diff options
author | Nicolas Ferre <nicolas.ferre@atmel.com> | 2011-03-10 13:08:54 -0500 |
---|---|---|
committer | Nicolas Ferre <nicolas.ferre@atmel.com> | 2012-02-03 09:36:39 -0500 |
commit | 11128726bf9e27e22322151a8018fd57e978e303 (patch) | |
tree | c7f2b897e0516577533ae9e538fa1eccc019af1b /arch/arm/mach-at91/clock.c | |
parent | cbd5c78e3b46881a6cc8bcea17f74b34301a0eb4 (diff) |
ARM: at91/at91sam9x5: clock management for at91sam9x5 chip family
Several changes to PMC have to be managed for adding this support:
- alternate prescaler location for both MCKR and PCKR
- alternate CSS length for PCKR
- added cpu_is_at91sam9x5() to functional switches
- manage UTMI bias like sam9g45 chip family
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Diffstat (limited to 'arch/arm/mach-at91/clock.c')
-rw-r--r-- | arch/arm/mach-at91/clock.c | 83 |
1 files changed, 64 insertions, 19 deletions
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index aa04e22a9da6..a5291e0e7004 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c | |||
@@ -48,24 +48,37 @@ | |||
48 | * Chips have some kind of clocks : group them by functionality | 48 | * Chips have some kind of clocks : group them by functionality |
49 | */ | 49 | */ |
50 | #define cpu_has_utmi() ( cpu_is_at91sam9rl() \ | 50 | #define cpu_has_utmi() ( cpu_is_at91sam9rl() \ |
51 | || cpu_is_at91sam9g45()) | 51 | || cpu_is_at91sam9g45() \ |
52 | || cpu_is_at91sam9x5()) | ||
52 | 53 | ||
53 | #define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ | 54 | #define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ |
54 | || cpu_is_at91sam9g45()) | 55 | || cpu_is_at91sam9g45() \ |
56 | || cpu_is_at91sam9x5()) | ||
55 | 57 | ||
56 | #define cpu_has_300M_plla() (cpu_is_at91sam9g10()) | 58 | #define cpu_has_300M_plla() (cpu_is_at91sam9g10()) |
57 | 59 | ||
58 | #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \ | 60 | #define cpu_has_pllb() (!(cpu_is_at91sam9rl() \ |
59 | || cpu_is_at91sam9g45())) | 61 | || cpu_is_at91sam9g45() \ |
62 | || cpu_is_at91sam9x5())) | ||
60 | 63 | ||
61 | #define cpu_has_upll() (cpu_is_at91sam9g45()) | 64 | #define cpu_has_upll() (cpu_is_at91sam9g45() \ |
65 | || cpu_is_at91sam9x5()) | ||
62 | 66 | ||
63 | /* USB host HS & FS */ | 67 | /* USB host HS & FS */ |
64 | #define cpu_has_uhp() (!cpu_is_at91sam9rl()) | 68 | #define cpu_has_uhp() (!cpu_is_at91sam9rl()) |
65 | 69 | ||
66 | /* USB device FS only */ | 70 | /* USB device FS only */ |
67 | #define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \ | 71 | #define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \ |
68 | || cpu_is_at91sam9g45())) | 72 | || cpu_is_at91sam9g45() \ |
73 | || cpu_is_at91sam9x5())) | ||
74 | |||
75 | #define cpu_has_plladiv2() (cpu_is_at91sam9g45() \ | ||
76 | || cpu_is_at91sam9x5()) | ||
77 | |||
78 | #define cpu_has_mdiv3() (cpu_is_at91sam9g45() \ | ||
79 | || cpu_is_at91sam9x5()) | ||
80 | |||
81 | #define cpu_has_alt_prescaler() (cpu_is_at91sam9x5()) | ||
69 | 82 | ||
70 | static LIST_HEAD(clocks); | 83 | static LIST_HEAD(clocks); |
71 | static DEFINE_SPINLOCK(clk_lock); | 84 | static DEFINE_SPINLOCK(clk_lock); |
@@ -138,13 +151,6 @@ static void pmc_uckr_mode(struct clk *clk, int is_on) | |||
138 | { | 151 | { |
139 | unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); | 152 | unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); |
140 | 153 | ||
141 | if (cpu_is_at91sam9g45()) { | ||
142 | if (is_on) | ||
143 | uckr |= AT91_PMC_BIASEN; | ||
144 | else | ||
145 | uckr &= ~AT91_PMC_BIASEN; | ||
146 | } | ||
147 | |||
148 | if (is_on) { | 154 | if (is_on) { |
149 | is_on = AT91_PMC_LOCKU; | 155 | is_on = AT91_PMC_LOCKU; |
150 | at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); | 156 | at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); |
@@ -209,11 +215,24 @@ static struct clk __init *at91_css_to_clk(unsigned long css) | |||
209 | return &utmi_clk; | 215 | return &utmi_clk; |
210 | else if (cpu_has_pllb()) | 216 | else if (cpu_has_pllb()) |
211 | return &pllb; | 217 | return &pllb; |
218 | break; | ||
219 | /* alternate PMC: can use master clock */ | ||
220 | case AT91_PMC_CSS_MASTER: | ||
221 | return &mck; | ||
212 | } | 222 | } |
213 | 223 | ||
214 | return NULL; | 224 | return NULL; |
215 | } | 225 | } |
216 | 226 | ||
227 | static int pmc_prescaler_divider(u32 reg) | ||
228 | { | ||
229 | if (cpu_has_alt_prescaler()) { | ||
230 | return 1 << ((reg & AT91_PMC_ALT_PRES) >> PMC_ALT_PRES_OFFSET); | ||
231 | } else { | ||
232 | return 1 << ((reg & AT91_PMC_PRES) >> PMC_PRES_OFFSET); | ||
233 | } | ||
234 | } | ||
235 | |||
217 | static void __clk_enable(struct clk *clk) | 236 | static void __clk_enable(struct clk *clk) |
218 | { | 237 | { |
219 | if (clk->parent) | 238 | if (clk->parent) |
@@ -315,12 +334,22 @@ int clk_set_rate(struct clk *clk, unsigned long rate) | |||
315 | { | 334 | { |
316 | unsigned long flags; | 335 | unsigned long flags; |
317 | unsigned prescale; | 336 | unsigned prescale; |
337 | unsigned long prescale_offset, css_mask; | ||
318 | unsigned long actual; | 338 | unsigned long actual; |
319 | 339 | ||
320 | if (!clk_is_programmable(clk)) | 340 | if (!clk_is_programmable(clk)) |
321 | return -EINVAL; | 341 | return -EINVAL; |
322 | if (clk->users) | 342 | if (clk->users) |
323 | return -EBUSY; | 343 | return -EBUSY; |
344 | |||
345 | if (cpu_has_alt_prescaler()) { | ||
346 | prescale_offset = PMC_ALT_PRES_OFFSET; | ||
347 | css_mask = AT91_PMC_ALT_PCKR_CSS; | ||
348 | } else { | ||
349 | prescale_offset = PMC_PRES_OFFSET; | ||
350 | css_mask = AT91_PMC_CSS; | ||
351 | } | ||
352 | |||
324 | spin_lock_irqsave(&clk_lock, flags); | 353 | spin_lock_irqsave(&clk_lock, flags); |
325 | 354 | ||
326 | actual = clk->parent->rate_hz; | 355 | actual = clk->parent->rate_hz; |
@@ -329,8 +358,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate) | |||
329 | u32 pckr; | 358 | u32 pckr; |
330 | 359 | ||
331 | pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); | 360 | pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); |
332 | pckr &= AT91_PMC_CSS; /* clock selection */ | 361 | pckr &= css_mask; /* keep clock selection */ |
333 | pckr |= prescale << 2; | 362 | pckr |= prescale << prescale_offset; |
334 | at91_sys_write(AT91_PMC_PCKR(clk->id), pckr); | 363 | at91_sys_write(AT91_PMC_PCKR(clk->id), pckr); |
335 | clk->rate_hz = actual; | 364 | clk->rate_hz = actual; |
336 | break; | 365 | break; |
@@ -377,11 +406,17 @@ static void __init init_programmable_clock(struct clk *clk) | |||
377 | { | 406 | { |
378 | struct clk *parent; | 407 | struct clk *parent; |
379 | u32 pckr; | 408 | u32 pckr; |
409 | unsigned int css_mask; | ||
410 | |||
411 | if (cpu_has_alt_prescaler()) | ||
412 | css_mask = AT91_PMC_ALT_PCKR_CSS; | ||
413 | else | ||
414 | css_mask = AT91_PMC_CSS; | ||
380 | 415 | ||
381 | pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); | 416 | pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); |
382 | parent = at91_css_to_clk(pckr & AT91_PMC_CSS); | 417 | parent = at91_css_to_clk(pckr & css_mask); |
383 | clk->parent = parent; | 418 | clk->parent = parent; |
384 | clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2)); | 419 | clk->rate_hz = parent->rate_hz / pmc_prescaler_divider(pckr); |
385 | } | 420 | } |
386 | 421 | ||
387 | #endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ | 422 | #endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ |
@@ -663,7 +698,7 @@ int __init at91_clock_init(unsigned long main_clock) | |||
663 | if (pll_overclock) | 698 | if (pll_overclock) |
664 | pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); | 699 | pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); |
665 | 700 | ||
666 | if (cpu_is_at91sam9g45()) { | 701 | if (cpu_has_plladiv2()) { |
667 | mckr = at91_sys_read(AT91_PMC_MCKR); | 702 | mckr = at91_sys_read(AT91_PMC_MCKR); |
668 | plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */ | 703 | plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */ |
669 | } | 704 | } |
@@ -685,6 +720,10 @@ int __init at91_clock_init(unsigned long main_clock) | |||
685 | * (obtain the USB High Speed 480 MHz when input is 12 MHz) | 720 | * (obtain the USB High Speed 480 MHz when input is 12 MHz) |
686 | */ | 721 | */ |
687 | utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; | 722 | utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; |
723 | |||
724 | /* UTMI bias and PLL are managed at the same time */ | ||
725 | if (cpu_has_upll()) | ||
726 | utmi_clk.pmc_mask |= AT91_PMC_BIASEN; | ||
688 | } | 727 | } |
689 | 728 | ||
690 | /* | 729 | /* |
@@ -703,7 +742,7 @@ int __init at91_clock_init(unsigned long main_clock) | |||
703 | mckr = at91_sys_read(AT91_PMC_MCKR); | 742 | mckr = at91_sys_read(AT91_PMC_MCKR); |
704 | mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS); | 743 | mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS); |
705 | freq = mck.parent->rate_hz; | 744 | freq = mck.parent->rate_hz; |
706 | freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */ | 745 | freq /= pmc_prescaler_divider(mckr); /* prescale */ |
707 | if (cpu_is_at91rm9200()) { | 746 | if (cpu_is_at91rm9200()) { |
708 | mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ | 747 | mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ |
709 | } else if (cpu_is_at91sam9g20()) { | 748 | } else if (cpu_is_at91sam9g20()) { |
@@ -711,13 +750,19 @@ int __init at91_clock_init(unsigned long main_clock) | |||
711 | freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ | 750 | freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ |
712 | if (mckr & AT91_PMC_PDIV) | 751 | if (mckr & AT91_PMC_PDIV) |
713 | freq /= 2; /* processor clock division */ | 752 | freq /= 2; /* processor clock division */ |
714 | } else if (cpu_is_at91sam9g45()) { | 753 | } else if (cpu_has_mdiv3()) { |
715 | mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ? | 754 | mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ? |
716 | freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ | 755 | freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ |
717 | } else { | 756 | } else { |
718 | mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ | 757 | mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ |
719 | } | 758 | } |
720 | 759 | ||
760 | if (cpu_has_alt_prescaler()) { | ||
761 | /* Programmable clocks can use MCK */ | ||
762 | mck.type |= CLK_TYPE_PRIMARY; | ||
763 | mck.id = 4; | ||
764 | } | ||
765 | |||
721 | /* Register the PMC's standard clocks */ | 766 | /* Register the PMC's standard clocks */ |
722 | for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) | 767 | for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) |
723 | at91_clk_add(standard_pmc_clocks[i]); | 768 | at91_clk_add(standard_pmc_clocks[i]); |