Commit 5ad67d3e authored by Mike Turquette's avatar Mike Turquette

Merge tag 'v3.18-rockchip-cpuclk' of...

Merge tag 'v3.18-rockchip-cpuclk' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into clk-next

CPU clock handling for Rockchip SoCs
parents 8791db53 0e5bdb3f
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
obj-y += clk-rockchip.o obj-y += clk-rockchip.o
obj-y += clk.o obj-y += clk.o
obj-y += clk-pll.o obj-y += clk-pll.o
obj-y += clk-cpu.o
obj-$(CONFIG_RESET_CONTROLLER) += softrst.o obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
obj-y += clk-rk3188.o obj-y += clk-rk3188.o
......
This diff is collapsed.
...@@ -34,7 +34,6 @@ struct rockchip_clk_pll { ...@@ -34,7 +34,6 @@ struct rockchip_clk_pll {
const struct clk_ops *pll_mux_ops; const struct clk_ops *pll_mux_ops;
struct notifier_block clk_nb; struct notifier_block clk_nb;
bool rate_change_remuxed;
void __iomem *reg_base; void __iomem *reg_base;
int lock_offset; int lock_offset;
...@@ -108,38 +107,6 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll) ...@@ -108,38 +107,6 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
return -ETIMEDOUT; return -ETIMEDOUT;
} }
/**
* Set pll mux when changing the pll rate.
* This makes sure to move the pll mux away from the actual pll before
* changing its rate and back to the original parent after the change.
*/
static int rockchip_pll_notifier_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
struct rockchip_clk_pll *pll = to_rockchip_clk_pll_nb(nb);
struct clk_mux *pll_mux = &pll->pll_mux;
const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
int cur_parent;
switch (event) {
case PRE_RATE_CHANGE:
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);
pll->rate_change_remuxed = 1;
}
break;
case POST_RATE_CHANGE:
if (pll->rate_change_remuxed) {
pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
pll->rate_change_remuxed = 0;
}
break;
}
return NOTIFY_OK;
}
/** /**
* PLL used in RK3066, RK3188 and RK3288 * PLL used in RK3066, RK3188 and RK3288
*/ */
...@@ -194,6 +161,10 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -194,6 +161,10 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
const struct rockchip_pll_rate_table *rate; const struct rockchip_pll_rate_table *rate;
unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate); unsigned long old_rate = rockchip_rk3066_pll_recalc_rate(hw, prate);
struct regmap *grf = rockchip_clk_get_grf(); struct regmap *grf = rockchip_clk_get_grf();
struct clk_mux *pll_mux = &pll->pll_mux;
const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
int rate_change_remuxed = 0;
int cur_parent;
int ret; int ret;
if (IS_ERR(grf)) { if (IS_ERR(grf)) {
...@@ -216,6 +187,12 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -216,6 +187,12 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n", pr_debug("%s: rate settings for %lu (nr, no, nf): (%d, %d, %d)\n",
__func__, rate->rate, rate->nr, rate->no, rate->nf); __func__, rate->rate, rate->nr, rate->no, rate->nf);
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;
}
/* enter reset mode */ /* enter reset mode */
writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0), writel(HIWORD_UPDATE(RK3066_PLLCON3_RESET, RK3066_PLLCON3_RESET, 0),
pll->reg_base + RK3066_PLLCON(3)); pll->reg_base + RK3066_PLLCON(3));
...@@ -247,6 +224,9 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate, ...@@ -247,6 +224,9 @@ static int rockchip_rk3066_pll_set_rate(struct clk_hw *hw, unsigned long drate,
rockchip_rk3066_pll_set_rate(hw, old_rate, prate); rockchip_rk3066_pll_set_rate(hw, old_rate, prate);
} }
if (rate_change_remuxed)
pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
return ret; return ret;
} }
...@@ -310,7 +290,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, ...@@ -310,7 +290,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
struct clk_mux *pll_mux; struct clk_mux *pll_mux;
struct clk *pll_clk, *mux_clk; struct clk *pll_clk, *mux_clk;
char pll_name[20]; char pll_name[20];
int ret;
if (num_parents != 2) { if (num_parents != 2) {
pr_err("%s: needs two parent clocks\n", __func__); pr_err("%s: needs two parent clocks\n", __func__);
...@@ -367,7 +346,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, ...@@ -367,7 +346,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
pll->lock_offset = grf_lock_offset; pll->lock_offset = grf_lock_offset;
pll->lock_shift = lock_shift; pll->lock_shift = lock_shift;
pll->lock = lock; pll->lock = lock;
pll->clk_nb.notifier_call = rockchip_pll_notifier_cb;
pll_clk = clk_register(NULL, &pll->hw); pll_clk = clk_register(NULL, &pll->hw);
if (IS_ERR(pll_clk)) { if (IS_ERR(pll_clk)) {
...@@ -377,14 +355,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, ...@@ -377,14 +355,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
goto err_pll; goto err_pll;
} }
ret = clk_notifier_register(pll_clk, &pll->clk_nb);
if (ret) {
pr_err("%s: failed to register clock notifier for %s : %d\n",
__func__, name, ret);
mux_clk = ERR_PTR(ret);
goto err_pll_notifier;
}
/* create the mux on top of the real pll */ /* create the mux on top of the real pll */
pll->pll_mux_ops = &clk_mux_ops; pll->pll_mux_ops = &clk_mux_ops;
pll_mux = &pll->pll_mux; pll_mux = &pll->pll_mux;
...@@ -417,13 +387,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, ...@@ -417,13 +387,6 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
return mux_clk; return mux_clk;
err_mux: err_mux:
ret = clk_notifier_unregister(pll_clk, &pll->clk_nb);
if (ret) {
pr_err("%s: could not unregister clock notifier in error path : %d\n",
__func__, ret);
return mux_clk;
}
err_pll_notifier:
clk_unregister(pll_clk); clk_unregister(pll_clk);
err_pll: err_pll:
kfree(pll); kfree(pll);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <dt-bindings/clock/rk3188-cru-common.h> #include <dt-bindings/clock/rk3188-cru-common.h>
#include "clk.h" #include "clk.h"
#define RK3066_GRF_SOC_STATUS 0x15c
#define RK3188_GRF_SOC_STATUS 0xac #define RK3188_GRF_SOC_STATUS 0xac
enum rk3188_plls { enum rk3188_plls {
...@@ -100,6 +101,98 @@ struct rockchip_pll_rate_table rk3188_pll_rates[] = { ...@@ -100,6 +101,98 @@ struct rockchip_pll_rate_table rk3188_pll_rates[] = {
{ /* sentinel */ }, { /* 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_pll_p) = { "xin24m", "xin32k" };
PNAME(mux_armclk_p) = { "apll", "gpll_armclk" }; PNAME(mux_armclk_p) = { "apll", "gpll_armclk" };
PNAME(mux_ddrphy_p) = { "dpll", "gpll_ddr" }; PNAME(mux_ddrphy_p) = { "dpll", "gpll_ddr" };
...@@ -173,17 +266,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { ...@@ -173,17 +266,10 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
GATE(0, "aclk_cpu", "aclk_cpu_pre", 0, GATE(0, "aclk_cpu", "aclk_cpu_pre", 0,
RK2928_CLKGATE_CON(0), 3, GFLAGS), 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, GATE(0, "atclk_cpu", "pclk_cpu_pre", 0,
RK2928_CLKGATE_CON(0), 6, GFLAGS), RK2928_CLKGATE_CON(0), 6, GFLAGS),
GATE(0, "pclk_cpu", "pclk_cpu_pre", 0, GATE(0, "pclk_cpu", "pclk_cpu_pre", 0,
RK2928_CLKGATE_CON(0), 5, GFLAGS), 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, GATE(0, "hclk_cpu", "hclk_cpu_pre", 0,
RK2928_CLKGATE_CON(0), 4, GFLAGS), RK2928_CLKGATE_CON(0), 4, GFLAGS),
...@@ -412,10 +498,18 @@ static struct clk_div_table div_aclk_cpu_t[] = { ...@@ -412,10 +498,18 @@ static struct clk_div_table div_aclk_cpu_t[] = {
}; };
static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { 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, 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, GATE(CORE_L2C, "core_l2c", "aclk_cpu", 0,
RK2928_CLKGATE_CON(9), 4, GFLAGS), RK2928_CLKGATE_CON(9), 4, GFLAGS),
...@@ -524,8 +618,6 @@ PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1", ...@@ -524,8 +618,6 @@ PNAME(mux_hsicphy_p) = { "sclk_otgphy0", "sclk_otgphy1",
"gpll", "cpll" }; "gpll", "cpll" };
static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { 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, COMPOSITE_NOMUX_DIVTBL(0, "aclk_core", "armclk", 0,
RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY, RK2928_CLKSEL_CON(1), 3, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS), div_rk3188_aclk_core_t, RK2928_CLKGATE_CON(0), 7, GFLAGS),
...@@ -533,6 +625,13 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = { ...@@ -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 */ /* 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, 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), 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, GATE(CORE_L2C, "core_l2c", "armclk", 0,
RK2928_CLKGATE_CON(9), 4, GFLAGS), RK2928_CLKGATE_CON(9), 4, GFLAGS),
...@@ -629,9 +728,6 @@ static void __init rk3188_common_clk_init(struct device_node *np) ...@@ -629,9 +728,6 @@ static void __init rk3188_common_clk_init(struct device_node *np)
pr_warn("%s: could not register clock usb480m: %ld\n", pr_warn("%s: could not register clock usb480m: %ld\n",
__func__, PTR_ERR(clk)); __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, rockchip_clk_register_branches(common_clk_branches,
ARRAY_SIZE(common_clk_branches)); ARRAY_SIZE(common_clk_branches));
rockchip_clk_protect_critical(rk3188_critical_clocks, rockchip_clk_protect_critical(rk3188_critical_clocks,
...@@ -644,16 +740,51 @@ static void __init rk3188_common_clk_init(struct device_node *np) ...@@ -644,16 +740,51 @@ static void __init rk3188_common_clk_init(struct device_node *np)
static void __init rk3066a_clk_init(struct device_node *np) static void __init rk3066a_clk_init(struct device_node *np)
{ {
rk3188_common_clk_init(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, rockchip_clk_register_branches(rk3066a_clk_branches,
ARRAY_SIZE(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); CLK_OF_DECLARE(rk3066a_cru, "rockchip,rk3066a-cru", rk3066a_clk_init);
static void __init rk3188a_clk_init(struct device_node *np) static void __init rk3188a_clk_init(struct device_node *np)
{ {
struct clk *clk1, *clk2;
unsigned long rate;
int ret;
rk3188_common_clk_init(np); 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, rockchip_clk_register_branches(rk3188_clk_branches,
ARRAY_SIZE(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); CLK_OF_DECLARE(rk3188a_cru, "rockchip,rk3188a-cru", rk3188a_clk_init);
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "clk.h" #include "clk.h"
#define RK3288_GRF_SOC_CON(x) (0x244 + x * 4) #define RK3288_GRF_SOC_CON(x) (0x244 + x * 4)
#define RK3288_GRF_SOC_STATUS 0x280 #define RK3288_GRF_SOC_STATUS1 0x284
enum rk3288_plls { enum rk3288_plls {
apll, dpll, cpll, gpll, npll, apll, dpll, cpll, gpll, npll,
...@@ -101,6 +101,70 @@ struct rockchip_pll_rate_table rk3288_pll_rates[] = { ...@@ -101,6 +101,70 @@ struct rockchip_pll_rate_table rk3288_pll_rates[] = {
{ /* sentinel */ }, { /* sentinel */ },
}; };
#define RK3288_DIV_ACLK_CORE_M0_MASK 0xf
#define RK3288_DIV_ACLK_CORE_M0_SHIFT 0
#define RK3288_DIV_ACLK_CORE_MP_MASK 0xf
#define RK3288_DIV_ACLK_CORE_MP_SHIFT 4
#define RK3288_DIV_L2RAM_MASK 0x7
#define RK3288_DIV_L2RAM_SHIFT 0
#define RK3288_DIV_ATCLK_MASK 0x1f
#define RK3288_DIV_ATCLK_SHIFT 4
#define RK3288_DIV_PCLK_DBGPRE_MASK 0x1f
#define RK3288_DIV_PCLK_DBGPRE_SHIFT 9
#define RK3288_CLKSEL0(_core_m0, _core_mp) \
{ \
.reg = RK3288_CLKSEL_CON(0), \
.val = HIWORD_UPDATE(_core_m0, RK3288_DIV_ACLK_CORE_M0_MASK, \
RK3288_DIV_ACLK_CORE_M0_SHIFT) | \
HIWORD_UPDATE(_core_mp, RK3288_DIV_ACLK_CORE_MP_MASK, \
RK3288_DIV_ACLK_CORE_MP_SHIFT), \
}
#define RK3288_CLKSEL37(_l2ram, _atclk, _pclk_dbg_pre) \
{ \
.reg = RK3288_CLKSEL_CON(37), \
.val = HIWORD_UPDATE(_l2ram, RK3288_DIV_L2RAM_MASK, \
RK3288_DIV_L2RAM_SHIFT) | \
HIWORD_UPDATE(_atclk, RK3288_DIV_ATCLK_MASK, \
RK3288_DIV_ATCLK_SHIFT) | \
HIWORD_UPDATE(_pclk_dbg_pre, \
RK3288_DIV_PCLK_DBGPRE_MASK, \
RK3288_DIV_PCLK_DBGPRE_SHIFT), \
}
#define RK3288_CPUCLK_RATE(_prate, _core_m0, _core_mp, _l2ram, _atclk, _pdbg) \
{ \
.prate = _prate, \
.divs = { \
RK3288_CLKSEL0(_core_m0, _core_mp), \
RK3288_CLKSEL37(_l2ram, _atclk, _pdbg), \
}, \
}
static struct rockchip_cpuclk_rate_table rk3288_cpuclk_rates[] __initdata = {
RK3288_CPUCLK_RATE(1800000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE(1704000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE(1608000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE(1512000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE(1416000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE(1200000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE(1008000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE( 816000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE( 696000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE( 600000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE( 408000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE( 312000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE( 216000000, 2, 4, 2, 4, 4),
RK3288_CPUCLK_RATE( 126000000, 2, 4, 2, 4, 4),
};
static const struct rockchip_cpuclk_reg_data rk3288_cpuclk_data = {
.core_reg = RK3288_CLKSEL_CON(0),
.div_core_shift = 8,
.div_core_mask = 0x1f,
.mux_core_shift = 15,
};
PNAME(mux_pll_p) = { "xin24m", "xin32k" }; PNAME(mux_pll_p) = { "xin24m", "xin32k" };
PNAME(mux_armclk_p) = { "apll_core", "gpll_core" }; PNAME(mux_armclk_p) = { "apll_core", "gpll_core" };
PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" }; PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" };
...@@ -166,35 +230,33 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { ...@@ -166,35 +230,33 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
RK3288_CLKGATE_CON(0), 1, GFLAGS), RK3288_CLKGATE_CON(0), 1, GFLAGS),
GATE(0, "gpll_core", "gpll", 0, GATE(0, "gpll_core", "gpll", 0,
RK3288_CLKGATE_CON(0), 2, GFLAGS), RK3288_CLKGATE_CON(0), 2, GFLAGS),
COMPOSITE_NOGATE(0, "armclk", mux_armclk_p, 0,
RK3288_CLKSEL_CON(0), 15, 1, MFLAGS, 8, 5, DFLAGS),
COMPOSITE_NOMUX(0, "armcore0", "armclk", 0, COMPOSITE_NOMUX(0, "armcore0", "armclk", 0,
RK3288_CLKSEL_CON(36), 0, 3, DFLAGS, RK3288_CLKSEL_CON(36), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 0, GFLAGS), RK3288_CLKGATE_CON(12), 0, GFLAGS),
COMPOSITE_NOMUX(0, "armcore1", "armclk", 0, COMPOSITE_NOMUX(0, "armcore1", "armclk", 0,
RK3288_CLKSEL_CON(36), 4, 3, DFLAGS, RK3288_CLKSEL_CON(36), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 1, GFLAGS), RK3288_CLKGATE_CON(12), 1, GFLAGS),
COMPOSITE_NOMUX(0, "armcore2", "armclk", 0, COMPOSITE_NOMUX(0, "armcore2", "armclk", 0,
RK3288_CLKSEL_CON(36), 8, 3, DFLAGS, RK3288_CLKSEL_CON(36), 8, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 2, GFLAGS), RK3288_CLKGATE_CON(12), 2, GFLAGS),
COMPOSITE_NOMUX(0, "armcore3", "armclk", 0, COMPOSITE_NOMUX(0, "armcore3", "armclk", 0,
RK3288_CLKSEL_CON(36), 12, 3, DFLAGS, RK3288_CLKSEL_CON(36), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 3, GFLAGS), RK3288_CLKGATE_CON(12), 3, GFLAGS),
COMPOSITE_NOMUX(0, "l2ram", "armclk", 0, COMPOSITE_NOMUX(0, "l2ram", "armclk", 0,
RK3288_CLKSEL_CON(37), 0, 3, DFLAGS, RK3288_CLKSEL_CON(37), 0, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 4, GFLAGS), RK3288_CLKGATE_CON(12), 4, GFLAGS),
COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", 0, COMPOSITE_NOMUX(0, "aclk_core_m0", "armclk", 0,
RK3288_CLKSEL_CON(0), 0, 4, DFLAGS, RK3288_CLKSEL_CON(0), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 5, GFLAGS), RK3288_CLKGATE_CON(12), 5, GFLAGS),
COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", 0, COMPOSITE_NOMUX(0, "aclk_core_mp", "armclk", 0,
RK3288_CLKSEL_CON(0), 4, 4, DFLAGS, RK3288_CLKSEL_CON(0), 4, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 6, GFLAGS), RK3288_CLKGATE_CON(12), 6, GFLAGS),
COMPOSITE_NOMUX(0, "atclk", "armclk", 0, COMPOSITE_NOMUX(0, "atclk", "armclk", 0,
RK3288_CLKSEL_CON(37), 4, 5, DFLAGS, RK3288_CLKSEL_CON(37), 4, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 7, GFLAGS), RK3288_CLKGATE_CON(12), 7, GFLAGS),
COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", 0, COMPOSITE_NOMUX(0, "pclk_dbg_pre", "armclk", 0,
RK3288_CLKSEL_CON(37), 9, 5, DFLAGS, RK3288_CLKSEL_CON(37), 9, 5, DFLAGS | CLK_DIVIDER_READ_ONLY,
RK3288_CLKGATE_CON(12), 8, GFLAGS), RK3288_CLKGATE_CON(12), 8, GFLAGS),
GATE(0, "pclk_dbg", "pclk_dbg_pre", 0, GATE(0, "pclk_dbg", "pclk_dbg_pre", 0,
RK3288_CLKGATE_CON(12), 9, GFLAGS), RK3288_CLKGATE_CON(12), 9, GFLAGS),
...@@ -733,12 +795,17 @@ static void __init rk3288_clk_init(struct device_node *np) ...@@ -733,12 +795,17 @@ static void __init rk3288_clk_init(struct device_node *np)
rockchip_clk_register_plls(rk3288_pll_clks, rockchip_clk_register_plls(rk3288_pll_clks,
ARRAY_SIZE(rk3288_pll_clks), ARRAY_SIZE(rk3288_pll_clks),
RK3288_GRF_SOC_STATUS); RK3288_GRF_SOC_STATUS1);
rockchip_clk_register_branches(rk3288_clk_branches, rockchip_clk_register_branches(rk3288_clk_branches,
ARRAY_SIZE(rk3288_clk_branches)); ARRAY_SIZE(rk3288_clk_branches));
rockchip_clk_protect_critical(rk3288_critical_clocks, rockchip_clk_protect_critical(rk3288_critical_clocks,
ARRAY_SIZE(rk3288_critical_clocks)); ARRAY_SIZE(rk3288_critical_clocks));
rockchip_clk_register_armclk(ARMCLK, "armclk",
mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
&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, reg_base + RK3288_SOFTRST_CON(0),
ROCKCHIP_SOFTRST_HIWORD_MASK); ROCKCHIP_SOFTRST_HIWORD_MASK);
} }
......
...@@ -297,6 +297,27 @@ void __init rockchip_clk_register_branches( ...@@ -297,6 +297,27 @@ void __init rockchip_clk_register_branches(
} }
} }
void __init rockchip_clk_register_armclk(unsigned int lookup_id,
const char *name, const char **parent_names,
u8 num_parents,
const struct rockchip_cpuclk_reg_data *reg_data,
const struct rockchip_cpuclk_rate_table *rates,
int nrates)
{
struct clk *clk;
clk = rockchip_clk_register_cpuclk(name, parent_names, num_parents,
reg_data, rates, nrates, reg_base,
&clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s: %ld\n",
__func__, name, PTR_ERR(clk));
return;
}
rockchip_clk_add_lookup(clk, lookup_id);
}
void __init rockchip_clk_protect_critical(const char *clocks[], int nclocks) void __init rockchip_clk_protect_critical(const char *clocks[], int nclocks)
{ {
int i; int i;
......
...@@ -120,6 +120,38 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, ...@@ -120,6 +120,38 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
struct rockchip_pll_rate_table *rate_table, struct rockchip_pll_rate_table *rate_table,
spinlock_t *lock); spinlock_t *lock);
struct rockchip_cpuclk_clksel {
int reg;
u32 val;
};
#define ROCKCHIP_CPUCLK_NUM_DIVIDERS 2
struct rockchip_cpuclk_rate_table {
unsigned long prate;
struct rockchip_cpuclk_clksel divs[ROCKCHIP_CPUCLK_NUM_DIVIDERS];
};
/**
* struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock
* @core_reg: register offset of the core settings register
* @div_core_shift: core divider offset used to divide the pll value
* @div_core_mask: core divider mask
* @mux_core_shift: offset of the core multiplexer
*/
struct rockchip_cpuclk_reg_data {
int core_reg;
u8 div_core_shift;
u32 div_core_mask;
int mux_core_reg;
u8 mux_core_shift;
};
struct clk *rockchip_clk_register_cpuclk(const char *name,
const char **parent_names, u8 num_parents,
const struct rockchip_cpuclk_reg_data *reg_data,
const struct rockchip_cpuclk_rate_table *rates,
int nrates, void __iomem *reg_base, spinlock_t *lock);
#define PNAME(x) static const char *x[] __initconst #define PNAME(x) static const char *x[] __initconst
enum rockchip_clk_branch_type { enum rockchip_clk_branch_type {
...@@ -329,6 +361,11 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, ...@@ -329,6 +361,11 @@ void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list,
unsigned int nr_clk); unsigned int nr_clk);
void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list,
unsigned int nr_pll, int grf_lock_offset); unsigned int nr_pll, int grf_lock_offset);
void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name,
const char **parent_names, u8 num_parents,
const struct rockchip_cpuclk_reg_data *reg_data,
const struct rockchip_cpuclk_rate_table *rates,
int nrates);
void rockchip_clk_protect_critical(const char *clocks[], int nclocks); void rockchip_clk_protect_critical(const char *clocks[], int nclocks);
#define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0)
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define PLL_GPLL 4 #define PLL_GPLL 4
#define CORE_PERI 5 #define CORE_PERI 5
#define CORE_L2C 6 #define CORE_L2C 6
#define ARMCLK 7
/* sclk gates (special clocks) */ /* sclk gates (special clocks) */
#define SCLK_UART0 64 #define SCLK_UART0 64
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#define PLL_CPLL 3 #define PLL_CPLL 3
#define PLL_GPLL 4 #define PLL_GPLL 4
#define PLL_NPLL 5 #define PLL_NPLL 5
#define ARMCLK 6
/* sclk gates (special clocks) */ /* sclk gates (special clocks) */
#define SCLK_GPU 64 #define SCLK_GPU 64
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment