diff options
140 files changed, 4384 insertions, 835 deletions
diff --git a/Documentation/dev-tools/kunit/api/clk.rst b/Documentation/dev-tools/kunit/api/clk.rst new file mode 100644 index 000000000000..eeaa50089453 --- /dev/null +++ b/Documentation/dev-tools/kunit/api/clk.rst @@ -0,0 +1,10 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======== +Clk API +======== + +The KUnit clk API is used to test clk providers and clk consumers. + +.. kernel-doc:: drivers/clk/clk_kunit_helpers.c + :export: diff --git a/Documentation/dev-tools/kunit/api/index.rst b/Documentation/dev-tools/kunit/api/index.rst index 2d8f756aab56..5cdb552a0808 100644 --- a/Documentation/dev-tools/kunit/api/index.rst +++ b/Documentation/dev-tools/kunit/api/index.rst @@ -9,11 +9,17 @@ API Reference test resource functionredirection + clk + of + platformdevice This page documents the KUnit kernel testing API. It is divided into the following sections: +Core KUnit API +============== + Documentation/dev-tools/kunit/api/test.rst - Documents all of the standard testing API @@ -25,3 +31,18 @@ Documentation/dev-tools/kunit/api/resource.rst Documentation/dev-tools/kunit/api/functionredirection.rst - Documents the KUnit Function Redirection API + +Driver KUnit API +================ + +Documentation/dev-tools/kunit/api/clk.rst + + - Documents the KUnit clk API + +Documentation/dev-tools/kunit/api/of.rst + + - Documents the KUnit device tree (OF) API + +Documentation/dev-tools/kunit/api/platformdevice.rst + + - Documents the KUnit platform device API diff --git a/Documentation/dev-tools/kunit/api/of.rst b/Documentation/dev-tools/kunit/api/of.rst new file mode 100644 index 000000000000..cb4193dcddbb --- /dev/null +++ b/Documentation/dev-tools/kunit/api/of.rst @@ -0,0 +1,13 @@ +.. SPDX-License-Identifier: GPL-2.0 + +==================== +Device Tree (OF) API +==================== + +The KUnit device tree API is used to test device tree (of_*) dependent code. + +.. kernel-doc:: include/kunit/of.h + :internal: + +.. kernel-doc:: drivers/of/of_kunit_helpers.c + :export: diff --git a/Documentation/dev-tools/kunit/api/platformdevice.rst b/Documentation/dev-tools/kunit/api/platformdevice.rst new file mode 100644 index 000000000000..49ddd5729003 --- /dev/null +++ b/Documentation/dev-tools/kunit/api/platformdevice.rst @@ -0,0 +1,10 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================== +Platform Device API +=================== + +The KUnit platform device API is used to test platform devices. + +.. kernel-doc:: lib/kunit/platform.c + :export: diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt deleted file mode 100644 index 149567a38215..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,bdpsys.txt +++ /dev/null @@ -1,24 +0,0 @@ -Mediatek bdpsys controller -============================ - -The Mediatek bdpsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be: - - "mediatek,mt2701-bdpsys", "syscon" - - "mediatek,mt2712-bdpsys", "syscon" - - "mediatek,mt7623-bdpsys", "mediatek,mt2701-bdpsys", "syscon" -- #clock-cells: Must be 1 - -The bdpsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -bdpsys: clock-controller@1c000000 { - compatible = "mediatek,mt2701-bdpsys", "syscon"; - reg = <0 0x1c000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,camsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,camsys.txt deleted file mode 100644 index a0ce82085ad0..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,camsys.txt +++ /dev/null @@ -1,24 +0,0 @@ -MediaTek CAMSYS controller -============================ - -The MediaTek camsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt6765-camsys", "syscon" - - "mediatek,mt6779-camsys", "syscon" - - "mediatek,mt8183-camsys", "syscon" -- #clock-cells: Must be 1 - -The camsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -camsys: camsys@1a000000 { - compatible = "mediatek,mt8183-camsys", "syscon"; - reg = <0 0x1a000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt deleted file mode 100644 index dce4c9241932..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,imgsys.txt +++ /dev/null @@ -1,30 +0,0 @@ -Mediatek imgsys controller -============================ - -The Mediatek imgsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt2701-imgsys", "syscon" - - "mediatek,mt2712-imgsys", "syscon" - - "mediatek,mt6765-imgsys", "syscon" - - "mediatek,mt6779-imgsys", "syscon" - - "mediatek,mt6797-imgsys", "syscon" - - "mediatek,mt7623-imgsys", "mediatek,mt2701-imgsys", "syscon" - - "mediatek,mt8167-imgsys", "syscon" - - "mediatek,mt8173-imgsys", "syscon" - - "mediatek,mt8183-imgsys", "syscon" -- #clock-cells: Must be 1 - -The imgsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -imgsys: clock-controller@15000000 { - compatible = "mediatek,mt8173-imgsys", "syscon"; - reg = <0 0x15000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipesys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipesys.txt deleted file mode 100644 index 2ce889b023d9..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipesys.txt +++ /dev/null @@ -1,22 +0,0 @@ -Mediatek ipesys controller -============================ - -The Mediatek ipesys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt6779-ipesys", "syscon" -- #clock-cells: Must be 1 - -The ipesys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -ipesys: clock-controller@1b000000 { - compatible = "mediatek,mt6779-ipesys", "syscon"; - reg = <0 0x1b000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipu.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipu.txt deleted file mode 100644 index aabc8c5c8ed2..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,ipu.txt +++ /dev/null @@ -1,43 +0,0 @@ -Mediatek IPU controller -============================ - -The Mediatek ipu controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt8183-ipu_conn", "syscon" - - "mediatek,mt8183-ipu_adl", "syscon" - - "mediatek,mt8183-ipu_core0", "syscon" - - "mediatek,mt8183-ipu_core1", "syscon" -- #clock-cells: Must be 1 - -The ipu controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -ipu_conn: syscon@19000000 { - compatible = "mediatek,mt8183-ipu_conn", "syscon"; - reg = <0 0x19000000 0 0x1000>; - #clock-cells = <1>; -}; - -ipu_adl: syscon@19010000 { - compatible = "mediatek,mt8183-ipu_adl", "syscon"; - reg = <0 0x19010000 0 0x1000>; - #clock-cells = <1>; -}; - -ipu_core0: syscon@19180000 { - compatible = "mediatek,mt8183-ipu_core0", "syscon"; - reg = <0 0x19180000 0 0x1000>; - #clock-cells = <1>; -}; - -ipu_core1: syscon@19280000 { - compatible = "mediatek,mt8183-ipu_core1", "syscon"; - reg = <0 0x19280000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,jpgdecsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,jpgdecsys.txt deleted file mode 100644 index 2df799cd06a7..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,jpgdecsys.txt +++ /dev/null @@ -1,22 +0,0 @@ -Mediatek jpgdecsys controller -============================ - -The Mediatek jpgdecsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be: - - "mediatek,mt2712-jpgdecsys", "syscon" -- #clock-cells: Must be 1 - -The jpgdecsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -jpgdecsys: syscon@19000000 { - compatible = "mediatek,mt2712-jpgdecsys", "syscon"; - reg = <0 0x19000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mcucfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mcucfg.txt deleted file mode 100644 index 2b882b7ca72e..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mcucfg.txt +++ /dev/null @@ -1,23 +0,0 @@ -Mediatek mcucfg controller -============================ - -The Mediatek mcucfg controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt2712-mcucfg", "syscon" - - "mediatek,mt8183-mcucfg", "syscon" -- #clock-cells: Must be 1 - -The mcucfg controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -mcucfg: syscon@10220000 { - compatible = "mediatek,mt2712-mcucfg", "syscon"; - reg = <0 0x10220000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mfgcfg.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mfgcfg.txt deleted file mode 100644 index 054424fb64b4..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mfgcfg.txt +++ /dev/null @@ -1,25 +0,0 @@ -Mediatek mfgcfg controller -============================ - -The Mediatek mfgcfg controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt2712-mfgcfg", "syscon" - - "mediatek,mt6779-mfgcfg", "syscon" - - "mediatek,mt8167-mfgcfg", "syscon" - - "mediatek,mt8183-mfgcfg", "syscon" -- #clock-cells: Must be 1 - -The mfgcfg controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -mfgcfg: syscon@13000000 { - compatible = "mediatek,mt2712-mfgcfg", "syscon"; - reg = <0 0x13000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mipi0a.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,mipi0a.txt deleted file mode 100644 index 1c671943ce4d..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mipi0a.txt +++ /dev/null @@ -1,28 +0,0 @@ -Mediatek mipi0a (mipi_rx_ana_csi0a) controller -============================ - -The Mediatek mipi0a controller provides various clocks -to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt6765-mipi0a", "syscon" -- #clock-cells: Must be 1 - -The mipi0a controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -The mipi0a controller also uses the common power domain from -Documentation/devicetree/bindings/soc/mediatek/scpsys.txt -The available power domains are defined in dt-bindings/power/mt*-power.h. - -Example: - -mipi0a: clock-controller@11c10000 { - compatible = "mediatek,mt6765-mipi0a", "syscon"; - reg = <0 0x11c10000 0 0x1000>; - power-domains = <&scpsys MT6765_POWER_DOMAIN_CAM>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vcodecsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vcodecsys.txt deleted file mode 100644 index f090147b7f1e..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vcodecsys.txt +++ /dev/null @@ -1,27 +0,0 @@ -Mediatek vcodecsys controller -============================ - -The Mediatek vcodecsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt6765-vcodecsys", "syscon" -- #clock-cells: Must be 1 - -The vcodecsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -The vcodecsys controller also uses the common power domain from -Documentation/devicetree/bindings/soc/mediatek/scpsys.txt -The available power domains are defined in dt-bindings/power/mt*-power.h. - -Example: - -venc_gcon: clock-controller@17000000 { - compatible = "mediatek,mt6765-vcodecsys", "syscon"; - reg = <0 0x17000000 0 0x10000>; - power-domains = <&scpsys MT6765_POWER_DOMAIN_VCODEC>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt deleted file mode 100644 index 98195169176a..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vdecsys.txt +++ /dev/null @@ -1,29 +0,0 @@ -Mediatek vdecsys controller -============================ - -The Mediatek vdecsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt2701-vdecsys", "syscon" - - "mediatek,mt2712-vdecsys", "syscon" - - "mediatek,mt6779-vdecsys", "syscon" - - "mediatek,mt6797-vdecsys", "syscon" - - "mediatek,mt7623-vdecsys", "mediatek,mt2701-vdecsys", "syscon" - - "mediatek,mt8167-vdecsys", "syscon" - - "mediatek,mt8173-vdecsys", "syscon" - - "mediatek,mt8183-vdecsys", "syscon" -- #clock-cells: Must be 1 - -The vdecsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -vdecsys: clock-controller@16000000 { - compatible = "mediatek,mt8173-vdecsys", "syscon"; - reg = <0 0x16000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencltsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencltsys.txt deleted file mode 100644 index 3cc299fd7857..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencltsys.txt +++ /dev/null @@ -1,22 +0,0 @@ -Mediatek vencltsys controller -============================ - -The Mediatek vencltsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be: - - "mediatek,mt8173-vencltsys", "syscon" -- #clock-cells: Must be 1 - -The vencltsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -vencltsys: clock-controller@19000000 { - compatible = "mediatek,mt8173-vencltsys", "syscon"; - reg = <0 0x19000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencsys.txt b/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencsys.txt deleted file mode 100644 index 6a6a14e15cd7..000000000000 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,vencsys.txt +++ /dev/null @@ -1,26 +0,0 @@ -Mediatek vencsys controller -============================ - -The Mediatek vencsys controller provides various clocks to the system. - -Required Properties: - -- compatible: Should be one of: - - "mediatek,mt2712-vencsys", "syscon" - - "mediatek,mt6779-vencsys", "syscon" - - "mediatek,mt6797-vencsys", "syscon" - - "mediatek,mt8173-vencsys", "syscon" - - "mediatek,mt8183-vencsys", "syscon" -- #clock-cells: Must be 1 - -The vencsys controller uses the common clk binding from -Documentation/devicetree/bindings/clock/clock-bindings.txt -The available clocks are defined in dt-bindings/clock/mt*-clk.h. - -Example: - -vencsys: clock-controller@18000000 { - compatible = "mediatek,mt8173-vencsys", "syscon"; - reg = <0 0x18000000 0 0x1000>; - #clock-cells = <1>; -}; diff --git a/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-div.yaml b/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-div.yaml index bd4cefbb1244..30252c95700c 100644 --- a/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-div.yaml +++ b/Documentation/devicetree/bindings/clock/baikal,bt1-ccu-div.yaml @@ -134,9 +134,13 @@ properties: "#reset-cells": const: 1 - clocks: true + clocks: + minItems: 3 + maxItems: 4 - clock-names: true + clock-names: + minItems: 3 + maxItems: 4 additionalProperties: false diff --git a/Documentation/devicetree/bindings/clock/cirrus,lochnagar.yaml b/Documentation/devicetree/bindings/clock/cirrus,lochnagar.yaml index 59de125647ec..ccff74eda9fb 100644 --- a/Documentation/devicetree/bindings/clock/cirrus,lochnagar.yaml +++ b/Documentation/devicetree/bindings/clock/cirrus,lochnagar.yaml @@ -67,9 +67,9 @@ properties: minItems: 1 maxItems: 19 - clocks: true - assigned-clocks: true - assigned-clock-parents: true + clocks: + minItems: 1 + maxItems: 19 additionalProperties: false diff --git a/Documentation/devicetree/bindings/clock/imx8mp-audiomix.yaml b/Documentation/devicetree/bindings/clock/imx8mp-audiomix.yaml index 0a6dc1a6e122..6588a17a7d9a 100644 --- a/Documentation/devicetree/bindings/clock/imx8mp-audiomix.yaml +++ b/Documentation/devicetree/bindings/clock/imx8mp-audiomix.yaml @@ -44,6 +44,9 @@ properties: ID in its "clocks" phandle cell. See include/dt-bindings/clock/imx8mp-clock.h for the full list of i.MX8MP IMX8MP_CLK_AUDIOMIX_ clock IDs. + '#reset-cells': + const: 1 + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml index 685535846cbb..db5f48e4dd15 100644 --- a/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,apmixedsys.yaml @@ -35,7 +35,7 @@ properties: - mediatek,mt2701-apmixedsys - mediatek,mt2712-apmixedsys - mediatek,mt6765-apmixedsys - - mediatek,mt6779-apmixedsys + - mediatek,mt6779-apmixed - mediatek,mt6795-apmixedsys - mediatek,mt7629-apmixedsys - mediatek,mt8167-apmixedsys diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml b/Documentation/devicetree/bindings/clock/mediatek,infracfg.yaml index 230b5188a88d..252c46d316ee 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,infracfg.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,infracfg.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/mediatek/mediatek,infracfg.yaml# +$id: http://devicetree.org/schemas/clock/mediatek,infracfg.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: MediaTek Infrastructure System Configuration Controller diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8186-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml index 7cd14b163abe..f4e58bfa504f 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8186-clock.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-clock.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8186-clock.yaml# +$id: http://devicetree.org/schemas/clock/mediatek,mt8186-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: MediaTek Functional Clock Controller for MT8186 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8186-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml index 64c769416690..1c446fbc5108 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8186-sys-clock.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8186-sys-clock.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8186-sys-clock.yaml# +$id: http://devicetree.org/schemas/clock/mediatek,mt8186-sys-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: MediaTek System Clock Controller for MT8186 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8192-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8192-clock.yaml index dff4c8e8fd4b..b8d690e28bdc 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8192-clock.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8192-clock.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8192-clock.yaml# +$id: http://devicetree.org/schemas/clock/mediatek,mt8192-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: MediaTek Functional Clock Controller for MT8192 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8192-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8192-sys-clock.yaml index 8d608fddf3f9..bf8c9aacdf1e 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8192-sys-clock.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8192-sys-clock.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8192-sys-clock.yaml# +$id: http://devicetree.org/schemas/clock/mediatek,mt8192-sys-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: MediaTek System Clock Controller for MT8192 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8195-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8195-clock.yaml index d17164b0b13e..fcc963aff087 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8195-clock.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8195-clock.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8195-clock.yaml# +$id: http://devicetree.org/schemas/clock/mediatek,mt8195-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: MediaTek Functional Clock Controller for MT8195 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8195-sys-clock.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt8195-sys-clock.yaml index 066c9b3d6ac9..69f096eb168d 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,mt8195-sys-clock.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,mt8195-sys-clock.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/mediatek/mediatek,mt8195-sys-clock.yaml# +$id: http://devicetree.org/schemas/clock/mediatek,mt8195-sys-clock.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: MediaTek System Clock Controller for MT8195 diff --git a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml b/Documentation/devicetree/bindings/clock/mediatek,pericfg.yaml index 33c94c491828..2f06baecfd23 100644 --- a/Documentation/devicetree/bindings/arm/mediatek/mediatek,pericfg.yaml +++ b/Documentation/devicetree/bindings/clock/mediatek,pericfg.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/arm/mediatek/mediatek,pericfg.yaml# +$id: http://devicetree.org/schemas/clock/mediatek,pericfg.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: MediaTek Peripheral Configuration Controller diff --git a/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml b/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml new file mode 100644 index 000000000000..10483e26878f --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,syscon.yaml @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,syscon.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MediaTek Clock controller syscon's + +maintainers: + - Matthias Brugger <[email protected]> + - AngeloGioacchino Del Regno <[email protected]> + +description: + The MediaTek clock controller syscon's provide various clocks to the system. + +properties: + compatible: + oneOf: + - items: + - enum: + - mediatek,mt2701-bdpsys + - mediatek,mt2701-imgsys + - mediatek,mt2701-vdecsys + - mediatek,mt2712-bdpsys + - mediatek,mt2712-imgsys + - mediatek,mt2712-jpgdecsys + - mediatek,mt2712-mcucfg + - mediatek,mt2712-mfgcfg + - mediatek,mt2712-vdecsys + - mediatek,mt2712-vencsys + - mediatek,mt6765-camsys + - mediatek,mt6765-imgsys + - mediatek,mt6765-mipi0a + - mediatek,mt6765-vcodecsys + - mediatek,mt6779-camsys + - mediatek,mt6779-imgsys + - mediatek,mt6779-ipesys + - mediatek,mt6779-mfgcfg + - mediatek,mt6779-vdecsys + - mediatek,mt6779-vencsys + - mediatek,mt6797-imgsys + - mediatek,mt6797-vdecsys + - mediatek,mt6797-vencsys + - mediatek,mt8167-imgsys + - mediatek,mt8167-mfgcfg + - mediatek,mt8167-vdecsys + - mediatek,mt8173-imgsys + - mediatek,mt8173-vdecsys + - mediatek,mt8173-vencltsys + - mediatek,mt8173-vencsys + - mediatek,mt8183-camsys + - mediatek,mt8183-imgsys + - mediatek,mt8183-ipu_conn + - mediatek,mt8183-ipu_adl + - mediatek,mt8183-ipu_core0 + - mediatek,mt8183-ipu_core1 + - mediatek,mt8183-mcucfg + - mediatek,mt8183-mfgcfg + - mediatek,mt8183-vdecsys + - mediatek,mt8183-vencsys + - const: syscon + - items: + - const: mediatek,mt7623-bdpsys + - const: mediatek,mt2701-bdpsys + - const: syscon + - items: + - const: mediatek,mt7623-imgsys + - const: mediatek,mt2701-imgsys + - const: syscon + - items: + - const: mediatek,mt7623-vdecsys + - const: mediatek,mt2701-vdecsys + - const: syscon + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clock-controller@11220000 { + compatible = "mediatek,mt2701-bdpsys", "syscon"; + reg = <0x11220000 0x2000>; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml index 2dffc02dcd8b..5dc360b2ea4b 100644 --- a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml +++ b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml @@ -16,6 +16,7 @@ properties: - nxp,imx95-lvds-csr - nxp,imx95-display-csr - nxp,imx95-camera-csr + - nxp,imx95-netcmix-blk-ctrl - nxp,imx95-vpu-csr - const: syscon diff --git a/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt b/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt deleted file mode 100644 index 20cbca3f41d8..000000000000 --- a/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.txt +++ /dev/null @@ -1,30 +0,0 @@ -NXP LPC32xx Clock Controller - -Required properties: -- compatible: should be "nxp,lpc3220-clk" -- reg: should contain clock controller registers location and length -- #clock-cells: must be 1, the cell holds id of a clock provided by the - clock controller -- clocks: phandles of external oscillators, the list must contain one - 32768 Hz oscillator and may have one optional high frequency oscillator -- clock-names: list of external oscillator clock names, must contain - "xtal_32k" and may have optional "xtal" - -Examples: - - /* System Control Block */ - scb { - compatible = "simple-bus"; - ranges = <0x0 0x040004000 0x00001000>; - #address-cells = <1>; - #size-cells = <1>; - - clk: clock-controller@0 { - compatible = "nxp,lpc3220-clk"; - reg = <0x00 0x114>; - #clock-cells = <1>; - - clocks = <&xtal_32k>, <&xtal>; - clock-names = "xtal_32k", "xtal"; - }; - }; diff --git a/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.yaml b/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.yaml new file mode 100644 index 000000000000..16f79616d18a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nxp,lpc3220-clk.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/nxp,lpc3220-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP LPC32xx Clock Controller + +maintainers: + - Animesh Agarwal <[email protected]> + +properties: + compatible: + const: nxp,lpc3220-clk + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + + clocks: + minItems: 1 + items: + - description: External 32768 Hz oscillator. + - description: Optional high frequency oscillator. + + clock-names: + minItems: 1 + items: + - const: xtal_32k + - const: xtal + +required: + - compatible + - reg + - '#clock-cells' + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + clock-controller@0 { + compatible = "nxp,lpc3220-clk"; + reg = <0x00 0x114>; + #clock-cells = <1>; + clocks = <&xtal_32k>, <&xtal>; + clock-names = "xtal_32k", "xtal"; + }; diff --git a/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt b/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt deleted file mode 100644 index 0aa249409b51..000000000000 --- a/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.txt +++ /dev/null @@ -1,22 +0,0 @@ -NXP LPC32xx USB Clock Controller - -Required properties: -- compatible: should be "nxp,lpc3220-usb-clk" -- reg: should contain clock controller registers location and length -- #clock-cells: must be 1, the cell holds id of a clock provided by the - USB clock controller - -Examples: - - usb { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - ranges = <0x0 0x31020000 0x00001000>; - - usbclk: clock-controller@f00 { - compatible = "nxp,lpc3220-usb-clk"; - reg = <0xf00 0x100>; - #clock-cells = <1>; - }; - }; diff --git a/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.yaml b/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.yaml new file mode 100644 index 000000000000..10361d2292fb --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nxp,lpc3220-usb-clk.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/nxp,lpc3220-usb-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP LPC32xx USB Clock Controller + +maintainers: + - Animesh Agarwal <[email protected]> + +properties: + compatible: + const: nxp,lpc3220-usb-clk + + reg: + maxItems: 1 + + '#clock-cells': + const: 1 + +required: + - compatible + - reg + - '#clock-cells' + +additionalProperties: false + +examples: + - | + clock-controller@f00 { + compatible = "nxp,lpc3220-usb-clk"; + reg = <0xf00 0x100>; + #clock-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-clocks.yaml b/Documentation/devicetree/bindings/clock/renesas,cpg-clocks.yaml index 9185d101737e..a0e09b7002f0 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-clocks.yaml +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-clocks.yaml @@ -32,12 +32,16 @@ properties: reg: maxItems: 1 - clocks: true + clocks: + minItems: 1 + maxItems: 3 '#clock-cells': const: 1 - clock-output-names: true + clock-output-names: + minItems: 3 + maxItems: 17 renesas,mode: description: Board-specific settings of the MD_CK* bits on R-Mobile A1 diff --git a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml index 084259d30232..77ce3615c65a 100644 --- a/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml +++ b/Documentation/devicetree/bindings/clock/renesas,cpg-mssr.yaml @@ -31,6 +31,7 @@ properties: - renesas,r8a7745-cpg-mssr # RZ/G1E - renesas,r8a77470-cpg-mssr # RZ/G1C - renesas,r8a774a1-cpg-mssr # RZ/G2M + - renesas,r8a774a3-cpg-mssr # RZ/G2M v3.0 - renesas,r8a774b1-cpg-mssr # RZ/G2N - renesas,r8a774c0-cpg-mssr # RZ/G2E - renesas,r8a774e1-cpg-mssr # RZ/G2H diff --git a/Documentation/devicetree/bindings/clock/renesas,rzv2h-cpg.yaml b/Documentation/devicetree/bindings/clock/renesas,rzv2h-cpg.yaml new file mode 100644 index 000000000000..926c503bed1f --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,rzv2h-cpg.yaml @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/renesas,rzv2h-cpg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Renesas RZ/V2H(P) Clock Pulse Generator (CPG) + +maintainers: + - Lad Prabhakar <[email protected]> + +description: + On Renesas RZ/V2H(P) SoCs, the CPG (Clock Pulse Generator) handles generation + and control of clock signals for the IP modules, generation and control of resets, + and control over booting, low power consumption and power supply domains. + +properties: + compatible: + const: renesas,r9a09g057-cpg + + reg: + maxItems: 1 + + clocks: + items: + - description: AUDIO_EXTAL clock input + - description: RTXIN clock input + - description: QEXTAL clock input + + clock-names: + items: + - const: audio_extal + - const: rtxin + - const: qextal + + '#clock-cells': + description: | + - For CPG core clocks, the two clock specifier cells must be "CPG_CORE" + and a core clock reference, as defined in + <dt-bindings/clock/renesas,r9a09g057-cpg.h>, + - For module clocks, the two clock specifier cells must be "CPG_MOD" and + a module number. The module number is calculated as the CLKON register + offset index multiplied by 16, plus the actual bit in the register + used to turn the CLK ON. For example, for CGC_GIC_0_GICCLK, the + calculation is (1 * 16 + 3) = 0x13. + const: 2 + + '#power-domain-cells': + const: 0 + + '#reset-cells': + description: + The single reset specifier cell must be the reset number. The reset number + is calculated as the reset register offset index multiplied by 16, plus the + actual bit in the register used to reset the specific IP block. For example, + for SYS_0_PRESETN, the calculation is (3 * 16 + 0) = 0x30. + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#power-domain-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + clock-controller@10420000 { + compatible = "renesas,r9a09g057-cpg"; + reg = <0x10420000 0x10000>; + clocks = <&audio_extal_clk>, <&rtxin_clk>, <&qextal_clk>; + clock-names = "audio_extal", "rtxin", "qextal"; + #clock-cells = <2>; + #power-domain-cells = <0>; + #reset-cells = <1>; + }; diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.yaml b/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.yaml index 5194be0b410e..9b3aaae546cb 100644 --- a/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.yaml +++ b/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.yaml @@ -60,8 +60,14 @@ properties: - st,stm32mp1-rcc - st,stm32mp13-rcc - const: syscon - clocks: true - clock-names: true + + clocks: + minItems: 1 + maxItems: 5 + + clock-names: + minItems: 1 + maxItems: 5 reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index a70ce43b3dc0..3761346045e1 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1476,6 +1476,8 @@ patternProperties: description: Terasic Inc. "^tesla,.*": description: Tesla, Inc. + "^test,.*": + description: Reserved for use by tests. For example, KUnit. "^tfc,.*": description: Three Five Corp "^thead,.*": diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 9b745ba54de1..964111361497 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -393,6 +393,7 @@ bool device_is_bound(struct device *dev) { return dev->p && klist_node_attached(&dev->p->knode_driver); } +EXPORT_SYMBOL_GPL(device_is_bound); static void driver_bound(struct device *dev) { diff --git a/drivers/clk/.kunitconfig b/drivers/clk/.kunitconfig index efa12ac2b3f2..54ece9207055 100644 --- a/drivers/clk/.kunitconfig +++ b/drivers/clk/.kunitconfig @@ -1,6 +1,8 @@ CONFIG_KUNIT=y +CONFIG_OF=y CONFIG_COMMON_CLK=y CONFIG_CLK_KUNIT_TEST=y +CONFIG_CLK_FIXED_RATE_KUNIT_TEST=y CONFIG_CLK_GATE_KUNIT_TEST=y CONFIG_CLK_FD_KUNIT_TEST=y CONFIG_UML_PCI_OVER_VIRTIO=n diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 983ef4f36d8c..260961668e48 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -509,9 +509,20 @@ config CLK_KUNIT_TEST tristate "Basic Clock Framework Kunit Tests" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS + select OF_OVERLAY if OF + select DTC help Kunit tests for the common clock framework. +config CLK_FIXED_RATE_KUNIT_TEST + tristate "Basic fixed rate clk type KUnit test" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + select OF_OVERLAY if OF + select DTC + help + KUnit tests for the basic fixed rate clk type. + config CLK_GATE_KUNIT_TEST tristate "Basic gate type Kunit test" if !KUNIT_ALL_TESTS depends on KUNIT diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f793a16cad40..9b783c3e5d2f 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -2,10 +2,14 @@ # common clock types obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o clkdev.o obj-$(CONFIG_COMMON_CLK) += clk.o -obj-$(CONFIG_CLK_KUNIT_TEST) += clk_test.o +obj-$(CONFIG_CLK_KUNIT_TEST) += clk-test.o +clk-test-y := clk_test.o \ + kunit_clk_parent_data_test.dtbo.o obj-$(CONFIG_COMMON_CLK) += clk-divider.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o +obj-$(CONFIG_CLK_FIXED_RATE_KUNIT_TEST) += clk-fixed-rate-test.o +clk-fixed-rate-test-y := clk-fixed-rate_test.o kunit_clk_fixed_rate_test.dtbo.o obj-$(CONFIG_COMMON_CLK) += clk-gate.o obj-$(CONFIG_CLK_GATE_KUNIT_TEST) += clk-gate_test.o obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o @@ -18,6 +22,11 @@ ifeq ($(CONFIG_OF), y) obj-$(CONFIG_COMMON_CLK) += clk-conf.o endif +# KUnit specific helpers +ifeq ($(CONFIG_COMMON_CLK), y) +obj-$(CONFIG_KUNIT) += clk_kunit_helpers.o +endif + # hardware specific clock types # please keep this section sorted lexicographically by file path name obj-$(CONFIG_COMMON_CLK_APPLE_NCO) += clk-apple-nco.o diff --git a/drivers/clk/at91/dt-compat.c b/drivers/clk/at91/dt-compat.c index a32dc2111b90..f5a5f9ba7634 100644 --- a/drivers/clk/at91/dt-compat.c +++ b/drivers/clk/at91/dt-compat.c @@ -563,9 +563,10 @@ of_at91_clk_pll_get_characteristics(struct device_node *np) if (num_cells < 2 || num_cells > 4) return NULL; - if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp)) + num_output = of_property_count_u32_elems(np, "atmel,pll-clk-output-ranges"); + if (num_output <= 0) return NULL; - num_output = tmp / (sizeof(u32) * num_cells); + num_output /= num_cells; characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); if (!characteristics) diff --git a/drivers/clk/bcm/clk-bcm53573-ilp.c b/drivers/clk/bcm/clk-bcm53573-ilp.c index 84f2af736ee8..83ef41d618be 100644 --- a/drivers/clk/bcm/clk-bcm53573-ilp.c +++ b/drivers/clk/bcm/clk-bcm53573-ilp.c @@ -112,7 +112,7 @@ static void bcm53573_ilp_init(struct device_node *np) goto err_free_ilp; } - ilp->regmap = syscon_node_to_regmap(of_get_parent(np)); + ilp->regmap = syscon_node_to_regmap(np->parent); if (IS_ERR(ilp->regmap)) { err = PTR_ERR(ilp->regmap); goto err_free_ilp; diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index 058420562020..303a0bb26e54 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -10,6 +10,7 @@ #include <linux/device.h> #include <linux/of.h> #include <linux/printk.h> +#include <linux/slab.h> static int __set_clk_parents(struct device_node *node, bool clk_supplier) { @@ -81,11 +82,44 @@ err: static int __set_clk_rates(struct device_node *node, bool clk_supplier) { struct of_phandle_args clkspec; - int rc, index = 0; + int rc, count, count_64, index; struct clk *clk; - u32 rate; + u64 *rates_64 __free(kfree) = NULL; + u32 *rates __free(kfree) = NULL; + + count = of_property_count_u32_elems(node, "assigned-clock-rates"); + count_64 = of_property_count_u64_elems(node, "assigned-clock-rates-u64"); + if (count_64 > 0) { + count = count_64; + rates_64 = kcalloc(count, sizeof(*rates_64), GFP_KERNEL); + if (!rates_64) + return -ENOMEM; + + rc = of_property_read_u64_array(node, + "assigned-clock-rates-u64", + rates_64, count); + } else if (count > 0) { + rates = kcalloc(count, sizeof(*rates), GFP_KERNEL); + if (!rates) + return -ENOMEM; + + rc = of_property_read_u32_array(node, "assigned-clock-rates", + rates, count); + } else { + return 0; + } + + if (rc) + return rc; + + for (index = 0; index < count; index++) { + unsigned long rate; + + if (rates_64) + rate = rates_64[index]; + else + rate = rates[index]; - of_property_for_each_u32(node, "assigned-clock-rates", rate) { if (rate) { rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells", index, &clkspec); @@ -112,12 +146,11 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) rc = clk_set_rate(clk, rate); if (rc < 0) - pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n", + pr_err("clk: couldn't set %s clk rate to %lu (%d), current rate: %lu\n", __clk_get_name(clk), rate, rc, clk_get_rate(clk)); clk_put(clk); } - index++; } return 0; } diff --git a/drivers/clk/clk-fixed-rate_test.c b/drivers/clk/clk-fixed-rate_test.c new file mode 100644 index 000000000000..0e04c10a21aa --- /dev/null +++ b/drivers/clk/clk-fixed-rate_test.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit test for clk fixed rate basic type + */ +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/completion.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include <kunit/clk.h> +#include <kunit/of.h> +#include <kunit/platform_device.h> +#include <kunit/resource.h> +#include <kunit/test.h> + +#include "clk-fixed-rate_test.h" + +/** + * struct clk_hw_fixed_rate_kunit_params - Parameters to pass to __clk_hw_register_fixed_rate() + * @dev: device registering clk + * @np: device_node of device registering clk + * @name: name of clk + * @parent_name: parent name of clk + * @parent_hw: clk_hw pointer to parent of clk + * @parent_data: parent_data describing parent of clk + * @flags: clk framework flags + * @fixed_rate: frequency of clk + * @fixed_accuracy: accuracy of clk + * @clk_fixed_flags: fixed rate specific clk flags + */ +struct clk_hw_fixed_rate_kunit_params { + struct device *dev; + struct device_node *np; + const char *name; + const char *parent_name; + const struct clk_hw *parent_hw; + const struct clk_parent_data *parent_data; + unsigned long flags; + unsigned long fixed_rate; + unsigned long fixed_accuracy; + unsigned long clk_fixed_flags; +}; + +static int +clk_hw_register_fixed_rate_kunit_init(struct kunit_resource *res, void *context) +{ + struct clk_hw_fixed_rate_kunit_params *params = context; + struct clk_hw *hw; + + hw = __clk_hw_register_fixed_rate(params->dev, params->np, + params->name, + params->parent_name, + params->parent_hw, + params->parent_data, + params->flags, + params->fixed_rate, + params->fixed_accuracy, + params->clk_fixed_flags, + false); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + res->data = hw; + + return 0; +} + +static void clk_hw_register_fixed_rate_kunit_exit(struct kunit_resource *res) +{ + struct clk_hw *hw = res->data; + + clk_hw_unregister_fixed_rate(hw); +} + +/** + * clk_hw_register_fixed_rate_kunit() - Test managed __clk_hw_register_fixed_rate() + * @test: The test context + * @params: Arguments to __clk_hw_register_fixed_rate() + * + * Return: Registered fixed rate clk_hw or ERR_PTR on failure + */ +static struct clk_hw * +clk_hw_register_fixed_rate_kunit(struct kunit *test, + struct clk_hw_fixed_rate_kunit_params *params) +{ + struct clk_hw *hw; + + hw = kunit_alloc_resource(test, + clk_hw_register_fixed_rate_kunit_init, + clk_hw_register_fixed_rate_kunit_exit, + GFP_KERNEL, params); + if (!hw) + return ERR_PTR(-EINVAL); + + return hw; +} + +/** + * clk_hw_unregister_fixed_rate_kunit() - Test managed clk_hw_unregister_fixed_rate() + * @test: The test context + * @hw: fixed rate clk to unregister upon test completion + * + * Automatically unregister @hw when @test is complete via + * clk_hw_unregister_fixed_rate(). + * + * Return: 0 on success or negative errno on failure + */ +static int clk_hw_unregister_fixed_rate_kunit(struct kunit *test, struct clk_hw *hw) +{ + if (!kunit_alloc_resource(test, NULL, + clk_hw_register_fixed_rate_kunit_exit, + GFP_KERNEL, hw)) + return -ENOMEM; + + return 0; +} + +/* + * Test that clk_get_rate() on a fixed rate clk registered with + * clk_hw_register_fixed_rate() gets the proper frequency. + */ +static void clk_fixed_rate_rate_test(struct kunit *test) +{ + struct clk_hw *hw; + struct clk *clk; + const unsigned long fixed_rate = 230000; + + hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", NULL, 0, fixed_rate); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); + + clk = clk_hw_get_clk_prepared_enabled_kunit(test, hw, __func__); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); + + KUNIT_EXPECT_EQ(test, fixed_rate, clk_get_rate(clk)); +} + +/* + * Test that clk_get_accuracy() on a fixed rate clk registered via + * clk_hw_register_fixed_rate_with_accuracy() gets the proper accuracy. + */ +static void clk_fixed_rate_accuracy_test(struct kunit *test) +{ + struct clk_hw *hw; + struct clk *clk; + const unsigned long fixed_accuracy = 5000; + + hw = clk_hw_register_fixed_rate_with_accuracy(NULL, "test-fixed-rate", + NULL, 0, 0, + fixed_accuracy); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); + + clk = clk_hw_get_clk_kunit(test, hw, __func__); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); + + KUNIT_EXPECT_EQ(test, fixed_accuracy, clk_get_accuracy(clk)); +} + +/* Test suite for a fixed rate clk without any parent */ +static struct kunit_case clk_fixed_rate_test_cases[] = { + KUNIT_CASE(clk_fixed_rate_rate_test), + KUNIT_CASE(clk_fixed_rate_accuracy_test), + {} +}; + +static struct kunit_suite clk_fixed_rate_suite = { + .name = "clk_fixed_rate", + .test_cases = clk_fixed_rate_test_cases, +}; + +/* + * Test that clk_get_parent() on a fixed rate clk gets the proper parent. + */ +static void clk_fixed_rate_parent_test(struct kunit *test) +{ + struct clk_hw *hw, *parent_hw; + struct clk *expected_parent, *actual_parent; + struct clk *clk; + const char *parent_name = "test-fixed-rate-parent"; + struct clk_hw_fixed_rate_kunit_params parent_params = { + .name = parent_name, + }; + + parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw); + KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw)); + + expected_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent); + + hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", parent_name, 0, 0); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); + + clk = clk_hw_get_clk_kunit(test, hw, __func__); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); + + actual_parent = clk_get_parent(clk); + KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent)); +} + +/* + * Test that clk_get_rate() on a fixed rate clk ignores the parent rate. + */ +static void clk_fixed_rate_parent_rate_test(struct kunit *test) +{ + struct clk_hw *hw, *parent_hw; + struct clk *clk; + const unsigned long expected_rate = 1405; + const unsigned long parent_rate = 90402; + const char *parent_name = "test-fixed-rate-parent"; + struct clk_hw_fixed_rate_kunit_params parent_params = { + .name = parent_name, + .fixed_rate = parent_rate, + }; + + parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw); + KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw)); + + hw = clk_hw_register_fixed_rate(NULL, "test-fixed-rate", parent_name, 0, + expected_rate); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); + + clk = clk_hw_get_clk_prepared_enabled_kunit(test, hw, __func__); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); + + KUNIT_EXPECT_EQ(test, expected_rate, clk_get_rate(clk)); +} + +/* + * Test that clk_get_accuracy() on a fixed rate clk ignores the parent accuracy. + */ +static void clk_fixed_rate_parent_accuracy_test(struct kunit *test) +{ + struct clk_hw *hw, *parent_hw; + struct clk *clk; + const unsigned long expected_accuracy = 900; + const unsigned long parent_accuracy = 24000; + const char *parent_name = "test-fixed-rate-parent"; + struct clk_hw_fixed_rate_kunit_params parent_params = { + .name = parent_name, + .fixed_accuracy = parent_accuracy, + }; + + parent_hw = clk_hw_register_fixed_rate_kunit(test, &parent_params); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw); + KUNIT_ASSERT_STREQ(test, parent_name, clk_hw_get_name(parent_hw)); + + hw = clk_hw_register_fixed_rate_with_accuracy(NULL, "test-fixed-rate", + parent_name, 0, 0, + expected_accuracy); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw); + KUNIT_ASSERT_EQ(test, 0, clk_hw_unregister_fixed_rate_kunit(test, hw)); + + clk = clk_hw_get_clk_kunit(test, hw, __func__); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); + + KUNIT_EXPECT_EQ(test, expected_accuracy, clk_get_accuracy(clk)); +} + +/* Test suite for a fixed rate clk with a parent */ +static struct kunit_case clk_fixed_rate_parent_test_cases[] = { + KUNIT_CASE(clk_fixed_rate_parent_test), + KUNIT_CASE(clk_fixed_rate_parent_rate_test), + KUNIT_CASE(clk_fixed_rate_parent_accuracy_test), + {} +}; + +static struct kunit_suite clk_fixed_rate_parent_suite = { + .name = "clk_fixed_rate_parent", + .test_cases = clk_fixed_rate_parent_test_cases, +}; + +struct clk_fixed_rate_of_test_context { + struct device *dev; + struct platform_driver pdrv; + struct completion probed; +}; + +static inline struct clk_fixed_rate_of_test_context * +pdev_to_clk_fixed_rate_of_test_context(struct platform_device *pdev) +{ + return container_of(to_platform_driver(pdev->dev.driver), + struct clk_fixed_rate_of_test_context, + pdrv); +} + +/* + * Test that of_fixed_clk_setup() registers a fixed rate clk with the proper + * rate. + */ +static void clk_fixed_rate_of_probe_test(struct kunit *test) +{ + struct clk_fixed_rate_of_test_context *ctx = test->priv; + struct device *dev = ctx->dev; + struct clk *clk; + + clk = clk_get_kunit(test, dev, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); + + KUNIT_ASSERT_EQ(test, 0, clk_prepare_enable_kunit(test, clk)); + KUNIT_EXPECT_EQ(test, TEST_FIXED_FREQUENCY, clk_get_rate(clk)); +} + +/* + * Test that of_fixed_clk_setup() registers a fixed rate clk with the proper + * accuracy. + */ +static void clk_fixed_rate_of_accuracy_test(struct kunit *test) +{ + struct clk_fixed_rate_of_test_context *ctx = test->priv; + struct device *dev = ctx->dev; + struct clk *clk; + + clk = clk_get_kunit(test, dev, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, clk); + + KUNIT_EXPECT_EQ(test, TEST_FIXED_ACCURACY, clk_get_accuracy(clk)); +} + +static struct kunit_case clk_fixed_rate_of_cases[] = { + KUNIT_CASE(clk_fixed_rate_of_probe_test), + KUNIT_CASE(clk_fixed_rate_of_accuracy_test), + {} +}; + +static int clk_fixed_rate_of_test_probe(struct platform_device *pdev) +{ + struct clk_fixed_rate_of_test_context *ctx; + + ctx = pdev_to_clk_fixed_rate_of_test_context(pdev); + ctx->dev = &pdev->dev; + complete(&ctx->probed); + + return 0; +} + +static int clk_fixed_rate_of_init(struct kunit *test) +{ + struct clk_fixed_rate_of_test_context *ctx; + static const struct of_device_id match_table[] = { + { .compatible = "test,single-clk-consumer" }, + { } + }; + + KUNIT_ASSERT_EQ(test, 0, of_overlay_apply_kunit(test, kunit_clk_fixed_rate_test)); + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + test->priv = ctx; + + ctx->pdrv.probe = clk_fixed_rate_of_test_probe; + ctx->pdrv.driver.of_match_table = match_table; + ctx->pdrv.driver.name = __func__; + ctx->pdrv.driver.owner = THIS_MODULE; + init_completion(&ctx->probed); + + KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv)); + KUNIT_ASSERT_NE(test, 0, wait_for_completion_timeout(&ctx->probed, HZ)); + + return 0; +} + +static struct kunit_suite clk_fixed_rate_of_suite = { + .name = "clk_fixed_rate_of", + .init = clk_fixed_rate_of_init, + .test_cases = clk_fixed_rate_of_cases, +}; + +kunit_test_suites( + &clk_fixed_rate_suite, + &clk_fixed_rate_of_suite, + &clk_fixed_rate_parent_suite, +); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("KUnit test for clk fixed rate basic type"); diff --git a/drivers/clk/clk-fixed-rate_test.h b/drivers/clk/clk-fixed-rate_test.h new file mode 100644 index 000000000000..e0d28e5b6081 --- /dev/null +++ b/drivers/clk/clk-fixed-rate_test.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _CLK_FIXED_RATE_TEST_H +#define _CLK_FIXED_RATE_TEST_H + +#define TEST_FIXED_FREQUENCY 50000000 +#define TEST_FIXED_ACCURACY 300 + +#endif diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index 99b271c1278a..c997e7491996 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -1405,16 +1405,12 @@ static int lmk04832_probe(struct spi_device *spi) lmk->dev = &spi->dev; - lmk->oscin = devm_clk_get(lmk->dev, "oscin"); + lmk->oscin = devm_clk_get_enabled(lmk->dev, "oscin"); if (IS_ERR(lmk->oscin)) { dev_err(lmk->dev, "failed to get oscin clock\n"); return PTR_ERR(lmk->oscin); } - ret = clk_prepare_enable(lmk->oscin); - if (ret) - return ret; - lmk->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); @@ -1422,14 +1418,14 @@ static int lmk04832_probe(struct spi_device *spi) sizeof(struct lmk_dclk), GFP_KERNEL); if (!lmk->dclk) { ret = -ENOMEM; - goto err_disable_oscin; + return ret; } lmk->clkout = devm_kcalloc(lmk->dev, info->num_channels, sizeof(*lmk->clkout), GFP_KERNEL); if (!lmk->clkout) { ret = -ENOMEM; - goto err_disable_oscin; + return ret; } lmk->clk_data = devm_kzalloc(lmk->dev, struct_size(lmk->clk_data, hws, @@ -1437,7 +1433,7 @@ static int lmk04832_probe(struct spi_device *spi) GFP_KERNEL); if (!lmk->clk_data) { ret = -ENOMEM; - goto err_disable_oscin; + return ret; } device_property_read_u32(lmk->dev, "ti,vco-hz", &lmk->vco_rate); @@ -1465,7 +1461,7 @@ static int lmk04832_probe(struct spi_device *spi) dev_err(lmk->dev, "missing reg property in child: %s\n", child->full_name); of_node_put(child); - goto err_disable_oscin; + return ret; } of_property_read_u32(child, "ti,clkout-fmt", @@ -1486,7 +1482,7 @@ static int lmk04832_probe(struct spi_device *spi) __func__, PTR_ERR(lmk->regmap)); ret = PTR_ERR(lmk->regmap); - goto err_disable_oscin; + return ret; } regmap_write(lmk->regmap, LMK04832_REG_RST3W, LMK04832_BIT_RESET); @@ -1496,7 +1492,7 @@ static int lmk04832_probe(struct spi_device *spi) &rdbk_pin); ret = lmk04832_set_spi_rdbk(lmk, rdbk_pin); if (ret) - goto err_disable_oscin; + return ret; } regmap_bulk_read(lmk->regmap, LMK04832_REG_ID_PROD_MSB, &tmp, 3); @@ -1504,13 +1500,13 @@ static int lmk04832_probe(struct spi_device *spi) dev_err(lmk->dev, "unsupported device type: pid 0x%04x, maskrev 0x%02x\n", tmp[0] << 8 | tmp[1], tmp[2]); ret = -EINVAL; - goto err_disable_oscin; + return ret; } ret = lmk04832_register_vco(lmk); if (ret) { dev_err(lmk->dev, "failed to init device clock path\n"); - goto err_disable_oscin; + return ret; } if (lmk->vco_rate) { @@ -1518,21 +1514,21 @@ static int lmk04832_probe(struct spi_device *spi) ret = clk_set_rate(lmk->vco.clk, lmk->vco_rate); if (ret) { dev_err(lmk->dev, "failed to set VCO rate\n"); - goto err_disable_oscin; + return ret; } } ret = lmk04832_register_sclk(lmk); if (ret) { dev_err(lmk->dev, "failed to init SYNC/SYSREF clock path\n"); - goto err_disable_oscin; + return ret; } for (i = 0; i < info->num_channels; i++) { ret = lmk04832_register_clkout(lmk, i); if (ret) { dev_err(lmk->dev, "failed to register clk %d\n", i); - goto err_disable_oscin; + return ret; } } @@ -1541,24 +1537,12 @@ static int lmk04832_probe(struct spi_device *spi) lmk->clk_data); if (ret) { dev_err(lmk->dev, "failed to add provider (%d)\n", ret); - goto err_disable_oscin; + return ret; } spi_set_drvdata(spi, lmk); return 0; - -err_disable_oscin: - clk_disable_unprepare(lmk->oscin); - - return ret; -} - -static void lmk04832_remove(struct spi_device *spi) -{ - struct lmk04832 *lmk = spi_get_drvdata(spi); - - clk_disable_unprepare(lmk->oscin); } static const struct spi_device_id lmk04832_id[] = { @@ -1579,7 +1563,6 @@ static struct spi_driver lmk04832_driver = { .of_match_table = lmk04832_of_id, }, .probe = lmk04832_probe, - .remove = lmk04832_remove, .id_table = lmk04832_id, }; module_spi_driver(lmk04832_driver); diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index d86a02563f6c..15510c2ff21c 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -156,13 +156,13 @@ static void scmi_clk_atomic_disable(struct clk_hw *hw) scmi_proto_clk_ops->disable(clk->ph, clk->id, ATOMIC); } -static int scmi_clk_atomic_is_enabled(struct clk_hw *hw) +static int __scmi_clk_is_enabled(struct clk_hw *hw, bool atomic) { int ret; bool enabled = false; struct scmi_clk *clk = to_scmi_clk(hw); - ret = scmi_proto_clk_ops->state_get(clk->ph, clk->id, &enabled, ATOMIC); + ret = scmi_proto_clk_ops->state_get(clk->ph, clk->id, &enabled, atomic); if (ret) dev_warn(clk->dev, "Failed to get state for clock ID %d\n", clk->id); @@ -170,6 +170,16 @@ static int scmi_clk_atomic_is_enabled(struct clk_hw *hw) return !!enabled; } +static int scmi_clk_atomic_is_enabled(struct clk_hw *hw) +{ + return __scmi_clk_is_enabled(hw, ATOMIC); +} + +static int scmi_clk_is_enabled(struct clk_hw *hw) +{ + return __scmi_clk_is_enabled(hw, NOT_ATOMIC); +} + static int scmi_clk_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) { int ret; @@ -285,6 +295,8 @@ scmi_clk_ops_alloc(struct device *dev, unsigned long feats_key) if (feats_key & BIT(SCMI_CLK_ATOMIC_SUPPORTED)) ops->is_enabled = scmi_clk_atomic_is_enabled; + else + ops->is_prepared = scmi_clk_is_enabled; /* Rate ops */ ops->recalc_rate = scmi_clk_recalc_rate; diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 285ed1ad8a37..d02451f951cf 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4762,7 +4762,7 @@ void __clk_put(struct clk *clk) clk->exclusive_count = 0; } - hlist_del(&clk->clks_node); + clk_core_unlink_consumer(clk); /* If we had any boundaries on that clock, let's drop them. */ if (clk->min_rate > 0 || clk->max_rate < ULONG_MAX) @@ -5232,7 +5232,7 @@ static int of_parse_clkspec(const struct device_node *np, int index, * clocks. */ np = np->parent; - if (np && !of_get_property(np, "clock-ranges", NULL)) + if (np && !of_property_present(np, "clock-ranges")) break; index = 0; } diff --git a/drivers/clk/clk_kunit_helpers.c b/drivers/clk/clk_kunit_helpers.c new file mode 100644 index 000000000000..52fd25594c96 --- /dev/null +++ b/drivers/clk/clk_kunit_helpers.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit helpers for clk providers and consumers + */ +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +#include <kunit/clk.h> +#include <kunit/resource.h> + +KUNIT_DEFINE_ACTION_WRAPPER(clk_disable_unprepare_wrapper, + clk_disable_unprepare, struct clk *); +/** + * clk_prepare_enable_kunit() - Test managed clk_prepare_enable() + * @test: The test context + * @clk: clk to prepare and enable + * + * Return: 0 on success, or negative errno on failure. + */ +int clk_prepare_enable_kunit(struct kunit *test, struct clk *clk) +{ + int ret; + + ret = clk_prepare_enable(clk); + if (ret) + return ret; + + return kunit_add_action_or_reset(test, clk_disable_unprepare_wrapper, + clk); +} +EXPORT_SYMBOL_GPL(clk_prepare_enable_kunit); + +KUNIT_DEFINE_ACTION_WRAPPER(clk_put_wrapper, clk_put, struct clk *); + +static struct clk *__clk_get_kunit(struct kunit *test, struct clk *clk) +{ + int ret; + + if (IS_ERR(clk)) + return clk; + + ret = kunit_add_action_or_reset(test, clk_put_wrapper, clk); + if (ret) + return ERR_PTR(ret); + + return clk; +} + +/** + * clk_get_kunit() - Test managed clk_get() + * @test: The test context + * @dev: device for clock "consumer" + * @con_id: clock consumer ID + * + * Just like clk_get(), except the clk is managed by the test case and is + * automatically put with clk_put() after the test case concludes. + * + * Return: new clk consumer or ERR_PTR on failure. + */ +struct clk * +clk_get_kunit(struct kunit *test, struct device *dev, const char *con_id) +{ + struct clk *clk; + + clk = clk_get(dev, con_id); + + return __clk_get_kunit(test, clk); +} +EXPORT_SYMBOL_GPL(clk_get_kunit); + +/** + * of_clk_get_kunit() - Test managed of_clk_get() + * @test: The test context + * @np: device_node for clock "consumer" + * @index: index in 'clocks' property of @np + * + * Just like of_clk_get(), except the clk is managed by the test case and is + * automatically put with clk_put() after the test case concludes. + * + * Return: new clk consumer or ERR_PTR on failure. + */ +struct clk * +of_clk_get_kunit(struct kunit *test, struct device_node *np, int index) +{ + struct clk *clk; + + clk = of_clk_get(np, index); + + return __clk_get_kunit(test, clk); +} +EXPORT_SYMBOL_GPL(of_clk_get_kunit); + +/** + * clk_hw_get_clk_kunit() - Test managed clk_hw_get_clk() + * @test: The test context + * @hw: clk_hw associated with the clk being consumed + * @con_id: connection ID string on device + * + * Just like clk_hw_get_clk(), except the clk is managed by the test case and + * is automatically put with clk_put() after the test case concludes. + * + * Return: new clk consumer or ERR_PTR on failure. + */ +struct clk * +clk_hw_get_clk_kunit(struct kunit *test, struct clk_hw *hw, const char *con_id) +{ + struct clk *clk; + + clk = clk_hw_get_clk(hw, con_id); + + return __clk_get_kunit(test, clk); +} +EXPORT_SYMBOL_GPL(clk_hw_get_clk_kunit); + +/** + * clk_hw_get_clk_prepared_enabled_kunit() - Test managed clk_hw_get_clk() + clk_prepare_enable() + * @test: The test context + * @hw: clk_hw associated with the clk being consumed + * @con_id: connection ID string on device + * + * Just like + * + * .. code-block:: c + * + * struct clk *clk = clk_hw_get_clk(...); + * clk_prepare_enable(clk); + * + * except the clk is managed by the test case and is automatically disabled and + * unprepared with clk_disable_unprepare() and put with clk_put() after the + * test case concludes. + * + * Return: new clk consumer that is prepared and enabled or ERR_PTR on failure. + */ +struct clk * +clk_hw_get_clk_prepared_enabled_kunit(struct kunit *test, struct clk_hw *hw, + const char *con_id) +{ + int ret; + struct clk *clk; + + clk = clk_hw_get_clk_kunit(test, hw, con_id); + if (IS_ERR(clk)) + return clk; + + ret = clk_prepare_enable_kunit(test, clk); + if (ret) + return ERR_PTR(ret); + + return clk; +} +EXPORT_SYMBOL_GPL(clk_hw_get_clk_prepared_enabled_kunit); + +KUNIT_DEFINE_ACTION_WRAPPER(clk_hw_unregister_wrapper, + clk_hw_unregister, struct clk_hw *); + +/** + * clk_hw_register_kunit() - Test managed clk_hw_register() + * @test: The test context + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * Just like clk_hw_register(), except the clk registration is managed by the + * test case and is automatically unregistered after the test case concludes. + * + * Return: 0 on success or a negative errno value on failure. + */ +int clk_hw_register_kunit(struct kunit *test, struct device *dev, struct clk_hw *hw) +{ + int ret; + + ret = clk_hw_register(dev, hw); + if (ret) + return ret; + + return kunit_add_action_or_reset(test, clk_hw_unregister_wrapper, hw); +} +EXPORT_SYMBOL_GPL(clk_hw_register_kunit); + +/** + * of_clk_hw_register_kunit() - Test managed of_clk_hw_register() + * @test: The test context + * @node: device_node of device that is registering this clock + * @hw: link to hardware-specific clock data + * + * Just like of_clk_hw_register(), except the clk registration is managed by + * the test case and is automatically unregistered after the test case + * concludes. + * + * Return: 0 on success or a negative errno value on failure. + */ +int of_clk_hw_register_kunit(struct kunit *test, struct device_node *node, struct clk_hw *hw) +{ + int ret; + + ret = of_clk_hw_register(node, hw); + if (ret) + return ret; + + return kunit_add_action_or_reset(test, clk_hw_unregister_wrapper, hw); +} +EXPORT_SYMBOL_GPL(of_clk_hw_register_kunit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("KUnit helpers for clk providers and consumers"); diff --git a/drivers/clk/clk_parent_data_test.h b/drivers/clk/clk_parent_data_test.h new file mode 100644 index 000000000000..eedd53ae910d --- /dev/null +++ b/drivers/clk/clk_parent_data_test.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _CLK_PARENT_DATA_TEST_H +#define _CLK_PARENT_DATA_TEST_H + +#define CLK_PARENT_DATA_1MHZ_NAME "1mhz_fixed_legacy" +#define CLK_PARENT_DATA_PARENT1 "parent_fwname" +#define CLK_PARENT_DATA_PARENT2 "50" +#define CLK_PARENT_DATA_50MHZ_NAME "50_clk" + +#endif diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c index fbbea66d9cba..41fc8eba3418 100644 --- a/drivers/clk/clk_test.c +++ b/drivers/clk/clk_test.c @@ -4,12 +4,19 @@ */ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/platform_device.h> /* Needed for clk_hw_get_clk() */ #include "clk.h" +#include <kunit/clk.h> +#include <kunit/of.h> +#include <kunit/platform_device.h> #include <kunit/test.h> +#include "clk_parent_data_test.h" + static const struct clk_ops empty_clk_ops = { }; #define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000) @@ -2659,6 +2666,448 @@ static struct kunit_suite clk_mux_no_reparent_test_suite = { .test_cases = clk_mux_no_reparent_test_cases, }; +struct clk_register_clk_parent_data_test_case { + const char *desc; + struct clk_parent_data pdata; +}; + +static void +clk_register_clk_parent_data_test_case_to_desc( + const struct clk_register_clk_parent_data_test_case *t, char *desc) +{ + strcpy(desc, t->desc); +} + +static const struct clk_register_clk_parent_data_test_case +clk_register_clk_parent_data_of_cases[] = { + { + /* + * Test that a clk registered with a struct device_node can + * find a parent based on struct clk_parent_data::index. + */ + .desc = "clk_parent_data_of_index_test", + .pdata.index = 0, + }, + { + /* + * Test that a clk registered with a struct device_node can + * find a parent based on struct clk_parent_data::fwname. + */ + .desc = "clk_parent_data_of_fwname_test", + .pdata.fw_name = CLK_PARENT_DATA_PARENT1, + }, + { + /* + * Test that a clk registered with a struct device_node can + * find a parent based on struct clk_parent_data::name. + */ + .desc = "clk_parent_data_of_name_test", + /* The index must be negative to indicate firmware not used */ + .pdata.index = -1, + .pdata.name = CLK_PARENT_DATA_1MHZ_NAME, + }, + { + /* + * Test that a clk registered with a struct device_node can + * find a parent based on struct + * clk_parent_data::{fw_name,name}. + */ + .desc = "clk_parent_data_of_fwname_name_test", + .pdata.fw_name = CLK_PARENT_DATA_PARENT1, + .pdata.name = "not_matching", + }, + { + /* + * Test that a clk registered with a struct device_node can + * find a parent based on struct clk_parent_data::{index,name}. + * Index takes priority. + */ + .desc = "clk_parent_data_of_index_name_priority_test", + .pdata.index = 0, + .pdata.name = "not_matching", + }, + { + /* + * Test that a clk registered with a struct device_node can + * find a parent based on struct + * clk_parent_data::{index,fwname,name}. The fw_name takes + * priority over index and name. + */ + .desc = "clk_parent_data_of_index_fwname_name_priority_test", + .pdata.index = 1, + .pdata.fw_name = CLK_PARENT_DATA_PARENT1, + .pdata.name = "not_matching", + }, +}; + +KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_of_test, clk_register_clk_parent_data_of_cases, + clk_register_clk_parent_data_test_case_to_desc) + +/** + * struct clk_register_clk_parent_data_of_ctx - Context for clk_parent_data OF tests + * @np: device node of clk under test + * @hw: clk_hw for clk under test + */ +struct clk_register_clk_parent_data_of_ctx { + struct device_node *np; + struct clk_hw hw; +}; + +static int clk_register_clk_parent_data_of_test_init(struct kunit *test) +{ + struct clk_register_clk_parent_data_of_ctx *ctx; + + KUNIT_ASSERT_EQ(test, 0, + of_overlay_apply_kunit(test, kunit_clk_parent_data_test)); + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + test->priv = ctx; + + ctx->np = of_find_compatible_node(NULL, NULL, "test,clk-parent-data"); + if (!ctx->np) + return -ENODEV; + + of_node_put_kunit(test, ctx->np); + + return 0; +} + +/* + * Test that a clk registered with a struct device_node can find a parent based on + * struct clk_parent_data when the hw member isn't set. + */ +static void clk_register_clk_parent_data_of_test(struct kunit *test) +{ + struct clk_register_clk_parent_data_of_ctx *ctx = test->priv; + struct clk_hw *parent_hw; + const struct clk_register_clk_parent_data_test_case *test_param; + struct clk_init_data init = { }; + struct clk *expected_parent, *actual_parent; + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->np); + + expected_parent = of_clk_get_kunit(test, ctx->np, 0); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent); + + test_param = test->param_value; + init.parent_data = &test_param->pdata; + init.num_parents = 1; + init.name = "parent_data_of_test_clk"; + init.ops = &clk_dummy_single_parent_ops; + ctx->hw.init = &init; + KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, ctx->np, &ctx->hw)); + + parent_hw = clk_hw_get_parent(&ctx->hw); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw); + + actual_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, actual_parent); + + KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent)); +} + +static struct kunit_case clk_register_clk_parent_data_of_test_cases[] = { + KUNIT_CASE_PARAM(clk_register_clk_parent_data_of_test, + clk_register_clk_parent_data_of_test_gen_params), + {} +}; + +/* + * Test suite for registering clks with struct clk_parent_data and a struct + * device_node. + */ +static struct kunit_suite clk_register_clk_parent_data_of_suite = { + .name = "clk_register_clk_parent_data_of", + .init = clk_register_clk_parent_data_of_test_init, + .test_cases = clk_register_clk_parent_data_of_test_cases, +}; + +/** + * struct clk_register_clk_parent_data_device_ctx - Context for clk_parent_data device tests + * @dev: device of clk under test + * @hw: clk_hw for clk under test + * @pdrv: driver to attach to find @dev + */ +struct clk_register_clk_parent_data_device_ctx { + struct device *dev; + struct clk_hw hw; + struct platform_driver pdrv; +}; + +static inline struct clk_register_clk_parent_data_device_ctx * +clk_register_clk_parent_data_driver_to_test_context(struct platform_device *pdev) +{ + return container_of(to_platform_driver(pdev->dev.driver), + struct clk_register_clk_parent_data_device_ctx, pdrv); +} + +static int clk_register_clk_parent_data_device_probe(struct platform_device *pdev) +{ + struct clk_register_clk_parent_data_device_ctx *ctx; + + ctx = clk_register_clk_parent_data_driver_to_test_context(pdev); + ctx->dev = &pdev->dev; + + return 0; +} + +static void clk_register_clk_parent_data_device_driver(struct kunit *test) +{ + struct clk_register_clk_parent_data_device_ctx *ctx = test->priv; + static const struct of_device_id match_table[] = { + { .compatible = "test,clk-parent-data" }, + { } + }; + + ctx->pdrv.probe = clk_register_clk_parent_data_device_probe; + ctx->pdrv.driver.of_match_table = match_table; + ctx->pdrv.driver.name = __func__; + ctx->pdrv.driver.owner = THIS_MODULE; + + KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv)); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev); +} + +static const struct clk_register_clk_parent_data_test_case +clk_register_clk_parent_data_device_cases[] = { + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::index. + */ + .desc = "clk_parent_data_device_index_test", + .pdata.index = 1, + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::fwname. + */ + .desc = "clk_parent_data_device_fwname_test", + .pdata.fw_name = CLK_PARENT_DATA_PARENT2, + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::name. + */ + .desc = "clk_parent_data_device_name_test", + /* The index must be negative to indicate firmware not used */ + .pdata.index = -1, + .pdata.name = CLK_PARENT_DATA_50MHZ_NAME, + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::{fw_name,name}. + */ + .desc = "clk_parent_data_device_fwname_name_test", + .pdata.fw_name = CLK_PARENT_DATA_PARENT2, + .pdata.name = "not_matching", + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::{index,name}. Index + * takes priority. + */ + .desc = "clk_parent_data_device_index_name_priority_test", + .pdata.index = 1, + .pdata.name = "not_matching", + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::{index,fwname,name}. + * The fw_name takes priority over index and name. + */ + .desc = "clk_parent_data_device_index_fwname_name_priority_test", + .pdata.index = 0, + .pdata.fw_name = CLK_PARENT_DATA_PARENT2, + .pdata.name = "not_matching", + }, +}; + +KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_device_test, + clk_register_clk_parent_data_device_cases, + clk_register_clk_parent_data_test_case_to_desc) + +/* + * Test that a clk registered with a struct device can find a parent based on + * struct clk_parent_data when the hw member isn't set. + */ +static void clk_register_clk_parent_data_device_test(struct kunit *test) +{ + struct clk_register_clk_parent_data_device_ctx *ctx; + const struct clk_register_clk_parent_data_test_case *test_param; + struct clk_hw *parent_hw; + struct clk_init_data init = { }; + struct clk *expected_parent, *actual_parent; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + test->priv = ctx; + + clk_register_clk_parent_data_device_driver(test); + + expected_parent = clk_get_kunit(test, ctx->dev, "50"); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent); + + test_param = test->param_value; + init.parent_data = &test_param->pdata; + init.num_parents = 1; + init.name = "parent_data_device_test_clk"; + init.ops = &clk_dummy_single_parent_ops; + ctx->hw.init = &init; + KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, &ctx->hw)); + + parent_hw = clk_hw_get_parent(&ctx->hw); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw); + + actual_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, actual_parent); + + KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent)); +} + +static const struct clk_register_clk_parent_data_test_case +clk_register_clk_parent_data_device_hw_cases[] = { + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::hw. + */ + .desc = "clk_parent_data_device_hw_index_test", + /* The index must be negative to indicate firmware not used */ + .pdata.index = -1, + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::hw when + * struct clk_parent_data::fw_name is set. + */ + .desc = "clk_parent_data_device_hw_fwname_test", + .pdata.fw_name = CLK_PARENT_DATA_PARENT2, + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::hw when struct + * clk_parent_data::name is set. + */ + .desc = "clk_parent_data_device_hw_name_test", + /* The index must be negative to indicate firmware not used */ + .pdata.index = -1, + .pdata.name = CLK_PARENT_DATA_50MHZ_NAME, + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::hw when struct + * clk_parent_data::{fw_name,name} are set. + */ + .desc = "clk_parent_data_device_hw_fwname_name_test", + .pdata.fw_name = CLK_PARENT_DATA_PARENT2, + .pdata.name = "not_matching", + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::hw when struct + * clk_parent_data::index is set. The hw pointer takes + * priority. + */ + .desc = "clk_parent_data_device_hw_index_priority_test", + .pdata.index = 0, + }, + { + /* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::hw when + * struct clk_parent_data::{index,fwname,name} are set. + * The hw pointer takes priority over everything else. + */ + .desc = "clk_parent_data_device_hw_index_fwname_name_priority_test", + .pdata.index = 0, + .pdata.fw_name = CLK_PARENT_DATA_PARENT2, + .pdata.name = "not_matching", + }, +}; + +KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_device_hw_test, + clk_register_clk_parent_data_device_hw_cases, + clk_register_clk_parent_data_test_case_to_desc) + +/* + * Test that a clk registered with a struct device can find a + * parent based on struct clk_parent_data::hw. + */ +static void clk_register_clk_parent_data_device_hw_test(struct kunit *test) +{ + struct clk_register_clk_parent_data_device_ctx *ctx; + const struct clk_register_clk_parent_data_test_case *test_param; + struct clk_dummy_context *parent; + struct clk_hw *parent_hw; + struct clk_parent_data pdata = { }; + struct clk_init_data init = { }; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + test->priv = ctx; + + clk_register_clk_parent_data_device_driver(test); + + parent = kunit_kzalloc(test, sizeof(*parent), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent); + + parent_hw = &parent->hw; + parent_hw->init = CLK_HW_INIT_NO_PARENT("parent-clk", + &clk_dummy_rate_ops, 0); + + KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, parent_hw)); + + test_param = test->param_value; + memcpy(&pdata, &test_param->pdata, sizeof(pdata)); + pdata.hw = parent_hw; + init.parent_data = &pdata; + init.num_parents = 1; + init.ops = &clk_dummy_single_parent_ops; + init.name = "parent_data_device_hw_test_clk"; + ctx->hw.init = &init; + KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, &ctx->hw)); + + KUNIT_EXPECT_PTR_EQ(test, parent_hw, clk_hw_get_parent(&ctx->hw)); +} + +static struct kunit_case clk_register_clk_parent_data_device_test_cases[] = { + KUNIT_CASE_PARAM(clk_register_clk_parent_data_device_test, + clk_register_clk_parent_data_device_test_gen_params), + KUNIT_CASE_PARAM(clk_register_clk_parent_data_device_hw_test, + clk_register_clk_parent_data_device_hw_test_gen_params), + {} +}; + +static int clk_register_clk_parent_data_device_init(struct kunit *test) +{ + KUNIT_ASSERT_EQ(test, 0, + of_overlay_apply_kunit(test, kunit_clk_parent_data_test)); + + return 0; +} + +/* + * Test suite for registering clks with struct clk_parent_data and a struct + * device. + */ +static struct kunit_suite clk_register_clk_parent_data_device_suite = { + .name = "clk_register_clk_parent_data_device", + .init = clk_register_clk_parent_data_device_init, + .test_cases = clk_register_clk_parent_data_device_test_cases, +}; + kunit_test_suites( &clk_leaf_mux_set_rate_parent_test_suite, &clk_test_suite, @@ -2671,8 +3120,10 @@ kunit_test_suites( &clk_range_test_suite, &clk_range_maximize_test_suite, &clk_range_minimize_test_suite, + &clk_register_clk_parent_data_of_suite, + &clk_register_clk_parent_data_device_suite, &clk_single_parent_mux_test_suite, - &clk_uncached_test_suite + &clk_uncached_test_suite, ); MODULE_DESCRIPTION("Kunit tests for clk framework"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/davinci/da8xx-cfgchip.c b/drivers/clk/davinci/da8xx-cfgchip.c index ec60ecb517f1..a5109fe8b16e 100644 --- a/drivers/clk/davinci/da8xx-cfgchip.c +++ b/drivers/clk/davinci/da8xx-cfgchip.c @@ -513,8 +513,7 @@ da8xx_cfgchip_register_usb0_clk48(struct device *dev, fck_clk = devm_clk_get(dev, "fck"); if (IS_ERR(fck_clk)) { - dev_err_probe(dev, PTR_ERR(fck_clk), "Missing fck clock\n"); - return ERR_CAST(fck_clk); + return dev_err_cast_probe(dev, fck_clk, "Missing fck clock\n"); } usb0 = devm_kzalloc(dev, sizeof(*usb0), GFP_KERNEL); @@ -749,11 +748,9 @@ static int da8xx_cfgchip_probe(struct platform_device *pdev) clk_init = device_get_match_data(dev); if (clk_init) { - struct device_node *parent; + struct device_node *parent __free(device_node) = of_get_parent(dev->of_node); - parent = of_get_parent(dev->of_node); regmap = syscon_node_to_regmap(parent); - of_node_put(parent); } else if (pdev->id_entry && pdata) { clk_init = (void *)pdev->id_entry->driver_data; regmap = pdata->cfgchip; diff --git a/drivers/clk/hisilicon/clk-hi3559a.c b/drivers/clk/hisilicon/clk-hi3559a.c index c79a94f6d9d2..8646e9d352ed 100644 --- a/drivers/clk/hisilicon/clk-hi3559a.c +++ b/drivers/clk/hisilicon/clk-hi3559a.c @@ -407,7 +407,7 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct hi3559av100_clk_pll *clk = to_pll_clk(hw); - u64 frac_val, fbdiv_val, refdiv_val; + u64 frac_val, fbdiv_val; u32 postdiv1_val, postdiv2_val; u32 val; u64 tmp, rate; @@ -435,14 +435,13 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, val = readl_relaxed(clk->ctrl_reg2); val = val >> clk->refdiv_shift; val &= ((1 << clk->refdiv_width) - 1); - refdiv_val = val; /* rate = 24000000 * (fbdiv + frac / (1<<24) ) / refdiv */ rate = 0; tmp = 24000000 * fbdiv_val + (24000000 * frac_val) / (1 << 24); rate += tmp; - do_div(rate, refdiv_val); - do_div(rate, postdiv1_val * postdiv2_val); + rate = div_u64(rate, val); + rate = div_u64(rate, postdiv1_val * postdiv2_val); return rate; } diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 6da0fba68225..6ff6d934848a 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -81,6 +81,7 @@ config CLK_IMX8MP tristate "IMX8MP CCM Clock Driver" depends on ARCH_MXC || COMPILE_TEST select MXC_CLK + select AUXILIARY_BUS if RESET_CONTROLLER help Build the driver for i.MX8MP CCM Clock Driver diff --git a/drivers/clk/imx/clk-composite-7ulp.c b/drivers/clk/imx/clk-composite-7ulp.c index e208ddc51133..8ed2e0ad2769 100644 --- a/drivers/clk/imx/clk-composite-7ulp.c +++ b/drivers/clk/imx/clk-composite-7ulp.c @@ -14,6 +14,7 @@ #include "../clk-fractional-divider.h" #include "clk.h" +#define PCG_PR_MASK BIT(31) #define PCG_PCS_SHIFT 24 #define PCG_PCS_MASK 0x7 #define PCG_CGC_SHIFT 30 @@ -78,6 +79,12 @@ static struct clk_hw *imx_ulp_clk_hw_composite(const char *name, struct clk_hw *hw; u32 val; + val = readl(reg); + if (!(val & PCG_PR_MASK)) { + pr_info("PCC PR is 0 for clk:%s, bypass\n", name); + return NULL; + } + if (mux_present) { mux = kzalloc(sizeof(*mux), GFP_KERNEL); if (!mux) diff --git a/drivers/clk/imx/clk-composite-8m.c b/drivers/clk/imx/clk-composite-8m.c index 8cc07d056a83..f187582ba491 100644 --- a/drivers/clk/imx/clk-composite-8m.c +++ b/drivers/clk/imx/clk-composite-8m.c @@ -204,6 +204,34 @@ static const struct clk_ops imx8m_clk_composite_mux_ops = { .determine_rate = imx8m_clk_composite_mux_determine_rate, }; +static int imx8m_clk_composite_gate_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); + unsigned long flags; + u32 val; + + spin_lock_irqsave(gate->lock, flags); + + val = readl(gate->reg); + val |= BIT(gate->bit_idx); + writel(val, gate->reg); + + spin_unlock_irqrestore(gate->lock, flags); + + return 0; +} + +static void imx8m_clk_composite_gate_disable(struct clk_hw *hw) +{ + /* composite clk requires the disable hook */ +} + +static const struct clk_ops imx8m_clk_composite_gate_ops = { + .enable = imx8m_clk_composite_gate_enable, + .disable = imx8m_clk_composite_gate_disable, + .is_enabled = clk_gate_is_enabled, +}; + struct clk_hw *__imx8m_clk_hw_composite(const char *name, const char * const *parent_names, int num_parents, void __iomem *reg, @@ -217,6 +245,7 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name, struct clk_mux *mux; const struct clk_ops *divider_ops; const struct clk_ops *mux_ops; + const struct clk_ops *gate_ops; mux = kzalloc(sizeof(*mux), GFP_KERNEL); if (!mux) @@ -257,20 +286,22 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name, div->flags = CLK_DIVIDER_ROUND_CLOSEST; /* skip registering the gate ops if M4 is enabled */ - if (!mcore_booted) { - gate = kzalloc(sizeof(*gate), GFP_KERNEL); - if (!gate) - goto free_div; - - gate_hw = &gate->hw; - gate->reg = reg; - gate->bit_idx = PCG_CGC_SHIFT; - gate->lock = &imx_ccm_lock; - } + gate = kzalloc(sizeof(*gate), GFP_KERNEL); + if (!gate) + goto free_div; + + gate_hw = &gate->hw; + gate->reg = reg; + gate->bit_idx = PCG_CGC_SHIFT; + gate->lock = &imx_ccm_lock; + if (!mcore_booted) + gate_ops = &clk_gate_ops; + else + gate_ops = &imx8m_clk_composite_gate_ops; hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, mux_hw, mux_ops, div_hw, - divider_ops, gate_hw, &clk_gate_ops, flags); + divider_ops, gate_hw, gate_ops, flags); if (IS_ERR(hw)) goto free_gate; diff --git a/drivers/clk/imx/clk-composite-93.c b/drivers/clk/imx/clk-composite-93.c index 81164bdcd6cc..6c6c5a30f328 100644 --- a/drivers/clk/imx/clk-composite-93.c +++ b/drivers/clk/imx/clk-composite-93.c @@ -76,6 +76,13 @@ static int imx93_clk_composite_gate_enable(struct clk_hw *hw) static void imx93_clk_composite_gate_disable(struct clk_hw *hw) { + /* + * Skip disable the root clock gate if mcore enabled. + * The root clock may be used by the mcore. + */ + if (mcore_booted) + return; + imx93_clk_composite_gate_endisable(hw, 0); } @@ -222,7 +229,7 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, mux_hw, &clk_mux_ro_ops, div_hw, &clk_divider_ro_ops, NULL, NULL, flags); - } else if (!mcore_booted) { + } else { gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) goto fail; @@ -238,12 +245,6 @@ struct clk_hw *imx93_clk_composite_flags(const char *name, const char * const *p &imx93_clk_composite_divider_ops, gate_hw, &imx93_clk_composite_gate_ops, flags | CLK_SET_RATE_NO_REPARENT); - } else { - hw = clk_hw_register_composite(NULL, name, parent_names, num_parents, - mux_hw, &imx93_clk_composite_mux_ops, div_hw, - &imx93_clk_composite_divider_ops, NULL, - &imx93_clk_composite_gate_ops, - flags | CLK_SET_RATE_NO_REPARENT); } if (IS_ERR(hw)) diff --git a/drivers/clk/imx/clk-fracn-gppll.c b/drivers/clk/imx/clk-fracn-gppll.c index 44462ab50e51..591e0364ee5c 100644 --- a/drivers/clk/imx/clk-fracn-gppll.c +++ b/drivers/clk/imx/clk-fracn-gppll.c @@ -78,6 +78,7 @@ struct clk_fracn_gppll { * The Fvco should be in range 2.5Ghz to 5Ghz */ static const struct imx_fracn_gppll_rate_table fracn_tbl[] = { + PLL_FRACN_GP(1039500000U, 173, 25, 100, 1, 4), PLL_FRACN_GP(650000000U, 162, 50, 100, 0, 6), PLL_FRACN_GP(594000000U, 198, 0, 1, 0, 8), PLL_FRACN_GP(560000000U, 140, 0, 1, 0, 6), @@ -106,6 +107,7 @@ static const struct imx_fracn_gppll_rate_table int_tbl[] = { PLL_FRACN_GP_INTEGER(1700000000U, 141, 1, 2), PLL_FRACN_GP_INTEGER(1400000000U, 175, 1, 3), PLL_FRACN_GP_INTEGER(900000000U, 150, 1, 4), + PLL_FRACN_GP_INTEGER(800000000U, 200, 1, 6), }; struct imx_fracn_gppll_clk imx_fracn_gppll_integer = { @@ -291,6 +293,10 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw) if (val & POWERUP_MASK) return 0; + if (pll->flags & CLK_FRACN_GPPLL_FRACN) + writel_relaxed(readl_relaxed(pll->base + PLL_NUMERATOR), + pll->base + PLL_NUMERATOR); + val |= CLKMUX_BYPASS; writel_relaxed(val, pll->base + PLL_CTRL); diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index f9394e94f69d..05c7a82b751f 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -542,8 +542,8 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clk_set_parent(hws[IMX6UL_CLK_ENFC_SEL]->clk, hws[IMX6UL_CLK_PLL2_PFD2]->clk); - clk_set_parent(hws[IMX6UL_CLK_ENET1_REF_SEL]->clk, hws[IMX6UL_CLK_ENET_REF]->clk); - clk_set_parent(hws[IMX6UL_CLK_ENET2_REF_SEL]->clk, hws[IMX6UL_CLK_ENET2_REF]->clk); + clk_set_parent(hws[IMX6UL_CLK_ENET1_REF_SEL]->clk, hws[IMX6UL_CLK_ENET1_REF_125M]->clk); + clk_set_parent(hws[IMX6UL_CLK_ENET2_REF_SEL]->clk, hws[IMX6UL_CLK_ENET2_REF_125M]->clk); imx_register_uart_clocks(); } diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 2b77d1fc7bb9..99adc55e3f5d 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -498,14 +498,14 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) hws[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_hw_mux2_flags("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel), CLK_SET_PARENT_GATE); hws[IMX7D_NAND_USDHC_BUS_ROOT_SRC] = imx_clk_hw_mux2_flags("nand_usdhc_src", base + 0x8980, 24, 3, nand_usdhc_bus_sel, ARRAY_SIZE(nand_usdhc_bus_sel), CLK_SET_PARENT_GATE); hws[IMX7D_DRAM_PHYM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_src", base + 0x9800, 24, 1, dram_phym_sel, ARRAY_SIZE(dram_phym_sel), CLK_SET_PARENT_GATE); - hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel), CLK_SET_PARENT_GATE); + hws[IMX7D_DRAM_ROOT_SRC] = imx_clk_hw_mux2("dram_src", base + 0x9880, 24, 1, dram_sel, ARRAY_SIZE(dram_sel)); hws[IMX7D_DRAM_PHYM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_phym_alt_src", base + 0xa000, 24, 3, dram_phym_alt_sel, ARRAY_SIZE(dram_phym_alt_sel), CLK_SET_PARENT_GATE); - hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2_flags("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel), CLK_SET_PARENT_GATE); + hws[IMX7D_DRAM_ALT_ROOT_SRC] = imx_clk_hw_mux2("dram_alt_src", base + 0xa080, 24, 3, dram_alt_sel, ARRAY_SIZE(dram_alt_sel)); hws[IMX7D_USB_HSIC_ROOT_SRC] = imx_clk_hw_mux2_flags("usb_hsic_src", base + 0xa100, 24, 3, usb_hsic_sel, ARRAY_SIZE(usb_hsic_sel), CLK_SET_PARENT_GATE); hws[IMX7D_PCIE_CTRL_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_ctrl_src", base + 0xa180, 24, 3, pcie_ctrl_sel, ARRAY_SIZE(pcie_ctrl_sel), CLK_SET_PARENT_GATE); hws[IMX7D_PCIE_PHY_ROOT_SRC] = imx_clk_hw_mux2_flags("pcie_phy_src", base + 0xa200, 24, 3, pcie_phy_sel, ARRAY_SIZE(pcie_phy_sel), CLK_SET_PARENT_GATE); hws[IMX7D_EPDC_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("epdc_pixel_src", base + 0xa280, 24, 3, epdc_pixel_sel, ARRAY_SIZE(epdc_pixel_sel), CLK_SET_PARENT_GATE); - hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_PARENT_GATE); + hws[IMX7D_LCDIF_PIXEL_ROOT_SRC] = imx_clk_hw_mux2_flags("lcdif_pixel_src", base + 0xa300, 24, 3, lcdif_pixel_sel, ARRAY_SIZE(lcdif_pixel_sel), CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT); hws[IMX7D_MIPI_DSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dsi_src", base + 0xa380, 24, 3, mipi_dsi_sel, ARRAY_SIZE(mipi_dsi_sel), CLK_SET_PARENT_GATE); hws[IMX7D_MIPI_CSI_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_csi_src", base + 0xa400, 24, 3, mipi_csi_sel, ARRAY_SIZE(mipi_csi_sel), CLK_SET_PARENT_GATE); hws[IMX7D_MIPI_DPHY_ROOT_SRC] = imx_clk_hw_mux2_flags("mipi_dphy_src", base + 0xa480, 24, 3, mipi_dphy_sel, ARRAY_SIZE(mipi_dphy_sel), CLK_SET_PARENT_GATE); diff --git a/drivers/clk/imx/clk-imx8-acm.c b/drivers/clk/imx/clk-imx8-acm.c index 1bdb480cc96c..61d8c7e9ae0b 100644 --- a/drivers/clk/imx/clk-imx8-acm.c +++ b/drivers/clk/imx/clk-imx8-acm.c @@ -54,10 +54,12 @@ struct clk_imx8_acm_sel { * struct imx8_acm_soc_data - soc specific data * @sels: pointer to struct clk_imx8_acm_sel * @num_sels: numbers of items + * @mclk_sels: pointer to imx8qm/qxp/dxl_mclk_sels */ struct imx8_acm_soc_data { struct clk_imx8_acm_sel *sels; unsigned int num_sels; + struct clk_parent_data *mclk_sels; }; /** @@ -111,11 +113,14 @@ static const struct clk_parent_data imx8qm_mclk_out_sels[] = { { .fw_name = "sai6_rx_bclk" }, }; -static const struct clk_parent_data imx8qm_mclk_sels[] = { +#define ACM_AUD_CLK0_SEL_INDEX 2 +#define ACM_AUD_CLK1_SEL_INDEX 3 + +static struct clk_parent_data imx8qm_mclk_sels[] = { { .fw_name = "aud_pll_div_clk0_lpcg_clk" }, { .fw_name = "aud_pll_div_clk1_lpcg_clk" }, - { .fw_name = "acm_aud_clk0_sel" }, - { .fw_name = "acm_aud_clk1_sel" }, + { }, /* clk_hw pointer of "acm_aud_clk0_sel" */ + { }, /* clk_hw pointer of "acm_aud_clk1_sel" */ }; static const struct clk_parent_data imx8qm_asrc_mux_clk_sels[] = { @@ -176,11 +181,11 @@ static const struct clk_parent_data imx8qxp_mclk_out_sels[] = { { .fw_name = "sai4_rx_bclk" }, }; -static const struct clk_parent_data imx8qxp_mclk_sels[] = { +static struct clk_parent_data imx8qxp_mclk_sels[] = { { .fw_name = "aud_pll_div_clk0_lpcg_clk" }, { .fw_name = "aud_pll_div_clk1_lpcg_clk" }, - { .fw_name = "acm_aud_clk0_sel" }, - { .fw_name = "acm_aud_clk1_sel" }, + { }, /* clk_hw pointer of "acm_aud_clk0_sel" */ + { }, /* clk_hw pointer of "acm_aud_clk1_sel" */ }; static struct clk_imx8_acm_sel imx8qxp_sels[] = { @@ -228,11 +233,11 @@ static const struct clk_parent_data imx8dxl_mclk_out_sels[] = { { .index = -1 }, }; -static const struct clk_parent_data imx8dxl_mclk_sels[] = { +static struct clk_parent_data imx8dxl_mclk_sels[] = { { .fw_name = "aud_pll_div_clk0_lpcg_clk" }, { .fw_name = "aud_pll_div_clk1_lpcg_clk" }, - { .fw_name = "acm_aud_clk0_sel" }, - { .fw_name = "acm_aud_clk1_sel" }, + { }, /* clk_hw pointer of "acm_aud_clk0_sel" */ + { }, /* clk_hw pointer of "acm_aud_clk1_sel" */ }; static struct clk_imx8_acm_sel imx8dxl_sels[] = { @@ -375,6 +380,18 @@ static int imx8_acm_clk_probe(struct platform_device *pdev) imx_check_clk_hws(hws, IMX_ADMA_ACM_CLK_END); goto err_clk_register; } + + /* + * The IMX_ADMA_ACM_AUD_CLK0_SEL and IMX_ADMA_ACM_AUD_CLK1_SEL are + * registered first. After registration, update the clk_hw pointer + * to imx8qm/qxp/dxl_mclk_sels structures. + */ + if (sels[i].clkid == IMX_ADMA_ACM_AUD_CLK0_SEL) + priv->soc_data->mclk_sels[ACM_AUD_CLK0_SEL_INDEX].hw = + hws[IMX_ADMA_ACM_AUD_CLK0_SEL]; + if (sels[i].clkid == IMX_ADMA_ACM_AUD_CLK1_SEL) + priv->soc_data->mclk_sels[ACM_AUD_CLK1_SEL_INDEX].hw = + hws[IMX_ADMA_ACM_AUD_CLK1_SEL]; } ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_hw_data); @@ -406,16 +423,19 @@ static void imx8_acm_clk_remove(struct platform_device *pdev) static const struct imx8_acm_soc_data imx8qm_acm_data = { .sels = imx8qm_sels, .num_sels = ARRAY_SIZE(imx8qm_sels), + .mclk_sels = imx8qm_mclk_sels, }; static const struct imx8_acm_soc_data imx8qxp_acm_data = { .sels = imx8qxp_sels, .num_sels = ARRAY_SIZE(imx8qxp_sels), + .mclk_sels = imx8qxp_mclk_sels, }; static const struct imx8_acm_soc_data imx8dxl_acm_data = { .sels = imx8dxl_sels, .num_sels = ARRAY_SIZE(imx8dxl_sels), + .mclk_sels = imx8dxl_mclk_sels, }; static const struct of_device_id imx8_acm_match[] = { diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 075f643e3f35..342049b847b9 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -432,7 +432,7 @@ static int imx8mm_clocks_probe(struct platform_device *pdev) /* BUS */ hws[IMX8MM_CLK_MAIN_AXI] = imx8m_clk_hw_composite_bus_critical("main_axi", imx8mm_main_axi_sels, base + 0x8800); hws[IMX8MM_CLK_ENET_AXI] = imx8m_clk_hw_composite_bus("enet_axi", imx8mm_enet_axi_sels, base + 0x8880); - hws[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite_bus_critical("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900); + hws[IMX8MM_CLK_NAND_USDHC_BUS] = imx8m_clk_hw_composite("nand_usdhc_bus", imx8mm_nand_usdhc_sels, base + 0x8900); hws[IMX8MM_CLK_VPU_BUS] = imx8m_clk_hw_composite_bus("vpu_bus", imx8mm_vpu_bus_sels, base + 0x8980); hws[IMX8MM_CLK_DISP_AXI] = imx8m_clk_hw_composite_bus("disp_axi", imx8mm_disp_axi_sels, base + 0x8a00); hws[IMX8MM_CLK_DISP_APB] = imx8m_clk_hw_composite_bus("disp_apb", imx8mm_disp_apb_sels, base + 0x8a80); diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index 4bd1ed11353b..ab77e148e70c 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -583,6 +583,7 @@ static int imx8mn_clocks_probe(struct platform_device *pdev) hws[IMX8MN_CLK_SDMA2_ROOT] = imx_clk_hw_gate4("sdma2_clk", "ipg_audio_root", base + 0x43b0, 0); hws[IMX8MN_CLK_SDMA3_ROOT] = imx_clk_hw_gate4("sdma3_clk", "ipg_audio_root", base + 0x45f0, 0); hws[IMX8MN_CLK_SAI7_ROOT] = imx_clk_hw_gate2_shared2("sai7_root_clk", "sai7", base + 0x4650, 0, &share_count_sai7); + hws[IMX8MN_CLK_SAI7_IPG] = imx_clk_hw_gate2_shared2("sai7_ipg_clk", "ipg_audio_root", base + 0x4650, 0, &share_count_sai7); hws[IMX8MN_CLK_GPT_3M] = imx_clk_hw_fixed_factor("gpt_3m", "osc_24m", 1, 8); diff --git a/drivers/clk/imx/clk-imx8mp-audiomix.c b/drivers/clk/imx/clk-imx8mp-audiomix.c index b381d6f784c8..50ad5873c990 100644 --- a/drivers/clk/imx/clk-imx8mp-audiomix.c +++ b/drivers/clk/imx/clk-imx8mp-audiomix.c @@ -5,6 +5,7 @@ * Copyright (C) 2022 Marek Vasut <[email protected]> */ +#include <linux/auxiliary_bus.h> #include <linux/clk-provider.h> #include <linux/device.h> #include <linux/io.h> @@ -13,6 +14,7 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/slab.h> #include <dt-bindings/clock/imx8mp-clock.h> @@ -154,6 +156,15 @@ static const struct clk_parent_data clk_imx8mp_audiomix_pll_bypass_sels[] = { PDM_SEL, 2, 0 \ } +#define CLK_GATE_PARENT(gname, cname, pname) \ + { \ + gname"_cg", \ + IMX8MP_CLK_AUDIOMIX_##cname, \ + { .fw_name = pname, .name = pname }, NULL, 1, \ + CLKEN0 + 4 * !!(IMX8MP_CLK_AUDIOMIX_##cname / 32), \ + 1, IMX8MP_CLK_AUDIOMIX_##cname % 32 \ + } + struct clk_imx8mp_audiomix_sel { const char *name; int clkid; @@ -171,14 +182,14 @@ static struct clk_imx8mp_audiomix_sel sels[] = { CLK_GATE("earc", EARC_IPG), CLK_GATE("ocrama", OCRAMA_IPG), CLK_GATE("aud2htx", AUD2HTX_IPG), - CLK_GATE("earc_phy", EARC_PHY), + CLK_GATE_PARENT("earc_phy", EARC_PHY, "sai_pll_out_div2"), CLK_GATE("sdma2", SDMA2_ROOT), CLK_GATE("sdma3", SDMA3_ROOT), CLK_GATE("spba2", SPBA2_ROOT), CLK_GATE("dsp", DSP_ROOT), CLK_GATE("dspdbg", DSPDBG_ROOT), CLK_GATE("edma", EDMA_ROOT), - CLK_GATE("audpll", AUDPLL_ROOT), + CLK_GATE_PARENT("audpll", AUDPLL_ROOT, "osc_24m"), CLK_GATE("mu2", MU2_ROOT), CLK_GATE("mu3", MU3_ROOT), CLK_PDM, @@ -217,6 +228,63 @@ struct clk_imx8mp_audiomix_priv { struct clk_hw_onecell_data clk_data; }; +#if IS_ENABLED(CONFIG_RESET_CONTROLLER) + +static void clk_imx8mp_audiomix_reset_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +static void clk_imx8mp_audiomix_reset_adev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + + kfree(adev); +} + +static int clk_imx8mp_audiomix_reset_controller_register(struct device *dev, + struct clk_imx8mp_audiomix_priv *priv) +{ + struct auxiliary_device *adev __free(kfree) = NULL; + int ret; + + if (!of_property_present(dev->of_node, "#reset-cells")) + return 0; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + adev->name = "reset"; + adev->dev.parent = dev; + adev->dev.release = clk_imx8mp_audiomix_reset_adev_release; + + ret = auxiliary_device_init(adev); + if (ret) + return ret; + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(dev, clk_imx8mp_audiomix_reset_unregister_adev, + no_free_ptr(adev)); +} + +#else /* !CONFIG_RESET_CONTROLLER */ + +static int clk_imx8mp_audiomix_reset_controller_register(struct clk_imx8mp_audiomix_priv *priv) +{ + return 0; +} + +#endif /* !CONFIG_RESET_CONTROLLER */ + static void clk_imx8mp_audiomix_save_restore(struct device *dev, bool save) { struct clk_imx8mp_audiomix_priv *priv = dev_get_drvdata(dev); @@ -269,12 +337,12 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(sels); i++) { if (sels[i].num_parents == 1) { hw = devm_clk_hw_register_gate_parent_data(dev, - sels[i].name, &sels[i].parent, 0, + sels[i].name, &sels[i].parent, CLK_SET_RATE_PARENT, base + sels[i].reg, sels[i].shift, 0, NULL); } else { hw = devm_clk_hw_register_mux_parent_data_table(dev, sels[i].name, sels[i].parents, - sels[i].num_parents, 0, + sels[i].num_parents, CLK_SET_RATE_PARENT, base + sels[i].reg, sels[i].shift, sels[i].width, 0, NULL, NULL); @@ -317,7 +385,8 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev) clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_BYPASS] = hw; hw = devm_clk_hw_register_gate(dev, "sai_pll_out", "sai_pll_bypass", - 0, base + SAI_PLL_GNRL_CTL, 13, + CLK_SET_RATE_PARENT, + base + SAI_PLL_GNRL_CTL, 13, 0, NULL); if (IS_ERR(hw)) { ret = PTR_ERR(hw); @@ -326,7 +395,8 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev) clk_hw_data->hws[IMX8MP_CLK_AUDIOMIX_SAI_PLL_OUT] = hw; hw = devm_clk_hw_register_fixed_factor(dev, "sai_pll_out_div2", - "sai_pll_out", 0, 1, 2); + "sai_pll_out", + CLK_SET_RATE_PARENT, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto err_clk_register; @@ -337,6 +407,10 @@ static int clk_imx8mp_audiomix_probe(struct platform_device *pdev) if (ret) goto err_clk_register; + ret = clk_imx8mp_audiomix_reset_controller_register(dev, priv); + if (ret) + goto err_clk_register; + pm_runtime_put_sync(dev); return 0; diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index 670aa2bab301..516dbd170c8a 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -547,12 +547,12 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_AHB] = imx8m_clk_hw_composite_bus_critical("ahb_root", imx8mp_ahb_sels, ccm_base + 0x9000); hws[IMX8MP_CLK_AUDIO_AHB] = imx8m_clk_hw_composite_bus("audio_ahb", imx8mp_audio_ahb_sels, ccm_base + 0x9100); hws[IMX8MP_CLK_MIPI_DSI_ESC_RX] = imx8m_clk_hw_composite_bus("mipi_dsi_esc_rx", imx8mp_mipi_dsi_esc_rx_sels, ccm_base + 0x9200); - hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite_bus("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300); + hws[IMX8MP_CLK_MEDIA_DISP2_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp2_pix", imx8mp_media_disp_pix_sels, ccm_base + 0x9300, CLK_SET_RATE_PARENT); hws[IMX8MP_CLK_IPG_ROOT] = imx_clk_hw_divider2("ipg_root", "ahb_root", ccm_base + 0x9080, 0, 1); - hws[IMX8MP_CLK_DRAM_ALT] = imx8m_clk_hw_composite("dram_alt", imx8mp_dram_alt_sels, ccm_base + 0xa000); - hws[IMX8MP_CLK_DRAM_APB] = imx8m_clk_hw_composite_critical("dram_apb", imx8mp_dram_apb_sels, ccm_base + 0xa080); + hws[IMX8MP_CLK_DRAM_ALT] = imx8m_clk_hw_fw_managed_composite("dram_alt", imx8mp_dram_alt_sels, ccm_base + 0xa000); + hws[IMX8MP_CLK_DRAM_APB] = imx8m_clk_hw_fw_managed_composite_critical("dram_apb", imx8mp_dram_apb_sels, ccm_base + 0xa080); hws[IMX8MP_CLK_VPU_G1] = imx8m_clk_hw_composite("vpu_g1", imx8mp_vpu_g1_sels, ccm_base + 0xa100); hws[IMX8MP_CLK_VPU_G2] = imx8m_clk_hw_composite("vpu_g2", imx8mp_vpu_g2_sels, ccm_base + 0xa180); hws[IMX8MP_CLK_CAN1] = imx8m_clk_hw_composite("can1", imx8mp_can1_sels, ccm_base + 0xa200); @@ -609,7 +609,7 @@ static int imx8mp_clocks_probe(struct platform_device *pdev) hws[IMX8MP_CLK_USDHC3] = imx8m_clk_hw_composite("usdhc3", imx8mp_usdhc3_sels, ccm_base + 0xbc80); hws[IMX8MP_CLK_MEDIA_CAM1_PIX] = imx8m_clk_hw_composite("media_cam1_pix", imx8mp_media_cam1_pix_sels, ccm_base + 0xbd00); hws[IMX8MP_CLK_MEDIA_MIPI_PHY1_REF] = imx8m_clk_hw_composite("media_mipi_phy1_ref", imx8mp_media_mipi_phy1_ref_sels, ccm_base + 0xbd80); - hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite("media_disp1_pix", imx8mp_media_disp_pix_sels, ccm_base + 0xbe00); + hws[IMX8MP_CLK_MEDIA_DISP1_PIX] = imx8m_clk_hw_composite_bus_flags("media_disp1_pix", imx8mp_media_disp_pix_sels, ccm_base + 0xbe00, CLK_SET_RATE_PARENT); hws[IMX8MP_CLK_MEDIA_CAM2_PIX] = imx8m_clk_hw_composite("media_cam2_pix", imx8mp_media_cam2_pix_sels, ccm_base + 0xbe80); hws[IMX8MP_CLK_MEDIA_LDB] = imx8m_clk_hw_composite("media_ldb", imx8mp_media_ldb_sels, ccm_base + 0xbf00); hws[IMX8MP_CLK_MEMREPAIR] = imx8m_clk_hw_composite_critical("mem_repair", imx8mp_memrepair_sels, ccm_base + 0xbf80); diff --git a/drivers/clk/imx/clk-imx8qxp.c b/drivers/clk/imx/clk-imx8qxp.c index 7d8883916cac..3ae162625bb1 100644 --- a/drivers/clk/imx/clk-imx8qxp.c +++ b/drivers/clk/imx/clk-imx8qxp.c @@ -71,7 +71,7 @@ static const char *const lvds0_sels[] = { "clk_dummy", "clk_dummy", "clk_dummy", - "mipi0_lvds_bypass_clk", + "lvds0_bypass_clk", }; static const char *const lvds1_sels[] = { @@ -79,7 +79,7 @@ static const char *const lvds1_sels[] = { "clk_dummy", "clk_dummy", "clk_dummy", - "mipi1_lvds_bypass_clk", + "lvds1_bypass_clk", }; static const char * const mipi_sels[] = { @@ -90,6 +90,22 @@ static const char * const mipi_sels[] = { "clk_dummy", }; +static const char * const mipi0_phy_sels[] = { + "clk_dummy", + "clk_dummy", + "mipi_pll_div2_clk", + "clk_dummy", + "mipi0_bypass_clk", +}; + +static const char * const mipi1_phy_sels[] = { + "clk_dummy", + "clk_dummy", + "mipi_pll_div2_clk", + "clk_dummy", + "mipi1_bypass_clk", +}; + static const char * const lcd_sels[] = { "clk_dummy", "clk_dummy", @@ -170,8 +186,8 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) imx_clk_scu("pwm_clk", IMX_SC_R_LCD_0_PWM_0, IMX_SC_PM_CLK_PER); imx_clk_scu("elcdif_pll", IMX_SC_R_ELCDIF_PLL, IMX_SC_PM_CLK_PLL); imx_clk_scu2("lcd_clk", lcd_sels, ARRAY_SIZE(lcd_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_PER); - imx_clk_scu2("lcd_pxl_clk", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_MISC0); imx_clk_scu("lcd_pxl_bypass_div_clk", IMX_SC_R_LCD_0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu2("lcd_pxl_clk", lcd_pxl_sels, ARRAY_SIZE(lcd_pxl_sels), IMX_SC_R_LCD_0, IMX_SC_PM_CLK_MISC0); /* Audio SS */ imx_clk_scu("audio_pll0_clk", IMX_SC_R_AUDIO_PLL_0, IMX_SC_PM_CLK_PLL); @@ -206,42 +222,41 @@ static int imx8qxp_clk_probe(struct platform_device *pdev) imx_clk_scu("usb3_lpm_div", IMX_SC_R_USB_2, IMX_SC_PM_CLK_MISC); /* Display controller SS */ - imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0); - imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1); imx_clk_scu("dc0_pll0_clk", IMX_SC_R_DC_0_PLL_0, IMX_SC_PM_CLK_PLL); imx_clk_scu("dc0_pll1_clk", IMX_SC_R_DC_0_PLL_1, IMX_SC_PM_CLK_PLL); imx_clk_scu("dc0_bypass0_clk", IMX_SC_R_DC_0_VIDEO0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu2("dc0_disp0_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC0); + imx_clk_scu2("dc0_disp1_clk", dc0_sels, ARRAY_SIZE(dc0_sels), IMX_SC_R_DC_0, IMX_SC_PM_CLK_MISC1); imx_clk_scu("dc0_bypass1_clk", IMX_SC_R_DC_0_VIDEO1, IMX_SC_PM_CLK_BYPASS); - imx_clk_scu2("dc1_disp0_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC0); - imx_clk_scu2("dc1_disp1_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC1); imx_clk_scu("dc1_pll0_clk", IMX_SC_R_DC_1_PLL_0, IMX_SC_PM_CLK_PLL); imx_clk_scu("dc1_pll1_clk", IMX_SC_R_DC_1_PLL_1, IMX_SC_PM_CLK_PLL); imx_clk_scu("dc1_bypass0_clk", IMX_SC_R_DC_1_VIDEO0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu2("dc1_disp0_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC0); + imx_clk_scu2("dc1_disp1_clk", dc1_sels, ARRAY_SIZE(dc1_sels), IMX_SC_R_DC_1, IMX_SC_PM_CLK_MISC1); imx_clk_scu("dc1_bypass1_clk", IMX_SC_R_DC_1_VIDEO1, IMX_SC_PM_CLK_BYPASS); /* MIPI-LVDS SS */ imx_clk_scu("mipi0_bypass_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_BYPASS); - imx_clk_scu("mipi0_pixel_clk", IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PER); - imx_clk_scu("mipi0_lvds_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS); - imx_clk_scu2("mipi0_lvds_pixel_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2); - imx_clk_scu2("mipi0_lvds_phy_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3); + imx_clk_scu2("mipi0_pixel_clk", mipi0_phy_sels, ARRAY_SIZE(mipi0_phy_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PER); + imx_clk_scu("lvds0_bypass_clk", IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu2("lvds0_pixel_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC2); + imx_clk_scu2("lvds0_phy_clk", lvds0_sels, ARRAY_SIZE(lvds0_sels), IMX_SC_R_LVDS_0, IMX_SC_PM_CLK_MISC3); imx_clk_scu2("mipi0_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_MST_BUS); imx_clk_scu2("mipi0_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_SLV_BUS); - imx_clk_scu2("mipi0_dsi_phy_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PHY); + imx_clk_scu2("mipi0_dsi_phy_clk", mipi0_phy_sels, ARRAY_SIZE(mipi0_phy_sels), IMX_SC_R_MIPI_0, IMX_SC_PM_CLK_PHY); imx_clk_scu("mipi0_i2c0_clk", IMX_SC_R_MIPI_0_I2C_0, IMX_SC_PM_CLK_MISC2); imx_clk_scu("mipi0_i2c1_clk", IMX_SC_R_MIPI_0_I2C_1, IMX_SC_PM_CLK_MISC2); imx_clk_scu("mipi0_pwm0_clk", IMX_SC_R_MIPI_0_PWM_0, IMX_SC_PM_CLK_PER); imx_clk_scu("mipi1_bypass_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_BYPASS); - imx_clk_scu("mipi1_pixel_clk", IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PER); - imx_clk_scu("mipi1_lvds_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS); - imx_clk_scu2("mipi1_lvds_pixel_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2); - imx_clk_scu2("mipi1_lvds_phy_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3); - + imx_clk_scu2("mipi1_pixel_clk", mipi1_phy_sels, ARRAY_SIZE(mipi1_phy_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PER); + imx_clk_scu("lvds1_bypass_clk", IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_BYPASS); + imx_clk_scu2("lvds1_pixel_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC2); + imx_clk_scu2("lvds1_phy_clk", lvds1_sels, ARRAY_SIZE(lvds1_sels), IMX_SC_R_LVDS_1, IMX_SC_PM_CLK_MISC3); imx_clk_scu2("mipi1_dsi_tx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_MST_BUS); imx_clk_scu2("mipi1_dsi_rx_esc_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_SLV_BUS); - imx_clk_scu2("mipi1_dsi_phy_clk", mipi_sels, ARRAY_SIZE(mipi_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PHY); + imx_clk_scu2("mipi1_dsi_phy_clk", mipi1_phy_sels, ARRAY_SIZE(mipi1_phy_sels), IMX_SC_R_MIPI_1, IMX_SC_PM_CLK_PHY); imx_clk_scu("mipi1_i2c0_clk", IMX_SC_R_MIPI_1_I2C_0, IMX_SC_PM_CLK_MISC2); imx_clk_scu("mipi1_i2c1_clk", IMX_SC_R_MIPI_1_I2C_1, IMX_SC_PM_CLK_MISC2); imx_clk_scu("mipi1_pwm0_clk", IMX_SC_R_MIPI_1_PWM_0, IMX_SC_PM_CLK_PER); diff --git a/drivers/clk/imx/clk-imx95-blk-ctl.c b/drivers/clk/imx/clk-imx95-blk-ctl.c index 74f595f9e5e3..19a62da74be4 100644 --- a/drivers/clk/imx/clk-imx95-blk-ctl.c +++ b/drivers/clk/imx/clk-imx95-blk-ctl.c @@ -248,6 +248,35 @@ static const struct imx95_blk_ctl_dev_data dispmix_csr_dev_data = { .clk_reg_offset = 0, }; +static const struct imx95_blk_ctl_clk_dev_data netxmix_clk_dev_data[] = { + [IMX95_CLK_NETCMIX_ENETC0_RMII] = { + .name = "enetc0_rmii_sel", + .parent_names = (const char *[]){"ext_enetref", "enetref"}, + .num_parents = 2, + .reg = 4, + .bit_idx = 5, + .bit_width = 1, + .type = CLK_MUX, + .flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, + }, + [IMX95_CLK_NETCMIX_ENETC1_RMII] = { + .name = "enetc1_rmii_sel", + .parent_names = (const char *[]){"ext_enetref", "enetref"}, + .num_parents = 2, + .reg = 4, + .bit_idx = 10, + .bit_width = 1, + .type = CLK_MUX, + .flags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, + }, +}; + +static const struct imx95_blk_ctl_dev_data netcmix_dev_data = { + .num_clks = ARRAY_SIZE(netxmix_clk_dev_data), + .clk_dev_data = netxmix_clk_dev_data, + .clk_reg_offset = 0, +}; + static int imx95_bc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -419,6 +448,7 @@ static const struct of_device_id imx95_bc_of_match[] = { { .compatible = "nxp,imx95-lvds-csr", .data = &lvds_csr_dev_data }, { .compatible = "nxp,imx95-display-csr", .data = &dispmix_csr_dev_data }, { .compatible = "nxp,imx95-vpu-csr", .data = &vpublk_dev_data }, + { .compatible = "nxp,imx95-netcmix-blk-ctrl", .data = &netcmix_dev_data}, { /* Sentinel */ }, }; MODULE_DEVICE_TABLE(of, imx95_bc_of_match); diff --git a/drivers/clk/imx/clk-imxrt1050.c b/drivers/clk/imx/clk-imxrt1050.c index 08d155feb035..efd1ac9d8eeb 100644 --- a/drivers/clk/imx/clk-imxrt1050.c +++ b/drivers/clk/imx/clk-imxrt1050.c @@ -176,6 +176,7 @@ static struct platform_driver imxrt1050_clk_driver = { }; module_platform_driver(imxrt1050_clk_driver); +MODULE_DESCRIPTION("NXP i.MX RT1050 clock driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Jesse Taube <[email protected]>"); MODULE_AUTHOR("Giulio Benetti <[email protected]>"); diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index e35496af5ceb..df83bd939492 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -226,4 +226,5 @@ static int __init imx_clk_disable_uart(void) late_initcall_sync(imx_clk_disable_uart); #endif +MODULE_DESCRIPTION("Common clock support for NXP i.MX SoC family"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index adb7ad649a0d..aa5202f284f3 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -442,6 +442,10 @@ struct clk_hw *__imx8m_clk_hw_composite(const char *name, _imx8m_clk_hw_composite(name, parent_names, reg, \ IMX_COMPOSITE_BUS, IMX_COMPOSITE_CLK_FLAGS_DEFAULT) +#define imx8m_clk_hw_composite_bus_flags(name, parent_names, reg, flags) \ + _imx8m_clk_hw_composite(name, parent_names, reg, \ + IMX_COMPOSITE_BUS, IMX_COMPOSITE_CLK_FLAGS_DEFAULT | flags) + #define imx8m_clk_hw_composite_bus_critical(name, parent_names, reg) \ _imx8m_clk_hw_composite(name, parent_names, reg, \ IMX_COMPOSITE_BUS, IMX_COMPOSITE_CLK_FLAGS_CRITICAL) diff --git a/drivers/clk/kunit_clk_fixed_rate_test.dtso b/drivers/clk/kunit_clk_fixed_rate_test.dtso new file mode 100644 index 000000000000..d838ce766fa2 --- /dev/null +++ b/drivers/clk/kunit_clk_fixed_rate_test.dtso @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "clk-fixed-rate_test.h" + +&{/} { + fixed_50MHz: kunit-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <TEST_FIXED_FREQUENCY>; + clock-accuracy = <TEST_FIXED_ACCURACY>; + }; + + kunit-clock-consumer { + compatible = "test,single-clk-consumer"; + clocks = <&fixed_50MHz>; + }; +}; diff --git a/drivers/clk/kunit_clk_parent_data_test.dtso b/drivers/clk/kunit_clk_parent_data_test.dtso new file mode 100644 index 000000000000..7d3ed9a5a2e8 --- /dev/null +++ b/drivers/clk/kunit_clk_parent_data_test.dtso @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +#include "clk_parent_data_test.h" + +&{/} { + fixed_50: kunit-clock-50MHz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = CLK_PARENT_DATA_50MHZ_NAME; + }; + + fixed_parent: kunit-clock-1MHz { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + clock-output-names = CLK_PARENT_DATA_1MHZ_NAME; + }; + + kunit-clock-controller { + compatible = "test,clk-parent-data"; + clocks = <&fixed_parent>, <&fixed_50>; + clock-names = CLK_PARENT_DATA_PARENT1, CLK_PARENT_DATA_PARENT2; + #clock-cells = <1>; + }; +}; diff --git a/drivers/clk/mediatek/reset.c b/drivers/clk/mediatek/reset.c index 290ceda84ce4..2e3303975096 100644 --- a/drivers/clk/mediatek/reset.c +++ b/drivers/clk/mediatek/reset.c @@ -110,65 +110,6 @@ static int reset_xlate(struct reset_controller_dev *rcdev, return data->desc->rst_idx_map[reset_spec->args[0]]; } -int mtk_register_reset_controller(struct device_node *np, - const struct mtk_clk_rst_desc *desc) -{ - struct regmap *regmap; - const struct reset_control_ops *rcops = NULL; - struct mtk_clk_rst_data *data; - int ret; - - if (!desc) { - pr_err("mtk clock reset desc is NULL\n"); - return -EINVAL; - } - - switch (desc->version) { - case MTK_RST_SIMPLE: - rcops = &mtk_reset_ops; - break; - case MTK_RST_SET_CLR: - rcops = &mtk_reset_ops_set_clr; - break; - default: - pr_err("Unknown reset version %d\n", desc->version); - return -EINVAL; - } - - regmap = device_node_to_regmap(np); - if (IS_ERR(regmap)) { - pr_err("Cannot find regmap for %pOF: %pe\n", np, regmap); - return -EINVAL; - } - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->desc = desc; - data->regmap = regmap; - data->rcdev.owner = THIS_MODULE; - data->rcdev.ops = rcops; - data->rcdev.of_node = np; - - if (data->desc->rst_idx_map_nr > 0) { - data->rcdev.of_reset_n_cells = 1; - data->rcdev.nr_resets = desc->rst_idx_map_nr; - data->rcdev.of_xlate = reset_xlate; - } else { - data->rcdev.nr_resets = desc->rst_bank_nr * RST_NR_PER_BANK; - } - - ret = reset_controller_register(&data->rcdev); - if (ret) { - pr_err("could not register reset controller: %d\n", ret); - kfree(data); - return ret; - } - - return 0; -} - int mtk_register_reset_controller_with_dev(struct device *dev, const struct mtk_clk_rst_desc *desc) { @@ -198,7 +139,7 @@ int mtk_register_reset_controller_with_dev(struct device *dev, regmap = device_node_to_regmap(np); if (IS_ERR(regmap)) { dev_err(dev, "Cannot find regmap %pe\n", regmap); - return -EINVAL; + return PTR_ERR(regmap); } data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); diff --git a/drivers/clk/mediatek/reset.h b/drivers/clk/mediatek/reset.h index 6a58a3d59165..562ffd290a22 100644 --- a/drivers/clk/mediatek/reset.h +++ b/drivers/clk/mediatek/reset.h @@ -60,16 +60,6 @@ struct mtk_clk_rst_data { }; /** - * mtk_register_reset_controller - Register MediaTek clock reset controller - * @np: Pointer to device node. - * @desc: Constant pointer to description of clock reset. - * - * Return: 0 on success and errorno otherwise. - */ -int mtk_register_reset_controller(struct device_node *np, - const struct mtk_clk_rst_desc *desc); - -/** * mtk_register_reset_controller - Register mediatek clock reset controller with device * @np: Pointer to device. * @desc: Constant pointer to description of clock reset. diff --git a/drivers/clk/meson/a1-peripherals.c b/drivers/clk/meson/a1-peripherals.c index 99b5bc450446..7aa6abb2eb1f 100644 --- a/drivers/clk/meson/a1-peripherals.c +++ b/drivers/clk/meson/a1-peripherals.c @@ -2183,7 +2183,7 @@ static struct clk_regmap *const a1_periphs_regmaps[] = { &dmc_sel2, }; -static struct regmap_config a1_periphs_regmap_cfg = { +static const struct regmap_config a1_periphs_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -2246,3 +2246,4 @@ MODULE_DESCRIPTION("Amlogic A1 Peripherals Clock Controller driver"); MODULE_AUTHOR("Jian Hu <[email protected]>"); MODULE_AUTHOR("Dmitry Rokosov <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c index a16e537d139a..8e5a42d1afbb 100644 --- a/drivers/clk/meson/a1-pll.c +++ b/drivers/clk/meson/a1-pll.c @@ -295,7 +295,7 @@ static struct clk_regmap *const a1_pll_regmaps[] = { &hifi_pll, }; -static struct regmap_config a1_pll_regmap_cfg = { +static const struct regmap_config a1_pll_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -360,3 +360,4 @@ MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver"); MODULE_AUTHOR("Jian Hu <[email protected]>"); MODULE_AUTHOR("Dmitry Rokosov <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/axg-aoclk.c b/drivers/clk/meson/axg-aoclk.c index fa1dcb7f91e4..1dabc81535a6 100644 --- a/drivers/clk/meson/axg-aoclk.c +++ b/drivers/clk/meson/axg-aoclk.c @@ -342,3 +342,4 @@ module_platform_driver(axg_aoclkc_driver); MODULE_DESCRIPTION("Amlogic AXG Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/axg-audio.c b/drivers/clk/meson/axg-audio.c index e03a5bf899c0..beda86349389 100644 --- a/drivers/clk/meson/axg-audio.c +++ b/drivers/clk/meson/axg-audio.c @@ -753,6 +753,9 @@ static struct clk_regmap toddr_d = AUD_PCLK_GATE(toddr_d, AUDIO_CLK_GATE_EN1, 1); static struct clk_regmap loopback_b = AUD_PCLK_GATE(loopback_b, AUDIO_CLK_GATE_EN1, 2); +static struct clk_regmap earcrx = + AUD_PCLK_GATE(earcrx, AUDIO_CLK_GATE_EN1, 6); + static struct clk_regmap sm1_mst_a_mclk_sel = AUD_MST_MCLK_MUX(mst_a_mclk, AUDIO_SM1_MCLK_A_CTRL); @@ -766,6 +769,10 @@ static struct clk_regmap sm1_mst_e_mclk_sel = AUD_MST_MCLK_MUX(mst_e_mclk, AUDIO_SM1_MCLK_E_CTRL); static struct clk_regmap sm1_mst_f_mclk_sel = AUD_MST_MCLK_MUX(mst_f_mclk, AUDIO_SM1_MCLK_F_CTRL); +static struct clk_regmap sm1_earcrx_cmdc_clk_sel = + AUD_MST_MCLK_MUX(earcrx_cmdc_clk, AUDIO_EARCRX_CMDC_CLK_CTRL); +static struct clk_regmap sm1_earcrx_dmac_clk_sel = + AUD_MST_MCLK_MUX(earcrx_dmac_clk, AUDIO_EARCRX_DMAC_CLK_CTRL); static struct clk_regmap sm1_mst_a_mclk_div = AUD_MST_MCLK_DIV(mst_a_mclk, AUDIO_SM1_MCLK_A_CTRL); @@ -779,6 +786,11 @@ static struct clk_regmap sm1_mst_e_mclk_div = AUD_MST_MCLK_DIV(mst_e_mclk, AUDIO_SM1_MCLK_E_CTRL); static struct clk_regmap sm1_mst_f_mclk_div = AUD_MST_MCLK_DIV(mst_f_mclk, AUDIO_SM1_MCLK_F_CTRL); +static struct clk_regmap sm1_earcrx_cmdc_clk_div = + AUD_MST_MCLK_DIV(earcrx_cmdc_clk, AUDIO_EARCRX_CMDC_CLK_CTRL); +static struct clk_regmap sm1_earcrx_dmac_clk_div = + AUD_MST_MCLK_DIV(earcrx_dmac_clk, AUDIO_EARCRX_DMAC_CLK_CTRL); + static struct clk_regmap sm1_mst_a_mclk = AUD_MST_MCLK_GATE(mst_a_mclk, AUDIO_SM1_MCLK_A_CTRL); @@ -792,6 +804,10 @@ static struct clk_regmap sm1_mst_e_mclk = AUD_MST_MCLK_GATE(mst_e_mclk, AUDIO_SM1_MCLK_E_CTRL); static struct clk_regmap sm1_mst_f_mclk = AUD_MST_MCLK_GATE(mst_f_mclk, AUDIO_SM1_MCLK_F_CTRL); +static struct clk_regmap sm1_earcrx_cmdc_clk = + AUD_MST_MCLK_GATE(earcrx_cmdc_clk, AUDIO_EARCRX_CMDC_CLK_CTRL); +static struct clk_regmap sm1_earcrx_dmac_clk = + AUD_MST_MCLK_GATE(earcrx_dmac_clk, AUDIO_EARCRX_DMAC_CLK_CTRL); static struct clk_regmap sm1_tdm_mclk_pad_0 = AUD_TDM_PAD_CTRL( tdm_mclk_pad_0, AUDIO_SM1_MST_PAD_CTRL0, 0, mclk_pad_ctrl_parent_data); @@ -1232,6 +1248,13 @@ static struct clk_hw *sm1_audio_hw_clks[] = { [AUD_CLKID_SYSCLK_A_EN] = &sm1_sysclk_a_en.hw, [AUD_CLKID_SYSCLK_B_DIV] = &sm1_sysclk_b_div.hw, [AUD_CLKID_SYSCLK_B_EN] = &sm1_sysclk_b_en.hw, + [AUD_CLKID_EARCRX] = &earcrx.hw, + [AUD_CLKID_EARCRX_CMDC_SEL] = &sm1_earcrx_cmdc_clk_sel.hw, + [AUD_CLKID_EARCRX_CMDC_DIV] = &sm1_earcrx_cmdc_clk_div.hw, + [AUD_CLKID_EARCRX_CMDC] = &sm1_earcrx_cmdc_clk.hw, + [AUD_CLKID_EARCRX_DMAC_SEL] = &sm1_earcrx_dmac_clk_sel.hw, + [AUD_CLKID_EARCRX_DMAC_DIV] = &sm1_earcrx_dmac_clk_div.hw, + [AUD_CLKID_EARCRX_DMAC] = &sm1_earcrx_dmac_clk.hw, }; @@ -1646,6 +1669,13 @@ static struct clk_regmap *const sm1_clk_regmaps[] = { &sm1_sysclk_a_en, &sm1_sysclk_b_div, &sm1_sysclk_b_en, + &earcrx, + &sm1_earcrx_cmdc_clk_sel, + &sm1_earcrx_cmdc_clk_div, + &sm1_earcrx_cmdc_clk, + &sm1_earcrx_dmac_clk_sel, + &sm1_earcrx_dmac_clk_div, + &sm1_earcrx_dmac_clk, }; struct axg_audio_reset_data { @@ -1726,11 +1756,10 @@ static const struct reset_control_ops axg_audio_rstc_ops = { .status = axg_audio_reset_status, }; -static const struct regmap_config axg_audio_regmap_cfg = { +static struct regmap_config axg_audio_regmap_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .max_register = AUDIO_CLK_SPDIFOUT_B_CTRL, }; struct audioclk_data { @@ -1739,6 +1768,7 @@ struct audioclk_data { struct meson_clk_hw_data hw_clks; unsigned int reset_offset; unsigned int reset_num; + unsigned int max_register; }; static int axg_audio_clkc_probe(struct platform_device *pdev) @@ -1760,6 +1790,7 @@ static int axg_audio_clkc_probe(struct platform_device *pdev) if (IS_ERR(regs)) return PTR_ERR(regs); + axg_audio_regmap_cfg.max_register = data->max_register; map = devm_regmap_init_mmio(dev, regs, &axg_audio_regmap_cfg); if (IS_ERR(map)) { dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(map)); @@ -1828,6 +1859,7 @@ static const struct audioclk_data axg_audioclk_data = { .hws = axg_audio_hw_clks, .num = ARRAY_SIZE(axg_audio_hw_clks), }, + .max_register = AUDIO_CLK_PDMIN_CTRL1, }; static const struct audioclk_data g12a_audioclk_data = { @@ -1839,6 +1871,7 @@ static const struct audioclk_data g12a_audioclk_data = { }, .reset_offset = AUDIO_SW_RESET, .reset_num = 26, + .max_register = AUDIO_CLK_SPDIFOUT_B_CTRL, }; static const struct audioclk_data sm1_audioclk_data = { @@ -1850,6 +1883,7 @@ static const struct audioclk_data sm1_audioclk_data = { }, .reset_offset = AUDIO_SM1_SW_RESET0, .reset_num = 39, + .max_register = AUDIO_EARCRX_DMAC_CLK_CTRL, }; static const struct of_device_id clkc_match_table[] = { @@ -1878,3 +1912,4 @@ module_platform_driver(axg_audio_driver); MODULE_DESCRIPTION("Amlogic AXG/G12A/SM1 Audio Clock driver"); MODULE_AUTHOR("Jerome Brunet <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/axg-audio.h b/drivers/clk/meson/axg-audio.h index 01a3da19933e..9e7765b630c9 100644 --- a/drivers/clk/meson/axg-audio.h +++ b/drivers/clk/meson/axg-audio.h @@ -64,5 +64,7 @@ #define AUDIO_SM1_SW_RESET1 0x02C #define AUDIO_CLK81_CTRL 0x030 #define AUDIO_CLK81_EN 0x034 +#define AUDIO_EARCRX_CMDC_CLK_CTRL 0x0D0 +#define AUDIO_EARCRX_DMAC_CLK_CTRL 0x0D4 #endif /*__AXG_AUDIO_CLKC_H */ diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 065b5f198297..757c7a28c53d 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -2187,3 +2187,4 @@ module_platform_driver(axg_driver); MODULE_DESCRIPTION("Amlogic AXG Main Clock Controller driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/c3-peripherals.c b/drivers/clk/meson/c3-peripherals.c index 56b33d23c317..7dcbf4ebee07 100644 --- a/drivers/clk/meson/c3-peripherals.c +++ b/drivers/clk/meson/c3-peripherals.c @@ -2296,7 +2296,7 @@ static struct clk_regmap *const c3_periphs_clk_regmaps[] = { &vapb, }; -static struct regmap_config clkc_regmap_config = { +static const struct regmap_config clkc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -2364,3 +2364,4 @@ module_platform_driver(c3_peripherals_driver); MODULE_DESCRIPTION("Amlogic C3 Peripherals Clock Controller driver"); MODULE_AUTHOR("Chuan Liu <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/c3-pll.c b/drivers/clk/meson/c3-pll.c index 6d5271c61d14..32bd2ed9d304 100644 --- a/drivers/clk/meson/c3-pll.c +++ b/drivers/clk/meson/c3-pll.c @@ -678,7 +678,7 @@ static struct clk_regmap *const c3_pll_clk_regmaps[] = { &mclk1, }; -static struct regmap_config clkc_regmap_config = { +static const struct regmap_config clkc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -745,3 +745,4 @@ module_platform_driver(c3_pll_driver); MODULE_DESCRIPTION("Amlogic C3 PLL Clock Controller driver"); MODULE_AUTHOR("Chuan Liu <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/clk-cpu-dyndiv.c b/drivers/clk/meson/clk-cpu-dyndiv.c index aa824b030cb8..6c1f58826e24 100644 --- a/drivers/clk/meson/clk-cpu-dyndiv.c +++ b/drivers/clk/meson/clk-cpu-dyndiv.c @@ -65,8 +65,9 @@ const struct clk_ops meson_clk_cpu_dyndiv_ops = { .determine_rate = meson_clk_cpu_dyndiv_determine_rate, .set_rate = meson_clk_cpu_dyndiv_set_rate, }; -EXPORT_SYMBOL_GPL(meson_clk_cpu_dyndiv_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_cpu_dyndiv_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic CPU Dynamic Clock divider"); MODULE_AUTHOR("Neil Armstrong <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/clk-dualdiv.c b/drivers/clk/meson/clk-dualdiv.c index d46c02b51be5..913bf25d3771 100644 --- a/drivers/clk/meson/clk-dualdiv.c +++ b/drivers/clk/meson/clk-dualdiv.c @@ -130,14 +130,15 @@ const struct clk_ops meson_clk_dualdiv_ops = { .determine_rate = meson_clk_dualdiv_determine_rate, .set_rate = meson_clk_dualdiv_set_rate, }; -EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_dualdiv_ops, CLK_MESON); const struct clk_ops meson_clk_dualdiv_ro_ops = { .recalc_rate = meson_clk_dualdiv_recalc_rate, }; -EXPORT_SYMBOL_GPL(meson_clk_dualdiv_ro_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_dualdiv_ro_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic dual divider driver"); MODULE_AUTHOR("Neil Armstrong <[email protected]>"); MODULE_AUTHOR("Jerome Brunet <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c index eae9b7dc5a6c..f639d56f0fd3 100644 --- a/drivers/clk/meson/clk-mpll.c +++ b/drivers/clk/meson/clk-mpll.c @@ -165,7 +165,7 @@ const struct clk_ops meson_clk_mpll_ro_ops = { .recalc_rate = mpll_recalc_rate, .determine_rate = mpll_determine_rate, }; -EXPORT_SYMBOL_GPL(meson_clk_mpll_ro_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ro_ops, CLK_MESON); const struct clk_ops meson_clk_mpll_ops = { .recalc_rate = mpll_recalc_rate, @@ -173,8 +173,9 @@ const struct clk_ops meson_clk_mpll_ops = { .set_rate = mpll_set_rate, .init = mpll_init, }; -EXPORT_SYMBOL_GPL(meson_clk_mpll_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_mpll_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic MPLL driver"); MODULE_AUTHOR("Michael Turquette <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/clk-phase.c b/drivers/clk/meson/clk-phase.c index ff3f0b1a3ed1..c1526fbfb6c4 100644 --- a/drivers/clk/meson/clk-phase.c +++ b/drivers/clk/meson/clk-phase.c @@ -61,7 +61,7 @@ const struct clk_ops meson_clk_phase_ops = { .get_phase = meson_clk_phase_get_phase, .set_phase = meson_clk_phase_set_phase, }; -EXPORT_SYMBOL_GPL(meson_clk_phase_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_phase_ops, CLK_MESON); /* * This is a special clock for the audio controller. @@ -123,7 +123,7 @@ const struct clk_ops meson_clk_triphase_ops = { .get_phase = meson_clk_triphase_get_phase, .set_phase = meson_clk_triphase_set_phase, }; -EXPORT_SYMBOL_GPL(meson_clk_triphase_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_triphase_ops, CLK_MESON); /* * This is a special clock for the audio controller. @@ -178,9 +178,9 @@ const struct clk_ops meson_sclk_ws_inv_ops = { .get_phase = meson_sclk_ws_inv_get_phase, .set_phase = meson_sclk_ws_inv_set_phase, }; -EXPORT_SYMBOL_GPL(meson_sclk_ws_inv_ops); - +EXPORT_SYMBOL_NS_GPL(meson_sclk_ws_inv_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic phase driver"); MODULE_AUTHOR("Jerome Brunet <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 467dc8b61a37..bc570a2ff3a3 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -472,7 +472,7 @@ const struct clk_ops meson_clk_pcie_pll_ops = { .enable = meson_clk_pcie_pll_enable, .disable = meson_clk_pll_disable }; -EXPORT_SYMBOL_GPL(meson_clk_pcie_pll_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_pcie_pll_ops, CLK_MESON); const struct clk_ops meson_clk_pll_ops = { .init = meson_clk_pll_init, @@ -483,15 +483,16 @@ const struct clk_ops meson_clk_pll_ops = { .enable = meson_clk_pll_enable, .disable = meson_clk_pll_disable }; -EXPORT_SYMBOL_GPL(meson_clk_pll_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_pll_ops, CLK_MESON); const struct clk_ops meson_clk_pll_ro_ops = { .recalc_rate = meson_clk_pll_recalc_rate, .is_enabled = meson_clk_pll_is_enabled, }; -EXPORT_SYMBOL_GPL(meson_clk_pll_ro_ops); +EXPORT_SYMBOL_NS_GPL(meson_clk_pll_ro_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic PLL driver"); MODULE_AUTHOR("Carlo Caione <[email protected]>"); MODULE_AUTHOR("Jerome Brunet <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/clk-regmap.c b/drivers/clk/meson/clk-regmap.c index ad116d24f700..07f7e441b916 100644 --- a/drivers/clk/meson/clk-regmap.c +++ b/drivers/clk/meson/clk-regmap.c @@ -49,12 +49,12 @@ const struct clk_ops clk_regmap_gate_ops = { .disable = clk_regmap_gate_disable, .is_enabled = clk_regmap_gate_is_enabled, }; -EXPORT_SYMBOL_GPL(clk_regmap_gate_ops); +EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ops, CLK_MESON); const struct clk_ops clk_regmap_gate_ro_ops = { .is_enabled = clk_regmap_gate_is_enabled, }; -EXPORT_SYMBOL_GPL(clk_regmap_gate_ro_ops); +EXPORT_SYMBOL_NS_GPL(clk_regmap_gate_ro_ops, CLK_MESON); static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw, unsigned long prate) @@ -125,13 +125,13 @@ const struct clk_ops clk_regmap_divider_ops = { .determine_rate = clk_regmap_div_determine_rate, .set_rate = clk_regmap_div_set_rate, }; -EXPORT_SYMBOL_GPL(clk_regmap_divider_ops); +EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ops, CLK_MESON); const struct clk_ops clk_regmap_divider_ro_ops = { .recalc_rate = clk_regmap_div_recalc_rate, .determine_rate = clk_regmap_div_determine_rate, }; -EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops); +EXPORT_SYMBOL_NS_GPL(clk_regmap_divider_ro_ops, CLK_MESON); static u8 clk_regmap_mux_get_parent(struct clk_hw *hw) { @@ -174,13 +174,14 @@ const struct clk_ops clk_regmap_mux_ops = { .set_parent = clk_regmap_mux_set_parent, .determine_rate = clk_regmap_mux_determine_rate, }; -EXPORT_SYMBOL_GPL(clk_regmap_mux_ops); +EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ops, CLK_MESON); const struct clk_ops clk_regmap_mux_ro_ops = { .get_parent = clk_regmap_mux_get_parent, }; -EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops); +EXPORT_SYMBOL_NS_GPL(clk_regmap_mux_ro_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic regmap backed clock driver"); MODULE_AUTHOR("Jerome Brunet <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/g12a-aoclk.c b/drivers/clk/meson/g12a-aoclk.c index a5f4d15d8396..f0a18d8c9fc2 100644 --- a/drivers/clk/meson/g12a-aoclk.c +++ b/drivers/clk/meson/g12a-aoclk.c @@ -477,3 +477,4 @@ module_platform_driver(g12a_aoclkc_driver); MODULE_DESCRIPTION("Amlogic G12A Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c index 4647e84d2502..02dda57105b1 100644 --- a/drivers/clk/meson/g12a.c +++ b/drivers/clk/meson/g12a.c @@ -5616,3 +5616,4 @@ module_platform_driver(g12a_driver); MODULE_DESCRIPTION("Amlogic G12/SM1 Main Clock Controller driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/gxbb-aoclk.c b/drivers/clk/meson/gxbb-aoclk.c index 33fafbdf65c4..83b034157b35 100644 --- a/drivers/clk/meson/gxbb-aoclk.c +++ b/drivers/clk/meson/gxbb-aoclk.c @@ -303,3 +303,4 @@ module_platform_driver(gxbb_aoclkc_driver); MODULE_DESCRIPTION("Amlogic GXBB Always-ON Clock Controller driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index d3175e4335bb..f071faad1ebb 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -3571,3 +3571,4 @@ module_platform_driver(gxbb_driver); MODULE_DESCRIPTION("Amlogic GXBB Main Clock Controller driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/meson-aoclk.c b/drivers/clk/meson/meson-aoclk.c index 2dd064201fae..053940ee8940 100644 --- a/drivers/clk/meson/meson-aoclk.c +++ b/drivers/clk/meson/meson-aoclk.c @@ -88,7 +88,8 @@ int meson_aoclkc_probe(struct platform_device *pdev) return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); } -EXPORT_SYMBOL_GPL(meson_aoclkc_probe); +EXPORT_SYMBOL_NS_GPL(meson_aoclkc_probe, CLK_MESON); MODULE_DESCRIPTION("Amlogic Always-ON Clock Controller helpers"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/meson-clkc-utils.c b/drivers/clk/meson/meson-clkc-utils.c index 4dd5948b7ae4..a8cd2c21fab7 100644 --- a/drivers/clk/meson/meson-clkc-utils.c +++ b/drivers/clk/meson/meson-clkc-utils.c @@ -20,7 +20,8 @@ struct clk_hw *meson_clk_hw_get(struct of_phandle_args *clkspec, void *clk_hw_da return data->hws[idx]; } -EXPORT_SYMBOL_GPL(meson_clk_hw_get); +EXPORT_SYMBOL_NS_GPL(meson_clk_hw_get, CLK_MESON); MODULE_DESCRIPTION("Amlogic Clock Controller Utilities"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/meson-eeclk.c b/drivers/clk/meson/meson-eeclk.c index 570992eece86..66f79e384fe5 100644 --- a/drivers/clk/meson/meson-eeclk.c +++ b/drivers/clk/meson/meson-eeclk.c @@ -57,7 +57,8 @@ int meson_eeclkc_probe(struct platform_device *pdev) return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, (void *)&data->hw_clks); } -EXPORT_SYMBOL_GPL(meson_eeclkc_probe); +EXPORT_SYMBOL_NS_GPL(meson_eeclkc_probe, CLK_MESON); MODULE_DESCRIPTION("Amlogic Main Clock Controller Helpers"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/s4-peripherals.c b/drivers/clk/meson/s4-peripherals.c index 130c50554290..c930cf0614a0 100644 --- a/drivers/clk/meson/s4-peripherals.c +++ b/drivers/clk/meson/s4-peripherals.c @@ -3747,7 +3747,7 @@ static struct clk_regmap *const s4_periphs_clk_regmaps[] = { &s4_adc_extclk_in_gate, }; -static struct regmap_config clkc_regmap_config = { +static const struct regmap_config clkc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -3814,3 +3814,4 @@ module_platform_driver(s4_driver); MODULE_DESCRIPTION("Amlogic S4 Peripherals Clock Controller driver"); MODULE_AUTHOR("Yu Tu <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/s4-pll.c b/drivers/clk/meson/s4-pll.c index c2afade24f9f..b0258933fb9d 100644 --- a/drivers/clk/meson/s4-pll.c +++ b/drivers/clk/meson/s4-pll.c @@ -799,7 +799,7 @@ static const struct reg_sequence s4_init_regs[] = { { .reg = ANACTRL_MPLL_CTRL0, .def = 0x00000543 }, }; -static struct regmap_config clkc_regmap_config = { +static const struct regmap_config clkc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -873,3 +873,4 @@ module_platform_driver(s4_driver); MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver"); MODULE_AUTHOR("Yu Tu <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/sclk-div.c b/drivers/clk/meson/sclk-div.c index 987f5b06587c..ae03b048182f 100644 --- a/drivers/clk/meson/sclk-div.c +++ b/drivers/clk/meson/sclk-div.c @@ -247,8 +247,9 @@ const struct clk_ops meson_sclk_div_ops = { .set_duty_cycle = sclk_div_set_duty_cycle, .init = sclk_div_init, }; -EXPORT_SYMBOL_GPL(meson_sclk_div_ops); +EXPORT_SYMBOL_NS_GPL(meson_sclk_div_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic Sample divider driver"); MODULE_AUTHOR("Jerome Brunet <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/vclk.c b/drivers/clk/meson/vclk.c index e886df55d6e3..36f637d2d01b 100644 --- a/drivers/clk/meson/vclk.c +++ b/drivers/clk/meson/vclk.c @@ -49,7 +49,7 @@ const struct clk_ops meson_vclk_gate_ops = { .disable = meson_vclk_gate_disable, .is_enabled = meson_vclk_gate_is_enabled, }; -EXPORT_SYMBOL_GPL(meson_vclk_gate_ops); +EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops, CLK_MESON); /* The VCLK Divider has supplementary reset & enable bits */ @@ -134,8 +134,9 @@ const struct clk_ops meson_vclk_div_ops = { .disable = meson_vclk_div_disable, .is_enabled = meson_vclk_div_is_enabled, }; -EXPORT_SYMBOL_GPL(meson_vclk_div_ops); +EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic vclk clock driver"); MODULE_AUTHOR("Neil Armstrong <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/meson/vid-pll-div.c b/drivers/clk/meson/vid-pll-div.c index ee129f86794d..486cf68fc97a 100644 --- a/drivers/clk/meson/vid-pll-div.c +++ b/drivers/clk/meson/vid-pll-div.c @@ -92,8 +92,9 @@ static unsigned long meson_vid_pll_div_recalc_rate(struct clk_hw *hw, const struct clk_ops meson_vid_pll_div_ro_ops = { .recalc_rate = meson_vid_pll_div_recalc_rate, }; -EXPORT_SYMBOL_GPL(meson_vid_pll_div_ro_ops); +EXPORT_SYMBOL_NS_GPL(meson_vid_pll_div_ro_ops, CLK_MESON); MODULE_DESCRIPTION("Amlogic video pll divider driver"); MODULE_AUTHOR("Neil Armstrong <[email protected]>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(CLK_MESON); diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index 454d131f475e..07ac9e6937e5 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -447,7 +447,6 @@ struct clk *mmp_clk_register_mix(struct device *dev, struct mmp_clk_mix *mix; struct clk *clk; struct clk_init_data init; - size_t table_bytes; mix = kzalloc(sizeof(*mix), GFP_KERNEL); if (!mix) @@ -461,8 +460,8 @@ struct clk *mmp_clk_register_mix(struct device *dev, memcpy(&mix->reg_info, &config->reg_info, sizeof(config->reg_info)); if (config->table) { - table_bytes = sizeof(*config->table) * config->table_size; - mix->table = kmemdup(config->table, table_bytes, GFP_KERNEL); + mix->table = kmemdup_array(config->table, config->table_size, + sizeof(*mix->table), GFP_KERNEL); if (!mix->table) goto free_mix; @@ -470,9 +469,8 @@ struct clk *mmp_clk_register_mix(struct device *dev, } if (config->mux_table) { - table_bytes = sizeof(u32) * num_parents; - mix->mux_table = kmemdup(config->mux_table, table_bytes, - GFP_KERNEL); + mix->mux_table = kmemdup_array(config->mux_table, num_parents, + sizeof(*mix->mux_table), GFP_KERNEL); if (!mix->mux_table) { kfree(mix->table); goto free_mix; diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index 4410d16de4e2..76791a1c50ac 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -40,6 +40,7 @@ config CLK_RENESAS select CLK_R9A07G054 if ARCH_R9A07G054 select CLK_R9A08G045 if ARCH_R9A08G045 select CLK_R9A09G011 if ARCH_R9A09G011 + select CLK_R9A09G057 if ARCH_R9A09G057 select CLK_SH73A0 if ARCH_SH73A0 if CLK_RENESAS @@ -193,6 +194,10 @@ config CLK_R9A09G011 bool "RZ/V2M clock support" if COMPILE_TEST select CLK_RZG2L +config CLK_R9A09G057 + bool "RZ/V2H(P) clock support" if COMPILE_TEST + select CLK_RZV2H + config CLK_SH73A0 bool "SH-Mobile AG5 clock support" if COMPILE_TEST select CLK_RENESAS_CPG_MSTP @@ -228,6 +233,10 @@ config CLK_RZG2L bool "RZ/{G2L,G2UL,G3S,V2L} family clock support" if COMPILE_TEST select RESET_CONTROLLER +config CLK_RZV2H + bool "RZ/V2H(P) family clock support" if COMPILE_TEST + select RESET_CONTROLLER + # Generic config CLK_RENESAS_CPG_MSSR bool "CPG/MSSR clock support" if COMPILE_TEST diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index f7e18679c3b8..23d2e26051c8 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o obj-$(CONFIG_CLK_R9A07G054) += r9a07g044-cpg.o obj-$(CONFIG_CLK_R9A08G045) += r9a08g045-cpg.o obj-$(CONFIG_CLK_R9A09G011) += r9a09g011-cpg.o +obj-$(CONFIG_CLK_R9A09G057) += r9a09g057-cpg.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o # Family @@ -46,6 +47,7 @@ obj-$(CONFIG_CLK_RCAR_GEN3_CPG) += rcar-gen3-cpg.o obj-$(CONFIG_CLK_RCAR_GEN4_CPG) += rcar-gen4-cpg.o obj-$(CONFIG_CLK_RCAR_USB2_CLOCK_SEL) += rcar-usb2-clock-sel.o obj-$(CONFIG_CLK_RZG2L) += rzg2l-cpg.o +obj-$(CONFIG_CLK_RZV2H) += rzv2h-cpg.o # Generic obj-$(CONFIG_CLK_RENESAS_CPG_MSSR) += renesas-cpg-mssr.o diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 5304c977562f..5bc473c2adb3 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -207,7 +207,7 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) for (i = 0; i < MSTP_MAX_CLOCKS; ++i) clks[i] = ERR_PTR(-ENOENT); - if (of_find_property(np, "clock-indices", &i)) + if (of_property_present(np, "clock-indices")) idxname = "clock-indices"; else idxname = "renesas,clock-indices"; diff --git a/drivers/clk/renesas/r8a779a0-cpg-mssr.c b/drivers/clk/renesas/r8a779a0-cpg-mssr.c index ff3f85e906fe..4c8e4c69c1bf 100644 --- a/drivers/clk/renesas/r8a779a0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779a0-cpg-mssr.c @@ -61,6 +61,11 @@ enum clk_ids { DEF_BASE(_name, _id, CLK_TYPE_GEN4_PLL2X_3X, CLK_MAIN, \ .offset = _offset) +#define CPG_PLL20CR 0x0834 /* PLL20 Control Register */ +#define CPG_PLL21CR 0x0838 /* PLL21 Control Register */ +#define CPG_PLL30CR 0x083c /* PLL30 Control Register */ +#define CPG_PLL31CR 0x0840 /* PLL31 Control Register */ + static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { /* External Clock Inputs */ DEF_INPUT("extal", CLK_EXTAL), @@ -70,10 +75,10 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL), DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN), DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN), - DEF_PLL(".pll20", CLK_PLL20, 0x0834), - DEF_PLL(".pll21", CLK_PLL21, 0x0838), - DEF_PLL(".pll30", CLK_PLL30, 0x083c), - DEF_PLL(".pll31", CLK_PLL31, 0x0840), + DEF_PLL(".pll20", CLK_PLL20, CPG_PLL20CR), + DEF_PLL(".pll21", CLK_PLL21, CPG_PLL21CR), + DEF_PLL(".pll30", CLK_PLL30, CPG_PLL30CR), + DEF_PLL(".pll31", CLK_PLL31, CPG_PLL31CR), DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), DEF_FIXED(".pll20_div2", CLK_PLL20_DIV2, CLK_PLL20, 2, 1), @@ -116,17 +121,17 @@ static const struct cpg_core_clk r8a779a0_core_clks[] __initconst = { DEF_FIXED("cp", R8A779A0_CLK_CP, CLK_EXTAL, 2, 1), DEF_FIXED("cl16mck", R8A779A0_CLK_CL16MCK, CLK_PLL1_DIV2, 64, 1), - DEF_GEN4_SDH("sd0h", R8A779A0_CLK_SD0H, CLK_SDSRC, 0x870), - DEF_GEN4_SD("sd0", R8A779A0_CLK_SD0, R8A779A0_CLK_SD0H, 0x870), + DEF_GEN4_SDH("sd0h", R8A779A0_CLK_SD0H, CLK_SDSRC, CPG_SD0CKCR), + DEF_GEN4_SD("sd0", R8A779A0_CLK_SD0, R8A779A0_CLK_SD0H, CPG_SD0CKCR), DEF_BASE("rpc", R8A779A0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC), DEF_BASE("rpcd2", R8A779A0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779A0_CLK_RPC), - DEF_DIV6P1("mso", R8A779A0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), - DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), - DEF_DIV6P1("csi0", R8A779A0_CLK_CSI0, CLK_PLL5_DIV4, 0x880), - DEF_DIV6P1("dsi", R8A779A0_CLK_DSI, CLK_PLL5_DIV4, 0x884), + DEF_DIV6P1("mso", R8A779A0_CLK_MSO, CLK_PLL5_DIV4, CPG_MSOCKCR), + DEF_DIV6P1("canfd", R8A779A0_CLK_CANFD, CLK_PLL5_DIV4, CPG_CANFDCKCR), + DEF_DIV6P1("csi0", R8A779A0_CLK_CSI0, CLK_PLL5_DIV4, CPG_CSICKCR), + DEF_DIV6P1("dsi", R8A779A0_CLK_DSI, CLK_PLL5_DIV4, CPG_DSIEXTCKCR), DEF_GEN4_OSC("osc", R8A779A0_CLK_OSC, CLK_EXTAL, 8), DEF_GEN4_MDSEL("r", R8A779A0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1), @@ -253,12 +258,12 @@ static const unsigned int r8a779a0_crit_mod_clks[] __initconst = { */ #define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \ (((md) & BIT(13)) >> 13)) -static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] = { - /* EXTAL div PLL1 mult/div PLL2 mult/div PLL3 mult/div PLL4 mult/div PLL5 mult/div PLL6 mult/div OSC prediv */ - { 1, 128, 1, 0, 0, 0, 0, 144, 1, 192, 1, 0, 0, 16, }, - { 1, 106, 1, 0, 0, 0, 0, 120, 1, 160, 1, 0, 0, 19, }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - { 2, 128, 1, 0, 0, 0, 0, 144, 1, 192, 1, 0, 0, 32, }, +static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] __initconst = { + /* EXTAL div PLL1 mult/div PLL5 mult/div OSC prediv */ + { 1, 128, 1, 192, 1, 16, }, + { 1, 106, 1, 160, 1, 19, }, + { 0, 0, 0, 0, 0, 0, }, + { 2, 128, 1, 192, 1, 32, }, }; diff --git a/drivers/clk/renesas/r8a779f0-cpg-mssr.c b/drivers/clk/renesas/r8a779f0-cpg-mssr.c index cc06127406ab..f33342314b2e 100644 --- a/drivers/clk/renesas/r8a779f0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779f0-cpg-mssr.c @@ -57,12 +57,12 @@ static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = { DEF_INPUT("extalr", CLK_EXTALR), /* Internal Core Clocks */ - DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL), - DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN), - DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN4_PLL2, CLK_MAIN), - DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN4_PLL3, CLK_MAIN), - DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN), - DEF_BASE(".pll6", CLK_PLL6, CLK_TYPE_GEN4_PLL6, CLK_MAIN), + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL), + DEF_GEN4_PLL_F9_24(".pll1", 1, CLK_PLL1, CLK_MAIN), + DEF_GEN4_PLL_V9_24(".pll2", 2, CLK_PLL2, CLK_MAIN), + DEF_GEN4_PLL_V9_24(".pll3", 3, CLK_PLL3, CLK_MAIN), + DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN), + DEF_GEN4_PLL_V9_24(".pll6", 6, CLK_PLL6, CLK_MAIN), DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 2, 1), @@ -115,13 +115,13 @@ static const struct cpg_core_clk r8a779f0_core_clks[] __initconst = { DEF_FIXED("sasyncperd2",R8A779F0_CLK_SASYNCPERD2, CLK_SASYNCPER,2, 1), DEF_FIXED("sasyncperd4",R8A779F0_CLK_SASYNCPERD4, CLK_SASYNCPER,4, 1), - DEF_GEN4_SDH("sd0h", R8A779F0_CLK_SD0H, CLK_SDSRC, 0x870), - DEF_GEN4_SD("sd0", R8A779F0_CLK_SD0, R8A779F0_CLK_SD0H, 0x870), + DEF_GEN4_SDH("sd0h", R8A779F0_CLK_SD0H, CLK_SDSRC, CPG_SD0CKCR), + DEF_GEN4_SD("sd0", R8A779F0_CLK_SD0, R8A779F0_CLK_SD0H, CPG_SD0CKCR), DEF_BASE("rpc", R8A779F0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC), DEF_BASE("rpcd2", R8A779F0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779F0_CLK_RPC), - DEF_DIV6P1("mso", R8A779F0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), + DEF_DIV6P1("mso", R8A779F0_CLK_MSO, CLK_PLL5_DIV4, CPG_MSOCKCR), DEF_GEN4_OSC("osc", R8A779F0_CLK_OSC, CLK_EXTAL, 8), DEF_GEN4_MDSEL("r", R8A779F0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1), @@ -187,12 +187,12 @@ static const unsigned int r8a779f0_crit_mod_clks[] __initconst = { #define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \ (((md) & BIT(13)) >> 13)) -static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] = { - /* EXTAL div PLL1 mult/div PLL2 mult/div PLL3 mult/div PLL4 mult/div PLL5 mult/div PLL6 mult/div OSC prediv */ - { 1, 200, 1, 150, 1, 200, 1, 0, 0, 200, 1, 134, 1, 15, }, - { 1, 160, 1, 120, 1, 160, 1, 0, 0, 160, 1, 106, 1, 19, }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - { 2, 160, 1, 120, 1, 160, 1, 0, 0, 160, 1, 106, 1, 38, }, +static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] __initconst = { + /* EXTAL div PLL1 mult/div PLL5 mult/div OSC prediv */ + { 1, 200, 1, 200, 1, 15, }, + { 1, 160, 1, 160, 1, 19, }, + { 0, 0, 0, 0, 0, 0, }, + { 2, 160, 1, 160, 1, 38, }, }; static int __init r8a779f0_cpg_mssr_init(struct device *dev) diff --git a/drivers/clk/renesas/r8a779g0-cpg-mssr.c b/drivers/clk/renesas/r8a779g0-cpg-mssr.c index c4b1938db76b..55c8dd032fc3 100644 --- a/drivers/clk/renesas/r8a779g0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779g0-cpg-mssr.c @@ -66,13 +66,13 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { DEF_INPUT("extalr", CLK_EXTALR), /* Internal Core Clocks */ - DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL), - DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN), - DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN4_PLL2_VAR, CLK_MAIN), - DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN4_PLL3, CLK_MAIN), - DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN4_PLL4, CLK_MAIN), - DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN), - DEF_BASE(".pll6", CLK_PLL6, CLK_TYPE_GEN4_PLL6, CLK_MAIN), + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL), + DEF_GEN4_PLL_F8_25(".pll1", 1, CLK_PLL1, CLK_MAIN), + DEF_GEN4_PLL_V8_25(".pll2", 2, CLK_PLL2, CLK_MAIN), + DEF_GEN4_PLL_V8_25(".pll3", 3, CLK_PLL3, CLK_MAIN), + DEF_GEN4_PLL_V8_25(".pll4", 4, CLK_PLL4, CLK_MAIN), + DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN), + DEF_GEN4_PLL_V8_25(".pll6", 6, CLK_PLL6, CLK_MAIN), DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 2, 1), @@ -146,14 +146,14 @@ static const struct cpg_core_clk r8a779g0_core_clks[] __initconst = { DEF_FIXED("viobusd2", R8A779G0_CLK_VIOBUSD2, CLK_VIO, 2, 1), DEF_FIXED("vcbus", R8A779G0_CLK_VCBUS, CLK_VC, 1, 1), DEF_FIXED("vcbusd2", R8A779G0_CLK_VCBUSD2, CLK_VC, 2, 1), - DEF_DIV6P1("canfd", R8A779G0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), - DEF_DIV6P1("csi", R8A779G0_CLK_CSI, CLK_PLL5_DIV4, 0x880), + DEF_DIV6P1("canfd", R8A779G0_CLK_CANFD, CLK_PLL5_DIV4, CPG_CANFDCKCR), + DEF_DIV6P1("csi", R8A779G0_CLK_CSI, CLK_PLL5_DIV4, CPG_CSICKCR), DEF_FIXED("dsiref", R8A779G0_CLK_DSIREF, CLK_PLL5_DIV4, 48, 1), - DEF_DIV6P1("dsiext", R8A779G0_CLK_DSIEXT, CLK_PLL5_DIV4, 0x884), + DEF_DIV6P1("dsiext", R8A779G0_CLK_DSIEXT, CLK_PLL5_DIV4, CPG_DSIEXTCKCR), - DEF_GEN4_SDH("sd0h", R8A779G0_CLK_SD0H, CLK_SDSRC, 0x870), - DEF_GEN4_SD("sd0", R8A779G0_CLK_SD0, R8A779G0_CLK_SD0H, 0x870), - DEF_DIV6P1("mso", R8A779G0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), + DEF_GEN4_SDH("sd0h", R8A779G0_CLK_SD0H, CLK_SDSRC, CPG_SD0CKCR), + DEF_GEN4_SD("sd0", R8A779G0_CLK_SD0, R8A779G0_CLK_SD0H, CPG_SD0CKCR), + DEF_DIV6P1("mso", R8A779G0_CLK_MSO, CLK_PLL5_DIV4, CPG_MSOCKCR), DEF_BASE("rpc", R8A779G0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC), DEF_BASE("rpcd2", R8A779G0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779G0_CLK_RPC), @@ -258,12 +258,12 @@ static const struct mssr_mod_clk r8a779g0_mod_clks[] __initconst = { #define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \ (((md) & BIT(13)) >> 13)) -static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] = { - /* EXTAL div PLL1 mult/div PLL2 mult/div PLL3 mult/div PLL4 mult/div PLL5 mult/div PLL6 mult/div OSC prediv */ - { 1, 192, 1, 204, 1, 192, 1, 144, 1, 192, 1, 168, 1, 16, }, - { 1, 160, 1, 170, 1, 160, 1, 120, 1, 160, 1, 140, 1, 19, }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - { 2, 192, 1, 204, 1, 192, 1, 144, 1, 192, 1, 168, 1, 32, }, +static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] __initconst = { + /* EXTAL div PLL1 mult/div PLL5 mult/div OSC prediv */ + { 1, 192, 1, 192, 1, 16, }, + { 1, 160, 1, 160, 1, 19, }, + { 0, 0, 0, 0, 0, 0, }, + { 2, 192, 1, 192, 1, 32, }, }; static int __init r8a779g0_cpg_mssr_init(struct device *dev) diff --git a/drivers/clk/renesas/r8a779h0-cpg-mssr.c b/drivers/clk/renesas/r8a779h0-cpg-mssr.c index 16a2e26abcc7..e20c048bfa9b 100644 --- a/drivers/clk/renesas/r8a779h0-cpg-mssr.c +++ b/drivers/clk/renesas/r8a779h0-cpg-mssr.c @@ -63,19 +63,19 @@ enum clk_ids { MOD_CLK_BASE }; -static const struct cpg_core_clk r8a779h0_core_clks[] = { +static const struct cpg_core_clk r8a779h0_core_clks[] __initconst = { /* External Clock Inputs */ DEF_INPUT("extal", CLK_EXTAL), DEF_INPUT("extalr", CLK_EXTALR), /* Internal Core Clocks */ DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN4_MAIN, CLK_EXTAL), - DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN4_PLL1, CLK_MAIN), - DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN4_PLL2, CLK_MAIN), - DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN4_PLL3, CLK_MAIN), - DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN4_PLL4, CLK_MAIN), + DEF_GEN4_PLL_F8_25(".pll1", 1, CLK_PLL1, CLK_MAIN), + DEF_GEN4_PLL_V8_25(".pll2", 2, CLK_PLL2, CLK_MAIN), + DEF_GEN4_PLL_V8_25(".pll3", 3, CLK_PLL3, CLK_MAIN), + DEF_GEN4_PLL_V8_25(".pll4", 4, CLK_PLL4, CLK_MAIN), DEF_BASE(".pll5", CLK_PLL5, CLK_TYPE_GEN4_PLL5, CLK_MAIN), - DEF_BASE(".pll6", CLK_PLL6, CLK_TYPE_GEN4_PLL6, CLK_MAIN), + DEF_GEN4_PLL_V8_25(".pll6", 6, CLK_PLL6, CLK_MAIN), DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 2, 1), @@ -156,14 +156,14 @@ static const struct cpg_core_clk r8a779h0_core_clks[] = { DEF_FIXED("viobusd2", R8A779H0_CLK_VIOBUSD2, CLK_VIOSRC, 2, 1), DEF_FIXED("vcbusd1", R8A779H0_CLK_VCBUSD1, CLK_VCSRC, 1, 1), DEF_FIXED("vcbusd2", R8A779H0_CLK_VCBUSD2, CLK_VCSRC, 2, 1), - DEF_DIV6P1("canfd", R8A779H0_CLK_CANFD, CLK_PLL5_DIV4, 0x878), - DEF_DIV6P1("csi", R8A779H0_CLK_CSI, CLK_PLL5_DIV4, 0x880), + DEF_DIV6P1("canfd", R8A779H0_CLK_CANFD, CLK_PLL5_DIV4, CPG_CANFDCKCR), + DEF_DIV6P1("csi", R8A779H0_CLK_CSI, CLK_PLL5_DIV4, CPG_CSICKCR), DEF_FIXED("dsiref", R8A779H0_CLK_DSIREF, CLK_PLL5_DIV4, 48, 1), - DEF_DIV6P1("dsiext", R8A779H0_CLK_DSIEXT, CLK_PLL5_DIV4, 0x884), - DEF_DIV6P1("mso", R8A779H0_CLK_MSO, CLK_PLL5_DIV4, 0x87c), + DEF_DIV6P1("dsiext", R8A779H0_CLK_DSIEXT, CLK_PLL5_DIV4, CPG_DSIEXTCKCR), + DEF_DIV6P1("mso", R8A779H0_CLK_MSO, CLK_PLL5_DIV4, CPG_MSOCKCR), - DEF_GEN4_SDH("sd0h", R8A779H0_CLK_SD0H, CLK_SDSRC, 0x870), - DEF_GEN4_SD("sd0", R8A779H0_CLK_SD0, R8A779H0_CLK_SD0H, 0x870), + DEF_GEN4_SDH("sd0h", R8A779H0_CLK_SD0H, CLK_SDSRC, CPG_SD0CKCR), + DEF_GEN4_SD("sd0", R8A779H0_CLK_SD0, R8A779H0_CLK_SD0H, CPG_SD0CKCR), DEF_BASE("rpc", R8A779H0_CLK_RPC, CLK_TYPE_GEN4_RPC, CLK_RPCSRC), DEF_BASE("rpcd2", R8A779H0_CLK_RPCD2, CLK_TYPE_GEN4_RPCD2, R8A779H0_CLK_RPC), @@ -172,10 +172,11 @@ static const struct cpg_core_clk r8a779h0_core_clks[] = { DEF_GEN4_MDSEL("r", R8A779H0_CLK_R, 29, CLK_EXTALR, 1, CLK_OCO, 1), }; -static const struct mssr_mod_clk r8a779h0_mod_clks[] = { +static const struct mssr_mod_clk r8a779h0_mod_clks[] __initconst = { DEF_MOD("avb0:rgmii0", 211, R8A779H0_CLK_S0D8_HSC), DEF_MOD("avb1:rgmii1", 212, R8A779H0_CLK_S0D8_HSC), DEF_MOD("avb2:rgmii2", 213, R8A779H0_CLK_S0D8_HSC), + DEF_MOD("canfd0", 328, R8A779H0_CLK_SASYNCPERD2), DEF_MOD("csi40", 331, R8A779H0_CLK_CSI), DEF_MOD("csi41", 400, R8A779H0_CLK_CSI), DEF_MOD("hscif0", 514, R8A779H0_CLK_SASYNCPERD1), @@ -195,6 +196,8 @@ static const struct mssr_mod_clk r8a779h0_mod_clks[] = { DEF_MOD("msi3", 621, R8A779H0_CLK_MSO), DEF_MOD("msi4", 622, R8A779H0_CLK_MSO), DEF_MOD("msi5", 623, R8A779H0_CLK_MSO), + DEF_MOD("pcie0", 624, R8A779H0_CLK_S0D2_HSC), + DEF_MOD("pwm", 628, R8A779H0_CLK_SASYNCPERD4), DEF_MOD("rpc-if", 629, R8A779H0_CLK_RPCD2), DEF_MOD("scif0", 702, R8A779H0_CLK_SASYNCPERD4), DEF_MOD("scif1", 703, R8A779H0_CLK_SASYNCPERD4), @@ -252,12 +255,12 @@ static const struct mssr_mod_clk r8a779h0_mod_clks[] = { #define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 13) | \ (((md) & BIT(13)) >> 13)) -static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] = { - /* EXTAL div PLL1 mult/div PLL2 mult/div PLL3 mult/div PLL4 mult/div PLL5 mult/div PLL6 mult/div OSC prediv */ - { 1, 192, 1, 240, 1, 192, 1, 240, 1, 192, 1, 168, 1, 16, }, - { 1, 160, 1, 200, 1, 160, 1, 200, 1, 160, 1, 140, 1, 19, }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - { 2, 192, 1, 240, 1, 192, 1, 240, 1, 192, 1, 168, 1, 32, }, +static const struct rcar_gen4_cpg_pll_config cpg_pll_configs[4] __initconst = { + /* EXTAL div PLL1 mult/div PLL5 mult/div OSC prediv */ + { 1, 192, 1, 192, 1, 16, }, + { 1, 160, 1, 160, 1, 19, }, + { 0, 0, 0, 0, 0, 0, }, + { 2, 192, 1, 192, 1, 32, }, }; static int __init r8a779h0_cpg_mssr_init(struct device *dev) diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c index 16acc95f3c62..c3c2b0c43983 100644 --- a/drivers/clk/renesas/r9a07g043-cpg.c +++ b/drivers/clk/renesas/r9a07g043-cpg.c @@ -52,6 +52,8 @@ enum clk_ids { CLK_PLL5, CLK_PLL5_500, CLK_PLL5_250, + CLK_PLL5_FOUTPOSTDIV, + CLK_DSI_DIV, #endif CLK_PLL6, CLK_PLL6_250, @@ -120,6 +122,7 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { DEF_FIXED(".pll5", CLK_PLL5, CLK_EXTAL, 125, 1), DEF_FIXED(".pll5_500", CLK_PLL5_500, CLK_PLL5, 1, 6), DEF_FIXED(".pll5_250", CLK_PLL5_250, CLK_PLL5_500, 1, 2), + DEF_PLL5_FOUTPOSTDIV(".pll5_foutpostdiv", CLK_PLL5_FOUTPOSTDIV, CLK_EXTAL), #endif DEF_FIXED(".pll6", CLK_PLL6, CLK_EXTAL, 125, 6), DEF_FIXED(".pll6_250", CLK_PLL6_250, CLK_PLL6, 1, 2), @@ -146,6 +149,8 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = { #ifdef CONFIG_ARM64 DEF_FIXED("M2", R9A07G043_CLK_M2, CLK_PLL3_533, 1, 2), DEF_FIXED("M2_DIV2", CLK_M2_DIV2, R9A07G043_CLK_M2, 1, 2), + DEF_DSI_DIV("DSI_DIV", CLK_DSI_DIV, CLK_PLL5_FOUTPOSTDIV, CLK_SET_RATE_PARENT), + DEF_FIXED("M3", R9A07G043_CLK_M3, CLK_DSI_DIV, 1, 1), #endif }; @@ -209,6 +214,12 @@ static const struct rzg2l_mod_clk r9a07g043_mod_clks[] = { 0x564, 2), DEF_MOD("cru_aclk", R9A07G043_CRU_ACLK, R9A07G043_CLK_M0, 0x564, 3), + DEF_COUPLED("lcdc_clk_a", R9A07G043_LCDC_CLK_A, R9A07G043_CLK_M0, + 0x56c, 0), + DEF_COUPLED("lcdc_clk_p", R9A07G043_LCDC_CLK_P, R9A07G043_CLK_ZT, + 0x56c, 0), + DEF_MOD("lcdc_clk_d", R9A07G043_LCDC_CLK_D, R9A07G043_CLK_M3, + 0x56c, 1), #endif DEF_MOD("ssi0_pclk", R9A07G043_SSI0_PCLK2, R9A07G043_CLK_P0, 0x570, 0), @@ -309,6 +320,7 @@ static const struct rzg2l_reset r9a07g043_resets[] = { DEF_RST(R9A07G043_CRU_CMN_RSTB, 0x864, 0), DEF_RST(R9A07G043_CRU_PRESETN, 0x864, 1), DEF_RST(R9A07G043_CRU_ARESETN, 0x864, 2), + DEF_RST(R9A07G043_LCDC_RESET_N, 0x86c, 0), #endif DEF_RST(R9A07G043_SSI0_RST_M2_REG, 0x870, 0), DEF_RST(R9A07G043_SSI1_RST_M2_REG, 0x870, 1), diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c index a891bfc3ab5a..1ce40fb51f13 100644 --- a/drivers/clk/renesas/r9a08g045-cpg.c +++ b/drivers/clk/renesas/r9a08g045-cpg.c @@ -193,6 +193,7 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { DEF_MOD("ia55_pclk", R9A08G045_IA55_PCLK, R9A08G045_CLK_P2, 0x518, 0), DEF_MOD("ia55_clk", R9A08G045_IA55_CLK, R9A08G045_CLK_P1, 0x518, 1), DEF_MOD("dmac_aclk", R9A08G045_DMAC_ACLK, R9A08G045_CLK_P3, 0x52c, 0), + DEF_MOD("dmac_pclk", R9A08G045_DMAC_PCLK, CLK_P3_DIV2, 0x52c, 1), DEF_MOD("wdt0_pclk", R9A08G045_WDT0_PCLK, R9A08G045_CLK_P0, 0x548, 0), DEF_MOD("wdt0_clk", R9A08G045_WDT0_CLK, R9A08G045_OSCCLK, 0x548, 1), DEF_MOD("sdhi0_imclk", R9A08G045_SDHI0_IMCLK, CLK_SD0_DIV4, 0x554, 0), @@ -207,6 +208,10 @@ static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = { DEF_MOD("sdhi2_imclk2", R9A08G045_SDHI2_IMCLK2, CLK_SD2_DIV4, 0x554, 9), DEF_MOD("sdhi2_clk_hs", R9A08G045_SDHI2_CLK_HS, R9A08G045_CLK_SD2, 0x554, 10), DEF_MOD("sdhi2_aclk", R9A08G045_SDHI2_ACLK, R9A08G045_CLK_P1, 0x554, 11), + DEF_MOD("usb0_host", R9A08G045_USB_U2H0_HCLK, R9A08G045_CLK_P1, 0x578, 0), + DEF_MOD("usb1_host", R9A08G045_USB_U2H1_HCLK, R9A08G045_CLK_P1, 0x578, 1), + DEF_MOD("usb0_func", R9A08G045_USB_U2P_EXR_CPUCLK, R9A08G045_CLK_P1, 0x578, 2), + DEF_MOD("usb_pclk", R9A08G045_USB_PCLK, R9A08G045_CLK_P1, 0x578, 3), DEF_COUPLED("eth0_axi", R9A08G045_ETH0_CLK_AXI, R9A08G045_CLK_M0, 0x57c, 0), DEF_COUPLED("eth0_chi", R9A08G045_ETH0_CLK_CHI, R9A08G045_CLK_ZT, 0x57c, 0), DEF_MOD("eth0_refclk", R9A08G045_ETH0_REFCLK, R9A08G045_CLK_HP, 0x57c, 8), @@ -226,10 +231,16 @@ static const struct rzg2l_reset r9a08g045_resets[] = { DEF_RST(R9A08G045_GIC600_GICRESET_N, 0x814, 0), DEF_RST(R9A08G045_GIC600_DBG_GICRESET_N, 0x814, 1), DEF_RST(R9A08G045_IA55_RESETN, 0x818, 0), + DEF_RST(R9A08G045_DMAC_ARESETN, 0x82c, 0), + DEF_RST(R9A08G045_DMAC_RST_ASYNC, 0x82c, 1), DEF_RST(R9A08G045_WDT0_PRESETN, 0x848, 0), DEF_RST(R9A08G045_SDHI0_IXRST, 0x854, 0), DEF_RST(R9A08G045_SDHI1_IXRST, 0x854, 1), DEF_RST(R9A08G045_SDHI2_IXRST, 0x854, 2), + DEF_RST(R9A08G045_USB_U2H0_HRESETN, 0x878, 0), + DEF_RST(R9A08G045_USB_U2H1_HRESETN, 0x878, 1), + DEF_RST(R9A08G045_USB_U2P_EXL_SYSRST, 0x878, 2), + DEF_RST(R9A08G045_USB_PRESETN, 0x878, 3), DEF_RST(R9A08G045_ETH0_RST_HW_N, 0x87c, 0), DEF_RST(R9A08G045_ETH1_RST_HW_N, 0x87c, 1), DEF_RST(R9A08G045_I2C0_MRST, 0x880, 0), @@ -277,6 +288,15 @@ static const struct rzg2l_cpg_pm_domain_init_data r9a08g045_pm_domains[] = { DEF_PD("sdhi2", R9A08G045_PD_SDHI2, DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(11)), RZG2L_PD_F_NONE), + DEF_PD("usb0", R9A08G045_PD_USB0, + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, GENMASK(6, 5)), + RZG2L_PD_F_NONE), + DEF_PD("usb1", R9A08G045_PD_USB1, + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(7)), + RZG2L_PD_F_NONE), + DEF_PD("usb-phy", R9A08G045_PD_USB_PHY, + DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(4)), + RZG2L_PD_F_NONE), DEF_PD("eth0", R9A08G045_PD_ETHER0, DEF_REG_CONF(CPG_BUS_PERI_COM_MSTOP, BIT(2)), RZG2L_PD_F_NONE), diff --git a/drivers/clk/renesas/r9a09g057-cpg.c b/drivers/clk/renesas/r9a09g057-cpg.c new file mode 100644 index 000000000000..3ee32db5c0af --- /dev/null +++ b/drivers/clk/renesas/r9a09g057-cpg.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/V2H(P) CPG driver + * + * Copyright (C) 2024 Renesas Electronics Corp. + */ + +#include <linux/clk-provider.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/kernel.h> + +#include <dt-bindings/clock/renesas,r9a09g057-cpg.h> + +#include "rzv2h-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R9A09G057_IOTOP_0_SHCLK, + + /* External Input Clocks */ + CLK_AUDIO_EXTAL, + CLK_RTXIN, + CLK_QEXTAL, + + /* PLL Clocks */ + CLK_PLLCM33, + CLK_PLLCLN, + CLK_PLLDTY, + CLK_PLLCA55, + + /* Internal Core Clocks */ + CLK_PLLCM33_DIV16, + CLK_PLLCLN_DIV2, + CLK_PLLCLN_DIV8, + CLK_PLLCLN_DIV16, + CLK_PLLDTY_ACPU, + CLK_PLLDTY_ACPU_DIV4, + + /* Module Clocks */ + MOD_CLK_BASE, +}; + +static const struct clk_div_table dtable_2_64[] = { + {0, 2}, + {1, 4}, + {2, 8}, + {3, 16}, + {4, 64}, + {0, 0}, +}; + +static const struct cpg_core_clk r9a09g057_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("audio_extal", CLK_AUDIO_EXTAL), + DEF_INPUT("rtxin", CLK_RTXIN), + DEF_INPUT("qextal", CLK_QEXTAL), + + /* PLL Clocks */ + DEF_FIXED(".pllcm33", CLK_PLLCM33, CLK_QEXTAL, 200, 3), + DEF_FIXED(".pllcln", CLK_PLLCLN, CLK_QEXTAL, 200, 3), + DEF_FIXED(".plldty", CLK_PLLDTY, CLK_QEXTAL, 200, 3), + DEF_PLL(".pllca55", CLK_PLLCA55, CLK_QEXTAL, PLL_CONF(0x64)), + + /* Internal Core Clocks */ + DEF_FIXED(".pllcm33_div16", CLK_PLLCM33_DIV16, CLK_PLLCM33, 1, 16), + + DEF_FIXED(".pllcln_div2", CLK_PLLCLN_DIV2, CLK_PLLCLN, 1, 2), + DEF_FIXED(".pllcln_div8", CLK_PLLCLN_DIV8, CLK_PLLCLN, 1, 8), + DEF_FIXED(".pllcln_div16", CLK_PLLCLN_DIV16, CLK_PLLCLN, 1, 16), + + DEF_DDIV(".plldty_acpu", CLK_PLLDTY_ACPU, CLK_PLLDTY, CDDIV0_DIVCTL2, dtable_2_64), + DEF_FIXED(".plldty_acpu_div4", CLK_PLLDTY_ACPU_DIV4, CLK_PLLDTY_ACPU, 1, 4), + + /* Core Clocks */ + DEF_FIXED("sys_0_pclk", R9A09G057_SYS_0_PCLK, CLK_QEXTAL, 1, 1), + DEF_FIXED("iotop_0_shclk", R9A09G057_IOTOP_0_SHCLK, CLK_PLLCM33_DIV16, 1, 1), +}; + +static const struct rzv2h_mod_clk r9a09g057_mod_clks[] __initconst = { + DEF_MOD("gtm_0_pclk", CLK_PLLCM33_DIV16, 4, 3, 2, 3), + DEF_MOD("gtm_1_pclk", CLK_PLLCM33_DIV16, 4, 4, 2, 4), + DEF_MOD("gtm_2_pclk", CLK_PLLCLN_DIV16, 4, 5, 2, 5), + DEF_MOD("gtm_3_pclk", CLK_PLLCLN_DIV16, 4, 6, 2, 6), + DEF_MOD("gtm_4_pclk", CLK_PLLCLN_DIV16, 4, 7, 2, 7), + DEF_MOD("gtm_5_pclk", CLK_PLLCLN_DIV16, 4, 8, 2, 8), + DEF_MOD("gtm_6_pclk", CLK_PLLCLN_DIV16, 4, 9, 2, 9), + DEF_MOD("gtm_7_pclk", CLK_PLLCLN_DIV16, 4, 10, 2, 10), + DEF_MOD("wdt_0_clkp", CLK_PLLCM33_DIV16, 4, 11, 2, 11), + DEF_MOD("wdt_0_clk_loco", CLK_QEXTAL, 4, 12, 2, 12), + DEF_MOD("wdt_1_clkp", CLK_PLLCLN_DIV16, 4, 13, 2, 13), + DEF_MOD("wdt_1_clk_loco", CLK_QEXTAL, 4, 14, 2, 14), + DEF_MOD("wdt_2_clkp", CLK_PLLCLN_DIV16, 4, 15, 2, 15), + DEF_MOD("wdt_2_clk_loco", CLK_QEXTAL, 5, 0, 2, 16), + DEF_MOD("wdt_3_clkp", CLK_PLLCLN_DIV16, 5, 1, 2, 17), + DEF_MOD("wdt_3_clk_loco", CLK_QEXTAL, 5, 2, 2, 18), + DEF_MOD("scif_0_clk_pck", CLK_PLLCM33_DIV16, 8, 15, 4, 15), + DEF_MOD("riic_8_ckm", CLK_PLLCM33_DIV16, 9, 3, 4, 19), + DEF_MOD("riic_0_ckm", CLK_PLLCLN_DIV16, 9, 4, 4, 20), + DEF_MOD("riic_1_ckm", CLK_PLLCLN_DIV16, 9, 5, 4, 21), + DEF_MOD("riic_2_ckm", CLK_PLLCLN_DIV16, 9, 6, 4, 22), + DEF_MOD("riic_3_ckm", CLK_PLLCLN_DIV16, 9, 7, 4, 23), + DEF_MOD("riic_4_ckm", CLK_PLLCLN_DIV16, 9, 8, 4, 24), + DEF_MOD("riic_5_ckm", CLK_PLLCLN_DIV16, 9, 9, 4, 25), + DEF_MOD("riic_6_ckm", CLK_PLLCLN_DIV16, 9, 10, 4, 26), + DEF_MOD("riic_7_ckm", CLK_PLLCLN_DIV16, 9, 11, 4, 27), + DEF_MOD("sdhi_0_imclk", CLK_PLLCLN_DIV8, 10, 3, 5, 3), + DEF_MOD("sdhi_0_imclk2", CLK_PLLCLN_DIV8, 10, 4, 5, 4), + DEF_MOD("sdhi_0_clk_hs", CLK_PLLCLN_DIV2, 10, 5, 5, 5), + DEF_MOD("sdhi_0_aclk", CLK_PLLDTY_ACPU_DIV4, 10, 6, 5, 6), + DEF_MOD("sdhi_1_imclk", CLK_PLLCLN_DIV8, 10, 7, 5, 7), + DEF_MOD("sdhi_1_imclk2", CLK_PLLCLN_DIV8, 10, 8, 5, 8), + DEF_MOD("sdhi_1_clk_hs", CLK_PLLCLN_DIV2, 10, 9, 5, 9), + DEF_MOD("sdhi_1_aclk", CLK_PLLDTY_ACPU_DIV4, 10, 10, 5, 10), + DEF_MOD("sdhi_2_imclk", CLK_PLLCLN_DIV8, 10, 11, 5, 11), + DEF_MOD("sdhi_2_imclk2", CLK_PLLCLN_DIV8, 10, 12, 5, 12), + DEF_MOD("sdhi_2_clk_hs", CLK_PLLCLN_DIV2, 10, 13, 5, 13), + DEF_MOD("sdhi_2_aclk", CLK_PLLDTY_ACPU_DIV4, 10, 14, 5, 14), +}; + +static const struct rzv2h_reset r9a09g057_resets[] __initconst = { + DEF_RST(6, 13, 2, 30), /* GTM_0_PRESETZ */ + DEF_RST(6, 14, 2, 31), /* GTM_1_PRESETZ */ + DEF_RST(6, 15, 3, 0), /* GTM_2_PRESETZ */ + DEF_RST(7, 0, 3, 1), /* GTM_3_PRESETZ */ + DEF_RST(7, 1, 3, 2), /* GTM_4_PRESETZ */ + DEF_RST(7, 2, 3, 3), /* GTM_5_PRESETZ */ + DEF_RST(7, 3, 3, 4), /* GTM_6_PRESETZ */ + DEF_RST(7, 4, 3, 5), /* GTM_7_PRESETZ */ + DEF_RST(7, 5, 3, 6), /* WDT_0_RESET */ + DEF_RST(7, 6, 3, 7), /* WDT_1_RESET */ + DEF_RST(7, 7, 3, 8), /* WDT_2_RESET */ + DEF_RST(7, 8, 3, 9), /* WDT_3_RESET */ + DEF_RST(9, 5, 4, 6), /* SCIF_0_RST_SYSTEM_N */ + DEF_RST(9, 8, 4, 9), /* RIIC_0_MRST */ + DEF_RST(9, 9, 4, 10), /* RIIC_1_MRST */ + DEF_RST(9, 10, 4, 11), /* RIIC_2_MRST */ + DEF_RST(9, 11, 4, 12), /* RIIC_3_MRST */ + DEF_RST(9, 12, 4, 13), /* RIIC_4_MRST */ + DEF_RST(9, 13, 4, 14), /* RIIC_5_MRST */ + DEF_RST(9, 14, 4, 15), /* RIIC_6_MRST */ + DEF_RST(9, 15, 4, 16), /* RIIC_7_MRST */ + DEF_RST(10, 0, 4, 17), /* RIIC_8_MRST */ + DEF_RST(10, 7, 4, 24), /* SDHI_0_IXRST */ + DEF_RST(10, 8, 4, 25), /* SDHI_1_IXRST */ + DEF_RST(10, 9, 4, 26), /* SDHI_2_IXRST */ +}; + +const struct rzv2h_cpg_info r9a09g057_cpg_info __initconst = { + /* Core Clocks */ + .core_clks = r9a09g057_core_clks, + .num_core_clks = ARRAY_SIZE(r9a09g057_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r9a09g057_mod_clks, + .num_mod_clks = ARRAY_SIZE(r9a09g057_mod_clks), + .num_hw_mod_clks = 25 * 16, + + /* Resets */ + .resets = r9a09g057_resets, + .num_resets = ARRAY_SIZE(r9a09g057_resets), +}; diff --git a/drivers/clk/renesas/rcar-gen4-cpg.c b/drivers/clk/renesas/rcar-gen4-cpg.c index 77a4bb3e17f3..31aa790fd003 100644 --- a/drivers/clk/renesas/rcar-gen4-cpg.c +++ b/drivers/clk/renesas/rcar-gen4-cpg.c @@ -45,7 +45,6 @@ static u32 cpg_mode __initdata; #define CPG_PLL6CR1 0x8d8 #define CPG_PLLxCR0_KICK BIT(31) -#define CPG_PLLxCR0_NI GENMASK(27, 20) /* Integer mult. factor */ #define CPG_PLLxCR0_SSMODE GENMASK(18, 16) /* PLL mode */ #define CPG_PLLxCR0_SSMODE_FM BIT(18) /* Fractional Multiplication */ #define CPG_PLLxCR0_SSMODE_DITH BIT(17) /* Frequency Dithering */ @@ -53,35 +52,57 @@ static u32 cpg_mode __initdata; #define CPG_PLLxCR0_SSFREQ GENMASK(14, 8) /* SSCG Modulation Frequency */ #define CPG_PLLxCR0_SSDEPT GENMASK(6, 0) /* SSCG Modulation Depth */ -#define SSMODE_FM BIT(2) /* Fractional Multiplication */ -#define SSMODE_DITHER BIT(1) /* Frequency Dithering */ -#define SSMODE_CENTER BIT(0) /* Center (vs. Down) Spread Dithering */ +/* Fractional 8.25 PLL */ +#define CPG_PLLxCR0_NI8 GENMASK(27, 20) /* Integer mult. factor */ +#define CPG_PLLxCR1_NF25 GENMASK(24, 0) /* Fractional mult. factor */ + +/* Fractional 9.24 PLL */ +#define CPG_PLLxCR0_NI9 GENMASK(28, 20) /* Integer mult. factor */ +#define CPG_PLLxCR1_NF24 GENMASK(23, 0) /* Fractional mult. factor */ + +#define CPG_PLLxCR_STC GENMASK(30, 24) /* R_Car V3U PLLxCR */ + +#define CPG_RPCCKCR 0x874 /* RPC Clock Freq. Control Register */ + +#define CPG_SD0CKCR1 0x8a4 /* SD-IF0 Clock Freq. Control Reg. 1 */ + +#define CPG_SD0CKCR1_SDSRC_SEL GENMASK(30, 29) /* SDSRC clock freq. select */ /* PLL Clocks */ struct cpg_pll_clk { struct clk_hw hw; void __iomem *pllcr0_reg; + void __iomem *pllcr1_reg; void __iomem *pllecr_reg; u32 pllecr_pllst_mask; }; #define to_pll_clk(_hw) container_of(_hw, struct cpg_pll_clk, hw) -static unsigned long cpg_pll_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static unsigned long cpg_pll_8_25_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) { struct cpg_pll_clk *pll_clk = to_pll_clk(hw); - unsigned int mult; - - mult = FIELD_GET(CPG_PLLxCR0_NI, readl(pll_clk->pllcr0_reg)) + 1; + u32 cr0 = readl(pll_clk->pllcr0_reg); + unsigned int ni, nf; + unsigned long rate; + + ni = (FIELD_GET(CPG_PLLxCR0_NI8, cr0) + 1) * 2; + rate = parent_rate * ni; + if (cr0 & CPG_PLLxCR0_SSMODE_FM) { + nf = FIELD_GET(CPG_PLLxCR1_NF25, readl(pll_clk->pllcr1_reg)); + rate += mul_u64_u32_shr(parent_rate, nf, 24); + } - return parent_rate * mult * 2; + return rate; } -static int cpg_pll_clk_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) +static int cpg_pll_8_25_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - unsigned int min_mult, max_mult, mult; + struct cpg_pll_clk *pll_clk = to_pll_clk(hw); + unsigned int min_mult, max_mult, ni, nf; + u32 cr0 = readl(pll_clk->pllcr0_reg); unsigned long prate; prate = req->best_parent_rate * 2; @@ -90,28 +111,58 @@ static int cpg_pll_clk_determine_rate(struct clk_hw *hw, if (max_mult < min_mult) return -EINVAL; - mult = DIV_ROUND_CLOSEST_ULL(req->rate, prate); - mult = clamp(mult, min_mult, max_mult); + if (cr0 & CPG_PLLxCR0_SSMODE_FM) { + ni = div64_ul(req->rate, prate); + if (ni < min_mult) { + ni = min_mult; + nf = 0; + } else { + ni = min(ni, max_mult); + nf = div64_ul((u64)(req->rate - prate * ni) << 24, + req->best_parent_rate); + } + } else { + ni = DIV_ROUND_CLOSEST_ULL(req->rate, prate); + ni = clamp(ni, min_mult, max_mult); + nf = 0; + } + req->rate = prate * ni + mul_u64_u32_shr(req->best_parent_rate, nf, 24); - req->rate = prate * mult; return 0; } -static int cpg_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) +static int cpg_pll_8_25_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) { struct cpg_pll_clk *pll_clk = to_pll_clk(hw); - unsigned int mult; + unsigned long prate = parent_rate * 2; + u32 cr0 = readl(pll_clk->pllcr0_reg); + unsigned int ni, nf; u32 val; - mult = DIV_ROUND_CLOSEST_ULL(rate, parent_rate * 2); - mult = clamp(mult, 1U, 256U); + if (cr0 & CPG_PLLxCR0_SSMODE_FM) { + ni = div64_ul(rate, prate); + if (ni < 1) { + ni = 1; + nf = 0; + } else { + ni = min(ni, 256U); + nf = div64_ul((u64)(rate - prate * ni) << 24, + parent_rate); + } + } else { + ni = DIV_ROUND_CLOSEST_ULL(rate, prate); + ni = clamp(ni, 1U, 256U); + } if (readl(pll_clk->pllcr0_reg) & CPG_PLLxCR0_KICK) return -EBUSY; - cpg_reg_modify(pll_clk->pllcr0_reg, CPG_PLLxCR0_NI, - FIELD_PREP(CPG_PLLxCR0_NI, mult - 1)); + cpg_reg_modify(pll_clk->pllcr0_reg, CPG_PLLxCR0_NI8, + FIELD_PREP(CPG_PLLxCR0_NI8, ni - 1)); + if (cr0 & CPG_PLLxCR0_SSMODE_FM) + cpg_reg_modify(pll_clk->pllcr1_reg, CPG_PLLxCR1_NF25, + FIELD_PREP(CPG_PLLxCR1_NF25, nf)); /* * Set KICK bit in PLLxCR0 to update hardware setting and wait for @@ -132,22 +183,55 @@ static int cpg_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, val & pll_clk->pllecr_pllst_mask, 0, 1000); } -static const struct clk_ops cpg_pll_clk_ops = { - .recalc_rate = cpg_pll_clk_recalc_rate, - .determine_rate = cpg_pll_clk_determine_rate, - .set_rate = cpg_pll_clk_set_rate, +static const struct clk_ops cpg_pll_f8_25_clk_ops = { + .recalc_rate = cpg_pll_8_25_clk_recalc_rate, +}; + +static const struct clk_ops cpg_pll_v8_25_clk_ops = { + .recalc_rate = cpg_pll_8_25_clk_recalc_rate, + .determine_rate = cpg_pll_8_25_clk_determine_rate, + .set_rate = cpg_pll_8_25_clk_set_rate, +}; + +static unsigned long cpg_pll_9_24_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct cpg_pll_clk *pll_clk = to_pll_clk(hw); + u32 cr0 = readl(pll_clk->pllcr0_reg); + unsigned int ni, nf; + unsigned long rate; + + ni = FIELD_GET(CPG_PLLxCR0_NI9, cr0) + 1; + rate = parent_rate * ni; + if (cr0 & CPG_PLLxCR0_SSMODE_FM) { + nf = FIELD_GET(CPG_PLLxCR1_NF24, readl(pll_clk->pllcr1_reg)); + rate += mul_u64_u32_shr(parent_rate, nf, 24); + } else { + rate *= 2; + } + + return rate; +} + +static const struct clk_ops cpg_pll_f9_24_clk_ops = { + .recalc_rate = cpg_pll_9_24_clk_recalc_rate, }; static struct clk * __init cpg_pll_clk_register(const char *name, const char *parent_name, void __iomem *base, - unsigned int cr0_offset, - unsigned int cr1_offset, - unsigned int index) - + unsigned int index, + const struct clk_ops *ops) { - struct cpg_pll_clk *pll_clk; + static const struct { u16 cr0, cr1; } pll_cr_offsets[] __initconst = { + [1 - 1] = { CPG_PLL1CR0, CPG_PLL1CR1 }, + [2 - 1] = { CPG_PLL2CR0, CPG_PLL2CR1 }, + [3 - 1] = { CPG_PLL3CR0, CPG_PLL3CR1 }, + [4 - 1] = { CPG_PLL4CR0, CPG_PLL4CR1 }, + [6 - 1] = { CPG_PLL6CR0, CPG_PLL6CR1 }, + }; struct clk_init_data init = {}; + struct cpg_pll_clk *pll_clk; struct clk *clk; pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL); @@ -155,25 +239,23 @@ static struct clk * __init cpg_pll_clk_register(const char *name, return ERR_PTR(-ENOMEM); init.name = name; - init.ops = &cpg_pll_clk_ops; + init.ops = ops; init.parent_names = &parent_name; init.num_parents = 1; pll_clk->hw.init = &init; - pll_clk->pllcr0_reg = base + cr0_offset; + pll_clk->pllcr0_reg = base + pll_cr_offsets[index - 1].cr0; + pll_clk->pllcr1_reg = base + pll_cr_offsets[index - 1].cr1; pll_clk->pllecr_reg = base + CPG_PLLECR; pll_clk->pllecr_pllst_mask = CPG_PLLECR_PLLST(index); - /* Disable Fractional Multiplication and Frequency Dithering */ - writel(0, base + cr1_offset); - cpg_reg_modify(pll_clk->pllcr0_reg, CPG_PLLxCR0_SSMODE, 0); - clk = clk_register(NULL, &pll_clk->hw); if (IS_ERR(clk)) kfree(pll_clk); return clk; } + /* * Z0 Clock & Z1 Clock */ @@ -358,51 +440,41 @@ struct clk * __init rcar_gen4_cpg_clk_register(struct device *dev, div = cpg_pll_config->pll1_div; break; - case CLK_TYPE_GEN4_PLL2_VAR: - /* - * PLL2 is implemented as a custom clock, to change the - * multiplier when cpufreq changes between normal and boost - * modes. - */ - return cpg_pll_clk_register(core->name, __clk_get_name(parent), - base, CPG_PLL2CR0, CPG_PLL2CR1, 2); - - case CLK_TYPE_GEN4_PLL2: - mult = cpg_pll_config->pll2_mult; - div = cpg_pll_config->pll2_div; - break; - - case CLK_TYPE_GEN4_PLL3: - mult = cpg_pll_config->pll3_mult; - div = cpg_pll_config->pll3_div; - break; - - case CLK_TYPE_GEN4_PLL4: - mult = cpg_pll_config->pll4_mult; - div = cpg_pll_config->pll4_div; - break; - case CLK_TYPE_GEN4_PLL5: mult = cpg_pll_config->pll5_mult; div = cpg_pll_config->pll5_div; break; - case CLK_TYPE_GEN4_PLL6: - mult = cpg_pll_config->pll6_mult; - div = cpg_pll_config->pll6_div; - break; - case CLK_TYPE_GEN4_PLL2X_3X: value = readl(base + core->offset); - mult = (((value >> 24) & 0x7f) + 1) * 2; + mult = (FIELD_GET(CPG_PLLxCR_STC, value) + 1) * 2; break; + case CLK_TYPE_GEN4_PLL_F8_25: + return cpg_pll_clk_register(core->name, __clk_get_name(parent), + base, core->offset, + &cpg_pll_f8_25_clk_ops); + + case CLK_TYPE_GEN4_PLL_V8_25: + return cpg_pll_clk_register(core->name, __clk_get_name(parent), + base, core->offset, + &cpg_pll_v8_25_clk_ops); + + case CLK_TYPE_GEN4_PLL_V9_24: + /* Variable fractional 9.24 is not yet supported, using fixed */ + fallthrough; + case CLK_TYPE_GEN4_PLL_F9_24: + return cpg_pll_clk_register(core->name, __clk_get_name(parent), + base, core->offset, + &cpg_pll_f9_24_clk_ops); + case CLK_TYPE_GEN4_Z: return cpg_z_clk_register(core->name, __clk_get_name(parent), base, core->div, core->offset); case CLK_TYPE_GEN4_SDSRC: - div = ((readl(base + SD0CKCR1) >> 29) & 0x03) + 4; + value = readl(base + CPG_SD0CKCR1); + div = FIELD_GET(CPG_SD0CKCR1_SDSRC_SEL, value) + 4; break; case CLK_TYPE_GEN4_SDH: diff --git a/drivers/clk/renesas/rcar-gen4-cpg.h b/drivers/clk/renesas/rcar-gen4-cpg.h index 006537e29e4e..717fd148464f 100644 --- a/drivers/clk/renesas/rcar-gen4-cpg.h +++ b/drivers/clk/renesas/rcar-gen4-cpg.h @@ -12,13 +12,12 @@ enum rcar_gen4_clk_types { CLK_TYPE_GEN4_MAIN = CLK_TYPE_CUSTOM, CLK_TYPE_GEN4_PLL1, - CLK_TYPE_GEN4_PLL2, - CLK_TYPE_GEN4_PLL2_VAR, CLK_TYPE_GEN4_PLL2X_3X, /* r8a779a0 only */ - CLK_TYPE_GEN4_PLL3, - CLK_TYPE_GEN4_PLL4, CLK_TYPE_GEN4_PLL5, - CLK_TYPE_GEN4_PLL6, + CLK_TYPE_GEN4_PLL_F8_25, /* Fixed fractional 8.25 PLL */ + CLK_TYPE_GEN4_PLL_V8_25, /* Variable fractional 8.25 PLL */ + CLK_TYPE_GEN4_PLL_F9_24, /* Fixed fractional 9.24 PLL */ + CLK_TYPE_GEN4_PLL_V9_24, /* Variable fractional 9.24 PLL */ CLK_TYPE_GEN4_SDSRC, CLK_TYPE_GEN4_SDH, CLK_TYPE_GEN4_SD, @@ -47,6 +46,18 @@ enum rcar_gen4_clk_types { #define DEF_GEN4_OSC(_name, _id, _parent, _div) \ DEF_BASE(_name, _id, CLK_TYPE_GEN4_OSC, _parent, .div = _div) +#define DEF_GEN4_PLL_F8_25(_name, _idx, _id, _parent) \ + DEF_BASE(_name, _id, CLK_TYPE_GEN4_PLL_F8_25, _parent, .offset = _idx) + +#define DEF_GEN4_PLL_V8_25(_name, _idx, _id, _parent) \ + DEF_BASE(_name, _id, CLK_TYPE_GEN4_PLL_V8_25, _parent, .offset = _idx) + +#define DEF_GEN4_PLL_F9_24(_name, _idx, _id, _parent) \ + DEF_BASE(_name, _id, CLK_TYPE_GEN4_PLL_F9_24, _parent, .offset = _idx) + +#define DEF_GEN4_PLL_V9_24(_name, _idx, _id, _parent) \ + DEF_BASE(_name, _id, CLK_TYPE_GEN4_PLL_V9_24, _parent, .offset = _idx) + #define DEF_GEN4_Z(_name, _id, _type, _parent, _div, _offset) \ DEF_BASE(_name, _id, _type, _parent, .div = _div, .offset = _offset) @@ -54,21 +65,16 @@ struct rcar_gen4_cpg_pll_config { u8 extal_div; u8 pll1_mult; u8 pll1_div; - u8 pll2_mult; - u8 pll2_div; - u8 pll3_mult; - u8 pll3_div; - u8 pll4_mult; - u8 pll4_div; u8 pll5_mult; u8 pll5_div; - u8 pll6_mult; - u8 pll6_div; u8 osc_prediv; }; -#define CPG_RPCCKCR 0x874 -#define SD0CKCR1 0x8a4 +#define CPG_SD0CKCR 0x870 /* SD-IF0 Clock Frequency Control Register */ +#define CPG_CANFDCKCR 0x878 /* CAN-FD Clock Frequency Control Register */ +#define CPG_MSOCKCR 0x87c /* MSIOF Clock Frequency Control Register */ +#define CPG_CSICKCR 0x880 /* CSI Clock Frequency Control Register */ +#define CPG_DSIEXTCKCR 0x884 /* DSI Clock Frequency Control Register */ struct clk *rcar_gen4_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, const struct cpg_mssr_info *info, diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 04b78064d4e0..88bf39e8c79c 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -339,8 +339,7 @@ static const struct clk_ops rzg3s_div_clk_ops = { }; static struct clk * __init -rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks, - void __iomem *base, struct rzg2l_cpg_priv *priv) +rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct rzg2l_cpg_priv *priv) { struct div_hw_data *div_hw_data; struct clk_init_data init = {}; @@ -351,7 +350,7 @@ rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks, u32 max = 0; int ret; - parent = clks[core->parent & 0xffff]; + parent = priv->clks[core->parent]; if (IS_ERR(parent)) return ERR_CAST(parent); @@ -400,16 +399,15 @@ rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks, static struct clk * __init rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, - struct clk **clks, - void __iomem *base, struct rzg2l_cpg_priv *priv) { + void __iomem *base = priv->base; struct device *dev = priv->dev; const struct clk *parent; const char *parent_name; struct clk_hw *clk_hw; - parent = clks[core->parent & 0xffff]; + parent = priv->clks[core->parent]; if (IS_ERR(parent)) return ERR_CAST(parent); @@ -440,7 +438,6 @@ rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core, static struct clk * __init rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, - void __iomem *base, struct rzg2l_cpg_priv *priv) { const struct clk_hw *clk_hw; @@ -448,7 +445,7 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core, clk_hw = devm_clk_hw_register_mux(priv->dev, core->name, core->parent_names, core->num_parents, core->flag, - base + GET_REG_OFFSET(core->conf), + priv->base + GET_REG_OFFSET(core->conf), GET_SHIFT(core->conf), GET_WIDTH(core->conf), core->mux_flags, &priv->rmw_lock); @@ -508,7 +505,6 @@ static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { static struct clk * __init rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, - void __iomem *base, struct rzg2l_cpg_priv *priv) { struct sd_mux_hw_data *sd_mux_hw_data; @@ -652,7 +648,6 @@ static const struct clk_ops rzg2l_cpg_dsi_div_ops = { static struct clk * __init rzg2l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core, - struct clk **clks, struct rzg2l_cpg_priv *priv) { struct dsi_div_hw_data *clk_hw_data; @@ -662,7 +657,7 @@ rzg2l_cpg_dsi_div_clk_register(const struct cpg_core_clk *core, struct clk_hw *clk_hw; int ret; - parent = clks[core->parent & 0xffff]; + parent = priv->clks[core->parent]; if (IS_ERR(parent)) return ERR_CAST(parent); @@ -900,7 +895,6 @@ static const struct clk_ops rzg2l_cpg_sipll5_ops = { static struct clk * __init rzg2l_cpg_sipll5_register(const struct cpg_core_clk *core, - struct clk **clks, struct rzg2l_cpg_priv *priv) { const struct clk *parent; @@ -910,7 +904,7 @@ rzg2l_cpg_sipll5_register(const struct cpg_core_clk *core, struct clk_hw *clk_hw; int ret; - parent = clks[core->parent & 0xffff]; + parent = priv->clks[core->parent]; if (IS_ERR(parent)) return ERR_CAST(parent); @@ -1013,8 +1007,6 @@ static const struct clk_ops rzg3s_cpg_pll_ops = { static struct clk * __init rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core, - struct clk **clks, - void __iomem *base, struct rzg2l_cpg_priv *priv, const struct clk_ops *ops) { @@ -1023,8 +1015,9 @@ rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core, struct clk_init_data init; const char *parent_name; struct pll_clk *pll_clk; + int ret; - parent = clks[core->parent & 0xffff]; + parent = priv->clks[core->parent]; if (IS_ERR(parent)) return ERR_CAST(parent); @@ -1041,11 +1034,15 @@ rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core, pll_clk->hw.init = &init; pll_clk->conf = core->conf; - pll_clk->base = base; + pll_clk->base = priv->base; pll_clk->priv = priv; pll_clk->type = core->type; - return clk_register(NULL, &pll_clk->hw); + ret = devm_clk_hw_register(dev, &pll_clk->hw); + if (ret) + return ERR_PTR(ret); + + return pll_clk->hw.clk; } static struct clk @@ -1102,6 +1099,7 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, struct device *dev = priv->dev; unsigned int id = core->id, div = core->div; const char *parent_name; + struct clk_hw *clk_hw; WARN_DEBUG(id >= priv->num_core_clks); WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); @@ -1124,39 +1122,40 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core, } parent_name = __clk_get_name(parent); - clk = clk_register_fixed_factor(NULL, core->name, - parent_name, CLK_SET_RATE_PARENT, - core->mult, div); + clk_hw = devm_clk_hw_register_fixed_factor(dev, core->name, parent_name, + CLK_SET_RATE_PARENT, + core->mult, div); + if (IS_ERR(clk_hw)) + clk = ERR_CAST(clk_hw); + else + clk = clk_hw->clk; break; case CLK_TYPE_SAM_PLL: - clk = rzg2l_cpg_pll_clk_register(core, priv->clks, priv->base, priv, - &rzg2l_cpg_pll_ops); + clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg2l_cpg_pll_ops); break; case CLK_TYPE_G3S_PLL: - clk = rzg2l_cpg_pll_clk_register(core, priv->clks, priv->base, priv, - &rzg3s_cpg_pll_ops); + clk = rzg2l_cpg_pll_clk_register(core, priv, &rzg3s_cpg_pll_ops); break; case CLK_TYPE_SIPLL5: - clk = rzg2l_cpg_sipll5_register(core, priv->clks, priv); + clk = rzg2l_cpg_sipll5_register(core, priv); break; case CLK_TYPE_DIV: - clk = rzg2l_cpg_div_clk_register(core, priv->clks, - priv->base, priv); + clk = rzg2l_cpg_div_clk_register(core, priv); break; case CLK_TYPE_G3S_DIV: - clk = rzg3s_cpg_div_clk_register(core, priv->clks, priv->base, priv); + clk = rzg3s_cpg_div_clk_register(core, priv); break; case CLK_TYPE_MUX: - clk = rzg2l_cpg_mux_clk_register(core, priv->base, priv); + clk = rzg2l_cpg_mux_clk_register(core, priv); break; case CLK_TYPE_SD_MUX: - clk = rzg2l_cpg_sd_mux_clk_register(core, priv->base, priv); + clk = rzg2l_cpg_sd_mux_clk_register(core, priv); break; case CLK_TYPE_PLL5_4_MUX: clk = rzg2l_cpg_pll5_4_mux_clk_register(core, priv); break; case CLK_TYPE_DSI_DIV: - clk = rzg2l_cpg_dsi_div_clk_register(core, priv->clks, priv); + clk = rzg2l_cpg_dsi_div_clk_register(core, priv); break; default: goto fail; @@ -1337,6 +1336,7 @@ rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod, struct clk *parent, *clk; const char *parent_name; unsigned int i; + int ret; WARN_DEBUG(id < priv->num_core_clks); WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks); @@ -1380,10 +1380,13 @@ rzg2l_cpg_register_mod_clk(const struct rzg2l_mod_clk *mod, clock->priv = priv; clock->hw.init = &init; - clk = clk_register(NULL, &clock->hw); - if (IS_ERR(clk)) + ret = devm_clk_hw_register(dev, &clock->hw); + if (ret) { + clk = ERR_PTR(ret); goto fail; + } + clk = clock->hw.clk; dev_dbg(dev, "Module clock %pC at %lu Hz\n", clk, clk_get_rate(clk)); priv->clks[id] = clk; diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c new file mode 100644 index 000000000000..b524a9d33610 --- /dev/null +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -0,0 +1,853 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/V2H(P) Clock Pulse Generator + * + * Copyright (C) 2024 Renesas Electronics Corp. + * + * Based on rzg2l-cpg.c + * + * Copyright (C) 2015 Glider bvba + * Copyright (C) 2013 Ideas On Board SPRL + * Copyright (C) 2015 Renesas Electronics Corp. + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/iopoll.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_clock.h> +#include <linux/pm_domain.h> +#include <linux/reset-controller.h> + +#include <dt-bindings/clock/renesas-cpg-mssr.h> + +#include "rzv2h-cpg.h" + +#ifdef DEBUG +#define WARN_DEBUG(x) WARN_ON(x) +#else +#define WARN_DEBUG(x) do { } while (0) +#endif + +#define GET_CLK_ON_OFFSET(x) (0x600 + ((x) * 4)) +#define GET_CLK_MON_OFFSET(x) (0x800 + ((x) * 4)) +#define GET_RST_OFFSET(x) (0x900 + ((x) * 4)) +#define GET_RST_MON_OFFSET(x) (0xA00 + ((x) * 4)) + +#define KDIV(val) ((s16)FIELD_GET(GENMASK(31, 16), (val))) +#define MDIV(val) FIELD_GET(GENMASK(15, 6), (val)) +#define PDIV(val) FIELD_GET(GENMASK(5, 0), (val)) +#define SDIV(val) FIELD_GET(GENMASK(2, 0), (val)) + +#define DDIV_DIVCTL_WEN(shift) BIT((shift) + 16) + +#define GET_MOD_CLK_ID(base, index, bit) \ + ((base) + ((((index) * (16))) + (bit))) + +#define CPG_CLKSTATUS0 (0x700) + +/** + * struct rzv2h_cpg_priv - Clock Pulse Generator Private Data + * + * @dev: CPG device + * @base: CPG register block base address + * @rmw_lock: protects register accesses + * @clks: Array containing all Core and Module Clocks + * @num_core_clks: Number of Core Clocks in clks[] + * @num_mod_clks: Number of Module Clocks in clks[] + * @resets: Array of resets + * @num_resets: Number of Module Resets in info->resets[] + * @last_dt_core_clk: ID of the last Core Clock exported to DT + * @rcdev: Reset controller entity + */ +struct rzv2h_cpg_priv { + struct device *dev; + void __iomem *base; + spinlock_t rmw_lock; + + struct clk **clks; + unsigned int num_core_clks; + unsigned int num_mod_clks; + struct rzv2h_reset *resets; + unsigned int num_resets; + unsigned int last_dt_core_clk; + + struct reset_controller_dev rcdev; +}; + +#define rcdev_to_priv(x) container_of(x, struct rzv2h_cpg_priv, rcdev) + +struct pll_clk { + struct rzv2h_cpg_priv *priv; + void __iomem *base; + struct clk_hw hw; + unsigned int conf; + unsigned int type; +}; + +#define to_pll(_hw) container_of(_hw, struct pll_clk, hw) + +/** + * struct mod_clock - Module clock + * + * @priv: CPG private data + * @hw: handle between common and hardware-specific interfaces + * @on_index: register offset + * @on_bit: ON/MON bit + * @mon_index: monitor register offset + * @mon_bit: montor bit + */ +struct mod_clock { + struct rzv2h_cpg_priv *priv; + struct clk_hw hw; + u8 on_index; + u8 on_bit; + s8 mon_index; + u8 mon_bit; +}; + +#define to_mod_clock(_hw) container_of(_hw, struct mod_clock, hw) + +/** + * struct ddiv_clk - DDIV clock + * + * @priv: CPG private data + * @div: divider clk + * @mon: monitor bit in CPG_CLKSTATUS0 register + */ +struct ddiv_clk { + struct rzv2h_cpg_priv *priv; + struct clk_divider div; + u8 mon; +}; + +#define to_ddiv_clock(_div) container_of(_div, struct ddiv_clk, div) + +static unsigned long rzv2h_cpg_pll_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct pll_clk *pll_clk = to_pll(hw); + struct rzv2h_cpg_priv *priv = pll_clk->priv; + unsigned int clk1, clk2; + u64 rate; + + if (!PLL_CLK_ACCESS(pll_clk->conf)) + return 0; + + clk1 = readl(priv->base + PLL_CLK1_OFFSET(pll_clk->conf)); + clk2 = readl(priv->base + PLL_CLK2_OFFSET(pll_clk->conf)); + + rate = mul_u64_u32_shr(parent_rate, (MDIV(clk1) << 16) + KDIV(clk1), + 16 + SDIV(clk2)); + + return DIV_ROUND_CLOSEST_ULL(rate, PDIV(clk1)); +} + +static const struct clk_ops rzv2h_cpg_pll_ops = { + .recalc_rate = rzv2h_cpg_pll_clk_recalc_rate, +}; + +static struct clk * __init +rzv2h_cpg_pll_clk_register(const struct cpg_core_clk *core, + struct rzv2h_cpg_priv *priv, + const struct clk_ops *ops) +{ + void __iomem *base = priv->base; + struct device *dev = priv->dev; + struct clk_init_data init; + const struct clk *parent; + const char *parent_name; + struct pll_clk *pll_clk; + int ret; + + parent = priv->clks[core->parent]; + if (IS_ERR(parent)) + return ERR_CAST(parent); + + pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL); + if (!pll_clk) + return ERR_PTR(-ENOMEM); + + parent_name = __clk_get_name(parent); + init.name = core->name; + init.ops = ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + pll_clk->hw.init = &init; + pll_clk->conf = core->cfg.conf; + pll_clk->base = base; + pll_clk->priv = priv; + pll_clk->type = core->type; + + ret = devm_clk_hw_register(dev, &pll_clk->hw); + if (ret) + return ERR_PTR(ret); + + return pll_clk->hw.clk; +} + +static unsigned long rzv2h_ddiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + unsigned int val; + + val = readl(divider->reg) >> divider->shift; + val &= clk_div_mask(divider->width); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + +static long rzv2h_ddiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct clk_divider *divider = to_clk_divider(hw); + + return divider_round_rate(hw, rate, prate, divider->table, + divider->width, divider->flags); +} + +static int rzv2h_ddiv_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_divider *divider = to_clk_divider(hw); + + return divider_determine_rate(hw, req, divider->table, divider->width, + divider->flags); +} + +static inline int rzv2h_cpg_wait_ddiv_clk_update_done(void __iomem *base, u8 mon) +{ + u32 bitmask = BIT(mon); + u32 val; + + return readl_poll_timeout_atomic(base + CPG_CLKSTATUS0, val, !(val & bitmask), 10, 200); +} + +static int rzv2h_ddiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); + struct ddiv_clk *ddiv = to_ddiv_clock(divider); + struct rzv2h_cpg_priv *priv = ddiv->priv; + unsigned long flags = 0; + int value; + u32 val; + int ret; + + value = divider_get_val(rate, parent_rate, divider->table, + divider->width, divider->flags); + if (value < 0) + return value; + + spin_lock_irqsave(divider->lock, flags); + + ret = rzv2h_cpg_wait_ddiv_clk_update_done(priv->base, ddiv->mon); + if (ret) + goto ddiv_timeout; + + val = readl(divider->reg) | DDIV_DIVCTL_WEN(divider->shift); + val &= ~(clk_div_mask(divider->width) << divider->shift); + val |= (u32)value << divider->shift; + writel(val, divider->reg); + + ret = rzv2h_cpg_wait_ddiv_clk_update_done(priv->base, ddiv->mon); + if (ret) + goto ddiv_timeout; + + spin_unlock_irqrestore(divider->lock, flags); + + return 0; + +ddiv_timeout: + spin_unlock_irqrestore(divider->lock, flags); + return ret; +} + +static const struct clk_ops rzv2h_ddiv_clk_divider_ops = { + .recalc_rate = rzv2h_ddiv_recalc_rate, + .round_rate = rzv2h_ddiv_round_rate, + .determine_rate = rzv2h_ddiv_determine_rate, + .set_rate = rzv2h_ddiv_set_rate, +}; + +static struct clk * __init +rzv2h_cpg_ddiv_clk_register(const struct cpg_core_clk *core, + struct rzv2h_cpg_priv *priv) +{ + struct ddiv cfg_ddiv = core->cfg.ddiv; + struct clk_init_data init = {}; + struct device *dev = priv->dev; + u8 shift = cfg_ddiv.shift; + u8 width = cfg_ddiv.width; + const struct clk *parent; + const char *parent_name; + struct clk_divider *div; + struct ddiv_clk *ddiv; + int ret; + + parent = priv->clks[core->parent]; + if (IS_ERR(parent)) + return ERR_CAST(parent); + + parent_name = __clk_get_name(parent); + + if ((shift + width) > 16) + return ERR_PTR(-EINVAL); + + ddiv = devm_kzalloc(priv->dev, sizeof(*ddiv), GFP_KERNEL); + if (!ddiv) + return ERR_PTR(-ENOMEM); + + init.name = core->name; + init.ops = &rzv2h_ddiv_clk_divider_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + + ddiv->priv = priv; + ddiv->mon = cfg_ddiv.monbit; + div = &ddiv->div; + div->reg = priv->base + cfg_ddiv.offset; + div->shift = shift; + div->width = width; + div->flags = core->flag; + div->lock = &priv->rmw_lock; + div->hw.init = &init; + div->table = core->dtable; + + ret = devm_clk_hw_register(dev, &div->hw); + if (ret) + return ERR_PTR(ret); + + return div->hw.clk; +} + +static struct clk +*rzv2h_cpg_clk_src_twocell_get(struct of_phandle_args *clkspec, + void *data) +{ + unsigned int clkidx = clkspec->args[1]; + struct rzv2h_cpg_priv *priv = data; + struct device *dev = priv->dev; + const char *type; + struct clk *clk; + + switch (clkspec->args[0]) { + case CPG_CORE: + type = "core"; + if (clkidx > priv->last_dt_core_clk) { + dev_err(dev, "Invalid %s clock index %u\n", type, clkidx); + return ERR_PTR(-EINVAL); + } + clk = priv->clks[clkidx]; + break; + + case CPG_MOD: + type = "module"; + if (clkidx >= priv->num_mod_clks) { + dev_err(dev, "Invalid %s clock index %u\n", type, clkidx); + return ERR_PTR(-EINVAL); + } + clk = priv->clks[priv->num_core_clks + clkidx]; + break; + + default: + dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]); + return ERR_PTR(-EINVAL); + } + + if (IS_ERR(clk)) + dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx, + PTR_ERR(clk)); + else + dev_dbg(dev, "clock (%u, %u) is %pC at %lu Hz\n", + clkspec->args[0], clkspec->args[1], clk, + clk_get_rate(clk)); + return clk; +} + +static void __init +rzv2h_cpg_register_core_clk(const struct cpg_core_clk *core, + struct rzv2h_cpg_priv *priv) +{ + struct clk *clk = ERR_PTR(-EOPNOTSUPP), *parent; + unsigned int id = core->id, div = core->div; + struct device *dev = priv->dev; + const char *parent_name; + struct clk_hw *clk_hw; + + WARN_DEBUG(id >= priv->num_core_clks); + WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); + + switch (core->type) { + case CLK_TYPE_IN: + clk = of_clk_get_by_name(priv->dev->of_node, core->name); + break; + case CLK_TYPE_FF: + WARN_DEBUG(core->parent >= priv->num_core_clks); + parent = priv->clks[core->parent]; + if (IS_ERR(parent)) { + clk = parent; + goto fail; + } + + parent_name = __clk_get_name(parent); + clk_hw = devm_clk_hw_register_fixed_factor(dev, core->name, + parent_name, CLK_SET_RATE_PARENT, + core->mult, div); + if (IS_ERR(clk_hw)) + clk = ERR_CAST(clk_hw); + else + clk = clk_hw->clk; + break; + case CLK_TYPE_PLL: + clk = rzv2h_cpg_pll_clk_register(core, priv, &rzv2h_cpg_pll_ops); + break; + case CLK_TYPE_DDIV: + clk = rzv2h_cpg_ddiv_clk_register(core, priv); + break; + default: + goto fail; + } + + if (IS_ERR_OR_NULL(clk)) + goto fail; + + dev_dbg(dev, "Core clock %pC at %lu Hz\n", clk, clk_get_rate(clk)); + priv->clks[id] = clk; + return; + +fail: + dev_err(dev, "Failed to register core clock %s: %ld\n", + core->name, PTR_ERR(clk)); +} + +static int rzv2h_mod_clock_endisable(struct clk_hw *hw, bool enable) +{ + struct mod_clock *clock = to_mod_clock(hw); + unsigned int reg = GET_CLK_ON_OFFSET(clock->on_index); + struct rzv2h_cpg_priv *priv = clock->priv; + u32 bitmask = BIT(clock->on_bit); + struct device *dev = priv->dev; + u32 value; + int error; + + dev_dbg(dev, "CLK_ON 0x%x/%pC %s\n", reg, hw->clk, + enable ? "ON" : "OFF"); + + value = bitmask << 16; + if (enable) + value |= bitmask; + + writel(value, priv->base + reg); + + if (!enable || clock->mon_index < 0) + return 0; + + reg = GET_CLK_MON_OFFSET(clock->mon_index); + bitmask = BIT(clock->mon_bit); + error = readl_poll_timeout_atomic(priv->base + reg, value, + value & bitmask, 0, 10); + if (error) + dev_err(dev, "Failed to enable CLK_ON %p\n", + priv->base + reg); + + return error; +} + +static int rzv2h_mod_clock_enable(struct clk_hw *hw) +{ + return rzv2h_mod_clock_endisable(hw, true); +} + +static void rzv2h_mod_clock_disable(struct clk_hw *hw) +{ + rzv2h_mod_clock_endisable(hw, false); +} + +static int rzv2h_mod_clock_is_enabled(struct clk_hw *hw) +{ + struct mod_clock *clock = to_mod_clock(hw); + struct rzv2h_cpg_priv *priv = clock->priv; + u32 bitmask; + u32 offset; + + if (clock->mon_index >= 0) { + offset = GET_CLK_MON_OFFSET(clock->mon_index); + bitmask = BIT(clock->mon_bit); + } else { + offset = GET_CLK_ON_OFFSET(clock->on_index); + bitmask = BIT(clock->on_bit); + } + + return readl(priv->base + offset) & bitmask; +} + +static const struct clk_ops rzv2h_mod_clock_ops = { + .enable = rzv2h_mod_clock_enable, + .disable = rzv2h_mod_clock_disable, + .is_enabled = rzv2h_mod_clock_is_enabled, +}; + +static void __init +rzv2h_cpg_register_mod_clk(const struct rzv2h_mod_clk *mod, + struct rzv2h_cpg_priv *priv) +{ + struct mod_clock *clock = NULL; + struct device *dev = priv->dev; + struct clk_init_data init; + struct clk *parent, *clk; + const char *parent_name; + unsigned int id; + int ret; + + id = GET_MOD_CLK_ID(priv->num_core_clks, mod->on_index, mod->on_bit); + WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks); + WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks); + WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT); + + parent = priv->clks[mod->parent]; + if (IS_ERR(parent)) { + clk = parent; + goto fail; + } + + clock = devm_kzalloc(dev, sizeof(*clock), GFP_KERNEL); + if (!clock) { + clk = ERR_PTR(-ENOMEM); + goto fail; + } + + init.name = mod->name; + init.ops = &rzv2h_mod_clock_ops; + init.flags = CLK_SET_RATE_PARENT; + if (mod->critical) + init.flags |= CLK_IS_CRITICAL; + + parent_name = __clk_get_name(parent); + init.parent_names = &parent_name; + init.num_parents = 1; + + clock->on_index = mod->on_index; + clock->on_bit = mod->on_bit; + clock->mon_index = mod->mon_index; + clock->mon_bit = mod->mon_bit; + clock->priv = priv; + clock->hw.init = &init; + + ret = devm_clk_hw_register(dev, &clock->hw); + if (ret) { + clk = ERR_PTR(ret); + goto fail; + } + + priv->clks[id] = clock->hw.clk; + + return; + +fail: + dev_err(dev, "Failed to register module clock %s: %ld\n", + mod->name, PTR_ERR(clk)); +} + +static int rzv2h_cpg_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rzv2h_cpg_priv *priv = rcdev_to_priv(rcdev); + unsigned int reg = GET_RST_OFFSET(priv->resets[id].reset_index); + u32 mask = BIT(priv->resets[id].reset_bit); + u8 monbit = priv->resets[id].mon_bit; + u32 value = mask << 16; + + dev_dbg(rcdev->dev, "assert id:%ld offset:0x%x\n", id, reg); + + writel(value, priv->base + reg); + + reg = GET_RST_MON_OFFSET(priv->resets[id].mon_index); + mask = BIT(monbit); + + return readl_poll_timeout_atomic(priv->base + reg, value, + value & mask, 10, 200); +} + +static int rzv2h_cpg_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rzv2h_cpg_priv *priv = rcdev_to_priv(rcdev); + unsigned int reg = GET_RST_OFFSET(priv->resets[id].reset_index); + u32 mask = BIT(priv->resets[id].reset_bit); + u8 monbit = priv->resets[id].mon_bit; + u32 value = (mask << 16) | mask; + + dev_dbg(rcdev->dev, "deassert id:%ld offset:0x%x\n", id, reg); + + writel(value, priv->base + reg); + + reg = GET_RST_MON_OFFSET(priv->resets[id].mon_index); + mask = BIT(monbit); + + return readl_poll_timeout_atomic(priv->base + reg, value, + !(value & mask), 10, 200); +} + +static int rzv2h_cpg_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + ret = rzv2h_cpg_assert(rcdev, id); + if (ret) + return ret; + + return rzv2h_cpg_deassert(rcdev, id); +} + +static int rzv2h_cpg_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct rzv2h_cpg_priv *priv = rcdev_to_priv(rcdev); + unsigned int reg = GET_RST_MON_OFFSET(priv->resets[id].mon_index); + u8 monbit = priv->resets[id].mon_bit; + + return !!(readl(priv->base + reg) & BIT(monbit)); +} + +static const struct reset_control_ops rzv2h_cpg_reset_ops = { + .reset = rzv2h_cpg_reset, + .assert = rzv2h_cpg_assert, + .deassert = rzv2h_cpg_deassert, + .status = rzv2h_cpg_status, +}; + +static int rzv2h_cpg_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + struct rzv2h_cpg_priv *priv = rcdev_to_priv(rcdev); + unsigned int id = reset_spec->args[0]; + u8 rst_index = id / 16; + u8 rst_bit = id % 16; + unsigned int i; + + for (i = 0; i < rcdev->nr_resets; i++) { + if (rst_index == priv->resets[i].reset_index && + rst_bit == priv->resets[i].reset_bit) + return i; + } + + return -EINVAL; +} + +static int rzv2h_cpg_reset_controller_register(struct rzv2h_cpg_priv *priv) +{ + priv->rcdev.ops = &rzv2h_cpg_reset_ops; + priv->rcdev.of_node = priv->dev->of_node; + priv->rcdev.dev = priv->dev; + priv->rcdev.of_reset_n_cells = 1; + priv->rcdev.of_xlate = rzv2h_cpg_reset_xlate; + priv->rcdev.nr_resets = priv->num_resets; + + return devm_reset_controller_register(priv->dev, &priv->rcdev); +} + +/** + * struct rzv2h_cpg_pd - RZ/V2H power domain data structure + * @priv: pointer to CPG private data structure + * @genpd: generic PM domain + */ +struct rzv2h_cpg_pd { + struct rzv2h_cpg_priv *priv; + struct generic_pm_domain genpd; +}; + +static int rzv2h_cpg_attach_dev(struct generic_pm_domain *domain, struct device *dev) +{ + struct device_node *np = dev->of_node; + struct of_phandle_args clkspec; + bool once = true; + struct clk *clk; + int error; + int i = 0; + + while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, + &clkspec)) { + if (once) { + once = false; + error = pm_clk_create(dev); + if (error) { + of_node_put(clkspec.np); + goto err; + } + } + clk = of_clk_get_from_provider(&clkspec); + of_node_put(clkspec.np); + if (IS_ERR(clk)) { + error = PTR_ERR(clk); + goto fail_destroy; + } + + error = pm_clk_add_clk(dev, clk); + if (error) { + dev_err(dev, "pm_clk_add_clk failed %d\n", + error); + goto fail_put; + } + i++; + } + + return 0; + +fail_put: + clk_put(clk); + +fail_destroy: + pm_clk_destroy(dev); +err: + return error; +} + +static void rzv2h_cpg_detach_dev(struct generic_pm_domain *unused, struct device *dev) +{ + if (!pm_clk_no_clocks(dev)) + pm_clk_destroy(dev); +} + +static void rzv2h_cpg_genpd_remove_simple(void *data) +{ + pm_genpd_remove(data); +} + +static int __init rzv2h_cpg_add_pm_domains(struct rzv2h_cpg_priv *priv) +{ + struct device *dev = priv->dev; + struct device_node *np = dev->of_node; + struct rzv2h_cpg_pd *pd; + int ret; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + pd->genpd.name = np->name; + pd->priv = priv; + pd->genpd.flags |= GENPD_FLAG_ALWAYS_ON | GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; + pd->genpd.attach_dev = rzv2h_cpg_attach_dev; + pd->genpd.detach_dev = rzv2h_cpg_detach_dev; + ret = pm_genpd_init(&pd->genpd, &pm_domain_always_on_gov, false); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, rzv2h_cpg_genpd_remove_simple, &pd->genpd); + if (ret) + return ret; + + return of_genpd_add_provider_simple(np, &pd->genpd); +} + +static void rzv2h_cpg_del_clk_provider(void *data) +{ + of_clk_del_provider(data); +} + +static int __init rzv2h_cpg_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const struct rzv2h_cpg_info *info; + struct rzv2h_cpg_priv *priv; + unsigned int nclks, i; + struct clk **clks; + int error; + + info = of_device_get_match_data(dev); + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + spin_lock_init(&priv->rmw_lock); + + priv->dev = dev; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + nclks = info->num_total_core_clks + info->num_hw_mod_clks; + clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL); + if (!clks) + return -ENOMEM; + + priv->resets = devm_kmemdup(dev, info->resets, sizeof(*info->resets) * + info->num_resets, GFP_KERNEL); + if (!priv->resets) + return -ENOMEM; + + dev_set_drvdata(dev, priv); + priv->clks = clks; + priv->num_core_clks = info->num_total_core_clks; + priv->num_mod_clks = info->num_hw_mod_clks; + priv->last_dt_core_clk = info->last_dt_core_clk; + priv->num_resets = info->num_resets; + + for (i = 0; i < nclks; i++) + clks[i] = ERR_PTR(-ENOENT); + + for (i = 0; i < info->num_core_clks; i++) + rzv2h_cpg_register_core_clk(&info->core_clks[i], priv); + + for (i = 0; i < info->num_mod_clks; i++) + rzv2h_cpg_register_mod_clk(&info->mod_clks[i], priv); + + error = of_clk_add_provider(np, rzv2h_cpg_clk_src_twocell_get, priv); + if (error) + return error; + + error = devm_add_action_or_reset(dev, rzv2h_cpg_del_clk_provider, np); + if (error) + return error; + + error = rzv2h_cpg_add_pm_domains(priv); + if (error) + return error; + + error = rzv2h_cpg_reset_controller_register(priv); + if (error) + return error; + + return 0; +} + +static const struct of_device_id rzv2h_cpg_match[] = { +#ifdef CONFIG_CLK_R9A09G057 + { + .compatible = "renesas,r9a09g057-cpg", + .data = &r9a09g057_cpg_info, + }, +#endif + { /* sentinel */ } +}; + +static struct platform_driver rzv2h_cpg_driver = { + .driver = { + .name = "rzv2h-cpg", + .of_match_table = rzv2h_cpg_match, + }, +}; + +static int __init rzv2h_cpg_init(void) +{ + return platform_driver_probe(&rzv2h_cpg_driver, rzv2h_cpg_probe); +} + +subsys_initcall(rzv2h_cpg_init); + +MODULE_DESCRIPTION("Renesas RZ/V2H CPG Driver"); diff --git a/drivers/clk/renesas/rzv2h-cpg.h b/drivers/clk/renesas/rzv2h-cpg.h new file mode 100644 index 000000000000..1bd406c69015 --- /dev/null +++ b/drivers/clk/renesas/rzv2h-cpg.h @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Renesas RZ/V2H(P) Clock Pulse Generator + * + * Copyright (C) 2024 Renesas Electronics Corp. + */ + +#ifndef __RENESAS_RZV2H_CPG_H__ +#define __RENESAS_RZV2H_CPG_H__ + +/** + * struct ddiv - Structure for dynamic switching divider + * + * @offset: register offset + * @shift: position of the divider bit + * @width: width of the divider + * @monbit: monitor bit in CPG_CLKSTATUS0 register + */ +struct ddiv { + unsigned int offset:11; + unsigned int shift:4; + unsigned int width:4; + unsigned int monbit:5; +}; + +#define DDIV_PACK(_offset, _shift, _width, _monbit) \ + ((struct ddiv){ \ + .offset = _offset, \ + .shift = _shift, \ + .width = _width, \ + .monbit = _monbit \ + }) + +#define CPG_CDDIV0 (0x400) + +#define CDDIV0_DIVCTL2 DDIV_PACK(CPG_CDDIV0, 8, 3, 2) + +/** + * Definitions of CPG Core Clocks + * + * These include: + * - Clock outputs exported to DT + * - External input clocks + * - Internal CPG clocks + */ +struct cpg_core_clk { + const char *name; + unsigned int id; + unsigned int parent; + unsigned int div; + unsigned int mult; + unsigned int type; + union { + unsigned int conf; + struct ddiv ddiv; + } cfg; + const struct clk_div_table *dtable; + u32 flag; +}; + +enum clk_types { + /* Generic */ + CLK_TYPE_IN, /* External Clock Input */ + CLK_TYPE_FF, /* Fixed Factor Clock */ + CLK_TYPE_PLL, + CLK_TYPE_DDIV, /* Dynamic Switching Divider */ +}; + +/* BIT(31) indicates if CLK1/2 are accessible or not */ +#define PLL_CONF(n) (BIT(31) | ((n) & ~GENMASK(31, 16))) +#define PLL_CLK_ACCESS(n) ((n) & BIT(31) ? 1 : 0) +#define PLL_CLK1_OFFSET(n) ((n) & ~GENMASK(31, 16)) +#define PLL_CLK2_OFFSET(n) (((n) & ~GENMASK(31, 16)) + (0x4)) + +#define DEF_TYPE(_name, _id, _type...) \ + { .name = _name, .id = _id, .type = _type } +#define DEF_BASE(_name, _id, _type, _parent...) \ + DEF_TYPE(_name, _id, _type, .parent = _parent) +#define DEF_PLL(_name, _id, _parent, _conf) \ + DEF_TYPE(_name, _id, CLK_TYPE_PLL, .parent = _parent, .cfg.conf = _conf) +#define DEF_INPUT(_name, _id) \ + DEF_TYPE(_name, _id, CLK_TYPE_IN) +#define DEF_FIXED(_name, _id, _parent, _mult, _div) \ + DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult) +#define DEF_DDIV(_name, _id, _parent, _ddiv_packed, _dtable) \ + DEF_TYPE(_name, _id, CLK_TYPE_DDIV, \ + .cfg.ddiv = _ddiv_packed, \ + .parent = _parent, \ + .dtable = _dtable, \ + .flag = CLK_DIVIDER_HIWORD_MASK) + +/** + * struct rzv2h_mod_clk - Module Clocks definitions + * + * @name: handle between common and hardware-specific interfaces + * @parent: id of parent clock + * @critical: flag to indicate the clock is critical + * @on_index: control register index + * @on_bit: ON bit + * @mon_index: monitor register index + * @mon_bit: monitor bit + */ +struct rzv2h_mod_clk { + const char *name; + u16 parent; + bool critical; + u8 on_index; + u8 on_bit; + s8 mon_index; + u8 mon_bit; +}; + +#define DEF_MOD_BASE(_name, _parent, _critical, _onindex, _onbit, _monindex, _monbit) \ + { \ + .name = (_name), \ + .parent = (_parent), \ + .critical = (_critical), \ + .on_index = (_onindex), \ + .on_bit = (_onbit), \ + .mon_index = (_monindex), \ + .mon_bit = (_monbit), \ + } + +#define DEF_MOD(_name, _parent, _onindex, _onbit, _monindex, _monbit) \ + DEF_MOD_BASE(_name, _parent, false, _onindex, _onbit, _monindex, _monbit) + +#define DEF_MOD_CRITICAL(_name, _parent, _onindex, _onbit, _monindex, _monbit) \ + DEF_MOD_BASE(_name, _parent, true, _onindex, _onbit, _monindex, _monbit) + +/** + * struct rzv2h_reset - Reset definitions + * + * @reset_index: reset register index + * @reset_bit: reset bit + * @mon_index: monitor register index + * @mon_bit: monitor bit + */ +struct rzv2h_reset { + u8 reset_index; + u8 reset_bit; + u8 mon_index; + u8 mon_bit; +}; + +#define DEF_RST_BASE(_resindex, _resbit, _monindex, _monbit) \ + { \ + .reset_index = (_resindex), \ + .reset_bit = (_resbit), \ + .mon_index = (_monindex), \ + .mon_bit = (_monbit), \ + } + +#define DEF_RST(_resindex, _resbit, _monindex, _monbit) \ + DEF_RST_BASE(_resindex, _resbit, _monindex, _monbit) + +/** + * struct rzv2h_cpg_info - SoC-specific CPG Description + * + * @core_clks: Array of Core Clock definitions + * @num_core_clks: Number of entries in core_clks[] + * @last_dt_core_clk: ID of the last Core Clock exported to DT + * @num_total_core_clks: Total number of Core Clocks (exported + internal) + * + * @mod_clks: Array of Module Clock definitions + * @num_mod_clks: Number of entries in mod_clks[] + * @num_hw_mod_clks: Number of Module Clocks supported by the hardware + * + * @resets: Array of Module Reset definitions + * @num_resets: Number of entries in resets[] + */ +struct rzv2h_cpg_info { + /* Core Clocks */ + const struct cpg_core_clk *core_clks; + unsigned int num_core_clks; + unsigned int last_dt_core_clk; + unsigned int num_total_core_clks; + + /* Module Clocks */ + const struct rzv2h_mod_clk *mod_clks; + unsigned int num_mod_clks; + unsigned int num_hw_mod_clks; + + /* Resets */ + const struct rzv2h_reset *resets; + unsigned int num_resets; +}; + +extern const struct rzv2h_cpg_info r9a09g057_cpg_info; + +#endif /* __RENESAS_RZV2H_CPG_H__ */ diff --git a/drivers/clk/starfive/clk-starfive-jh7110-vout.c b/drivers/clk/starfive/clk-starfive-jh7110-vout.c index 53f7af234cc2..aabd0484ac23 100644 --- a/drivers/clk/starfive/clk-starfive-jh7110-vout.c +++ b/drivers/clk/starfive/clk-starfive-jh7110-vout.c @@ -145,7 +145,7 @@ static int jh7110_voutcrg_probe(struct platform_device *pdev) /* enable power domain and clocks */ pm_runtime_enable(priv->dev); - ret = pm_runtime_get_sync(priv->dev); + ret = pm_runtime_resume_and_get(priv->dev); if (ret < 0) return dev_err_probe(priv->dev, ret, "failed to turn on power\n"); diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index d964e3affd42..0eab7f3e2eab 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -240,6 +240,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) } clk = of_clk_get_from_provider(&clkspec); + of_node_put(clkspec.np); if (IS_ERR(clk)) { pr_err("%s: failed to get atl clock %d from provider\n", __func__, i); diff --git a/drivers/clk/versatile/clk-sp810.c b/drivers/clk/versatile/clk-sp810.c index 45adac1b4630..033d4f78edc8 100644 --- a/drivers/clk/versatile/clk-sp810.c +++ b/drivers/clk/versatile/clk-sp810.c @@ -110,7 +110,7 @@ static void __init clk_sp810_of_setup(struct device_node *node) init.parent_names = parent_names; init.num_parents = num; - deprecated = !of_find_property(node, "assigned-clock-parents", NULL); + deprecated = !of_property_present(node, "assigned-clock-parents"); for (i = 0; i < ARRAY_SIZE(sp810->timerclken); i++) { snprintf(name, sizeof(name), "sp810_%d_%d", instance, i); diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c index e9cd80e085dc..3f929cf8dd2f 100644 --- a/drivers/clk/visconti/pll.c +++ b/drivers/clk/visconti/pll.c @@ -262,9 +262,9 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, for (len = 0; rate_table[len].rate != 0; ) len++; pll->rate_count = len; - pll->rate_table = kmemdup(rate_table, - pll->rate_count * sizeof(struct visconti_pll_rate_table), - GFP_KERNEL); + pll->rate_table = kmemdup_array(rate_table, + pll->rate_count, sizeof(*pll->rate_table), + GFP_KERNEL); WARN(!pll->rate_table, "%s: could not allocate rate table for %s\n", __func__, name); init.ops = &visconti_pll_ops; diff --git a/drivers/of/.kunitconfig b/drivers/of/.kunitconfig index 5a8fee11978c..4c53d2c7a275 100644 --- a/drivers/of/.kunitconfig +++ b/drivers/of/.kunitconfig @@ -1,3 +1,4 @@ CONFIG_KUNIT=y CONFIG_OF=y CONFIG_OF_KUNIT_TEST=y +CONFIG_OF_OVERLAY_KUNIT_TEST=y diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index dd726c7056bf..0e2d608c3e20 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -107,6 +107,16 @@ config OF_OVERLAY While this option is selected automatically when needed, you can enable it manually to improve device tree unit test coverage. +config OF_OVERLAY_KUNIT_TEST + tristate "Device Tree overlay KUnit tests" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + select OF_OVERLAY + help + This option builds KUnit unit tests for the device tree overlay code. + + If unsure, say N here, but this option is safe to enable. + config OF_NUMA bool diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 251d33532148..379a0afcbdc0 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -19,6 +19,9 @@ obj-y += kexec.o endif endif +obj-$(CONFIG_KUNIT) += of_kunit_helpers.o obj-$(CONFIG_OF_KUNIT_TEST) += of_test.o +obj-$(CONFIG_OF_OVERLAY_KUNIT_TEST) += overlay-test.o +overlay-test-y := overlay_test.o kunit_overlay_test.dtbo.o obj-$(CONFIG_OF_UNITTEST) += unittest-data/ diff --git a/drivers/of/kunit_overlay_test.dtso b/drivers/of/kunit_overlay_test.dtso new file mode 100644 index 000000000000..85f20b4b4c16 --- /dev/null +++ b/drivers/of/kunit_overlay_test.dtso @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 +/dts-v1/; +/plugin/; + +&{/} { + kunit-test { + compatible = "test,empty"; + }; +}; diff --git a/drivers/of/of_kunit_helpers.c b/drivers/of/of_kunit_helpers.c new file mode 100644 index 000000000000..287d6c91bb37 --- /dev/null +++ b/drivers/of/of_kunit_helpers.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test managed DeviceTree APIs + */ + +#include <linux/of.h> +#include <linux/of_fdt.h> + +#include <kunit/of.h> +#include <kunit/test.h> +#include <kunit/resource.h> + +#if defined(CONFIG_OF_OVERLAY) && defined(CONFIG_OF_EARLY_FLATTREE) + +static void of_overlay_fdt_apply_kunit_exit(void *ovcs_id) +{ + of_overlay_remove(ovcs_id); +} + +/** + * of_overlay_fdt_apply_kunit() - Test managed of_overlay_fdt_apply() + * @test: test context + * @overlay_fdt: device tree overlay to apply + * @overlay_fdt_size: size in bytes of @overlay_fdt + * @ovcs_id: identifier of overlay, used to remove the overlay + * + * Just like of_overlay_fdt_apply(), except the overlay is managed by the test + * case and is automatically removed with of_overlay_remove() after the test + * case concludes. + * + * Return: 0 on success, negative errno on failure + */ +int of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt, + u32 overlay_fdt_size, int *ovcs_id) +{ + int ret; + int *copy_id; + + copy_id = kunit_kmalloc(test, sizeof(*copy_id), GFP_KERNEL); + if (!copy_id) + return -ENOMEM; + + ret = of_overlay_fdt_apply(overlay_fdt, overlay_fdt_size, + ovcs_id, NULL); + if (ret) + return ret; + + *copy_id = *ovcs_id; + + return kunit_add_action_or_reset(test, of_overlay_fdt_apply_kunit_exit, + copy_id); +} +EXPORT_SYMBOL_GPL(of_overlay_fdt_apply_kunit); + +#endif + +KUNIT_DEFINE_ACTION_WRAPPER(of_node_put_wrapper, of_node_put, struct device_node *); + +/** + * of_node_put_kunit() - Test managed of_node_put() + * @test: test context + * @node: node to pass to `of_node_put()` + * + * Just like of_node_put(), except the node is managed by the test case and is + * automatically put with of_node_put() after the test case concludes. + */ +void of_node_put_kunit(struct kunit *test, struct device_node *node) +{ + if (kunit_add_action(test, of_node_put_wrapper, node)) { + KUNIT_FAIL(test, + "Can't allocate a kunit resource to put of_node\n"); + } +} +EXPORT_SYMBOL_GPL(of_node_put_kunit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Test managed DeviceTree APIs"); diff --git a/drivers/of/overlay_test.c b/drivers/of/overlay_test.c new file mode 100644 index 000000000000..19a292cdeee3 --- /dev/null +++ b/drivers/of/overlay_test.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for device tree overlays + */ +#include <linux/device/bus.h> +#include <linux/kconfig.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> + +#include <kunit/of.h> +#include <kunit/test.h> + +static const char * const kunit_node_name = "kunit-test"; +static const char * const kunit_compatible = "test,empty"; + +/* Test that of_overlay_apply_kunit() adds a node to the live tree */ +static void of_overlay_apply_kunit_apply(struct kunit *test) +{ + struct device_node *np; + + KUNIT_ASSERT_EQ(test, 0, + of_overlay_apply_kunit(test, kunit_overlay_test)); + + np = of_find_node_by_name(NULL, kunit_node_name); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, np); + of_node_put(np); +} + +/* + * Test that of_overlay_apply_kunit() creates platform devices with the + * expected device_node + */ +static void of_overlay_apply_kunit_platform_device(struct kunit *test) +{ + struct platform_device *pdev; + struct device_node *np; + + KUNIT_ASSERT_EQ(test, 0, + of_overlay_apply_kunit(test, kunit_overlay_test)); + + np = of_find_node_by_name(NULL, kunit_node_name); + of_node_put_kunit(test, np); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, np); + + pdev = of_find_device_by_node(np); + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, pdev); + if (pdev) + put_device(&pdev->dev); +} + +static int of_overlay_bus_match_compatible(struct device *dev, const void *data) +{ + return of_device_is_compatible(dev->of_node, data); +} + +/* Test that of_overlay_apply_kunit() cleans up after the test is finished */ +static void of_overlay_apply_kunit_cleanup(struct kunit *test) +{ + struct kunit fake; + struct platform_device *pdev; + struct device *dev; + struct device_node *np; + + if (!IS_ENABLED(CONFIG_OF_EARLY_FLATTREE)) + kunit_skip(test, "requires CONFIG_OF_EARLY_FLATTREE for root node"); + + kunit_init_test(&fake, "fake test", NULL); + KUNIT_ASSERT_EQ(test, fake.status, KUNIT_SUCCESS); + + KUNIT_ASSERT_EQ(test, 0, + of_overlay_apply_kunit(&fake, kunit_overlay_test)); + + np = of_find_node_by_name(NULL, kunit_node_name); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, np); + of_node_put_kunit(test, np); + + pdev = of_find_device_by_node(np); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + put_device(&pdev->dev); /* Not derefing 'pdev' after this */ + + /* Remove overlay */ + kunit_cleanup(&fake); + + /* The node and device should be removed */ + np = of_find_node_by_name(NULL, kunit_node_name); + KUNIT_EXPECT_PTR_EQ(test, NULL, np); + of_node_put(np); + + dev = bus_find_device(&platform_bus_type, NULL, kunit_compatible, + of_overlay_bus_match_compatible); + KUNIT_EXPECT_PTR_EQ(test, NULL, dev); + put_device(dev); +} + +static struct kunit_case of_overlay_apply_kunit_test_cases[] = { + KUNIT_CASE(of_overlay_apply_kunit_apply), + KUNIT_CASE(of_overlay_apply_kunit_platform_device), + KUNIT_CASE(of_overlay_apply_kunit_cleanup), + {} +}; + +/* + * Test suite for test managed device tree overlays. + */ +static struct kunit_suite of_overlay_apply_kunit_suite = { + .name = "of_overlay_apply_kunit", + .test_cases = of_overlay_apply_kunit_test_cases, +}; + +kunit_test_suites( + &of_overlay_apply_kunit_suite, +); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("KUnit tests for device tree overlays"); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 389d4ea6bfc1..86be4dfb9323 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -732,11 +732,14 @@ static int of_platform_notify(struct notifier_block *nb, struct of_reconfig_data *rd = arg; struct platform_device *pdev_parent, *pdev; bool children_left; + struct device_node *parent; switch (of_reconfig_get_state_change(action, rd)) { case OF_RECONFIG_CHANGE_ADD: - /* verify that the parent is a bus */ - if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS)) + parent = rd->dn->parent; + /* verify that the parent is a bus (or the root node) */ + if (!of_node_is_root(parent) && + !of_node_check_flag(parent, OF_POPULATED_BUS)) return NOTIFY_OK; /* not for us */ /* already populated? (driver using of_populate manually) */ @@ -749,7 +752,7 @@ static int of_platform_notify(struct notifier_block *nb, */ rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE; /* pdev_parent may be NULL when no bus platform device */ - pdev_parent = of_find_device_by_node(rd->dn->parent); + pdev_parent = of_find_device_by_node(parent); pdev = of_platform_device_create(rd->dn, NULL, pdev_parent ? &pdev_parent->dev : NULL); platform_device_put(pdev_parent); diff --git a/include/dt-bindings/clock/axg-audio-clkc.h b/include/dt-bindings/clock/axg-audio-clkc.h index 08c82c22fa5f..607f23b83fa7 100644 --- a/include/dt-bindings/clock/axg-audio-clkc.h +++ b/include/dt-bindings/clock/axg-audio-clkc.h @@ -155,5 +155,12 @@ #define AUD_CLKID_SYSCLK_B_DIV 175 #define AUD_CLKID_SYSCLK_A_EN 176 #define AUD_CLKID_SYSCLK_B_EN 177 +#define AUD_CLKID_EARCRX 178 +#define AUD_CLKID_EARCRX_CMDC_SEL 179 +#define AUD_CLKID_EARCRX_CMDC_DIV 180 +#define AUD_CLKID_EARCRX_CMDC 181 +#define AUD_CLKID_EARCRX_DMAC_SEL 182 +#define AUD_CLKID_EARCRX_DMAC_DIV 183 +#define AUD_CLKID_EARCRX_DMAC 184 #endif /* __AXG_AUDIO_CLKC_BINDINGS_H */ diff --git a/include/dt-bindings/clock/nxp,imx95-clock.h b/include/dt-bindings/clock/nxp,imx95-clock.h index 782662c3e740..b7a713a9ac8c 100644 --- a/include/dt-bindings/clock/nxp,imx95-clock.h +++ b/include/dt-bindings/clock/nxp,imx95-clock.h @@ -25,4 +25,7 @@ #define IMX95_CLK_DISPMIX_ENG0_SEL 0 #define IMX95_CLK_DISPMIX_ENG1_SEL 1 +#define IMX95_CLK_NETCMIX_ENETC0_RMII 0 +#define IMX95_CLK_NETCMIX_ENETC1_RMII 1 + #endif /* __DT_BINDINGS_CLOCK_IMX95_H */ diff --git a/include/dt-bindings/clock/renesas,r9a09g057-cpg.h b/include/dt-bindings/clock/renesas,r9a09g057-cpg.h new file mode 100644 index 000000000000..541e6d719bd6 --- /dev/null +++ b/include/dt-bindings/clock/renesas,r9a09g057-cpg.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + * + * Copyright (C) 2024 Renesas Electronics Corp. + */ +#ifndef __DT_BINDINGS_CLOCK_RENESAS_R9A09G057_CPG_H__ +#define __DT_BINDINGS_CLOCK_RENESAS_R9A09G057_CPG_H__ + +#include <dt-bindings/clock/renesas-cpg-mssr.h> + +/* Core Clock list */ +#define R9A09G057_SYS_0_PCLK 0 +#define R9A09G057_CA55_0_CORE_CLK0 1 +#define R9A09G057_CA55_0_CORE_CLK1 2 +#define R9A09G057_CA55_0_CORE_CLK2 3 +#define R9A09G057_CA55_0_CORE_CLK3 4 +#define R9A09G057_CA55_0_PERIPHCLK 5 +#define R9A09G057_CM33_CLK0 6 +#define R9A09G057_CST_0_SWCLKTCK 7 +#define R9A09G057_IOTOP_0_SHCLK 8 + +#endif /* __DT_BINDINGS_CLOCK_RENESAS_R9A09G057_CPG_H__ */ diff --git a/include/kunit/clk.h b/include/kunit/clk.h new file mode 100644 index 000000000000..73bc99cefe7b --- /dev/null +++ b/include/kunit/clk.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _CLK_KUNIT_H +#define _CLK_KUNIT_H + +struct clk; +struct clk_hw; +struct device; +struct device_node; +struct kunit; + +struct clk * +clk_get_kunit(struct kunit *test, struct device *dev, const char *con_id); +struct clk * +of_clk_get_kunit(struct kunit *test, struct device_node *np, int index); + +struct clk * +clk_hw_get_clk_kunit(struct kunit *test, struct clk_hw *hw, const char *con_id); +struct clk * +clk_hw_get_clk_prepared_enabled_kunit(struct kunit *test, struct clk_hw *hw, + const char *con_id); + +int clk_prepare_enable_kunit(struct kunit *test, struct clk *clk); + +int clk_hw_register_kunit(struct kunit *test, struct device *dev, struct clk_hw *hw); +int of_clk_hw_register_kunit(struct kunit *test, struct device_node *node, + struct clk_hw *hw); + +#endif diff --git a/include/kunit/of.h b/include/kunit/of.h new file mode 100644 index 000000000000..48d4e70c9666 --- /dev/null +++ b/include/kunit/of.h @@ -0,0 +1,115 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _KUNIT_OF_H +#define _KUNIT_OF_H + +#include <kunit/test.h> + +struct device_node; + +#ifdef CONFIG_OF + +void of_node_put_kunit(struct kunit *test, struct device_node *node); + +#else + +static inline +void of_node_put_kunit(struct kunit *test, struct device_node *node) +{ + kunit_skip(test, "requires CONFIG_OF"); +} + +#endif /* !CONFIG_OF */ + +#if defined(CONFIG_OF) && defined(CONFIG_OF_OVERLAY) && defined(CONFIG_OF_EARLY_FLATTREE) + +int of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt, + u32 overlay_fdt_size, int *ovcs_id); +#else + +static inline int +of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt, + u32 overlay_fdt_size, int *ovcs_id) +{ + kunit_skip(test, "requires CONFIG_OF and CONFIG_OF_OVERLAY and CONFIG_OF_EARLY_FLATTREE for root node"); + return -EINVAL; +} + +#endif + +/** + * __of_overlay_apply_kunit() - Test managed of_overlay_fdt_apply() variant + * @test: test context + * @overlay_begin: start address of overlay to apply + * @overlay_end: end address of overlay to apply + * + * This is mostly internal API. See of_overlay_apply_kunit() for the wrapper + * that makes this easier to use. + * + * Similar to of_overlay_fdt_apply(), except the overlay is managed by the test + * case and is automatically removed with of_overlay_remove() after the test + * case concludes. + * + * Return: 0 on success, negative errno on failure + */ +static inline int __of_overlay_apply_kunit(struct kunit *test, + u8 *overlay_begin, + const u8 *overlay_end) +{ + int unused; + + return of_overlay_fdt_apply_kunit(test, overlay_begin, + overlay_end - overlay_begin, + &unused); +} + +/** + * of_overlay_apply_kunit() - Test managed of_overlay_fdt_apply() for built-in overlays + * @test: test context + * @overlay_name: name of overlay to apply + * + * This macro is used to apply a device tree overlay built with the + * cmd_dt_S_dtbo rule in scripts/Makefile.lib that has been compiled into the + * kernel image or KUnit test module. The overlay is automatically removed when + * the test is finished. + * + * Unit tests that need device tree nodes should compile an overlay file with + * @overlay_name\.dtbo.o in their Makefile along with their unit test and then + * load the overlay during their test. The @overlay_name matches the filename + * of the overlay without the dtbo filename extension. If CONFIG_OF_OVERLAY is + * not enabled, the @test will be skipped. + * + * In the Makefile + * + * .. code-block:: none + * + * obj-$(CONFIG_OF_OVERLAY_KUNIT_TEST) += overlay_test.o kunit_overlay_test.dtbo.o + * + * In the test + * + * .. code-block:: c + * + * static void of_overlay_kunit_of_overlay_apply(struct kunit *test) + * { + * struct device_node *np; + * + * KUNIT_ASSERT_EQ(test, 0, + * of_overlay_apply_kunit(test, kunit_overlay_test)); + * + * np = of_find_node_by_name(NULL, "test-kunit"); + * KUNIT_EXPECT_NOT_ERR_OR_NULL(test, np); + * of_node_put(np); + * } + * + * Return: 0 on success, negative errno on failure. + */ +#define of_overlay_apply_kunit(test, overlay_name) \ +({ \ + extern uint8_t __dtbo_##overlay_name##_begin[]; \ + extern uint8_t __dtbo_##overlay_name##_end[]; \ + \ + __of_overlay_apply_kunit((test), \ + __dtbo_##overlay_name##_begin, \ + __dtbo_##overlay_name##_end); \ +}) + +#endif diff --git a/include/kunit/platform_device.h b/include/kunit/platform_device.h new file mode 100644 index 000000000000..0fc0999d2420 --- /dev/null +++ b/include/kunit/platform_device.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _KUNIT_PLATFORM_DRIVER_H +#define _KUNIT_PLATFORM_DRIVER_H + +struct kunit; +struct platform_device; +struct platform_driver; + +struct platform_device * +kunit_platform_device_alloc(struct kunit *test, const char *name, int id); +int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev); + +int kunit_platform_device_prepare_wait_for_probe(struct kunit *test, + struct platform_device *pdev, + struct completion *x); + +int kunit_platform_driver_register(struct kunit *test, + struct platform_driver *drv); + +#endif diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile index 30f6bbf04a4a..5aa51978e456 100644 --- a/lib/kunit/Makefile +++ b/lib/kunit/Makefile @@ -9,7 +9,8 @@ kunit-objs += test.o \ try-catch.o \ executor.o \ attributes.o \ - device.o + device.o \ + platform.o ifeq ($(CONFIG_KUNIT_DEBUGFS),y) kunit-objs += debugfs.o @@ -19,6 +20,7 @@ endif obj-y += hooks.o obj-$(CONFIG_KUNIT_TEST) += kunit-test.o +obj-$(CONFIG_KUNIT_TEST) += platform-test.o # string-stream-test compiles built-in only. ifeq ($(CONFIG_KUNIT_TEST),y) diff --git a/lib/kunit/platform-test.c b/lib/kunit/platform-test.c new file mode 100644 index 000000000000..e3debb8fbcef --- /dev/null +++ b/lib/kunit/platform-test.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit test for KUnit platform driver infrastructure. + */ + +#include <linux/platform_device.h> + +#include <kunit/platform_device.h> +#include <kunit/test.h> + +/* + * Test that kunit_platform_device_alloc() creates a platform device. + */ +static void kunit_platform_device_alloc_test(struct kunit *test) +{ + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, + kunit_platform_device_alloc(test, "kunit-platform", 1)); +} + +/* + * Test that kunit_platform_device_add() registers a platform device on the + * platform bus with the proper name and id. + */ +static void kunit_platform_device_add_test(struct kunit *test) +{ + struct platform_device *pdev; + const char *name = "kunit-platform-add"; + const int id = -1; + + pdev = kunit_platform_device_alloc(test, name, id); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + + KUNIT_EXPECT_EQ(test, 0, kunit_platform_device_add(test, pdev)); + KUNIT_EXPECT_TRUE(test, dev_is_platform(&pdev->dev)); + KUNIT_EXPECT_STREQ(test, pdev->name, name); + KUNIT_EXPECT_EQ(test, pdev->id, id); +} + +/* + * Test that kunit_platform_device_add() called twice with the same device name + * and id fails the second time and properly cleans up. + */ +static void kunit_platform_device_add_twice_fails_test(struct kunit *test) +{ + struct platform_device *pdev; + const char *name = "kunit-platform-add-2"; + const int id = -1; + + pdev = kunit_platform_device_alloc(test, name, id); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, pdev)); + + pdev = kunit_platform_device_alloc(test, name, id); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + + KUNIT_EXPECT_NE(test, 0, kunit_platform_device_add(test, pdev)); +} + +static int kunit_platform_device_find_by_name(struct device *dev, const void *data) +{ + return strcmp(dev_name(dev), data) == 0; +} + +/* + * Test that kunit_platform_device_add() cleans up by removing the platform + * device when the test finishes. */ +static void kunit_platform_device_add_cleans_up(struct kunit *test) +{ + struct platform_device *pdev; + const char *name = "kunit-platform-clean"; + const int id = -1; + struct kunit fake; + struct device *dev; + + kunit_init_test(&fake, "kunit_platform_device_add_fake_test", NULL); + KUNIT_ASSERT_EQ(test, fake.status, KUNIT_SUCCESS); + + pdev = kunit_platform_device_alloc(&fake, name, id); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(&fake, pdev)); + dev = bus_find_device(&platform_bus_type, NULL, name, + kunit_platform_device_find_by_name); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + put_device(dev); + + /* Remove pdev */ + kunit_cleanup(&fake); + + /* + * Failing to migrate the kunit_resource would lead to an extra + * put_device() call on the platform device. The best we can do here is + * make sure the device no longer exists on the bus, but if something + * is wrong we'll see a refcount underflow here. We can't test for a + * refcount underflow because the kref matches the lifetime of the + * device which should already be freed and could be used by something + * else. + */ + dev = bus_find_device(&platform_bus_type, NULL, name, + kunit_platform_device_find_by_name); + KUNIT_EXPECT_PTR_EQ(test, NULL, dev); + put_device(dev); +} + +/* + * Test suite for struct platform_device kunit APIs + */ +static struct kunit_case kunit_platform_device_test_cases[] = { + KUNIT_CASE(kunit_platform_device_alloc_test), + KUNIT_CASE(kunit_platform_device_add_test), + KUNIT_CASE(kunit_platform_device_add_twice_fails_test), + KUNIT_CASE(kunit_platform_device_add_cleans_up), + {} +}; + +static struct kunit_suite kunit_platform_device_suite = { + .name = "kunit_platform_device", + .test_cases = kunit_platform_device_test_cases, +}; + +struct kunit_platform_driver_test_context { + struct platform_driver pdrv; + const char *data; +}; + +static const char * const test_data = "test data"; + +static inline struct kunit_platform_driver_test_context * +to_test_context(struct platform_device *pdev) +{ + return container_of(to_platform_driver(pdev->dev.driver), + struct kunit_platform_driver_test_context, + pdrv); +} + +static int kunit_platform_driver_probe(struct platform_device *pdev) +{ + struct kunit_platform_driver_test_context *ctx; + + ctx = to_test_context(pdev); + ctx->data = test_data; + + return 0; +} + +/* Test that kunit_platform_driver_register() registers a driver that probes. */ +static void kunit_platform_driver_register_test(struct kunit *test) +{ + struct platform_device *pdev; + struct kunit_platform_driver_test_context *ctx; + DECLARE_COMPLETION_ONSTACK(comp); + const char *name = "kunit-platform-register"; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + pdev = kunit_platform_device_alloc(test, name, -1); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, pdev)); + + ctx->pdrv.probe = kunit_platform_driver_probe; + ctx->pdrv.driver.name = name; + ctx->pdrv.driver.owner = THIS_MODULE; + + KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_prepare_wait_for_probe(test, pdev, &comp)); + + KUNIT_EXPECT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv)); + KUNIT_EXPECT_NE(test, 0, wait_for_completion_timeout(&comp, 3 * HZ)); + KUNIT_EXPECT_STREQ(test, ctx->data, test_data); +} + +/* + * Test that kunit_platform_device_prepare_wait_for_probe() completes the completion + * when the device is already probed. + */ +static void kunit_platform_device_prepare_wait_for_probe_completes_when_already_probed(struct kunit *test) +{ + struct platform_device *pdev; + struct kunit_platform_driver_test_context *ctx; + DECLARE_COMPLETION_ONSTACK(comp); + const char *name = "kunit-platform-wait"; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + + pdev = kunit_platform_device_alloc(test, name, -1); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, pdev)); + + ctx->pdrv.probe = kunit_platform_driver_probe; + ctx->pdrv.driver.name = name; + ctx->pdrv.driver.owner = THIS_MODULE; + + /* Make sure driver has actually probed */ + KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_prepare_wait_for_probe(test, pdev, &comp)); + KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv)); + KUNIT_ASSERT_NE(test, 0, wait_for_completion_timeout(&comp, 3 * HZ)); + + reinit_completion(&comp); + KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_prepare_wait_for_probe(test, pdev, &comp)); + + KUNIT_EXPECT_NE(test, 0, wait_for_completion_timeout(&comp, HZ)); +} + +static struct kunit_case kunit_platform_driver_test_cases[] = { + KUNIT_CASE(kunit_platform_driver_register_test), + KUNIT_CASE(kunit_platform_device_prepare_wait_for_probe_completes_when_already_probed), + {} +}; + +/* + * Test suite for struct platform_driver kunit APIs + */ +static struct kunit_suite kunit_platform_driver_suite = { + .name = "kunit_platform_driver", + .test_cases = kunit_platform_driver_test_cases, +}; + +kunit_test_suites( + &kunit_platform_device_suite, + &kunit_platform_driver_suite, +); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("KUnit test for KUnit platform driver infrastructure"); diff --git a/lib/kunit/platform.c b/lib/kunit/platform.c new file mode 100644 index 000000000000..0b518de26065 --- /dev/null +++ b/lib/kunit/platform.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test managed platform driver + */ + +#include <linux/completion.h> +#include <linux/device/bus.h> +#include <linux/device/driver.h> +#include <linux/platform_device.h> + +#include <kunit/platform_device.h> +#include <kunit/resource.h> + +struct kunit_platform_device_alloc_params { + const char *name; + int id; +}; + +static int kunit_platform_device_alloc_init(struct kunit_resource *res, void *context) +{ + struct kunit_platform_device_alloc_params *params = context; + struct platform_device *pdev; + + pdev = platform_device_alloc(params->name, params->id); + if (!pdev) + return -ENOMEM; + + res->data = pdev; + + return 0; +} + +static void kunit_platform_device_alloc_exit(struct kunit_resource *res) +{ + struct platform_device *pdev = res->data; + + platform_device_put(pdev); +} + +/** + * kunit_platform_device_alloc() - Allocate a KUnit test managed platform device + * @test: test context + * @name: device name of platform device to alloc + * @id: identifier of platform device to alloc. + * + * Allocate a test managed platform device. The device is put when the test completes. + * + * Return: Allocated platform device on success, NULL on failure. + */ +struct platform_device * +kunit_platform_device_alloc(struct kunit *test, const char *name, int id) +{ + struct kunit_platform_device_alloc_params params = { + .name = name, + .id = id, + }; + + return kunit_alloc_resource(test, + kunit_platform_device_alloc_init, + kunit_platform_device_alloc_exit, + GFP_KERNEL, ¶ms); +} +EXPORT_SYMBOL_GPL(kunit_platform_device_alloc); + +static void kunit_platform_device_add_exit(struct kunit_resource *res) +{ + struct platform_device *pdev = res->data; + + platform_device_unregister(pdev); +} + +static bool +kunit_platform_device_alloc_match(struct kunit *test, + struct kunit_resource *res, void *match_data) +{ + struct platform_device *pdev = match_data; + + return res->data == pdev && res->free == kunit_platform_device_alloc_exit; +} + +KUNIT_DEFINE_ACTION_WRAPPER(platform_device_unregister_wrapper, + platform_device_unregister, struct platform_device *); +/** + * kunit_platform_device_add() - Register a KUnit test managed platform device + * @test: test context + * @pdev: platform device to add + * + * Register a test managed platform device. The device is unregistered when the + * test completes. + * + * Return: 0 on success, negative errno on failure. + */ +int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev) +{ + struct kunit_resource *res; + int ret; + + ret = platform_device_add(pdev); + if (ret) + return ret; + + res = kunit_find_resource(test, kunit_platform_device_alloc_match, pdev); + if (res) { + /* + * Transfer the reference count of the platform device if it + * was allocated with kunit_platform_device_alloc(). In this + * case, calling platform_device_put() when the test exits from + * kunit_platform_device_alloc_exit() would lead to reference + * count underflow because platform_device_unregister_wrapper() + * calls platform_device_unregister() which also calls + * platform_device_put(). + * + * Usually callers transfer the refcount initialized in + * platform_device_alloc() to platform_device_add() by calling + * platform_device_unregister() when platform_device_add() + * succeeds or platform_device_put() when it fails. KUnit has to + * keep this straight by redirecting the free routine for the + * resource to the right function. Luckily this only has to + * account for the success scenario. + */ + res->free = kunit_platform_device_add_exit; + kunit_put_resource(res); + } else { + ret = kunit_add_action_or_reset(test, platform_device_unregister_wrapper, pdev); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(kunit_platform_device_add); + +struct kunit_platform_device_probe_nb { + struct completion *x; + struct device *dev; + struct notifier_block nb; +}; + +static int kunit_platform_device_probe_notify(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct kunit_platform_device_probe_nb *knb; + struct device *dev = data; + + knb = container_of(nb, struct kunit_platform_device_probe_nb, nb); + if (event != BUS_NOTIFY_BOUND_DRIVER || knb->dev != dev) + return NOTIFY_DONE; + + complete(knb->x); + + return NOTIFY_OK; +} + +static void kunit_platform_device_probe_nb_remove(void *nb) +{ + bus_unregister_notifier(&platform_bus_type, nb); +} + +/** + * kunit_platform_device_prepare_wait_for_probe() - Prepare a completion + * variable to wait for a platform device to probe + * @test: test context + * @pdev: platform device to prepare to wait for probe of + * @x: completion variable completed when @dev has probed + * + * Prepare a completion variable @x to wait for @pdev to probe. Waiting on the + * completion forces a preemption, allowing the platform driver to probe. + * + * Example + * + * .. code-block:: c + * + * static int kunit_platform_driver_probe(struct platform_device *pdev) + * { + * return 0; + * } + * + * static void kunit_platform_driver_test(struct kunit *test) + * { + * struct platform_device *pdev; + * struct platform_driver *pdrv; + * DECLARE_COMPLETION_ONSTACK(comp); + * + * pdev = kunit_platform_device_alloc(test, "kunit-platform", -1); + * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev); + * KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, pdev)); + * + * pdrv = kunit_kzalloc(test, sizeof(*pdrv), GFP_KERNEL); + * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdrv); + * + * pdrv->probe = kunit_platform_driver_probe; + * pdrv->driver.name = "kunit-platform"; + * pdrv->driver.owner = THIS_MODULE; + * + * KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_prepare_wait_for_probe(test, pdev, &comp)); + * KUNIT_ASSERT_EQ(test, 0, kunit_platform_driver_register(test, pdrv)); + * + * KUNIT_EXPECT_NE(test, 0, wait_for_completion_timeout(&comp, 3 * HZ)); + * } + * + * Return: 0 on success, negative errno on failure. + */ +int kunit_platform_device_prepare_wait_for_probe(struct kunit *test, + struct platform_device *pdev, + struct completion *x) +{ + struct device *dev = &pdev->dev; + struct kunit_platform_device_probe_nb *knb; + bool bound; + + knb = kunit_kzalloc(test, sizeof(*knb), GFP_KERNEL); + if (!knb) + return -ENOMEM; + + knb->nb.notifier_call = kunit_platform_device_probe_notify; + knb->dev = dev; + knb->x = x; + + device_lock(dev); + bound = device_is_bound(dev); + if (bound) { + device_unlock(dev); + complete(x); + kunit_kfree(test, knb); + return 0; + } + + bus_register_notifier(&platform_bus_type, &knb->nb); + device_unlock(&pdev->dev); + + return kunit_add_action_or_reset(test, kunit_platform_device_probe_nb_remove, &knb->nb); +} +EXPORT_SYMBOL_GPL(kunit_platform_device_prepare_wait_for_probe); + +KUNIT_DEFINE_ACTION_WRAPPER(platform_driver_unregister_wrapper, + platform_driver_unregister, struct platform_driver *); +/** + * kunit_platform_driver_register() - Register a KUnit test managed platform driver + * @test: test context + * @drv: platform driver to register + * + * Register a test managed platform driver. This allows callers to embed the + * @drv in a container structure and use container_of() in the probe function + * to pass information to KUnit tests. + * + * Example + * + * .. code-block:: c + * + * struct kunit_test_context { + * struct platform_driver pdrv; + * const char *data; + * }; + * + * static inline struct kunit_test_context * + * to_test_context(struct platform_device *pdev) + * { + * return container_of(to_platform_driver(pdev->dev.driver), + * struct kunit_test_context, + * pdrv); + * } + * + * static int kunit_platform_driver_probe(struct platform_device *pdev) + * { + * struct kunit_test_context *ctx; + * + * ctx = to_test_context(pdev); + * ctx->data = "test data"; + * + * return 0; + * } + * + * static void kunit_platform_driver_test(struct kunit *test) + * { + * struct kunit_test_context *ctx; + * + * ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + * KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); + * + * ctx->pdrv.probe = kunit_platform_driver_probe; + * ctx->pdrv.driver.name = "kunit-platform"; + * ctx->pdrv.driver.owner = THIS_MODULE; + * + * KUNIT_EXPECT_EQ(test, 0, kunit_platform_driver_register(test, &ctx->pdrv)); + * <... wait for driver to probe ...> + * KUNIT_EXPECT_STREQ(test, ctx->data, "test data"); + * } + * + * Return: 0 on success, negative errno on failure. + */ +int kunit_platform_driver_register(struct kunit *test, + struct platform_driver *drv) +{ + int ret; + + ret = platform_driver_register(drv); + if (ret) + return ret; + + return kunit_add_action_or_reset(test, platform_driver_unregister_wrapper, drv); +} +EXPORT_SYMBOL_GPL(kunit_platform_driver_register); |