]>
Commit | Line | Data |
---|---|---|
aa44ef4d | 1 | /* |
c15def1c | 2 | * Copyright (C) 2008-2009 ST-Ericsson SA |
aa44ef4d SK |
3 | * |
4 | * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2, as | |
8 | * published by the Free Software Foundation. | |
9 | * | |
10 | */ | |
11 | #include <linux/types.h> | |
12 | #include <linux/init.h> | |
13 | #include <linux/device.h> | |
14 | #include <linux/amba/bus.h> | |
aa90eb9d | 15 | #include <linux/interrupt.h> |
aa44ef4d SK |
16 | #include <linux/irq.h> |
17 | #include <linux/platform_device.h> | |
cc2c1334 | 18 | #include <linux/io.h> |
3a8e39c9 | 19 | #include <linux/mfd/abx500/ab8500.h> |
661c6af0 | 20 | #include <linux/mfd/dbx500-prcmu.h> |
fa86a764 LJ |
21 | #include <linux/of.h> |
22 | #include <linux/of_platform.h> | |
23 | #include <linux/regulator/machine.h> | |
7cb15e10 | 24 | #include <linux/platform_data/pinctrl-nomadik.h> |
4040d10a | 25 | #include <linux/random.h> |
aa44ef4d | 26 | |
5caecb44 | 27 | #include <asm/pmu.h> |
aa44ef4d | 28 | #include <asm/mach/map.h> |
fa86a764 | 29 | #include <asm/mach/arch.h> |
b8edf848 | 30 | |
aa44ef4d | 31 | #include <mach/hardware.h> |
cc2c1334 | 32 | #include <mach/setup.h> |
5b1f7ddf | 33 | #include <mach/devices.h> |
eda413c2 | 34 | #include <mach/db8500-regs.h> |
c3b9d1db | 35 | #include <mach/irqs.h> |
94bdc0e2 | 36 | |
fbf1eadf | 37 | #include "devices-db8500.h" |
6f3f3c3f | 38 | #include "ste-dma40-db8500.h" |
7a4f2609 | 39 | |
fa86a764 | 40 | #include "board-mop500.h" |
7a4f2609 | 41 | #include "id.h" |
fbf1eadf | 42 | |
aa44ef4d | 43 | /* minimum static i/o mapping required to boot U8500 platforms */ |
abf12d71 | 44 | static struct map_desc u8500_uart_io_desc[] __initdata = { |
92389ca8 RV |
45 | __IO_DEV_DESC(U8500_UART0_BASE, SZ_4K), |
46 | __IO_DEV_DESC(U8500_UART2_BASE, SZ_4K), | |
abf12d71 | 47 | }; |
bc71c096 LW |
48 | /* U8500 and U9540 common io_desc */ |
49 | static struct map_desc u8500_common_io_desc[] __initdata = { | |
215e83d9 LW |
50 | /* SCU base also covers GIC CPU BASE and TWD with its 4K page */ |
51 | __IO_DEV_DESC(U8500_SCU_BASE, SZ_4K), | |
92389ca8 RV |
52 | __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K), |
53 | __IO_DEV_DESC(U8500_L2CC_BASE, SZ_4K), | |
92389ca8 | 54 | __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), |
92389ca8 RV |
55 | __IO_DEV_DESC(U8500_BACKUPRAM0_BASE, SZ_8K), |
56 | ||
57 | __IO_DEV_DESC(U8500_CLKRST1_BASE, SZ_4K), | |
58 | __IO_DEV_DESC(U8500_CLKRST2_BASE, SZ_4K), | |
59 | __IO_DEV_DESC(U8500_CLKRST3_BASE, SZ_4K), | |
60 | __IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K), | |
61 | __IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K), | |
62 | ||
c9c09572 | 63 | __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K), |
94bdc0e2 RV |
64 | __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K), |
65 | __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K), | |
66 | __IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K), | |
ee9581d7 MJ |
67 | }; |
68 | ||
69 | /* U8500 IO map specific description */ | |
70 | static struct map_desc u8500_io_desc[] __initdata = { | |
71 | __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), | |
fcbd458e | 72 | __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K), |
ee9581d7 MJ |
73 | |
74 | }; | |
75 | ||
76 | /* U9540 IO map specific description */ | |
77 | static struct map_desc u9540_io_desc[] __initdata = { | |
78 | __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K + SZ_8K), | |
79 | __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K + SZ_8K), | |
75a36ee0 RV |
80 | }; |
81 | ||
abf12d71 | 82 | void __init u8500_map_io(void) |
f946738c | 83 | { |
abf12d71 RV |
84 | /* |
85 | * Map the UARTs early so that the DEBUG_LL stuff continues to work. | |
86 | */ | |
87 | iotable_init(u8500_uart_io_desc, ARRAY_SIZE(u8500_uart_io_desc)); | |
f946738c | 88 | |
abf12d71 | 89 | ux500_map_io(); |
f946738c | 90 | |
bc71c096 | 91 | iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc)); |
75a36ee0 | 92 | |
e1bbb55d | 93 | if (cpu_is_ux540_family()) |
ee9581d7 MJ |
94 | iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc)); |
95 | else | |
96 | iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); | |
75a36ee0 | 97 | |
11871890 | 98 | _PRCMU_BASE = __io_address(U8500_PRCMU_BASE); |
aa44ef4d SK |
99 | } |
100 | ||
aa90eb9d RV |
101 | static struct resource db8500_pmu_resources[] = { |
102 | [0] = { | |
103 | .start = IRQ_DB8500_PMU, | |
104 | .end = IRQ_DB8500_PMU, | |
105 | .flags = IORESOURCE_IRQ, | |
106 | }, | |
107 | }; | |
108 | ||
109 | /* | |
110 | * The PMU IRQ lines of two cores are wired together into a single interrupt. | |
111 | * Bounce the interrupt to the other core if it's not ours. | |
112 | */ | |
113 | static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler) | |
114 | { | |
115 | irqreturn_t ret = handler(irq, dev); | |
116 | int other = !smp_processor_id(); | |
117 | ||
118 | if (ret == IRQ_NONE && cpu_online(other)) | |
119 | irq_set_affinity(irq, cpumask_of(other)); | |
120 | ||
121 | /* | |
122 | * We should be able to get away with the amount of IRQ_NONEs we give, | |
123 | * while still having the spurious IRQ detection code kick in if the | |
124 | * interrupt really starts hitting spuriously. | |
125 | */ | |
126 | return ret; | |
127 | } | |
128 | ||
3a8e39c9 | 129 | struct arm_pmu_platdata db8500_pmu_platdata = { |
aa90eb9d RV |
130 | .handle_irq = db8500_pmu_handler, |
131 | }; | |
132 | ||
133 | static struct platform_device db8500_pmu_device = { | |
134 | .name = "arm-pmu", | |
df3d17e0 | 135 | .id = -1, |
aa90eb9d RV |
136 | .num_resources = ARRAY_SIZE(db8500_pmu_resources), |
137 | .resource = db8500_pmu_resources, | |
138 | .dev.platform_data = &db8500_pmu_platdata, | |
139 | }; | |
140 | ||
141 | static struct platform_device *platform_devs[] __initdata = { | |
142 | &u8500_dma40_device, | |
143 | &db8500_pmu_device, | |
144 | }; | |
145 | ||
01afdd13 RV |
146 | static resource_size_t __initdata db8500_gpio_base[] = { |
147 | U8500_GPIOBANK0_BASE, | |
148 | U8500_GPIOBANK1_BASE, | |
149 | U8500_GPIOBANK2_BASE, | |
150 | U8500_GPIOBANK3_BASE, | |
151 | U8500_GPIOBANK4_BASE, | |
152 | U8500_GPIOBANK5_BASE, | |
153 | U8500_GPIOBANK6_BASE, | |
154 | U8500_GPIOBANK7_BASE, | |
155 | U8500_GPIOBANK8_BASE, | |
156 | }; | |
157 | ||
18403424 | 158 | static void __init db8500_add_gpios(struct device *parent) |
01afdd13 RV |
159 | { |
160 | struct nmk_gpio_platform_data pdata = { | |
c15def1c | 161 | .supports_sleepmode = true, |
01afdd13 RV |
162 | }; |
163 | ||
18403424 | 164 | dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base), |
01afdd13 | 165 | IRQ_DB8500_GPIO0, &pdata); |
f4828336 | 166 | dbx500_add_pinctrl(parent, "pinctrl-db8500", U8500_PRCMU_BASE); |
01afdd13 RV |
167 | } |
168 | ||
6f3f3c3f MYK |
169 | static int usb_db8500_rx_dma_cfg[] = { |
170 | DB8500_DMA_DEV38_USB_OTG_IEP_1_9, | |
171 | DB8500_DMA_DEV37_USB_OTG_IEP_2_10, | |
172 | DB8500_DMA_DEV36_USB_OTG_IEP_3_11, | |
173 | DB8500_DMA_DEV19_USB_OTG_IEP_4_12, | |
174 | DB8500_DMA_DEV18_USB_OTG_IEP_5_13, | |
175 | DB8500_DMA_DEV17_USB_OTG_IEP_6_14, | |
176 | DB8500_DMA_DEV16_USB_OTG_IEP_7_15, | |
177 | DB8500_DMA_DEV39_USB_OTG_IEP_8 | |
178 | }; | |
179 | ||
180 | static int usb_db8500_tx_dma_cfg[] = { | |
181 | DB8500_DMA_DEV38_USB_OTG_OEP_1_9, | |
182 | DB8500_DMA_DEV37_USB_OTG_OEP_2_10, | |
183 | DB8500_DMA_DEV36_USB_OTG_OEP_3_11, | |
184 | DB8500_DMA_DEV19_USB_OTG_OEP_4_12, | |
185 | DB8500_DMA_DEV18_USB_OTG_OEP_5_13, | |
186 | DB8500_DMA_DEV17_USB_OTG_OEP_6_14, | |
187 | DB8500_DMA_DEV16_USB_OTG_OEP_7_15, | |
188 | DB8500_DMA_DEV39_USB_OTG_OEP_8 | |
189 | }; | |
190 | ||
eda413c2 LJ |
191 | static const char *db8500_read_soc_id(void) |
192 | { | |
193 | void __iomem *uid = __io_address(U8500_BB_UID_BASE); | |
194 | ||
4040d10a LW |
195 | /* Throw these device-specific numbers into the entropy pool */ |
196 | add_device_randomness(uid, 0x14); | |
eda413c2 LJ |
197 | return kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x", |
198 | readl((u32 *)uid+1), | |
199 | readl((u32 *)uid+1), readl((u32 *)uid+2), | |
200 | readl((u32 *)uid+3), readl((u32 *)uid+4)); | |
201 | } | |
202 | ||
203 | static struct device * __init db8500_soc_device_init(void) | |
204 | { | |
205 | const char *soc_id = db8500_read_soc_id(); | |
206 | ||
207 | return ux500_soc_device_init(soc_id); | |
208 | } | |
209 | ||
aa44ef4d SK |
210 | /* |
211 | * This function is called from the board init | |
212 | */ | |
3a8e39c9 | 213 | struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500) |
aa44ef4d | 214 | { |
eda413c2 | 215 | struct device *parent; |
b024a0c8 | 216 | int i; |
eda413c2 LJ |
217 | |
218 | parent = db8500_soc_device_init(); | |
219 | ||
220 | db8500_add_rtc(parent); | |
221 | db8500_add_gpios(parent); | |
222 | db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); | |
fbf1eadf | 223 | |
f65c1982 LJ |
224 | for (i = 0; i < ARRAY_SIZE(platform_devs); i++) |
225 | platform_devs[i]->dev.parent = parent; | |
226 | ||
3a8e39c9 LJ |
227 | db8500_prcmu_device.dev.platform_data = ab8500; |
228 | ||
f65c1982 LJ |
229 | platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); |
230 | ||
231 | return parent; | |
232 | } | |
233 | ||
fa86a764 LJ |
234 | #ifdef CONFIG_MACH_UX500_DT |
235 | ||
f65c1982 | 236 | /* TODO: Once all pieces are DT:ed, remove completely. */ |
fa86a764 | 237 | static struct device * __init u8500_of_init_devices(void) |
f65c1982 | 238 | { |
fa86a764 | 239 | struct device *parent = db8500_soc_device_init(); |
f65c1982 | 240 | |
f65c1982 LJ |
241 | db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); |
242 | ||
38cd8c5d | 243 | u8500_dma40_device.dev.parent = parent; |
b024a0c8 | 244 | |
08d05026 LJ |
245 | /* |
246 | * Devices to be DT:ed: | |
247 | * u8500_dma40_device = todo | |
da384870 | 248 | * db8500_pmu_device = done |
dee42ebe | 249 | * db8500_prcmu_device = done |
08d05026 | 250 | */ |
38cd8c5d | 251 | platform_device_register(&u8500_dma40_device); |
aa44ef4d | 252 | |
eda413c2 | 253 | return parent; |
aa44ef4d | 254 | } |
fa86a764 LJ |
255 | |
256 | static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { | |
257 | /* Requires call-back bindings. */ | |
258 | OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &db8500_pmu_platdata), | |
cece5c40 | 259 | /* Requires DMA bindings. */ |
fa86a764 LJ |
260 | OF_DEV_AUXDATA("arm,pl011", 0x80120000, "uart0", &uart0_plat), |
261 | OF_DEV_AUXDATA("arm,pl011", 0x80121000, "uart1", &uart1_plat), | |
262 | OF_DEV_AUXDATA("arm,pl011", 0x80007000, "uart2", &uart2_plat), | |
fa86a764 LJ |
263 | OF_DEV_AUXDATA("arm,pl022", 0x80002000, "ssp0", &ssp0_plat), |
264 | OF_DEV_AUXDATA("arm,pl18x", 0x80126000, "sdi0", &mop500_sdi0_data), | |
265 | OF_DEV_AUXDATA("arm,pl18x", 0x80118000, "sdi1", &mop500_sdi1_data), | |
266 | OF_DEV_AUXDATA("arm,pl18x", 0x80005000, "sdi2", &mop500_sdi2_data), | |
267 | OF_DEV_AUXDATA("arm,pl18x", 0x80114000, "sdi4", &mop500_sdi4_data), | |
268 | /* Requires clock name bindings. */ | |
269 | OF_DEV_AUXDATA("st,nomadik-gpio", 0x8012e000, "gpio.0", NULL), | |
270 | OF_DEV_AUXDATA("st,nomadik-gpio", 0x8012e080, "gpio.1", NULL), | |
271 | OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e000, "gpio.2", NULL), | |
272 | OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e080, "gpio.3", NULL), | |
273 | OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e100, "gpio.4", NULL), | |
274 | OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e180, "gpio.5", NULL), | |
275 | OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e000, "gpio.6", NULL), | |
276 | OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e080, "gpio.7", NULL), | |
277 | OF_DEV_AUXDATA("st,nomadik-gpio", 0xa03fe000, "gpio.8", NULL), | |
278 | OF_DEV_AUXDATA("st,nomadik-i2c", 0x80004000, "nmk-i2c.0", NULL), | |
279 | OF_DEV_AUXDATA("st,nomadik-i2c", 0x80122000, "nmk-i2c.1", NULL), | |
280 | OF_DEV_AUXDATA("st,nomadik-i2c", 0x80128000, "nmk-i2c.2", NULL), | |
281 | OF_DEV_AUXDATA("st,nomadik-i2c", 0x80110000, "nmk-i2c.3", NULL), | |
282 | OF_DEV_AUXDATA("st,nomadik-i2c", 0x8012a000, "nmk-i2c.4", NULL), | |
05ec260e LW |
283 | OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", |
284 | &db8500_prcmu_pdata), | |
fa86a764 | 285 | /* Requires device name bindings. */ |
e32af889 | 286 | OF_DEV_AUXDATA("stericsson,nmk-pinctrl", U8500_PRCMU_BASE, |
9fcb4cc2 | 287 | "pinctrl-db8500", NULL), |
fa86a764 LJ |
288 | /* Requires clock name and DMA bindings. */ |
289 | OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80123000, | |
290 | "ux500-msp-i2s.0", &msp0_platform_data), | |
291 | OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80124000, | |
292 | "ux500-msp-i2s.1", &msp1_platform_data), | |
293 | OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80117000, | |
294 | "ux500-msp-i2s.2", &msp2_platform_data), | |
295 | OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80125000, | |
296 | "ux500-msp-i2s.3", &msp3_platform_data), | |
297 | {}, | |
298 | }; | |
299 | ||
300 | static const struct of_device_id u8500_local_bus_nodes[] = { | |
301 | /* only create devices below soc node */ | |
302 | { .compatible = "stericsson,db8500", }, | |
303 | { .compatible = "stericsson,db8500-prcmu", }, | |
304 | { .compatible = "simple-bus"}, | |
305 | { }, | |
306 | }; | |
307 | ||
308 | static void __init u8500_init_machine(void) | |
309 | { | |
310 | struct device *parent = NULL; | |
311 | ||
312 | /* Pinmaps must be in place before devices register */ | |
313 | if (of_machine_is_compatible("st-ericsson,mop500")) | |
314 | mop500_pinmaps_init(); | |
315 | else if (of_machine_is_compatible("calaosystems,snowball-a9500")) | |
316 | snowball_pinmaps_init(); | |
317 | else if (of_machine_is_compatible("st-ericsson,hrefv60+")) | |
318 | hrefv60_pinmaps_init(); | |
58e5b9e3 LJ |
319 | else if (of_machine_is_compatible("st-ericsson,ccu9540")) {} |
320 | /* TODO: Add pinmaps for ccu9540 board. */ | |
fa86a764 LJ |
321 | |
322 | /* TODO: Export SoC, USB, cpu-freq and DMA40 */ | |
323 | parent = u8500_of_init_devices(); | |
324 | ||
325 | /* automatically probe child nodes of db8500 device */ | |
326 | of_platform_populate(NULL, u8500_local_bus_nodes, u8500_auxdata_lookup, parent); | |
fa86a764 LJ |
327 | } |
328 | ||
79b40753 LJ |
329 | static const char * stericsson_dt_platform_compat[] = { |
330 | "st-ericsson,u8500", | |
331 | "st-ericsson,u8540", | |
332 | "st-ericsson,u9500", | |
333 | "st-ericsson,u9540", | |
fa86a764 LJ |
334 | NULL, |
335 | }; | |
336 | ||
46c1bf81 | 337 | DT_MACHINE_START(U8500_DT, "ST-Ericsson Ux5x0 platform (Device Tree Support)") |
f44c5fd1 | 338 | .smp = smp_ops(ux500_smp_ops), |
fa86a764 LJ |
339 | .map_io = u8500_map_io, |
340 | .init_irq = ux500_init_irq, | |
341 | /* we re-use nomadik timer here */ | |
6bb27d73 | 342 | .init_time = ux500_timer_init, |
fa86a764 | 343 | .init_machine = u8500_init_machine, |
74a1c9ab | 344 | .init_late = NULL, |
79b40753 | 345 | .dt_compat = stericsson_dt_platform_compat, |
fa86a764 LJ |
346 | MACHINE_END |
347 | ||
348 | #endif |