Commit 946797aa authored by Chen-Yu Tsai's avatar Chen-Yu Tsai Committed by Maxime Ripard

clk: sunxi-ng: Support fixed post-dividers on MP style clocks

On the A64, the MMC module clocks are fixed in the new timing mode,
i.e. they do not have a bit to select the mode. These clocks have
a 2x divider somewhere between the clock and the MMC module.

To be consistent with other SoCs supporting the new timing mode,
we model the 2x divider as a fixed post-divider on the MMC module
clocks.

To do this, we first add fixed post-divider to the MP style clocks,
which the MMC module clocks are.
Signed-off-by: default avatarChen-Yu Tsai <wens@csie.org>
Tested-by: default avatarAndre Przywara <andre.przywara@arm.com>
Signed-off-by: default avatarMaxime Ripard <maxime.ripard@free-electrons.com>
parent 4d1369ca
...@@ -50,12 +50,19 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux, ...@@ -50,12 +50,19 @@ static unsigned long ccu_mp_round_rate(struct ccu_mux_internal *mux,
unsigned int max_m, max_p; unsigned int max_m, max_p;
unsigned int m, p; unsigned int m, p;
if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate *= cmp->fixed_post_div;
max_m = cmp->m.max ?: 1 << cmp->m.width; max_m = cmp->m.max ?: 1 << cmp->m.width;
max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p); ccu_mp_find_best(*parent_rate, rate, max_m, max_p, &m, &p);
rate = *parent_rate / p / m;
if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= cmp->fixed_post_div;
return *parent_rate / p / m; return rate;
} }
static void ccu_mp_disable(struct clk_hw *hw) static void ccu_mp_disable(struct clk_hw *hw)
...@@ -83,6 +90,7 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw, ...@@ -83,6 +90,7 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct ccu_mp *cmp = hw_to_ccu_mp(hw); struct ccu_mp *cmp = hw_to_ccu_mp(hw);
unsigned long rate;
unsigned int m, p; unsigned int m, p;
u32 reg; u32 reg;
...@@ -101,7 +109,11 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw, ...@@ -101,7 +109,11 @@ static unsigned long ccu_mp_recalc_rate(struct clk_hw *hw,
p = reg >> cmp->p.shift; p = reg >> cmp->p.shift;
p &= (1 << cmp->p.width) - 1; p &= (1 << cmp->p.width) - 1;
return (parent_rate >> p) / m; rate = (parent_rate >> p) / m;
if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate /= cmp->fixed_post_div;
return rate;
} }
static int ccu_mp_determine_rate(struct clk_hw *hw, static int ccu_mp_determine_rate(struct clk_hw *hw,
...@@ -129,6 +141,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -129,6 +141,10 @@ static int ccu_mp_set_rate(struct clk_hw *hw, unsigned long rate,
max_m = cmp->m.max ?: 1 << cmp->m.width; max_m = cmp->m.max ?: 1 << cmp->m.width;
max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1); max_p = cmp->p.max ?: 1 << ((1 << cmp->p.width) - 1);
/* Adjust target rate according to post-dividers */
if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
rate = rate * cmp->fixed_post_div;
ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p); ccu_mp_find_best(parent_rate, rate, max_m, max_p, &m, &p);
spin_lock_irqsave(cmp->common.lock, flags); spin_lock_irqsave(cmp->common.lock, flags);
......
...@@ -33,9 +33,33 @@ struct ccu_mp { ...@@ -33,9 +33,33 @@ struct ccu_mp {
struct ccu_div_internal m; struct ccu_div_internal m;
struct ccu_div_internal p; struct ccu_div_internal p;
struct ccu_mux_internal mux; struct ccu_mux_internal mux;
unsigned int fixed_post_div;
struct ccu_common common; struct ccu_common common;
}; };
#define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
_gate, _postdiv, _flags) \
struct ccu_mp _struct = { \
.enable = _gate, \
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
.mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
.fixed_post_div = _postdiv, \
.common = { \
.reg = _reg, \
.features = CCU_FEATURE_FIXED_POSTDIV, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&ccu_mp_ops, \
_flags), \
} \
}
#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \ _mshift, _mwidth, \
_pshift, _pwidth, \ _pshift, _pwidth, \
......
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