The clk framework and driver changes for 4.5 look pretty typical. The

bulk of the changes are to clk controller drivers, though some
 improvements to the core and some re-usable blocks/templates also
 received some love. In this past cycle the clk maintainers developed a
 good workflow for handling the common case of patch submissions
 containing a new drivers, new shared Device Tree header and a new Device
 Tree binding description. This requires coordination with the Device
 Tree maintainers and with the architecture maintainers (typically the
 arm-soc tree in our case). This explains the increase in changes to
 include/dt-bindings/... and to
 Documentation/devicetree/bindings/clock/... coming from the clk tree.
 The same commits can be expected to come through those trees on
 occasion, through the use of shared, immutable branches.
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJWmVD1AAoJEKI6nJvDJaTUWqAQAJRqH+iKSnLyuVek6USYPXdp
 ZOW1JHIySCUF/ci3fvv9vbIuW/w4Uc9FdRdAfIIaWO32bpk4ljtEogVasvavL/54
 geN+0YERZpth+PL/wk+g+Dons/8BgN9AL+0ToaVVh2MsRE903jWpe+l0qWCl+SUn
 DQF+yB9F4QcVT7gb+KI0B6hr6lv5Mu/t9Ffq3DrK2UG71IEbrv953pVo19foZqbf
 FgMgduERMHvaM/R6p5xfXxIESbjE+QNMnykEo6bWcHF2wfQrIiYlW1khtnsigNus
 kze2mYWjG77KGkrOex5kwjuBDPfiaGAstk3jcRCCMB7nRmuFcJgryF8003CD3QvW
 +cY+ZBSkyXXtL/nrkefebAplQjsvum7dJ+W6hxA32B772jFL8s8ee5rGda0ibw8N
 nFQRopVcNPoR52tjmSEOxm7Z9vqoDj5qManDdZe62kr6bCFId97E6SzeGgeyDuBQ
 V7tkss9klHMhx29V37wkyl+A/pWXO+CsGzHLEivH8/L1CysMK1WGhyHJJ2/JTDTR
 n3z1EYdg67PbHpfhboscuLP+sHcrAefOCe2la4wKxwqd4DGw6J8RhhVZml6XnfQ3
 I4yLri8Pguol49G1ac1U87ylebKsXhWR5CRHVas1BFHrt0FGULHnl0ZOLzOu4GRZ
 h8/nd9ZODLFhB1w7fL1B
 =nkGr
 -----END PGP SIGNATURE-----

Merge tag 'clk-for-linus-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clk framework updates from Michael Turquette:
 "The clk framework and driver changes for 4.5 look pretty typical.  The
  bulk of the changes are to clk controller drivers, though some
  improvements to the core and some re-usable blocks/templates also
  received some love.

  In this past cycle the clk maintainers developed a good workflow for
  handling the common case of patch submissions containing a new
  drivers, new shared Device Tree header and a new Device Tree binding
  description.  This requires coordination with the Device Tree
  maintainers and with the architecture maintainers (typically the
  arm-soc tree in our case).

  This explains the increase in changes to include/dt-bindings/... and
  to Documentation/devicetree/bindings/clock/... coming from the clk
  tree.  The same commits can be expected to come through those trees on
  occasion, through the use of shared, immutable branches"

* tag 'clk-for-linus-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (125 commits)
  clk: remove duplicated COMMON_CLK_NXP record from clk/Kconfig
  clk: fix clk-gpio.c with optional clock= DT property
  clk: rockchip: fix section mismatches with new child-clocks
  clk: gpio: handle error codes for of_clk_get_parent_count()
  clk: gpio: fix memory leak
  clk: shmobile: r8a7795: Add SATA0 clock
  clk: bcm2835: Add PWM clock support
  clk: bcm2835: Support for clock parent selection
  clk: bcm2835: add a round up ability to the clock divisor
  clk: lpc32xx: add common clock framework driver
  clk: lpc18xx: add NXP specific COMMON_CLK_NXP configuration symbol
  dt-bindings: clock: add NXP LPC32xx clock list for consumers
  dt-bindings: clock: add description of LPC32xx USB clock controller
  dt-bindings: clock: add description of LPC32xx clock controller
  clk: rockchip: rk3036: include downstream muxes into fractional dividers
  clk: add flag for clocks that need to be enabled on rate changes
  clk: rockchip: Allow the RK3288 SPDIF clocks to change their parent
  clk: rockchip: include downstream muxes into fractional dividers
  clk: rockchip: handle mux dependency of fractional dividers
  clk: bcm2835: Add a driver for the auxiliary peripheral clock gates.
  ...
This commit is contained in:
Linus Torvalds 2016-01-15 18:21:28 -08:00
commit ece6267878
119 changed files with 20639 additions and 1353 deletions

View File

@ -0,0 +1,31 @@
Broadcom BCM2835 auxiliary peripheral support
This binding uses the common clock binding:
Documentation/devicetree/bindings/clock/clock-bindings.txt
The auxiliary peripherals (UART, SPI1, and SPI2) have a small register
area controlling clock gating to the peripherals, and providing an IRQ
status register.
Required properties:
- compatible: Should be "brcm,bcm2835-aux"
- #clock-cells: Should be <1>. The permitted clock-specifier values can be
found in include/dt-bindings/clock/bcm2835-aux.h
- reg: Specifies base physical address and size of the registers
- clocks: The parent clock phandle
Example:
clocks: cprman@7e101000 {
compatible = "brcm,bcm2835-cprman";
#clock-cells = <1>;
reg = <0x7e101000 0x2000>;
clocks = <&clk_osc>;
};
aux: aux@0x7e215004 {
compatible = "brcm,bcm2835-aux";
#clock-cells = <1>;
reg = <0x7e215000 0x8>;
clocks = <&clocks BCM2835_CLOCK_VPU>;
};

View File

@ -208,3 +208,8 @@ These clock IDs are defined in:
ch3_unused lcpll_ports 4 BCM_NS2_LCPLL_PORTS_CH3_UNUSED
ch4_unused lcpll_ports 5 BCM_NS2_LCPLL_PORTS_CH4_UNUSED
ch5_unused lcpll_ports 6 BCM_NS2_LCPLL_PORTS_CH5_UNUSED
BCM63138
--------
PLL and leaf clock compatible strings for BCM63138 are:
"brcm,bcm63138-armpll"

View File

@ -0,0 +1,22 @@
CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
Required properties:
- compatible: "cirrus,cs2000-cp"
- reg: The chip select number on the I2C bus
- clocks: common clock binding for CLK_IN, XTI/REF_CLK
- clock-names: CLK_IN : clk_in, XTI/REF_CLK : ref_clk
- #clock-cells: must be <0>
Example:
&i2c2 {
...
cs2000: clk_multiplier@4f {
#clock-cells = <0>;
compatible = "cirrus,cs2000-cp";
reg = <0x4f>;
clocks = <&rcar_sound 0>, <&x12_clk>;
clock-names = "clk_in", "ref_clk";
};
};

View File

@ -0,0 +1,56 @@
NVIDIA Tegra210 Clock And Reset Controller
This binding uses the common clock binding:
Documentation/devicetree/bindings/clock/clock-bindings.txt
The CAR (Clock And Reset) Controller on Tegra is the HW module responsible
for muxing and gating Tegra's clocks, and setting their rates.
Required properties :
- compatible : Should be "nvidia,tegra210-car"
- reg : Should contain CAR registers location and length
- clocks : Should contain phandle and clock specifiers for two clocks:
the 32 KHz "32k_in".
- #clock-cells : Should be 1.
In clock consumers, this cell represents the clock ID exposed by the
CAR. The assignments may be found in header file
<dt-bindings/clock/tegra210-car.h>.
- #reset-cells : Should be 1.
In clock consumers, this cell represents the bit number in the CAR's
array of CLK_RST_CONTROLLER_RST_DEVICES_* registers.
Example SoC include file:
/ {
tegra_car: clock {
compatible = "nvidia,tegra210-car";
reg = <0x60006000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};
usb@c5004000 {
clocks = <&tegra_car TEGRA210_CLK_USB2>;
};
};
Example board file:
/ {
clocks {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <0>;
clk_32k: clock@1 {
compatible = "fixed-clock";
reg = <1>;
#clock-cells = <0>;
clock-frequency = <32768>;
};
};
&tegra_car {
clocks = <&clk_32k>;
};
};

View File

@ -0,0 +1,30 @@
NXP LPC32xx Clock Controller
Required properties:
- compatible: should be "nxp,lpc3220-clk"
- reg: should contain clock controller registers location and length
- #clock-cells: must be 1, the cell holds id of a clock provided by the
clock controller
- clocks: phandles of external oscillators, the list must contain one
32768 Hz oscillator and may have one optional high frequency oscillator
- clock-names: list of external oscillator clock names, must contain
"xtal_32k" and may have optional "xtal"
Examples:
/* System Control Block */
scb {
compatible = "simple-bus";
ranges = <0x0 0x040004000 0x00001000>;
#address-cells = <1>;
#size-cells = <1>;
clk: clock-controller@0 {
compatible = "nxp,lpc3220-clk";
reg = <0x00 0x114>;
#clock-cells = <1>;
clocks = <&xtal_32k>, <&xtal>;
clock-names = "xtal_32k", "xtal";
};
};

View File

@ -0,0 +1,22 @@
NXP LPC32xx USB Clock Controller
Required properties:
- compatible: should be "nxp,lpc3220-usb-clk"
- reg: should contain clock controller registers location and length
- #clock-cells: must be 1, the cell holds id of a clock provided by the
USB clock controller
Examples:
usb {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges = <0x0 0x31020000 0x00001000>;
usbclk: clock-controller@f00 {
compatible = "nxp,lpc3220-usb-clk";
reg = <0xf00 0x100>;
#clock-cells = <1>;
};
};

View File

@ -13,6 +13,7 @@ Required properties :
"qcom,gcc-msm8974"
"qcom,gcc-msm8974pro"
"qcom,gcc-msm8974pro-ac"
"qcom,gcc-msm8996"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1

View File

@ -9,6 +9,7 @@ Required properties :
"qcom,mmcc-msm8660"
"qcom,mmcc-msm8960"
"qcom,mmcc-msm8974"
"qcom,mmcc-msm8996"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1

View File

@ -20,6 +20,10 @@ Required Properties:
clocks must be specified. For clocks with multiple parents, invalid
settings must be specified as "<0>".
- #clock-cells: Must be 0
Optional Properties:
- clock-output-names: The name of the clock as a free-form string

View File

@ -0,0 +1,56 @@
* Rockchip RK3036 Clock and Reset Unit
The RK3036 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,rk3036-cru"
- reg: physical base address of the controller and length of memory mapped
region.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Optional Properties:
- rockchip,grf: phandle to the syscon managing the "general register files"
If missing pll rates are not changeable, due to the missing pll lock status.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/rk3036-cru.h headers and can be
used in device tree sources. Similar macros exist for the reset sources in
these files.
External clocks:
There are several clocks that are generated outside the SoC. It is expected
that they are defined using standard clock bindings with following
clock-output-names:
- "xin24m" - crystal input - required,
- "ext_i2s" - external I2S clock - optional,
- "ext_gmac" - external GMAC clock - optional
Example: Clock controller node:
cru: cru@20000000 {
compatible = "rockchip,rk3036-cru";
reg = <0x20000000 0x1000>;
rockchip,grf = <&grf>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Example: UART controller node that consumes the clock generated by the clock
controller:
uart0: serial@20060000 {
compatible = "snps,dw-apb-uart";
reg = <0x20060000 0x100>;
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&cru SCLK_UART0>;
};

View File

@ -0,0 +1,58 @@
* Rockchip RK3228 Clock and Reset Unit
The RK3228 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,rk3228-cru"
- reg: physical base address of the controller and length of memory mapped
region.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Optional Properties:
- rockchip,grf: phandle to the syscon managing the "general register files"
If missing pll rates are not changeable, due to the missing pll lock status.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/rk3228-cru.h headers and can be
used in device tree sources. Similar macros exist for the reset sources in
these files.
External clocks:
There are several clocks that are generated outside the SoC. It is expected
that they are defined using standard clock bindings with following
clock-output-names:
- "xin24m" - crystal input - required,
- "ext_i2s" - external I2S clock - optional,
- "ext_gmac" - external GMAC clock - optional
- "ext_hsadc" - external HSADC clock - optional
- "phy_50m_out" - output clock of the pll in the mac phy
Example: Clock controller node:
cru: cru@20000000 {
compatible = "rockchip,rk3228-cru";
reg = <0x20000000 0x1000>;
rockchip,grf = <&grf>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Example: UART controller node that consumes the clock generated by the clock
controller:
uart0: serial@10110000 {
compatible = "snps,dw-apb-uart";
reg = <0x10110000 0x100>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&cru SCLK_UART0>;
};

View File

@ -27,7 +27,9 @@ Required properties:
"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
"allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
"allwinner,sun9i-a80-cpus-clk" - for the CPUS on A80
"allwinner,sun6i-a31-ahb1-clk" - for the AHB1 clock on A31
"allwinner,sun8i-h3-ahb2-clk" - for the AHB2 clock on H3
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
"allwinner,sun8i-a23-ahb1-gates-clk" - for the AHB1 gates on A23
"allwinner,sun9i-a80-ahb0-gates-clk" - for the AHB0 gates on A80
@ -55,6 +57,9 @@ Required properties:
"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
"allwinner,sun8i-h3-bus-gates-clk" - for the bus gates on H3
"allwinner,sun9i-a80-apbs-gates-clk" - for the APBS gates on A80
"allwinner,sun4i-a10-dram-gates-clk" - for the DRAM gates on A10
"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
@ -68,8 +73,10 @@ Required properties:
"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
"allwinner,sun8i-a23-usb-clk" - for usb gates + resets on A23
"allwinner,sun8i-h3-usb-clk" - for usb gates + resets on H3
"allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
"allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
"allwinner,sun4i-a10-ve-clk" - for the Video Engine clock
Required properties for all clocks:
- reg : shall be the control register address for the clock.
@ -89,6 +96,9 @@ Required properties for all clocks:
And "allwinner,*-usb-clk" clocks also require:
- reset-cells : shall be set to 1
The "allwinner,sun4i-a10-ve-clk" clock also requires:
- reset-cells : shall be set to 0
The "allwinner,sun9i-a80-mmc-config-clk" clock also requires:
- #reset-cells : shall be set to 1
- resets : shall be the reset control phandle for the mmc block.

View File

@ -0,0 +1,23 @@
* Sigma Designs Tango4 Clock Generator
The Tango4 clock generator outputs cpu_clk and sys_clk (the latter is used
for RAM and various peripheral devices). The clock binding described here
is applicable to all Tango4 SoCs.
Required Properties:
- compatible: should be "sigma,tango4-clkgen".
- reg: physical base address of the device and length of memory mapped region.
- clocks: phandle of the input clock (crystal oscillator).
- clock-output-names: should be "cpuclk" and "sysclk".
- #clock-cells: should be set to 1.
Example:
clkgen: clkgen@10000 {
compatible = "sigma,tango4-clkgen";
reg = <0x10000 0x40>;
clocks = <&xtal>;
clock-output-names = "cpuclk", "sysclk";
#clock-cells = <1>;
};

View File

@ -225,5 +225,9 @@ void __init ti_clk_init_features(void)
if (omap_rev() == OMAP3430_REV_ES1_0)
features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
/* Errata I810 for omap5 / dra7 */
if (soc_is_omap54xx() || soc_is_dra7xx())
features.flags |= TI_CLK_ERRATA_I810;
ti_clk_setup_features(&features);
}

View File

@ -116,6 +116,12 @@ config COMMON_CLK_CDCE925
Given a target output frequency, the driver will set the PLL and
divider to best approximate the desired output.
config COMMON_CLK_CS2000_CP
tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier"
depends on I2C
help
If you say yes here you get support for the CS2000 clock multiplier.
config COMMON_CLK_S2MPS11
tristate "Clock driver for S2MPS1X/S5M8767 MFD"
depends on MFD_SEC_CORE
@ -161,6 +167,12 @@ config COMMON_CLK_KEYSTONE
Supports clock drivers for Keystone based SOCs. These SOCs have local
a power sleep control module that gate the clock to the IPs and PLLs.
config COMMON_CLK_NXP
def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX)
select REGMAP_MMIO if ARCH_LPC32XX
---help---
Support for clock providers on NXP platforms.
config COMMON_CLK_PALMAS
tristate "Clock driver for TI Palmas devices"
depends on MFD_PALMAS

View File

@ -21,6 +21,7 @@ obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
@ -42,6 +43,7 @@ obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
obj-$(CONFIG_ARCH_TANGOX) += clk-tango4.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
@ -62,13 +64,14 @@ endif
obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_MESON) += meson/
obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_LPC18XX) += nxp/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
obj-$(CONFIG_COMMON_CLK_NXP) += nxp/
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/
obj-$(CONFIG_ARCH_RENESAS) += shmobile/
obj-$(CONFIG_ARCH_SIRF) += sirf/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/

View File

@ -10,7 +10,6 @@
*
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/slab.h>
@ -72,8 +71,6 @@ struct clk_sam9x5_slow {
#define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
static struct clk *slow_clk;
static int clk_slow_osc_prepare(struct clk_hw *hw)
{
struct clk_slow_osc *osc = to_clk_slow_osc(hw);
@ -360,8 +357,6 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
clk = clk_register(NULL, &slowck->hw);
if (IS_ERR(clk))
kfree(slowck);
else
slow_clk = clk;
return clk;
}
@ -433,8 +428,6 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
clk = clk_register(NULL, &slowck->hw);
if (IS_ERR(clk))
kfree(slowck);
else
slow_clk = clk;
return clk;
}
@ -462,25 +455,3 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
/*
* FIXME: All slow clk users are not properly claiming it (get + prepare +
* enable) before using it.
* If all users properly claiming this clock decide that they don't need it
* anymore (or are removed), it is disabled while faulty users are still
* requiring it, and the system hangs.
* Prevent this clock from being disabled until all users are properly
* requesting it.
* Once this is done we should remove this function and the slow_clk variable.
*/
static int __init of_at91_clk_slow_retain(void)
{
if (!slow_clk)
return 0;
__clk_get(slow_clk);
clk_prepare_enable(slow_clk);
return 0;
}
arch_initcall(of_at91_clk_slow_retain);

View File

@ -1,3 +1,13 @@
config CLK_BCM_63XX
bool "Broadcom BCM63xx clock support"
depends on ARCH_BCM_63XX || COMPILE_TEST
depends on COMMON_CLK
select COMMON_CLK_IPROC
default ARCH_BCM_63XX
help
Enable common clock framework support for Broadcom BCM63xx DSL SoCs
based on the ARM architecture
config CLK_BCM_KONA
bool "Broadcom Kona CCU clock support"
depends on ARCH_BCM_MOBILE || COMPILE_TEST

View File

@ -1,9 +1,11 @@
obj-$(CONFIG_CLK_BCM_63XX) += clk-bcm63xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-ns2.o
obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2015 Broadcom
*
* 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.
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/bcm2835.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <dt-bindings/clock/bcm2835-aux.h>
#define BCM2835_AUXIRQ 0x00
#define BCM2835_AUXENB 0x04
static int bcm2835_aux_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct clk_onecell_data *onecell;
const char *parent;
struct clk *parent_clk;
struct resource *res;
void __iomem *reg, *gate;
parent_clk = devm_clk_get(dev, NULL);
if (IS_ERR(parent_clk))
return PTR_ERR(parent_clk);
parent = __clk_get_name(parent_clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
reg = devm_ioremap_resource(dev, res);
if (!reg)
return -ENODEV;
onecell = devm_kmalloc(dev, sizeof(*onecell), GFP_KERNEL);
if (!onecell)
return -ENOMEM;
onecell->clk_num = BCM2835_AUX_CLOCK_COUNT;
onecell->clks = devm_kcalloc(dev, BCM2835_AUX_CLOCK_COUNT,
sizeof(*onecell->clks), GFP_KERNEL);
if (!onecell->clks)
return -ENOMEM;
gate = reg + BCM2835_AUXENB;
onecell->clks[BCM2835_AUX_CLOCK_UART] =
clk_register_gate(dev, "aux_uart", parent, 0, gate, 0, 0, NULL);
onecell->clks[BCM2835_AUX_CLOCK_SPI1] =
clk_register_gate(dev, "aux_spi1", parent, 0, gate, 1, 0, NULL);
onecell->clks[BCM2835_AUX_CLOCK_SPI2] =
clk_register_gate(dev, "aux_spi2", parent, 0, gate, 2, 0, NULL);
of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, onecell);
return 0;
}
static const struct of_device_id bcm2835_aux_clk_of_match[] = {
{ .compatible = "brcm,bcm2835-aux", },
{},
};
MODULE_DEVICE_TABLE(of, bcm2835_aux_clk_of_match);
static struct platform_driver bcm2835_aux_clk_driver = {
.driver = {
.name = "bcm2835-aux-clk",
.of_match_table = bcm2835_aux_clk_of_match,
},
.probe = bcm2835_aux_clk_probe,
};
builtin_platform_driver(bcm2835_aux_clk_driver);
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
MODULE_DESCRIPTION("BCM2835 auxiliary peripheral clock driver");
MODULE_LICENSE("GPL v2");

View File

@ -807,6 +807,16 @@ static const struct bcm2835_clock_data bcm2835_clock_emmc_data = {
.frac_bits = 8,
};
static const struct bcm2835_clock_data bcm2835_clock_pwm_data = {
.name = "pwm",
.num_mux_parents = ARRAY_SIZE(bcm2835_clock_per_parents),
.parents = bcm2835_clock_per_parents,
.ctl_reg = CM_PWMCTL,
.div_reg = CM_PWMDIV,
.int_bits = 12,
.frac_bits = 12,
};
struct bcm2835_pll {
struct clk_hw hw;
struct bcm2835_cprman *cprman;
@ -1148,22 +1158,24 @@ static int bcm2835_clock_is_on(struct clk_hw *hw)
static u32 bcm2835_clock_choose_div(struct clk_hw *hw,
unsigned long rate,
unsigned long parent_rate)
unsigned long parent_rate,
bool round_up)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
const struct bcm2835_clock_data *data = clock->data;
u32 unused_frac_mask = GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0);
u32 unused_frac_mask =
GENMASK(CM_DIV_FRAC_BITS - data->frac_bits, 0) >> 1;
u64 temp = (u64)parent_rate << CM_DIV_FRAC_BITS;
u64 rem;
u32 div;
do_div(temp, rate);
rem = do_div(temp, rate);
div = temp;
/* Round and mask off the unused bits */
if (unused_frac_mask != 0) {
div += unused_frac_mask >> 1;
div &= ~unused_frac_mask;
}
/* Round up and mask off the unused bits */
if (round_up && ((div & unused_frac_mask) != 0 || rem != 0))
div += unused_frac_mask + 1;
div &= ~unused_frac_mask;
/* Clamp to the limits. */
div = max(div, unused_frac_mask + 1);
@ -1197,16 +1209,6 @@ static long bcm2835_clock_rate_from_divisor(struct bcm2835_clock *clock,
return temp;
}
static long bcm2835_clock_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *parent_rate)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
u32 div = bcm2835_clock_choose_div(hw, rate, *parent_rate);
return bcm2835_clock_rate_from_divisor(clock, *parent_rate, div);
}
static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@ -1271,20 +1273,82 @@ static int bcm2835_clock_set_rate(struct clk_hw *hw,
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman;
const struct bcm2835_clock_data *data = clock->data;
u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate);
u32 div = bcm2835_clock_choose_div(hw, rate, parent_rate, false);
cprman_write(cprman, data->div_reg, div);
return 0;
}
static int bcm2835_clock_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct clk_hw *parent, *best_parent = NULL;
unsigned long rate, best_rate = 0;
unsigned long prate, best_prate = 0;
size_t i;
u32 div;
/*
* Select parent clock that results in the closest but lower rate
*/
for (i = 0; i < clk_hw_get_num_parents(hw); ++i) {
parent = clk_hw_get_parent_by_index(hw, i);
if (!parent)
continue;
prate = clk_hw_get_rate(parent);
div = bcm2835_clock_choose_div(hw, req->rate, prate, true);
rate = bcm2835_clock_rate_from_divisor(clock, prate, div);
if (rate > best_rate && rate <= req->rate) {
best_parent = parent;
best_prate = prate;
best_rate = rate;
}
}
if (!best_parent)
return -EINVAL;
req->best_parent_hw = best_parent;
req->best_parent_rate = best_prate;
req->rate = best_rate;
return 0;
}
static int bcm2835_clock_set_parent(struct clk_hw *hw, u8 index)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman;
const struct bcm2835_clock_data *data = clock->data;
u8 src = (index << CM_SRC_SHIFT) & CM_SRC_MASK;
cprman_write(cprman, data->ctl_reg, src);
return 0;
}
static u8 bcm2835_clock_get_parent(struct clk_hw *hw)
{
struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw);
struct bcm2835_cprman *cprman = clock->cprman;
const struct bcm2835_clock_data *data = clock->data;
u32 src = cprman_read(cprman, data->ctl_reg);
return (src & CM_SRC_MASK) >> CM_SRC_SHIFT;
}
static const struct clk_ops bcm2835_clock_clk_ops = {
.is_prepared = bcm2835_clock_is_on,
.prepare = bcm2835_clock_on,
.unprepare = bcm2835_clock_off,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
.round_rate = bcm2835_clock_round_rate,
.determine_rate = bcm2835_clock_determine_rate,
.set_parent = bcm2835_clock_set_parent,
.get_parent = bcm2835_clock_get_parent,
};
static int bcm2835_vpu_clock_is_on(struct clk_hw *hw)
@ -1300,7 +1364,9 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = {
.is_prepared = bcm2835_vpu_clock_is_on,
.recalc_rate = bcm2835_clock_get_rate,
.set_rate = bcm2835_clock_set_rate,
.round_rate = bcm2835_clock_round_rate,
.determine_rate = bcm2835_clock_determine_rate,
.set_parent = bcm2835_clock_set_parent,
.get_parent = bcm2835_clock_get_parent,
};
static struct clk *bcm2835_register_pll(struct bcm2835_cprman *cprman,
@ -1394,45 +1460,23 @@ static struct clk *bcm2835_register_clock(struct bcm2835_cprman *cprman,
{
struct bcm2835_clock *clock;
struct clk_init_data init;
const char *parent;
const char *parents[1 << CM_SRC_BITS];
size_t i;
/*
* Most of the clock generators have a mux field, so we
* instantiate a generic mux as our parent to handle it.
* Replace our "xosc" references with the oscillator's
* actual name.
*/
if (data->num_mux_parents) {
const char *parents[1 << CM_SRC_BITS];
int i;
parent = devm_kasprintf(cprman->dev, GFP_KERNEL,
"mux_%s", data->name);
if (!parent)
return NULL;
/*
* Replace our "xosc" references with the oscillator's
* actual name.
*/
for (i = 0; i < data->num_mux_parents; i++) {
if (strcmp(data->parents[i], "xosc") == 0)
parents[i] = cprman->osc_name;
else
parents[i] = data->parents[i];
}
clk_register_mux(cprman->dev, parent,
parents, data->num_mux_parents,
CLK_SET_RATE_PARENT,
cprman->regs + data->ctl_reg,
CM_SRC_SHIFT, CM_SRC_BITS,
0, &cprman->regs_lock);
} else {
parent = data->parents[0];
for (i = 0; i < data->num_mux_parents; i++) {
if (strcmp(data->parents[i], "xosc") == 0)
parents[i] = cprman->osc_name;
else
parents[i] = data->parents[i];
}
memset(&init, 0, sizeof(init));
init.parent_names = &parent;
init.num_parents = 1;
init.parent_names = parents;
init.num_parents = data->num_mux_parents;
init.name = data->name;
init.flags = CLK_IGNORE_UNUSED;
@ -1550,6 +1594,9 @@ static int bcm2835_clk_probe(struct platform_device *pdev)
cprman->regs + CM_PERIICTL, CM_GATE_BIT,
0, &cprman->regs_lock);
clks[BCM2835_CLOCK_PWM] =
bcm2835_register_clock(cprman, &bcm2835_clock_pwm_data);
return of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
&cprman->onecell);
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (C) 2015 Broadcom Corporation
*
* 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.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include "clk-iproc.h"
static void __init bcm63138_armpll_init(struct device_node *node)
{
iproc_armpll_setup(node);
}
CLK_OF_DECLARE(bcm63138_armpll, "brcm,bcm63138-armpll", bcm63138_armpll_init);

510
drivers/clk/clk-cs2000-cp.c Normal file
View File

@ -0,0 +1,510 @@
/*
* CS2000 -- CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier
*
* Copyright (C) 2015 Renesas Electronics Corporation
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/of_device.h>
#include <linux/module.h>
#define CH_MAX 4
#define RATIO_REG_SIZE 4
#define DEVICE_ID 0x1
#define DEVICE_CTRL 0x2
#define DEVICE_CFG1 0x3
#define DEVICE_CFG2 0x4
#define GLOBAL_CFG 0x5
#define Ratio_Add(x, nth) (6 + (x * 4) + (nth))
#define Ratio_Val(x, nth) ((x >> (24 - (8 * nth))) & 0xFF)
#define Val_Ratio(x, nth) ((x & 0xFF) << (24 - (8 * nth)))
#define FUNC_CFG1 0x16
#define FUNC_CFG2 0x17
/* DEVICE_ID */
#define REVISION_MASK (0x7)
#define REVISION_B2_B3 (0x4)
#define REVISION_C1 (0x6)
/* DEVICE_CTRL */
#define PLL_UNLOCK (1 << 7)
/* DEVICE_CFG1 */
#define RSEL(x) (((x) & 0x3) << 3)
#define RSEL_MASK RSEL(0x3)
#define ENDEV1 (0x1)
/* GLOBAL_CFG */
#define ENDEV2 (0x1)
#define CH_SIZE_ERR(ch) ((ch < 0) || (ch >= CH_MAX))
#define hw_to_priv(_hw) container_of(_hw, struct cs2000_priv, hw)
#define priv_to_client(priv) (priv->client)
#define priv_to_dev(priv) (&(priv_to_client(priv)->dev))
#define CLK_IN 0
#define REF_CLK 1
#define CLK_MAX 2
struct cs2000_priv {
struct clk_hw hw;
struct i2c_client *client;
struct clk *clk_in;
struct clk *ref_clk;
struct clk *clk_out;
};
static const struct of_device_id cs2000_of_match[] = {
{ .compatible = "cirrus,cs2000-cp", },
{},
};
MODULE_DEVICE_TABLE(of, cs2000_of_match);
static const struct i2c_device_id cs2000_id[] = {
{ "cs2000-cp", },
{}
};
MODULE_DEVICE_TABLE(i2c, cs2000_id);
#define cs2000_read(priv, addr) \
i2c_smbus_read_byte_data(priv_to_client(priv), addr)
#define cs2000_write(priv, addr, val) \
i2c_smbus_write_byte_data(priv_to_client(priv), addr, val)
static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val)
{
s32 data;
data = cs2000_read(priv, addr);
if (data < 0)
return data;
data &= ~mask;
data |= (val & mask);
return cs2000_write(priv, addr, data);
}
static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable)
{
int ret;
ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1,
enable ? ENDEV1 : 0);
if (ret < 0)
return ret;
ret = cs2000_bset(priv, GLOBAL_CFG, ENDEV2,
enable ? ENDEV2 : 0);
if (ret < 0)
return ret;
return 0;
}
static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv,
u32 rate_in)
{
u32 val;
if (rate_in >= 32000000 && rate_in < 56000000)
val = 0x0;
else if (rate_in >= 16000000 && rate_in < 28000000)
val = 0x1;
else if (rate_in >= 8000000 && rate_in < 14000000)
val = 0x2;
else
return -EINVAL;
return cs2000_bset(priv, FUNC_CFG1, 0x3 << 3, val << 3);
}
static int cs2000_wait_pll_lock(struct cs2000_priv *priv)
{
struct device *dev = priv_to_dev(priv);
s32 val;
unsigned int i;
for (i = 0; i < 256; i++) {
val = cs2000_read(priv, DEVICE_CTRL);
if (val < 0)
return val;
if (!(val & PLL_UNLOCK))
return 0;
udelay(1);
}
dev_err(dev, "pll lock failed\n");
return -ETIMEDOUT;
}
static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable)
{
/* enable both AUX_OUT, CLK_OUT */
return cs2000_write(priv, DEVICE_CTRL, enable ? 0 : 0x3);
}
static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out)
{
u64 ratio;
/*
* ratio = rate_out / rate_in * 2^20
*
* To avoid over flow, rate_out is u64.
* The result should be u32.
*/
ratio = (u64)rate_out << 20;
do_div(ratio, rate_in);
return ratio;
}
static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in)
{
u64 rate_out;
/*
* ratio = rate_out / rate_in * 2^20
*
* To avoid over flow, rate_out is u64.
* The result should be u32 or unsigned long.
*/
rate_out = (u64)ratio * rate_in;
return rate_out >> 20;
}
static int cs2000_ratio_set(struct cs2000_priv *priv,
int ch, u32 rate_in, u32 rate_out)
{
u32 val;
unsigned int i;
int ret;
if (CH_SIZE_ERR(ch))
return -EINVAL;
val = cs2000_rate_to_ratio(rate_in, rate_out);
for (i = 0; i < RATIO_REG_SIZE; i++) {
ret = cs2000_write(priv,
Ratio_Add(ch, i),
Ratio_Val(val, i));
if (ret < 0)
return ret;
}
return 0;
}
static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch)
{
s32 tmp;
u32 val;
unsigned int i;
val = 0;
for (i = 0; i < RATIO_REG_SIZE; i++) {
tmp = cs2000_read(priv, Ratio_Add(ch, i));
if (tmp < 0)
return 0;
val |= Val_Ratio(tmp, i);
}
return val;
}
static int cs2000_ratio_select(struct cs2000_priv *priv, int ch)
{
int ret;
if (CH_SIZE_ERR(ch))
return -EINVAL;
/*
* FIXME
*
* this driver supports static ratio mode only at this point.
*/
ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch));
if (ret < 0)
return ret;
ret = cs2000_write(priv, DEVICE_CFG2, 0x0);
if (ret < 0)
return ret;
return 0;
}
static unsigned long cs2000_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct cs2000_priv *priv = hw_to_priv(hw);
int ch = 0; /* it uses ch0 only at this point */
u32 ratio;
ratio = cs2000_ratio_get(priv, ch);
return cs2000_ratio_to_rate(ratio, parent_rate);
}
static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
u32 ratio;
ratio = cs2000_rate_to_ratio(*parent_rate, rate);
return cs2000_ratio_to_rate(ratio, *parent_rate);
}
static int __cs2000_set_rate(struct cs2000_priv *priv, int ch,
unsigned long rate, unsigned long parent_rate)
{
int ret;
ret = cs2000_clk_in_bound_rate(priv, parent_rate);
if (ret < 0)
return ret;
ret = cs2000_ratio_set(priv, ch, parent_rate, rate);
if (ret < 0)
return ret;
ret = cs2000_ratio_select(priv, ch);
if (ret < 0)
return ret;
return 0;
}
static int cs2000_set_rate(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
{
struct cs2000_priv *priv = hw_to_priv(hw);
int ch = 0; /* it uses ch0 only at this point */
return __cs2000_set_rate(priv, ch, rate, parent_rate);
}
static int cs2000_enable(struct clk_hw *hw)
{
struct cs2000_priv *priv = hw_to_priv(hw);
int ret;
ret = cs2000_enable_dev_config(priv, true);
if (ret < 0)
return ret;
ret = cs2000_clk_out_enable(priv, true);
if (ret < 0)
return ret;
ret = cs2000_wait_pll_lock(priv);
if (ret < 0)
return ret;
return ret;
}
static void cs2000_disable(struct clk_hw *hw)
{
struct cs2000_priv *priv = hw_to_priv(hw);
cs2000_enable_dev_config(priv, false);
cs2000_clk_out_enable(priv, false);
}
static u8 cs2000_get_parent(struct clk_hw *hw)
{
/* always return REF_CLK */
return REF_CLK;
}
static const struct clk_ops cs2000_ops = {
.get_parent = cs2000_get_parent,
.recalc_rate = cs2000_recalc_rate,
.round_rate = cs2000_round_rate,
.set_rate = cs2000_set_rate,
.prepare = cs2000_enable,
.unprepare = cs2000_disable,
};
static int cs2000_clk_get(struct cs2000_priv *priv)
{
struct i2c_client *client = priv_to_client(priv);
struct device *dev = &client->dev;
struct clk *clk_in, *ref_clk;
clk_in = devm_clk_get(dev, "clk_in");
/* not yet provided */
if (IS_ERR(clk_in))
return -EPROBE_DEFER;
ref_clk = devm_clk_get(dev, "ref_clk");
/* not yet provided */
if (IS_ERR(ref_clk))
return -EPROBE_DEFER;
priv->clk_in = clk_in;
priv->ref_clk = ref_clk;
return 0;
}
static int cs2000_clk_register(struct cs2000_priv *priv)
{
struct device *dev = priv_to_dev(priv);
struct device_node *np = dev->of_node;
struct clk_init_data init;
const char *name = np->name;
struct clk *clk;
static const char *parent_names[CLK_MAX];
int ch = 0; /* it uses ch0 only at this point */
int rate;
int ret;
of_property_read_string(np, "clock-output-names", &name);
/*
* set default rate as 1/1.
* otherwise .set_rate which setup ratio
* is never called if user requests 1/1 rate
*/
rate = clk_get_rate(priv->ref_clk);
ret = __cs2000_set_rate(priv, ch, rate, rate);
if (ret < 0)
return ret;
parent_names[CLK_IN] = __clk_get_name(priv->clk_in);
parent_names[REF_CLK] = __clk_get_name(priv->ref_clk);
init.name = name;
init.ops = &cs2000_ops;
init.flags = CLK_SET_RATE_GATE;
init.parent_names = parent_names;
init.num_parents = ARRAY_SIZE(parent_names);
priv->hw.init = &init;
clk = clk_register(dev, &priv->hw);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
if (ret < 0) {
clk_unregister(clk);
return ret;
}
priv->clk_out = clk;
return 0;
}
static int cs2000_version_print(struct cs2000_priv *priv)
{
struct i2c_client *client = priv_to_client(priv);
struct device *dev = &client->dev;
s32 val;
const char *revision;
val = cs2000_read(priv, DEVICE_ID);
if (val < 0)
return val;
/* CS2000 should be 0x0 */
if (val >> 3)
return -EIO;
switch (val & REVISION_MASK) {
case REVISION_B2_B3:
revision = "B2 / B3";
break;
case REVISION_C1:
revision = "C1";
break;
default:
return -EIO;
}
dev_info(dev, "revision - %s\n", revision);
return 0;
}
static int cs2000_remove(struct i2c_client *client)
{
struct cs2000_priv *priv = i2c_get_clientdata(client);
struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
of_clk_del_provider(np);
clk_unregister(priv->clk_out);
return 0;
}
static int cs2000_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cs2000_priv *priv;
struct device *dev = &client->dev;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->client = client;
i2c_set_clientdata(client, priv);
ret = cs2000_clk_get(priv);
if (ret < 0)
return ret;
ret = cs2000_clk_register(priv);
if (ret < 0)
return ret;
ret = cs2000_version_print(priv);
if (ret < 0)
goto probe_err;
return 0;
probe_err:
cs2000_remove(client);
return ret;
}
static struct i2c_driver cs2000_driver = {
.driver = {
.name = "cs2000-cp",
.of_match_table = cs2000_of_match,
},
.probe = cs2000_probe,
.remove = cs2000_remove,
.id_table = cs2000_id,
};
module_i2c_driver(cs2000_driver);
MODULE_DESCRIPTION("CS2000-CP driver");
MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
MODULE_LICENSE("GPL v2");

View File

@ -32,13 +32,14 @@
#define div_mask(width) ((1 << (width)) - 1)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table,
u8 width)
{
unsigned int maxdiv = 0;
unsigned int maxdiv = 0, mask = div_mask(width);
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->div > maxdiv)
if (clkt->div > maxdiv && clkt->val <= mask)
maxdiv = clkt->div;
return maxdiv;
}
@ -62,7 +63,7 @@ static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << div_mask(width);
if (table)
return _get_table_maxdiv(table);
return _get_table_maxdiv(table, width);
return div_mask(width) + 1;
}

View File

@ -264,8 +264,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
const char * const *parent_names, u8 num_parents,
unsigned gpio, bool active_low)
{
return clk_register_gpio_gate(NULL, name, parent_names[0],
gpio, active_low, 0);
return clk_register_gpio_gate(NULL, name, parent_names ?
parent_names[0] : NULL, gpio, active_low, 0);
}
static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
@ -287,18 +287,26 @@ static void __init of_gpio_clk_setup(struct device_node *node,
const char **parent_names;
int i, num_parents;
num_parents = of_clk_get_parent_count(node);
if (num_parents < 0)
return;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return;
num_parents = of_clk_get_parent_count(node);
if (num_parents) {
parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
if (!parent_names) {
kfree(data);
return;
}
parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
if (!parent_names)
return;
for (i = 0; i < num_parents; i++)
parent_names[i] = of_clk_get_parent_name(node, i);
for (i = 0; i < num_parents; i++)
parent_names[i] = of_clk_get_parent_name(node, i);
} else {
parent_names = NULL;
}
data->num_parents = num_parents;
data->parent_names = parent_names;

View File

@ -71,10 +71,9 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
u32 val;
unsigned long flags = 0;
if (mux->table)
if (mux->table) {
index = mux->table[index];
else {
} else {
if (mux->flags & CLK_MUX_INDEX_BIT)
index = 1 << index;

View File

@ -1091,6 +1091,13 @@ 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),

61
drivers/clk/clk-tango4.c Normal file
View File

@ -0,0 +1,61 @@
#include <linux/kernel.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
#include <linux/init.h>
#include <linux/io.h>
static struct clk *out[2];
static struct clk_onecell_data clk_data = { out, 2 };
#define SYSCLK_CTRL 0x20
#define CPUCLK_CTRL 0x24
#define LEGACY_DIV 0x3c
#define PLL_N(val) (((val) >> 0) & 0x7f)
#define PLL_K(val) (((val) >> 13) & 0x7)
#define PLL_M(val) (((val) >> 16) & 0x7)
#define DIV_INDEX(val) (((val) >> 8) & 0xf)
static void __init make_pll(int idx, const char *parent, void __iomem *base)
{
char name[8];
u32 val, mul, div;
sprintf(name, "pll%d", idx);
val = readl_relaxed(base + idx*8);
mul = PLL_N(val) + 1;
div = (PLL_M(val) + 1) << PLL_K(val);
clk_register_fixed_factor(NULL, name, parent, 0, mul, div);
}
static int __init get_div(void __iomem *base)
{
u8 sysclk_tab[16] = { 2, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4 };
int idx = DIV_INDEX(readl_relaxed(base + LEGACY_DIV));
return sysclk_tab[idx];
}
static void __init tango4_clkgen_setup(struct device_node *np)
{
int div, ret;
void __iomem *base = of_iomap(np, 0);
const char *parent = of_clk_get_parent_name(np, 0);
if (!base)
panic("%s: invalid address\n", np->full_name);
make_pll(0, parent, base);
make_pll(1, parent, base);
out[0] = clk_register_divider(NULL, "cpuclk", "pll0", 0,
base + CPUCLK_CTRL, 8, 8, CLK_DIVIDER_ONE_BASED, NULL);
div = readl_relaxed(base + SYSCLK_CTRL) & BIT(23) ? get_div(base) : 4;
out[1] = clk_register_fixed_factor(NULL, "sysclk", "pll1", 0, 1, div);
ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
if (IS_ERR(out[0]) || IS_ERR(out[1]) || ret < 0)
panic("%s: clk registration failed\n", np->full_name);
}
CLK_OF_DECLARE(tango4_clkgen, "sigma,tango4-clkgen", tango4_clkgen_setup);

View File

@ -351,7 +351,8 @@ static int xgene_clk_set_rate(struct clk_hw *hw, unsigned long rate,
/* Set new divider */
data = xgene_clk_read(pclk->param.divider_reg +
pclk->param.reg_divider_offset);
data &= ~((1 << pclk->param.reg_divider_width) - 1);
data &= ~((1 << pclk->param.reg_divider_width) - 1)
<< pclk->param.reg_divider_shift;
data |= divider;
xgene_clk_write(data, pclk->param.divider_reg +
pclk->param.reg_divider_offset);

View File

@ -1443,6 +1443,15 @@ static void clk_change_rate(struct clk_core *core)
else if (core->parent)
best_parent_rate = core->parent->rate;
if (core->flags & CLK_SET_RATE_UNGATE) {
unsigned long flags;
clk_core_prepare(core);
flags = clk_enable_lock();
clk_core_enable(core);
clk_enable_unlock(flags);
}
if (core->new_parent && core->new_parent != core->parent) {
old_parent = __clk_set_parent_before(core, core->new_parent);
trace_clk_set_parent(core, core->new_parent);
@ -1469,6 +1478,15 @@ static void clk_change_rate(struct clk_core *core)
core->rate = clk_recalc(core, best_parent_rate);
if (core->flags & CLK_SET_RATE_UNGATE) {
unsigned long flags;
flags = clk_enable_lock();
clk_core_disable(core);
clk_enable_unlock(flags);
clk_core_unprepare(core);
}
if (core->notifier_count && old_rate != core->rate)
__clk_notify(core, POST_RATE_CHANGE, old_rate, core->rate);
@ -1944,7 +1962,7 @@ bool clk_is_match(const struct clk *p, const struct clk *q)
if (p == q)
return true;
/* true if clk->core pointers match. Avoid derefing garbage */
/* true if clk->core pointers match. Avoid dereferencing garbage */
if (!IS_ERR_OR_NULL(p) && !IS_ERR_OR_NULL(q))
if (p->core == q->core)
return true;
@ -2482,7 +2500,7 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
struct clk *clk;
/* This is to allow this function to be chained to others */
if (!hw || IS_ERR(hw))
if (IS_ERR_OR_NULL(hw))
return (struct clk *) hw;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
@ -2806,10 +2824,9 @@ void __clk_put(struct clk *clk)
* re-enter into the clk framework by calling any top-level clk APIs;
* this will cause a nested prepare_lock mutex.
*
* In all notification cases cases (pre, post and abort rate change) the
* original clock rate is passed to the callback via struct
* clk_notifier_data.old_rate and the new frequency is passed via struct
* clk_notifier_data.new_rate.
* In all notification cases (pre, post and abort rate change) the original
* clock rate is passed to the callback via struct clk_notifier_data.old_rate
* and the new frequency is passed via struct clk_notifier_data.new_rate.
*
* clk_notifier_register() must be called from non-atomic context.
* Returns -EINVAL if called with null arguments, -ENOMEM upon
@ -3062,9 +3079,6 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
int count;
struct clk *clk;
if (index < 0)
return NULL;
rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
&clkspec);
if (rc)
@ -3083,6 +3097,9 @@ const char *of_clk_get_parent_name(struct device_node *np, int index)
}
count++;
}
/* We went off the end of 'clock-indices' without finding it */
if (prop && !vp)
return NULL;
if (of_property_read_string_index(clkspec.np, "clock-output-names",
index,

View File

@ -96,13 +96,11 @@ static struct clk ** const uart_clks[] __initconst = {
NULL
};
static int __init __mx25_clocks_init(unsigned long osc_rate,
void __iomem *ccm_base)
static int __init __mx25_clocks_init(void __iomem *ccm_base)
{
BUG_ON(!ccm_base);
clk[dummy] = imx_clk_fixed("dummy", 0);
clk[osc] = imx_clk_fixed("osc", osc_rate);
clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX25, "mpll", "osc", ccm(CCM_MPCTL));
clk[upll] = imx_clk_pllv1(IMX_PLLV1_IMX25, "upll", "osc", ccm(CCM_UPCTL));
clk[mpll_cpu_3_4] = imx_clk_fixed_factor("mpll_cpu_3_4", "mpll", 3, 4);
@ -250,22 +248,10 @@ static int __init __mx25_clocks_init(unsigned long osc_rate,
static void __init mx25_clocks_init_dt(struct device_node *np)
{
struct device_node *refnp;
unsigned long osc_rate = 24000000;
void __iomem *ccm;
/* retrieve the freqency of fixed clocks from device tree */
for_each_compatible_node(refnp, NULL, "fixed-clock") {
u32 rate;
if (of_property_read_u32(refnp, "clock-frequency", &rate))
continue;
if (of_device_is_compatible(refnp, "fsl,imx-osc"))
osc_rate = rate;
}
ccm = of_iomap(np, 0);
__mx25_clocks_init(osc_rate, ccm);
__mx25_clocks_init(ccm);
clk_data.clks = clk;
clk_data.clk_num = ARRAY_SIZE(clk);

View File

@ -519,10 +519,10 @@ static void __init mx53_clocks_init(struct device_node *np)
mx53_ldb_di0_sel, ARRAY_SIZE(mx53_ldb_di0_sel), CLK_SET_RATE_PARENT);
clk[IMX5_CLK_LDB_DI0_GATE] = imx_clk_gate2("ldb_di0_gate", "ldb_di0_div", MXC_CCM_CCGR6, 28);
clk[IMX5_CLK_LDB_DI1_GATE] = imx_clk_gate2("ldb_di1_gate", "ldb_di1_div", MXC_CCM_CCGR6, 30);
clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
mx53_ipu_di0_sel, ARRAY_SIZE(mx53_ipu_di0_sel));
clk[IMX5_CLK_IPU_DI1_SEL] = imx_clk_mux("ipu_di1_sel", MXC_CCM_CSCMR2, 29, 3,
mx53_ipu_di1_sel, ARRAY_SIZE(mx53_ipu_di1_sel));
clk[IMX5_CLK_IPU_DI0_SEL] = imx_clk_mux_flags("ipu_di0_sel", MXC_CCM_CSCMR2, 26, 3,
mx53_ipu_di0_sel, ARRAY_SIZE(mx53_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,
mx53_ipu_di1_sel, ARRAY_SIZE(mx53_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,
mx53_tve_ext_sel, ARRAY_SIZE(mx53_tve_ext_sel), CLK_SET_RATE_PARENT);
clk[IMX5_CLK_TVE_GATE] = imx_clk_gate2("tve_gate", "tve_pred", MXC_CCM_CCGR2, 30);

View File

@ -70,7 +70,8 @@ static const char *cko_sels[] = { "cko1", "cko2", };
static const char *lvds_sels[] = {
"dummy", "dummy", "dummy", "dummy", "dummy", "dummy",
"pll4_audio", "pll5_video", "pll8_mlb", "enet_ref",
"pcie_ref_125m", "sata_ref_100m",
"pcie_ref_125m", "sata_ref_100m", "usbphy1", "usbphy2",
"dummy", "dummy", "dummy", "dummy", "osc",
};
static const char *pll_bypass_src_sels[] = { "osc", "lvds1_in", "lvds2_in", "dummy", };
static const char *pll1_bypass_sels[] = { "pll1", "pll1_bypass_src", };

View File

@ -399,9 +399,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node)
/* mask handshake of mmdc */
writel_relaxed(BM_CCM_CCDR_MMDC_CH0_MASK, base + CCDR);
for (i = 0; i < ARRAY_SIZE(clks); i++)
if (IS_ERR(clks[i]))
pr_err("i.MX6UL clk %d: register failed with %ld\n", i, PTR_ERR(clks[i]));
imx_check_clocks(clks, ARRAY_SIZE(clks));
clk_data.clks = clks;
clk_data.clk_num = ARRAY_SIZE(clks);

View File

@ -833,10 +833,13 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node)
clks[IMX7D_GPT_3M_CLK] = imx_clk_fixed_factor("gpt_3m", "osc", 1, 8);
for (i = 0; i < ARRAY_SIZE(clks); i++)
if (IS_ERR(clks[i]))
pr_err("i.MX7D clk %d: register failed with %ld\n",
i, PTR_ERR(clks[i]));
clks[IMX7D_CLK_ARM] = imx_clk_cpu("arm", "arm_a7_root_clk",
clks[IMX7D_ARM_A7_ROOT_CLK],
clks[IMX7D_ARM_A7_ROOT_SRC],
clks[IMX7D_PLL_ARM_MAIN_CLK],
clks[IMX7D_PLL_SYS_MAIN_CLK]);
imx_check_clocks(clks, ARRAY_SIZE(clks));
clk_data.clks = clks;
clk_data.clk_num = ARRAY_SIZE(clks);

View File

@ -97,6 +97,16 @@ static void clk_pllv3_unprepare(struct clk_hw *hw)
writel_relaxed(val, pll->base);
}
static int clk_pllv3_is_prepared(struct clk_hw *hw)
{
struct clk_pllv3 *pll = to_clk_pllv3(hw);
if (readl_relaxed(pll->base) & BM_PLL_LOCK)
return 1;
return 0;
}
static unsigned long clk_pllv3_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
@ -139,6 +149,7 @@ static int clk_pllv3_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops clk_pllv3_ops = {
.prepare = clk_pllv3_prepare,
.unprepare = clk_pllv3_unprepare,
.is_prepared = clk_pllv3_is_prepared,
.recalc_rate = clk_pllv3_recalc_rate,
.round_rate = clk_pllv3_round_rate,
.set_rate = clk_pllv3_set_rate,
@ -193,6 +204,7 @@ static int clk_pllv3_sys_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops clk_pllv3_sys_ops = {
.prepare = clk_pllv3_prepare,
.unprepare = clk_pllv3_unprepare,
.is_prepared = clk_pllv3_is_prepared,
.recalc_rate = clk_pllv3_sys_recalc_rate,
.round_rate = clk_pllv3_sys_round_rate,
.set_rate = clk_pllv3_sys_set_rate,
@ -265,6 +277,7 @@ static int clk_pllv3_av_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops clk_pllv3_av_ops = {
.prepare = clk_pllv3_prepare,
.unprepare = clk_pllv3_unprepare,
.is_prepared = clk_pllv3_is_prepared,
.recalc_rate = clk_pllv3_av_recalc_rate,
.round_rate = clk_pllv3_av_round_rate,
.set_rate = clk_pllv3_av_set_rate,
@ -279,6 +292,7 @@ static unsigned long clk_pllv3_enet_recalc_rate(struct clk_hw *hw,
static const struct clk_ops clk_pllv3_enet_ops = {
.prepare = clk_pllv3_prepare,
.unprepare = clk_pllv3_unprepare,
.is_prepared = clk_pllv3_is_prepared,
.recalc_rate = clk_pllv3_enet_recalc_rate,
};

View File

@ -7,6 +7,6 @@ obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o
obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o
obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o
obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o
obj-$(CONFIG_DOVE_CLK) += dove.o
obj-$(CONFIG_DOVE_CLK) += dove.o dove-divider.o
obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o
obj-$(CONFIG_ORION_CLK) += orion.o

View File

@ -0,0 +1,262 @@
/*
* Marvell Dove PMU Core PLL divider driver
*
* Cleaned up by substantially rewriting, and converted to DT by
* Russell King. Origin is not known.
*/
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "dove-divider.h"
struct dove_clk {
const char *name;
struct clk_hw hw;
void __iomem *base;
spinlock_t *lock;
u8 div_bit_start;
u8 div_bit_end;
u8 div_bit_load;
u8 div_bit_size;
u32 *divider_table;
};
enum {
DIV_CTRL0 = 0,
DIV_CTRL1 = 4,
DIV_CTRL1_N_RESET_MASK = BIT(10),
};
#define to_dove_clk(hw) container_of(hw, struct dove_clk, hw)
static void dove_load_divider(void __iomem *base, u32 val, u32 mask, u32 load)
{
u32 v;
v = readl_relaxed(base + DIV_CTRL1) | DIV_CTRL1_N_RESET_MASK;
writel_relaxed(v, base + DIV_CTRL1);
v = (readl_relaxed(base + DIV_CTRL0) & ~(mask | load)) | val;
writel_relaxed(v, base + DIV_CTRL0);
writel_relaxed(v | load, base + DIV_CTRL0);
ndelay(250);
writel_relaxed(v, base + DIV_CTRL0);
}
static unsigned int dove_get_divider(struct dove_clk *dc)
{
unsigned int divider;
u32 val;
val = readl_relaxed(dc->base + DIV_CTRL0);
val >>= dc->div_bit_start;
divider = val & ~(~0 << dc->div_bit_size);
if (dc->divider_table)
divider = dc->divider_table[divider];
return divider;
}
static int dove_calc_divider(const struct dove_clk *dc, unsigned long rate,
unsigned long parent_rate, bool set)
{
unsigned int divider, max;
divider = DIV_ROUND_CLOSEST(parent_rate, rate);
if (dc->divider_table) {
unsigned int i;
for (i = 0; dc->divider_table[i]; i++)
if (divider == dc->divider_table[i]) {
divider = i;
break;
}
if (!dc->divider_table[i])
return -EINVAL;
} else {
max = 1 << dc->div_bit_size;
if (set && (divider == 0 || divider >= max))
return -EINVAL;
if (divider >= max)
divider = max - 1;
else if (divider == 0)
divider = 1;
}
return divider;
}
static unsigned long dove_recalc_rate(struct clk_hw *hw, unsigned long parent)
{
struct dove_clk *dc = to_dove_clk(hw);
unsigned int divider = dove_get_divider(dc);
unsigned long rate = DIV_ROUND_CLOSEST(parent, divider);
pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
__func__, dc->name, divider, parent, rate);
return rate;
}
static long dove_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent)
{
struct dove_clk *dc = to_dove_clk(hw);
unsigned long parent_rate = *parent;
int divider;
divider = dove_calc_divider(dc, rate, parent_rate, false);
if (divider < 0)
return divider;
rate = DIV_ROUND_CLOSEST(parent_rate, divider);
pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
__func__, dc->name, divider, parent_rate, rate);
return rate;
}
static int dove_set_clock(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct dove_clk *dc = to_dove_clk(hw);
u32 mask, load, div;
int divider;
divider = dove_calc_divider(dc, rate, parent_rate, true);
if (divider < 0)
return divider;
pr_debug("%s(): %s divider=%u parent=%lu rate=%lu\n",
__func__, dc->name, divider, parent_rate, rate);
div = (u32)divider << dc->div_bit_start;
mask = ~(~0 << dc->div_bit_size) << dc->div_bit_start;
load = BIT(dc->div_bit_load);
spin_lock(dc->lock);
dove_load_divider(dc->base, div, mask, load);
spin_unlock(dc->lock);
return 0;
}
static const struct clk_ops dove_divider_ops = {
.set_rate = dove_set_clock,
.round_rate = dove_round_rate,
.recalc_rate = dove_recalc_rate,
};
static struct clk *clk_register_dove_divider(struct device *dev,
struct dove_clk *dc, const char **parent_names, size_t num_parents,
void __iomem *base)
{
char name[32];
struct clk_init_data init = {
.name = name,
.ops = &dove_divider_ops,
.parent_names = parent_names,
.num_parents = num_parents,
};
strlcpy(name, dc->name, sizeof(name));
dc->hw.init = &init;
dc->base = base;
dc->div_bit_size = dc->div_bit_end - dc->div_bit_start + 1;
return clk_register(dev, &dc->hw);
}
static DEFINE_SPINLOCK(dove_divider_lock);
static u32 axi_divider[] = {-1, 2, 1, 3, 4, 6, 5, 7, 8, 10, 9, 0};
static struct dove_clk dove_hw_clocks[4] = {
{
.name = "axi",
.lock = &dove_divider_lock,
.div_bit_start = 1,
.div_bit_end = 6,
.div_bit_load = 7,
.divider_table = axi_divider,
}, {
.name = "gpu",
.lock = &dove_divider_lock,
.div_bit_start = 8,
.div_bit_end = 13,
.div_bit_load = 14,
}, {
.name = "vmeta",
.lock = &dove_divider_lock,
.div_bit_start = 15,
.div_bit_end = 20,
.div_bit_load = 21,
}, {
.name = "lcd",
.lock = &dove_divider_lock,
.div_bit_start = 22,
.div_bit_end = 27,
.div_bit_load = 28,
},
};
static const char *core_pll[] = {
"core-pll",
};
static int dove_divider_init(struct device *dev, void __iomem *base,
struct clk **clks)
{
struct clk *clk;
int i;
/*
* Create the core PLL clock. We treat this as a fixed rate
* clock as we don't know any better, and documentation is sparse.
*/
clk = clk_register_fixed_rate(dev, core_pll[0], NULL, CLK_IS_ROOT,
2000000000UL);
if (IS_ERR(clk))
return PTR_ERR(clk);
for (i = 0; i < ARRAY_SIZE(dove_hw_clocks); i++)
clks[i] = clk_register_dove_divider(dev, &dove_hw_clocks[i],
core_pll,
ARRAY_SIZE(core_pll), base);
return 0;
}
static struct clk *dove_divider_clocks[4];
static struct clk_onecell_data dove_divider_data = {
.clks = dove_divider_clocks,
.clk_num = ARRAY_SIZE(dove_divider_clocks),
};
void __init dove_divider_clk_init(struct device_node *np)
{
void *base;
base = of_iomap(np, 0);
if (WARN_ON(!base))
return;
if (WARN_ON(dove_divider_init(NULL, base, dove_divider_clocks))) {
iounmap(base);
return;
}
of_clk_add_provider(np, of_clk_src_onecell_get, &dove_divider_data);
}

View File

@ -0,0 +1,6 @@
#ifndef DOVE_DIVIDER_H
#define DOVE_DIVIDER_H
void __init dove_divider_clk_init(struct device_node *np);
#endif

View File

@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include "common.h"
#include "dove-divider.h"
/*
* Core Clocks
@ -184,9 +185,14 @@ static void __init dove_clk_init(struct device_node *np)
{
struct device_node *cgnp =
of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock");
struct device_node *ddnp =
of_find_compatible_node(NULL, NULL, "marvell,dove-divider-clock");
mvebu_coreclk_setup(np, &dove_coreclks);
if (ddnp)
dove_divider_clk_init(ddnp);
if (cgnp)
mvebu_clk_gating_setup(cgnp, dove_gating_desc);
}

View File

@ -1,2 +1,3 @@
obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-cgu.o
obj-$(CONFIG_ARCH_LPC18XX) += clk-lpc18xx-ccu.o
obj-$(CONFIG_ARCH_LPC32XX) += clk-lpc32xx.o

File diff suppressed because it is too large Load Diff

View File

@ -106,3 +106,20 @@ config MSM_MMCC_8974
Support for the multimedia clock controller on msm8974 devices.
Say Y if you want to support multimedia devices such as display,
graphics, video encode/decode, camera, etc.
config MSM_GCC_8996
tristate "MSM8996 Global Clock Controller"
depends on COMMON_CLK_QCOM
help
Support for the global clock controller on msm8996 devices.
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, UFS, SD/eMMC, PCIe, etc.
config MSM_MMCC_8996
tristate "MSM8996 Multimedia Clock Controller"
select MSM_GCC_8996
depends on COMMON_CLK_QCOM
help
Support for the multimedia clock controller on msm8996 devices.
Say Y if you want to support multimedia devices such as display,
graphics, video encode/decode, camera, etc.

View File

@ -2,6 +2,7 @@ obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o
clk-qcom-y += common.o
clk-qcom-y += clk-regmap.o
clk-qcom-y += clk-alpha-pll.o
clk-qcom-y += clk-pll.o
clk-qcom-y += clk-rcg.o
clk-qcom-y += clk-rcg2.o
@ -20,5 +21,7 @@ obj-$(CONFIG_MSM_GCC_8916) += gcc-msm8916.o
obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
obj-$(CONFIG_MSM_GCC_8996) += gcc-msm8996.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o

View File

@ -0,0 +1,355 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/kernel.h>
#include <linux/export.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include "clk-alpha-pll.h"
#define PLL_MODE 0x00
# define PLL_OUTCTRL BIT(0)
# define PLL_BYPASSNL BIT(1)
# define PLL_RESET_N BIT(2)
# define PLL_LOCK_COUNT_SHIFT 8
# define PLL_LOCK_COUNT_MASK 0x3f
# define PLL_BIAS_COUNT_SHIFT 14
# define PLL_BIAS_COUNT_MASK 0x3f
# define PLL_VOTE_FSM_ENA BIT(20)
# define PLL_VOTE_FSM_RESET BIT(21)
# define PLL_ACTIVE_FLAG BIT(30)
# define PLL_LOCK_DET BIT(31)
#define PLL_L_VAL 0x04
#define PLL_ALPHA_VAL 0x08
#define PLL_ALPHA_VAL_U 0x0c
#define PLL_USER_CTL 0x10
# define PLL_POST_DIV_SHIFT 8
# define PLL_POST_DIV_MASK 0xf
# define PLL_ALPHA_EN BIT(24)
# define PLL_VCO_SHIFT 20
# define PLL_VCO_MASK 0x3
#define PLL_USER_CTL_U 0x14
#define PLL_CONFIG_CTL 0x18
#define PLL_TEST_CTL 0x1c
#define PLL_TEST_CTL_U 0x20
#define PLL_STATUS 0x24
/*
* Even though 40 bits are present, use only 32 for ease of calculation.
*/
#define ALPHA_REG_BITWIDTH 40
#define ALPHA_BITWIDTH 32
#define to_clk_alpha_pll(_hw) container_of(to_clk_regmap(_hw), \
struct clk_alpha_pll, clkr)
#define to_clk_alpha_pll_postdiv(_hw) container_of(to_clk_regmap(_hw), \
struct clk_alpha_pll_postdiv, clkr)
static int wait_for_pll(struct clk_alpha_pll *pll)
{
u32 val, mask, off;
int count;
int ret;
const char *name = clk_hw_get_name(&pll->clkr.hw);
off = pll->offset;
ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
if (ret)
return ret;
if (val & PLL_VOTE_FSM_ENA)
mask = PLL_ACTIVE_FLAG;
else
mask = PLL_LOCK_DET;
/* Wait for pll to enable. */
for (count = 100; count > 0; count--) {
ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
if (ret)
return ret;
if ((val & mask) == mask)
return 0;
udelay(1);
}
WARN(1, "%s didn't enable after voting for it!\n", name);
return -ETIMEDOUT;
}
static int clk_alpha_pll_enable(struct clk_hw *hw)
{
int ret;
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
u32 val, mask, off;
off = pll->offset;
mask = PLL_OUTCTRL | PLL_RESET_N | PLL_BYPASSNL;
ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
if (ret)
return ret;
/* If in FSM mode, just vote for it */
if (val & PLL_VOTE_FSM_ENA) {
ret = clk_enable_regmap(hw);
if (ret)
return ret;
return wait_for_pll(pll);
}
/* Skip if already enabled */
if ((val & mask) == mask)
return 0;
ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
PLL_BYPASSNL, PLL_BYPASSNL);
if (ret)
return ret;
/*
* H/W requires a 5us delay between disabling the bypass and
* de-asserting the reset.
*/
mb();
udelay(5);
ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
PLL_RESET_N, PLL_RESET_N);
if (ret)
return ret;
ret = wait_for_pll(pll);
if (ret)
return ret;
ret = regmap_update_bits(pll->clkr.regmap, off + PLL_MODE,
PLL_OUTCTRL, PLL_OUTCTRL);
/* Ensure that the write above goes through before returning. */
mb();
return ret;
}
static void clk_alpha_pll_disable(struct clk_hw *hw)
{
int ret;
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
u32 val, mask, off;
off = pll->offset;
ret = regmap_read(pll->clkr.regmap, off + PLL_MODE, &val);
if (ret)
return;
/* If in FSM mode, just unvote it */
if (val & PLL_VOTE_FSM_ENA) {
clk_disable_regmap(hw);
return;
}
mask = PLL_OUTCTRL;
regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0);
/* Delay of 2 output clock ticks required until output is disabled */
mb();
udelay(1);
mask = PLL_RESET_N | PLL_BYPASSNL;
regmap_update_bits(pll->clkr.regmap, off + PLL_MODE, mask, 0);
}
static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a)
{
return (prate * l) + ((prate * a) >> ALPHA_BITWIDTH);
}
static unsigned long
alpha_pll_round_rate(unsigned long rate, unsigned long prate, u32 *l, u64 *a)
{
u64 remainder;
u64 quotient;
quotient = rate;
remainder = do_div(quotient, prate);
*l = quotient;
if (!remainder) {
*a = 0;
return rate;
}
/* Upper ALPHA_BITWIDTH bits of Alpha */
quotient = remainder << ALPHA_BITWIDTH;
remainder = do_div(quotient, prate);
if (remainder)
quotient++;
*a = quotient;
return alpha_pll_calc_rate(prate, *l, *a);
}
static const struct pll_vco *
alpha_pll_find_vco(const struct clk_alpha_pll *pll, unsigned long rate)
{
const struct pll_vco *v = pll->vco_table;
const struct pll_vco *end = v + pll->num_vco;
for (; v < end; v++)
if (rate >= v->min_freq && rate <= v->max_freq)
return v;
return NULL;
}
static unsigned long
clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
u32 l, low, high, ctl;
u64 a = 0, prate = parent_rate;
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
u32 off = pll->offset;
regmap_read(pll->clkr.regmap, off + PLL_L_VAL, &l);
regmap_read(pll->clkr.regmap, off + PLL_USER_CTL, &ctl);
if (ctl & PLL_ALPHA_EN) {
regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL, &low);
regmap_read(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, &high);
a = (u64)high << 32 | low;
a >>= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH;
}
return alpha_pll_calc_rate(prate, l, a);
}
static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long prate)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
const struct pll_vco *vco;
u32 l, off = pll->offset;
u64 a;
rate = alpha_pll_round_rate(rate, prate, &l, &a);
vco = alpha_pll_find_vco(pll, rate);
if (!vco) {
pr_err("alpha pll not in a valid vco range\n");
return -EINVAL;
}
a <<= (ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH);
regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l);
regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL, a);
regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, a >> 32);
regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL,
PLL_VCO_MASK << PLL_VCO_SHIFT,
vco->val << PLL_VCO_SHIFT);
regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, PLL_ALPHA_EN,
PLL_ALPHA_EN);
return 0;
}
static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
u32 l;
u64 a;
unsigned long min_freq, max_freq;
rate = alpha_pll_round_rate(rate, *prate, &l, &a);
if (alpha_pll_find_vco(pll, rate))
return rate;
min_freq = pll->vco_table[0].min_freq;
max_freq = pll->vco_table[pll->num_vco - 1].max_freq;
return clamp(rate, min_freq, max_freq);
}
const struct clk_ops clk_alpha_pll_ops = {
.enable = clk_alpha_pll_enable,
.disable = clk_alpha_pll_disable,
.recalc_rate = clk_alpha_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
.set_rate = clk_alpha_pll_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_ops);
static unsigned long
clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
u32 ctl;
regmap_read(pll->clkr.regmap, pll->offset + PLL_USER_CTL, &ctl);
ctl >>= PLL_POST_DIV_SHIFT;
ctl &= PLL_POST_DIV_MASK;
return parent_rate >> fls(ctl);
}
static const struct clk_div_table clk_alpha_div_table[] = {
{ 0x0, 1 },
{ 0x1, 2 },
{ 0x3, 4 },
{ 0x7, 8 },
{ 0xf, 16 },
{ }
};
static long
clk_alpha_pll_postdiv_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
return divider_round_rate(hw, rate, prate, clk_alpha_div_table,
pll->width, CLK_DIVIDER_POWER_OF_TWO);
}
static int clk_alpha_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw);
int div;
/* 16 -> 0xf, 8 -> 0x7, 4 -> 0x3, 2 -> 0x1, 1 -> 0x0 */
div = DIV_ROUND_UP_ULL((u64)parent_rate, rate) - 1;
return regmap_update_bits(pll->clkr.regmap, pll->offset + PLL_USER_CTL,
PLL_POST_DIV_MASK << PLL_POST_DIV_SHIFT,
div << PLL_POST_DIV_SHIFT);
}
const struct clk_ops clk_alpha_pll_postdiv_ops = {
.recalc_rate = clk_alpha_pll_postdiv_recalc_rate,
.round_rate = clk_alpha_pll_postdiv_round_rate,
.set_rate = clk_alpha_pll_postdiv_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_postdiv_ops);

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 __QCOM_CLK_ALPHA_PLL_H__
#define __QCOM_CLK_ALPHA_PLL_H__
#include <linux/clk-provider.h>
#include "clk-regmap.h"
struct pll_vco {
unsigned long min_freq;
unsigned long max_freq;
u32 val;
};
/**
* struct clk_alpha_pll - phase locked loop (PLL)
* @offset: base address of registers
* @vco_table: array of VCO settings
* @clkr: regmap clock handle
*/
struct clk_alpha_pll {
u32 offset;
const struct pll_vco *vco_table;
size_t num_vco;
struct clk_regmap clkr;
};
/**
* struct clk_alpha_pll_postdiv - phase locked loop (PLL) post-divider
* @offset: base address of registers
* @width: width of post-divider
* @clkr: regmap clock handle
*/
struct clk_alpha_pll_postdiv {
u32 offset;
u8 width;
struct clk_regmap clkr;
};
extern const struct clk_ops clk_alpha_pll_ops;
extern const struct clk_ops clk_alpha_pll_postdiv_ops;
#endif

View File

@ -178,5 +178,6 @@ extern const struct clk_ops clk_edp_pixel_ops;
extern const struct clk_ops clk_byte_ops;
extern const struct clk_ops clk_byte2_ops;
extern const struct clk_ops clk_pixel_ops;
extern const struct clk_ops clk_gfx3d_ops;
#endif

View File

@ -723,3 +723,90 @@ const struct clk_ops clk_pixel_ops = {
.determine_rate = clk_pixel_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_pixel_ops);
static int clk_gfx3d_determine_rate(struct clk_hw *hw,
struct clk_rate_request *req)
{
struct clk_rate_request parent_req = { };
struct clk_hw *p2, *p8, *p9, *xo;
unsigned long p9_rate;
int ret;
xo = clk_hw_get_parent_by_index(hw, 0);
if (req->rate == clk_hw_get_rate(xo)) {
req->best_parent_hw = xo;
return 0;
}
p9 = clk_hw_get_parent_by_index(hw, 2);
p2 = clk_hw_get_parent_by_index(hw, 3);
p8 = clk_hw_get_parent_by_index(hw, 4);
/* PLL9 is a fixed rate PLL */
p9_rate = clk_hw_get_rate(p9);
parent_req.rate = req->rate = min(req->rate, p9_rate);
if (req->rate == p9_rate) {
req->rate = req->best_parent_rate = p9_rate;
req->best_parent_hw = p9;
return 0;
}
if (req->best_parent_hw == p9) {
/* Are we going back to a previously used rate? */
if (clk_hw_get_rate(p8) == req->rate)
req->best_parent_hw = p8;
else
req->best_parent_hw = p2;
} else if (req->best_parent_hw == p8) {
req->best_parent_hw = p2;
} else {
req->best_parent_hw = p8;
}
ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
if (ret)
return ret;
req->rate = req->best_parent_rate = parent_req.rate;
return 0;
}
static int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate, u8 index)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
u32 cfg;
int ret;
/* Just mux it, we don't use the division or m/n hardware */
cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
if (ret)
return ret;
return update_config(rcg);
}
static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
/*
* We should never get here; clk_gfx3d_determine_rate() should always
* make us use a different parent than what we're currently using, so
* clk_gfx3d_set_rate_and_parent() should always be called.
*/
return 0;
}
const struct clk_ops clk_gfx3d_ops = {
.is_enabled = clk_rcg2_is_enabled,
.get_parent = clk_rcg2_get_parent,
.set_parent = clk_rcg2_set_parent,
.recalc_rate = clk_rcg2_recalc_rate,
.set_rate = clk_gfx3d_set_rate,
.set_rate_and_parent = clk_gfx3d_set_rate_and_parent,
.determine_rate = clk_gfx3d_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_gfx3d_ops);

View File

@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/reset-controller.h>
#include <linux/of.h>
#include "common.h"
#include "clk-rcg.h"
@ -88,6 +89,92 @@ static void qcom_cc_gdsc_unregister(void *data)
gdsc_unregister(data);
}
/*
* Backwards compatibility with old DTs. Register a pass-through factor 1/1
* clock to translate 'path' clk into 'name' clk and regsiter the 'path'
* clk as a fixed rate clock if it isn't present.
*/
static int _qcom_cc_register_board_clk(struct device *dev, const char *path,
const char *name, unsigned long rate,
bool add_factor)
{
struct device_node *node = NULL;
struct device_node *clocks_node;
struct clk_fixed_factor *factor;
struct clk_fixed_rate *fixed;
struct clk *clk;
struct clk_init_data init_data = { };
clocks_node = of_find_node_by_path("/clocks");
if (clocks_node)
node = of_find_node_by_name(clocks_node, path);
of_node_put(clocks_node);
if (!node) {
fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL);
if (!fixed)
return -EINVAL;
fixed->fixed_rate = rate;
fixed->hw.init = &init_data;
init_data.name = path;
init_data.flags = CLK_IS_ROOT;
init_data.ops = &clk_fixed_rate_ops;
clk = devm_clk_register(dev, &fixed->hw);
if (IS_ERR(clk))
return PTR_ERR(clk);
}
of_node_put(node);
if (add_factor) {
factor = devm_kzalloc(dev, sizeof(*factor), GFP_KERNEL);
if (!factor)
return -EINVAL;
factor->mult = factor->div = 1;
factor->hw.init = &init_data;
init_data.name = name;
init_data.parent_names = &path;
init_data.num_parents = 1;
init_data.flags = 0;
init_data.ops = &clk_fixed_factor_ops;
clk = devm_clk_register(dev, &factor->hw);
if (IS_ERR(clk))
return PTR_ERR(clk);
}
return 0;
}
int qcom_cc_register_board_clk(struct device *dev, const char *path,
const char *name, unsigned long rate)
{
bool add_factor = true;
struct device_node *node;
/* The RPM clock driver will add the factor clock if present */
if (IS_ENABLED(CONFIG_QCOM_RPMCC)) {
node = of_find_compatible_node(NULL, NULL, "qcom,rpmcc");
if (of_device_is_available(node))
add_factor = false;
of_node_put(node);
}
return _qcom_cc_register_board_clk(dev, path, name, rate, add_factor);
}
EXPORT_SYMBOL_GPL(qcom_cc_register_board_clk);
int qcom_cc_register_sleep_clk(struct device *dev)
{
return _qcom_cc_register_board_clk(dev, "sleep_clk", "sleep_clk_src",
32768, true);
}
EXPORT_SYMBOL_GPL(qcom_cc_register_sleep_clk);
int qcom_cc_really_probe(struct platform_device *pdev,
const struct qcom_cc_desc *desc, struct regmap *regmap)
{

View File

@ -37,6 +37,10 @@ extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
extern int qcom_find_src_index(struct clk_hw *hw, const struct parent_map *map,
u8 src);
extern int qcom_cc_register_board_clk(struct device *dev, const char *path,
const char *name, unsigned long rate);
extern int qcom_cc_register_sleep_clk(struct device *dev);
extern struct regmap *qcom_cc_map(struct platform_device *pdev,
const struct qcom_cc_desc *desc);
extern int qcom_cc_really_probe(struct platform_device *pdev,

View File

@ -3587,6 +3587,7 @@ static const struct regmap_config gcc_apq8084_regmap_config = {
.val_bits = 32,
.max_register = 0x1fc0,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_apq8084_desc = {
@ -3607,18 +3608,16 @@ MODULE_DEVICE_TABLE(of, gcc_apq8084_match_table);
static int gcc_apq8084_probe(struct platform_device *pdev)
{
struct clk *clk;
int ret;
struct device *dev = &pdev->dev;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
if (ret)
return ret;
clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
CLK_IS_ROOT, 32768);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_sleep_clk(dev);
if (ret)
return ret;
return qcom_cc_probe(pdev, &gcc_apq8084_desc);
}

View File

@ -3005,6 +3005,7 @@ static const struct regmap_config gcc_ipq806x_regmap_config = {
.val_bits = 32,
.max_register = 0x3e40,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_ipq806x_desc = {
@ -3023,19 +3024,17 @@ MODULE_DEVICE_TABLE(of, gcc_ipq806x_match_table);
static int gcc_ipq806x_probe(struct platform_device *pdev)
{
struct clk *clk;
struct device *dev = &pdev->dev;
struct regmap *regmap;
int ret;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
if (ret)
return ret;
clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 25000000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
if (ret)
return ret;
ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc);
if (ret)

View File

@ -2702,6 +2702,7 @@ static const struct regmap_config gcc_msm8660_regmap_config = {
.val_bits = 32,
.max_register = 0x363c,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8660_desc = {
@ -2720,17 +2721,16 @@ MODULE_DEVICE_TABLE(of, gcc_msm8660_match_table);
static int gcc_msm8660_probe(struct platform_device *pdev)
{
struct clk *clk;
int ret;
struct device *dev = &pdev->dev;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
if (ret)
return ret;
clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 27000000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
if (ret)
return ret;
return qcom_cc_probe(pdev, &gcc_msm8660_desc);
}

View File

@ -3336,6 +3336,7 @@ static const struct regmap_config gcc_msm8916_regmap_config = {
.val_bits = 32,
.max_register = 0x80000,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8916_desc = {
@ -3356,18 +3357,16 @@ MODULE_DEVICE_TABLE(of, gcc_msm8916_match_table);
static int gcc_msm8916_probe(struct platform_device *pdev)
{
struct clk *clk;
int ret;
struct device *dev = &pdev->dev;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
if (ret)
return ret;
clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
CLK_IS_ROOT, 32768);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_sleep_clk(dev);
if (ret)
return ret;
return qcom_cc_probe(pdev, &gcc_msm8916_desc);
}

View File

@ -3468,6 +3468,7 @@ static const struct regmap_config gcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0x3660,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct regmap_config gcc_apq8064_regmap_config = {
@ -3476,6 +3477,7 @@ static const struct regmap_config gcc_apq8064_regmap_config = {
.val_bits = 32,
.max_register = 0x3880,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8960_desc = {
@ -3503,7 +3505,6 @@ MODULE_DEVICE_TABLE(of, gcc_msm8960_match_table);
static int gcc_msm8960_probe(struct platform_device *pdev)
{
struct clk *clk;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
struct platform_device *tsens;
@ -3513,14 +3514,13 @@ static int gcc_msm8960_probe(struct platform_device *pdev)
if (!match)
return -EINVAL;
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 19200000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "cxo_board", "cxo", 19200000);
if (ret)
return ret;
clk = clk_register_fixed_rate(dev, "pxo", NULL, CLK_IS_ROOT, 27000000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "pxo_board", "pxo", 27000000);
if (ret)
return ret;
ret = qcom_cc_probe(pdev, match->data);
if (ret)

View File

@ -2680,6 +2680,7 @@ static const struct regmap_config gcc_msm8974_regmap_config = {
.val_bits = 32,
.max_register = 0x1fc0,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc gcc_msm8974_desc = {
@ -2717,7 +2718,7 @@ static void msm8974_pro_clock_override(void)
static int gcc_msm8974_probe(struct platform_device *pdev)
{
struct clk *clk;
int ret;
struct device *dev = &pdev->dev;
bool pro;
const struct of_device_id *id;
@ -2730,16 +2731,13 @@ static int gcc_msm8974_probe(struct platform_device *pdev)
if (pro)
msm8974_pro_clock_override();
/* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "xo", NULL, CLK_IS_ROOT, 19200000);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_board_clk(dev, "xo_board", "xo", 19200000);
if (ret)
return ret;
/* Should move to DT node? */
clk = clk_register_fixed_rate(dev, "sleep_clk_src", NULL,
CLK_IS_ROOT, 32768);
if (IS_ERR(clk))
return PTR_ERR(clk);
ret = qcom_cc_register_sleep_clk(dev);
if (ret)
return ret;
return qcom_cc_probe(pdev, &gcc_msm8974_desc);
}

File diff suppressed because it is too large Load Diff

View File

@ -419,6 +419,7 @@ static const struct regmap_config lcc_ipq806x_regmap_config = {
.val_bits = 32,
.max_register = 0xfc,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc lcc_ipq806x_desc = {

View File

@ -524,6 +524,7 @@ static const struct regmap_config lcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0xfc,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc lcc_msm8960_desc = {

View File

@ -3368,6 +3368,7 @@ static const struct regmap_config mmcc_apq8084_regmap_config = {
.val_bits = 32,
.max_register = 0x5104,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_apq8084_desc = {

View File

@ -3029,6 +3029,7 @@ static const struct regmap_config mmcc_msm8960_regmap_config = {
.val_bits = 32,
.max_register = 0x334,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct regmap_config mmcc_apq8064_regmap_config = {
@ -3037,6 +3038,7 @@ static const struct regmap_config mmcc_apq8064_regmap_config = {
.val_bits = 32,
.max_register = 0x350,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_msm8960_desc = {

View File

@ -2594,6 +2594,7 @@ static const struct regmap_config mmcc_msm8974_regmap_config = {
.val_bits = 32,
.max_register = 0x5104,
.fast_io = true,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
static const struct qcom_cc_desc mmcc_msm8974_desc = {

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,8 @@ obj-y += clk-inverter.o
obj-y += clk-mmc-phase.o
obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
obj-y += clk-rk3036.o
obj-y += clk-rk3188.o
obj-y += clk-rk3228.o
obj-y += clk-rk3288.o
obj-y += clk-rk3368.o

View File

@ -242,8 +242,8 @@ struct clk *rockchip_clk_register_cpuclk(const char *name,
struct clk *clk, *cclk;
int ret;
if (num_parents != 2) {
pr_err("%s: needs two parent clocks\n", __func__);
if (num_parents < 2) {
pr_err("%s: needs at least two parent clocks\n", __func__);
return ERR_PTR(-EINVAL);
}

View File

@ -2,6 +2,9 @@
* Copyright (c) 2014 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
* Copyright (c) 2015 Rockchip Electronics Co. Ltd.
* Author: Xing Zheng <zhengxing@rock-chips.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
@ -19,6 +22,7 @@
#include <linux/delay.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include "clk.h"
#define PLL_MODE_MASK 0x3
@ -107,6 +111,252 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
return -ETIMEDOUT;
}
/**
* PLL used in RK3036
*/
#define RK3036_PLLCON(i) (i * 0x4)
#define RK3036_PLLCON0_FBDIV_MASK 0xfff
#define RK3036_PLLCON0_FBDIV_SHIFT 0
#define RK3036_PLLCON0_POSTDIV1_MASK 0x7
#define RK3036_PLLCON0_POSTDIV1_SHIFT 12
#define RK3036_PLLCON1_REFDIV_MASK 0x3f
#define RK3036_PLLCON1_REFDIV_SHIFT 0
#define RK3036_PLLCON1_POSTDIV2_MASK 0x7
#define RK3036_PLLCON1_POSTDIV2_SHIFT 6
#define RK3036_PLLCON1_DSMPD_MASK 0x1
#define RK3036_PLLCON1_DSMPD_SHIFT 12
#define RK3036_PLLCON2_FRAC_MASK 0xffffff
#define RK3036_PLLCON2_FRAC_SHIFT 0
#define RK3036_PLLCON1_PWRDOWN (1 << 13)
static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll,
struct rockchip_pll_rate_table *rate)
{
u32 pllcon;
pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(0));
rate->fbdiv = ((pllcon >> RK3036_PLLCON0_FBDIV_SHIFT)
& RK3036_PLLCON0_FBDIV_MASK);
rate->postdiv1 = ((pllcon >> RK3036_PLLCON0_POSTDIV1_SHIFT)
& RK3036_PLLCON0_POSTDIV1_MASK);
pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(1));
rate->refdiv = ((pllcon >> RK3036_PLLCON1_REFDIV_SHIFT)
& RK3036_PLLCON1_REFDIV_MASK);
rate->postdiv2 = ((pllcon >> RK3036_PLLCON1_POSTDIV2_SHIFT)
& RK3036_PLLCON1_POSTDIV2_MASK);
rate->dsmpd = ((pllcon >> RK3036_PLLCON1_DSMPD_SHIFT)
& RK3036_PLLCON1_DSMPD_MASK);
pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
rate->frac = ((pllcon >> RK3036_PLLCON2_FRAC_SHIFT)
& RK3036_PLLCON2_FRAC_MASK);
}
static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
unsigned long prate)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
struct rockchip_pll_rate_table cur;
u64 rate64 = prate;
rockchip_rk3036_pll_get_params(pll, &cur);
rate64 *= cur.fbdiv;
do_div(rate64, cur.refdiv);
if (cur.dsmpd == 0) {
/* fractional mode */
u64 frac_rate64 = prate * cur.frac;
do_div(frac_rate64, cur.refdiv);
rate64 += frac_rate64 >> 24;
}
do_div(rate64, cur.postdiv1);
do_div(rate64, cur.postdiv2);
return (unsigned long)rate64;
}
static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
const struct rockchip_pll_rate_table *rate)
{
const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
struct clk_mux *pll_mux = &pll->pll_mux;
struct rockchip_pll_rate_table cur;
u32 pllcon;
int rate_change_remuxed = 0;
int cur_parent;
int ret;
pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
__func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv,
rate->postdiv2, rate->dsmpd, rate->frac);
rockchip_rk3036_pll_get_params(pll, &cur);
cur.rate = 0;
cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
if (cur_parent == PLL_MODE_NORM) {
pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
rate_change_remuxed = 1;
}
/* update pll values */
writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3036_PLLCON0_FBDIV_MASK,
RK3036_PLLCON0_FBDIV_SHIFT) |
HIWORD_UPDATE(rate->postdiv1, RK3036_PLLCON0_POSTDIV1_MASK,
RK3036_PLLCON0_POSTDIV1_SHIFT),
pll->reg_base + RK3036_PLLCON(0));
writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3036_PLLCON1_REFDIV_MASK,
RK3036_PLLCON1_REFDIV_SHIFT) |
HIWORD_UPDATE(rate->postdiv2, RK3036_PLLCON1_POSTDIV2_MASK,
RK3036_PLLCON1_POSTDIV2_SHIFT) |
HIWORD_UPDATE(rate->dsmpd, RK3036_PLLCON1_DSMPD_MASK,
RK3036_PLLCON1_DSMPD_SHIFT),
pll->reg_base + RK3036_PLLCON(1));
/* GPLL CON2 is not HIWORD_MASK */
pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
pllcon &= ~(RK3036_PLLCON2_FRAC_MASK << RK3036_PLLCON2_FRAC_SHIFT);
pllcon |= rate->frac << RK3036_PLLCON2_FRAC_SHIFT;
writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2));
/* wait for the pll to lock */
ret = rockchip_pll_wait_lock(pll);
if (ret) {
pr_warn("%s: pll update unsucessful, trying to restore old params\n",
__func__);
rockchip_rk3036_pll_set_params(pll, &cur);
}
if (rate_change_remuxed)
pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
return ret;
}
static int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
const struct rockchip_pll_rate_table *rate;
unsigned long old_rate = rockchip_rk3036_pll_recalc_rate(hw, prate);
struct regmap *grf = rockchip_clk_get_grf();
if (IS_ERR(grf)) {
pr_debug("%s: grf regmap not available, aborting rate change\n",
__func__);
return PTR_ERR(grf);
}
pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
__func__, __clk_get_name(hw->clk), old_rate, drate, prate);
/* Get required rate settings from table */
rate = rockchip_get_pll_settings(pll, drate);
if (!rate) {
pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
drate, __clk_get_name(hw->clk));
return -EINVAL;
}
return rockchip_rk3036_pll_set_params(pll, rate);
}
static int rockchip_rk3036_pll_enable(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
pll->reg_base + RK3036_PLLCON(1));
return 0;
}
static void rockchip_rk3036_pll_disable(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN,
RK3036_PLLCON1_PWRDOWN, 0),
pll->reg_base + RK3036_PLLCON(1));
}
static int rockchip_rk3036_pll_is_enabled(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
u32 pllcon = readl(pll->reg_base + RK3036_PLLCON(1));
return !(pllcon & RK3036_PLLCON1_PWRDOWN);
}
static void rockchip_rk3036_pll_init(struct clk_hw *hw)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
const struct rockchip_pll_rate_table *rate;
struct rockchip_pll_rate_table cur;
unsigned long drate;
if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
return;
drate = clk_hw_get_rate(hw);
rate = rockchip_get_pll_settings(pll, drate);
/* when no rate setting for the current rate, rely on clk_set_rate */
if (!rate)
return;
rockchip_rk3036_pll_get_params(pll, &cur);
pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk),
drate);
pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2,
cur.dsmpd, cur.frac);
pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2,
rate->dsmpd, rate->frac);
if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 ||
rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 ||
rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) {
struct clk *parent = clk_get_parent(hw->clk);
if (!parent) {
pr_warn("%s: parent of %s not available\n",
__func__, __clk_get_name(hw->clk));
return;
}
pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
__func__, __clk_get_name(hw->clk));
rockchip_rk3036_pll_set_params(pll, rate);
}
}
static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = {
.recalc_rate = rockchip_rk3036_pll_recalc_rate,
.enable = rockchip_rk3036_pll_enable,
.disable = rockchip_rk3036_pll_disable,
.is_enabled = rockchip_rk3036_pll_is_enabled,
};
static const struct clk_ops rockchip_rk3036_pll_clk_ops = {
.recalc_rate = rockchip_rk3036_pll_recalc_rate,
.round_rate = rockchip_pll_round_rate,
.set_rate = rockchip_rk3036_pll_set_rate,
.enable = rockchip_rk3036_pll_enable,
.disable = rockchip_rk3036_pll_disable,
.is_enabled = rockchip_rk3036_pll_is_enabled,
.init = rockchip_rk3036_pll_init,
};
/**
* PLL used in RK3066, RK3188 and RK3288
*/
@ -376,7 +626,7 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
pll_mux->lock = lock;
pll_mux->hw.init = &init;
if (pll_type == pll_rk3066)
if (pll_type == pll_rk3036 || pll_type == pll_rk3066)
pll_mux->flags |= CLK_MUX_HIWORD_MASK;
/* the actual muxing is xin24m, pll-output, xin32k */
@ -421,6 +671,12 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
}
switch (pll_type) {
case pll_rk3036:
if (!pll->rate_table)
init.ops = &rockchip_rk3036_pll_clk_norate_ops;
else
init.ops = &rockchip_rk3036_pll_clk_ops;
break;
case pll_rk3066:
if (!pll->rate_table)
init.ops = &rockchip_rk3066_pll_clk_norate_ops;

View File

@ -0,0 +1,493 @@
/*
* Copyright (c) 2014 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
* Copyright (c) 2015 Rockchip Electronics Co. Ltd.
* Author: Xing Zheng <zhengxing@rock-chips.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.
*
* 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/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
#include <dt-bindings/clock/rk3036-cru.h>
#include "clk.h"
#define RK3036_GRF_SOC_STATUS0 0x14c
enum rk3036_plls {
apll, dpll, gpll,
};
static struct rockchip_pll_rate_table rk3036_pll_rates[] = {
/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0),
RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0),
{ /* sentinel */ },
};
#define RK3036_DIV_CPU_MASK 0x1f
#define RK3036_DIV_CPU_SHIFT 8
#define RK3036_DIV_PERI_MASK 0xf
#define RK3036_DIV_PERI_SHIFT 0
#define RK3036_DIV_ACLK_MASK 0x7
#define RK3036_DIV_ACLK_SHIFT 4
#define RK3036_DIV_HCLK_MASK 0x3
#define RK3036_DIV_HCLK_SHIFT 8
#define RK3036_DIV_PCLK_MASK 0x7
#define RK3036_DIV_PCLK_SHIFT 12
#define RK3036_CLKSEL1(_core_periph_div) \
{ \
.reg = RK2928_CLKSEL_CON(1), \
.val = HIWORD_UPDATE(_core_periph_div, RK3036_DIV_PERI_MASK, \
RK3036_DIV_PERI_SHIFT) \
}
#define RK3036_CPUCLK_RATE(_prate, _core_periph_div) \
{ \
.prate = _prate, \
.divs = { \
RK3036_CLKSEL1(_core_periph_div), \
}, \
}
static struct rockchip_cpuclk_rate_table rk3036_cpuclk_rates[] __initdata = {
RK3036_CPUCLK_RATE(816000000, 4),
RK3036_CPUCLK_RATE(600000000, 4),
RK3036_CPUCLK_RATE(312000000, 4),
};
static const struct rockchip_cpuclk_reg_data rk3036_cpuclk_data = {
.core_reg = RK2928_CLKSEL_CON(0),
.div_core_shift = 0,
.div_core_mask = 0x1f,
.mux_core_shift = 7,
};
PNAME(mux_pll_p) = { "xin24m", "xin24m" };
PNAME(mux_armclk_p) = { "apll", "gpll_armclk" };
PNAME(mux_busclk_p) = { "apll", "dpll_cpu", "gpll_cpu" };
PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" };
PNAME(mux_pll_src_3plls_p) = { "apll", "dpll", "gpll" };
PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" };
PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p) = { "apll", "dpll", "gpll" "usb480m" };
PNAME(mux_mmc_src_p) = { "apll", "dpll", "gpll", "xin24m" };
PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" };
PNAME(mux_i2s_clkout_p) = { "i2s_pre", "xin12m" };
PNAME(mux_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" };
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_mac_p) = { "mac_pll_src", "ext_gmac" };
PNAME(mux_dclk_p) = { "dclk_lcdc", "dclk_cru" };
static struct rockchip_pll_clock rk3036_pll_clks[] __initdata = {
[apll] = PLL(pll_rk3036, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
RK2928_MODE_CON, 0, 5, 0, rk3036_pll_rates),
[dpll] = PLL(pll_rk3036, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4),
RK2928_MODE_CON, 4, 4, 0, NULL),
[gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12),
RK2928_MODE_CON, 12, 6, ROCKCHIP_PLL_SYNC_RATE, rk3036_pll_rates),
};
#define MFLAGS CLK_MUX_HIWORD_MASK
#define DFLAGS CLK_DIVIDER_HIWORD_MASK
#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
static struct rockchip_clk_branch rk3036_uart0_fracmux __initdata =
MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(13), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3036_uart1_fracmux __initdata =
MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(14), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3036_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 rk3036_i2s_fracmux __initdata =
MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3036_spdif_fracmux __initdata =
MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0,
RK2928_CLKSEL_CON(5), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
/*
* Clock-Architecture Diagram 1
*/
GATE(0, "gpll_armclk", "gpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 6, GFLAGS),
/*
* Clock-Architecture Diagram 2
*/
GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 2, GFLAGS),
GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 8, GFLAGS),
COMPOSITE_NOGATE(0, "ddrphy2x", mux_ddrphy_p, CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(26), 8, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK2928_CLKGATE_CON(0), 7, GFLAGS),
COMPOSITE_NOMUX(0, "aclk_core_pre", "armclk", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK2928_CLKGATE_CON(0), 7, GFLAGS),
GATE(0, "dpll_cpu", "dpll", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS),
GATE(0, "gpll_cpu", "gpll", 0, RK2928_CLKGATE_CON(0), 1, GFLAGS),
COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_busclk_p, 0,
RK2928_CLKSEL_CON(0), 14, 2, MFLAGS, 8, 5, DFLAGS),
GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 3, GFLAGS),
COMPOSITE_NOMUX(PCLK_CPU, "pclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(1), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK2928_CLKGATE_CON(0), 5, GFLAGS),
COMPOSITE_NOMUX(HCLK_CPU, "hclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK2928_CLKGATE_CON(0), 4, GFLAGS),
COMPOSITE(0, "aclk_peri_src", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(10), 14, 2, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(2), 0, GFLAGS),
GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0,
RK2928_CLKGATE_CON(2), 1, GFLAGS),
DIV(0, "pclk_peri_src", "aclk_peri_src", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
GATE(PCLK_PERI, "pclk_peri", "pclk_peri_src", 0,
RK2928_CLKGATE_CON(2), 3, GFLAGS),
DIV(0, "hclk_peri_src", "aclk_peri_src", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
GATE(HCLK_PERI, "hclk_peri", "hclk_peri_src", 0,
RK2928_CLKGATE_CON(2), 2, GFLAGS),
COMPOSITE_NODIV(SCLK_TIMER0, "sclk_timer0", mux_timer_p, CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(2), 4, 1, DFLAGS,
RK2928_CLKGATE_CON(1), 0, GFLAGS),
COMPOSITE_NODIV(SCLK_TIMER1, "sclk_timer1", mux_timer_p, CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(2), 5, 1, DFLAGS,
RK2928_CLKGATE_CON(1), 1, GFLAGS),
COMPOSITE_NODIV(SCLK_TIMER2, "sclk_timer2", mux_timer_p, CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(2), 6, 1, DFLAGS,
RK2928_CLKGATE_CON(2), 4, GFLAGS),
COMPOSITE_NODIV(SCLK_TIMER3, "sclk_timer3", mux_timer_p, CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(2), 7, 1, DFLAGS,
RK2928_CLKGATE_CON(2), 5, GFLAGS),
MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
RK2928_CLKSEL_CON(13), 10, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart0_src", "uart_pll_clk", 0,
RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 8, GFLAGS),
COMPOSITE_NOMUX(0, "uart1_src", "uart_pll_clk", 0,
RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 8, GFLAGS),
COMPOSITE_NOMUX(0, "uart2_src", "uart_pll_clk", 0,
RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 8, GFLAGS),
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(17), 0,
RK2928_CLKGATE_CON(1), 9, GFLAGS,
&rk3036_uart0_fracmux),
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(18), 0,
RK2928_CLKGATE_CON(1), 11, GFLAGS,
&rk3036_uart1_fracmux),
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(19), 0,
RK2928_CLKGATE_CON(1), 13, GFLAGS,
&rk3036_uart2_fracmux),
COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 11, GFLAGS),
COMPOSITE(0, "aclk_hvec", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS,
RK2928_CLKGATE_CON(10), 6, GFLAGS),
COMPOSITE(0, "aclk_disp1_pre", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(1), 4, GFLAGS),
COMPOSITE(0, "hclk_disp_pre", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(0), 11, GFLAGS),
COMPOSITE(SCLK_LCDC, "dclk_lcdc", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(28), 0, 2, MFLAGS, 8, 8, DFLAGS,
RK2928_CLKGATE_CON(3), 2, GFLAGS),
COMPOSITE_NODIV(0, "sclk_sdmmc_src", mux_mmc_src_p, 0,
RK2928_CLKSEL_CON(12), 8, 2, DFLAGS,
RK2928_CLKGATE_CON(2), 11, GFLAGS),
DIV(SCLK_SDMMC, "sclk_sdmmc", "sclk_sdmmc_src", 0,
RK2928_CLKSEL_CON(11), 0, 7, DFLAGS),
COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
RK2928_CLKSEL_CON(12), 10, 2, DFLAGS,
RK2928_CLKGATE_CON(2), 13, GFLAGS),
DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
RK2928_CLKSEL_CON(11), 8, 7, DFLAGS),
COMPOSITE(SCLK_EMMC, "sclk_emmc", mux_mmc_src_p, 0,
RK2928_CLKSEL_CON(12), 12, 2, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(2), 14, GFLAGS),
MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3036_SDMMC_CON0, 1),
MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3036_SDMMC_CON1, 0),
MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3036_SDIO_CON0, 1),
MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3036_SDIO_CON1, 0),
MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3036_EMMC_CON0, 1),
MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3036_EMMC_CON1, 0),
COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 9, GFLAGS),
COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(7), 0,
RK2928_CLKGATE_CON(0), 10, GFLAGS,
&rk3036_i2s_fracmux),
COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_clkout", mux_i2s_clkout_p, 0,
RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
RK2928_CLKGATE_CON(0), 13, GFLAGS),
GATE(SCLK_I2S, "sclk_i2s", "i2s_pre", CLK_SET_RATE_PARENT,
RK2928_CLKGATE_CON(0), 14, GFLAGS),
COMPOSITE(0, "spdif_src", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(5), 10, 2, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(2), 10, GFLAGS),
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", 0,
RK2928_CLKSEL_CON(9), 0,
RK2928_CLKGATE_CON(2), 12, GFLAGS,
&rk3036_spdif_fracmux),
GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(1), 5, GFLAGS),
COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(34), 8, 2, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 13, GFLAGS),
COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(25), 8, 2, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(2), 9, GFLAGS),
COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS,
RK2928_CLKGATE_CON(10), 4, GFLAGS),
COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS,
RK2928_CLKGATE_CON(10), 5, GFLAGS),
COMPOSITE_NOGATE(0, "mac_pll_src", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 4, 5, DFLAGS),
MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(21), 3, 1, MFLAGS),
COMPOSITE_NOMUX(SCLK_MAC, "mac_clk", "mac_clk_ref", 0,
RK2928_CLKSEL_CON(21), 9, 5, DFLAGS,
RK2928_CLKGATE_CON(2), 6, GFLAGS),
MUX(SCLK_HDMI, "dclk_hdmi", mux_dclk_p, 0,
RK2928_CLKSEL_CON(31), 0, 1, MFLAGS),
/*
* Clock-Architecture Diagram 3
*/
/* aclk_cpu gates */
GATE(0, "sclk_intmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 12, GFLAGS),
GATE(0, "aclk_strc_sys", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 10, GFLAGS),
/* hclk_cpu gates */
GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 6, GFLAGS),
/* pclk_cpu gates */
GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS),
GATE(PCLK_DDRUPCTL, "pclk_ddrupctl", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 7, GFLAGS),
GATE(PCLK_ACODEC, "pclk_acodec", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS),
GATE(PCLK_HDMI, "pclk_hdmi", "pclk_cpu", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS),
/* aclk_vio gates */
GATE(ACLK_VIO, "aclk_vio", "aclk_disp1_pre", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(6), 13, GFLAGS),
GATE(ACLK_LCDC, "aclk_lcdc", "aclk_disp1_pre", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS),
GATE(HCLK_VIO_BUS, "hclk_vio_bus", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(6), 12, GFLAGS),
GATE(HCLK_LCDC, "hclk_lcdc", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS),
/* hclk_video gates */
GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(3), 12, GFLAGS),
/* xin24m gates */
GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK2928_CLKGATE_CON(10), 0, GFLAGS),
GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK2928_CLKGATE_CON(10), 1, GFLAGS),
/* aclk_peri gates */
GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 3, GFLAGS),
GATE(0, "aclk_cpu_peri", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 2, GFLAGS),
GATE(ACLK_DMAC2, "aclk_dmac2", "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),
/* hclk_peri gates */
GATE(0, "hclk_peri_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS),
GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 13, GFLAGS),
GATE(0, "hclk_peri_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 14, GFLAGS),
GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 9, GFLAGS),
GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 10, GFLAGS),
GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 11, GFLAGS),
GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 0, GFLAGS),
GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS),
GATE(HCLK_OTG1, "hclk_otg1", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 3, GFLAGS),
GATE(HCLK_I2S, "hclk_i2s", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
GATE(0, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS),
GATE(0, "hclk_mac", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 15, GFLAGS),
/* pclk_peri gates */
GATE(0, "pclk_peri_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 1, GFLAGS),
GATE(0, "pclk_efuse", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 2, GFLAGS),
GATE(PCLK_TIMER, "pclk_timer", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 7, GFLAGS),
GATE(PCLK_PWM, "pclk_pwm", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 10, GFLAGS),
GATE(PCLK_SPI, "pclk_spi", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 12, GFLAGS),
GATE(PCLK_WDT, "pclk_wdt", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS),
GATE(PCLK_UART0, "pclk_uart0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS),
GATE(PCLK_UART1, "pclk_uart1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS),
GATE(PCLK_UART2, "pclk_uart2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS),
GATE(PCLK_I2C0, "pclk_i2c0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
GATE(PCLK_I2C1, "pclk_i2c1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 5, GFLAGS),
GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS),
GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 10, GFLAGS),
GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS),
};
static const char *const rk3036_critical_clocks[] __initconst = {
"aclk_cpu",
"aclk_peri",
"hclk_peri",
"pclk_peri",
};
static void __init rk3036_clk_init(struct device_node *np)
{
void __iomem *reg_base;
struct clk *clk;
reg_base = of_iomap(np, 0);
if (!reg_base) {
pr_err("%s: could not map cru region\n", __func__);
return;
}
rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
/* xin12m is created by an cru-internal divider */
clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
if (IS_ERR(clk))
pr_warn("%s: could not register clock xin12m: %ld\n",
__func__, PTR_ERR(clk));
clk = clk_register_fixed_factor(NULL, "usb480m", "xin24m", 0, 20, 1);
if (IS_ERR(clk))
pr_warn("%s: could not register clock usb480m: %ld\n",
__func__, PTR_ERR(clk));
clk = clk_register_fixed_factor(NULL, "ddrphy", "ddrphy2x", 0, 1, 2);
if (IS_ERR(clk))
pr_warn("%s: could not register clock ddrphy: %ld\n",
__func__, PTR_ERR(clk));
clk = clk_register_fixed_factor(NULL, "hclk_vcodec_pre",
"aclk_vcodec", 0, 1, 4);
if (IS_ERR(clk))
pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
__func__, PTR_ERR(clk));
clk = clk_register_fixed_factor(NULL, "sclk_macref_out",
"hclk_peri_src", 0, 1, 2);
if (IS_ERR(clk))
pr_warn("%s: could not register clock sclk_macref_out: %ld\n",
__func__, PTR_ERR(clk));
rockchip_clk_register_plls(rk3036_pll_clks,
ARRAY_SIZE(rk3036_pll_clks),
RK3036_GRF_SOC_STATUS0);
rockchip_clk_register_branches(rk3036_clk_branches,
ARRAY_SIZE(rk3036_clk_branches));
rockchip_clk_protect_critical(rk3036_critical_clocks,
ARRAY_SIZE(rk3036_critical_clocks));
rockchip_clk_register_armclk(ARMCLK, "armclk",
mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
&rk3036_cpuclk_data, rk3036_cpuclk_rates,
ARRAY_SIZE(rk3036_cpuclk_rates));
rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL);
}
CLK_OF_DECLARE(rk3036_cru, "rockchip,rk3036-cru", rk3036_clk_init);

View File

@ -247,6 +247,30 @@ static struct clk_div_table div_core_peri_t[] = {
{ /* sentinel */ },
};
static struct rockchip_clk_branch common_hsadc_out_fracmux __initdata =
MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0,
RK2928_CLKSEL_CON(22), 4, 2, MFLAGS);
static struct rockchip_clk_branch common_spdif_fracmux __initdata =
MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(5), 8, 2, MFLAGS);
static struct rockchip_clk_branch common_uart0_fracmux __initdata =
MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0,
RK2928_CLKSEL_CON(13), 8, 2, MFLAGS);
static struct rockchip_clk_branch common_uart1_fracmux __initdata =
MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0,
RK2928_CLKSEL_CON(14), 8, 2, MFLAGS);
static struct rockchip_clk_branch common_uart2_fracmux __initdata =
MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0,
RK2928_CLKSEL_CON(15), 8, 2, MFLAGS);
static struct rockchip_clk_branch common_uart3_fracmux __initdata =
MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0,
RK2928_CLKSEL_CON(16), 8, 2, MFLAGS);
static struct rockchip_clk_branch common_clk_branches[] __initdata = {
/*
* Clock-Architecture Diagram 2
@ -335,11 +359,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE(0, "hsadc_src", mux_pll_src_gpll_cpll_p, 0,
RK2928_CLKSEL_CON(22), 0, 1, MFLAGS, 8, 8, DFLAGS,
RK2928_CLKGATE_CON(2), 6, GFLAGS),
COMPOSITE_FRAC(0, "hsadc_frac", "hsadc_src", 0,
COMPOSITE_FRACMUX(0, "hsadc_frac", "hsadc_src", 0,
RK2928_CLKSEL_CON(23), 0,
RK2928_CLKGATE_CON(2), 7, GFLAGS),
MUX(0, "sclk_hsadc_out", mux_sclk_hsadc_p, 0,
RK2928_CLKSEL_CON(22), 4, 2, MFLAGS),
RK2928_CLKGATE_CON(2), 7, GFLAGS,
&common_hsadc_out_fracmux),
INVERTER(SCLK_HSADC, "sclk_hsadc", "sclk_hsadc_out",
RK2928_CLKSEL_CON(22), 7, IFLAGS),
@ -350,11 +373,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "spdif_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(5), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 13, GFLAGS),
COMPOSITE_FRAC(0, "spdif_frac", "spdif_pre", CLK_SET_RATE_PARENT,
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_pll", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(9), 0,
RK2928_CLKGATE_CON(0), 14, GFLAGS),
MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(5), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(0), 14, GFLAGS,
&common_spdif_fracmux),
/*
* Clock-Architecture Diagram 4
@ -385,35 +407,31 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "uart0_pre", "uart_src", 0,
RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 8, GFLAGS),
COMPOSITE_FRAC(0, "uart0_frac", "uart0_pre", 0,
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_pre", 0,
RK2928_CLKSEL_CON(17), 0,
RK2928_CLKGATE_CON(1), 9, GFLAGS),
MUX(SCLK_UART0, "sclk_uart0", mux_sclk_uart0_p, 0,
RK2928_CLKSEL_CON(13), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(1), 9, GFLAGS,
&common_uart0_fracmux),
COMPOSITE_NOMUX(0, "uart1_pre", "uart_src", 0,
RK2928_CLKSEL_CON(14), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 10, GFLAGS),
COMPOSITE_FRAC(0, "uart1_frac", "uart1_pre", 0,
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_pre", 0,
RK2928_CLKSEL_CON(18), 0,
RK2928_CLKGATE_CON(1), 11, GFLAGS),
MUX(SCLK_UART1, "sclk_uart1", mux_sclk_uart1_p, 0,
RK2928_CLKSEL_CON(14), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(1), 11, GFLAGS,
&common_uart1_fracmux),
COMPOSITE_NOMUX(0, "uart2_pre", "uart_src", 0,
RK2928_CLKSEL_CON(15), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 12, GFLAGS),
COMPOSITE_FRAC(0, "uart2_frac", "uart2_pre", 0,
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_pre", 0,
RK2928_CLKSEL_CON(19), 0,
RK2928_CLKGATE_CON(1), 13, GFLAGS),
MUX(SCLK_UART2, "sclk_uart2", mux_sclk_uart2_p, 0,
RK2928_CLKSEL_CON(15), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(1), 13, GFLAGS,
&common_uart2_fracmux),
COMPOSITE_NOMUX(0, "uart3_pre", "uart_src", 0,
RK2928_CLKSEL_CON(16), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 14, GFLAGS),
COMPOSITE_FRAC(0, "uart3_frac", "uart3_pre", 0,
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_pre", 0,
RK2928_CLKSEL_CON(20), 0,
RK2928_CLKGATE_CON(1), 15, GFLAGS),
MUX(SCLK_UART3, "sclk_uart3", mux_sclk_uart3_p, 0,
RK2928_CLKSEL_CON(16), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(1), 15, GFLAGS,
&common_uart3_fracmux),
GATE(SCLK_JTAG, "jtag", "ext_jtag", 0, RK2928_CLKGATE_CON(1), 3, GFLAGS),
@ -523,6 +541,18 @@ static struct clk_div_table div_aclk_cpu_t[] = {
{ /* sentinel */ },
};
static struct rockchip_clk_branch rk3066a_i2s0_fracmux __initdata =
MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
RK2928_CLKSEL_CON(2), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3066a_i2s1_fracmux __initdata =
MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0,
RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3066a_i2s2_fracmux __initdata =
MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0,
RK2928_CLKSEL_CON(4), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
DIVTBL(0, "aclk_cpu_pre", "armclk", 0,
RK2928_CLKSEL_CON(1), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, div_aclk_cpu_t),
@ -584,27 +614,24 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(2), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 7, GFLAGS),
COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0,
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
RK2928_CLKSEL_CON(6), 0,
RK2928_CLKGATE_CON(0), 8, GFLAGS),
MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
RK2928_CLKSEL_CON(2), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(0), 8, GFLAGS,
&rk3066a_i2s0_fracmux),
COMPOSITE_NOMUX(0, "i2s1_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 9, GFLAGS),
COMPOSITE_FRAC(0, "i2s1_frac", "i2s1_pre", 0,
COMPOSITE_FRACMUX(0, "i2s1_frac", "i2s1_pre", 0,
RK2928_CLKSEL_CON(7), 0,
RK2928_CLKGATE_CON(0), 10, GFLAGS),
MUX(SCLK_I2S1, "sclk_i2s1", mux_sclk_i2s1_p, 0,
RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(0), 10, GFLAGS,
&rk3066a_i2s1_fracmux),
COMPOSITE_NOMUX(0, "i2s2_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(4), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 11, GFLAGS),
COMPOSITE_FRAC(0, "i2s2_frac", "i2s2_pre", 0,
COMPOSITE_FRACMUX(0, "i2s2_frac", "i2s2_pre", 0,
RK2928_CLKSEL_CON(8), 0,
RK2928_CLKGATE_CON(0), 12, GFLAGS),
MUX(SCLK_I2S2, "sclk_i2s2", mux_sclk_i2s2_p, 0,
RK2928_CLKSEL_CON(4), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(0), 12, GFLAGS,
&rk3066a_i2s2_fracmux),
GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
@ -638,6 +665,10 @@ static struct clk_div_table div_rk3188_aclk_core_t[] = {
PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1",
"gpll", "cpll" };
static struct rockchip_clk_branch rk3188_i2s0_fracmux __initdata =
MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
RK2928_CLKSEL_CON(3), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
@ -691,11 +722,10 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
COMPOSITE_NOMUX(0, "i2s0_pre", "i2s_src", 0,
RK2928_CLKSEL_CON(3), 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 9, GFLAGS),
COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_pre", 0,
COMPOSITE_FRACMUX(0, "i2s0_frac", "i2s0_pre", 0,
RK2928_CLKSEL_CON(7), 0,
RK2928_CLKGATE_CON(0), 10, GFLAGS),
MUX(SCLK_I2S0, "sclk_i2s0", mux_sclk_i2s0_p, 0,
RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
RK2928_CLKGATE_CON(0), 10, GFLAGS,
&rk3188_i2s0_fracmux),
GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
@ -750,7 +780,7 @@ static void __init rk3188_common_clk_init(struct device_node *np)
rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
rockchip_register_restart_notifier(RK2928_GLB_SRST_FST);
rockchip_register_restart_notifier(RK2928_GLB_SRST_FST, NULL);
}
static void __init rk3066a_clk_init(struct device_node *np)

View File

@ -0,0 +1,678 @@
/*
* Copyright (c) 2015 Rockchip Electronics Co. Ltd.
* Author: Xing Zheng <zhengxing@rock-chips.com>
* Jeffy Chen <jeffy.chen@rock-chips.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.
*
* 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/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/syscore_ops.h>
#include <dt-bindings/clock/rk3228-cru.h>
#include "clk.h"
#define RK3228_GRF_SOC_STATUS0 0x480
enum rk3228_plls {
apll, dpll, cpll, gpll,
};
static struct rockchip_pll_rate_table rk3228_pll_rates[] = {
/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0),
RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0),
{ /* sentinel */ },
};
#define RK3228_DIV_CPU_MASK 0x1f
#define RK3228_DIV_CPU_SHIFT 8
#define RK3228_DIV_PERI_MASK 0xf
#define RK3228_DIV_PERI_SHIFT 0
#define RK3228_DIV_ACLK_MASK 0x7
#define RK3228_DIV_ACLK_SHIFT 4
#define RK3228_DIV_HCLK_MASK 0x3
#define RK3228_DIV_HCLK_SHIFT 8
#define RK3228_DIV_PCLK_MASK 0x7
#define RK3228_DIV_PCLK_SHIFT 12
#define RK3228_CLKSEL1(_core_peri_div) \
{ \
.reg = RK2928_CLKSEL_CON(1), \
.val = HIWORD_UPDATE(_core_peri_div, RK3228_DIV_PERI_MASK, \
RK3228_DIV_PERI_SHIFT) \
}
#define RK3228_CPUCLK_RATE(_prate, _core_peri_div) \
{ \
.prate = _prate, \
.divs = { \
RK3228_CLKSEL1(_core_peri_div), \
}, \
}
static struct rockchip_cpuclk_rate_table rk3228_cpuclk_rates[] __initdata = {
RK3228_CPUCLK_RATE(816000000, 4),
RK3228_CPUCLK_RATE(600000000, 4),
RK3228_CPUCLK_RATE(312000000, 4),
};
static const struct rockchip_cpuclk_reg_data rk3228_cpuclk_data = {
.core_reg = RK2928_CLKSEL_CON(0),
.div_core_shift = 0,
.div_core_mask = 0x1f,
.mux_core_shift = 6,
};
PNAME(mux_pll_p) = { "clk_24m", "xin24m" };
PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr", "apll_ddr" };
PNAME(mux_armclk_p) = { "apll_core", "gpll_core", "dpll_core" };
PNAME(mux_usb480m_phy_p) = { "usb480m_phy0", "usb480m_phy1" };
PNAME(mux_usb480m_p) = { "usb480m_phy", "xin24m" };
PNAME(mux_hdmiphy_p) = { "hdmiphy_phy", "xin24m" };
PNAME(mux_aclk_cpu_src_p) = { "cpll_aclk_cpu", "gpll_aclk_cpu", "hdmiphy_aclk_cpu" };
PNAME(mux_pll_src_4plls_p) = { "cpll", "gpll", "hdmiphy" "usb480m" };
PNAME(mux_pll_src_3plls_p) = { "cpll", "gpll", "hdmiphy" };
PNAME(mux_pll_src_2plls_p) = { "cpll", "gpll" };
PNAME(mux_sclk_hdmi_cec_p) = { "cpll", "gpll", "xin24m" };
PNAME(mux_aclk_peri_src_p) = { "cpll_peri", "gpll_peri", "hdmiphy_peri" };
PNAME(mux_mmc_src_p) = { "cpll", "gpll", "xin24m", "usb480m" };
PNAME(mux_pll_src_cpll_gpll_usb480m_p) = { "cpll", "gpll", "usb480m" };
PNAME(mux_sclk_rga_p) = { "gpll", "cpll", "sclk_rga_src" };
PNAME(mux_sclk_vop_src_p) = { "gpll_vop", "cpll_vop" };
PNAME(mux_dclk_vop_p) = { "hdmiphy", "sclk_vop_pre" };
PNAME(mux_i2s0_p) = { "i2s0_src", "i2s0_frac", "ext_i2s", "xin12m" };
PNAME(mux_i2s1_pre_p) = { "i2s1_src", "i2s1_frac", "ext_i2s", "xin12m" };
PNAME(mux_i2s_out_p) = { "i2s1_pre", "xin12m" };
PNAME(mux_i2s2_p) = { "i2s2_src", "i2s2_frac", "xin12m" };
PNAME(mux_sclk_spdif_p) = { "sclk_spdif_src", "spdif_frac", "xin12m" };
PNAME(mux_aclk_gpu_pre_p) = { "cpll_gpu", "gpll_gpu", "hdmiphy_gpu", "usb480m_gpu" };
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_50m_p) = { "ext_gmac", "phy_50m_out" };
PNAME(mux_sclk_gmac_pre_p) = { "sclk_gmac_src", "sclk_macphy_50m" };
PNAME(mux_sclk_macphy_p) = { "sclk_gmac_src", "ext_gmac" };
static struct rockchip_pll_clock rk3228_pll_clks[] __initdata = {
[apll] = PLL(pll_rk3036, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
RK2928_MODE_CON, 0, 7, 0, rk3228_pll_rates),
[dpll] = PLL(pll_rk3036, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(3),
RK2928_MODE_CON, 4, 6, 0, NULL),
[cpll] = PLL(pll_rk3036, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(6),
RK2928_MODE_CON, 8, 8, 0, NULL),
[gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(9),
RK2928_MODE_CON, 12, 9, ROCKCHIP_PLL_SYNC_RATE, rk3228_pll_rates),
};
#define MFLAGS CLK_MUX_HIWORD_MASK
#define DFLAGS CLK_DIVIDER_HIWORD_MASK
#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
static struct rockchip_clk_branch rk3228_clk_branches[] __initdata = {
/*
* Clock-Architecture Diagram 1
*/
DIV(0, "clk_24m", "xin24m", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(4), 8, 5, DFLAGS),
/* PD_DDR */
GATE(0, "apll_ddr", "apll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 2, GFLAGS),
GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 2, GFLAGS),
GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 2, GFLAGS),
COMPOSITE(0, "ddrphy4x", mux_ddrphy_p, CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(26), 8, 2, MFLAGS, 0, 3, DFLAGS | CLK_DIVIDER_POWER_OF_TWO,
RK2928_CLKGATE_CON(7), 1, GFLAGS),
GATE(0, "ddrc", "ddrphy_pre", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(8), 5, GFLAGS),
GATE(0, "ddrphy", "ddrphy_pre", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(7), 0, GFLAGS),
/* PD_CORE */
GATE(0, "dpll_core", "dpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 6, GFLAGS),
GATE(0, "apll_core", "apll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 6, GFLAGS),
GATE(0, "gpll_core", "gpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 6, GFLAGS),
COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK2928_CLKGATE_CON(4), 1, GFLAGS),
COMPOSITE_NOMUX(0, "armcore", "armclk", CLK_IGNORE_UNUSED,
RK2928_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK2928_CLKGATE_CON(4), 0, GFLAGS),
/* PD_MISC */
MUX(0, "hdmiphy", mux_hdmiphy_p, CLK_SET_RATE_PARENT,
RK2928_MISC_CON, 13, 1, MFLAGS),
MUX(0, "usb480m_phy", mux_usb480m_phy_p, CLK_SET_RATE_PARENT,
RK2928_MISC_CON, 14, 1, MFLAGS),
MUX(0, "usb480m", mux_usb480m_p, CLK_SET_RATE_PARENT,
RK2928_MISC_CON, 15, 1, MFLAGS),
/* PD_BUS */
GATE(0, "hdmiphy_aclk_cpu", "hdmiphy", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 1, GFLAGS),
GATE(0, "gpll_aclk_cpu", "gpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 1, GFLAGS),
GATE(0, "cpll_aclk_cpu", "cpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(0), 1, GFLAGS),
COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_aclk_cpu_src_p, 0,
RK2928_CLKSEL_CON(0), 13, 2, MFLAGS, 8, 5, DFLAGS),
GATE(ARMCLK, "aclk_cpu", "aclk_cpu_src", 0,
RK2928_CLKGATE_CON(6), 0, GFLAGS),
COMPOSITE_NOMUX(0, "hclk_cpu", "aclk_cpu_src", 0,
RK2928_CLKSEL_CON(1), 8, 2, DFLAGS,
RK2928_CLKGATE_CON(6), 1, GFLAGS),
COMPOSITE_NOMUX(0, "pclk_bus_src", "aclk_cpu_src", 0,
RK2928_CLKSEL_CON(1), 12, 3, DFLAGS,
RK2928_CLKGATE_CON(6), 2, GFLAGS),
GATE(0, "pclk_cpu", "pclk_bus_src", 0,
RK2928_CLKGATE_CON(6), 3, GFLAGS),
GATE(0, "pclk_phy_pre", "pclk_bus_src", 0,
RK2928_CLKGATE_CON(6), 4, GFLAGS),
GATE(0, "pclk_ddr_pre", "pclk_bus_src", 0,
RK2928_CLKGATE_CON(6), 13, GFLAGS),
/* PD_VIDEO */
COMPOSITE(0, "aclk_vpu_pre", mux_pll_src_4plls_p, 0,
RK2928_CLKSEL_CON(32), 5, 2, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 11, GFLAGS),
GATE(0, "hclk_vpu_src", "aclk_vpu_pre", 0,
RK2928_CLKGATE_CON(4), 4, GFLAGS),
COMPOSITE(0, "aclk_rkvdec_pre", mux_pll_src_4plls_p, 0,
RK2928_CLKSEL_CON(28), 6, 2, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 2, GFLAGS),
GATE(0, "hclk_rkvdec_src", "aclk_rkvdec_pre", 0,
RK2928_CLKGATE_CON(4), 5, GFLAGS),
COMPOSITE(0, "sclk_vdec_cabac", mux_pll_src_4plls_p, 0,
RK2928_CLKSEL_CON(28), 14, 2, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 3, GFLAGS),
COMPOSITE(0, "sclk_vdec_core", mux_pll_src_4plls_p, 0,
RK2928_CLKSEL_CON(34), 13, 2, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 4, GFLAGS),
/* PD_VIO */
COMPOSITE(0, "aclk_iep_pre", mux_pll_src_4plls_p, 0,
RK2928_CLKSEL_CON(31), 5, 2, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 0, GFLAGS),
DIV(0, "hclk_vio_pre", "aclk_iep_pre", 0,
RK2928_CLKSEL_CON(2), 0, 5, DFLAGS),
COMPOSITE(0, "aclk_hdcp_pre", mux_pll_src_4plls_p, 0,
RK2928_CLKSEL_CON(31), 13, 2, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(1), 4, GFLAGS),
MUX(0, "sclk_rga_src", mux_pll_src_4plls_p, 0,
RK2928_CLKSEL_CON(33), 13, 2, MFLAGS),
COMPOSITE_NOMUX(0, "aclk_rga_pre", "sclk_rga_src", 0,
RK2928_CLKSEL_CON(33), 8, 5, DFLAGS,
RK2928_CLKGATE_CON(1), 2, GFLAGS),
COMPOSITE(0, "sclk_rga", mux_sclk_rga_p, 0,
RK2928_CLKSEL_CON(22), 5, 2, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(3), 6, GFLAGS),
COMPOSITE(0, "aclk_vop_pre", mux_pll_src_4plls_p, 0,
RK2928_CLKSEL_CON(33), 5, 2, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(1), 1, GFLAGS),
COMPOSITE(0, "sclk_hdcp", mux_pll_src_3plls_p, 0,
RK2928_CLKSEL_CON(23), 14, 2, MFLAGS, 8, 6, DFLAGS,
RK2928_CLKGATE_CON(3), 5, GFLAGS),
GATE(0, "sclk_hdmi_hdcp", "xin24m", 0,
RK2928_CLKGATE_CON(3), 7, GFLAGS),
COMPOSITE(0, "sclk_hdmi_cec", mux_sclk_hdmi_cec_p, 0,
RK2928_CLKSEL_CON(21), 14, 2, MFLAGS, 0, 14, DFLAGS,
RK2928_CLKGATE_CON(3), 8, GFLAGS),
/* PD_PERI */
GATE(0, "cpll_peri", "cpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(2), 0, GFLAGS),
GATE(0, "gpll_peri", "gpll", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(2), 0, GFLAGS),
GATE(0, "hdmiphy_peri", "hdmiphy", CLK_IGNORE_UNUSED,
RK2928_CLKGATE_CON(2), 0, GFLAGS),
COMPOSITE_NOGATE(0, "aclk_peri_src", mux_aclk_peri_src_p, 0,
RK2928_CLKSEL_CON(10), 10, 2, MFLAGS, 0, 5, DFLAGS),
COMPOSITE_NOMUX(PCLK_PERI, "pclk_peri", "aclk_peri_src", 0,
RK2928_CLKSEL_CON(10), 12, 3, DFLAGS,
RK2928_CLKGATE_CON(5), 2, GFLAGS),
COMPOSITE_NOMUX(HCLK_PERI, "hclk_peri", "aclk_peri_src", 0,
RK2928_CLKSEL_CON(10), 8, 2, DFLAGS,
RK2928_CLKGATE_CON(5), 1, GFLAGS),
GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0,
RK2928_CLKGATE_CON(5), 0, GFLAGS),
GATE(SCLK_TIMER0, "sclk_timer0", "xin24m", 0,
RK2928_CLKGATE_CON(6), 5, GFLAGS),
GATE(SCLK_TIMER1, "sclk_timer1", "xin24m", 0,
RK2928_CLKGATE_CON(6), 6, GFLAGS),
GATE(SCLK_TIMER2, "sclk_timer2", "xin24m", 0,
RK2928_CLKGATE_CON(6), 7, GFLAGS),
GATE(SCLK_TIMER3, "sclk_timer3", "xin24m", 0,
RK2928_CLKGATE_CON(6), 8, GFLAGS),
GATE(SCLK_TIMER4, "sclk_timer4", "xin24m", 0,
RK2928_CLKGATE_CON(6), 9, GFLAGS),
GATE(SCLK_TIMER5, "sclk_timer5", "xin24m", 0,
RK2928_CLKGATE_CON(6), 10, GFLAGS),
COMPOSITE(0, "sclk_crypto", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(24), 5, 1, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(2), 7, GFLAGS),
COMPOSITE(0, "sclk_tsp", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(22), 15, 1, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(2), 6, GFLAGS),
GATE(0, "sclk_hsadc", "ext_hsadc", 0,
RK3288_CLKGATE_CON(10), 12, GFLAGS),
COMPOSITE(0, "sclk_wifi", mux_pll_src_cpll_gpll_usb480m_p, 0,
RK2928_CLKSEL_CON(23), 5, 2, MFLAGS, 0, 6, DFLAGS,
RK2928_CLKGATE_CON(2), 15, GFLAGS),
COMPOSITE(SCLK_SDMMC, "sclk_sdmmc0", mux_mmc_src_p, 0,
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,
RK2928_CLKSEL_CON(11), 10, 2, MFLAGS,
RK2928_CLKGATE_CON(2), 13, GFLAGS),
DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
RK2928_CLKSEL_CON(12), 0, 8, DFLAGS),
COMPOSITE_NODIV(0, "sclk_emmc_src", mux_mmc_src_p, 0,
RK2928_CLKSEL_CON(11), 12, 2, MFLAGS,
RK2928_CLKGATE_CON(2), 14, GFLAGS),
DIV(SCLK_EMMC, "sclk_emmc", "sclk_emmc_src", 0,
RK2928_CLKSEL_CON(12), 8, 8, DFLAGS),
/*
* Clock-Architecture Diagram 2
*/
GATE(0, "gpll_vop", "gpll", 0,
RK2928_CLKGATE_CON(3), 1, GFLAGS),
GATE(0, "cpll_vop", "cpll", 0,
RK2928_CLKGATE_CON(3), 1, GFLAGS),
MUX(0, "sclk_vop_src", mux_sclk_vop_src_p, 0,
RK2928_CLKSEL_CON(27), 0, 1, MFLAGS),
DIV(0, "dclk_hdmiphy", "sclk_vop_src", 0,
RK2928_CLKSEL_CON(29), 0, 3, DFLAGS),
DIV(0, "sclk_vop_pre", "sclk_vop_src", 0,
RK2928_CLKSEL_CON(27), 8, 8, DFLAGS),
MUX(0, "dclk_vop", mux_dclk_vop_p, 0,
RK2928_CLKSEL_CON(27), 1, 1, MFLAGS),
COMPOSITE(0, "i2s0_src", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(9), 15, 1, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 3, GFLAGS),
COMPOSITE_FRAC(0, "i2s0_frac", "i2s0_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(8), 0,
RK3288_CLKGATE_CON(0), 4, GFLAGS),
COMPOSITE_NODIV(SCLK_I2S0, "sclk_i2s0", mux_i2s0_p, 0,
RK2928_CLKSEL_CON(9), 8, 2, MFLAGS,
RK2928_CLKGATE_CON(0), 5, GFLAGS),
COMPOSITE(0, "i2s1_src", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(3), 15, 1, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 10, GFLAGS),
COMPOSITE_FRAC(0, "i2s1_frac", "i2s1_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(7), 0,
RK3288_CLKGATE_CON(0), 11, GFLAGS),
MUX(0, "i2s1_pre", mux_i2s1_pre_p, 0,
RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
GATE(SCLK_I2S1, "sclk_i2s1", "i2s1_pre", 0,
RK2928_CLKGATE_CON(0), 14, GFLAGS),
COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_out", mux_i2s_out_p, 0,
RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
RK2928_CLKGATE_CON(0), 13, GFLAGS),
COMPOSITE(0, "i2s2_src", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(16), 15, 1, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(0), 7, GFLAGS),
COMPOSITE_FRAC(0, "i2s2_frac", "i2s2_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(30), 0,
RK3288_CLKGATE_CON(0), 8, GFLAGS),
COMPOSITE_NODIV(SCLK_I2S2, "sclk_i2s2", mux_i2s2_p, 0,
RK2928_CLKSEL_CON(16), 8, 2, MFLAGS,
RK2928_CLKGATE_CON(0), 9, GFLAGS),
COMPOSITE(0, "sclk_spdif_src", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(6), 15, 1, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(2), 10, GFLAGS),
COMPOSITE_FRAC(0, "spdif_frac", "sclk_spdif_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(20), 0,
RK3288_CLKGATE_CON(2), 12, GFLAGS),
MUX(SCLK_SPDIF, "sclk_spdif", mux_sclk_spdif_p, 0,
RK2928_CLKSEL_CON(6), 8, 2, MFLAGS),
GATE(0, "jtag", "ext_jtag", 0,
RK2928_CLKGATE_CON(1), 3, GFLAGS),
GATE(0, "sclk_otgphy0", "xin24m", 0,
RK2928_CLKGATE_CON(1), 5, GFLAGS),
GATE(0, "sclk_otgphy1", "xin24m", 0,
RK2928_CLKGATE_CON(1), 6, GFLAGS),
COMPOSITE_NOMUX(0, "sclk_tsadc", "xin24m", 0,
RK2928_CLKSEL_CON(24), 6, 10, DFLAGS,
RK2928_CLKGATE_CON(2), 8, GFLAGS),
GATE(0, "cpll_gpu", "cpll", 0,
RK2928_CLKGATE_CON(3), 13, GFLAGS),
GATE(0, "gpll_gpu", "gpll", 0,
RK2928_CLKGATE_CON(3), 13, GFLAGS),
GATE(0, "hdmiphy_gpu", "hdmiphy", 0,
RK2928_CLKGATE_CON(3), 13, GFLAGS),
GATE(0, "usb480m_gpu", "usb480m", 0,
RK2928_CLKGATE_CON(3), 13, GFLAGS),
COMPOSITE_NOGATE(0, "aclk_gpu_pre", mux_aclk_gpu_pre_p, 0,
RK2928_CLKSEL_CON(34), 5, 2, MFLAGS, 0, 5, DFLAGS),
COMPOSITE(SCLK_SPI0, "sclk_spi0", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(25), 8, 1, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(2), 9, GFLAGS),
/* PD_UART */
COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gpll_usb480m_p, 0,
RK2928_CLKSEL_CON(13), 12, 2, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 8, GFLAGS),
COMPOSITE(0, "uart1_src", mux_pll_src_cpll_gpll_usb480m_p, 0,
RK2928_CLKSEL_CON(14), 12, 2, MFLAGS, 0, 7, DFLAGS,
RK2928_CLKGATE_CON(1), 10, GFLAGS),
COMPOSITE(0, "uart2_src", mux_pll_src_cpll_gpll_usb480m_p,
0, RK2928_CLKSEL_CON(15), 12, 2,
MFLAGS, 0, 7, DFLAGS, RK2928_CLKGATE_CON(1), 12, GFLAGS),
COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(17), 0,
RK2928_CLKGATE_CON(1), 9, GFLAGS),
COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(18), 0,
RK2928_CLKGATE_CON(1), 11, GFLAGS),
COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(19), 0,
RK2928_CLKGATE_CON(1), 13, GFLAGS),
MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(13), 8, 2, MFLAGS),
MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(14), 8, 2, MFLAGS),
MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
RK2928_CLKSEL_CON(15), 8, 2, MFLAGS),
COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(2), 14, 1, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(1), 0, GFLAGS),
COMPOSITE(0, "sclk_gmac_src", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(5), 7, 1, MFLAGS, 0, 5, DFLAGS,
RK2928_CLKGATE_CON(1), 7, GFLAGS),
MUX(0, "sclk_macphy_50m", mux_sclk_macphy_50m_p, 0,
RK2928_CLKSEL_CON(29), 10, 1, MFLAGS),
MUX(0, "sclk_gmac_pre", mux_sclk_gmac_pre_p, 0,
RK2928_CLKSEL_CON(5), 5, 1, MFLAGS),
GATE(0, "sclk_mac_refout", "sclk_gmac_pre", 0,
RK2928_CLKGATE_CON(5), 4, GFLAGS),
GATE(0, "sclk_mac_ref", "sclk_gmac_pre", 0,
RK2928_CLKGATE_CON(5), 3, GFLAGS),
GATE(0, "sclk_mac_rx", "sclk_gmac_pre", 0,
RK2928_CLKGATE_CON(5), 5, GFLAGS),
GATE(0, "sclk_mac_tx", "sclk_gmac_pre", 0,
RK2928_CLKGATE_CON(5), 6, GFLAGS),
COMPOSITE(0, "sclk_macphy", mux_sclk_macphy_p, 0,
RK2928_CLKSEL_CON(29), 12, 1, MFLAGS, 8, 2, DFLAGS,
RK2928_CLKGATE_CON(5), 7, GFLAGS),
COMPOSITE(0, "sclk_gmac_out", mux_pll_src_2plls_p, 0,
RK2928_CLKSEL_CON(5), 15, 1, MFLAGS, 8, 5, DFLAGS,
RK2928_CLKGATE_CON(2), 2, GFLAGS),
/*
* Clock-Architecture Diagram 3
*/
/* PD_VOP */
GATE(0, "aclk_rga", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 0, GFLAGS),
GATE(0, "aclk_rga_noc", "aclk_rga_pre", 0, RK2928_CLKGATE_CON(13), 11, GFLAGS),
GATE(0, "aclk_iep", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 2, GFLAGS),
GATE(0, "aclk_iep_noc", "aclk_iep_pre", 0, RK2928_CLKGATE_CON(13), 9, GFLAGS),
GATE(0, "aclk_vop", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 5, GFLAGS),
GATE(0, "aclk_vop_noc", "aclk_vop_pre", 0, RK2928_CLKGATE_CON(13), 12, GFLAGS),
GATE(0, "aclk_hdcp", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(14), 10, GFLAGS),
GATE(0, "aclk_hdcp_noc", "aclk_hdcp_pre", 0, RK2928_CLKGATE_CON(13), 10, GFLAGS),
GATE(0, "hclk_rga", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 1, GFLAGS),
GATE(0, "hclk_iep", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 3, GFLAGS),
GATE(0, "hclk_vop", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 6, GFLAGS),
GATE(0, "hclk_vio_ahb_arbi", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 7, GFLAGS),
GATE(0, "hclk_vio_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 8, GFLAGS),
GATE(0, "hclk_vop_noc", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(13), 13, GFLAGS),
GATE(0, "hclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 7, GFLAGS),
GATE(0, "hclk_hdcp_mmu", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 12, GFLAGS),
GATE(0, "pclk_hdmi_ctrl", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 6, GFLAGS),
GATE(0, "pclk_vio_h2p", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 8, GFLAGS),
GATE(0, "pclk_hdcp", "hclk_vio_pre", 0, RK2928_CLKGATE_CON(14), 11, GFLAGS),
/* PD_PERI */
GATE(0, "aclk_peri_noc", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 0, GFLAGS),
GATE(0, "aclk_gmac", "aclk_peri", 0, RK2928_CLKGATE_CON(11), 4, GFLAGS),
GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 0, GFLAGS),
GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 1, GFLAGS),
GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 2, GFLAGS),
GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 3, GFLAGS),
GATE(0, "hclk_host0", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 6, GFLAGS),
GATE(0, "hclk_host0_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 7, GFLAGS),
GATE(0, "hclk_host1", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 8, GFLAGS),
GATE(0, "hclk_host1_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 9, GFLAGS),
GATE(0, "hclk_host2", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 10, GFLAGS),
GATE(0, "hclk_otg", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 12, GFLAGS),
GATE(0, "hclk_otg_pmu", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 13, GFLAGS),
GATE(0, "hclk_host2_arb", "hclk_peri", 0, RK2928_CLKGATE_CON(11), 14, GFLAGS),
GATE(0, "hclk_peri_noc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 1, GFLAGS),
GATE(0, "pclk_gmac", "pclk_peri", 0, RK2928_CLKGATE_CON(11), 5, GFLAGS),
GATE(0, "pclk_peri_noc", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(12), 2, GFLAGS),
/* PD_GPU */
GATE(0, "aclk_gpu", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(13), 14, GFLAGS),
GATE(0, "aclk_gpu_noc", "aclk_gpu_pre", 0, RK2928_CLKGATE_CON(13), 15, GFLAGS),
/* PD_BUS */
GATE(0, "sclk_initmem_mbist", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS),
GATE(0, "aclk_initmem", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS),
GATE(ACLK_DMAC, "aclk_dmac_bus", "aclk_cpu", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS),
GATE(0, "aclk_bus_noc", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS),
GATE(0, "hclk_rom", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 3, GFLAGS),
GATE(0, "hclk_i2s0_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 7, GFLAGS),
GATE(0, "hclk_i2s1_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 8, GFLAGS),
GATE(0, "hclk_i2s2_2ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS),
GATE(0, "hclk_spdif_8ch", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 10, GFLAGS),
GATE(0, "hclk_tsp", "hclk_cpu", 0, RK2928_CLKGATE_CON(10), 11, GFLAGS),
GATE(0, "hclk_crypto_mst", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS),
GATE(0, "hclk_crypto_slv", "hclk_cpu", 0, RK2928_CLKGATE_CON(8), 12, GFLAGS),
GATE(0, "pclk_ddrupctl", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
GATE(0, "pclk_ddrmon", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
GATE(0, "pclk_msch_noc", "pclk_ddr_pre", 0, RK2928_CLKGATE_CON(10), 2, GFLAGS),
GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS),
GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 14, GFLAGS),
GATE(PCLK_I2C0, "pclk_i2c0", "pclk_cpu", 0, RK2928_CLKGATE_CON(8), 15, GFLAGS),
GATE(PCLK_I2C1, "pclk_i2c1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 0, GFLAGS),
GATE(PCLK_I2C2, "pclk_i2c2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 1, GFLAGS),
GATE(PCLK_I2C3, "pclk_i2c3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 2, GFLAGS),
GATE(PCLK_TIMER, "pclk_timer0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS),
GATE(0, "pclk_stimer", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS),
GATE(PCLK_SPI0, "pclk_spi0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS),
GATE(PCLK_PWM, "pclk_rk_pwm", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 7, GFLAGS),
GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 8, GFLAGS),
GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 9, GFLAGS),
GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 10, GFLAGS),
GATE(PCLK_GPIO3, "pclk_gpio3", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 11, GFLAGS),
GATE(PCLK_UART0, "pclk_uart0", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 12, GFLAGS),
GATE(PCLK_UART1, "pclk_uart1", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 13, GFLAGS),
GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 14, GFLAGS),
GATE(0, "pclk_tsadc", "pclk_cpu", 0, RK2928_CLKGATE_CON(9), 15, GFLAGS),
GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 0, GFLAGS),
GATE(0, "pclk_cru", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 1, GFLAGS),
GATE(0, "pclk_sgrf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(10), 2, GFLAGS),
GATE(0, "pclk_sim", "pclk_cpu", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS),
GATE(0, "pclk_ddrphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 3, GFLAGS),
GATE(0, "pclk_acodecphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 5, GFLAGS),
GATE(0, "pclk_hdmiphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 7, GFLAGS),
GATE(0, "pclk_vdacphy", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS),
GATE(0, "pclk_phy_noc", "pclk_phy_pre", 0, RK2928_CLKGATE_CON(10), 9, GFLAGS),
GATE(0, "aclk_vpu", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 0, GFLAGS),
GATE(0, "aclk_vpu_noc", "aclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 4, GFLAGS),
GATE(0, "aclk_rkvdec", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 2, GFLAGS),
GATE(0, "aclk_rkvdec_noc", "aclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 6, GFLAGS),
GATE(0, "hclk_vpu", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 1, GFLAGS),
GATE(0, "hclk_vpu_noc", "hclk_vpu_pre", 0, RK2928_CLKGATE_CON(15), 5, GFLAGS),
GATE(0, "hclk_rkvdec", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 3, GFLAGS),
GATE(0, "hclk_rkvdec_noc", "hclk_rkvdec_pre", 0, RK2928_CLKGATE_CON(15), 7, GFLAGS),
/* PD_MMC */
MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3228_SDMMC_CON0, 1),
MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3228_SDMMC_CON1, 1),
MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3228_SDIO_CON0, 1),
MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3228_SDIO_CON1, 1),
MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3228_EMMC_CON0, 1),
MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3228_EMMC_CON1, 1),
};
static const char *const rk3228_critical_clocks[] __initconst = {
"aclk_cpu",
"aclk_peri",
"hclk_peri",
"pclk_peri",
};
static void __init rk3228_clk_init(struct device_node *np)
{
void __iomem *reg_base;
struct clk *clk;
reg_base = of_iomap(np, 0);
if (!reg_base) {
pr_err("%s: could not map cru region\n", __func__);
return;
}
rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
/* xin12m is created by an cru-internal divider */
clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
if (IS_ERR(clk))
pr_warn("%s: could not register clock xin12m: %ld\n",
__func__, PTR_ERR(clk));
clk = clk_register_fixed_factor(NULL, "ddrphy_pre", "ddrphy4x", 0, 1, 4);
if (IS_ERR(clk))
pr_warn("%s: could not register clock ddrphy_pre: %ld\n",
__func__, PTR_ERR(clk));
clk = clk_register_fixed_factor(NULL, "hclk_vpu_pre",
"hclk_vpu_src", 0, 1, 4);
if (IS_ERR(clk))
pr_warn("%s: could not register clock hclk_vpu_pre: %ld\n",
__func__, PTR_ERR(clk));
clk = clk_register_fixed_factor(NULL, "hclk_rkvdec_pre",
"hclk_rkvdec_src", 0, 1, 4);
if (IS_ERR(clk))
pr_warn("%s: could not register clock hclk_rkvdec_pre: %ld\n",
__func__, PTR_ERR(clk));
rockchip_clk_register_plls(rk3228_pll_clks,
ARRAY_SIZE(rk3228_pll_clks),
RK3228_GRF_SOC_STATUS0);
rockchip_clk_register_branches(rk3228_clk_branches,
ARRAY_SIZE(rk3228_clk_branches));
rockchip_clk_protect_critical(rk3228_critical_clocks,
ARRAY_SIZE(rk3228_critical_clocks));
rockchip_clk_register_armclk(ARMCLK, "armclk",
mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
&rk3228_cpuclk_data, rk3228_cpuclk_rates,
ARRAY_SIZE(rk3228_cpuclk_rates));
rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
rockchip_register_restart_notifier(RK3228_GLB_SRST_FST, NULL);
}
CLK_OF_DECLARE(rk3228_cru, "rockchip,rk3228-cru", rk3228_clk_init);

View File

@ -225,6 +225,38 @@ static struct clk_div_table div_hclk_cpu_t[] = {
#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
#define IFLAGS ROCKCHIP_INVERTER_HIWORD_MASK
static struct rockchip_clk_branch rk3288_i2s_fracmux __initdata =
MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(4), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3288_spdif_fracmux __initdata =
MUX(0, "spdif_mux", mux_spdif_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(5), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3288_spdif_8ch_fracmux __initdata =
MUX(0, "spdif_8ch_mux", mux_spdif_8ch_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(40), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3288_uart0_fracmux __initdata =
MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(13), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3288_uart1_fracmux __initdata =
MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(14), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3288_uart2_fracmux __initdata =
MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(15), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3288_uart3_fracmux __initdata =
MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(16), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3288_uart4_fracmux __initdata =
MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(3), 8, 2, MFLAGS);
static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
/*
* Clock-Architecture Diagram 1
@ -295,7 +327,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
RK3288_CLKGATE_CON(0), 4, GFLAGS),
GATE(0, "c2c_host", "aclk_cpu_src", 0,
RK3288_CLKGATE_CON(13), 8, GFLAGS),
COMPOSITE_NOMUX(0, "crypto", "aclk_cpu_pre", 0,
COMPOSITE_NOMUX(SCLK_CRYPTO, "crypto", "aclk_cpu_pre", 0,
RK3288_CLKSEL_CON(26), 6, 2, DFLAGS,
RK3288_CLKGATE_CON(5), 4, GFLAGS),
GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", CLK_IGNORE_UNUSED,
@ -304,11 +336,10 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE(0, "i2s_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(4), 15, 1, MFLAGS, 0, 7, DFLAGS,
RK3288_CLKGATE_CON(4), 1, GFLAGS),
COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
COMPOSITE_FRACMUX(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(8), 0,
RK3288_CLKGATE_CON(4), 2, GFLAGS),
MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(4), 8, 2, MFLAGS),
RK3288_CLKGATE_CON(4), 2, GFLAGS,
&rk3288_i2s_fracmux),
COMPOSITE_NODIV(SCLK_I2S0_OUT, "i2s0_clkout", mux_i2s_clkout_p, 0,
RK3288_CLKSEL_CON(4), 12, 1, MFLAGS,
RK3288_CLKGATE_CON(4), 0, GFLAGS),
@ -317,23 +348,23 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
MUX(0, "spdif_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(5), 15, 1, MFLAGS),
COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", 0,
COMPOSITE_NOMUX(0, "spdif_pre", "spdif_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(5), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(4), 4, GFLAGS),
COMPOSITE_FRAC(0, "spdif_frac", "spdif_src", 0,
COMPOSITE_FRACMUX(0, "spdif_frac", "spdif_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(9), 0,
RK3288_CLKGATE_CON(4), 5, GFLAGS),
COMPOSITE_NODIV(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0,
RK3288_CLKSEL_CON(5), 8, 2, MFLAGS,
RK3288_CLKGATE_CON(4), 5, GFLAGS,
&rk3288_spdif_fracmux),
GATE(SCLK_SPDIF, "sclk_spdif", "spdif_mux", CLK_SET_RATE_PARENT,
RK3288_CLKGATE_CON(4), 6, GFLAGS),
COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", 0,
COMPOSITE_NOMUX(0, "spdif_8ch_pre", "spdif_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(40), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(4), 7, GFLAGS),
COMPOSITE_FRAC(0, "spdif_8ch_frac", "spdif_8ch_pre", 0,
COMPOSITE_FRACMUX(0, "spdif_8ch_frac", "spdif_8ch_pre", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(41), 0,
RK3288_CLKGATE_CON(4), 8, GFLAGS),
COMPOSITE_NODIV(SCLK_SPDIF8CH, "sclk_spdif_8ch", mux_spdif_8ch_p, 0,
RK3288_CLKSEL_CON(40), 8, 2, MFLAGS,
RK3288_CLKGATE_CON(4), 8, GFLAGS,
&rk3288_spdif_8ch_fracmux),
GATE(SCLK_SPDIF8CH, "sclk_spdif_8ch", "spdif_8ch_mux", CLK_SET_RATE_PARENT,
RK3288_CLKGATE_CON(4), 9, GFLAGS),
GATE(0, "sclk_acc_efuse", "xin24m", 0,
@ -536,45 +567,40 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0,
RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 8, GFLAGS),
COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
COMPOSITE_FRACMUX(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(17), 0,
RK3288_CLKGATE_CON(1), 9, GFLAGS),
MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(13), 8, 2, MFLAGS),
RK3288_CLKGATE_CON(1), 9, GFLAGS,
&rk3288_uart0_fracmux),
MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
RK3288_CLKSEL_CON(14), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 10, GFLAGS),
COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
COMPOSITE_FRACMUX(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(18), 0,
RK3288_CLKGATE_CON(1), 11, GFLAGS),
MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(14), 8, 2, MFLAGS),
RK3288_CLKGATE_CON(1), 11, GFLAGS,
&rk3288_uart1_fracmux),
COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 12, GFLAGS),
COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
COMPOSITE_FRACMUX(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(19), 0,
RK3288_CLKGATE_CON(1), 13, GFLAGS),
MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(15), 8, 2, MFLAGS),
RK3288_CLKGATE_CON(1), 13, GFLAGS,
&rk3288_uart2_fracmux),
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 14, GFLAGS),
COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
COMPOSITE_FRACMUX(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(20), 0,
RK3288_CLKGATE_CON(1), 15, GFLAGS),
MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(16), 8, 2, MFLAGS),
RK3288_CLKGATE_CON(1), 15, GFLAGS,
&rk3288_uart3_fracmux),
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(2), 12, GFLAGS),
COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
COMPOSITE_FRACMUX(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(7), 0,
RK3288_CLKGATE_CON(2), 13, GFLAGS),
MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
RK3288_CLKGATE_CON(2), 13, GFLAGS,
&rk3288_uart4_fracmux),
COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
@ -644,10 +670,10 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(PCLK_PUBL0, "pclk_publ0", "pclk_cpu", 0, RK3288_CLKGATE_CON(10), 15, GFLAGS),
GATE(PCLK_DDRUPCTL1, "pclk_ddrupctl1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 0, GFLAGS),
GATE(PCLK_PUBL1, "pclk_publ1", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 1, GFLAGS),
GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS),
GATE(PCLK_EFUSE1024, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS),
GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS),
GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS),
GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS),
/* ddrctrl [DDR Controller PHY clock] gates */
@ -709,7 +735,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS),
GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
GATE(SCLK_MIPIDSI_24M, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
/* sclk_gpu gates */
GATE(ACLK_GPU, "aclk_gpu", "sclk_gpu", 0, RK3288_CLKGATE_CON(18), 0, GFLAGS),
@ -783,10 +809,10 @@ static const char *const rk3288_critical_clocks[] __initconst = {
"pclk_pd_pmu",
};
#ifdef CONFIG_PM_SLEEP
static void __iomem *rk3288_cru_base;
/* Some CRU registers will be reset in maskrom when the system
/*
* Some CRU registers will be reset in maskrom when the system
* wakes up from fastboot.
* So save them before suspend, restore them after resume.
*/
@ -840,33 +866,27 @@ static void rk3288_clk_resume(void)
}
}
static void rk3288_clk_shutdown(void)
{
writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
}
static struct syscore_ops rk3288_clk_syscore_ops = {
.suspend = rk3288_clk_suspend,
.resume = rk3288_clk_resume,
};
static void rk3288_clk_sleep_init(void __iomem *reg_base)
{
rk3288_cru_base = reg_base;
register_syscore_ops(&rk3288_clk_syscore_ops);
}
#else /* CONFIG_PM_SLEEP */
static void rk3288_clk_sleep_init(void __iomem *reg_base) {}
#endif
static void __init rk3288_clk_init(struct device_node *np)
{
void __iomem *reg_base;
struct clk *clk;
reg_base = of_iomap(np, 0);
if (!reg_base) {
rk3288_cru_base = of_iomap(np, 0);
if (!rk3288_cru_base) {
pr_err("%s: could not map cru region\n", __func__);
return;
}
rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS);
/* xin12m is created by an cru-internal divider */
clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
@ -907,10 +927,12 @@ static void __init rk3288_clk_init(struct device_node *np)
&rk3288_cpuclk_data, rk3288_cpuclk_rates,
ARRAY_SIZE(rk3288_cpuclk_rates));
rockchip_register_softrst(np, 12, reg_base + RK3288_SOFTRST_CON(0),
rockchip_register_softrst(np, 12,
rk3288_cru_base + RK3288_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
rockchip_register_restart_notifier(RK3288_GLB_SRST_FST);
rk3288_clk_sleep_init(reg_base);
rockchip_register_restart_notifier(RK3288_GLB_SRST_FST,
rk3288_clk_shutdown);
register_syscore_ops(&rk3288_clk_syscore_ops);
}
CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init);

View File

@ -184,13 +184,13 @@ static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = {
#define RK3368_CLKSEL0(_offs, _aclkm) \
{ \
.reg = RK3288_CLKSEL_CON(0 + _offs), \
.reg = RK3368_CLKSEL_CON(0 + _offs), \
.val = HIWORD_UPDATE(_aclkm, RK3368_DIV_ACLKM_MASK, \
RK3368_DIV_ACLKM_SHIFT), \
}
#define RK3368_CLKSEL1(_offs, _atclk, _pdbg) \
{ \
.reg = RK3288_CLKSEL_CON(1 + _offs), \
.reg = RK3368_CLKSEL_CON(1 + _offs), \
.val = HIWORD_UPDATE(_atclk, RK3368_DIV_ATCLK_MASK, \
RK3368_DIV_ATCLK_SHIFT) | \
HIWORD_UPDATE(_pdbg, RK3368_DIV_PCLK_DBG_MASK, \
@ -819,6 +819,13 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
};
static const char *const rk3368_critical_clocks[] __initconst = {
"aclk_bus",
"aclk_peri",
/*
* pwm1 supplies vdd_logic on a lot of boards, is currently unhandled
* but needs to stay enabled there (including its parents) at all times.
*/
"pclk_pwm1",
"pclk_pd_pmu",
};
@ -882,6 +889,6 @@ static void __init rk3368_clk_init(struct device_node *np)
rockchip_register_softrst(np, 15, reg_base + RK3368_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK);
rockchip_register_restart_notifier(RK3368_GLB_SRST_FST);
rockchip_register_restart_notifier(RK3368_GLB_SRST_FST, NULL);
}
CLK_OF_DECLARE(rk3368_cru, "rockchip,rk3368-cru", rk3368_clk_init);

View File

@ -102,22 +102,82 @@ static struct clk *rockchip_clk_register_branch(const char *name,
return clk;
}
struct rockchip_clk_frac {
struct notifier_block clk_nb;
struct clk_fractional_divider div;
struct clk_gate gate;
struct clk_mux mux;
const struct clk_ops *mux_ops;
int mux_frac_idx;
bool rate_change_remuxed;
int rate_change_idx;
};
#define to_rockchip_clk_frac_nb(nb) \
container_of(nb, struct rockchip_clk_frac, clk_nb)
static int rockchip_clk_frac_notifier_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
struct clk_notifier_data *ndata = data;
struct rockchip_clk_frac *frac = to_rockchip_clk_frac_nb(nb);
struct clk_mux *frac_mux = &frac->mux;
int ret = 0;
pr_debug("%s: event %lu, old_rate %lu, new_rate: %lu\n",
__func__, event, ndata->old_rate, ndata->new_rate);
if (event == PRE_RATE_CHANGE) {
frac->rate_change_idx = frac->mux_ops->get_parent(&frac_mux->hw);
if (frac->rate_change_idx != frac->mux_frac_idx) {
frac->mux_ops->set_parent(&frac_mux->hw, frac->mux_frac_idx);
frac->rate_change_remuxed = 1;
}
} else if (event == POST_RATE_CHANGE) {
/*
* The POST_RATE_CHANGE notifier runs directly after the
* divider clock is set in clk_change_rate, so we'll have
* remuxed back to the original parent before clk_change_rate
* reaches the mux itself.
*/
if (frac->rate_change_remuxed) {
frac->mux_ops->set_parent(&frac_mux->hw, frac->rate_change_idx);
frac->rate_change_remuxed = 0;
}
}
return notifier_from_errno(ret);
}
static struct clk *rockchip_clk_register_frac_branch(const char *name,
const char *const *parent_names, u8 num_parents,
void __iomem *base, int muxdiv_offset, u8 div_flags,
int gate_offset, u8 gate_shift, u8 gate_flags,
unsigned long flags, spinlock_t *lock)
unsigned long flags, struct rockchip_clk_branch *child,
spinlock_t *lock)
{
struct rockchip_clk_frac *frac;
struct clk *clk;
struct clk_gate *gate = NULL;
struct clk_fractional_divider *div = NULL;
const struct clk_ops *div_ops = NULL, *gate_ops = NULL;
if (gate_offset >= 0) {
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate)
return ERR_PTR(-ENOMEM);
if (muxdiv_offset < 0)
return ERR_PTR(-EINVAL);
if (child && child->branch_type != branch_mux) {
pr_err("%s: fractional child clock for %s can only be a mux\n",
__func__, name);
return ERR_PTR(-EINVAL);
}
frac = kzalloc(sizeof(*frac), GFP_KERNEL);
if (!frac)
return ERR_PTR(-ENOMEM);
if (gate_offset >= 0) {
gate = &frac->gate;
gate->flags = gate_flags;
gate->reg = base + gate_offset;
gate->bit_idx = gate_shift;
@ -125,13 +185,7 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name,
gate_ops = &clk_gate_ops;
}
if (muxdiv_offset < 0)
return ERR_PTR(-EINVAL);
div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div)
return ERR_PTR(-ENOMEM);
div = &frac->div;
div->flags = div_flags;
div->reg = base + muxdiv_offset;
div->mshift = 16;
@ -147,7 +201,61 @@ static struct clk *rockchip_clk_register_frac_branch(const char *name,
NULL, NULL,
&div->hw, div_ops,
gate ? &gate->hw : NULL, gate_ops,
flags);
flags | CLK_SET_RATE_UNGATE);
if (IS_ERR(clk)) {
kfree(frac);
return clk;
}
if (child) {
struct clk_mux *frac_mux = &frac->mux;
struct clk_init_data init;
struct clk *mux_clk;
int i, ret;
frac->mux_frac_idx = -1;
for (i = 0; i < child->num_parents; i++) {
if (!strcmp(name, child->parent_names[i])) {
pr_debug("%s: found fractional parent in mux at pos %d\n",
__func__, i);
frac->mux_frac_idx = i;
break;
}
}
frac->mux_ops = &clk_mux_ops;
frac->clk_nb.notifier_call = rockchip_clk_frac_notifier_cb;
frac_mux->reg = base + child->muxdiv_offset;
frac_mux->shift = child->mux_shift;
frac_mux->mask = BIT(child->mux_width) - 1;
frac_mux->flags = child->mux_flags;
frac_mux->lock = lock;
frac_mux->hw.init = &init;
init.name = child->name;
init.flags = child->flags | CLK_SET_RATE_PARENT;
init.ops = frac->mux_ops;
init.parent_names = child->parent_names;
init.num_parents = child->num_parents;
mux_clk = clk_register(NULL, &frac_mux->hw);
if (IS_ERR(mux_clk))
return clk;
rockchip_clk_add_lookup(mux_clk, child->id);
/* notifier on the fraction divider to catch rate changes */
if (frac->mux_frac_idx >= 0) {
ret = clk_notifier_register(clk, &frac->clk_nb);
if (ret)
pr_err("%s: failed to register clock notifier for %s\n",
__func__, name);
} else {
pr_warn("%s: could not find %s as parent of %s, rate changes may not work\n",
__func__, name, child->name);
}
}
return clk;
}
@ -251,7 +359,8 @@ void __init rockchip_clk_register_branches(
list->parent_names, list->num_parents,
reg_base, list->muxdiv_offset, list->div_flags,
list->gate_offset, list->gate_shift,
list->gate_flags, flags, &clk_lock);
list->gate_flags, flags, list->child,
&clk_lock);
break;
case branch_gate:
flags |= CLK_SET_RATE_PARENT;
@ -341,9 +450,13 @@ void __init rockchip_clk_protect_critical(const char *const clocks[],
}
static unsigned int reg_restart;
static void (*cb_restart)(void);
static int rockchip_restart_notify(struct notifier_block *this,
unsigned long mode, void *cmd)
{
if (cb_restart)
cb_restart();
writel(0xfdb9, reg_base + reg_restart);
return NOTIFY_DONE;
}
@ -353,11 +466,12 @@ static struct notifier_block rockchip_restart_handler = {
.priority = 128,
};
void __init rockchip_register_restart_notifier(unsigned int reg)
void __init rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void))
{
int ret;
reg_restart = reg;
cb_restart = cb;
ret = register_restart_handler(&rockchip_restart_handler);
if (ret)
pr_err("%s: cannot register restart handler, %d\n",

View File

@ -2,6 +2,9 @@
* Copyright (c) 2014 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
* Copyright (c) 2015 Rockchip Electronics Co. Ltd.
* Author: Xing Zheng <zhengxing@rock-chips.com>
*
* based on
*
* samsung/clk.h
@ -30,7 +33,7 @@ struct clk;
#define HIWORD_UPDATE(val, mask, shift) \
((val) << (shift) | (mask) << ((shift) + 16))
/* register positions shared by RK2928, RK3066 and RK3188 */
/* register positions shared by RK2928, RK3036, RK3066, RK3188 and RK3228 */
#define RK2928_PLL_CON(x) ((x) * 0x4)
#define RK2928_MODE_CON 0x40
#define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44)
@ -40,6 +43,22 @@ struct clk;
#define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110)
#define RK2928_MISC_CON 0x134
#define RK3036_SDMMC_CON0 0x144
#define RK3036_SDMMC_CON1 0x148
#define RK3036_SDIO_CON0 0x14c
#define RK3036_SDIO_CON1 0x150
#define RK3036_EMMC_CON0 0x154
#define RK3036_EMMC_CON1 0x158
#define RK3228_GLB_SRST_FST 0x1f0
#define RK3228_GLB_SRST_SND 0x1f4
#define RK3228_SDMMC_CON0 0x1c0
#define RK3228_SDMMC_CON1 0x1c4
#define RK3228_SDIO_CON0 0x1c8
#define RK3228_SDIO_CON1 0x1cc
#define RK3228_EMMC_CON0 0x1d8
#define RK3228_EMMC_CON1 0x1dc
#define RK3288_PLL_CON(x) RK2928_PLL_CON(x)
#define RK3288_MODE_CON 0x50
#define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60)
@ -74,9 +93,22 @@ struct clk;
#define RK3368_EMMC_CON1 0x41c
enum rockchip_pll_type {
pll_rk3036,
pll_rk3066,
};
#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \
_postdiv2, _dsmpd, _frac) \
{ \
.rate = _rate##U, \
.fbdiv = _fbdiv, \
.postdiv1 = _postdiv1, \
.refdiv = _refdiv, \
.postdiv2 = _postdiv2, \
.dsmpd = _dsmpd, \
.frac = _frac, \
}
#define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \
{ \
.rate = _rate##U, \
@ -101,6 +133,13 @@ struct rockchip_pll_rate_table {
unsigned int nf;
unsigned int no;
unsigned int nb;
/* for RK3036 */
unsigned int fbdiv;
unsigned int postdiv1;
unsigned int refdiv;
unsigned int postdiv2;
unsigned int dsmpd;
unsigned int frac;
};
/**
@ -235,6 +274,7 @@ struct rockchip_clk_branch {
int gate_offset;
u8 gate_shift;
u8 gate_flags;
struct rockchip_clk_branch *child;
};
#define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\
@ -369,6 +409,24 @@ struct rockchip_clk_branch {
.gate_flags = gf, \
}
#define COMPOSITE_FRACMUX(_id, cname, pname, f, mo, df, go, gs, gf, ch) \
{ \
.id = _id, \
.branch_type = branch_fraction_divider, \
.name = cname, \
.parent_names = (const char *[]){ pname }, \
.num_parents = 1, \
.flags = f, \
.muxdiv_offset = mo, \
.div_shift = 16, \
.div_width = 16, \
.div_flags = df, \
.gate_offset = go, \
.gate_shift = gs, \
.gate_flags = gf, \
.child = ch, \
}
#define MUX(_id, cname, pnames, f, o, s, w, mf) \
{ \
.id = _id, \
@ -464,7 +522,7 @@ void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name,
const struct rockchip_cpuclk_rate_table *rates,
int nrates);
void rockchip_clk_protect_critical(const char *const clocks[], int nclocks);
void rockchip_register_restart_notifier(unsigned int reg);
void rockchip_register_restart_notifier(unsigned int reg, void (*cb)(void));
#define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0)

View File

@ -148,6 +148,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent);
unsigned long alt_div = 0, alt_div_mask = DIV_MASK;
unsigned long div0, div1 = 0, mux_reg;
unsigned long flags;
/* find out the divider values to use for clock data */
while ((cfg_data->prate * 1000) != ndata->new_rate) {
@ -156,7 +157,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
cfg_data++;
}
spin_lock(cpuclk->lock);
spin_lock_irqsave(cpuclk->lock, flags);
/*
* For the selected PLL clock frequency, get the pre-defined divider
@ -212,7 +213,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata,
DIV_MASK_ALL);
}
spin_unlock(cpuclk->lock);
spin_unlock_irqrestore(cpuclk->lock, flags);
return 0;
}
@ -223,6 +224,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg;
unsigned long div = 0, div_mask = DIV_MASK;
unsigned long mux_reg;
unsigned long flags;
/* find out the divider values to use for clock data */
if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) {
@ -233,7 +235,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
}
}
spin_lock(cpuclk->lock);
spin_lock_irqsave(cpuclk->lock, flags);
/* select mout_apll as the alternate parent */
mux_reg = readl(base + E4210_SRC_CPU);
@ -246,7 +248,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata,
}
exynos_set_safe_div(base, div, div_mask);
spin_unlock(cpuclk->lock);
spin_unlock_irqrestore(cpuclk->lock, flags);
return 0;
}

View File

@ -18,6 +18,7 @@
#include <linux/syscore_ops.h>
#include "clk.h"
#include "clk-cpu.h"
#define APLL_LOCK 0x0
#define APLL_CON0 0x100
@ -616,9 +617,11 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
MUX(0, "mout_mspll_kfc", mout_mspll_cpu_p, SRC_TOP7, 8, 2),
MUX(0, "mout_mspll_cpu", mout_mspll_cpu_p, SRC_TOP7, 12, 2),
MUX(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1),
MUX_F(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0),
MUX(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1),
MUX(0, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1),
MUX_F(0, "mout_kpll", mout_kpll_p, SRC_KFC, 0, 1,
CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0),
MUX(0, "mout_kfc", mout_kfc_p, SRC_KFC, 16, 1),
MUX(0, "mout_aclk200", mout_group1_p, SRC_TOP0, 8, 2),
@ -677,8 +680,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP5, 20, 1),
MUX(CLK_MOUT_USER_ACLK300_DISP1, "mout_user_aclk300_disp1",
mout_user_aclk300_disp1_p, SRC_TOP5, 24, 1),
MUX(0, "mout_user_aclk300_gscl", mout_user_aclk300_gscl_p,
SRC_TOP5, 28, 1),
MUX(CLK_MOUT_USER_ACLK300_GSCL, "mout_user_aclk300_gscl",
mout_user_aclk300_gscl_p, SRC_TOP5, 28, 1),
MUX(0, "mout_sclk_mpll", mout_mpll_p, SRC_TOP6, 0, 1),
MUX(CLK_MOUT_VPLL, "mout_sclk_vpll", mout_vpll_p, SRC_TOP6, 4, 1),
@ -729,8 +732,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP12, 20, 1),
MUX(CLK_MOUT_SW_ACLK300, "mout_sw_aclk300_disp1",
mout_sw_aclk300_disp1_p, SRC_TOP12, 24, 1),
MUX(0, "mout_sw_aclk300_gscl", mout_sw_aclk300_gscl_p,
SRC_TOP12, 28, 1),
MUX(CLK_MOUT_SW_ACLK300_GSCL, "mout_sw_aclk300_gscl",
mout_sw_aclk300_gscl_p, SRC_TOP12, 28, 1),
/* DISP1 Block */
MUX(0, "mout_mipi1", mout_group2_p, SRC_DISP10, 16, 3),
@ -926,7 +929,7 @@ static struct samsung_gate_clock exynos5x_gate_clks[] __initdata = {
GATE_BUS_TOP, 13, 0, 0),
GATE(0, "aclk166", "mout_user_aclk166",
GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333", "mout_aclk333",
GATE(0, "aclk333", "mout_user_aclk333",
GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk400_isp", "mout_user_aclk400_isp",
GATE_BUS_TOP, 16, 0, 0),
@ -1246,6 +1249,74 @@ static struct samsung_pll_clock exynos5x_plls[nr_plls] __initdata = {
KPLL_CON0, NULL),
};
#define E5420_EGL_DIV0(apll, pclk_dbg, atb, cpud) \
((((apll) << 24) | ((pclk_dbg) << 20) | ((atb) << 16) | \
((cpud) << 4)))
static const struct exynos_cpuclk_cfg_data exynos5420_eglclk_d[] __initconst = {
{ 1800000, E5420_EGL_DIV0(3, 7, 7, 4), },
{ 1700000, E5420_EGL_DIV0(3, 7, 7, 3), },
{ 1600000, E5420_EGL_DIV0(3, 7, 7, 3), },
{ 1500000, E5420_EGL_DIV0(3, 7, 7, 3), },
{ 1400000, E5420_EGL_DIV0(3, 7, 7, 3), },
{ 1300000, E5420_EGL_DIV0(3, 7, 7, 2), },
{ 1200000, E5420_EGL_DIV0(3, 7, 7, 2), },
{ 1100000, E5420_EGL_DIV0(3, 7, 7, 2), },
{ 1000000, E5420_EGL_DIV0(3, 6, 6, 2), },
{ 900000, E5420_EGL_DIV0(3, 6, 6, 2), },
{ 800000, E5420_EGL_DIV0(3, 5, 5, 2), },
{ 700000, E5420_EGL_DIV0(3, 5, 5, 2), },
{ 600000, E5420_EGL_DIV0(3, 4, 4, 2), },
{ 500000, E5420_EGL_DIV0(3, 3, 3, 2), },
{ 400000, E5420_EGL_DIV0(3, 3, 3, 2), },
{ 300000, E5420_EGL_DIV0(3, 3, 3, 2), },
{ 200000, E5420_EGL_DIV0(3, 3, 3, 2), },
{ 0 },
};
static const struct exynos_cpuclk_cfg_data exynos5800_eglclk_d[] __initconst = {
{ 2000000, E5420_EGL_DIV0(3, 7, 7, 4), },
{ 1900000, E5420_EGL_DIV0(3, 7, 7, 4), },
{ 1800000, E5420_EGL_DIV0(3, 7, 7, 4), },
{ 1700000, E5420_EGL_DIV0(3, 7, 7, 3), },
{ 1600000, E5420_EGL_DIV0(3, 7, 7, 3), },
{ 1500000, E5420_EGL_DIV0(3, 7, 7, 3), },
{ 1400000, E5420_EGL_DIV0(3, 7, 7, 3), },
{ 1300000, E5420_EGL_DIV0(3, 7, 7, 2), },
{ 1200000, E5420_EGL_DIV0(3, 7, 7, 2), },
{ 1100000, E5420_EGL_DIV0(3, 7, 7, 2), },
{ 1000000, E5420_EGL_DIV0(3, 7, 6, 2), },
{ 900000, E5420_EGL_DIV0(3, 7, 6, 2), },
{ 800000, E5420_EGL_DIV0(3, 7, 5, 2), },
{ 700000, E5420_EGL_DIV0(3, 7, 5, 2), },
{ 600000, E5420_EGL_DIV0(3, 7, 4, 2), },
{ 500000, E5420_EGL_DIV0(3, 7, 3, 2), },
{ 400000, E5420_EGL_DIV0(3, 7, 3, 2), },
{ 300000, E5420_EGL_DIV0(3, 7, 3, 2), },
{ 200000, E5420_EGL_DIV0(3, 7, 3, 2), },
{ 0 },
};
#define E5420_KFC_DIV(kpll, pclk, aclk) \
((((kpll) << 24) | ((pclk) << 20) | ((aclk) << 4)))
static const struct exynos_cpuclk_cfg_data exynos5420_kfcclk_d[] __initconst = {
{ 1400000, E5420_KFC_DIV(3, 5, 3), }, /* for Exynos5800 */
{ 1300000, E5420_KFC_DIV(3, 5, 2), },
{ 1200000, E5420_KFC_DIV(3, 5, 2), },
{ 1100000, E5420_KFC_DIV(3, 5, 2), },
{ 1000000, E5420_KFC_DIV(3, 5, 2), },
{ 900000, E5420_KFC_DIV(3, 5, 2), },
{ 800000, E5420_KFC_DIV(3, 5, 2), },
{ 700000, E5420_KFC_DIV(3, 4, 2), },
{ 600000, E5420_KFC_DIV(3, 4, 2), },
{ 500000, E5420_KFC_DIV(3, 4, 2), },
{ 400000, E5420_KFC_DIV(3, 3, 2), },
{ 300000, E5420_KFC_DIV(3, 3, 2), },
{ 200000, E5420_KFC_DIV(3, 3, 2), },
{ 0 },
};
static const struct of_device_id ext_clk_match[] __initconst = {
{ .compatible = "samsung,exynos5420-oscclk", .data = (void *)0, },
{ },
@ -1310,6 +1381,19 @@ static void __init exynos5x_clk_init(struct device_node *np,
ARRAY_SIZE(exynos5800_gate_clks));
}
if (soc == EXYNOS5420) {
exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
mout_cpu_p[0], mout_cpu_p[1], 0x200,
exynos5420_eglclk_d, ARRAY_SIZE(exynos5420_eglclk_d), 0);
} else {
exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk",
mout_cpu_p[0], mout_cpu_p[1], 0x200,
exynos5800_eglclk_d, ARRAY_SIZE(exynos5800_eglclk_d), 0);
}
exynos_register_cpu_clock(ctx, CLK_KFC_CLK, "kfcclk",
mout_kfc_p[0], mout_kfc_p[1], 0x28200,
exynos5420_kfcclk_d, ARRAY_SIZE(exynos5420_kfcclk_d), 0);
exynos5420_clk_sleep_init();
samsung_clk_of_add_provider(np, ctx);

View File

@ -77,12 +77,11 @@ static u8 s3c24xx_clkout_get_parent(struct clk_hw *hw)
static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index)
{
struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw);
int ret = 0;
s3c2410_modify_misccr((clkout->mask << clkout->shift),
(index << clkout->shift));
return ret;
return 0;
}
static const struct clk_ops s3c24xx_clkout_ops = {

View File

@ -1,13 +1,13 @@
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o clk-mstp.o
obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o clk-mstp.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o clk-mstp.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o clk-mstp.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o clk-mstp.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o clk-mstp.o clk-div6.o
obj-$(CONFIG_ARCH_R8A7795) += renesas-cpg-mssr.o \
r8a7795-cpg-mssr.o clk-div6.o
obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o clk-mstp.o clk-div6.o

View File

@ -18,6 +18,8 @@
#include <linux/of_address.h>
#include <linux/slab.h>
#include "clk-div6.h"
#define CPG_DIV6_CKSTP BIT(8)
#define CPG_DIV6_DIV(d) ((d) & 0x3f)
#define CPG_DIV6_DIV_MASK 0x3f
@ -172,67 +174,44 @@ static const struct clk_ops cpg_div6_clock_ops = {
.set_rate = cpg_div6_clock_set_rate,
};
static void __init cpg_div6_clock_init(struct device_node *np)
/**
* cpg_div6_register - Register a DIV6 clock
* @name: Name of the DIV6 clock
* @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8)
* @parent_names: Array containing the names of the parent clocks
* @reg: Mapped register used to control the DIV6 clock
*/
struct clk * __init cpg_div6_register(const char *name,
unsigned int num_parents,
const char **parent_names,
void __iomem *reg)
{
unsigned int num_parents, valid_parents;
const char **parent_names;
unsigned int valid_parents;
struct clk_init_data init;
struct div6_clock *clock;
const char *name;
struct clk *clk;
unsigned int i;
int ret;
clock = kzalloc(sizeof(*clock), GFP_KERNEL);
if (!clock)
return;
num_parents = of_clk_get_parent_count(np);
if (num_parents < 1) {
pr_err("%s: no parent found for %s DIV6 clock\n",
__func__, np->name);
return;
}
return ERR_PTR(-ENOMEM);
clock->parents = kmalloc_array(num_parents, sizeof(*clock->parents),
GFP_KERNEL);
parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
GFP_KERNEL);
if (!parent_names)
return;
GFP_KERNEL);
if (!clock->parents) {
clk = ERR_PTR(-ENOMEM);
goto free_clock;
}
/* Remap the clock register and read the divisor. Disabling the
* clock overwrites the divisor, so we need to cache its value for the
* enable operation.
clock->reg = reg;
/*
* Read the divisor. Disabling the clock overwrites the divisor, so we
* need to cache its value for the enable operation.
*/
clock->reg = of_iomap(np, 0);
if (clock->reg == NULL) {
pr_err("%s: failed to map %s DIV6 clock register\n",
__func__, np->name);
goto error;
}
clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;
/* Parse the DT properties. */
ret = of_property_read_string(np, "clock-output-names", &name);
if (ret < 0) {
pr_err("%s: failed to get %s DIV6 clock output name\n",
__func__, np->name);
goto error;
}
for (i = 0, valid_parents = 0; i < num_parents; i++) {
const char *name = of_clk_get_parent_name(np, i);
if (name) {
parent_names[valid_parents] = name;
clock->parents[valid_parents] = i;
valid_parents++;
}
}
switch (num_parents) {
case 1:
/* fixed parent clock */
@ -250,8 +229,18 @@ static void __init cpg_div6_clock_init(struct device_node *np)
break;
default:
pr_err("%s: invalid number of parents for DIV6 clock %s\n",
__func__, np->name);
goto error;
__func__, name);
clk = ERR_PTR(-EINVAL);
goto free_parents;
}
/* Filter out invalid parents */
for (i = 0, valid_parents = 0; i < num_parents; i++) {
if (parent_names[i]) {
parent_names[valid_parents] = parent_names[i];
clock->parents[valid_parents] = i;
valid_parents++;
}
}
/* Register the clock. */
@ -264,6 +253,53 @@ static void __init cpg_div6_clock_init(struct device_node *np)
clock->hw.init = &init;
clk = clk_register(NULL, &clock->hw);
if (IS_ERR(clk))
goto free_parents;
return clk;
free_parents:
kfree(clock->parents);
free_clock:
kfree(clock);
return clk;
}
static void __init cpg_div6_clock_init(struct device_node *np)
{
unsigned int num_parents;
const char **parent_names;
const char *clk_name = np->name;
void __iomem *reg;
struct clk *clk;
unsigned int i;
num_parents = of_clk_get_parent_count(np);
if (num_parents < 1) {
pr_err("%s: no parent found for %s DIV6 clock\n",
__func__, np->name);
return;
}
parent_names = kmalloc_array(num_parents, sizeof(*parent_names),
GFP_KERNEL);
if (!parent_names)
return;
reg = of_iomap(np, 0);
if (reg == NULL) {
pr_err("%s: failed to map %s DIV6 clock register\n",
__func__, np->name);
goto error;
}
/* Parse the DT properties. */
of_property_read_string(np, "clock-output-names", &clk_name);
for (i = 0; i < num_parents; i++)
parent_names[i] = of_clk_get_parent_name(np, i);
clk = cpg_div6_register(clk_name, num_parents, parent_names, reg);
if (IS_ERR(clk)) {
pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
__func__, np->name, PTR_ERR(clk));
@ -276,9 +312,8 @@ static void __init cpg_div6_clock_init(struct device_node *np)
return;
error:
if (clock->reg)
iounmap(clock->reg);
if (reg)
iounmap(reg);
kfree(parent_names);
kfree(clock);
}
CLK_OF_DECLARE(cpg_div6_clk, "renesas,cpg-div6-clock", cpg_div6_clock_init);

View File

@ -0,0 +1,7 @@
#ifndef __SHMOBILE_CLK_DIV6_H__
#define __SHMOBILE_CLK_DIV6_H__
struct clk *cpg_div6_register(const char *name, unsigned int num_parents,
const char **parent_names, void __iomem *reg);
#endif

View File

@ -115,7 +115,7 @@ static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate,
*
* Using experimental measurements, it seems that no more than
* ~10 iterations are needed, independently of the CPU rate.
* Since this value might be dependant of external xtal rate, pll1
* Since this value might be dependent on external xtal rate, pll1
* rate or even the other emulation clocks rate, use 1000 as a
* "super" safe value.
*/
@ -262,7 +262,7 @@ static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
* 1 1 0 30 / 2 x172/2 x208/2 x106
* 1 1 1 30 / 2 x172/2 x208/2 x88
*
* *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2)
* *1 : Table 7.6 indicates VCO output (PLLx = VCO/2)
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \
(((md) & BIT(13)) >> 12) | \

View File

@ -0,0 +1,383 @@
/*
* r8a7795 Clock Pulse Generator / Module Standby and Software Reset
*
* Copyright (C) 2015 Glider bvba
*
* Based on clk-rcar-gen3.c
*
* 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/bug.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <dt-bindings/clock/r8a7795-cpg-mssr.h>
#include "renesas-cpg-mssr.h"
enum clk_ids {
/* Core Clock Outputs exported to DT */
LAST_DT_CORE_CLK = R8A7795_CLK_OSC,
/* External Input Clocks */
CLK_EXTAL,
CLK_EXTALR,
/* Internal Core Clocks */
CLK_MAIN,
CLK_PLL0,
CLK_PLL1,
CLK_PLL2,
CLK_PLL3,
CLK_PLL4,
CLK_PLL1_DIV2,
CLK_PLL1_DIV4,
CLK_S0,
CLK_S1,
CLK_S2,
CLK_S3,
CLK_SDSRC,
CLK_SSPSRC,
/* Module Clocks */
MOD_CLK_BASE
};
enum r8a7795_clk_types {
CLK_TYPE_GEN3_MAIN = CLK_TYPE_CUSTOM,
CLK_TYPE_GEN3_PLL0,
CLK_TYPE_GEN3_PLL1,
CLK_TYPE_GEN3_PLL2,
CLK_TYPE_GEN3_PLL3,
CLK_TYPE_GEN3_PLL4,
};
static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
DEF_INPUT("extalr", CLK_EXTALR),
/* Internal Core Clocks */
DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL),
DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN),
DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN),
DEF_BASE(".pll2", CLK_PLL2, CLK_TYPE_GEN3_PLL2, CLK_MAIN),
DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN),
DEF_BASE(".pll4", CLK_PLL4, CLK_TYPE_GEN3_PLL4, CLK_MAIN),
DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1),
DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1),
DEF_FIXED(".s0", CLK_S0, CLK_PLL1_DIV2, 2, 1),
DEF_FIXED(".s1", CLK_S1, CLK_PLL1_DIV2, 3, 1),
DEF_FIXED(".s2", CLK_S2, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED(".s3", CLK_S3, CLK_PLL1_DIV2, 6, 1),
/* Core Clock Outputs */
DEF_FIXED("ztr", R8A7795_CLK_ZTR, CLK_PLL1_DIV2, 6, 1),
DEF_FIXED("ztrd2", R8A7795_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1),
DEF_FIXED("zt", R8A7795_CLK_ZT, CLK_PLL1_DIV2, 4, 1),
DEF_FIXED("zx", R8A7795_CLK_ZX, CLK_PLL1_DIV2, 2, 1),
DEF_FIXED("s0d1", R8A7795_CLK_S0D1, CLK_S0, 1, 1),
DEF_FIXED("s0d4", R8A7795_CLK_S0D4, CLK_S0, 4, 1),
DEF_FIXED("s1d1", R8A7795_CLK_S1D1, CLK_S1, 1, 1),
DEF_FIXED("s1d2", R8A7795_CLK_S1D2, CLK_S1, 2, 1),
DEF_FIXED("s1d4", R8A7795_CLK_S1D4, CLK_S1, 4, 1),
DEF_FIXED("s2d1", R8A7795_CLK_S2D1, CLK_S2, 1, 1),
DEF_FIXED("s2d2", R8A7795_CLK_S2D2, CLK_S2, 2, 1),
DEF_FIXED("s2d4", R8A7795_CLK_S2D4, CLK_S2, 4, 1),
DEF_FIXED("s3d1", R8A7795_CLK_S3D1, CLK_S3, 1, 1),
DEF_FIXED("s3d2", R8A7795_CLK_S3D2, CLK_S3, 2, 1),
DEF_FIXED("s3d4", R8A7795_CLK_S3D4, CLK_S3, 4, 1),
DEF_FIXED("cl", R8A7795_CLK_CL, CLK_PLL1_DIV2, 48, 1),
DEF_FIXED("cp", R8A7795_CLK_CP, CLK_EXTAL, 2, 1),
DEF_DIV6P1("mso", R8A7795_CLK_MSO, CLK_PLL1_DIV4, 0x014),
DEF_DIV6P1("hdmi", R8A7795_CLK_HDMI, CLK_PLL1_DIV2, 0x250),
};
static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
DEF_MOD("scif5", 202, R8A7795_CLK_S3D4),
DEF_MOD("scif4", 203, R8A7795_CLK_S3D4),
DEF_MOD("scif3", 204, R8A7795_CLK_S3D4),
DEF_MOD("scif1", 206, R8A7795_CLK_S3D4),
DEF_MOD("scif0", 207, R8A7795_CLK_S3D4),
DEF_MOD("msiof3", 208, R8A7795_CLK_MSO),
DEF_MOD("msiof2", 209, R8A7795_CLK_MSO),
DEF_MOD("msiof1", 210, R8A7795_CLK_MSO),
DEF_MOD("msiof0", 211, R8A7795_CLK_MSO),
DEF_MOD("sys-dmac2", 217, R8A7795_CLK_S3D1),
DEF_MOD("sys-dmac1", 218, R8A7795_CLK_S3D1),
DEF_MOD("sys-dmac0", 219, R8A7795_CLK_S3D1),
DEF_MOD("scif2", 310, R8A7795_CLK_S3D4),
DEF_MOD("pcie1", 318, R8A7795_CLK_S3D1),
DEF_MOD("pcie0", 319, R8A7795_CLK_S3D1),
DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1),
DEF_MOD("audmac0", 502, R8A7795_CLK_S3D4),
DEF_MOD("audmac1", 501, R8A7795_CLK_S3D4),
DEF_MOD("hscif4", 516, R8A7795_CLK_S3D1),
DEF_MOD("hscif3", 517, R8A7795_CLK_S3D1),
DEF_MOD("hscif2", 518, R8A7795_CLK_S3D1),
DEF_MOD("hscif1", 519, R8A7795_CLK_S3D1),
DEF_MOD("hscif0", 520, R8A7795_CLK_S3D1),
DEF_MOD("vspd3", 620, R8A7795_CLK_S2D1),
DEF_MOD("vspd2", 621, R8A7795_CLK_S2D1),
DEF_MOD("vspd1", 622, R8A7795_CLK_S2D1),
DEF_MOD("vspd0", 623, R8A7795_CLK_S2D1),
DEF_MOD("vspbc", 624, R8A7795_CLK_S2D1),
DEF_MOD("vspbd", 626, R8A7795_CLK_S2D1),
DEF_MOD("vspi2", 629, R8A7795_CLK_S2D1),
DEF_MOD("vspi1", 630, R8A7795_CLK_S2D1),
DEF_MOD("vspi0", 631, R8A7795_CLK_S2D1),
DEF_MOD("ehci2", 701, R8A7795_CLK_S3D4),
DEF_MOD("ehci1", 702, R8A7795_CLK_S3D4),
DEF_MOD("ehci0", 703, R8A7795_CLK_S3D4),
DEF_MOD("hsusb", 704, R8A7795_CLK_S3D4),
DEF_MOD("du3", 721, R8A7795_CLK_S2D1),
DEF_MOD("du2", 722, R8A7795_CLK_S2D1),
DEF_MOD("du1", 723, R8A7795_CLK_S2D1),
DEF_MOD("du0", 724, R8A7795_CLK_S2D1),
DEF_MOD("hdmi1", 728, R8A7795_CLK_HDMI),
DEF_MOD("hdmi0", 729, R8A7795_CLK_HDMI),
DEF_MOD("etheravb", 812, R8A7795_CLK_S3D2),
DEF_MOD("sata0", 815, R8A7795_CLK_S3D2),
DEF_MOD("gpio7", 905, R8A7795_CLK_CP),
DEF_MOD("gpio6", 906, R8A7795_CLK_CP),
DEF_MOD("gpio5", 907, R8A7795_CLK_CP),
DEF_MOD("gpio4", 908, R8A7795_CLK_CP),
DEF_MOD("gpio3", 909, R8A7795_CLK_CP),
DEF_MOD("gpio2", 910, R8A7795_CLK_CP),
DEF_MOD("gpio1", 911, R8A7795_CLK_CP),
DEF_MOD("gpio0", 912, R8A7795_CLK_CP),
DEF_MOD("i2c6", 918, R8A7795_CLK_S3D2),
DEF_MOD("i2c5", 919, R8A7795_CLK_S3D2),
DEF_MOD("i2c4", 927, R8A7795_CLK_S3D2),
DEF_MOD("i2c3", 928, R8A7795_CLK_S3D2),
DEF_MOD("i2c2", 929, R8A7795_CLK_S3D2),
DEF_MOD("i2c1", 930, R8A7795_CLK_S3D2),
DEF_MOD("i2c0", 931, R8A7795_CLK_S3D2),
DEF_MOD("ssi-all", 1005, R8A7795_CLK_S3D4),
DEF_MOD("ssi9", 1006, MOD_CLK_ID(1005)),
DEF_MOD("ssi8", 1007, MOD_CLK_ID(1005)),
DEF_MOD("ssi7", 1008, MOD_CLK_ID(1005)),
DEF_MOD("ssi6", 1009, MOD_CLK_ID(1005)),
DEF_MOD("ssi5", 1010, MOD_CLK_ID(1005)),
DEF_MOD("ssi4", 1011, MOD_CLK_ID(1005)),
DEF_MOD("ssi3", 1012, MOD_CLK_ID(1005)),
DEF_MOD("ssi2", 1013, MOD_CLK_ID(1005)),
DEF_MOD("ssi1", 1014, MOD_CLK_ID(1005)),
DEF_MOD("ssi0", 1015, MOD_CLK_ID(1005)),
DEF_MOD("scu-all", 1017, R8A7795_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-src9", 1022, MOD_CLK_ID(1017)),
DEF_MOD("scu-src8", 1023, MOD_CLK_ID(1017)),
DEF_MOD("scu-src7", 1024, MOD_CLK_ID(1017)),
DEF_MOD("scu-src6", 1025, MOD_CLK_ID(1017)),
DEF_MOD("scu-src5", 1026, MOD_CLK_ID(1017)),
DEF_MOD("scu-src4", 1027, MOD_CLK_ID(1017)),
DEF_MOD("scu-src3", 1028, MOD_CLK_ID(1017)),
DEF_MOD("scu-src2", 1029, MOD_CLK_ID(1017)),
DEF_MOD("scu-src1", 1030, MOD_CLK_ID(1017)),
DEF_MOD("scu-src0", 1031, MOD_CLK_ID(1017)),
};
static const unsigned int r8a7795_crit_mod_clks[] __initconst = {
MOD_CLK_ID(408), /* INTC-AP (GIC) */
};
#define CPG_PLL0CR 0x00d8
#define CPG_PLL2CR 0x002c
#define CPG_PLL4CR 0x01f4
/*
* CPG Clock Data
*/
/*
* MD EXTAL PLL0 PLL1 PLL2 PLL3 PLL4
* 14 13 19 17 (MHz)
*-------------------------------------------------------------------
* 0 0 0 0 16.66 x 1 x180 x192 x144 x192 x144
* 0 0 0 1 16.66 x 1 x180 x192 x144 x128 x144
* 0 0 1 0 Prohibited setting
* 0 0 1 1 16.66 x 1 x180 x192 x144 x192 x144
* 0 1 0 0 20 x 1 x150 x160 x120 x160 x120
* 0 1 0 1 20 x 1 x150 x160 x120 x106 x120
* 0 1 1 0 Prohibited setting
* 0 1 1 1 20 x 1 x150 x160 x120 x160 x120
* 1 0 0 0 25 x 1 x120 x128 x96 x128 x96
* 1 0 0 1 25 x 1 x120 x128 x96 x84 x96
* 1 0 1 0 Prohibited setting
* 1 0 1 1 25 x 1 x120 x128 x96 x128 x96
* 1 1 0 0 33.33 / 2 x180 x192 x144 x192 x144
* 1 1 0 1 33.33 / 2 x180 x192 x144 x128 x144
* 1 1 1 0 Prohibited setting
* 1 1 1 1 33.33 / 2 x180 x192 x144 x192 x144
*/
#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 11) | \
(((md) & BIT(13)) >> 11) | \
(((md) & BIT(19)) >> 18) | \
(((md) & BIT(17)) >> 17))
struct cpg_pll_config {
unsigned int extal_div;
unsigned int pll1_mult;
unsigned int pll3_mult;
};
static const struct 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, },
};
static const struct cpg_pll_config *cpg_pll_config __initdata;
static
struct clk * __init r8a7795_cpg_clk_register(struct device *dev,
const struct cpg_core_clk *core,
const struct cpg_mssr_info *info,
struct clk **clks,
void __iomem *base)
{
const struct clk *parent;
unsigned int mult = 1;
unsigned int div = 1;
u32 value;
parent = clks[core->parent];
if (IS_ERR(parent))
return ERR_CAST(parent);
switch (core->type) {
case CLK_TYPE_GEN3_MAIN:
div = cpg_pll_config->extal_div;
break;
case CLK_TYPE_GEN3_PLL0:
/*
* PLL0 is a configurable multiplier clock. Register it as a
* fixed factor clock for now as there's no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value.
*/
value = readl(base + CPG_PLL0CR);
mult = (((value >> 24) & 0x7f) + 1) * 2;
break;
case CLK_TYPE_GEN3_PLL1:
mult = cpg_pll_config->pll1_mult;
break;
case CLK_TYPE_GEN3_PLL2:
/*
* PLL2 is a configurable multiplier clock. Register it as a
* fixed factor clock for now as there's no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value.
*/
value = readl(base + CPG_PLL2CR);
mult = (((value >> 24) & 0x7f) + 1) * 2;
break;
case CLK_TYPE_GEN3_PLL3:
mult = cpg_pll_config->pll3_mult;
break;
case CLK_TYPE_GEN3_PLL4:
/*
* PLL4 is a configurable multiplier clock. Register it as a
* fixed factor clock for now as there's no generic multiplier
* clock implementation and we currently have no need to change
* the multiplier value.
*/
value = readl(base + CPG_PLL4CR);
mult = (((value >> 24) & 0x7f) + 1) * 2;
break;
default:
return ERR_PTR(-EINVAL);
}
return clk_register_fixed_factor(NULL, core->name,
__clk_get_name(parent), 0, mult, div);
}
/*
* Reset register definitions.
*/
#define MODEMR 0xe6160060
static u32 rcar_gen3_read_mode_pins(void)
{
void __iomem *modemr = ioremap_nocache(MODEMR, 4);
u32 mode;
BUG_ON(!modemr);
mode = ioread32(modemr);
iounmap(modemr);
return mode;
}
static int __init r8a7795_cpg_mssr_init(struct device *dev)
{
u32 cpg_mode = rcar_gen3_read_mode_pins();
cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)];
if (!cpg_pll_config->extal_div) {
dev_err(dev, "Prohibited setting (cpg_mode=0x%x)\n", cpg_mode);
return -EINVAL;
}
return 0;
}
const struct cpg_mssr_info r8a7795_cpg_mssr_info __initconst = {
/* Core Clocks */
.core_clks = r8a7795_core_clks,
.num_core_clks = ARRAY_SIZE(r8a7795_core_clks),
.last_dt_core_clk = LAST_DT_CORE_CLK,
.num_total_core_clks = MOD_CLK_BASE,
/* Module Clocks */
.mod_clks = r8a7795_mod_clks,
.num_mod_clks = ARRAY_SIZE(r8a7795_mod_clks),
.num_hw_mod_clks = 12 * 32,
/* Critical Module Clocks */
.crit_mod_clks = r8a7795_crit_mod_clks,
.num_crit_mod_clks = ARRAY_SIZE(r8a7795_crit_mod_clks),
/* Callbacks */
.init = r8a7795_cpg_mssr_init,
.cpg_clk_register = r8a7795_cpg_clk_register,
};

View File

@ -0,0 +1,596 @@
/*
* Renesas Clock Pulse Generator / Module Standby and Software Reset
*
* Copyright (C) 2015 Glider bvba
*
* Based on clk-mstp.c, clk-rcar-gen2.c, and clk-rcar-gen3.c
*
* Copyright (C) 2013 Ideas On Board SPRL
* 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/clk.h>
#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/slab.h>
#include <dt-bindings/clock/renesas-cpg-mssr.h>
#include "renesas-cpg-mssr.h"
#include "clk-div6.h"
#ifdef DEBUG
#define WARN_DEBUG(x) do { } while (0)
#else
#define WARN_DEBUG(x) WARN_ON(x)
#endif
/*
* Module Standby and Software Reset register offets.
*
* If the registers exist, these are valid for SH-Mobile, R-Mobile,
* R-Car Gen 2, and R-Car Gen 3.
* These are NOT valid for R-Car Gen1 and RZ/A1!
*/
/*
* Module Stop Status Register offsets
*/
static const u16 mstpsr[] = {
0x030, 0x038, 0x040, 0x048, 0x04C, 0x03C, 0x1C0, 0x1C4,
0x9A0, 0x9A4, 0x9A8, 0x9AC,
};
#define MSTPSR(i) mstpsr[i]
/*
* System Module Stop Control Register offsets
*/
static const u16 smstpcr[] = {
0x130, 0x134, 0x138, 0x13C, 0x140, 0x144, 0x148, 0x14C,
0x990, 0x994, 0x998, 0x99C,
};
#define SMSTPCR(i) smstpcr[i]
/*
* Software Reset Register offsets
*/
static const u16 srcr[] = {
0x0A0, 0x0A8, 0x0B0, 0x0B8, 0x0BC, 0x0C4, 0x1C8, 0x1CC,
0x920, 0x924, 0x928, 0x92C,
};
#define SRCR(i) srcr[i]
/* Realtime Module Stop Control Register offsets */
#define RMSTPCR(i) (smstpcr[i] - 0x20)
/* Modem Module Stop Control Register offsets (r8a73a4) */
#define MMSTPCR(i) (smstpcr[i] + 0x20)
/* Software Reset Clearing Register offsets */
#define SRSTCLR(i) (0x940 + (i) * 4)
/**
* Clock Pulse Generator / Module Standby and Software Reset Private Data
*
* @dev: CPG/MSSR device
* @base: CPG/MSSR register block base address
* @mstp_lock: protects writes to SMSTPCR
* @clks: Array containing all Core and Module Clocks
* @num_core_clks: Number of Core Clocks in clks[]
* @num_mod_clks: Number of Module Clocks in clks[]
* @last_dt_core_clk: ID of the last Core Clock exported to DT
*/
struct cpg_mssr_priv {
struct device *dev;
void __iomem *base;
spinlock_t mstp_lock;
struct clk **clks;
unsigned int num_core_clks;
unsigned int num_mod_clks;
unsigned int last_dt_core_clk;
};
/**
* struct mstp_clock - MSTP gating clock
* @hw: handle between common and hardware-specific interfaces
* @index: MSTP clock number
* @priv: CPG/MSSR private data
*/
struct mstp_clock {
struct clk_hw hw;
u32 index;
struct cpg_mssr_priv *priv;
};
#define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw)
static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable)
{
struct mstp_clock *clock = to_mstp_clock(hw);
struct cpg_mssr_priv *priv = clock->priv;
unsigned int reg = clock->index / 32;
unsigned int bit = clock->index % 32;
struct device *dev = priv->dev;
u32 bitmask = BIT(bit);
unsigned long flags;
unsigned int i;
u32 value;
dev_dbg(dev, "MSTP %u%02u/%pC %s\n", reg, bit, hw->clk,
enable ? "ON" : "OFF");
spin_lock_irqsave(&priv->mstp_lock, flags);
value = clk_readl(priv->base + SMSTPCR(reg));
if (enable)
value &= ~bitmask;
else
value |= bitmask;
clk_writel(value, priv->base + SMSTPCR(reg));
spin_unlock_irqrestore(&priv->mstp_lock, flags);
if (!enable)
return 0;
for (i = 1000; i > 0; --i) {
if (!(clk_readl(priv->base + MSTPSR(reg)) &
bitmask))
break;
cpu_relax();
}
if (!i) {
dev_err(dev, "Failed to enable SMSTP %p[%d]\n",
priv->base + SMSTPCR(reg), bit);
return -ETIMEDOUT;
}
return 0;
}
static int cpg_mstp_clock_enable(struct clk_hw *hw)
{
return cpg_mstp_clock_endisable(hw, true);
}
static void cpg_mstp_clock_disable(struct clk_hw *hw)
{
cpg_mstp_clock_endisable(hw, false);
}
static int cpg_mstp_clock_is_enabled(struct clk_hw *hw)
{
struct mstp_clock *clock = to_mstp_clock(hw);
struct cpg_mssr_priv *priv = clock->priv;
u32 value;
value = clk_readl(priv->base + MSTPSR(clock->index / 32));
return !(value & BIT(clock->index % 32));
}
static const struct clk_ops cpg_mstp_clock_ops = {
.enable = cpg_mstp_clock_enable,
.disable = cpg_mstp_clock_disable,
.is_enabled = cpg_mstp_clock_is_enabled,
};
static
struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec,
void *data)
{
unsigned int clkidx = clkspec->args[1];
struct cpg_mssr_priv *priv = data;
struct device *dev = priv->dev;
unsigned int idx;
const char *type;
struct clk *clk;
switch (clkspec->args[0]) {
case CPG_CORE:
type = "core";
if (clkidx > priv->last_dt_core_clk) {
dev_err(dev, "Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = priv->clks[clkidx];
break;
case CPG_MOD:
type = "module";
idx = MOD_CLK_PACK(clkidx);
if (clkidx % 100 > 31 || idx >= priv->num_mod_clks) {
dev_err(dev, "Invalid %s clock index %u\n", type,
clkidx);
return ERR_PTR(-EINVAL);
}
clk = priv->clks[priv->num_core_clks + idx];
break;
default:
dev_err(dev, "Invalid CPG clock type %u\n", clkspec->args[0]);
return ERR_PTR(-EINVAL);
}
if (IS_ERR(clk))
dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx,
PTR_ERR(clk));
else
dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n",
clkspec->args[0], clkspec->args[1], clk, clk);
return clk;
}
static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core,
const struct cpg_mssr_info *info,
struct cpg_mssr_priv *priv)
{
struct clk *clk = NULL, *parent;
struct device *dev = priv->dev;
unsigned int id = core->id;
const char *parent_name;
WARN_DEBUG(id >= priv->num_core_clks);
WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
switch (core->type) {
case CLK_TYPE_IN:
clk = of_clk_get_by_name(priv->dev->of_node, core->name);
break;
case CLK_TYPE_FF:
case CLK_TYPE_DIV6P1:
WARN_DEBUG(core->parent >= priv->num_core_clks);
parent = priv->clks[core->parent];
if (IS_ERR(parent)) {
clk = parent;
goto fail;
}
parent_name = __clk_get_name(parent);
if (core->type == CLK_TYPE_FF) {
clk = clk_register_fixed_factor(NULL, core->name,
parent_name, 0,
core->mult, core->div);
} else {
clk = cpg_div6_register(core->name, 1, &parent_name,
priv->base + core->offset);
}
break;
default:
if (info->cpg_clk_register)
clk = info->cpg_clk_register(dev, core, info,
priv->clks, priv->base);
else
dev_err(dev, "%s has unsupported core clock type %u\n",
core->name, core->type);
break;
}
if (IS_ERR_OR_NULL(clk))
goto fail;
dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk);
priv->clks[id] = clk;
return;
fail:
dev_err(dev, "Failed to register %s clock %s: %ld\n", "core,",
core->name, PTR_ERR(clk));
}
static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod,
const struct cpg_mssr_info *info,
struct cpg_mssr_priv *priv)
{
struct mstp_clock *clock = NULL;
struct device *dev = priv->dev;
unsigned int id = mod->id;
struct clk_init_data init;
struct clk *parent, *clk;
const char *parent_name;
unsigned int i;
WARN_DEBUG(id < priv->num_core_clks);
WARN_DEBUG(id >= priv->num_core_clks + priv->num_mod_clks);
WARN_DEBUG(mod->parent >= priv->num_core_clks + priv->num_mod_clks);
WARN_DEBUG(PTR_ERR(priv->clks[id]) != -ENOENT);
parent = priv->clks[mod->parent];
if (IS_ERR(parent)) {
clk = parent;
goto fail;
}
clock = kzalloc(sizeof(*clock), GFP_KERNEL);
if (!clock) {
clk = ERR_PTR(-ENOMEM);
goto fail;
}
init.name = mod->name;
init.ops = &cpg_mstp_clock_ops;
init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT;
for (i = 0; i < info->num_crit_mod_clks; i++)
if (id == info->crit_mod_clks[i]) {
#ifdef CLK_ENABLE_HAND_OFF
dev_dbg(dev, "MSTP %s setting CLK_ENABLE_HAND_OFF\n",
mod->name);
init.flags |= CLK_ENABLE_HAND_OFF;
break;
#else
dev_dbg(dev, "Ignoring MSTP %s to prevent disabling\n",
mod->name);
return;
#endif
}
parent_name = __clk_get_name(parent);
init.parent_names = &parent_name;
init.num_parents = 1;
clock->index = id - priv->num_core_clks;
clock->priv = priv;
clock->hw.init = &init;
clk = clk_register(NULL, &clock->hw);
if (IS_ERR(clk))
goto fail;
dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk);
priv->clks[id] = clk;
return;
fail:
dev_err(dev, "Failed to register %s clock %s: %ld\n", "module,",
mod->name, PTR_ERR(clk));
kfree(clock);
}
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
struct cpg_mssr_clk_domain {
struct generic_pm_domain genpd;
struct device_node *np;
unsigned int num_core_pm_clks;
unsigned int core_pm_clks[0];
};
static bool cpg_mssr_is_pm_clk(const struct of_phandle_args *clkspec,
struct cpg_mssr_clk_domain *pd)
{
unsigned int i;
if (clkspec->np != pd->np || clkspec->args_count != 2)
return false;
switch (clkspec->args[0]) {
case CPG_CORE:
for (i = 0; i < pd->num_core_pm_clks; i++)
if (clkspec->args[1] == pd->core_pm_clks[i])
return true;
return false;
case CPG_MOD:
return true;
default:
return false;
}
}
static int cpg_mssr_attach_dev(struct generic_pm_domain *genpd,
struct device *dev)
{
struct cpg_mssr_clk_domain *pd =
container_of(genpd, struct cpg_mssr_clk_domain, genpd);
struct device_node *np = dev->of_node;
struct of_phandle_args clkspec;
struct clk *clk;
int i = 0;
int error;
while (!of_parse_phandle_with_args(np, "clocks", "#clock-cells", i,
&clkspec)) {
if (cpg_mssr_is_pm_clk(&clkspec, pd))
goto found;
of_node_put(clkspec.np);
i++;
}
return 0;
found:
clk = of_clk_get_from_provider(&clkspec);
of_node_put(clkspec.np);
if (IS_ERR(clk))
return PTR_ERR(clk);
error = pm_clk_create(dev);
if (error) {
dev_err(dev, "pm_clk_create failed %d\n", error);
goto fail_put;
}
error = pm_clk_add_clk(dev, clk);
if (error) {
dev_err(dev, "pm_clk_add_clk %pC failed %d\n", clk, error);
goto fail_destroy;
}
return 0;
fail_destroy:
pm_clk_destroy(dev);
fail_put:
clk_put(clk);
return error;
}
static void cpg_mssr_detach_dev(struct generic_pm_domain *genpd,
struct device *dev)
{
if (!list_empty(&dev->power.subsys_data->clock_list))
pm_clk_destroy(dev);
}
static int __init cpg_mssr_add_clk_domain(struct device *dev,
const unsigned int *core_pm_clks,
unsigned int num_core_pm_clks)
{
struct device_node *np = dev->of_node;
struct generic_pm_domain *genpd;
struct cpg_mssr_clk_domain *pd;
size_t pm_size = num_core_pm_clks * sizeof(core_pm_clks[0]);
pd = devm_kzalloc(dev, sizeof(*pd) + pm_size, GFP_KERNEL);
if (!pd)
return -ENOMEM;
pd->np = np;
pd->num_core_pm_clks = num_core_pm_clks;
memcpy(pd->core_pm_clks, core_pm_clks, pm_size);
genpd = &pd->genpd;
genpd->name = np->name;
genpd->flags = GENPD_FLAG_PM_CLK;
pm_genpd_init(genpd, &simple_qos_governor, false);
genpd->attach_dev = cpg_mssr_attach_dev;
genpd->detach_dev = cpg_mssr_detach_dev;
of_genpd_add_provider_simple(np, genpd);
return 0;
}
#else
static inline int cpg_mssr_add_clk_domain(struct device *dev,
const unsigned int *core_pm_clks,
unsigned int num_core_pm_clks)
{
return 0;
}
#endif /* !CONFIG_PM_GENERIC_DOMAINS_OF */
static const struct of_device_id cpg_mssr_match[] = {
#ifdef CONFIG_ARCH_R8A7795
{
.compatible = "renesas,r8a7795-cpg-mssr",
.data = &r8a7795_cpg_mssr_info,
},
#endif
{ /* sentinel */ }
};
static void cpg_mssr_del_clk_provider(void *data)
{
of_clk_del_provider(data);
}
static int __init cpg_mssr_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
const struct cpg_mssr_info *info;
struct cpg_mssr_priv *priv;
unsigned int nclks, i;
struct resource *res;
struct clk **clks;
int error;
info = of_match_node(cpg_mssr_match, np)->data;
if (info->init) {
error = info->init(dev);
if (error)
return error;
}
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
spin_lock_init(&priv->mstp_lock);
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);
nclks = info->num_total_core_clks + info->num_hw_mod_clks;
clks = devm_kmalloc_array(dev, nclks, sizeof(*clks), GFP_KERNEL);
if (!clks)
return -ENOMEM;
priv->clks = clks;
priv->num_core_clks = info->num_total_core_clks;
priv->num_mod_clks = info->num_hw_mod_clks;
priv->last_dt_core_clk = info->last_dt_core_clk;
for (i = 0; i < nclks; i++)
clks[i] = ERR_PTR(-ENOENT);
for (i = 0; i < info->num_core_clks; i++)
cpg_mssr_register_core_clk(&info->core_clks[i], info, priv);
for (i = 0; i < info->num_mod_clks; i++)
cpg_mssr_register_mod_clk(&info->mod_clks[i], info, priv);
error = of_clk_add_provider(np, cpg_mssr_clk_src_twocell_get, priv);
if (error)
return error;
devm_add_action(dev, cpg_mssr_del_clk_provider, np);
error = cpg_mssr_add_clk_domain(dev, info->core_pm_clks,
info->num_core_pm_clks);
if (error)
return error;
return 0;
}
static struct platform_driver cpg_mssr_driver = {
.driver = {
.name = "renesas-cpg-mssr",
.of_match_table = cpg_mssr_match,
},
};
static int __init cpg_mssr_init(void)
{
return platform_driver_probe(&cpg_mssr_driver, cpg_mssr_probe);
}
subsys_initcall(cpg_mssr_init);
MODULE_DESCRIPTION("Renesas CPG/MSSR Driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,132 @@
/*
* Renesas Clock Pulse Generator / Module Standby and Software Reset
*
* 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.
*/
#ifndef __CLK_RENESAS_CPG_MSSR_H__
#define __CLK_RENESAS_CPG_MSSR_H__
/*
* Definitions of CPG Core Clocks
*
* These include:
* - Clock outputs exported to DT
* - External input clocks
* - Internal CPG clocks
*/
struct cpg_core_clk {
/* Common */
const char *name;
unsigned int id;
unsigned int type;
/* Depending on type */
unsigned int parent; /* Core Clocks only */
unsigned int div;
unsigned int mult;
unsigned int offset;
};
enum clk_types {
/* Generic */
CLK_TYPE_IN, /* External Clock Input */
CLK_TYPE_FF, /* Fixed Factor Clock */
CLK_TYPE_DIV6P1, /* DIV6 Clock with 1 parent clock */
/* Custom definitions start here */
CLK_TYPE_CUSTOM,
};
#define DEF_TYPE(_name, _id, _type...) \
{ .name = _name, .id = _id, .type = _type }
#define DEF_BASE(_name, _id, _type, _parent...) \
DEF_TYPE(_name, _id, _type, .parent = _parent)
#define DEF_INPUT(_name, _id) \
DEF_TYPE(_name, _id, CLK_TYPE_IN)
#define DEF_FIXED(_name, _id, _parent, _div, _mult) \
DEF_BASE(_name, _id, CLK_TYPE_FF, _parent, .div = _div, .mult = _mult)
#define DEF_DIV6P1(_name, _id, _parent, _offset) \
DEF_BASE(_name, _id, CLK_TYPE_DIV6P1, _parent, .offset = _offset)
/*
* Definitions of Module Clocks
*/
struct mssr_mod_clk {
const char *name;
unsigned int id;
unsigned int parent; /* Add MOD_CLK_BASE for Module Clocks */
};
/* Convert from sparse base-100 to packed index space */
#define MOD_CLK_PACK(x) ((x) - ((x) / 100) * (100 - 32))
#define MOD_CLK_ID(x) (MOD_CLK_BASE + MOD_CLK_PACK(x))
#define DEF_MOD(_name, _mod, _parent...) \
{ .name = _name, .id = MOD_CLK_ID(_mod), .parent = _parent }
struct device_node;
/**
* SoC-specific CPG/MSSR Description
*
* @core_clks: Array of Core Clock definitions
* @num_core_clks: Number of entries in core_clks[]
* @last_dt_core_clk: ID of the last Core Clock exported to DT
* @num_total_core_clks: Total number of Core Clocks (exported + internal)
*
* @mod_clks: Array of Module Clock definitions
* @num_mod_clks: Number of entries in mod_clks[]
* @num_hw_mod_clks: Number of Module Clocks supported by the hardware
*
* @crit_mod_clks: Array with Module Clock IDs of critical clocks that
* should not be disabled without a knowledgeable driver
* @num_crit_mod_clks: Number of entries in crit_mod_clks[]
*
* @core_pm_clks: Array with IDs of Core Clocks that are suitable for Power
* Management, in addition to Module Clocks
* @num_core_pm_clks: Number of entries in core_pm_clks[]
*
* @init: Optional callback to perform SoC-specific initialization
* @cpg_clk_register: Optional callback to handle special Core Clock types
*/
struct cpg_mssr_info {
/* Core Clocks */
const struct cpg_core_clk *core_clks;
unsigned int num_core_clks;
unsigned int last_dt_core_clk;
unsigned int num_total_core_clks;
/* Module Clocks */
const struct mssr_mod_clk *mod_clks;
unsigned int num_mod_clks;
unsigned int num_hw_mod_clks;
/* Critical Module Clocks that should not be disabled */
const unsigned int *crit_mod_clks;
unsigned int num_crit_mod_clks;
/* Core Clocks suitable for PM, in addition to the Module Clocks */
const unsigned int *core_pm_clks;
unsigned int num_core_pm_clks;
/* Callbacks */
int (*init)(struct device *dev);
struct clk *(*cpg_clk_register)(struct device *dev,
const struct cpg_core_clk *core,
const struct cpg_mssr_info *info,
struct clk **clks, void __iomem *base);
};
extern const struct cpg_mssr_info r8a7795_cpg_mssr_info;
#endif

View File

@ -549,19 +549,20 @@ static int clk_fs660c32_vco_get_params(unsigned long input,
return 0;
}
static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw, unsigned long rate
, unsigned long *prate)
static long quadfs_pll_fs660c32_round_rate(struct clk_hw *hw,
unsigned long rate,
unsigned long *prate)
{
struct stm_fs params;
if (!clk_fs660c32_vco_get_params(*prate, rate, &params))
clk_fs660c32_vco_get_rate(*prate, &params, &rate);
if (clk_fs660c32_vco_get_params(*prate, rate, &params))
return rate;
pr_debug("%s: %s new rate %ld [sdiv=0x%x,md=0x%x,pe=0x%x,nsdiv3=%u]\n",
clk_fs660c32_vco_get_rate(*prate, &params, &rate);
pr_debug("%s: %s new rate %ld [ndiv=%u]\n",
__func__, clk_hw_get_name(hw),
rate, (unsigned int)params.sdiv,
(unsigned int)params.mdiv,
(unsigned int)params.pe, (unsigned int)params.nsdiv);
rate, (unsigned int)params.ndiv);
return rate;
}

View File

@ -7,14 +7,19 @@ obj-y += clk-a10-codec.o
obj-y += clk-a10-hosc.o
obj-y += clk-a10-mod1.o
obj-y += clk-a10-pll2.o
obj-y += clk-a10-ve.o
obj-y += clk-a20-gmac.o
obj-y += clk-mod0.o
obj-y += clk-simple-gates.o
obj-y += clk-sun8i-bus-gates.o
obj-y += clk-sun8i-mbus.o
obj-y += clk-sun9i-core.o
obj-y += clk-sun9i-mmc.o
obj-y += clk-usb.o
obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o
obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
clk-sun8i-apb0.o

View File

@ -0,0 +1,171 @@
/*
* Copyright 2015 Chen-Yu Tsai
*
* Chen-Yu Tsai <wens@csie.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.
*/
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
static DEFINE_SPINLOCK(ve_lock);
#define SUN4I_VE_ENABLE 31
#define SUN4I_VE_DIVIDER_SHIFT 16
#define SUN4I_VE_DIVIDER_WIDTH 3
#define SUN4I_VE_RESET 0
/**
* sunxi_ve_reset... - reset bit in ve clk registers handling
*/
struct ve_reset_data {
void __iomem *reg;
spinlock_t *lock;
struct reset_controller_dev rcdev;
};
static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct ve_reset_data *data = container_of(rcdev,
struct ve_reset_data,
rcdev);
unsigned long flags;
u32 reg;
spin_lock_irqsave(data->lock, flags);
reg = readl(data->reg);
writel(reg & ~BIT(SUN4I_VE_RESET), data->reg);
spin_unlock_irqrestore(data->lock, flags);
return 0;
}
static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev,
unsigned long id)
{
struct ve_reset_data *data = container_of(rcdev,
struct ve_reset_data,
rcdev);
unsigned long flags;
u32 reg;
spin_lock_irqsave(data->lock, flags);
reg = readl(data->reg);
writel(reg | BIT(SUN4I_VE_RESET), data->reg);
spin_unlock_irqrestore(data->lock, flags);
return 0;
}
static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,
const struct of_phandle_args *reset_spec)
{
if (WARN_ON(reset_spec->args_count != 0))
return -EINVAL;
return 0;
}
static struct reset_control_ops sunxi_ve_reset_ops = {
.assert = sunxi_ve_reset_assert,
.deassert = sunxi_ve_reset_deassert,
};
static void __init sun4i_ve_clk_setup(struct device_node *node)
{
struct clk *clk;
struct clk_divider *div;
struct clk_gate *gate;
struct ve_reset_data *reset_data;
const char *parent;
const char *clk_name = node->name;
void __iomem *reg;
int err;
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg))
return;
div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div)
goto err_unmap;
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate)
goto err_free_div;
of_property_read_string(node, "clock-output-names", &clk_name);
parent = of_clk_get_parent_name(node, 0);
gate->reg = reg;
gate->bit_idx = SUN4I_VE_ENABLE;
gate->lock = &ve_lock;
div->reg = reg;
div->shift = SUN4I_VE_DIVIDER_SHIFT;
div->width = SUN4I_VE_DIVIDER_WIDTH;
div->lock = &ve_lock;
clk = clk_register_composite(NULL, clk_name, &parent, 1,
NULL, NULL,
&div->hw, &clk_divider_ops,
&gate->hw, &clk_gate_ops,
CLK_SET_RATE_PARENT);
if (IS_ERR(clk))
goto err_free_gate;
err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
if (err)
goto err_unregister_clk;
reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
if (!reset_data)
goto err_del_provider;
reset_data->reg = reg;
reset_data->lock = &ve_lock;
reset_data->rcdev.nr_resets = 1;
reset_data->rcdev.ops = &sunxi_ve_reset_ops;
reset_data->rcdev.of_node = node;
reset_data->rcdev.of_xlate = sunxi_ve_of_xlate;
reset_data->rcdev.of_reset_n_cells = 0;
err = reset_controller_register(&reset_data->rcdev);
if (err)
goto err_free_reset;
return;
err_free_reset:
kfree(reset_data);
err_del_provider:
of_clk_del_provider(node);
err_unregister_clk:
clk_unregister(clk);
err_free_gate:
kfree(gate);
err_free_div:
kfree(div);
err_unmap:
iounmap(reg);
}
CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk",
sun4i_ve_clk_setup);

View File

@ -140,6 +140,8 @@ CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
sunxi_simple_gates_init);
CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
sunxi_simple_gates_init);
CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
sunxi_simple_gates_init);
static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
14, /* ahb_sdram */
@ -158,3 +160,15 @@ CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner,sun5i-a13-ahb-gates-clk",
sun4i_a10_ahb_init);
CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
sun4i_a10_ahb_init);
static const int sun4i_a10_dram_critical_clocks[] __initconst = {
15, /* dram_output */
};
static void __init sun4i_a10_dram_init(struct device_node *node)
{
sunxi_simple_gates_setup(node, sun4i_a10_dram_critical_clocks,
ARRAY_SIZE(sun4i_a10_dram_critical_clocks));
}
CLK_OF_DECLARE(sun4i_a10_dram, "allwinner,sun4i-a10-dram-gates-clk",
sun4i_a10_dram_init);

View File

@ -17,13 +17,77 @@
#include <linux/clk-provider.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
static struct clk *sun8i_a23_apb0_register(struct device_node *node,
void __iomem *reg)
{
const char *clk_name = node->name;
const char *clk_parent;
struct clk *clk;
int ret;
clk_parent = of_clk_get_parent_name(node, 0);
if (!clk_parent)
return ERR_PTR(-EINVAL);
of_property_read_string(node, "clock-output-names", &clk_name);
/* The A23 APB0 clock is a standard 2 bit wide divider clock */
clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg,
0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
if (IS_ERR(clk))
return clk;
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
if (ret)
goto err_unregister;
return clk;
err_unregister:
clk_unregister_divider(clk);
return ERR_PTR(ret);
}
static void sun8i_a23_apb0_setup(struct device_node *node)
{
void __iomem *reg;
struct resource res;
struct clk *clk;
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg)) {
/*
* This happens with clk nodes instantiated through mfd,
* as those do not have their resources assigned in the
* device tree. Do not print an error in this case.
*/
if (PTR_ERR(reg) != -EINVAL)
pr_err("Could not get registers for a23-apb0-clk\n");
return;
}
clk = sun8i_a23_apb0_register(node, reg);
if (IS_ERR(clk))
goto err_unmap;
return;
err_unmap:
iounmap(reg);
of_address_to_resource(node, 0, &res);
release_mem_region(res.start, resource_size(&res));
}
CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk",
sun8i_a23_apb0_setup);
static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
const char *clk_name = np->name;
const char *clk_parent;
struct resource *r;
void __iomem *reg;
struct clk *clk;
@ -33,19 +97,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev)
if (IS_ERR(reg))
return PTR_ERR(reg);
clk_parent = of_clk_get_parent_name(np, 0);
if (!clk_parent)
return -EINVAL;
of_property_read_string(np, "clock-output-names", &clk_name);
/* The A23 APB0 clock is a standard 2 bit wide divider clock */
clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg,
0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL);
clk = sun8i_a23_apb0_register(np, reg);
if (IS_ERR(clk))
return PTR_ERR(clk);
return of_clk_add_provider(np, of_clk_src_simple_get, clk);
return 0;
}
static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = {

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
*
* Based on clk-simple-gates.c, which is:
* Copyright 2015 Maxime Ripard
*
* Maxime Ripard <maxime.ripard@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.
*
* 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/clk.h>
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
static DEFINE_SPINLOCK(gates_lock);
static void __init sun8i_h3_bus_gates_init(struct device_node *node)
{
static const char * const names[] = { "ahb1", "ahb2", "apb1", "apb2" };
enum { AHB1, AHB2, APB1, APB2, PARENT_MAX } clk_parent;
const char *parents[PARENT_MAX];
struct clk_onecell_data *clk_data;
const char *clk_name;
struct property *prop;
struct resource res;
void __iomem *clk_reg;
void __iomem *reg;
const __be32 *p;
int number, i;
u8 clk_bit;
int index;
reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(reg))
return;
for (i = 0; i < ARRAY_SIZE(names); i++) {
int idx = of_property_match_string(node, "clock-names",
names[i]);
if (idx < 0)
return;
parents[i] = of_clk_get_parent_name(node, idx);
}
clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
if (!clk_data)
goto err_unmap;
number = of_property_count_u32_elems(node, "clock-indices");
of_property_read_u32_index(node, "clock-indices", number - 1, &number);
clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL);
if (!clk_data->clks)
goto err_free_data;
i = 0;
of_property_for_each_u32(node, "clock-indices", prop, p, index) {
of_property_read_string_index(node, "clock-output-names",
i, &clk_name);
if (index == 17 || (index >= 29 && index <= 31))
clk_parent = AHB2;
else if (index <= 63 || index >= 128)
clk_parent = AHB1;
else if (index >= 64 && index <= 95)
clk_parent = APB1;
else if (index >= 96 && index <= 127)
clk_parent = APB2;
clk_reg = reg + 4 * (index / 32);
clk_bit = index % 32;
clk_data->clks[index] = clk_register_gate(NULL, clk_name,
parents[clk_parent],
0, clk_reg, clk_bit,
0, &gates_lock);
i++;
if (IS_ERR(clk_data->clks[index])) {
WARN_ON(true);
continue;
}
}
clk_data->clk_num = number + 1;
of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
return;
err_free_data:
kfree(clk_data);
err_unmap:
iounmap(reg);
of_address_to_resource(node, 0, &res);
release_mem_region(res.start, resource_size(&res));
}
CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk",
sun8i_h3_bus_gates_init);

View File

@ -0,0 +1,240 @@
/*
* Copyright (C) 2015 Chen-Yu Tsai
*
* Chen-Yu Tsai <wens@csie.org>
*
* Allwinner A80 CPUS clock driver
*
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/of.h>
#include <linux/of_address.h>
static DEFINE_SPINLOCK(sun9i_a80_cpus_lock);
/**
* sun9i_a80_cpus_clk_setup() - Setup function for a80 cpus composite clk
*/
#define SUN9I_CPUS_MAX_PARENTS 4
#define SUN9I_CPUS_MUX_PARENT_PLL4 3
#define SUN9I_CPUS_MUX_SHIFT 16
#define SUN9I_CPUS_MUX_MASK GENMASK(17, 16)
#define SUN9I_CPUS_MUX_GET_PARENT(reg) ((reg & SUN9I_CPUS_MUX_MASK) >> \
SUN9I_CPUS_MUX_SHIFT)
#define SUN9I_CPUS_DIV_SHIFT 4
#define SUN9I_CPUS_DIV_MASK GENMASK(5, 4)
#define SUN9I_CPUS_DIV_GET(reg) ((reg & SUN9I_CPUS_DIV_MASK) >> \
SUN9I_CPUS_DIV_SHIFT)
#define SUN9I_CPUS_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_DIV_MASK) | \
(div << SUN9I_CPUS_DIV_SHIFT))
#define SUN9I_CPUS_PLL4_DIV_SHIFT 8
#define SUN9I_CPUS_PLL4_DIV_MASK GENMASK(12, 8)
#define SUN9I_CPUS_PLL4_DIV_GET(reg) ((reg & SUN9I_CPUS_PLL4_DIV_MASK) >> \
SUN9I_CPUS_PLL4_DIV_SHIFT)
#define SUN9I_CPUS_PLL4_DIV_SET(reg, div) ((reg & ~SUN9I_CPUS_PLL4_DIV_MASK) | \
(div << SUN9I_CPUS_PLL4_DIV_SHIFT))
struct sun9i_a80_cpus_clk {
struct clk_hw hw;
void __iomem *reg;
};
#define to_sun9i_a80_cpus_clk(_hw) container_of(_hw, struct sun9i_a80_cpus_clk, hw)
static unsigned long sun9i_a80_cpus_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
unsigned long rate;
u32 reg;
/* Fetch the register value */
reg = readl(cpus->reg);
/* apply pre-divider first if parent is pll4 */
if (SUN9I_CPUS_MUX_GET_PARENT(reg) == SUN9I_CPUS_MUX_PARENT_PLL4)
parent_rate /= SUN9I_CPUS_PLL4_DIV_GET(reg) + 1;
/* clk divider */
rate = parent_rate / (SUN9I_CPUS_DIV_GET(reg) + 1);
return rate;
}
static long sun9i_a80_cpus_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
u8 parent, unsigned long parent_rate)
{
u8 div, pre_div = 1;
/*
* clock can only divide, so we will never be able to achieve
* frequencies higher than the parent frequency
*/
if (parent_rate && rate > parent_rate)
rate = parent_rate;
div = DIV_ROUND_UP(parent_rate, rate);
/* calculate pre-divider if parent is pll4 */
if (parent == SUN9I_CPUS_MUX_PARENT_PLL4 && div > 4) {
/* pre-divider is 1 ~ 32 */
if (div < 32) {
pre_div = div;
div = 1;
} else if (div < 64) {
pre_div = DIV_ROUND_UP(div, 2);
div = 2;
} else if (div < 96) {
pre_div = DIV_ROUND_UP(div, 3);
div = 3;
} else {
pre_div = DIV_ROUND_UP(div, 4);
div = 4;
}
}
/* we were asked to pass back divider values */
if (divp) {
*divp = div - 1;
*pre_divp = pre_div - 1;
}
return parent_rate / pre_div / div;
}
static int sun9i_a80_cpus_clk_determine_rate(struct clk_hw *clk,
struct clk_rate_request *req)
{
struct clk_hw *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
unsigned long rate = req->rate;
/* find the parent that can help provide the fastest rate <= rate */
num_parents = clk_hw_get_num_parents(clk);
for (i = 0; i < num_parents; i++) {
parent = clk_hw_get_parent_by_index(clk, i);
if (!parent)
continue;
if (clk_hw_get_flags(clk) & CLK_SET_RATE_PARENT)
parent_rate = clk_hw_round_rate(parent, rate);
else
parent_rate = clk_hw_get_rate(parent);
child_rate = sun9i_a80_cpus_clk_round(rate, NULL, NULL, i,
parent_rate);
if (child_rate <= rate && child_rate > best_child_rate) {
best_parent = parent;
best = parent_rate;
best_child_rate = child_rate;
}
}
if (!best_parent)
return -EINVAL;
req->best_parent_hw = best_parent;
req->best_parent_rate = best;
req->rate = best_child_rate;
return 0;
}
static int sun9i_a80_cpus_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct sun9i_a80_cpus_clk *cpus = to_sun9i_a80_cpus_clk(hw);
unsigned long flags;
u8 div, pre_div, parent;
u32 reg;
spin_lock_irqsave(&sun9i_a80_cpus_lock, flags);
reg = readl(cpus->reg);
/* need to know which parent is used to apply pre-divider */
parent = SUN9I_CPUS_MUX_GET_PARENT(reg);
sun9i_a80_cpus_clk_round(rate, &div, &pre_div, parent, parent_rate);
reg = SUN9I_CPUS_DIV_SET(reg, div);
reg = SUN9I_CPUS_PLL4_DIV_SET(reg, pre_div);
writel(reg, cpus->reg);
spin_unlock_irqrestore(&sun9i_a80_cpus_lock, flags);
return 0;
}
static const struct clk_ops sun9i_a80_cpus_clk_ops = {
.determine_rate = sun9i_a80_cpus_clk_determine_rate,
.recalc_rate = sun9i_a80_cpus_clk_recalc_rate,
.set_rate = sun9i_a80_cpus_clk_set_rate,
};
static void sun9i_a80_cpus_setup(struct device_node *node)
{
const char *clk_name = node->name;
const char *parents[SUN9I_CPUS_MAX_PARENTS];
struct resource res;
struct sun9i_a80_cpus_clk *cpus;
struct clk_mux *mux;
struct clk *clk;
int ret;
cpus = kzalloc(sizeof(*cpus), GFP_KERNEL);
if (!cpus)
return;
cpus->reg = of_io_request_and_map(node, 0, of_node_full_name(node));
if (IS_ERR(cpus->reg))
goto err_free_cpus;
of_property_read_string(node, "clock-output-names", &clk_name);
/* we have a mux, we will have >1 parents */
ret = of_clk_parent_fill(node, parents, SUN9I_CPUS_MAX_PARENTS);
mux = kzalloc(sizeof(*mux), GFP_KERNEL);
if (!mux)
goto err_unmap;
/* set up clock properties */
mux->reg = cpus->reg;
mux->shift = SUN9I_CPUS_MUX_SHIFT;
/* un-shifted mask is what mux_clk expects */
mux->mask = SUN9I_CPUS_MUX_MASK >> SUN9I_CPUS_MUX_SHIFT;
mux->lock = &sun9i_a80_cpus_lock;
clk = clk_register_composite(NULL, clk_name, parents, ret,
&mux->hw, &clk_mux_ops,
&cpus->hw, &sun9i_a80_cpus_clk_ops,
NULL, NULL, 0);
if (IS_ERR(clk))
goto err_free_mux;
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
if (ret)
goto err_unregister;
return;
err_unregister:
clk_unregister(clk);
err_free_mux:
kfree(mux);
err_unmap:
iounmap(cpus->reg);
of_address_to_resource(node, 0, &res);
release_mem_region(res.start, resource_size(&res));
err_free_cpus:
kfree(cpus);
}
CLK_OF_DECLARE(sun9i_a80_cpus, "allwinner,sun9i-a80-cpus-clk",
sun9i_a80_cpus_setup);

View File

@ -778,6 +778,10 @@ static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = {
.shift = 12,
};
static const struct mux_data sun8i_h3_ahb2_mux_data __initconst = {
.shift = 0,
};
static void __init sunxi_mux_clk_setup(struct device_node *node,
struct mux_data *data)
{
@ -1130,6 +1134,7 @@ static const struct of_device_id clk_divs_match[] __initconst = {
static const struct of_device_id clk_mux_match[] __initconst = {
{.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,},
{.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
{.compatible = "allwinner,sun8i-h3-ahb2-clk", .data = &sun8i_h3_ahb2_mux_data,},
{}
};
@ -1212,6 +1217,7 @@ CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks);
CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
CLK_OF_DECLARE(sun8i_a33_clk_init, "allwinner,sun8i-a33", sun6i_init_clocks);
CLK_OF_DECLARE(sun8i_h3_clk_init, "allwinner,sun8i-h3", sun6i_init_clocks);
static void __init sun9i_init_clocks(struct device_node *node)
{

View File

@ -243,3 +243,15 @@ static void __init sun9i_a80_usb_phy_setup(struct device_node *node)
sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock);
}
CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);
static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst = {
.clk_mask = BIT(19) | BIT(18) | BIT(17) | BIT(16) |
BIT(11) | BIT(10) | BIT(9) | BIT(8),
.reset_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
};
static void __init sun8i_h3_usb_setup(struct device_node *node)
{
sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock);
}
CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup);

View File

@ -20,3 +20,4 @@ obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124-dfll-fcpu.o
obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
obj-y += cvb.o
obj-$(CONFIG_ARCH_TEGRA_210_SOC) += clk-tegra210.o

View File

@ -13,6 +13,7 @@ enum clk_id {
tegra_clk_amx1,
tegra_clk_apbdma,
tegra_clk_apbif,
tegra_clk_ape,
tegra_clk_audio0,
tegra_clk_audio0_2x,
tegra_clk_audio0_mux,
@ -38,6 +39,7 @@ enum clk_id {
tegra_clk_cile,
tegra_clk_clk_32k,
tegra_clk_clk72Mhz,
tegra_clk_clk72Mhz_8,
tegra_clk_clk_m,
tegra_clk_clk_m_div2,
tegra_clk_clk_m_div4,
@ -51,17 +53,21 @@ enum clk_id {
tegra_clk_cml1,
tegra_clk_csi,
tegra_clk_csite,
tegra_clk_csite_8,
tegra_clk_csus,
tegra_clk_cve,
tegra_clk_dam0,
tegra_clk_dam1,
tegra_clk_dam2,
tegra_clk_d_audio,
tegra_clk_dbgapb,
tegra_clk_dds,
tegra_clk_dfll_ref,
tegra_clk_dfll_soc,
tegra_clk_disp1,
tegra_clk_disp1_8,
tegra_clk_disp2,
tegra_clk_disp2_8,
tegra_clk_dp2,
tegra_clk_dpaux,
tegra_clk_dsialp,
@ -71,6 +77,7 @@ enum clk_id {
tegra_clk_dtv,
tegra_clk_emc,
tegra_clk_entropy,
tegra_clk_entropy_8,
tegra_clk_epp,
tegra_clk_epp_8,
tegra_clk_extern1,
@ -85,12 +92,16 @@ enum clk_id {
tegra_clk_gr3d_8,
tegra_clk_hclk,
tegra_clk_hda,
tegra_clk_hda_8,
tegra_clk_hda2codec_2x,
tegra_clk_hda2codec_2x_8,
tegra_clk_hda2hdmi,
tegra_clk_hdmi,
tegra_clk_hdmi_audio,
tegra_clk_host1x,
tegra_clk_host1x_8,
tegra_clk_host1x_9,
tegra_clk_hsic_trk,
tegra_clk_i2c1,
tegra_clk_i2c2,
tegra_clk_i2c3,
@ -110,11 +121,14 @@ enum clk_id {
tegra_clk_i2s4_sync,
tegra_clk_isp,
tegra_clk_isp_8,
tegra_clk_isp_9,
tegra_clk_ispb,
tegra_clk_kbc,
tegra_clk_kfuse,
tegra_clk_la,
tegra_clk_maud,
tegra_clk_mipi,
tegra_clk_mipibif,
tegra_clk_mipi_cal,
tegra_clk_mpe,
tegra_clk_mselect,
@ -124,15 +138,24 @@ enum clk_id {
tegra_clk_ndspeed,
tegra_clk_ndspeed_8,
tegra_clk_nor,
tegra_clk_nvdec,
tegra_clk_nvenc,
tegra_clk_nvjpg,
tegra_clk_owr,
tegra_clk_owr_8,
tegra_clk_pcie,
tegra_clk_pclk,
tegra_clk_pll_a,
tegra_clk_pll_a_out0,
tegra_clk_pll_a1,
tegra_clk_pll_c,
tegra_clk_pll_c2,
tegra_clk_pll_c3,
tegra_clk_pll_c4,
tegra_clk_pll_c4_out0,
tegra_clk_pll_c4_out1,
tegra_clk_pll_c4_out2,
tegra_clk_pll_c4_out3,
tegra_clk_pll_c_out1,
tegra_clk_pll_d,
tegra_clk_pll_d2,
@ -140,19 +163,29 @@ enum clk_id {
tegra_clk_pll_d_out0,
tegra_clk_pll_dp,
tegra_clk_pll_e_out0,
tegra_clk_pll_g_ref,
tegra_clk_pll_m,
tegra_clk_pll_m_out1,
tegra_clk_pll_mb,
tegra_clk_pll_p,
tegra_clk_pll_p_out1,
tegra_clk_pll_p_out2,
tegra_clk_pll_p_out2_int,
tegra_clk_pll_p_out3,
tegra_clk_pll_p_out4,
tegra_clk_pll_p_out4_cpu,
tegra_clk_pll_p_out5,
tegra_clk_pll_p_out_hsio,
tegra_clk_pll_p_out_xusb,
tegra_clk_pll_p_out_cpu,
tegra_clk_pll_p_out_adsp,
tegra_clk_pll_ref,
tegra_clk_pll_re_out,
tegra_clk_pll_re_vco,
tegra_clk_pll_u,
tegra_clk_pll_u_out,
tegra_clk_pll_u_out1,
tegra_clk_pll_u_out2,
tegra_clk_pll_u_12m,
tegra_clk_pll_u_480m,
tegra_clk_pll_u_48m,
@ -160,53 +193,80 @@ enum clk_id {
tegra_clk_pll_x,
tegra_clk_pll_x_out0,
tegra_clk_pwm,
tegra_clk_qspi,
tegra_clk_rtc,
tegra_clk_sata,
tegra_clk_sata_8,
tegra_clk_sata_cold,
tegra_clk_sata_oob,
tegra_clk_sata_oob_8,
tegra_clk_sbc1,
tegra_clk_sbc1_8,
tegra_clk_sbc1_9,
tegra_clk_sbc2,
tegra_clk_sbc2_8,
tegra_clk_sbc2_9,
tegra_clk_sbc3,
tegra_clk_sbc3_8,
tegra_clk_sbc3_9,
tegra_clk_sbc4,
tegra_clk_sbc4_8,
tegra_clk_sbc4_9,
tegra_clk_sbc5,
tegra_clk_sbc5_8,
tegra_clk_sbc6,
tegra_clk_sbc6_8,
tegra_clk_sclk,
tegra_clk_sdmmc_legacy,
tegra_clk_sdmmc1,
tegra_clk_sdmmc1_8,
tegra_clk_sdmmc1_9,
tegra_clk_sdmmc2,
tegra_clk_sdmmc2_8,
tegra_clk_sdmmc2_9,
tegra_clk_sdmmc3,
tegra_clk_sdmmc3_8,
tegra_clk_sdmmc3_9,
tegra_clk_sdmmc4,
tegra_clk_sdmmc4_8,
tegra_clk_sdmmc4_9,
tegra_clk_se,
tegra_clk_soc_therm,
tegra_clk_soc_therm_8,
tegra_clk_sor0,
tegra_clk_sor0_lvds,
tegra_clk_sor1,
tegra_clk_sor1_brick,
tegra_clk_sor1_src,
tegra_clk_spdif,
tegra_clk_spdif_2x,
tegra_clk_spdif_in,
tegra_clk_spdif_in_8,
tegra_clk_spdif_in_sync,
tegra_clk_spdif_mux,
tegra_clk_spdif_out,
tegra_clk_timer,
tegra_clk_trace,
tegra_clk_tsec,
tegra_clk_tsec_8,
tegra_clk_tsecb,
tegra_clk_tsensor,
tegra_clk_tvdac,
tegra_clk_tvo,
tegra_clk_uarta,
tegra_clk_uarta_8,
tegra_clk_uartb,
tegra_clk_uartb_8,
tegra_clk_uartc,
tegra_clk_uartc_8,
tegra_clk_uartd,
tegra_clk_uartd_8,
tegra_clk_uarte,
tegra_clk_uarte_8,
tegra_clk_uartape,
tegra_clk_usb2,
tegra_clk_usb2_hsic_trk,
tegra_clk_usb2_trk,
tegra_clk_usb3,
tegra_clk_usbd,
tegra_clk_vcp,
@ -216,22 +276,35 @@ enum clk_id {
tegra_clk_vi,
tegra_clk_vi_8,
tegra_clk_vi_9,
tegra_clk_vi_10,
tegra_clk_vi_i2c,
tegra_clk_vic03,
tegra_clk_vic03_8,
tegra_clk_vim2_clk,
tegra_clk_vimclk_sync,
tegra_clk_vi_sensor,
tegra_clk_vi_sensor2,
tegra_clk_vi_sensor_8,
tegra_clk_vi_sensor_9,
tegra_clk_vi_sensor2,
tegra_clk_vi_sensor2_8,
tegra_clk_xusb_dev,
tegra_clk_xusb_dev_src,
tegra_clk_xusb_dev_src_8,
tegra_clk_xusb_falcon_src,
tegra_clk_xusb_falcon_src_8,
tegra_clk_xusb_fs_src,
tegra_clk_xusb_gate,
tegra_clk_xusb_host,
tegra_clk_xusb_host_src,
tegra_clk_xusb_host_src_8,
tegra_clk_xusb_hs_src,
tegra_clk_xusb_hs_src_4,
tegra_clk_xusb_ss,
tegra_clk_xusb_ss_src,
tegra_clk_xusb_ss_src_8,
tegra_clk_xusb_ss_div2,
tegra_clk_xusb_ssp_src,
tegra_clk_sclk_mux,
tegra_clk_max,
};

File diff suppressed because it is too large Load Diff

View File

@ -124,6 +124,20 @@
#define CLK_SOURCE_HDMI_AUDIO 0x668
#define CLK_SOURCE_VIC03 0x678
#define CLK_SOURCE_CLK72MHZ 0x66c
#define CLK_SOURCE_DBGAPB 0x718
#define CLK_SOURCE_NVENC 0x6a0
#define CLK_SOURCE_NVDEC 0x698
#define CLK_SOURCE_NVJPG 0x69c
#define CLK_SOURCE_APE 0x6c0
#define CLK_SOURCE_SOR1 0x410
#define CLK_SOURCE_SDMMC_LEGACY 0x694
#define CLK_SOURCE_QSPI 0x6c4
#define CLK_SOURCE_VI_I2C 0x6c8
#define CLK_SOURCE_MIPIBIF 0x660
#define CLK_SOURCE_UARTAPE 0x710
#define CLK_SOURCE_TSECB 0x6d8
#define CLK_SOURCE_MAUD 0x6d4
#define CLK_SOURCE_USB2_HSIC_TRK 0x6cc
#define MASK(x) (BIT(x) - 1)
@ -182,6 +196,13 @@
TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\
_parents##_idx, 0, NULL)
#define UART8(_name, _parents, _offset,\
_clk_num, _clk_id) \
TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\
29, MASK(3), 0, 0, 16, 1, TEGRA_DIVIDER_UART| \
TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\
_parents##_idx, 0, NULL)
#define I2C(_name, _parents, _offset,\
_clk_num, _clk_id) \
TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\
@ -221,8 +242,21 @@
.flags = _flags \
}
#define DIV8(_name, _parent_name, _offset, _clk_id, _flags) \
{ \
.name = _name, \
.clk_id = _clk_id, \
.p.parent_name = _parent_name, \
.periph = TEGRA_CLK_PERIPH(0, 0, 0, 0, 8, 1, \
TEGRA_DIVIDER_ROUND_UP, 0, 0, \
NULL, NULL), \
.offset = _offset, \
.flags = _flags, \
}
#define PLLP_BASE 0xa0
#define PLLP_MISC 0xac
#define PLLP_MISC1 0x680
#define PLLP_OUTA 0xa4
#define PLLP_OUTB 0xa8
#define PLLP_OUTC 0x67c
@ -234,6 +268,7 @@ static DEFINE_SPINLOCK(PLLP_OUTA_lock);
static DEFINE_SPINLOCK(PLLP_OUTB_lock);
static DEFINE_SPINLOCK(PLLP_OUTC_lock);
static DEFINE_SPINLOCK(sor0_lock);
static DEFINE_SPINLOCK(sor1_lock);
#define MUX_I2S_SPDIF(_id) \
static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \
@ -285,6 +320,68 @@ static u32 mux_pllp_clkm_idx[] = {
[0] = 0, [1] = 3,
};
static const char *mux_pllp_clkm_2[] = {
"pll_p", "clk_m"
};
static u32 mux_pllp_clkm_2_idx[] = {
[0] = 2, [1] = 6,
};
static const char *mux_pllc2_c_c3_pllp_plla1_clkm[] = {
"pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a1", "clk_m"
};
static u32 mux_pllc2_c_c3_pllp_plla1_clkm_idx[] = {
[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 6, [5] = 7,
};
static const char *
mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0[] = {
"pll_c4_out1", "pll_c", "pll_c4_out2", "pll_p", "clk_m",
"pll_a_out0", "pll_c4_out0"
};
static u32 mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0_idx[] = {
[0] = 0, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
};
static const char *mux_pllc_pllp_plla[] = {
"pll_c", "pll_p", "pll_a_out0"
};
static u32 mux_pllc_pllp_plla_idx[] = {
[0] = 1, [1] = 2, [2] = 3,
};
static const char *mux_clkm_pllc_pllp_plla[] = {
"clk_m", "pll_c", "pll_p", "pll_a_out0"
};
#define mux_clkm_pllc_pllp_plla_idx NULL
static const char *mux_pllc_pllp_plla1_pllc2_c3_clkm[] = {
"pll_c", "pll_p", "pll_a1", "pll_c2", "pll_c3", "clk_m"
};
static u32 mux_pllc_pllp_plla1_pllc2_c3_clkm_idx[] = {
[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6,
};
static const char *mux_pllc2_c_c3_pllp_clkm_plla1_pllc4[] = {
"pll_c2", "pll_c", "pll_c3", "pll_p", "clk_m", "pll_a1", "pll_c4_out0",
};
static u32 mux_pllc2_c_c3_pllp_clkm_plla1_pllc4_idx[] = {
[0] = 1, [1] = 2, [2] = 3, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
};
static const char *mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4[] = {
"pll_c", "pll_p", "pll_a1", "pll_c2", "pll_c3", "clk_m", "pll_c4_out0",
};
#define mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4_idx \
mux_pllc2_c_c3_pllp_clkm_plla1_pllc4_idx
static const char *
mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm[] = {
"pll_a_out0", "pll_c4_out0", "pll_c", "pll_c4_out1", "pll_p",
"pll_c4_out2", "clk_m"
};
#define mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm_idx NULL
static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = {
"pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0"
};
@ -302,12 +399,93 @@ static const char *mux_pllm_pllc_pllp_plla[] = {
#define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx
static const char *mux_pllp_pllc_clkm[] = {
"pll_p", "pll_c", "pll_m"
"pll_p", "pll_c", "clk_m"
};
static u32 mux_pllp_pllc_clkm_idx[] = {
[0] = 0, [1] = 1, [2] = 3,
};
static const char *mux_pllp_pllc_clkm_1[] = {
"pll_p", "pll_c", "clk_m"
};
static u32 mux_pllp_pllc_clkm_1_idx[] = {
[0] = 0, [1] = 2, [2] = 5,
};
static const char *mux_pllp_pllc_plla_clkm[] = {
"pll_p", "pll_c", "pll_a_out0", "clk_m"
};
static u32 mux_pllp_pllc_plla_clkm_idx[] = {
[0] = 0, [1] = 2, [2] = 4, [3] = 6,
};
static const char *mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2[] = {
"pll_p", "pll_c", "pll_c4_out0", "pll_c4_out1", "clk_m", "pll_c4_out2"
};
static u32 mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2_idx[] = {
[0] = 0, [1] = 2, [2] = 3, [3] = 5, [4] = 6, [5] = 7,
};
static const char *
mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0[] = {
"pll_p", "pll_c_out1", "pll_c", "pll_c4_out2", "pll_c4_out1",
"clk_m", "pll_c4_out0"
};
static u32
mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = {
[0] = 0, [1] = 1, [2] = 2, [3] = 4, [4] = 5, [5] = 6, [6] = 7,
};
static const char *mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0[] = {
"pll_p", "pll_c4_out2", "pll_c4_out1", "clk_m", "pll_c4_out0"
};
static u32 mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0_idx[] = {
[0] = 0, [1] = 3, [2] = 4, [3] = 6, [4] = 7,
};
static const char *mux_pllp_clkm_pllc4_out2_out1_out0_lj[] = {
"pll_p",
"pll_c4_out2", "pll_c4_out0", /* LJ input */
"pll_c4_out2", "pll_c4_out1",
"pll_c4_out1", /* LJ input */
"clk_m", "pll_c4_out0"
};
#define mux_pllp_clkm_pllc4_out2_out1_out0_lj_idx NULL
static const char *mux_pllp_pllc2_c_c3_clkm[] = {
"pll_p", "pll_c2", "pll_c", "pll_c3", "clk_m"
};
static u32 mux_pllp_pllc2_c_c3_clkm_idx[] = {
[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 6,
};
static const char *mux_pllp_clkm_clk32_plle[] = {
"pll_p", "clk_m", "clk_32k", "pll_e"
};
static u32 mux_pllp_clkm_clk32_plle_idx[] = {
[0] = 0, [1] = 2, [2] = 4, [3] = 6,
};
static const char *mux_pllp_pllp_out3_clkm_clk32k_plla[] = {
"pll_p", "pll_p_out3", "clk_m", "clk_32k", "pll_a_out0"
};
#define mux_pllp_pllp_out3_clkm_clk32k_plla_idx NULL
static const char *mux_pllp_out3_clkm_pllp_pllc4[] = {
"pll_p_out3", "clk_m", "pll_p", "pll_c4_out0", "pll_c4_out1",
"pll_c4_out2"
};
static u32 mux_pllp_out3_clkm_pllp_pllc4_idx[] = {
[0] = 0, [1] = 3, [2] = 4, [3] = 5, [4] = 6, [5] = 7,
};
static const char *mux_clkm_pllp_pllre[] = {
"clk_m", "pll_p_out_xusb", "pll_re_out"
};
static u32 mux_clkm_pllp_pllre_idx[] = {
[0] = 0, [1] = 1, [2] = 5,
};
static const char *mux_pllp_pllc_clkm_clk32[] = {
"pll_p", "pll_c", "clk_m", "clk_32k"
};
@ -332,6 +510,11 @@ static u32 mux_clkm_48M_pllp_480M_idx[] = {
[0] = 0, [1] = 2, [2] = 4, [3] = 6,
};
static const char *mux_clkm_pllre_clk32_480M[] = {
"clk_m", "pll_re_out", "clk_32k", "pll_u_480M"
};
#define mux_clkm_pllre_clk32_480M_idx NULL
static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = {
"clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref"
};
@ -339,10 +522,27 @@ static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = {
[0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7,
};
static const char *mux_ss_60M[] = {
static const char *mux_pllp_out3_pllp_pllc_clkm[] = {
"pll_p_out3", "pll_p", "pll_c", "clk_m"
};
static u32 mux_pllp_out3_pllp_pllc_clkm_idx[] = {
[0] = 0, [1] = 1, [2] = 2, [3] = 6,
};
static const char *mux_ss_div2_60M[] = {
"xusb_ss_div2", "pll_u_60M"
};
#define mux_ss_60M_idx NULL
#define mux_ss_div2_60M_idx NULL
static const char *mux_ss_div2_60M_ss[] = {
"xusb_ss_div2", "pll_u_60M", "xusb_ss_src"
};
#define mux_ss_div2_60M_ss_idx NULL
static const char *mux_ss_clkm[] = {
"xusb_ss_src", "clk_m"
};
#define mux_ss_clkm_idx NULL
static const char *mux_d_audio_clk[] = {
"pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync",
@ -386,6 +586,32 @@ static u32 mux_pllm_pllc2_c_c3_pllp_plla_pllc4_idx[] = {
[0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, [6] = 7,
};
/* SOR1 mux'es */
static const char *mux_pllp_plld_plld2_clkm[] = {
"pll_p", "pll_d_out0", "pll_d2_out0", "clk_m"
};
static u32 mux_pllp_plld_plld2_clkm_idx[] = {
[0] = 0, [1] = 2, [2] = 5, [3] = 6
};
static const char *mux_plldp_sor1_src[] = {
"pll_dp", "clk_sor1_src"
};
#define mux_plldp_sor1_src_idx NULL
static const char *mux_clkm_sor1_brick_sor1_src[] = {
"clk_m", "sor1_brick", "sor1_src", "sor1_brick"
};
#define mux_clkm_sor1_brick_sor1_src_idx NULL
static const char *mux_pllp_pllre_clkm[] = {
"pll_p", "pll_re_out1", "clk_m"
};
static u32 mux_pllp_pllre_clkm_idx[] = {
[0] = 0, [1] = 2, [2] = 3,
};
static const char *mux_clkm_plldp_sor0lvds[] = {
"clk_m", "pll_dp", "sor0_lvds",
};
@ -401,6 +627,7 @@ static struct tegra_periph_init_data periph_clks[] = {
I2C("i2c3", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, tegra_clk_i2c3),
I2C("i2c4", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, tegra_clk_i2c4),
I2C("i2c5", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, tegra_clk_i2c5),
I2C("i2c6", mux_pllp_clkm, CLK_SOURCE_I2C6, 166, tegra_clk_i2c6),
INT("vde", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde),
INT("vi", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi),
INT("epp", mux_pllm_pllc_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp),
@ -411,14 +638,19 @@ static struct tegra_periph_init_data periph_clks[] = {
INT8("vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde_8),
INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_8),
INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_9),
INT8("vi", mux_pllc2_c_c3_pllp_clkm_plla1_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_10),
INT8("epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp_8),
INT8("msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, TEGRA_PERIPH_WAR_1005168, tegra_clk_msenc),
INT8("tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec),
INT("tsec", mux_pllp_pllc_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec_8),
INT8("host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_8),
INT8("host1x", mux_pllc4_out1_pllc_pllc4_out2_pllp_clkm_plla_pllc4_out0, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_9),
INT8("se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
INT8("se", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se),
INT8("2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d_8),
INT8("3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d_8),
INT8("vic03", mux_pllm_pllc_pllp_plla_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03),
INT8("vic03", mux_pllc_pllp_plla1_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03_8),
INT_FLAGS("mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, 0, tegra_clk_mselect, CLK_IGNORE_UNUSED),
MUX("i2s0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, TEGRA_PERIPH_ON_APB, tegra_clk_i2s0),
MUX("i2s1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, tegra_clk_i2s1),
@ -427,22 +659,31 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("i2s4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, TEGRA_PERIPH_ON_APB, tegra_clk_i2s4),
MUX("spdif_out", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_out),
MUX("spdif_in", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in),
MUX8("spdif_in", mux_pllp_pllc_clkm_1, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in_8),
MUX("pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, TEGRA_PERIPH_ON_APB, tegra_clk_pwm),
MUX("adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, TEGRA_PERIPH_ON_APB, tegra_clk_adx),
MUX("amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, TEGRA_PERIPH_ON_APB, tegra_clk_amx),
MUX("hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda),
MUX("hda", mux_pllp_pllc_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda_8),
MUX("hda2codec_2x", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x),
MUX8("hda2codec_2x", mux_pllp_pllc_plla_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x_8),
MUX("vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, TEGRA_PERIPH_ON_APB, tegra_clk_vfir),
MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1),
MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2),
MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3),
MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4),
MUX8("sdmmc1", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_9),
MUX8("sdmmc2", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_9),
MUX8("sdmmc3", mux_pllp_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_9),
MUX8("sdmmc4", mux_pllp_clkm_pllc4_out2_out1_out0_lj, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4_9),
MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la),
MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace),
MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr),
MUX("owr", mux_pllp_pllc_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr_8),
MUX("nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, 0, tegra_clk_nor),
MUX("mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, TEGRA_PERIPH_ON_APB, tegra_clk_mipi),
MUX("vi_sensor", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor),
MUX("vi_sensor", mux_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_9),
MUX("cilab", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, 0, tegra_clk_cilab),
MUX("cilcd", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, 0, tegra_clk_cilcd),
MUX("cile", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, 0, tegra_clk_cile),
@ -465,10 +706,13 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("ndflash", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash),
MUX("ndspeed", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed),
MUX("sata_oob", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob),
MUX("sata_oob", mux_pllp_pllc_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob_8),
MUX("sata", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata),
MUX("sata", mux_pllp_pllc_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata_8),
MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
MUX("vi_sensor2", mux_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2_8),
MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_8),
MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_8),
MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_8),
@ -479,6 +723,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("sbc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_8),
MUX8("sbc5", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC5, 104, TEGRA_PERIPH_ON_APB, tegra_clk_sbc5_8),
MUX8("sbc6", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC6, 105, TEGRA_PERIPH_ON_APB, tegra_clk_sbc6_8),
MUX("sbc1", mux_pllp_pllc_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_9),
MUX("sbc2", mux_pllp_pllc_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_9),
MUX("sbc3", mux_pllp_pllc_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_9),
MUX("sbc4", mux_pllp_pllc_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_9),
MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8),
MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8),
MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi),
@ -486,27 +734,59 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2),
MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3),
MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm),
MUX8("soc_therm", mux_clkm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm_8),
MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 164, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8),
MUX8("isp", mux_pllm_pllc_pllp_plla_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_8),
MUX8("isp", mux_pllc_pllp_plla1_pllc2_c3_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_9),
MUX8("entropy", mux_pllp_clkm1, CLK_SOURCE_ENTROPY, 149, 0, tegra_clk_entropy),
MUX8("entropy", mux_pllp_clkm_clk32_plle, CLK_SOURCE_ENTROPY, 149, 0, tegra_clk_entropy_8),
MUX8("hdmi_audio", mux_pllp3_pllc_clkm, CLK_SOURCE_HDMI_AUDIO, 176, TEGRA_PERIPH_NO_RESET, tegra_clk_hdmi_audio),
MUX8("clk72mhz", mux_pllp3_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz),
MUX8("clk72mhz", mux_pllp_out3_pllp_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz_8),
MUX8_NOGATE_LOCK("sor0_lvds", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_SOR0, tegra_clk_sor0_lvds, &sor0_lock),
MUX_FLAGS("csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite, CLK_IGNORE_UNUSED),
MUX_FLAGS("csite", mux_pllp_pllre_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite_8, CLK_IGNORE_UNUSED),
NODIV("disp1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1, NULL),
NODIV("disp1", mux_pllp_plld_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1_8, NULL),
NODIV("disp2", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2, NULL),
NODIV("disp2", mux_pllp_plld_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2_8, NULL),
NODIV("sor0", mux_clkm_plldp_sor0lvds, CLK_SOURCE_SOR0, 14, 3, 182, 0, tegra_clk_sor0, &sor0_lock),
UART("uarta", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, tegra_clk_uarta),
UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb),
UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc),
UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd),
UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte),
UART8("uarta", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTA, 6, tegra_clk_uarta_8),
UART8("uartb", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTB, 7, tegra_clk_uartb_8),
UART8("uartc", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTC, 55, tegra_clk_uartc_8),
UART8("uartd", mux_pllp_pllc_pllc4_out0_pllc4_out1_clkm_pllc4_out2, CLK_SOURCE_UARTD, 65, tegra_clk_uartd_8),
XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src),
XUSB("xusb_host_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src_8),
XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
XUSB("xusb_falcon_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src_8),
XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src),
NODIV("xusb_hs_src", mux_ss_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src_8),
NODIV("xusb_hs_src", mux_ss_div2_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
NODIV("xusb_hs_src", mux_ss_div2_60M_ss, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(2), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src_4, NULL),
NODIV("xusb_ssp_src", mux_ss_clkm, CLK_SOURCE_XUSB_SS_SRC, 24, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ssp_src, NULL),
XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
XUSB("xusb_dev_src", mux_clkm_pllp_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src_8),
MUX8("dbgapb", mux_pllp_clkm_2, CLK_SOURCE_DBGAPB, 185, TEGRA_PERIPH_NO_RESET, tegra_clk_dbgapb),
MUX8("msenc", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVENC, 219, 0, tegra_clk_nvenc),
MUX8("nvdec", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVDEC, 194, 0, tegra_clk_nvdec),
MUX8("nvjpg", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVJPG, 195, 0, tegra_clk_nvjpg),
MUX8("ape", mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm, CLK_SOURCE_APE, 198, TEGRA_PERIPH_ON_APB, tegra_clk_ape),
MUX8_NOGATE_LOCK("sor1_src", mux_pllp_plld_plld2_clkm, CLK_SOURCE_SOR1, tegra_clk_sor1_src, &sor1_lock),
NODIV("sor1_brick", mux_plldp_sor1_src, CLK_SOURCE_SOR1, 14, MASK(1), 183, 0, tegra_clk_sor1_brick, &sor1_lock),
NODIV("sor1", mux_clkm_sor1_brick_sor1_src, CLK_SOURCE_SOR1, 15, MASK(1), 183, 0, tegra_clk_sor1, &sor1_lock),
MUX8("sdmmc_legacy", mux_pllp_out3_clkm_pllp_pllc4, CLK_SOURCE_SDMMC_LEGACY, 193, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_sdmmc_legacy),
MUX8("qspi", mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_QSPI, 211, TEGRA_PERIPH_ON_APB, tegra_clk_qspi),
MUX("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, TEGRA_PERIPH_ON_APB, tegra_clk_vi_i2c),
MUX("mipibif", mux_pllp_clkm, CLK_SOURCE_MIPIBIF, 173, TEGRA_PERIPH_ON_APB, tegra_clk_mipibif),
MUX("uartape", mux_pllp_pllc_clkm, CLK_SOURCE_UARTAPE, 212, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_uartape),
MUX8("tsecb", mux_pllp_pllc2_c_c3_clkm, CLK_SOURCE_TSECB, 206, 0, tegra_clk_tsecb),
MUX8("maud", mux_pllp_pllp_out3_clkm_clk32k_plla, CLK_SOURCE_MAUD, 202, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_maud),
};
static struct tegra_periph_init_data gate_clks[] = {
@ -543,6 +823,16 @@ static struct tegra_periph_init_data gate_clks[] = {
GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0),
GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0),
GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0),
GATE("pllg_ref", "pll_ref", 189, 0, tegra_clk_pll_g_ref, 0),
GATE("hsic_trk", "usb2_hsic_trk", 209, TEGRA_PERIPH_NO_RESET, tegra_clk_hsic_trk, 0),
GATE("usb2_trk", "usb2_hsic_trk", 210, TEGRA_PERIPH_NO_RESET, tegra_clk_usb2_trk, 0),
GATE("xusb_gate", "osc", 143, 0, tegra_clk_xusb_gate, 0),
GATE("pll_p_out_cpu", "pll_p", 223, 0, tegra_clk_pll_p_out_cpu, 0),
GATE("pll_p_out_adsp", "pll_p", 187, 0, tegra_clk_pll_p_out_adsp, 0),
};
static struct tegra_periph_init_data div_clks[] = {
DIV8("usb2_hsic_trk", "osc", CLK_SOURCE_USB2_HSIC_TRK, tegra_clk_usb2_hsic_trk, 0),
};
struct pll_out_data {
@ -633,6 +923,33 @@ static void __init gate_clk_init(void __iomem *clk_base,
}
}
static void __init div_clk_init(void __iomem *clk_base,
struct tegra_clk *tegra_clks)
{
int i;
struct clk *clk;
struct clk **dt_clk;
for (i = 0; i < ARRAY_SIZE(div_clks); i++) {
struct tegra_periph_init_data *data;
data = div_clks + i;
dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks);
if (!dt_clk)
continue;
clk = tegra_clk_register_divider(data->name,
data->p.parent_name, clk_base + data->offset,
data->flags, data->periph.divider.flags,
data->periph.divider.shift,
data->periph.divider.width,
data->periph.divider.frac_width,
data->periph.divider.lock);
*dt_clk = clk;
}
}
static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *pll_params)
@ -669,6 +986,51 @@ static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base,
data->lock);
*dt_clk = clk;
}
dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_cpu,
tegra_clks);
if (dt_clk) {
/*
* Tegra210 has control on enabling/disabling PLLP branches to
* CPU, register a gate clock "pll_p_out_cpu" for this gating
* function and parent "pll_p_out4" to it, so when we are
* re-parenting CPU off from "pll_p_out4" the PLLP branching to
* CPU can be disabled automatically.
*/
clk = tegra_clk_register_divider("pll_p_out4_div",
"pll_p_out_cpu", clk_base + PLLP_OUTB, 0, 0, 24,
8, 1, &PLLP_OUTB_lock);
dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out4_cpu, tegra_clks);
if (dt_clk) {
clk = tegra_clk_register_pll_out("pll_p_out4",
"pll_p_out4_div", clk_base + PLLP_OUTB,
17, 16, CLK_IGNORE_UNUSED |
CLK_SET_RATE_PARENT, 0,
&PLLP_OUTB_lock);
*dt_clk = clk;
}
}
dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_hsio, tegra_clks);
if (dt_clk) {
/* PLLP_OUT_HSIO */
clk = clk_register_gate(NULL, "pll_p_out_hsio", "pll_p",
CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
clk_base + PLLP_MISC1, 29, 0, NULL);
*dt_clk = clk;
}
dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p_out_xusb, tegra_clks);
if (dt_clk) {
/* PLLP_OUT_XUSB */
clk = clk_register_gate(NULL, "pll_p_out_xusb",
"pll_p_out_hsio", CLK_SET_RATE_PARENT |
CLK_IGNORE_UNUSED, clk_base + PLLP_MISC1, 28, 0,
NULL);
clk_register_clkdev(clk, "pll_p_out_xusb", NULL);
*dt_clk = clk;
}
}
void __init tegra_periph_clk_init(void __iomem *clk_base,
@ -678,4 +1040,5 @@ void __init tegra_periph_clk_init(void __iomem *clk_base,
init_pllp(clk_base, pmc_base, tegra_clks, pll_params);
periph_clk_init(clk_base, tegra_clks);
gate_clk_init(clk_base, tegra_clks);
div_clk_init(clk_base, tegra_clks);
}

View File

@ -34,9 +34,25 @@
#define CCLKLP_BURST_POLICY 0x370
#define SCLK_BURST_POLICY 0x028
#define SYSTEM_CLK_RATE 0x030
#define SCLK_DIVIDER 0x2c
static DEFINE_SPINLOCK(sysrate_lock);
enum tegra_super_gen {
gen4 = 4,
gen5,
};
struct tegra_super_gen_info {
enum tegra_super_gen gen;
const char **sclk_parents;
const char **cclk_g_parents;
const char **cclk_lp_parents;
int num_sclk_parents;
int num_cclk_g_parents;
int num_cclk_lp_parents;
};
static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
"pll_p", "pll_p_out2", "unused",
"clk_32k", "pll_m_out1" };
@ -51,21 +67,81 @@ static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
"pll_p", "pll_p_out4", "unused",
"unused", "pll_x", "pll_x_out0" };
const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
.gen = gen4,
.sclk_parents = sclk_parents,
.cclk_g_parents = cclk_g_parents,
.cclk_lp_parents = cclk_lp_parents,
.num_sclk_parents = ARRAY_SIZE(sclk_parents),
.num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents),
.num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents),
};
static const char *sclk_parents_gen5[] = { "clk_m", "pll_c_out1", "pll_c4_out3",
"pll_p", "pll_p_out2", "pll_c4_out1",
"clk_32k", "pll_c4_out2" };
static const char *cclk_g_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
"pll_p", "pll_p_out4", "unused",
"unused", "pll_x", "unused", "unused",
"unused", "unused", "unused", "unused",
"dfllCPU_out" };
static const char *cclk_lp_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
"pll_p", "pll_p_out4", "unused",
"unused", "pll_x", "unused", "unused",
"unused", "unused", "unused", "unused",
"dfllCPU_out" };
const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
.gen = gen5,
.sclk_parents = sclk_parents_gen5,
.cclk_g_parents = cclk_g_parents_gen5,
.cclk_lp_parents = cclk_lp_parents_gen5,
.num_sclk_parents = ARRAY_SIZE(sclk_parents_gen5),
.num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents_gen5),
.num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents_gen5),
};
static void __init tegra_sclk_init(void __iomem *clk_base,
struct tegra_clk *tegra_clks)
struct tegra_clk *tegra_clks,
const struct tegra_super_gen_info *gen_info)
{
struct clk *clk;
struct clk **dt_clk;
/* SCLK */
dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
/* SCLK_MUX */
dt_clk = tegra_lookup_dt_id(tegra_clk_sclk_mux, tegra_clks);
if (dt_clk) {
clk = tegra_clk_register_super_mux("sclk", sclk_parents,
ARRAY_SIZE(sclk_parents),
clk = tegra_clk_register_super_mux("sclk_mux",
gen_info->sclk_parents,
gen_info->num_sclk_parents,
CLK_SET_RATE_PARENT,
clk_base + SCLK_BURST_POLICY,
0, 4, 0, 0, NULL);
*dt_clk = clk;
/* SCLK */
dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
if (dt_clk) {
clk = clk_register_divider(NULL, "sclk", "sclk_mux", 0,
clk_base + SCLK_DIVIDER, 0, 8,
0, &sysrate_lock);
*dt_clk = clk;
}
} else {
/* SCLK */
dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
if (dt_clk) {
clk = tegra_clk_register_super_mux("sclk",
gen_info->sclk_parents,
gen_info->num_sclk_parents,
CLK_SET_RATE_PARENT,
clk_base + SCLK_BURST_POLICY,
0, 4, 0, 0, NULL);
*dt_clk = clk;
}
}
/* HCLK */
@ -95,10 +171,11 @@ static void __init tegra_sclk_init(void __iomem *clk_base,
*dt_clk = clk;
}
void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
void __init tegra_super_clk_init(void __iomem *clk_base,
void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *params)
struct tegra_clk_pll_params *params,
const struct tegra_super_gen_info *gen_info)
{
struct clk *clk;
struct clk **dt_clk;
@ -106,28 +183,50 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
/* CCLKG */
dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks);
if (dt_clk) {
clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents,
ARRAY_SIZE(cclk_g_parents),
if (gen_info->gen == gen5) {
clk = tegra_clk_register_super_mux("cclk_g",
gen_info->cclk_g_parents,
gen_info->num_cclk_g_parents,
CLK_SET_RATE_PARENT,
clk_base + CCLKG_BURST_POLICY,
0, 4, 8, 0, NULL);
} else {
clk = tegra_clk_register_super_mux("cclk_g",
gen_info->cclk_g_parents,
gen_info->num_cclk_g_parents,
CLK_SET_RATE_PARENT,
clk_base + CCLKG_BURST_POLICY,
0, 4, 0, 0, NULL);
}
*dt_clk = clk;
}
/* CCLKLP */
dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks);
if (dt_clk) {
clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents,
ARRAY_SIZE(cclk_lp_parents),
if (gen_info->gen == gen5) {
clk = tegra_clk_register_super_mux("cclk_lp",
gen_info->cclk_lp_parents,
gen_info->num_cclk_lp_parents,
CLK_SET_RATE_PARENT,
clk_base + CCLKLP_BURST_POLICY,
0, 4, 8, 0, NULL);
} else {
clk = tegra_clk_register_super_mux("cclk_lp",
gen_info->cclk_lp_parents,
gen_info->num_cclk_lp_parents,
CLK_SET_RATE_PARENT,
clk_base + CCLKLP_BURST_POLICY,
TEGRA_DIVIDER_2, 4, 8, 9, NULL);
}
*dt_clk = clk;
}
tegra_sclk_init(clk_base, tegra_clks);
tegra_sclk_init(clk_base, tegra_clks, gen_info);
#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
defined(CONFIG_ARCH_TEGRA_124_SOC) || \
defined(CONFIG_ARCH_TEGRA_210_SOC)
/* PLLX */
dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks);
if (!dt_clk)
@ -148,3 +247,20 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
#endif
}
void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *params)
{
tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
&tegra_super_gen_info_gen4);
}
void __init tegra_super_clk_gen5_init(void __iomem *clk_base,
void __iomem *pmc_base,
struct tegra_clk *tegra_clks,
struct tegra_clk_pll_params *params)
{
tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
&tegra_super_gen_info_gen5);
}

View File

@ -182,40 +182,40 @@ static struct div_nmp pllxc_nmp = {
.divp_width = 4,
};
static struct pdiv_map pllxc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
static const struct pdiv_map pllxc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
{ .pdiv = 0, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
{ 12000000, 624000000, 104, 0, 2},
{ 12000000, 600000000, 100, 0, 2},
{ 13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 624000000, 104, 1, 2, 0 },
{ 12000000, 600000000, 100, 1, 2, 0 },
{ 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c_params = {
.input_min = 12000000,
.input_max = 800000000,
.cf_min = 12000000,
.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.vco_min = 600000000,
.vco_max = 1400000000,
.base_reg = PLLC_BASE,
@ -232,7 +232,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_c_freq_table,
.flags = TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct div_nmp pllcx_nmp = {
@ -244,22 +244,22 @@ static struct div_nmp pllcx_nmp = {
.divp_width = 3,
};
static struct pdiv_map pllc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 8, .hw_val = 5 },
static const struct pdiv_map pllc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 8, .hw_val = 5 },
{ .pdiv = 16, .hw_val = 7 },
{ .pdiv = 0, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
{12000000, 600000000, 100, 0, 2},
{13000000, 600000000, 92, 0, 2}, /* actual: 598.0 MHz */
{16800000, 600000000, 71, 0, 2}, /* actual: 596.4 MHz */
{19200000, 600000000, 62, 0, 2}, /* actual: 595.2 MHz */
{26000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
{0, 0, 0, 0, 0, 0},
{ 12000000, 600000000, 100, 1, 2, 0 },
{ 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c2_params = {
@ -318,26 +318,26 @@ static struct div_nmp pllm_nmp = {
.override_divp_shift = 27,
};
static struct pdiv_map pllm_p[] = {
static const struct pdiv_map pllm_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
{12000000, 800000000, 66, 0, 1}, /* actual: 792.0 MHz */
{13000000, 800000000, 61, 0, 1}, /* actual: 793.0 MHz */
{16800000, 800000000, 47, 0, 1}, /* actual: 789.6 MHz */
{19200000, 800000000, 41, 0, 1}, /* actual: 787.2 MHz */
{26000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */
{0, 0, 0, 0, 0, 0},
{ 12000000, 800000000, 66, 1, 1, 0 }, /* actual: 792.0 MHz */
{ 13000000, 800000000, 61, 1, 1, 0 }, /* actual: 793.0 MHz */
{ 16800000, 800000000, 47, 1, 1, 0 }, /* actual: 789.6 MHz */
{ 19200000, 800000000, 41, 1, 1, 0 }, /* actual: 787.2 MHz */
{ 26000000, 800000000, 61, 2, 1, 0 }, /* actual: 793.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_m_params = {
.input_min = 12000000,
.input_max = 500000000,
.cf_min = 12000000,
.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.vco_min = 400000000,
.vco_max = 1066000000,
.base_reg = PLLM_BASE,
@ -351,7 +351,8 @@ static struct tegra_clk_pll_params pll_m_params = {
.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
.freq_table = pll_m_freq_table,
.flags = TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
TEGRA_PLL_FIXED,
};
static struct div_nmp pllp_nmp = {
@ -364,12 +365,12 @@ static struct div_nmp pllp_nmp = {
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
{12000000, 216000000, 432, 12, 1, 8},
{13000000, 216000000, 432, 13, 1, 8},
{16800000, 216000000, 360, 14, 1, 8},
{19200000, 216000000, 360, 16, 1, 8},
{26000000, 216000000, 432, 26, 1, 8},
{0, 0, 0, 0, 0, 0},
{ 12000000, 216000000, 432, 12, 2, 8 },
{ 13000000, 216000000, 432, 13, 2, 8 },
{ 16800000, 216000000, 360, 14, 2, 8 },
{ 19200000, 216000000, 360, 16, 2, 8 },
{ 26000000, 216000000, 432, 26, 2, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_p_params = {
@ -386,19 +387,19 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_p_freq_table,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 408000000,
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
{9600000, 282240000, 147, 5, 0, 4},
{9600000, 368640000, 192, 5, 0, 4},
{9600000, 240000000, 200, 8, 0, 8},
{28800000, 282240000, 245, 25, 0, 8},
{28800000, 368640000, 320, 25, 0, 8},
{28800000, 240000000, 200, 24, 0, 8},
{0, 0, 0, 0, 0, 0},
{ 9600000, 282240000, 147, 5, 1, 4 },
{ 9600000, 368640000, 192, 5, 1, 4 },
{ 9600000, 240000000, 200, 8, 1, 8 },
{ 28800000, 282240000, 245, 25, 1, 8 },
{ 28800000, 368640000, 320, 25, 1, 8 },
{ 28800000, 240000000, 200, 24, 1, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
@ -416,28 +417,26 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_a_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
{12000000, 216000000, 864, 12, 2, 12},
{13000000, 216000000, 864, 13, 2, 12},
{16800000, 216000000, 720, 14, 2, 12},
{19200000, 216000000, 720, 16, 2, 12},
{26000000, 216000000, 864, 26, 2, 12},
{12000000, 594000000, 594, 12, 0, 12},
{13000000, 594000000, 594, 13, 0, 12},
{16800000, 594000000, 495, 14, 0, 12},
{19200000, 594000000, 495, 16, 0, 12},
{26000000, 594000000, 594, 26, 0, 12},
{12000000, 1000000000, 1000, 12, 0, 12},
{13000000, 1000000000, 1000, 13, 0, 12},
{19200000, 1000000000, 625, 12, 0, 12},
{26000000, 1000000000, 1000, 26, 0, 12},
{0, 0, 0, 0, 0, 0},
{ 12000000, 216000000, 864, 12, 4, 12 },
{ 13000000, 216000000, 864, 13, 4, 12 },
{ 16800000, 216000000, 720, 14, 4, 12 },
{ 19200000, 216000000, 720, 16, 4, 12 },
{ 26000000, 216000000, 864, 26, 4, 12 },
{ 12000000, 594000000, 594, 12, 1, 12 },
{ 13000000, 594000000, 594, 13, 1, 12 },
{ 16800000, 594000000, 495, 14, 1, 12 },
{ 19200000, 594000000, 495, 16, 1, 12 },
{ 26000000, 594000000, 594, 26, 1, 12 },
{ 12000000, 1000000000, 1000, 12, 1, 12 },
{ 13000000, 1000000000, 1000, 13, 1, 12 },
{ 19200000, 1000000000, 625, 12, 1, 12 },
{ 26000000, 1000000000, 1000, 26, 1, 12 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_d_params = {
@ -455,7 +454,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
TEGRA_PLL_USE_LOCK,
TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_d2_params = {
@ -473,10 +472,10 @@ static struct tegra_clk_pll_params pll_d2_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
TEGRA_PLL_USE_LOCK,
TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct pdiv_map pllu_p[] = {
static const struct pdiv_map pllu_p[] = {
{ .pdiv = 1, .hw_val = 1 },
{ .pdiv = 2, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
@ -492,12 +491,12 @@ static struct div_nmp pllu_nmp = {
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
{12000000, 480000000, 960, 12, 0, 12},
{13000000, 480000000, 960, 13, 0, 12},
{16800000, 480000000, 400, 7, 0, 5},
{19200000, 480000000, 200, 4, 0, 3},
{26000000, 480000000, 960, 26, 0, 12},
{0, 0, 0, 0, 0, 0},
{ 12000000, 480000000, 960, 12, 2, 12 },
{ 13000000, 480000000, 960, 13, 2, 12 },
{ 16800000, 480000000, 400, 7, 2, 5 },
{ 19200000, 480000000, 200, 4, 2, 3 },
{ 26000000, 480000000, 960, 26, 2, 12 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_u_params = {
@ -516,25 +515,24 @@ static struct tegra_clk_pll_params pll_u_params = {
.div_nmp = &pllu_nmp,
.freq_table = pll_u_freq_table,
.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
TEGRA_PLL_USE_LOCK,
TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1 GHz */
{12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */
{13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */
{16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */
{19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */
{26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */
{0, 0, 0, 0, 0, 0},
{ 12000000, 1000000000, 83, 1, 1, 0 }, /* actual: 996.0 MHz */
{ 13000000, 1000000000, 76, 1, 1, 0 }, /* actual: 988.0 MHz */
{ 16800000, 1000000000, 59, 1, 1, 0 }, /* actual: 991.2 MHz */
{ 19200000, 1000000000, 52, 1, 1, 0 }, /* actual: 998.4 MHz */
{ 26000000, 1000000000, 76, 2, 1, 0 }, /* actual: 988.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_x_params = {
.input_min = 12000000,
.input_max = 800000000,
.cf_min = 12000000,
.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.vco_min = 700000000,
.vco_max = 2400000000U,
.base_reg = PLLX_BASE,
@ -551,15 +549,34 @@ static struct tegra_clk_pll_params pll_x_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_x_freq_table,
.flags = TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
{336000000, 100000000, 100, 21, 16, 11},
{312000000, 100000000, 200, 26, 24, 13},
{12000000, 100000000, 200, 1, 24, 13},
{0, 0, 0, 0, 0, 0},
{ 336000000, 100000000, 100, 21, 16, 11 },
{ 312000000, 100000000, 200, 26, 24, 13 },
{ 12000000, 100000000, 200, 1, 24, 13 },
{ 0, 0, 0, 0, 0, 0 },
};
static const struct pdiv_map plle_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
{ .pdiv = 0, .hw_val = 0 }
};
static struct div_nmp plle_nmp = {
@ -584,9 +601,10 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
.pdiv_tohw = plle_p,
.div_nmp = &plle_nmp,
.freq_table = pll_e_freq_table,
.flags = TEGRA_PLL_FIXED,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};
@ -614,18 +632,19 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
.div_nmp = &pllre_nmp,
.flags = TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
TEGRA_PLL_LOCK_MISC,
};
/* possible OSC frequencies in Hz */
static unsigned long tegra114_input_freq[] = {
[0] = 13000000,
[1] = 16800000,
[4] = 19200000,
[5] = 38400000,
[8] = 12000000,
[9] = 48000000,
[12] = 260000000,
[ 0] = 13000000,
[ 1] = 16800000,
[ 4] = 19200000,
[ 5] = 38400000,
[ 8] = 12000000,
[ 9] = 48000000,
[12] = 26000000,
};
#define MASK(x) (BIT(x) - 1)
@ -644,21 +663,27 @@ struct utmi_clk_param {
};
static const struct utmi_clk_param utmi_parameters[] = {
{.osc_frequency = 13000000, .enable_delay_count = 0x02,
.stable_count = 0x33, .active_delay_count = 0x05,
.xtal_freq_count = 0x7F},
{.osc_frequency = 19200000, .enable_delay_count = 0x03,
.stable_count = 0x4B, .active_delay_count = 0x06,
.xtal_freq_count = 0xBB},
{.osc_frequency = 12000000, .enable_delay_count = 0x02,
.stable_count = 0x2F, .active_delay_count = 0x04,
.xtal_freq_count = 0x76},
{.osc_frequency = 26000000, .enable_delay_count = 0x04,
.stable_count = 0x66, .active_delay_count = 0x09,
.xtal_freq_count = 0xFE},
{.osc_frequency = 16800000, .enable_delay_count = 0x03,
.stable_count = 0x41, .active_delay_count = 0x0A,
.xtal_freq_count = 0xA4},
{
.osc_frequency = 13000000, .enable_delay_count = 0x02,
.stable_count = 0x33, .active_delay_count = 0x05,
.xtal_freq_count = 0x7f
}, {
.osc_frequency = 19200000, .enable_delay_count = 0x03,
.stable_count = 0x4b, .active_delay_count = 0x06,
.xtal_freq_count = 0xbb
}, {
.osc_frequency = 12000000, .enable_delay_count = 0x02,
.stable_count = 0x2f, .active_delay_count = 0x04,
.xtal_freq_count = 0x76
}, {
.osc_frequency = 26000000, .enable_delay_count = 0x04,
.stable_count = 0x66, .active_delay_count = 0x09,
.xtal_freq_count = 0xfe
}, {
.osc_frequency = 16800000, .enable_delay_count = 0x03,
.stable_count = 0x41, .active_delay_count = 0x0a,
.xtal_freq_count = 0xa4
},
};
/* peripheral mux definitions */
@ -965,8 +990,8 @@ static void __init tegra114_fixed_clk_init(void __iomem *clk_base)
static __init void tegra114_utmi_param_configure(void __iomem *clk_base)
{
unsigned int i;
u32 reg;
int i;
for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
if (osc_freq == utmi_parameters[i].osc_frequency)
@ -1173,7 +1198,7 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
{
struct clk *clk;
struct tegra_periph_init_data *data;
int i;
unsigned int i;
/* xusb_ss_div2 */
clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
@ -1278,7 +1303,7 @@ static struct tegra_cpu_car_ops tegra114_cpu_car_ops = {
static const struct of_device_id pmc_match[] __initconst = {
{ .compatible = "nvidia,tegra114-pmc" },
{},
{ },
};
/*
@ -1286,37 +1311,37 @@ static const struct of_device_id pmc_match[] __initconst = {
* breaks
*/
static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA114_CLK_UARTA, TEGRA114_CLK_PLL_P, 408000000, 0},
{TEGRA114_CLK_UARTB, TEGRA114_CLK_PLL_P, 408000000, 0},
{TEGRA114_CLK_UARTC, TEGRA114_CLK_PLL_P, 408000000, 0},
{TEGRA114_CLK_UARTD, TEGRA114_CLK_PLL_P, 408000000, 0},
{TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1},
{TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1},
{TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1},
{TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1},
{TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1},
{TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA114_CLK_I2S3, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA114_CLK_I2S4, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA114_CLK_HOST1X, TEGRA114_CLK_PLL_P, 136000000, 0},
{TEGRA114_CLK_DFLL_SOC, TEGRA114_CLK_PLL_P, 51000000, 1},
{TEGRA114_CLK_DFLL_REF, TEGRA114_CLK_PLL_P, 51000000, 1},
{TEGRA114_CLK_DISP1, TEGRA114_CLK_PLL_P, 0, 0},
{TEGRA114_CLK_DISP2, TEGRA114_CLK_PLL_P, 0, 0},
{TEGRA114_CLK_GR2D, TEGRA114_CLK_PLL_C2, 300000000, 0},
{TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0},
{TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0},
{TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0},
{TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0},
{TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0},
{TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0},
{TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0},
{TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0},
{TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0},
/* This MUST be the last entry. */
{TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0},
{ TEGRA114_CLK_UARTA, TEGRA114_CLK_PLL_P, 408000000, 0 },
{ TEGRA114_CLK_UARTB, TEGRA114_CLK_PLL_P, 408000000, 0 },
{ TEGRA114_CLK_UARTC, TEGRA114_CLK_PLL_P, 408000000, 0 },
{ TEGRA114_CLK_UARTD, TEGRA114_CLK_PLL_P, 408000000, 0 },
{ TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1 },
{ TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1 },
{ TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1 },
{ TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1 },
{ TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1 },
{ TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA114_CLK_I2S3, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA114_CLK_I2S4, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA114_CLK_HOST1X, TEGRA114_CLK_PLL_P, 136000000, 0 },
{ TEGRA114_CLK_DFLL_SOC, TEGRA114_CLK_PLL_P, 51000000, 1 },
{ TEGRA114_CLK_DFLL_REF, TEGRA114_CLK_PLL_P, 51000000, 1 },
{ TEGRA114_CLK_DISP1, TEGRA114_CLK_PLL_P, 0, 0 },
{ TEGRA114_CLK_DISP2, TEGRA114_CLK_PLL_P, 0, 0 },
{ TEGRA114_CLK_GR2D, TEGRA114_CLK_PLL_C2, 300000000, 0 },
{ TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0 },
{ TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0 },
{ TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0 },
{ TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0 },
{ TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0 },
{ TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0 },
{ TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0 },
{ TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0 },
{ TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0 },
/* must be the last entry */
{ TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0 },
};
static void __init tegra114_clock_apply_init_table(void)

View File

@ -150,13 +150,13 @@ static DEFINE_SPINLOCK(emc_lock);
/* possible OSC frequencies in Hz */
static unsigned long tegra124_input_freq[] = {
[0] = 13000000,
[1] = 16800000,
[4] = 19200000,
[5] = 38400000,
[8] = 12000000,
[9] = 48000000,
[12] = 260000000,
[ 0] = 13000000,
[ 1] = 16800000,
[ 4] = 19200000,
[ 5] = 38400000,
[ 8] = 12000000,
[ 9] = 48000000,
[12] = 26000000,
};
static struct div_nmp pllxc_nmp = {
@ -168,33 +168,33 @@ static struct div_nmp pllxc_nmp = {
.divp_width = 4,
};
static struct pdiv_map pllxc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
static const struct pdiv_map pllxc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
{ .pdiv = 0, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1 GHz */
{12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */
{13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */
{16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */
{19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */
{26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */
{0, 0, 0, 0, 0, 0},
{ 12000000, 1000000000, 83, 1, 1, 0 }, /* actual: 996.0 MHz */
{ 13000000, 1000000000, 76, 1, 1, 0 }, /* actual: 988.0 MHz */
{ 16800000, 1000000000, 59, 1, 1, 0 }, /* actual: 991.2 MHz */
{ 19200000, 1000000000, 52, 1, 1, 0 }, /* actual: 998.4 MHz */
{ 26000000, 1000000000, 76, 2, 1, 0 }, /* actual: 988.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_x_params = {
@ -218,24 +218,24 @@ static struct tegra_clk_pll_params pll_x_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_x_freq_table,
.flags = TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
{ 12000000, 624000000, 104, 1, 2},
{ 12000000, 600000000, 100, 1, 2},
{ 13000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 2}, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 2}, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 2}, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 624000000, 104, 1, 2, 0 },
{ 12000000, 600000000, 100, 1, 2, 0 },
{ 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c_params = {
.input_min = 12000000,
.input_max = 800000000,
.cf_min = 12000000,
.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */
.vco_min = 600000000,
.vco_max = 1400000000,
.base_reg = PLLC_BASE,
@ -252,7 +252,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
.freq_table = pll_c_freq_table,
.flags = TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct div_nmp pllcx_nmp = {
@ -264,25 +264,25 @@ static struct div_nmp pllcx_nmp = {
.divp_width = 3,
};
static struct pdiv_map pllc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 6, .hw_val = 4 },
{ .pdiv = 8, .hw_val = 5 },
static const struct pdiv_map pllc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 6, .hw_val = 4 },
{ .pdiv = 8, .hw_val = 5 },
{ .pdiv = 12, .hw_val = 6 },
{ .pdiv = 16, .hw_val = 7 },
{ .pdiv = 0, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = {
{12000000, 600000000, 100, 1, 2},
{13000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */
{16800000, 600000000, 71, 1, 2}, /* actual: 596.4 MHz */
{19200000, 600000000, 62, 1, 2}, /* actual: 595.2 MHz */
{26000000, 600000000, 92, 2, 2}, /* actual: 598.0 MHz */
{0, 0, 0, 0, 0, 0},
{ 12000000, 600000000, 100, 1, 2, 0 },
{ 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c2_params = {
@ -338,32 +338,32 @@ static struct div_nmp pllss_nmp = {
.divp_width = 4,
};
static struct pdiv_map pll12g_ssd_esd_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
static const struct pdiv_map pll12g_ssd_esd_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
{ .pdiv = 0, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_c4_freq_table[] = {
{ 12000000, 600000000, 100, 1, 1},
{ 13000000, 600000000, 92, 1, 1}, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 1}, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 1}, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 1}, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 600000000, 100, 1, 2, 0 },
{ 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_c4_params = {
@ -386,21 +386,35 @@ static struct tegra_clk_pll_params pll_c4_params = {
.ext_misc_reg[1] = 0x5b0,
.ext_misc_reg[2] = 0x5b4,
.freq_table = pll_c4_freq_table,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct pdiv_map pllm_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 0, .hw_val = 0 },
static const struct pdiv_map pllm_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
{12000000, 800000000, 66, 1, 1}, /* actual: 792.0 MHz */
{13000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */
{16800000, 800000000, 47, 1, 1}, /* actual: 789.6 MHz */
{19200000, 800000000, 41, 1, 1}, /* actual: 787.2 MHz */
{26000000, 800000000, 61, 2, 1}, /* actual: 793.0 MHz */
{0, 0, 0, 0, 0, 0},
{ 12000000, 800000000, 66, 1, 1, 0 }, /* actual: 792.0 MHz */
{ 13000000, 800000000, 61, 1, 1, 0 }, /* actual: 793.0 MHz */
{ 16800000, 800000000, 47, 1, 1, 0 }, /* actual: 789.6 MHz */
{ 19200000, 800000000, 41, 1, 1, 0 }, /* actual: 787.2 MHz */
{ 26000000, 800000000, 61, 2, 1, 0 }, /* actual: 793.0 MHz */
{ 0, 0, 0, 0, 0, 0},
};
static struct div_nmp pllm_nmp = {
@ -427,22 +441,41 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.max_p = 2,
.max_p = 5,
.pdiv_tohw = pllm_p,
.div_nmp = &pllm_nmp,
.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
.freq_table = pll_m_freq_table,
.flags = TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
/* PLLE special case: use cpcon field to store cml divider value */
{336000000, 100000000, 100, 21, 16, 11},
{312000000, 100000000, 200, 26, 24, 13},
{13000000, 100000000, 200, 1, 26, 13},
{12000000, 100000000, 200, 1, 24, 13},
{0, 0, 0, 0, 0, 0},
{ 336000000, 100000000, 100, 21, 16, 11 },
{ 312000000, 100000000, 200, 26, 24, 13 },
{ 13000000, 100000000, 200, 1, 26, 13 },
{ 12000000, 100000000, 200, 1, 24, 13 },
{ 0, 0, 0, 0, 0, 0 },
};
static const struct pdiv_map plle_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
{ .pdiv = 3, .hw_val = 2 },
{ .pdiv = 4, .hw_val = 3 },
{ .pdiv = 5, .hw_val = 4 },
{ .pdiv = 6, .hw_val = 5 },
{ .pdiv = 8, .hw_val = 6 },
{ .pdiv = 10, .hw_val = 7 },
{ .pdiv = 12, .hw_val = 8 },
{ .pdiv = 16, .hw_val = 9 },
{ .pdiv = 12, .hw_val = 10 },
{ .pdiv = 16, .hw_val = 11 },
{ .pdiv = 20, .hw_val = 12 },
{ .pdiv = 24, .hw_val = 13 },
{ .pdiv = 32, .hw_val = 14 },
{ .pdiv = 1, .hw_val = 0 },
};
static struct div_nmp plle_nmp = {
@ -467,9 +500,10 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
.pdiv_tohw = plle_p,
.div_nmp = &plle_nmp,
.freq_table = pll_e_freq_table,
.flags = TEGRA_PLL_FIXED,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};
@ -507,7 +541,8 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
.div_nmp = &pllre_nmp,
.flags = TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE |
TEGRA_PLL_LOCK_MISC,
};
static struct div_nmp pllp_nmp = {
@ -520,12 +555,12 @@ static struct div_nmp pllp_nmp = {
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
{12000000, 408000000, 408, 12, 0, 8},
{13000000, 408000000, 408, 13, 0, 8},
{16800000, 408000000, 340, 14, 0, 8},
{19200000, 408000000, 340, 16, 0, 8},
{26000000, 408000000, 408, 26, 0, 8},
{0, 0, 0, 0, 0, 0},
{ 12000000, 408000000, 408, 12, 1, 8 },
{ 13000000, 408000000, 408, 13, 1, 8 },
{ 16800000, 408000000, 340, 14, 1, 8 },
{ 19200000, 408000000, 340, 16, 1, 8 },
{ 26000000, 408000000, 408, 26, 1, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_p_params = {
@ -543,18 +578,18 @@ static struct tegra_clk_pll_params pll_p_params = {
.div_nmp = &pllp_nmp,
.freq_table = pll_p_freq_table,
.fixed_rate = 408000000,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK |
TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
{9600000, 282240000, 147, 5, 0, 4},
{9600000, 368640000, 192, 5, 0, 4},
{9600000, 240000000, 200, 8, 0, 8},
{28800000, 282240000, 245, 25, 0, 8},
{28800000, 368640000, 320, 25, 0, 8},
{28800000, 240000000, 200, 24, 0, 8},
{0, 0, 0, 0, 0, 0},
{ 9600000, 282240000, 147, 5, 1, 4 },
{ 9600000, 368640000, 192, 5, 1, 4 },
{ 9600000, 240000000, 200, 8, 1, 8 },
{ 28800000, 282240000, 245, 25, 1, 8 },
{ 28800000, 368640000, 320, 25, 1, 8 },
{ 28800000, 240000000, 200, 24, 1, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_a_params = {
@ -571,7 +606,8 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_delay = 300,
.div_nmp = &pllp_nmp,
.freq_table = pll_a_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK |
TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct div_nmp plld_nmp = {
@ -584,24 +620,21 @@ static struct div_nmp plld_nmp = {
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
{12000000, 216000000, 864, 12, 4, 12},
{13000000, 216000000, 864, 13, 4, 12},
{16800000, 216000000, 720, 14, 4, 12},
{19200000, 216000000, 720, 16, 4, 12},
{26000000, 216000000, 864, 26, 4, 12},
{12000000, 594000000, 594, 12, 1, 12},
{13000000, 594000000, 594, 13, 1, 12},
{16800000, 594000000, 495, 14, 1, 12},
{19200000, 594000000, 495, 16, 1, 12},
{26000000, 594000000, 594, 26, 1, 12},
{12000000, 1000000000, 1000, 12, 1, 12},
{13000000, 1000000000, 1000, 13, 1, 12},
{19200000, 1000000000, 625, 12, 1, 12},
{26000000, 1000000000, 1000, 26, 1, 12},
{0, 0, 0, 0, 0, 0},
{ 12000000, 216000000, 864, 12, 4, 12 },
{ 13000000, 216000000, 864, 13, 4, 12 },
{ 16800000, 216000000, 720, 14, 4, 12 },
{ 19200000, 216000000, 720, 16, 4, 12 },
{ 26000000, 216000000, 864, 26, 4, 12 },
{ 12000000, 594000000, 594, 12, 1, 12 },
{ 13000000, 594000000, 594, 13, 1, 12 },
{ 16800000, 594000000, 495, 14, 1, 12 },
{ 19200000, 594000000, 495, 16, 1, 12 },
{ 26000000, 594000000, 594, 26, 1, 12 },
{ 12000000, 1000000000, 1000, 12, 1, 12 },
{ 13000000, 1000000000, 1000, 13, 1, 12 },
{ 19200000, 1000000000, 625, 12, 1, 12 },
{ 26000000, 1000000000, 1000, 26, 1, 12 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_d_params = {
@ -619,16 +652,16 @@ static struct tegra_clk_pll_params pll_d_params = {
.div_nmp = &plld_nmp,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
TEGRA_PLL_USE_LOCK,
TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = {
{ 12000000, 594000000, 99, 1, 2},
{ 13000000, 594000000, 91, 1, 2}, /* actual: 591.5 MHz */
{ 16800000, 594000000, 71, 1, 2}, /* actual: 596.4 MHz */
{ 19200000, 594000000, 62, 1, 2}, /* actual: 595.2 MHz */
{ 26000000, 594000000, 91, 2, 2}, /* actual: 591.5 MHz */
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 594000000, 99, 1, 2, 0 },
{ 13000000, 594000000, 91, 1, 2, 0 }, /* actual: 591.5 MHz */
{ 16800000, 594000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
{ 19200000, 594000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
{ 26000000, 594000000, 91, 2, 2, 0 }, /* actual: 591.5 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params tegra124_pll_d2_params = {
@ -652,15 +685,16 @@ static struct tegra_clk_pll_params tegra124_pll_d2_params = {
.ext_misc_reg[2] = 0x578,
.max_p = 15,
.freq_table = tegra124_pll_d2_freq_table,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = {
{ 12000000, 600000000, 100, 1, 1},
{ 13000000, 600000000, 92, 1, 1}, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 1}, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 1}, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 1}, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 600000000, 100, 1, 2, 0 },
{ 13000000, 600000000, 92, 1, 2, 0 }, /* actual: 598.0 MHz */
{ 16800000, 600000000, 71, 1, 2, 0 }, /* actual: 596.4 MHz */
{ 19200000, 600000000, 62, 1, 2, 0 }, /* actual: 595.2 MHz */
{ 26000000, 600000000, 92, 2, 2, 0 }, /* actual: 598.0 MHz */
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_dp_params = {
@ -684,9 +718,10 @@ static struct tegra_clk_pll_params pll_dp_params = {
.ext_misc_reg[2] = 0x5a0,
.max_p = 5,
.freq_table = pll_dp_freq_table,
.flags = TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct pdiv_map pllu_p[] = {
static const struct pdiv_map pllu_p[] = {
{ .pdiv = 1, .hw_val = 1 },
{ .pdiv = 2, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
@ -702,12 +737,12 @@ static struct div_nmp pllu_nmp = {
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
{12000000, 480000000, 960, 12, 2, 12},
{13000000, 480000000, 960, 13, 2, 12},
{16800000, 480000000, 400, 7, 2, 5},
{19200000, 480000000, 200, 4, 2, 3},
{26000000, 480000000, 960, 26, 2, 12},
{0, 0, 0, 0, 0, 0},
{ 12000000, 480000000, 960, 12, 2, 12 },
{ 13000000, 480000000, 960, 13, 2, 12 },
{ 16800000, 480000000, 400, 7, 2, 5 },
{ 19200000, 480000000, 200, 4, 2, 3 },
{ 26000000, 480000000, 960, 26, 2, 12 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_params pll_u_params = {
@ -726,7 +761,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.div_nmp = &pllu_nmp,
.freq_table = pll_u_freq_table,
.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON |
TEGRA_PLL_USE_LOCK,
TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE,
};
struct utmi_clk_param {
@ -743,21 +778,27 @@ struct utmi_clk_param {
};
static const struct utmi_clk_param utmi_parameters[] = {
{.osc_frequency = 13000000, .enable_delay_count = 0x02,
.stable_count = 0x33, .active_delay_count = 0x05,
.xtal_freq_count = 0x7F},
{.osc_frequency = 19200000, .enable_delay_count = 0x03,
.stable_count = 0x4B, .active_delay_count = 0x06,
.xtal_freq_count = 0xBB},
{.osc_frequency = 12000000, .enable_delay_count = 0x02,
.stable_count = 0x2F, .active_delay_count = 0x04,
.xtal_freq_count = 0x76},
{.osc_frequency = 26000000, .enable_delay_count = 0x04,
.stable_count = 0x66, .active_delay_count = 0x09,
.xtal_freq_count = 0xFE},
{.osc_frequency = 16800000, .enable_delay_count = 0x03,
.stable_count = 0x41, .active_delay_count = 0x0A,
.xtal_freq_count = 0xA4},
{
.osc_frequency = 13000000, .enable_delay_count = 0x02,
.stable_count = 0x33, .active_delay_count = 0x05,
.xtal_freq_count = 0x7f
}, {
.osc_frequency = 19200000, .enable_delay_count = 0x03,
.stable_count = 0x4b, .active_delay_count = 0x06,
.xtal_freq_count = 0xbb
}, {
.osc_frequency = 12000000, .enable_delay_count = 0x02,
.stable_count = 0x2f, .active_delay_count = 0x04,
.xtal_freq_count = 0x76
}, {
.osc_frequency = 26000000, .enable_delay_count = 0x04,
.stable_count = 0x66, .active_delay_count = 0x09,
.xtal_freq_count = 0xfe
}, {
.osc_frequency = 16800000, .enable_delay_count = 0x03,
.stable_count = 0x41, .active_delay_count = 0x0a,
.xtal_freq_count = 0xa4
},
};
static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
@ -1024,8 +1065,8 @@ static struct clk **clks;
static void tegra124_utmi_param_configure(void __iomem *clk_base)
{
unsigned int i;
u32 reg;
int i;
for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) {
if (osc_freq == utmi_parameters[i].osc_frequency)
@ -1356,65 +1397,65 @@ static struct tegra_cpu_car_ops tegra124_cpu_car_ops = {
static const struct of_device_id pmc_match[] __initconst = {
{ .compatible = "nvidia,tegra124-pmc" },
{},
{ },
};
static struct tegra_clk_init_table common_init_table[] __initdata = {
{TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1},
{TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1},
{TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1},
{TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1},
{TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0},
{TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1},
{TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0},
{TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0},
{TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1},
{TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1},
{TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1},
{TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0},
{TEGRA124_CLK_PLL_C_OUT1, TEGRA124_CLK_CLK_MAX, 100000000, 0},
{TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1},
{TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0},
{TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0},
{TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0},
{TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0},
{TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0},
{TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0},
{TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0},
{TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0},
{TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0},
{TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0},
{TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0},
/* This MUST be the last entry. */
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
{ TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0 },
{ TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0 },
{ TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0 },
{ TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0 },
{ TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1 },
{ TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1 },
{ TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1 },
{ TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1 },
{ TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1 },
{ TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0 },
{ TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1 },
{ TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0 },
{ TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0 },
{ TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1 },
{ TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1 },
{ TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1 },
{ TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0 },
{ TEGRA124_CLK_PLL_C_OUT1, TEGRA124_CLK_CLK_MAX, 100000000, 0 },
{ TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1 },
{ TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0 },
{ TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0 },
{ TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0 },
{ TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0 },
{ TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0 },
{ TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0 },
{ TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0 },
{ TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0 },
{ TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0 },
{ TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0 },
{ TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1 },
{ TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1 },
{ TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0 },
/* must be the last entry */
{ TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
};
static struct tegra_clk_init_table tegra124_init_table[] __initdata = {
{TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0},
{TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_HDA, TEGRA124_CLK_PLL_P, 102000000, 0},
{TEGRA124_CLK_HDA2CODEC_2X, TEGRA124_CLK_PLL_P, 48000000, 0},
/* This MUST be the last entry. */
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
{ TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0 },
{ TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1 },
{ TEGRA124_CLK_HDA, TEGRA124_CLK_PLL_P, 102000000, 0 },
{ TEGRA124_CLK_HDA2CODEC_2X, TEGRA124_CLK_PLL_P, 48000000, 0 },
/* must be the last entry */
{ TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
};
/* Tegra132 requires the SOC_THERM clock to remain active */
static struct tegra_clk_init_table tegra132_init_table[] __initdata = {
{TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1},
/* This MUST be the last entry. */
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
{ TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1 },
/* must be the last entry */
{ TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0 },
};
static struct tegra_audio_clk_info tegra124_audio_plls[] = {

View File

@ -166,126 +166,120 @@ static DEFINE_SPINLOCK(emc_lock);
static struct clk **clks;
static struct tegra_clk_pll_freq_table pll_c_freq_table[] = {
{ 12000000, 600000000, 600, 12, 0, 8 },
{ 13000000, 600000000, 600, 13, 0, 8 },
{ 19200000, 600000000, 500, 16, 0, 6 },
{ 26000000, 600000000, 600, 26, 0, 8 },
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 600000000, 600, 12, 1, 8 },
{ 13000000, 600000000, 600, 13, 1, 8 },
{ 19200000, 600000000, 500, 16, 1, 6 },
{ 26000000, 600000000, 600, 26, 1, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_m_freq_table[] = {
{ 12000000, 666000000, 666, 12, 0, 8},
{ 13000000, 666000000, 666, 13, 0, 8},
{ 19200000, 666000000, 555, 16, 0, 8},
{ 26000000, 666000000, 666, 26, 0, 8},
{ 12000000, 600000000, 600, 12, 0, 8},
{ 13000000, 600000000, 600, 13, 0, 8},
{ 19200000, 600000000, 375, 12, 0, 6},
{ 26000000, 600000000, 600, 26, 0, 8},
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 666000000, 666, 12, 1, 8 },
{ 13000000, 666000000, 666, 13, 1, 8 },
{ 19200000, 666000000, 555, 16, 1, 8 },
{ 26000000, 666000000, 666, 26, 1, 8 },
{ 12000000, 600000000, 600, 12, 1, 8 },
{ 13000000, 600000000, 600, 13, 1, 8 },
{ 19200000, 600000000, 375, 12, 1, 6 },
{ 26000000, 600000000, 600, 26, 1, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
{ 12000000, 216000000, 432, 12, 1, 8},
{ 13000000, 216000000, 432, 13, 1, 8},
{ 19200000, 216000000, 90, 4, 1, 1},
{ 26000000, 216000000, 432, 26, 1, 8},
{ 12000000, 432000000, 432, 12, 0, 8},
{ 13000000, 432000000, 432, 13, 0, 8},
{ 19200000, 432000000, 90, 4, 0, 1},
{ 26000000, 432000000, 432, 26, 0, 8},
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 216000000, 432, 12, 2, 8 },
{ 13000000, 216000000, 432, 13, 2, 8 },
{ 19200000, 216000000, 90, 4, 2, 1 },
{ 26000000, 216000000, 432, 26, 2, 8 },
{ 12000000, 432000000, 432, 12, 1, 8 },
{ 13000000, 432000000, 432, 13, 1, 8 },
{ 19200000, 432000000, 90, 4, 1, 1 },
{ 26000000, 432000000, 432, 26, 1, 8 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
{ 28800000, 56448000, 49, 25, 0, 1},
{ 28800000, 73728000, 64, 25, 0, 1},
{ 28800000, 24000000, 5, 6, 0, 1},
{ 0, 0, 0, 0, 0, 0 },
{ 28800000, 56448000, 49, 25, 1, 1 },
{ 28800000, 73728000, 64, 25, 1, 1 },
{ 28800000, 24000000, 5, 6, 1, 1 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
{ 12000000, 216000000, 216, 12, 0, 4},
{ 13000000, 216000000, 216, 13, 0, 4},
{ 19200000, 216000000, 135, 12, 0, 3},
{ 26000000, 216000000, 216, 26, 0, 4},
{ 12000000, 594000000, 594, 12, 0, 8},
{ 13000000, 594000000, 594, 13, 0, 8},
{ 19200000, 594000000, 495, 16, 0, 8},
{ 26000000, 594000000, 594, 26, 0, 8},
{ 12000000, 1000000000, 1000, 12, 0, 12},
{ 13000000, 1000000000, 1000, 13, 0, 12},
{ 19200000, 1000000000, 625, 12, 0, 8},
{ 26000000, 1000000000, 1000, 26, 0, 12},
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 216000000, 216, 12, 1, 4 },
{ 13000000, 216000000, 216, 13, 1, 4 },
{ 19200000, 216000000, 135, 12, 1, 3 },
{ 26000000, 216000000, 216, 26, 1, 4 },
{ 12000000, 594000000, 594, 12, 1, 8 },
{ 13000000, 594000000, 594, 13, 1, 8 },
{ 19200000, 594000000, 495, 16, 1, 8 },
{ 26000000, 594000000, 594, 26, 1, 8 },
{ 12000000, 1000000000, 1000, 12, 1, 12 },
{ 13000000, 1000000000, 1000, 13, 1, 12 },
{ 19200000, 1000000000, 625, 12, 1, 8 },
{ 26000000, 1000000000, 1000, 26, 1, 12 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
{ 12000000, 480000000, 960, 12, 0, 0},
{ 13000000, 480000000, 960, 13, 0, 0},
{ 19200000, 480000000, 200, 4, 0, 0},
{ 26000000, 480000000, 960, 26, 0, 0},
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 480000000, 960, 12, 1, 0 },
{ 13000000, 480000000, 960, 13, 1, 0 },
{ 19200000, 480000000, 200, 4, 1, 0 },
{ 26000000, 480000000, 960, 26, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
/* 1 GHz */
{ 12000000, 1000000000, 1000, 12, 0, 12},
{ 13000000, 1000000000, 1000, 13, 0, 12},
{ 19200000, 1000000000, 625, 12, 0, 8},
{ 26000000, 1000000000, 1000, 26, 0, 12},
{ 12000000, 1000000000, 1000, 12, 1, 12 },
{ 13000000, 1000000000, 1000, 13, 1, 12 },
{ 19200000, 1000000000, 625, 12, 1, 8 },
{ 26000000, 1000000000, 1000, 26, 1, 12 },
/* 912 MHz */
{ 12000000, 912000000, 912, 12, 0, 12},
{ 13000000, 912000000, 912, 13, 0, 12},
{ 19200000, 912000000, 760, 16, 0, 8},
{ 26000000, 912000000, 912, 26, 0, 12},
{ 12000000, 912000000, 912, 12, 1, 12 },
{ 13000000, 912000000, 912, 13, 1, 12 },
{ 19200000, 912000000, 760, 16, 1, 8 },
{ 26000000, 912000000, 912, 26, 1, 12 },
/* 816 MHz */
{ 12000000, 816000000, 816, 12, 0, 12},
{ 13000000, 816000000, 816, 13, 0, 12},
{ 19200000, 816000000, 680, 16, 0, 8},
{ 26000000, 816000000, 816, 26, 0, 12},
{ 12000000, 816000000, 816, 12, 1, 12 },
{ 13000000, 816000000, 816, 13, 1, 12 },
{ 19200000, 816000000, 680, 16, 1, 8 },
{ 26000000, 816000000, 816, 26, 1, 12 },
/* 760 MHz */
{ 12000000, 760000000, 760, 12, 0, 12},
{ 13000000, 760000000, 760, 13, 0, 12},
{ 19200000, 760000000, 950, 24, 0, 8},
{ 26000000, 760000000, 760, 26, 0, 12},
{ 12000000, 760000000, 760, 12, 1, 12 },
{ 13000000, 760000000, 760, 13, 1, 12 },
{ 19200000, 760000000, 950, 24, 1, 8 },
{ 26000000, 760000000, 760, 26, 1, 12 },
/* 750 MHz */
{ 12000000, 750000000, 750, 12, 0, 12},
{ 13000000, 750000000, 750, 13, 0, 12},
{ 19200000, 750000000, 625, 16, 0, 8},
{ 26000000, 750000000, 750, 26, 0, 12},
{ 12000000, 750000000, 750, 12, 1, 12 },
{ 13000000, 750000000, 750, 13, 1, 12 },
{ 19200000, 750000000, 625, 16, 1, 8 },
{ 26000000, 750000000, 750, 26, 1, 12 },
/* 608 MHz */
{ 12000000, 608000000, 608, 12, 0, 12},
{ 13000000, 608000000, 608, 13, 0, 12},
{ 19200000, 608000000, 380, 12, 0, 8},
{ 26000000, 608000000, 608, 26, 0, 12},
{ 12000000, 608000000, 608, 12, 1, 12 },
{ 13000000, 608000000, 608, 13, 1, 12 },
{ 19200000, 608000000, 380, 12, 1, 8 },
{ 26000000, 608000000, 608, 26, 1, 12 },
/* 456 MHz */
{ 12000000, 456000000, 456, 12, 0, 12},
{ 13000000, 456000000, 456, 13, 0, 12},
{ 19200000, 456000000, 380, 16, 0, 8},
{ 26000000, 456000000, 456, 26, 0, 12},
{ 12000000, 456000000, 456, 12, 1, 12 },
{ 13000000, 456000000, 456, 13, 1, 12 },
{ 19200000, 456000000, 380, 16, 1, 8 },
{ 26000000, 456000000, 456, 26, 1, 12 },
/* 312 MHz */
{ 12000000, 312000000, 312, 12, 0, 12},
{ 13000000, 312000000, 312, 13, 0, 12},
{ 19200000, 312000000, 260, 16, 0, 8},
{ 26000000, 312000000, 312, 26, 0, 12},
{ 12000000, 312000000, 312, 12, 1, 12 },
{ 13000000, 312000000, 312, 13, 1, 12 },
{ 19200000, 312000000, 260, 16, 1, 8 },
{ 26000000, 312000000, 312, 26, 1, 12 },
{ 0, 0, 0, 0, 0, 0 },
};
{ 0, 0, 0, 0, 0, 0 },
static const struct pdiv_map plle_p[] = {
{ .pdiv = 1, .hw_val = 1 },
{ .pdiv = 0, .hw_val = 0 },
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
{ 12000000, 100000000, 200, 24, 0, 0 },
{ 0, 0, 0, 0, 0, 0 },
{ 12000000, 100000000, 200, 24, 1, 0 },
{ 0, 0, 0, 0, 0, 0 },
};
/* PLL parameters */
@ -302,7 +296,7 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_c_freq_table,
.flags = TEGRA_PLL_HAS_CPCON,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_m_params = {
@ -318,7 +312,7 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_m_freq_table,
.flags = TEGRA_PLL_HAS_CPCON,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_p_params = {
@ -334,7 +328,8 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_p_freq_table,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON |
TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 216000000,
};
@ -351,7 +346,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_a_freq_table,
.flags = TEGRA_PLL_HAS_CPCON,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_d_params = {
@ -367,10 +362,10 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.freq_table = pll_d_freq_table,
.flags = TEGRA_PLL_HAS_CPCON,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct pdiv_map pllu_p[] = {
static const struct pdiv_map pllu_p[] = {
{ .pdiv = 1, .hw_val = 1 },
{ .pdiv = 2, .hw_val = 0 },
{ .pdiv = 0, .hw_val = 0 },
@ -390,7 +385,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_delay = 1000,
.pdiv_tohw = pllu_p,
.freq_table = pll_u_freq_table,
.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON,
.flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_x_params = {
@ -406,7 +401,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.freq_table = pll_x_freq_table,
.flags = TEGRA_PLL_HAS_CPCON,
.flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_HAS_LOCK_ENABLE,
};
static struct tegra_clk_pll_params pll_e_params = {
@ -421,8 +416,10 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 0,
.pdiv_tohw = plle_p,
.freq_table = pll_e_freq_table,
.flags = TEGRA_PLL_FIXED,
.flags = TEGRA_PLL_FIXED | TEGRA_PLL_LOCK_MISC |
TEGRA_PLL_HAS_LOCK_ENABLE,
.fixed_rate = 100000000,
};
@ -733,9 +730,9 @@ static void tegra20_super_clk_init(void)
clks[TEGRA20_CLK_TWD] = clk;
}
static const char *audio_parents[] = {"spdif_in", "i2s1", "i2s2", "unused",
"pll_a_out0", "unused", "unused",
"unused"};
static const char *audio_parents[] = { "spdif_in", "i2s1", "i2s2", "unused",
"pll_a_out0", "unused", "unused",
"unused" };
static void __init tegra20_audio_clk_init(void)
{
@ -759,19 +756,18 @@ static void __init tegra20_audio_clk_init(void)
CLK_SET_RATE_PARENT, 89,
periph_clk_enb_refcnt);
clks[TEGRA20_CLK_AUDIO_2X] = clk;
}
static const char *i2s1_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
"clk_m"};
static const char *i2s2_parents[] = {"pll_a_out0", "audio_2x", "pll_p",
"clk_m"};
static const char *pwm_parents[] = {"pll_p", "pll_c", "audio", "clk_m",
"clk_32k"};
static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"};
static const char *mux_pllpdc_clkm[] = {"pll_p", "pll_d_out0", "pll_c",
"clk_m"};
static const char *mux_pllmcp_clkm[] = {"pll_m", "pll_c", "pll_p", "clk_m"};
static const char *i2s1_parents[] = { "pll_a_out0", "audio_2x", "pll_p",
"clk_m" };
static const char *i2s2_parents[] = { "pll_a_out0", "audio_2x", "pll_p",
"clk_m" };
static const char *pwm_parents[] = { "pll_p", "pll_c", "audio", "clk_m",
"clk_32k" };
static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" };
static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c",
"clk_m" };
static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" };
static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("i2s1", i2s1_parents, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2S1),
@ -802,7 +798,7 @@ static void __init tegra20_periph_clk_init(void)
{
struct tegra_periph_init_data *data;
struct clk *clk;
int i;
unsigned int i;
/* ac97 */
clk = tegra_clk_register_periph_gate("ac97", "pll_a_out0",
@ -1025,44 +1021,45 @@ static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
};
static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA20_CLK_PLL_P, TEGRA20_CLK_CLK_MAX, 216000000, 1},
{TEGRA20_CLK_PLL_P_OUT1, TEGRA20_CLK_CLK_MAX, 28800000, 1},
{TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1},
{TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1},
{TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1},
{TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1},
{TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1},
{TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1},
{TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1},
{TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1},
{TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1},
{TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1},
{TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1},
{TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0},
{TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1},
{TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1},
{TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1},
{TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1},
{TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0},
{TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0},
{TEGRA20_CLK_SDMMC4, TEGRA20_CLK_PLL_P, 48000000, 0},
{TEGRA20_CLK_SPI, TEGRA20_CLK_PLL_P, 20000000, 0},
{TEGRA20_CLK_SBC1, TEGRA20_CLK_PLL_P, 100000000, 0},
{TEGRA20_CLK_SBC2, TEGRA20_CLK_PLL_P, 100000000, 0},
{TEGRA20_CLK_SBC3, TEGRA20_CLK_PLL_P, 100000000, 0},
{TEGRA20_CLK_SBC4, TEGRA20_CLK_PLL_P, 100000000, 0},
{TEGRA20_CLK_HOST1X, TEGRA20_CLK_PLL_C, 150000000, 0},
{TEGRA20_CLK_DISP1, TEGRA20_CLK_PLL_P, 600000000, 0},
{TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0},
{TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0},
{TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0},
{TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0}, /* This MUST be the last entry */
{ TEGRA20_CLK_PLL_P, TEGRA20_CLK_CLK_MAX, 216000000, 1 },
{ TEGRA20_CLK_PLL_P_OUT1, TEGRA20_CLK_CLK_MAX, 28800000, 1 },
{ TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1 },
{ TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 },
{ TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 },
{ TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1 },
{ TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1 },
{ TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1 },
{ TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },
{ TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1 },
{ TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 },
{ TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1 },
{ TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },
{ TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0 },
{ TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0 },
{ TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0 },
{ TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0 },
{ TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0 },
{ TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1 },
{ TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1 },
{ TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1 },
{ TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1 },
{ TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0 },
{ TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0 },
{ TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0 },
{ TEGRA20_CLK_SDMMC4, TEGRA20_CLK_PLL_P, 48000000, 0 },
{ TEGRA20_CLK_SPI, TEGRA20_CLK_PLL_P, 20000000, 0 },
{ TEGRA20_CLK_SBC1, TEGRA20_CLK_PLL_P, 100000000, 0 },
{ TEGRA20_CLK_SBC2, TEGRA20_CLK_PLL_P, 100000000, 0 },
{ TEGRA20_CLK_SBC3, TEGRA20_CLK_PLL_P, 100000000, 0 },
{ TEGRA20_CLK_SBC4, TEGRA20_CLK_PLL_P, 100000000, 0 },
{ TEGRA20_CLK_HOST1X, TEGRA20_CLK_PLL_C, 150000000, 0 },
{ TEGRA20_CLK_DISP1, TEGRA20_CLK_PLL_P, 600000000, 0 },
{ TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0 },
{ TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0 },
{ TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
/* must be the last entry */
{ TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
};
static void __init tegra20_clock_apply_init_table(void)
@ -1076,16 +1073,17 @@ static void __init tegra20_clock_apply_init_table(void)
* table under two names.
*/
static struct tegra_clk_duplicate tegra_clk_duplicates[] = {
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "utmip-pad", NULL),
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-ehci.0", NULL),
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-otg", NULL),
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CCLK, NULL, "cpu"),
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CLK_MAX, NULL, NULL), /* Must be the last entry */
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "utmip-pad", NULL),
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-ehci.0", NULL),
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-otg", NULL),
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CCLK, NULL, "cpu"),
/* must be the last entry */
TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CLK_MAX, NULL, NULL),
};
static const struct of_device_id pmc_match[] __initconst = {
{ .compatible = "nvidia,tegra20-pmc" },
{},
{ },
};
static void __init tegra20_clock_init(struct device_node *np)

Some files were not shown because too many files have changed in this diff Show More