diff options
Diffstat (limited to 'arch/arm/mach-at91/clock.c')
-rw-r--r-- | arch/arm/mach-at91/clock.c | 77 |
1 files changed, 62 insertions, 15 deletions
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index bac578f..9113da6 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -29,6 +29,7 @@ #include <mach/cpu.h> #include "clock.h" +#include "generic.h" /* @@ -47,20 +48,25 @@ * Chips have some kind of clocks : group them by functionality */ #define cpu_has_utmi() ( cpu_is_at91cap9() \ - || cpu_is_at91sam9rl()) + || cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45()) -#define cpu_has_800M_plla() (cpu_is_at91sam9g20()) +#define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ + || cpu_is_at91sam9g45()) -#define cpu_has_pllb() (!cpu_is_at91sam9rl()) +#define cpu_has_300M_plla() (cpu_is_at91sam9g10()) -#define cpu_has_upll() (0) +#define cpu_has_pllb() (!(cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45())) + +#define cpu_has_upll() (cpu_is_at91sam9g45()) /* USB host HS & FS */ #define cpu_has_uhp() (!cpu_is_at91sam9rl()) /* USB device FS only */ -#define cpu_has_udpfs() (!cpu_is_at91sam9rl()) - +#define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45())) static LIST_HEAD(clocks); static DEFINE_SPINLOCK(clk_lock); @@ -133,6 +139,13 @@ static void pmc_uckr_mode(struct clk *clk, int is_on) { unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); + if (cpu_is_at91sam9g45()) { + if (is_on) + uckr |= AT91_PMC_BIASEN; + else + uckr &= ~AT91_PMC_BIASEN; + } + if (is_on) { is_on = AT91_PMC_LOCKU; at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); @@ -310,6 +323,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate) unsigned long flags; unsigned prescale; unsigned long actual; + unsigned long prev = ULONG_MAX; if (!clk_is_programmable(clk)) return -EINVAL; @@ -317,8 +331,16 @@ long clk_round_rate(struct clk *clk, unsigned long rate) actual = clk->parent->rate_hz; for (prescale = 0; prescale < 7; prescale++) { - if (actual && actual <= rate) + if (actual > rate) + prev = actual; + + if (actual && actual <= rate) { + if ((prev - rate) < (rate - actual)) { + actual = prev; + prescale--; + } break; + } actual >>= 1; } @@ -373,6 +395,10 @@ int clk_set_parent(struct clk *clk, struct clk *parent) return -EBUSY; if (!clk_is_primary(parent) || !clk_is_programmable(clk)) return -EINVAL; + + if (cpu_is_at91sam9rl() && parent->id == AT91_PMC_CSS_PLLB) + return -EINVAL; + spin_lock_irqsave(&clk_lock, flags); clk->rate_hz = parent->rate_hz; @@ -475,7 +501,8 @@ postcore_initcall(at91_clk_debugfs_init); int __init clk_register(struct clk *clk) { if (clk_is_peripheral(clk)) { - clk->parent = &mck; + if (!clk->parent) + clk->parent = &mck; clk->mode = pmc_periph_mode; list_add_tail(&clk->node, &clocks); } @@ -601,7 +628,9 @@ static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock) uhpck.pmc_mask = AT91RM9200_PMC_UHP; udpck.pmc_mask = AT91RM9200_PMC_UDP; at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP); - } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) { + } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || + cpu_is_at91sam9263() || cpu_is_at91sam9g20() || + cpu_is_at91sam9g10() || cpu_is_at572d940hf()) { uhpck.pmc_mask = AT91SAM926x_PMC_UHP; udpck.pmc_mask = AT91SAM926x_PMC_UDP; } else if (cpu_is_at91cap9()) { @@ -629,7 +658,7 @@ static void __init at91_upll_usbfs_clock_init(unsigned long main_clock) /* Now set uhpck values */ uhpck.parent = &utmi_clk; uhpck.pmc_mask = AT91SAM926x_PMC_UHP; - uhpck.rate_hz = utmi_clk.parent->rate_hz; + uhpck.rate_hz = utmi_clk.rate_hz; uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8); } @@ -637,6 +666,7 @@ int __init at91_clock_init(unsigned long main_clock) { unsigned tmp, freq, mckr; int i; + int pll_overclock = false; /* * When the bootloader initialized the main oscillator correctly, @@ -654,12 +684,25 @@ int __init at91_clock_init(unsigned long main_clock) /* report if PLLA is more than mildly overclocked */ plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR)); - if ((!cpu_has_800M_plla() && plla.rate_hz > 209000000) - || (cpu_has_800M_plla() && plla.rate_hz > 800000000)) + if (cpu_has_300M_plla()) { + if (plla.rate_hz > 300000000) + pll_overclock = true; + } else if (cpu_has_800M_plla()) { + if (plla.rate_hz > 800000000) + pll_overclock = true; + } else { + if (plla.rate_hz > 209000000) + pll_overclock = true; + } + if (pll_overclock) pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); + if (cpu_is_at91sam9g45()) { + mckr = at91_sys_read(AT91_PMC_MCKR); + plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */ + } - if (cpu_has_upll() && !cpu_has_pllb()) { + if (!cpu_has_pllb() && cpu_has_upll()) { /* setup UTMI clock as the fourth primary clock * (instead of pllb) */ utmi_clk.type |= CLK_TYPE_PRIMARY; @@ -670,12 +713,13 @@ int __init at91_clock_init(unsigned long main_clock) /* * USB HS clock init */ - if (cpu_has_utmi()) + if (cpu_has_utmi()) { /* * multiplier is hard-wired to 40 * (obtain the USB High Speed 480 MHz when input is 12 MHz) */ utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; + } /* * USB FS clock init @@ -701,8 +745,11 @@ int __init at91_clock_init(unsigned long main_clock) freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ if (mckr & AT91_PMC_PDIV) freq /= 2; /* processor clock division */ + } else if (cpu_is_at91sam9g45()) { + mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ? + freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ } else { - mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ } /* Register the PMC's standard clocks */ |