forked from Minki/linux
Char/Misc driver patches for 5.9-rc1
Here is the large set of char and misc and other driver subsystem patches for 5.9-rc1. Lots of new driver submissions in here, and cleanups and features for existing drivers. Highlights are: - habanalabs driver updates - coresight driver updates - nvmem driver updates - huge number of "W=1" build warning cleanups from Lee Jones - dyndbg updates - virtbox driver fixes and updates - soundwire driver updates - mei driver updates - phy driver updates - fpga driver updates - lots of smaller individual misc/char driver cleanups and fixes Full details are in the shortlog. All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXylccQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ymofgCfZ1CxNWd0ZVM0YIn8cY9gO6ON7MsAnRq48hvn Vjf4rKM73GC11bVF4Gyy =Xq1R -----END PGP SIGNATURE----- Merge tag 'char-misc-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc driver updates from Greg KH: "Here is the large set of char and misc and other driver subsystem patches for 5.9-rc1. Lots of new driver submissions in here, and cleanups and features for existing drivers. Highlights are: - habanalabs driver updates - coresight driver updates - nvmem driver updates - huge number of "W=1" build warning cleanups from Lee Jones - dyndbg updates - virtbox driver fixes and updates - soundwire driver updates - mei driver updates - phy driver updates - fpga driver updates - lots of smaller individual misc/char driver cleanups and fixes Full details are in the shortlog. All of these have been in linux-next with no reported issues" * tag 'char-misc-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (322 commits) habanalabs: remove unused but set variable 'ctx_asid' nvmem: qcom-spmi-sdam: Enable multiple devices dt-bindings: nvmem: SID: add binding for A100's SID controller nvmem: update Kconfig description nvmem: qfprom: Add fuse blowing support dt-bindings: nvmem: Add properties needed for blowing fuses dt-bindings: nvmem: qfprom: Convert to yaml nvmem: qfprom: use NVMEM_DEVID_AUTO for multiple instances nvmem: core: add support to auto devid nvmem: core: Add nvmem_cell_read_u8() nvmem: core: Grammar fixes for help text nvmem: sc27xx: add sc2730 efuse support nvmem: Enforce nvmem stride in the sysfs interface MAINTAINERS: Add git tree for NVMEM FRAMEWORK nvmem: sprd: Fix return value of sprd_efuse_probe() drivers: android: Fix the SPDX comment style drivers: android: Fix a variable declaration coding style issue drivers: android: Remove braces for a single statement if-else block drivers: android: Remove the use of else after return drivers: android: Fix a variable declaration coding style issue ...
This commit is contained in:
commit
1785d11612
@ -90,3 +90,16 @@ Description: Display trc status register content
|
||||
The ME FW writes Glitch Detection HW (TRC)
|
||||
status information into trc status register
|
||||
for BIOS and OS to monitor fw health.
|
||||
|
||||
What: /sys/class/mei/meiN/kind
|
||||
Date: Jul 2020
|
||||
KernelVersion: 5.8
|
||||
Contact: Tomas Winkler <tomas.winkler@intel.com>
|
||||
Description: Display kind of the device
|
||||
|
||||
Generic devices are marked as "mei"
|
||||
while special purpose have their own
|
||||
names.
|
||||
Available options:
|
||||
- mei: generic mei device.
|
||||
- itouch: itouch (ipts) mei device.
|
||||
|
@ -126,3 +126,39 @@ Description:
|
||||
1 no action
|
||||
0 firmware record the notify code defined
|
||||
in b[15:0].
|
||||
|
||||
What: /sys/devices/platform/stratix10-rsu.0/dcmf0
|
||||
Date: June 2020
|
||||
KernelVersion: 5.8
|
||||
Contact: Richard Gong <richard.gong@linux.intel.com>
|
||||
Description:
|
||||
(RO) Decision firmware copy 0 version information.
|
||||
|
||||
What: /sys/devices/platform/stratix10-rsu.0/dcmf1
|
||||
Date: June 2020
|
||||
KernelVersion: 5.8
|
||||
Contact: Richard Gong <richard.gong@linux.intel.com>
|
||||
Description:
|
||||
(RO) Decision firmware copy 1 version information.
|
||||
|
||||
What: /sys/devices/platform/stratix10-rsu.0/dcmf2
|
||||
Date: June 2020
|
||||
KernelVersion: 5.8
|
||||
Contact: Richard Gong <richard.gong@linux.intel.com>
|
||||
Description:
|
||||
(RO) Decision firmware copy 2 version information.
|
||||
|
||||
What: /sys/devices/platform/stratix10-rsu.0/dcmf3
|
||||
Date: June 2020
|
||||
KernelVersion: 5.8
|
||||
Contact: Richard Gong <richard.gong@linux.intel.com>
|
||||
Description:
|
||||
(RO) Decision firmware copy 3 version information.
|
||||
|
||||
What: /sys/devices/platform/stratix10-rsu.0/max_retry
|
||||
Date: June 2020
|
||||
KernelVersion: 5.8
|
||||
Contact: Richard Gong <richard.gong@linux.intel.com>
|
||||
Description:
|
||||
(RO) max retry parameter is stored in the firmware
|
||||
decision IO section, as a byte located at offset 0x18c.
|
||||
|
@ -70,10 +70,10 @@ statements via::
|
||||
|
||||
nullarbor:~ # cat <debugfs>/dynamic_debug/control
|
||||
# filename:lineno [module]function flags format
|
||||
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
|
||||
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012"
|
||||
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012"
|
||||
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012"
|
||||
net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
|
||||
net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012"
|
||||
net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012"
|
||||
net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012"
|
||||
...
|
||||
|
||||
|
||||
@ -93,7 +93,7 @@ the debug statement callsites with any non-default flags::
|
||||
|
||||
nullarbor:~ # awk '$3 != "=_"' <debugfs>/dynamic_debug/control
|
||||
# filename:lineno [module]function flags format
|
||||
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
|
||||
net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
|
||||
|
||||
Command Language Reference
|
||||
==========================
|
||||
@ -156,6 +156,7 @@ against. Possible keywords are:::
|
||||
``line-range`` cannot contain space, e.g.
|
||||
"1-30" is valid range but "1 - 30" is not.
|
||||
|
||||
``module=foo`` combined keyword=value form is interchangably accepted
|
||||
|
||||
The meanings of each keyword are:
|
||||
|
||||
@ -164,15 +165,18 @@ func
|
||||
of each callsite. Example::
|
||||
|
||||
func svc_tcp_accept
|
||||
func *recv* # in rfcomm, bluetooth, ping, tcp
|
||||
|
||||
file
|
||||
The given string is compared against either the full pathname, the
|
||||
src-root relative pathname, or the basename of the source file of
|
||||
each callsite. Examples::
|
||||
The given string is compared against either the src-root relative
|
||||
pathname, or the basename of the source file of each callsite.
|
||||
Examples::
|
||||
|
||||
file svcsock.c
|
||||
file kernel/freezer.c
|
||||
file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
|
||||
file kernel/freezer.c # ie column 1 of control file
|
||||
file drivers/usb/* # all callsites under it
|
||||
file inode.c:start_* # parse :tail as a func (above)
|
||||
file inode.c:1-100 # parse :tail as a line-range (above)
|
||||
|
||||
module
|
||||
The given string is compared against the module name
|
||||
@ -182,6 +186,7 @@ module
|
||||
|
||||
module sunrpc
|
||||
module nfsd
|
||||
module drm* # both drm, drm_kms_helper
|
||||
|
||||
format
|
||||
The given string is searched for in the dynamic debug format
|
||||
@ -251,8 +256,8 @@ the syntax described above, but must not exceed 1023 characters. Your
|
||||
bootloader may impose lower limits.
|
||||
|
||||
These ``dyndbg`` params are processed just after the ddebug tables are
|
||||
processed, as part of the arch_initcall. Thus you can enable debug
|
||||
messages in all code run after this arch_initcall via this boot
|
||||
processed, as part of the early_initcall. Thus you can enable debug
|
||||
messages in all code run after this early_initcall via this boot
|
||||
parameter.
|
||||
|
||||
On an x86 system for example ACPI enablement is a subsys_initcall and::
|
||||
|
@ -108,6 +108,13 @@ its hardware characteristcs.
|
||||
* arm,cp14: must be present if the system accesses ETM/PTM management
|
||||
registers via co-processor 14.
|
||||
|
||||
* qcom,skip-power-up: boolean. Indicates that an implementation can
|
||||
skip powering up the trace unit. TRCPDCR.PU does not have to be set
|
||||
on Qualcomm Technologies Inc. systems since ETMs are in the same power
|
||||
domain as their CPU cores. This property is required to identify such
|
||||
systems with hardware errata where the CPU watchdog counter is stopped
|
||||
when TRCPDCR.PU is set.
|
||||
|
||||
* Optional property for TMC:
|
||||
|
||||
* arm,buffer-size: size of contiguous buffer space for TMC ETR
|
||||
@ -121,6 +128,12 @@ its hardware characteristcs.
|
||||
* interrupts : Exactly one SPI may be listed for reporting the address
|
||||
error
|
||||
|
||||
* Optional property for configurable replicators:
|
||||
|
||||
* qcom,replicator-loses-context: boolean. Indicates that the replicator
|
||||
will lose register context when AMBA clock is removed which is observed
|
||||
in some replicator designs.
|
||||
|
||||
Graph bindings for Coresight
|
||||
-------------------------------
|
||||
|
||||
|
@ -1,11 +1,14 @@
|
||||
Xilinx Slave Serial SPI FPGA Manager
|
||||
|
||||
Xilinx Spartan-6 FPGAs support a method of loading the bitstream over
|
||||
what is referred to as "slave serial" interface.
|
||||
Xilinx Spartan-6 and 7 Series FPGAs support a method of loading the
|
||||
bitstream over what is referred to as "slave serial" interface.
|
||||
The slave serial link is not technically SPI, and might require extra
|
||||
circuits in order to play nicely with other SPI slaves on the same bus.
|
||||
|
||||
See https://www.xilinx.com/support/documentation/user_guides/ug380.pdf
|
||||
See:
|
||||
- https://www.xilinx.com/support/documentation/user_guides/ug380.pdf
|
||||
- https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
|
||||
- https://www.xilinx.com/support/documentation/application_notes/xapp583-fpga-configuration.pdf
|
||||
|
||||
Required properties:
|
||||
- compatible: should contain "xlnx,fpga-slave-serial"
|
||||
@ -13,6 +16,10 @@ Required properties:
|
||||
- prog_b-gpios: config pin (referred to as PROGRAM_B in the manual)
|
||||
- done-gpios: config status pin (referred to as DONE in the manual)
|
||||
|
||||
Optional properties:
|
||||
- init-b-gpios: initialization status and configuration error pin
|
||||
(referred to as INIT_B in the manual)
|
||||
|
||||
Example for full FPGA configuration:
|
||||
|
||||
fpga-region0 {
|
||||
@ -37,7 +44,8 @@ Example for full FPGA configuration:
|
||||
spi-max-frequency = <60000000>;
|
||||
spi-cpha;
|
||||
reg = <0>;
|
||||
done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
|
||||
prog_b-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
|
||||
init-b-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>;
|
||||
done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
@ -15,14 +15,17 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- allwinner,sun4i-a10-sid
|
||||
- allwinner,sun7i-a20-sid
|
||||
- allwinner,sun8i-a83t-sid
|
||||
- allwinner,sun8i-h3-sid
|
||||
- allwinner,sun50i-a64-sid
|
||||
- allwinner,sun50i-h5-sid
|
||||
- allwinner,sun50i-h6-sid
|
||||
oneOf:
|
||||
- const: allwinner,sun4i-a10-sid
|
||||
- const: allwinner,sun7i-a20-sid
|
||||
- const: allwinner,sun8i-a83t-sid
|
||||
- const: allwinner,sun8i-h3-sid
|
||||
- const: allwinner,sun50i-a64-sid
|
||||
- items:
|
||||
- const: allwinner,sun50i-a100-sid
|
||||
- const: allwinner,sun50i-a64-sid
|
||||
- const: allwinner,sun50i-h5-sid
|
||||
- const: allwinner,sun50i-h6-sid
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
96
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
Normal file
96
Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml
Normal file
@ -0,0 +1,96 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/nvmem/qcom,qfprom.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies Inc, QFPROM Efuse bindings
|
||||
|
||||
maintainers:
|
||||
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
|
||||
allOf:
|
||||
- $ref: "nvmem.yaml#"
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,qfprom
|
||||
|
||||
reg:
|
||||
# If the QFPROM is read-only OS image then only the corrected region
|
||||
# needs to be provided. If the QFPROM is writable then all 4 regions
|
||||
# must be provided.
|
||||
oneOf:
|
||||
- items:
|
||||
- description: The corrected region.
|
||||
- items:
|
||||
- description: The corrected region.
|
||||
- description: The raw region.
|
||||
- description: The config region.
|
||||
- description: The security control region.
|
||||
|
||||
# Clock must be provided if QFPROM is writable from the OS image.
|
||||
clocks:
|
||||
maxItems: 1
|
||||
clock-names:
|
||||
const: core
|
||||
|
||||
# Supply reference must be provided if QFPROM is writable from the OS image.
|
||||
vcc-supply:
|
||||
description: Our power supply.
|
||||
|
||||
# Needed if any child nodes are present.
|
||||
"#address-cells":
|
||||
const: 1
|
||||
"#size-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
|
||||
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
efuse@784000 {
|
||||
compatible = "qcom,qfprom";
|
||||
reg = <0 0x00784000 0 0x8ff>,
|
||||
<0 0x00780000 0 0x7a0>,
|
||||
<0 0x00782000 0 0x100>,
|
||||
<0 0x00786000 0 0x1fff>;
|
||||
clocks = <&gcc GCC_SEC_CTRL_CLK_SRC>;
|
||||
clock-names = "core";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
vcc-supply = <&vreg_l11a_1p8>;
|
||||
|
||||
hstx-trim-primary@25b {
|
||||
reg = <0x25b 0x1>;
|
||||
bits = <1 3>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
- |
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
efuse@784000 {
|
||||
compatible = "qcom,qfprom";
|
||||
reg = <0 0x00784000 0 0x8ff>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
hstx-trim-primary@1eb {
|
||||
reg = <0x1eb 0x1>;
|
||||
bits = <1 4>;
|
||||
};
|
||||
};
|
||||
};
|
@ -1,35 +0,0 @@
|
||||
= Qualcomm QFPROM device tree bindings =
|
||||
|
||||
This binding is intended to represent QFPROM which is found in most QCOM SOCs.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "qcom,qfprom"
|
||||
- reg: Should contain registers location and length
|
||||
|
||||
= Data cells =
|
||||
Are child nodes of qfprom, bindings of which as described in
|
||||
bindings/nvmem/nvmem.txt
|
||||
|
||||
Example:
|
||||
|
||||
qfprom: qfprom@700000 {
|
||||
compatible = "qcom,qfprom";
|
||||
reg = <0x00700000 0x8000>;
|
||||
...
|
||||
/* Data cells */
|
||||
tsens_calibration: calib@404 {
|
||||
reg = <0x4404 0x10>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
= Data consumers =
|
||||
Are device nodes which consume nvmem data cells.
|
||||
|
||||
For example:
|
||||
|
||||
tsens {
|
||||
...
|
||||
nvmem-cells = <&tsens_calibration>;
|
||||
nvmem-cell-names = "calibration";
|
||||
};
|
@ -0,0 +1,79 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/phy/brcm,bcm63xx-usbh-phy.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: BCM63xx USBH PHY
|
||||
|
||||
maintainers:
|
||||
- Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- brcm,bcm6318-usbh-phy
|
||||
- brcm,bcm6328-usbh-phy
|
||||
- brcm,bcm6358-usbh-phy
|
||||
- brcm,bcm6362-usbh-phy
|
||||
- brcm,bcm6368-usbh-phy
|
||||
- brcm,bcm63268-usbh-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: usbh
|
||||
- const: usb_ref
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- "#phy-cells"
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- brcm,bcm6318-usbh-phy
|
||||
- brcm,bcm6328-usbh-phy
|
||||
- brcm,bcm6362-usbh-phy
|
||||
- brcm,bcm63268-usbh-phy
|
||||
then:
|
||||
properties:
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
required:
|
||||
- power-domains
|
||||
else:
|
||||
properties:
|
||||
power-domains: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
usbh: usb-phy@10001700 {
|
||||
compatible = "brcm,bcm6368-usbh-phy";
|
||||
reg = <0x10001700 0x38>;
|
||||
clocks = <&periph_clk 15>;
|
||||
clock-names = "usbh";
|
||||
resets = <&periph_rst 12>;
|
||||
#phy-cells = <1>;
|
||||
};
|
@ -12,6 +12,13 @@ Required properties:
|
||||
- #address-cells: should be 1.
|
||||
- #size-cells: should be 0.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reg-names: must be "comphy" as the first name, and "conf".
|
||||
- reg: must contain the comphy register location and length as the first
|
||||
pair, followed by an optional configuration register address and
|
||||
length pair.
|
||||
|
||||
A sub-node is required for each comphy lane provided by the comphy.
|
||||
|
||||
Required properties (child nodes):
|
||||
@ -24,7 +31,8 @@ Example:
|
||||
|
||||
comphy: phy@18300 {
|
||||
compatible = "marvell,armada-380-comphy";
|
||||
reg = <0x18300 0x100>;
|
||||
reg-names = "comphy", "conf";
|
||||
reg = <0x18300 0x100>, <0x18460 4>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
|
@ -0,0 +1,55 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/qcom,ipq806x-usb-phy-hs.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm ipq806x usb DWC3 HS PHY CONTROLLER
|
||||
|
||||
maintainers:
|
||||
- Ansuel Smith <ansuelsmth@gmail.com>
|
||||
|
||||
description:
|
||||
DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer
|
||||
controllers used in ipq806x. Each DWC3 PHY controller should have its
|
||||
own node.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,ipq806x-usb-phy-hs
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: ref
|
||||
- const: xo
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#phy-cells"
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
|
||||
|
||||
hs_phy_0: phy@110f8800 {
|
||||
compatible = "qcom,ipq806x-usb-phy-hs";
|
||||
reg = <0x110f8800 0x30>;
|
||||
clocks = <&gcc USB30_0_UTMI_CLK>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <0>;
|
||||
};
|
@ -0,0 +1,73 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/qcom,ipq806x-usb-phy-ss.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm ipq806x usb DWC3 SS PHY CONTROLLER
|
||||
|
||||
maintainers:
|
||||
- Ansuel Smith <ansuelsmth@gmail.com>
|
||||
|
||||
description:
|
||||
DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer
|
||||
controllers used in ipq806x. Each DWC3 PHY controller should have its
|
||||
own node.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,ipq806x-usb-phy-ss
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
items:
|
||||
- const: ref
|
||||
- const: xo
|
||||
|
||||
qcom,rx-eq:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Override value for rx_eq.
|
||||
default: 4
|
||||
maximum: 7
|
||||
|
||||
qcom,tx-deamp-3_5db:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Override value for transmit preemphasis.
|
||||
default: 23
|
||||
maximum: 63
|
||||
|
||||
qcom,mpll:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description: Override value for mpll.
|
||||
default: 0
|
||||
maximum: 7
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#phy-cells"
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
|
||||
|
||||
ss_phy_0: phy@110f8830 {
|
||||
compatible = "qcom,ipq806x-usb-phy-ss";
|
||||
reg = <0x110f8830 0x30>;
|
||||
clocks = <&gcc USB30_0_MASTER_CLK>;
|
||||
clock-names = "ref";
|
||||
#phy-cells = <0>;
|
||||
};
|
@ -18,6 +18,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,ipq8074-qmp-pcie-phy
|
||||
- qcom,ipq8074-qmp-usb3-phy
|
||||
- qcom,msm8996-qmp-pcie-phy
|
||||
- qcom,msm8996-qmp-ufs-phy
|
||||
- qcom,msm8996-qmp-usb3-phy
|
||||
@ -161,6 +162,7 @@ allOf:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq8074-qmp-usb3-phy
|
||||
- qcom,msm8996-qmp-usb3-phy
|
||||
- qcom,msm8998-qmp-pcie-phy
|
||||
- qcom,msm8998-qmp-usb3-phy
|
||||
|
@ -18,6 +18,7 @@ properties:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,ipq8074-qusb2-phy
|
||||
- qcom,msm8996-qusb2-phy
|
||||
- qcom,msm8998-qusb2-phy
|
||||
- items:
|
||||
|
@ -21,6 +21,7 @@ properties:
|
||||
- renesas,usb2-phy-r8a774a1 # RZ/G2M
|
||||
- renesas,usb2-phy-r8a774b1 # RZ/G2N
|
||||
- renesas,usb2-phy-r8a774c0 # RZ/G2E
|
||||
- renesas,usb2-phy-r8a774e1 # RZ/G2H
|
||||
- renesas,usb2-phy-r8a7795 # R-Car H3
|
||||
- renesas,usb2-phy-r8a7796 # R-Car M3-W
|
||||
- renesas,usb2-phy-r8a77961 # R-Car M3-W+
|
||||
|
@ -15,6 +15,7 @@ properties:
|
||||
- enum:
|
||||
- renesas,r8a774a1-usb3-phy # RZ/G2M
|
||||
- renesas,r8a774b1-usb3-phy # RZ/G2N
|
||||
- renesas,r8a774e1-usb3-phy # RZ/G2H
|
||||
- renesas,r8a7795-usb3-phy # R-Car H3
|
||||
- renesas,r8a7796-usb3-phy # R-Car M3-W
|
||||
- renesas,r8a77961-usb3-phy # R-Car M3-W+
|
||||
|
75
Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml
Normal file
75
Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml
Normal file
@ -0,0 +1,75 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/samsung,ufs-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung SoC series UFS PHY Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Alim Akhtar <alim.akhtar@samsung.com>
|
||||
|
||||
properties:
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,exynos7-ufs-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: phy-pma
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: PLL reference clock
|
||||
- description: symbol clock for input symbol ( rx0-ch0 symbol clock)
|
||||
- description: symbol clock for input symbol ( rx1-ch1 symbol clock)
|
||||
- description: symbol clock for output symbol ( tx0 symbol clock)
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref_clk
|
||||
- const: rx1_symbol_clk
|
||||
- const: rx0_symbol_clk
|
||||
- const: tx0_symbol_clk
|
||||
|
||||
samsung,pmu-syscon:
|
||||
$ref: '/schemas/types.yaml#/definitions/phandle'
|
||||
description: phandle for PMU system controller interface, used to
|
||||
control pmu registers bits for ufs m-phy
|
||||
|
||||
required:
|
||||
- "#phy-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- clocks
|
||||
- clock-names
|
||||
- samsung,pmu-syscon
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/exynos7-clk.h>
|
||||
|
||||
ufs_phy: ufs-phy@15571800 {
|
||||
compatible = "samsung,exynos7-ufs-phy";
|
||||
reg = <0x15571800 0x240>;
|
||||
reg-names = "phy-pma";
|
||||
samsung,pmu-syscon = <&pmu_system_controller>;
|
||||
#phy-cells = <0>;
|
||||
clocks = <&clock_fsys1 SCLK_COMBO_PHY_EMBEDDED_26M>,
|
||||
<&clock_fsys1 PHYCLK_UFS20_RX1_SYMBOL_USER>,
|
||||
<&clock_fsys1 PHYCLK_UFS20_RX0_SYMBOL_USER>,
|
||||
<&clock_fsys1 PHYCLK_UFS20_TX0_SYMBOL_USER>;
|
||||
clock-names = "ref_clk", "rx1_symbol_clk",
|
||||
"rx0_symbol_clk", "tx0_symbol_clk";
|
||||
|
||||
};
|
||||
...
|
@ -31,12 +31,16 @@ properties:
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- const: link # for PXs2
|
||||
- items: # for PXs3
|
||||
- items: # for PXs3 with phy-ext
|
||||
- const: link
|
||||
- const: phy
|
||||
- const: phy-ext
|
||||
- items: # for others
|
||||
- const: link
|
||||
- const: phy
|
||||
|
||||
|
105
Documentation/devicetree/bindings/phy/xlnx,zynqmp-psgtr.yaml
Normal file
105
Documentation/devicetree/bindings/phy/xlnx,zynqmp-psgtr.yaml
Normal file
@ -0,0 +1,105 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/xlnx,zynqmp-psgtr.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Xilinx ZynqMP Gigabit Transceiver PHY Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
|
||||
description: |
|
||||
This binding describes the Xilinx ZynqMP Gigabit Transceiver (GTR) PHY. The
|
||||
GTR provides four lanes and is used by USB, SATA, PCIE, Display port and
|
||||
Ethernet SGMII controllers.
|
||||
|
||||
properties:
|
||||
"#phy-cells":
|
||||
const: 4
|
||||
description: |
|
||||
The cells contain the following arguments.
|
||||
|
||||
- description: The GTR lane
|
||||
minimum: 0
|
||||
maximum: 3
|
||||
- description: The PHY type
|
||||
enum:
|
||||
- PHY_TYPE_DP
|
||||
- PHY_TYPE_PCIE
|
||||
- PHY_TYPE_SATA
|
||||
- PHY_TYPE_SGMII
|
||||
- PHY_TYPE_USB
|
||||
- description: The PHY instance
|
||||
minimum: 0
|
||||
maximum: 1 # for DP, SATA or USB
|
||||
maximum: 3 # for PCIE or SGMII
|
||||
- description: The reference clock number
|
||||
minimum: 0
|
||||
maximum: 3
|
||||
|
||||
compatible:
|
||||
enum:
|
||||
- xlnx,zynqmp-psgtr-v1.1
|
||||
- xlnx,zynqmp-psgtr
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
description: |
|
||||
Clock for each PS_MGTREFCLK[0-3] reference clock input. Unconnected
|
||||
inputs shall not have an entry.
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 4
|
||||
items:
|
||||
pattern: "^ref[0-3]$"
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: SERDES registers block
|
||||
- description: SIOU registers block
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: serdes
|
||||
- const: siou
|
||||
|
||||
xlnx,tx-termination-fix:
|
||||
description: |
|
||||
Include this for fixing functional issue with the TX termination
|
||||
resistance in GT, which can be out of spec for the XCZU9EG silicon
|
||||
version.
|
||||
type: boolean
|
||||
|
||||
required:
|
||||
- "#phy-cells"
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
const: xlnx,zynqmp-psgtr-v1.1
|
||||
|
||||
then:
|
||||
properties:
|
||||
xlnx,tx-termination-fix: false
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
phy: phy@fd400000 {
|
||||
compatible = "xlnx,zynqmp-psgtr-v1.1";
|
||||
reg = <0xfd400000 0x40000>,
|
||||
<0xfd3d0000 0x1000>;
|
||||
reg-names = "serdes", "siou";
|
||||
clocks = <&refclks 3>, <&refclks 2>, <&refclks 0>;
|
||||
clock-names = "ref1", "ref2", "ref3";
|
||||
#phy-cells = <4>;
|
||||
};
|
||||
|
||||
...
|
@ -28,6 +28,6 @@ able to make use of built-in firmware:
|
||||
* Some firmware files may be really large in size. The remote-proc subsystem
|
||||
is an example subsystem which deals with these sorts of firmware
|
||||
* The firmware may need to be scraped out from some device specific location
|
||||
dynamically, an example is calibration data for for some WiFi chipsets. This
|
||||
dynamically, an example is calibration data for some WiFi chipsets. This
|
||||
calibration data can be unique per sold device.
|
||||
|
||||
|
@ -24,7 +24,7 @@ available. Stuffing the firmware into initramfs resolves this race issue,
|
||||
however note that using initrd does not suffice to address the same race.
|
||||
|
||||
There are circumstances that justify not wanting to include firmware into
|
||||
initramfs, such as dealing with large firmware firmware files for the
|
||||
initramfs, such as dealing with large firmware files for the
|
||||
remote-proc subsystem. For such cases using a userspace fallback mechanism
|
||||
is currently the only viable solution as only userspace can know for sure
|
||||
when the real rootfs is ready and mounted.
|
||||
|
@ -27,7 +27,7 @@ Some implementation details about the firmware cache setup:
|
||||
uses all synchronous call except :c:func:`request_firmware_into_buf`.
|
||||
|
||||
* If an asynchronous call is used the firmware cache is only set up for a
|
||||
device if if the second argument (uevent) to request_firmware_nowait() is
|
||||
device if the second argument (uevent) to request_firmware_nowait() is
|
||||
true. When uevent is true it requests that a kobject uevent be sent to
|
||||
userspace for the firmware request through the sysfs fallback mechanism
|
||||
if the firmware file is not found.
|
||||
|
@ -76,5 +76,5 @@ firmware. For example if you used request_firmware() and it returns,
|
||||
the driver has the firmware image accessible in fw_entry->{data,size}.
|
||||
If something went wrong request_firmware() returns non-zero and fw_entry
|
||||
is set to NULL. Once your driver is done with processing the firmware it
|
||||
can call call release_firmware(fw_entry) to release the firmware image
|
||||
can call release_firmware(fw_entry) to release the firmware image
|
||||
and any related resource.
|
||||
|
@ -293,6 +293,10 @@ per stream. From ASoC DPCM framework, this stream state maybe linked to
|
||||
|
||||
int sdw_alloc_stream(char * stream_name);
|
||||
|
||||
The SoundWire core provides a sdw_startup_stream() helper function,
|
||||
typically called during a dailink .startup() callback, which performs
|
||||
stream allocation and sets the stream pointer for all DAIs
|
||||
connected to a stream.
|
||||
|
||||
SDW_STREAM_CONFIGURED
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -509,7 +513,12 @@ In .shutdown() the data structure maintaining stream state are freed up.
|
||||
|
||||
void sdw_release_stream(struct sdw_stream_runtime * stream);
|
||||
|
||||
Not Supported
|
||||
The SoundWire core provides a sdw_shutdown_stream() helper function,
|
||||
typically called during a dailink .shutdown() callback, which clears
|
||||
the stream pointer for all DAIS connected to a stream and releases the
|
||||
memory allocated for the stream.
|
||||
|
||||
Not Supported
|
||||
=============
|
||||
|
||||
1. A single port with multiple channels supported cannot be used between two
|
||||
|
@ -274,7 +274,7 @@ fields of ``struct uio_mem``:
|
||||
region, it will show up in the corresponding sysfs node.
|
||||
|
||||
- ``int memtype``: Required if the mapping is used. Set this to
|
||||
``UIO_MEM_PHYS`` if you you have physical memory on your card to be
|
||||
``UIO_MEM_PHYS`` if you have physical memory on your card to be
|
||||
mapped. Use ``UIO_MEM_LOGICAL`` for logical memory (e.g. allocated
|
||||
with :c:func:`__get_free_pages()` but not kmalloc()). There's also
|
||||
``UIO_MEM_VIRTUAL`` for virtual memory.
|
||||
|
@ -273,7 +273,7 @@ buffer is full, the FPGA informs the host about that (appending a
|
||||
XILLYMSG_OPCODE_RELEASEBUF message channel 0 and sending an interrupt if
|
||||
necessary). The host responds by making the data available for reading through
|
||||
the character device. When all data has been read, the host writes on the
|
||||
the FPGA's buffer control register, allowing the buffer's overwriting. Flow
|
||||
FPGA's buffer control register, allowing the buffer's overwriting. Flow
|
||||
control mechanisms exist on both sides to prevent underflows and overflows.
|
||||
|
||||
This is not good enough for creating a TCP/IP-like stream: If the data flow
|
||||
|
@ -89,6 +89,8 @@ The following functions are exposed through ioctls:
|
||||
- Program bitstream (DFL_FPGA_FME_PORT_PR)
|
||||
- Assign port to PF (DFL_FPGA_FME_PORT_ASSIGN)
|
||||
- Release port from PF (DFL_FPGA_FME_PORT_RELEASE)
|
||||
- Get number of irqs of FME global error (DFL_FPGA_FME_ERR_GET_IRQ_NUM)
|
||||
- Set interrupt trigger for FME error (DFL_FPGA_FME_ERR_SET_IRQ)
|
||||
|
||||
More functions are exposed through sysfs
|
||||
(/sys/class/fpga_region/regionX/dfl-fme.n/):
|
||||
@ -149,6 +151,10 @@ The following functions are exposed through ioctls:
|
||||
- Map DMA buffer (DFL_FPGA_PORT_DMA_MAP)
|
||||
- Unmap DMA buffer (DFL_FPGA_PORT_DMA_UNMAP)
|
||||
- Reset AFU (DFL_FPGA_PORT_RESET)
|
||||
- Get number of irqs of port error (DFL_FPGA_PORT_ERR_GET_IRQ_NUM)
|
||||
- Set interrupt trigger for port error (DFL_FPGA_PORT_ERR_SET_IRQ)
|
||||
- Get number of irqs of UINT (DFL_FPGA_PORT_UINT_GET_IRQ_NUM)
|
||||
- Set interrupt trigger for UINT (DFL_FPGA_PORT_UINT_SET_IRQ)
|
||||
|
||||
DFL_FPGA_PORT_RESET:
|
||||
reset the FPGA Port and its AFU. Userspace can do Port
|
||||
@ -462,6 +468,19 @@ since they are system-wide counters on FPGA device.
|
||||
The current driver does not support sampling. So "perf record" is unsupported.
|
||||
|
||||
|
||||
Interrupt support
|
||||
=================
|
||||
Some FME and AFU private features are able to generate interrupts. As mentioned
|
||||
above, users could call ioctl (DFL_FPGA_*_GET_IRQ_NUM) to know whether or how
|
||||
many interrupts are supported for this private feature. Drivers also implement
|
||||
an eventfd based interrupt handling mechanism for users to get notified when
|
||||
interrupt happens. Users could set eventfds to driver via
|
||||
ioctl (DFL_FPGA_*_SET_IRQ), and then poll/select on these eventfds waiting for
|
||||
notification.
|
||||
In Current DFL, 3 sub features (Port error, FME global error and AFU interrupt)
|
||||
support interrupts.
|
||||
|
||||
|
||||
Add new FIUs support
|
||||
====================
|
||||
It's possible that developers made some new function blocks (FIUs) under this
|
||||
|
17
MAINTAINERS
17
MAINTAINERS
@ -1179,6 +1179,8 @@ M: Todd Kjos <tkjos@android.com>
|
||||
M: Martijn Coenen <maco@android.com>
|
||||
M: Joel Fernandes <joel@joelfernandes.org>
|
||||
M: Christian Brauner <christian@brauner.io>
|
||||
M: Hridya Valsaraju <hridya@google.com>
|
||||
M: Suren Baghdasaryan <surenb@google.com>
|
||||
L: devel@driverdev.osuosl.org
|
||||
S: Supported
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
|
||||
@ -8833,7 +8835,7 @@ M: Tomas Winkler <tomas.winkler@intel.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/driver-api/mei/*
|
||||
F: drivers/misc/mei/*
|
||||
F: drivers/misc/mei/
|
||||
F: drivers/watchdog/mei_wdt.c
|
||||
F: include/linux/mei_cl_bus.h
|
||||
F: include/uapi/linux/mei.h
|
||||
@ -12329,6 +12331,7 @@ F: drivers/nvme/target/
|
||||
NVMEM FRAMEWORK
|
||||
M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/srini/nvmem.git
|
||||
F: Documentation/ABI/stable/sysfs-bus-nvmem
|
||||
F: Documentation/devicetree/bindings/nvmem/
|
||||
F: drivers/nvmem/
|
||||
@ -16082,8 +16085,9 @@ F: sound/soc/sof/
|
||||
|
||||
SOUNDWIRE SUBSYSTEM
|
||||
M: Vinod Koul <vkoul@kernel.org>
|
||||
M: Sanyog Kale <sanyog.r.kale@intel.com>
|
||||
M: Bard Liao <yung-chuan.liao@linux.intel.com>
|
||||
R: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
|
||||
R: Sanyog Kale <sanyog.r.kale@intel.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Supported
|
||||
F: Documentation/driver-api/soundwire/
|
||||
@ -18922,6 +18926,15 @@ F: Documentation/devicetree/bindings/media/xilinx/
|
||||
F: drivers/media/platform/xilinx/
|
||||
F: include/uapi/linux/xilinx-v4l2-controls.h
|
||||
|
||||
XILINX ZYNQMP PSGTR PHY DRIVER
|
||||
M: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com>
|
||||
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
T: git https://github.com/Xilinx/linux-xlnx.git
|
||||
F: Documentation/devicetree/bindings/phy/xlnx,zynqmp-psgtr.yaml
|
||||
F: drivers/phy/xilinx/phy-zynqmp.c
|
||||
|
||||
XILLYBUS DRIVER
|
||||
M: Eli Billauer <eli.billauer@gmail.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
|
@ -1969,9 +1969,8 @@ static void binder_send_failed_reply(struct binder_transaction *t,
|
||||
binder_thread_dec_tmpref(target_thread);
|
||||
binder_free_transaction(t);
|
||||
return;
|
||||
} else {
|
||||
__release(&target_thread->proc->inner_lock);
|
||||
}
|
||||
__release(&target_thread->proc->inner_lock);
|
||||
next = t->from_parent;
|
||||
|
||||
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
|
||||
@ -2760,11 +2759,10 @@ static bool binder_proc_transaction(struct binder_transaction *t,
|
||||
binder_node_lock(node);
|
||||
if (oneway) {
|
||||
BUG_ON(thread);
|
||||
if (node->has_async_transaction) {
|
||||
if (node->has_async_transaction)
|
||||
pending_async = true;
|
||||
} else {
|
||||
else
|
||||
node->has_async_transaction = true;
|
||||
}
|
||||
}
|
||||
|
||||
binder_inner_proc_lock(proc);
|
||||
@ -2982,6 +2980,12 @@ static void binder_transaction(struct binder_proc *proc,
|
||||
goto err_dead_binder;
|
||||
}
|
||||
e->to_node = target_node->debug_id;
|
||||
if (WARN_ON(proc == target_proc)) {
|
||||
return_error = BR_FAILED_REPLY;
|
||||
return_error_param = -EINVAL;
|
||||
return_error_line = __LINE__;
|
||||
goto err_invalid_target_handle;
|
||||
}
|
||||
if (security_binder_transaction(proc->tsk,
|
||||
target_proc->tsk) < 0) {
|
||||
return_error = BR_FAILED_REPLY;
|
||||
@ -3635,10 +3639,17 @@ static int binder_thread_write(struct binder_proc *proc,
|
||||
struct binder_node *ctx_mgr_node;
|
||||
mutex_lock(&context->context_mgr_node_lock);
|
||||
ctx_mgr_node = context->binder_context_mgr_node;
|
||||
if (ctx_mgr_node)
|
||||
if (ctx_mgr_node) {
|
||||
if (ctx_mgr_node->proc == proc) {
|
||||
binder_user_error("%d:%d context manager tried to acquire desc 0\n",
|
||||
proc->pid, thread->pid);
|
||||
mutex_unlock(&context->context_mgr_node_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = binder_inc_ref_for_node(
|
||||
proc, ctx_mgr_node,
|
||||
strong, NULL, &rdata);
|
||||
}
|
||||
mutex_unlock(&context->context_mgr_node_lock);
|
||||
}
|
||||
if (ret)
|
||||
|
@ -547,6 +547,7 @@ static void binder_delete_free_buffer(struct binder_alloc *alloc,
|
||||
{
|
||||
struct binder_buffer *prev, *next = NULL;
|
||||
bool to_free = true;
|
||||
|
||||
BUG_ON(alloc->buffers.next == &buffer->entry);
|
||||
prev = binder_buffer_prev(buffer);
|
||||
BUG_ON(!prev->free);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include <linux/compiler_types.h>
|
||||
#include <linux/errno.h>
|
||||
@ -351,6 +351,7 @@ static const struct super_operations binderfs_super_ops = {
|
||||
static inline bool is_binderfs_control_device(const struct dentry *dentry)
|
||||
{
|
||||
struct binderfs_info *info = dentry->d_sb->s_fs_info;
|
||||
|
||||
return info->control_dentry == dentry;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,16 @@ static bool fsl_mc_device_match(struct fsl_mc_device *mc_dev,
|
||||
{
|
||||
return mc_dev->obj_desc.id == obj_desc->id &&
|
||||
strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0;
|
||||
}
|
||||
|
||||
static bool fsl_mc_obj_desc_is_allocatable(struct fsl_mc_obj_desc *obj)
|
||||
{
|
||||
if (strcmp(obj->type, "dpmcp") == 0 ||
|
||||
strcmp(obj->type, "dpcon") == 0 ||
|
||||
strcmp(obj->type, "dpbp") == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data)
|
||||
@ -150,6 +159,27 @@ static void check_plugged_state_change(struct fsl_mc_device *mc_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static void fsl_mc_obj_device_add(struct fsl_mc_device *mc_bus_dev,
|
||||
struct fsl_mc_obj_desc *obj_desc)
|
||||
{
|
||||
int error;
|
||||
struct fsl_mc_device *child_dev;
|
||||
|
||||
/*
|
||||
* Check if device is already known to Linux:
|
||||
*/
|
||||
child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
|
||||
if (child_dev) {
|
||||
check_plugged_state_change(child_dev, obj_desc);
|
||||
put_device(&child_dev->dev);
|
||||
} else {
|
||||
error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
|
||||
&child_dev);
|
||||
if (error < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dprc_add_new_devices - Adds devices to the logical bus for a DPRC
|
||||
*
|
||||
@ -166,30 +196,23 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
|
||||
struct fsl_mc_obj_desc *obj_desc_array,
|
||||
int num_child_objects_in_mc)
|
||||
{
|
||||
int error;
|
||||
int i;
|
||||
|
||||
/* probe the allocable objects first */
|
||||
for (i = 0; i < num_child_objects_in_mc; i++) {
|
||||
struct fsl_mc_device *child_dev;
|
||||
struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
|
||||
|
||||
if (strlen(obj_desc->type) == 0)
|
||||
continue;
|
||||
if (strlen(obj_desc->type) > 0 &&
|
||||
fsl_mc_obj_desc_is_allocatable(obj_desc))
|
||||
fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if device is already known to Linux:
|
||||
*/
|
||||
child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
|
||||
if (child_dev) {
|
||||
check_plugged_state_change(child_dev, obj_desc);
|
||||
put_device(&child_dev->dev);
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < num_child_objects_in_mc; i++) {
|
||||
struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
|
||||
|
||||
error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
|
||||
&child_dev);
|
||||
if (error < 0)
|
||||
continue;
|
||||
if (strlen(obj_desc->type) > 0 &&
|
||||
!fsl_mc_obj_desc_is_allocatable(obj_desc))
|
||||
fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,6 +213,31 @@ struct device_type fsl_mc_bus_dpseci_type = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpseci_type);
|
||||
|
||||
struct device_type fsl_mc_bus_dpdmux_type = {
|
||||
.name = "fsl_mc_bus_dpdmux"
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdmux_type);
|
||||
|
||||
struct device_type fsl_mc_bus_dpdcei_type = {
|
||||
.name = "fsl_mc_bus_dpdcei"
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdcei_type);
|
||||
|
||||
struct device_type fsl_mc_bus_dpaiop_type = {
|
||||
.name = "fsl_mc_bus_dpaiop"
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpaiop_type);
|
||||
|
||||
struct device_type fsl_mc_bus_dpci_type = {
|
||||
.name = "fsl_mc_bus_dpci"
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpci_type);
|
||||
|
||||
struct device_type fsl_mc_bus_dpdmai_type = {
|
||||
.name = "fsl_mc_bus_dpdmai"
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdmai_type);
|
||||
|
||||
static struct device_type *fsl_mc_get_device_type(const char *type)
|
||||
{
|
||||
static const struct {
|
||||
@ -229,6 +254,11 @@ static struct device_type *fsl_mc_get_device_type(const char *type)
|
||||
{ &fsl_mc_bus_dpmac_type, "dpmac" },
|
||||
{ &fsl_mc_bus_dprtc_type, "dprtc" },
|
||||
{ &fsl_mc_bus_dpseci_type, "dpseci" },
|
||||
{ &fsl_mc_bus_dpdmux_type, "dpdmux" },
|
||||
{ &fsl_mc_bus_dpdcei_type, "dpdcei" },
|
||||
{ &fsl_mc_bus_dpaiop_type, "dpaiop" },
|
||||
{ &fsl_mc_bus_dpci_type, "dpci" },
|
||||
{ &fsl_mc_bus_dpdmai_type, "dpdmai" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
int i;
|
||||
|
@ -82,7 +82,7 @@ int __must_check fsl_create_mc_io(struct device *dev,
|
||||
mc_io->portal_phys_addr = mc_portal_phys_addr;
|
||||
mc_io->portal_size = mc_portal_size;
|
||||
if (flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
|
||||
spin_lock_init(&mc_io->spinlock);
|
||||
raw_spin_lock_init(&mc_io->spinlock);
|
||||
else
|
||||
mutex_init(&mc_io->mutex);
|
||||
|
||||
|
@ -251,7 +251,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd)
|
||||
return -EINVAL;
|
||||
|
||||
if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
|
||||
spin_lock_irqsave(&mc_io->spinlock, irq_flags);
|
||||
raw_spin_lock_irqsave(&mc_io->spinlock, irq_flags);
|
||||
else
|
||||
mutex_lock(&mc_io->mutex);
|
||||
|
||||
@ -287,7 +287,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd)
|
||||
error = 0;
|
||||
common_exit:
|
||||
if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
|
||||
spin_unlock_irqrestore(&mc_io->spinlock, irq_flags);
|
||||
raw_spin_unlock_irqrestore(&mc_io->spinlock, irq_flags);
|
||||
else
|
||||
mutex_unlock(&mc_io->mutex);
|
||||
|
||||
|
@ -38,7 +38,7 @@ config PRINTER
|
||||
box (as opposed to using a serial printer; if the connector at the
|
||||
printer has 9 or 25 holes ["female"], then it's serial), say Y.
|
||||
Also read the Printing-HOWTO, available from
|
||||
<http://www.tldp.org/docs.html#howto>.
|
||||
<https://www.tldp.org/docs.html#howto>.
|
||||
|
||||
It is possible to share one parallel port among several devices
|
||||
(e.g. printer and ZIP drive) and it is safe to compile the
|
||||
@ -201,7 +201,7 @@ config DTLK
|
||||
depends on ISA
|
||||
help
|
||||
This driver is for the DoubleTalk PC, a speech synthesizer
|
||||
manufactured by RC Systems (<http://www.rcsys.com/>). It is also
|
||||
manufactured by RC Systems (<https://www.rcsys.com/>). It is also
|
||||
called the `internal DoubleTalk'.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
@ -237,7 +237,7 @@ config APPLICOM
|
||||
This driver provides the kernel-side support for the intelligent
|
||||
fieldbus cards made by Applicom International. More information
|
||||
about these cards can be found on the WWW at the address
|
||||
<http://www.applicom-int.com/>, or by email from David Woodhouse
|
||||
<https://www.applicom-int.com/>, or by email from David Woodhouse
|
||||
<dwmw2@infradead.org>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
|
@ -126,7 +126,7 @@ static int smapi_request(unsigned short inBX, unsigned short inCX,
|
||||
|
||||
int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings)
|
||||
{
|
||||
int bRC = -EIO;
|
||||
int bRC;
|
||||
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
|
||||
static const unsigned short ausDspBases[] = {
|
||||
0x0030, 0x4E30, 0x8E30, 0xCE30,
|
||||
@ -497,7 +497,7 @@ exit_smapi_request_error:
|
||||
|
||||
int smapi_set_DSP_power_state(bool bOn)
|
||||
{
|
||||
int bRC = -EIO;
|
||||
int bRC;
|
||||
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
|
||||
unsigned short usPowerFunction;
|
||||
|
||||
|
@ -37,7 +37,7 @@ static struct raw_device_data *raw_devices;
|
||||
static DEFINE_MUTEX(raw_mutex);
|
||||
static const struct file_operations raw_ctl_fops; /* forward declaration */
|
||||
|
||||
static int max_raw_minors = MAX_RAW_MINORS;
|
||||
static int max_raw_minors = CONFIG_MAX_RAW_DEVS;
|
||||
|
||||
module_param(max_raw_minors, int, 0);
|
||||
MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)");
|
||||
@ -317,9 +317,9 @@ static int __init raw_init(void)
|
||||
int ret;
|
||||
|
||||
if (max_raw_minors < 1 || max_raw_minors > 65536) {
|
||||
printk(KERN_WARNING "raw: invalid max_raw_minors (must be"
|
||||
" between 1 and 65536), using %d\n", MAX_RAW_MINORS);
|
||||
max_raw_minors = MAX_RAW_MINORS;
|
||||
pr_warn("raw: invalid max_raw_minors (must be between 1 and 65536), using %d\n",
|
||||
CONFIG_MAX_RAW_DEVS);
|
||||
max_raw_minors = CONFIG_MAX_RAW_DEVS;
|
||||
}
|
||||
|
||||
raw_devices = vzalloc(array_size(max_raw_minors,
|
||||
|
@ -172,7 +172,7 @@ static struct tty_driver *ttyprintk_driver;
|
||||
|
||||
static int __init ttyprintk_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
int ret;
|
||||
|
||||
spin_lock_init(&tpk_port.spinlock);
|
||||
|
||||
|
@ -2112,18 +2112,18 @@ fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct virtio_device_id id_table[] = {
|
||||
static const struct virtio_device_id id_table[] = {
|
||||
{ VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(virtio, id_table);
|
||||
|
||||
static unsigned int features[] = {
|
||||
static const unsigned int features[] = {
|
||||
VIRTIO_CONSOLE_F_SIZE,
|
||||
VIRTIO_CONSOLE_F_MULTIPORT,
|
||||
};
|
||||
|
||||
static struct virtio_device_id rproc_serial_id_table[] = {
|
||||
static const struct virtio_device_id rproc_serial_id_table[] = {
|
||||
#if IS_ENABLED(CONFIG_REMOTEPROC)
|
||||
{ VIRTIO_ID_RPROC_SERIAL, VIRTIO_DEV_ANY_ID },
|
||||
#endif
|
||||
@ -2131,7 +2131,7 @@ static struct virtio_device_id rproc_serial_id_table[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(virtio, rproc_serial_id_table);
|
||||
|
||||
static unsigned int rproc_serial_features[] = {
|
||||
static const unsigned int rproc_serial_features[] = {
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -20,10 +20,16 @@
|
||||
#define RSU_VERSION_MASK GENMASK_ULL(63, 32)
|
||||
#define RSU_ERROR_LOCATION_MASK GENMASK_ULL(31, 0)
|
||||
#define RSU_ERROR_DETAIL_MASK GENMASK_ULL(63, 32)
|
||||
#define RSU_DCMF0_MASK GENMASK_ULL(31, 0)
|
||||
#define RSU_DCMF1_MASK GENMASK_ULL(63, 32)
|
||||
#define RSU_DCMF2_MASK GENMASK_ULL(31, 0)
|
||||
#define RSU_DCMF3_MASK GENMASK_ULL(63, 32)
|
||||
|
||||
#define RSU_TIMEOUT (msecs_to_jiffies(SVC_RSU_REQUEST_TIMEOUT_MS))
|
||||
|
||||
#define INVALID_RETRY_COUNTER 0xFFFFFFFF
|
||||
#define INVALID_RETRY_COUNTER 0xFF
|
||||
#define INVALID_DCMF_VERSION 0xFF
|
||||
|
||||
|
||||
typedef void (*rsu_callback)(struct stratix10_svc_client *client,
|
||||
struct stratix10_svc_cb_data *data);
|
||||
@ -35,11 +41,16 @@ typedef void (*rsu_callback)(struct stratix10_svc_client *client,
|
||||
* @lock: a mutex to protect callback completion state
|
||||
* @status.current_image: address of image currently running in flash
|
||||
* @status.fail_image: address of failed image in flash
|
||||
* @status.version: the version number of RSU firmware
|
||||
* @status.version: the interface version number of RSU firmware
|
||||
* @status.state: the state of RSU system
|
||||
* @status.error_details: error code
|
||||
* @status.error_location: the error offset inside the image that failed
|
||||
* @dcmf_version.dcmf0: Quartus dcmf0 version
|
||||
* @dcmf_version.dcmf1: Quartus dcmf1 version
|
||||
* @dcmf_version.dcmf2: Quartus dcmf2 version
|
||||
* @dcmf_version.dcmf3: Quartus dcmf3 version
|
||||
* @retry_counter: the current image's retry counter
|
||||
* @max_retry: the preset max retry value
|
||||
*/
|
||||
struct stratix10_rsu_priv {
|
||||
struct stratix10_svc_chan *chan;
|
||||
@ -54,7 +65,16 @@ struct stratix10_rsu_priv {
|
||||
unsigned int error_details;
|
||||
unsigned int error_location;
|
||||
} status;
|
||||
|
||||
struct {
|
||||
unsigned int dcmf0;
|
||||
unsigned int dcmf1;
|
||||
unsigned int dcmf2;
|
||||
unsigned int dcmf3;
|
||||
} dcmf_version;
|
||||
|
||||
unsigned int retry_counter;
|
||||
unsigned int max_retry;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -109,7 +129,7 @@ static void rsu_command_callback(struct stratix10_svc_client *client,
|
||||
struct stratix10_rsu_priv *priv = client->priv;
|
||||
|
||||
if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
|
||||
dev_warn(client->dev, "Secure FW doesn't support notify\n");
|
||||
dev_warn(client->dev, "FW doesn't support notify\n");
|
||||
else if (data->status == BIT(SVC_STATUS_ERROR))
|
||||
dev_err(client->dev, "Failure, returned status is %lu\n",
|
||||
BIT(data->status));
|
||||
@ -119,7 +139,7 @@ static void rsu_command_callback(struct stratix10_svc_client *client,
|
||||
|
||||
/**
|
||||
* rsu_retry_callback() - Callback from Intel service layer for getting
|
||||
* the current image's retry counter from firmware
|
||||
* the current image's retry counter from the firmware
|
||||
* @client: pointer to client
|
||||
* @data: pointer to callback data structure
|
||||
*
|
||||
@ -136,7 +156,7 @@ static void rsu_retry_callback(struct stratix10_svc_client *client,
|
||||
if (data->status == BIT(SVC_STATUS_OK))
|
||||
priv->retry_counter = *counter;
|
||||
else if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
|
||||
dev_warn(client->dev, "Secure FW doesn't support retry\n");
|
||||
dev_warn(client->dev, "FW doesn't support retry\n");
|
||||
else
|
||||
dev_err(client->dev, "Failed to get retry counter %lu\n",
|
||||
BIT(data->status));
|
||||
@ -144,6 +164,57 @@ static void rsu_retry_callback(struct stratix10_svc_client *client,
|
||||
complete(&priv->completion);
|
||||
}
|
||||
|
||||
/**
|
||||
* rsu_max_retry_callback() - Callback from Intel service layer for getting
|
||||
* the max retry value from the firmware
|
||||
* @client: pointer to client
|
||||
* @data: pointer to callback data structure
|
||||
*
|
||||
* Callback from Intel service layer for max retry.
|
||||
*/
|
||||
static void rsu_max_retry_callback(struct stratix10_svc_client *client,
|
||||
struct stratix10_svc_cb_data *data)
|
||||
{
|
||||
struct stratix10_rsu_priv *priv = client->priv;
|
||||
unsigned int *max_retry = (unsigned int *)data->kaddr1;
|
||||
|
||||
if (data->status == BIT(SVC_STATUS_OK))
|
||||
priv->max_retry = *max_retry;
|
||||
else if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
|
||||
dev_warn(client->dev, "FW doesn't support max retry\n");
|
||||
else
|
||||
dev_err(client->dev, "Failed to get max retry %lu\n",
|
||||
BIT(data->status));
|
||||
|
||||
complete(&priv->completion);
|
||||
}
|
||||
|
||||
/**
|
||||
* rsu_dcmf_version_callback() - Callback from Intel service layer for getting
|
||||
* the DCMF version
|
||||
* @client: pointer to client
|
||||
* @data: pointer to callback data structure
|
||||
*
|
||||
* Callback from Intel service layer for DCMF version number
|
||||
*/
|
||||
static void rsu_dcmf_version_callback(struct stratix10_svc_client *client,
|
||||
struct stratix10_svc_cb_data *data)
|
||||
{
|
||||
struct stratix10_rsu_priv *priv = client->priv;
|
||||
unsigned long long *value1 = (unsigned long long *)data->kaddr1;
|
||||
unsigned long long *value2 = (unsigned long long *)data->kaddr2;
|
||||
|
||||
if (data->status == BIT(SVC_STATUS_OK)) {
|
||||
priv->dcmf_version.dcmf0 = FIELD_GET(RSU_DCMF0_MASK, *value1);
|
||||
priv->dcmf_version.dcmf1 = FIELD_GET(RSU_DCMF1_MASK, *value1);
|
||||
priv->dcmf_version.dcmf2 = FIELD_GET(RSU_DCMF2_MASK, *value2);
|
||||
priv->dcmf_version.dcmf3 = FIELD_GET(RSU_DCMF3_MASK, *value2);
|
||||
} else
|
||||
dev_err(client->dev, "failed to get DCMF version\n");
|
||||
|
||||
complete(&priv->completion);
|
||||
}
|
||||
|
||||
/**
|
||||
* rsu_send_msg() - send a message to Intel service layer
|
||||
* @priv: pointer to rsu private data
|
||||
@ -282,6 +353,61 @@ static ssize_t retry_counter_show(struct device *dev,
|
||||
return sprintf(buf, "0x%08x\n", priv->retry_counter);
|
||||
}
|
||||
|
||||
static ssize_t max_retry_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
|
||||
return sprintf(buf, "0x%08x\n", priv->max_retry);
|
||||
}
|
||||
|
||||
static ssize_t dcmf0_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
|
||||
return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf0);
|
||||
}
|
||||
|
||||
static ssize_t dcmf1_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
|
||||
return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf1);
|
||||
}
|
||||
|
||||
static ssize_t dcmf2_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
|
||||
return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf2);
|
||||
}
|
||||
|
||||
static ssize_t dcmf3_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
|
||||
return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf3);
|
||||
}
|
||||
|
||||
static ssize_t reboot_image_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@ -290,7 +416,7 @@ static ssize_t reboot_image_store(struct device *dev,
|
||||
unsigned long address;
|
||||
int ret;
|
||||
|
||||
if (priv == 0)
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
|
||||
ret = kstrtoul(buf, 0, &address);
|
||||
@ -315,7 +441,7 @@ static ssize_t notify_store(struct device *dev,
|
||||
unsigned long status;
|
||||
int ret;
|
||||
|
||||
if (priv == 0)
|
||||
if (!priv)
|
||||
return -ENODEV;
|
||||
|
||||
ret = kstrtoul(buf, 0, &status);
|
||||
@ -353,6 +479,11 @@ static DEVICE_ATTR_RO(version);
|
||||
static DEVICE_ATTR_RO(error_location);
|
||||
static DEVICE_ATTR_RO(error_details);
|
||||
static DEVICE_ATTR_RO(retry_counter);
|
||||
static DEVICE_ATTR_RO(max_retry);
|
||||
static DEVICE_ATTR_RO(dcmf0);
|
||||
static DEVICE_ATTR_RO(dcmf1);
|
||||
static DEVICE_ATTR_RO(dcmf2);
|
||||
static DEVICE_ATTR_RO(dcmf3);
|
||||
static DEVICE_ATTR_WO(reboot_image);
|
||||
static DEVICE_ATTR_WO(notify);
|
||||
|
||||
@ -364,6 +495,11 @@ static struct attribute *rsu_attrs[] = {
|
||||
&dev_attr_error_location.attr,
|
||||
&dev_attr_error_details.attr,
|
||||
&dev_attr_retry_counter.attr,
|
||||
&dev_attr_max_retry.attr,
|
||||
&dev_attr_dcmf0.attr,
|
||||
&dev_attr_dcmf1.attr,
|
||||
&dev_attr_dcmf2.attr,
|
||||
&dev_attr_dcmf3.attr,
|
||||
&dev_attr_reboot_image.attr,
|
||||
&dev_attr_notify.attr,
|
||||
NULL
|
||||
@ -391,6 +527,11 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
|
||||
priv->status.version = 0;
|
||||
priv->status.state = 0;
|
||||
priv->retry_counter = INVALID_RETRY_COUNTER;
|
||||
priv->dcmf_version.dcmf0 = INVALID_DCMF_VERSION;
|
||||
priv->dcmf_version.dcmf1 = INVALID_DCMF_VERSION;
|
||||
priv->dcmf_version.dcmf2 = INVALID_DCMF_VERSION;
|
||||
priv->dcmf_version.dcmf3 = INVALID_DCMF_VERSION;
|
||||
priv->max_retry = INVALID_RETRY_COUNTER;
|
||||
|
||||
mutex_init(&priv->lock);
|
||||
priv->chan = stratix10_svc_request_channel_byname(&priv->client,
|
||||
@ -412,12 +553,27 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
}
|
||||
|
||||
/* get DCMF version from firmware */
|
||||
ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION,
|
||||
0, rsu_dcmf_version_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting DCMF version %i\n", ret);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
}
|
||||
|
||||
ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting RSU retry %i\n", ret);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
}
|
||||
|
||||
ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0,
|
||||
rsu_max_retry_callback);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error, getting RSU max retry %i\n", ret);
|
||||
stratix10_svc_free_channel(priv->chan);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -305,9 +305,15 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data,
|
||||
cb_data->status = BIT(SVC_STATUS_COMPLETED);
|
||||
break;
|
||||
case COMMAND_RSU_RETRY:
|
||||
case COMMAND_RSU_MAX_RETRY:
|
||||
cb_data->status = BIT(SVC_STATUS_OK);
|
||||
cb_data->kaddr1 = &res.a1;
|
||||
break;
|
||||
case COMMAND_RSU_DCMF_VERSION:
|
||||
cb_data->status = BIT(SVC_STATUS_OK);
|
||||
cb_data->kaddr1 = &res.a1;
|
||||
cb_data->kaddr2 = &res.a2;
|
||||
break;
|
||||
default:
|
||||
pr_warn("it shouldn't happen\n");
|
||||
break;
|
||||
@ -406,6 +412,16 @@ static int svc_normal_to_secure_thread(void *data)
|
||||
a1 = 0;
|
||||
a2 = 0;
|
||||
break;
|
||||
case COMMAND_RSU_MAX_RETRY:
|
||||
a0 = INTEL_SIP_SMC_RSU_MAX_RETRY;
|
||||
a1 = 0;
|
||||
a2 = 0;
|
||||
break;
|
||||
case COMMAND_RSU_DCMF_VERSION:
|
||||
a0 = INTEL_SIP_SMC_RSU_DCMF_VERSION;
|
||||
a1 = 0;
|
||||
a2 = 0;
|
||||
break;
|
||||
default:
|
||||
pr_warn("it shouldn't happen\n");
|
||||
break;
|
||||
@ -474,6 +490,7 @@ static int svc_normal_to_secure_thread(void *data)
|
||||
* doesn't support RSU notify or retry
|
||||
*/
|
||||
if ((pdata->command == COMMAND_RSU_RETRY) ||
|
||||
(pdata->command == COMMAND_RSU_MAX_RETRY) ||
|
||||
(pdata->command == COMMAND_RSU_NOTIFY)) {
|
||||
cbdata->status =
|
||||
BIT(SVC_STATUS_NO_SUPPORT);
|
||||
|
@ -16,15 +16,6 @@
|
||||
|
||||
#include "dfl-afu.h"
|
||||
|
||||
static void put_all_pages(struct page **pages, int npages)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < npages; i++)
|
||||
if (pages[i])
|
||||
put_page(pages[i]);
|
||||
}
|
||||
|
||||
void afu_dma_region_init(struct dfl_feature_platform_data *pdata)
|
||||
{
|
||||
struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata);
|
||||
@ -57,22 +48,22 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata,
|
||||
goto unlock_vm;
|
||||
}
|
||||
|
||||
pinned = get_user_pages_fast(region->user_addr, npages, FOLL_WRITE,
|
||||
pinned = pin_user_pages_fast(region->user_addr, npages, FOLL_WRITE,
|
||||
region->pages);
|
||||
if (pinned < 0) {
|
||||
ret = pinned;
|
||||
goto free_pages;
|
||||
} else if (pinned != npages) {
|
||||
ret = -EFAULT;
|
||||
goto put_pages;
|
||||
goto unpin_pages;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "%d pages pinned\n", pinned);
|
||||
|
||||
return 0;
|
||||
|
||||
put_pages:
|
||||
put_all_pages(region->pages, pinned);
|
||||
unpin_pages:
|
||||
unpin_user_pages(region->pages, pinned);
|
||||
free_pages:
|
||||
kfree(region->pages);
|
||||
unlock_vm:
|
||||
@ -94,7 +85,7 @@ static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata,
|
||||
long npages = region->length >> PAGE_SHIFT;
|
||||
struct device *dev = &pdata->dev->dev;
|
||||
|
||||
put_all_pages(region->pages, npages);
|
||||
unpin_user_pages(region->pages, npages);
|
||||
kfree(region->pages);
|
||||
account_locked_vm(current->mm, npages, false);
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
* Mitchel Henry <henry.mitchel@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/fpga-dfl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "dfl-afu.h"
|
||||
@ -219,6 +220,21 @@ static void port_err_uinit(struct platform_device *pdev,
|
||||
afu_port_err_mask(&pdev->dev, true);
|
||||
}
|
||||
|
||||
static long
|
||||
port_err_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DFL_FPGA_PORT_ERR_GET_IRQ_NUM:
|
||||
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
|
||||
case DFL_FPGA_PORT_ERR_SET_IRQ:
|
||||
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
|
||||
default:
|
||||
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
const struct dfl_feature_id port_err_id_table[] = {
|
||||
{.id = PORT_FEATURE_ID_ERROR,},
|
||||
{0,}
|
||||
@ -227,4 +243,5 @@ const struct dfl_feature_id port_err_id_table[] = {
|
||||
const struct dfl_feature_ops port_err_ops = {
|
||||
.init = port_err_init,
|
||||
.uinit = port_err_uinit,
|
||||
.ioctl = port_err_ioctl,
|
||||
};
|
||||
|
@ -530,6 +530,30 @@ static const struct dfl_feature_ops port_stp_ops = {
|
||||
.init = port_stp_init,
|
||||
};
|
||||
|
||||
static long
|
||||
port_uint_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DFL_FPGA_PORT_UINT_GET_IRQ_NUM:
|
||||
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
|
||||
case DFL_FPGA_PORT_UINT_SET_IRQ:
|
||||
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
|
||||
default:
|
||||
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dfl_feature_id port_uint_id_table[] = {
|
||||
{.id = PORT_FEATURE_ID_UINT,},
|
||||
{0,}
|
||||
};
|
||||
|
||||
static const struct dfl_feature_ops port_uint_ops = {
|
||||
.ioctl = port_uint_ioctl,
|
||||
};
|
||||
|
||||
static struct dfl_feature_driver port_feature_drvs[] = {
|
||||
{
|
||||
.id_table = port_hdr_id_table,
|
||||
@ -547,6 +571,10 @@ static struct dfl_feature_driver port_feature_drvs[] = {
|
||||
.id_table = port_stp_id_table,
|
||||
.ops = &port_stp_ops,
|
||||
},
|
||||
{
|
||||
.id_table = port_uint_id_table,
|
||||
.ops = &port_uint_ops,
|
||||
},
|
||||
{
|
||||
.ops = NULL,
|
||||
}
|
||||
@ -578,6 +606,7 @@ static int afu_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct platform_device *pdev = filp->private_data;
|
||||
struct dfl_feature_platform_data *pdata;
|
||||
struct dfl_feature *feature;
|
||||
|
||||
dev_dbg(&pdev->dev, "Device File Release\n");
|
||||
|
||||
@ -587,6 +616,9 @@ static int afu_release(struct inode *inode, struct file *filp)
|
||||
dfl_feature_dev_use_end(pdata);
|
||||
|
||||
if (!dfl_feature_dev_use_count(pdata)) {
|
||||
dfl_fpga_dev_for_each_feature(pdata, feature)
|
||||
dfl_fpga_set_irq_triggers(feature, 0,
|
||||
feature->nr_irqs, NULL);
|
||||
__port_reset(pdev);
|
||||
afu_dma_region_destroy(pdata);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
* Mitchel, Henry <henry.mitchel@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/fpga-dfl.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "dfl.h"
|
||||
@ -348,6 +349,22 @@ static void fme_global_err_uinit(struct platform_device *pdev,
|
||||
fme_err_mask(&pdev->dev, true);
|
||||
}
|
||||
|
||||
static long
|
||||
fme_global_error_ioctl(struct platform_device *pdev,
|
||||
struct dfl_feature *feature,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case DFL_FPGA_FME_ERR_GET_IRQ_NUM:
|
||||
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
|
||||
case DFL_FPGA_FME_ERR_SET_IRQ:
|
||||
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
|
||||
default:
|
||||
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
const struct dfl_feature_id fme_global_err_id_table[] = {
|
||||
{.id = FME_FEATURE_ID_GLOBAL_ERR,},
|
||||
{0,}
|
||||
@ -356,4 +373,5 @@ const struct dfl_feature_id fme_global_err_id_table[] = {
|
||||
const struct dfl_feature_ops fme_global_err_ops = {
|
||||
.init = fme_global_err_init,
|
||||
.uinit = fme_global_err_uinit,
|
||||
.ioctl = fme_global_error_ioctl,
|
||||
};
|
||||
|
@ -620,11 +620,17 @@ static int fme_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = filp->private_data;
|
||||
struct platform_device *pdev = pdata->dev;
|
||||
struct dfl_feature *feature;
|
||||
|
||||
dev_dbg(&pdev->dev, "Device File Release\n");
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
dfl_feature_dev_use_end(pdata);
|
||||
|
||||
if (!dfl_feature_dev_use_count(pdata))
|
||||
dfl_fpga_dev_for_each_feature(pdata, feature)
|
||||
dfl_fpga_set_irq_triggers(feature, 0,
|
||||
feature->nr_irqs, NULL);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
return 0;
|
||||
|
@ -39,10 +39,32 @@ static void __iomem *cci_pci_ioremap_bar(struct pci_dev *pcidev, int bar)
|
||||
return pcim_iomap_table(pcidev)[bar];
|
||||
}
|
||||
|
||||
static int cci_pci_alloc_irq(struct pci_dev *pcidev)
|
||||
{
|
||||
int ret, nvec = pci_msix_vec_count(pcidev);
|
||||
|
||||
if (nvec <= 0) {
|
||||
dev_dbg(&pcidev->dev, "fpga interrupt not supported\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = pci_alloc_irq_vectors(pcidev, nvec, nvec, PCI_IRQ_MSIX);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return nvec;
|
||||
}
|
||||
|
||||
static void cci_pci_free_irq(struct pci_dev *pcidev)
|
||||
{
|
||||
pci_free_irq_vectors(pcidev);
|
||||
}
|
||||
|
||||
/* PCI Device ID */
|
||||
#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD
|
||||
#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0
|
||||
#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4
|
||||
#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30
|
||||
/* VF Device */
|
||||
#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF
|
||||
#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1
|
||||
@ -55,6 +77,7 @@ static struct pci_device_id cci_pcie_id_tbl[] = {
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_6_X),},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),},
|
||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),},
|
||||
{0,}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl);
|
||||
@ -78,17 +101,34 @@ static void cci_remove_feature_devs(struct pci_dev *pcidev)
|
||||
|
||||
/* remove all children feature devices */
|
||||
dfl_fpga_feature_devs_remove(drvdata->cdev);
|
||||
cci_pci_free_irq(pcidev);
|
||||
}
|
||||
|
||||
static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec)
|
||||
{
|
||||
unsigned int i;
|
||||
int *table;
|
||||
|
||||
table = kcalloc(nvec, sizeof(int), GFP_KERNEL);
|
||||
if (!table)
|
||||
return table;
|
||||
|
||||
for (i = 0; i < nvec; i++)
|
||||
table[i] = pci_irq_vector(pcidev, i);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
/* enumerate feature devices under pci device */
|
||||
static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
|
||||
{
|
||||
struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
|
||||
int port_num, bar, i, nvec, ret = 0;
|
||||
struct dfl_fpga_enum_info *info;
|
||||
struct dfl_fpga_cdev *cdev;
|
||||
resource_size_t start, len;
|
||||
int port_num, bar, i, ret = 0;
|
||||
void __iomem *base;
|
||||
int *irq_table;
|
||||
u32 offset;
|
||||
u64 v;
|
||||
|
||||
@ -97,11 +137,30 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
/* add irq info for enumeration if the device support irq */
|
||||
nvec = cci_pci_alloc_irq(pcidev);
|
||||
if (nvec < 0) {
|
||||
dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec);
|
||||
ret = nvec;
|
||||
goto enum_info_free_exit;
|
||||
} else if (nvec) {
|
||||
irq_table = cci_pci_create_irq_table(pcidev, nvec);
|
||||
if (!irq_table) {
|
||||
ret = -ENOMEM;
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table);
|
||||
kfree(irq_table);
|
||||
if (ret)
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
/* start to find Device Feature List from Bar 0 */
|
||||
base = cci_pci_ioremap_bar(pcidev, 0);
|
||||
if (!base) {
|
||||
ret = -ENOMEM;
|
||||
goto enum_info_free_exit;
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -154,7 +213,7 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
|
||||
dfl_fpga_enum_info_add_dfl(info, start, len, base);
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
goto enum_info_free_exit;
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
/* start enumeration with prepared enumeration information */
|
||||
@ -162,11 +221,14 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
|
||||
if (IS_ERR(cdev)) {
|
||||
dev_err(&pcidev->dev, "Enumeration failure\n");
|
||||
ret = PTR_ERR(cdev);
|
||||
goto enum_info_free_exit;
|
||||
goto irq_free_exit;
|
||||
}
|
||||
|
||||
drvdata->cdev = cdev;
|
||||
|
||||
irq_free_exit:
|
||||
if (ret)
|
||||
cci_pci_free_irq(pcidev);
|
||||
enum_info_free_exit:
|
||||
dfl_fpga_enum_info_free(info);
|
||||
|
||||
@ -211,12 +273,10 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
|
||||
}
|
||||
|
||||
ret = cci_enumerate_feature_devs(pcidev);
|
||||
if (ret) {
|
||||
dev_err(&pcidev->dev, "enumeration failure %d.\n", ret);
|
||||
goto disable_error_report_exit;
|
||||
}
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
dev_err(&pcidev->dev, "enumeration failure %d.\n", ret);
|
||||
|
||||
disable_error_report_exit:
|
||||
pci_disable_pcie_error_reporting(pcidev);
|
||||
|
@ -10,7 +10,9 @@
|
||||
* Wu Hao <hao.wu@intel.com>
|
||||
* Xiao Guangrong <guangrong.xiao@linux.intel.com>
|
||||
*/
|
||||
#include <linux/fpga-dfl.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "dfl.h"
|
||||
|
||||
@ -421,6 +423,9 @@ EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister);
|
||||
*
|
||||
* @dev: device to enumerate.
|
||||
* @cdev: the container device for all feature devices.
|
||||
* @nr_irqs: number of irqs for all feature devices.
|
||||
* @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of
|
||||
* this device.
|
||||
* @feature_dev: current feature device.
|
||||
* @ioaddr: header register region address of feature device in enumeration.
|
||||
* @sub_features: a sub features linked list for feature device in enumeration.
|
||||
@ -429,6 +434,9 @@ EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister);
|
||||
struct build_feature_devs_info {
|
||||
struct device *dev;
|
||||
struct dfl_fpga_cdev *cdev;
|
||||
unsigned int nr_irqs;
|
||||
int *irq_table;
|
||||
|
||||
struct platform_device *feature_dev;
|
||||
void __iomem *ioaddr;
|
||||
struct list_head sub_features;
|
||||
@ -442,12 +450,16 @@ struct build_feature_devs_info {
|
||||
* @mmio_res: mmio resource of this sub feature.
|
||||
* @ioaddr: mapped base address of mmio resource.
|
||||
* @node: node in sub_features linked list.
|
||||
* @irq_base: start of irq index in this sub feature.
|
||||
* @nr_irqs: number of irqs of this sub feature.
|
||||
*/
|
||||
struct dfl_feature_info {
|
||||
u64 fid;
|
||||
struct resource mmio_res;
|
||||
void __iomem *ioaddr;
|
||||
struct list_head node;
|
||||
unsigned int irq_base;
|
||||
unsigned int nr_irqs;
|
||||
};
|
||||
|
||||
static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev,
|
||||
@ -487,8 +499,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
|
||||
* it will be automatically freed by device's release() callback,
|
||||
* platform_device_release().
|
||||
*/
|
||||
pdata = kzalloc(dfl_feature_platform_data_size(binfo->feature_num),
|
||||
GFP_KERNEL);
|
||||
pdata = kzalloc(struct_size(pdata, features, binfo->feature_num), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -520,13 +531,30 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
|
||||
/* fill features and resource information for feature dev */
|
||||
list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) {
|
||||
struct dfl_feature *feature = &pdata->features[index];
|
||||
struct dfl_feature_irq_ctx *ctx;
|
||||
unsigned int i;
|
||||
|
||||
/* save resource information for each feature */
|
||||
feature->dev = fdev;
|
||||
feature->id = finfo->fid;
|
||||
feature->resource_index = index;
|
||||
feature->ioaddr = finfo->ioaddr;
|
||||
fdev->resource[index++] = finfo->mmio_res;
|
||||
|
||||
if (finfo->nr_irqs) {
|
||||
ctx = devm_kcalloc(binfo->dev, finfo->nr_irqs,
|
||||
sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < finfo->nr_irqs; i++)
|
||||
ctx[i].irq =
|
||||
binfo->irq_table[finfo->irq_base + i];
|
||||
|
||||
feature->irq_ctx = ctx;
|
||||
feature->nr_irqs = finfo->nr_irqs;
|
||||
}
|
||||
|
||||
list_del(&finfo->node);
|
||||
kfree(finfo);
|
||||
}
|
||||
@ -638,6 +666,78 @@ static u64 feature_id(void __iomem *start)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_feature_irqs(struct build_feature_devs_info *binfo,
|
||||
resource_size_t ofst, u64 fid,
|
||||
unsigned int *irq_base, unsigned int *nr_irqs)
|
||||
{
|
||||
void __iomem *base = binfo->ioaddr + ofst;
|
||||
unsigned int i, ibase, inr = 0;
|
||||
int virq;
|
||||
u64 v;
|
||||
|
||||
/*
|
||||
* Ideally DFL framework should only read info from DFL header, but
|
||||
* current version DFL only provides mmio resources information for
|
||||
* each feature in DFL Header, no field for interrupt resources.
|
||||
* Interrupt resource information is provided by specific mmio
|
||||
* registers of each private feature which supports interrupt. So in
|
||||
* order to parse and assign irq resources, DFL framework has to look
|
||||
* into specific capability registers of these private features.
|
||||
*
|
||||
* Once future DFL version supports generic interrupt resource
|
||||
* information in common DFL headers, the generic interrupt parsing
|
||||
* code will be added. But in order to be compatible to old version
|
||||
* DFL, the driver may still fall back to these quirks.
|
||||
*/
|
||||
switch (fid) {
|
||||
case PORT_FEATURE_ID_UINT:
|
||||
v = readq(base + PORT_UINT_CAP);
|
||||
ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
|
||||
inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
|
||||
break;
|
||||
case PORT_FEATURE_ID_ERROR:
|
||||
v = readq(base + PORT_ERROR_CAP);
|
||||
ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
|
||||
break;
|
||||
case FME_FEATURE_ID_GLOBAL_ERR:
|
||||
v = readq(base + FME_ERROR_CAP);
|
||||
ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
|
||||
inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inr) {
|
||||
*irq_base = 0;
|
||||
*nr_irqs = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_dbg(binfo->dev, "feature: 0x%llx, irq_base: %u, nr_irqs: %u\n",
|
||||
fid, ibase, inr);
|
||||
|
||||
if (ibase + inr > binfo->nr_irqs) {
|
||||
dev_err(binfo->dev,
|
||||
"Invalid interrupt number in feature 0x%llx\n", fid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < inr; i++) {
|
||||
virq = binfo->irq_table[ibase + i];
|
||||
if (virq < 0 || virq > NR_IRQS) {
|
||||
dev_err(binfo->dev,
|
||||
"Invalid irq table entry for feature 0x%llx\n",
|
||||
fid);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
*irq_base = ibase;
|
||||
*nr_irqs = inr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* when create sub feature instances, for private features, it doesn't need
|
||||
* to provide resource size and feature id as they could be read from DFH
|
||||
@ -650,7 +750,9 @@ create_feature_instance(struct build_feature_devs_info *binfo,
|
||||
struct dfl_fpga_enum_dfl *dfl, resource_size_t ofst,
|
||||
resource_size_t size, u64 fid)
|
||||
{
|
||||
unsigned int irq_base, nr_irqs;
|
||||
struct dfl_feature_info *finfo;
|
||||
int ret;
|
||||
|
||||
/* read feature size and id if inputs are invalid */
|
||||
size = size ? size : feature_size(dfl->ioaddr + ofst);
|
||||
@ -659,6 +761,10 @@ create_feature_instance(struct build_feature_devs_info *binfo,
|
||||
if (dfl->len - ofst < size)
|
||||
return -EINVAL;
|
||||
|
||||
ret = parse_feature_irqs(binfo, ofst, fid, &irq_base, &nr_irqs);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
finfo = kzalloc(sizeof(*finfo), GFP_KERNEL);
|
||||
if (!finfo)
|
||||
return -ENOMEM;
|
||||
@ -667,6 +773,8 @@ create_feature_instance(struct build_feature_devs_info *binfo,
|
||||
finfo->mmio_res.start = dfl->start + ofst;
|
||||
finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
|
||||
finfo->mmio_res.flags = IORESOURCE_MEM;
|
||||
finfo->irq_base = irq_base;
|
||||
finfo->nr_irqs = nr_irqs;
|
||||
finfo->ioaddr = dfl->ioaddr + ofst;
|
||||
|
||||
list_add_tail(&finfo->node, &binfo->sub_features);
|
||||
@ -853,6 +961,10 @@ void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
|
||||
devm_kfree(dev, dfl);
|
||||
}
|
||||
|
||||
/* remove irq table */
|
||||
if (info->irq_table)
|
||||
devm_kfree(dev, info->irq_table);
|
||||
|
||||
devm_kfree(dev, info);
|
||||
put_device(dev);
|
||||
}
|
||||
@ -892,6 +1004,45 @@ int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_dfl);
|
||||
|
||||
/**
|
||||
* dfl_fpga_enum_info_add_irq - add irq table to enum info
|
||||
*
|
||||
* @info: ptr to dfl_fpga_enum_info
|
||||
* @nr_irqs: number of irqs of the DFL fpga device to be enumerated.
|
||||
* @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of
|
||||
* this device.
|
||||
*
|
||||
* One FPGA device may have several interrupts. This function adds irq
|
||||
* information of the DFL fpga device to enum info for next step enumeration.
|
||||
* This function should be called before dfl_fpga_feature_devs_enumerate().
|
||||
* As we only support one irq domain for all DFLs in the same enum info, adding
|
||||
* irq table a second time for the same enum info will return error.
|
||||
*
|
||||
* If we need to enumerate DFLs which belong to different irq domains, we
|
||||
* should fill more enum info and enumerate them one by one.
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise.
|
||||
*/
|
||||
int dfl_fpga_enum_info_add_irq(struct dfl_fpga_enum_info *info,
|
||||
unsigned int nr_irqs, int *irq_table)
|
||||
{
|
||||
if (!nr_irqs || !irq_table)
|
||||
return -EINVAL;
|
||||
|
||||
if (info->irq_table)
|
||||
return -EEXIST;
|
||||
|
||||
info->irq_table = devm_kmemdup(info->dev, irq_table,
|
||||
sizeof(int) * nr_irqs, GFP_KERNEL);
|
||||
if (!info->irq_table)
|
||||
return -ENOMEM;
|
||||
|
||||
info->nr_irqs = nr_irqs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_irq);
|
||||
|
||||
static int remove_feature_dev(struct device *dev, void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
@ -959,6 +1110,10 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
|
||||
binfo->dev = info->dev;
|
||||
binfo->cdev = cdev;
|
||||
|
||||
binfo->nr_irqs = info->nr_irqs;
|
||||
if (info->nr_irqs)
|
||||
binfo->irq_table = info->irq_table;
|
||||
|
||||
/*
|
||||
* start enumeration for all feature devices based on Device Feature
|
||||
* Lists.
|
||||
@ -1241,6 +1396,160 @@ done:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf);
|
||||
|
||||
static irqreturn_t dfl_irq_handler(int irq, void *arg)
|
||||
{
|
||||
struct eventfd_ctx *trigger = arg;
|
||||
|
||||
eventfd_signal(trigger, 1);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int do_set_irq_trigger(struct dfl_feature *feature, unsigned int idx,
|
||||
int fd)
|
||||
{
|
||||
struct platform_device *pdev = feature->dev;
|
||||
struct eventfd_ctx *trigger;
|
||||
int irq, ret;
|
||||
|
||||
irq = feature->irq_ctx[idx].irq;
|
||||
|
||||
if (feature->irq_ctx[idx].trigger) {
|
||||
free_irq(irq, feature->irq_ctx[idx].trigger);
|
||||
kfree(feature->irq_ctx[idx].name);
|
||||
eventfd_ctx_put(feature->irq_ctx[idx].trigger);
|
||||
feature->irq_ctx[idx].trigger = NULL;
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
feature->irq_ctx[idx].name =
|
||||
kasprintf(GFP_KERNEL, "fpga-irq[%u](%s-%llx)", idx,
|
||||
dev_name(&pdev->dev), feature->id);
|
||||
if (!feature->irq_ctx[idx].name)
|
||||
return -ENOMEM;
|
||||
|
||||
trigger = eventfd_ctx_fdget(fd);
|
||||
if (IS_ERR(trigger)) {
|
||||
ret = PTR_ERR(trigger);
|
||||
goto free_name;
|
||||
}
|
||||
|
||||
ret = request_irq(irq, dfl_irq_handler, 0,
|
||||
feature->irq_ctx[idx].name, trigger);
|
||||
if (!ret) {
|
||||
feature->irq_ctx[idx].trigger = trigger;
|
||||
return ret;
|
||||
}
|
||||
|
||||
eventfd_ctx_put(trigger);
|
||||
free_name:
|
||||
kfree(feature->irq_ctx[idx].name);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dfl_fpga_set_irq_triggers - set eventfd triggers for dfl feature interrupts
|
||||
*
|
||||
* @feature: dfl sub feature.
|
||||
* @start: start of irq index in this dfl sub feature.
|
||||
* @count: number of irqs.
|
||||
* @fds: eventfds to bind with irqs. unbind related irq if fds[n] is negative.
|
||||
* unbind "count" specified number of irqs if fds ptr is NULL.
|
||||
*
|
||||
* Bind given eventfds with irqs in this dfl sub feature. Unbind related irq if
|
||||
* fds[n] is negative. Unbind "count" specified number of irqs if fds ptr is
|
||||
* NULL.
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise.
|
||||
*/
|
||||
int dfl_fpga_set_irq_triggers(struct dfl_feature *feature, unsigned int start,
|
||||
unsigned int count, int32_t *fds)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret = 0;
|
||||
|
||||
/* overflow */
|
||||
if (unlikely(start + count < start))
|
||||
return -EINVAL;
|
||||
|
||||
/* exceeds nr_irqs */
|
||||
if (start + count > feature->nr_irqs)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
int fd = fds ? fds[i] : -1;
|
||||
|
||||
ret = do_set_irq_trigger(feature, start + i, fd);
|
||||
if (ret) {
|
||||
while (i--)
|
||||
do_set_irq_trigger(feature, start + i, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfl_fpga_set_irq_triggers);
|
||||
|
||||
/**
|
||||
* dfl_feature_ioctl_get_num_irqs - dfl feature _GET_IRQ_NUM ioctl interface.
|
||||
* @pdev: the feature device which has the sub feature
|
||||
* @feature: the dfl sub feature
|
||||
* @arg: ioctl argument
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise.
|
||||
*/
|
||||
long dfl_feature_ioctl_get_num_irqs(struct platform_device *pdev,
|
||||
struct dfl_feature *feature,
|
||||
unsigned long arg)
|
||||
{
|
||||
return put_user(feature->nr_irqs, (__u32 __user *)arg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfl_feature_ioctl_get_num_irqs);
|
||||
|
||||
/**
|
||||
* dfl_feature_ioctl_set_irq - dfl feature _SET_IRQ ioctl interface.
|
||||
* @pdev: the feature device which has the sub feature
|
||||
* @feature: the dfl sub feature
|
||||
* @arg: ioctl argument
|
||||
*
|
||||
* Return: 0 on success, negative error code otherwise.
|
||||
*/
|
||||
long dfl_feature_ioctl_set_irq(struct platform_device *pdev,
|
||||
struct dfl_feature *feature,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct dfl_fpga_irq_set hdr;
|
||||
s32 *fds;
|
||||
long ret;
|
||||
|
||||
if (!feature->nr_irqs)
|
||||
return -ENOENT;
|
||||
|
||||
if (copy_from_user(&hdr, (void __user *)arg, sizeof(hdr)))
|
||||
return -EFAULT;
|
||||
|
||||
if (!hdr.count || (hdr.start + hdr.count > feature->nr_irqs) ||
|
||||
(hdr.start + hdr.count < hdr.start))
|
||||
return -EINVAL;
|
||||
|
||||
fds = memdup_user((void __user *)(arg + sizeof(hdr)),
|
||||
hdr.count * sizeof(s32));
|
||||
if (IS_ERR(fds))
|
||||
return PTR_ERR(fds);
|
||||
|
||||
mutex_lock(&pdata->lock);
|
||||
ret = dfl_fpga_set_irq_triggers(feature, hdr.start, hdr.count, fds);
|
||||
mutex_unlock(&pdata->lock);
|
||||
|
||||
kfree(fds);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dfl_feature_ioctl_set_irq);
|
||||
|
||||
static void __exit dfl_fpga_exit(void)
|
||||
{
|
||||
dfl_chardev_uinit();
|
||||
|
@ -17,7 +17,9 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/eventfd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/io-64-nonatomic-lo-hi.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -112,6 +114,13 @@
|
||||
#define FME_PORT_OFST_ACC_VF 1
|
||||
#define FME_PORT_OFST_IMP BIT_ULL(60)
|
||||
|
||||
/* FME Error Capability Register */
|
||||
#define FME_ERROR_CAP 0x70
|
||||
|
||||
/* FME Error Capability Register Bitfield */
|
||||
#define FME_ERROR_CAP_SUPP_INT BIT_ULL(0) /* Interrupt Support */
|
||||
#define FME_ERROR_CAP_INT_VECT GENMASK_ULL(12, 1) /* Interrupt vector */
|
||||
|
||||
/* PORT Header Register Set */
|
||||
#define PORT_HDR_DFH DFH
|
||||
#define PORT_HDR_GUID_L GUID_L
|
||||
@ -145,6 +154,20 @@
|
||||
#define PORT_STS_PWR_STATE_AP2 2 /* 90% throttling */
|
||||
#define PORT_STS_PWR_STATE_AP6 6 /* 100% throttling */
|
||||
|
||||
/* Port Error Capability Register */
|
||||
#define PORT_ERROR_CAP 0x38
|
||||
|
||||
/* Port Error Capability Register Bitfield */
|
||||
#define PORT_ERROR_CAP_SUPP_INT BIT_ULL(0) /* Interrupt Support */
|
||||
#define PORT_ERROR_CAP_INT_VECT GENMASK_ULL(12, 1) /* Interrupt vector */
|
||||
|
||||
/* Port Uint Capability Register */
|
||||
#define PORT_UINT_CAP 0x8
|
||||
|
||||
/* Port Uint Capability Register Bitfield */
|
||||
#define PORT_UINT_CAP_INT_NUM GENMASK_ULL(11, 0) /* Interrupts num */
|
||||
#define PORT_UINT_CAP_FST_VECT GENMASK_ULL(23, 12) /* First Vector */
|
||||
|
||||
/**
|
||||
* struct dfl_fpga_port_ops - port ops
|
||||
*
|
||||
@ -188,21 +211,40 @@ struct dfl_feature_driver {
|
||||
const struct dfl_feature_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dfl_feature_irq_ctx - dfl private feature interrupt context
|
||||
*
|
||||
* @irq: Linux IRQ number of this interrupt.
|
||||
* @trigger: eventfd context to signal when interrupt happens.
|
||||
* @name: irq name needed when requesting irq.
|
||||
*/
|
||||
struct dfl_feature_irq_ctx {
|
||||
int irq;
|
||||
struct eventfd_ctx *trigger;
|
||||
char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dfl_feature - sub feature of the feature devices
|
||||
*
|
||||
* @dev: ptr to pdev of the feature device which has the sub feature.
|
||||
* @id: sub feature id.
|
||||
* @resource_index: each sub feature has one mmio resource for its registers.
|
||||
* this index is used to find its mmio resource from the
|
||||
* feature dev (platform device)'s reources.
|
||||
* @ioaddr: mapped mmio resource address.
|
||||
* @irq_ctx: interrupt context list.
|
||||
* @nr_irqs: number of interrupt contexts.
|
||||
* @ops: ops of this sub feature.
|
||||
* @priv: priv data of this feature.
|
||||
*/
|
||||
struct dfl_feature {
|
||||
struct platform_device *dev;
|
||||
u64 id;
|
||||
int resource_index;
|
||||
void __iomem *ioaddr;
|
||||
struct dfl_feature_irq_ctx *irq_ctx;
|
||||
unsigned int nr_irqs;
|
||||
const struct dfl_feature_ops *ops;
|
||||
void *priv;
|
||||
};
|
||||
@ -299,12 +341,6 @@ struct dfl_feature_ops {
|
||||
#define DFL_FPGA_FEATURE_DEV_FME "dfl-fme"
|
||||
#define DFL_FPGA_FEATURE_DEV_PORT "dfl-port"
|
||||
|
||||
static inline int dfl_feature_platform_data_size(const int num)
|
||||
{
|
||||
return sizeof(struct dfl_feature_platform_data) +
|
||||
num * sizeof(struct dfl_feature);
|
||||
}
|
||||
|
||||
void dfl_fpga_dev_feature_uinit(struct platform_device *pdev);
|
||||
int dfl_fpga_dev_feature_init(struct platform_device *pdev,
|
||||
struct dfl_feature_driver *feature_drvs);
|
||||
@ -390,10 +426,14 @@ static inline u8 dfl_feature_revision(void __iomem *base)
|
||||
*
|
||||
* @dev: parent device.
|
||||
* @dfls: list of device feature lists.
|
||||
* @nr_irqs: number of irqs for all feature devices.
|
||||
* @irq_table: Linux IRQ numbers for all irqs, indexed by hw irq numbers.
|
||||
*/
|
||||
struct dfl_fpga_enum_info {
|
||||
struct device *dev;
|
||||
struct list_head dfls;
|
||||
unsigned int nr_irqs;
|
||||
int *irq_table;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -417,6 +457,8 @@ struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct device *dev);
|
||||
int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
|
||||
resource_size_t start, resource_size_t len,
|
||||
void __iomem *ioaddr);
|
||||
int dfl_fpga_enum_info_add_irq(struct dfl_fpga_enum_info *info,
|
||||
unsigned int nr_irqs, int *irq_table);
|
||||
void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info);
|
||||
|
||||
/**
|
||||
@ -468,4 +510,13 @@ int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id);
|
||||
int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id);
|
||||
void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev);
|
||||
int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vf);
|
||||
int dfl_fpga_set_irq_triggers(struct dfl_feature *feature, unsigned int start,
|
||||
unsigned int count, int32_t *fds);
|
||||
long dfl_feature_ioctl_get_num_irqs(struct platform_device *pdev,
|
||||
struct dfl_feature *feature,
|
||||
unsigned long arg);
|
||||
long dfl_feature_ioctl_set_irq(struct platform_device *pdev,
|
||||
struct dfl_feature *feature,
|
||||
unsigned long arg);
|
||||
|
||||
#endif /* __FPGA_DFL_H */
|
||||
|
@ -328,7 +328,7 @@ struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name,
|
||||
void *priv)
|
||||
{
|
||||
struct fpga_bridge *bridge;
|
||||
int id, ret = 0;
|
||||
int id, ret;
|
||||
|
||||
if (!name || !strlen(name)) {
|
||||
dev_err(dev, "Attempt to register with no name!\n");
|
||||
@ -340,10 +340,8 @@ struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name,
|
||||
return NULL;
|
||||
|
||||
id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
ret = id;
|
||||
if (id < 0)
|
||||
goto error_kfree;
|
||||
}
|
||||
|
||||
mutex_init(&bridge->mutex);
|
||||
INIT_LIST_HEAD(&bridge->node);
|
||||
|
@ -581,10 +581,8 @@ struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
|
||||
return NULL;
|
||||
|
||||
id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL);
|
||||
if (id < 0) {
|
||||
ret = id;
|
||||
if (id < 0)
|
||||
goto error_kfree;
|
||||
}
|
||||
|
||||
mutex_init(&mgr->ref_mutex);
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Xilinx Spartan6 Slave Serial SPI Driver
|
||||
* Xilinx Spartan6 and 7 Series Slave Serial SPI Driver
|
||||
*
|
||||
* Copyright (C) 2017 DENX Software Engineering
|
||||
*
|
||||
@ -23,6 +23,7 @@
|
||||
struct xilinx_spi_conf {
|
||||
struct spi_device *spi;
|
||||
struct gpio_desc *prog_b;
|
||||
struct gpio_desc *init_b;
|
||||
struct gpio_desc *done;
|
||||
};
|
||||
|
||||
@ -36,13 +37,45 @@ static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
|
||||
return FPGA_MGR_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
|
||||
* a given delay if the pin is unavailable
|
||||
*
|
||||
* @mgr: The FPGA manager object
|
||||
* @value: Value INIT_B to wait for (1 = asserted = low)
|
||||
* @alt_udelay: Delay to wait if the INIT_B GPIO is not available
|
||||
*
|
||||
* Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
|
||||
* too much time passed waiting for that. If no INIT_B GPIO is available
|
||||
* then always return 0.
|
||||
*/
|
||||
static int wait_for_init_b(struct fpga_manager *mgr, int value,
|
||||
unsigned long alt_udelay)
|
||||
{
|
||||
struct xilinx_spi_conf *conf = mgr->priv;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
|
||||
|
||||
if (conf->init_b) {
|
||||
while (time_before(jiffies, timeout)) {
|
||||
/* dump_state(conf, "wait for init_d .."); */
|
||||
if (gpiod_get_value(conf->init_b) == value)
|
||||
return 0;
|
||||
usleep_range(100, 400);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
udelay(alt_udelay);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xilinx_spi_write_init(struct fpga_manager *mgr,
|
||||
struct fpga_image_info *info,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct xilinx_spi_conf *conf = mgr->priv;
|
||||
const size_t prog_latency_7500us = 7500;
|
||||
const size_t prog_pulse_1us = 1;
|
||||
int err;
|
||||
|
||||
if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
|
||||
dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
|
||||
@ -51,17 +84,28 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr,
|
||||
|
||||
gpiod_set_value(conf->prog_b, 1);
|
||||
|
||||
udelay(prog_pulse_1us); /* min is 500 ns */
|
||||
err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
|
||||
if (err) {
|
||||
dev_err(&mgr->dev, "INIT_B pin did not go low\n");
|
||||
gpiod_set_value(conf->prog_b, 0);
|
||||
return err;
|
||||
}
|
||||
|
||||
gpiod_set_value(conf->prog_b, 0);
|
||||
|
||||
err = wait_for_init_b(mgr, 0, 0);
|
||||
if (err) {
|
||||
dev_err(&mgr->dev, "INIT_B pin did not go high\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (gpiod_get_value(conf->done)) {
|
||||
dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* program latency */
|
||||
usleep_range(prog_latency_7500us, prog_latency_7500us + 100);
|
||||
usleep_range(7500, 7600);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -156,6 +200,13 @@ static int xilinx_spi_probe(struct spi_device *spi)
|
||||
return PTR_ERR(conf->prog_b);
|
||||
}
|
||||
|
||||
conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
|
||||
if (IS_ERR(conf->init_b)) {
|
||||
dev_err(&spi->dev, "Failed to get INIT_B gpio: %ld\n",
|
||||
PTR_ERR(conf->init_b));
|
||||
return PTR_ERR(conf->init_b);
|
||||
}
|
||||
|
||||
conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
|
||||
if (IS_ERR(conf->done)) {
|
||||
dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n",
|
||||
|
@ -759,7 +759,7 @@ static int check_urb_status(struct urb *urb)
|
||||
case -EOVERFLOW:
|
||||
dev_err(dev, "%s: overflow actual length is %d\n",
|
||||
__func__, urb->actual_length);
|
||||
/* fall through */
|
||||
fallthrough;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
|
@ -1233,7 +1233,7 @@ int gb_interface_add(struct gb_interface *intf)
|
||||
case GB_INTERFACE_TYPE_GREYBUS:
|
||||
dev_info(&intf->dev, "GMP VID=0x%08x, PID=0x%08x\n",
|
||||
intf->vendor_id, intf->product_id);
|
||||
/* fall-through */
|
||||
fallthrough;
|
||||
case GB_INTERFACE_TYPE_UNIPRO:
|
||||
dev_info(&intf->dev, "DDBL1 Manufacturer=0x%08x, Product=0x%08x\n",
|
||||
intf->ddbl1_manufacturer_id,
|
||||
|
@ -568,10 +568,7 @@ out:
|
||||
}
|
||||
|
||||
static struct amba_id catu_ids[] = {
|
||||
{
|
||||
.id = 0x000bb9ee,
|
||||
.mask = 0x000fffff,
|
||||
},
|
||||
CS_AMBA_ID(0x000bb9ee),
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -226,9 +226,6 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||
sink = coresight_get_enabled_sink(true);
|
||||
}
|
||||
|
||||
if (!sink)
|
||||
goto err;
|
||||
|
||||
mask = &event_data->mask;
|
||||
|
||||
/*
|
||||
@ -253,6 +250,16 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* No sink provided - look for a default sink for one of the
|
||||
* devices. At present we only support topology where all CPUs
|
||||
* use the same sink [N:1], so only need to find one sink. The
|
||||
* coresight_build_path later will remove any CPU that does not
|
||||
* attach to the sink, or if we have not found a sink.
|
||||
*/
|
||||
if (!sink)
|
||||
sink = coresight_find_default_sink(csdev);
|
||||
|
||||
/*
|
||||
* Building a path doesn't enable it, it simply builds a
|
||||
* list of devices from source to sink that can be
|
||||
@ -267,6 +274,10 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
|
||||
*etm_event_cpu_path_ptr(event_data, cpu) = path;
|
||||
}
|
||||
|
||||
/* no sink found for any CPU - cannot trace */
|
||||
if (!sink)
|
||||
goto err;
|
||||
|
||||
/* If we don't have any CPUs ready for tracing, abort */
|
||||
cpu = cpumask_first(mask);
|
||||
if (cpu >= nr_cpu_ids)
|
||||
|
@ -196,12 +196,14 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
|
||||
writel_relaxed(config->vmid_mask0, drvdata->base + TRCVMIDCCTLR0);
|
||||
writel_relaxed(config->vmid_mask1, drvdata->base + TRCVMIDCCTLR1);
|
||||
|
||||
/*
|
||||
* Request to keep the trace unit powered and also
|
||||
* emulation of powerdown
|
||||
*/
|
||||
writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) | TRCPDCR_PU,
|
||||
drvdata->base + TRCPDCR);
|
||||
if (!drvdata->skip_power_up) {
|
||||
/*
|
||||
* Request to keep the trace unit powered and also
|
||||
* emulation of powerdown
|
||||
*/
|
||||
writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) |
|
||||
TRCPDCR_PU, drvdata->base + TRCPDCR);
|
||||
}
|
||||
|
||||
/* Enable the trace unit */
|
||||
writel_relaxed(1, drvdata->base + TRCPRGCTLR);
|
||||
@ -476,10 +478,12 @@ static void etm4_disable_hw(void *info)
|
||||
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
/* power can be removed from the trace unit now */
|
||||
control = readl_relaxed(drvdata->base + TRCPDCR);
|
||||
control &= ~TRCPDCR_PU;
|
||||
writel_relaxed(control, drvdata->base + TRCPDCR);
|
||||
if (!drvdata->skip_power_up) {
|
||||
/* power can be removed from the trace unit now */
|
||||
control = readl_relaxed(drvdata->base + TRCPDCR);
|
||||
control &= ~TRCPDCR_PU;
|
||||
writel_relaxed(control, drvdata->base + TRCPDCR);
|
||||
}
|
||||
|
||||
control = readl_relaxed(drvdata->base + TRCPRGCTLR);
|
||||
|
||||
@ -507,6 +511,12 @@ static void etm4_disable_hw(void *info)
|
||||
readl_relaxed(drvdata->base + TRCSSCSRn(i));
|
||||
}
|
||||
|
||||
/* read back the current counter values */
|
||||
for (i = 0; i < drvdata->nr_cntr; i++) {
|
||||
config->cntr_val[i] =
|
||||
readl_relaxed(drvdata->base + TRCCNTVRn(i));
|
||||
}
|
||||
|
||||
coresight_disclaim_device_unlocked(drvdata->base);
|
||||
|
||||
CS_LOCK(drvdata->base);
|
||||
@ -1196,8 +1206,8 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
|
||||
}
|
||||
|
||||
for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
|
||||
state->trcacvr[i] = readl(drvdata->base + TRCACVRn(i));
|
||||
state->trcacatr[i] = readl(drvdata->base + TRCACATRn(i));
|
||||
state->trcacvr[i] = readq(drvdata->base + TRCACVRn(i));
|
||||
state->trcacatr[i] = readq(drvdata->base + TRCACATRn(i));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1208,10 +1218,10 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
|
||||
*/
|
||||
|
||||
for (i = 0; i < drvdata->numcidc; i++)
|
||||
state->trccidcvr[i] = readl(drvdata->base + TRCCIDCVRn(i));
|
||||
state->trccidcvr[i] = readq(drvdata->base + TRCCIDCVRn(i));
|
||||
|
||||
for (i = 0; i < drvdata->numvmidc; i++)
|
||||
state->trcvmidcvr[i] = readl(drvdata->base + TRCVMIDCVRn(i));
|
||||
state->trcvmidcvr[i] = readq(drvdata->base + TRCVMIDCVRn(i));
|
||||
|
||||
state->trccidcctlr0 = readl(drvdata->base + TRCCIDCCTLR0);
|
||||
state->trccidcctlr1 = readl(drvdata->base + TRCCIDCCTLR1);
|
||||
@ -1309,18 +1319,18 @@ static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
|
||||
}
|
||||
|
||||
for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
|
||||
writel_relaxed(state->trcacvr[i],
|
||||
writeq_relaxed(state->trcacvr[i],
|
||||
drvdata->base + TRCACVRn(i));
|
||||
writel_relaxed(state->trcacatr[i],
|
||||
writeq_relaxed(state->trcacatr[i],
|
||||
drvdata->base + TRCACATRn(i));
|
||||
}
|
||||
|
||||
for (i = 0; i < drvdata->numcidc; i++)
|
||||
writel_relaxed(state->trccidcvr[i],
|
||||
writeq_relaxed(state->trccidcvr[i],
|
||||
drvdata->base + TRCCIDCVRn(i));
|
||||
|
||||
for (i = 0; i < drvdata->numvmidc; i++)
|
||||
writel_relaxed(state->trcvmidcvr[i],
|
||||
writeq_relaxed(state->trcvmidcvr[i],
|
||||
drvdata->base + TRCVMIDCVRn(i));
|
||||
|
||||
writel_relaxed(state->trccidcctlr0, drvdata->base + TRCCIDCCTLR0);
|
||||
@ -1468,6 +1478,9 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
|
||||
drvdata->skip_power_up = true;
|
||||
|
||||
/* Validity for the resource is already checked by the AMBA core */
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
|
@ -133,7 +133,7 @@
|
||||
#define ETMv4_MAX_CTXID_CMP 8
|
||||
#define ETM_MAX_VMID_CMP 8
|
||||
#define ETM_MAX_PE_CMP 8
|
||||
#define ETM_MAX_RES_SEL 16
|
||||
#define ETM_MAX_RES_SEL 32
|
||||
#define ETM_MAX_SS_CMP 8
|
||||
|
||||
#define ETM_ARCH_V4 0x40
|
||||
@ -325,7 +325,7 @@ struct etmv4_save_state {
|
||||
u32 trccntctlr[ETMv4_MAX_CNTR];
|
||||
u32 trccntvr[ETMv4_MAX_CNTR];
|
||||
|
||||
u32 trcrsctlr[ETM_MAX_RES_SEL * 2];
|
||||
u32 trcrsctlr[ETM_MAX_RES_SEL];
|
||||
|
||||
u32 trcssccr[ETM_MAX_SS_CMP];
|
||||
u32 trcsscsr[ETM_MAX_SS_CMP];
|
||||
@ -334,7 +334,7 @@ struct etmv4_save_state {
|
||||
u64 trcacvr[ETM_MAX_SINGLE_ADDR_CMP];
|
||||
u64 trcacatr[ETM_MAX_SINGLE_ADDR_CMP];
|
||||
u64 trccidcvr[ETMv4_MAX_CTXID_CMP];
|
||||
u32 trcvmidcvr[ETM_MAX_VMID_CMP];
|
||||
u64 trcvmidcvr[ETM_MAX_VMID_CMP];
|
||||
u32 trccidcctlr0;
|
||||
u32 trccidcctlr1;
|
||||
u32 trcvmidcctlr0;
|
||||
@ -407,6 +407,8 @@ struct etmv4_save_state {
|
||||
* @config: structure holding configuration parameters.
|
||||
* @save_state: State to be preserved across power loss
|
||||
* @state_needs_restore: True when there is context to restore after PM exit
|
||||
* @skip_power_up: Indicates if an implementation can skip powering up
|
||||
* the trace unit.
|
||||
*/
|
||||
struct etmv4_drvdata {
|
||||
void __iomem *base;
|
||||
@ -454,6 +456,7 @@ struct etmv4_drvdata {
|
||||
struct etmv4_config config;
|
||||
struct etmv4_save_state *save_state;
|
||||
bool state_needs_restore;
|
||||
bool skip_power_up;
|
||||
};
|
||||
|
||||
/* Address comparator access types */
|
||||
|
@ -27,9 +27,8 @@ static int coresight_alloc_conns(struct device *dev,
|
||||
struct coresight_platform_data *pdata)
|
||||
{
|
||||
if (pdata->nr_outport) {
|
||||
pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
|
||||
sizeof(*pdata->conns),
|
||||
GFP_KERNEL);
|
||||
pdata->conns = devm_kcalloc(dev, pdata->nr_outport,
|
||||
sizeof(*pdata->conns), GFP_KERNEL);
|
||||
if (!pdata->conns)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -150,6 +150,8 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data);
|
||||
struct coresight_device *coresight_get_sink(struct list_head *path);
|
||||
struct coresight_device *coresight_get_enabled_sink(bool reset);
|
||||
struct coresight_device *coresight_get_sink_by_id(u32 id);
|
||||
struct coresight_device *
|
||||
coresight_find_default_sink(struct coresight_device *csdev);
|
||||
struct list_head *coresight_build_path(struct coresight_device *csdev,
|
||||
struct coresight_device *sink);
|
||||
void coresight_release_path(struct list_head *path);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/coresight.h>
|
||||
@ -32,12 +33,14 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
|
||||
* @atclk: optional clock for the core parts of the replicator.
|
||||
* @csdev: component vitals needed by the framework
|
||||
* @spinlock: serialize enable/disable operations.
|
||||
* @check_idfilter_val: check if the context is lost upon clock removal.
|
||||
*/
|
||||
struct replicator_drvdata {
|
||||
void __iomem *base;
|
||||
struct clk *atclk;
|
||||
struct coresight_device *csdev;
|
||||
spinlock_t spinlock;
|
||||
bool check_idfilter_val;
|
||||
};
|
||||
|
||||
static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
|
||||
@ -66,29 +69,43 @@ static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
|
||||
int inport, int outport)
|
||||
{
|
||||
int rc = 0;
|
||||
u32 reg;
|
||||
|
||||
switch (outport) {
|
||||
case 0:
|
||||
reg = REPLICATOR_IDFILTER0;
|
||||
break;
|
||||
case 1:
|
||||
reg = REPLICATOR_IDFILTER1;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
u32 id0val, id1val;
|
||||
|
||||
CS_UNLOCK(drvdata->base);
|
||||
|
||||
if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
|
||||
(readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
|
||||
id0val = readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0);
|
||||
id1val = readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1);
|
||||
|
||||
/*
|
||||
* Some replicator designs lose context when AMBA clocks are removed,
|
||||
* so have a check for this.
|
||||
*/
|
||||
if (drvdata->check_idfilter_val && id0val == 0x0 && id1val == 0x0)
|
||||
id0val = id1val = 0xff;
|
||||
|
||||
if (id0val == 0xff && id1val == 0xff)
|
||||
rc = coresight_claim_device_unlocked(drvdata->base);
|
||||
|
||||
if (!rc) {
|
||||
switch (outport) {
|
||||
case 0:
|
||||
id0val = 0x0;
|
||||
break;
|
||||
case 1:
|
||||
id1val = 0x0;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure that the outport is enabled. */
|
||||
if (!rc)
|
||||
writel_relaxed(0x00, drvdata->base + reg);
|
||||
if (!rc) {
|
||||
writel_relaxed(id0val, drvdata->base + REPLICATOR_IDFILTER0);
|
||||
writel_relaxed(id1val, drvdata->base + REPLICATOR_IDFILTER1);
|
||||
}
|
||||
|
||||
CS_LOCK(drvdata->base);
|
||||
|
||||
return rc;
|
||||
@ -239,6 +256,10 @@ static int replicator_probe(struct device *dev, struct resource *res)
|
||||
desc.groups = replicator_groups;
|
||||
}
|
||||
|
||||
if (fwnode_property_present(dev_fwnode(dev),
|
||||
"qcom,replicator-loses-context"))
|
||||
drvdata->check_idfilter_val = true;
|
||||
|
||||
dev_set_drvdata(dev, drvdata);
|
||||
|
||||
pdata = coresight_get_platform_data(dev);
|
||||
@ -348,16 +369,9 @@ static int dynamic_replicator_probe(struct amba_device *adev,
|
||||
}
|
||||
|
||||
static const struct amba_id dynamic_replicator_ids[] = {
|
||||
{
|
||||
.id = 0x000bb909,
|
||||
.mask = 0x000fffff,
|
||||
},
|
||||
{
|
||||
/* Coresight SoC-600 */
|
||||
.id = 0x000bb9ec,
|
||||
.mask = 0x000fffff,
|
||||
},
|
||||
{ 0, 0 },
|
||||
CS_AMBA_ID(0x000bb909),
|
||||
CS_AMBA_ID(0x000bb9ec), /* Coresight SoC-600 */
|
||||
{},
|
||||
};
|
||||
|
||||
static struct amba_driver dynamic_replicator_driver = {
|
||||
|
@ -727,8 +727,6 @@ static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res)
|
||||
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
|
||||
if (!adev)
|
||||
return -ENODEV;
|
||||
rc = acpi_dev_get_resources(adev, &res_list, NULL, NULL);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
@ -639,15 +639,14 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
/* There is no point in reading a TMC in HW FIFO mode */
|
||||
mode = readl_relaxed(drvdata->base + TMC_MODE);
|
||||
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Re-enable the TMC if need be */
|
||||
if (drvdata->mode == CS_MODE_SYSFS) {
|
||||
/* There is no point in reading a TMC in HW FIFO mode */
|
||||
mode = readl_relaxed(drvdata->base + TMC_MODE);
|
||||
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
/*
|
||||
* The trace run will continue with the same allocated trace
|
||||
* buffer. As such zero-out the buffer so that we don't end
|
||||
|
@ -1110,7 +1110,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
|
||||
|
||||
}
|
||||
|
||||
static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
|
||||
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
|
||||
{
|
||||
__tmc_etr_disable_hw(drvdata);
|
||||
/* Disable CATU device if this ETR is connected to one */
|
||||
|
@ -484,7 +484,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
break;
|
||||
case TMC_CONFIG_TYPE_ETR:
|
||||
desc.type = CORESIGHT_DEV_TYPE_SINK;
|
||||
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
|
||||
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
|
||||
desc.ops = &tmc_etr_cs_ops;
|
||||
ret = tmc_etr_setup_caps(dev, devid,
|
||||
coresight_get_uci_data(id));
|
||||
@ -496,6 +496,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
break;
|
||||
case TMC_CONFIG_TYPE_ETF:
|
||||
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
|
||||
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
|
||||
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
|
||||
desc.ops = &tmc_etf_cs_ops;
|
||||
dev_list = &etf_devs;
|
||||
@ -538,6 +539,28 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tmc_shutdown(struct amba_device *adev)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct tmc_drvdata *drvdata = amba_get_drvdata(adev);
|
||||
|
||||
spin_lock_irqsave(&drvdata->spinlock, flags);
|
||||
|
||||
if (drvdata->mode == CS_MODE_DISABLED)
|
||||
goto out;
|
||||
|
||||
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
|
||||
tmc_etr_disable_hw(drvdata);
|
||||
|
||||
/*
|
||||
* We do not care about coresight unregister here unlike remove
|
||||
* callback which is required for making coresight modular since
|
||||
* the system is going down after this.
|
||||
*/
|
||||
out:
|
||||
spin_unlock_irqrestore(&drvdata->spinlock, flags);
|
||||
}
|
||||
|
||||
static const struct amba_id tmc_ids[] = {
|
||||
CS_AMBA_ID(0x000bb961),
|
||||
/* Coresight SoC 600 TMC-ETR/ETS */
|
||||
@ -556,6 +579,7 @@ static struct amba_driver tmc_driver = {
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
.probe = tmc_probe,
|
||||
.shutdown = tmc_shutdown,
|
||||
.id_table = tmc_ids,
|
||||
};
|
||||
builtin_amba_driver(tmc_driver);
|
||||
|
@ -268,6 +268,7 @@ ssize_t tmc_etb_get_sysfs_trace(struct tmc_drvdata *drvdata,
|
||||
/* ETR functions */
|
||||
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata);
|
||||
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata);
|
||||
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata);
|
||||
extern const struct coresight_ops tmc_etr_cs_ops;
|
||||
ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
|
||||
loff_t pos, size_t len, char **bufpp);
|
||||
|
@ -769,6 +769,171 @@ void coresight_release_path(struct list_head *path)
|
||||
path = NULL;
|
||||
}
|
||||
|
||||
/* return true if the device is a suitable type for a default sink */
|
||||
static inline bool coresight_is_def_sink_type(struct coresight_device *csdev)
|
||||
{
|
||||
/* sink & correct subtype */
|
||||
if (((csdev->type == CORESIGHT_DEV_TYPE_SINK) ||
|
||||
(csdev->type == CORESIGHT_DEV_TYPE_LINKSINK)) &&
|
||||
(csdev->subtype.sink_subtype >= CORESIGHT_DEV_SUBTYPE_SINK_BUFFER))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_select_best_sink - return the best sink for use as default from
|
||||
* the two provided.
|
||||
*
|
||||
* @sink: current best sink.
|
||||
* @depth: search depth where current sink was found.
|
||||
* @new_sink: new sink for comparison with current sink.
|
||||
* @new_depth: search depth where new sink was found.
|
||||
*
|
||||
* Sinks prioritised according to coresight_dev_subtype_sink, with only
|
||||
* subtypes CORESIGHT_DEV_SUBTYPE_SINK_BUFFER or higher being used.
|
||||
*
|
||||
* Where two sinks of equal priority are found, the sink closest to the
|
||||
* source is used (smallest search depth).
|
||||
*
|
||||
* return @new_sink & update @depth if better than @sink, else return @sink.
|
||||
*/
|
||||
static struct coresight_device *
|
||||
coresight_select_best_sink(struct coresight_device *sink, int *depth,
|
||||
struct coresight_device *new_sink, int new_depth)
|
||||
{
|
||||
bool update = false;
|
||||
|
||||
if (!sink) {
|
||||
/* first found at this level */
|
||||
update = true;
|
||||
} else if (new_sink->subtype.sink_subtype >
|
||||
sink->subtype.sink_subtype) {
|
||||
/* found better sink */
|
||||
update = true;
|
||||
} else if ((new_sink->subtype.sink_subtype ==
|
||||
sink->subtype.sink_subtype) &&
|
||||
(*depth > new_depth)) {
|
||||
/* found same but closer sink */
|
||||
update = true;
|
||||
}
|
||||
|
||||
if (update)
|
||||
*depth = new_depth;
|
||||
return update ? new_sink : sink;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_find_sink - recursive function to walk trace connections from
|
||||
* source to find a suitable default sink.
|
||||
*
|
||||
* @csdev: source / current device to check.
|
||||
* @depth: [in] search depth of calling dev, [out] depth of found sink.
|
||||
*
|
||||
* This will walk the connection path from a source (ETM) till a suitable
|
||||
* sink is encountered and return that sink to the original caller.
|
||||
*
|
||||
* If current device is a plain sink return that & depth, otherwise recursively
|
||||
* call child connections looking for a sink. Select best possible using
|
||||
* coresight_select_best_sink.
|
||||
*
|
||||
* return best sink found, or NULL if not found at this node or child nodes.
|
||||
*/
|
||||
static struct coresight_device *
|
||||
coresight_find_sink(struct coresight_device *csdev, int *depth)
|
||||
{
|
||||
int i, curr_depth = *depth + 1, found_depth = 0;
|
||||
struct coresight_device *found_sink = NULL;
|
||||
|
||||
if (coresight_is_def_sink_type(csdev)) {
|
||||
found_depth = curr_depth;
|
||||
found_sink = csdev;
|
||||
if (csdev->type == CORESIGHT_DEV_TYPE_SINK)
|
||||
goto return_def_sink;
|
||||
/* look past LINKSINK for something better */
|
||||
}
|
||||
|
||||
/*
|
||||
* Not a sink we want - or possible child sink may be better.
|
||||
* recursively explore each port found on this element.
|
||||
*/
|
||||
for (i = 0; i < csdev->pdata->nr_outport; i++) {
|
||||
struct coresight_device *child_dev, *sink = NULL;
|
||||
int child_depth = curr_depth;
|
||||
|
||||
child_dev = csdev->pdata->conns[i].child_dev;
|
||||
if (child_dev)
|
||||
sink = coresight_find_sink(child_dev, &child_depth);
|
||||
|
||||
if (sink)
|
||||
found_sink = coresight_select_best_sink(found_sink,
|
||||
&found_depth,
|
||||
sink,
|
||||
child_depth);
|
||||
}
|
||||
|
||||
return_def_sink:
|
||||
/* return found sink and depth */
|
||||
if (found_sink)
|
||||
*depth = found_depth;
|
||||
return found_sink;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_find_default_sink: Find a sink suitable for use as a
|
||||
* default sink.
|
||||
*
|
||||
* @csdev: starting source to find a connected sink.
|
||||
*
|
||||
* Walks connections graph looking for a suitable sink to enable for the
|
||||
* supplied source. Uses CoreSight device subtypes and distance from source
|
||||
* to select the best sink.
|
||||
*
|
||||
* If a sink is found, then the default sink for this device is set and
|
||||
* will be automatically used in future.
|
||||
*
|
||||
* Used in cases where the CoreSight user (perf / sysfs) has not selected a
|
||||
* sink.
|
||||
*/
|
||||
struct coresight_device *
|
||||
coresight_find_default_sink(struct coresight_device *csdev)
|
||||
{
|
||||
int depth = 0;
|
||||
|
||||
/* look for a default sink if we have not found for this device */
|
||||
if (!csdev->def_sink)
|
||||
csdev->def_sink = coresight_find_sink(csdev, &depth);
|
||||
return csdev->def_sink;
|
||||
}
|
||||
|
||||
static int coresight_remove_sink_ref(struct device *dev, void *data)
|
||||
{
|
||||
struct coresight_device *sink = data;
|
||||
struct coresight_device *source = to_coresight_device(dev);
|
||||
|
||||
if (source->def_sink == sink)
|
||||
source->def_sink = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* coresight_clear_default_sink: Remove all default sink references to the
|
||||
* supplied sink.
|
||||
*
|
||||
* If supplied device is a sink, then check all the bus devices and clear
|
||||
* out all the references to this sink from the coresight_device def_sink
|
||||
* parameter.
|
||||
*
|
||||
* @csdev: coresight sink - remove references to this from all sources.
|
||||
*/
|
||||
static void coresight_clear_default_sink(struct coresight_device *csdev)
|
||||
{
|
||||
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK) ||
|
||||
(csdev->type == CORESIGHT_DEV_TYPE_LINKSINK)) {
|
||||
bus_for_each_dev(&coresight_bustype, NULL, csdev,
|
||||
coresight_remove_sink_ref);
|
||||
}
|
||||
}
|
||||
|
||||
/** coresight_validate_source - make sure a source has the right credentials
|
||||
* @csdev: the device structure for a source.
|
||||
* @function: the function this was called from.
|
||||
@ -1358,6 +1523,7 @@ void coresight_unregister(struct coresight_device *csdev)
|
||||
etm_perf_del_symlink_sink(csdev);
|
||||
/* Remove references of that device in the topology */
|
||||
coresight_remove_conns(csdev);
|
||||
coresight_clear_default_sink(csdev);
|
||||
coresight_release_platform_data(csdev, csdev->pdata);
|
||||
device_unregister(&csdev->dev);
|
||||
}
|
||||
|
@ -269,23 +269,22 @@ static int aggregate_requests(struct icc_node *node)
|
||||
static int apply_constraints(struct icc_path *path)
|
||||
{
|
||||
struct icc_node *next, *prev = NULL;
|
||||
struct icc_provider *p;
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < path->num_nodes; i++) {
|
||||
next = path->reqs[i].node;
|
||||
p = next->provider;
|
||||
|
||||
/*
|
||||
* Both endpoints should be valid master-slave pairs of the
|
||||
* same interconnect provider that will be configured.
|
||||
*/
|
||||
if (!prev || next->provider != prev->provider) {
|
||||
/* both endpoints should be valid master-slave pairs */
|
||||
if (!prev || (p != prev->provider && !p->inter_set)) {
|
||||
prev = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set the constraints */
|
||||
ret = next->provider->set(prev, next);
|
||||
ret = p->set(prev, next);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -340,12 +339,12 @@ EXPORT_SYMBOL_GPL(of_icc_xlate_onecell);
|
||||
* Returns a valid pointer to struct icc_node on success or ERR_PTR()
|
||||
* on failure.
|
||||
*/
|
||||
static struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
|
||||
struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
|
||||
{
|
||||
struct icc_node *node = ERR_PTR(-EPROBE_DEFER);
|
||||
struct icc_provider *provider;
|
||||
|
||||
if (!spec || spec->args_count != 1)
|
||||
if (!spec)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
mutex_lock(&icc_lock);
|
||||
@ -359,6 +358,7 @@ static struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
|
||||
|
||||
return node;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_icc_get_from_provider);
|
||||
|
||||
static void devm_icc_release(struct device *dev, void *res)
|
||||
{
|
||||
|
@ -83,7 +83,7 @@ config IBM_ASM
|
||||
|
||||
WARNING: This software may not be supported or function
|
||||
correctly on your IBM server. Please consult the IBM ServerProven
|
||||
website <http://www-03.ibm.com/systems/info/x86servers/serverproven/compat/us/>
|
||||
website <https://www-03.ibm.com/systems/info/x86servers/serverproven/compat/us/>
|
||||
for information on the specific driver level and support statement
|
||||
for your IBM server.
|
||||
|
||||
|
@ -923,7 +923,7 @@ struct c2port_device *c2port_device_register(char *name,
|
||||
}
|
||||
dev_set_drvdata(c2dev->dev, c2dev);
|
||||
|
||||
strncpy(c2dev->name, name, C2PORT_NAME_LEN);
|
||||
strncpy(c2dev->name, name, C2PORT_NAME_LEN - 1);
|
||||
c2dev->ops = ops;
|
||||
mutex_init(&c2dev->mutex);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_MISC_ALCOR_PCI) += alcor_pci.o
|
||||
obj-$(CONFIG_MISC_RTSX_PCI) += rtsx_pci.o
|
||||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o rts5261.o
|
||||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o rts5261.o rts5228.o
|
||||
obj-$(CONFIG_MISC_RTSX_USB) += rtsx_usb.o
|
||||
|
@ -37,10 +37,11 @@ static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
|
||||
|
||||
static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg1 = 0;
|
||||
u8 reg3 = 0;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®1);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®1);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg1);
|
||||
|
||||
if (!rtsx_vendor_setting_valid(reg1))
|
||||
@ -52,16 +53,17 @@ static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
pcr->card_drive_sel &= 0x3F;
|
||||
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg1);
|
||||
|
||||
rtsx_pci_read_config_byte(pcr, PCR_SETTING_REG3, ®3);
|
||||
pci_read_config_byte(pdev, PCR_SETTING_REG3, ®3);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG3, reg3);
|
||||
pcr->sd30_drive_sel_3v3 = rtl8411_reg_to_sd30_drive_sel_3v3(reg3);
|
||||
}
|
||||
|
||||
static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg = 0;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
if (!rtsx_vendor_setting_valid(reg))
|
||||
|
@ -23,9 +23,10 @@ static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr)
|
||||
|
||||
static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
if (rts5209_vendor_setting1_valid(reg)) {
|
||||
@ -34,7 +35,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
pcr->aspm_en = rts5209_reg_to_aspm(reg);
|
||||
}
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG2, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
|
||||
if (rts5209_vendor_setting2_valid(reg)) {
|
||||
|
@ -56,9 +56,10 @@ static void rts5227_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
|
||||
|
||||
static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
if (!rtsx_vendor_setting_valid(reg))
|
||||
@ -69,7 +70,7 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
pcr->card_drive_sel &= 0x3F;
|
||||
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG2, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
|
||||
if (rtsx_reg_check_reverse_socket(reg))
|
||||
|
747
drivers/misc/cardreader/rts5228.c
Normal file
747
drivers/misc/cardreader/rts5228.c
Normal file
@ -0,0 +1,747 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2018-2019 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Ricky WU <ricky_wu@realtek.com>
|
||||
* Rui FENG <rui_feng@realsil.com.cn>
|
||||
* Wei WANG <wei_wang@realsil.com.cn>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/rtsx_pci.h>
|
||||
|
||||
#include "rts5228.h"
|
||||
#include "rtsx_pcr.h"
|
||||
|
||||
static u8 rts5228_get_ic_version(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
|
||||
return val & IC_VERSION_MASK;
|
||||
}
|
||||
|
||||
static void rts5228_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
|
||||
{
|
||||
u8 driving_3v3[4][3] = {
|
||||
{0x13, 0x13, 0x13},
|
||||
{0x96, 0x96, 0x96},
|
||||
{0x7F, 0x7F, 0x7F},
|
||||
{0x96, 0x96, 0x96},
|
||||
};
|
||||
u8 driving_1v8[4][3] = {
|
||||
{0x99, 0x99, 0x99},
|
||||
{0xB5, 0xB5, 0xB5},
|
||||
{0xE6, 0x7E, 0xFE},
|
||||
{0x6B, 0x6B, 0x6B},
|
||||
};
|
||||
u8 (*driving)[3], drive_sel;
|
||||
|
||||
if (voltage == OUTPUT_3V3) {
|
||||
driving = driving_3v3;
|
||||
drive_sel = pcr->sd30_drive_sel_3v3;
|
||||
} else {
|
||||
driving = driving_1v8;
|
||||
drive_sel = pcr->sd30_drive_sel_1v8;
|
||||
}
|
||||
|
||||
rtsx_pci_write_register(pcr, SD30_CLK_DRIVE_SEL,
|
||||
0xFF, driving[drive_sel][0]);
|
||||
|
||||
rtsx_pci_write_register(pcr, SD30_CMD_DRIVE_SEL,
|
||||
0xFF, driving[drive_sel][1]);
|
||||
|
||||
rtsx_pci_write_register(pcr, SD30_DAT_DRIVE_SEL,
|
||||
0xFF, driving[drive_sel][2]);
|
||||
}
|
||||
|
||||
static void rtsx5228_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg;
|
||||
|
||||
/* 0x724~0x727 */
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
if (!rtsx_vendor_setting_valid(reg)) {
|
||||
pcr_dbg(pcr, "skip fetch vendor setting\n");
|
||||
return;
|
||||
}
|
||||
pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
|
||||
pcr->aspm_en = rtsx_reg_to_aspm(reg);
|
||||
|
||||
/* 0x814~0x817 */
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG2, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
|
||||
pcr->rtd3_en = rtsx_reg_to_rtd3(reg);
|
||||
if (rtsx_check_mmc_support(reg))
|
||||
pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
|
||||
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
|
||||
if (rtsx_reg_check_reverse_socket(reg))
|
||||
pcr->flags |= PCR_REVERSE_SOCKET;
|
||||
}
|
||||
|
||||
static int rts5228_optimize_phy(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40);
|
||||
}
|
||||
|
||||
static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
|
||||
{
|
||||
/* Set relink_time to 0 */
|
||||
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
|
||||
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
|
||||
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
|
||||
RELINK_TIME_MASK, 0);
|
||||
|
||||
if (pm_state == HOST_ENTER_S3)
|
||||
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
|
||||
D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
|
||||
|
||||
rtsx_pci_write_register(pcr, FPDCTL,
|
||||
SSC_POWER_DOWN, SSC_POWER_DOWN);
|
||||
}
|
||||
|
||||
static int rts5228_enable_auto_blink(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, OLT_LED_CTL,
|
||||
LED_SHINE_MASK, LED_SHINE_EN);
|
||||
}
|
||||
|
||||
static int rts5228_disable_auto_blink(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, OLT_LED_CTL,
|
||||
LED_SHINE_MASK, LED_SHINE_DISABLE);
|
||||
}
|
||||
|
||||
static int rts5228_turn_on_led(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, GPIO_CTL,
|
||||
0x02, 0x02);
|
||||
}
|
||||
|
||||
static int rts5228_turn_off_led(struct rtsx_pcr *pcr)
|
||||
{
|
||||
return rtsx_pci_write_register(pcr, GPIO_CTL,
|
||||
0x02, 0x00);
|
||||
}
|
||||
|
||||
/* SD Pull Control Enable:
|
||||
* SD_DAT[3:0] ==> pull up
|
||||
* SD_CD ==> pull up
|
||||
* SD_WP ==> pull up
|
||||
* SD_CMD ==> pull up
|
||||
* SD_CLK ==> pull down
|
||||
*/
|
||||
static const u32 rts5228_sd_pull_ctl_enable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
|
||||
0,
|
||||
};
|
||||
|
||||
/* SD Pull Control Disable:
|
||||
* SD_DAT[3:0] ==> pull down
|
||||
* SD_CD ==> pull up
|
||||
* SD_WP ==> pull down
|
||||
* SD_CMD ==> pull down
|
||||
* SD_CLK ==> pull down
|
||||
*/
|
||||
static const u32 rts5228_sd_pull_ctl_disable_tbl[] = {
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
|
||||
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
|
||||
0,
|
||||
};
|
||||
|
||||
static int rts5228_sd_set_sample_push_timing_sd30(struct rtsx_pcr *pcr)
|
||||
{
|
||||
rtsx_pci_write_register(pcr, SD_CFG1, SD_MODE_SELECT_MASK
|
||||
| SD_ASYNC_FIFO_NOT_RST, SD_30_MODE | SD_ASYNC_FIFO_NOT_RST);
|
||||
rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, CLK_LOW_FREQ);
|
||||
rtsx_pci_write_register(pcr, CARD_CLK_SOURCE, 0xFF,
|
||||
CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
|
||||
rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rts5228_card_power_on(struct rtsx_pcr *pcr, int card)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
if (option->ocp_en)
|
||||
rtsx_pci_enable_ocp(pcr);
|
||||
|
||||
rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
|
||||
CFG_SD_POW_AUTO_PD, CFG_SD_POW_AUTO_PD);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG1,
|
||||
RTS5228_LDO1_TUNE_MASK, RTS5228_LDO1_33);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1233318_POW_CTL,
|
||||
RTS5228_LDO1_POWERON_MASK, RTS5228_LDO1_SOFTSTART);
|
||||
mdelay(2);
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1233318_POW_CTL,
|
||||
RTS5228_LDO1_POWERON_MASK, RTS5228_LDO1_FULLON);
|
||||
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1233318_POW_CTL,
|
||||
RTS5228_LDO3318_POWERON, RTS5228_LDO3318_POWERON);
|
||||
|
||||
msleep(20);
|
||||
|
||||
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN);
|
||||
|
||||
/* Initialize SD_CFG1 register */
|
||||
rtsx_pci_write_register(pcr, SD_CFG1, 0xFF,
|
||||
SD_CLK_DIVIDE_128 | SD_20_MODE | SD_BUS_WIDTH_1BIT);
|
||||
|
||||
rtsx_pci_write_register(pcr, SD_SAMPLE_POINT_CTL,
|
||||
0xFF, SD20_RX_POS_EDGE);
|
||||
rtsx_pci_write_register(pcr, SD_PUSH_POINT_CTL, 0xFF, 0);
|
||||
rtsx_pci_write_register(pcr, CARD_STOP, SD_STOP | SD_CLR_ERR,
|
||||
SD_STOP | SD_CLR_ERR);
|
||||
|
||||
/* Reset SD_CFG3 register */
|
||||
rtsx_pci_write_register(pcr, SD_CFG3, SD30_CLK_END_EN, 0);
|
||||
rtsx_pci_write_register(pcr, REG_SD_STOP_SDCLK_CFG,
|
||||
SD30_CLK_STOP_CFG_EN | SD30_CLK_STOP_CFG1 |
|
||||
SD30_CLK_STOP_CFG0, 0);
|
||||
|
||||
if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50 ||
|
||||
pcr->extra_caps & EXTRA_CAPS_SD_SDR104)
|
||||
rts5228_sd_set_sample_push_timing_sd30(pcr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rts5228_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
|
||||
{
|
||||
int err;
|
||||
u16 val = 0;
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_CARD_PWR_CTL,
|
||||
RTS5228_PUPDC, RTS5228_PUPDC);
|
||||
|
||||
switch (voltage) {
|
||||
case OUTPUT_3V3:
|
||||
rtsx_pci_read_phy_register(pcr, PHY_TUNE, &val);
|
||||
val |= PHY_TUNE_SDBUS_33;
|
||||
err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_DV3318_CFG,
|
||||
RTS5228_DV3318_TUNE_MASK, RTS5228_DV3318_33);
|
||||
rtsx_pci_write_register(pcr, SD_PAD_CTL,
|
||||
SD_IO_USING_1V8, 0);
|
||||
break;
|
||||
case OUTPUT_1V8:
|
||||
rtsx_pci_read_phy_register(pcr, PHY_TUNE, &val);
|
||||
val &= ~PHY_TUNE_SDBUS_33;
|
||||
err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_DV3318_CFG,
|
||||
RTS5228_DV3318_TUNE_MASK, RTS5228_DV3318_18);
|
||||
rtsx_pci_write_register(pcr, SD_PAD_CTL,
|
||||
SD_IO_USING_1V8, SD_IO_USING_1V8);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* set pad drive */
|
||||
rts5228_fill_driving(pcr, voltage);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rts5228_stop_cmd(struct rtsx_pcr *pcr)
|
||||
{
|
||||
rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD);
|
||||
rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA);
|
||||
rtsx_pci_write_register(pcr, RTS5260_DMA_RST_CTL_0,
|
||||
RTS5260_DMA_RST | RTS5260_ADMA3_RST,
|
||||
RTS5260_DMA_RST | RTS5260_ADMA3_RST);
|
||||
rtsx_pci_write_register(pcr, RBCTL, RB_FLUSH, RB_FLUSH);
|
||||
}
|
||||
|
||||
static void rts5228_card_before_power_off(struct rtsx_pcr *pcr)
|
||||
{
|
||||
rts5228_stop_cmd(pcr);
|
||||
rts5228_switch_output_voltage(pcr, OUTPUT_3V3);
|
||||
}
|
||||
|
||||
static void rts5228_enable_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 val = 0;
|
||||
|
||||
val = SD_OCP_INT_EN | SD_DETECT_EN;
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
|
||||
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN,
|
||||
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN);
|
||||
}
|
||||
|
||||
static void rts5228_disable_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 mask = 0;
|
||||
|
||||
mask = SD_OCP_INT_EN | SD_DETECT_EN;
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
|
||||
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN, 0);
|
||||
}
|
||||
|
||||
static int rts5228_card_power_off(struct rtsx_pcr *pcr, int card)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
rts5228_card_before_power_off(pcr);
|
||||
err = rtsx_pci_write_register(pcr, RTS5228_LDO1233318_POW_CTL,
|
||||
RTS5228_LDO_POWERON_MASK, 0);
|
||||
rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0, CFG_SD_POW_AUTO_PD, 0);
|
||||
|
||||
if (pcr->option.ocp_en)
|
||||
rtsx_pci_disable_ocp(pcr);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void rts5228_init_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
if (option->ocp_en) {
|
||||
u8 mask, val;
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
|
||||
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN,
|
||||
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
|
||||
RTS5228_LDO1_OCP_THD_MASK, option->sd_800mA_ocp_thd);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
|
||||
RTS5228_LDO1_OCP_LMT_THD_MASK,
|
||||
RTS5228_LDO1_LMT_THD_1500);
|
||||
|
||||
rtsx_pci_read_register(pcr, RTS5228_LDO1_CFG0, &val);
|
||||
|
||||
mask = SD_OCP_GLITCH_MASK;
|
||||
val = pcr->hw_param.ocp_glitch;
|
||||
rtsx_pci_write_register(pcr, REG_OCPGLITCH, mask, val);
|
||||
|
||||
rts5228_enable_ocp(pcr);
|
||||
|
||||
} else {
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
|
||||
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void rts5228_clear_ocpstat(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u8 mask = 0;
|
||||
u8 val = 0;
|
||||
|
||||
mask = SD_OCP_INT_CLR | SD_OC_CLR;
|
||||
val = SD_OCP_INT_CLR | SD_OC_CLR;
|
||||
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
|
||||
|
||||
udelay(1000);
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
|
||||
|
||||
}
|
||||
|
||||
static void rts5228_process_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
if (!pcr->option.ocp_en)
|
||||
return;
|
||||
|
||||
rtsx_pci_get_ocpstat(pcr, &pcr->ocp_stat);
|
||||
|
||||
if (pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) {
|
||||
rts5228_clear_ocpstat(pcr);
|
||||
rts5228_card_power_off(pcr, RTSX_SD_CARD);
|
||||
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
|
||||
pcr->ocp_stat = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void rts5228_init_from_cfg(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
int l1ss;
|
||||
u32 lval;
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!l1ss)
|
||||
return;
|
||||
|
||||
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
|
||||
|
||||
if (0 == (lval & 0x0F))
|
||||
rtsx_pci_enable_oobs_polling(pcr);
|
||||
else
|
||||
rtsx_pci_disable_oobs_polling(pcr);
|
||||
|
||||
if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
else
|
||||
rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
|
||||
if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
else
|
||||
rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
|
||||
if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
|
||||
else
|
||||
rtsx_clear_dev_flag(pcr, PM_L1_1_EN);
|
||||
|
||||
if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
|
||||
else
|
||||
rtsx_clear_dev_flag(pcr, PM_L1_2_EN);
|
||||
|
||||
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0);
|
||||
if (option->ltr_en) {
|
||||
u16 val;
|
||||
|
||||
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
|
||||
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
|
||||
option->ltr_enabled = true;
|
||||
option->ltr_active = true;
|
||||
rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
|
||||
} else {
|
||||
option->ltr_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
|
||||
| PM_L1_1_EN | PM_L1_2_EN))
|
||||
option->force_clkreq_0 = false;
|
||||
else
|
||||
option->force_clkreq_0 = true;
|
||||
}
|
||||
|
||||
static int rts5228_extra_init_hw(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5228_AUTOLOAD_CFG1,
|
||||
CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
|
||||
|
||||
rts5228_init_from_cfg(pcr);
|
||||
|
||||
rtsx_pci_write_register(pcr, L1SUB_CONFIG1,
|
||||
AUX_CLK_ACTIVE_SEL_MASK, MAC_CKSW_DONE);
|
||||
rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, 0);
|
||||
|
||||
rtsx_pci_write_register(pcr, FUNC_FORCE_CTL,
|
||||
FUNC_FORCE_UPME_XMT_DBG, FUNC_FORCE_UPME_XMT_DBG);
|
||||
|
||||
rtsx_pci_write_register(pcr, PCLK_CTL,
|
||||
PCLK_MODE_SEL, PCLK_MODE_SEL);
|
||||
|
||||
rtsx_pci_write_register(pcr, PM_EVENT_DEBUG, PME_DEBUG_0, PME_DEBUG_0);
|
||||
rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, CLK_PM_EN, CLK_PM_EN);
|
||||
|
||||
/* LED shine disabled, set initial shine cycle period */
|
||||
rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x0F, 0x02);
|
||||
|
||||
/* Configure driving */
|
||||
rts5228_fill_driving(pcr, OUTPUT_3V3);
|
||||
|
||||
if (pcr->flags & PCR_REVERSE_SOCKET)
|
||||
rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x30);
|
||||
else
|
||||
rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
|
||||
|
||||
/*
|
||||
* If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
|
||||
* to drive low, and we forcibly request clock.
|
||||
*/
|
||||
if (option->force_clkreq_0)
|
||||
rtsx_pci_write_register(pcr, PETXCFG,
|
||||
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
|
||||
else
|
||||
rtsx_pci_write_register(pcr, PETXCFG,
|
||||
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
|
||||
|
||||
rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
|
||||
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
|
||||
rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL,
|
||||
FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rts5228_enable_aspm(struct rtsx_pcr *pcr, bool enable)
|
||||
{
|
||||
u8 mask, val;
|
||||
|
||||
if (pcr->aspm_enabled == enable)
|
||||
return;
|
||||
|
||||
mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
|
||||
val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
|
||||
val |= (pcr->aspm_en & 0x02);
|
||||
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
|
||||
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC, pcr->aspm_en);
|
||||
pcr->aspm_enabled = enable;
|
||||
}
|
||||
|
||||
static void rts5228_disable_aspm(struct rtsx_pcr *pcr, bool enable)
|
||||
{
|
||||
u8 mask, val;
|
||||
|
||||
if (pcr->aspm_enabled == enable)
|
||||
return;
|
||||
|
||||
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC, 0);
|
||||
mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
|
||||
val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
|
||||
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
|
||||
rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
|
||||
mdelay(10);
|
||||
pcr->aspm_enabled = enable;
|
||||
}
|
||||
|
||||
static void rts5228_set_aspm(struct rtsx_pcr *pcr, bool enable)
|
||||
{
|
||||
if (enable)
|
||||
rts5228_enable_aspm(pcr, true);
|
||||
else
|
||||
rts5228_disable_aspm(pcr, false);
|
||||
}
|
||||
|
||||
static void rts5228_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
int aspm_L1_1, aspm_L1_2;
|
||||
u8 val = 0;
|
||||
|
||||
aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
|
||||
if (active) {
|
||||
/* run, latency: 60us */
|
||||
if (aspm_L1_1)
|
||||
val = option->ltr_l1off_snooze_sspwrgate;
|
||||
} else {
|
||||
/* l1off, latency: 300us */
|
||||
if (aspm_L1_2)
|
||||
val = option->ltr_l1off_sspwrgate;
|
||||
}
|
||||
|
||||
rtsx_set_l1off_sub(pcr, val);
|
||||
}
|
||||
|
||||
static const struct pcr_ops rts5228_pcr_ops = {
|
||||
.fetch_vendor_settings = rtsx5228_fetch_vendor_settings,
|
||||
.turn_on_led = rts5228_turn_on_led,
|
||||
.turn_off_led = rts5228_turn_off_led,
|
||||
.extra_init_hw = rts5228_extra_init_hw,
|
||||
.enable_auto_blink = rts5228_enable_auto_blink,
|
||||
.disable_auto_blink = rts5228_disable_auto_blink,
|
||||
.card_power_on = rts5228_card_power_on,
|
||||
.card_power_off = rts5228_card_power_off,
|
||||
.switch_output_voltage = rts5228_switch_output_voltage,
|
||||
.force_power_down = rts5228_force_power_down,
|
||||
.stop_cmd = rts5228_stop_cmd,
|
||||
.set_aspm = rts5228_set_aspm,
|
||||
.set_l1off_cfg_sub_d0 = rts5228_set_l1off_cfg_sub_d0,
|
||||
.enable_ocp = rts5228_enable_ocp,
|
||||
.disable_ocp = rts5228_disable_ocp,
|
||||
.init_ocp = rts5228_init_ocp,
|
||||
.process_ocp = rts5228_process_ocp,
|
||||
.clear_ocpstat = rts5228_clear_ocpstat,
|
||||
.optimize_phy = rts5228_optimize_phy,
|
||||
};
|
||||
|
||||
|
||||
static inline u8 double_ssc_depth(u8 depth)
|
||||
{
|
||||
return ((depth > 1) ? (depth - 1) : depth);
|
||||
}
|
||||
|
||||
int rts5228_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
|
||||
{
|
||||
int err, clk;
|
||||
u16 n;
|
||||
u8 clk_divider, mcu_cnt, div;
|
||||
static const u8 depth[] = {
|
||||
[RTSX_SSC_DEPTH_4M] = RTS5228_SSC_DEPTH_4M,
|
||||
[RTSX_SSC_DEPTH_2M] = RTS5228_SSC_DEPTH_2M,
|
||||
[RTSX_SSC_DEPTH_1M] = RTS5228_SSC_DEPTH_1M,
|
||||
[RTSX_SSC_DEPTH_500K] = RTS5228_SSC_DEPTH_512K,
|
||||
};
|
||||
|
||||
if (initial_mode) {
|
||||
/* We use 250k(around) here, in initial stage */
|
||||
clk_divider = SD_CLK_DIVIDE_128;
|
||||
card_clock = 30000000;
|
||||
} else {
|
||||
clk_divider = SD_CLK_DIVIDE_0;
|
||||
}
|
||||
err = rtsx_pci_write_register(pcr, SD_CFG1,
|
||||
SD_CLK_DIVIDE_MASK, clk_divider);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
card_clock /= 1000000;
|
||||
pcr_dbg(pcr, "Switch card clock to %dMHz\n", card_clock);
|
||||
|
||||
clk = card_clock;
|
||||
if (!initial_mode && double_clk)
|
||||
clk = card_clock * 2;
|
||||
pcr_dbg(pcr, "Internal SSC clock: %dMHz (cur_clock = %d)\n",
|
||||
clk, pcr->cur_clock);
|
||||
|
||||
if (clk == pcr->cur_clock)
|
||||
return 0;
|
||||
|
||||
if (pcr->ops->conv_clk_and_div_n)
|
||||
n = pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
|
||||
else
|
||||
n = clk - 4;
|
||||
if ((clk <= 4) || (n > 396))
|
||||
return -EINVAL;
|
||||
|
||||
mcu_cnt = 125/clk + 3;
|
||||
if (mcu_cnt > 15)
|
||||
mcu_cnt = 15;
|
||||
|
||||
div = CLK_DIV_1;
|
||||
while ((n < MIN_DIV_N_PCR - 4) && (div < CLK_DIV_8)) {
|
||||
if (pcr->ops->conv_clk_and_div_n) {
|
||||
int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
|
||||
DIV_N_TO_CLK) * 2;
|
||||
n = pcr->ops->conv_clk_and_div_n(dbl_clk,
|
||||
CLK_TO_DIV_N);
|
||||
} else {
|
||||
n = (n + 4) * 2 - 4;
|
||||
}
|
||||
div++;
|
||||
}
|
||||
|
||||
n = (n / 2) - 1;
|
||||
pcr_dbg(pcr, "n = %d, div = %d\n", n, div);
|
||||
|
||||
ssc_depth = depth[ssc_depth];
|
||||
if (double_clk)
|
||||
ssc_depth = double_ssc_depth(ssc_depth);
|
||||
|
||||
if (ssc_depth) {
|
||||
if (div == CLK_DIV_2) {
|
||||
if (ssc_depth > 1)
|
||||
ssc_depth -= 1;
|
||||
else
|
||||
ssc_depth = RTS5228_SSC_DEPTH_8M;
|
||||
} else if (div == CLK_DIV_4) {
|
||||
if (ssc_depth > 2)
|
||||
ssc_depth -= 2;
|
||||
else
|
||||
ssc_depth = RTS5228_SSC_DEPTH_8M;
|
||||
} else if (div == CLK_DIV_8) {
|
||||
if (ssc_depth > 3)
|
||||
ssc_depth -= 3;
|
||||
else
|
||||
ssc_depth = RTS5228_SSC_DEPTH_8M;
|
||||
}
|
||||
} else {
|
||||
ssc_depth = 0;
|
||||
}
|
||||
pcr_dbg(pcr, "ssc_depth = %d\n", ssc_depth);
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL,
|
||||
CLK_LOW_FREQ, CLK_LOW_FREQ);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV,
|
||||
0xFF, (div << 4) | mcu_cnt);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2,
|
||||
SSC_DEPTH_MASK, ssc_depth);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
|
||||
if (vpclk) {
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
|
||||
PHASE_NOT_RESET, 0);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK1_CTL,
|
||||
PHASE_NOT_RESET, 0);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
|
||||
PHASE_NOT_RESET, PHASE_NOT_RESET);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK1_CTL,
|
||||
PHASE_NOT_RESET, PHASE_NOT_RESET);
|
||||
}
|
||||
|
||||
err = rtsx_pci_send_cmd(pcr, 2000);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Wait SSC clock stable */
|
||||
udelay(SSC_CLOCK_STABLE_WAIT);
|
||||
err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
pcr->cur_clock = clk;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void rts5228_init_params(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
struct rtsx_hw_param *hw_param = &pcr->hw_param;
|
||||
|
||||
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
|
||||
pcr->num_slots = 1;
|
||||
pcr->ops = &rts5228_pcr_ops;
|
||||
|
||||
pcr->flags = 0;
|
||||
pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
|
||||
pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
|
||||
pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
|
||||
pcr->aspm_en = ASPM_L1_EN;
|
||||
pcr->tx_initial_phase = SET_CLOCK_PHASE(28, 27, 11);
|
||||
pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
|
||||
|
||||
pcr->ic_version = rts5228_get_ic_version(pcr);
|
||||
pcr->sd_pull_ctl_enable_tbl = rts5228_sd_pull_ctl_enable_tbl;
|
||||
pcr->sd_pull_ctl_disable_tbl = rts5228_sd_pull_ctl_disable_tbl;
|
||||
|
||||
pcr->reg_pm_ctrl3 = RTS5228_AUTOLOAD_CFG3;
|
||||
|
||||
option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN
|
||||
| LTR_L1SS_PWR_GATE_EN);
|
||||
option->ltr_en = true;
|
||||
|
||||
/* init latency of active, idle, L1OFF to 60us, 300us, 3ms */
|
||||
option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF;
|
||||
option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF;
|
||||
option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF;
|
||||
option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF;
|
||||
option->ltr_l1off_sspwrgate = 0x7F;
|
||||
option->ltr_l1off_snooze_sspwrgate = 0x78;
|
||||
|
||||
option->ocp_en = 1;
|
||||
hw_param->interrupt_en |= SD_OC_INT_EN;
|
||||
hw_param->ocp_glitch = SD_OCP_GLITCH_800U;
|
||||
option->sd_800mA_ocp_thd = RTS5228_LDO1_OCP_THD_930;
|
||||
}
|
168
drivers/misc/cardreader/rts5228.h
Normal file
168
drivers/misc/cardreader/rts5228.h
Normal file
@ -0,0 +1,168 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2018-2019 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* Author:
|
||||
* Ricky WU <ricky_wu@realtek.com>
|
||||
* Rui FENG <rui_feng@realsil.com.cn>
|
||||
* Wei WANG <wei_wang@realsil.com.cn>
|
||||
*/
|
||||
#ifndef RTS5228_H
|
||||
#define RTS5228_H
|
||||
|
||||
|
||||
#define RTS5228_AUTOLOAD_CFG0 0xFF7B
|
||||
#define RTS5228_AUTOLOAD_CFG1 0xFF7C
|
||||
#define RTS5228_AUTOLOAD_CFG2 0xFF7D
|
||||
#define RTS5228_AUTOLOAD_CFG3 0xFF7E
|
||||
#define RTS5228_AUTOLOAD_CFG4 0xFF7F
|
||||
|
||||
#define RTS5228_REG_VREF 0xFE97
|
||||
#define RTS5228_PWD_SUSPND_EN (1 << 4)
|
||||
|
||||
#define RTS5228_PAD_H3L1 0xFF79
|
||||
#define PAD_GPIO_H3L1 (1 << 3)
|
||||
|
||||
/* SSC_CTL2 0xFC12 */
|
||||
#define RTS5228_SSC_DEPTH_MASK 0x07
|
||||
#define RTS5228_SSC_DEPTH_DISALBE 0x00
|
||||
#define RTS5228_SSC_DEPTH_8M 0x01
|
||||
#define RTS5228_SSC_DEPTH_4M 0x02
|
||||
#define RTS5228_SSC_DEPTH_2M 0x03
|
||||
#define RTS5228_SSC_DEPTH_1M 0x04
|
||||
#define RTS5228_SSC_DEPTH_512K 0x05
|
||||
#define RTS5228_SSC_DEPTH_256K 0x06
|
||||
#define RTS5228_SSC_DEPTH_128K 0x07
|
||||
|
||||
/* DMACTL 0xFE2C */
|
||||
#define RTS5228_DMA_PACK_SIZE_MASK 0xF0
|
||||
|
||||
#define RTS5228_REG_LDO12_CFG 0xFF6E
|
||||
#define RTS5228_LDO12_VO_TUNE_MASK (0x07<<1)
|
||||
#define RTS5228_LDO12_100 (0x00<<1)
|
||||
#define RTS5228_LDO12_105 (0x01<<1)
|
||||
#define RTS5228_LDO12_110 (0x02<<1)
|
||||
#define RTS5228_LDO12_115 (0x03<<1)
|
||||
#define RTS5228_LDO12_120 (0x04<<1)
|
||||
#define RTS5228_LDO12_125 (0x05<<1)
|
||||
#define RTS5228_LDO12_130 (0x06<<1)
|
||||
#define RTS5228_LDO12_135 (0x07<<1)
|
||||
#define RTS5228_REG_PWD_LDO12 (0x01<<0)
|
||||
|
||||
#define RTS5228_REG_LDO12_L12 0xFF6F
|
||||
#define RTS5228_LDO12_L12_MASK (0x07<<4)
|
||||
#define RTS5228_LDO12_L12_120 (0x04<<4)
|
||||
|
||||
/* LDO control register */
|
||||
#define RTS5228_CARD_PWR_CTL 0xFD50
|
||||
#define RTS5228_PUPDC (0x01<<5)
|
||||
|
||||
#define RTS5228_LDO1233318_POW_CTL 0xFF70
|
||||
#define RTS5228_LDO3318_POWERON (0x01<<3)
|
||||
#define RTS5228_LDO1_POWEROFF (0x00<<0)
|
||||
#define RTS5228_LDO1_SOFTSTART (0x01<<0)
|
||||
#define RTS5228_LDO1_FULLON (0x03<<0)
|
||||
#define RTS5228_LDO1_POWERON_MASK (0x03<<0)
|
||||
#define RTS5228_LDO_POWERON_MASK (0x0F<<0)
|
||||
|
||||
#define RTS5228_DV3318_CFG 0xFF71
|
||||
#define RTS5228_DV3318_TUNE_MASK (0x07<<4)
|
||||
#define RTS5228_DV3318_17 (0x00<<4)
|
||||
#define RTS5228_DV3318_1V75 (0x01<<4)
|
||||
#define RTS5228_DV3318_18 (0x02<<4)
|
||||
#define RTS5228_DV3318_1V85 (0x03<<4)
|
||||
#define RTS5228_DV3318_19 (0x04<<4)
|
||||
#define RTS5228_DV3318_33 (0x07<<4)
|
||||
#define RTS5228_DV3318_SR_MASK (0x03<<2)
|
||||
#define RTS5228_DV3318_SR_0 (0x00<<2)
|
||||
#define RTS5228_DV3318_SR_250 (0x01<<2)
|
||||
#define RTS5228_DV3318_SR_500 (0x02<<2)
|
||||
#define RTS5228_DV3318_SR_1000 (0x03<<2)
|
||||
|
||||
#define RTS5228_LDO1_CFG0 0xFF72
|
||||
#define RTS5228_LDO1_OCP_THD_MASK (0x07<<5)
|
||||
#define RTS5228_LDO1_OCP_EN (0x01<<4)
|
||||
#define RTS5228_LDO1_OCP_LMT_THD_MASK (0x03<<2)
|
||||
#define RTS5228_LDO1_OCP_LMT_EN (0x01<<1)
|
||||
|
||||
#define RTS5228_LDO1_OCP_THD_730 (0x00<<5)
|
||||
#define RTS5228_LDO1_OCP_THD_780 (0x01<<5)
|
||||
#define RTS5228_LDO1_OCP_THD_860 (0x02<<5)
|
||||
#define RTS5228_LDO1_OCP_THD_930 (0x03<<5)
|
||||
#define RTS5228_LDO1_OCP_THD_1000 (0x04<<5)
|
||||
#define RTS5228_LDO1_OCP_THD_1070 (0x05<<5)
|
||||
#define RTS5228_LDO1_OCP_THD_1140 (0x06<<5)
|
||||
#define RTS5228_LDO1_OCP_THD_1220 (0x07<<5)
|
||||
|
||||
#define RTS5228_LDO1_LMT_THD_450 (0x00<<2)
|
||||
#define RTS5228_LDO1_LMT_THD_1000 (0x01<<2)
|
||||
#define RTS5228_LDO1_LMT_THD_1500 (0x02<<2)
|
||||
#define RTS5228_LDO1_LMT_THD_2000 (0x03<<2)
|
||||
|
||||
#define RTS5228_LDO1_CFG1 0xFF73
|
||||
#define RTS5228_LDO1_SR_TIME_MASK (0x03<<6)
|
||||
#define RTS5228_LDO1_SR_0_0 (0x00<<6)
|
||||
#define RTS5228_LDO1_SR_0_25 (0x01<<6)
|
||||
#define RTS5228_LDO1_SR_0_5 (0x02<<6)
|
||||
#define RTS5228_LDO1_SR_1_0 (0x03<<6)
|
||||
#define RTS5228_LDO1_TUNE_MASK (0x07<<1)
|
||||
#define RTS5228_LDO1_18 (0x05<<1)
|
||||
#define RTS5228_LDO1_33 (0x07<<1)
|
||||
#define RTS5228_LDO1_PWD_MASK (0x01<<0)
|
||||
|
||||
#define RTS5228_AUXCLK_GAT_CTL 0xFF74
|
||||
|
||||
#define RTS5228_REG_RREF_CTL_0 0xFF75
|
||||
#define RTS5228_FORCE_RREF_EXTL (0x01<<7)
|
||||
#define RTS5228_REG_BG33_MASK (0x07<<0)
|
||||
#define RTS5228_RREF_12_1V (0x04<<0)
|
||||
#define RTS5228_RREF_12_3V (0x05<<0)
|
||||
|
||||
#define RTS5228_REG_RREF_CTL_1 0xFF76
|
||||
|
||||
#define RTS5228_REG_RREF_CTL_2 0xFF77
|
||||
#define RTS5228_TEST_INTL_RREF (0x01<<7)
|
||||
#define RTS5228_DGLCH_TIME_MASK (0x03<<5)
|
||||
#define RTS5228_DGLCH_TIME_50 (0x00<<5)
|
||||
#define RTS5228_DGLCH_TIME_75 (0x01<<5)
|
||||
#define RTS5228_DGLCH_TIME_100 (0x02<<5)
|
||||
#define RTS5228_DGLCH_TIME_125 (0x03<<5)
|
||||
#define RTS5228_REG_REXT_TUNE_MASK (0x1F<<0)
|
||||
|
||||
#define RTS5228_REG_PME_FORCE_CTL 0xFF78
|
||||
#define FORCE_PM_CONTROL 0x20
|
||||
#define FORCE_PM_VALUE 0x10
|
||||
|
||||
|
||||
/* Single LUN, support SD */
|
||||
#define DEFAULT_SINGLE 0
|
||||
#define SD_LUN 1
|
||||
|
||||
|
||||
/* For Change_FPGA_SSCClock Function */
|
||||
#define MULTIPLY_BY_1 0x00
|
||||
#define MULTIPLY_BY_2 0x01
|
||||
#define MULTIPLY_BY_3 0x02
|
||||
#define MULTIPLY_BY_4 0x03
|
||||
#define MULTIPLY_BY_5 0x04
|
||||
#define MULTIPLY_BY_6 0x05
|
||||
#define MULTIPLY_BY_7 0x06
|
||||
#define MULTIPLY_BY_8 0x07
|
||||
#define MULTIPLY_BY_9 0x08
|
||||
#define MULTIPLY_BY_10 0x09
|
||||
|
||||
#define DIVIDE_BY_2 0x01
|
||||
#define DIVIDE_BY_3 0x02
|
||||
#define DIVIDE_BY_4 0x03
|
||||
#define DIVIDE_BY_5 0x04
|
||||
#define DIVIDE_BY_6 0x05
|
||||
#define DIVIDE_BY_7 0x06
|
||||
#define DIVIDE_BY_8 0x07
|
||||
#define DIVIDE_BY_9 0x08
|
||||
#define DIVIDE_BY_10 0x09
|
||||
|
||||
int rts5228_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
|
||||
|
||||
#endif /* RTS5228_H */
|
@ -23,9 +23,10 @@ static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr)
|
||||
|
||||
static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
if (!rtsx_vendor_setting_valid(reg))
|
||||
@ -37,7 +38,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
pcr->card_drive_sel &= 0x3F;
|
||||
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG2, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
pcr->sd30_drive_sel_3v3 =
|
||||
map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
|
||||
|
@ -55,9 +55,10 @@ static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
|
||||
|
||||
static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
if (!rtsx_vendor_setting_valid(reg)) {
|
||||
@ -70,7 +71,7 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
pcr->card_drive_sel &= 0x3F;
|
||||
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG2, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
|
||||
if (rtsx_reg_check_reverse_socket(reg))
|
||||
@ -93,32 +94,33 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
|
||||
|
||||
static void rts5249_init_from_cfg(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
int l1ss;
|
||||
struct rtsx_cr_option *option = &(pcr->option);
|
||||
u32 lval;
|
||||
|
||||
if (CHK_PCI_PID(pcr, PID_524A))
|
||||
rtsx_pci_read_config_dword(pcr,
|
||||
PCR_ASPM_SETTING_REG1, &lval);
|
||||
else
|
||||
rtsx_pci_read_config_dword(pcr,
|
||||
PCR_ASPM_SETTING_REG2, &lval);
|
||||
l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!l1ss)
|
||||
return;
|
||||
|
||||
if (lval & ASPM_L1_1_EN_MASK)
|
||||
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
|
||||
|
||||
if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
|
||||
if (lval & ASPM_L1_2_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
|
||||
if (lval & PM_L1_1_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
|
||||
|
||||
if (lval & PM_L1_2_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
|
||||
|
||||
if (option->ltr_en) {
|
||||
u16 val;
|
||||
|
||||
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
|
||||
pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
|
||||
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
|
||||
option->ltr_enabled = true;
|
||||
option->ltr_active = true;
|
||||
|
@ -64,9 +64,10 @@ static void rts5260_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
|
||||
|
||||
static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
if (!rtsx_vendor_setting_valid(reg)) {
|
||||
@ -79,7 +80,7 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
pcr->card_drive_sel &= 0x3F;
|
||||
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG2, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
|
||||
if (rtsx_reg_check_reverse_socket(reg))
|
||||
@ -496,21 +497,27 @@ static void rts5260_pwr_saving_setting(struct rtsx_pcr *pcr)
|
||||
|
||||
static void rts5260_init_from_cfg(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
int l1ss;
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
u32 lval;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_ASPM_SETTING_5260, &lval);
|
||||
l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!l1ss)
|
||||
return;
|
||||
|
||||
if (lval & ASPM_L1_1_EN_MASK)
|
||||
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
|
||||
|
||||
if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
|
||||
if (lval & ASPM_L1_2_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
|
||||
if (lval & PM_L1_1_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
|
||||
|
||||
if (lval & PM_L1_2_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
|
||||
|
||||
rts5260_pwr_saving_setting(pcr);
|
||||
@ -518,7 +525,7 @@ static void rts5260_init_from_cfg(struct rtsx_pcr *pcr)
|
||||
if (option->ltr_en) {
|
||||
u16 val;
|
||||
|
||||
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
|
||||
pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
|
||||
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
|
||||
option->ltr_enabled = true;
|
||||
option->ltr_active = true;
|
||||
|
@ -59,9 +59,11 @@ static void rts5261_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
|
||||
|
||||
static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
u32 reg;
|
||||
|
||||
/* 0x814~0x817 */
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG2, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
|
||||
if (!rts5261_vendor_setting_valid(reg)) {
|
||||
@ -76,7 +78,7 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
||||
pcr->flags |= PCR_REVERSE_SOCKET;
|
||||
|
||||
/* 0x724~0x727 */
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG1, ®);
|
||||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
|
||||
|
||||
pcr->aspm_en = rts5261_reg_to_aspm(reg);
|
||||
@ -361,6 +363,7 @@ static void rts5261_process_ocp(struct rtsx_pcr *pcr)
|
||||
|
||||
static int rts5261_init_from_hw(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
int retval;
|
||||
u32 lval, i;
|
||||
u8 valid, efuse_valid, tmp;
|
||||
@ -386,8 +389,7 @@ static int rts5261_init_from_hw(struct rtsx_pcr *pcr)
|
||||
pcr_dbg(pcr, "Load efuse valid: 0x%x\n", efuse_valid);
|
||||
|
||||
if (efuse_valid == 0) {
|
||||
retval = rtsx_pci_read_config_dword(pcr,
|
||||
PCR_SETTING_REG2, &lval);
|
||||
retval = pci_read_config_dword(pdev, PCR_SETTING_REG2, &lval);
|
||||
if (retval != 0)
|
||||
pcr_dbg(pcr, "read 0x814 DW fail\n");
|
||||
pcr_dbg(pcr, "DW from 0x814: 0x%x\n", lval);
|
||||
@ -399,9 +401,9 @@ static int rts5261_init_from_hw(struct rtsx_pcr *pcr)
|
||||
REG_EFUSE_POR, 0);
|
||||
pcr_dbg(pcr, "Disable efuse por!\n");
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &lval);
|
||||
pci_read_config_dword(pdev, PCR_SETTING_REG2, &lval);
|
||||
lval = lval & 0x00FFFFFF;
|
||||
retval = rtsx_pci_write_config_dword(pcr, PCR_SETTING_REG2, lval);
|
||||
retval = pci_write_config_dword(pdev, PCR_SETTING_REG2, lval);
|
||||
if (retval != 0)
|
||||
pcr_dbg(pcr, "write config fail\n");
|
||||
|
||||
@ -410,27 +412,33 @@ static int rts5261_init_from_hw(struct rtsx_pcr *pcr)
|
||||
|
||||
static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
int l1ss;
|
||||
u32 lval;
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
|
||||
rtsx_pci_read_config_dword(pcr, PCR_ASPM_SETTING_REG1, &lval);
|
||||
l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
|
||||
if (!l1ss)
|
||||
return;
|
||||
|
||||
if (lval & ASPM_L1_1_EN_MASK)
|
||||
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
|
||||
|
||||
if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
else
|
||||
rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN);
|
||||
|
||||
if (lval & ASPM_L1_2_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
|
||||
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
else
|
||||
rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN);
|
||||
|
||||
if (lval & PM_L1_1_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
|
||||
else
|
||||
rtsx_clear_dev_flag(pcr, PM_L1_1_EN);
|
||||
|
||||
if (lval & PM_L1_2_EN_MASK)
|
||||
if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
|
||||
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
|
||||
else
|
||||
rtsx_clear_dev_flag(pcr, PM_L1_2_EN);
|
||||
@ -439,7 +447,7 @@ static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
|
||||
if (option->ltr_en) {
|
||||
u16 val;
|
||||
|
||||
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
|
||||
pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
|
||||
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
|
||||
option->ltr_enabled = true;
|
||||
option->ltr_active = true;
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include "rtsx_pcr.h"
|
||||
#include "rts5261.h"
|
||||
#include "rts5228.h"
|
||||
|
||||
static bool msi_en = true;
|
||||
module_param(msi_en, bool, S_IRUGO | S_IWUSR);
|
||||
@ -50,6 +51,7 @@ static const struct pci_device_id rtsx_pci_ids[] = {
|
||||
{ PCI_DEVICE(0x10EC, 0x525A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x5260), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x5261), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ PCI_DEVICE(0x10EC, 0x5228), PCI_CLASS_OTHERS << 16, 0xFF0000 },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
@ -206,16 +208,10 @@ int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val)
|
||||
int err, i, finished = 0;
|
||||
u8 tmp;
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8));
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81);
|
||||
|
||||
err = rtsx_pci_send_cmd(pcr, 100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
rtsx_pci_write_register(pcr, PHYDATA0, 0xFF, (u8)val);
|
||||
rtsx_pci_write_register(pcr, PHYDATA1, 0xFF, (u8)(val >> 8));
|
||||
rtsx_pci_write_register(pcr, PHYADDR, 0xFF, addr);
|
||||
rtsx_pci_write_register(pcr, PHYRWCTL, 0xFF, 0x81);
|
||||
|
||||
for (i = 0; i < 100000; i++) {
|
||||
err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
|
||||
@ -247,16 +243,10 @@ int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
|
||||
{
|
||||
int err, i, finished = 0;
|
||||
u16 data;
|
||||
u8 *ptr, tmp;
|
||||
u8 tmp, val1, val2;
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80);
|
||||
|
||||
err = rtsx_pci_send_cmd(pcr, 100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
rtsx_pci_write_register(pcr, PHYADDR, 0xFF, addr);
|
||||
rtsx_pci_write_register(pcr, PHYRWCTL, 0xFF, 0x80);
|
||||
|
||||
for (i = 0; i < 100000; i++) {
|
||||
err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
|
||||
@ -272,17 +262,9 @@ int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
|
||||
if (!finished)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
rtsx_pci_init_cmd(pcr);
|
||||
|
||||
rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0);
|
||||
rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0);
|
||||
|
||||
err = rtsx_pci_send_cmd(pcr, 100);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
ptr = rtsx_pci_get_cmd_data(pcr);
|
||||
data = ((u16)ptr[1] << 8) | ptr[0];
|
||||
rtsx_pci_read_register(pcr, PHYDATA0, &val1);
|
||||
rtsx_pci_read_register(pcr, PHYDATA1, &val2);
|
||||
data = val1 | (val2 << 8);
|
||||
|
||||
if (val)
|
||||
*val = data;
|
||||
@ -417,7 +399,7 @@ static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr,
|
||||
if (end)
|
||||
option |= RTSX_SG_END;
|
||||
|
||||
if (PCI_PID(pcr) == PID_5261) {
|
||||
if ((PCI_PID(pcr) == PID_5261) || (PCI_PID(pcr) == PID_5228)) {
|
||||
if (len > 0xFFFF)
|
||||
val = ((u64)addr << 32) | (((u64)len & 0xFFFF) << 16)
|
||||
| (((u64)len >> 16) << 6) | option;
|
||||
@ -723,6 +705,9 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
||||
if (PCI_PID(pcr) == PID_5261)
|
||||
return rts5261_pci_switch_clock(pcr, card_clock,
|
||||
ssc_depth, initial_mode, double_clk, vpclk);
|
||||
if (PCI_PID(pcr) == PID_5228)
|
||||
return rts5228_pci_switch_clock(pcr, card_clock,
|
||||
ssc_depth, initial_mode, double_clk, vpclk);
|
||||
|
||||
if (initial_mode) {
|
||||
/* We use 250k(around) here, in initial stage */
|
||||
@ -1111,8 +1096,7 @@ static void rtsx_pci_idle_work(struct work_struct *work)
|
||||
mutex_unlock(&pcr->pcr_mutex);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
|
||||
static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
|
||||
{
|
||||
if (pcr->ops->turn_off_led)
|
||||
pcr->ops->turn_off_led(pcr);
|
||||
@ -1126,7 +1110,6 @@ static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
|
||||
if (pcr->ops->force_power_down)
|
||||
pcr->ops->force_power_down(pcr, pm_state);
|
||||
}
|
||||
#endif
|
||||
|
||||
void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
|
||||
{
|
||||
@ -1202,6 +1185,36 @@ void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr)
|
||||
}
|
||||
}
|
||||
|
||||
void rtsx_pci_enable_oobs_polling(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
if ((PCI_PID(pcr) != PID_525A) && (PCI_PID(pcr) != PID_5260)) {
|
||||
rtsx_pci_read_phy_register(pcr, 0x01, &val);
|
||||
val |= 1<<9;
|
||||
rtsx_pci_write_phy_register(pcr, 0x01, val);
|
||||
}
|
||||
rtsx_pci_write_register(pcr, REG_CFG_OOBS_OFF_TIMER, 0xFF, 0x32);
|
||||
rtsx_pci_write_register(pcr, REG_CFG_OOBS_ON_TIMER, 0xFF, 0x05);
|
||||
rtsx_pci_write_register(pcr, REG_CFG_VCM_ON_TIMER, 0xFF, 0x83);
|
||||
rtsx_pci_write_register(pcr, REG_CFG_OOBS_POLLING, 0xFF, 0xDE);
|
||||
|
||||
}
|
||||
|
||||
void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr)
|
||||
{
|
||||
u16 val;
|
||||
|
||||
if ((PCI_PID(pcr) != PID_525A) && (PCI_PID(pcr) != PID_5260)) {
|
||||
rtsx_pci_read_phy_register(pcr, 0x01, &val);
|
||||
val &= ~(1<<9);
|
||||
rtsx_pci_write_phy_register(pcr, 0x01, val);
|
||||
}
|
||||
rtsx_pci_write_register(pcr, REG_CFG_VCM_ON_TIMER, 0xFF, 0x03);
|
||||
rtsx_pci_write_register(pcr, REG_CFG_OOBS_POLLING, 0xFF, 0x00);
|
||||
|
||||
}
|
||||
|
||||
int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr)
|
||||
{
|
||||
rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN |
|
||||
@ -1231,9 +1244,13 @@ int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr)
|
||||
|
||||
static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct pci_dev *pdev = pcr->pci;
|
||||
int err;
|
||||
|
||||
pcr->pcie_cap = pci_find_capability(pcr->pci, PCI_CAP_ID_EXP);
|
||||
if (PCI_PID(pcr) == PID_5228)
|
||||
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG1, RTS5228_LDO1_SR_TIME_MASK,
|
||||
RTS5228_LDO1_SR_0_5);
|
||||
|
||||
rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr);
|
||||
|
||||
rtsx_pci_enable_bus_int(pcr);
|
||||
@ -1280,6 +1297,9 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
|
||||
if (PCI_PID(pcr) == PID_5261)
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF,
|
||||
RTS5261_SSC_DEPTH_2M);
|
||||
else if (PCI_PID(pcr) == PID_5228)
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF,
|
||||
RTS5228_SSC_DEPTH_2M);
|
||||
else
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12);
|
||||
|
||||
@ -1314,6 +1334,7 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
|
||||
case PID_525A:
|
||||
case PID_5260:
|
||||
case PID_5261:
|
||||
case PID_5228:
|
||||
rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
|
||||
break;
|
||||
default:
|
||||
@ -1324,9 +1345,10 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
|
||||
rtsx_pci_init_ocp(pcr);
|
||||
|
||||
/* Enable clk_request_n to enable clock power management */
|
||||
rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1);
|
||||
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_CLKREQ_EN);
|
||||
/* Enter L1 when host tx idle */
|
||||
rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B);
|
||||
pci_write_config_byte(pdev, 0x70F, 0x5B);
|
||||
|
||||
if (pcr->ops->extra_init_hw) {
|
||||
err = pcr->ops->extra_init_hw(pcr);
|
||||
@ -1401,6 +1423,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
|
||||
case 0x5261:
|
||||
rts5261_init_params(pcr);
|
||||
break;
|
||||
|
||||
case 0x5228:
|
||||
rts5228_init_params(pcr);
|
||||
break;
|
||||
}
|
||||
|
||||
pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n",
|
||||
@ -1604,10 +1630,9 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
|
||||
pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
|
||||
static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
|
||||
{
|
||||
struct pci_dev *pcidev = to_pci_dev(dev_d);
|
||||
struct pcr_handle *handle;
|
||||
struct rtsx_pcr *pcr;
|
||||
|
||||
@ -1623,17 +1648,15 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
|
||||
|
||||
rtsx_pci_power_off(pcr, HOST_ENTER_S3);
|
||||
|
||||
pci_save_state(pcidev);
|
||||
pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
|
||||
pci_disable_device(pcidev);
|
||||
pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
|
||||
device_wakeup_disable(dev_d);
|
||||
|
||||
mutex_unlock(&pcr->pcr_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtsx_pci_resume(struct pci_dev *pcidev)
|
||||
static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
|
||||
{
|
||||
struct pci_dev *pcidev = to_pci_dev(dev_d);
|
||||
struct pcr_handle *handle;
|
||||
struct rtsx_pcr *pcr;
|
||||
int ret = 0;
|
||||
@ -1645,13 +1668,6 @@ static int rtsx_pci_resume(struct pci_dev *pcidev)
|
||||
|
||||
mutex_lock(&pcr->pcr_mutex);
|
||||
|
||||
pci_set_power_state(pcidev, PCI_D0);
|
||||
pci_restore_state(pcidev);
|
||||
ret = pci_enable_device(pcidev);
|
||||
if (ret)
|
||||
goto out;
|
||||
pci_set_master(pcidev);
|
||||
|
||||
ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
|
||||
if (ret)
|
||||
goto out;
|
||||
@ -1667,6 +1683,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static void rtsx_pci_shutdown(struct pci_dev *pcidev)
|
||||
{
|
||||
struct pcr_handle *handle;
|
||||
@ -1686,19 +1704,18 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
|
||||
|
||||
#else /* CONFIG_PM */
|
||||
|
||||
#define rtsx_pci_suspend NULL
|
||||
#define rtsx_pci_resume NULL
|
||||
#define rtsx_pci_shutdown NULL
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(rtsx_pci_pm_ops, rtsx_pci_suspend, rtsx_pci_resume);
|
||||
|
||||
static struct pci_driver rtsx_pci_driver = {
|
||||
.name = DRV_NAME_RTSX_PCI,
|
||||
.id_table = rtsx_pci_ids,
|
||||
.probe = rtsx_pci_probe,
|
||||
.remove = rtsx_pci_remove,
|
||||
.suspend = rtsx_pci_suspend,
|
||||
.resume = rtsx_pci_resume,
|
||||
.driver.pm = &rtsx_pci_pm_ops,
|
||||
.shutdown = rtsx_pci_shutdown,
|
||||
};
|
||||
module_pci_driver(rtsx_pci_driver);
|
||||
|
@ -53,6 +53,7 @@ void rts525a_init_params(struct rtsx_pcr *pcr);
|
||||
void rtl8411b_init_params(struct rtsx_pcr *pcr);
|
||||
void rts5260_init_params(struct rtsx_pcr *pcr);
|
||||
void rts5261_init_params(struct rtsx_pcr *pcr);
|
||||
void rts5228_init_params(struct rtsx_pcr *pcr);
|
||||
|
||||
static inline u8 map_sd_drive(int idx)
|
||||
{
|
||||
@ -70,6 +71,8 @@ static inline u8 map_sd_drive(int idx)
|
||||
#define rts5209_vendor_setting1_valid(reg) (!((reg) & 0x80))
|
||||
#define rts5209_vendor_setting2_valid(reg) ((reg) & 0x80)
|
||||
|
||||
#define rtsx_check_mmc_support(reg) ((reg) & 0x10)
|
||||
#define rtsx_reg_to_rtd3(reg) ((reg) & 0x02)
|
||||
#define rtsx_reg_to_aspm(reg) (((reg) >> 28) & 0x03)
|
||||
#define rtsx_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 26) & 0x03)
|
||||
#define rtsx_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x03)
|
||||
@ -100,6 +103,8 @@ void rtsx_pci_disable_ocp(struct rtsx_pcr *pcr);
|
||||
void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr);
|
||||
int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val);
|
||||
void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr);
|
||||
void rtsx_pci_enable_oobs_polling(struct rtsx_pcr *pcr);
|
||||
void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr);
|
||||
int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr);
|
||||
int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr);
|
||||
|
||||
|
@ -759,7 +759,7 @@ static int rtsx_usb_post_reset(struct usb_interface *intf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct usb_device_id rtsx_usb_usb_ids[] = {
|
||||
static const struct usb_device_id rtsx_usb_usb_ids[] = {
|
||||
{ USB_DEVICE(0x0BDA, 0x0129) },
|
||||
{ USB_DEVICE(0x0BDA, 0x0139) },
|
||||
{ USB_DEVICE(0x0BDA, 0x0140) },
|
||||
|
@ -166,37 +166,24 @@ void cb710_set_irq_handler(struct cb710_slot *slot,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cb710_set_irq_handler);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int cb710_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||
static int __maybe_unused cb710_suspend(struct device *dev_d)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev_d);
|
||||
struct cb710_chip *chip = pci_get_drvdata(pdev);
|
||||
|
||||
devm_free_irq(&pdev->dev, pdev->irq, chip);
|
||||
pci_save_state(pdev);
|
||||
pci_disable_device(pdev);
|
||||
if (state.event & PM_EVENT_SLEEP)
|
||||
pci_set_power_state(pdev, PCI_D3hot);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cb710_resume(struct pci_dev *pdev)
|
||||
static int __maybe_unused cb710_resume(struct device *dev_d)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev_d);
|
||||
struct cb710_chip *chip = pci_get_drvdata(pdev);
|
||||
int err;
|
||||
|
||||
pci_set_power_state(pdev, PCI_D0);
|
||||
pci_restore_state(pdev);
|
||||
err = pcim_enable_device(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return devm_request_irq(&pdev->dev, pdev->irq,
|
||||
cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static int cb710_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent)
|
||||
{
|
||||
@ -312,15 +299,14 @@ static const struct pci_device_id cb710_pci_tbl[] = {
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(cb710_pm_ops, cb710_suspend, cb710_resume);
|
||||
|
||||
static struct pci_driver cb710_driver = {
|
||||
.name = KBUILD_MODNAME,
|
||||
.id_table = cb710_pci_tbl,
|
||||
.probe = cb710_probe,
|
||||
.remove = cb710_remove_one,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = cb710_suspend,
|
||||
.resume = cb710_resume,
|
||||
#endif
|
||||
.driver.pm = &cb710_pm_ops,
|
||||
};
|
||||
|
||||
static int __init cb710_init_module(void)
|
||||
|
@ -117,6 +117,7 @@ static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data)
|
||||
/**
|
||||
* cb710_sg_dwiter_write_next_block() - write next 32-bit word to sg buffer
|
||||
* @miter: sg mapping iterator used for writing
|
||||
* @data: data to write to sg buffer
|
||||
*
|
||||
* Description:
|
||||
* Writes 32-bit word starting at byte pointed to by @miter@
|
||||
|
@ -175,7 +175,7 @@ static int update_devicetree(struct cxl *adapter, s32 scope)
|
||||
struct update_nodes_workarea *unwa;
|
||||
u32 action, node_count;
|
||||
int token, rc, i;
|
||||
__be32 *data, drc_index, phandle;
|
||||
__be32 *data, phandle;
|
||||
char *buf;
|
||||
|
||||
token = rtas_token("ibm,update-nodes");
|
||||
@ -213,7 +213,7 @@ static int update_devicetree(struct cxl *adapter, s32 scope)
|
||||
break;
|
||||
case OPCODE_ADD:
|
||||
/* nothing to do, just move pointer */
|
||||
drc_index = *data++;
|
||||
data++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ long cxl_h_attach_process(u64 unit_address,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_detach_process - Detach a process element from a coherent
|
||||
* platform function.
|
||||
*/
|
||||
@ -197,7 +197,7 @@ long cxl_h_detach_process(u64 unit_address, u64 process_token)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_control_function - This H_CONTROL_CA_FUNCTION hypervisor call allows
|
||||
* the partition to manipulate or query
|
||||
* certain coherent platform function behaviors.
|
||||
@ -238,7 +238,7 @@ static long cxl_h_control_function(u64 unit_address, u64 op,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_reset_afu - Perform a reset to the coherent platform function.
|
||||
*/
|
||||
long cxl_h_reset_afu(u64 unit_address)
|
||||
@ -249,7 +249,7 @@ long cxl_h_reset_afu(u64 unit_address)
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_suspend_process - Suspend a process from being executed
|
||||
* Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
|
||||
* process was attached.
|
||||
@ -262,7 +262,7 @@ long cxl_h_suspend_process(u64 unit_address, u64 process_token)
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_resume_process - Resume a process to be executed
|
||||
* Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
|
||||
* process was attached.
|
||||
@ -275,7 +275,7 @@ long cxl_h_resume_process(u64 unit_address, u64 process_token)
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_read_error_state - Checks the error state of the coherent
|
||||
* platform function.
|
||||
* R4 contains the error state
|
||||
@ -288,7 +288,7 @@ long cxl_h_read_error_state(u64 unit_address, u64 *state)
|
||||
state);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_get_afu_err - collect the AFU error buffer
|
||||
* Parameter1 = byte offset into error buffer to retrieve, valid values
|
||||
* are between 0 and (ibm,error-buffer-size - 1)
|
||||
@ -304,7 +304,7 @@ long cxl_h_get_afu_err(u64 unit_address, u64 offset,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_get_config - collect configuration record for the
|
||||
* coherent platform function
|
||||
* Parameter1 = # of configuration record to retrieve, valid values are
|
||||
@ -324,7 +324,7 @@ long cxl_h_get_config(u64 unit_address, u64 cr_num, u64 offset,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_terminate_process - Terminate the process before completion
|
||||
* Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
|
||||
* process was attached.
|
||||
@ -337,7 +337,7 @@ long cxl_h_terminate_process(u64 unit_address, u64 process_token)
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_collect_vpd - Collect VPD for the coherent platform function.
|
||||
* Parameter1 = # of VPD record to retrieve, valid values are between 0
|
||||
* and (ibm,#config-records - 1).
|
||||
@ -355,7 +355,7 @@ long cxl_h_collect_vpd(u64 unit_address, u64 record, u64 list_address,
|
||||
out);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_get_fn_error_interrupt - Read the function-wide error data based on an interrupt
|
||||
*/
|
||||
long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg)
|
||||
@ -365,7 +365,7 @@ long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg)
|
||||
0, 0, 0, 0, reg);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_ack_fn_error_interrupt - Acknowledge function-wide error data
|
||||
* based on an interrupt
|
||||
* Parameter1 = value to write to the function-wide error interrupt register
|
||||
@ -378,7 +378,7 @@ long cxl_h_ack_fn_error_interrupt(u64 unit_address, u64 value)
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_get_error_log - Retrieve the Platform Log ID (PLID) of
|
||||
* an error log
|
||||
*/
|
||||
@ -390,7 +390,7 @@ long cxl_h_get_error_log(u64 unit_address, u64 value)
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_collect_int_info - Collect interrupt info about a coherent
|
||||
* platform function after an interrupt occurred.
|
||||
*/
|
||||
@ -425,7 +425,7 @@ long cxl_h_collect_int_info(u64 unit_address, u64 process_token,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_control_faults - Control the operation of a coherent platform
|
||||
* function after a fault occurs.
|
||||
*
|
||||
@ -470,7 +470,7 @@ long cxl_h_control_faults(u64 unit_address, u64 process_token,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_control_facility - This H_CONTROL_CA_FACILITY hypervisor call
|
||||
* allows the partition to manipulate or query
|
||||
* certain coherent platform facility behaviors.
|
||||
@ -509,7 +509,7 @@ static long cxl_h_control_facility(u64 unit_address, u64 op,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_reset_adapter - Perform a reset to the coherent platform facility.
|
||||
*/
|
||||
long cxl_h_reset_adapter(u64 unit_address)
|
||||
@ -520,7 +520,7 @@ long cxl_h_reset_adapter(u64 unit_address)
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_collect_vpd - Collect VPD for the coherent platform function.
|
||||
* Parameter1 = 4K naturally aligned real buffer containing block
|
||||
* list entries
|
||||
@ -536,7 +536,7 @@ long cxl_h_collect_vpd_adapter(u64 unit_address, u64 list_address,
|
||||
out);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_download_facility - This H_DOWNLOAD_CA_FACILITY
|
||||
* hypervisor call provide platform support for
|
||||
* downloading a base adapter image to the coherent
|
||||
@ -616,7 +616,7 @@ static long cxl_h_download_facility(u64 unit_address, u64 op,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_download_adapter_image - Download the base image to the coherent
|
||||
* platform facility.
|
||||
*/
|
||||
@ -629,7 +629,7 @@ long cxl_h_download_adapter_image(u64 unit_address,
|
||||
list_address, num, out);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* cxl_h_validate_adapter_image - Validate the base image in the coherent
|
||||
* platform facility.
|
||||
*/
|
||||
|
@ -624,7 +624,7 @@ static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int c
|
||||
rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
|
||||
&afu->dev.kobj, "cr%i", cr->cr);
|
||||
if (rc)
|
||||
goto err;
|
||||
goto err1;
|
||||
|
||||
rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
|
||||
if (rc)
|
||||
|
@ -150,7 +150,7 @@ static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
|
||||
|
||||
out:
|
||||
cxl_afu_configured_put(afu);
|
||||
return rc ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
|
||||
return rc ? PCIBIOS_DEVICE_NOT_FOUND : 0;
|
||||
}
|
||||
|
||||
static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
|
||||
@ -184,7 +184,7 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
|
||||
|
||||
out:
|
||||
cxl_afu_configured_put(afu);
|
||||
return rc ? PCIBIOS_SET_FAILED : PCIBIOS_SUCCESSFUL;
|
||||
return rc ? PCIBIOS_SET_FAILED : 0;
|
||||
}
|
||||
|
||||
static struct pci_ops cxl_pcie_pci_ops =
|
||||
|
@ -66,13 +66,13 @@
|
||||
Path Models", IEEE Transactions on communications, COM-25,
|
||||
No. 6, June
|
||||
1977.
|
||||
http://www.rowetel.com/images/echo/dual_path_paper.pdf
|
||||
https://www.rowetel.com/images/echo/dual_path_paper.pdf
|
||||
|
||||
[2] The classic, very useful paper that tells you how to
|
||||
actually build a real world echo canceller:
|
||||
Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice
|
||||
Echo Canceller with a TMS320020,
|
||||
http://www.rowetel.com/images/echo/spra129.pdf
|
||||
https://www.rowetel.com/images/echo/spra129.pdf
|
||||
|
||||
[3] I have written a series of blog posts on this work, here is
|
||||
Part 1: http://www.rowetel.com/blog/?p=18
|
||||
@ -80,7 +80,7 @@
|
||||
[4] The source code http://svn.rowetel.com/software/oslec/
|
||||
|
||||
[5] A nice reference on LMS filters:
|
||||
http://en.wikipedia.org/wiki/Least_mean_squares_filter
|
||||
https://en.wikipedia.org/wiki/Least_mean_squares_filter
|
||||
|
||||
Credits:
|
||||
|
||||
|
@ -225,7 +225,7 @@ static const struct of_device_id at24_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at24_of_match);
|
||||
|
||||
static const struct acpi_device_id at24_acpi_ids[] = {
|
||||
static const struct acpi_device_id __maybe_unused at24_acpi_ids[] = {
|
||||
{ "INT3499", (kernel_ulong_t)&at24_data_INT3499 },
|
||||
{ "TPF0001", (kernel_ulong_t)&at24_data_24c1024 },
|
||||
{ /* END OF LIST */ }
|
||||
|
@ -228,7 +228,7 @@ EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
|
||||
/**
|
||||
* eeprom_93cx6_readb - Read a byte from eeprom
|
||||
* @eeprom: Pointer to eeprom structure
|
||||
* @word: Byte index from where we should start reading
|
||||
* @byte: Byte index from where we should start reading
|
||||
* @data: target pointer where the information will have to be stored
|
||||
*
|
||||
* This function will read a byte of the eeprom data
|
||||
@ -270,7 +270,7 @@ EXPORT_SYMBOL_GPL(eeprom_93cx6_readb);
|
||||
* @eeprom: Pointer to eeprom structure
|
||||
* @byte: Index from where we should start reading
|
||||
* @data: target pointer where the information will have to be stored
|
||||
* @words: Number of bytes that should be read.
|
||||
* @bytes: Number of bytes that should be read.
|
||||
*
|
||||
* This function will read all requested bytes from the eeprom,
|
||||
* this is done by calling eeprom_93cx6_readb() multiple times.
|
||||
|
@ -103,7 +103,9 @@ EXPORT_SYMBOL_GPL(enclosure_for_each_device);
|
||||
* enclosure_register - register device as an enclosure
|
||||
*
|
||||
* @dev: device containing the enclosure
|
||||
* @name: chosen device name
|
||||
* @components: number of components in the enclosure
|
||||
* @cb: platform call-backs
|
||||
*
|
||||
* This sets up the device for being an enclosure. Note that @dev does
|
||||
* not have to be a dedicated enclosure device. It may be some other type
|
||||
@ -266,7 +268,7 @@ static const struct attribute_group *enclosure_component_groups[];
|
||||
/**
|
||||
* enclosure_component_alloc - prepare a new enclosure component
|
||||
* @edev: the enclosure to add the component
|
||||
* @num: the device number
|
||||
* @number: the device number
|
||||
* @type: the type of component being added
|
||||
* @name: an optional name to appear in sysfs (leave NULL if none)
|
||||
*
|
||||
@ -347,7 +349,7 @@ EXPORT_SYMBOL_GPL(enclosure_component_register);
|
||||
/**
|
||||
* enclosure_add_device - add a device as being part of an enclosure
|
||||
* @edev: the enclosure device being added to.
|
||||
* @num: the number of the component
|
||||
* @component: the number of the component
|
||||
* @dev: the device being added
|
||||
*
|
||||
* Declares a real device to reside in slot (or identifier) @num of an
|
||||
@ -389,7 +391,7 @@ EXPORT_SYMBOL_GPL(enclosure_add_device);
|
||||
/**
|
||||
* enclosure_remove_device - remove a device from an enclosure
|
||||
* @edev: the enclosure device
|
||||
* @num: the number of the component to remove
|
||||
* @dev: device to remove/put
|
||||
*
|
||||
* Returns zero on success or an error.
|
||||
*
|
||||
|
@ -165,6 +165,7 @@ static void genwqe_dev_free(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_bus_reset() - Card recovery
|
||||
* @cd: GenWQE device information
|
||||
*
|
||||
* pci_reset_function() will recover the device and ensure that the
|
||||
* registers are accessible again when it completes with success. If
|
||||
@ -262,6 +263,7 @@ static void genwqe_tweak_hardware(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_recovery_on_fatal_gfir_required() - Version depended actions
|
||||
* @cd: GenWQE device information
|
||||
*
|
||||
* Bitstreams older than 2013-02-17 have a bug where fatal GFIRs must
|
||||
* be ignored. This is e.g. true for the bitstream we gave to the card
|
||||
@ -280,6 +282,7 @@ int genwqe_flash_readback_fails(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_T_psec() - Calculate PF/VF timeout register content
|
||||
* @cd: GenWQE device information
|
||||
*
|
||||
* Note: From a design perspective it turned out to be a bad idea to
|
||||
* use codes here to specifiy the frequency/speed values. An old
|
||||
@ -303,6 +306,7 @@ static int genwqe_T_psec(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_setup_pf_jtimer() - Setup PF hardware timeouts for DDCB execution
|
||||
* @cd: GenWQE device information
|
||||
*
|
||||
* Do this _after_ card_reset() is called. Otherwise the values will
|
||||
* vanish. The settings need to be done when the queues are inactive.
|
||||
@ -329,6 +333,7 @@ static bool genwqe_setup_pf_jtimer(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_setup_vf_jtimer() - Setup VF hardware timeouts for DDCB execution
|
||||
* @cd: GenWQE device information
|
||||
*/
|
||||
static bool genwqe_setup_vf_jtimer(struct genwqe_dev *cd)
|
||||
{
|
||||
@ -543,6 +548,7 @@ static int genwqe_start(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_stop() - Stop card operation
|
||||
* @cd: GenWQE device information
|
||||
*
|
||||
* Recovery notes:
|
||||
* As long as genwqe_thread runs we might access registers during
|
||||
@ -569,6 +575,8 @@ static int genwqe_stop(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_recover_card() - Try to recover the card if it is possible
|
||||
* @cd: GenWQE device information
|
||||
* @fatal_err: Indicate whether to attempt soft reset
|
||||
*
|
||||
* If fatal_err is set no register access is possible anymore. It is
|
||||
* likely that genwqe_start fails in that situation. Proper error
|
||||
@ -618,6 +626,7 @@ static int genwqe_health_check_cond(struct genwqe_dev *cd, u64 *gfir)
|
||||
|
||||
/**
|
||||
* genwqe_fir_checking() - Check the fault isolation registers of the card
|
||||
* @cd: GenWQE device information
|
||||
*
|
||||
* If this code works ok, can be tried out with help of the genwqe_poke tool:
|
||||
* sudo ./tools/genwqe_poke 0x8 0xfefefefefef
|
||||
@ -762,6 +771,7 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_pci_fundamental_reset() - trigger a PCIe fundamental reset on the slot
|
||||
* @pci_dev: PCI device information struct
|
||||
*
|
||||
* Note: pci_set_pcie_reset_state() is not implemented on all archs, so this
|
||||
* reset method will not work in all cases.
|
||||
@ -826,8 +836,9 @@ static int genwqe_platform_recovery(struct genwqe_dev *cd)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* genwqe_reload_bistream() - reload card bitstream
|
||||
* @cd: GenWQE device information
|
||||
*
|
||||
* Set the appropriate register and call fundamental reset to reaload the card
|
||||
* bitstream.
|
||||
@ -880,6 +891,7 @@ static int genwqe_reload_bistream(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_health_thread() - Health checking thread
|
||||
* @data: GenWQE device information
|
||||
*
|
||||
* This thread is only started for the PF of the card.
|
||||
*
|
||||
@ -1043,18 +1055,17 @@ static int genwqe_health_thread_running(struct genwqe_dev *cd)
|
||||
|
||||
static int genwqe_health_check_stop(struct genwqe_dev *cd)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!genwqe_health_thread_running(cd))
|
||||
return -EIO;
|
||||
|
||||
rc = kthread_stop(cd->health_thread);
|
||||
kthread_stop(cd->health_thread);
|
||||
cd->health_thread = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* genwqe_pci_setup() - Allocate PCIe related resources for our card
|
||||
* @cd: GenWQE device information
|
||||
*/
|
||||
static int genwqe_pci_setup(struct genwqe_dev *cd)
|
||||
{
|
||||
@ -1140,6 +1151,7 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_pci_remove() - Free PCIe related resources for our card
|
||||
* @cd: GenWQE device information
|
||||
*/
|
||||
static void genwqe_pci_remove(struct genwqe_dev *cd)
|
||||
{
|
||||
@ -1154,7 +1166,8 @@ static void genwqe_pci_remove(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_probe() - Device initialization
|
||||
* @pdev: PCI device information struct
|
||||
* @pci_dev: PCI device information struct
|
||||
* @id: PCI device ID
|
||||
*
|
||||
* Callable for multiple cards. This function is called on bind.
|
||||
*
|
||||
@ -1214,6 +1227,7 @@ static int genwqe_probe(struct pci_dev *pci_dev,
|
||||
|
||||
/**
|
||||
* genwqe_remove() - Called when device is removed (hot-plugable)
|
||||
* @pci_dev: PCI device information struct
|
||||
*
|
||||
* Or when driver is unloaded respecitively when unbind is done.
|
||||
*/
|
||||
@ -1233,8 +1247,10 @@ static void genwqe_remove(struct pci_dev *pci_dev)
|
||||
genwqe_dev_free(cd);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* genwqe_err_error_detected() - Error detection callback
|
||||
* @pci_dev: PCI device information struct
|
||||
* @state: PCI channel state
|
||||
*
|
||||
* This callback is called by the PCI subsystem whenever a PCI bus
|
||||
* error is detected.
|
||||
@ -1324,7 +1340,7 @@ static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_error_handlers genwqe_err_handler = {
|
||||
static const struct pci_error_handlers genwqe_err_handler = {
|
||||
.error_detected = genwqe_err_error_detected,
|
||||
.mmio_enabled = genwqe_err_result_none,
|
||||
.slot_reset = genwqe_err_slot_reset,
|
||||
@ -1342,6 +1358,8 @@ static struct pci_driver genwqe_driver = {
|
||||
|
||||
/**
|
||||
* genwqe_devnode() - Set default access mode for genwqe devices.
|
||||
* @dev: Pointer to device (unused)
|
||||
* @mode: Carrier to pass-back given mode (permissions)
|
||||
*
|
||||
* Default mode should be rw for everybody. Do not change default
|
||||
* device name.
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
/*
|
||||
* IBM Accelerator Family 'GenWQE'
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2013
|
||||
@ -244,10 +244,13 @@ static int ddcb_requ_finished(struct genwqe_dev *cd, struct ddcb_requ *req)
|
||||
(cd->card_state != GENWQE_CARD_USED);
|
||||
}
|
||||
|
||||
#define RET_DDCB_APPENDED 1
|
||||
#define RET_DDCB_TAPPED 2
|
||||
/**
|
||||
* enqueue_ddcb() - Enqueue a DDCB
|
||||
* @cd: pointer to genwqe device descriptor
|
||||
* @queue: queue this operation should be done on
|
||||
* @pddcb: pointer to ddcb structure
|
||||
* @ddcb_no: pointer to ddcb number being tapped
|
||||
*
|
||||
* Start execution of DDCB by tapping or append to queue via NEXT
|
||||
@ -259,9 +262,6 @@ static int ddcb_requ_finished(struct genwqe_dev *cd, struct ddcb_requ *req)
|
||||
* Return: 1 if new DDCB is appended to previous
|
||||
* 2 if DDCB queue is tapped via register/simulation
|
||||
*/
|
||||
#define RET_DDCB_APPENDED 1
|
||||
#define RET_DDCB_TAPPED 2
|
||||
|
||||
static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
|
||||
struct ddcb *pddcb, int ddcb_no)
|
||||
{
|
||||
@ -316,6 +316,8 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
|
||||
|
||||
/**
|
||||
* copy_ddcb_results() - Copy output state from real DDCB to request
|
||||
* @req: pointer to requsted DDCB parameters
|
||||
* @ddcb_no: pointer to ddcb number being tapped
|
||||
*
|
||||
* Copy DDCB ASV to request struct. There is no endian
|
||||
* conversion made, since data structure in ASV is still
|
||||
@ -356,6 +358,7 @@ static void copy_ddcb_results(struct ddcb_requ *req, int ddcb_no)
|
||||
/**
|
||||
* genwqe_check_ddcb_queue() - Checks DDCB queue for completed work equests.
|
||||
* @cd: pointer to genwqe device descriptor
|
||||
* @queue: queue to be checked
|
||||
*
|
||||
* Return: Number of DDCBs which were finished
|
||||
*/
|
||||
@ -553,6 +556,8 @@ int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
|
||||
/**
|
||||
* get_next_ddcb() - Get next available DDCB
|
||||
* @cd: pointer to genwqe device descriptor
|
||||
* @queue: DDCB queue
|
||||
* @num: internal DDCB number
|
||||
*
|
||||
* DDCB's content is completely cleared but presets for PRE and
|
||||
* SEQNUM. This function must only be called when ddcb_lock is held.
|
||||
@ -900,7 +905,7 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req,
|
||||
/**
|
||||
* __genwqe_execute_raw_ddcb() - Setup and execute DDCB
|
||||
* @cd: pointer to genwqe device descriptor
|
||||
* @req: user provided DDCB request
|
||||
* @cmd: user provided DDCB command
|
||||
* @f_flags: file mode: blocking, non-blocking
|
||||
*/
|
||||
int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
|
||||
@ -965,6 +970,7 @@ int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
|
||||
|
||||
/**
|
||||
* genwqe_next_ddcb_ready() - Figure out if the next DDCB is already finished
|
||||
* @cd: pointer to genwqe device descriptor
|
||||
*
|
||||
* We use this as condition for our wait-queue code.
|
||||
*/
|
||||
@ -993,6 +999,7 @@ static int genwqe_next_ddcb_ready(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_ddcbs_in_flight() - Check how many DDCBs are in flight
|
||||
* @cd: pointer to genwqe device descriptor
|
||||
*
|
||||
* Keep track on the number of DDCBs which ware currently in the
|
||||
* queue. This is needed for statistics as well as conditon if we want
|
||||
@ -1171,6 +1178,7 @@ static irqreturn_t genwqe_vf_isr(int irq, void *dev_id)
|
||||
|
||||
/**
|
||||
* genwqe_card_thread() - Work thread for the DDCB queue
|
||||
* @data: pointer to genwqe device descriptor
|
||||
*
|
||||
* The idea is to check if there are DDCBs in processing. If there are
|
||||
* some finished DDCBs, we process them and wakeup the
|
||||
@ -1299,6 +1307,7 @@ int genwqe_setup_service_layer(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* queue_wake_up_all() - Handles fatal error case
|
||||
* @cd: pointer to genwqe device descriptor
|
||||
*
|
||||
* The PCI device got unusable and we have to stop all pending
|
||||
* requests as fast as we can. The code after this must purge the
|
||||
@ -1323,6 +1332,7 @@ static int queue_wake_up_all(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_finish_queue() - Remove any genwqe devices and user-interfaces
|
||||
* @cd: pointer to genwqe device descriptor
|
||||
*
|
||||
* Relies on the pre-condition that there are no users of the card
|
||||
* device anymore e.g. with open file-descriptors.
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
/*
|
||||
* IBM Accelerator Family 'GenWQE'
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2013
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
/*
|
||||
* IBM Accelerator Family 'GenWQE'
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2013
|
||||
@ -87,7 +87,7 @@ static int genwqe_del_pin(struct genwqe_file *cfile, struct dma_mapping *m)
|
||||
* @cfile: Descriptor of opened file
|
||||
* @u_addr: User virtual address
|
||||
* @size: Size of buffer
|
||||
* @dma_addr: DMA address to be updated
|
||||
* @virt_addr: Virtual address to be updated
|
||||
*
|
||||
* Return: Pointer to the corresponding mapping NULL if not found
|
||||
*/
|
||||
@ -144,6 +144,7 @@ static void __genwqe_del_mapping(struct genwqe_file *cfile,
|
||||
* @u_addr: user virtual address
|
||||
* @size: size of buffer
|
||||
* @dma_addr: DMA address to be updated
|
||||
* @virt_addr: Virtual address to be updated
|
||||
* Return: Pointer to the corresponding mapping NULL if not found
|
||||
*/
|
||||
static struct dma_mapping *__genwqe_search_mapping(struct genwqe_file *cfile,
|
||||
@ -249,6 +250,8 @@ static void genwqe_remove_pinnings(struct genwqe_file *cfile)
|
||||
|
||||
/**
|
||||
* genwqe_kill_fasync() - Send signal to all processes with open GenWQE files
|
||||
* @cd: GenWQE device information
|
||||
* @sig: Signal to send out
|
||||
*
|
||||
* E.g. genwqe_send_signal(cd, SIGIO);
|
||||
*/
|
||||
@ -380,6 +383,7 @@ static void genwqe_vma_open(struct vm_area_struct *vma)
|
||||
|
||||
/**
|
||||
* genwqe_vma_close() - Called each time when vma is unmapped
|
||||
* @vma: VMA area to close
|
||||
*
|
||||
* Free memory which got allocated by GenWQE mmap().
|
||||
*/
|
||||
@ -416,6 +420,8 @@ static const struct vm_operations_struct genwqe_vma_ops = {
|
||||
|
||||
/**
|
||||
* genwqe_mmap() - Provide contignous buffers to userspace
|
||||
* @filp: File pointer (unused)
|
||||
* @vma: VMA area to map
|
||||
*
|
||||
* We use mmap() to allocate contignous buffers used for DMA
|
||||
* transfers. After the buffer is allocated we remap it to user-space
|
||||
@ -484,16 +490,15 @@ static int genwqe_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define FLASH_BLOCK 0x40000 /* we use 256k blocks */
|
||||
|
||||
/**
|
||||
* do_flash_update() - Excute flash update (write image or CVPD)
|
||||
* @cd: genwqe device
|
||||
* @cfile: Descriptor of opened file
|
||||
* @load: details about image load
|
||||
*
|
||||
* Return: 0 if successful
|
||||
*/
|
||||
|
||||
#define FLASH_BLOCK 0x40000 /* we use 256k blocks */
|
||||
|
||||
static int do_flash_update(struct genwqe_file *cfile,
|
||||
struct genwqe_bitstream *load)
|
||||
{
|
||||
@ -820,6 +825,8 @@ static int genwqe_unpin_mem(struct genwqe_file *cfile, struct genwqe_mem *m)
|
||||
|
||||
/**
|
||||
* ddcb_cmd_cleanup() - Remove dynamically created fixup entries
|
||||
* @cfile: Descriptor of opened file
|
||||
* @req: DDCB work request
|
||||
*
|
||||
* Only if there are any. Pinnings are not removed.
|
||||
*/
|
||||
@ -844,6 +851,8 @@ static int ddcb_cmd_cleanup(struct genwqe_file *cfile, struct ddcb_requ *req)
|
||||
|
||||
/**
|
||||
* ddcb_cmd_fixups() - Establish DMA fixups/sglists for user memory references
|
||||
* @cfile: Descriptor of opened file
|
||||
* @req: DDCB work request
|
||||
*
|
||||
* Before the DDCB gets executed we need to handle the fixups. We
|
||||
* replace the user-space addresses with DMA addresses or do
|
||||
@ -974,6 +983,8 @@ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req)
|
||||
|
||||
/**
|
||||
* genwqe_execute_ddcb() - Execute DDCB using userspace address fixups
|
||||
* @cfile: Descriptor of opened file
|
||||
* @cmd: Command identifier (passed from user)
|
||||
*
|
||||
* The code will build up the translation tables or lookup the
|
||||
* contignous memory allocation table to find the right translations
|
||||
@ -1339,6 +1350,7 @@ static int genwqe_inform_and_stop_processes(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_device_remove() - Remove genwqe's char device
|
||||
* @cd: GenWQE device information
|
||||
*
|
||||
* This function must be called after the client devices are removed
|
||||
* because it will free the major/minor number range for the genwqe
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
/*
|
||||
* IBM Accelerator Family 'GenWQE'
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2013
|
||||
@ -129,7 +129,7 @@ static ssize_t base_clock_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(base_clock);
|
||||
|
||||
/**
|
||||
/*
|
||||
* curr_bitstream_show() - Show the current bitstream id
|
||||
*
|
||||
* There is a bug in some old versions of the CPLD which selects the
|
||||
@ -156,7 +156,7 @@ static ssize_t curr_bitstream_show(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RO(curr_bitstream);
|
||||
|
||||
/**
|
||||
/*
|
||||
* next_bitstream_show() - Show the next activated bitstream
|
||||
*
|
||||
* IO_SLC_CFGREG_SOFTRESET: This register can only be accessed by the PF.
|
||||
@ -260,7 +260,7 @@ static struct attribute *genwqe_normal_attributes[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* genwqe_is_visible() - Determine if sysfs attribute should be visible or not
|
||||
*
|
||||
* VFs have restricted mmio capabilities, so not all sysfs entries
|
||||
|
@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/**
|
||||
/*
|
||||
* IBM Accelerator Family 'GenWQE'
|
||||
*
|
||||
* (C) Copyright IBM Corp. 2013
|
||||
@ -129,6 +129,9 @@ u32 __genwqe_readl(struct genwqe_dev *cd, u64 byte_offs)
|
||||
|
||||
/**
|
||||
* genwqe_read_app_id() - Extract app_id
|
||||
* @cd: genwqe device descriptor
|
||||
* @app_name: carrier used to pass-back name
|
||||
* @len: length of data for name
|
||||
*
|
||||
* app_unitcfg need to be filled with valid data first
|
||||
*/
|
||||
@ -183,7 +186,7 @@ void genwqe_init_crc32(void)
|
||||
* @init: initial crc (0xffffffff at start)
|
||||
*
|
||||
* polynomial = x^32 * + x^29 + x^18 + x^14 + x^3 + 1 (0x20044009)
|
||||
|
||||
*
|
||||
* Example: 4 bytes 0x01 0x02 0x03 0x04 with init=0xffffffff should
|
||||
* result in a crc32 of 0xf33cb7d3.
|
||||
*
|
||||
@ -277,7 +280,7 @@ static int genwqe_sgl_size(int num_pages)
|
||||
return roundup(len, PAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* genwqe_alloc_sync_sgl() - Allocate memory for sgl and overlapping pages
|
||||
*
|
||||
* Allocates memory for sgl and overlapping pages. Pages which might
|
||||
@ -460,6 +463,8 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
|
||||
|
||||
/**
|
||||
* genwqe_free_sync_sgl() - Free memory for sgl and overlapping pages
|
||||
* @cd: genwqe device descriptor
|
||||
* @sgl: scatter gather list describing user-space memory
|
||||
*
|
||||
* After the DMA transfer has been completed we free the memory for
|
||||
* the sgl and the cached pages. Data is being transferred from cached
|
||||
@ -710,6 +715,7 @@ int genwqe_read_softreset(struct genwqe_dev *cd)
|
||||
/**
|
||||
* genwqe_set_interrupt_capability() - Configure MSI capability structure
|
||||
* @cd: pointer to the device
|
||||
* @count: number of vectors to allocate
|
||||
* Return: 0 if no error
|
||||
*/
|
||||
int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count)
|
||||
@ -738,7 +744,7 @@ void genwqe_reset_interrupt_capability(struct genwqe_dev *cd)
|
||||
* @i: index to desired entry
|
||||
* @m: maximum possible entries
|
||||
* @addr: addr which is read
|
||||
* @index: index in debug array
|
||||
* @idx: index in debug array
|
||||
* @val: read value
|
||||
*/
|
||||
static int set_reg_idx(struct genwqe_dev *cd, struct genwqe_reg *r,
|
||||
@ -818,6 +824,8 @@ int genwqe_read_ffdc_regs(struct genwqe_dev *cd, struct genwqe_reg *regs,
|
||||
|
||||
/**
|
||||
* genwqe_ffdc_buff_size() - Calculates the number of dump registers
|
||||
* @cd: genwqe device descriptor
|
||||
* @uid: unit ID
|
||||
*/
|
||||
int genwqe_ffdc_buff_size(struct genwqe_dev *cd, int uid)
|
||||
{
|
||||
@ -871,6 +879,10 @@ int genwqe_ffdc_buff_size(struct genwqe_dev *cd, int uid)
|
||||
|
||||
/**
|
||||
* genwqe_ffdc_buff_read() - Implements LogoutExtendedErrorRegisters procedure
|
||||
* @cd: genwqe device descriptor
|
||||
* @uid: unit ID
|
||||
* @regs: register information
|
||||
* @max_regs: number of register entries
|
||||
*/
|
||||
int genwqe_ffdc_buff_read(struct genwqe_dev *cd, int uid,
|
||||
struct genwqe_reg *regs, unsigned int max_regs)
|
||||
@ -956,6 +968,10 @@ int genwqe_ffdc_buff_read(struct genwqe_dev *cd, int uid,
|
||||
|
||||
/**
|
||||
* genwqe_write_vreg() - Write register in virtual window
|
||||
* @cd: genwqe device descriptor
|
||||
* @reg: register (byte) offset within BAR
|
||||
* @val: value to write
|
||||
* @func: PCI virtual function
|
||||
*
|
||||
* Note, these registers are only accessible to the PF through the
|
||||
* VF-window. It is not intended for the VF to access.
|
||||
@ -969,6 +985,9 @@ int genwqe_write_vreg(struct genwqe_dev *cd, u32 reg, u64 val, int func)
|
||||
|
||||
/**
|
||||
* genwqe_read_vreg() - Read register in virtual window
|
||||
* @cd: genwqe device descriptor
|
||||
* @reg: register (byte) offset within BAR
|
||||
* @func: PCI virtual function
|
||||
*
|
||||
* Note, these registers are only accessible to the PF through the
|
||||
* VF-window. It is not intended for the VF to access.
|
||||
@ -981,6 +1000,7 @@ u64 genwqe_read_vreg(struct genwqe_dev *cd, u32 reg, int func)
|
||||
|
||||
/**
|
||||
* genwqe_base_clock_frequency() - Deteremine base clock frequency of the card
|
||||
* @cd: genwqe device descriptor
|
||||
*
|
||||
* Note: From a design perspective it turned out to be a bad idea to
|
||||
* use codes here to specifiy the frequency/speed values. An old
|
||||
@ -1005,6 +1025,7 @@ int genwqe_base_clock_frequency(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_stop_traps() - Stop traps
|
||||
* @cd: genwqe device descriptor
|
||||
*
|
||||
* Before reading out the analysis data, we need to stop the traps.
|
||||
*/
|
||||
@ -1015,6 +1036,7 @@ void genwqe_stop_traps(struct genwqe_dev *cd)
|
||||
|
||||
/**
|
||||
* genwqe_start_traps() - Start traps
|
||||
* @cd: genwqe device descriptor
|
||||
*
|
||||
* After having read the data, we can/must enable the traps again.
|
||||
*/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user