rockchip,bits = <5 1>;
clocks = <&clk_apll>, <&clk_gpll>;
clock-output-names = "aclk_cpu";
- #clock-cells = <0>;
+ #clock-cells = <0>;
#clock-init-cells = <1>;
};
clocks = <&clk_core>;
clock-output-names = "clk_core_peri";
rockchip,div-type = <CLK_DIVIDER_USER_DEFINE>;
+ rockchip,clkops-idx = <CLKOPS_RATE_CORE_PERI>;
#clock-cells = <0>;
rockchip,div-relations = <0x0 2
0x1 4
clocks = <&clk_apll>,
<&clk_gates0 1>;
clock-output-names = "clk_core";
+ rockchip,flags = <(CLK_GET_RATE_NOCACHE |
+ CLK_SET_RATE_NO_REPARENT)>;
#clock-cells = <0>;
};
rockchip,bits = <9 5>;
clocks = <&clk_core>;
rockchip,div-type = <CLK_DIVIDER_PLUS_ONE>;
+ rockchip,clkops-idx = <CLKOPS_RATE_CORE>;
};
/* reg[15:14]: reserved */
clock-output-names = "aclk_core";
#clock-cells = <0>;
rockchip,div-type = <CLK_DIVIDER_USER_DEFINE>;
+ rockchip,clkops-idx = <CLKOPS_RATE_CORE_PERI>;
rockchip,div-relations = <0x0 1
0x1 2
0x2 3
rockchip,bits = <15 1>;
clocks = <&clk_cpll>, <&clk_gpll>;
clock-output-names = "aclk_peri_mux";
- #clock-cells = <0>;
+ #clock-cells = <0>;
#clock-init-cells = <1>;
};
};
.set_rate = clk_fracdiv_set_rate,
};
+static unsigned long clk_core_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ /* As parent rate could be changed in clk_core.set_rate
+ * ops, the passing_in parent_rate may not be the newest
+ * and we should use the parent->rate instead. As a side
+ * effect, we should NOT directly set clk_core's parent
+ * (apll) rate, otherwise we will get a wrong recalc rate
+ * with clk_core_recalc_rate.
+ */
+ struct clk *parent = __clk_get_parent(hw->clk);
+
+ return clk_divider_recalc_rate(hw, __clk_get_rate(parent));
+}
+
+static long clk_core_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_p)
+{
+ struct clk *parent = __clk_get_parent(hw->clk);
+
+ if (IS_ERR_OR_NULL(parent)) {
+ clk_err("fail to get parent!\n");
+ return 0;
+ }
+
+ return clk_round_rate(parent, rate);
+}
+
+static long clk_core_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ return clk_core_determine_rate(hw, rate, prate, NULL);
+}
+
+static int clk_core_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk *parent = __clk_get_parent(hw->clk);
+ struct clk *grand_p = __clk_get_parent(parent);
+ int ret;
+
+ if (IS_ERR_OR_NULL(parent) || IS_ERR_OR_NULL(grand_p)) {
+ clk_err("fail to get parent or grand_parent!\n");
+ return -EINVAL;
+ }
+
+ ret = parent->ops->set_rate(parent->hw, rate, __clk_get_rate(grand_p));
+ parent->rate = parent->ops->recalc_rate(parent->hw,
+ __clk_get_rate(grand_p));
+
+ return ret;
+}
+
+const struct clk_ops clkops_rate_core = {
+ .recalc_rate = clk_core_recalc_rate,
+ .round_rate = clk_core_round_rate,
+ .set_rate = clk_core_set_rate,
+ .determine_rate = clk_core_determine_rate,
+};
+
+const struct clk_ops clkops_rate_core_peri = {
+ .recalc_rate = clk_divider_recalc_rate,
+ .round_rate = clk_divider_round_rate,
+ .set_rate = NULL,
+};
+
struct clk_ops_table rk_clkops_rate_table[] = {
{.index = CLKOPS_RATE_MUX_DIV, .clk_ops = &clkops_rate_auto_parent},
{.index = CLKOPS_RATE_EVENDIV, .clk_ops = &clkops_rate_evendiv},
{.index = CLKOPS_RATE_DCLK_LCDC, .clk_ops = &clkops_rate_dclk_lcdc},
{.index = CLKOPS_RATE_I2S_FRAC, .clk_ops = &clkops_rate_i2s_frac},
{.index = CLKOPS_RATE_FRAC, .clk_ops = &clkops_rate_frac},
+ {.index = CLKOPS_RATE_CORE, .clk_ops = &clkops_rate_core},
+ {.index = CLKOPS_RATE_CORE_PERI, .clk_ops = &clkops_rate_core_peri},
{.index = CLKOPS_RATE_I2S, .clk_ops = NULL},
{.index = CLKOPS_RATE_CIFOUT, .clk_ops = NULL},
{.index = CLKOPS_RATE_UART, .clk_ops = NULL},
rate = rate64;
} else {
rate = parent_rate;
- clk_debug("pll id=%d by pass mode\n", pll_id);
+ clk_debug("pll id=%d slow mode\n", pll_id);
}
clk_debug("pll id=%d, recalc rate =%lu\n", pll->id, rate);
if (lock)
spin_unlock_irqrestore(lock, flags);
- clk_debug("pll id=%d, dump reg:\n con0=%x,con1=%x,mode=%x\n", pll_id,
- cru_readl(PLL_CONS(pll_id,0)),(PLL_CONS(pll_id,1)),
+ clk_debug("pll id=%d, dump reg: con0=0x%08x, con1=0x%08x, mode=0x%08x\n",
+ pll_id,
+ cru_readl(PLL_CONS(pll_id,0)),
+ cru_readl(PLL_CONS(pll_id,1)),
cru_readl(CRU_MODE_CON));
clk_debug("_pll_clk_set_rate end!\n");
CHANGE_APLL:
ps = apll_get_best_set(rate, apll_table);
- clk_debug("apll will set rate(%lu) table con(%x,%x,%x),sel(%x,%x)\n",
- ps->rate, ps->pllcon0, ps->pllcon1, ps->pllcon2,
+ clk_debug("apll will set rate %lu\n", ps->rate);
+ clk_debug("table con:%08x,%08x,%08x, sel:%08x,%08x\n",
+ ps->pllcon0, ps->pllcon1, ps->pllcon2,
ps->clksel0, ps->clksel1);
local_irq_save(flags);
/* If core src don't select gpll, apll need to enter slow mode
* before power down
*/
+ //FIXME
//if(!sel_gpll)
- cru_writel(PLL_MODE_SLOW(APLL_ID), CRU_MODE_CON);
+ cru_writel(PLL_MODE_SLOW(pll->id), CRU_MODE_CON);
/* PLL power down */
cru_writel((0x1<<(16+1))|(0x1<<1), PLL_CONS(pll->id, 3));
}
/* PLL return from slow mode */
- //if (!sel_gpll)
- cru_writel(PLL_MODE_NORM(APLL_ID), CRU_MODE_CON);
+ //FIXME
+ //if(!sel_gpll)
+ cru_writel(PLL_MODE_NORM(pll->id), CRU_MODE_CON);
/* reparent to apll, and set div to 1 */
if (sel_gpll) {
#define CLKOPS_RATE_UART 7
#define CLKOPS_RATE_HSADC 8
#define CLKOPS_RATE_MAC_REF 9
+#define CLKOPS_RATE_CORE 10
+#define CLKOPS_RATE_CORE_PERI 11
#define CLKOPS_TABLE_END (~0)