static void pll1_mode(struct clk *clk, int enabled) { unsigned long timeout; u32 status; u32 ctrl; ctrl = pm_readl(PLL1); if (enabled) { if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) { pr_debug("clk %s: failed to enable, rate not set\n", clk->name); return; } ctrl |= PM_BIT(PLLEN); pm_writel(PLL1, ctrl); /* Wait for PLL lock. */ for (timeout = 10000; timeout; timeout--) { status = pm_readl(ISR); if (status & PM_BIT(LOCK1)) break; udelay(10); } if (!(status & PM_BIT(LOCK1))) printk(KERN_ERR "clk %s: timeout waiting for lock\n", clk->name); } else { ctrl &= ~PM_BIT(PLLEN); pm_writel(PLL1, ctrl); } }
static int clk_show(struct seq_file *s, void *unused) { struct clkinf r; int i; /* show all the power manager registers */ seq_printf(s, "MCCTRL = %8x\n", pm_readl(MCCTRL)); seq_printf(s, "CKSEL = %8x\n", pm_readl(CKSEL)); seq_printf(s, "CPUMASK = %8x\n", pm_readl(CPU_MASK)); seq_printf(s, "HSBMASK = %8x\n", pm_readl(HSB_MASK)); seq_printf(s, "PBAMASK = %8x\n", pm_readl(PBA_MASK)); seq_printf(s, "PBBMASK = %8x\n", pm_readl(PBB_MASK)); seq_printf(s, "PLL0 = %8x\n", pm_readl(PLL0)); seq_printf(s, "PLL1 = %8x\n", pm_readl(PLL1)); seq_printf(s, "IMR = %8x\n", pm_readl(IMR)); for (i = 0; i < 8; i++) { if (i == 5) continue; seq_printf(s, "GCCTRL%d = %8x\n", i, pm_readl(GCCTRL(i))); } seq_printf(s, "\n"); /* show clock tree as derived from the three oscillators * we "know" are at the head of the list */ r.s = s; r.nest = 0; dump_clock(at32_clock_list[0], &r); dump_clock(at32_clock_list[1], &r); dump_clock(at32_clock_list[2], &r); return 0; }
void __init at32_clock_init(void) { u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0; int i; if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) { main_clock = &pll0; cpu_clk.parent = &pll0; } else { main_clock = &osc0; cpu_clk.parent = &osc0; } if (pm_readl(PLL0) & PM_BIT(PLLOSC)) pll0.parent = &osc1; if (pm_readl(PLL1) & PM_BIT(PLLOSC)) pll1.parent = &osc1; genclk_init_parent(&gclk0); genclk_init_parent(&gclk1); genclk_init_parent(&gclk2); genclk_init_parent(&gclk3); genclk_init_parent(&gclk4); genclk_init_parent(&atmel_lcdfb0_pixclk); genclk_init_parent(&abdac0_sample_clk); /* * Turn on all clocks that have at least one user already, and * turn off everything else. We only do this for module * clocks, and even though it isn't particularly pretty to * check the address of the mode function, it should do the * trick... */ for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { struct clk *clk = at32_clock_list[i]; if (clk->users == 0) continue; if (clk->mode == &cpu_clk_mode) cpu_mask |= 1 << clk->index; else if (clk->mode == &hsb_clk_mode) hsb_mask |= 1 << clk->index; else if (clk->mode == &pba_clk_mode) pba_mask |= 1 << clk->index; else if (clk->mode == &pbb_clk_mode) pbb_mask |= 1 << clk->index; } pm_writel(CPU_MASK, cpu_mask); pm_writel(HSB_MASK, hsb_mask); pm_writel(PBA_MASK, pba_mask); pm_writel(PBB_MASK, pbb_mask); }
int genclk_set_parent(struct clk *clk, struct clk *parent) { u32 control; dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n", clk->name, parent->name, clk->parent->name); control = pm_readl(GCCTRL(clk->index)); if (parent == &osc1 || parent == &pll1) control |= PM_BIT(OSCSEL); else if (parent == &osc0 || parent == &pll0) control &= ~PM_BIT(OSCSEL); else return -EINVAL; if (parent == &pll0 || parent == &pll1) control |= PM_BIT(PLLSEL); else control &= ~PM_BIT(PLLSEL); pm_writel(GCCTRL(clk->index), control); clk->parent = parent; return 0; }
static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply) { u32 control; unsigned long parent_rate, actual_rate, div; parent_rate = clk->parent->get_rate(clk->parent); control = pm_readl(GCCTRL(clk->index)); if (rate > 3 * parent_rate / 4) { actual_rate = parent_rate; control &= ~PM_BIT(DIVEN); } else { div = (parent_rate + rate) / (2 * rate) - 1; control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN); actual_rate = parent_rate / (2 * (div + 1)); } dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n", clk->name, rate, actual_rate); if (apply) pm_writel(GCCTRL(clk->index), control); return actual_rate; }
static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply) { u32 control; unsigned long parent_rate, child_div, actual_rate, div; parent_rate = clk->parent->get_rate(clk->parent); control = pm_readl(CKSEL); if (control & PM_BIT(HSBDIV)) child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1); else child_div = 1; if (rate > 3 * (parent_rate / 4) || child_div == 1) { actual_rate = parent_rate; control &= ~PM_BIT(CPUDIV); } else { unsigned int cpusel; div = (parent_rate + rate / 2) / rate; if (div > child_div) div = child_div; cpusel = (div > 1) ? (fls(div) - 2) : 0; control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control); actual_rate = parent_rate / (1 << (cpusel + 1)); } pr_debug("clk %s: new rate %lu (actual rate %lu)\n", clk->name, rate, actual_rate); if (apply) pm_writel(CKSEL, control); return actual_rate; }
static unsigned long pll1_get_rate(struct clk *clk) { u32 control; control = pm_readl(PLL1); return pll_get_rate(clk, control); }
static unsigned long pbb_clk_get_rate(struct clk *clk) { unsigned long cksel, shift = 0; cksel = pm_readl(CKSEL); if (cksel & PM_BIT(PBBDIV)) shift = PM_BFEXT(PBBSEL, cksel) + 1; return bus_clk_get_rate(clk, shift); }
static unsigned long genclk_get_rate(struct clk *clk) { u32 control; unsigned long div = 1; control = pm_readl(GCCTRL(clk->index)); if (control & PM_BIT(DIVEN)) div = 2 * (PM_BFEXT(DIV, control) + 1); return clk->parent->get_rate(clk->parent) / div; }
static void genclk_mode(struct clk *clk, int enabled) { u32 control; control = pm_readl(GCCTRL(clk->index)); if (enabled) control |= PM_BIT(CEN); else control &= ~PM_BIT(CEN); pm_writel(GCCTRL(clk->index), control); }
static void pbb_clk_mode(struct clk *clk, int enabled) { unsigned long flags; u32 mask; spin_lock_irqsave(&pm_lock, flags); mask = pm_readl(PBB_MASK); if (enabled) mask |= 1 << clk->index; else mask &= ~(1 << clk->index); pm_writel(PBB_MASK, mask); spin_unlock_irqrestore(&pm_lock, flags); }
static void __init genclk_init_parent(struct clk *clk) { u32 control; struct clk *parent; BUG_ON(clk->index > 7); control = pm_readl(GCCTRL(clk->index)); if (control & PM_BIT(OSCSEL)) parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1; else parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0; clk->parent = parent; }
static int pll1_set_parent(struct clk *clk, struct clk *parent) { u32 ctrl; if (clk->users > 0) return -EBUSY; ctrl = pm_readl(PLL1); WARN_ON(ctrl & PM_BIT(PLLEN)); if (parent == &osc0) ctrl &= ~PM_BIT(PLLOSC); else if (parent == &osc1) ctrl |= PM_BIT(PLLOSC); else return -EINVAL; pm_writel(PLL1, ctrl); clk->parent = parent; return 0; }