|
@@ -107,9 +107,6 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|
if (bypass)
|
|
if (bypass)
|
|
return parent_rate;
|
|
return parent_rate;
|
|
|
|
|
|
- if (!enable)
|
|
|
|
- return 0;
|
|
|
|
-
|
|
|
|
for (od = 0; od < pll_info->od_max; od++) {
|
|
for (od = 0; od < pll_info->od_max; od++) {
|
|
if (pll_info->od_encoding[od] == od_enc)
|
|
if (pll_info->od_encoding[od] == od_enc)
|
|
break;
|
|
break;
|
|
@@ -153,17 +150,25 @@ ingenic_pll_calc(const struct ingenic_cgu_clk_info *clk_info,
|
|
return div_u64((u64)parent_rate * m, n * od);
|
|
return div_u64((u64)parent_rate * m, n * od);
|
|
}
|
|
}
|
|
|
|
|
|
-static long
|
|
|
|
-ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
|
|
|
|
- unsigned long *prate)
|
|
|
|
|
|
+static inline const struct ingenic_cgu_clk_info *to_clk_info(
|
|
|
|
+ struct ingenic_clk *ingenic_clk)
|
|
{
|
|
{
|
|
- struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
|
|
|
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
|
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
|
const struct ingenic_cgu_clk_info *clk_info;
|
|
const struct ingenic_cgu_clk_info *clk_info;
|
|
|
|
|
|
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
|
clk_info = &cgu->clock_info[ingenic_clk->idx];
|
|
BUG_ON(clk_info->type != CGU_CLK_PLL);
|
|
BUG_ON(clk_info->type != CGU_CLK_PLL);
|
|
|
|
|
|
|
|
+ return clk_info;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static long
|
|
|
|
+ingenic_pll_round_rate(struct clk_hw *hw, unsigned long req_rate,
|
|
|
|
+ unsigned long *prate)
|
|
|
|
+{
|
|
|
|
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
|
|
|
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
|
|
|
|
+
|
|
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
|
|
return ingenic_pll_calc(clk_info, req_rate, *prate, NULL, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -171,19 +176,14 @@ static int
|
|
ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
|
ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
|
unsigned long parent_rate)
|
|
unsigned long parent_rate)
|
|
{
|
|
{
|
|
- const unsigned timeout = 100;
|
|
|
|
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
|
struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
|
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
|
struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
|
- const struct ingenic_cgu_clk_info *clk_info;
|
|
|
|
- const struct ingenic_cgu_pll_info *pll_info;
|
|
|
|
|
|
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
|
|
|
|
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
|
|
unsigned long rate, flags;
|
|
unsigned long rate, flags;
|
|
- unsigned m, n, od, i;
|
|
|
|
|
|
+ unsigned int m, n, od;
|
|
u32 ctl;
|
|
u32 ctl;
|
|
|
|
|
|
- clk_info = &cgu->clock_info[ingenic_clk->idx];
|
|
|
|
- BUG_ON(clk_info->type != CGU_CLK_PLL);
|
|
|
|
- pll_info = &clk_info->pll;
|
|
|
|
-
|
|
|
|
rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
|
|
rate = ingenic_pll_calc(clk_info, req_rate, parent_rate,
|
|
&m, &n, &od);
|
|
&m, &n, &od);
|
|
if (rate != req_rate)
|
|
if (rate != req_rate)
|
|
@@ -202,6 +202,26 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
|
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
|
|
ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift);
|
|
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
|
|
ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift;
|
|
|
|
|
|
|
|
+ writel(ctl, cgu->base + pll_info->reg);
|
|
|
|
+ spin_unlock_irqrestore(&cgu->lock, flags);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int ingenic_pll_enable(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
|
|
|
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
|
|
|
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
|
|
|
|
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
|
|
|
|
+ const unsigned int timeout = 100;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ unsigned int i;
|
|
|
|
+ u32 ctl;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&cgu->lock, flags);
|
|
|
|
+ ctl = readl(cgu->base + pll_info->reg);
|
|
|
|
+
|
|
ctl &= ~BIT(pll_info->bypass_bit);
|
|
ctl &= ~BIT(pll_info->bypass_bit);
|
|
ctl |= BIT(pll_info->enable_bit);
|
|
ctl |= BIT(pll_info->enable_bit);
|
|
|
|
|
|
@@ -223,10 +243,48 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void ingenic_pll_disable(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
|
|
|
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
|
|
|
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
|
|
|
|
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ u32 ctl;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&cgu->lock, flags);
|
|
|
|
+ ctl = readl(cgu->base + pll_info->reg);
|
|
|
|
+
|
|
|
|
+ ctl &= ~BIT(pll_info->enable_bit);
|
|
|
|
+
|
|
|
|
+ writel(ctl, cgu->base + pll_info->reg);
|
|
|
|
+ spin_unlock_irqrestore(&cgu->lock, flags);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int ingenic_pll_is_enabled(struct clk_hw *hw)
|
|
|
|
+{
|
|
|
|
+ struct ingenic_clk *ingenic_clk = to_ingenic_clk(hw);
|
|
|
|
+ struct ingenic_cgu *cgu = ingenic_clk->cgu;
|
|
|
|
+ const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk);
|
|
|
|
+ const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ u32 ctl;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&cgu->lock, flags);
|
|
|
|
+ ctl = readl(cgu->base + pll_info->reg);
|
|
|
|
+ spin_unlock_irqrestore(&cgu->lock, flags);
|
|
|
|
+
|
|
|
|
+ return !!(ctl & BIT(pll_info->enable_bit));
|
|
|
|
+}
|
|
|
|
+
|
|
static const struct clk_ops ingenic_pll_ops = {
|
|
static const struct clk_ops ingenic_pll_ops = {
|
|
.recalc_rate = ingenic_pll_recalc_rate,
|
|
.recalc_rate = ingenic_pll_recalc_rate,
|
|
.round_rate = ingenic_pll_round_rate,
|
|
.round_rate = ingenic_pll_round_rate,
|
|
.set_rate = ingenic_pll_set_rate,
|
|
.set_rate = ingenic_pll_set_rate,
|
|
|
|
+
|
|
|
|
+ .enable = ingenic_pll_enable,
|
|
|
|
+ .disable = ingenic_pll_disable,
|
|
|
|
+ .is_enabled = ingenic_pll_is_enabled,
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -601,6 +659,7 @@ static int ingenic_register_clock(struct ingenic_cgu *cgu, unsigned idx)
|
|
}
|
|
}
|
|
} else if (caps & CGU_CLK_PLL) {
|
|
} else if (caps & CGU_CLK_PLL) {
|
|
clk_init.ops = &ingenic_pll_ops;
|
|
clk_init.ops = &ingenic_pll_ops;
|
|
|
|
+ clk_init.flags |= CLK_SET_RATE_GATE;
|
|
|
|
|
|
caps &= ~CGU_CLK_PLL;
|
|
caps &= ~CGU_CLK_PLL;
|
|
|
|
|