diff options
Diffstat (limited to 'arch/arm/mach-ux500/clock.c')
-rw-r--r-- | arch/arm/mach-ux500/clock.c | 104 |
1 files changed, 98 insertions, 6 deletions
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c index 6544855af2f1..fe84b9021c7a 100644 --- a/arch/arm/mach-ux500/clock.c +++ b/arch/arm/mach-ux500/clock.c | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #include <asm/clkdev.h> | 17 | #include <asm/clkdev.h> |
18 | 18 | ||
19 | #include <plat/mtu.h> | ||
19 | #include <mach/hardware.h> | 20 | #include <mach/hardware.h> |
20 | #include "clock.h" | 21 | #include "clock.h" |
21 | 22 | ||
@@ -59,6 +60,9 @@ | |||
59 | #define PRCM_DMACLK_MGT 0x074 | 60 | #define PRCM_DMACLK_MGT 0x074 |
60 | #define PRCM_B2R2CLK_MGT 0x078 | 61 | #define PRCM_B2R2CLK_MGT 0x078 |
61 | #define PRCM_TVCLK_MGT 0x07C | 62 | #define PRCM_TVCLK_MGT 0x07C |
63 | #define PRCM_TCR 0x1C8 | ||
64 | #define PRCM_TCR_STOPPED (1 << 16) | ||
65 | #define PRCM_TCR_DOZE_MODE (1 << 17) | ||
62 | #define PRCM_UNIPROCLK_MGT 0x278 | 66 | #define PRCM_UNIPROCLK_MGT 0x278 |
63 | #define PRCM_SSPCLK_MGT 0x280 | 67 | #define PRCM_SSPCLK_MGT 0x280 |
64 | #define PRCM_RNGCLK_MGT 0x284 | 68 | #define PRCM_RNGCLK_MGT 0x284 |
@@ -120,10 +124,95 @@ void clk_disable(struct clk *clk) | |||
120 | } | 124 | } |
121 | EXPORT_SYMBOL(clk_disable); | 125 | EXPORT_SYMBOL(clk_disable); |
122 | 126 | ||
127 | /* | ||
128 | * The MTU has a separate, rather complex muxing setup | ||
129 | * with alternative parents (peripheral cluster or | ||
130 | * ULP or fixed 32768 Hz) depending on settings | ||
131 | */ | ||
132 | static unsigned long clk_mtu_get_rate(struct clk *clk) | ||
133 | { | ||
134 | void __iomem *addr = __io_address(U8500_PRCMU_BASE) | ||
135 | + PRCM_TCR; | ||
136 | u32 tcr = readl(addr); | ||
137 | int mtu = (int) clk->data; | ||
138 | /* | ||
139 | * One of these is selected eventually | ||
140 | * TODO: Replace the constant with a reference | ||
141 | * to the ULP source once this is modeled. | ||
142 | */ | ||
143 | unsigned long clk32k = 32768; | ||
144 | unsigned long mturate; | ||
145 | unsigned long retclk; | ||
146 | |||
147 | /* Get the rate from the parent as a default */ | ||
148 | if (clk->parent_periph) | ||
149 | mturate = clk_get_rate(clk->parent_periph); | ||
150 | else if (clk->parent_cluster) | ||
151 | mturate = clk_get_rate(clk->parent_cluster); | ||
152 | else | ||
153 | /* We need to be connected SOMEWHERE */ | ||
154 | BUG(); | ||
155 | |||
156 | /* | ||
157 | * Are we in doze mode? | ||
158 | * In this mode the parent peripheral or the fixed 32768 Hz | ||
159 | * clock is fed into the block. | ||
160 | */ | ||
161 | if (!(tcr & PRCM_TCR_DOZE_MODE)) { | ||
162 | /* | ||
163 | * Here we're using the clock input from the APE ULP | ||
164 | * clock domain. But first: are the timers stopped? | ||
165 | */ | ||
166 | if (tcr & PRCM_TCR_STOPPED) { | ||
167 | clk32k = 0; | ||
168 | mturate = 0; | ||
169 | } else { | ||
170 | /* Else default mode: 0 and 2.4 MHz */ | ||
171 | clk32k = 0; | ||
172 | if (cpu_is_u5500()) | ||
173 | /* DB5500 divides by 8 */ | ||
174 | mturate /= 8; | ||
175 | else if (cpu_is_u8500ed()) { | ||
176 | /* | ||
177 | * This clocking setting must not be used | ||
178 | * in the ED chip, it is simply not | ||
179 | * connected anywhere! | ||
180 | */ | ||
181 | mturate = 0; | ||
182 | BUG(); | ||
183 | } else | ||
184 | /* | ||
185 | * In this mode the ulp38m4 clock is divided | ||
186 | * by a factor 16, on the DB8500 typically | ||
187 | * 38400000 / 16 ~ 2.4 MHz. | ||
188 | * TODO: Replace the constant with a reference | ||
189 | * to the ULP source once this is modeled. | ||
190 | */ | ||
191 | mturate = 38400000 / 16; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | /* Return the clock selected for this MTU */ | ||
196 | if (tcr & (1 << mtu)) | ||
197 | retclk = clk32k; | ||
198 | else | ||
199 | retclk = mturate; | ||
200 | |||
201 | pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk); | ||
202 | return retclk; | ||
203 | } | ||
204 | |||
123 | unsigned long clk_get_rate(struct clk *clk) | 205 | unsigned long clk_get_rate(struct clk *clk) |
124 | { | 206 | { |
125 | unsigned long rate; | 207 | unsigned long rate; |
126 | 208 | ||
209 | /* | ||
210 | * If there is a custom getrate callback for this clock, | ||
211 | * it will take precedence. | ||
212 | */ | ||
213 | if (clk->get_rate) | ||
214 | return clk->get_rate(clk); | ||
215 | |||
127 | if (clk->ops && clk->ops->get_rate) | 216 | if (clk->ops && clk->ops->get_rate) |
128 | return clk->ops->get_rate(clk); | 217 | return clk->ops->get_rate(clk); |
129 | 218 | ||
@@ -341,8 +430,9 @@ static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL); | |||
341 | 430 | ||
342 | /* Peripheral Cluster #6 */ | 431 | /* Peripheral Cluster #6 */ |
343 | 432 | ||
344 | static DEFINE_PRCC_CLK(6, mtu1_v1, 8, -1, NULL); | 433 | /* MTU ID in data */ |
345 | static DEFINE_PRCC_CLK(6, mtu0_v1, 7, -1, NULL); | 434 | static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1); |
435 | static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0); | ||
346 | static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); | 436 | static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL); |
347 | static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); | 437 | static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL); |
348 | static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); | 438 | static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL); |
@@ -357,8 +447,9 @@ static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk); | |||
357 | /* Peripheral Cluster #7 */ | 447 | /* Peripheral Cluster #7 */ |
358 | 448 | ||
359 | static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); | 449 | static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL); |
360 | static DEFINE_PRCC_CLK(7, mtu1_ed, 3, -1, NULL); | 450 | /* MTU ID in data */ |
361 | static DEFINE_PRCC_CLK(7, mtu0_ed, 2, -1, NULL); | 451 | static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1); |
452 | static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0); | ||
362 | static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); | 453 | static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); |
363 | static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); | 454 | static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); |
364 | 455 | ||
@@ -503,15 +594,17 @@ static struct clk_lookup u8500_v1_clks[] = { | |||
503 | CLK(uiccclk, "uicc", NULL), | 594 | CLK(uiccclk, "uicc", NULL), |
504 | }; | 595 | }; |
505 | 596 | ||
506 | static int __init clk_init(void) | 597 | int __init clk_init(void) |
507 | { | 598 | { |
508 | if (cpu_is_u8500ed()) { | 599 | if (cpu_is_u8500ed()) { |
509 | clk_prcmu_ops.enable = clk_prcmu_ed_enable; | 600 | clk_prcmu_ops.enable = clk_prcmu_ed_enable; |
510 | clk_prcmu_ops.disable = clk_prcmu_ed_disable; | 601 | clk_prcmu_ops.disable = clk_prcmu_ed_disable; |
602 | clk_per6clk.rate = 100000000; | ||
511 | } else if (cpu_is_u5500()) { | 603 | } else if (cpu_is_u5500()) { |
512 | /* Clock tree for U5500 not implemented yet */ | 604 | /* Clock tree for U5500 not implemented yet */ |
513 | clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; | 605 | clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; |
514 | clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; | 606 | clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; |
607 | clk_per6clk.rate = 26000000; | ||
515 | } | 608 | } |
516 | 609 | ||
517 | clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); | 610 | clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); |
@@ -522,4 +615,3 @@ static int __init clk_init(void) | |||
522 | 615 | ||
523 | return 0; | 616 | return 0; |
524 | } | 617 | } |
525 | arch_initcall(clk_init); | ||