The diff is dominated by the Allwinner A10/A20 SoCs getting converted to
the sunxi-ng framework. Otherwise, the heavy hitters are various drivers for SoCs like AT91, Amlogic, Renesas, and Rockchip. There are some other new clk drivers in here too but overall this is just a bunch of clk drivers for various different pieces of hardware and a collection of non-critical fixes for clk drivers. New Drivers: - Allwinner R40 SoCs - Renesas R-Car Gen3 USB 2.0 clock selector PHY - Atmel AT91 audio PLL - Uniphier PXs3 SoCs - ARC HSDK Board PLLs - AXS10X Board PLLs - STMicroelectronics STM32H743 SoCs Removed Drivers: - Non-compiling mb86s7x support Updates: - Allwinner A10/A20 SoCs converted to sunxi-ng framework - Allwinner H3 CPU clk fixes - Renesas R-Car D3 SoC - Renesas V2H and M3-W modules - Samsung Exynos5420/5422/5800 audio fixes - Rockchip fractional clk approximation fixes - Rockchip rk3126 SoC support within the rk3128 driver - Amlogic gxbb CEC32 and sd_emmc clks - Amlogic meson8b reset controller support - IDT VersaClock 5P49V5925/5P49V6901 support - Qualcomm MSM8996 SMMU clks - Various 'const' applications for struct clk_ops - si5351 PLL reset bugfix - Uniphier audio on LD11/LD20 and ethernet support on LD11/LD20/Pro4/PXs2 - Assorted Tegra clk driver fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJZuIAQAAoJEK0CiJfG5JUlUMQQAKFwCZRfTzz0m9jJ9s1XZSR/ vldNAEUGm+Mz0W84xIzFqaT0UI1+SJK4e9Du+EN6phcCD5yVB0JS2EtRa84Bku/i Zy6AYSUNbGjx94HPwIq1hKt+UOIfBiNbJKMnkoCbEyYPA/TiWzr8JR5GyLjwYhPq IZHSvKqUKM3h2nr+MtpFJIIk8DlkLARRca4CCqa5i2Oqj6B8rjQQAq7TaLAM3ASN tSFIW2vdmWD+om2L57WHhwBgaYnUB4jBCRWkFZRsO4ZIRgm4VpePmosy2UTZ7fqb kEaW2bPuv65zUHpvjHG6yXo+yh0yk1fBsXG/joXgJ4oOmNzsIgnCZzPnGUC1ccms QdK/qhdIXsdgiR2DZtYuzUHji8+TNIPPjfAFyJjUwxDBXpqzXvsvltx2a1hg/rUP VDvTL2OnoGtrW2bXPufCkxBsyejJ4RqC5riMJws5xgMkqKKUajiLovPeuL6+8kU+ ncqWYiIkEvHNKpmW511G/g+ClLk89zgXfxKFWWR+iDjSvA0hgaiRj1V3C2HIyS8f CLpalf6ao2+O008rUiaiqJyxWuwLujcdYokay2HXvTYc45rXrVwvlaDajxqs2eer lekUA4ZbX2g6qvB0lna6PNlv8JLQ1XPdzhWD2eeQIi7JgVSgwg++kUJqglsuai56 eg5zNo6891GL9zFW10/A =0JbT -----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 diff is dominated by the Allwinner A10/A20 SoCs getting converted to the sunxi-ng framework. Otherwise, the heavy hitters are various drivers for SoCs like AT91, Amlogic, Renesas, and Rockchip. There are some other new clk drivers in here too but overall this is just a bunch of clk drivers for various different pieces of hardware and a collection of non-critical fixes for clk drivers. New Drivers: - Allwinner R40 SoCs - Renesas R-Car Gen3 USB 2.0 clock selector PHY - Atmel AT91 audio PLL - Uniphier PXs3 SoCs - ARC HSDK Board PLLs - AXS10X Board PLLs - STMicroelectronics STM32H743 SoCs Removed Drivers: - Non-compiling mb86s7x support Updates: - Allwinner A10/A20 SoCs converted to sunxi-ng framework - Allwinner H3 CPU clk fixes - Renesas R-Car D3 SoC - Renesas V2H and M3-W modules - Samsung Exynos5420/5422/5800 audio fixes - Rockchip fractional clk approximation fixes - Rockchip rk3126 SoC support within the rk3128 driver - Amlogic gxbb CEC32 and sd_emmc clks - Amlogic meson8b reset controller support - IDT VersaClock 5P49V5925/5P49V6901 support - Qualcomm MSM8996 SMMU clks - Various 'const' applications for struct clk_ops - si5351 PLL reset bugfix - Uniphier audio on LD11/LD20 and ethernet support on LD11/LD20/Pro4/PXs2 - Assorted Tegra clk driver fixes" * tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (120 commits) clk: si5351: fix PLL reset ASoC: atmel-classd: remove aclk clock ASoC: atmel-classd: remove aclk clock from DT binding clk: at91: clk-generated: make gclk determine audio_pll rate clk: at91: clk-generated: create function to find best_diff clk: at91: add audio pll clock drivers dt-bindings: clk: at91: add audio plls to the compatible list clk: at91: clk-generated: remove useless divisor loop clk: mb86s7x: Drop non-building driver clk: ti: check for null return in strrchr to avoid null dereferencing clk: Don't write error code into divider register clk: uniphier: add video input subsystem clock clk: uniphier: add audio system clock clk: stm32h7: Add stm32h743 clock driver clk: gate: expose clk_gate_ops::is_enabled clk: nxp: clk-lpc32xx: rename clk_gate_is_enabled() clk: uniphier: add PXs3 clock data clk: hi6220: change watchdog clock source clk: Kconfig: Name RK805 in Kconfig for COMMON_CLK_RK808 clk: cs2000: Add cs2000_set_saved_rate ...
This commit is contained in:
commit
f60a2abfdb
|
@ -5,9 +5,11 @@ controllers within the Always-On part of the SoC.
|
|||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be "amlogic,gxbb-aoclkc"
|
||||
- reg: physical base address of the clock controller and length of memory
|
||||
mapped region.
|
||||
- compatible: value should be different for each SoC family as :
|
||||
- GXBB (S905) : "amlogic,meson-gxbb-aoclkc"
|
||||
- GXL (S905X, S905D) : "amlogic,meson-gxl-aoclkc"
|
||||
- GXM (S912) : "amlogic,meson-gxm-aoclkc"
|
||||
followed by the common "amlogic,meson-gx-aoclkc"
|
||||
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
|
@ -23,14 +25,22 @@ to specify the reset which they consume. All available resets are defined as
|
|||
preprocessor macros in the dt-bindings/reset/gxbb-aoclkc.h header and can be
|
||||
used in device tree sources.
|
||||
|
||||
Parent node should have the following properties :
|
||||
- compatible: "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd"
|
||||
- reg: base address and size of the AO system control register space.
|
||||
|
||||
Example: AO Clock controller node:
|
||||
|
||||
clkc_AO: clock-controller@040 {
|
||||
compatible = "amlogic,gxbb-aoclkc";
|
||||
reg = <0x0 0x040 0x0 0x4>;
|
||||
ao_sysctrl: sys-ctrl@0 {
|
||||
compatible = "amlogic,meson-gx-ao-sysctrl", "syscon", "simple-mfd";
|
||||
reg = <0x0 0x0 0x0 0x100>;
|
||||
|
||||
clkc_AO: clock-controller {
|
||||
compatible = "amlogic,meson-gxbb-aoclkc", "amlogic,meson-gx-aoclkc";
|
||||
#clock-cells = <1>;
|
||||
#reset-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
Example: UART controller node that consumes the clock and reset generated
|
||||
by the clock controller:
|
||||
|
|
|
@ -81,6 +81,16 @@ Required properties:
|
|||
"atmel,sama5d2-clk-generated":
|
||||
at91 generated clock
|
||||
|
||||
"atmel,sama5d2-clk-audio-pll-frac":
|
||||
at91 audio fractional pll
|
||||
|
||||
"atmel,sama5d2-clk-audio-pll-pad":
|
||||
at91 audio pll CLK_AUDIO output pin
|
||||
|
||||
"atmel,sama5d2-clk-audio-pll-pmc"
|
||||
at91 audio pll output on AUDIOPLLCLK that feeds the PMC
|
||||
and can be used by peripheral clock or generic clock
|
||||
|
||||
Required properties for SCKC node:
|
||||
- reg : defines the IO memory reserved for the SCKC.
|
||||
- #size-cells : shall be 0 (reg is used to encode clk id).
|
||||
|
|
|
@ -1,24 +1,32 @@
|
|||
Binding for IDT VersaClock5 programmable i2c clock generator.
|
||||
Binding for IDT VersaClock 5,6 programmable i2c clock generators.
|
||||
|
||||
The IDT VersaClock5 are programmable i2c clock generators providing
|
||||
from 3 to 12 output clocks.
|
||||
The IDT VersaClock 5 and VersaClock 6 are programmable i2c clock
|
||||
generators providing from 3 to 12 output clocks.
|
||||
|
||||
==I2C device node==
|
||||
|
||||
Required properties:
|
||||
- compatible: shall be one of "idt,5p49v5923" , "idt,5p49v5933" ,
|
||||
"idt,5p49v5935".
|
||||
- compatible: shall be one of
|
||||
"idt,5p49v5923"
|
||||
"idt,5p49v5925"
|
||||
"idt,5p49v5933"
|
||||
"idt,5p49v5935"
|
||||
"idt,5p49v6901"
|
||||
- reg: i2c device address, shall be 0x68 or 0x6a.
|
||||
- #clock-cells: from common clock binding; shall be set to 1.
|
||||
- clocks: from common clock binding; list of parent clock handles,
|
||||
- 5p49v5923: (required) either or both of XTAL or CLKIN
|
||||
- 5p49v5923 and
|
||||
5p49v5925 and
|
||||
5p49v6901: (required) either or both of XTAL or CLKIN
|
||||
reference clock.
|
||||
- 5p49v5933 and
|
||||
- 5p49v5935: (optional) property not present (internal
|
||||
Xtal used) or CLKIN reference
|
||||
clock.
|
||||
- clock-names: from common clock binding; clock input names, can be
|
||||
- 5p49v5923: (required) either or both of "xin", "clkin".
|
||||
- 5p49v5923 and
|
||||
5p49v5925 and
|
||||
5p49v6901: (required) either or both of "xin", "clkin".
|
||||
- 5p49v5933 and
|
||||
- 5p49v5935: (optional) property not present or "clkin".
|
||||
|
||||
|
@ -37,6 +45,7 @@ clock specifier, the following mapping applies:
|
|||
1 -- OUT1
|
||||
2 -- OUT4
|
||||
|
||||
5P49V5925 and
|
||||
5P49V5935:
|
||||
0 -- OUT0_SEL_I2CB
|
||||
1 -- OUT1
|
||||
|
@ -44,6 +53,13 @@ clock specifier, the following mapping applies:
|
|||
3 -- OUT3
|
||||
4 -- OUT4
|
||||
|
||||
5P49V6901:
|
||||
0 -- OUT0_SEL_I2CB
|
||||
1 -- OUT1
|
||||
2 -- OUT2
|
||||
3 -- OUT3
|
||||
4 -- OUT4
|
||||
|
||||
==Example==
|
||||
|
||||
/* 25MHz reference crystal */
|
||||
|
|
|
@ -22,6 +22,7 @@ Required Properties:
|
|||
- "renesas,r8a7794-cpg-mssr" for the r8a7794 SoC (R-Car E2)
|
||||
- "renesas,r8a7795-cpg-mssr" for the r8a7795 SoC (R-Car H3)
|
||||
- "renesas,r8a7796-cpg-mssr" for the r8a7796 SoC (R-Car M3-W)
|
||||
- "renesas,r8a77995-cpg-mssr" for the r8a77995 SoC (R-Car D3)
|
||||
|
||||
- reg: Base address and length of the memory resource used by the CPG/MSSR
|
||||
block
|
||||
|
@ -30,7 +31,7 @@ Required Properties:
|
|||
clock-names
|
||||
- clock-names: List of external parent clock names. Valid names are:
|
||||
- "extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7792, r8a7793, r8a7794,
|
||||
r8a7795, r8a7796)
|
||||
r8a7795, r8a7796, r8a77995)
|
||||
- "extalr" (r8a7795, r8a7796)
|
||||
- "usb_extal" (r8a7743, r8a7745, r8a7790, r8a7791, r8a7793, r8a7794)
|
||||
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
* Renesas R-Car USB 2.0 clock selector
|
||||
|
||||
This file provides information on what the device node for the R-Car USB 2.0
|
||||
clock selector.
|
||||
|
||||
If you connect an external clock to the USB_EXTAL pin only, you should set
|
||||
the clock rate to "usb_extal" node only.
|
||||
If you connect an oscillator to both the USB_XTAL and USB_EXTAL, this module
|
||||
is not needed because this is default setting. (Of course, you can set the
|
||||
clock rates to both "usb_extal" and "usb_xtal" nodes.
|
||||
|
||||
Case 1: An external clock connects to R-Car SoC
|
||||
+----------+ +--- R-Car ---------------------+
|
||||
|External |---|USB_EXTAL ---> all usb channels|
|
||||
|clock | |USB_XTAL |
|
||||
+----------+ +-------------------------------+
|
||||
In this case, we need this driver with "usb_extal" clock.
|
||||
|
||||
Case 2: An oscillator connects to R-Car SoC
|
||||
+----------+ +--- R-Car ---------------------+
|
||||
|Oscillator|---|USB_EXTAL -+-> all usb channels|
|
||||
| |---|USB_XTAL --+ |
|
||||
+----------+ +-------------------------------+
|
||||
In this case, we don't need this selector.
|
||||
|
||||
Required properties:
|
||||
- compatible: "renesas,r8a7795-rcar-usb2-clock-sel" if the device is a part of
|
||||
an R8A7795 SoC.
|
||||
"renesas,r8a7796-rcar-usb2-clock-sel" if the device if a part of
|
||||
an R8A7796 SoC.
|
||||
"renesas,rcar-gen3-usb2-clock-sel" for a generic R-Car Gen3
|
||||
compatible device.
|
||||
|
||||
When compatible with the generic version, nodes must list the
|
||||
SoC-specific version corresponding to the platform first
|
||||
followed by the generic version.
|
||||
|
||||
- reg: offset and length of the USB 2.0 clock selector register block.
|
||||
- clocks: A list of phandles and specifier pairs.
|
||||
- clock-names: Name of the clocks.
|
||||
- The functional clock must be "ehci_ohci"
|
||||
- The USB_EXTAL clock pin must be "usb_extal"
|
||||
- The USB_XTAL clock pin must be "usb_xtal"
|
||||
- #clock-cells: Must be 0
|
||||
|
||||
Example (R-Car H3):
|
||||
|
||||
usb2_clksel: clock-controller@e6590630 {
|
||||
compatible = "renesas,r8a77950-rcar-usb2-clock-sel",
|
||||
"renesas,rcar-gen3-usb2-clock-sel";
|
||||
reg = <0 0xe6590630 0 0x02>;
|
||||
clocks = <&cpg CPG_MOD 703>, <&usb_extal>, <&usb_xtal>;
|
||||
clock-names = "ehci_ohci", "usb_extal", "usb_xtal";
|
||||
#clock-cells = <0>;
|
||||
};
|
|
@ -1,12 +1,14 @@
|
|||
* Rockchip RK3128 Clock and Reset Unit
|
||||
* Rockchip RK3126/RK3128 Clock and Reset Unit
|
||||
|
||||
The RK3128 clock controller generates and supplies clock to various
|
||||
The RK3126/RK3128 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,rk3128-cru"
|
||||
- compatible: should be "rockchip,rk3126-cru" or "rockchip,rk3128-cru"
|
||||
"rockchip,rk3126-cru" - controller compatible with RK3126 SoC.
|
||||
"rockchip,rk3128-cru" - controller compatible with RK3128 SoC.
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- #clock-cells: should be 1.
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
Binding for the HSDK Generic PLL clock
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "snps,hsdk-<name>-pll-clock"
|
||||
"snps,hsdk-core-pll-clock"
|
||||
"snps,hsdk-gp-pll-clock"
|
||||
"snps,hsdk-hdmi-pll-clock"
|
||||
- reg : should contain base register location and length.
|
||||
- clocks: shall be the input parent clock phandle for the PLL.
|
||||
- #clock-cells: from common clock binding; Should always be set to 0.
|
||||
|
||||
Example:
|
||||
input_clk: input-clk {
|
||||
clock-frequency = <33333333>;
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
cpu_clk: cpu-clk@0 {
|
||||
compatible = "snps,hsdk-core-pll-clock";
|
||||
reg = <0x00 0x10>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&input_clk>;
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
Binding for the AXS10X Generic PLL clock
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "snps,axs10x-<name>-pll-clock"
|
||||
"snps,axs10x-arc-pll-clock"
|
||||
"snps,axs10x-pgu-pll-clock"
|
||||
- reg: should always contain 2 pairs address - length: first for PLL config
|
||||
registers and second for corresponding LOCK CGU register.
|
||||
- clocks: shall be the input parent clock phandle for the PLL.
|
||||
- #clock-cells: from common clock binding; Should always be set to 0.
|
||||
|
||||
Example:
|
||||
input-clk: input-clk {
|
||||
clock-frequency = <33333333>;
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
core-clk: core-clk@80 {
|
||||
compatible = "snps,axs10x-arc-pll-clock";
|
||||
reg = <0x80 0x10>, <0x100 0x10>;
|
||||
#clock-cells = <0>;
|
||||
clocks = <&input-clk>;
|
||||
};
|
|
@ -0,0 +1,71 @@
|
|||
STMicroelectronics STM32H7 Reset and Clock Controller
|
||||
=====================================================
|
||||
|
||||
The RCC IP is both a reset and a clock controller.
|
||||
|
||||
Please refer to clock-bindings.txt for common clock controller binding usage.
|
||||
Please also refer to reset.txt for common reset controller binding usage.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be:
|
||||
"st,stm32h743-rcc"
|
||||
|
||||
- reg: should be register base and length as documented in the
|
||||
datasheet
|
||||
|
||||
- #reset-cells: 1, see below
|
||||
|
||||
- #clock-cells : from common clock binding; shall be set to 1
|
||||
|
||||
- clocks: External oscillator clock phandle
|
||||
- high speed external clock signal (HSE)
|
||||
- low speed external clock signal (LSE)
|
||||
- external I2S clock (I2S_CKIN)
|
||||
|
||||
Optional properties:
|
||||
- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
|
||||
write protection (RTC clock).
|
||||
|
||||
Example:
|
||||
|
||||
rcc: reset-clock-controller@58024400 {
|
||||
compatible = "st,stm32h743-rcc", "st,stm32-rcc";
|
||||
reg = <0x58024400 0x400>;
|
||||
#reset-cells = <1>;
|
||||
#clock-cells = <2>;
|
||||
clocks = <&clk_hse>, <&clk_lse>, <&clk_i2s_ckin>;
|
||||
|
||||
st,syscfg = <&pwrcfg>;
|
||||
};
|
||||
|
||||
The peripheral clock consumer should specify the desired clock by
|
||||
having the clock ID in its "clocks" phandle cell.
|
||||
|
||||
Example:
|
||||
|
||||
timer5: timer@40000c00 {
|
||||
compatible = "st,stm32-timer";
|
||||
reg = <0x40000c00 0x400>;
|
||||
interrupts = <50>;
|
||||
clocks = <&rcc TIM5_CK>;
|
||||
};
|
||||
|
||||
Specifying softreset control of devices
|
||||
=======================================
|
||||
|
||||
Device nodes should specify the reset channel required in their "resets"
|
||||
property, containing a phandle to the reset device node and an index specifying
|
||||
which channel to use.
|
||||
The index is the bit number within the RCC registers bank, starting from RCC
|
||||
base address.
|
||||
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
|
||||
Where bit_offset is the bit offset within the register.
|
||||
|
||||
For example, for CRC reset:
|
||||
crc = AHB4RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x88 / 4 * 32 + 19 = 1107
|
||||
|
||||
Example:
|
||||
|
||||
timer2 {
|
||||
resets = <&rcc STM32H7_APB1L_RESET(TIM2)>;
|
||||
};
|
|
@ -3,18 +3,24 @@ Allwinner Clock Control Unit Binding
|
|||
|
||||
Required properties :
|
||||
- compatible: must contain one of the following compatibles:
|
||||
- "allwinner,sun4i-a10-ccu"
|
||||
- "allwinner,sun5i-a10s-ccu"
|
||||
- "allwinner,sun5i-a13-ccu"
|
||||
- "allwinner,sun6i-a31-ccu"
|
||||
- "allwinner,sun7i-a20-ccu"
|
||||
- "allwinner,sun8i-a23-ccu"
|
||||
- "allwinner,sun8i-a33-ccu"
|
||||
- "allwinner,sun8i-a83t-ccu"
|
||||
- "allwinner,sun8i-a83t-r-ccu"
|
||||
- "allwinner,sun8i-h3-ccu"
|
||||
- "allwinner,sun8i-h3-r-ccu"
|
||||
+ - "allwinner,sun8i-r40-ccu"
|
||||
- "allwinner,sun8i-v3s-ccu"
|
||||
- "allwinner,sun9i-a80-ccu"
|
||||
- "allwinner,sun50i-a64-ccu"
|
||||
- "allwinner,sun50i-a64-r-ccu"
|
||||
- "allwinner,sun50i-h5-ccu"
|
||||
- "nextthing,gr8-ccu"
|
||||
|
||||
- reg: Must contain the registers base address and length
|
||||
- clocks: phandle to the oscillators feeding the CCU. Two are needed:
|
||||
|
|
|
@ -6,7 +6,6 @@ System clock
|
|||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-clock" - for sLD3 SoC.
|
||||
"socionext,uniphier-ld4-clock" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-clock" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-clock" - for sLD8 SoC.
|
||||
|
@ -14,6 +13,7 @@ Required properties:
|
|||
"socionext,uniphier-pxs2-clock" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-clock" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-clock" - for LD20 SoC.
|
||||
"socionext,uniphier-pxs3-clock" - for PXs3 SoC
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
@ -48,7 +48,6 @@ Media I/O (MIO) clock, SD clock
|
|||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-mio-clock" - for sLD3 SoC.
|
||||
"socionext,uniphier-ld4-mio-clock" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-mio-clock" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-mio-clock" - for sLD8 SoC.
|
||||
|
@ -56,6 +55,7 @@ Required properties:
|
|||
"socionext,uniphier-pxs2-sd-clock" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-mio-clock" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-sd-clock" - for LD20 SoC.
|
||||
"socionext,uniphier-pxs3-sd-clock" - for PXs3 SoC
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
@ -82,11 +82,9 @@ Provided clocks:
|
|||
8: USB2 ch0 host
|
||||
9: USB2 ch1 host
|
||||
10: USB2 ch2 host
|
||||
11: USB2 ch3 host
|
||||
12: USB2 ch0 PHY
|
||||
13: USB2 ch1 PHY
|
||||
14: USB2 ch2 PHY
|
||||
15: USB2 ch3 PHY
|
||||
|
||||
|
||||
Peripheral clock
|
||||
|
@ -94,7 +92,6 @@ Peripheral clock
|
|||
|
||||
Required properties:
|
||||
- compatible: should be one of the following:
|
||||
"socionext,uniphier-sld3-peri-clock" - for sLD3 SoC.
|
||||
"socionext,uniphier-ld4-peri-clock" - for LD4 SoC.
|
||||
"socionext,uniphier-pro4-peri-clock" - for Pro4 SoC.
|
||||
"socionext,uniphier-sld8-peri-clock" - for sLD8 SoC.
|
||||
|
@ -102,6 +99,7 @@ Required properties:
|
|||
"socionext,uniphier-pxs2-peri-clock" - for PXs2/LD6b SoC.
|
||||
"socionext,uniphier-ld11-peri-clock" - for LD11 SoC.
|
||||
"socionext,uniphier-ld20-peri-clock" - for LD20 SoC.
|
||||
"socionext,uniphier-pxs3-peri-clock" - for PXs3 SoC
|
||||
- #clock-cells: should be 1.
|
||||
|
||||
Example:
|
||||
|
|
|
@ -13,13 +13,11 @@ Required properties:
|
|||
Must be "tx".
|
||||
- clock-names
|
||||
Tuple listing input clock names.
|
||||
Required elements: "pclk", "gclk" and "aclk".
|
||||
Required elements: "pclk" and "gclk".
|
||||
- clocks
|
||||
Please refer to clock-bindings.txt.
|
||||
- assigned-clocks
|
||||
Should be <&classd_gclk>.
|
||||
- assigned-clock-parents
|
||||
Should be <&audio_pll_pmc>.
|
||||
|
||||
Optional properties:
|
||||
- pinctrl-names, pinctrl-0
|
||||
|
@ -45,10 +43,9 @@ classd: classd@fc048000 {
|
|||
(AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
|
||||
| AT91_XDMAC_DT_PERID(47))>;
|
||||
dma-names = "tx";
|
||||
clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>;
|
||||
clock-names = "pclk", "gclk", "aclk";
|
||||
clocks = <&classd_clk>, <&classd_gclk>;
|
||||
clock-names = "pclk", "gclk";
|
||||
assigned-clocks = <&classd_gclk>;
|
||||
assigned-clock-parents = <&audio_pll_pmc>;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_classd_default>;
|
||||
|
|
12
MAINTAINERS
12
MAINTAINERS
|
@ -12842,6 +12842,18 @@ F: drivers/clocksource/arc_timer.c
|
|||
F: drivers/tty/serial/arc_uart.c
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git
|
||||
|
||||
SYNOPSYS ARC HSDK SDP pll clock driver
|
||||
M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
|
||||
S: Supported
|
||||
F: drivers/clk/clk-hsdk-pll.c
|
||||
F: Documentation/devicetree/bindings/clock/snps,hsdk-pll-clock.txt
|
||||
|
||||
SYNOPSYS ARC SDP clock driver
|
||||
M: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
|
||||
S: Supported
|
||||
F: drivers/clk/axs10x/*
|
||||
F: Documentation/devicetree/bindings/clock/snps,pll-clock.txt
|
||||
|
||||
SYNOPSYS ARC SDP platform support
|
||||
M: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
S: Supported
|
||||
|
|
|
@ -26,6 +26,7 @@ config SOC_SAMA5D2
|
|||
select HAVE_AT91_USB_CLK
|
||||
select HAVE_AT91_H32MX
|
||||
select HAVE_AT91_GENERATED_CLK
|
||||
select HAVE_AT91_AUDIO_PLL
|
||||
select PINCTRL_AT91PIO4
|
||||
help
|
||||
Select this if ou are using one of Atmel's SAMA5D2 family SoC.
|
||||
|
@ -125,6 +126,9 @@ config HAVE_AT91_H32MX
|
|||
config HAVE_AT91_GENERATED_CLK
|
||||
bool
|
||||
|
||||
config HAVE_AT91_AUDIO_PLL
|
||||
bool
|
||||
|
||||
config SOC_SAM_V4_V5
|
||||
bool
|
||||
|
||||
|
|
|
@ -31,6 +31,13 @@ config COMMON_CLK_WM831X
|
|||
|
||||
source "drivers/clk/versatile/Kconfig"
|
||||
|
||||
config CLK_HSDK
|
||||
bool "PLL Driver for HSDK platform"
|
||||
depends on OF || COMPILE_TEST
|
||||
---help---
|
||||
This driver supports the HSDK core, system, ddr, tunnel and hdmi PLLs
|
||||
control.
|
||||
|
||||
config COMMON_CLK_MAX77686
|
||||
tristate "Clock driver for Maxim 77620/77686/77802 MFD"
|
||||
depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST
|
||||
|
@ -39,10 +46,10 @@ config COMMON_CLK_MAX77686
|
|||
clock.
|
||||
|
||||
config COMMON_CLK_RK808
|
||||
tristate "Clock driver for RK808/RK818"
|
||||
tristate "Clock driver for RK805/RK808/RK818"
|
||||
depends on MFD_RK808
|
||||
---help---
|
||||
This driver supports RK808 and RK818 crystal oscillator clock. These
|
||||
This driver supports RK805, RK808 and RK818 crystal oscillator clock. These
|
||||
multi-function devices have two fixed-rate oscillators,
|
||||
clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
|
||||
by control register.
|
||||
|
@ -210,14 +217,14 @@ config COMMON_CLK_OXNAS
|
|||
Support for the OXNAS SoC Family clocks.
|
||||
|
||||
config COMMON_CLK_VC5
|
||||
tristate "Clock driver for IDT VersaClock5 devices"
|
||||
tristate "Clock driver for IDT VersaClock 5,6 devices"
|
||||
depends on I2C
|
||||
depends on OF
|
||||
select REGMAP_I2C
|
||||
help
|
||||
---help---
|
||||
This driver supports the IDT VersaClock5 programmable clock
|
||||
generator.
|
||||
This driver supports the IDT VersaClock 5 and VersaClock 6
|
||||
programmable clock generators.
|
||||
|
||||
source "drivers/clk/bcm/Kconfig"
|
||||
source "drivers/clk/hisilicon/Kconfig"
|
||||
|
|
|
@ -27,8 +27,8 @@ obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
|
|||
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
|
||||
obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
|
||||
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
|
||||
obj-$(CONFIG_CLK_HSDK) += clk-hsdk-pll.o
|
||||
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
|
||||
obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o
|
||||
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
|
||||
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
|
||||
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
|
||||
|
@ -44,6 +44,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
|
|||
obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
|
||||
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
|
||||
obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
|
||||
obj-$(CONFIG_ARCH_STM32) += clk-stm32h7.o
|
||||
obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o
|
||||
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
|
||||
obj-$(CONFIG_ARCH_U300) += clk-u300.o
|
||||
|
|
|
@ -6,6 +6,7 @@ obj-y += pmc.o sckc.o
|
|||
obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o
|
||||
obj-y += clk-system.o clk-peripheral.o clk-programmable.o
|
||||
|
||||
obj-$(CONFIG_HAVE_AT91_AUDIO_PLL) += clk-audio-pll.o
|
||||
obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o
|
||||
obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o
|
||||
obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o
|
||||
|
|
|
@ -0,0 +1,536 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Atmel Corporation,
|
||||
* Songjun Wu <songjun.wu@atmel.com>,
|
||||
* Nicolas Ferre <nicolas.ferre@atmel.com>
|
||||
* Copyright (C) 2017 Free Electrons,
|
||||
* Quentin Schulz <quentin.schulz@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Sama5d2 SoC has two audio PLLs (PMC and PAD) that shares the same parent
|
||||
* (FRAC). FRAC can output between 620 and 700MHz and only multiply the rate of
|
||||
* its own parent. PMC and PAD can then divide the FRAC rate to best match the
|
||||
* asked rate.
|
||||
*
|
||||
* Traits of FRAC clock:
|
||||
* enable - clk_enable writes nd, fracr parameters and enables PLL
|
||||
* rate - rate is adjustable.
|
||||
* clk->rate = parent->rate * ((nd + 1) + (fracr / 2^22))
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*
|
||||
* Traits of PMC clock:
|
||||
* enable - clk_enable writes qdpmc, and enables PMC output
|
||||
* rate - rate is adjustable.
|
||||
* clk->rate = parent->rate / (qdpmc + 1)
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*
|
||||
* Traits of PAD clock:
|
||||
* enable - clk_enable writes divisors and enables PAD output
|
||||
* rate - rate is adjustable.
|
||||
* clk->rate = parent->rate / (qdaudio * div))
|
||||
* parent - fixed parent. No clk_set_parent support
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk/at91_pmc.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define AUDIO_PLL_DIV_FRAC BIT(22)
|
||||
#define AUDIO_PLL_ND_MAX (AT91_PMC_AUDIO_PLL_ND_MASK >> \
|
||||
AT91_PMC_AUDIO_PLL_ND_OFFSET)
|
||||
|
||||
#define AUDIO_PLL_QDPAD(qd, div) ((AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV(qd) & \
|
||||
AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MASK) | \
|
||||
(AT91_PMC_AUDIO_PLL_QDPAD_DIV(div) & \
|
||||
AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK))
|
||||
|
||||
#define AUDIO_PLL_QDPMC_MAX (AT91_PMC_AUDIO_PLL_QDPMC_MASK >> \
|
||||
AT91_PMC_AUDIO_PLL_QDPMC_OFFSET)
|
||||
|
||||
#define AUDIO_PLL_FOUT_MIN 620000000UL
|
||||
#define AUDIO_PLL_FOUT_MAX 700000000UL
|
||||
|
||||
struct clk_audio_frac {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
u32 fracr;
|
||||
u8 nd;
|
||||
};
|
||||
|
||||
struct clk_audio_pad {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
u8 qdaudio;
|
||||
u8 div;
|
||||
};
|
||||
|
||||
struct clk_audio_pmc {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
u8 qdpmc;
|
||||
};
|
||||
|
||||
#define to_clk_audio_frac(hw) container_of(hw, struct clk_audio_frac, hw)
|
||||
#define to_clk_audio_pad(hw) container_of(hw, struct clk_audio_pad, hw)
|
||||
#define to_clk_audio_pmc(hw) container_of(hw, struct clk_audio_pmc, hw)
|
||||
|
||||
static int clk_audio_pll_frac_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_audio_frac *frac = to_clk_audio_frac(hw);
|
||||
|
||||
regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_RESETN, 0);
|
||||
regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_RESETN,
|
||||
AT91_PMC_AUDIO_PLL_RESETN);
|
||||
regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL1,
|
||||
AT91_PMC_AUDIO_PLL_FRACR_MASK, frac->fracr);
|
||||
|
||||
/*
|
||||
* reset and enable have to be done in 2 separated writes
|
||||
* for AT91_PMC_AUDIO_PLL0
|
||||
*/
|
||||
regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_PLLEN |
|
||||
AT91_PMC_AUDIO_PLL_ND_MASK,
|
||||
AT91_PMC_AUDIO_PLL_PLLEN |
|
||||
AT91_PMC_AUDIO_PLL_ND(frac->nd));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_audio_pll_pad_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
|
||||
|
||||
regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL1,
|
||||
AT91_PMC_AUDIO_PLL_QDPAD_MASK,
|
||||
AUDIO_PLL_QDPAD(apad_ck->qdaudio, apad_ck->div));
|
||||
regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_PADEN, AT91_PMC_AUDIO_PLL_PADEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_audio_pll_pmc_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
|
||||
|
||||
regmap_update_bits(apmc_ck->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_PMCEN |
|
||||
AT91_PMC_AUDIO_PLL_QDPMC_MASK,
|
||||
AT91_PMC_AUDIO_PLL_PMCEN |
|
||||
AT91_PMC_AUDIO_PLL_QDPMC(apmc_ck->qdpmc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void clk_audio_pll_frac_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_audio_frac *frac = to_clk_audio_frac(hw);
|
||||
|
||||
regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_PLLEN, 0);
|
||||
/* do it in 2 separated writes */
|
||||
regmap_update_bits(frac->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_RESETN, 0);
|
||||
}
|
||||
|
||||
static void clk_audio_pll_pad_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
|
||||
|
||||
regmap_update_bits(apad_ck->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_PADEN, 0);
|
||||
}
|
||||
|
||||
static void clk_audio_pll_pmc_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
|
||||
|
||||
regmap_update_bits(apmc_ck->regmap, AT91_PMC_AUDIO_PLL0,
|
||||
AT91_PMC_AUDIO_PLL_PMCEN, 0);
|
||||
}
|
||||
|
||||
static unsigned long clk_audio_pll_fout(unsigned long parent_rate,
|
||||
unsigned long nd, unsigned long fracr)
|
||||
{
|
||||
unsigned long long fr = (unsigned long long)parent_rate * fracr;
|
||||
|
||||
pr_debug("A PLL: %s, fr = %llu\n", __func__, fr);
|
||||
|
||||
fr = DIV_ROUND_CLOSEST_ULL(fr, AUDIO_PLL_DIV_FRAC);
|
||||
|
||||
pr_debug("A PLL: %s, fr = %llu\n", __func__, fr);
|
||||
|
||||
return parent_rate * (nd + 1) + fr;
|
||||
}
|
||||
|
||||
static unsigned long clk_audio_pll_frac_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_audio_frac *frac = to_clk_audio_frac(hw);
|
||||
unsigned long fout;
|
||||
|
||||
fout = clk_audio_pll_fout(parent_rate, frac->nd, frac->fracr);
|
||||
|
||||
pr_debug("A PLL: %s, fout = %lu (nd = %u, fracr = %lu)\n", __func__,
|
||||
fout, frac->nd, (unsigned long)frac->fracr);
|
||||
|
||||
return fout;
|
||||
}
|
||||
|
||||
static unsigned long clk_audio_pll_pad_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
|
||||
unsigned long apad_rate = 0;
|
||||
|
||||
if (apad_ck->qdaudio && apad_ck->div)
|
||||
apad_rate = parent_rate / (apad_ck->qdaudio * apad_ck->div);
|
||||
|
||||
pr_debug("A PLL/PAD: %s, apad_rate = %lu (div = %u, qdaudio = %u)\n",
|
||||
__func__, apad_rate, apad_ck->div, apad_ck->qdaudio);
|
||||
|
||||
return apad_rate;
|
||||
}
|
||||
|
||||
static unsigned long clk_audio_pll_pmc_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
|
||||
unsigned long apmc_rate = 0;
|
||||
|
||||
apmc_rate = parent_rate / (apmc_ck->qdpmc + 1);
|
||||
|
||||
pr_debug("A PLL/PMC: %s, apmc_rate = %lu (qdpmc = %u)\n", __func__,
|
||||
apmc_rate, apmc_ck->qdpmc);
|
||||
|
||||
return apmc_rate;
|
||||
}
|
||||
|
||||
static int clk_audio_pll_frac_compute_frac(unsigned long rate,
|
||||
unsigned long parent_rate,
|
||||
unsigned long *nd,
|
||||
unsigned long *fracr)
|
||||
{
|
||||
unsigned long long tmp, rem;
|
||||
|
||||
if (!rate)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = rate;
|
||||
rem = do_div(tmp, parent_rate);
|
||||
if (!tmp || tmp >= AUDIO_PLL_ND_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
*nd = tmp - 1;
|
||||
|
||||
tmp = rem * AUDIO_PLL_DIV_FRAC;
|
||||
tmp = DIV_ROUND_CLOSEST_ULL(tmp, parent_rate);
|
||||
if (tmp > AT91_PMC_AUDIO_PLL_FRACR_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
/* we can cast here as we verified the bounds just above */
|
||||
*fracr = (unsigned long)tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_audio_pll_frac_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long fracr, nd;
|
||||
int ret;
|
||||
|
||||
pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__,
|
||||
req->rate, req->best_parent_rate);
|
||||
|
||||
req->rate = clamp(req->rate, AUDIO_PLL_FOUT_MIN, AUDIO_PLL_FOUT_MAX);
|
||||
|
||||
req->min_rate = max(req->min_rate, AUDIO_PLL_FOUT_MIN);
|
||||
req->max_rate = min(req->max_rate, AUDIO_PLL_FOUT_MAX);
|
||||
|
||||
ret = clk_audio_pll_frac_compute_frac(req->rate, req->best_parent_rate,
|
||||
&nd, &fracr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
req->rate = clk_audio_pll_fout(req->best_parent_rate, nd, fracr);
|
||||
|
||||
req->best_parent_hw = clk_hw_get_parent(hw);
|
||||
|
||||
pr_debug("A PLL: %s, best_rate = %lu (nd = %lu, fracr = %lu)\n",
|
||||
__func__, req->rate, nd, fracr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_hw *pclk = clk_hw_get_parent(hw);
|
||||
long best_rate = -EINVAL;
|
||||
unsigned long best_parent_rate;
|
||||
unsigned long tmp_qd;
|
||||
u32 div;
|
||||
long tmp_rate;
|
||||
int tmp_diff;
|
||||
int best_diff = -1;
|
||||
|
||||
pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
|
||||
rate, *parent_rate);
|
||||
|
||||
/*
|
||||
* Rate divisor is actually made of two different divisors, multiplied
|
||||
* between themselves before dividing the rate.
|
||||
* tmp_qd goes from 1 to 31 and div is either 2 or 3.
|
||||
* In order to avoid testing twice the rate divisor (e.g. divisor 12 can
|
||||
* be found with (tmp_qd, div) = (2, 6) or (3, 4)), we remove any loop
|
||||
* for a rate divisor when div is 2 and tmp_qd is a multiple of 3.
|
||||
* We cannot inverse it (condition div is 3 and tmp_qd is even) or we
|
||||
* would miss some rate divisor that aren't reachable with div being 2
|
||||
* (e.g. rate divisor 90 is made with div = 3 and tmp_qd = 30, thus
|
||||
* tmp_qd is even so we skip it because we think div 2 could make this
|
||||
* rate divisor which isn't possible since tmp_qd has to be <= 31).
|
||||
*/
|
||||
for (tmp_qd = 1; tmp_qd < AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX; tmp_qd++)
|
||||
for (div = 2; div <= 3; div++) {
|
||||
if (div == 2 && tmp_qd % 3 == 0)
|
||||
continue;
|
||||
|
||||
best_parent_rate = clk_hw_round_rate(pclk,
|
||||
rate * tmp_qd * div);
|
||||
tmp_rate = best_parent_rate / (div * tmp_qd);
|
||||
tmp_diff = abs(rate - tmp_rate);
|
||||
|
||||
if (best_diff < 0 || best_diff > tmp_diff) {
|
||||
*parent_rate = best_parent_rate;
|
||||
best_rate = tmp_rate;
|
||||
best_diff = tmp_diff;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("A PLL/PAD: %s, best_rate = %ld, best_parent_rate = %lu\n",
|
||||
__func__, best_rate, best_parent_rate);
|
||||
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_hw *pclk = clk_hw_get_parent(hw);
|
||||
long best_rate = -EINVAL;
|
||||
unsigned long best_parent_rate = 0;
|
||||
u32 tmp_qd = 0, div;
|
||||
long tmp_rate;
|
||||
int tmp_diff;
|
||||
int best_diff = -1;
|
||||
|
||||
pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
|
||||
rate, *parent_rate);
|
||||
|
||||
for (div = 1; div <= AUDIO_PLL_QDPMC_MAX; div++) {
|
||||
best_parent_rate = clk_round_rate(pclk->clk, rate * div);
|
||||
tmp_rate = best_parent_rate / div;
|
||||
tmp_diff = abs(rate - tmp_rate);
|
||||
|
||||
if (best_diff < 0 || best_diff > tmp_diff) {
|
||||
*parent_rate = best_parent_rate;
|
||||
best_rate = tmp_rate;
|
||||
best_diff = tmp_diff;
|
||||
tmp_qd = div;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("A PLL/PMC: %s, best_rate = %ld, best_parent_rate = %lu (qd = %d)\n",
|
||||
__func__, best_rate, *parent_rate, tmp_qd - 1);
|
||||
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
static int clk_audio_pll_frac_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_audio_frac *frac = to_clk_audio_frac(hw);
|
||||
unsigned long fracr, nd;
|
||||
int ret;
|
||||
|
||||
pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n", __func__, rate,
|
||||
parent_rate);
|
||||
|
||||
if (rate < AUDIO_PLL_FOUT_MIN || rate > AUDIO_PLL_FOUT_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
ret = clk_audio_pll_frac_compute_frac(rate, parent_rate, &nd, &fracr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
frac->nd = nd;
|
||||
frac->fracr = fracr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_audio_pll_pad_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw);
|
||||
u8 tmp_div;
|
||||
|
||||
pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n", __func__,
|
||||
rate, parent_rate);
|
||||
|
||||
if (!rate)
|
||||
return -EINVAL;
|
||||
|
||||
tmp_div = parent_rate / rate;
|
||||
if (tmp_div % 3 == 0) {
|
||||
apad_ck->qdaudio = tmp_div / 3;
|
||||
apad_ck->div = 3;
|
||||
} else {
|
||||
apad_ck->qdaudio = tmp_div / 2;
|
||||
apad_ck->div = 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clk_audio_pll_pmc_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw);
|
||||
|
||||
if (!rate)
|
||||
return -EINVAL;
|
||||
|
||||
pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n", __func__,
|
||||
rate, parent_rate);
|
||||
|
||||
apmc_ck->qdpmc = parent_rate / rate - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops audio_pll_frac_ops = {
|
||||
.enable = clk_audio_pll_frac_enable,
|
||||
.disable = clk_audio_pll_frac_disable,
|
||||
.recalc_rate = clk_audio_pll_frac_recalc_rate,
|
||||
.determine_rate = clk_audio_pll_frac_determine_rate,
|
||||
.set_rate = clk_audio_pll_frac_set_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops audio_pll_pad_ops = {
|
||||
.enable = clk_audio_pll_pad_enable,
|
||||
.disable = clk_audio_pll_pad_disable,
|
||||
.recalc_rate = clk_audio_pll_pad_recalc_rate,
|
||||
.round_rate = clk_audio_pll_pad_round_rate,
|
||||
.set_rate = clk_audio_pll_pad_set_rate,
|
||||
};
|
||||
|
||||
static const struct clk_ops audio_pll_pmc_ops = {
|
||||
.enable = clk_audio_pll_pmc_enable,
|
||||
.disable = clk_audio_pll_pmc_disable,
|
||||
.recalc_rate = clk_audio_pll_pmc_recalc_rate,
|
||||
.round_rate = clk_audio_pll_pmc_round_rate,
|
||||
.set_rate = clk_audio_pll_pmc_set_rate,
|
||||
};
|
||||
|
||||
static int of_sama5d2_clk_audio_pll_setup(struct device_node *np,
|
||||
struct clk_init_data *init,
|
||||
struct clk_hw *hw,
|
||||
struct regmap **clk_audio_regmap)
|
||||
{
|
||||
struct regmap *regmap;
|
||||
const char *parent_names[1];
|
||||
int ret;
|
||||
|
||||
regmap = syscon_node_to_regmap(of_get_parent(np));
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
init->name = np->name;
|
||||
of_clk_parent_fill(np, parent_names, 1);
|
||||
init->parent_names = parent_names;
|
||||
init->num_parents = 1;
|
||||
|
||||
hw->init = init;
|
||||
*clk_audio_regmap = regmap;
|
||||
|
||||
ret = clk_hw_register(NULL, hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
|
||||
}
|
||||
|
||||
static void __init of_sama5d2_clk_audio_pll_frac_setup(struct device_node *np)
|
||||
{
|
||||
struct clk_audio_frac *frac_ck;
|
||||
struct clk_init_data init = {};
|
||||
|
||||
frac_ck = kzalloc(sizeof(*frac_ck), GFP_KERNEL);
|
||||
if (!frac_ck)
|
||||
return;
|
||||
|
||||
init.ops = &audio_pll_frac_ops;
|
||||
init.flags = CLK_SET_RATE_GATE;
|
||||
|
||||
if (of_sama5d2_clk_audio_pll_setup(np, &init, &frac_ck->hw,
|
||||
&frac_ck->regmap))
|
||||
kfree(frac_ck);
|
||||
}
|
||||
|
||||
static void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np)
|
||||
{
|
||||
struct clk_audio_pad *apad_ck;
|
||||
struct clk_init_data init = {};
|
||||
|
||||
apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL);
|
||||
if (!apad_ck)
|
||||
return;
|
||||
|
||||
init.ops = &audio_pll_pad_ops;
|
||||
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT;
|
||||
|
||||
if (of_sama5d2_clk_audio_pll_setup(np, &init, &apad_ck->hw,
|
||||
&apad_ck->regmap))
|
||||
kfree(apad_ck);
|
||||
}
|
||||
|
||||
static void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np)
|
||||
{
|
||||
struct clk_audio_pad *apmc_ck;
|
||||
struct clk_init_data init = {};
|
||||
|
||||
apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL);
|
||||
if (!apmc_ck)
|
||||
return;
|
||||
|
||||
init.ops = &audio_pll_pmc_ops;
|
||||
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT;
|
||||
|
||||
if (of_sama5d2_clk_audio_pll_setup(np, &init, &apmc_ck->hw,
|
||||
&apmc_ck->regmap))
|
||||
kfree(apmc_ck);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_frac_setup,
|
||||
"atmel,sama5d2-clk-audio-pll-frac",
|
||||
of_sama5d2_clk_audio_pll_frac_setup);
|
||||
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pad_setup,
|
||||
"atmel,sama5d2-clk-audio-pll-pad",
|
||||
of_sama5d2_clk_audio_pll_pad_setup);
|
||||
CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
|
||||
"atmel,sama5d2-clk-audio-pll-pmc",
|
||||
of_sama5d2_clk_audio_pll_pmc_setup);
|
|
@ -26,6 +26,13 @@
|
|||
#define GENERATED_SOURCE_MAX 6
|
||||
#define GENERATED_MAX_DIV 255
|
||||
|
||||
#define GCK_ID_SSC0 43
|
||||
#define GCK_ID_SSC1 44
|
||||
#define GCK_ID_I2S0 54
|
||||
#define GCK_ID_I2S1 55
|
||||
#define GCK_ID_CLASSD 59
|
||||
#define GCK_INDEX_DT_AUDIO_PLL 5
|
||||
|
||||
struct clk_generated {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
|
@ -34,6 +41,7 @@ struct clk_generated {
|
|||
u32 id;
|
||||
u32 gckdiv;
|
||||
u8 parent_id;
|
||||
bool audio_pll_allowed;
|
||||
};
|
||||
|
||||
#define to_clk_generated(hw) \
|
||||
|
@ -99,21 +107,41 @@ clk_generated_recalc_rate(struct clk_hw *hw,
|
|||
return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1);
|
||||
}
|
||||
|
||||
static void clk_generated_best_diff(struct clk_rate_request *req,
|
||||
struct clk_hw *parent,
|
||||
unsigned long parent_rate, u32 div,
|
||||
int *best_diff, long *best_rate)
|
||||
{
|
||||
unsigned long tmp_rate;
|
||||
int tmp_diff;
|
||||
|
||||
if (!div)
|
||||
tmp_rate = parent_rate;
|
||||
else
|
||||
tmp_rate = parent_rate / div;
|
||||
tmp_diff = abs(req->rate - tmp_rate);
|
||||
|
||||
if (*best_diff < 0 || *best_diff > tmp_diff) {
|
||||
*best_rate = tmp_rate;
|
||||
*best_diff = tmp_diff;
|
||||
req->best_parent_rate = parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
}
|
||||
}
|
||||
|
||||
static int clk_generated_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_generated *gck = to_clk_generated(hw);
|
||||
struct clk_hw *parent = NULL;
|
||||
struct clk_rate_request req_parent = *req;
|
||||
long best_rate = -EINVAL;
|
||||
unsigned long tmp_rate, min_rate;
|
||||
unsigned long min_rate, parent_rate;
|
||||
int best_diff = -1;
|
||||
int tmp_diff;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
u32 div;
|
||||
unsigned long parent_rate;
|
||||
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw) - 1; i++) {
|
||||
parent = clk_hw_get_parent_by_index(hw, i);
|
||||
if (!parent)
|
||||
continue;
|
||||
|
@ -124,25 +152,43 @@ static int clk_generated_determine_rate(struct clk_hw *hw,
|
|||
(gck->range.max && min_rate > gck->range.max))
|
||||
continue;
|
||||
|
||||
for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
|
||||
tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
|
||||
tmp_diff = abs(req->rate - tmp_rate);
|
||||
div = DIV_ROUND_CLOSEST(parent_rate, req->rate);
|
||||
|
||||
if (best_diff < 0 || best_diff > tmp_diff) {
|
||||
best_rate = tmp_rate;
|
||||
best_diff = tmp_diff;
|
||||
req->best_parent_rate = parent_rate;
|
||||
req->best_parent_hw = parent;
|
||||
}
|
||||
|
||||
if (!best_diff || tmp_rate < req->rate)
|
||||
break;
|
||||
}
|
||||
clk_generated_best_diff(req, parent, parent_rate, div,
|
||||
&best_diff, &best_rate);
|
||||
|
||||
if (!best_diff)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The audio_pll rate can be modified, unlike the five others clocks
|
||||
* that should never be altered.
|
||||
* The audio_pll can technically be used by multiple consumers. However,
|
||||
* with the rate locking, the first consumer to enable to clock will be
|
||||
* the one definitely setting the rate of the clock.
|
||||
* Since audio IPs are most likely to request the same rate, we enforce
|
||||
* that the only clks able to modify gck rate are those of audio IPs.
|
||||
*/
|
||||
|
||||
if (!gck->audio_pll_allowed)
|
||||
goto end;
|
||||
|
||||
parent = clk_hw_get_parent_by_index(hw, GCK_INDEX_DT_AUDIO_PLL);
|
||||
if (!parent)
|
||||
goto end;
|
||||
|
||||
for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
|
||||
req_parent.rate = req->rate * div;
|
||||
__clk_determine_rate(parent, &req_parent);
|
||||
clk_generated_best_diff(req, parent, req_parent.rate, div,
|
||||
&best_diff, &best_rate);
|
||||
|
||||
if (!best_diff)
|
||||
break;
|
||||
}
|
||||
|
||||
end:
|
||||
pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
|
||||
__func__, best_rate,
|
||||
__clk_get_name((req->best_parent_hw)->clk),
|
||||
|
@ -252,7 +298,8 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
|
|||
init.ops = &generated_ops;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
|
||||
init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
|
||||
CLK_SET_RATE_PARENT;
|
||||
|
||||
gck->id = id;
|
||||
gck->hw.init = &init;
|
||||
|
@ -284,6 +331,7 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
|
|||
struct device_node *gcknp;
|
||||
struct clk_range range = CLK_RANGE(0, 0);
|
||||
struct regmap *regmap;
|
||||
struct clk_generated *gck;
|
||||
|
||||
num_parents = of_clk_get_parent_count(np);
|
||||
if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
|
||||
|
@ -315,6 +363,21 @@ static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
|
|||
hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
|
||||
parent_names, num_parents,
|
||||
id, &range);
|
||||
|
||||
gck = to_clk_generated(hw);
|
||||
|
||||
if (of_device_is_compatible(np,
|
||||
"atmel,sama5d2-clk-generated")) {
|
||||
if (gck->id == GCK_ID_SSC0 || gck->id == GCK_ID_SSC1 ||
|
||||
gck->id == GCK_ID_I2S0 || gck->id == GCK_ID_I2S1 ||
|
||||
gck->id == GCK_ID_CLASSD)
|
||||
gck->audio_pll_allowed = true;
|
||||
else
|
||||
gck->audio_pll_allowed = false;
|
||||
} else {
|
||||
gck->audio_pll_allowed = false;
|
||||
}
|
||||
|
||||
if (IS_ERR(hw))
|
||||
continue;
|
||||
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
obj-y += i2s_pll_clock.o
|
||||
obj-y += pll_clock.o
|
||||
|
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* Synopsys AXS10X SDP Generic PLL clock driver
|
||||
*
|
||||
* Copyright (C) 2017 Synopsys
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/* PLL registers addresses */
|
||||
#define PLL_REG_IDIV 0x0
|
||||
#define PLL_REG_FBDIV 0x4
|
||||
#define PLL_REG_ODIV 0x8
|
||||
|
||||
/*
|
||||
* Bit fields of the PLL IDIV/FBDIV/ODIV registers:
|
||||
* ________________________________________________________________________
|
||||
* |31 15| 14 | 13 | 12 |11 6|5 0|
|
||||
* |-------RESRVED------|-NOUPDATE-|-BYPASS-|-EDGE-|--HIGHTIME--|--LOWTIME--|
|
||||
* |____________________|__________|________|______|____________|___________|
|
||||
*
|
||||
* Following macros determine the way of access to these registers
|
||||
* They should be set up only using the macros.
|
||||
* reg should be an u32 variable.
|
||||
*/
|
||||
|
||||
#define PLL_REG_GET_LOW(reg) \
|
||||
(((reg) & (0x3F << 0)) >> 0)
|
||||
#define PLL_REG_GET_HIGH(reg) \
|
||||
(((reg) & (0x3F << 6)) >> 6)
|
||||
#define PLL_REG_GET_EDGE(reg) \
|
||||
(((reg) & (BIT(12))) ? 1 : 0)
|
||||
#define PLL_REG_GET_BYPASS(reg) \
|
||||
(((reg) & (BIT(13))) ? 1 : 0)
|
||||
#define PLL_REG_GET_NOUPD(reg) \
|
||||
(((reg) & (BIT(14))) ? 1 : 0)
|
||||
#define PLL_REG_GET_PAD(reg) \
|
||||
(((reg) & (0x1FFFF << 15)) >> 15)
|
||||
|
||||
#define PLL_REG_SET_LOW(reg, value) \
|
||||
{ reg |= (((value) & 0x3F) << 0); }
|
||||
#define PLL_REG_SET_HIGH(reg, value) \
|
||||
{ reg |= (((value) & 0x3F) << 6); }
|
||||
#define PLL_REG_SET_EDGE(reg, value) \
|
||||
{ reg |= (((value) & 0x01) << 12); }
|
||||
#define PLL_REG_SET_BYPASS(reg, value) \
|
||||
{ reg |= (((value) & 0x01) << 13); }
|
||||
#define PLL_REG_SET_NOUPD(reg, value) \
|
||||
{ reg |= (((value) & 0x01) << 14); }
|
||||
#define PLL_REG_SET_PAD(reg, value) \
|
||||
{ reg |= (((value) & 0x1FFFF) << 15); }
|
||||
|
||||
#define PLL_LOCK BIT(0)
|
||||
#define PLL_ERROR BIT(1)
|
||||
#define PLL_MAX_LOCK_TIME 100 /* 100 us */
|
||||
|
||||
struct axs10x_pll_cfg {
|
||||
u32 rate;
|
||||
u32 idiv;
|
||||
u32 fbdiv;
|
||||
u32 odiv;
|
||||
};
|
||||
|
||||
static const struct axs10x_pll_cfg arc_pll_cfg[] = {
|
||||
{ 33333333, 1, 1, 1 },
|
||||
{ 50000000, 1, 30, 20 },
|
||||
{ 75000000, 2, 45, 10 },
|
||||
{ 90000000, 2, 54, 10 },
|
||||
{ 100000000, 1, 30, 10 },
|
||||
{ 125000000, 2, 45, 6 },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct axs10x_pll_cfg pgu_pll_cfg[] = {
|
||||
{ 25200000, 1, 84, 90 },
|
||||
{ 50000000, 1, 100, 54 },
|
||||
{ 74250000, 1, 44, 16 },
|
||||
{}
|
||||
};
|
||||
|
||||
struct axs10x_pll_clk {
|
||||
struct clk_hw hw;
|
||||
void __iomem *base;
|
||||
void __iomem *lock;
|
||||
const struct axs10x_pll_cfg *pll_cfg;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static inline void axs10x_pll_write(struct axs10x_pll_clk *clk, u32 reg,
|
||||
u32 val)
|
||||
{
|
||||
iowrite32(val, clk->base + reg);
|
||||
}
|
||||
|
||||
static inline u32 axs10x_pll_read(struct axs10x_pll_clk *clk, u32 reg)
|
||||
{
|
||||
return ioread32(clk->base + reg);
|
||||
}
|
||||
|
||||
static inline struct axs10x_pll_clk *to_axs10x_pll_clk(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct axs10x_pll_clk, hw);
|
||||
}
|
||||
|
||||
static inline u32 axs10x_div_get_value(u32 reg)
|
||||
{
|
||||
if (PLL_REG_GET_BYPASS(reg))
|
||||
return 1;
|
||||
|
||||
return PLL_REG_GET_HIGH(reg) + PLL_REG_GET_LOW(reg);
|
||||
}
|
||||
|
||||
static inline u32 axs10x_encode_div(unsigned int id, int upd)
|
||||
{
|
||||
u32 div = 0;
|
||||
|
||||
PLL_REG_SET_LOW(div, (id % 2 == 0) ? id >> 1 : (id >> 1) + 1);
|
||||
PLL_REG_SET_HIGH(div, id >> 1);
|
||||
PLL_REG_SET_EDGE(div, id % 2);
|
||||
PLL_REG_SET_BYPASS(div, id == 1 ? 1 : 0);
|
||||
PLL_REG_SET_NOUPD(div, upd == 0 ? 1 : 0);
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
static unsigned long axs10x_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u64 rate;
|
||||
u32 idiv, fbdiv, odiv;
|
||||
struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
|
||||
|
||||
idiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_IDIV));
|
||||
fbdiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_FBDIV));
|
||||
odiv = axs10x_div_get_value(axs10x_pll_read(clk, PLL_REG_ODIV));
|
||||
|
||||
rate = (u64)parent_rate * fbdiv;
|
||||
do_div(rate, idiv * odiv);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long axs10x_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
int i;
|
||||
long best_rate;
|
||||
struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
|
||||
const struct axs10x_pll_cfg *pll_cfg = clk->pll_cfg;
|
||||
|
||||
if (pll_cfg[0].rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
best_rate = pll_cfg[0].rate;
|
||||
|
||||
for (i = 1; pll_cfg[i].rate != 0; i++) {
|
||||
if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
|
||||
best_rate = pll_cfg[i].rate;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
static int axs10x_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
int i;
|
||||
struct axs10x_pll_clk *clk = to_axs10x_pll_clk(hw);
|
||||
const struct axs10x_pll_cfg *pll_cfg = clk->pll_cfg;
|
||||
|
||||
for (i = 0; pll_cfg[i].rate != 0; i++) {
|
||||
if (pll_cfg[i].rate == rate) {
|
||||
axs10x_pll_write(clk, PLL_REG_IDIV,
|
||||
axs10x_encode_div(pll_cfg[i].idiv, 0));
|
||||
axs10x_pll_write(clk, PLL_REG_FBDIV,
|
||||
axs10x_encode_div(pll_cfg[i].fbdiv, 0));
|
||||
axs10x_pll_write(clk, PLL_REG_ODIV,
|
||||
axs10x_encode_div(pll_cfg[i].odiv, 1));
|
||||
|
||||
/*
|
||||
* Wait until CGU relocks and check error status.
|
||||
* If after timeout CGU is unlocked yet return error
|
||||
*/
|
||||
udelay(PLL_MAX_LOCK_TIME);
|
||||
if (!(ioread32(clk->lock) & PLL_LOCK))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (ioread32(clk->lock) & PLL_ERROR)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
|
||||
parent_rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct clk_ops axs10x_pll_ops = {
|
||||
.recalc_rate = axs10x_pll_recalc_rate,
|
||||
.round_rate = axs10x_pll_round_rate,
|
||||
.set_rate = axs10x_pll_set_rate,
|
||||
};
|
||||
|
||||
static int axs10x_pll_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
const char *parent_name;
|
||||
struct axs10x_pll_clk *pll_clk;
|
||||
struct resource *mem;
|
||||
struct clk_init_data init = { };
|
||||
int ret;
|
||||
|
||||
pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
|
||||
if (!pll_clk)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pll_clk->base = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(pll_clk->base))
|
||||
return PTR_ERR(pll_clk->base);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
pll_clk->lock = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(pll_clk->lock))
|
||||
return PTR_ERR(pll_clk->lock);
|
||||
|
||||
init.name = dev->of_node->name;
|
||||
init.ops = &axs10x_pll_ops;
|
||||
parent_name = of_clk_get_parent_name(dev->of_node, 0);
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
pll_clk->hw.init = &init;
|
||||
pll_clk->dev = dev;
|
||||
pll_clk->pll_cfg = of_device_get_match_data(dev);
|
||||
|
||||
if (!pll_clk->pll_cfg) {
|
||||
dev_err(dev, "No OF match data provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_clk_hw_register(dev, &pll_clk->hw);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register %s clock\n", init.name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get,
|
||||
&pll_clk->hw);
|
||||
}
|
||||
|
||||
static int axs10x_pll_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
of_clk_del_provider(pdev->dev.of_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init of_axs10x_pll_clk_setup(struct device_node *node)
|
||||
{
|
||||
const char *parent_name;
|
||||
struct axs10x_pll_clk *pll_clk;
|
||||
struct clk_init_data init = { };
|
||||
int ret;
|
||||
|
||||
pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
|
||||
if (!pll_clk)
|
||||
return;
|
||||
|
||||
pll_clk->base = of_iomap(node, 0);
|
||||
if (!pll_clk->base) {
|
||||
pr_err("failed to map pll div registers\n");
|
||||
goto err_free_pll_clk;
|
||||
}
|
||||
|
||||
pll_clk->lock = of_iomap(node, 1);
|
||||
if (!pll_clk->lock) {
|
||||
pr_err("failed to map pll lock register\n");
|
||||
goto err_unmap_base;
|
||||
}
|
||||
|
||||
init.name = node->name;
|
||||
init.ops = &axs10x_pll_ops;
|
||||
parent_name = of_clk_get_parent_name(node, 0);
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = parent_name ? 1 : 0;
|
||||
pll_clk->hw.init = &init;
|
||||
pll_clk->pll_cfg = arc_pll_cfg;
|
||||
|
||||
ret = clk_hw_register(NULL, &pll_clk->hw);
|
||||
if (ret) {
|
||||
pr_err("failed to register %s clock\n", node->name);
|
||||
goto err_unmap_lock;
|
||||
}
|
||||
|
||||
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
|
||||
if (ret) {
|
||||
pr_err("failed to add hw provider for %s clock\n", node->name);
|
||||
goto err_unregister_clk;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_unregister_clk:
|
||||
clk_hw_unregister(&pll_clk->hw);
|
||||
err_unmap_lock:
|
||||
iounmap(pll_clk->lock);
|
||||
err_unmap_base:
|
||||
iounmap(pll_clk->base);
|
||||
err_free_pll_clk:
|
||||
kfree(pll_clk);
|
||||
}
|
||||
CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock",
|
||||
of_axs10x_pll_clk_setup);
|
||||
|
||||
static const struct of_device_id axs10x_pll_clk_id[] = {
|
||||
{ .compatible = "snps,axs10x-pgu-pll-clock", .data = &pgu_pll_cfg},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axs10x_pll_clk_id);
|
||||
|
||||
static struct platform_driver axs10x_pll_clk_driver = {
|
||||
.driver = {
|
||||
.name = "axs10x-pll-clock",
|
||||
.of_match_table = axs10x_pll_clk_id,
|
||||
},
|
||||
.probe = axs10x_pll_clk_probe,
|
||||
.remove = axs10x_pll_clk_remove,
|
||||
};
|
||||
builtin_platform_driver(axs10x_pll_clk_driver);
|
||||
|
||||
MODULE_AUTHOR("Vlad Zakharov <vzakhar@synopsys.com>");
|
||||
MODULE_DESCRIPTION("Synopsys AXS10X SDP Generic PLL Clock Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -679,8 +679,7 @@ static void __init berlin2_clock_setup(struct device_node *np)
|
|||
if (!IS_ERR(hws[n]))
|
||||
continue;
|
||||
|
||||
pr_err("%s: Unable to register leaf clock %d\n",
|
||||
np->full_name, n);
|
||||
pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
|
||||
goto bg2_fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -304,14 +304,14 @@ static void __init berlin2q_clock_setup(struct device_node *np)
|
|||
|
||||
gbase = of_iomap(parent_np, 0);
|
||||
if (!gbase) {
|
||||
pr_err("%s: Unable to map global base\n", np->full_name);
|
||||
pr_err("%pOF: Unable to map global base\n", np);
|
||||
return;
|
||||
}
|
||||
|
||||
/* BG2Q CPU PLL is not part of global registers */
|
||||
cpupll_base = of_iomap(parent_np, 1);
|
||||
if (!cpupll_base) {
|
||||
pr_err("%s: Unable to map cpupll base\n", np->full_name);
|
||||
pr_err("%pOF: Unable to map cpupll base\n", np);
|
||||
iounmap(gbase);
|
||||
return;
|
||||
}
|
||||
|
@ -376,8 +376,7 @@ static void __init berlin2q_clock_setup(struct device_node *np)
|
|||
if (!IS_ERR(hws[n]))
|
||||
continue;
|
||||
|
||||
pr_err("%s: Unable to register leaf clock %d\n",
|
||||
np->full_name, n);
|
||||
pr_err("%pOF: Unable to register leaf clock %d\n", np, n);
|
||||
goto bg2q_fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -338,8 +338,8 @@ static void __init asm9260_acc_init(struct device_node *np)
|
|||
if (!IS_ERR(hws[n]))
|
||||
continue;
|
||||
|
||||
pr_err("%s: Unable to register leaf clock %d\n",
|
||||
np->full_name, n);
|
||||
pr_err("%pOF: Unable to register leaf clock %d\n",
|
||||
np, n);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
|
|||
num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
|
||||
"#clock-cells");
|
||||
if (num_parents == -EINVAL)
|
||||
pr_err("clk: invalid value of clock-parents property at %s\n",
|
||||
node->full_name);
|
||||
pr_err("clk: invalid value of clock-parents property at %pOF\n",
|
||||
node);
|
||||
|
||||
for (index = 0; index < num_parents; index++) {
|
||||
rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
|
||||
|
@ -41,8 +41,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
|
|||
pclk = of_clk_get_from_provider(&clkspec);
|
||||
if (IS_ERR(pclk)) {
|
||||
if (PTR_ERR(pclk) != -EPROBE_DEFER)
|
||||
pr_warn("clk: couldn't get parent clock %d for %s\n",
|
||||
index, node->full_name);
|
||||
pr_warn("clk: couldn't get parent clock %d for %pOF\n",
|
||||
index, node);
|
||||
return PTR_ERR(pclk);
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,8 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
|
|||
clk = of_clk_get_from_provider(&clkspec);
|
||||
if (IS_ERR(clk)) {
|
||||
if (PTR_ERR(clk) != -EPROBE_DEFER)
|
||||
pr_warn("clk: couldn't get assigned clock %d for %s\n",
|
||||
index, node->full_name);
|
||||
pr_warn("clk: couldn't get assigned clock %d for %pOF\n",
|
||||
index, node);
|
||||
rc = PTR_ERR(clk);
|
||||
goto err;
|
||||
}
|
||||
|
@ -102,8 +102,8 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
|
|||
clk = of_clk_get_from_provider(&clkspec);
|
||||
if (IS_ERR(clk)) {
|
||||
if (PTR_ERR(clk) != -EPROBE_DEFER)
|
||||
pr_warn("clk: couldn't get clock %d for %s\n",
|
||||
index, node->full_name);
|
||||
pr_warn("clk: couldn't get clock %d for %pOF\n",
|
||||
index, node);
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
|
|
|
@ -343,6 +343,15 @@ static int cs2000_set_rate(struct clk_hw *hw,
|
|||
return __cs2000_set_rate(priv, ch, rate, parent_rate);
|
||||
}
|
||||
|
||||
static int cs2000_set_saved_rate(struct cs2000_priv *priv)
|
||||
{
|
||||
int ch = 0; /* it uses ch0 only at this point */
|
||||
|
||||
return __cs2000_set_rate(priv, ch,
|
||||
priv->saved_rate,
|
||||
priv->saved_parent_rate);
|
||||
}
|
||||
|
||||
static int cs2000_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct cs2000_priv *priv = hw_to_priv(hw);
|
||||
|
@ -535,11 +544,8 @@ probe_err:
|
|||
static int cs2000_resume(struct device *dev)
|
||||
{
|
||||
struct cs2000_priv *priv = dev_get_drvdata(dev);
|
||||
int ch = 0; /* it uses ch0 only at this point */
|
||||
|
||||
return __cs2000_set_rate(priv, ch,
|
||||
priv->saved_rate,
|
||||
priv->saved_parent_rate);
|
||||
return cs2000_set_saved_rate(priv);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops cs2000_pm_ops = {
|
||||
|
|
|
@ -385,12 +385,14 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_divider *divider = to_clk_divider(hw);
|
||||
unsigned int value;
|
||||
int value;
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
value = divider_get_val(rate, parent_rate, divider->table,
|
||||
divider->width, divider->flags);
|
||||
if (value < 0)
|
||||
return value;
|
||||
|
||||
if (divider->lock)
|
||||
spin_lock_irqsave(divider->lock, flags);
|
||||
|
@ -403,7 +405,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
val = clk_readl(divider->reg);
|
||||
val &= ~(div_mask(divider->width) << divider->shift);
|
||||
}
|
||||
val |= value << divider->shift;
|
||||
val |= (u32)value << divider->shift;
|
||||
clk_writel(val, divider->reg);
|
||||
|
||||
if (divider->lock)
|
||||
|
|
|
@ -49,16 +49,12 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
static void clk_fd_general_approximation(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate,
|
||||
unsigned long *m, unsigned long *n)
|
||||
{
|
||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
||||
unsigned long scale;
|
||||
unsigned long m, n;
|
||||
u64 ret;
|
||||
|
||||
if (!rate || rate >= *parent_rate)
|
||||
return *parent_rate;
|
||||
|
||||
/*
|
||||
* Get rate closer to *parent_rate to guarantee there is no overflow
|
||||
|
@ -71,7 +67,23 @@ static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
rational_best_approximation(rate, *parent_rate,
|
||||
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
||||
&m, &n);
|
||||
m, n);
|
||||
}
|
||||
|
||||
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
||||
unsigned long m, n;
|
||||
u64 ret;
|
||||
|
||||
if (!rate || rate >= *parent_rate)
|
||||
return *parent_rate;
|
||||
|
||||
if (fd->approximation)
|
||||
fd->approximation(hw, rate, parent_rate, &m, &n);
|
||||
else
|
||||
clk_fd_general_approximation(hw, rate, parent_rate, &m, &n);
|
||||
|
||||
ret = (u64)*parent_rate * m;
|
||||
do_div(ret, n);
|
||||
|
|
|
@ -86,7 +86,7 @@ static void clk_gate_disable(struct clk_hw *hw)
|
|||
clk_gate_endisable(hw, 0);
|
||||
}
|
||||
|
||||
static int clk_gate_is_enabled(struct clk_hw *hw)
|
||||
int clk_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
u32 reg;
|
||||
struct clk_gate *gate = to_clk_gate(hw);
|
||||
|
@ -101,6 +101,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
|
|||
|
||||
return reg ? 1 : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clk_gate_is_enabled);
|
||||
|
||||
const struct clk_ops clk_gate_ops = {
|
||||
.enable = clk_gate_enable,
|
||||
|
|
|
@ -37,7 +37,6 @@ static DEFINE_SPINLOCK(gemini_clk_lock);
|
|||
|
||||
#define GEMINI_GLOBAL_MISC_CONTROL 0x30
|
||||
#define PCI_CLK_66MHZ BIT(18)
|
||||
#define PCI_CLK_OE BIT(17)
|
||||
|
||||
#define GEMINI_GLOBAL_CLOCK_CONTROL 0x34
|
||||
#define PCI_CLKRUN_EN BIT(16)
|
||||
|
@ -159,9 +158,6 @@ static int gemini_pci_enable(struct clk_hw *hw)
|
|||
|
||||
regmap_update_bits(pciclk->map, GEMINI_GLOBAL_CLOCK_CONTROL,
|
||||
0, PCI_CLKRUN_EN);
|
||||
regmap_update_bits(pciclk->map,
|
||||
GEMINI_GLOBAL_MISC_CONTROL,
|
||||
0, PCI_CLK_OE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -169,9 +165,6 @@ static void gemini_pci_disable(struct clk_hw *hw)
|
|||
{
|
||||
struct clk_gemini_pci *pciclk = to_pciclk(hw);
|
||||
|
||||
regmap_update_bits(pciclk->map,
|
||||
GEMINI_GLOBAL_MISC_CONTROL,
|
||||
PCI_CLK_OE, 0);
|
||||
regmap_update_bits(pciclk->map, GEMINI_GLOBAL_CLOCK_CONTROL,
|
||||
PCI_CLKRUN_EN, 0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* Synopsys HSDK SDP Generic PLL clock driver
|
||||
*
|
||||
* Copyright (C) 2017 Synopsys
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define CGU_PLL_CTRL 0x000 /* ARC PLL control register */
|
||||
#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */
|
||||
#define CGU_PLL_FMEAS 0x008 /* ARC PLL frequency measurement register */
|
||||
#define CGU_PLL_MON 0x00C /* ARC PLL monitor register */
|
||||
|
||||
#define CGU_PLL_CTRL_ODIV_SHIFT 2
|
||||
#define CGU_PLL_CTRL_IDIV_SHIFT 4
|
||||
#define CGU_PLL_CTRL_FBDIV_SHIFT 9
|
||||
#define CGU_PLL_CTRL_BAND_SHIFT 20
|
||||
|
||||
#define CGU_PLL_CTRL_ODIV_MASK GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT)
|
||||
#define CGU_PLL_CTRL_IDIV_MASK GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT)
|
||||
#define CGU_PLL_CTRL_FBDIV_MASK GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT)
|
||||
|
||||
#define CGU_PLL_CTRL_PD BIT(0)
|
||||
#define CGU_PLL_CTRL_BYPASS BIT(1)
|
||||
|
||||
#define CGU_PLL_STATUS_LOCK BIT(0)
|
||||
#define CGU_PLL_STATUS_ERR BIT(1)
|
||||
|
||||
#define HSDK_PLL_MAX_LOCK_TIME 100 /* 100 us */
|
||||
|
||||
#define CGU_PLL_SOURCE_MAX 1
|
||||
|
||||
#define CORE_IF_CLK_THRESHOLD_HZ 500000000
|
||||
#define CREG_CORE_IF_CLK_DIV_1 0x0
|
||||
#define CREG_CORE_IF_CLK_DIV_2 0x1
|
||||
|
||||
struct hsdk_pll_cfg {
|
||||
u32 rate;
|
||||
u32 idiv;
|
||||
u32 fbdiv;
|
||||
u32 odiv;
|
||||
u32 band;
|
||||
};
|
||||
|
||||
static const struct hsdk_pll_cfg asdt_pll_cfg[] = {
|
||||
{ 100000000, 0, 11, 3, 0 },
|
||||
{ 133000000, 0, 15, 3, 0 },
|
||||
{ 200000000, 1, 47, 3, 0 },
|
||||
{ 233000000, 1, 27, 2, 0 },
|
||||
{ 300000000, 1, 35, 2, 0 },
|
||||
{ 333000000, 1, 39, 2, 0 },
|
||||
{ 400000000, 1, 47, 2, 0 },
|
||||
{ 500000000, 0, 14, 1, 0 },
|
||||
{ 600000000, 0, 17, 1, 0 },
|
||||
{ 700000000, 0, 20, 1, 0 },
|
||||
{ 800000000, 0, 23, 1, 0 },
|
||||
{ 900000000, 1, 26, 0, 0 },
|
||||
{ 1000000000, 1, 29, 0, 0 },
|
||||
{ 1100000000, 1, 32, 0, 0 },
|
||||
{ 1200000000, 1, 35, 0, 0 },
|
||||
{ 1300000000, 1, 38, 0, 0 },
|
||||
{ 1400000000, 1, 41, 0, 0 },
|
||||
{ 1500000000, 1, 44, 0, 0 },
|
||||
{ 1600000000, 1, 47, 0, 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
|
||||
{ 297000000, 0, 21, 2, 0 },
|
||||
{ 540000000, 0, 19, 1, 0 },
|
||||
{ 594000000, 0, 21, 1, 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
struct hsdk_pll_clk {
|
||||
struct clk_hw hw;
|
||||
void __iomem *regs;
|
||||
void __iomem *spec_regs;
|
||||
const struct hsdk_pll_devdata *pll_devdata;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
struct hsdk_pll_devdata {
|
||||
const struct hsdk_pll_cfg *pll_cfg;
|
||||
int (*update_rate)(struct hsdk_pll_clk *clk, unsigned long rate,
|
||||
const struct hsdk_pll_cfg *cfg);
|
||||
};
|
||||
|
||||
static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *, unsigned long,
|
||||
const struct hsdk_pll_cfg *);
|
||||
static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *, unsigned long,
|
||||
const struct hsdk_pll_cfg *);
|
||||
|
||||
static const struct hsdk_pll_devdata core_pll_devdata = {
|
||||
.pll_cfg = asdt_pll_cfg,
|
||||
.update_rate = hsdk_pll_core_update_rate,
|
||||
};
|
||||
|
||||
static const struct hsdk_pll_devdata sdt_pll_devdata = {
|
||||
.pll_cfg = asdt_pll_cfg,
|
||||
.update_rate = hsdk_pll_comm_update_rate,
|
||||
};
|
||||
|
||||
static const struct hsdk_pll_devdata hdmi_pll_devdata = {
|
||||
.pll_cfg = hdmi_pll_cfg,
|
||||
.update_rate = hsdk_pll_comm_update_rate,
|
||||
};
|
||||
|
||||
static inline void hsdk_pll_write(struct hsdk_pll_clk *clk, u32 reg, u32 val)
|
||||
{
|
||||
iowrite32(val, clk->regs + reg);
|
||||
}
|
||||
|
||||
static inline u32 hsdk_pll_read(struct hsdk_pll_clk *clk, u32 reg)
|
||||
{
|
||||
return ioread32(clk->regs + reg);
|
||||
}
|
||||
|
||||
static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk,
|
||||
const struct hsdk_pll_cfg *cfg)
|
||||
{
|
||||
u32 val = 0;
|
||||
|
||||
/* Powerdown and Bypass bits should be cleared */
|
||||
val |= cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
|
||||
val |= cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
|
||||
val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
|
||||
val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
|
||||
|
||||
dev_dbg(clk->dev, "write configurarion: %#x\n", val);
|
||||
|
||||
hsdk_pll_write(clk, CGU_PLL_CTRL, val);
|
||||
}
|
||||
|
||||
static inline bool hsdk_pll_is_locked(struct hsdk_pll_clk *clk)
|
||||
{
|
||||
return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK);
|
||||
}
|
||||
|
||||
static inline bool hsdk_pll_is_err(struct hsdk_pll_clk *clk)
|
||||
{
|
||||
return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR);
|
||||
}
|
||||
|
||||
static inline struct hsdk_pll_clk *to_hsdk_pll_clk(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct hsdk_pll_clk, hw);
|
||||
}
|
||||
|
||||
static unsigned long hsdk_pll_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
u32 val;
|
||||
u64 rate;
|
||||
u32 idiv, fbdiv, odiv;
|
||||
struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
|
||||
|
||||
val = hsdk_pll_read(clk, CGU_PLL_CTRL);
|
||||
|
||||
dev_dbg(clk->dev, "current configurarion: %#x\n", val);
|
||||
|
||||
/* Check if PLL is disabled */
|
||||
if (val & CGU_PLL_CTRL_PD)
|
||||
return 0;
|
||||
|
||||
/* Check if PLL is bypassed */
|
||||
if (val & CGU_PLL_CTRL_BYPASS)
|
||||
return parent_rate;
|
||||
|
||||
/* input divider = reg.idiv + 1 */
|
||||
idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT);
|
||||
/* fb divider = 2*(reg.fbdiv + 1) */
|
||||
fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT));
|
||||
/* output divider = 2^(reg.odiv) */
|
||||
odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT);
|
||||
|
||||
rate = (u64)parent_rate * fbdiv;
|
||||
do_div(rate, idiv * odiv);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long hsdk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
int i;
|
||||
unsigned long best_rate;
|
||||
struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
|
||||
const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
|
||||
|
||||
if (pll_cfg[0].rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
best_rate = pll_cfg[0].rate;
|
||||
|
||||
for (i = 1; pll_cfg[i].rate != 0; i++) {
|
||||
if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
|
||||
best_rate = pll_cfg[i].rate;
|
||||
}
|
||||
|
||||
dev_dbg(clk->dev, "chosen best rate: %lu\n", best_rate);
|
||||
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
static int hsdk_pll_comm_update_rate(struct hsdk_pll_clk *clk,
|
||||
unsigned long rate,
|
||||
const struct hsdk_pll_cfg *cfg)
|
||||
{
|
||||
hsdk_pll_set_cfg(clk, cfg);
|
||||
|
||||
/*
|
||||
* Wait until CGU relocks and check error status.
|
||||
* If after timeout CGU is unlocked yet return error.
|
||||
*/
|
||||
udelay(HSDK_PLL_MAX_LOCK_TIME);
|
||||
if (!hsdk_pll_is_locked(clk))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (hsdk_pll_is_err(clk))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hsdk_pll_core_update_rate(struct hsdk_pll_clk *clk,
|
||||
unsigned long rate,
|
||||
const struct hsdk_pll_cfg *cfg)
|
||||
{
|
||||
/*
|
||||
* When core clock exceeds 500MHz, the divider for the interface
|
||||
* clock must be programmed to div-by-2.
|
||||
*/
|
||||
if (rate > CORE_IF_CLK_THRESHOLD_HZ)
|
||||
iowrite32(CREG_CORE_IF_CLK_DIV_2, clk->spec_regs);
|
||||
|
||||
hsdk_pll_set_cfg(clk, cfg);
|
||||
|
||||
/*
|
||||
* Wait until CGU relocks and check error status.
|
||||
* If after timeout CGU is unlocked yet return error.
|
||||
*/
|
||||
udelay(HSDK_PLL_MAX_LOCK_TIME);
|
||||
if (!hsdk_pll_is_locked(clk))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if (hsdk_pll_is_err(clk))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Program divider to div-by-1 if we succesfuly set core clock below
|
||||
* 500MHz threshold.
|
||||
*/
|
||||
if (rate <= CORE_IF_CLK_THRESHOLD_HZ)
|
||||
iowrite32(CREG_CORE_IF_CLK_DIV_1, clk->spec_regs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hsdk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
int i;
|
||||
struct hsdk_pll_clk *clk = to_hsdk_pll_clk(hw);
|
||||
const struct hsdk_pll_cfg *pll_cfg = clk->pll_devdata->pll_cfg;
|
||||
|
||||
for (i = 0; pll_cfg[i].rate != 0; i++) {
|
||||
if (pll_cfg[i].rate == rate) {
|
||||
return clk->pll_devdata->update_rate(clk, rate,
|
||||
&pll_cfg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(clk->dev, "invalid rate=%ld, parent_rate=%ld\n", rate,
|
||||
parent_rate);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct clk_ops hsdk_pll_ops = {
|
||||
.recalc_rate = hsdk_pll_recalc_rate,
|
||||
.round_rate = hsdk_pll_round_rate,
|
||||
.set_rate = hsdk_pll_set_rate,
|
||||
};
|
||||
|
||||
static int hsdk_pll_clk_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct resource *mem;
|
||||
const char *parent_name;
|
||||
unsigned int num_parents;
|
||||
struct hsdk_pll_clk *pll_clk;
|
||||
struct clk_init_data init = { };
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pll_clk = devm_kzalloc(dev, sizeof(*pll_clk), GFP_KERNEL);
|
||||
if (!pll_clk)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pll_clk->regs = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(pll_clk->regs))
|
||||
return PTR_ERR(pll_clk->regs);
|
||||
|
||||
init.name = dev->of_node->name;
|
||||
init.ops = &hsdk_pll_ops;
|
||||
parent_name = of_clk_get_parent_name(dev->of_node, 0);
|
||||
init.parent_names = &parent_name;
|
||||
num_parents = of_clk_get_parent_count(dev->of_node);
|
||||
if (num_parents == 0 || num_parents > CGU_PLL_SOURCE_MAX) {
|
||||
dev_err(dev, "wrong clock parents number: %u\n", num_parents);
|
||||
return -EINVAL;
|
||||
}
|
||||
init.num_parents = num_parents;
|
||||
|
||||
pll_clk->hw.init = &init;
|
||||
pll_clk->dev = dev;
|
||||
pll_clk->pll_devdata = of_device_get_match_data(dev);
|
||||
|
||||
if (!pll_clk->pll_devdata) {
|
||||
dev_err(dev, "No OF match data provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_clk_hw_register(dev, &pll_clk->hw);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register %s clock\n", init.name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_simple_get,
|
||||
&pll_clk->hw);
|
||||
}
|
||||
|
||||
static int hsdk_pll_clk_remove(struct platform_device *pdev)
|
||||
{
|
||||
of_clk_del_provider(pdev->dev.of_node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __init of_hsdk_pll_clk_setup(struct device_node *node)
|
||||
{
|
||||
int ret;
|
||||
const char *parent_name;
|
||||
unsigned int num_parents;
|
||||
struct hsdk_pll_clk *pll_clk;
|
||||
struct clk_init_data init = { };
|
||||
|
||||
pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
|
||||
if (!pll_clk)
|
||||
return;
|
||||
|
||||
pll_clk->regs = of_iomap(node, 0);
|
||||
if (!pll_clk->regs) {
|
||||
pr_err("failed to map pll registers\n");
|
||||
goto err_free_pll_clk;
|
||||
}
|
||||
|
||||
pll_clk->spec_regs = of_iomap(node, 1);
|
||||
if (!pll_clk->spec_regs) {
|
||||
pr_err("failed to map pll registers\n");
|
||||
goto err_unmap_comm_regs;
|
||||
}
|
||||
|
||||
init.name = node->name;
|
||||
init.ops = &hsdk_pll_ops;
|
||||
parent_name = of_clk_get_parent_name(node, 0);
|
||||
init.parent_names = &parent_name;
|
||||
num_parents = of_clk_get_parent_count(node);
|
||||
if (num_parents > CGU_PLL_SOURCE_MAX) {
|
||||
pr_err("too much clock parents: %u\n", num_parents);
|
||||
goto err_unmap_spec_regs;
|
||||
}
|
||||
init.num_parents = num_parents;
|
||||
|
||||
pll_clk->hw.init = &init;
|
||||
pll_clk->pll_devdata = &core_pll_devdata;
|
||||
|
||||
ret = clk_hw_register(NULL, &pll_clk->hw);
|
||||
if (ret) {
|
||||
pr_err("failed to register %s clock\n", node->name);
|
||||
goto err_unmap_spec_regs;
|
||||
}
|
||||
|
||||
ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, &pll_clk->hw);
|
||||
if (ret) {
|
||||
pr_err("failed to add hw provider for %s clock\n", node->name);
|
||||
goto err_unmap_spec_regs;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err_unmap_spec_regs:
|
||||
iounmap(pll_clk->spec_regs);
|
||||
err_unmap_comm_regs:
|
||||
iounmap(pll_clk->regs);
|
||||
err_free_pll_clk:
|
||||
kfree(pll_clk);
|
||||
}
|
||||
|
||||
/* Core PLL needed early for ARC cpus timers */
|
||||
CLK_OF_DECLARE(hsdk_pll_clock, "snps,hsdk-core-pll-clock",
|
||||
of_hsdk_pll_clk_setup);
|
||||
|
||||
static const struct of_device_id hsdk_pll_clk_id[] = {
|
||||
{ .compatible = "snps,hsdk-gp-pll-clock", .data = &sdt_pll_devdata},
|
||||
{ .compatible = "snps,hsdk-hdmi-pll-clock", .data = &hdmi_pll_devdata},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver hsdk_pll_clk_driver = {
|
||||
.driver = {
|
||||
.name = "hsdk-gp-pll-clock",
|
||||
.of_match_table = hsdk_pll_clk_id,
|
||||
},
|
||||
.probe = hsdk_pll_clk_probe,
|
||||
.remove = hsdk_pll_clk_remove,
|
||||
};
|
||||
builtin_platform_driver(hsdk_pll_clk_driver);
|
|
@ -1,390 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2015 FUJITSU SEMICONDUCTOR LIMITED
|
||||
* Copyright (C) 2015 Linaro Ltd.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/topology.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <soc/mb86s7x/scb_mhu.h>
|
||||
|
||||
#define to_crg_clk(p) container_of(p, struct crg_clk, hw)
|
||||
#define to_clc_clk(p) container_of(p, struct cl_clk, hw)
|
||||
|
||||
struct mb86s7x_peri_clk {
|
||||
u32 payload_size;
|
||||
u32 cntrlr;
|
||||
u32 domain;
|
||||
u32 port;
|
||||
u32 en;
|
||||
u64 frequency;
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct hack_rate {
|
||||
unsigned clk_id;
|
||||
unsigned long rate;
|
||||
int gated;
|
||||
};
|
||||
|
||||
struct crg_clk {
|
||||
struct clk_hw hw;
|
||||
u8 cntrlr, domain, port;
|
||||
};
|
||||
|
||||
static int crg_gate_control(struct clk_hw *hw, int en)
|
||||
{
|
||||
struct crg_clk *crgclk = to_crg_clk(hw);
|
||||
struct mb86s7x_peri_clk cmd;
|
||||
int ret;
|
||||
|
||||
cmd.payload_size = sizeof(cmd);
|
||||
cmd.cntrlr = crgclk->cntrlr;
|
||||
cmd.domain = crgclk->domain;
|
||||
cmd.port = crgclk->port;
|
||||
cmd.en = en;
|
||||
|
||||
/* Port is UngatedCLK */
|
||||
if (cmd.port == 8)
|
||||
return en ? 0 : -EINVAL;
|
||||
|
||||
pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u En-%u}\n",
|
||||
__func__, __LINE__, cmd.cntrlr,
|
||||
cmd.domain, cmd.port, cmd.en);
|
||||
|
||||
ret = mb86s7x_send_packet(CMD_PERI_CLOCK_GATE_SET_REQ,
|
||||
&cmd, sizeof(cmd));
|
||||
if (ret < 0) {
|
||||
pr_err("%s:%d failed!\n", __func__, __LINE__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u En-%u}\n",
|
||||
__func__, __LINE__, cmd.cntrlr,
|
||||
cmd.domain, cmd.port, cmd.en);
|
||||
|
||||
/* If the request was rejected */
|
||||
if (cmd.en != en)
|
||||
ret = -EINVAL;
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int crg_port_prepare(struct clk_hw *hw)
|
||||
{
|
||||
return crg_gate_control(hw, 1);
|
||||
}
|
||||
|
||||
static void crg_port_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
crg_gate_control(hw, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
crg_rate_control(struct clk_hw *hw, int set, unsigned long *rate)
|
||||
{
|
||||
struct crg_clk *crgclk = to_crg_clk(hw);
|
||||
struct mb86s7x_peri_clk cmd;
|
||||
int code, ret;
|
||||
|
||||
cmd.payload_size = sizeof(cmd);
|
||||
cmd.cntrlr = crgclk->cntrlr;
|
||||
cmd.domain = crgclk->domain;
|
||||
cmd.port = crgclk->port;
|
||||
cmd.frequency = *rate;
|
||||
|
||||
if (set) {
|
||||
code = CMD_PERI_CLOCK_RATE_SET_REQ;
|
||||
pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
|
||||
__func__, __LINE__, cmd.cntrlr,
|
||||
cmd.domain, cmd.port, cmd.frequency);
|
||||
} else {
|
||||
code = CMD_PERI_CLOCK_RATE_GET_REQ;
|
||||
pr_debug("%s:%d CMD Cntrlr-%u Dom-%u Port-%u Rate-GET}\n",
|
||||
__func__, __LINE__, cmd.cntrlr,
|
||||
cmd.domain, cmd.port);
|
||||
}
|
||||
|
||||
ret = mb86s7x_send_packet(code, &cmd, sizeof(cmd));
|
||||
if (ret < 0) {
|
||||
pr_err("%s:%d failed!\n", __func__, __LINE__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (set)
|
||||
pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-SET %lluHz}\n",
|
||||
__func__, __LINE__, cmd.cntrlr,
|
||||
cmd.domain, cmd.port, cmd.frequency);
|
||||
else
|
||||
pr_debug("%s:%d REP Cntrlr-%u Dom-%u Port-%u Rate-GOT %lluHz}\n",
|
||||
__func__, __LINE__, cmd.cntrlr,
|
||||
cmd.domain, cmd.port, cmd.frequency);
|
||||
|
||||
*rate = cmd.frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
crg_port_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
crg_rate_control(hw, 0, &rate);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long
|
||||
crg_port_round_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long *pr)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int
|
||||
crg_port_set_rate(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
return crg_rate_control(hw, 1, &rate);
|
||||
}
|
||||
|
||||
const struct clk_ops crg_port_ops = {
|
||||
.prepare = crg_port_prepare,
|
||||
.unprepare = crg_port_unprepare,
|
||||
.recalc_rate = crg_port_recalc_rate,
|
||||
.round_rate = crg_port_round_rate,
|
||||
.set_rate = crg_port_set_rate,
|
||||
};
|
||||
|
||||
struct mb86s70_crg11 {
|
||||
struct mutex lock; /* protects CLK populating and searching */
|
||||
};
|
||||
|
||||
static struct clk *crg11_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct mb86s70_crg11 *crg11 = data;
|
||||
struct clk_init_data init;
|
||||
u32 cntrlr, domain, port;
|
||||
struct crg_clk *crgclk;
|
||||
struct clk *clk;
|
||||
char clkp[20];
|
||||
|
||||
if (clkspec->args_count != 3)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
cntrlr = clkspec->args[0];
|
||||
domain = clkspec->args[1];
|
||||
port = clkspec->args[2];
|
||||
|
||||
if (port > 7)
|
||||
snprintf(clkp, 20, "UngatedCLK%d_%X", cntrlr, domain);
|
||||
else
|
||||
snprintf(clkp, 20, "CLK%d_%X_%d", cntrlr, domain, port);
|
||||
|
||||
mutex_lock(&crg11->lock);
|
||||
|
||||
clk = __clk_lookup(clkp);
|
||||
if (clk) {
|
||||
mutex_unlock(&crg11->lock);
|
||||
return clk;
|
||||
}
|
||||
|
||||
crgclk = kzalloc(sizeof(*crgclk), GFP_KERNEL);
|
||||
if (!crgclk) {
|
||||
mutex_unlock(&crg11->lock);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = clkp;
|
||||
init.num_parents = 0;
|
||||
init.ops = &crg_port_ops;
|
||||
init.flags = 0;
|
||||
crgclk->hw.init = &init;
|
||||
crgclk->cntrlr = cntrlr;
|
||||
crgclk->domain = domain;
|
||||
crgclk->port = port;
|
||||
clk = clk_register(NULL, &crgclk->hw);
|
||||
if (IS_ERR(clk))
|
||||
pr_err("%s:%d Error!\n", __func__, __LINE__);
|
||||
else
|
||||
pr_debug("Registered %s\n", clkp);
|
||||
|
||||
clk_register_clkdev(clk, clkp, NULL);
|
||||
mutex_unlock(&crg11->lock);
|
||||
return clk;
|
||||
}
|
||||
|
||||
static void __init crg_port_init(struct device_node *node)
|
||||
{
|
||||
struct mb86s70_crg11 *crg11;
|
||||
|
||||
crg11 = kzalloc(sizeof(*crg11), GFP_KERNEL);
|
||||
if (!crg11)
|
||||
return;
|
||||
|
||||
mutex_init(&crg11->lock);
|
||||
|
||||
of_clk_add_provider(node, crg11_get, crg11);
|
||||
}
|
||||
CLK_OF_DECLARE(crg11_gate, "fujitsu,mb86s70-crg11", crg_port_init);
|
||||
|
||||
struct cl_clk {
|
||||
struct clk_hw hw;
|
||||
int cluster;
|
||||
};
|
||||
|
||||
struct mb86s7x_cpu_freq {
|
||||
u32 payload_size;
|
||||
u32 cluster_class;
|
||||
u32 cluster_id;
|
||||
u32 cpu_id;
|
||||
u64 frequency;
|
||||
};
|
||||
|
||||
static void mhu_cluster_rate(struct clk_hw *hw, unsigned long *rate, int get)
|
||||
{
|
||||
struct cl_clk *clc = to_clc_clk(hw);
|
||||
struct mb86s7x_cpu_freq cmd;
|
||||
int code, ret;
|
||||
|
||||
cmd.payload_size = sizeof(cmd);
|
||||
cmd.cluster_class = 0;
|
||||
cmd.cluster_id = clc->cluster;
|
||||
cmd.cpu_id = 0;
|
||||
cmd.frequency = *rate;
|
||||
|
||||
if (get)
|
||||
code = CMD_CPU_CLOCK_RATE_GET_REQ;
|
||||
else
|
||||
code = CMD_CPU_CLOCK_RATE_SET_REQ;
|
||||
|
||||
pr_debug("%s:%d CMD Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
|
||||
__func__, __LINE__, cmd.cluster_class,
|
||||
cmd.cluster_id, cmd.cpu_id, cmd.frequency);
|
||||
|
||||
ret = mb86s7x_send_packet(code, &cmd, sizeof(cmd));
|
||||
if (ret < 0) {
|
||||
pr_err("%s:%d failed!\n", __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("%s:%d REP Cl_Class-%u CL_ID-%u CPU_ID-%u Freq-%llu}\n",
|
||||
__func__, __LINE__, cmd.cluster_class,
|
||||
cmd.cluster_id, cmd.cpu_id, cmd.frequency);
|
||||
|
||||
*rate = cmd.frequency;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
clc_recalc_rate(struct clk_hw *hw, unsigned long unused)
|
||||
{
|
||||
unsigned long rate;
|
||||
|
||||
mhu_cluster_rate(hw, &rate, 1);
|
||||
return rate;
|
||||
}
|
||||
|
||||
static long
|
||||
clc_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *unused)
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int
|
||||
clc_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long unused)
|
||||
{
|
||||
unsigned long res = rate;
|
||||
|
||||
mhu_cluster_rate(hw, &res, 0);
|
||||
|
||||
return (res == rate) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static struct clk_ops clk_clc_ops = {
|
||||
.recalc_rate = clc_recalc_rate,
|
||||
.round_rate = clc_round_rate,
|
||||
.set_rate = clc_set_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *mb86s7x_clclk_register(struct device *cpu_dev)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct cl_clk *clc;
|
||||
int ret;
|
||||
|
||||
clc = kzalloc(sizeof(*clc), GFP_KERNEL);
|
||||
if (!clc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
clc->hw.init = &init;
|
||||
clc->cluster = topology_physical_package_id(cpu_dev->id);
|
||||
|
||||
init.name = dev_name(cpu_dev);
|
||||
init.ops = &clk_clc_ops;
|
||||
init.flags = CLK_GET_RATE_NOCACHE;
|
||||
init.num_parents = 0;
|
||||
|
||||
ret = devm_clk_hw_register(cpu_dev, &clc->hw);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
return &clc->hw;
|
||||
}
|
||||
|
||||
static int mb86s7x_clclk_of_init(void)
|
||||
{
|
||||
int cpu, ret = -ENODEV;
|
||||
struct device_node *np;
|
||||
struct clk_hw *hw;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fujitsu,mb86s70-scb-1.0");
|
||||
if (!np || !of_device_is_available(np))
|
||||
goto exit;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct device *cpu_dev = get_cpu_device(cpu);
|
||||
|
||||
if (!cpu_dev) {
|
||||
pr_err("failed to get cpu%d device\n", cpu);
|
||||
continue;
|
||||
}
|
||||
|
||||
hw = mb86s7x_clclk_register(cpu_dev);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("failed to register cpu%d clock\n", cpu);
|
||||
continue;
|
||||
}
|
||||
if (clk_hw_register_clkdev(hw, NULL, dev_name(cpu_dev))) {
|
||||
pr_err("failed to register cpu%d clock lookup\n", cpu);
|
||||
continue;
|
||||
}
|
||||
pr_debug("registered clk for %s\n", dev_name(cpu_dev));
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
platform_device_register_simple("arm-bL-cpufreq-dt", -1, NULL, 0);
|
||||
exit:
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
module_init(mb86s7x_clclk_of_init);
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
static void __init moxart_of_pll_clk_init(struct device_node *node)
|
||||
{
|
||||
static void __iomem *base;
|
||||
void __iomem *base;
|
||||
struct clk_hw *hw;
|
||||
struct clk *ref_clk;
|
||||
unsigned int mul;
|
||||
|
@ -30,7 +30,7 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
|
|||
|
||||
base = of_iomap(node, 0);
|
||||
if (!base) {
|
||||
pr_err("%s: of_iomap failed\n", node->full_name);
|
||||
pr_err("%pOF: of_iomap failed\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -39,13 +39,13 @@ static void __init moxart_of_pll_clk_init(struct device_node *node)
|
|||
|
||||
ref_clk = of_clk_get(node, 0);
|
||||
if (IS_ERR(ref_clk)) {
|
||||
pr_err("%s: of_clk_get failed\n", node->full_name);
|
||||
pr_err("%pOF: of_clk_get failed\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, mul, 1);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("%s: failed to register clock\n", node->full_name);
|
||||
pr_err("%pOF: failed to register clock\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
|
|||
|
||||
static void __init moxart_of_apb_clk_init(struct device_node *node)
|
||||
{
|
||||
static void __iomem *base;
|
||||
void __iomem *base;
|
||||
struct clk_hw *hw;
|
||||
struct clk *pll_clk;
|
||||
unsigned int div, val;
|
||||
|
@ -70,7 +70,7 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
|
|||
|
||||
base = of_iomap(node, 0);
|
||||
if (!base) {
|
||||
pr_err("%s: of_iomap failed\n", node->full_name);
|
||||
pr_err("%pOF: of_iomap failed\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -83,13 +83,13 @@ static void __init moxart_of_apb_clk_init(struct device_node *node)
|
|||
|
||||
pll_clk = of_clk_get(node, 0);
|
||||
if (IS_ERR(pll_clk)) {
|
||||
pr_err("%s: of_clk_get failed\n", node->full_name);
|
||||
pr_err("%pOF: of_clk_get failed\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
hw = clk_hw_register_fixed_factor(NULL, name, parent_name, 0, 1, div);
|
||||
if (IS_ERR(hw)) {
|
||||
pr_err("%s: failed to register clock\n", node->full_name);
|
||||
pr_err("%pOF: failed to register clock\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/fsl/guts.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -536,6 +537,17 @@ static const struct clockgen_chipinfo chipinfo[] = {
|
|||
.pll_mask = 0x07,
|
||||
.flags = CG_PLL_8BIT,
|
||||
},
|
||||
{
|
||||
.compat = "fsl,ls1088a-clockgen",
|
||||
.cmux_groups = {
|
||||
&clockgen2_cmux_cga12
|
||||
},
|
||||
.cmux_to_group = {
|
||||
0, 0, -1
|
||||
},
|
||||
.pll_mask = 0x07,
|
||||
.flags = CG_VER3 | CG_LITTLE_ENDIAN,
|
||||
},
|
||||
{
|
||||
.compat = "fsl,ls1012a-clockgen",
|
||||
.cmux_groups = {
|
||||
|
@ -1113,6 +1125,7 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
|
|||
|
||||
for (i = 0; i < ARRAY_SIZE(pll->div); i++) {
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
snprintf(pll->div[i].name, sizeof(pll->div[i].name),
|
||||
"cg-pll%d-div%d", idx, i + 1);
|
||||
|
@ -1126,6 +1139,11 @@ static void __init create_one_pll(struct clockgen *cg, int idx)
|
|||
}
|
||||
|
||||
pll->div[i].clk = clk;
|
||||
ret = clk_register_clkdev(clk, pll->div[i].name, NULL);
|
||||
if (ret != 0)
|
||||
pr_err("%s: %s: register to lookup table failed %ld\n",
|
||||
__func__, pll->div[i].name, PTR_ERR(clk));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1348,8 +1366,7 @@ static void __init clockgen_init(struct device_node *np)
|
|||
}
|
||||
|
||||
if (i == ARRAY_SIZE(chipinfo)) {
|
||||
pr_err("%s: unknown clockgen node %s\n", __func__,
|
||||
np->full_name);
|
||||
pr_err("%s: unknown clockgen node %pOF\n", __func__, np);
|
||||
goto err;
|
||||
}
|
||||
clockgen.info = chipinfo[i];
|
||||
|
@ -1362,8 +1379,8 @@ static void __init clockgen_init(struct device_node *np)
|
|||
if (guts) {
|
||||
clockgen.guts = of_iomap(guts, 0);
|
||||
if (!clockgen.guts) {
|
||||
pr_err("%s: Couldn't map %s regs\n", __func__,
|
||||
guts->full_name);
|
||||
pr_err("%s: Couldn't map %pOF regs\n", __func__,
|
||||
guts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1398,6 +1415,7 @@ CLK_OF_DECLARE(qoriq_clockgen_ls1012a, "fsl,ls1012a-clockgen", clockgen_init);
|
|||
CLK_OF_DECLARE(qoriq_clockgen_ls1021a, "fsl,ls1021a-clockgen", clockgen_init);
|
||||
CLK_OF_DECLARE(qoriq_clockgen_ls1043a, "fsl,ls1043a-clockgen", clockgen_init);
|
||||
CLK_OF_DECLARE(qoriq_clockgen_ls1046a, "fsl,ls1046a-clockgen", clockgen_init);
|
||||
CLK_OF_DECLARE(qoriq_clockgen_ls1088a, "fsl,ls1088a-clockgen", clockgen_init);
|
||||
CLK_OF_DECLARE(qoriq_clockgen_ls2080a, "fsl,ls2080a-clockgen", clockgen_init);
|
||||
|
||||
/* Legacy nodes */
|
||||
|
|
|
@ -519,6 +519,11 @@ static int si5351_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
SI5351_CLK_INTEGER_MODE,
|
||||
(hwdata->params.p2 == 0) ? SI5351_CLK_INTEGER_MODE : 0);
|
||||
|
||||
/* Do a pll soft reset on the affected pll */
|
||||
si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
|
||||
hwdata->num == 0 ? SI5351_PLL_RESET_A :
|
||||
SI5351_PLL_RESET_B);
|
||||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: p1 = %lu, p2 = %lu, p3 = %lu, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, clk_hw_get_name(hw),
|
||||
|
@ -1091,13 +1096,6 @@ static int si5351_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
si5351_set_bits(hwdata->drvdata, SI5351_CLK0_CTRL + hwdata->num,
|
||||
SI5351_CLK_POWERDOWN, 0);
|
||||
|
||||
/*
|
||||
* Do a pll soft reset on both plls, needed in some cases to get
|
||||
* all outputs running.
|
||||
*/
|
||||
si5351_reg_write(hwdata->drvdata, SI5351_PLL_RESET,
|
||||
SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
|
||||
|
||||
dev_dbg(&hwdata->drvdata->client->dev,
|
||||
"%s - %s: rdiv = %u, parent_rate = %lu, rate = %lu\n",
|
||||
__func__, clk_hw_get_name(hw), (1 << rdiv),
|
||||
|
|
|
@ -1541,8 +1541,8 @@ static void __init stm32f4_rcc_init(struct device_node *np)
|
|||
base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock);
|
||||
|
||||
if (IS_ERR(clks[idx])) {
|
||||
pr_err("%s: Unable to register leaf clock %s\n",
|
||||
np->full_name, gd->name);
|
||||
pr_err("%pOF: Unable to register leaf clock %s\n",
|
||||
np, gd->name);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -57,6 +57,7 @@
|
|||
#define VC5_PRIM_SRC_SHDN 0x10
|
||||
#define VC5_PRIM_SRC_SHDN_EN_XTAL BIT(7)
|
||||
#define VC5_PRIM_SRC_SHDN_EN_CLKIN BIT(6)
|
||||
#define VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ BIT(3)
|
||||
#define VC5_PRIM_SRC_SHDN_SP BIT(1)
|
||||
#define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN BIT(0)
|
||||
|
||||
|
@ -122,12 +123,16 @@
|
|||
/* flags to describe chip features */
|
||||
/* chip has built-in oscilator */
|
||||
#define VC5_HAS_INTERNAL_XTAL BIT(0)
|
||||
/* chip has PFD requency doubler */
|
||||
#define VC5_HAS_PFD_FREQ_DBL BIT(1)
|
||||
|
||||
/* Supported IDT VC5 models. */
|
||||
enum vc5_model {
|
||||
IDT_VC5_5P49V5923,
|
||||
IDT_VC5_5P49V5925,
|
||||
IDT_VC5_5P49V5933,
|
||||
IDT_VC5_5P49V5935,
|
||||
IDT_VC6_5P49V6901,
|
||||
};
|
||||
|
||||
/* Structure to describe features of a particular VC5 model */
|
||||
|
@ -157,6 +162,8 @@ struct vc5_driver_data {
|
|||
struct clk *pin_clkin;
|
||||
unsigned char clk_mux_ins;
|
||||
struct clk_hw clk_mux;
|
||||
struct clk_hw clk_mul;
|
||||
struct clk_hw clk_pfd;
|
||||
struct vc5_hw_data clk_pll;
|
||||
struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
|
||||
struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
|
||||
|
@ -166,6 +173,14 @@ static const char * const vc5_mux_names[] = {
|
|||
"mux"
|
||||
};
|
||||
|
||||
static const char * const vc5_dbl_names[] = {
|
||||
"dbl"
|
||||
};
|
||||
|
||||
static const char * const vc5_pfd_names[] = {
|
||||
"pfd"
|
||||
};
|
||||
|
||||
static const char * const vc5_pll_names[] = {
|
||||
"pll"
|
||||
};
|
||||
|
@ -254,11 +269,64 @@ static int vc5_mux_set_parent(struct clk_hw *hw, u8 index)
|
|||
return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src);
|
||||
}
|
||||
|
||||
static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw,
|
||||
static const struct clk_ops vc5_mux_ops = {
|
||||
.set_parent = vc5_mux_set_parent,
|
||||
.get_parent = vc5_mux_get_parent,
|
||||
};
|
||||
|
||||
static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct vc5_driver_data *vc5 =
|
||||
container_of(hw, struct vc5_driver_data, clk_mux);
|
||||
container_of(hw, struct vc5_driver_data, clk_mul);
|
||||
unsigned int premul;
|
||||
|
||||
regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
|
||||
if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ)
|
||||
parent_rate *= 2;
|
||||
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
if ((*parent_rate == rate) || ((*parent_rate * 2) == rate))
|
||||
return rate;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct vc5_driver_data *vc5 =
|
||||
container_of(hw, struct vc5_driver_data, clk_mul);
|
||||
u32 mask;
|
||||
|
||||
if ((parent_rate * 2) == rate)
|
||||
mask = VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ;
|
||||
else
|
||||
mask = 0;
|
||||
|
||||
regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
|
||||
VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
|
||||
mask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops vc5_dbl_ops = {
|
||||
.recalc_rate = vc5_dbl_recalc_rate,
|
||||
.round_rate = vc5_dbl_round_rate,
|
||||
.set_rate = vc5_dbl_set_rate,
|
||||
};
|
||||
|
||||
static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct vc5_driver_data *vc5 =
|
||||
container_of(hw, struct vc5_driver_data, clk_pfd);
|
||||
unsigned int prediv, div;
|
||||
|
||||
regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
|
||||
|
@ -276,7 +344,7 @@ static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw,
|
|||
return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
|
||||
}
|
||||
|
||||
static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
unsigned long idiv;
|
||||
|
@ -296,11 +364,11 @@ static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return *parent_rate / idiv;
|
||||
}
|
||||
|
||||
static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct vc5_driver_data *vc5 =
|
||||
container_of(hw, struct vc5_driver_data, clk_mux);
|
||||
container_of(hw, struct vc5_driver_data, clk_pfd);
|
||||
unsigned long idiv;
|
||||
u8 div;
|
||||
|
||||
|
@ -328,12 +396,10 @@ static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops vc5_mux_ops = {
|
||||
.set_parent = vc5_mux_set_parent,
|
||||
.get_parent = vc5_mux_get_parent,
|
||||
.recalc_rate = vc5_mux_recalc_rate,
|
||||
.round_rate = vc5_mux_round_rate,
|
||||
.set_rate = vc5_mux_set_rate,
|
||||
static const struct clk_ops vc5_pfd_ops = {
|
||||
.recalc_rate = vc5_pfd_recalc_rate,
|
||||
.round_rate = vc5_pfd_round_rate,
|
||||
.set_rate = vc5_pfd_set_rate,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -426,6 +492,10 @@ static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw,
|
|||
div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) |
|
||||
(od_frc[2] << 6) | (od_frc[3] >> 2);
|
||||
|
||||
/* Avoid division by zero if the output is not configured. */
|
||||
if (div_int == 0 && div_frc == 0)
|
||||
return 0;
|
||||
|
||||
/* The PLL divider has 12 integer bits and 30 fractional bits */
|
||||
return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
|
||||
}
|
||||
|
@ -503,6 +573,25 @@ static int vc5_clk_out_prepare(struct clk_hw *hw)
|
|||
{
|
||||
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
|
||||
struct vc5_driver_data *vc5 = hwdata->vc5;
|
||||
const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
|
||||
VC5_OUT_DIV_CONTROL_SEL_EXT |
|
||||
VC5_OUT_DIV_CONTROL_EN_FOD;
|
||||
unsigned int src;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If the input mux is disabled, enable it first and
|
||||
* select source from matching FOD.
|
||||
*/
|
||||
regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
|
||||
if ((src & mask) == 0) {
|
||||
src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD;
|
||||
ret = regmap_update_bits(vc5->regmap,
|
||||
VC5_OUT_DIV_CONTROL(hwdata->num),
|
||||
mask | VC5_OUT_DIV_CONTROL_RESET, src);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Enable the clock buffer */
|
||||
regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
|
||||
|
@ -516,7 +605,7 @@ static void vc5_clk_out_unprepare(struct clk_hw *hw)
|
|||
struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
|
||||
struct vc5_driver_data *vc5 = hwdata->vc5;
|
||||
|
||||
/* Enable the clock buffer */
|
||||
/* Disable the clock buffer */
|
||||
regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
|
||||
VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0);
|
||||
}
|
||||
|
@ -537,6 +626,9 @@ static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
|
|||
regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
|
||||
src &= mask;
|
||||
|
||||
if (src == 0) /* Input mux set to DISABLED */
|
||||
return 0;
|
||||
|
||||
if ((src & fodclkmask) == VC5_OUT_DIV_CONTROL_EN_FOD)
|
||||
return 0;
|
||||
|
||||
|
@ -595,7 +687,9 @@ static int vc5_map_index_to_output(const enum vc5_model model,
|
|||
case IDT_VC5_5P49V5933:
|
||||
return (n == 0) ? 0 : 3;
|
||||
case IDT_VC5_5P49V5923:
|
||||
case IDT_VC5_5P49V5925:
|
||||
case IDT_VC5_5P49V5935:
|
||||
case IDT_VC6_5P49V6901:
|
||||
default:
|
||||
return n;
|
||||
}
|
||||
|
@ -672,12 +766,46 @@ static int vc5_probe(struct i2c_client *client,
|
|||
goto err_clk;
|
||||
}
|
||||
|
||||
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
|
||||
/* Register frequency doubler */
|
||||
memset(&init, 0, sizeof(init));
|
||||
init.name = vc5_dbl_names[0];
|
||||
init.ops = &vc5_dbl_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = vc5_mux_names;
|
||||
init.num_parents = 1;
|
||||
vc5->clk_mul.init = &init;
|
||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n",
|
||||
init.name);
|
||||
goto err_clk;
|
||||
}
|
||||
}
|
||||
|
||||
/* Register PFD */
|
||||
memset(&init, 0, sizeof(init));
|
||||
init.name = vc5_pfd_names[0];
|
||||
init.ops = &vc5_pfd_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
|
||||
init.parent_names = vc5_dbl_names;
|
||||
else
|
||||
init.parent_names = vc5_mux_names;
|
||||
init.num_parents = 1;
|
||||
vc5->clk_pfd.init = &init;
|
||||
ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "unable to register %s\n", init.name);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
/* Register PLL */
|
||||
memset(&init, 0, sizeof(init));
|
||||
init.name = vc5_pll_names[0];
|
||||
init.ops = &vc5_pll_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = vc5_mux_names;
|
||||
init.parent_names = vc5_pfd_names;
|
||||
init.num_parents = 1;
|
||||
vc5->clk_pll.num = 0;
|
||||
vc5->clk_pll.vc5 = vc5;
|
||||
|
@ -785,6 +913,13 @@ static const struct vc5_chip_info idt_5p49v5923_info = {
|
|||
.flags = 0,
|
||||
};
|
||||
|
||||
static const struct vc5_chip_info idt_5p49v5925_info = {
|
||||
.model = IDT_VC5_5P49V5925,
|
||||
.clk_fod_cnt = 4,
|
||||
.clk_out_cnt = 5,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
static const struct vc5_chip_info idt_5p49v5933_info = {
|
||||
.model = IDT_VC5_5P49V5933,
|
||||
.clk_fod_cnt = 2,
|
||||
|
@ -799,18 +934,29 @@ static const struct vc5_chip_info idt_5p49v5935_info = {
|
|||
.flags = VC5_HAS_INTERNAL_XTAL,
|
||||
};
|
||||
|
||||
static const struct vc5_chip_info idt_5p49v6901_info = {
|
||||
.model = IDT_VC6_5P49V6901,
|
||||
.clk_fod_cnt = 4,
|
||||
.clk_out_cnt = 5,
|
||||
.flags = VC5_HAS_PFD_FREQ_DBL,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id vc5_id[] = {
|
||||
{ "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
|
||||
{ "5p49v5925", .driver_data = IDT_VC5_5P49V5925 },
|
||||
{ "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
|
||||
{ "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
|
||||
{ "5p49v6901", .driver_data = IDT_VC6_5P49V6901 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, vc5_id);
|
||||
|
||||
static const struct of_device_id clk_vc5_of_match[] = {
|
||||
{ .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info },
|
||||
{ .compatible = "idt,5p49v5925", .data = &idt_5p49v5925_info },
|
||||
{ .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
|
||||
{ .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
|
||||
{ .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
|
||||
|
|
|
@ -192,7 +192,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty
|
|||
|
||||
reg = of_iomap(np, 0);
|
||||
if (reg == NULL) {
|
||||
pr_err("Unable to map CSR register for %s\n", np->full_name);
|
||||
pr_err("Unable to map CSR register for %pOF\n", np);
|
||||
return;
|
||||
}
|
||||
of_property_read_string(np, "clock-output-names", &clk_name);
|
||||
|
@ -409,12 +409,12 @@ static void xgene_pmdclk_init(struct device_node *np)
|
|||
/* Parse the DTS register for resource */
|
||||
rc = of_address_to_resource(np, 0, &res);
|
||||
if (rc != 0) {
|
||||
pr_err("no DTS register for %s\n", np->full_name);
|
||||
pr_err("no DTS register for %pOF\n", np);
|
||||
return;
|
||||
}
|
||||
csr_reg = of_iomap(np, 0);
|
||||
if (!csr_reg) {
|
||||
pr_err("Unable to map resource for %s\n", np->full_name);
|
||||
pr_err("Unable to map resource for %pOF\n", np);
|
||||
return;
|
||||
}
|
||||
of_property_read_string(np, "clock-output-names", &clk_name);
|
||||
|
@ -703,16 +703,14 @@ static void __init xgene_devclk_init(struct device_node *np)
|
|||
rc = of_address_to_resource(np, i, &res);
|
||||
if (rc != 0) {
|
||||
if (i == 0) {
|
||||
pr_err("no DTS register for %s\n",
|
||||
np->full_name);
|
||||
pr_err("no DTS register for %pOF\n", np);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
map_res = of_iomap(np, i);
|
||||
if (map_res == NULL) {
|
||||
pr_err("Unable to map resource %d for %s\n",
|
||||
i, np->full_name);
|
||||
pr_err("Unable to map resource %d for %pOF\n", i, np);
|
||||
goto err;
|
||||
}
|
||||
if (strcmp(res.name, "div-reg") == 0)
|
||||
|
@ -747,8 +745,7 @@ static void __init xgene_devclk_init(struct device_node *np)
|
|||
pr_debug("Add %s clock\n", clk_name);
|
||||
rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
|
||||
if (rc != 0)
|
||||
pr_err("%s: could register provider clk %s\n", __func__,
|
||||
np->full_name);
|
||||
pr_err("%s: could register provider clk %pOF\n", __func__, np);
|
||||
|
||||
return;
|
||||
|
||||
|
|
|
@ -3132,7 +3132,7 @@ int of_clk_add_provider(struct device_node *np,
|
|||
mutex_lock(&of_clk_mutex);
|
||||
list_add(&cp->link, &of_clk_providers);
|
||||
mutex_unlock(&of_clk_mutex);
|
||||
pr_debug("Added clock from %s\n", np->full_name);
|
||||
pr_debug("Added clock from %pOF\n", np);
|
||||
|
||||
ret = of_clk_set_defaults(np, true);
|
||||
if (ret < 0)
|
||||
|
@ -3167,7 +3167,7 @@ int of_clk_add_hw_provider(struct device_node *np,
|
|||
mutex_lock(&of_clk_mutex);
|
||||
list_add(&cp->link, &of_clk_providers);
|
||||
mutex_unlock(&of_clk_mutex);
|
||||
pr_debug("Added clk_hw provider from %s\n", np->full_name);
|
||||
pr_debug("Added clk_hw provider from %pOF\n", np);
|
||||
|
||||
ret = of_clk_set_defaults(np, true);
|
||||
if (ret < 0)
|
||||
|
|
|
@ -77,8 +77,8 @@ static struct clk *__of_clk_get_by_name(struct device_node *np,
|
|||
break;
|
||||
} else if (name && index >= 0) {
|
||||
if (PTR_ERR(clk) != -EPROBE_DEFER)
|
||||
pr_err("ERROR: could not get clock %s:%s(%i)\n",
|
||||
np->full_name, name ? name : "", index);
|
||||
pr_err("ERROR: could not get clock %pOF:%s(%i)\n",
|
||||
np, name ? name : "", index);
|
||||
return clk;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ static struct hisi_fixed_factor_clock hi6220_fixed_factor_clks[] __initdata = {
|
|||
};
|
||||
|
||||
static struct hisi_gate_clock hi6220_separated_gate_clks_ao[] __initdata = {
|
||||
{ HI6220_WDT0_PCLK, "wdt0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
|
||||
{ HI6220_WDT1_PCLK, "wdt1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
|
||||
{ HI6220_WDT2_PCLK, "wdt2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
|
||||
{ HI6220_WDT0_PCLK, "wdt0_pclk", "ref32k", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 12, 0, },
|
||||
{ HI6220_WDT1_PCLK, "wdt1_pclk", "ref32k", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 13, 0, },
|
||||
{ HI6220_WDT2_PCLK, "wdt2_pclk", "ref32k", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 14, 0, },
|
||||
{ HI6220_TIMER0_PCLK, "timer0_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 15, 0, },
|
||||
{ HI6220_TIMER1_PCLK, "timer1_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 16, 0, },
|
||||
{ HI6220_TIMER2_PCLK, "timer2_pclk", "clk_tcxo", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x630, 17, 0, },
|
||||
|
|
|
@ -416,10 +416,10 @@ static void __init mx51_clocks_init(struct device_node *np)
|
|||
|
||||
clk[IMX5_CLK_LP_APM] = imx_clk_mux("lp_apm", MXC_CCM_CCSR, 9, 1,
|
||||
lp_apm_sel, ARRAY_SIZE(lp_apm_sel));
|
||||
clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
|
||||
mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel));
|
||||
clk[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
|
||||
mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel));
|
||||
clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_flags("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
|
||||
mx51_ipu_di0_sel, ARRAY_SIZE(mx51_ipu_di0_sel), CLK_SET_RATE_PARENT);
|
||||
clk[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux_flags("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
|
||||
mx51_ipu_di1_sel, ARRAY_SIZE(mx51_ipu_di1_sel), CLK_SET_RATE_PARENT);
|
||||
clk[IMX5_CLK_TVE_EXT_SEL] = imx_clk_mux_flags("tve_ext_sel", MXC_CCM_CSCMR1, 6, 1,
|
||||
mx51_tve_ext_sel, ARRAY_SIZE(mx51_tve_ext_sel), CLK_SET_RATE_PARENT);
|
||||
clk[IMX5_CLK_TVE_SEL] = imx_clk_mux("tve_sel", MXC_CCM_CSCMR1, 7, 1,
|
||||
|
|
|
@ -71,7 +71,7 @@ static const char *pll5_bypass_sels[] = { "pll5", "pll5_bypass_src", };
|
|||
static const char *pll6_bypass_sels[] = { "pll6", "pll6_bypass_src", };
|
||||
static const char *pll7_bypass_sels[] = { "pll7", "pll7_bypass_src", };
|
||||
|
||||
static struct clk_div_table clk_enet_ref_table[] = {
|
||||
static const struct clk_div_table clk_enet_ref_table[] = {
|
||||
{ .val = 0, .div = 20, },
|
||||
{ .val = 1, .div = 10, },
|
||||
{ .val = 2, .div = 5, },
|
||||
|
@ -79,14 +79,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table post_div_table[] = {
|
||||
static const struct clk_div_table post_div_table[] = {
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 0, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table video_div_table[] = {
|
||||
static const struct clk_div_table video_div_table[] = {
|
||||
{ .val = 0, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 2, .div = 1, },
|
||||
|
|
|
@ -105,7 +105,7 @@ static int const clks_init_on[] __initconst = {
|
|||
IMX6SX_CLK_EPIT2,
|
||||
};
|
||||
|
||||
static struct clk_div_table clk_enet_ref_table[] = {
|
||||
static const struct clk_div_table clk_enet_ref_table[] = {
|
||||
{ .val = 0, .div = 20, },
|
||||
{ .val = 1, .div = 10, },
|
||||
{ .val = 2, .div = 5, },
|
||||
|
@ -113,14 +113,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table post_div_table[] = {
|
||||
static const struct clk_div_table post_div_table[] = {
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 0, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table video_div_table[] = {
|
||||
static const struct clk_div_table video_div_table[] = {
|
||||
{ .val = 0, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 2, .div = 1, },
|
||||
|
|
|
@ -78,7 +78,7 @@ static int const clks_init_on[] __initconst = {
|
|||
IMX6UL_CLK_MMDC_P0_FAST, IMX6UL_CLK_MMDC_P0_IPG,
|
||||
};
|
||||
|
||||
static struct clk_div_table clk_enet_ref_table[] = {
|
||||
static const struct clk_div_table clk_enet_ref_table[] = {
|
||||
{ .val = 0, .div = 20, },
|
||||
{ .val = 1, .div = 10, },
|
||||
{ .val = 2, .div = 5, },
|
||||
|
@ -86,14 +86,14 @@ static struct clk_div_table clk_enet_ref_table[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table post_div_table[] = {
|
||||
static const struct clk_div_table post_div_table[] = {
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 0, .div = 4, },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table video_div_table[] = {
|
||||
static const struct clk_div_table video_div_table[] = {
|
||||
{ .val = 0, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
{ .val = 2, .div = 1, },
|
||||
|
|
|
@ -27,7 +27,7 @@ static u32 share_count_sai2;
|
|||
static u32 share_count_sai3;
|
||||
static u32 share_count_nand;
|
||||
|
||||
static struct clk_div_table test_div_table[] = {
|
||||
static const struct clk_div_table test_div_table[] = {
|
||||
{ .val = 3, .div = 1, },
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
|
@ -35,7 +35,7 @@ static struct clk_div_table test_div_table[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static struct clk_div_table post_div_table[] = {
|
||||
static const struct clk_div_table post_div_table[] = {
|
||||
{ .val = 3, .div = 4, },
|
||||
{ .val = 2, .div = 1, },
|
||||
{ .val = 1, .div = 2, },
|
||||
|
|
|
@ -102,7 +102,7 @@ static const char *ftm_ext_sels[] = {"sirc_128k", "sxosc", "fxosc_half", "audio_
|
|||
static const char *ftm_fix_sels[] = { "sxosc", "ipg_bus", };
|
||||
|
||||
|
||||
static struct clk_div_table pll4_audio_div_table[] = {
|
||||
static const struct clk_div_table pll4_audio_div_table[] = {
|
||||
{ .val = 0, .div = 1 },
|
||||
{ .val = 1, .div = 2 },
|
||||
{ .val = 2, .div = 6 },
|
||||
|
|
|
@ -27,7 +27,6 @@ static inline struct mtk_clk_cpumux *to_mtk_clk_cpumux(struct clk_hw *_hw)
|
|||
static u8 clk_cpumux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct mtk_clk_cpumux *mux = to_mtk_clk_cpumux(hw);
|
||||
int num_parents = clk_hw_get_num_parents(hw);
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(mux->regmap, mux->reg, &val);
|
||||
|
@ -35,9 +34,6 @@ static u8 clk_cpumux_get_parent(struct clk_hw *hw)
|
|||
val >>= mux->shift;
|
||||
val &= mux->mask;
|
||||
|
||||
if (val >= num_parents)
|
||||
return -EINVAL;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
|
@ -98,7 +94,7 @@ int __init mtk_clk_register_cpumuxes(struct device_node *node,
|
|||
|
||||
regmap = syscon_node_to_regmap(node);
|
||||
if (IS_ERR(regmap)) {
|
||||
pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
|
||||
pr_err("Cannot find regmap for %pOF: %ld\n", node,
|
||||
PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ int mtk_clk_register_gates(struct device_node *node,
|
|||
|
||||
regmap = syscon_node_to_regmap(node);
|
||||
if (IS_ERR(regmap)) {
|
||||
pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
|
||||
pr_err("Cannot find regmap for %pOF: %ld\n", node,
|
||||
PTR_ERR(regmap));
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ void mtk_register_reset_controller(struct device_node *np,
|
|||
|
||||
regmap = syscon_node_to_regmap(np);
|
||||
if (IS_ERR(regmap)) {
|
||||
pr_err("Cannot find regmap for %s: %ld\n", np->full_name,
|
||||
pr_err("Cannot find regmap for %pOF: %ld\n", np,
|
||||
PTR_ERR(regmap));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ config COMMON_CLK_AMLOGIC
|
|||
config COMMON_CLK_MESON8B
|
||||
bool
|
||||
depends on COMMON_CLK_AMLOGIC
|
||||
select RESET_CONTROLLER
|
||||
help
|
||||
Support for the clock controller on AmLogic S802 (Meson8),
|
||||
S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o clk-audio-divider.o
|
||||
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o
|
||||
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
|
||||
obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o gxbb-aoclk-regmap.o gxbb-aoclk-32k.o
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (c) 2017 BayLibre, SAS.
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/regmap.h>
|
||||
#include "gxbb-aoclk.h"
|
||||
|
||||
/*
|
||||
* The AO Domain embeds a dual/divider to generate a more precise
|
||||
* 32,768KHz clock for low-power suspend mode and CEC.
|
||||
* ______ ______
|
||||
* | | | |
|
||||
* ______ | Div1 |-| Cnt1 | ______
|
||||
* | | /|______| |______|\ | |
|
||||
* Xtal-->| Gate |---| ______ ______ X-X--| Gate |-->
|
||||
* |______| | \| | | |/ | |______|
|
||||
* | | Div2 |-| Cnt2 | |
|
||||
* | |______| |______| |
|
||||
* |_______________________|
|
||||
*
|
||||
* The dividing can be switched to single or dual, with a counter
|
||||
* for each divider to set when the switching is done.
|
||||
* The entire dividing mechanism can be also bypassed.
|
||||
*/
|
||||
|
||||
#define CLK_CNTL0_N1_MASK GENMASK(11, 0)
|
||||
#define CLK_CNTL0_N2_MASK GENMASK(23, 12)
|
||||
#define CLK_CNTL0_DUALDIV_EN BIT(28)
|
||||
#define CLK_CNTL0_OUT_GATE_EN BIT(30)
|
||||
#define CLK_CNTL0_IN_GATE_EN BIT(31)
|
||||
|
||||
#define CLK_CNTL1_M1_MASK GENMASK(11, 0)
|
||||
#define CLK_CNTL1_M2_MASK GENMASK(23, 12)
|
||||
#define CLK_CNTL1_BYPASS_EN BIT(24)
|
||||
#define CLK_CNTL1_SELECT_OSC BIT(27)
|
||||
|
||||
#define PWR_CNTL_ALT_32K_SEL GENMASK(13, 10)
|
||||
|
||||
struct cec_32k_freq_table {
|
||||
unsigned long parent_rate;
|
||||
unsigned long target_rate;
|
||||
bool dualdiv;
|
||||
unsigned int n1;
|
||||
unsigned int n2;
|
||||
unsigned int m1;
|
||||
unsigned int m2;
|
||||
};
|
||||
|
||||
static const struct cec_32k_freq_table aoclk_cec_32k_table[] = {
|
||||
[0] = {
|
||||
.parent_rate = 24000000,
|
||||
.target_rate = 32768,
|
||||
.dualdiv = true,
|
||||
.n1 = 733,
|
||||
.n2 = 732,
|
||||
.m1 = 8,
|
||||
.m2 = 11,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* If CLK_CNTL0_DUALDIV_EN == 0
|
||||
* - will use N1 divider only
|
||||
* If CLK_CNTL0_DUALDIV_EN == 1
|
||||
* - hold M1 cycles of N1 divider then changes to N2
|
||||
* - hold M2 cycles of N2 divider then changes to N1
|
||||
* Then we can get more accurate division.
|
||||
*/
|
||||
static unsigned long aoclk_cec_32k_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw);
|
||||
unsigned long n1;
|
||||
u32 reg0, reg1;
|
||||
|
||||
regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, ®0);
|
||||
regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, ®1);
|
||||
|
||||
if (reg1 & CLK_CNTL1_BYPASS_EN)
|
||||
return parent_rate;
|
||||
|
||||
if (reg0 & CLK_CNTL0_DUALDIV_EN) {
|
||||
unsigned long n2, m1, m2, f1, f2, p1, p2;
|
||||
|
||||
n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1;
|
||||
n2 = FIELD_GET(CLK_CNTL0_N2_MASK, reg0) + 1;
|
||||
|
||||
m1 = FIELD_GET(CLK_CNTL1_M1_MASK, reg1) + 1;
|
||||
m2 = FIELD_GET(CLK_CNTL1_M2_MASK, reg1) + 1;
|
||||
|
||||
f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
|
||||
f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
|
||||
|
||||
p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
|
||||
p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
|
||||
|
||||
return DIV_ROUND_UP(100000000, p1 + p2);
|
||||
}
|
||||
|
||||
n1 = FIELD_GET(CLK_CNTL0_N1_MASK, reg0) + 1;
|
||||
|
||||
return DIV_ROUND_CLOSEST(parent_rate, n1);
|
||||
}
|
||||
|
||||
static const struct cec_32k_freq_table *find_cec_32k_freq(unsigned long rate,
|
||||
unsigned long prate)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0 ; i < ARRAY_SIZE(aoclk_cec_32k_table) ; ++i)
|
||||
if (aoclk_cec_32k_table[i].parent_rate == prate &&
|
||||
aoclk_cec_32k_table[i].target_rate == rate)
|
||||
return &aoclk_cec_32k_table[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static long aoclk_cec_32k_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate,
|
||||
*prate);
|
||||
|
||||
/* If invalid return first one */
|
||||
if (!freq)
|
||||
return aoclk_cec_32k_table[0].target_rate;
|
||||
|
||||
return freq->target_rate;
|
||||
}
|
||||
|
||||
/*
|
||||
* From the Amlogic init procedure, the IN and OUT gates needs to be handled
|
||||
* in the init procedure to avoid any glitches.
|
||||
*/
|
||||
|
||||
static int aoclk_cec_32k_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
const struct cec_32k_freq_table *freq = find_cec_32k_freq(rate,
|
||||
parent_rate);
|
||||
struct aoclk_cec_32k *cec_32k = to_aoclk_cec_32k(hw);
|
||||
u32 reg = 0;
|
||||
|
||||
if (!freq)
|
||||
return -EINVAL;
|
||||
|
||||
/* Disable clock */
|
||||
regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
|
||||
CLK_CNTL0_IN_GATE_EN | CLK_CNTL0_OUT_GATE_EN, 0);
|
||||
|
||||
reg = FIELD_PREP(CLK_CNTL0_N1_MASK, freq->n1 - 1);
|
||||
if (freq->dualdiv)
|
||||
reg |= CLK_CNTL0_DUALDIV_EN |
|
||||
FIELD_PREP(CLK_CNTL0_N2_MASK, freq->n2 - 1);
|
||||
|
||||
regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0, reg);
|
||||
|
||||
reg = FIELD_PREP(CLK_CNTL1_M1_MASK, freq->m1 - 1);
|
||||
if (freq->dualdiv)
|
||||
reg |= FIELD_PREP(CLK_CNTL1_M2_MASK, freq->m2 - 1);
|
||||
|
||||
regmap_write(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, reg);
|
||||
|
||||
/* Enable clock */
|
||||
regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
|
||||
CLK_CNTL0_IN_GATE_EN, CLK_CNTL0_IN_GATE_EN);
|
||||
|
||||
udelay(200);
|
||||
|
||||
regmap_update_bits(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL0,
|
||||
CLK_CNTL0_OUT_GATE_EN, CLK_CNTL0_OUT_GATE_EN);
|
||||
|
||||
regmap_update_bits(cec_32k->regmap, AO_CRT_CLK_CNTL1,
|
||||
CLK_CNTL1_SELECT_OSC, CLK_CNTL1_SELECT_OSC);
|
||||
|
||||
/* Select 32k from XTAL */
|
||||
regmap_update_bits(cec_32k->regmap,
|
||||
AO_RTI_PWR_CNTL_REG0,
|
||||
PWR_CNTL_ALT_32K_SEL,
|
||||
FIELD_PREP(PWR_CNTL_ALT_32K_SEL, 4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct clk_ops meson_aoclk_cec_32k_ops = {
|
||||
.recalc_rate = aoclk_cec_32k_recalc_rate,
|
||||
.round_rate = aoclk_cec_32k_round_rate,
|
||||
.set_rate = aoclk_cec_32k_set_rate,
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright (c) 2017 BayLibre, SAS.
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/regmap.h>
|
||||
#include "gxbb-aoclk.h"
|
||||
|
||||
static int aoclk_gate_regmap_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
|
||||
|
||||
return regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0,
|
||||
BIT(gate->bit_idx), BIT(gate->bit_idx));
|
||||
}
|
||||
|
||||
static void aoclk_gate_regmap_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
|
||||
|
||||
regmap_update_bits(gate->regmap, AO_RTI_GEN_CNTL_REG0,
|
||||
BIT(gate->bit_idx), 0);
|
||||
}
|
||||
|
||||
static int aoclk_gate_regmap_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct aoclk_gate_regmap *gate = to_aoclk_gate_regmap(hw);
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(gate->regmap, AO_RTI_GEN_CNTL_REG0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return (val & BIT(gate->bit_idx)) != 0;
|
||||
}
|
||||
|
||||
const struct clk_ops meson_aoclk_gate_regmap_ops = {
|
||||
.enable = aoclk_gate_regmap_enable,
|
||||
.disable = aoclk_gate_regmap_disable,
|
||||
.is_enabled = aoclk_gate_regmap_is_enabled,
|
||||
};
|
|
@ -56,16 +56,20 @@
|
|||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <dt-bindings/clock/gxbb-aoclkc.h>
|
||||
#include <dt-bindings/reset/gxbb-aoclkc.h>
|
||||
#include "gxbb-aoclk.h"
|
||||
|
||||
static DEFINE_SPINLOCK(gxbb_aoclk_lock);
|
||||
|
||||
struct gxbb_aoclk_reset_controller {
|
||||
struct reset_controller_dev reset;
|
||||
unsigned int *data;
|
||||
void __iomem *base;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev,
|
||||
|
@ -74,9 +78,8 @@ static int gxbb_aoclk_do_reset(struct reset_controller_dev *rcdev,
|
|||
struct gxbb_aoclk_reset_controller *reset =
|
||||
container_of(rcdev, struct gxbb_aoclk_reset_controller, reset);
|
||||
|
||||
writel(BIT(reset->data[id]), reset->base);
|
||||
|
||||
return 0;
|
||||
return regmap_write(reset->regmap, AO_RTI_GEN_CNTL_REG0,
|
||||
BIT(reset->data[id]));
|
||||
}
|
||||
|
||||
static const struct reset_control_ops gxbb_aoclk_reset_ops = {
|
||||
|
@ -84,13 +87,12 @@ static const struct reset_control_ops gxbb_aoclk_reset_ops = {
|
|||
};
|
||||
|
||||
#define GXBB_AO_GATE(_name, _bit) \
|
||||
static struct clk_gate _name##_ao = { \
|
||||
.reg = (void __iomem *)0, \
|
||||
static struct aoclk_gate_regmap _name##_ao = { \
|
||||
.bit_idx = (_bit), \
|
||||
.lock = &gxbb_aoclk_lock, \
|
||||
.hw.init = &(struct clk_init_data) { \
|
||||
.name = #_name "_ao", \
|
||||
.ops = &clk_gate_ops, \
|
||||
.ops = &meson_aoclk_gate_regmap_ops, \
|
||||
.parent_names = (const char *[]){ "clk81" }, \
|
||||
.num_parents = 1, \
|
||||
.flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \
|
||||
|
@ -104,6 +106,17 @@ GXBB_AO_GATE(uart1, 3);
|
|||
GXBB_AO_GATE(uart2, 5);
|
||||
GXBB_AO_GATE(ir_blaster, 6);
|
||||
|
||||
static struct aoclk_cec_32k cec_32k_ao = {
|
||||
.lock = &gxbb_aoclk_lock,
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "cec_32k_ao",
|
||||
.ops = &meson_aoclk_cec_32k_ops,
|
||||
.parent_names = (const char *[]){ "xtal" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
static unsigned int gxbb_aoclk_reset[] = {
|
||||
[RESET_AO_REMOTE] = 16,
|
||||
[RESET_AO_I2C_MASTER] = 18,
|
||||
|
@ -113,7 +126,7 @@ static unsigned int gxbb_aoclk_reset[] = {
|
|||
[RESET_AO_IR_BLASTER] = 23,
|
||||
};
|
||||
|
||||
static struct clk_gate *gxbb_aoclk_gate[] = {
|
||||
static struct aoclk_gate_regmap *gxbb_aoclk_gate[] = {
|
||||
[CLKID_AO_REMOTE] = &remote_ao,
|
||||
[CLKID_AO_I2C_MASTER] = &i2c_master_ao,
|
||||
[CLKID_AO_I2C_SLAVE] = &i2c_slave_ao,
|
||||
|
@ -130,30 +143,30 @@ static struct clk_hw_onecell_data gxbb_aoclk_onecell_data = {
|
|||
[CLKID_AO_UART1] = &uart1_ao.hw,
|
||||
[CLKID_AO_UART2] = &uart2_ao.hw,
|
||||
[CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw,
|
||||
[CLKID_AO_CEC_32K] = &cec_32k_ao.hw,
|
||||
},
|
||||
.num = ARRAY_SIZE(gxbb_aoclk_gate),
|
||||
.num = 7,
|
||||
};
|
||||
|
||||
static int gxbb_aoclkc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
void __iomem *base;
|
||||
int ret, clkid;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gxbb_aoclk_reset_controller *rstc;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regmap *regmap;
|
||||
int ret, clkid;
|
||||
|
||||
rstc = devm_kzalloc(dev, sizeof(*rstc), GFP_KERNEL);
|
||||
if (!rstc)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Generic clocks */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
regmap = syscon_node_to_regmap(of_get_parent(dev->of_node));
|
||||
if (IS_ERR(regmap)) {
|
||||
dev_err(dev, "failed to get regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Reset Controller */
|
||||
rstc->base = base;
|
||||
rstc->regmap = regmap;
|
||||
rstc->data = gxbb_aoclk_reset;
|
||||
rstc->reset.ops = &gxbb_aoclk_reset_ops;
|
||||
rstc->reset.nr_resets = ARRAY_SIZE(gxbb_aoclk_reset);
|
||||
|
@ -161,10 +174,10 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev)
|
|||
ret = devm_reset_controller_register(dev, &rstc->reset);
|
||||
|
||||
/*
|
||||
* Populate base address and register all clks
|
||||
* Populate regmap and register all clks
|
||||
*/
|
||||
for (clkid = 0; clkid < gxbb_aoclk_onecell_data.num; clkid++) {
|
||||
gxbb_aoclk_gate[clkid]->reg = base;
|
||||
for (clkid = 0; clkid < ARRAY_SIZE(gxbb_aoclk_gate); clkid++) {
|
||||
gxbb_aoclk_gate[clkid]->regmap = regmap;
|
||||
|
||||
ret = devm_clk_hw_register(dev,
|
||||
gxbb_aoclk_onecell_data.hws[clkid]);
|
||||
|
@ -172,12 +185,18 @@ static int gxbb_aoclkc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Specific clocks */
|
||||
cec_32k_ao.regmap = regmap;
|
||||
ret = devm_clk_hw_register(dev, &cec_32k_ao.hw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
|
||||
&gxbb_aoclk_onecell_data);
|
||||
}
|
||||
|
||||
static const struct of_device_id gxbb_aoclkc_match_table[] = {
|
||||
{ .compatible = "amlogic,gxbb-aoclkc" },
|
||||
{ .compatible = "amlogic,meson-gx-aoclkc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2017 BayLibre, SAS
|
||||
* Author: Neil Armstrong <narmstrong@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#ifndef __GXBB_AOCLKC_H
|
||||
#define __GXBB_AOCLKC_H
|
||||
|
||||
/* AO Configuration Clock registers offsets */
|
||||
#define AO_RTI_PWR_CNTL_REG1 0x0c
|
||||
#define AO_RTI_PWR_CNTL_REG0 0x10
|
||||
#define AO_RTI_GEN_CNTL_REG0 0x40
|
||||
#define AO_OSCIN_CNTL 0x58
|
||||
#define AO_CRT_CLK_CNTL1 0x68
|
||||
#define AO_RTC_ALT_CLK_CNTL0 0x94
|
||||
#define AO_RTC_ALT_CLK_CNTL1 0x98
|
||||
|
||||
struct aoclk_gate_regmap {
|
||||
struct clk_hw hw;
|
||||
unsigned bit_idx;
|
||||
struct regmap *regmap;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
#define to_aoclk_gate_regmap(_hw) \
|
||||
container_of(_hw, struct aoclk_gate_regmap, hw)
|
||||
|
||||
extern const struct clk_ops meson_aoclk_gate_regmap_ops;
|
||||
|
||||
struct aoclk_cec_32k {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
#define to_aoclk_cec_32k(_hw) container_of(_hw, struct aoclk_cec_32k, hw)
|
||||
|
||||
extern const struct clk_ops meson_aoclk_cec_32k_ops;
|
||||
|
||||
#endif /* __GXBB_AOCLKC_H */
|
|
@ -850,13 +850,14 @@ static struct meson_clk_audio_divider gxbb_cts_amclk_div = {
|
|||
.shift = 0,
|
||||
.width = 8,
|
||||
},
|
||||
.flags = CLK_DIVIDER_ROUND_CLOSEST,
|
||||
.lock = &clk_lock,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "cts_amclk_div",
|
||||
.ops = &meson_clk_audio_divider_ops,
|
||||
.parent_names = (const char *[]){ "cts_amclk_sel" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -894,12 +895,13 @@ static struct clk_divider gxbb_cts_mclk_i958_div = {
|
|||
.shift = 16,
|
||||
.width = 8,
|
||||
.lock = &clk_lock,
|
||||
.flags = CLK_DIVIDER_ROUND_CLOSEST,
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "cts_mclk_i958_div",
|
||||
.ops = &clk_divider_ops,
|
||||
.parent_names = (const char *[]){ "cts_mclk_i958_sel" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_DIVIDER_ROUND_CLOSEST,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -979,6 +981,156 @@ static struct clk_mux gxbb_32k_clk_sel = {
|
|||
},
|
||||
};
|
||||
|
||||
static const char * const gxbb_sd_emmc_clk0_parent_names[] = {
|
||||
"xtal", "fclk_div2", "fclk_div3", "fclk_div5", "fclk_div7",
|
||||
|
||||
/*
|
||||
* Following these parent clocks, we should also have had mpll2, mpll3
|
||||
* and gp0_pll but these clocks are too precious to be used here. All
|
||||
* the necessary rates for MMC and NAND operation can be acheived using
|
||||
* xtal or fclk_div clocks
|
||||
*/
|
||||
};
|
||||
|
||||
/* SDIO clock */
|
||||
static struct clk_mux gxbb_sd_emmc_a_clk0_sel = {
|
||||
.reg = (void *)HHI_SD_EMMC_CLK_CNTL,
|
||||
.mask = 0x7,
|
||||
.shift = 9,
|
||||
.lock = &clk_lock,
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "sd_emmc_a_clk0_sel",
|
||||
.ops = &clk_mux_ops,
|
||||
.parent_names = gxbb_sd_emmc_clk0_parent_names,
|
||||
.num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_divider gxbb_sd_emmc_a_clk0_div = {
|
||||
.reg = (void *)HHI_SD_EMMC_CLK_CNTL,
|
||||
.shift = 0,
|
||||
.width = 7,
|
||||
.lock = &clk_lock,
|
||||
.flags = CLK_DIVIDER_ROUND_CLOSEST,
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "sd_emmc_a_clk0_div",
|
||||
.ops = &clk_divider_ops,
|
||||
.parent_names = (const char *[]){ "sd_emmc_a_clk0_sel" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gate gxbb_sd_emmc_a_clk0 = {
|
||||
.reg = (void *)HHI_SD_EMMC_CLK_CNTL,
|
||||
.bit_idx = 7,
|
||||
.lock = &clk_lock,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "sd_emmc_a_clk0",
|
||||
.ops = &clk_gate_ops,
|
||||
.parent_names = (const char *[]){ "sd_emmc_a_clk0_div" },
|
||||
.num_parents = 1,
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* We need CLK_IGNORE_UNUSED because mmc DT node point to xtal
|
||||
* instead of this clock. CCF would gate this on boot, killing
|
||||
* the mmc controller. Please remove this flag once DT properly
|
||||
* point to this clock instead of xtal
|
||||
*
|
||||
* Same goes for emmc B and C clocks
|
||||
*/
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
/* SDcard clock */
|
||||
static struct clk_mux gxbb_sd_emmc_b_clk0_sel = {
|
||||
.reg = (void *)HHI_SD_EMMC_CLK_CNTL,
|
||||
.mask = 0x7,
|
||||
.shift = 25,
|
||||
.lock = &clk_lock,
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "sd_emmc_b_clk0_sel",
|
||||
.ops = &clk_mux_ops,
|
||||
.parent_names = gxbb_sd_emmc_clk0_parent_names,
|
||||
.num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_divider gxbb_sd_emmc_b_clk0_div = {
|
||||
.reg = (void *)HHI_SD_EMMC_CLK_CNTL,
|
||||
.shift = 16,
|
||||
.width = 7,
|
||||
.lock = &clk_lock,
|
||||
.flags = CLK_DIVIDER_ROUND_CLOSEST,
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "sd_emmc_b_clk0_div",
|
||||
.ops = &clk_divider_ops,
|
||||
.parent_names = (const char *[]){ "sd_emmc_b_clk0_sel" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gate gxbb_sd_emmc_b_clk0 = {
|
||||
.reg = (void *)HHI_SD_EMMC_CLK_CNTL,
|
||||
.bit_idx = 23,
|
||||
.lock = &clk_lock,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "sd_emmc_b_clk0",
|
||||
.ops = &clk_gate_ops,
|
||||
.parent_names = (const char *[]){ "sd_emmc_b_clk0_div" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
/* EMMC/NAND clock */
|
||||
static struct clk_mux gxbb_sd_emmc_c_clk0_sel = {
|
||||
.reg = (void *)HHI_NAND_CLK_CNTL,
|
||||
.mask = 0x7,
|
||||
.shift = 9,
|
||||
.lock = &clk_lock,
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "sd_emmc_c_clk0_sel",
|
||||
.ops = &clk_mux_ops,
|
||||
.parent_names = gxbb_sd_emmc_clk0_parent_names,
|
||||
.num_parents = ARRAY_SIZE(gxbb_sd_emmc_clk0_parent_names),
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_divider gxbb_sd_emmc_c_clk0_div = {
|
||||
.reg = (void *)HHI_NAND_CLK_CNTL,
|
||||
.shift = 0,
|
||||
.width = 7,
|
||||
.lock = &clk_lock,
|
||||
.flags = CLK_DIVIDER_ROUND_CLOSEST,
|
||||
.hw.init = &(struct clk_init_data) {
|
||||
.name = "sd_emmc_c_clk0_div",
|
||||
.ops = &clk_divider_ops,
|
||||
.parent_names = (const char *[]){ "sd_emmc_c_clk0_sel" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_gate gxbb_sd_emmc_c_clk0 = {
|
||||
.reg = (void *)HHI_NAND_CLK_CNTL,
|
||||
.bit_idx = 7,
|
||||
.lock = &clk_lock,
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "sd_emmc_c_clk0",
|
||||
.ops = &clk_gate_ops,
|
||||
.parent_names = (const char *[]){ "sd_emmc_c_clk0_div" },
|
||||
.num_parents = 1,
|
||||
.flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
|
||||
},
|
||||
};
|
||||
|
||||
/* Everything Else (EE) domain gates */
|
||||
static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0);
|
||||
static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1);
|
||||
|
@ -1188,6 +1340,15 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = {
|
|||
[CLKID_32K_CLK] = &gxbb_32k_clk.hw,
|
||||
[CLKID_32K_CLK_SEL] = &gxbb_32k_clk_sel.hw,
|
||||
[CLKID_32K_CLK_DIV] = &gxbb_32k_clk_div.hw,
|
||||
[CLKID_SD_EMMC_A_CLK0_SEL] = &gxbb_sd_emmc_a_clk0_sel.hw,
|
||||
[CLKID_SD_EMMC_A_CLK0_DIV] = &gxbb_sd_emmc_a_clk0_div.hw,
|
||||
[CLKID_SD_EMMC_A_CLK0] = &gxbb_sd_emmc_a_clk0.hw,
|
||||
[CLKID_SD_EMMC_B_CLK0_SEL] = &gxbb_sd_emmc_b_clk0_sel.hw,
|
||||
[CLKID_SD_EMMC_B_CLK0_DIV] = &gxbb_sd_emmc_b_clk0_div.hw,
|
||||
[CLKID_SD_EMMC_B_CLK0] = &gxbb_sd_emmc_b_clk0.hw,
|
||||
[CLKID_SD_EMMC_C_CLK0_SEL] = &gxbb_sd_emmc_c_clk0_sel.hw,
|
||||
[CLKID_SD_EMMC_C_CLK0_DIV] = &gxbb_sd_emmc_c_clk0_div.hw,
|
||||
[CLKID_SD_EMMC_C_CLK0] = &gxbb_sd_emmc_c_clk0.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
|
@ -1311,6 +1472,15 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = {
|
|||
[CLKID_32K_CLK] = &gxbb_32k_clk.hw,
|
||||
[CLKID_32K_CLK_SEL] = &gxbb_32k_clk_sel.hw,
|
||||
[CLKID_32K_CLK_DIV] = &gxbb_32k_clk_div.hw,
|
||||
[CLKID_SD_EMMC_A_CLK0_SEL] = &gxbb_sd_emmc_a_clk0_sel.hw,
|
||||
[CLKID_SD_EMMC_A_CLK0_DIV] = &gxbb_sd_emmc_a_clk0_div.hw,
|
||||
[CLKID_SD_EMMC_A_CLK0] = &gxbb_sd_emmc_a_clk0.hw,
|
||||
[CLKID_SD_EMMC_B_CLK0_SEL] = &gxbb_sd_emmc_b_clk0_sel.hw,
|
||||
[CLKID_SD_EMMC_B_CLK0_DIV] = &gxbb_sd_emmc_b_clk0_div.hw,
|
||||
[CLKID_SD_EMMC_B_CLK0] = &gxbb_sd_emmc_b_clk0.hw,
|
||||
[CLKID_SD_EMMC_C_CLK0_SEL] = &gxbb_sd_emmc_c_clk0_sel.hw,
|
||||
[CLKID_SD_EMMC_C_CLK0_DIV] = &gxbb_sd_emmc_c_clk0_div.hw,
|
||||
[CLKID_SD_EMMC_C_CLK0] = &gxbb_sd_emmc_c_clk0.hw,
|
||||
[NR_CLKS] = NULL,
|
||||
},
|
||||
.num = NR_CLKS,
|
||||
|
@ -1427,6 +1597,9 @@ static struct clk_gate *const gxbb_clk_gates[] = {
|
|||
&gxbb_cts_amclk,
|
||||
&gxbb_cts_mclk_i958,
|
||||
&gxbb_32k_clk,
|
||||
&gxbb_sd_emmc_a_clk0,
|
||||
&gxbb_sd_emmc_b_clk0,
|
||||
&gxbb_sd_emmc_c_clk0,
|
||||
};
|
||||
|
||||
static struct clk_mux *const gxbb_clk_muxes[] = {
|
||||
|
@ -1439,6 +1612,9 @@ static struct clk_mux *const gxbb_clk_muxes[] = {
|
|||
&gxbb_cts_mclk_i958_sel,
|
||||
&gxbb_cts_i958,
|
||||
&gxbb_32k_clk_sel,
|
||||
&gxbb_sd_emmc_a_clk0_sel,
|
||||
&gxbb_sd_emmc_b_clk0_sel,
|
||||
&gxbb_sd_emmc_c_clk0_sel,
|
||||
};
|
||||
|
||||
static struct clk_divider *const gxbb_clk_dividers[] = {
|
||||
|
@ -1448,6 +1624,9 @@ static struct clk_divider *const gxbb_clk_dividers[] = {
|
|||
&gxbb_mali_1_div,
|
||||
&gxbb_cts_mclk_i958_div,
|
||||
&gxbb_32k_clk_div,
|
||||
&gxbb_sd_emmc_a_clk0_div,
|
||||
&gxbb_sd_emmc_b_clk0_div,
|
||||
&gxbb_sd_emmc_c_clk0_div,
|
||||
};
|
||||
|
||||
static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = {
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "clkc.h"
|
||||
|
@ -32,6 +34,13 @@
|
|||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
static void __iomem *clk_base;
|
||||
|
||||
struct meson8b_clk_reset {
|
||||
struct reset_controller_dev reset;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
static const struct pll_rate_table sys_pll_rate_table[] = {
|
||||
PLL_RATE(312000000, 52, 1, 2),
|
||||
PLL_RATE(336000000, 56, 1, 2),
|
||||
|
@ -696,20 +705,114 @@ static struct clk_divider *const meson8b_clk_dividers[] = {
|
|||
&meson8b_mpeg_clk_div,
|
||||
};
|
||||
|
||||
static const struct meson8b_clk_reset_line {
|
||||
u32 reg;
|
||||
u8 bit_idx;
|
||||
} meson8b_clk_reset_bits[] = {
|
||||
[CLKC_RESET_L2_CACHE_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 30
|
||||
},
|
||||
[CLKC_RESET_AXI_64_TO_128_BRIDGE_A5_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 29
|
||||
},
|
||||
[CLKC_RESET_SCU_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 28
|
||||
},
|
||||
[CLKC_RESET_CPU3_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 27
|
||||
},
|
||||
[CLKC_RESET_CPU2_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 26
|
||||
},
|
||||
[CLKC_RESET_CPU1_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 25
|
||||
},
|
||||
[CLKC_RESET_CPU0_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 24
|
||||
},
|
||||
[CLKC_RESET_A5_GLOBAL_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 18
|
||||
},
|
||||
[CLKC_RESET_A5_AXI_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 17
|
||||
},
|
||||
[CLKC_RESET_A5_ABP_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL0, .bit_idx = 16
|
||||
},
|
||||
[CLKC_RESET_AXI_64_TO_128_BRIDGE_MMC_SOFT_RESET] = {
|
||||
.reg = HHI_SYS_CPU_CLK_CNTL1, .bit_idx = 30
|
||||
},
|
||||
[CLKC_RESET_VID_CLK_CNTL_SOFT_RESET] = {
|
||||
.reg = HHI_VID_CLK_CNTL, .bit_idx = 15
|
||||
},
|
||||
[CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_POST] = {
|
||||
.reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 7
|
||||
},
|
||||
[CLKC_RESET_VID_DIVIDER_CNTL_SOFT_RESET_PRE] = {
|
||||
.reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 3
|
||||
},
|
||||
[CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_POST] = {
|
||||
.reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 1
|
||||
},
|
||||
[CLKC_RESET_VID_DIVIDER_CNTL_RESET_N_PRE] = {
|
||||
.reg = HHI_VID_DIVIDER_CNTL, .bit_idx = 0
|
||||
},
|
||||
};
|
||||
|
||||
static int meson8b_clk_reset_update(struct reset_controller_dev *rcdev,
|
||||
unsigned long id, bool assert)
|
||||
{
|
||||
struct meson8b_clk_reset *meson8b_clk_reset =
|
||||
container_of(rcdev, struct meson8b_clk_reset, reset);
|
||||
unsigned long flags;
|
||||
const struct meson8b_clk_reset_line *reset;
|
||||
u32 val;
|
||||
|
||||
if (id >= ARRAY_SIZE(meson8b_clk_reset_bits))
|
||||
return -EINVAL;
|
||||
|
||||
reset = &meson8b_clk_reset_bits[id];
|
||||
|
||||
spin_lock_irqsave(&clk_lock, flags);
|
||||
|
||||
val = readl(meson8b_clk_reset->base + reset->reg);
|
||||
if (assert)
|
||||
val |= BIT(reset->bit_idx);
|
||||
else
|
||||
val &= ~BIT(reset->bit_idx);
|
||||
writel(val, meson8b_clk_reset->base + reset->reg);
|
||||
|
||||
spin_unlock_irqrestore(&clk_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson8b_clk_reset_assert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return meson8b_clk_reset_update(rcdev, id, true);
|
||||
}
|
||||
|
||||
static int meson8b_clk_reset_deassert(struct reset_controller_dev *rcdev,
|
||||
unsigned long id)
|
||||
{
|
||||
return meson8b_clk_reset_update(rcdev, id, false);
|
||||
}
|
||||
|
||||
static const struct reset_control_ops meson8b_clk_reset_ops = {
|
||||
.assert = meson8b_clk_reset_assert,
|
||||
.deassert = meson8b_clk_reset_deassert,
|
||||
};
|
||||
|
||||
static int meson8b_clkc_probe(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *clk_base;
|
||||
int ret, clkid, i;
|
||||
struct clk_hw *parent_hw;
|
||||
struct clk *parent_clk;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
/* Generic clocks and PLLs */
|
||||
clk_base = of_iomap(dev->of_node, 1);
|
||||
if (!clk_base) {
|
||||
pr_err("%s: Unable to map clk base\n", __func__);
|
||||
if (!clk_base)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* Populate base address for PLLs */
|
||||
for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++)
|
||||
|
@ -749,7 +852,7 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
|
|||
/* FIXME convert to devm_clk_register */
|
||||
ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]);
|
||||
if (ret)
|
||||
goto iounmap;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -772,15 +875,11 @@ static int meson8b_clkc_probe(struct platform_device *pdev)
|
|||
if (ret) {
|
||||
pr_err("%s: failed to register clock notifier for cpu_clk\n",
|
||||
__func__);
|
||||
goto iounmap;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
|
||||
&meson8b_hw_onecell_data);
|
||||
|
||||
iounmap:
|
||||
iounmap(clk_base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id meson8b_clkc_match_table[] = {
|
||||
|
@ -799,3 +898,39 @@ static struct platform_driver meson8b_driver = {
|
|||
};
|
||||
|
||||
builtin_platform_driver(meson8b_driver);
|
||||
|
||||
static void __init meson8b_clkc_reset_init(struct device_node *np)
|
||||
{
|
||||
struct meson8b_clk_reset *rstc;
|
||||
int ret;
|
||||
|
||||
/* Generic clocks, PLLs and some of the reset-bits */
|
||||
clk_base = of_iomap(np, 1);
|
||||
if (!clk_base) {
|
||||
pr_err("%s: Unable to map clk base\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
|
||||
if (!rstc)
|
||||
return;
|
||||
|
||||
/* Reset Controller */
|
||||
rstc->base = clk_base;
|
||||
rstc->reset.ops = &meson8b_clk_reset_ops;
|
||||
rstc->reset.nr_resets = ARRAY_SIZE(meson8b_clk_reset_bits);
|
||||
rstc->reset.of_node = np;
|
||||
ret = reset_controller_register(&rstc->reset);
|
||||
if (ret) {
|
||||
pr_err("%s: Failed to register clkc reset controller: %d\n",
|
||||
__func__, ret);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE_DRIVER(meson8_clkc, "amlogic,meson8-clkc",
|
||||
meson8b_clkc_reset_init);
|
||||
CLK_OF_DECLARE_DRIVER(meson8b_clkc, "amlogic,meson8b-clkc",
|
||||
meson8b_clkc_reset_init);
|
||||
CLK_OF_DECLARE_DRIVER(meson8m2_clkc, "amlogic,meson8m2-clkc",
|
||||
meson8b_clkc_reset_init);
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
#define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */
|
||||
#define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */
|
||||
#define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */
|
||||
#define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */
|
||||
#define HHI_VID_DIVIDER_CNTL 0x198 /* 0x66 offset in data sheet */
|
||||
#define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */
|
||||
#define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */
|
||||
#define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */
|
||||
#define HHI_VID_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */
|
||||
|
@ -68,7 +71,11 @@
|
|||
|
||||
#define CLK_NR_CLKS 96
|
||||
|
||||
/* include the CLKIDs that have been made part of the stable DT binding */
|
||||
/*
|
||||
* include the CLKID and RESETID that have
|
||||
* been made part of the stable DT binding
|
||||
*/
|
||||
#include <dt-bindings/clock/meson8b-clkc.h>
|
||||
#include <dt-bindings/reset/amlogic,meson8b-clkc-reset.h>
|
||||
|
||||
#endif /* __MESON8B_H */
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
void mmp_clk_init(struct device_node *np, struct mmp_clk_unit *unit,
|
||||
int nr_clks)
|
||||
{
|
||||
static struct clk **clk_table;
|
||||
struct clk **clk_table;
|
||||
|
||||
clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
|
||||
if (!clk_table)
|
||||
|
|
|
@ -885,7 +885,7 @@ static const struct clk_ops clk_usb_i2c_ops = {
|
|||
.recalc_rate = clk_usb_i2c_recalc_rate,
|
||||
};
|
||||
|
||||
static int clk_gate_enable(struct clk_hw *hw)
|
||||
static int lpc32xx_clk_gate_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
|
||||
u32 mask = BIT(clk->bit_idx);
|
||||
|
@ -894,7 +894,7 @@ static int clk_gate_enable(struct clk_hw *hw)
|
|||
return regmap_update_bits(clk_regmap, clk->reg, mask, val);
|
||||
}
|
||||
|
||||
static void clk_gate_disable(struct clk_hw *hw)
|
||||
static void lpc32xx_clk_gate_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
|
||||
u32 mask = BIT(clk->bit_idx);
|
||||
|
@ -903,7 +903,7 @@ static void clk_gate_disable(struct clk_hw *hw)
|
|||
regmap_update_bits(clk_regmap, clk->reg, mask, val);
|
||||
}
|
||||
|
||||
static int clk_gate_is_enabled(struct clk_hw *hw)
|
||||
static int lpc32xx_clk_gate_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct lpc32xx_clk_gate *clk = to_lpc32xx_gate(hw);
|
||||
u32 val;
|
||||
|
@ -916,9 +916,9 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
|
|||
}
|
||||
|
||||
static const struct clk_ops lpc32xx_clk_gate_ops = {
|
||||
.enable = clk_gate_enable,
|
||||
.disable = clk_gate_disable,
|
||||
.is_enabled = clk_gate_is_enabled,
|
||||
.enable = lpc32xx_clk_gate_enable,
|
||||
.disable = lpc32xx_clk_gate_disable,
|
||||
.is_enabled = lpc32xx_clk_gate_is_enabled,
|
||||
};
|
||||
|
||||
#define div_mask(width) ((1 << (width)) - 1)
|
||||
|
|
|
@ -412,8 +412,6 @@ static const struct clk_ops clk_smd_rpm_ops = {
|
|||
static const struct clk_ops clk_smd_rpm_branch_ops = {
|
||||
.prepare = clk_smd_rpm_prepare,
|
||||
.unprepare = clk_smd_rpm_unprepare,
|
||||
.round_rate = clk_smd_rpm_round_rate,
|
||||
.recalc_rate = clk_smd_rpm_recalc_rate,
|
||||
};
|
||||
|
||||
/* msm8916 */
|
||||
|
|
|
@ -1176,7 +1176,7 @@ static struct clk_rcg2 bimc_gpu_clk_src = {
|
|||
.parent_names = gcc_xo_gpll0_bimc,
|
||||
.num_parents = 3,
|
||||
.flags = CLK_GET_RATE_NOCACHE,
|
||||
.ops = &clk_rcg2_shared_ops,
|
||||
.ops = &clk_rcg2_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -2730,6 +2730,32 @@ static struct clk_fixed_factor ufs_rx_cfg_clk_src = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_hlos1_vote_lpass_core_smmu_clk = {
|
||||
.halt_reg = 0x7d010,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.clkr = {
|
||||
.enable_reg = 0x7d010,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "hlos1_vote_lpass_core_smmu_clk",
|
||||
.ops = &clk_branch2_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_hlos1_vote_lpass_adsp_smmu_clk = {
|
||||
.halt_reg = 0x7d014,
|
||||
.halt_check = BRANCH_HALT_VOTED,
|
||||
.clkr = {
|
||||
.enable_reg = 0x7d014,
|
||||
.enable_mask = BIT(0),
|
||||
.hw.init = &(struct clk_init_data){
|
||||
.name = "hlos1_vote_lpass_adsp_smmu_clk",
|
||||
.ops = &clk_branch2_ops,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_branch gcc_ufs_rx_cfg_clk = {
|
||||
.halt_reg = 0x75014,
|
||||
.clkr = {
|
||||
|
@ -3307,6 +3333,8 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
|
|||
[GCC_UFS_AHB_CLK] = &gcc_ufs_ahb_clk.clkr,
|
||||
[GCC_UFS_TX_CFG_CLK] = &gcc_ufs_tx_cfg_clk.clkr,
|
||||
[GCC_UFS_RX_CFG_CLK] = &gcc_ufs_rx_cfg_clk.clkr,
|
||||
[GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK] = &gcc_hlos1_vote_lpass_core_smmu_clk.clkr,
|
||||
[GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK] = &gcc_hlos1_vote_lpass_adsp_smmu_clk.clkr,
|
||||
[GCC_UFS_TX_SYMBOL_0_CLK] = &gcc_ufs_tx_symbol_0_clk.clkr,
|
||||
[GCC_UFS_RX_SYMBOL_0_CLK] = &gcc_ufs_rx_symbol_0_clk.clkr,
|
||||
[GCC_UFS_RX_SYMBOL_1_CLK] = &gcc_ufs_rx_symbol_1_clk.clkr,
|
||||
|
|
|
@ -15,6 +15,7 @@ config CLK_RENESAS
|
|||
select CLK_R8A7794 if ARCH_R8A7794
|
||||
select CLK_R8A7795 if ARCH_R8A7795
|
||||
select CLK_R8A7796 if ARCH_R8A7796
|
||||
select CLK_R8A77995 if ARCH_R8A77995
|
||||
select CLK_SH73A0 if ARCH_SH73A0
|
||||
|
||||
if CLK_RENESAS
|
||||
|
@ -34,94 +35,103 @@ config CLK_EMEV2
|
|||
bool "Emma Mobile EV2 clock support" if COMPILE_TEST
|
||||
|
||||
config CLK_RZA1
|
||||
bool
|
||||
bool "RZ/A1H clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSTP
|
||||
|
||||
config CLK_R8A73A4
|
||||
bool
|
||||
bool "R-Mobile APE6 clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSTP
|
||||
select CLK_RENESAS_DIV6
|
||||
|
||||
config CLK_R8A7740
|
||||
bool
|
||||
bool "R-Mobile A1 clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSTP
|
||||
select CLK_RENESAS_DIV6
|
||||
|
||||
config CLK_R8A7743
|
||||
bool
|
||||
bool "RZ/G1M clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN2_CPG
|
||||
|
||||
config CLK_R8A7745
|
||||
bool
|
||||
bool "RZ/G1E clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN2_CPG
|
||||
|
||||
config CLK_R8A7778
|
||||
bool
|
||||
bool "R-Car M1A clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSTP
|
||||
|
||||
config CLK_R8A7779
|
||||
bool
|
||||
bool "R-Car H1 clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSTP
|
||||
|
||||
config CLK_R8A7790
|
||||
bool
|
||||
bool "R-Car H2 clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY
|
||||
select CLK_RCAR_GEN2_CPG
|
||||
select CLK_RENESAS_DIV6
|
||||
|
||||
config CLK_R8A7791
|
||||
bool
|
||||
bool "R-Car M2-W/N clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY
|
||||
select CLK_RCAR_GEN2_CPG
|
||||
select CLK_RENESAS_DIV6
|
||||
|
||||
config CLK_R8A7792
|
||||
bool
|
||||
bool "R-Car V2H clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY
|
||||
select CLK_RCAR_GEN2_CPG
|
||||
|
||||
config CLK_R8A7794
|
||||
bool
|
||||
bool "R-Car E2 clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN2 if CLK_RENESAS_LEGACY
|
||||
select CLK_RCAR_GEN2_CPG
|
||||
select CLK_RENESAS_DIV6
|
||||
|
||||
config CLK_R8A7795
|
||||
bool
|
||||
bool "R-Car H3 clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN3_CPG
|
||||
|
||||
config CLK_R8A7796
|
||||
bool
|
||||
bool "R-Car M3-W clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN3_CPG
|
||||
|
||||
config CLK_R8A77995
|
||||
bool "R-Car D3 clock support" if COMPILE_TEST
|
||||
select CLK_RCAR_GEN3_CPG
|
||||
|
||||
config CLK_SH73A0
|
||||
bool
|
||||
bool "SH-Mobile AG5 clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSTP
|
||||
select CLK_RENESAS_DIV6
|
||||
|
||||
|
||||
# Family
|
||||
config CLK_RCAR_GEN2
|
||||
bool
|
||||
bool "R-Car Gen2 legacy clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSTP
|
||||
select CLK_RENESAS_DIV6
|
||||
|
||||
config CLK_RCAR_GEN2_CPG
|
||||
bool
|
||||
bool "R-Car Gen2 CPG clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSSR
|
||||
|
||||
config CLK_RCAR_GEN3_CPG
|
||||
bool
|
||||
bool "R-Car Gen3 CPG clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_CPG_MSSR
|
||||
|
||||
config CLK_RCAR_USB2_CLOCK_SEL
|
||||
bool "Renesas R-Car USB2 clock selector support"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
help
|
||||
This is a driver for R-Car USB2 clock selector
|
||||
|
||||
# Generic
|
||||
config CLK_RENESAS_CPG_MSSR
|
||||
bool
|
||||
bool "CPG/MSSR clock support" if COMPILE_TEST
|
||||
select CLK_RENESAS_DIV6
|
||||
|
||||
config CLK_RENESAS_CPG_MSTP
|
||||
bool
|
||||
bool "MSTP clock support" if COMPILE_TEST
|
||||
|
||||
config CLK_RENESAS_DIV6
|
||||
bool "DIV6 clock support" if COMPILE_TEST
|
||||
|
|
|
@ -13,12 +13,14 @@ obj-$(CONFIG_CLK_R8A7792) += r8a7792-cpg-mssr.o
|
|||
obj-$(CONFIG_CLK_R8A7794) += r8a7794-cpg-mssr.o
|
||||
obj-$(CONFIG_CLK_R8A7795) += r8a7795-cpg-mssr.o
|
||||
obj-$(CONFIG_CLK_R8A7796) += r8a7796-cpg-mssr.o
|
||||
obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o
|
||||
obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o
|
||||
|
||||
# Family
|
||||
obj-$(CONFIG_CLK_RCAR_GEN2) += clk-rcar-gen2.o
|
||||
obj-$(CONFIG_CLK_RCAR_GEN2_CPG) += rcar-gen2-cpg.o
|
||||
obj-$(CONFIG_CLK_RCAR_GEN3_CPG) += rcar-gen3-cpg.o
|
||||
obj-$(CONFIG_CLK_RCAR_USB2_CLOCK_SEL) += rcar-usb2-clock-sel.o
|
||||
|
||||
# Generic
|
||||
obj-$(CONFIG_CLK_RENESAS_CPG_MSSR) += renesas-cpg-mssr.o
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
* @hw: handle between common and hardware-specific interfaces
|
||||
* @reg: IO-remapped register
|
||||
* @div: divisor value (1-64)
|
||||
* @src_shift: Shift to access the register bits to select the parent clock
|
||||
* @src_width: Number of register bits to select the parent clock (may be 0)
|
||||
* @parents: Array to map from valid parent clocks indices to hardware indices
|
||||
*/
|
||||
struct div6_clock {
|
||||
struct clk_hw hw;
|
||||
|
|
|
@ -335,7 +335,7 @@ void __init cpg_mstp_add_clk_domain(struct device_node *np)
|
|||
u32 ncells;
|
||||
|
||||
if (of_property_read_u32(np, "#power-domain-cells", &ncells)) {
|
||||
pr_warn("%s lacks #power-domain-cells\n", np->full_name);
|
||||
pr_warn("%pOF lacks #power-domain-cells\n", np);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -407,8 +407,7 @@ static void __init rcar_gen2_cpg_clocks_init(struct device_node *np)
|
|||
|
||||
if (rcar_rst_read_mode_pins(&cpg_mode)) {
|
||||
/* Backward-compatibility with old DT */
|
||||
pr_warn("%s: failed to obtain mode pins from RST\n",
|
||||
np->full_name);
|
||||
pr_warn("%pOF: failed to obtain mode pins from RST\n", np);
|
||||
cpg_mode = rcar_gen2_read_mode_pins();
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,13 @@ static const struct mssr_mod_clk r8a7792_mod_clks[] __initconst = {
|
|||
DEF_MOD("vin1", 810, R8A7792_CLK_ZG),
|
||||
DEF_MOD("vin0", 811, R8A7792_CLK_ZG),
|
||||
DEF_MOD("etheravb", 812, R8A7792_CLK_HP),
|
||||
DEF_MOD("imr-lx3", 821, R8A7792_CLK_ZG),
|
||||
DEF_MOD("imr-lsx3-1", 822, R8A7792_CLK_ZG),
|
||||
DEF_MOD("imr-lsx3-0", 823, R8A7792_CLK_ZG),
|
||||
DEF_MOD("imr-lsx3-5", 825, R8A7792_CLK_ZG),
|
||||
DEF_MOD("imr-lsx3-4", 826, R8A7792_CLK_ZG),
|
||||
DEF_MOD("imr-lsx3-3", 827, R8A7792_CLK_ZG),
|
||||
DEF_MOD("imr-lsx3-2", 828, R8A7792_CLK_ZG),
|
||||
DEF_MOD("gyro-adc", 901, R8A7792_CLK_P),
|
||||
DEF_MOD("gpio7", 904, R8A7792_CLK_CP),
|
||||
DEF_MOD("gpio6", 905, R8A7792_CLK_CP),
|
||||
|
|
|
@ -305,23 +305,23 @@ static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
|
|||
(((md) & BIT(17)) >> 17))
|
||||
|
||||
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
|
||||
/* EXTAL div PLL1 mult PLL3 mult */
|
||||
{ 1, 192, 192, },
|
||||
{ 1, 192, 128, },
|
||||
/* EXTAL div PLL1 mult/div PLL3 mult/div */
|
||||
{ 1, 192, 1, 192, 1, },
|
||||
{ 1, 192, 1, 128, 1, },
|
||||
{ 0, /* Prohibited setting */ },
|
||||
{ 1, 192, 192, },
|
||||
{ 1, 160, 160, },
|
||||
{ 1, 160, 106, },
|
||||
{ 1, 192, 1, 192, 1, },
|
||||
{ 1, 160, 1, 160, 1, },
|
||||
{ 1, 160, 1, 106, 1, },
|
||||
{ 0, /* Prohibited setting */ },
|
||||
{ 1, 160, 160, },
|
||||
{ 1, 128, 128, },
|
||||
{ 1, 128, 84, },
|
||||
{ 1, 160, 1, 160, 1, },
|
||||
{ 1, 128, 1, 128, 1, },
|
||||
{ 1, 128, 1, 84, 1, },
|
||||
{ 0, /* Prohibited setting */ },
|
||||
{ 1, 128, 128, },
|
||||
{ 2, 192, 192, },
|
||||
{ 2, 192, 128, },
|
||||
{ 1, 128, 1, 128, 1, },
|
||||
{ 2, 192, 1, 192, 1, },
|
||||
{ 2, 192, 1, 128, 1, },
|
||||
{ 0, /* Prohibited setting */ },
|
||||
{ 2, 192, 192, },
|
||||
{ 2, 192, 1, 192, 1, },
|
||||
};
|
||||
|
||||
static const struct soc_device_attribute r8a7795es1[] __initconst = {
|
||||
|
|
|
@ -138,6 +138,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = {
|
|||
DEF_MOD("sdif0", 314, R8A7796_CLK_SD0),
|
||||
DEF_MOD("pcie1", 318, R8A7796_CLK_S3D1),
|
||||
DEF_MOD("pcie0", 319, R8A7796_CLK_S3D1),
|
||||
DEF_MOD("usb3-if0", 328, R8A7796_CLK_S3D1),
|
||||
DEF_MOD("usb-dmac0", 330, R8A7796_CLK_S3D1),
|
||||
DEF_MOD("usb-dmac1", 331, R8A7796_CLK_S3D1),
|
||||
DEF_MOD("rwdt", 402, R8A7796_CLK_R),
|
||||
|
@ -277,23 +278,23 @@ static const unsigned int r8a7796_crit_mod_clks[] __initconst = {
|
|||
(((md) & BIT(17)) >> 17))
|
||||
|
||||
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[16] __initconst = {
|
||||
/* EXTAL div PLL1 mult PLL3 mult */
|
||||
{ 1, 192, 192, },
|
||||
{ 1, 192, 128, },
|
||||
/* EXTAL div PLL1 mult/div PLL3 mult/div */
|
||||
{ 1, 192, 1, 192, 1, },
|
||||
{ 1, 192, 1, 128, 1, },
|
||||
{ 0, /* Prohibited setting */ },
|
||||
{ 1, 192, 192, },
|
||||
{ 1, 160, 160, },
|
||||
{ 1, 160, 106, },
|
||||
{ 1, 192, 1, 192, 1, },
|
||||
{ 1, 160, 1, 160, 1, },
|
||||
{ 1, 160, 1, 106, 1, },
|
||||
{ 0, /* Prohibited setting */ },
|
||||
{ 1, 160, 160, },
|
||||
{ 1, 128, 128, },
|
||||
{ 1, 128, 84, },
|
||||
{ 1, 160, 1, 160, 1, },
|
||||
{ 1, 128, 1, 128, 1, },
|
||||
{ 1, 128, 1, 84, 1, },
|
||||
{ 0, /* Prohibited setting */ },
|
||||
{ 1, 128, 128, },
|
||||
{ 2, 192, 192, },
|
||||
{ 2, 192, 128, },
|
||||
{ 1, 128, 1, 128, 1, },
|
||||
{ 2, 192, 1, 192, 1, },
|
||||
{ 2, 192, 1, 128, 1, },
|
||||
{ 0, /* Prohibited setting */ },
|
||||
{ 2, 192, 192, },
|
||||
{ 2, 192, 1, 192, 1, },
|
||||
};
|
||||
|
||||
static int __init r8a7796_cpg_mssr_init(struct device *dev)
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* r8a77995 Clock Pulse Generator / Module Standby and Software Reset
|
||||
*
|
||||
* Copyright (C) 2017 Glider bvba
|
||||
*
|
||||
* Based on r8a7795-cpg-mssr.c
|
||||
*
|
||||
* Copyright (C) 2015 Glider bvba
|
||||
* Copyright (C) 2015 Renesas Electronics Corp.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/soc/renesas/rcar-rst.h>
|
||||
|
||||
#include <dt-bindings/clock/r8a77995-cpg-mssr.h>
|
||||
|
||||
#include "renesas-cpg-mssr.h"
|
||||
#include "rcar-gen3-cpg.h"
|
||||
|
||||
enum clk_ids {
|
||||
/* Core Clock Outputs exported to DT */
|
||||
LAST_DT_CORE_CLK = R8A77995_CLK_CP,
|
||||
|
||||
/* External Input Clocks */
|
||||
CLK_EXTAL,
|
||||
|
||||
/* Internal Core Clocks */
|
||||
CLK_MAIN,
|
||||
CLK_PLL0,
|
||||
CLK_PLL1,
|
||||
CLK_PLL3,
|
||||
CLK_PLL0D2,
|
||||
CLK_PLL0D3,
|
||||
CLK_PLL0D5,
|
||||
CLK_PLL1D2,
|
||||
CLK_PE,
|
||||
CLK_S0,
|
||||
CLK_S1,
|
||||
CLK_S2,
|
||||
CLK_S3,
|
||||
CLK_SDSRC,
|
||||
CLK_SSPSRC,
|
||||
|
||||
/* Module Clocks */
|
||||
MOD_CLK_BASE
|
||||
};
|
||||
|
||||
static const struct cpg_core_clk r8a77995_core_clks[] __initconst = {
|
||||
/* External Clock Inputs */
|
||||
DEF_INPUT("extal", CLK_EXTAL),
|
||||
|
||||
/* Internal Core Clocks */
|
||||
DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
|
||||
DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
|
||||
DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
|
||||
|
||||
DEF_FIXED(".pll0", CLK_PLL0, CLK_MAIN, 4, 250),
|
||||
DEF_FIXED(".pll0d2", CLK_PLL0D2, CLK_PLL0, 2, 1),
|
||||
DEF_FIXED(".pll0d3", CLK_PLL0D3, CLK_PLL0, 3, 1),
|
||||
DEF_FIXED(".pll0d5", CLK_PLL0D5, CLK_PLL0, 5, 1),
|
||||
DEF_FIXED(".pll1d2", CLK_PLL1D2, CLK_PLL1, 2, 1),
|
||||
DEF_FIXED(".pe", CLK_PE, CLK_PLL0D3, 4, 1),
|
||||
DEF_FIXED(".s0", CLK_S0, CLK_PLL1, 2, 1),
|
||||
DEF_FIXED(".s1", CLK_S1, CLK_PLL1, 3, 1),
|
||||
DEF_FIXED(".s2", CLK_S2, CLK_PLL1, 4, 1),
|
||||
DEF_FIXED(".s3", CLK_S3, CLK_PLL1, 6, 1),
|
||||
DEF_FIXED(".sdsrc", CLK_SDSRC, CLK_PLL1, 2, 1),
|
||||
|
||||
/* Core Clock Outputs */
|
||||
DEF_FIXED("z2", R8A77995_CLK_Z2, CLK_PLL0D3, 1, 1),
|
||||
DEF_FIXED("ztr", R8A77995_CLK_ZTR, CLK_PLL1, 6, 1),
|
||||
DEF_FIXED("zt", R8A77995_CLK_ZT, CLK_PLL1, 4, 1),
|
||||
DEF_FIXED("zx", R8A77995_CLK_ZX, CLK_PLL1, 3, 1),
|
||||
DEF_FIXED("s0d1", R8A77995_CLK_S0D1, CLK_S0, 1, 1),
|
||||
DEF_FIXED("s1d1", R8A77995_CLK_S1D1, CLK_S1, 1, 1),
|
||||
DEF_FIXED("s1d2", R8A77995_CLK_S1D2, CLK_S1, 2, 1),
|
||||
DEF_FIXED("s1d4", R8A77995_CLK_S1D4, CLK_S1, 4, 1),
|
||||
DEF_FIXED("s2d1", R8A77995_CLK_S2D1, CLK_S2, 1, 1),
|
||||
DEF_FIXED("s2d2", R8A77995_CLK_S2D2, CLK_S2, 2, 1),
|
||||
DEF_FIXED("s2d4", R8A77995_CLK_S2D4, CLK_S2, 4, 1),
|
||||
DEF_FIXED("s3d1", R8A77995_CLK_S3D1, CLK_S3, 1, 1),
|
||||
DEF_FIXED("s3d2", R8A77995_CLK_S3D2, CLK_S3, 2, 1),
|
||||
DEF_FIXED("s3d4", R8A77995_CLK_S3D4, CLK_S3, 4, 1),
|
||||
|
||||
DEF_FIXED("cl", R8A77995_CLK_CL, CLK_PLL1, 48, 1),
|
||||
DEF_FIXED("cp", R8A77995_CLK_CP, CLK_EXTAL, 2, 1),
|
||||
DEF_FIXED("osc", R8A77995_CLK_OSC, CLK_EXTAL, 384, 1),
|
||||
DEF_FIXED("r", R8A77995_CLK_R, CLK_EXTAL, 1536, 1),
|
||||
|
||||
DEF_GEN3_PE("s1d4c", R8A77995_CLK_S1D4C, CLK_S1, 4, CLK_PE, 2),
|
||||
DEF_GEN3_PE("s3d1c", R8A77995_CLK_S3D1C, CLK_S3, 1, CLK_PE, 1),
|
||||
DEF_GEN3_PE("s3d2c", R8A77995_CLK_S3D2C, CLK_S3, 2, CLK_PE, 2),
|
||||
DEF_GEN3_PE("s3d4c", R8A77995_CLK_S3D4C, CLK_S3, 4, CLK_PE, 4),
|
||||
|
||||
DEF_GEN3_SD("sd0", R8A77995_CLK_SD0, CLK_SDSRC, 0x268),
|
||||
|
||||
DEF_DIV6P1("canfd", R8A77995_CLK_CANFD, CLK_PLL0D3, 0x244),
|
||||
DEF_DIV6P1("mso", R8A77995_CLK_MSO, CLK_PLL1D2, 0x014),
|
||||
};
|
||||
|
||||
static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = {
|
||||
DEF_MOD("scif5", 202, R8A77995_CLK_S3D4C),
|
||||
DEF_MOD("scif4", 203, R8A77995_CLK_S3D4C),
|
||||
DEF_MOD("scif3", 204, R8A77995_CLK_S3D4C),
|
||||
DEF_MOD("scif1", 206, R8A77995_CLK_S3D4C),
|
||||
DEF_MOD("scif0", 207, R8A77995_CLK_S3D4C),
|
||||
DEF_MOD("msiof3", 208, R8A77995_CLK_MSO),
|
||||
DEF_MOD("msiof2", 209, R8A77995_CLK_MSO),
|
||||
DEF_MOD("msiof1", 210, R8A77995_CLK_MSO),
|
||||
DEF_MOD("msiof0", 211, R8A77995_CLK_MSO),
|
||||
DEF_MOD("sys-dmac2", 217, R8A77995_CLK_S3D1),
|
||||
DEF_MOD("sys-dmac1", 218, R8A77995_CLK_S3D1),
|
||||
DEF_MOD("sys-dmac0", 219, R8A77995_CLK_S3D1),
|
||||
DEF_MOD("cmt3", 300, R8A77995_CLK_R),
|
||||
DEF_MOD("cmt2", 301, R8A77995_CLK_R),
|
||||
DEF_MOD("cmt1", 302, R8A77995_CLK_R),
|
||||
DEF_MOD("cmt0", 303, R8A77995_CLK_R),
|
||||
DEF_MOD("scif2", 310, R8A77995_CLK_S3D4C),
|
||||
DEF_MOD("emmc0", 312, R8A77995_CLK_SD0),
|
||||
DEF_MOD("usb-dmac0", 330, R8A77995_CLK_S3D1),
|
||||
DEF_MOD("usb-dmac1", 331, R8A77995_CLK_S3D1),
|
||||
DEF_MOD("rwdt", 402, R8A77995_CLK_R),
|
||||
DEF_MOD("intc-ex", 407, R8A77995_CLK_CP),
|
||||
DEF_MOD("intc-ap", 408, R8A77995_CLK_S3D1),
|
||||
DEF_MOD("audmac0", 502, R8A77995_CLK_S3D1),
|
||||
DEF_MOD("hscif3", 517, R8A77995_CLK_S3D1C),
|
||||
DEF_MOD("hscif0", 520, R8A77995_CLK_S3D1C),
|
||||
DEF_MOD("thermal", 522, R8A77995_CLK_CP),
|
||||
DEF_MOD("pwm", 523, R8A77995_CLK_S3D4C),
|
||||
DEF_MOD("fcpvd1", 602, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("fcpvd0", 603, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("fcpvbs", 607, R8A77995_CLK_S0D1),
|
||||
DEF_MOD("vspd1", 622, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("vspd0", 623, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("vspbs", 627, R8A77995_CLK_S0D1),
|
||||
DEF_MOD("ehci0", 703, R8A77995_CLK_S3D2),
|
||||
DEF_MOD("hsusb", 704, R8A77995_CLK_S3D2),
|
||||
DEF_MOD("du1", 723, R8A77995_CLK_S2D1),
|
||||
DEF_MOD("du0", 724, R8A77995_CLK_S2D1),
|
||||
DEF_MOD("lvds", 727, R8A77995_CLK_S2D1),
|
||||
DEF_MOD("vin7", 804, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("vin6", 805, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("vin5", 806, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("vin4", 807, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("etheravb", 812, R8A77995_CLK_S3D2),
|
||||
DEF_MOD("imr0", 823, R8A77995_CLK_S1D2),
|
||||
DEF_MOD("gpio6", 906, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("gpio5", 907, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("gpio4", 908, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("gpio3", 909, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("gpio2", 910, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("gpio1", 911, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("gpio0", 912, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("can-fd", 914, R8A77995_CLK_S3D2),
|
||||
DEF_MOD("can-if1", 915, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("can-if0", 916, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("i2c3", 928, R8A77995_CLK_S3D2),
|
||||
DEF_MOD("i2c2", 929, R8A77995_CLK_S3D2),
|
||||
DEF_MOD("i2c1", 930, R8A77995_CLK_S3D2),
|
||||
DEF_MOD("i2c0", 931, R8A77995_CLK_S3D2),
|
||||
DEF_MOD("ssi-all", 1005, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)),
|
||||
DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)),
|
||||
DEF_MOD("scu-all", 1017, R8A77995_CLK_S3D4),
|
||||
DEF_MOD("scu-dvc1", 1018, MOD_CLK_ID(1017)),
|
||||
DEF_MOD("scu-dvc0", 1019, MOD_CLK_ID(1017)),
|
||||
DEF_MOD("scu-ctu1-mix1", 1020, MOD_CLK_ID(1017)),
|
||||
DEF_MOD("scu-ctu0-mix0", 1021, MOD_CLK_ID(1017)),
|
||||
DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)),
|
||||
DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)),
|
||||
};
|
||||
|
||||
static const unsigned int r8a77995_crit_mod_clks[] __initconst = {
|
||||
MOD_CLK_ID(408), /* INTC-AP (GIC) */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* CPG Clock Data
|
||||
*/
|
||||
|
||||
/*
|
||||
* MD19 EXTAL (MHz) PLL0 PLL1 PLL3
|
||||
*--------------------------------------------------------------------
|
||||
* 0 48 x 1 x250/4 x100/3 x100/3
|
||||
* 1 48 x 1 x250/4 x100/3 x116/6
|
||||
*/
|
||||
#define CPG_PLL_CONFIG_INDEX(md) (((md) & BIT(19)) >> 19)
|
||||
|
||||
static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[2] __initconst = {
|
||||
/* EXTAL div PLL1 mult/div PLL3 mult/div */
|
||||
{ 1, 100, 3, 100, 3, },
|
||||
{ 1, 100, 3, 116, 6, },
|
||||
};
|
||||
|
||||
static int __init r8a77995_cpg_mssr_init(struct device *dev)
|
||||
{
|
||||
const struct rcar_gen3_cpg_pll_config *cpg_pll_config;
|
||||
u32 cpg_mode;
|
||||
int error;
|
||||
|
||||
error = rcar_rst_read_mode_pins(&cpg_mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
|
||||
|
||||
return rcar_gen3_cpg_init(cpg_pll_config, 0, cpg_mode);
|
||||
}
|
||||
|
||||
const struct cpg_mssr_info r8a77995_cpg_mssr_info __initconst = {
|
||||
/* Core Clocks */
|
||||
.core_clks = r8a77995_core_clks,
|
||||
.num_core_clks = ARRAY_SIZE(r8a77995_core_clks),
|
||||
.last_dt_core_clk = LAST_DT_CORE_CLK,
|
||||
.num_total_core_clks = MOD_CLK_BASE,
|
||||
|
||||
/* Module Clocks */
|
||||
.mod_clks = r8a77995_mod_clks,
|
||||
.num_mod_clks = ARRAY_SIZE(r8a77995_mod_clks),
|
||||
.num_hw_mod_clks = 12 * 32,
|
||||
|
||||
/* Critical Module Clocks */
|
||||
.crit_mod_clks = r8a77995_crit_mod_clks,
|
||||
.num_crit_mod_clks = ARRAY_SIZE(r8a77995_crit_mod_clks),
|
||||
|
||||
/* Callbacks */
|
||||
.init = r8a77995_cpg_mssr_init,
|
||||
.cpg_clk_register = rcar_gen3_cpg_clk_register,
|
||||
};
|
|
@ -60,6 +60,7 @@ struct sd_clock {
|
|||
unsigned int div_num;
|
||||
unsigned int div_min;
|
||||
unsigned int div_max;
|
||||
unsigned int cur_div_idx;
|
||||
};
|
||||
|
||||
/* SDn divider
|
||||
|
@ -96,21 +97,10 @@ static const struct sd_div_table cpg_sd_div_table[] = {
|
|||
static int cpg_sd_clock_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct sd_clock *clock = to_sd_clock(hw);
|
||||
u32 val, sd_fc;
|
||||
unsigned int i;
|
||||
|
||||
val = readl(clock->reg);
|
||||
|
||||
sd_fc = val & CPG_SD_FC_MASK;
|
||||
for (i = 0; i < clock->div_num; i++)
|
||||
if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
|
||||
break;
|
||||
|
||||
if (i >= clock->div_num)
|
||||
return -EINVAL;
|
||||
u32 val = readl(clock->reg);
|
||||
|
||||
val &= ~(CPG_SD_STP_MASK);
|
||||
val |= clock->div_table[i].val & CPG_SD_STP_MASK;
|
||||
val |= clock->div_table[clock->cur_div_idx].val & CPG_SD_STP_MASK;
|
||||
|
||||
writel(val, clock->reg);
|
||||
|
||||
|
@ -135,21 +125,9 @@ static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw,
|
|||
unsigned long parent_rate)
|
||||
{
|
||||
struct sd_clock *clock = to_sd_clock(hw);
|
||||
unsigned long rate = parent_rate;
|
||||
u32 val, sd_fc;
|
||||
unsigned int i;
|
||||
|
||||
val = readl(clock->reg);
|
||||
|
||||
sd_fc = val & CPG_SD_FC_MASK;
|
||||
for (i = 0; i < clock->div_num; i++)
|
||||
if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
|
||||
break;
|
||||
|
||||
if (i >= clock->div_num)
|
||||
return -EINVAL;
|
||||
|
||||
return DIV_ROUND_CLOSEST(rate, clock->div_table[i].div);
|
||||
return DIV_ROUND_CLOSEST(parent_rate,
|
||||
clock->div_table[clock->cur_div_idx].div);
|
||||
}
|
||||
|
||||
static unsigned int cpg_sd_clock_calc_div(struct sd_clock *clock,
|
||||
|
@ -190,6 +168,8 @@ static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
if (i >= clock->div_num)
|
||||
return -EINVAL;
|
||||
|
||||
clock->cur_div_idx = i;
|
||||
|
||||
val = readl(clock->reg);
|
||||
val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK);
|
||||
val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK);
|
||||
|
@ -215,6 +195,7 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core,
|
|||
struct sd_clock *clock;
|
||||
struct clk *clk;
|
||||
unsigned int i;
|
||||
u32 sd_fc;
|
||||
|
||||
clock = kzalloc(sizeof(*clock), GFP_KERNEL);
|
||||
if (!clock)
|
||||
|
@ -231,6 +212,18 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core,
|
|||
clock->div_table = cpg_sd_div_table;
|
||||
clock->div_num = ARRAY_SIZE(cpg_sd_div_table);
|
||||
|
||||
sd_fc = readl(clock->reg) & CPG_SD_FC_MASK;
|
||||
for (i = 0; i < clock->div_num; i++)
|
||||
if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK))
|
||||
break;
|
||||
|
||||
if (WARN_ON(i >= clock->div_num)) {
|
||||
kfree(clock);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
clock->cur_div_idx = i;
|
||||
|
||||
clock->div_max = clock->div_table[0].div;
|
||||
clock->div_min = clock->div_max;
|
||||
for (i = 1; i < clock->div_num; i++) {
|
||||
|
@ -279,7 +272,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
|
|||
unsigned int div = 1;
|
||||
u32 value;
|
||||
|
||||
parent = clks[core->parent];
|
||||
parent = clks[core->parent & 0xffff]; /* CLK_TYPE_PE uses high bits */
|
||||
if (IS_ERR(parent))
|
||||
return ERR_CAST(parent);
|
||||
|
||||
|
@ -303,6 +296,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
|
|||
|
||||
case CLK_TYPE_GEN3_PLL1:
|
||||
mult = cpg_pll_config->pll1_mult;
|
||||
div = cpg_pll_config->pll1_div;
|
||||
break;
|
||||
|
||||
case CLK_TYPE_GEN3_PLL2:
|
||||
|
@ -320,6 +314,7 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
|
|||
|
||||
case CLK_TYPE_GEN3_PLL3:
|
||||
mult = cpg_pll_config->pll3_mult;
|
||||
div = cpg_pll_config->pll3_div;
|
||||
break;
|
||||
|
||||
case CLK_TYPE_GEN3_PLL4:
|
||||
|
@ -360,6 +355,24 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
|
|||
parent = clks[cpg_clk_extalr];
|
||||
break;
|
||||
|
||||
case CLK_TYPE_GEN3_PE:
|
||||
/*
|
||||
* Peripheral clock with a fixed divider, selectable between
|
||||
* clean and spread spectrum parents using MD12
|
||||
*/
|
||||
if (cpg_mode & BIT(12)) {
|
||||
/* Clean */
|
||||
div = core->div & 0xffff;
|
||||
} else {
|
||||
/* SCCG */
|
||||
parent = clks[core->parent >> 16];
|
||||
if (IS_ERR(parent))
|
||||
return ERR_CAST(parent);
|
||||
div = core->div >> 16;
|
||||
}
|
||||
mult = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
|
|
@ -20,15 +20,24 @@ enum rcar_gen3_clk_types {
|
|||
CLK_TYPE_GEN3_PLL4,
|
||||
CLK_TYPE_GEN3_SD,
|
||||
CLK_TYPE_GEN3_R,
|
||||
CLK_TYPE_GEN3_PE,
|
||||
};
|
||||
|
||||
#define DEF_GEN3_SD(_name, _id, _parent, _offset) \
|
||||
DEF_BASE(_name, _id, CLK_TYPE_GEN3_SD, _parent, .offset = _offset)
|
||||
|
||||
#define DEF_GEN3_PE(_name, _id, _parent_sscg, _div_sscg, _parent_clean, \
|
||||
_div_clean) \
|
||||
DEF_BASE(_name, _id, CLK_TYPE_GEN3_PE, \
|
||||
(_parent_sscg) << 16 | (_parent_clean), \
|
||||
.div = (_div_sscg) << 16 | (_div_clean))
|
||||
|
||||
struct rcar_gen3_cpg_pll_config {
|
||||
unsigned int extal_div;
|
||||
unsigned int pll1_mult;
|
||||
unsigned int pll3_mult;
|
||||
u8 extal_div;
|
||||
u8 pll1_mult;
|
||||
u8 pll1_div;
|
||||
u8 pll3_mult;
|
||||
u8 pll3_div;
|
||||
};
|
||||
|
||||
#define CPG_RCKCR 0x240
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Renesas R-Car USB2.0 clock selector
|
||||
*
|
||||
* Copyright (C) 2017 Renesas Electronics Corp.
|
||||
*
|
||||
* Based on renesas-cpg-mssr.c
|
||||
*
|
||||
* Copyright (C) 2015 Glider bvba
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define USB20_CLKSET0 0x00
|
||||
#define CLKSET0_INTCLK_EN BIT(11)
|
||||
#define CLKSET0_PRIVATE BIT(0)
|
||||
#define CLKSET0_EXTAL_ONLY (CLKSET0_INTCLK_EN | CLKSET0_PRIVATE)
|
||||
|
||||
struct usb2_clock_sel_priv {
|
||||
void __iomem *base;
|
||||
struct clk_hw hw;
|
||||
bool extal;
|
||||
bool xtal;
|
||||
};
|
||||
#define to_priv(_hw) container_of(_hw, struct usb2_clock_sel_priv, hw)
|
||||
|
||||
static void usb2_clock_sel_enable_extal_only(struct usb2_clock_sel_priv *priv)
|
||||
{
|
||||
u16 val = readw(priv->base + USB20_CLKSET0);
|
||||
|
||||
pr_debug("%s: enter %d %d %x\n", __func__,
|
||||
priv->extal, priv->xtal, val);
|
||||
|
||||
if (priv->extal && !priv->xtal && val != CLKSET0_EXTAL_ONLY)
|
||||
writew(CLKSET0_EXTAL_ONLY, priv->base + USB20_CLKSET0);
|
||||
}
|
||||
|
||||
static void usb2_clock_sel_disable_extal_only(struct usb2_clock_sel_priv *priv)
|
||||
{
|
||||
if (priv->extal && !priv->xtal)
|
||||
writew(CLKSET0_PRIVATE, priv->base + USB20_CLKSET0);
|
||||
}
|
||||
|
||||
static int usb2_clock_sel_enable(struct clk_hw *hw)
|
||||
{
|
||||
usb2_clock_sel_enable_extal_only(to_priv(hw));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb2_clock_sel_disable(struct clk_hw *hw)
|
||||
{
|
||||
usb2_clock_sel_disable_extal_only(to_priv(hw));
|
||||
}
|
||||
|
||||
/*
|
||||
* This module seems a mux, but this driver assumes a gate because
|
||||
* ehci/ohci platform drivers don't support clk_set_parent() for now.
|
||||
* If this driver acts as a gate, ehci/ohci-platform drivers don't need
|
||||
* any modification.
|
||||
*/
|
||||
static const struct clk_ops usb2_clock_sel_clock_ops = {
|
||||
.enable = usb2_clock_sel_enable,
|
||||
.disable = usb2_clock_sel_disable,
|
||||
};
|
||||
|
||||
static const struct of_device_id rcar_usb2_clock_sel_match[] = {
|
||||
{ .compatible = "renesas,rcar-gen3-usb2-clock-sel" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int rcar_usb2_clock_sel_suspend(struct device *dev)
|
||||
{
|
||||
struct usb2_clock_sel_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
usb2_clock_sel_disable_extal_only(priv);
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_usb2_clock_sel_resume(struct device *dev)
|
||||
{
|
||||
struct usb2_clock_sel_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
pm_runtime_get_sync(dev);
|
||||
usb2_clock_sel_enable_extal_only(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_usb2_clock_sel_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct usb2_clock_sel_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
of_clk_del_provider(dev->of_node);
|
||||
clk_hw_unregister(&priv->hw);
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_usb2_clock_sel_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct usb2_clock_sel_priv *priv;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
clk = devm_clk_get(dev, "usb_extal");
|
||||
if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
|
||||
priv->extal = !!clk_get_rate(clk);
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
clk = devm_clk_get(dev, "usb_xtal");
|
||||
if (!IS_ERR(clk) && !clk_prepare_enable(clk)) {
|
||||
priv->xtal = !!clk_get_rate(clk);
|
||||
clk_disable_unprepare(clk);
|
||||
}
|
||||
|
||||
if (!priv->extal && !priv->xtal) {
|
||||
dev_err(dev, "This driver needs usb_extal or usb_xtal\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
dev_set_drvdata(dev, priv);
|
||||
|
||||
init.name = "rcar_usb2_clock_sel";
|
||||
init.ops = &usb2_clock_sel_clock_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = NULL;
|
||||
init.num_parents = 0;
|
||||
priv->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &priv->hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
return of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw);
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rcar_usb2_clock_sel_pm_ops = {
|
||||
.suspend = rcar_usb2_clock_sel_suspend,
|
||||
.resume = rcar_usb2_clock_sel_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver rcar_usb2_clock_sel_driver = {
|
||||
.driver = {
|
||||
.name = "rcar-usb2-clock-sel",
|
||||
.of_match_table = rcar_usb2_clock_sel_match,
|
||||
.pm = &rcar_usb2_clock_sel_pm_ops,
|
||||
},
|
||||
.probe = rcar_usb2_clock_sel_probe,
|
||||
.remove = rcar_usb2_clock_sel_remove,
|
||||
};
|
||||
builtin_platform_driver(rcar_usb2_clock_sel_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Renesas R-Car USB2 clock selector Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -679,6 +679,12 @@ static const struct of_device_id cpg_mssr_match[] = {
|
|||
.compatible = "renesas,r8a7796-cpg-mssr",
|
||||
.data = &r8a7796_cpg_mssr_info,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_CLK_R8A77995
|
||||
{
|
||||
.compatible = "renesas,r8a77995-cpg-mssr",
|
||||
.data = &r8a77995_cpg_mssr_info,
|
||||
},
|
||||
#endif
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
|
|
@ -138,6 +138,7 @@ extern const struct cpg_mssr_info r8a7792_cpg_mssr_info;
|
|||
extern const struct cpg_mssr_info r8a7794_cpg_mssr_info;
|
||||
extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
|
||||
extern const struct cpg_mssr_info r8a7796_cpg_mssr_info;
|
||||
extern const struct cpg_mssr_info r8a77995_cpg_mssr_info;
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -201,7 +201,7 @@ static struct rockchip_clk_branch rk3128_uart2_fracmux __initdata =
|
|||
MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
|
||||
RK2928_CLKSEL_CON(15), 8, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = {
|
||||
static struct rockchip_clk_branch common_clk_branches[] __initdata = {
|
||||
/*
|
||||
* Clock-Architecture Diagram 1
|
||||
*/
|
||||
|
@ -459,10 +459,6 @@ static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = {
|
|||
RK2928_CLKSEL_CON(2), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RK2928_CLKGATE_CON(10), 15, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_SFC, "sclk_sfc", mux_sclk_sfc_src_p, 0,
|
||||
RK2928_CLKSEL_CON(11), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RK2928_CLKGATE_CON(3), 15, GFLAGS),
|
||||
|
||||
COMPOSITE_NOMUX(PCLK_PMU_PRE, "pclk_pmu_pre", "cpll", 0,
|
||||
RK2928_CLKSEL_CON(29), 8, 6, DFLAGS,
|
||||
RK2928_CLKGATE_CON(1), 0, GFLAGS),
|
||||
|
@ -495,7 +491,6 @@ static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = {
|
|||
GATE(ACLK_DMAC, "aclk_dmac", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 1, GFLAGS),
|
||||
GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 15, GFLAGS),
|
||||
GATE(0, "aclk_cpu_to_peri", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 2, GFLAGS),
|
||||
GATE(HCLK_GPS, "hclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(3), 14, GFLAGS),
|
||||
|
||||
GATE(HCLK_I2S_8CH, "hclk_i2s_8ch", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
|
||||
GATE(0, "hclk_peri_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS),
|
||||
|
@ -541,7 +536,6 @@ static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = {
|
|||
GATE(0, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 6, GFLAGS),
|
||||
GATE(HCLK_CRYPTO, "hclk_crypto", "hclk_cpu", 0, RK2928_CLKGATE_CON(3), 5, GFLAGS),
|
||||
|
||||
GATE(PCLK_HDMI, "pclk_hdmi", "pclk_cpu", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS),
|
||||
GATE(PCLK_ACODEC, "pclk_acodec", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS),
|
||||
GATE(0, "pclk_ddrupctl", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 7, GFLAGS),
|
||||
GATE(0, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS),
|
||||
|
@ -561,6 +555,21 @@ static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = {
|
|||
MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 0),
|
||||
};
|
||||
|
||||
static struct rockchip_clk_branch rk3126_clk_branches[] __initdata = {
|
||||
GATE(0, "pclk_stimer", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 15, GFLAGS),
|
||||
GATE(0, "pclk_s_efuse", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS),
|
||||
GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 8, GFLAGS),
|
||||
};
|
||||
|
||||
static struct rockchip_clk_branch rk3128_clk_branches[] __initdata = {
|
||||
COMPOSITE(SCLK_SFC, "sclk_sfc", mux_sclk_sfc_src_p, 0,
|
||||
RK2928_CLKSEL_CON(11), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RK2928_CLKGATE_CON(3), 15, GFLAGS),
|
||||
|
||||
GATE(HCLK_GPS, "hclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(3), 14, GFLAGS),
|
||||
GATE(PCLK_HDMI, "pclk_hdmi", "pclk_cpu", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS),
|
||||
};
|
||||
|
||||
static const char *const rk3128_critical_clocks[] __initconst = {
|
||||
"aclk_cpu",
|
||||
"hclk_cpu",
|
||||
|
@ -570,7 +579,7 @@ static const char *const rk3128_critical_clocks[] __initconst = {
|
|||
"pclk_peri",
|
||||
};
|
||||
|
||||
static void __init rk3128_clk_init(struct device_node *np)
|
||||
static struct rockchip_clk_provider *__init rk3128_common_clk_init(struct device_node *np)
|
||||
{
|
||||
struct rockchip_clk_provider *ctx;
|
||||
void __iomem *reg_base;
|
||||
|
@ -578,23 +587,21 @@ static void __init rk3128_clk_init(struct device_node *np)
|
|||
reg_base = of_iomap(np, 0);
|
||||
if (!reg_base) {
|
||||
pr_err("%s: could not map cru region\n", __func__);
|
||||
return;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
ctx = rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
|
||||
if (IS_ERR(ctx)) {
|
||||
pr_err("%s: rockchip clk init failed\n", __func__);
|
||||
iounmap(reg_base);
|
||||
return;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
rockchip_clk_register_plls(ctx, rk3128_pll_clks,
|
||||
ARRAY_SIZE(rk3128_pll_clks),
|
||||
RK3128_GRF_SOC_STATUS0);
|
||||
rockchip_clk_register_branches(ctx, rk3128_clk_branches,
|
||||
ARRAY_SIZE(rk3128_clk_branches));
|
||||
rockchip_clk_protect_critical(rk3128_critical_clocks,
|
||||
ARRAY_SIZE(rk3128_critical_clocks));
|
||||
rockchip_clk_register_branches(ctx, common_clk_branches,
|
||||
ARRAY_SIZE(common_clk_branches));
|
||||
|
||||
rockchip_clk_register_armclk(ctx, ARMCLK, "armclk",
|
||||
mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
|
||||
|
@ -606,6 +613,40 @@ static void __init rk3128_clk_init(struct device_node *np)
|
|||
|
||||
rockchip_register_restart_notifier(ctx, RK2928_GLB_SRST_FST, NULL);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void __init rk3126_clk_init(struct device_node *np)
|
||||
{
|
||||
struct rockchip_clk_provider *ctx;
|
||||
|
||||
ctx = rk3128_common_clk_init(np);
|
||||
if (IS_ERR(ctx))
|
||||
return;
|
||||
|
||||
rockchip_clk_register_branches(ctx, rk3126_clk_branches,
|
||||
ARRAY_SIZE(rk3126_clk_branches));
|
||||
rockchip_clk_protect_critical(rk3128_critical_clocks,
|
||||
ARRAY_SIZE(rk3128_critical_clocks));
|
||||
|
||||
rockchip_clk_of_add_provider(np, ctx);
|
||||
}
|
||||
|
||||
CLK_OF_DECLARE(rk3126_cru, "rockchip,rk3126-cru", rk3126_clk_init);
|
||||
|
||||
static void __init rk3128_clk_init(struct device_node *np)
|
||||
{
|
||||
struct rockchip_clk_provider *ctx;
|
||||
|
||||
ctx = rk3128_common_clk_init(np);
|
||||
if (IS_ERR(ctx))
|
||||
return;
|
||||
|
||||
rockchip_clk_register_branches(ctx, rk3128_clk_branches,
|
||||
ARRAY_SIZE(rk3128_clk_branches));
|
||||
rockchip_clk_protect_critical(rk3128_critical_clocks,
|
||||
ARRAY_SIZE(rk3128_critical_clocks));
|
||||
|
||||
rockchip_clk_of_add_provider(np, ctx);
|
||||
}
|
||||
|
||||
|
|
|
@ -391,7 +391,7 @@ static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
|
|||
RK2928_CLKSEL_CON(11), 8, 2, MFLAGS, 0, 8, DFLAGS,
|
||||
RK2928_CLKGATE_CON(2), 11, GFLAGS),
|
||||
|
||||
COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
|
||||
COMPOSITE_NODIV(SCLK_SDIO_SRC, "sclk_sdio_src", mux_mmc_src_p, 0,
|
||||
RK2928_CLKSEL_CON(11), 10, 2, MFLAGS,
|
||||
RK2928_CLKGATE_CON(2), 13, GFLAGS),
|
||||
DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
|
||||
|
|
|
@ -93,9 +93,24 @@ static struct rockchip_pll_rate_table rv1108_pll_rates[] = {
|
|||
}
|
||||
|
||||
static struct rockchip_cpuclk_rate_table rv1108_cpuclk_rates[] __initdata = {
|
||||
RV1108_CPUCLK_RATE(816000000, 4),
|
||||
RV1108_CPUCLK_RATE(600000000, 4),
|
||||
RV1108_CPUCLK_RATE(312000000, 4),
|
||||
RV1108_CPUCLK_RATE(1608000000, 7),
|
||||
RV1108_CPUCLK_RATE(1512000000, 7),
|
||||
RV1108_CPUCLK_RATE(1488000000, 5),
|
||||
RV1108_CPUCLK_RATE(1416000000, 5),
|
||||
RV1108_CPUCLK_RATE(1392000000, 5),
|
||||
RV1108_CPUCLK_RATE(1296000000, 5),
|
||||
RV1108_CPUCLK_RATE(1200000000, 5),
|
||||
RV1108_CPUCLK_RATE(1104000000, 5),
|
||||
RV1108_CPUCLK_RATE(1008000000, 5),
|
||||
RV1108_CPUCLK_RATE(912000000, 5),
|
||||
RV1108_CPUCLK_RATE(816000000, 3),
|
||||
RV1108_CPUCLK_RATE(696000000, 3),
|
||||
RV1108_CPUCLK_RATE(600000000, 3),
|
||||
RV1108_CPUCLK_RATE(500000000, 3),
|
||||
RV1108_CPUCLK_RATE(408000000, 1),
|
||||
RV1108_CPUCLK_RATE(312000000, 1),
|
||||
RV1108_CPUCLK_RATE(216000000, 1),
|
||||
RV1108_CPUCLK_RATE(96000000, 1),
|
||||
};
|
||||
|
||||
static const struct rockchip_cpuclk_reg_data rv1108_cpuclk_data = {
|
||||
|
@ -105,7 +120,7 @@ static const struct rockchip_cpuclk_reg_data rv1108_cpuclk_data = {
|
|||
.mux_core_alt = 1,
|
||||
.mux_core_main = 0,
|
||||
.mux_core_shift = 8,
|
||||
.mux_core_mask = 0x1,
|
||||
.mux_core_mask = 0x3,
|
||||
};
|
||||
|
||||
PNAME(mux_pll_p) = { "xin24m", "xin24m"};
|
||||
|
@ -114,30 +129,42 @@ PNAME(mux_armclk_p) = { "apll_core", "gpll_core", "dpll_core" };
|
|||
PNAME(mux_usb480m_pre_p) = { "usbphy", "xin24m" };
|
||||
PNAME(mux_hdmiphy_phy_p) = { "hdmiphy", "xin24m" };
|
||||
PNAME(mux_dclk_hdmiphy_pre_p) = { "dclk_hdmiphy_src_gpll", "dclk_hdmiphy_src_dpll" };
|
||||
PNAME(mux_pll_src_4plls_p) = { "dpll", "hdmiphy", "gpll", "usb480m" };
|
||||
PNAME(mux_pll_src_4plls_p) = { "dpll", "gpll", "hdmiphy", "usb480m" };
|
||||
PNAME(mux_pll_src_3plls_p) = { "apll", "gpll", "dpll" };
|
||||
PNAME(mux_pll_src_2plls_p) = { "dpll", "gpll" };
|
||||
PNAME(mux_pll_src_apll_gpll_p) = { "apll", "gpll" };
|
||||
PNAME(mux_aclk_peri_src_p) = { "aclk_peri_src_dpll", "aclk_peri_src_gpll" };
|
||||
PNAME(mux_aclk_peri_src_p) = { "aclk_peri_src_gpll", "aclk_peri_src_dpll" };
|
||||
PNAME(mux_aclk_bus_src_p) = { "aclk_bus_src_gpll", "aclk_bus_src_apll", "aclk_bus_src_dpll" };
|
||||
PNAME(mux_mmc_src_p) = { "dpll", "gpll", "xin24m", "usb480m" };
|
||||
PNAME(mux_pll_src_dpll_gpll_usb480m_p) = { "dpll", "gpll", "usb480m" };
|
||||
PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" };
|
||||
PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" };
|
||||
PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" };
|
||||
PNAME(mux_sclk_macphy_p) = { "sclk_macphy_pre", "ext_gmac" };
|
||||
PNAME(mux_sclk_mac_p) = { "sclk_mac_pre", "ext_gmac" };
|
||||
PNAME(mux_i2s0_pre_p) = { "i2s0_src", "i2s0_frac", "ext_i2s", "xin12m" };
|
||||
PNAME(mux_i2s_out_p) = { "i2s0_pre", "xin12m" };
|
||||
PNAME(mux_i2s1_p) = { "i2s1_src", "i2s1_frac", "xin12m" };
|
||||
PNAME(mux_i2s2_p) = { "i2s2_src", "i2s2_frac", "xin12m" };
|
||||
PNAME(mux_i2s1_p) = { "i2s1_src", "i2s1_frac", "dummy", "xin12m" };
|
||||
PNAME(mux_i2s2_p) = { "i2s2_src", "i2s2_frac", "dummy", "xin12m" };
|
||||
PNAME(mux_wifi_src_p) = { "gpll", "xin24m" };
|
||||
PNAME(mux_cifout_src_p) = { "hdmiphy", "gpll" };
|
||||
PNAME(mux_cifout_p) = { "sclk_cifout_src", "xin24m" };
|
||||
PNAME(mux_sclk_cif0_src_p) = { "pclk_vip", "clk_cif0_chn_out", "pclkin_cvbs2cif" };
|
||||
PNAME(mux_sclk_cif1_src_p) = { "pclk_vip", "clk_cif1_chn_out", "pclkin_cvbs2cif" };
|
||||
PNAME(mux_sclk_cif2_src_p) = { "pclk_vip", "clk_cif2_chn_out", "pclkin_cvbs2cif" };
|
||||
PNAME(mux_sclk_cif3_src_p) = { "pclk_vip", "clk_cif3_chn_out", "pclkin_cvbs2cif" };
|
||||
PNAME(mux_dsp_src_p) = { "dpll", "gpll", "apll", "usb480m" };
|
||||
PNAME(mux_dclk_hdmiphy_p) = { "hdmiphy", "xin24m" };
|
||||
PNAME(mux_dclk_vop_p) = { "dclk_hdmiphy", "dclk_vop_src" };
|
||||
PNAME(mux_hdmi_cec_src_p) = { "dpll", "gpll", "xin24m" };
|
||||
PNAME(mux_cvbs_src_p) = { "apll", "io_cvbs_clkin", "hdmiphy", "gpll" };
|
||||
|
||||
static struct rockchip_pll_clock rv1108_pll_clks[] __initdata = {
|
||||
[apll] = PLL(pll_rk3399, PLL_APLL, "apll", mux_pll_p, 0, RV1108_PLL_CON(0),
|
||||
RV1108_PLL_CON(3), 8, 31, 0, rv1108_pll_rates),
|
||||
RV1108_PLL_CON(3), 8, 0, 0, rv1108_pll_rates),
|
||||
[dpll] = PLL(pll_rk3399, PLL_DPLL, "dpll", mux_pll_p, 0, RV1108_PLL_CON(8),
|
||||
RV1108_PLL_CON(11), 8, 31, 0, NULL),
|
||||
RV1108_PLL_CON(11), 8, 1, 0, NULL),
|
||||
[gpll] = PLL(pll_rk3399, PLL_GPLL, "gpll", mux_pll_p, 0, RV1108_PLL_CON(16),
|
||||
RV1108_PLL_CON(19), 8, 31, ROCKCHIP_PLL_SYNC_RATE, rv1108_pll_rates),
|
||||
RV1108_PLL_CON(19), 8, 2, 0, rv1108_pll_rates),
|
||||
};
|
||||
|
||||
#define MFLAGS CLK_MUX_HIWORD_MASK
|
||||
|
@ -170,10 +197,10 @@ static struct rockchip_clk_branch rv1108_i2s2_fracmux __initdata =
|
|||
RV1108_CLKSEL_CON(7), 12, 2, MFLAGS);
|
||||
|
||||
static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
||||
MUX(0, "hdmi_phy", mux_hdmiphy_phy_p, CLK_SET_RATE_PARENT,
|
||||
RV1108_MISC_CON, 13, 2, MFLAGS),
|
||||
MUX(0, "hdmiphy", mux_hdmiphy_phy_p, CLK_SET_RATE_PARENT,
|
||||
RV1108_MISC_CON, 13, 1, MFLAGS),
|
||||
MUX(0, "usb480m", mux_usb480m_pre_p, CLK_SET_RATE_PARENT,
|
||||
RV1108_MISC_CON, 15, 2, MFLAGS),
|
||||
RV1108_MISC_CON, 15, 1, MFLAGS),
|
||||
/*
|
||||
* Clock-Architecture Diagram 2
|
||||
*/
|
||||
|
@ -197,50 +224,212 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
RV1108_CLKGATE_CON(11), 1, GFLAGS),
|
||||
|
||||
/* PD_RKVENC */
|
||||
COMPOSITE(0, "aclk_rkvenc_pre", mux_pll_src_4plls_p, 0,
|
||||
RV1108_CLKSEL_CON(37), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 8, GFLAGS),
|
||||
FACTOR_GATE(0, "hclk_rkvenc_pre", "aclk_rkvenc_pre", 0, 1, 4,
|
||||
RV1108_CLKGATE_CON(8), 10, GFLAGS),
|
||||
COMPOSITE(SCLK_VENC_CORE, "clk_venc_core", mux_pll_src_4plls_p, 0,
|
||||
RV1108_CLKSEL_CON(37), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 9, GFLAGS),
|
||||
GATE(ACLK_RKVENC, "aclk_rkvenc", "aclk_rkvenc_pre", 0,
|
||||
RV1108_CLKGATE_CON(19), 8, GFLAGS),
|
||||
GATE(HCLK_RKVENC, "hclk_rkvenc", "hclk_rkvenc_pre", 0,
|
||||
RV1108_CLKGATE_CON(19), 9, GFLAGS),
|
||||
GATE(0, "aclk_rkvenc_niu", "aclk_rkvenc_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(19), 11, GFLAGS),
|
||||
GATE(0, "hclk_rkvenc_niu", "hclk_rkvenc_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(19), 10, GFLAGS),
|
||||
|
||||
/* PD_RKVDEC */
|
||||
COMPOSITE(SCLK_HEVC_CORE, "sclk_hevc_core", mux_pll_src_4plls_p, 0,
|
||||
RV1108_CLKSEL_CON(36), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 2, GFLAGS),
|
||||
FACTOR_GATE(0, "hclk_rkvdec_pre", "sclk_hevc_core", 0, 1, 4,
|
||||
RV1108_CLKGATE_CON(8), 10, GFLAGS),
|
||||
COMPOSITE(SCLK_HEVC_CABAC, "clk_hevc_cabac", mux_pll_src_4plls_p, 0,
|
||||
RV1108_CLKSEL_CON(35), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 1, GFLAGS),
|
||||
|
||||
COMPOSITE(0, "aclk_rkvdec_pre", mux_pll_src_4plls_p, 0,
|
||||
RV1108_CLKSEL_CON(35), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 0, GFLAGS),
|
||||
COMPOSITE(0, "aclk_vpu_pre", mux_pll_src_4plls_p, 0,
|
||||
RV1108_CLKSEL_CON(36), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 3, GFLAGS),
|
||||
GATE(ACLK_RKVDEC, "aclk_rkvdec", "aclk_rkvdec_pre", 0,
|
||||
RV1108_CLKGATE_CON(19), 0, GFLAGS),
|
||||
GATE(ACLK_VPU, "aclk_vpu", "aclk_vpu_pre", 0,
|
||||
RV1108_CLKGATE_CON(19), 1, GFLAGS),
|
||||
GATE(HCLK_RKVDEC, "hclk_rkvdec", "hclk_rkvdec_pre", 0,
|
||||
RV1108_CLKGATE_CON(19), 2, GFLAGS),
|
||||
GATE(HCLK_VPU, "hclk_vpu", "hclk_rkvdec_pre", 0,
|
||||
RV1108_CLKGATE_CON(19), 3, GFLAGS),
|
||||
GATE(0, "aclk_rkvdec_niu", "aclk_rkvdec_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(19), 4, GFLAGS),
|
||||
GATE(0, "hclk_rkvdec_niu", "hclk_rkvdec_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(19), 5, GFLAGS),
|
||||
GATE(0, "aclk_vpu_niu", "aclk_vpu_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(19), 6, GFLAGS),
|
||||
|
||||
/* PD_PMU_wrapper */
|
||||
COMPOSITE_NOMUX(0, "pmu_24m_ena", "gpll", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(38), 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 12, GFLAGS),
|
||||
GATE(0, "pmu", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "pclk_pmu", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(10), 0, GFLAGS),
|
||||
GATE(0, "intmem1", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "pclk_intmem1", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(10), 1, GFLAGS),
|
||||
GATE(0, "gpio0_pmu", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_GPIO0_PMU, "pclk_gpio0_pmu", "pmu_24m_ena", 0,
|
||||
RV1108_CLKGATE_CON(10), 2, GFLAGS),
|
||||
GATE(0, "pmugrf", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "pclk_pmugrf", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(10), 3, GFLAGS),
|
||||
GATE(0, "pmu_noc", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "pclk_pmu_niu", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(10), 4, GFLAGS),
|
||||
GATE(0, "i2c0_pmu_pclk", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_I2C0_PMU, "pclk_i2c0_pmu", "pmu_24m_ena", 0,
|
||||
RV1108_CLKGATE_CON(10), 5, GFLAGS),
|
||||
GATE(0, "pwm0_pmu_pclk", "pmu_24m_ena", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_PWM0_PMU, "pclk_pwm0_pmu", "pmu_24m_ena", 0,
|
||||
RV1108_CLKGATE_CON(10), 6, GFLAGS),
|
||||
COMPOSITE(0, "pwm0_pmu_clk", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED,
|
||||
COMPOSITE(SCLK_PWM0_PMU, "sclk_pwm0_pmu", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(12), 7, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 15, GFLAGS),
|
||||
COMPOSITE(0, "i2c0_pmu_clk", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED,
|
||||
COMPOSITE(SCLK_I2C0_PMU, "sclk_i2c0_pmu", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(19), 7, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(8), 14, GFLAGS),
|
||||
GATE(0, "pvtm_pmu", "xin24m", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(8), 13, GFLAGS),
|
||||
|
||||
/*
|
||||
* Clock-Architecture Diagram 3
|
||||
*/
|
||||
COMPOSITE(SCLK_WIFI, "sclk_wifi", mux_wifi_src_p, 0,
|
||||
RV1108_CLKSEL_CON(28), 15, 1, MFLAGS, 8, 6, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 8, GFLAGS),
|
||||
COMPOSITE_NODIV(0, "sclk_cifout_src", mux_cifout_src_p, 0,
|
||||
RV1108_CLKSEL_CON(40), 8, 1, MFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 11, GFLAGS),
|
||||
COMPOSITE_NOGATE(SCLK_CIFOUT, "sclk_cifout", mux_cifout_p, 0,
|
||||
RV1108_CLKSEL_CON(40), 12, 1, MFLAGS, 0, 5, DFLAGS),
|
||||
COMPOSITE_NOMUX(SCLK_MIPI_CSI_OUT, "sclk_mipi_csi_out", "xin24m", 0,
|
||||
RV1108_CLKSEL_CON(41), 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 12, GFLAGS),
|
||||
|
||||
GATE(0, "pclk_acodecphy", "pclk_top_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(14), 6, GFLAGS),
|
||||
GATE(0, "pclk_usbgrf", "pclk_top_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(14), 14, GFLAGS),
|
||||
|
||||
GATE(ACLK_CIF0, "aclk_cif0", "aclk_vio1_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 10, GFLAGS),
|
||||
GATE(HCLK_CIF0, "hclk_cif0", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 10, GFLAGS),
|
||||
COMPOSITE_NODIV(SCLK_CIF0, "sclk_cif0", mux_sclk_cif0_src_p, 0,
|
||||
RV1108_CLKSEL_CON(31), 0, 2, MFLAGS,
|
||||
RV1108_CLKGATE_CON(7), 9, GFLAGS),
|
||||
GATE(ACLK_CIF1, "aclk_cif1", "aclk_vio1_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 6, GFLAGS),
|
||||
GATE(HCLK_CIF1, "hclk_cif1", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 7, GFLAGS),
|
||||
COMPOSITE_NODIV(SCLK_CIF1, "sclk_cif1", mux_sclk_cif1_src_p, 0,
|
||||
RV1108_CLKSEL_CON(31), 2, 2, MFLAGS,
|
||||
RV1108_CLKGATE_CON(7), 10, GFLAGS),
|
||||
GATE(ACLK_CIF2, "aclk_cif2", "aclk_vio1_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 8, GFLAGS),
|
||||
GATE(HCLK_CIF2, "hclk_cif2", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 9, GFLAGS),
|
||||
COMPOSITE_NODIV(SCLK_CIF2, "sclk_cif2", mux_sclk_cif2_src_p, 0,
|
||||
RV1108_CLKSEL_CON(31), 4, 2, MFLAGS,
|
||||
RV1108_CLKGATE_CON(7), 11, GFLAGS),
|
||||
GATE(ACLK_CIF3, "aclk_cif3", "aclk_vio1_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 10, GFLAGS),
|
||||
GATE(HCLK_CIF3, "hclk_cif3", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 11, GFLAGS),
|
||||
COMPOSITE_NODIV(SCLK_CIF3, "sclk_cif3", mux_sclk_cif3_src_p, 0,
|
||||
RV1108_CLKSEL_CON(31), 6, 2, MFLAGS,
|
||||
RV1108_CLKGATE_CON(7), 12, GFLAGS),
|
||||
GATE(0, "pclk_cif1to4", "pclk_vip", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(7), 8, GFLAGS),
|
||||
|
||||
/* PD_DSP_wrapper */
|
||||
COMPOSITE(SCLK_DSP, "sclk_dsp", mux_dsp_src_p, 0,
|
||||
RV1108_CLKSEL_CON(42), 8, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 0, GFLAGS),
|
||||
GATE(0, "clk_dsp_sys_wd", "sclk_dsp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 0, GFLAGS),
|
||||
GATE(0, "clk_dsp_epp_wd", "sclk_dsp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 1, GFLAGS),
|
||||
GATE(0, "clk_dsp_edp_wd", "sclk_dsp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 2, GFLAGS),
|
||||
GATE(0, "clk_dsp_iop_wd", "sclk_dsp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 3, GFLAGS),
|
||||
GATE(0, "clk_dsp_free", "sclk_dsp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 13, GFLAGS),
|
||||
COMPOSITE_NOMUX(SCLK_DSP_IOP, "sclk_dsp_iop", "sclk_dsp", 0,
|
||||
RV1108_CLKSEL_CON(44), 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 1, GFLAGS),
|
||||
COMPOSITE_NOMUX(SCLK_DSP_EPP, "sclk_dsp_epp", "sclk_dsp", 0,
|
||||
RV1108_CLKSEL_CON(44), 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 2, GFLAGS),
|
||||
COMPOSITE_NOMUX(SCLK_DSP_EDP, "sclk_dsp_edp", "sclk_dsp", 0,
|
||||
RV1108_CLKSEL_CON(45), 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 3, GFLAGS),
|
||||
COMPOSITE_NOMUX(SCLK_DSP_EDAP, "sclk_dsp_edap", "sclk_dsp", 0,
|
||||
RV1108_CLKSEL_CON(45), 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 4, GFLAGS),
|
||||
GATE(0, "pclk_dsp_iop_niu", "sclk_dsp_iop", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 4, GFLAGS),
|
||||
GATE(0, "aclk_dsp_epp_niu", "sclk_dsp_epp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 5, GFLAGS),
|
||||
GATE(0, "aclk_dsp_edp_niu", "sclk_dsp_edp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 6, GFLAGS),
|
||||
GATE(0, "pclk_dsp_dbg_niu", "sclk_dsp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 7, GFLAGS),
|
||||
GATE(0, "aclk_dsp_edap_niu", "sclk_dsp_edap", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 14, GFLAGS),
|
||||
COMPOSITE_NOMUX(SCLK_DSP_PFM, "sclk_dsp_pfm", "sclk_dsp", 0,
|
||||
RV1108_CLKSEL_CON(43), 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 5, GFLAGS),
|
||||
COMPOSITE_NOMUX(PCLK_DSP_CFG, "pclk_dsp_cfg", "sclk_dsp", 0,
|
||||
RV1108_CLKSEL_CON(43), 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(9), 6, GFLAGS),
|
||||
GATE(0, "pclk_dsp_cfg_niu", "pclk_dsp_cfg", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 8, GFLAGS),
|
||||
GATE(0, "pclk_dsp_pfm_mon", "pclk_dsp_cfg", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 9, GFLAGS),
|
||||
GATE(0, "pclk_intc", "pclk_dsp_cfg", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 10, GFLAGS),
|
||||
GATE(0, "pclk_dsp_grf", "pclk_dsp_cfg", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 11, GFLAGS),
|
||||
GATE(0, "pclk_mailbox", "pclk_dsp_cfg", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 12, GFLAGS),
|
||||
GATE(0, "aclk_dsp_epp_perf", "sclk_dsp_epp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(16), 15, GFLAGS),
|
||||
GATE(0, "aclk_dsp_edp_perf", "sclk_dsp_edp", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(11), 8, GFLAGS),
|
||||
|
||||
/*
|
||||
* Clock-Architecture Diagram 4
|
||||
*/
|
||||
COMPOSITE(0, "aclk_vio0_2wrap_occ", mux_pll_src_4plls_p, CLK_IGNORE_UNUSED,
|
||||
COMPOSITE(0, "aclk_vio0_pre", mux_pll_src_4plls_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(6), 0, GFLAGS),
|
||||
GATE(0, "aclk_vio0_pre", "aclk_vio0_2wrap_occ", CLK_IGNORE_UNUSED,
|
||||
GATE(ACLK_VIO0, "aclk_vio0", "aclk_vio0_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 0, GFLAGS),
|
||||
COMPOSITE_NOMUX(0, "hclk_vio_pre", "aclk_vio0_pre", 0,
|
||||
RV1108_CLKSEL_CON(29), 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(7), 2, GFLAGS),
|
||||
GATE(HCLK_VIO, "hclk_vio", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 2, GFLAGS),
|
||||
COMPOSITE_NOMUX(0, "pclk_vio_pre", "aclk_vio0_pre", 0,
|
||||
RV1108_CLKSEL_CON(29), 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(7), 3, GFLAGS),
|
||||
GATE(PCLK_VIO, "pclk_vio", "pclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 3, GFLAGS),
|
||||
COMPOSITE(0, "aclk_vio1_pre", mux_pll_src_4plls_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(28), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(6), 1, GFLAGS),
|
||||
GATE(ACLK_VIO1, "aclk_vio1", "aclk_vio1_pre", 0,
|
||||
RV1108_CLKGATE_CON(17), 1, GFLAGS),
|
||||
|
||||
INVERTER(0, "pclk_vip", "ext_vip",
|
||||
RV1108_CLKSEL_CON(31), 8, IFLAGS),
|
||||
|
@ -252,8 +441,63 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
RV1108_CLKGATE_CON(6), 5, GFLAGS),
|
||||
GATE(0, "dclk_hdmiphy_src_dpll", "dpll", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(6), 4, GFLAGS),
|
||||
COMPOSITE_NOGATE(0, "dclk_hdmiphy", mux_dclk_hdmiphy_pre_p, 0,
|
||||
RV1108_CLKSEL_CON(32), 6, 2, MFLAGS, 8, 6, DFLAGS),
|
||||
COMPOSITE_NOGATE(0, "dclk_hdmiphy_pre", mux_dclk_hdmiphy_pre_p, 0,
|
||||
RV1108_CLKSEL_CON(32), 6, 1, MFLAGS, 8, 6, DFLAGS),
|
||||
COMPOSITE_NOGATE(DCLK_VOP_SRC, "dclk_vop_src", mux_dclk_hdmiphy_pre_p, 0,
|
||||
RV1108_CLKSEL_CON(32), 6, 1, MFLAGS, 0, 6, DFLAGS),
|
||||
MUX(DCLK_HDMIPHY, "dclk_hdmiphy", mux_dclk_hdmiphy_p, CLK_SET_RATE_PARENT,
|
||||
RV1108_CLKSEL_CON(32), 15, 1, MFLAGS),
|
||||
MUX(DCLK_VOP, "dclk_vop", mux_dclk_vop_p, CLK_SET_RATE_PARENT,
|
||||
RV1108_CLKSEL_CON(32), 7, 1, MFLAGS),
|
||||
GATE(ACLK_VOP, "aclk_vop", "aclk_vio0_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 0, GFLAGS),
|
||||
GATE(HCLK_VOP, "hclk_vop", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 1, GFLAGS),
|
||||
GATE(ACLK_IEP, "aclk_iep", "aclk_vio0_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 2, GFLAGS),
|
||||
GATE(HCLK_IEP, "hclk_iep", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 3, GFLAGS),
|
||||
|
||||
GATE(ACLK_RGA, "aclk_rga", "aclk_vio1_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 4, GFLAGS),
|
||||
GATE(HCLK_RGA, "hclk_rga", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 5, GFLAGS),
|
||||
COMPOSITE(SCLK_RGA, "sclk_rga", mux_pll_src_4plls_p, 0,
|
||||
RV1108_CLKSEL_CON(33), 6, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(6), 6, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_CVBS_HOST, "sclk_cvbs_host", mux_cvbs_src_p, 0,
|
||||
RV1108_CLKSEL_CON(33), 13, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(6), 7, GFLAGS),
|
||||
FACTOR(0, "sclk_cvbs_27m", "sclk_cvbs_host", 0, 1, 2),
|
||||
|
||||
GATE(SCLK_HDMI_SFR, "sclk_hdmi_sfr", "xin24m", 0,
|
||||
RV1108_CLKGATE_CON(6), 8, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_HDMI_CEC, "sclk_hdmi_cec", mux_hdmi_cec_src_p, 0,
|
||||
RV1108_CLKSEL_CON(34), 14, 2, MFLAGS, 0, 14, DFLAGS,
|
||||
RV1108_CLKGATE_CON(6), 9, GFLAGS),
|
||||
GATE(PCLK_MIPI_DSI, "pclk_mipi_dsi", "pclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 8, GFLAGS),
|
||||
GATE(PCLK_HDMI_CTRL, "pclk_hdmi_ctrl", "pclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 9, GFLAGS),
|
||||
|
||||
GATE(ACLK_ISP, "aclk_isp", "aclk_vio1_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 12, GFLAGS),
|
||||
GATE(HCLK_ISP, "hclk_isp", "hclk_vio_pre", 0,
|
||||
RV1108_CLKGATE_CON(18), 11, GFLAGS),
|
||||
COMPOSITE(SCLK_ISP, "sclk_isp", mux_pll_src_4plls_p, 0,
|
||||
RV1108_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(6), 3, GFLAGS),
|
||||
|
||||
GATE(0, "clk_dsiphy24m", "xin24m", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(9), 10, GFLAGS),
|
||||
GATE(0, "pclk_vdacphy", "pclk_top_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(14), 9, GFLAGS),
|
||||
GATE(0, "pclk_mipi_dsiphy", "pclk_top_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(14), 11, GFLAGS),
|
||||
GATE(0, "pclk_mipi_csiphy", "pclk_top_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(14), 12, GFLAGS),
|
||||
|
||||
/*
|
||||
* Clock-Architecture Diagram 5
|
||||
|
@ -261,10 +505,11 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
|
||||
FACTOR(0, "xin12m", "xin24m", 0, 1, 2),
|
||||
|
||||
COMPOSITE(0, "i2s0_src", mux_pll_src_2plls_p, 0,
|
||||
|
||||
COMPOSITE(SCLK_I2S0_SRC, "i2s0_src", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(5), 8, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(2), 0, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
|
||||
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
|
||||
RV1108_CLKSEL_CON(8), 0,
|
||||
RV1108_CLKGATE_CON(2), 1, GFLAGS,
|
||||
&rv1108_i2s0_fracmux),
|
||||
|
@ -274,7 +519,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
RV1108_CLKSEL_CON(5), 15, 1, MFLAGS,
|
||||
RV1108_CLKGATE_CON(2), 3, GFLAGS),
|
||||
|
||||
COMPOSITE(0, "i2s1_src", mux_pll_src_2plls_p, 0,
|
||||
COMPOSITE(SCLK_I2S1_SRC, "i2s1_src", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(6), 8, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(2), 4, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
|
||||
|
@ -284,7 +529,7 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", CLK_SET_RATE_PARENT,
|
||||
RV1108_CLKGATE_CON(2), 6, GFLAGS),
|
||||
|
||||
COMPOSITE(0, "i2s2_src", mux_pll_src_2plls_p, 0,
|
||||
COMPOSITE(SCLK_I2S2_SRC, "i2s2_src", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(7), 8, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 8, GFLAGS),
|
||||
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT,
|
||||
|
@ -303,32 +548,53 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
RV1108_CLKGATE_CON(1), 2, GFLAGS),
|
||||
COMPOSITE_NOGATE(ACLK_PRE, "aclk_bus_pre", mux_aclk_bus_src_p, 0,
|
||||
RV1108_CLKSEL_CON(2), 8, 2, MFLAGS, 0, 5, DFLAGS),
|
||||
COMPOSITE_NOMUX(0, "hclk_bus_pre", "aclk_bus_2wrap_occ", 0,
|
||||
COMPOSITE_NOMUX(HCLK_BUS, "hclk_bus_pre", "aclk_bus_pre", 0,
|
||||
RV1108_CLKSEL_CON(3), 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(1), 4, GFLAGS),
|
||||
COMPOSITE_NOMUX(0, "pclken_bus", "aclk_bus_2wrap_occ", 0,
|
||||
COMPOSITE_NOMUX(0, "pclk_bus_pre", "aclk_bus_pre", 0,
|
||||
RV1108_CLKSEL_CON(3), 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(1), 5, GFLAGS),
|
||||
GATE(0, "pclk_bus_pre", "pclken_bus", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_BUS, "pclk_bus", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(1), 6, GFLAGS),
|
||||
GATE(0, "pclk_top_pre", "pclken_bus", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "pclk_top_pre", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(1), 7, GFLAGS),
|
||||
GATE(0, "pclk_ddr_pre", "pclken_bus", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "pclk_ddr_pre", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(1), 8, GFLAGS),
|
||||
GATE(0, "clk_timer0", "mux_pll_p", CLK_IGNORE_UNUSED,
|
||||
GATE(SCLK_TIMER0, "clk_timer0", "xin24m", 0,
|
||||
RV1108_CLKGATE_CON(1), 9, GFLAGS),
|
||||
GATE(0, "clk_timer1", "mux_pll_p", CLK_IGNORE_UNUSED,
|
||||
GATE(SCLK_TIMER1, "clk_timer1", "xin24m", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(1), 10, GFLAGS),
|
||||
GATE(0, "pclk_timer", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_TIMER, "pclk_timer", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(13), 4, GFLAGS),
|
||||
|
||||
COMPOSITE(0, "uart0_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED,
|
||||
GATE(HCLK_I2S0_8CH, "hclk_i2s0_8ch", "hclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(12), 7, GFLAGS),
|
||||
GATE(HCLK_I2S1_2CH, "hclk_i2s1_2ch", "hclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(12), 8, GFLAGS),
|
||||
GATE(HCLK_I2S2_2CH, "hclk_i2s2_2ch", "hclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(12), 9, GFLAGS),
|
||||
|
||||
GATE(HCLK_CRYPTO_MST, "hclk_crypto_mst", "hclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(12), 10, GFLAGS),
|
||||
GATE(HCLK_CRYPTO_SLV, "hclk_crypto_slv", "hclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(12), 11, GFLAGS),
|
||||
COMPOSITE(SCLK_CRYPTO, "sclk_crypto", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(11), 7, 1, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(2), 12, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(11), 15, 1, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 0, GFLAGS),
|
||||
GATE(PCLK_SPI, "pclk_spi", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 5, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_UART0_SRC, "uart0_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(13), 12, 2, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 1, GFLAGS),
|
||||
COMPOSITE(0, "uart1_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED,
|
||||
COMPOSITE(SCLK_UART1_SRC, "uart1_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 3, GFLAGS),
|
||||
COMPOSITE(0, "uart21_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED,
|
||||
COMPOSITE(SCLK_UART2_SRC, "uart2_src", mux_pll_src_dpll_gpll_usb480m_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(15), 12, 2, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 5, GFLAGS),
|
||||
|
||||
|
@ -344,44 +610,58 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
RV1108_CLKSEL_CON(18), 0,
|
||||
RV1108_CLKGATE_CON(3), 6, GFLAGS,
|
||||
&rv1108_uart2_fracmux),
|
||||
GATE(PCLK_UART0, "pclk_uart0", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_UART0, "pclk_uart0", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 10, GFLAGS),
|
||||
GATE(PCLK_UART1, "pclk_uart1", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_UART1, "pclk_uart1", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 11, GFLAGS),
|
||||
GATE(PCLK_UART2, "pclk_uart2", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_UART2, "pclk_uart2", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 12, GFLAGS),
|
||||
|
||||
COMPOSITE(0, "clk_i2c1", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(19), 15, 2, MFLAGS, 8, 7, DFLAGS,
|
||||
COMPOSITE(SCLK_I2C1, "clk_i2c1", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(19), 15, 1, MFLAGS, 8, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 7, GFLAGS),
|
||||
COMPOSITE(0, "clk_i2c2", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(20), 7, 2, MFLAGS, 0, 7, DFLAGS,
|
||||
COMPOSITE(SCLK_I2C2, "clk_i2c2", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(20), 7, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 8, GFLAGS),
|
||||
COMPOSITE(0, "clk_i2c3", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(20), 15, 2, MFLAGS, 8, 7, DFLAGS,
|
||||
COMPOSITE(SCLK_I2C3, "clk_i2c3", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(20), 15, 1, MFLAGS, 8, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 9, GFLAGS),
|
||||
GATE(0, "pclk_i2c1", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_I2C1, "pclk_i2c1", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 0, GFLAGS),
|
||||
GATE(0, "pclk_i2c2", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_I2C2, "pclk_i2c2", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 1, GFLAGS),
|
||||
GATE(0, "pclk_i2c3", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_I2C3, "pclk_i2c3", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 2, GFLAGS),
|
||||
COMPOSITE(0, "clk_pwm1", mux_pll_src_2plls_p, CLK_IGNORE_UNUSED,
|
||||
COMPOSITE(SCLK_PWM, "clk_pwm", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(12), 15, 2, MFLAGS, 8, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 10, GFLAGS),
|
||||
GATE(0, "pclk_pwm1", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_PWM, "pclk_pwm", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 6, GFLAGS),
|
||||
GATE(0, "pclk_wdt", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_WDT, "pclk_wdt", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 3, GFLAGS),
|
||||
GATE(0, "pclk_gpio1", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 7, GFLAGS),
|
||||
GATE(0, "pclk_gpio2", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 8, GFLAGS),
|
||||
GATE(0, "pclk_gpio3", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 9, GFLAGS),
|
||||
|
||||
GATE(0, "pclk_grf", "pclk_bus_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(14), 0, GFLAGS),
|
||||
GATE(PCLK_EFUSE0, "pclk_efuse0", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(12), 12, GFLAGS),
|
||||
GATE(PCLK_EFUSE1, "pclk_efuse1", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(12), 13, GFLAGS),
|
||||
GATE(PCLK_TSADC, "pclk_tsadc", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 13, GFLAGS),
|
||||
COMPOSITE_NOMUX(SCLK_TSADC, "sclk_tsadc", "xin24m", 0,
|
||||
RV1108_CLKSEL_CON(21), 0, 10, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 11, GFLAGS),
|
||||
GATE(PCLK_SARADC, "pclk_saradc", "pclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(13), 14, GFLAGS),
|
||||
COMPOSITE_NOMUX(SCLK_SARADC, "sclk_saradc", "xin24m", 0,
|
||||
RV1108_CLKSEL_CON(22), 0, 10, DFLAGS,
|
||||
RV1108_CLKGATE_CON(3), 12, GFLAGS),
|
||||
|
||||
GATE(ACLK_DMAC, "aclk_dmac", "aclk_bus_pre", 0,
|
||||
RV1108_CLKGATE_CON(12), 2, GFLAGS),
|
||||
|
@ -397,18 +677,24 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
RV1108_CLKGATE_CON(0), 9, GFLAGS),
|
||||
GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(0), 10, GFLAGS),
|
||||
COMPOSITE(0, "ddrphy4x", mux_ddrphy_p, CLK_IGNORE_UNUSED,
|
||||
COMPOSITE_NOGATE(0, "clk_ddrphy_src", mux_ddrphy_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(4), 8, 2, MFLAGS, 0, 3,
|
||||
DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
|
||||
DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
|
||||
FACTOR(0, "clk_ddr", "clk_ddrphy_src", 0, 1, 2),
|
||||
GATE(0, "clk_ddrphy4x", "clk_ddr", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(10), 9, GFLAGS),
|
||||
GATE(0, "ddrupctl", "ddrphy_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(12), 4, GFLAGS),
|
||||
GATE(0, "ddrc", "ddrphy", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "nclk_ddrupctl", "clk_ddr", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(12), 5, GFLAGS),
|
||||
GATE(0, "ddrmon", "ddrphy_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(0, "pclk_ddrmon", "pclk_ddr_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(12), 6, GFLAGS),
|
||||
GATE(0, "timer_clk", "xin24m", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(0), 11, GFLAGS),
|
||||
GATE(0, "pclk_mschniu", "pclk_ddr_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(14), 2, GFLAGS),
|
||||
GATE(0, "pclk_ddrphy", "pclk_ddr_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(14), 4, GFLAGS),
|
||||
|
||||
/*
|
||||
* Clock-Architecture Diagram 6
|
||||
|
@ -418,23 +704,23 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
COMPOSITE_NOMUX(0, "pclk_periph_pre", "gpll", 0,
|
||||
RV1108_CLKSEL_CON(23), 10, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(4), 5, GFLAGS),
|
||||
GATE(0, "pclk_periph", "pclk_periph_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(PCLK_PERI, "pclk_periph", "pclk_periph_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(15), 13, GFLAGS),
|
||||
COMPOSITE_NOMUX(0, "hclk_periph_pre", "gpll", 0,
|
||||
RV1108_CLKSEL_CON(23), 5, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(4), 4, GFLAGS),
|
||||
GATE(0, "hclk_periph", "hclk_periph_pre", CLK_IGNORE_UNUSED,
|
||||
GATE(HCLK_PERI, "hclk_periph", "hclk_periph_pre", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(15), 12, GFLAGS),
|
||||
|
||||
GATE(0, "aclk_peri_src_dpll", "dpll", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(4), 1, GFLAGS),
|
||||
GATE(0, "aclk_peri_src_gpll", "gpll", CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKGATE_CON(4), 2, GFLAGS),
|
||||
COMPOSITE(0, "aclk_periph", mux_aclk_peri_src_p, CLK_IGNORE_UNUSED,
|
||||
RV1108_CLKSEL_CON(23), 15, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
COMPOSITE(ACLK_PERI, "aclk_periph", mux_aclk_peri_src_p, 0,
|
||||
RV1108_CLKSEL_CON(23), 15, 1, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(15), 11, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0,
|
||||
COMPOSITE(SCLK_SDMMC, "sclk_sdmmc", mux_mmc_src_p, 0,
|
||||
RV1108_CLKSEL_CON(25), 8, 2, MFLAGS, 0, 8, DFLAGS,
|
||||
RV1108_CLKGATE_CON(5), 0, GFLAGS),
|
||||
|
||||
|
@ -454,23 +740,31 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
GATE(HCLK_EMMC, "hclk_emmc", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 2, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(27), 14, 2, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKSEL_CON(27), 14, 1, MFLAGS, 8, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(5), 3, GFLAGS),
|
||||
GATE(HCLK_NANDC, "hclk_nandc", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 3, GFLAGS),
|
||||
|
||||
GATE(HCLK_HOST0, "hclk_host0", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 6, GFLAGS),
|
||||
GATE(0, "hclk_host0_arb", "hclk_periph", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(15), 7, GFLAGS),
|
||||
GATE(HCLK_OTG, "hclk_otg", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 8, GFLAGS),
|
||||
GATE(0, "hclk_otg_pmu", "hclk_periph", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(15), 9, GFLAGS),
|
||||
GATE(SCLK_USBPHY, "clk_usbphy", "xin24m", CLK_IGNORE_UNUSED, RV1108_CLKGATE_CON(5), 5, GFLAGS),
|
||||
|
||||
COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_2plls_p, 0,
|
||||
RV1108_CLKSEL_CON(27), 7, 2, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKSEL_CON(27), 7, 1, MFLAGS, 0, 7, DFLAGS,
|
||||
RV1108_CLKGATE_CON(5), 4, GFLAGS),
|
||||
GATE(HCLK_SFC, "hclk_sfc", "hclk_periph", 0, RV1108_CLKGATE_CON(15), 10, GFLAGS),
|
||||
|
||||
COMPOSITE(0, "sclk_macphy_pre", mux_pll_src_apll_gpll_p, 0,
|
||||
RV1108_CLKSEL_CON(24), 12, 2, MFLAGS, 0, 5, DFLAGS,
|
||||
COMPOSITE(SCLK_MAC_PRE, "sclk_mac_pre", mux_pll_src_apll_gpll_p, 0,
|
||||
RV1108_CLKSEL_CON(24), 12, 1, MFLAGS, 0, 5, DFLAGS,
|
||||
RV1108_CLKGATE_CON(4), 10, GFLAGS),
|
||||
MUX(0, "sclk_macphy", mux_sclk_macphy_p, CLK_SET_RATE_PARENT,
|
||||
RV1108_CLKSEL_CON(24), 8, 2, MFLAGS),
|
||||
GATE(0, "sclk_macphy_rx", "sclk_macphy", 0, RV1108_CLKGATE_CON(4), 8, GFLAGS),
|
||||
GATE(0, "sclk_mac_ref", "sclk_macphy", 0, RV1108_CLKGATE_CON(4), 6, GFLAGS),
|
||||
GATE(0, "sclk_mac_refout", "sclk_macphy", 0, RV1108_CLKGATE_CON(4), 7, GFLAGS),
|
||||
MUX(SCLK_MAC, "sclk_mac", mux_sclk_mac_p, CLK_SET_RATE_PARENT,
|
||||
RV1108_CLKSEL_CON(24), 8, 1, MFLAGS),
|
||||
GATE(SCLK_MAC_RX, "sclk_mac_rx", "sclk_mac", 0, RV1108_CLKGATE_CON(4), 8, GFLAGS),
|
||||
GATE(SCLK_MAC_REF, "sclk_mac_ref", "sclk_mac", 0, RV1108_CLKGATE_CON(4), 6, GFLAGS),
|
||||
GATE(SCLK_MAC_REFOUT, "sclk_mac_refout", "sclk_mac", 0, RV1108_CLKGATE_CON(4), 7, GFLAGS),
|
||||
GATE(ACLK_GMAC, "aclk_gmac", "aclk_periph", 0, RV1108_CLKGATE_CON(15), 4, GFLAGS),
|
||||
GATE(PCLK_GMAC, "pclk_gmac", "pclk_periph", 0, RV1108_CLKGATE_CON(15), 5, GFLAGS),
|
||||
|
||||
MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RV1108_SDMMC_CON0, 1),
|
||||
MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RV1108_SDMMC_CON1, 1),
|
||||
|
@ -484,10 +778,16 @@ static struct rockchip_clk_branch rv1108_clk_branches[] __initdata = {
|
|||
|
||||
static const char *const rv1108_critical_clocks[] __initconst = {
|
||||
"aclk_core",
|
||||
"aclk_bus_src_gpll",
|
||||
"aclk_bus",
|
||||
"hclk_bus",
|
||||
"pclk_bus",
|
||||
"aclk_periph",
|
||||
"hclk_periph",
|
||||
"pclk_periph",
|
||||
"nclk_ddrupctl",
|
||||
"pclk_ddrmon",
|
||||
"pclk_acodecphy",
|
||||
"pclk_pmu",
|
||||
};
|
||||
|
||||
static void __init rv1108_clk_init(struct device_node *np)
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/rational.h>
|
||||
#include "clk.h"
|
||||
|
||||
/**
|
||||
|
@ -164,6 +165,40 @@ static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb,
|
|||
return notifier_from_errno(ret);
|
||||
}
|
||||
|
||||
/**
|
||||
* fractional divider must set that denominator is 20 times larger than
|
||||
* numerator to generate precise clock frequency.
|
||||
*/
|
||||
static void rockchip_fractional_approximation(struct clk_hw *hw,
|
||||
unsigned long rate, unsigned long *parent_rate,
|
||||
unsigned long *m, unsigned long *n)
|
||||
{
|
||||
struct clk_fractional_divider *fd = to_clk_fd(hw);
|
||||
unsigned long p_rate, p_parent_rate;
|
||||
struct clk_hw *p_parent;
|
||||
unsigned long scale;
|
||||
|
||||
p_rate = clk_hw_get_rate(clk_hw_get_parent(hw));
|
||||
if ((rate * 20 > p_rate) && (p_rate % rate != 0)) {
|
||||
p_parent = clk_hw_get_parent(clk_hw_get_parent(hw));
|
||||
p_parent_rate = clk_hw_get_rate(p_parent);
|
||||
*parent_rate = p_parent_rate;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get rate closer to *parent_rate to guarantee there is no overflow
|
||||
* for m and n. In the result it will be the nearest rate left shifted
|
||||
* by (scale - fd->nwidth) bits.
|
||||
*/
|
||||
scale = fls_long(*parent_rate / rate - 1);
|
||||
if (scale > fd->nwidth)
|
||||
rate <<= scale - fd->nwidth;
|
||||
|
||||
rational_best_approximation(rate, *parent_rate,
|
||||
GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
|
||||
m, n);
|
||||
}
|
||||
|
||||
static struct clk *rockchip_clk_register_frac_branch(
|
||||
struct rockchip_clk_provider *ctx, const char *name,
|
||||
const char *const *parent_names, u8 num_parents,
|
||||
|
@ -210,6 +245,7 @@ static struct clk *rockchip_clk_register_frac_branch(
|
|||
div->nwidth = 16;
|
||||
div->nmask = GENMASK(div->nwidth - 1, 0) << div->nshift;
|
||||
div->lock = lock;
|
||||
div->approximation = rockchip_fractional_approximation;
|
||||
div_ops = &clk_fractional_divider_ops;
|
||||
|
||||
clk = clk_register_composite(NULL, name, parent_names, num_parents,
|
||||
|
|
|
@ -180,7 +180,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
|
|||
}
|
||||
clk_table[EXYNOS_MOUT_AUDSS] = clk_hw_register_mux(NULL, "mout_audss",
|
||||
mout_audss_p, ARRAY_SIZE(mout_audss_p),
|
||||
CLK_SET_RATE_NO_REPARENT,
|
||||
CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
|
||||
reg_base + ASS_CLK_SRC, 0, 1, 0, &lock);
|
||||
|
||||
cdclk = devm_clk_get(&pdev->dev, "cdclk");
|
||||
|
@ -195,11 +195,11 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
|
|||
reg_base + ASS_CLK_SRC, 2, 2, 0, &lock);
|
||||
|
||||
clk_table[EXYNOS_DOUT_SRP] = clk_hw_register_divider(NULL, "dout_srp",
|
||||
"mout_audss", 0, reg_base + ASS_CLK_DIV, 0, 4,
|
||||
0, &lock);
|
||||
"mout_audss", CLK_SET_RATE_PARENT,
|
||||
reg_base + ASS_CLK_DIV, 0, 4, 0, &lock);
|
||||
|
||||
clk_table[EXYNOS_DOUT_AUD_BUS] = clk_hw_register_divider(NULL,
|
||||
"dout_aud_bus", "dout_srp", 0,
|
||||
"dout_aud_bus", "dout_srp", CLK_SET_RATE_PARENT,
|
||||
reg_base + ASS_CLK_DIV, 4, 4, 0, &lock);
|
||||
|
||||
clk_table[EXYNOS_DOUT_I2S] = clk_hw_register_divider(NULL, "dout_i2s",
|
||||
|
|
|
@ -537,8 +537,8 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
|
|||
|
||||
MUX(CLK_MOUT_MX_MSPLL_CCORE, "mout_mx_mspll_ccore",
|
||||
mout_mx_mspll_ccore_p, SRC_TOP7, 16, 2),
|
||||
MUX(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p,
|
||||
SRC_TOP7, 20, 2),
|
||||
MUX_F(CLK_MOUT_MAU_EPLL, "mout_mau_epll_clk", mout_mau_epll_clk_5800_p,
|
||||
SRC_TOP7, 20, 2, CLK_SET_RATE_PARENT, 0),
|
||||
MUX(0, "sclk_bpll", mout_bpll_p, SRC_TOP7, 24, 1),
|
||||
MUX(0, "mout_epll2", mout_epll2_5800_p, SRC_TOP7, 28, 1),
|
||||
|
||||
|
@ -547,8 +547,8 @@ static const struct samsung_mux_clock exynos5800_mux_clks[] __initconst = {
|
|||
MUX(0, "mout_aclk432_cam", mout_group6_5800_p, SRC_TOP8, 24, 2),
|
||||
MUX(0, "mout_aclk432_scaler", mout_group6_5800_p, SRC_TOP8, 28, 2),
|
||||
|
||||
MUX(CLK_MOUT_USER_MAU_EPLL, "mout_user_mau_epll", mout_group16_5800_p,
|
||||
SRC_TOP9, 8, 1),
|
||||
MUX_F(CLK_MOUT_USER_MAU_EPLL, "mout_user_mau_epll", mout_group16_5800_p,
|
||||
SRC_TOP9, 8, 1, CLK_SET_RATE_PARENT, 0),
|
||||
MUX(0, "mout_user_aclk550_cam", mout_group15_5800_p,
|
||||
SRC_TOP9, 16, 1),
|
||||
MUX(0, "mout_user_aclkfl1_550_cam", mout_group13_5800_p,
|
||||
|
@ -590,6 +590,8 @@ static const struct samsung_gate_clock exynos5800_gate_clks[] __initconst = {
|
|||
GATE_BUS_TOP, 24, 0, 0),
|
||||
GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
|
||||
GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0),
|
||||
GATE(CLK_MAU_EPLL, "mau_epll", "mout_user_mau_epll",
|
||||
SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
|
||||
};
|
||||
|
||||
static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = {
|
||||
|
@ -629,6 +631,11 @@ static const struct samsung_div_clock exynos5420_div_clks[] __initconst = {
|
|||
"mout_aclk400_wcore_bpll", DIV_TOP0, 16, 3),
|
||||
};
|
||||
|
||||
static const struct samsung_gate_clock exynos5420_gate_clks[] __initconst = {
|
||||
GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
|
||||
SRC_MASK_TOP7, 20, CLK_SET_RATE_PARENT, 0),
|
||||
};
|
||||
|
||||
static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
|
||||
MUX(0, "mout_user_pclk66_gpio", mout_user_pclk66_gpio_p,
|
||||
SRC_TOP7, 4, 1),
|
||||
|
@ -706,7 +713,8 @@ static const struct samsung_mux_clock exynos5x_mux_clks[] __initconst = {
|
|||
MUX(0, "mout_sclk_spll", mout_spll_p, SRC_TOP6, 8, 1),
|
||||
MUX(0, "mout_sclk_ipll", mout_ipll_p, SRC_TOP6, 12, 1),
|
||||
MUX(0, "mout_sclk_rpll", mout_rpll_p, SRC_TOP6, 16, 1),
|
||||
MUX(CLK_MOUT_EPLL, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1),
|
||||
MUX_F(CLK_MOUT_EPLL, "mout_sclk_epll", mout_epll_p, SRC_TOP6, 20, 1,
|
||||
CLK_SET_RATE_PARENT, 0),
|
||||
MUX(0, "mout_sclk_dpll", mout_dpll_p, SRC_TOP6, 24, 1),
|
||||
MUX(0, "mout_sclk_cpll", mout_cpll_p, SRC_TOP6, 28, 1),
|
||||
|
||||
|
@ -1001,9 +1009,6 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = {
|
|||
GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1",
|
||||
SRC_MASK_TOP2, 24, CLK_IS_CRITICAL, 0),
|
||||
|
||||
GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
|
||||
SRC_MASK_TOP7, 20, 0, 0),
|
||||
|
||||
/* sclk */
|
||||
GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_uart0",
|
||||
GATE_TOP_SCLK_PERIC, 0, CLK_SET_RATE_PARENT, 0),
|
||||
|
@ -1440,6 +1445,8 @@ static void __init exynos5x_clk_init(struct device_node *np,
|
|||
ARRAY_SIZE(exynos5420_mux_clks));
|
||||
samsung_clk_register_div(ctx, exynos5420_div_clks,
|
||||
ARRAY_SIZE(exynos5420_div_clks));
|
||||
samsung_clk_register_gate(ctx, exynos5420_gate_clks,
|
||||
ARRAY_SIZE(exynos5420_gate_clks));
|
||||
} else {
|
||||
samsung_clk_register_fixed_factor(
|
||||
ctx, exynos5800_fixed_factor_clks,
|
||||
|
|
|
@ -11,6 +11,19 @@ config SUN50I_A64_CCU
|
|||
default ARM64 && ARCH_SUNXI
|
||||
depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST
|
||||
|
||||
config SUN4I_A10_CCU
|
||||
bool "Support for the Allwinner A10/A20 CCU"
|
||||
select SUNXI_CCU_DIV
|
||||
select SUNXI_CCU_MULT
|
||||
select SUNXI_CCU_NK
|
||||
select SUNXI_CCU_NKM
|
||||
select SUNXI_CCU_NM
|
||||
select SUNXI_CCU_MP
|
||||
select SUNXI_CCU_PHASE
|
||||
default MACH_SUN4I
|
||||
default MACH_SUN7I
|
||||
depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST
|
||||
|
||||
config SUN5I_CCU
|
||||
bool "Support for the Allwinner sun5i family CCM"
|
||||
default MACH_SUN5I
|
||||
|
@ -48,6 +61,11 @@ config SUN8I_V3S_CCU
|
|||
config SUN8I_DE2_CCU
|
||||
bool "Support for the Allwinner SoCs DE2 CCU"
|
||||
|
||||
config SUN8I_R40_CCU
|
||||
bool "Support for the Allwinner R40 CCU"
|
||||
default MACH_SUN8I
|
||||
depends on MACH_SUN8I || COMPILE_TEST
|
||||
|
||||
config SUN9I_A80_CCU
|
||||
bool "Support for the Allwinner A80 CCU"
|
||||
default MACH_SUN9I
|
||||
|
|
|
@ -20,6 +20,7 @@ lib-$(CONFIG_SUNXI_CCU) += ccu_mp.o
|
|||
|
||||
# SoC support
|
||||
obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o
|
||||
obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o
|
||||
obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o
|
||||
obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o
|
||||
obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o
|
||||
|
@ -29,6 +30,7 @@ obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o
|
|||
obj-$(CONFIG_SUN8I_V3S_CCU) += ccu-sun8i-v3s.o
|
||||
obj-$(CONFIG_SUN8I_DE2_CCU) += ccu-sun8i-de2.o
|
||||
obj-$(CONFIG_SUN8I_R_CCU) += ccu-sun8i-r.o
|
||||
obj-$(CONFIG_SUN8I_R40_CCU) += ccu-sun8i-r40.o
|
||||
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80.o
|
||||
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80-de.o
|
||||
obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80-usb.o
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2017 Priit Laes
|
||||
*
|
||||
* Priit Laes <plaes@plaes.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _CCU_SUN4I_A10_H_
|
||||
#define _CCU_SUN4I_A10_H_
|
||||
|
||||
#include <dt-bindings/clock/sun4i-a10-ccu.h>
|
||||
#include <dt-bindings/clock/sun7i-a20-ccu.h>
|
||||
#include <dt-bindings/reset/sun4i-a10-ccu.h>
|
||||
|
||||
/* The HOSC is exported */
|
||||
#define CLK_PLL_CORE 2
|
||||
#define CLK_PLL_AUDIO_BASE 3
|
||||
#define CLK_PLL_AUDIO 4
|
||||
#define CLK_PLL_AUDIO_2X 5
|
||||
#define CLK_PLL_AUDIO_4X 6
|
||||
#define CLK_PLL_AUDIO_8X 7
|
||||
#define CLK_PLL_VIDEO0 8
|
||||
#define CLK_PLL_VIDEO0_2X 9
|
||||
#define CLK_PLL_VE 10
|
||||
#define CLK_PLL_DDR_BASE 11
|
||||
#define CLK_PLL_DDR 12
|
||||
#define CLK_PLL_DDR_OTHER 13
|
||||
#define CLK_PLL_PERIPH_BASE 14
|
||||
#define CLK_PLL_PERIPH 15
|
||||
#define CLK_PLL_PERIPH_SATA 16
|
||||
#define CLK_PLL_VIDEO1 17
|
||||
#define CLK_PLL_VIDEO1_2X 18
|
||||
#define CLK_PLL_GPU 19
|
||||
|
||||
/* The CPU clock is exported */
|
||||
#define CLK_AXI 21
|
||||
#define CLK_AXI_DRAM 22
|
||||
#define CLK_AHB 23
|
||||
#define CLK_APB0 24
|
||||
#define CLK_APB1 25
|
||||
|
||||
/* AHB gates are exported (23..68) */
|
||||
/* APB0 gates are exported (69..78) */
|
||||
/* APB1 gates are exported (79..95) */
|
||||
/* IP module clocks are exported (96..128) */
|
||||
/* DRAM gates are exported (129..142)*/
|
||||
/* Media (display engine clocks & etc) are exported (143..169) */
|
||||
|
||||
#define CLK_NUMBER_SUN4I (CLK_MBUS + 1)
|
||||
#define CLK_NUMBER_SUN7I (CLK_OUT_B + 1)
|
||||
|
||||
#endif /* _CCU_SUN4I_A10_H_ */
|
|
@ -976,8 +976,7 @@ static void __init sun5i_ccu_init(struct device_node *node,
|
|||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("%s: Could not map the clock registers\n",
|
||||
of_node_full_name(node));
|
||||
pr_err("%pOF: Could not map the clock registers\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1217,8 +1217,7 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node)
|
|||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("%s: Could not map the clock registers\n",
|
||||
of_node_full_name(node));
|
||||
pr_err("%pOF: Could not map the clock registers\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -716,8 +716,7 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node)
|
|||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("%s: Could not map the clock registers\n",
|
||||
of_node_full_name(node));
|
||||
pr_err("%pOF: Could not map the clock registers\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -777,8 +777,7 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node)
|
|||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("%s: Could not map the clock registers\n",
|
||||
of_node_full_name(node));
|
||||
pr_err("%pOF: Could not map the clock registers\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de",
|
|||
static const char * const cpux_parents[] = { "osc32k", "osc24M",
|
||||
"pll-cpux" , "pll-cpux" };
|
||||
static SUNXI_CCU_MUX(cpux_clk, "cpux", cpux_parents,
|
||||
0x050, 16, 2, CLK_IS_CRITICAL);
|
||||
0x050, 16, 2, CLK_IS_CRITICAL | CLK_SET_RATE_PARENT);
|
||||
|
||||
static SUNXI_CCU_M(axi_clk, "axi", "cpux", 0x050, 0, 2, 0);
|
||||
|
||||
|
@ -1103,6 +1103,13 @@ static const struct sunxi_ccu_desc sun50i_h5_ccu_desc = {
|
|||
.num_resets = ARRAY_SIZE(sun50i_h5_ccu_resets),
|
||||
};
|
||||
|
||||
static struct ccu_pll_nb sun8i_h3_pll_cpu_nb = {
|
||||
.common = &pll_cpux_clk.common,
|
||||
/* copy from pll_cpux_clk */
|
||||
.enable = BIT(31),
|
||||
.lock = BIT(28),
|
||||
};
|
||||
|
||||
static struct ccu_mux_nb sun8i_h3_cpu_nb = {
|
||||
.common = &cpux_clk.common,
|
||||
.cm = &cpux_clk.mux,
|
||||
|
@ -1118,8 +1125,7 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node,
|
|||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("%s: Could not map the clock registers\n",
|
||||
of_node_full_name(node));
|
||||
pr_err("%pOF: Could not map the clock registers\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1130,6 +1136,10 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node,
|
|||
|
||||
sunxi_ccu_probe(node, reg, desc);
|
||||
|
||||
/* Gate then ungate PLL CPU after any rate changes */
|
||||
ccu_pll_notifier_register(&sun8i_h3_pll_cpu_nb);
|
||||
|
||||
/* Reparent CPU during PLL CPU rate changes */
|
||||
ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
|
||||
&sun8i_h3_cpu_nb);
|
||||
}
|
||||
|
|
|
@ -290,8 +290,7 @@ static void __init sunxi_r_ccu_init(struct device_node *node,
|
|||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("%s: Could not map the clock registers\n",
|
||||
of_node_full_name(node));
|
||||
pr_err("%pOF: Could not map the clock registers\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
*/
|
||||
|
||||
#ifndef _CCU_SUN8I_R_H
|
||||
#define _CCU_SUN8I_R_H_
|
||||
#define _CCU_SUN8I_R_H
|
||||
|
||||
#include <dt-bindings/clock/sun8i-r-ccu.h>
|
||||
#include <dt-bindings/reset/sun8i-r-ccu.h>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2017 Icenowy Zheng <icenowy@aosc.io>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _CCU_SUN8I_R40_H_
|
||||
#define _CCU_SUN8I_R40_H_
|
||||
|
||||
#include <dt-bindings/clock/sun8i-r40-ccu.h>
|
||||
#include <dt-bindings/reset/sun8i-r40-ccu.h>
|
||||
|
||||
#define CLK_OSC_12M 0
|
||||
#define CLK_PLL_CPU 1
|
||||
#define CLK_PLL_AUDIO_BASE 2
|
||||
#define CLK_PLL_AUDIO 3
|
||||
#define CLK_PLL_AUDIO_2X 4
|
||||
#define CLK_PLL_AUDIO_4X 5
|
||||
#define CLK_PLL_AUDIO_8X 6
|
||||
#define CLK_PLL_VIDEO0 7
|
||||
#define CLK_PLL_VIDEO0_2X 8
|
||||
#define CLK_PLL_VE 9
|
||||
#define CLK_PLL_DDR0 10
|
||||
#define CLK_PLL_PERIPH0 11
|
||||
#define CLK_PLL_PERIPH0_SATA 12
|
||||
#define CLK_PLL_PERIPH0_2X 13
|
||||
#define CLK_PLL_PERIPH1 14
|
||||
#define CLK_PLL_PERIPH1_2X 15
|
||||
#define CLK_PLL_VIDEO1 16
|
||||
#define CLK_PLL_VIDEO1_2X 17
|
||||
#define CLK_PLL_SATA 18
|
||||
#define CLK_PLL_SATA_OUT 19
|
||||
#define CLK_PLL_GPU 20
|
||||
#define CLK_PLL_MIPI 21
|
||||
#define CLK_PLL_DE 22
|
||||
#define CLK_PLL_DDR1 23
|
||||
|
||||
/* The CPU clock is exported */
|
||||
|
||||
#define CLK_AXI 25
|
||||
#define CLK_AHB1 26
|
||||
#define CLK_APB1 27
|
||||
#define CLK_APB2 28
|
||||
|
||||
/* All the bus gates are exported */
|
||||
|
||||
/* The first bunch of module clocks are exported */
|
||||
|
||||
#define CLK_DRAM 132
|
||||
|
||||
/* All the DRAM gates are exported */
|
||||
|
||||
/* Some more module clocks are exported */
|
||||
|
||||
#define CLK_MBUS 155
|
||||
|
||||
/* Another bunch of module clocks are exported */
|
||||
|
||||
#define CLK_NUMBER (CLK_OUTB + 1)
|
||||
|
||||
#endif /* _CCU_SUN8I_R40_H_ */
|
|
@ -575,8 +575,7 @@ static void __init sun8i_v3s_ccu_setup(struct device_node *node)
|
|||
|
||||
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
|
||||
if (IS_ERR(reg)) {
|
||||
pr_err("%s: Could not map the clock registers\n",
|
||||
of_node_full_name(node));
|
||||
pr_err("%pOF: Could not map the clock registers\n", node);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,18 @@ static unsigned long ccu_div_round_rate(struct ccu_mux_internal *mux,
|
|||
{
|
||||
struct ccu_div *cd = data;
|
||||
|
||||
return divider_round_rate_parent(&cd->common.hw, parent,
|
||||
if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
|
||||
rate *= cd->fixed_post_div;
|
||||
|
||||
rate = divider_round_rate_parent(&cd->common.hw, parent,
|
||||
rate, parent_rate,
|
||||
cd->div.table, cd->div.width,
|
||||
cd->div.flags);
|
||||
|
||||
if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
|
||||
rate /= cd->fixed_post_div;
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static void ccu_div_disable(struct clk_hw *hw)
|
||||
|
@ -62,8 +70,13 @@ static unsigned long ccu_div_recalc_rate(struct clk_hw *hw,
|
|||
parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
|
||||
parent_rate);
|
||||
|
||||
return divider_recalc_rate(hw, parent_rate, val, cd->div.table,
|
||||
val = divider_recalc_rate(hw, parent_rate, val, cd->div.table,
|
||||
cd->div.flags);
|
||||
|
||||
if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
|
||||
val /= cd->fixed_post_div;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int ccu_div_determine_rate(struct clk_hw *hw,
|
||||
|
@ -86,6 +99,9 @@ static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
|
||||
parent_rate);
|
||||
|
||||
if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
|
||||
rate *= cd->fixed_post_div;
|
||||
|
||||
val = divider_get_val(rate, parent_rate, cd->div.table, cd->div.width,
|
||||
cd->div.flags);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue