mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-19 20:05:08 +00:00
SoC: driver updates for 6.8
A new drivers/cache/ subsystem is added to contain drivers for abstracting cache flush methods on riscv and potentially others, as this is needed for handling non-coherent DMA but several SoCs require nonstandard hardware methods for it. op-tee gains support for asynchronous notification with FF-A, as well as support for a system thread for executing in secure world. The tee, reset, bus, memory and scmi subsystems have a couple of minor updates. Platform specific soc driver changes include: - Samsung Exynos gains driver support for Google GS101 (Tensor G1) across multiple subsystems - Qualcomm Snapdragon gains support for SM8650 and X1E along with added features for some other SoCs - Mediatek adds support for "Smart Voltage Scaling" on MT8186 and MT8195, and driver support for MT8188 along with some code refactoring. - Microchip Polarfire FPGA support for "Auto Update" of the FPGA bitstream - Apple M1 mailbox driver is rewritten into a SoC driver - minor updates on amlogic, mvebu, ti, zynq, imx, renesas and hisilicon -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmWeypsACgkQYKtH/8kJ UifCpxAA0CMZRXKZOuTw9we2eS9rCy5nBrJsDiEAi9UPgQYUIrD7BVng+PAMN5UD AeEDEjUEmZ+a4hyDDPxwdlhI2qIvIITAZ1qbwcElXvt41MTIyo+1BK+kI6A7oxHd oPh9kG0yRjb5tNc6utrHbXpEb6AxfXYcdAOzA2YRonqKohYUJlGqHtAub2Dqd6FD nuYXGXSZKWMpd0L1X7nuD8+uBj8DbQgq0HfhiAj3vUgzwkYk/SlTo/DYByJOQeMA HE1X/vG7qwrdHC4VNXaiJJ/GQ6ZXAZXdK+F97v+FtfClPVuxAffMlTbb6t/CyiVb 4HrVzduyNMlIh8OqxLXabXJ0iJ970wkuPlOZy2pZmgkV5oKGSXSGxXWAwMvOmCVO RSgetXYHX3gDGQ59Si+LsEQhORdChMMik5nBPdyxj1UK3QsObV40qLpHBae7GWnA Qb6+3FrtnbiHfOMxGmhC4lqDfgSfByW1BspxsFyy33wb+TPfYJzOnXYe8aYTZ1iw GSuWNa/uHF61Q2v0d3Lt09GhUh9wWradnJ+caxpB0B0MHG2QQqFI8EVwIEn1/spu bWpItLT8UUDgNx+F9KRzP3HqwqbDzd9fnojSPescTzudpvpP9MC5X3w05pQ6iA1x HFJ+2J/ENvDAHWSAySn7Qx4JKSeLxm1YcquXQW2sVTVwFTkqigw= =4bKY -----END PGP SIGNATURE----- Merge tag 'soc-drivers-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc Pull SoC driver updates from Arnd Bergmann: "A new drivers/cache/ subsystem is added to contain drivers for abstracting cache flush methods on riscv and potentially others, as this is needed for handling non-coherent DMA but several SoCs require nonstandard hardware methods for it. op-tee gains support for asynchronous notification with FF-A, as well as support for a system thread for executing in secure world. The tee, reset, bus, memory and scmi subsystems have a couple of minor updates. Platform specific soc driver changes include: - Samsung Exynos gains driver support for Google GS101 (Tensor G1) across multiple subsystems - Qualcomm Snapdragon gains support for SM8650 and X1E along with added features for some other SoCs - Mediatek adds support for "Smart Voltage Scaling" on MT8186 and MT8195, and driver support for MT8188 along with some code refactoring. - Microchip Polarfire FPGA support for "Auto Update" of the FPGA bitstream - Apple M1 mailbox driver is rewritten into a SoC driver - minor updates on amlogic, mvebu, ti, zynq, imx, renesas and hisilicon" * tag 'soc-drivers-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (189 commits) memory: ti-emif-pm: Convert to platform remove callback returning void memory: ti-aemif: Convert to platform remove callback returning void memory: tegra210-emc: Convert to platform remove callback returning void memory: tegra186-emc: Convert to platform remove callback returning void memory: stm32-fmc2-ebi: Convert to platform remove callback returning void memory: exynos5422-dmc: Convert to platform remove callback returning void memory: renesas-rpc-if: Convert to platform remove callback returning void memory: omap-gpmc: Convert to platform remove callback returning void memory: mtk-smi: Convert to platform remove callback returning void memory: jz4780-nemc: Convert to platform remove callback returning void memory: fsl_ifc: Convert to platform remove callback returning void memory: fsl-corenet-cf: Convert to platform remove callback returning void memory: emif: Convert to platform remove callback returning void memory: brcmstb_memc: Convert to platform remove callback returning void memory: brcmstb_dpfe: Convert to platform remove callback returning void soc: qcom: llcc: Fix LLCC_TRP_ATTR2_CFGn offset firmware: qcom: qseecom: fix memory leaks in error paths dt-bindings: clock: google,gs101: rename CMU_TOP gate defines soc: qcom: llcc: Fix typo in kernel-doc dt-bindings: soc: qcom,aoss-qmp: document the X1E80100 Always-On Subsystem side channel ...
This commit is contained in:
commit
f6597d1706
4
CREDITS
4
CREDITS
@ -1424,6 +1424,10 @@ S: University of Stellenbosch
|
|||||||
S: Stellenbosch, Western Cape
|
S: Stellenbosch, Western Cape
|
||||||
S: South Africa
|
S: South Africa
|
||||||
|
|
||||||
|
N: Andy Gross
|
||||||
|
E: agross@kernel.org
|
||||||
|
D: Qualcomm SoC subsystem and drivers
|
||||||
|
|
||||||
N: Grant Grundler
|
N: Grant Grundler
|
||||||
E: grantgrundler@gmail.com
|
E: grantgrundler@gmail.com
|
||||||
W: http://obmouse.sourceforge.net/
|
W: http://obmouse.sourceforge.net/
|
||||||
|
@ -3,7 +3,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/linked_full_lane
|
|||||||
What: /sys/devices/platform/HISI04Bx:00/chipX/crc_err_cnt
|
What: /sys/devices/platform/HISI04Bx:00/chipX/crc_err_cnt
|
||||||
Date: November 2023
|
Date: November 2023
|
||||||
KernelVersion: 6.6
|
KernelVersion: 6.6
|
||||||
Contact: Huisong Li <lihuisong@huawei.org>
|
Contact: Huisong Li <lihuisong@huawei.com>
|
||||||
Description:
|
Description:
|
||||||
The /sys/devices/platform/HISI04Bx:00/chipX/ directory
|
The /sys/devices/platform/HISI04Bx:00/chipX/ directory
|
||||||
contains read-only attributes exposing some summarization
|
contains read-only attributes exposing some summarization
|
||||||
@ -26,7 +26,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/linked_full_lane
|
|||||||
What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/crc_err_cnt
|
What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/crc_err_cnt
|
||||||
Date: November 2023
|
Date: November 2023
|
||||||
KernelVersion: 6.6
|
KernelVersion: 6.6
|
||||||
Contact: Huisong Li <lihuisong@huawei.org>
|
Contact: Huisong Li <lihuisong@huawei.com>
|
||||||
Description:
|
Description:
|
||||||
The /sys/devices/platform/HISI04Bx:00/chipX/dieY/ directory
|
The /sys/devices/platform/HISI04Bx:00/chipX/dieY/ directory
|
||||||
contains read-only attributes exposing some summarization
|
contains read-only attributes exposing some summarization
|
||||||
@ -54,7 +54,7 @@ What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/lane_mask
|
|||||||
What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/crc_err_cnt
|
What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/crc_err_cnt
|
||||||
Date: November 2023
|
Date: November 2023
|
||||||
KernelVersion: 6.6
|
KernelVersion: 6.6
|
||||||
Contact: Huisong Li <lihuisong@huawei.org>
|
Contact: Huisong Li <lihuisong@huawei.com>
|
||||||
Description:
|
Description:
|
||||||
The /sys/devices/platform/HISI04Bx/chipX/dieX/hccsN/ directory
|
The /sys/devices/platform/HISI04Bx/chipX/dieX/hccsN/ directory
|
||||||
contains read-only attributes exposing information about
|
contains read-only attributes exposing information about
|
||||||
|
@ -33,6 +33,8 @@ properties:
|
|||||||
- qcom,sm8350-llcc
|
- qcom,sm8350-llcc
|
||||||
- qcom,sm8450-llcc
|
- qcom,sm8450-llcc
|
||||||
- qcom,sm8550-llcc
|
- qcom,sm8550-llcc
|
||||||
|
- qcom,sm8650-llcc
|
||||||
|
- qcom,x1e80100-llcc
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
minItems: 2
|
minItems: 2
|
||||||
@ -104,6 +106,7 @@ allOf:
|
|||||||
- qcom,qdu1000-llcc
|
- qcom,qdu1000-llcc
|
||||||
- qcom,sc8180x-llcc
|
- qcom,sc8180x-llcc
|
||||||
- qcom,sc8280xp-llcc
|
- qcom,sc8280xp-llcc
|
||||||
|
- qcom,x1e80100-llcc
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
reg:
|
reg:
|
||||||
|
@ -38,7 +38,9 @@ properties:
|
|||||||
- sifive,fu740-c000-ccache
|
- sifive,fu740-c000-ccache
|
||||||
- const: cache
|
- const: cache
|
||||||
- items:
|
- items:
|
||||||
- const: starfive,jh7110-ccache
|
- enum:
|
||||||
|
- starfive,jh7100-ccache
|
||||||
|
- starfive,jh7110-ccache
|
||||||
- const: sifive,ccache0
|
- const: sifive,ccache0
|
||||||
- const: cache
|
- const: cache
|
||||||
- items:
|
- items:
|
||||||
@ -88,6 +90,7 @@ allOf:
|
|||||||
contains:
|
contains:
|
||||||
enum:
|
enum:
|
||||||
- sifive,fu740-c000-ccache
|
- sifive,fu740-c000-ccache
|
||||||
|
- starfive,jh7100-ccache
|
||||||
- starfive,jh7110-ccache
|
- starfive,jh7110-ccache
|
||||||
- microchip,mpfs-ccache
|
- microchip,mpfs-ccache
|
||||||
|
|
||||||
@ -111,6 +114,7 @@ allOf:
|
|||||||
contains:
|
contains:
|
||||||
enum:
|
enum:
|
||||||
- sifive,fu740-c000-ccache
|
- sifive,fu740-c000-ccache
|
||||||
|
- starfive,jh7100-ccache
|
||||||
- starfive,jh7110-ccache
|
- starfive,jh7110-ccache
|
||||||
|
|
||||||
then:
|
then:
|
||||||
|
@ -63,7 +63,9 @@ properties:
|
|||||||
- qcom,scm-sm8350
|
- qcom,scm-sm8350
|
||||||
- qcom,scm-sm8450
|
- qcom,scm-sm8450
|
||||||
- qcom,scm-sm8550
|
- qcom,scm-sm8550
|
||||||
|
- qcom,scm-sm8650
|
||||||
- qcom,scm-qcs404
|
- qcom,scm-qcs404
|
||||||
|
- qcom,scm-x1e80100
|
||||||
- const: qcom,scm
|
- const: qcom,scm
|
||||||
|
|
||||||
clocks:
|
clocks:
|
||||||
@ -178,21 +180,6 @@ allOf:
|
|||||||
minItems: 3
|
minItems: 3
|
||||||
maxItems: 3
|
maxItems: 3
|
||||||
|
|
||||||
# Interconnects
|
|
||||||
- if:
|
|
||||||
not:
|
|
||||||
properties:
|
|
||||||
compatible:
|
|
||||||
contains:
|
|
||||||
enum:
|
|
||||||
- qcom,scm-qdu1000
|
|
||||||
- qcom,scm-sc8280xp
|
|
||||||
- qcom,scm-sm8450
|
|
||||||
- qcom,scm-sm8550
|
|
||||||
then:
|
|
||||||
properties:
|
|
||||||
interconnects: false
|
|
||||||
|
|
||||||
# Interrupts
|
# Interrupts
|
||||||
- if:
|
- if:
|
||||||
not:
|
not:
|
||||||
@ -202,6 +189,7 @@ allOf:
|
|||||||
enum:
|
enum:
|
||||||
- qcom,scm-sm8450
|
- qcom,scm-sm8450
|
||||||
- qcom,scm-sm8550
|
- qcom,scm-sm8550
|
||||||
|
- qcom,scm-sm8650
|
||||||
then:
|
then:
|
||||||
properties:
|
properties:
|
||||||
interrupts: false
|
interrupts: false
|
||||||
|
@ -18,6 +18,7 @@ properties:
|
|||||||
- amlogic,meson-axg-reset # Reset Controller on AXG and compatible SoCs
|
- amlogic,meson-axg-reset # Reset Controller on AXG and compatible SoCs
|
||||||
- amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs
|
- amlogic,meson-a1-reset # Reset Controller on A1 and compatible SoCs
|
||||||
- amlogic,meson-s4-reset # Reset Controller on S4 and compatible SoCs
|
- amlogic,meson-s4-reset # Reset Controller on S4 and compatible SoCs
|
||||||
|
- amlogic,c3-reset # Reset Controller on C3 and compatible SoCs
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
@ -28,28 +28,17 @@ description: |
|
|||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
oneOf:
|
oneOf:
|
||||||
- const: "fsl,imx51-src"
|
- const: fsl,imx51-src
|
||||||
- items:
|
- items:
|
||||||
- const: "fsl,imx50-src"
|
- enum:
|
||||||
- const: "fsl,imx51-src"
|
- fsl,imx50-src
|
||||||
- items:
|
- fsl,imx53-src
|
||||||
- const: "fsl,imx53-src"
|
- fsl,imx6q-src
|
||||||
- const: "fsl,imx51-src"
|
- fsl,imx6sx-src
|
||||||
- items:
|
- fsl,imx6sl-src
|
||||||
- const: "fsl,imx6q-src"
|
- fsl,imx6ul-src
|
||||||
- const: "fsl,imx51-src"
|
- fsl,imx6sll-src
|
||||||
- items:
|
- const: fsl,imx51-src
|
||||||
- const: "fsl,imx6sx-src"
|
|
||||||
- const: "fsl,imx51-src"
|
|
||||||
- items:
|
|
||||||
- const: "fsl,imx6sl-src"
|
|
||||||
- const: "fsl,imx51-src"
|
|
||||||
- items:
|
|
||||||
- const: "fsl,imx6ul-src"
|
|
||||||
- const: "fsl,imx51-src"
|
|
||||||
- items:
|
|
||||||
- const: "fsl,imx6sll-src"
|
|
||||||
- const: "fsl,imx51-src"
|
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
@ -50,32 +50,9 @@ additionalProperties: false
|
|||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
#include <dt-bindings/interrupt-controller/irq.h>
|
iomcu_rst_controller {
|
||||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
|
||||||
#include <dt-bindings/clock/hi3660-clock.h>
|
|
||||||
|
|
||||||
iomcu: iomcu@ffd7e000 {
|
|
||||||
compatible = "hisilicon,hi3660-iomcu", "syscon";
|
|
||||||
reg = <0xffd7e000 0x1000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
iomcu_rst: iomcu_rst_controller {
|
|
||||||
compatible = "hisilicon,hi3660-reset";
|
compatible = "hisilicon,hi3660-reset";
|
||||||
hisilicon,rst-syscon = <&iomcu>;
|
hisilicon,rst-syscon = <&iomcu>;
|
||||||
#reset-cells = <2>;
|
#reset-cells = <2>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Specifying reset lines connected to IP modules */
|
|
||||||
i2c@ffd71000 {
|
|
||||||
compatible = "snps,designware-i2c";
|
|
||||||
reg = <0xffd71000 0x1000>;
|
|
||||||
interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
clock-frequency = <400000>;
|
|
||||||
clocks = <&crg_ctrl HI3660_CLK_GATE_I2C0>;
|
|
||||||
resets = <&iomcu_rst 0x20 3>;
|
|
||||||
pinctrl-names = "default";
|
|
||||||
pinctrl-0 = <&i2c0_pmx_func &i2c0_cfg_func>;
|
|
||||||
};
|
|
||||||
...
|
...
|
||||||
|
@ -18,17 +18,17 @@ properties:
|
|||||||
oneOf:
|
oneOf:
|
||||||
- description: on SC7180 SoCs the following compatibles must be specified
|
- description: on SC7180 SoCs the following compatibles must be specified
|
||||||
items:
|
items:
|
||||||
- const: "qcom,sc7180-aoss-cc"
|
- const: qcom,sc7180-aoss-cc
|
||||||
- const: "qcom,sdm845-aoss-cc"
|
- const: qcom,sdm845-aoss-cc
|
||||||
|
|
||||||
- description: on SC7280 SoCs the following compatibles must be specified
|
- description: on SC7280 SoCs the following compatibles must be specified
|
||||||
items:
|
items:
|
||||||
- const: "qcom,sc7280-aoss-cc"
|
- const: qcom,sc7280-aoss-cc
|
||||||
- const: "qcom,sdm845-aoss-cc"
|
- const: qcom,sdm845-aoss-cc
|
||||||
|
|
||||||
- description: on SDM845 SoCs the following compatibles must be specified
|
- description: on SDM845 SoCs the following compatibles must be specified
|
||||||
items:
|
items:
|
||||||
- const: "qcom,sdm845-aoss-cc"
|
- const: qcom,sdm845-aoss-cc
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
@ -18,16 +18,16 @@ properties:
|
|||||||
oneOf:
|
oneOf:
|
||||||
- description: on SC7180 SoCs the following compatibles must be specified
|
- description: on SC7180 SoCs the following compatibles must be specified
|
||||||
items:
|
items:
|
||||||
- const: "qcom,sc7180-pdc-global"
|
- const: qcom,sc7180-pdc-global
|
||||||
- const: "qcom,sdm845-pdc-global"
|
- const: qcom,sdm845-pdc-global
|
||||||
|
|
||||||
- description: on SC7280 SoCs the following compatibles must be specified
|
- description: on SC7280 SoCs the following compatibles must be specified
|
||||||
items:
|
items:
|
||||||
- const: "qcom,sc7280-pdc-global"
|
- const: qcom,sc7280-pdc-global
|
||||||
|
|
||||||
- description: on SDM845 SoCs the following compatibles must be specified
|
- description: on SDM845 SoCs the following compatibles must be specified
|
||||||
items:
|
items:
|
||||||
- const: "qcom,sdm845-pdc-global"
|
- const: qcom,sdm845-pdc-global
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
@ -17,7 +17,7 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
items:
|
items:
|
||||||
- enum:
|
- enum:
|
||||||
- renesas,r9a07g043-usbphy-ctrl # RZ/G2UL
|
- renesas,r9a07g043-usbphy-ctrl # RZ/G2UL and RZ/Five
|
||||||
- renesas,r9a07g044-usbphy-ctrl # RZ/G2{L,LC}
|
- renesas,r9a07g044-usbphy-ctrl # RZ/G2{L,LC}
|
||||||
- renesas,r9a07g054-usbphy-ctrl # RZ/V2L
|
- renesas,r9a07g054-usbphy-ctrl # RZ/V2L
|
||||||
- const: renesas,rzg2l-usbphy-ctrl
|
- const: renesas,rzg2l-usbphy-ctrl
|
||||||
|
@ -21,6 +21,7 @@ properties:
|
|||||||
- enum:
|
- enum:
|
||||||
- apple,s5l-uart
|
- apple,s5l-uart
|
||||||
- axis,artpec8-uart
|
- axis,artpec8-uart
|
||||||
|
- google,gs101-uart
|
||||||
- samsung,s3c6400-uart
|
- samsung,s3c6400-uart
|
||||||
- samsung,s5pv210-uart
|
- samsung,s5pv210-uart
|
||||||
- samsung,exynos4210-uart
|
- samsung,exynos4210-uart
|
||||||
@ -133,6 +134,16 @@ allOf:
|
|||||||
- const: uart
|
- const: uart
|
||||||
- const: clk_uart_baud0
|
- const: clk_uart_baud0
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- google,gs101-uart
|
||||||
|
then:
|
||||||
|
required:
|
||||||
|
- samsung,uart-fifosize
|
||||||
|
|
||||||
unevaluatedProperties: false
|
unevaluatedProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
|
@ -26,6 +26,16 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
const: microchip,mpfs-sys-controller
|
const: microchip,mpfs-sys-controller
|
||||||
|
|
||||||
|
microchip,bitstream-flash:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description:
|
||||||
|
The SPI flash connected to the system controller's QSPI controller.
|
||||||
|
The system controller may retrieve FPGA bitstreams from this flash to
|
||||||
|
perform In-Application Programming (IAP) or during device initialisation
|
||||||
|
for Auto Update. The MSS and system controller have separate QSPI
|
||||||
|
controllers and this flash is connected to both. Software running in the
|
||||||
|
MSS can write bitstreams to the flash.
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- mboxes
|
- mboxes
|
||||||
|
@ -38,6 +38,8 @@ properties:
|
|||||||
- qcom,sm8350-aoss-qmp
|
- qcom,sm8350-aoss-qmp
|
||||||
- qcom,sm8450-aoss-qmp
|
- qcom,sm8450-aoss-qmp
|
||||||
- qcom,sm8550-aoss-qmp
|
- qcom,sm8550-aoss-qmp
|
||||||
|
- qcom,sm8650-aoss-qmp
|
||||||
|
- qcom,x1e80100-aoss-qmp
|
||||||
- const: qcom,aoss-qmp
|
- const: qcom,aoss-qmp
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
|
@ -20,14 +20,20 @@ description:
|
|||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
items:
|
oneOf:
|
||||||
- enum:
|
- items:
|
||||||
- qcom,sc8180x-pmic-glink
|
- enum:
|
||||||
- qcom,sc8280xp-pmic-glink
|
- qcom,sc8180x-pmic-glink
|
||||||
- qcom,sm8350-pmic-glink
|
- qcom,sc8280xp-pmic-glink
|
||||||
- qcom,sm8450-pmic-glink
|
- qcom,sm8350-pmic-glink
|
||||||
- qcom,sm8550-pmic-glink
|
- qcom,sm8450-pmic-glink
|
||||||
- const: qcom,pmic-glink
|
- qcom,sm8550-pmic-glink
|
||||||
|
- const: qcom,pmic-glink
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- qcom,sm8650-pmic-glink
|
||||||
|
- const: qcom,sm8550-pmic-glink
|
||||||
|
- const: qcom,pmic-glink
|
||||||
|
|
||||||
'#address-cells':
|
'#address-cells':
|
||||||
const: 1
|
const: 1
|
||||||
|
@ -31,10 +31,24 @@ properties:
|
|||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
qcom,qmp:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
|
description: Reference to the AOSS side-channel message RAM
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
- reg
|
- reg
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- if:
|
||||||
|
not:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: qcom,rpmh-stats
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
qcom,qmp: false
|
||||||
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
|
@ -25,6 +25,7 @@ properties:
|
|||||||
oneOf:
|
oneOf:
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
- google,gs101-usi
|
||||||
- samsung,exynosautov9-usi
|
- samsung,exynosautov9-usi
|
||||||
- samsung,exynosautov920-usi
|
- samsung,exynosautov920-usi
|
||||||
- const: samsung,exynos850-usi
|
- const: samsung,exynos850-usi
|
||||||
|
@ -18,6 +18,7 @@ properties:
|
|||||||
compatible:
|
compatible:
|
||||||
oneOf:
|
oneOf:
|
||||||
- enum:
|
- enum:
|
||||||
|
- google,gs101-wdt # for Google gs101
|
||||||
- samsung,s3c2410-wdt # for S3C2410
|
- samsung,s3c2410-wdt # for S3C2410
|
||||||
- samsung,s3c6410-wdt # for S3C6410, S5PV210 and Exynos4
|
- samsung,s3c6410-wdt # for S3C6410, S5PV210 and Exynos4
|
||||||
- samsung,exynos5250-wdt # for Exynos5250
|
- samsung,exynos5250-wdt # for Exynos5250
|
||||||
@ -47,13 +48,14 @@ properties:
|
|||||||
samsung,cluster-index:
|
samsung,cluster-index:
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
description:
|
description:
|
||||||
Index of CPU cluster on which watchdog is running (in case of Exynos850)
|
Index of CPU cluster on which watchdog is running (in case of Exynos850
|
||||||
|
or Google gs101).
|
||||||
|
|
||||||
samsung,syscon-phandle:
|
samsung,syscon-phandle:
|
||||||
$ref: /schemas/types.yaml#/definitions/phandle
|
$ref: /schemas/types.yaml#/definitions/phandle
|
||||||
description:
|
description:
|
||||||
Phandle to the PMU system controller node (in case of Exynos5250,
|
Phandle to the PMU system controller node (in case of Exynos5250,
|
||||||
Exynos5420, Exynos7 and Exynos850).
|
Exynos5420, Exynos7, Exynos850 and gs101).
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
@ -69,6 +71,7 @@ allOf:
|
|||||||
compatible:
|
compatible:
|
||||||
contains:
|
contains:
|
||||||
enum:
|
enum:
|
||||||
|
- google,gs101-wdt
|
||||||
- samsung,exynos5250-wdt
|
- samsung,exynos5250-wdt
|
||||||
- samsung,exynos5420-wdt
|
- samsung,exynos5420-wdt
|
||||||
- samsung,exynos7-wdt
|
- samsung,exynos7-wdt
|
||||||
@ -82,6 +85,7 @@ allOf:
|
|||||||
compatible:
|
compatible:
|
||||||
contains:
|
contains:
|
||||||
enum:
|
enum:
|
||||||
|
- google,gs101-wdt
|
||||||
- samsung,exynos850-wdt
|
- samsung,exynos850-wdt
|
||||||
- samsung,exynosautov9-wdt
|
- samsung,exynosautov9-wdt
|
||||||
then:
|
then:
|
||||||
|
18
MAINTAINERS
18
MAINTAINERS
@ -1931,7 +1931,6 @@ F: drivers/i2c/busses/i2c-pasemi-platform.c
|
|||||||
F: drivers/iommu/apple-dart.c
|
F: drivers/iommu/apple-dart.c
|
||||||
F: drivers/iommu/io-pgtable-dart.c
|
F: drivers/iommu/io-pgtable-dart.c
|
||||||
F: drivers/irqchip/irq-apple-aic.c
|
F: drivers/irqchip/irq-apple-aic.c
|
||||||
F: drivers/mailbox/apple-mailbox.c
|
|
||||||
F: drivers/nvme/host/apple.c
|
F: drivers/nvme/host/apple.c
|
||||||
F: drivers/nvmem/apple-efuses.c
|
F: drivers/nvmem/apple-efuses.c
|
||||||
F: drivers/pinctrl/pinctrl-apple-gpio.c
|
F: drivers/pinctrl/pinctrl-apple-gpio.c
|
||||||
@ -1940,7 +1939,6 @@ F: drivers/soc/apple/*
|
|||||||
F: drivers/watchdog/apple_wdt.c
|
F: drivers/watchdog/apple_wdt.c
|
||||||
F: include/dt-bindings/interrupt-controller/apple-aic.h
|
F: include/dt-bindings/interrupt-controller/apple-aic.h
|
||||||
F: include/dt-bindings/pinctrl/apple.h
|
F: include/dt-bindings/pinctrl/apple.h
|
||||||
F: include/linux/apple-mailbox.h
|
|
||||||
F: include/linux/soc/apple/*
|
F: include/linux/soc/apple/*
|
||||||
|
|
||||||
ARM/ARTPEC MACHINE SUPPORT
|
ARM/ARTPEC MACHINE SUPPORT
|
||||||
@ -2544,7 +2542,6 @@ F: arch/arm64/boot/dts/qcom/sc7280*
|
|||||||
F: arch/arm64/boot/dts/qcom/sdm845-cheza*
|
F: arch/arm64/boot/dts/qcom/sdm845-cheza*
|
||||||
|
|
||||||
ARM/QUALCOMM SUPPORT
|
ARM/QUALCOMM SUPPORT
|
||||||
M: Andy Gross <agross@kernel.org>
|
|
||||||
M: Bjorn Andersson <andersson@kernel.org>
|
M: Bjorn Andersson <andersson@kernel.org>
|
||||||
M: Konrad Dybcio <konrad.dybcio@linaro.org>
|
M: Konrad Dybcio <konrad.dybcio@linaro.org>
|
||||||
L: linux-arm-msm@vger.kernel.org
|
L: linux-arm-msm@vger.kernel.org
|
||||||
@ -18644,6 +18641,7 @@ F: Documentation/devicetree/bindings/usb/microchip,mpfs-musb.yaml
|
|||||||
F: arch/riscv/boot/dts/microchip/
|
F: arch/riscv/boot/dts/microchip/
|
||||||
F: drivers/char/hw_random/mpfs-rng.c
|
F: drivers/char/hw_random/mpfs-rng.c
|
||||||
F: drivers/clk/microchip/clk-mpfs*.c
|
F: drivers/clk/microchip/clk-mpfs*.c
|
||||||
|
F: drivers/firmware/microchip/mpfs-auto-update.c
|
||||||
F: drivers/i2c/busses/i2c-microchip-corei2c.c
|
F: drivers/i2c/busses/i2c-microchip-corei2c.c
|
||||||
F: drivers/mailbox/mailbox-mpfs.c
|
F: drivers/mailbox/mailbox-mpfs.c
|
||||||
F: drivers/pci/controller/pcie-microchip-host.c
|
F: drivers/pci/controller/pcie-microchip-host.c
|
||||||
@ -19779,6 +19777,13 @@ S: Supported
|
|||||||
N: sifive
|
N: sifive
|
||||||
K: [^@]sifive
|
K: [^@]sifive
|
||||||
|
|
||||||
|
SIFIVE CACHE DRIVER
|
||||||
|
M: Conor Dooley <conor@kernel.org>
|
||||||
|
L: linux-riscv@lists.infradead.org
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/devicetree/bindings/cache/sifive,ccache0.yaml
|
||||||
|
F: drivers/cache/sifive_ccache.c
|
||||||
|
|
||||||
SIFIVE FU540 SYSTEM-ON-CHIP
|
SIFIVE FU540 SYSTEM-ON-CHIP
|
||||||
M: Paul Walmsley <paul.walmsley@sifive.com>
|
M: Paul Walmsley <paul.walmsley@sifive.com>
|
||||||
M: Palmer Dabbelt <palmer@dabbelt.com>
|
M: Palmer Dabbelt <palmer@dabbelt.com>
|
||||||
@ -19794,13 +19799,6 @@ S: Maintained
|
|||||||
F: Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
|
F: Documentation/devicetree/bindings/dma/sifive,fu540-c000-pdma.yaml
|
||||||
F: drivers/dma/sf-pdma/
|
F: drivers/dma/sf-pdma/
|
||||||
|
|
||||||
SIFIVE SOC DRIVERS
|
|
||||||
M: Conor Dooley <conor@kernel.org>
|
|
||||||
L: linux-riscv@lists.infradead.org
|
|
||||||
S: Maintained
|
|
||||||
T: git https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/
|
|
||||||
F: Documentation/devicetree/bindings/cache/sifive,ccache0.yaml
|
|
||||||
F: drivers/soc/sifive/
|
|
||||||
|
|
||||||
SILEAD TOUCHSCREEN DRIVER
|
SILEAD TOUCHSCREEN DRIVER
|
||||||
M: Hans de Goede <hdegoede@redhat.com>
|
M: Hans de Goede <hdegoede@redhat.com>
|
||||||
|
@ -53,6 +53,25 @@ config ERRATA_SIFIVE_CIP_1200
|
|||||||
|
|
||||||
If you don't know what to do here, say "Y".
|
If you don't know what to do here, say "Y".
|
||||||
|
|
||||||
|
config ERRATA_STARFIVE_JH7100
|
||||||
|
bool "StarFive JH7100 support"
|
||||||
|
depends on ARCH_STARFIVE
|
||||||
|
depends on !DMA_DIRECT_REMAP
|
||||||
|
depends on NONPORTABLE
|
||||||
|
select DMA_GLOBAL_POOL
|
||||||
|
select RISCV_DMA_NONCOHERENT
|
||||||
|
select RISCV_NONSTANDARD_CACHE_OPS
|
||||||
|
select SIFIVE_CCACHE
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
The StarFive JH7100 was a test chip for the JH7110 and has
|
||||||
|
caches that are non-coherent with respect to peripheral DMAs.
|
||||||
|
It was designed before the Zicbom extension so needs non-standard
|
||||||
|
cache operations through the SiFive cache controller.
|
||||||
|
|
||||||
|
Say "Y" if you want to support the BeagleV Starlight and/or
|
||||||
|
StarFive VisionFive V1 boards.
|
||||||
|
|
||||||
config ERRATA_THEAD
|
config ERRATA_THEAD
|
||||||
bool "T-HEAD errata"
|
bool "T-HEAD errata"
|
||||||
depends on RISCV_ALTERNATIVE
|
depends on RISCV_ALTERNATIVE
|
||||||
|
@ -1167,14 +1167,11 @@ error_cleanup_mc_io:
|
|||||||
* fsl_mc_bus_remove - callback invoked when the root MC bus is being
|
* fsl_mc_bus_remove - callback invoked when the root MC bus is being
|
||||||
* removed
|
* removed
|
||||||
*/
|
*/
|
||||||
static int fsl_mc_bus_remove(struct platform_device *pdev)
|
static void fsl_mc_bus_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct fsl_mc *mc = platform_get_drvdata(pdev);
|
struct fsl_mc *mc = platform_get_drvdata(pdev);
|
||||||
struct fsl_mc_io *mc_io;
|
struct fsl_mc_io *mc_io;
|
||||||
|
|
||||||
if (!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mc_io = mc->root_mc_bus_dev->mc_io;
|
mc_io = mc->root_mc_bus_dev->mc_io;
|
||||||
fsl_mc_device_remove(mc->root_mc_bus_dev);
|
fsl_mc_device_remove(mc->root_mc_bus_dev);
|
||||||
fsl_destroy_mc_io(mc_io);
|
fsl_destroy_mc_io(mc_io);
|
||||||
@ -1190,13 +1187,6 @@ static int fsl_mc_bus_remove(struct platform_device *pdev)
|
|||||||
(GCR1_P1_STOP | GCR1_P2_STOP),
|
(GCR1_P1_STOP | GCR1_P2_STOP),
|
||||||
mc->fsl_mc_regs + FSL_MC_GCR1);
|
mc->fsl_mc_regs + FSL_MC_GCR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void fsl_mc_bus_shutdown(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
fsl_mc_bus_remove(pdev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id fsl_mc_bus_match_table[] = {
|
static const struct of_device_id fsl_mc_bus_match_table[] = {
|
||||||
@ -1220,8 +1210,8 @@ static struct platform_driver fsl_mc_bus_driver = {
|
|||||||
.acpi_match_table = fsl_mc_bus_acpi_match_table,
|
.acpi_match_table = fsl_mc_bus_acpi_match_table,
|
||||||
},
|
},
|
||||||
.probe = fsl_mc_bus_probe,
|
.probe = fsl_mc_bus_probe,
|
||||||
.remove = fsl_mc_bus_remove,
|
.remove_new = fsl_mc_bus_remove,
|
||||||
.shutdown = fsl_mc_bus_shutdown,
|
.shutdown = fsl_mc_bus_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int fsl_mc_bus_notifier(struct notifier_block *nb,
|
static int fsl_mc_bus_notifier(struct notifier_block *nb,
|
||||||
|
@ -657,7 +657,7 @@ static int hisi_lpc_probe(struct platform_device *pdev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hisi_lpc_remove(struct platform_device *pdev)
|
static void hisi_lpc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev);
|
struct hisi_lpc_dev *lpcdev = dev_get_drvdata(dev);
|
||||||
@ -669,8 +669,6 @@ static int hisi_lpc_remove(struct platform_device *pdev)
|
|||||||
of_platform_depopulate(dev);
|
of_platform_depopulate(dev);
|
||||||
|
|
||||||
logic_pio_unregister_range(range);
|
logic_pio_unregister_range(range);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id hisi_lpc_of_match[] = {
|
static const struct of_device_id hisi_lpc_of_match[] = {
|
||||||
@ -691,6 +689,6 @@ static struct platform_driver hisi_lpc_driver = {
|
|||||||
.acpi_match_table = hisi_lpc_acpi_match,
|
.acpi_match_table = hisi_lpc_acpi_match,
|
||||||
},
|
},
|
||||||
.probe = hisi_lpc_probe,
|
.probe = hisi_lpc_probe,
|
||||||
.remove = hisi_lpc_remove,
|
.remove_new = hisi_lpc_remove,
|
||||||
};
|
};
|
||||||
builtin_platform_driver(hisi_lpc_driver);
|
builtin_platform_driver(hisi_lpc_driver);
|
||||||
|
@ -11,7 +11,10 @@
|
|||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/property.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
@ -202,9 +205,7 @@ static int weim_timing_setup(struct device *dev, struct device_node *np,
|
|||||||
|
|
||||||
static int weim_parse_dt(struct platform_device *pdev)
|
static int weim_parse_dt(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const struct of_device_id *of_id = of_match_device(weim_id_table,
|
const struct imx_weim_devtype *devtype = device_get_match_data(&pdev->dev);
|
||||||
&pdev->dev);
|
|
||||||
const struct imx_weim_devtype *devtype = of_id->data;
|
|
||||||
int ret = 0, have_child = 0;
|
int ret = 0, have_child = 0;
|
||||||
struct device_node *child;
|
struct device_node *child;
|
||||||
struct weim_priv *priv;
|
struct weim_priv *priv;
|
||||||
|
@ -755,7 +755,7 @@ static int moxtet_irq_setup(struct moxtet *moxtet)
|
|||||||
moxtet->irq.masked = ~0;
|
moxtet->irq.masked = ~0;
|
||||||
|
|
||||||
ret = request_threaded_irq(moxtet->dev_irq, NULL, moxtet_irq_thread_fn,
|
ret = request_threaded_irq(moxtet->dev_irq, NULL, moxtet_irq_thread_fn,
|
||||||
IRQF_ONESHOT, "moxtet", moxtet);
|
IRQF_SHARED | IRQF_ONESHOT, "moxtet", moxtet);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
|
|
||||||
@ -830,6 +830,12 @@ static void moxtet_remove(struct spi_device *spi)
|
|||||||
mutex_destroy(&moxtet->lock);
|
mutex_destroy(&moxtet->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct spi_device_id moxtet_spi_ids[] = {
|
||||||
|
{ "moxtet" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(spi, moxtet_spi_ids);
|
||||||
|
|
||||||
static const struct of_device_id moxtet_dt_ids[] = {
|
static const struct of_device_id moxtet_dt_ids[] = {
|
||||||
{ .compatible = "cznic,moxtet" },
|
{ .compatible = "cznic,moxtet" },
|
||||||
{},
|
{},
|
||||||
@ -841,6 +847,7 @@ static struct spi_driver moxtet_spi_driver = {
|
|||||||
.name = "moxtet",
|
.name = "moxtet",
|
||||||
.of_match_table = moxtet_dt_ids,
|
.of_match_table = moxtet_dt_ids,
|
||||||
},
|
},
|
||||||
|
.id_table = moxtet_spi_ids,
|
||||||
.probe = moxtet_probe,
|
.probe = moxtet_probe,
|
||||||
.remove = moxtet_remove,
|
.remove = moxtet_remove,
|
||||||
};
|
};
|
||||||
|
@ -84,12 +84,10 @@ err0:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int omap_ocp2scp_remove(struct platform_device *pdev)
|
static void omap_ocp2scp_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
|
device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
@ -103,7 +101,7 @@ MODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table);
|
|||||||
|
|
||||||
static struct platform_driver omap_ocp2scp_driver = {
|
static struct platform_driver omap_ocp2scp_driver = {
|
||||||
.probe = omap_ocp2scp_probe,
|
.probe = omap_ocp2scp_probe,
|
||||||
.remove = omap_ocp2scp_remove,
|
.remove_new = omap_ocp2scp_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "omap-ocp2scp",
|
.name = "omap-ocp2scp",
|
||||||
.of_match_table = of_match_ptr(omap_ocp2scp_id_table),
|
.of_match_table = of_match_ptr(omap_ocp2scp_id_table),
|
||||||
|
@ -261,7 +261,7 @@ err0:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int omap3_l3_remove(struct platform_device *pdev)
|
static void omap3_l3_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct omap3_l3 *l3 = platform_get_drvdata(pdev);
|
struct omap3_l3 *l3 = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
@ -269,13 +269,11 @@ static int omap3_l3_remove(struct platform_device *pdev)
|
|||||||
free_irq(l3->debug_irq, l3);
|
free_irq(l3->debug_irq, l3);
|
||||||
iounmap(l3->rt);
|
iounmap(l3->rt);
|
||||||
kfree(l3);
|
kfree(l3);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver omap3_l3_driver = {
|
static struct platform_driver omap3_l3_driver = {
|
||||||
.probe = omap3_l3_probe,
|
.probe = omap3_l3_probe,
|
||||||
.remove = omap3_l3_remove,
|
.remove_new = omap3_l3_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "omap_l3_smx",
|
.name = "omap_l3_smx",
|
||||||
.of_match_table = of_match_ptr(omap3_l3_match),
|
.of_match_table = of_match_ptr(omap3_l3_match),
|
||||||
|
@ -350,7 +350,7 @@ static int qcom_ssc_block_bus_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int qcom_ssc_block_bus_remove(struct platform_device *pdev)
|
static void qcom_ssc_block_bus_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct qcom_ssc_block_bus_data *data = platform_get_drvdata(pdev);
|
struct qcom_ssc_block_bus_data *data = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
@ -363,8 +363,6 @@ static int qcom_ssc_block_bus_remove(struct platform_device *pdev)
|
|||||||
qcom_ssc_block_bus_pds_detach(&pdev->dev, data->pds, data->num_pds);
|
qcom_ssc_block_bus_pds_detach(&pdev->dev, data->pds, data->num_pds);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
pm_clk_destroy(&pdev->dev);
|
pm_clk_destroy(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id qcom_ssc_block_bus_of_match[] = {
|
static const struct of_device_id qcom_ssc_block_bus_of_match[] = {
|
||||||
@ -375,7 +373,7 @@ MODULE_DEVICE_TABLE(of, qcom_ssc_block_bus_of_match);
|
|||||||
|
|
||||||
static struct platform_driver qcom_ssc_block_bus_driver = {
|
static struct platform_driver qcom_ssc_block_bus_driver = {
|
||||||
.probe = qcom_ssc_block_bus_probe,
|
.probe = qcom_ssc_block_bus_probe,
|
||||||
.remove = qcom_ssc_block_bus_remove,
|
.remove_new = qcom_ssc_block_bus_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qcom-ssc-block-bus",
|
.name = "qcom-ssc-block-bus",
|
||||||
.of_match_table = qcom_ssc_block_bus_of_match,
|
.of_match_table = qcom_ssc_block_bus_of_match,
|
||||||
|
@ -74,17 +74,16 @@ static int simple_pm_bus_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int simple_pm_bus_remove(struct platform_device *pdev)
|
static void simple_pm_bus_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
const void *data = of_device_get_match_data(&pdev->dev);
|
const void *data = of_device_get_match_data(&pdev->dev);
|
||||||
|
|
||||||
if (pdev->driver_override || data)
|
if (pdev->driver_override || data)
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "%s\n", __func__);
|
dev_dbg(&pdev->dev, "%s\n", __func__);
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int simple_pm_bus_runtime_suspend(struct device *dev)
|
static int simple_pm_bus_runtime_suspend(struct device *dev)
|
||||||
@ -129,7 +128,7 @@ MODULE_DEVICE_TABLE(of, simple_pm_bus_of_match);
|
|||||||
|
|
||||||
static struct platform_driver simple_pm_bus_driver = {
|
static struct platform_driver simple_pm_bus_driver = {
|
||||||
.probe = simple_pm_bus_probe,
|
.probe = simple_pm_bus_probe,
|
||||||
.remove = simple_pm_bus_remove,
|
.remove_new = simple_pm_bus_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "simple-pm-bus",
|
.name = "simple-pm-bus",
|
||||||
.of_match_table = simple_pm_bus_of_match,
|
.of_match_table = simple_pm_bus_of_match,
|
||||||
|
@ -24,10 +24,9 @@ static int sun50i_de2_bus_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sun50i_de2_bus_remove(struct platform_device *pdev)
|
static void sun50i_de2_bus_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
sunxi_sram_release(&pdev->dev);
|
sunxi_sram_release(&pdev->dev);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id sun50i_de2_bus_of_match[] = {
|
static const struct of_device_id sun50i_de2_bus_of_match[] = {
|
||||||
@ -37,7 +36,7 @@ static const struct of_device_id sun50i_de2_bus_of_match[] = {
|
|||||||
|
|
||||||
static struct platform_driver sun50i_de2_bus_driver = {
|
static struct platform_driver sun50i_de2_bus_driver = {
|
||||||
.probe = sun50i_de2_bus_probe,
|
.probe = sun50i_de2_bus_probe,
|
||||||
.remove = sun50i_de2_bus_remove,
|
.remove_new = sun50i_de2_bus_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sun50i-de2-bus",
|
.name = "sun50i-de2-bus",
|
||||||
.of_match_table = sun50i_de2_bus_of_match,
|
.of_match_table = sun50i_de2_bus_of_match,
|
||||||
|
@ -817,15 +817,13 @@ static int sunxi_rsb_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sunxi_rsb_remove(struct platform_device *pdev)
|
static void sunxi_rsb_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sunxi_rsb *rsb = platform_get_drvdata(pdev);
|
struct sunxi_rsb *rsb = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices);
|
device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
sunxi_rsb_hw_exit(rsb);
|
sunxi_rsb_hw_exit(rsb);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops sunxi_rsb_dev_pm_ops = {
|
static const struct dev_pm_ops sunxi_rsb_dev_pm_ops = {
|
||||||
@ -842,7 +840,7 @@ MODULE_DEVICE_TABLE(of, sunxi_rsb_of_match_table);
|
|||||||
|
|
||||||
static struct platform_driver sunxi_rsb_driver = {
|
static struct platform_driver sunxi_rsb_driver = {
|
||||||
.probe = sunxi_rsb_probe,
|
.probe = sunxi_rsb_probe,
|
||||||
.remove = sunxi_rsb_remove,
|
.remove_new = sunxi_rsb_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = RSB_CTRL_NAME,
|
.name = RSB_CTRL_NAME,
|
||||||
.of_match_table = sunxi_rsb_of_match_table,
|
.of_match_table = sunxi_rsb_of_match_table,
|
||||||
|
@ -53,11 +53,9 @@ static int tegra_aconnect_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra_aconnect_remove(struct platform_device *pdev)
|
static void tegra_aconnect_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra_aconnect_runtime_resume(struct device *dev)
|
static int tegra_aconnect_runtime_resume(struct device *dev)
|
||||||
@ -106,7 +104,7 @@ MODULE_DEVICE_TABLE(of, tegra_aconnect_of_match);
|
|||||||
|
|
||||||
static struct platform_driver tegra_aconnect_driver = {
|
static struct platform_driver tegra_aconnect_driver = {
|
||||||
.probe = tegra_aconnect_probe,
|
.probe = tegra_aconnect_probe,
|
||||||
.remove = tegra_aconnect_remove,
|
.remove_new = tegra_aconnect_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "tegra-aconnect",
|
.name = "tegra-aconnect",
|
||||||
.of_match_table = tegra_aconnect_of_match,
|
.of_match_table = tegra_aconnect_of_match,
|
||||||
|
@ -258,14 +258,12 @@ static int tegra_gmi_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra_gmi_remove(struct platform_device *pdev)
|
static void tegra_gmi_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct tegra_gmi *gmi = platform_get_drvdata(pdev);
|
struct tegra_gmi *gmi = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
of_platform_depopulate(gmi->dev);
|
of_platform_depopulate(gmi->dev);
|
||||||
tegra_gmi_disable(gmi);
|
tegra_gmi_disable(gmi);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused tegra_gmi_runtime_resume(struct device *dev)
|
static int __maybe_unused tegra_gmi_runtime_resume(struct device *dev)
|
||||||
@ -305,7 +303,7 @@ MODULE_DEVICE_TABLE(of, tegra_gmi_id_table);
|
|||||||
|
|
||||||
static struct platform_driver tegra_gmi_driver = {
|
static struct platform_driver tegra_gmi_driver = {
|
||||||
.probe = tegra_gmi_probe,
|
.probe = tegra_gmi_probe,
|
||||||
.remove = tegra_gmi_remove,
|
.remove_new = tegra_gmi_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "tegra-gmi",
|
.name = "tegra-gmi",
|
||||||
.of_match_table = tegra_gmi_id_table,
|
.of_match_table = tegra_gmi_id_table,
|
||||||
|
@ -33,10 +33,9 @@ static int pwmss_probe(struct platform_device *pdev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pwmss_remove(struct platform_device *pdev)
|
static void pwmss_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver pwmss_driver = {
|
static struct platform_driver pwmss_driver = {
|
||||||
@ -45,7 +44,7 @@ static struct platform_driver pwmss_driver = {
|
|||||||
.of_match_table = pwmss_of_match,
|
.of_match_table = pwmss_of_match,
|
||||||
},
|
},
|
||||||
.probe = pwmss_probe,
|
.probe = pwmss_probe,
|
||||||
.remove = pwmss_remove,
|
.remove_new = pwmss_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(pwmss_driver);
|
module_platform_driver(pwmss_driver);
|
||||||
|
@ -3397,7 +3397,7 @@ unprepare:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sysc_remove(struct platform_device *pdev)
|
static void sysc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct sysc *ddata = platform_get_drvdata(pdev);
|
struct sysc *ddata = platform_get_drvdata(pdev);
|
||||||
int error;
|
int error;
|
||||||
@ -3422,8 +3422,6 @@ static int sysc_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
unprepare:
|
unprepare:
|
||||||
sysc_unprepare(ddata);
|
sysc_unprepare(ddata);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id sysc_match[] = {
|
static const struct of_device_id sysc_match[] = {
|
||||||
@ -3449,7 +3447,7 @@ MODULE_DEVICE_TABLE(of, sysc_match);
|
|||||||
|
|
||||||
static struct platform_driver sysc_driver = {
|
static struct platform_driver sysc_driver = {
|
||||||
.probe = sysc_probe,
|
.probe = sysc_probe,
|
||||||
.remove = sysc_remove,
|
.remove_new = sysc_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ti-sysc",
|
.name = "ti-sysc",
|
||||||
.of_match_table = sysc_match,
|
.of_match_table = sysc_match,
|
||||||
|
@ -331,7 +331,7 @@ static int ts_nbus_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ts_nbus_remove(struct platform_device *pdev)
|
static void ts_nbus_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct ts_nbus *ts_nbus = dev_get_drvdata(&pdev->dev);
|
struct ts_nbus *ts_nbus = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
@ -339,8 +339,6 @@ static int ts_nbus_remove(struct platform_device *pdev)
|
|||||||
mutex_lock(&ts_nbus->lock);
|
mutex_lock(&ts_nbus->lock);
|
||||||
pwm_disable(ts_nbus->pwm);
|
pwm_disable(ts_nbus->pwm);
|
||||||
mutex_unlock(&ts_nbus->lock);
|
mutex_unlock(&ts_nbus->lock);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id ts_nbus_of_match[] = {
|
static const struct of_device_id ts_nbus_of_match[] = {
|
||||||
@ -351,7 +349,7 @@ MODULE_DEVICE_TABLE(of, ts_nbus_of_match);
|
|||||||
|
|
||||||
static struct platform_driver ts_nbus_driver = {
|
static struct platform_driver ts_nbus_driver = {
|
||||||
.probe = ts_nbus_probe,
|
.probe = ts_nbus_probe,
|
||||||
.remove = ts_nbus_remove,
|
.remove_new = ts_nbus_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ts_nbus",
|
.name = "ts_nbus",
|
||||||
.of_match_table = ts_nbus_of_match,
|
.of_match_table = ts_nbus_of_match,
|
||||||
|
6
drivers/cache/Kconfig
vendored
6
drivers/cache/Kconfig
vendored
@ -8,4 +8,10 @@ config AX45MP_L2_CACHE
|
|||||||
help
|
help
|
||||||
Support for the L2 cache controller on Andes Technology AX45MP platforms.
|
Support for the L2 cache controller on Andes Technology AX45MP platforms.
|
||||||
|
|
||||||
|
config SIFIVE_CCACHE
|
||||||
|
bool "Sifive Composable Cache controller"
|
||||||
|
depends on ARCH_SIFIVE || ARCH_STARFIVE
|
||||||
|
help
|
||||||
|
Support for the composable cache controller on SiFive platforms.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
3
drivers/cache/Makefile
vendored
3
drivers/cache/Makefile
vendored
@ -1,3 +1,4 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o
|
obj-$(CONFIG_AX45MP_L2_CACHE) += ax45mp_cache.o
|
||||||
|
obj-$(CONFIG_SIFIVE_CCACHE) += sifive_ccache.o
|
||||||
|
@ -8,13 +8,16 @@
|
|||||||
|
|
||||||
#define pr_fmt(fmt) "CCACHE: " fmt
|
#define pr_fmt(fmt) "CCACHE: " fmt
|
||||||
|
|
||||||
|
#include <linux/align.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
#include <asm/cacheinfo.h>
|
#include <asm/cacheinfo.h>
|
||||||
|
#include <asm/dma-noncoherent.h>
|
||||||
#include <soc/sifive/sifive_ccache.h>
|
#include <soc/sifive/sifive_ccache.h>
|
||||||
|
|
||||||
#define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100
|
#define SIFIVE_CCACHE_DIRECCFIX_LOW 0x100
|
||||||
@ -39,10 +42,14 @@
|
|||||||
#define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16)
|
#define SIFIVE_CCACHE_CONFIG_SETS_MASK GENMASK_ULL(23, 16)
|
||||||
#define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24)
|
#define SIFIVE_CCACHE_CONFIG_BLKS_MASK GENMASK_ULL(31, 24)
|
||||||
|
|
||||||
|
#define SIFIVE_CCACHE_FLUSH64 0x200
|
||||||
|
#define SIFIVE_CCACHE_FLUSH32 0x240
|
||||||
|
|
||||||
#define SIFIVE_CCACHE_WAYENABLE 0x08
|
#define SIFIVE_CCACHE_WAYENABLE 0x08
|
||||||
#define SIFIVE_CCACHE_ECCINJECTERR 0x40
|
#define SIFIVE_CCACHE_ECCINJECTERR 0x40
|
||||||
|
|
||||||
#define SIFIVE_CCACHE_MAX_ECCINTR 4
|
#define SIFIVE_CCACHE_MAX_ECCINTR 4
|
||||||
|
#define SIFIVE_CCACHE_LINE_SIZE 64
|
||||||
|
|
||||||
static void __iomem *ccache_base;
|
static void __iomem *ccache_base;
|
||||||
static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR];
|
static int g_irq[SIFIVE_CCACHE_MAX_ECCINTR];
|
||||||
@ -56,6 +63,11 @@ enum {
|
|||||||
DIR_UNCORR,
|
DIR_UNCORR,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
QUIRK_NONSTANDARD_CACHE_OPS = BIT(0),
|
||||||
|
QUIRK_BROKEN_DATA_UNCORR = BIT(1),
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
static struct dentry *sifive_test;
|
static struct dentry *sifive_test;
|
||||||
|
|
||||||
@ -106,6 +118,8 @@ static void ccache_config_read(void)
|
|||||||
static const struct of_device_id sifive_ccache_ids[] = {
|
static const struct of_device_id sifive_ccache_ids[] = {
|
||||||
{ .compatible = "sifive,fu540-c000-ccache" },
|
{ .compatible = "sifive,fu540-c000-ccache" },
|
||||||
{ .compatible = "sifive,fu740-c000-ccache" },
|
{ .compatible = "sifive,fu740-c000-ccache" },
|
||||||
|
{ .compatible = "starfive,jh7100-ccache",
|
||||||
|
.data = (void *)(QUIRK_NONSTANDARD_CACHE_OPS | QUIRK_BROKEN_DATA_UNCORR) },
|
||||||
{ .compatible = "sifive,ccache0" },
|
{ .compatible = "sifive,ccache0" },
|
||||||
{ /* end of table */ }
|
{ /* end of table */ }
|
||||||
};
|
};
|
||||||
@ -124,6 +138,34 @@ int unregister_sifive_ccache_error_notifier(struct notifier_block *nb)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier);
|
EXPORT_SYMBOL_GPL(unregister_sifive_ccache_error_notifier);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
|
||||||
|
static void ccache_flush_range(phys_addr_t start, size_t len)
|
||||||
|
{
|
||||||
|
phys_addr_t end = start + len;
|
||||||
|
phys_addr_t line;
|
||||||
|
|
||||||
|
if (!len)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mb();
|
||||||
|
for (line = ALIGN_DOWN(start, SIFIVE_CCACHE_LINE_SIZE); line < end;
|
||||||
|
line += SIFIVE_CCACHE_LINE_SIZE) {
|
||||||
|
#ifdef CONFIG_32BIT
|
||||||
|
writel(line >> 4, ccache_base + SIFIVE_CCACHE_FLUSH32);
|
||||||
|
#else
|
||||||
|
writeq(line, ccache_base + SIFIVE_CCACHE_FLUSH64);
|
||||||
|
#endif
|
||||||
|
mb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct riscv_nonstd_cache_ops ccache_mgmt_ops __initconst = {
|
||||||
|
.wback = &ccache_flush_range,
|
||||||
|
.inv = &ccache_flush_range,
|
||||||
|
.wback_inv = &ccache_flush_range,
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_RISCV_NONSTANDARD_CACHE_OPS */
|
||||||
|
|
||||||
static int ccache_largest_wayenabled(void)
|
static int ccache_largest_wayenabled(void)
|
||||||
{
|
{
|
||||||
return readl(ccache_base + SIFIVE_CCACHE_WAYENABLE) & 0xFF;
|
return readl(ccache_base + SIFIVE_CCACHE_WAYENABLE) & 0xFF;
|
||||||
@ -210,11 +252,15 @@ static int __init sifive_ccache_init(void)
|
|||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
struct resource res;
|
struct resource res;
|
||||||
int i, rc, intr_num;
|
int i, rc, intr_num;
|
||||||
|
const struct of_device_id *match;
|
||||||
|
unsigned long quirks;
|
||||||
|
|
||||||
np = of_find_matching_node(NULL, sifive_ccache_ids);
|
np = of_find_matching_node_and_match(NULL, sifive_ccache_ids, &match);
|
||||||
if (!np)
|
if (!np)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
quirks = (uintptr_t)match->data;
|
||||||
|
|
||||||
if (of_address_to_resource(np, 0, &res)) {
|
if (of_address_to_resource(np, 0, &res)) {
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
goto err_node_put;
|
goto err_node_put;
|
||||||
@ -240,6 +286,10 @@ static int __init sifive_ccache_init(void)
|
|||||||
|
|
||||||
for (i = 0; i < intr_num; i++) {
|
for (i = 0; i < intr_num; i++) {
|
||||||
g_irq[i] = irq_of_parse_and_map(np, i);
|
g_irq[i] = irq_of_parse_and_map(np, i);
|
||||||
|
|
||||||
|
if (i == DATA_UNCORR && (quirks & QUIRK_BROKEN_DATA_UNCORR))
|
||||||
|
continue;
|
||||||
|
|
||||||
rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc",
|
rc = request_irq(g_irq[i], ccache_int_handler, 0, "ccache_ecc",
|
||||||
NULL);
|
NULL);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
@ -249,6 +299,14 @@ static int __init sifive_ccache_init(void)
|
|||||||
}
|
}
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
|
|
||||||
|
#ifdef CONFIG_RISCV_NONSTANDARD_CACHE_OPS
|
||||||
|
if (quirks & QUIRK_NONSTANDARD_CACHE_OPS) {
|
||||||
|
riscv_cbom_block_size = SIFIVE_CCACHE_LINE_SIZE;
|
||||||
|
riscv_noncoherent_supported();
|
||||||
|
riscv_noncoherent_register_cache_ops(&ccache_mgmt_ops);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ccache_config_read();
|
ccache_config_read();
|
||||||
|
|
||||||
ccache_cache_ops.get_priv_group = ccache_get_priv_group;
|
ccache_cache_ops.get_priv_group = ccache_get_priv_group;
|
||||||
@ -269,4 +327,4 @@ err_node_put:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_initcall(sifive_ccache_init);
|
arch_initcall(sifive_ccache_init);
|
@ -21,6 +21,7 @@ obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o
|
|||||||
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7885.o
|
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7885.o
|
||||||
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos850.o
|
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos850.o
|
||||||
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynosautov9.o
|
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynosautov9.o
|
||||||
|
obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-gs101.o
|
||||||
obj-$(CONFIG_S3C64XX_COMMON_CLK) += clk-s3c64xx.o
|
obj-$(CONFIG_S3C64XX_COMMON_CLK) += clk-s3c64xx.o
|
||||||
obj-$(CONFIG_S5PV210_COMMON_CLK) += clk-s5pv210.o clk-s5pv210-audss.o
|
obj-$(CONFIG_S5PV210_COMMON_CLK) += clk-s5pv210.o clk-s5pv210-audss.o
|
||||||
obj-$(CONFIG_TESLA_FSD_COMMON_CLK) += clk-fsd.o
|
obj-$(CONFIG_TESLA_FSD_COMMON_CLK) += clk-fsd.o
|
||||||
|
2518
drivers/clk/samsung/clk-gs101.c
Normal file
2518
drivers/clk/samsung/clk-gs101.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -443,6 +443,9 @@ static unsigned long samsung_pll0822x_recalc_rate(struct clk_hw *hw,
|
|||||||
sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK;
|
sdiv = (pll_con3 >> PLL0822X_SDIV_SHIFT) & PLL0822X_SDIV_MASK;
|
||||||
|
|
||||||
fvco *= mdiv;
|
fvco *= mdiv;
|
||||||
|
if (pll->type == pll_0516x)
|
||||||
|
fvco *= 2;
|
||||||
|
|
||||||
do_div(fvco, (pdiv << sdiv));
|
do_div(fvco, (pdiv << sdiv));
|
||||||
|
|
||||||
return (unsigned long)fvco;
|
return (unsigned long)fvco;
|
||||||
@ -1316,6 +1319,9 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx,
|
|||||||
case pll_1417x:
|
case pll_1417x:
|
||||||
case pll_0818x:
|
case pll_0818x:
|
||||||
case pll_0822x:
|
case pll_0822x:
|
||||||
|
case pll_0516x:
|
||||||
|
case pll_0517x:
|
||||||
|
case pll_0518x:
|
||||||
pll->enable_offs = PLL0822X_ENABLE_SHIFT;
|
pll->enable_offs = PLL0822X_ENABLE_SHIFT;
|
||||||
pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT;
|
pll->lock_offs = PLL0822X_LOCK_STAT_SHIFT;
|
||||||
if (!pll->rate_table)
|
if (!pll->rate_table)
|
||||||
|
@ -38,6 +38,9 @@ enum samsung_pll_type {
|
|||||||
pll_0822x,
|
pll_0822x,
|
||||||
pll_0831x,
|
pll_0831x,
|
||||||
pll_142xx,
|
pll_142xx,
|
||||||
|
pll_0516x,
|
||||||
|
pll_0517x,
|
||||||
|
pll_0518x,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \
|
#define PLL_RATE(_fin, _m, _p, _s, _k, _ks) \
|
||||||
|
@ -272,6 +272,7 @@ source "drivers/firmware/google/Kconfig"
|
|||||||
source "drivers/firmware/efi/Kconfig"
|
source "drivers/firmware/efi/Kconfig"
|
||||||
source "drivers/firmware/imx/Kconfig"
|
source "drivers/firmware/imx/Kconfig"
|
||||||
source "drivers/firmware/meson/Kconfig"
|
source "drivers/firmware/meson/Kconfig"
|
||||||
|
source "drivers/firmware/microchip/Kconfig"
|
||||||
source "drivers/firmware/psci/Kconfig"
|
source "drivers/firmware/psci/Kconfig"
|
||||||
source "drivers/firmware/qcom/Kconfig"
|
source "drivers/firmware/qcom/Kconfig"
|
||||||
source "drivers/firmware/smccc/Kconfig"
|
source "drivers/firmware/smccc/Kconfig"
|
||||||
|
@ -28,6 +28,7 @@ obj-y += arm_scmi/
|
|||||||
obj-y += broadcom/
|
obj-y += broadcom/
|
||||||
obj-y += cirrus/
|
obj-y += cirrus/
|
||||||
obj-y += meson/
|
obj-y += meson/
|
||||||
|
obj-y += microchip/
|
||||||
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
|
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
|
||||||
obj-y += efi/
|
obj-y += efi/
|
||||||
obj-y += imx/
|
obj-y += imx/
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
|
||||||
|
|
||||||
#define SCMI_BASE_NUM_SOURCES 1
|
#define SCMI_BASE_NUM_SOURCES 1
|
||||||
#define SCMI_BASE_MAX_CMD_ERR_COUNT 1024
|
#define SCMI_BASE_MAX_CMD_ERR_COUNT 1024
|
||||||
|
|
||||||
@ -385,7 +388,7 @@ static int scmi_base_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
|
|
||||||
rev->major_ver = PROTOCOL_REV_MAJOR(version),
|
rev->major_ver = PROTOCOL_REV_MAJOR(version),
|
||||||
rev->minor_ver = PROTOCOL_REV_MINOR(version);
|
rev->minor_ver = PROTOCOL_REV_MINOR(version);
|
||||||
ph->set_priv(ph, rev);
|
ph->set_priv(ph, rev, version);
|
||||||
|
|
||||||
ret = scmi_base_attributes_get(ph);
|
ret = scmi_base_attributes_get(ph);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -423,6 +426,7 @@ static const struct scmi_protocol scmi_base = {
|
|||||||
.instance_init = &scmi_base_protocol_init,
|
.instance_init = &scmi_base_protocol_init,
|
||||||
.ops = NULL,
|
.ops = NULL,
|
||||||
.events = &base_protocol_events,
|
.events = &base_protocol_events,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(base, scmi_base)
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20001
|
||||||
|
|
||||||
enum scmi_clock_protocol_cmd {
|
enum scmi_clock_protocol_cmd {
|
||||||
CLOCK_ATTRIBUTES = 0x3,
|
CLOCK_ATTRIBUTES = 0x3,
|
||||||
CLOCK_DESCRIBE_RATES = 0x4,
|
CLOCK_DESCRIBE_RATES = 0x4,
|
||||||
@ -318,7 +321,7 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
|
|||||||
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) {
|
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) {
|
||||||
if (SUPPORTS_EXTENDED_NAMES(attributes))
|
if (SUPPORTS_EXTENDED_NAMES(attributes))
|
||||||
ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id,
|
ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id,
|
||||||
clk->name,
|
NULL, clk->name,
|
||||||
SCMI_MAX_STR_SIZE);
|
SCMI_MAX_STR_SIZE);
|
||||||
|
|
||||||
if (SUPPORTS_RATE_CHANGED_NOTIF(attributes))
|
if (SUPPORTS_RATE_CHANGED_NOTIF(attributes))
|
||||||
@ -961,7 +964,7 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
}
|
}
|
||||||
|
|
||||||
cinfo->version = version;
|
cinfo->version = version;
|
||||||
return ph->set_priv(ph, cinfo);
|
return ph->set_priv(ph, cinfo, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct scmi_protocol scmi_clock = {
|
static const struct scmi_protocol scmi_clock = {
|
||||||
@ -970,6 +973,7 @@ static const struct scmi_protocol scmi_clock = {
|
|||||||
.instance_init = &scmi_clock_protocol_init,
|
.instance_init = &scmi_clock_protocol_init,
|
||||||
.ops = &clk_proto_ops,
|
.ops = &clk_proto_ops,
|
||||||
.events = &clk_protocol_events,
|
.events = &clk_protocol_events,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock)
|
||||||
|
@ -85,6 +85,7 @@ struct scmi_xfers_info {
|
|||||||
* @gid: A reference for per-protocol devres management.
|
* @gid: A reference for per-protocol devres management.
|
||||||
* @users: A refcount to track effective users of this protocol.
|
* @users: A refcount to track effective users of this protocol.
|
||||||
* @priv: Reference for optional protocol private data.
|
* @priv: Reference for optional protocol private data.
|
||||||
|
* @version: Protocol version supported by the platform as detected at runtime.
|
||||||
* @ph: An embedded protocol handle that will be passed down to protocol
|
* @ph: An embedded protocol handle that will be passed down to protocol
|
||||||
* initialization code to identify this instance.
|
* initialization code to identify this instance.
|
||||||
*
|
*
|
||||||
@ -97,6 +98,7 @@ struct scmi_protocol_instance {
|
|||||||
void *gid;
|
void *gid;
|
||||||
refcount_t users;
|
refcount_t users;
|
||||||
void *priv;
|
void *priv;
|
||||||
|
unsigned int version;
|
||||||
struct scmi_protocol_handle ph;
|
struct scmi_protocol_handle ph;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1392,15 +1394,17 @@ static int version_get(const struct scmi_protocol_handle *ph, u32 *version)
|
|||||||
*
|
*
|
||||||
* @ph: A reference to the protocol handle.
|
* @ph: A reference to the protocol handle.
|
||||||
* @priv: The private data to set.
|
* @priv: The private data to set.
|
||||||
|
* @version: The detected protocol version for the core to register.
|
||||||
*
|
*
|
||||||
* Return: 0 on Success
|
* Return: 0 on Success
|
||||||
*/
|
*/
|
||||||
static int scmi_set_protocol_priv(const struct scmi_protocol_handle *ph,
|
static int scmi_set_protocol_priv(const struct scmi_protocol_handle *ph,
|
||||||
void *priv)
|
void *priv, u32 version)
|
||||||
{
|
{
|
||||||
struct scmi_protocol_instance *pi = ph_to_pi(ph);
|
struct scmi_protocol_instance *pi = ph_to_pi(ph);
|
||||||
|
|
||||||
pi->priv = priv;
|
pi->priv = priv;
|
||||||
|
pi->version = version;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1438,6 +1442,7 @@ struct scmi_msg_resp_domain_name_get {
|
|||||||
* @ph: A protocol handle reference.
|
* @ph: A protocol handle reference.
|
||||||
* @cmd_id: The specific command ID to use.
|
* @cmd_id: The specific command ID to use.
|
||||||
* @res_id: The specific resource ID to use.
|
* @res_id: The specific resource ID to use.
|
||||||
|
* @flags: A pointer to specific flags to use, if any.
|
||||||
* @name: A pointer to the preallocated area where the retrieved name will be
|
* @name: A pointer to the preallocated area where the retrieved name will be
|
||||||
* stored as a NULL terminated string.
|
* stored as a NULL terminated string.
|
||||||
* @len: The len in bytes of the @name char array.
|
* @len: The len in bytes of the @name char array.
|
||||||
@ -1445,19 +1450,22 @@ struct scmi_msg_resp_domain_name_get {
|
|||||||
* Return: 0 on Succcess
|
* Return: 0 on Succcess
|
||||||
*/
|
*/
|
||||||
static int scmi_common_extended_name_get(const struct scmi_protocol_handle *ph,
|
static int scmi_common_extended_name_get(const struct scmi_protocol_handle *ph,
|
||||||
u8 cmd_id, u32 res_id, char *name,
|
u8 cmd_id, u32 res_id, u32 *flags,
|
||||||
size_t len)
|
char *name, size_t len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
size_t txlen;
|
||||||
struct scmi_xfer *t;
|
struct scmi_xfer *t;
|
||||||
struct scmi_msg_resp_domain_name_get *resp;
|
struct scmi_msg_resp_domain_name_get *resp;
|
||||||
|
|
||||||
ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(res_id),
|
txlen = !flags ? sizeof(res_id) : sizeof(res_id) + sizeof(*flags);
|
||||||
sizeof(*resp), &t);
|
ret = ph->xops->xfer_get_init(ph, cmd_id, txlen, sizeof(*resp), &t);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
put_unaligned_le32(res_id, t->tx.buf);
|
put_unaligned_le32(res_id, t->tx.buf);
|
||||||
|
if (flags)
|
||||||
|
put_unaligned_le32(*flags, t->tx.buf + sizeof(res_id));
|
||||||
resp = t->rx.buf;
|
resp = t->rx.buf;
|
||||||
|
|
||||||
ret = ph->xops->do_xfer(ph, t);
|
ret = ph->xops->do_xfer(ph, t);
|
||||||
@ -1845,6 +1853,12 @@ scmi_alloc_init_protocol_instance(struct scmi_info *info,
|
|||||||
devres_close_group(handle->dev, pi->gid);
|
devres_close_group(handle->dev, pi->gid);
|
||||||
dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id);
|
dev_dbg(handle->dev, "Initialized protocol: 0x%X\n", pi->proto->id);
|
||||||
|
|
||||||
|
if (pi->version > proto->supported_version)
|
||||||
|
dev_warn(handle->dev,
|
||||||
|
"Detected UNSUPPORTED higher version 0x%X for protocol 0x%X."
|
||||||
|
"Backward compatibility is NOT assured.\n",
|
||||||
|
pi->version, pi->proto->id);
|
||||||
|
|
||||||
return pi;
|
return pi;
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
@ -440,6 +440,10 @@ static int scmi_optee_chan_setup(struct scmi_chan_info *cinfo, struct device *de
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto err_free_shm;
|
goto err_free_shm;
|
||||||
|
|
||||||
|
ret = tee_client_system_session(scmi_optee_private->tee_ctx, channel->tee_session);
|
||||||
|
if (ret)
|
||||||
|
dev_warn(dev, "Could not switch to system session, do best effort\n");
|
||||||
|
|
||||||
ret = get_channel(channel);
|
ret = get_channel(channel);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_close_sess;
|
goto err_close_sess;
|
||||||
|
@ -24,7 +24,10 @@
|
|||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
#define MAX_OPPS 16
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x40000
|
||||||
|
|
||||||
|
#define MAX_OPPS 32
|
||||||
|
|
||||||
enum scmi_performance_protocol_cmd {
|
enum scmi_performance_protocol_cmd {
|
||||||
PERF_DOMAIN_ATTRIBUTES = 0x3,
|
PERF_DOMAIN_ATTRIBUTES = 0x3,
|
||||||
@ -289,7 +292,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
|
|||||||
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
|
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
|
||||||
SUPPORTS_EXTENDED_NAMES(flags))
|
SUPPORTS_EXTENDED_NAMES(flags))
|
||||||
ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET,
|
ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET,
|
||||||
dom_info->id, dom_info->info.name,
|
dom_info->id, NULL, dom_info->info.name,
|
||||||
SCMI_MAX_STR_SIZE);
|
SCMI_MAX_STR_SIZE);
|
||||||
|
|
||||||
if (dom_info->level_indexing_mode) {
|
if (dom_info->level_indexing_mode) {
|
||||||
@ -505,6 +508,9 @@ static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
|
|||||||
if (IS_ERR(dom))
|
if (IS_ERR(dom))
|
||||||
return PTR_ERR(dom);
|
return PTR_ERR(dom);
|
||||||
|
|
||||||
|
if (!dom->set_limits)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
|
if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -655,6 +661,9 @@ static int scmi_perf_level_set(const struct scmi_protocol_handle *ph,
|
|||||||
if (IS_ERR(dom))
|
if (IS_ERR(dom))
|
||||||
return PTR_ERR(dom);
|
return PTR_ERR(dom);
|
||||||
|
|
||||||
|
if (!dom->info.set_perf)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (dom->level_indexing_mode) {
|
if (dom->level_indexing_mode) {
|
||||||
struct scmi_opp *opp;
|
struct scmi_opp *opp;
|
||||||
|
|
||||||
@ -754,7 +763,7 @@ static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
|
static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
|
||||||
u32 domain, struct scmi_fc_info **p_fc)
|
struct perf_dom_info *dom)
|
||||||
{
|
{
|
||||||
struct scmi_fc_info *fc;
|
struct scmi_fc_info *fc;
|
||||||
|
|
||||||
@ -763,24 +772,26 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
PERF_LEVEL_SET, 4, domain,
|
PERF_LEVEL_GET, 4, dom->id,
|
||||||
&fc[PERF_FC_LEVEL].set_addr,
|
|
||||||
&fc[PERF_FC_LEVEL].set_db);
|
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
|
||||||
PERF_LEVEL_GET, 4, domain,
|
|
||||||
&fc[PERF_FC_LEVEL].get_addr, NULL);
|
&fc[PERF_FC_LEVEL].get_addr, NULL);
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
PERF_LIMITS_SET, 8, domain,
|
PERF_LIMITS_GET, 8, dom->id,
|
||||||
&fc[PERF_FC_LIMIT].set_addr,
|
|
||||||
&fc[PERF_FC_LIMIT].set_db);
|
|
||||||
|
|
||||||
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
|
||||||
PERF_LIMITS_GET, 8, domain,
|
|
||||||
&fc[PERF_FC_LIMIT].get_addr, NULL);
|
&fc[PERF_FC_LIMIT].get_addr, NULL);
|
||||||
|
|
||||||
*p_fc = fc;
|
if (dom->info.set_perf)
|
||||||
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
|
PERF_LEVEL_SET, 4, dom->id,
|
||||||
|
&fc[PERF_FC_LEVEL].set_addr,
|
||||||
|
&fc[PERF_FC_LEVEL].set_db);
|
||||||
|
|
||||||
|
if (dom->set_limits)
|
||||||
|
ph->hops->fastchannel_init(ph, PERF_DESCRIBE_FASTCHANNEL,
|
||||||
|
PERF_LIMITS_SET, 8, dom->id,
|
||||||
|
&fc[PERF_FC_LIMIT].set_addr,
|
||||||
|
&fc[PERF_FC_LIMIT].set_db);
|
||||||
|
|
||||||
|
dom->fc_info = fc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
|
static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
|
||||||
@ -1091,14 +1102,14 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
scmi_perf_describe_levels_get(ph, dom, version);
|
scmi_perf_describe_levels_get(ph, dom, version);
|
||||||
|
|
||||||
if (dom->perf_fastchannels)
|
if (dom->perf_fastchannels)
|
||||||
scmi_perf_domain_init_fc(ph, dom->id, &dom->fc_info);
|
scmi_perf_domain_init_fc(ph, dom);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = devm_add_action_or_reset(ph->dev, scmi_perf_xa_destroy, pinfo);
|
ret = devm_add_action_or_reset(ph->dev, scmi_perf_xa_destroy, pinfo);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return ph->set_priv(ph, pinfo);
|
return ph->set_priv(ph, pinfo, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct scmi_protocol scmi_perf = {
|
static const struct scmi_protocol scmi_perf = {
|
||||||
@ -1107,6 +1118,7 @@ static const struct scmi_protocol scmi_perf = {
|
|||||||
.instance_init = &scmi_perf_protocol_init,
|
.instance_init = &scmi_perf_protocol_init,
|
||||||
.ops = &perf_proto_ops,
|
.ops = &perf_proto_ops,
|
||||||
.events = &perf_protocol_events,
|
.events = &perf_protocol_events,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(perf, scmi_perf)
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000
|
||||||
|
|
||||||
enum scmi_power_protocol_cmd {
|
enum scmi_power_protocol_cmd {
|
||||||
POWER_DOMAIN_ATTRIBUTES = 0x3,
|
POWER_DOMAIN_ATTRIBUTES = 0x3,
|
||||||
POWER_STATE_SET = 0x4,
|
POWER_STATE_SET = 0x4,
|
||||||
@ -133,7 +136,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
|
|||||||
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
|
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
|
||||||
SUPPORTS_EXTENDED_NAMES(flags)) {
|
SUPPORTS_EXTENDED_NAMES(flags)) {
|
||||||
ph->hops->extended_name_get(ph, POWER_DOMAIN_NAME_GET,
|
ph->hops->extended_name_get(ph, POWER_DOMAIN_NAME_GET,
|
||||||
domain, dom_info->name,
|
domain, NULL, dom_info->name,
|
||||||
SCMI_MAX_STR_SIZE);
|
SCMI_MAX_STR_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +331,7 @@ static int scmi_power_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
|
|
||||||
pinfo->version = version;
|
pinfo->version = version;
|
||||||
|
|
||||||
return ph->set_priv(ph, pinfo);
|
return ph->set_priv(ph, pinfo, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct scmi_protocol scmi_power = {
|
static const struct scmi_protocol scmi_power = {
|
||||||
@ -337,6 +340,7 @@ static const struct scmi_protocol scmi_power = {
|
|||||||
.instance_init = &scmi_power_protocol_init,
|
.instance_init = &scmi_power_protocol_init,
|
||||||
.ops = &power_proto_ops,
|
.ops = &power_proto_ops,
|
||||||
.events = &power_protocol_events,
|
.events = &power_protocol_events,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(power, scmi_power)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(power, scmi_power)
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
|
||||||
|
|
||||||
enum scmi_powercap_protocol_cmd {
|
enum scmi_powercap_protocol_cmd {
|
||||||
POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
|
POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
|
||||||
POWERCAP_CAP_GET = 0x4,
|
POWERCAP_CAP_GET = 0x4,
|
||||||
@ -270,7 +273,7 @@ clean:
|
|||||||
*/
|
*/
|
||||||
if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
|
if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
|
||||||
ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
|
ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
|
||||||
domain, dom_info->name,
|
domain, NULL, dom_info->name,
|
||||||
SCMI_MAX_STR_SIZE);
|
SCMI_MAX_STR_SIZE);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -975,7 +978,7 @@ scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pinfo->version = version;
|
pinfo->version = version;
|
||||||
return ph->set_priv(ph, pinfo);
|
return ph->set_priv(ph, pinfo, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct scmi_protocol scmi_powercap = {
|
static const struct scmi_protocol scmi_powercap = {
|
||||||
@ -984,6 +987,7 @@ static const struct scmi_protocol scmi_powercap = {
|
|||||||
.instance_init = &scmi_powercap_protocol_init,
|
.instance_init = &scmi_powercap_protocol_init,
|
||||||
.ops = &powercap_proto_ops,
|
.ops = &powercap_proto_ops,
|
||||||
.events = &powercap_protocol_events,
|
.events = &powercap_protocol_events,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
|
||||||
|
@ -174,7 +174,8 @@ struct scmi_protocol_handle {
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
const struct scmi_xfer_ops *xops;
|
const struct scmi_xfer_ops *xops;
|
||||||
const struct scmi_proto_helpers_ops *hops;
|
const struct scmi_proto_helpers_ops *hops;
|
||||||
int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv);
|
int (*set_priv)(const struct scmi_protocol_handle *ph, void *priv,
|
||||||
|
u32 version);
|
||||||
void *(*get_priv)(const struct scmi_protocol_handle *ph);
|
void *(*get_priv)(const struct scmi_protocol_handle *ph);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -256,7 +257,8 @@ struct scmi_fc_info {
|
|||||||
*/
|
*/
|
||||||
struct scmi_proto_helpers_ops {
|
struct scmi_proto_helpers_ops {
|
||||||
int (*extended_name_get)(const struct scmi_protocol_handle *ph,
|
int (*extended_name_get)(const struct scmi_protocol_handle *ph,
|
||||||
u8 cmd_id, u32 res_id, char *name, size_t len);
|
u8 cmd_id, u32 res_id, u32 *flags, char *name,
|
||||||
|
size_t len);
|
||||||
void *(*iter_response_init)(const struct scmi_protocol_handle *ph,
|
void *(*iter_response_init)(const struct scmi_protocol_handle *ph,
|
||||||
struct scmi_iterator_ops *ops,
|
struct scmi_iterator_ops *ops,
|
||||||
unsigned int max_resources, u8 msg_id,
|
unsigned int max_resources, u8 msg_id,
|
||||||
@ -310,6 +312,10 @@ typedef int (*scmi_prot_init_ph_fn_t)(const struct scmi_protocol_handle *);
|
|||||||
* @ops: Optional reference to the operations provided by the protocol and
|
* @ops: Optional reference to the operations provided by the protocol and
|
||||||
* exposed in scmi_protocol.h.
|
* exposed in scmi_protocol.h.
|
||||||
* @events: An optional reference to the events supported by this protocol.
|
* @events: An optional reference to the events supported by this protocol.
|
||||||
|
* @supported_version: The highest version currently supported for this
|
||||||
|
* protocol by the agent. Each protocol implementation
|
||||||
|
* in the agent is supposed to downgrade to match the
|
||||||
|
* protocol version supported by the platform.
|
||||||
*/
|
*/
|
||||||
struct scmi_protocol {
|
struct scmi_protocol {
|
||||||
const u8 id;
|
const u8 id;
|
||||||
@ -318,6 +324,7 @@ struct scmi_protocol {
|
|||||||
const scmi_prot_init_ph_fn_t instance_deinit;
|
const scmi_prot_init_ph_fn_t instance_deinit;
|
||||||
const void *ops;
|
const void *ops;
|
||||||
const struct scmi_protocol_events *events;
|
const struct scmi_protocol_events *events;
|
||||||
|
unsigned int supported_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(name, proto) \
|
#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(name, proto) \
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000
|
||||||
|
|
||||||
enum scmi_reset_protocol_cmd {
|
enum scmi_reset_protocol_cmd {
|
||||||
RESET_DOMAIN_ATTRIBUTES = 0x3,
|
RESET_DOMAIN_ATTRIBUTES = 0x3,
|
||||||
RESET = 0x4,
|
RESET = 0x4,
|
||||||
@ -128,7 +131,8 @@ scmi_reset_domain_attributes_get(const struct scmi_protocol_handle *ph,
|
|||||||
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
|
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
|
||||||
SUPPORTS_EXTENDED_NAMES(attributes))
|
SUPPORTS_EXTENDED_NAMES(attributes))
|
||||||
ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain,
|
ph->hops->extended_name_get(ph, RESET_DOMAIN_NAME_GET, domain,
|
||||||
dom_info->name, SCMI_MAX_STR_SIZE);
|
NULL, dom_info->name,
|
||||||
|
SCMI_MAX_STR_SIZE);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -342,7 +346,7 @@ static int scmi_reset_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pinfo->version = version;
|
pinfo->version = version;
|
||||||
return ph->set_priv(ph, pinfo);
|
return ph->set_priv(ph, pinfo, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct scmi_protocol scmi_reset = {
|
static const struct scmi_protocol scmi_reset = {
|
||||||
@ -351,6 +355,7 @@ static const struct scmi_protocol scmi_reset = {
|
|||||||
.instance_init = &scmi_reset_protocol_init,
|
.instance_init = &scmi_reset_protocol_init,
|
||||||
.ops = &reset_proto_ops,
|
.ops = &reset_proto_ops,
|
||||||
.events = &reset_protocol_events,
|
.events = &reset_protocol_events,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset)
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x30000
|
||||||
|
|
||||||
#define SCMI_MAX_NUM_SENSOR_AXIS 63
|
#define SCMI_MAX_NUM_SENSOR_AXIS 63
|
||||||
#define SCMIv2_SENSOR_PROTOCOL 0x10000
|
#define SCMIv2_SENSOR_PROTOCOL 0x10000
|
||||||
|
|
||||||
@ -644,7 +647,7 @@ iter_sens_descr_process_response(const struct scmi_protocol_handle *ph,
|
|||||||
if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 &&
|
if (PROTOCOL_REV_MAJOR(si->version) >= 0x3 &&
|
||||||
SUPPORTS_EXTENDED_NAMES(attrl))
|
SUPPORTS_EXTENDED_NAMES(attrl))
|
||||||
ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id,
|
ph->hops->extended_name_get(ph, SENSOR_NAME_GET, s->id,
|
||||||
s->name, SCMI_MAX_STR_SIZE);
|
NULL, s->name, SCMI_MAX_STR_SIZE);
|
||||||
|
|
||||||
if (s->extended_scalar_attrs) {
|
if (s->extended_scalar_attrs) {
|
||||||
s->sensor_power = le32_to_cpu(sdesc->power);
|
s->sensor_power = le32_to_cpu(sdesc->power);
|
||||||
@ -1138,7 +1141,7 @@ static int scmi_sensors_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return ph->set_priv(ph, sinfo);
|
return ph->set_priv(ph, sinfo, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct scmi_protocol scmi_sensors = {
|
static const struct scmi_protocol scmi_sensors = {
|
||||||
@ -1147,6 +1150,7 @@ static const struct scmi_protocol scmi_sensors = {
|
|||||||
.instance_init = &scmi_sensors_protocol_init,
|
.instance_init = &scmi_sensors_protocol_init,
|
||||||
.ops = &sensor_proto_ops,
|
.ops = &sensor_proto_ops,
|
||||||
.events = &sensor_protocol_events,
|
.events = &sensor_protocol_events,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(sensors, scmi_sensors)
|
||||||
|
@ -13,6 +13,9 @@
|
|||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
|
||||||
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
|
||||||
|
|
||||||
#define SCMI_SYSTEM_NUM_SOURCES 1
|
#define SCMI_SYSTEM_NUM_SOURCES 1
|
||||||
|
|
||||||
enum scmi_system_protocol_cmd {
|
enum scmi_system_protocol_cmd {
|
||||||
@ -144,7 +147,7 @@ static int scmi_system_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
|
if (PROTOCOL_REV_MAJOR(pinfo->version) >= 0x2)
|
||||||
pinfo->graceful_timeout_supported = true;
|
pinfo->graceful_timeout_supported = true;
|
||||||
|
|
||||||
return ph->set_priv(ph, pinfo);
|
return ph->set_priv(ph, pinfo, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct scmi_protocol scmi_system = {
|
static const struct scmi_protocol scmi_system = {
|
||||||
@ -153,6 +156,7 @@ static const struct scmi_protocol scmi_system = {
|
|||||||
.instance_init = &scmi_system_protocol_init,
|
.instance_init = &scmi_system_protocol_init,
|
||||||
.ops = NULL,
|
.ops = NULL,
|
||||||
.events = &system_protocol_events,
|
.events = &system_protocol_events,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(system, scmi_system)
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
|
|
||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
|
|
||||||
|
/* Updated only after ALL the mandatory features for that version are merged */
|
||||||
|
#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x20000
|
||||||
|
|
||||||
#define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0)
|
#define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0)
|
||||||
#define REMAINING_LEVELS_MASK GENMASK(31, 16)
|
#define REMAINING_LEVELS_MASK GENMASK(31, 16)
|
||||||
#define RETURNED_LEVELS_MASK GENMASK(11, 0)
|
#define RETURNED_LEVELS_MASK GENMASK(11, 0)
|
||||||
@ -242,7 +245,7 @@ static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
|
|||||||
if (SUPPORTS_EXTENDED_NAMES(attributes))
|
if (SUPPORTS_EXTENDED_NAMES(attributes))
|
||||||
ph->hops->extended_name_get(ph,
|
ph->hops->extended_name_get(ph,
|
||||||
VOLTAGE_DOMAIN_NAME_GET,
|
VOLTAGE_DOMAIN_NAME_GET,
|
||||||
v->id, v->name,
|
v->id, NULL, v->name,
|
||||||
SCMI_MAX_STR_SIZE);
|
SCMI_MAX_STR_SIZE);
|
||||||
if (SUPPORTS_ASYNC_LEVEL_SET(attributes))
|
if (SUPPORTS_ASYNC_LEVEL_SET(attributes))
|
||||||
v->async_level_set = true;
|
v->async_level_set = true;
|
||||||
@ -432,7 +435,7 @@ static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
|
|||||||
dev_warn(ph->dev, "No Voltage domains found.\n");
|
dev_warn(ph->dev, "No Voltage domains found.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ph->set_priv(ph, vinfo);
|
return ph->set_priv(ph, vinfo, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct scmi_protocol scmi_voltage = {
|
static const struct scmi_protocol scmi_voltage = {
|
||||||
@ -440,6 +443,7 @@ static const struct scmi_protocol scmi_voltage = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.instance_init = &scmi_voltage_protocol_init,
|
.instance_init = &scmi_voltage_protocol_init,
|
||||||
.ops = &voltage_proto_ops,
|
.ops = &voltage_proto_ops,
|
||||||
|
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage)
|
DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage)
|
||||||
|
@ -274,14 +274,11 @@ static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
|
|||||||
|
|
||||||
static DEVICE_ATTR_RO(serial);
|
static DEVICE_ATTR_RO(serial);
|
||||||
|
|
||||||
static struct attribute *meson_sm_sysfs_attributes[] = {
|
static struct attribute *meson_sm_sysfs_attrs[] = {
|
||||||
&dev_attr_serial.attr,
|
&dev_attr_serial.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
ATTRIBUTE_GROUPS(meson_sm_sysfs);
|
||||||
static const struct attribute_group meson_sm_sysfs_attr_group = {
|
|
||||||
.attrs = meson_sm_sysfs_attributes,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct of_device_id meson_sm_ids[] = {
|
static const struct of_device_id meson_sm_ids[] = {
|
||||||
{ .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip },
|
{ .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip },
|
||||||
@ -313,7 +310,7 @@ static int __init meson_sm_probe(struct platform_device *pdev)
|
|||||||
fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
|
fw->sm_shmem_out_base = meson_sm_map_shmem(chip->cmd_shmem_out_base,
|
||||||
chip->shmem_size);
|
chip->shmem_size);
|
||||||
if (WARN_ON(!fw->sm_shmem_out_base))
|
if (WARN_ON(!fw->sm_shmem_out_base))
|
||||||
goto out_in_base;
|
goto unmap_in_base;
|
||||||
}
|
}
|
||||||
|
|
||||||
fw->chip = chip;
|
fw->chip = chip;
|
||||||
@ -321,16 +318,15 @@ static int __init meson_sm_probe(struct platform_device *pdev)
|
|||||||
platform_set_drvdata(pdev, fw);
|
platform_set_drvdata(pdev, fw);
|
||||||
|
|
||||||
if (devm_of_platform_populate(dev))
|
if (devm_of_platform_populate(dev))
|
||||||
goto out_in_base;
|
goto unmap_out_base;
|
||||||
|
|
||||||
if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group))
|
|
||||||
goto out_in_base;
|
|
||||||
|
|
||||||
pr_info("secure-monitor enabled\n");
|
pr_info("secure-monitor enabled\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_in_base:
|
unmap_out_base:
|
||||||
|
iounmap(fw->sm_shmem_out_base);
|
||||||
|
unmap_in_base:
|
||||||
iounmap(fw->sm_shmem_in_base);
|
iounmap(fw->sm_shmem_in_base);
|
||||||
out:
|
out:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -340,6 +336,7 @@ static struct platform_driver meson_sm_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = "meson-sm",
|
.name = "meson-sm",
|
||||||
.of_match_table = of_match_ptr(meson_sm_ids),
|
.of_match_table = of_match_ptr(meson_sm_ids),
|
||||||
|
.dev_groups = meson_sm_sysfs_groups,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
module_platform_driver_probe(meson_sm_driver, meson_sm_probe);
|
module_platform_driver_probe(meson_sm_driver, meson_sm_probe);
|
||||||
|
12
drivers/firmware/microchip/Kconfig
Normal file
12
drivers/firmware/microchip/Kconfig
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
config POLARFIRE_SOC_AUTO_UPDATE
|
||||||
|
tristate "Microchip PolarFire SoC AUTO UPDATE"
|
||||||
|
depends on POLARFIRE_SOC_SYS_CTRL
|
||||||
|
select FW_LOADER
|
||||||
|
select FW_UPLOAD
|
||||||
|
help
|
||||||
|
Support for reprogramming PolarFire SoC from within Linux, using the
|
||||||
|
Auto Upgrade feature of the system controller.
|
||||||
|
|
||||||
|
If built as a module, it will be called mpfs-auto-update.
|
3
drivers/firmware/microchip/Makefile
Normal file
3
drivers/firmware/microchip/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
obj-$(CONFIG_POLARFIRE_SOC_AUTO_UPDATE) += mpfs-auto-update.o
|
494
drivers/firmware/microchip/mpfs-auto-update.c
Normal file
494
drivers/firmware/microchip/mpfs-auto-update.c
Normal file
@ -0,0 +1,494 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Microchip Polarfire SoC "Auto Update" FPGA reprogramming.
|
||||||
|
*
|
||||||
|
* Documentation of this functionality is available in the "PolarFire® FPGA and
|
||||||
|
* PolarFire SoC FPGA Programming" User Guide.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022-2023 Microchip Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* Author: Conor Dooley <conor.dooley@microchip.com>
|
||||||
|
*/
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#include <linux/math.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mtd/mtd.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/sizes.h>
|
||||||
|
|
||||||
|
#include <soc/microchip/mpfs.h>
|
||||||
|
|
||||||
|
#define AUTO_UPDATE_DEFAULT_MBOX_OFFSET 0u
|
||||||
|
#define AUTO_UPDATE_DEFAULT_RESP_OFFSET 0u
|
||||||
|
|
||||||
|
#define AUTO_UPDATE_FEATURE_CMD_OPCODE 0x05u
|
||||||
|
#define AUTO_UPDATE_FEATURE_CMD_DATA_SIZE 0u
|
||||||
|
#define AUTO_UPDATE_FEATURE_RESP_SIZE 33u
|
||||||
|
#define AUTO_UPDATE_FEATURE_CMD_DATA NULL
|
||||||
|
#define AUTO_UPDATE_FEATURE_ENABLED BIT(5)
|
||||||
|
|
||||||
|
#define AUTO_UPDATE_AUTHENTICATE_CMD_OPCODE 0x22u
|
||||||
|
#define AUTO_UPDATE_AUTHENTICATE_CMD_DATA_SIZE 0u
|
||||||
|
#define AUTO_UPDATE_AUTHENTICATE_RESP_SIZE 1u
|
||||||
|
#define AUTO_UPDATE_AUTHENTICATE_CMD_DATA NULL
|
||||||
|
|
||||||
|
#define AUTO_UPDATE_PROGRAM_CMD_OPCODE 0x46u
|
||||||
|
#define AUTO_UPDATE_PROGRAM_CMD_DATA_SIZE 0u
|
||||||
|
#define AUTO_UPDATE_PROGRAM_RESP_SIZE 1u
|
||||||
|
#define AUTO_UPDATE_PROGRAM_CMD_DATA NULL
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPI Flash layout example:
|
||||||
|
* |------------------------------| 0x0000000
|
||||||
|
* | 1 KiB |
|
||||||
|
* | SPI "directories" |
|
||||||
|
* |------------------------------| 0x0000400
|
||||||
|
* | 1 MiB |
|
||||||
|
* | Reserved area |
|
||||||
|
* | Used for bitstream info |
|
||||||
|
* |------------------------------| 0x0100400
|
||||||
|
* | 20 MiB |
|
||||||
|
* | Golden Image |
|
||||||
|
* |------------------------------| 0x1500400
|
||||||
|
* | 20 MiB |
|
||||||
|
* | Auto Upgrade Image |
|
||||||
|
* |------------------------------| 0x2900400
|
||||||
|
* | 20 MiB |
|
||||||
|
* | Reserved for multi-image IAP |
|
||||||
|
* | Unused for Auto Upgrade |
|
||||||
|
* |------------------------------| 0x3D00400
|
||||||
|
* | ? B |
|
||||||
|
* | Unused |
|
||||||
|
* |------------------------------| 0x?
|
||||||
|
*/
|
||||||
|
#define AUTO_UPDATE_DIRECTORY_BASE 0u
|
||||||
|
#define AUTO_UPDATE_DIRECTORY_WIDTH 4u
|
||||||
|
#define AUTO_UPDATE_GOLDEN_INDEX 0u
|
||||||
|
#define AUTO_UPDATE_UPGRADE_INDEX 1u
|
||||||
|
#define AUTO_UPDATE_BLANK_INDEX 2u
|
||||||
|
#define AUTO_UPDATE_GOLDEN_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_GOLDEN_INDEX)
|
||||||
|
#define AUTO_UPDATE_UPGRADE_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_UPGRADE_INDEX)
|
||||||
|
#define AUTO_UPDATE_BLANK_DIRECTORY (AUTO_UPDATE_DIRECTORY_WIDTH * AUTO_UPDATE_BLANK_INDEX)
|
||||||
|
#define AUTO_UPDATE_DIRECTORY_SIZE SZ_1K
|
||||||
|
#define AUTO_UPDATE_RESERVED_SIZE SZ_1M
|
||||||
|
#define AUTO_UPDATE_BITSTREAM_BASE (AUTO_UPDATE_DIRECTORY_SIZE + AUTO_UPDATE_RESERVED_SIZE)
|
||||||
|
|
||||||
|
#define AUTO_UPDATE_TIMEOUT_MS 60000
|
||||||
|
|
||||||
|
struct mpfs_auto_update_priv {
|
||||||
|
struct mpfs_sys_controller *sys_controller;
|
||||||
|
struct device *dev;
|
||||||
|
struct mtd_info *flash;
|
||||||
|
struct fw_upload *fw_uploader;
|
||||||
|
struct completion programming_complete;
|
||||||
|
size_t size_per_bitstream;
|
||||||
|
bool cancel_request;
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum fw_upload_err mpfs_auto_update_prepare(struct fw_upload *fw_uploader, const u8 *data,
|
||||||
|
u32 size)
|
||||||
|
{
|
||||||
|
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
|
||||||
|
size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verifying the Golden Image is idealistic. It will be evaluated
|
||||||
|
* against the currently programmed image and thus may fail - due to
|
||||||
|
* either rollback protection (if its an older version than that in use)
|
||||||
|
* or if the version is the same as that of the in-use image.
|
||||||
|
* Extracting the information as to why a failure occurred is not
|
||||||
|
* currently possible due to limitations of the system controller
|
||||||
|
* driver. If those are fixed, verification of the Golden Image should
|
||||||
|
* be added here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
priv->flash = mpfs_sys_controller_get_flash(priv->sys_controller);
|
||||||
|
if (!priv->flash)
|
||||||
|
return FW_UPLOAD_ERR_HW_ERROR;
|
||||||
|
|
||||||
|
erase_size = round_up(erase_size, (u64)priv->flash->erasesize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to calculate if we have enough space in the flash for the
|
||||||
|
* new image.
|
||||||
|
* First, chop off the first 1 KiB as it's reserved for the directory.
|
||||||
|
* The 1 MiB reserved for design info needs to be ignored also.
|
||||||
|
* All that remains is carved into 3 & rounded down to the erasesize.
|
||||||
|
* If this is smaller than the image size, we abort.
|
||||||
|
* There's also no need to consume more than 20 MiB per image.
|
||||||
|
*/
|
||||||
|
priv->size_per_bitstream = priv->flash->size - SZ_1K - SZ_1M;
|
||||||
|
priv->size_per_bitstream = round_down(priv->size_per_bitstream / 3, erase_size);
|
||||||
|
if (priv->size_per_bitstream > 20 * SZ_1M)
|
||||||
|
priv->size_per_bitstream = 20 * SZ_1M;
|
||||||
|
|
||||||
|
if (priv->size_per_bitstream < size) {
|
||||||
|
dev_err(priv->dev,
|
||||||
|
"flash device has insufficient capacity to store this bitstream\n");
|
||||||
|
return FW_UPLOAD_ERR_INVALID_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->cancel_request = false;
|
||||||
|
|
||||||
|
return FW_UPLOAD_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpfs_auto_update_cancel(struct fw_upload *fw_uploader)
|
||||||
|
{
|
||||||
|
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
|
||||||
|
|
||||||
|
priv->cancel_request = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum fw_upload_err mpfs_auto_update_poll_complete(struct fw_upload *fw_uploader)
|
||||||
|
{
|
||||||
|
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is no meaningful way to get the status of the programming while
|
||||||
|
* it is in progress, so attempting anything other than waiting for it
|
||||||
|
* to complete would be misplaced.
|
||||||
|
*/
|
||||||
|
ret = wait_for_completion_timeout(&priv->programming_complete,
|
||||||
|
msecs_to_jiffies(AUTO_UPDATE_TIMEOUT_MS));
|
||||||
|
if (ret)
|
||||||
|
return FW_UPLOAD_ERR_TIMEOUT;
|
||||||
|
|
||||||
|
return FW_UPLOAD_ERR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mpfs_auto_update_verify_image(struct fw_upload *fw_uploader)
|
||||||
|
{
|
||||||
|
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
|
||||||
|
struct mpfs_mss_response *response;
|
||||||
|
struct mpfs_mss_msg *message;
|
||||||
|
u32 *response_msg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(response_msg),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!response_msg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
response = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_response), GFP_KERNEL);
|
||||||
|
if (!response) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto free_response_msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
message = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_msg), GFP_KERNEL);
|
||||||
|
if (!message) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto free_response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The system controller can verify that an image in the flash is valid.
|
||||||
|
* Rather than duplicate the check in this driver, call the relevant
|
||||||
|
* service from the system controller instead.
|
||||||
|
* This service has no command data and no response data. It overloads
|
||||||
|
* mbox_offset with the image index in the flash's SPI directory where
|
||||||
|
* the bitstream is located.
|
||||||
|
*/
|
||||||
|
response->resp_msg = response_msg;
|
||||||
|
response->resp_size = AUTO_UPDATE_AUTHENTICATE_RESP_SIZE;
|
||||||
|
message->cmd_opcode = AUTO_UPDATE_AUTHENTICATE_CMD_OPCODE;
|
||||||
|
message->cmd_data_size = AUTO_UPDATE_AUTHENTICATE_CMD_DATA_SIZE;
|
||||||
|
message->response = response;
|
||||||
|
message->cmd_data = AUTO_UPDATE_AUTHENTICATE_CMD_DATA;
|
||||||
|
message->mbox_offset = AUTO_UPDATE_UPGRADE_INDEX;
|
||||||
|
message->resp_offset = AUTO_UPDATE_DEFAULT_RESP_OFFSET;
|
||||||
|
|
||||||
|
dev_info(priv->dev, "Running verification of Upgrade Image\n");
|
||||||
|
ret = mpfs_blocking_transaction(priv->sys_controller, message);
|
||||||
|
if (ret | response->resp_status) {
|
||||||
|
dev_warn(priv->dev, "Verification of Upgrade Image failed!\n");
|
||||||
|
ret = ret ? ret : -EBADMSG;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(priv->dev, "Verification of Upgrade Image passed!\n");
|
||||||
|
|
||||||
|
devm_kfree(priv->dev, message);
|
||||||
|
free_response:
|
||||||
|
devm_kfree(priv->dev, response);
|
||||||
|
free_response_msg:
|
||||||
|
devm_kfree(priv->dev, response_msg);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mpfs_auto_update_set_image_address(struct mpfs_auto_update_priv *priv, char *buffer,
|
||||||
|
u32 image_address, loff_t directory_address)
|
||||||
|
{
|
||||||
|
struct erase_info erase;
|
||||||
|
size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE;
|
||||||
|
size_t bytes_written = 0, bytes_read = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
erase_size = round_up(erase_size, (u64)priv->flash->erasesize);
|
||||||
|
|
||||||
|
erase.addr = AUTO_UPDATE_DIRECTORY_BASE;
|
||||||
|
erase.len = erase_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to write the "SPI DIRECTORY" to the first 1 KiB, telling
|
||||||
|
* the system controller where to find the actual bitstream. Since
|
||||||
|
* this is spi-nor, we have to read the first eraseblock, erase that
|
||||||
|
* portion of the flash, modify the data and then write it back.
|
||||||
|
* There's no need to do this though if things are already the way they
|
||||||
|
* should be, so check and save the write in that case.
|
||||||
|
*/
|
||||||
|
ret = mtd_read(priv->flash, AUTO_UPDATE_DIRECTORY_BASE, erase_size, &bytes_read,
|
||||||
|
(u_char *)buffer);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (bytes_read != erase_size)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
if ((*(u32 *)(buffer + AUTO_UPDATE_UPGRADE_DIRECTORY) == image_address) &&
|
||||||
|
!(*(u32 *)(buffer + AUTO_UPDATE_BLANK_DIRECTORY)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = mtd_erase(priv->flash, &erase);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Populate the image address and then zero out the next directory so
|
||||||
|
* that the system controller doesn't complain if in "Single Image"
|
||||||
|
* mode.
|
||||||
|
*/
|
||||||
|
memcpy(buffer + AUTO_UPDATE_UPGRADE_DIRECTORY, &image_address,
|
||||||
|
AUTO_UPDATE_DIRECTORY_WIDTH);
|
||||||
|
memset(buffer + AUTO_UPDATE_BLANK_DIRECTORY, 0x0, AUTO_UPDATE_DIRECTORY_WIDTH);
|
||||||
|
|
||||||
|
dev_info(priv->dev, "Writing the image address (%x) to the flash directory (%llx)\n",
|
||||||
|
image_address, directory_address);
|
||||||
|
|
||||||
|
ret = mtd_write(priv->flash, 0x0, erase_size, &bytes_written, (u_char *)buffer);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (bytes_written != erase_size)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mpfs_auto_update_write_bitstream(struct fw_upload *fw_uploader, const u8 *data,
|
||||||
|
u32 offset, u32 size, u32 *written)
|
||||||
|
{
|
||||||
|
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
|
||||||
|
struct erase_info erase;
|
||||||
|
char *buffer;
|
||||||
|
loff_t directory_address = AUTO_UPDATE_UPGRADE_DIRECTORY;
|
||||||
|
size_t erase_size = AUTO_UPDATE_DIRECTORY_SIZE;
|
||||||
|
size_t bytes_written = 0;
|
||||||
|
u32 image_address;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
erase_size = round_up(erase_size, (u64)priv->flash->erasesize);
|
||||||
|
|
||||||
|
image_address = AUTO_UPDATE_BITSTREAM_BASE +
|
||||||
|
AUTO_UPDATE_UPGRADE_INDEX * priv->size_per_bitstream;
|
||||||
|
|
||||||
|
buffer = devm_kzalloc(priv->dev, erase_size, GFP_KERNEL);
|
||||||
|
if (!buffer)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = mpfs_auto_update_set_image_address(priv, buffer, image_address, directory_address);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(priv->dev, "failed to set image address in the SPI directory: %d\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now the .spi image itself can be written to the flash. Preservation
|
||||||
|
* of contents here is not important here, unlike the spi "directory"
|
||||||
|
* which must be RMWed.
|
||||||
|
*/
|
||||||
|
erase.len = round_up(size, (size_t)priv->flash->erasesize);
|
||||||
|
erase.addr = image_address;
|
||||||
|
|
||||||
|
dev_info(priv->dev, "Erasing the flash at address (%x)\n", image_address);
|
||||||
|
ret = mtd_erase(priv->flash, &erase);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No parsing etc of the bitstream is required. The system controller
|
||||||
|
* will do all of that itself - including verifying that the bitstream
|
||||||
|
* is valid.
|
||||||
|
*/
|
||||||
|
dev_info(priv->dev, "Writing the image to the flash at address (%x)\n", image_address);
|
||||||
|
ret = mtd_write(priv->flash, (loff_t)image_address, size, &bytes_written, data);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (bytes_written != size) {
|
||||||
|
ret = -EIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*written = bytes_written;
|
||||||
|
|
||||||
|
out:
|
||||||
|
devm_kfree(priv->dev, buffer);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum fw_upload_err mpfs_auto_update_write(struct fw_upload *fw_uploader, const u8 *data,
|
||||||
|
u32 offset, u32 size, u32 *written)
|
||||||
|
{
|
||||||
|
struct mpfs_auto_update_priv *priv = fw_uploader->dd_handle;
|
||||||
|
enum fw_upload_err err = FW_UPLOAD_ERR_NONE;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
reinit_completion(&priv->programming_complete);
|
||||||
|
|
||||||
|
ret = mpfs_auto_update_write_bitstream(fw_uploader, data, offset, size, written);
|
||||||
|
if (ret) {
|
||||||
|
err = FW_UPLOAD_ERR_RW_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->cancel_request) {
|
||||||
|
err = FW_UPLOAD_ERR_CANCELED;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mpfs_auto_update_verify_image(fw_uploader);
|
||||||
|
if (ret)
|
||||||
|
err = FW_UPLOAD_ERR_FW_INVALID;
|
||||||
|
|
||||||
|
out:
|
||||||
|
complete(&priv->programming_complete);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct fw_upload_ops mpfs_auto_update_ops = {
|
||||||
|
.prepare = mpfs_auto_update_prepare,
|
||||||
|
.write = mpfs_auto_update_write,
|
||||||
|
.poll_complete = mpfs_auto_update_poll_complete,
|
||||||
|
.cancel = mpfs_auto_update_cancel,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mpfs_auto_update_available(struct mpfs_auto_update_priv *priv)
|
||||||
|
{
|
||||||
|
struct mpfs_mss_response *response;
|
||||||
|
struct mpfs_mss_msg *message;
|
||||||
|
u32 *response_msg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
response_msg = devm_kzalloc(priv->dev, AUTO_UPDATE_FEATURE_RESP_SIZE * sizeof(response_msg),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!response_msg)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
response = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_response), GFP_KERNEL);
|
||||||
|
if (!response)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
message = devm_kzalloc(priv->dev, sizeof(struct mpfs_mss_msg), GFP_KERNEL);
|
||||||
|
if (!message)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To verify that Auto Update is possible, the "Query Security Service
|
||||||
|
* Request" is performed.
|
||||||
|
* This service has no command data & does not overload mbox_offset.
|
||||||
|
*/
|
||||||
|
response->resp_msg = response_msg;
|
||||||
|
response->resp_size = AUTO_UPDATE_FEATURE_RESP_SIZE;
|
||||||
|
message->cmd_opcode = AUTO_UPDATE_FEATURE_CMD_OPCODE;
|
||||||
|
message->cmd_data_size = AUTO_UPDATE_FEATURE_CMD_DATA_SIZE;
|
||||||
|
message->response = response;
|
||||||
|
message->cmd_data = AUTO_UPDATE_FEATURE_CMD_DATA;
|
||||||
|
message->mbox_offset = AUTO_UPDATE_DEFAULT_MBOX_OFFSET;
|
||||||
|
message->resp_offset = AUTO_UPDATE_DEFAULT_RESP_OFFSET;
|
||||||
|
|
||||||
|
ret = mpfs_blocking_transaction(priv->sys_controller, message);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Currently, the system controller's firmware does not generate any
|
||||||
|
* interrupts for failed services, so mpfs_blocking_transaction() should
|
||||||
|
* time out & therefore return an error.
|
||||||
|
* Hitting this check is highly unlikely at present, but if the system
|
||||||
|
* controller's behaviour changes so that it does generate interrupts
|
||||||
|
* for failed services, it will be required.
|
||||||
|
*/
|
||||||
|
if (response->resp_status)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bit 5 of byte 1 is "UL_Auto Update" & if it is set, Auto Update is
|
||||||
|
* not possible.
|
||||||
|
*/
|
||||||
|
if (response_msg[1] & AUTO_UPDATE_FEATURE_ENABLED)
|
||||||
|
return -EPERM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mpfs_auto_update_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct mpfs_auto_update_priv *priv;
|
||||||
|
struct fw_upload *fw_uploader;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
priv->sys_controller = mpfs_sys_controller_get(dev);
|
||||||
|
if (IS_ERR(priv->sys_controller))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(priv->sys_controller),
|
||||||
|
"Could not register as a sub device of the system controller\n");
|
||||||
|
|
||||||
|
priv->dev = dev;
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
|
ret = mpfs_auto_update_available(priv);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret,
|
||||||
|
"The current bitstream does not support auto-update\n");
|
||||||
|
|
||||||
|
init_completion(&priv->programming_complete);
|
||||||
|
|
||||||
|
fw_uploader = firmware_upload_register(THIS_MODULE, dev, "mpfs-auto-update",
|
||||||
|
&mpfs_auto_update_ops, priv);
|
||||||
|
if (IS_ERR(fw_uploader))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(fw_uploader),
|
||||||
|
"Failed to register the bitstream uploader\n");
|
||||||
|
|
||||||
|
priv->fw_uploader = fw_uploader;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mpfs_auto_update_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct mpfs_auto_update_priv *priv = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
firmware_upload_unregister(priv->fw_uploader);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver mpfs_auto_update_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "mpfs-auto-update",
|
||||||
|
},
|
||||||
|
.probe = mpfs_auto_update_probe,
|
||||||
|
.remove_new = mpfs_auto_update_remove,
|
||||||
|
};
|
||||||
|
module_platform_driver(mpfs_auto_update_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");
|
||||||
|
MODULE_DESCRIPTION("PolarFire SoC Auto Update FPGA reprogramming");
|
@ -325,8 +325,10 @@ static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const e
|
|||||||
req_data->length = req_size;
|
req_data->length = req_size;
|
||||||
|
|
||||||
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
|
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
|
||||||
if (status < 0)
|
if (status < 0) {
|
||||||
return EFI_INVALID_PARAMETER;
|
efi_status = EFI_INVALID_PARAMETER;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
|
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
|
||||||
|
|
||||||
@ -471,8 +473,10 @@ static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const e
|
|||||||
req_data->length = req_size;
|
req_data->length = req_size;
|
||||||
|
|
||||||
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
|
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
|
||||||
if (status < 0)
|
if (status < 0) {
|
||||||
return EFI_INVALID_PARAMETER;
|
efi_status = EFI_INVALID_PARAMETER;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
|
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
|
||||||
|
|
||||||
@ -563,8 +567,10 @@ static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
|
|||||||
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
|
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
|
||||||
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
|
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
|
||||||
*name_size / sizeof(*name));
|
*name_size / sizeof(*name));
|
||||||
if (status < 0)
|
if (status < 0) {
|
||||||
return EFI_INVALID_PARAMETER;
|
efi_status = EFI_INVALID_PARAMETER;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
|
status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
|
||||||
if (status) {
|
if (status) {
|
||||||
@ -635,7 +641,7 @@ static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
|
|||||||
* have already been validated above, causing this function to
|
* have already been validated above, causing this function to
|
||||||
* bail with EFI_BUFFER_TOO_SMALL.
|
* bail with EFI_BUFFER_TOO_SMALL.
|
||||||
*/
|
*/
|
||||||
return EFI_DEVICE_ERROR;
|
efi_status = EFI_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
|
@ -164,7 +164,7 @@ static int ti_sci_debugfs_create(struct platform_device *pdev,
|
|||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
char debug_name[50] = "ti_sci_debug@";
|
char debug_name[50];
|
||||||
|
|
||||||
/* Debug region is optional */
|
/* Debug region is optional */
|
||||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||||
@ -181,10 +181,10 @@ static int ti_sci_debugfs_create(struct platform_device *pdev,
|
|||||||
/* Setup NULL termination */
|
/* Setup NULL termination */
|
||||||
info->debug_buffer[info->debug_region_size] = 0;
|
info->debug_buffer[info->debug_region_size] = 0;
|
||||||
|
|
||||||
info->d = debugfs_create_file(strncat(debug_name, dev_name(dev),
|
snprintf(debug_name, sizeof(debug_name), "ti_sci_debug@%s",
|
||||||
sizeof(debug_name) -
|
dev_name(dev));
|
||||||
sizeof("ti_sci_debug@")),
|
info->d = debugfs_create_file(debug_name, 0444, NULL, info,
|
||||||
0444, NULL, info, &ti_sci_debug_fops);
|
&ti_sci_debug_fops);
|
||||||
if (IS_ERR(info->d))
|
if (IS_ERR(info->d))
|
||||||
return PTR_ERR(info->d);
|
return PTR_ERR(info->d);
|
||||||
|
|
||||||
|
@ -8,18 +8,6 @@ menuconfig MAILBOX
|
|||||||
|
|
||||||
if MAILBOX
|
if MAILBOX
|
||||||
|
|
||||||
config APPLE_MAILBOX
|
|
||||||
tristate "Apple Mailbox driver"
|
|
||||||
depends on ARCH_APPLE || (ARM64 && COMPILE_TEST)
|
|
||||||
default ARCH_APPLE
|
|
||||||
help
|
|
||||||
Apple SoCs have various co-processors required for certain
|
|
||||||
peripherals to work (NVMe, display controller, etc.). This
|
|
||||||
driver adds support for the mailbox controller used to
|
|
||||||
communicate with those.
|
|
||||||
|
|
||||||
Say Y here if you have a Apple SoC.
|
|
||||||
|
|
||||||
config ARM_MHU
|
config ARM_MHU
|
||||||
tristate "ARM MHU Mailbox"
|
tristate "ARM MHU Mailbox"
|
||||||
depends on ARM_AMBA
|
depends on ARM_AMBA
|
||||||
|
@ -60,5 +60,3 @@ obj-$(CONFIG_SUN6I_MSGBOX) += sun6i-msgbox.o
|
|||||||
obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o
|
obj-$(CONFIG_SPRD_MBOX) += sprd-mailbox.o
|
||||||
|
|
||||||
obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o
|
obj-$(CONFIG_QCOM_IPCC) += qcom-ipcc.o
|
||||||
|
|
||||||
obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o
|
|
||||||
|
@ -1,441 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
|
||||||
/*
|
|
||||||
* Apple mailbox driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2021 The Asahi Linux Contributors
|
|
||||||
*
|
|
||||||
* This driver adds support for two mailbox variants (called ASC and M3 by
|
|
||||||
* Apple) found in Apple SoCs such as the M1. It consists of two FIFOs used to
|
|
||||||
* exchange 64+32 bit messages between the main CPU and a co-processor.
|
|
||||||
* Various coprocessors implement different IPC protocols based on these simple
|
|
||||||
* messages and shared memory buffers.
|
|
||||||
*
|
|
||||||
* Both the main CPU and the co-processor see the same set of registers but
|
|
||||||
* the first FIFO (A2I) is always used to transfer messages from the application
|
|
||||||
* processor (us) to the I/O processor and the second one (I2A) for the
|
|
||||||
* other direction.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/apple-mailbox.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/gfp.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/io.h>
|
|
||||||
#include <linux/mailbox_controller.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/platform_device.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/types.h>
|
|
||||||
|
|
||||||
#define APPLE_ASC_MBOX_CONTROL_FULL BIT(16)
|
|
||||||
#define APPLE_ASC_MBOX_CONTROL_EMPTY BIT(17)
|
|
||||||
|
|
||||||
#define APPLE_ASC_MBOX_A2I_CONTROL 0x110
|
|
||||||
#define APPLE_ASC_MBOX_A2I_SEND0 0x800
|
|
||||||
#define APPLE_ASC_MBOX_A2I_SEND1 0x808
|
|
||||||
#define APPLE_ASC_MBOX_A2I_RECV0 0x810
|
|
||||||
#define APPLE_ASC_MBOX_A2I_RECV1 0x818
|
|
||||||
|
|
||||||
#define APPLE_ASC_MBOX_I2A_CONTROL 0x114
|
|
||||||
#define APPLE_ASC_MBOX_I2A_SEND0 0x820
|
|
||||||
#define APPLE_ASC_MBOX_I2A_SEND1 0x828
|
|
||||||
#define APPLE_ASC_MBOX_I2A_RECV0 0x830
|
|
||||||
#define APPLE_ASC_MBOX_I2A_RECV1 0x838
|
|
||||||
|
|
||||||
#define APPLE_M3_MBOX_CONTROL_FULL BIT(16)
|
|
||||||
#define APPLE_M3_MBOX_CONTROL_EMPTY BIT(17)
|
|
||||||
|
|
||||||
#define APPLE_M3_MBOX_A2I_CONTROL 0x50
|
|
||||||
#define APPLE_M3_MBOX_A2I_SEND0 0x60
|
|
||||||
#define APPLE_M3_MBOX_A2I_SEND1 0x68
|
|
||||||
#define APPLE_M3_MBOX_A2I_RECV0 0x70
|
|
||||||
#define APPLE_M3_MBOX_A2I_RECV1 0x78
|
|
||||||
|
|
||||||
#define APPLE_M3_MBOX_I2A_CONTROL 0x80
|
|
||||||
#define APPLE_M3_MBOX_I2A_SEND0 0x90
|
|
||||||
#define APPLE_M3_MBOX_I2A_SEND1 0x98
|
|
||||||
#define APPLE_M3_MBOX_I2A_RECV0 0xa0
|
|
||||||
#define APPLE_M3_MBOX_I2A_RECV1 0xa8
|
|
||||||
|
|
||||||
#define APPLE_M3_MBOX_IRQ_ENABLE 0x48
|
|
||||||
#define APPLE_M3_MBOX_IRQ_ACK 0x4c
|
|
||||||
#define APPLE_M3_MBOX_IRQ_A2I_EMPTY BIT(0)
|
|
||||||
#define APPLE_M3_MBOX_IRQ_A2I_NOT_EMPTY BIT(1)
|
|
||||||
#define APPLE_M3_MBOX_IRQ_I2A_EMPTY BIT(2)
|
|
||||||
#define APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY BIT(3)
|
|
||||||
|
|
||||||
#define APPLE_MBOX_MSG1_OUTCNT GENMASK(56, 52)
|
|
||||||
#define APPLE_MBOX_MSG1_INCNT GENMASK(51, 48)
|
|
||||||
#define APPLE_MBOX_MSG1_OUTPTR GENMASK(47, 44)
|
|
||||||
#define APPLE_MBOX_MSG1_INPTR GENMASK(43, 40)
|
|
||||||
#define APPLE_MBOX_MSG1_MSG GENMASK(31, 0)
|
|
||||||
|
|
||||||
struct apple_mbox_hw {
|
|
||||||
unsigned int control_full;
|
|
||||||
unsigned int control_empty;
|
|
||||||
|
|
||||||
unsigned int a2i_control;
|
|
||||||
unsigned int a2i_send0;
|
|
||||||
unsigned int a2i_send1;
|
|
||||||
|
|
||||||
unsigned int i2a_control;
|
|
||||||
unsigned int i2a_recv0;
|
|
||||||
unsigned int i2a_recv1;
|
|
||||||
|
|
||||||
bool has_irq_controls;
|
|
||||||
unsigned int irq_enable;
|
|
||||||
unsigned int irq_ack;
|
|
||||||
unsigned int irq_bit_recv_not_empty;
|
|
||||||
unsigned int irq_bit_send_empty;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct apple_mbox {
|
|
||||||
void __iomem *regs;
|
|
||||||
const struct apple_mbox_hw *hw;
|
|
||||||
|
|
||||||
int irq_recv_not_empty;
|
|
||||||
int irq_send_empty;
|
|
||||||
|
|
||||||
struct mbox_chan chan;
|
|
||||||
|
|
||||||
struct device *dev;
|
|
||||||
struct mbox_controller controller;
|
|
||||||
spinlock_t rx_lock;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct of_device_id apple_mbox_of_match[];
|
|
||||||
|
|
||||||
static bool apple_mbox_hw_can_send(struct apple_mbox *apple_mbox)
|
|
||||||
{
|
|
||||||
u32 mbox_ctrl =
|
|
||||||
readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control);
|
|
||||||
|
|
||||||
return !(mbox_ctrl & apple_mbox->hw->control_full);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool apple_mbox_hw_send_empty(struct apple_mbox *apple_mbox)
|
|
||||||
{
|
|
||||||
u32 mbox_ctrl =
|
|
||||||
readl_relaxed(apple_mbox->regs + apple_mbox->hw->a2i_control);
|
|
||||||
|
|
||||||
return mbox_ctrl & apple_mbox->hw->control_empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apple_mbox_hw_send(struct apple_mbox *apple_mbox,
|
|
||||||
struct apple_mbox_msg *msg)
|
|
||||||
{
|
|
||||||
if (!apple_mbox_hw_can_send(apple_mbox))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
dev_dbg(apple_mbox->dev, "> TX %016llx %08x\n", msg->msg0, msg->msg1);
|
|
||||||
|
|
||||||
writeq_relaxed(msg->msg0, apple_mbox->regs + apple_mbox->hw->a2i_send0);
|
|
||||||
writeq_relaxed(FIELD_PREP(APPLE_MBOX_MSG1_MSG, msg->msg1),
|
|
||||||
apple_mbox->regs + apple_mbox->hw->a2i_send1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool apple_mbox_hw_can_recv(struct apple_mbox *apple_mbox)
|
|
||||||
{
|
|
||||||
u32 mbox_ctrl =
|
|
||||||
readl_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_control);
|
|
||||||
|
|
||||||
return !(mbox_ctrl & apple_mbox->hw->control_empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apple_mbox_hw_recv(struct apple_mbox *apple_mbox,
|
|
||||||
struct apple_mbox_msg *msg)
|
|
||||||
{
|
|
||||||
if (!apple_mbox_hw_can_recv(apple_mbox))
|
|
||||||
return -ENOMSG;
|
|
||||||
|
|
||||||
msg->msg0 = readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv0);
|
|
||||||
msg->msg1 = FIELD_GET(
|
|
||||||
APPLE_MBOX_MSG1_MSG,
|
|
||||||
readq_relaxed(apple_mbox->regs + apple_mbox->hw->i2a_recv1));
|
|
||||||
|
|
||||||
dev_dbg(apple_mbox->dev, "< RX %016llx %08x\n", msg->msg0, msg->msg1);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apple_mbox_chan_send_data(struct mbox_chan *chan, void *data)
|
|
||||||
{
|
|
||||||
struct apple_mbox *apple_mbox = chan->con_priv;
|
|
||||||
struct apple_mbox_msg *msg = data;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = apple_mbox_hw_send(apple_mbox, msg);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The interrupt is level triggered and will keep firing as long as the
|
|
||||||
* FIFO is empty. It will also keep firing if the FIFO was empty
|
|
||||||
* at any point in the past until it has been acknowledged at the
|
|
||||||
* mailbox level. By acknowledging it here we can ensure that we will
|
|
||||||
* only get the interrupt once the FIFO has been cleared again.
|
|
||||||
* If the FIFO is already empty before the ack it will fire again
|
|
||||||
* immediately after the ack.
|
|
||||||
*/
|
|
||||||
if (apple_mbox->hw->has_irq_controls) {
|
|
||||||
writel_relaxed(apple_mbox->hw->irq_bit_send_empty,
|
|
||||||
apple_mbox->regs + apple_mbox->hw->irq_ack);
|
|
||||||
}
|
|
||||||
enable_irq(apple_mbox->irq_send_empty);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data)
|
|
||||||
{
|
|
||||||
struct apple_mbox *apple_mbox = data;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We don't need to acknowledge the interrupt at the mailbox level
|
|
||||||
* here even if supported by the hardware. It will keep firing but that
|
|
||||||
* doesn't matter since it's disabled at the main interrupt controller.
|
|
||||||
* apple_mbox_chan_send_data will acknowledge it before enabling
|
|
||||||
* it at the main controller again.
|
|
||||||
*/
|
|
||||||
disable_irq_nosync(apple_mbox->irq_send_empty);
|
|
||||||
mbox_chan_txdone(&apple_mbox->chan, 0);
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apple_mbox_poll(struct apple_mbox *apple_mbox)
|
|
||||||
{
|
|
||||||
struct apple_mbox_msg msg;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
while (apple_mbox_hw_recv(apple_mbox, &msg) == 0) {
|
|
||||||
mbox_chan_received_data(&apple_mbox->chan, (void *)&msg);
|
|
||||||
ret++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The interrupt will keep firing even if there are no more messages
|
|
||||||
* unless we also acknowledge it at the mailbox level here.
|
|
||||||
* There's no race if a message comes in between the check in the while
|
|
||||||
* loop above and the ack below: If a new messages arrives inbetween
|
|
||||||
* those two the interrupt will just fire again immediately after the
|
|
||||||
* ack since it's level triggered.
|
|
||||||
*/
|
|
||||||
if (apple_mbox->hw->has_irq_controls) {
|
|
||||||
writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty,
|
|
||||||
apple_mbox->regs + apple_mbox->hw->irq_ack);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t apple_mbox_recv_irq(int irq, void *data)
|
|
||||||
{
|
|
||||||
struct apple_mbox *apple_mbox = data;
|
|
||||||
|
|
||||||
spin_lock(&apple_mbox->rx_lock);
|
|
||||||
apple_mbox_poll(apple_mbox);
|
|
||||||
spin_unlock(&apple_mbox->rx_lock);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool apple_mbox_chan_peek_data(struct mbox_chan *chan)
|
|
||||||
{
|
|
||||||
struct apple_mbox *apple_mbox = chan->con_priv;
|
|
||||||
unsigned long flags;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&apple_mbox->rx_lock, flags);
|
|
||||||
ret = apple_mbox_poll(apple_mbox);
|
|
||||||
spin_unlock_irqrestore(&apple_mbox->rx_lock, flags);
|
|
||||||
|
|
||||||
return ret > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apple_mbox_chan_flush(struct mbox_chan *chan, unsigned long timeout)
|
|
||||||
{
|
|
||||||
struct apple_mbox *apple_mbox = chan->con_priv;
|
|
||||||
unsigned long deadline = jiffies + msecs_to_jiffies(timeout);
|
|
||||||
|
|
||||||
while (time_before(jiffies, deadline)) {
|
|
||||||
if (apple_mbox_hw_send_empty(apple_mbox)) {
|
|
||||||
mbox_chan_txdone(&apple_mbox->chan, 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
udelay(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ETIME;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apple_mbox_chan_startup(struct mbox_chan *chan)
|
|
||||||
{
|
|
||||||
struct apple_mbox *apple_mbox = chan->con_priv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Only some variants of this mailbox HW provide interrupt control
|
|
||||||
* at the mailbox level. We therefore need to handle enabling/disabling
|
|
||||||
* interrupts at the main interrupt controller anyway for hardware that
|
|
||||||
* doesn't. Just always keep the interrupts we care about enabled at
|
|
||||||
* the mailbox level so that both hardware revisions behave almost
|
|
||||||
* the same.
|
|
||||||
*/
|
|
||||||
if (apple_mbox->hw->has_irq_controls) {
|
|
||||||
writel_relaxed(apple_mbox->hw->irq_bit_recv_not_empty |
|
|
||||||
apple_mbox->hw->irq_bit_send_empty,
|
|
||||||
apple_mbox->regs + apple_mbox->hw->irq_enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
enable_irq(apple_mbox->irq_recv_not_empty);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void apple_mbox_chan_shutdown(struct mbox_chan *chan)
|
|
||||||
{
|
|
||||||
struct apple_mbox *apple_mbox = chan->con_priv;
|
|
||||||
|
|
||||||
disable_irq(apple_mbox->irq_recv_not_empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct mbox_chan_ops apple_mbox_ops = {
|
|
||||||
.send_data = apple_mbox_chan_send_data,
|
|
||||||
.peek_data = apple_mbox_chan_peek_data,
|
|
||||||
.flush = apple_mbox_chan_flush,
|
|
||||||
.startup = apple_mbox_chan_startup,
|
|
||||||
.shutdown = apple_mbox_chan_shutdown,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct mbox_chan *apple_mbox_of_xlate(struct mbox_controller *mbox,
|
|
||||||
const struct of_phandle_args *args)
|
|
||||||
{
|
|
||||||
if (args->args_count != 0)
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
|
|
||||||
return &mbox->chans[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static int apple_mbox_probe(struct platform_device *pdev)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
const struct of_device_id *match;
|
|
||||||
char *irqname;
|
|
||||||
struct apple_mbox *mbox;
|
|
||||||
struct device *dev = &pdev->dev;
|
|
||||||
|
|
||||||
match = of_match_node(apple_mbox_of_match, pdev->dev.of_node);
|
|
||||||
if (!match)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!match->data)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
|
|
||||||
if (!mbox)
|
|
||||||
return -ENOMEM;
|
|
||||||
platform_set_drvdata(pdev, mbox);
|
|
||||||
|
|
||||||
mbox->dev = dev;
|
|
||||||
mbox->regs = devm_platform_ioremap_resource(pdev, 0);
|
|
||||||
if (IS_ERR(mbox->regs))
|
|
||||||
return PTR_ERR(mbox->regs);
|
|
||||||
|
|
||||||
mbox->hw = match->data;
|
|
||||||
mbox->irq_recv_not_empty =
|
|
||||||
platform_get_irq_byname(pdev, "recv-not-empty");
|
|
||||||
if (mbox->irq_recv_not_empty < 0)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
mbox->irq_send_empty = platform_get_irq_byname(pdev, "send-empty");
|
|
||||||
if (mbox->irq_send_empty < 0)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
mbox->controller.dev = mbox->dev;
|
|
||||||
mbox->controller.num_chans = 1;
|
|
||||||
mbox->controller.chans = &mbox->chan;
|
|
||||||
mbox->controller.ops = &apple_mbox_ops;
|
|
||||||
mbox->controller.txdone_irq = true;
|
|
||||||
mbox->controller.of_xlate = apple_mbox_of_xlate;
|
|
||||||
mbox->chan.con_priv = mbox;
|
|
||||||
spin_lock_init(&mbox->rx_lock);
|
|
||||||
|
|
||||||
irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev));
|
|
||||||
if (!irqname)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
ret = devm_request_threaded_irq(dev, mbox->irq_recv_not_empty, NULL,
|
|
||||||
apple_mbox_recv_irq,
|
|
||||||
IRQF_NO_AUTOEN | IRQF_ONESHOT, irqname,
|
|
||||||
mbox);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-send", dev_name(dev));
|
|
||||||
if (!irqname)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
ret = devm_request_irq(dev, mbox->irq_send_empty,
|
|
||||||
apple_mbox_send_empty_irq, IRQF_NO_AUTOEN,
|
|
||||||
irqname, mbox);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
return devm_mbox_controller_register(dev, &mbox->controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct apple_mbox_hw apple_mbox_asc_hw = {
|
|
||||||
.control_full = APPLE_ASC_MBOX_CONTROL_FULL,
|
|
||||||
.control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY,
|
|
||||||
|
|
||||||
.a2i_control = APPLE_ASC_MBOX_A2I_CONTROL,
|
|
||||||
.a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0,
|
|
||||||
.a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1,
|
|
||||||
|
|
||||||
.i2a_control = APPLE_ASC_MBOX_I2A_CONTROL,
|
|
||||||
.i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0,
|
|
||||||
.i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1,
|
|
||||||
|
|
||||||
.has_irq_controls = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct apple_mbox_hw apple_mbox_m3_hw = {
|
|
||||||
.control_full = APPLE_M3_MBOX_CONTROL_FULL,
|
|
||||||
.control_empty = APPLE_M3_MBOX_CONTROL_EMPTY,
|
|
||||||
|
|
||||||
.a2i_control = APPLE_M3_MBOX_A2I_CONTROL,
|
|
||||||
.a2i_send0 = APPLE_M3_MBOX_A2I_SEND0,
|
|
||||||
.a2i_send1 = APPLE_M3_MBOX_A2I_SEND1,
|
|
||||||
|
|
||||||
.i2a_control = APPLE_M3_MBOX_I2A_CONTROL,
|
|
||||||
.i2a_recv0 = APPLE_M3_MBOX_I2A_RECV0,
|
|
||||||
.i2a_recv1 = APPLE_M3_MBOX_I2A_RECV1,
|
|
||||||
|
|
||||||
.has_irq_controls = true,
|
|
||||||
.irq_enable = APPLE_M3_MBOX_IRQ_ENABLE,
|
|
||||||
.irq_ack = APPLE_M3_MBOX_IRQ_ACK,
|
|
||||||
.irq_bit_recv_not_empty = APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY,
|
|
||||||
.irq_bit_send_empty = APPLE_M3_MBOX_IRQ_A2I_EMPTY,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct of_device_id apple_mbox_of_match[] = {
|
|
||||||
{ .compatible = "apple,asc-mailbox-v4", .data = &apple_mbox_asc_hw },
|
|
||||||
{ .compatible = "apple,m3-mailbox-v2", .data = &apple_mbox_m3_hw },
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, apple_mbox_of_match);
|
|
||||||
|
|
||||||
static struct platform_driver apple_mbox_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "apple-mailbox",
|
|
||||||
.of_match_table = apple_mbox_of_match,
|
|
||||||
},
|
|
||||||
.probe = apple_mbox_probe,
|
|
||||||
};
|
|
||||||
module_platform_driver(apple_mbox_driver);
|
|
||||||
|
|
||||||
MODULE_LICENSE("Dual MIT/GPL");
|
|
||||||
MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
|
|
||||||
MODULE_DESCRIPTION("Apple Mailbox driver");
|
|
@ -909,13 +909,11 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brcmstb_dpfe_remove(struct platform_device *pdev)
|
static void brcmstb_dpfe_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct brcmstb_dpfe_priv *priv = dev_get_drvdata(&pdev->dev);
|
struct brcmstb_dpfe_priv *priv = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
|
sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id brcmstb_dpfe_of_match[] = {
|
static const struct of_device_id brcmstb_dpfe_of_match[] = {
|
||||||
@ -936,7 +934,7 @@ static struct platform_driver brcmstb_dpfe_driver = {
|
|||||||
.of_match_table = brcmstb_dpfe_of_match,
|
.of_match_table = brcmstb_dpfe_of_match,
|
||||||
},
|
},
|
||||||
.probe = brcmstb_dpfe_probe,
|
.probe = brcmstb_dpfe_probe,
|
||||||
.remove = brcmstb_dpfe_remove,
|
.remove_new = brcmstb_dpfe_remove,
|
||||||
.resume = brcmstb_dpfe_resume,
|
.resume = brcmstb_dpfe_resume,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,13 +152,11 @@ static int brcmstb_memc_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brcmstb_memc_remove(struct platform_device *pdev)
|
static void brcmstb_memc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
|
||||||
sysfs_remove_group(&dev->kobj, &dev_attr_group);
|
sysfs_remove_group(&dev->kobj, &dev_attr_group);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum brcmstb_memc_hwtype {
|
enum brcmstb_memc_hwtype {
|
||||||
@ -284,7 +282,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_memc_pm_ops, brcmstb_memc_suspend,
|
|||||||
|
|
||||||
static struct platform_driver brcmstb_memc_driver = {
|
static struct platform_driver brcmstb_memc_driver = {
|
||||||
.probe = brcmstb_memc_probe,
|
.probe = brcmstb_memc_probe,
|
||||||
.remove = brcmstb_memc_remove,
|
.remove_new = brcmstb_memc_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "brcmstb_memc",
|
.name = "brcmstb_memc",
|
||||||
.of_match_table = brcmstb_memc_of_match,
|
.of_match_table = brcmstb_memc_of_match,
|
||||||
|
@ -1159,13 +1159,11 @@ error:
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __exit emif_remove(struct platform_device *pdev)
|
static void __exit emif_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct emif_data *emif = platform_get_drvdata(pdev);
|
struct emif_data *emif = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
emif_debugfs_exit(emif);
|
emif_debugfs_exit(emif);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emif_shutdown(struct platform_device *pdev)
|
static void emif_shutdown(struct platform_device *pdev)
|
||||||
@ -1185,7 +1183,7 @@ MODULE_DEVICE_TABLE(of, emif_of_match);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static struct platform_driver emif_driver = {
|
static struct platform_driver emif_driver = {
|
||||||
.remove = __exit_p(emif_remove),
|
.remove_new = __exit_p(emif_remove),
|
||||||
.shutdown = emif_shutdown,
|
.shutdown = emif_shutdown,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "emif",
|
.name = "emif",
|
||||||
|
@ -223,7 +223,7 @@ static int ccf_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ccf_remove(struct platform_device *pdev)
|
static void ccf_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct ccf_private *ccf = dev_get_drvdata(&pdev->dev);
|
struct ccf_private *ccf = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
@ -241,8 +241,6 @@ static int ccf_remove(struct platform_device *pdev)
|
|||||||
iowrite32be(0, &ccf->err_regs->errinten);
|
iowrite32be(0, &ccf->err_regs->errinten);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver ccf_driver = {
|
static struct platform_driver ccf_driver = {
|
||||||
@ -251,7 +249,7 @@ static struct platform_driver ccf_driver = {
|
|||||||
.of_match_table = ccf_matches,
|
.of_match_table = ccf_matches,
|
||||||
},
|
},
|
||||||
.probe = ccf_probe,
|
.probe = ccf_probe,
|
||||||
.remove = ccf_remove,
|
.remove_new = ccf_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(ccf_driver);
|
module_platform_driver(ccf_driver);
|
||||||
|
@ -84,7 +84,7 @@ static int fsl_ifc_ctrl_init(struct fsl_ifc_ctrl *ctrl)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsl_ifc_ctrl_remove(struct platform_device *dev)
|
static void fsl_ifc_ctrl_remove(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
|
struct fsl_ifc_ctrl *ctrl = dev_get_drvdata(&dev->dev);
|
||||||
|
|
||||||
@ -98,8 +98,6 @@ static int fsl_ifc_ctrl_remove(struct platform_device *dev)
|
|||||||
iounmap(ctrl->gregs);
|
iounmap(ctrl->gregs);
|
||||||
|
|
||||||
dev_set_drvdata(&dev->dev, NULL);
|
dev_set_drvdata(&dev->dev, NULL);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -318,7 +316,7 @@ static struct platform_driver fsl_ifc_ctrl_driver = {
|
|||||||
.of_match_table = fsl_ifc_match,
|
.of_match_table = fsl_ifc_match,
|
||||||
},
|
},
|
||||||
.probe = fsl_ifc_ctrl_probe,
|
.probe = fsl_ifc_ctrl_probe,
|
||||||
.remove = fsl_ifc_ctrl_remove,
|
.remove_new = fsl_ifc_ctrl_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init fsl_ifc_init(void)
|
static int __init fsl_ifc_init(void)
|
||||||
|
@ -384,12 +384,11 @@ static int jz4780_nemc_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int jz4780_nemc_remove(struct platform_device *pdev)
|
static void jz4780_nemc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct jz4780_nemc *nemc = platform_get_drvdata(pdev);
|
struct jz4780_nemc *nemc = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
clk_disable_unprepare(nemc->clk);
|
clk_disable_unprepare(nemc->clk);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct jz_soc_info jz4740_soc_info = {
|
static const struct jz_soc_info jz4740_soc_info = {
|
||||||
@ -408,7 +407,7 @@ static const struct of_device_id jz4780_nemc_dt_match[] = {
|
|||||||
|
|
||||||
static struct platform_driver jz4780_nemc_driver = {
|
static struct platform_driver jz4780_nemc_driver = {
|
||||||
.probe = jz4780_nemc_probe,
|
.probe = jz4780_nemc_probe,
|
||||||
.remove = jz4780_nemc_remove,
|
.remove_new = jz4780_nemc_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "jz4780-nemc",
|
.name = "jz4780-nemc",
|
||||||
.of_match_table = of_match_ptr(jz4780_nemc_dt_match),
|
.of_match_table = of_match_ptr(jz4780_nemc_dt_match),
|
||||||
|
@ -566,14 +566,13 @@ err_pm_disable:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mtk_smi_larb_remove(struct platform_device *pdev)
|
static void mtk_smi_larb_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct mtk_smi_larb *larb = platform_get_drvdata(pdev);
|
struct mtk_smi_larb *larb = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
device_link_remove(&pdev->dev, larb->smi_common_dev);
|
device_link_remove(&pdev->dev, larb->smi_common_dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
component_del(&pdev->dev, &mtk_smi_larb_component_ops);
|
component_del(&pdev->dev, &mtk_smi_larb_component_ops);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
|
static int __maybe_unused mtk_smi_larb_resume(struct device *dev)
|
||||||
@ -616,7 +615,7 @@ static const struct dev_pm_ops smi_larb_pm_ops = {
|
|||||||
|
|
||||||
static struct platform_driver mtk_smi_larb_driver = {
|
static struct platform_driver mtk_smi_larb_driver = {
|
||||||
.probe = mtk_smi_larb_probe,
|
.probe = mtk_smi_larb_probe,
|
||||||
.remove = mtk_smi_larb_remove,
|
.remove_new = mtk_smi_larb_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "mtk-smi-larb",
|
.name = "mtk-smi-larb",
|
||||||
.of_match_table = mtk_smi_larb_of_ids,
|
.of_match_table = mtk_smi_larb_of_ids,
|
||||||
@ -795,14 +794,13 @@ static int mtk_smi_common_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mtk_smi_common_remove(struct platform_device *pdev)
|
static void mtk_smi_common_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct mtk_smi *common = dev_get_drvdata(&pdev->dev);
|
struct mtk_smi *common = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
|
if (common->plat->type == MTK_SMI_GEN2_SUB_COMM)
|
||||||
device_link_remove(&pdev->dev, common->smi_common_dev);
|
device_link_remove(&pdev->dev, common->smi_common_dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused mtk_smi_common_resume(struct device *dev)
|
static int __maybe_unused mtk_smi_common_resume(struct device *dev)
|
||||||
@ -842,7 +840,7 @@ static const struct dev_pm_ops smi_common_pm_ops = {
|
|||||||
|
|
||||||
static struct platform_driver mtk_smi_common_driver = {
|
static struct platform_driver mtk_smi_common_driver = {
|
||||||
.probe = mtk_smi_common_probe,
|
.probe = mtk_smi_common_probe,
|
||||||
.remove = mtk_smi_common_remove,
|
.remove_new = mtk_smi_common_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "mtk-smi-common",
|
.name = "mtk-smi-common",
|
||||||
.of_match_table = mtk_smi_common_of_ids,
|
.of_match_table = mtk_smi_common_of_ids,
|
||||||
|
@ -2690,7 +2690,7 @@ gpio_init_failed:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpmc_remove(struct platform_device *pdev)
|
static void gpmc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
|
struct gpmc_device *gpmc = platform_get_drvdata(pdev);
|
||||||
@ -2702,8 +2702,6 @@ static int gpmc_remove(struct platform_device *pdev)
|
|||||||
gpmc_mem_exit();
|
gpmc_mem_exit();
|
||||||
pm_runtime_put_sync(&pdev->dev);
|
pm_runtime_put_sync(&pdev->dev);
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
@ -2747,7 +2745,7 @@ MODULE_DEVICE_TABLE(of, gpmc_dt_ids);
|
|||||||
|
|
||||||
static struct platform_driver gpmc_driver = {
|
static struct platform_driver gpmc_driver = {
|
||||||
.probe = gpmc_probe,
|
.probe = gpmc_probe,
|
||||||
.remove = gpmc_remove,
|
.remove_new = gpmc_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = DEVICE_NAME,
|
.name = DEVICE_NAME,
|
||||||
.of_match_table = of_match_ptr(gpmc_dt_ids),
|
.of_match_table = of_match_ptr(gpmc_dt_ids),
|
||||||
|
@ -777,13 +777,11 @@ static int rpcif_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rpcif_remove(struct platform_device *pdev)
|
static void rpcif_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct rpcif_priv *rpc = platform_get_drvdata(pdev);
|
struct rpcif_priv *rpc = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
platform_device_unregister(rpc->vdev);
|
platform_device_unregister(rpc->vdev);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id rpcif_of_match[] = {
|
static const struct of_device_id rpcif_of_match[] = {
|
||||||
@ -797,7 +795,7 @@ MODULE_DEVICE_TABLE(of, rpcif_of_match);
|
|||||||
|
|
||||||
static struct platform_driver rpcif_driver = {
|
static struct platform_driver rpcif_driver = {
|
||||||
.probe = rpcif_probe,
|
.probe = rpcif_probe,
|
||||||
.remove = rpcif_remove,
|
.remove_new = rpcif_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "rpc-if",
|
.name = "rpc-if",
|
||||||
.of_match_table = rpcif_of_match,
|
.of_match_table = rpcif_of_match,
|
||||||
|
@ -1558,7 +1558,7 @@ remove_clocks:
|
|||||||
* clean the device's resources. It just calls explicitly disable function for
|
* clean the device's resources. It just calls explicitly disable function for
|
||||||
* the performance counters.
|
* the performance counters.
|
||||||
*/
|
*/
|
||||||
static int exynos5_dmc_remove(struct platform_device *pdev)
|
static void exynos5_dmc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct exynos5_dmc *dmc = dev_get_drvdata(&pdev->dev);
|
struct exynos5_dmc *dmc = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
@ -1569,8 +1569,6 @@ static int exynos5_dmc_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
clk_disable_unprepare(dmc->mout_bpll);
|
clk_disable_unprepare(dmc->mout_bpll);
|
||||||
clk_disable_unprepare(dmc->fout_bpll);
|
clk_disable_unprepare(dmc->fout_bpll);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id exynos5_dmc_of_match[] = {
|
static const struct of_device_id exynos5_dmc_of_match[] = {
|
||||||
@ -1581,7 +1579,7 @@ MODULE_DEVICE_TABLE(of, exynos5_dmc_of_match);
|
|||||||
|
|
||||||
static struct platform_driver exynos5_dmc_platdrv = {
|
static struct platform_driver exynos5_dmc_platdrv = {
|
||||||
.probe = exynos5_dmc_probe,
|
.probe = exynos5_dmc_probe,
|
||||||
.remove = exynos5_dmc_remove,
|
.remove_new = exynos5_dmc_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "exynos5-dmc",
|
.name = "exynos5-dmc",
|
||||||
.of_match_table = exynos5_dmc_of_match,
|
.of_match_table = exynos5_dmc_of_match,
|
||||||
|
@ -1146,7 +1146,7 @@ err_release:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm32_fmc2_ebi_remove(struct platform_device *pdev)
|
static void stm32_fmc2_ebi_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct stm32_fmc2_ebi *ebi = platform_get_drvdata(pdev);
|
struct stm32_fmc2_ebi *ebi = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
@ -1154,8 +1154,6 @@ static int stm32_fmc2_ebi_remove(struct platform_device *pdev)
|
|||||||
stm32_fmc2_ebi_disable_banks(ebi);
|
stm32_fmc2_ebi_disable_banks(ebi);
|
||||||
stm32_fmc2_ebi_disable(ebi);
|
stm32_fmc2_ebi_disable(ebi);
|
||||||
clk_disable_unprepare(ebi->clk);
|
clk_disable_unprepare(ebi->clk);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev)
|
static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev)
|
||||||
@ -1197,7 +1195,7 @@ MODULE_DEVICE_TABLE(of, stm32_fmc2_ebi_match);
|
|||||||
|
|
||||||
static struct platform_driver stm32_fmc2_ebi_driver = {
|
static struct platform_driver stm32_fmc2_ebi_driver = {
|
||||||
.probe = stm32_fmc2_ebi_probe,
|
.probe = stm32_fmc2_ebi_probe,
|
||||||
.remove = stm32_fmc2_ebi_remove,
|
.remove_new = stm32_fmc2_ebi_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "stm32_fmc2_ebi",
|
.name = "stm32_fmc2_ebi",
|
||||||
.of_match_table = stm32_fmc2_ebi_match,
|
.of_match_table = stm32_fmc2_ebi_match,
|
||||||
|
@ -378,7 +378,7 @@ put_bpmp:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra186_emc_remove(struct platform_device *pdev)
|
static void tegra186_emc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct tegra_mc *mc = dev_get_drvdata(pdev->dev.parent);
|
struct tegra_mc *mc = dev_get_drvdata(pdev->dev.parent);
|
||||||
struct tegra186_emc *emc = platform_get_drvdata(pdev);
|
struct tegra186_emc *emc = platform_get_drvdata(pdev);
|
||||||
@ -387,8 +387,6 @@ static int tegra186_emc_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
mc->bpmp = NULL;
|
mc->bpmp = NULL;
|
||||||
tegra_bpmp_put(emc->bpmp);
|
tegra_bpmp_put(emc->bpmp);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id tegra186_emc_of_match[] = {
|
static const struct of_device_id tegra186_emc_of_match[] = {
|
||||||
@ -413,7 +411,7 @@ static struct platform_driver tegra186_emc_driver = {
|
|||||||
.sync_state = icc_sync_state,
|
.sync_state = icc_sync_state,
|
||||||
},
|
},
|
||||||
.probe = tegra186_emc_probe,
|
.probe = tegra186_emc_probe,
|
||||||
.remove = tegra186_emc_remove,
|
.remove_new = tegra186_emc_remove,
|
||||||
};
|
};
|
||||||
module_platform_driver(tegra186_emc_driver);
|
module_platform_driver(tegra186_emc_driver);
|
||||||
|
|
||||||
|
@ -75,6 +75,9 @@ static void tegra186_mc_client_sid_override(struct tegra_mc *mc,
|
|||||||
{
|
{
|
||||||
u32 value, old;
|
u32 value, old;
|
||||||
|
|
||||||
|
if (client->regs.sid.security == 0 && client->regs.sid.override == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
value = readl(mc->regs + client->regs.sid.security);
|
value = readl(mc->regs + client->regs.sid.security);
|
||||||
if ((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0) {
|
if ((value & MC_SID_STREAMID_SECURITY_OVERRIDE) == 0) {
|
||||||
/*
|
/*
|
||||||
@ -136,9 +139,25 @@ static int tegra186_mc_probe_device(struct tegra_mc *mc, struct device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tegra186_mc_resume(struct tegra_mc *mc)
|
||||||
|
{
|
||||||
|
#if IS_ENABLED(CONFIG_IOMMU_API)
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < mc->soc->num_clients; i++) {
|
||||||
|
const struct tegra_mc_client *client = &mc->soc->clients[i];
|
||||||
|
|
||||||
|
tegra186_mc_client_sid_override(mc, client, client->sid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const struct tegra_mc_ops tegra186_mc_ops = {
|
const struct tegra_mc_ops tegra186_mc_ops = {
|
||||||
.probe = tegra186_mc_probe,
|
.probe = tegra186_mc_probe,
|
||||||
.remove = tegra186_mc_remove,
|
.remove = tegra186_mc_remove,
|
||||||
|
.resume = tegra186_mc_resume,
|
||||||
.probe_device = tegra186_mc_probe_device,
|
.probe_device = tegra186_mc_probe_device,
|
||||||
.handle_irq = tegra30_mc_handle_irq,
|
.handle_irq = tegra30_mc_handle_irq,
|
||||||
};
|
};
|
||||||
|
@ -1985,15 +1985,13 @@ release:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tegra210_emc_remove(struct platform_device *pdev)
|
static void tegra210_emc_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct tegra210_emc *emc = platform_get_drvdata(pdev);
|
struct tegra210_emc *emc = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
debugfs_remove_recursive(emc->debugfs.root);
|
debugfs_remove_recursive(emc->debugfs.root);
|
||||||
tegra210_clk_emc_detach(emc->clk);
|
tegra210_clk_emc_detach(emc->clk);
|
||||||
of_reserved_mem_device_release(emc->dev);
|
of_reserved_mem_device_release(emc->dev);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused tegra210_emc_suspend(struct device *dev)
|
static int __maybe_unused tegra210_emc_suspend(struct device *dev)
|
||||||
@ -2053,7 +2051,7 @@ static struct platform_driver tegra210_emc_driver = {
|
|||||||
.pm = &tegra210_emc_pm_ops,
|
.pm = &tegra210_emc_pm_ops,
|
||||||
},
|
},
|
||||||
.probe = tegra210_emc_probe,
|
.probe = tegra210_emc_probe,
|
||||||
.remove = tegra210_emc_remove,
|
.remove_new = tegra210_emc_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_platform_driver(tegra210_emc_driver);
|
module_platform_driver(tegra210_emc_driver);
|
||||||
|
@ -427,17 +427,16 @@ error:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aemif_remove(struct platform_device *pdev)
|
static void aemif_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct aemif_device *aemif = platform_get_drvdata(pdev);
|
struct aemif_device *aemif = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
clk_disable_unprepare(aemif->clk);
|
clk_disable_unprepare(aemif->clk);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct platform_driver aemif_driver = {
|
static struct platform_driver aemif_driver = {
|
||||||
.probe = aemif_probe,
|
.probe = aemif_probe,
|
||||||
.remove = aemif_remove,
|
.remove_new = aemif_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ti-aemif",
|
.name = "ti-aemif",
|
||||||
.of_match_table = of_match_ptr(aemif_of_match),
|
.of_match_table = of_match_ptr(aemif_of_match),
|
||||||
|
@ -315,15 +315,13 @@ fail_free_sram:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ti_emif_remove(struct platform_device *pdev)
|
static void ti_emif_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct ti_emif_data *emif_data = emif_instance;
|
struct ti_emif_data *emif_data = emif_instance;
|
||||||
|
|
||||||
emif_instance = NULL;
|
emif_instance = NULL;
|
||||||
|
|
||||||
ti_emif_free_sram(emif_data);
|
ti_emif_free_sram(emif_data);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops ti_emif_pm_ops = {
|
static const struct dev_pm_ops ti_emif_pm_ops = {
|
||||||
@ -332,7 +330,7 @@ static const struct dev_pm_ops ti_emif_pm_ops = {
|
|||||||
|
|
||||||
static struct platform_driver ti_emif_driver = {
|
static struct platform_driver ti_emif_driver = {
|
||||||
.probe = ti_emif_probe,
|
.probe = ti_emif_probe,
|
||||||
.remove = ti_emif_remove,
|
.remove_new = ti_emif_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = KBUILD_MODNAME,
|
.name = KBUILD_MODNAME,
|
||||||
.of_match_table = ti_emif_of_match,
|
.of_match_table = ti_emif_of_match,
|
||||||
|
@ -90,8 +90,7 @@ static int brcmstb_reset_probe(struct platform_device *pdev)
|
|||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||||
priv->base = devm_ioremap_resource(kdev, res);
|
|
||||||
if (IS_ERR(priv->base))
|
if (IS_ERR(priv->base))
|
||||||
return PTR_ERR(priv->base);
|
return PTR_ERR(priv->base);
|
||||||
|
|
||||||
|
@ -139,7 +139,6 @@ static int meson_audio_arb_probe(struct platform_device *pdev)
|
|||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
const struct meson_audio_arb_match_data *data;
|
const struct meson_audio_arb_match_data *data;
|
||||||
struct meson_audio_arb_data *arb;
|
struct meson_audio_arb_data *arb;
|
||||||
struct resource *res;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
data = of_device_get_match_data(dev);
|
data = of_device_get_match_data(dev);
|
||||||
@ -155,8 +154,7 @@ static int meson_audio_arb_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(arb->clk))
|
if (IS_ERR(arb->clk))
|
||||||
return dev_err_probe(dev, PTR_ERR(arb->clk), "failed to get clock\n");
|
return dev_err_probe(dev, PTR_ERR(arb->clk), "failed to get clock\n");
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
arb->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||||
arb->regs = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(arb->regs))
|
if (IS_ERR(arb->regs))
|
||||||
return PTR_ERR(arb->regs);
|
return PTR_ERR(arb->regs);
|
||||||
|
|
||||||
|
@ -108,6 +108,7 @@ static const struct of_device_id meson_reset_dt_ids[] = {
|
|||||||
{ .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param},
|
{ .compatible = "amlogic,meson-axg-reset", .data = &meson8b_param},
|
||||||
{ .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param},
|
{ .compatible = "amlogic,meson-a1-reset", .data = &meson_a1_param},
|
||||||
{ .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param},
|
{ .compatible = "amlogic,meson-s4-reset", .data = &meson_s4_param},
|
||||||
|
{ .compatible = "amlogic,c3-reset", .data = &meson_s4_param},
|
||||||
{ /* sentinel */ },
|
{ /* sentinel */ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
|
MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/property.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <linux/reset-controller.h>
|
#include <linux/reset-controller.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
@ -351,8 +351,7 @@ static int npcm_usb_reset(struct platform_device *pdev, struct npcm_rc_data *rc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc->info = (const struct npcm_reset_info *)
|
rc->info = device_get_match_data(dev);
|
||||||
of_match_device(dev->driver->of_match_table, dev)->data;
|
|
||||||
switch (rc->info->bmc_id) {
|
switch (rc->info->bmc_id) {
|
||||||
case BMC_NPCM7XX:
|
case BMC_NPCM7XX:
|
||||||
npcm_usb_reset_npcm7xx(rc);
|
npcm_usb_reset_npcm7xx(rc);
|
||||||
|
@ -90,7 +90,6 @@ static int qcom_aoss_reset_probe(struct platform_device *pdev)
|
|||||||
struct qcom_aoss_reset_data *data;
|
struct qcom_aoss_reset_data *data;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
const struct qcom_aoss_desc *desc;
|
const struct qcom_aoss_desc *desc;
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
desc = of_device_get_match_data(dev);
|
desc = of_device_get_match_data(dev);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
@ -101,8 +100,7 @@ static int qcom_aoss_reset_probe(struct platform_device *pdev)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
data->desc = desc;
|
data->desc = desc;
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
data->base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
data->base = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(data->base))
|
if (IS_ERR(data->base))
|
||||||
return PTR_ERR(data->base);
|
return PTR_ERR(data->base);
|
||||||
|
|
||||||
|
@ -114,7 +114,6 @@ static int qcom_pdc_reset_probe(struct platform_device *pdev)
|
|||||||
struct qcom_pdc_reset_data *data;
|
struct qcom_pdc_reset_data *data;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
desc = device_get_match_data(&pdev->dev);
|
desc = device_get_match_data(&pdev->dev);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
@ -125,8 +124,7 @@ static int qcom_pdc_reset_probe(struct platform_device *pdev)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
data->desc = desc;
|
data->desc = desc;
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
base = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(base))
|
if (IS_ERR(base))
|
||||||
return PTR_ERR(base);
|
return PTR_ERR(base);
|
||||||
|
|
||||||
|
@ -169,8 +169,7 @@ static int reset_simple_probe(struct platform_device *pdev)
|
|||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||||
membase = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(membase))
|
if (IS_ERR(membase))
|
||||||
return PTR_ERR(membase);
|
return PTR_ERR(membase);
|
||||||
|
|
||||||
|
@ -176,8 +176,7 @@ static int sp_reset_probe(struct platform_device *pdev)
|
|||||||
if (!reset)
|
if (!reset)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
reset->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||||
reset->base = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(reset->base))
|
if (IS_ERR(reset->base))
|
||||||
return PTR_ERR(reset->base);
|
return PTR_ERR(reset->base);
|
||||||
|
|
||||||
|
@ -58,8 +58,7 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev)
|
|||||||
priv->data->nrsts > MAX_RSTS))
|
priv->data->nrsts > MAX_RSTS))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
priv->rdata.membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||||
priv->rdata.membase = devm_ioremap_resource(dev, res);
|
|
||||||
if (IS_ERR(priv->rdata.membase))
|
if (IS_ERR(priv->rdata.membase))
|
||||||
return PTR_ERR(priv->rdata.membase);
|
return PTR_ERR(priv->rdata.membase);
|
||||||
|
|
||||||
|
@ -7,10 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/property.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
|
|
||||||
@ -183,14 +184,14 @@ static int syscfg_reset_controller_register(struct device *dev,
|
|||||||
int syscfg_reset_probe(struct platform_device *pdev)
|
int syscfg_reset_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = pdev ? &pdev->dev : NULL;
|
struct device *dev = pdev ? &pdev->dev : NULL;
|
||||||
const struct of_device_id *match;
|
const void *data;
|
||||||
|
|
||||||
if (!dev || !dev->driver)
|
if (!dev || !dev->driver)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
match = of_match_device(dev->driver->of_match_table, dev);
|
data = device_get_match_data(&pdev->dev);
|
||||||
if (!match || !match->data)
|
if (!data)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return syscfg_reset_controller_register(dev, match->data);
|
return syscfg_reset_controller_register(dev, data);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ source "drivers/soc/qcom/Kconfig"
|
|||||||
source "drivers/soc/renesas/Kconfig"
|
source "drivers/soc/renesas/Kconfig"
|
||||||
source "drivers/soc/rockchip/Kconfig"
|
source "drivers/soc/rockchip/Kconfig"
|
||||||
source "drivers/soc/samsung/Kconfig"
|
source "drivers/soc/samsung/Kconfig"
|
||||||
source "drivers/soc/sifive/Kconfig"
|
|
||||||
source "drivers/soc/sunxi/Kconfig"
|
source "drivers/soc/sunxi/Kconfig"
|
||||||
source "drivers/soc/tegra/Kconfig"
|
source "drivers/soc/tegra/Kconfig"
|
||||||
source "drivers/soc/ti/Kconfig"
|
source "drivers/soc/ti/Kconfig"
|
||||||
|
@ -28,7 +28,6 @@ obj-y += qcom/
|
|||||||
obj-y += renesas/
|
obj-y += renesas/
|
||||||
obj-y += rockchip/
|
obj-y += rockchip/
|
||||||
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
|
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
|
||||||
obj-y += sifive/
|
|
||||||
obj-y += sunxi/
|
obj-y += sunxi/
|
||||||
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
||||||
obj-y += ti/
|
obj-y += ti/
|
||||||
|
@ -4,9 +4,22 @@ if ARCH_APPLE || COMPILE_TEST
|
|||||||
|
|
||||||
menu "Apple SoC drivers"
|
menu "Apple SoC drivers"
|
||||||
|
|
||||||
|
config APPLE_MAILBOX
|
||||||
|
tristate "Apple SoC mailboxes"
|
||||||
|
depends on PM
|
||||||
|
depends on ARCH_APPLE || (64BIT && COMPILE_TEST)
|
||||||
|
default ARCH_APPLE
|
||||||
|
help
|
||||||
|
Apple SoCs have various co-processors required for certain
|
||||||
|
peripherals to work (NVMe, display controller, etc.). This
|
||||||
|
driver adds support for the mailbox controller used to
|
||||||
|
communicate with those.
|
||||||
|
|
||||||
|
Say Y here if you have an Apple SoC.
|
||||||
|
|
||||||
config APPLE_RTKIT
|
config APPLE_RTKIT
|
||||||
tristate "Apple RTKit co-processor IPC protocol"
|
tristate "Apple RTKit co-processor IPC protocol"
|
||||||
depends on MAILBOX
|
depends on APPLE_MAILBOX
|
||||||
depends on ARCH_APPLE || COMPILE_TEST
|
depends on ARCH_APPLE || COMPILE_TEST
|
||||||
default ARCH_APPLE
|
default ARCH_APPLE
|
||||||
help
|
help
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
# SPDX-License-Identifier: GPL-2.0-only
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o
|
||||||
|
apple-mailbox-y = mailbox.o
|
||||||
|
|
||||||
obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o
|
obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o
|
||||||
apple-rtkit-y = rtkit.o rtkit-crashlog.o
|
apple-rtkit-y = rtkit.o rtkit-crashlog.o
|
||||||
|
|
||||||
|
437
drivers/soc/apple/mailbox.c
Normal file
437
drivers/soc/apple/mailbox.c
Normal file
@ -0,0 +1,437 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
||||||
|
/*
|
||||||
|
* Apple mailbox driver
|
||||||
|
*
|
||||||
|
* Copyright The Asahi Linux Contributors
|
||||||
|
*
|
||||||
|
* This driver adds support for two mailbox variants (called ASC and M3 by
|
||||||
|
* Apple) found in Apple SoCs such as the M1. It consists of two FIFOs used to
|
||||||
|
* exchange 64+32 bit messages between the main CPU and a co-processor.
|
||||||
|
* Various coprocessors implement different IPC protocols based on these simple
|
||||||
|
* messages and shared memory buffers.
|
||||||
|
*
|
||||||
|
* Both the main CPU and the co-processor see the same set of registers but
|
||||||
|
* the first FIFO (A2I) is always used to transfer messages from the application
|
||||||
|
* processor (us) to the I/O processor and the second one (I2A) for the
|
||||||
|
* other direction.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/bits.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include "mailbox.h"
|
||||||
|
|
||||||
|
#define APPLE_ASC_MBOX_CONTROL_FULL BIT(16)
|
||||||
|
#define APPLE_ASC_MBOX_CONTROL_EMPTY BIT(17)
|
||||||
|
|
||||||
|
#define APPLE_ASC_MBOX_A2I_CONTROL 0x110
|
||||||
|
#define APPLE_ASC_MBOX_A2I_SEND0 0x800
|
||||||
|
#define APPLE_ASC_MBOX_A2I_SEND1 0x808
|
||||||
|
#define APPLE_ASC_MBOX_A2I_RECV0 0x810
|
||||||
|
#define APPLE_ASC_MBOX_A2I_RECV1 0x818
|
||||||
|
|
||||||
|
#define APPLE_ASC_MBOX_I2A_CONTROL 0x114
|
||||||
|
#define APPLE_ASC_MBOX_I2A_SEND0 0x820
|
||||||
|
#define APPLE_ASC_MBOX_I2A_SEND1 0x828
|
||||||
|
#define APPLE_ASC_MBOX_I2A_RECV0 0x830
|
||||||
|
#define APPLE_ASC_MBOX_I2A_RECV1 0x838
|
||||||
|
|
||||||
|
#define APPLE_M3_MBOX_CONTROL_FULL BIT(16)
|
||||||
|
#define APPLE_M3_MBOX_CONTROL_EMPTY BIT(17)
|
||||||
|
|
||||||
|
#define APPLE_M3_MBOX_A2I_CONTROL 0x50
|
||||||
|
#define APPLE_M3_MBOX_A2I_SEND0 0x60
|
||||||
|
#define APPLE_M3_MBOX_A2I_SEND1 0x68
|
||||||
|
#define APPLE_M3_MBOX_A2I_RECV0 0x70
|
||||||
|
#define APPLE_M3_MBOX_A2I_RECV1 0x78
|
||||||
|
|
||||||
|
#define APPLE_M3_MBOX_I2A_CONTROL 0x80
|
||||||
|
#define APPLE_M3_MBOX_I2A_SEND0 0x90
|
||||||
|
#define APPLE_M3_MBOX_I2A_SEND1 0x98
|
||||||
|
#define APPLE_M3_MBOX_I2A_RECV0 0xa0
|
||||||
|
#define APPLE_M3_MBOX_I2A_RECV1 0xa8
|
||||||
|
|
||||||
|
#define APPLE_M3_MBOX_IRQ_ENABLE 0x48
|
||||||
|
#define APPLE_M3_MBOX_IRQ_ACK 0x4c
|
||||||
|
#define APPLE_M3_MBOX_IRQ_A2I_EMPTY BIT(0)
|
||||||
|
#define APPLE_M3_MBOX_IRQ_A2I_NOT_EMPTY BIT(1)
|
||||||
|
#define APPLE_M3_MBOX_IRQ_I2A_EMPTY BIT(2)
|
||||||
|
#define APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY BIT(3)
|
||||||
|
|
||||||
|
#define APPLE_MBOX_MSG1_OUTCNT GENMASK(56, 52)
|
||||||
|
#define APPLE_MBOX_MSG1_INCNT GENMASK(51, 48)
|
||||||
|
#define APPLE_MBOX_MSG1_OUTPTR GENMASK(47, 44)
|
||||||
|
#define APPLE_MBOX_MSG1_INPTR GENMASK(43, 40)
|
||||||
|
#define APPLE_MBOX_MSG1_MSG GENMASK(31, 0)
|
||||||
|
|
||||||
|
#define APPLE_MBOX_TX_TIMEOUT 500
|
||||||
|
|
||||||
|
struct apple_mbox_hw {
|
||||||
|
unsigned int control_full;
|
||||||
|
unsigned int control_empty;
|
||||||
|
|
||||||
|
unsigned int a2i_control;
|
||||||
|
unsigned int a2i_send0;
|
||||||
|
unsigned int a2i_send1;
|
||||||
|
|
||||||
|
unsigned int i2a_control;
|
||||||
|
unsigned int i2a_recv0;
|
||||||
|
unsigned int i2a_recv1;
|
||||||
|
|
||||||
|
bool has_irq_controls;
|
||||||
|
unsigned int irq_enable;
|
||||||
|
unsigned int irq_ack;
|
||||||
|
unsigned int irq_bit_recv_not_empty;
|
||||||
|
unsigned int irq_bit_send_empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
int apple_mbox_send(struct apple_mbox *mbox, const struct apple_mbox_msg msg,
|
||||||
|
bool atomic)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
u32 mbox_ctrl;
|
||||||
|
long t;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&mbox->tx_lock, flags);
|
||||||
|
mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->a2i_control);
|
||||||
|
|
||||||
|
while (mbox_ctrl & mbox->hw->control_full) {
|
||||||
|
if (atomic) {
|
||||||
|
ret = readl_poll_timeout_atomic(
|
||||||
|
mbox->regs + mbox->hw->a2i_control, mbox_ctrl,
|
||||||
|
!(mbox_ctrl & mbox->hw->control_full), 100,
|
||||||
|
APPLE_MBOX_TX_TIMEOUT * 1000);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
spin_unlock_irqrestore(&mbox->tx_lock, flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The interrupt is level triggered and will keep firing as long as the
|
||||||
|
* FIFO is empty. It will also keep firing if the FIFO was empty
|
||||||
|
* at any point in the past until it has been acknowledged at the
|
||||||
|
* mailbox level. By acknowledging it here we can ensure that we will
|
||||||
|
* only get the interrupt once the FIFO has been cleared again.
|
||||||
|
* If the FIFO is already empty before the ack it will fire again
|
||||||
|
* immediately after the ack.
|
||||||
|
*/
|
||||||
|
if (mbox->hw->has_irq_controls) {
|
||||||
|
writel_relaxed(mbox->hw->irq_bit_send_empty,
|
||||||
|
mbox->regs + mbox->hw->irq_ack);
|
||||||
|
}
|
||||||
|
enable_irq(mbox->irq_send_empty);
|
||||||
|
reinit_completion(&mbox->tx_empty);
|
||||||
|
spin_unlock_irqrestore(&mbox->tx_lock, flags);
|
||||||
|
|
||||||
|
t = wait_for_completion_interruptible_timeout(
|
||||||
|
&mbox->tx_empty,
|
||||||
|
msecs_to_jiffies(APPLE_MBOX_TX_TIMEOUT));
|
||||||
|
if (t < 0)
|
||||||
|
return t;
|
||||||
|
else if (t == 0)
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&mbox->tx_lock, flags);
|
||||||
|
mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->a2i_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
writeq_relaxed(msg.msg0, mbox->regs + mbox->hw->a2i_send0);
|
||||||
|
writeq_relaxed(FIELD_PREP(APPLE_MBOX_MSG1_MSG, msg.msg1),
|
||||||
|
mbox->regs + mbox->hw->a2i_send1);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&mbox->tx_lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(apple_mbox_send);
|
||||||
|
|
||||||
|
static irqreturn_t apple_mbox_send_empty_irq(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct apple_mbox *mbox = data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't need to acknowledge the interrupt at the mailbox level
|
||||||
|
* here even if supported by the hardware. It will keep firing but that
|
||||||
|
* doesn't matter since it's disabled at the main interrupt controller.
|
||||||
|
* apple_mbox_send will acknowledge it before enabling
|
||||||
|
* it at the main controller again.
|
||||||
|
*/
|
||||||
|
spin_lock(&mbox->tx_lock);
|
||||||
|
disable_irq_nosync(mbox->irq_send_empty);
|
||||||
|
complete(&mbox->tx_empty);
|
||||||
|
spin_unlock(&mbox->tx_lock);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apple_mbox_poll_locked(struct apple_mbox *mbox)
|
||||||
|
{
|
||||||
|
struct apple_mbox_msg msg;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
u32 mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->i2a_control);
|
||||||
|
|
||||||
|
while (!(mbox_ctrl & mbox->hw->control_empty)) {
|
||||||
|
msg.msg0 = readq_relaxed(mbox->regs + mbox->hw->i2a_recv0);
|
||||||
|
msg.msg1 = FIELD_GET(
|
||||||
|
APPLE_MBOX_MSG1_MSG,
|
||||||
|
readq_relaxed(mbox->regs + mbox->hw->i2a_recv1));
|
||||||
|
|
||||||
|
mbox->rx(mbox, msg, mbox->cookie);
|
||||||
|
ret++;
|
||||||
|
mbox_ctrl = readl_relaxed(mbox->regs + mbox->hw->i2a_control);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The interrupt will keep firing even if there are no more messages
|
||||||
|
* unless we also acknowledge it at the mailbox level here.
|
||||||
|
* There's no race if a message comes in between the check in the while
|
||||||
|
* loop above and the ack below: If a new messages arrives inbetween
|
||||||
|
* those two the interrupt will just fire again immediately after the
|
||||||
|
* ack since it's level triggered.
|
||||||
|
*/
|
||||||
|
if (mbox->hw->has_irq_controls) {
|
||||||
|
writel_relaxed(mbox->hw->irq_bit_recv_not_empty,
|
||||||
|
mbox->regs + mbox->hw->irq_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t apple_mbox_recv_irq(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct apple_mbox *mbox = data;
|
||||||
|
|
||||||
|
spin_lock(&mbox->rx_lock);
|
||||||
|
apple_mbox_poll_locked(mbox);
|
||||||
|
spin_unlock(&mbox->rx_lock);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
int apple_mbox_poll(struct apple_mbox *mbox)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&mbox->rx_lock, flags);
|
||||||
|
ret = apple_mbox_poll_locked(mbox);
|
||||||
|
spin_unlock_irqrestore(&mbox->rx_lock, flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(apple_mbox_poll);
|
||||||
|
|
||||||
|
int apple_mbox_start(struct apple_mbox *mbox)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (mbox->active)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = pm_runtime_resume_and_get(mbox->dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only some variants of this mailbox HW provide interrupt control
|
||||||
|
* at the mailbox level. We therefore need to handle enabling/disabling
|
||||||
|
* interrupts at the main interrupt controller anyway for hardware that
|
||||||
|
* doesn't. Just always keep the interrupts we care about enabled at
|
||||||
|
* the mailbox level so that both hardware revisions behave almost
|
||||||
|
* the same.
|
||||||
|
*/
|
||||||
|
if (mbox->hw->has_irq_controls) {
|
||||||
|
writel_relaxed(mbox->hw->irq_bit_recv_not_empty |
|
||||||
|
mbox->hw->irq_bit_send_empty,
|
||||||
|
mbox->regs + mbox->hw->irq_enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
enable_irq(mbox->irq_recv_not_empty);
|
||||||
|
mbox->active = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(apple_mbox_start);
|
||||||
|
|
||||||
|
void apple_mbox_stop(struct apple_mbox *mbox)
|
||||||
|
{
|
||||||
|
if (!mbox->active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mbox->active = false;
|
||||||
|
disable_irq(mbox->irq_recv_not_empty);
|
||||||
|
pm_runtime_mark_last_busy(mbox->dev);
|
||||||
|
pm_runtime_put_autosuspend(mbox->dev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(apple_mbox_stop);
|
||||||
|
|
||||||
|
struct apple_mbox *apple_mbox_get(struct device *dev, int index)
|
||||||
|
{
|
||||||
|
struct of_phandle_args args;
|
||||||
|
struct platform_device *pdev;
|
||||||
|
struct apple_mbox *mbox;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells",
|
||||||
|
index, &args);
|
||||||
|
if (ret || !args.np)
|
||||||
|
return ERR_PTR(ret);
|
||||||
|
|
||||||
|
pdev = of_find_device_by_node(args.np);
|
||||||
|
of_node_put(args.np);
|
||||||
|
|
||||||
|
if (!pdev)
|
||||||
|
return ERR_PTR(EPROBE_DEFER);
|
||||||
|
|
||||||
|
mbox = platform_get_drvdata(pdev);
|
||||||
|
if (!mbox)
|
||||||
|
return ERR_PTR(EPROBE_DEFER);
|
||||||
|
|
||||||
|
if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER))
|
||||||
|
return ERR_PTR(ENODEV);
|
||||||
|
|
||||||
|
return mbox;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(apple_mbox_get);
|
||||||
|
|
||||||
|
struct apple_mbox *apple_mbox_get_byname(struct device *dev, const char *name)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
|
||||||
|
index = of_property_match_string(dev->of_node, "mbox-names", name);
|
||||||
|
if (index < 0)
|
||||||
|
return ERR_PTR(index);
|
||||||
|
|
||||||
|
return apple_mbox_get(dev, index);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(apple_mbox_get_byname);
|
||||||
|
|
||||||
|
static int apple_mbox_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
char *irqname;
|
||||||
|
struct apple_mbox *mbox;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
|
||||||
|
mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
|
||||||
|
if (!mbox)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mbox->dev = &pdev->dev;
|
||||||
|
mbox->hw = of_device_get_match_data(dev);
|
||||||
|
if (!mbox->hw)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mbox->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(mbox->regs))
|
||||||
|
return PTR_ERR(mbox->regs);
|
||||||
|
|
||||||
|
mbox->irq_recv_not_empty =
|
||||||
|
platform_get_irq_byname(pdev, "recv-not-empty");
|
||||||
|
if (mbox->irq_recv_not_empty < 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
mbox->irq_send_empty = platform_get_irq_byname(pdev, "send-empty");
|
||||||
|
if (mbox->irq_send_empty < 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
spin_lock_init(&mbox->rx_lock);
|
||||||
|
spin_lock_init(&mbox->tx_lock);
|
||||||
|
init_completion(&mbox->tx_empty);
|
||||||
|
|
||||||
|
irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-recv", dev_name(dev));
|
||||||
|
if (!irqname)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = devm_request_irq(dev, mbox->irq_recv_not_empty,
|
||||||
|
apple_mbox_recv_irq,
|
||||||
|
IRQF_NO_AUTOEN | IRQF_NO_SUSPEND, irqname, mbox);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
irqname = devm_kasprintf(dev, GFP_KERNEL, "%s-send", dev_name(dev));
|
||||||
|
if (!irqname)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = devm_request_irq(dev, mbox->irq_send_empty,
|
||||||
|
apple_mbox_send_empty_irq,
|
||||||
|
IRQF_NO_AUTOEN | IRQF_NO_SUSPEND, irqname, mbox);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = devm_pm_runtime_enable(dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, mbox);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct apple_mbox_hw apple_mbox_asc_hw = {
|
||||||
|
.control_full = APPLE_ASC_MBOX_CONTROL_FULL,
|
||||||
|
.control_empty = APPLE_ASC_MBOX_CONTROL_EMPTY,
|
||||||
|
|
||||||
|
.a2i_control = APPLE_ASC_MBOX_A2I_CONTROL,
|
||||||
|
.a2i_send0 = APPLE_ASC_MBOX_A2I_SEND0,
|
||||||
|
.a2i_send1 = APPLE_ASC_MBOX_A2I_SEND1,
|
||||||
|
|
||||||
|
.i2a_control = APPLE_ASC_MBOX_I2A_CONTROL,
|
||||||
|
.i2a_recv0 = APPLE_ASC_MBOX_I2A_RECV0,
|
||||||
|
.i2a_recv1 = APPLE_ASC_MBOX_I2A_RECV1,
|
||||||
|
|
||||||
|
.has_irq_controls = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct apple_mbox_hw apple_mbox_m3_hw = {
|
||||||
|
.control_full = APPLE_M3_MBOX_CONTROL_FULL,
|
||||||
|
.control_empty = APPLE_M3_MBOX_CONTROL_EMPTY,
|
||||||
|
|
||||||
|
.a2i_control = APPLE_M3_MBOX_A2I_CONTROL,
|
||||||
|
.a2i_send0 = APPLE_M3_MBOX_A2I_SEND0,
|
||||||
|
.a2i_send1 = APPLE_M3_MBOX_A2I_SEND1,
|
||||||
|
|
||||||
|
.i2a_control = APPLE_M3_MBOX_I2A_CONTROL,
|
||||||
|
.i2a_recv0 = APPLE_M3_MBOX_I2A_RECV0,
|
||||||
|
.i2a_recv1 = APPLE_M3_MBOX_I2A_RECV1,
|
||||||
|
|
||||||
|
.has_irq_controls = true,
|
||||||
|
.irq_enable = APPLE_M3_MBOX_IRQ_ENABLE,
|
||||||
|
.irq_ack = APPLE_M3_MBOX_IRQ_ACK,
|
||||||
|
.irq_bit_recv_not_empty = APPLE_M3_MBOX_IRQ_I2A_NOT_EMPTY,
|
||||||
|
.irq_bit_send_empty = APPLE_M3_MBOX_IRQ_A2I_EMPTY,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id apple_mbox_of_match[] = {
|
||||||
|
{ .compatible = "apple,asc-mailbox-v4", .data = &apple_mbox_asc_hw },
|
||||||
|
{ .compatible = "apple,m3-mailbox-v2", .data = &apple_mbox_m3_hw },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, apple_mbox_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver apple_mbox_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "apple-mailbox",
|
||||||
|
.of_match_table = apple_mbox_of_match,
|
||||||
|
},
|
||||||
|
.probe = apple_mbox_probe,
|
||||||
|
};
|
||||||
|
module_platform_driver(apple_mbox_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("Dual MIT/GPL");
|
||||||
|
MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
|
||||||
|
MODULE_DESCRIPTION("Apple Mailbox driver");
|
48
drivers/soc/apple/mailbox.h
Normal file
48
drivers/soc/apple/mailbox.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
|
||||||
|
/*
|
||||||
|
* Apple mailbox message format
|
||||||
|
*
|
||||||
|
* Copyright The Asahi Linux Contributors
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _APPLE_MAILBOX_H_
|
||||||
|
#define _APPLE_MAILBOX_H_
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
/* encodes a single 96bit message sent over the single channel */
|
||||||
|
struct apple_mbox_msg {
|
||||||
|
u64 msg0;
|
||||||
|
u32 msg1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct apple_mbox {
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *regs;
|
||||||
|
const struct apple_mbox_hw *hw;
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
int irq_recv_not_empty;
|
||||||
|
int irq_send_empty;
|
||||||
|
|
||||||
|
spinlock_t rx_lock;
|
||||||
|
spinlock_t tx_lock;
|
||||||
|
|
||||||
|
struct completion tx_empty;
|
||||||
|
|
||||||
|
/** Receive callback for incoming messages */
|
||||||
|
void (*rx)(struct apple_mbox *mbox, struct apple_mbox_msg msg, void *cookie);
|
||||||
|
void *cookie;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct apple_mbox *apple_mbox_get(struct device *dev, int index);
|
||||||
|
struct apple_mbox *apple_mbox_get_byname(struct device *dev, const char *name);
|
||||||
|
|
||||||
|
int apple_mbox_start(struct apple_mbox *mbox);
|
||||||
|
void apple_mbox_stop(struct apple_mbox *mbox);
|
||||||
|
int apple_mbox_poll(struct apple_mbox *mbox);
|
||||||
|
int apple_mbox_send(struct apple_mbox *mbox, struct apple_mbox_msg msg,
|
||||||
|
bool atomic);
|
||||||
|
|
||||||
|
#endif
|
@ -7,18 +7,17 @@
|
|||||||
#ifndef _APPLE_RTKIT_INTERAL_H
|
#ifndef _APPLE_RTKIT_INTERAL_H
|
||||||
#define _APPLE_RTKIT_INTERAL_H
|
#define _APPLE_RTKIT_INTERAL_H
|
||||||
|
|
||||||
#include <linux/apple-mailbox.h>
|
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
#include <linux/bitmap.h>
|
#include <linux/bitmap.h>
|
||||||
#include <linux/completion.h>
|
#include <linux/completion.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/mailbox_client.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/soc/apple/rtkit.h>
|
#include <linux/soc/apple/rtkit.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
#include "mailbox.h"
|
||||||
|
|
||||||
#define APPLE_RTKIT_APP_ENDPOINT_START 0x20
|
#define APPLE_RTKIT_APP_ENDPOINT_START 0x20
|
||||||
#define APPLE_RTKIT_MAX_ENDPOINTS 0x100
|
#define APPLE_RTKIT_MAX_ENDPOINTS 0x100
|
||||||
@ -28,10 +27,7 @@ struct apple_rtkit {
|
|||||||
const struct apple_rtkit_ops *ops;
|
const struct apple_rtkit_ops *ops;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
const char *mbox_name;
|
struct apple_mbox *mbox;
|
||||||
int mbox_idx;
|
|
||||||
struct mbox_client mbox_cl;
|
|
||||||
struct mbox_chan *mbox_chan;
|
|
||||||
|
|
||||||
struct completion epmap_completion;
|
struct completion epmap_completion;
|
||||||
struct completion iop_pwr_ack_completion;
|
struct completion iop_pwr_ack_completion;
|
||||||
|
@ -72,11 +72,6 @@ enum {
|
|||||||
#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
|
#define APPLE_RTKIT_MIN_SUPPORTED_VERSION 11
|
||||||
#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
|
#define APPLE_RTKIT_MAX_SUPPORTED_VERSION 12
|
||||||
|
|
||||||
struct apple_rtkit_msg {
|
|
||||||
struct completion *completion;
|
|
||||||
struct apple_mbox_msg mbox_msg;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct apple_rtkit_rx_work {
|
struct apple_rtkit_rx_work {
|
||||||
struct apple_rtkit *rtk;
|
struct apple_rtkit *rtk;
|
||||||
u8 ep;
|
u8 ep;
|
||||||
@ -550,12 +545,12 @@ static void apple_rtkit_rx_work(struct work_struct *work)
|
|||||||
kfree(rtk_work);
|
kfree(rtk_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apple_rtkit_rx(struct mbox_client *cl, void *mssg)
|
static void apple_rtkit_rx(struct apple_mbox *mbox, struct apple_mbox_msg msg,
|
||||||
|
void *cookie)
|
||||||
{
|
{
|
||||||
struct apple_rtkit *rtk = container_of(cl, struct apple_rtkit, mbox_cl);
|
struct apple_rtkit *rtk = cookie;
|
||||||
struct apple_mbox_msg *msg = mssg;
|
|
||||||
struct apple_rtkit_rx_work *work;
|
struct apple_rtkit_rx_work *work;
|
||||||
u8 ep = msg->msg1;
|
u8 ep = msg.msg1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The message was read from a MMIO FIFO and we have to make
|
* The message was read from a MMIO FIFO and we have to make
|
||||||
@ -571,7 +566,7 @@ static void apple_rtkit_rx(struct mbox_client *cl, void *mssg)
|
|||||||
|
|
||||||
if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
|
if (ep >= APPLE_RTKIT_APP_ENDPOINT_START &&
|
||||||
rtk->ops->recv_message_early &&
|
rtk->ops->recv_message_early &&
|
||||||
rtk->ops->recv_message_early(rtk->cookie, ep, msg->msg0))
|
rtk->ops->recv_message_early(rtk->cookie, ep, msg.msg0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
work = kzalloc(sizeof(*work), GFP_ATOMIC);
|
work = kzalloc(sizeof(*work), GFP_ATOMIC);
|
||||||
@ -580,30 +575,18 @@ static void apple_rtkit_rx(struct mbox_client *cl, void *mssg)
|
|||||||
|
|
||||||
work->rtk = rtk;
|
work->rtk = rtk;
|
||||||
work->ep = ep;
|
work->ep = ep;
|
||||||
work->msg = msg->msg0;
|
work->msg = msg.msg0;
|
||||||
INIT_WORK(&work->work, apple_rtkit_rx_work);
|
INIT_WORK(&work->work, apple_rtkit_rx_work);
|
||||||
queue_work(rtk->wq, &work->work);
|
queue_work(rtk->wq, &work->work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apple_rtkit_tx_done(struct mbox_client *cl, void *mssg, int r)
|
|
||||||
{
|
|
||||||
struct apple_rtkit_msg *msg =
|
|
||||||
container_of(mssg, struct apple_rtkit_msg, mbox_msg);
|
|
||||||
|
|
||||||
if (r == -ETIME)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (msg->completion)
|
|
||||||
complete(msg->completion);
|
|
||||||
kfree(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
|
int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
|
||||||
struct completion *completion, bool atomic)
|
struct completion *completion, bool atomic)
|
||||||
{
|
{
|
||||||
struct apple_rtkit_msg *msg;
|
struct apple_mbox_msg msg = {
|
||||||
int ret;
|
.msg0 = message,
|
||||||
gfp_t flags;
|
.msg1 = ep,
|
||||||
|
};
|
||||||
|
|
||||||
if (rtk->crashed)
|
if (rtk->crashed)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -611,19 +594,6 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
|
|||||||
!apple_rtkit_is_running(rtk))
|
!apple_rtkit_is_running(rtk))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (atomic)
|
|
||||||
flags = GFP_ATOMIC;
|
|
||||||
else
|
|
||||||
flags = GFP_KERNEL;
|
|
||||||
|
|
||||||
msg = kzalloc(sizeof(*msg), flags);
|
|
||||||
if (!msg)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
msg->mbox_msg.msg0 = message;
|
|
||||||
msg->mbox_msg.msg1 = ep;
|
|
||||||
msg->completion = completion;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The message will be sent with a MMIO write. We need the barrier
|
* The message will be sent with a MMIO write. We need the barrier
|
||||||
* here to ensure any previous writes to buffers are visible to the
|
* here to ensure any previous writes to buffers are visible to the
|
||||||
@ -631,51 +601,13 @@ int apple_rtkit_send_message(struct apple_rtkit *rtk, u8 ep, u64 message,
|
|||||||
*/
|
*/
|
||||||
dma_wmb();
|
dma_wmb();
|
||||||
|
|
||||||
ret = mbox_send_message(rtk->mbox_chan, &msg->mbox_msg);
|
return apple_mbox_send(rtk->mbox, msg, atomic);
|
||||||
if (ret < 0) {
|
|
||||||
kfree(msg);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(apple_rtkit_send_message);
|
EXPORT_SYMBOL_GPL(apple_rtkit_send_message);
|
||||||
|
|
||||||
int apple_rtkit_send_message_wait(struct apple_rtkit *rtk, u8 ep, u64 message,
|
|
||||||
unsigned long timeout, bool atomic)
|
|
||||||
{
|
|
||||||
DECLARE_COMPLETION_ONSTACK(completion);
|
|
||||||
int ret;
|
|
||||||
long t;
|
|
||||||
|
|
||||||
ret = apple_rtkit_send_message(rtk, ep, message, &completion, atomic);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (atomic) {
|
|
||||||
ret = mbox_flush(rtk->mbox_chan, timeout);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (try_wait_for_completion(&completion))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return -ETIME;
|
|
||||||
} else {
|
|
||||||
t = wait_for_completion_interruptible_timeout(
|
|
||||||
&completion, msecs_to_jiffies(timeout));
|
|
||||||
if (t < 0)
|
|
||||||
return t;
|
|
||||||
else if (t == 0)
|
|
||||||
return -ETIME;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(apple_rtkit_send_message_wait);
|
|
||||||
|
|
||||||
int apple_rtkit_poll(struct apple_rtkit *rtk)
|
int apple_rtkit_poll(struct apple_rtkit *rtk)
|
||||||
{
|
{
|
||||||
return mbox_client_peek_data(rtk->mbox_chan);
|
return apple_mbox_poll(rtk->mbox);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(apple_rtkit_poll);
|
EXPORT_SYMBOL_GPL(apple_rtkit_poll);
|
||||||
|
|
||||||
@ -697,20 +629,6 @@ int apple_rtkit_start_ep(struct apple_rtkit *rtk, u8 endpoint)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(apple_rtkit_start_ep);
|
EXPORT_SYMBOL_GPL(apple_rtkit_start_ep);
|
||||||
|
|
||||||
static int apple_rtkit_request_mbox_chan(struct apple_rtkit *rtk)
|
|
||||||
{
|
|
||||||
if (rtk->mbox_name)
|
|
||||||
rtk->mbox_chan = mbox_request_channel_byname(&rtk->mbox_cl,
|
|
||||||
rtk->mbox_name);
|
|
||||||
else
|
|
||||||
rtk->mbox_chan =
|
|
||||||
mbox_request_channel(&rtk->mbox_cl, rtk->mbox_idx);
|
|
||||||
|
|
||||||
if (IS_ERR(rtk->mbox_chan))
|
|
||||||
return PTR_ERR(rtk->mbox_chan);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
|
struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
|
||||||
const char *mbox_name, int mbox_idx,
|
const char *mbox_name, int mbox_idx,
|
||||||
const struct apple_rtkit_ops *ops)
|
const struct apple_rtkit_ops *ops)
|
||||||
@ -736,13 +654,18 @@ struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
|
|||||||
bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS);
|
bitmap_zero(rtk->endpoints, APPLE_RTKIT_MAX_ENDPOINTS);
|
||||||
set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints);
|
set_bit(APPLE_RTKIT_EP_MGMT, rtk->endpoints);
|
||||||
|
|
||||||
rtk->mbox_name = mbox_name;
|
if (mbox_name)
|
||||||
rtk->mbox_idx = mbox_idx;
|
rtk->mbox = apple_mbox_get_byname(dev, mbox_name);
|
||||||
rtk->mbox_cl.dev = dev;
|
else
|
||||||
rtk->mbox_cl.tx_block = false;
|
rtk->mbox = apple_mbox_get(dev, mbox_idx);
|
||||||
rtk->mbox_cl.knows_txdone = false;
|
|
||||||
rtk->mbox_cl.rx_callback = &apple_rtkit_rx;
|
if (IS_ERR(rtk->mbox)) {
|
||||||
rtk->mbox_cl.tx_done = &apple_rtkit_tx_done;
|
ret = PTR_ERR(rtk->mbox);
|
||||||
|
goto free_rtk;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtk->mbox->rx = apple_rtkit_rx;
|
||||||
|
rtk->mbox->cookie = rtk;
|
||||||
|
|
||||||
rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM,
|
rtk->wq = alloc_ordered_workqueue("rtkit-%s", WQ_MEM_RECLAIM,
|
||||||
dev_name(rtk->dev));
|
dev_name(rtk->dev));
|
||||||
@ -751,7 +674,7 @@ struct apple_rtkit *apple_rtkit_init(struct device *dev, void *cookie,
|
|||||||
goto free_rtk;
|
goto free_rtk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = apple_rtkit_request_mbox_chan(rtk);
|
ret = apple_mbox_start(rtk->mbox);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto destroy_wq;
|
goto destroy_wq;
|
||||||
|
|
||||||
@ -782,7 +705,7 @@ static int apple_rtkit_wait_for_completion(struct completion *c)
|
|||||||
int apple_rtkit_reinit(struct apple_rtkit *rtk)
|
int apple_rtkit_reinit(struct apple_rtkit *rtk)
|
||||||
{
|
{
|
||||||
/* make sure we don't handle any messages while reinitializing */
|
/* make sure we don't handle any messages while reinitializing */
|
||||||
mbox_free_channel(rtk->mbox_chan);
|
apple_mbox_stop(rtk->mbox);
|
||||||
flush_workqueue(rtk->wq);
|
flush_workqueue(rtk->wq);
|
||||||
|
|
||||||
apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
|
apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
|
||||||
@ -806,7 +729,7 @@ int apple_rtkit_reinit(struct apple_rtkit *rtk)
|
|||||||
rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_OFF;
|
rtk->iop_power_state = APPLE_RTKIT_PWR_STATE_OFF;
|
||||||
rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_OFF;
|
rtk->ap_power_state = APPLE_RTKIT_PWR_STATE_OFF;
|
||||||
|
|
||||||
return apple_rtkit_request_mbox_chan(rtk);
|
return apple_mbox_start(rtk->mbox);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(apple_rtkit_reinit);
|
EXPORT_SYMBOL_GPL(apple_rtkit_reinit);
|
||||||
|
|
||||||
@ -962,7 +885,7 @@ EXPORT_SYMBOL_GPL(apple_rtkit_wake);
|
|||||||
|
|
||||||
void apple_rtkit_free(struct apple_rtkit *rtk)
|
void apple_rtkit_free(struct apple_rtkit *rtk)
|
||||||
{
|
{
|
||||||
mbox_free_channel(rtk->mbox_chan);
|
apple_mbox_stop(rtk->mbox);
|
||||||
destroy_workqueue(rtk->wq);
|
destroy_workqueue(rtk->wq);
|
||||||
|
|
||||||
apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
|
apple_rtkit_free_buffer(rtk, &rtk->ioreport_buffer);
|
||||||
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user