18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Platform device support for Au1x00 SoCs.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * (C) Copyright Embedded Alley Solutions, Inc 2005
78c2ecf20Sopenharmony_ci * Author: Pantelis Antoniou <pantelis@embeddedalley.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public
108c2ecf20Sopenharmony_ci * License version 2.  This program is licensed "as is" without any
118c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/clk.h>
158c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
168c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
198c2ecf20Sopenharmony_ci#include <linux/serial_8250.h>
208c2ecf20Sopenharmony_ci#include <linux/slab.h>
218c2ecf20Sopenharmony_ci#include <linux/usb/ehci_pdriver.h>
228c2ecf20Sopenharmony_ci#include <linux/usb/ohci_pdriver.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include <asm/mach-au1x00/au1000.h>
258c2ecf20Sopenharmony_ci#include <asm/mach-au1x00/au1xxx_dbdma.h>
268c2ecf20Sopenharmony_ci#include <asm/mach-au1x00/au1100_mmc.h>
278c2ecf20Sopenharmony_ci#include <asm/mach-au1x00/au1xxx_eth.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include <prom.h>
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic void alchemy_8250_pm(struct uart_port *port, unsigned int state,
328c2ecf20Sopenharmony_ci			    unsigned int old_state)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_8250
358c2ecf20Sopenharmony_ci	switch (state) {
368c2ecf20Sopenharmony_ci	case 0:
378c2ecf20Sopenharmony_ci		alchemy_uart_enable(CPHYSADDR(port->membase));
388c2ecf20Sopenharmony_ci		serial8250_do_pm(port, state, old_state);
398c2ecf20Sopenharmony_ci		break;
408c2ecf20Sopenharmony_ci	case 3:		/* power off */
418c2ecf20Sopenharmony_ci		serial8250_do_pm(port, state, old_state);
428c2ecf20Sopenharmony_ci		alchemy_uart_disable(CPHYSADDR(port->membase));
438c2ecf20Sopenharmony_ci		break;
448c2ecf20Sopenharmony_ci	default:
458c2ecf20Sopenharmony_ci		serial8250_do_pm(port, state, old_state);
468c2ecf20Sopenharmony_ci		break;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci#endif
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define PORT(_base, _irq)					\
528c2ecf20Sopenharmony_ci	{							\
538c2ecf20Sopenharmony_ci		.mapbase	= _base,			\
548c2ecf20Sopenharmony_ci		.irq		= _irq,				\
558c2ecf20Sopenharmony_ci		.regshift	= 2,				\
568c2ecf20Sopenharmony_ci		.iotype		= UPIO_AU,			\
578c2ecf20Sopenharmony_ci		.flags		= UPF_SKIP_TEST | UPF_IOREMAP | \
588c2ecf20Sopenharmony_ci				  UPF_FIXED_TYPE,		\
598c2ecf20Sopenharmony_ci		.type		= PORT_16550A,			\
608c2ecf20Sopenharmony_ci		.pm		= alchemy_8250_pm,		\
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic struct plat_serial8250_port au1x00_uart_data[][4] __initdata = {
648c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1000] = {
658c2ecf20Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1000_UART0_INT),
668c2ecf20Sopenharmony_ci		PORT(AU1000_UART1_PHYS_ADDR, AU1000_UART1_INT),
678c2ecf20Sopenharmony_ci		PORT(AU1000_UART2_PHYS_ADDR, AU1000_UART2_INT),
688c2ecf20Sopenharmony_ci		PORT(AU1000_UART3_PHYS_ADDR, AU1000_UART3_INT),
698c2ecf20Sopenharmony_ci	},
708c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1500] = {
718c2ecf20Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1500_UART0_INT),
728c2ecf20Sopenharmony_ci		PORT(AU1000_UART3_PHYS_ADDR, AU1500_UART3_INT),
738c2ecf20Sopenharmony_ci	},
748c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1100] = {
758c2ecf20Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1100_UART0_INT),
768c2ecf20Sopenharmony_ci		PORT(AU1000_UART1_PHYS_ADDR, AU1100_UART1_INT),
778c2ecf20Sopenharmony_ci		PORT(AU1000_UART3_PHYS_ADDR, AU1100_UART3_INT),
788c2ecf20Sopenharmony_ci	},
798c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1550] = {
808c2ecf20Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1550_UART0_INT),
818c2ecf20Sopenharmony_ci		PORT(AU1000_UART1_PHYS_ADDR, AU1550_UART1_INT),
828c2ecf20Sopenharmony_ci		PORT(AU1000_UART3_PHYS_ADDR, AU1550_UART3_INT),
838c2ecf20Sopenharmony_ci	},
848c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1200] = {
858c2ecf20Sopenharmony_ci		PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT),
868c2ecf20Sopenharmony_ci		PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT),
878c2ecf20Sopenharmony_ci	},
888c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1300] = {
898c2ecf20Sopenharmony_ci		PORT(AU1300_UART0_PHYS_ADDR, AU1300_UART0_INT),
908c2ecf20Sopenharmony_ci		PORT(AU1300_UART1_PHYS_ADDR, AU1300_UART1_INT),
918c2ecf20Sopenharmony_ci		PORT(AU1300_UART2_PHYS_ADDR, AU1300_UART2_INT),
928c2ecf20Sopenharmony_ci		PORT(AU1300_UART3_PHYS_ADDR, AU1300_UART3_INT),
938c2ecf20Sopenharmony_ci	},
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic struct platform_device au1xx0_uart_device = {
978c2ecf20Sopenharmony_ci	.name			= "serial8250",
988c2ecf20Sopenharmony_ci	.id			= PLAT8250_DEV_AU1X00,
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void __init alchemy_setup_uarts(int ctype)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	long uartclk;
1048c2ecf20Sopenharmony_ci	int s = sizeof(struct plat_serial8250_port);
1058c2ecf20Sopenharmony_ci	int c = alchemy_get_uarts(ctype);
1068c2ecf20Sopenharmony_ci	struct plat_serial8250_port *ports;
1078c2ecf20Sopenharmony_ci	struct clk *clk = clk_get(NULL, ALCHEMY_PERIPH_CLK);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (IS_ERR(clk))
1108c2ecf20Sopenharmony_ci		return;
1118c2ecf20Sopenharmony_ci	if (clk_prepare_enable(clk)) {
1128c2ecf20Sopenharmony_ci		clk_put(clk);
1138c2ecf20Sopenharmony_ci		return;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci	uartclk = clk_get_rate(clk);
1168c2ecf20Sopenharmony_ci	clk_put(clk);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	ports = kcalloc(s, (c + 1), GFP_KERNEL);
1198c2ecf20Sopenharmony_ci	if (!ports) {
1208c2ecf20Sopenharmony_ci		printk(KERN_INFO "Alchemy: no memory for UART data\n");
1218c2ecf20Sopenharmony_ci		return;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci	memcpy(ports, au1x00_uart_data[ctype], s * c);
1248c2ecf20Sopenharmony_ci	au1xx0_uart_device.dev.platform_data = ports;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* Fill up uartclk. */
1278c2ecf20Sopenharmony_ci	for (s = 0; s < c; s++)
1288c2ecf20Sopenharmony_ci		ports[s].uartclk = uartclk;
1298c2ecf20Sopenharmony_ci	if (platform_device_register(&au1xx0_uart_device))
1308c2ecf20Sopenharmony_ci		printk(KERN_INFO "Alchemy: failed to register UARTs\n");
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic u64 alchemy_all_dmamask = DMA_BIT_MASK(32);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* Power on callback for the ehci platform driver */
1378c2ecf20Sopenharmony_cistatic int alchemy_ehci_power_on(struct platform_device *pdev)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	return alchemy_usb_control(ALCHEMY_USB_EHCI0, 1);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/* Power off/suspend callback for the ehci platform driver */
1438c2ecf20Sopenharmony_cistatic void alchemy_ehci_power_off(struct platform_device *pdev)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic struct usb_ehci_pdata alchemy_ehci_pdata = {
1498c2ecf20Sopenharmony_ci	.no_io_watchdog = 1,
1508c2ecf20Sopenharmony_ci	.power_on	= alchemy_ehci_power_on,
1518c2ecf20Sopenharmony_ci	.power_off	= alchemy_ehci_power_off,
1528c2ecf20Sopenharmony_ci	.power_suspend	= alchemy_ehci_power_off,
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/* Power on callback for the ohci platform driver */
1568c2ecf20Sopenharmony_cistatic int alchemy_ohci_power_on(struct platform_device *pdev)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	int unit;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	unit = (pdev->id == 1) ?
1618c2ecf20Sopenharmony_ci		ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	return alchemy_usb_control(unit, 1);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/* Power off/suspend callback for the ohci platform driver */
1678c2ecf20Sopenharmony_cistatic void alchemy_ohci_power_off(struct platform_device *pdev)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	int unit;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	unit = (pdev->id == 1) ?
1728c2ecf20Sopenharmony_ci		ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	alchemy_usb_control(unit, 0);
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic struct usb_ohci_pdata alchemy_ohci_pdata = {
1788c2ecf20Sopenharmony_ci	.power_on		= alchemy_ohci_power_on,
1798c2ecf20Sopenharmony_ci	.power_off		= alchemy_ohci_power_off,
1808c2ecf20Sopenharmony_ci	.power_suspend		= alchemy_ohci_power_off,
1818c2ecf20Sopenharmony_ci};
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_cistatic unsigned long alchemy_ohci_data[][2] __initdata = {
1848c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1000] = { AU1000_USB_OHCI_PHYS_ADDR, AU1000_USB_HOST_INT },
1858c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1500] = { AU1000_USB_OHCI_PHYS_ADDR, AU1500_USB_HOST_INT },
1868c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1100] = { AU1000_USB_OHCI_PHYS_ADDR, AU1100_USB_HOST_INT },
1878c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1550] = { AU1550_USB_OHCI_PHYS_ADDR, AU1550_USB_HOST_INT },
1888c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1200] = { AU1200_USB_OHCI_PHYS_ADDR, AU1200_USB_INT },
1898c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1300] = { AU1300_USB_OHCI0_PHYS_ADDR, AU1300_USB_INT },
1908c2ecf20Sopenharmony_ci};
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic unsigned long alchemy_ehci_data[][2] __initdata = {
1938c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1200] = { AU1200_USB_EHCI_PHYS_ADDR, AU1200_USB_INT },
1948c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1300] = { AU1300_USB_EHCI_PHYS_ADDR, AU1300_USB_INT },
1958c2ecf20Sopenharmony_ci};
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int __init _new_usbres(struct resource **r, struct platform_device **d)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	*r = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
2008c2ecf20Sopenharmony_ci	if (!*r)
2018c2ecf20Sopenharmony_ci		return -ENOMEM;
2028c2ecf20Sopenharmony_ci	*d = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
2038c2ecf20Sopenharmony_ci	if (!*d) {
2048c2ecf20Sopenharmony_ci		kfree(*r);
2058c2ecf20Sopenharmony_ci		return -ENOMEM;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	(*d)->dev.coherent_dma_mask = DMA_BIT_MASK(32);
2098c2ecf20Sopenharmony_ci	(*d)->num_resources = 2;
2108c2ecf20Sopenharmony_ci	(*d)->resource = *r;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic void __init alchemy_setup_usb(int ctype)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct resource *res;
2188c2ecf20Sopenharmony_ci	struct platform_device *pdev;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/* setup OHCI0.  Every variant has one */
2218c2ecf20Sopenharmony_ci	if (_new_usbres(&res, &pdev))
2228c2ecf20Sopenharmony_ci		return;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	res[0].start = alchemy_ohci_data[ctype][0];
2258c2ecf20Sopenharmony_ci	res[0].end = res[0].start + 0x100 - 1;
2268c2ecf20Sopenharmony_ci	res[0].flags = IORESOURCE_MEM;
2278c2ecf20Sopenharmony_ci	res[1].start = alchemy_ohci_data[ctype][1];
2288c2ecf20Sopenharmony_ci	res[1].end = res[1].start;
2298c2ecf20Sopenharmony_ci	res[1].flags = IORESOURCE_IRQ;
2308c2ecf20Sopenharmony_ci	pdev->name = "ohci-platform";
2318c2ecf20Sopenharmony_ci	pdev->id = 0;
2328c2ecf20Sopenharmony_ci	pdev->dev.dma_mask = &alchemy_all_dmamask;
2338c2ecf20Sopenharmony_ci	pdev->dev.platform_data = &alchemy_ohci_pdata;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (platform_device_register(pdev))
2368c2ecf20Sopenharmony_ci		printk(KERN_INFO "Alchemy USB: cannot add OHCI0\n");
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* setup EHCI0: Au1200/Au1300 */
2408c2ecf20Sopenharmony_ci	if ((ctype == ALCHEMY_CPU_AU1200) || (ctype == ALCHEMY_CPU_AU1300)) {
2418c2ecf20Sopenharmony_ci		if (_new_usbres(&res, &pdev))
2428c2ecf20Sopenharmony_ci			return;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci		res[0].start = alchemy_ehci_data[ctype][0];
2458c2ecf20Sopenharmony_ci		res[0].end = res[0].start + 0x100 - 1;
2468c2ecf20Sopenharmony_ci		res[0].flags = IORESOURCE_MEM;
2478c2ecf20Sopenharmony_ci		res[1].start = alchemy_ehci_data[ctype][1];
2488c2ecf20Sopenharmony_ci		res[1].end = res[1].start;
2498c2ecf20Sopenharmony_ci		res[1].flags = IORESOURCE_IRQ;
2508c2ecf20Sopenharmony_ci		pdev->name = "ehci-platform";
2518c2ecf20Sopenharmony_ci		pdev->id = 0;
2528c2ecf20Sopenharmony_ci		pdev->dev.dma_mask = &alchemy_all_dmamask;
2538c2ecf20Sopenharmony_ci		pdev->dev.platform_data = &alchemy_ehci_pdata;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		if (platform_device_register(pdev))
2568c2ecf20Sopenharmony_ci			printk(KERN_INFO "Alchemy USB: cannot add EHCI0\n");
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* Au1300: OHCI1 */
2608c2ecf20Sopenharmony_ci	if (ctype == ALCHEMY_CPU_AU1300) {
2618c2ecf20Sopenharmony_ci		if (_new_usbres(&res, &pdev))
2628c2ecf20Sopenharmony_ci			return;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		res[0].start = AU1300_USB_OHCI1_PHYS_ADDR;
2658c2ecf20Sopenharmony_ci		res[0].end = res[0].start + 0x100 - 1;
2668c2ecf20Sopenharmony_ci		res[0].flags = IORESOURCE_MEM;
2678c2ecf20Sopenharmony_ci		res[1].start = AU1300_USB_INT;
2688c2ecf20Sopenharmony_ci		res[1].end = res[1].start;
2698c2ecf20Sopenharmony_ci		res[1].flags = IORESOURCE_IRQ;
2708c2ecf20Sopenharmony_ci		pdev->name = "ohci-platform";
2718c2ecf20Sopenharmony_ci		pdev->id = 1;
2728c2ecf20Sopenharmony_ci		pdev->dev.dma_mask = &alchemy_all_dmamask;
2738c2ecf20Sopenharmony_ci		pdev->dev.platform_data = &alchemy_ohci_pdata;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		if (platform_device_register(pdev))
2768c2ecf20Sopenharmony_ci			printk(KERN_INFO "Alchemy USB: cannot add OHCI1\n");
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci/* Macro to help defining the Ethernet MAC resources */
2818c2ecf20Sopenharmony_ci#define MAC_RES_COUNT	4	/* MAC regs, MAC en, MAC INT, MACDMA regs */
2828c2ecf20Sopenharmony_ci#define MAC_RES(_base, _enable, _irq, _macdma)		\
2838c2ecf20Sopenharmony_ci	{						\
2848c2ecf20Sopenharmony_ci		.start	= _base,			\
2858c2ecf20Sopenharmony_ci		.end	= _base + 0xffff,		\
2868c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,		\
2878c2ecf20Sopenharmony_ci	},						\
2888c2ecf20Sopenharmony_ci	{						\
2898c2ecf20Sopenharmony_ci		.start	= _enable,			\
2908c2ecf20Sopenharmony_ci		.end	= _enable + 0x3,		\
2918c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,		\
2928c2ecf20Sopenharmony_ci	},						\
2938c2ecf20Sopenharmony_ci	{						\
2948c2ecf20Sopenharmony_ci		.start	= _irq,				\
2958c2ecf20Sopenharmony_ci		.end	= _irq,				\
2968c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_IRQ		\
2978c2ecf20Sopenharmony_ci	},						\
2988c2ecf20Sopenharmony_ci	{						\
2998c2ecf20Sopenharmony_ci		.start	= _macdma,			\
3008c2ecf20Sopenharmony_ci		.end	= _macdma + 0x1ff,		\
3018c2ecf20Sopenharmony_ci		.flags	= IORESOURCE_MEM,		\
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = {
3058c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1000] = {
3068c2ecf20Sopenharmony_ci		MAC_RES(AU1000_MAC0_PHYS_ADDR,
3078c2ecf20Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR,
3088c2ecf20Sopenharmony_ci			AU1000_MAC0_DMA_INT,
3098c2ecf20Sopenharmony_ci			AU1000_MACDMA0_PHYS_ADDR)
3108c2ecf20Sopenharmony_ci	},
3118c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1500] = {
3128c2ecf20Sopenharmony_ci		MAC_RES(AU1500_MAC0_PHYS_ADDR,
3138c2ecf20Sopenharmony_ci			AU1500_MACEN_PHYS_ADDR,
3148c2ecf20Sopenharmony_ci			AU1500_MAC0_DMA_INT,
3158c2ecf20Sopenharmony_ci			AU1000_MACDMA0_PHYS_ADDR)
3168c2ecf20Sopenharmony_ci	},
3178c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1100] = {
3188c2ecf20Sopenharmony_ci		MAC_RES(AU1000_MAC0_PHYS_ADDR,
3198c2ecf20Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR,
3208c2ecf20Sopenharmony_ci			AU1100_MAC0_DMA_INT,
3218c2ecf20Sopenharmony_ci			AU1000_MACDMA0_PHYS_ADDR)
3228c2ecf20Sopenharmony_ci	},
3238c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1550] = {
3248c2ecf20Sopenharmony_ci		MAC_RES(AU1000_MAC0_PHYS_ADDR,
3258c2ecf20Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR,
3268c2ecf20Sopenharmony_ci			AU1550_MAC0_DMA_INT,
3278c2ecf20Sopenharmony_ci			AU1000_MACDMA0_PHYS_ADDR)
3288c2ecf20Sopenharmony_ci	},
3298c2ecf20Sopenharmony_ci};
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic struct au1000_eth_platform_data au1xxx_eth0_platform_data = {
3328c2ecf20Sopenharmony_ci	.phy1_search_mac0 = 1,
3338c2ecf20Sopenharmony_ci};
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic struct platform_device au1xxx_eth0_device = {
3368c2ecf20Sopenharmony_ci	.name		= "au1000-eth",
3378c2ecf20Sopenharmony_ci	.id		= 0,
3388c2ecf20Sopenharmony_ci	.num_resources	= MAC_RES_COUNT,
3398c2ecf20Sopenharmony_ci	.dev = {
3408c2ecf20Sopenharmony_ci		.dma_mask               = &alchemy_all_dmamask,
3418c2ecf20Sopenharmony_ci		.coherent_dma_mask      = DMA_BIT_MASK(32),
3428c2ecf20Sopenharmony_ci		.platform_data          = &au1xxx_eth0_platform_data,
3438c2ecf20Sopenharmony_ci	},
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = {
3478c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1000] = {
3488c2ecf20Sopenharmony_ci		MAC_RES(AU1000_MAC1_PHYS_ADDR,
3498c2ecf20Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR + 4,
3508c2ecf20Sopenharmony_ci			AU1000_MAC1_DMA_INT,
3518c2ecf20Sopenharmony_ci			AU1000_MACDMA1_PHYS_ADDR)
3528c2ecf20Sopenharmony_ci	},
3538c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1500] = {
3548c2ecf20Sopenharmony_ci		MAC_RES(AU1500_MAC1_PHYS_ADDR,
3558c2ecf20Sopenharmony_ci			AU1500_MACEN_PHYS_ADDR + 4,
3568c2ecf20Sopenharmony_ci			AU1500_MAC1_DMA_INT,
3578c2ecf20Sopenharmony_ci			AU1000_MACDMA1_PHYS_ADDR)
3588c2ecf20Sopenharmony_ci	},
3598c2ecf20Sopenharmony_ci	[ALCHEMY_CPU_AU1550] = {
3608c2ecf20Sopenharmony_ci		MAC_RES(AU1000_MAC1_PHYS_ADDR,
3618c2ecf20Sopenharmony_ci			AU1000_MACEN_PHYS_ADDR + 4,
3628c2ecf20Sopenharmony_ci			AU1550_MAC1_DMA_INT,
3638c2ecf20Sopenharmony_ci			AU1000_MACDMA1_PHYS_ADDR)
3648c2ecf20Sopenharmony_ci	},
3658c2ecf20Sopenharmony_ci};
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_cistatic struct au1000_eth_platform_data au1xxx_eth1_platform_data = {
3688c2ecf20Sopenharmony_ci	.phy1_search_mac0 = 1,
3698c2ecf20Sopenharmony_ci};
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic struct platform_device au1xxx_eth1_device = {
3728c2ecf20Sopenharmony_ci	.name		= "au1000-eth",
3738c2ecf20Sopenharmony_ci	.id		= 1,
3748c2ecf20Sopenharmony_ci	.num_resources	= MAC_RES_COUNT,
3758c2ecf20Sopenharmony_ci	.dev = {
3768c2ecf20Sopenharmony_ci		.dma_mask               = &alchemy_all_dmamask,
3778c2ecf20Sopenharmony_ci		.coherent_dma_mask      = DMA_BIT_MASK(32),
3788c2ecf20Sopenharmony_ci		.platform_data          = &au1xxx_eth1_platform_data,
3798c2ecf20Sopenharmony_ci	},
3808c2ecf20Sopenharmony_ci};
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_civoid __init au1xxx_override_eth_cfg(unsigned int port,
3838c2ecf20Sopenharmony_ci			struct au1000_eth_platform_data *eth_data)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	if (!eth_data || port > 1)
3868c2ecf20Sopenharmony_ci		return;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (port == 0)
3898c2ecf20Sopenharmony_ci		memcpy(&au1xxx_eth0_platform_data, eth_data,
3908c2ecf20Sopenharmony_ci			sizeof(struct au1000_eth_platform_data));
3918c2ecf20Sopenharmony_ci	else
3928c2ecf20Sopenharmony_ci		memcpy(&au1xxx_eth1_platform_data, eth_data,
3938c2ecf20Sopenharmony_ci			sizeof(struct au1000_eth_platform_data));
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic void __init alchemy_setup_macs(int ctype)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	int ret, i;
3998c2ecf20Sopenharmony_ci	unsigned char ethaddr[6];
4008c2ecf20Sopenharmony_ci	struct resource *macres;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/* Handle 1st MAC */
4038c2ecf20Sopenharmony_ci	if (alchemy_get_macs(ctype) < 1)
4048c2ecf20Sopenharmony_ci		return;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	macres = kmemdup(au1xxx_eth0_resources[ctype],
4078c2ecf20Sopenharmony_ci			 sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
4088c2ecf20Sopenharmony_ci	if (!macres) {
4098c2ecf20Sopenharmony_ci		printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n");
4108c2ecf20Sopenharmony_ci		return;
4118c2ecf20Sopenharmony_ci	}
4128c2ecf20Sopenharmony_ci	au1xxx_eth0_device.resource = macres;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	i = prom_get_ethernet_addr(ethaddr);
4158c2ecf20Sopenharmony_ci	if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac))
4168c2ecf20Sopenharmony_ci		memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	ret = platform_device_register(&au1xxx_eth0_device);
4198c2ecf20Sopenharmony_ci	if (ret)
4208c2ecf20Sopenharmony_ci		printk(KERN_INFO "Alchemy: failed to register MAC0\n");
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/* Handle 2nd MAC */
4248c2ecf20Sopenharmony_ci	if (alchemy_get_macs(ctype) < 2)
4258c2ecf20Sopenharmony_ci		return;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	macres = kmemdup(au1xxx_eth1_resources[ctype],
4288c2ecf20Sopenharmony_ci			 sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
4298c2ecf20Sopenharmony_ci	if (!macres) {
4308c2ecf20Sopenharmony_ci		printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n");
4318c2ecf20Sopenharmony_ci		return;
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci	au1xxx_eth1_device.resource = macres;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	ethaddr[5] += 1;	/* next addr for 2nd MAC */
4368c2ecf20Sopenharmony_ci	if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac))
4378c2ecf20Sopenharmony_ci		memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* Register second MAC if enabled in pinfunc */
4408c2ecf20Sopenharmony_ci	if (!(alchemy_rdsys(AU1000_SYS_PINFUNC) & SYS_PF_NI2)) {
4418c2ecf20Sopenharmony_ci		ret = platform_device_register(&au1xxx_eth1_device);
4428c2ecf20Sopenharmony_ci		if (ret)
4438c2ecf20Sopenharmony_ci			printk(KERN_INFO "Alchemy: failed to register MAC1\n");
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic int __init au1xxx_platform_init(void)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	int ctype = alchemy_get_cputype();
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	alchemy_setup_uarts(ctype);
4528c2ecf20Sopenharmony_ci	alchemy_setup_macs(ctype);
4538c2ecf20Sopenharmony_ci	alchemy_setup_usb(ctype);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return 0;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ciarch_initcall(au1xxx_platform_init);
459