malta: support for coreFPGA6 boards

This patch adds support for running on Malta boards using coreFPGA6
core cards, including support for the msc01 system controller used
with them. The system controller is detected at runtime allowing one
U-boot binary to run on a Malta with either.

Due to the PCI I/O base differing between Maltas using gt64120 & msc01
system controllers, the UART setup is modified slightly. A second UART
is added so that there is one pointing at the correct address for each
system controller. The Malta board then defines its own
default_serial_console function to select the correct one at runtime.
The incorrect UART will simply not function.

Tested on:
  - A coreFPGA6 Malta running interAptiv and proAptiv bitstreams, both
    with and without an L2 cache.
  - QEMU.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
diff --git a/arch/mips/include/asm/malta.h b/arch/mips/include/asm/malta.h
index d4d44a2..0b50a66 100644
--- a/arch/mips/include/asm/malta.h
+++ b/arch/mips/include/asm/malta.h
@@ -9,15 +9,38 @@
 #ifndef _MIPS_ASM_MALTA_H
 #define _MIPS_ASM_MALTA_H
 
-#define MALTA_IO_PORT_BASE	0x18000000
+#define MALTA_GT_BASE			0x1be00000
+#define MALTA_GT_PCIIO_BASE		0x18000000
+#define MALTA_GT_UART0_BASE		(MALTA_GT_PCIIO_BASE + 0x3f8)
 
-#define MALTA_UART_BASE		(MALTA_IO_PORT_BASE + 0x3f8)
+#define MALTA_MSC01_BIU_BASE		0x1bc80000
+#define MALTA_MSC01_PCI_BASE		0x1bd00000
+#define MALTA_MSC01_PBC_BASE		0x1bd40000
+#define MALTA_MSC01_IP1_BASE		0x1bc00000
+#define MALTA_MSC01_IP1_SIZE		0x00400000
+#define MALTA_MSC01_IP2_BASE1		0x10000000
+#define MALTA_MSC01_IP2_SIZE1		0x08000000
+#define MALTA_MSC01_IP2_BASE2		0x18000000
+#define MALTA_MSC01_IP2_SIZE2		0x04000000
+#define MALTA_MSC01_IP3_BASE		0x1c000000
+#define MALTA_MSC01_IP3_SIZE		0x04000000
+#define MALTA_MSC01_PCIMEM_BASE		0x10000000
+#define MALTA_MSC01_PCIMEM_SIZE		0x10000000
+#define MALTA_MSC01_PCIMEM_MAP		0x10000000
+#define MALTA_MSC01_PCIIO_BASE		0x1b000000
+#define MALTA_MSC01_PCIIO_SIZE		0x00800000
+#define MALTA_MSC01_PCIIO_MAP		0x00000000
+#define MALTA_MSC01_UART0_BASE		(MALTA_MSC01_PCIIO_BASE + 0x3f8)
 
-#define MALTA_GT_BASE		0x1be00000
+#define MALTA_RESET_BASE		0x1f000500
+#define GORESET				0x42
 
-#define MALTA_RESET_BASE	0x1f000500
-#define GORESET			0x42
+#define MALTA_FLASH_BASE		0x1fc00000
 
-#define MALTA_FLASH_BASE	0x1fc00000
+#define MALTA_REVISION			0x1fc00010
+#define MALTA_REVISION_CORID_SHF	10
+#define MALTA_REVISION_CORID_MSK	(0x3f << MALTA_REVISION_CORID_SHF)
+#define MALTA_REVISION_CORID_CORE_LV		1
+#define MALTA_REVISION_CORID_CORE_FPGA6		14
 
 #endif /* _MIPS_ASM_MALTA_H */
diff --git a/board/imgtec/malta/lowlevel_init.S b/board/imgtec/malta/lowlevel_init.S
index fa0b6a7..1af34f1 100644
--- a/board/imgtec/malta/lowlevel_init.S
+++ b/board/imgtec/malta/lowlevel_init.S
@@ -6,6 +6,8 @@
 
 #include <config.h>
 #include <gt64120.h>
+#include <msc01.h>
+#include <pci.h>
 
 #include <asm/addrspace.h>
 #include <asm/regdef.h>
@@ -25,6 +27,25 @@
 
 	.globl	lowlevel_init
 lowlevel_init:
+	/* detect the core card */
+	li	t0, KSEG1ADDR(MALTA_REVISION)
+	lw	t0, 0(t0)
+	srl	t0, t0, MALTA_REVISION_CORID_SHF
+	andi	t0, t0, (MALTA_REVISION_CORID_MSK >> \
+			 MALTA_REVISION_CORID_SHF)
+
+	/* core cards using the gt64120 system controller */
+	li	t1, MALTA_REVISION_CORID_CORE_LV
+	beq	t0, t1, _gt64120
+
+	/* core cards using the MSC01 system controller */
+	 li	t1, MALTA_REVISION_CORID_CORE_FPGA6
+	beq	t0, t1, _msc01
+	 nop
+
+	/* unknown system controller */
+	b	.
+	 nop
 
 	/*
 	 * Load BAR registers of GT64120 as done by YAMON
@@ -39,7 +60,7 @@
 	 * based on write_bootloader() in qemu.git/hw/mips_malta.c
 	 * see GT64120 manual and qemu.git/hw/gt64xxx.c for details
 	 */
-
+_gt64120:
 	/* move GT64120 registers from 0x14000000 to 0x1be00000 */
 	li	t1, KSEG1ADDR(GT_DEF_BASE)
 	li	t0, CPU_TO_GT32(0xdf000000)
@@ -67,3 +88,144 @@
 
 	jr	ra
 	 nop
+
+	/*
+	 *
+	 */
+_msc01:
+	/* setup peripheral bus controller clock divide */
+	li	t0, KSEG1ADDR(MALTA_MSC01_PBC_BASE)
+	li	t1, 0x1 << MSC01_PBC_CLKCFG_SHF
+	sw	t1, MSC01_PBC_CLKCFG_OFS(t0)
+
+	/* tweak peripheral bus controller timings */
+	li	t1, (0x1 << MSC01_PBC_CS0TIM_CDT_SHF) | \
+		    (0x1 << MSC01_PBC_CS0TIM_CAT_SHF)
+	sw	t1, MSC01_PBC_CS0TIM_OFS(t0)
+	li	t1, (0x0 << MSC01_PBC_CS0RW_RDT_SHF) | \
+		    (0x2 << MSC01_PBC_CS0RW_RAT_SHF) | \
+		    (0x0 << MSC01_PBC_CS0RW_WDT_SHF) | \
+		    (0x2 << MSC01_PBC_CS0RW_WAT_SHF)
+	sw	t1, MSC01_PBC_CS0RW_OFS(t0)
+	lw	t1, MSC01_PBC_CS0CFG_OFS(t0)
+	li	t2, MSC01_PBC_CS0CFG_DTYP_MSK
+	and	t1, t2
+	ori	t1, (0x0 << MSC01_PBC_CS0CFG_ADM_SHF) | \
+		    (0x3 << MSC01_PBC_CS0CFG_WSIDLE_SHF) | \
+		    (0x10 << MSC01_PBC_CS0CFG_WS_SHF)
+	sw	t1, MSC01_PBC_CS0CFG_OFS(t0)
+
+	/* setup basic address decode */
+	li	t0, KSEG1ADDR(MALTA_MSC01_BIU_BASE)
+	li	t1, 0x0
+	li	t2, -CONFIG_SYS_MEM_SIZE
+	sw	t1, MSC01_BIU_MCBAS1L_OFS(t0)
+	sw	t2, MSC01_BIU_MCMSK1L_OFS(t0)
+	sw	t1, MSC01_BIU_MCBAS2L_OFS(t0)
+	sw	t2, MSC01_BIU_MCMSK2L_OFS(t0)
+
+	/* initialise IP1 - unused */
+	li	t1, MALTA_MSC01_IP1_BASE
+	li	t2, -MALTA_MSC01_IP1_SIZE
+	sw	t1, MSC01_BIU_IP1BAS1L_OFS(t0)
+	sw	t2, MSC01_BIU_IP1MSK1L_OFS(t0)
+	sw	t1, MSC01_BIU_IP1BAS2L_OFS(t0)
+	sw	t2, MSC01_BIU_IP1MSK2L_OFS(t0)
+
+	/* initialise IP2 - PCI */
+	li	t1, MALTA_MSC01_IP2_BASE1
+	li	t2, -MALTA_MSC01_IP2_SIZE1
+	sw	t1, MSC01_BIU_IP2BAS1L_OFS(t0)
+	sw	t2, MSC01_BIU_IP2MSK1L_OFS(t0)
+	li	t1, MALTA_MSC01_IP2_BASE2
+	li	t2, -MALTA_MSC01_IP2_SIZE2
+	sw	t1, MSC01_BIU_IP2BAS2L_OFS(t0)
+	sw	t2, MSC01_BIU_IP2MSK2L_OFS(t0)
+
+	/* initialise IP3 - peripheral bus controller */
+	li	t1, MALTA_MSC01_IP3_BASE
+	li	t2, -MALTA_MSC01_IP3_SIZE
+	sw	t1, MSC01_BIU_IP3BAS1L_OFS(t0)
+	sw	t2, MSC01_BIU_IP3MSK1L_OFS(t0)
+	sw	t1, MSC01_BIU_IP3BAS2L_OFS(t0)
+	sw	t2, MSC01_BIU_IP3MSK2L_OFS(t0)
+
+	/* setup PCI memory */
+	li	t0, KSEG1ADDR(MALTA_MSC01_PCI_BASE)
+	li	t1, MALTA_MSC01_PCIMEM_BASE
+	li	t2, (-MALTA_MSC01_PCIMEM_SIZE) & MSC01_PCI_SC2PMMSKL_MSK_MSK
+	li	t3, MALTA_MSC01_PCIMEM_MAP
+	sw	t1, MSC01_PCI_SC2PMBASL_OFS(t0)
+	sw	t2, MSC01_PCI_SC2PMMSKL_OFS(t0)
+	sw	t3, MSC01_PCI_SC2PMMAPL_OFS(t0)
+
+	/* setup PCI I/O */
+	li	t1, MALTA_MSC01_PCIIO_BASE
+	li	t2, (-MALTA_MSC01_PCIIO_SIZE) & MSC01_PCI_SC2PIOMSKL_MSK_MSK
+	li	t3, MALTA_MSC01_PCIIO_MAP
+	sw	t1, MSC01_PCI_SC2PIOBASL_OFS(t0)
+	sw	t2, MSC01_PCI_SC2PIOMSKL_OFS(t0)
+	sw	t3, MSC01_PCI_SC2PIOMAPL_OFS(t0)
+
+	/* setup PCI_BAR0 memory window */
+	li	t1, -CONFIG_SYS_MEM_SIZE
+	sw	t1, MSC01_PCI_BAR0_OFS(t0)
+
+	/* setup PCI to SysCon/CPU translation */
+	sw	t1, MSC01_PCI_P2SCMSKL_OFS(t0)
+	sw	zero, MSC01_PCI_P2SCMAPL_OFS(t0)
+
+	/* setup PCI vendor & device IDs */
+	li	t1, (PCI_VENDOR_ID_MIPS << MSC01_PCI_HEAD0_VENDORID_SHF) | \
+		    (PCI_DEVICE_ID_MIPS_MSC01 << MSC01_PCI_HEAD0_DEVICEID_SHF)
+	sw	t1, MSC01_PCI_HEAD0_OFS(t0)
+
+	/* setup PCI subsystem vendor & device IDs */
+	sw	t1, MSC01_PCI_HEAD11_OFS(t0)
+
+	/* setup PCI class, revision */
+	li	t1, (PCI_CLASS_BRIDGE_HOST << MSC01_PCI_HEAD2_CLASS_SHF) | \
+		    (0x1 << MSC01_PCI_HEAD2_REV_SHF)
+	sw	t1, MSC01_PCI_HEAD2_OFS(t0)
+
+	/* ensure a sane setup */
+	sw	zero, MSC01_PCI_HEAD3_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD4_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD5_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD6_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD7_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD8_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD9_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD10_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD12_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD13_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD14_OFS(t0)
+	sw	zero, MSC01_PCI_HEAD15_OFS(t0)
+
+	/* setup PCI command register */
+	li	t1, (PCI_COMMAND_FAST_BACK | \
+		     PCI_COMMAND_SERR | \
+		     PCI_COMMAND_PARITY | \
+		     PCI_COMMAND_MASTER | \
+		     PCI_COMMAND_MEMORY)
+	sw	t1, MSC01_PCI_HEAD1_OFS(t0)
+
+	/* setup PCI byte swapping */
+#ifdef CONFIG_SYS_BIG_ENDIAN
+	li	t1, (0x1 << MSC01_PCI_SWAP_BAR0_BSWAP_SHF) | \
+		    (0x1 << MSC01_PCI_SWAP_IO_BSWAP_SHF)
+	sw	t1, MSC01_PCI_SWAP_OFS(t0)
+#else
+	sw	zero, MSC01_PCI_SWAP_OFS(t0)
+#endif
+
+	/* enable PCI host configuration cycles */
+	lw	t1, MSC01_PCI_CFG_OFS(t0)
+	li	t2, MSC01_PCI_CFG_RA_MSK | \
+		    MSC01_PCI_CFG_G_MSK | \
+		    MSC01_PCI_CFG_EN_MSK
+	or	t1, t1, t2
+	sw	t1, MSC01_PCI_CFG_OFS(t0)
+
+	jr	ra
+	 nop
diff --git a/board/imgtec/malta/malta.c b/board/imgtec/malta/malta.c
index 09da9ea..2af0067 100644
--- a/board/imgtec/malta/malta.c
+++ b/board/imgtec/malta/malta.c
@@ -1,19 +1,67 @@
 /*
  * Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2013 Imagination Technologies
  *
  * SPDX-License-Identifier:	GPL-2.0
  */
 
 #include <common.h>
 #include <netdev.h>
+#include <pci_gt64120.h>
+#include <pci_msc01.h>
+#include <serial.h>
 
 #include <asm/addrspace.h>
 #include <asm/io.h>
 #include <asm/malta.h>
-#include <pci_gt64120.h>
 
 #include "superio.h"
 
+enum core_card {
+	CORE_UNKNOWN,
+	CORE_LV,
+	CORE_FPGA6,
+};
+
+enum sys_con {
+	SYSCON_UNKNOWN,
+	SYSCON_GT64120,
+	SYSCON_MSC01,
+};
+
+static enum core_card malta_core_card(void)
+{
+	u32 corid, rev;
+
+	rev = __raw_readl(CKSEG1ADDR(MALTA_REVISION));
+	corid = (rev & MALTA_REVISION_CORID_MSK) >> MALTA_REVISION_CORID_SHF;
+
+	switch (corid) {
+	case MALTA_REVISION_CORID_CORE_LV:
+		return CORE_LV;
+
+	case MALTA_REVISION_CORID_CORE_FPGA6:
+		return CORE_FPGA6;
+
+	default:
+		return CORE_UNKNOWN;
+	}
+}
+
+static enum sys_con malta_sys_con(void)
+{
+	switch (malta_core_card()) {
+	case CORE_LV:
+		return SYSCON_GT64120;
+
+	case CORE_FPGA6:
+		return SYSCON_MSC01;
+
+	default:
+		return SYSCON_UNKNOWN;
+	}
+}
+
 phys_size_t initdram(int board_type)
 {
 	return CONFIG_SYS_MEM_SIZE;
@@ -21,7 +69,25 @@
 
 int checkboard(void)
 {
-	puts("Board: MIPS Malta CoreLV (Qemu)\n");
+	enum core_card core;
+
+	puts("Board: MIPS Malta");
+
+	core = malta_core_card();
+	switch (core) {
+	case CORE_LV:
+		puts(" CoreLV");
+		break;
+
+	case CORE_FPGA6:
+		puts(" CoreFPGA6");
+		break;
+
+	default:
+		puts(" CoreUnknown");
+	}
+
+	putc('\n');
 	return 0;
 }
 
@@ -40,18 +106,62 @@
 
 int board_early_init_f(void)
 {
+	void *io_base;
+
+	/* choose correct PCI I/O base */
+	switch (malta_sys_con()) {
+	case SYSCON_GT64120:
+		io_base = (void *)CKSEG1ADDR(MALTA_GT_PCIIO_BASE);
+		break;
+
+	case SYSCON_MSC01:
+		io_base = (void *)CKSEG1ADDR(MALTA_MSC01_PCIIO_BASE);
+		break;
+
+	default:
+		return -1;
+	}
+
 	/* setup FDC37M817 super I/O controller */
-	malta_superio_init((void *)CKSEG1ADDR(MALTA_IO_PORT_BASE));
+	malta_superio_init(io_base);
 
 	return 0;
 }
 
+struct serial_device *default_serial_console(void)
+{
+	switch (malta_sys_con()) {
+	case SYSCON_GT64120:
+		return &eserial1_device;
+
+	default:
+	case SYSCON_MSC01:
+		return &eserial2_device;
+	}
+}
+
 void pci_init_board(void)
 {
-	set_io_port_base(CKSEG1ADDR(MALTA_IO_PORT_BASE));
+	switch (malta_sys_con()) {
+	case SYSCON_GT64120:
+		set_io_port_base(CKSEG1ADDR(MALTA_GT_PCIIO_BASE));
 
-	gt64120_pci_init((void *)CKSEG1ADDR(MALTA_GT_BASE),
-			 0x00000000, 0x00000000, CONFIG_SYS_MEM_SIZE,
-			 0x10000000, 0x10000000, 128 * 1024 * 1024,
-			 0x00000000, 0x00000000, 0x20000);
+		gt64120_pci_init((void *)CKSEG1ADDR(MALTA_GT_BASE),
+				 0x00000000, 0x00000000, CONFIG_SYS_MEM_SIZE,
+				 0x10000000, 0x10000000, 128 * 1024 * 1024,
+				 0x00000000, 0x00000000, 0x20000);
+		break;
+
+	default:
+	case SYSCON_MSC01:
+		set_io_port_base(CKSEG1ADDR(MALTA_MSC01_PCIIO_BASE));
+
+		msc01_pci_init((void *)CKSEG1ADDR(MALTA_MSC01_PCI_BASE),
+			       0x00000000, 0x00000000, CONFIG_SYS_MEM_SIZE,
+			       MALTA_MSC01_PCIMEM_MAP,
+			       CKSEG1ADDR(MALTA_MSC01_PCIMEM_BASE),
+			       MALTA_MSC01_PCIMEM_SIZE, MALTA_MSC01_PCIIO_MAP,
+			       0x00000000, MALTA_MSC01_PCIIO_SIZE);
+		break;
+	}
 }
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 99d51a6..6182a59 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_PCI) += pci.o pci_auto.o
 obj-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
 obj-$(CONFIG_PCI_GT64120) += pci_gt64120.o
+obj-$(CONFIG_PCI_MSC01) += pci_msc01.o
 obj-$(CONFIG_FTPCI100) += pci_ftpci100.o
 obj-$(CONFIG_IXP_PCI) += pci_ixp.o
 obj-$(CONFIG_SH4_PCI) += pci_sh4.o
diff --git a/drivers/pci/pci_msc01.c b/drivers/pci/pci_msc01.c
new file mode 100644
index 0000000..284ffa0
--- /dev/null
+++ b/drivers/pci/pci_msc01.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <msc01.h>
+#include <pci.h>
+#include <pci_msc01.h>
+#include <asm/io.h>
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+struct msc01_pci_controller {
+	struct pci_controller hose;
+	void *base;
+};
+
+static inline struct msc01_pci_controller *
+hose_to_msc01(struct pci_controller *hose)
+{
+	return container_of(hose, struct msc01_pci_controller, hose);
+}
+
+static int msc01_config_access(struct msc01_pci_controller *msc01,
+			       unsigned char access_type, pci_dev_t bdf,
+			       int where, u32 *data)
+{
+	const u32 aborts = MSC01_PCI_INTSTAT_MA_MSK | MSC01_PCI_INTSTAT_TA_MSK;
+	void *intstat = msc01->base + MSC01_PCI_INTSTAT_OFS;
+	void *cfgdata = msc01->base + MSC01_PCI_CFGDATA_OFS;
+	unsigned int bus = PCI_BUS(bdf);
+	unsigned int dev = PCI_DEV(bdf);
+	unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf);
+
+	/* clear abort status */
+	__raw_writel(aborts, intstat);
+
+	/* setup address */
+	__raw_writel((bus << MSC01_PCI_CFGADDR_BNUM_SHF) |
+		     (dev << MSC01_PCI_CFGADDR_DNUM_SHF) |
+		     (devfn << MSC01_PCI_CFGADDR_FNUM_SHF) |
+		     ((where / 4) << MSC01_PCI_CFGADDR_RNUM_SHF),
+		     msc01->base + MSC01_PCI_CFGADDR_OFS);
+
+	/* perform access */
+	if (access_type == PCI_ACCESS_WRITE)
+		__raw_writel(*data, cfgdata);
+	else
+		*data = __raw_readl(cfgdata);
+
+	/* check for aborts */
+	if (__raw_readl(intstat) & aborts) {
+		/* clear abort status */
+		__raw_writel(aborts, intstat);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int msc01_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
+				   int where, u32 *value)
+{
+	struct msc01_pci_controller *msc01 = hose_to_msc01(hose);
+
+	*value = 0xffffffff;
+	return msc01_config_access(msc01, PCI_ACCESS_READ, dev, where, value);
+}
+
+static int msc01_write_config_dword(struct pci_controller *hose, pci_dev_t dev,
+				    int where, u32 value)
+{
+	struct msc01_pci_controller *gt = hose_to_msc01(hose);
+	u32 data = value;
+
+	return msc01_config_access(gt, PCI_ACCESS_WRITE, dev, where, &data);
+}
+
+void msc01_pci_init(void *base, unsigned long sys_bus, unsigned long sys_phys,
+		    unsigned long sys_size, unsigned long mem_bus,
+		    unsigned long mem_phys, unsigned long mem_size,
+		    unsigned long io_bus, unsigned long io_phys,
+		    unsigned long io_size)
+{
+	static struct msc01_pci_controller global_msc01;
+	struct msc01_pci_controller *msc01;
+	struct pci_controller *hose;
+
+	msc01 = &global_msc01;
+	msc01->base = base;
+
+	hose = &msc01->hose;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0;
+
+	/* System memory space */
+	pci_set_region(&hose->regions[0], sys_bus, sys_phys, sys_size,
+		       PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+	/* PCI memory space */
+	pci_set_region(&hose->regions[1], mem_bus, mem_phys, mem_size,
+		       PCI_REGION_MEM);
+
+	/* PCI I/O space */
+	pci_set_region(&hose->regions[2], io_bus, io_phys, io_size,
+		       PCI_REGION_IO);
+
+	hose->region_count = 3;
+
+	pci_set_ops(hose,
+		    pci_hose_read_config_byte_via_dword,
+		    pci_hose_read_config_word_via_dword,
+		    msc01_read_config_dword,
+		    pci_hose_write_config_byte_via_dword,
+		    pci_hose_write_config_word_via_dword,
+		    msc01_write_config_dword);
+
+	pci_register_hose(hose);
+	hose->last_busno = pci_hose_scan(hose);
+}
diff --git a/include/configs/malta.h b/include/configs/malta.h
index d067d98..5e322f6 100644
--- a/include/configs/malta.h
+++ b/include/configs/malta.h
@@ -17,6 +17,7 @@
 
 #define CONFIG_PCI
 #define CONFIG_PCI_GT64120
+#define CONFIG_PCI_MSC01
 #define CONFIG_PCI_PNP
 #define CONFIG_PCNET
 
@@ -76,7 +77,8 @@
 #define CONFIG_SYS_NS16550_SERIAL
 #define CONFIG_SYS_NS16550_REG_SIZE	1
 #define CONFIG_SYS_NS16550_CLK		115200
-#define CONFIG_SYS_NS16550_COM1		CKSEG1ADDR(MALTA_UART_BASE)
+#define CONFIG_SYS_NS16550_COM1		CKSEG1ADDR(MALTA_GT_UART0_BASE)
+#define CONFIG_SYS_NS16550_COM2		CKSEG1ADDR(MALTA_MSC01_UART0_BASE)
 #define CONFIG_CONS_INDEX		1
 
 /*
diff --git a/include/msc01.h b/include/msc01.h
new file mode 100644
index 0000000..37cf963
--- /dev/null
+++ b/include/msc01.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __MSC01_H__
+#define __MSC01_H__
+
+/*
+ * Bus Interface Unit
+ */
+
+#define MSC01_BIU_IP1BAS1L_OFS		0x0208
+#define MSC01_BIU_IP1MSK1L_OFS		0x0218
+#define MSC01_BIU_IP1BAS2L_OFS		0x0248
+#define MSC01_BIU_IP1MSK2L_OFS		0x0258
+#define MSC01_BIU_IP2BAS1L_OFS		0x0288
+#define MSC01_BIU_IP2MSK1L_OFS		0x0298
+#define MSC01_BIU_IP2BAS2L_OFS		0x02c8
+#define MSC01_BIU_IP2MSK2L_OFS		0x02d8
+#define MSC01_BIU_IP3BAS1L_OFS		0x0308
+#define MSC01_BIU_IP3MSK1L_OFS		0x0318
+#define MSC01_BIU_IP3BAS2L_OFS		0x0348
+#define MSC01_BIU_IP3MSK2L_OFS		0x0358
+#define MSC01_BIU_MCBAS1L_OFS		0x0388
+#define MSC01_BIU_MCMSK1L_OFS		0x0398
+#define MSC01_BIU_MCBAS2L_OFS		0x03c8
+#define MSC01_BIU_MCMSK2L_OFS		0x03d8
+
+/*
+ * PCI Bridge
+ */
+
+#define MSC01_PCI_SC2PMBASL_OFS		0x0208
+#define MSC01_PCI_SC2PMMSKL_OFS		0x0218
+#define MSC01_PCI_SC2PMMAPL_OFS		0x0228
+#define MSC01_PCI_SC2PIOBASL_OFS	0x0248
+#define MSC01_PCI_SC2PIOMSKL_OFS	0x0258
+#define MSC01_PCI_SC2PIOMAPL_OFS	0x0268
+#define MSC01_PCI_P2SCMSKL_OFS		0x0308
+#define MSC01_PCI_P2SCMAPL_OFS		0x0318
+#define MSC01_PCI_INTSTAT_OFS		0x0608
+#define MSC01_PCI_CFGADDR_OFS		0x0610
+#define MSC01_PCI_CFGDATA_OFS		0x0618
+#define MSC01_PCI_HEAD0_OFS		0x2000
+#define MSC01_PCI_HEAD1_OFS		0x2008
+#define MSC01_PCI_HEAD2_OFS		0x2010
+#define MSC01_PCI_HEAD3_OFS		0x2018
+#define MSC01_PCI_HEAD4_OFS		0x2020
+#define MSC01_PCI_HEAD5_OFS		0x2028
+#define MSC01_PCI_HEAD6_OFS		0x2030
+#define MSC01_PCI_HEAD7_OFS		0x2038
+#define MSC01_PCI_HEAD8_OFS		0x2040
+#define MSC01_PCI_HEAD9_OFS		0x2048
+#define MSC01_PCI_HEAD10_OFS		0x2050
+#define MSC01_PCI_HEAD11_OFS		0x2058
+#define MSC01_PCI_HEAD12_OFS		0x2060
+#define MSC01_PCI_HEAD13_OFS		0x2068
+#define MSC01_PCI_HEAD14_OFS		0x2070
+#define MSC01_PCI_HEAD15_OFS		0x2078
+#define MSC01_PCI_BAR0_OFS		0x2220
+#define MSC01_PCI_CFG_OFS		0x2380
+#define MSC01_PCI_SWAP_OFS		0x2388
+
+#define MSC01_PCI_SC2PMMSKL_MSK_MSK	0xff000000
+#define MSC01_PCI_SC2PIOMSKL_MSK_MSK	0xff000000
+
+#define MSC01_PCI_INTSTAT_TA_SHF	6
+#define MSC01_PCI_INTSTAT_TA_MSK	(0x1 << MSC01_PCI_INTSTAT_TA_SHF)
+#define MSC01_PCI_INTSTAT_MA_SHF	7
+#define MSC01_PCI_INTSTAT_MA_MSK	(0x1 << MSC01_PCI_INTSTAT_MA_SHF)
+
+#define MSC01_PCI_CFGADDR_BNUM_SHF	16
+#define MSC01_PCI_CFGADDR_BNUM_MSK	(0xff << MSC01_PCI_CFGADDR_BNUM_SHF)
+#define MSC01_PCI_CFGADDR_DNUM_SHF	11
+#define MSC01_PCI_CFGADDR_DNUM_MSK	(0x1f << MSC01_PCI_CFGADDR_DNUM_SHF)
+#define MSC01_PCI_CFGADDR_FNUM_SHF	8
+#define MSC01_PCI_CFGADDR_FNUM_MSK	(0x3 << MSC01_PCI_CFGADDR_FNUM_SHF)
+#define MSC01_PCI_CFGADDR_RNUM_SHF	2
+#define MSC01_PCI_CFGADDR_RNUM_MSK	(0x3f << MSC01_PCI_CFGADDR_RNUM_SHF)
+
+#define MSC01_PCI_HEAD0_VENDORID_SHF	0
+#define MSC01_PCI_HEAD0_DEVICEID_SHF	16
+
+#define MSC01_PCI_HEAD2_REV_SHF		0
+#define MSC01_PCI_HEAD2_CLASS_SHF	16
+
+#define MSC01_PCI_CFG_EN_SHF		15
+#define MSC01_PCI_CFG_EN_MSK		(0x1 << MSC01_PCI_CFG_EN_SHF)
+#define MSC01_PCI_CFG_G_SHF		16
+#define MSC01_PCI_CFG_G_MSK		(0x1 << MSC01_PCI_CFG_G_SHF)
+#define MSC01_PCI_CFG_RA_SHF		17
+#define MSC01_PCI_CFG_RA_MSK		(0x1 << MSC01_PCI_CFG_RA_SHF)
+
+#define MSC01_PCI_SWAP_BAR0_BSWAP_SHF	0
+#define MSC01_PCI_SWAP_IO_BSWAP_SHF	18
+
+/*
+ * Peripheral Bus Controller
+ */
+
+#define MSC01_PBC_CLKCFG_OFS		0x0100
+#define MSC01_PBC_CS0CFG_OFS		0x0400
+#define MSC01_PBC_CS0TIM_OFS		0x0500
+#define MSC01_PBC_CS0RW_OFS		0x0600
+
+#define MSC01_PBC_CLKCFG_SHF		0
+#define MSC01_PBC_CLKCFG_MSK		(0x1f << MSC01_PBC_CLKCFG_SHF)
+
+#define MSC01_PBC_CS0CFG_WS_SHF		0
+#define MSC01_PBC_CS0CFG_WS_MSK		(0x1f << MSC01_PBC_CS0CFG_WS_SHF)
+#define MSC01_PBC_CS0CFG_WSIDLE_SHF	8
+#define MSC01_PBC_CS0CFG_WSIDLE_MSK	(0x1f << MSC01_PBC_CS0CFG_WSIDLE_SHF)
+#define MSC01_PBC_CS0CFG_DTYP_SHF	16
+#define MSC01_PBC_CS0CFG_DTYP_MSK	(0x3 << MSC01_PBC_CS0CFG_DTYP_SHF)
+#define MSC01_PBC_CS0CFG_ADM_SHF	20
+#define MSC01_PBC_CS0CFG_ADM_MSK	(0x1 << MSC01_PBC_CS0CFG_ADM_SHF)
+
+#define MSC01_PBC_CS0TIM_CAT_SHF	0
+#define MSC01_PBC_CS0TIM_CAT_MSK	(0x1f << MSC01_PBC_CS0TIM_CAT_SHF)
+#define MSC01_PBC_CS0TIM_CDT_SHF	8
+#define MSC01_PBC_CS0TIM_CDT_MSK	(0x1f << MSC01_PBC_CS0TIM_CDT_SHF)
+
+#define MSC01_PBC_CS0RW_WAT_SHF		0
+#define MSC01_PBC_CS0RW_WAT_MSK		(0x1f << MSC01_PBC_CS0RW_WAT_SHF)
+#define MSC01_PBC_CS0RW_WDT_SHF		8
+#define MSC01_PBC_CS0RW_WDT_MSK		(0x1f << MSC01_PBC_CS0RW_WDT_SHF)
+#define MSC01_PBC_CS0RW_RAT_SHF		16
+#define MSC01_PBC_CS0RW_RAT_MSK		(0x1f << MSC01_PBC_CS0RW_RAT_SHF)
+#define MSC01_PBC_CS0RW_RDT_SHF		24
+#define MSC01_PBC_CS0RW_RDT_MSK		(0x1f << MSC01_PBC_CS0RW_RDT_SHF)
+
+#endif /* __MSC01_H__ */
diff --git a/include/pci_ids.h b/include/pci_ids.h
index 2c6dfd4..6bab677 100644
--- a/include/pci_ids.h
+++ b/include/pci_ids.h
@@ -2170,6 +2170,9 @@
 #define PCI_DEVICE_ID_ENE_720		0x1421
 #define PCI_DEVICE_ID_ENE_722		0x1422
 
+#define PCI_VENDOR_ID_MIPS		0x153f
+#define PCI_DEVICE_ID_MIPS_MSC01	0x0001
+
 #define PCI_SUBVENDOR_ID_PERLE          0x155f
 #define PCI_SUBDEVICE_ID_PCI_RAS4       0xf001
 #define PCI_SUBDEVICE_ID_PCI_RAS8       0xf010
diff --git a/include/pci_msc01.h b/include/pci_msc01.h
new file mode 100644
index 0000000..54945a7
--- /dev/null
+++ b/include/pci_msc01.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __PCI_MSC01_H__
+#define __PCI_MSC01_H__
+
+extern void msc01_pci_init(void *base, unsigned long sys_bus,
+			   unsigned long sys_phys, unsigned long sys_size,
+			   unsigned long mem_bus, unsigned long mem_phys,
+			   unsigned long mem_size, unsigned long io_bus,
+			   unsigned long io_phys, unsigned long io_size);
+
+#endif /* __PCI_MSC01_H__ */