diff --git a/Documentation/ABI/testing/sysfs-driver-aspeed-uart-routing b/Documentation/ABI/testing/sysfs-driver-aspeed-uart-routing new file mode 100644 index 000000000000..b363827da437 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-aspeed-uart-routing @@ -0,0 +1,27 @@ +What: /sys/bus/platform/drivers/aspeed-uart-routing/*/uart* +Date: September 2021 +Contact: Oskar Senft + Chia-Wei Wang +Description: Selects the RX source of the UARTx device. + + When read, each file shows the list of available options with currently + selected option marked by brackets "[]". The list of available options + depends on the selected file. + + e.g. + cat /sys/bus/platform/drivers/aspeed-uart-routing/*.uart_routing/uart1 + [io1] io2 io3 io4 uart2 uart3 uart4 io6 + + In this case, UART1 gets its input from IO1 (physical serial port 1). + +Users: OpenBMC. Proposed changes should be mailed to + openbmc@lists.ozlabs.org + +What: /sys/bus/platform/drivers/aspeed-uart-routing/*/io* +Date: September 2021 +Contact: Oskar Senft + Chia-Wei Wang +Description: Selects the RX source of IOx serial port. The current selection + will be marked by brackets "[]". +Users: OpenBMC. Proposed changes should be mailed to + openbmc@lists.ozlabs.org diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index 49bbaf1a3ea6..f2ab6423b4af 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -211,6 +211,9 @@ properties: - qcom,gcc-msm8660 - qcom,kpss-acc-v1 - qcom,kpss-acc-v2 + - qcom,msm8226-smp + # Only valid on ARM 32-bit, see above for ARM v8 64-bit + - qcom,msm8916-smp - renesas,apmu - renesas,r9a06g032-smp - rockchip,rk3036-smp @@ -297,7 +300,8 @@ properties: Specifies the ACC* node associated with this CPU. Required for systems that have an "enable-method" property - value of "qcom,kpss-acc-v1" or "qcom,kpss-acc-v2" + value of "qcom,kpss-acc-v1", "qcom,kpss-acc-v2", "qcom,msm8226-smp" or + "qcom,msm8916-smp". * arm/msm/qcom,kpss-acc.txt diff --git a/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.yaml b/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.yaml index f99c0c6df21b..bfc352a2fdd6 100644 --- a/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.yaml +++ b/Documentation/devicetree/bindings/arm/samsung/exynos-chipid.yaml @@ -11,8 +11,9 @@ maintainers: properties: compatible: - items: - - const: samsung,exynos4210-chipid + enum: + - samsung,exynos4210-chipid + - samsung,exynos850-chipid reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/ddr/lpddr2.txt b/Documentation/devicetree/bindings/ddr/lpddr2.txt deleted file mode 100644 index ddd40121e6f6..000000000000 --- a/Documentation/devicetree/bindings/ddr/lpddr2.txt +++ /dev/null @@ -1,102 +0,0 @@ -* LPDDR2 SDRAM memories compliant to JEDEC JESD209-2 - -Required properties: -- compatible : Should be one of - "jedec,lpddr2-nvm", "jedec,lpddr2-s2", - "jedec,lpddr2-s4" - - "ti,jedec-lpddr2-s2" should be listed if the memory part is LPDDR2-S2 type - - "ti,jedec-lpddr2-s4" should be listed if the memory part is LPDDR2-S4 type - - "ti,jedec-lpddr2-nvm" should be listed if the memory part is LPDDR2-NVM type - -- density : representing density in Mb (Mega bits) - -- io-width : representing bus width. Possible values are 8, 16, and 32 - -Optional properties: - -The following optional properties represent the minimum value of some AC -timing parameters of the DDR device in terms of number of clock cycles. -These values shall be obtained from the device data-sheet. -- tRRD-min-tck -- tWTR-min-tck -- tXP-min-tck -- tRTP-min-tck -- tCKE-min-tck -- tRPab-min-tck -- tRCD-min-tck -- tWR-min-tck -- tRASmin-min-tck -- tCKESR-min-tck -- tFAW-min-tck - -Child nodes: -- The lpddr2 node may have one or more child nodes of type "lpddr2-timings". - "lpddr2-timings" provides AC timing parameters of the device for - a given speed-bin. The user may provide the timings for as many - speed-bins as is required. Please see Documentation/devicetree/ - bindings/ddr/lpddr2-timings.txt for more information on "lpddr2-timings" - -Example: - -elpida_ECB240ABACN : lpddr2 { - compatible = "Elpida,ECB240ABACN","jedec,lpddr2-s4"; - density = <2048>; - io-width = <32>; - - tRPab-min-tck = <3>; - tRCD-min-tck = <3>; - tWR-min-tck = <3>; - tRASmin-min-tck = <3>; - tRRD-min-tck = <2>; - tWTR-min-tck = <2>; - tXP-min-tck = <2>; - tRTP-min-tck = <2>; - tCKE-min-tck = <3>; - tCKESR-min-tck = <3>; - tFAW-min-tck = <8>; - - timings_elpida_ECB240ABACN_400mhz: lpddr2-timings@0 { - compatible = "jedec,lpddr2-timings"; - min-freq = <10000000>; - max-freq = <400000000>; - tRPab = <21000>; - tRCD = <18000>; - tWR = <15000>; - tRAS-min = <42000>; - tRRD = <10000>; - tWTR = <7500>; - tXP = <7500>; - tRTP = <7500>; - tCKESR = <15000>; - tDQSCK-max = <5500>; - tFAW = <50000>; - tZQCS = <90000>; - tZQCL = <360000>; - tZQinit = <1000000>; - tRAS-max-ns = <70000>; - }; - - timings_elpida_ECB240ABACN_200mhz: lpddr2-timings@1 { - compatible = "jedec,lpddr2-timings"; - min-freq = <10000000>; - max-freq = <200000000>; - tRPab = <21000>; - tRCD = <18000>; - tWR = <15000>; - tRAS-min = <42000>; - tRRD = <10000>; - tWTR = <10000>; - tXP = <7500>; - tRTP = <7500>; - tCKESR = <15000>; - tDQSCK-max = <5500>; - tFAW = <50000>; - tZQCS = <90000>; - tZQCL = <360000>; - tZQinit = <1000000>; - tRAS-max-ns = <70000>; - }; - -} diff --git a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml index b36d74c1da7c..63e585f48789 100644 --- a/Documentation/devicetree/bindings/display/msm/dp-controller.yaml +++ b/Documentation/devicetree/bindings/display/msm/dp-controller.yaml @@ -102,7 +102,6 @@ examples: - | #include #include - #include #include displayport-controller@ae90000 { diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt index a7333ad938d2..d7e3cda8924e 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt @@ -13,8 +13,10 @@ Required properties: * "qcom,scm-ipq806x" * "qcom,scm-ipq8074" * "qcom,scm-mdm9607" + * "qcom,scm-msm8226" * "qcom,scm-msm8660" * "qcom,scm-msm8916" + * "qcom,scm-msm8953" * "qcom,scm-msm8960" * "qcom,scm-msm8974" * "qcom,scm-msm8994" @@ -33,7 +35,7 @@ Required properties: * core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660" and "qcom,scm-msm8960" * core, iface and bus clocks required for "qcom,scm-apq8084", - "qcom,scm-msm8916" and "qcom,scm-msm8974" + "qcom,scm-msm8916", "qcom,scm-msm8953" and "qcom,scm-msm8974" - clock-names: Must contain "core" for the core clock, "iface" for the interface clock and "bus" for the bus clock per the requirements of the compatible. - qcom,dload-mode: phandle to the TCSR hardware block and offset of the diff --git a/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr2.yaml b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr2.yaml new file mode 100644 index 000000000000..25ed0266f6dd --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/ddr/jedec,lpddr2.yaml @@ -0,0 +1,223 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/memory-controllers/ddr/jedec,lpddr2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LPDDR2 SDRAM compliant to JEDEC JESD209-2 + +maintainers: + - Krzysztof Kozlowski + +properties: + compatible: + oneOf: + - items: + - enum: + - elpida,ECB240ABACN + - elpida,B8132B2PB-6D-F + - enum: + - jedec,lpddr2-s4 + - items: + - enum: + - jedec,lpddr2-s2 + - items: + - enum: + - jedec,lpddr2-nvm + + revision-id1: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 255 + description: | + Revision 1 value of SDRAM chip. Obtained from device datasheet. + + revision-id2: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 255 + description: | + Revision 2 value of SDRAM chip. Obtained from device datasheet. + + density: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + Density in megabits of SDRAM chip. Obtained from device datasheet. + enum: + - 64 + - 128 + - 256 + - 512 + - 1024 + - 2048 + - 4096 + - 8192 + - 16384 + - 32768 + + io-width: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + IO bus width in bits of SDRAM chip. Obtained from device datasheet. + enum: + - 32 + - 16 + - 8 + + tRRD-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + Active bank a to active bank b in terms of number of clock cycles. + Obtained from device datasheet. + + tWTR-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + Internal WRITE-to-READ command delay in terms of number of clock cycles. + Obtained from device datasheet. + + tXP-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + Exit power-down to next valid command delay in terms of number of clock + cycles. Obtained from device datasheet. + + tRTP-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + Internal READ to PRECHARGE command delay in terms of number of clock + cycles. Obtained from device datasheet. + + tCKE-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + CKE minimum pulse width (HIGH and LOW pulse width) in terms of number + of clock cycles. Obtained from device datasheet. + + tRPab-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + Row precharge time (all banks) in terms of number of clock cycles. + Obtained from device datasheet. + + tRCD-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + RAS-to-CAS delay in terms of number of clock cycles. Obtained from + device datasheet. + + tWR-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + WRITE recovery time in terms of number of clock cycles. Obtained from + device datasheet. + + tRASmin-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + Row active time in terms of number of clock cycles. Obtained from device + datasheet. + + tCKESR-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + CKE minimum pulse width during SELF REFRESH (low pulse width during + SELF REFRESH) in terms of number of clock cycles. Obtained from device + datasheet. + + tFAW-min-tck: + $ref: /schemas/types.yaml#/definitions/uint32 + maximum: 16 + description: | + Four-bank activate window in terms of number of clock cycles. Obtained + from device datasheet. + +patternProperties: + "^lpddr2-timings": + type: object + description: | + The lpddr2 node may have one or more child nodes of type "lpddr2-timings". + "lpddr2-timings" provides AC timing parameters of the device for + a given speed-bin. The user may provide the timings for as many + speed-bins as is required. Please see Documentation/devicetree/ + bindings/memory-controllers/ddr/lpddr2-timings.txt for more information + on "lpddr2-timings". + +required: + - compatible + - density + - io-width + +additionalProperties: false + +examples: + - | + elpida_ECB240ABACN: lpddr2 { + compatible = "elpida,ECB240ABACN", "jedec,lpddr2-s4"; + density = <2048>; + io-width = <32>; + revision-id1 = <1>; + revision-id2 = <0>; + + tRPab-min-tck = <3>; + tRCD-min-tck = <3>; + tWR-min-tck = <3>; + tRASmin-min-tck = <3>; + tRRD-min-tck = <2>; + tWTR-min-tck = <2>; + tXP-min-tck = <2>; + tRTP-min-tck = <2>; + tCKE-min-tck = <3>; + tCKESR-min-tck = <3>; + tFAW-min-tck = <8>; + + timings_elpida_ECB240ABACN_400mhz: lpddr2-timings0 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <400000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <7500>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + }; + + timings_elpida_ECB240ABACN_200mhz: lpddr2-timings1 { + compatible = "jedec,lpddr2-timings"; + min-freq = <10000000>; + max-freq = <200000000>; + tRPab = <21000>; + tRCD = <18000>; + tWR = <15000>; + tRAS-min = <42000>; + tRRD = <10000>; + tWTR = <10000>; + tXP = <7500>; + tRTP = <7500>; + tCKESR = <15000>; + tDQSCK-max = <5500>; + tFAW = <50000>; + tZQCS = <90000>; + tZQCL = <360000>; + tZQinit = <1000000>; + tRAS-max-ns = <70000>; + }; + }; diff --git a/Documentation/devicetree/bindings/ddr/lpddr2-timings.txt b/Documentation/devicetree/bindings/memory-controllers/ddr/lpddr2-timings.txt similarity index 100% rename from Documentation/devicetree/bindings/ddr/lpddr2-timings.txt rename to Documentation/devicetree/bindings/memory-controllers/ddr/lpddr2-timings.txt diff --git a/Documentation/devicetree/bindings/ddr/lpddr3-timings.txt b/Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3-timings.txt similarity index 100% rename from Documentation/devicetree/bindings/ddr/lpddr3-timings.txt rename to Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3-timings.txt diff --git a/Documentation/devicetree/bindings/ddr/lpddr3.txt b/Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3.txt similarity index 94% rename from Documentation/devicetree/bindings/ddr/lpddr3.txt rename to Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3.txt index b221e653d384..031af5fb0379 100644 --- a/Documentation/devicetree/bindings/ddr/lpddr3.txt +++ b/Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3.txt @@ -43,8 +43,9 @@ These values shall be obtained from the device data-sheet. Child nodes: - The lpddr3 node may have one or more child nodes of type "lpddr3-timings". "lpddr3-timings" provides AC timing parameters of the device for - a given speed-bin. Please see Documentation/devicetree/ - bindings/ddr/lpddr3-timings.txt for more information on "lpddr3-timings" + a given speed-bin. Please see + Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3-timings.txt + for more information on "lpddr3-timings" Example: diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml index e87e4382807c..3a82b0b27fa0 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-common.yaml @@ -16,7 +16,7 @@ description: | MediaTek SMI have two generations of HW architecture, here is the list which generation the SoCs use: generation 1: mt2701 and mt7623. - generation 2: mt2712, mt6779, mt8167, mt8173, mt8183 and mt8192. + generation 2: mt2712, mt6779, mt8167, mt8173, mt8183, mt8192 and mt8195. There's slight differences between the two SMI, for generation 2, the register which control the iommu port is at each larb's register base. But @@ -36,6 +36,9 @@ properties: - mediatek,mt8173-smi-common - mediatek,mt8183-smi-common - mediatek,mt8192-smi-common + - mediatek,mt8195-smi-common-vdo + - mediatek,mt8195-smi-common-vpp + - mediatek,mt8195-smi-sub-common - description: for mt7623 items: @@ -65,6 +68,10 @@ properties: minItems: 2 maxItems: 4 + mediatek,smi: + $ref: /schemas/types.yaml#/definitions/phandle + description: a phandle to the smi-common node above. Only for sub-common. + required: - compatible - reg @@ -91,6 +98,29 @@ allOf: - const: smi - const: async + - if: # only for sub common + properties: + compatible: + contains: + enum: + - mediatek,mt8195-smi-sub-common + then: + required: + - mediatek,smi + properties: + clock: + items: + minItems: 3 + maxItems: 3 + clock-names: + items: + - const: apb + - const: smi + - const: gals0 + else: + properties: + mediatek,smi: false + - if: # for gen2 HW that have gals properties: compatible: @@ -98,6 +128,8 @@ allOf: - mediatek,mt6779-smi-common - mediatek,mt8183-smi-common - mediatek,mt8192-smi-common + - mediatek,mt8195-smi-common-vdo + - mediatek,mt8195-smi-common-vpp then: properties: diff --git a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml index 2353f6cf3c80..eaeff1ada7f8 100644 --- a/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.yaml @@ -24,6 +24,7 @@ properties: - mediatek,mt8173-smi-larb - mediatek,mt8183-smi-larb - mediatek,mt8192-smi-larb + - mediatek,mt8195-smi-larb - description: for mt7623 items: @@ -74,6 +75,7 @@ allOf: compatible: enum: - mediatek,mt8183-smi-larb + - mediatek,mt8195-smi-larb then: properties: @@ -108,6 +110,7 @@ allOf: - mediatek,mt6779-smi-larb - mediatek,mt8167-smi-larb - mediatek,mt8192-smi-larb + - mediatek,mt8195-smi-larb then: required: diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.yaml b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.yaml index cac6842dc8f1..2fa44951cfde 100644 --- a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra20-emc.yaml @@ -164,12 +164,20 @@ patternProperties: "#size-cells": const: 0 + lpddr2: + $ref: "ddr/jedec,lpddr2.yaml#" + type: object + patternProperties: "^emc-table@[0-9]+$": $ref: "#/$defs/emc-table" - required: - - nvidia,ram-code + oneOf: + - required: + - nvidia,ram-code + + - required: + - lpddr2 additionalProperties: false @@ -227,4 +235,15 @@ examples: 0x00000000 0x00000000 0x00000000 0x00000000>; }; }; + + emc-tables@1 { + reg = <1>; + + lpddr2 { + compatible = "elpida,B8132B2PB-6D-F", "jedec,lpddr2-s4"; + revision-id1 = <1>; + density = <2048>; + io-width = <16>; + }; + }; }; diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml b/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml index d25072c414e4..9da80e8f2444 100644 --- a/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/renesas,rpc-if.yaml @@ -33,6 +33,7 @@ properties: - renesas,r8a77970-rpc-if # R-Car V3M - renesas,r8a77980-rpc-if # R-Car V3H - renesas,r8a77995-rpc-if # R-Car D3 + - renesas,r8a779a0-rpc-if # R-Car V3U - const: renesas,rcar-gen3-rpc-if # a generic R-Car gen3 or RZ/G2 device reg: diff --git a/Documentation/devicetree/bindings/memory-controllers/samsung,exynos5422-dmc.yaml b/Documentation/devicetree/bindings/memory-controllers/samsung,exynos5422-dmc.yaml index 6f4fd5814bf4..fe8639dcffab 100644 --- a/Documentation/devicetree/bindings/memory-controllers/samsung,exynos5422-dmc.yaml +++ b/Documentation/devicetree/bindings/memory-controllers/samsung,exynos5422-dmc.yaml @@ -51,7 +51,8 @@ properties: $ref: '/schemas/types.yaml#/definitions/phandle' description: | phandle of the connected DRAM memory device. For more information please - refer to documentation file: Documentation/devicetree/bindings/ddr/lpddr3.txt + refer to documentation file: + Documentation/devicetree/bindings/memory-controllers/ddr/lpddr3.txt operating-points-v2: true diff --git a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml index 239f37881cae..e810480e3eb7 100644 --- a/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml +++ b/Documentation/devicetree/bindings/power/qcom,rpmpd.yaml @@ -19,6 +19,7 @@ properties: - qcom,mdm9607-rpmpd - qcom,msm8916-rpmpd - qcom,msm8939-rpmpd + - qcom,msm8953-rpmpd - qcom,msm8976-rpmpd - qcom,msm8994-rpmpd - qcom,msm8996-rpmpd @@ -31,6 +32,7 @@ properties: - qcom,sdm845-rpmhpd - qcom,sdx55-rpmhpd - qcom,sm6115-rpmpd + - qcom,sm6350-rpmhpd - qcom,sm8150-rpmhpd - qcom,sm8250-rpmhpd - qcom,sm8350-rpmhpd diff --git a/Documentation/devicetree/bindings/reset/microchip,rst.yaml b/Documentation/devicetree/bindings/reset/microchip,rst.yaml index 370579aeeca1..578bfa529b16 100644 --- a/Documentation/devicetree/bindings/reset/microchip,rst.yaml +++ b/Documentation/devicetree/bindings/reset/microchip,rst.yaml @@ -20,7 +20,9 @@ properties: pattern: "^reset-controller@[0-9a-f]+$" compatible: - const: microchip,sparx5-switch-reset + enum: + - microchip,sparx5-switch-reset + - microchip,lan966x-switch-reset reg: items: diff --git a/Documentation/devicetree/bindings/reset/socionext,uniphier-glue-reset.yaml b/Documentation/devicetree/bindings/reset/socionext,uniphier-glue-reset.yaml index 29e4a900cad7..bfbd3e9b4186 100644 --- a/Documentation/devicetree/bindings/reset/socionext,uniphier-glue-reset.yaml +++ b/Documentation/devicetree/bindings/reset/socionext,uniphier-glue-reset.yaml @@ -23,6 +23,7 @@ properties: - socionext,uniphier-pxs2-usb3-reset - socionext,uniphier-ld20-usb3-reset - socionext,uniphier-pxs3-usb3-reset + - socionext,uniphier-nx1-usb3-reset - socionext,uniphier-pro4-ahci-reset - socionext,uniphier-pxs2-ahci-reset - socionext,uniphier-pxs3-ahci-reset diff --git a/Documentation/devicetree/bindings/reset/socionext,uniphier-reset.yaml b/Documentation/devicetree/bindings/reset/socionext,uniphier-reset.yaml index 4c9b0ebf6869..377a7d242323 100644 --- a/Documentation/devicetree/bindings/reset/socionext,uniphier-reset.yaml +++ b/Documentation/devicetree/bindings/reset/socionext,uniphier-reset.yaml @@ -23,6 +23,7 @@ properties: - socionext,uniphier-ld11-reset - socionext,uniphier-ld20-reset - socionext,uniphier-pxs3-reset + - socionext,uniphier-nx1-reset - description: Media I/O (MIO) reset, SD reset enum: - socionext,uniphier-ld4-mio-reset @@ -34,6 +35,7 @@ properties: - socionext,uniphier-ld11-sd-reset - socionext,uniphier-ld20-sd-reset - socionext,uniphier-pxs3-sd-reset + - socionext,uniphier-nx1-sd-reset - description: Peripheral reset enum: - socionext,uniphier-ld4-peri-reset @@ -44,6 +46,7 @@ properties: - socionext,uniphier-ld11-peri-reset - socionext,uniphier-ld20-peri-reset - socionext,uniphier-pxs3-peri-reset + - socionext,uniphier-nx1-peri-reset - description: Analog signal amplifier reset enum: - socionext,uniphier-ld11-adamv-reset diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index 93e4b737ee1b..e2e173dfada7 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -19,8 +19,7 @@ description: The AOSS side channel exposes control over a set of resources, used to control a set of debug related clocks and to affect the low power state of resources - related to the secondary subsystems. These resources are exposed as a set of - power-domains. + related to the secondary subsystems. properties: compatible: @@ -30,6 +29,7 @@ properties: - qcom,sc7280-aoss-qmp - qcom,sc8180x-aoss-qmp - qcom,sdm845-aoss-qmp + - qcom,sm6350-aoss-qmp - qcom,sm8150-aoss-qmp - qcom,sm8250-aoss-qmp - qcom,sm8350-aoss-qmp @@ -57,13 +57,6 @@ properties: description: The single clock represents the QDSS clock. - "#power-domain-cells": - const: 1 - description: | - The provided power-domains are: - CDSP state (0), LPASS state (1), modem state (2), SLPI - state (3), SPSS state (4) and Venus state (5). - required: - compatible - reg @@ -101,7 +94,6 @@ examples: mboxes = <&apss_shared 0>; #clock-cells = <0>; - #power-domain-cells = <1>; cx_cdev: cx { #cooling-cells = <2>; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml index cc3fe5ed7421..b32457c2fc0b 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.yaml @@ -34,6 +34,7 @@ properties: - qcom,rpm-ipq6018 - qcom,rpm-msm8226 - qcom,rpm-msm8916 + - qcom,rpm-msm8953 - qcom,rpm-msm8974 - qcom,rpm-msm8976 - qcom,rpm-msm8996 @@ -41,6 +42,7 @@ properties: - qcom,rpm-sdm660 - qcom,rpm-sm6115 - qcom,rpm-sm6125 + - qcom,rpm-qcm2290 - qcom,rpm-qcs404 qcom,smd-channels: @@ -57,6 +59,7 @@ if: - qcom,rpm-apq8084 - qcom,rpm-msm8916 - qcom,rpm-msm8974 + - qcom,rpm-msm8953 then: required: - qcom,smd-channels diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml index f7e17713b3d8..4149cf2b66be 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smem.yaml @@ -10,14 +10,18 @@ maintainers: - Andy Gross - Bjorn Andersson -description: | - This binding describes the Qualcomm Shared Memory Manager, used to share data - between various subsystems and OSes in Qualcomm platforms. +description: + This binding describes the Qualcomm Shared Memory Manager, a region of + reserved-memory used to share data between various subsystems and OSes in + Qualcomm platforms. properties: compatible: const: qcom,smem + reg: + maxItems: 1 + memory-region: maxItems: 1 description: handle to memory reservation for main SMEM memory region. @@ -29,11 +33,19 @@ properties: $ref: /schemas/types.yaml#/definitions/phandle description: handle to RPM message memory resource + no-map: true + required: - compatible - - memory-region - hwlocks +oneOf: + - required: + - reg + - no-map + - required: + - memory-region + additionalProperties: false examples: @@ -43,6 +55,20 @@ examples: #size-cells = <1>; ranges; + smem@fa00000 { + compatible = "qcom,smem"; + reg = <0xfa00000 0x200000>; + no-map; + + hwlocks = <&tcsr_mutex 3>; + }; + }; + - | + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + smem_region: smem@fa00000 { reg = <0xfa00000 0x200000>; no-map; diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml new file mode 100644 index 000000000000..07d2d5398345 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,spm.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/soc/qcom/qcom,spm.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm Subsystem Power Manager binding + +maintainers: + - Andy Gross + - Bjorn Andersson + +description: | + This binding describes the Qualcomm Subsystem Power Manager, used to control + the peripheral logic surrounding the application cores in Qualcomm platforms. + +properties: + compatible: + items: + - enum: + - qcom,sdm660-gold-saw2-v4.1-l2 + - qcom,sdm660-silver-saw2-v4.1-l2 + - qcom,msm8998-gold-saw2-v4.1-l2 + - qcom,msm8998-silver-saw2-v4.1-l2 + - qcom,msm8916-saw2-v3.0-cpu + - qcom,msm8226-saw2-v2.1-cpu + - qcom,msm8974-saw2-v2.1-cpu + - qcom,apq8084-saw2-v2.1-cpu + - qcom,apq8064-saw2-v1.1-cpu + - const: qcom,saw2 + + reg: + description: Base address and size of the SPM register region + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + + /* Example 1: SoC using SAW2 and kpss-acc-v2 CPUIdle */ + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "qcom,kryo"; + device_type = "cpu"; + enable-method = "qcom,kpss-acc-v2"; + qcom,saw = <&saw0>; + reg = <0x0>; + operating-points-v2 = <&cpu_opp_table>; + }; + }; + + saw0: power-manager@f9089000 { + compatible = "qcom,msm8974-saw2-v2.1-cpu", "qcom,saw2"; + reg = <0xf9089000 0x1000>; + }; + + - | + + /* + * Example 2: New-gen multi cluster SoC using SAW only for L2; + * This does not require any cpuidle driver, nor any cpu phandle. + */ + power-manager@17812000 { + compatible = "qcom,msm8998-gold-saw2-v4.1-l2", "qcom,saw2"; + reg = <0x17812000 0x1000>; + }; + + power-manager@17912000 { + compatible = "qcom,msm8998-silver-saw2-v4.1-l2", "qcom,saw2"; + reg = <0x17912000 0x1000>; + }; + +... diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml new file mode 100644 index 000000000000..99dff7d73b7e --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom-stats.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/soc/qcom/qcom-stats.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies, Inc. (QTI) Stats bindings + +maintainers: + - Maulik Shah + +description: + Always On Processor/Resource Power Manager maintains statistics of the SoC + sleep modes involving powering down of the rails and oscillator clock. + + Statistics includes SoC sleep mode type, number of times low power mode were + entered, time of last entry, time of last exit and accumulated sleep duration. + +properties: + compatible: + enum: + - qcom,rpmh-stats + - qcom,rpm-stats + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + # Example of rpmh sleep stats + - | + sram@c3f0000 { + compatible = "qcom,rpmh-stats"; + reg = <0x0c3f0000 0x400>; + }; + # Example of rpm sleep stats + - | + sram@4690000 { + compatible = "qcom,rpm-stats"; + reg = <0x04690000 0x10000>; + }; +... diff --git a/Documentation/devicetree/bindings/sram/sram.yaml b/Documentation/devicetree/bindings/sram/sram.yaml index 939cf2418445..d4e418b6a1c1 100644 --- a/Documentation/devicetree/bindings/sram/sram.yaml +++ b/Documentation/devicetree/bindings/sram/sram.yaml @@ -31,6 +31,7 @@ properties: - amlogic,meson-gxbb-sram - arm,juno-sram-ns - atmel,sama5d2-securam + - qcom,rpm-msg-ram - rockchip,rk3288-pmu-sram reg: @@ -135,7 +136,9 @@ if: properties: compatible: contains: - const: rockchip,rk3288-pmu-sram + enum: + - qcom,rpm-msg-ram + - rockchip,rk3288-pmu-sram else: required: diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 518487ec65e5..3c28347f873e 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -359,6 +359,8 @@ patternProperties: description: Shenzhen Elida Technology Co., Ltd. "^elimo,.*": description: Elimo Engineering Ltd. + "^elpida,.*": + description: Elpida Memory, Inc. "^embest,.*": description: Shenzhen Embest Technology Co., Ltd. "^emlid,.*": diff --git a/MAINTAINERS b/MAINTAINERS index 83321332f63e..8f7288596157 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11992,6 +11992,14 @@ M: Sean Wang S: Maintained F: drivers/char/hw_random/mtk-rng.c +MEDIATEK SMI DRIVER +M: Yong Wu +L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) +S: Supported +F: Documentation/devicetree/bindings/memory-controllers/mediatek,smi* +F: drivers/memory/mtk-smi.c +F: include/soc/mediatek/smi.h + MEDIATEK SWITCH DRIVER M: Sean Wang M: Landen Chao diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index d96209b20736..f0f9e8bec83a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -351,7 +351,7 @@ config ARCH_EP93XX select CLKSRC_MMIO select CPU_ARM920T select GPIOLIB - select HAVE_LEGACY_CLK + select COMMON_CLK help This enables support for the Cirrus EP93xx series of CPUs. @@ -480,7 +480,6 @@ config ARCH_S3C24XX select GPIOLIB select GENERIC_IRQ_MULTI_HANDLER select HAVE_S3C2410_I2C if I2C - select HAVE_S3C_RTC if RTC_CLASS select NEED_MACH_IO_H select S3C2410_WATCHDOG select SAMSUNG_ATAGS diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c index 2810eb5b2aca..cc75087134d3 100644 --- a/arch/arm/mach-ep93xx/clock.c +++ b/arch/arm/mach-ep93xx/clock.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "hardware.h" @@ -24,348 +25,194 @@ #include "soc.h" -struct clk { - struct clk *parent; - unsigned long rate; - int users; - int sw_locked; - void __iomem *enable_reg; - u32 enable_mask; - - unsigned long (*get_rate)(struct clk *clk); - int (*set_rate)(struct clk *clk, unsigned long rate); -}; - - -static unsigned long get_uart_rate(struct clk *clk); - -static int set_keytchclk_rate(struct clk *clk, unsigned long rate); -static int set_div_rate(struct clk *clk, unsigned long rate); -static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate); -static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate); - -static struct clk clk_xtali = { - .rate = EP93XX_EXT_CLK_RATE, -}; -static struct clk clk_uart1 = { - .parent = &clk_xtali, - .sw_locked = 1, - .enable_reg = EP93XX_SYSCON_DEVCFG, - .enable_mask = EP93XX_SYSCON_DEVCFG_U1EN, - .get_rate = get_uart_rate, -}; -static struct clk clk_uart2 = { - .parent = &clk_xtali, - .sw_locked = 1, - .enable_reg = EP93XX_SYSCON_DEVCFG, - .enable_mask = EP93XX_SYSCON_DEVCFG_U2EN, - .get_rate = get_uart_rate, -}; -static struct clk clk_uart3 = { - .parent = &clk_xtali, - .sw_locked = 1, - .enable_reg = EP93XX_SYSCON_DEVCFG, - .enable_mask = EP93XX_SYSCON_DEVCFG_U3EN, - .get_rate = get_uart_rate, -}; -static struct clk clk_pll1 = { - .parent = &clk_xtali, -}; -static struct clk clk_f = { - .parent = &clk_pll1, -}; -static struct clk clk_h = { - .parent = &clk_pll1, -}; -static struct clk clk_p = { - .parent = &clk_pll1, -}; -static struct clk clk_pll2 = { - .parent = &clk_xtali, -}; -static struct clk clk_usb_host = { - .parent = &clk_pll2, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN, -}; -static struct clk clk_keypad = { - .parent = &clk_xtali, - .sw_locked = 1, - .enable_reg = EP93XX_SYSCON_KEYTCHCLKDIV, - .enable_mask = EP93XX_SYSCON_KEYTCHCLKDIV_KEN, - .set_rate = set_keytchclk_rate, -}; -static struct clk clk_adc = { - .parent = &clk_xtali, - .sw_locked = 1, - .enable_reg = EP93XX_SYSCON_KEYTCHCLKDIV, - .enable_mask = EP93XX_SYSCON_KEYTCHCLKDIV_TSEN, - .set_rate = set_keytchclk_rate, -}; -static struct clk clk_spi = { - .parent = &clk_xtali, - .rate = EP93XX_EXT_CLK_RATE, -}; -static struct clk clk_pwm = { - .parent = &clk_xtali, - .rate = EP93XX_EXT_CLK_RATE, -}; - -static struct clk clk_video = { - .sw_locked = 1, - .enable_reg = EP93XX_SYSCON_VIDCLKDIV, - .enable_mask = EP93XX_SYSCON_CLKDIV_ENABLE, - .set_rate = set_div_rate, -}; - -static struct clk clk_i2s_mclk = { - .sw_locked = 1, - .enable_reg = EP93XX_SYSCON_I2SCLKDIV, - .enable_mask = EP93XX_SYSCON_CLKDIV_ENABLE, - .set_rate = set_div_rate, -}; - -static struct clk clk_i2s_sclk = { - .sw_locked = 1, - .parent = &clk_i2s_mclk, - .enable_reg = EP93XX_SYSCON_I2SCLKDIV, - .enable_mask = EP93XX_SYSCON_I2SCLKDIV_SENA, - .set_rate = set_i2s_sclk_rate, -}; - -static struct clk clk_i2s_lrclk = { - .sw_locked = 1, - .parent = &clk_i2s_sclk, - .enable_reg = EP93XX_SYSCON_I2SCLKDIV, - .enable_mask = EP93XX_SYSCON_I2SCLKDIV_SENA, - .set_rate = set_i2s_lrclk_rate, -}; - -/* DMA Clocks */ -static struct clk clk_m2p0 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P0, -}; -static struct clk clk_m2p1 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P1, -}; -static struct clk clk_m2p2 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P2, -}; -static struct clk clk_m2p3 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P3, -}; -static struct clk clk_m2p4 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P4, -}; -static struct clk clk_m2p5 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P5, -}; -static struct clk clk_m2p6 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P6, -}; -static struct clk clk_m2p7 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P7, -}; -static struct clk clk_m2p8 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P8, -}; -static struct clk clk_m2p9 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P9, -}; -static struct clk clk_m2m0 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M0, -}; -static struct clk clk_m2m1 = { - .parent = &clk_h, - .enable_reg = EP93XX_SYSCON_PWRCNT, - .enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M1, -}; - -#define INIT_CK(dev,con,ck) \ - { .dev_id = dev, .con_id = con, .clk = ck } - -static struct clk_lookup clocks[] = { - INIT_CK(NULL, "xtali", &clk_xtali), - INIT_CK("apb:uart1", NULL, &clk_uart1), - INIT_CK("apb:uart2", NULL, &clk_uart2), - INIT_CK("apb:uart3", NULL, &clk_uart3), - INIT_CK(NULL, "pll1", &clk_pll1), - INIT_CK(NULL, "fclk", &clk_f), - INIT_CK(NULL, "hclk", &clk_h), - INIT_CK(NULL, "apb_pclk", &clk_p), - INIT_CK(NULL, "pll2", &clk_pll2), - INIT_CK("ohci-platform", NULL, &clk_usb_host), - INIT_CK("ep93xx-keypad", NULL, &clk_keypad), - INIT_CK("ep93xx-adc", NULL, &clk_adc), - INIT_CK("ep93xx-fb", NULL, &clk_video), - INIT_CK("ep93xx-spi.0", NULL, &clk_spi), - INIT_CK("ep93xx-i2s", "mclk", &clk_i2s_mclk), - INIT_CK("ep93xx-i2s", "sclk", &clk_i2s_sclk), - INIT_CK("ep93xx-i2s", "lrclk", &clk_i2s_lrclk), - INIT_CK(NULL, "pwm_clk", &clk_pwm), - INIT_CK(NULL, "m2p0", &clk_m2p0), - INIT_CK(NULL, "m2p1", &clk_m2p1), - INIT_CK(NULL, "m2p2", &clk_m2p2), - INIT_CK(NULL, "m2p3", &clk_m2p3), - INIT_CK(NULL, "m2p4", &clk_m2p4), - INIT_CK(NULL, "m2p5", &clk_m2p5), - INIT_CK(NULL, "m2p6", &clk_m2p6), - INIT_CK(NULL, "m2p7", &clk_m2p7), - INIT_CK(NULL, "m2p8", &clk_m2p8), - INIT_CK(NULL, "m2p9", &clk_m2p9), - INIT_CK(NULL, "m2m0", &clk_m2m0), - INIT_CK(NULL, "m2m1", &clk_m2m1), -}; - static DEFINE_SPINLOCK(clk_lock); -static void __clk_enable(struct clk *clk) +static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; +static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; +static char pclk_divisors[] = { 1, 2, 4, 8 }; + +static char adc_divisors[] = { 16, 4 }; +static char sclk_divisors[] = { 2, 4 }; +static char lrclk_divisors[] = { 32, 64, 128 }; + +static const char * const mux_parents[] = { + "xtali", + "pll1", + "pll2" +}; + +/* + * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS + */ +static unsigned long calc_pll_rate(unsigned long long rate, u32 config_word) { - if (!clk->users++) { - if (clk->parent) - __clk_enable(clk->parent); + int i; - if (clk->enable_reg) { - u32 v; + rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ + rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ + do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ + for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */ + rate >>= 1; - v = __raw_readl(clk->enable_reg); - v |= clk->enable_mask; - if (clk->sw_locked) - ep93xx_syscon_swlocked_write(v, clk->enable_reg); - else - __raw_writel(v, clk->enable_reg); - } - } + return (unsigned long)rate; } -int clk_enable(struct clk *clk) +struct clk_psc { + struct clk_hw hw; + void __iomem *reg; + u8 bit_idx; + u32 mask; + u8 shift; + u8 width; + char *div; + u8 num_div; + spinlock_t *lock; +}; + +#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw) + +static int ep93xx_clk_is_enabled(struct clk_hw *hw) { - unsigned long flags; + struct clk_psc *psc = to_clk_psc(hw); + u32 val = readl(psc->reg); - if (!clk) - return -EINVAL; - - spin_lock_irqsave(&clk_lock, flags); - __clk_enable(clk); - spin_unlock_irqrestore(&clk_lock, flags); - - return 0; -} -EXPORT_SYMBOL(clk_enable); - -static void __clk_disable(struct clk *clk) -{ - if (!--clk->users) { - if (clk->enable_reg) { - u32 v; - - v = __raw_readl(clk->enable_reg); - v &= ~clk->enable_mask; - if (clk->sw_locked) - ep93xx_syscon_swlocked_write(v, clk->enable_reg); - else - __raw_writel(v, clk->enable_reg); - } - - if (clk->parent) - __clk_disable(clk->parent); - } + return (val & BIT(psc->bit_idx)) ? 1 : 0; } -void clk_disable(struct clk *clk) -{ - unsigned long flags; - - if (!clk) - return; - - spin_lock_irqsave(&clk_lock, flags); - __clk_disable(clk); - spin_unlock_irqrestore(&clk_lock, flags); -} -EXPORT_SYMBOL(clk_disable); - -static unsigned long get_uart_rate(struct clk *clk) -{ - unsigned long rate = clk_get_rate(clk->parent); - u32 value; - - value = __raw_readl(EP93XX_SYSCON_PWRCNT); - if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD) - return rate; - else - return rate / 2; -} - -unsigned long clk_get_rate(struct clk *clk) -{ - if (clk->get_rate) - return clk->get_rate(clk); - - return clk->rate; -} -EXPORT_SYMBOL(clk_get_rate); - -static int set_keytchclk_rate(struct clk *clk, unsigned long rate) +static int ep93xx_clk_enable(struct clk_hw *hw) { + struct clk_psc *psc = to_clk_psc(hw); + unsigned long flags = 0; u32 val; - u32 div_bit; - val = __raw_readl(clk->enable_reg); + if (psc->lock) + spin_lock_irqsave(psc->lock, flags); - /* - * The Key Matrix and ADC clocks are configured using the same - * System Controller register. The clock used will be either - * 1/4 or 1/16 the external clock rate depending on the - * EP93XX_SYSCON_KEYTCHCLKDIV_KDIV/EP93XX_SYSCON_KEYTCHCLKDIV_ADIV - * bit being set or cleared. - */ - div_bit = clk->enable_mask >> 15; + val = __raw_readl(psc->reg); + val |= BIT(psc->bit_idx); - if (rate == EP93XX_KEYTCHCLK_DIV4) - val |= div_bit; - else if (rate == EP93XX_KEYTCHCLK_DIV16) - val &= ~div_bit; - else - return -EINVAL; + ep93xx_syscon_swlocked_write(val, psc->reg); + + if (psc->lock) + spin_unlock_irqrestore(psc->lock, flags); - ep93xx_syscon_swlocked_write(val, clk->enable_reg); - clk->rate = rate; return 0; } -static int calc_clk_div(struct clk *clk, unsigned long rate, - int *psel, int *esel, int *pdiv, int *div) +static void ep93xx_clk_disable(struct clk_hw *hw) { - struct clk *mclk; - unsigned long max_rate, actual_rate, mclk_rate, rate_err = -1; - int i, found = 0, __div = 0, __pdiv = 0; + struct clk_psc *psc = to_clk_psc(hw); + unsigned long flags = 0; + u32 val; - /* Don't exceed the maximum rate */ - max_rate = max3(clk_pll1.rate / 4, clk_pll2.rate / 4, clk_xtali.rate / 4); - rate = min(rate, max_rate); + if (psc->lock) + spin_lock_irqsave(psc->lock, flags); + + val = __raw_readl(psc->reg); + val &= ~BIT(psc->bit_idx); + + ep93xx_syscon_swlocked_write(val, psc->reg); + + if (psc->lock) + spin_unlock_irqrestore(psc->lock, flags); +} + +static const struct clk_ops clk_ep93xx_gate_ops = { + .enable = ep93xx_clk_enable, + .disable = ep93xx_clk_disable, + .is_enabled = ep93xx_clk_is_enabled, +}; + +static struct clk_hw *ep93xx_clk_register_gate(const char *name, + const char *parent_name, + void __iomem *reg, + u8 bit_idx) +{ + struct clk_init_data init; + struct clk_psc *psc; + struct clk *clk; + + psc = kzalloc(sizeof(*psc), GFP_KERNEL); + if (!psc) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_ep93xx_gate_ops; + init.flags = CLK_SET_RATE_PARENT; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = (parent_name ? 1 : 0); + + psc->reg = reg; + psc->bit_idx = bit_idx; + psc->hw.init = &init; + psc->lock = &clk_lock; + + clk = clk_register(NULL, &psc->hw); + if (IS_ERR(clk)) + kfree(psc); + + return &psc->hw; +} + +static u8 ep93xx_mux_get_parent(struct clk_hw *hw) +{ + struct clk_psc *psc = to_clk_psc(hw); + u32 val = __raw_readl(psc->reg); + + if (!(val & EP93XX_SYSCON_CLKDIV_ESEL)) + return 0; + + if (!(val & EP93XX_SYSCON_CLKDIV_PSEL)) + return 1; + + return 2; +} + +static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index) +{ + struct clk_psc *psc = to_clk_psc(hw); + unsigned long flags = 0; + u32 val; + + if (index >= ARRAY_SIZE(mux_parents)) + return -EINVAL; + + if (psc->lock) + spin_lock_irqsave(psc->lock, flags); + + val = __raw_readl(psc->reg); + val &= ~(EP93XX_SYSCON_CLKDIV_ESEL | EP93XX_SYSCON_CLKDIV_PSEL); + + + if (index != 0) { + val |= EP93XX_SYSCON_CLKDIV_ESEL; + val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0; + } + + ep93xx_syscon_swlocked_write(val, psc->reg); + + if (psc->lock) + spin_unlock_irqrestore(psc->lock, flags); + + return 0; +} + +static bool is_best(unsigned long rate, unsigned long now, + unsigned long best) +{ + return abs(rate - now) < abs(rate - best); +} + +static int ep93xx_mux_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + unsigned long rate = req->rate; + struct clk *best_parent = 0; + unsigned long __parent_rate; + unsigned long best_rate = 0, actual_rate, mclk_rate; + unsigned long best_parent_rate; + int __div = 0, __pdiv = 0; + int i; /* * Try the two pll's and the external clock @@ -376,14 +223,11 @@ static int calc_clk_div(struct clk *clk, unsigned long rate, * http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf * */ - for (i = 0; i < 3; i++) { - if (i == 0) - mclk = &clk_xtali; - else if (i == 1) - mclk = &clk_pll1; - else - mclk = &clk_pll2; - mclk_rate = mclk->rate * 2; + for (i = 0; i < ARRAY_SIZE(mux_parents); i++) { + struct clk *parent = clk_get_sys(mux_parents[i], NULL); + + __parent_rate = clk_get_rate(parent); + mclk_rate = __parent_rate * 2; /* Try each predivider value */ for (__pdiv = 4; __pdiv <= 6; __pdiv++) { @@ -392,197 +236,494 @@ static int calc_clk_div(struct clk *clk, unsigned long rate, continue; actual_rate = mclk_rate / (__pdiv * __div); - - if (!found || abs(actual_rate - rate) < rate_err) { - *pdiv = __pdiv - 3; - *div = __div; - *psel = (i == 2); - *esel = (i != 0); - clk->parent = mclk; - clk->rate = actual_rate; - rate_err = abs(actual_rate - rate); - found = 1; + if (is_best(rate, actual_rate, best_rate)) { + best_rate = actual_rate; + best_parent_rate = __parent_rate; + best_parent = parent; } } } - if (!found) + if (!best_parent) return -EINVAL; + req->best_parent_rate = best_parent_rate; + req->best_parent_hw = __clk_get_hw(best_parent); + req->rate = best_rate; + return 0; } -static int set_div_rate(struct clk *clk, unsigned long rate) +static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - int err, psel = 0, esel = 0, pdiv = 0, div = 0; + struct clk_psc *psc = to_clk_psc(hw); + unsigned long rate = 0; + u32 val = __raw_readl(psc->reg); + int __pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03); + int __div = val & 0x7f; + + if (__div > 0) + rate = (parent_rate * 2) / ((__pdiv + 3) * __div); + + return rate; +} + +static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_psc *psc = to_clk_psc(hw); + int pdiv = 0, div = 0; + unsigned long best_rate = 0, actual_rate, mclk_rate; + int __div = 0, __pdiv = 0; u32 val; - err = calc_clk_div(clk, rate, &psel, &esel, &pdiv, &div); - if (err) - return err; + mclk_rate = parent_rate * 2; - /* Clear the esel, psel, pdiv and div bits */ - val = __raw_readl(clk->enable_reg); - val &= ~0x7fff; + for (__pdiv = 4; __pdiv <= 6; __pdiv++) { + __div = mclk_rate / (rate * __pdiv); + if (__div < 2 || __div > 127) + continue; - /* Set the new esel, psel, pdiv and div bits for the new clock rate */ - val |= (esel ? EP93XX_SYSCON_CLKDIV_ESEL : 0) | - (psel ? EP93XX_SYSCON_CLKDIV_PSEL : 0) | - (pdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | div; - ep93xx_syscon_swlocked_write(val, clk->enable_reg); - return 0; -} + actual_rate = mclk_rate / (__pdiv * __div); + if (is_best(rate, actual_rate, best_rate)) { + pdiv = __pdiv - 3; + div = __div; + best_rate = actual_rate; + } + } -static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate) -{ - unsigned val = __raw_readl(clk->enable_reg); - - if (rate == clk_i2s_mclk.rate / 2) - ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV, - clk->enable_reg); - else if (rate == clk_i2s_mclk.rate / 4) - ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV, - clk->enable_reg); - else + if (!best_rate) return -EINVAL; - clk_i2s_sclk.rate = rate; + val = __raw_readl(psc->reg); + + /* Clear old dividers */ + val &= ~0x37f; + + /* Set the new pdiv and div bits for the new clock rate */ + val |= (pdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | div; + ep93xx_syscon_swlocked_write(val, psc->reg); + return 0; } -static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate) -{ - unsigned val = __raw_readl(clk->enable_reg) & - ~EP93XX_I2SCLKDIV_LRDIV_MASK; - - if (rate == clk_i2s_sclk.rate / 32) - ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32, - clk->enable_reg); - else if (rate == clk_i2s_sclk.rate / 64) - ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64, - clk->enable_reg); - else if (rate == clk_i2s_sclk.rate / 128) - ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128, - clk->enable_reg); - else - return -EINVAL; +static const struct clk_ops clk_ddiv_ops = { + .enable = ep93xx_clk_enable, + .disable = ep93xx_clk_disable, + .is_enabled = ep93xx_clk_is_enabled, + .get_parent = ep93xx_mux_get_parent, + .set_parent = ep93xx_mux_set_parent_lock, + .determine_rate = ep93xx_mux_determine_rate, + .recalc_rate = ep93xx_ddiv_recalc_rate, + .set_rate = ep93xx_ddiv_set_rate, +}; - clk_i2s_lrclk.rate = rate; - return 0; +static struct clk_hw *clk_hw_register_ddiv(const char *name, + void __iomem *reg, + u8 bit_idx) +{ + struct clk_init_data init; + struct clk_psc *psc; + struct clk *clk; + + psc = kzalloc(sizeof(*psc), GFP_KERNEL); + if (!psc) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_ddiv_ops; + init.flags = 0; + init.parent_names = mux_parents; + init.num_parents = ARRAY_SIZE(mux_parents); + + psc->reg = reg; + psc->bit_idx = bit_idx; + psc->lock = &clk_lock; + psc->hw.init = &init; + + clk = clk_register(NULL, &psc->hw); + if (IS_ERR(clk)) + kfree(psc); + + return &psc->hw; } -int clk_set_rate(struct clk *clk, unsigned long rate) +static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { - if (clk->set_rate) - return clk->set_rate(clk, rate); + struct clk_psc *psc = to_clk_psc(hw); + u32 val = __raw_readl(psc->reg); + u8 index = (val & psc->mask) >> psc->shift; - return -EINVAL; + if (index > psc->num_div) + return 0; + + return DIV_ROUND_UP_ULL(parent_rate, psc->div[index]); } -EXPORT_SYMBOL(clk_set_rate); -long clk_round_rate(struct clk *clk, unsigned long rate) +static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) { - WARN_ON(clk); - return 0; -} -EXPORT_SYMBOL(clk_round_rate); - -int clk_set_parent(struct clk *clk, struct clk *parent) -{ - WARN_ON(clk); - return 0; -} -EXPORT_SYMBOL(clk_set_parent); - -struct clk *clk_get_parent(struct clk *clk) -{ - return clk->parent; -} -EXPORT_SYMBOL(clk_get_parent); - - -static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 }; -static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 }; -static char pclk_divisors[] = { 1, 2, 4, 8 }; - -/* - * PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS - */ -static unsigned long calc_pll_rate(u32 config_word) -{ - unsigned long long rate; + struct clk_psc *psc = to_clk_psc(hw); + unsigned long best = 0, now, maxdiv; int i; - rate = clk_xtali.rate; - rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */ - rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */ - do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */ - for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */ - rate >>= 1; + maxdiv = psc->div[psc->num_div - 1]; - return (unsigned long)rate; + for (i = 0; i < psc->num_div; i++) { + if ((rate * psc->div[i]) == *parent_rate) + return DIV_ROUND_UP_ULL((u64)*parent_rate, psc->div[i]); + + now = DIV_ROUND_UP_ULL((u64)*parent_rate, psc->div[i]); + + if (is_best(rate, now, best)) + best = now; + } + + if (!best) + best = DIV_ROUND_UP_ULL(*parent_rate, maxdiv); + + return best; } +static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_psc *psc = to_clk_psc(hw); + u32 val = __raw_readl(psc->reg) & ~psc->mask; + int i; + + for (i = 0; i < psc->num_div; i++) + if (rate == parent_rate / psc->div[i]) { + val |= i << psc->shift; + break; + } + + if (i == psc->num_div) + return -EINVAL; + + ep93xx_syscon_swlocked_write(val, psc->reg); + + return 0; +} + +static const struct clk_ops ep93xx_div_ops = { + .enable = ep93xx_clk_enable, + .disable = ep93xx_clk_disable, + .is_enabled = ep93xx_clk_is_enabled, + .recalc_rate = ep93xx_div_recalc_rate, + .round_rate = ep93xx_div_round_rate, + .set_rate = ep93xx_div_set_rate, +}; + +static struct clk_hw *clk_hw_register_div(const char *name, + const char *parent_name, + void __iomem *reg, + u8 enable_bit, + u8 shift, + u8 width, + char *clk_divisors, + u8 num_div) +{ + struct clk_init_data init; + struct clk_psc *psc; + struct clk *clk; + + psc = kzalloc(sizeof(*psc), GFP_KERNEL); + if (!psc) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &ep93xx_div_ops; + init.flags = 0; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = 1; + + psc->reg = reg; + psc->bit_idx = enable_bit; + psc->mask = GENMASK(shift + width - 1, shift); + psc->shift = shift; + psc->div = clk_divisors; + psc->num_div = num_div; + psc->lock = &clk_lock; + psc->hw.init = &init; + + clk = clk_register(NULL, &psc->hw); + if (IS_ERR(clk)) + kfree(psc); + + return &psc->hw; +} + +struct ep93xx_gate { + unsigned int bit; + const char *dev_id; + const char *con_id; +}; + +static struct ep93xx_gate ep93xx_uarts[] = { + {EP93XX_SYSCON_DEVCFG_U1EN, "apb:uart1", NULL}, + {EP93XX_SYSCON_DEVCFG_U2EN, "apb:uart2", NULL}, + {EP93XX_SYSCON_DEVCFG_U3EN, "apb:uart3", NULL}, +}; + +static void __init ep93xx_uart_clock_init(void) +{ + unsigned int i; + struct clk_hw *hw; + u32 value; + unsigned int clk_uart_div; + + value = __raw_readl(EP93XX_SYSCON_PWRCNT); + if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD) + clk_uart_div = 1; + else + clk_uart_div = 2; + + hw = clk_hw_register_fixed_factor(NULL, "uart", "xtali", 0, 1, clk_uart_div); + + /* parenting uart gate clocks to uart clock */ + for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) { + hw = ep93xx_clk_register_gate(ep93xx_uarts[i].dev_id, + "uart", + EP93XX_SYSCON_DEVCFG, + ep93xx_uarts[i].bit); + + clk_hw_register_clkdev(hw, NULL, ep93xx_uarts[i].dev_id); + } +} + +static struct ep93xx_gate ep93xx_dmas[] = { + {EP93XX_SYSCON_PWRCNT_DMA_M2P0, NULL, "m2p0"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P1, NULL, "m2p1"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P2, NULL, "m2p2"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P3, NULL, "m2p3"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P4, NULL, "m2p4"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P5, NULL, "m2p5"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P6, NULL, "m2p6"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P7, NULL, "m2p7"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P8, NULL, "m2p8"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2P9, NULL, "m2p9"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2M0, NULL, "m2m0"}, + {EP93XX_SYSCON_PWRCNT_DMA_M2M1, NULL, "m2m1"}, +}; + static void __init ep93xx_dma_clock_init(void) { - clk_m2p0.rate = clk_h.rate; - clk_m2p1.rate = clk_h.rate; - clk_m2p2.rate = clk_h.rate; - clk_m2p3.rate = clk_h.rate; - clk_m2p4.rate = clk_h.rate; - clk_m2p5.rate = clk_h.rate; - clk_m2p6.rate = clk_h.rate; - clk_m2p7.rate = clk_h.rate; - clk_m2p8.rate = clk_h.rate; - clk_m2p9.rate = clk_h.rate; - clk_m2m0.rate = clk_h.rate; - clk_m2m1.rate = clk_h.rate; + unsigned int i; + struct clk_hw *hw; + int ret; + + for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) { + hw = clk_hw_register_gate(NULL, ep93xx_dmas[i].con_id, + "hclk", 0, + EP93XX_SYSCON_PWRCNT, + ep93xx_dmas[i].bit, + 0, + &clk_lock); + + ret = clk_hw_register_clkdev(hw, ep93xx_dmas[i].con_id, NULL); + if (ret) + pr_err("%s: failed to register lookup %s\n", + __func__, ep93xx_dmas[i].con_id); + } } static int __init ep93xx_clock_init(void) { u32 value; + struct clk_hw *hw; + unsigned long clk_pll1_rate; + unsigned long clk_f_rate; + unsigned long clk_h_rate; + unsigned long clk_p_rate; + unsigned long clk_pll2_rate; + unsigned int clk_f_div; + unsigned int clk_h_div; + unsigned int clk_p_div; + unsigned int clk_usb_div; + unsigned long clk_spi_div; + + hw = clk_hw_register_fixed_rate(NULL, "xtali", NULL, 0, EP93XX_EXT_CLK_RATE); + clk_hw_register_clkdev(hw, NULL, "xtali"); /* Determine the bootloader configured pll1 rate */ value = __raw_readl(EP93XX_SYSCON_CLKSET1); if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1)) - clk_pll1.rate = clk_xtali.rate; + clk_pll1_rate = EP93XX_EXT_CLK_RATE; else - clk_pll1.rate = calc_pll_rate(value); + clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value); + + hw = clk_hw_register_fixed_rate(NULL, "pll1", "xtali", 0, clk_pll1_rate); + clk_hw_register_clkdev(hw, NULL, "pll1"); /* Initialize the pll1 derived clocks */ - clk_f.rate = clk_pll1.rate / fclk_divisors[(value >> 25) & 0x7]; - clk_h.rate = clk_pll1.rate / hclk_divisors[(value >> 20) & 0x7]; - clk_p.rate = clk_h.rate / pclk_divisors[(value >> 18) & 0x3]; + clk_f_div = fclk_divisors[(value >> 25) & 0x7]; + clk_h_div = hclk_divisors[(value >> 20) & 0x7]; + clk_p_div = pclk_divisors[(value >> 18) & 0x3]; + + hw = clk_hw_register_fixed_factor(NULL, "fclk", "pll1", 0, 1, clk_f_div); + clk_f_rate = clk_get_rate(hw->clk); + hw = clk_hw_register_fixed_factor(NULL, "hclk", "pll1", 0, 1, clk_h_div); + clk_h_rate = clk_get_rate(hw->clk); + hw = clk_hw_register_fixed_factor(NULL, "pclk", "hclk", 0, 1, clk_p_div); + clk_p_rate = clk_get_rate(hw->clk); + + clk_hw_register_clkdev(hw, "apb_pclk", NULL); + ep93xx_dma_clock_init(); /* Determine the bootloader configured pll2 rate */ value = __raw_readl(EP93XX_SYSCON_CLKSET2); if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2)) - clk_pll2.rate = clk_xtali.rate; + clk_pll2_rate = EP93XX_EXT_CLK_RATE; else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN) - clk_pll2.rate = calc_pll_rate(value); + clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value); else - clk_pll2.rate = 0; + clk_pll2_rate = 0; + + hw = clk_hw_register_fixed_rate(NULL, "pll2", "xtali", 0, clk_pll2_rate); + clk_hw_register_clkdev(hw, NULL, "pll2"); /* Initialize the pll2 derived clocks */ - clk_usb_host.rate = clk_pll2.rate / (((value >> 28) & 0xf) + 1); + /* + * These four bits set the divide ratio between the PLL2 + * output and the USB clock. + * 0000 - Divide by 1 + * 0001 - Divide by 2 + * 0010 - Divide by 3 + * 0011 - Divide by 4 + * 0100 - Divide by 5 + * 0101 - Divide by 6 + * 0110 - Divide by 7 + * 0111 - Divide by 8 + * 1000 - Divide by 9 + * 1001 - Divide by 10 + * 1010 - Divide by 11 + * 1011 - Divide by 12 + * 1100 - Divide by 13 + * 1101 - Divide by 14 + * 1110 - Divide by 15 + * 1111 - Divide by 1 + * On power-on-reset these bits are reset to 0000b. + */ + clk_usb_div = (((value >> 28) & 0xf) + 1); + hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2", 0, 1, clk_usb_div); + hw = clk_hw_register_gate(NULL, "ohci-platform", + "usb_clk", 0, + EP93XX_SYSCON_PWRCNT, + EP93XX_SYSCON_PWRCNT_USH_EN, + 0, + &clk_lock); + clk_hw_register_clkdev(hw, NULL, "ohci-platform"); /* * EP93xx SSP clock rate was doubled in version E2. For more information * see: * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf */ + clk_spi_div = 1; if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2) - clk_spi.rate /= 2; + clk_spi_div = 2; + hw = clk_hw_register_fixed_factor(NULL, "ep93xx-spi.0", "xtali", 0, 1, clk_spi_div); + clk_hw_register_clkdev(hw, NULL, "ep93xx-spi.0"); + + /* pwm clock */ + hw = clk_hw_register_fixed_factor(NULL, "pwm_clk", "xtali", 0, 1, 1); + clk_hw_register_clkdev(hw, "pwm_clk", NULL); pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n", - clk_pll1.rate / 1000000, clk_pll2.rate / 1000000); + clk_pll1_rate / 1000000, clk_pll2_rate / 1000000); pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n", - clk_f.rate / 1000000, clk_h.rate / 1000000, - clk_p.rate / 1000000); + clk_f_rate / 1000000, clk_h_rate / 1000000, + clk_p_rate / 1000000); + + ep93xx_uart_clock_init(); + + /* touchscreen/adc clock */ + hw = clk_hw_register_div("ep93xx-adc", + "xtali", + EP93XX_SYSCON_KEYTCHCLKDIV, + EP93XX_SYSCON_KEYTCHCLKDIV_TSEN, + EP93XX_SYSCON_KEYTCHCLKDIV_ADIV, + 1, + adc_divisors, + ARRAY_SIZE(adc_divisors)); + + clk_hw_register_clkdev(hw, NULL, "ep93xx-adc"); + + /* keypad clock */ + hw = clk_hw_register_div("ep93xx-keypad", + "xtali", + EP93XX_SYSCON_KEYTCHCLKDIV, + EP93XX_SYSCON_KEYTCHCLKDIV_KEN, + EP93XX_SYSCON_KEYTCHCLKDIV_KDIV, + 1, + adc_divisors, + ARRAY_SIZE(adc_divisors)); + + clk_hw_register_clkdev(hw, NULL, "ep93xx-keypad"); + + /* On reset PDIV and VDIV is set to zero, while PDIV zero + * means clock disable, VDIV shouldn't be zero. + * So i set both dividers to minimum. + */ + /* ENA - Enable CLK divider. */ + /* PDIV - 00 - Disable clock */ + /* VDIV - at least 2 */ + /* Check and enable video clk registers */ + value = __raw_readl(EP93XX_SYSCON_VIDCLKDIV); + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2; + ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_VIDCLKDIV); + + /* check and enable i2s clk registers */ + value = __raw_readl(EP93XX_SYSCON_I2SCLKDIV); + value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2; + ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_I2SCLKDIV); + + /* video clk */ + hw = clk_hw_register_ddiv("ep93xx-fb", + EP93XX_SYSCON_VIDCLKDIV, + EP93XX_SYSCON_CLKDIV_ENABLE); + + clk_hw_register_clkdev(hw, NULL, "ep93xx-fb"); + + /* i2s clk */ + hw = clk_hw_register_ddiv("mclk", + EP93XX_SYSCON_I2SCLKDIV, + EP93XX_SYSCON_CLKDIV_ENABLE); + + clk_hw_register_clkdev(hw, "mclk", "ep93xx-i2s"); + + /* i2s sclk */ +#define EP93XX_I2SCLKDIV_SDIV_SHIFT 16 +#define EP93XX_I2SCLKDIV_SDIV_WIDTH 1 + hw = clk_hw_register_div("sclk", + "mclk", + EP93XX_SYSCON_I2SCLKDIV, + EP93XX_SYSCON_I2SCLKDIV_SENA, + EP93XX_I2SCLKDIV_SDIV_SHIFT, + EP93XX_I2SCLKDIV_SDIV_WIDTH, + sclk_divisors, + ARRAY_SIZE(sclk_divisors)); + + clk_hw_register_clkdev(hw, "sclk", "ep93xx-i2s"); + + /* i2s lrclk */ +#define EP93XX_I2SCLKDIV_LRDIV32_SHIFT 17 +#define EP93XX_I2SCLKDIV_LRDIV32_WIDTH 3 + hw = clk_hw_register_div("lrclk", + "sclk", + EP93XX_SYSCON_I2SCLKDIV, + EP93XX_SYSCON_I2SCLKDIV_SENA, + EP93XX_I2SCLKDIV_LRDIV32_SHIFT, + EP93XX_I2SCLKDIV_LRDIV32_WIDTH, + lrclk_divisors, + ARRAY_SIZE(lrclk_divisors)); + + clk_hw_register_clkdev(hw, "lrclk", "ep93xx-i2s"); - clkdev_add_table(clocks, ARRAY_SIZE(clocks)); return 0; } postcore_initcall(ep93xx_clock_init); diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 4659132a0509..a3b4e843456a 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c @@ -214,7 +214,7 @@ static int ep93xx_ohci_power_on(struct platform_device *pdev) return PTR_ERR(ep93xx_ohci_host_clock); } - return clk_enable(ep93xx_ohci_host_clock); + return clk_prepare_enable(ep93xx_ohci_host_clock); } static void ep93xx_ohci_power_off(struct platform_device *pdev) diff --git a/arch/arm/mach-ep93xx/soc.h b/arch/arm/mach-ep93xx/soc.h index f2dace1c9154..94ef7f275f94 100644 --- a/arch/arm/mach-ep93xx/soc.h +++ b/arch/arm/mach-ep93xx/soc.h @@ -111,19 +111,19 @@ #define EP93XX_SYSCON_PWRCNT EP93XX_SYSCON_REG(0x04) #define EP93XX_SYSCON_PWRCNT_FIR_EN (1<<31) #define EP93XX_SYSCON_PWRCNT_UARTBAUD (1<<29) -#define EP93XX_SYSCON_PWRCNT_USH_EN (1<<28) -#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 (1<<27) -#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 (1<<26) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 (1<<25) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 (1<<24) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 (1<<23) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 (1<<22) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 (1<<21) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 (1<<20) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 (1<<19) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 (1<<18) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 (1<<17) -#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 (1<<16) +#define EP93XX_SYSCON_PWRCNT_USH_EN 28 +#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27 +#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17 +#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16 #define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08) #define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c) #define EP93XX_SYSCON_CLKSET1 EP93XX_SYSCON_REG(0x20) @@ -139,13 +139,13 @@ #define EP93XX_SYSCON_DEVCFG_GONK (1<<27) #define EP93XX_SYSCON_DEVCFG_TONG (1<<26) #define EP93XX_SYSCON_DEVCFG_MONG (1<<25) -#define EP93XX_SYSCON_DEVCFG_U3EN (1<<24) +#define EP93XX_SYSCON_DEVCFG_U3EN 24 #define EP93XX_SYSCON_DEVCFG_CPENA (1<<23) #define EP93XX_SYSCON_DEVCFG_A2ONG (1<<22) #define EP93XX_SYSCON_DEVCFG_A1ONG (1<<21) -#define EP93XX_SYSCON_DEVCFG_U2EN (1<<20) +#define EP93XX_SYSCON_DEVCFG_U2EN 20 #define EP93XX_SYSCON_DEVCFG_EXVC (1<<19) -#define EP93XX_SYSCON_DEVCFG_U1EN (1<<18) +#define EP93XX_SYSCON_DEVCFG_U1EN 18 #define EP93XX_SYSCON_DEVCFG_TIN (1<<17) #define EP93XX_SYSCON_DEVCFG_HC3IN (1<<15) #define EP93XX_SYSCON_DEVCFG_HC3EN (1<<14) @@ -163,12 +163,12 @@ #define EP93XX_SYSCON_DEVCFG_KEYS (1<<1) #define EP93XX_SYSCON_DEVCFG_SHENA (1<<0) #define EP93XX_SYSCON_VIDCLKDIV EP93XX_SYSCON_REG(0x84) -#define EP93XX_SYSCON_CLKDIV_ENABLE (1<<15) +#define EP93XX_SYSCON_CLKDIV_ENABLE 15 #define EP93XX_SYSCON_CLKDIV_ESEL (1<<14) #define EP93XX_SYSCON_CLKDIV_PSEL (1<<13) #define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8 #define EP93XX_SYSCON_I2SCLKDIV EP93XX_SYSCON_REG(0x8c) -#define EP93XX_SYSCON_I2SCLKDIV_SENA (1<<31) +#define EP93XX_SYSCON_I2SCLKDIV_SENA 31 #define EP93XX_SYSCON_I2SCLKDIV_ORIDE (1<<29) #define EP93XX_SYSCON_I2SCLKDIV_SPOL (1<<19) #define EP93XX_I2SCLKDIV_SDIV (1 << 16) @@ -177,9 +177,9 @@ #define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17) #define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17) #define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90) -#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN (1<<31) -#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16) -#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN (1<<15) +#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31 +#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16 +#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15 #define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV (1<<0) #define EP93XX_SYSCON_SYSCFG EP93XX_SYSCON_REG(0x9c) #define EP93XX_SYSCON_SYSCFG_REV_MASK (0xf0000000) diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 5a48abac6af4..dd1ae5571f43 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -13,7 +13,6 @@ menuconfig ARCH_EXYNOS select ARM_GIC select EXYNOS_IRQ_COMBINER select COMMON_CLK_SAMSUNG - select EXYNOS_CHIPID select EXYNOS_THERMAL select EXYNOS_PMU select EXYNOS_SROM @@ -22,7 +21,6 @@ menuconfig ARCH_EXYNOS select HAVE_ARM_ARCH_TIMER if ARCH_EXYNOS5 select HAVE_ARM_SCU if SMP select HAVE_S3C2410_I2C if I2C - select HAVE_S3C_RTC if RTC_CLASS select PINCTRL select PINCTRL_EXYNOS select PM_GENERIC_DOMAINS if PM diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c index 630a038f4513..58a4228455ce 100644 --- a/arch/arm/mach-qcom/platsmp.c +++ b/arch/arm/mach-qcom/platsmp.c @@ -29,6 +29,7 @@ #define COREPOR_RST BIT(5) #define CORE_RST BIT(4) #define L2DT_SLP BIT(3) +#define CORE_MEM_CLAMP BIT(1) #define CLAMP BIT(0) #define APC_PWR_GATE_CTL 0x14 @@ -75,6 +76,62 @@ static int scss_release_secondary(unsigned int cpu) return 0; } +static int cortex_a7_release_secondary(unsigned int cpu) +{ + int ret = 0; + void __iomem *reg; + struct device_node *cpu_node, *acc_node; + u32 reg_val; + + cpu_node = of_get_cpu_node(cpu, NULL); + if (!cpu_node) + return -ENODEV; + + acc_node = of_parse_phandle(cpu_node, "qcom,acc", 0); + if (!acc_node) { + ret = -ENODEV; + goto out_acc; + } + + reg = of_iomap(acc_node, 0); + if (!reg) { + ret = -ENOMEM; + goto out_acc_map; + } + + /* Put the CPU into reset. */ + reg_val = CORE_RST | COREPOR_RST | CLAMP | CORE_MEM_CLAMP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + + /* Turn on the BHS and set the BHS_CNT to 16 XO clock cycles */ + writel(BHS_EN | (0x10 << BHS_CNT_SHIFT), reg + APC_PWR_GATE_CTL); + /* Wait for the BHS to settle */ + udelay(2); + + reg_val &= ~CORE_MEM_CLAMP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + reg_val |= L2DT_SLP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + udelay(2); + + reg_val = (reg_val | BIT(17)) & ~CLAMP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + udelay(2); + + /* Release CPU out of reset and bring it to life. */ + reg_val &= ~(CORE_RST | COREPOR_RST); + writel(reg_val, reg + APCS_CPU_PWR_CTL); + reg_val |= CORE_PWRD_UP; + writel(reg_val, reg + APCS_CPU_PWR_CTL); + + iounmap(reg); +out_acc_map: + of_node_put(acc_node); +out_acc: + of_node_put(cpu_node); + return ret; +} + static int kpssv1_release_secondary(unsigned int cpu) { int ret = 0; @@ -281,6 +338,11 @@ static int msm8660_boot_secondary(unsigned int cpu, struct task_struct *idle) return qcom_boot_secondary(cpu, scss_release_secondary); } +static int cortex_a7_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + return qcom_boot_secondary(cpu, cortex_a7_release_secondary); +} + static int kpssv1_boot_secondary(unsigned int cpu, struct task_struct *idle) { return qcom_boot_secondary(cpu, kpssv1_release_secondary); @@ -315,6 +377,16 @@ static const struct smp_operations smp_msm8660_ops __initconst = { }; CPU_METHOD_OF_DECLARE(qcom_smp, "qcom,gcc-msm8660", &smp_msm8660_ops); +static const struct smp_operations qcom_smp_cortex_a7_ops __initconst = { + .smp_prepare_cpus = qcom_smp_prepare_cpus, + .smp_boot_secondary = cortex_a7_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU + .cpu_die = qcom_cpu_die, +#endif +}; +CPU_METHOD_OF_DECLARE(qcom_smp_msm8226, "qcom,msm8226-smp", &qcom_smp_cortex_a7_ops); +CPU_METHOD_OF_DECLARE(qcom_smp_msm8916, "qcom,msm8916-smp", &qcom_smp_cortex_a7_ops); + static const struct smp_operations qcom_smp_kpssv1_ops __initconst = { .smp_prepare_cpus = qcom_smp_prepare_cpus, .smp_boot_secondary = kpssv1_boot_secondary, diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig index d644b45bc29d..5a96099af991 100644 --- a/arch/arm/mach-s5pv210/Kconfig +++ b/arch/arm/mach-s5pv210/Kconfig @@ -13,7 +13,6 @@ config ARCH_S5PV210 select COMMON_CLK_SAMSUNG select GPIOLIB select HAVE_S3C2410_I2C if I2C - select HAVE_S3C_RTC if RTC_CLASS select PINCTRL select PINCTRL_EXYNOS select SOC_SAMSUNG diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 96a81967c3bf..1aa8b7073218 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -89,10 +89,8 @@ config ARCH_BRCMSTB config ARCH_EXYNOS bool "ARMv8 based Samsung Exynos SoC family" select COMMON_CLK_SAMSUNG - select EXYNOS_CHIPID select EXYNOS_PM_DOMAINS if PM_GENERIC_DOMAINS select EXYNOS_PMU - select HAVE_S3C_RTC if RTC_CLASS select PINCTRL select PINCTRL_EXYNOS select PM_GENERIC_DOMAINS if PM diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index a4cf3d692dc3..3c68e174a113 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -30,7 +30,7 @@ config ARM_INTEGRATOR_LM found on the ARM Integrator AP (Application Platform) config BRCMSTB_GISB_ARB - bool "Broadcom STB GISB bus arbiter" + tristate "Broadcom STB GISB bus arbiter" depends on ARM || ARM64 || MIPS default ARCH_BRCMSTB || BMIPS_GENERIC help diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index 6551286a60cc..4c2f7d61cb9b 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (C) 2014-2017 Broadcom + * Copyright (C) 2014-2021 Broadcom */ #include @@ -536,6 +536,7 @@ static struct platform_driver brcmstb_gisb_arb_driver = { .name = "brcm-gisb-arb", .of_match_table = brcmstb_gisb_arb_of_match, .pm = &brcmstb_gisb_arb_pm_ops, + .suppress_bind_attrs = true, }, }; @@ -546,3 +547,7 @@ static int __init brcm_gisb_driver_init(void) } module_init(brcm_gisb_driver_init); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("Broadcom STB GISB arbiter driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/bus/sun50i-de2.c b/drivers/bus/sun50i-de2.c index 672518741f86..414f29cdedf0 100644 --- a/drivers/bus/sun50i-de2.c +++ b/drivers/bus/sun50i-de2.c @@ -15,10 +15,9 @@ static int sun50i_de2_bus_probe(struct platform_device *pdev) int ret; ret = sunxi_sram_claim(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "Error couldn't map SRAM to device\n"); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Couldn't map SRAM to device\n"); of_platform_populate(np, NULL, NULL, &pdev->dev); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 6a8b7fb5be58..54c0ee6dda30 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include @@ -51,11 +53,18 @@ struct sysc_address { struct list_head node; }; +struct sysc_module { + struct sysc *ddata; + struct list_head node; +}; + struct sysc_soc_info { unsigned long general_purpose:1; enum sysc_soc soc; - struct mutex list_lock; /* disabled modules list lock */ + struct mutex list_lock; /* disabled and restored modules list lock */ struct list_head disabled_modules; + struct list_head restored_modules; + struct notifier_block nb; }; enum sysc_clocks { @@ -131,6 +140,7 @@ struct sysc { struct ti_sysc_cookie cookie; const char *name; u32 revision; + u32 sysconfig; unsigned int reserved:1; unsigned int enabled:1; unsigned int needs_resume:1; @@ -147,6 +157,7 @@ struct sysc { static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, bool is_child); +static int sysc_reset(struct sysc *ddata); static void sysc_write(struct sysc *ddata, int offset, u32 value) { @@ -223,37 +234,77 @@ static u32 sysc_read_sysstatus(struct sysc *ddata) return sysc_read(ddata, offset); } -/* Poll on reset status */ -static int sysc_wait_softreset(struct sysc *ddata) +static int sysc_poll_reset_sysstatus(struct sysc *ddata) { - u32 sysc_mask, syss_done, rstval; - int syss_offset, error = 0; - - if (ddata->cap->regbits->srst_shift < 0) - return 0; - - syss_offset = ddata->offsets[SYSC_SYSSTATUS]; - sysc_mask = BIT(ddata->cap->regbits->srst_shift); + int error, retries; + u32 syss_done, rstval; if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED) syss_done = 0; else syss_done = ddata->cfg.syss_mask; - if (syss_offset >= 0) { + if (likely(!timekeeping_suspended)) { error = readx_poll_timeout_atomic(sysc_read_sysstatus, ddata, rstval, (rstval & ddata->cfg.syss_mask) == syss_done, 100, MAX_MODULE_SOFTRESET_WAIT); + } else { + retries = MAX_MODULE_SOFTRESET_WAIT; + while (retries--) { + rstval = sysc_read_sysstatus(ddata); + if ((rstval & ddata->cfg.syss_mask) == syss_done) + return 0; + udelay(2); /* Account for udelay flakeyness */ + } + error = -ETIMEDOUT; + } - } else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) { + return error; +} + +static int sysc_poll_reset_sysconfig(struct sysc *ddata) +{ + int error, retries; + u32 sysc_mask, rstval; + + sysc_mask = BIT(ddata->cap->regbits->srst_shift); + + if (likely(!timekeeping_suspended)) { error = readx_poll_timeout_atomic(sysc_read_sysconfig, ddata, rstval, !(rstval & sysc_mask), 100, MAX_MODULE_SOFTRESET_WAIT); + } else { + retries = MAX_MODULE_SOFTRESET_WAIT; + while (retries--) { + rstval = sysc_read_sysconfig(ddata); + if (!(rstval & sysc_mask)) + return 0; + udelay(2); /* Account for udelay flakeyness */ + } + error = -ETIMEDOUT; } return error; } +/* Poll on reset status */ +static int sysc_wait_softreset(struct sysc *ddata) +{ + int syss_offset, error = 0; + + if (ddata->cap->regbits->srst_shift < 0) + return 0; + + syss_offset = ddata->offsets[SYSC_SYSSTATUS]; + + if (syss_offset >= 0) + error = sysc_poll_reset_sysstatus(ddata); + else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) + error = sysc_poll_reset_sysconfig(ddata); + + return error; +} + static int sysc_add_named_clock_from_child(struct sysc *ddata, const char *name, const char *optfck_name) @@ -1094,7 +1145,8 @@ set_midle: best_mode = fls(ddata->cfg.midlemodes) - 1; if (best_mode > SYSC_IDLE_MASK) { dev_err(dev, "%s: invalid midlemode\n", __func__); - return -EINVAL; + error = -EINVAL; + goto save_context; } if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY) @@ -1112,13 +1164,16 @@ set_autoidle: sysc_write_sysconfig(ddata, reg); } - /* Flush posted write */ - sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); + error = 0; + +save_context: + /* Save context and flush posted write */ + ddata->sysconfig = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); if (ddata->module_enable_quirk) ddata->module_enable_quirk(ddata); - return 0; + return error; } static int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode) @@ -1175,8 +1230,10 @@ static int sysc_disable_module(struct device *dev) set_sidle: /* Set SIDLE mode */ idlemodes = ddata->cfg.sidlemodes; - if (!idlemodes || regbits->sidle_shift < 0) - return 0; + if (!idlemodes || regbits->sidle_shift < 0) { + ret = 0; + goto save_context; + } if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE) { best_mode = SYSC_IDLE_FORCE; @@ -1184,7 +1241,8 @@ set_sidle: ret = sysc_best_idle_mode(idlemodes, &best_mode); if (ret) { dev_err(dev, "%s: invalid sidlemode\n", __func__); - return ret; + ret = -EINVAL; + goto save_context; } } @@ -1195,10 +1253,13 @@ set_sidle: reg |= 1 << regbits->autoidle_shift; sysc_write_sysconfig(ddata, reg); - /* Flush posted write */ - sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); + ret = 0; - return 0; +save_context: + /* Save context and flush posted write */ + ddata->sysconfig = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); + + return ret; } static int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev, @@ -1336,13 +1397,40 @@ err_allow_idle: return error; } +/* + * Checks if device context was lost. Assumes the sysconfig register value + * after lost context is different from the configured value. Only works for + * enabled devices. + * + * Eventually we may want to also add support to using the context lost + * registers that some SoCs have. + */ +static int sysc_check_context(struct sysc *ddata) +{ + u32 reg; + + if (!ddata->enabled) + return -ENODATA; + + reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); + if (reg == ddata->sysconfig) + return 0; + + return -EACCES; +} + static int sysc_reinit_module(struct sysc *ddata, bool leave_enabled) { struct device *dev = ddata->dev; int error; - /* Disable target module if it is enabled */ if (ddata->enabled) { + /* Nothing to do if enabled and context not lost */ + error = sysc_check_context(ddata); + if (!error) + return 0; + + /* Disable target module if it is enabled */ error = sysc_runtime_suspend(dev); if (error) dev_warn(dev, "reinit suspend failed: %i\n", error); @@ -1353,6 +1441,15 @@ static int sysc_reinit_module(struct sysc *ddata, bool leave_enabled) if (error) dev_warn(dev, "reinit resume failed: %i\n", error); + /* Some modules like am335x gpmc need reset and restore of sysconfig */ + if (ddata->cfg.quirks & SYSC_QUIRK_RESET_ON_CTX_LOST) { + error = sysc_reset(ddata); + if (error) + dev_warn(dev, "reinit reset failed: %i\n", error); + + sysc_write_sysconfig(ddata, ddata->sysconfig); + } + if (leave_enabled) return error; @@ -1442,10 +1539,6 @@ struct sysc_revision_quirk { static const struct sysc_revision_quirk sysc_revision_quirks[] = { /* These drivers need to be fixed to not use pm_runtime_irq_safe() */ - SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff, - SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), - SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff, - SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff, @@ -1479,7 +1572,10 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK_CLKDM_NOAUTO), SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, SYSC_QUIRK_CLKDM_NOAUTO), + SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff, + SYSC_QUIRK_OPT_CLKS_IN_RESET), SYSC_QUIRK("gpmc", 0, 0, 0x10, 0x14, 0x00000060, 0xffffffff, + SYSC_QUIRK_REINIT_ON_CTX_LOST | SYSC_QUIRK_RESET_ON_CTX_LOST | SYSC_QUIRK_GPMC_DEBUG), SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50030200, 0xffffffff, SYSC_QUIRK_OPT_CLKS_NEEDED), @@ -1515,10 +1611,11 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, - 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), + 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY | + SYSC_MODULE_QUIRK_OTG), SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY | - SYSC_QUIRK_REINIT_ON_RESUME), + SYSC_QUIRK_REINIT_ON_CTX_LOST), SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, SYSC_MODULE_QUIRK_WDT), /* PRUSS on am3, am4 and am5 */ @@ -1583,6 +1680,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("sdio", 0, 0, 0x10, -ENODEV, 0x40202301, 0xffff0ff0, 0), SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0), SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0), + SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff, 0), SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40000902, 0xffffffff, 0), SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0), SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff, 0), @@ -1874,6 +1972,22 @@ static void sysc_module_lock_quirk_rtc(struct sysc *ddata) sysc_quirk_rtc(ddata, true); } +/* OTG omap2430 glue layer up to omap4 needs OTG_FORCESTDBY configured */ +static void sysc_module_enable_quirk_otg(struct sysc *ddata) +{ + int offset = 0x414; /* OTG_FORCESTDBY */ + + sysc_write(ddata, offset, 0); +} + +static void sysc_module_disable_quirk_otg(struct sysc *ddata) +{ + int offset = 0x414; /* OTG_FORCESTDBY */ + u32 val = BIT(0); /* ENABLEFORCE */ + + sysc_write(ddata, offset, val); +} + /* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */ static void sysc_module_enable_quirk_sgx(struct sysc *ddata) { @@ -1956,6 +2070,11 @@ static void sysc_init_module_quirks(struct sysc *ddata) return; } + if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_OTG) { + ddata->module_enable_quirk = sysc_module_enable_quirk_otg; + ddata->module_disable_quirk = sysc_module_disable_quirk_otg; + } + if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX) ddata->module_enable_quirk = sysc_module_enable_quirk_sgx; @@ -2401,6 +2520,78 @@ static struct dev_pm_domain sysc_child_pm_domain = { } }; +/* Caller needs to take list_lock if ever used outside of cpu_pm */ +static void sysc_reinit_modules(struct sysc_soc_info *soc) +{ + struct sysc_module *module; + struct list_head *pos; + struct sysc *ddata; + + list_for_each(pos, &sysc_soc->restored_modules) { + module = list_entry(pos, struct sysc_module, node); + ddata = module->ddata; + sysc_reinit_module(ddata, ddata->enabled); + } +} + +/** + * sysc_context_notifier - optionally reset and restore module after idle + * @nb: notifier block + * @cmd: unused + * @v: unused + * + * Some interconnect target modules need to be restored, or reset and restored + * on CPU_PM CPU_PM_CLUSTER_EXIT notifier. This is needed at least for am335x + * OTG and GPMC target modules even if the modules are unused. + */ +static int sysc_context_notifier(struct notifier_block *nb, unsigned long cmd, + void *v) +{ + struct sysc_soc_info *soc; + + soc = container_of(nb, struct sysc_soc_info, nb); + + switch (cmd) { + case CPU_CLUSTER_PM_ENTER: + break; + case CPU_CLUSTER_PM_ENTER_FAILED: /* No need to restore context */ + break; + case CPU_CLUSTER_PM_EXIT: + sysc_reinit_modules(soc); + break; + } + + return NOTIFY_OK; +} + +/** + * sysc_add_restored - optionally add reset and restore quirk hanlling + * @ddata: device data + */ +static void sysc_add_restored(struct sysc *ddata) +{ + struct sysc_module *restored_module; + + restored_module = kzalloc(sizeof(*restored_module), GFP_KERNEL); + if (!restored_module) + return; + + restored_module->ddata = ddata; + + mutex_lock(&sysc_soc->list_lock); + + list_add(&restored_module->node, &sysc_soc->restored_modules); + + if (sysc_soc->nb.notifier_call) + goto out_unlock; + + sysc_soc->nb.notifier_call = sysc_context_notifier; + cpu_pm_register_notifier(&sysc_soc->nb); + +out_unlock: + mutex_unlock(&sysc_soc->list_lock); +} + /** * sysc_legacy_idle_quirk - handle children in omap_device compatible way * @ddata: device driver data @@ -2900,12 +3091,14 @@ static int sysc_add_disabled(unsigned long base) } /* - * One time init to detect the booted SoC and disable unavailable features. + * One time init to detect the booted SoC, disable unavailable features + * and initialize list for optional cpu_pm notifier. + * * Note that we initialize static data shared across all ti-sysc instances * so ddata is only used for SoC type. This can be called from module_init * once we no longer need to rely on platform data. */ -static int sysc_init_soc(struct sysc *ddata) +static int sysc_init_static_data(struct sysc *ddata) { const struct soc_device_attribute *match; struct ti_sysc_platform_data *pdata; @@ -2921,6 +3114,7 @@ static int sysc_init_soc(struct sysc *ddata) mutex_init(&sysc_soc->list_lock); INIT_LIST_HEAD(&sysc_soc->disabled_modules); + INIT_LIST_HEAD(&sysc_soc->restored_modules); sysc_soc->general_purpose = true; pdata = dev_get_platdata(ddata->dev); @@ -2985,15 +3179,24 @@ static int sysc_init_soc(struct sysc *ddata) return 0; } -static void sysc_cleanup_soc(void) +static void sysc_cleanup_static_data(void) { + struct sysc_module *restored_module; struct sysc_address *disabled_module; struct list_head *pos, *tmp; if (!sysc_soc) return; + if (sysc_soc->nb.notifier_call) + cpu_pm_unregister_notifier(&sysc_soc->nb); + mutex_lock(&sysc_soc->list_lock); + list_for_each_safe(pos, tmp, &sysc_soc->restored_modules) { + restored_module = list_entry(pos, struct sysc_module, node); + list_del(pos); + kfree(restored_module); + } list_for_each_safe(pos, tmp, &sysc_soc->disabled_modules) { disabled_module = list_entry(pos, struct sysc_address, node); list_del(pos); @@ -3061,7 +3264,7 @@ static int sysc_probe(struct platform_device *pdev) ddata->dev = &pdev->dev; platform_set_drvdata(pdev, ddata); - error = sysc_init_soc(ddata); + error = sysc_init_static_data(ddata); if (error) return error; @@ -3159,6 +3362,9 @@ static int sysc_probe(struct platform_device *pdev) pm_runtime_put(&pdev->dev); } + if (ddata->cfg.quirks & SYSC_QUIRK_REINIT_ON_CTX_LOST) + sysc_add_restored(ddata); + return 0; err: @@ -3240,7 +3446,7 @@ static void __exit sysc_exit(void) { bus_unregister_notifier(&platform_bus_type, &sysc_nb); platform_driver_unregister(&sysc_driver); - sysc_cleanup_soc(); + sysc_cleanup_static_data(); } module_exit(sysc_exit); diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm index 334f83e56120..15d6c46c0a47 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -99,7 +99,7 @@ config ARM_MVEBU_V7_CPUIDLE config ARM_TEGRA_CPUIDLE bool "CPU Idle Driver for NVIDIA Tegra SoCs" - depends on ARCH_TEGRA && !ARM64 + depends on (ARCH_TEGRA || COMPILE_TEST) && !ARM64 && MMU select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP select ARM_CPU_SUSPEND help @@ -112,6 +112,7 @@ config ARM_QCOM_SPM_CPUIDLE select CPU_IDLE_MULTIPLE_DRIVERS select DT_IDLE_STATES select QCOM_SCM + select QCOM_SPM help Select this to enable cpuidle for Qualcomm processors. The Subsystem Power Manager (SPM) controls low power modes for the diff --git a/drivers/cpuidle/cpuidle-qcom-spm.c b/drivers/cpuidle/cpuidle-qcom-spm.c index c0e7971da2da..01e77913a414 100644 --- a/drivers/cpuidle/cpuidle-qcom-spm.c +++ b/drivers/cpuidle/cpuidle-qcom-spm.c @@ -18,158 +18,18 @@ #include #include #include +#include #include #include #include "dt_idle_states.h" -#define MAX_PMIC_DATA 2 -#define MAX_SEQ_DATA 64 -#define SPM_CTL_INDEX 0x7f -#define SPM_CTL_INDEX_SHIFT 4 -#define SPM_CTL_EN BIT(0) - -enum pm_sleep_mode { - PM_SLEEP_MODE_STBY, - PM_SLEEP_MODE_RET, - PM_SLEEP_MODE_SPC, - PM_SLEEP_MODE_PC, - PM_SLEEP_MODE_NR, -}; - -enum spm_reg { - SPM_REG_CFG, - SPM_REG_SPM_CTL, - SPM_REG_DLY, - SPM_REG_PMIC_DLY, - SPM_REG_PMIC_DATA_0, - SPM_REG_PMIC_DATA_1, - SPM_REG_VCTL, - SPM_REG_SEQ_ENTRY, - SPM_REG_SPM_STS, - SPM_REG_PMIC_STS, - SPM_REG_NR, -}; - -struct spm_reg_data { - const u8 *reg_offset; - u32 spm_cfg; - u32 spm_dly; - u32 pmic_dly; - u32 pmic_data[MAX_PMIC_DATA]; - u8 seq[MAX_SEQ_DATA]; - u8 start_index[PM_SLEEP_MODE_NR]; -}; - -struct spm_driver_data { +struct cpuidle_qcom_spm_data { struct cpuidle_driver cpuidle_driver; - void __iomem *reg_base; - const struct spm_reg_data *reg_data; + struct spm_driver_data *spm; }; -static const u8 spm_reg_offset_v2_1[SPM_REG_NR] = { - [SPM_REG_CFG] = 0x08, - [SPM_REG_SPM_CTL] = 0x30, - [SPM_REG_DLY] = 0x34, - [SPM_REG_SEQ_ENTRY] = 0x80, -}; - -/* SPM register data for 8974, 8084 */ -static const struct spm_reg_data spm_reg_8974_8084_cpu = { - .reg_offset = spm_reg_offset_v2_1, - .spm_cfg = 0x1, - .spm_dly = 0x3C102800, - .seq = { 0x03, 0x0B, 0x0F, 0x00, 0x20, 0x80, 0x10, 0xE8, 0x5B, 0x03, - 0x3B, 0xE8, 0x5B, 0x82, 0x10, 0x0B, 0x30, 0x06, 0x26, 0x30, - 0x0F }, - .start_index[PM_SLEEP_MODE_STBY] = 0, - .start_index[PM_SLEEP_MODE_SPC] = 3, -}; - -/* SPM register data for 8226 */ -static const struct spm_reg_data spm_reg_8226_cpu = { - .reg_offset = spm_reg_offset_v2_1, - .spm_cfg = 0x0, - .spm_dly = 0x3C102800, - .seq = { 0x60, 0x03, 0x60, 0x0B, 0x0F, 0x20, 0x10, 0x80, 0x30, 0x90, - 0x5B, 0x60, 0x03, 0x60, 0x3B, 0x76, 0x76, 0x0B, 0x94, 0x5B, - 0x80, 0x10, 0x26, 0x30, 0x0F }, - .start_index[PM_SLEEP_MODE_STBY] = 0, - .start_index[PM_SLEEP_MODE_SPC] = 5, -}; - -static const u8 spm_reg_offset_v1_1[SPM_REG_NR] = { - [SPM_REG_CFG] = 0x08, - [SPM_REG_SPM_CTL] = 0x20, - [SPM_REG_PMIC_DLY] = 0x24, - [SPM_REG_PMIC_DATA_0] = 0x28, - [SPM_REG_PMIC_DATA_1] = 0x2C, - [SPM_REG_SEQ_ENTRY] = 0x80, -}; - -/* SPM register data for 8064 */ -static const struct spm_reg_data spm_reg_8064_cpu = { - .reg_offset = spm_reg_offset_v1_1, - .spm_cfg = 0x1F, - .pmic_dly = 0x02020004, - .pmic_data[0] = 0x0084009C, - .pmic_data[1] = 0x00A4001C, - .seq = { 0x03, 0x0F, 0x00, 0x24, 0x54, 0x10, 0x09, 0x03, 0x01, - 0x10, 0x54, 0x30, 0x0C, 0x24, 0x30, 0x0F }, - .start_index[PM_SLEEP_MODE_STBY] = 0, - .start_index[PM_SLEEP_MODE_SPC] = 2, -}; - -static inline void spm_register_write(struct spm_driver_data *drv, - enum spm_reg reg, u32 val) -{ - if (drv->reg_data->reg_offset[reg]) - writel_relaxed(val, drv->reg_base + - drv->reg_data->reg_offset[reg]); -} - -/* Ensure a guaranteed write, before return */ -static inline void spm_register_write_sync(struct spm_driver_data *drv, - enum spm_reg reg, u32 val) -{ - u32 ret; - - if (!drv->reg_data->reg_offset[reg]) - return; - - do { - writel_relaxed(val, drv->reg_base + - drv->reg_data->reg_offset[reg]); - ret = readl_relaxed(drv->reg_base + - drv->reg_data->reg_offset[reg]); - if (ret == val) - break; - cpu_relax(); - } while (1); -} - -static inline u32 spm_register_read(struct spm_driver_data *drv, - enum spm_reg reg) -{ - return readl_relaxed(drv->reg_base + drv->reg_data->reg_offset[reg]); -} - -static void spm_set_low_power_mode(struct spm_driver_data *drv, - enum pm_sleep_mode mode) -{ - u32 start_index; - u32 ctl_val; - - start_index = drv->reg_data->start_index[mode]; - - ctl_val = spm_register_read(drv, SPM_REG_SPM_CTL); - ctl_val &= ~(SPM_CTL_INDEX << SPM_CTL_INDEX_SHIFT); - ctl_val |= start_index << SPM_CTL_INDEX_SHIFT; - ctl_val |= SPM_CTL_EN; - spm_register_write_sync(drv, SPM_REG_SPM_CTL, ctl_val); -} - static int qcom_pm_collapse(unsigned long int unused) { qcom_scm_cpu_power_down(QCOM_SCM_CPU_PWR_DOWN_L2_ON); @@ -201,10 +61,10 @@ static int qcom_cpu_spc(struct spm_driver_data *drv) static int spm_enter_idle_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, int idx) { - struct spm_driver_data *data = container_of(drv, struct spm_driver_data, - cpuidle_driver); + struct cpuidle_qcom_spm_data *data = container_of(drv, struct cpuidle_qcom_spm_data, + cpuidle_driver); - return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data); + return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data->spm); } static struct cpuidle_driver qcom_spm_idle_driver = { @@ -225,134 +85,92 @@ static const struct of_device_id qcom_idle_state_match[] = { { }, }; -static int spm_cpuidle_init(struct cpuidle_driver *drv, int cpu) +static int spm_cpuidle_register(struct device *cpuidle_dev, int cpu) { + struct platform_device *pdev = NULL; + struct device_node *cpu_node, *saw_node; + struct cpuidle_qcom_spm_data *data = NULL; int ret; - memcpy(drv, &qcom_spm_idle_driver, sizeof(*drv)); - drv->cpumask = (struct cpumask *)cpumask_of(cpu); + cpu_node = of_cpu_device_node_get(cpu); + if (!cpu_node) + return -ENODEV; - /* Parse idle states from device tree */ - ret = dt_init_idle_driver(drv, qcom_idle_state_match, 1); + saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0); + if (!saw_node) + return -ENODEV; + + pdev = of_find_device_by_node(saw_node); + of_node_put(saw_node); + of_node_put(cpu_node); + if (!pdev) + return -ENODEV; + + data = devm_kzalloc(cpuidle_dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->spm = dev_get_drvdata(&pdev->dev); + if (!data->spm) + return -EINVAL; + + data->cpuidle_driver = qcom_spm_idle_driver; + data->cpuidle_driver.cpumask = (struct cpumask *)cpumask_of(cpu); + + ret = dt_init_idle_driver(&data->cpuidle_driver, + qcom_idle_state_match, 1); if (ret <= 0) return ret ? : -ENODEV; - /* We have atleast one power down mode */ - return qcom_scm_set_warm_boot_addr(cpu_resume_arm, drv->cpumask); + ret = qcom_scm_set_warm_boot_addr(cpu_resume_arm, cpumask_of(cpu)); + if (ret) + return ret; + + return cpuidle_register(&data->cpuidle_driver, NULL); } -static struct spm_driver_data *spm_get_drv(struct platform_device *pdev, - int *spm_cpu) +static int spm_cpuidle_drv_probe(struct platform_device *pdev) { - struct spm_driver_data *drv = NULL; - struct device_node *cpu_node, *saw_node; - int cpu; - bool found = 0; - - for_each_possible_cpu(cpu) { - cpu_node = of_cpu_device_node_get(cpu); - if (!cpu_node) - continue; - saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0); - found = (saw_node == pdev->dev.of_node); - of_node_put(saw_node); - of_node_put(cpu_node); - if (found) - break; - } - - if (found) { - drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); - if (drv) - *spm_cpu = cpu; - } - - return drv; -} - -static const struct of_device_id spm_match_table[] = { - { .compatible = "qcom,msm8226-saw2-v2.1-cpu", - .data = &spm_reg_8226_cpu }, - { .compatible = "qcom,msm8974-saw2-v2.1-cpu", - .data = &spm_reg_8974_8084_cpu }, - { .compatible = "qcom,apq8084-saw2-v2.1-cpu", - .data = &spm_reg_8974_8084_cpu }, - { .compatible = "qcom,apq8064-saw2-v1.1-cpu", - .data = &spm_reg_8064_cpu }, - { }, -}; - -static int spm_dev_probe(struct platform_device *pdev) -{ - struct spm_driver_data *drv; - struct resource *res; - const struct of_device_id *match_id; - void __iomem *addr; int cpu, ret; if (!qcom_scm_is_available()) return -EPROBE_DEFER; - drv = spm_get_drv(pdev, &cpu); - if (!drv) - return -EINVAL; - platform_set_drvdata(pdev, drv); + for_each_possible_cpu(cpu) { + ret = spm_cpuidle_register(&pdev->dev, cpu); + if (ret && ret != -ENODEV) { + dev_err(&pdev->dev, + "Cannot register for CPU%d: %d\n", cpu, ret); + } + } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - drv->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(drv->reg_base)) - return PTR_ERR(drv->reg_base); - - match_id = of_match_node(spm_match_table, pdev->dev.of_node); - if (!match_id) - return -ENODEV; - - drv->reg_data = match_id->data; - - ret = spm_cpuidle_init(&drv->cpuidle_driver, cpu); - if (ret) - return ret; - - /* Write the SPM sequences first.. */ - addr = drv->reg_base + drv->reg_data->reg_offset[SPM_REG_SEQ_ENTRY]; - __iowrite32_copy(addr, drv->reg_data->seq, - ARRAY_SIZE(drv->reg_data->seq) / 4); - - /* - * ..and then the control registers. - * On some SoC if the control registers are written first and if the - * CPU was held in reset, the reset signal could trigger the SPM state - * machine, before the sequences are completely written. - */ - spm_register_write(drv, SPM_REG_CFG, drv->reg_data->spm_cfg); - spm_register_write(drv, SPM_REG_DLY, drv->reg_data->spm_dly); - spm_register_write(drv, SPM_REG_PMIC_DLY, drv->reg_data->pmic_dly); - spm_register_write(drv, SPM_REG_PMIC_DATA_0, - drv->reg_data->pmic_data[0]); - spm_register_write(drv, SPM_REG_PMIC_DATA_1, - drv->reg_data->pmic_data[1]); - - /* Set up Standby as the default low power mode */ - spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY); - - return cpuidle_register(&drv->cpuidle_driver, NULL); -} - -static int spm_dev_remove(struct platform_device *pdev) -{ - struct spm_driver_data *drv = platform_get_drvdata(pdev); - - cpuidle_unregister(&drv->cpuidle_driver); return 0; } -static struct platform_driver spm_driver = { - .probe = spm_dev_probe, - .remove = spm_dev_remove, +static struct platform_driver spm_cpuidle_driver = { + .probe = spm_cpuidle_drv_probe, .driver = { - .name = "saw", - .of_match_table = spm_match_table, + .name = "qcom-spm-cpuidle", + .suppress_bind_attrs = true, }, }; -builtin_platform_driver(spm_driver); +static int __init qcom_spm_cpuidle_init(void) +{ + struct platform_device *pdev; + int ret; + + ret = platform_driver_register(&spm_cpuidle_driver); + if (ret) + return ret; + + pdev = platform_device_register_simple("qcom-spm-cpuidle", + -1, NULL, 0); + if (IS_ERR(pdev)) { + platform_driver_unregister(&spm_cpuidle_driver); + return PTR_ERR(pdev); + } + + return 0; +} +device_initcall(qcom_spm_cpuidle_init); diff --git a/drivers/cpuidle/cpuidle-tegra.c b/drivers/cpuidle/cpuidle-tegra.c index 508bd9f23792..9845629aeb6d 100644 --- a/drivers/cpuidle/cpuidle-tegra.c +++ b/drivers/cpuidle/cpuidle-tegra.c @@ -337,6 +337,9 @@ static void tegra_cpuidle_setup_tegra114_c7_state(void) static int tegra_cpuidle_probe(struct platform_device *pdev) { + if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NOT_READY) + return -EPROBE_DEFER; + /* LP2 could be disabled in device-tree */ if (tegra_pmc_get_suspend_mode() < TEGRA_SUSPEND_LP2) tegra_cpuidle_disable_state(TEGRA_CC6); diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index c9fb56afbcb4..14f900047ac0 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -167,6 +167,27 @@ struct ffa_drv_info { static struct ffa_drv_info *drv_info; +/* + * The driver must be able to support all the versions from the earliest + * supported FFA_MIN_VERSION to the latest supported FFA_DRIVER_VERSION. + * The specification states that if firmware supports a FFA implementation + * that is incompatible with and at a greater version number than specified + * by the caller(FFA_DRIVER_VERSION passed as parameter to FFA_VERSION), + * it must return the NOT_SUPPORTED error code. + */ +static u32 ffa_compatible_version_find(u32 version) +{ + u16 major = MAJOR_VERSION(version), minor = MINOR_VERSION(version); + u16 drv_major = MAJOR_VERSION(FFA_DRIVER_VERSION); + u16 drv_minor = MINOR_VERSION(FFA_DRIVER_VERSION); + + if ((major < drv_major) || (major == drv_major && minor <= drv_minor)) + return version; + + pr_info("Firmware version higher than driver version, downgrading\n"); + return FFA_DRIVER_VERSION; +} + static int ffa_version_check(u32 *version) { ffa_value_t ver; @@ -180,15 +201,20 @@ static int ffa_version_check(u32 *version) return -EOPNOTSUPP; } - if (ver.a0 < FFA_MIN_VERSION || ver.a0 > FFA_DRIVER_VERSION) { - pr_err("Incompatible version %d.%d found\n", - MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0)); + if (ver.a0 < FFA_MIN_VERSION) { + pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n", + MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0), + MAJOR_VERSION(FFA_MIN_VERSION), + MINOR_VERSION(FFA_MIN_VERSION)); return -EINVAL; } - *version = ver.a0; - pr_info("Version %d.%d found\n", MAJOR_VERSION(ver.a0), + pr_info("Driver version %d.%d\n", MAJOR_VERSION(FFA_DRIVER_VERSION), + MINOR_VERSION(FFA_DRIVER_VERSION)); + pr_info("Firmware version %d.%d found\n", MAJOR_VERSION(ver.a0), MINOR_VERSION(ver.a0)); + *version = ffa_compatible_version_find(ver.a0); + return 0; } @@ -586,6 +612,22 @@ ffa_memory_share(struct ffa_device *dev, struct ffa_mem_ops_args *args) return ffa_memory_ops(FFA_FN_NATIVE(MEM_SHARE), args); } +static int +ffa_memory_lend(struct ffa_device *dev, struct ffa_mem_ops_args *args) +{ + /* Note that upon a successful MEM_LEND request the caller + * must ensure that the memory region specified is not accessed + * until a successful MEM_RECALIM call has been made. + * On systems with a hypervisor present this will been enforced, + * however on systems without a hypervisor the responsibility + * falls to the calling kernel driver to prevent access. + */ + if (dev->mode_32bit) + return ffa_memory_ops(FFA_MEM_LEND, args); + + return ffa_memory_ops(FFA_FN_NATIVE(MEM_LEND), args); +} + static const struct ffa_dev_ops ffa_ops = { .api_version_get = ffa_api_version_get, .partition_info_get = ffa_partition_info_get, @@ -593,6 +635,7 @@ static const struct ffa_dev_ops ffa_ops = { .sync_send_receive = ffa_sync_send_receive, .memory_reclaim = ffa_memory_reclaim, .memory_share = ffa_memory_share, + .memory_lend = ffa_memory_lend, }; const struct ffa_dev_ops *ffa_dev_ops_get(struct ffa_device *dev) diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 2ee97bab7440..7db8066b19fd 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -252,7 +252,7 @@ static bool __qcom_scm_is_call_available(struct device *dev, u32 svc_id, break; default: pr_err("Unknown SMC convention being used\n"); - return -EINVAL; + return false; } ret = qcom_scm_call(dev, &desc, &res); @@ -1348,6 +1348,10 @@ static const struct of_device_id qcom_scm_dt_match[] = { 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) diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c index 3e9fa4b54358..6d66fe03fb6a 100644 --- a/drivers/firmware/tegra/bpmp-debugfs.c +++ b/drivers/firmware/tegra/bpmp-debugfs.c @@ -74,28 +74,36 @@ static void seqbuf_seek(struct seqbuf *seqbuf, ssize_t offset) static const char *get_filename(struct tegra_bpmp *bpmp, const struct file *file, char *buf, int size) { - char root_path_buf[512]; - const char *root_path; - const char *filename; + const char *root_path, *filename = NULL; + char *root_path_buf; size_t root_len; + root_path_buf = kzalloc(512, GFP_KERNEL); + if (!root_path_buf) + goto out; + root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf, sizeof(root_path_buf)); if (IS_ERR(root_path)) - return NULL; + goto out; root_len = strlen(root_path); filename = dentry_path(file->f_path.dentry, buf, size); - if (IS_ERR(filename)) - return NULL; + if (IS_ERR(filename)) { + filename = NULL; + goto out; + } - if (strlen(filename) < root_len || - strncmp(filename, root_path, root_len)) - return NULL; + if (strlen(filename) < root_len || strncmp(filename, root_path, root_len)) { + filename = NULL; + goto out; + } filename += root_len; +out: + kfree(root_path_buf); return filename; } diff --git a/drivers/firmware/tegra/bpmp-tegra210.c b/drivers/firmware/tegra/bpmp-tegra210.c index c32754055c60..c9c830f658c3 100644 --- a/drivers/firmware/tegra/bpmp-tegra210.c +++ b/drivers/firmware/tegra/bpmp-tegra210.c @@ -162,7 +162,6 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp) { struct platform_device *pdev = to_platform_device(bpmp->dev); struct tegra210_bpmp *priv; - struct resource *res; unsigned int i; int err; @@ -172,13 +171,11 @@ static int tegra210_bpmp_init(struct tegra_bpmp *bpmp) bpmp->priv = priv; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->atomics = devm_ioremap_resource(&pdev->dev, res); + priv->atomics = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->atomics)) return PTR_ERR(priv->atomics); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - priv->arb_sema = devm_ioremap_resource(&pdev->dev, res); + priv->arb_sema = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(priv->arb_sema)) return PTR_ERR(priv->arb_sema); diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 93b40c245f00..5d90d2eb0019 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -11,6 +11,7 @@ #include #include #include +#include #include