Path: blob/master/arch/mips/alchemy/common/platform.c
10819 views
/*1* Platform device support for Au1x00 SoCs.2*3* Copyright 2004, Matt Porter <[email protected]>4*5* (C) Copyright Embedded Alley Solutions, Inc 20056* Author: Pantelis Antoniou <[email protected]>7*8* This file is licensed under the terms of the GNU General Public9* License version 2. This program is licensed "as is" without any10* warranty of any kind, whether express or implied.11*/1213#include <linux/dma-mapping.h>14#include <linux/etherdevice.h>15#include <linux/init.h>16#include <linux/platform_device.h>17#include <linux/serial_8250.h>18#include <linux/slab.h>1920#include <asm/mach-au1x00/au1xxx.h>21#include <asm/mach-au1x00/au1xxx_dbdma.h>22#include <asm/mach-au1x00/au1100_mmc.h>23#include <asm/mach-au1x00/au1xxx_eth.h>2425#include <prom.h>2627static void alchemy_8250_pm(struct uart_port *port, unsigned int state,28unsigned int old_state)29{30#ifdef CONFIG_SERIAL_825031switch (state) {32case 0:33alchemy_uart_enable(CPHYSADDR(port->membase));34serial8250_do_pm(port, state, old_state);35break;36case 3: /* power off */37serial8250_do_pm(port, state, old_state);38alchemy_uart_disable(CPHYSADDR(port->membase));39break;40default:41serial8250_do_pm(port, state, old_state);42break;43}44#endif45}4647#define PORT(_base, _irq) \48{ \49.mapbase = _base, \50.irq = _irq, \51.regshift = 2, \52.iotype = UPIO_AU, \53.flags = UPF_SKIP_TEST | UPF_IOREMAP | \54UPF_FIXED_TYPE, \55.type = PORT_16550A, \56.pm = alchemy_8250_pm, \57}5859static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = {60[ALCHEMY_CPU_AU1000] = {61PORT(AU1000_UART0_PHYS_ADDR, AU1000_UART0_INT),62PORT(AU1000_UART1_PHYS_ADDR, AU1000_UART1_INT),63PORT(AU1000_UART2_PHYS_ADDR, AU1000_UART2_INT),64PORT(AU1000_UART3_PHYS_ADDR, AU1000_UART3_INT),65},66[ALCHEMY_CPU_AU1500] = {67PORT(AU1000_UART0_PHYS_ADDR, AU1500_UART0_INT),68PORT(AU1000_UART3_PHYS_ADDR, AU1500_UART3_INT),69},70[ALCHEMY_CPU_AU1100] = {71PORT(AU1000_UART0_PHYS_ADDR, AU1100_UART0_INT),72PORT(AU1000_UART1_PHYS_ADDR, AU1100_UART1_INT),73PORT(AU1000_UART3_PHYS_ADDR, AU1100_UART3_INT),74},75[ALCHEMY_CPU_AU1550] = {76PORT(AU1000_UART0_PHYS_ADDR, AU1550_UART0_INT),77PORT(AU1000_UART1_PHYS_ADDR, AU1550_UART1_INT),78PORT(AU1000_UART3_PHYS_ADDR, AU1550_UART3_INT),79},80[ALCHEMY_CPU_AU1200] = {81PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT),82PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT),83},84};8586static struct platform_device au1xx0_uart_device = {87.name = "serial8250",88.id = PLAT8250_DEV_AU1X00,89};9091static void __init alchemy_setup_uarts(int ctype)92{93unsigned int uartclk = get_au1x00_uart_baud_base() * 16;94int s = sizeof(struct plat_serial8250_port);95int c = alchemy_get_uarts(ctype);96struct plat_serial8250_port *ports;9798ports = kzalloc(s * (c + 1), GFP_KERNEL);99if (!ports) {100printk(KERN_INFO "Alchemy: no memory for UART data\n");101return;102}103memcpy(ports, au1x00_uart_data[ctype], s * c);104au1xx0_uart_device.dev.platform_data = ports;105106/* Fill up uartclk. */107for (s = 0; s < c; s++)108ports[s].uartclk = uartclk;109if (platform_device_register(&au1xx0_uart_device))110printk(KERN_INFO "Alchemy: failed to register UARTs\n");111}112113/* OHCI (USB full speed host controller) */114static struct resource au1xxx_usb_ohci_resources[] = {115[0] = {116.start = USB_OHCI_BASE,117.end = USB_OHCI_BASE + USB_OHCI_LEN - 1,118.flags = IORESOURCE_MEM,119},120[1] = {121.start = FOR_PLATFORM_C_USB_HOST_INT,122.end = FOR_PLATFORM_C_USB_HOST_INT,123.flags = IORESOURCE_IRQ,124},125};126127/* The dmamask must be set for OHCI to work */128static u64 ohci_dmamask = DMA_BIT_MASK(32);129130static struct platform_device au1xxx_usb_ohci_device = {131.name = "au1xxx-ohci",132.id = 0,133.dev = {134.dma_mask = &ohci_dmamask,135.coherent_dma_mask = DMA_BIT_MASK(32),136},137.num_resources = ARRAY_SIZE(au1xxx_usb_ohci_resources),138.resource = au1xxx_usb_ohci_resources,139};140141/*** AU1100 LCD controller ***/142143#ifdef CONFIG_FB_AU1100144static struct resource au1100_lcd_resources[] = {145[0] = {146.start = LCD_PHYS_ADDR,147.end = LCD_PHYS_ADDR + 0x800 - 1,148.flags = IORESOURCE_MEM,149},150[1] = {151.start = AU1100_LCD_INT,152.end = AU1100_LCD_INT,153.flags = IORESOURCE_IRQ,154}155};156157static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32);158159static struct platform_device au1100_lcd_device = {160.name = "au1100-lcd",161.id = 0,162.dev = {163.dma_mask = &au1100_lcd_dmamask,164.coherent_dma_mask = DMA_BIT_MASK(32),165},166.num_resources = ARRAY_SIZE(au1100_lcd_resources),167.resource = au1100_lcd_resources,168};169#endif170171#ifdef CONFIG_SOC_AU1200172/* EHCI (USB high speed host controller) */173static struct resource au1xxx_usb_ehci_resources[] = {174[0] = {175.start = USB_EHCI_BASE,176.end = USB_EHCI_BASE + USB_EHCI_LEN - 1,177.flags = IORESOURCE_MEM,178},179[1] = {180.start = AU1200_USB_INT,181.end = AU1200_USB_INT,182.flags = IORESOURCE_IRQ,183},184};185186static u64 ehci_dmamask = DMA_BIT_MASK(32);187188static struct platform_device au1xxx_usb_ehci_device = {189.name = "au1xxx-ehci",190.id = 0,191.dev = {192.dma_mask = &ehci_dmamask,193.coherent_dma_mask = DMA_BIT_MASK(32),194},195.num_resources = ARRAY_SIZE(au1xxx_usb_ehci_resources),196.resource = au1xxx_usb_ehci_resources,197};198199/* Au1200 UDC (USB gadget controller) */200static struct resource au1xxx_usb_gdt_resources[] = {201[0] = {202.start = USB_UDC_BASE,203.end = USB_UDC_BASE + USB_UDC_LEN - 1,204.flags = IORESOURCE_MEM,205},206[1] = {207.start = AU1200_USB_INT,208.end = AU1200_USB_INT,209.flags = IORESOURCE_IRQ,210},211};212213static u64 udc_dmamask = DMA_BIT_MASK(32);214215static struct platform_device au1xxx_usb_gdt_device = {216.name = "au1xxx-udc",217.id = 0,218.dev = {219.dma_mask = &udc_dmamask,220.coherent_dma_mask = DMA_BIT_MASK(32),221},222.num_resources = ARRAY_SIZE(au1xxx_usb_gdt_resources),223.resource = au1xxx_usb_gdt_resources,224};225226/* Au1200 UOC (USB OTG controller) */227static struct resource au1xxx_usb_otg_resources[] = {228[0] = {229.start = USB_UOC_BASE,230.end = USB_UOC_BASE + USB_UOC_LEN - 1,231.flags = IORESOURCE_MEM,232},233[1] = {234.start = AU1200_USB_INT,235.end = AU1200_USB_INT,236.flags = IORESOURCE_IRQ,237},238};239240static u64 uoc_dmamask = DMA_BIT_MASK(32);241242static struct platform_device au1xxx_usb_otg_device = {243.name = "au1xxx-uoc",244.id = 0,245.dev = {246.dma_mask = &uoc_dmamask,247.coherent_dma_mask = DMA_BIT_MASK(32),248},249.num_resources = ARRAY_SIZE(au1xxx_usb_otg_resources),250.resource = au1xxx_usb_otg_resources,251};252253static struct resource au1200_lcd_resources[] = {254[0] = {255.start = LCD_PHYS_ADDR,256.end = LCD_PHYS_ADDR + 0x800 - 1,257.flags = IORESOURCE_MEM,258},259[1] = {260.start = AU1200_LCD_INT,261.end = AU1200_LCD_INT,262.flags = IORESOURCE_IRQ,263}264};265266static u64 au1200_lcd_dmamask = DMA_BIT_MASK(32);267268static struct platform_device au1200_lcd_device = {269.name = "au1200-lcd",270.id = 0,271.dev = {272.dma_mask = &au1200_lcd_dmamask,273.coherent_dma_mask = DMA_BIT_MASK(32),274},275.num_resources = ARRAY_SIZE(au1200_lcd_resources),276.resource = au1200_lcd_resources,277};278279static u64 au1xxx_mmc_dmamask = DMA_BIT_MASK(32);280281extern struct au1xmmc_platform_data au1xmmc_platdata[2];282283static struct resource au1200_mmc0_resources[] = {284[0] = {285.start = AU1100_SD0_PHYS_ADDR,286.end = AU1100_SD0_PHYS_ADDR + 0xfff,287.flags = IORESOURCE_MEM,288},289[1] = {290.start = AU1200_SD_INT,291.end = AU1200_SD_INT,292.flags = IORESOURCE_IRQ,293},294[2] = {295.start = DSCR_CMD0_SDMS_TX0,296.end = DSCR_CMD0_SDMS_TX0,297.flags = IORESOURCE_DMA,298},299[3] = {300.start = DSCR_CMD0_SDMS_RX0,301.end = DSCR_CMD0_SDMS_RX0,302.flags = IORESOURCE_DMA,303}304};305306static struct platform_device au1200_mmc0_device = {307.name = "au1xxx-mmc",308.id = 0,309.dev = {310.dma_mask = &au1xxx_mmc_dmamask,311.coherent_dma_mask = DMA_BIT_MASK(32),312.platform_data = &au1xmmc_platdata[0],313},314.num_resources = ARRAY_SIZE(au1200_mmc0_resources),315.resource = au1200_mmc0_resources,316};317318#ifndef CONFIG_MIPS_DB1200319static struct resource au1200_mmc1_resources[] = {320[0] = {321.start = AU1100_SD1_PHYS_ADDR,322.end = AU1100_SD1_PHYS_ADDR + 0xfff,323.flags = IORESOURCE_MEM,324},325[1] = {326.start = AU1200_SD_INT,327.end = AU1200_SD_INT,328.flags = IORESOURCE_IRQ,329},330[2] = {331.start = DSCR_CMD0_SDMS_TX1,332.end = DSCR_CMD0_SDMS_TX1,333.flags = IORESOURCE_DMA,334},335[3] = {336.start = DSCR_CMD0_SDMS_RX1,337.end = DSCR_CMD0_SDMS_RX1,338.flags = IORESOURCE_DMA,339}340};341342static struct platform_device au1200_mmc1_device = {343.name = "au1xxx-mmc",344.id = 1,345.dev = {346.dma_mask = &au1xxx_mmc_dmamask,347.coherent_dma_mask = DMA_BIT_MASK(32),348.platform_data = &au1xmmc_platdata[1],349},350.num_resources = ARRAY_SIZE(au1200_mmc1_resources),351.resource = au1200_mmc1_resources,352};353#endif /* #ifndef CONFIG_MIPS_DB1200 */354#endif /* #ifdef CONFIG_SOC_AU1200 */355356/* All Alchemy demoboards with I2C have this #define in their headers */357#ifdef SMBUS_PSC_BASE358static struct resource pbdb_smbus_resources[] = {359{360.start = CPHYSADDR(SMBUS_PSC_BASE),361.end = CPHYSADDR(SMBUS_PSC_BASE + 0xfffff),362.flags = IORESOURCE_MEM,363},364};365366static struct platform_device pbdb_smbus_device = {367.name = "au1xpsc_smbus",368.id = 0, /* bus number */369.num_resources = ARRAY_SIZE(pbdb_smbus_resources),370.resource = pbdb_smbus_resources,371};372#endif373374/* Macro to help defining the Ethernet MAC resources */375#define MAC_RES_COUNT 3 /* MAC regs base, MAC enable reg, MAC INT */376#define MAC_RES(_base, _enable, _irq) \377{ \378.start = _base, \379.end = _base + 0xffff, \380.flags = IORESOURCE_MEM, \381}, \382{ \383.start = _enable, \384.end = _enable + 0x3, \385.flags = IORESOURCE_MEM, \386}, \387{ \388.start = _irq, \389.end = _irq, \390.flags = IORESOURCE_IRQ \391}392393static struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = {394[ALCHEMY_CPU_AU1000] = {395MAC_RES(AU1000_MAC0_PHYS_ADDR,396AU1000_MACEN_PHYS_ADDR,397AU1000_MAC0_DMA_INT)398},399[ALCHEMY_CPU_AU1500] = {400MAC_RES(AU1500_MAC0_PHYS_ADDR,401AU1500_MACEN_PHYS_ADDR,402AU1500_MAC0_DMA_INT)403},404[ALCHEMY_CPU_AU1100] = {405MAC_RES(AU1000_MAC0_PHYS_ADDR,406AU1000_MACEN_PHYS_ADDR,407AU1100_MAC0_DMA_INT)408},409[ALCHEMY_CPU_AU1550] = {410MAC_RES(AU1000_MAC0_PHYS_ADDR,411AU1000_MACEN_PHYS_ADDR,412AU1550_MAC0_DMA_INT)413},414};415416static struct au1000_eth_platform_data au1xxx_eth0_platform_data = {417.phy1_search_mac0 = 1,418};419420static struct platform_device au1xxx_eth0_device = {421.name = "au1000-eth",422.id = 0,423.num_resources = MAC_RES_COUNT,424.dev.platform_data = &au1xxx_eth0_platform_data,425};426427static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = {428[ALCHEMY_CPU_AU1000] = {429MAC_RES(AU1000_MAC1_PHYS_ADDR,430AU1000_MACEN_PHYS_ADDR + 4,431AU1000_MAC1_DMA_INT)432},433[ALCHEMY_CPU_AU1500] = {434MAC_RES(AU1500_MAC1_PHYS_ADDR,435AU1500_MACEN_PHYS_ADDR + 4,436AU1500_MAC1_DMA_INT)437},438[ALCHEMY_CPU_AU1550] = {439MAC_RES(AU1000_MAC1_PHYS_ADDR,440AU1000_MACEN_PHYS_ADDR + 4,441AU1550_MAC1_DMA_INT)442},443};444445static struct au1000_eth_platform_data au1xxx_eth1_platform_data = {446.phy1_search_mac0 = 1,447};448449static struct platform_device au1xxx_eth1_device = {450.name = "au1000-eth",451.id = 1,452.num_resources = MAC_RES_COUNT,453.dev.platform_data = &au1xxx_eth1_platform_data,454};455456void __init au1xxx_override_eth_cfg(unsigned int port,457struct au1000_eth_platform_data *eth_data)458{459if (!eth_data || port > 1)460return;461462if (port == 0)463memcpy(&au1xxx_eth0_platform_data, eth_data,464sizeof(struct au1000_eth_platform_data));465else466memcpy(&au1xxx_eth1_platform_data, eth_data,467sizeof(struct au1000_eth_platform_data));468}469470static void __init alchemy_setup_macs(int ctype)471{472int ret, i;473unsigned char ethaddr[6];474struct resource *macres;475476/* Handle 1st MAC */477if (alchemy_get_macs(ctype) < 1)478return;479480macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);481if (!macres) {482printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n");483return;484}485memcpy(macres, au1xxx_eth0_resources[ctype],486sizeof(struct resource) * MAC_RES_COUNT);487au1xxx_eth0_device.resource = macres;488489i = prom_get_ethernet_addr(ethaddr);490if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac))491memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6);492493ret = platform_device_register(&au1xxx_eth0_device);494if (!ret)495printk(KERN_INFO "Alchemy: failed to register MAC0\n");496497498/* Handle 2nd MAC */499if (alchemy_get_macs(ctype) < 2)500return;501502macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);503if (!macres) {504printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n");505return;506}507memcpy(macres, au1xxx_eth1_resources[ctype],508sizeof(struct resource) * MAC_RES_COUNT);509au1xxx_eth1_device.resource = macres;510511ethaddr[5] += 1; /* next addr for 2nd MAC */512if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac))513memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6);514515/* Register second MAC if enabled in pinfunc */516if (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) {517ret = platform_device_register(&au1xxx_eth1_device);518if (ret)519printk(KERN_INFO "Alchemy: failed to register MAC1\n");520}521}522523static struct platform_device *au1xxx_platform_devices[] __initdata = {524&au1xxx_usb_ohci_device,525#ifdef CONFIG_FB_AU1100526&au1100_lcd_device,527#endif528#ifdef CONFIG_SOC_AU1200529&au1xxx_usb_ehci_device,530&au1xxx_usb_gdt_device,531&au1xxx_usb_otg_device,532&au1200_lcd_device,533&au1200_mmc0_device,534#ifndef CONFIG_MIPS_DB1200535&au1200_mmc1_device,536#endif537#endif538#ifdef SMBUS_PSC_BASE539&pbdb_smbus_device,540#endif541};542543static int __init au1xxx_platform_init(void)544{545int err, ctype = alchemy_get_cputype();546547alchemy_setup_uarts(ctype);548alchemy_setup_macs(ctype);549550err = platform_add_devices(au1xxx_platform_devices,551ARRAY_SIZE(au1xxx_platform_devices));552return err;553}554555arch_initcall(au1xxx_platform_init);556557558