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:
Stephen Boyd 2020-10-20 11:47:02 -07:00
9 changed files with 156 additions and 69 deletions

View file

@ -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 {

View file

@ -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, &params);
axi_clkgen_set_div(axi_clkgen, MMCM_REG_CLKOUT0_1, MMCM_REG_CLKOUT0_2,
MMCM_REG_CLKOUT5_2, &params);
axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
axi_clkgen_calc_clk_params(d, 0, &params);
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, &params);
axi_clkgen_set_div(axi_clkgen, MMCM_REG_CLK_FB1, MMCM_REG_CLK_FB2,
MMCM_REG_CLKOUT6_2, &params);
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, &reg);
if (reg & MMCM_CLKOUT_NOCOUNT) {
dout = 1;
} else {
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, &reg);
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, &reg);
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, &reg);
if (reg & MMCM_CLKOUT_NOCOUNT) {
m = 1;
} else {
axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, &reg);
m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
}
d = (val & 0x3f) + ((val >> 6) & 0x3f);
if (d == 0 || dout == 0)
return 0;

View file

@ -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;

View file

@ -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) {

View file

@ -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},
};

View file

@ -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,

View file

@ -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, \

View file

@ -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;

View file

@ -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;