diff --git a/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs b/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs new file mode 100644 index 000000000000..fdb4e36310fb --- /dev/null +++ b/Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs @@ -0,0 +1,81 @@ +What: /sys/devices/platform/HISI04Bx:00/chipX/all_linked +What: /sys/devices/platform/HISI04Bx:00/chipX/linked_full_lane +What: /sys/devices/platform/HISI04Bx:00/chipX/crc_err_cnt +Date: November 2023 +KernelVersion: 6.6 +Contact: Huisong Li +Description: + The /sys/devices/platform/HISI04Bx:00/chipX/ directory + contains read-only attributes exposing some summarization + information of all HCCS ports under a specified chip. + The X in 'chipX' indicates the Xth chip on platform. + + There are following attributes in this directory: + + ================= ==== ========================================= + all_linked: (RO) if all enabled ports on this chip are + linked (bool). + linked_full_lane: (RO) if all linked ports on this chip are full + lane (bool). + crc_err_cnt: (RO) total CRC err count for all ports on this + chip. + ================= ==== ========================================= + +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/all_linked +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/linked_full_lane +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/crc_err_cnt +Date: November 2023 +KernelVersion: 6.6 +Contact: Huisong Li +Description: + The /sys/devices/platform/HISI04Bx:00/chipX/dieY/ directory + contains read-only attributes exposing some summarization + information of all HCCS ports under a specified die. + The Y in 'dieY' indicates the hardware id of the die on chip who + has chip id X. + + There are following attributes in this directory: + + ================= ==== ========================================= + all_linked: (RO) if all enabled ports on this die are + linked (bool). + linked_full_lane: (RO) if all linked ports on this die are full + lane (bool). + crc_err_cnt: (RO) total CRC err count for all ports on this + die. + ================= ==== ========================================= + +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/type +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/lane_mode +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/enable +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/cur_lane_num +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/link_fsm +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/lane_mask +What: /sys/devices/platform/HISI04Bx:00/chipX/dieY/hccsN/crc_err_cnt +Date: November 2023 +KernelVersion: 6.6 +Contact: Huisong Li +Description: + The /sys/devices/platform/HISI04Bx/chipX/dieX/hccsN/ directory + contains read-only attributes exposing information about + a HCCS port. The N value in 'hccsN' indicates this port id. + The X in 'chipX' indicates the ID of the chip to which the + HCCS port belongs. For example, X ranges from to 'n - 1' if the + chip number on platform is n. + The Y in 'dieY' indicates the hardware id of the die to which + the hccs port belongs. + Note: type, lane_mode and enable are fixed attributes on running + platform. + + The HCCS port have the following attributes: + + ============= ==== ============================================= + type: (RO) port type (string), e.g. HCCS-v1 -> H32 + lane_mode: (RO) the lane mode of this port (string), e.g. x8 + enable: (RO) indicate if this port is enabled (bool). + cur_lane_num: (RO) current lane number of this port. + link_fsm: (RO) link finite state machine of this port. + lane_mask: (RO) current lane mask of this port, every bit + indicates a lane. + crc_err_cnt: (RO) CRC err count on this port. + ============= ==== ============================================= diff --git a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml index d6774db257f0..59cc88a52f6b 100644 --- a/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,dispcc-sm8x50.yaml @@ -82,7 +82,7 @@ additionalProperties: false examples: - | #include - #include + #include clock-controller@af00000 { compatible = "qcom,sm8250-dispcc"; reg = <0x0af00000 0x10000>; @@ -103,7 +103,7 @@ examples: #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; - power-domains = <&rpmhpd SM8250_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; required-opps = <&rpmhpd_opp_low_svs>; }; ... diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml index 23505c8c3dbd..d723bb11d947 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8350-videocc.yaml @@ -51,7 +51,7 @@ unevaluatedProperties: false examples: - | #include - #include + #include clock-controller@abf0000 { compatible = "qcom,sm8350-videocc"; @@ -59,7 +59,7 @@ examples: clocks = <&rpmhcc RPMH_CXO_CLK>, <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>; - power-domains = <&rpmhpd SM8350_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; required-opps = <&rpmhpd_opp_low_svs>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml index 87ae74166807..8178c35bc348 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-camcc.yaml @@ -64,7 +64,7 @@ examples: - | #include #include - #include + #include clock-controller@ade0000 { compatible = "qcom,sm8450-camcc"; reg = <0xade0000 0x20000>; @@ -72,7 +72,7 @@ examples: <&rpmhcc RPMH_CXO_CLK>, <&rpmhcc RPMH_CXO_CLK_A>, <&sleep_clk>; - power-domains = <&rpmhpd SM8450_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; required-opps = <&rpmhpd_opp_low_svs>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml index 1dd1f696dcd3..2f22310b08a9 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-dispcc.yaml @@ -76,7 +76,7 @@ examples: - | #include #include - #include + #include clock-controller@af00000 { compatible = "qcom,sm8450-dispcc"; reg = <0x0af00000 0x10000>; @@ -91,7 +91,7 @@ examples: #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; - power-domains = <&rpmhpd SM8450_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; required-opps = <&rpmhpd_opp_low_svs>; }; ... diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml index f1c6dd50f184..bad8f019a8d3 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8450-videocc.yaml @@ -64,13 +64,13 @@ examples: - | #include #include - #include + #include videocc: clock-controller@aaf0000 { compatible = "qcom,sm8450-videocc"; reg = <0x0aaf0000 0x10000>; clocks = <&rpmhcc RPMH_CXO_CLK>, <&gcc GCC_VIDEO_AHB_CLK>; - power-domains = <&rpmhpd SM8450_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; required-opps = <&rpmhpd_opp_low_svs>; #clock-cells = <1>; #reset-cells = <1>; diff --git a/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml b/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml index ab25f7cbaa2e..c129f8c16b50 100644 --- a/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,sm8550-dispcc.yaml @@ -76,7 +76,7 @@ examples: - | #include #include - #include + #include clock-controller@af00000 { compatible = "qcom,sm8550-dispcc"; reg = <0x0af00000 0x10000>; @@ -99,7 +99,7 @@ examples: #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; - power-domains = <&rpmhpd SM8550_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; required-opps = <&rpmhpd_opp_low_svs>; }; ... diff --git a/Documentation/devicetree/bindings/clock/qcom,videocc.yaml b/Documentation/devicetree/bindings/clock/qcom,videocc.yaml index 2b07146161b4..6de01cf3259d 100644 --- a/Documentation/devicetree/bindings/clock/qcom,videocc.yaml +++ b/Documentation/devicetree/bindings/clock/qcom,videocc.yaml @@ -124,7 +124,7 @@ additionalProperties: false examples: - | #include - #include + #include clock-controller@ab00000 { compatible = "qcom,sdm845-videocc"; reg = <0x0ab00000 0x10000>; @@ -133,7 +133,7 @@ examples: #clock-cells = <1>; #reset-cells = <1>; #power-domain-cells = <1>; - power-domains = <&rpmhpd SM8250_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; required-opps = <&rpmhpd_opp_low_svs>; }; ... diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml index 687c8c170cd4..acd2ed391b2f 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-dpu.yaml @@ -54,7 +54,7 @@ examples: #include #include #include - #include + #include display-controller@ae01000 { compatible = "qcom,sm8250-dpu"; @@ -72,7 +72,7 @@ examples: assigned-clock-rates = <19200000>; operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SM8250_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; interrupt-parent = <&mdss>; interrupts = <0>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml index 368d3db0ce96..5cfb9b917e90 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8250-mdss.yaml @@ -76,7 +76,7 @@ examples: #include #include #include - #include + #include display-subsystem@ae00000 { compatible = "qcom,sm8250-mdss"; @@ -121,7 +121,7 @@ examples: assigned-clock-rates = <19200000>; operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SM8250_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; interrupt-parent = <&mdss>; interrupts = <0>; @@ -196,7 +196,7 @@ examples: assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; operating-points-v2 = <&dsi_opp_table>; - power-domains = <&rpmhpd SM8250_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; phys = <&dsi0_phy>; phy-names = "dsi"; @@ -286,7 +286,7 @@ examples: assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; operating-points-v2 = <&dsi_opp_table>; - power-domains = <&rpmhpd SM8250_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; phys = <&dsi1_phy>; phy-names = "dsi"; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml index 120500395c9a..1a4e03531a1b 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8350-dpu.yaml @@ -51,7 +51,7 @@ examples: #include #include #include - #include + #include display-controller@ae01000 { compatible = "qcom,sm8350-dpu"; @@ -76,7 +76,7 @@ examples: assigned-clock-rates = <19200000>; operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SM8350_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; interrupt-parent = <&mdss>; interrupts = <0>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8350-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8350-mdss.yaml index f2cbeb435f1b..8c89fb7fc8a3 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8350-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8350-mdss.yaml @@ -81,7 +81,7 @@ examples: #include #include #include - #include + #include display-subsystem@ae00000 { compatible = "qcom,sm8350-mdss"; @@ -134,7 +134,7 @@ examples: assigned-clock-rates = <19200000>; operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SM8350_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; interrupt-parent = <&mdss>; interrupts = <0>; @@ -203,7 +203,7 @@ examples: <&mdss_dsi0_phy 1>; operating-points-v2 = <&dsi_opp_table>; - power-domains = <&rpmhpd SM8350_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; phys = <&mdss_dsi0_phy>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml index 0d17ece1c453..da3fd66c564f 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-dpu.yaml @@ -58,7 +58,7 @@ examples: #include #include #include - #include + #include display-controller@ae01000 { compatible = "qcom,sm8450-dpu"; @@ -83,7 +83,7 @@ examples: assigned-clock-rates = <19200000>; operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SM8450_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; interrupt-parent = <&mdss>; interrupts = <0>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml index 494e2a080e99..cfad5049a966 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8450-mdss.yaml @@ -76,7 +76,7 @@ examples: #include #include #include - #include + #include display-subsystem@ae00000 { compatible = "qcom,sm8450-mdss"; @@ -130,7 +130,7 @@ examples: assigned-clock-rates = <19200000>; operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SM8450_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; interrupt-parent = <&mdss>; interrupts = <0>; @@ -210,7 +210,7 @@ examples: assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; operating-points-v2 = <&dsi_opp_table>; - power-domains = <&rpmhpd SM8450_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; phys = <&dsi0_phy>; phy-names = "dsi"; @@ -305,7 +305,7 @@ examples: assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; operating-points-v2 = <&dsi_opp_table>; - power-domains = <&rpmhpd SM8450_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; phys = <&dsi1_phy>; phy-names = "dsi"; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml index ff58a747bb6f..99908fbe74f0 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8550-dpu.yaml @@ -57,7 +57,7 @@ examples: #include #include #include - #include + #include display-controller@ae01000 { compatible = "qcom,sm8550-dpu"; @@ -82,7 +82,7 @@ examples: assigned-clock-rates = <19200000>; operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SM8550_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; interrupt-parent = <&mdss>; interrupts = <0>; diff --git a/Documentation/devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml b/Documentation/devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml index 70ce7cb7a80d..5390a8e79ad3 100644 --- a/Documentation/devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml +++ b/Documentation/devicetree/bindings/display/msm/qcom,sm8550-mdss.yaml @@ -76,7 +76,7 @@ examples: #include #include #include - #include + #include display-subsystem@ae00000 { compatible = "qcom,sm8550-mdss"; @@ -130,7 +130,7 @@ examples: assigned-clock-rates = <19200000>; operating-points-v2 = <&mdp_opp_table>; - power-domains = <&rpmhpd SM8550_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; interrupt-parent = <&mdss>; interrupts = <0>; @@ -205,7 +205,7 @@ examples: assigned-clock-parents = <&dsi0_phy 0>, <&dsi0_phy 1>; operating-points-v2 = <&dsi_opp_table>; - power-domains = <&rpmhpd SM8550_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; phys = <&dsi0_phy>; phy-names = "dsi"; @@ -294,7 +294,7 @@ examples: assigned-clock-parents = <&dsi1_phy 0>, <&dsi1_phy 1>; operating-points-v2 = <&dsi_opp_table>; - power-domains = <&rpmhpd SM8550_MMCX>; + power-domains = <&rpmhpd RPMHPD_MMCX>; phys = <&dsi1_phy>; phy-names = "dsi"; diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index bdbee58a542b..4233ea839bfc 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -176,6 +176,7 @@ allOf: contains: enum: - qcom,scm-qdu1000 + - qcom,scm-sc8280xp - qcom,scm-sm8450 - qcom,scm-sm8550 then: diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt index 2a1d16bdf834..ea939f54c5eb 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/arm,versatile-fpga-irq.txt @@ -6,7 +6,7 @@ controllers are OR:ed together and fed to the CPU tile's IRQ input. Each instance can handle up to 32 interrupts. Required properties: -- compatible: "arm,versatile-fpga-irq" or "oxsemi,ox810se-rps-irq" +- compatible: "arm,versatile-fpga-irq" - interrupt-controller: Identifies the node as an interrupt controller - #interrupt-cells: The number of cells to define the interrupts. Must be 1 as the FPGA IRQ controller has no configuration options for interrupt @@ -19,6 +19,8 @@ Required properties: the system till not make it possible for devices to request these interrupts. +The "oxsemi,ox810se-rps-irq" compatible is deprecated. + Example: pic: pic@14000000 { diff --git a/Documentation/devicetree/bindings/media/qcom,sm8250-venus.yaml b/Documentation/devicetree/bindings/media/qcom,sm8250-venus.yaml index 7915dcd2d99f..f66033ae8b59 100644 --- a/Documentation/devicetree/bindings/media/qcom,sm8250-venus.yaml +++ b/Documentation/devicetree/bindings/media/qcom,sm8250-venus.yaml @@ -106,7 +106,7 @@ examples: #include #include #include - #include + #include venus: video-codec@aa00000 { compatible = "qcom,sm8250-venus"; @@ -114,7 +114,7 @@ examples: interrupts = ; power-domains = <&videocc MVS0C_GDSC>, <&videocc MVS0_GDSC>, - <&rpmhpd SM8250_MX>; + <&rpmhpd RPMHPD_MX>; power-domain-names = "venus", "vcodec0", "mx"; clocks = <&gcc GCC_VIDEO_AXI0_CLK>, diff --git a/Documentation/devicetree/bindings/memory-controllers/ingenic,nemc.yaml b/Documentation/devicetree/bindings/memory-controllers/ingenic,nemc.yaml index a02724221ff3..b40cec0eb651 100644 --- a/Documentation/devicetree/bindings/memory-controllers/ingenic,nemc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/ingenic,nemc.yaml @@ -39,6 +39,7 @@ properties: patternProperties: ".*@[0-9]+$": type: object + $ref: mc-peripheral-props.yaml# required: - compatible diff --git a/Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml b/Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml index 5acfcad12bb7..8d9dae15ade0 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/mc-peripheral-props.yaml @@ -34,6 +34,8 @@ required: # The controller specific properties go here. allOf: - $ref: st,stm32-fmc2-ebi-props.yaml# + - $ref: ingenic,nemc-peripherals.yaml# - $ref: intel,ixp4xx-expansion-peripheral-props.yaml# + - $ref: ti,gpmc-child.yaml# additionalProperties: true diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml index 6da28e630577..80141eb7fc6b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.yaml @@ -215,7 +215,7 @@ examples: #include #include #include - #include + #include sdhc_2: mmc@8804000 { compatible = "qcom,sm8250-sdhci", "qcom,sdhci-msm-v5"; @@ -232,7 +232,7 @@ examples: iommus = <&apps_smmu 0x4a0 0x0>; qcom,dll-config = <0x0007642c>; qcom,ddr-config = <0x80040868>; - power-domains = <&rpmhpd SM8250_CX>; + power-domains = <&rpmhpd RPMHPD_CX>; operating-points-v2 = <&sdhc2_opp_table>; diff --git a/Documentation/devicetree/bindings/net/davicom,dm9000.yaml b/Documentation/devicetree/bindings/net/davicom,dm9000.yaml new file mode 100644 index 000000000000..66a7c6eec767 --- /dev/null +++ b/Documentation/devicetree/bindings/net/davicom,dm9000.yaml @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/davicom,dm9000.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Davicom DM9000 Fast Ethernet Controller + +maintainers: + - Paul Cercueil + +properties: + compatible: + const: davicom,dm9000 + + reg: + items: + - description: Address registers + - description: Data registers + + interrupts: + maxItems: 1 + + davicom,no-eeprom: + type: boolean + description: Configuration EEPROM is not available + + davicom,ext-phy: + type: boolean + description: Use external PHY + + reset-gpios: + maxItems: 1 + + vcc-supply: true + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml# + - $ref: /schemas/net/ethernet-controller.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + ethernet@a8000000 { + compatible = "davicom,dm9000"; + reg = <0xa8000000 0x2>, <0xa8000002 0x2>; + interrupt-parent = <&gph1>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; + local-mac-address = [00 00 de ad be ef]; + davicom,no-eeprom; + }; diff --git a/Documentation/devicetree/bindings/net/davicom-dm9000.txt b/Documentation/devicetree/bindings/net/davicom-dm9000.txt deleted file mode 100644 index 64c159e9cbf7..000000000000 --- a/Documentation/devicetree/bindings/net/davicom-dm9000.txt +++ /dev/null @@ -1,27 +0,0 @@ -Davicom DM9000 Fast Ethernet controller - -Required properties: -- compatible = "davicom,dm9000"; -- reg : physical addresses and sizes of registers, must contain 2 entries: - first entry : address register, - second entry : data register. -- interrupts : interrupt specifier specific to interrupt controller - -Optional properties: -- davicom,no-eeprom : Configuration EEPROM is not available -- davicom,ext-phy : Use external PHY -- reset-gpios : phandle of gpio that will be used to reset chip during probe -- vcc-supply : phandle of regulator that will be used to enable power to chip - -Example: - - ethernet@18000000 { - compatible = "davicom,dm9000"; - reg = <0x18000000 0x2 0x18000004 0x2>; - interrupt-parent = <&gpn>; - interrupts = <7 4>; - local-mac-address = [00 00 de ad be ef]; - davicom,no-eeprom; - reset-gpios = <&gpf 12 GPIO_ACTIVE_LOW>; - vcc-supply = <ð0_power>; - }; diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml b/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml index eab21bb2050a..d80bbedfe3aa 100644 --- a/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml +++ b/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml @@ -12,7 +12,7 @@ maintainers: - Jianxin Pan description: |+ - Secure Power Domains used in Meson A1/C1/S4 SoCs, and should be the child node + Secure Power Domains used in Meson A1/C1/S4 & C3 SoCs, and should be the child node of secure-monitor. properties: @@ -20,6 +20,7 @@ properties: enum: - amlogic,meson-a1-pwrc - amlogic,meson-s4-pwrc + - amlogic,c3-pwrc "#power-domain-cells": const: 1 diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index f9c211a9a938..9b03c41d3604 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -41,6 +41,7 @@ properties: - qcom,sdm845-rpmhpd - qcom,sdx55-rpmhpd - qcom,sdx65-rpmhpd + - qcom,sdx75-rpmhpd - qcom,sm6115-rpmpd - qcom,sm6125-rpmpd - qcom,sm6350-rpmhpd diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,glink-edge.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,glink-edge.yaml index 7b43ad3daa56..e78a89c9ec41 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,glink-edge.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,glink-edge.yaml @@ -14,9 +14,6 @@ description: related to the remote processor. properties: - $nodename: - const: glink-edge - apr: $ref: /schemas/soc/qcom/qcom,apr.yaml# required: diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml index f5a044e20c4e..884158bccd50 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,glink-rpm-edge.yaml @@ -84,7 +84,7 @@ examples: - | #include - rpm-glink { + glink-edge { compatible = "qcom,glink-rpm"; interrupts = ; mboxes = <&apcs_glb 0>; diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml new file mode 100644 index 000000000000..7afafde17a38 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/qcom,rpm-proc.yaml @@ -0,0 +1,171 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/remoteproc/qcom,rpm-proc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Resource Power Manager (RPM) Processor/Subsystem + +maintainers: + - Bjorn Andersson + - Konrad Dybcio + - Stephan Gerhold + +description: | + Resource Power Manager (RPM) subsystem found in various Qualcomm platforms: + + +--------------------------------------------+ + | RPM subsystem (qcom,rpm-proc) | + | | + reset | +---------------+ +-----+ +-----+ | + --------->| | | MPM | | CPR | ... | + IPC interrupts | | ARM Cortex-M3 |--- +-----+ +-----+ | + ----------------->| | | | | | + | +---------------+ |---------------------- | + | +---------------+ | | + | | Code RAM |--| +------------------+ | + | +---------------+ | | | | + | +---------------+ |--| Message RAM | | + | | Data RAM |--| | | | + | +---------------+ | +------------------+ | + +--------------------|-----------------------+ + v + NoC + + The firmware running on the processor inside the RPM subsystem allows each + component in the system to vote for state of the system resources, such as + clocks, regulators and bus frequencies. It implements multiple separate + communication interfaces that are described in subnodes, e.g. SMD and MPM: + + +------------------------------+ + | ARM Cortex-M3 | + | | +------------------------------+ + | +--------------------------+ | | Message RAM | + | | RPM firmware | | | | + IPC IRQ 0 | | +----------------------+ | | | +--------------------------+ | + -------------->| SMD server |<------->| SMD data structures | | + | | | +--------------+ | | | | | +--------------+ | | + | | | | rpm_requests | ... | | | | | | rpm_requests | ... | | + | | | +--------------+ | | | | | +--------------+ | | + IPC IRQ 1 | | +----------------------+ | | | +--------------------------+ | + -------------->| MPM virtualization |<--------| MPM register copy (vMPM) | | + | | +----------------------+ | | | +--------------------------+ | + | | ... | | | | ... | + | +--------------------|-----+ | +------------------------------+ + +----------------------|-------+ + v + +--------------+ + | MPM Hardware | + +--------------+ + + The services provided by the firmware are only available after the firmware + has been loaded and the processor has been released from reset. Usually this + happens early in the boot process before the operating system is started. + +properties: + compatible: + items: + - enum: + - qcom,apq8084-rpm-proc + - qcom,ipq6018-rpm-proc + - qcom,ipq9574-rpm-proc + - qcom,mdm9607-rpm-proc + - qcom,msm8226-rpm-proc + - qcom,msm8610-rpm-proc + - qcom,msm8909-rpm-proc + - qcom,msm8916-rpm-proc + - qcom,msm8917-rpm-proc + - qcom,msm8936-rpm-proc + - qcom,msm8937-rpm-proc + - qcom,msm8952-rpm-proc + - qcom,msm8953-rpm-proc + - qcom,msm8974-rpm-proc + - qcom,msm8976-rpm-proc + - qcom,msm8994-rpm-proc + - qcom,msm8996-rpm-proc + - qcom,msm8998-rpm-proc + - qcom,qcm2290-rpm-proc + - qcom,qcs404-rpm-proc + - qcom,sdm660-rpm-proc + - qcom,sm6115-rpm-proc + - qcom,sm6125-rpm-proc + - qcom,sm6375-rpm-proc + - const: qcom,rpm-proc + + smd-edge: + $ref: /schemas/remoteproc/qcom,smd-edge.yaml# + description: + Qualcomm Shared Memory subnode which represents communication edge, + channels and devices related to the RPM subsystem. + + glink-edge: + $ref: /schemas/remoteproc/qcom,glink-rpm-edge.yaml# + description: + Qualcomm G-Link subnode which represents communication edge, + channels and devices related to the RPM subsystem. + + interrupt-controller: + type: object + $ref: /schemas/interrupt-controller/qcom,mpm.yaml# + description: + MSM Power Manager (MPM) interrupt controller that monitors interrupts + when the system is asleep. + + master-stats: + $ref: /schemas/soc/qcom/qcom,rpm-master-stats.yaml# + description: + Subsystem-level low-power mode statistics provided by RPM. + +required: + - compatible + +oneOf: + - required: + - smd-edge + - required: + - glink-edge + +additionalProperties: false + +examples: + # SMD + - | + #include + #include + + remoteproc { + compatible = "qcom,msm8916-rpm-proc", "qcom,rpm-proc"; + + smd-edge { + interrupts = ; + qcom,ipc = <&apcs 8 0>; + qcom,smd-edge = <15>; + + rpm-requests { + compatible = "qcom,rpm-msm8916"; + qcom,smd-channels = "rpm_requests"; + /* ... */ + }; + }; + }; + # GLINK + - | + #include + #include + + remoteproc { + compatible = "qcom,qcm2290-rpm-proc", "qcom,rpm-proc"; + + glink-edge { + compatible = "qcom,glink-rpm"; + interrupts = ; + qcom,rpm-msg-ram = <&rpm_msg_ram>; + mboxes = <&apcs_glb 0>; + + rpm-requests { + compatible = "qcom,rpm-qcm2290"; + qcom,glink-channels = "rpm_requests"; + /* ... */ + }; + }; + }; diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml b/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml index af24f9a3cdf1..9a04d192e7e4 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml +++ b/Documentation/devicetree/bindings/remoteproc/qcom,sm8350-pas.yaml @@ -139,7 +139,7 @@ examples: #include #include #include - #include + #include remoteproc@30000000 { compatible = "qcom,sm8450-adsp-pas"; @@ -160,8 +160,8 @@ examples: memory-region = <&adsp_mem>; - power-domains = <&rpmhpd SM8450_LCX>, - <&rpmhpd SM8450_LMX>; + power-domains = <&rpmhpd RPMHPD_LCX>, + <&rpmhpd RPMHPD_LMX>; power-domain-names = "lcx", "lmx"; qcom,qmp = <&aoss_qmp>; diff --git a/Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml b/Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml index 0d50f6a54af3..49db66801429 100644 --- a/Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml +++ b/Documentation/devicetree/bindings/reset/xlnx,zynqmp-reset.yaml @@ -32,6 +32,7 @@ properties: enum: - xlnx,zynqmp-reset - xlnx,versal-reset + - xlnx,versal-net-reset "#reset-cells": const: 1 diff --git a/Documentation/devicetree/bindings/soc/loongson/loongson,ls2k-pmc.yaml b/Documentation/devicetree/bindings/soc/loongson/loongson,ls2k-pmc.yaml new file mode 100644 index 000000000000..da2dcfeebf12 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/loongson/loongson,ls2k-pmc.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/loongson/loongson,ls2k-pmc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Loongson-2 Power Manager controller + +maintainers: + - Yinbo Zhu + +properties: + compatible: + items: + - enum: + - loongson,ls2k0500-pmc + - loongson,ls2k1000-pmc + - const: syscon + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + loongson,suspend-address: + $ref: /schemas/types.yaml#/definitions/uint64 + description: + The "loongson,suspend-address" is a deep sleep state (Suspend To + RAM) firmware entry address which was jumped from kernel and it's + value was dependent on specific platform firmware code. In + addition, the PM need according to it to indicate that current + SoC whether support Suspend To RAM. + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + #include + + power-management@1fe27000 { + compatible = "loongson,ls2k1000-pmc", "syscon"; + reg = <0x1fe27000 0x58>; + interrupt-parent = <&liointc1>; + interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + loongson,suspend-address = <0x0 0x1c000500>; + }; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml index 65c02a7fef80..2fa725b8af5d 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml @@ -34,22 +34,27 @@ properties: - qcom,rpm-apq8084 - qcom,rpm-ipq6018 - qcom,rpm-ipq9574 + - qcom,rpm-mdm9607 - qcom,rpm-msm8226 + - qcom,rpm-msm8610 - qcom,rpm-msm8909 - qcom,rpm-msm8916 + - qcom,rpm-msm8917 - qcom,rpm-msm8936 + - qcom,rpm-msm8937 + - qcom,rpm-msm8952 - qcom,rpm-msm8953 - qcom,rpm-msm8974 - qcom,rpm-msm8976 - qcom,rpm-msm8994 - qcom,rpm-msm8996 - qcom,rpm-msm8998 + - qcom,rpm-qcm2290 + - qcom,rpm-qcs404 - qcom,rpm-sdm660 - qcom,rpm-sm6115 - qcom,rpm-sm6125 - qcom,rpm-sm6375 - - qcom,rpm-qcm2290 - - qcom,rpm-qcs404 clock-controller: $ref: /schemas/clock/qcom,rpmcc.yaml# @@ -81,12 +86,18 @@ if: contains: enum: - qcom,rpm-apq8084 + - qcom,rpm-mdm9607 - qcom,rpm-msm8226 + - qcom,rpm-msm8610 + - qcom,rpm-msm8909 - qcom,rpm-msm8916 + - qcom,rpm-msm8917 - qcom,rpm-msm8936 + - qcom,rpm-msm8937 + - qcom,rpm-msm8952 + - qcom,rpm-msm8953 - qcom,rpm-msm8974 - qcom,rpm-msm8976 - - qcom,rpm-msm8953 - qcom,rpm-msm8994 then: properties: @@ -109,10 +120,10 @@ examples: #include #include - smd { - compatible = "qcom,smd"; + remoteproc { + compatible = "qcom,msm8916-rpm-proc", "qcom,rpm-proc"; - rpm { + smd-edge { interrupts = ; qcom,ipc = <&apcs 8 0>; qcom,smd-edge = <15>; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml index 063e595c12f7..4819ce90d206 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.yaml @@ -15,6 +15,12 @@ description: The Qualcomm Shared Memory Driver is a FIFO based communication channel for sending data between the various subsystems in Qualcomm platforms. + Using the top-level SMD node is deprecated. Instead, the SMD edges are defined + directly below the device node representing the respective remote subsystem + or remote processor. + +deprecated: true + properties: compatible: const: qcom,smd @@ -37,6 +43,7 @@ examples: # The following example represents a smd node, with one edge representing the # "rpm" subsystem. For the "rpm" subsystem we have a device tied to the # "rpm_request" channel. + # NOTE: This is deprecated, represent the RPM using "qcom,rpm-proc" instead. - | #include diff --git a/Documentation/devicetree/bindings/sram/qcom,ocmem.yaml b/Documentation/devicetree/bindings/sram/qcom,ocmem.yaml index 4bbf6db0b6bd..61c784ef7b51 100644 --- a/Documentation/devicetree/bindings/sram/qcom,ocmem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,ocmem.yaml @@ -15,7 +15,9 @@ description: | properties: compatible: - const: qcom,msm8974-ocmem + enum: + - qcom,msm8226-ocmem # v1.1.0 + - qcom,msm8974-ocmem # v1.4.0 reg: items: @@ -28,11 +30,13 @@ properties: - const: mem clocks: + minItems: 1 items: - description: Core clock - description: Interface clock clock-names: + minItems: 1 items: - const: core - const: iface @@ -58,6 +62,26 @@ required: additionalProperties: false +allOf: + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8974-ocmem + then: + properties: + clocks: + minItems: 2 + clock-names: + minItems: 2 + else: + properties: + clocks: + minItems: 1 + clock-names: + minItems: 1 + patternProperties: "-sram@[0-9a-f]+$": type: object diff --git a/MAINTAINERS b/MAINTAINERS index 2ef597fd0a3c..4005784ffa7b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2508,16 +2508,6 @@ S: Maintained W: http://www.digriz.org.uk/ts78xx/kernel F: arch/arm/mach-orion5x/ts78xx-* -ARM/OXNAS platform support -M: Neil Armstrong -L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) -L: linux-oxnas@groups.io (moderated for non-subscribers) -S: Maintained -F: arch/arm/boot/dts/ox8*.dts* -F: arch/arm/mach-oxnas/ -F: drivers/power/reset/oxnas-restart.c -N: oxnas - ARM/QUALCOMM CHROMEBOOK SUPPORT R: cros-qcom-dts-watchers@chromium.org F: arch/arm64/boot/dts/qcom/sc7180* @@ -2945,14 +2935,13 @@ M: Sudeep Holla M: Lorenzo Pieralisi L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained -F: */*/*/vexpress* -F: */*/vexpress* -F: arch/arm/boot/dts/arm/vexpress* +N: mps2 +N: vexpress F: arch/arm/mach-versatile/ F: arch/arm64/boot/dts/arm/ -F: drivers/clk/versatile/clk-vexpress-osc.c F: drivers/clocksource/timer-versatile.c -N: mps2 +X: drivers/cpufreq/vexpress-spc-cpufreq.c +X: Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml ARM/VFP SUPPORT M: Russell King @@ -5402,7 +5391,7 @@ M: Kukjin Kim R: Krzysztof Kozlowski L: linux-pm@vger.kernel.org L: linux-samsung-soc@vger.kernel.org -S: Supported +S: Maintained F: arch/arm/mach-exynos/pm.c F: drivers/cpuidle/cpuidle-exynos.c F: include/linux/platform_data/cpuidle-exynos.h @@ -9378,6 +9367,13 @@ W: https://www.hisilicon.com F: Documentation/devicetree/bindings/i2c/hisilicon,ascend910-i2c.yaml F: drivers/i2c/busses/i2c-hisi.c +HISILICON KUNPENG SOC HCCS DRIVER +M: Huisong Li +S: Maintained +F: Documentation/ABI/testing/sysfs-devices-platform-kunpeng_hccs +F: drivers/soc/hisilicon/kunpeng_hccs.c +F: drivers/soc/hisilicon/kunpeng_hccs.h + HISILICON LPC BUS DRIVER M: Jay Fang S: Maintained @@ -12353,6 +12349,13 @@ S: Maintained F: Documentation/devicetree/bindings/hwinfo/loongson,ls2k-chipid.yaml F: drivers/soc/loongson/loongson2_guts.c +LOONGSON-2 SOC SERIES PM DRIVER +M: Yinbo Zhu +L: linux-pm@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/soc/loongson/loongson,ls2k-pmc.yaml +F: drivers/soc/loongson/loongson2_pm.c + LOONGSON-2 SOC SERIES PINCTRL DRIVER M: zhanghongchen M: Yinbo Zhu @@ -12902,7 +12905,7 @@ F: drivers/power/supply/max77976_charger.c MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS M: Krzysztof Kozlowski L: linux-pm@vger.kernel.org -S: Supported +S: Maintained B: mailto:linux-samsung-soc@vger.kernel.org F: Documentation/devicetree/bindings/power/supply/maxim,max14577.yaml F: Documentation/devicetree/bindings/power/supply/maxim,max77693.yaml @@ -12913,7 +12916,7 @@ MAXIM PMIC AND MUIC DRIVERS FOR EXYNOS BASED BOARDS M: Chanwoo Choi M: Krzysztof Kozlowski L: linux-kernel@vger.kernel.org -S: Supported +S: Maintained B: mailto:linux-samsung-soc@vger.kernel.org F: Documentation/devicetree/bindings/*/maxim,max14577.yaml F: Documentation/devicetree/bindings/*/maxim,max77686.yaml @@ -18884,7 +18887,7 @@ SAMSUNG MULTIFUNCTION PMIC DEVICE DRIVERS M: Krzysztof Kozlowski L: linux-kernel@vger.kernel.org L: linux-samsung-soc@vger.kernel.org -S: Supported +S: Maintained B: mailto:linux-samsung-soc@vger.kernel.org F: Documentation/devicetree/bindings/clock/samsung,s2mps11.yaml F: Documentation/devicetree/bindings/mfd/samsung,s2m*.yaml @@ -18956,7 +18959,7 @@ M: Tomasz Figa M: Chanwoo Choi R: Alim Akhtar L: linux-samsung-soc@vger.kernel.org -S: Supported +S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/snawrocki/clk.git F: Documentation/devicetree/bindings/clock/samsung,*.yaml diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index fcfa280df98a..c98dd6ca2629 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -210,7 +210,8 @@ config TI_PWMSS config TI_SYSC bool "TI sysc interconnect target module driver" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || ARCH_K3 + default y help Generic driver for Texas Instruments interconnect target module found on many TI SoCs. diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 4352745a923c..e2c30b4c9aa6 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -994,75 +994,18 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev, } EXPORT_SYMBOL_GPL(fsl_mc_get_endpoint); -static int parse_mc_ranges(struct device *dev, - int *paddr_cells, - int *mc_addr_cells, - int *mc_size_cells, - const __be32 **ranges_start) -{ - const __be32 *prop; - int range_tuple_cell_count; - int ranges_len; - int tuple_len; - struct device_node *mc_node = dev->of_node; - - *ranges_start = of_get_property(mc_node, "ranges", &ranges_len); - if (!(*ranges_start) || !ranges_len) { - dev_warn(dev, - "missing or empty ranges property for device tree node '%pOFn'\n", - mc_node); - return 0; - } - - *paddr_cells = of_n_addr_cells(mc_node); - - prop = of_get_property(mc_node, "#address-cells", NULL); - if (prop) - *mc_addr_cells = be32_to_cpup(prop); - else - *mc_addr_cells = *paddr_cells; - - prop = of_get_property(mc_node, "#size-cells", NULL); - if (prop) - *mc_size_cells = be32_to_cpup(prop); - else - *mc_size_cells = of_n_size_cells(mc_node); - - range_tuple_cell_count = *paddr_cells + *mc_addr_cells + - *mc_size_cells; - - tuple_len = range_tuple_cell_count * sizeof(__be32); - if (ranges_len % tuple_len != 0) { - dev_err(dev, "malformed ranges property '%pOFn'\n", mc_node); - return -EINVAL; - } - - return ranges_len / tuple_len; -} - static int get_mc_addr_translation_ranges(struct device *dev, struct fsl_mc_addr_translation_range **ranges, u8 *num_ranges) { - int ret; - int paddr_cells; - int mc_addr_cells; - int mc_size_cells; - int i; - const __be32 *ranges_start; - const __be32 *cell; + struct fsl_mc_addr_translation_range *r; + struct of_range_parser parser; + struct of_range range; - ret = parse_mc_ranges(dev, - &paddr_cells, - &mc_addr_cells, - &mc_size_cells, - &ranges_start); - if (ret < 0) - return ret; - - *num_ranges = ret; - if (!ret) { + of_range_parser_init(&parser, dev->of_node); + *num_ranges = of_range_count(&parser); + if (!*num_ranges) { /* * Missing or empty ranges property ("ranges;") for the * 'fsl,qoriq-mc' node. In this case, identity mapping @@ -1078,20 +1021,13 @@ static int get_mc_addr_translation_ranges(struct device *dev, if (!(*ranges)) return -ENOMEM; - cell = ranges_start; - for (i = 0; i < *num_ranges; ++i) { - struct fsl_mc_addr_translation_range *range = &(*ranges)[i]; - - range->mc_region_type = of_read_number(cell, 1); - range->start_mc_offset = of_read_number(cell + 1, - mc_addr_cells - 1); - cell += mc_addr_cells; - range->start_phys_addr = of_read_number(cell, paddr_cells); - cell += paddr_cells; - range->end_mc_offset = range->start_mc_offset + - of_read_number(cell, mc_size_cells); - - cell += mc_size_cells; + r = *ranges; + for_each_of_range(&parser, &range) { + r->mc_region_type = range.flags; + r->start_mc_offset = range.bus_addr; + r->end_mc_offset = range.bus_addr + range.size; + r->start_phys_addr = range.cpu_addr; + r++; } return 0; diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index 52a5d0447390..42c9386a7b42 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -273,7 +273,7 @@ static int weim_probe(struct platform_device *pdev) return -ENOMEM; /* get the resource */ - base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c index bb1606f5ce2d..8e1a38bfcd8b 100644 --- a/drivers/bus/omap_l3_smx.c +++ b/drivers/bus/omap_l3_smx.c @@ -166,19 +166,10 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3) irqreturn_t ret = IRQ_NONE; int_type = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR; - if (!int_type) { + if (!int_type) status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_0); - /* - * if we have a timeout error, there's nothing we can - * do besides rebooting the board. So let's BUG on any - * of such errors and handle the others. timeout error - * is severe and not expected to occur. - */ - BUG_ON(status & L3_STATUS_0_TIMEOUT_MASK); - } else { + else status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_1); - /* No timeout error for debug sources */ - } /* identify the error source */ err_source = __ffs(status); @@ -190,6 +181,14 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3) ret |= omap3_l3_block_irq(l3, error, error_addr); } + /* + * if we have a timeout error, there's nothing we can + * do besides rebooting the board. So let's BUG on any + * of such errors and handle the others. timeout error + * is severe and not expected to occur. + */ + BUG_ON(!int_type && status & L3_STATUS_0_TIMEOUT_MASK); + /* Clear the status register */ clear = (L3_AGENT_STATUS_CLEAR_IA << int_type) | L3_AGENT_STATUS_CLEAR_TA; diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index 696c0aefb0ca..2aefd5dde3c9 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -746,7 +746,6 @@ static int sunxi_rsb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct resource *r; struct sunxi_rsb *rsb; u32 clk_freq = 3000000; int irq, ret; @@ -766,8 +765,7 @@ static int sunxi_rsb_probe(struct platform_device *pdev) rsb->dev = dev; rsb->clk_freq = clk_freq; platform_set_drvdata(pdev, rsb); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rsb->regs = devm_ioremap_resource(dev, r); + rsb->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rsb->regs)) return PTR_ERR(rsb->regs); diff --git a/drivers/bus/tegra-gmi.c b/drivers/bus/tegra-gmi.c index e3506ef37051..59919e99f7cc 100644 --- a/drivers/bus/tegra-gmi.c +++ b/drivers/bus/tegra-gmi.c @@ -211,7 +211,6 @@ static int tegra_gmi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct tegra_gmi *gmi; - struct resource *res; int err; gmi = devm_kzalloc(dev, sizeof(*gmi), GFP_KERNEL); @@ -221,8 +220,7 @@ static int tegra_gmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gmi); gmi->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gmi->base = devm_ioremap_resource(dev, res); + gmi->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(gmi->base)) return PTR_ERR(gmi->base); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 4cb23b9e06ea..eb4e7bee1e20 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -109,6 +109,7 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = { * @cookie: data used by legacy platform callbacks * @name: name if available * @revision: interconnect target module revision + * @sysconfig: saved sysconfig register value * @reserved: target module is reserved and already in use * @enabled: sysc runtime enabled status * @needs_resume: runtime resume needed on resume from suspend @@ -1525,6 +1526,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47424e03, 0xffffffff, + SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), /* Quirks that need to be set based on the module address */ SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff, @@ -3106,7 +3109,7 @@ static int sysc_init_static_data(struct sysc *ddata) match = soc_device_match(sysc_soc_match); if (match && match->data) - sysc_soc->soc = (int)match->data; + sysc_soc->soc = (enum sysc_soc)(uintptr_t)match->data; /* * Check and warn about possible old incomplete dtb. We now want to see diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c index 472a570bd53a..c4e1becbb2d2 100644 --- a/drivers/bus/vexpress-config.c +++ b/drivers/bus/vexpress-config.c @@ -350,7 +350,6 @@ static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = { static int vexpress_syscfg_probe(struct platform_device *pdev) { struct vexpress_syscfg *syscfg; - struct resource *res; struct vexpress_config_bridge *bridge; struct device_node *node; int master; @@ -362,8 +361,7 @@ static int vexpress_syscfg_probe(struct platform_device *pdev) syscfg->dev = &pdev->dev; INIT_LIST_HEAD(&syscfg->funcs); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - syscfg->base = devm_ioremap_resource(&pdev->dev, res); + syscfg->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(syscfg->base)) return PTR_ERR(syscfg->base); diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index ecf5c4de851b..c0cd556fbaae 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -2,19 +2,22 @@ /* * System Control and Management Interface (SCMI) Performance Protocol * - * Copyright (C) 2018-2022 ARM Ltd. + * Copyright (C) 2018-2023 ARM Ltd. */ #define pr_fmt(fmt) "SCMI Notifications PERF - " fmt #include -#include +#include #include +#include #include +#include #include #include #include #include +#include #include @@ -46,6 +49,9 @@ struct scmi_opp { u32 perf; u32 power; u32 trans_latency_us; + u32 indicative_freq; + u32 level_index; + struct hlist_node hash; }; struct scmi_msg_resp_perf_attributes { @@ -66,6 +72,7 @@ struct scmi_msg_resp_perf_domain_attributes { #define SUPPORTS_PERF_LEVEL_NOTIFY(x) ((x) & BIT(28)) #define SUPPORTS_PERF_FASTCHANNELS(x) ((x) & BIT(27)) #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(26)) +#define SUPPORTS_LEVEL_INDEXING(x) ((x) & BIT(25)) __le32 rate_limit_us; __le32 sustained_freq_khz; __le32 sustained_perf_level; @@ -122,12 +129,27 @@ struct scmi_msg_resp_perf_describe_levels { } opp[]; }; +struct scmi_msg_resp_perf_describe_levels_v4 { + __le16 num_returned; + __le16 num_remaining; + struct { + __le32 perf_val; + __le32 power; + __le16 transition_latency_us; + __le16 reserved; + __le32 indicative_freq; + __le32 level_index; + } opp[]; +}; + struct perf_dom_info { + u32 id; bool set_limits; bool set_perf; bool perf_limit_notify; bool perf_level_notify; bool perf_fastchannels; + bool level_indexing_mode; u32 opp_count; u32 sustained_freq_khz; u32 sustained_perf_level; @@ -135,11 +157,26 @@ struct perf_dom_info { char name[SCMI_MAX_STR_SIZE]; struct scmi_opp opp[MAX_OPPS]; struct scmi_fc_info *fc_info; + struct xarray opps_by_idx; + struct xarray opps_by_lvl; + DECLARE_HASHTABLE(opps_by_freq, ilog2(MAX_OPPS)); }; +#define LOOKUP_BY_FREQ(__htp, __freq) \ +({ \ + /* u32 cast is needed to pick right hash func */ \ + u32 f_ = (u32)(__freq); \ + struct scmi_opp *_opp; \ + \ + hash_for_each_possible((__htp), _opp, hash, f_) \ + if (_opp->indicative_freq == f_) \ + break; \ + _opp; \ +}) + struct scmi_perf_info { u32 version; - int num_domains; + u16 num_domains; enum scmi_power_scale power_scale; u64 stats_addr; u32 stats_size; @@ -186,9 +223,20 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph, return ret; } +static void scmi_perf_xa_destroy(void *data) +{ + int domain; + struct scmi_perf_info *pinfo = data; + + for (domain = 0; domain < pinfo->num_domains; domain++) { + xa_destroy(&((pinfo->dom_info + domain)->opps_by_idx)); + xa_destroy(&((pinfo->dom_info + domain)->opps_by_lvl)); + } +} + static int scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, - u32 domain, struct perf_dom_info *dom_info, + struct perf_dom_info *dom_info, u32 version) { int ret; @@ -197,11 +245,11 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, struct scmi_msg_resp_perf_domain_attributes *attr; ret = ph->xops->xfer_get_init(ph, PERF_DOMAIN_ATTRIBUTES, - sizeof(domain), sizeof(*attr), &t); + sizeof(dom_info->id), sizeof(*attr), &t); if (ret) return ret; - put_unaligned_le32(domain, t->tx.buf); + put_unaligned_le32(dom_info->id, t->tx.buf); attr = t->rx.buf; ret = ph->xops->do_xfer(ph, t); @@ -213,6 +261,9 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags); dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags); dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags); + if (PROTOCOL_REV_MAJOR(version) >= 0x4) + dom_info->level_indexing_mode = + SUPPORTS_LEVEL_INDEXING(flags); dom_info->sustained_freq_khz = le32_to_cpu(attr->sustained_freq_khz); dom_info->sustained_perf_level = @@ -236,8 +287,15 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, */ if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(flags)) - ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET, domain, - dom_info->name, SCMI_MAX_STR_SIZE); + ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET, + dom_info->id, dom_info->name, + SCMI_MAX_STR_SIZE); + + if (dom_info->level_indexing_mode) { + xa_init(&dom_info->opps_by_idx); + xa_init(&dom_info->opps_by_lvl); + hash_init(dom_info->opps_by_freq); + } return ret; } @@ -250,7 +308,7 @@ static int opp_cmp_func(const void *opp1, const void *opp2) } struct scmi_perf_ipriv { - u32 domain; + u32 version; struct perf_dom_info *perf_dom; }; @@ -261,7 +319,7 @@ static void iter_perf_levels_prepare_message(void *message, struct scmi_msg_perf_describe_levels *msg = message; const struct scmi_perf_ipriv *p = priv; - msg->domain = cpu_to_le32(p->domain); + msg->domain = cpu_to_le32(p->perf_dom->id); /* Set the number of OPPs to be skipped/already read */ msg->level_index = cpu_to_le32(desc_index); } @@ -277,31 +335,63 @@ static int iter_perf_levels_update_state(struct scmi_iterator_state *st, return 0; } +static inline void +process_response_opp(struct scmi_opp *opp, unsigned int loop_idx, + const struct scmi_msg_resp_perf_describe_levels *r) +{ + opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val); + opp->power = le32_to_cpu(r->opp[loop_idx].power); + opp->trans_latency_us = + le16_to_cpu(r->opp[loop_idx].transition_latency_us); +} + +static inline void +process_response_opp_v4(struct perf_dom_info *dom, struct scmi_opp *opp, + unsigned int loop_idx, + const struct scmi_msg_resp_perf_describe_levels_v4 *r) +{ + opp->perf = le32_to_cpu(r->opp[loop_idx].perf_val); + opp->power = le32_to_cpu(r->opp[loop_idx].power); + opp->trans_latency_us = + le16_to_cpu(r->opp[loop_idx].transition_latency_us); + + /* Note that PERF v4 reports always five 32-bit words */ + opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq); + if (dom->level_indexing_mode) { + opp->level_index = le32_to_cpu(r->opp[loop_idx].level_index); + + xa_store(&dom->opps_by_idx, opp->level_index, opp, GFP_KERNEL); + xa_store(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL); + hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq); + } +} + static int iter_perf_levels_process_response(const struct scmi_protocol_handle *ph, const void *response, struct scmi_iterator_state *st, void *priv) { struct scmi_opp *opp; - const struct scmi_msg_resp_perf_describe_levels *r = response; struct scmi_perf_ipriv *p = priv; opp = &p->perf_dom->opp[st->desc_index + st->loop_idx]; - opp->perf = le32_to_cpu(r->opp[st->loop_idx].perf_val); - opp->power = le32_to_cpu(r->opp[st->loop_idx].power); - opp->trans_latency_us = - le16_to_cpu(r->opp[st->loop_idx].transition_latency_us); + if (PROTOCOL_REV_MAJOR(p->version) <= 0x3) + process_response_opp(opp, st->loop_idx, response); + else + process_response_opp_v4(p->perf_dom, opp, st->loop_idx, + response); p->perf_dom->opp_count++; - dev_dbg(ph->dev, "Level %d Power %d Latency %dus\n", - opp->perf, opp->power, opp->trans_latency_us); + dev_dbg(ph->dev, "Level %d Power %d Latency %dus Ifreq %d Index %d\n", + opp->perf, opp->power, opp->trans_latency_us, + opp->indicative_freq, opp->level_index); return 0; } static int -scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain, - struct perf_dom_info *perf_dom) +scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, + struct perf_dom_info *perf_dom, u32 version) { int ret; void *iter; @@ -311,7 +401,7 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain, .process_response = iter_perf_levels_process_response, }; struct scmi_perf_ipriv ppriv = { - .domain = domain, + .version = version, .perf_dom = perf_dom, }; @@ -333,8 +423,8 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, u32 domain, return ret; } -static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph, - u32 domain, u32 max_perf, u32 min_perf) +static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 max_perf, u32 min_perf) { int ret; struct scmi_xfer *t; @@ -356,31 +446,73 @@ static int scmi_perf_mb_limits_set(const struct scmi_protocol_handle *ph, return ret; } -static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph, - u32 domain, u32 max_perf, u32 min_perf) +static inline struct perf_dom_info * +scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain) { struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; - if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf) - return -EINVAL; + if (domain >= pi->num_domains) + return ERR_PTR(-EINVAL); + return pi->dom_info + domain; +} + +static int __scmi_perf_limits_set(const struct scmi_protocol_handle *ph, + struct perf_dom_info *dom, u32 max_perf, + u32 min_perf) +{ if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].set_addr) { struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT]; trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_SET, - domain, min_perf, max_perf); + dom->id, min_perf, max_perf); iowrite32(max_perf, fci->set_addr); iowrite32(min_perf, fci->set_addr + 4); ph->hops->fastchannel_db_ring(fci->set_db); return 0; } - return scmi_perf_mb_limits_set(ph, domain, max_perf, min_perf); + return scmi_perf_msg_limits_set(ph, dom->id, max_perf, min_perf); } -static int scmi_perf_mb_limits_get(const struct scmi_protocol_handle *ph, - u32 domain, u32 *max_perf, u32 *min_perf) +static int scmi_perf_limits_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 max_perf, u32 min_perf) +{ + struct scmi_perf_info *pi = ph->get_priv(ph); + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); + + if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3 && !max_perf && !min_perf) + return -EINVAL; + + if (dom->level_indexing_mode) { + struct scmi_opp *opp; + + if (min_perf) { + opp = xa_load(&dom->opps_by_lvl, min_perf); + if (!opp) + return -EIO; + + min_perf = opp->level_index; + } + + if (max_perf) { + opp = xa_load(&dom->opps_by_lvl, max_perf); + if (!opp) + return -EIO; + + max_perf = opp->level_index; + } + } + + return __scmi_perf_limits_set(ph, dom, max_perf, min_perf); +} + +static int scmi_perf_msg_limits_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *max_perf, u32 *min_perf) { int ret; struct scmi_xfer *t; @@ -405,27 +537,58 @@ static int scmi_perf_mb_limits_get(const struct scmi_protocol_handle *ph, return ret; } -static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph, - u32 domain, u32 *max_perf, u32 *min_perf) +static int __scmi_perf_limits_get(const struct scmi_protocol_handle *ph, + struct perf_dom_info *dom, u32 *max_perf, + u32 *min_perf) { - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; - if (dom->fc_info && dom->fc_info[PERF_FC_LIMIT].get_addr) { struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LIMIT]; *max_perf = ioread32(fci->get_addr); *min_perf = ioread32(fci->get_addr + 4); trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LIMITS_GET, - domain, *min_perf, *max_perf); + dom->id, *min_perf, *max_perf); return 0; } - return scmi_perf_mb_limits_get(ph, domain, max_perf, min_perf); + return scmi_perf_msg_limits_get(ph, dom->id, max_perf, min_perf); } -static int scmi_perf_mb_level_set(const struct scmi_protocol_handle *ph, - u32 domain, u32 level, bool poll) +static int scmi_perf_limits_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *max_perf, u32 *min_perf) +{ + int ret; + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); + + ret = __scmi_perf_limits_get(ph, dom, max_perf, min_perf); + if (ret) + return ret; + + if (dom->level_indexing_mode) { + struct scmi_opp *opp; + + opp = xa_load(&dom->opps_by_idx, *min_perf); + if (!opp) + return -EIO; + + *min_perf = opp->perf; + + opp = xa_load(&dom->opps_by_idx, *max_perf); + if (!opp) + return -EIO; + + *max_perf = opp->perf; + } + + return 0; +} + +static int scmi_perf_msg_level_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 level, bool poll) { int ret; struct scmi_xfer *t; @@ -446,27 +609,47 @@ static int scmi_perf_mb_level_set(const struct scmi_protocol_handle *ph, return ret; } -static int scmi_perf_level_set(const struct scmi_protocol_handle *ph, - u32 domain, u32 level, bool poll) +static int __scmi_perf_level_set(const struct scmi_protocol_handle *ph, + struct perf_dom_info *dom, u32 level, + bool poll) { - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; - if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr) { struct scmi_fc_info *fci = &dom->fc_info[PERF_FC_LEVEL]; trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_SET, - domain, level, 0); + dom->id, level, 0); iowrite32(level, fci->set_addr); ph->hops->fastchannel_db_ring(fci->set_db); return 0; } - return scmi_perf_mb_level_set(ph, domain, level, poll); + return scmi_perf_msg_level_set(ph, dom->id, level, poll); } -static int scmi_perf_mb_level_get(const struct scmi_protocol_handle *ph, - u32 domain, u32 *level, bool poll) +static int scmi_perf_level_set(const struct scmi_protocol_handle *ph, + u32 domain, u32 level, bool poll) +{ + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); + + if (dom->level_indexing_mode) { + struct scmi_opp *opp; + + opp = xa_load(&dom->opps_by_lvl, level); + if (!opp) + return -EIO; + + level = opp->level_index; + } + + return __scmi_perf_level_set(ph, dom, level, poll); +} + +static int scmi_perf_msg_level_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *level, bool poll) { int ret; struct scmi_xfer *t; @@ -487,20 +670,45 @@ static int scmi_perf_mb_level_get(const struct scmi_protocol_handle *ph, return ret; } -static int scmi_perf_level_get(const struct scmi_protocol_handle *ph, - u32 domain, u32 *level, bool poll) +static int __scmi_perf_level_get(const struct scmi_protocol_handle *ph, + struct perf_dom_info *dom, u32 *level, + bool poll) { - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; - if (dom->fc_info && dom->fc_info[PERF_FC_LEVEL].get_addr) { *level = ioread32(dom->fc_info[PERF_FC_LEVEL].get_addr); trace_scmi_fc_call(SCMI_PROTOCOL_PERF, PERF_LEVEL_GET, - domain, *level, 0); + dom->id, *level, 0); return 0; } - return scmi_perf_mb_level_get(ph, domain, level, poll); + return scmi_perf_msg_level_get(ph, dom->id, level, poll); +} + +static int scmi_perf_level_get(const struct scmi_protocol_handle *ph, + u32 domain, u32 *level, bool poll) +{ + int ret; + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); + + ret = __scmi_perf_level_get(ph, dom, level, poll); + if (ret) + return ret; + + if (dom->level_indexing_mode) { + struct scmi_opp *opp; + + opp = xa_load(&dom->opps_by_idx, *level); + if (!opp) + return -EIO; + + *level = opp->perf; + } + + return 0; } static int scmi_perf_level_limits_notify(const struct scmi_protocol_handle *ph, @@ -574,27 +782,37 @@ static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, unsigned long freq; struct scmi_opp *opp; struct perf_dom_info *dom; - struct scmi_perf_info *pi = ph->get_priv(ph); domain = scmi_dev_domain_id(dev); if (domain < 0) - return domain; + return -EINVAL; - dom = pi->dom_info + domain; + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { - freq = opp->perf * dom->mult_factor; + if (!dom->level_indexing_mode) + freq = opp->perf * dom->mult_factor; + else + freq = opp->indicative_freq * 1000; ret = dev_pm_opp_add(dev, freq, 0); if (ret) { dev_warn(dev, "failed to add opp %luHz\n", freq); while (idx-- > 0) { - freq = (--opp)->perf * dom->mult_factor; + if (!dom->level_indexing_mode) + freq = (--opp)->perf * dom->mult_factor; + else + freq = (--opp)->indicative_freq * 1000; dev_pm_opp_remove(dev, freq); } return ret; } + + dev_dbg(dev, "[%d][%s]:: Registered OPP[%d] %lu\n", + domain, dom->name, idx, freq); } return 0; } @@ -603,14 +821,17 @@ static int scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph, struct device *dev) { + int domain; struct perf_dom_info *dom; - struct scmi_perf_info *pi = ph->get_priv(ph); - int domain = scmi_dev_domain_id(dev); + domain = scmi_dev_domain_id(dev); if (domain < 0) - return domain; + return -EINVAL; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); - dom = pi->dom_info + domain; /* uS to nS */ return dom->opp[dom->opp_count - 1].trans_latency_us * 1000; } @@ -618,10 +839,26 @@ scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph, static int scmi_dvfs_freq_set(const struct scmi_protocol_handle *ph, u32 domain, unsigned long freq, bool poll) { - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; + unsigned int level; + struct perf_dom_info *dom; - return scmi_perf_level_set(ph, domain, freq / dom->mult_factor, poll); + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); + + if (!dom->level_indexing_mode) { + level = freq / dom->mult_factor; + } else { + struct scmi_opp *opp; + + opp = LOOKUP_BY_FREQ(dom->opps_by_freq, freq / 1000); + if (!opp) + return -EIO; + + level = opp->level_index; + } + + return __scmi_perf_level_set(ph, dom, level, poll); } static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain, @@ -629,12 +866,27 @@ static int scmi_dvfs_freq_get(const struct scmi_protocol_handle *ph, u32 domain, { int ret; u32 level; - struct scmi_perf_info *pi = ph->get_priv(ph); - struct perf_dom_info *dom = pi->dom_info + domain; + struct perf_dom_info *dom; - ret = scmi_perf_level_get(ph, domain, &level, poll); - if (!ret) + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); + + ret = __scmi_perf_level_get(ph, dom, &level, poll); + if (ret) + return ret; + + if (!dom->level_indexing_mode) { *freq = level * dom->mult_factor; + } else { + struct scmi_opp *opp; + + opp = xa_load(&dom->opps_by_idx, level); + if (!opp) + return -EIO; + + *freq = opp->indicative_freq * 1000; + } return ret; } @@ -643,18 +895,21 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph, u32 domain, unsigned long *freq, unsigned long *power) { - struct scmi_perf_info *pi = ph->get_priv(ph); struct perf_dom_info *dom; unsigned long opp_freq; int idx, ret = -EINVAL; struct scmi_opp *opp; - dom = pi->dom_info + domain; - if (!dom) - return -EIO; + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return PTR_ERR(dom); for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { - opp_freq = opp->perf * dom->mult_factor; + if (!dom->level_indexing_mode) + opp_freq = opp->perf * dom->mult_factor; + else + opp_freq = opp->indicative_freq * 1000; + if (opp_freq < *freq) continue; @@ -670,10 +925,16 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph, static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph, struct device *dev) { + int domain; struct perf_dom_info *dom; - struct scmi_perf_info *pi = ph->get_priv(ph); - dom = pi->dom_info + scmi_dev_domain_id(dev); + domain = scmi_dev_domain_id(dev); + if (domain < 0) + return false; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return false; return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr; } @@ -831,13 +1092,18 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph) for (domain = 0; domain < pinfo->num_domains; domain++) { struct perf_dom_info *dom = pinfo->dom_info + domain; - scmi_perf_domain_attributes_get(ph, domain, dom, version); - scmi_perf_describe_levels_get(ph, domain, dom); + dom->id = domain; + scmi_perf_domain_attributes_get(ph, dom, version); + scmi_perf_describe_levels_get(ph, dom, version); if (dom->perf_fastchannels) - scmi_perf_domain_init_fc(ph, domain, &dom->fc_info); + scmi_perf_domain_init_fc(ph, dom->id, &dom->fc_info); } + ret = devm_add_action_or_reset(ph->dev, scmi_perf_xa_destroy, pinfo); + if (ret) + return ret; + pinfo->version = version; return ph->set_priv(ph, pinfo); diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index d9dcc20945c6..7cc0dec04587 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2019 NXP + * Copyright 2019,2023 NXP * * Implementation of the SCU IRQ functions using MU. * @@ -9,12 +9,14 @@ #include #include #include +#include #include #include +#include #define IMX_SC_IRQ_FUNC_ENABLE 1 #define IMX_SC_IRQ_FUNC_STATUS 2 -#define IMX_SC_IRQ_NUM_GROUP 4 +#define IMX_SC_IRQ_NUM_GROUP 9 static u32 mu_resource_id; @@ -40,63 +42,102 @@ struct imx_sc_msg_irq_enable { u8 enable; } __packed; +struct scu_wakeup { + u32 mask; + u32 wakeup_src; + bool valid; +}; + +/* Sysfs functions */ +static struct kobject *wakeup_obj; +static ssize_t wakeup_source_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); +static struct kobj_attribute wakeup_source_attr = + __ATTR(wakeup_src, 0660, wakeup_source_show, NULL); + +static struct scu_wakeup scu_irq_wakeup[IMX_SC_IRQ_NUM_GROUP]; + static struct imx_sc_ipc *imx_sc_irq_ipc_handle; static struct work_struct imx_sc_irq_work; -static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain); +static BLOCKING_NOTIFIER_HEAD(imx_scu_irq_notifier_chain); int imx_scu_irq_register_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_register( + return blocking_notifier_chain_register( &imx_scu_irq_notifier_chain, nb); } EXPORT_SYMBOL(imx_scu_irq_register_notifier); int imx_scu_irq_unregister_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_unregister( + return blocking_notifier_chain_unregister( &imx_scu_irq_notifier_chain, nb); } EXPORT_SYMBOL(imx_scu_irq_unregister_notifier); static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group) { - return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain, + return blocking_notifier_call_chain(&imx_scu_irq_notifier_chain, status, (void *)group); } static void imx_scu_irq_work_handler(struct work_struct *work) { - struct imx_sc_msg_irq_get_status msg; - struct imx_sc_rpc_msg *hdr = &msg.hdr; u32 irq_status; int ret; u8 i; for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) { - hdr->ver = IMX_SC_RPC_VERSION; - hdr->svc = IMX_SC_RPC_SVC_IRQ; - hdr->func = IMX_SC_IRQ_FUNC_STATUS; - hdr->size = 2; + if (scu_irq_wakeup[i].mask) { + scu_irq_wakeup[i].valid = false; + scu_irq_wakeup[i].wakeup_src = 0; + } - msg.data.req.resource = mu_resource_id; - msg.data.req.group = i; - - ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true); + ret = imx_scu_irq_get_status(i, &irq_status); if (ret) { pr_err("get irq group %d status failed, ret %d\n", i, ret); return; } - irq_status = msg.data.resp.status; if (!irq_status) continue; + if (scu_irq_wakeup[i].mask & irq_status) { + scu_irq_wakeup[i].valid = true; + scu_irq_wakeup[i].wakeup_src = irq_status & scu_irq_wakeup[i].mask; + } else { + scu_irq_wakeup[i].wakeup_src = irq_status; + } pm_system_wakeup(); imx_scu_irq_notifier_call_chain(irq_status, &i); } } +int imx_scu_irq_get_status(u8 group, u32 *irq_status) +{ + struct imx_sc_msg_irq_get_status msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_IRQ; + hdr->func = IMX_SC_IRQ_FUNC_STATUS; + hdr->size = 2; + + msg.data.req.resource = mu_resource_id; + msg.data.req.group = group; + + ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true); + if (ret) + return ret; + + if (irq_status) + *irq_status = msg.data.resp.status; + + return 0; +} +EXPORT_SYMBOL(imx_scu_irq_get_status); + int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) { struct imx_sc_msg_irq_enable msg; @@ -121,6 +162,11 @@ int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) pr_err("enable irq failed, group %d, mask %d, ret %d\n", group, mask, ret); + if (enable) + scu_irq_wakeup[group].mask |= mask; + else + scu_irq_wakeup[group].mask &= ~mask; + return ret; } EXPORT_SYMBOL(imx_scu_irq_group_enable); @@ -130,6 +176,25 @@ static void imx_scu_irq_callback(struct mbox_client *c, void *msg) schedule_work(&imx_sc_irq_work); } +static ssize_t wakeup_source_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + int i; + + for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) { + if (!scu_irq_wakeup[i].wakeup_src) + continue; + + if (scu_irq_wakeup[i].valid) + sprintf(buf, "Wakeup source group = %d, irq = 0x%x\n", + i, scu_irq_wakeup[i].wakeup_src); + else + sprintf(buf, "Spurious SCU wakeup, group = %d, irq = 0x%x\n", + i, scu_irq_wakeup[i].wakeup_src); + } + + return strlen(buf); +} + int imx_scu_enable_general_irq_channel(struct device *dev) { struct of_phandle_args spec; @@ -169,6 +234,25 @@ int imx_scu_enable_general_irq_channel(struct device *dev) mu_resource_id = IMX_SC_R_MU_0A + i; + /* Create directory under /sysfs/firmware */ + wakeup_obj = kobject_create_and_add("scu_wakeup_source", firmware_kobj); + if (!wakeup_obj) { + ret = -ENOMEM; + goto free_ch; + } + + ret = sysfs_create_file(wakeup_obj, &wakeup_source_attr.attr); + if (ret) { + dev_err(dev, "Cannot create wakeup source src file......\n"); + kobject_put(wakeup_obj); + goto free_ch; + } + + return 0; + +free_ch: + mbox_free_channel(ch); + return ret; } EXPORT_SYMBOL(imx_scu_enable_general_irq_channel); diff --git a/drivers/firmware/imx/imx-scu-soc.c b/drivers/firmware/imx/imx-scu-soc.c index 2f32353de2c9..497192320562 100644 --- a/drivers/firmware/imx/imx-scu-soc.c +++ b/drivers/firmware/imx/imx-scu-soc.c @@ -78,6 +78,22 @@ static int imx_scu_soc_id(void) return msg.data.resp.id; } +static const char *imx_scu_soc_name(u32 id) +{ + switch (id) { + case 0x1: + return "i.MX8QM"; + case 0x2: + return "i.MX8QXP"; + case 0xe: + return "i.MX8DXL"; + default: + break; + } + + return "NULL"; +} + int imx_scu_soc_init(struct device *dev) { struct soc_device_attribute *soc_dev_attr; @@ -113,9 +129,7 @@ int imx_scu_soc_init(struct device *dev) /* format soc_id value passed from SCU firmware */ val = id & 0x1f; - soc_dev_attr->soc_id = devm_kasprintf(dev, GFP_KERNEL, "0x%x", val); - if (!soc_dev_attr->soc_id) - return -ENOMEM; + soc_dev_attr->soc_id = imx_scu_soc_name(val); /* format revision value passed from SCU firmware */ val = (id >> 5) & 0xf; diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 47db49911e7b..14ff9d3504bf 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -20,7 +20,7 @@ #include #define SCU_MU_CHAN_NUM 8 -#define MAX_RX_TIMEOUT (msecs_to_jiffies(30)) +#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000)) struct imx_sc_chan { struct imx_sc_ipc *sc_ipc; @@ -353,7 +353,12 @@ static struct platform_driver imx_scu_driver = { }, .probe = imx_scu_probe, }; -builtin_platform_driver(imx_scu_driver); + +static int __init imx_scu_driver_init(void) +{ + return platform_driver_register(&imx_scu_driver); +} +subsys_initcall_sync(imx_scu_driver_init); MODULE_AUTHOR("Dong Aisheng "); MODULE_DESCRIPTION("IMX SCU firmware protocol driver"); diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index 798bcdb05d84..9a2656d73600 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -292,6 +292,8 @@ static int __init meson_sm_probe(struct platform_device *pdev) return -ENOMEM; chip = of_match_device(meson_sm_ids, dev)->data; + if (!chip) + return -EINVAL; if (chip->cmd_shmem_in_base) { fw->sm_shmem_in_base = meson_sm_map_shmem(chip->cmd_shmem_in_base, diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index fde33acd46b7..06fe8aca870d 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -26,10 +26,6 @@ static bool download_mode = IS_ENABLED(CONFIG_QCOM_SCM_DOWNLOAD_MODE_DEFAULT); module_param(download_mode, bool, 0); -#define SCM_HAS_CORE_CLK BIT(0) -#define SCM_HAS_IFACE_CLK BIT(1) -#define SCM_HAS_BUS_CLK BIT(2) - struct qcom_scm { struct device *dev; struct clk *core_clk; @@ -351,7 +347,7 @@ int qcom_scm_set_warm_boot_addr(void *entry) return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_warm_bits); return 0; } -EXPORT_SYMBOL(qcom_scm_set_warm_boot_addr); +EXPORT_SYMBOL_GPL(qcom_scm_set_warm_boot_addr); /** * qcom_scm_set_cold_boot_addr() - Set the cold boot address for all cpus @@ -364,7 +360,7 @@ int qcom_scm_set_cold_boot_addr(void *entry) return qcom_scm_set_boot_addr(entry, qcom_scm_cpu_cold_bits); return 0; } -EXPORT_SYMBOL(qcom_scm_set_cold_boot_addr); +EXPORT_SYMBOL_GPL(qcom_scm_set_cold_boot_addr); /** * qcom_scm_cpu_power_down() - Power down the cpu @@ -386,7 +382,7 @@ void qcom_scm_cpu_power_down(u32 flags) qcom_scm_call_atomic(__scm ? __scm->dev : NULL, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_cpu_power_down); +EXPORT_SYMBOL_GPL(qcom_scm_cpu_power_down); int qcom_scm_set_remote_state(u32 state, u32 id) { @@ -405,7 +401,7 @@ int qcom_scm_set_remote_state(u32 state, u32 id) return ret ? : res.result[0]; } -EXPORT_SYMBOL(qcom_scm_set_remote_state); +EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state); static int __qcom_scm_set_dload_mode(struct device *dev, bool enable) { @@ -515,7 +511,7 @@ out: return ret ? : res.result[0]; } -EXPORT_SYMBOL(qcom_scm_pas_init_image); +EXPORT_SYMBOL_GPL(qcom_scm_pas_init_image); /** * qcom_scm_pas_metadata_release() - release metadata context @@ -532,7 +528,7 @@ void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx) ctx->phys = 0; ctx->size = 0; } -EXPORT_SYMBOL(qcom_scm_pas_metadata_release); +EXPORT_SYMBOL_GPL(qcom_scm_pas_metadata_release); /** * qcom_scm_pas_mem_setup() - Prepare the memory related to a given peripheral @@ -571,7 +567,7 @@ int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size) return ret ? : res.result[0]; } -EXPORT_SYMBOL(qcom_scm_pas_mem_setup); +EXPORT_SYMBOL_GPL(qcom_scm_pas_mem_setup); /** * qcom_scm_pas_auth_and_reset() - Authenticate the given peripheral firmware @@ -606,7 +602,7 @@ int qcom_scm_pas_auth_and_reset(u32 peripheral) return ret ? : res.result[0]; } -EXPORT_SYMBOL(qcom_scm_pas_auth_and_reset); +EXPORT_SYMBOL_GPL(qcom_scm_pas_auth_and_reset); /** * qcom_scm_pas_shutdown() - Shut down the remote processor @@ -641,7 +637,7 @@ int qcom_scm_pas_shutdown(u32 peripheral) return ret ? : res.result[0]; } -EXPORT_SYMBOL(qcom_scm_pas_shutdown); +EXPORT_SYMBOL_GPL(qcom_scm_pas_shutdown); /** * qcom_scm_pas_supported() - Check if the peripheral authentication service is @@ -670,7 +666,7 @@ bool qcom_scm_pas_supported(u32 peripheral) return ret ? false : !!res.result[0]; } -EXPORT_SYMBOL(qcom_scm_pas_supported); +EXPORT_SYMBOL_GPL(qcom_scm_pas_supported); static int __qcom_scm_pas_mss_reset(struct device *dev, bool reset) { @@ -732,7 +728,7 @@ int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val) return ret < 0 ? ret : 0; } -EXPORT_SYMBOL(qcom_scm_io_readl); +EXPORT_SYMBOL_GPL(qcom_scm_io_readl); int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) { @@ -747,7 +743,7 @@ int qcom_scm_io_writel(phys_addr_t addr, unsigned int val) return qcom_scm_call_atomic(__scm->dev, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_io_writel); +EXPORT_SYMBOL_GPL(qcom_scm_io_writel); /** * qcom_scm_restore_sec_cfg_available() - Check if secure environment @@ -760,7 +756,7 @@ bool qcom_scm_restore_sec_cfg_available(void) return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_MP, QCOM_SCM_MP_RESTORE_SEC_CFG); } -EXPORT_SYMBOL(qcom_scm_restore_sec_cfg_available); +EXPORT_SYMBOL_GPL(qcom_scm_restore_sec_cfg_available); int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) { @@ -779,7 +775,7 @@ int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare) return ret ? : res.result[0]; } -EXPORT_SYMBOL(qcom_scm_restore_sec_cfg); +EXPORT_SYMBOL_GPL(qcom_scm_restore_sec_cfg); int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) { @@ -800,7 +796,7 @@ int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size) return ret ? : res.result[1]; } -EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_size); +EXPORT_SYMBOL_GPL(qcom_scm_iommu_secure_ptbl_size); int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) { @@ -824,7 +820,7 @@ int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare) return ret; } -EXPORT_SYMBOL(qcom_scm_iommu_secure_ptbl_init); +EXPORT_SYMBOL_GPL(qcom_scm_iommu_secure_ptbl_init); int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size) { @@ -839,7 +835,7 @@ int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size) return qcom_scm_call(__scm->dev, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_iommu_set_cp_pool_size); +EXPORT_SYMBOL_GPL(qcom_scm_iommu_set_cp_pool_size); int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size, u32 cp_nonpixel_start, @@ -863,7 +859,7 @@ int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size, return ret ? : res.result[0]; } -EXPORT_SYMBOL(qcom_scm_mem_protect_video_var); +EXPORT_SYMBOL_GPL(qcom_scm_mem_protect_video_var); static int __qcom_scm_assign_mem(struct device *dev, phys_addr_t mem_region, size_t mem_sz, phys_addr_t src, size_t src_sz, @@ -972,7 +968,7 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, *srcvm = next_vm; return 0; } -EXPORT_SYMBOL(qcom_scm_assign_mem); +EXPORT_SYMBOL_GPL(qcom_scm_assign_mem); /** * qcom_scm_ocmem_lock_available() - is OCMEM lock/unlock interface available @@ -982,7 +978,7 @@ bool qcom_scm_ocmem_lock_available(void) return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_OCMEM, QCOM_SCM_OCMEM_LOCK_CMD); } -EXPORT_SYMBOL(qcom_scm_ocmem_lock_available); +EXPORT_SYMBOL_GPL(qcom_scm_ocmem_lock_available); /** * qcom_scm_ocmem_lock() - call OCMEM lock interface to assign an OCMEM @@ -1008,7 +1004,7 @@ int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size, return qcom_scm_call(__scm->dev, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_ocmem_lock); +EXPORT_SYMBOL_GPL(qcom_scm_ocmem_lock); /** * qcom_scm_ocmem_unlock() - call OCMEM unlock interface to release an OCMEM @@ -1031,7 +1027,7 @@ int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size) return qcom_scm_call(__scm->dev, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_ocmem_unlock); +EXPORT_SYMBOL_GPL(qcom_scm_ocmem_unlock); /** * qcom_scm_ice_available() - Is the ICE key programming interface available? @@ -1046,7 +1042,7 @@ bool qcom_scm_ice_available(void) __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES, QCOM_SCM_ES_CONFIG_SET_ICE_KEY); } -EXPORT_SYMBOL(qcom_scm_ice_available); +EXPORT_SYMBOL_GPL(qcom_scm_ice_available); /** * qcom_scm_ice_invalidate_key() - Invalidate an inline encryption key @@ -1072,7 +1068,7 @@ int qcom_scm_ice_invalidate_key(u32 index) return qcom_scm_call(__scm->dev, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_ice_invalidate_key); +EXPORT_SYMBOL_GPL(qcom_scm_ice_invalidate_key); /** * qcom_scm_ice_set_key() - Set an inline encryption key @@ -1138,7 +1134,7 @@ int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size, dma_free_coherent(__scm->dev, key_size, keybuf, key_phys); return ret; } -EXPORT_SYMBOL(qcom_scm_ice_set_key); +EXPORT_SYMBOL_GPL(qcom_scm_ice_set_key); /** * qcom_scm_hdcp_available() - Check if secure environment supports HDCP. @@ -1160,7 +1156,7 @@ bool qcom_scm_hdcp_available(void) return avail; } -EXPORT_SYMBOL(qcom_scm_hdcp_available); +EXPORT_SYMBOL_GPL(qcom_scm_hdcp_available); /** * qcom_scm_hdcp_req() - Send HDCP request. @@ -1207,7 +1203,7 @@ int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) return ret; } -EXPORT_SYMBOL(qcom_scm_hdcp_req); +EXPORT_SYMBOL_GPL(qcom_scm_hdcp_req); int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt) { @@ -1223,7 +1219,7 @@ int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt) return qcom_scm_call(__scm->dev, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_iommu_set_pt_format); +EXPORT_SYMBOL_GPL(qcom_scm_iommu_set_pt_format); int qcom_scm_qsmmu500_wait_safe_toggle(bool en) { @@ -1239,13 +1235,13 @@ int qcom_scm_qsmmu500_wait_safe_toggle(bool en) return qcom_scm_call_atomic(__scm->dev, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_qsmmu500_wait_safe_toggle); +EXPORT_SYMBOL_GPL(qcom_scm_qsmmu500_wait_safe_toggle); bool qcom_scm_lmh_dcvsh_available(void) { return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_LMH, QCOM_SCM_LMH_LIMIT_DCVSH); } -EXPORT_SYMBOL(qcom_scm_lmh_dcvsh_available); +EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh_available); int qcom_scm_lmh_profile_change(u32 profile_id) { @@ -1259,7 +1255,7 @@ int qcom_scm_lmh_profile_change(u32 profile_id) return qcom_scm_call(__scm->dev, &desc, NULL); } -EXPORT_SYMBOL(qcom_scm_lmh_profile_change); +EXPORT_SYMBOL_GPL(qcom_scm_lmh_profile_change); int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val, u64 limit_node, u32 node_id, u64 version) @@ -1297,7 +1293,7 @@ int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val, dma_free_coherent(__scm->dev, payload_size, payload_buf, payload_phys); return ret; } -EXPORT_SYMBOL(qcom_scm_lmh_dcvsh); +EXPORT_SYMBOL_GPL(qcom_scm_lmh_dcvsh); static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) { @@ -1332,7 +1328,7 @@ bool qcom_scm_is_available(void) { return !!__scm; } -EXPORT_SYMBOL(qcom_scm_is_available); +EXPORT_SYMBOL_GPL(qcom_scm_is_available); static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx) { @@ -1405,7 +1401,6 @@ out: static int qcom_scm_probe(struct platform_device *pdev) { struct qcom_scm *scm; - unsigned long clks; int irq, ret; scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL); @@ -1418,51 +1413,22 @@ static int qcom_scm_probe(struct platform_device *pdev) mutex_init(&scm->scm_bw_lock); - clks = (unsigned long)of_device_get_match_data(&pdev->dev); - scm->path = devm_of_icc_get(&pdev->dev, NULL); if (IS_ERR(scm->path)) return dev_err_probe(&pdev->dev, PTR_ERR(scm->path), "failed to acquire interconnect path\n"); - scm->core_clk = devm_clk_get(&pdev->dev, "core"); - if (IS_ERR(scm->core_clk)) { - if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER) - return PTR_ERR(scm->core_clk); + scm->core_clk = devm_clk_get_optional(&pdev->dev, "core"); + if (IS_ERR(scm->core_clk)) + return PTR_ERR(scm->core_clk); - if (clks & SCM_HAS_CORE_CLK) { - dev_err(&pdev->dev, "failed to acquire core clk\n"); - return PTR_ERR(scm->core_clk); - } + scm->iface_clk = devm_clk_get_optional(&pdev->dev, "iface"); + if (IS_ERR(scm->iface_clk)) + return PTR_ERR(scm->iface_clk); - scm->core_clk = NULL; - } - - scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); - if (IS_ERR(scm->iface_clk)) { - if (PTR_ERR(scm->iface_clk) == -EPROBE_DEFER) - return PTR_ERR(scm->iface_clk); - - if (clks & SCM_HAS_IFACE_CLK) { - dev_err(&pdev->dev, "failed to acquire iface clk\n"); - return PTR_ERR(scm->iface_clk); - } - - scm->iface_clk = NULL; - } - - scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); - if (IS_ERR(scm->bus_clk)) { - if (PTR_ERR(scm->bus_clk) == -EPROBE_DEFER) - return PTR_ERR(scm->bus_clk); - - if (clks & SCM_HAS_BUS_CLK) { - dev_err(&pdev->dev, "failed to acquire bus clk\n"); - return PTR_ERR(scm->bus_clk); - } - - scm->bus_clk = NULL; - } + scm->bus_clk = devm_clk_get_optional(&pdev->dev, "bus"); + if (IS_ERR(scm->bus_clk)) + return PTR_ERR(scm->bus_clk); scm->reset.ops = &qcom_scm_pas_reset_ops; scm->reset.nr_resets = 1; @@ -1512,39 +1478,15 @@ static void qcom_scm_shutdown(struct platform_device *pdev) } static const struct of_device_id qcom_scm_dt_match[] = { - { .compatible = "qcom,scm-apq8064", - /* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */ - }, - { .compatible = "qcom,scm-apq8084", .data = (void *)(SCM_HAS_CORE_CLK | - SCM_HAS_IFACE_CLK | - SCM_HAS_BUS_CLK) - }, - { .compatible = "qcom,scm-ipq4019" }, - { .compatible = "qcom,scm-mdm9607", .data = (void *)(SCM_HAS_CORE_CLK | - SCM_HAS_IFACE_CLK | - SCM_HAS_BUS_CLK) }, - { .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK }, - { .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK }, - { .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK | - SCM_HAS_IFACE_CLK | - SCM_HAS_BUS_CLK) - }, - { .compatible = "qcom,scm-msm8953", .data = (void *)(SCM_HAS_CORE_CLK | - SCM_HAS_IFACE_CLK | - SCM_HAS_BUS_CLK) - }, - { .compatible = "qcom,scm-msm8974", .data = (void *)(SCM_HAS_CORE_CLK | - SCM_HAS_IFACE_CLK | - SCM_HAS_BUS_CLK) - }, - { .compatible = "qcom,scm-msm8976", .data = (void *)(SCM_HAS_CORE_CLK | - SCM_HAS_IFACE_CLK | - SCM_HAS_BUS_CLK) - }, - { .compatible = "qcom,scm-msm8994" }, - { .compatible = "qcom,scm-msm8996" }, - { .compatible = "qcom,scm-sm6375", .data = (void *)SCM_HAS_CORE_CLK }, { .compatible = "qcom,scm" }, + + /* Legacy entries kept for backwards compatibility */ + { .compatible = "qcom,scm-apq8064" }, + { .compatible = "qcom,scm-apq8084" }, + { .compatible = "qcom,scm-ipq4019" }, + { .compatible = "qcom,scm-msm8953" }, + { .compatible = "qcom,scm-msm8974" }, + { .compatible = "qcom,scm-msm8996" }, {} }; MODULE_DEVICE_TABLE(of, qcom_scm_dt_match); diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 039d92a595ec..26a37f47f4ca 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -97,7 +97,6 @@ struct ti_sci_desc { * @node: list head * @host_id: Host ID * @users: Number of users of this instance - * @is_suspending: Flag set to indicate in suspend path. */ struct ti_sci_info { struct device *dev; @@ -116,7 +115,6 @@ struct ti_sci_info { u8 host_id; /* protected by ti_sci_list_mutex */ int users; - bool is_suspending; }; #define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl) @@ -418,14 +416,14 @@ static inline int ti_sci_do_xfer(struct ti_sci_info *info, ret = 0; - if (!info->is_suspending) { + if (system_state <= SYSTEM_RUNNING) { /* And we wait for the response. */ timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); if (!wait_for_completion_timeout(&xfer->done, timeout)) ret = -ETIMEDOUT; } else { /* - * If we are suspending, we cannot use wait_for_completion_timeout + * If we are !running, we cannot use wait_for_completion_timeout * during noirq phase, so we must manually poll the completion. */ ret = read_poll_timeout_atomic(try_wait_for_completion, done_state, @@ -1978,8 +1976,6 @@ static int ti_sci_free_irq(const struct ti_sci_handle *handle, u32 valid_params, * @src_index: IRQ source index within the source device * @dst_id: Device ID of the IRQ destination * @dst_host_irq: IRQ number of the destination device - * @vint_irq: Boolean specifying if this interrupt belongs to - * Interrupt Aggregator. * * Return: 0 if all went fine, else return appropriate error. */ @@ -2026,8 +2022,6 @@ static int ti_sci_cmd_set_event_map(const struct ti_sci_handle *handle, * @src_index: IRQ source index within the source device * @dst_id: Device ID of the IRQ destination * @dst_host_irq: IRQ number of the destination device - * @vint_irq: Boolean specifying if this interrupt belongs to - * Interrupt Aggregator. * * Return: 0 if all went fine, else return appropriate error. */ @@ -2620,6 +2614,7 @@ fail: * configuration flags * @handle: Pointer to TI SCI handle * @proc_id: Processor ID this request is for + * @bootvector: Processor Boot vector (start address) * @config_flags_set: Configuration flags to be set * @config_flags_clear: Configuration flags to be cleared. * @@ -2736,9 +2731,13 @@ fail: } /** - * ti_sci_cmd_get_boot_status() - Command to get the processor boot status + * ti_sci_cmd_proc_get_status() - Command to get the processor boot status * @handle: Pointer to TI SCI handle * @proc_id: Processor ID this request is for + * @bv: Processor Boot vector (start address) + * @cfg_flags: Processor specific configuration flags + * @ctrl_flags: Processor specific control flags + * @sts_flags: Processor specific status flags * * Return: 0 if all went well, else returns appropriate error value. */ @@ -3256,7 +3255,7 @@ EXPORT_SYMBOL_GPL(devm_ti_sci_get_of_resource); * @handle: TISCI handle * @dev: Device pointer to which the resource is assigned * @dev_id: TISCI device id to which the resource is assigned - * @suub_type: TISCI resource subytpe representing the resource. + * @sub_type: TISCI resource subytpe representing the resource. * * Return: Pointer to ti_sci_resource if all went well else appropriate * error pointer. @@ -3281,35 +3280,6 @@ static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode, return NOTIFY_BAD; } -static void ti_sci_set_is_suspending(struct ti_sci_info *info, bool is_suspending) -{ - info->is_suspending = is_suspending; -} - -static int ti_sci_suspend(struct device *dev) -{ - struct ti_sci_info *info = dev_get_drvdata(dev); - /* - * We must switch operation to polled mode now as drivers and the genpd - * layer may make late TI SCI calls to change clock and device states - * from the noirq phase of suspend. - */ - ti_sci_set_is_suspending(info, true); - - return 0; -} - -static int ti_sci_resume(struct device *dev) -{ - struct ti_sci_info *info = dev_get_drvdata(dev); - - ti_sci_set_is_suspending(info, false); - - return 0; -} - -static DEFINE_SIMPLE_DEV_PM_OPS(ti_sci_pm_ops, ti_sci_suspend, ti_sci_resume); - /* Description for K2G */ static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = { .default_host_id = 2, @@ -3516,7 +3486,6 @@ static struct platform_driver ti_sci_driver = { .driver = { .name = "ti-sci", .of_match_table = of_match_ptr(ti_sci_of_match), - .pm = &ti_sci_pm_ops, }, }; module_platform_driver(ti_sci_driver); diff --git a/drivers/genpd/amlogic/meson-ee-pwrc.c b/drivers/genpd/amlogic/meson-ee-pwrc.c index f54acffc83f9..cfb796d40d9d 100644 --- a/drivers/genpd/amlogic/meson-ee-pwrc.c +++ b/drivers/genpd/amlogic/meson-ee-pwrc.c @@ -4,13 +4,12 @@ * Author: Neil Armstrong */ -#include #include #include #include #include #include -#include +#include #include #include #include diff --git a/drivers/genpd/amlogic/meson-gx-pwrc-vpu.c b/drivers/genpd/amlogic/meson-gx-pwrc-vpu.c index 5d4f12800d93..33df520eab95 100644 --- a/drivers/genpd/amlogic/meson-gx-pwrc-vpu.c +++ b/drivers/genpd/amlogic/meson-gx-pwrc-vpu.c @@ -5,13 +5,12 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include #include #include #include #include #include -#include +#include #include #include #include diff --git a/drivers/genpd/amlogic/meson-secure-pwrc.c b/drivers/genpd/amlogic/meson-secure-pwrc.c index 25b4b71df9b8..89c881c56cd7 100644 --- a/drivers/genpd/amlogic/meson-secure-pwrc.c +++ b/drivers/genpd/amlogic/meson-secure-pwrc.c @@ -7,10 +7,11 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include +#include #include #include #include +#include #include #include #include @@ -120,6 +121,22 @@ static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = { SEC_PD(RSA, 0), }; +static struct meson_secure_pwrc_domain_desc c3_pwrc_domains[] = { + SEC_PD(C3_NNA, 0), + SEC_PD(C3_AUDIO, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_SDIOA, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_EMMC, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_USB_COMB, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_SDCARD, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_ETH, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_GE2D, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_CVE, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_GDC_WRAP, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_ISP_TOP, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_MIPI_ISP_WRAP, GENPD_FLAG_ALWAYS_ON), + SEC_PD(C3_VCODEC, 0), +}; + static struct meson_secure_pwrc_domain_desc s4_pwrc_domains[] = { SEC_PD(S4_DOS_HEVC, 0), SEC_PD(S4_DOS_VDEC, 0), @@ -179,7 +196,7 @@ static int meson_secure_pwrc_probe(struct platform_device *pdev) for (i = 0 ; i < match->count ; ++i) { struct meson_secure_pwrc_domain *dom = &pwrc->domains[i]; - if (!match->domains[i].index) + if (!match->domains[i].name) continue; dom->pwrc = pwrc; @@ -202,6 +219,11 @@ static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = { .count = ARRAY_SIZE(a1_pwrc_domains), }; +static struct meson_secure_pwrc_domain_data amlogic_secure_c3_pwrc_data = { + .domains = c3_pwrc_domains, + .count = ARRAY_SIZE(c3_pwrc_domains), +}; + static struct meson_secure_pwrc_domain_data meson_secure_s4_pwrc_data = { .domains = s4_pwrc_domains, .count = ARRAY_SIZE(s4_pwrc_domains), @@ -212,6 +234,10 @@ static const struct of_device_id meson_secure_pwrc_match_table[] = { .compatible = "amlogic,meson-a1-pwrc", .data = &meson_secure_a1_pwrc_data, }, + { + .compatible = "amlogic,c3-pwrc", + .data = &amlogic_secure_c3_pwrc_data, + }, { .compatible = "amlogic,meson-s4-pwrc", .data = &meson_secure_s4_pwrc_data, diff --git a/drivers/genpd/bcm/bcm-pmb.c b/drivers/genpd/bcm/bcm-pmb.c index 9407cac47fdb..a72ba26ecf9d 100644 --- a/drivers/genpd/bcm/bcm-pmb.c +++ b/drivers/genpd/bcm/bcm-pmb.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/genpd/bcm/bcm63xx-power.c b/drivers/genpd/bcm/bcm63xx-power.c index aa72e13d5d0e..98b0c2430dbc 100644 --- a/drivers/genpd/bcm/bcm63xx-power.c +++ b/drivers/genpd/bcm/bcm63xx-power.c @@ -14,7 +14,6 @@ #include #include #include -#include struct bcm63xx_power_dev { struct generic_pm_domain genpd; diff --git a/drivers/genpd/bcm/raspberrypi-power.c b/drivers/genpd/bcm/raspberrypi-power.c index 58175af982a0..06196ebfe03b 100644 --- a/drivers/genpd/bcm/raspberrypi-power.c +++ b/drivers/genpd/bcm/raspberrypi-power.c @@ -7,7 +7,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/genpd/imx/gpcv2.c b/drivers/genpd/imx/gpcv2.c index 4b3300b090a8..fbd3d92f8cd8 100644 --- a/drivers/genpd/imx/gpcv2.c +++ b/drivers/genpd/imx/gpcv2.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/genpd/imx/imx8m-blk-ctrl.c b/drivers/genpd/imx/imx8m-blk-ctrl.c index afbca0d48c14..cc5ef6e2f0a8 100644 --- a/drivers/genpd/imx/imx8m-blk-ctrl.c +++ b/drivers/genpd/imx/imx8m-blk-ctrl.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/genpd/imx/imx8mp-blk-ctrl.c b/drivers/genpd/imx/imx8mp-blk-ctrl.c index 1c1fcab4979a..c6ac32c1a8c1 100644 --- a/drivers/genpd/imx/imx8mp-blk-ctrl.c +++ b/drivers/genpd/imx/imx8mp-blk-ctrl.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/genpd/imx/imx93-blk-ctrl.c b/drivers/genpd/imx/imx93-blk-ctrl.c index 2c600329436c..40bd90f8b977 100644 --- a/drivers/genpd/imx/imx93-blk-ctrl.c +++ b/drivers/genpd/imx/imx93-blk-ctrl.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -187,6 +187,8 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd) return 0; } +static struct lock_class_key blk_ctrl_genpd_lock_class; + static int imx93_blk_ctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -269,6 +271,19 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev) goto cleanup_pds; } + /* + * We use runtime PM to trigger power on/off of the upstream GPC + * domain, as a strict hierarchical parent/child power domain + * setup doesn't allow us to meet the sequencing requirements. + * This means we have nested locking of genpd locks, without the + * nesting being visible at the genpd level, so we need a + * separate lock class to make lockdep aware of the fact that + * this are separate domain locks that can be nested without a + * self-deadlock. + */ + lockdep_set_class(&domain->genpd.mlock, + &blk_ctrl_genpd_lock_class); + bc->onecell_data.domains[i] = &domain->genpd; } diff --git a/drivers/genpd/imx/imx93-pd.c b/drivers/genpd/imx/imx93-pd.c index 832deeed8fd6..b9e60d136875 100644 --- a/drivers/genpd/imx/imx93-pd.c +++ b/drivers/genpd/imx/imx93-pd.c @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include #include diff --git a/drivers/genpd/qcom/cpr.c b/drivers/genpd/qcom/cpr.c index 144ea68e0920..94a3f0977212 100644 --- a/drivers/genpd/qcom/cpr.c +++ b/drivers/genpd/qcom/cpr.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/genpd/qcom/rpmhpd.c b/drivers/genpd/qcom/rpmhpd.c index 63c35a32065b..a87e336d5e33 100644 --- a/drivers/genpd/qcom/rpmhpd.c +++ b/drivers/genpd/qcom/rpmhpd.c @@ -9,12 +9,12 @@ #include #include #include -#include #include #include #include #include #include +#include #define domain_to_rpmhpd(domain) container_of(domain, struct rpmhpd, pd) @@ -307,6 +307,21 @@ static const struct rpmhpd_desc sdx65_desc = { .num_pds = ARRAY_SIZE(sdx65_rpmhpds), }; +/* SDX75 RPMH powerdomains */ +static struct rpmhpd *sdx75_rpmhpds[] = { + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, + [RPMHPD_MSS] = &mss, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_MXC] = &mxc, +}; + +static const struct rpmhpd_desc sdx75_desc = { + .rpmhpds = sdx75_rpmhpds, + .num_pds = ARRAY_SIZE(sdx75_rpmhpds), +}; + /* SM6350 RPMH powerdomains */ static struct rpmhpd *sm6350_rpmhpds[] = { [SM6350_CX] = &cx_w_mx_parent, @@ -359,16 +374,16 @@ static const struct rpmhpd_desc sa8155p_desc = { /* SM8250 RPMH powerdomains */ static struct rpmhpd *sm8250_rpmhpds[] = { - [SM8250_CX] = &cx_w_mx_parent, - [SM8250_CX_AO] = &cx_ao_w_mx_parent, - [SM8250_EBI] = &ebi, - [SM8250_GFX] = &gfx, - [SM8250_LCX] = &lcx, - [SM8250_LMX] = &lmx, - [SM8250_MMCX] = &mmcx, - [SM8250_MMCX_AO] = &mmcx_ao, - [SM8250_MX] = &mx, - [SM8250_MX_AO] = &mx_ao, + [RPMHPD_CX] = &cx_w_mx_parent, + [RPMHPD_CX_AO] = &cx_ao_w_mx_parent, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_LCX] = &lcx, + [RPMHPD_LMX] = &lmx, + [RPMHPD_MMCX] = &mmcx, + [RPMHPD_MMCX_AO] = &mmcx_ao, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, }; static const struct rpmhpd_desc sm8250_desc = { @@ -378,19 +393,19 @@ static const struct rpmhpd_desc sm8250_desc = { /* SM8350 Power domains */ static struct rpmhpd *sm8350_rpmhpds[] = { - [SM8350_CX] = &cx_w_mx_parent, - [SM8350_CX_AO] = &cx_ao_w_mx_parent, - [SM8350_EBI] = &ebi, - [SM8350_GFX] = &gfx, - [SM8350_LCX] = &lcx, - [SM8350_LMX] = &lmx, - [SM8350_MMCX] = &mmcx, - [SM8350_MMCX_AO] = &mmcx_ao, - [SM8350_MSS] = &mss, - [SM8350_MX] = &mx, - [SM8350_MX_AO] = &mx_ao, - [SM8350_MXC] = &mxc, - [SM8350_MXC_AO] = &mxc_ao, + [RPMHPD_CX] = &cx_w_mx_parent, + [RPMHPD_CX_AO] = &cx_ao_w_mx_parent, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_LCX] = &lcx, + [RPMHPD_LMX] = &lmx, + [RPMHPD_MMCX] = &mmcx, + [RPMHPD_MMCX_AO] = &mmcx_ao, + [RPMHPD_MSS] = &mss, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_MXC] = &mxc, + [RPMHPD_MXC_AO] = &mxc_ao, }; static const struct rpmhpd_desc sm8350_desc = { @@ -400,19 +415,19 @@ static const struct rpmhpd_desc sm8350_desc = { /* SM8450 RPMH powerdomains */ static struct rpmhpd *sm8450_rpmhpds[] = { - [SM8450_CX] = &cx, - [SM8450_CX_AO] = &cx_ao, - [SM8450_EBI] = &ebi, - [SM8450_GFX] = &gfx, - [SM8450_LCX] = &lcx, - [SM8450_LMX] = &lmx, - [SM8450_MMCX] = &mmcx_w_cx_parent, - [SM8450_MMCX_AO] = &mmcx_ao_w_cx_parent, - [SM8450_MSS] = &mss, - [SM8450_MX] = &mx, - [SM8450_MX_AO] = &mx_ao, - [SM8450_MXC] = &mxc, - [SM8450_MXC_AO] = &mxc_ao, + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_LCX] = &lcx, + [RPMHPD_LMX] = &lmx, + [RPMHPD_MMCX] = &mmcx_w_cx_parent, + [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, + [RPMHPD_MSS] = &mss, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_MXC] = &mxc, + [RPMHPD_MXC_AO] = &mxc_ao, }; static const struct rpmhpd_desc sm8450_desc = { @@ -422,20 +437,20 @@ static const struct rpmhpd_desc sm8450_desc = { /* SM8550 RPMH powerdomains */ static struct rpmhpd *sm8550_rpmhpds[] = { - [SM8550_CX] = &cx, - [SM8550_CX_AO] = &cx_ao, - [SM8550_EBI] = &ebi, - [SM8550_GFX] = &gfx, - [SM8550_LCX] = &lcx, - [SM8550_LMX] = &lmx, - [SM8550_MMCX] = &mmcx_w_cx_parent, - [SM8550_MMCX_AO] = &mmcx_ao_w_cx_parent, - [SM8550_MSS] = &mss, - [SM8550_MX] = &mx, - [SM8550_MX_AO] = &mx_ao, - [SM8550_MXC] = &mxc, - [SM8550_MXC_AO] = &mxc_ao, - [SM8550_NSP] = &nsp, + [RPMHPD_CX] = &cx, + [RPMHPD_CX_AO] = &cx_ao, + [RPMHPD_EBI] = &ebi, + [RPMHPD_GFX] = &gfx, + [RPMHPD_LCX] = &lcx, + [RPMHPD_LMX] = &lmx, + [RPMHPD_MMCX] = &mmcx_w_cx_parent, + [RPMHPD_MMCX_AO] = &mmcx_ao_w_cx_parent, + [RPMHPD_MSS] = &mss, + [RPMHPD_MX] = &mx, + [RPMHPD_MX_AO] = &mx_ao, + [RPMHPD_MXC] = &mxc, + [RPMHPD_MXC_AO] = &mxc_ao, + [RPMHPD_NSP] = &nsp, }; static const struct rpmhpd_desc sm8550_desc = { @@ -545,6 +560,7 @@ static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc }, { .compatible = "qcom,sdx55-rpmhpd", .data = &sdx55_desc}, { .compatible = "qcom,sdx65-rpmhpd", .data = &sdx65_desc}, + { .compatible = "qcom,sdx75-rpmhpd", .data = &sdx75_desc}, { .compatible = "qcom,sm6350-rpmhpd", .data = &sm6350_desc }, { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc }, diff --git a/drivers/genpd/qcom/rpmpd.c b/drivers/genpd/qcom/rpmpd.c index 99b017fd76b7..3135dd1dafe0 100644 --- a/drivers/genpd/qcom/rpmpd.c +++ b/drivers/genpd/qcom/rpmpd.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -58,6 +57,7 @@ struct rpmpd { struct qcom_smd_rpm *rpm; unsigned int max_state; __le32 key; + bool state_synced; }; struct rpmpd_desc { @@ -823,7 +823,11 @@ static int rpmpd_aggregate_corner(struct rpmpd *pd) unsigned int this_active_corner = 0, this_sleep_corner = 0; unsigned int peer_active_corner = 0, peer_sleep_corner = 0; - to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner); + /* Clamp to the highest corner/level if sync_state isn't done yet */ + if (!pd->state_synced) + this_active_corner = this_sleep_corner = pd->max_state - 1; + else + to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner); if (peer && peer->enabled) to_active_sleep(peer, peer->corner, &peer_active_corner, @@ -973,11 +977,38 @@ static int rpmpd_probe(struct platform_device *pdev) return of_genpd_add_provider_onecell(pdev->dev.of_node, data); } +static void rpmpd_sync_state(struct device *dev) +{ + const struct rpmpd_desc *desc = of_device_get_match_data(dev); + struct rpmpd **rpmpds = desc->rpmpds; + struct rpmpd *pd; + unsigned int i; + int ret; + + mutex_lock(&rpmpd_lock); + for (i = 0; i < desc->num_pds; i++) { + pd = rpmpds[i]; + if (!pd) + continue; + + pd->state_synced = true; + + if (!pd->enabled) + pd->corner = 0; + + ret = rpmpd_aggregate_corner(pd); + if (ret) + dev_err(dev, "failed to sync %s: %d\n", pd->pd.name, ret); + } + mutex_unlock(&rpmpd_lock); +} + static struct platform_driver rpmpd_driver = { .driver = { .name = "qcom-rpmpd", .of_match_table = rpmpd_match_table, .suppress_bind_attrs = true, + .sync_state = rpmpd_sync_state, }, .probe = rpmpd_probe, }; diff --git a/drivers/genpd/rockchip/pm-domains.c b/drivers/genpd/rockchip/pm-domains.c index e3de49e671dc..d5d3ecb38283 100644 --- a/drivers/genpd/rockchip/pm-domains.c +++ b/drivers/genpd/rockchip/pm-domains.c @@ -976,6 +976,7 @@ static const struct rockchip_domain_info px30_pm_domains[] = { static const struct rockchip_domain_info rv1126_pm_domains[] = { [RV1126_PD_VEPU] = DOMAIN_RV1126("vepu", BIT(2), BIT(9), BIT(9), false), [RV1126_PD_VI] = DOMAIN_RV1126("vi", BIT(4), BIT(6), BIT(6), false), + [RV1126_PD_VO] = DOMAIN_RV1126("vo", BIT(5), BIT(7), BIT(7), false), [RV1126_PD_ISPP] = DOMAIN_RV1126("ispp", BIT(1), BIT(8), BIT(8), false), [RV1126_PD_VDPU] = DOMAIN_RV1126("vdpu", BIT(3), BIT(10), BIT(10), false), [RV1126_PD_NVM] = DOMAIN_RV1126("nvm", BIT(7), BIT(11), BIT(11), false), diff --git a/drivers/genpd/samsung/exynos-pm-domains.c b/drivers/genpd/samsung/exynos-pm-domains.c index d07f3c9d6903..9b502e8751d1 100644 --- a/drivers/genpd/samsung/exynos-pm-domains.c +++ b/drivers/genpd/samsung/exynos-pm-domains.c @@ -11,11 +11,12 @@ #include #include +#include #include #include #include +#include #include -#include #include struct exynos_pm_domain_config { diff --git a/drivers/genpd/ti/omap_prm.c b/drivers/genpd/ti/omap_prm.c index ecd9a8bdd7c0..c2feae3a634c 100644 --- a/drivers/genpd/ti/omap_prm.c +++ b/drivers/genpd/ti/omap_prm.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -943,10 +942,6 @@ static int omap_prm_probe(struct platform_device *pdev) struct omap_prm *prm; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - data = of_device_get_match_data(&pdev->dev); if (!data) return -ENOTSUPP; @@ -955,6 +950,10 @@ static int omap_prm_probe(struct platform_device *pdev) if (!prm) return -ENOMEM; + prm->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(prm->base)) + return PTR_ERR(prm->base); + while (data->base != res->start) { if (!data->base) return -EINVAL; @@ -963,10 +962,6 @@ static int omap_prm_probe(struct platform_device *pdev) prm->data = data; - prm->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(prm->base)) - return PTR_ERR(prm->base); - ret = omap_prm_domain_init(&pdev->dev, prm); if (ret) return ret; diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index ba543ed9c154..5018a06060e6 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -242,5 +242,4 @@ static int __init fpga_irq_of_init(struct device_node *node, } IRQCHIP_DECLARE(arm_fpga, "arm,versatile-fpga-irq", fpga_irq_of_init); IRQCHIP_DECLARE(arm_fpga_sic, "arm,versatile-sic", fpga_irq_of_init); -IRQCHIP_DECLARE(ox810se_rps, "oxsemi,ox810se-rps-irq", fpga_irq_of_init); #endif diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 9339f80b21c5..a7ab3d377206 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -32,8 +32,7 @@ #include #include #include -#include -#include +#include #include #define DRVNAME "brcmstb-dpfe" diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c index 0ef8cc878b95..2bf34da85d22 100644 --- a/drivers/memory/da8xx-ddrctl.c +++ b/drivers/memory/da8xx-ddrctl.c @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c index 9e8d8e9c5ad8..2509e5152036 100644 --- a/drivers/memory/fsl_ifc.c +++ b/drivers/memory/fsl_ifc.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/memory/jz4780-nemc.c b/drivers/memory/jz4780-nemc.c index 555f7ac3b7dd..e5a93e7da15f 100644 --- a/drivers/memory/jz4780-nemc.c +++ b/drivers/memory/jz4780-nemc.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/memory/pl353-smc.c b/drivers/memory/pl353-smc.c index d39ee7d06665..48540817e046 100644 --- a/drivers/memory/pl353-smc.c +++ b/drivers/memory/pl353-smc.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 75fcba45ec1b..9695b2d3ae59 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c index c491cd549644..6d019dbd721c 100644 --- a/drivers/memory/samsung/exynos5422-dmc.c +++ b/drivers/memory/samsung/exynos5422-dmc.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c index ffec26a99313..9015e8277dc8 100644 --- a/drivers/memory/stm32-fmc2-ebi.c +++ b/drivers/memory/stm32-fmc2-ebi.c @@ -7,8 +7,10 @@ #include #include #include +#include #include #include +#include #include #include diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index deb6e65b59af..67d6e70b4eab 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index d780a84241fe..470b7dbab2c2 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c index 6ad8a4023dd7..4007f4e16d74 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -155,6 +155,73 @@ DEFINE_DEBUGFS_ATTRIBUTE(tegra186_emc_debug_max_rate_fops, tegra186_emc_debug_max_rate_get, tegra186_emc_debug_max_rate_set, "%llu\n"); +static int tegra186_emc_get_emc_dvfs_latency(struct tegra186_emc *emc) +{ + struct mrq_emc_dvfs_latency_response response; + struct tegra_bpmp_message msg; + unsigned int i; + int err; + + memset(&msg, 0, sizeof(msg)); + msg.mrq = MRQ_EMC_DVFS_LATENCY; + msg.tx.data = NULL; + msg.tx.size = 0; + msg.rx.data = &response; + msg.rx.size = sizeof(response); + + err = tegra_bpmp_transfer(emc->bpmp, &msg); + if (err < 0) { + dev_err(emc->dev, "failed to EMC DVFS pairs: %d\n", err); + return err; + } + if (msg.rx.ret < 0) { + dev_err(emc->dev, "EMC DVFS MRQ failed: %d (BPMP error code)\n", msg.rx.ret); + return -EINVAL; + } + + emc->debugfs.min_rate = ULONG_MAX; + emc->debugfs.max_rate = 0; + + emc->num_dvfs = response.num_pairs; + + emc->dvfs = devm_kmalloc_array(emc->dev, emc->num_dvfs, sizeof(*emc->dvfs), GFP_KERNEL); + if (!emc->dvfs) + return -ENOMEM; + + dev_dbg(emc->dev, "%u DVFS pairs:\n", emc->num_dvfs); + + for (i = 0; i < emc->num_dvfs; i++) { + emc->dvfs[i].rate = response.pairs[i].freq * 1000; + emc->dvfs[i].latency = response.pairs[i].latency; + + if (emc->dvfs[i].rate < emc->debugfs.min_rate) + emc->debugfs.min_rate = emc->dvfs[i].rate; + + if (emc->dvfs[i].rate > emc->debugfs.max_rate) + emc->debugfs.max_rate = emc->dvfs[i].rate; + + dev_dbg(emc->dev, " %2u: %lu Hz -> %lu us\n", i, + emc->dvfs[i].rate, emc->dvfs[i].latency); + } + + err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, emc->debugfs.max_rate); + if (err < 0) { + dev_err(emc->dev, "failed to set rate range [%lu-%lu] for %pC\n", + emc->debugfs.min_rate, emc->debugfs.max_rate, emc->clk); + return err; + } + + emc->debugfs.root = debugfs_create_dir("emc", NULL); + debugfs_create_file("available_rates", 0444, emc->debugfs.root, emc, + &tegra186_emc_debug_available_rates_fops); + debugfs_create_file("min_rate", 0644, emc->debugfs.root, emc, + &tegra186_emc_debug_min_rate_fops); + debugfs_create_file("max_rate", 0644, emc->debugfs.root, emc, + &tegra186_emc_debug_max_rate_fops); + + return 0; +} + /* * tegra_emc_icc_set_bw() - Set BW api for EMC provider * @src: ICC node for External Memory Controller (EMC) @@ -251,10 +318,7 @@ err_msg: static int tegra186_emc_probe(struct platform_device *pdev) { struct tegra_mc *mc = dev_get_drvdata(pdev->dev.parent); - struct mrq_emc_dvfs_latency_response response; - struct tegra_bpmp_message msg; struct tegra186_emc *emc; - unsigned int i; int err; emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL); @@ -275,69 +339,11 @@ static int tegra186_emc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, emc); emc->dev = &pdev->dev; - memset(&msg, 0, sizeof(msg)); - msg.mrq = MRQ_EMC_DVFS_LATENCY; - msg.tx.data = NULL; - msg.tx.size = 0; - msg.rx.data = &response; - msg.rx.size = sizeof(response); - - err = tegra_bpmp_transfer(emc->bpmp, &msg); - if (err < 0) { - dev_err(&pdev->dev, "failed to EMC DVFS pairs: %d\n", err); - goto put_bpmp; + if (tegra_bpmp_mrq_is_supported(emc->bpmp, MRQ_EMC_DVFS_LATENCY)) { + err = tegra186_emc_get_emc_dvfs_latency(emc); + if (err) + goto put_bpmp; } - if (msg.rx.ret < 0) { - err = -EINVAL; - dev_err(&pdev->dev, "EMC DVFS MRQ failed: %d (BPMP error code)\n", msg.rx.ret); - goto put_bpmp; - } - - emc->debugfs.min_rate = ULONG_MAX; - emc->debugfs.max_rate = 0; - - emc->num_dvfs = response.num_pairs; - - emc->dvfs = devm_kmalloc_array(&pdev->dev, emc->num_dvfs, - sizeof(*emc->dvfs), GFP_KERNEL); - if (!emc->dvfs) { - err = -ENOMEM; - goto put_bpmp; - } - - dev_dbg(&pdev->dev, "%u DVFS pairs:\n", emc->num_dvfs); - - for (i = 0; i < emc->num_dvfs; i++) { - emc->dvfs[i].rate = response.pairs[i].freq * 1000; - emc->dvfs[i].latency = response.pairs[i].latency; - - if (emc->dvfs[i].rate < emc->debugfs.min_rate) - emc->debugfs.min_rate = emc->dvfs[i].rate; - - if (emc->dvfs[i].rate > emc->debugfs.max_rate) - emc->debugfs.max_rate = emc->dvfs[i].rate; - - dev_dbg(&pdev->dev, " %2u: %lu Hz -> %lu us\n", i, - emc->dvfs[i].rate, emc->dvfs[i].latency); - } - - err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, - emc->debugfs.max_rate); - if (err < 0) { - dev_err(&pdev->dev, - "failed to set rate range [%lu-%lu] for %pC\n", - emc->debugfs.min_rate, emc->debugfs.max_rate, - emc->clk); - goto put_bpmp; - } - - emc->debugfs.root = debugfs_create_dir("emc", NULL); - debugfs_create_file("available_rates", S_IRUGO, emc->debugfs.root, - emc, &tegra186_emc_debug_available_rates_fops); - debugfs_create_file("min_rate", S_IRUGO | S_IWUSR, emc->debugfs.root, - emc, &tegra186_emc_debug_min_rate_fops); - debugfs_create_file("max_rate", S_IRUGO | S_IWUSR, emc->debugfs.root, - emc, &tegra186_emc_debug_max_rate_fops); if (mc && mc->soc->icc_ops) { if (tegra_bpmp_mrq_is_supported(emc->bpmp, MRQ_BWMGR_INT)) { diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index 7bb73f06fad3..533f85a4b2bd 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index fcd7738fcb53..544bfd216a22 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c @@ -5,8 +5,9 @@ #include #include +#include #include -#include +#include #include #include diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c index ae5f982f861b..3300bde47c13 100644 --- a/drivers/memory/tegra/tegra210-emc-core.c +++ b/drivers/memory/tegra/tegra210-emc-core.c @@ -9,10 +9,10 @@ #include #include #include +#include #include -#include -#include #include +#include #include #include #include diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c index 8fb83b39f5f5..9e5b5dbd9c8d 100644 --- a/drivers/memory/tegra/tegra234.c +++ b/drivers/memory/tegra/tegra234.c @@ -12,6 +12,10 @@ #include #include "mc.h" +/* + * MC Client entries are sorted in the increasing order of the + * override and security register offsets. + */ static const struct tegra_mc_client tegra234_mc_clients[] = { { .id = TEGRA234_MEMORY_CLIENT_HDAR, @@ -25,6 +29,130 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0xac, }, }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVENCSRD, + .name = "nvencsrd", + .bpmp_id = TEGRA_ICC_BPMP_NVENC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVENC, + .regs = { + .sid = { + .override = 0xe0, + .security = 0xe4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE6AR, + .name = "pcie6ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE6, + .regs = { + .sid = { + .override = 0x140, + .security = 0x144, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE6AW, + .name = "pcie6aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE6, + .regs = { + .sid = { + .override = 0x148, + .security = 0x14c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE7AR, + .name = "pcie7ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE7, + .regs = { + .sid = { + .override = 0x150, + .security = 0x154, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVENCSWR, + .name = "nvencswr", + .bpmp_id = TEGRA_ICC_BPMP_NVENC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVENC, + .regs = { + .sid = { + .override = 0x158, + .security = 0x15c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA0RDB, + .name = "dla0rdb", + .sid = TEGRA234_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x160, + .security = 0x164, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA0RDB1, + .name = "dla0rdb1", + .sid = TEGRA234_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x168, + .security = 0x16c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA0WRB, + .name = "dla0wrb", + .sid = TEGRA234_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x170, + .security = 0x174, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDB, + .name = "dla0rdb", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x178, + .security = 0x17c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE7AW, + .name = "pcie7aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE7, + .regs = { + .sid = { + .override = 0x180, + .security = 0x184, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE8AR, + .name = "pcie8ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_8, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE8, + .regs = { + .sid = { + .override = 0x190, + .security = 0x194, + }, + }, }, { .id = TEGRA234_MEMORY_CLIENT_HDAW, .name = "hdaw", @@ -37,6 +165,102 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x1ac, }, }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE8AW, + .name = "pcie8aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_8, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE8, + .regs = { + .sid = { + .override = 0x1d8, + .security = 0x1dc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE9AR, + .name = "pcie9ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_9, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE9, + .regs = { + .sid = { + .override = 0x1e0, + .security = 0x1e4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE6AR1, + .name = "pcie6ar1", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE6, + .regs = { + .sid = { + .override = 0x1e8, + .security = 0x1ec, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE9AW, + .name = "pcie9aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_9, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE9, + .regs = { + .sid = { + .override = 0x1f0, + .security = 0x1f4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE10AR, + .name = "pcie10ar", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE10, + .regs = { + .sid = { + .override = 0x1f8, + .security = 0x1fc, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE10AW, + .name = "pcie10aw", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE10, + .regs = { + .sid = { + .override = 0x200, + .security = 0x204, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE10AR1, + .name = "pcie10ar1", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE10, + .regs = { + .sid = { + .override = 0x240, + .security = 0x244, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_PCIE7AR1, + .name = "pcie7ar1", + .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_PCIE7, + .regs = { + .sid = { + .override = 0x248, + .security = 0x24c, + }, + }, }, { .id = TEGRA234_MEMORY_CLIENT_MGBEARD, .name = "mgbeard", @@ -157,6 +381,50 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x33c, }, }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VICSRD, + .name = "vicsrd", + .bpmp_id = TEGRA_ICC_BPMP_VIC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_VIC, + .regs = { + .sid = { + .override = 0x360, + .security = 0x364, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VICSWR, + .name = "vicswr", + .bpmp_id = TEGRA_ICC_BPMP_VIC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_VIC, + .regs = { + .sid = { + .override = 0x368, + .security = 0x36c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDB1, + .name = "dla0rdb1", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x370, + .security = 0x374, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1WRB, + .name = "dla0wrb", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x378, + .security = 0x37c, + }, + }, }, { .id = TEGRA234_MEMORY_CLIENT_VI2W, .name = "vi2w", @@ -182,15 +450,27 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_VI2FALW, - .name = "vi2falw", - .bpmp_id = TEGRA_ICC_BPMP_VI2FAL, - .type = TEGRA_ICC_ISO_VIFAL, - .sid = TEGRA234_SID_ISO_VI2FALC, + .id = TEGRA234_MEMORY_CLIENT_NVDECSRD, + .name = "nvdecsrd", + .bpmp_id = TEGRA_ICC_BPMP_NVDEC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDEC, .regs = { .sid = { - .override = 0x3e0, - .security = 0x3e4, + .override = 0x3c0, + .security = 0x3c4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVDECSWR, + .name = "nvdecswr", + .bpmp_id = TEGRA_ICC_BPMP_NVDEC, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVDEC, + .regs = { + .sid = { + .override = 0x3c8, + .security = 0x3cc, }, }, }, { @@ -217,6 +497,42 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x3dc, }, }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VI2FALW, + .name = "vi2falw", + .bpmp_id = TEGRA_ICC_BPMP_VI2FAL, + .type = TEGRA_ICC_ISO_VIFAL, + .sid = TEGRA234_SID_ISO_VI2FALC, + .regs = { + .sid = { + .override = 0x3e0, + .security = 0x3e4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVJPGSRD, + .name = "nvjpgsrd", + .bpmp_id = TEGRA_ICC_BPMP_NVJPG_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVJPG, + .regs = { + .sid = { + .override = 0x3f0, + .security = 0x3f4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVJPGSWR, + .name = "nvjpgswr", + .bpmp_id = TEGRA_ICC_BPMP_NVJPG_0, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_NVJPG, + .regs = { + .sid = { + .override = 0x3f8, + .security = 0x3fc, + }, + }, }, { .id = TEGRA234_MEMORY_CLIENT_NVDISPLAYR, .name = "nvdisplayr", @@ -229,18 +545,6 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x494, }, }, - }, { - .id = TEGRA234_MEMORY_CLIENT_NVDISPLAYR1, - .name = "nvdisplayr1", - .bpmp_id = TEGRA_ICC_BPMP_DISPLAY, - .type = TEGRA_ICC_ISO_DISPLAY, - .sid = TEGRA234_SID_ISO_NVDISPLAY, - .regs = { - .sid = { - .override = 0x508, - .security = 0x50c, - }, - }, }, { .id = TEGRA234_MEMORY_CLIENT_BPMPR, .name = "bpmpr", @@ -305,6 +609,18 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x504, }, }, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVDISPLAYR1, + .name = "nvdisplayr1", + .bpmp_id = TEGRA_ICC_BPMP_DISPLAY, + .type = TEGRA_ICC_ISO_DISPLAY, + .sid = TEGRA234_SID_ISO_NVDISPLAY, + .regs = { + .sid = { + .override = 0x508, + .security = 0x50c, + }, + }, }, { .id = TEGRA234_MEMORY_CLIENT_DLA0RDA, .name = "dla0rda", @@ -335,26 +651,6 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x604, }, }, - }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0RDB, - .name = "dla0rdb", - .sid = TEGRA234_SID_NVDLA0, - .regs = { - .sid = { - .override = 0x160, - .security = 0x164, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0RDA1, - .name = "dla0rda1", - .sid = TEGRA234_SID_NVDLA0, - .regs = { - .sid = { - .override = 0x748, - .security = 0x74c, - }, - }, }, { .id = TEGRA234_MEMORY_CLIENT_DLA0FALWRB, .name = "dla0falwrb", @@ -365,26 +661,6 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x60c, }, }, - }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0RDB1, - .name = "dla0rdb1", - .sid = TEGRA234_SID_NVDLA0, - .regs = { - .sid = { - .override = 0x168, - .security = 0x16c, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_DLA0WRB, - .name = "dla0wrb", - .sid = TEGRA234_SID_NVDLA0, - .regs = { - .sid = { - .override = 0x170, - .security = 0x174, - }, - }, }, { .id = TEGRA234_MEMORY_CLIENT_DLA1RDA, .name = "dla0rda", @@ -415,26 +691,6 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x624, }, }, - }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1RDB, - .name = "dla0rdb", - .sid = TEGRA234_SID_NVDLA1, - .regs = { - .sid = { - .override = 0x178, - .security = 0x17c, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1RDA1, - .name = "dla0rda1", - .sid = TEGRA234_SID_NVDLA1, - .regs = { - .sid = { - .override = 0x750, - .security = 0x754, - }, - }, }, { .id = TEGRA234_MEMORY_CLIENT_DLA1FALWRB, .name = "dla0falwrb", @@ -445,26 +701,6 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x62c, }, }, - }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1RDB1, - .name = "dla0rdb1", - .sid = TEGRA234_SID_NVDLA1, - .regs = { - .sid = { - .override = 0x370, - .security = 0x374, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_DLA1WRB, - .name = "dla0wrb", - .sid = TEGRA234_SID_NVDLA1, - .regs = { - .sid = { - .override = 0x378, - .security = 0x37c, - }, - }, }, { .id = TEGRA234_MEMORY_CLIENT_PCIE0R, .name = "pcie0r", @@ -609,6 +845,26 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .security = 0x71c, }, }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA0RDA1, + .name = "dla0rda1", + .sid = TEGRA234_SID_NVDLA0, + .regs = { + .sid = { + .override = 0x748, + .security = 0x74c, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_DLA1RDA1, + .name = "dla0rda1", + .sid = TEGRA234_SID_NVDLA1, + .regs = { + .sid = { + .override = 0x750, + .security = 0x754, + }, + }, }, { .id = TEGRA234_MEMORY_CLIENT_PCIE5R1, .name = "pcie5r1", @@ -622,159 +878,27 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE6AR, - .name = "pcie6ar", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, + .id = TEGRA234_MEMORY_CLIENT_NVJPG1SRD, + .name = "nvjpg1srd", + .bpmp_id = TEGRA_ICC_BPMP_NVJPG_1, .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE6, + .sid = TEGRA234_SID_NVJPG1, .regs = { .sid = { - .override = 0x140, - .security = 0x144, + .override = 0x918, + .security = 0x91c, }, }, }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE6AW, - .name = "pcie6aw", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, + .id = TEGRA234_MEMORY_CLIENT_NVJPG1SWR, + .name = "nvjpg1swr", + .bpmp_id = TEGRA_ICC_BPMP_NVJPG_1, .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE6, + .sid = TEGRA234_SID_NVJPG1, .regs = { .sid = { - .override = 0x148, - .security = 0x14c, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE6AR1, - .name = "pcie6ar1", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_6, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE6, - .regs = { - .sid = { - .override = 0x1e8, - .security = 0x1ec, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE7AR, - .name = "pcie7ar", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE7, - .regs = { - .sid = { - .override = 0x150, - .security = 0x154, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE7AW, - .name = "pcie7aw", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE7, - .regs = { - .sid = { - .override = 0x180, - .security = 0x184, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE7AR1, - .name = "pcie7ar1", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_7, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE7, - .regs = { - .sid = { - .override = 0x248, - .security = 0x24c, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE8AR, - .name = "pcie8ar", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_8, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE8, - .regs = { - .sid = { - .override = 0x190, - .security = 0x194, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE8AW, - .name = "pcie8aw", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_8, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE8, - .regs = { - .sid = { - .override = 0x1d8, - .security = 0x1dc, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE9AR, - .name = "pcie9ar", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_9, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE9, - .regs = { - .sid = { - .override = 0x1e0, - .security = 0x1e4, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE9AW, - .name = "pcie9aw", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_9, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE9, - .regs = { - .sid = { - .override = 0x1f0, - .security = 0x1f4, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE10AR, - .name = "pcie10ar", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE10, - .regs = { - .sid = { - .override = 0x1f8, - .security = 0x1fc, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE10AW, - .name = "pcie10aw", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE10, - .regs = { - .sid = { - .override = 0x200, - .security = 0x204, - }, - }, - }, { - .id = TEGRA234_MEMORY_CLIENT_PCIE10AR1, - .name = "pcie10ar1", - .bpmp_id = TEGRA_ICC_BPMP_PCIE_10, - .type = TEGRA_ICC_NISO, - .sid = TEGRA234_SID_PCIE10, - .regs = { - .sid = { - .override = 0x240, - .security = 0x244, + .override = 0x920, + .security = 0x924, }, }, }, { @@ -792,6 +916,16 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { .name = "sw_cluster2", .bpmp_id = TEGRA_ICC_BPMP_CPU_CLUSTER2, .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVL1R, + .name = "nvl1r", + .bpmp_id = TEGRA_ICC_BPMP_GPU, + .type = TEGRA_ICC_NISO, + }, { + .id = TEGRA234_MEMORY_CLIENT_NVL1W, + .name = "nvl1w", + .bpmp_id = TEGRA_ICC_BPMP_GPU, + .type = TEGRA_ICC_NISO, }, }; diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c index c91e9b7e2e01..9eae25c57ec6 100644 --- a/drivers/memory/tegra/tegra30-emc.c +++ b/drivers/memory/tegra/tegra30-emc.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index 84316357513d..06f8b35e0a14 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -3,8 +3,8 @@ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. */ +#include #include -#include #include #include diff --git a/drivers/net/ipa/ipa_power.c b/drivers/net/ipa/ipa_power.c index 921eecf3eff6..0eaa7a7f3343 100644 --- a/drivers/net/ipa/ipa_power.c +++ b/drivers/net/ipa/ipa_power.c @@ -324,15 +324,12 @@ void ipa_power_retention(struct ipa *ipa, bool enable) { static const char fmt[] = "{ class: bcm, res: ipa_pc, val: %c }"; struct ipa_power *power = ipa->power; - char buf[36]; /* Exactly enough for fmt[]; size a multiple of 4 */ int ret; if (!power->qmp) return; /* Not needed on this platform */ - (void)snprintf(buf, sizeof(buf), fmt, enable ? '1' : '0'); - - ret = qmp_send(power->qmp, buf, sizeof(buf)); + ret = qmp_send(power->qmp, fmt, enable ? '1' : '0'); if (ret) dev_err(power->dev, "error %d sending QMP %sable request\n", ret, enable ? "en" : "dis"); diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index 192c7aa0e39e..4ee5e67a9f03 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -23,19 +23,13 @@ static int q6v5_load_state_toggle(struct qcom_q6v5 *q6v5, bool enable) { - char buf[Q6V5_LOAD_STATE_MSG_LEN]; int ret; if (!q6v5->qmp) return 0; - ret = snprintf(buf, sizeof(buf), - "{class: image, res: load_state, name: %s, val: %s}", + ret = qmp_send(q6v5->qmp, "{class: image, res: load_state, name: %s, val: %s}", q6v5->load_state, enable ? "on" : "off"); - - WARN_ON(ret >= Q6V5_LOAD_STATE_MSG_LEN); - - ret = qmp_send(q6v5->qmp, buf, sizeof(buf)); if (ret) dev_err(q6v5->dev, "failed to toggle load state\n"); diff --git a/drivers/reset/hisilicon/hi6220_reset.c b/drivers/reset/hisilicon/hi6220_reset.c index 5ca145b64e63..8d1fce18ded7 100644 --- a/drivers/reset/hisilicon/hi6220_reset.c +++ b/drivers/reset/hisilicon/hi6220_reset.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/reset/hisilicon/reset-hi3660.c b/drivers/reset/hisilicon/reset-hi3660.c index 965f5ceba7d8..1beb275275ad 100644 --- a/drivers/reset/hisilicon/reset-hi3660.c +++ b/drivers/reset/hisilicon/reset-hi3660.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include @@ -90,8 +90,8 @@ static int hi3660_reset_probe(struct platform_device *pdev) "hisi,rst-syscon"); } if (IS_ERR(rc->map)) { - dev_err(dev, "failed to get hisilicon,rst-syscon\n"); - return PTR_ERR(rc->map); + return dev_err_probe(dev, PTR_ERR(rc->map), + "failed to get hisilicon,rst-syscon\n"); } rc->rst.ops = &hi3660_reset_ops, diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c index a8b8f5ea77ec..b5d620132052 100644 --- a/drivers/reset/reset-ath79.c +++ b/drivers/reset/reset-ath79.c @@ -93,8 +93,6 @@ static int ath79_reset_probe(struct platform_device *pdev) if (!ath79_reset) return -ENOMEM; - platform_set_drvdata(pdev, ath79_reset); - ath79_reset->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ath79_reset->base)) return PTR_ERR(ath79_reset->base); diff --git a/drivers/reset/reset-bcm6345.c b/drivers/reset/reset-bcm6345.c index ac6c7ad1deda..aa9353439e70 100644 --- a/drivers/reset/reset-bcm6345.c +++ b/drivers/reset/reset-bcm6345.c @@ -102,8 +102,6 @@ static int bcm6345_reset_probe(struct platform_device *pdev) if (!bcm6345_reset) return -ENOMEM; - platform_set_drvdata(pdev, bcm6345_reset); - bcm6345_reset->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(bcm6345_reset->base)) return PTR_ERR(bcm6345_reset->base); diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c index d2408725eb2c..dd01fe11c5cb 100644 --- a/drivers/reset/reset-imx7.c +++ b/drivers/reset/reset-imx7.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/reset/reset-intel-gw.c b/drivers/reset/reset-intel-gw.c index effc177db80a..a5a01388ae7f 100644 --- a/drivers/reset/reset-intel-gw.c +++ b/drivers/reset/reset-intel-gw.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/reset/reset-k210.c b/drivers/reset/reset-k210.c index 1b6e03522b40..b62a2fd44e4e 100644 --- a/drivers/reset/reset-k210.c +++ b/drivers/reset/reset-k210.c @@ -3,7 +3,6 @@ * Copyright (c) 2020 Western Digital Corporation or its affiliates. */ #include -#include #include #include #include diff --git a/drivers/reset/reset-lantiq.c b/drivers/reset/reset-lantiq.c index 549ba45d8597..652a45890cb2 100644 --- a/drivers/reset/reset-lantiq.c +++ b/drivers/reset/reset-lantiq.c @@ -173,7 +173,6 @@ static int lantiq_rcu_reset_probe(struct platform_device *pdev) return -ENOMEM; priv->dev = &pdev->dev; - platform_set_drvdata(pdev, priv); err = lantiq_rcu_reset_of_parse(pdev, priv); if (err) diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c index 36ec95518905..28fb85772b3e 100644 --- a/drivers/reset/reset-lpc18xx.c +++ b/drivers/reset/reset-lpc18xx.c @@ -188,8 +188,6 @@ static int lpc18xx_rgu_probe(struct platform_device *pdev) rc->rcdev.ops = &lpc18xx_rgu_ops; rc->rcdev.of_node = pdev->dev.of_node; - platform_set_drvdata(pdev, rc); - ret = reset_controller_register(&rc->rcdev); if (ret) { dev_err(&pdev->dev, "unable to register device\n"); diff --git a/drivers/reset/reset-meson-audio-arb.c b/drivers/reset/reset-meson-audio-arb.c index 6a3f6a6a3bbf..7e46dbc04998 100644 --- a/drivers/reset/reset-meson-audio-arb.c +++ b/drivers/reset/reset-meson-audio-arb.c @@ -5,7 +5,8 @@ #include #include #include -#include +#include +#include #include #include diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 13878ca2779d..a7af051b17fb 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -14,7 +14,6 @@ #include #include #include -#include #define BITS_PER_REG 32 @@ -129,8 +128,6 @@ static int meson_reset_probe(struct platform_device *pdev) if (!data->param) return -ENODEV; - platform_set_drvdata(pdev, data); - spin_lock_init(&data->lock); data->rcdev.owner = THIS_MODULE; diff --git a/drivers/reset/reset-microchip-sparx5.c b/drivers/reset/reset-microchip-sparx5.c index ead25942061d..636e85c388b0 100644 --- a/drivers/reset/reset-microchip-sparx5.c +++ b/drivers/reset/reset-microchip-sparx5.c @@ -7,9 +7,10 @@ * https://github.com/microchip-ung/sparx-5_reginfo */ #include -#include +#include #include #include +#include #include #include diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c index e71ab73092ab..7f3fb2d472f4 100644 --- a/drivers/reset/reset-mpfs.c +++ b/drivers/reset/reset-mpfs.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/reset/reset-npcm.c b/drivers/reset/reset-npcm.c index f2333506b0a6..f6c4f854f2be 100644 --- a/drivers/reset/reset-npcm.c +++ b/drivers/reset/reset-npcm.c @@ -394,8 +394,6 @@ static int npcm_rc_probe(struct platform_device *pdev) rc->rcdev.of_reset_n_cells = 2; rc->rcdev.of_xlate = npcm_reset_xlate; - platform_set_drvdata(pdev, rc); - ret = devm_reset_controller_register(&pdev->dev, &rc->rcdev); if (ret) { dev_err(&pdev->dev, "unable to register device\n"); diff --git a/drivers/reset/reset-qcom-aoss.c b/drivers/reset/reset-qcom-aoss.c index 9333b923dda0..f52e90e36194 100644 --- a/drivers/reset/reset-qcom-aoss.c +++ b/drivers/reset/reset-qcom-aoss.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include struct qcom_aoss_reset_map { diff --git a/drivers/reset/reset-qcom-pdc.c b/drivers/reset/reset-qcom-pdc.c index f22bb49a4ac8..a3aae3f902e6 100644 --- a/drivers/reset/reset-qcom-pdc.c +++ b/drivers/reset/reset-qcom-pdc.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index 361a68314265..7ea5adbf2097 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c index f0dd7ffc3b72..23f86ddb8668 100644 --- a/drivers/reset/reset-ti-syscon.c +++ b/drivers/reset/reset-ti-syscon.c @@ -204,8 +204,6 @@ static int ti_syscon_reset_probe(struct platform_device *pdev) data->controls = controls; data->nr_controls = nr_controls; - platform_set_drvdata(pdev, data); - return devm_reset_controller_register(dev, &data->rcdev); } diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c index 15abac9fc72c..97b3ddcdade1 100644 --- a/drivers/reset/reset-uniphier-glue.c +++ b/drivers/reset/reset-uniphier-glue.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include @@ -99,8 +99,6 @@ static int uniphier_glue_reset_probe(struct platform_device *pdev) priv->rdata.rcdev.of_node = dev->of_node; priv->rdata.active_low = true; - platform_set_drvdata(pdev, priv); - return devm_reset_controller_register(dev, &priv->rdata.rcdev); } diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index ff7580f38056..79c43c204d46 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/reset/reset-zynq.c b/drivers/reset/reset-zynq.c index 706bbbbb4ec7..688b512882ec 100644 --- a/drivers/reset/reset-zynq.c +++ b/drivers/reset/reset-zynq.c @@ -94,7 +94,6 @@ static int zynq_reset_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - platform_set_drvdata(pdev, priv); priv->slcr = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "syscon"); diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index 59dc0ff9af9e..c770ea3a1894 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -9,11 +9,11 @@ #include #include #include -#include #define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START) #define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START #define VERSAL_NR_RESETS 95 +#define VERSAL_NET_NR_RESETS 176 struct zynqmp_reset_soc_data { u32 reset_id; @@ -88,6 +88,11 @@ static const struct zynqmp_reset_soc_data versal_reset_data = { .num_resets = VERSAL_NR_RESETS, }; +static const struct zynqmp_reset_soc_data versal_net_reset_data = { + .reset_id = 0, + .num_resets = VERSAL_NET_NR_RESETS, +}; + static const struct reset_control_ops zynqmp_reset_ops = { .reset = zynqmp_reset_reset, .assert = zynqmp_reset_assert, @@ -107,8 +112,6 @@ static int zynqmp_reset_probe(struct platform_device *pdev) if (!priv->data) return -EINVAL; - platform_set_drvdata(pdev, priv); - priv->rcdev.ops = &zynqmp_reset_ops; priv->rcdev.owner = THIS_MODULE; priv->rcdev.of_node = pdev->dev.of_node; @@ -122,6 +125,7 @@ static int zynqmp_reset_probe(struct platform_device *pdev) static const struct of_device_id zynqmp_reset_dt_ids[] = { { .compatible = "xlnx,zynqmp-reset", .data = &zynqmp_reset_data, }, { .compatible = "xlnx,versal-reset", .data = &versal_reset_data, }, + { .compatible = "xlnx,versal-net-reset", .data = &versal_net_reset_data, }, { /* sentinel */ }, }; diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index 7b9c298aa491..43f601c84b4f 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1479,6 +1479,9 @@ struct qcom_smd_edge *qcom_smd_register_edge(struct device *parent, struct qcom_smd_edge *edge; int ret; + if (!qcom_smem_is_available()) + return ERR_PTR(-EPROBE_DEFER); + edge = kzalloc(sizeof(*edge), GFP_KERNEL); if (!edge) return ERR_PTR(-ENOMEM); @@ -1553,12 +1556,9 @@ EXPORT_SYMBOL(qcom_smd_unregister_edge); static int qcom_smd_probe(struct platform_device *pdev) { struct device_node *node; - void *p; - /* Wait for smem */ - p = qcom_smem_get(QCOM_SMEM_HOST_ANY, smem_items[0].alloc_tbl_id, NULL); - if (PTR_ERR(p) == -EPROBE_DEFER) - return PTR_ERR(p); + if (!qcom_smem_is_available()) + return -EPROBE_DEFER; for_each_available_child_of_node(pdev->dev.of_node, node) qcom_smd_register_edge(&pdev->dev, node); diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 4e176280113a..d21e75d69294 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -10,6 +10,7 @@ source "drivers/soc/bcm/Kconfig" source "drivers/soc/canaan/Kconfig" source "drivers/soc/fsl/Kconfig" source "drivers/soc/fujitsu/Kconfig" +source "drivers/soc/hisilicon/Kconfig" source "drivers/soc/imx/Kconfig" source "drivers/soc/ixp4xx/Kconfig" source "drivers/soc/litex/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 708eaad8f590..0706a27d13be 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_MACH_DOVE) += dove/ obj-y += fsl/ obj-y += fujitsu/ obj-$(CONFIG_ARCH_GEMINI) += gemini/ +obj-y += hisilicon/ obj-y += imx/ obj-y += ixp4xx/ obj-$(CONFIG_SOC_XWAY) += lantiq/ diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c index 383b0cfc584e..b6e06c4d2117 100644 --- a/drivers/soc/amlogic/meson-canvas.c +++ b/drivers/soc/amlogic/meson-canvas.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig new file mode 100644 index 000000000000..0ab688af308f --- /dev/null +++ b/drivers/soc/hisilicon/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only + +menu "Hisilicon SoC drivers" + depends on ARCH_HISI || COMPILE_TEST + +config KUNPENG_HCCS + tristate "HCCS driver on Kunpeng SoC" + depends on ACPI + depends on MAILBOX + depends on ARM64 || COMPILE_TEST + help + The Huawei Cache Coherence System (HCCS) is a multi-chip + interconnection bus protocol. + The performance of application may be affected if some HCCS + ports are not in full lane status, have a large number of CRC + errors and so on. + + Say M here if you want to include support for querying the + health status and port information of HCCS on Kunpeng SoC. + +endmenu diff --git a/drivers/soc/hisilicon/Makefile b/drivers/soc/hisilicon/Makefile new file mode 100644 index 000000000000..226e747e70d6 --- /dev/null +++ b/drivers/soc/hisilicon/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_KUNPENG_HCCS) += kunpeng_hccs.o diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c new file mode 100644 index 000000000000..f3810d9d1caa --- /dev/null +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -0,0 +1,1276 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * The Huawei Cache Coherence System (HCCS) is a multi-chip interconnection + * bus protocol. + * + * Copyright (c) 2023 Hisilicon Limited. + * Author: Huisong Li + * + * HCCS driver for Kunpeng SoC provides the following features: + * - Retrieve the following information about each port: + * - port type + * - lane mode + * - enable + * - current lane mode + * - link finite state machine + * - lane mask + * - CRC error count + * + * - Retrieve the following information about all the ports on the chip or + * the die: + * - if all enabled ports are in linked + * - if all linked ports are in full lane + * - CRC error count sum + */ +#include +#include +#include +#include + +#include + +#include "kunpeng_hccs.h" + +/* PCC defines */ +#define HCCS_PCC_SIGNATURE_MASK 0x50434300 +#define HCCS_PCC_STATUS_CMD_COMPLETE BIT(0) + +/* + * Arbitrary retries in case the remote processor is slow to respond + * to PCC commands + */ +#define HCCS_PCC_CMD_WAIT_RETRIES_NUM 500ULL +#define HCCS_POLL_STATUS_TIME_INTERVAL_US 3 + +static struct hccs_port_info *kobj_to_port_info(struct kobject *k) +{ + return container_of(k, struct hccs_port_info, kobj); +} + +static struct hccs_die_info *kobj_to_die_info(struct kobject *k) +{ + return container_of(k, struct hccs_die_info, kobj); +} + +static struct hccs_chip_info *kobj_to_chip_info(struct kobject *k) +{ + return container_of(k, struct hccs_chip_info, kobj); +} + +struct hccs_register_ctx { + struct device *dev; + u8 chan_id; + int err; +}; + +static acpi_status hccs_get_register_cb(struct acpi_resource *ares, + void *context) +{ + struct acpi_resource_generic_register *reg; + struct hccs_register_ctx *ctx = context; + + if (ares->type != ACPI_RESOURCE_TYPE_GENERIC_REGISTER) + return AE_OK; + + reg = &ares->data.generic_reg; + if (reg->space_id != ACPI_ADR_SPACE_PLATFORM_COMM) { + dev_err(ctx->dev, "Bad register resource.\n"); + ctx->err = -EINVAL; + return AE_ERROR; + } + ctx->chan_id = reg->access_size; + + return AE_OK; +} + +static int hccs_get_pcc_chan_id(struct hccs_dev *hdev) +{ + acpi_handle handle = ACPI_HANDLE(hdev->dev); + struct hccs_register_ctx ctx = {0}; + acpi_status status; + + if (!acpi_has_method(handle, METHOD_NAME__CRS)) + return -ENODEV; + + ctx.dev = hdev->dev; + status = acpi_walk_resources(handle, METHOD_NAME__CRS, + hccs_get_register_cb, &ctx); + if (ACPI_FAILURE(status)) + return ctx.err; + hdev->chan_id = ctx.chan_id; + + return 0; +} + +static void hccs_chan_tx_done(struct mbox_client *cl, void *msg, int ret) +{ + if (ret < 0) + pr_debug("TX did not complete: CMD sent:0x%x, ret:%d\n", + *(u8 *)msg, ret); + else + pr_debug("TX completed. CMD sent:0x%x, ret:%d\n", + *(u8 *)msg, ret); +} + +static void hccs_unregister_pcc_channel(struct hccs_dev *hdev) +{ + struct hccs_mbox_client_info *cl_info = &hdev->cl_info; + + if (cl_info->pcc_comm_addr) + iounmap(cl_info->pcc_comm_addr); + pcc_mbox_free_channel(hdev->cl_info.pcc_chan); +} + +static int hccs_register_pcc_channel(struct hccs_dev *hdev) +{ + struct hccs_mbox_client_info *cl_info = &hdev->cl_info; + struct mbox_client *cl = &cl_info->client; + struct pcc_mbox_chan *pcc_chan; + struct device *dev = hdev->dev; + int rc; + + cl->dev = dev; + cl->tx_block = false; + cl->knows_txdone = true; + cl->tx_done = hccs_chan_tx_done; + pcc_chan = pcc_mbox_request_channel(cl, hdev->chan_id); + if (IS_ERR(pcc_chan)) { + dev_err(dev, "PPC channel request failed.\n"); + rc = -ENODEV; + goto out; + } + cl_info->pcc_chan = pcc_chan; + cl_info->mbox_chan = pcc_chan->mchan; + + /* + * pcc_chan->latency is just a nominal value. In reality the remote + * processor could be much slower to reply. So add an arbitrary amount + * of wait on top of nominal. + */ + cl_info->deadline_us = + HCCS_PCC_CMD_WAIT_RETRIES_NUM * pcc_chan->latency; + if (cl_info->mbox_chan->mbox->txdone_irq) { + dev_err(dev, "PCC IRQ in PCCT is enabled.\n"); + rc = -EINVAL; + goto err_mbx_channel_free; + } + + if (pcc_chan->shmem_base_addr) { + cl_info->pcc_comm_addr = ioremap(pcc_chan->shmem_base_addr, + pcc_chan->shmem_size); + if (!cl_info->pcc_comm_addr) { + dev_err(dev, "Failed to ioremap PCC communication region for channel-%d.\n", + hdev->chan_id); + rc = -ENOMEM; + goto err_mbx_channel_free; + } + } + + return 0; + +err_mbx_channel_free: + pcc_mbox_free_channel(cl_info->pcc_chan); +out: + return rc; +} + +static int hccs_check_chan_cmd_complete(struct hccs_dev *hdev) +{ + struct hccs_mbox_client_info *cl_info = &hdev->cl_info; + struct acpi_pcct_shared_memory __iomem *comm_base = + cl_info->pcc_comm_addr; + u16 status; + int ret; + + /* + * Poll PCC status register every 3us(delay_us) for maximum of + * deadline_us(timeout_us) until PCC command complete bit is set(cond) + */ + ret = readw_poll_timeout(&comm_base->status, status, + status & HCCS_PCC_STATUS_CMD_COMPLETE, + HCCS_POLL_STATUS_TIME_INTERVAL_US, + cl_info->deadline_us); + if (unlikely(ret)) + dev_err(hdev->dev, "poll PCC status failed, ret = %d.\n", ret); + + return ret; +} + +static int hccs_pcc_cmd_send(struct hccs_dev *hdev, u8 cmd, + struct hccs_desc *desc) +{ + struct hccs_mbox_client_info *cl_info = &hdev->cl_info; + void __iomem *comm_space = cl_info->pcc_comm_addr + + sizeof(struct acpi_pcct_shared_memory); + struct hccs_fw_inner_head *fw_inner_head; + struct acpi_pcct_shared_memory tmp = {0}; + u16 comm_space_size; + int ret; + + /* Write signature for this subspace */ + tmp.signature = HCCS_PCC_SIGNATURE_MASK | hdev->chan_id; + /* Write to the shared command region */ + tmp.command = cmd; + /* Clear cmd complete bit */ + tmp.status = 0; + memcpy_toio(cl_info->pcc_comm_addr, (void *)&tmp, + sizeof(struct acpi_pcct_shared_memory)); + + /* Copy the message to the PCC comm space */ + comm_space_size = HCCS_PCC_SHARE_MEM_BYTES - + sizeof(struct acpi_pcct_shared_memory); + memcpy_toio(comm_space, (void *)desc, comm_space_size); + + /* Ring doorbell */ + ret = mbox_send_message(cl_info->mbox_chan, &cmd); + if (ret < 0) { + dev_err(hdev->dev, "Send PCC mbox message failed, ret = %d.\n", + ret); + goto end; + } + + /* Wait for completion */ + ret = hccs_check_chan_cmd_complete(hdev); + if (ret) + goto end; + + /* Copy response data */ + memcpy_fromio((void *)desc, comm_space, comm_space_size); + fw_inner_head = &desc->rsp.fw_inner_head; + if (fw_inner_head->retStatus) { + dev_err(hdev->dev, "Execute PCC command failed, error code = %u.\n", + fw_inner_head->retStatus); + ret = -EIO; + } + +end: + mbox_client_txdone(cl_info->mbox_chan, ret); + return ret; +} + +static void hccs_init_req_desc(struct hccs_desc *desc) +{ + struct hccs_req_desc *req = &desc->req; + + memset(desc, 0, sizeof(*desc)); + req->req_head.module_code = HCCS_SERDES_MODULE_CODE; +} + +static int hccs_get_dev_caps(struct hccs_dev *hdev) +{ + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DEV_CAP, &desc); + if (ret) { + dev_err(hdev->dev, "Get device capabilities failed, ret = %d.\n", + ret); + return ret; + } + memcpy(&hdev->caps, desc.rsp.data, sizeof(hdev->caps)); + + return 0; +} + +static int hccs_query_chip_num_on_platform(struct hccs_dev *hdev) +{ + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_CHIP_NUM, &desc); + if (ret) { + dev_err(hdev->dev, "query system chip number failed, ret = %d.\n", + ret); + return ret; + } + + hdev->chip_num = *((u8 *)&desc.rsp.data); + if (!hdev->chip_num) { + dev_err(hdev->dev, "chip num obtained from firmware is zero.\n"); + return -EINVAL; + } + + return 0; +} + +static int hccs_get_chip_info(struct hccs_dev *hdev, + struct hccs_chip_info *chip) +{ + struct hccs_die_num_req_param *req_param; + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + req_param = (struct hccs_die_num_req_param *)desc.req.data; + req_param->chip_id = chip->chip_id; + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_NUM, &desc); + if (ret) + return ret; + + chip->die_num = *((u8 *)&desc.rsp.data); + + return 0; +} + +static int hccs_query_chip_info_on_platform(struct hccs_dev *hdev) +{ + struct hccs_chip_info *chip; + int ret; + u8 idx; + + ret = hccs_query_chip_num_on_platform(hdev); + if (ret) { + dev_err(hdev->dev, "query chip number on platform failed, ret = %d.\n", + ret); + return ret; + } + + hdev->chips = devm_kzalloc(hdev->dev, + hdev->chip_num * sizeof(struct hccs_chip_info), + GFP_KERNEL); + if (!hdev->chips) { + dev_err(hdev->dev, "allocate all chips memory failed.\n"); + return -ENOMEM; + } + + for (idx = 0; idx < hdev->chip_num; idx++) { + chip = &hdev->chips[idx]; + chip->chip_id = idx; + ret = hccs_get_chip_info(hdev, chip); + if (ret) { + dev_err(hdev->dev, "get chip%u info failed, ret = %d.\n", + idx, ret); + return ret; + } + chip->hdev = hdev; + } + + return 0; +} + +static int hccs_query_die_info_on_chip(struct hccs_dev *hdev, u8 chip_id, + u8 die_idx, struct hccs_die_info *die) +{ + struct hccs_die_info_req_param *req_param; + struct hccs_die_info_rsp_data *rsp_data; + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + req_param = (struct hccs_die_info_req_param *)desc.req.data; + req_param->chip_id = chip_id; + req_param->die_idx = die_idx; + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_INFO, &desc); + if (ret) + return ret; + + rsp_data = (struct hccs_die_info_rsp_data *)desc.rsp.data; + die->die_id = rsp_data->die_id; + die->port_num = rsp_data->port_num; + die->min_port_id = rsp_data->min_port_id; + die->max_port_id = rsp_data->max_port_id; + if (die->min_port_id > die->max_port_id) { + dev_err(hdev->dev, "min port id(%u) > max port id(%u) on die_idx(%u).\n", + die->min_port_id, die->max_port_id, die_idx); + return -EINVAL; + } + if (die->max_port_id > HCCS_DIE_MAX_PORT_ID) { + dev_err(hdev->dev, "max port id(%u) on die_idx(%u) is too big.\n", + die->max_port_id, die_idx); + return -EINVAL; + } + + return 0; +} + +static int hccs_query_all_die_info_on_platform(struct hccs_dev *hdev) +{ + struct device *dev = hdev->dev; + struct hccs_chip_info *chip; + struct hccs_die_info *die; + u8 i, j; + int ret; + + for (i = 0; i < hdev->chip_num; i++) { + chip = &hdev->chips[i]; + if (!chip->die_num) + continue; + + chip->dies = devm_kzalloc(hdev->dev, + chip->die_num * sizeof(struct hccs_die_info), + GFP_KERNEL); + if (!chip->dies) { + dev_err(dev, "allocate all dies memory on chip%u failed.\n", + i); + return -ENOMEM; + } + + for (j = 0; j < chip->die_num; j++) { + die = &chip->dies[j]; + ret = hccs_query_die_info_on_chip(hdev, i, j, die); + if (ret) { + dev_err(dev, "get die idx (%u) info on chip%u failed, ret = %d.\n", + j, i, ret); + return ret; + } + die->chip = chip; + } + } + + return 0; +} + +static int hccs_get_bd_info(struct hccs_dev *hdev, u8 opcode, + struct hccs_desc *desc, + void *buf, size_t buf_len, + struct hccs_rsp_head *rsp_head) +{ + struct hccs_rsp_head *head; + struct hccs_rsp_desc *rsp; + int ret; + + ret = hccs_pcc_cmd_send(hdev, opcode, desc); + if (ret) + return ret; + + rsp = &desc->rsp; + head = &rsp->rsp_head; + if (head->data_len > buf_len) { + dev_err(hdev->dev, + "buffer overflow (buf_len = %zu, data_len = %u)!\n", + buf_len, head->data_len); + return -ENOMEM; + } + + memcpy(buf, rsp->data, head->data_len); + *rsp_head = *head; + + return 0; +} + +static int hccs_get_all_port_attr(struct hccs_dev *hdev, + struct hccs_die_info *die, + struct hccs_port_attr *attrs, u16 size) +{ + struct hccs_die_comm_req_param *req_param; + struct hccs_req_head *req_head; + struct hccs_rsp_head rsp_head; + struct hccs_desc desc; + size_t left_buf_len; + u32 data_len = 0; + u8 start_id; + u8 *buf; + int ret; + + buf = (u8 *)attrs; + left_buf_len = sizeof(struct hccs_port_attr) * size; + start_id = die->min_port_id; + while (start_id <= die->max_port_id) { + hccs_init_req_desc(&desc); + req_head = &desc.req.req_head; + req_head->start_id = start_id; + req_param = (struct hccs_die_comm_req_param *)desc.req.data; + req_param->chip_id = die->chip->chip_id; + req_param->die_id = die->die_id; + + ret = hccs_get_bd_info(hdev, HCCS_GET_DIE_PORT_INFO, &desc, + buf + data_len, left_buf_len, &rsp_head); + if (ret) { + dev_err(hdev->dev, + "get the information of port%u on die%u failed, ret = %d.\n", + start_id, die->die_id, ret); + return ret; + } + + data_len += rsp_head.data_len; + left_buf_len -= rsp_head.data_len; + if (unlikely(rsp_head.next_id <= start_id)) { + dev_err(hdev->dev, + "next port id (%u) is not greater than last start id (%u) on die%u.\n", + rsp_head.next_id, start_id, die->die_id); + return -EINVAL; + } + start_id = rsp_head.next_id; + } + + return 0; +} + +static int hccs_get_all_port_info_on_die(struct hccs_dev *hdev, + struct hccs_die_info *die) +{ + struct hccs_port_attr *attrs; + struct hccs_port_info *port; + int ret; + u8 i; + + attrs = kcalloc(die->port_num, sizeof(struct hccs_port_attr), + GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + ret = hccs_get_all_port_attr(hdev, die, attrs, die->port_num); + if (ret) + goto out; + + for (i = 0; i < die->port_num; i++) { + port = &die->ports[i]; + port->port_id = attrs[i].port_id; + port->port_type = attrs[i].port_type; + port->lane_mode = attrs[i].lane_mode; + port->enable = attrs[i].enable; + port->die = die; + } + +out: + kfree(attrs); + return ret; +} + +static int hccs_query_all_port_info_on_platform(struct hccs_dev *hdev) +{ + + struct device *dev = hdev->dev; + struct hccs_chip_info *chip; + struct hccs_die_info *die; + u8 i, j; + int ret; + + for (i = 0; i < hdev->chip_num; i++) { + chip = &hdev->chips[i]; + for (j = 0; j < chip->die_num; j++) { + die = &chip->dies[j]; + if (!die->port_num) + continue; + + die->ports = devm_kzalloc(dev, + die->port_num * sizeof(struct hccs_port_info), + GFP_KERNEL); + if (!die->ports) { + dev_err(dev, "allocate ports memory on chip%u/die%u failed.\n", + i, die->die_id); + return -ENOMEM; + } + + ret = hccs_get_all_port_info_on_die(hdev, die); + if (ret) { + dev_err(dev, "get all port info on chip%u/die%u failed, ret = %d.\n", + i, die->die_id, ret); + return ret; + } + } + } + + return 0; +} + +static int hccs_get_hw_info(struct hccs_dev *hdev) +{ + int ret; + + ret = hccs_query_chip_info_on_platform(hdev); + if (ret) { + dev_err(hdev->dev, "query chip info on platform failed, ret = %d.\n", + ret); + return ret; + } + + ret = hccs_query_all_die_info_on_platform(hdev); + if (ret) { + dev_err(hdev->dev, "query all die info on platform failed, ret = %d.\n", + ret); + return ret; + } + + ret = hccs_query_all_port_info_on_platform(hdev); + if (ret) { + dev_err(hdev->dev, "query all port info on platform failed, ret = %d.\n", + ret); + return ret; + } + + return 0; +} + +static int hccs_query_port_link_status(struct hccs_dev *hdev, + const struct hccs_port_info *port, + struct hccs_link_status *link_status) +{ + const struct hccs_die_info *die = port->die; + const struct hccs_chip_info *chip = die->chip; + struct hccs_port_comm_req_param *req_param; + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + req_param = (struct hccs_port_comm_req_param *)desc.req.data; + req_param->chip_id = chip->chip_id; + req_param->die_id = die->die_id; + req_param->port_id = port->port_id; + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_PORT_LINK_STATUS, &desc); + if (ret) { + dev_err(hdev->dev, + "get port link status info failed, ret = %d.\n", ret); + return ret; + } + + *link_status = *((struct hccs_link_status *)desc.rsp.data); + + return 0; +} + +static int hccs_query_port_crc_err_cnt(struct hccs_dev *hdev, + const struct hccs_port_info *port, + u64 *crc_err_cnt) +{ + const struct hccs_die_info *die = port->die; + const struct hccs_chip_info *chip = die->chip; + struct hccs_port_comm_req_param *req_param; + struct hccs_desc desc; + int ret; + + hccs_init_req_desc(&desc); + req_param = (struct hccs_port_comm_req_param *)desc.req.data; + req_param->chip_id = chip->chip_id; + req_param->die_id = die->die_id; + req_param->port_id = port->port_id; + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_PORT_CRC_ERR_CNT, &desc); + if (ret) { + dev_err(hdev->dev, + "get port crc error count failed, ret = %d.\n", ret); + return ret; + } + + memcpy(crc_err_cnt, &desc.rsp.data, sizeof(u64)); + + return 0; +} + +static int hccs_get_die_all_link_status(struct hccs_dev *hdev, + const struct hccs_die_info *die, + u8 *all_linked) +{ + struct hccs_die_comm_req_param *req_param; + struct hccs_desc desc; + int ret; + + if (die->port_num == 0) { + *all_linked = 1; + return 0; + } + + hccs_init_req_desc(&desc); + req_param = (struct hccs_die_comm_req_param *)desc.req.data; + req_param->chip_id = die->chip->chip_id; + req_param->die_id = die->die_id; + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_PORTS_LINK_STA, &desc); + if (ret) { + dev_err(hdev->dev, + "get link status of all ports failed on die%u, ret = %d.\n", + die->die_id, ret); + return ret; + } + + *all_linked = *((u8 *)&desc.rsp.data); + + return 0; +} + +static int hccs_get_die_all_port_lane_status(struct hccs_dev *hdev, + const struct hccs_die_info *die, + u8 *full_lane) +{ + struct hccs_die_comm_req_param *req_param; + struct hccs_desc desc; + int ret; + + if (die->port_num == 0) { + *full_lane = 1; + return 0; + } + + hccs_init_req_desc(&desc); + req_param = (struct hccs_die_comm_req_param *)desc.req.data; + req_param->chip_id = die->chip->chip_id; + req_param->die_id = die->die_id; + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_PORTS_LANE_STA, &desc); + if (ret) { + dev_err(hdev->dev, "get lane status of all ports failed on die%u, ret = %d.\n", + die->die_id, ret); + return ret; + } + + *full_lane = *((u8 *)&desc.rsp.data); + + return 0; +} + +static int hccs_get_die_total_crc_err_cnt(struct hccs_dev *hdev, + const struct hccs_die_info *die, + u64 *total_crc_err_cnt) +{ + struct hccs_die_comm_req_param *req_param; + struct hccs_desc desc; + int ret; + + if (die->port_num == 0) { + *total_crc_err_cnt = 0; + return 0; + } + + hccs_init_req_desc(&desc); + req_param = (struct hccs_die_comm_req_param *)desc.req.data; + req_param->chip_id = die->chip->chip_id; + req_param->die_id = die->die_id; + ret = hccs_pcc_cmd_send(hdev, HCCS_GET_DIE_PORTS_CRC_ERR_CNT, &desc); + if (ret) { + dev_err(hdev->dev, "get crc error count sum failed on die%u, ret = %d.\n", + die->die_id, ret); + return ret; + } + + memcpy(total_crc_err_cnt, &desc.rsp.data, sizeof(u64)); + + return 0; +} + +static ssize_t hccs_show(struct kobject *k, struct attribute *attr, char *buf) +{ + struct kobj_attribute *kobj_attr; + + kobj_attr = container_of(attr, struct kobj_attribute, attr); + + return kobj_attr->show(k, kobj_attr, buf); +} + +static const struct sysfs_ops hccs_comm_ops = { + .show = hccs_show, +}; + +static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + const struct hccs_port_info *port = kobj_to_port_info(kobj); + + return sysfs_emit(buf, "HCCS-v%u\n", port->port_type); +} +static struct kobj_attribute hccs_type_attr = __ATTR_RO(type); + +static ssize_t lane_mode_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + const struct hccs_port_info *port = kobj_to_port_info(kobj); + + return sysfs_emit(buf, "x%u\n", port->lane_mode); +} +static struct kobj_attribute lane_mode_attr = __ATTR_RO(lane_mode); + +static ssize_t enable_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + const struct hccs_port_info *port = kobj_to_port_info(kobj); + + return sysfs_emit(buf, "%u\n", port->enable); +} +static struct kobj_attribute port_enable_attr = __ATTR_RO(enable); + +static ssize_t cur_lane_num_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + const struct hccs_port_info *port = kobj_to_port_info(kobj); + struct hccs_dev *hdev = port->die->chip->hdev; + struct hccs_link_status link_status = {0}; + int ret; + + mutex_lock(&hdev->lock); + ret = hccs_query_port_link_status(hdev, port, &link_status); + mutex_unlock(&hdev->lock); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", link_status.lane_num); +} +static struct kobj_attribute cur_lane_num_attr = __ATTR_RO(cur_lane_num); + +static ssize_t link_fsm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + const struct hccs_port_info *port = kobj_to_port_info(kobj); + struct hccs_dev *hdev = port->die->chip->hdev; + struct hccs_link_status link_status = {0}; + const struct { + u8 link_fsm; + char *str; + } link_fsm_map[] = { + {HCCS_PORT_RESET, "reset"}, + {HCCS_PORT_SETUP, "setup"}, + {HCCS_PORT_CONFIG, "config"}, + {HCCS_PORT_READY, "link-up"}, + }; + const char *link_fsm_str = "unknown"; + size_t i; + int ret; + + mutex_lock(&hdev->lock); + ret = hccs_query_port_link_status(hdev, port, &link_status); + mutex_unlock(&hdev->lock); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(link_fsm_map); i++) { + if (link_fsm_map[i].link_fsm == link_status.link_fsm) { + link_fsm_str = link_fsm_map[i].str; + break; + } + } + + return sysfs_emit(buf, "%s\n", link_fsm_str); +} +static struct kobj_attribute link_fsm_attr = __ATTR_RO(link_fsm); + +static ssize_t lane_mask_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + const struct hccs_port_info *port = kobj_to_port_info(kobj); + struct hccs_dev *hdev = port->die->chip->hdev; + struct hccs_link_status link_status = {0}; + int ret; + + mutex_lock(&hdev->lock); + ret = hccs_query_port_link_status(hdev, port, &link_status); + mutex_unlock(&hdev->lock); + if (ret) + return ret; + + return sysfs_emit(buf, "0x%x\n", link_status.lane_mask); +} +static struct kobj_attribute lane_mask_attr = __ATTR_RO(lane_mask); + +static ssize_t crc_err_cnt_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + const struct hccs_port_info *port = kobj_to_port_info(kobj); + struct hccs_dev *hdev = port->die->chip->hdev; + u64 crc_err_cnt; + int ret; + + mutex_lock(&hdev->lock); + ret = hccs_query_port_crc_err_cnt(hdev, port, &crc_err_cnt); + mutex_unlock(&hdev->lock); + if (ret) + return ret; + + return sysfs_emit(buf, "%llu\n", crc_err_cnt); +} +static struct kobj_attribute crc_err_cnt_attr = __ATTR_RO(crc_err_cnt); + +static struct attribute *hccs_port_default_attrs[] = { + &hccs_type_attr.attr, + &lane_mode_attr.attr, + &port_enable_attr.attr, + &cur_lane_num_attr.attr, + &link_fsm_attr.attr, + &lane_mask_attr.attr, + &crc_err_cnt_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(hccs_port_default); + +static const struct kobj_type hccs_port_type = { + .sysfs_ops = &hccs_comm_ops, + .default_groups = hccs_port_default_groups, +}; + +static ssize_t all_linked_on_die_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + const struct hccs_die_info *die = kobj_to_die_info(kobj); + struct hccs_dev *hdev = die->chip->hdev; + u8 all_linked; + int ret; + + mutex_lock(&hdev->lock); + ret = hccs_get_die_all_link_status(hdev, die, &all_linked); + mutex_unlock(&hdev->lock); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", all_linked); +} +static struct kobj_attribute all_linked_on_die_attr = + __ATTR(all_linked, 0444, all_linked_on_die_show, NULL); + +static ssize_t linked_full_lane_on_die_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + const struct hccs_die_info *die = kobj_to_die_info(kobj); + struct hccs_dev *hdev = die->chip->hdev; + u8 full_lane; + int ret; + + mutex_lock(&hdev->lock); + ret = hccs_get_die_all_port_lane_status(hdev, die, &full_lane); + mutex_unlock(&hdev->lock); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", full_lane); +} +static struct kobj_attribute linked_full_lane_on_die_attr = + __ATTR(linked_full_lane, 0444, linked_full_lane_on_die_show, NULL); + +static ssize_t crc_err_cnt_sum_on_die_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + const struct hccs_die_info *die = kobj_to_die_info(kobj); + struct hccs_dev *hdev = die->chip->hdev; + u64 total_crc_err_cnt; + int ret; + + mutex_lock(&hdev->lock); + ret = hccs_get_die_total_crc_err_cnt(hdev, die, &total_crc_err_cnt); + mutex_unlock(&hdev->lock); + if (ret) + return ret; + + return sysfs_emit(buf, "%llu\n", total_crc_err_cnt); +} +static struct kobj_attribute crc_err_cnt_sum_on_die_attr = + __ATTR(crc_err_cnt, 0444, crc_err_cnt_sum_on_die_show, NULL); + +static struct attribute *hccs_die_default_attrs[] = { + &all_linked_on_die_attr.attr, + &linked_full_lane_on_die_attr.attr, + &crc_err_cnt_sum_on_die_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(hccs_die_default); + +static const struct kobj_type hccs_die_type = { + .sysfs_ops = &hccs_comm_ops, + .default_groups = hccs_die_default_groups, +}; + +static ssize_t all_linked_on_chip_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + const struct hccs_chip_info *chip = kobj_to_chip_info(kobj); + struct hccs_dev *hdev = chip->hdev; + const struct hccs_die_info *die; + u8 all_linked = 1; + u8 i, tmp; + int ret; + + mutex_lock(&hdev->lock); + for (i = 0; i < chip->die_num; i++) { + die = &chip->dies[i]; + ret = hccs_get_die_all_link_status(hdev, die, &tmp); + if (ret) { + mutex_unlock(&hdev->lock); + return ret; + } + if (tmp != all_linked) { + all_linked = 0; + break; + } + } + mutex_unlock(&hdev->lock); + + return sysfs_emit(buf, "%u\n", all_linked); +} +static struct kobj_attribute all_linked_on_chip_attr = + __ATTR(all_linked, 0444, all_linked_on_chip_show, NULL); + +static ssize_t linked_full_lane_on_chip_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + const struct hccs_chip_info *chip = kobj_to_chip_info(kobj); + struct hccs_dev *hdev = chip->hdev; + const struct hccs_die_info *die; + u8 full_lane = 1; + u8 i, tmp; + int ret; + + mutex_lock(&hdev->lock); + for (i = 0; i < chip->die_num; i++) { + die = &chip->dies[i]; + ret = hccs_get_die_all_port_lane_status(hdev, die, &tmp); + if (ret) { + mutex_unlock(&hdev->lock); + return ret; + } + if (tmp != full_lane) { + full_lane = 0; + break; + } + } + mutex_unlock(&hdev->lock); + + return sysfs_emit(buf, "%u\n", full_lane); +} +static struct kobj_attribute linked_full_lane_on_chip_attr = + __ATTR(linked_full_lane, 0444, linked_full_lane_on_chip_show, NULL); + +static ssize_t crc_err_cnt_sum_on_chip_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + const struct hccs_chip_info *chip = kobj_to_chip_info(kobj); + u64 crc_err_cnt, total_crc_err_cnt = 0; + struct hccs_dev *hdev = chip->hdev; + const struct hccs_die_info *die; + int ret; + u16 i; + + mutex_lock(&hdev->lock); + for (i = 0; i < chip->die_num; i++) { + die = &chip->dies[i]; + ret = hccs_get_die_total_crc_err_cnt(hdev, die, &crc_err_cnt); + if (ret) { + mutex_unlock(&hdev->lock); + return ret; + } + + total_crc_err_cnt += crc_err_cnt; + } + mutex_unlock(&hdev->lock); + + return sysfs_emit(buf, "%llu\n", total_crc_err_cnt); +} +static struct kobj_attribute crc_err_cnt_sum_on_chip_attr = + __ATTR(crc_err_cnt, 0444, crc_err_cnt_sum_on_chip_show, NULL); + +static struct attribute *hccs_chip_default_attrs[] = { + &all_linked_on_chip_attr.attr, + &linked_full_lane_on_chip_attr.attr, + &crc_err_cnt_sum_on_chip_attr.attr, + NULL, +}; +ATTRIBUTE_GROUPS(hccs_chip_default); + +static const struct kobj_type hccs_chip_type = { + .sysfs_ops = &hccs_comm_ops, + .default_groups = hccs_chip_default_groups, +}; + +static void hccs_remove_die_dir(struct hccs_die_info *die) +{ + struct hccs_port_info *port; + u8 i; + + for (i = 0; i < die->port_num; i++) { + port = &die->ports[i]; + if (port->dir_created) + kobject_put(&port->kobj); + } + + kobject_put(&die->kobj); +} + +static void hccs_remove_chip_dir(struct hccs_chip_info *chip) +{ + struct hccs_die_info *die; + u8 i; + + for (i = 0; i < chip->die_num; i++) { + die = &chip->dies[i]; + if (die->dir_created) + hccs_remove_die_dir(die); + } + + kobject_put(&chip->kobj); +} + +static void hccs_remove_topo_dirs(struct hccs_dev *hdev) +{ + u8 i; + + for (i = 0; i < hdev->chip_num; i++) + hccs_remove_chip_dir(&hdev->chips[i]); +} + +static int hccs_create_hccs_dir(struct hccs_dev *hdev, + struct hccs_die_info *die, + struct hccs_port_info *port) +{ + int ret; + + ret = kobject_init_and_add(&port->kobj, &hccs_port_type, + &die->kobj, "hccs%d", port->port_id); + if (ret) { + kobject_put(&port->kobj); + return ret; + } + + return 0; +} + +static int hccs_create_die_dir(struct hccs_dev *hdev, + struct hccs_chip_info *chip, + struct hccs_die_info *die) +{ + struct hccs_port_info *port; + int ret; + u16 i; + + ret = kobject_init_and_add(&die->kobj, &hccs_die_type, + &chip->kobj, "die%d", die->die_id); + if (ret) { + kobject_put(&die->kobj); + return ret; + } + + for (i = 0; i < die->port_num; i++) { + port = &die->ports[i]; + ret = hccs_create_hccs_dir(hdev, die, port); + if (ret) { + dev_err(hdev->dev, "create hccs%d dir failed.\n", + port->port_id); + goto err; + } + port->dir_created = true; + } + + return 0; +err: + hccs_remove_die_dir(die); + + return ret; +} + +static int hccs_create_chip_dir(struct hccs_dev *hdev, + struct hccs_chip_info *chip) +{ + struct hccs_die_info *die; + int ret; + u16 id; + + ret = kobject_init_and_add(&chip->kobj, &hccs_chip_type, + &hdev->dev->kobj, "chip%d", chip->chip_id); + if (ret) { + kobject_put(&chip->kobj); + return ret; + } + + for (id = 0; id < chip->die_num; id++) { + die = &chip->dies[id]; + ret = hccs_create_die_dir(hdev, chip, die); + if (ret) + goto err; + die->dir_created = true; + } + + return 0; +err: + hccs_remove_chip_dir(chip); + + return ret; +} + +static int hccs_create_topo_dirs(struct hccs_dev *hdev) +{ + struct hccs_chip_info *chip; + u8 id, k; + int ret; + + for (id = 0; id < hdev->chip_num; id++) { + chip = &hdev->chips[id]; + ret = hccs_create_chip_dir(hdev, chip); + if (ret) { + dev_err(hdev->dev, "init chip%d dir failed!\n", id); + goto err; + } + } + + return 0; +err: + for (k = 0; k < id; k++) + hccs_remove_chip_dir(&hdev->chips[k]); + + return ret; +} + +static int hccs_probe(struct platform_device *pdev) +{ + struct acpi_device *acpi_dev; + struct hccs_dev *hdev; + int rc; + + if (acpi_disabled) { + dev_err(&pdev->dev, "acpi is disabled.\n"); + return -ENODEV; + } + acpi_dev = ACPI_COMPANION(&pdev->dev); + if (!acpi_dev) + return -ENODEV; + + hdev = devm_kzalloc(&pdev->dev, sizeof(*hdev), GFP_KERNEL); + if (!hdev) + return -ENOMEM; + hdev->acpi_dev = acpi_dev; + hdev->dev = &pdev->dev; + platform_set_drvdata(pdev, hdev); + + mutex_init(&hdev->lock); + rc = hccs_get_pcc_chan_id(hdev); + if (rc) + return rc; + rc = hccs_register_pcc_channel(hdev); + if (rc) + return rc; + + rc = hccs_get_dev_caps(hdev); + if (rc) + goto unregister_pcc_chan; + + rc = hccs_get_hw_info(hdev); + if (rc) + goto unregister_pcc_chan; + + rc = hccs_create_topo_dirs(hdev); + if (rc) + goto unregister_pcc_chan; + + return 0; + +unregister_pcc_chan: + hccs_unregister_pcc_channel(hdev); + + return rc; +} + +static int hccs_remove(struct platform_device *pdev) +{ + struct hccs_dev *hdev = platform_get_drvdata(pdev); + + hccs_remove_topo_dirs(hdev); + hccs_unregister_pcc_channel(hdev); + + return 0; +} + +static const struct acpi_device_id hccs_acpi_match[] = { + { "HISI04B1"}, + { ""}, +}; +MODULE_DEVICE_TABLE(acpi, hccs_acpi_match); + +static struct platform_driver hccs_driver = { + .probe = hccs_probe, + .remove = hccs_remove, + .driver = { + .name = "kunpeng_hccs", + .acpi_match_table = hccs_acpi_match, + }, +}; + +module_platform_driver(hccs_driver); + +MODULE_DESCRIPTION("Kunpeng SoC HCCS driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Huisong Li "); diff --git a/drivers/soc/hisilicon/kunpeng_hccs.h b/drivers/soc/hisilicon/kunpeng_hccs.h new file mode 100644 index 000000000000..6012d2776028 --- /dev/null +++ b/drivers/soc/hisilicon/kunpeng_hccs.h @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2023 Hisilicon Limited. */ + +#ifndef __KUNPENG_HCCS_H__ +#define __KUNPENG_HCCS_H__ + +/* + * |--------------- Chip0 ---------------|---------------- ChipN -------------| + * |--------Die0-------|--------DieN-------|--------Die0-------|-------DieN-------| + * | P0 | P1 | P2 | P3 | P0 | P1 | P2 | P3 | P0 | P1 | P2 | P3 |P0 | P1 | P2 | P3 | + */ + +/* + * This value cannot be 255, otherwise the loop of the multi-BD communication + * case cannot end. + */ +#define HCCS_DIE_MAX_PORT_ID 254 + +struct hccs_port_info { + u8 port_id; + u8 port_type; + u8 lane_mode; + bool enable; /* if the port is enabled */ + struct kobject kobj; + bool dir_created; + struct hccs_die_info *die; /* point to the die the port is located */ +}; + +struct hccs_die_info { + u8 die_id; + u8 port_num; + u8 min_port_id; + u8 max_port_id; + struct hccs_port_info *ports; + struct kobject kobj; + bool dir_created; + struct hccs_chip_info *chip; /* point to the chip the die is located */ +}; + +struct hccs_chip_info { + u8 chip_id; + u8 die_num; + struct hccs_die_info *dies; + struct kobject kobj; + struct hccs_dev *hdev; +}; + +struct hccs_mbox_client_info { + struct mbox_client client; + struct mbox_chan *mbox_chan; + struct pcc_mbox_chan *pcc_chan; + u64 deadline_us; + void __iomem *pcc_comm_addr; +}; + +struct hccs_dev { + struct device *dev; + struct acpi_device *acpi_dev; + u64 caps; + u8 chip_num; + struct hccs_chip_info *chips; + u8 chan_id; + struct mutex lock; + struct hccs_mbox_client_info cl_info; +}; + +#define HCCS_SERDES_MODULE_CODE 0x32 +enum hccs_subcmd_type { + HCCS_GET_CHIP_NUM = 0x1, + HCCS_GET_DIE_NUM, + HCCS_GET_DIE_INFO, + HCCS_GET_DIE_PORT_INFO, + HCCS_GET_DEV_CAP, + HCCS_GET_PORT_LINK_STATUS, + HCCS_GET_PORT_CRC_ERR_CNT, + HCCS_GET_DIE_PORTS_LANE_STA, + HCCS_GET_DIE_PORTS_LINK_STA, + HCCS_GET_DIE_PORTS_CRC_ERR_CNT, + HCCS_SUB_CMD_MAX = 255, +}; + +struct hccs_die_num_req_param { + u8 chip_id; +}; + +struct hccs_die_info_req_param { + u8 chip_id; + u8 die_idx; +}; + +struct hccs_die_info_rsp_data { + u8 die_id; + u8 port_num; + u8 min_port_id; + u8 max_port_id; +}; + +struct hccs_port_attr { + u8 port_id; + u8 port_type; + u8 lane_mode; + u8 enable : 1; /* if the port is enabled */ + u16 rsv[2]; +}; + +/* + * The common command request for getting the information of all HCCS port on + * specified DIE. + */ +struct hccs_die_comm_req_param { + u8 chip_id; + u8 die_id; /* id in hardware */ +}; + +/* The common command request for getting the information of a specific port */ +struct hccs_port_comm_req_param { + u8 chip_id; + u8 die_id; + u8 port_id; +}; + +#define HCCS_PORT_RESET 1 +#define HCCS_PORT_SETUP 2 +#define HCCS_PORT_CONFIG 3 +#define HCCS_PORT_READY 4 +struct hccs_link_status { + u8 lane_mask; /* indicate which lanes are used. */ + u8 link_fsm : 3; /* link fsm, 1: reset 2: setup 3: config 4: link-up */ + u8 lane_num : 5; /* current lane number */ +}; + +struct hccs_req_head { + u8 module_code; /* set to 0x32 for serdes */ + u8 start_id; + u8 rsv[2]; +}; + +struct hccs_rsp_head { + u8 data_len; + u8 next_id; + u8 rsv[2]; +}; + +struct hccs_fw_inner_head { + u8 retStatus; /* 0: success, other: failure */ + u8 rsv[7]; +}; + +#define HCCS_PCC_SHARE_MEM_BYTES 64 +#define HCCS_FW_INNER_HEAD_BYTES 8 +#define HCCS_RSP_HEAD_BYTES 4 + +#define HCCS_MAX_RSP_DATA_BYTES (HCCS_PCC_SHARE_MEM_BYTES - \ + HCCS_FW_INNER_HEAD_BYTES - \ + HCCS_RSP_HEAD_BYTES) +#define HCCS_MAX_RSP_DATA_SIZE_MAX (HCCS_MAX_RSP_DATA_BYTES / 4) + +/* + * Note: Actual available size of data field also depands on the PCC header + * bytes of the specific type. Driver needs to copy the response data in the + * communication space based on the real length. + */ +struct hccs_rsp_desc { + struct hccs_fw_inner_head fw_inner_head; /* 8 Bytes */ + struct hccs_rsp_head rsp_head; /* 4 Bytes */ + u32 data[HCCS_MAX_RSP_DATA_SIZE_MAX]; +}; + +#define HCCS_REQ_HEAD_BYTES 4 +#define HCCS_MAX_REQ_DATA_BYTES (HCCS_PCC_SHARE_MEM_BYTES - \ + HCCS_REQ_HEAD_BYTES) +#define HCCS_MAX_REQ_DATA_SIZE_MAX (HCCS_MAX_REQ_DATA_BYTES / 4) + +/* + * Note: Actual available size of data field also depands on the PCC header + * bytes of the specific type. Driver needs to copy the request data to the + * communication space based on the real length. + */ +struct hccs_req_desc { + struct hccs_req_head req_head; /* 4 Bytes */ + u32 data[HCCS_MAX_REQ_DATA_SIZE_MAX]; +}; + +struct hccs_desc { + union { + struct hccs_req_desc req; + struct hccs_rsp_desc rsp; + }; +}; + +#endif /* __KUNPENG_HCCS_H__ */ diff --git a/drivers/soc/loongson/Kconfig b/drivers/soc/loongson/Kconfig index 707f56358dc4..314e13bb3e01 100644 --- a/drivers/soc/loongson/Kconfig +++ b/drivers/soc/loongson/Kconfig @@ -16,3 +16,13 @@ config LOONGSON2_GUTS SoCs. Initially only reading SVR and registering soc device are supported. Other guts accesses, such as reading firmware configuration by default, should eventually be added into this driver as well. + +config LOONGSON2_PM + bool "Loongson-2 SoC Power Management Controller Driver" + depends on LOONGARCH && OF + help + The Loongson-2's power management controller was ACPI, supports ACPI + S2Idle (Suspend To Idle), ACPI S3 (Suspend To RAM), ACPI S4 (Suspend To + Disk), ACPI S5 (Soft Shutdown) and supports multiple wake-up methods + (USB, GMAC, PWRBTN, etc.). This driver was to add power management + controller support that base on dts for Loongson-2 series SoCs. diff --git a/drivers/soc/loongson/Makefile b/drivers/soc/loongson/Makefile index 263c486df638..4118f50f55e2 100644 --- a/drivers/soc/loongson/Makefile +++ b/drivers/soc/loongson/Makefile @@ -4,3 +4,4 @@ # obj-$(CONFIG_LOONGSON2_GUTS) += loongson2_guts.o +obj-$(CONFIG_LOONGSON2_PM) += loongson2_pm.o diff --git a/drivers/soc/loongson/loongson2_pm.c b/drivers/soc/loongson/loongson2_pm.c new file mode 100644 index 000000000000..796add6e8b63 --- /dev/null +++ b/drivers/soc/loongson/loongson2_pm.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Loongson-2 PM Support + * + * Copyright (C) 2023 Loongson Technology Corporation Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOONGSON2_PM1_CNT_REG 0x14 +#define LOONGSON2_PM1_STS_REG 0x0c +#define LOONGSON2_PM1_ENA_REG 0x10 +#define LOONGSON2_GPE0_STS_REG 0x28 +#define LOONGSON2_GPE0_ENA_REG 0x2c + +#define LOONGSON2_PM1_PWRBTN_STS BIT(8) +#define LOONGSON2_PM1_PCIEXP_WAKE_STS BIT(14) +#define LOONGSON2_PM1_WAKE_STS BIT(15) +#define LOONGSON2_PM1_CNT_INT_EN BIT(0) +#define LOONGSON2_PM1_PWRBTN_EN LOONGSON2_PM1_PWRBTN_STS + +static struct loongson2_pm { + void __iomem *base; + struct input_dev *dev; + bool suspended; +} loongson2_pm; + +#define loongson2_pm_readw(reg) readw(loongson2_pm.base + reg) +#define loongson2_pm_readl(reg) readl(loongson2_pm.base + reg) +#define loongson2_pm_writew(val, reg) writew(val, loongson2_pm.base + reg) +#define loongson2_pm_writel(val, reg) writel(val, loongson2_pm.base + reg) + +static void loongson2_pm_status_clear(void) +{ + u16 value; + + value = loongson2_pm_readw(LOONGSON2_PM1_STS_REG); + value |= (LOONGSON2_PM1_PWRBTN_STS | LOONGSON2_PM1_PCIEXP_WAKE_STS | + LOONGSON2_PM1_WAKE_STS); + loongson2_pm_writew(value, LOONGSON2_PM1_STS_REG); + loongson2_pm_writel(loongson2_pm_readl(LOONGSON2_GPE0_STS_REG), LOONGSON2_GPE0_STS_REG); +} + +static void loongson2_pm_irq_enable(void) +{ + u16 value; + + value = loongson2_pm_readw(LOONGSON2_PM1_CNT_REG); + value |= LOONGSON2_PM1_CNT_INT_EN; + loongson2_pm_writew(value, LOONGSON2_PM1_CNT_REG); + + value = loongson2_pm_readw(LOONGSON2_PM1_ENA_REG); + value |= LOONGSON2_PM1_PWRBTN_EN; + loongson2_pm_writew(value, LOONGSON2_PM1_ENA_REG); +} + +static int loongson2_suspend_enter(suspend_state_t state) +{ + loongson2_pm_status_clear(); + loongarch_common_suspend(); + loongarch_suspend_enter(); + loongarch_common_resume(); + loongson2_pm_irq_enable(); + pm_set_resume_via_firmware(); + + return 0; +} + +static int loongson2_suspend_begin(suspend_state_t state) +{ + pm_set_suspend_via_firmware(); + + return 0; +} + +static int loongson2_suspend_valid_state(suspend_state_t state) +{ + return (state == PM_SUSPEND_MEM); +} + +static const struct platform_suspend_ops loongson2_suspend_ops = { + .valid = loongson2_suspend_valid_state, + .begin = loongson2_suspend_begin, + .enter = loongson2_suspend_enter, +}; + +static int loongson2_power_button_init(struct device *dev, int irq) +{ + int ret; + struct input_dev *button; + + button = input_allocate_device(); + if (!dev) + return -ENOMEM; + + button->name = "Power Button"; + button->phys = "pm/button/input0"; + button->id.bustype = BUS_HOST; + button->dev.parent = NULL; + input_set_capability(button, EV_KEY, KEY_POWER); + + ret = input_register_device(button); + if (ret) + goto free_dev; + + dev_pm_set_wake_irq(&button->dev, irq); + device_set_wakeup_capable(&button->dev, true); + device_set_wakeup_enable(&button->dev, true); + + loongson2_pm.dev = button; + dev_info(dev, "Power Button: Init successful!\n"); + + return 0; + +free_dev: + input_free_device(button); + + return ret; +} + +static irqreturn_t loongson2_pm_irq_handler(int irq, void *dev_id) +{ + u16 status = loongson2_pm_readw(LOONGSON2_PM1_STS_REG); + + if (!loongson2_pm.suspended && (status & LOONGSON2_PM1_PWRBTN_STS)) { + pr_info("Power Button pressed...\n"); + input_report_key(loongson2_pm.dev, KEY_POWER, 1); + input_sync(loongson2_pm.dev); + input_report_key(loongson2_pm.dev, KEY_POWER, 0); + input_sync(loongson2_pm.dev); + } + + loongson2_pm_status_clear(); + + return IRQ_HANDLED; +} + +static int __maybe_unused loongson2_pm_suspend(struct device *dev) +{ + loongson2_pm.suspended = true; + + return 0; +} + +static int __maybe_unused loongson2_pm_resume(struct device *dev) +{ + loongson2_pm.suspended = false; + + return 0; +} +static SIMPLE_DEV_PM_OPS(loongson2_pm_ops, loongson2_pm_suspend, loongson2_pm_resume); + +static int loongson2_pm_probe(struct platform_device *pdev) +{ + int irq, retval; + u64 suspend_addr; + struct device *dev = &pdev->dev; + + loongson2_pm.base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(loongson2_pm.base)) + return PTR_ERR(loongson2_pm.base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + if (!device_property_read_u64(dev, "loongson,suspend-address", &suspend_addr)) + loongson_sysconf.suspend_addr = (u64)phys_to_virt(suspend_addr); + else + dev_err(dev, "No loongson,suspend-address, could not support S3!\n"); + + if (loongson2_power_button_init(dev, irq)) + return -EINVAL; + + retval = devm_request_irq(&pdev->dev, irq, loongson2_pm_irq_handler, + IRQF_SHARED, "pm_irq", &loongson2_pm); + if (retval) + return retval; + + loongson2_pm_irq_enable(); + loongson2_pm_status_clear(); + + if (loongson_sysconf.suspend_addr) + suspend_set_ops(&loongson2_suspend_ops); + + return 0; +} + +static const struct of_device_id loongson2_pm_match[] = { + { .compatible = "loongson,ls2k0500-pmc", }, + { .compatible = "loongson,ls2k1000-pmc", }, + {}, +}; + +static struct platform_driver loongson2_pm_driver = { + .driver = { + .name = "ls2k-pm", + .pm = &loongson2_pm_ops, + .of_match_table = loongson2_pm_match, + }, + .probe = loongson2_pm_probe, +}; +module_platform_driver(loongson2_pm_driver); + +MODULE_DESCRIPTION("Loongson-2 PM driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index e597799e8121..715348869d04 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -191,6 +191,7 @@ config QCOM_SMD_RPM tristate "Qualcomm Resource Power Manager (RPM) over SMD" depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG + depends on RPMSG_QCOM_SMD || RPMSG_QCOM_SMD=n help If you say yes to this option, support will be included for the Resource Power Manager system found in the Qualcomm 8974 based diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index f548a7150bb2..bbca2e1e55bb 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -17,7 +17,7 @@ obj-$(CONFIG_QCOM_RPM_MASTER_STATS) += rpm_master_stats.o obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o qcom_rpmh-y += rpmh-rsc.o qcom_rpmh-y += rpmh.o -obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o +obj-$(CONFIG_QCOM_SMD_RPM) += rpm-proc.o smd-rpm.o obj-$(CONFIG_QCOM_SMEM) += smem.o obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index 33856abd560c..34c40368d5b5 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -284,7 +284,7 @@ static int cmd_db_debugfs_dump(struct seq_file *seq, void *p) ent = rsc_to_entry_header(rsc); for (j = 0; j < le16_to_cpu(rsc->cnt); j++, ent++) { seq_printf(seq, "0x%05x: %*pEp", le32_to_cpu(ent->addr), - (int)sizeof(ent->id), ent->id); + (int)strnlen(ent->id, sizeof(ent->id)), ent->id); len = le16_to_cpu(ent->len); if (len) { diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index 40068a285913..adf2d523f103 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -165,9 +165,6 @@ enum bwmon_fields { struct icc_bwmon_data { unsigned int sample_ms; unsigned int count_unit_kb; /* kbytes */ - unsigned int default_highbw_kbps; - unsigned int default_medbw_kbps; - unsigned int default_lowbw_kbps; u8 zone1_thres_count; u8 zone3_thres_count; unsigned int quirks; @@ -564,20 +561,21 @@ static void bwmon_set_threshold(struct icc_bwmon *bwmon, static void bwmon_start(struct icc_bwmon *bwmon) { const struct icc_bwmon_data *data = bwmon->data; + u32 bw_low = 0; int window; + /* No need to check for errors, as this must have succeeded before. */ + dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_low, 0); + bwmon_clear_counters(bwmon, true); window = mult_frac(bwmon->data->sample_ms, HW_TIMER_HZ, MSEC_PER_SEC); /* Maximum sampling window: 0xffffff for v4 and 0xfffff for v5 */ regmap_field_write(bwmon->regs[F_SAMPLE_WINDOW], window); - bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], - data->default_highbw_kbps); - bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], - data->default_medbw_kbps); - bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW], - data->default_lowbw_kbps); + bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_HIGH], bw_low); + bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_MED], bw_low); + bwmon_set_threshold(bwmon, bwmon->regs[F_THRESHOLD_LOW], 0); regmap_field_write(bwmon->regs[F_THRESHOLD_COUNT_ZONE0], BWMON_THRESHOLD_COUNT_ZONE0_DEFAULT); @@ -807,9 +805,6 @@ static int bwmon_remove(struct platform_device *pdev) static const struct icc_bwmon_data msm8998_bwmon_data = { .sample_ms = 4, .count_unit_kb = 1024, - .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */ - .default_medbw_kbps = 512 * 1024, /* 512 MBps */ - .default_lowbw_kbps = 0, .zone1_thres_count = 16, .zone3_thres_count = 1, .quirks = BWMON_HAS_GLOBAL_IRQ, @@ -822,9 +817,6 @@ static const struct icc_bwmon_data msm8998_bwmon_data = { static const struct icc_bwmon_data sdm845_cpu_bwmon_data = { .sample_ms = 4, .count_unit_kb = 64, - .default_highbw_kbps = 4800 * 1024, /* 4.8 GBps */ - .default_medbw_kbps = 512 * 1024, /* 512 MBps */ - .default_lowbw_kbps = 0, .zone1_thres_count = 16, .zone3_thres_count = 1, .quirks = BWMON_HAS_GLOBAL_IRQ, @@ -835,9 +827,6 @@ static const struct icc_bwmon_data sdm845_cpu_bwmon_data = { static const struct icc_bwmon_data sdm845_llcc_bwmon_data = { .sample_ms = 4, .count_unit_kb = 1024, - .default_highbw_kbps = 800 * 1024, /* 800 MBps */ - .default_medbw_kbps = 256 * 1024, /* 256 MBps */ - .default_lowbw_kbps = 0, .zone1_thres_count = 16, .zone3_thres_count = 1, .regmap_fields = sdm845_llcc_bwmon_reg_fields, @@ -847,9 +836,6 @@ static const struct icc_bwmon_data sdm845_llcc_bwmon_data = { static const struct icc_bwmon_data sc7280_llcc_bwmon_data = { .sample_ms = 4, .count_unit_kb = 64, - .default_highbw_kbps = 800 * 1024, /* 800 MBps */ - .default_medbw_kbps = 256 * 1024, /* 256 MBps */ - .default_lowbw_kbps = 0, .zone1_thres_count = 16, .zone3_thres_count = 1, .quirks = BWMON_NEEDS_FORCE_CLEAR, diff --git a/drivers/soc/qcom/ice.c b/drivers/soc/qcom/ice.c index a6123ea96272..fbab7fe5c652 100644 --- a/drivers/soc/qcom/ice.c +++ b/drivers/soc/qcom/ice.c @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include #include diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 67c19ed2219a..e32a4161a8d0 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index aaddc3cc53b7..20f5461d46b9 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -14,7 +14,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -54,6 +55,8 @@ struct ocmem { const struct ocmem_config *config; struct resource *memory; void __iomem *mmio; + struct clk *core_clk; + struct clk *iface_clk; unsigned int num_ports; unsigned int num_macros; bool interleaved; @@ -80,8 +83,8 @@ struct ocmem { #define OCMEM_HW_VERSION_MINOR(val) FIELD_GET(GENMASK(27, 16), val) #define OCMEM_HW_VERSION_STEP(val) FIELD_GET(GENMASK(15, 0), val) -#define OCMEM_HW_PROFILE_NUM_PORTS(val) FIELD_PREP(0x0000000f, (val)) -#define OCMEM_HW_PROFILE_NUM_MACROS(val) FIELD_PREP(0x00003f00, (val)) +#define OCMEM_HW_PROFILE_NUM_PORTS(val) FIELD_GET(0x0000000f, (val)) +#define OCMEM_HW_PROFILE_NUM_MACROS(val) FIELD_GET(0x00003f00, (val)) #define OCMEM_HW_PROFILE_LAST_REGN_HALFSIZE 0x00010000 #define OCMEM_HW_PROFILE_INTERLEAVING 0x00020000 @@ -95,16 +98,6 @@ struct ocmem { #define OCMEM_PSGSC_CTL_MACRO2_MODE(val) FIELD_PREP(0x00000700, (val)) #define OCMEM_PSGSC_CTL_MACRO3_MODE(val) FIELD_PREP(0x00007000, (val)) -#define OCMEM_CLK_CORE_IDX 0 -static struct clk_bulk_data ocmem_clks[] = { - { - .id = "core", - }, - { - .id = "iface", - }, -}; - static inline void ocmem_write(struct ocmem *ocmem, u32 reg, u32 data) { writel(data, ocmem->mmio + reg); @@ -320,19 +313,20 @@ static int ocmem_dev_probe(struct platform_device *pdev) ocmem->dev = dev; ocmem->config = device_get_match_data(dev); - ret = devm_clk_bulk_get(dev, ARRAY_SIZE(ocmem_clks), ocmem_clks); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Unable to get clocks\n"); + ocmem->core_clk = devm_clk_get(dev, "core"); + if (IS_ERR(ocmem->core_clk)) + return dev_err_probe(dev, PTR_ERR(ocmem->core_clk), + "Unable to get core clock\n"); - return ret; - } + ocmem->iface_clk = devm_clk_get_optional(dev, "iface"); + if (IS_ERR(ocmem->iface_clk)) + return dev_err_probe(dev, PTR_ERR(ocmem->iface_clk), + "Unable to get iface clock\n"); ocmem->mmio = devm_platform_ioremap_resource_byname(pdev, "ctrl"); - if (IS_ERR(ocmem->mmio)) { - dev_err(&pdev->dev, "Failed to ioremap ocmem_ctrl resource\n"); - return PTR_ERR(ocmem->mmio); - } + if (IS_ERR(ocmem->mmio)) + return dev_err_probe(&pdev->dev, PTR_ERR(ocmem->mmio), + "Failed to ioremap ocmem_ctrl resource\n"); ocmem->memory = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); @@ -342,19 +336,23 @@ static int ocmem_dev_probe(struct platform_device *pdev) } /* The core clock is synchronous with graphics */ - WARN_ON(clk_set_rate(ocmem_clks[OCMEM_CLK_CORE_IDX].clk, 1000) < 0); + WARN_ON(clk_set_rate(ocmem->core_clk, 1000) < 0); - ret = clk_bulk_prepare_enable(ARRAY_SIZE(ocmem_clks), ocmem_clks); + ret = clk_prepare_enable(ocmem->core_clk); + if (ret) + return dev_err_probe(ocmem->dev, ret, "Failed to enable core clock\n"); + + ret = clk_prepare_enable(ocmem->iface_clk); if (ret) { - dev_info(ocmem->dev, "Failed to enable clocks\n"); - return ret; + clk_disable_unprepare(ocmem->core_clk); + return dev_err_probe(ocmem->dev, ret, "Failed to enable iface clock\n"); } if (qcom_scm_restore_sec_cfg_available()) { dev_dbg(dev, "configuring scm\n"); ret = qcom_scm_restore_sec_cfg(QCOM_SCM_OCMEM_DEV_ID, 0); if (ret) { - dev_err(dev, "Could not enable secure configuration\n"); + dev_err_probe(dev, ret, "Could not enable secure configuration\n"); goto err_clk_disable; } } @@ -413,23 +411,33 @@ static int ocmem_dev_probe(struct platform_device *pdev) return 0; err_clk_disable: - clk_bulk_disable_unprepare(ARRAY_SIZE(ocmem_clks), ocmem_clks); + clk_disable_unprepare(ocmem->core_clk); + clk_disable_unprepare(ocmem->iface_clk); return ret; } static int ocmem_dev_remove(struct platform_device *pdev) { - clk_bulk_disable_unprepare(ARRAY_SIZE(ocmem_clks), ocmem_clks); + struct ocmem *ocmem = platform_get_drvdata(pdev); + + clk_disable_unprepare(ocmem->core_clk); + clk_disable_unprepare(ocmem->iface_clk); return 0; } +static const struct ocmem_config ocmem_8226_config = { + .num_regions = 1, + .macro_size = SZ_128K, +}; + static const struct ocmem_config ocmem_8974_config = { .num_regions = 3, .macro_size = SZ_128K, }; static const struct of_device_id ocmem_of_match[] = { + { .compatible = "qcom,msm8226-ocmem", .data = &ocmem_8226_config }, { .compatible = "qcom,msm8974-ocmem", .data = &ocmem_8974_config }, { } }; diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index c87056769ebd..61c89ddfc75b 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -4,8 +4,8 @@ * Copyright (c) 2022, Linaro Ltd */ #include -#include #include +#include #include #include #include @@ -342,13 +342,9 @@ static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT BIT(PMIC_GLINK_CLIENT_ALTMODE) | BIT(PMIC_GLINK_CLIENT_UCSI); -/* Do not handle altmode for now on those platforms */ -static const unsigned long pmic_glink_sm8550_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | - BIT(PMIC_GLINK_CLIENT_UCSI); - static const struct of_device_id pmic_glink_of_match[] = { { .compatible = "qcom,sm8450-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, - { .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8550_client_mask }, + { .compatible = "qcom,sm8550-pmic-glink", .data = &pmic_glink_sm8450_client_mask }, { .compatible = "qcom,pmic-glink" }, {} }; diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c index df48fbea4b68..d05e0d6edf49 100644 --- a/drivers/soc/qcom/pmic_glink_altmode.c +++ b/drivers/soc/qcom/pmic_glink_altmode.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include @@ -68,6 +70,8 @@ struct pmic_glink_altmode_port { struct typec_switch *typec_switch; struct typec_mux *typec_mux; struct typec_mux_state state; + struct typec_retimer *typec_retimer; + struct typec_retimer_state retimer_state; struct typec_altmode dp_alt; struct work_struct work; @@ -157,6 +161,14 @@ static void pmic_glink_altmode_enable_dp(struct pmic_glink_altmode *altmode, ret = typec_mux_set(port->typec_mux, &port->state); if (ret) dev_err(altmode->dev, "failed to switch mux to DP\n"); + + port->retimer_state.alt = &port->dp_alt; + port->retimer_state.data = &dp_data; + port->retimer_state.mode = TYPEC_MODAL_STATE(mode); + + ret = typec_retimer_set(port->typec_retimer, &port->retimer_state); + if (ret) + dev_err(altmode->dev, "failed to setup retimer to DP\n"); } static void pmic_glink_altmode_enable_usb(struct pmic_glink_altmode *altmode, @@ -171,6 +183,36 @@ static void pmic_glink_altmode_enable_usb(struct pmic_glink_altmode *altmode, ret = typec_mux_set(port->typec_mux, &port->state); if (ret) dev_err(altmode->dev, "failed to switch mux to USB\n"); + + port->retimer_state.alt = NULL; + port->retimer_state.data = NULL; + port->retimer_state.mode = TYPEC_STATE_USB; + + ret = typec_retimer_set(port->typec_retimer, &port->retimer_state); + if (ret) + dev_err(altmode->dev, "failed to setup retimer to USB\n"); +} + +static void pmic_glink_altmode_safe(struct pmic_glink_altmode *altmode, + struct pmic_glink_altmode_port *port) +{ + int ret; + + port->state.alt = NULL; + port->state.data = NULL; + port->state.mode = TYPEC_STATE_SAFE; + + ret = typec_mux_set(port->typec_mux, &port->state); + if (ret) + dev_err(altmode->dev, "failed to switch mux to safe mode\n"); + + port->retimer_state.alt = NULL; + port->retimer_state.data = NULL; + port->retimer_state.mode = TYPEC_STATE_SAFE; + + ret = typec_retimer_set(port->typec_retimer, &port->retimer_state); + if (ret) + dev_err(altmode->dev, "failed to setup retimer to USB\n"); } static void pmic_glink_altmode_worker(struct work_struct *work) @@ -180,7 +222,9 @@ static void pmic_glink_altmode_worker(struct work_struct *work) typec_switch_set(alt_port->typec_switch, alt_port->orientation); - if (alt_port->svid == USB_TYPEC_DP_SID) + if (alt_port->svid == USB_TYPEC_DP_SID && alt_port->mode == 0xff) + pmic_glink_altmode_safe(altmode, alt_port); + else if (alt_port->svid == USB_TYPEC_DP_SID) pmic_glink_altmode_enable_dp(altmode, alt_port, alt_port->mode, alt_port->hpd_state, alt_port->hpd_irq); else @@ -331,6 +375,11 @@ static const struct drm_bridge_funcs pmic_glink_altmode_bridge_funcs = { .attach = pmic_glink_altmode_attach, }; +static void pmic_glink_altmode_put_retimer(void *data) +{ + typec_retimer_put(data); +} + static void pmic_glink_altmode_put_mux(void *data) { typec_mux_put(data); @@ -437,6 +486,17 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, if (ret) return ret; + alt_port->typec_retimer = fwnode_typec_retimer_get(fwnode); + if (IS_ERR(alt_port->typec_retimer)) + return dev_err_probe(dev, PTR_ERR(alt_port->typec_retimer), + "failed to acquire retimer-switch for port: %d\n", + port); + + ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_retimer, + alt_port->typec_retimer); + if (ret) + return ret; + alt_port->typec_switch = fwnode_typec_switch_get(fwnode); if (IS_ERR(alt_port->typec_switch)) return dev_err_probe(dev, PTR_ERR(alt_port->typec_switch), diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index e376c32cc16e..77f0cf126629 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -205,37 +205,42 @@ static bool qmp_message_empty(struct qmp *qmp) /** * qmp_send() - send a message to the AOSS * @qmp: qmp context - * @data: message to be sent - * @len: length of the message + * @fmt: format string for message to be sent + * @...: arguments for the format string * - * Transmit @data to AOSS and wait for the AOSS to acknowledge the message. - * @len must be a multiple of 4 and not longer than the mailbox size. Access is - * synchronized by this implementation. + * Transmit message to AOSS and wait for the AOSS to acknowledge the message. + * data must not be longer than the mailbox size. Access is synchronized by + * this implementation. * * Return: 0 on success, negative errno on failure */ -int qmp_send(struct qmp *qmp, const void *data, size_t len) +int qmp_send(struct qmp *qmp, const char *fmt, ...) { + char buf[QMP_MSG_LEN]; long time_left; + va_list args; + int len; int ret; - if (WARN_ON(IS_ERR_OR_NULL(qmp) || !data)) + if (WARN_ON(IS_ERR_OR_NULL(qmp) || !fmt)) return -EINVAL; - if (WARN_ON(len + sizeof(u32) > qmp->size)) - return -EINVAL; + memset(buf, 0, sizeof(buf)); + va_start(args, fmt); + len = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); - if (WARN_ON(len % sizeof(u32))) + if (WARN_ON(len >= sizeof(buf))) return -EINVAL; mutex_lock(&qmp->tx_lock); /* The message RAM only implements 32-bit accesses */ __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32), - data, len / sizeof(u32)); - writel(len, qmp->msgram + qmp->offset); + buf, sizeof(buf) / sizeof(u32)); + writel(sizeof(buf), qmp->msgram + qmp->offset); - /* Read back len to confirm data written in message RAM */ + /* Read back length to confirm data written in message RAM */ readl(qmp->msgram + qmp->offset); qmp_kick(qmp); @@ -259,18 +264,18 @@ EXPORT_SYMBOL(qmp_send); static int qmp_qdss_clk_prepare(struct clk_hw *hw) { - static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 1}"; + static const char *buf = "{class: clock, res: qdss, val: 1}"; struct qmp *qmp = container_of(hw, struct qmp, qdss_clk); - return qmp_send(qmp, buf, sizeof(buf)); + return qmp_send(qmp, buf); } static void qmp_qdss_clk_unprepare(struct clk_hw *hw) { - static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 0}"; + static const char *buf = "{class: clock, res: qdss, val: 0}"; struct qmp *qmp = container_of(hw, struct qmp, qdss_clk); - qmp_send(qmp, buf, sizeof(buf)); + qmp_send(qmp, buf); } static const struct clk_ops qmp_qdss_clk_ops = { @@ -329,7 +334,6 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct qmp_cooling_device *qmp_cdev = cdev->devdata; - char buf[QMP_MSG_LEN] = {}; bool cdev_state; int ret; @@ -339,13 +343,8 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, if (qmp_cdev->state == state) return 0; - snprintf(buf, sizeof(buf), - "{class: volt_flr, event:zero_temp, res:%s, value:%s}", - qmp_cdev->name, - cdev_state ? "on" : "off"); - - ret = qmp_send(qmp_cdev->qmp, buf, sizeof(buf)); - + ret = qmp_send(qmp_cdev->qmp, "{class: volt_flr, event:zero_temp, res:%s, value:%s}", + qmp_cdev->name, cdev_state ? "on" : "off"); if (!ret) qmp_cdev->state = cdev_state; diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c index f1742e5bddb9..df7907a83aa8 100644 --- a/drivers/soc/qcom/qcom_gsbi.c +++ b/drivers/soc/qcom/qcom_gsbi.c @@ -129,7 +129,7 @@ static int gsbi_probe(struct platform_device *pdev) const struct of_device_id *match; void __iomem *base; struct gsbi_info *gsbi; - int i, ret; + int i; u32 mask, gsbi_num; const struct crci_config *config = NULL; @@ -178,12 +178,10 @@ static int gsbi_probe(struct platform_device *pdev) dev_info(&pdev->dev, "GSBI port protocol: %d crci: %d\n", gsbi->mode, gsbi->crci); - gsbi->hclk = devm_clk_get(&pdev->dev, "iface"); + gsbi->hclk = devm_clk_get_enabled(&pdev->dev, "iface"); if (IS_ERR(gsbi->hclk)) return PTR_ERR(gsbi->hclk); - clk_prepare_enable(gsbi->hclk); - writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci, base + GSBI_CTRL_REG); @@ -211,10 +209,7 @@ static int gsbi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gsbi); - ret = of_platform_populate(node, NULL, NULL, &pdev->dev); - if (ret) - clk_disable_unprepare(gsbi->hclk); - return ret; + return of_platform_populate(node, NULL, NULL, &pdev->dev); } static int gsbi_remove(struct platform_device *pdev) diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index b7158e3c3a0b..5c7161b18b72 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -534,8 +534,8 @@ static int qmi_decode_string_elem(const struct qmi_elem_info *ei_array, decoded_bytes += rc; } - if (string_len > temp_ei->elem_len) { - pr_err("%s: String len %d > Max Len %d\n", + if (string_len >= temp_ei->elem_len) { + pr_err("%s: String len %d >= Max Len %d\n", __func__, string_len, temp_ei->elem_len); return -ETOOSMALL; } else if (string_len > tlv_len) { diff --git a/drivers/soc/qcom/rpm-proc.c b/drivers/soc/qcom/rpm-proc.c new file mode 100644 index 000000000000..2995d9b90190 --- /dev/null +++ b/drivers/soc/qcom/rpm-proc.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2021-2023, Stephan Gerhold */ + +#include +#include +#include +#include +#include + +static int rpm_proc_probe(struct platform_device *pdev) +{ + struct qcom_smd_edge *edge = NULL; + struct device *dev = &pdev->dev; + struct device_node *edge_node; + int ret; + + edge_node = of_get_child_by_name(dev->of_node, "smd-edge"); + if (edge_node) { + edge = qcom_smd_register_edge(dev, edge_node); + of_node_put(edge_node); + if (IS_ERR(edge)) + return dev_err_probe(dev, PTR_ERR(edge), + "Failed to register smd-edge\n"); + } + + ret = devm_of_platform_populate(dev); + if (ret) { + dev_err(dev, "Failed to populate child devices: %d\n", ret); + goto err; + } + + platform_set_drvdata(pdev, edge); + return 0; +err: + if (edge) + qcom_smd_unregister_edge(edge); + return ret; +} + +static void rpm_proc_remove(struct platform_device *pdev) +{ + struct qcom_smd_edge *edge = platform_get_drvdata(pdev); + + if (edge) + qcom_smd_unregister_edge(edge); +} + +static const struct of_device_id rpm_proc_of_match[] = { + { .compatible = "qcom,rpm-proc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rpm_proc_of_match); + +static struct platform_driver rpm_proc_driver = { + .probe = rpm_proc_probe, + .remove_new = rpm_proc_remove, + .driver = { + .name = "qcom-rpm-proc", + .of_match_table = rpm_proc_of_match, + }, +}; + +static int __init rpm_proc_init(void) +{ + return platform_driver_register(&rpm_proc_driver); +} +arch_initcall(rpm_proc_init); + +static void __exit rpm_proc_exit(void) +{ + platform_driver_unregister(&rpm_proc_driver); +} +module_exit(rpm_proc_exit); + +MODULE_DESCRIPTION("Qualcomm RPM processor/subsystem driver"); +MODULE_AUTHOR("Stephan Gerhold "); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 0dd4363ebac8..a021dc71807b 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -516,7 +516,7 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid); write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr); write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data); - trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd); + trace_rpmh_send_msg(drv, tcs_id, msg->state, j, msgid, cmd); } cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id); diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index 0c1aa809cc4e..13d8c52330d0 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -199,6 +199,9 @@ static int qcom_smd_rpm_probe(struct rpmsg_device *rpdev) struct qcom_smd_rpm *rpm; int ret; + if (!rpdev->dev.of_node) + return -EINVAL; + rpm = devm_kzalloc(&rpdev->dev, sizeof(*rpm), GFP_KERNEL); if (!rpm) return -ENOMEM; @@ -230,38 +233,18 @@ static void qcom_smd_rpm_remove(struct rpmsg_device *rpdev) of_platform_depopulate(&rpdev->dev); } -static const struct of_device_id qcom_smd_rpm_of_match[] = { - { .compatible = "qcom,rpm-apq8084" }, - { .compatible = "qcom,rpm-ipq6018" }, - { .compatible = "qcom,rpm-ipq9574" }, - { .compatible = "qcom,rpm-msm8226" }, - { .compatible = "qcom,rpm-msm8909" }, - { .compatible = "qcom,rpm-msm8916" }, - { .compatible = "qcom,rpm-msm8936" }, - { .compatible = "qcom,rpm-msm8953" }, - { .compatible = "qcom,rpm-msm8974" }, - { .compatible = "qcom,rpm-msm8976" }, - { .compatible = "qcom,rpm-msm8994" }, - { .compatible = "qcom,rpm-msm8996" }, - { .compatible = "qcom,rpm-msm8998" }, - { .compatible = "qcom,rpm-sdm660" }, - { .compatible = "qcom,rpm-sm6115" }, - { .compatible = "qcom,rpm-sm6125" }, - { .compatible = "qcom,rpm-sm6375" }, - { .compatible = "qcom,rpm-qcm2290" }, - { .compatible = "qcom,rpm-qcs404" }, - {} +static const struct rpmsg_device_id qcom_smd_rpm_id_table[] = { + { .name = "rpm_requests", }, + { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match); +MODULE_DEVICE_TABLE(rpmsg, qcom_smd_rpm_id_table); static struct rpmsg_driver qcom_smd_rpm_driver = { .probe = qcom_smd_rpm_probe, .remove = qcom_smd_rpm_remove, .callback = qcom_smd_rpm_callback, - .drv = { - .name = "qcom_smd_rpm", - .of_match_table = qcom_smd_rpm_of_match, - }, + .id_table = qcom_smd_rpm_id_table, + .drv.name = "qcom_smd_rpm", }; static int __init qcom_smd_rpm_init(void) diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index b0d59e815c3b..d4a89d2bb43b 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -359,6 +359,17 @@ static struct qcom_smem *__smem; /* Timeout (ms) for the trylock of remote spinlocks */ #define HWSPINLOCK_TIMEOUT 1000 +/** + * qcom_smem_is_available() - Check if SMEM is available + * + * Return: true if SMEM is available, false otherwise. + */ +bool qcom_smem_is_available(void) +{ + return !!__smem; +} +EXPORT_SYMBOL(qcom_smem_is_available); + static int qcom_smem_alloc_private(struct qcom_smem *smem, struct smem_partition *part, unsigned item, @@ -724,7 +735,7 @@ EXPORT_SYMBOL_GPL(qcom_smem_get_free_space); static bool addr_in_range(void __iomem *base, size_t size, void *addr) { - return base && (addr >= base && addr < base + size); + return base && ((void __iomem *)addr >= base && (void __iomem *)addr < base + size); } /** @@ -1059,7 +1070,6 @@ static int qcom_smem_probe(struct platform_device *pdev) struct reserved_mem *rmem; struct qcom_smem *smem; unsigned long flags; - size_t array_size; int num_regions; int hwlock_id; u32 version; @@ -1071,8 +1081,8 @@ static int qcom_smem_probe(struct platform_device *pdev) if (of_property_present(pdev->dev.of_node, "qcom,rpm-msg-ram")) num_regions++; - array_size = num_regions * sizeof(struct smem_region); - smem = devm_kzalloc(&pdev->dev, sizeof(*smem) + array_size, GFP_KERNEL); + smem = devm_kzalloc(&pdev->dev, struct_size(smem, regions, num_regions), + GFP_KERNEL); if (!smem) return -ENOMEM; diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 4d49945b3a35..497cfb720fcb 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -371,6 +371,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SDA429W) }, { qcom_board_id(SM8350) }, { qcom_board_id(QCM2290) }, + { qcom_board_id(SM7125) }, { qcom_board_id(SM6115) }, { qcom_board_id(IPQ5010) }, { qcom_board_id(IPQ5018) }, @@ -405,8 +406,8 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SA8775P) }, { qcom_board_id(QRU1000) }, { qcom_board_id(QDU1000) }, + { qcom_board_id(SM4450) }, { qcom_board_id(QDU1010) }, - { qcom_board_id(IPQ5019) }, { qcom_board_id(QRU1032) }, { qcom_board_id(QRU1052) }, { qcom_board_id(QRU1062) }, diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index a6cbeb40831b..2f0b1bfe7658 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include #include #include @@ -275,15 +273,13 @@ static int spm_dev_probe(struct platform_device *pdev) { const struct of_device_id *match_id; struct spm_driver_data *drv; - struct resource *res; void __iomem *addr; drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); if (!drv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - drv->reg_base = devm_ioremap_resource(&pdev->dev, res); + drv->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(drv->reg_base)) return PTR_ERR(drv->reg_base); diff --git a/drivers/soc/qcom/trace-rpmh.h b/drivers/soc/qcom/trace-rpmh.h index 12b676b20cb2..be6b42ecc1f8 100644 --- a/drivers/soc/qcom/trace-rpmh.h +++ b/drivers/soc/qcom/trace-rpmh.h @@ -38,14 +38,15 @@ TRACE_EVENT(rpmh_tx_done, TRACE_EVENT(rpmh_send_msg, - TP_PROTO(struct rsc_drv *d, int m, int n, u32 h, + TP_PROTO(struct rsc_drv *d, int m, enum rpmh_state state, int n, u32 h, const struct tcs_cmd *c), - TP_ARGS(d, m, n, h, c), + TP_ARGS(d, m, state, n, h, c), TP_STRUCT__entry( __string(name, d->name) __field(int, m) + __field(u32, state) __field(int, n) __field(u32, hdr) __field(u32, addr) @@ -56,6 +57,7 @@ TRACE_EVENT(rpmh_send_msg, TP_fast_assign( __assign_str(name, d->name); __entry->m = m; + __entry->state = state; __entry->n = n; __entry->hdr = h; __entry->addr = c->addr; @@ -63,8 +65,14 @@ TRACE_EVENT(rpmh_send_msg, __entry->wait = c->wait; ), - TP_printk("%s: send-msg: tcs(m): %d cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d", - __get_str(name), __entry->m, __entry->n, __entry->hdr, + TP_printk("%s: tcs(m): %d [%s] cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d", + __get_str(name), __entry->m, + __print_symbolic(__entry->state, + { RPMH_SLEEP_STATE, "sleep" }, + { RPMH_WAKE_ONLY_STATE, "wake" }, + { RPMH_ACTIVE_ONLY_STATE, "active" }), + __entry->n, + __entry->hdr, __entry->addr, __entry->data, __entry->wait) ); diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index 2a06d631e415..ad9942412c58 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c index 15a3970e3509..d768c5a70174 100644 --- a/drivers/soc/rockchip/grf.c +++ b/drivers/soc/rockchip/grf.c @@ -121,6 +121,17 @@ static const struct rockchip_grf_info rk3566_pipegrf __initconst = { .num_values = ARRAY_SIZE(rk3566_defaults), }; +#define RK3588_GRF_SOC_CON6 0x0318 + +static const struct rockchip_grf_value rk3588_defaults[] __initconst = { + { "jtag switching", RK3588_GRF_SOC_CON6, HIWORD_UPDATE(0, 1, 14) }, +}; + +static const struct rockchip_grf_info rk3588_sysgrf __initconst = { + .values = rk3588_defaults, + .num_values = ARRAY_SIZE(rk3588_defaults), +}; + static const struct of_device_id rockchip_grf_dt_match[] __initconst = { { @@ -147,6 +158,9 @@ static const struct of_device_id rockchip_grf_dt_match[] __initconst = { }, { .compatible = "rockchip,rk3566-pipe-grf", .data = (void *)&rk3566_pipegrf, + }, { + .compatible = "rockchip,rk3588-sys-grf", + .data = (void *)&rk3588_sysgrf, }, { /* sentinel */ }, }; diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index 0fb3631e7346..7ba45c4aff97 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index 5b2664da9853..250537d7cfd6 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -7,9 +7,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 4c4864cd2342..4458b2e0562b 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/soc/tegra/cbb/tegra-cbb.c b/drivers/soc/tegra/cbb/tegra-cbb.c index bd96204a68ee..84ab46c9d9f5 100644 --- a/drivers/soc/tegra/cbb/tegra-cbb.c +++ b/drivers/soc/tegra/cbb/tegra-cbb.c @@ -7,13 +7,9 @@ #include #include #include -#include -#include #include #include #include -#include -#include #include #include #include @@ -126,20 +122,16 @@ int tegra_cbb_get_irq(struct platform_device *pdev, unsigned int *nonsec_irq, if (num_intr == 2) { irq = platform_get_irq(pdev, index); - if (irq <= 0) { - dev_err(&pdev->dev, "failed to get non-secure IRQ: %d\n", irq); + if (irq <= 0) return -ENOENT; - } *nonsec_irq = irq; index++; } irq = platform_get_irq(pdev, index); - if (irq <= 0) { - dev_err(&pdev->dev, "failed to get secure IRQ: %d\n", irq); + if (irq <= 0) return -ENOENT; - } *sec_irq = irq; diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c index 54d7ce05c636..cf6886f362d3 100644 --- a/drivers/soc/tegra/cbb/tegra194-cbb.c +++ b/drivers/soc/tegra/cbb/tegra194-cbb.c @@ -15,12 +15,10 @@ #include #include #include -#include +#include #include #include #include -#include -#include #include #include #include diff --git a/drivers/soc/tegra/cbb/tegra234-cbb.c b/drivers/soc/tegra/cbb/tegra234-cbb.c index 5d16161b2566..5cf0e8c34164 100644 --- a/drivers/soc/tegra/cbb/tegra234-cbb.c +++ b/drivers/soc/tegra/cbb/tegra234-cbb.c @@ -16,12 +16,9 @@ #include #include #include -#include #include #include #include -#include -#include #include #include #include diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index d7a37f5d4527..a2c28f493a75 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -125,13 +125,10 @@ static int tegra_fuse_probe(struct platform_device *pdev) return err; /* take over the memory region from the early initialization */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fuse->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(fuse->base)) + return PTR_ERR(fuse->base); fuse->phys = res->start; - fuse->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(fuse->base)) { - err = PTR_ERR(fuse->base); - return err; - } fuse->clk = devm_clk_get(&pdev->dev, "fuse"); if (IS_ERR(fuse->clk)) { diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 12503f563e36..fdecf7b7c246 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index c759fb7c8adc..e94d46372a63 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -10,8 +10,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index eb0a1d924526..da970f3dbf35 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -4,13 +4,13 @@ */ #include +#include #include #include #include -#include -#include #include +#include #include "fuse.h" diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c index 8f131368a758..148f54d9691d 100644 --- a/drivers/soc/ti/k3-ringacc.c +++ b/drivers/soc/ti/k3-ringacc.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -125,6 +124,7 @@ struct k3_ring_ops { * @occ: Occupancy * @windex: Write index * @rindex: Read index + * @tdown_complete: Tear down complete state */ struct k3_ring_state { u32 free; @@ -192,7 +192,7 @@ struct k3_ringacc_ops { * @num_rings: number of ring in RA * @rings_inuse: bitfield for ring usage tracking * @rm_gp_range: general purpose rings range from tisci - * @dma_ring_reset_quirk: DMA reset w/a enable + * @dma_ring_reset_quirk: DMA reset workaround enable * @num_proxies: number of RA proxies * @proxy_inuse: bitfield for proxy usage tracking * @rings: array of rings descriptors (struct @k3_ring) @@ -229,9 +229,9 @@ struct k3_ringacc { }; /** - * struct k3_ringacc - Rings accelerator SoC data + * struct k3_ringacc_soc_data - Rings accelerator SoC data * - * @dma_ring_reset_quirk: DMA reset w/a enable + * @dma_ring_reset_quirk: DMA reset workaround enable */ struct k3_ringacc_soc_data { unsigned dma_ring_reset_quirk:1; @@ -1368,15 +1368,12 @@ static int k3_ringacc_init(struct platform_device *pdev, const struct soc_device_attribute *soc; void __iomem *base_fifo, *base_rt; struct device *dev = &pdev->dev; - struct resource *res; int ret, i; dev->msi.domain = of_msi_get_domain(dev, dev->of_node, DOMAIN_BUS_TI_SCI_INTA_MSI); - if (!dev->msi.domain) { - dev_err(dev, "Failed to get MSI domain\n"); + if (!dev->msi.domain) return -EPROBE_DEFER; - } ret = k3_ringacc_probe_dt(ringacc); if (ret) @@ -1389,24 +1386,20 @@ static int k3_ringacc_init(struct platform_device *pdev, ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt"); - base_rt = devm_ioremap_resource(dev, res); + base_rt = devm_platform_ioremap_resource_byname(pdev, "rt"); if (IS_ERR(base_rt)) return PTR_ERR(base_rt); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fifos"); - base_fifo = devm_ioremap_resource(dev, res); + base_fifo = devm_platform_ioremap_resource_byname(pdev, "fifos"); if (IS_ERR(base_fifo)) return PTR_ERR(base_fifo); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "proxy_gcfg"); - ringacc->proxy_gcfg = devm_ioremap_resource(dev, res); + ringacc->proxy_gcfg = devm_platform_ioremap_resource_byname(pdev, "proxy_gcfg"); if (IS_ERR(ringacc->proxy_gcfg)) return PTR_ERR(ringacc->proxy_gcfg); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "proxy_target"); - ringacc->proxy_target_base = devm_ioremap_resource(dev, res); + ringacc->proxy_target_base = devm_platform_ioremap_resource_byname(pdev, + "proxy_target"); if (IS_ERR(ringacc->proxy_target_base)) return PTR_ERR(ringacc->proxy_target_base); @@ -1473,7 +1466,6 @@ struct k3_ringacc *k3_ringacc_dmarings_init(struct platform_device *pdev, struct device *dev = &pdev->dev; struct k3_ringacc *ringacc; void __iomem *base_rt; - struct resource *res; int i; ringacc = devm_kzalloc(dev, sizeof(*ringacc), GFP_KERNEL); @@ -1488,8 +1480,7 @@ struct k3_ringacc *k3_ringacc_dmarings_init(struct platform_device *pdev, mutex_init(&ringacc->req_lock); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ringrt"); - base_rt = devm_ioremap_resource(dev, res); + base_rt = devm_platform_ioremap_resource_byname(pdev, "ringrt"); if (IS_ERR(base_rt)) return ERR_CAST(base_rt); diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c index ad97e08a25f6..6ea9b8c7d335 100644 --- a/drivers/soc/ti/k3-socinfo.c +++ b/drivers/soc/ti/k3-socinfo.c @@ -45,6 +45,7 @@ static const struct k3_soc_id { { 0xBB7E, "AM62X" }, { 0xBB80, "J784S4" }, { 0xBB8D, "AM62AX" }, + { 0xBB9D, "AM62PX" }, }; static int diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index 7fdefee1ed87..f49f8492dde5 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -14,8 +14,10 @@ #include #include #include +#include #include -#include +#include +#include #include #include #include diff --git a/drivers/soc/ti/ti_sci_inta_msi.c b/drivers/soc/ti/ti_sci_inta_msi.c index b9251e1d9a5c..c36364522157 100644 --- a/drivers/soc/ti/ti_sci_inta_msi.c +++ b/drivers/soc/ti/ti_sci_inta_msi.c @@ -9,9 +9,10 @@ #include #include #include +#include #include -#include #include +#include #include #include diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c index f9d9b82b562d..86a048a10a13 100644 --- a/drivers/soc/xilinx/xlnx_event_manager.c +++ b/drivers/soc/xilinx/xlnx_event_manager.c @@ -666,7 +666,7 @@ static int xlnx_event_manager_probe(struct platform_device *pdev) return ret; } -static int xlnx_event_manager_remove(struct platform_device *pdev) +static void xlnx_event_manager_remove(struct platform_device *pdev) { int i; struct registered_event_data *eve_data; @@ -691,13 +691,11 @@ static int xlnx_event_manager_remove(struct platform_device *pdev) xlnx_event_cleanup_sgi(pdev); event_manager_availability = -EACCES; - - return ret; } static struct platform_driver xlnx_event_manager_driver = { .probe = xlnx_event_manager_probe, - .remove = xlnx_event_manager_remove, + .remove_new = xlnx_event_manager_remove, .driver = { .name = "xlnx_event_manager", }, diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 641dcc958911..c2c819701eec 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -242,8 +243,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev) } } else if (of_property_present(pdev->dev.of_node, "interrupts")) { irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -ENXIO; + if (irq < 0) + return irq; ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, zynqmp_pm_isr, diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h index bcbe9ee2cdaf..be12e1dd1f38 100644 --- a/include/dt-bindings/arm/qcom,ids.h +++ b/include/dt-bindings/arm/qcom,ids.h @@ -215,6 +215,7 @@ #define QCOM_ID_SDA429W 437 #define QCOM_ID_SM8350 439 #define QCOM_ID_QCM2290 441 +#define QCOM_ID_SM7125 443 #define QCOM_ID_SM6115 444 #define QCOM_ID_IPQ5010 446 #define QCOM_ID_IPQ5018 447 @@ -249,8 +250,8 @@ #define QCOM_ID_SA8775P 534 #define QCOM_ID_QRU1000 539 #define QCOM_ID_QDU1000 545 +#define QCOM_ID_SM4450 568 #define QCOM_ID_QDU1010 587 -#define QCOM_ID_IPQ5019 569 #define QCOM_ID_QRU1032 588 #define QCOM_ID_QRU1052 589 #define QCOM_ID_QRU1062 590 diff --git a/include/dt-bindings/firmware/qcom,scm.h b/include/dt-bindings/firmware/qcom,scm.h index d1dc09e72923..6de8b08e1e79 100644 --- a/include/dt-bindings/firmware/qcom,scm.h +++ b/include/dt-bindings/firmware/qcom,scm.h @@ -2,17 +2,38 @@ /* * Copyright (c) 2010-2015, 2018-2019 The Linux Foundation. All rights reserved. * Copyright (C) 2015 Linaro Ltd. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _DT_BINDINGS_FIRMWARE_QCOM_SCM_H #define _DT_BINDINGS_FIRMWARE_QCOM_SCM_H +#define QCOM_SCM_VMID_TZ 0x1 #define QCOM_SCM_VMID_HLOS 0x3 #define QCOM_SCM_VMID_SSC_Q6 0x5 #define QCOM_SCM_VMID_ADSP_Q6 0x6 +#define QCOM_SCM_VMID_CP_TOUCH 0x8 +#define QCOM_SCM_VMID_CP_BITSTREAM 0x9 +#define QCOM_SCM_VMID_CP_PIXEL 0xA +#define QCOM_SCM_VMID_CP_NON_PIXEL 0xB +#define QCOM_SCM_VMID_CP_CAMERA 0xD +#define QCOM_SCM_VMID_HLOS_FREE 0xE #define QCOM_SCM_VMID_MSS_MSA 0xF +#define QCOM_SCM_VMID_MSS_NONMSA 0x10 +#define QCOM_SCM_VMID_CP_SEC_DISPLAY 0x11 +#define QCOM_SCM_VMID_CP_APP 0x12 +#define QCOM_SCM_VMID_LPASS 0x16 #define QCOM_SCM_VMID_WLAN 0x18 #define QCOM_SCM_VMID_WLAN_CE 0x19 +#define QCOM_SCM_VMID_CP_SPSS_SP 0x1A +#define QCOM_SCM_VMID_CP_CAMERA_PREVIEW 0x1D +#define QCOM_SCM_VMID_CDSP 0x1E +#define QCOM_SCM_VMID_CP_SPSS_SP_SHARED 0x22 +#define QCOM_SCM_VMID_CP_SPSS_HLOS_SHARED 0x24 +#define QCOM_SCM_VMID_ADSP_HEAP 0x25 +#define QCOM_SCM_VMID_CP_CDSP 0x2A #define QCOM_SCM_VMID_NAV 0x2B +#define QCOM_SCM_VMID_TVM 0x2D +#define QCOM_SCM_VMID_OEMVM 0x31 #endif diff --git a/include/dt-bindings/power/amlogic,c3-pwrc.h b/include/dt-bindings/power/amlogic,c3-pwrc.h new file mode 100644 index 000000000000..1d98a25b08a4 --- /dev/null +++ b/include/dt-bindings/power/amlogic,c3-pwrc.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: (GPL-2.0+ or MIT) */ +/* + * Copyright (c) 2023 Amlogic, Inc. + * Author: hongyu chen1 + */ +#ifndef _DT_BINDINGS_AMLOGIC_C3_POWER_H +#define _DT_BINDINGS_AMLOGIC_C3_POWER_H + +#define PWRC_C3_NNA_ID 0 +#define PWRC_C3_AUDIO_ID 1 +#define PWRC_C3_RESV_SEC_ID 2 +#define PWRC_C3_SDIOA_ID 3 +#define PWRC_C3_EMMC_ID 4 +#define PWRC_C3_USB_COMB_ID 5 +#define PWRC_C3_SDCARD_ID 6 +#define PWRC_C3_ETH_ID 7 +#define PWRC_C3_RESV0_ID 8 +#define PWRC_C3_GE2D_ID 9 +#define PWRC_C3_CVE_ID 10 +#define PWRC_C3_GDC_WRAP_ID 11 +#define PWRC_C3_ISP_TOP_ID 12 +#define PWRC_C3_MIPI_ISP_WRAP_ID 13 +#define PWRC_C3_VCODEC_ID 14 + +#endif diff --git a/include/dt-bindings/power/qcom,rpmhpd.h b/include/dt-bindings/power/qcom,rpmhpd.h new file mode 100644 index 000000000000..7c201a66bc69 --- /dev/null +++ b/include/dt-bindings/power/qcom,rpmhpd.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _DT_BINDINGS_POWER_QCOM_RPMHPD_H +#define _DT_BINDINGS_POWER_QCOM_RPMHPD_H + +/* Generic RPMH Power Domain Indexes */ +#define RPMHPD_CX 0 +#define RPMHPD_CX_AO 1 +#define RPMHPD_EBI 2 +#define RPMHPD_GFX 3 +#define RPMHPD_LCX 4 +#define RPMHPD_LMX 5 +#define RPMHPD_MMCX 6 +#define RPMHPD_MMCX_AO 7 +#define RPMHPD_MX 8 +#define RPMHPD_MX_AO 9 +#define RPMHPD_MXC 10 +#define RPMHPD_MXC_AO 11 +#define RPMHPD_MSS 12 +#define RPMHPD_NSP 13 +#define RPMHPD_NSP0 14 +#define RPMHPD_NSP1 15 +#define RPMHPD_QPHY 16 +#define RPMHPD_DDR 17 +#define RPMHPD_XO 18 + +#endif diff --git a/include/linux/firmware/imx/sci.h b/include/linux/firmware/imx/sci.h index 5cc63fe7e84d..df17196df5ff 100644 --- a/include/linux/firmware/imx/sci.h +++ b/include/linux/firmware/imx/sci.h @@ -21,31 +21,37 @@ int imx_scu_enable_general_irq_channel(struct device *dev); int imx_scu_irq_register_notifier(struct notifier_block *nb); int imx_scu_irq_unregister_notifier(struct notifier_block *nb); int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable); +int imx_scu_irq_get_status(u8 group, u32 *irq_status); int imx_scu_soc_init(struct device *dev); #else static inline int imx_scu_soc_init(struct device *dev) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int imx_scu_enable_general_irq_channel(struct device *dev) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int imx_scu_irq_register_notifier(struct notifier_block *nb) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int imx_scu_irq_unregister_notifier(struct notifier_block *nb) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) { - return -ENOTSUPP; + return -EOPNOTSUPP; +} + +static inline int imx_scu_irq_get_status(u8 group, u32 *irq_status) +{ + return -EOPNOTSUPP; } #endif #endif /* _SC_SCI_H */ diff --git a/include/linux/firmware/qcom/qcom_scm.h b/include/linux/firmware/qcom/qcom_scm.h index 250ea4efb7cb..0c091a3f6d49 100644 --- a/include/linux/firmware/qcom/qcom_scm.h +++ b/include/linux/firmware/qcom/qcom_scm.h @@ -75,7 +75,7 @@ struct qcom_scm_pas_metadata { extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size, struct qcom_scm_pas_metadata *ctx); -void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); +extern void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx); extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size); extern int qcom_scm_pas_auth_and_reset(u32 peripheral); diff --git a/include/linux/soc/qcom/qcom_aoss.h b/include/linux/soc/qcom/qcom_aoss.h index 3c2a82e606f8..7361ca028752 100644 --- a/include/linux/soc/qcom/qcom_aoss.h +++ b/include/linux/soc/qcom/qcom_aoss.h @@ -13,13 +13,13 @@ struct qmp; #if IS_ENABLED(CONFIG_QCOM_AOSS_QMP) -int qmp_send(struct qmp *qmp, const void *data, size_t len); +int qmp_send(struct qmp *qmp, const char *fmt, ...); struct qmp *qmp_get(struct device *dev); void qmp_put(struct qmp *qmp); #else -static inline int qmp_send(struct qmp *qmp, const void *data, size_t len) +static inline int qmp_send(struct qmp *qmp, const char *fmt, ...) { return -ENODEV; } diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h index 223db6a9c733..a36a3b9d4929 100644 --- a/include/linux/soc/qcom/smem.h +++ b/include/linux/soc/qcom/smem.h @@ -4,6 +4,7 @@ #define QCOM_SMEM_HOST_ANY -1 +bool qcom_smem_is_available(void); int qcom_smem_alloc(unsigned host, unsigned item, size_t size); void *qcom_smem_get(unsigned host, unsigned item, size_t *size);