]>
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> |
bb16bd9b LW |
20 | #include <linux/platform_data/usb-musb-ux500.h> |
21 | #include <linux/platform_data/pinctrl-nomadik.h> | |
aa44ef4d | 22 | |
5caecb44 | 23 | #include <asm/pmu.h> |
aa44ef4d SK |
24 | #include <asm/mach/map.h> |
25 | #include <mach/hardware.h> | |
cc2c1334 | 26 | #include <mach/setup.h> |
5b1f7ddf | 27 | #include <mach/devices.h> |
eda413c2 | 28 | #include <mach/db8500-regs.h> |
94bdc0e2 | 29 | |
fbf1eadf | 30 | #include "devices-db8500.h" |
6f3f3c3f | 31 | #include "ste-dma40-db8500.h" |
fbf1eadf | 32 | |
aa44ef4d | 33 | /* minimum static i/o mapping required to boot U8500 platforms */ |
abf12d71 | 34 | static struct map_desc u8500_uart_io_desc[] __initdata = { |
92389ca8 RV |
35 | __IO_DEV_DESC(U8500_UART0_BASE, SZ_4K), |
36 | __IO_DEV_DESC(U8500_UART2_BASE, SZ_4K), | |
abf12d71 | 37 | }; |
bc71c096 LW |
38 | /* U8500 and U9540 common io_desc */ |
39 | static struct map_desc u8500_common_io_desc[] __initdata = { | |
215e83d9 LW |
40 | /* SCU base also covers GIC CPU BASE and TWD with its 4K page */ |
41 | __IO_DEV_DESC(U8500_SCU_BASE, SZ_4K), | |
92389ca8 RV |
42 | __IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K), |
43 | __IO_DEV_DESC(U8500_L2CC_BASE, SZ_4K), | |
92389ca8 | 44 | __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), |
92389ca8 RV |
45 | __IO_DEV_DESC(U8500_BACKUPRAM0_BASE, SZ_8K), |
46 | ||
47 | __IO_DEV_DESC(U8500_CLKRST1_BASE, SZ_4K), | |
48 | __IO_DEV_DESC(U8500_CLKRST2_BASE, SZ_4K), | |
49 | __IO_DEV_DESC(U8500_CLKRST3_BASE, SZ_4K), | |
50 | __IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K), | |
51 | __IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K), | |
52 | ||
c9c09572 | 53 | __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K), |
94bdc0e2 RV |
54 | __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K), |
55 | __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K), | |
56 | __IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K), | |
ee9581d7 MJ |
57 | }; |
58 | ||
59 | /* U8500 IO map specific description */ | |
60 | static struct map_desc u8500_io_desc[] __initdata = { | |
61 | __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), | |
fcbd458e | 62 | __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K), |
ee9581d7 MJ |
63 | |
64 | }; | |
65 | ||
66 | /* U9540 IO map specific description */ | |
67 | static struct map_desc u9540_io_desc[] __initdata = { | |
68 | __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K + SZ_8K), | |
69 | __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K + SZ_8K), | |
75a36ee0 RV |
70 | }; |
71 | ||
abf12d71 | 72 | void __init u8500_map_io(void) |
f946738c | 73 | { |
abf12d71 RV |
74 | /* |
75 | * Map the UARTs early so that the DEBUG_LL stuff continues to work. | |
76 | */ | |
77 | iotable_init(u8500_uart_io_desc, ARRAY_SIZE(u8500_uart_io_desc)); | |
f946738c | 78 | |
abf12d71 | 79 | ux500_map_io(); |
f946738c | 80 | |
bc71c096 | 81 | iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc)); |
75a36ee0 | 82 | |
e1bbb55d | 83 | if (cpu_is_ux540_family()) |
ee9581d7 MJ |
84 | iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc)); |
85 | else | |
86 | iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); | |
75a36ee0 | 87 | |
11871890 | 88 | _PRCMU_BASE = __io_address(U8500_PRCMU_BASE); |
aa44ef4d SK |
89 | } |
90 | ||
aa90eb9d RV |
91 | static struct resource db8500_pmu_resources[] = { |
92 | [0] = { | |
93 | .start = IRQ_DB8500_PMU, | |
94 | .end = IRQ_DB8500_PMU, | |
95 | .flags = IORESOURCE_IRQ, | |
96 | }, | |
97 | }; | |
98 | ||
99 | /* | |
100 | * The PMU IRQ lines of two cores are wired together into a single interrupt. | |
101 | * Bounce the interrupt to the other core if it's not ours. | |
102 | */ | |
103 | static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler) | |
104 | { | |
105 | irqreturn_t ret = handler(irq, dev); | |
106 | int other = !smp_processor_id(); | |
107 | ||
108 | if (ret == IRQ_NONE && cpu_online(other)) | |
109 | irq_set_affinity(irq, cpumask_of(other)); | |
110 | ||
111 | /* | |
112 | * We should be able to get away with the amount of IRQ_NONEs we give, | |
113 | * while still having the spurious IRQ detection code kick in if the | |
114 | * interrupt really starts hitting spuriously. | |
115 | */ | |
116 | return ret; | |
117 | } | |
118 | ||
3a8e39c9 | 119 | struct arm_pmu_platdata db8500_pmu_platdata = { |
aa90eb9d RV |
120 | .handle_irq = db8500_pmu_handler, |
121 | }; | |
122 | ||
123 | static struct platform_device db8500_pmu_device = { | |
124 | .name = "arm-pmu", | |
df3d17e0 | 125 | .id = -1, |
aa90eb9d RV |
126 | .num_resources = ARRAY_SIZE(db8500_pmu_resources), |
127 | .resource = db8500_pmu_resources, | |
128 | .dev.platform_data = &db8500_pmu_platdata, | |
129 | }; | |
130 | ||
3df57bcf MN |
131 | static struct platform_device db8500_prcmu_device = { |
132 | .name = "db8500-prcmu", | |
133 | }; | |
134 | ||
aa90eb9d RV |
135 | static struct platform_device *platform_devs[] __initdata = { |
136 | &u8500_dma40_device, | |
137 | &db8500_pmu_device, | |
3df57bcf | 138 | &db8500_prcmu_device, |
aa90eb9d RV |
139 | }; |
140 | ||
01afdd13 RV |
141 | static resource_size_t __initdata db8500_gpio_base[] = { |
142 | U8500_GPIOBANK0_BASE, | |
143 | U8500_GPIOBANK1_BASE, | |
144 | U8500_GPIOBANK2_BASE, | |
145 | U8500_GPIOBANK3_BASE, | |
146 | U8500_GPIOBANK4_BASE, | |
147 | U8500_GPIOBANK5_BASE, | |
148 | U8500_GPIOBANK6_BASE, | |
149 | U8500_GPIOBANK7_BASE, | |
150 | U8500_GPIOBANK8_BASE, | |
151 | }; | |
152 | ||
18403424 | 153 | static void __init db8500_add_gpios(struct device *parent) |
01afdd13 RV |
154 | { |
155 | struct nmk_gpio_platform_data pdata = { | |
c15def1c | 156 | .supports_sleepmode = true, |
01afdd13 RV |
157 | }; |
158 | ||
18403424 | 159 | dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base), |
01afdd13 | 160 | IRQ_DB8500_GPIO0, &pdata); |
e98ea774 | 161 | dbx500_add_pinctrl(parent, "pinctrl-db8500"); |
01afdd13 RV |
162 | } |
163 | ||
6f3f3c3f MYK |
164 | static int usb_db8500_rx_dma_cfg[] = { |
165 | DB8500_DMA_DEV38_USB_OTG_IEP_1_9, | |
166 | DB8500_DMA_DEV37_USB_OTG_IEP_2_10, | |
167 | DB8500_DMA_DEV36_USB_OTG_IEP_3_11, | |
168 | DB8500_DMA_DEV19_USB_OTG_IEP_4_12, | |
169 | DB8500_DMA_DEV18_USB_OTG_IEP_5_13, | |
170 | DB8500_DMA_DEV17_USB_OTG_IEP_6_14, | |
171 | DB8500_DMA_DEV16_USB_OTG_IEP_7_15, | |
172 | DB8500_DMA_DEV39_USB_OTG_IEP_8 | |
173 | }; | |
174 | ||
175 | static int usb_db8500_tx_dma_cfg[] = { | |
176 | DB8500_DMA_DEV38_USB_OTG_OEP_1_9, | |
177 | DB8500_DMA_DEV37_USB_OTG_OEP_2_10, | |
178 | DB8500_DMA_DEV36_USB_OTG_OEP_3_11, | |
179 | DB8500_DMA_DEV19_USB_OTG_OEP_4_12, | |
180 | DB8500_DMA_DEV18_USB_OTG_OEP_5_13, | |
181 | DB8500_DMA_DEV17_USB_OTG_OEP_6_14, | |
182 | DB8500_DMA_DEV16_USB_OTG_OEP_7_15, | |
183 | DB8500_DMA_DEV39_USB_OTG_OEP_8 | |
184 | }; | |
185 | ||
eda413c2 LJ |
186 | static const char *db8500_read_soc_id(void) |
187 | { | |
188 | void __iomem *uid = __io_address(U8500_BB_UID_BASE); | |
189 | ||
190 | return kasprintf(GFP_KERNEL, "%08x%08x%08x%08x%08x", | |
191 | readl((u32 *)uid+1), | |
192 | readl((u32 *)uid+1), readl((u32 *)uid+2), | |
193 | readl((u32 *)uid+3), readl((u32 *)uid+4)); | |
194 | } | |
195 | ||
196 | static struct device * __init db8500_soc_device_init(void) | |
197 | { | |
198 | const char *soc_id = db8500_read_soc_id(); | |
199 | ||
200 | return ux500_soc_device_init(soc_id); | |
201 | } | |
202 | ||
aa44ef4d SK |
203 | /* |
204 | * This function is called from the board init | |
205 | */ | |
3a8e39c9 | 206 | struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500) |
aa44ef4d | 207 | { |
eda413c2 | 208 | struct device *parent; |
b024a0c8 | 209 | int i; |
eda413c2 LJ |
210 | |
211 | parent = db8500_soc_device_init(); | |
212 | ||
213 | db8500_add_rtc(parent); | |
214 | db8500_add_gpios(parent); | |
215 | db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); | |
fbf1eadf | 216 | |
f65c1982 LJ |
217 | platform_device_register_data(parent, |
218 | "cpufreq-u8500", -1, NULL, 0); | |
219 | ||
220 | for (i = 0; i < ARRAY_SIZE(platform_devs); i++) | |
221 | platform_devs[i]->dev.parent = parent; | |
222 | ||
3a8e39c9 LJ |
223 | db8500_prcmu_device.dev.platform_data = ab8500; |
224 | ||
f65c1982 LJ |
225 | platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); |
226 | ||
227 | return parent; | |
228 | } | |
229 | ||
230 | /* TODO: Once all pieces are DT:ed, remove completely. */ | |
231 | struct device * __init u8500_of_init_devices(void) | |
232 | { | |
233 | struct device *parent; | |
f65c1982 LJ |
234 | |
235 | parent = db8500_soc_device_init(); | |
236 | ||
f65c1982 LJ |
237 | db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg); |
238 | ||
b024a0c8 LJ |
239 | platform_device_register_data(parent, |
240 | "cpufreq-u8500", -1, NULL, 0); | |
241 | ||
38cd8c5d | 242 | u8500_dma40_device.dev.parent = parent; |
b024a0c8 | 243 | |
08d05026 LJ |
244 | /* |
245 | * Devices to be DT:ed: | |
246 | * u8500_dma40_device = todo | |
da384870 | 247 | * db8500_pmu_device = done |
dee42ebe | 248 | * db8500_prcmu_device = done |
08d05026 | 249 | */ |
38cd8c5d | 250 | platform_device_register(&u8500_dma40_device); |
aa44ef4d | 251 | |
eda413c2 | 252 | return parent; |
aa44ef4d | 253 | } |