Merge branches 'clk-semicolon', 'clk-axi-clkgen', 'clk-qoriq', 'clk-baikal', 'clk-const' and 'clk-mmp2' into clk-next
* clk-semicolon: clk: meson: use semicolons rather than commas to separate statements clk: mvebu: ap80x-cpu: use semicolons rather than commas to separate statements clk: uniphier: use semicolons rather than commas to separate statements * clk-axi-clkgen: clk: axi-clkgen: Set power bits for fractional mode clk: axi-clkgen: Add support for fractional dividers * clk-qoriq: clk: qoriq: modify MAX_PLL_DIV to 32 * clk-baikal: clk: baikal-t1: Mark Ethernet PLL as critical * clk-const: clk: pxa: Constify static struct clk_ops * clk-mmp2: clk: mmp2: Fix the display clock divider base
This commit is contained in:
Коммит
97f2f490c1
|
@ -51,11 +51,13 @@ struct ccu_pll_info {
|
|||
};
|
||||
|
||||
/*
|
||||
* Mark as critical all PLLs except Ethernet one. CPU and DDR PLLs are sources
|
||||
* of CPU cores and DDR controller reference clocks, due to which they
|
||||
* obviously shouldn't be ever gated. SATA and PCIe PLLs are the parents of
|
||||
* APB-bus and DDR controller AXI-bus clocks. If they are gated the system will
|
||||
* be unusable.
|
||||
* Alas we have to mark all PLLs as critical. CPU and DDR PLLs are sources of
|
||||
* CPU cores and DDR controller reference clocks, due to which they obviously
|
||||
* shouldn't be ever gated. SATA and PCIe PLLs are the parents of APB-bus and
|
||||
* DDR controller AXI-bus clocks. If they are gated the system will be
|
||||
* unusable. Moreover disabling SATA and Ethernet PLLs causes automatic reset
|
||||
* of the corresponding subsystems. So until we aren't ready to re-initialize
|
||||
* all the devices consuming those PLLs, they will be marked as critical too.
|
||||
*/
|
||||
static const struct ccu_pll_info pll_info[] = {
|
||||
CCU_PLL_INFO(CCU_CPU_PLL, "cpu_pll", "ref_clk", CCU_CPU_PLL_BASE,
|
||||
|
@ -67,7 +69,7 @@ static const struct ccu_pll_info pll_info[] = {
|
|||
CCU_PLL_INFO(CCU_PCIE_PLL, "pcie_pll", "ref_clk", CCU_PCIE_PLL_BASE,
|
||||
CLK_IS_CRITICAL),
|
||||
CCU_PLL_INFO(CCU_ETH_PLL, "eth_pll", "ref_clk", CCU_ETH_PLL_BASE,
|
||||
CLK_SET_RATE_GATE)
|
||||
CLK_IS_CRITICAL | CLK_SET_RATE_GATE)
|
||||
};
|
||||
|
||||
struct ccu_pll_data {
|
||||
|
|
|
@ -27,19 +27,23 @@
|
|||
|
||||
#define AXI_CLKGEN_V2_DRP_STATUS_BUSY BIT(16)
|
||||
|
||||
#define MMCM_REG_CLKOUT5_2 0x07
|
||||
#define MMCM_REG_CLKOUT0_1 0x08
|
||||
#define MMCM_REG_CLKOUT0_2 0x09
|
||||
#define MMCM_REG_CLKOUT6_2 0x13
|
||||
#define MMCM_REG_CLK_FB1 0x14
|
||||
#define MMCM_REG_CLK_FB2 0x15
|
||||
#define MMCM_REG_CLK_DIV 0x16
|
||||
#define MMCM_REG_LOCK1 0x18
|
||||
#define MMCM_REG_LOCK2 0x19
|
||||
#define MMCM_REG_LOCK3 0x1a
|
||||
#define MMCM_REG_POWER 0x28
|
||||
#define MMCM_REG_FILTER1 0x4e
|
||||
#define MMCM_REG_FILTER2 0x4f
|
||||
|
||||
#define MMCM_CLKOUT_NOCOUNT BIT(6)
|
||||
|
||||
#define MMCM_CLK_DIV_DIVIDE BIT(11)
|
||||
#define MMCM_CLK_DIV_NOCOUNT BIT(12)
|
||||
|
||||
struct axi_clkgen {
|
||||
|
@ -107,6 +111,8 @@ static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
|
|||
unsigned long d, d_min, d_max, _d_min, _d_max;
|
||||
unsigned long m, m_min, m_max;
|
||||
unsigned long f, dout, best_f, fvco;
|
||||
unsigned long fract_shift = 0;
|
||||
unsigned long fvco_min_fract, fvco_max_fract;
|
||||
|
||||
fin /= 1000;
|
||||
fout /= 1000;
|
||||
|
@ -119,42 +125,89 @@ static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
|
|||
d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
|
||||
d_max = min_t(unsigned long, fin / fpfd_min, 80);
|
||||
|
||||
m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1);
|
||||
m_max = min_t(unsigned long, fvco_max * d_max / fin, 64);
|
||||
again:
|
||||
fvco_min_fract = fvco_min << fract_shift;
|
||||
fvco_max_fract = fvco_max << fract_shift;
|
||||
|
||||
m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min_fract, fin) * d_min, 1);
|
||||
m_max = min_t(unsigned long, fvco_max_fract * d_max / fin, 64 << fract_shift);
|
||||
|
||||
for (m = m_min; m <= m_max; m++) {
|
||||
_d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max));
|
||||
_d_max = min(d_max, fin * m / fvco_min);
|
||||
_d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max_fract));
|
||||
_d_max = min(d_max, fin * m / fvco_min_fract);
|
||||
|
||||
for (d = _d_min; d <= _d_max; d++) {
|
||||
fvco = fin * m / d;
|
||||
|
||||
dout = DIV_ROUND_CLOSEST(fvco, fout);
|
||||
dout = clamp_t(unsigned long, dout, 1, 128);
|
||||
dout = clamp_t(unsigned long, dout, 1, 128 << fract_shift);
|
||||
f = fvco / dout;
|
||||
if (abs(f - fout) < abs(best_f - fout)) {
|
||||
best_f = f;
|
||||
*best_d = d;
|
||||
*best_m = m;
|
||||
*best_dout = dout;
|
||||
*best_m = m << (3 - fract_shift);
|
||||
*best_dout = dout << (3 - fract_shift);
|
||||
if (best_f == fout)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Lets see if we find a better setting in fractional mode */
|
||||
if (fract_shift == 0) {
|
||||
fract_shift = 3;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low,
|
||||
unsigned int *high, unsigned int *edge, unsigned int *nocount)
|
||||
{
|
||||
if (divider == 1)
|
||||
*nocount = 1;
|
||||
else
|
||||
*nocount = 0;
|
||||
struct axi_clkgen_div_params {
|
||||
unsigned int low;
|
||||
unsigned int high;
|
||||
unsigned int edge;
|
||||
unsigned int nocount;
|
||||
unsigned int frac_en;
|
||||
unsigned int frac;
|
||||
unsigned int frac_wf_f;
|
||||
unsigned int frac_wf_r;
|
||||
unsigned int frac_phase;
|
||||
};
|
||||
|
||||
*high = divider / 2;
|
||||
*edge = divider % 2;
|
||||
*low = divider - *high;
|
||||
static void axi_clkgen_calc_clk_params(unsigned int divider,
|
||||
unsigned int frac_divider, struct axi_clkgen_div_params *params)
|
||||
{
|
||||
|
||||
memset(params, 0x0, sizeof(*params));
|
||||
|
||||
if (divider == 1) {
|
||||
params->nocount = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (frac_divider == 0) {
|
||||
params->high = divider / 2;
|
||||
params->edge = divider % 2;
|
||||
params->low = divider - params->high;
|
||||
} else {
|
||||
params->frac_en = 1;
|
||||
params->frac = frac_divider;
|
||||
|
||||
params->high = divider / 2;
|
||||
params->edge = divider % 2;
|
||||
params->low = params->high;
|
||||
|
||||
if (params->edge == 0) {
|
||||
params->high--;
|
||||
params->frac_wf_r = 1;
|
||||
}
|
||||
|
||||
if (params->edge == 0 || frac_divider == 1)
|
||||
params->low--;
|
||||
if (((params->edge == 0) ^ (frac_divider == 1)) ||
|
||||
(divider == 2 && frac_divider == 1))
|
||||
params->frac_wf_f = 1;
|
||||
|
||||
params->frac_phase = params->edge * 4 + frac_divider / 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
|
||||
|
@ -246,15 +299,29 @@ static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
|
|||
return container_of(clk_hw, struct axi_clkgen, clk_hw);
|
||||
}
|
||||
|
||||
static void axi_clkgen_set_div(struct axi_clkgen *axi_clkgen,
|
||||
unsigned int reg1, unsigned int reg2, unsigned int reg3,
|
||||
struct axi_clkgen_div_params *params)
|
||||
{
|
||||
axi_clkgen_mmcm_write(axi_clkgen, reg1,
|
||||
(params->high << 6) | params->low, 0xefff);
|
||||
axi_clkgen_mmcm_write(axi_clkgen, reg2,
|
||||
(params->frac << 12) | (params->frac_en << 11) |
|
||||
(params->frac_wf_r << 10) | (params->edge << 7) |
|
||||
(params->nocount << 6), 0x7fff);
|
||||
if (reg3 != 0) {
|
||||
axi_clkgen_mmcm_write(axi_clkgen, reg3,
|
||||
(params->frac_phase << 11) | (params->frac_wf_f << 10), 0x3c00);
|
||||
}
|
||||
}
|
||||
|
||||
static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
|
||||
unsigned int d, m, dout;
|
||||
unsigned int nocount;
|
||||
unsigned int high;
|
||||
unsigned int edge;
|
||||
unsigned int low;
|
||||
struct axi_clkgen_div_params params;
|
||||
uint32_t power = 0;
|
||||
uint32_t filter;
|
||||
uint32_t lock;
|
||||
|
||||
|
@ -266,24 +333,26 @@ static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
|||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if ((dout & 0x7) != 0 || (m & 0x7) != 0)
|
||||
power |= 0x9800;
|
||||
|
||||
axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_POWER, power, 0x9800);
|
||||
|
||||
filter = axi_clkgen_lookup_filter(m - 1);
|
||||
lock = axi_clkgen_lookup_lock(m - 1);
|
||||
|
||||
axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_1,
|
||||
(high << 6) | low, 0xefff);
|
||||
axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLKOUT0_2,
|
||||
(edge << 7) | (nocount << 6), 0x03ff);
|
||||
axi_clkgen_calc_clk_params(dout >> 3, dout & 0x7, ¶ms);
|
||||
axi_clkgen_set_div(axi_clkgen, MMCM_REG_CLKOUT0_1, MMCM_REG_CLKOUT0_2,
|
||||
MMCM_REG_CLKOUT5_2, ¶ms);
|
||||
|
||||
axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_calc_clk_params(d, 0, ¶ms);
|
||||
axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_DIV,
|
||||
(edge << 13) | (nocount << 12) | (high << 6) | low, 0x3fff);
|
||||
(params.edge << 13) | (params.nocount << 12) |
|
||||
(params.high << 6) | params.low, 0x3fff);
|
||||
|
||||
axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB1,
|
||||
(high << 6) | low, 0xefff);
|
||||
axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_CLK_FB2,
|
||||
(edge << 7) | (nocount << 6), 0x03ff);
|
||||
axi_clkgen_calc_clk_params(m >> 3, m & 0x7, ¶ms);
|
||||
axi_clkgen_set_div(axi_clkgen, MMCM_REG_CLK_FB1, MMCM_REG_CLK_FB2,
|
||||
MMCM_REG_CLKOUT6_2, ¶ms);
|
||||
|
||||
axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK1, lock & 0x3ff, 0x3ff);
|
||||
axi_clkgen_mmcm_write(axi_clkgen, MMCM_REG_LOCK2,
|
||||
|
@ -313,35 +382,51 @@ static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
|
|||
return min_t(unsigned long long, tmp, LONG_MAX);
|
||||
}
|
||||
|
||||
static unsigned int axi_clkgen_get_div(struct axi_clkgen *axi_clkgen,
|
||||
unsigned int reg1, unsigned int reg2)
|
||||
{
|
||||
unsigned int val1, val2;
|
||||
unsigned int div;
|
||||
|
||||
axi_clkgen_mmcm_read(axi_clkgen, reg2, &val2);
|
||||
if (val2 & MMCM_CLKOUT_NOCOUNT)
|
||||
return 8;
|
||||
|
||||
axi_clkgen_mmcm_read(axi_clkgen, reg1, &val1);
|
||||
|
||||
div = (val1 & 0x3f) + ((val1 >> 6) & 0x3f);
|
||||
div <<= 3;
|
||||
|
||||
if (val2 & MMCM_CLK_DIV_DIVIDE) {
|
||||
if ((val2 & BIT(7)) && (val2 & 0x7000) != 0x1000)
|
||||
div += 8;
|
||||
else
|
||||
div += 16;
|
||||
|
||||
div += (val2 >> 12) & 0x7;
|
||||
}
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
|
||||
unsigned int d, m, dout;
|
||||
unsigned int reg;
|
||||
unsigned long long tmp;
|
||||
unsigned int val;
|
||||
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_2, ®);
|
||||
if (reg & MMCM_CLKOUT_NOCOUNT) {
|
||||
dout = 1;
|
||||
} else {
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®);
|
||||
dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
}
|
||||
dout = axi_clkgen_get_div(axi_clkgen, MMCM_REG_CLKOUT0_1,
|
||||
MMCM_REG_CLKOUT0_2);
|
||||
m = axi_clkgen_get_div(axi_clkgen, MMCM_REG_CLK_FB1,
|
||||
MMCM_REG_CLK_FB2);
|
||||
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, ®);
|
||||
if (reg & MMCM_CLK_DIV_NOCOUNT)
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, &val);
|
||||
if (val & MMCM_CLK_DIV_NOCOUNT)
|
||||
d = 1;
|
||||
else
|
||||
d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB2, ®);
|
||||
if (reg & MMCM_CLKOUT_NOCOUNT) {
|
||||
m = 1;
|
||||
} else {
|
||||
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®);
|
||||
m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
}
|
||||
d = (val & 0x3f) + ((val >> 6) & 0x3f);
|
||||
|
||||
if (d == 0 || dout == 0)
|
||||
return 0;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#define CGA_PLL4 4 /* only on clockgen-1.0, which lacks CGB */
|
||||
#define CGB_PLL1 4
|
||||
#define CGB_PLL2 5
|
||||
#define MAX_PLL_DIV 16
|
||||
#define MAX_PLL_DIV 32
|
||||
|
||||
struct clockgen_pll_div {
|
||||
struct clk *clk;
|
||||
|
|
|
@ -57,7 +57,7 @@ int meson_aoclkc_probe(struct platform_device *pdev)
|
|||
rstc->data = data;
|
||||
rstc->regmap = regmap;
|
||||
rstc->reset.ops = &meson_aoclk_reset_ops;
|
||||
rstc->reset.nr_resets = data->num_reset,
|
||||
rstc->reset.nr_resets = data->num_reset;
|
||||
rstc->reset.of_node = dev->of_node;
|
||||
ret = devm_reset_controller_register(dev, &rstc->reset);
|
||||
if (ret) {
|
||||
|
|
|
@ -347,9 +347,9 @@ static struct mmp_param_mux_clk mmp3_apmu_mux_clks[] = {
|
|||
};
|
||||
|
||||
static struct mmp_param_div_clk apmu_div_clks[] = {
|
||||
{0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 8, 4, 0, &disp0_lock},
|
||||
{0, "disp0_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 8, 4, CLK_DIVIDER_ONE_BASED, &disp0_lock},
|
||||
{0, "disp0_sphy_div", "disp0_mux", CLK_SET_RATE_PARENT, APMU_DISP0, 15, 5, 0, &disp0_lock},
|
||||
{0, "disp1_div", "disp1_mux", CLK_SET_RATE_PARENT, APMU_DISP1, 8, 4, 0, &disp1_lock},
|
||||
{0, "disp1_div", "disp1_mux", CLK_SET_RATE_PARENT, APMU_DISP1, 8, 4, CLK_DIVIDER_ONE_BASED, &disp1_lock},
|
||||
{0, "ccic0_sphy_div", "ccic0_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC0, 10, 5, 0, &ccic0_lock},
|
||||
{0, "ccic1_sphy_div", "ccic1_mix_clk", CLK_SET_RATE_PARENT, APMU_CCIC1, 10, 5, 0, &ccic1_lock},
|
||||
};
|
||||
|
|
|
@ -197,7 +197,7 @@ static int ap_cpu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
|
||||
stable_bit = BIT(clk->pll_regs->ratio_state_offset +
|
||||
clk->cluster *
|
||||
clk->pll_regs->ratio_state_cluster_offset),
|
||||
clk->pll_regs->ratio_state_cluster_offset);
|
||||
ret = regmap_read_poll_timeout(clk->pll_cr_base,
|
||||
clk->pll_regs->ratio_state_reg, reg,
|
||||
reg & stable_bit, STATUS_POLL_PERIOD_US,
|
||||
|
|
|
@ -19,11 +19,11 @@
|
|||
#define MUX_RO_RATE_RO_OPS(name, clk_name) \
|
||||
static struct clk_hw name ## _mux_hw; \
|
||||
static struct clk_hw name ## _rate_hw; \
|
||||
static struct clk_ops name ## _mux_ops = { \
|
||||
static const struct clk_ops name ## _mux_ops = { \
|
||||
.get_parent = name ## _get_parent, \
|
||||
.set_parent = dummy_clk_set_parent, \
|
||||
}; \
|
||||
static struct clk_ops name ## _rate_ops = { \
|
||||
static const struct clk_ops name ## _rate_ops = { \
|
||||
.recalc_rate = name ## _get_rate, \
|
||||
}; \
|
||||
static struct clk * __init clk_register_ ## name(void) \
|
||||
|
@ -38,7 +38,7 @@
|
|||
|
||||
#define RATE_RO_OPS(name, clk_name) \
|
||||
static struct clk_hw name ## _rate_hw; \
|
||||
static const struct clk_ops name ## _rate_ops = { \
|
||||
static const struct clk_ops name ## _rate_ops = { \
|
||||
.recalc_rate = name ## _get_rate, \
|
||||
}; \
|
||||
static struct clk * __init clk_register_ ## name(void) \
|
||||
|
@ -53,7 +53,7 @@
|
|||
|
||||
#define RATE_OPS(name, clk_name) \
|
||||
static struct clk_hw name ## _rate_hw; \
|
||||
static struct clk_ops name ## _rate_ops = { \
|
||||
static const struct clk_ops name ## _rate_ops = { \
|
||||
.recalc_rate = name ## _get_rate, \
|
||||
.set_rate = name ## _set_rate, \
|
||||
.determine_rate = name ## _determine_rate, \
|
||||
|
|
|
@ -90,7 +90,7 @@ struct clk_hw *uniphier_clk_register_cpugear(struct device *dev,
|
|||
init.ops = &uniphier_clk_cpugear_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = data->parent_names;
|
||||
init.num_parents = data->num_parents,
|
||||
init.num_parents = data->num_parents;
|
||||
|
||||
gear->regmap = regmap;
|
||||
gear->regbase = data->regbase;
|
||||
|
|
|
@ -70,7 +70,7 @@ struct clk_hw *uniphier_clk_register_mux(struct device *dev,
|
|||
init.ops = &uniphier_clk_mux_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = data->parent_names;
|
||||
init.num_parents = data->num_parents,
|
||||
init.num_parents = data->num_parents;
|
||||
|
||||
mux->regmap = regmap;
|
||||
mux->reg = data->reg;
|
||||
|
|
Загрузка…
Ссылка в новой задаче