diff options
Diffstat (limited to 'arch/mips/alchemy/common')
| -rw-r--r-- | arch/mips/alchemy/common/Makefile | 10 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/clocks.c | 2 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/dbdma.c | 367 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/dma.c | 106 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/gpiolib.c (renamed from arch/mips/alchemy/common/gpiolib-au1000.c) | 89 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/irq.c | 1208 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/pci.c | 104 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/platform.c | 625 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/power.c | 72 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/setup.c | 26 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/sleeper.S | 97 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/time.c | 36 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/usb.c | 593 | ||||
| -rw-r--r-- | arch/mips/alchemy/common/vss.c | 84 | 
14 files changed, 2182 insertions, 1237 deletions
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index 27811fe341d..cb83d8d21ae 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile @@ -6,15 +6,9 @@  #  obj-y += prom.o time.o clocks.o platform.o power.o setup.o \ -	sleeper.o dma.o dbdma.o - -obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += irq.o +	sleeper.o dma.o dbdma.o vss.o irq.o usb.o  # optional gpiolib support  ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) - ifeq ($(CONFIG_GPIOLIB),y) -  obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += gpiolib-au1000.o - endif + obj-$(CONFIG_GPIOLIB) += gpiolib.o  endif - -obj-$(CONFIG_PCI)		+= pci.o diff --git a/arch/mips/alchemy/common/clocks.c b/arch/mips/alchemy/common/clocks.c index af0fe41055a..f38298a8b98 100644 --- a/arch/mips/alchemy/common/clocks.c +++ b/arch/mips/alchemy/common/clocks.c @@ -75,7 +75,7 @@ void set_au1x00_uart_baud_base(unsigned long new_baud_base)   * counter, if it exists.  If we don't have an accurate processor   * speed, all of the peripherals that derive their clocks based on   * this advertised speed will introduce error and sometimes not work - * properly.  This function is futher convoluted to still allow configurations + * properly.  This function is further convoluted to still allow configurations   * to do that in case they have really, really old silicon with a   * write-only PLL register.			-- Dan   */ diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c index ca0506a8585..19d5642c16d 100644 --- a/arch/mips/alchemy/common/dbdma.c +++ b/arch/mips/alchemy/common/dbdma.c @@ -36,12 +36,10 @@  #include <linux/spinlock.h>  #include <linux/interrupt.h>  #include <linux/module.h> -#include <linux/sysdev.h> +#include <linux/syscore_ops.h>  #include <asm/mach-au1x00/au1000.h>  #include <asm/mach-au1x00/au1xxx_dbdma.h> -#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) -  /*   * The Descriptor Based DMA supports up to 16 channels.   * @@ -58,123 +56,144 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);  /* I couldn't find a macro that did this... */  #define ALIGN_ADDR(x, a)	((((u32)(x)) + (a-1)) & ~(a-1)) -static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; +static dbdma_global_t *dbdma_gptr = +			(dbdma_global_t *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);  static int dbdma_initialized; -static dbdev_tab_t dbdev_tab[] = { -#ifdef CONFIG_SOC_AU1550 +static dbdev_tab_t *dbdev_tab; + +static dbdev_tab_t au1550_dbdev_tab[] __initdata = {  	/* UARTS */ -	{ DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, -	{ DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 }, -	{ DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x11400004, 0, 0 }, -	{ DSCR_CMD0_UART3_RX, DEV_FLAGS_IN, 0, 8, 0x11400000, 0, 0 }, +	{ AU1550_DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, +	{ AU1550_DSCR_CMD0_UART0_RX, DEV_FLAGS_IN,  0, 8, 0x11100000, 0, 0 }, +	{ AU1550_DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8, 0x11400004, 0, 0 }, +	{ AU1550_DSCR_CMD0_UART3_RX, DEV_FLAGS_IN,  0, 8, 0x11400000, 0, 0 },  	/* EXT DMA */ -	{ DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_DMA_REQ2, 0, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_DMA_REQ3, 0, 0, 0, 0x00000000, 0, 0 }, +	{ AU1550_DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, +	{ AU1550_DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, +	{ AU1550_DSCR_CMD0_DMA_REQ2, 0, 0, 0, 0x00000000, 0, 0 }, +	{ AU1550_DSCR_CMD0_DMA_REQ3, 0, 0, 0, 0x00000000, 0, 0 },  	/* USB DEV */ -	{ DSCR_CMD0_USBDEV_RX0, DEV_FLAGS_IN, 4, 8, 0x10200000, 0, 0 }, -	{ DSCR_CMD0_USBDEV_TX0, DEV_FLAGS_OUT, 4, 8, 0x10200004, 0, 0 }, -	{ DSCR_CMD0_USBDEV_TX1, DEV_FLAGS_OUT, 4, 8, 0x10200008, 0, 0 }, -	{ DSCR_CMD0_USBDEV_TX2, DEV_FLAGS_OUT, 4, 8, 0x1020000c, 0, 0 }, -	{ DSCR_CMD0_USBDEV_RX3, DEV_FLAGS_IN, 4, 8, 0x10200010, 0, 0 }, -	{ DSCR_CMD0_USBDEV_RX4, DEV_FLAGS_IN, 4, 8, 0x10200014, 0, 0 }, +	{ AU1550_DSCR_CMD0_USBDEV_RX0, DEV_FLAGS_IN,  4, 8, 0x10200000, 0, 0 }, +	{ AU1550_DSCR_CMD0_USBDEV_TX0, DEV_FLAGS_OUT, 4, 8, 0x10200004, 0, 0 }, +	{ AU1550_DSCR_CMD0_USBDEV_TX1, DEV_FLAGS_OUT, 4, 8, 0x10200008, 0, 0 }, +	{ AU1550_DSCR_CMD0_USBDEV_TX2, DEV_FLAGS_OUT, 4, 8, 0x1020000c, 0, 0 }, +	{ AU1550_DSCR_CMD0_USBDEV_RX3, DEV_FLAGS_IN,  4, 8, 0x10200010, 0, 0 }, +	{ AU1550_DSCR_CMD0_USBDEV_RX4, DEV_FLAGS_IN,  4, 8, 0x10200014, 0, 0 }, + +	/* PSCs */ +	{ AU1550_DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 }, +	{ AU1550_DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN,  0, 0, 0x11a0001c, 0, 0 }, +	{ AU1550_DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 }, +	{ AU1550_DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN,  0, 0, 0x11b0001c, 0, 0 }, +	{ AU1550_DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 0, 0x10a0001c, 0, 0 }, +	{ AU1550_DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN,  0, 0, 0x10a0001c, 0, 0 }, +	{ AU1550_DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 0, 0x10b0001c, 0, 0 }, +	{ AU1550_DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN,  0, 0, 0x10b0001c, 0, 0 }, + +	{ AU1550_DSCR_CMD0_PCI_WRITE,  0, 0, 0, 0x00000000, 0, 0 },  /* PCI */ +	{ AU1550_DSCR_CMD0_NAND_FLASH, 0, 0, 0, 0x00000000, 0, 0 }, /* NAND */ -	/* PSC 0 */ -	{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 }, -	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 }, +	/* MAC 0 */ +	{ AU1550_DSCR_CMD0_MAC0_RX, DEV_FLAGS_IN,  0, 0, 0x00000000, 0, 0 }, +	{ AU1550_DSCR_CMD0_MAC0_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, -	/* PSC 1 */ -	{ DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 }, -	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 }, +	/* MAC 1 */ +	{ AU1550_DSCR_CMD0_MAC1_RX, DEV_FLAGS_IN,  0, 0, 0x00000000, 0, 0 }, +	{ AU1550_DSCR_CMD0_MAC1_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, -	/* PSC 2 */ -	{ DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT, 0, 0, 0x10a0001c, 0, 0 }, -	{ DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN, 0, 0, 0x10a0001c, 0, 0 }, +	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ DSCR_CMD0_ALWAYS,   DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +}; -	/* PSC 3 */ -	{ DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT, 0, 0, 0x10b0001c, 0, 0 }, -	{ DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN, 0, 0, 0x10b0001c, 0, 0 }, +static dbdev_tab_t au1200_dbdev_tab[] __initdata = { +	{ AU1200_DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, +	{ AU1200_DSCR_CMD0_UART0_RX, DEV_FLAGS_IN,  0, 8, 0x11100000, 0, 0 }, +	{ AU1200_DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x11200004, 0, 0 }, +	{ AU1200_DSCR_CMD0_UART1_RX, DEV_FLAGS_IN,  0, 8, 0x11200000, 0, 0 }, -	{ DSCR_CMD0_PCI_WRITE, 0, 0, 0, 0x00000000, 0, 0 },	/* PCI */ -	{ DSCR_CMD0_NAND_FLASH, 0, 0, 0, 0x00000000, 0, 0 },	/* NAND */ +	{ AU1200_DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, +	{ AU1200_DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, -	/* MAC 0 */ -	{ DSCR_CMD0_MAC0_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_MAC0_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, +	{ AU1200_DSCR_CMD0_MAE_BE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ AU1200_DSCR_CMD0_MAE_FE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ AU1200_DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ AU1200_DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, -	/* MAC 1 */ -	{ DSCR_CMD0_MAC1_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_MAC1_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, +	{ AU1200_DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 }, +	{ AU1200_DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN,  4, 8, 0x10600004, 0, 0 }, +	{ AU1200_DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 }, +	{ AU1200_DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN,  4, 8, 0x10680004, 0, 0 }, + +	{ AU1200_DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 }, +	{ AU1200_DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 }, + +	{ AU1200_DSCR_CMD0_PSC0_TX,   DEV_FLAGS_OUT, 0, 16, 0x11a0001c, 0, 0 }, +	{ AU1200_DSCR_CMD0_PSC0_RX,   DEV_FLAGS_IN,  0, 16, 0x11a0001c, 0, 0 }, +	{ AU1200_DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ AU1200_DSCR_CMD0_PSC1_TX,   DEV_FLAGS_OUT, 0, 16, 0x11b0001c, 0, 0 }, +	{ AU1200_DSCR_CMD0_PSC1_RX,   DEV_FLAGS_IN,  0, 16, 0x11b0001c, 0, 0 }, +	{ AU1200_DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + +	{ AU1200_DSCR_CMD0_CIM_RXA,  DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 }, +	{ AU1200_DSCR_CMD0_CIM_RXB,  DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 }, +	{ AU1200_DSCR_CMD0_CIM_RXC,  DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 }, +	{ AU1200_DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, -#endif /* CONFIG_SOC_AU1550 */ +	{ AU1200_DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, -#ifdef CONFIG_SOC_AU1200 -	{ DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8, 0x11100004, 0, 0 }, -	{ DSCR_CMD0_UART0_RX, DEV_FLAGS_IN, 0, 8, 0x11100000, 0, 0 }, -	{ DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8, 0x11200004, 0, 0 }, -	{ DSCR_CMD0_UART1_RX, DEV_FLAGS_IN, 0, 8, 0x11200000, 0, 0 }, +	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ DSCR_CMD0_ALWAYS,   DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +}; -	{ DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 }, +static dbdev_tab_t au1300_dbdev_tab[] __initdata = { +	{ AU1300_DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8,  0x10100004, 0, 0 }, +	{ AU1300_DSCR_CMD0_UART0_RX, DEV_FLAGS_IN,  0, 8,  0x10100000, 0, 0 }, +	{ AU1300_DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8,  0x10101004, 0, 0 }, +	{ AU1300_DSCR_CMD0_UART1_RX, DEV_FLAGS_IN,  0, 8,  0x10101000, 0, 0 }, +	{ AU1300_DSCR_CMD0_UART2_TX, DEV_FLAGS_OUT, 0, 8,  0x10102004, 0, 0 }, +	{ AU1300_DSCR_CMD0_UART2_RX, DEV_FLAGS_IN,  0, 8,  0x10102000, 0, 0 }, +	{ AU1300_DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8,  0x10103004, 0, 0 }, +	{ AU1300_DSCR_CMD0_UART3_RX, DEV_FLAGS_IN,  0, 8,  0x10103000, 0, 0 }, -	{ DSCR_CMD0_MAE_BE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_MAE_FE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ AU1300_DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8,  0x10600000, 0, 0 }, +	{ AU1300_DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN,  4, 8,  0x10600004, 0, 0 }, +	{ AU1300_DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 8, 8,  0x10601000, 0, 0 }, +	{ AU1300_DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN,  8, 8,  0x10601004, 0, 0 }, -	{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 }, -	{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 }, -	{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 }, -	{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 }, +	{ AU1300_DSCR_CMD0_AES_RX, DEV_FLAGS_IN ,   4, 32, 0x10300008, 0, 0 }, +	{ AU1300_DSCR_CMD0_AES_TX, DEV_FLAGS_OUT,   4, 32, 0x10300004, 0, 0 }, -	{ DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 }, -	{ DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 }, +	{ AU1300_DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0001c, 0, 0 }, +	{ AU1300_DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN,   0, 16, 0x10a0001c, 0, 0 }, +	{ AU1300_DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0101c, 0, 0 }, +	{ AU1300_DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN,   0, 16, 0x10a0101c, 0, 0 }, +	{ AU1300_DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0201c, 0, 0 }, +	{ AU1300_DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN,   0, 16, 0x10a0201c, 0, 0 }, +	{ AU1300_DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0301c, 0, 0 }, +	{ AU1300_DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN,   0, 16, 0x10a0301c, 0, 0 }, -	{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 16, 0x11a0001c, 0, 0 }, -	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 16, 0x11a0001c, 0, 0 }, -	{ DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ AU1300_DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE,   0, 0,  0x00000000, 0, 0 }, +	{ AU1300_DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 16, 0x11b0001c, 0, 0 }, -	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 16, 0x11b0001c, 0, 0 }, -	{ DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ AU1300_DSCR_CMD0_SDMS_TX2, DEV_FLAGS_OUT, 4, 8,  0x10602000, 0, 0 }, +	{ AU1300_DSCR_CMD0_SDMS_RX2, DEV_FLAGS_IN,  4, 8,  0x10602004, 0, 0 }, -	{ DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 }, -	{ DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 }, -	{ DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 }, -	{ DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, +	{ AU1300_DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, +	{ AU1300_DSCR_CMD0_UDMA, DEV_FLAGS_ANYUSE,  0, 32, 0x14001810, 0, 0 }, -#endif /* CONFIG_SOC_AU1200 */ +	{ AU1300_DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 }, +	{ AU1300_DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },  	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, -	{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, - -	/* Provide 16 user definable device types */ -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, -	{ ~0, 0, 0, 0, 0, 0, 0 }, +	{ DSCR_CMD0_ALWAYS,   DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },  }; -#define DBDEV_TAB_SIZE	ARRAY_SIZE(dbdev_tab) - +/* 32 predefined plus 32 custom */ +#define DBDEV_TAB_SIZE		64  static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS]; @@ -233,7 +252,7 @@ EXPORT_SYMBOL(au1xxx_ddma_del_device);  u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,         void (*callback)(int, void *), void *callparam)  { -	unsigned long   flags; +	unsigned long	flags;  	u32		used, chan;  	u32		dcp;  	int		i; @@ -299,7 +318,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,  	if (ctp != NULL) {  		memset(ctp, 0, sizeof(chan_tab_t));  		ctp->chan_index = chan = i; -		dcp = DDMA_CHANNEL_BASE; +		dcp = KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR);  		dcp += (0x0100 * chan);  		ctp->chan_ptr = (au1x_dma_chan_t *)dcp;  		cp = (au1x_dma_chan_t *)dcp; @@ -493,7 +512,7 @@ u32 au1xxx_dbdma_ring_alloc(u32 chanid, int entries)  		break;  	} -	/* If source input is FIFO, set static address.	*/ +	/* If source input is FIFO, set static address. */  	if (stp->dev_flags & DEV_FLAGS_IN) {  		if (stp->dev_flags & DEV_FLAGS_BURSTABLE)  			src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST); @@ -616,7 +635,7 @@ u32 au1xxx_dbdma_put_source(u32 chanid, dma_addr_t buf, int nbytes, u32 flags)  	dma_cache_wback_inv((unsigned long)dp, sizeof(*dp));  	ctp->chan_ptr->ddma_dbell = 0; -	/* Get next descriptor pointer.	*/ +	/* Get next descriptor pointer. */  	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));  	/* Return something non-zero. */ @@ -678,7 +697,7 @@ u32 au1xxx_dbdma_put_dest(u32 chanid, dma_addr_t buf, int nbytes, u32 flags)  	dma_cache_wback_inv((unsigned long)dp, sizeof(*dp));  	ctp->chan_ptr->ddma_dbell = 0; -	/* Get next descriptor pointer.	*/ +	/* Get next descriptor pointer. */  	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));  	/* Return something non-zero. */ @@ -723,7 +742,7 @@ u32 au1xxx_dbdma_get_dest(u32 chanid, void **buf, int *nbytes)  	*nbytes = dp->dscr_cmd1;  	rv = dp->dscr_stat; -	/* Get next descriptor pointer.	*/ +	/* Get next descriptor pointer. */  	ctp->get_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));  	/* Return something non-zero. */ @@ -872,7 +891,7 @@ void au1xxx_dbdma_dump(u32 chanid)  	chan_tab_t	 *ctp;  	au1x_ddma_desc_t *dp;  	dbdev_tab_t	 *stp, *dtp; -	au1x_dma_chan_t  *cp; +	au1x_dma_chan_t	 *cp;  	u32 i		 = 0;  	ctp = *((chan_tab_t **)chanid); @@ -950,7 +969,7 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)  	dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V;  	ctp->chan_ptr->ddma_dbell = 0; -	/* Get next descriptor pointer.	*/ +	/* Get next descriptor pointer. */  	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));  	/* Return something non-zero. */ @@ -958,141 +977,113 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)  } -struct alchemy_dbdma_sysdev { -	struct sys_device sysdev; -	u32 pm_regs[NUM_DBDMA_CHANS + 1][6]; -}; +static unsigned long alchemy_dbdma_pm_data[NUM_DBDMA_CHANS + 1][6]; -static int alchemy_dbdma_suspend(struct sys_device *dev, -				 pm_message_t state) +static int alchemy_dbdma_suspend(void)  { -	struct alchemy_dbdma_sysdev *sdev = -		container_of(dev, struct alchemy_dbdma_sysdev, sysdev);  	int i; -	u32 addr; +	void __iomem *addr; -	addr = DDMA_GLOBAL_BASE; -	sdev->pm_regs[0][0] = au_readl(addr + 0x00); -	sdev->pm_regs[0][1] = au_readl(addr + 0x04); -	sdev->pm_regs[0][2] = au_readl(addr + 0x08); -	sdev->pm_regs[0][3] = au_readl(addr + 0x0c); +	addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); +	alchemy_dbdma_pm_data[0][0] = __raw_readl(addr + 0x00); +	alchemy_dbdma_pm_data[0][1] = __raw_readl(addr + 0x04); +	alchemy_dbdma_pm_data[0][2] = __raw_readl(addr + 0x08); +	alchemy_dbdma_pm_data[0][3] = __raw_readl(addr + 0x0c);  	/* save channel configurations */ -	for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) { -		sdev->pm_regs[i][0] = au_readl(addr + 0x00); -		sdev->pm_regs[i][1] = au_readl(addr + 0x04); -		sdev->pm_regs[i][2] = au_readl(addr + 0x08); -		sdev->pm_regs[i][3] = au_readl(addr + 0x0c); -		sdev->pm_regs[i][4] = au_readl(addr + 0x10); -		sdev->pm_regs[i][5] = au_readl(addr + 0x14); +	addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); +	for (i = 1; i <= NUM_DBDMA_CHANS; i++) { +		alchemy_dbdma_pm_data[i][0] = __raw_readl(addr + 0x00); +		alchemy_dbdma_pm_data[i][1] = __raw_readl(addr + 0x04); +		alchemy_dbdma_pm_data[i][2] = __raw_readl(addr + 0x08); +		alchemy_dbdma_pm_data[i][3] = __raw_readl(addr + 0x0c); +		alchemy_dbdma_pm_data[i][4] = __raw_readl(addr + 0x10); +		alchemy_dbdma_pm_data[i][5] = __raw_readl(addr + 0x14);  		/* halt channel */ -		au_writel(sdev->pm_regs[i][0] & ~1, addr + 0x00); -		au_sync(); -		while (!(au_readl(addr + 0x14) & 1)) -			au_sync(); +		__raw_writel(alchemy_dbdma_pm_data[i][0] & ~1, addr + 0x00); +		wmb(); +		while (!(__raw_readl(addr + 0x14) & 1)) +			wmb();  		addr += 0x100;	/* next channel base */  	}  	/* disable channel interrupts */ -	au_writel(0, DDMA_GLOBAL_BASE + 0x0c); -	au_sync(); +	addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); +	__raw_writel(0, addr + 0x0c); +	wmb();  	return 0;  } -static int alchemy_dbdma_resume(struct sys_device *dev) +static void alchemy_dbdma_resume(void)  { -	struct alchemy_dbdma_sysdev *sdev = -		container_of(dev, struct alchemy_dbdma_sysdev, sysdev);  	int i; -	u32 addr; +	void __iomem *addr; -	addr = DDMA_GLOBAL_BASE; -	au_writel(sdev->pm_regs[0][0], addr + 0x00); -	au_writel(sdev->pm_regs[0][1], addr + 0x04); -	au_writel(sdev->pm_regs[0][2], addr + 0x08); -	au_writel(sdev->pm_regs[0][3], addr + 0x0c); +	addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR); +	__raw_writel(alchemy_dbdma_pm_data[0][0], addr + 0x00); +	__raw_writel(alchemy_dbdma_pm_data[0][1], addr + 0x04); +	__raw_writel(alchemy_dbdma_pm_data[0][2], addr + 0x08); +	__raw_writel(alchemy_dbdma_pm_data[0][3], addr + 0x0c);  	/* restore channel configurations */ -	for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) { -		au_writel(sdev->pm_regs[i][0], addr + 0x00); -		au_writel(sdev->pm_regs[i][1], addr + 0x04); -		au_writel(sdev->pm_regs[i][2], addr + 0x08); -		au_writel(sdev->pm_regs[i][3], addr + 0x0c); -		au_writel(sdev->pm_regs[i][4], addr + 0x10); -		au_writel(sdev->pm_regs[i][5], addr + 0x14); -		au_sync(); +	addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); +	for (i = 1; i <= NUM_DBDMA_CHANS; i++) { +		__raw_writel(alchemy_dbdma_pm_data[i][0], addr + 0x00); +		__raw_writel(alchemy_dbdma_pm_data[i][1], addr + 0x04); +		__raw_writel(alchemy_dbdma_pm_data[i][2], addr + 0x08); +		__raw_writel(alchemy_dbdma_pm_data[i][3], addr + 0x0c); +		__raw_writel(alchemy_dbdma_pm_data[i][4], addr + 0x10); +		__raw_writel(alchemy_dbdma_pm_data[i][5], addr + 0x14); +		wmb();  		addr += 0x100;	/* next channel base */  	} - -	return 0;  } -static struct sysdev_class alchemy_dbdma_sysdev_class = { -	.name		= "dbdma", +static struct syscore_ops alchemy_dbdma_syscore_ops = {  	.suspend	= alchemy_dbdma_suspend,  	.resume		= alchemy_dbdma_resume,  }; -static int __init alchemy_dbdma_sysdev_init(void) +static int __init dbdma_setup(unsigned int irq, dbdev_tab_t *idtable)  { -	struct alchemy_dbdma_sysdev *sdev;  	int ret; -	ret = sysdev_class_register(&alchemy_dbdma_sysdev_class); -	if (ret) -		return ret; - -	sdev = kzalloc(sizeof(struct alchemy_dbdma_sysdev), GFP_KERNEL); -	if (!sdev) +	dbdev_tab = kzalloc(sizeof(dbdev_tab_t) * DBDEV_TAB_SIZE, GFP_KERNEL); +	if (!dbdev_tab)  		return -ENOMEM; -	sdev->sysdev.id = -1; -	sdev->sysdev.cls = &alchemy_dbdma_sysdev_class; -	ret = sysdev_register(&sdev->sysdev); -	if (ret) -		kfree(sdev); - -	return ret; -} - -static int __init au1xxx_dbdma_init(void) -{ -	int irq_nr, ret; +	memcpy(dbdev_tab, idtable, 32 * sizeof(dbdev_tab_t)); +	for (ret = 32; ret < DBDEV_TAB_SIZE; ret++) +		dbdev_tab[ret].dev_id = ~0;  	dbdma_gptr->ddma_config = 0;  	dbdma_gptr->ddma_throttle = 0;  	dbdma_gptr->ddma_inten = 0xffff;  	au_sync(); -	switch (alchemy_get_cputype()) { -	case ALCHEMY_CPU_AU1550: -		irq_nr = AU1550_DDMA_INT; -		break; -	case ALCHEMY_CPU_AU1200: -		irq_nr = AU1200_DDMA_INT; -		break; -	default: -		return -ENODEV; -	} - -	ret = request_irq(irq_nr, dbdma_interrupt, IRQF_DISABLED, -			"Au1xxx dbdma", (void *)dbdma_gptr); +	ret = request_irq(irq, dbdma_interrupt, 0, "dbdma", (void *)dbdma_gptr);  	if (ret)  		printk(KERN_ERR "Cannot grab DBDMA interrupt!\n");  	else {  		dbdma_initialized = 1; -		printk(KERN_INFO "Alchemy DBDMA initialized\n"); -		ret = alchemy_dbdma_sysdev_init(); -		if (ret) { -			printk(KERN_ERR "DBDMA PM init failed\n"); -			ret = 0; -		} +		register_syscore_ops(&alchemy_dbdma_syscore_ops);  	}  	return ret;  } -subsys_initcall(au1xxx_dbdma_init); -#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */ +static int __init alchemy_dbdma_init(void) +{ +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1550: +		return dbdma_setup(AU1550_DDMA_INT, au1550_dbdev_tab); +	case ALCHEMY_CPU_AU1200: +		return dbdma_setup(AU1200_DDMA_INT, au1200_dbdev_tab); +	case ALCHEMY_CPU_AU1300: +		return dbdma_setup(AU1300_DDMA_INT, au1300_dbdev_tab); +	} +	return 0; +} +subsys_initcall(alchemy_dbdma_init); diff --git a/arch/mips/alchemy/common/dma.c b/arch/mips/alchemy/common/dma.c index d5278877891..9b624e2c0fc 100644 --- a/arch/mips/alchemy/common/dma.c +++ b/arch/mips/alchemy/common/dma.c @@ -40,8 +40,6 @@  #include <asm/mach-au1x00/au1000.h>  #include <asm/mach-au1x00/au1000_dma.h> -#if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1500) || \ -    defined(CONFIG_SOC_AU1100)  /*   * A note on resource allocation:   * @@ -58,6 +56,9 @@   * returned from request_dma.   */ +/* DMA Channel register block spacing */ +#define DMA_CHANNEL_LEN		0x00000100 +  DEFINE_SPINLOCK(au1000_dma_spin_lock);  struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = { @@ -77,22 +78,23 @@ static const struct dma_dev {  	unsigned int fifo_addr;  	unsigned int dma_mode;  } dma_dev_table[DMA_NUM_DEV] = { -	{UART0_ADDR + UART_TX, 0}, -	{UART0_ADDR + UART_RX, 0}, -	{0, 0}, -	{0, 0}, -	{AC97C_DATA, DMA_DW16 },          /* coherent */ -	{AC97C_DATA, DMA_DR | DMA_DW16 }, /* coherent */ -	{UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC}, -	{UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC}, -	{USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC}, -	{USBD_EP0WR, DMA_DW8 | DMA_NC}, -	{USBD_EP2WR, DMA_DW8 | DMA_NC}, -	{USBD_EP3WR, DMA_DW8 | DMA_NC}, -	{USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC}, -	{USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC}, -	{I2S_DATA, DMA_DW32 | DMA_NC}, -	{I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC} +	{ AU1000_UART0_PHYS_ADDR + 0x04, DMA_DW8 },		/* UART0_TX */ +	{ AU1000_UART0_PHYS_ADDR + 0x00, DMA_DW8 | DMA_DR },	/* UART0_RX */ +	{ 0, 0 },	/* DMA_REQ0 */ +	{ 0, 0 },	/* DMA_REQ1 */ +	{ AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 },		/* AC97 TX c */ +	{ AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 | DMA_DR },	/* AC97 RX c */ +	{ AU1000_UART3_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC },	/* UART3_TX */ +	{ AU1000_UART3_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* UART3_RX */ +	{ AU1000_USB_UDC_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* EP0RD */ +	{ AU1000_USB_UDC_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC }, /* EP0WR */ +	{ AU1000_USB_UDC_PHYS_ADDR + 0x08, DMA_DW8 | DMA_NC }, /* EP2WR */ +	{ AU1000_USB_UDC_PHYS_ADDR + 0x0c, DMA_DW8 | DMA_NC }, /* EP3WR */ +	{ AU1000_USB_UDC_PHYS_ADDR + 0x10, DMA_DW8 | DMA_NC | DMA_DR }, /* EP4RD */ +	{ AU1000_USB_UDC_PHYS_ADDR + 0x14, DMA_DW8 | DMA_NC | DMA_DR }, /* EP5RD */ +	/* on Au1500, these 2 are DMA_REQ2/3 (GPIO208/209) instead! */ +	{ AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC},	/* I2S TX */ +	{ AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC | DMA_DR}, /* I2S RX */  };  int au1000_dma_read_proc(char *buf, char **start, off_t fpos, @@ -123,10 +125,10 @@ int au1000_dma_read_proc(char *buf, char **start, off_t fpos,  /* Device FIFO addresses and default DMA modes - 2nd bank */  static const struct dma_dev dma_dev_table_bank2[DMA_NUM_DEV_BANK2] = { -	{ SD0_XMIT_FIFO, DMA_DS | DMA_DW8 },		/* coherent */ -	{ SD0_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 },	/* coherent */ -	{ SD1_XMIT_FIFO, DMA_DS | DMA_DW8 },		/* coherent */ -	{ SD1_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 }	/* coherent */ +	{ AU1100_SD0_PHYS_ADDR + 0x00, DMA_DS | DMA_DW8 },		/* coherent */ +	{ AU1100_SD0_PHYS_ADDR + 0x04, DMA_DS | DMA_DW8 | DMA_DR },	/* coherent */ +	{ AU1100_SD1_PHYS_ADDR + 0x00, DMA_DS | DMA_DW8 },		/* coherent */ +	{ AU1100_SD1_PHYS_ADDR + 0x04, DMA_DS | DMA_DW8 | DMA_DR }	/* coherent */  };  void dump_au1000_dma_channel(unsigned int dmanr) @@ -166,13 +168,13 @@ int request_au1000_dma(int dev_id, const char *dev_str,  	const struct dma_dev *dev;  	int i, ret; -#if defined(CONFIG_SOC_AU1100) -	if (dev_id < 0 || dev_id >= (DMA_NUM_DEV + DMA_NUM_DEV_BANK2)) -		return -EINVAL; -#else -	if (dev_id < 0 || dev_id >= DMA_NUM_DEV) -		return -EINVAL; -#endif +	if (alchemy_get_cputype() == ALCHEMY_CPU_AU1100) { +		if (dev_id < 0 || dev_id >= (DMA_NUM_DEV + DMA_NUM_DEV_BANK2)) +			return -EINVAL; +	} else { +		if (dev_id < 0 || dev_id >= DMA_NUM_DEV) +			return -EINVAL; +	}  	for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++)  		if (au1000_dma_table[i].dev_id < 0) @@ -202,7 +204,7 @@ int request_au1000_dma(int dev_id, const char *dev_str,  	}  	/* fill it in */ -	chan->io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN; +	chan->io = KSEG1ADDR(AU1000_DMA_PHYS_ADDR) + i * DMA_CHANNEL_LEN;  	chan->dev_id = dev_id;  	chan->dev_str = dev_str;  	chan->fifo_addr = dev->fifo_addr; @@ -235,30 +237,28 @@ EXPORT_SYMBOL(free_au1000_dma);  static int __init au1000_dma_init(void)  { -        int base, i; - -        switch (alchemy_get_cputype()) { -        case ALCHEMY_CPU_AU1000: -                base = AU1000_DMA_INT_BASE; -                break; -        case ALCHEMY_CPU_AU1500: -                base = AU1500_DMA_INT_BASE; -                break; -        case ALCHEMY_CPU_AU1100: -                base = AU1100_DMA_INT_BASE; -                break; -        default: -                goto out; -        } - -        for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) -                au1000_dma_table[i].irq = base + i; - -        printk(KERN_INFO "Alchemy DMA initialized\n"); +	int base, i; + +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1000: +		base = AU1000_DMA_INT_BASE; +		break; +	case ALCHEMY_CPU_AU1500: +		base = AU1500_DMA_INT_BASE; +		break; +	case ALCHEMY_CPU_AU1100: +		base = AU1100_DMA_INT_BASE; +		break; +	default: +		goto out; +	} + +	for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++) +		au1000_dma_table[i].irq = base + i; + +	printk(KERN_INFO "Alchemy DMA initialized\n");  out: -        return 0; +	return 0;  }  arch_initcall(au1000_dma_init); - -#endif /* AU1000 AU1500 AU1100 */ diff --git a/arch/mips/alchemy/common/gpiolib-au1000.c b/arch/mips/alchemy/common/gpiolib.c index c8e1a94d4a9..f9bc4f52044 100644 --- a/arch/mips/alchemy/common/gpiolib-au1000.c +++ b/arch/mips/alchemy/common/gpiolib.c @@ -1,6 +1,6 @@  /*   *  Copyright (C) 2007-2009, OpenWrt.org, Florian Fainelli <florian@openwrt.org> - *  	GPIOLIB support for Au1000, Au1500, Au1100, Au1550 and Au12x0. + *	GPIOLIB support for Alchemy chips.   *   *  This program is free software; you can redistribute	 it and/or modify it   *  under  the terms of	 the GNU General  Public License as published by the @@ -23,18 +23,20 @@   *  675 Mass Ave, Cambridge, MA 02139, USA.   *   *  Notes : - * 	au1000 SoC have only one GPIO block : GPIO1 - * 	Au1100, Au15x0, Au12x0 have a second one : GPIO2 + *	This file must ONLY be built when CONFIG_GPIOLIB=y and + *	 CONFIG_ALCHEMY_GPIO_INDIRECT=n, otherwise compilation will fail! + *	au1000 SoC have only one GPIO block : GPIO1 + *	Au1100, Au15x0, Au12x0 have a second one : GPIO2 + *	Au1300 is totally different: 1 block with up to 128 GPIOs   */ +#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/types.h> -#include <linux/platform_device.h>  #include <linux/gpio.h> - -#include <asm/mach-au1x00/au1000.h> -#include <asm/mach-au1x00/gpio.h> +#include <asm/mach-au1x00/gpio-au1000.h> +#include <asm/mach-au1x00/gpio-au1300.h>  static int gpio2_get(struct gpio_chip *chip, unsigned offset)  { @@ -104,23 +106,70 @@ struct gpio_chip alchemy_gpio_chip[] = {  		.ngpio			= ALCHEMY_GPIO1_NUM,  	},  	[1] = { -		.label                  = "alchemy-gpio2", -		.direction_input        = gpio2_direction_input, -		.direction_output       = gpio2_direction_output, -		.get                    = gpio2_get, -		.set                    = gpio2_set, +		.label			= "alchemy-gpio2", +		.direction_input	= gpio2_direction_input, +		.direction_output	= gpio2_direction_output, +		.get			= gpio2_get, +		.set			= gpio2_set,  		.to_irq			= gpio2_to_irq, -		.base                   = ALCHEMY_GPIO2_BASE, -		.ngpio                  = ALCHEMY_GPIO2_NUM, +		.base			= ALCHEMY_GPIO2_BASE, +		.ngpio			= ALCHEMY_GPIO2_NUM,  	},  }; -static int __init alchemy_gpiolib_init(void) +static int alchemy_gpic_get(struct gpio_chip *chip, unsigned int off)  { -	gpiochip_add(&alchemy_gpio_chip[0]); -	if (alchemy_get_cputype() != ALCHEMY_CPU_AU1000) -		gpiochip_add(&alchemy_gpio_chip[1]); +	return au1300_gpio_get_value(off + AU1300_GPIO_BASE); +} + +static void alchemy_gpic_set(struct gpio_chip *chip, unsigned int off, int v) +{ +	au1300_gpio_set_value(off + AU1300_GPIO_BASE, v); +} -	return 0; +static int alchemy_gpic_dir_input(struct gpio_chip *chip, unsigned int off) +{ +	return au1300_gpio_direction_input(off + AU1300_GPIO_BASE); +} + +static int alchemy_gpic_dir_output(struct gpio_chip *chip, unsigned int off, +				   int v) +{ +	return au1300_gpio_direction_output(off + AU1300_GPIO_BASE, v); +} + +static int alchemy_gpic_gpio_to_irq(struct gpio_chip *chip, unsigned int off) +{ +	return au1300_gpio_to_irq(off + AU1300_GPIO_BASE); +} + +static struct gpio_chip au1300_gpiochip = { +	.label			= "alchemy-gpic", +	.direction_input	= alchemy_gpic_dir_input, +	.direction_output	= alchemy_gpic_dir_output, +	.get			= alchemy_gpic_get, +	.set			= alchemy_gpic_set, +	.to_irq			= alchemy_gpic_gpio_to_irq, +	.base			= AU1300_GPIO_BASE, +	.ngpio			= AU1300_GPIO_NUM, +}; + +static int __init alchemy_gpiochip_init(void) +{ +	int ret = 0; + +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1000: +		ret = gpiochip_add(&alchemy_gpio_chip[0]); +		break; +	case ALCHEMY_CPU_AU1500...ALCHEMY_CPU_AU1200: +		ret = gpiochip_add(&alchemy_gpio_chip[0]); +		ret |= gpiochip_add(&alchemy_gpio_chip[1]); +		break; +	case ALCHEMY_CPU_AU1300: +		ret = gpiochip_add(&au1300_gpiochip); +		break; +	} +	return ret;  } -arch_initcall(alchemy_gpiolib_init); +arch_initcall(alchemy_gpiochip_init); diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 9f78ada83b3..63a71817a00 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -25,21 +25,57 @@   *  675 Mass Ave, Cambridge, MA 02139, USA.   */ -#include <linux/bitops.h> +#include <linux/export.h>  #include <linux/init.h>  #include <linux/interrupt.h> -#include <linux/irq.h>  #include <linux/slab.h> -#include <linux/sysdev.h> +#include <linux/syscore_ops.h>  #include <asm/irq_cpu.h> -#include <asm/mipsregs.h>  #include <asm/mach-au1x00/au1000.h> -#ifdef CONFIG_MIPS_PB1000 -#include <asm/mach-pb1x00/pb1000.h> -#endif +#include <asm/mach-au1x00/gpio-au1300.h> + +/* Interrupt Controller register offsets */ +#define IC_CFG0RD	0x40 +#define IC_CFG0SET	0x40 +#define IC_CFG0CLR	0x44 +#define IC_CFG1RD	0x48 +#define IC_CFG1SET	0x48 +#define IC_CFG1CLR	0x4C +#define IC_CFG2RD	0x50 +#define IC_CFG2SET	0x50 +#define IC_CFG2CLR	0x54 +#define IC_REQ0INT	0x54 +#define IC_SRCRD	0x58 +#define IC_SRCSET	0x58 +#define IC_SRCCLR	0x5C +#define IC_REQ1INT	0x5C +#define IC_ASSIGNRD	0x60 +#define IC_ASSIGNSET	0x60 +#define IC_ASSIGNCLR	0x64 +#define IC_WAKERD	0x68 +#define IC_WAKESET	0x68 +#define IC_WAKECLR	0x6C +#define IC_MASKRD	0x70 +#define IC_MASKSET	0x70 +#define IC_MASKCLR	0x74 +#define IC_RISINGRD	0x78 +#define IC_RISINGCLR	0x78 +#define IC_FALLINGRD	0x7C +#define IC_FALLINGCLR	0x7C +#define IC_TESTBIT	0x80 + +/* per-processor fixed function irqs */ +struct alchemy_irqmap { +	int irq;	/* linux IRQ number */ +	int type;	/* IRQ_TYPE_ */ +	int prio;	/* irq priority, 0 highest, 3 lowest */ +	int internal;	/* GPIC: internal source (no ext. pin)? */ +}; + +static int au1x_ic_settype(struct irq_data *d, unsigned int type); +static int au1300_gpic_settype(struct irq_data *d, unsigned int type); -static int au1x_ic_settype(unsigned int irq, unsigned int flow_type);  /* NOTE on interrupt priorities: The original writers of this code said:   * @@ -47,268 +83,303 @@ static int au1x_ic_settype(unsigned int irq, unsigned int flow_type);   * the USB devices-side packet complete interrupt (USB_DEV_REQ_INT)   * needs the highest priority.   */ - -/* per-processor fixed function irqs */ -struct au1xxx_irqmap { -	int im_irq; -	int im_type; -	int im_request;		/* set 1 to get higher priority */ +struct alchemy_irqmap au1000_irqmap[] __initdata = { +	{ AU1000_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_UART2_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_SSI0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_SSI1_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 }, +	{ AU1000_IRDA_TX_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_IRDA_RX_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,	0, 0 }, +	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1000_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1000_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1000_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ -1, },  }; -struct au1xxx_irqmap au1000_irqmap[] __initdata = { -	{ AU1000_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_UART2_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_SSI0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_SSI1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 }, -	{ AU1000_IRDA_TX_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_IRDA_RX_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 }, -	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1000_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1000_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1000_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, +struct alchemy_irqmap au1500_irqmap[] __initdata = { +	{ AU1500_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_PCI_INTA,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1500_PCI_INTB,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1500_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_PCI_INTC,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1500_PCI_INTD,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1500_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 }, +	{ AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,	0, 0 }, +	{ AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1500_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1500_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1500_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 },  	{ -1, },  }; -struct au1xxx_irqmap au1500_irqmap[] __initdata = { -	{ AU1500_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_PCI_INTA,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1500_PCI_INTB,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1500_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_PCI_INTC,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1500_PCI_INTD,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1500_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 }, -	{ AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 }, -	{ AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1500_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1500_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1500_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, +struct alchemy_irqmap au1100_irqmap[] __initdata = { +	{ AU1100_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_SD_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_SSI0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_SSI1_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 }, +	{ AU1100_IRDA_TX_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_IRDA_RX_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,	0, 0 }, +	{ AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1100_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1100_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_LCD_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1100_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 },  	{ -1, },  }; -struct au1xxx_irqmap au1100_irqmap[] __initdata = { -	{ AU1100_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_SD_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_SSI0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_SSI1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 }, -	{ AU1100_IRDA_TX_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_IRDA_RX_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 }, -	{ AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1100_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1100_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_LCD_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1100_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, +struct alchemy_irqmap au1550_irqmap[] __initdata = { +	{ AU1550_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_PCI_INTA,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1550_PCI_INTB,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1550_DDMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_CRYPTO_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_PCI_INTC,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1550_PCI_INTD,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1550_PCI_RST_INT,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1550_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_PSC0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_PSC1_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_PSC2_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_PSC3_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 }, +	{ AU1550_NAND_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,	0, 0 }, +	{ AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1550_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,	1, 0 }, +	{ AU1550_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1550_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 },  	{ -1, },  }; -struct au1xxx_irqmap au1550_irqmap[] __initdata = { -	{ AU1550_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_PCI_INTA,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1550_PCI_INTB,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1550_DDMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_CRYPTO_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_PCI_INTC,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1550_PCI_INTD,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1550_PCI_RST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1550_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_PSC0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_PSC1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_PSC2_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_PSC3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 }, -	{ AU1550_NAND_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 }, -	{ AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1550_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 }, -	{ AU1550_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1550_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, +struct alchemy_irqmap au1200_irqmap[] __initdata = { +	{ AU1200_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_SWT_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_SD_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_DDMA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_MAE_BE_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_MAE_FE_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_PSC0_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_PSC1_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_AES_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_CAMERA_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0, 0 }, +	{ AU1200_NAND_INT,	  IRQ_TYPE_EDGE_RISING, 1, 0 }, +	{ AU1200_USB_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_LCD_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 }, +	{ AU1200_MAE_BOTH_INT,	  IRQ_TYPE_LEVEL_HIGH,	1, 0 },  	{ -1, },  }; -struct au1xxx_irqmap au1200_irqmap[] __initdata = { -	{ AU1200_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_SWT_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_SD_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_DDMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_MAE_BE_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_MAE_FE_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_PSC0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_PSC1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_AES_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_CAMERA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 }, -	{ AU1200_NAND_INT,	  IRQ_TYPE_EDGE_RISING, 0 }, -	{ AU1200_USB_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_LCD_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ AU1200_MAE_BOTH_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 }, -	{ -1, }, +static struct alchemy_irqmap au1300_irqmap[] __initdata = { +	/* multifunction: gpio pin or device */ +	{ AU1300_UART1_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_UART2_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_UART3_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_SD1_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_SD2_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_PSC0_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_PSC1_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_PSC2_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_PSC3_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	{ AU1300_NAND_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 0, }, +	/* au1300 internal */ +	{ AU1300_DDMA_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_MMU_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_MPU_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_GPU_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_UDMA_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_TOY_INT,	 IRQ_TYPE_EDGE_RISING,	1, 1, }, +	{ AU1300_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING,	1, 1, }, +	{ AU1300_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING,	1, 1, }, +	{ AU1300_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING,	1, 1, }, +	{ AU1300_RTC_INT,	 IRQ_TYPE_EDGE_RISING,	1, 1, }, +	{ AU1300_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING,	1, 1, }, +	{ AU1300_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING,	1, 1, }, +	{ AU1300_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING,	0, 1, }, +	{ AU1300_UART0_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_SD0_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_USB_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_LCD_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_BSA_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_MPE_INT,	 IRQ_TYPE_EDGE_RISING,	1, 1, }, +	{ AU1300_ITE_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_AES_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ AU1300_CIM_INT,	 IRQ_TYPE_LEVEL_HIGH,	1, 1, }, +	{ -1, },	/* terminator */  }; +/******************************************************************************/ -static void au1x_ic0_unmask(unsigned int irq_nr) +static void au1x_ic0_unmask(struct irq_data *d)  { -	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; -	au_writel(1 << bit, IC0_MASKSET); -	au_writel(1 << bit, IC0_WAKESET); -	au_sync(); +	unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); + +	__raw_writel(1 << bit, base + IC_MASKSET); +	__raw_writel(1 << bit, base + IC_WAKESET); +	wmb();  } -static void au1x_ic1_unmask(unsigned int irq_nr) +static void au1x_ic1_unmask(struct irq_data *d)  { -	unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; -	au_writel(1 << bit, IC1_MASKSET); -	au_writel(1 << bit, IC1_WAKESET); +	unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); -/* very hacky. does the pb1000 cpld auto-disable this int? - * nowhere in the current kernel sources is it disabled.	--mlau - */ -#if defined(CONFIG_MIPS_PB1000) -	if (irq_nr == AU1000_GPIO15_INT) -		au_writel(0x4000, PB1000_MDR); /* enable int */ -#endif -	au_sync(); +	__raw_writel(1 << bit, base + IC_MASKSET); +	__raw_writel(1 << bit, base + IC_WAKESET); +	wmb();  } -static void au1x_ic0_mask(unsigned int irq_nr) +static void au1x_ic0_mask(struct irq_data *d)  { -	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; -	au_writel(1 << bit, IC0_MASKCLR); -	au_writel(1 << bit, IC0_WAKECLR); -	au_sync(); +	unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); + +	__raw_writel(1 << bit, base + IC_MASKCLR); +	__raw_writel(1 << bit, base + IC_WAKECLR); +	wmb();  } -static void au1x_ic1_mask(unsigned int irq_nr) +static void au1x_ic1_mask(struct irq_data *d)  { -	unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; -	au_writel(1 << bit, IC1_MASKCLR); -	au_writel(1 << bit, IC1_WAKECLR); -	au_sync(); +	unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); + +	__raw_writel(1 << bit, base + IC_MASKCLR); +	__raw_writel(1 << bit, base + IC_WAKECLR); +	wmb();  } -static void au1x_ic0_ack(unsigned int irq_nr) +static void au1x_ic0_ack(struct irq_data *d)  { -	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; +	unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);  	/*  	 * This may assume that we don't get interrupts from  	 * both edges at once, or if we do, that we don't care.  	 */ -	au_writel(1 << bit, IC0_FALLINGCLR); -	au_writel(1 << bit, IC0_RISINGCLR); -	au_sync(); +	__raw_writel(1 << bit, base + IC_FALLINGCLR); +	__raw_writel(1 << bit, base + IC_RISINGCLR); +	wmb();  } -static void au1x_ic1_ack(unsigned int irq_nr) +static void au1x_ic1_ack(struct irq_data *d)  { -	unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; +	unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);  	/*  	 * This may assume that we don't get interrupts from  	 * both edges at once, or if we do, that we don't care.  	 */ -	au_writel(1 << bit, IC1_FALLINGCLR); -	au_writel(1 << bit, IC1_RISINGCLR); -	au_sync(); +	__raw_writel(1 << bit, base + IC_FALLINGCLR); +	__raw_writel(1 << bit, base + IC_RISINGCLR); +	wmb();  } -static void au1x_ic0_maskack(unsigned int irq_nr) +static void au1x_ic0_maskack(struct irq_data *d)  { -	unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE; +	unsigned int bit = d->irq - AU1000_INTC0_INT_BASE; +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR); -	au_writel(1 << bit, IC0_WAKECLR); -	au_writel(1 << bit, IC0_MASKCLR); -	au_writel(1 << bit, IC0_RISINGCLR); -	au_writel(1 << bit, IC0_FALLINGCLR); -	au_sync(); +	__raw_writel(1 << bit, base + IC_WAKECLR); +	__raw_writel(1 << bit, base + IC_MASKCLR); +	__raw_writel(1 << bit, base + IC_RISINGCLR); +	__raw_writel(1 << bit, base + IC_FALLINGCLR); +	wmb();  } -static void au1x_ic1_maskack(unsigned int irq_nr) +static void au1x_ic1_maskack(struct irq_data *d)  { -	unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE; +	unsigned int bit = d->irq - AU1000_INTC1_INT_BASE; +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); -	au_writel(1 << bit, IC1_WAKECLR); -	au_writel(1 << bit, IC1_MASKCLR); -	au_writel(1 << bit, IC1_RISINGCLR); -	au_writel(1 << bit, IC1_FALLINGCLR); -	au_sync(); +	__raw_writel(1 << bit, base + IC_WAKECLR); +	__raw_writel(1 << bit, base + IC_MASKCLR); +	__raw_writel(1 << bit, base + IC_RISINGCLR); +	__raw_writel(1 << bit, base + IC_FALLINGCLR); +	wmb();  } -static int au1x_ic1_setwake(unsigned int irq, unsigned int on) +static int au1x_ic1_setwake(struct irq_data *d, unsigned int on)  { -	int bit = irq - AU1000_INTC1_INT_BASE; +	int bit = d->irq - AU1000_INTC1_INT_BASE;  	unsigned long wakemsk, flags;  	/* only GPIO 0-7 can act as wakeup source.  Fortunately these @@ -318,13 +389,13 @@ static int au1x_ic1_setwake(unsigned int irq, unsigned int on)  		return -EINVAL;  	local_irq_save(flags); -	wakemsk = au_readl(SYS_WAKEMSK); +	wakemsk = __raw_readl((void __iomem *)SYS_WAKEMSK);  	if (on)  		wakemsk |= 1 << bit;  	else  		wakemsk &= ~(1 << bit); -	au_writel(wakemsk, SYS_WAKEMSK); -	au_sync(); +	__raw_writel(wakemsk, (void __iomem *)SYS_WAKEMSK); +	wmb();  	local_irq_restore(flags);  	return 0; @@ -336,308 +407,591 @@ static int au1x_ic1_setwake(unsigned int irq, unsigned int on)   */  static struct irq_chip au1x_ic0_chip = {  	.name		= "Alchemy-IC0", -	.ack		= au1x_ic0_ack, -	.mask		= au1x_ic0_mask, -	.mask_ack	= au1x_ic0_maskack, -	.unmask		= au1x_ic0_unmask, -	.set_type	= au1x_ic_settype, +	.irq_ack	= au1x_ic0_ack, +	.irq_mask	= au1x_ic0_mask, +	.irq_mask_ack	= au1x_ic0_maskack, +	.irq_unmask	= au1x_ic0_unmask, +	.irq_set_type	= au1x_ic_settype,  };  static struct irq_chip au1x_ic1_chip = {  	.name		= "Alchemy-IC1", -	.ack		= au1x_ic1_ack, -	.mask		= au1x_ic1_mask, -	.mask_ack	= au1x_ic1_maskack, -	.unmask		= au1x_ic1_unmask, -	.set_type	= au1x_ic_settype, -	.set_wake	= au1x_ic1_setwake, +	.irq_ack	= au1x_ic1_ack, +	.irq_mask	= au1x_ic1_mask, +	.irq_mask_ack	= au1x_ic1_maskack, +	.irq_unmask	= au1x_ic1_unmask, +	.irq_set_type	= au1x_ic_settype, +	.irq_set_wake	= au1x_ic1_setwake,  }; -static int au1x_ic_settype(unsigned int irq, unsigned int flow_type) +static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type)  {  	struct irq_chip *chip; -	unsigned long icr[6]; -	unsigned int bit, ic; +	unsigned int bit, irq = d->irq; +	irq_flow_handler_t handler = NULL; +	unsigned char *name = NULL; +	void __iomem *base;  	int ret;  	if (irq >= AU1000_INTC1_INT_BASE) {  		bit = irq - AU1000_INTC1_INT_BASE;  		chip = &au1x_ic1_chip; -		ic = 1; +		base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);  	} else {  		bit = irq - AU1000_INTC0_INT_BASE;  		chip = &au1x_ic0_chip; -		ic = 0; +		base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);  	}  	if (bit > 31)  		return -EINVAL; -	icr[0] = ic ? IC1_CFG0SET : IC0_CFG0SET; -	icr[1] = ic ? IC1_CFG1SET : IC0_CFG1SET; -	icr[2] = ic ? IC1_CFG2SET : IC0_CFG2SET; -	icr[3] = ic ? IC1_CFG0CLR : IC0_CFG0CLR; -	icr[4] = ic ? IC1_CFG1CLR : IC0_CFG1CLR; -	icr[5] = ic ? IC1_CFG2CLR : IC0_CFG2CLR; -  	ret = 0;  	switch (flow_type) {	/* cfgregs 2:1:0 */  	case IRQ_TYPE_EDGE_RISING:	/* 0:0:1 */ -		au_writel(1 << bit, icr[5]); -		au_writel(1 << bit, icr[4]); -		au_writel(1 << bit, icr[0]); -		set_irq_chip_and_handler_name(irq, chip, -				handle_edge_irq, "riseedge"); +		__raw_writel(1 << bit, base + IC_CFG2CLR); +		__raw_writel(1 << bit, base + IC_CFG1CLR); +		__raw_writel(1 << bit, base + IC_CFG0SET); +		handler = handle_edge_irq; +		name = "riseedge";  		break;  	case IRQ_TYPE_EDGE_FALLING:	/* 0:1:0 */ -		au_writel(1 << bit, icr[5]); -		au_writel(1 << bit, icr[1]); -		au_writel(1 << bit, icr[3]); -		set_irq_chip_and_handler_name(irq, chip, -				handle_edge_irq, "falledge"); +		__raw_writel(1 << bit, base + IC_CFG2CLR); +		__raw_writel(1 << bit, base + IC_CFG1SET); +		__raw_writel(1 << bit, base + IC_CFG0CLR); +		handler = handle_edge_irq; +		name = "falledge";  		break;  	case IRQ_TYPE_EDGE_BOTH:	/* 0:1:1 */ -		au_writel(1 << bit, icr[5]); -		au_writel(1 << bit, icr[1]); -		au_writel(1 << bit, icr[0]); -		set_irq_chip_and_handler_name(irq, chip, -				handle_edge_irq, "bothedge"); +		__raw_writel(1 << bit, base + IC_CFG2CLR); +		__raw_writel(1 << bit, base + IC_CFG1SET); +		__raw_writel(1 << bit, base + IC_CFG0SET); +		handler = handle_edge_irq; +		name = "bothedge";  		break;  	case IRQ_TYPE_LEVEL_HIGH:	/* 1:0:1 */ -		au_writel(1 << bit, icr[2]); -		au_writel(1 << bit, icr[4]); -		au_writel(1 << bit, icr[0]); -		set_irq_chip_and_handler_name(irq, chip, -				handle_level_irq, "hilevel"); +		__raw_writel(1 << bit, base + IC_CFG2SET); +		__raw_writel(1 << bit, base + IC_CFG1CLR); +		__raw_writel(1 << bit, base + IC_CFG0SET); +		handler = handle_level_irq; +		name = "hilevel";  		break;  	case IRQ_TYPE_LEVEL_LOW:	/* 1:1:0 */ -		au_writel(1 << bit, icr[2]); -		au_writel(1 << bit, icr[1]); -		au_writel(1 << bit, icr[3]); -		set_irq_chip_and_handler_name(irq, chip, -				handle_level_irq, "lowlevel"); +		__raw_writel(1 << bit, base + IC_CFG2SET); +		__raw_writel(1 << bit, base + IC_CFG1SET); +		__raw_writel(1 << bit, base + IC_CFG0CLR); +		handler = handle_level_irq; +		name = "lowlevel";  		break;  	case IRQ_TYPE_NONE:		/* 0:0:0 */ -		au_writel(1 << bit, icr[5]); -		au_writel(1 << bit, icr[4]); -		au_writel(1 << bit, icr[3]); -		/* set at least chip so we can call set_irq_type() on it */ -		set_irq_chip(irq, chip); +		__raw_writel(1 << bit, base + IC_CFG2CLR); +		__raw_writel(1 << bit, base + IC_CFG1CLR); +		__raw_writel(1 << bit, base + IC_CFG0CLR);  		break;  	default:  		ret = -EINVAL;  	} -	au_sync(); +	__irq_set_chip_handler_name_locked(d->irq, chip, handler, name); + +	wmb();  	return ret;  } -asmlinkage void plat_irq_dispatch(void) +/******************************************************************************/ + +/* + * au1300_gpic_chgcfg - change PIN configuration. + * @gpio:	pin to change (0-based GPIO number from datasheet). + * @clr:	clear all bits set in 'clr'. + * @set:	set these bits. + * + * modifies a pins' configuration register, bits set in @clr will + * be cleared in the register, bits in @set will be set. + */ +static inline void au1300_gpic_chgcfg(unsigned int gpio, +				      unsigned long clr, +				      unsigned long set) +{ +	void __iomem *r = AU1300_GPIC_ADDR; +	unsigned long l; + +	r += gpio * 4;	/* offset into pin config array */ +	l = __raw_readl(r + AU1300_GPIC_PINCFG); +	l &= ~clr; +	l |= set; +	__raw_writel(l, r + AU1300_GPIC_PINCFG); +	wmb(); +} + +/* + * au1300_pinfunc_to_gpio - assign a pin as GPIO input (GPIO ctrl). + * @pin:	pin (0-based GPIO number from datasheet). + * + * Assigns a GPIO pin to the GPIO controller, so its level can either + * be read or set through the generic GPIO functions. + * If you need a GPOUT, use au1300_gpio_set_value(pin, 0/1). + * REVISIT: is this function really necessary? + */ +void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio)  { -	unsigned int pending = read_c0_status() & read_c0_cause(); -	unsigned long s, off; - -	if (pending & CAUSEF_IP7) { -		off = MIPS_CPU_IRQ_BASE + 7; -		goto handle; -	} else if (pending & CAUSEF_IP2) { -		s = IC0_REQ0INT; -		off = AU1000_INTC0_INT_BASE; -	} else if (pending & CAUSEF_IP3) { -		s = IC0_REQ1INT; -		off = AU1000_INTC0_INT_BASE; -	} else if (pending & CAUSEF_IP4) { -		s = IC1_REQ0INT; -		off = AU1000_INTC1_INT_BASE; -	} else if (pending & CAUSEF_IP5) { -		s = IC1_REQ1INT; -		off = AU1000_INTC1_INT_BASE; -	} else -		goto spurious; - -	s = au_readl(s); -	if (unlikely(!s)) { -spurious: -		spurious_interrupt(); -		return; +	au1300_gpio_direction_input(gpio + AU1300_GPIO_BASE); +} +EXPORT_SYMBOL_GPL(au1300_pinfunc_to_gpio); + +/* + * au1300_pinfunc_to_dev - assign a pin to the device function. + * @pin:	pin (0-based GPIO number from datasheet). + * + * Assigns a GPIO pin to its associated device function; the pin will be + * driven by the device and not through GPIO functions. + */ +void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio) +{ +	void __iomem *r = AU1300_GPIC_ADDR; +	unsigned long bit; + +	r += GPIC_GPIO_BANKOFF(gpio); +	bit = GPIC_GPIO_TO_BIT(gpio); +	__raw_writel(bit, r + AU1300_GPIC_DEVSEL); +	wmb(); +} +EXPORT_SYMBOL_GPL(au1300_pinfunc_to_dev); + +/* + * au1300_set_irq_priority -  set internal priority of IRQ. + * @irq:	irq to set priority (linux irq number). + * @p:		priority (0 = highest, 3 = lowest). + */ +void au1300_set_irq_priority(unsigned int irq, int p) +{ +	irq -= ALCHEMY_GPIC_INT_BASE; +	au1300_gpic_chgcfg(irq, GPIC_CFG_IL_MASK, GPIC_CFG_IL_SET(p)); +} +EXPORT_SYMBOL_GPL(au1300_set_irq_priority); + +/* + * au1300_set_dbdma_gpio - assign a gpio to one of the DBDMA triggers. + * @dchan:	dbdma trigger select (0, 1). + * @gpio:	pin to assign as trigger. + * + * DBDMA controller has 2 external trigger sources; this function + * assigns a GPIO to the selected trigger. + */ +void au1300_set_dbdma_gpio(int dchan, unsigned int gpio) +{ +	unsigned long r; + +	if ((dchan >= 0) && (dchan <= 1)) { +		r = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL); +		r &= ~(0xff << (8 * dchan)); +		r |= (gpio & 0x7f) << (8 * dchan); +		__raw_writel(r, AU1300_GPIC_ADDR + AU1300_GPIC_DMASEL); +		wmb();  	} -	off += __ffs(s); -handle: -	do_IRQ(off);  } -static void __init au1000_init_irq(struct au1xxx_irqmap *map) +static inline void gpic_pin_set_idlewake(unsigned int gpio, int allow)  { -	unsigned int bit, irq_nr; -	int i; +	au1300_gpic_chgcfg(gpio, GPIC_CFG_IDLEWAKE, +			   allow ? GPIC_CFG_IDLEWAKE : 0); +} -	/* -	 * Initialize interrupt controllers to a safe state. -	 */ -	au_writel(0xffffffff, IC0_CFG0CLR); -	au_writel(0xffffffff, IC0_CFG1CLR); -	au_writel(0xffffffff, IC0_CFG2CLR); -	au_writel(0xffffffff, IC0_MASKCLR); -	au_writel(0xffffffff, IC0_ASSIGNCLR); -	au_writel(0xffffffff, IC0_WAKECLR); -	au_writel(0xffffffff, IC0_SRCSET); -	au_writel(0xffffffff, IC0_FALLINGCLR); -	au_writel(0xffffffff, IC0_RISINGCLR); -	au_writel(0x00000000, IC0_TESTBIT); - -	au_writel(0xffffffff, IC1_CFG0CLR); -	au_writel(0xffffffff, IC1_CFG1CLR); -	au_writel(0xffffffff, IC1_CFG2CLR); -	au_writel(0xffffffff, IC1_MASKCLR); -	au_writel(0xffffffff, IC1_ASSIGNCLR); -	au_writel(0xffffffff, IC1_WAKECLR); -	au_writel(0xffffffff, IC1_SRCSET); -	au_writel(0xffffffff, IC1_FALLINGCLR); -	au_writel(0xffffffff, IC1_RISINGCLR); -	au_writel(0x00000000, IC1_TESTBIT); +static void au1300_gpic_mask(struct irq_data *d) +{ +	void __iomem *r = AU1300_GPIC_ADDR; +	unsigned long bit, irq = d->irq; -	mips_cpu_irq_init(); +	irq -= ALCHEMY_GPIC_INT_BASE; +	r += GPIC_GPIO_BANKOFF(irq); +	bit = GPIC_GPIO_TO_BIT(irq); +	__raw_writel(bit, r + AU1300_GPIC_IDIS); +	wmb(); -	/* register all 64 possible IC0+IC1 irq sources as type "none". -	 * Use set_irq_type() to set edge/level behaviour at runtime. -	 */ -	for (i = AU1000_INTC0_INT_BASE; -	     (i < AU1000_INTC0_INT_BASE + 32); i++) -		au1x_ic_settype(i, IRQ_TYPE_NONE); +	gpic_pin_set_idlewake(irq, 0); +} -	for (i = AU1000_INTC1_INT_BASE; -	     (i < AU1000_INTC1_INT_BASE + 32); i++) -		au1x_ic_settype(i, IRQ_TYPE_NONE); +static void au1300_gpic_unmask(struct irq_data *d) +{ +	void __iomem *r = AU1300_GPIC_ADDR; +	unsigned long bit, irq = d->irq; -	/* -	 * Initialize IC0, which is fixed per processor. -	 */ -	while (map->im_irq != -1) { -		irq_nr = map->im_irq; +	irq -= ALCHEMY_GPIC_INT_BASE; -		if (irq_nr >= AU1000_INTC1_INT_BASE) { -			bit = irq_nr - AU1000_INTC1_INT_BASE; -			if (map->im_request) -				au_writel(1 << bit, IC1_ASSIGNSET); -		} else { -			bit = irq_nr - AU1000_INTC0_INT_BASE; -			if (map->im_request) -				au_writel(1 << bit, IC0_ASSIGNSET); -		} +	gpic_pin_set_idlewake(irq, 1); -		au1x_ic_settype(irq_nr, map->im_type); -		++map; -	} +	r += GPIC_GPIO_BANKOFF(irq); +	bit = GPIC_GPIO_TO_BIT(irq); +	__raw_writel(bit, r + AU1300_GPIC_IEN); +	wmb(); +} -	set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3); +static void au1300_gpic_maskack(struct irq_data *d) +{ +	void __iomem *r = AU1300_GPIC_ADDR; +	unsigned long bit, irq = d->irq; + +	irq -= ALCHEMY_GPIC_INT_BASE; +	r += GPIC_GPIO_BANKOFF(irq); +	bit = GPIC_GPIO_TO_BIT(irq); +	__raw_writel(bit, r + AU1300_GPIC_IPEND);	/* ack */ +	__raw_writel(bit, r + AU1300_GPIC_IDIS);	/* mask */ +	wmb(); + +	gpic_pin_set_idlewake(irq, 0);  } -void __init arch_init_irq(void) +static void au1300_gpic_ack(struct irq_data *d)  { -	switch (alchemy_get_cputype()) { -	case ALCHEMY_CPU_AU1000: -		au1000_init_irq(au1000_irqmap); +	void __iomem *r = AU1300_GPIC_ADDR; +	unsigned long bit, irq = d->irq; + +	irq -= ALCHEMY_GPIC_INT_BASE; +	r += GPIC_GPIO_BANKOFF(irq); +	bit = GPIC_GPIO_TO_BIT(irq); +	__raw_writel(bit, r + AU1300_GPIC_IPEND);	/* ack */ +	wmb(); +} + +static struct irq_chip au1300_gpic = { +	.name		= "GPIOINT", +	.irq_ack	= au1300_gpic_ack, +	.irq_mask	= au1300_gpic_mask, +	.irq_mask_ack	= au1300_gpic_maskack, +	.irq_unmask	= au1300_gpic_unmask, +	.irq_set_type	= au1300_gpic_settype, +}; + +static int au1300_gpic_settype(struct irq_data *d, unsigned int type) +{ +	unsigned long s; +	unsigned char *name = NULL; +	irq_flow_handler_t hdl = NULL; + +	switch (type) { +	case IRQ_TYPE_LEVEL_HIGH: +		s = GPIC_CFG_IC_LEVEL_HIGH; +		name = "high"; +		hdl = handle_level_irq;  		break; -	case ALCHEMY_CPU_AU1500: -		au1000_init_irq(au1500_irqmap); +	case IRQ_TYPE_LEVEL_LOW: +		s = GPIC_CFG_IC_LEVEL_LOW; +		name = "low"; +		hdl = handle_level_irq;  		break; -	case ALCHEMY_CPU_AU1100: -		au1000_init_irq(au1100_irqmap); +	case IRQ_TYPE_EDGE_RISING: +		s = GPIC_CFG_IC_EDGE_RISE; +		name = "posedge"; +		hdl = handle_edge_irq;  		break; -	case ALCHEMY_CPU_AU1550: -		au1000_init_irq(au1550_irqmap); +	case IRQ_TYPE_EDGE_FALLING: +		s = GPIC_CFG_IC_EDGE_FALL; +		name = "negedge"; +		hdl = handle_edge_irq;  		break; -	case ALCHEMY_CPU_AU1200: -		au1000_init_irq(au1200_irqmap); +	case IRQ_TYPE_EDGE_BOTH: +		s = GPIC_CFG_IC_EDGE_BOTH; +		name = "bothedge"; +		hdl = handle_edge_irq; +		break; +	case IRQ_TYPE_NONE: +		s = GPIC_CFG_IC_OFF; +		name = "disabled"; +		hdl = handle_level_irq;  		break; +	default: +		return -EINVAL;  	} + +	__irq_set_chip_handler_name_locked(d->irq, &au1300_gpic, hdl, name); + +	au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s); + +	return 0;  } -struct alchemy_ic_sysdev { -	struct sys_device sysdev; -	void __iomem *base; -	unsigned long pmdata[7]; -}; +/******************************************************************************/ -static int alchemy_ic_suspend(struct sys_device *dev, pm_message_t state) +static inline void ic_init(void __iomem *base)  { -	struct alchemy_ic_sysdev *icdev = -			container_of(dev, struct alchemy_ic_sysdev, sysdev); +	/* initialize interrupt controller to a safe state */ +	__raw_writel(0xffffffff, base + IC_CFG0CLR); +	__raw_writel(0xffffffff, base + IC_CFG1CLR); +	__raw_writel(0xffffffff, base + IC_CFG2CLR); +	__raw_writel(0xffffffff, base + IC_MASKCLR); +	__raw_writel(0xffffffff, base + IC_ASSIGNCLR); +	__raw_writel(0xffffffff, base + IC_WAKECLR); +	__raw_writel(0xffffffff, base + IC_SRCSET); +	__raw_writel(0xffffffff, base + IC_FALLINGCLR); +	__raw_writel(0xffffffff, base + IC_RISINGCLR); +	__raw_writel(0x00000000, base + IC_TESTBIT); +	wmb(); +} -	icdev->pmdata[0] = __raw_readl(icdev->base + IC_CFG0RD); -	icdev->pmdata[1] = __raw_readl(icdev->base + IC_CFG1RD); -	icdev->pmdata[2] = __raw_readl(icdev->base + IC_CFG2RD); -	icdev->pmdata[3] = __raw_readl(icdev->base + IC_SRCRD); -	icdev->pmdata[4] = __raw_readl(icdev->base + IC_ASSIGNRD); -	icdev->pmdata[5] = __raw_readl(icdev->base + IC_WAKERD); -	icdev->pmdata[6] = __raw_readl(icdev->base + IC_MASKRD); +static unsigned long alchemy_gpic_pmdata[ALCHEMY_GPIC_INT_NUM + 6]; -	return 0; +static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d) +{ +	d[0] = __raw_readl(base + IC_CFG0RD); +	d[1] = __raw_readl(base + IC_CFG1RD); +	d[2] = __raw_readl(base + IC_CFG2RD); +	d[3] = __raw_readl(base + IC_SRCRD); +	d[4] = __raw_readl(base + IC_ASSIGNRD); +	d[5] = __raw_readl(base + IC_WAKERD); +	d[6] = __raw_readl(base + IC_MASKRD); +	ic_init(base);		/* shut it up too while at it */  } -static int alchemy_ic_resume(struct sys_device *dev) +static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d)  { -	struct alchemy_ic_sysdev *icdev = -			container_of(dev, struct alchemy_ic_sysdev, sysdev); +	ic_init(base); + +	__raw_writel(d[0], base + IC_CFG0SET); +	__raw_writel(d[1], base + IC_CFG1SET); +	__raw_writel(d[2], base + IC_CFG2SET); +	__raw_writel(d[3], base + IC_SRCSET); +	__raw_writel(d[4], base + IC_ASSIGNSET); +	__raw_writel(d[5], base + IC_WAKESET); +	wmb(); -	__raw_writel(0xffffffff, icdev->base + IC_MASKCLR); -	__raw_writel(0xffffffff, icdev->base + IC_CFG0CLR); -	__raw_writel(0xffffffff, icdev->base + IC_CFG1CLR); -	__raw_writel(0xffffffff, icdev->base + IC_CFG2CLR); -	__raw_writel(0xffffffff, icdev->base + IC_SRCCLR); -	__raw_writel(0xffffffff, icdev->base + IC_ASSIGNCLR); -	__raw_writel(0xffffffff, icdev->base + IC_WAKECLR); -	__raw_writel(0xffffffff, icdev->base + IC_RISINGCLR); -	__raw_writel(0xffffffff, icdev->base + IC_FALLINGCLR); -	__raw_writel(0x00000000, icdev->base + IC_TESTBIT); +	__raw_writel(d[6], base + IC_MASKSET);  	wmb(); -	__raw_writel(icdev->pmdata[0], icdev->base + IC_CFG0SET); -	__raw_writel(icdev->pmdata[1], icdev->base + IC_CFG1SET); -	__raw_writel(icdev->pmdata[2], icdev->base + IC_CFG2SET); -	__raw_writel(icdev->pmdata[3], icdev->base + IC_SRCSET); -	__raw_writel(icdev->pmdata[4], icdev->base + IC_ASSIGNSET); -	__raw_writel(icdev->pmdata[5], icdev->base + IC_WAKESET); +} + +static int alchemy_ic_suspend(void) +{ +	alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), +			       alchemy_gpic_pmdata); +	alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), +			       &alchemy_gpic_pmdata[7]); +	return 0; +} + +static void alchemy_ic_resume(void) +{ +	alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR), +			      &alchemy_gpic_pmdata[7]); +	alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR), +			      alchemy_gpic_pmdata); +} + +static int alchemy_gpic_suspend(void) +{ +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); +	int i; + +	/* save 4 interrupt mask status registers */ +	alchemy_gpic_pmdata[0] = __raw_readl(base + AU1300_GPIC_IEN + 0x0); +	alchemy_gpic_pmdata[1] = __raw_readl(base + AU1300_GPIC_IEN + 0x4); +	alchemy_gpic_pmdata[2] = __raw_readl(base + AU1300_GPIC_IEN + 0x8); +	alchemy_gpic_pmdata[3] = __raw_readl(base + AU1300_GPIC_IEN + 0xc); + +	/* save misc register(s) */ +	alchemy_gpic_pmdata[4] = __raw_readl(base + AU1300_GPIC_DMASEL); + +	/* molto silenzioso */ +	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0); +	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4); +	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8); +	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc);  	wmb(); -	__raw_writel(icdev->pmdata[6], icdev->base + IC_MASKSET); +	/* save pin/int-type configuration */ +	base += AU1300_GPIC_PINCFG; +	for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++) +		alchemy_gpic_pmdata[i + 5] = __raw_readl(base + (i << 2)); +  	wmb();  	return 0;  } -static struct sysdev_class alchemy_ic_sysdev_class = { -	.name		= "ic", +static void alchemy_gpic_resume(void) +{ +	void __iomem *base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); +	int i; + +	/* disable all first */ +	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x0); +	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x4); +	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0x8); +	__raw_writel(~0UL, base + AU1300_GPIC_IDIS + 0xc); +	wmb(); + +	/* restore pin/int-type configurations */ +	base += AU1300_GPIC_PINCFG; +	for (i = 0; i < ALCHEMY_GPIC_INT_NUM; i++) +		__raw_writel(alchemy_gpic_pmdata[i + 5], base + (i << 2)); +	wmb(); + +	/* restore misc register(s) */ +	base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR); +	__raw_writel(alchemy_gpic_pmdata[4], base + AU1300_GPIC_DMASEL); +	wmb(); + +	/* finally restore masks */ +	__raw_writel(alchemy_gpic_pmdata[0], base + AU1300_GPIC_IEN + 0x0); +	__raw_writel(alchemy_gpic_pmdata[1], base + AU1300_GPIC_IEN + 0x4); +	__raw_writel(alchemy_gpic_pmdata[2], base + AU1300_GPIC_IEN + 0x8); +	__raw_writel(alchemy_gpic_pmdata[3], base + AU1300_GPIC_IEN + 0xc); +	wmb(); +} + +static struct syscore_ops alchemy_ic_pmops = {  	.suspend	= alchemy_ic_suspend,  	.resume		= alchemy_ic_resume,  }; -static int __init alchemy_ic_sysdev_init(void) +static struct syscore_ops alchemy_gpic_pmops = { +	.suspend	= alchemy_gpic_suspend, +	.resume		= alchemy_gpic_resume, +}; + +/******************************************************************************/ + +/* create chained handlers for the 4 IC requests to the MIPS IRQ ctrl */ +#define DISP(name, base, addr)						      \ +static void au1000_##name##_dispatch(unsigned int irq, struct irq_desc *d)    \ +{									      \ +	unsigned long r = __raw_readl((void __iomem *)KSEG1ADDR(addr));	      \ +	if (likely(r))							      \ +		generic_handle_irq(base + __ffs(r));			      \ +	else								      \ +		spurious_interrupt();					      \ +} + +DISP(ic0r0, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ0INT) +DISP(ic0r1, AU1000_INTC0_INT_BASE, AU1000_IC0_PHYS_ADDR + IC_REQ1INT) +DISP(ic1r0, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ0INT) +DISP(ic1r1, AU1000_INTC1_INT_BASE, AU1000_IC1_PHYS_ADDR + IC_REQ1INT) + +static void alchemy_gpic_dispatch(unsigned int irq, struct irq_desc *d)  { -	struct alchemy_ic_sysdev *icdev; -	unsigned long icbase[2] = { IC0_PHYS_ADDR, IC1_PHYS_ADDR }; -	int err, i; +	int i = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_PRIENC); +	generic_handle_irq(ALCHEMY_GPIC_INT_BASE + i); +} -	err = sysdev_class_register(&alchemy_ic_sysdev_class); -	if (err) -		return err; +/******************************************************************************/ -	for (i = 0; i < 2; i++) { -		icdev = kzalloc(sizeof(struct alchemy_ic_sysdev), GFP_KERNEL); -		if (!icdev) -			return -ENOMEM; +static void __init au1000_init_irq(struct alchemy_irqmap *map) +{ +	unsigned int bit, irq_nr; +	void __iomem *base; -		icdev->base = ioremap(icbase[i], 0x1000); +	ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR)); +	ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR)); +	register_syscore_ops(&alchemy_ic_pmops); +	mips_cpu_irq_init(); -		icdev->sysdev.id = i; -		icdev->sysdev.cls = &alchemy_ic_sysdev_class; -		err = sysdev_register(&icdev->sysdev); -		if (err) { -			kfree(icdev); -			return err; +	/* register all 64 possible IC0+IC1 irq sources as type "none". +	 * Use set_irq_type() to set edge/level behaviour at runtime. +	 */ +	for (irq_nr = AU1000_INTC0_INT_BASE; +	     (irq_nr < AU1000_INTC0_INT_BASE + 32); irq_nr++) +		au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); + +	for (irq_nr = AU1000_INTC1_INT_BASE; +	     (irq_nr < AU1000_INTC1_INT_BASE + 32); irq_nr++) +		au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE); + +	/* +	 * Initialize IC0, which is fixed per processor. +	 */ +	while (map->irq != -1) { +		irq_nr = map->irq; + +		if (irq_nr >= AU1000_INTC1_INT_BASE) { +			bit = irq_nr - AU1000_INTC1_INT_BASE; +			base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR); +		} else { +			bit = irq_nr - AU1000_INTC0_INT_BASE; +			base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);  		} +		if (map->prio == 0) +			__raw_writel(1 << bit, base + IC_ASSIGNSET); + +		au1x_ic_settype(irq_get_irq_data(irq_nr), map->type); +		++map;  	} -	return 0; +	irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, au1000_ic0r0_dispatch); +	irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, au1000_ic0r1_dispatch); +	irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, au1000_ic1r0_dispatch); +	irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, au1000_ic1r1_dispatch); +} + +static void __init alchemy_gpic_init_irq(const struct alchemy_irqmap *dints) +{ +	int i; +	void __iomem *bank_base; + +	register_syscore_ops(&alchemy_gpic_pmops); +	mips_cpu_irq_init(); + +	/* disable & ack all possible interrupt sources */ +	for (i = 0; i < 4; i++) { +		bank_base = AU1300_GPIC_ADDR + (i * 4); +		__raw_writel(~0UL, bank_base + AU1300_GPIC_IDIS); +		wmb(); +		__raw_writel(~0UL, bank_base + AU1300_GPIC_IPEND); +		wmb(); +	} + +	/* register an irq_chip for them, with 2nd highest priority */ +	for (i = ALCHEMY_GPIC_INT_BASE; i <= ALCHEMY_GPIC_INT_LAST; i++) { +		au1300_set_irq_priority(i, 1); +		au1300_gpic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE); +	} + +	/* setup known on-chip sources */ +	while ((i = dints->irq) != -1) { +		au1300_gpic_settype(irq_get_irq_data(i), dints->type); +		au1300_set_irq_priority(i, dints->prio); + +		if (dints->internal) +			au1300_pinfunc_to_dev(i - ALCHEMY_GPIC_INT_BASE); + +		dints++; +	} + +	irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 2, alchemy_gpic_dispatch); +	irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 3, alchemy_gpic_dispatch); +	irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 4, alchemy_gpic_dispatch); +	irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 5, alchemy_gpic_dispatch); +} + +/******************************************************************************/ + +void __init arch_init_irq(void) +{ +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1000: +		au1000_init_irq(au1000_irqmap); +		break; +	case ALCHEMY_CPU_AU1500: +		au1000_init_irq(au1500_irqmap); +		break; +	case ALCHEMY_CPU_AU1100: +		au1000_init_irq(au1100_irqmap); +		break; +	case ALCHEMY_CPU_AU1550: +		au1000_init_irq(au1550_irqmap); +		break; +	case ALCHEMY_CPU_AU1200: +		au1000_init_irq(au1200_irqmap); +		break; +	case ALCHEMY_CPU_AU1300: +		alchemy_gpic_init_irq(au1300_irqmap); +		break; +	default: +		pr_err("unknown Alchemy IRQ core\n"); +		break; +	} +} + +asmlinkage void plat_irq_dispatch(void) +{ +	unsigned long r = (read_c0_status() & read_c0_cause()) >> 8; +	do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(r & 0xff));  } -device_initcall(alchemy_ic_sysdev_init); diff --git a/arch/mips/alchemy/common/pci.c b/arch/mips/alchemy/common/pci.c deleted file mode 100644 index 7866cf50cf9..00000000000 --- a/arch/mips/alchemy/common/pci.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - *	Alchemy/AMD Au1x00 PCI support. - * - * Copyright 2001-2003, 2007-2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> - * - * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) - * - *  Support for all devices (greater than 16) added by David Gathright. - * - *  This program is free software; you can redistribute  it and/or modify it - *  under  the terms of  the GNU General  Public License as published by the - *  Free Software Foundation;  either version 2 of the  License, or (at your - *  option) any later version. - * - *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED - *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF - *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN - *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, - *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF - *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT - *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *  You should have received a copy of the  GNU General Public License along - *  with this program; if not, write  to the Free Software Foundation, Inc., - *  675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/init.h> - -#include <asm/mach-au1x00/au1000.h> - -/* TBD */ -static struct resource pci_io_resource = { -	.start	= PCI_IO_START, -	.end	= PCI_IO_END, -	.name	= "PCI IO space", -	.flags	= IORESOURCE_IO -}; - -static struct resource pci_mem_resource = { -	.start	= PCI_MEM_START, -	.end	= PCI_MEM_END, -	.name	= "PCI memory space", -	.flags	= IORESOURCE_MEM -}; - -extern struct pci_ops au1x_pci_ops; - -static struct pci_controller au1x_controller = { -	.pci_ops	= &au1x_pci_ops, -	.io_resource	= &pci_io_resource, -	.mem_resource	= &pci_mem_resource, -}; - -#if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) -static unsigned long virt_io_addr; -#endif - -static int __init au1x_pci_setup(void) -{ -	extern void au1x_pci_cfg_init(void); - -#if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550) -	virt_io_addr = (unsigned long)ioremap(Au1500_PCI_IO_START, -			Au1500_PCI_IO_END - Au1500_PCI_IO_START + 1); - -	if (!virt_io_addr) { -		printk(KERN_ERR "Unable to ioremap pci space\n"); -		return 1; -	} -	au1x_controller.io_map_base = virt_io_addr; - -#ifdef CONFIG_DMA_NONCOHERENT -	{ -		/* -		 *  Set the NC bit in controller for Au1500 pre-AC silicon -		 */ -		u32 prid = read_c0_prid(); - -		if ((prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) { -			au_writel((1 << 16) | au_readl(Au1500_PCI_CFG), -				  Au1500_PCI_CFG); -			printk(KERN_INFO "Non-coherent PCI accesses enabled\n"); -		} -	} -#endif - -	set_io_port_base(virt_io_addr); -#endif - -	au1x_pci_cfg_init(); - -	register_pci_controller(&au1x_controller); -	return 0; -} - -arch_initcall(au1x_pci_setup); diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index 3691630931d..9837a134a6d 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -13,11 +13,14 @@  #include <linux/dma-mapping.h>  #include <linux/etherdevice.h> +#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/serial_8250.h> -#include <linux/init.h> +#include <linux/slab.h> +#include <linux/usb/ehci_pdriver.h> +#include <linux/usb/ohci_pdriver.h> -#include <asm/mach-au1x00/au1xxx.h> +#include <asm/mach-au1x00/au1000.h>  #include <asm/mach-au1x00/au1xxx_dbdma.h>  #include <asm/mach-au1x00/au1100_mmc.h>  #include <asm/mach-au1x00/au1xxx_eth.h> @@ -27,28 +30,21 @@  static void alchemy_8250_pm(struct uart_port *port, unsigned int state,  			    unsigned int old_state)  { +#ifdef CONFIG_SERIAL_8250  	switch (state) {  	case 0: -		if ((__raw_readl(port->membase + UART_MOD_CNTRL) & 3) != 3) { -			/* power-on sequence as suggested in the databooks */ -			__raw_writel(0, port->membase + UART_MOD_CNTRL); -			wmb(); -			__raw_writel(1, port->membase + UART_MOD_CNTRL); -			wmb(); -		} -		__raw_writel(3, port->membase + UART_MOD_CNTRL); /* full on */ -		wmb(); +		alchemy_uart_enable(CPHYSADDR(port->membase));  		serial8250_do_pm(port, state, old_state);  		break;  	case 3:		/* power off */  		serial8250_do_pm(port, state, old_state); -		__raw_writel(0, port->membase + UART_MOD_CNTRL); -		wmb(); +		alchemy_uart_disable(CPHYSADDR(port->membase));  		break;  	default:  		serial8250_do_pm(port, state, old_state);  		break;  	} +#endif  }  #define PORT(_base, _irq)					\ @@ -57,336 +53,272 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state,  		.irq		= _irq,				\  		.regshift	= 2,				\  		.iotype		= UPIO_AU,			\ -		.flags		= UPF_SKIP_TEST | UPF_IOREMAP |	\ +		.flags		= UPF_SKIP_TEST | UPF_IOREMAP | \  				  UPF_FIXED_TYPE,		\  		.type		= PORT_16550A,			\  		.pm		= alchemy_8250_pm,		\  	} -static struct plat_serial8250_port au1x00_uart_data[] = { -#if defined(CONFIG_SOC_AU1000) -	PORT(UART0_PHYS_ADDR, AU1000_UART0_INT), -	PORT(UART1_PHYS_ADDR, AU1000_UART1_INT), -	PORT(UART2_PHYS_ADDR, AU1000_UART2_INT), -	PORT(UART3_PHYS_ADDR, AU1000_UART3_INT), -#elif defined(CONFIG_SOC_AU1500) -	PORT(UART0_PHYS_ADDR, AU1500_UART0_INT), -	PORT(UART3_PHYS_ADDR, AU1500_UART3_INT), -#elif defined(CONFIG_SOC_AU1100) -	PORT(UART0_PHYS_ADDR, AU1100_UART0_INT), -	PORT(UART1_PHYS_ADDR, AU1100_UART1_INT), -	PORT(UART3_PHYS_ADDR, AU1100_UART3_INT), -#elif defined(CONFIG_SOC_AU1550) -	PORT(UART0_PHYS_ADDR, AU1550_UART0_INT), -	PORT(UART1_PHYS_ADDR, AU1550_UART1_INT), -	PORT(UART3_PHYS_ADDR, AU1550_UART3_INT), -#elif defined(CONFIG_SOC_AU1200) -	PORT(UART0_PHYS_ADDR, AU1200_UART0_INT), -	PORT(UART1_PHYS_ADDR, AU1200_UART1_INT), -#endif -	{ }, +static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = { +	[ALCHEMY_CPU_AU1000] = { +		PORT(AU1000_UART0_PHYS_ADDR, AU1000_UART0_INT), +		PORT(AU1000_UART1_PHYS_ADDR, AU1000_UART1_INT), +		PORT(AU1000_UART2_PHYS_ADDR, AU1000_UART2_INT), +		PORT(AU1000_UART3_PHYS_ADDR, AU1000_UART3_INT), +	}, +	[ALCHEMY_CPU_AU1500] = { +		PORT(AU1000_UART0_PHYS_ADDR, AU1500_UART0_INT), +		PORT(AU1000_UART3_PHYS_ADDR, AU1500_UART3_INT), +	}, +	[ALCHEMY_CPU_AU1100] = { +		PORT(AU1000_UART0_PHYS_ADDR, AU1100_UART0_INT), +		PORT(AU1000_UART1_PHYS_ADDR, AU1100_UART1_INT), +		PORT(AU1000_UART3_PHYS_ADDR, AU1100_UART3_INT), +	}, +	[ALCHEMY_CPU_AU1550] = { +		PORT(AU1000_UART0_PHYS_ADDR, AU1550_UART0_INT), +		PORT(AU1000_UART1_PHYS_ADDR, AU1550_UART1_INT), +		PORT(AU1000_UART3_PHYS_ADDR, AU1550_UART3_INT), +	}, +	[ALCHEMY_CPU_AU1200] = { +		PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT), +		PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT), +	}, +	[ALCHEMY_CPU_AU1300] = { +		PORT(AU1300_UART0_PHYS_ADDR, AU1300_UART0_INT), +		PORT(AU1300_UART1_PHYS_ADDR, AU1300_UART1_INT), +		PORT(AU1300_UART2_PHYS_ADDR, AU1300_UART2_INT), +		PORT(AU1300_UART3_PHYS_ADDR, AU1300_UART3_INT), +	},  };  static struct platform_device au1xx0_uart_device = {  	.name			= "serial8250",  	.id			= PLAT8250_DEV_AU1X00, -	.dev			= { -		.platform_data	= au1x00_uart_data, -	},  }; -/* OHCI (USB full speed host controller) */ -static struct resource au1xxx_usb_ohci_resources[] = { -	[0] = { -		.start		= USB_OHCI_BASE, -		.end		= USB_OHCI_BASE + USB_OHCI_LEN - 1, -		.flags		= IORESOURCE_MEM, -	}, -	[1] = { -		.start		= FOR_PLATFORM_C_USB_HOST_INT, -		.end		= FOR_PLATFORM_C_USB_HOST_INT, -		.flags		= IORESOURCE_IRQ, -	}, -}; +static void __init alchemy_setup_uarts(int ctype) +{ +	unsigned int uartclk = get_au1x00_uart_baud_base() * 16; +	int s = sizeof(struct plat_serial8250_port); +	int c = alchemy_get_uarts(ctype); +	struct plat_serial8250_port *ports; -/* The dmamask must be set for OHCI to work */ -static u64 ohci_dmamask = DMA_BIT_MASK(32); +	ports = kzalloc(s * (c + 1), GFP_KERNEL); +	if (!ports) { +		printk(KERN_INFO "Alchemy: no memory for UART data\n"); +		return; +	} +	memcpy(ports, au1x00_uart_data[ctype], s * c); +	au1xx0_uart_device.dev.platform_data = ports; -static struct platform_device au1xxx_usb_ohci_device = { -	.name		= "au1xxx-ohci", -	.id		= 0, -	.dev = { -		.dma_mask		= &ohci_dmamask, -		.coherent_dma_mask	= DMA_BIT_MASK(32), -	}, -	.num_resources	= ARRAY_SIZE(au1xxx_usb_ohci_resources), -	.resource	= au1xxx_usb_ohci_resources, -}; +	/* Fill up uartclk. */ +	for (s = 0; s < c; s++) +		ports[s].uartclk = uartclk; +	if (platform_device_register(&au1xx0_uart_device)) +		printk(KERN_INFO "Alchemy: failed to register UARTs\n"); +} -/*** AU1100 LCD controller ***/ -#ifdef CONFIG_FB_AU1100 -static struct resource au1100_lcd_resources[] = { -	[0] = { -		.start          = LCD_PHYS_ADDR, -		.end            = LCD_PHYS_ADDR + 0x800 - 1, -		.flags          = IORESOURCE_MEM, -	}, -	[1] = { -		.start          = AU1100_LCD_INT, -		.end            = AU1100_LCD_INT, -		.flags          = IORESOURCE_IRQ, -	} -}; +/* The dmamask must be set for OHCI/EHCI to work */ +static u64 alchemy_ohci_dmamask = DMA_BIT_MASK(32); +static u64 __maybe_unused alchemy_ehci_dmamask = DMA_BIT_MASK(32); -static u64 au1100_lcd_dmamask = DMA_BIT_MASK(32); +/* Power on callback for the ehci platform driver */ +static int alchemy_ehci_power_on(struct platform_device *pdev) +{ +	return alchemy_usb_control(ALCHEMY_USB_EHCI0, 1); +} -static struct platform_device au1100_lcd_device = { -	.name           = "au1100-lcd", -	.id             = 0, -	.dev = { -		.dma_mask               = &au1100_lcd_dmamask, -		.coherent_dma_mask      = DMA_BIT_MASK(32), -	}, -	.num_resources  = ARRAY_SIZE(au1100_lcd_resources), -	.resource       = au1100_lcd_resources, -}; -#endif +/* Power off/suspend callback for the ehci platform driver */ +static void alchemy_ehci_power_off(struct platform_device *pdev) +{ +	alchemy_usb_control(ALCHEMY_USB_EHCI0, 0); +} -#ifdef CONFIG_SOC_AU1200 -/* EHCI (USB high speed host controller) */ -static struct resource au1xxx_usb_ehci_resources[] = { -	[0] = { -		.start		= USB_EHCI_BASE, -		.end		= USB_EHCI_BASE + USB_EHCI_LEN - 1, -		.flags		= IORESOURCE_MEM, -	}, -	[1] = { -		.start		= AU1200_USB_INT, -		.end		= AU1200_USB_INT, -		.flags		= IORESOURCE_IRQ, -	}, +static struct usb_ehci_pdata alchemy_ehci_pdata = { +	.no_io_watchdog = 1, +	.power_on	= alchemy_ehci_power_on, +	.power_off	= alchemy_ehci_power_off, +	.power_suspend	= alchemy_ehci_power_off,  }; -static u64 ehci_dmamask = DMA_BIT_MASK(32); +/* Power on callback for the ohci platform driver */ +static int alchemy_ohci_power_on(struct platform_device *pdev) +{ +	int unit; -static struct platform_device au1xxx_usb_ehci_device = { -	.name		= "au1xxx-ehci", -	.id		= 0, -	.dev = { -		.dma_mask		= &ehci_dmamask, -		.coherent_dma_mask	= DMA_BIT_MASK(32), -	}, -	.num_resources	= ARRAY_SIZE(au1xxx_usb_ehci_resources), -	.resource	= au1xxx_usb_ehci_resources, -}; +	unit = (pdev->id == 1) ? +		ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; -/* Au1200 UDC (USB gadget controller) */ -static struct resource au1xxx_usb_gdt_resources[] = { -	[0] = { -		.start		= USB_UDC_BASE, -		.end		= USB_UDC_BASE + USB_UDC_LEN - 1, -		.flags		= IORESOURCE_MEM, -	}, -	[1] = { -		.start		= AU1200_USB_INT, -		.end		= AU1200_USB_INT, -		.flags		= IORESOURCE_IRQ, -	}, -}; +	return alchemy_usb_control(unit, 1); +} -static u64 udc_dmamask = DMA_BIT_MASK(32); +/* Power off/suspend callback for the ohci platform driver */ +static void alchemy_ohci_power_off(struct platform_device *pdev) +{ +	int unit; -static struct platform_device au1xxx_usb_gdt_device = { -	.name		= "au1xxx-udc", -	.id		= 0, -	.dev = { -		.dma_mask		= &udc_dmamask, -		.coherent_dma_mask	= DMA_BIT_MASK(32), -	}, -	.num_resources	= ARRAY_SIZE(au1xxx_usb_gdt_resources), -	.resource	= au1xxx_usb_gdt_resources, -}; +	unit = (pdev->id == 1) ? +		ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0; -/* Au1200 UOC (USB OTG controller) */ -static struct resource au1xxx_usb_otg_resources[] = { -	[0] = { -		.start		= USB_UOC_BASE, -		.end		= USB_UOC_BASE + USB_UOC_LEN - 1, -		.flags		= IORESOURCE_MEM, -	}, -	[1] = { -		.start		= AU1200_USB_INT, -		.end		= AU1200_USB_INT, -		.flags		= IORESOURCE_IRQ, -	}, +	alchemy_usb_control(unit, 0); +} + +static struct usb_ohci_pdata alchemy_ohci_pdata = { +	.power_on		= alchemy_ohci_power_on, +	.power_off		= alchemy_ohci_power_off, +	.power_suspend		= alchemy_ohci_power_off,  }; -static u64 uoc_dmamask = DMA_BIT_MASK(32); +static unsigned long alchemy_ohci_data[][2] __initdata = { +	[ALCHEMY_CPU_AU1000] = { AU1000_USB_OHCI_PHYS_ADDR, AU1000_USB_HOST_INT }, +	[ALCHEMY_CPU_AU1500] = { AU1000_USB_OHCI_PHYS_ADDR, AU1500_USB_HOST_INT }, +	[ALCHEMY_CPU_AU1100] = { AU1000_USB_OHCI_PHYS_ADDR, AU1100_USB_HOST_INT }, +	[ALCHEMY_CPU_AU1550] = { AU1550_USB_OHCI_PHYS_ADDR, AU1550_USB_HOST_INT }, +	[ALCHEMY_CPU_AU1200] = { AU1200_USB_OHCI_PHYS_ADDR, AU1200_USB_INT }, +	[ALCHEMY_CPU_AU1300] = { AU1300_USB_OHCI0_PHYS_ADDR, AU1300_USB_INT }, +}; -static struct platform_device au1xxx_usb_otg_device = { -	.name		= "au1xxx-uoc", -	.id		= 0, -	.dev = { -		.dma_mask		= &uoc_dmamask, -		.coherent_dma_mask	= DMA_BIT_MASK(32), -	}, -	.num_resources	= ARRAY_SIZE(au1xxx_usb_otg_resources), -	.resource	= au1xxx_usb_otg_resources, +static unsigned long alchemy_ehci_data[][2] __initdata = { +	[ALCHEMY_CPU_AU1200] = { AU1200_USB_EHCI_PHYS_ADDR, AU1200_USB_INT }, +	[ALCHEMY_CPU_AU1300] = { AU1300_USB_EHCI_PHYS_ADDR, AU1300_USB_INT },  }; -static struct resource au1200_lcd_resources[] = { -	[0] = { -		.start          = LCD_PHYS_ADDR, -		.end            = LCD_PHYS_ADDR + 0x800 - 1, -		.flags          = IORESOURCE_MEM, -	}, -	[1] = { -		.start          = AU1200_LCD_INT, -		.end            = AU1200_LCD_INT, -		.flags          = IORESOURCE_IRQ, +static int __init _new_usbres(struct resource **r, struct platform_device **d) +{ +	*r = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); +	if (!*r) +		return -ENOMEM; +	*d = kzalloc(sizeof(struct platform_device), GFP_KERNEL); +	if (!*d) { +		kfree(*r); +		return -ENOMEM;  	} -}; -static u64 au1200_lcd_dmamask = DMA_BIT_MASK(32); +	(*d)->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	(*d)->num_resources = 2; +	(*d)->resource = *r; -static struct platform_device au1200_lcd_device = { -	.name           = "au1200-lcd", -	.id             = 0, -	.dev = { -		.dma_mask               = &au1200_lcd_dmamask, -		.coherent_dma_mask      = DMA_BIT_MASK(32), -	}, -	.num_resources  = ARRAY_SIZE(au1200_lcd_resources), -	.resource       = au1200_lcd_resources, -}; +	return 0; +} -static u64 au1xxx_mmc_dmamask =  DMA_BIT_MASK(32); +static void __init alchemy_setup_usb(int ctype) +{ +	struct resource *res; +	struct platform_device *pdev; -extern struct au1xmmc_platform_data au1xmmc_platdata[2]; +	/* setup OHCI0.  Every variant has one */ +	if (_new_usbres(&res, &pdev)) +		return; -static struct resource au1200_mmc0_resources[] = { -	[0] = { -		.start          = SD0_PHYS_ADDR, -		.end            = SD0_PHYS_ADDR + 0x7ffff, -		.flags          = IORESOURCE_MEM, -	}, -	[1] = { -		.start		= AU1200_SD_INT, -		.end		= AU1200_SD_INT, -		.flags		= IORESOURCE_IRQ, -	}, -	[2] = { -		.start		= DSCR_CMD0_SDMS_TX0, -		.end		= DSCR_CMD0_SDMS_TX0, -		.flags		= IORESOURCE_DMA, -	}, -	[3] = { -		.start          = DSCR_CMD0_SDMS_RX0, -		.end		= DSCR_CMD0_SDMS_RX0, -		.flags          = IORESOURCE_DMA, +	res[0].start = alchemy_ohci_data[ctype][0]; +	res[0].end = res[0].start + 0x100 - 1; +	res[0].flags = IORESOURCE_MEM; +	res[1].start = alchemy_ohci_data[ctype][1]; +	res[1].end = res[1].start; +	res[1].flags = IORESOURCE_IRQ; +	pdev->name = "ohci-platform"; +	pdev->id = 0; +	pdev->dev.dma_mask = &alchemy_ohci_dmamask; +	pdev->dev.platform_data = &alchemy_ohci_pdata; + +	if (platform_device_register(pdev)) +		printk(KERN_INFO "Alchemy USB: cannot add OHCI0\n"); + + +	/* setup EHCI0: Au1200/Au1300 */ +	if ((ctype == ALCHEMY_CPU_AU1200) || (ctype == ALCHEMY_CPU_AU1300)) { +		if (_new_usbres(&res, &pdev)) +			return; + +		res[0].start = alchemy_ehci_data[ctype][0]; +		res[0].end = res[0].start + 0x100 - 1; +		res[0].flags = IORESOURCE_MEM; +		res[1].start = alchemy_ehci_data[ctype][1]; +		res[1].end = res[1].start; +		res[1].flags = IORESOURCE_IRQ; +		pdev->name = "ehci-platform"; +		pdev->id = 0; +		pdev->dev.dma_mask = &alchemy_ehci_dmamask; +		pdev->dev.platform_data = &alchemy_ehci_pdata; + +		if (platform_device_register(pdev)) +			printk(KERN_INFO "Alchemy USB: cannot add EHCI0\n");  	} -}; -static struct platform_device au1200_mmc0_device = { -	.name = "au1xxx-mmc", -	.id = 0, -	.dev = { -		.dma_mask		= &au1xxx_mmc_dmamask, -		.coherent_dma_mask	= DMA_BIT_MASK(32), -		.platform_data		= &au1xmmc_platdata[0], -	}, -	.num_resources	= ARRAY_SIZE(au1200_mmc0_resources), -	.resource	= au1200_mmc0_resources, -}; - -#ifndef CONFIG_MIPS_DB1200 -static struct resource au1200_mmc1_resources[] = { -	[0] = { -		.start          = SD1_PHYS_ADDR, -		.end            = SD1_PHYS_ADDR + 0x7ffff, -		.flags          = IORESOURCE_MEM, -	}, -	[1] = { -		.start		= AU1200_SD_INT, -		.end		= AU1200_SD_INT, -		.flags		= IORESOURCE_IRQ, -	}, -	[2] = { -		.start		= DSCR_CMD0_SDMS_TX1, -		.end		= DSCR_CMD0_SDMS_TX1, -		.flags		= IORESOURCE_DMA, -	}, -	[3] = { -		.start          = DSCR_CMD0_SDMS_RX1, -		.end		= DSCR_CMD0_SDMS_RX1, -		.flags          = IORESOURCE_DMA, +	/* Au1300: OHCI1 */ +	if (ctype == ALCHEMY_CPU_AU1300) { +		if (_new_usbres(&res, &pdev)) +			return; + +		res[0].start = AU1300_USB_OHCI1_PHYS_ADDR; +		res[0].end = res[0].start + 0x100 - 1; +		res[0].flags = IORESOURCE_MEM; +		res[1].start = AU1300_USB_INT; +		res[1].end = res[1].start; +		res[1].flags = IORESOURCE_IRQ; +		pdev->name = "ohci-platform"; +		pdev->id = 1; +		pdev->dev.dma_mask = &alchemy_ohci_dmamask; +		pdev->dev.platform_data = &alchemy_ohci_pdata; + +		if (platform_device_register(pdev)) +			printk(KERN_INFO "Alchemy USB: cannot add OHCI1\n");  	} -}; - -static struct platform_device au1200_mmc1_device = { -	.name = "au1xxx-mmc", -	.id = 1, -	.dev = { -		.dma_mask		= &au1xxx_mmc_dmamask, -		.coherent_dma_mask	= DMA_BIT_MASK(32), -		.platform_data		= &au1xmmc_platdata[1], -	}, -	.num_resources	= ARRAY_SIZE(au1200_mmc1_resources), -	.resource	= au1200_mmc1_resources, -}; -#endif /* #ifndef CONFIG_MIPS_DB1200 */ -#endif /* #ifdef CONFIG_SOC_AU1200 */ - -/* All Alchemy demoboards with I2C have this #define in their headers */ -#ifdef SMBUS_PSC_BASE -static struct resource pbdb_smbus_resources[] = { -	{ -		.start	= CPHYSADDR(SMBUS_PSC_BASE), -		.end	= CPHYSADDR(SMBUS_PSC_BASE + 0xfffff), -		.flags	= IORESOURCE_MEM, -	}, -}; - -static struct platform_device pbdb_smbus_device = { -	.name		= "au1xpsc_smbus", -	.id		= 0,	/* bus number */ -	.num_resources	= ARRAY_SIZE(pbdb_smbus_resources), -	.resource	= pbdb_smbus_resources, -}; -#endif +}  /* Macro to help defining the Ethernet MAC resources */ -#define MAC_RES(_base, _enable, _irq)			\ +#define MAC_RES_COUNT	4	/* MAC regs, MAC en, MAC INT, MACDMA regs */ +#define MAC_RES(_base, _enable, _irq, _macdma)		\  	{						\ -		.start	= CPHYSADDR(_base),		\ -		.end	= CPHYSADDR(_base + 0xffff),	\ +		.start	= _base,			\ +		.end	= _base + 0xffff,		\  		.flags	= IORESOURCE_MEM,		\  	},						\  	{						\ -		.start	= CPHYSADDR(_enable),		\ -		.end	= CPHYSADDR(_enable + 0x3),	\ +		.start	= _enable,			\ +		.end	= _enable + 0x3,		\  		.flags	= IORESOURCE_MEM,		\  	},						\  	{						\  		.start	= _irq,				\  		.end	= _irq,				\  		.flags	= IORESOURCE_IRQ		\ +	},						\ +	{						\ +		.start	= _macdma,			\ +		.end	= _macdma + 0x1ff,		\ +		.flags	= IORESOURCE_MEM,		\  	} -static struct resource au1xxx_eth0_resources[] = { -#if defined(CONFIG_SOC_AU1000) -	MAC_RES(AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1100) -	MAC_RES(AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1550) -	MAC_RES(AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT), -#elif defined(CONFIG_SOC_AU1500) -	MAC_RES(AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT), -#endif +static struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = { +	[ALCHEMY_CPU_AU1000] = { +		MAC_RES(AU1000_MAC0_PHYS_ADDR, +			AU1000_MACEN_PHYS_ADDR, +			AU1000_MAC0_DMA_INT, +			AU1000_MACDMA0_PHYS_ADDR) +	}, +	[ALCHEMY_CPU_AU1500] = { +		MAC_RES(AU1500_MAC0_PHYS_ADDR, +			AU1500_MACEN_PHYS_ADDR, +			AU1500_MAC0_DMA_INT, +			AU1000_MACDMA0_PHYS_ADDR) +	}, +	[ALCHEMY_CPU_AU1100] = { +		MAC_RES(AU1000_MAC0_PHYS_ADDR, +			AU1000_MACEN_PHYS_ADDR, +			AU1100_MAC0_DMA_INT, +			AU1000_MACDMA0_PHYS_ADDR) +	}, +	[ALCHEMY_CPU_AU1550] = { +		MAC_RES(AU1000_MAC0_PHYS_ADDR, +			AU1000_MACEN_PHYS_ADDR, +			AU1550_MAC0_DMA_INT, +			AU1000_MACDMA0_PHYS_ADDR) +	},  }; -  static struct au1000_eth_platform_data au1xxx_eth0_platform_data = {  	.phy1_search_mac0 = 1,  }; @@ -394,20 +326,29 @@ static struct au1000_eth_platform_data au1xxx_eth0_platform_data = {  static struct platform_device au1xxx_eth0_device = {  	.name		= "au1000-eth",  	.id		= 0, -	.num_resources	= ARRAY_SIZE(au1xxx_eth0_resources), -	.resource	= au1xxx_eth0_resources, +	.num_resources	= MAC_RES_COUNT,  	.dev.platform_data = &au1xxx_eth0_platform_data,  }; -#ifndef CONFIG_SOC_AU1100 -static struct resource au1xxx_eth1_resources[] = { -#if defined(CONFIG_SOC_AU1000) -	MAC_RES(AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT), -#elif defined(CONFIG_SOC_AU1550) -	MAC_RES(AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT), -#elif defined(CONFIG_SOC_AU1500) -	MAC_RES(AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT), -#endif +static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = { +	[ALCHEMY_CPU_AU1000] = { +		MAC_RES(AU1000_MAC1_PHYS_ADDR, +			AU1000_MACEN_PHYS_ADDR + 4, +			AU1000_MAC1_DMA_INT, +			AU1000_MACDMA1_PHYS_ADDR) +	}, +	[ALCHEMY_CPU_AU1500] = { +		MAC_RES(AU1500_MAC1_PHYS_ADDR, +			AU1500_MACEN_PHYS_ADDR + 4, +			AU1500_MAC1_DMA_INT, +			AU1000_MACDMA1_PHYS_ADDR) +	}, +	[ALCHEMY_CPU_AU1550] = { +		MAC_RES(AU1000_MAC1_PHYS_ADDR, +			AU1000_MACEN_PHYS_ADDR + 4, +			AU1550_MAC1_DMA_INT, +			AU1000_MACDMA1_PHYS_ADDR) +	},  };  static struct au1000_eth_platform_data au1xxx_eth1_platform_data = { @@ -417,11 +358,9 @@ static struct au1000_eth_platform_data au1xxx_eth1_platform_data = {  static struct platform_device au1xxx_eth1_device = {  	.name		= "au1000-eth",  	.id		= 1, -	.num_resources	= ARRAY_SIZE(au1xxx_eth1_resources), -	.resource	= au1xxx_eth1_resources, +	.num_resources	= MAC_RES_COUNT,  	.dev.platform_data = &au1xxx_eth1_platform_data,  }; -#endif  void __init au1xxx_override_eth_cfg(unsigned int port,  			struct au1000_eth_platform_data *eth_data) @@ -432,63 +371,71 @@ void __init au1xxx_override_eth_cfg(unsigned int port,  	if (port == 0)  		memcpy(&au1xxx_eth0_platform_data, eth_data,  			sizeof(struct au1000_eth_platform_data)); -#ifndef CONFIG_SOC_AU1100  	else  		memcpy(&au1xxx_eth1_platform_data, eth_data,  			sizeof(struct au1000_eth_platform_data)); -#endif  } -static struct platform_device *au1xxx_platform_devices[] __initdata = { -	&au1xx0_uart_device, -	&au1xxx_usb_ohci_device, -#ifdef CONFIG_FB_AU1100 -	&au1100_lcd_device, -#endif -#ifdef CONFIG_SOC_AU1200 -	&au1xxx_usb_ehci_device, -	&au1xxx_usb_gdt_device, -	&au1xxx_usb_otg_device, -	&au1200_lcd_device, -	&au1200_mmc0_device, -#ifndef CONFIG_MIPS_DB1200 -	&au1200_mmc1_device, -#endif -#endif -#ifdef SMBUS_PSC_BASE -	&pbdb_smbus_device, -#endif -	&au1xxx_eth0_device, -}; - -static int __init au1xxx_platform_init(void) +static void __init alchemy_setup_macs(int ctype)  { -	unsigned int uartclk = get_au1x00_uart_baud_base() * 16; -	int err, i; +	int ret, i;  	unsigned char ethaddr[6]; +	struct resource *macres; -	/* Fill up uartclk. */ -	for (i = 0; au1x00_uart_data[i].flags; i++) -		au1x00_uart_data[i].uartclk = uartclk; +	/* Handle 1st MAC */ +	if (alchemy_get_macs(ctype) < 1) +		return; + +	macres = kmemdup(au1xxx_eth0_resources[ctype], +			 sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); +	if (!macres) { +		printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n"); +		return; +	} +	au1xxx_eth0_device.resource = macres; -	/* use firmware-provided mac addr if available and necessary */  	i = prom_get_ethernet_addr(ethaddr);  	if (!i && !is_valid_ether_addr(au1xxx_eth0_platform_data.mac))  		memcpy(au1xxx_eth0_platform_data.mac, ethaddr, 6); -	err = platform_add_devices(au1xxx_platform_devices, -				   ARRAY_SIZE(au1xxx_platform_devices)); -#ifndef CONFIG_SOC_AU1100 +	ret = platform_device_register(&au1xxx_eth0_device); +	if (ret) +		printk(KERN_INFO "Alchemy: failed to register MAC0\n"); + + +	/* Handle 2nd MAC */ +	if (alchemy_get_macs(ctype) < 2) +		return; + +	macres = kmemdup(au1xxx_eth1_resources[ctype], +			 sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL); +	if (!macres) { +		printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n"); +		return; +	} +	au1xxx_eth1_device.resource = macres; +  	ethaddr[5] += 1;	/* next addr for 2nd MAC */  	if (!i && !is_valid_ether_addr(au1xxx_eth1_platform_data.mac))  		memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6);  	/* Register second MAC if enabled in pinfunc */ -	if (!err && !(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) -		err = platform_device_register(&au1xxx_eth1_device); -#endif +	if (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) { +		ret = platform_device_register(&au1xxx_eth1_device); +		if (ret) +			printk(KERN_INFO "Alchemy: failed to register MAC1\n"); +	} +} + +static int __init au1xxx_platform_init(void) +{ +	int ctype = alchemy_get_cputype(); + +	alchemy_setup_uarts(ctype); +	alchemy_setup_macs(ctype); +	alchemy_setup_usb(ctype); -	return err; +	return 0;  }  arch_initcall(au1xxx_platform_init); diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c index e5916a516e5..bdb28dee8fd 100644 --- a/arch/mips/alchemy/common/power.c +++ b/arch/mips/alchemy/common/power.c @@ -29,7 +29,6 @@   *  675 Mass Ave, Cambridge, MA 02139, USA.   */ -#include <linux/init.h>  #include <linux/pm.h>  #include <linux/sysctl.h>  #include <linux/jiffies.h> @@ -37,8 +36,6 @@  #include <asm/uaccess.h>  #include <asm/mach-au1x00/au1000.h> -#ifdef CONFIG_PM -  /*   * We need to save/restore a bunch of core registers that are   * either volatile or reset to some state across a processor sleep. @@ -49,7 +46,6 @@   * We only have to save/restore registers that aren't otherwise   * done as part of a driver pm_* function.   */ -static unsigned int sleep_usb[2];  static unsigned int sleep_sys_clocks[5];  static unsigned int sleep_sys_pinfunc;  static unsigned int sleep_static_memctlr[4][3]; @@ -57,31 +53,6 @@ static unsigned int sleep_static_memctlr[4][3];  static void save_core_regs(void)  { -#ifndef CONFIG_SOC_AU1200 -	/* Shutdown USB host/device. */ -	sleep_usb[0] = au_readl(USB_HOST_CONFIG); - -	/* There appears to be some undocumented reset register.... */ -	au_writel(0, 0xb0100004); -	au_sync(); -	au_writel(0, USB_HOST_CONFIG); -	au_sync(); - -	sleep_usb[1] = au_readl(USBD_ENABLE); -	au_writel(0, USBD_ENABLE); -	au_sync(); - -#else	/* AU1200 */ - -	/* enable access to OTG mmio so we can save OTG CAP/MUX. -	 * FIXME: write an OTG driver and move this stuff there! -	 */ -	au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4); -	au_sync(); -	sleep_usb[0] = au_readl(0xb4020020);	/* OTG_CAP */ -	sleep_usb[1] = au_readl(0xb4020024);	/* OTG_MUX */ -#endif -  	/* Clocks and PLLs. */  	sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0);  	sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1); @@ -125,22 +96,6 @@ static void restore_core_regs(void)  	au_writel(sleep_sys_pinfunc, SYS_PINFUNC);  	au_sync(); -#ifndef CONFIG_SOC_AU1200 -	au_writel(sleep_usb[0], USB_HOST_CONFIG); -	au_writel(sleep_usb[1], USBD_ENABLE); -	au_sync(); -#else -	/* enable accces to OTG memory */ -	au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4); -	au_sync(); - -	/* restore OTG caps and port mux. */ -	au_writel(sleep_usb[0], 0xb4020020 + 0);	/* OTG_CAP */ -	au_sync(); -	au_writel(sleep_usb[1], 0xb4020020 + 4);	/* OTG_MUX */ -	au_sync(); -#endif -  	/* Restore the static memory controller configuration. */  	au_writel(sleep_static_memctlr[0][0], MEM_STCFG0);  	au_writel(sleep_static_memctlr[0][1], MEM_STTIME0); @@ -158,15 +113,22 @@ static void restore_core_regs(void)  void au_sleep(void)  { -	int cpuid = alchemy_get_cputype(); -	if (cpuid != ALCHEMY_CPU_UNKNOWN) { -		save_core_regs(); -		if (cpuid <= ALCHEMY_CPU_AU1500) -			alchemy_sleep_au1000(); -		else if (cpuid <= ALCHEMY_CPU_AU1200) -			alchemy_sleep_au1550(); -		restore_core_regs(); +	save_core_regs(); + +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1000: +	case ALCHEMY_CPU_AU1500: +	case ALCHEMY_CPU_AU1100: +		alchemy_sleep_au1000(); +		break; +	case ALCHEMY_CPU_AU1550: +	case ALCHEMY_CPU_AU1200: +		alchemy_sleep_au1550(); +		break; +	case ALCHEMY_CPU_AU1300: +		alchemy_sleep_au1300(); +		break;  	} -} -#endif	/* CONFIG_PM */ +	restore_core_regs(); +} diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 561e5da2658..8267e3c9772 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -30,6 +30,7 @@  #include <linux/jiffies.h>  #include <linux/module.h> +#include <asm/dma-coherence.h>  #include <asm/mipsregs.h>  #include <asm/time.h> @@ -52,8 +53,6 @@ void __init plat_mem_setup(void)  	/* this is faster than wasting cycles trying to approximate it */  	preset_lpj = (est_freq >> 1) / HZ; -	board_setup();  /* board specific setup */ -  	if (au1xxx_cpu_needs_config_od())  		/* Various early Au1xx0 errata corrected by this */  		set_c0_config(1 << 19); /* Set Config[OD] */ @@ -61,6 +60,23 @@ void __init plat_mem_setup(void)  		/* Clear to obtain best system bus performance */  		clear_c0_config(1 << 19); /* Clear Config[OD] */ +	hw_coherentio = 0; +	coherentio = 1; +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1000: +	case ALCHEMY_CPU_AU1500: +	case ALCHEMY_CPU_AU1100: +		coherentio = 0; +		break; +	case ALCHEMY_CPU_AU1200: +		/* Au1200 AB USB does not support coherent memory */ +		if (0 == (read_c0_prid() & PRID_REV_MASK)) +			coherentio = 0; +		break; +	} + +	board_setup();	/* board specific setup */ +  	/* IO/MEM resources. */  	set_io_port_base(0);  	ioport_resource.start = IOPORT_RESOURCE_START; @@ -73,8 +89,8 @@ void __init plat_mem_setup(void)  /* This routine should be valid for all Au1x based boards */  phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size)  { -	u32 start = (u32)Au1500_PCI_MEM_START; -	u32 end   = (u32)Au1500_PCI_MEM_END; +	unsigned long start = ALCHEMY_PCI_MEMWIN_START; +	unsigned long end = ALCHEMY_PCI_MEMWIN_END;  	/* Don't fixup 36-bit addresses */  	if ((phys_addr >> 32) != 0) @@ -82,7 +98,7 @@ phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size)  	/* Check for PCI memory window */  	if (phys_addr >= start && (phys_addr + size - 1) <= end) -		return (phys_t)((phys_addr - start) + Au1500_PCI_MEM_START); +		return (phys_t)(AU1500_PCI_MEM_PHYS_ADDR + phys_addr);  	/* default nop */  	return phys_addr; diff --git a/arch/mips/alchemy/common/sleeper.S b/arch/mips/alchemy/common/sleeper.S index 77f3c743b71..c73d81270b4 100644 --- a/arch/mips/alchemy/common/sleeper.S +++ b/arch/mips/alchemy/common/sleeper.S @@ -95,19 +95,19 @@ LEAF(alchemy_sleep_au1000)  	/* cache following instructions, as memory gets put to sleep */  	la	t0, 1f -	.set	mips3 +	.set	arch=r4000  	cache	0x14, 0(t0)  	cache	0x14, 32(t0)  	cache	0x14, 64(t0)  	cache	0x14, 96(t0)  	.set	mips0 -1:	lui 	a0, 0xb400		/* mem_xxx */ -	sw	zero, 0x001c(a0) 	/* Precharge */ +1:	lui	a0, 0xb400		/* mem_xxx */ +	sw	zero, 0x001c(a0)	/* Precharge */  	sync  	sw	zero, 0x0020(a0)	/* Auto Refresh */  	sync -	sw	zero, 0x0030(a0)  	/* Sleep */ +	sw	zero, 0x0030(a0)	/* Sleep */  	sync  	DO_SLEEP @@ -121,22 +121,22 @@ LEAF(alchemy_sleep_au1550)  	/* cache following instructions, as memory gets put to sleep */  	la	t0, 1f -	.set	mips3 +	.set	arch=r4000  	cache	0x14, 0(t0)  	cache	0x14, 32(t0)  	cache	0x14, 64(t0)  	cache	0x14, 96(t0)  	.set	mips0 -1:	lui 	a0, 0xb400		/* mem_xxx */ -	sw	zero, 0x08c0(a0) 	/* Precharge */ +1:	lui	a0, 0xb400		/* mem_xxx */ +	sw	zero, 0x08c0(a0)	/* Precharge */  	sync  	sw	zero, 0x08d0(a0)	/* Self Refresh */  	sync  	/* wait for sdram to enter self-refresh mode */ -	lui 	t0, 0x0100 -2:	lw 	t1, 0x0850(a0)		/* mem_sdstat */ +	lui	t0, 0x0100 +2:	lw	t1, 0x0850(a0)		/* mem_sdstat */  	and	t2, t1, t0  	beq	t2, zero, 2b  	 nop @@ -144,15 +144,88 @@ LEAF(alchemy_sleep_au1550)  	/* disable SDRAM clocks */  	lui	t0, 0xcfff  	ori	t0, t0, 0xffff -	lw 	t1, 0x0840(a0)		/* mem_sdconfiga */ -	and 	t1, t0, t1		/* clear CE[1:0] */ -	sw 	t1, 0x0840(a0)		/* mem_sdconfiga */ +	lw	t1, 0x0840(a0)		/* mem_sdconfiga */ +	and	t1, t0, t1		/* clear CE[1:0] */ +	sw	t1, 0x0840(a0)		/* mem_sdconfiga */  	sync  	DO_SLEEP  END(alchemy_sleep_au1550) +/* sleepcode for Au1300 memory controller type */ +LEAF(alchemy_sleep_au1300) + +	SETUP_SLEEP + +	/* cache following instructions, as memory gets put to sleep */ +	la	t0, 2f +	la	t1, 4f +	subu	t2, t1, t0 + +	.set	arch=r4000 + +1:	cache	0x14, 0(t0) +	subu	t2, t2, 32 +	bgez	t2, 1b +	 addu	t0, t0, 32 + +	.set	mips0 + +2:	lui	a0, 0xb400		/* mem_xxx */ + +	/* disable all ports in mem_sdportcfga */ +	sw	zero, 0x868(a0)		/* mem_sdportcfga */ +	sync + +	/* disable ODT */ +	li	t0, 0x03010000 +	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */ +	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */ +	sync + +	/* precharge */ +	li	t0, 0x23000400 +	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */ +	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */ +	sync + +	/* auto refresh */ +	sw	zero, 0x08c8(a0)	/* mem_sdautoref */ +	sync + +	/* block access to the DDR */ +	lw	t0, 0x0848(a0)		/* mem_sdconfigb */ +	li	t1, (1 << 7 | 0x3F) +	or	t0, t0, t1 +	sw	t0, 0x0848(a0)		/* mem_sdconfigb */ +	sync + +	/* issue the Self Refresh command */ +	li	t0, 0x10000000 +	sw	t0, 0x08dc(a0)		/* mem_sdcmd1 */ +	sw	t0, 0x08d8(a0)		/* mem_sdcmd0 */ +	sync + +	/* wait for sdram to enter self-refresh mode */ +	lui	t0, 0x0300 +3:	lw	t1, 0x0850(a0)		/* mem_sdstat */ +	and	t2, t1, t0 +	bne	t2, t0, 3b +	 nop + +	/* disable SDRAM clocks */ +	li	t0, ~(3<<28) +	lw	t1, 0x0840(a0)		/* mem_sdconfiga */ +	and	t1, t1, t0		/* clear CE[1:0] */ +	sw	t1, 0x0840(a0)		/* mem_sdconfiga */ +	sync + +	DO_SLEEP +4: + +END(alchemy_sleep_au1300) +  	/* This is where we return upon wakeup.  	 * Reload all of the registers and return. diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c index 2aecb2fdf98..93fa586d52e 100644 --- a/arch/mips/alchemy/common/time.c +++ b/arch/mips/alchemy/common/time.c @@ -36,6 +36,7 @@  #include <linux/interrupt.h>  #include <linux/spinlock.h> +#include <asm/idle.h>  #include <asm/processor.h>  #include <asm/time.h>  #include <asm/mach-au1x00/au1000.h> @@ -53,7 +54,7 @@ static struct clocksource au1x_counter1_clocksource = {  	.read		= au1x_counter1_read,  	.mask		= CLOCKSOURCE_MASK(32),  	.flags		= CLOCK_SOURCE_IS_CONTINUOUS, -	.rating		= 100, +	.rating		= 1500,  };  static int au1x_rtcmatch2_set_next_event(unsigned long delta, @@ -84,15 +85,15 @@ static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id)  static struct clock_event_device au1x_rtcmatch2_clockdev = {  	.name		= "rtcmatch2",  	.features	= CLOCK_EVT_FEAT_ONESHOT, -	.rating		= 100, -	.set_next_event	= au1x_rtcmatch2_set_next_event, +	.rating		= 1500, +	.set_next_event = au1x_rtcmatch2_set_next_event,  	.set_mode	= au1x_rtcmatch2_set_mode,  	.cpumask	= cpu_all_mask,  };  static struct irqaction au1x_rtcmatch2_irqaction = {  	.handler	= au1x_rtcmatch2_irq, -	.flags		= IRQF_DISABLED | IRQF_TIMER, +	.flags		= IRQF_TIMER,  	.name		= "timer",  	.dev_id		= &au1x_rtcmatch2_clockdev,  }; @@ -141,13 +142,12 @@ static int __init alchemy_time_init(unsigned int m2int)  		goto cntr_err;  	/* register counter1 clocksource and event device */ -	clocksource_set_clock(&au1x_counter1_clocksource, 32768); -	clocksource_register(&au1x_counter1_clocksource); +	clocksource_register_hz(&au1x_counter1_clocksource, 32768);  	cd->shift = 32;  	cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);  	cd->max_delta_ns = clockevent_delta2ns(0xffffffff, cd); -	cd->min_delta_ns = clockevent_delta2ns(8, cd);	/* ~0.25ms */ +	cd->min_delta_ns = clockevent_delta2ns(9, cd);	/* ~0.28ms */  	clockevents_register_device(cd);  	setup_irq(m2int, &au1x_rtcmatch2_irqaction); @@ -159,26 +159,13 @@ cntr_err:  	return -1;  } -static void __init alchemy_setup_c0timer(void) -{ -	/* -	 * MIPS kernel assigns 'au1k_wait' to 'cpu_wait' before this -	 * function is called.  Because the Alchemy counters are unusable -	 * the C0 timekeeping code is installed and use of the 'wait' -	 * instruction must be prohibited, which is done most easily by -	 * assigning NULL to cpu_wait. -	 */ -	cpu_wait = NULL; -	r4k_clockevent_init(); -	init_r4k_clocksource(); -} -  static int alchemy_m2inttab[] __initdata = {  	AU1000_RTC_MATCH2_INT,  	AU1500_RTC_MATCH2_INT,  	AU1100_RTC_MATCH2_INT,  	AU1550_RTC_MATCH2_INT,  	AU1200_RTC_MATCH2_INT, +	AU1300_RTC_MATCH2_INT,  };  void __init plat_time_init(void) @@ -186,8 +173,7 @@ void __init plat_time_init(void)  	int t;  	t = alchemy_get_cputype(); -	if (t == ALCHEMY_CPU_UNKNOWN) -		alchemy_setup_c0timer(); -	else if (alchemy_time_init(alchemy_m2inttab[t])) -		alchemy_setup_c0timer(); +	if (t == ALCHEMY_CPU_UNKNOWN || +	    alchemy_time_init(alchemy_m2inttab[t])) +		cpu_wait = NULL;	/* wait doesn't work with r4k timer */  } diff --git a/arch/mips/alchemy/common/usb.c b/arch/mips/alchemy/common/usb.c new file mode 100644 index 00000000000..d193dbea84a --- /dev/null +++ b/arch/mips/alchemy/common/usb.c @@ -0,0 +1,593 @@ +/* + * USB block power/access management abstraction. + * + * Au1000+: The OHCI block control register is at the far end of the OHCI memory + *	    area. Au1550 has OHCI on different base address. No need to handle + *	    UDC here. + * Au1200:  one register to control access and clocks to O/EHCI, UDC and OTG + *	    as well as the PHY for EHCI and UDC. + * + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/syscore_ops.h> +#include <asm/cpu.h> +#include <asm/mach-au1x00/au1000.h> + +/* control register offsets */ +#define AU1000_OHCICFG	0x7fffc +#define AU1550_OHCICFG	0x07ffc +#define AU1200_USBCFG	0x04 + +/* Au1000 USB block config bits */ +#define USBHEN_RD	(1 << 4)		/* OHCI reset-done indicator */ +#define USBHEN_CE	(1 << 3)		/* OHCI block clock enable */ +#define USBHEN_E	(1 << 2)		/* OHCI block enable */ +#define USBHEN_C	(1 << 1)		/* OHCI block coherency bit */ +#define USBHEN_BE	(1 << 0)		/* OHCI Big-Endian */ + +/* Au1200 USB config bits */ +#define USBCFG_PFEN	(1 << 31)		/* prefetch enable (undoc) */ +#define USBCFG_RDCOMB	(1 << 30)		/* read combining (undoc) */ +#define USBCFG_UNKNOWN	(5 << 20)		/* unknown, leave this way */ +#define USBCFG_SSD	(1 << 23)		/* serial short detect en */ +#define USBCFG_PPE	(1 << 19)		/* HS PHY PLL */ +#define USBCFG_UCE	(1 << 18)		/* UDC clock enable */ +#define USBCFG_ECE	(1 << 17)		/* EHCI clock enable */ +#define USBCFG_OCE	(1 << 16)		/* OHCI clock enable */ +#define USBCFG_FLA(x)	(((x) & 0x3f) << 8) +#define USBCFG_UCAM	(1 << 7)		/* coherent access (undoc) */ +#define USBCFG_GME	(1 << 6)		/* OTG mem access */ +#define USBCFG_DBE	(1 << 5)		/* UDC busmaster enable */ +#define USBCFG_DME	(1 << 4)		/* UDC mem enable */ +#define USBCFG_EBE	(1 << 3)		/* EHCI busmaster enable */ +#define USBCFG_EME	(1 << 2)		/* EHCI mem enable */ +#define USBCFG_OBE	(1 << 1)		/* OHCI busmaster enable */ +#define USBCFG_OME	(1 << 0)		/* OHCI mem enable */ +#define USBCFG_INIT_AU1200	(USBCFG_PFEN | USBCFG_RDCOMB | USBCFG_UNKNOWN |\ +				 USBCFG_SSD | USBCFG_FLA(0x20) | USBCFG_UCAM | \ +				 USBCFG_GME | USBCFG_DBE | USBCFG_DME |	       \ +				 USBCFG_EBE | USBCFG_EME | USBCFG_OBE |	       \ +				 USBCFG_OME) + +/* Au1300 USB config registers */ +#define USB_DWC_CTRL1		0x00 +#define USB_DWC_CTRL2		0x04 +#define USB_VBUS_TIMER		0x10 +#define USB_SBUS_CTRL		0x14 +#define USB_MSR_ERR		0x18 +#define USB_DWC_CTRL3		0x1C +#define USB_DWC_CTRL4		0x20 +#define USB_OTG_STATUS		0x28 +#define USB_DWC_CTRL5		0x2C +#define USB_DWC_CTRL6		0x30 +#define USB_DWC_CTRL7		0x34 +#define USB_PHY_STATUS		0xC0 +#define USB_INT_STATUS		0xC4 +#define USB_INT_ENABLE		0xC8 + +#define USB_DWC_CTRL1_OTGD	0x04 /* set to DISable OTG */ +#define USB_DWC_CTRL1_HSTRS	0x02 /* set to ENable EHCI */ +#define USB_DWC_CTRL1_DCRS	0x01 /* set to ENable UDC */ + +#define USB_DWC_CTRL2_PHY1RS	0x04 /* set to enable PHY1 */ +#define USB_DWC_CTRL2_PHY0RS	0x02 /* set to enable PHY0 */ +#define USB_DWC_CTRL2_PHYRS	0x01 /* set to enable PHY */ + +#define USB_DWC_CTRL3_OHCI1_CKEN	(1 << 19) +#define USB_DWC_CTRL3_OHCI0_CKEN	(1 << 18) +#define USB_DWC_CTRL3_EHCI0_CKEN	(1 << 17) +#define USB_DWC_CTRL3_OTG0_CKEN		(1 << 16) + +#define USB_SBUS_CTRL_SBCA		0x04 /* coherent access */ + +#define USB_INTEN_FORCE			0x20 +#define USB_INTEN_PHY			0x10 +#define USB_INTEN_UDC			0x08 +#define USB_INTEN_EHCI			0x04 +#define USB_INTEN_OHCI1			0x02 +#define USB_INTEN_OHCI0			0x01 + +static DEFINE_SPINLOCK(alchemy_usb_lock); + +static inline void __au1300_usb_phyctl(void __iomem *base, int enable) +{ +	unsigned long r, s; + +	r = __raw_readl(base + USB_DWC_CTRL2); +	s = __raw_readl(base + USB_DWC_CTRL3); + +	s &= USB_DWC_CTRL3_OHCI1_CKEN | USB_DWC_CTRL3_OHCI0_CKEN | +		USB_DWC_CTRL3_EHCI0_CKEN | USB_DWC_CTRL3_OTG0_CKEN; + +	if (enable) { +		/* simply enable all PHYs */ +		r |= USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | +		     USB_DWC_CTRL2_PHYRS; +		__raw_writel(r, base + USB_DWC_CTRL2); +		wmb(); +	} else if (!s) { +		/* no USB block active, do disable all PHYs */ +		r &= ~(USB_DWC_CTRL2_PHY1RS | USB_DWC_CTRL2_PHY0RS | +		       USB_DWC_CTRL2_PHYRS); +		__raw_writel(r, base + USB_DWC_CTRL2); +		wmb(); +	} +} + +static inline void __au1300_ohci_control(void __iomem *base, int enable, int id) +{ +	unsigned long r; + +	if (enable) { +		__raw_writel(1, base + USB_DWC_CTRL7);	/* start OHCI clock */ +		wmb(); + +		r = __raw_readl(base + USB_DWC_CTRL3);	/* enable OHCI block */ +		r |= (id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN +			       : USB_DWC_CTRL3_OHCI1_CKEN; +		__raw_writel(r, base + USB_DWC_CTRL3); +		wmb(); + +		__au1300_usb_phyctl(base, enable);	/* power up the PHYs */ + +		r = __raw_readl(base + USB_INT_ENABLE); +		r |= (id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1; +		__raw_writel(r, base + USB_INT_ENABLE); +		wmb(); + +		/* reset the OHCI start clock bit */ +		__raw_writel(0, base + USB_DWC_CTRL7); +		wmb(); +	} else { +		r = __raw_readl(base + USB_INT_ENABLE); +		r &= ~((id == 0) ? USB_INTEN_OHCI0 : USB_INTEN_OHCI1); +		__raw_writel(r, base + USB_INT_ENABLE); +		wmb(); + +		r = __raw_readl(base + USB_DWC_CTRL3); +		r &= ~((id == 0) ? USB_DWC_CTRL3_OHCI0_CKEN +				 : USB_DWC_CTRL3_OHCI1_CKEN); +		__raw_writel(r, base + USB_DWC_CTRL3); +		wmb(); + +		__au1300_usb_phyctl(base, enable); +	} +} + +static inline void __au1300_ehci_control(void __iomem *base, int enable) +{ +	unsigned long r; + +	if (enable) { +		r = __raw_readl(base + USB_DWC_CTRL3); +		r |= USB_DWC_CTRL3_EHCI0_CKEN; +		__raw_writel(r, base + USB_DWC_CTRL3); +		wmb(); + +		r = __raw_readl(base + USB_DWC_CTRL1); +		r |= USB_DWC_CTRL1_HSTRS; +		__raw_writel(r, base + USB_DWC_CTRL1); +		wmb(); + +		__au1300_usb_phyctl(base, enable); + +		r = __raw_readl(base + USB_INT_ENABLE); +		r |= USB_INTEN_EHCI; +		__raw_writel(r, base + USB_INT_ENABLE); +		wmb(); +	} else { +		r = __raw_readl(base + USB_INT_ENABLE); +		r &= ~USB_INTEN_EHCI; +		__raw_writel(r, base + USB_INT_ENABLE); +		wmb(); + +		r = __raw_readl(base + USB_DWC_CTRL1); +		r &= ~USB_DWC_CTRL1_HSTRS; +		__raw_writel(r, base + USB_DWC_CTRL1); +		wmb(); + +		r = __raw_readl(base + USB_DWC_CTRL3); +		r &= ~USB_DWC_CTRL3_EHCI0_CKEN; +		__raw_writel(r, base + USB_DWC_CTRL3); +		wmb(); + +		__au1300_usb_phyctl(base, enable); +	} +} + +static inline void __au1300_udc_control(void __iomem *base, int enable) +{ +	unsigned long r; + +	if (enable) { +		r = __raw_readl(base + USB_DWC_CTRL1); +		r |= USB_DWC_CTRL1_DCRS; +		__raw_writel(r, base + USB_DWC_CTRL1); +		wmb(); + +		__au1300_usb_phyctl(base, enable); + +		r = __raw_readl(base + USB_INT_ENABLE); +		r |= USB_INTEN_UDC; +		__raw_writel(r, base + USB_INT_ENABLE); +		wmb(); +	} else { +		r = __raw_readl(base + USB_INT_ENABLE); +		r &= ~USB_INTEN_UDC; +		__raw_writel(r, base + USB_INT_ENABLE); +		wmb(); + +		r = __raw_readl(base + USB_DWC_CTRL1); +		r &= ~USB_DWC_CTRL1_DCRS; +		__raw_writel(r, base + USB_DWC_CTRL1); +		wmb(); + +		__au1300_usb_phyctl(base, enable); +	} +} + +static inline void __au1300_otg_control(void __iomem *base, int enable) +{ +	unsigned long r; +	if (enable) { +		r = __raw_readl(base + USB_DWC_CTRL3); +		r |= USB_DWC_CTRL3_OTG0_CKEN; +		__raw_writel(r, base + USB_DWC_CTRL3); +		wmb(); + +		r = __raw_readl(base + USB_DWC_CTRL1); +		r &= ~USB_DWC_CTRL1_OTGD; +		__raw_writel(r, base + USB_DWC_CTRL1); +		wmb(); + +		__au1300_usb_phyctl(base, enable); +	} else { +		r = __raw_readl(base + USB_DWC_CTRL1); +		r |= USB_DWC_CTRL1_OTGD; +		__raw_writel(r, base + USB_DWC_CTRL1); +		wmb(); + +		r = __raw_readl(base + USB_DWC_CTRL3); +		r &= ~USB_DWC_CTRL3_OTG0_CKEN; +		__raw_writel(r, base + USB_DWC_CTRL3); +		wmb(); + +		__au1300_usb_phyctl(base, enable); +	} +} + +static inline int au1300_usb_control(int block, int enable) +{ +	void __iomem *base = +		(void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); +	int ret = 0; + +	switch (block) { +	case ALCHEMY_USB_OHCI0: +		__au1300_ohci_control(base, enable, 0); +		break; +	case ALCHEMY_USB_OHCI1: +		__au1300_ohci_control(base, enable, 1); +		break; +	case ALCHEMY_USB_EHCI0: +		__au1300_ehci_control(base, enable); +		break; +	case ALCHEMY_USB_UDC0: +		__au1300_udc_control(base, enable); +		break; +	case ALCHEMY_USB_OTG0: +		__au1300_otg_control(base, enable); +		break; +	default: +		ret = -ENODEV; +	} +	return ret; +} + +static inline void au1300_usb_init(void) +{ +	void __iomem *base = +		(void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); + +	/* set some sane defaults.  Note: we don't fiddle with DWC_CTRL4 +	 * here at all: Port 2 routing (EHCI or UDC) must be set either +	 * by boot firmware or platform init code; I can't autodetect +	 * a sane setting. +	 */ +	__raw_writel(0, base + USB_INT_ENABLE); /* disable all USB irqs */ +	wmb(); +	__raw_writel(0, base + USB_DWC_CTRL3); /* disable all clocks */ +	wmb(); +	__raw_writel(~0, base + USB_MSR_ERR); /* clear all errors */ +	wmb(); +	__raw_writel(~0, base + USB_INT_STATUS); /* clear int status */ +	wmb(); +	/* set coherent access bit */ +	__raw_writel(USB_SBUS_CTRL_SBCA, base + USB_SBUS_CTRL); +	wmb(); +} + +static inline void __au1200_ohci_control(void __iomem *base, int enable) +{ +	unsigned long r = __raw_readl(base + AU1200_USBCFG); +	if (enable) { +		__raw_writel(r | USBCFG_OCE, base + AU1200_USBCFG); +		wmb(); +		udelay(2000); +	} else { +		__raw_writel(r & ~USBCFG_OCE, base + AU1200_USBCFG); +		wmb(); +		udelay(1000); +	} +} + +static inline void __au1200_ehci_control(void __iomem *base, int enable) +{ +	unsigned long r = __raw_readl(base + AU1200_USBCFG); +	if (enable) { +		__raw_writel(r | USBCFG_ECE | USBCFG_PPE, base + AU1200_USBCFG); +		wmb(); +		udelay(1000); +	} else { +		if (!(r & USBCFG_UCE))		/* UDC also off? */ +			r &= ~USBCFG_PPE;	/* yes: disable HS PHY PLL */ +		__raw_writel(r & ~USBCFG_ECE, base + AU1200_USBCFG); +		wmb(); +		udelay(1000); +	} +} + +static inline void __au1200_udc_control(void __iomem *base, int enable) +{ +	unsigned long r = __raw_readl(base + AU1200_USBCFG); +	if (enable) { +		__raw_writel(r | USBCFG_UCE | USBCFG_PPE, base + AU1200_USBCFG); +		wmb(); +	} else { +		if (!(r & USBCFG_ECE))		/* EHCI also off? */ +			r &= ~USBCFG_PPE;	/* yes: disable HS PHY PLL */ +		__raw_writel(r & ~USBCFG_UCE, base + AU1200_USBCFG); +		wmb(); +	} +} + +static inline int au1200_usb_control(int block, int enable) +{ +	void __iomem *base = +			(void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); + +	switch (block) { +	case ALCHEMY_USB_OHCI0: +		__au1200_ohci_control(base, enable); +		break; +	case ALCHEMY_USB_UDC0: +		__au1200_udc_control(base, enable); +		break; +	case ALCHEMY_USB_EHCI0: +		__au1200_ehci_control(base, enable); +		break; +	default: +		return -ENODEV; +	} +	return 0; +} + + +/* initialize USB block(s) to a known working state */ +static inline void au1200_usb_init(void) +{ +	void __iomem *base = +			(void __iomem *)KSEG1ADDR(AU1200_USB_CTL_PHYS_ADDR); +	__raw_writel(USBCFG_INIT_AU1200, base + AU1200_USBCFG); +	wmb(); +	udelay(1000); +} + +static inline void au1000_usb_init(unsigned long rb, int reg) +{ +	void __iomem *base = (void __iomem *)KSEG1ADDR(rb + reg); +	unsigned long r = __raw_readl(base); + +#if defined(__BIG_ENDIAN) +	r |= USBHEN_BE; +#endif +	r |= USBHEN_C; + +	__raw_writel(r, base); +	wmb(); +	udelay(1000); +} + + +static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg) +{ +	void __iomem *base = (void __iomem *)KSEG1ADDR(rb); +	unsigned long r = __raw_readl(base + creg); + +	if (enable) { +		__raw_writel(r | USBHEN_CE, base + creg); +		wmb(); +		udelay(1000); +		__raw_writel(r | USBHEN_CE | USBHEN_E, base + creg); +		wmb(); +		udelay(1000); + +		/* wait for reset complete (read reg twice: au1500 erratum) */ +		while (__raw_readl(base + creg), +			!(__raw_readl(base + creg) & USBHEN_RD)) +			udelay(1000); +	} else { +		__raw_writel(r & ~(USBHEN_CE | USBHEN_E), base + creg); +		wmb(); +	} +} + +static inline int au1000_usb_control(int block, int enable, unsigned long rb, +				     int creg) +{ +	int ret = 0; + +	switch (block) { +	case ALCHEMY_USB_OHCI0: +		__au1xx0_ohci_control(enable, rb, creg); +		break; +	default: +		ret = -ENODEV; +	} +	return ret; +} + +/* + * alchemy_usb_control - control Alchemy on-chip USB blocks + * @block:	USB block to target + * @enable:	set 1 to enable a block, 0 to disable + */ +int alchemy_usb_control(int block, int enable) +{ +	unsigned long flags; +	int ret; + +	spin_lock_irqsave(&alchemy_usb_lock, flags); +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1000: +	case ALCHEMY_CPU_AU1500: +	case ALCHEMY_CPU_AU1100: +		ret = au1000_usb_control(block, enable, +				AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); +		break; +	case ALCHEMY_CPU_AU1550: +		ret = au1000_usb_control(block, enable, +				AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); +		break; +	case ALCHEMY_CPU_AU1200: +		ret = au1200_usb_control(block, enable); +		break; +	case ALCHEMY_CPU_AU1300: +		ret = au1300_usb_control(block, enable); +		break; +	default: +		ret = -ENODEV; +	} +	spin_unlock_irqrestore(&alchemy_usb_lock, flags); +	return ret; +} +EXPORT_SYMBOL_GPL(alchemy_usb_control); + + +static unsigned long alchemy_usb_pmdata[2]; + +static void au1000_usb_pm(unsigned long br, int creg, int susp) +{ +	void __iomem *base = (void __iomem *)KSEG1ADDR(br); + +	if (susp) { +		alchemy_usb_pmdata[0] = __raw_readl(base + creg); +		/* There appears to be some undocumented reset register.... */ +		__raw_writel(0, base + 0x04); +		wmb(); +		__raw_writel(0, base + creg); +		wmb(); +	} else { +		__raw_writel(alchemy_usb_pmdata[0], base + creg); +		wmb(); +	} +} + +static void au1200_usb_pm(int susp) +{ +	void __iomem *base = +			(void __iomem *)KSEG1ADDR(AU1200_USB_OTG_PHYS_ADDR); +	if (susp) { +		/* save OTG_CAP/MUX registers which indicate port routing */ +		/* FIXME: write an OTG driver to do that */ +		alchemy_usb_pmdata[0] = __raw_readl(base + 0x00); +		alchemy_usb_pmdata[1] = __raw_readl(base + 0x04); +	} else { +		/* restore access to all MMIO areas */ +		au1200_usb_init(); + +		/* restore OTG_CAP/MUX registers */ +		__raw_writel(alchemy_usb_pmdata[0], base + 0x00); +		__raw_writel(alchemy_usb_pmdata[1], base + 0x04); +		wmb(); +	} +} + +static void au1300_usb_pm(int susp) +{ +	void __iomem *base = +			(void __iomem *)KSEG1ADDR(AU1300_USB_CTL_PHYS_ADDR); +	/* remember Port2 routing */ +	if (susp) { +		alchemy_usb_pmdata[0] = __raw_readl(base + USB_DWC_CTRL4); +	} else { +		au1300_usb_init(); +		__raw_writel(alchemy_usb_pmdata[0], base + USB_DWC_CTRL4); +		wmb(); +	} +} + +static void alchemy_usb_pm(int susp) +{ +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1000: +	case ALCHEMY_CPU_AU1500: +	case ALCHEMY_CPU_AU1100: +		au1000_usb_pm(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG, susp); +		break; +	case ALCHEMY_CPU_AU1550: +		au1000_usb_pm(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG, susp); +		break; +	case ALCHEMY_CPU_AU1200: +		au1200_usb_pm(susp); +		break; +	case ALCHEMY_CPU_AU1300: +		au1300_usb_pm(susp); +		break; +	} +} + +static int alchemy_usb_suspend(void) +{ +	alchemy_usb_pm(1); +	return 0; +} + +static void alchemy_usb_resume(void) +{ +	alchemy_usb_pm(0); +} + +static struct syscore_ops alchemy_usb_pm_ops = { +	.suspend	= alchemy_usb_suspend, +	.resume		= alchemy_usb_resume, +}; + +static int __init alchemy_usb_init(void) +{ +	switch (alchemy_get_cputype()) { +	case ALCHEMY_CPU_AU1000: +	case ALCHEMY_CPU_AU1500: +	case ALCHEMY_CPU_AU1100: +		au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); +		break; +	case ALCHEMY_CPU_AU1550: +		au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); +		break; +	case ALCHEMY_CPU_AU1200: +		au1200_usb_init(); +		break; +	case ALCHEMY_CPU_AU1300: +		au1300_usb_init(); +		break; +	} + +	register_syscore_ops(&alchemy_usb_pm_ops); + +	return 0; +} +arch_initcall(alchemy_usb_init); diff --git a/arch/mips/alchemy/common/vss.c b/arch/mips/alchemy/common/vss.c new file mode 100644 index 00000000000..d23b1444d36 --- /dev/null +++ b/arch/mips/alchemy/common/vss.c @@ -0,0 +1,84 @@ +/* + * Au1300 media block power gating (VSS) + * + * This is a stop-gap solution until I have the clock framework integration + * ready. This stuff here really must be handled transparently when clocks + * for various media blocks are enabled/disabled. + */ + +#include <linux/module.h> +#include <linux/spinlock.h> +#include <asm/mach-au1x00/au1000.h> + +#define VSS_GATE	0x00	/* gate wait timers */ +#define VSS_CLKRST	0x04	/* clock/block control */ +#define VSS_FTR		0x08	/* footers */ + +#define VSS_ADDR(blk)	(KSEG1ADDR(AU1300_VSS_PHYS_ADDR) + (blk * 0x0c)) + +static DEFINE_SPINLOCK(au1300_vss_lock); + +/* enable a block as outlined in the databook */ +static inline void __enable_block(int block) +{ +	void __iomem *base = (void __iomem *)VSS_ADDR(block); + +	__raw_writel(3, base + VSS_CLKRST);	/* enable clock, assert reset */ +	wmb(); + +	__raw_writel(0x01fffffe, base + VSS_GATE); /* maximum setup time */ +	wmb(); + +	/* enable footers in sequence */ +	__raw_writel(0x01, base + VSS_FTR); +	wmb(); +	__raw_writel(0x03, base + VSS_FTR); +	wmb(); +	__raw_writel(0x07, base + VSS_FTR); +	wmb(); +	__raw_writel(0x0f, base + VSS_FTR); +	wmb(); + +	__raw_writel(0x01ffffff, base + VSS_GATE); /* start FSM too */ +	wmb(); + +	__raw_writel(2, base + VSS_CLKRST);	/* deassert reset */ +	wmb(); + +	__raw_writel(0x1f, base + VSS_FTR);	/* enable isolation cells */ +	wmb(); +} + +/* disable a block as outlined in the databook */ +static inline void __disable_block(int block) +{ +	void __iomem *base = (void __iomem *)VSS_ADDR(block); + +	__raw_writel(0x0f, base + VSS_FTR);	/* disable isolation cells */ +	wmb(); +	__raw_writel(0, base + VSS_GATE);	/* disable FSM */ +	wmb(); +	__raw_writel(3, base + VSS_CLKRST);	/* assert reset */ +	wmb(); +	__raw_writel(1, base + VSS_CLKRST);	/* disable clock */ +	wmb(); +	__raw_writel(0, base + VSS_FTR);	/* disable all footers */ +	wmb(); +} + +void au1300_vss_block_control(int block, int enable) +{ +	unsigned long flags; + +	if (alchemy_get_cputype() != ALCHEMY_CPU_AU1300) +		return; + +	/* only one block at a time */ +	spin_lock_irqsave(&au1300_vss_lock, flags); +	if (enable) +		__enable_block(block); +	else +		__disable_block(block); +	spin_unlock_irqrestore(&au1300_vss_lock, flags); +} +EXPORT_SYMBOL_GPL(au1300_vss_block_control);  | 
