common.c revision 85bc26211c6a2c6e82c2403697f8ce44e9587215
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 <linux/spi/orion_spi.h>
22#include <net/dsa.h>
23#include <asm/page.h>
24#include <asm/setup.h>
25#include <asm/timex.h>
26#include <asm/mach/arch.h>
27#include <asm/mach/map.h>
28#include <asm/mach/time.h>
29#include <mach/hardware.h>
30#include <mach/orion5x.h>
31#include <plat/ehci-orion.h>
32#include <plat/mv_xor.h>
33#include <plat/orion_nand.h>
34#include <plat/orion5x_wdt.h>
35#include <plat/time.h>
36#include "common.h"
37
38/*****************************************************************************
39 * I/O Address Mapping
40 ****************************************************************************/
41static struct map_desc orion5x_io_desc[] __initdata = {
42	{
43		.virtual	= ORION5X_REGS_VIRT_BASE,
44		.pfn		= __phys_to_pfn(ORION5X_REGS_PHYS_BASE),
45		.length		= ORION5X_REGS_SIZE,
46		.type		= MT_DEVICE,
47	}, {
48		.virtual	= ORION5X_PCIE_IO_VIRT_BASE,
49		.pfn		= __phys_to_pfn(ORION5X_PCIE_IO_PHYS_BASE),
50		.length		= ORION5X_PCIE_IO_SIZE,
51		.type		= MT_DEVICE,
52	}, {
53		.virtual	= ORION5X_PCI_IO_VIRT_BASE,
54		.pfn		= __phys_to_pfn(ORION5X_PCI_IO_PHYS_BASE),
55		.length		= ORION5X_PCI_IO_SIZE,
56		.type		= MT_DEVICE,
57	}, {
58		.virtual	= ORION5X_PCIE_WA_VIRT_BASE,
59		.pfn		= __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE),
60		.length		= ORION5X_PCIE_WA_SIZE,
61		.type		= MT_DEVICE,
62	},
63};
64
65void __init orion5x_map_io(void)
66{
67	iotable_init(orion5x_io_desc, ARRAY_SIZE(orion5x_io_desc));
68}
69
70
71/*****************************************************************************
72 * EHCI
73 ****************************************************************************/
74static struct orion_ehci_data orion5x_ehci_data = {
75	.dram		= &orion5x_mbus_dram_info,
76	.phy_version	= EHCI_PHY_ORION,
77};
78
79static u64 ehci_dmamask = 0xffffffffUL;
80
81
82/*****************************************************************************
83 * EHCI0
84 ****************************************************************************/
85static struct resource orion5x_ehci0_resources[] = {
86	{
87		.start	= ORION5X_USB0_PHYS_BASE,
88		.end	= ORION5X_USB0_PHYS_BASE + SZ_4K - 1,
89		.flags	= IORESOURCE_MEM,
90	}, {
91		.start	= IRQ_ORION5X_USB0_CTRL,
92		.end	= IRQ_ORION5X_USB0_CTRL,
93		.flags	= IORESOURCE_IRQ,
94	},
95};
96
97static struct platform_device orion5x_ehci0 = {
98	.name		= "orion-ehci",
99	.id		= 0,
100	.dev		= {
101		.dma_mask		= &ehci_dmamask,
102		.coherent_dma_mask	= 0xffffffff,
103		.platform_data		= &orion5x_ehci_data,
104	},
105	.resource	= orion5x_ehci0_resources,
106	.num_resources	= ARRAY_SIZE(orion5x_ehci0_resources),
107};
108
109void __init orion5x_ehci0_init(void)
110{
111	platform_device_register(&orion5x_ehci0);
112}
113
114
115/*****************************************************************************
116 * EHCI1
117 ****************************************************************************/
118static struct resource orion5x_ehci1_resources[] = {
119	{
120		.start	= ORION5X_USB1_PHYS_BASE,
121		.end	= ORION5X_USB1_PHYS_BASE + SZ_4K - 1,
122		.flags	= IORESOURCE_MEM,
123	}, {
124		.start	= IRQ_ORION5X_USB1_CTRL,
125		.end	= IRQ_ORION5X_USB1_CTRL,
126		.flags	= IORESOURCE_IRQ,
127	},
128};
129
130static struct platform_device orion5x_ehci1 = {
131	.name		= "orion-ehci",
132	.id		= 1,
133	.dev		= {
134		.dma_mask		= &ehci_dmamask,
135		.coherent_dma_mask	= 0xffffffff,
136		.platform_data		= &orion5x_ehci_data,
137	},
138	.resource	= orion5x_ehci1_resources,
139	.num_resources	= ARRAY_SIZE(orion5x_ehci1_resources),
140};
141
142void __init orion5x_ehci1_init(void)
143{
144	platform_device_register(&orion5x_ehci1);
145}
146
147
148/*****************************************************************************
149 * GigE
150 ****************************************************************************/
151struct mv643xx_eth_shared_platform_data orion5x_eth_shared_data = {
152	.dram		= &orion5x_mbus_dram_info,
153};
154
155static struct resource orion5x_eth_shared_resources[] = {
156	{
157		.start	= ORION5X_ETH_PHYS_BASE + 0x2000,
158		.end	= ORION5X_ETH_PHYS_BASE + 0x3fff,
159		.flags	= IORESOURCE_MEM,
160	}, {
161		.start	= IRQ_ORION5X_ETH_ERR,
162		.end	= IRQ_ORION5X_ETH_ERR,
163		.flags	= IORESOURCE_IRQ,
164	},
165};
166
167static struct platform_device orion5x_eth_shared = {
168	.name		= MV643XX_ETH_SHARED_NAME,
169	.id		= 0,
170	.dev		= {
171		.platform_data	= &orion5x_eth_shared_data,
172	},
173	.num_resources	= ARRAY_SIZE(orion5x_eth_shared_resources),
174	.resource	= orion5x_eth_shared_resources,
175};
176
177static struct resource orion5x_eth_resources[] = {
178	{
179		.name	= "eth irq",
180		.start	= IRQ_ORION5X_ETH_SUM,
181		.end	= IRQ_ORION5X_ETH_SUM,
182		.flags	= IORESOURCE_IRQ,
183	},
184};
185
186static struct platform_device orion5x_eth = {
187	.name		= MV643XX_ETH_NAME,
188	.id		= 0,
189	.num_resources	= 1,
190	.resource	= orion5x_eth_resources,
191};
192
193void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
194{
195	eth_data->shared = &orion5x_eth_shared;
196	orion5x_eth.dev.platform_data = eth_data;
197
198	platform_device_register(&orion5x_eth_shared);
199	platform_device_register(&orion5x_eth);
200}
201
202
203/*****************************************************************************
204 * Ethernet switch
205 ****************************************************************************/
206static struct resource orion5x_switch_resources[] = {
207	{
208		.start	= 0,
209		.end	= 0,
210		.flags	= IORESOURCE_IRQ,
211	},
212};
213
214static struct platform_device orion5x_switch_device = {
215	.name		= "dsa",
216	.id		= 0,
217	.num_resources	= 0,
218	.resource	= orion5x_switch_resources,
219};
220
221void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq)
222{
223	int i;
224
225	if (irq != NO_IRQ) {
226		orion5x_switch_resources[0].start = irq;
227		orion5x_switch_resources[0].end = irq;
228		orion5x_switch_device.num_resources = 1;
229	}
230
231	d->netdev = &orion5x_eth.dev;
232	for (i = 0; i < d->nr_chips; i++)
233		d->chip[i].mii_bus = &orion5x_eth_shared.dev;
234	orion5x_switch_device.dev.platform_data = d;
235
236	platform_device_register(&orion5x_switch_device);
237}
238
239
240/*****************************************************************************
241 * I2C
242 ****************************************************************************/
243static struct mv64xxx_i2c_pdata orion5x_i2c_pdata = {
244	.freq_m		= 8, /* assumes 166 MHz TCLK */
245	.freq_n		= 3,
246	.timeout	= 1000, /* Default timeout of 1 second */
247};
248
249static struct resource orion5x_i2c_resources[] = {
250	{
251		.start	= I2C_PHYS_BASE,
252		.end	= I2C_PHYS_BASE + 0x1f,
253		.flags	= IORESOURCE_MEM,
254	}, {
255		.start	= IRQ_ORION5X_I2C,
256		.end	= IRQ_ORION5X_I2C,
257		.flags	= IORESOURCE_IRQ,
258	},
259};
260
261static struct platform_device orion5x_i2c = {
262	.name		= MV64XXX_I2C_CTLR_NAME,
263	.id		= 0,
264	.num_resources	= ARRAY_SIZE(orion5x_i2c_resources),
265	.resource	= orion5x_i2c_resources,
266	.dev		= {
267		.platform_data	= &orion5x_i2c_pdata,
268	},
269};
270
271void __init orion5x_i2c_init(void)
272{
273	platform_device_register(&orion5x_i2c);
274}
275
276
277/*****************************************************************************
278 * SATA
279 ****************************************************************************/
280static struct resource orion5x_sata_resources[] = {
281	{
282		.name	= "sata base",
283		.start	= ORION5X_SATA_PHYS_BASE,
284		.end	= ORION5X_SATA_PHYS_BASE + 0x5000 - 1,
285		.flags	= IORESOURCE_MEM,
286	}, {
287		.name	= "sata irq",
288		.start	= IRQ_ORION5X_SATA,
289		.end	= IRQ_ORION5X_SATA,
290		.flags	= IORESOURCE_IRQ,
291	},
292};
293
294static struct platform_device orion5x_sata = {
295	.name		= "sata_mv",
296	.id		= 0,
297	.dev		= {
298		.coherent_dma_mask	= 0xffffffff,
299	},
300	.num_resources	= ARRAY_SIZE(orion5x_sata_resources),
301	.resource	= orion5x_sata_resources,
302};
303
304void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data)
305{
306	sata_data->dram = &orion5x_mbus_dram_info;
307	orion5x_sata.dev.platform_data = sata_data;
308	platform_device_register(&orion5x_sata);
309}
310
311
312/*****************************************************************************
313 * SPI
314 ****************************************************************************/
315static struct orion_spi_info orion5x_spi_plat_data = {
316	.tclk			= 0,
317	.enable_clock_fix	= 1,
318};
319
320static struct resource orion5x_spi_resources[] = {
321	{
322		.name	= "spi base",
323		.start	= SPI_PHYS_BASE,
324		.end	= SPI_PHYS_BASE + 0x1f,
325		.flags	= IORESOURCE_MEM,
326	},
327};
328
329static struct platform_device orion5x_spi = {
330	.name		= "orion_spi",
331	.id		= 0,
332	.dev		= {
333		.platform_data	= &orion5x_spi_plat_data,
334	},
335	.num_resources	= ARRAY_SIZE(orion5x_spi_resources),
336	.resource	= orion5x_spi_resources,
337};
338
339void __init orion5x_spi_init()
340{
341	platform_device_register(&orion5x_spi);
342}
343
344
345/*****************************************************************************
346 * UART0
347 ****************************************************************************/
348static struct plat_serial8250_port orion5x_uart0_data[] = {
349	{
350		.mapbase	= UART0_PHYS_BASE,
351		.membase	= (char *)UART0_VIRT_BASE,
352		.irq		= IRQ_ORION5X_UART0,
353		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
354		.iotype		= UPIO_MEM,
355		.regshift	= 2,
356		.uartclk	= 0,
357	}, {
358	},
359};
360
361static struct resource orion5x_uart0_resources[] = {
362	{
363		.start		= UART0_PHYS_BASE,
364		.end		= UART0_PHYS_BASE + 0xff,
365		.flags		= IORESOURCE_MEM,
366	}, {
367		.start		= IRQ_ORION5X_UART0,
368		.end		= IRQ_ORION5X_UART0,
369		.flags		= IORESOURCE_IRQ,
370	},
371};
372
373static struct platform_device orion5x_uart0 = {
374	.name			= "serial8250",
375	.id			= PLAT8250_DEV_PLATFORM,
376	.dev			= {
377		.platform_data	= orion5x_uart0_data,
378	},
379	.resource		= orion5x_uart0_resources,
380	.num_resources		= ARRAY_SIZE(orion5x_uart0_resources),
381};
382
383void __init orion5x_uart0_init(void)
384{
385	platform_device_register(&orion5x_uart0);
386}
387
388
389/*****************************************************************************
390 * UART1
391 ****************************************************************************/
392static struct plat_serial8250_port orion5x_uart1_data[] = {
393	{
394		.mapbase	= UART1_PHYS_BASE,
395		.membase	= (char *)UART1_VIRT_BASE,
396		.irq		= IRQ_ORION5X_UART1,
397		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
398		.iotype		= UPIO_MEM,
399		.regshift	= 2,
400		.uartclk	= 0,
401	}, {
402	},
403};
404
405static struct resource orion5x_uart1_resources[] = {
406	{
407		.start		= UART1_PHYS_BASE,
408		.end		= UART1_PHYS_BASE + 0xff,
409		.flags		= IORESOURCE_MEM,
410	}, {
411		.start		= IRQ_ORION5X_UART1,
412		.end		= IRQ_ORION5X_UART1,
413		.flags		= IORESOURCE_IRQ,
414	},
415};
416
417static struct platform_device orion5x_uart1 = {
418	.name			= "serial8250",
419	.id			= PLAT8250_DEV_PLATFORM1,
420	.dev			= {
421		.platform_data	= orion5x_uart1_data,
422	},
423	.resource		= orion5x_uart1_resources,
424	.num_resources		= ARRAY_SIZE(orion5x_uart1_resources),
425};
426
427void __init orion5x_uart1_init(void)
428{
429	platform_device_register(&orion5x_uart1);
430}
431
432
433/*****************************************************************************
434 * XOR engine
435 ****************************************************************************/
436struct mv_xor_platform_shared_data orion5x_xor_shared_data = {
437	.dram		= &orion5x_mbus_dram_info,
438};
439
440static struct resource orion5x_xor_shared_resources[] = {
441	{
442		.name	= "xor low",
443		.start	= ORION5X_XOR_PHYS_BASE,
444		.end	= ORION5X_XOR_PHYS_BASE + 0xff,
445		.flags	= IORESOURCE_MEM,
446	}, {
447		.name	= "xor high",
448		.start	= ORION5X_XOR_PHYS_BASE + 0x200,
449		.end	= ORION5X_XOR_PHYS_BASE + 0x2ff,
450		.flags	= IORESOURCE_MEM,
451	},
452};
453
454static struct platform_device orion5x_xor_shared = {
455	.name		= MV_XOR_SHARED_NAME,
456	.id		= 0,
457	.dev		= {
458		.platform_data	= &orion5x_xor_shared_data,
459	},
460	.num_resources	= ARRAY_SIZE(orion5x_xor_shared_resources),
461	.resource	= orion5x_xor_shared_resources,
462};
463
464static u64 orion5x_xor_dmamask = DMA_BIT_MASK(32);
465
466static struct resource orion5x_xor0_resources[] = {
467	[0] = {
468		.start	= IRQ_ORION5X_XOR0,
469		.end	= IRQ_ORION5X_XOR0,
470		.flags	= IORESOURCE_IRQ,
471	},
472};
473
474static struct mv_xor_platform_data orion5x_xor0_data = {
475	.shared		= &orion5x_xor_shared,
476	.hw_id		= 0,
477	.pool_size	= PAGE_SIZE,
478};
479
480static struct platform_device orion5x_xor0_channel = {
481	.name		= MV_XOR_NAME,
482	.id		= 0,
483	.num_resources	= ARRAY_SIZE(orion5x_xor0_resources),
484	.resource	= orion5x_xor0_resources,
485	.dev		= {
486		.dma_mask		= &orion5x_xor_dmamask,
487		.coherent_dma_mask	= DMA_BIT_MASK(64),
488		.platform_data		= (void *)&orion5x_xor0_data,
489	},
490};
491
492static struct resource orion5x_xor1_resources[] = {
493	[0] = {
494		.start	= IRQ_ORION5X_XOR1,
495		.end	= IRQ_ORION5X_XOR1,
496		.flags	= IORESOURCE_IRQ,
497	},
498};
499
500static struct mv_xor_platform_data orion5x_xor1_data = {
501	.shared		= &orion5x_xor_shared,
502	.hw_id		= 1,
503	.pool_size	= PAGE_SIZE,
504};
505
506static struct platform_device orion5x_xor1_channel = {
507	.name		= MV_XOR_NAME,
508	.id		= 1,
509	.num_resources	= ARRAY_SIZE(orion5x_xor1_resources),
510	.resource	= orion5x_xor1_resources,
511	.dev		= {
512		.dma_mask		= &orion5x_xor_dmamask,
513		.coherent_dma_mask	= DMA_BIT_MASK(64),
514		.platform_data		= (void *)&orion5x_xor1_data,
515	},
516};
517
518void __init orion5x_xor_init(void)
519{
520	platform_device_register(&orion5x_xor_shared);
521
522	/*
523	 * two engines can't do memset simultaneously, this limitation
524	 * satisfied by removing memset support from one of the engines.
525	 */
526	dma_cap_set(DMA_MEMCPY, orion5x_xor0_data.cap_mask);
527	dma_cap_set(DMA_XOR, orion5x_xor0_data.cap_mask);
528	platform_device_register(&orion5x_xor0_channel);
529
530	dma_cap_set(DMA_MEMCPY, orion5x_xor1_data.cap_mask);
531	dma_cap_set(DMA_MEMSET, orion5x_xor1_data.cap_mask);
532	dma_cap_set(DMA_XOR, orion5x_xor1_data.cap_mask);
533	platform_device_register(&orion5x_xor1_channel);
534}
535
536
537/*****************************************************************************
538 * Watchdog
539 ****************************************************************************/
540static struct orion5x_wdt_platform_data orion5x_wdt_data = {
541	.tclk			= 0,
542};
543
544static struct platform_device orion5x_wdt_device = {
545	.name		= "orion5x_wdt",
546	.id		= -1,
547	.dev		= {
548		.platform_data	= &orion5x_wdt_data,
549	},
550	.num_resources	= 0,
551};
552
553void __init orion5x_wdt_init(void)
554{
555	orion5x_wdt_data.tclk = orion5x_tclk;
556	platform_device_register(&orion5x_wdt_device);
557}
558
559
560/*****************************************************************************
561 * Time handling
562 ****************************************************************************/
563int orion5x_tclk;
564
565int __init orion5x_find_tclk(void)
566{
567	u32 dev, rev;
568
569	orion5x_pcie_id(&dev, &rev);
570	if (dev == MV88F6183_DEV_ID &&
571	    (readl(MPP_RESET_SAMPLE) & 0x00000200) == 0)
572		return 133333333;
573
574	return 166666667;
575}
576
577static void orion5x_timer_init(void)
578{
579	orion5x_tclk = orion5x_find_tclk();
580	orion_time_init(IRQ_ORION5X_BRIDGE, orion5x_tclk);
581}
582
583struct sys_timer orion5x_timer = {
584	.init = orion5x_timer_init,
585};
586
587
588/*****************************************************************************
589 * General
590 ****************************************************************************/
591/*
592 * Identify device ID and rev from PCIe configuration header space '0'.
593 */
594static void __init orion5x_id(u32 *dev, u32 *rev, char **dev_name)
595{
596	orion5x_pcie_id(dev, rev);
597
598	if (*dev == MV88F5281_DEV_ID) {
599		if (*rev == MV88F5281_REV_D2) {
600			*dev_name = "MV88F5281-D2";
601		} else if (*rev == MV88F5281_REV_D1) {
602			*dev_name = "MV88F5281-D1";
603		} else if (*rev == MV88F5281_REV_D0) {
604			*dev_name = "MV88F5281-D0";
605		} else {
606			*dev_name = "MV88F5281-Rev-Unsupported";
607		}
608	} else if (*dev == MV88F5182_DEV_ID) {
609		if (*rev == MV88F5182_REV_A2) {
610			*dev_name = "MV88F5182-A2";
611		} else {
612			*dev_name = "MV88F5182-Rev-Unsupported";
613		}
614	} else if (*dev == MV88F5181_DEV_ID) {
615		if (*rev == MV88F5181_REV_B1) {
616			*dev_name = "MV88F5181-Rev-B1";
617		} else if (*rev == MV88F5181L_REV_A1) {
618			*dev_name = "MV88F5181L-Rev-A1";
619		} else {
620			*dev_name = "MV88F5181(L)-Rev-Unsupported";
621		}
622	} else if (*dev == MV88F6183_DEV_ID) {
623		if (*rev == MV88F6183_REV_B0) {
624			*dev_name = "MV88F6183-Rev-B0";
625		} else {
626			*dev_name = "MV88F6183-Rev-Unsupported";
627		}
628	} else {
629		*dev_name = "Device-Unknown";
630	}
631}
632
633void __init orion5x_init(void)
634{
635	char *dev_name;
636	u32 dev, rev;
637
638	orion5x_id(&dev, &rev, &dev_name);
639	printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, orion5x_tclk);
640
641	orion5x_eth_shared_data.t_clk = orion5x_tclk;
642	orion5x_spi_plat_data.tclk = orion5x_tclk;
643	orion5x_uart0_data[0].uartclk = orion5x_tclk;
644	orion5x_uart1_data[0].uartclk = orion5x_tclk;
645
646	/*
647	 * Setup Orion address map
648	 */
649	orion5x_setup_cpu_mbus_bridge();
650
651	/*
652	 * Don't issue "Wait for Interrupt" instruction if we are
653	 * running on D0 5281 silicon.
654	 */
655	if (dev == MV88F5281_DEV_ID && rev == MV88F5281_REV_D0) {
656		printk(KERN_INFO "Orion: Applying 5281 D0 WFI workaround.\n");
657		disable_hlt();
658	}
659
660	/*
661	 * Register watchdog driver
662	 */
663	orion5x_wdt_init();
664}
665
666/*
667 * Many orion-based systems have buggy bootloader implementations.
668 * This is a common fixup for bogus memory tags.
669 */
670void __init tag_fixup_mem32(struct machine_desc *mdesc, struct tag *t,
671			    char **from, struct meminfo *meminfo)
672{
673	for (; t->hdr.size; t = tag_next(t))
674		if (t->hdr.tag == ATAG_MEM &&
675		    (!t->u.mem.size || t->u.mem.size & ~PAGE_MASK ||
676		     t->u.mem.start & ~PAGE_MASK)) {
677			printk(KERN_WARNING
678			       "Clearing invalid memory bank %dKB@0x%08x\n",
679			       t->u.mem.size / 1024, t->u.mem.start);
680			t->hdr.tag = 0;
681		}
682}
683