Base Au1200 2.6 support.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 2edbef5..455de42 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -642,6 +642,10 @@
 	help
 	  If you want this kernel to run on SGI O2 workstation, say Y here.
 
+config SOC_AU1200
+	bool
+	select SOC_AU1X00
+
 config SOC_AU1X00
 	bool "Support for AMD/Alchemy Au1X00 SOCs"
 	select SYS_SUPPORTS_32BIT_KERNEL
@@ -702,6 +706,13 @@
 	select HW_HAS_PCI
 	select MIPS_DISABLE_OBSOLETE_IDE
 
+config MIPS_PB1200
+	bool "AMD Alchemy PB1200 board"
+	select SOC_AU1200
+	select DMA_NONCOHERENT
+	select MIPS_DISABLE_OBSOLETE_IDE
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+
 config MIPS_DB1000
 	bool "DB1000 board"
 	depends on SOC_AU1000
@@ -732,6 +743,13 @@
 	depends on SOC_AU1500
 	select DMA_NONCOHERENT
 
+config MIPS_DB1200
+	bool "AMD Alchemy DB1200 board"
+	select SOC_AU1200
+	select DMA_NONCOHERENT
+	select MIPS_DISABLE_OBSOLETE_IDE
+	select SYS_SUPPORTS_LITTLE_ENDIAN
+
 config MIPS_MIRAGE
 	bool "Mirage board"
 	depends on SOC_AU1500
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 5f2dfcd..99da8a2 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -266,6 +266,13 @@
 load-$(CONFIG_MIPS_PB1550)	+= 0xffffffff80100000
 
 #
+# AMD Alchemy Pb1200 eval board
+#
+libs-$(CONFIG_MIPS_PB1200)	+= arch/mips/au1000/pb1200/
+cflags-$(CONFIG_MIPS_PB1200)	+= -Iinclude/asm-mips/mach-pb1x00
+load-$(CONFIG_MIPS_PB1200)	+= 0xffffffff80100000
+
+#
 # AMD Alchemy Db1000 eval board
 #
 libs-$(CONFIG_MIPS_DB1000)	+= arch/mips/au1000/db1x00/
@@ -294,6 +301,13 @@
 load-$(CONFIG_MIPS_DB1550)	+= 0xffffffff80100000
 
 #
+# AMD Alchemy Db1200 eval board
+#
+libs-$(CONFIG_MIPS_DB1200)	+= arch/mips/au1000/pb1200/
+cflags-$(CONFIG_MIPS_DB1200)	+= -Iinclude/asm-mips/mach-db1x00
+load-$(CONFIG_MIPS_DB1200)	+= 0xffffffff80100000
+
+#
 # AMD Alchemy Bosporus eval board
 #
 libs-$(CONFIG_MIPS_BOSPORUS)	+= arch/mips/au1000/db1x00/
diff --git a/arch/mips/au1000/common/au1xxx_irqmap.c b/arch/mips/au1000/common/au1xxx_irqmap.c
index 8a0f39f..0b2c03c 100644
--- a/arch/mips/au1000/common/au1xxx_irqmap.c
+++ b/arch/mips/au1000/common/au1xxx_irqmap.c
@@ -173,14 +173,14 @@
 	{ AU1550_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
 	{ AU1550_PSC2_INT, INTC_INT_HIGH_LEVEL, 0},
 	{ AU1550_PSC3_INT, INTC_INT_HIGH_LEVEL, 0},
-	{ AU1550_TOY_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1550_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1550_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1550_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
-	{ AU1550_RTC_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1550_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1550_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1550_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
+	{ AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
 	{ AU1550_NAND_INT, INTC_INT_RISE_EDGE, 0},
 	{ AU1550_USB_DEV_REQ_INT, INTC_INT_HIGH_LEVEL, 0 },
 	{ AU1550_USB_DEV_SUS_INT, INTC_INT_RISE_EDGE, 0 },
@@ -201,14 +201,14 @@
 	{ AU1200_PSC1_INT, INTC_INT_HIGH_LEVEL, 0},
 	{ AU1200_AES_INT, INTC_INT_HIGH_LEVEL, 0},
 	{ AU1200_CAMERA_INT, INTC_INT_HIGH_LEVEL, 0},
-	{ AU1200_TOY_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1200_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1200_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1200_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
-	{ AU1200_RTC_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1200_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1200_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
-	{ AU1200_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_TOY_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_TOY_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_TOY_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_TOY_MATCH2_INT, INTC_INT_RISE_EDGE, 1 },
+	{ AU1000_RTC_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_RTC_MATCH0_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_RTC_MATCH1_INT, INTC_INT_RISE_EDGE, 0 },
+	{ AU1000_RTC_MATCH2_INT, INTC_INT_RISE_EDGE, 0 },
 	{ AU1200_NAND_INT, INTC_INT_RISE_EDGE, 0},
 	{ AU1200_USB_INT, INTC_INT_HIGH_LEVEL, 0 },
 	{ AU1200_LCD_INT, INTC_INT_HIGH_LEVEL, 0},
diff --git a/arch/mips/au1000/common/cputable.c b/arch/mips/au1000/common/cputable.c
index f5521df..4dbde82 100644
--- a/arch/mips/au1000/common/cputable.c
+++ b/arch/mips/au1000/common/cputable.c
@@ -37,7 +37,8 @@
     { 0xffffffff, 0x02030203, "Au1100 BD", 0, 1 },
     { 0xffffffff, 0x02030204, "Au1100 BE", 0, 1 },
     { 0xffffffff, 0x03030200, "Au1550 AA", 0, 1 },
-    { 0xffffffff, 0x04030200, "Au1200 AA", 0, 1 },
+    { 0xffffffff, 0x04030200, "Au1200 AB", 0, 0 },
+    { 0xffffffff, 0x04030201, "Au1200 AC", 0, 1 },
     { 0x00000000, 0x00000000, "Unknown Au1xxx", 1, 0 },
 };
 
diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c
index adfc317..cf10dc2 100644
--- a/arch/mips/au1000/common/dbdma.c
+++ b/arch/mips/au1000/common/dbdma.c
@@ -29,6 +29,7 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -42,6 +43,8 @@
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/system.h>
 
+/* #include <linux/module.h> */
+
 #if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
 
 /*
@@ -55,43 +58,16 @@
  * functions.  The drivers allocate the data buffers and assign them
  * to the descriptors.
  */
-static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
+static spinlock_t au1xxx_dbdma_spin_lock = SPIN_LOCK_UNLOCKED;
 
 /* I couldn't find a macro that did this......
 */
 #define ALIGN_ADDR(x, a)	((((u32)(x)) + (a-1)) & ~(a-1))
 
-static volatile dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
-static int dbdma_initialized;
+static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
+static int dbdma_initialized=0;
 static void au1xxx_dbdma_init(void);
 
-typedef struct dbdma_device_table {
-	u32		dev_id;
-	u32		dev_flags;
-	u32		dev_tsize;
-	u32		dev_devwidth;
-	u32		dev_physaddr;		/* If FIFO */
-	u32		dev_intlevel;
-	u32		dev_intpolarity;
-} dbdev_tab_t;
-
-typedef struct dbdma_chan_config {
-	u32			chan_flags;
-	u32			chan_index;
-	dbdev_tab_t		*chan_src;
-	dbdev_tab_t		*chan_dest;
-	au1x_dma_chan_t		*chan_ptr;
-	au1x_ddma_desc_t	*chan_desc_base;
-	au1x_ddma_desc_t	*get_ptr, *put_ptr, *cur_ptr;
-	void			*chan_callparam;
-	void (*chan_callback)(int, void *, struct pt_regs *);
-} chan_tab_t;
-
-#define	DEV_FLAGS_INUSE		(1 << 0)
-#define	DEV_FLAGS_ANYUSE	(1 << 1)
-#define DEV_FLAGS_OUT		(1 << 2)
-#define DEV_FLAGS_IN		(1 << 3)
-
 static dbdev_tab_t dbdev_tab[] = {
 #ifdef CONFIG_SOC_AU1550
 	/* UARTS */
@@ -157,13 +133,13 @@
 	{ DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 	{ DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 
-	{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
-	{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
-	{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
-	{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+	{ DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 },
+	{ DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 },
+	{ DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 },
+	{ DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 },
 
-	{ DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 },
-	{ DSCR_CMD0_AES_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 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, 0, 0x11a0001c, 0, 0 },
 	{ DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 },
@@ -173,9 +149,9 @@
 	{ DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 },
 	{ DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 
-	{ DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
-	{ DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
-	{ DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
+	{ DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 },
+	{ DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 },
+	{ DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 },
 	{ DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 
 	{ DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 },
@@ -184,6 +160,24 @@
 
 	{ DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
 	{ DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 },
+
+	/* Provide 16 user definable device types */
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
+	{ 0, 0, 0, 0, 0, 0, 0 },
 };
 
 #define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t))
@@ -203,6 +197,30 @@
 	return NULL;
 }
 
+u32
+au1xxx_ddma_add_device(dbdev_tab_t *dev)
+{
+	u32 ret = 0;
+	dbdev_tab_t *p=NULL;
+	static u16 new_id=0x1000;
+
+	p = find_dbdev_id(0);
+	if ( NULL != p )
+	{
+		memcpy(p, dev, sizeof(dbdev_tab_t));
+ 		p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id);
+		ret = p->dev_id;
+		new_id++;
+#if 0
+		printk("add_device: id:%x flags:%x padd:%x\n",
+				p->dev_id, p->dev_flags, p->dev_physaddr );
+#endif
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(au1xxx_ddma_add_device);
+
 /* Allocate a channel and return a non-zero descriptor if successful.
 */
 u32
@@ -215,7 +233,7 @@
 	int		i;
 	dbdev_tab_t	*stp, *dtp;
 	chan_tab_t	*ctp;
-	volatile au1x_dma_chan_t *cp;
+	au1x_dma_chan_t *cp;
 
 	/* We do the intialization on the first channel allocation.
 	 * We have to wait because of the interrupt handler initialization
@@ -225,9 +243,6 @@
 		au1xxx_dbdma_init();
 	dbdma_initialized = 1;
 
-	if ((srcid > DSCR_NDEV_IDS) || (destid > DSCR_NDEV_IDS))
-		return 0;
-
 	if ((stp = find_dbdev_id(srcid)) == NULL) return 0;
 	if ((dtp = find_dbdev_id(destid)) == NULL) return 0;
 
@@ -269,9 +284,9 @@
 				/* If kmalloc fails, it is caught below same
 				 * as a channel not available.
 				 */
-				ctp = kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
+				ctp = (chan_tab_t *)
+					kmalloc(sizeof(chan_tab_t), GFP_KERNEL);
 				chan_tab_ptr[i] = ctp;
-				ctp->chan_index = chan = i;
 				break;
 			}
 		}
@@ -279,10 +294,11 @@
 
 		if (ctp != NULL) {
 			memset(ctp, 0, sizeof(chan_tab_t));
+			ctp->chan_index = chan = i;
 			dcp = DDMA_CHANNEL_BASE;
 			dcp += (0x0100 * chan);
 			ctp->chan_ptr = (au1x_dma_chan_t *)dcp;
-			cp = (volatile au1x_dma_chan_t *)dcp;
+			cp = (au1x_dma_chan_t *)dcp;
 			ctp->chan_src = stp;
 			ctp->chan_dest = dtp;
 			ctp->chan_callback = callback;
@@ -299,6 +315,9 @@
 				i |= DDMA_CFG_DED;
 			if (dtp->dev_intpolarity)
 				i |= DDMA_CFG_DP;
+			if ((stp->dev_flags & DEV_FLAGS_SYNC) ||
+				(dtp->dev_flags & DEV_FLAGS_SYNC))
+					i |= DDMA_CFG_SYNC;
 			cp->ddma_cfg = i;
 			au_sync();
 
@@ -309,14 +328,14 @@
 			rv = (u32)(&chan_tab_ptr[chan]);
 		}
 		else {
-			/* Release devices.
-			*/
+			/* Release devices */
 			stp->dev_flags &= ~DEV_FLAGS_INUSE;
 			dtp->dev_flags &= ~DEV_FLAGS_INUSE;
 		}
 	}
 	return rv;
 }
+EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc);
 
 /* Set the device width if source or destination is a FIFO.
  * Should be 8, 16, or 32 bits.
@@ -344,6 +363,7 @@
 
 	return rv;
 }
+EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth);
 
 /* Allocate a descriptor ring, initializing as much as possible.
 */
@@ -370,7 +390,8 @@
 	 * and if we try that first we are likely to not waste larger
 	 * slabs of memory.
 	 */
-	desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL);
+	desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t),
+			GFP_KERNEL|GFP_DMA);
 	if (desc_base == 0)
 		return 0;
 
@@ -381,7 +402,7 @@
 		kfree((const void *)desc_base);
 		i = entries * sizeof(au1x_ddma_desc_t);
 		i += (sizeof(au1x_ddma_desc_t) - 1);
-		if ((desc_base = (u32)kmalloc(i, GFP_KERNEL)) == 0)
+		if ((desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA)) == 0)
 			return 0;
 
 		desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t));
@@ -461,9 +482,14 @@
 	/* If source input is fifo, set static address.
 	*/
 	if (stp->dev_flags & DEV_FLAGS_IN) {
-		src0 = stp->dev_physaddr;
+		if ( stp->dev_flags & DEV_FLAGS_BURSTABLE )
+			src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST);
+		else
 		src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC);
+
 	}
+	if (stp->dev_physaddr)
+		src0 = stp->dev_physaddr;
 
 	/* Set up dest1.  For now, assume no stride and increment.
 	 * A channel attribute update can change this later.
@@ -487,10 +513,18 @@
 	/* If destination output is fifo, set static address.
 	*/
 	if (dtp->dev_flags & DEV_FLAGS_OUT) {
-		dest0 = dtp->dev_physaddr;
+		if ( dtp->dev_flags & DEV_FLAGS_BURSTABLE )
+	                dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST);
+				else
 		dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC);
 	}
+	if (dtp->dev_physaddr)
+		dest0 = dtp->dev_physaddr;
 
+#if 0
+		printk("did:%x sid:%x cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
+			dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, src1, dest0, dest1 );
+#endif
 	for (i=0; i<entries; i++) {
 		dp->dscr_cmd0 = cmd0;
 		dp->dscr_cmd1 = cmd1;
@@ -499,6 +533,7 @@
 		dp->dscr_dest0 = dest0;
 		dp->dscr_dest1 = dest1;
 		dp->dscr_stat = 0;
+				dp->sw_context = dp->sw_status = 0;
 		dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1));
 		dp++;
 	}
@@ -511,13 +546,14 @@
 
 	return (u32)(ctp->chan_desc_base);
 }
+EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc);
 
 /* Put a source buffer into the DMA ring.
  * This updates the source pointer and byte count.  Normally used
  * for memory to fifo transfers.
  */
 u32
-au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes)
+_au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags)
 {
 	chan_tab_t		*ctp;
 	au1x_ddma_desc_t	*dp;
@@ -544,24 +580,40 @@
 	*/
 	dp->dscr_source0 = virt_to_phys(buf);
 	dp->dscr_cmd1 = nbytes;
-	dp->dscr_cmd0 |= DSCR_CMD0_V;	/* Let it rip */
-	ctp->chan_ptr->ddma_dbell = 0xffffffff;	/* Make it go */
-
+	/* Check flags  */
+	if (flags & DDMA_FLAGS_IE)
+		dp->dscr_cmd0 |= DSCR_CMD0_IE;
+	if (flags & DDMA_FLAGS_NOIE)
+		dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
 	/* Get next descriptor pointer.
 	*/
 	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
 
+	/*
+	 * There is an errata on the Au1200/Au1550 parts that could result
+	 * in "stale" data being DMA'd. It has to do with the snoop logic on
+	 * the dache eviction buffer.  NONCOHERENT_IO is on by default for
+	 * these parts. If it is fixedin the future, these dma_cache_inv will
+	 * just be nothing more than empty macros. See io.h.
+	 * */
+	dma_cache_wback_inv(buf,nbytes);
+        dp->dscr_cmd0 |= DSCR_CMD0_V;        /* Let it rip */
+	au_sync();
+	dma_cache_wback_inv(dp, sizeof(dp));
+        ctp->chan_ptr->ddma_dbell = 0;
+
 	/* return something not zero.
 	*/
 	return nbytes;
 }
+EXPORT_SYMBOL(_au1xxx_dbdma_put_source);
 
 /* Put a destination buffer into the DMA ring.
  * This updates the destination pointer and byte count.  Normally used
  * to place an empty buffer into the ring for fifo to memory transfers.
  */
 u32
-au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes)
+_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags)
 {
 	chan_tab_t		*ctp;
 	au1x_ddma_desc_t	*dp;
@@ -583,11 +635,33 @@
 	if (dp->dscr_cmd0 & DSCR_CMD0_V)
 		return 0;
 
-	/* Load up buffer address and byte count.
-	*/
+	/* Load up buffer address and byte count */
+
+	/* Check flags  */
+	if (flags & DDMA_FLAGS_IE)
+		dp->dscr_cmd0 |= DSCR_CMD0_IE;
+	if (flags & DDMA_FLAGS_NOIE)
+		dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
+
 	dp->dscr_dest0 = virt_to_phys(buf);
 	dp->dscr_cmd1 = nbytes;
+#if 0
+	printk("cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n",
+			dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0,
+			dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1 );
+#endif
+	/*
+	 * There is an errata on the Au1200/Au1550 parts that could result in
+	 * "stale" data being DMA'd. It has to do with the snoop logic on the
+	 * dache eviction buffer. NONCOHERENT_IO is on by default for these
+	 * parts. If it is fixedin the future, these dma_cache_inv will just
+	 * be nothing more than empty macros. See io.h.
+	 * */
+	dma_cache_inv(buf,nbytes);
 	dp->dscr_cmd0 |= DSCR_CMD0_V;	/* Let it rip */
+	au_sync();
+	dma_cache_wback_inv(dp, sizeof(dp));
+        ctp->chan_ptr->ddma_dbell = 0;
 
 	/* Get next descriptor pointer.
 	*/
@@ -597,6 +671,7 @@
 	*/
 	return nbytes;
 }
+EXPORT_SYMBOL(_au1xxx_dbdma_put_dest);
 
 /* Get a destination buffer into the DMA ring.
  * Normally used to get a full buffer from the ring during fifo
@@ -646,7 +721,7 @@
 au1xxx_dbdma_stop(u32 chanid)
 {
 	chan_tab_t	*ctp;
-	volatile au1x_dma_chan_t *cp;
+	au1x_dma_chan_t *cp;
 	int halt_timeout = 0;
 
 	ctp = *((chan_tab_t **)chanid);
@@ -666,6 +741,7 @@
 	cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V);
 	au_sync();
 }
+EXPORT_SYMBOL(au1xxx_dbdma_stop);
 
 /* Start using the current descriptor pointer.  If the dbdma encounters
  * a not valid descriptor, it will stop.  In this case, we can just
@@ -675,17 +751,17 @@
 au1xxx_dbdma_start(u32 chanid)
 {
 	chan_tab_t	*ctp;
-	volatile au1x_dma_chan_t *cp;
+	au1x_dma_chan_t *cp;
 
 	ctp = *((chan_tab_t **)chanid);
-
 	cp = ctp->chan_ptr;
 	cp->ddma_desptr = virt_to_phys(ctp->cur_ptr);
 	cp->ddma_cfg |= DDMA_CFG_EN;	/* Enable channel */
 	au_sync();
-	cp->ddma_dbell = 0xffffffff;	/* Make it go */
+	cp->ddma_dbell = 0;
 	au_sync();
 }
+EXPORT_SYMBOL(au1xxx_dbdma_start);
 
 void
 au1xxx_dbdma_reset(u32 chanid)
@@ -704,15 +780,21 @@
 
 	do {
 		dp->dscr_cmd0 &= ~DSCR_CMD0_V;
+		/* reset our SW status -- this is used to determine
+		 * if a descriptor is in use by upper level SW. Since
+		 * posting can reset 'V' bit.
+		 */
+		dp->sw_status = 0;
 		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
 	} while (dp != ctp->chan_desc_base);
 }
+EXPORT_SYMBOL(au1xxx_dbdma_reset);
 
 u32
 au1xxx_get_dma_residue(u32 chanid)
 {
 	chan_tab_t	*ctp;
-	volatile au1x_dma_chan_t *cp;
+	au1x_dma_chan_t *cp;
 	u32		rv;
 
 	ctp = *((chan_tab_t **)chanid);
@@ -747,15 +829,16 @@
 
 	kfree(ctp);
 }
+EXPORT_SYMBOL(au1xxx_dbdma_chan_free);
 
-static irqreturn_t
+static void
 dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	u32	intstat;
+	u32        				intstat, flags;
 	u32	chan_index;
 	chan_tab_t		*ctp;
 	au1x_ddma_desc_t	*dp;
-	volatile au1x_dma_chan_t *cp;
+	au1x_dma_chan_t *cp;
 
 	intstat = dbdma_gptr->ddma_intstat;
 	au_sync();
@@ -774,19 +857,26 @@
 		(ctp->chan_callback)(irq, ctp->chan_callparam, regs);
 
 	ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
-
-	return IRQ_HANDLED;
 }
 
-static void
-au1xxx_dbdma_init(void)
+static void au1xxx_dbdma_init(void)
 {
+	int irq_nr;
+
 	dbdma_gptr->ddma_config = 0;
 	dbdma_gptr->ddma_throttle = 0;
 	dbdma_gptr->ddma_inten = 0xffff;
 	au_sync();
 
-	if (request_irq(AU1550_DDMA_INT, dbdma_interrupt, SA_INTERRUPT,
+#if defined(CONFIG_SOC_AU1550)
+	irq_nr = AU1550_DDMA_INT;
+#elif defined(CONFIG_SOC_AU1200)
+	irq_nr = AU1200_DDMA_INT;
+#else
+	#error Unknown Au1x00 SOC
+#endif
+
+	if (request_irq(irq_nr, dbdma_interrupt, SA_INTERRUPT,
 			"Au1xxx dbdma", (void *)dbdma_gptr))
 		printk("Can't get 1550 dbdma irq");
 }
@@ -797,7 +887,8 @@
 	chan_tab_t		*ctp;
 	au1x_ddma_desc_t	*dp;
 	dbdev_tab_t		*stp, *dtp;
-	volatile au1x_dma_chan_t *cp;
+	au1x_dma_chan_t *cp;
+		u32			i = 0;
 
 	ctp = *((chan_tab_t **)chanid);
 	stp = ctp->chan_src;
@@ -822,15 +913,64 @@
 	dp = ctp->chan_desc_base;
 
 	do {
-		printk("dp %08x, cmd0 %08x, cmd1 %08x\n",
-			(u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
-		printk("src0 %08x, src1 %08x, dest0 %08x\n",
-			dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0);
-		printk("dest1 %08x, stat %08x, nxtptr %08x\n",
-			dp->dscr_dest1, dp->dscr_stat, dp->dscr_nxtptr);
+                printk("Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n",
+                        i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1);
+                printk("src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n",
+                        dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1);
+                printk("stat %08x, nxtptr %08x\n",
+                        dp->dscr_stat, dp->dscr_nxtptr);
 		dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
 	} while (dp != ctp->chan_desc_base);
 }
 
+/* Put a descriptor into the DMA ring.
+ * This updates the source/destination pointers and byte count.
+ */
+u32
+au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr )
+{
+	chan_tab_t *ctp;
+	au1x_ddma_desc_t *dp;
+	u32 nbytes=0;
+
+	/* I guess we could check this to be within the
+	* range of the table......
+	*/
+	ctp = *((chan_tab_t **)chanid);
+
+	/* We should have multiple callers for a particular channel,
+	* an interrupt doesn't affect this pointer nor the descriptor,
+	* so no locking should be needed.
+	*/
+	dp = ctp->put_ptr;
+
+	/* If the descriptor is valid, we are way ahead of the DMA
+	* engine, so just return an error condition.
+	*/
+	if (dp->dscr_cmd0 & DSCR_CMD0_V)
+		return 0;
+
+	/* Load up buffer addresses and byte count.
+	*/
+	dp->dscr_dest0 = dscr->dscr_dest0;
+	dp->dscr_source0 = dscr->dscr_source0;
+	dp->dscr_dest1 = dscr->dscr_dest1;
+	dp->dscr_source1 = dscr->dscr_source1;
+	dp->dscr_cmd1 = dscr->dscr_cmd1;
+	nbytes = dscr->dscr_cmd1;
+	/* Allow the caller to specifiy if an interrupt is generated */
+	dp->dscr_cmd0 &= ~DSCR_CMD0_IE;
+	dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V;
+	ctp->chan_ptr->ddma_dbell = 0;
+
+	/* Get next descriptor pointer.
+	*/
+	ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr));
+
+	/* return something not zero.
+	*/
+	return nbytes;
+}
+
 #endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
 
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 0b912f7..ebf93bd 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -488,7 +488,7 @@
 	intc0_req0 |= au_readl(IC0_REQ0INT);
 
 	if (!intc0_req0) return;
-
+#ifdef AU1000_USB_DEV_REQ_INT
 	/*
 	 * Because of the tight timing of SETUP token to reply
 	 * transactions, the USB devices-side packet complete
@@ -499,7 +499,7 @@
 		do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
 		return;
 	}
-
+#endif
 	irq = au_ffs(intc0_req0) - 1;
 	intc0_req0 &= ~(1<<irq);
 	do_IRQ(irq, regs);
diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c
index 447a9a4..0b21bed 100644
--- a/arch/mips/au1000/common/usbdev.c
+++ b/arch/mips/au1000/common/usbdev.c
@@ -1005,11 +1005,11 @@
 #endif
 		dev->ep0_stage = SETUP_STAGE;
 		break;
-		}
+	}
 
 	spin_unlock(&ep0->lock);
-		// we're done processing the packet, free it
-		kfree(pkt);
+	// we're done processing the packet, free it
+	kfree(pkt);
 }
 
 
@@ -1072,8 +1072,7 @@
 			clear_dma_done1(ep0->indma);
 
 		pkt = send_packet_complete(ep0);
-		if (pkt)
-			kfree(pkt);
+		kfree(pkt);
 	}
 
 	/*
@@ -1302,8 +1301,7 @@
 		endpoint_flush(ep);
 	}
 
-	if (usbdev.full_conf_desc)
-		kfree(usbdev.full_conf_desc);
+	kfree(usbdev.full_conf_desc);
 }
 
 int
diff --git a/arch/mips/au1000/pb1200/Makefile b/arch/mips/au1000/pb1200/Makefile
new file mode 100644
index 0000000..22b673c
--- /dev/null
+++ b/arch/mips/au1000/pb1200/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Alchemy Semiconductor PB1200 board.
+#
+
+lib-y := init.o board_setup.o irqmap.o
diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/au1000/pb1200/board_setup.c
new file mode 100644
index 0000000..209a07c
--- /dev/null
+++ b/arch/mips/au1000/pb1200/board_setup.c
@@ -0,0 +1,187 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Alchemy Pb1200/Db1200 board setup.
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+#include <linux/mc146818rtc.h>
+#include <linux/delay.h>
+
+#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
+#include <linux/ide.h>
+#endif
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+
+#ifdef CONFIG_MIPS_PB1200
+#include <asm/mach-pb1x00/pb1200.h>
+#endif
+
+#ifdef CONFIG_MIPS_DB1200
+#include <asm/mach-db1x00/db1200.h>
+#define PB1200_ETH_INT DB1200_ETH_INT
+#define PB1200_IDE_INT DB1200_IDE_INT
+#endif
+
+extern void _board_init_irq(void);
+extern void	(*board_init_irq)(void);
+
+#ifdef CONFIG_BLK_DEV_IDE_AU1XXX
+extern struct ide_ops *ide_ops;
+extern struct ide_ops au1xxx_ide_ops;
+extern u32 au1xxx_ide_virtbase;
+extern u64 au1xxx_ide_physbase;
+extern int au1xxx_ide_irq;
+
+u32 led_base_addr;
+/* Ddma */
+chan_tab_t *ide_read_ch, *ide_write_ch;
+u32 au1xxx_ide_ddma_enable = 0, switch4ddma = 1; // PIO+ddma
+
+dbdev_tab_t new_dbdev_tab_element = { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 };
+#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX */
+
+void board_reset (void)
+{
+	bcsr->resets = 0;
+}
+
+void __init board_setup(void)
+{
+	char *argptr = NULL;
+	u32 pin_func;
+
+#if 0
+	/* Enable PSC1 SYNC for AC97.  Normaly done in audio driver,
+	 * but it is board specific code, so put it here.
+	 */
+	pin_func = au_readl(SYS_PINFUNC);
+	au_sync();
+	pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
+	au_writel(pin_func, SYS_PINFUNC);
+
+	au_writel(0, (u32)bcsr|0x10); /* turn off pcmcia power */
+	au_sync();
+#endif
+
+#if defined( CONFIG_I2C_ALGO_AU1550 )
+	{
+	u32 freq0, clksrc;
+
+	/* Select SMBUS in CPLD */
+	bcsr->resets &= ~(BCSR_RESETS_PCS0MUX);
+
+	pin_func = au_readl(SYS_PINFUNC);
+	au_sync();
+	pin_func &= ~(3<<17 | 1<<4);
+	/* Set GPIOs correctly */
+	pin_func |= 2<<17;
+	au_writel(pin_func, SYS_PINFUNC);
+	au_sync();
+
+	/* The i2c driver depends on 50Mhz clock */
+	freq0 = au_readl(SYS_FREQCTRL0);
+	au_sync();
+	freq0 &= ~(SYS_FC_FRDIV1_MASK | SYS_FC_FS1 | SYS_FC_FE1);
+	freq0 |= (3<<SYS_FC_FRDIV1_BIT);
+	/* 396Mhz / (3+1)*2 == 49.5Mhz */
+	au_writel(freq0, SYS_FREQCTRL0);
+	au_sync();
+	freq0 |= SYS_FC_FE1;
+	au_writel(freq0, SYS_FREQCTRL0);
+	au_sync();
+
+	clksrc = au_readl(SYS_CLKSRC);
+	au_sync();
+	clksrc &= ~0x01f00000;
+	/* bit 22 is EXTCLK0 for PSC0 */
+	clksrc |= (0x3 << 22);
+	au_writel(clksrc, SYS_CLKSRC);
+	au_sync();
+	}
+#endif
+
+#ifdef CONFIG_FB_AU1200
+	argptr = prom_getcmdline();
+#ifdef CONFIG_MIPS_PB1200
+	strcat(argptr, " video=au1200fb:panel:s11");
+#endif
+#ifdef CONFIG_MIPS_DB1200
+	strcat(argptr, " video=au1200fb:panel:s7");
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE_AU1XXX)
+	/*
+	 * Iniz IDE parameters
+	 */
+	ide_ops = &au1xxx_ide_ops;
+	au1xxx_ide_irq = PB1200_IDE_INT;
+	au1xxx_ide_physbase = AU1XXX_ATA_PHYS_ADDR;
+	au1xxx_ide_virtbase = KSEG1ADDR(AU1XXX_ATA_PHYS_ADDR);
+	/*
+	 * change PIO or PIO+Ddma
+	 * check the GPIO-5 pin condition. pb1200:s18_dot */
+	switch4ddma = (au_readl(SYS_PINSTATERD) & (1 << 5)) ? 1 : 0;
+#endif
+
+	/* The Pb1200 development board uses external MUX for PSC0 to
+	support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI
+	*/
+#if defined(CONFIG_AU1550_PSC_SPI) && defined(CONFIG_I2C_ALGO_AU1550)
+	#error I2C and SPI are mutually exclusive. Both are physically connected to PSC0.\
+			Refer to Pb1200/Db1200 documentation.
+#elif defined( CONFIG_AU1550_PSC_SPI )
+	bcsr->resets |= BCSR_RESETS_PCS0MUX;
+#elif defined( CONFIG_I2C_ALGO_AU1550 )
+	bcsr->resets &= (~BCSR_RESETS_PCS0MUX);
+#endif
+	au_sync();
+
+#ifdef CONFIG_MIPS_PB1200
+	printk("AMD Alchemy Pb1200 Board\n");
+#endif
+#ifdef CONFIG_MIPS_DB1200
+	printk("AMD Alchemy Db1200 Board\n");
+#endif
+#if 0
+	/* Setup Pb1200 External Interrupt Controller */
+	{
+		extern void (*board_init_irq)(void);
+		extern void _board_init_irq(void);
+		board_init_irq = _board_init_irq;
+	}
+#endif
+}
diff --git a/arch/mips/au1000/pb1200/init.c b/arch/mips/au1000/pb1200/init.c
new file mode 100644
index 0000000..27f09e3
--- /dev/null
+++ b/arch/mips/au1000/pb1200/init.c
@@ -0,0 +1,69 @@
+/*
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	PB1200 board setup
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+extern void  __init prom_init_cmdline(void);
+extern char *prom_getenv(char *envname);
+
+const char *get_system_type(void)
+{
+	return "Alchemy Pb1200";
+}
+
+void __init prom_init(void)
+{
+	unsigned char *memsize_str;
+	unsigned long memsize;
+
+	prom_argc = (int) fw_arg0;
+	prom_argv = (char **) fw_arg1;
+	prom_envp = (char **) fw_arg2;
+
+	mips_machgroup = MACH_GROUP_ALCHEMY;
+	mips_machtype = MACH_PB1200;
+
+	prom_init_cmdline();
+	memsize_str = prom_getenv("memsize");
+	if (!memsize_str) {
+		memsize = 0x08000000;
+	} else {
+		memsize = simple_strtol(memsize_str, NULL, 0);
+	}
+	add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c
new file mode 100644
index 0000000..2ec64e7
--- /dev/null
+++ b/arch/mips/au1000/pb1200/irqmap.c
@@ -0,0 +1,180 @@
+/*
+ * BRIEF MODULE DESCRIPTION
+ *	Au1xxx irq map table
+ *
+ *  This program is free software; you can redistribute	 it and/or modify it
+ *  under  the terms of	 the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the	License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
+ *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
+ *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#ifdef CONFIG_MIPS_PB1200
+#include <asm/mach-pb1x00/pb1200.h>
+#endif
+
+#ifdef CONFIG_MIPS_DB1200
+#include <asm/mach-db1x00/db1200.h>
+#define PB1200_INT_BEGIN DB1200_INT_BEGIN
+#define PB1200_INT_END DB1200_INT_END
+#endif
+
+au1xxx_irq_map_t au1xxx_irq_map[] = {
+	{ AU1000_GPIO_7, INTC_INT_LOW_LEVEL, 0 }, // This is exteranl interrupt cascade
+};
+
+int au1xxx_nr_irqs = sizeof(au1xxx_irq_map)/sizeof(au1xxx_irq_map_t);
+
+/*
+ *	Support for External interrupts on the PbAu1200 Development platform.
+ */
+static volatile int pb1200_cascade_en=0;
+
+void pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned short bisr = bcsr->int_status;
+	int extirq_nr = 0;
+
+	/* Clear all the edge interrupts. This has no effect on level */
+	bcsr->int_status = bisr;
+	for( ; bisr; bisr &= (bisr-1) )
+	{
+		extirq_nr = (PB1200_INT_BEGIN-1) + au_ffs(bisr);
+		/* Ack and dispatch IRQ */
+		do_IRQ(extirq_nr,regs);
+	}
+}
+
+inline void pb1200_enable_irq(unsigned int irq_nr)
+{
+	bcsr->intset_mask = 1<<(irq_nr - PB1200_INT_BEGIN);
+	bcsr->intset = 1<<(irq_nr - PB1200_INT_BEGIN);
+}
+
+inline void pb1200_disable_irq(unsigned int irq_nr)
+{
+	bcsr->intclr_mask = 1<<(irq_nr - PB1200_INT_BEGIN);
+	bcsr->intclr = 1<<(irq_nr - PB1200_INT_BEGIN);
+}
+
+static unsigned int pb1200_startup_irq( unsigned int irq_nr )
+{
+	if (++pb1200_cascade_en == 1)
+	{
+		request_irq(AU1000_GPIO_7, &pb1200_cascade_handler,
+			0, "Pb1200 Cascade", &pb1200_cascade_handler );
+#ifdef CONFIG_MIPS_PB1200
+    /* We have a problem with CPLD rev3. Enable a workaround */
+	if( ((bcsr->whoami & BCSR_WHOAMI_CPLD)>>4) <= 3)
+	{
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("Pb1200 must be at CPLD rev4. Please have Pb1200\n");
+		printk("updated to latest revision. This software will not\n");
+		printk("work on anything less than CPLD rev4\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		printk("\nWARNING!!!\n");
+		while(1);
+	}
+#endif
+	}
+	pb1200_enable_irq(irq_nr);
+	return 0;
+}
+
+static void pb1200_shutdown_irq( unsigned int irq_nr )
+{
+	pb1200_disable_irq(irq_nr);
+	if (--pb1200_cascade_en == 0)
+	{
+		free_irq(AU1000_GPIO_7,&pb1200_cascade_handler );
+	}
+	return;
+}
+
+static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr)
+{
+	pb1200_disable_irq( irq_nr );
+}
+
+static void pb1200_end_irq(unsigned int irq_nr)
+{
+	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
+		pb1200_enable_irq(irq_nr);
+	}
+}
+
+static struct hw_interrupt_type external_irq_type =
+{
+#ifdef CONFIG_MIPS_PB1200
+	"Pb1200 Ext",
+#endif
+#ifdef CONFIG_MIPS_DB1200
+	"Db1200 Ext",
+#endif
+	pb1200_startup_irq,
+	pb1200_shutdown_irq,
+	pb1200_enable_irq,
+	pb1200_disable_irq,
+	pb1200_mask_and_ack_irq,
+	pb1200_end_irq,
+	NULL
+};
+
+void _board_init_irq(void)
+{
+	int irq_nr;
+
+	for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++)
+	{
+		irq_desc[irq_nr].handler = &external_irq_type;
+		pb1200_disable_irq(irq_nr);
+	}
+
+	/* GPIO_7 can not be hooked here, so it is hooked upon first
+	request of any source attached to the cascade */
+}
+
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 7685f8b..66c2a27 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -116,6 +116,8 @@
 	case CPU_AU1000:
 	case CPU_AU1100:
 	case CPU_AU1500:
+	case CPU_AU1550:
+	case CPU_AU1200:
 		if (au1k_wait_ptr != NULL) {
 			cpu_wait = au1k_wait_ptr;
 			printk(" available.\n");
@@ -505,6 +507,9 @@
 		case 3:
 			c->cputype = CPU_AU1550;
 			break;
+		case 4:
+			c->cputype = CPU_AU1200;
+			break;
 		default:
 			panic("Unknown Au Core!");
 			break;
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 760fcdf..1388852 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -60,6 +60,9 @@
 	[CPU_TX3927]	"TX3927",
 	[CPU_AU1000]	"Au1000",
 	[CPU_AU1500]	"Au1500",
+	[CPU_AU1100]	"Au1100",
+	[CPU_AU1550]	"Au1550",
+	[CPU_AU1200]	"Au1200",
 	[CPU_4KEC]	"MIPS 4KEc",
 	[CPU_4KSC]	"MIPS 4KSc",
 	[CPU_VR41XX]	"NEC Vr41xx",
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 03100b8..e26dd82 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -1036,7 +1036,11 @@
 		c->icache.flags |= MIPS_CACHE_VTAG;
 		break;
 
+	case CPU_AU1000:
 	case CPU_AU1500:
+	case CPU_AU1100:
+	case CPU_AU1550:
+	case CPU_AU1200:
 		c->icache.flags |= MIPS_CACHE_IC_F_DC;
 		break;
 	}
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 6569be3..248537c 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -840,6 +840,7 @@
 	case CPU_AU1100:
 	case CPU_AU1500:
 	case CPU_AU1550:
+	case CPU_AU1200:
 		i_nop(p);
 		tlbw(p);
 		break;