// SPDX-License-Identifier: GPL-2.0 /* * Alchemy clocks. * * Exposes all configurable internal clock sources to the clk framework. * * We have: * - Root source, usually 12MHz supplied by an external crystal * - 3 PLLs which generate multiples of root rate [AUX, CPU, AUX2] * * Dividers: * - 6 clock dividers with: * * selectable source [one of the PLLs], * * output divided between [2 .. 512 in steps of 2] (!Au1300) * or [1 .. 256 in steps of 1] (Au1300), * * can be enabled individually. * * - up to 6 "internal" (fixed) consumers which: * * take either AUXPLL or one of the above 6 dividers as input, * * divide this input by 1, 2, or 4 (and 3 on Au1300). * * can be disabled separately. * * Misc clocks: * - sysbus clock: CPU core clock (CPUPLL) divided by 2, 3 or 4. * depends on board design and should be set by bootloader, read-only. * - peripheral clock: half the rate of sysbus clock, source for a lot * of peripheral blocks, read-only. * - memory clock: clk rate to main memory chips, depends on board * design and is read-only, * - lrclk: the static bus clock signal for synchronous operation. * depends on board design, must be set by bootloader, * but may be required to correctly configure devices attached to * the static bus. The Au1000/1500/1100 manuals call it LCLK, on * later models it's called RCLK.
*/
/* Base clock: 12MHz is the default in all databooks, and I haven't * found any board yet which uses a different rate.
*/ #define ALCHEMY_ROOTCLK_RATE 12000000
/* * the internal sources which can be driven by the PLLs and dividers. * Names taken from the databooks, refer to them for more information, * especially which ones are share a clock line.
*/ staticconstchar * const alchemy_au1300_intclknames[] = { "lcd_intclk", "gpemgp_clk", "maempe_clk", "maebsa_clk", "EXTCLK0", "EXTCLK1"
};
/* * On early Au1000, sys_cpupll was write-only. Since these * silicon versions of Au1000 are not sold, we don't bend * over backwards trying to determine the frequency.
*/ if (unlikely(au1xxx_cpu_has_pll_wo()))
t = 396000000; else {
t = alchemy_rdsys(AU1000_SYS_CPUPLL) & 0x7f; if (alchemy_get_cputype() < ALCHEMY_CPU_AU1300)
t &= 0x3f;
t *= parent_rate;
}
staticstruct clk __init *alchemy_clk_setup_periph(constchar *pn)
{ /* Peripheral clock runs at half the rate of sysbus clk */ struct clk *c;
c = clk_register_fixed_factor(NULL, ALCHEMY_PERIPH_CLK,
pn, 0, 1, 2); if (!IS_ERR(c))
clk_register_clkdev(c, ALCHEMY_PERIPH_CLK, NULL); return c;
}
/* mem clock **********************************************************/
staticstruct clk __init *alchemy_clk_setup_mem(constchar *pn, int ct)
{ void __iomem *addr = IOMEM(AU1000_MEM_PHYS_ADDR); unsignedlong v; struct clk *c; int div;
switch (ct) { case ALCHEMY_CPU_AU1550: case ALCHEMY_CPU_AU1200:
v = __raw_readl(addr + AU1550_MEM_SDCONFIGB);
div = (v & (1 << 15)) ? 1 : 2; break; case ALCHEMY_CPU_AU1300:
v = __raw_readl(addr + AU1550_MEM_SDCONFIGB);
div = (v & (1 << 31)) ? 1 : 2; break; case ALCHEMY_CPU_AU1000: case ALCHEMY_CPU_AU1500: case ALCHEMY_CPU_AU1100: default:
div = 2; break;
}
c = clk_register_fixed_factor(NULL, ALCHEMY_MEM_CLK, pn,
0, 1, div); if (!IS_ERR(c))
clk_register_clkdev(c, ALCHEMY_MEM_CLK, NULL); return c;
}
/* lrclk: external synchronous static bus clock ***********************/
staticstruct clk __init *alchemy_clk_setup_lrclk(constchar *pn, int t)
{ /* Au1000, Au1500: MEM_STCFG0[11]: If bit is set, lrclk=pclk/5, * otherwise lrclk=pclk/4. * All other variants: MEM_STCFG0[15:13] = divisor. * L/RCLK = periph_clk / (divisor + 1) * On Au1000, Au1500, Au1100 it's called LCLK, * on later models it's called RCLK, but it's the same thing.
*/ struct clk *c; unsignedlong v = alchemy_rdsmem(AU1000_MEM_STCFG0);
switch (t) { case ALCHEMY_CPU_AU1000: case ALCHEMY_CPU_AU1500:
v = 4 + ((v >> 11) & 1); break; default: /* all other models */
v = ((v >> 13) & 7) + 1;
}
c = clk_register_fixed_factor(NULL, ALCHEMY_LR_CLK,
pn, 0, 1, v); if (!IS_ERR(c))
clk_register_clkdev(c, ALCHEMY_LR_CLK, NULL); return c;
}
/* Clock dividers and muxes *******************************************/
/* data for fgen and csrc mux-dividers */ struct alchemy_fgcs_clk { struct clk_hw hw;
spinlock_t *reglock; /* register lock */ unsignedlong reg; /* SYS_FREQCTRL0/1 */ int shift; /* offset in register */ int parent; /* parent before disable [Au1300] */ int isen; /* is it enabled? */ int *dt; /* dividertable for csrc */
}; #define to_fgcs_clk(x) container_of(x, struct alchemy_fgcs_clk, hw)
staticlong alchemy_calc_div(unsignedlong rate, unsignedlong prate, int scale, int maxdiv, unsignedlong *rv)
{ long div1, div2;
/* look at the rates each enabled parent supplies and select * the one that gets closest to but not over the requested rate.
*/ for (j = 0; j < 7; j++) {
pc = clk_hw_get_parent_by_index(hw, j); if (!pc) break;
/* if this parent is currently unused, remember it. * XXX: we would actually want clk_has_active_children() * but this is a good-enough approximation for now.
*/ if (!clk_hw_is_prepared(pc)) { if (!free)
free = pc;
}
pr = clk_hw_get_rate(pc); if (pr < req->rate) continue;
/* what can hardware actually provide */
tdv = alchemy_calc_div(req->rate, pr, scale, maxdiv, NULL);
nr = pr / tdv;
diff = req->rate - nr; if (nr > req->rate) continue;
/* if we couldn't get the exact rate we wanted from the enabled * parents, maybe we can tell an available disabled/inactive one * to give us a rate we can divide down to the requested rate.
*/ if (lastdiff && free) { for (j = (maxdiv == 4) ? 1 : scale; j <= maxdiv; j += scale) {
tpr = req->rate * j; if (tpr < 0) break;
pr = clk_hw_round_rate(free, tpr);
spin_lock_irqsave(c->reglock, flags);
c->parent = index + 1; /* value to write to register */ if (c->isen)
__alchemy_clk_fgv2_en(c);
spin_unlock_irqrestore(c->reglock, flags);
/* fg0-2 and fg4-6 share a "scale"-bit. With this bit cleared, the * dividers behave exactly as on previous models (dividers are multiples * of 2); with the bit set, dividers are multiples of 1, halving their * range, but making them also much more flexible.
*/ staticint alchemy_clk_fgv2_setr(struct clk_hw *hw, unsignedlong rate, unsignedlong parent_rate)
{ struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); int sh = c->shift + 2; unsignedlong div, v, flags, ret;
if (!rate || !parent_rate || rate > parent_rate) return -EINVAL;
v = alchemy_rdsys(c->reg) & (1 << 30); /* test "scale" bit */
ret = alchemy_calc_div(rate, parent_rate, v ? 1 : 2,
v ? 256 : 512, &div);
spin_lock_irqsave(c->reglock, flags);
v = alchemy_rdsys(c->reg);
v &= ~(0xff << sh);
v |= (div & 0xff) << sh;
alchemy_wrsys(v, c->reg);
spin_unlock_irqrestore(c->reglock, flags);
a = kcalloc(6, sizeof(*a), GFP_KERNEL); if (!a) return -ENOMEM;
spin_lock_init(&alchemy_clk_fg0_lock);
spin_lock_init(&alchemy_clk_fg1_lock);
ret = 0; for (i = 0; i < 6; i++) {
id.name = alchemy_clk_fgen_names[i];
a->shift = 10 * (i < 3 ? i : i - 3); if (i > 2) {
a->reg = AU1000_SYS_FREQCTRL1;
a->reglock = &alchemy_clk_fg1_lock;
} else {
a->reg = AU1000_SYS_FREQCTRL0;
a->reglock = &alchemy_clk_fg0_lock;
}
/* default to first parent if bootloader has set * the mux to disabled state.
*/ if (ctype == ALCHEMY_CPU_AU1300) {
v = alchemy_rdsys(a->reg);
a->parent = (v >> a->shift) & 3; if (!a->parent) {
a->parent = 1;
a->isen = 0;
} else
a->isen = 1;
}
a->hw.init = &id;
c = clk_register(NULL, &a->hw); if (IS_ERR(c))
ret++; else
clk_register_clkdev(c, id.name, NULL);
a++;
}
spin_lock_irqsave(c->reglock, flags);
c->parent = index + 1; /* value to write to register */ if (c->isen)
__alchemy_clk_csrc_en(c);
spin_unlock_irqrestore(c->reglock, flags);
/* Root of the Alchemy clock tree: external 12MHz crystal osc */
c = clk_register_fixed_rate(NULL, ALCHEMY_ROOT_CLK, NULL,
0, ALCHEMY_ROOTCLK_RATE);
ERRCK(c)
/* CPU core clock */
c = alchemy_clk_setup_cpu(ALCHEMY_ROOT_CLK, ctype);
ERRCK(c)
/* AUXPLLs: max 1GHz on Au1300, 748MHz on older models */
i = (ctype == ALCHEMY_CPU_AU1300) ? 84 : 63;
c = alchemy_clk_setup_aux(ALCHEMY_ROOT_CLK, ALCHEMY_AUXPLL_CLK,
i, AU1000_SYS_AUXPLL);
ERRCK(c)
if (ctype == ALCHEMY_CPU_AU1300) {
c = alchemy_clk_setup_aux(ALCHEMY_ROOT_CLK,
ALCHEMY_AUXPLL2_CLK, i,
AU1300_SYS_AUXPLL2);
ERRCK(c)
}
/* sysbus clock: cpu core clock divided by 2, 3 or 4 */
c = alchemy_clk_setup_sysbus(ALCHEMY_CPU_CLK);
ERRCK(c)
/* peripheral clock: runs at half rate of sysbus clk */
c = alchemy_clk_setup_periph(ALCHEMY_SYSBUS_CLK);
ERRCK(c)
/* SDR/DDR memory clock */
c = alchemy_clk_setup_mem(ALCHEMY_SYSBUS_CLK, ctype);
ERRCK(c)
/* L/RCLK: external static bus clock for synchronous mode */
c = alchemy_clk_setup_lrclk(ALCHEMY_PERIPH_CLK, ctype);
ERRCK(c)
/* Frequency dividers 0-5 */
ret = alchemy_clk_init_fgens(ctype); if (ret) {
ret = -ENODEV; goto out;
}
/* diving muxes for internal sources */
ret = alchemy_clk_setup_imux(ctype); if (ret) {
ret = -ENODEV; goto out;
}
/* set up aliases drivers might look for */ while (t->base) { if (t->cputype == ctype)
clk_add_alias(t->alias, NULL, t->base, NULL);
t++;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.