diff options
Diffstat (limited to 'arch/arm/mach-orion5x/common.c')
-rw-r--r-- | arch/arm/mach-orion5x/common.c | 437 |
1 files changed, 437 insertions, 0 deletions
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c new file mode 100644 index 00000000000..faf4e321191 --- /dev/null +++ b/arch/arm/mach-orion5x/common.c | |||
@@ -0,0 +1,437 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/common.c | ||
3 | * | ||
4 | * Core functions for Marvell Orion 5x SoCs | ||
5 | * | ||
6 | * Maintainer: Tzachi Perelstein <tzachi@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/serial_8250.h> | ||
17 | #include <linux/mbus.h> | ||
18 | #include <linux/mv643xx_eth.h> | ||
19 | #include <linux/mv643xx_i2c.h> | ||
20 | #include <linux/ata_platform.h> | ||
21 | #include <asm/page.h> | ||
22 | #include <asm/setup.h> | ||
23 | #include <asm/timex.h> | ||
24 | #include <asm/mach/arch.h> | ||
25 | #include <asm/mach/map.h> | ||
26 | #include <asm/mach/time.h> | ||
27 | #include <asm/arch/hardware.h> | ||
28 | #include <asm/arch/orion5x.h> | ||
29 | #include <asm/plat-orion/ehci-orion.h> | ||
30 | #include <asm/plat-orion/orion_nand.h> | ||
31 | #include <asm/plat-orion/time.h> | ||
32 | #include "common.h" | ||
33 | |||
34 | /***************************************************************************** | ||
35 | * I/O Address Mapping | ||
36 | ****************************************************************************/ | ||
37 | static struct map_desc orion5x_io_desc[] __initdata = { | ||
38 | { | ||
39 | .virtual = ORION5X_REGS_VIRT_BASE, | ||
40 | .pfn = __phys_to_pfn(ORION5X_REGS_PHYS_BASE), | ||
41 | .length = ORION5X_REGS_SIZE, | ||
42 | .type = MT_DEVICE, | ||
43 | }, { | ||
44 | .virtual = ORION5X_PCIE_IO_VIRT_BASE, | ||
45 | .pfn = __phys_to_pfn(ORION5X_PCIE_IO_PHYS_BASE), | ||
46 | .length = ORION5X_PCIE_IO_SIZE, | ||
47 | .type = MT_DEVICE, | ||
48 | }, { | ||
49 | .virtual = ORION5X_PCI_IO_VIRT_BASE, | ||
50 | .pfn = __phys_to_pfn(ORION5X_PCI_IO_PHYS_BASE), | ||
51 | .length = ORION5X_PCI_IO_SIZE, | ||
52 | .type = MT_DEVICE, | ||
53 | }, { | ||
54 | .virtual = ORION5X_PCIE_WA_VIRT_BASE, | ||
55 | .pfn = __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE), | ||
56 | .length = ORION5X_PCIE_WA_SIZE, | ||
57 | .type = MT_DEVICE, | ||
58 | }, | ||
59 | }; | ||
60 | |||
61 | void __init orion5x_map_io(void) | ||
62 | { | ||
63 | iotable_init(orion5x_io_desc, ARRAY_SIZE(orion5x_io_desc)); | ||
64 | } | ||
65 | |||
66 | |||
67 | /***************************************************************************** | ||
68 | * EHCI | ||
69 | ****************************************************************************/ | ||
70 | static struct orion_ehci_data orion5x_ehci_data = { | ||
71 | .dram = &orion5x_mbus_dram_info, | ||
72 | }; | ||
73 | |||
74 | static u64 ehci_dmamask = 0xffffffffUL; | ||
75 | |||
76 | |||
77 | /***************************************************************************** | ||
78 | * EHCI0 | ||
79 | ****************************************************************************/ | ||
80 | static struct resource orion5x_ehci0_resources[] = { | ||
81 | { | ||
82 | .start = ORION5X_USB0_PHYS_BASE, | ||
83 | .end = ORION5X_USB0_PHYS_BASE + SZ_4K - 1, | ||
84 | .flags = IORESOURCE_MEM, | ||
85 | }, { | ||
86 | .start = IRQ_ORION5X_USB0_CTRL, | ||
87 | .end = IRQ_ORION5X_USB0_CTRL, | ||
88 | .flags = IORESOURCE_IRQ, | ||
89 | }, | ||
90 | }; | ||
91 | |||
92 | static struct platform_device orion5x_ehci0 = { | ||
93 | .name = "orion-ehci", | ||
94 | .id = 0, | ||
95 | .dev = { | ||
96 | .dma_mask = &ehci_dmamask, | ||
97 | .coherent_dma_mask = 0xffffffff, | ||
98 | .platform_data = &orion5x_ehci_data, | ||
99 | }, | ||
100 | .resource = orion5x_ehci0_resources, | ||
101 | .num_resources = ARRAY_SIZE(orion5x_ehci0_resources), | ||
102 | }; | ||
103 | |||
104 | void __init orion5x_ehci0_init(void) | ||
105 | { | ||
106 | platform_device_register(&orion5x_ehci0); | ||
107 | } | ||
108 | |||
109 | |||
110 | /***************************************************************************** | ||
111 | * EHCI1 | ||
112 | ****************************************************************************/ | ||
113 | static struct resource orion5x_ehci1_resources[] = { | ||
114 | { | ||
115 | .start = ORION5X_USB1_PHYS_BASE, | ||
116 | .end = ORION5X_USB1_PHYS_BASE + SZ_4K - 1, | ||
117 | .flags = IORESOURCE_MEM, | ||
118 | }, { | ||
119 | .start = IRQ_ORION5X_USB1_CTRL, | ||
120 | .end = IRQ_ORION5X_USB1_CTRL, | ||
121 | .flags = IORESOURCE_IRQ, | ||
122 | }, | ||
123 | }; | ||
124 | |||
125 | static struct platform_device orion5x_ehci1 = { | ||
126 | .name = "orion-ehci", | ||
127 | .id = 1, | ||
128 | .dev = { | ||
129 | .dma_mask = &ehci_dmamask, | ||
130 | .coherent_dma_mask = 0xffffffff, | ||
131 | .platform_data = &orion5x_ehci_data, | ||
132 | }, | ||
133 | .resource = orion5x_ehci1_resources, | ||
134 | .num_resources = ARRAY_SIZE(orion5x_ehci1_resources), | ||
135 | }; | ||
136 | |||
137 | void __init orion5x_ehci1_init(void) | ||
138 | { | ||
139 | platform_device_register(&orion5x_ehci1); | ||
140 | } | ||
141 | |||
142 | |||
143 | /***************************************************************************** | ||
144 | * GigE | ||
145 | ****************************************************************************/ | ||
146 | struct mv643xx_eth_shared_platform_data orion5x_eth_shared_data = { | ||
147 | .dram = &orion5x_mbus_dram_info, | ||
148 | .t_clk = ORION5X_TCLK, | ||
149 | }; | ||
150 | |||
151 | static struct resource orion5x_eth_shared_resources[] = { | ||
152 | { | ||
153 | .start = ORION5X_ETH_PHYS_BASE + 0x2000, | ||
154 | .end = ORION5X_ETH_PHYS_BASE + 0x3fff, | ||
155 | .flags = IORESOURCE_MEM, | ||
156 | }, | ||
157 | }; | ||
158 | |||
159 | static struct platform_device orion5x_eth_shared = { | ||
160 | .name = MV643XX_ETH_SHARED_NAME, | ||
161 | .id = 0, | ||
162 | .dev = { | ||
163 | .platform_data = &orion5x_eth_shared_data, | ||
164 | }, | ||
165 | .num_resources = 1, | ||
166 | .resource = orion5x_eth_shared_resources, | ||
167 | }; | ||
168 | |||
169 | static struct resource orion5x_eth_resources[] = { | ||
170 | { | ||
171 | .name = "eth irq", | ||
172 | .start = IRQ_ORION5X_ETH_SUM, | ||
173 | .end = IRQ_ORION5X_ETH_SUM, | ||
174 | .flags = IORESOURCE_IRQ, | ||
175 | }, | ||
176 | }; | ||
177 | |||
178 | static struct platform_device orion5x_eth = { | ||
179 | .name = MV643XX_ETH_NAME, | ||
180 | .id = 0, | ||
181 | .num_resources = 1, | ||
182 | .resource = orion5x_eth_resources, | ||
183 | }; | ||
184 | |||
185 | void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) | ||
186 | { | ||
187 | eth_data->shared = &orion5x_eth_shared; | ||
188 | orion5x_eth.dev.platform_data = eth_data; | ||
189 | |||
190 | platform_device_register(&orion5x_eth_shared); | ||
191 | platform_device_register(&orion5x_eth); | ||
192 | } | ||
193 | |||
194 | |||
195 | /***************************************************************************** | ||
196 | * I2C | ||
197 | ****************************************************************************/ | ||
198 | static struct mv64xxx_i2c_pdata orion5x_i2c_pdata = { | ||
199 | .freq_m = 8, /* assumes 166 MHz TCLK */ | ||
200 | .freq_n = 3, | ||
201 | .timeout = 1000, /* Default timeout of 1 second */ | ||
202 | }; | ||
203 | |||
204 | static struct resource orion5x_i2c_resources[] = { | ||
205 | { | ||
206 | .name = "i2c base", | ||
207 | .start = I2C_PHYS_BASE, | ||
208 | .end = I2C_PHYS_BASE + 0x1f, | ||
209 | .flags = IORESOURCE_MEM, | ||
210 | }, { | ||
211 | .name = "i2c irq", | ||
212 | .start = IRQ_ORION5X_I2C, | ||
213 | .end = IRQ_ORION5X_I2C, | ||
214 | .flags = IORESOURCE_IRQ, | ||
215 | }, | ||
216 | }; | ||
217 | |||
218 | static struct platform_device orion5x_i2c = { | ||
219 | .name = MV64XXX_I2C_CTLR_NAME, | ||
220 | .id = 0, | ||
221 | .num_resources = ARRAY_SIZE(orion5x_i2c_resources), | ||
222 | .resource = orion5x_i2c_resources, | ||
223 | .dev = { | ||
224 | .platform_data = &orion5x_i2c_pdata, | ||
225 | }, | ||
226 | }; | ||
227 | |||
228 | void __init orion5x_i2c_init(void) | ||
229 | { | ||
230 | platform_device_register(&orion5x_i2c); | ||
231 | } | ||
232 | |||
233 | |||
234 | /***************************************************************************** | ||
235 | * SATA | ||
236 | ****************************************************************************/ | ||
237 | static struct resource orion5x_sata_resources[] = { | ||
238 | { | ||
239 | .name = "sata base", | ||
240 | .start = ORION5X_SATA_PHYS_BASE, | ||
241 | .end = ORION5X_SATA_PHYS_BASE + 0x5000 - 1, | ||
242 | .flags = IORESOURCE_MEM, | ||
243 | }, { | ||
244 | .name = "sata irq", | ||
245 | .start = IRQ_ORION5X_SATA, | ||
246 | .end = IRQ_ORION5X_SATA, | ||
247 | .flags = IORESOURCE_IRQ, | ||
248 | }, | ||
249 | }; | ||
250 | |||
251 | static struct platform_device orion5x_sata = { | ||
252 | .name = "sata_mv", | ||
253 | .id = 0, | ||
254 | .dev = { | ||
255 | .coherent_dma_mask = 0xffffffff, | ||
256 | }, | ||
257 | .num_resources = ARRAY_SIZE(orion5x_sata_resources), | ||
258 | .resource = orion5x_sata_resources, | ||
259 | }; | ||
260 | |||
261 | void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) | ||
262 | { | ||
263 | sata_data->dram = &orion5x_mbus_dram_info; | ||
264 | orion5x_sata.dev.platform_data = sata_data; | ||
265 | platform_device_register(&orion5x_sata); | ||
266 | } | ||
267 | |||
268 | |||
269 | /***************************************************************************** | ||
270 | * UART0 | ||
271 | ****************************************************************************/ | ||
272 | static struct plat_serial8250_port orion5x_uart0_data[] = { | ||
273 | { | ||
274 | .mapbase = UART0_PHYS_BASE, | ||
275 | .membase = (char *)UART0_VIRT_BASE, | ||
276 | .irq = IRQ_ORION5X_UART0, | ||
277 | .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, | ||
278 | .iotype = UPIO_MEM, | ||
279 | .regshift = 2, | ||
280 | .uartclk = ORION5X_TCLK, | ||
281 | }, { | ||
282 | }, | ||
283 | }; | ||
284 | |||
285 | static struct resource orion5x_uart0_resources[] = { | ||
286 | { | ||
287 | .start = UART0_PHYS_BASE, | ||
288 | .end = UART0_PHYS_BASE + 0xff, | ||
289 | .flags = IORESOURCE_MEM, | ||
290 | }, { | ||
291 | .start = IRQ_ORION5X_UART0, | ||
292 | .end = IRQ_ORION5X_UART0, | ||
293 | .flags = IORESOURCE_IRQ, | ||
294 | }, | ||
295 | }; | ||
296 | |||
297 | static struct platform_device orion5x_uart0 = { | ||
298 | .name = "serial8250", | ||
299 | .id = PLAT8250_DEV_PLATFORM, | ||
300 | .dev = { | ||
301 | .platform_data = orion5x_uart0_data, | ||
302 | }, | ||
303 | .resource = orion5x_uart0_resources, | ||
304 | .num_resources = ARRAY_SIZE(orion5x_uart0_resources), | ||
305 | }; | ||
306 | |||
307 | void __init orion5x_uart0_init(void) | ||
308 | { | ||
309 | platform_device_register(&orion5x_uart0); | ||
310 | } | ||
311 | |||
312 | |||
313 | /***************************************************************************** | ||
314 | * UART1 | ||
315 | ****************************************************************************/ | ||
316 | static struct plat_serial8250_port orion5x_uart1_data[] = { | ||
317 | { | ||
318 | .mapbase = UART1_PHYS_BASE, | ||
319 | .membase = (char *)UART1_VIRT_BASE, | ||
320 | .irq = IRQ_ORION5X_UART1, | ||
321 | .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, | ||
322 | .iotype = UPIO_MEM, | ||
323 | .regshift = 2, | ||
324 | .uartclk = ORION5X_TCLK, | ||
325 | }, { | ||
326 | }, | ||
327 | }; | ||
328 | |||
329 | static struct resource orion5x_uart1_resources[] = { | ||
330 | { | ||
331 | .start = UART1_PHYS_BASE, | ||
332 | .end = UART1_PHYS_BASE + 0xff, | ||
333 | .flags = IORESOURCE_MEM, | ||
334 | }, { | ||
335 | .start = IRQ_ORION5X_UART1, | ||
336 | .end = IRQ_ORION5X_UART1, | ||
337 | .flags = IORESOURCE_IRQ, | ||
338 | }, | ||
339 | }; | ||
340 | |||
341 | static struct platform_device orion5x_uart1 = { | ||
342 | .name = "serial8250", | ||
343 | .id = PLAT8250_DEV_PLATFORM1, | ||
344 | .dev = { | ||
345 | .platform_data = orion5x_uart1_data, | ||
346 | }, | ||
347 | .resource = orion5x_uart1_resources, | ||
348 | .num_resources = ARRAY_SIZE(orion5x_uart1_resources), | ||
349 | }; | ||
350 | |||
351 | void __init orion5x_uart1_init(void) | ||
352 | { | ||
353 | platform_device_register(&orion5x_uart1); | ||
354 | } | ||
355 | |||
356 | |||
357 | /***************************************************************************** | ||
358 | * Time handling | ||
359 | ****************************************************************************/ | ||
360 | static void orion5x_timer_init(void) | ||
361 | { | ||
362 | orion_time_init(IRQ_ORION5X_BRIDGE, ORION5X_TCLK); | ||
363 | } | ||
364 | |||
365 | struct sys_timer orion5x_timer = { | ||
366 | .init = orion5x_timer_init, | ||
367 | }; | ||
368 | |||
369 | |||
370 | /***************************************************************************** | ||
371 | * General | ||
372 | ****************************************************************************/ | ||
373 | /* | ||
374 | * Identify device ID and rev from PCIe configuration header space '0'. | ||
375 | */ | ||
376 | static void __init orion5x_id(u32 *dev, u32 *rev, char **dev_name) | ||
377 | { | ||
378 | orion5x_pcie_id(dev, rev); | ||
379 | |||
380 | if (*dev == MV88F5281_DEV_ID) { | ||
381 | if (*rev == MV88F5281_REV_D2) { | ||
382 | *dev_name = "MV88F5281-D2"; | ||
383 | } else if (*rev == MV88F5281_REV_D1) { | ||
384 | *dev_name = "MV88F5281-D1"; | ||
385 | } else { | ||
386 | *dev_name = "MV88F5281-Rev-Unsupported"; | ||
387 | } | ||
388 | } else if (*dev == MV88F5182_DEV_ID) { | ||
389 | if (*rev == MV88F5182_REV_A2) { | ||
390 | *dev_name = "MV88F5182-A2"; | ||
391 | } else { | ||
392 | *dev_name = "MV88F5182-Rev-Unsupported"; | ||
393 | } | ||
394 | } else if (*dev == MV88F5181_DEV_ID) { | ||
395 | if (*rev == MV88F5181_REV_B1) { | ||
396 | *dev_name = "MV88F5181-Rev-B1"; | ||
397 | } else if (*rev == MV88F5181L_REV_A1) { | ||
398 | *dev_name = "MV88F5181L-Rev-A1"; | ||
399 | } else { | ||
400 | *dev_name = "MV88F5181(L)-Rev-Unsupported"; | ||
401 | } | ||
402 | } else { | ||
403 | *dev_name = "Device-Unknown"; | ||
404 | } | ||
405 | } | ||
406 | |||
407 | void __init orion5x_init(void) | ||
408 | { | ||
409 | char *dev_name; | ||
410 | u32 dev, rev; | ||
411 | |||
412 | orion5x_id(&dev, &rev, &dev_name); | ||
413 | printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, ORION5X_TCLK); | ||
414 | |||
415 | /* | ||
416 | * Setup Orion address map | ||
417 | */ | ||
418 | orion5x_setup_cpu_mbus_bridge(); | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | * Many orion-based systems have buggy bootloader implementations. | ||
423 | * This is a common fixup for bogus memory tags. | ||
424 | */ | ||
425 | void __init tag_fixup_mem32(struct machine_desc *mdesc, struct tag *t, | ||
426 | char **from, struct meminfo *meminfo) | ||
427 | { | ||
428 | for (; t->hdr.size; t = tag_next(t)) | ||
429 | if (t->hdr.tag == ATAG_MEM && | ||
430 | (!t->u.mem.size || t->u.mem.size & ~PAGE_MASK || | ||
431 | t->u.mem.start & ~PAGE_MASK)) { | ||
432 | printk(KERN_WARNING | ||
433 | "Clearing invalid memory bank %dKB@0x%08x\n", | ||
434 | t->u.mem.size / 1024, t->u.mem.start); | ||
435 | t->hdr.tag = 0; | ||
436 | } | ||
437 | } | ||