mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-28 16:52:18 +00:00
The core framework gained a clk provider helper, a clk consumer helper, and
some unit tests for the assigned clk rates feature in DeviceTree. On the vendor driver side, we gained a whole pile of SoC driver support detailed below. The majority in the diffstat is Qualcomm, but there's also quite a few Samsung and Mediatek clk driver additions in here as well. The top vendors is quite common, but the sheer amount of new drivers is uncommon, so I'm anticipating a larger number of fixes for clk drivers this cycle. Core: - devm_clk_bulk_get_all_enabled() to return number of clks acquired - devm_clk_hw_register_gate_parent_hw() helper to modernize drivers - KUnit tests for clk-assigned-rates{,-u64} New Drivers: - Marvell PXA1908 SoC clks - Mobileye EyeQ5, EyeQ6L and EyeQ6H clk driver - TWL6030 clk driver - Nuvoton Arbel BMC NPCM8XX SoC clks - MediaTek MT6735 SoC clks - MediaTek MT7620, MT7628 and MT7688 MMC clks - Add a driver for gated fixed rate clocks - Global clock controllers for Qualcomm QCS8300 and IPQ5424 SoCs - Camera, display and video clock controllers for Qualcomm SA8775P SoCs - Global, display, GPU, TCSR, and RPMh clock controllers for Qualcomm SAR2130P - Global, camera, display, GPU, and video clock controllers for Qualcomm SM8475 SoCs - RTC power domain and Battery Backup Function (VBATTB) clock support for the Renesas RZ/G3S SoC - Qualcomm IPQ9574 alpha PLLs - Support for i.MX91 CCM in the i.MX93 driver - Microchip LAN969X SoC clks - Cortex-A55 core clocks and Interrupt Control Unit (ICU) clock and reset on Renesas RZ/V2H(P) - Samsung ExynosAutov920 clk drivers for PERIC1, MISC, HSI0 and HSI1 - Samsung Exynos8895 clk drivers for FSYS0/1, PERIC0/1, PERIS and TOP Updates: - Convert more clk bindings to YAML - Various clk driver cleanups: NULL checks, add const, etc. - Remove END/NUM #defines that count number of clks in various binding headers - Continue moving reset drivers to drivers/reset via auxiliary bus -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEE9L57QeeUxqYDyoaDrQKIl8bklSUFAmc/r1kRHHNib3lkQGtl cm5lbC5vcmcACgkQrQKIl8bklSUlaw/+NkmTMPSpgKy8NfZi6KoCk3U5llaknXvj Y/Y2pB7UpOFDTsSCKRcFrZ6JWS6GIogE70W9w+zxIht4QA4Ekd9vKT7VRhMl+8t/ pz2i0c0Pm24hSye9LKM7JCVIVL8SNYonOs3wC1sfMVMDoUikVwupj6Bmj0nAYrBo hbJFBXtn/LbyYImJQ9hYqHnUtJKGp/N7hhpGu6kT/lbzcaWsBMp4lhH+s20DJz5e kdJVJGaLOELerAG/SHIxh9obtfznvex6x3itTB0o/d6/1DSDjjlxnZH8YV8eQWk0 kK+ORuewA+qCi3RiPReHCPBIfPI4HL0z3k5JFA5eI7eD4VZIis+YBOa/Y8bQR9bG wDg5qh5su0fdeWBUvkFB03igNoMdtH68iYd2q3YE0ka95FGulcyvbqoyxTJnjIxW 328PizYZV8LQ4+LGSdIFyp9f/SrjF0pAt7yTF8Dis3jq3ul/6ELX9G6OCNgtGKQz p0Hb01fKC4s7w48QI5OXQKfS382vS8G8a2NIwt2xxorc4+Dr2rjPvlDhErshCOAT nDEerIjGWr/0rQeTGxg+SLUx5ytq2aBkysg95/9WVe3b8kZeePiW9gEH4tgealY8 eHzFvbqXutlKer0xLOYiLd3hOeHhkCJNj48QS8jVXtRGGeLjZONw5F1mjTNskPpx 9jbKMcDjGyc= =FqLm -----END PGP SIGNATURE----- Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux Pull clk updates from Stephen Boyd: "The core framework gained a clk provider helper, a clk consumer helper, and some unit tests for the assigned clk rates feature in DeviceTree. On the vendor driver side, we gained a whole pile of SoC driver support detailed below. The majority in the diffstat is Qualcomm, but there's also quite a few Samsung and Mediatek clk driver additions in here as well. The top vendors is quite common, but the sheer amount of new drivers is uncommon, so I'm anticipating a larger number of fixes for clk drivers this cycle. Core: - devm_clk_bulk_get_all_enabled() to return number of clks acquired - devm_clk_hw_register_gate_parent_hw() helper to modernize drivers - KUnit tests for clk-assigned-rates{,-u64} New Drivers: - Marvell PXA1908 SoC clks - Mobileye EyeQ5, EyeQ6L and EyeQ6H clk driver - TWL6030 clk driver - Nuvoton Arbel BMC NPCM8XX SoC clks - MediaTek MT6735 SoC clks - MediaTek MT7620, MT7628 and MT7688 MMC clks - Add a driver for gated fixed rate clocks - Global clock controllers for Qualcomm QCS8300 and IPQ5424 SoCs - Camera, display and video clock controllers for Qualcomm SA8775P SoCs - Global, display, GPU, TCSR, and RPMh clock controllers for Qualcomm SAR2130P - Global, camera, display, GPU, and video clock controllers for Qualcomm SM8475 SoCs - RTC power domain and Battery Backup Function (VBATTB) clock support for the Renesas RZ/G3S SoC - Qualcomm IPQ9574 alpha PLLs - Support for i.MX91 CCM in the i.MX93 driver - Microchip LAN969X SoC clks - Cortex-A55 core clocks and Interrupt Control Unit (ICU) clock and reset on Renesas RZ/V2H(P) - Samsung ExynosAutov920 clk drivers for PERIC1, MISC, HSI0 and HSI1 - Samsung Exynos8895 clk drivers for FSYS0/1, PERIC0/1, PERIS and TOP Updates: - Convert more clk bindings to YAML - Various clk driver cleanups: NULL checks, add const, etc. - Remove END/NUM #defines that count number of clks in various binding headers - Continue moving reset drivers to drivers/reset via auxiliary bus" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (162 commits) clk: clk-loongson2: Fix potential buffer overflow in flexible-array member access clk: Fix invalid execution of clk_set_rate clk: clk-loongson2: Fix memory corruption bug in struct loongson2_clk_provider clk: lan966x: make it selectable for ARCH_LAN969X clk: eyeq: add EyeQ6H west fixed factor clocks clk: eyeq: add EyeQ6H central fixed factor clocks clk: eyeq: add EyeQ5 fixed factor clocks clk: eyeq: add fixed factor clocks infrastructure clk: eyeq: require clock index with phandle in all cases clk: fixed-factor: add clk_hw_register_fixed_factor_index() function dt-bindings: clock: eyeq: add more Mobileye EyeQ5/EyeQ6H clocks dt-bindings: soc: mobileye: set `#clock-cells = <1>` for all compatibles clk: clk-axi-clkgen: make sure to enable the AXI bus clock dt-bindings: clock: axi-clkgen: include AXI clk clk: mmp: Add Marvell PXA1908 MPMU driver clk: mmp: Add Marvell PXA1908 APMU driver clk: mmp: Add Marvell PXA1908 APBCP driver clk: mmp: Add Marvell PXA1908 APBC driver dt-bindings: clock: Add Marvell PXA1908 clock bindings clk: mmp: Switch to use struct u32_fract instead of custom one ...
This commit is contained in:
commit
9f3a2ba62c
@ -1,52 +0,0 @@
|
||||
* Actions Semi Owl Clock Management Unit (CMU)
|
||||
|
||||
The Actions Semi Owl Clock Management Unit generates and supplies clock
|
||||
to various controllers within the SoC. The clock binding described here is
|
||||
applicable to S900, S700 and S500 SoC's.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following,
|
||||
"actions,s900-cmu"
|
||||
"actions,s700-cmu"
|
||||
"actions,s500-cmu"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- clocks: Reference to the parent clocks ("hosc", "losc")
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Each clock is assigned an identifier, and client nodes can use this identifier
|
||||
to specify the clock which they consume.
|
||||
|
||||
All available clocks are defined as preprocessor macros in corresponding
|
||||
dt-bindings/clock/actions,s900-cmu.h or actions,s700-cmu.h or
|
||||
actions,s500-cmu.h header and can be used in device tree sources.
|
||||
|
||||
External clocks:
|
||||
|
||||
The hosc clock used as input for the plls is generated outside the SoC. It is
|
||||
expected that it is defined using standard clock bindings as "hosc".
|
||||
|
||||
Actions Semi S900 CMU also requires one more clock:
|
||||
- "losc" - internal low frequency oscillator
|
||||
|
||||
Example: Clock Management Unit node:
|
||||
|
||||
cmu: clock-controller@e0160000 {
|
||||
compatible = "actions,s900-cmu";
|
||||
reg = <0x0 0xe0160000 0x0 0x1000>;
|
||||
clocks = <&hosc>, <&losc>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes clock generated by the clock
|
||||
management unit:
|
||||
|
||||
uart: serial@e012a000 {
|
||||
compatible = "actions,s900-uart", "actions,owl-uart";
|
||||
reg = <0x0 0xe012a000 0x0 0x2000>;
|
||||
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cmu CLK_UART5>;
|
||||
};
|
60
Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml
Normal file
60
Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml
Normal file
@ -0,0 +1,60 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/actions,owl-cmu.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Actions Semi Owl Clock Management Unit (CMU)
|
||||
|
||||
maintainers:
|
||||
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
description: |
|
||||
The Actions Semi Owl Clock Management Unit generates and supplies clock
|
||||
to various controllers within the SoC.
|
||||
|
||||
See also:
|
||||
include/dt-bindings/clock/actions,s500-cmu.h
|
||||
include/dt-bindings/clock/actions,s700-cmu.h
|
||||
include/dt-bindings/clock/actions,s900-cmu.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- actions,s500-cmu
|
||||
- actions,s700-cmu
|
||||
- actions,s900-cmu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Host oscillator source
|
||||
- description: Internal low frequency oscillator source
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
"#reset-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- "#clock-cells"
|
||||
- "#reset-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-controller@e0160000 {
|
||||
compatible = "actions,s900-cmu";
|
||||
reg = <0xe0160000 0x1000>;
|
||||
clocks = <&hosc>, <&losc>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
...
|
@ -26,9 +26,21 @@ properties:
|
||||
description:
|
||||
Specifies the reference clock(s) from which the output frequency is
|
||||
derived. This must either reference one clock if only the first clock
|
||||
input is connected or two if both clock inputs are connected.
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
input is connected or two if both clock inputs are connected. The last
|
||||
clock is the AXI bus clock that needs to be enabled so we can access the
|
||||
core registers.
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
oneOf:
|
||||
- items:
|
||||
- const: clkin1
|
||||
- const: s_axi_aclk
|
||||
- items:
|
||||
- const: clkin1
|
||||
- const: clkin2
|
||||
- const: s_axi_aclk
|
||||
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
@ -40,6 +52,7 @@ required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
@ -50,5 +63,6 @@ examples:
|
||||
compatible = "adi,axi-clkgen-2.00.a";
|
||||
#clock-cells = <0>;
|
||||
reg = <0xff000000 0x1000>;
|
||||
clocks = <&osc 1>;
|
||||
clocks = <&osc 1>, <&clkc 15>;
|
||||
clock-names = "clkin1", "s_axi_aclk";
|
||||
};
|
||||
|
@ -34,8 +34,10 @@ properties:
|
||||
- airoha,en7581-scu
|
||||
|
||||
reg:
|
||||
minItems: 2
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: scu base address
|
||||
- description: misc scu base address
|
||||
minItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
description:
|
||||
@ -60,9 +62,7 @@ allOf:
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- description: scu base address
|
||||
- description: misc scu base address
|
||||
minItems: 2
|
||||
|
||||
'#reset-cells': false
|
||||
|
||||
@ -73,11 +73,7 @@ allOf:
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- description: scu base address
|
||||
- description: misc scu base address
|
||||
- description: reset base address
|
||||
- description: pb scu base address
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
@ -96,12 +92,9 @@ examples:
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
scuclk: clock-controller@1fa20000 {
|
||||
scuclk: clock-controller@1fb00000 {
|
||||
compatible = "airoha,en7581-scu";
|
||||
reg = <0x0 0x1fa20000 0x0 0x400>,
|
||||
<0x0 0x1fb00000 0x0 0x90>,
|
||||
<0x0 0x1fb00830 0x0 0x8>,
|
||||
<0x0 0x1fbe3400 0x0 0xfc>;
|
||||
reg = <0x0 0x1fb00000 0x0 0x970>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/amlogic,meson8-clkc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Controller
|
||||
|
||||
maintainers:
|
||||
- Neil Armstrong <neil.armstrong@linaro.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- amlogic,meson8-clkc
|
||||
- amlogic,meson8b-clkc
|
||||
- items:
|
||||
- const: amlogic,meson8m2-clkc
|
||||
- const: amlogic,meson8-clkc
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 3
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: xtal
|
||||
- const: ddr_pll
|
||||
- const: clk_32k
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
'#reset-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- '#reset-cells'
|
||||
|
||||
additionalProperties: false
|
@ -1,51 +0,0 @@
|
||||
* Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Unit
|
||||
|
||||
The Amlogic Meson8 / Meson8b / Meson8m2 clock controller generates and
|
||||
supplies clock to various controllers within the SoC.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: must be one of:
|
||||
- "amlogic,meson8-clkc" for Meson8 (S802) SoCs
|
||||
- "amlogic,meson8b-clkc" for Meson8 (S805) SoCs
|
||||
- "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
- clocks: list of clock phandles, one for each entry in clock-names
|
||||
- clock-names: should contain the following:
|
||||
* "xtal": the 24MHz system oscillator
|
||||
* "ddr_pll": the DDR PLL clock
|
||||
* "clk_32k": (if present) the 32kHz clock signal from GPIOAO_6 (CLK_32K_IN)
|
||||
|
||||
Parent node should have the following properties :
|
||||
- compatible: "amlogic,meson-hhi-sysctrl", "simple-mfd", "syscon"
|
||||
- reg: base address and size of the HHI system control register space.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. All available clocks are defined as
|
||||
preprocessor macros in the dt-bindings/clock/meson8b-clkc.h header and can be
|
||||
used in device tree sources.
|
||||
|
||||
Similarly a preprocessor macro for each reset line is defined in
|
||||
dt-bindings/reset/amlogic,meson8b-clkc-reset.h (which can be used from the
|
||||
device tree sources).
|
||||
|
||||
|
||||
Example: Clock controller node:
|
||||
|
||||
clkc: clock-controller {
|
||||
compatible = "amlogic,meson8b-clkc";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
|
||||
Example: UART controller node that consumes the clock generated by the clock
|
||||
controller:
|
||||
|
||||
uart_AO: serial@c81004c0 {
|
||||
compatible = "amlogic,meson-uart";
|
||||
reg = <0xc81004c0 0x14>;
|
||||
interrupts = <0 90 1>;
|
||||
clocks = <&clkc CLKID_CLK81>;
|
||||
};
|
@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/gated-fixed-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Gated Fixed clock
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: gated-fixed-clock
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clock-frequency: true
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
enable-gpios:
|
||||
description:
|
||||
Contains a single GPIO specifier for the GPIO that enables and disables
|
||||
the oscillator.
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply:
|
||||
description: handle of the regulator that provides the supply voltage
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#clock-cells"
|
||||
- clock-frequency
|
||||
- vdd-supply
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
clock-1000000000 {
|
||||
compatible = "gated-fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <1000000000>;
|
||||
vdd-supply = <®_vdd>;
|
||||
};
|
||||
...
|
@ -16,6 +16,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fsl,imx91-ccm
|
||||
- fsl,imx93-ccm
|
||||
|
||||
reg:
|
||||
|
48
Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml
Normal file
48
Documentation/devicetree/bindings/clock/marvell,pxa1908.yaml
Normal file
@ -0,0 +1,48 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/marvell,pxa1908.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Marvell PXA1908 Clock Controllers
|
||||
|
||||
maintainers:
|
||||
- Duje Mihanović <duje.mihanovic@skole.hr>
|
||||
|
||||
description: |
|
||||
The PXA1908 clock subsystem generates and supplies clock to various
|
||||
controllers within the PXA1908 SoC. The PXA1908 contains numerous clock
|
||||
controller blocks, with the ones currently supported being APBC, APBCP, MPMU
|
||||
and APMU roughly corresponding to internal buses.
|
||||
|
||||
All these clock identifiers could be found in <include/dt-bindings/marvell,pxa1908.h>.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- marvell,pxa1908-apbc
|
||||
- marvell,pxa1908-apbcp
|
||||
- marvell,pxa1908-mpmu
|
||||
- marvell,pxa1908-apmu
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- '#clock-cells'
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
# APMU block:
|
||||
- |
|
||||
clock-controller@d4282800 {
|
||||
compatible = "marvell,pxa1908-apmu";
|
||||
reg = <0xd4282800 0x400>;
|
||||
#clock-cells = <1>;
|
||||
};
|
@ -12,7 +12,8 @@ maintainers:
|
||||
|
||||
description:
|
||||
The Mediatek apmixedsys controller provides PLLs to the system.
|
||||
The clock values can be found in <dt-bindings/clock/mt*-clk.h>.
|
||||
The clock values can be found in <dt-bindings/clock/mt*-clk.h>
|
||||
and <dt-bindings/clock/mediatek,mt*-apmixedsys.h>.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -34,6 +35,7 @@ properties:
|
||||
- enum:
|
||||
- mediatek,mt2701-apmixedsys
|
||||
- mediatek,mt2712-apmixedsys
|
||||
- mediatek,mt6735-apmixedsys
|
||||
- mediatek,mt6765-apmixedsys
|
||||
- mediatek,mt6779-apmixed
|
||||
- mediatek,mt6795-apmixedsys
|
||||
|
@ -11,9 +11,10 @@ maintainers:
|
||||
|
||||
description:
|
||||
The Mediatek infracfg controller provides various clocks and reset outputs
|
||||
to the system. The clock values can be found in <dt-bindings/clock/mt*-clk.h>,
|
||||
and reset values in <dt-bindings/reset/mt*-reset.h> and
|
||||
<dt-bindings/reset/mt*-resets.h>.
|
||||
to the system. The clock values can be found in <dt-bindings/clock/mt*-clk.h>
|
||||
and <dt-bindings/clock/mediatek,mt*-infracfg.h>, and reset values in
|
||||
<dt-bindings/reset/mt*-reset.h>, <dt-bindings/reset/mt*-resets.h> and
|
||||
<dt-bindings/reset/mediatek,mt*-infracfg.h>.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -22,6 +23,7 @@ properties:
|
||||
- enum:
|
||||
- mediatek,mt2701-infracfg
|
||||
- mediatek,mt2712-infracfg
|
||||
- mediatek,mt6735-infracfg
|
||||
- mediatek,mt6765-infracfg
|
||||
- mediatek,mt6795-infracfg
|
||||
- mediatek,mt6779-infracfg_ao
|
||||
|
@ -20,6 +20,7 @@ properties:
|
||||
- enum:
|
||||
- mediatek,mt2701-pericfg
|
||||
- mediatek,mt2712-pericfg
|
||||
- mediatek,mt6735-pericfg
|
||||
- mediatek,mt6765-pericfg
|
||||
- mediatek,mt6795-pericfg
|
||||
- mediatek,mt7622-pericfg
|
||||
|
@ -28,6 +28,10 @@ properties:
|
||||
- mediatek,mt2712-mfgcfg
|
||||
- mediatek,mt2712-vdecsys
|
||||
- mediatek,mt2712-vencsys
|
||||
- mediatek,mt6735-imgsys
|
||||
- mediatek,mt6735-mfgcfg
|
||||
- mediatek,mt6735-vdecsys
|
||||
- mediatek,mt6735-vencsys
|
||||
- mediatek,mt6765-camsys
|
||||
- mediatek,mt6765-imgsys
|
||||
- mediatek,mt6765-mipi0a
|
||||
|
@ -12,7 +12,8 @@ maintainers:
|
||||
|
||||
description:
|
||||
The Mediatek topckgen controller provides various clocks to the system.
|
||||
The clock values can be found in <dt-bindings/clock/mt*-clk.h>.
|
||||
The clock values can be found in <dt-bindings/clock/mt*-clk.h> and
|
||||
<dt-bindings/clock/mediatek,mt*-topckgen.h>.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
@ -31,6 +32,7 @@ properties:
|
||||
- enum:
|
||||
- mediatek,mt2701-topckgen
|
||||
- mediatek,mt2712-topckgen
|
||||
- mediatek,mt6735-topckgen
|
||||
- mediatek,mt6765-topckgen
|
||||
- mediatek,mt6779-topckgen
|
||||
- mediatek,mt6795-topckgen
|
||||
|
@ -16,7 +16,18 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: microchip,lan966x-gck
|
||||
oneOf:
|
||||
- enum:
|
||||
- microchip,lan966x-gck
|
||||
- microchip,lan9691-gck
|
||||
- items:
|
||||
- enum:
|
||||
- microchip,lan9698-gck
|
||||
- microchip,lan9696-gck
|
||||
- microchip,lan9694-gck
|
||||
- microchip,lan9693-gck
|
||||
- microchip,lan9692-gck
|
||||
- const: microchip,lan9691-gck
|
||||
|
||||
reg:
|
||||
minItems: 1
|
||||
|
@ -1,51 +0,0 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/mobileye,eyeq5-clk.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mobileye EyeQ5 clock controller
|
||||
|
||||
description:
|
||||
The EyeQ5 clock controller handles 10 read-only PLLs derived from the main
|
||||
crystal clock. It also exposes one divider clock, a child of one of the PLLs.
|
||||
Its registers live in a shared region called OLB.
|
||||
|
||||
maintainers:
|
||||
- Grégory Clement <gregory.clement@bootlin.com>
|
||||
- Théo Lebrun <theo.lebrun@bootlin.com>
|
||||
- Vladimir Kondratiev <vladimir.kondratiev@mobileye.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: mobileye,eyeq5-clk
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: plls
|
||||
- const: ospi
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
description:
|
||||
Input parent clock to all PLLs. Expected to be the main crystal.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
additionalProperties: false
|
@ -13,9 +13,10 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- nxp,imx95-lvds-csr
|
||||
- nxp,imx95-display-csr
|
||||
- nxp,imx95-camera-csr
|
||||
- nxp,imx95-display-csr
|
||||
- nxp,imx95-hsio-blk-ctl
|
||||
- nxp,imx95-lvds-csr
|
||||
- nxp,imx95-netcmix-blk-ctrl
|
||||
- nxp,imx95-vpu-csr
|
||||
- const: syscon
|
||||
|
@ -17,7 +17,9 @@ description: |
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,gcc-sm8450
|
||||
enum:
|
||||
- qcom,gcc-sm8450
|
||||
- qcom,sm8475-gcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
|
@ -4,31 +4,35 @@
|
||||
$id: http://devicetree.org/schemas/clock/qcom,ipq5332-gcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller on IPQ5332
|
||||
title: Qualcomm Global Clock & Reset Controller on IPQ5332 and IPQ5424
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <andersson@kernel.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and power
|
||||
domains on IPQ5332.
|
||||
domains on IPQ5332 and IPQ5424.
|
||||
|
||||
See also:: include/dt-bindings/clock/qcom,gcc-ipq5332.h
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
See also:
|
||||
include/dt-bindings/clock/qcom,gcc-ipq5332.h
|
||||
include/dt-bindings/clock/qcom,gcc-ipq5424.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,ipq5332-gcc
|
||||
enum:
|
||||
- qcom,ipq5332-gcc
|
||||
- qcom,ipq5424-gcc
|
||||
|
||||
clocks:
|
||||
minItems: 5
|
||||
items:
|
||||
- description: Board XO clock source
|
||||
- description: Sleep clock source
|
||||
- description: PCIE 2lane PHY pipe clock source
|
||||
- description: PCIE 2lane x1 PHY pipe clock source (For second lane)
|
||||
- description: USB PCIE wrapper pipe clock source
|
||||
- description: PCIE 2-lane PHY2 pipe clock source
|
||||
- description: PCIE 2-lane PHY3 pipe clock source
|
||||
|
||||
'#power-domain-cells': false
|
||||
'#interconnect-cells':
|
||||
@ -38,6 +42,29 @@ required:
|
||||
- compatible
|
||||
- clocks
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: qcom,ipq5332-gcc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
maxItems: 5
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: qcom,ipq5424-gcc
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 7
|
||||
maxItems: 7
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -0,0 +1,66 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,qcs8300-gcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Technologies, Inc. Global Clock & Reset Controller on QCS8300
|
||||
|
||||
maintainers:
|
||||
- Taniya Das <quic_tdas@quicinc.com>
|
||||
- Imran Shaik <quic_imrashai@quicinc.com>
|
||||
|
||||
description: |
|
||||
Qualcomm Technologies, Inc. Global clock control module provides the clocks, resets and
|
||||
power domains on QCS8300
|
||||
|
||||
See also: include/dt-bindings/clock/qcom,qcs8300-gcc.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,qcs8300-gcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: Board XO source
|
||||
- description: Sleep clock source
|
||||
- description: PCIE 0 Pipe clock source
|
||||
- description: PCIE 1 Pipe clock source
|
||||
- description: PCIE Phy Auxiliary clock source
|
||||
- description: First EMAC controller reference clock
|
||||
- description: UFS Phy Rx symbol 0 clock source
|
||||
- description: UFS Phy Rx symbol 1 clock source
|
||||
- description: UFS Phy Tx symbol 0 clock source
|
||||
- description: USB3 Phy wrapper pipe clock source
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- '#power-domain-cells'
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
clock-controller@100000 {
|
||||
compatible = "qcom,qcs8300-gcc";
|
||||
reg = <0x00100000 0xc7018>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&sleep_clk>,
|
||||
<&pcie_0_pipe_clk>,
|
||||
<&pcie_1_pipe_clk>,
|
||||
<&pcie_phy_aux_clk>,
|
||||
<&rxc0_ref_clk>,
|
||||
<&ufs_phy_rx_symbol_0_clk>,
|
||||
<&ufs_phy_rx_symbol_1_clk>,
|
||||
<&ufs_phy_tx_symbol_0_clk>,
|
||||
<&usb3_phy_wrapper_gcc_usb30_prim_pipe_clk>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -19,6 +19,7 @@ properties:
|
||||
enum:
|
||||
- qcom,qdu1000-rpmh-clk
|
||||
- qcom,sa8775p-rpmh-clk
|
||||
- qcom,sar2130p-rpmh-clk
|
||||
- qcom,sc7180-rpmh-clk
|
||||
- qcom,sc7280-rpmh-clk
|
||||
- qcom,sc8180x-rpmh-clk
|
||||
|
@ -0,0 +1,65 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/qcom,sar2130p-gcc.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm Global Clock & Reset Controller on sar2130p
|
||||
|
||||
maintainers:
|
||||
- Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
|
||||
|
||||
description: |
|
||||
Qualcomm global clock control module provides the clocks, resets and
|
||||
power domains on sar2130p.
|
||||
|
||||
See also: include/dt-bindings/clock/qcom,sar2130p-gcc.h
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sar2130p-gcc
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: XO reference clock
|
||||
- description: Sleep clock
|
||||
- description: PCIe 0 pipe clock
|
||||
- description: PCIe 1 pipe clock
|
||||
- description: Primary USB3 PHY wrapper pipe clock
|
||||
|
||||
protected-clocks:
|
||||
maxItems: 240
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- '#power-domain-cells'
|
||||
|
||||
allOf:
|
||||
- $ref: qcom,gcc.yaml#
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/qcom,rpmh.h>
|
||||
#include <dt-bindings/power/qcom,rpmhpd.h>
|
||||
|
||||
gcc: clock-controller@100000 {
|
||||
compatible = "qcom,sar2130p-gcc";
|
||||
reg = <0x100000 0x1f4200>;
|
||||
clocks = <&rpmhcc RPMH_CXO_CLK>,
|
||||
<&sleep_clk>,
|
||||
<&pcie_0_pipe_clk>,
|
||||
<&pcie_1_pipe_clk>,
|
||||
<&usb_0_ssphy>;
|
||||
power-domains = <&rpmhpd RPMHPD_CX>;
|
||||
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
#power-domain-cells = <1>;
|
||||
};
|
||||
...
|
@ -26,6 +26,7 @@ properties:
|
||||
enum:
|
||||
- qcom,sc8280xp-camcc
|
||||
- qcom,sm8450-camcc
|
||||
- qcom,sm8475-camcc
|
||||
- qcom,sm8550-camcc
|
||||
- qcom,sm8650-camcc
|
||||
- qcom,x1e80100-camcc
|
||||
|
@ -19,6 +19,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sm8450-dispcc
|
||||
- qcom,sm8475-dispcc
|
||||
|
||||
clocks:
|
||||
minItems: 3
|
||||
|
@ -14,6 +14,7 @@ description: |
|
||||
domains on Qualcomm SoCs.
|
||||
|
||||
See also::
|
||||
include/dt-bindings/clock/qcom,sar2130p-gpucc.h
|
||||
include/dt-bindings/clock/qcom,sm4450-gpucc.h
|
||||
include/dt-bindings/clock/qcom,sm8450-gpucc.h
|
||||
include/dt-bindings/clock/qcom,sm8550-gpucc.h
|
||||
@ -24,8 +25,10 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sar2130p-gpucc
|
||||
- qcom,sm4450-gpucc
|
||||
- qcom,sm8450-gpucc
|
||||
- qcom,sm8475-gpucc
|
||||
- qcom,sm8550-gpucc
|
||||
- qcom,sm8650-gpucc
|
||||
- qcom,x1e80100-gpucc
|
||||
|
@ -22,6 +22,7 @@ properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sm8450-videocc
|
||||
- qcom,sm8475-videocc
|
||||
- qcom,sm8550-videocc
|
||||
- qcom,sm8650-videocc
|
||||
|
||||
|
@ -22,6 +22,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,sar2130p-dispcc
|
||||
- qcom,sm8550-dispcc
|
||||
- qcom,sm8650-dispcc
|
||||
- qcom,x1e80100-dispcc
|
||||
|
@ -21,6 +21,7 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- qcom,sar2130p-tcsr
|
||||
- qcom,sm8550-tcsr
|
||||
- qcom,sm8650-tcsr
|
||||
- qcom,x1e80100-tcsr
|
||||
|
@ -1,58 +0,0 @@
|
||||
* Rockchip RK3328 Clock and Reset Unit
|
||||
|
||||
The RK3328 clock controller generates and supplies clock to various
|
||||
controllers within the SoC and also implements a reset controller for SoC
|
||||
peripherals.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be "rockchip,rk3328-cru"
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #clock-cells: should be 1.
|
||||
- #reset-cells: should be 1.
|
||||
|
||||
Optional Properties:
|
||||
|
||||
- rockchip,grf: phandle to the syscon managing the "general register files"
|
||||
If missing pll rates are not changeable, due to the missing pll lock status.
|
||||
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. All available clocks are defined as
|
||||
preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be
|
||||
used in device tree sources. Similar macros exist for the reset sources in
|
||||
these files.
|
||||
|
||||
External clocks:
|
||||
|
||||
There are several clocks that are generated outside the SoC. It is expected
|
||||
that they are defined using standard clock bindings with following
|
||||
clock-output-names:
|
||||
- "xin24m" - crystal input - required,
|
||||
- "clkin_i2s" - external I2S clock - optional,
|
||||
- "gmac_clkin" - external GMAC clock - optional
|
||||
- "phy_50m_out" - output clock of the pll in the mac phy
|
||||
- "hdmi_phy" - output clock of the hdmi phy pll - optional
|
||||
|
||||
Example: Clock controller node:
|
||||
|
||||
cru: clock-controller@ff440000 {
|
||||
compatible = "rockchip,rk3328-cru";
|
||||
reg = <0x0 0xff440000 0x0 0x1000>;
|
||||
rockchip,grf = <&grf>;
|
||||
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes the clock generated by the clock
|
||||
controller:
|
||||
|
||||
uart0: serial@ff120000 {
|
||||
compatible = "snps,dw-apb-uart";
|
||||
reg = <0xff120000 0x100>;
|
||||
interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
clocks = <&cru SCLK_UART0>;
|
||||
};
|
@ -0,0 +1,74 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/rockchip,rk3328-cru.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip RK3328 Clock and Reset Unit (CRU)
|
||||
|
||||
maintainers:
|
||||
- Elaine Zhang <zhangqing@rock-chips.com>
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
description: |
|
||||
The RK3328 clock controller generates and supplies clocks to various
|
||||
controllers within the SoC and also implements a reset controller for SoC
|
||||
peripherals.
|
||||
Each clock is assigned an identifier and client nodes can use this identifier
|
||||
to specify the clock which they consume. All available clocks are defined as
|
||||
preprocessor macros in the dt-bindings/clock/rk3328-cru.h headers and can be
|
||||
used in device tree sources. Similar macros exist for the reset sources in
|
||||
these files.
|
||||
There are several clocks that are generated outside the SoC. It is expected
|
||||
that they are defined using standard clock bindings with following
|
||||
clock-output-names:
|
||||
- "xin24m" - crystal input - required,
|
||||
- "clkin_i2s" - external I2S clock - optional,
|
||||
- "gmac_clkin" - external GMAC clock - optional
|
||||
- "phy_50m_out" - output clock of the pll in the mac phy
|
||||
- "hdmi_phy" - output clock of the hdmi phy pll - optional
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3328-cru
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
"#reset-cells":
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
const: xin24m
|
||||
|
||||
rockchip,grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to the syscon managing the "general register files" (GRF),
|
||||
if missing pll rates are not changeable, due to the missing pll
|
||||
lock status.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#clock-cells"
|
||||
- "#reset-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
cru: clock-controller@ff440000 {
|
||||
compatible = "rockchip,rk3328-cru";
|
||||
reg = <0xff440000 0x1000>;
|
||||
rockchip,grf = <&grf>;
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
@ -16,8 +16,8 @@ merged to this clock. The component clocks shall be of one of the
|
||||
"ti,*composite*-clock" types.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/ti/mux.txt
|
||||
[3] Documentation/devicetree/bindings/clock/ti/divider.txt
|
||||
[2] Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml
|
||||
[3] Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml
|
||||
[4] Documentation/devicetree/bindings/clock/ti/gate.txt
|
||||
|
||||
Required properties:
|
||||
|
@ -1,115 +0,0 @@
|
||||
Binding for TI divider clock
|
||||
|
||||
This binding uses the common clock binding[1]. It assumes a
|
||||
register-mapped adjustable clock rate divider that does not gate and has
|
||||
only one input clock or parent. By default the value programmed into
|
||||
the register is one less than the actual divisor value. E.g:
|
||||
|
||||
register value actual divisor value
|
||||
0 1
|
||||
1 2
|
||||
2 3
|
||||
|
||||
This assumption may be modified by the following optional properties:
|
||||
|
||||
ti,index-starts-at-one - valid divisor values start at 1, not the default
|
||||
of 0. E.g:
|
||||
register value actual divisor value
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
ti,index-power-of-two - valid divisor values are powers of two. E.g:
|
||||
register value actual divisor value
|
||||
0 1
|
||||
1 2
|
||||
2 4
|
||||
|
||||
Additionally an array of valid dividers may be supplied like so:
|
||||
|
||||
ti,dividers = <4>, <8>, <0>, <16>;
|
||||
|
||||
Which will map the resulting values to a divisor table by their index:
|
||||
register value actual divisor value
|
||||
0 4
|
||||
1 8
|
||||
2 <invalid divisor, skipped>
|
||||
3 16
|
||||
|
||||
Any zero value in this array means the corresponding bit-value is invalid
|
||||
and must not be used.
|
||||
|
||||
The binding must also provide the register to control the divider and
|
||||
unless the divider array is provided, min and max dividers. Optionally
|
||||
the number of bits to shift that mask, if necessary. If the shift value
|
||||
is missing it is the same as supplying a zero shift.
|
||||
|
||||
This binding can also optionally provide support to the hardware autoidle
|
||||
feature, see [2].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock".
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
- clocks : link to phandle of parent clock
|
||||
- reg : offset for register controlling adjustable divider
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : from common clock binding.
|
||||
- ti,dividers : array of integers defining divisors
|
||||
- ti,bit-shift : number of bits to shift the divider value, defaults to 0
|
||||
- ti,min-div : min divisor for dividing the input clock rate, only
|
||||
needed if the first divisor is offset from the default value (1)
|
||||
- ti,max-div : max divisor for dividing the input clock rate, only needed
|
||||
if ti,dividers is not defined.
|
||||
- ti,index-starts-at-one : valid divisor programming starts at 1, not zero,
|
||||
only valid if ti,dividers is not defined.
|
||||
- ti,index-power-of-two : valid divisor programming must be a power of two,
|
||||
only valid if ti,dividers is not defined.
|
||||
- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock,
|
||||
see [2]
|
||||
- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0,
|
||||
see [2]
|
||||
- ti,set-rate-parent : clk_set_rate is propagated to parent
|
||||
- ti,latch-bit : latch the divider value to HW, only needed if the register
|
||||
access requires this. As an example dra76x DPLL_GMAC H14 divider implements
|
||||
such behavior.
|
||||
|
||||
Examples:
|
||||
dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
clocks = <&dpll_usb_ck>;
|
||||
ti,max-div = <127>;
|
||||
reg = <0x190>;
|
||||
ti,index-starts-at-one;
|
||||
};
|
||||
|
||||
aess_fclk: aess_fclk@4a004528 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
clocks = <&abe_clk>;
|
||||
ti,bit-shift = <24>;
|
||||
reg = <0x528>;
|
||||
ti,max-div = <2>;
|
||||
};
|
||||
|
||||
dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,composite-divider-clock";
|
||||
clocks = <&dpll_core_x2_ck>;
|
||||
ti,max-div = <31>;
|
||||
reg = <0x0134>;
|
||||
ti,index-starts-at-one;
|
||||
};
|
||||
|
||||
ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,composite-divider-clock";
|
||||
clocks = <&corex2_fck>;
|
||||
ti,bit-shift = <8>;
|
||||
reg = <0x0a40>;
|
||||
ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
|
||||
};
|
@ -1,55 +0,0 @@
|
||||
Binding for Texas Instruments interface clock.
|
||||
|
||||
This binding uses the common clock binding[1]. This clock is
|
||||
quite much similar to the basic gate-clock [2], however,
|
||||
it supports a number of additional features, including
|
||||
companion clock finding (match corresponding functional gate
|
||||
clock) and hardware autoidle enable / disable.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
[2] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be one of:
|
||||
"ti,omap3-interface-clock" - basic OMAP3 interface clock
|
||||
"ti,omap3-no-wait-interface-clock" - interface clock which has no hardware
|
||||
capability for waiting clock to be ready
|
||||
"ti,omap3-hsotgusb-interface-clock" - interface clock with USB specific HW
|
||||
handling
|
||||
"ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling
|
||||
"ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling
|
||||
"ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling
|
||||
"ti,omap2430-interface-clock" - interface clock with OMAP2430 specific HW
|
||||
handling
|
||||
- #clock-cells : from common clock binding; shall be set to 0
|
||||
- clocks : link to phandle of parent clock
|
||||
- reg : base address for the control register
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : from common clock binding.
|
||||
- ti,bit-shift : bit shift for the bit enabling/disabling the clock (default 0)
|
||||
|
||||
Examples:
|
||||
aes1_ick: aes1_ick@48004a14 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,omap3-interface-clock";
|
||||
clocks = <&security_l4_ick2>;
|
||||
reg = <0x48004a14 0x4>;
|
||||
ti,bit-shift = <3>;
|
||||
};
|
||||
|
||||
cam_ick: cam_ick@48004f10 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,omap3-no-wait-interface-clock";
|
||||
clocks = <&l4_ick>;
|
||||
reg = <0x48004f10 0x4>;
|
||||
ti,bit-shift = <0>;
|
||||
};
|
||||
|
||||
ssi_ick_3430es2: ssi_ick_3430es2@48004a10 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,omap3-ssi-interface-clock";
|
||||
clocks = <&ssi_l4_ick>;
|
||||
reg = <0x48004a10 0x4>;
|
||||
ti,bit-shift = <0>;
|
||||
};
|
@ -1,78 +0,0 @@
|
||||
Binding for TI mux clock.
|
||||
|
||||
This binding uses the common clock binding[1]. It assumes a
|
||||
register-mapped multiplexer with multiple input clock signals or
|
||||
parents, one of which can be selected as output. This clock does not
|
||||
gate or adjust the parent rate via a divider or multiplier.
|
||||
|
||||
By default the "clocks" property lists the parents in the same order
|
||||
as they are programmed into the register. E.g:
|
||||
|
||||
clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
|
||||
|
||||
results in programming the register as follows:
|
||||
|
||||
register value selected parent clock
|
||||
0 foo_clock
|
||||
1 bar_clock
|
||||
2 baz_clock
|
||||
|
||||
Some clock controller IPs do not allow a value of zero to be programmed
|
||||
into the register, instead indexing begins at 1. The optional property
|
||||
"index-starts-at-one" modified the scheme as follows:
|
||||
|
||||
register value selected clock parent
|
||||
1 foo_clock
|
||||
2 bar_clock
|
||||
3 baz_clock
|
||||
|
||||
The binding must provide the register to control the mux. Optionally
|
||||
the number of bits to shift the control field in the register can be
|
||||
supplied. If the shift value is missing it is the same as supplying
|
||||
a zero shift.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock".
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
- clocks : link phandles of parent clocks
|
||||
- reg : register offset for register controlling adjustable mux
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : from common clock binding.
|
||||
- ti,bit-shift : number of bits to shift the bit-mask, defaults to
|
||||
0 if not present
|
||||
- ti,index-starts-at-one : valid input select programming starts at 1, not
|
||||
zero
|
||||
- ti,set-rate-parent : clk_set_rate is propagated to parent clock,
|
||||
not supported by the composite-mux-clock subtype
|
||||
- ti,latch-bit : latch the mux value to HW, only needed if the register
|
||||
access requires this. As an example, dra7x DPLL_GMAC H14 muxing
|
||||
implements such behavior.
|
||||
|
||||
Examples:
|
||||
|
||||
sys_clkin_ck: sys_clkin_ck@4a306110 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,mux-clock";
|
||||
clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
|
||||
reg = <0x0110>;
|
||||
ti,index-starts-at-one;
|
||||
};
|
||||
|
||||
abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,mux-clock";
|
||||
clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
|
||||
ti,bit-shift = <24>;
|
||||
reg = <0x0108>;
|
||||
};
|
||||
|
||||
mcbsp5_mux_fck: mcbsp5_mux_fck {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,composite-mux-clock";
|
||||
clocks = <&core_96m_fck>, <&mcbsp_clks>;
|
||||
ti,bit-shift = <4>;
|
||||
reg = <0x02d8>;
|
||||
};
|
193
Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml
Normal file
193
Documentation/devicetree/bindings/clock/ti/ti,divider-clock.yaml
Normal file
@ -0,0 +1,193 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/ti/ti,divider-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments divider clock
|
||||
|
||||
maintainers:
|
||||
- Tero Kristo <kristo@kernel.org>
|
||||
|
||||
description: |
|
||||
This clock It assumes a register-mapped adjustable clock rate divider
|
||||
that does not gate and has only one input clock or parent. By default the
|
||||
value programmed into the register is one less than the actual divisor value.
|
||||
E.g:
|
||||
|
||||
register value actual divisor value
|
||||
0 1
|
||||
1 2
|
||||
2 3
|
||||
|
||||
This assumption may be modified by the following optional properties:
|
||||
|
||||
ti,index-starts-at-one - valid divisor values start at 1, not the default
|
||||
of 0. E.g:
|
||||
register value actual divisor value
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
|
||||
ti,index-power-of-two - valid divisor values are powers of two. E.g:
|
||||
register value actual divisor value
|
||||
0 1
|
||||
1 2
|
||||
2 4
|
||||
|
||||
Additionally an array of valid dividers may be supplied like so:
|
||||
|
||||
ti,dividers = <4>, <8>, <0>, <16>;
|
||||
|
||||
Which will map the resulting values to a divisor table by their index:
|
||||
register value actual divisor value
|
||||
0 4
|
||||
1 8
|
||||
2 <invalid divisor, skipped>
|
||||
3 16
|
||||
|
||||
Any zero value in this array means the corresponding bit-value is invalid
|
||||
and must not be used.
|
||||
|
||||
The binding must also provide the register to control the divider and
|
||||
unless the divider array is provided, min and max dividers. Optionally
|
||||
the number of bits to shift that mask, if necessary. If the shift value
|
||||
is missing it is the same as supplying a zero shift.
|
||||
|
||||
This binding can also optionally provide support to the hardware autoidle
|
||||
feature, see [1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/ti/autoidle.txt
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,divider-clock
|
||||
- ti,composite-divider-clock
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ti,dividers:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-array
|
||||
description:
|
||||
array of integers defining divisors
|
||||
|
||||
ti,bit-shift:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
number of bits to shift the divider value
|
||||
maximum: 31
|
||||
default: 0
|
||||
|
||||
ti,min-div:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
min divisor for dividing the input clock rate, only
|
||||
needed if the first divisor is offset from the default value (1)
|
||||
minimum: 1
|
||||
default: 1
|
||||
|
||||
|
||||
ti,max-div:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
max divisor for dividing the input clock rate, only needed
|
||||
if ti,dividers is not defined.
|
||||
|
||||
ti,index-starts-at-one:
|
||||
type: boolean
|
||||
description:
|
||||
valid divisor programming starts at 1, not zero,
|
||||
only valid if ti,dividers is not defined
|
||||
|
||||
ti,index-power-of-two:
|
||||
type: boolean
|
||||
description:
|
||||
valid divisor programming must be a power of two,
|
||||
only valid if ti,dividers is not defined.
|
||||
|
||||
ti,autoidle-shift:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
bit shift of the autoidle enable bit for the clock,
|
||||
see [1].
|
||||
maximum: 31
|
||||
default: 0
|
||||
|
||||
ti,invert-autoidle-bit:
|
||||
type: boolean
|
||||
description:
|
||||
autoidle is enabled by setting the bit to 0,
|
||||
see [1]
|
||||
|
||||
ti,set-rate-parent:
|
||||
type: boolean
|
||||
description:
|
||||
clk_set_rate is propagated to parent |
|
||||
|
||||
ti,latch-bit:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
latch the divider value to HW, only needed if the register
|
||||
compatible access requires this. As an example dra76x DPLL_GMAC
|
||||
H14 divider implements such behavior.
|
||||
|
||||
dependentSchemas:
|
||||
ti,dividers:
|
||||
properties:
|
||||
ti,min-div: false
|
||||
ti,max-div: false
|
||||
ti,index-power-of-two: false
|
||||
ti,index-starts-at-one: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clock-controller@190 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
clocks = <&dpll_usb_ck>;
|
||||
ti,max-div = <127>;
|
||||
reg = <0x190>;
|
||||
ti,index-starts-at-one;
|
||||
};
|
||||
|
||||
clock-controller@528 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,divider-clock";
|
||||
clocks = <&abe_clk>;
|
||||
ti,bit-shift = <24>;
|
||||
reg = <0x528>;
|
||||
ti,max-div = <2>;
|
||||
};
|
||||
|
||||
clock-controller@a40 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,composite-divider-clock";
|
||||
clocks = <&corex2_fck>;
|
||||
ti,bit-shift = <8>;
|
||||
reg = <0x0a40>;
|
||||
ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
|
||||
};
|
||||
};
|
@ -0,0 +1,71 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/ti/ti,interface-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments interface clock.
|
||||
|
||||
maintainers:
|
||||
- Tero Kristo <kristo@kernel.org>
|
||||
|
||||
description: |
|
||||
This clock is quite much similar to the basic gate-clock[1], however,
|
||||
it supports a number of additional features, including
|
||||
companion clock finding (match corresponding functional gate
|
||||
clock) and hardware autoidle enable / disable.
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/gpio-gate-clock.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,omap3-interface-clock # basic OMAP3 interface clock
|
||||
- ti,omap3-no-wait-interface-clock # interface clock which has no hardware
|
||||
# capability for waiting clock to be ready
|
||||
- ti,omap3-hsotgusb-interface-clock # interface clock with USB specific HW handling
|
||||
- ti,omap3-dss-interface-clock # interface clock with DSS specific HW handling
|
||||
- ti,omap3-ssi-interface-clock # interface clock with SSI specific HW handling
|
||||
- ti,am35xx-interface-clock # interface clock with AM35xx specific HW handling
|
||||
- ti,omap2430-interface-clock # interface clock with OMAP2430 specific HW handling
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ti,bit-shift:
|
||||
description:
|
||||
bit shift for the bit enabling/disabling the clock
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
default: 0
|
||||
maximum: 31
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- '#clock-cells'
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
aes1_ick: clock-controller@3 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "ti,omap3-interface-clock";
|
||||
clocks = <&security_l4_ick2>;
|
||||
reg = <3>;
|
||||
};
|
||||
};
|
125
Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml
Normal file
125
Documentation/devicetree/bindings/clock/ti/ti,mux-clock.yaml
Normal file
@ -0,0 +1,125 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/clock/ti/ti,mux-clock.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments mux clock
|
||||
|
||||
maintainers:
|
||||
- Tero Kristo <kristo@kernel.org>
|
||||
|
||||
description: |
|
||||
This clock assumes a register-mapped multiplexer with multiple inpt clock
|
||||
signals or parents, one of which can be selected as output. This clock does
|
||||
not gate or adjust the parent rate via a divider or multiplier.
|
||||
|
||||
By default the "clocks" property lists the parents in the same order
|
||||
as they are programmed into the register. E.g:
|
||||
|
||||
clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
|
||||
|
||||
Results in programming the register as follows:
|
||||
|
||||
register value selected parent clock
|
||||
0 foo_clock
|
||||
1 bar_clock
|
||||
2 baz_clock
|
||||
|
||||
Some clock controller IPs do not allow a value of zero to be programmed
|
||||
into the register, instead indexing begins at 1. The optional property
|
||||
"index-starts-at-one" modified the scheme as follows:
|
||||
|
||||
register value selected clock parent
|
||||
1 foo_clock
|
||||
2 bar_clock
|
||||
3 baz_clock
|
||||
|
||||
The binding must provide the register to control the mux. Optionally
|
||||
the number of bits to shift the control field in the register can be
|
||||
supplied. If the shift value is missing it is the same as supplying
|
||||
a zero shift.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- ti,mux-clock
|
||||
- ti,composite-mux-clock
|
||||
|
||||
"#clock-cells":
|
||||
const: 0
|
||||
|
||||
clocks: true
|
||||
|
||||
clock-output-names:
|
||||
maxItems: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
ti,bit-shift:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Number of bits to shift the bit-mask
|
||||
maximum: 31
|
||||
default: 0
|
||||
|
||||
ti,index-starts-at-one:
|
||||
type: boolean
|
||||
description:
|
||||
Valid input select programming starts at 1, not zero
|
||||
|
||||
ti,set-rate-parent:
|
||||
type: boolean
|
||||
description:
|
||||
clk_set_rate is propagated to parent clock,
|
||||
not supported by the composite-mux-clock subtype.
|
||||
|
||||
ti,latch-bit:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Latch the mux value to HW, only needed if the register
|
||||
access requires this. As an example, dra7x DPLL_GMAC H14 muxing
|
||||
implements such behavior.
|
||||
maximum: 31
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: ti,composite-mux-clock
|
||||
then:
|
||||
properties:
|
||||
ti,set-rate-parent: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
- reg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
bus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
clock-controller@110 {
|
||||
compatible = "ti,mux-clock";
|
||||
reg = <0x0110>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>;
|
||||
ti,index-starts-at-one;
|
||||
ti,set-rate-parent;
|
||||
};
|
||||
|
||||
clock-controller@120 {
|
||||
compatible = "ti,composite-mux-clock";
|
||||
reg = <0x0120>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&core_96m_fck>, <&mcbsp_clks>;
|
||||
ti,bit-shift = <4>;
|
||||
};
|
||||
};
|
@ -39,6 +39,11 @@ properties:
|
||||
- const: clk_in1
|
||||
- const: s_axi_aclk
|
||||
|
||||
xlnx,static-config:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Indicate whether the core has been configured without support for dynamic
|
||||
runtime reconfguration of the clocking primitive MMCM/PLL.
|
||||
|
||||
xlnx,speed-grade:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
@ -70,6 +75,7 @@ examples:
|
||||
compatible = "xlnx,clocking-wizard";
|
||||
reg = <0xb0000000 0x10000>;
|
||||
#clock-cells = <1>;
|
||||
xlnx,static-config;
|
||||
xlnx,speed-grade = <1>;
|
||||
xlnx,nr-outputs = <6>;
|
||||
clock-names = "clk_in1", "s_axi_aclk";
|
||||
|
@ -21,6 +21,13 @@ properties:
|
||||
'#reset-cells':
|
||||
const: 2
|
||||
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: specify external 25MHz reference clock.
|
||||
|
||||
nuvoton,sysgcr:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description: a phandle to access GCR registers.
|
||||
@ -39,6 +46,17 @@ required:
|
||||
- '#reset-cells'
|
||||
- nuvoton,sysgcr
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- nuvoton,npcm845-reset
|
||||
then:
|
||||
required:
|
||||
- '#clock-cells'
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -41,9 +41,7 @@ properties:
|
||||
enum: [ 1, 2 ]
|
||||
|
||||
'#clock-cells':
|
||||
description:
|
||||
Cell is clock index. Optional if compatible has a single clock.
|
||||
enum: [ 0, 1 ]
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
@ -312,26 +310,6 @@ allOf:
|
||||
properties:
|
||||
'#reset-cells': false
|
||||
|
||||
# Compatibles exposing a single clock.
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mobileye,eyeq6h-central-olb
|
||||
- mobileye,eyeq6h-east-olb
|
||||
- mobileye,eyeq6h-west-olb
|
||||
- mobileye,eyeq6h-ddr0-olb
|
||||
- mobileye,eyeq6h-ddr1-olb
|
||||
then:
|
||||
properties:
|
||||
'#clock-cells':
|
||||
const: 0
|
||||
else:
|
||||
properties:
|
||||
'#clock-cells':
|
||||
const: 1
|
||||
|
||||
# Only EyeQ5 has pinctrl in OLB.
|
||||
- if:
|
||||
not:
|
||||
|
28
MAINTAINERS
28
MAINTAINERS
@ -2006,7 +2006,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
L: linux-actions@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/arm/actions.yaml
|
||||
F: Documentation/devicetree/bindings/clock/actions,owl-cmu.txt
|
||||
F: Documentation/devicetree/bindings/clock/actions,owl-cmu.yaml
|
||||
F: Documentation/devicetree/bindings/dma/owl-dma.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-owl.yaml
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
|
||||
@ -14570,6 +14570,32 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/mmc/mtk-sd.yaml
|
||||
F: drivers/mmc/host/mtk-sd.c
|
||||
|
||||
MEDIATEK MT6735 CLOCK & RESET DRIVERS
|
||||
M: Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
L: linux-clk@vger.kernel.org
|
||||
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: drivers/clk/mediatek/clk-mt6735-apmixedsys.c
|
||||
F: drivers/clk/mediatek/clk-mt6735-imgsys.c
|
||||
F: drivers/clk/mediatek/clk-mt6735-infracfg.c
|
||||
F: drivers/clk/mediatek/clk-mt6735-mfgcfg.c
|
||||
F: drivers/clk/mediatek/clk-mt6735-pericfg.c
|
||||
F: drivers/clk/mediatek/clk-mt6735-topckgen.c
|
||||
F: drivers/clk/mediatek/clk-mt6735-vdecsys.c
|
||||
F: drivers/clk/mediatek/clk-mt6735-vencsys.c
|
||||
F: include/dt-bindings/clock/mediatek,mt6735-apmixedsys.h
|
||||
F: include/dt-bindings/clock/mediatek,mt6735-imgsys.h
|
||||
F: include/dt-bindings/clock/mediatek,mt6735-infracfg.h
|
||||
F: include/dt-bindings/clock/mediatek,mt6735-mfgcfg.h
|
||||
F: include/dt-bindings/clock/mediatek,mt6735-pericfg.h
|
||||
F: include/dt-bindings/clock/mediatek,mt6735-topckgen.h
|
||||
F: include/dt-bindings/clock/mediatek,mt6735-vdecsys.h
|
||||
F: include/dt-bindings/clock/mediatek,mt6735-vencsys.h
|
||||
F: include/dt-bindings/reset/mediatek,mt6735-infracfg.h
|
||||
F: include/dt-bindings/reset/mediatek,mt6735-mfgcfg.h
|
||||
F: include/dt-bindings/reset/mediatek,mt6735-pericfg.h
|
||||
F: include/dt-bindings/reset/mediatek,mt6735-vdecsys.h
|
||||
|
||||
MEDIATEK MT76 WIRELESS LAN DRIVER
|
||||
M: Felix Fietkau <nbd@nbd.name>
|
||||
M: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
|
@ -1,5 +1,6 @@
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_OVERLAY=y
|
||||
CONFIG_COMMON_CLK=y
|
||||
CONFIG_CLK_KUNIT_TEST=y
|
||||
CONFIG_CLK_FIXED_RATE_KUNIT_TEST=y
|
||||
|
@ -226,6 +226,17 @@ config COMMON_CLK_EP93XX
|
||||
help
|
||||
This driver supports the SoC clocks on the Cirrus Logic ep93xx.
|
||||
|
||||
config COMMON_CLK_EYEQ
|
||||
bool "Clock driver for the Mobileye EyeQ platform"
|
||||
depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST
|
||||
select AUXILIARY_BUS
|
||||
default MACH_EYEQ5 || MACH_EYEQ6H
|
||||
help
|
||||
This driver provides clocks found on Mobileye EyeQ5, EyeQ6L and Eye6H
|
||||
SoCs. Controllers live in shared register regions called OLB. Driver
|
||||
provides read-only PLLs, derived from the main crystal clock (which
|
||||
must be constant). It also exposes some divider clocks.
|
||||
|
||||
config COMMON_CLK_FSL_FLEXSPI
|
||||
tristate "Clock driver for FlexSPI on Layerscape SoCs"
|
||||
depends on ARCH_LAYERSCAPE || COMPILE_TEST
|
||||
@ -259,7 +270,7 @@ config COMMON_CLK_LAN966X
|
||||
tristate "Generic Clock Controller driver for LAN966X SoC"
|
||||
depends on HAS_IOMEM
|
||||
depends on OF
|
||||
depends on SOC_LAN966 || COMPILE_TEST
|
||||
depends on SOC_LAN966 || ARCH_LAN969X || COMPILE_TEST
|
||||
help
|
||||
This driver provides support for Generic Clock Controller(GCK) on
|
||||
LAN966X SoC. GCK generates and supplies clock to various peripherals
|
||||
@ -291,7 +302,7 @@ config CLK_TWL
|
||||
help
|
||||
Enable support for controlling the clock resources on TWL family
|
||||
PMICs. These devices have some 32K clock outputs which can be
|
||||
controlled by software. For now, only the TWL6032 clocks are
|
||||
controlled by software. For now, the TWL6032 and TWL6030 clocks are
|
||||
supported.
|
||||
|
||||
config CLK_TWL6040
|
||||
@ -342,6 +353,14 @@ config COMMON_CLK_LOCHNAGAR
|
||||
This driver supports the clocking features of the Cirrus Logic
|
||||
Lochnagar audio development board.
|
||||
|
||||
config COMMON_CLK_NPCM8XX
|
||||
tristate "Clock driver for the NPCM8XX SoC Family"
|
||||
depends on ARCH_NPCM || COMPILE_TEST
|
||||
help
|
||||
This driver supports the clocks on the Nuvoton BMC NPCM8XX SoC Family,
|
||||
all the clocks are initialized by the bootloader, so this driver
|
||||
allows only reading of current settings directly from the hardware.
|
||||
|
||||
config COMMON_CLK_LOONGSON2
|
||||
bool "Clock driver for Loongson-2 SoC"
|
||||
depends on LOONGARCH || COMPILE_TEST
|
||||
@ -517,7 +536,6 @@ 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.
|
||||
@ -526,7 +544,6 @@ 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.
|
||||
|
@ -4,6 +4,20 @@ 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
|
||||
clk-test-y := clk_test.o \
|
||||
kunit_clk_assigned_rates_u64_one.dtbo.o \
|
||||
kunit_clk_assigned_rates_u64_one_consumer.dtbo.o \
|
||||
kunit_clk_assigned_rates_u64_multiple.dtbo.o \
|
||||
kunit_clk_assigned_rates_u64_multiple_consumer.dtbo.o \
|
||||
kunit_clk_assigned_rates_multiple.dtbo.o \
|
||||
kunit_clk_assigned_rates_multiple_consumer.dtbo.o \
|
||||
kunit_clk_assigned_rates_null.dtbo.o \
|
||||
kunit_clk_assigned_rates_null_consumer.dtbo.o \
|
||||
kunit_clk_assigned_rates_one.dtbo.o \
|
||||
kunit_clk_assigned_rates_one_consumer.dtbo.o \
|
||||
kunit_clk_assigned_rates_without.dtbo.o \
|
||||
kunit_clk_assigned_rates_without_consumer.dtbo.o \
|
||||
kunit_clk_assigned_rates_zero.dtbo.o \
|
||||
kunit_clk_assigned_rates_zero_consumer.dtbo.o \
|
||||
kunit_clk_parent_data_test.dtbo.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-divider.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
|
||||
@ -42,6 +56,7 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
|
||||
obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
|
||||
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
|
||||
obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
|
||||
obj-$(CONFIG_COMMON_CLK_EYEQ) += clk-eyeq.o
|
||||
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
|
||||
obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) += clk-fsl-flexspi.o
|
||||
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
|
||||
@ -62,6 +77,7 @@ obj-$(CONFIG_ARCH_MILBEAUT_M10V) += clk-milbeaut.o
|
||||
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
|
||||
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
|
||||
obj-$(CONFIG_ARCH_NPCM7XX) += clk-npcm7xx.o
|
||||
obj-$(CONFIG_COMMON_CLK_NPCM8XX) += clk-npcm8xx.o
|
||||
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
|
||||
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
|
||||
obj-$(CONFIG_CLK_LS1028A_PLLDIG) += clk-plldig.o
|
||||
|
@ -297,6 +297,9 @@ static int applnco_probe(struct platform_device *pdev)
|
||||
memset(&init, 0, sizeof(init));
|
||||
init.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||
"%s-%d", np->name, i);
|
||||
if (!init.name)
|
||||
return -ENOMEM;
|
||||
|
||||
init.ops = &applnco_ops;
|
||||
init.parent_data = &pdata;
|
||||
init.num_parents = 1;
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
@ -512,6 +513,7 @@ static int axi_clkgen_probe(struct platform_device *pdev)
|
||||
struct clk_init_data init;
|
||||
const char *parent_names[2];
|
||||
const char *clk_name;
|
||||
struct clk *axi_clk;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
@ -528,8 +530,24 @@ static int axi_clkgen_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(axi_clkgen->base);
|
||||
|
||||
init.num_parents = of_clk_get_parent_count(pdev->dev.of_node);
|
||||
if (init.num_parents < 1 || init.num_parents > 2)
|
||||
return -EINVAL;
|
||||
|
||||
axi_clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk");
|
||||
if (!IS_ERR(axi_clk)) {
|
||||
if (init.num_parents < 2 || init.num_parents > 3)
|
||||
return -EINVAL;
|
||||
|
||||
init.num_parents -= 1;
|
||||
} else {
|
||||
/*
|
||||
* Legacy... So that old DTs which do not have clock-names still
|
||||
* work. In this case we don't explicitly enable the AXI bus
|
||||
* clock.
|
||||
*/
|
||||
if (PTR_ERR(axi_clk) != -ENOENT)
|
||||
return PTR_ERR(axi_clk);
|
||||
if (init.num_parents < 1 || init.num_parents > 2)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < init.num_parents; i++) {
|
||||
parent_names[i] = of_clk_get_parent_name(pdev->dev.of_node, i);
|
||||
|
@ -678,7 +678,7 @@ MODULE_DEVICE_TABLE(of, cdce706_dt_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id cdce706_id[] = {
|
||||
{ "cdce706", 0 },
|
||||
{ "cdce706" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cdce706_id);
|
||||
|
@ -601,7 +601,7 @@ static int cdce925_regulator_enable(struct device *dev, const char *name)
|
||||
|
||||
/* The CDCE925 uses a funky way to read/write registers. Bulk mode is
|
||||
* just weird, so just use the single byte mode exclusively. */
|
||||
static struct regmap_bus regmap_cdce925_bus = {
|
||||
static const struct regmap_bus regmap_cdce925_bus = {
|
||||
.write = cdce925_regmap_i2c_write,
|
||||
.read = cdce925_regmap_i2c_read,
|
||||
};
|
||||
|
@ -218,8 +218,8 @@ static void devm_clk_bulk_release_all_enable(struct device *dev, void *res)
|
||||
clk_bulk_put_all(devres->num_clks, devres->clks);
|
||||
}
|
||||
|
||||
int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
|
||||
struct clk_bulk_data **clks)
|
||||
int __must_check devm_clk_bulk_get_all_enabled(struct device *dev,
|
||||
struct clk_bulk_data **clks)
|
||||
{
|
||||
struct clk_bulk_devres *devres;
|
||||
int ret;
|
||||
@ -244,11 +244,12 @@ int __must_check devm_clk_bulk_get_all_enable(struct device *dev,
|
||||
} else {
|
||||
clk_bulk_put_all(devres->num_clks, devres->clks);
|
||||
devres_free(devres);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return devres->num_clks;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enable);
|
||||
EXPORT_SYMBOL_GPL(devm_clk_bulk_get_all_enabled);
|
||||
|
||||
static int devm_clk_match(struct device *dev, void *res, void *data)
|
||||
{
|
||||
|
@ -72,6 +72,8 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
|
||||
return clk_div_mask(width);
|
||||
if (flags & CLK_DIVIDER_POWER_OF_TWO)
|
||||
return 1 << clk_div_mask(width);
|
||||
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
|
||||
return 2 * (clk_div_mask(width) + 1);
|
||||
if (table)
|
||||
return _get_table_maxdiv(table, width);
|
||||
return clk_div_mask(width) + 1;
|
||||
@ -97,6 +99,8 @@ static unsigned int _get_div(const struct clk_div_table *table,
|
||||
return 1 << val;
|
||||
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
||||
return val ? val : clk_div_mask(width) + 1;
|
||||
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
|
||||
return 2 * (val + 1);
|
||||
if (table)
|
||||
return _get_table_div(table, val);
|
||||
return val + 1;
|
||||
@ -122,6 +126,8 @@ static unsigned int _get_val(const struct clk_div_table *table,
|
||||
return __ffs(div);
|
||||
if (flags & CLK_DIVIDER_MAX_AT_ZERO)
|
||||
return (div == clk_div_mask(width) + 1) ? 0 : div;
|
||||
if (flags & CLK_DIVIDER_EVEN_INTEGERS)
|
||||
return (div >> 1) - 1;
|
||||
if (table)
|
||||
return _get_table_val(table, div);
|
||||
return div - 1;
|
||||
@ -538,7 +544,8 @@ struct clk_hw *__clk_hw_register_divider(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,
|
||||
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_divider *div;
|
||||
@ -610,8 +617,8 @@ EXPORT_SYMBOL_GPL(__clk_hw_register_divider);
|
||||
struct clk *clk_register_divider_table(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_divider_flags, const struct clk_div_table *table,
|
||||
spinlock_t *lock)
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
|
||||
@ -664,7 +671,8 @@ struct clk_hw *__devm_clk_hw_register_divider(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,
|
||||
void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
unsigned long clk_divider_flags,
|
||||
const struct clk_div_table *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_hw **ptr, *hw;
|
||||
|
@ -3,8 +3,10 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <dt-bindings/clock/en7523-clk.h>
|
||||
#include <dt-bindings/reset/airoha,en7581-reset.h>
|
||||
@ -31,19 +33,14 @@
|
||||
#define REG_RESET_CONTROL_PCIE1 BIT(27)
|
||||
#define REG_RESET_CONTROL_PCIE2 BIT(26)
|
||||
/* EN7581 */
|
||||
#define REG_PCIE0_MEM 0x00
|
||||
#define REG_PCIE0_MEM_MASK 0x04
|
||||
#define REG_PCIE1_MEM 0x08
|
||||
#define REG_PCIE1_MEM_MASK 0x0c
|
||||
#define REG_PCIE2_MEM 0x10
|
||||
#define REG_PCIE2_MEM_MASK 0x14
|
||||
#define REG_NP_SCU_PCIC 0x88
|
||||
#define REG_NP_SCU_SSTR 0x9c
|
||||
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
|
||||
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
|
||||
#define REG_CRYPTO_CLKSRC2 0x20c
|
||||
|
||||
#define REG_RST_CTRL2 0x00
|
||||
#define REG_RST_CTRL1 0x04
|
||||
#define REG_RST_CTRL2 0x830
|
||||
#define REG_RST_CTRL1 0x834
|
||||
|
||||
struct en_clk_desc {
|
||||
int id;
|
||||
@ -79,12 +76,8 @@ struct en_rst_data {
|
||||
|
||||
struct en_clk_soc_data {
|
||||
const struct clk_ops pcie_ops;
|
||||
struct {
|
||||
const u16 *bank_ofs;
|
||||
const u16 *idx_map;
|
||||
u16 idx_map_nr;
|
||||
} reset;
|
||||
int (*hw_init)(struct platform_device *pdev, void __iomem *np_base);
|
||||
int (*hw_init)(struct platform_device *pdev,
|
||||
struct clk_hw_onecell_data *clk_data);
|
||||
};
|
||||
|
||||
static const u32 gsw_base[] = { 400000000, 500000000 };
|
||||
@ -92,6 +85,10 @@ static const u32 emi_base[] = { 333000000, 400000000 };
|
||||
static const u32 bus_base[] = { 500000000, 540000000 };
|
||||
static const u32 slic_base[] = { 100000000, 3125000 };
|
||||
static const u32 npu_base[] = { 333000000, 400000000, 500000000 };
|
||||
/* EN7581 */
|
||||
static const u32 emi7581_base[] = { 540000000, 480000000, 400000000, 300000000 };
|
||||
static const u32 npu7581_base[] = { 800000000, 750000000, 720000000, 600000000 };
|
||||
static const u32 crypto_base[] = { 540000000, 480000000 };
|
||||
|
||||
static const struct en_clk_desc en7523_base_clks[] = {
|
||||
{
|
||||
@ -189,6 +186,102 @@ static const struct en_clk_desc en7523_base_clks[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct en_clk_desc en7581_base_clks[] = {
|
||||
{
|
||||
.id = EN7523_CLK_GSW,
|
||||
.name = "gsw",
|
||||
|
||||
.base_reg = REG_GSW_CLK_DIV_SEL,
|
||||
.base_bits = 1,
|
||||
.base_shift = 8,
|
||||
.base_values = gsw_base,
|
||||
.n_base_values = ARRAY_SIZE(gsw_base),
|
||||
|
||||
.div_bits = 3,
|
||||
.div_shift = 0,
|
||||
.div_step = 1,
|
||||
.div_offset = 1,
|
||||
}, {
|
||||
.id = EN7523_CLK_EMI,
|
||||
.name = "emi",
|
||||
|
||||
.base_reg = REG_EMI_CLK_DIV_SEL,
|
||||
.base_bits = 2,
|
||||
.base_shift = 8,
|
||||
.base_values = emi7581_base,
|
||||
.n_base_values = ARRAY_SIZE(emi7581_base),
|
||||
|
||||
.div_bits = 3,
|
||||
.div_shift = 0,
|
||||
.div_step = 1,
|
||||
.div_offset = 1,
|
||||
}, {
|
||||
.id = EN7523_CLK_BUS,
|
||||
.name = "bus",
|
||||
|
||||
.base_reg = REG_BUS_CLK_DIV_SEL,
|
||||
.base_bits = 1,
|
||||
.base_shift = 8,
|
||||
.base_values = bus_base,
|
||||
.n_base_values = ARRAY_SIZE(bus_base),
|
||||
|
||||
.div_bits = 3,
|
||||
.div_shift = 0,
|
||||
.div_step = 1,
|
||||
.div_offset = 1,
|
||||
}, {
|
||||
.id = EN7523_CLK_SLIC,
|
||||
.name = "slic",
|
||||
|
||||
.base_reg = REG_SPI_CLK_FREQ_SEL,
|
||||
.base_bits = 1,
|
||||
.base_shift = 0,
|
||||
.base_values = slic_base,
|
||||
.n_base_values = ARRAY_SIZE(slic_base),
|
||||
|
||||
.div_reg = REG_SPI_CLK_DIV_SEL,
|
||||
.div_bits = 5,
|
||||
.div_shift = 24,
|
||||
.div_val0 = 20,
|
||||
.div_step = 2,
|
||||
}, {
|
||||
.id = EN7523_CLK_SPI,
|
||||
.name = "spi",
|
||||
|
||||
.base_reg = REG_SPI_CLK_DIV_SEL,
|
||||
|
||||
.base_value = 400000000,
|
||||
|
||||
.div_bits = 5,
|
||||
.div_shift = 8,
|
||||
.div_val0 = 40,
|
||||
.div_step = 2,
|
||||
}, {
|
||||
.id = EN7523_CLK_NPU,
|
||||
.name = "npu",
|
||||
|
||||
.base_reg = REG_NPU_CLK_DIV_SEL,
|
||||
.base_bits = 2,
|
||||
.base_shift = 8,
|
||||
.base_values = npu7581_base,
|
||||
.n_base_values = ARRAY_SIZE(npu7581_base),
|
||||
|
||||
.div_bits = 3,
|
||||
.div_shift = 0,
|
||||
.div_step = 1,
|
||||
.div_offset = 1,
|
||||
}, {
|
||||
.id = EN7523_CLK_CRYPTO,
|
||||
.name = "crypto",
|
||||
|
||||
.base_reg = REG_CRYPTO_CLKSRC2,
|
||||
.base_bits = 1,
|
||||
.base_shift = 0,
|
||||
.base_values = crypto_base,
|
||||
.n_base_values = ARRAY_SIZE(crypto_base),
|
||||
}
|
||||
};
|
||||
|
||||
static const u16 en7581_rst_ofs[] = {
|
||||
REG_RST_CTRL2,
|
||||
REG_RST_CTRL1,
|
||||
@ -252,15 +345,11 @@ static const u16 en7581_rst_map[] = {
|
||||
[EN7581_XPON_MAC_RST] = RST_NR_PER_BANK + 31,
|
||||
};
|
||||
|
||||
static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
|
||||
static u32 en7523_get_base_rate(const struct en_clk_desc *desc, u32 val)
|
||||
{
|
||||
const struct en_clk_desc *desc = &en7523_base_clks[i];
|
||||
u32 val;
|
||||
|
||||
if (!desc->base_bits)
|
||||
return desc->base_value;
|
||||
|
||||
val = readl(base + desc->base_reg);
|
||||
val >>= desc->base_shift;
|
||||
val &= (1 << desc->base_bits) - 1;
|
||||
|
||||
@ -270,16 +359,11 @@ static unsigned int en7523_get_base_rate(void __iomem *base, unsigned int i)
|
||||
return desc->base_values[val];
|
||||
}
|
||||
|
||||
static u32 en7523_get_div(void __iomem *base, int i)
|
||||
static u32 en7523_get_div(const struct en_clk_desc *desc, u32 val)
|
||||
{
|
||||
const struct en_clk_desc *desc = &en7523_base_clks[i];
|
||||
u32 reg, val;
|
||||
|
||||
if (!desc->div_bits)
|
||||
return 1;
|
||||
|
||||
reg = desc->div_reg ? desc->div_reg : desc->base_reg;
|
||||
val = readl(base + reg);
|
||||
val >>= desc->div_shift;
|
||||
val &= (1 << desc->div_bits) - 1;
|
||||
|
||||
@ -412,32 +496,6 @@ static void en7581_pci_disable(struct clk_hw *hw)
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
static int en7581_clk_hw_init(struct platform_device *pdev,
|
||||
void __iomem *np_base)
|
||||
{
|
||||
void __iomem *pb_base;
|
||||
u32 val;
|
||||
|
||||
pb_base = devm_platform_ioremap_resource(pdev, 3);
|
||||
if (IS_ERR(pb_base))
|
||||
return PTR_ERR(pb_base);
|
||||
|
||||
val = readl(np_base + REG_NP_SCU_SSTR);
|
||||
val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
|
||||
writel(val, np_base + REG_NP_SCU_SSTR);
|
||||
val = readl(np_base + REG_NP_SCU_PCIC);
|
||||
writel(val | 3, np_base + REG_NP_SCU_PCIC);
|
||||
|
||||
writel(0x20000000, pb_base + REG_PCIE0_MEM);
|
||||
writel(0xfc000000, pb_base + REG_PCIE0_MEM_MASK);
|
||||
writel(0x24000000, pb_base + REG_PCIE1_MEM);
|
||||
writel(0xfc000000, pb_base + REG_PCIE1_MEM_MASK);
|
||||
writel(0x28000000, pb_base + REG_PCIE2_MEM);
|
||||
writel(0xfc000000, pb_base + REG_PCIE2_MEM_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
|
||||
void __iomem *base, void __iomem *np_base)
|
||||
{
|
||||
@ -447,9 +505,12 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(en7523_base_clks); i++) {
|
||||
const struct en_clk_desc *desc = &en7523_base_clks[i];
|
||||
u32 reg = desc->div_reg ? desc->div_reg : desc->base_reg;
|
||||
u32 val = readl(base + desc->base_reg);
|
||||
|
||||
rate = en7523_get_base_rate(base, i);
|
||||
rate /= en7523_get_div(base, i);
|
||||
rate = en7523_get_base_rate(desc, val);
|
||||
val = readl(base + reg);
|
||||
rate /= en7523_get_div(desc, val);
|
||||
|
||||
hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
|
||||
if (IS_ERR(hw)) {
|
||||
@ -467,6 +528,68 @@ static void en7523_register_clocks(struct device *dev, struct clk_hw_onecell_dat
|
||||
clk_data->num = EN7523_NUM_CLOCKS;
|
||||
}
|
||||
|
||||
static int en7523_clk_hw_init(struct platform_device *pdev,
|
||||
struct clk_hw_onecell_data *clk_data)
|
||||
{
|
||||
void __iomem *base, *np_base;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
np_base = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(np_base))
|
||||
return PTR_ERR(np_base);
|
||||
|
||||
en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void en7581_register_clocks(struct device *dev, struct clk_hw_onecell_data *clk_data,
|
||||
struct regmap *map, void __iomem *base)
|
||||
{
|
||||
struct clk_hw *hw;
|
||||
u32 rate;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(en7581_base_clks); i++) {
|
||||
const struct en_clk_desc *desc = &en7581_base_clks[i];
|
||||
u32 val, reg = desc->div_reg ? desc->div_reg : desc->base_reg;
|
||||
int err;
|
||||
|
||||
err = regmap_read(map, desc->base_reg, &val);
|
||||
if (err) {
|
||||
pr_err("Failed reading fixed clk rate %s: %d\n",
|
||||
desc->name, err);
|
||||
continue;
|
||||
}
|
||||
rate = en7523_get_base_rate(desc, val);
|
||||
|
||||
err = regmap_read(map, reg, &val);
|
||||
if (err) {
|
||||
pr_err("Failed reading fixed clk div %s: %d\n",
|
||||
desc->name, err);
|
||||
continue;
|
||||
}
|
||||
rate /= en7523_get_div(desc, val);
|
||||
|
||||
hw = clk_hw_register_fixed_rate(dev, desc->name, NULL, 0, rate);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("Failed to register clk %s: %ld\n",
|
||||
desc->name, PTR_ERR(hw));
|
||||
continue;
|
||||
}
|
||||
|
||||
clk_data->hws[desc->id] = hw;
|
||||
}
|
||||
|
||||
hw = en7523_register_pcie_clk(dev, base);
|
||||
clk_data->hws[EN7523_CLK_PCIE] = hw;
|
||||
|
||||
clk_data->num = EN7523_NUM_CLOCKS;
|
||||
}
|
||||
|
||||
static int en7523_reset_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool assert)
|
||||
{
|
||||
@ -516,38 +639,27 @@ static int en7523_reset_xlate(struct reset_controller_dev *rcdev,
|
||||
return rst_data->idx_map[reset_spec->args[0]];
|
||||
}
|
||||
|
||||
static const struct reset_control_ops en7523_reset_ops = {
|
||||
static const struct reset_control_ops en7581_reset_ops = {
|
||||
.assert = en7523_reset_assert,
|
||||
.deassert = en7523_reset_deassert,
|
||||
.status = en7523_reset_status,
|
||||
};
|
||||
|
||||
static int en7523_reset_register(struct platform_device *pdev,
|
||||
const struct en_clk_soc_data *soc_data)
|
||||
static int en7581_reset_register(struct device *dev, void __iomem *base)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct en_rst_data *rst_data;
|
||||
void __iomem *base;
|
||||
|
||||
/* no reset lines available */
|
||||
if (!soc_data->reset.idx_map_nr)
|
||||
return 0;
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 2);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
rst_data = devm_kzalloc(dev, sizeof(*rst_data), GFP_KERNEL);
|
||||
if (!rst_data)
|
||||
return -ENOMEM;
|
||||
|
||||
rst_data->bank_ofs = soc_data->reset.bank_ofs;
|
||||
rst_data->idx_map = soc_data->reset.idx_map;
|
||||
rst_data->bank_ofs = en7581_rst_ofs;
|
||||
rst_data->idx_map = en7581_rst_map;
|
||||
rst_data->base = base;
|
||||
|
||||
rst_data->rcdev.nr_resets = soc_data->reset.idx_map_nr;
|
||||
rst_data->rcdev.nr_resets = ARRAY_SIZE(en7581_rst_map);
|
||||
rst_data->rcdev.of_xlate = en7523_reset_xlate;
|
||||
rst_data->rcdev.ops = &en7523_reset_ops;
|
||||
rst_data->rcdev.ops = &en7581_reset_ops;
|
||||
rst_data->rcdev.of_node = dev->of_node;
|
||||
rst_data->rcdev.of_reset_n_cells = 1;
|
||||
rst_data->rcdev.owner = THIS_MODULE;
|
||||
@ -556,28 +668,38 @@ static int en7523_reset_register(struct platform_device *pdev,
|
||||
return devm_reset_controller_register(dev, &rst_data->rcdev);
|
||||
}
|
||||
|
||||
static int en7523_clk_probe(struct platform_device *pdev)
|
||||
static int en7581_clk_hw_init(struct platform_device *pdev,
|
||||
struct clk_hw_onecell_data *clk_data)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
const struct en_clk_soc_data *soc_data;
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
void __iomem *base, *np_base;
|
||||
int r;
|
||||
struct regmap *map;
|
||||
void __iomem *base;
|
||||
u32 val;
|
||||
|
||||
map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
|
||||
if (IS_ERR(map))
|
||||
return PTR_ERR(map);
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
np_base = devm_platform_ioremap_resource(pdev, 1);
|
||||
if (IS_ERR(np_base))
|
||||
return PTR_ERR(np_base);
|
||||
en7581_register_clocks(&pdev->dev, clk_data, map, base);
|
||||
|
||||
soc_data = device_get_match_data(&pdev->dev);
|
||||
if (soc_data->hw_init) {
|
||||
r = soc_data->hw_init(pdev, np_base);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
val = readl(base + REG_NP_SCU_SSTR);
|
||||
val &= ~(REG_PCIE_XSI0_SEL_MASK | REG_PCIE_XSI1_SEL_MASK);
|
||||
writel(val, base + REG_NP_SCU_SSTR);
|
||||
val = readl(base + REG_NP_SCU_PCIC);
|
||||
writel(val | 3, base + REG_NP_SCU_PCIC);
|
||||
|
||||
return en7581_reset_register(&pdev->dev, base);
|
||||
}
|
||||
|
||||
static int en7523_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
const struct en_clk_soc_data *soc_data;
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
int r;
|
||||
|
||||
clk_data = devm_kzalloc(&pdev->dev,
|
||||
struct_size(clk_data, hws, EN7523_NUM_CLOCKS),
|
||||
@ -585,21 +707,12 @@ static int en7523_clk_probe(struct platform_device *pdev)
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
en7523_register_clocks(&pdev->dev, clk_data, base, np_base);
|
||||
|
||||
r = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
|
||||
soc_data = device_get_match_data(&pdev->dev);
|
||||
r = soc_data->hw_init(pdev, clk_data);
|
||||
if (r)
|
||||
return dev_err_probe(&pdev->dev, r, "Could not register clock provider: %s\n",
|
||||
pdev->name);
|
||||
return r;
|
||||
|
||||
r = en7523_reset_register(pdev, soc_data);
|
||||
if (r) {
|
||||
of_clk_del_provider(node);
|
||||
return dev_err_probe(&pdev->dev, r, "Could not register reset controller: %s\n",
|
||||
pdev->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
|
||||
}
|
||||
|
||||
static const struct en_clk_soc_data en7523_data = {
|
||||
@ -608,6 +721,7 @@ static const struct en_clk_soc_data en7523_data = {
|
||||
.prepare = en7523_pci_prepare,
|
||||
.unprepare = en7523_pci_unprepare,
|
||||
},
|
||||
.hw_init = en7523_clk_hw_init,
|
||||
};
|
||||
|
||||
static const struct en_clk_soc_data en7581_data = {
|
||||
@ -616,11 +730,6 @@ static const struct en_clk_soc_data en7581_data = {
|
||||
.enable = en7581_pci_enable,
|
||||
.disable = en7581_pci_disable,
|
||||
},
|
||||
.reset = {
|
||||
.bank_ofs = en7581_rst_ofs,
|
||||
.idx_map = en7581_rst_map,
|
||||
.idx_map_nr = ARRAY_SIZE(en7581_rst_map),
|
||||
},
|
||||
.hw_init = en7581_clk_hw_init,
|
||||
};
|
||||
|
||||
|
859
drivers/clk/clk-eyeq.c
Normal file
859
drivers/clk/clk-eyeq.c
Normal file
@ -0,0 +1,859 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* PLL clock driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms.
|
||||
*
|
||||
* This controller handles:
|
||||
* - Read-only PLLs, all derived from the same main crystal clock.
|
||||
* - It also exposes divider clocks, those are children to PLLs.
|
||||
* - Fixed factor clocks, children to PLLs.
|
||||
*
|
||||
* Parent clock is expected to be constant. This driver's registers live in a
|
||||
* shared region called OLB. Some PLLs and fixed-factors are initialised early
|
||||
* by of_clk_init(); if so, two clk providers are registered.
|
||||
*
|
||||
* We use eqc_ as prefix, as-in "EyeQ Clock", but way shorter.
|
||||
*
|
||||
* Copyright (C) 2024 Mobileye Vision Technologies Ltd.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set pr_fmt() for printing from eqc_early_init().
|
||||
* It is called at of_clk_init() stage (read: really early).
|
||||
*/
|
||||
#define pr_fmt(fmt) "clk-eyeq: " fmt
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <dt-bindings/clock/mobileye,eyeq5-clk.h>
|
||||
|
||||
/* In frac mode, it enables fractional noise canceling DAC. Else, no function. */
|
||||
#define PCSR0_DAC_EN BIT(0)
|
||||
/* Fractional or integer mode */
|
||||
#define PCSR0_DSM_EN BIT(1)
|
||||
#define PCSR0_PLL_EN BIT(2)
|
||||
/* All clocks output held at 0 */
|
||||
#define PCSR0_FOUTPOSTDIV_EN BIT(3)
|
||||
#define PCSR0_POST_DIV1 GENMASK(6, 4)
|
||||
#define PCSR0_POST_DIV2 GENMASK(9, 7)
|
||||
#define PCSR0_REF_DIV GENMASK(15, 10)
|
||||
#define PCSR0_INTIN GENMASK(27, 16)
|
||||
#define PCSR0_BYPASS BIT(28)
|
||||
/* Bits 30..29 are reserved */
|
||||
#define PCSR0_PLL_LOCKED BIT(31)
|
||||
|
||||
#define PCSR1_RESET BIT(0)
|
||||
#define PCSR1_SSGC_DIV GENMASK(4, 1)
|
||||
/* Spread amplitude (% = 0.1 * SPREAD[4:0]) */
|
||||
#define PCSR1_SPREAD GENMASK(9, 5)
|
||||
#define PCSR1_DIS_SSCG BIT(10)
|
||||
/* Down-spread or center-spread */
|
||||
#define PCSR1_DOWN_SPREAD BIT(11)
|
||||
#define PCSR1_FRAC_IN GENMASK(31, 12)
|
||||
|
||||
struct eqc_pll {
|
||||
unsigned int index;
|
||||
const char *name;
|
||||
unsigned int reg64;
|
||||
};
|
||||
|
||||
/*
|
||||
* Divider clock. Divider is 2*(v+1), with v the register value.
|
||||
* Min divider is 2, max is 2*(2^width).
|
||||
*/
|
||||
struct eqc_div {
|
||||
unsigned int index;
|
||||
const char *name;
|
||||
unsigned int parent;
|
||||
unsigned int reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
};
|
||||
|
||||
struct eqc_fixed_factor {
|
||||
unsigned int index;
|
||||
const char *name;
|
||||
unsigned int mult;
|
||||
unsigned int div;
|
||||
unsigned int parent;
|
||||
};
|
||||
|
||||
struct eqc_match_data {
|
||||
unsigned int pll_count;
|
||||
const struct eqc_pll *plls;
|
||||
|
||||
unsigned int div_count;
|
||||
const struct eqc_div *divs;
|
||||
|
||||
unsigned int fixed_factor_count;
|
||||
const struct eqc_fixed_factor *fixed_factors;
|
||||
|
||||
const char *reset_auxdev_name;
|
||||
const char *pinctrl_auxdev_name;
|
||||
|
||||
unsigned int early_clk_count;
|
||||
};
|
||||
|
||||
struct eqc_early_match_data {
|
||||
unsigned int early_pll_count;
|
||||
const struct eqc_pll *early_plls;
|
||||
|
||||
unsigned int early_fixed_factor_count;
|
||||
const struct eqc_fixed_factor *early_fixed_factors;
|
||||
|
||||
/*
|
||||
* We want our of_xlate callback to EPROBE_DEFER instead of dev_err()
|
||||
* and EINVAL. For that, we must know the total clock count.
|
||||
*/
|
||||
unsigned int late_clk_count;
|
||||
};
|
||||
|
||||
/*
|
||||
* Both factors (mult and div) must fit in 32 bits. When an operation overflows,
|
||||
* this function throws away low bits so that factors still fit in 32 bits.
|
||||
*
|
||||
* Precision loss depends on amplitude of mult and div. Worst theorical
|
||||
* loss is: (UINT_MAX+1) / UINT_MAX - 1 = 2.3e-10.
|
||||
* This is 1Hz every 4.3GHz.
|
||||
*/
|
||||
static void eqc_pll_downshift_factors(unsigned long *mult, unsigned long *div)
|
||||
{
|
||||
unsigned long biggest;
|
||||
unsigned int shift;
|
||||
|
||||
/* This function can be removed if mult/div switch to unsigned long. */
|
||||
static_assert(sizeof_field(struct clk_fixed_factor, mult) == sizeof(unsigned int));
|
||||
static_assert(sizeof_field(struct clk_fixed_factor, div) == sizeof(unsigned int));
|
||||
|
||||
/* No overflow, nothing to be done. */
|
||||
if (*mult <= UINT_MAX && *div <= UINT_MAX)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Compute the shift required to bring the biggest factor into unsigned
|
||||
* int range. That is, shift its highest set bit to the unsigned int
|
||||
* most significant bit.
|
||||
*/
|
||||
biggest = max(*mult, *div);
|
||||
shift = __fls(biggest) - (BITS_PER_BYTE * sizeof(unsigned int)) + 1;
|
||||
|
||||
*mult >>= shift;
|
||||
*div >>= shift;
|
||||
}
|
||||
|
||||
static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult,
|
||||
unsigned long *div, unsigned long *acc)
|
||||
{
|
||||
u32 spread;
|
||||
|
||||
if (r0 & PCSR0_BYPASS) {
|
||||
*mult = 1;
|
||||
*div = 1;
|
||||
*acc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(r0 & PCSR0_PLL_LOCKED))
|
||||
return -EINVAL;
|
||||
|
||||
*mult = FIELD_GET(PCSR0_INTIN, r0);
|
||||
*div = FIELD_GET(PCSR0_REF_DIV, r0);
|
||||
if (r0 & PCSR0_FOUTPOSTDIV_EN)
|
||||
*div *= FIELD_GET(PCSR0_POST_DIV1, r0) * FIELD_GET(PCSR0_POST_DIV2, r0);
|
||||
|
||||
/* Fractional mode, in 2^20 (0x100000) parts. */
|
||||
if (r0 & PCSR0_DSM_EN) {
|
||||
*div *= (1ULL << 20);
|
||||
*mult = *mult * (1ULL << 20) + FIELD_GET(PCSR1_FRAC_IN, r1);
|
||||
}
|
||||
|
||||
if (!*mult || !*div)
|
||||
return -EINVAL;
|
||||
|
||||
if (r1 & (PCSR1_RESET | PCSR1_DIS_SSCG)) {
|
||||
*acc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Spread spectrum.
|
||||
*
|
||||
* Spread is 1/1000 parts of frequency, accuracy is half of
|
||||
* that. To get accuracy, convert to ppb (parts per billion).
|
||||
*
|
||||
* acc = spread * 1e6 / 2
|
||||
* with acc in parts per billion and,
|
||||
* spread in parts per thousand.
|
||||
*/
|
||||
spread = FIELD_GET(PCSR1_SPREAD, r1);
|
||||
*acc = spread * 500000;
|
||||
|
||||
if (r1 & PCSR1_DOWN_SPREAD) {
|
||||
/*
|
||||
* Downspreading: the central frequency is half a
|
||||
* spread lower.
|
||||
*/
|
||||
*mult *= 2000 - spread;
|
||||
*div *= 2000;
|
||||
|
||||
/*
|
||||
* Previous operation might overflow 32 bits. If it
|
||||
* does, throw away the least amount of low bits.
|
||||
*/
|
||||
eqc_pll_downshift_factors(mult, div);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eqc_probe_init_plls(struct device *dev, const struct eqc_match_data *data,
|
||||
void __iomem *base, struct clk_hw_onecell_data *cells)
|
||||
{
|
||||
unsigned long mult, div, acc;
|
||||
const struct eqc_pll *pll;
|
||||
struct clk_hw *hw;
|
||||
unsigned int i;
|
||||
u32 r0, r1;
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < data->pll_count; i++) {
|
||||
pll = &data->plls[i];
|
||||
|
||||
val = readq(base + pll->reg64);
|
||||
r0 = val;
|
||||
r1 = val >> 32;
|
||||
|
||||
ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc);
|
||||
if (ret) {
|
||||
dev_warn(dev, "failed parsing state of %s\n", pll->name);
|
||||
cells->hws[pll->index] = ERR_PTR(ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_fixed_factor_with_accuracy_fwname(dev,
|
||||
dev->of_node, pll->name, "ref", 0, mult, div, acc);
|
||||
cells->hws[pll->index] = hw;
|
||||
if (IS_ERR(hw))
|
||||
dev_warn(dev, "failed registering %s: %pe\n", pll->name, hw);
|
||||
}
|
||||
}
|
||||
|
||||
static void eqc_probe_init_divs(struct device *dev, const struct eqc_match_data *data,
|
||||
void __iomem *base, struct clk_hw_onecell_data *cells)
|
||||
{
|
||||
struct clk_parent_data parent_data = { };
|
||||
const struct eqc_div *div;
|
||||
struct clk_hw *parent;
|
||||
void __iomem *reg;
|
||||
struct clk_hw *hw;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < data->div_count; i++) {
|
||||
div = &data->divs[i];
|
||||
reg = base + div->reg;
|
||||
parent = cells->hws[div->parent];
|
||||
|
||||
if (IS_ERR(parent)) {
|
||||
/* Parent is in early clk provider. */
|
||||
parent_data.index = div->parent;
|
||||
parent_data.hw = NULL;
|
||||
} else {
|
||||
/* Avoid clock lookup when we already have the hw reference. */
|
||||
parent_data.index = 0;
|
||||
parent_data.hw = parent;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_divider_table_parent_data(dev, div->name,
|
||||
&parent_data, 0, reg, div->shift, div->width,
|
||||
CLK_DIVIDER_EVEN_INTEGERS, NULL, NULL);
|
||||
cells->hws[div->index] = hw;
|
||||
if (IS_ERR(hw))
|
||||
dev_warn(dev, "failed registering %s: %pe\n",
|
||||
div->name, hw);
|
||||
}
|
||||
}
|
||||
|
||||
static void eqc_probe_init_fixed_factors(struct device *dev,
|
||||
const struct eqc_match_data *data,
|
||||
struct clk_hw_onecell_data *cells)
|
||||
{
|
||||
const struct eqc_fixed_factor *ff;
|
||||
struct clk_hw *hw, *parent_hw;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < data->fixed_factor_count; i++) {
|
||||
ff = &data->fixed_factors[i];
|
||||
parent_hw = cells->hws[ff->parent];
|
||||
|
||||
if (IS_ERR(parent_hw)) {
|
||||
/* Parent is in early clk provider. */
|
||||
hw = clk_hw_register_fixed_factor_index(dev, ff->name,
|
||||
ff->parent, 0, ff->mult, ff->div);
|
||||
} else {
|
||||
/* Avoid clock lookup when we already have the hw reference. */
|
||||
hw = clk_hw_register_fixed_factor_parent_hw(dev, ff->name,
|
||||
parent_hw, 0, ff->mult, ff->div);
|
||||
}
|
||||
|
||||
cells->hws[ff->index] = hw;
|
||||
if (IS_ERR(hw))
|
||||
dev_warn(dev, "failed registering %s: %pe\n",
|
||||
ff->name, hw);
|
||||
}
|
||||
}
|
||||
|
||||
static void eqc_auxdev_release(struct device *dev)
|
||||
{
|
||||
struct auxiliary_device *adev = to_auxiliary_dev(dev);
|
||||
|
||||
kfree(adev);
|
||||
}
|
||||
|
||||
static int eqc_auxdev_create(struct device *dev, void __iomem *base,
|
||||
const char *name, u32 id)
|
||||
{
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
adev = kzalloc(sizeof(*adev), GFP_KERNEL);
|
||||
if (!adev)
|
||||
return -ENOMEM;
|
||||
|
||||
adev->name = name;
|
||||
adev->dev.parent = dev;
|
||||
adev->dev.platform_data = (void __force *)base;
|
||||
adev->dev.release = eqc_auxdev_release;
|
||||
adev->id = id;
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = auxiliary_device_add(adev);
|
||||
if (ret)
|
||||
auxiliary_device_uninit(adev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int eqc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct eqc_match_data *data;
|
||||
struct clk_hw_onecell_data *cells;
|
||||
unsigned int i, clk_count;
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
data = device_get_match_data(dev);
|
||||
if (!data)
|
||||
return 0; /* No clocks nor auxdevs, we are done. */
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
base = ioremap(res->start, resource_size(res));
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Init optional reset auxiliary device. */
|
||||
if (data->reset_auxdev_name) {
|
||||
ret = eqc_auxdev_create(dev, base, data->reset_auxdev_name, 0);
|
||||
if (ret)
|
||||
dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
|
||||
KBUILD_MODNAME, data->reset_auxdev_name, ret);
|
||||
}
|
||||
|
||||
/* Init optional pinctrl auxiliary device. */
|
||||
if (data->pinctrl_auxdev_name) {
|
||||
ret = eqc_auxdev_create(dev, base, data->pinctrl_auxdev_name, 0);
|
||||
if (ret)
|
||||
dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n",
|
||||
KBUILD_MODNAME, data->pinctrl_auxdev_name, ret);
|
||||
}
|
||||
|
||||
if (data->pll_count + data->div_count + data->fixed_factor_count == 0)
|
||||
return 0; /* Zero clocks, we are done. */
|
||||
|
||||
clk_count = data->pll_count + data->div_count +
|
||||
data->fixed_factor_count + data->early_clk_count;
|
||||
cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL);
|
||||
if (!cells)
|
||||
return -ENOMEM;
|
||||
|
||||
cells->num = clk_count;
|
||||
|
||||
/* Early PLLs are marked as errors: the early provider will get queried. */
|
||||
for (i = 0; i < clk_count; i++)
|
||||
cells->hws[i] = ERR_PTR(-EINVAL);
|
||||
|
||||
eqc_probe_init_plls(dev, data, base, cells);
|
||||
|
||||
eqc_probe_init_divs(dev, data, base, cells);
|
||||
|
||||
eqc_probe_init_fixed_factors(dev, data, cells);
|
||||
|
||||
return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells);
|
||||
}
|
||||
|
||||
/* Required early for GIC timer (pll-cpu) and UARTs (pll-per). */
|
||||
static const struct eqc_pll eqc_eyeq5_early_plls[] = {
|
||||
{ .index = EQ5C_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C },
|
||||
{ .index = EQ5C_PLL_PER, .name = "pll-per", .reg64 = 0x05C },
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq5_plls[] = {
|
||||
{ .index = EQ5C_PLL_VMP, .name = "pll-vmp", .reg64 = 0x034 },
|
||||
{ .index = EQ5C_PLL_PMA, .name = "pll-pma", .reg64 = 0x03C },
|
||||
{ .index = EQ5C_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 },
|
||||
{ .index = EQ5C_PLL_DDR0, .name = "pll-ddr0", .reg64 = 0x04C },
|
||||
{ .index = EQ5C_PLL_PCI, .name = "pll-pci", .reg64 = 0x054 },
|
||||
{ .index = EQ5C_PLL_PMAC, .name = "pll-pmac", .reg64 = 0x064 },
|
||||
{ .index = EQ5C_PLL_MPC, .name = "pll-mpc", .reg64 = 0x06C },
|
||||
{ .index = EQ5C_PLL_DDR1, .name = "pll-ddr1", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
enum {
|
||||
/*
|
||||
* EQ5C_PLL_CPU children.
|
||||
* EQ5C_PER_OCC_PCI is the last clock exposed in dt-bindings.
|
||||
*/
|
||||
EQ5C_CPU_OCC = EQ5C_PER_OCC_PCI + 1,
|
||||
EQ5C_CPU_SI_CSS0,
|
||||
EQ5C_CPU_CPC,
|
||||
EQ5C_CPU_CM,
|
||||
EQ5C_CPU_MEM,
|
||||
EQ5C_CPU_OCC_ISRAM,
|
||||
EQ5C_CPU_ISRAM,
|
||||
EQ5C_CPU_OCC_DBU,
|
||||
EQ5C_CPU_SI_DBU_TP,
|
||||
|
||||
/*
|
||||
* EQ5C_PLL_VDI children.
|
||||
*/
|
||||
EQ5C_VDI_OCC_VDI,
|
||||
EQ5C_VDI_VDI,
|
||||
EQ5C_VDI_OCC_CAN_SER,
|
||||
EQ5C_VDI_CAN_SER,
|
||||
EQ5C_VDI_I2C_SER,
|
||||
|
||||
/*
|
||||
* EQ5C_PLL_PER children.
|
||||
*/
|
||||
EQ5C_PER_PERIPH,
|
||||
EQ5C_PER_CAN,
|
||||
EQ5C_PER_TIMER,
|
||||
EQ5C_PER_CCF,
|
||||
EQ5C_PER_OCC_MJPEG,
|
||||
EQ5C_PER_HSM,
|
||||
EQ5C_PER_MJPEG,
|
||||
EQ5C_PER_FCMU_A,
|
||||
};
|
||||
|
||||
static const struct eqc_fixed_factor eqc_eyeq5_early_fixed_factors[] = {
|
||||
/* EQ5C_PLL_CPU children */
|
||||
{ EQ5C_CPU_OCC, "occ-cpu", 1, 1, EQ5C_PLL_CPU },
|
||||
{ EQ5C_CPU_SI_CSS0, "si-css0", 1, 1, EQ5C_CPU_OCC },
|
||||
{ EQ5C_CPU_CORE0, "core0", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_CORE1, "core1", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_CORE2, "core2", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_CORE3, "core3", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
|
||||
/* EQ5C_PLL_PER children */
|
||||
{ EQ5C_PER_OCC, "occ-periph", 1, 16, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_UART, "uart", 1, 1, EQ5C_PER_OCC },
|
||||
};
|
||||
|
||||
static const struct eqc_fixed_factor eqc_eyeq5_fixed_factors[] = {
|
||||
/* EQ5C_PLL_CPU children */
|
||||
{ EQ5C_CPU_CPC, "cpc", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_CM, "cm", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_MEM, "mem", 1, 1, EQ5C_CPU_SI_CSS0 },
|
||||
{ EQ5C_CPU_OCC_ISRAM, "occ-isram", 1, 2, EQ5C_PLL_CPU },
|
||||
{ EQ5C_CPU_ISRAM, "isram", 1, 1, EQ5C_CPU_OCC_ISRAM },
|
||||
{ EQ5C_CPU_OCC_DBU, "occ-dbu", 1, 10, EQ5C_PLL_CPU },
|
||||
{ EQ5C_CPU_SI_DBU_TP, "si-dbu-tp", 1, 1, EQ5C_CPU_OCC_DBU },
|
||||
|
||||
/* EQ5C_PLL_VDI children */
|
||||
{ EQ5C_VDI_OCC_VDI, "occ-vdi", 1, 2, EQ5C_PLL_VDI },
|
||||
{ EQ5C_VDI_VDI, "vdi", 1, 1, EQ5C_VDI_OCC_VDI },
|
||||
{ EQ5C_VDI_OCC_CAN_SER, "occ-can-ser", 1, 16, EQ5C_PLL_VDI },
|
||||
{ EQ5C_VDI_CAN_SER, "can-ser", 1, 1, EQ5C_VDI_OCC_CAN_SER },
|
||||
{ EQ5C_VDI_I2C_SER, "i2c-ser", 1, 20, EQ5C_PLL_VDI },
|
||||
|
||||
/* EQ5C_PLL_PER children */
|
||||
{ EQ5C_PER_PERIPH, "periph", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_CAN, "can", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_SPI, "spi", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_I2C, "i2c", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_TIMER, "timer", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_GPIO, "gpio", 1, 1, EQ5C_PER_OCC },
|
||||
{ EQ5C_PER_EMMC, "emmc-sys", 1, 10, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_CCF, "ccf-ctrl", 1, 4, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_OCC_MJPEG, "occ-mjpeg", 1, 2, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_HSM, "hsm", 1, 1, EQ5C_PER_OCC_MJPEG },
|
||||
{ EQ5C_PER_MJPEG, "mjpeg", 1, 1, EQ5C_PER_OCC_MJPEG },
|
||||
{ EQ5C_PER_FCMU_A, "fcmu-a", 1, 20, EQ5C_PLL_PER },
|
||||
{ EQ5C_PER_OCC_PCI, "occ-pci-sys", 1, 8, EQ5C_PLL_PER },
|
||||
};
|
||||
|
||||
static const struct eqc_div eqc_eyeq5_divs[] = {
|
||||
{
|
||||
.index = EQ5C_DIV_OSPI,
|
||||
.name = "div-ospi",
|
||||
.parent = EQ5C_PLL_PER,
|
||||
.reg = 0x11C,
|
||||
.shift = 0,
|
||||
.width = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct eqc_early_match_data eqc_eyeq5_early_match_data __initconst = {
|
||||
.early_pll_count = ARRAY_SIZE(eqc_eyeq5_early_plls),
|
||||
.early_plls = eqc_eyeq5_early_plls,
|
||||
|
||||
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq5_early_fixed_factors),
|
||||
.early_fixed_factors = eqc_eyeq5_early_fixed_factors,
|
||||
|
||||
.late_clk_count = ARRAY_SIZE(eqc_eyeq5_plls) + ARRAY_SIZE(eqc_eyeq5_divs) +
|
||||
ARRAY_SIZE(eqc_eyeq5_fixed_factors),
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq5_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq5_plls),
|
||||
.plls = eqc_eyeq5_plls,
|
||||
|
||||
.div_count = ARRAY_SIZE(eqc_eyeq5_divs),
|
||||
.divs = eqc_eyeq5_divs,
|
||||
|
||||
.fixed_factor_count = ARRAY_SIZE(eqc_eyeq5_fixed_factors),
|
||||
.fixed_factors = eqc_eyeq5_fixed_factors,
|
||||
|
||||
.reset_auxdev_name = "reset",
|
||||
.pinctrl_auxdev_name = "pinctrl",
|
||||
|
||||
.early_clk_count = ARRAY_SIZE(eqc_eyeq5_early_plls) +
|
||||
ARRAY_SIZE(eqc_eyeq5_early_fixed_factors),
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6l_plls[] = {
|
||||
{ .index = EQ6LC_PLL_DDR, .name = "pll-ddr", .reg64 = 0x02C },
|
||||
{ .index = EQ6LC_PLL_CPU, .name = "pll-cpu", .reg64 = 0x034 }, /* also acc */
|
||||
{ .index = EQ6LC_PLL_PER, .name = "pll-per", .reg64 = 0x03C },
|
||||
{ .index = EQ6LC_PLL_VDI, .name = "pll-vdi", .reg64 = 0x044 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6l_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6l_plls),
|
||||
.plls = eqc_eyeq6l_plls,
|
||||
|
||||
.reset_auxdev_name = "reset",
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_west_match_data = {
|
||||
.reset_auxdev_name = "reset_west",
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_east_plls[] = {
|
||||
{ .index = 0, .name = "pll-east", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_east_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_east_plls),
|
||||
.plls = eqc_eyeq6h_east_plls,
|
||||
|
||||
.reset_auxdev_name = "reset_east",
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_south_plls[] = {
|
||||
{ .index = EQ6HC_SOUTH_PLL_VDI, .name = "pll-vdi", .reg64 = 0x000 },
|
||||
{ .index = EQ6HC_SOUTH_PLL_PCIE, .name = "pll-pcie", .reg64 = 0x008 },
|
||||
{ .index = EQ6HC_SOUTH_PLL_PER, .name = "pll-per", .reg64 = 0x010 },
|
||||
{ .index = EQ6HC_SOUTH_PLL_ISP, .name = "pll-isp", .reg64 = 0x018 },
|
||||
};
|
||||
|
||||
static const struct eqc_div eqc_eyeq6h_south_divs[] = {
|
||||
{
|
||||
.index = EQ6HC_SOUTH_DIV_EMMC,
|
||||
.name = "div-emmc",
|
||||
.parent = EQ6HC_SOUTH_PLL_PER,
|
||||
.reg = 0x070,
|
||||
.shift = 4,
|
||||
.width = 4,
|
||||
},
|
||||
{
|
||||
.index = EQ6HC_SOUTH_DIV_OSPI_REF,
|
||||
.name = "div-ospi-ref",
|
||||
.parent = EQ6HC_SOUTH_PLL_PER,
|
||||
.reg = 0x090,
|
||||
.shift = 4,
|
||||
.width = 4,
|
||||
},
|
||||
{
|
||||
.index = EQ6HC_SOUTH_DIV_OSPI_SYS,
|
||||
.name = "div-ospi-sys",
|
||||
.parent = EQ6HC_SOUTH_PLL_PER,
|
||||
.reg = 0x090,
|
||||
.shift = 8,
|
||||
.width = 1,
|
||||
},
|
||||
{
|
||||
.index = EQ6HC_SOUTH_DIV_TSU,
|
||||
.name = "div-tsu",
|
||||
.parent = EQ6HC_SOUTH_PLL_PCIE,
|
||||
.reg = 0x098,
|
||||
.shift = 4,
|
||||
.width = 8,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_south_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_south_plls),
|
||||
.plls = eqc_eyeq6h_south_plls,
|
||||
|
||||
.div_count = ARRAY_SIZE(eqc_eyeq6h_south_divs),
|
||||
.divs = eqc_eyeq6h_south_divs,
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_ddr0_plls[] = {
|
||||
{ .index = 0, .name = "pll-ddr0", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_ddr0_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr0_plls),
|
||||
.plls = eqc_eyeq6h_ddr0_plls,
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_ddr1_plls[] = {
|
||||
{ .index = 0, .name = "pll-ddr1", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_ddr1_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_ddr1_plls),
|
||||
.plls = eqc_eyeq6h_ddr1_plls,
|
||||
};
|
||||
|
||||
static const struct eqc_pll eqc_eyeq6h_acc_plls[] = {
|
||||
{ .index = EQ6HC_ACC_PLL_XNN, .name = "pll-xnn", .reg64 = 0x040 },
|
||||
{ .index = EQ6HC_ACC_PLL_VMP, .name = "pll-vmp", .reg64 = 0x050 },
|
||||
{ .index = EQ6HC_ACC_PLL_PMA, .name = "pll-pma", .reg64 = 0x05C },
|
||||
{ .index = EQ6HC_ACC_PLL_MPC, .name = "pll-mpc", .reg64 = 0x068 },
|
||||
{ .index = EQ6HC_ACC_PLL_NOC, .name = "pll-noc", .reg64 = 0x070 },
|
||||
};
|
||||
|
||||
static const struct eqc_match_data eqc_eyeq6h_acc_match_data = {
|
||||
.pll_count = ARRAY_SIZE(eqc_eyeq6h_acc_plls),
|
||||
.plls = eqc_eyeq6h_acc_plls,
|
||||
|
||||
.reset_auxdev_name = "reset_acc",
|
||||
};
|
||||
|
||||
static const struct of_device_id eqc_match_table[] = {
|
||||
{ .compatible = "mobileye,eyeq5-olb", .data = &eqc_eyeq5_match_data },
|
||||
{ .compatible = "mobileye,eyeq6l-olb", .data = &eqc_eyeq6l_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-west-olb", .data = &eqc_eyeq6h_west_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-east-olb", .data = &eqc_eyeq6h_east_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-south-olb", .data = &eqc_eyeq6h_south_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-ddr0-olb", .data = &eqc_eyeq6h_ddr0_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-ddr1-olb", .data = &eqc_eyeq6h_ddr1_match_data },
|
||||
{ .compatible = "mobileye,eyeq6h-acc-olb", .data = &eqc_eyeq6h_acc_match_data },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver eqc_driver = {
|
||||
.probe = eqc_probe,
|
||||
.driver = {
|
||||
.name = "clk-eyeq",
|
||||
.of_match_table = eqc_match_table,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(eqc_driver);
|
||||
|
||||
/* Required early for GIC timer. */
|
||||
static const struct eqc_pll eqc_eyeq6h_central_early_plls[] = {
|
||||
{ .index = EQ6HC_CENTRAL_PLL_CPU, .name = "pll-cpu", .reg64 = 0x02C },
|
||||
};
|
||||
|
||||
static const struct eqc_fixed_factor eqc_eyeq6h_central_early_fixed_factors[] = {
|
||||
{ EQ6HC_CENTRAL_CPU_OCC, "occ-cpu", 1, 1, EQ6HC_CENTRAL_PLL_CPU },
|
||||
};
|
||||
|
||||
static const struct eqc_early_match_data eqc_eyeq6h_central_early_match_data __initconst = {
|
||||
.early_pll_count = ARRAY_SIZE(eqc_eyeq6h_central_early_plls),
|
||||
.early_plls = eqc_eyeq6h_central_early_plls,
|
||||
|
||||
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6h_central_early_fixed_factors),
|
||||
.early_fixed_factors = eqc_eyeq6h_central_early_fixed_factors,
|
||||
};
|
||||
|
||||
/* Required early for UART. */
|
||||
static const struct eqc_pll eqc_eyeq6h_west_early_plls[] = {
|
||||
{ .index = EQ6HC_WEST_PLL_PER, .name = "pll-west", .reg64 = 0x074 },
|
||||
};
|
||||
|
||||
static const struct eqc_fixed_factor eqc_eyeq6h_west_early_fixed_factors[] = {
|
||||
{ EQ6HC_WEST_PER_OCC, "west-per-occ", 1, 10, EQ6HC_WEST_PLL_PER },
|
||||
{ EQ6HC_WEST_PER_UART, "west-per-uart", 1, 1, EQ6HC_WEST_PER_OCC },
|
||||
};
|
||||
|
||||
static const struct eqc_early_match_data eqc_eyeq6h_west_early_match_data __initconst = {
|
||||
.early_pll_count = ARRAY_SIZE(eqc_eyeq6h_west_early_plls),
|
||||
.early_plls = eqc_eyeq6h_west_early_plls,
|
||||
|
||||
.early_fixed_factor_count = ARRAY_SIZE(eqc_eyeq6h_west_early_fixed_factors),
|
||||
.early_fixed_factors = eqc_eyeq6h_west_early_fixed_factors,
|
||||
};
|
||||
|
||||
static void __init eqc_early_init(struct device_node *np,
|
||||
const struct eqc_early_match_data *early_data)
|
||||
{
|
||||
struct clk_hw_onecell_data *cells;
|
||||
unsigned int i, clk_count;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
|
||||
clk_count = early_data->early_pll_count + early_data->early_fixed_factor_count +
|
||||
early_data->late_clk_count;
|
||||
cells = kzalloc(struct_size(cells, hws, clk_count), GFP_KERNEL);
|
||||
if (!cells) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
cells->num = clk_count;
|
||||
|
||||
/*
|
||||
* Mark all clocks as deferred; some are registered here, the rest at
|
||||
* platform device probe.
|
||||
*
|
||||
* Once the platform device is probed, its provider will take priority
|
||||
* when looking up clocks.
|
||||
*/
|
||||
for (i = 0; i < clk_count; i++)
|
||||
cells->hws[i] = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
/* Offsets (reg64) of early PLLs are relative to OLB block. */
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < early_data->early_pll_count; i++) {
|
||||
const struct eqc_pll *pll = &early_data->early_plls[i];
|
||||
unsigned long mult, div, acc;
|
||||
struct clk_hw *hw;
|
||||
u32 r0, r1;
|
||||
u64 val;
|
||||
|
||||
val = readq(base + pll->reg64);
|
||||
r0 = val;
|
||||
r1 = val >> 32;
|
||||
|
||||
ret = eqc_pll_parse_registers(r0, r1, &mult, &div, &acc);
|
||||
if (ret) {
|
||||
pr_err("failed parsing state of %s\n", pll->name);
|
||||
goto err;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_fixed_factor_with_accuracy_fwname(NULL,
|
||||
np, pll->name, "ref", 0, mult, div, acc);
|
||||
cells->hws[pll->index] = hw;
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("failed registering %s: %pe\n", pll->name, hw);
|
||||
ret = PTR_ERR(hw);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < early_data->early_fixed_factor_count; i++) {
|
||||
const struct eqc_fixed_factor *ff = &early_data->early_fixed_factors[i];
|
||||
struct clk_hw *parent_hw = cells->hws[ff->parent];
|
||||
struct clk_hw *hw;
|
||||
|
||||
hw = clk_hw_register_fixed_factor_parent_hw(NULL, ff->name,
|
||||
parent_hw, 0, ff->mult, ff->div);
|
||||
cells->hws[ff->index] = hw;
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("failed registering %s: %pe\n", ff->name, hw);
|
||||
ret = PTR_ERR(hw);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, cells);
|
||||
if (ret) {
|
||||
pr_err("failed registering clk provider: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
/*
|
||||
* We are doomed. The system will not be able to boot.
|
||||
*
|
||||
* Let's still try to be good citizens by freeing resources and print
|
||||
* a last error message that might help debugging.
|
||||
*/
|
||||
|
||||
pr_err("failed clk init: %d\n", ret);
|
||||
|
||||
if (cells) {
|
||||
of_clk_del_provider(np);
|
||||
|
||||
for (i = 0; i < early_data->early_pll_count; i++) {
|
||||
const struct eqc_pll *pll = &early_data->early_plls[i];
|
||||
struct clk_hw *hw = cells->hws[pll->index];
|
||||
|
||||
if (!IS_ERR_OR_NULL(hw))
|
||||
clk_hw_unregister_fixed_factor(hw);
|
||||
}
|
||||
|
||||
kfree(cells);
|
||||
}
|
||||
}
|
||||
|
||||
static void __init eqc_eyeq5_early_init(struct device_node *np)
|
||||
{
|
||||
eqc_early_init(np, &eqc_eyeq5_early_match_data);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(eqc_eyeq5, "mobileye,eyeq5-olb", eqc_eyeq5_early_init);
|
||||
|
||||
static void __init eqc_eyeq6h_central_early_init(struct device_node *np)
|
||||
{
|
||||
eqc_early_init(np, &eqc_eyeq6h_central_early_match_data);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_central, "mobileye,eyeq6h-central-olb",
|
||||
eqc_eyeq6h_central_early_init);
|
||||
|
||||
static void __init eqc_eyeq6h_west_early_init(struct device_node *np)
|
||||
{
|
||||
eqc_early_init(np, &eqc_eyeq6h_west_early_match_data);
|
||||
}
|
||||
CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_west, "mobileye,eyeq6h-west-olb",
|
||||
eqc_eyeq6h_west_early_init);
|
@ -241,6 +241,17 @@ struct clk_hw *clk_hw_register_fixed_factor_with_accuracy_fwname(struct device *
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_with_accuracy_fwname);
|
||||
|
||||
struct clk_hw *clk_hw_register_fixed_factor_index(struct device *dev,
|
||||
const char *name, unsigned int index, unsigned long flags,
|
||||
unsigned int mult, unsigned int div)
|
||||
{
|
||||
const struct clk_parent_data pdata = { .index = index };
|
||||
|
||||
return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, &pdata,
|
||||
flags, mult, div, 0, 0, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_index);
|
||||
|
||||
struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
|
||||
const char *parent_name, unsigned long flags,
|
||||
unsigned int mult, unsigned int div)
|
||||
|
@ -17,13 +17,15 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
/**
|
||||
* DOC: basic gpio gated clock which can be enabled and disabled
|
||||
* with gpio output
|
||||
* Traits of this clock:
|
||||
* prepare - clk_(un)prepare only ensures parent is (un)prepared
|
||||
* enable - clk_enable and clk_disable are functional & control gpio
|
||||
* prepare - clk_(un)prepare are functional and control a gpio that can sleep
|
||||
* enable - clk_enable and clk_disable are functional & control
|
||||
* non-sleeping gpio
|
||||
* rate - inherits rate from parent. No clk_set_rate support
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*/
|
||||
@ -199,7 +201,6 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
|
||||
struct gpio_desc *gpiod;
|
||||
struct clk_hw *hw;
|
||||
bool is_mux;
|
||||
int ret;
|
||||
|
||||
is_mux = of_device_is_compatible(node, "gpio-mux-clock");
|
||||
|
||||
@ -211,17 +212,9 @@ static int gpio_clk_driver_probe(struct platform_device *pdev)
|
||||
|
||||
gpio_name = is_mux ? "select" : "enable";
|
||||
gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpiod)) {
|
||||
ret = PTR_ERR(gpiod);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n",
|
||||
node, __func__);
|
||||
else
|
||||
pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n",
|
||||
node, __func__,
|
||||
gpio_name);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(gpiod))
|
||||
return dev_err_probe(dev, PTR_ERR(gpiod),
|
||||
"Can't get '%s' named GPIO property\n", gpio_name);
|
||||
|
||||
if (is_mux)
|
||||
hw = clk_hw_register_gpio_mux(dev, gpiod);
|
||||
@ -247,3 +240,187 @@ static struct platform_driver gpio_clk_driver = {
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(gpio_clk_driver);
|
||||
|
||||
/**
|
||||
* DOC: gated fixed clock, controlled with a gpio output and a regulator
|
||||
* Traits of this clock:
|
||||
* prepare - clk_prepare and clk_unprepare are function & control regulator
|
||||
* optionally a gpio that can sleep
|
||||
* enable - clk_enable and clk_disable are functional & control gpio
|
||||
* rate - rate is fixed and set on clock registration
|
||||
* parent - fixed clock is a root clock and has no parent
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct clk_gated_fixed - Gateable fixed rate clock
|
||||
* @clk_gpio: instance of clk_gpio for gate-gpio
|
||||
* @supply: supply regulator
|
||||
* @rate: fixed rate
|
||||
*/
|
||||
struct clk_gated_fixed {
|
||||
struct clk_gpio clk_gpio;
|
||||
struct regulator *supply;
|
||||
unsigned long rate;
|
||||
};
|
||||
|
||||
#define to_clk_gated_fixed(_clk_gpio) container_of(_clk_gpio, struct clk_gated_fixed, clk_gpio)
|
||||
|
||||
static unsigned long clk_gated_fixed_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
return to_clk_gated_fixed(to_clk_gpio(hw))->rate;
|
||||
}
|
||||
|
||||
static int clk_gated_fixed_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
|
||||
|
||||
if (!clk->supply)
|
||||
return 0;
|
||||
|
||||
return regulator_enable(clk->supply);
|
||||
}
|
||||
|
||||
static void clk_gated_fixed_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
|
||||
|
||||
if (!clk->supply)
|
||||
return;
|
||||
|
||||
regulator_disable(clk->supply);
|
||||
}
|
||||
|
||||
static int clk_gated_fixed_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_gated_fixed *clk = to_clk_gated_fixed(to_clk_gpio(hw));
|
||||
|
||||
if (!clk->supply)
|
||||
return true;
|
||||
|
||||
return regulator_is_enabled(clk->supply);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fixed gated clock with non-sleeping gpio.
|
||||
*
|
||||
* Prepare operation turns on the supply regulator
|
||||
* and the enable operation switches the enable-gpio.
|
||||
*/
|
||||
static const struct clk_ops clk_gated_fixed_ops = {
|
||||
.prepare = clk_gated_fixed_prepare,
|
||||
.unprepare = clk_gated_fixed_unprepare,
|
||||
.is_prepared = clk_gated_fixed_is_prepared,
|
||||
.enable = clk_gpio_gate_enable,
|
||||
.disable = clk_gpio_gate_disable,
|
||||
.is_enabled = clk_gpio_gate_is_enabled,
|
||||
.recalc_rate = clk_gated_fixed_recalc_rate,
|
||||
};
|
||||
|
||||
static int clk_sleeping_gated_fixed_prepare(struct clk_hw *hw)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_gated_fixed_prepare(hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_sleeping_gpio_gate_prepare(hw);
|
||||
if (ret)
|
||||
clk_gated_fixed_unprepare(hw);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void clk_sleeping_gated_fixed_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
clk_gated_fixed_unprepare(hw);
|
||||
clk_sleeping_gpio_gate_unprepare(hw);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fixed gated clock with non-sleeping gpio.
|
||||
*
|
||||
* Enabling the supply regulator and switching the enable-gpio happens
|
||||
* both in the prepare step.
|
||||
* is_prepared only needs to check the gpio state, as toggling the
|
||||
* gpio is the last step when preparing.
|
||||
*/
|
||||
static const struct clk_ops clk_sleeping_gated_fixed_ops = {
|
||||
.prepare = clk_sleeping_gated_fixed_prepare,
|
||||
.unprepare = clk_sleeping_gated_fixed_unprepare,
|
||||
.is_prepared = clk_sleeping_gpio_gate_is_prepared,
|
||||
.recalc_rate = clk_gated_fixed_recalc_rate,
|
||||
};
|
||||
|
||||
static int clk_gated_fixed_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk_gated_fixed *clk;
|
||||
const struct clk_ops *ops;
|
||||
const char *clk_name;
|
||||
u32 rate;
|
||||
int ret;
|
||||
|
||||
clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
|
||||
if (!clk)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = device_property_read_u32(dev, "clock-frequency", &rate);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to get clock-frequency\n");
|
||||
clk->rate = rate;
|
||||
|
||||
ret = device_property_read_string(dev, "clock-output-names", &clk_name);
|
||||
if (ret)
|
||||
clk_name = fwnode_get_name(dev->fwnode);
|
||||
|
||||
clk->supply = devm_regulator_get_optional(dev, "vdd");
|
||||
if (IS_ERR(clk->supply)) {
|
||||
if (PTR_ERR(clk->supply) != -ENODEV)
|
||||
return dev_err_probe(dev, PTR_ERR(clk->supply),
|
||||
"Failed to get regulator\n");
|
||||
clk->supply = NULL;
|
||||
}
|
||||
|
||||
clk->clk_gpio.gpiod = devm_gpiod_get_optional(dev, "enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(clk->clk_gpio.gpiod))
|
||||
return dev_err_probe(dev, PTR_ERR(clk->clk_gpio.gpiod),
|
||||
"Failed to get gpio\n");
|
||||
|
||||
if (gpiod_cansleep(clk->clk_gpio.gpiod))
|
||||
ops = &clk_sleeping_gated_fixed_ops;
|
||||
else
|
||||
ops = &clk_gated_fixed_ops;
|
||||
|
||||
clk->clk_gpio.hw.init = CLK_HW_INIT_NO_PARENT(clk_name, ops, 0);
|
||||
|
||||
/* register the clock */
|
||||
ret = devm_clk_hw_register(dev, &clk->clk_gpio.hw);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to register clock\n");
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
|
||||
&clk->clk_gpio.hw);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to register clock provider\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id gated_fixed_clk_match_table[] = {
|
||||
{ .compatible = "gated-fixed-clock" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver gated_fixed_clk_driver = {
|
||||
.probe = clk_gated_fixed_probe,
|
||||
.driver = {
|
||||
.name = "gated-fixed-clk",
|
||||
.of_match_table = gated_fixed_clk_match_table,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver(gated_fixed_clk_driver);
|
||||
|
@ -24,13 +24,20 @@
|
||||
|
||||
#define DIV_MAX 255
|
||||
|
||||
static const char *clk_names[N_CLOCKS] = {
|
||||
static const char * const lan966x_clk_names[] = {
|
||||
"qspi0", "qspi1", "qspi2", "sdmmc0",
|
||||
"pi", "mcan0", "mcan1", "flexcom0",
|
||||
"flexcom1", "flexcom2", "flexcom3",
|
||||
"flexcom4", "timer1", "usb_refclk",
|
||||
};
|
||||
|
||||
static const char * const lan969x_clk_names[] = {
|
||||
"qspi0", "qspi2", "sdmmc0", "sdmmc1",
|
||||
"mcan0", "mcan1", "flexcom0",
|
||||
"flexcom1", "flexcom2", "flexcom3",
|
||||
"timer1", "usb_refclk",
|
||||
};
|
||||
|
||||
struct lan966x_gck {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
@ -53,7 +60,7 @@ struct clk_gate_soc_desc {
|
||||
int bit_idx;
|
||||
};
|
||||
|
||||
static const struct clk_gate_soc_desc clk_gate_desc[] = {
|
||||
static const struct clk_gate_soc_desc lan966x_clk_gate_desc[] = {
|
||||
{ "uhphs", 11 },
|
||||
{ "udphs", 10 },
|
||||
{ "mcramc", 9 },
|
||||
@ -61,6 +68,37 @@ static const struct clk_gate_soc_desc clk_gate_desc[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct clk_gate_soc_desc lan969x_clk_gate_desc[] = {
|
||||
{ "usb_drd", 10 },
|
||||
{ "mcramc", 9 },
|
||||
{ "hmatrix", 8 },
|
||||
{ }
|
||||
};
|
||||
|
||||
struct lan966x_match_data {
|
||||
char *name;
|
||||
const char * const *clk_name;
|
||||
const struct clk_gate_soc_desc *clk_gate_desc;
|
||||
u8 num_generic_clks;
|
||||
u8 num_total_clks;
|
||||
};
|
||||
|
||||
static struct lan966x_match_data lan966x_desc = {
|
||||
.name = "lan966x",
|
||||
.clk_name = lan966x_clk_names,
|
||||
.clk_gate_desc = lan966x_clk_gate_desc,
|
||||
.num_total_clks = 18,
|
||||
.num_generic_clks = 14,
|
||||
};
|
||||
|
||||
static struct lan966x_match_data lan969x_desc = {
|
||||
.name = "lan969x",
|
||||
.clk_name = lan969x_clk_names,
|
||||
.clk_gate_desc = lan969x_clk_gate_desc,
|
||||
.num_total_clks = 15,
|
||||
.num_generic_clks = 12,
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(clk_gate_lock);
|
||||
static void __iomem *base;
|
||||
|
||||
@ -186,24 +224,26 @@ static struct clk_hw *lan966x_gck_clk_register(struct device *dev, int i)
|
||||
};
|
||||
|
||||
static int lan966x_gate_clk_register(struct device *dev,
|
||||
const struct lan966x_match_data *data,
|
||||
struct clk_hw_onecell_data *hw_data,
|
||||
void __iomem *gate_base)
|
||||
{
|
||||
int i;
|
||||
for (int i = data->num_generic_clks; i < data->num_total_clks; ++i) {
|
||||
int idx = i - data->num_generic_clks;
|
||||
const struct clk_gate_soc_desc *desc;
|
||||
|
||||
for (i = GCK_GATE_UHPHS; i < N_CLOCKS; ++i) {
|
||||
int idx = i - GCK_GATE_UHPHS;
|
||||
desc = &data->clk_gate_desc[idx];
|
||||
|
||||
hw_data->hws[i] =
|
||||
devm_clk_hw_register_gate(dev, clk_gate_desc[idx].name,
|
||||
"lan966x", 0, gate_base,
|
||||
clk_gate_desc[idx].bit_idx,
|
||||
devm_clk_hw_register_gate(dev, desc->name,
|
||||
data->name, 0, gate_base,
|
||||
desc->bit_idx,
|
||||
0, &clk_gate_lock);
|
||||
|
||||
if (IS_ERR(hw_data->hws[i]))
|
||||
return dev_err_probe(dev, PTR_ERR(hw_data->hws[i]),
|
||||
"failed to register %s clock\n",
|
||||
clk_gate_desc[idx].name);
|
||||
desc->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -211,13 +251,18 @@ static int lan966x_gate_clk_register(struct device *dev,
|
||||
|
||||
static int lan966x_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct lan966x_match_data *data;
|
||||
struct clk_hw_onecell_data *hw_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *gate_base;
|
||||
struct resource *res;
|
||||
int i, ret;
|
||||
|
||||
hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, N_CLOCKS),
|
||||
data = device_get_match_data(dev);
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
hw_data = devm_kzalloc(dev, struct_size(hw_data, hws, data->num_total_clks),
|
||||
GFP_KERNEL);
|
||||
if (!hw_data)
|
||||
return -ENOMEM;
|
||||
@ -228,10 +273,10 @@ static int lan966x_clk_probe(struct platform_device *pdev)
|
||||
|
||||
init.ops = &lan966x_gck_ops;
|
||||
|
||||
hw_data->num = GCK_GATE_UHPHS;
|
||||
hw_data->num = data->num_generic_clks;
|
||||
|
||||
for (i = 0; i < GCK_GATE_UHPHS; i++) {
|
||||
init.name = clk_names[i];
|
||||
for (i = 0; i < data->num_generic_clks; i++) {
|
||||
init.name = data->clk_name[i];
|
||||
hw_data->hws[i] = lan966x_gck_clk_register(dev, i);
|
||||
if (IS_ERR(hw_data->hws[i])) {
|
||||
dev_err(dev, "failed to register %s clock\n",
|
||||
@ -246,9 +291,9 @@ static int lan966x_clk_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(gate_base))
|
||||
return PTR_ERR(gate_base);
|
||||
|
||||
hw_data->num = N_CLOCKS;
|
||||
hw_data->num = data->num_total_clks;
|
||||
|
||||
ret = lan966x_gate_clk_register(dev, hw_data, gate_base);
|
||||
ret = lan966x_gate_clk_register(dev, data, hw_data, gate_base);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -257,7 +302,8 @@ static int lan966x_clk_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id lan966x_clk_dt_ids[] = {
|
||||
{ .compatible = "microchip,lan966x-gck", },
|
||||
{ .compatible = "microchip,lan966x-gck", .data = &lan966x_desc },
|
||||
{ .compatible = "microchip,lan9691-gck", .data = &lan969x_desc },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lan966x_clk_dt_ids);
|
||||
|
@ -29,8 +29,10 @@ enum loongson2_clk_type {
|
||||
struct loongson2_clk_provider {
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
struct clk_hw_onecell_data clk_data;
|
||||
spinlock_t clk_lock; /* protect access to DIV registers */
|
||||
|
||||
/* Must be last --ends in a flexible-array member. */
|
||||
struct clk_hw_onecell_data clk_data;
|
||||
};
|
||||
|
||||
struct loongson2_clk_data {
|
||||
@ -304,7 +306,7 @@ static int loongson2_clk_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(clp->base);
|
||||
|
||||
spin_lock_init(&clp->clk_lock);
|
||||
clp->clk_data.num = clks_num + 1;
|
||||
clp->clk_data.num = clks_num;
|
||||
clp->dev = dev;
|
||||
|
||||
for (i = 0; i < clks_num; i++) {
|
||||
|
430
drivers/clk/clk-npcm8xx.c
Normal file
430
drivers/clk/clk-npcm8xx.c
Normal file
@ -0,0 +1,430 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Nuvoton NPCM8xx Clock Generator
|
||||
* All the clocks are initialized by the bootloader, so this driver allows only
|
||||
* reading of current settings directly from the hardware.
|
||||
*
|
||||
* Copyright (C) 2020 Nuvoton Technologies
|
||||
* Author: Tomer Maimon <tomer.maimon@nuvoton.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "npcm8xx_clk: " fmt
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <dt-bindings/clock/nuvoton,npcm845-clk.h>
|
||||
#include <soc/nuvoton/clock-npcm8xx.h>
|
||||
|
||||
/* npcm8xx clock registers*/
|
||||
#define NPCM8XX_CLKSEL 0x04
|
||||
#define NPCM8XX_CLKDIV1 0x08
|
||||
#define NPCM8XX_CLKDIV2 0x2C
|
||||
#define NPCM8XX_CLKDIV3 0x58
|
||||
#define NPCM8XX_CLKDIV4 0x7C
|
||||
#define NPCM8XX_PLLCON0 0x0C
|
||||
#define NPCM8XX_PLLCON1 0x10
|
||||
#define NPCM8XX_PLLCON2 0x54
|
||||
#define NPCM8XX_PLLCONG 0x60
|
||||
#define NPCM8XX_THRTL_CNT 0xC0
|
||||
|
||||
#define PLLCON_LOKI BIT(31)
|
||||
#define PLLCON_LOKS BIT(30)
|
||||
#define PLLCON_FBDV GENMASK(27, 16)
|
||||
#define PLLCON_OTDV2 GENMASK(15, 13)
|
||||
#define PLLCON_PWDEN BIT(12)
|
||||
#define PLLCON_OTDV1 GENMASK(10, 8)
|
||||
#define PLLCON_INDV GENMASK(5, 0)
|
||||
|
||||
static void __iomem *clk_base;
|
||||
|
||||
struct npcm8xx_clk_pll {
|
||||
void __iomem *pllcon;
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
unsigned long flags;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
#define to_npcm8xx_clk_pll(_hw) container_of(_hw, struct npcm8xx_clk_pll, hw)
|
||||
|
||||
struct npcm8xx_clk_pll_data {
|
||||
const char *name;
|
||||
struct clk_parent_data parent;
|
||||
unsigned int reg;
|
||||
unsigned long flags;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
struct npcm8xx_clk_div_data {
|
||||
u32 reg;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
const char *name;
|
||||
const struct clk_hw *parent_hw;
|
||||
unsigned long clk_divider_flags;
|
||||
unsigned long flags;
|
||||
int onecell_idx;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
struct npcm8xx_clk_mux_data {
|
||||
u8 shift;
|
||||
u32 mask;
|
||||
const u32 *table;
|
||||
const char *name;
|
||||
const struct clk_parent_data *parent_data;
|
||||
u8 num_parents;
|
||||
unsigned long flags;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
|
||||
static struct clk_hw hw_pll1_div2, hw_pll2_div2, hw_gfx_div2, hw_pre_clk;
|
||||
static struct npcm8xx_clk_pll_data npcm8xx_pll_clks[] = {
|
||||
{ "pll0", { .index = 0 }, NPCM8XX_PLLCON0, 0 },
|
||||
{ "pll1", { .index = 0 }, NPCM8XX_PLLCON1, 0 },
|
||||
{ "pll2", { .index = 0 }, NPCM8XX_PLLCON2, 0 },
|
||||
{ "pll_gfx", { .index = 0 }, NPCM8XX_PLLCONG, 0 },
|
||||
};
|
||||
|
||||
static const u32 cpuck_mux_table[] = { 0, 1, 2, 7 };
|
||||
static const struct clk_parent_data cpuck_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[0].hw },
|
||||
{ .hw = &npcm8xx_pll_clks[1].hw },
|
||||
{ .index = 0 },
|
||||
{ .hw = &npcm8xx_pll_clks[2].hw }
|
||||
};
|
||||
|
||||
static const u32 pixcksel_mux_table[] = { 0, 2 };
|
||||
static const struct clk_parent_data pixcksel_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[3].hw },
|
||||
{ .index = 0 }
|
||||
};
|
||||
|
||||
static const u32 default_mux_table[] = { 0, 1, 2, 3 };
|
||||
static const struct clk_parent_data default_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[0].hw },
|
||||
{ .hw = &npcm8xx_pll_clks[1].hw },
|
||||
{ .index = 0 },
|
||||
{ .hw = &hw_pll2_div2 }
|
||||
};
|
||||
|
||||
static const u32 sucksel_mux_table[] = { 2, 3 };
|
||||
static const struct clk_parent_data sucksel_mux_parents[] = {
|
||||
{ .index = 0 },
|
||||
{ .hw = &hw_pll2_div2 }
|
||||
};
|
||||
|
||||
static const u32 mccksel_mux_table[] = { 0, 2 };
|
||||
static const struct clk_parent_data mccksel_mux_parents[] = {
|
||||
{ .hw = &hw_pll1_div2 },
|
||||
{ .index = 0 }
|
||||
};
|
||||
|
||||
static const u32 clkoutsel_mux_table[] = { 0, 1, 2, 3, 4 };
|
||||
static const struct clk_parent_data clkoutsel_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[0].hw },
|
||||
{ .hw = &npcm8xx_pll_clks[1].hw },
|
||||
{ .index = 0 },
|
||||
{ .hw = &hw_gfx_div2 },
|
||||
{ .hw = &hw_pll2_div2 }
|
||||
};
|
||||
|
||||
static const u32 gfxmsel_mux_table[] = { 2, 3 };
|
||||
static const struct clk_parent_data gfxmsel_mux_parents[] = {
|
||||
{ .index = 0 },
|
||||
{ .hw = &npcm8xx_pll_clks[2].hw }
|
||||
};
|
||||
|
||||
static const u32 dvcssel_mux_table[] = { 2, 3 };
|
||||
static const struct clk_parent_data dvcssel_mux_parents[] = {
|
||||
{ .index = 0 },
|
||||
{ .hw = &npcm8xx_pll_clks[2].hw }
|
||||
};
|
||||
|
||||
static const u32 default3_mux_table[] = { 0, 1, 2 };
|
||||
static const struct clk_parent_data default3_mux_parents[] = {
|
||||
{ .hw = &npcm8xx_pll_clks[0].hw },
|
||||
{ .hw = &npcm8xx_pll_clks[1].hw },
|
||||
{ .index = 0 }
|
||||
};
|
||||
|
||||
static struct npcm8xx_clk_mux_data npcm8xx_muxes[] = {
|
||||
{ 0, 3, cpuck_mux_table, "cpu_mux", cpuck_mux_parents,
|
||||
ARRAY_SIZE(cpuck_mux_parents), CLK_IS_CRITICAL },
|
||||
{ 4, 2, pixcksel_mux_table, "gfx_pixel_mux", pixcksel_mux_parents,
|
||||
ARRAY_SIZE(pixcksel_mux_parents), 0 },
|
||||
{ 6, 2, default_mux_table, "sd_mux", default_mux_parents,
|
||||
ARRAY_SIZE(default_mux_parents), 0 },
|
||||
{ 8, 2, default_mux_table, "uart_mux", default_mux_parents,
|
||||
ARRAY_SIZE(default_mux_parents), 0 },
|
||||
{ 10, 2, sucksel_mux_table, "serial_usb_mux", sucksel_mux_parents,
|
||||
ARRAY_SIZE(sucksel_mux_parents), 0 },
|
||||
{ 12, 2, mccksel_mux_table, "mc_mux", mccksel_mux_parents,
|
||||
ARRAY_SIZE(mccksel_mux_parents), 0 },
|
||||
{ 14, 2, default_mux_table, "adc_mux", default_mux_parents,
|
||||
ARRAY_SIZE(default_mux_parents), 0 },
|
||||
{ 16, 2, default_mux_table, "gfx_mux", default_mux_parents,
|
||||
ARRAY_SIZE(default_mux_parents), 0 },
|
||||
{ 18, 3, clkoutsel_mux_table, "clkout_mux", clkoutsel_mux_parents,
|
||||
ARRAY_SIZE(clkoutsel_mux_parents), 0 },
|
||||
{ 21, 2, gfxmsel_mux_table, "gfxm_mux", gfxmsel_mux_parents,
|
||||
ARRAY_SIZE(gfxmsel_mux_parents), 0 },
|
||||
{ 23, 2, dvcssel_mux_table, "dvc_mux", dvcssel_mux_parents,
|
||||
ARRAY_SIZE(dvcssel_mux_parents), 0 },
|
||||
{ 25, 2, default3_mux_table, "rg_mux", default3_mux_parents,
|
||||
ARRAY_SIZE(default3_mux_parents), 0 },
|
||||
{ 27, 2, default3_mux_table, "rcp_mux", default3_mux_parents,
|
||||
ARRAY_SIZE(default3_mux_parents), 0 },
|
||||
};
|
||||
|
||||
/* configurable pre dividers: */
|
||||
static struct npcm8xx_clk_div_data npcm8xx_pre_divs[] = {
|
||||
{ NPCM8XX_CLKDIV1, 21, 5, "pre_adc", &npcm8xx_muxes[6].hw, CLK_DIVIDER_READ_ONLY, 0, -1 },
|
||||
{ NPCM8XX_CLKDIV1, 26, 2, "ahb", &hw_pre_clk, CLK_DIVIDER_READ_ONLY, CLK_IS_CRITICAL, NPCM8XX_CLK_AHB },
|
||||
};
|
||||
|
||||
/* configurable dividers: */
|
||||
static struct npcm8xx_clk_div_data npcm8xx_divs[] = {
|
||||
{ NPCM8XX_CLKDIV1, 28, 3, "adc", &npcm8xx_pre_divs[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_ADC },
|
||||
{ NPCM8XX_CLKDIV1, 16, 5, "uart", &npcm8xx_muxes[3].hw, 0, 0, NPCM8XX_CLK_UART },
|
||||
{ NPCM8XX_CLKDIV1, 11, 5, "mmc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_MMC },
|
||||
{ NPCM8XX_CLKDIV1, 6, 5, "spi3", &npcm8xx_pre_divs[1].hw, 0, 0, NPCM8XX_CLK_SPI3 },
|
||||
{ NPCM8XX_CLKDIV1, 2, 4, "pci", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_PCI },
|
||||
|
||||
{ NPCM8XX_CLKDIV2, 30, 2, "apb4", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB4 },
|
||||
{ NPCM8XX_CLKDIV2, 28, 2, "apb3", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB3 },
|
||||
{ NPCM8XX_CLKDIV2, 26, 2, "apb2", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB2 },
|
||||
{ NPCM8XX_CLKDIV2, 24, 2, "apb1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB1 },
|
||||
{ NPCM8XX_CLKDIV2, 22, 2, "apb5", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_APB5 },
|
||||
{ NPCM8XX_CLKDIV2, 16, 5, "clkout", &npcm8xx_muxes[8].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_CLKOUT },
|
||||
{ NPCM8XX_CLKDIV2, 13, 3, "gfx", &npcm8xx_muxes[7].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_GFX },
|
||||
{ NPCM8XX_CLKDIV2, 8, 5, "usb_bridge", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU },
|
||||
{ NPCM8XX_CLKDIV2, 4, 4, "usb_host", &npcm8xx_muxes[4].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SU48 },
|
||||
{ NPCM8XX_CLKDIV2, 0, 4, "sdhc", &npcm8xx_muxes[2].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SDHC },
|
||||
|
||||
{ NPCM8XX_CLKDIV3, 16, 8, "spi1", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI1 },
|
||||
{ NPCM8XX_CLKDIV3, 11, 5, "uart2", &npcm8xx_muxes[3].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_UART2 },
|
||||
{ NPCM8XX_CLKDIV3, 6, 5, "spi0", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPI0 },
|
||||
{ NPCM8XX_CLKDIV3, 1, 5, "spix", &npcm8xx_pre_divs[1].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_SPIX },
|
||||
|
||||
{ NPCM8XX_CLKDIV4, 28, 4, "rg", &npcm8xx_muxes[11].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RG },
|
||||
{ NPCM8XX_CLKDIV4, 12, 4, "rcp", &npcm8xx_muxes[12].hw, CLK_DIVIDER_READ_ONLY, 0, NPCM8XX_CLK_RCP },
|
||||
|
||||
{ NPCM8XX_THRTL_CNT, 0, 2, "th", &npcm8xx_muxes[0].hw, CLK_DIVIDER_READ_ONLY | CLK_DIVIDER_POWER_OF_TWO, 0, NPCM8XX_CLK_TH },
|
||||
};
|
||||
|
||||
static unsigned long npcm8xx_clk_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct npcm8xx_clk_pll *pll = to_npcm8xx_clk_pll(hw);
|
||||
unsigned long fbdv, indv, otdv1, otdv2;
|
||||
unsigned int val;
|
||||
u64 ret;
|
||||
|
||||
if (parent_rate == 0) {
|
||||
pr_debug("%s: parent rate is zero\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = readl_relaxed(pll->pllcon);
|
||||
|
||||
indv = FIELD_GET(PLLCON_INDV, val);
|
||||
fbdv = FIELD_GET(PLLCON_FBDV, val);
|
||||
otdv1 = FIELD_GET(PLLCON_OTDV1, val);
|
||||
otdv2 = FIELD_GET(PLLCON_OTDV2, val);
|
||||
|
||||
ret = (u64)parent_rate * fbdv;
|
||||
do_div(ret, indv * otdv1 * otdv2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct clk_ops npcm8xx_clk_pll_ops = {
|
||||
.recalc_rate = npcm8xx_clk_pll_recalc_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *
|
||||
npcm8xx_clk_register_pll(struct device *dev, void __iomem *pllcon,
|
||||
const char *name, const struct clk_parent_data *parent,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct npcm8xx_clk_pll *pll;
|
||||
struct clk_init_data init = {};
|
||||
int ret;
|
||||
|
||||
pll = devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL);
|
||||
if (!pll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &npcm8xx_clk_pll_ops;
|
||||
init.parent_data = parent;
|
||||
init.num_parents = 1;
|
||||
init.flags = flags;
|
||||
|
||||
pll->pllcon = pllcon;
|
||||
pll->hw.init = &init;
|
||||
|
||||
ret = devm_clk_hw_register(dev, &pll->hw);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return &pll->hw;
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(npcm8xx_clk_lock);
|
||||
|
||||
static int npcm8xx_clk_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct npcm_clock_adev *rdev = to_npcm_clock_adev(adev);
|
||||
struct clk_hw_onecell_data *npcm8xx_clk_data;
|
||||
struct device *dev = &adev->dev;
|
||||
struct clk_hw *hw;
|
||||
unsigned int i;
|
||||
|
||||
npcm8xx_clk_data = devm_kzalloc(dev, struct_size(npcm8xx_clk_data, hws,
|
||||
NPCM8XX_NUM_CLOCKS),
|
||||
GFP_KERNEL);
|
||||
if (!npcm8xx_clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
clk_base = rdev->base;
|
||||
|
||||
npcm8xx_clk_data->num = NPCM8XX_NUM_CLOCKS;
|
||||
|
||||
for (i = 0; i < NPCM8XX_NUM_CLOCKS; i++)
|
||||
npcm8xx_clk_data->hws[i] = ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
/* Register plls */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm8xx_pll_clks); i++) {
|
||||
struct npcm8xx_clk_pll_data *pll_clk = &npcm8xx_pll_clks[i];
|
||||
|
||||
hw = npcm8xx_clk_register_pll(dev, clk_base + pll_clk->reg,
|
||||
pll_clk->name, &pll_clk->parent,
|
||||
pll_clk->flags);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll\n");
|
||||
pll_clk->hw = *hw;
|
||||
}
|
||||
|
||||
/* Register fixed dividers */
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "pll1_div2", "pll1", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register fixed div\n");
|
||||
hw_pll1_div2 = *hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "pll2_div2", "pll2", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pll2 div2\n");
|
||||
hw_pll2_div2 = *hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "pll_gfx_div2", "pll_gfx", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register gfx div2\n");
|
||||
hw_gfx_div2 = *hw;
|
||||
|
||||
/* Register muxes */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm8xx_muxes); i++) {
|
||||
struct npcm8xx_clk_mux_data *mux_data = &npcm8xx_muxes[i];
|
||||
|
||||
hw = devm_clk_hw_register_mux_parent_data_table(dev,
|
||||
mux_data->name,
|
||||
mux_data->parent_data,
|
||||
mux_data->num_parents,
|
||||
mux_data->flags,
|
||||
clk_base + NPCM8XX_CLKSEL,
|
||||
mux_data->shift,
|
||||
mux_data->mask,
|
||||
0,
|
||||
mux_data->table,
|
||||
&npcm8xx_clk_lock);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register mux\n");
|
||||
mux_data->hw = *hw;
|
||||
}
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "pre_clk", "cpu_mux", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre clk div2\n");
|
||||
hw_pre_clk = *hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "axi", "th", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register axi div2\n");
|
||||
npcm8xx_clk_data->hws[NPCM8XX_CLK_AXI] = hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor(dev, "atb", "axi", 0, 1, 2);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register atb div2\n");
|
||||
npcm8xx_clk_data->hws[NPCM8XX_CLK_ATB] = hw;
|
||||
|
||||
/* Register pre dividers */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm8xx_pre_divs); i++) {
|
||||
struct npcm8xx_clk_div_data *div_data = &npcm8xx_pre_divs[i];
|
||||
|
||||
hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name,
|
||||
div_data->parent_hw,
|
||||
div_data->flags,
|
||||
clk_base + div_data->reg,
|
||||
div_data->shift,
|
||||
div_data->width,
|
||||
div_data->clk_divider_flags,
|
||||
&npcm8xx_clk_lock);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register pre div\n");
|
||||
div_data->hw = *hw;
|
||||
|
||||
if (div_data->onecell_idx >= 0)
|
||||
npcm8xx_clk_data->hws[div_data->onecell_idx] = hw;
|
||||
}
|
||||
|
||||
/* Register dividers */
|
||||
for (i = 0; i < ARRAY_SIZE(npcm8xx_divs); i++) {
|
||||
struct npcm8xx_clk_div_data *div_data = &npcm8xx_divs[i];
|
||||
|
||||
hw = devm_clk_hw_register_divider_parent_hw(dev, div_data->name,
|
||||
div_data->parent_hw,
|
||||
div_data->flags,
|
||||
clk_base + div_data->reg,
|
||||
div_data->shift,
|
||||
div_data->width,
|
||||
div_data->clk_divider_flags,
|
||||
&npcm8xx_clk_lock);
|
||||
if (IS_ERR(hw))
|
||||
return dev_err_probe(dev, PTR_ERR(hw), "Can't register div\n");
|
||||
|
||||
if (div_data->onecell_idx >= 0)
|
||||
npcm8xx_clk_data->hws[div_data->onecell_idx] = hw;
|
||||
}
|
||||
|
||||
return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
|
||||
npcm8xx_clk_data);
|
||||
}
|
||||
|
||||
static const struct auxiliary_device_id npcm8xx_clock_ids[] = {
|
||||
{
|
||||
.name = "reset_npcm.clk-npcm8xx",
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(auxiliary, npcm8xx_clock_ids);
|
||||
|
||||
static struct auxiliary_driver npcm8xx_clock_driver = {
|
||||
.probe = npcm8xx_clk_probe,
|
||||
.id_table = npcm8xx_clock_ids,
|
||||
};
|
||||
module_auxiliary_driver(npcm8xx_clock_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Clock driver for Nuvoton NPCM8XX BMC SoC");
|
||||
MODULE_AUTHOR("Tomer Maimon <tomer.maimon@nuvoton.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <dt-bindings/clock/fsl,qoriq-clockgen.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
@ -1065,11 +1066,8 @@ static void __init _clockgen_init(struct device_node *np, bool legacy);
|
||||
static void __init legacy_init_clockgen(struct device_node *np)
|
||||
{
|
||||
if (!clockgen.node) {
|
||||
struct device_node *parent_np;
|
||||
|
||||
parent_np = of_get_parent(np);
|
||||
struct device_node *parent_np __free(device_node) = of_get_parent(np);
|
||||
_clockgen_init(parent_np, true);
|
||||
of_node_put(parent_np);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,7 +371,7 @@ static int si514_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id si514_id[] = {
|
||||
{ "si514", 0 },
|
||||
{ "si514" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, si514_id);
|
||||
|
@ -11,13 +11,29 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define VREG_STATE 2
|
||||
#define VREG_STATE 2
|
||||
#define VREG_GRP 0
|
||||
#define TWL6030_CFG_STATE_OFF 0x00
|
||||
#define TWL6030_CFG_STATE_ON 0x01
|
||||
#define TWL6030_CFG_STATE_MASK 0x03
|
||||
#define TWL6030_CFG_STATE_GRP_SHIFT 5
|
||||
#define TWL6030_CFG_STATE_APP_SHIFT 2
|
||||
#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
|
||||
#define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
|
||||
TWL6030_CFG_STATE_APP_SHIFT)
|
||||
#define P1_GRP BIT(0) /* processor power group */
|
||||
#define P2_GRP BIT(1)
|
||||
#define P3_GRP BIT(2)
|
||||
#define ALL_GRP (P1_GRP | P2_GRP | P3_GRP)
|
||||
|
||||
enum twl_type {
|
||||
TWL_TYPE_6030,
|
||||
TWL_TYPE_6032,
|
||||
};
|
||||
|
||||
struct twl_clock_info {
|
||||
struct device *dev;
|
||||
enum twl_type type;
|
||||
u8 base;
|
||||
struct clk_hw hw;
|
||||
};
|
||||
@ -56,14 +72,21 @@ static unsigned long twl_clks_recalc_rate(struct clk_hw *hw,
|
||||
static int twl6032_clks_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
|
||||
int ret;
|
||||
|
||||
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
TWL6030_CFG_STATE_ON);
|
||||
if (ret < 0)
|
||||
dev_err(cinfo->dev, "clk prepare failed\n");
|
||||
if (cinfo->type == TWL_TYPE_6030) {
|
||||
int grp;
|
||||
|
||||
return ret;
|
||||
grp = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_GRP);
|
||||
if (grp < 0)
|
||||
return grp;
|
||||
|
||||
return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
grp << TWL6030_CFG_STATE_GRP_SHIFT |
|
||||
TWL6030_CFG_STATE_ON);
|
||||
}
|
||||
|
||||
return twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
TWL6030_CFG_STATE_ON);
|
||||
}
|
||||
|
||||
static void twl6032_clks_unprepare(struct clk_hw *hw)
|
||||
@ -71,32 +94,21 @@ static void twl6032_clks_unprepare(struct clk_hw *hw)
|
||||
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
|
||||
int ret;
|
||||
|
||||
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
TWL6030_CFG_STATE_OFF);
|
||||
if (cinfo->type == TWL_TYPE_6030)
|
||||
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
ALL_GRP << TWL6030_CFG_STATE_GRP_SHIFT |
|
||||
TWL6030_CFG_STATE_OFF);
|
||||
else
|
||||
ret = twlclk_write(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE,
|
||||
TWL6030_CFG_STATE_OFF);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(cinfo->dev, "clk unprepare failed\n");
|
||||
}
|
||||
|
||||
static int twl6032_clks_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct twl_clock_info *cinfo = to_twl_clks_info(hw);
|
||||
int val;
|
||||
|
||||
val = twlclk_read(cinfo, TWL_MODULE_PM_RECEIVER, VREG_STATE);
|
||||
if (val < 0) {
|
||||
dev_err(cinfo->dev, "clk read failed\n");
|
||||
return val;
|
||||
}
|
||||
|
||||
val &= TWL6030_CFG_STATE_MASK;
|
||||
|
||||
return val == TWL6030_CFG_STATE_ON;
|
||||
}
|
||||
|
||||
static const struct clk_ops twl6032_clks_ops = {
|
||||
.prepare = twl6032_clks_prepare,
|
||||
.unprepare = twl6032_clks_unprepare,
|
||||
.is_prepared = twl6032_clks_is_prepared,
|
||||
.recalc_rate = twl_clks_recalc_rate,
|
||||
};
|
||||
|
||||
@ -155,6 +167,7 @@ static int twl_clks_probe(struct platform_device *pdev)
|
||||
for (i = 0; i < count; i++) {
|
||||
cinfo[i].base = hw_data[i].base;
|
||||
cinfo[i].dev = &pdev->dev;
|
||||
cinfo[i].type = platform_get_device_id(pdev)->driver_data;
|
||||
cinfo[i].hw.init = &hw_data[i].init;
|
||||
ret = devm_clk_hw_register(&pdev->dev, &cinfo[i].hw);
|
||||
if (ret) {
|
||||
@ -176,7 +189,11 @@ static int twl_clks_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct platform_device_id twl_clks_id[] = {
|
||||
{
|
||||
.name = "twl6030-clk",
|
||||
.driver_data = TWL_TYPE_6030,
|
||||
}, {
|
||||
.name = "twl6032-clk",
|
||||
.driver_data = TWL_TYPE_6032,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
@ -608,12 +608,6 @@ bool clk_hw_is_prepared(const struct clk_hw *hw)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_is_prepared);
|
||||
|
||||
bool clk_hw_rate_is_protected(const struct clk_hw *hw)
|
||||
{
|
||||
return clk_core_rate_is_protected(hw->core);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_hw_rate_is_protected);
|
||||
|
||||
bool clk_hw_is_enabled(const struct clk_hw *hw)
|
||||
{
|
||||
return clk_core_is_enabled(hw->core);
|
||||
@ -2536,7 +2530,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
|
||||
rate = clk_core_req_round_rate_nolock(core, req_rate);
|
||||
|
||||
/* bail early if nothing to do */
|
||||
if (rate == clk_core_get_rate_nolock(core))
|
||||
if (rate == clk_core_get_rate_recalc(core))
|
||||
return 0;
|
||||
|
||||
/* fail on a direct rate set of a protected provider */
|
||||
|
@ -203,5 +203,35 @@ int of_clk_hw_register_kunit(struct kunit *test, struct device_node *node, struc
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_hw_register_kunit);
|
||||
|
||||
KUNIT_DEFINE_ACTION_WRAPPER(of_clk_del_provider_wrapper,
|
||||
of_clk_del_provider, struct device_node *);
|
||||
|
||||
/**
|
||||
* of_clk_add_hw_provider_kunit() - Test managed of_clk_add_hw_provider()
|
||||
* @test: The test context
|
||||
* @np: Device node pointer associated with clock provider
|
||||
* @get: Callback for decoding clk_hw
|
||||
* @data: Context pointer for @get callback.
|
||||
*
|
||||
* Just like of_clk_add_hw_provider(), except the clk_hw provider 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_add_hw_provider_kunit(struct kunit *test, struct device_node *np,
|
||||
struct clk_hw *(*get)(struct of_phandle_args *clkspec, void *data),
|
||||
void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = of_clk_add_hw_provider(np, get, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return kunit_add_action_or_reset(test, of_clk_del_provider_wrapper, np);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_clk_add_hw_provider_kunit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("KUnit helpers for clk providers and consumers");
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/clk-conf.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
@ -15,6 +16,7 @@
|
||||
#include <kunit/platform_device.h>
|
||||
#include <kunit/test.h>
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
#include "clk_parent_data_test.h"
|
||||
|
||||
static const struct clk_ops empty_clk_ops = { };
|
||||
@ -3075,7 +3077,326 @@ static struct kunit_suite clk_register_clk_parent_data_device_suite = {
|
||||
.test_cases = clk_register_clk_parent_data_device_test_cases,
|
||||
};
|
||||
|
||||
struct clk_assigned_rates_context {
|
||||
struct clk_dummy_context clk0;
|
||||
struct clk_dummy_context clk1;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct clk_assigned_rates_test_param - Test parameters for clk_assigned_rates test
|
||||
* @desc: Test description
|
||||
* @overlay_begin: Pointer to start of DT overlay to apply for test
|
||||
* @overlay_end: Pointer to end of DT overlay to apply for test
|
||||
* @rate0: Initial rate of first clk
|
||||
* @rate1: Initial rate of second clk
|
||||
* @consumer_test: true if a consumer is being tested
|
||||
*/
|
||||
struct clk_assigned_rates_test_param {
|
||||
const char *desc;
|
||||
u8 *overlay_begin;
|
||||
u8 *overlay_end;
|
||||
unsigned long rate0;
|
||||
unsigned long rate1;
|
||||
bool consumer_test;
|
||||
};
|
||||
|
||||
#define TEST_PARAM_OVERLAY(overlay_name) \
|
||||
.overlay_begin = of_overlay_begin(overlay_name), \
|
||||
.overlay_end = of_overlay_end(overlay_name)
|
||||
|
||||
static void
|
||||
clk_assigned_rates_register_clk(struct kunit *test,
|
||||
struct clk_dummy_context *ctx,
|
||||
struct device_node *np, const char *name,
|
||||
unsigned long rate)
|
||||
{
|
||||
struct clk_init_data init = { };
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_dummy_rate_ops;
|
||||
ctx->hw.init = &init;
|
||||
ctx->rate = rate;
|
||||
|
||||
KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, np, &ctx->hw));
|
||||
KUNIT_ASSERT_EQ(test, ctx->rate, rate);
|
||||
}
|
||||
|
||||
/*
|
||||
* Does most of the work of the test:
|
||||
*
|
||||
* 1. Apply the overlay to test
|
||||
* 2. Register the clk or clks to test
|
||||
* 3. Register the clk provider
|
||||
* 4. Apply clk defaults to the consumer device if this is a consumer test
|
||||
*
|
||||
* The tests will set different test_param values to test different scenarios
|
||||
* and validate that in their test functions.
|
||||
*/
|
||||
static int clk_assigned_rates_test_init(struct kunit *test)
|
||||
{
|
||||
struct device_node *np, *consumer;
|
||||
struct clk_hw_onecell_data *data;
|
||||
struct clk_assigned_rates_context *ctx;
|
||||
u32 clk_cells;
|
||||
const struct clk_assigned_rates_test_param *test_param;
|
||||
|
||||
test_param = test->param_value;
|
||||
|
||||
KUNIT_ASSERT_EQ(test, 0, __of_overlay_apply_kunit(test,
|
||||
test_param->overlay_begin,
|
||||
test_param->overlay_end));
|
||||
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
|
||||
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL));
|
||||
test->priv = ctx;
|
||||
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
|
||||
np = of_find_compatible_node(NULL, NULL, "test,clk-assigned-rates"));
|
||||
of_node_put_kunit(test, np);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, 0, of_property_read_u32(np, "#clock-cells", &clk_cells));
|
||||
/* Only support #clock-cells = <0> or <1> */
|
||||
KUNIT_ASSERT_LT(test, clk_cells, 2);
|
||||
|
||||
clk_assigned_rates_register_clk(test, &ctx->clk0, np,
|
||||
"test_assigned_rate0", test_param->rate0);
|
||||
if (clk_cells == 0) {
|
||||
KUNIT_ASSERT_EQ(test, 0,
|
||||
of_clk_add_hw_provider_kunit(test, np, of_clk_hw_simple_get,
|
||||
&ctx->clk0.hw));
|
||||
} else if (clk_cells == 1) {
|
||||
clk_assigned_rates_register_clk(test, &ctx->clk1, np,
|
||||
"test_assigned_rate1", test_param->rate1);
|
||||
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
|
||||
data = kunit_kzalloc(test, struct_size(data, hws, 2), GFP_KERNEL));
|
||||
data->num = 2;
|
||||
data->hws[0] = &ctx->clk0.hw;
|
||||
data->hws[1] = &ctx->clk1.hw;
|
||||
|
||||
KUNIT_ASSERT_EQ(test, 0,
|
||||
of_clk_add_hw_provider_kunit(test, np, of_clk_hw_onecell_get, data));
|
||||
}
|
||||
|
||||
/* Consumers are optional */
|
||||
if (test_param->consumer_test) {
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test,
|
||||
consumer = of_find_compatible_node(NULL, NULL, "test,clk-consumer"));
|
||||
of_node_put_kunit(test, consumer);
|
||||
|
||||
KUNIT_ASSERT_EQ(test, 0, of_clk_set_defaults(consumer, false));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_assigned_rates_assigns_one(struct kunit *test)
|
||||
{
|
||||
struct clk_assigned_rates_context *ctx = test->priv;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
|
||||
}
|
||||
|
||||
static void clk_assigned_rates_assigns_multiple(struct kunit *test)
|
||||
{
|
||||
struct clk_assigned_rates_context *ctx = test->priv;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
|
||||
KUNIT_EXPECT_EQ(test, ctx->clk1.rate, ASSIGNED_RATES_1_RATE);
|
||||
}
|
||||
|
||||
static void clk_assigned_rates_skips(struct kunit *test)
|
||||
{
|
||||
struct clk_assigned_rates_context *ctx = test->priv;
|
||||
const struct clk_assigned_rates_test_param *test_param = test->param_value;
|
||||
|
||||
KUNIT_EXPECT_NE(test, ctx->clk0.rate, ASSIGNED_RATES_0_RATE);
|
||||
KUNIT_EXPECT_EQ(test, ctx->clk0.rate, test_param->rate0);
|
||||
}
|
||||
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_one_consumer);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_one_consumer);
|
||||
|
||||
/* Test cases that assign one rate */
|
||||
static const struct clk_assigned_rates_test_param clk_assigned_rates_assigns_one_test_params[] = {
|
||||
{
|
||||
/*
|
||||
* Test that a single cell assigned-clock-rates property
|
||||
* assigns the rate when the property is in the provider.
|
||||
*/
|
||||
.desc = "provider assigns",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_one),
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that a single cell assigned-clock-rates property
|
||||
* assigns the rate when the property is in the consumer.
|
||||
*/
|
||||
.desc = "consumer assigns",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_one_consumer),
|
||||
.consumer_test = true,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that a single cell assigned-clock-rates-u64 property
|
||||
* assigns the rate when the property is in the provider.
|
||||
*/
|
||||
.desc = "provider assigns u64",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_one),
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that a single cell assigned-clock-rates-u64 property
|
||||
* assigns the rate when the property is in the consumer.
|
||||
*/
|
||||
.desc = "consumer assigns u64",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_one_consumer),
|
||||
.consumer_test = true,
|
||||
},
|
||||
};
|
||||
KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_assigns_one,
|
||||
clk_assigned_rates_assigns_one_test_params, desc)
|
||||
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_multiple);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_multiple_consumer);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_multiple);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_u64_multiple_consumer);
|
||||
|
||||
/* Test cases that assign multiple rates */
|
||||
static const struct clk_assigned_rates_test_param clk_assigned_rates_assigns_multiple_test_params[] = {
|
||||
{
|
||||
/*
|
||||
* Test that a multiple cell assigned-clock-rates property
|
||||
* assigns the rates when the property is in the provider.
|
||||
*/
|
||||
.desc = "provider assigns",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_multiple),
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that a multiple cell assigned-clock-rates property
|
||||
* assigns the rates when the property is in the consumer.
|
||||
*/
|
||||
.desc = "consumer assigns",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_multiple_consumer),
|
||||
.consumer_test = true,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that a single cell assigned-clock-rates-u64 property
|
||||
* assigns the rate when the property is in the provider.
|
||||
*/
|
||||
.desc = "provider assigns u64",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_multiple),
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that a multiple cell assigned-clock-rates-u64 property
|
||||
* assigns the rates when the property is in the consumer.
|
||||
*/
|
||||
.desc = "consumer assigns u64",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_u64_multiple_consumer),
|
||||
.consumer_test = true,
|
||||
},
|
||||
};
|
||||
KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_assigns_multiple,
|
||||
clk_assigned_rates_assigns_multiple_test_params,
|
||||
desc)
|
||||
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_without);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_without_consumer);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_zero);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_zero_consumer);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_null);
|
||||
OF_OVERLAY_DECLARE(kunit_clk_assigned_rates_null_consumer);
|
||||
|
||||
/* Test cases that skip changing the rate due to malformed DT */
|
||||
static const struct clk_assigned_rates_test_param clk_assigned_rates_skips_test_params[] = {
|
||||
{
|
||||
/*
|
||||
* Test that an assigned-clock-rates property without an assigned-clocks
|
||||
* property fails when the property is in the provider.
|
||||
*/
|
||||
.desc = "provider missing assigned-clocks",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_without),
|
||||
.rate0 = 3000,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that an assigned-clock-rates property without an assigned-clocks
|
||||
* property fails when the property is in the consumer.
|
||||
*/
|
||||
.desc = "consumer missing assigned-clocks",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_without_consumer),
|
||||
.rate0 = 3000,
|
||||
.consumer_test = true,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that an assigned-clock-rates property of zero doesn't
|
||||
* set a rate when the property is in the provider.
|
||||
*/
|
||||
.desc = "provider assigned-clock-rates of zero",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_zero),
|
||||
.rate0 = 3000,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that an assigned-clock-rates property of zero doesn't
|
||||
* set a rate when the property is in the consumer.
|
||||
*/
|
||||
.desc = "consumer assigned-clock-rates of zero",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_zero_consumer),
|
||||
.rate0 = 3000,
|
||||
.consumer_test = true,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that an assigned-clocks property with a null phandle
|
||||
* doesn't set a rate when the property is in the provider.
|
||||
*/
|
||||
.desc = "provider assigned-clocks null phandle",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_null),
|
||||
.rate0 = 3000,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Test that an assigned-clocks property with a null phandle
|
||||
* doesn't set a rate when the property is in the consumer.
|
||||
*/
|
||||
.desc = "provider assigned-clocks null phandle",
|
||||
TEST_PARAM_OVERLAY(kunit_clk_assigned_rates_null_consumer),
|
||||
.rate0 = 3000,
|
||||
.consumer_test = true,
|
||||
},
|
||||
};
|
||||
KUNIT_ARRAY_PARAM_DESC(clk_assigned_rates_skips,
|
||||
clk_assigned_rates_skips_test_params,
|
||||
desc)
|
||||
|
||||
static struct kunit_case clk_assigned_rates_test_cases[] = {
|
||||
KUNIT_CASE_PARAM(clk_assigned_rates_assigns_one,
|
||||
clk_assigned_rates_assigns_one_gen_params),
|
||||
KUNIT_CASE_PARAM(clk_assigned_rates_assigns_multiple,
|
||||
clk_assigned_rates_assigns_multiple_gen_params),
|
||||
KUNIT_CASE_PARAM(clk_assigned_rates_skips,
|
||||
clk_assigned_rates_skips_gen_params),
|
||||
{}
|
||||
};
|
||||
|
||||
/*
|
||||
* Test suite for assigned-clock-rates{-u64} DT property.
|
||||
*/
|
||||
static struct kunit_suite clk_assigned_rates_suite = {
|
||||
.name = "clk_assigned_rates",
|
||||
.test_cases = clk_assigned_rates_test_cases,
|
||||
.init = clk_assigned_rates_test_init,
|
||||
};
|
||||
|
||||
kunit_test_suites(
|
||||
&clk_assigned_rates_suite,
|
||||
&clk_leaf_mux_set_rate_parent_test_suite,
|
||||
&clk_test_suite,
|
||||
&clk_multiple_parents_mux_test_suite,
|
||||
|
@ -254,9 +254,11 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
pll_div = FIELD_PREP(PLL_RDIV_MASK, rate->rdiv) | rate->odiv |
|
||||
FIELD_PREP(PLL_MFI_MASK, rate->mfi);
|
||||
writel_relaxed(pll_div, pll->base + PLL_DIV);
|
||||
readl(pll->base + PLL_DIV);
|
||||
if (pll->flags & CLK_FRACN_GPPLL_FRACN) {
|
||||
writel_relaxed(rate->mfd, pll->base + PLL_DENOMINATOR);
|
||||
writel_relaxed(FIELD_PREP(PLL_MFN_MASK, rate->mfn), pll->base + PLL_NUMERATOR);
|
||||
readl(pll->base + PLL_NUMERATOR);
|
||||
}
|
||||
|
||||
/* Wait for 5us according to fracn mode pll doc */
|
||||
@ -265,6 +267,7 @@ static int clk_fracn_gppll_set_rate(struct clk_hw *hw, unsigned long drate,
|
||||
/* Enable Powerup */
|
||||
tmp |= POWERUP_MASK;
|
||||
writel_relaxed(tmp, pll->base + PLL_CTRL);
|
||||
readl(pll->base + PLL_CTRL);
|
||||
|
||||
/* Wait Lock */
|
||||
ret = clk_fracn_gppll_wait_lock(pll);
|
||||
@ -302,14 +305,15 @@ static int clk_fracn_gppll_prepare(struct clk_hw *hw)
|
||||
|
||||
val |= POWERUP_MASK;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
|
||||
val |= CLKMUX_EN;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
readl(pll->base + PLL_CTRL);
|
||||
|
||||
ret = clk_fracn_gppll_wait_lock(pll);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val |= CLKMUX_EN;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
|
||||
val &= ~CLKMUX_BYPASS;
|
||||
writel_relaxed(val, pll->base + PLL_CTRL);
|
||||
|
||||
|
@ -294,9 +294,9 @@ static int clk_imx_acm_attach_pm_domains(struct device *dev,
|
||||
DL_FLAG_STATELESS |
|
||||
DL_FLAG_PM_RUNTIME |
|
||||
DL_FLAG_RPM_ACTIVE);
|
||||
if (IS_ERR(dev_pm->pd_dev_link[i])) {
|
||||
if (!dev_pm->pd_dev_link[i]) {
|
||||
dev_pm_domain_detach(dev_pm->pd_dev[i], false);
|
||||
ret = PTR_ERR(dev_pm->pd_dev_link[i]);
|
||||
ret = -EINVAL;
|
||||
goto detach_pm;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,11 @@
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
#define IMX93_CLK_END 207
|
||||
|
||||
#define PLAT_IMX93 BIT(0)
|
||||
#define PLAT_IMX91 BIT(1)
|
||||
|
||||
enum clk_sel {
|
||||
LOW_SPEED_IO_SEL,
|
||||
NON_IO_SEL,
|
||||
@ -53,6 +58,7 @@ static const struct imx93_clk_root {
|
||||
u32 off;
|
||||
enum clk_sel sel;
|
||||
unsigned long flags;
|
||||
unsigned long plat;
|
||||
} root_array[] = {
|
||||
/* a55/m33/bus critical clk for system run */
|
||||
{ IMX93_CLK_A55_PERIPH, "a55_periph_root", 0x0000, FAST_SEL, CLK_IS_CRITICAL },
|
||||
@ -63,7 +69,7 @@ static const struct imx93_clk_root {
|
||||
{ IMX93_CLK_BUS_AON, "bus_aon_root", 0x0300, LOW_SPEED_IO_SEL, CLK_IS_CRITICAL },
|
||||
{ IMX93_CLK_WAKEUP_AXI, "wakeup_axi_root", 0x0380, FAST_SEL, CLK_IS_CRITICAL },
|
||||
{ IMX93_CLK_SWO_TRACE, "swo_trace_root", 0x0400, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_M33_SYSTICK, "m33_systick_root", 0x0480, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_FLEXIO1, "flexio1_root", 0x0500, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_FLEXIO2, "flexio2_root", 0x0580, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_LPTMR1, "lptmr1_root", 0x0700, LOW_SPEED_IO_SEL, },
|
||||
@ -120,15 +126,15 @@ static const struct imx93_clk_root {
|
||||
{ IMX93_CLK_HSIO_ACSCAN_80M, "hsio_acscan_80m_root", 0x1f80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_HSIO_ACSCAN_480M, "hsio_acscan_480m_root", 0x2000, MISC_SEL, },
|
||||
{ IMX93_CLK_NIC_AXI, "nic_axi_root", 0x2080, FAST_SEL, CLK_IS_CRITICAL, },
|
||||
{ IMX93_CLK_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, },
|
||||
{ IMX93_CLK_ML_APB, "ml_apb_root", 0x2180, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_ML, "ml_root", 0x2200, FAST_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_MEDIA_AXI, "media_axi_root", 0x2280, FAST_SEL, },
|
||||
{ IMX93_CLK_MEDIA_APB, "media_apb_root", 0x2300, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, },
|
||||
{ IMX93_CLK_MEDIA_LDB, "media_ldb_root", 0x2380, VIDEO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_MEDIA_DISP_PIX, "media_disp_pix_root", 0x2400, VIDEO_SEL, },
|
||||
{ IMX93_CLK_CAM_PIX, "cam_pix_root", 0x2480, VIDEO_SEL, },
|
||||
{ IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, },
|
||||
{ IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, },
|
||||
{ IMX93_CLK_MIPI_TEST_BYTE, "mipi_test_byte_root", 0x2500, VIDEO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_MIPI_PHY_CFG, "mipi_phy_cfg_root", 0x2580, VIDEO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_ADC, "adc_root", 0x2700, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_PDM, "pdm_root", 0x2780, AUDIO_SEL, },
|
||||
{ IMX93_CLK_TSTMR1, "tstmr1_root", 0x2800, LOW_SPEED_IO_SEL, },
|
||||
@ -137,13 +143,16 @@ static const struct imx93_clk_root {
|
||||
{ IMX93_CLK_MQS2, "mqs2_root", 0x2980, AUDIO_SEL, },
|
||||
{ IMX93_CLK_AUDIO_XCVR, "audio_xcvr_root", 0x2a00, NON_IO_SEL, },
|
||||
{ IMX93_CLK_SPDIF, "spdif_root", 0x2a80, AUDIO_SEL, },
|
||||
{ IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, },
|
||||
{ IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, },
|
||||
{ IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_ENET, "enet_root", 0x2b00, NON_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_ENET_TIMER1, "enet_timer1_root", 0x2b80, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_ENET_TIMER2, "enet_timer2_root", 0x2c00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_ENET_REF, "enet_ref_root", 0x2c80, NON_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_ENET_REF_PHY, "enet_ref_phy_root", 0x2d00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX91_CLK_ENET1_QOS_TSN, "enet1_qos_tsn_root", 0x2b00, NON_IO_SEL, 0, PLAT_IMX91, },
|
||||
{ IMX91_CLK_ENET_TIMER, "enet_timer_root", 0x2b80, LOW_SPEED_IO_SEL, 0, PLAT_IMX91, },
|
||||
{ IMX91_CLK_ENET2_REGULAR, "enet2_regular_root", 0x2c80, NON_IO_SEL, 0, PLAT_IMX91, },
|
||||
{ IMX93_CLK_I3C1_SLOW, "i3c1_slow_root", 0x2d80, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_I3C2_SLOW, "i3c2_slow_root", 0x2e00, LOW_SPEED_IO_SEL, 0, PLAT_IMX93, },
|
||||
{ IMX93_CLK_USB_PHY_BURUNIN, "usb_phy_root", 0x2e80, LOW_SPEED_IO_SEL, },
|
||||
{ IMX93_CLK_PAL_CAME_SCAN, "pal_came_scan_root", 0x2f00, MISC_SEL, }
|
||||
};
|
||||
@ -155,6 +164,7 @@ static const struct imx93_clk_ccgr {
|
||||
u32 off;
|
||||
unsigned long flags;
|
||||
u32 *shared_count;
|
||||
unsigned long plat;
|
||||
} ccgr_array[] = {
|
||||
{ IMX93_CLK_A55_GATE, "a55_alt", "a55_alt_root", 0x8000, },
|
||||
/* M33 critical clk for system run */
|
||||
@ -244,8 +254,10 @@ static const struct imx93_clk_ccgr {
|
||||
{ IMX93_CLK_AUD_XCVR_GATE, "aud_xcvr", "audio_xcvr_root", 0x9b80, },
|
||||
{ IMX93_CLK_SPDIF_GATE, "spdif", "spdif_root", 0x9c00, },
|
||||
{ IMX93_CLK_HSIO_32K_GATE, "hsio_32k", "osc_32k", 0x9dc0, },
|
||||
{ IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, },
|
||||
{ IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, },
|
||||
{ IMX93_CLK_ENET1_GATE, "enet1", "wakeup_axi_root", 0x9e00, 0, NULL, PLAT_IMX93, },
|
||||
{ IMX93_CLK_ENET_QOS_GATE, "enet_qos", "wakeup_axi_root", 0x9e40, 0, NULL, PLAT_IMX93, },
|
||||
{ IMX91_CLK_ENET2_REGULAR_GATE, "enet2_regular", "wakeup_axi_root", 0x9e00, 0, NULL, PLAT_IMX91, },
|
||||
{ IMX91_CLK_ENET1_QOS_TSN_GATE, "enet1_qos_tsn", "wakeup_axi_root", 0x9e40, 0, NULL, PLAT_IMX91, },
|
||||
/* Critical because clk accessed during CPU idle */
|
||||
{ IMX93_CLK_SYS_CNT_GATE, "sys_cnt", "osc_24m", 0x9e80, CLK_IS_CRITICAL},
|
||||
{ IMX93_CLK_TSTMR1_GATE, "tstmr1", "bus_aon_root", 0x9ec0, },
|
||||
@ -265,6 +277,7 @@ static int imx93_clocks_probe(struct platform_device *pdev)
|
||||
const struct imx93_clk_ccgr *ccgr;
|
||||
void __iomem *base, *anatop_base;
|
||||
int i, ret;
|
||||
const unsigned long plat = (unsigned long)device_get_match_data(&pdev->dev);
|
||||
|
||||
clk_hw_data = devm_kzalloc(dev, struct_size(clk_hw_data, hws,
|
||||
IMX93_CLK_END), GFP_KERNEL);
|
||||
@ -314,17 +327,20 @@ static int imx93_clocks_probe(struct platform_device *pdev)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(root_array); i++) {
|
||||
root = &root_array[i];
|
||||
clks[root->clk] = imx93_clk_composite_flags(root->name,
|
||||
parent_names[root->sel],
|
||||
4, base + root->off, 3,
|
||||
root->flags);
|
||||
if (!root->plat || root->plat & plat)
|
||||
clks[root->clk] = imx93_clk_composite_flags(root->name,
|
||||
parent_names[root->sel],
|
||||
4, base + root->off, 3,
|
||||
root->flags);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ccgr_array); i++) {
|
||||
ccgr = &ccgr_array[i];
|
||||
clks[ccgr->clk] = imx93_clk_gate(NULL, ccgr->name, ccgr->parent_name,
|
||||
ccgr->flags, base + ccgr->off, 0, 1, 1, 3,
|
||||
ccgr->shared_count);
|
||||
if (!ccgr->plat || ccgr->plat & plat)
|
||||
clks[ccgr->clk] = imx93_clk_gate(NULL,
|
||||
ccgr->name, ccgr->parent_name,
|
||||
ccgr->flags, base + ccgr->off, 0, 1, 1, 3,
|
||||
ccgr->shared_count);
|
||||
}
|
||||
|
||||
clks[IMX93_CLK_A55_SEL] = imx_clk_hw_mux2("a55_sel", base + 0x4820, 0, 1, a55_core_sels,
|
||||
@ -354,7 +370,8 @@ static int imx93_clocks_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id imx93_clk_of_match[] = {
|
||||
{ .compatible = "fsl,imx93-ccm" },
|
||||
{ .compatible = "fsl,imx93-ccm", .data = (void *)PLAT_IMX93 },
|
||||
{ .compatible = "fsl,imx91-ccm", .data = (void *)PLAT_IMX91 },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx93_clk_of_match);
|
||||
|
@ -277,6 +277,25 @@ static const struct imx95_blk_ctl_dev_data netcmix_dev_data = {
|
||||
.clk_reg_offset = 0,
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_clk_dev_data hsio_blk_ctl_clk_dev_data[] = {
|
||||
[0] = {
|
||||
.name = "hsio_blk_ctl_clk",
|
||||
.parent_names = (const char *[]){ "hsio_pll", },
|
||||
.num_parents = 1,
|
||||
.reg = 0,
|
||||
.bit_idx = 6,
|
||||
.bit_width = 1,
|
||||
.type = CLK_GATE,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct imx95_blk_ctl_dev_data hsio_blk_ctl_dev_data = {
|
||||
.num_clks = 1,
|
||||
.clk_dev_data = hsio_blk_ctl_clk_dev_data,
|
||||
.clk_reg_offset = 0,
|
||||
};
|
||||
|
||||
static int imx95_bc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -447,6 +466,7 @@ static const struct of_device_id imx95_bc_of_match[] = {
|
||||
{ .compatible = "nxp,imx95-display-master-csr", },
|
||||
{ .compatible = "nxp,imx95-lvds-csr", .data = &lvds_csr_dev_data },
|
||||
{ .compatible = "nxp,imx95-display-csr", .data = &dispmix_csr_dev_data },
|
||||
{ .compatible = "nxp,imx95-hsio-blk-ctl", .data = &hsio_blk_ctl_dev_data },
|
||||
{ .compatible = "nxp,imx95-vpu-csr", .data = &vpublk_dev_data },
|
||||
{ .compatible = "nxp,imx95-netcmix-blk-ctrl", .data = &netcmix_dev_data},
|
||||
{ /* Sentinel */ },
|
||||
|
@ -6,10 +6,12 @@
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "clk-scu.h"
|
||||
|
||||
@ -41,6 +43,29 @@ struct clk_lpcg_scu {
|
||||
|
||||
#define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
|
||||
|
||||
/* e10858 -LPCG clock gating register synchronization errata */
|
||||
static void lpcg_e10858_writel(unsigned long rate, void __iomem *reg, u32 val)
|
||||
{
|
||||
writel(val, reg);
|
||||
|
||||
if (rate >= 24 * HZ_PER_MHZ || rate == 0) {
|
||||
/*
|
||||
* The time taken to access the LPCG registers from the AP core
|
||||
* through the interconnect is longer than the minimum delay
|
||||
* of 4 clock cycles required by the errata.
|
||||
* Adding a readl will provide sufficient delay to prevent
|
||||
* back-to-back writes.
|
||||
*/
|
||||
readl(reg);
|
||||
} else {
|
||||
/*
|
||||
* For clocks running below 24MHz, wait a minimum of
|
||||
* 4 clock cycles.
|
||||
*/
|
||||
ndelay(4 * (DIV_ROUND_UP(1000 * HZ_PER_MHZ, rate)));
|
||||
}
|
||||
}
|
||||
|
||||
static int clk_lpcg_scu_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_lpcg_scu *clk = to_clk_lpcg_scu(hw);
|
||||
@ -57,7 +82,8 @@ static int clk_lpcg_scu_enable(struct clk_hw *hw)
|
||||
val |= CLK_GATE_SCU_LPCG_HW_SEL;
|
||||
|
||||
reg |= val << clk->bit_idx;
|
||||
writel(reg, clk->reg);
|
||||
|
||||
lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg);
|
||||
|
||||
spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
|
||||
|
||||
@ -74,7 +100,7 @@ static void clk_lpcg_scu_disable(struct clk_hw *hw)
|
||||
|
||||
reg = readl_relaxed(clk->reg);
|
||||
reg &= ~(CLK_GATE_SCU_LPCG_MASK << clk->bit_idx);
|
||||
writel(reg, clk->reg);
|
||||
lpcg_e10858_writel(clk_hw_get_rate(hw), clk->reg, reg);
|
||||
|
||||
spin_unlock_irqrestore(&imx_lpcg_scu_lock, flags);
|
||||
}
|
||||
@ -135,6 +161,9 @@ static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
|
||||
{
|
||||
struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
|
||||
|
||||
if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
|
||||
return 0;
|
||||
|
||||
clk->state = readl_relaxed(clk->reg);
|
||||
dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
|
||||
|
||||
@ -145,13 +174,11 @@ static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
|
||||
{
|
||||
struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* FIXME: Sometimes writes don't work unless the CPU issues
|
||||
* them twice
|
||||
*/
|
||||
if (!strncmp("hdmi_lpcg", clk_hw_get_name(&clk->hw), strlen("hdmi_lpcg")))
|
||||
return 0;
|
||||
|
||||
writel(clk->state, clk->reg);
|
||||
writel(clk->state, clk->reg);
|
||||
lpcg_e10858_writel(0, clk->reg, clk->state);
|
||||
dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
|
||||
|
||||
return 0;
|
||||
|
@ -596,7 +596,7 @@ static int __maybe_unused imx_clk_scu_suspend(struct device *dev)
|
||||
clk->rate = clk_scu_recalc_rate(&clk->hw, 0);
|
||||
else
|
||||
clk->rate = clk_hw_get_rate(&clk->hw);
|
||||
clk->is_enabled = clk_hw_is_enabled(&clk->hw);
|
||||
clk->is_enabled = clk_hw_is_prepared(&clk->hw);
|
||||
|
||||
if (clk->parent)
|
||||
dev_dbg(dev, "save parent %s idx %u\n", clk_hw_get_name(clk->parent),
|
||||
|
8
drivers/clk/kunit_clk_assigned_rates.h
Normal file
8
drivers/clk/kunit_clk_assigned_rates.h
Normal file
@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _KUNIT_CLK_ASSIGNED_RATES_H
|
||||
#define _KUNIT_CLK_ASSIGNED_RATES_H
|
||||
|
||||
#define ASSIGNED_RATES_0_RATE 1600000
|
||||
#define ASSIGNED_RATES_1_RATE 9700000
|
||||
|
||||
#endif
|
16
drivers/clk/kunit_clk_assigned_rates_multiple.dtso
Normal file
16
drivers/clk/kunit_clk_assigned_rates_multiple.dtso
Normal file
@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <1>;
|
||||
assigned-clocks = <&clk 0>,
|
||||
<&clk 1>;
|
||||
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>,
|
||||
<ASSIGNED_RATES_1_RATE>;
|
||||
};
|
||||
};
|
20
drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso
Normal file
20
drivers/clk/kunit_clk_assigned_rates_multiple_consumer.dtso
Normal file
@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
kunit-clock-consumer {
|
||||
compatible = "test,clk-consumer";
|
||||
assigned-clocks = <&clk 0>,
|
||||
<&clk 1>;
|
||||
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>,
|
||||
<ASSIGNED_RATES_1_RATE>;
|
||||
};
|
||||
};
|
14
drivers/clk/kunit_clk_assigned_rates_null.dtso
Normal file
14
drivers/clk/kunit_clk_assigned_rates_null.dtso
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
assigned-clocks = <0>;
|
||||
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
|
||||
};
|
||||
};
|
18
drivers/clk/kunit_clk_assigned_rates_null_consumer.dtso
Normal file
18
drivers/clk/kunit_clk_assigned_rates_null_consumer.dtso
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
kunit-clock-consumer {
|
||||
compatible = "test,clk-consumer";
|
||||
assigned-clocks = <0>;
|
||||
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
|
||||
};
|
||||
};
|
14
drivers/clk/kunit_clk_assigned_rates_one.dtso
Normal file
14
drivers/clk/kunit_clk_assigned_rates_one.dtso
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
assigned-clocks = <&clk>;
|
||||
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
|
||||
};
|
||||
};
|
18
drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso
Normal file
18
drivers/clk/kunit_clk_assigned_rates_one_consumer.dtso
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
kunit-clock-consumer {
|
||||
compatible = "test,clk-consumer";
|
||||
assigned-clocks = <&clk>;
|
||||
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
|
||||
};
|
||||
};
|
16
drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
Normal file
16
drivers/clk/kunit_clk_assigned_rates_u64_multiple.dtso
Normal file
@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <1>;
|
||||
assigned-clocks = <&clk 0>,
|
||||
<&clk 1>;
|
||||
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
|
||||
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
|
||||
};
|
||||
};
|
@ -0,0 +1,20 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <1>;
|
||||
};
|
||||
|
||||
kunit-clock-consumer {
|
||||
compatible = "test,clk-consumer";
|
||||
assigned-clocks = <&clk 0>,
|
||||
<&clk 1>;
|
||||
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>,
|
||||
/bits/ 64 <ASSIGNED_RATES_1_RATE>;
|
||||
};
|
||||
};
|
14
drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
Normal file
14
drivers/clk/kunit_clk_assigned_rates_u64_one.dtso
Normal file
@ -0,0 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
assigned-clocks = <&clk>;
|
||||
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
|
||||
};
|
||||
};
|
18
drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
Normal file
18
drivers/clk/kunit_clk_assigned_rates_u64_one_consumer.dtso
Normal file
@ -0,0 +1,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
kunit-clock-consumer {
|
||||
compatible = "test,clk-consumer";
|
||||
assigned-clocks = <&clk>;
|
||||
assigned-clock-rates-u64 = /bits/ 64 <ASSIGNED_RATES_0_RATE>;
|
||||
};
|
||||
};
|
13
drivers/clk/kunit_clk_assigned_rates_without.dtso
Normal file
13
drivers/clk/kunit_clk_assigned_rates_without.dtso
Normal file
@ -0,0 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
|
||||
};
|
||||
};
|
17
drivers/clk/kunit_clk_assigned_rates_without_consumer.dtso
Normal file
17
drivers/clk/kunit_clk_assigned_rates_without_consumer.dtso
Normal file
@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
#include "kunit_clk_assigned_rates.h"
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
kunit-clock-consumer {
|
||||
compatible = "test,clk-consumer";
|
||||
assigned-clock-rates = <ASSIGNED_RATES_0_RATE>;
|
||||
};
|
||||
};
|
12
drivers/clk/kunit_clk_assigned_rates_zero.dtso
Normal file
12
drivers/clk/kunit_clk_assigned_rates_zero.dtso
Normal file
@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
assigned-clocks = <&clk>;
|
||||
assigned-clock-rates = <0>;
|
||||
};
|
||||
};
|
16
drivers/clk/kunit_clk_assigned_rates_zero_consumer.dtso
Normal file
16
drivers/clk/kunit_clk_assigned_rates_zero_consumer.dtso
Normal file
@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/dts-v1/;
|
||||
/plugin/;
|
||||
|
||||
&{/} {
|
||||
clk: kunit-clock {
|
||||
compatible = "test,clk-assigned-rates";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
kunit-clock-consumer {
|
||||
compatible = "test,clk-consumer";
|
||||
assigned-clocks = <&clk>;
|
||||
assigned-clock-rates = <0>;
|
||||
};
|
||||
};
|
@ -124,6 +124,43 @@ config COMMON_CLK_MT2712_VENCSYS
|
||||
help
|
||||
This driver supports MediaTek MT2712 vencsys clocks.
|
||||
|
||||
config COMMON_CLK_MT6735
|
||||
tristate "Main clock drivers for MediaTek MT6735"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
select COMMON_CLK_MEDIATEK
|
||||
help
|
||||
This enables drivers for clocks and resets provided
|
||||
by apmixedsys, topckgen, infracfg and pericfg on the
|
||||
MediaTek MT6735 SoC.
|
||||
|
||||
config COMMON_CLK_MT6735_IMGSYS
|
||||
tristate "Clock driver for MediaTek MT6735 imgsys"
|
||||
depends on COMMON_CLK_MT6735
|
||||
help
|
||||
This enables a driver for clocks provided by imgsys
|
||||
on the MediaTek MT6735 SoC.
|
||||
|
||||
config COMMON_CLK_MT6735_MFGCFG
|
||||
tristate "Clock driver for MediaTek MT6735 mfgcfg"
|
||||
depends on COMMON_CLK_MT6735
|
||||
help
|
||||
This enables a driver for clocks and resets provided
|
||||
by mfgcfg on the MediaTek MT6735 SoC.
|
||||
|
||||
config COMMON_CLK_MT6735_VDECSYS
|
||||
tristate "Clock driver for MediaTek MT6735 vdecsys"
|
||||
depends on COMMON_CLK_MT6735
|
||||
help
|
||||
This enables a driver for clocks and resets provided
|
||||
by vdecsys on the MediaTek MT6735 SoC.
|
||||
|
||||
config COMMON_CLK_MT6735_VENCSYS
|
||||
tristate "Clock driver for MediaTek MT6735 vencsys"
|
||||
depends on COMMON_CLK_MT6735
|
||||
help
|
||||
This enables a driver for clocks provided by vencsys
|
||||
on the MediaTek MT6735 SoC.
|
||||
|
||||
config COMMON_CLK_MT6765
|
||||
bool "Clock driver for MediaTek MT6765"
|
||||
depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST
|
||||
@ -887,13 +924,6 @@ config COMMON_CLK_MT8195_APUSYS
|
||||
help
|
||||
This driver supports MediaTek MT8195 AI Processor Unit System clocks.
|
||||
|
||||
config COMMON_CLK_MT8195_AUDSYS
|
||||
tristate "Clock driver for MediaTek MT8195 audsys"
|
||||
depends on COMMON_CLK_MT8195
|
||||
default COMMON_CLK_MT8195
|
||||
help
|
||||
This driver supports MediaTek MT8195 audsys clocks.
|
||||
|
||||
config COMMON_CLK_MT8195_IMP_IIC_WRAP
|
||||
tristate "Clock driver for MediaTek MT8195 imp_iic_wrap"
|
||||
depends on COMMON_CLK_MT8195
|
||||
@ -908,14 +938,6 @@ config COMMON_CLK_MT8195_MFGCFG
|
||||
help
|
||||
This driver supports MediaTek MT8195 mfgcfg clocks.
|
||||
|
||||
config COMMON_CLK_MT8195_MSDC
|
||||
tristate "Clock driver for MediaTek MT8195 msdc"
|
||||
depends on COMMON_CLK_MT8195
|
||||
default COMMON_CLK_MT8195
|
||||
help
|
||||
This driver supports MediaTek MT8195 MMC and SD Controller's
|
||||
msdc and msdc_top clocks.
|
||||
|
||||
config COMMON_CLK_MT8195_SCP_ADSP
|
||||
tristate "Clock driver for MediaTek MT8195 scp_adsp"
|
||||
depends on COMMON_CLK_MT8195
|
||||
|
@ -2,6 +2,11 @@
|
||||
obj-$(CONFIG_COMMON_CLK_MEDIATEK) += clk-mtk.o clk-pll.o clk-gate.o clk-apmixed.o clk-cpumux.o reset.o clk-mux.o
|
||||
obj-$(CONFIG_COMMON_CLK_MEDIATEK_FHCTL) += clk-fhctl.o clk-pllfh.o
|
||||
|
||||
obj-$(CONFIG_COMMON_CLK_MT6735) += clk-mt6735-apmixedsys.o clk-mt6735-infracfg.o clk-mt6735-pericfg.o clk-mt6735-topckgen.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT6735_IMGSYS) += clk-mt6735-imgsys.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT6735_MFGCFG) += clk-mt6735-mfgcfg.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT6735_VDECSYS) += clk-mt6735-vdecsys.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT6735_VENCSYS) += clk-mt6735-vencsys.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT6765) += clk-mt6765.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT6765_AUDIOSYS) += clk-mt6765-audio.o
|
||||
obj-$(CONFIG_COMMON_CLK_MT6765_CAMSYS) += clk-mt6765-cam.o
|
||||
|
137
drivers/clk/mediatek/clk-mt6735-apmixedsys.c
Normal file
137
drivers/clk/mediatek/clk-mt6735-apmixedsys.c
Normal file
@ -0,0 +1,137 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-pll.h"
|
||||
|
||||
#include <dt-bindings/clock/mediatek,mt6735-apmixedsys.h>
|
||||
|
||||
#define AP_PLL_CON_5 0x014
|
||||
#define ARMPLL_CON0 0x200
|
||||
#define ARMPLL_CON1 0x204
|
||||
#define ARMPLL_PWR_CON0 0x20c
|
||||
#define MAINPLL_CON0 0x210
|
||||
#define MAINPLL_CON1 0x214
|
||||
#define MAINPLL_PWR_CON0 0x21c
|
||||
#define UNIVPLL_CON0 0x220
|
||||
#define UNIVPLL_CON1 0x224
|
||||
#define UNIVPLL_PWR_CON0 0x22c
|
||||
#define MMPLL_CON0 0x230
|
||||
#define MMPLL_CON1 0x234
|
||||
#define MMPLL_PWR_CON0 0x23c
|
||||
#define MSDCPLL_CON0 0x240
|
||||
#define MSDCPLL_CON1 0x244
|
||||
#define MSDCPLL_PWR_CON0 0x24c
|
||||
#define VENCPLL_CON0 0x250
|
||||
#define VENCPLL_CON1 0x254
|
||||
#define VENCPLL_PWR_CON0 0x25c
|
||||
#define TVDPLL_CON0 0x260
|
||||
#define TVDPLL_CON1 0x264
|
||||
#define TVDPLL_PWR_CON0 0x26c
|
||||
#define APLL1_CON0 0x270
|
||||
#define APLL1_CON1 0x274
|
||||
#define APLL1_CON2 0x278
|
||||
#define APLL1_PWR_CON0 0x280
|
||||
#define APLL2_CON0 0x284
|
||||
#define APLL2_CON1 0x288
|
||||
#define APLL2_CON2 0x28c
|
||||
#define APLL2_PWR_CON0 0x294
|
||||
|
||||
#define CON0_RST_BAR BIT(24)
|
||||
|
||||
#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _rst_bar_mask, \
|
||||
_pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \
|
||||
_tuner_en_bit, _pcw_reg, _pcwbits, _flags) { \
|
||||
.id = _id, \
|
||||
.name = _name, \
|
||||
.parent_name = "clk26m", \
|
||||
.reg = _reg, \
|
||||
.pwr_reg = _pwr_reg, \
|
||||
.en_mask = _en_mask, \
|
||||
.rst_bar_mask = _rst_bar_mask, \
|
||||
.pd_reg = _pd_reg, \
|
||||
.pd_shift = _pd_shift, \
|
||||
.tuner_reg = _tuner_reg, \
|
||||
.tuner_en_reg = _tuner_en_reg, \
|
||||
.tuner_en_bit = _tuner_en_bit, \
|
||||
.pcw_reg = _pcw_reg, \
|
||||
.pcw_chg_reg = _pcw_reg, \
|
||||
.pcwbits = _pcwbits, \
|
||||
.flags = _flags, \
|
||||
}
|
||||
|
||||
static const struct mtk_pll_data apmixedsys_plls[] = {
|
||||
PLL(CLK_APMIXED_ARMPLL, "armpll", ARMPLL_CON0, ARMPLL_PWR_CON0, 0x00000001, 0, ARMPLL_CON1, 24, 0, 0, 0, ARMPLL_CON1, 21, PLL_AO),
|
||||
PLL(CLK_APMIXED_MAINPLL, "mainpll", MAINPLL_CON0, MAINPLL_PWR_CON0, 0xf0000101, CON0_RST_BAR, MAINPLL_CON1, 24, 0, 0, 0, MAINPLL_CON1, 21, HAVE_RST_BAR),
|
||||
PLL(CLK_APMIXED_UNIVPLL, "univpll", UNIVPLL_CON0, UNIVPLL_PWR_CON0, 0xfc000001, CON0_RST_BAR, UNIVPLL_CON1, 24, 0, 0, 0, UNIVPLL_CON1, 21, HAVE_RST_BAR),
|
||||
PLL(CLK_APMIXED_MMPLL, "mmpll", MMPLL_CON0, MMPLL_PWR_CON0, 0x00000001, 0, MMPLL_CON1, 24, 0, 0, 0, MMPLL_CON1, 21, 0),
|
||||
PLL(CLK_APMIXED_MSDCPLL, "msdcpll", MSDCPLL_CON0, MSDCPLL_PWR_CON0, 0x00000001, 0, MSDCPLL_CON1, 24, 0, 0, 0, MSDCPLL_CON1, 21, 0),
|
||||
PLL(CLK_APMIXED_VENCPLL, "vencpll", VENCPLL_CON0, VENCPLL_PWR_CON0, 0x00000001, CON0_RST_BAR, VENCPLL_CON1, 24, 0, 0, 0, VENCPLL_CON1, 21, HAVE_RST_BAR),
|
||||
PLL(CLK_APMIXED_TVDPLL, "tvdpll", TVDPLL_CON0, TVDPLL_PWR_CON0, 0x00000001, 0, TVDPLL_CON1, 24, 0, 0, 0, TVDPLL_CON1, 21, 0),
|
||||
PLL(CLK_APMIXED_APLL1, "apll1", APLL1_CON0, APLL1_PWR_CON0, 0x00000001, 0, APLL1_CON0, 4, APLL1_CON2, AP_PLL_CON_5, 0, APLL1_CON1, 31, 0),
|
||||
PLL(CLK_APMIXED_APLL2, "apll2", APLL2_CON0, APLL2_PWR_CON0, 0x00000001, 0, APLL2_CON0, 4, APLL2_CON2, AP_PLL_CON_5, 1, APLL2_CON1, 31, 0)
|
||||
};
|
||||
|
||||
static int clk_mt6735_apmixed_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *base;
|
||||
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
int ret;
|
||||
|
||||
base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
clk_data = mtk_devm_alloc_clk_data(&pdev->dev, ARRAY_SIZE(apmixedsys_plls));
|
||||
if (!clk_data)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, clk_data);
|
||||
|
||||
ret = mtk_clk_register_plls(pdev->dev.of_node, apmixedsys_plls,
|
||||
ARRAY_SIZE(apmixedsys_plls), clk_data);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register PLLs: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_onecell_get,
|
||||
clk_data);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register clock provider: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void clk_mt6735_apmixed_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct clk_hw_onecell_data *clk_data = platform_get_drvdata(pdev);
|
||||
|
||||
mtk_clk_unregister_plls(apmixedsys_plls, ARRAY_SIZE(apmixedsys_plls), clk_data);
|
||||
}
|
||||
|
||||
static const struct of_device_id of_match_mt6735_apmixedsys[] = {
|
||||
{ .compatible = "mediatek,mt6735-apmixedsys" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_match_mt6735_apmixedsys);
|
||||
|
||||
static struct platform_driver clk_mt6735_apmixedsys = {
|
||||
.probe = clk_mt6735_apmixed_probe,
|
||||
.remove = clk_mt6735_apmixed_remove,
|
||||
.driver = {
|
||||
.name = "clk-mt6735-apmixedsys",
|
||||
.of_match_table = of_match_mt6735_apmixedsys,
|
||||
},
|
||||
};
|
||||
module_platform_driver(clk_mt6735_apmixedsys);
|
||||
|
||||
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
|
||||
MODULE_DESCRIPTION("MediaTek MT6735 apmixedsys clock driver");
|
||||
MODULE_LICENSE("GPL");
|
57
drivers/clk/mediatek/clk-mt6735-imgsys.c
Normal file
57
drivers/clk/mediatek/clk-mt6735-imgsys.c
Normal file
@ -0,0 +1,57 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mtk.h"
|
||||
|
||||
#include <dt-bindings/clock/mediatek,mt6735-imgsys.h>
|
||||
|
||||
#define IMG_CG_CON 0x00
|
||||
#define IMG_CG_SET 0x04
|
||||
#define IMG_CG_CLR 0x08
|
||||
|
||||
static struct mtk_gate_regs imgsys_cg_regs = {
|
||||
.set_ofs = IMG_CG_SET,
|
||||
.clr_ofs = IMG_CG_CLR,
|
||||
.sta_ofs = IMG_CG_CON,
|
||||
};
|
||||
|
||||
static const struct mtk_gate imgsys_gates[] = {
|
||||
GATE_MTK(CLK_IMG_SMI_LARB2, "smi_larb2", "mm_sel", &imgsys_cg_regs, 0, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_IMG_CAM_SMI, "cam_smi", "mm_sel", &imgsys_cg_regs, 5, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_IMG_CAM_CAM, "cam_cam", "mm_sel", &imgsys_cg_regs, 6, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_IMG_SEN_TG, "sen_tg", "mm_sel", &imgsys_cg_regs, 7, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_IMG_SEN_CAM, "sen_cam", "mm_sel", &imgsys_cg_regs, 8, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_IMG_CAM_SV, "cam_sv", "mm_sel", &imgsys_cg_regs, 9, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_IMG_SUFOD, "sufod", "mm_sel", &imgsys_cg_regs, 10, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_IMG_FD, "fd", "mm_sel", &imgsys_cg_regs, 11, &mtk_clk_gate_ops_setclr),
|
||||
};
|
||||
|
||||
static const struct mtk_clk_desc imgsys_clks = {
|
||||
.clks = imgsys_gates,
|
||||
.num_clks = ARRAY_SIZE(imgsys_gates),
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_mt6735_imgsys[] = {
|
||||
{ .compatible = "mediatek,mt6735-imgsys", .data = &imgsys_clks },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver clk_mt6735_imgsys = {
|
||||
.probe = mtk_clk_simple_probe,
|
||||
.remove = mtk_clk_simple_remove,
|
||||
.driver = {
|
||||
.name = "clk-mt6735-imgsys",
|
||||
.of_match_table = of_match_mt6735_imgsys,
|
||||
},
|
||||
};
|
||||
module_platform_driver(clk_mt6735_imgsys);
|
||||
|
||||
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
|
||||
MODULE_DESCRIPTION("MediaTek MT6735 imgsys clock driver");
|
||||
MODULE_LICENSE("GPL");
|
107
drivers/clk/mediatek/clk-mt6735-infracfg.c
Normal file
107
drivers/clk/mediatek/clk-mt6735-infracfg.c
Normal file
@ -0,0 +1,107 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mtk.h"
|
||||
|
||||
#include <dt-bindings/clock/mediatek,mt6735-infracfg.h>
|
||||
#include <dt-bindings/reset/mediatek,mt6735-infracfg.h>
|
||||
|
||||
#define INFRA_RST0 0x30
|
||||
#define INFRA_GLOBALCON_PDN0 0x40
|
||||
#define INFRA_PDN1 0x44
|
||||
#define INFRA_PDN_STA 0x48
|
||||
|
||||
#define RST_NR_PER_BANK 32
|
||||
|
||||
static struct mtk_gate_regs infra_cg_regs = {
|
||||
.set_ofs = INFRA_GLOBALCON_PDN0,
|
||||
.clr_ofs = INFRA_PDN1,
|
||||
.sta_ofs = INFRA_PDN_STA,
|
||||
};
|
||||
|
||||
static const struct mtk_gate infracfg_gates[] = {
|
||||
GATE_MTK(CLK_INFRA_DBG, "dbg", "axi_sel", &infra_cg_regs, 0, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_GCE, "gce", "axi_sel", &infra_cg_regs, 1, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_TRBG, "trbg", "axi_sel", &infra_cg_regs, 2, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_CPUM, "cpum", "axi_sel", &infra_cg_regs, 3, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_DEVAPC, "devapc", "axi_sel", &infra_cg_regs, 4, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_AUDIO, "audio", "aud_intbus_sel", &infra_cg_regs, 5, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_GCPU, "gcpu", "axi_sel", &infra_cg_regs, 6, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_L2C_SRAM, "l2csram", "axi_sel", &infra_cg_regs, 7, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_M4U, "m4u", "axi_sel", &infra_cg_regs, 8, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_CLDMA, "cldma", "axi_sel", &infra_cg_regs, 12, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_CONNMCU_BUS, "connmcu_bus", "axi_sel", &infra_cg_regs, 15, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_KP, "kp", "axi_sel", &infra_cg_regs, 16, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK_FLAGS(CLK_INFRA_APXGPT, "apxgpt", "axi_sel", &infra_cg_regs, 18, &mtk_clk_gate_ops_setclr, CLK_IS_CRITICAL),
|
||||
GATE_MTK(CLK_INFRA_SEJ, "sej", "axi_sel", &infra_cg_regs, 19, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_CCIF0_AP, "ccif0ap", "axi_sel", &infra_cg_regs, 20, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_CCIF1_AP, "ccif1ap", "axi_sel", &infra_cg_regs, 21, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_PMIC_SPI, "pmicspi", "pmicspi_sel", &infra_cg_regs, 22, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_INFRA_PMIC_WRAP, "pmicwrap", "axi_sel", &infra_cg_regs, 23, &mtk_clk_gate_ops_setclr)
|
||||
};
|
||||
|
||||
static u16 infracfg_rst_bank_ofs[] = { INFRA_RST0 };
|
||||
|
||||
static u16 infracfg_rst_idx_map[] = {
|
||||
[MT6735_INFRA_RST0_EMI_REG] = 0 * RST_NR_PER_BANK + 0,
|
||||
[MT6735_INFRA_RST0_DRAMC0_AO] = 0 * RST_NR_PER_BANK + 1,
|
||||
[MT6735_INFRA_RST0_AP_CIRQ_EINT] = 0 * RST_NR_PER_BANK + 3,
|
||||
[MT6735_INFRA_RST0_APXGPT] = 0 * RST_NR_PER_BANK + 4,
|
||||
[MT6735_INFRA_RST0_SCPSYS] = 0 * RST_NR_PER_BANK + 5,
|
||||
[MT6735_INFRA_RST0_KP] = 0 * RST_NR_PER_BANK + 6,
|
||||
[MT6735_INFRA_RST0_PMIC_WRAP] = 0 * RST_NR_PER_BANK + 7,
|
||||
[MT6735_INFRA_RST0_CLDMA_AO_TOP] = 0 * RST_NR_PER_BANK + 8,
|
||||
[MT6735_INFRA_RST0_USBSIF_TOP] = 0 * RST_NR_PER_BANK + 9,
|
||||
[MT6735_INFRA_RST0_EMI] = 0 * RST_NR_PER_BANK + 16,
|
||||
[MT6735_INFRA_RST0_CCIF] = 0 * RST_NR_PER_BANK + 17,
|
||||
[MT6735_INFRA_RST0_DRAMC0] = 0 * RST_NR_PER_BANK + 18,
|
||||
[MT6735_INFRA_RST0_EMI_AO_REG] = 0 * RST_NR_PER_BANK + 19,
|
||||
[MT6735_INFRA_RST0_CCIF_AO] = 0 * RST_NR_PER_BANK + 20,
|
||||
[MT6735_INFRA_RST0_TRNG] = 0 * RST_NR_PER_BANK + 21,
|
||||
[MT6735_INFRA_RST0_SYS_CIRQ] = 0 * RST_NR_PER_BANK + 22,
|
||||
[MT6735_INFRA_RST0_GCE] = 0 * RST_NR_PER_BANK + 23,
|
||||
[MT6735_INFRA_RST0_M4U] = 0 * RST_NR_PER_BANK + 24,
|
||||
[MT6735_INFRA_RST0_CCIF1] = 0 * RST_NR_PER_BANK + 25,
|
||||
[MT6735_INFRA_RST0_CLDMA_TOP_PD] = 0 * RST_NR_PER_BANK + 26
|
||||
};
|
||||
|
||||
static const struct mtk_clk_rst_desc infracfg_resets = {
|
||||
.version = MTK_RST_SIMPLE,
|
||||
.rst_bank_ofs = infracfg_rst_bank_ofs,
|
||||
.rst_bank_nr = ARRAY_SIZE(infracfg_rst_bank_ofs),
|
||||
.rst_idx_map = infracfg_rst_idx_map,
|
||||
.rst_idx_map_nr = ARRAY_SIZE(infracfg_rst_idx_map)
|
||||
};
|
||||
|
||||
static const struct mtk_clk_desc infracfg_clks = {
|
||||
.clks = infracfg_gates,
|
||||
.num_clks = ARRAY_SIZE(infracfg_gates),
|
||||
|
||||
.rst_desc = &infracfg_resets
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_mt6735_infracfg[] = {
|
||||
{ .compatible = "mediatek,mt6735-infracfg", .data = &infracfg_clks },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_match_mt6735_infracfg);
|
||||
|
||||
static struct platform_driver clk_mt6735_infracfg = {
|
||||
.probe = mtk_clk_simple_probe,
|
||||
.remove = mtk_clk_simple_remove,
|
||||
.driver = {
|
||||
.name = "clk-mt6735-infracfg",
|
||||
.of_match_table = of_match_mt6735_infracfg,
|
||||
},
|
||||
};
|
||||
module_platform_driver(clk_mt6735_infracfg);
|
||||
|
||||
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
|
||||
MODULE_DESCRIPTION("MediaTek MT6735 infracfg clock and reset driver");
|
||||
MODULE_LICENSE("GPL");
|
61
drivers/clk/mediatek/clk-mt6735-mfgcfg.c
Normal file
61
drivers/clk/mediatek/clk-mt6735-mfgcfg.c
Normal file
@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mtk.h"
|
||||
|
||||
#include <dt-bindings/clock/mediatek,mt6735-mfgcfg.h>
|
||||
|
||||
#define MFG_CG_CON 0x00
|
||||
#define MFG_CG_SET 0x04
|
||||
#define MFG_CG_CLR 0x08
|
||||
#define MFG_RESET 0x0c
|
||||
|
||||
static struct mtk_gate_regs mfgcfg_cg_regs = {
|
||||
.set_ofs = MFG_CG_SET,
|
||||
.clr_ofs = MFG_CG_CLR,
|
||||
.sta_ofs = MFG_CG_CON,
|
||||
};
|
||||
|
||||
static const struct mtk_gate mfgcfg_gates[] = {
|
||||
GATE_MTK(CLK_MFG_BG3D, "bg3d", "mfg_sel", &mfgcfg_cg_regs, 0, &mtk_clk_gate_ops_setclr),
|
||||
};
|
||||
|
||||
static u16 mfgcfg_rst_ofs[] = { MFG_RESET };
|
||||
|
||||
static const struct mtk_clk_rst_desc mfgcfg_resets = {
|
||||
.version = MTK_RST_SIMPLE,
|
||||
.rst_bank_ofs = mfgcfg_rst_ofs,
|
||||
.rst_bank_nr = ARRAY_SIZE(mfgcfg_rst_ofs)
|
||||
};
|
||||
|
||||
static const struct mtk_clk_desc mfgcfg_clks = {
|
||||
.clks = mfgcfg_gates,
|
||||
.num_clks = ARRAY_SIZE(mfgcfg_gates),
|
||||
|
||||
.rst_desc = &mfgcfg_resets
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_mt6735_mfgcfg[] = {
|
||||
{ .compatible = "mediatek,mt6735-mfgcfg", .data = &mfgcfg_clks },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver clk_mt6735_mfgcfg = {
|
||||
.probe = mtk_clk_simple_probe,
|
||||
.remove = mtk_clk_simple_remove,
|
||||
.driver = {
|
||||
.name = "clk-mt6735-mfgcfg",
|
||||
.of_match_table = of_match_mt6735_mfgcfg,
|
||||
},
|
||||
};
|
||||
module_platform_driver(clk_mt6735_mfgcfg);
|
||||
|
||||
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
|
||||
MODULE_DESCRIPTION("Mediatek MT6735 mfgcfg clock and reset driver");
|
||||
MODULE_LICENSE("GPL");
|
124
drivers/clk/mediatek/clk-mt6735-pericfg.c
Normal file
124
drivers/clk/mediatek/clk-mt6735-pericfg.c
Normal file
@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mtk.h"
|
||||
|
||||
#include <dt-bindings/clock/mediatek,mt6735-pericfg.h>
|
||||
#include <dt-bindings/reset/mediatek,mt6735-pericfg.h>
|
||||
|
||||
#define PERI_GLOBALCON_RST0 0x00
|
||||
#define PERI_GLOBALCON_RST1 0x04
|
||||
#define PERI_GLOBALCON_PDN0_SET 0x08
|
||||
#define PERI_GLOBALCON_PDN0_CLR 0x10
|
||||
#define PERI_GLOBALCON_PDN0_STA 0x18
|
||||
|
||||
#define RST_NR_PER_BANK 32
|
||||
|
||||
static struct mtk_gate_regs peri_cg_regs = {
|
||||
.set_ofs = PERI_GLOBALCON_PDN0_SET,
|
||||
.clr_ofs = PERI_GLOBALCON_PDN0_CLR,
|
||||
.sta_ofs = PERI_GLOBALCON_PDN0_STA,
|
||||
};
|
||||
|
||||
static const struct mtk_gate pericfg_gates[] = {
|
||||
GATE_MTK(CLK_PERI_DISP_PWM, "disp_pwm", "disppwm_sel", &peri_cg_regs, 0, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_THERM, "therm", "axi_sel", &peri_cg_regs, 1, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_PWM1, "pwm1", "axi_sel", &peri_cg_regs, 2, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_PWM2, "pwm2", "axi_sel", &peri_cg_regs, 3, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_PWM3, "pwm3", "axi_sel", &peri_cg_regs, 4, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_PWM4, "pwm4", "axi_sel", &peri_cg_regs, 5, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_PWM5, "pwm5", "axi_sel", &peri_cg_regs, 6, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_PWM6, "pwm6", "axi_sel", &peri_cg_regs, 7, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_PWM7, "pwm7", "axi_sel", &peri_cg_regs, 8, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_PWM, "pwm", "axi_sel", &peri_cg_regs, 9, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_USB0, "usb0", "usb20_sel", &peri_cg_regs, 10, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_IRDA, "irda", "irda_sel", &peri_cg_regs, 11, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_APDMA, "apdma", "axi_sel", &peri_cg_regs, 12, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_MSDC30_0, "msdc30_0", "msdc30_0_sel", &peri_cg_regs, 13, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_MSDC30_1, "msdc30_1", "msdc30_1_sel", &peri_cg_regs, 14, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_MSDC30_2, "msdc30_2", "msdc30_2_sel", &peri_cg_regs, 15, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_MSDC30_3, "msdc30_3", "msdc30_3_sel", &peri_cg_regs, 16, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_UART0, "uart0", "uart_sel", &peri_cg_regs, 17, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_UART1, "uart1", "uart_sel", &peri_cg_regs, 18, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_UART2, "uart2", "uart_sel", &peri_cg_regs, 19, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_UART3, "uart3", "uart_sel", &peri_cg_regs, 20, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_UART4, "uart4", "uart_sel", &peri_cg_regs, 21, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_BTIF, "btif", "axi_sel", &peri_cg_regs, 22, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_I2C0, "i2c0", "axi_sel", &peri_cg_regs, 23, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_I2C1, "i2c1", "axi_sel", &peri_cg_regs, 24, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_I2C2, "i2c2", "axi_sel", &peri_cg_regs, 25, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_I2C3, "i2c3", "axi_sel", &peri_cg_regs, 26, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_AUXADC, "auxadc", "axi_sel", &peri_cg_regs, 27, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_SPI0, "spi0", "spi_sel", &peri_cg_regs, 28, &mtk_clk_gate_ops_setclr),
|
||||
GATE_MTK(CLK_PERI_IRTX, "irtx", "irtx_sel", &peri_cg_regs, 29, &mtk_clk_gate_ops_setclr)
|
||||
};
|
||||
|
||||
static u16 pericfg_rst_bank_ofs[] = { PERI_GLOBALCON_RST0, PERI_GLOBALCON_RST1 };
|
||||
|
||||
static u16 pericfg_rst_idx_map[] = {
|
||||
[MT6735_PERI_RST0_UART0] = 0 * RST_NR_PER_BANK + 0,
|
||||
[MT6735_PERI_RST0_UART1] = 0 * RST_NR_PER_BANK + 1,
|
||||
[MT6735_PERI_RST0_UART2] = 0 * RST_NR_PER_BANK + 2,
|
||||
[MT6735_PERI_RST0_UART3] = 0 * RST_NR_PER_BANK + 3,
|
||||
[MT6735_PERI_RST0_UART4] = 0 * RST_NR_PER_BANK + 4,
|
||||
[MT6735_PERI_RST0_BTIF] = 0 * RST_NR_PER_BANK + 6,
|
||||
[MT6735_PERI_RST0_DISP_PWM_PERI] = 0 * RST_NR_PER_BANK + 7,
|
||||
[MT6735_PERI_RST0_PWM] = 0 * RST_NR_PER_BANK + 8,
|
||||
[MT6735_PERI_RST0_AUXADC] = 0 * RST_NR_PER_BANK + 10,
|
||||
[MT6735_PERI_RST0_DMA] = 0 * RST_NR_PER_BANK + 11,
|
||||
[MT6735_PERI_RST0_IRDA] = 0 * RST_NR_PER_BANK + 12,
|
||||
[MT6735_PERI_RST0_IRTX] = 0 * RST_NR_PER_BANK + 13,
|
||||
[MT6735_PERI_RST0_THERM] = 0 * RST_NR_PER_BANK + 16,
|
||||
[MT6735_PERI_RST0_MSDC2] = 0 * RST_NR_PER_BANK + 17,
|
||||
[MT6735_PERI_RST0_MSDC3] = 0 * RST_NR_PER_BANK + 18,
|
||||
[MT6735_PERI_RST0_MSDC0] = 0 * RST_NR_PER_BANK + 19,
|
||||
[MT6735_PERI_RST0_MSDC1] = 0 * RST_NR_PER_BANK + 20,
|
||||
[MT6735_PERI_RST0_I2C0] = 0 * RST_NR_PER_BANK + 22,
|
||||
[MT6735_PERI_RST0_I2C1] = 0 * RST_NR_PER_BANK + 23,
|
||||
[MT6735_PERI_RST0_I2C2] = 0 * RST_NR_PER_BANK + 24,
|
||||
[MT6735_PERI_RST0_I2C3] = 0 * RST_NR_PER_BANK + 25,
|
||||
[MT6735_PERI_RST0_USB] = 0 * RST_NR_PER_BANK + 28,
|
||||
|
||||
[MT6735_PERI_RST1_SPI0] = 1 * RST_NR_PER_BANK + 1,
|
||||
};
|
||||
|
||||
static const struct mtk_clk_rst_desc pericfg_resets = {
|
||||
.version = MTK_RST_SIMPLE,
|
||||
.rst_bank_ofs = pericfg_rst_bank_ofs,
|
||||
.rst_bank_nr = ARRAY_SIZE(pericfg_rst_bank_ofs),
|
||||
.rst_idx_map = pericfg_rst_idx_map,
|
||||
.rst_idx_map_nr = ARRAY_SIZE(pericfg_rst_idx_map)
|
||||
};
|
||||
|
||||
static const struct mtk_clk_desc pericfg_clks = {
|
||||
.clks = pericfg_gates,
|
||||
.num_clks = ARRAY_SIZE(pericfg_gates),
|
||||
|
||||
.rst_desc = &pericfg_resets
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_mt6735_pericfg[] = {
|
||||
{ .compatible = "mediatek,mt6735-pericfg", .data = &pericfg_clks },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_match_mt6735_pericfg);
|
||||
|
||||
static struct platform_driver clk_mt6735_pericfg = {
|
||||
.probe = mtk_clk_simple_probe,
|
||||
.remove = mtk_clk_simple_remove,
|
||||
.driver = {
|
||||
.name = "clk-mt6735-pericfg",
|
||||
.of_match_table = of_match_mt6735_pericfg,
|
||||
},
|
||||
};
|
||||
module_platform_driver(clk_mt6735_pericfg);
|
||||
|
||||
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
|
||||
MODULE_DESCRIPTION("MediaTek MT6735 pericfg clock driver");
|
||||
MODULE_LICENSE("GPL");
|
394
drivers/clk/mediatek/clk-mt6735-topckgen.c
Normal file
394
drivers/clk/mediatek/clk-mt6735-topckgen.c
Normal file
@ -0,0 +1,394 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-mtk.h"
|
||||
#include "clk-mux.h"
|
||||
|
||||
#include <dt-bindings/clock/mediatek,mt6735-topckgen.h>
|
||||
|
||||
#define CLK_CFG_0 0x40
|
||||
#define CLK_CFG_0_SET 0x44
|
||||
#define CLK_CFG_0_CLR 0x48
|
||||
#define CLK_CFG_1 0x50
|
||||
#define CLK_CFG_1_SET 0x54
|
||||
#define CLK_CFG_1_CLR 0x58
|
||||
#define CLK_CFG_2 0x60
|
||||
#define CLK_CFG_2_SET 0x64
|
||||
#define CLK_CFG_2_CLR 0x68
|
||||
#define CLK_CFG_3 0x70
|
||||
#define CLK_CFG_3_SET 0x74
|
||||
#define CLK_CFG_3_CLR 0x78
|
||||
#define CLK_CFG_4 0x80
|
||||
#define CLK_CFG_4_SET 0x84
|
||||
#define CLK_CFG_4_CLR 0x88
|
||||
#define CLK_CFG_5 0x90
|
||||
#define CLK_CFG_5_SET 0x94
|
||||
#define CLK_CFG_5_CLR 0x98
|
||||
#define CLK_CFG_6 0xa0
|
||||
#define CLK_CFG_6_SET 0xa4
|
||||
#define CLK_CFG_6_CLR 0xa8
|
||||
#define CLK_CFG_7 0xb0
|
||||
#define CLK_CFG_7_SET 0xb4
|
||||
#define CLK_CFG_7_CLR 0xb8
|
||||
|
||||
static DEFINE_SPINLOCK(mt6735_topckgen_lock);
|
||||
|
||||
/* Some clocks with unknown details are modeled as fixed clocks */
|
||||
static const struct mtk_fixed_clk topckgen_fixed_clks[] = {
|
||||
/*
|
||||
* This clock is available as a parent option for multiple
|
||||
* muxes and seems like an alternative name for clk26m at first,
|
||||
* but it appears alongside it in several muxes which should
|
||||
* mean it is a separate clock.
|
||||
*/
|
||||
FIXED_CLK(CLK_TOP_AD_SYS_26M_CK, "ad_sys_26m_ck", "clk26m", 26 * MHZ),
|
||||
/*
|
||||
* This clock is the parent of DMPLL divisors. It might be MEMPLL
|
||||
* or its parent, as DMPLL appears to be an alternative name for
|
||||
* MEMPLL.
|
||||
*/
|
||||
FIXED_CLK(CLK_TOP_CLKPH_MCK_O, "clkph_mck_o", NULL, 0),
|
||||
/*
|
||||
* DMPLL clock (dmpll_ck), controlled by DDRPHY.
|
||||
*/
|
||||
FIXED_CLK(CLK_TOP_DMPLL, "dmpll", "clkph_mck_o", 0),
|
||||
/*
|
||||
* MIPI DPI clock. Parent option for dpi0_sel. Unknown parent.
|
||||
*/
|
||||
FIXED_CLK(CLK_TOP_DPI_CK, "dpi_ck", NULL, 0),
|
||||
/*
|
||||
* This clock is a child of WHPLL which is controlled by
|
||||
* the modem.
|
||||
*/
|
||||
FIXED_CLK(CLK_TOP_WHPLL_AUDIO_CK, "whpll_audio_ck", NULL, 0)
|
||||
};
|
||||
|
||||
static const struct mtk_fixed_factor topckgen_factors[] = {
|
||||
FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2),
|
||||
FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "mainpll", 1, 3),
|
||||
FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5),
|
||||
FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "mainpll", 1, 2),
|
||||
FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "mainpll", 1, 4),
|
||||
FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "mainpll", 1, 8),
|
||||
FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "mainpll", 1, 16),
|
||||
FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "mainpll", 1, 2),
|
||||
FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "mainpll", 1, 4),
|
||||
FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "mainpll", 1, 2),
|
||||
FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "mainpll", 1, 4),
|
||||
FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "mainpll", 1, 2),
|
||||
FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "mainpll", 1, 4),
|
||||
FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2),
|
||||
FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll", 1, 3),
|
||||
FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5),
|
||||
FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll", 1, 26),
|
||||
FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll", 1, 2),
|
||||
FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll", 1, 4),
|
||||
FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll", 1, 8),
|
||||
FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll", 1, 2),
|
||||
FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll", 1, 4),
|
||||
FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll", 1, 8),
|
||||
FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll", 1, 2),
|
||||
FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll", 1, 4),
|
||||
FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll", 1, 2),
|
||||
FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll", 1, 4),
|
||||
FACTOR(CLK_TOP_MSDCPLL_D8, "msdcpll_d8", "msdcpll", 1, 8),
|
||||
FACTOR(CLK_TOP_MSDCPLL_D16, "msdcpll_d16", "msdcpll", 1, 16),
|
||||
FACTOR(CLK_TOP_VENCPLL_D3, "vencpll_d3", "vencpll", 1, 3),
|
||||
FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll", 1, 2),
|
||||
FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll", 1, 4),
|
||||
FACTOR(CLK_TOP_DMPLL_D2, "dmpll_d2", "clkph_mck_o", 1, 2),
|
||||
FACTOR(CLK_TOP_DMPLL_D4, "dmpll_d4", "clkph_mck_o", 1, 4),
|
||||
FACTOR(CLK_TOP_DMPLL_D8, "dmpll_d8", "clkph_mck_o", 1, 8),
|
||||
FACTOR(CLK_TOP_AD_SYS_26M_D2, "ad_sys_26m_d2", "clk26m", 1, 2)
|
||||
};
|
||||
|
||||
static const char * const axi_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll1_d2",
|
||||
"syspll_d5",
|
||||
"syspll1_d4",
|
||||
"univpll_d5",
|
||||
"univpll2_d2",
|
||||
"dmpll",
|
||||
"dmpll_d2"
|
||||
};
|
||||
|
||||
static const char * const mem_sel_parents[] = {
|
||||
"clk26m",
|
||||
"dmpll"
|
||||
};
|
||||
|
||||
static const char * const ddrphycfg_parents[] = {
|
||||
"clk26m",
|
||||
"syspll1_d8"
|
||||
};
|
||||
|
||||
static const char * const mm_sel_parents[] = {
|
||||
"clk26m",
|
||||
"vencpll",
|
||||
"syspll1_d2",
|
||||
"syspll_d5",
|
||||
"syspll1_d4",
|
||||
"univpll_d5",
|
||||
"univpll2_d2",
|
||||
"dmpll"
|
||||
};
|
||||
|
||||
static const char * const pwm_sel_parents[] = {
|
||||
"clk26m",
|
||||
"univpll2_d4",
|
||||
"univpll3_d2",
|
||||
"univpll1_d4"
|
||||
};
|
||||
|
||||
static const char * const vdec_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll1_d2",
|
||||
"syspll_d5",
|
||||
"syspll1_d4",
|
||||
"univpll_d5",
|
||||
"syspll_d2",
|
||||
"syspll2_d2",
|
||||
"msdcpll_d2"
|
||||
};
|
||||
|
||||
static const char * const mfg_sel_parents[] = {
|
||||
"clk26m",
|
||||
"mmpll",
|
||||
"clk26m",
|
||||
"clk26m",
|
||||
"clk26m",
|
||||
"clk26m",
|
||||
"clk26m",
|
||||
"clk26m",
|
||||
"clk26m",
|
||||
"syspll_d3",
|
||||
"syspll1_d2",
|
||||
"syspll_d5",
|
||||
"univpll_d3",
|
||||
"univpll1_d2"
|
||||
};
|
||||
|
||||
static const char * const camtg_sel_parents[] = {
|
||||
"clk26m",
|
||||
"univpll_d26",
|
||||
"univpll2_d2",
|
||||
"syspll3_d2",
|
||||
"syspll3_d4",
|
||||
"msdcpll_d4"
|
||||
};
|
||||
|
||||
static const char * const uart_sel_parents[] = {
|
||||
"clk26m",
|
||||
"univpll2_d8"
|
||||
};
|
||||
|
||||
static const char * const spi_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll3_d2",
|
||||
"msdcpll_d8",
|
||||
"syspll2_d4",
|
||||
"syspll4_d2",
|
||||
"univpll2_d4",
|
||||
"univpll1_d8"
|
||||
};
|
||||
|
||||
static const char * const usb20_sel_parents[] = {
|
||||
"clk26m",
|
||||
"univpll1_d8",
|
||||
"univpll3_d4"
|
||||
};
|
||||
|
||||
static const char * const msdc50_0_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll1_d2",
|
||||
"syspll2_d2",
|
||||
"syspll4_d2",
|
||||
"univpll_d5",
|
||||
"univpll1_d4"
|
||||
};
|
||||
|
||||
static const char * const msdc30_0_sel_parents[] = {
|
||||
"clk26m",
|
||||
"msdcpll",
|
||||
"msdcpll_d2",
|
||||
"msdcpll_d4",
|
||||
"syspll2_d2",
|
||||
"syspll1_d4",
|
||||
"univpll1_d4",
|
||||
"univpll_d3",
|
||||
"univpll_d26",
|
||||
"syspll2_d4",
|
||||
"univpll_d2"
|
||||
};
|
||||
|
||||
static const char * const msdc30_1_2_sel_parents[] = {
|
||||
"clk26m",
|
||||
"univpll2_d2",
|
||||
"msdcpll_d4",
|
||||
"syspll2_d2",
|
||||
"syspll1_d4",
|
||||
"univpll1_d4",
|
||||
"univpll_d26",
|
||||
"syspll2_d4"
|
||||
};
|
||||
|
||||
static const char * const msdc30_3_sel_parents[] = {
|
||||
"clk26m",
|
||||
"univpll2_d2",
|
||||
"msdcpll_d4",
|
||||
"syspll2_d2",
|
||||
"syspll1_d4",
|
||||
"univpll1_d4",
|
||||
"univpll_d26",
|
||||
"msdcpll_d16",
|
||||
"syspll2_d4"
|
||||
};
|
||||
|
||||
static const char * const audio_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll3_d4",
|
||||
"syspll4_d4",
|
||||
"syspll1_d16"
|
||||
};
|
||||
|
||||
static const char * const aud_intbus_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll1_d4",
|
||||
"syspll4_d2",
|
||||
"dmpll_d4"
|
||||
};
|
||||
|
||||
static const char * const pmicspi_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll1_d8",
|
||||
"syspll3_d4",
|
||||
"syspll1_d16",
|
||||
"univpll3_d4",
|
||||
"univpll_d26",
|
||||
"dmpll_d4",
|
||||
"dmpll_d8"
|
||||
};
|
||||
|
||||
static const char * const scp_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll1_d8",
|
||||
"dmpll_d2",
|
||||
"dmpll_d4"
|
||||
};
|
||||
|
||||
static const char * const atb_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll1_d2",
|
||||
"syspll_d5",
|
||||
"dmpll"
|
||||
};
|
||||
|
||||
static const char * const dpi0_sel_parents[] = {
|
||||
"clk26m",
|
||||
"tvdpll",
|
||||
"tvdpll_d2",
|
||||
"tvdpll_d4",
|
||||
"dpi_ck"
|
||||
};
|
||||
|
||||
static const char * const scam_sel_parents[] = {
|
||||
"clk26m",
|
||||
"syspll3_d2",
|
||||
"univpll2_d4",
|
||||
"vencpll_d3"
|
||||
};
|
||||
|
||||
static const char * const mfg13m_sel_parents[] = {
|
||||
"clk26m",
|
||||
"ad_sys_26m_d2"
|
||||
};
|
||||
|
||||
static const char * const aud_1_2_sel_parents[] = {
|
||||
"clk26m",
|
||||
"apll1"
|
||||
};
|
||||
|
||||
static const char * const irda_sel_parents[] = {
|
||||
"clk26m",
|
||||
"univpll2_d4"
|
||||
};
|
||||
|
||||
static const char * const irtx_sel_parents[] = {
|
||||
"clk26m",
|
||||
"ad_sys_26m_ck"
|
||||
};
|
||||
|
||||
static const char * const disppwm_sel_parents[] = {
|
||||
"clk26m",
|
||||
"univpll2_d4",
|
||||
"syspll4_d2_d8",
|
||||
"ad_sys_26m_ck"
|
||||
};
|
||||
|
||||
static const struct mtk_mux topckgen_muxes[] = {
|
||||
MUX_CLR_SET_UPD(CLK_TOP_AXI_SEL, "axi_sel", axi_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 0, 3, 0, 0),
|
||||
MUX_CLR_SET_UPD(CLK_TOP_MEM_SEL, "mem_sel", mem_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 8, 1, 0, 0),
|
||||
MUX_CLR_SET_UPD(CLK_TOP_DDRPHY_SEL, "ddrphycfg_sel", ddrphycfg_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 16, 1, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_MM_SEL, "mm_sel", mm_sel_parents, CLK_CFG_0, CLK_CFG_0_SET, CLK_CFG_0_CLR, 24, 3, 31, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_PWM_SEL, "pwm_sel", pwm_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 0, 2, 7, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_VDEC_SEL, "vdec_sel", vdec_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 8, 3, 15, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG_SEL, "mfg_sel", mfg_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 16, 4, 23, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_CAMTG_SEL, "camtg_sel", camtg_sel_parents, CLK_CFG_1, CLK_CFG_1_SET, CLK_CFG_1_CLR, 24, 3, 31, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_UART_SEL, "uart_sel", uart_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 0, 1, 7, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_SPI_SEL, "spi_sel", spi_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 8, 3, 15, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_USB20_SEL, "usb20_sel", usb20_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 16, 2, 23, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", msdc50_0_sel_parents, CLK_CFG_2, CLK_CFG_2_SET, CLK_CFG_2_CLR, 24, 3, 31, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_0_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 0, 4, 7, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_1_2_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 8, 3, 15, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", msdc30_1_2_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 16, 3, 23, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", msdc30_3_sel_parents, CLK_CFG_3, CLK_CFG_3_SET, CLK_CFG_3_CLR, 24, 4, 31, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDIO_SEL, "audio_sel", audio_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 0, 2, 7, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUDINTBUS_SEL, "aud_intbus_sel", aud_intbus_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 8, 2, 15, 0, 0),
|
||||
MUX_CLR_SET_UPD(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 16, 3, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_SCP_SEL, "scp_sel", scp_sel_parents, CLK_CFG_4, CLK_CFG_4_SET, CLK_CFG_4_CLR, 24, 2, 31, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_ATB_SEL, "atb_sel", atb_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 0, 2, 7, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_DPI0_SEL, "dpi0_sel", dpi0_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 8, 3, 15, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_SCAM_SEL, "scam_sel", scam_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 16, 2, 23, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_MFG13M_SEL, "mfg13m_sel", mfg13m_sel_parents, CLK_CFG_5, CLK_CFG_5_SET, CLK_CFG_5_CLR, 24, 1, 31, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD1_SEL, "aud_1_sel", aud_1_2_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 0, 1, 7, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_AUD2_SEL, "aud_2_sel", aud_1_2_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 8, 1, 15, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_IRDA_SEL, "irda_sel", irda_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 16, 1, 23, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_IRTX_SEL, "irtx_sel", irtx_sel_parents, CLK_CFG_6, CLK_CFG_6_SET, CLK_CFG_6_CLR, 24, 1, 31, 0, 0),
|
||||
MUX_GATE_CLR_SET_UPD(CLK_TOP_DISPPWM_SEL, "disppwm_sel", disppwm_sel_parents, CLK_CFG_7, CLK_CFG_7_SET, CLK_CFG_7_CLR, 0, 2, 7, 0, 0),
|
||||
};
|
||||
|
||||
static const struct mtk_clk_desc topckgen_desc = {
|
||||
.fixed_clks = topckgen_fixed_clks,
|
||||
.num_fixed_clks = ARRAY_SIZE(topckgen_fixed_clks),
|
||||
.factor_clks = topckgen_factors,
|
||||
.num_factor_clks = ARRAY_SIZE(topckgen_factors),
|
||||
.mux_clks = topckgen_muxes,
|
||||
.num_mux_clks = ARRAY_SIZE(topckgen_muxes),
|
||||
.clk_lock = &mt6735_topckgen_lock,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_mt6735_topckgen[] = {
|
||||
{ .compatible = "mediatek,mt6735-topckgen", .data = &topckgen_desc},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_match_mt6735_topckgen);
|
||||
|
||||
static struct platform_driver clk_mt6735_topckgen = {
|
||||
.probe = mtk_clk_simple_probe,
|
||||
.remove = mtk_clk_simple_remove,
|
||||
.driver = {
|
||||
.name = "clk-mt6735-topckgen",
|
||||
.of_match_table = of_match_mt6735_topckgen,
|
||||
},
|
||||
};
|
||||
module_platform_driver(clk_mt6735_topckgen);
|
||||
|
||||
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
|
||||
MODULE_DESCRIPTION("MediaTek MT6735 topckgen clock driver");
|
||||
MODULE_LICENSE("GPL");
|
79
drivers/clk/mediatek/clk-mt6735-vdecsys.c
Normal file
79
drivers/clk/mediatek/clk-mt6735-vdecsys.c
Normal file
@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mtk.h"
|
||||
|
||||
#include <dt-bindings/clock/mediatek,mt6735-vdecsys.h>
|
||||
#include <dt-bindings/reset/mediatek,mt6735-vdecsys.h>
|
||||
|
||||
#define VDEC_CKEN_SET 0x00
|
||||
#define VDEC_CKEN_CLR 0x04
|
||||
#define SMI_LARB1_CKEN_SET 0x08
|
||||
#define SMI_LARB1_CKEN_CLR 0x0c
|
||||
#define VDEC_RESETB_CON 0x10
|
||||
#define SMI_LARB1_RESETB_CON 0x14
|
||||
|
||||
#define RST_NR_PER_BANK 32
|
||||
|
||||
static struct mtk_gate_regs vdec_cg_regs = {
|
||||
.set_ofs = VDEC_CKEN_SET,
|
||||
.clr_ofs = VDEC_CKEN_CLR,
|
||||
.sta_ofs = VDEC_CKEN_SET,
|
||||
};
|
||||
|
||||
static struct mtk_gate_regs smi_larb1_cg_regs = {
|
||||
.set_ofs = SMI_LARB1_CKEN_SET,
|
||||
.clr_ofs = SMI_LARB1_CKEN_CLR,
|
||||
.sta_ofs = SMI_LARB1_CKEN_SET,
|
||||
};
|
||||
|
||||
static const struct mtk_gate vdecsys_gates[] = {
|
||||
GATE_MTK(CLK_VDEC_VDEC, "vdec", "vdec_sel", &vdec_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv),
|
||||
GATE_MTK(CLK_VDEC_SMI_LARB1, "smi_larb1", "vdec_sel", &smi_larb1_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv),
|
||||
};
|
||||
|
||||
static u16 vdecsys_rst_bank_ofs[] = { VDEC_RESETB_CON, SMI_LARB1_RESETB_CON };
|
||||
|
||||
static u16 vdecsys_rst_idx_map[] = {
|
||||
[MT6735_VDEC_RST0_VDEC] = 0 * RST_NR_PER_BANK + 0,
|
||||
[MT6735_VDEC_RST1_SMI_LARB1] = 1 * RST_NR_PER_BANK + 0,
|
||||
};
|
||||
|
||||
static const struct mtk_clk_rst_desc vdecsys_resets = {
|
||||
.version = MTK_RST_SIMPLE,
|
||||
.rst_bank_ofs = vdecsys_rst_bank_ofs,
|
||||
.rst_bank_nr = ARRAY_SIZE(vdecsys_rst_bank_ofs),
|
||||
.rst_idx_map = vdecsys_rst_idx_map,
|
||||
.rst_idx_map_nr = ARRAY_SIZE(vdecsys_rst_idx_map)
|
||||
};
|
||||
|
||||
static const struct mtk_clk_desc vdecsys_clks = {
|
||||
.clks = vdecsys_gates,
|
||||
.num_clks = ARRAY_SIZE(vdecsys_gates),
|
||||
.rst_desc = &vdecsys_resets
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_mt6735_vdecsys[] = {
|
||||
{ .compatible = "mediatek,mt6735-vdecsys", .data = &vdecsys_clks },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver clk_mt6735_vdecsys = {
|
||||
.probe = mtk_clk_simple_probe,
|
||||
.remove = mtk_clk_simple_remove,
|
||||
.driver = {
|
||||
.name = "clk-mt6735-vdecsys",
|
||||
.of_match_table = of_match_mt6735_vdecsys,
|
||||
},
|
||||
};
|
||||
module_platform_driver(clk_mt6735_vdecsys);
|
||||
|
||||
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
|
||||
MODULE_DESCRIPTION("MediaTek MT6735 vdecsys clock and reset driver");
|
||||
MODULE_LICENSE("GPL");
|
53
drivers/clk/mediatek/clk-mt6735-vencsys.c
Normal file
53
drivers/clk/mediatek/clk-mt6735-vencsys.c
Normal file
@ -0,0 +1,53 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022 Yassine Oudjana <y.oudjana@protonmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "clk-gate.h"
|
||||
#include "clk-mtk.h"
|
||||
|
||||
#include <dt-bindings/clock/mediatek,mt6735-vencsys.h>
|
||||
|
||||
#define VENC_CG_CON 0x00
|
||||
#define VENC_CG_SET 0x04
|
||||
#define VENC_CG_CLR 0x08
|
||||
|
||||
static struct mtk_gate_regs venc_cg_regs = {
|
||||
.set_ofs = VENC_CG_SET,
|
||||
.clr_ofs = VENC_CG_CLR,
|
||||
.sta_ofs = VENC_CG_CON,
|
||||
};
|
||||
|
||||
static const struct mtk_gate vencsys_gates[] = {
|
||||
GATE_MTK(CLK_VENC_SMI_LARB3, "smi_larb3", "mm_sel", &venc_cg_regs, 0, &mtk_clk_gate_ops_setclr_inv),
|
||||
GATE_MTK(CLK_VENC_VENC, "venc", "mm_sel", &venc_cg_regs, 4, &mtk_clk_gate_ops_setclr_inv),
|
||||
GATE_MTK(CLK_VENC_JPGENC, "jpgenc", "mm_sel", &venc_cg_regs, 8, &mtk_clk_gate_ops_setclr_inv),
|
||||
GATE_MTK(CLK_VENC_JPGDEC, "jpgdec", "mm_sel", &venc_cg_regs, 12, &mtk_clk_gate_ops_setclr_inv),
|
||||
};
|
||||
|
||||
static const struct mtk_clk_desc vencsys_clks = {
|
||||
.clks = vencsys_gates,
|
||||
.num_clks = ARRAY_SIZE(vencsys_gates),
|
||||
};
|
||||
|
||||
static const struct of_device_id of_match_mt6735_vencsys[] = {
|
||||
{ .compatible = "mediatek,mt6735-vencsys", .data = &vencsys_clks },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver clk_mt6735_vencsys = {
|
||||
.probe = mtk_clk_simple_probe,
|
||||
.remove = mtk_clk_simple_remove,
|
||||
.driver = {
|
||||
.name = "clk-mt6735-vencsys",
|
||||
.of_match_table = of_match_mt6735_vencsys,
|
||||
},
|
||||
};
|
||||
module_platform_driver(clk_mt6735_vencsys);
|
||||
|
||||
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
|
||||
MODULE_DESCRIPTION("Mediatek MT6735 vencsys clock driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -342,11 +342,14 @@ static const char * const dsp7_parents[] = {
|
||||
"univpll_d3"
|
||||
};
|
||||
|
||||
/*
|
||||
* MFG can be also parented to "univpll_d6" and "univpll_d7":
|
||||
* these have been removed from the parents list to let us
|
||||
* achieve GPU DVFS without any special clock handlers.
|
||||
*/
|
||||
static const char * const mfg_core_tmp_parents[] = {
|
||||
"clk26m",
|
||||
"mainpll_d5_d2",
|
||||
"univpll_d6",
|
||||
"univpll_d7"
|
||||
"mainpll_d5_d2"
|
||||
};
|
||||
|
||||
static const char * const camtg_parents[] = {
|
||||
|
@ -106,6 +106,7 @@ config COMMON_CLK_AXG_AUDIO
|
||||
select COMMON_CLK_MESON_SCLK_DIV
|
||||
select COMMON_CLK_MESON_CLKC_UTILS
|
||||
select REGMAP_MMIO
|
||||
depends on RESET_MESON_AUX
|
||||
help
|
||||
Support for the audio clock controller on AmLogic A113D devices,
|
||||
aka axg, Say Y if you want audio subsystem to work.
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <soc/amlogic/reset-meson-aux.h>
|
||||
|
||||
#include "meson-clkc-utils.h"
|
||||
#include "axg-audio.h"
|
||||
#include "clk-regmap.h"
|
||||
@ -1678,84 +1680,6 @@ static struct clk_regmap *const sm1_clk_regmaps[] = {
|
||||
&sm1_earcrx_dmac_clk,
|
||||
};
|
||||
|
||||
struct axg_audio_reset_data {
|
||||
struct reset_controller_dev rstc;
|
||||
struct regmap *map;
|
||||
unsigned int offset;
|
||||
};
|
||||
|
||||
static void axg_audio_reset_reg_and_bit(struct axg_audio_reset_data *rst,
|
||||
unsigned long id,
|
||||
unsigned int *reg,
|
||||
unsigned int *bit)
|
||||
{
|
||||
unsigned int stride = regmap_get_reg_stride(rst->map);
|
||||
|
||||
*reg = (id / (stride * BITS_PER_BYTE)) * stride;
|
||||
*reg += rst->offset;
|
||||
*bit = id % (stride * BITS_PER_BYTE);
|
||||
}
|
||||
|
||||
static int axg_audio_reset_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool assert)
|
||||
{
|
||||
struct axg_audio_reset_data *rst =
|
||||
container_of(rcdev, struct axg_audio_reset_data, rstc);
|
||||
unsigned int offset, bit;
|
||||
|
||||
axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
|
||||
|
||||
regmap_update_bits(rst->map, offset, BIT(bit),
|
||||
assert ? BIT(bit) : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axg_audio_reset_status(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
struct axg_audio_reset_data *rst =
|
||||
container_of(rcdev, struct axg_audio_reset_data, rstc);
|
||||
unsigned int val, offset, bit;
|
||||
|
||||
axg_audio_reset_reg_and_bit(rst, id, &offset, &bit);
|
||||
|
||||
regmap_read(rst->map, offset, &val);
|
||||
|
||||
return !!(val & BIT(bit));
|
||||
}
|
||||
|
||||
static int axg_audio_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return axg_audio_reset_update(rcdev, id, true);
|
||||
}
|
||||
|
||||
static int axg_audio_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return axg_audio_reset_update(rcdev, id, false);
|
||||
}
|
||||
|
||||
static int axg_audio_reset_toggle(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = axg_audio_reset_assert(rcdev, id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return axg_audio_reset_deassert(rcdev, id);
|
||||
}
|
||||
|
||||
static const struct reset_control_ops axg_audio_rstc_ops = {
|
||||
.assert = axg_audio_reset_assert,
|
||||
.deassert = axg_audio_reset_deassert,
|
||||
.reset = axg_audio_reset_toggle,
|
||||
.status = axg_audio_reset_status,
|
||||
};
|
||||
|
||||
static struct regmap_config axg_audio_regmap_cfg = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
@ -1766,16 +1690,14 @@ struct audioclk_data {
|
||||
struct clk_regmap *const *regmap_clks;
|
||||
unsigned int regmap_clk_num;
|
||||
struct meson_clk_hw_data hw_clks;
|
||||
unsigned int reset_offset;
|
||||
unsigned int reset_num;
|
||||
unsigned int max_register;
|
||||
const char *rst_drvname;
|
||||
};
|
||||
|
||||
static int axg_audio_clkc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const struct audioclk_data *data;
|
||||
struct axg_audio_reset_data *rst;
|
||||
struct regmap *map;
|
||||
void __iomem *regs;
|
||||
struct clk_hw *hw;
|
||||
@ -1834,22 +1756,11 @@ static int axg_audio_clkc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Stop here if there is no reset */
|
||||
if (!data->reset_num)
|
||||
return 0;
|
||||
/* Register auxiliary reset driver when applicable */
|
||||
if (data->rst_drvname)
|
||||
ret = devm_meson_rst_aux_register(dev, map, data->rst_drvname);
|
||||
|
||||
rst = devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL);
|
||||
if (!rst)
|
||||
return -ENOMEM;
|
||||
|
||||
rst->map = map;
|
||||
rst->offset = data->reset_offset;
|
||||
rst->rstc.nr_resets = data->reset_num;
|
||||
rst->rstc.ops = &axg_audio_rstc_ops;
|
||||
rst->rstc.of_node = dev->of_node;
|
||||
rst->rstc.owner = THIS_MODULE;
|
||||
|
||||
return devm_reset_controller_register(dev, &rst->rstc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct audioclk_data axg_audioclk_data = {
|
||||
@ -1869,9 +1780,8 @@ static const struct audioclk_data g12a_audioclk_data = {
|
||||
.hws = g12a_audio_hw_clks,
|
||||
.num = ARRAY_SIZE(g12a_audio_hw_clks),
|
||||
},
|
||||
.reset_offset = AUDIO_SW_RESET,
|
||||
.reset_num = 26,
|
||||
.max_register = AUDIO_CLK_SPDIFOUT_B_CTRL,
|
||||
.rst_drvname = "rst-g12a",
|
||||
};
|
||||
|
||||
static const struct audioclk_data sm1_audioclk_data = {
|
||||
@ -1881,9 +1791,8 @@ static const struct audioclk_data sm1_audioclk_data = {
|
||||
.hws = sm1_audio_hw_clks,
|
||||
.num = ARRAY_SIZE(sm1_audio_hw_clks),
|
||||
},
|
||||
.reset_offset = AUDIO_SM1_SW_RESET0,
|
||||
.reset_num = 39,
|
||||
.max_register = AUDIO_EARCRX_DMAC_CLK_CTRL,
|
||||
.rst_drvname = "rst-sm1",
|
||||
};
|
||||
|
||||
static const struct of_device_id clkc_match_table[] = {
|
||||
|
@ -23,8 +23,6 @@
|
||||
|
||||
#include <dt-bindings/clock/axg-clkc.h>
|
||||
|
||||
static DEFINE_SPINLOCK(meson_clk_lock);
|
||||
|
||||
static struct clk_regmap axg_fixed_pll_dco = {
|
||||
.data = &(struct meson_clk_pll_data){
|
||||
.en = {
|
||||
@ -506,7 +504,6 @@ static struct clk_regmap axg_mpll0_div = {
|
||||
.shift = 0,
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
@ -557,7 +554,6 @@ static struct clk_regmap axg_mpll1_div = {
|
||||
.shift = 1,
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
@ -613,7 +609,6 @@ static struct clk_regmap axg_mpll2_div = {
|
||||
.shift = 2,
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
@ -664,7 +659,6 @@ static struct clk_regmap axg_mpll3_div = {
|
||||
.shift = 3,
|
||||
.width = 1,
|
||||
},
|
||||
.lock = &meson_clk_lock,
|
||||
.flags = CLK_MESON_MPLL_ROUND_CLOSEST,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data){
|
||||
|
@ -361,6 +361,7 @@ static struct clk_regmap hifi_pll_dco = {
|
||||
.range = &c3_gp0_pll_mult_range,
|
||||
.init_regs = c3_hifi_init_regs,
|
||||
.init_count = ARRAY_SIZE(c3_hifi_init_regs),
|
||||
.frac_max = 100000,
|
||||
},
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "hifi_pll_dco",
|
||||
|
@ -112,26 +112,15 @@ static int mpll_set_rate(struct clk_hw *hw,
|
||||
struct clk_regmap *clk = to_clk_regmap(hw);
|
||||
struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
|
||||
unsigned int sdm, n2;
|
||||
unsigned long flags = 0;
|
||||
|
||||
params_from_rate(rate, parent_rate, &sdm, &n2, mpll->flags);
|
||||
|
||||
if (mpll->lock)
|
||||
spin_lock_irqsave(mpll->lock, flags);
|
||||
else
|
||||
__acquire(mpll->lock);
|
||||
|
||||
/* Set the fractional part */
|
||||
meson_parm_write(clk->map, &mpll->sdm, sdm);
|
||||
|
||||
/* Set the integer divider part */
|
||||
meson_parm_write(clk->map, &mpll->n2, n2);
|
||||
|
||||
if (mpll->lock)
|
||||
spin_unlock_irqrestore(mpll->lock, flags);
|
||||
else
|
||||
__release(mpll->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user