162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Platform device support for Au1x00 SoCs.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * (C) Copyright Embedded Alley Solutions, Inc 2005
762306a36Sopenharmony_ci * Author: Pantelis Antoniou <pantelis@embeddedalley.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
1062306a36Sopenharmony_ci * License version 2.  This program is licensed "as is" without any
1162306a36Sopenharmony_ci * warranty of any kind, whether express or implied.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/clk.h>
1562306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1662306a36Sopenharmony_ci#include <linux/etherdevice.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/serial_8250.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <linux/usb/ehci_pdriver.h>
2262306a36Sopenharmony_ci#include <linux/usb/ohci_pdriver.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <asm/mach-au1x00/au1000.h>
2562306a36Sopenharmony_ci#include <asm/mach-au1x00/au1xxx_dbdma.h>
2662306a36Sopenharmony_ci#include <asm/mach-au1x00/au1100_mmc.h>
2762306a36Sopenharmony_ci#include <asm/mach-au1x00/au1xxx_eth.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include <prom.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic void alchemy_8250_pm(struct uart_port *port, unsigned int state,
3262306a36Sopenharmony_ci			    unsigned int old_state)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci#ifdef CONFIG_SERIAL_8250
3562306a36Sopenharmony_ci	switch (state) {
3662306a36Sopenharmony_ci	case 0:
3762306a36Sopenharmony_ci		alchemy_uart_enable(CPHYSADDR(port->membase));
3862306a36Sopenharmony_ci		serial8250_do_pm(port, state, old_state);
3962306a36Sopenharmony_ci		break;
4062306a36Sopenharmony_ci	case 3:		/* power off */
4162306a36Sopenharmony_ci		serial8250_do_pm(port, state, old_state);
4262306a36Sopenharmony_ci		alchemy_uart_disable(CPHYSADDR(port->membase));
4362306a36Sopenharmony_ci		break;
4462306a36Sopenharmony_ci	default:
4562306a36Sopenharmony_ci		serial8250_do_pm(port, state, old_state);
4662306a36Sopenharmony_ci		break;
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci#endif
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define PORT(_base, _irq)					\
5262306a36Sopenharmony_ci	{							\
5362306a36Sopenharmony_ci		.mapbase	= _base,			\
5462306a36Sopenharmony_ci		.mapsize	= 0x1000,			\
5562306a36Sopenharmony_ci		.irq		= _irq,				\
5662306a36Sopenharmony_ci		.regshift	= 2,				\
5762306a36Sopenharmony_ci		.flags		= UPF_SKIP_TEST | UPF_IOREMAP | \
5862306a36Sopenharmony_ci				  UPF_FIXED_TYPE,		\
5962306a36Sopenharmony_ci		.type		= PORT_16550A,			\
6062306a36Sopenharmony_ci		.pm		= alchemy_8250_pm,		\
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic struct plat_serial8250_port au1x00_uart_data[][4] __initdata = {
6462306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1000] = {
6562306a36Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1000_UART0_INT),
6662306a36Sopenharmony_ci		PORT(AU1000_UART1_PHYS_ADDR, AU1000_UART1_INT),
6762306a36Sopenharmony_ci		PORT(AU1000_UART2_PHYS_ADDR, AU1000_UART2_INT),
6862306a36Sopenharmony_ci		PORT(AU1000_UART3_PHYS_ADDR, AU1000_UART3_INT),
6962306a36Sopenharmony_ci	},
7062306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1500] = {
7162306a36Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1500_UART0_INT),
7262306a36Sopenharmony_ci		PORT(AU1000_UART3_PHYS_ADDR, AU1500_UART3_INT),
7362306a36Sopenharmony_ci	},
7462306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1100] = {
7562306a36Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1100_UART0_INT),
7662306a36Sopenharmony_ci		PORT(AU1000_UART1_PHYS_ADDR, AU1100_UART1_INT),
7762306a36Sopenharmony_ci		PORT(AU1000_UART3_PHYS_ADDR, AU1100_UART3_INT),
7862306a36Sopenharmony_ci	},
7962306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1550] = {
8062306a36Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1550_UART0_INT),
8162306a36Sopenharmony_ci		PORT(AU1000_UART1_PHYS_ADDR, AU1550_UART1_INT),
8262306a36Sopenharmony_ci		PORT(AU1000_UART3_PHYS_ADDR, AU1550_UART3_INT),
8362306a36Sopenharmony_ci	},
8462306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1200] = {
8562306a36Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT),
8662306a36Sopenharmony_ci		PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT),
8762306a36Sopenharmony_ci	},
8862306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1300] = {
8962306a36Sopenharmony_ci		PORT(AU1300_UART0_PHYS_ADDR, AU1300_UART0_INT),
9062306a36Sopenharmony_ci		PORT(AU1300_UART1_PHYS_ADDR, AU1300_UART1_INT),
9162306a36Sopenharmony_ci		PORT(AU1300_UART2_PHYS_ADDR, AU1300_UART2_INT),
9262306a36Sopenharmony_ci		PORT(AU1300_UART3_PHYS_ADDR, AU1300_UART3_INT),
9362306a36Sopenharmony_ci	},
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic struct platform_device au1xx0_uart_device = {
9762306a36Sopenharmony_ci	.name			= "serial8250",
9862306a36Sopenharmony_ci	.id			= PLAT8250_DEV_AU1X00,
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic void __init alchemy_setup_uarts(int ctype)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	long uartclk;
10462306a36Sopenharmony_ci	int s = sizeof(struct plat_serial8250_port);
10562306a36Sopenharmony_ci	int c = alchemy_get_uarts(ctype);
10662306a36Sopenharmony_ci	struct plat_serial8250_port *ports;
10762306a36Sopenharmony_ci	struct clk *clk = clk_get(NULL, ALCHEMY_PERIPH_CLK);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (IS_ERR(clk))
11062306a36Sopenharmony_ci		return;
11162306a36Sopenharmony_ci	if (clk_prepare_enable(clk)) {
11262306a36Sopenharmony_ci		clk_put(clk);
11362306a36Sopenharmony_ci		return;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	uartclk = clk_get_rate(clk);
11662306a36Sopenharmony_ci	clk_put(clk);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	ports = kcalloc(s, (c + 1), GFP_KERNEL);
11962306a36Sopenharmony_ci	if (!ports) {
12062306a36Sopenharmony_ci		printk(KERN_INFO "Alchemy: no memory for UART data\n");
12162306a36Sopenharmony_ci		return;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci	memcpy(ports, au1x00_uart_data[ctype], s * c);
12462306a36Sopenharmony_ci	au1xx0_uart_device.dev.platform_data = ports;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	/* Fill up uartclk. */
12762306a36Sopenharmony_ci	for (s = 0; s < c; s++) {
12862306a36Sopenharmony_ci		ports[s].uartclk = uartclk;
12962306a36Sopenharmony_ci		if (au_platform_setup(&ports[s]) < 0) {
13062306a36Sopenharmony_ci			kfree(ports);
13162306a36Sopenharmony_ci			printk(KERN_INFO "Alchemy: missing support for UARTs\n");
13262306a36Sopenharmony_ci			return;
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci	if (platform_device_register(&au1xx0_uart_device))
13662306a36Sopenharmony_ci		printk(KERN_INFO "Alchemy: failed to register UARTs\n");
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic u64 alchemy_all_dmamask = DMA_BIT_MASK(32);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* Power on callback for the ehci platform driver */
14362306a36Sopenharmony_cistatic int alchemy_ehci_power_on(struct platform_device *pdev)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	return alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci/* Power off/suspend callback for the ehci platform driver */
14962306a36Sopenharmony_cistatic void alchemy_ehci_power_off(struct platform_device *pdev)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic struct usb_ehci_pdata alchemy_ehci_pdata = {
15562306a36Sopenharmony_ci	.no_io_watchdog = 1,
15662306a36Sopenharmony_ci	.power_on	= alchemy_ehci_power_on,
15762306a36Sopenharmony_ci	.power_off	= alchemy_ehci_power_off,
15862306a36Sopenharmony_ci	.power_suspend	= alchemy_ehci_power_off,
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci/* Power on callback for the ohci platform driver */
16262306a36Sopenharmony_cistatic int alchemy_ohci_power_on(struct platform_device *pdev)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	int unit;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	unit = (pdev->id == 1) ?
16762306a36Sopenharmony_ci		ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return alchemy_usb_control(unit, 1);
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/* Power off/suspend callback for the ohci platform driver */
17362306a36Sopenharmony_cistatic void alchemy_ohci_power_off(struct platform_device *pdev)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	int unit;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	unit = (pdev->id == 1) ?
17862306a36Sopenharmony_ci		ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	alchemy_usb_control(unit, 0);
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic struct usb_ohci_pdata alchemy_ohci_pdata = {
18462306a36Sopenharmony_ci	.power_on		= alchemy_ohci_power_on,
18562306a36Sopenharmony_ci	.power_off		= alchemy_ohci_power_off,
18662306a36Sopenharmony_ci	.power_suspend		= alchemy_ohci_power_off,
18762306a36Sopenharmony_ci};
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic unsigned long alchemy_ohci_data[][2] __initdata = {
19062306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1000] = { AU1000_USB_OHCI_PHYS_ADDR, AU1000_USB_HOST_INT },
19162306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1500] = { AU1000_USB_OHCI_PHYS_ADDR, AU1500_USB_HOST_INT },
19262306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1100] = { AU1000_USB_OHCI_PHYS_ADDR, AU1100_USB_HOST_INT },
19362306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1550] = { AU1550_USB_OHCI_PHYS_ADDR, AU1550_USB_HOST_INT },
19462306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1200] = { AU1200_USB_OHCI_PHYS_ADDR, AU1200_USB_INT },
19562306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1300] = { AU1300_USB_OHCI0_PHYS_ADDR, AU1300_USB_INT },
19662306a36Sopenharmony_ci};
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic unsigned long alchemy_ehci_data[][2] __initdata = {
19962306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1200] = { AU1200_USB_EHCI_PHYS_ADDR, AU1200_USB_INT },
20062306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1300] = { AU1300_USB_EHCI_PHYS_ADDR, AU1300_USB_INT },
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int __init _new_usbres(struct resource **r, struct platform_device **d)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	*r = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
20662306a36Sopenharmony_ci	if (!*r)
20762306a36Sopenharmony_ci		return -ENOMEM;
20862306a36Sopenharmony_ci	*d = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
20962306a36Sopenharmony_ci	if (!*d) {
21062306a36Sopenharmony_ci		kfree(*r);
21162306a36Sopenharmony_ci		return -ENOMEM;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	(*d)->dev.coherent_dma_mask = DMA_BIT_MASK(32);
21562306a36Sopenharmony_ci	(*d)->num_resources = 2;
21662306a36Sopenharmony_ci	(*d)->resource = *r;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic void __init alchemy_setup_usb(int ctype)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	struct resource *res;
22462306a36Sopenharmony_ci	struct platform_device *pdev;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	/* setup OHCI0.  Every variant has one */
22762306a36Sopenharmony_ci	if (_new_usbres(&res, &pdev))
22862306a36Sopenharmony_ci		return;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	res[0].start = alchemy_ohci_data[ctype][0];
23162306a36Sopenharmony_ci	res[0].end = res[0].start + 0x100 - 1;
23262306a36Sopenharmony_ci	res[0].flags = IORESOURCE_MEM;
23362306a36Sopenharmony_ci	res[1].start = alchemy_ohci_data[ctype][1];
23462306a36Sopenharmony_ci	res[1].end = res[1].start;
23562306a36Sopenharmony_ci	res[1].flags = IORESOURCE_IRQ;
23662306a36Sopenharmony_ci	pdev->name = "ohci-platform";
23762306a36Sopenharmony_ci	pdev->id = 0;
23862306a36Sopenharmony_ci	pdev->dev.dma_mask = &alchemy_all_dmamask;
23962306a36Sopenharmony_ci	pdev->dev.platform_data = &alchemy_ohci_pdata;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (platform_device_register(pdev))
24262306a36Sopenharmony_ci		printk(KERN_INFO "Alchemy USB: cannot add OHCI0\n");
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* setup EHCI0: Au1200/Au1300 */
24662306a36Sopenharmony_ci	if ((ctype == ALCHEMY_CPU_AU1200) || (ctype == ALCHEMY_CPU_AU1300)) {
24762306a36Sopenharmony_ci		if (_new_usbres(&res, &pdev))
24862306a36Sopenharmony_ci			return;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		res[0].start = alchemy_ehci_data[ctype][0];
25162306a36Sopenharmony_ci		res[0].end = res[0].start + 0x100 - 1;
25262306a36Sopenharmony_ci		res[0].flags = IORESOURCE_MEM;
25362306a36Sopenharmony_ci		res[1].start = alchemy_ehci_data[ctype][1];
25462306a36Sopenharmony_ci		res[1].end = res[1].start;
25562306a36Sopenharmony_ci		res[1].flags = IORESOURCE_IRQ;
25662306a36Sopenharmony_ci		pdev->name = "ehci-platform";
25762306a36Sopenharmony_ci		pdev->id = 0;
25862306a36Sopenharmony_ci		pdev->dev.dma_mask = &alchemy_all_dmamask;
25962306a36Sopenharmony_ci		pdev->dev.platform_data = &alchemy_ehci_pdata;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		if (platform_device_register(pdev))
26262306a36Sopenharmony_ci			printk(KERN_INFO "Alchemy USB: cannot add EHCI0\n");
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	/* Au1300: OHCI1 */
26662306a36Sopenharmony_ci	if (ctype == ALCHEMY_CPU_AU1300) {
26762306a36Sopenharmony_ci		if (_new_usbres(&res, &pdev))
26862306a36Sopenharmony_ci			return;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		res[0].start = AU1300_USB_OHCI1_PHYS_ADDR;
27162306a36Sopenharmony_ci		res[0].end = res[0].start + 0x100 - 1;
27262306a36Sopenharmony_ci		res[0].flags = IORESOURCE_MEM;
27362306a36Sopenharmony_ci		res[1].start = AU1300_USB_INT;
27462306a36Sopenharmony_ci		res[1].end = res[1].start;
27562306a36Sopenharmony_ci		res[1].flags = IORESOURCE_IRQ;
27662306a36Sopenharmony_ci		pdev->name = "ohci-platform";
27762306a36Sopenharmony_ci		pdev->id = 1;
27862306a36Sopenharmony_ci		pdev->dev.dma_mask = &alchemy_all_dmamask;
27962306a36Sopenharmony_ci		pdev->dev.platform_data = &alchemy_ohci_pdata;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		if (platform_device_register(pdev))
28262306a36Sopenharmony_ci			printk(KERN_INFO "Alchemy USB: cannot add OHCI1\n");
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci/* Macro to help defining the Ethernet MAC resources */
28762306a36Sopenharmony_ci#define MAC_RES_COUNT	4	/* MAC regs, MAC en, MAC INT, MACDMA regs */
28862306a36Sopenharmony_ci#define MAC_RES(_base, _enable, _irq, _macdma)		\
28962306a36Sopenharmony_ci	{						\
29062306a36Sopenharmony_ci		.start	= _base,			\
29162306a36Sopenharmony_ci		.end	= _base + 0xffff,		\
29262306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,		\
29362306a36Sopenharmony_ci	},						\
29462306a36Sopenharmony_ci	{						\
29562306a36Sopenharmony_ci		.start	= _enable,			\
29662306a36Sopenharmony_ci		.end	= _enable + 0x3,		\
29762306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,		\
29862306a36Sopenharmony_ci	},						\
29962306a36Sopenharmony_ci	{						\
30062306a36Sopenharmony_ci		.start	= _irq,				\
30162306a36Sopenharmony_ci		.end	= _irq,				\
30262306a36Sopenharmony_ci		.flags	= IORESOURCE_IRQ		\
30362306a36Sopenharmony_ci	},						\
30462306a36Sopenharmony_ci	{						\
30562306a36Sopenharmony_ci		.start	= _macdma,			\
30662306a36Sopenharmony_ci		.end	= _macdma + 0x1ff,		\
30762306a36Sopenharmony_ci		.flags	= IORESOURCE_MEM,		\
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = {
31162306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1000] = {
31262306a36Sopenharmony_ci		MAC_RES(AU1000_MAC0_PHYS_ADDR,
31362306a36Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR,
31462306a36Sopenharmony_ci			AU1000_MAC0_DMA_INT,
31562306a36Sopenharmony_ci			AU1000_MACDMA0_PHYS_ADDR)
31662306a36Sopenharmony_ci	},
31762306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1500] = {
31862306a36Sopenharmony_ci		MAC_RES(AU1500_MAC0_PHYS_ADDR,
31962306a36Sopenharmony_ci			AU1500_MACEN_PHYS_ADDR,
32062306a36Sopenharmony_ci			AU1500_MAC0_DMA_INT,
32162306a36Sopenharmony_ci			AU1000_MACDMA0_PHYS_ADDR)
32262306a36Sopenharmony_ci	},
32362306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1100] = {
32462306a36Sopenharmony_ci		MAC_RES(AU1000_MAC0_PHYS_ADDR,
32562306a36Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR,
32662306a36Sopenharmony_ci			AU1100_MAC0_DMA_INT,
32762306a36Sopenharmony_ci			AU1000_MACDMA0_PHYS_ADDR)
32862306a36Sopenharmony_ci	},
32962306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1550] = {
33062306a36Sopenharmony_ci		MAC_RES(AU1000_MAC0_PHYS_ADDR,
33162306a36Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR,
33262306a36Sopenharmony_ci			AU1550_MAC0_DMA_INT,
33362306a36Sopenharmony_ci			AU1000_MACDMA0_PHYS_ADDR)
33462306a36Sopenharmony_ci	},
33562306a36Sopenharmony_ci};
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic struct au1000_eth_platform_data au1xxx_eth0_platform_data = {
33862306a36Sopenharmony_ci	.phy1_search_mac0 = 1,
33962306a36Sopenharmony_ci};
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic struct platform_device au1xxx_eth0_device = {
34262306a36Sopenharmony_ci	.name		= "au1000-eth",
34362306a36Sopenharmony_ci	.id		= 0,
34462306a36Sopenharmony_ci	.num_resources	= MAC_RES_COUNT,
34562306a36Sopenharmony_ci	.dev = {
34662306a36Sopenharmony_ci		.dma_mask               = &alchemy_all_dmamask,
34762306a36Sopenharmony_ci		.coherent_dma_mask      = DMA_BIT_MASK(32),
34862306a36Sopenharmony_ci		.platform_data          = &au1xxx_eth0_platform_data,
34962306a36Sopenharmony_ci	},
35062306a36Sopenharmony_ci};
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = {
35362306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1000] = {
35462306a36Sopenharmony_ci		MAC_RES(AU1000_MAC1_PHYS_ADDR,
35562306a36Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR + 4,
35662306a36Sopenharmony_ci			AU1000_MAC1_DMA_INT,
35762306a36Sopenharmony_ci			AU1000_MACDMA1_PHYS_ADDR)
35862306a36Sopenharmony_ci	},
35962306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1500] = {
36062306a36Sopenharmony_ci		MAC_RES(AU1500_MAC1_PHYS_ADDR,
36162306a36Sopenharmony_ci			AU1500_MACEN_PHYS_ADDR + 4,
36262306a36Sopenharmony_ci			AU1500_MAC1_DMA_INT,
36362306a36Sopenharmony_ci			AU1000_MACDMA1_PHYS_ADDR)
36462306a36Sopenharmony_ci	},
36562306a36Sopenharmony_ci	[ALCHEMY_CPU_AU1550] = {
36662306a36Sopenharmony_ci		MAC_RES(AU1000_MAC1_PHYS_ADDR,
36762306a36Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR + 4,
36862306a36Sopenharmony_ci			AU1550_MAC1_DMA_INT,
36962306a36Sopenharmony_ci			AU1000_MACDMA1_PHYS_ADDR)
37062306a36Sopenharmony_ci	},
37162306a36Sopenharmony_ci};
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic struct au1000_eth_platform_data au1xxx_eth1_platform_data = {
37462306a36Sopenharmony_ci	.phy1_search_mac0 = 1,
37562306a36Sopenharmony_ci};
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic struct platform_device au1xxx_eth1_device = {
37862306a36Sopenharmony_ci	.name		= "au1000-eth",
37962306a36Sopenharmony_ci	.id		= 1,
38062306a36Sopenharmony_ci	.num_resources	= MAC_RES_COUNT,
38162306a36Sopenharmony_ci	.dev = {
38262306a36Sopenharmony_ci		.dma_mask               = &alchemy_all_dmamask,
38362306a36Sopenharmony_ci		.coherent_dma_mask      = DMA_BIT_MASK(32),
38462306a36Sopenharmony_ci		.platform_data          = &au1xxx_eth1_platform_data,
38562306a36Sopenharmony_ci	},
38662306a36Sopenharmony_ci};
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_civoid __init au1xxx_override_eth_cfg(unsigned int port,
38962306a36Sopenharmony_ci			struct au1000_eth_platform_data *eth_data)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	if (!eth_data || port > 1)
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (port == 0)
39562306a36Sopenharmony_ci		memcpy(&au1xxx_eth0_platform_data, eth_data,
39662306a36Sopenharmony_ci			sizeof(struct au1000_eth_platform_data));
39762306a36Sopenharmony_ci	else
39862306a36Sopenharmony_ci		memcpy(&au1xxx_eth1_platform_data, eth_data,
39962306a36Sopenharmony_ci			sizeof(struct au1000_eth_platform_data));
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic void __init alchemy_setup_macs(int ctype)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	int ret, i;
40562306a36Sopenharmony_ci	unsigned char ethaddr[6];
40662306a36Sopenharmony_ci	struct resource *macres;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* Handle 1st MAC */
40962306a36Sopenharmony_ci	if (alchemy_get_macs(ctype) < 1)
41062306a36Sopenharmony_ci		return;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	macres = kmemdup(au1xxx_eth0_resources[ctype],
41362306a36Sopenharmony_ci			 sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
41462306a36Sopenharmony_ci	if (!macres) {
41562306a36Sopenharmony_ci		printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n");
41662306a36Sopenharmony_ci		return;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci	au1xxx_eth0_device.resource = macres;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	i = prom_get_ethernet_addr(ethaddr);
42162306a36Sopenharmony_ci	if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac))
42262306a36Sopenharmony_ci		memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	ret = platform_device_register(&au1xxx_eth0_device);
42562306a36Sopenharmony_ci	if (ret)
42662306a36Sopenharmony_ci		printk(KERN_INFO "Alchemy: failed to register MAC0\n");
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* Handle 2nd MAC */
43062306a36Sopenharmony_ci	if (alchemy_get_macs(ctype) < 2)
43162306a36Sopenharmony_ci		return;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	macres = kmemdup(au1xxx_eth1_resources[ctype],
43462306a36Sopenharmony_ci			 sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
43562306a36Sopenharmony_ci	if (!macres) {
43662306a36Sopenharmony_ci		printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n");
43762306a36Sopenharmony_ci		return;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci	au1xxx_eth1_device.resource = macres;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	ethaddr[5] += 1;	/* next addr for 2nd MAC */
44262306a36Sopenharmony_ci	if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac))
44362306a36Sopenharmony_ci		memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/* Register second MAC if enabled in pinfunc */
44662306a36Sopenharmony_ci	if (!(alchemy_rdsys(AU1000_SYS_PINFUNC) & SYS_PF_NI2)) {
44762306a36Sopenharmony_ci		ret = platform_device_register(&au1xxx_eth1_device);
44862306a36Sopenharmony_ci		if (ret)
44962306a36Sopenharmony_ci			printk(KERN_INFO "Alchemy: failed to register MAC1\n");
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int __init au1xxx_platform_init(void)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	int ctype = alchemy_get_cputype();
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	alchemy_setup_uarts(ctype);
45862306a36Sopenharmony_ci	alchemy_setup_macs(ctype);
45962306a36Sopenharmony_ci	alchemy_setup_usb(ctype);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	return 0;
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ciarch_initcall(au1xxx_platform_init);
465