diff options
author | Ludovic Desroches <ludovic.desroches@atmel.com> | 2013-03-22 09:24:12 -0400 |
---|---|---|
committer | Nicolas Ferre <nicolas.ferre@atmel.com> | 2013-03-26 07:18:04 -0400 |
commit | 8f4b47949f61eb7f68f458d56a661a7842e67c44 (patch) | |
tree | eebf2f59a252a6dc8dc200e23cd81521d936b386 /arch/arm/mach-at91/clock.c | |
parent | 8f0cdcc5700d9f9508385f41f6047fca82334eba (diff) |
ARM: at91: introduce SAMA5 support
This patch introduces the SAMA5 support and a generic board file for SAMA5
devices. It also updates the PMC driver to manage clock division which is a
requirement since some peripherals can't work at the bus frequency on SAMA5.
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Diffstat (limited to 'arch/arm/mach-at91/clock.c')
-rw-r--r-- | arch/arm/mach-at91/clock.c | 109 |
1 files changed, 84 insertions, 25 deletions
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 33361505c0cd..da841885d01c 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c | |||
@@ -54,7 +54,10 @@ EXPORT_SYMBOL_GPL(at91_pmc_base); | |||
54 | */ | 54 | */ |
55 | #define cpu_has_utmi() ( cpu_is_at91sam9rl() \ | 55 | #define cpu_has_utmi() ( cpu_is_at91sam9rl() \ |
56 | || cpu_is_at91sam9g45() \ | 56 | || cpu_is_at91sam9g45() \ |
57 | || cpu_is_at91sam9x5()) | 57 | || cpu_is_at91sam9x5() \ |
58 | || cpu_is_sama5d3()) | ||
59 | |||
60 | #define cpu_has_1056M_plla() (cpu_is_sama5d3()) | ||
58 | 61 | ||
59 | #define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ | 62 | #define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ |
60 | || cpu_is_at91sam9g45() \ | 63 | || cpu_is_at91sam9g45() \ |
@@ -75,7 +78,8 @@ EXPORT_SYMBOL_GPL(at91_pmc_base); | |||
75 | || cpu_is_at91sam9n12())) | 78 | || cpu_is_at91sam9n12())) |
76 | 79 | ||
77 | #define cpu_has_upll() (cpu_is_at91sam9g45() \ | 80 | #define cpu_has_upll() (cpu_is_at91sam9g45() \ |
78 | || cpu_is_at91sam9x5()) | 81 | || cpu_is_at91sam9x5() \ |
82 | || cpu_is_sama5d3()) | ||
79 | 83 | ||
80 | /* USB host HS & FS */ | 84 | /* USB host HS & FS */ |
81 | #define cpu_has_uhp() (!cpu_is_at91sam9rl()) | 85 | #define cpu_has_uhp() (!cpu_is_at91sam9rl()) |
@@ -83,18 +87,22 @@ EXPORT_SYMBOL_GPL(at91_pmc_base); | |||
83 | /* USB device FS only */ | 87 | /* USB device FS only */ |
84 | #define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \ | 88 | #define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \ |
85 | || cpu_is_at91sam9g45() \ | 89 | || cpu_is_at91sam9g45() \ |
86 | || cpu_is_at91sam9x5())) | 90 | || cpu_is_at91sam9x5() \ |
91 | || cpu_is_sama5d3())) | ||
87 | 92 | ||
88 | #define cpu_has_plladiv2() (cpu_is_at91sam9g45() \ | 93 | #define cpu_has_plladiv2() (cpu_is_at91sam9g45() \ |
89 | || cpu_is_at91sam9x5() \ | 94 | || cpu_is_at91sam9x5() \ |
90 | || cpu_is_at91sam9n12()) | 95 | || cpu_is_at91sam9n12() \ |
96 | || cpu_is_sama5d3()) | ||
91 | 97 | ||
92 | #define cpu_has_mdiv3() (cpu_is_at91sam9g45() \ | 98 | #define cpu_has_mdiv3() (cpu_is_at91sam9g45() \ |
93 | || cpu_is_at91sam9x5() \ | 99 | || cpu_is_at91sam9x5() \ |
94 | || cpu_is_at91sam9n12()) | 100 | || cpu_is_at91sam9n12() \ |
101 | || cpu_is_sama5d3()) | ||
95 | 102 | ||
96 | #define cpu_has_alt_prescaler() (cpu_is_at91sam9x5() \ | 103 | #define cpu_has_alt_prescaler() (cpu_is_at91sam9x5() \ |
97 | || cpu_is_at91sam9n12()) | 104 | || cpu_is_at91sam9n12() \ |
105 | || cpu_is_sama5d3()) | ||
98 | 106 | ||
99 | static LIST_HEAD(clocks); | 107 | static LIST_HEAD(clocks); |
100 | static DEFINE_SPINLOCK(clk_lock); | 108 | static DEFINE_SPINLOCK(clk_lock); |
@@ -210,10 +218,26 @@ struct clk mck = { | |||
210 | 218 | ||
211 | static void pmc_periph_mode(struct clk *clk, int is_on) | 219 | static void pmc_periph_mode(struct clk *clk, int is_on) |
212 | { | 220 | { |
213 | if (is_on) | 221 | u32 regval = 0; |
214 | at91_pmc_write(AT91_PMC_PCER, clk->pmc_mask); | 222 | |
215 | else | 223 | /* |
216 | at91_pmc_write(AT91_PMC_PCDR, clk->pmc_mask); | 224 | * With sama5d3 devices, we are managing clock division so we have to |
225 | * use the Peripheral Control Register introduced from at91sam9x5 | ||
226 | * devices. | ||
227 | */ | ||
228 | if (cpu_is_sama5d3()) { | ||
229 | regval |= AT91_PMC_PCR_CMD; /* write command */ | ||
230 | regval |= clk->pid & AT91_PMC_PCR_PID; /* peripheral selection */ | ||
231 | regval |= AT91_PMC_PCR_DIV(clk->div); | ||
232 | if (is_on) | ||
233 | regval |= AT91_PMC_PCR_EN; /* enable clock */ | ||
234 | at91_pmc_write(AT91_PMC_PCR, regval); | ||
235 | } else { | ||
236 | if (is_on) | ||
237 | at91_pmc_write(AT91_PMC_PCER, clk->pmc_mask); | ||
238 | else | ||
239 | at91_pmc_write(AT91_PMC_PCDR, clk->pmc_mask); | ||
240 | } | ||
217 | } | 241 | } |
218 | 242 | ||
219 | static struct clk __init *at91_css_to_clk(unsigned long css) | 243 | static struct clk __init *at91_css_to_clk(unsigned long css) |
@@ -443,14 +467,18 @@ static void __init init_programmable_clock(struct clk *clk) | |||
443 | 467 | ||
444 | static int at91_clk_show(struct seq_file *s, void *unused) | 468 | static int at91_clk_show(struct seq_file *s, void *unused) |
445 | { | 469 | { |
446 | u32 scsr, pcsr, uckr = 0, sr; | 470 | u32 scsr, pcsr, pcsr1 = 0, uckr = 0, sr; |
447 | struct clk *clk; | 471 | struct clk *clk; |
448 | 472 | ||
449 | scsr = at91_pmc_read(AT91_PMC_SCSR); | 473 | scsr = at91_pmc_read(AT91_PMC_SCSR); |
450 | pcsr = at91_pmc_read(AT91_PMC_PCSR); | 474 | pcsr = at91_pmc_read(AT91_PMC_PCSR); |
475 | if (cpu_is_sama5d3()) | ||
476 | pcsr1 = at91_pmc_read(AT91_PMC_PCSR1); | ||
451 | sr = at91_pmc_read(AT91_PMC_SR); | 477 | sr = at91_pmc_read(AT91_PMC_SR); |
452 | seq_printf(s, "SCSR = %8x\n", scsr); | 478 | seq_printf(s, "SCSR = %8x\n", scsr); |
453 | seq_printf(s, "PCSR = %8x\n", pcsr); | 479 | seq_printf(s, "PCSR = %8x\n", pcsr); |
480 | if (cpu_is_sama5d3()) | ||
481 | seq_printf(s, "PCSR1 = %8x\n", pcsr1); | ||
454 | seq_printf(s, "MOR = %8x\n", at91_pmc_read(AT91_CKGR_MOR)); | 482 | seq_printf(s, "MOR = %8x\n", at91_pmc_read(AT91_CKGR_MOR)); |
455 | seq_printf(s, "MCFR = %8x\n", at91_pmc_read(AT91_CKGR_MCFR)); | 483 | seq_printf(s, "MCFR = %8x\n", at91_pmc_read(AT91_CKGR_MCFR)); |
456 | seq_printf(s, "PLLA = %8x\n", at91_pmc_read(AT91_CKGR_PLLAR)); | 484 | seq_printf(s, "PLLA = %8x\n", at91_pmc_read(AT91_CKGR_PLLAR)); |
@@ -470,20 +498,30 @@ static int at91_clk_show(struct seq_file *s, void *unused) | |||
470 | list_for_each_entry(clk, &clocks, node) { | 498 | list_for_each_entry(clk, &clocks, node) { |
471 | char *state; | 499 | char *state; |
472 | 500 | ||
473 | if (clk->mode == pmc_sys_mode) | 501 | if (clk->mode == pmc_sys_mode) { |
474 | state = (scsr & clk->pmc_mask) ? "on" : "off"; | 502 | state = (scsr & clk->pmc_mask) ? "on" : "off"; |
475 | else if (clk->mode == pmc_periph_mode) | 503 | } else if (clk->mode == pmc_periph_mode) { |
476 | state = (pcsr & clk->pmc_mask) ? "on" : "off"; | 504 | if (cpu_is_sama5d3()) { |
477 | else if (clk->mode == pmc_uckr_mode) | 505 | u32 pmc_mask = 1 << (clk->pid % 32); |
506 | |||
507 | if (clk->pid > 31) | ||
508 | state = (pcsr1 & pmc_mask) ? "on" : "off"; | ||
509 | else | ||
510 | state = (pcsr & pmc_mask) ? "on" : "off"; | ||
511 | } else { | ||
512 | state = (pcsr & clk->pmc_mask) ? "on" : "off"; | ||
513 | } | ||
514 | } else if (clk->mode == pmc_uckr_mode) { | ||
478 | state = (uckr & clk->pmc_mask) ? "on" : "off"; | 515 | state = (uckr & clk->pmc_mask) ? "on" : "off"; |
479 | else if (clk->pmc_mask) | 516 | } else if (clk->pmc_mask) { |
480 | state = (sr & clk->pmc_mask) ? "on" : "off"; | 517 | state = (sr & clk->pmc_mask) ? "on" : "off"; |
481 | else if (clk == &clk32k || clk == &main_clk) | 518 | } else if (clk == &clk32k || clk == &main_clk) { |
482 | state = "on"; | 519 | state = "on"; |
483 | else | 520 | } else { |
484 | state = ""; | 521 | state = ""; |
522 | } | ||
485 | 523 | ||
486 | seq_printf(s, "%-10s users=%2d %-3s %9ld Hz %s\n", | 524 | seq_printf(s, "%-10s users=%2d %-3s %9lu Hz %s\n", |
487 | clk->name, clk->users, state, clk_get_rate(clk), | 525 | clk->name, clk->users, state, clk_get_rate(clk), |
488 | clk->parent ? clk->parent->name : ""); | 526 | clk->parent ? clk->parent->name : ""); |
489 | } | 527 | } |
@@ -530,6 +568,9 @@ int __init clk_register(struct clk *clk) | |||
530 | if (clk_is_peripheral(clk)) { | 568 | if (clk_is_peripheral(clk)) { |
531 | if (!clk->parent) | 569 | if (!clk->parent) |
532 | clk->parent = &mck; | 570 | clk->parent = &mck; |
571 | if (cpu_is_sama5d3()) | ||
572 | clk->rate_hz = DIV_ROUND_UP(clk->parent->rate_hz, | ||
573 | 1 << clk->div); | ||
533 | clk->mode = pmc_periph_mode; | 574 | clk->mode = pmc_periph_mode; |
534 | } | 575 | } |
535 | else if (clk_is_sys(clk)) { | 576 | else if (clk_is_sys(clk)) { |
@@ -555,7 +596,11 @@ static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg) | |||
555 | unsigned mul, div; | 596 | unsigned mul, div; |
556 | 597 | ||
557 | div = reg & 0xff; | 598 | div = reg & 0xff; |
558 | mul = (reg >> 16) & 0x7ff; | 599 | if (cpu_is_sama5d3()) |
600 | mul = AT91_PMC3_MUL_GET(reg); | ||
601 | else | ||
602 | mul = AT91_PMC_MUL_GET(reg); | ||
603 | |||
559 | if (div && mul) { | 604 | if (div && mul) { |
560 | freq /= div; | 605 | freq /= div; |
561 | freq *= mul + 1; | 606 | freq *= mul + 1; |
@@ -706,12 +751,15 @@ static int __init at91_pmc_init(unsigned long main_clock) | |||
706 | 751 | ||
707 | /* report if PLLA is more than mildly overclocked */ | 752 | /* report if PLLA is more than mildly overclocked */ |
708 | plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_pmc_read(AT91_CKGR_PLLAR)); | 753 | plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_pmc_read(AT91_CKGR_PLLAR)); |
709 | if (cpu_has_300M_plla()) { | 754 | if (cpu_has_1056M_plla()) { |
710 | if (plla.rate_hz > 300000000) | 755 | if (plla.rate_hz > 1056000000) |
711 | pll_overclock = true; | 756 | pll_overclock = true; |
712 | } else if (cpu_has_800M_plla()) { | 757 | } else if (cpu_has_800M_plla()) { |
713 | if (plla.rate_hz > 800000000) | 758 | if (plla.rate_hz > 800000000) |
714 | pll_overclock = true; | 759 | pll_overclock = true; |
760 | } else if (cpu_has_300M_plla()) { | ||
761 | if (plla.rate_hz > 300000000) | ||
762 | pll_overclock = true; | ||
715 | } else if (cpu_has_240M_plla()) { | 763 | } else if (cpu_has_240M_plla()) { |
716 | if (plla.rate_hz > 240000000) | 764 | if (plla.rate_hz > 240000000) |
717 | pll_overclock = true; | 765 | pll_overclock = true; |
@@ -872,6 +920,7 @@ int __init at91_clock_init(unsigned long main_clock) | |||
872 | static int __init at91_clock_reset(void) | 920 | static int __init at91_clock_reset(void) |
873 | { | 921 | { |
874 | unsigned long pcdr = 0; | 922 | unsigned long pcdr = 0; |
923 | unsigned long pcdr1 = 0; | ||
875 | unsigned long scdr = 0; | 924 | unsigned long scdr = 0; |
876 | struct clk *clk; | 925 | struct clk *clk; |
877 | 926 | ||
@@ -879,8 +928,17 @@ static int __init at91_clock_reset(void) | |||
879 | if (clk->users > 0) | 928 | if (clk->users > 0) |
880 | continue; | 929 | continue; |
881 | 930 | ||
882 | if (clk->mode == pmc_periph_mode) | 931 | if (clk->mode == pmc_periph_mode) { |
883 | pcdr |= clk->pmc_mask; | 932 | if (cpu_is_sama5d3()) { |
933 | u32 pmc_mask = 1 << (clk->pid % 32); | ||
934 | |||
935 | if (clk->pid > 31) | ||
936 | pcdr1 |= pmc_mask; | ||
937 | else | ||
938 | pcdr |= pmc_mask; | ||
939 | } else | ||
940 | pcdr |= clk->pmc_mask; | ||
941 | } | ||
884 | 942 | ||
885 | if (clk->mode == pmc_sys_mode) | 943 | if (clk->mode == pmc_sys_mode) |
886 | scdr |= clk->pmc_mask; | 944 | scdr |= clk->pmc_mask; |
@@ -888,8 +946,9 @@ static int __init at91_clock_reset(void) | |||
888 | pr_debug("Clocks: disable unused %s\n", clk->name); | 946 | pr_debug("Clocks: disable unused %s\n", clk->name); |
889 | } | 947 | } |
890 | 948 | ||
891 | at91_pmc_write(AT91_PMC_PCDR, pcdr); | ||
892 | at91_pmc_write(AT91_PMC_SCDR, scdr); | 949 | at91_pmc_write(AT91_PMC_SCDR, scdr); |
950 | if (cpu_is_sama5d3()) | ||
951 | at91_pmc_write(AT91_PMC_PCDR1, pcdr1); | ||
893 | 952 | ||
894 | return 0; | 953 | return 0; |
895 | } | 954 | } |