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:
Linus Torvalds 2017-09-13 11:04:14 -07:00
commit f60a2abfdb
142 changed files with 9356 additions and 1103 deletions

View File

@ -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:

View File

@ -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).

View File

@ -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 */

View File

@ -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)

View File

@ -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>;
};

View File

@ -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.

View File

@ -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>;
};

View File

@ -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>;
};

View File

@ -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)>;
};

View File

@ -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:

View File

@ -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:

View File

@ -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>;

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;
u32 div;
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;

View File

@ -1 +1,2 @@
obj-y += i2s_pll_clock.o
obj-y += pll_clock.o

View File

@ -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");

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 = {

View File

@ -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)

View File

@ -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);

View File

@ -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,

View File

@ -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);
}

431
drivers/clk/clk-hsdk-pll.c Normal file
View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -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),

View File

@ -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;
}
}

1410
drivers/clk/clk-stm32h7.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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;

View File

@ -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)

View File

@ -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;
}

View File

@ -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, },

View File

@ -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,

View File

@ -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, },

View File

@ -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, },

View File

@ -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, },

View File

@ -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, },

View File

@ -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 },

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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, &reg0);
regmap_read(cec_32k->regmap, AO_RTC_ALT_CLK_CNTL1, &reg1);
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,
};

View File

@ -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,
};

View File

@ -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" },
{ }
};

View File

@ -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 */

View File

@ -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,
},
};
@ -880,7 +881,7 @@ static struct clk_mux gxbb_cts_mclk_i958_sel = {
/* Default parent unknown (register reset value: 0) */
.table = (u32[]){ 1, 2, 3 },
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.hw.init = &(struct clk_init_data) {
.name = "cts_mclk_i958_sel",
.ops = &clk_mux_ops,
.parent_names = (const char *[]){ "mpll0", "mpll1", "mpll2" },
@ -894,12 +895,13 @@ static struct clk_divider gxbb_cts_mclk_i958_div = {
.shift = 16,
.width = 8,
.lock = &clk_lock,
.hw.init = &(struct clk_init_data){
.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[] = {

View File

@ -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);

View File

@ -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 */

View File

@ -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)

View File

@ -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)

View File

@ -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 */

View File

@ -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,
},
};

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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),

View File

@ -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, },
{ 0, /* Prohibited setting */ },
{ 1, 192, 192, },
{ 1, 160, 160, },
{ 1, 160, 106, },
{ 0, /* Prohibited setting */ },
{ 1, 160, 160, },
{ 1, 128, 128, },
{ 1, 128, 84, },
{ 0, /* Prohibited setting */ },
{ 1, 128, 128, },
{ 2, 192, 192, },
{ 2, 192, 128, },
{ 0, /* Prohibited setting */ },
{ 2, 192, 192, },
/* EXTAL div PLL1 mult/div PLL3 mult/div */
{ 1, 192, 1, 192, 1, },
{ 1, 192, 1, 128, 1, },
{ 0, /* Prohibited setting */ },
{ 1, 192, 1, 192, 1, },
{ 1, 160, 1, 160, 1, },
{ 1, 160, 1, 106, 1, },
{ 0, /* Prohibited setting */ },
{ 1, 160, 1, 160, 1, },
{ 1, 128, 1, 128, 1, },
{ 1, 128, 1, 84, 1, },
{ 0, /* Prohibited setting */ },
{ 1, 128, 1, 128, 1, },
{ 2, 192, 1, 192, 1, },
{ 2, 192, 1, 128, 1, },
{ 0, /* Prohibited setting */ },
{ 2, 192, 1, 192, 1, },
};
static const struct soc_device_attribute r8a7795es1[] __initconst = {

View File

@ -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, },
{ 0, /* Prohibited setting */ },
{ 1, 192, 192, },
{ 1, 160, 160, },
{ 1, 160, 106, },
{ 0, /* Prohibited setting */ },
{ 1, 160, 160, },
{ 1, 128, 128, },
{ 1, 128, 84, },
{ 0, /* Prohibited setting */ },
{ 1, 128, 128, },
{ 2, 192, 192, },
{ 2, 192, 128, },
{ 0, /* Prohibited setting */ },
{ 2, 192, 192, },
/* EXTAL div PLL1 mult/div PLL3 mult/div */
{ 1, 192, 1, 192, 1, },
{ 1, 192, 1, 128, 1, },
{ 0, /* Prohibited setting */ },
{ 1, 192, 1, 192, 1, },
{ 1, 160, 1, 160, 1, },
{ 1, 160, 1, 106, 1, },
{ 0, /* Prohibited setting */ },
{ 1, 160, 1, 160, 1, },
{ 1, 128, 1, 128, 1, },
{ 1, 128, 1, 84, 1, },
{ 0, /* Prohibited setting */ },
{ 1, 128, 1, 128, 1, },
{ 2, 192, 1, 192, 1, },
{ 2, 192, 1, 128, 1, },
{ 0, /* Prohibited setting */ },
{ 2, 192, 1, 192, 1, },
};
static int __init r8a7796_cpg_mssr_init(struct device *dev)

View File

@ -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,
};

View File

@ -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);
}

View File

@ -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

View File

@ -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");

View File

@ -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 */ }
};

View File

@ -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;
/*

View File

@ -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);
}

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -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",

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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,
cd->div.flags);
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