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: Chen-Yu Tsai <wens@csie.org> Tested-by: Andre Przywara <andre.przywara@arm.com> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
This commit is contained in:
parent
4d1369cae0
commit
946797aa3f
@ -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;
|
||||||
|
|
||||||
return *parent_rate / p / m;
|
if (cmp->common.features & CCU_FEATURE_FIXED_POSTDIV)
|
||||||
|
rate /= cmp->fixed_post_div;
|
||||||
|
|
||||||
|
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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 {
|
|||||||
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, \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user