diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-15 09:05:03 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-15 09:05:03 +0400 |
commit | c0fa2373f8cfed90437d8d7b17e0b1a84009a10a (patch) | |
tree | 43fb2edd0c11874d0b2e56714e53894d10321e19 /drivers/clk/rockchip/clk-rk3188.c | |
parent | fcc3a5d277571bc6048e7b4ef8cd391b935de629 (diff) | |
parent | 98d147f50eb0ce4328e013f5f2c076896003c761 (diff) | |
download | linux-c0fa2373f8cfed90437d8d7b17e0b1a84009a10a.tar.xz |
Merge tag 'clk-for-linus-3.18' of git://git.linaro.org/people/mike.turquette/linux
Pull clock tree updates from Mike Turquette:
"The clk tree changes for 3.18 are dominated by clock drivers. Mostly
fixes and enhancements to existing drivers as well as new drivers.
This tag contains a bit more arch code than I usually take due to some
OMAP2+ changes. Additionally it contains the restart notifier
handlers which are merged as a dependency into several trees.
The PXA changes are the only messy part. Due to having a stable tree
I had to revert one patch and follow up with one more fix near the tip
of this tag. Some dead code is introduced but it will soon become
live code after 3.18-rc1 is released as the rest of the PXA family is
converted over to the common clock framework.
Another trend in this tag is that multiple vendors have started to
push the complexity of changing their CPU frequency into the clock
driver, whereas this used to be done in CPUfreq drivers.
Changes to the clk core include a generic gpio-clock type and a
clk_set_phase() function added to the top-level clk.h api. Due to
some confusion on the fbdev mailing list the kernel boot parameters
documentation was updated to further explain the clk_ignore_unused
parameter, which is often required by users of the simplefb driver.
Finally some fixes to the locking around the clock debugfs stuff was
done to prevent deadlocks when interacting with other subsystems."
* tag 'clk-for-linus-3.18' of git://git.linaro.org/people/mike.turquette/linux: (99 commits)
clk: pxa clocks build system fix
Revert "arm: pxa: Transition pxa27x to clk framework"
clk: samsung: register restart handlers for s3c2412 and s3c2443
clk: rockchip: add restart handler
clk: rockchip: rk3288: i2s_frac adds flag to set parent's rate
doc/kernel-parameters.txt: clarify clk_ignore_unused
arm: pxa: Transition pxa27x to clk framework
dts: add devicetree bindings for pxa27x clocks
clk: add pxa27x clock drivers
arm: pxa: add clock pll selection bits
clk: dts: document pxa clock binding
clk: add pxa clocks infrastructure
clk: gpio-gate: Ensure gpiod_ APIs are prototyped
clk: ti: dra7-atl-clock: Mark the device as pm_runtime_irq_safe
clk: ti: LLVMLinux: Move __init outside of type definition
clk: ti: consider the fact that of_clk_get() might return an error
clk: ti: dra7-atl-clock: fix a memory leak
clk: ti: change clock init to use generic of_clk_init
clk: hix5hd2: add I2C clocks
clk: hix5hd2: add watchdog0 clocks
...
Diffstat (limited to 'drivers/clk/rockchip/clk-rk3188.c')
-rw-r--r-- | drivers/clk/rockchip/clk-rk3188.c | 171 |
1 files changed, 156 insertions, 15 deletions
diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index a83a6d8d0fb6..beed49c79126 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -19,6 +19,7 @@ #include <dt-bindings/clock/rk3188-cru-common.h> #include "clk.h" +#define RK3066_GRF_SOC_STATUS 0x15c #define RK3188_GRF_SOC_STATUS 0xac enum rk3188_plls { @@ -100,6 +101,98 @@ struct rockchip_pll_rate_table rk3188_pll_rates[] = { { /* sentinel */ }, }; +#define RK3066_DIV_CORE_PERIPH_MASK 0x3 +#define RK3066_DIV_CORE_PERIPH_SHIFT 6 +#define RK3066_DIV_ACLK_CORE_MASK 0x7 +#define RK3066_DIV_ACLK_CORE_SHIFT 0 +#define RK3066_DIV_ACLK_HCLK_MASK 0x3 +#define RK3066_DIV_ACLK_HCLK_SHIFT 8 +#define RK3066_DIV_ACLK_PCLK_MASK 0x3 +#define RK3066_DIV_ACLK_PCLK_SHIFT 12 +#define RK3066_DIV_AHB2APB_MASK 0x3 +#define RK3066_DIV_AHB2APB_SHIFT 14 + +#define RK3066_CLKSEL0(_core_peri) \ + { \ + .reg = RK2928_CLKSEL_CON(0), \ + .val = HIWORD_UPDATE(_core_peri, RK3066_DIV_CORE_PERIPH_MASK, \ + RK3066_DIV_CORE_PERIPH_SHIFT) \ + } +#define RK3066_CLKSEL1(_aclk_core, _aclk_hclk, _aclk_pclk, _ahb2apb) \ + { \ + .reg = RK2928_CLKSEL_CON(1), \ + .val = HIWORD_UPDATE(_aclk_core, RK3066_DIV_ACLK_CORE_MASK, \ + RK3066_DIV_ACLK_CORE_SHIFT) | \ + HIWORD_UPDATE(_aclk_hclk, RK3066_DIV_ACLK_HCLK_MASK, \ + RK3066_DIV_ACLK_HCLK_SHIFT) | \ + HIWORD_UPDATE(_aclk_pclk, RK3066_DIV_ACLK_PCLK_MASK, \ + RK3066_DIV_ACLK_PCLK_SHIFT) | \ + HIWORD_UPDATE(_ahb2apb, RK3066_DIV_AHB2APB_MASK, \ + RK3066_DIV_AHB2APB_SHIFT), \ + } + +#define RK3066_CPUCLK_RATE(_prate, _core_peri, _acore, _ahclk, _apclk, _h2p) \ + { \ + .prate = _prate, \ + .divs = { \ + RK3066_CLKSEL0(_core_peri), \ + RK3066_CLKSEL1(_acore, _ahclk, _apclk, _h2p), \ + }, \ + } + +static struct rockchip_cpuclk_rate_table rk3066_cpuclk_rates[] __initdata = { + RK3066_CPUCLK_RATE(1416000000, 2, 3, 1, 2, 1), + RK3066_CPUCLK_RATE(1200000000, 2, 3, 1, 2, 1), + RK3066_CPUCLK_RATE(1008000000, 2, 2, 1, 2, 1), + RK3066_CPUCLK_RATE( 816000000, 2, 2, 1, 2, 1), + RK3066_CPUCLK_RATE( 600000000, 1, 2, 1, 2, 1), + RK3066_CPUCLK_RATE( 504000000, 1, 1, 1, 2, 1), + RK3066_CPUCLK_RATE( 312000000, 0, 1, 1, 1, 0), +}; + +static const struct rockchip_cpuclk_reg_data rk3066_cpuclk_data = { + .core_reg = RK2928_CLKSEL_CON(0), + .div_core_shift = 0, + .div_core_mask = 0x1f, + .mux_core_shift = 8, +}; + +#define RK3188_DIV_ACLK_CORE_MASK 0x7 +#define RK3188_DIV_ACLK_CORE_SHIFT 3 + +#define RK3188_CLKSEL1(_aclk_core) \ + { \ + .reg = RK2928_CLKSEL_CON(1), \ + .val = HIWORD_UPDATE(_aclk_core, RK3188_DIV_ACLK_CORE_MASK,\ + RK3188_DIV_ACLK_CORE_SHIFT) \ + } +#define RK3188_CPUCLK_RATE(_prate, _core_peri, _aclk_core) \ + { \ + .prate = _prate, \ + .divs = { \ + RK3066_CLKSEL0(_core_peri), \ + RK3188_CLKSEL1(_aclk_core), \ + }, \ + } + +static struct rockchip_cpuclk_rate_table rk3188_cpuclk_rates[] __initdata = { + RK3188_CPUCLK_RATE(1608000000, 2, 3), + RK3188_CPUCLK_RATE(1416000000, 2, 3), + RK3188_CPUCLK_RATE(1200000000, 2, 3), + RK3188_CPUCLK_RATE(1008000000, 2, 3), + RK3188_CPUCLK_RATE( 816000000, 2, 3), + RK3188_CPUCLK_RATE( 600000000, 1, 3), + RK3188_CPUCLK_RATE( 504000000, 1, 3), + RK3188_CPUCLK_RATE( 312000000, 0, 1), +}; + +static const struct rockchip_cpuclk_reg_data rk3188_cpuclk_data = { + .core_reg = RK2928_CLKSEL_CON(0), + .div_core_shift = 9, + .div_core_mask = 0x1f, + .mux_core_shift = 8, +}; + PNAME(mux_pll_p) = { "xin24m", "xin32k" }; PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; PNAME(mux_ddrphy_p) = { "dpll", "gpll_ddr" }; @@ -173,17 +266,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, RK2928_CLKGATE_CON(0), 3, GFLAGS), - DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, - RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), GATE(0, "atclk_cpu", "pclk_cpu_pre", 0, RK2928_CLKGATE_CON(0), 6, GFLAGS), GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, RK2928_CLKGATE_CON(0), 5, GFLAGS), - DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, - RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), - COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, - RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, - RK2928_CLKGATE_CON(4), 9, GFLAGS), GATE(0, "hclk_cpu", "hclk_cpu_pre", 0, RK2928_CLKGATE_CON(0), 4, GFLAGS), @@ -412,10 +498,18 @@ static struct clk_div_table div_aclk_cpu_t[] = { }; static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { - COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, - RK2928_CLKSEL_CON(0), 8, 1, MFLAGS, 0, 5, DFLAGS), DIVTBL(0, "aclk_cpu_pre", "armclk", 0, - RK2928_CLKSEL_CON(1), 0, 3, DFLAGS, div_aclk_cpu_t), + RK2928_CLKSEL_CON(1), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, div_aclk_cpu_t), + DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO + | CLK_DIVIDER_READ_ONLY), + DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO + | CLK_DIVIDER_READ_ONLY), + COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO + | CLK_DIVIDER_READ_ONLY, + RK2928_CLKGATE_CON(4), 9, GFLAGS), GATE(CORE_L2C, "core_l2c", "aclk_cpu", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS), @@ -524,8 +618,6 @@ PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1", "gpll", "cpll" }; static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { - COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0, - RK2928_CLKSEL_CON(0), 8, 1, MFLAGS, 9, 5, DFLAGS), COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", 0, RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS), @@ -533,6 +625,13 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { /* do not source aclk_cpu_pre from the apll, to keep complexity down */ COMPOSITE_NOGATE(0, "aclk_cpu_pre", mux_aclk_cpu_p, CLK_SET_RATE_NO_REPARENT, RK2928_CLKSEL_CON(0), 5, 1, MFLAGS, 0, 5, DFLAGS), + DIV(0, "pclk_cpu_pre", "aclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), + DIV(0, "hclk_cpu_pre", "aclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO), + COMPOSITE_NOMUX(0, "hclk_ahb2apb", "hclk_cpu_pre", 0, + RK2928_CLKSEL_CON(1), 14, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO, + RK2928_CLKGATE_CON(4), 9, GFLAGS), GATE(CORE_L2C, "core_l2c", "armclk", 0, RK2928_CLKGATE_CON(9), 4, GFLAGS), @@ -599,6 +698,12 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { GATE(ACLK_GPS, "aclk_gps", "aclk_peri", 0, RK2928_CLKGATE_CON(8), 13, GFLAGS), }; +static const char *rk3188_critical_clocks[] __initconst = { + "aclk_cpu", + "aclk_peri", + "hclk_peri", +}; + static void __init rk3188_common_clk_init(struct device_node *np) { void __iomem *reg_base; @@ -623,29 +728,65 @@ static void __init rk3188_common_clk_init(struct device_node *np) pr_warn("%s: could not register clock usb480m: %ld\n", __func__, PTR_ERR(clk)); - rockchip_clk_register_plls(rk3188_pll_clks, - ARRAY_SIZE(rk3188_pll_clks), - RK3188_GRF_SOC_STATUS); rockchip_clk_register_branches(common_clk_branches, ARRAY_SIZE(common_clk_branches)); + rockchip_clk_protect_critical(rk3188_critical_clocks, + ARRAY_SIZE(rk3188_critical_clocks)); rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0), ROCKCHIP_SOFTRST_HIWORD_MASK); + + rockchip_register_restart_notifier(RK2928_GLB_SRST_FST); } static void __init rk3066a_clk_init(struct device_node *np) { rk3188_common_clk_init(np); + rockchip_clk_register_plls(rk3188_pll_clks, + ARRAY_SIZE(rk3188_pll_clks), + RK3066_GRF_SOC_STATUS); rockchip_clk_register_branches(rk3066a_clk_branches, ARRAY_SIZE(rk3066a_clk_branches)); + rockchip_clk_register_armclk(ARMCLK, "armclk", + mux_armclk_p, ARRAY_SIZE(mux_armclk_p), + &rk3066_cpuclk_data, rk3066_cpuclk_rates, + ARRAY_SIZE(rk3066_cpuclk_rates)); } CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init); static void __init rk3188a_clk_init(struct device_node *np) { + struct clk *clk1, *clk2; + unsigned long rate; + int ret; + rk3188_common_clk_init(np); + rockchip_clk_register_plls(rk3188_pll_clks, + ARRAY_SIZE(rk3188_pll_clks), + RK3188_GRF_SOC_STATUS); rockchip_clk_register_branches(rk3188_clk_branches, ARRAY_SIZE(rk3188_clk_branches)); + rockchip_clk_register_armclk(ARMCLK, "armclk", + mux_armclk_p, ARRAY_SIZE(mux_armclk_p), + &rk3188_cpuclk_data, rk3188_cpuclk_rates, + ARRAY_SIZE(rk3188_cpuclk_rates)); + + /* reparent aclk_cpu_pre from apll */ + clk1 = __clk_lookup("aclk_cpu_pre"); + clk2 = __clk_lookup("gpll"); + if (clk1 && clk2) { + rate = clk_get_rate(clk1); + + ret = clk_set_parent(clk1, clk2); + if (ret < 0) + pr_warn("%s: could not reparent aclk_cpu_pre to gpll\n", + __func__); + + clk_set_rate(clk1, rate); + } else { + pr_warn("%s: missing clocks to reparent aclk_cpu_pre to gpll\n", + __func__); + } } CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init); |