aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/alchemy/common
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/alchemy/common')
-rw-r--r--arch/mips/alchemy/common/Makefile4
-rw-r--r--arch/mips/alchemy/common/dbdma.c63
-rw-r--r--arch/mips/alchemy/common/gpiolib.c56
-rw-r--r--arch/mips/alchemy/common/irq.c875
-rw-r--r--arch/mips/alchemy/common/platform.c99
-rw-r--r--arch/mips/alchemy/common/power.c4
-rw-r--r--arch/mips/alchemy/common/setup.c18
-rw-r--r--arch/mips/alchemy/common/sleeper.S97
-rw-r--r--arch/mips/alchemy/common/time.c33
-rw-r--r--arch/mips/alchemy/common/usb.c593
-rw-r--r--arch/mips/alchemy/common/vss.c84
11 files changed, 1597 insertions, 329 deletions
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index 811ece7b22e..cb83d8d21ae 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -6,9 +6,7 @@
#
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),)
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index 0e63ee487d6..19d5642c16d 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -148,6 +148,50 @@ static dbdev_tab_t au1200_dbdev_tab[] __initdata = {
{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 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 },
+
+ { 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 },
+
+ { 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 },
+
+ { 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 },
+
+ { 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 },
+
+ { 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 },
+
+ { AU1300_DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+ { AU1300_DSCR_CMD0_UDMA, DEV_FLAGS_ANYUSE, 0, 32, 0x14001810, 0, 0 },
+
+ { 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 },
+};
+
/* 32 predefined plus 32 custom */
#define DBDEV_TAB_SIZE 64
@@ -208,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;
@@ -468,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);
@@ -591,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. */
@@ -653,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. */
@@ -698,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. */
@@ -847,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);
@@ -925,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. */
@@ -1019,8 +1063,7 @@ static int __init dbdma_setup(unsigned int irq, dbdev_tab_t *idtable)
dbdma_gptr->ddma_inten = 0xffff;
au_sync();
- ret = request_irq(irq, dbdma_interrupt, IRQF_DISABLED, "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 {
@@ -1038,6 +1081,8 @@ static int __init alchemy_dbdma_init(void)
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;
}
diff --git a/arch/mips/alchemy/common/gpiolib.c b/arch/mips/alchemy/common/gpiolib.c
index 91fb4d9e30f..f9bc4f52044 100644
--- a/arch/mips/alchemy/common/gpiolib.c
+++ b/arch/mips/alchemy/common/gpiolib.c
@@ -27,6 +27,7 @@
* 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>
@@ -35,6 +36,7 @@
#include <linux/types.h>
#include <linux/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,17 +106,54 @@ 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 alchemy_gpic_get(struct gpio_chip *chip, unsigned int off)
+{
+ 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);
+}
+
+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;
@@ -127,6 +166,9 @@ static int __init alchemy_gpiochip_init(void)
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;
}
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index 8b60ba0675e..63a71817a00 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -25,19 +25,15 @@
* 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/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
@@ -69,7 +65,17 @@
#define IC_FALLINGCLR 0x7C
#define IC_TESTBIT 0x80
-static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type);
+/* 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);
+
/* NOTE on interrupt priorities: The original writers of this code said:
*
@@ -77,176 +83,207 @@ static int au1x_ic_settype(struct irq_data *d, 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(struct irq_data *d)
{
@@ -265,14 +302,6 @@ static void au1x_ic1_unmask(struct irq_data *d)
__raw_writel(1 << bit, base + IC_MASKSET);
__raw_writel(1 << bit, base + IC_WAKESET);
-
-/* 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 (d->irq == AU1000_GPIO15_INT)
- __raw_writel(0x4000, (void __iomem *)PB1000_MDR); /* enable int */
-#endif
wmb();
}
@@ -470,40 +499,219 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type)
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)
+{
+ 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)
{
- 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 = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ0INT;
- off = AU1000_INTC0_INT_BASE;
- } else if (pending & CAUSEF_IP3) {
- s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ1INT;
- off = AU1000_INTC0_INT_BASE;
- } else if (pending & CAUSEF_IP4) {
- s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ0INT;
- off = AU1000_INTC1_INT_BASE;
- } else if (pending & CAUSEF_IP5) {
- s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ1INT;
- off = AU1000_INTC1_INT_BASE;
- } else
- goto spurious;
-
- s = __raw_readl((void __iomem *)s);
- if (unlikely(!s)) {
-spurious:
- spurious_interrupt();
- return;
+ 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 inline void gpic_pin_set_idlewake(unsigned int gpio, int allow)
+{
+ au1300_gpic_chgcfg(gpio, GPIC_CFG_IDLEWAKE,
+ allow ? GPIC_CFG_IDLEWAKE : 0);
+}
+
+static void au1300_gpic_mask(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_IDIS);
+ wmb();
+
+ gpic_pin_set_idlewake(irq, 0);
+}
+
+static void au1300_gpic_unmask(struct irq_data *d)
+{
+ void __iomem *r = AU1300_GPIC_ADDR;
+ unsigned long bit, irq = d->irq;
+
+ irq -= ALCHEMY_GPIC_INT_BASE;
+
+ gpic_pin_set_idlewake(irq, 1);
+
+ r += GPIC_GPIO_BANKOFF(irq);
+ bit = GPIC_GPIO_TO_BIT(irq);
+ __raw_writel(bit, r + AU1300_GPIC_IEN);
+ wmb();
+}
+
+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);
+}
+
+static void au1300_gpic_ack(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 */
+ 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 IRQ_TYPE_LEVEL_LOW:
+ s = GPIC_CFG_IC_LEVEL_LOW;
+ name = "low";
+ hdl = handle_level_irq;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ s = GPIC_CFG_IC_EDGE_RISE;
+ name = "posedge";
+ hdl = handle_edge_irq;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ s = GPIC_CFG_IC_EDGE_FALL;
+ name = "negedge";
+ hdl = handle_edge_irq;
+ break;
+ 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;
+}
+
+/******************************************************************************/
static inline void ic_init(void __iomem *base)
{
@@ -521,13 +729,159 @@ static inline void ic_init(void __iomem *base)
wmb();
}
-static void __init au1000_init_irq(struct au1xxx_irqmap *map)
+static unsigned long alchemy_gpic_pmdata[ALCHEMY_GPIC_INT_NUM + 6];
+
+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 inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d)
+{
+ 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(d[6], base + IC_MASKSET);
+ wmb();
+}
+
+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();
+
+ /* 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 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 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)
+{
+ int i = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_PRIENC);
+ generic_handle_irq(ALCHEMY_GPIC_INT_BASE + i);
+}
+
+/******************************************************************************/
+
+static void __init au1000_init_irq(struct alchemy_irqmap *map)
{
unsigned int bit, irq_nr;
void __iomem *base;
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();
/* register all 64 possible IC0+IC1 irq sources as type "none".
@@ -544,8 +898,8 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map)
/*
* Initialize IC0, which is fixed per processor.
*/
- while (map->im_irq != -1) {
- irq_nr = map->im_irq;
+ while (map->irq != -1) {
+ irq_nr = map->irq;
if (irq_nr >= AU1000_INTC1_INT_BASE) {
bit = irq_nr - AU1000_INTC1_INT_BASE;
@@ -554,16 +908,61 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map)
bit = irq_nr - AU1000_INTC0_INT_BASE;
base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
}
- if (map->im_request)
+ if (map->prio == 0)
__raw_writel(1 << bit, base + IC_ASSIGNSET);
- au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type);
+ au1x_ic_settype(irq_get_irq_data(irq_nr), map->type);
++map;
}
- set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
+ 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()) {
@@ -582,65 +981,17 @@ void __init arch_init_irq(void)
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;
}
}
-
-static unsigned long alchemy_ic_pmdata[7 * 2];
-
-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 inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d)
-{
- 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(d[6], base + IC_MASKSET);
- wmb();
-}
-
-static int alchemy_ic_suspend(void)
-{
- alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
- alchemy_ic_pmdata);
- alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
- &alchemy_ic_pmdata[7]);
- return 0;
-}
-
-static void alchemy_ic_resume(void)
-{
- alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
- &alchemy_ic_pmdata[7]);
- alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
- alchemy_ic_pmdata);
-}
-
-static struct syscore_ops alchemy_ic_syscore_ops = {
- .suspend = alchemy_ic_suspend,
- .resume = alchemy_ic_resume,
-};
-
-static int __init alchemy_ic_pm_init(void)
+asmlinkage void plat_irq_dispatch(void)
{
- register_syscore_ops(&alchemy_ic_syscore_ops);
- return 0;
+ unsigned long r = (read_c0_status() & read_c0_cause()) >> 8;
+ do_IRQ(MIPS_CPU_IRQ_BASE + __ffs(r & 0xff));
}
-device_initcall(alchemy_ic_pm_init);
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index c8e5d72a582..9837a134a6d 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -17,6 +17,8 @@
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/slab.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
@@ -51,7 +53,7 @@ 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, \
@@ -82,6 +84,12 @@ static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = {
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 = {
@@ -116,16 +124,65 @@ static void __init alchemy_setup_uarts(int ctype)
static u64 alchemy_ohci_dmamask = DMA_BIT_MASK(32);
static u64 __maybe_unused alchemy_ehci_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);
+}
+
+/* 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);
+}
+
+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,
+};
+
+/* Power on callback for the ohci platform driver */
+static int alchemy_ohci_power_on(struct platform_device *pdev)
+{
+ int unit;
+
+ unit = (pdev->id == 1) ?
+ ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
+
+ return alchemy_usb_control(unit, 1);
+}
+
+/* Power off/suspend callback for the ohci platform driver */
+static void alchemy_ohci_power_off(struct platform_device *pdev)
+{
+ int unit;
+
+ unit = (pdev->id == 1) ?
+ ALCHEMY_USB_OHCI1 : ALCHEMY_USB_OHCI0;
+
+ 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 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 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 int __init _new_usbres(struct resource **r, struct platform_device **d)
@@ -161,16 +218,17 @@ static void __init alchemy_setup_usb(int ctype)
res[1].start = alchemy_ohci_data[ctype][1];
res[1].end = res[1].start;
res[1].flags = IORESOURCE_IRQ;
- pdev->name = "au1xxx-ohci";
+ 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 */
- if (ctype == ALCHEMY_CPU_AU1200) {
+ /* setup EHCI0: Au1200/Au1300 */
+ if ((ctype == ALCHEMY_CPU_AU1200) || (ctype == ALCHEMY_CPU_AU1300)) {
if (_new_usbres(&res, &pdev))
return;
@@ -180,13 +238,34 @@ static void __init alchemy_setup_usb(int ctype)
res[1].start = alchemy_ehci_data[ctype][1];
res[1].end = res[1].start;
res[1].flags = IORESOURCE_IRQ;
- pdev->name = "au1xxx-ehci";
+ 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");
}
+
+ /* 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");
+ }
}
/* Macro to help defining the Ethernet MAC resources */
@@ -307,13 +386,12 @@ static void __init alchemy_setup_macs(int ctype)
if (alchemy_get_macs(ctype) < 1)
return;
- macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+ 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;
}
- memcpy(macres, au1xxx_eth0_resources[ctype],
- sizeof(struct resource) * MAC_RES_COUNT);
au1xxx_eth0_device.resource = macres;
i = prom_get_ethernet_addr(ethaddr);
@@ -329,13 +407,12 @@ static void __init alchemy_setup_macs(int ctype)
if (alchemy_get_macs(ctype) < 2)
return;
- macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+ 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;
}
- memcpy(macres, au1xxx_eth1_resources[ctype],
- sizeof(struct resource) * MAC_RES_COUNT);
au1xxx_eth1_device.resource = macres;
ethaddr[5] += 1; /* next addr for 2nd MAC */
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index bdd6651e9a4..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>
@@ -126,6 +125,9 @@ void au_sleep(void)
case ALCHEMY_CPU_AU1200:
alchemy_sleep_au1550();
break;
+ case ALCHEMY_CPU_AU1300:
+ alchemy_sleep_au1300();
+ break;
}
restore_core_regs();
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c
index 37ffd997c61..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>
@@ -59,7 +60,22 @@ void __init plat_mem_setup(void)
/* Clear to obtain best system bus performance */
clear_c0_config(1 << 19); /* Clear Config[OD] */
- board_setup(); /* board specific setup */
+ 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);
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 d5da6adbf63..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,
};
@@ -146,7 +147,7 @@ static int __init alchemy_time_init(unsigned int m2int)
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);
@@ -158,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)
@@ -185,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);