diff options
Diffstat (limited to 'arch/arm/mach-ux500')
-rw-r--r-- | arch/arm/mach-ux500/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-ux500/clock.c | 104 | ||||
-rw-r--r-- | arch/arm/mach-ux500/clock.h | 22 | ||||
-rw-r--r-- | arch/arm/mach-ux500/cpu.c | 6 |
4 files changed, 128 insertions, 7 deletions
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index c7bc4199e3a8..4556aea9c3c5 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile | |||
@@ -7,4 +7,5 @@ obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o | |||
7 | obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o | 7 | obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o |
8 | obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o | 8 | obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o |
9 | obj-$(CONFIG_MACH_U5500) += board-u5500.o | 9 | obj-$(CONFIG_MACH_U5500) += board-u5500.o |
10 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o | 10 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o |
11 | obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o | ||
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); | ||
diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h index e4f99b65026f..a05802501527 100644 --- a/arch/arm/mach-ux500/clock.h +++ b/arch/arm/mach-ux500/clock.h | |||
@@ -28,6 +28,9 @@ struct clkops { | |||
28 | * @ops: pointer to clkops struct used to control this clock | 28 | * @ops: pointer to clkops struct used to control this clock |
29 | * @name: name, for debugging | 29 | * @name: name, for debugging |
30 | * @enabled: refcount. positive if enabled, zero if disabled | 30 | * @enabled: refcount. positive if enabled, zero if disabled |
31 | * @get_rate: custom callback for getting the clock rate | ||
32 | * @data: custom per-clock data for example for the get_rate | ||
33 | * callback | ||
31 | * @rate: fixed rate for clocks which don't implement | 34 | * @rate: fixed rate for clocks which don't implement |
32 | * ops->getrate | 35 | * ops->getrate |
33 | * @prcmu_cg_off: address offset of the combined enable/disable register | 36 | * @prcmu_cg_off: address offset of the combined enable/disable register |
@@ -67,6 +70,8 @@ struct clk { | |||
67 | const struct clkops *ops; | 70 | const struct clkops *ops; |
68 | const char *name; | 71 | const char *name; |
69 | unsigned int enabled; | 72 | unsigned int enabled; |
73 | unsigned long (*get_rate)(struct clk *); | ||
74 | void *data; | ||
70 | 75 | ||
71 | unsigned long rate; | 76 | unsigned long rate; |
72 | struct list_head list; | 77 | struct list_head list; |
@@ -117,9 +122,26 @@ struct clk clk_##_name = { \ | |||
117 | .parent_periph = _kernclk \ | 122 | .parent_periph = _kernclk \ |
118 | } | 123 | } |
119 | 124 | ||
125 | #define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \ | ||
126 | struct clk clk_##_name = { \ | ||
127 | .name = #_name, \ | ||
128 | .ops = &clk_prcc_ops, \ | ||
129 | .cluster = _pclust, \ | ||
130 | .prcc_bus = _bus_en, \ | ||
131 | .prcc_kernel = _kernel_en, \ | ||
132 | .parent_cluster = &clk_per##_pclust##clk, \ | ||
133 | .parent_periph = _kernclk, \ | ||
134 | .get_rate = _callback, \ | ||
135 | .data = (void *) _data \ | ||
136 | } | ||
137 | |||
138 | |||
120 | #define CLK(_clk, _devname, _conname) \ | 139 | #define CLK(_clk, _devname, _conname) \ |
121 | { \ | 140 | { \ |
122 | .clk = &clk_##_clk, \ | 141 | .clk = &clk_##_clk, \ |
123 | .dev_id = _devname, \ | 142 | .dev_id = _devname, \ |
124 | .con_id = _conname, \ | 143 | .con_id = _conname, \ |
125 | } | 144 | } |
145 | |||
146 | int __init clk_db8500_ed_fixup(void); | ||
147 | int __init clk_init(void); | ||
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index d81ad023963c..e0fd747e447a 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c | |||
@@ -62,6 +62,12 @@ void __init ux500_init_irq(void) | |||
62 | { | 62 | { |
63 | gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29); | 63 | gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29); |
64 | gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE)); | 64 | gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE)); |
65 | |||
66 | /* | ||
67 | * Init clocks here so that they are available for system timer | ||
68 | * initialization. | ||
69 | */ | ||
70 | clk_init(); | ||
65 | } | 71 | } |
66 | 72 | ||
67 | #ifdef CONFIG_CACHE_L2X0 | 73 | #ifdef CONFIG_CACHE_L2X0 |