[PATCH] MIPS: Alchemy: basic Au1300 SoC support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add support for the Au1300 SoC: 
- CPU core detection
- New GPIO/Interrupt controller code,
- enable DBDMA, video and PSCs for new subtype.

Signed-off-by: Manuel Lauss <manuel.lauss@xxxxxxxxx>
---
I'm submitting this in the hopes of some feedback.  The code here
adds just interrupt controller support which should be enough to
get a new board started.

I'm still working on DB1300 support; unfortunately the FPGA's
irq multiplexer is extremely problematic: it generates mostly
spurious interrupts or refuses to generate any more when poked
the wrong way.

I've tried to contact Kevin Hickey and other people
inside RMI for assistance but got no response in the last 3 months.

Please have a look,

Thanks!
     Manuel Lauss

 arch/mips/alchemy/Kconfig                        |    9 +
 arch/mips/alchemy/common/Makefile                |    2 +
 arch/mips/alchemy/common/dbdma.c                 |   48 ++-
 arch/mips/alchemy/common/gpioint.c               |  462 ++++++++++++++++++++++
 arch/mips/alchemy/common/gpiolib-au1300.c        |   54 +++
 arch/mips/alchemy/common/platform.c              |    9 +
 arch/mips/alchemy/common/power.c                 |    9 +-
 arch/mips/alchemy/common/time.c                  |    1 +
 arch/mips/include/asm/cpu.h                      |    8 +
 arch/mips/include/asm/mach-au1x00/au1000.h       |  197 +++++++++-
 arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h |   33 ++
 arch/mips/include/asm/mach-au1x00/gpio-au1300.h  |  215 ++++++++++
 arch/mips/include/asm/mach-au1x00/gpio.h         |    4 +
 arch/mips/kernel/cpu-probe.c                     |   18 +
 drivers/i2c/busses/Kconfig                       |    2 +-
 drivers/spi/Kconfig                              |    2 +-
 drivers/video/Kconfig                            |   17 +-
 17 files changed, 1071 insertions(+), 19 deletions(-)
 create mode 100644 arch/mips/alchemy/common/gpioint.c
 create mode 100644 arch/mips/alchemy/common/gpiolib-au1300.c
 create mode 100644 arch/mips/include/asm/mach-au1x00/gpio-au1300.h

diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig
index df3b1a7..0789c55 100644
--- a/arch/mips/alchemy/Kconfig
+++ b/arch/mips/alchemy/Kconfig
@@ -2,6 +2,10 @@
 config ALCHEMY_GPIOINT_AU1000
 	bool
 
+# au1300-style GPIO/INT controller
+config ALCHEMY_GPIOINT_AU1300
+	bool
+
 # select this in your board config if you don't want to use the gpio
 # namespace as documented in the manuals.  In this case however you need
 # to create the necessary gpio_* functions in your board code/headers!
@@ -155,6 +159,11 @@ config SOC_AU1200
 	select SOC_AU1X00
 	select ALCHEMY_GPIOINT_AU1000
 
+config SOC_AU1300
+	bool
+	select SOC_AU1X00
+	select ALCHEMY_GPIOINT_AU1300
+
 config SOC_AU1X00
 	bool
 	select 64BIT_PHYS_ADDR
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index 06c0e65..b3b7c92 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -9,11 +9,13 @@ 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
+obj-$(CONFIG_ALCHEMY_GPIOINT_AU1300) += gpioint.o
 
 # optional gpiolib support
 ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),)
  ifeq ($(CONFIG_GPIOLIB),y)
   obj-$(CONFIG_ALCHEMY_GPIOINT_AU1000) += gpiolib-au1000.o
+  obj-$(CONFIG_ALCHEMY_GPIOINT_AU1300) += gpiolib-au1300.o
  endif
 endif
 
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index ca0506a..aedb7e5 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -40,8 +40,6 @@
 #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.
  *
@@ -151,6 +149,47 @@ static dbdev_tab_t dbdev_tab[] = {
 
 #endif /* CONFIG_SOC_AU1200 */
 
+#ifdef CONFIG_SOC_AU1300
+	{ DSCR_CMD0_UART0_TX, DEV_FLAGS_OUT, 0, 8,  0x10100004, 0, 0 },
+	{ DSCR_CMD0_UART0_RX, DEV_FLAGS_IN,  0, 8,  0x10100000, 0, 0 },
+	{ DSCR_CMD0_UART1_TX, DEV_FLAGS_OUT, 0, 8,  0x10101004, 0, 0 },
+	{ DSCR_CMD0_UART1_RX, DEV_FLAGS_IN,  0, 8,  0x10101000, 0, 0 },
+	{ DSCR_CMD0_UART2_TX, DEV_FLAGS_OUT, 0, 8,  0x10102004, 0, 0 },
+	{ DSCR_CMD0_UART2_RX, DEV_FLAGS_IN,  0, 8,  0x10102000, 0, 0 },
+	{ DSCR_CMD0_UART3_TX, DEV_FLAGS_OUT, 0, 8,  0x10103004, 0, 0 },
+	{ DSCR_CMD0_UART3_RX, DEV_FLAGS_IN,  0, 8,  0x10103000, 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, 8, 8,  0x10601000, 0, 0 },
+	{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN,  8, 8,  0x10601004, 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 },
+
+	{ DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0001c, 0, 0 },
+	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN,   0, 16, 0x10a0001c, 0, 0 },
+	{ DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0101c, 0, 0 },
+	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN,   0, 16, 0x10a0101c, 0, 0 },
+	{ DSCR_CMD0_PSC2_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0201c, 0, 0 },
+	{ DSCR_CMD0_PSC2_RX, DEV_FLAGS_IN,   0, 16, 0x10a0201c, 0, 0 },
+	{ DSCR_CMD0_PSC3_TX, DEV_FLAGS_OUT,  0, 16, 0x10a0301c, 0, 0 },
+	{ DSCR_CMD0_PSC3_RX, DEV_FLAGS_IN,   0, 16, 0x10a0301c, 0, 0 },
+
+	{ DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE,   0, 0,  0x00000000, 0, 0 },
+	{ DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+
+	{ DSCR_CMD0_SDMS_TX2, DEV_FLAGS_OUT, 4, 8,  0x10602000, 0, 0 },
+	{ DSCR_CMD0_SDMS_RX2, DEV_FLAGS_IN,  4, 8,  0x10602004, 0, 0 },
+
+	{ DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+	{ DSCR_CMD0_UDMA, DEV_FLAGS_ANYUSE,  0, 32, 0x14001810, 0, 0 },
+
+	{ DSCR_CMD0_DMA_REQ0, 0, 0, 0, 0x00000000, 0, 0 },
+	{ DSCR_CMD0_DMA_REQ1, 0, 0, 0, 0x00000000, 0, 0 },
+#endif /* CONFIG_SOC_AU1300 */
+
 	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 	{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 
@@ -1073,6 +1112,9 @@ static int __init au1xxx_dbdma_init(void)
 	case ALCHEMY_CPU_AU1200:
 		irq_nr = AU1200_DDMA_INT;
 		break;
+	case ALCHEMY_CPU_AU1300:
+		irq_nr = AU1300_DDMA_INT;
+		break;
 	default:
 		return -ENODEV;
 	}
@@ -1094,5 +1136,3 @@ static int __init au1xxx_dbdma_init(void)
 	return ret;
 }
 subsys_initcall(au1xxx_dbdma_init);
-
-#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
diff --git a/arch/mips/alchemy/common/gpioint.c b/arch/mips/alchemy/common/gpioint.c
new file mode 100644
index 0000000..873b5d7
--- /dev/null
+++ b/arch/mips/alchemy/common/gpioint.c
@@ -0,0 +1,462 @@
+/*
+ * gpioint.c - Au1300 GPIO+Interrupt controller support.
+ *
+ * Copyright (c) 2009-2010 Manuel Lauss <manuel.lauss@xxxxxxxxx>
+ *
+ * licensed under the GPLv2.
+ */
+
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sysdev.h>
+#include <linux/types.h>
+
+#include <asm/irq_cpu.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/gpio-au1300.h>
+
+#if 0
+#define DBG(x...)	printk(KERN_INFO "GPIC " x)
+#else
+#define DBG(x...)
+#endif
+
+static int au1300_gpic_settype(unsigned int irq, unsigned int type);
+
+/* setup for known onchip sources */
+struct gpic_devint_data {
+	int irq;	/* linux IRQ number */
+	int type;	/* IRQ_TYPE_ */
+	int prio;	/* irq priority, 0 highest, 3 lowest */
+	int internal;	/* internal-only source (no ext. pin)? */
+};
+
+struct gpic_devint_data au1300_devints[] __initdata = {
+	/* multifunction: gpio/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-only ints */
+	{ 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 */
+};
+
+struct alchemy_gpic_sysdev {
+	struct sys_device sysdev;
+	void __iomem *base;
+	unsigned long icr[6];
+	unsigned long pincfg[128];
+};
+
+
+/*
+ * au1300_gpic_modcfg - 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.
+ * NOTE: according to the datasheet, this should only be called
+ * for disabled interrupts!
+ */
+static inline void au1300_gpic_modcfg(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();
+
+	DBG("MODCFG(%03d) %08lx %08lx -> %08lx\n", gpio, clr, set, l);
+}
+
+/*
+ * 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);
+
+	DBG("PIN2GPIN(%03d)\n", (int)gpio);
+}
+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();
+
+	DBG("PIN2DEV(%03d)\n", (int)gpio);
+}
+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_modcfg(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();
+	}
+}
+
+/**********************************************************************/
+
+static void gpic_pin_set_idlewake(int gpio, int allow)
+{
+	au1300_gpic_modcfg(gpio, GPIC_CFG_IDLEWAKE,
+			   allow ? GPIC_CFG_IDLEWAKE : 0);
+
+	DBG("SETIDLEWAKE(%03d) %d\n", gpio, allow);
+}
+
+static void au1300_gpic_mask(unsigned int irq)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	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(unsigned int irq)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	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(unsigned int irq)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	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(unsigned int irq)
+{
+	void __iomem *r = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	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		= "Au1300-GPIOINT",
+	.ack		= au1300_gpic_ack,
+	.mask		= au1300_gpic_mask,
+	.mask_ack	= au1300_gpic_maskack,
+	.unmask		= au1300_gpic_unmask,
+	.set_type	= au1300_gpic_settype,
+};
+
+#define SICHN(i, h, n)		\
+	set_irq_chip_and_handler_name(i, &au1300_gpic, h, n)
+
+static int au1300_gpic_settype(unsigned int irq, unsigned int type)
+{
+	unsigned long s;
+
+	switch (type) {
+	case IRQ_TYPE_LEVEL_HIGH:
+		s = GPIC_CFG_IC_LEVEL_HIGH;
+		SICHN(irq, handle_level_irq, "highlevel");
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		s = GPIC_CFG_IC_LEVEL_LOW;
+		SICHN(irq, handle_level_irq, "lowlevel");
+		break;
+	case IRQ_TYPE_EDGE_RISING:
+		s = GPIC_CFG_IC_EDGE_RISE;
+		SICHN(irq, handle_edge_irq, "riseedge");
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		s = GPIC_CFG_IC_EDGE_FALL;
+		SICHN(irq, handle_edge_irq, "falledge");
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		s = GPIC_CFG_IC_EDGE_BOTH;
+		SICHN(irq, handle_edge_irq, "bothedge");
+		break;
+	case IRQ_TYPE_NONE:
+		s = GPIC_CFG_IC_OFF;
+		SICHN(irq, handle_level_irq, "disabled");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	au1300_gpic_modcfg(irq - ALCHEMY_GPIC_INT_BASE,
+			   GPIC_CFG_IC_MASK, s);
+
+	return 0;
+}
+
+static void __init alchemy_gpic_init_irq(struct gpic_devint_data *dints)
+{
+	int i;
+	void __iomem *bank_base;
+
+	mips_cpu_irq_init();
+
+	/* disable & ack all possible on-chip 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 all possible irq sources, with 2nd highest priority */
+	bank_base = AU1300_GPIC_ADDR + AU1300_GPIC_PINCFG;
+	for (i = ALCHEMY_GPIC_INT_BASE; i <= ALCHEMY_GPIC_INT_LAST; i++) {
+		au1300_set_irq_priority(i, 1);
+		au1300_gpic_settype(i, IRQ_TYPE_NONE);
+	}
+
+	/* setup known on-chip sources */
+	while ((i = dints->irq) != -1) {
+		au1300_gpic_settype(i, dints->type);
+		au1300_set_irq_priority(i, dints->prio);
+
+		if (dints->internal)
+			au1300_pinfunc_to_dev(i - ALCHEMY_GPIC_INT_BASE);
+
+		dints++;
+	}
+
+	set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
+}
+
+static int alchemy_gpic_suspend(struct sys_device *dev, pm_message_t state)
+{
+	struct alchemy_gpic_sysdev *icdev =
+		container_of(dev, struct alchemy_gpic_sysdev, sysdev);
+	void __iomem *addy;
+	int i;
+
+	/* save pin configuration */
+	addy = icdev->base + AU1300_GPIC_PINCFG;
+	for (i = 0; i < 128; i++)
+		icdev->pincfg[i] = __raw_readl(addy + (i << 2));
+
+	/* save interrupt mask status */
+	icdev->icr[0] = __raw_readl(icdev->base + AU1300_GPIC_IEN + 0x0);
+	icdev->icr[1] = __raw_readl(icdev->base + AU1300_GPIC_IEN + 0x4);
+	icdev->icr[2] = __raw_readl(icdev->base + AU1300_GPIC_IEN + 0x8);
+	icdev->icr[3] = __raw_readl(icdev->base + AU1300_GPIC_IEN + 0xc);
+
+	/* misc */
+	icdev->icr[4] = __raw_readl(icdev->base + AU1300_GPIC_DMASEL);
+	wmb();
+
+	return 0;
+}
+
+static int alchemy_gpic_resume(struct sys_device *dev)
+{
+	struct alchemy_gpic_sysdev *icdev =
+		container_of(dev, struct alchemy_gpic_sysdev, sysdev);
+	void __iomem *addy;
+	int i;
+
+	/* mask all off first */
+	__raw_writel(-1, icdev->base + AU1300_GPIC_IDIS + 0x0);
+	__raw_writel(-1, icdev->base + AU1300_GPIC_IDIS + 0x4);
+	__raw_writel(-1, icdev->base + AU1300_GPIC_IDIS + 0x8);
+	__raw_writel(-1, icdev->base + AU1300_GPIC_IDIS + 0xc);
+	wmb();
+
+	/* restore pin configurations */
+	addy = icdev->base + AU1300_GPIC_PINCFG;
+	for (i = 0; i < 128; i++)
+		__raw_writel(icdev->pincfg[i], addy + (i << 2));
+	wmb();
+
+	__raw_writel(icdev->icr[4], icdev->base + AU1300_GPIC_DMASEL);
+	wmb();
+
+	/* restore masks */
+	addy = icdev->base + AU1300_GPIC_IEN;
+	__raw_writel(icdev->icr[0], addy + 0x0);
+	wmb();
+	__raw_writel(icdev->icr[1], addy + 0x4);
+	wmb();
+	__raw_writel(icdev->icr[2], addy + 0x8);
+	wmb();
+	__raw_writel(icdev->icr[3], addy + 0xc);
+	wmb();
+
+	return 0;
+}
+
+static struct sysdev_class alchemy_gpic_sysdev_class = {
+	.name		= "gpic",
+	.suspend	= alchemy_gpic_suspend,
+	.resume		= alchemy_gpic_resume,
+};
+
+static int __init alchemy_gpic_sysdev_init(void)
+{
+	struct alchemy_gpic_sysdev *icdev;
+	int err;
+
+	err = sysdev_class_register(&alchemy_gpic_sysdev_class);
+	if (err)
+		return err;
+
+	icdev = kzalloc(sizeof(struct alchemy_gpic_sysdev), GFP_KERNEL);
+	if (!icdev)
+		return -ENOMEM;
+
+	icdev->base = (void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR);
+
+	icdev->sysdev.id = -1;
+	icdev->sysdev.cls = &alchemy_gpic_sysdev_class;
+	err = sysdev_register(&icdev->sysdev);
+	if (err)
+		kfree(icdev);
+
+	return err;
+}
+device_initcall(alchemy_gpic_sysdev_init);
+
+/**********************************************************************/
+
+void __init arch_init_irq(void)
+{
+	switch (alchemy_get_cputype()) {
+	case ALCHEMY_CPU_AU1300:
+		alchemy_gpic_init_irq(&au1300_devints[0]);
+		break;
+	default:
+		panic("Alchemy GPIC: unsupported CPU!\n");
+	}
+}
+
+void plat_irq_dispatch(void)
+{
+	unsigned long c = read_c0_cause(), s = read_c0_status();
+	int i;
+
+	DBG("M %08lx  S %08lx\n", c, s);
+	c &= s;
+
+	if (c & CAUSEF_IP7)		/* c0 timer */
+		i = MIPS_CPU_IRQ_BASE + 7 - ALCHEMY_GPIC_INT_BASE;
+	else if (c & (CAUSEF_IP2 | CAUSEF_IP3 | CAUSEF_IP4 | CAUSEF_IP5)) {
+		i = __raw_readl(AU1300_GPIC_ADDR + AU1300_GPIC_PRIENC);
+		DBG("I %d\n", i);
+		if (unlikely(i == 127))
+			goto spurious;
+	} else
+		goto spurious;
+
+	do_IRQ(i + ALCHEMY_GPIC_INT_BASE);
+	return;
+spurious:
+	spurious_interrupt();
+}
diff --git a/arch/mips/alchemy/common/gpiolib-au1300.c b/arch/mips/alchemy/common/gpiolib-au1300.c
new file mode 100644
index 0000000..661cc6f
--- /dev/null
+++ b/arch/mips/alchemy/common/gpiolib-au1300.c
@@ -0,0 +1,54 @@
+/*
+ * Au1300-style GPIO/INT Controller GPIOLIB support
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+
+#include <asm/mach-au1x00/gpio-au1300.h>
+
+static int _gpic_get(struct gpio_chip *chip, unsigned int off)
+{
+	return au1300_gpio_get_value(off + AU1300_GPIO_BASE);
+}
+
+static void _gpic_set(struct gpio_chip *chip, unsigned int off, int v)
+{
+	au1300_gpio_set_value(off + AU1300_GPIO_BASE, v);
+}
+
+static int _gpic_direction_input(struct gpio_chip *chip, unsigned int off)
+{
+	return au1300_gpio_direction_input(off + AU1300_GPIO_BASE);
+}
+
+static int _gpic_direction_output(struct gpio_chip *chip, unsigned int off,
+				   int v)
+{
+	return au1300_gpio_direction_output(off + AU1300_GPIO_BASE, v);
+}
+
+static int _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			= "au1300",
+	.direction_input	= _gpic_direction_input,
+	.direction_output	= _gpic_direction_output,
+	.get			= _gpic_get,
+	.set			= _gpic_set,
+	.to_irq			= _gpic_gpio_to_irq,
+	.base			= AU1300_GPIO_BASE,
+	.ngpio			= AU1300_GPIO_NUM,
+};
+
+static int __init au1300_gpiochip_init(void)
+{
+	return gpiochip_add(&au1300_gpiochip);
+}
+arch_initcall(au1300_gpiochip_init);
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 2580e77..6539ca3 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -53,6 +53,11 @@ static struct plat_serial8250_port au1x00_uart_data[] = {
 #elif defined(CONFIG_SOC_AU1200)
 	PORT(UART0_PHYS_ADDR, AU1200_UART0_INT),
 	PORT(UART1_PHYS_ADDR, AU1200_UART1_INT),
+#elif defined(CONFIG_SOC_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),
 #endif
 #endif	/* CONFIG_SERIAL_8250_AU1X00 */
 	{ },
@@ -66,6 +71,7 @@ static struct platform_device au1xx0_uart_device = {
 	},
 };
 
+#ifdef FOR_PLATFORM_C_USB_HOST_INT
 /* OHCI (USB full speed host controller) */
 static struct resource au1xxx_usb_ohci_resources[] = {
 	[0] = {
@@ -93,6 +99,7 @@ static struct platform_device au1xxx_usb_ohci_device = {
 	.num_resources	= ARRAY_SIZE(au1xxx_usb_ohci_resources),
 	.resource	= au1xxx_usb_ohci_resources,
 };
+#endif
 
 /*** AU1100 LCD controller ***/
 
@@ -412,7 +419,9 @@ void __init au1xxx_override_eth_cfg(unsigned int port,
 
 static struct platform_device *au1xxx_platform_devices[] __initdata = {
 	&au1xx0_uart_device,
+#ifdef FOR_PLATFORM_C_USB_HOST_INT
 	&au1xxx_usb_ohci_device,
+#endif
 #ifdef CONFIG_FB_AU1100
 	&au1100_lcd_device,
 #endif
diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c
index 5ef06a1..af249d1 100644
--- a/arch/mips/alchemy/common/power.c
+++ b/arch/mips/alchemy/common/power.c
@@ -54,7 +54,9 @@ static unsigned int sleep_uart0_fifoctl;
 static unsigned int sleep_uart0_linectl;
 static unsigned int sleep_uart0_clkdiv;
 static unsigned int sleep_uart0_enable;
+#ifndef CONFIG_SOC_AU1300
 static unsigned int sleep_usb[2];
+#endif
 static unsigned int sleep_sys_clocks[5];
 static unsigned int sleep_sys_pinfunc;
 static unsigned int sleep_static_memctlr[4][3];
@@ -79,7 +81,8 @@ static void save_core_regs(void)
 	au_sync();
 
 #ifndef CONFIG_SOC_AU1200
-	/* Shutdown USB host/device. */
+#ifndef CONFIG_SOC_AU1300	/* doesn't apply to Au1300 USB */
+/* Shutdown USB host/device. */
 	sleep_usb[0] = au_readl(USB_HOST_CONFIG);
 
 	/* There appears to be some undocumented reset register.... */
@@ -91,7 +94,7 @@ static void save_core_regs(void)
 	sleep_usb[1] = au_readl(USBD_ENABLE);
 	au_writel(0, USBD_ENABLE);
 	au_sync();
-
+#endif /* au1300 */
 #else	/* AU1200 */
 
 	/* enable access to OTG mmio so we can save OTG CAP/MUX.
@@ -147,9 +150,11 @@ static void restore_core_regs(void)
 	au_sync();
 
 #ifndef CONFIG_SOC_AU1200
+#ifndef CONFIG_SOC_AU1300	/* doesn't apply to Au1300 either */
 	au_writel(sleep_usb[0], USB_HOST_CONFIG);
 	au_writel(sleep_usb[1], USBD_ENABLE);
 	au_sync();
+#endif
 #else
 	/* enable accces to OTG memory */
 	au_writel(au_readl(USB_MSR_BASE + 4) | (1 << 6), USB_MSR_BASE + 4);
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index 2aecb2f..db82325 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -179,6 +179,7 @@ static int alchemy_m2inttab[] __initdata = {
 	AU1100_RTC_MATCH2_INT,
 	AU1550_RTC_MATCH2_INT,
 	AU1200_RTC_MATCH2_INT,
+	AU1300_RTC_MATCH2_INT,
 };
 
 void __init plat_time_init(void)
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index a5acda4..acb12f0 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -33,6 +33,7 @@
 #define PRID_COMP_TOSHIBA	0x070000
 #define PRID_COMP_LSI		0x080000
 #define PRID_COMP_LEXRA		0x0b0000
+#define PRID_COMP_RMI		0x0c0000
 #define PRID_COMP_CAVIUM	0x0d0000
 
 
@@ -121,6 +122,13 @@
 #define PRID_REV_BCM6368	0x0030
 
 /*
+ * These are the PRID's for when 23:16 == PRID_COMP_RMI
+ */
+
+#define PRID_IMP_AU13XX		0x8000
+
+
+/*
  * These are the PRID's for when 23:16 == PRID_COMP_CAVIUM
  */
 
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index a697661..f826db2 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -136,6 +136,7 @@ static inline int au1xxx_cpu_needs_config_od(void)
 #define ALCHEMY_CPU_AU1100	2
 #define ALCHEMY_CPU_AU1550	3
 #define ALCHEMY_CPU_AU1200	4
+#define ALCHEMY_CPU_AU1300	5
 
 static inline int alchemy_get_cputype(void)
 {
@@ -156,6 +157,9 @@ static inline int alchemy_get_cputype(void)
 	case 0x05030000:
 		return ALCHEMY_CPU_AU1200;
 		break;
+	case 0x800c0000:
+		return ALCHEMY_CPU_AU1300;
+		break;
 	}
 
 	return ALCHEMY_CPU_UNKNOWN;
@@ -180,6 +184,68 @@ static inline void alchemy_uart_putchar(u32 uart_phys, u8 c)
 	wmb();
 }
 
+/* Multifunction pins: Each of these pins can either be assigned to the
+ * GPIO controller or a on-chip peripheral.
+ * Call "au1300_pinfunc_to_dev()" or "au1300_pinfunc_to_gpio()" to
+ * assign one of these to either the GPIO controller or the device.
+ */
+enum au1300_multifunc_pins {
+	/* wake-from-str pins 0-3 */
+	AU1300_PIN_WAKE0 = 0, AU1300_PIN_WAKE1, AU1300_PIN_WAKE2,
+	AU1300_PIN_WAKE3,
+	/* external clock sources for PSCs: 4-5 */
+	AU1300_PIN_EXTCLK0, AU1300_PIN_EXTCLK1,
+	/* 8bit MMC interface on SD0: 6-9 */
+	AU1300_PIN_SD0DAT4, AU1300_PIN_SD0DAT5, AU1300_PIN_SD0DAT6,
+	AU1300_PIN_SD0DAT7,
+	/* aux clk input for freqgen 3: 10 */
+	AU1300_PIN_FG3AUX,
+	/* UART1 pins: 11-18 */
+	AU1300_PIN_U1RI, AU1300_PIN_U1DCD, AU1300_PIN_U1DSR,
+	AU1300_PIN_U1CTS, AU1300_PIN_U1RTS, AU1300_PIN_U1DTR,
+	AU1300_PIN_U1RX, AU1300_PIN_U1TX,
+	/* UART0 pins: 19-24 */
+	AU1300_PIN_U0RI, AU1300_PIN_U0DCD, AU1300_PIN_U0DSR,
+	AU1300_PIN_U0CTS, AU1300_PIN_U0RTS, AU1300_PIN_U0DTR,
+	/* UART2: 25-26 */
+	AU1300_PIN_U2RX, AU1300_PIN_U2TX,
+	/* UART3: 27-28 */
+	AU1300_PIN_U3RX, AU1300_PIN_U3TX,
+	/* LCD controller PWMs, ext pixclock: 29-31 */
+	AU1300_PIN_LCDPWM0, AU1300_PIN_LCDPWM1, AU1300_PIN_LCDCLKIN,
+	/* SD1 interface: 32-37 */
+	AU1300_PIN_SD1DAT0, AU1300_PIN_SD1DAT1, AU1300_PIN_SD1DAT2,
+	AU1300_PIN_SD1DAT3, AU1300_PIN_SD1CMD, AU1300_PIN_SD1CLK,
+	/* SD2 interface: 38-43 */
+	AU1300_PIN_SD2DAT0, AU1300_PIN_SD2DAT1, AU1300_PIN_SD2DAT2,
+	AU1300_PIN_SD2DAT3, AU1300_PIN_SD2CMD, AU1300_PIN_SD2CLK,
+	/* PSC0/1 clocks: 44-45 */
+	AU1300_PIN_PSC0CLK, AU1300_PIN_PSC1CLK,
+	/* PSCs: 46-49/50-53/54-57/58-61 */
+	AU1300_PIN_PSC0SYNC0, AU1300_PIN_PSC0SYNC1, AU1300_PIN_PSC0D0,
+	AU1300_PIN_PSC0D1,
+	AU1300_PIN_PSC1SYNC0, AU1300_PIN_PSC1SYNC1, AU1300_PIN_PSC1D0,
+	AU1300_PIN_PSC1D1,
+	AU1300_PIN_PSC2SYNC0, AU1300_PIN_PSC2SYNC1, AU1300_PIN_PSC2D0,
+	AU1300_PIN_PSC2D1,
+	AU1300_PIN_PSC3SYNC0, AU1300_PIN_PSC3SYNC1, AU1300_PIN_PSC3D0,
+	AU1300_PIN_PSC3D1,
+	/* PCMCIA interface: 62-70 */
+	AU1300_PIN_PCE2, AU1300_PIN_PCE1, AU1300_PIN_PIOS16,
+	AU1300_PIN_PIOR, AU1300_PIN_PWE, AU1300_PIN_PWAIT,
+	AU1300_PIN_PREG, AU1300_PIN_POE, AU1300_PIN_PIOW,
+	/* camera interface H/V sync inputs: 71-72 */
+	AU1300_PIN_CIMLS, AU1300_PIN_CIMFS,
+	/* PSC2/3 clocks: 73-74 */
+	AU1300_PIN_PSC2CLK, AU1300_PIN_PSC3CLK,
+};
+
+/* GPIC (Au1300) pin management: arch/mips/alchemy/common/gpioint.c */
+extern void au1300_pinfunc_to_gpio(enum au1300_multifunc_pins gpio);
+extern void au1300_pinfunc_to_dev(enum au1300_multifunc_pins gpio);
+extern void au1300_set_irq_priority(unsigned int irq, int p);
+extern void au1300_set_dbdma_gpio(int dchan, unsigned int gpio);
+
 /* arch/mips/au1000/common/clocks.c */
 extern void set_au1x00_speed(unsigned int new_freq);
 extern unsigned int get_au1x00_speed(void);
@@ -194,13 +260,17 @@ void au_sleep(void);
 
 
 /* SOC Interrupt numbers */
-
+/* Au1000-style (IC0/1): 2 controllers with 32 sources each */
 #define AU1000_INTC0_INT_BASE	(MIPS_CPU_IRQ_BASE + 8)
 #define AU1000_INTC0_INT_LAST	(AU1000_INTC0_INT_BASE + 31)
 #define AU1000_INTC1_INT_BASE	(AU1000_INTC0_INT_LAST + 1)
 #define AU1000_INTC1_INT_LAST	(AU1000_INTC1_INT_BASE + 31)
 #define AU1000_MAX_INTR 	AU1000_INTC1_INT_LAST
 
+/* Au1300-style (GPIC): 1 controller with up to 128 sources */
+#define ALCHEMY_GPIC_INT_BASE	(MIPS_CPU_IRQ_BASE + 8)
+#define ALCHEMY_GPIC_INT_LAST	(ALCHEMY_GPIC_INT_BASE + 127)
+
 enum soc_au1000_ints {
 	AU1000_FIRST_INT	= AU1000_INTC0_INT_BASE,
 	AU1000_UART0_INT	= AU1000_FIRST_INT,
@@ -521,6 +591,43 @@ enum soc_au1200_ints {
 
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
+/* Au1300 peripheral interrupt numbers */
+#define AU1300_FIRST_INT	(ALCHEMY_GPIC_INT_BASE)
+#define AU1300_UART1_INT	(AU1300_FIRST_INT + 17)
+#define AU1300_UART2_INT	(AU1300_FIRST_INT + 25)
+#define AU1300_UART3_INT	(AU1300_FIRST_INT + 27)
+#define AU1300_SD1_INT		(AU1300_FIRST_INT + 32)
+#define AU1300_SD2_INT		(AU1300_FIRST_INT + 38)
+#define AU1300_PSC0_INT		(AU1300_FIRST_INT + 48)
+#define AU1300_PSC1_INT		(AU1300_FIRST_INT + 52)
+#define AU1300_PSC2_INT		(AU1300_FIRST_INT + 56)
+#define AU1300_PSC3_INT		(AU1300_FIRST_INT + 60)
+#define AU1300_NAND_INT		(AU1300_FIRST_INT + 62)
+#define AU1300_DDMA_INT		(AU1300_FIRST_INT + 75)
+#define AU1300_MMU_INT		(AU1300_FIRST_INT + 76)
+#define AU1300_MPU_INT		(AU1300_FIRST_INT + 77)
+#define AU1300_GPU_INT		(AU1300_FIRST_INT + 78)
+#define AU1300_UDMA_INT		(AU1300_FIRST_INT + 79)
+#define AU1300_TOY_INT		(AU1300_FIRST_INT + 80)
+#define AU1300_TOY_MATCH0_INT	(AU1300_FIRST_INT + 81)
+#define AU1300_TOY_MATCH1_INT	(AU1300_FIRST_INT + 82)
+#define AU1300_TOY_MATCH2_INT	(AU1300_FIRST_INT + 83)
+#define AU1300_RTC_INT		(AU1300_FIRST_INT + 84)
+#define AU1300_RTC_MATCH0_INT	(AU1300_FIRST_INT + 85)
+#define AU1300_RTC_MATCH1_INT	(AU1300_FIRST_INT + 86)
+#define AU1300_RTC_MATCH2_INT	(AU1300_FIRST_INT + 87)
+#define AU1300_UART0_INT	(AU1300_FIRST_INT + 88)
+#define AU1300_SD0_INT		(AU1300_FIRST_INT + 89)
+#define AU1300_USB_INT		(AU1300_FIRST_INT + 90)
+#define AU1300_LCD_INT		(AU1300_FIRST_INT + 91)
+#define AU1300_BSA_INT		(AU1300_FIRST_INT + 92)
+#define AU1300_MPE_INT		(AU1300_FIRST_INT + 93)
+#define AU1300_ITE_INT		(AU1300_FIRST_INT + 94)
+#define AU1300_AES_INT		(AU1300_FIRST_INT + 95)
+#define AU1300_CIM_INT		(AU1300_FIRST_INT + 96)
+
+/**********************************************************************/
+
 /*
  * SDRAM register offsets
  */
@@ -808,6 +915,46 @@ enum soc_au1200_ints {
 #define PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL
 #endif
 
+/**********************************************************************/
+
+#define AU1300_ROM_PHYS_ADDR	0x10000000
+#define AU1300_OTP_PHYS_ADDR	0x10002000
+#define AU1300_UART0_PHYS_ADDR	0x10100000
+#define AU1300_UART1_PHYS_ADDR	0x10101000
+#define AU1300_UART2_PHYS_ADDR	0x10102000
+#define AU1300_UART3_PHYS_ADDR	0x10103000
+#define AU1300_GPIC_PHYS_ADDR	0x10200000
+#define AU1300_AES_PHYS_ADDR	0x10300000
+#define AU1300_GPU_PHYS_ADDR	0x10500000
+#define AU1300_SD0_PHYS_ADDR	0x10600000
+#define AU1300_SD1_PHYS_ADDR	0x10601000
+#define AU1300_SD2_PHYS_ADDR	0x10602000
+#define AU1300_SYS_PHYS_ADDR	0x10900000
+#define AU1300_PSC0_PHYS_ADDR	0x10A00000
+#define AU1300_PSC1_PHYS_ADDR	0x10A01000
+#define AU1300_PSC2_PHYS_ADDR	0x10A02000
+#define AU1300_PSC3_PHYS_ADDR	0x10A03000
+#define AU1300_VSS_PHYS_ADDR	0x11003000
+
+#define AU1300_MEM_PHYS_ADDR	0x14000000
+#define AU1300_STATIC_PHYS_ADDR	0x14001000
+#define AU1300_UDMA_PHYS_ADDR	0x14001800
+#define AU1300_DDMA_PHYS_ADDR	0x14002000
+#define AU1300_CIM_PHYS_ADDR	0x14004000
+#define AU1300_MAEITE_PHYS_ADDR	0x14010000
+#define AU1300_MAEMPE_PHYS_ADDR	0x14014000
+#define AU1300_USB_PHYS_ADDR	0x14020000
+#define AU1300_MAEBSA_PHYS_ADDR	0x14030000
+#define AU1300_LCD_PHYS_ADDR	0x15000000
+
+#ifdef CONFIG_SOC_AU1300
+#define PCMCIA_IO_PHYS_ADDR	0xF00000000ULL
+#define PCMCIA_ATTR_PHYS_ADDR	0xF40000000ULL
+#define PCMCIA_MEM_PHYS_ADDR	0xF80000000ULL
+#endif
+
+/**********************************************************************/
+
 /* Static Bus Controller */
 #define MEM_STCFG0		0xB4001000
 #define MEM_STTIME0		0xB4001004
@@ -825,14 +972,12 @@ enum soc_au1200_ints {
 #define MEM_STTIME3		0xB4001034
 #define MEM_STADDR3		0xB4001038
 
-#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
 #define MEM_STNDCTL		0xB4001100
 #define MEM_STSTAT		0xB4001104
 
 #define MEM_STNAND_CMD		0x0
 #define MEM_STNAND_ADDR 	0x4
 #define MEM_STNAND_DATA 	0x20
-#endif
 
 
 /* Interrupt Controller register offsets */
@@ -942,6 +1087,52 @@ enum soc_au1200_ints {
 
 #define IC1_TESTBIT		0xB1800080
 
+/*
+ * Au1300 GPIO+INT controller (GPIC) register offsets and bits
+ * Registers are 128bits (0x10 bytes), divided into 4 "banks".
+ */
+#define AU1300_GPIC_PINVAL	0x0000
+#define AU1300_GPIC_PINVALCLR	0x0010
+#define AU1300_GPIC_IPEND	0x0020
+#define AU1300_GPIC_PRIENC	0x0030
+#define AU1300_GPIC_IEN		0x0040	/* int_mask in manual */
+#define AU1300_GPIC_IDIS	0x0050	/* int_maskclr in manual */
+#define AU1300_GPIC_DMASEL	0x0060
+#define AU1300_GPIC_DEVSEL	0x0080
+#define AU1300_GPIC_DEVCLR	0x0090
+#define AU1300_GPIC_RSTVAL	0x00a0
+/* pin configuration space. one 32bit register for up to 128 IRQs */
+#define AU1300_GPIC_PINCFG	0x1000
+
+#define GPIC_GPIO_TO_BIT(gpio)	\
+	(1 << ((gpio) & 0x1f))
+
+#define GPIC_GPIO_BANKOFF(gpio)	\
+	(((gpio) >> 5) * 4)
+
+/* Pin Control bits: who owns the pin, what does it do */
+#define GPIC_CFG_PC_GPIN		0
+#define GPIC_CFG_PC_DEV			1
+#define GPIC_CFG_PC_GPOLOW		2
+#define GPIC_CFG_PC_GPOHIGH		3
+#define GPIC_CFG_PC_MASK		3
+
+/* assign pin to MIPS IRQ line */
+#define GPIC_CFG_IL_SET(x)	(((x) & 3) << 2)
+#define GPIC_CFG_IL_MASK	(3 << 2)
+
+/* pin interrupt type setup */
+#define GPIC_CFG_IC_OFF		(0 << 4)
+#define GPIC_CFG_IC_LEVEL_LOW	(1 << 4)
+#define GPIC_CFG_IC_LEVEL_HIGH	(2 << 4)
+#define GPIC_CFG_IC_EDGE_FALL	(5 << 4)
+#define GPIC_CFG_IC_EDGE_RISE	(6 << 4)
+#define GPIC_CFG_IC_EDGE_BOTH	(7 << 4)
+#define GPIC_CFG_IC_MASK	(7 << 4)
+
+/* allow interrupt to wake cpu from 'wait' */
+#define GPIC_CFG_IDLEWAKE	(1 << 7)
+
 
 /* Au1000 */
 #ifdef CONFIG_SOC_AU1000
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
index c8a553a..17101e1 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
@@ -195,6 +195,39 @@ typedef volatile struct au1xxx_ddma_desc {
 #define DSCR_CMD0_CIM_SYNC	26
 #endif /* CONFIG_SOC_AU1200 */
 
+#ifdef CONFIG_SOC_AU1300
+#define DSCR_CMD0_UART0_TX      0
+#define DSCR_CMD0_UART0_RX      1
+#define DSCR_CMD0_UART1_TX      2
+#define DSCR_CMD0_UART1_RX      3
+#define DSCR_CMD0_UART2_TX      4
+#define DSCR_CMD0_UART2_RX      5
+#define DSCR_CMD0_UART3_TX      6
+#define DSCR_CMD0_UART3_RX      7
+#define DSCR_CMD0_SDMS_TX0      8
+#define DSCR_CMD0_SDMS_RX0      9
+#define DSCR_CMD0_SDMS_TX1      10
+#define DSCR_CMD0_SDMS_RX1      11
+#define DSCR_CMD0_AES_TX        12
+#define DSCR_CMD0_AES_RX        13
+#define DSCR_CMD0_PSC0_TX       14
+#define DSCR_CMD0_PSC0_RX       15
+#define DSCR_CMD0_PSC1_TX       16
+#define DSCR_CMD0_PSC1_RX       17
+#define DSCR_CMD0_PSC2_TX       18
+#define DSCR_CMD0_PSC2_RX       19
+#define DSCR_CMD0_PSC3_TX       20
+#define DSCR_CMD0_PSC3_RX       21
+#define DSCR_CMD0_LCD           22
+#define DSCR_CMD0_NAND_FLASH    23
+#define DSCR_CMD0_SDMS_TX2      24
+#define DSCR_CMD0_SDMS_RX2      25
+#define DSCR_CMD0_CIM_SYNC      26
+#define DSCR_CMD0_UDMA          27
+#define DSCR_CMD0_DMA_REQ0      28
+#define DSCR_CMD0_DMA_REQ1      29
+#endif /* CONFIG_SOC_AU1300 */
+
 #define DSCR_CMD0_THROTTLE	30
 #define DSCR_CMD0_ALWAYS	31
 #define DSCR_NDEV_IDS		32
diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1300.h b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h
new file mode 100644
index 0000000..afdc4d1
--- /dev/null
+++ b/arch/mips/include/asm/mach-au1x00/gpio-au1300.h
@@ -0,0 +1,215 @@
+/*
+ * gpio-au1300.h -- GPIO control for Au1300 and compatibles.
+ *
+ * Copyright (c) 2009-2010 Manuel Lauss <manuel.lauss@xxxxxxxxx>
+ */
+
+#ifndef _GPIO_AU1300_H_
+#define _GPIO_AU1300_H_
+
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define AU1300_GPIO_BASE	0
+#define AU1300_GPIO_NUM		75
+#define AU1300_GPIO_MAX		(AU1300_GPIO_BASE + AU1300_GPIO_NUM - 1)
+
+#define AU1300_GPIC_ADDR	\
+	(void __iomem *)KSEG1ADDR(AU1300_GPIC_PHYS_ADDR)
+
+static inline int au1300_gpio_get_value(int gpio)
+{
+	void __iomem *roff = AU1300_GPIC_ADDR;
+	int bit;
+
+	gpio -= AU1300_GPIO_BASE;
+	roff += GPIC_GPIO_BANKOFF(gpio);
+	bit = GPIC_GPIO_TO_BIT(gpio);
+	return __raw_readl(roff + AU1300_GPIC_PINVAL) & bit;
+}
+
+static inline int au1300_gpio_direction_input(int gpio)
+{
+	void __iomem *roff = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	gpio -= AU1300_GPIO_BASE;
+
+	roff += GPIC_GPIO_BANKOFF(gpio);
+	bit = GPIC_GPIO_TO_BIT(gpio);
+	__raw_writel(bit, roff + AU1300_GPIC_DEVCLR);
+	wmb();
+
+	return 0;
+}
+
+static inline int au1300_gpio_set_value(int gpio, int v)
+{
+	void __iomem *roff = AU1300_GPIC_ADDR;
+	unsigned long bit;
+
+	gpio -= AU1300_GPIO_BASE;
+
+	roff += GPIC_GPIO_BANKOFF(gpio);
+	bit = GPIC_GPIO_TO_BIT(gpio);
+	__raw_writel(bit, roff + (v ? AU1300_GPIC_PINVAL
+				    : AU1300_GPIC_PINVALCLR));
+	wmb();
+
+	return 0;
+}
+
+static inline int au1300_gpio_direction_output(int gpio, int v)
+{
+	/* hw switches to output automatically */
+	return au1300_gpio_set_value(gpio, v);
+}
+
+static inline int au1300_gpio_to_irq(int gpio)
+{
+	return AU1300_FIRST_INT + (gpio - AU1300_GPIO_BASE);
+}
+
+static inline int au1300_irq_to_gpio(int irq)
+{
+	return (irq - AU1300_FIRST_INT) + AU1300_GPIO_BASE;
+}
+
+static inline int au1300_gpio_is_valid(int gpio)
+{
+	return ((gpio >= AU1300_GPIO_BASE) && (gpio <= AU1300_GPIO_MAX));
+}
+
+static inline int au1300_gpio_cansleep(int gpio)
+{
+	return 0;
+}
+
+static inline void alchemy_gpio1_input_enable(void)
+{
+	__raw_writel(0, (void __iomem *)KSEG1ADDR(AU1300_SYS_PHYS_ADDR) + 0x110);
+	wmb();
+}
+
+/* hardware remembers gpio 0-63 levels on powerup */
+static inline int au1300_gpio_getinitlvl(unsigned int gpio)
+{
+	void __iomem *roff = AU1300_GPIC_ADDR;
+	unsigned long v;
+
+	if (unlikely(gpio > 63))
+		return 0;
+	else if (gpio > 31) {
+		gpio -= 32;
+		roff += 4;
+	}
+
+	v = __raw_readl(roff + AU1300_GPIC_RSTVAL);
+	return (v >> gpio) & 1;
+}
+
+/**********************************************************************/
+
+/* Linux gpio framework integration.
+*
+* 4 use cases of Alchemy GPIOS:
+*(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y:
+*	Board must register gpiochips.
+*(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n:
+*	A gpiochip for the 75 GPIOs is registered.
+*
+*(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y:
+*	the boards' gpio.h must provide	the linux gpio wrapper functions,
+*
+*(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n:
+*	inlinable gpio functions are provided which enable access to the
+*	Au1300 gpios only by using the numbers straight out of the data-
+*	sheets.
+
+* Cases 1 and 3 are intended for boards which want to provide their own
+* GPIO namespace and -operations (i.e. for example you have 8 GPIOs
+* which are in part provided by spare Au1300 GPIO pins and in part by
+* an external FPGA but you still want them to be accssible in linux
+* as gpio0-7. The board can of course use the alchemy_gpioX_* functions
+* as required).
+*/
+
+#ifndef CONFIG_GPIOLIB
+
+
+#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT	/* case (4) */
+
+static inline int gpio_direction_input(int gpio)
+{
+	return au1300_gpio_direction_input(gpio);
+}
+
+static inline int gpio_direction_output(int gpio, int v)
+{
+	return au1300_gpio_direction_output(gpio, v);
+}
+
+static inline int gpio_get_value(int gpio)
+{
+	return au1300_gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(int gpio, int v)
+{
+	au1300_gpio_set_value(gpio, v);
+}
+
+static inline int gpio_is_valid(int gpio)
+{
+	return au1300_gpio_is_valid(gpio);
+}
+
+static inline int gpio_cansleep(int gpio)
+{
+	return au1300_gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(int gpio)
+{
+	return au1300_gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(int irq)
+{
+	return au1300_irq_to_gpio(irq);
+}
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+	return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+}
+
+#endif	/* !CONFIG_ALCHEMY_GPIO_INDIRECT */
+
+
+#else	/* CONFIG GPIOLIB */
+
+
+/* using gpiolib to provide up to 2 gpio_chips for on-chip gpios */
+#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT	/* case (2) */
+
+/* get everything through gpiolib */
+#define gpio_to_irq	__gpio_to_irq
+#define gpio_get_value	__gpio_get_value
+#define gpio_set_value	__gpio_set_value
+#define gpio_cansleep	__gpio_cansleep
+#define irq_to_gpio	au1300_irq_to_gpio
+
+#include <asm-generic/gpio.h>
+
+#endif	/* !CONFIG_ALCHEMY_GPIO_INDIRECT */
+
+
+#endif	/* !CONFIG_GPIOLIB */
+
+#endif /* _GPIO_AU1300_H_ */
diff --git a/arch/mips/include/asm/mach-au1x00/gpio.h b/arch/mips/include/asm/mach-au1x00/gpio.h
index c3f60cd..4d6edea 100644
--- a/arch/mips/include/asm/mach-au1x00/gpio.h
+++ b/arch/mips/include/asm/mach-au1x00/gpio.h
@@ -5,6 +5,10 @@
 
 #include <asm/mach-au1x00/gpio-au1000.h>
 
+#elif defined(CONFIG_ALCHEMY_GPIOINT_AU1300)
+
+#include <asm/mach-au1x00/gpio-au1300.h>
+
 #endif
 
 #endif	/* _ALCHEMY_GPIO_H_ */
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index be5bb16..432eef7 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -826,6 +826,21 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
 	}
 }
 
+static inline void cpu_probe_rmi(struct cpuinfo_mips *c, int cpu)
+{
+	decode_configs(c);
+
+	switch (c->processor_id & 0xff00) {
+	case PRID_IMP_AU13XX:
+		c->cputype = CPU_ALCHEMY;
+		__cpu_name[cpu] = "Au13xx";
+		break;
+	default:
+		panic("Unknown RMI core!\n");
+		break;
+	}
+}
+
 static inline void cpu_probe_sibyte(struct cpuinfo_mips *c, unsigned int cpu)
 {
 	decode_configs(c);
@@ -967,6 +982,9 @@ __cpuinit void cpu_probe(void)
 	case PRID_COMP_NXP:
 		cpu_probe_nxp(c, cpu);
 		break;
+	case PRID_COMP_RMI:
+		cpu_probe_rmi(c, cpu);
+		break;
 	case PRID_COMP_CAVIUM:
 		cpu_probe_cavium(c, cpu);
 		break;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 9c6170c..3207d6d 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -297,7 +297,7 @@ config I2C_AT91
 
 config I2C_AU1550
 	tristate "Au1550/Au1200 SMBus interface"
-	depends on SOC_AU1550 || SOC_AU1200
+	depends on SOC_AU1550 || SOC_AU1200 || SOC_AU1300
 	help
 	  If you say yes to this option, support will be included for the
 	  Au1550 and Au1200 SMBus interface.
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a191fa2..1d88767 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -68,7 +68,7 @@ config SPI_BFIN
 
 config SPI_AU1550
 	tristate "Au1550/Au12x0 SPI Controller"
-	depends on (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
+	depends on (SOC_AU1550 || SOC_AU1200 || SOC_AU1300) && EXPERIMENTAL
 	select SPI_BITBANG
 	help
 	  If you say yes to this option, support will be included for the
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6e16244..5ac6939 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1694,15 +1694,16 @@ config FB_AU1100
 	  au1100fb:panel=<name>.
 
 config FB_AU1200
-	bool "Au1200 LCD Driver"
-	depends on (FB = y) && MIPS && SOC_AU1200
-	select FB_CFB_FILLRECT
-	select FB_CFB_COPYAREA
-	select FB_CFB_IMAGEBLIT
+	bool "Au1200/Au1300 LCD Driver"
+	depends on (FB = y) && (SOC_AU1200 || SOC_AU1300)
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
 	help
-	  This is the framebuffer driver for the AMD Au1200 SOC.  It can drive
-	  various panels and CRTs by passing in kernel cmd line option
-	  au1200fb:panel=<name>.
+	  This is the framebuffer driver for the AMD Au1200/Au1300 SOCs.
+	  It can drive various panels and CRTs by passing in kernel
+	  cmdline option au1200fb:panel=<name>.
 
 source "drivers/video/geode/Kconfig"
 
-- 
1.7.0.4



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux