From 373bbe25ffaa3b5e75d1edefe47d26eaf9ae4242 Mon Sep 17 00:00:00 2001
From: Rafal Jaworowski <raj@FreeBSD.org>
Date: Mon, 13 Oct 2008 20:07:13 +0000
Subject: [PATCH] Introduce basic support for Marvell families of
 system-on-chip ARM devices:

  *  Orion
     - 88F5181
     - 88F5182
     - 88F5281

  * Kirkwood
     - 88F6281

  * Discovery
     - MV78100

The above families of SOCs are built around CPU cores compliant with ARMv5TE
instruction set architecture definition. They share a number of integrated
peripherals. This commit brings support for the following basic elements:

  * GPIO
  * Interrupt controller
  * L1, L2 cache
  * Timers, watchdog, RTC
  * TWSI (I2C)
  * UART

Other peripherals drivers will be introduced separately.

Reviewed by:	imp, marcel, stass (Thanks guys!)
Obtained from:	Marvell, Semihalf
---
 sys/arm/arm/elf_trampoline.c        |   2 +
 sys/arm/include/intr.h              |   4 +-
 sys/arm/include/resource.h          |   1 +
 sys/arm/mv/bus_space.c              | 162 +++++
 sys/arm/mv/common.c                 | 965 ++++++++++++++++++++++++++++
 sys/arm/mv/discovery/db78xxx.c      | 110 ++++
 sys/arm/mv/discovery/discovery.c    | 160 +++++
 sys/arm/mv/discovery/files.db78xxx  |   4 +
 sys/arm/mv/discovery/std.db78xxx    |  13 +
 sys/arm/mv/files.mv                 |  34 +
 sys/arm/mv/gpio.c                   | 516 +++++++++++++++
 sys/arm/mv/ic.c                     | 289 +++++++++
 sys/arm/mv/kirkwood/db88f6xxx.c     | 124 ++++
 sys/arm/mv/kirkwood/files.db88f6xxx |   5 +
 sys/arm/mv/kirkwood/kirkwood.c      | 161 +++++
 sys/arm/mv/kirkwood/std.db88f6xxx   |  13 +
 sys/arm/mv/mv_machdep.c             | 643 ++++++++++++++++++
 sys/arm/mv/mvreg.h                  | 540 ++++++++++++++++
 sys/arm/mv/mvvar.h                  | 122 ++++
 sys/arm/mv/obio.c                   | 355 ++++++++++
 sys/arm/mv/orion/db88f5xxx.c        | 177 +++++
 sys/arm/mv/orion/files.db88f5xxx    |   4 +
 sys/arm/mv/orion/orion.c            | 189 ++++++
 sys/arm/mv/orion/std.db88f5xxx      |  13 +
 sys/arm/mv/rtc.c                    | 184 ++++++
 sys/arm/mv/std.mv                   |   5 +
 sys/arm/mv/timer.c                  | 381 +++++++++++
 sys/arm/mv/twsi.c                   | 523 +++++++++++++++
 sys/conf/Makefile.arm               |   3 +-
 sys/conf/options.arm                |   4 +
 sys/dev/uart/uart_bus_mbus.c        |  81 +++
 sys/dev/uart/uart_cpu_mv.c          |  90 +++
 32 files changed, 5875 insertions(+), 2 deletions(-)
 create mode 100644 sys/arm/mv/bus_space.c
 create mode 100644 sys/arm/mv/common.c
 create mode 100644 sys/arm/mv/discovery/db78xxx.c
 create mode 100644 sys/arm/mv/discovery/discovery.c
 create mode 100644 sys/arm/mv/discovery/files.db78xxx
 create mode 100644 sys/arm/mv/discovery/std.db78xxx
 create mode 100644 sys/arm/mv/files.mv
 create mode 100644 sys/arm/mv/gpio.c
 create mode 100644 sys/arm/mv/ic.c
 create mode 100644 sys/arm/mv/kirkwood/db88f6xxx.c
 create mode 100644 sys/arm/mv/kirkwood/files.db88f6xxx
 create mode 100644 sys/arm/mv/kirkwood/kirkwood.c
 create mode 100644 sys/arm/mv/kirkwood/std.db88f6xxx
 create mode 100644 sys/arm/mv/mv_machdep.c
 create mode 100644 sys/arm/mv/mvreg.h
 create mode 100644 sys/arm/mv/mvvar.h
 create mode 100644 sys/arm/mv/obio.c
 create mode 100644 sys/arm/mv/orion/db88f5xxx.c
 create mode 100644 sys/arm/mv/orion/files.db88f5xxx
 create mode 100644 sys/arm/mv/orion/orion.c
 create mode 100644 sys/arm/mv/orion/std.db88f5xxx
 create mode 100644 sys/arm/mv/rtc.c
 create mode 100644 sys/arm/mv/std.mv
 create mode 100644 sys/arm/mv/timer.c
 create mode 100644 sys/arm/mv/twsi.c
 create mode 100644 sys/dev/uart/uart_bus_mbus.c
 create mode 100644 sys/dev/uart/uart_cpu_mv.c

diff --git a/sys/arm/arm/elf_trampoline.c b/sys/arm/arm/elf_trampoline.c
index 99025465d476..98e76fe7744d 100644
--- a/sys/arm/arm/elf_trampoline.c
+++ b/sys/arm/arm/elf_trampoline.c
@@ -73,6 +73,8 @@ void __startC(void);
 #endif
 #ifdef CPU_XSCALE_81342
 #define cpu_l2cache_wbinv_all	xscalec3_l2cache_purge
+#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
+#define cpu_l2cache_wbinv_all	feroceon_l2cache_wbinv_all
 #else
 #define cpu_l2cache_wbinv_all()	
 #endif
diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h
index bf2bf6d6a54f..d75f14ed02a2 100644
--- a/sys/arm/include/intr.h
+++ b/sys/arm/include/intr.h
@@ -44,7 +44,9 @@
 #elif defined(CPU_XSCALE_PXA2X0)
 #include <arm/xscale/pxa/pxareg.h>
 #define	NIRQ		IRQ_GPIO_MAX
-#elif defined(CPU_ARM9)
+#elif defined(SOC_MV_DISCOVERY)
+#define NIRQ		96
+#elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD)
 #define NIRQ		64
 #else
 #define NIRQ		32
diff --git a/sys/arm/include/resource.h b/sys/arm/include/resource.h
index 229d14f253b0..90dd5cdea2da 100644
--- a/sys/arm/include/resource.h
+++ b/sys/arm/include/resource.h
@@ -41,5 +41,6 @@
 #define	SYS_RES_DRQ	2	/* isa dma lines */
 #define	SYS_RES_MEMORY	3	/* i/o memory */
 #define	SYS_RES_IOPORT	4	/* i/o ports */
+#define	SYS_RES_GPIO	5	/* general purpose i/o */
 
 #endif /* !_MACHINE_RESOURCE_H_ */
diff --git a/sys/arm/mv/bus_space.c b/sys/arm/mv/bus_space.c
new file mode 100644
index 000000000000..2cdc454d4700
--- /dev/null
+++ b/sys/arm/mv/bus_space.c
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+/*
+ * Bus space functions for Marvell SoC family
+ */
+
+/* Prototypes for all the bus_space structure functions */
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+/*
+ * The obio bus space tag.  This is constant for all instances, so
+ * we never have to explicitly "create" it.
+ */
+static struct bus_space _base_tag = {
+	/* cookie */
+	(void *) 0,
+
+	/* mapping/unmapping */
+	generic_bs_map,
+	generic_bs_unmap,
+	generic_bs_subregion,
+
+	/* allocation/deallocation */
+	generic_bs_alloc,
+	generic_bs_free,
+
+	/* barrier */
+	generic_bs_barrier,
+
+	/* read (single) */
+	generic_bs_r_1,
+	generic_armv4_bs_r_2,
+	generic_bs_r_4,
+	NULL,
+
+	/* read multiple */
+	generic_bs_rm_1,
+	generic_armv4_bs_rm_2,
+	generic_bs_rm_4,
+	NULL,
+
+	/* read region */
+	generic_bs_rr_1,
+	generic_armv4_bs_rr_2,
+	generic_bs_rr_4,
+	NULL,
+
+	/* write (single) */
+	generic_bs_w_1,
+	generic_armv4_bs_w_2,
+	generic_bs_w_4,
+	NULL,
+
+	/* write multiple */
+	generic_bs_wm_1,
+	generic_armv4_bs_wm_2,
+	generic_bs_wm_4,
+	NULL,
+
+	/* write region */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* set multiple */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* set region */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* copy */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* read stream (single) */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* read multiple stream */
+	NULL,
+	generic_armv4_bs_rm_2,		/* bus_space_read_multi_stream_2 */
+	NULL,
+	NULL,
+
+	/* read region stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* write stream (single) */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* write multiple stream */
+	NULL,
+	generic_armv4_bs_wm_2,		/* bus_space_write_multi_stream_2 */
+	NULL,
+	NULL,
+
+	/* write region stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+bus_space_tag_t obio_tag = &_base_tag;
diff --git a/sys/arm/mv/common.c b/sys/arm/mv/common.c
new file mode 100644
index 000000000000..5489874ba8f9
--- /dev/null
+++ b/sys/arm/mv/common.c
@@ -0,0 +1,965 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+static int win_eth_can_remap(int i);
+
+static int decode_win_cpu_valid(void);
+static int decode_win_usb_valid(void);
+static int decode_win_eth_valid(void);
+static int decode_win_pcie_valid(void);
+
+static void decode_win_cpu_setup(void);
+static void decode_win_usb_setup(uint32_t ctrl);
+static void decode_win_eth_setup(uint32_t base);
+static void decode_win_pcie_setup(uint32_t base);
+
+static uint32_t dev, rev;
+
+uint32_t
+read_cpu_ctrl(uint32_t reg)
+{
+
+	return (bus_space_read_4(obio_tag, MV_CPU_CONTROL_BASE, reg));
+}
+
+void
+write_cpu_ctrl(uint32_t reg, uint32_t val)
+{
+
+	bus_space_write_4(obio_tag, MV_CPU_CONTROL_BASE, reg, val);
+}
+
+void
+cpu_reset(void)
+{
+
+	write_cpu_ctrl(RSTOUTn_MASK, SOFT_RST_OUT_EN);
+	write_cpu_ctrl(SYSTEM_SOFT_RESET, SYS_SOFT_RST);
+	while (1);
+}
+
+uint32_t
+cpu_extra_feat(void)
+{
+	uint32_t ef = 0;
+
+	soc_id(&dev, &rev);
+	if (dev == MV_DEV_88F6281 || dev == MV_DEV_MV78100)
+		__asm __volatile("mrc p15, 1, %0, c15, c1, 0" : "=r" (ef));
+	else if (dev == MV_DEV_88F5182 || dev == MV_DEV_88F5281)
+		__asm __volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (ef));
+	else if (bootverbose)
+		printf("This ARM Core does not support any extra features\n");
+
+	return (ef);
+}
+
+uint32_t
+soc_power_ctrl_get(uint32_t mask)
+{
+
+	if (mask != CPU_PM_CTRL_NONE)
+		mask &= read_cpu_ctrl(CPU_PM_CTRL);
+
+	return (mask);
+}
+
+uint32_t
+get_tclk(void)
+{
+
+#if defined(SOC_MV_DISCOVERY)
+	return (TCLK_200MHZ);
+#else
+	return (TCLK_166MHZ);
+#endif
+}
+
+void
+soc_id(uint32_t *dev, uint32_t *rev)
+{
+
+	/*
+	 * Notice: system identifiers are available in the registers range of
+	 * PCIE controller, so using this function is only allowed (and
+	 * possible) after the internal registers range has been mapped in via
+	 * pmap_devmap_bootstrap().
+	 */
+	*dev = bus_space_read_4(obio_tag, MV_PCIE_BASE, 0) >> 16;
+	*rev = bus_space_read_4(obio_tag, MV_PCIE_BASE, 8) & 0xff;
+}
+
+void
+soc_identify(void)
+{
+	uint32_t d, r;
+	const char *dev;
+	const char *rev;
+
+	soc_id(&d, &r);
+
+	printf("SOC: ");
+	if (bootverbose)
+		printf("(0x%4x:0x%02x) ", d, r);
+
+	rev = "";
+	switch (d) {
+	case MV_DEV_88F5181:
+		dev = "Marvell 88F5181";
+		if (r == 3)
+			rev = "B1";
+		break;
+	case MV_DEV_88F5182:
+		dev = "Marvell 88F5182";
+		if (r == 2)
+			rev = "A2";
+		break;
+	case MV_DEV_88F5281:
+		dev = "Marvell 88F5281";
+		if (r == 4)
+			rev = "D0";
+		else if (r == 5)
+			rev = "D1";
+		else if (r == 6)
+			rev = "D2";
+		break;
+	case MV_DEV_88F6281:
+		dev = "Marvell 88F6281";
+		break;
+	case MV_DEV_MV78100:
+		dev = "Marvell MV78100";
+		break;
+	default:
+		dev = "UNKNOWN";
+		break;
+	}
+
+	printf("%s", dev);
+	if (*rev != '\0')
+		printf(" rev %s", rev);
+	printf(", TClock %dMHz\n", get_tclk() / 1000 / 1000);
+
+	/* TODO add info on currently set endianess */
+}
+
+int
+soc_decode_win(void)
+{
+
+	/* Retrieve our ID: some windows facilities vary between SoC models */
+	soc_id(&dev, &rev);
+
+	if (decode_win_cpu_valid() != 1 || decode_win_usb_valid() != 1 ||
+	    decode_win_eth_valid() != 1 || decode_win_idma_valid() != 1 ||
+	    decode_win_pcie_valid() != 1)
+		return(-1);
+
+	decode_win_cpu_setup();
+	decode_win_usb_setup(MV_USB0_BASE);
+	decode_win_eth_setup(MV_ETH0_BASE);
+	if (dev == MV_DEV_MV78100)
+		decode_win_eth_setup(MV_ETH1_BASE);
+	decode_win_idma_setup();
+	decode_win_pcie_setup(MV_PCIE_BASE);
+
+	/* TODO set up decode wins for SATA */
+
+	return (0);
+}
+
+/**************************************************************************
+ * Decode windows registers accessors
+ **************************************************************************/
+WIN_REG_IDX_RD(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE)
+WIN_REG_IDX_RD(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE)
+WIN_REG_IDX_RD(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE)
+WIN_REG_IDX_RD(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE)
+WIN_REG_IDX_WR(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE)
+WIN_REG_IDX_WR(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE)
+WIN_REG_IDX_WR(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE)
+WIN_REG_IDX_WR(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE)
+
+WIN_REG_IDX_RD(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE)
+WIN_REG_IDX_RD(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE)
+
+WIN_REG_IDX_RD(win_usb, cr, MV_WIN_USB_CTRL, MV_USB_AWR_BASE)
+WIN_REG_IDX_RD(win_usb, br, MV_WIN_USB_BASE, MV_USB_AWR_BASE)
+WIN_REG_IDX_WR(win_usb, cr, MV_WIN_USB_CTRL, MV_USB_AWR_BASE)
+WIN_REG_IDX_WR(win_usb, br, MV_WIN_USB_BASE, MV_USB_AWR_BASE)
+
+WIN_REG_BASE_IDX_RD(win_eth, br, MV_WIN_ETH_BASE)
+WIN_REG_BASE_IDX_RD(win_eth, sz, MV_WIN_ETH_SIZE)
+WIN_REG_BASE_IDX_RD(win_eth, har, MV_WIN_ETH_REMAP)
+WIN_REG_BASE_IDX_WR(win_eth, br, MV_WIN_ETH_BASE)
+WIN_REG_BASE_IDX_WR(win_eth, sz, MV_WIN_ETH_SIZE)
+WIN_REG_BASE_IDX_WR(win_eth, har, MV_WIN_ETH_REMAP)
+WIN_REG_BASE_RD(win_eth, bare, 0x290)
+WIN_REG_BASE_RD(win_eth, epap, 0x294)
+WIN_REG_BASE_WR(win_eth, bare, 0x290)
+WIN_REG_BASE_WR(win_eth, epap, 0x294)
+
+WIN_REG_BASE_IDX_RD(win_pcie, cr, MV_WIN_PCIE_CTRL);
+WIN_REG_BASE_IDX_RD(win_pcie, br, MV_WIN_PCIE_BASE);
+WIN_REG_BASE_IDX_RD(win_pcie, remap, MV_WIN_PCIE_REMAP);
+WIN_REG_BASE_IDX_WR(win_pcie, cr, MV_WIN_PCIE_CTRL);
+WIN_REG_BASE_IDX_WR(win_pcie, br, MV_WIN_PCIE_BASE);
+WIN_REG_BASE_IDX_WR(win_pcie, remap, MV_WIN_PCIE_REMAP);
+WIN_REG_BASE_IDX_WR(pcie, bar, MV_PCIE_BAR);
+
+WIN_REG_IDX_RD(win_idma, br, MV_WIN_IDMA_BASE, MV_IDMA_BASE)
+WIN_REG_IDX_RD(win_idma, sz, MV_WIN_IDMA_SIZE, MV_IDMA_BASE)
+WIN_REG_IDX_RD(win_idma, har, MV_WIN_IDMA_REMAP, MV_IDMA_BASE)
+WIN_REG_IDX_RD(win_idma, cap, MV_WIN_IDMA_CAP, MV_IDMA_BASE)
+WIN_REG_IDX_WR(win_idma, br, MV_WIN_IDMA_BASE, MV_IDMA_BASE)
+WIN_REG_IDX_WR(win_idma, sz, MV_WIN_IDMA_SIZE, MV_IDMA_BASE)
+WIN_REG_IDX_WR(win_idma, har, MV_WIN_IDMA_REMAP, MV_IDMA_BASE)
+WIN_REG_IDX_WR(win_idma, cap, MV_WIN_IDMA_CAP, MV_IDMA_BASE)
+WIN_REG_RD(win_idma, bare, 0xa80, MV_IDMA_BASE)
+WIN_REG_WR(win_idma, bare, 0xa80, MV_IDMA_BASE)
+
+/**************************************************************************
+ * Decode windows helper routines
+ **************************************************************************/
+void
+soc_dump_decode_win(void)
+{
+	int i;
+
+	soc_id(&dev, &rev);
+
+	for (i = 0; i < MV_WIN_CPU_MAX; i++) {
+		printf("CPU window#%d: c 0x%08x, b 0x%08x", i,
+		    win_cpu_cr_read(i),
+		    win_cpu_br_read(i));
+
+		if (win_cpu_can_remap(i))
+			printf(", rl 0x%08x, rh 0x%08x",
+			    win_cpu_remap_l_read(i),
+			    win_cpu_remap_h_read(i));
+
+		printf("\n");
+	}
+	printf("Internal regs base: 0x%08x\n",
+	    bus_space_read_4(obio_tag, MV_INTREGS_BASE, 0));
+
+	for (i = 0; i < MV_WIN_DDR_MAX; i++)
+		printf("DDR CS#%d: b 0x%08x, s 0x%08x\n", i,
+		    ddr_br_read(i), ddr_sz_read(i));
+	
+	for (i = 0; i < MV_WIN_USB_MAX; i++)
+		printf("USB window#%d: c 0x%08x, b 0x%08x\n", i,
+		    win_usb_cr_read(i), win_usb_br_read(i));
+
+	for (i = 0; i < MV_WIN_ETH_MAX; i++) {
+		printf("ETH window#%d: b 0x%08x, s 0x%08x", i,
+		    win_eth_br_read(MV_ETH0_BASE, i),
+		    win_eth_sz_read(MV_ETH0_BASE, i));
+
+		if (win_eth_can_remap(i))
+			printf(", ha 0x%08x",
+			    win_eth_har_read(MV_ETH0_BASE, i));
+
+		printf("\n");
+	}
+	printf("ETH windows: bare 0x%08x, epap 0x%08x\n",
+	    win_eth_bare_read(MV_ETH0_BASE),
+	    win_eth_epap_read(MV_ETH0_BASE));
+
+	decode_win_idma_dump();
+	printf("\n");
+}
+
+/**************************************************************************
+ * CPU windows routines
+ **************************************************************************/
+int
+win_cpu_can_remap(int i)
+{
+
+	/* Depending on the SoC certain windows have remap capability */
+	if ((dev == MV_DEV_88F5182 && i < 2) ||
+	    (dev == MV_DEV_88F5281 && i < 4) ||
+	    (dev == MV_DEV_88F6281 && i < 4) ||
+	    (dev == MV_DEV_MV78100 && i < 8))
+		return (1);
+
+	return (0);
+}
+
+/* XXX This should check for overlapping remap fields too.. */
+int
+decode_win_overlap(int win, int win_no, const struct decode_win *wintab)
+{
+	const struct decode_win *tab;
+	int i;
+
+	tab = wintab;
+
+	for (i = 0; i < win_no; i++, tab++) {
+		if (i == win)
+			/* Skip self */
+			continue;
+
+		if ((tab->base + tab->size - 1) < (wintab + win)->base)
+			continue;
+
+		else if (((wintab + win)->base + (wintab + win)->size - 1) <
+		    tab->base)
+			continue;
+		else
+			return (i);
+	}
+
+	return (-1);
+}
+
+static int
+decode_win_cpu_valid(void)
+{
+	int i, j, rv;
+	uint32_t b, e, s;
+
+	if (cpu_wins_no > MV_WIN_CPU_MAX) {
+		printf("CPU windows: too many entries: %d\n", cpu_wins_no);
+		return (-1);
+	}
+
+	rv = 1;
+	for (i = 0; i < cpu_wins_no; i++) {
+
+		if (cpu_wins[i].target == 0) {
+			printf("CPU window#%d: DDR target window is not "
+			    "supposed to be reprogrammed!\n", i);
+			rv = 0;
+		}
+
+		if (cpu_wins[i].remap >= 0 && win_cpu_can_remap(i) != 1) {
+			printf("CPU window#%d: not capable of remapping, but "
+			    "val 0x%08x defined\n", i, cpu_wins[i].remap);
+			rv = 0;
+		}
+
+		s = cpu_wins[i].size;
+		b = cpu_wins[i].base;
+		e = b + s - 1;
+		if (s > (0xFFFFFFFF - b + 1)) {
+			/*
+			 * XXX this boundary check should account for 64bit
+			 * and remapping..
+			 */
+			printf("CPU window#%d: no space for size 0x%08x at "
+			    "0x%08x\n", i, s, b);
+			rv = 0;
+			continue;
+		}
+
+		j = decode_win_overlap(i, cpu_wins_no, &cpu_wins[0]);
+		if (j >= 0) {
+			printf("CPU window#%d: (0x%08x - 0x%08x) overlaps "
+			    "with #%d (0x%08x - 0x%08x)\n", i, b, e, j,
+			    cpu_wins[j].base,
+			    cpu_wins[j].base + cpu_wins[j].size - 1);
+			rv = 0;
+		}
+	}
+
+	return (rv);
+}
+
+static void
+decode_win_cpu_setup(void)
+{
+	uint32_t br, cr;
+	int i;
+
+	/* Disable all CPU windows */
+	for (i = 0; i < MV_WIN_CPU_MAX; i++) {
+		win_cpu_cr_write(i, 0);
+		win_cpu_br_write(i, 0);
+		if (win_cpu_can_remap(i)) {
+			win_cpu_remap_l_write(i, 0);
+			win_cpu_remap_h_write(i, 0);
+		}
+	}
+
+	for (i = 0; i < cpu_wins_no; i++)
+		if (cpu_wins[i].target > 0) {
+
+			br = cpu_wins[i].base & 0xffff0000;
+			win_cpu_br_write(i, br);
+
+			if (win_cpu_can_remap(i)) {
+				if (cpu_wins[i].remap >= 0) {
+					win_cpu_remap_l_write(i,
+					    cpu_wins[i].remap & 0xffff0000);
+					win_cpu_remap_h_write(i, 0);
+				} else {
+					/*
+					 * Remap function is not used for
+					 * a given window (capable of
+					 * remapping) - set remap field with the
+					 * same value as base.
+					 */
+					win_cpu_remap_l_write(i,
+					     cpu_wins[i].base & 0xffff0000);
+					win_cpu_remap_h_write(i, 0);
+				}
+			}
+
+			cr = ((cpu_wins[i].size - 1) & 0xffff0000) |
+			    (cpu_wins[i].attr << 8) |
+			    (cpu_wins[i].target << 4) | 1;
+
+			win_cpu_cr_write(i, cr);
+		}
+}
+
+/*
+ * Check if we're able to cover all active DDR banks.
+ */
+static int
+decode_win_can_cover_ddr(int max)
+{
+	int i, c;
+
+	c = 0;
+	for (i = 0; i < MV_WIN_DDR_MAX; i++)
+		if (ddr_is_active(i))
+			c++;
+
+	if (c > max) {
+		printf("Unable to cover all active DDR banks: "
+		    "%d, available windows: %d\n", c, max);
+		return (0);
+	}
+
+	return (1);
+}
+
+/**************************************************************************
+ * DDR windows routines
+ **************************************************************************/
+int
+ddr_is_active(int i)
+{
+
+	if (ddr_sz_read(i) & 0x1)
+		return (1);
+
+	return (0);
+}
+
+uint32_t
+ddr_base(int i)
+{
+
+	return (ddr_br_read(i) & 0xff000000);
+}
+
+uint32_t
+ddr_size(int i)
+{
+
+	return ((ddr_sz_read(i) | 0x00ffffff) + 1);
+}
+
+uint32_t
+ddr_attr(int i)
+{
+
+	return (i == 0 ? 0xe :
+	    (i == 1 ? 0xd :
+	    (i == 2 ? 0xb :
+	    (i == 3 ? 0x7 : 0xff))));
+}
+
+uint32_t
+ddr_target(int i)
+{
+
+	/* Mbus unit ID is 0x0 for DDR SDRAM controller */
+	return (0);
+}
+
+/**************************************************************************
+ * USB windows routines
+ **************************************************************************/
+static int
+decode_win_usb_valid(void)
+{
+
+	return (decode_win_can_cover_ddr(MV_WIN_USB_MAX));
+}
+
+/*
+ * Set USB decode windows.
+ */
+static void
+decode_win_usb_setup(uint32_t ctrl)
+{
+	uint32_t br, cr;
+	int i, j;
+
+	/* Disable and clear all USB windows */
+	for (i = 0; i < MV_WIN_USB_MAX; i++) {
+		win_usb_cr_write(i, 0);
+		win_usb_br_write(i, 0);
+	}
+
+	/* Only access to active DRAM banks is required */
+	for (i = 0; i < MV_WIN_DDR_MAX; i++)
+		if (ddr_is_active(i)) {
+			br = ddr_base(i);
+			/*
+			 * XXX for 6281 we should handle Mbus write burst limit
+			 * field in the ctrl reg
+			 */
+			cr = (((ddr_size(i) - 1) & 0xffff0000) |
+			    (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1); 
+
+			/* Set the first free USB window */
+			for (j = 0; j < MV_WIN_USB_MAX; j++) {
+				if (win_usb_cr_read(j) & 0x1)
+					continue;
+
+				win_usb_br_write(j, br);
+				win_usb_cr_write(j, cr);
+				break;
+			}
+		}
+}
+
+/**************************************************************************
+ * ETH windows routines
+ **************************************************************************/
+
+static int
+win_eth_can_remap(int i)
+{
+
+	/* ETH encode windows 0-3 have remap capability */
+	if (i < 4)
+		return (1);
+	
+	return (0);
+}
+
+static int
+eth_bare_read(uint32_t base, int i)
+{
+	uint32_t v;
+
+	v = win_eth_bare_read(base);
+	v &= (1 << i);
+
+	return (v >> i);
+}
+
+static void
+eth_bare_write(uint32_t base, int i, int val)
+{
+	uint32_t v;
+
+	v = win_eth_bare_read(base);
+	v &= ~(1 << i);
+	v |= (val << i);
+	win_eth_bare_write(base, v);
+}
+
+static void
+eth_epap_write(uint32_t base, int i, int val)
+{
+	uint32_t v;
+
+	v = win_eth_epap_read(base);
+	v &= ~(0x3 << (i * 2));
+	v |= (val << (i * 2));
+	win_eth_epap_write(base, v);
+}
+
+static void
+decode_win_eth_setup(uint32_t base)
+{
+	uint32_t br, sz;
+	int i, j;
+
+	/* Disable, clear and revoke protection for all ETH windows */
+	for (i = 0; i < MV_WIN_ETH_MAX; i++) {
+
+		eth_bare_write(base, i, 1);
+		eth_epap_write(base, i, 0);
+		win_eth_br_write(base, i, 0);
+		win_eth_sz_write(base, i, 0);
+		if (win_eth_can_remap(i))
+			win_eth_har_write(base, i, 0);
+	}
+
+	/* Only access to active DRAM banks is required */
+	for (i = 0; i < MV_WIN_DDR_MAX; i++)
+		if (ddr_is_active(i)) {
+
+			br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i); 
+			sz = ((ddr_size(i) - 1) & 0xffff0000);
+
+			/* Set the first free ETH window */
+			for (j = 0; j < MV_WIN_ETH_MAX; j++) {
+				if (eth_bare_read(base, j) == 0)
+					continue;
+
+				win_eth_br_write(base, j, br);
+				win_eth_sz_write(base, j, sz);
+
+				/* XXX remapping ETH windows not supported */
+
+				/* Set protection RW */
+				eth_epap_write(base, j, 0x3);
+
+				/* Enable window */
+				eth_bare_write(base, j, 0);
+				break;
+			}
+		}
+}
+
+static int
+decode_win_eth_valid(void)
+{
+
+	return (decode_win_can_cover_ddr(MV_WIN_ETH_MAX));
+}
+
+/**************************************************************************
+ * PCIE windows routines
+ **************************************************************************/
+
+static void
+decode_win_pcie_setup(uint32_t base)
+{
+	uint32_t size = 0;
+	uint32_t cr, br;
+	int i, j;
+
+	for (i = 0; i < MV_PCIE_BAR_MAX; i++)
+		pcie_bar_write(base, i, 0);
+
+	for (i = 0; i < MV_WIN_PCIE_MAX; i++) {
+		win_pcie_cr_write(base, i, 0);
+		win_pcie_br_write(base, i, 0);
+		win_pcie_remap_write(base, i, 0);
+	}
+
+	for (i = 0; i < MV_WIN_DDR_MAX; i++) {
+		if (ddr_is_active(i)) {
+			/* Map DDR to BAR 1 */
+			cr = (ddr_size(i) - 1) & 0xffff0000;
+			size += ddr_size(i) & 0xffff0000;
+			cr |= (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1;
+			br = ddr_base(i);
+
+			/* Use the first available PCIE window */
+			for (j = 0; j < MV_WIN_PCIE_MAX; j++) {
+				if (win_pcie_cr_read(base, j) != 0)
+					continue;
+
+				win_pcie_br_write(base, j, br);
+				win_pcie_cr_write(base, j, cr);
+				break;
+			}
+		}
+	}
+
+	/*
+	 * Upper 16 bits in BAR register is interpreted as BAR size
+	 * (in 64 kB units) plus 64kB, so substract 0x10000
+	 * form value passed to register to get correct value.
+	 */
+	size -= 0x10000;
+	pcie_bar_write(base, 0, size | 1);
+}
+
+static int
+decode_win_pcie_valid(void)
+{
+
+	return (decode_win_can_cover_ddr(MV_WIN_PCIE_MAX));
+}
+
+/**************************************************************************
+ * IDMA windows routines
+ **************************************************************************/
+#if defined(SOC_MV_ORION) || defined(SOC_MV_DISCOVERY)
+static int
+idma_bare_read(int i)
+{
+	uint32_t v;
+
+	v = win_idma_bare_read();
+	v &= (1 << i);
+
+	return (v >> i);
+}
+
+static void
+idma_bare_write(int i, int val)
+{
+	uint32_t v;
+
+	v = win_idma_bare_read();
+	v &= ~(1 << i);
+	v |= (val << i);
+	win_idma_bare_write(v);
+}
+
+/*
+ * Sets channel protection 'val' for window 'w' on channel 'c'
+ */
+static void
+idma_cap_write(int c, int w, int val)
+{
+	uint32_t v;
+
+	v = win_idma_cap_read(c);
+	v &= ~(0x3 << (w * 2));
+	v |= (val << (w * 2));
+	win_idma_cap_write(c, v);
+}
+
+/*
+ * Set protection 'val' on all channels for window 'w'
+ */
+static void
+idma_set_prot(int w, int val)
+{
+	int c;
+
+	for (c = 0; c < MV_IDMA_CHAN_MAX; c++)
+		idma_cap_write(c, w, val);
+}
+
+static int
+win_idma_can_remap(int i)
+{
+
+	/* IDMA decode windows 0-3 have remap capability */
+	if (i < 4)
+		return (1);
+	
+	return (0);
+}
+
+void
+decode_win_idma_setup(void)
+{
+	uint32_t br, sz;
+	int i, j;
+
+	/*
+	 * Disable and clear all IDMA windows, revoke protection for all channels
+	 */
+	for (i = 0; i < MV_WIN_IDMA_MAX; i++) {
+
+		idma_bare_write(i, 1);
+		win_idma_br_write(i, 0);
+		win_idma_sz_write(i, 0);
+		if (win_idma_can_remap(i) == 1)
+			win_idma_har_write(i, 0);
+	}
+	for (i = 0; i < MV_IDMA_CHAN_MAX; i++)
+		win_idma_cap_write(i, 0);
+
+	/*
+	 * Set up access to all active DRAM banks
+	 */
+	for (i = 0; i < MV_WIN_DDR_MAX; i++)
+		if (ddr_is_active(i)) {
+			br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i); 
+			sz = ((ddr_size(i) - 1) & 0xffff0000);
+
+			/* Place DDR entries in non-remapped windows */
+			for (j = 0; j < MV_WIN_IDMA_MAX; j++)
+				if (win_idma_can_remap(j) != 1 &&
+				    idma_bare_read(j) == 1) {
+
+					/* Configure window */
+					win_idma_br_write(j, br);
+					win_idma_sz_write(j, sz);
+
+					/* Set protection RW on all channels */
+					idma_set_prot(j, 0x3);
+
+					/* Enable window */
+					idma_bare_write(j, 0);
+					break;
+				}
+		}
+
+	/*
+	 * Remaining targets -- from statically defined table
+	 */
+	for (i = 0; i < idma_wins_no; i++)
+		if (idma_wins[i].target > 0) {
+			br = (idma_wins[i].base & 0xffff0000) |
+			    (idma_wins[i].attr << 8) | idma_wins[i].target; 
+			sz = ((idma_wins[i].size - 1) & 0xffff0000);
+
+			/* Set the first free IDMA window */
+			for (j = 0; j < MV_WIN_IDMA_MAX; j++) {
+				if (idma_bare_read(j) == 0)
+					continue;
+
+				/* Configure window */
+				win_idma_br_write(j, br);
+				win_idma_sz_write(j, sz);
+				if (win_idma_can_remap(j) && idma_wins[j].remap >= 0)
+					win_idma_har_write(j, idma_wins[j].remap);
+
+				/* Set protection RW on all channels */
+				idma_set_prot(j, 0x3);
+
+				/* Enable window */
+				idma_bare_write(j, 0);
+				break;
+			}
+		}
+}
+
+int
+decode_win_idma_valid(void)
+{
+	const struct decode_win *wintab;
+	int c, i, j, rv;
+	uint32_t b, e, s;
+
+	if (idma_wins_no > MV_WIN_IDMA_MAX) {
+		printf("IDMA windows: too many entries: %d\n", idma_wins_no);
+		return (-1);
+	}
+	for (i = 0, c = 0; i < MV_WIN_DDR_MAX; i++)
+		if (ddr_is_active(i))
+			c++;
+
+	if (idma_wins_no > (MV_WIN_IDMA_MAX - c)) {
+		printf("IDMA windows: too many entries: %d, available: %d\n",
+		    idma_wins_no, MV_WIN_IDMA_MAX - c);
+		return (-1);
+	}
+
+	wintab = idma_wins;
+	rv = 1;
+	for (i = 0; i < idma_wins_no; i++, wintab++) {
+
+		if (wintab->target == 0) {
+			printf("IDMA window#%d: DDR target window is not supposed "
+			    "to be reprogrammed!\n", i);
+			rv = 0;
+		}
+
+		if (wintab->remap >= 0 && win_cpu_can_remap(i) != 1) {
+			printf("IDMA window#%d: not capable of remapping, but "
+			    "val 0x%08x defined\n", i, wintab->remap);
+			rv = 0;
+		}
+
+		s = wintab->size;
+		b = wintab->base;
+		e = b + s - 1;
+		if (s > (0xFFFFFFFF - b + 1)) {
+			/* XXX this boundary check should accont for 64bit and
+			 * remapping.. */
+			printf("IDMA window#%d: no space for size 0x%08x at "
+			    "0x%08x\n", i, s, b);
+			rv = 0;
+			continue;
+		}
+
+		j = decode_win_overlap(i, idma_wins_no, &idma_wins[0]);
+		if (j >= 0) {
+			printf("IDMA window#%d: (0x%08x - 0x%08x) overlaps with "
+			    "#%d (0x%08x - 0x%08x)\n", i, b, e, j,
+			    idma_wins[j].base,
+			    idma_wins[j].base + idma_wins[j].size - 1);
+			rv = 0;
+		}
+	}
+
+	return (rv);
+}
+
+void
+decode_win_idma_dump(void)
+{
+	int i;
+
+	for (i = 0; i < MV_WIN_IDMA_MAX; i++) {
+		printf("IDMA window#%d: b 0x%08x, s 0x%08x", i,
+		    win_idma_br_read(i), win_idma_sz_read(i));
+		
+		if (win_idma_can_remap(i))
+			printf(", ha 0x%08x", win_idma_har_read(i));
+
+		printf("\n");
+	}
+	for (i = 0; i < MV_IDMA_CHAN_MAX; i++)
+		printf("IDMA channel#%d: ap 0x%08x\n", i,
+		    win_idma_cap_read(i));
+	printf("IDMA windows: bare 0x%08x\n", win_idma_bare_read());
+}
+#else
+
+/* Provide dummy functions to satisfy the build for SoCs not equipped with IDMA */
+int
+decode_win_idma_valid(void)
+{
+
+	return (1);
+}
+
+void
+decode_win_idma_setup(void)
+{
+}
+
+void
+decode_win_idma_dump(void)
+{
+}
+#endif
diff --git a/sys/arm/mv/discovery/db78xxx.c b/sys/arm/mv/discovery/db78xxx.c
new file mode 100644
index 000000000000..f472793f5eb9
--- /dev/null
+++ b/sys/arm/mv/discovery/db78xxx.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/pte.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+/*
+ * Virtual address space layout:
+ * -----------------------------
+ * 0x0000_0000 - 0xbfff_ffff	: user process
+ *
+ * 0xc040_0000 - virtual_avail	: kernel reserved (text, data, page tables
+ *				: structures, ARM stacks etc.)
+ * virtual_avail - 0xefff_ffff	: KVA (virtual_avail is typically < 0xc0a0_0000)
+ * 0xf000_0000 - 0xf0ff_ffff	: no-cache allocation area (16MB)
+ * 0xf100_0000 - 0xf10f_ffff	: SoC integrated devices registers range (1MB)
+ * 0xf110_0000 - 0xfffe_ffff	: PCIE (MEM+IO) outbound windows (~238MB)
+ * 0xffff_0000 - 0xffff_0fff	: 'high' vectors page (4KB)
+ * 0xffff_1000 - 0xffff_1fff	: ARM_TP_ADDRESS/RAS page (4KB)
+ * 0xffff_2000 - 0xffff_ffff	: unused (~55KB)
+ */
+
+const struct pmap_devmap *pmap_devmap_bootstrap_table;
+vm_offset_t pmap_bootstrap_lastaddr;
+
+/* Static device mappings. */
+static const struct pmap_devmap pmap_devmap[] = {
+	/*
+	 * Map the on-board devices VA == PA so that we can access them
+	 * with the MMU on or off.
+	 */
+	{ /* SoC integrated peripherals registers range */
+		MV_BASE,
+		MV_PHYS_BASE,
+		MV_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ 0, 0, 0, 0, 0, }
+};
+
+int
+platform_pmap_init(void)
+{
+
+	pmap_bootstrap_lastaddr = MV_BASE - ARM_NOCACHE_KVA_SIZE;
+	pmap_devmap_bootstrap_table = &pmap_devmap[0];
+
+	return (0);
+}
+
+static void
+platform_identify(void *dummy)
+{
+
+	soc_identify();
+
+	/*
+	 * XXX Board identification e.g. read out from FPGA or similar should
+	 * go here
+	 */
+}
+SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, NULL);
+
+/*
+ * TODO routine setting GPIO/MPP pins
+ */
diff --git a/sys/arm/mv/discovery/discovery.c b/sys/arm/mv/discovery/discovery.c
new file mode 100644
index 000000000000..33f0bf5d97d8
--- /dev/null
+++ b/sys/arm/mv/discovery/discovery.c
@@ -0,0 +1,160 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+struct obio_device obio_devices[] = {
+	{ "ic", MV_IC_BASE, MV_IC_SIZE,
+		{ -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "timer", MV_TIMERS_BASE, MV_TIMERS_SIZE,
+		{ MV_INT_TIMER0, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "gpio", MV_GPIO_BASE, MV_GPIO_SIZE,
+		{ MV_INT_GPIO7_0, MV_INT_GPIO15_8,
+		  MV_INT_GPIO23_16, MV_INT_GPIO31_24, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "uart", MV_UART0_BASE, MV_UART_SIZE,
+		{ MV_INT_UART0, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "uart", MV_UART1_BASE, MV_UART_SIZE,
+		{ MV_INT_UART1, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "idma", MV_IDMA_BASE, MV_IDMA_SIZE,
+		{ MV_INT_IDMA_ERR, MV_INT_IDMA0, MV_INT_IDMA1,
+		  MV_INT_IDMA2, MV_INT_IDMA3, -1 },
+		{ -1 },
+		CPU_PM_CTRL_IDMA
+	},
+	{ "xor", MV_XOR_BASE, MV_XOR_SIZE,
+		{ MV_INT_XOR0, MV_INT_XOR1,
+		  MV_INT_XOR_ERR, -1 },
+		{ -1 },
+		CPU_PM_CTRL_XOR
+	},
+	{ "ehci", MV_USB0_BASE, MV_USB_SIZE,
+		{ MV_INT_USB_ERR, MV_INT_USB0, -1 },
+		{ -1 },
+		CPU_PM_CTRL_USB0 | CPU_PM_CTRL_USB1 | CPU_PM_CTRL_USB2
+	},
+	{ "mge", MV_ETH0_BASE, MV_ETH_SIZE,
+		{ MV_INT_GBERX, MV_INT_GBETX, MV_INT_GBEMISC,
+		  MV_INT_GBESUM, MV_INT_GBE_ERR, -1 },
+		{ -1 },
+		CPU_PM_CTRL_GE0
+	},
+	{ "mge", MV_ETH1_BASE, MV_ETH_SIZE,
+		{ MV_INT_GBE1RX, MV_INT_GBE1TX, MV_INT_GBE1MISC,
+		  MV_INT_GBE1SUM, MV_INT_GBE_ERR, -1 },
+		{ -1 },
+		CPU_PM_CTRL_GE1
+	},
+	{ "twsi", MV_TWSI_BASE, MV_TWSI_SIZE,
+		{ -1 }, { -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ NULL, 0, 0, { 0 }, { 0 }, 0 }
+};
+
+struct resource_spec mv_gpio_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		2,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		3,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+struct resource_spec mv_xor_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		2,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+const struct decode_win cpu_win_tbl[] = {
+	/* PCIE IO */
+	{ 4, 0x51, MV_PCIE_IO_PHYS_BASE, MV_PCIE_IO_SIZE, -1 },
+
+	/* PCIE MEM */
+	{ 4, 0x59, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
+
+	/* Device bus BOOT */
+	{ 1, 0x2f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
+
+	/* Device bus CS0 */
+	{ 1, 0x3e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
+
+	/* Device bus CS1 */
+	{ 1, 0x3d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
+
+	/* Device bus CS2 */
+	{ 1, 0x3b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
+};
+const struct decode_win *cpu_wins = cpu_win_tbl;
+int cpu_wins_no = sizeof(cpu_win_tbl) / sizeof(struct decode_win);
+
+/*
+ * Note: the decode windows table for IDMA does not explicitly have DRAM
+ * entries, which are not statically defined: active DDR banks (== windows)
+ * are established in run time from actual DDR windows settings. All active
+ * DDR banks are mapped into IDMA decode windows, so at least one IDMA decode
+ * window is occupied by the DDR bank; in case when all (MV_WIN_DDR_MAX)
+ * DDR banks are active, the remaining available IDMA decode windows for other
+ * targets is only MV_WIN_IDMA_MAX - MV_WIN_DDR_MAX.
+ */
+const struct decode_win idma_win_tbl[] = {
+	/* PCIE MEM */
+	{ 4, 0x59, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
+};
+const struct decode_win *idma_wins = idma_win_tbl;
+int idma_wins_no = sizeof(idma_win_tbl) / sizeof(struct decode_win);
diff --git a/sys/arm/mv/discovery/files.db78xxx b/sys/arm/mv/discovery/files.db78xxx
new file mode 100644
index 000000000000..b01285fd2582
--- /dev/null
+++ b/sys/arm/mv/discovery/files.db78xxx
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+arm/mv/discovery/discovery.c	standard
+arm/mv/discovery/db78xxx.c	standard
diff --git a/sys/arm/mv/discovery/std.db78xxx b/sys/arm/mv/discovery/std.db78xxx
new file mode 100644
index 000000000000..b2f6049e0d8f
--- /dev/null
+++ b/sys/arm/mv/discovery/std.db78xxx
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+include	"../mv/std.mv"
+files	"../mv/discovery/files.db78xxx"
+
+makeoptions	KERNPHYSADDR=0x00900000
+makeoptions	KERNVIRTADDR=0xc0900000
+
+options		KERNPHYSADDR=0x00900000
+options		KERNVIRTADDR=0xc0900000
+options		PHYSADDR=0x00000000
+options		PHYSMEM_SIZE=0x20000000
+options		STARTUP_PAGETABLE_ADDR=0x00100000
diff --git a/sys/arm/mv/files.mv b/sys/arm/mv/files.mv
new file mode 100644
index 000000000000..bba8c83deb2a
--- /dev/null
+++ b/sys/arm/mv/files.mv
@@ -0,0 +1,34 @@
+# $FreeBSD$
+#
+# The Marvell CPU cores
+# - Compliant with V5TE architecture
+# - Super scalar dual issue CPU
+# - Big/Little Endian
+# - MMU/MPU
+# - L1 Cache: Supports streaming and write allocate
+# - Variable pipeline stages
+# - Out-of-order execution
+# - Branch Prediction
+# - JTAG/ICE
+# - Vector Floating Point (VFP) unit
+#
+arm/arm/bus_space_generic.c	standard
+arm/arm/cpufunc_asm_arm10.S	standard
+arm/arm/cpufunc_asm_armv5_ec.S	standard
+arm/arm/cpufunc_asm_feroceon.S	standard
+arm/arm/irq_dispatch.S		standard
+
+arm/mv/bus_space.c		standard
+arm/mv/common.c			standard
+arm/mv/gpio.c			standard
+arm/mv/ic.c			standard
+arm/mv/mv_machdep.c		standard
+arm/mv/obio.c			standard
+arm/mv/timer.c			standard
+arm/mv/twsi.c			optional	iicbus
+
+dev/mge/if_mge.c		optional	mge
+dev/uart/uart_bus_mbus.c	optional	uart
+dev/uart/uart_cpu_mv.c		optional	uart
+dev/uart/uart_dev_ns8250.c	optional	uart
+dev/usb/ehci_mbus.c		optional	ehci
diff --git a/sys/arm/mv/gpio.c b/sys/arm/mv/gpio.c
new file mode 100644
index 000000000000..bb7f04b46cdf
--- /dev/null
+++ b/sys/arm/mv/gpio.c
@@ -0,0 +1,516 @@
+/*-
+ * Copyright (c) 2006 Benno Rice.
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Adapted and extended for Marvell SoCs by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_gpio.c, rev 1
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/interrupt.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/queue.h>
+#include <sys/timetc.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <arm/mv/mvvar.h>
+#include <arm/mv/mvreg.h>
+
+#define GPIO_MAX_INTR_COUNT	8
+#define GPIO_PINS_PER_REG	32
+
+struct mv_gpio_softc {
+	struct resource *	res[GPIO_MAX_INTR_COUNT + 1];
+	void			*ih_cookie[GPIO_MAX_INTR_COUNT];
+	bus_space_tag_t		bst;
+	bus_space_handle_t	bsh;
+	uint8_t			pin_num;	/* number of GPIO pins */
+	uint8_t			irq_num;	/* number of real IRQs occupied by GPIO controller */
+	uint8_t			use_high;
+};
+
+extern struct resource_spec mv_gpio_spec[];
+
+static struct mv_gpio_softc *mv_gpio_softc = NULL;
+static uint32_t	gpio_setup[MV_GPIO_MAX_NPINS];
+
+static int	mv_gpio_probe(device_t);
+static int	mv_gpio_attach(device_t);
+static void	mv_gpio_intr(void *);
+
+static void	mv_gpio_intr_handler(int pin);
+static uint32_t	mv_gpio_reg_read(uint32_t reg);
+static void	mv_gpio_reg_write(uint32_t reg, uint32_t val);
+static void	mv_gpio_reg_set(uint32_t reg, uint32_t val);
+static void	mv_gpio_reg_clear(uint32_t reg, uint32_t val);
+
+static void	mv_gpio_blink(uint32_t pin, uint8_t enable);
+static void	mv_gpio_polarity(uint32_t pin, uint8_t enable);
+static void	mv_gpio_level(uint32_t pin, uint8_t enable);
+static void	mv_gpio_edge(uint32_t pin, uint8_t enable);
+static void	mv_gpio_out_en(uint32_t pin, uint8_t enable);
+static void	mv_gpio_int_ack(uint32_t pin);
+static void	mv_gpio_value_set(uint32_t pin, uint8_t val);
+static uint32_t	mv_gpio_value_get(uint32_t pin);
+
+static device_method_t mv_gpio_methods[] = {
+	DEVMETHOD(device_probe,		mv_gpio_probe),
+	DEVMETHOD(device_attach,	mv_gpio_attach),
+	{ 0, 0 }
+};
+
+static driver_t mv_gpio_driver = {
+	"gpio",
+	mv_gpio_methods,
+	sizeof(struct mv_gpio_softc),
+};
+
+static devclass_t mv_gpio_devclass;
+
+DRIVER_MODULE(gpio, mbus, mv_gpio_driver, mv_gpio_devclass, 0, 0);
+
+static int
+mv_gpio_probe(device_t dev)
+{
+
+	device_set_desc(dev, "Marvell Integrated GPIO Controller");
+	return (0);
+}
+
+static int
+mv_gpio_attach(device_t dev)
+{
+	int	error, i;
+	struct	mv_gpio_softc *sc;
+	uint32_t dev_id, rev_id;
+
+	sc = (struct mv_gpio_softc *)device_get_softc(dev);
+
+	if (mv_gpio_softc != NULL)
+		return (ENXIO);
+	mv_gpio_softc = sc;
+
+	/* Get board id and revision */
+	soc_id(&dev_id, &rev_id);
+
+	if (dev_id == MV_DEV_88F5182 ||
+	    dev_id == MV_DEV_88F5281 ||
+	    dev_id == MV_DEV_MV78100) {
+		sc->pin_num = 32;
+		sc->irq_num = 4;
+		sc->use_high = 0;
+
+	} else if (dev_id == MV_DEV_88F6281) {
+		sc->pin_num = 50;
+		sc->irq_num = 7;
+		sc->use_high = 1;
+
+	} else {
+		device_printf(dev, "unknown board id=0x%x\n", dev_id);
+		return (ENXIO);
+	}
+
+	error = bus_alloc_resources(dev, mv_gpio_spec, sc->res);
+	if (error) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->bst = rman_get_bustag(sc->res[0]);
+	sc->bsh = rman_get_bushandle(sc->res[0]);
+
+	/* Disable and clear all interrupts */
+	bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_EDGE_MASK, 0);
+	bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_LEV_MASK, 0);
+	bus_space_write_4(sc->bst, sc->bsh, GPIO_INT_CAUSE, 0);
+
+	if (sc->use_high) {
+		bus_space_write_4(sc->bst, sc->bsh,
+		    GPIO_HI_INT_EDGE_MASK, 0);
+		bus_space_write_4(sc->bst, sc->bsh,
+		    GPIO_HI_INT_LEV_MASK, 0);
+		bus_space_write_4(sc->bst, sc->bsh,
+		    GPIO_HI_INT_CAUSE, 0);
+	}
+
+	for (i = 0; i < sc->irq_num; i++) {
+		if (bus_setup_intr(dev, sc->res[1 + i],
+		    INTR_TYPE_MISC | INTR_FAST,
+		    (driver_filter_t *)mv_gpio_intr, NULL,
+		    sc, &sc->ih_cookie[i]) != 0) {
+			bus_release_resources(dev, mv_gpio_spec, sc->res);
+			device_printf(dev, "could not set up intr %d\n", i);
+			return (ENXIO);
+		}
+	}
+
+	return (0);
+}
+
+static void
+mv_gpio_intr(void *arg)
+{
+	uint32_t	int_cause, gpio_val;
+	uint32_t	int_cause_hi, gpio_val_hi = 0;
+	int		i;
+
+	int_cause = mv_gpio_reg_read(GPIO_INT_CAUSE);
+	gpio_val = mv_gpio_reg_read(GPIO_DATA_IN);
+	gpio_val &= int_cause;
+	if (mv_gpio_softc->use_high) {
+		int_cause_hi = mv_gpio_reg_read(GPIO_HI_INT_CAUSE);
+		gpio_val_hi = mv_gpio_reg_read(GPIO_HI_DATA_IN);
+		gpio_val_hi &= int_cause_hi;
+	}
+
+	i = 0;
+	while (gpio_val != 0) {
+		if (gpio_val & 1)
+			mv_gpio_intr_handler(i);
+		gpio_val >>= 1;
+		i++;
+	}
+
+	if (mv_gpio_softc->use_high) {
+		i = 0;
+		while (gpio_val_hi != 0) {
+			if (gpio_val_hi & 1)
+				mv_gpio_intr_handler(i + GPIO_PINS_PER_REG);
+			gpio_val_hi >>= 1;
+			i++;
+		}
+	}
+}
+
+/*
+ * GPIO interrupt handling
+ */
+
+static struct intr_event	*gpio_events[MV_GPIO_MAX_NPINS];
+
+int
+mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt,
+    void (*hand)(void *), void *arg, int pin, int flags, void **cookiep)
+{
+	struct	intr_event *event;
+	int	error;
+
+	if (pin < 0 || pin >= mv_gpio_softc->pin_num)
+		return (ENXIO);
+	event = gpio_events[pin];
+	if (event == NULL) {
+		error = intr_event_create(&event, (void *)pin, 0, pin,
+		    (void (*)(void *))mv_gpio_intr_mask,
+		    (void (*)(void *))mv_gpio_intr_unmask,
+		    (void (*)(void *))mv_gpio_int_ack,
+		    NULL,
+		    "gpio%d:", pin);
+		if (error != 0)
+			return (error);
+		gpio_events[pin] = event;
+	}
+
+	intr_event_add_handler(event, name, filt, hand, arg, intr_priority(flags),
+	    flags, cookiep);
+	return (0);
+}
+
+void
+mv_gpio_intr_mask(int pin)
+{
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (gpio_setup[pin] & MV_GPIO_EDGE)
+		mv_gpio_edge(pin, 0);
+	else
+		mv_gpio_level(pin, 0);
+}
+
+void
+mv_gpio_intr_unmask(int pin)
+{
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (gpio_setup[pin] & MV_GPIO_EDGE)
+		mv_gpio_edge(pin, 1);
+	else
+		mv_gpio_level(pin, 1);
+}
+
+static void
+mv_gpio_intr_handler(int pin)
+{
+	struct	intr_event *event;
+
+	event = gpio_events[pin];
+	if (event == NULL || TAILQ_EMPTY(&event->ie_handlers))
+		return;
+
+	intr_event_handle(event, NULL);
+}
+
+int
+mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask)
+{
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return (EINVAL);
+
+	if (mask & MV_GPIO_BLINK)
+		mv_gpio_blink(pin, flags & MV_GPIO_BLINK);
+	if (mask & MV_GPIO_POLARITY)
+		mv_gpio_polarity(pin, flags & MV_GPIO_POLARITY);
+	if (mask & MV_GPIO_EDGE)
+		mv_gpio_edge(pin, flags & MV_GPIO_EDGE);
+	if (mask & MV_GPIO_LEVEL)
+		mv_gpio_level(pin, flags & MV_GPIO_LEVEL);
+
+	gpio_setup[pin] &= ~(mask);
+	gpio_setup[pin] |= (flags & mask);
+
+	return (0);
+}
+
+void
+mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable)
+{
+
+	mv_gpio_value_set(pin, val);
+	mv_gpio_out_en(pin, enable);
+}
+
+uint8_t
+mv_gpio_in(uint32_t pin)
+{
+
+	return (mv_gpio_value_get(pin));
+}
+
+static uint32_t
+mv_gpio_reg_read(uint32_t reg)
+{
+
+	return (bus_space_read_4(mv_gpio_softc->bst,
+	    mv_gpio_softc->bsh, reg));
+}
+
+static void
+mv_gpio_reg_write(uint32_t reg, uint32_t val)
+{
+
+	bus_space_write_4(mv_gpio_softc->bst,
+	    mv_gpio_softc->bsh, reg, val);
+}
+
+static void
+mv_gpio_reg_set(uint32_t reg, uint32_t pin)
+{
+	uint32_t reg_val;
+
+	reg_val = mv_gpio_reg_read(reg);
+	reg_val |= GPIO(pin);
+	mv_gpio_reg_write(reg, reg_val);
+}
+
+static void
+mv_gpio_reg_clear(uint32_t reg, uint32_t pin)
+{
+	uint32_t reg_val;
+
+	reg_val = mv_gpio_reg_read(reg);
+	reg_val &= ~(GPIO(pin));
+	mv_gpio_reg_write(reg, reg_val);
+}
+
+static void
+mv_gpio_out_en(uint32_t pin, uint8_t enable)
+{
+	uint32_t reg;
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (pin >= GPIO_PINS_PER_REG) {
+		reg = GPIO_HI_DATA_OUT_EN_CTRL;
+		pin -= GPIO_PINS_PER_REG;
+	} else
+		reg = GPIO_DATA_OUT_EN_CTRL;
+
+	if (enable)
+		mv_gpio_reg_clear(reg, pin);
+	else
+		mv_gpio_reg_set(reg, pin);
+}
+
+static void
+mv_gpio_blink(uint32_t pin, uint8_t enable)
+{
+	uint32_t reg;
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (pin >= GPIO_PINS_PER_REG) {
+		reg = GPIO_HI_BLINK_EN;
+		pin -= GPIO_PINS_PER_REG;
+	} else
+		reg = GPIO_BLINK_EN;
+
+	if (enable)
+		mv_gpio_reg_set(reg, pin);
+	else
+		mv_gpio_reg_clear(reg, pin);
+}
+
+static void
+mv_gpio_polarity(uint32_t pin, uint8_t enable)
+{
+	uint32_t reg;
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (pin >= GPIO_PINS_PER_REG) {
+		reg = GPIO_HI_DATA_IN_POLAR;
+		pin -= GPIO_PINS_PER_REG;
+	} else
+		reg = GPIO_DATA_IN_POLAR;
+
+	if (enable)
+		mv_gpio_reg_set(reg, pin);
+	else
+		mv_gpio_reg_clear(reg, pin);
+}
+
+static void
+mv_gpio_level(uint32_t pin, uint8_t enable)
+{
+	uint32_t reg;
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (pin >= GPIO_PINS_PER_REG) {
+		reg = GPIO_HI_INT_LEV_MASK;
+		pin -= GPIO_PINS_PER_REG;
+	} else
+		reg = GPIO_INT_LEV_MASK;
+
+	if (enable)
+		mv_gpio_reg_set(reg, pin);
+	else
+		mv_gpio_reg_clear(reg, pin);
+}
+
+static void
+mv_gpio_edge(uint32_t pin, uint8_t enable)
+{
+	uint32_t reg;
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (pin >= GPIO_PINS_PER_REG) {
+		reg = GPIO_HI_INT_EDGE_MASK;
+		pin -= GPIO_PINS_PER_REG;
+	} else
+		reg = GPIO_INT_EDGE_MASK;
+
+	if (enable)
+		mv_gpio_reg_set(reg, pin);
+	else
+		mv_gpio_reg_clear(reg, pin);
+}
+
+static void
+mv_gpio_int_ack(uint32_t pin)
+{
+	uint32_t reg;
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (pin >= GPIO_PINS_PER_REG) {
+		reg = GPIO_HI_INT_CAUSE;
+		pin -= GPIO_PINS_PER_REG;
+	} else
+		reg = GPIO_INT_CAUSE;
+
+	mv_gpio_reg_clear(reg, pin);
+}
+
+static uint32_t
+mv_gpio_value_get(uint32_t pin)
+{
+	uint32_t reg, reg_val;
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return (0);
+
+	if (pin >= GPIO_PINS_PER_REG) {
+		reg = GPIO_HI_DATA_IN;
+		pin -= GPIO_PINS_PER_REG;
+	} else
+		reg = GPIO_DATA_IN;
+
+	reg_val = mv_gpio_reg_read(reg);
+
+	return (reg_val & GPIO(pin));
+}
+
+static void
+mv_gpio_value_set(uint32_t pin, uint8_t val)
+{
+	uint32_t reg;
+
+	if (pin >= mv_gpio_softc->pin_num)
+		return;
+
+	if (pin >= GPIO_PINS_PER_REG) {
+		reg = GPIO_HI_DATA_OUT;
+		pin -= GPIO_PINS_PER_REG;
+	} else
+		reg = GPIO_DATA_OUT;
+
+	if (val)
+		mv_gpio_reg_set(reg, pin);
+	else
+		mv_gpio_reg_clear(reg, pin);
+}
diff --git a/sys/arm/mv/ic.c b/sys/arm/mv/ic.c
new file mode 100644
index 000000000000..47db7c4368a5
--- /dev/null
+++ b/sys/arm/mv/ic.c
@@ -0,0 +1,289 @@
+/*-
+ * Copyright (c) 2006 Benno Rice.
+ * Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Adapted and extended to Marvell SoCs by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_icu.c, rev 1
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+struct mv_ic_softc {
+	struct resource	*	ic_res[1];
+	bus_space_tag_t		ic_bst;
+	bus_space_handle_t	ic_bsh;
+	int			ic_high_regs;
+	int			ic_error_regs;
+};
+
+static struct resource_spec mv_ic_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static struct mv_ic_softc *mv_ic_sc = NULL;
+
+static int	mv_ic_probe(device_t);
+static int	mv_ic_attach(device_t);
+
+uint32_t	mv_ic_get_cause(void);
+uint32_t	mv_ic_get_mask(void);
+void		mv_ic_set_mask(uint32_t);
+uint32_t	mv_ic_get_cause_hi(void);
+uint32_t	mv_ic_get_mask_hi(void);
+void		mv_ic_set_mask_hi(uint32_t);
+uint32_t	mv_ic_get_cause_error(void);
+uint32_t	mv_ic_get_mask_error(void);
+void		mv_ic_set_mask_error(uint32_t);
+static void	arm_mask_irq_all(void);
+
+static int
+mv_ic_probe(device_t dev)
+{
+
+	device_set_desc(dev, "Marvell Integrated Interrupt Controller");
+	return (0);
+}
+
+static int
+mv_ic_attach(device_t dev)
+{
+	struct mv_ic_softc *sc;
+	uint32_t dev_id, rev_id;
+	int error;
+
+	sc = (struct mv_ic_softc *)device_get_softc(dev);
+
+	if (mv_ic_sc != NULL)
+		return (ENXIO);
+	mv_ic_sc = sc;
+
+	soc_id(&dev_id, &rev_id);
+
+	sc->ic_high_regs = 0;
+	sc->ic_error_regs = 0;
+
+	if (dev_id == MV_DEV_88F6281 || dev_id == MV_DEV_MV78100)
+		sc->ic_high_regs = 1;
+
+	if (dev_id == MV_DEV_MV78100)
+		sc->ic_error_regs = 1;
+
+	error = bus_alloc_resources(dev, mv_ic_spec, sc->ic_res);
+	if (error) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->ic_bst = rman_get_bustag(sc->ic_res[0]);
+	sc->ic_bsh = rman_get_bushandle(sc->ic_res[0]);
+
+	/* Mask all interrupts */
+	arm_mask_irq_all();
+
+	return (0);
+}
+
+static device_method_t mv_ic_methods[] = {
+	DEVMETHOD(device_probe,		mv_ic_probe),
+	DEVMETHOD(device_attach,	mv_ic_attach),
+	{ 0, 0 }
+};
+
+static driver_t mv_ic_driver = {
+	"ic",
+	mv_ic_methods,
+	sizeof(struct mv_ic_softc),
+};
+
+static devclass_t mv_ic_devclass;
+
+DRIVER_MODULE(ic, mbus, mv_ic_driver, mv_ic_devclass, 0, 0);
+
+int
+arm_get_next_irq(void)
+{
+	int irq;
+
+	irq = mv_ic_get_cause() & mv_ic_get_mask();
+	if (irq)
+		return (ffs(irq) - 1);
+
+	if (mv_ic_sc->ic_high_regs) {
+		irq = mv_ic_get_cause_hi() & mv_ic_get_mask_hi();
+		if (irq)
+			return (ffs(irq) + 31);
+	}
+
+	if (mv_ic_sc->ic_error_regs) {
+		irq = mv_ic_get_cause_error() & mv_ic_get_mask_error();
+		if (irq)
+			return (ffs(irq) + 63);
+	}
+
+	return (-1);
+}
+
+static void
+arm_mask_irq_all(void)
+{
+
+	mv_ic_set_mask(0);
+
+	if (mv_ic_sc->ic_high_regs)
+		mv_ic_set_mask_hi(0);
+
+	if (mv_ic_sc->ic_error_regs)
+		mv_ic_set_mask_error(0);
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+	uint32_t	mr;
+
+	if (nb < 32) {
+		mr = mv_ic_get_mask();
+		mr &= ~(1 << nb);
+		mv_ic_set_mask(mr);
+
+	} else if ((nb < 64) && mv_ic_sc->ic_high_regs) {
+		mr = mv_ic_get_mask_hi();
+		mr &= ~(1 << (nb - 32));
+		mv_ic_set_mask_hi(mr);
+
+	} else if ((nb < 96) && mv_ic_sc->ic_error_regs) {
+		mr = mv_ic_get_mask_error();
+		mr &= ~(1 << (nb - 64));
+		mv_ic_set_mask_error(mr);
+	}
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+	uint32_t	mr;
+
+	if (nb < 32) {
+		mr = mv_ic_get_mask();
+		mr |= (1 << nb);
+		mv_ic_set_mask(mr);
+
+	} else if ((nb < 64) && mv_ic_sc->ic_high_regs) {
+		mr = mv_ic_get_mask_hi();
+		mr |= (1 << (nb - 32));
+		mv_ic_set_mask_hi(mr);
+
+	} else if ((nb < 96) && mv_ic_sc->ic_error_regs) {
+		mr = mv_ic_get_mask_error();
+		mr |= (1 << (nb - 64));
+		mv_ic_set_mask_error(mr);
+	}
+}
+
+void
+mv_ic_set_mask(uint32_t val)
+{
+
+	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
+	    IRQ_MASK, val);
+}
+
+uint32_t
+mv_ic_get_mask(void)
+{
+
+	return (bus_space_read_4(mv_ic_sc->ic_bst,
+	    mv_ic_sc->ic_bsh, IRQ_MASK));
+}
+
+uint32_t
+mv_ic_get_cause(void)
+{
+
+	return (bus_space_read_4(mv_ic_sc->ic_bst,
+	    mv_ic_sc->ic_bsh, IRQ_CAUSE));
+}
+
+void
+mv_ic_set_mask_hi(uint32_t val)
+{
+
+	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
+	    IRQ_MASK_HI, val);
+}
+
+uint32_t
+mv_ic_get_mask_hi(void)
+{
+
+	return (bus_space_read_4(mv_ic_sc->ic_bst,
+	    mv_ic_sc->ic_bsh, IRQ_MASK_HI));
+}
+
+uint32_t
+mv_ic_get_cause_hi(void)
+{
+
+	return (bus_space_read_4(mv_ic_sc->ic_bst,
+	    mv_ic_sc->ic_bsh, IRQ_CAUSE_HI));
+}
+
+void
+mv_ic_set_mask_error(uint32_t val)
+{
+
+	bus_space_write_4(mv_ic_sc->ic_bst, mv_ic_sc->ic_bsh,
+	    IRQ_MASK_ERROR, val);
+}
+
+uint32_t
+mv_ic_get_mask_error(void)
+{
+
+	return (bus_space_read_4(mv_ic_sc->ic_bst,
+	    mv_ic_sc->ic_bsh, IRQ_MASK_ERROR));
+}
+
+uint32_t
+mv_ic_get_cause_error(void)
+{
+
+	return (bus_space_read_4(mv_ic_sc->ic_bst,
+	    mv_ic_sc->ic_bsh, IRQ_CAUSE_ERROR));
+}
diff --git a/sys/arm/mv/kirkwood/db88f6xxx.c b/sys/arm/mv/kirkwood/db88f6xxx.c
new file mode 100644
index 000000000000..8db9258ffae8
--- /dev/null
+++ b/sys/arm/mv/kirkwood/db88f6xxx.c
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/pte.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+/*
+ * Virtual address space layout:
+ * -----------------------------
+ * 0x0000_0000 - 0xbfff_ffff	: user process
+ *
+ * 0xc040_0000 - virtual_avail	: kernel reserved (text, data, page tables
+ *				: structures, ARM stacks etc.)
+ * virtual_avail - 0xefff_ffff	: KVA (virtual_avail is typically < 0xc0a0_0000)
+ * 0xf000_0000 - 0xf0ff_ffff	: no-cache allocation area (16MB)
+ * 0xf100_0000 - 0xf10f_ffff	: SoC integrated devices registers range (1MB)
+ * 0xf110_0000 - 0xfffe_ffff	: PCIE (MEM+IO) outbound windows (~238MB)
+ * 0xffff_0000 - 0xffff_0fff	: 'high' vectors page (4KB)
+ * 0xffff_1000 - 0xffff_1fff	: ARM_TP_ADDRESS/RAS page (4KB)
+ * 0xffff_2000 - 0xffff_ffff	: unused (~55KB)
+ */
+
+const struct pmap_devmap *pmap_devmap_bootstrap_table;
+vm_offset_t pmap_bootstrap_lastaddr;
+
+/* Static device mappings. */
+static const struct pmap_devmap pmap_devmap[] = {
+	/*
+	 * Map the on-board devices VA == PA so that we can access them
+	 * with the MMU on or off.
+	 */
+	{ /* SoC integrated peripherals registers range */
+		MV_BASE,
+		MV_PHYS_BASE,
+		MV_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ /* PCIE I/O */
+		MV_PCIE_IO_BASE,
+		MV_PCIE_IO_PHYS_BASE,
+		MV_PCIE_IO_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ /* PCIE Memory */
+		MV_PCIE_MEM_BASE,
+		MV_PCIE_MEM_PHYS_BASE,
+		MV_PCIE_MEM_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ 0, 0, 0, 0, 0, }
+};
+
+int
+platform_pmap_init(void)
+{
+
+	pmap_bootstrap_lastaddr = MV_BASE - ARM_NOCACHE_KVA_SIZE;
+	pmap_devmap_bootstrap_table = &pmap_devmap[0];
+
+	return (0);
+}
+
+static void
+platform_identify(void *dummy)
+{
+
+	soc_identify();
+
+	/*
+	 * XXX Board identification e.g. read out from FPGA or similar should
+	 * go here
+	 */
+}
+SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, NULL);
+
+/*
+ * TODO routine setting GPIO/MPP pins 
+ */
diff --git a/sys/arm/mv/kirkwood/files.db88f6xxx b/sys/arm/mv/kirkwood/files.db88f6xxx
new file mode 100644
index 000000000000..c0de03c4f945
--- /dev/null
+++ b/sys/arm/mv/kirkwood/files.db88f6xxx
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+arm/mv/rtc.c			standard
+arm/mv/kirkwood/kirkwood.c	standard
+arm/mv/kirkwood/db88f6xxx.c	standard
diff --git a/sys/arm/mv/kirkwood/kirkwood.c b/sys/arm/mv/kirkwood/kirkwood.c
new file mode 100644
index 000000000000..416c14170520
--- /dev/null
+++ b/sys/arm/mv/kirkwood/kirkwood.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+struct obio_device obio_devices[] = {
+	{ "ic", MV_IC_BASE, MV_IC_SIZE,
+		{ -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "timer", MV_TIMERS_BASE, MV_TIMERS_SIZE,
+		{ MV_INT_BRIDGE, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "rtc", MV_RTC_BASE, MV_RTC_SIZE,
+		{ -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "gpio", MV_GPIO_BASE, MV_GPIO_SIZE,
+		{ MV_INT_GPIO7_0, MV_INT_GPIO15_8,
+		  MV_INT_GPIO23_16, MV_INT_GPIO31_24, 
+		  MV_INT_GPIOHI7_0, MV_INT_GPIOHI15_8,
+		  MV_INT_GPIOHI23_16, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "uart", MV_UART0_BASE, MV_UART_SIZE,
+		{ MV_INT_UART0, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "uart", MV_UART1_BASE, MV_UART_SIZE,
+		{ MV_INT_UART1, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "xor", MV_XOR_BASE, MV_XOR_SIZE,
+		{ MV_INT_XOR0_CHAN0, MV_INT_XOR0_CHAN1,
+		  MV_INT_XOR1_CHAN0, MV_INT_XOR1_CHAN1,
+		  MV_INT_XOR0_ERR, MV_INT_XOR1_ERR,
+		  -1 },
+		{ -1 },
+		CPU_PM_CTRL_XOR0 | CPU_PM_CTRL_XOR1
+	},
+	{ "ehci", MV_USB0_BASE, MV_USB_SIZE,
+		{ MV_INT_USB_BERR, MV_INT_USB_CI, -1 },
+		{ -1 },
+		CPU_PM_CTRL_USB0
+	},
+	{ "mge", MV_ETH0_BASE, MV_ETH_SIZE,
+		{ MV_INT_GBERX, MV_INT_GBETX, MV_INT_GBEMISC,
+		  MV_INT_GBESUM, MV_INT_GBEERR, -1 },
+		{ -1 },
+		CPU_PM_CTRL_GE0
+	},
+	{ "twsi", MV_TWSI_BASE, MV_TWSI_SIZE,
+		{ -1 }, { -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "pcib", MV_PCIE_BASE, MV_PCIE_SIZE,
+		{ MV_INT_PEX0_ERR, -1 },
+		{ -1 },
+		CPU_PM_CTRL_PEX0
+	},
+	{ NULL, 0, 0, { 0 }, { 0 }, 0 }
+};
+
+#if 0
+const struct mv_pci_info pci_info[] = {
+	{ 1,    MV_PCIE_IO_BASE, MV_PCIE_IO_SIZE,
+		MV_PCIE_MEM_BASE, MV_PCIE_MEM_SIZE,
+		NULL, MV_INT_PEX0
+	}
+};
+#endif
+
+struct resource_spec mv_gpio_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		2,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		3,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		4,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		5,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		6,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+struct resource_spec mv_xor_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		2,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		3,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		4,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		5,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+const struct decode_win cpu_win_tbl[] = {
+	/* PCIE IO */
+	{ 4, 0xE0, MV_PCIE_IO_PHYS_BASE, MV_PCIE_IO_SIZE, -1 },
+
+	/* PCIE MEM */
+	{ 4, 0xE8, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
+
+	/* Device bus BOOT */
+	{ 1, 0x0f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
+
+	/* Device bus CS0 */
+	{ 1, 0x1e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
+
+	/* Device bus CS1 */
+	{ 1, 0x1d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
+
+	/* Device bus CS2 */
+	{ 1, 0x1b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
+};
+const struct decode_win *cpu_wins = cpu_win_tbl;
+int cpu_wins_no = sizeof(cpu_win_tbl) / sizeof(struct decode_win);
diff --git a/sys/arm/mv/kirkwood/std.db88f6xxx b/sys/arm/mv/kirkwood/std.db88f6xxx
new file mode 100644
index 000000000000..84af354e5071
--- /dev/null
+++ b/sys/arm/mv/kirkwood/std.db88f6xxx
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+include	"../mv/std.mv"
+files	"../mv/kirkwood/files.db88f6xxx"
+
+makeoptions	KERNPHYSADDR=0x00900000
+makeoptions	KERNVIRTADDR=0xc0900000
+
+options		KERNPHYSADDR=0x00900000
+options		KERNVIRTADDR=0xc0900000
+options		PHYSADDR=0x00000000
+options		PHYSMEM_SIZE=0x20000000
+options		STARTUP_PAGETABLE_ADDR=0x00100000
diff --git a/sys/arm/mv/mv_machdep.c b/sys/arm/mv/mv_machdep.c
new file mode 100644
index 000000000000..fa5ddbd314df
--- /dev/null
+++ b/sys/arm/mv/mv_machdep.c
@@ -0,0 +1,643 @@
+/*-
+ * Copyright (c) 1994-1998 Mark Brinicombe.
+ * Copyright (c) 1994 Brini.
+ * All rights reserved.
+ *
+ * This code is derived from software written for Brini by Mark Brinicombe
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ *    endorse or promote products derived from this software without specific
+ *    prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI OR CONTRIBUTORS 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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/at91/kb920x_machdep.c, rev 45
+ */
+
+#include "opt_msgbuf.h"
+#include "opt_ddb.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysproto.h>
+#include <sys/signalvar.h>
+#include <sys/imgact.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/cons.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/buf.h>
+#include <sys/exec.h>
+#include <sys/kdb.h>
+#include <sys/msgbuf.h>
+#include <machine/reg.h>
+#include <machine/cpu.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+#include <vm/vm_map.h>
+#include <vm/vnode_pager.h>
+#include <machine/pte.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/pcb.h>
+#include <machine/undefined.h>
+#include <machine/machdep.h>
+#include <machine/metadata.h>
+#include <machine/armreg.h>
+#include <machine/bus.h>
+#include <sys/reboot.h>
+#include <machine/bootinfo.h>
+
+#include <arm/mv/mvvar.h>	/* XXX eventually this should be eliminated */
+
+#ifdef  DEBUG
+#define debugf(fmt, args...) printf(fmt, ##args)
+#else
+#define debugf(fmt, args...)
+#endif
+
+#define KERNEL_PT_SYS	0	/* Page table for mapping proc0 zero page */
+#define KERNEL_PT_KERN	1
+
+/*
+ * This is the number of L2 page tables required for covering max
+ * (hypothetical) memsize of 4GB and all kernel mappings (vectors, msgbuf,
+ * stacks etc.), uprounded to be divisible by 4.
+ */
+#define KERNEL_PT_MAX	78
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE	1
+#define ABT_STACK_SIZE	1
+#define UND_STACK_SIZE	1
+
+/* Maximum number of memory regions */
+#define MEM_REGIONS	8
+
+extern unsigned char kernbase[];
+extern unsigned char _etext[];
+extern unsigned char _edata[];
+extern unsigned char __bss_start[];
+extern unsigned char _end[];
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+extern const struct pmap_devmap *pmap_devmap_bootstrap_table;
+extern vm_offset_t pmap_bootstrap_lastaddr;
+
+struct pv_addr kernel_pt_table[KERNEL_PT_MAX];
+
+extern int *end;
+
+struct pcpu __pcpu;
+struct pcpu *pcpup = &__pcpu;
+
+/* Physical and virtual addresses for some global pages */
+
+vm_paddr_t phys_avail[10];
+vm_paddr_t dump_avail[4];
+vm_offset_t physical_pages;
+
+struct pv_addr systempage;
+struct pv_addr msgbufpv;
+struct pv_addr irqstack;
+struct pv_addr undstack;
+struct pv_addr abtstack;
+struct pv_addr kernelstack;
+
+static struct trapframe proc0_tf;
+
+struct mem_region {
+	vm_offset_t	mr_start;
+	vm_size_t	mr_size;
+};
+
+static struct mem_region availmem_regions[MEM_REGIONS];
+static int availmem_regions_sz;
+
+struct bootinfo *bootinfo;
+
+static void print_kenv(void);
+static void print_kernel_section_addr(void);
+static void print_bootinfo(void);
+
+static void physmap_init(int);
+
+static char *
+kenv_next(char *cp)
+{
+
+	if (cp != NULL) {
+		while (*cp != 0)
+			cp++;
+		cp++;
+		if (*cp == 0)
+			cp = NULL;
+	}
+	return (cp);
+}
+
+static void
+print_kenv(void)
+{
+	int len;
+	char *cp;
+
+	debugf("loader passed (static) kenv:\n");
+	if (kern_envp == NULL) {
+		debugf(" no env, null ptr\n");
+		return;
+	}
+	debugf(" kern_envp = 0x%08x\n", (uint32_t)kern_envp);
+
+	len = 0;
+	for (cp = kern_envp; cp != NULL; cp = kenv_next(cp))
+		debugf(" %x %s\n", (uint32_t)cp, cp);
+}
+
+static void
+print_bootinfo(void)
+{
+	struct bi_mem_region *mr;
+	struct bi_eth_addr *eth;
+	int i, j;
+
+	debugf("bootinfo:\n");
+	if (bootinfo == NULL) {
+		debugf(" no bootinfo, null ptr\n");
+		return;
+	}
+
+	debugf(" version = 0x%08x\n", bootinfo->bi_version);
+	debugf(" ccsrbar = 0x%08x\n", bootinfo->bi_bar_base);
+	debugf(" cpu_clk = 0x%08x\n", bootinfo->bi_cpu_clk);
+	debugf(" bus_clk = 0x%08x\n", bootinfo->bi_bus_clk);
+
+	debugf(" mem regions:\n");
+	mr = (struct bi_mem_region *)bootinfo->bi_data;
+	for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++)
+		debugf("    #%d, base = 0x%08x, size = 0x%08x\n", i,
+		    mr->mem_base, mr->mem_size);
+
+	debugf(" eth addresses:\n");
+	eth = (struct bi_eth_addr *)mr;
+	for (i = 0; i < bootinfo->bi_eth_addr_no; i++, eth++) {
+		debugf("    #%d, addr = ", i);
+		for (j = 0; j < 6; j++)
+			debugf("%02x ", eth->mac_addr[j]);
+		debugf("\n");
+	}
+}
+
+static void
+print_kernel_section_addr(void)
+{
+
+	debugf("kernel image addresses:\n");
+	debugf(" kernbase       = 0x%08x\n", (uint32_t)kernbase);
+	debugf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext);
+	debugf(" _edata         = 0x%08x\n", (uint32_t)_edata);
+	debugf(" __bss_start    = 0x%08x\n", (uint32_t)__bss_start);
+	debugf(" _end           = 0x%08x\n", (uint32_t)_end);
+}
+
+struct bi_mem_region *
+bootinfo_mr(void)
+{
+
+	return ((struct bi_mem_region *)bootinfo->bi_data);
+}
+
+static void
+physmap_init(int hardcoded)
+{
+	int i, j, cnt;
+	vm_offset_t phys_kernelend, kernload;
+	uint32_t s, e, sz;
+	struct mem_region *mp, *mp1;
+
+	phys_kernelend = KERNPHYSADDR + (virtual_avail - KERNVIRTADDR);
+	kernload = KERNPHYSADDR;
+
+	/*
+	 * Use hardcoded physical addresses if we don't use memory regions
+	 * from metadata.
+	 */
+	if (hardcoded) {
+		phys_avail[0] = 0;
+		phys_avail[1] = kernload;
+
+		phys_avail[2] = phys_kernelend;
+		phys_avail[3] = PHYSMEM_SIZE;
+
+		phys_avail[4] = 0;
+		phys_avail[5] = 0;
+		return;
+	}
+
+	/*
+	 * Remove kernel physical address range from avail
+	 * regions list. Page align all regions.
+	 * Non-page aligned memory isn't very interesting to us.
+	 * Also, sort the entries for ascending addresses.
+	 */
+	sz = 0;
+	cnt = availmem_regions_sz;
+	debugf("processing avail regions:\n");
+	for (mp = availmem_regions; mp->mr_size; mp++) {
+		s = mp->mr_start;
+		e = mp->mr_start + mp->mr_size;
+		debugf(" %08x-%08x -> ", s, e);
+		/* Check whether this region holds all of the kernel. */
+		if (s < kernload && e > phys_kernelend) {
+			availmem_regions[cnt].mr_start = phys_kernelend;
+			availmem_regions[cnt++].mr_size = e - phys_kernelend;
+			e = kernload;
+		}
+		/* Look whether this regions starts within the kernel. */
+		if (s >= kernload && s < phys_kernelend) {
+			if (e <= phys_kernelend)
+				goto empty;
+			s = phys_kernelend;
+		}
+		/* Now look whether this region ends within the kernel. */
+		if (e > kernload && e <= phys_kernelend) {
+			if (s >= kernload) {
+				goto empty;
+			}
+			e = kernload;
+		}
+		/* Now page align the start and size of the region. */
+		s = round_page(s);
+		e = trunc_page(e);
+		if (e < s)
+			e = s;
+		sz = e - s;
+		debugf("%08x-%08x = %x\n", s, e, sz);
+
+		/* Check whether some memory is left here. */
+		if (sz == 0) {
+		empty:
+			printf("skipping\n");
+			bcopy(mp + 1, mp,
+			    (cnt - (mp - availmem_regions)) * sizeof(*mp));
+			cnt--;
+			mp--;
+			continue;
+		}
+
+		/* Do an insertion sort. */
+		for (mp1 = availmem_regions; mp1 < mp; mp1++)
+			if (s < mp1->mr_start)
+				break;
+		if (mp1 < mp) {
+			bcopy(mp1, mp1 + 1, (char *)mp - (char *)mp1);
+			mp1->mr_start = s;
+			mp1->mr_size = sz;
+		} else {
+			mp->mr_start = s;
+			mp->mr_size = sz;
+		}
+	}
+	availmem_regions_sz = cnt;
+
+	/* Fill in phys_avail table, based on availmem_regions */
+	debugf("fill in phys_avail:\n");
+	for (i = 0, j = 0; i < availmem_regions_sz; i++, j += 2) {
+
+		debugf(" region: 0x%08x - 0x%08x (0x%08x)\n",
+		    availmem_regions[i].mr_start,
+		    availmem_regions[i].mr_start + availmem_regions[i].mr_size,
+		    availmem_regions[i].mr_size);
+
+		phys_avail[j] = availmem_regions[i].mr_start;
+		phys_avail[j + 1] = availmem_regions[i].mr_start +
+		    availmem_regions[i].mr_size;
+	}
+	phys_avail[j] = 0;
+	phys_avail[j + 1] = 0;
+}
+
+void *
+initarm(void *mdp, void *unused __unused)
+{
+	struct pv_addr kernel_l1pt;
+	vm_offset_t freemempos, l2_start, lastaddr;
+	uint32_t memsize, l2size;
+	struct bi_mem_region *mr;
+	void *kmdp;
+	u_int l1pagetable;
+	int i = 0;
+
+	kmdp = NULL;
+	lastaddr = 0;
+	memsize = 0;
+
+	set_cpufuncs();
+
+	/*
+	 * Mask metadata pointer: it is supposed to be on page boundary. If
+	 * the first argument (mdp) doesn't point to a valid address the
+	 * bootloader must have passed us something else than the metadata
+	 * ptr... In this case we want to fall back to some built-in settings.
+	 */
+	mdp = (void *)((uint32_t)mdp & ~PAGE_MASK);
+
+	/* Parse metadata and fetch parameters */
+	if (mdp != NULL) {
+		preload_metadata = mdp;
+		kmdp = preload_search_by_type("elf kernel");
+		if (kmdp != NULL) {
+			bootinfo = (struct bootinfo *)preload_search_info(kmdp,
+			    MODINFO_METADATA|MODINFOMD_BOOTINFO);
+
+			boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
+			kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
+			lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t);
+		}
+
+		/* Initialize memory regions table */
+		mr = bootinfo_mr();
+		for (i = 0; i < bootinfo->bi_mem_reg_no; i++, mr++) {
+			if (i == MEM_REGIONS)
+				break;
+			availmem_regions[i].mr_start = mr->mem_base;
+			availmem_regions[i].mr_size = mr->mem_size;
+			memsize += mr->mem_size;
+		}
+		availmem_regions_sz = i;
+	} else {
+		/* Fall back to hardcoded boothowto flags and metadata. */
+		boothowto = RB_VERBOSE | RB_SINGLE;
+		lastaddr = fake_preload_metadata();
+
+		/*
+		 * Assume a single memory region of size specified in board
+		 * configuration file.
+		 */
+		memsize = PHYSMEM_SIZE;
+	}
+
+	/*
+	 * If memsize is invalid, we can neither proceed nor panic (too
+	 * early for console output).
+	 */
+	if (memsize == 0)
+		while (1);
+
+	/* Platform-specific initialisation */
+	if (platform_pmap_init() != 0)
+		return (NULL);
+
+	pcpu_init(pcpup, 0, sizeof(struct pcpu));
+	PCPU_SET(curthread, &thread0);
+
+	/* Calculate number of L2 tables needed for mapping vm_page_array */
+	l2size = (memsize / PAGE_SIZE) * sizeof(struct vm_page);
+	l2size = (l2size >> L1_S_SHIFT) + 1;
+
+	/*
+	 * Add one table for end of kernel map, one for stacks, msgbuf and
+	 * L1 and L2 tables map and one for vectors map.
+	 */
+	l2size += 3;
+
+	/* Make it divisible by 4 */
+	l2size = (l2size + 3) & ~3;
+
+#define KERNEL_TEXT_BASE (KERNBASE)
+	freemempos = (lastaddr + PAGE_MASK) & ~PAGE_MASK;
+
+	/* Define a macro to simplify memory allocation */
+#define valloc_pages(var, np)                   \
+	alloc_pages((var).pv_va, (np));         \
+	(var).pv_pa = (var).pv_va + (KERNPHYSADDR - KERNVIRTADDR);
+
+#define alloc_pages(var, np)			\
+	(var) = freemempos;		\
+	freemempos += (np * PAGE_SIZE);		\
+	memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+	while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0)
+		freemempos += PAGE_SIZE;
+	valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+
+	for (i = 0; i < l2size; ++i) {
+		if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
+			valloc_pages(kernel_pt_table[i],
+			    L2_TABLE_SIZE / PAGE_SIZE);
+		} else {
+			kernel_pt_table[i].pv_va = freemempos -
+			    (i % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) *
+			    L2_TABLE_SIZE_REAL;
+			kernel_pt_table[i].pv_pa =
+			    kernel_pt_table[i].pv_va - KERNVIRTADDR +
+			    KERNPHYSADDR;
+		}
+	}
+	/*
+	 * Allocate a page for the system page mapped to 0x00000000
+	 * or 0xffff0000. This page will just contain the system vectors
+	 * and can be shared by all processes.
+	 */
+	valloc_pages(systempage, 1);
+
+	/* Allocate stacks for all modes */
+	valloc_pages(irqstack, IRQ_STACK_SIZE);
+	valloc_pages(abtstack, ABT_STACK_SIZE);
+	valloc_pages(undstack, UND_STACK_SIZE);
+	valloc_pages(kernelstack, KSTACK_PAGES);
+	valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE);
+
+	/*
+	 * Now we start construction of the L1 page table
+	 * We start by mapping the L2 page tables into the L1.
+	 * This means that we can replace L1 mappings later on if necessary
+	 */
+	l1pagetable = kernel_l1pt.pv_va;
+
+	/*
+	 * Try to map as much as possible of kernel text and data using
+	 * 1MB section mapping and for the rest of initial kernel address
+	 * space use L2 coarse tables.
+	 *
+	 * Link L2 tables for mapping remainder of kernel (modulo 1MB)
+	 * and kernel structures
+	 */
+	l2_start = lastaddr & ~(L1_S_OFFSET);
+	for (i = 0 ; i < l2size - 1; i++)
+		pmap_link_l2pt(l1pagetable, l2_start + i * L1_S_SIZE,
+		    &kernel_pt_table[KERNEL_PT_KERN + i]);
+
+	pmap_curmaxkvaddr = l2_start + (l2size - 1) * L1_S_SIZE;
+	
+	/* Map kernel code and data */
+	pmap_map_chunk(l1pagetable, KERNVIRTADDR, KERNPHYSADDR,
+	   (((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+
+	/* Map L1 directory and allocated L2 page tables */
+	pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
+	    L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+
+	pmap_map_chunk(l1pagetable, kernel_pt_table[0].pv_va,
+	    kernel_pt_table[0].pv_pa,
+	    L2_TABLE_SIZE_REAL * l2size,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+
+	/* Map allocated stacks and msgbuf */
+	pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa,
+	    freemempos - irqstack.pv_va,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	/* Link and map the vector page */
+	pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
+	    &kernel_pt_table[KERNEL_PT_SYS]);
+	pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	pmap_devmap_bootstrap(l1pagetable, pmap_devmap_bootstrap_table);
+	cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) |
+	    DOMAIN_CLIENT);
+	setttb(kernel_l1pt.pv_pa);
+	cpu_tlb_flushID();
+	cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2));
+	cninit();
+	physmem = memsize / PAGE_SIZE;
+
+	debugf("initarm: console initialized\n");
+	debugf(" arg1 mdp = 0x%08x\n", (uint32_t)mdp);
+	debugf(" boothowto = 0x%08x\n", boothowto);
+	print_bootinfo();
+	print_kernel_section_addr();
+	print_kenv();
+
+	/*
+	 * Re-initialise decode windows
+	 */
+	if (soc_decode_win() != 0)
+		printf("WARNING: could not re-initialise decode windows! "
+		    "Running with existing settings...\n");
+	/*
+	 * Pages were allocated during the secondary bootstrap for the
+	 * stacks for different CPU modes.
+	 * We must now set the r13 registers in the different CPU modes to
+	 * point to these stacks.
+	 * Since the ARM stacks use STMFD etc. we must set r13 to the top end
+	 * of the stack memory.
+	 */
+	cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE);
+	set_stackptr(PSR_IRQ32_MODE,
+	    irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
+	set_stackptr(PSR_ABT32_MODE,
+	    abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
+	set_stackptr(PSR_UND32_MODE,
+	    undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
+
+	/*
+	 * We must now clean the cache again....
+	 * Cleaning may be done by reading new data to displace any
+	 * dirty data in the cache. This will have happened in setttb()
+	 * but since we are boot strapping the addresses used for the read
+	 * may have just been remapped and thus the cache could be out
+	 * of sync. A re-clean after the switch will cure this.
+	 * After booting there are no gross reloations of the kernel thus
+	 * this problem will not occur after initarm().
+	 */
+	cpu_idcache_wbinv_all();
+
+	/* Set stack for exception handlers */
+	data_abort_handler_address = (u_int)data_abort_handler;
+	prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
+	undefined_handler_address = (u_int)undefinedinstruction_bounce;
+	undefined_init();
+
+	proc_linkup0(&proc0, &thread0);
+	thread0.td_kstack = kernelstack.pv_va;
+	thread0.td_kstack_pages = KSTACK_PAGES;
+	thread0.td_pcb = (struct pcb *)
+	    (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1;
+	thread0.td_pcb->pcb_flags = 0;
+	thread0.td_frame = &proc0_tf;
+	pcpup->pc_curpcb = thread0.td_pcb;
+
+	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
+
+	dump_avail[0] = KERNPHYSADDR;
+	dump_avail[1] = KERNPHYSADDR + memsize;
+	dump_avail[2] = 0;
+	dump_avail[3] = 0;
+
+	pmap_bootstrap(freemempos, pmap_bootstrap_lastaddr, &kernel_l1pt);
+	msgbufp = (void *)msgbufpv.pv_va;
+	msgbufinit(msgbufp, MSGBUF_SIZE);
+	mutex_init();
+
+	/*
+	 * Prepare map of physical memory regions available to vm subsystem.
+	 * If metadata pointer doesn't point to a valid address, use hardcoded
+	 * values.
+	 */
+	physmap_init((mdp != NULL) ? 0 : 1);
+
+	/* Do basic tuning, hz etc */
+	init_param1();
+	init_param2(physmem);
+	kdb_init();
+	return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
+	    sizeof(struct pcb)));
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+	return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+	return (0);
+}
diff --git a/sys/arm/mv/mvreg.h b/sys/arm/mv/mvreg.h
new file mode 100644
index 000000000000..68c2314c1b09
--- /dev/null
+++ b/sys/arm/mv/mvreg.h
@@ -0,0 +1,540 @@
+/*-
+ * Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MVREG_H_
+#define _MVREG_H_
+
+#include <machine/intr.h>
+
+/*
+ * Physical addresses of integrated SoC peripherals
+ */
+#define MV_PHYS_BASE		0xF1000000
+#define MV_SIZE			0x100000
+
+/*
+ * Decode windows addresses (physical)
+ */
+#define MV_PCIE_IO_PHYS_BASE	(MV_PHYS_BASE + MV_SIZE)
+#define MV_PCIE_IO_BASE		MV_PCIE_IO_PHYS_BASE
+#define MV_PCIE_IO_SIZE		(1024 * 1024)
+#define MV_PCI_IO_PHYS_BASE	(MV_PCIE_IO_PHYS_BASE + MV_PCIE_IO_SIZE) 
+#define MV_PCI_IO_BASE		MV_PCI_IO_PHYS_BASE
+#define MV_PCI_IO_SIZE		(1024 * 1024)
+
+#define MV_PCIE_MEM_PHYS_BASE	(MV_PCI_IO_PHYS_BASE + MV_PCI_IO_SIZE)
+#define MV_PCIE_MEM_BASE	MV_PCIE_MEM_PHYS_BASE
+#define MV_PCIE_MEM_SIZE	(64 * 1024 * 1024)
+#define MV_PCI_MEM_PHYS_BASE	(MV_PCIE_MEM_PHYS_BASE + MV_PCIE_MEM_SIZE)
+#define MV_PCI_MEM_BASE		MV_PCI_MEM_PHYS_BASE
+#define MV_PCI_MEM_SIZE		(64 * 1024 * 1024)
+
+/* XXX DEV_BOOT, CSx are board specific, should be defined per platform */
+
+/* 512KB NOR FLASH */
+#define MV_DEV_BOOT_PHYS_BASE	(MV_PCI_MEM_PHYS_BASE + MV_PCI_MEM_SIZE)
+#define MV_DEV_BOOT_SIZE		(512 * 1024)
+/* CS0: 7-seg LED */
+#define MV_DEV_CS0_PHYS_BASE	0xFA000000
+#define MV_DEV_CS0_SIZE	(1024 * 1024) /* XXX u-boot has 2MB */
+/* CS1: 32MB NOR FLASH */
+#define MV_DEV_CS1_PHYS_BASE	(MV_DEV_CS0_PHYS_BASE + MV_DEV_CS0_SIZE)
+#define MV_DEV_CS1_SIZE	(32 * 1024 * 1024)
+/* CS2: 32MB NAND FLASH */
+#define MV_DEV_CS2_PHYS_BASE	(MV_DEV_CS1_PHYS_BASE + MV_DEV_CS1_SIZE)
+#define MV_DEV_CS2_SIZE	1024	/* XXX u-boot has 1MB */
+
+/* XXX this is probably not robust against wraparounds... */
+#if ((MV_DEV_CS2_PHYS_BASE + MV_DEV_CS2_SIZE) > 0xFFFEFFFF)
+#error Devices memory layout overlaps reset vectors range!
+#endif
+
+/*
+ * Integrated SoC peripherals addresses
+ */
+#define MV_BASE			MV_PHYS_BASE	/* VA == PA mapping */
+#define MV_DDR_CADR_BASE	(MV_BASE + 0x1500)
+#define MV_MPP_BASE		(MV_BASE + 0x10000)
+#define MV_GPIO_BASE		(MV_BASE + 0x10100)
+#define MV_GPIO_SIZE		0x20
+#define MV_RTC_BASE		(MV_BASE + 0x10300)
+#define MV_RTC_SIZE		0x08
+#define MV_TWSI_BASE		(MV_BASE + 0x11000)
+#define MV_TWSI_SIZE		0x20
+#define MV_UART0_BASE		(MV_BASE + 0x12000)
+#define MV_UART1_BASE		(MV_BASE + 0x12100)
+#define MV_UART_SIZE		0x20
+#define MV_MBUS_BRIDGE_BASE	(MV_BASE + 0x20000)
+#define MV_INTREGS_BASE		(MV_MBUS_BRIDGE_BASE + 0x80)
+#define MV_CPU_CONTROL_BASE	(MV_MBUS_BRIDGE_BASE + 0x100)
+#define MV_IC_BASE		(MV_MBUS_BRIDGE_BASE + 0x200)
+#define MV_IC_SIZE		0x3C
+#define MV_TIMERS_BASE		(MV_MBUS_BRIDGE_BASE + 0x300)
+#define MV_TIMERS_SIZE		0x30
+#define MV_PCI_BASE		(MV_BASE + 0x30000)
+#define MV_PCI_SIZE		0x2000
+#define MV_PCIE_BASE		(MV_BASE + 0x40000)
+#define MV_PCIE_SIZE		0x2000
+#define MV_USB0_BASE		(MV_BASE + 0x50000)
+#define MV_USB1_BASE		(MV_USB0_BASE + 0x1000)
+#define MV_USB2_BASE		(MV_USB0_BASE + 0x2000)
+#define MV_USB_SIZE		0x1000
+#define MV_USB_HOST_OFST	0x0100		/* EHCI HC regs start at this offset within USB range */
+#define MV_USB_AWR_BASE		(MV_USB0_BASE + 0x320)
+#define MV_IDMA_BASE		(MV_BASE + 0x60000)
+#define MV_IDMA_SIZE		0x1000
+#define MV_XOR_BASE		(MV_BASE + 0x60000)
+#define MV_XOR_SIZE		0x1000
+#define MV_ETH0_BASE		(MV_BASE + 0x72000)
+#define MV_ETH1_BASE		(MV_BASE + 0x76000)
+#define MV_ETH_SIZE		0x2000
+
+#define MV_DEV_CS0_BASE	MV_DEV_CS0_PHYS_BASE
+
+/*
+ * Interrupt sources
+ */
+#if defined(SOC_MV_ORION)
+
+#define MV_INT_BRIDGE		0	/* AHB-MBus Bridge Interrupt */
+#define MV_INT_UART0		3	/* UART0 Interrupt */
+#define MV_INT_UART1		4
+#define MV_INT_GPIO7_0		6	/* GPIO[7:0] Interrupt */
+#define MV_INT_GPIO15_8		7	/* GPIO[15:8] Interrupt */
+#define MV_INT_GPIO23_16	8	/* GPIO[23:16] Interrupt */
+#define MV_INT_GPIO31_24	9	/* GPIO[31:24] Interrupt */
+#define MV_INT_PEX0_ERR		10	/* PCI Express Error */
+#define MV_INT_PEX0		11	/* PCI Express INTA,B,C,D Message */
+#define MV_INT_PCI_ERR		15	/* PCI Error */
+#define MV_INT_USB_BERR		16	/* USB Bridge Error */
+#define MV_INT_USB_CI		17	/* USB Controller interrupt */
+#define MV_INT_GBERX		18	/* GbE receive interrupt */
+#define MV_INT_GBETX		19	/* GbE transmit interrupt */
+#define MV_INT_GBEMISC		20	/* GbE misc. interrupt */
+#define MV_INT_GBESUM		21	/* GbE summary interrupt */
+#define MV_INT_GBEERR		22	/* GbE error interrupt */
+#define MV_INT_IDMA_ERR		23	/* DMA error interrupt */
+#define MV_INT_IDMA0		24	/* IDMA chan. 0 completion interrupt */
+#define MV_INT_IDMA1		25	/* IDMA chan. 1 completion interrupt */
+#define MV_INT_IDMA2		26	/* IDMA chan. 2 completion interrupt */
+#define MV_INT_IDMA3		27	/* IDMA chan. 3 completion interrupt */
+#define MV_INT_SATA		29	/* Serial-ATA Interrupt */
+
+#elif defined(SOC_MV_KIRKWOOD)
+
+#define MV_INT_BRIDGE		1	/* AHB-MBus Bridge Interrupt */
+#define MV_INT_XOR0_CHAN0	5	/* XOR engine 0 channel 0 Interrupt */
+#define MV_INT_XOR0_CHAN1	6	/* XOR engine 0 channel 1 Interrupt */
+#define MV_INT_XOR1_CHAN0	7	/* XOR engine 1 channel 0 Interrupt */
+#define MV_INT_XOR1_CHAN1	8	/* XOR engine 1 channel 1 Interrupt */
+#define MV_INT_PEX0		9	/* PCI Express INTA,B,C,D Message */
+#define MV_INT_GBESUM		11	/* GbE0 summary interrupt */
+#define MV_INT_GBERX		12	/* GbE0 receive interrupt */
+#define MV_INT_GBETX		13	/* GbE0 transmit interrupt */
+#define MV_INT_GBEMISC		14	/* GbE0 misc. interrupt */
+#define MV_INT_GBE1SUM		15	/* GbE1 summary interrupt */
+#define MV_INT_GBE1RX		16	/* GbE1 receive interrupt */
+#define MV_INT_GBE1TX		17	/* GbE1 transmit interrupt */
+#define MV_INT_GBE1MISC		18	/* GbE1 misc. interrupt */
+#define MV_INT_USB_CI		19	/* USB Controller interrupt */
+#define MV_INT_SATA		21	/* Serial-ATA Interrupt */
+#define MV_INT_IDMA_ERR		23	/* DMA error interrupt */
+#define MV_INT_UART0		33	/* UART0 Interrupt */
+#define MV_INT_UART1		34
+#define MV_INT_GPIO7_0		35	/* GPIO[7:0] Interrupt */
+#define MV_INT_GPIO15_8		36	/* GPIO[15:8] Interrupt */
+#define MV_INT_GPIO23_16	37	/* GPIO[23:16] Interrupt */
+#define MV_INT_GPIO31_24	38	/* GPIO[31:24] Interrupt */
+#define MV_INT_GPIOHI7_0	39	/* GPIOHI[7:0] Interrupt */
+#define MV_INT_GPIOHI15_8	40	/* GPIOHI[15:8] Interrupt */
+#define MV_INT_GPIOHI23_16	41	/* GPIOHI[23:16] Interrupt */
+#define MV_INT_XOR0_ERR		42	/* XOR engine 0 error Interrupt */
+#define MV_INT_XOR1_ERR		43	/* XOR engine 1 error Interrupt */
+#define MV_INT_PEX0_ERR		44	/* PCI Express Error */
+#define MV_INT_GBEERR		46	/* GbE0 error interrupt */
+#define MV_INT_GBE1ERR		47	/* GbE1 error interrupt */
+#define MV_INT_USB_BERR		48	/* USB Bridge Error */
+
+#elif defined(SOC_MV_DISCOVERY)
+
+#define MV_INT_ERRSUM		0	/* Summary of error interrupts */
+#define MV_INT_SPI		1	/* SPI interrupt */
+#define MV_INT_TWSI0		2	/* TWSI0 interrupt */
+#define MV_INT_TWSI1		3	/* TWSI1 interrupt */
+#define MV_INT_IDMA0		4	/* IDMA Channel0 completion */
+#define MV_INT_IDMA1		5	/* IDMA Channel0 completion */
+#define MV_INT_IDMA2		6	/* IDMA Channel0 completion */
+#define MV_INT_IDMA3		7	/* IDMA Channel0 completion */
+#define MV_INT_TIMER0		8	/* Timer0 interrupt */
+#define MV_INT_TIMER1		9	/* Timer1 interrupt */
+#define MV_INT_TIMER2		10	/* Timer2 interrupt */
+#define MV_INT_TIMER3		11	/* Timer3 interrupt */
+#define MV_INT_UART0		12	/* UART0 interrupt */
+#define MV_INT_UART1		13	/* UART1 interrupt */
+#define MV_INT_UART2		14	/* UART2 interrupt */
+#define MV_INT_UART3		15	/* UART3 interrupt */
+#define MV_INT_USB0		16	/* USB0 interrupt */
+#define MV_INT_USB1		17	/* USB1 interrupt */
+#define MV_INT_USB2		18	/* USB2 interrupt */
+#define MV_INT_CRYPTO		19	/* Crypto engine completion interrupt */
+#define MV_INT_XOR0		22	/* XOR engine 0 completion interrupt */
+#define MV_INT_XOR1		23	/* XOR engine 1 completion interrupt */
+#define MV_INT_SATA		26	/* SATA interrupt */
+#define MV_INT_PEX00		32	/* PCI Express port 0.0 INTA/B/C/D */
+#define MV_INT_PEX01		33	/* PCI Express port 0.1 INTA/B/C/D */
+#define MV_INT_PEX02		34	/* PCI Express port 0.2 INTA/B/C/D */
+#define MV_INT_PEX03		35	/* PCI Express port 0.3 INTA/B/C/D */
+#define MV_INT_PEX10		36	/* PCI Express port 1.0 INTA/B/C/D */
+#define MV_INT_PEX11		37	/* PCI Express port 1.1 INTA/B/C/D */
+#define MV_INT_PEX12		38	/* PCI Express port 1.2 INTA/B/C/D */
+#define MV_INT_PEX13		39	/* PCI Express port 1.3 INTA/B/C/D */
+#define MV_INT_GBESUM		40	/* Gigabit Ethernet Port 0 summary */
+#define MV_INT_GBERX		41	/* Gigabit Ethernet Port 0 Rx summary */
+#define MV_INT_GBETX		42	/* Gigabit Ethernet Port 0 Tx summary */
+#define MV_INT_GBEMISC		43	/* Gigabit Ethernet Port 0 Misc summ. */
+#define MV_INT_GBE1SUM		44	/* Gigabit Ethernet Port 1 summary */
+#define MV_INT_GBE1RX		45	/* Gigabit Ethernet Port 1 Rx summary */
+#define MV_INT_GBE1TX		46	/* Gigabit Ethernet Port 1 Tx summary */
+#define MV_INT_GBE1MISC		47	/* Gigabit Ethernet Port 1 Misc summ. */
+#define MV_INT_GPIO7_0		56	/* GPIO[7:0] Interrupt */
+#define MV_INT_GPIO15_8		57	/* GPIO[15:8] Interrupt */
+#define MV_INT_GPIO23_16	58	/* GPIO[23:16] Interrupt */
+#define MV_INT_GPIO31_24	59	/* GPIO[31:24] Interrupt */
+#define MV_INT_DB_IN		60	/* Inbound Doorbell Cause reg Summary */
+#define MV_INT_DB_OUT		61	/* Outbound Doorbell Cause reg Summ. */
+#define MV_INT_CRYPT_ERR	64	/* Crypto engine error */
+#define MV_INT_DEV_ERR		65	/* Device bus error */
+#define MV_INT_IDMA_ERR		66	/* DMA error */
+#define MV_INT_CPU_ERR		67	/* CPU error */
+#define MV_INT_PEX0_ERR		68	/* PCI-Express port0 error */
+#define MV_INT_PEX1_ERR		69	/* PCI-Express port1 error */
+#define MV_INT_GBE_ERR		70	/* Gigabit Ethernet error */
+#define MV_INT_USB_ERR		72	/* USB error */
+#define MV_INT_DRAM_ERR		73	/* DRAM ECC error */
+#define MV_INT_XOR_ERR		74	/* XOR engine error */
+#define MV_INT_WD		79	/* WD Timer interrupt */
+
+#endif /* SOC_MV_ORION */
+
+#define BRIDGE_IRQ_CAUSE	0x10
+#define BRIGDE_IRQ_MASK		0x14
+
+#if defined(SOC_MV_DISCOVERY)
+#define IRQ_CAUSE_ERROR		0x0
+#define IRQ_CAUSE		0x4
+#define IRQ_CAUSE_HI		0x8
+#define IRQ_MASK_ERROR		0xC
+#define IRQ_MASK		0x10
+#define IRQ_MASK_HI		0x14
+#define IRQ_CAUSE_SELECT	0x18
+#define FIQ_MASK_ERROR		0x1C
+#define FIQ_MASK		0x20
+#define FIQ_MASK_HI		0x24
+#define FIQ_CAUSE_SELECT	0x28
+#define ENDPOINT_IRQ_MASK_ERROR	0x2C
+#define ENDPOINT_IRQ_MASK	0x30
+#define ENDPOINT_IRQ_MASK_HI	0x34
+#define ENDPOINT_IRQ_CAUSE_SELECT 0x38
+#else /* !SOC_MV_DISCOVERY */
+#define IRQ_CAUSE		0x0
+#define IRQ_MASK		0x4
+#define FIQ_MASK		0x8
+#define ENDPOINT_IRQ_MASK	0xC
+#define IRQ_CAUSE_HI		0x10
+#define IRQ_MASK_HI		0x14
+#define FIQ_MASK_HI		0x18
+#define ENDPOINT_IRQ_MASK_HI	0x1C
+#define IRQ_CAUSE_ERROR		(-1)		/* Fake defines for unified */
+#define IRQ_MASK_ERROR		(-1)		/* interrupt controller code */
+#endif
+
+#define BRIDGE_IRQ_CAUSE	0x10
+#define IRQ_CPU_SELF		0x00000001
+#define IRQ_TIMER0		0x00000002
+#define IRQ_TIMER1		0x00000004
+#define IRQ_TIMER_WD		0x00000008
+
+#define BRIDGE_IRQ_MASK		0x14
+#define IRQ_CPU_MASK		0x00000001
+#define IRQ_TIMER0_MASK		0x00000002
+#define IRQ_TIMER1_MASK		0x00000004
+#define IRQ_TIMER_WD_MASK	0x00000008
+
+/*
+ * System reset
+ */
+#define RSTOUTn_MASK		0x8
+#define WD_RST_OUT_EN		0x00000002
+#define SOFT_RST_OUT_EN		0x00000004
+#define SYSTEM_SOFT_RESET	0xc
+#define SYS_SOFT_RST		0x00000001
+
+/*
+ * Power Control
+ */
+#define CPU_PM_CTRL		0x1C
+#define CPU_PM_CTRL_NONE	0
+
+#if defined(SOC_MV_KIRKWOOD)
+#define CPU_PM_CTRL_GE0		(1 << 0)
+#define CPU_PM_CTRL_PEX0_PHY	(1 << 1)
+#define CPU_PM_CTRL_PEX0	(1 << 2)
+#define CPU_PM_CTRL_USB0	(1 << 3)
+#define CPU_PM_CTRL_SDIO	(1 << 4)
+#define CPU_PM_CTRL_TSU		(1 << 5)
+#define CPU_PM_CTRL_DUNIT	(1 << 6)
+#define CPU_PM_CTRL_RUNIT	(1 << 7)
+#define CPU_PM_CTRL_XOR0	(1 << 8)
+#define CPU_PM_CTRL_AUDIO	(1 << 9)
+#define CPU_PM_CTRL_SATA0	(1 << 14)
+#define CPU_PM_CTRL_SATA1	(1 << 15)
+#define CPU_PM_CTRL_XOR1	(1 << 16)
+#define CPU_PM_CTRL_CRYPTO	(1 << 17)
+#define CPU_PM_CTRL_GE1		(1 << 18)
+#define CPU_PM_CTRL_TDM		(1 << 19)
+#elif defined(SOC_MV_DISCOVERY)
+#define CPU_PM_CTRL_GE0		(1 << 1)
+#define CPU_PM_CTRL_GE1		(1 << 2)
+#define CPU_PM_CTRL_PEX00	(1 << 5)
+#define CPU_PM_CTRL_PEX01	(1 << 6)
+#define CPU_PM_CTRL_PEX02	(1 << 7)
+#define CPU_PM_CTRL_PEX03	(1 << 8)
+#define CPU_PM_CTRL_PEX10	(1 << 9)
+#define CPU_PM_CTRL_PEX11	(1 << 10)
+#define CPU_PM_CTRL_PEX12	(1 << 11)
+#define CPU_PM_CTRL_PEX13	(1 << 12)
+#define CPU_PM_CTRL_SATA0_PHY	(1 << 13)
+#define CPU_PM_CTRL_SATA0	(1 << 14)
+#define CPU_PM_CTRL_SATA1_PHY	(1 << 15)
+#define CPU_PM_CTRL_SATA1	(1 << 16)
+#define CPU_PM_CTRL_USB0	(1 << 17)
+#define CPU_PM_CTRL_USB1	(1 << 18)
+#define CPU_PM_CTRL_USB2	(1 << 19)
+#define CPU_PM_CTRL_IDMA	(1 << 20)
+#define CPU_PM_CTRL_XOR		(1 << 21)
+#define CPU_PM_CTRL_CRYPTO	(1 << 22)
+#define CPU_PM_CTRL_DEVICE	(1 << 23)
+#endif
+
+/*
+ * Timers
+ */
+#define CPU_TIMER_CONTROL	0x0
+#define CPU_TIMER0_EN		0x00000001
+#define CPU_TIMER0_AUTO		0x00000002
+#define CPU_TIMER1_EN		0x00000004
+#define CPU_TIMER1_AUTO		0x00000008
+#define CPU_TIMER_WD_EN		0x00000010
+#define CPU_TIMER_WD_AUTO	0x00000020
+#define CPU_TIMER0_REL		0x10
+#define CPU_TIMER0		0x14
+
+/*
+ * GPIO
+ */
+#define GPIO_DATA_OUT		0x00
+#define GPIO_DATA_OUT_EN_CTRL	0x04
+#define GPIO_BLINK_EN		0x08
+#define GPIO_DATA_IN_POLAR	0x0c
+#define GPIO_DATA_IN		0x10
+#define GPIO_INT_CAUSE		0x14
+#define GPIO_INT_EDGE_MASK	0x18
+#define GPIO_INT_LEV_MASK	0x1c
+
+#define GPIO_HI_DATA_OUT		0x40
+#define GPIO_HI_DATA_OUT_EN_CTRL	0x44
+#define GPIO_HI_BLINK_EN		0x48
+#define GPIO_HI_DATA_IN_POLAR		0x4c
+#define GPIO_HI_DATA_IN			0x50
+#define GPIO_HI_INT_CAUSE		0x54
+#define GPIO_HI_INT_EDGE_MASK		0x58
+#define GPIO_HI_INT_LEV_MASK		0x5c
+
+#define GPIO(n)			(1 << (n))
+#define MV_GPIO_MAX_NPINS	64
+
+#define MV_GPIO_BLINK		0x1
+#define MV_GPIO_POLARITY	0x2
+#define MV_GPIO_EDGE		0x4
+#define MV_GPIO_LEVEL		0x8
+
+#define IS_GPIO_IRQ(irq)	((irq) >= NIRQ && (irq) < NIRQ + MV_GPIO_MAX_NPINS)
+#define GPIO2IRQ(gpio)		((gpio) + NIRQ)
+#define IRQ2GPIO(irq)		((irq) - NIRQ)
+
+/*
+ * MPP
+ */
+#define MPP_CONTROL0		0x00
+#define MPP_CONTROL1		0x04
+#define MPP_CONTROL2		0x50
+#define DEVICE_MULTIPLEX	0x08
+
+#if defined(SOC_MV_ORION)
+#define SAMPLE_AT_RESET		0x10
+#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
+#define SAMPLE_AT_RESET		0x30
+#else
+#error SOC_MV_XX not defined
+#endif
+
+/*
+ * Clocks
+ */
+#ifdef SOC_MV_ORION
+#define TCLK_MASK		0x300
+#define TCLK_SHIFT		0x8
+#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
+#define TCLK_MASK		0x30000
+#define TCLK_SHIFT		0x10
+#else
+#error SOC_MV_XX not defined
+#endif
+
+#define TCLK_100MHZ		100000000
+#define TCLK_125MHZ		125000000
+#define TCLK_133MHZ		133333333
+#define TCLK_150MHZ		150000000
+#define TCLK_166MHZ		166666667
+#define TCLK_200MHZ		200000000
+
+/*
+ * Chip ID
+ */
+#define MV_DEV_88F5181	0x5181
+#define MV_DEV_88F5182	0x5182
+#define MV_DEV_88F5281	0x5281
+#define MV_DEV_88F6281	0x6281
+#define MV_DEV_MV78100	0x6381
+
+/*
+ * Decode windows definitions and macros
+ */
+#define MV_WIN_CPU_CTRL(n)		(0x10 * (n) + (((n) < 8) ? 0x000 : 0x880))
+#define MV_WIN_CPU_BASE(n)		(0x10 * (n) + (((n) < 8) ? 0x004 : 0x884))
+#define MV_WIN_CPU_REMAP_LO(n)		(0x10 * (n) + (((n) < 8) ? 0x008 : 0x888))
+#define MV_WIN_CPU_REMAP_HI(n)		(0x10 * (n) + (((n) < 8) ? 0x00C : 0x88C))
+#if defined(SOC_MV_DISCOVERY)
+#define MV_WIN_CPU_MAX			14
+#else
+#define MV_WIN_CPU_MAX			8
+#endif
+
+#define MV_WIN_DDR_BASE(n)		(0x8 * (n) + 0x0)
+#define MV_WIN_DDR_SIZE(n)		(0x8 * (n) + 0x4)
+#define MV_WIN_DDR_MAX			4
+
+#define MV_WIN_USB_CTRL(n)		(0x10 * (n) + 0x0)
+#define MV_WIN_USB_BASE(n)		(0x10 * (n) + 0x4)
+#define MV_WIN_USB_MAX			4
+
+#define MV_WIN_ETH_BASE(n)		(0x8 * (n) + 0x200)
+#define MV_WIN_ETH_SIZE(n)		(0x8 * (n) + 0x204)
+#define MV_WIN_ETH_REMAP(n)		(0x4 * (n) + 0x280)
+#define MV_WIN_ETH_MAX			6
+
+#define MV_WIN_IDMA_BASE(n)		(0x8 * (n) + 0xa00)
+#define MV_WIN_IDMA_SIZE(n)		(0x8 * (n) + 0xa04)
+#define MV_WIN_IDMA_REMAP(n)		(0x4 * (n) + 0xa60)
+#define MV_WIN_IDMA_CAP(n)		(0x4 * (n) + 0xa70)
+#define MV_WIN_IDMA_MAX			8
+#define MV_IDMA_CHAN_MAX		4
+
+#define MV_WIN_PCIE_CTRL(n)		(0x10 * (((n) < 5) ? (n) : \
+					    (n) + 1) + 0x1820)
+#define MV_WIN_PCIE_BASE(n)		(0x10 * (((n) < 5) ? (n) : \
+					    (n) + 1) + 0x1824)
+#define MV_WIN_PCIE_REMAP(n)		(0x10 * (((n) < 5) ? (n) : \
+					    (n) + 1) + 0x182C)
+#define MV_WIN_PCIE_MAX			6
+
+#define MV_PCIE_BAR(n)			(0x04 * (n) + 0x1804)
+#define MV_PCIE_BAR_MAX			3
+
+#define WIN_REG_IDX_RD(pre,reg,off,base)					\
+	static __inline uint32_t						\
+	pre ## _ ## reg ## _read(int i)						\
+	{									\
+		return (bus_space_read_4(obio_tag, base, off(i)));		\
+	}
+
+#define WIN_REG_BASE_IDX_RD(pre,reg,off)					\
+	static __inline uint32_t						\
+	pre ## _ ## reg ## _read(uint32_t base, int i)				\
+	{									\
+		return (bus_space_read_4(obio_tag, base, off(i)));		\
+	}
+
+#define WIN_REG_IDX_WR(pre,reg,off,base)					\
+	static __inline void							\
+	pre ## _ ## reg ## _write(int i, uint32_t val)				\
+	{									\
+		bus_space_write_4(obio_tag, base, off(i), val);			\
+	}
+
+#define WIN_REG_BASE_IDX_WR(pre,reg,off)					\
+	static __inline void							\
+	pre ## _ ## reg ## _write(uint32_t base, int i, uint32_t val)		\
+	{									\
+		bus_space_write_4(obio_tag, base, off(i), val);			\
+	}
+
+#define WIN_REG_RD(pre,reg,off,base)						\
+	static __inline uint32_t						\
+	pre ## _ ## reg ## _read(void)						\
+	{									\
+		return (bus_space_read_4(obio_tag, base, off));			\
+	}
+
+#define WIN_REG_BASE_RD(pre,reg,off)						\
+	static __inline uint32_t						\
+	pre ## _ ## reg ## _read(uint32_t base)					\
+	{									\
+		return (bus_space_read_4(obio_tag, base, off));			\
+	}
+
+#define WIN_REG_WR(pre,reg,off,base)						\
+	static __inline void							\
+	pre ## _ ## reg ## _write(uint32_t val)					\
+	{									\
+		bus_space_write_4(obio_tag, base, off, val);			\
+	}
+
+#define WIN_REG_BASE_WR(pre,reg,off)						\
+	static __inline void							\
+	pre ## _ ## reg ## _write(uint32_t base, uint32_t val)			\
+	{									\
+		bus_space_write_4(obio_tag, base, off, val);			\
+	}
+
+#endif /* _MVREG_H_ */
diff --git a/sys/arm/mv/mvvar.h b/sys/arm/mv/mvvar.h
new file mode 100644
index 000000000000..cdf87c9e9ef8
--- /dev/null
+++ b/sys/arm/mv/mvvar.h
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2002, 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed for the NetBSD Project by
+ *	Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0var.h, rev 1
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MVVAR_H_
+#define _MVVAR_H_
+
+#include <sys/rman.h>
+
+struct obio_softc {
+	bus_space_tag_t obio_bst;	/* bus space tag */
+	struct rman	obio_mem;
+	struct rman	obio_irq;
+	struct rman	obio_gpio;
+};
+
+struct obio_device {
+	const char	*od_name;
+	u_long		od_base;
+	u_long		od_size;
+	u_int		od_irqs[7 + 1];	/* keep additional entry for -1 sentinel */
+	u_int		od_gpio[2 + 1]; /* as above for IRQ */
+	u_int		od_pwr_mask;
+	struct resource_list od_resources;
+};
+
+struct decode_win {
+	int		target;		/* Mbus unit ID */
+	int		attr;		/* Attributes of the target interface */
+	vm_paddr_t	base;		/* Physical base addr */
+	uint32_t	size;
+	int		remap;
+};
+
+extern bus_space_tag_t		obio_tag;
+extern struct obio_device	obio_devices[];
+extern const struct decode_win	*cpu_wins;
+extern const struct decode_win	*idma_wins;
+extern int	cpu_wins_no;
+extern int	idma_wins_no;
+
+/* Function prototypes */
+int	mv_gpio_setup_intrhandler(const char *name, driver_filter_t *filt, 
+    void (*hand)(void *), void *arg, int pin, int flags, void **cookiep);
+void	mv_gpio_intr_mask(int pin);
+void	mv_gpio_intr_unmask(int pin);
+int	mv_gpio_configure(uint32_t pin, uint32_t flags, uint32_t mask);
+void	mv_gpio_out(uint32_t pin, uint8_t val, uint8_t enable);
+uint8_t	mv_gpio_in(uint32_t pin);
+
+int	platform_pmap_init(void);
+int	soc_decode_win(void);
+void	soc_id(uint32_t *dev, uint32_t *rev);
+void	soc_identify(void);
+void	soc_dump_decode_win(void);
+uint32_t soc_power_ctrl_get(uint32_t mask);
+
+int decode_win_overlap(int, int, const struct decode_win *);
+int win_cpu_can_remap(int);
+
+void	decode_win_idma_dump(void);
+void	decode_win_idma_setup(void);
+int	decode_win_idma_valid(void);
+
+int		ddr_is_active(int i);
+uint32_t	ddr_base(int i);
+uint32_t	ddr_size(int i);
+uint32_t	ddr_attr(int i);
+uint32_t	ddr_target(int i);
+
+uint32_t	cpu_extra_feat(void);
+uint32_t	get_tclk(void);
+uint32_t	read_cpu_ctrl(uint32_t);
+void		write_cpu_ctrl(uint32_t, uint32_t);
+
+enum mbus_device_ivars {
+	MBUS_IVAR_BASE,
+};
+
+#define	MBUS_ACCESSOR(var, ivar, type)	\
+	__BUS_ACCESSOR(mbus, var, MBUS, ivar, type)
+
+MBUS_ACCESSOR(base,	BASE,	u_long)
+
+#undef	MBUS_ACCESSOR
+
+#endif /* _MVVAR_H_ */
diff --git a/sys/arm/mv/obio.c b/sys/arm/mv/obio.c
new file mode 100644
index 000000000000..bd757a5913d6
--- /dev/null
+++ b/sys/arm/mv/obio.c
@@ -0,0 +1,355 @@
+/*-
+ * Copyright (c) 2006 Benno Rice.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_obio.c, rev 1
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <arm/mv/mvvar.h>
+#include <arm/mv/mvreg.h>
+
+static void	mbus_identify(driver_t *, device_t);
+static int	mbus_probe(device_t);
+static int	mbus_attach(device_t);
+
+static void
+mbus_identify(driver_t *driver, device_t parent)
+{
+
+	BUS_ADD_CHILD(parent, 0, "mbus", 0);
+}
+
+static int
+mbus_probe(device_t dev)
+{
+
+	device_set_desc(dev, "Marvell Internal Bus (Mbus)");
+	return (0);
+}
+
+static int
+mbus_attach(device_t dev)
+{
+	struct		obio_softc *sc;
+	struct		obio_device *od;
+	int		i;
+	device_t	child;
+
+	sc = device_get_softc(dev);
+
+	sc->obio_bst = obio_tag;
+
+	sc->obio_mem.rm_type = RMAN_ARRAY;
+	sc->obio_mem.rm_descr = "Marvell OBIO Memory";
+	if (rman_init(&sc->obio_mem) != 0)
+		panic("mbus_attach: failed to init obio mem rman");
+	if (rman_manage_region(&sc->obio_mem, 0, ~0) != 0)
+		panic("mbus_attach: failed to set up obio mem rman");
+
+	sc->obio_irq.rm_type = RMAN_ARRAY;
+	sc->obio_irq.rm_descr = "Marvell OBIO IRQ";
+	if (rman_init(&sc->obio_irq) != 0)
+		panic("mbus_attach: failed to init obio irq rman");
+	if (rman_manage_region(&sc->obio_irq, 0, NIRQ - 1) != 0)
+		panic("mbus_attach: failed to set up obio irq rman");
+
+	sc->obio_gpio.rm_type = RMAN_ARRAY;
+	sc->obio_gpio.rm_descr = "Marvell GPIO";
+	if (rman_init(&sc->obio_gpio) != 0)
+		panic("mbus_attach: failed to init gpio rman");
+	if (rman_manage_region(&sc->obio_gpio, 0, MV_GPIO_MAX_NPINS - 1) != 0)
+		panic("mbus_attach: failed to set up gpio rman");
+
+	for (od = obio_devices; od->od_name != NULL; od++) {
+		if (soc_power_ctrl_get(od->od_pwr_mask) != od->od_pwr_mask)
+			continue;
+
+		resource_list_init(&od->od_resources);
+
+		resource_list_add(&od->od_resources, SYS_RES_MEMORY, 0,
+		    od->od_base, od->od_base + od->od_size, od->od_size);
+
+		for (i = 0; od->od_irqs[i] != -1; i++) {
+			resource_list_add(&od->od_resources, SYS_RES_IRQ, i,
+			    od->od_irqs[i], od->od_irqs[i], 1);
+		}
+
+		for (i = 0; od->od_gpio[i] != -1; i++) {
+			resource_list_add(&od->od_resources, SYS_RES_GPIO, i,
+			    od->od_gpio[i], od->od_gpio[i], 1);
+		}
+
+		child = device_add_child(dev, od->od_name, -1);
+		device_set_ivars(child, od);
+	}
+
+	bus_generic_probe(dev);
+	bus_generic_attach(dev);
+
+	return (0);
+}
+
+static int
+mbus_print_child(device_t dev, device_t child)
+{
+	struct	obio_device *od;
+	int	rv;
+
+	od = (struct obio_device *)device_get_ivars(child);
+	if (od == NULL)
+		panic("Unknown device on %s", device_get_nameunit(dev));
+
+	rv = 0;
+
+	rv += bus_print_child_header(dev, child);
+
+	rv += resource_list_print_type(&od->od_resources, "at mem",
+	    SYS_RES_MEMORY, "0x%08lx");
+	rv += resource_list_print_type(&od->od_resources, "irq",
+	    SYS_RES_IRQ, "%ld");
+	rv += resource_list_print_type(&od->od_resources, "gpio",
+	    SYS_RES_GPIO, "%ld");
+
+	if (device_get_flags(child))
+		rv += printf(" flags %#x", device_get_flags(child));
+	rv += bus_print_child_footer(dev, child);
+
+	return (rv);
+}
+
+static int
+mbus_setup_intr(device_t dev, device_t child, struct resource *ires, int flags,
+    driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
+{
+	struct	obio_softc *sc;
+	int error;
+
+	sc = (struct obio_softc *)device_get_softc(dev);
+
+	if (rman_is_region_manager(ires, &sc->obio_gpio)) {
+		error = mv_gpio_setup_intrhandler(
+		    device_get_nameunit(child), filt, intr, arg,
+		    rman_get_start(ires), flags, cookiep);
+
+		if (error != 0)
+			return (error);
+
+		mv_gpio_intr_unmask(rman_get_start(ires));
+		return (0);
+	}
+
+	BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, intr, arg,
+	    cookiep);
+	arm_unmask_irq(rman_get_start(ires));
+	return (0);
+}
+
+static int
+mbus_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie)
+{
+
+	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, ires, cookie));
+}
+
+static int
+mbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+	struct	obio_device *od;
+
+	od = (struct obio_device *)device_get_ivars(child);
+
+	switch (which) {
+	case MBUS_IVAR_BASE:
+		*((u_long *)result) = od->od_base;
+		break;
+
+	default:
+		return (ENOENT);
+	}
+
+	return (0);
+}
+
+static struct resource_list *
+mbus_get_resource_list(device_t dev, device_t child)
+{
+	struct	obio_device *od;
+
+	od = (struct obio_device *)device_get_ivars(child);
+
+	if (od == NULL)
+		return (NULL);
+
+	return (&od->od_resources);
+}
+
+static struct resource *
+mbus_alloc_resource(device_t dev, device_t child, int type, int *rid,
+    u_long start, u_long end, u_long count, u_int flags)
+{
+	struct	obio_softc *sc;
+	struct	obio_device *od;
+	struct	resource *rv;
+	struct	resource_list *rl;
+	struct	resource_list_entry *rle = NULL;
+	struct	rman *rm;
+	int	needactivate;
+
+	sc = (struct obio_softc *)device_get_softc(dev);
+
+	if (type == SYS_RES_IRQ && IS_GPIO_IRQ(start)) {
+		type = SYS_RES_GPIO;
+		start = IRQ2GPIO(start);
+	}
+
+	switch (type) {
+	case SYS_RES_IRQ:
+		rm = &sc->obio_irq;
+		break;
+	case SYS_RES_MEMORY:
+		rm = &sc->obio_mem;
+		break;
+	case SYS_RES_GPIO:
+		rm = &sc->obio_gpio;
+		break;
+	default:
+		return (NULL);
+	}
+
+	if (device_get_parent(child) == dev) {
+		od = (struct obio_device *)device_get_ivars(child);
+		rl = &od->od_resources;
+		rle = resource_list_find(rl, type, *rid);
+
+		if (rle->res != NULL)
+			panic("mbus_alloc_resource: resource is busy");
+	}
+
+	if (rle) {
+		start = rle->start;
+		end = rle->end;
+		count = rle->count;
+	}
+
+	needactivate = flags & RF_ACTIVE;
+	flags &= ~RF_ACTIVE;
+	rv = rman_reserve_resource(rm, start, end, count, flags, child);
+
+	if (rv == NULL)
+		return (NULL);
+
+	if (rle)
+		rle->res = rv;
+
+	rman_set_rid(rv, *rid);
+
+	if (type == SYS_RES_MEMORY) {
+		rman_set_bustag(rv, sc->obio_bst);
+		rman_set_bushandle(rv, start);
+	}
+
+	if (needactivate)
+		if (bus_activate_resource(child, type, *rid, rv)) {
+			rman_release_resource(rv);
+			return (NULL);
+		}
+
+	return (rv);
+}
+
+static int
+mbus_release_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+	struct	obio_device *od;
+	struct	resource_list *rl;
+	struct	resource_list_entry *rle;
+
+	if (device_get_parent(child) == dev) {
+		od = (struct obio_device *)device_get_ivars(child);
+		rl = &od->od_resources;
+		rle = resource_list_find(rl, type, rid);
+
+		if (!rle)
+			panic("mbus_release_resource: can't find resource");
+
+		if (!rle->res)
+			panic("mbus_release_resource: resource entry is not busy");
+
+		r = rle->res;
+		rle->res = NULL;
+	}
+
+	rman_release_resource(r);
+
+	return (0);
+}
+
+static int
+mbus_activate_resource(device_t dev, device_t child, int type, int rid,
+    struct resource *r)
+{
+
+	return (rman_activate_resource(r));
+}
+
+static device_method_t mbus_methods[] = {
+	DEVMETHOD(device_identify,	mbus_identify),
+	DEVMETHOD(device_probe,		mbus_probe),
+	DEVMETHOD(device_attach,	mbus_attach),
+
+	DEVMETHOD(bus_print_child,	mbus_print_child),
+
+	DEVMETHOD(bus_read_ivar,	mbus_read_ivar),
+	DEVMETHOD(bus_setup_intr,	mbus_setup_intr),
+	DEVMETHOD(bus_teardown_intr,	mbus_teardown_intr),
+
+	DEVMETHOD(bus_get_resource_list,	mbus_get_resource_list),
+	DEVMETHOD(bus_alloc_resource,		mbus_alloc_resource),
+	DEVMETHOD(bus_release_resource,		mbus_release_resource),
+	DEVMETHOD(bus_activate_resource,	mbus_activate_resource),
+
+	{0, 0}
+};
+
+static driver_t mbus_driver = {
+	"mbus",
+	mbus_methods,
+	sizeof(struct obio_softc),
+};
+
+static devclass_t mbus_devclass;
+
+DRIVER_MODULE(mbus, nexus, mbus_driver, mbus_devclass, 0, 0);
diff --git a/sys/arm/mv/orion/db88f5xxx.c b/sys/arm/mv/orion/db88f5xxx.c
new file mode 100644
index 000000000000..5c333b4dfca8
--- /dev/null
+++ b/sys/arm/mv/orion/db88f5xxx.c
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/pte.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+/*
+ * Virtual address space layout:
+ * -----------------------------
+ * 0x0000_0000 - 0xbfff_ffff	: user process
+ *
+ * 0xc040_0000 - virtual_avail	: kernel reserved (text, data, page tables
+ *				: structures, ARM stacks etc.)
+ * virtual_avail - 0xefff_ffff	: KVA (virtual_avail is typically < 0xc0a0_0000)
+ * 0xf000_0000 - 0xf0ff_ffff	: no-cache allocation area (16MB)
+ * 0xf100_0000 - 0xf10f_ffff	: SoC integrated devices registers range (1MB)
+ * 0xf110_0000 - 0xfffe_ffff	: PCI, PCIE (MEM+IO) outbound windows (~238MB)
+ * 0xffff_0000 - 0xffff_0fff	: 'high' vectors page (4KB)
+ * 0xffff_1000 - 0xffff_1fff	: ARM_TP_ADDRESS/RAS page (4KB)
+ * 0xffff_2000 - 0xffff_ffff	: unused (~55KB)
+ */
+
+const struct pmap_devmap *pmap_devmap_bootstrap_table;
+vm_offset_t pmap_bootstrap_lastaddr;
+
+/* Static device mappings. */
+static const struct pmap_devmap pmap_devmap[] = {
+	/*
+	 * Map the on-board devices VA == PA so that we can access them
+	 * with the MMU on or off.
+	 */
+	{ /* SoC integrated peripherals registers range */
+		MV_BASE,
+		MV_PHYS_BASE,
+		MV_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ /* PCIE I/O */
+		MV_PCIE_IO_BASE,
+		MV_PCIE_IO_PHYS_BASE,
+		MV_PCIE_IO_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ /* PCIE Memory */
+		MV_PCIE_MEM_BASE,
+		MV_PCIE_MEM_PHYS_BASE,
+		MV_PCIE_MEM_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ /* PCI I/O */
+		MV_PCI_IO_BASE,
+		MV_PCI_IO_PHYS_BASE,
+		MV_PCI_IO_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ /* PCI Memory */
+		MV_PCI_MEM_BASE,
+		MV_PCI_MEM_PHYS_BASE,
+		MV_PCI_MEM_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ /* 7-seg LED */
+		MV_DEV_CS0_BASE,
+		MV_DEV_CS0_PHYS_BASE,
+		MV_DEV_CS0_SIZE,
+		VM_PROT_READ | VM_PROT_WRITE,
+		PTE_NOCACHE,
+	},
+	{ 0, 0, 0, 0, 0, }
+};
+
+#if 0
+int platform_pci_get_irq(u_int bus, u_int slot, u_int func, u_int pin)
+{
+	int irq;
+
+	switch (slot) {
+	case 7:
+		irq = GPIO2IRQ(12);	/* GPIO 0 for DB-88F5182  */
+		break;			/* GPIO 12 for DB-88F5281 */
+	case 8:
+	case 9:
+		irq = GPIO2IRQ(13);	/* GPIO 1 for DB-88F5182  */
+		break;			/* GPIO 13 for DB-88F5281 */
+	default:
+		irq = -1;
+		break;
+	};
+
+	/*
+	 * XXX This isn't the right place to setup GPIO, but it makes sure
+	 * that PCI works on 5XXX targets where U-Boot doesn't set up the GPIO
+	 * correctly to handle PCI IRQs (e.g., on 5182). This code will go
+	 * away once we set up GPIO in a generic way in a proper place (TBD).
+	 */
+	if (irq >= 0)
+		mv_gpio_configure(IRQ2GPIO(irq), MV_GPIO_POLARITY |
+		    MV_GPIO_LEVEL, ~0u);
+
+	return(irq);
+}
+#endif
+
+int
+platform_pmap_init(void)
+{
+
+	pmap_bootstrap_lastaddr = MV_BASE - ARM_NOCACHE_KVA_SIZE;
+	pmap_devmap_bootstrap_table = &pmap_devmap[0];
+
+	return (0);
+}
+
+static void
+platform_identify(void *dummy)
+{
+
+	soc_identify();
+
+	/*
+	 * XXX Board identification e.g. read out from FPGA or similar should
+	 * go here
+	 */
+}
+SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify, NULL);
+
+/*
+ * TODO routine setting GPIO/MPP pins 
+ */
diff --git a/sys/arm/mv/orion/files.db88f5xxx b/sys/arm/mv/orion/files.db88f5xxx
new file mode 100644
index 000000000000..9bdbc3b3d5bd
--- /dev/null
+++ b/sys/arm/mv/orion/files.db88f5xxx
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+arm/mv/orion/orion.c		standard
+arm/mv/orion/db88f5xxx.c	standard
diff --git a/sys/arm/mv/orion/orion.c b/sys/arm/mv/orion/orion.c
new file mode 100644
index 000000000000..8eb4908a9e0c
--- /dev/null
+++ b/sys/arm/mv/orion/orion.c
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+#if 0
+#include <arm/mv/mv_pci.h>
+extern int platform_pci_get_irq(u_int bus, u_int slot, u_int func, u_int pin);
+#endif
+
+struct obio_device obio_devices[] = {
+	{ "ic", MV_IC_BASE, MV_IC_SIZE,
+		{ -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "timer", MV_TIMERS_BASE, MV_TIMERS_SIZE,
+		{ MV_INT_BRIDGE, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "gpio", MV_GPIO_BASE, MV_GPIO_SIZE,
+		{ MV_INT_GPIO7_0, MV_INT_GPIO15_8,
+		  MV_INT_GPIO23_16, MV_INT_GPIO31_24, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "uart", MV_UART0_BASE, MV_UART_SIZE,
+		{ MV_INT_UART0, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "uart", MV_UART1_BASE, MV_UART_SIZE,
+		{ MV_INT_UART1, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "idma", MV_IDMA_BASE, MV_IDMA_SIZE,
+		{ MV_INT_IDMA_ERR, MV_INT_IDMA0, MV_INT_IDMA1,
+		  MV_INT_IDMA2, MV_INT_IDMA3, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "ehci", MV_USB0_BASE, MV_USB_SIZE,
+		{ MV_INT_USB_BERR, MV_INT_USB_CI, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "mge", MV_ETH0_BASE, MV_ETH_SIZE,
+		{ MV_INT_GBERX, MV_INT_GBETX, MV_INT_GBEMISC,
+		  MV_INT_GBESUM, MV_INT_GBEERR, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "twsi", MV_TWSI_BASE, MV_TWSI_SIZE,
+		{ -1 }, { -1 },
+		CPU_PM_CTRL_NONE
+	},
+	{ "pcib", MV_PCIE_BASE, MV_PCIE_SIZE,
+		{ MV_INT_PEX0_ERR, -1 },
+		{ -1 },
+		CPU_PM_CTRL_NONE
+        },
+	{ "pcib", MV_PCI_BASE, MV_PCI_SIZE,
+		{ MV_INT_PCI_ERR, -1 },
+		{-1 },
+		CPU_PM_CTRL_NONE
+        },
+	{ NULL, 0, 0, { 0 } }
+};
+
+#if 0
+const struct mv_pci_info pci_info[] = {
+	{ 1,	MV_PCIE_IO_BASE, MV_PCIE_IO_SIZE,
+		MV_PCIE_MEM_BASE, MV_PCIE_MEM_SIZE,
+		NULL, MV_INT_PEX0
+	},
+	{ 0,	MV_PCI_IO_BASE, MV_PCI_IO_SIZE,
+		MV_PCI_MEM_BASE, MV_PCI_MEM_SIZE,
+		platform_pci_get_irq, -1
+	},
+};
+#endif
+
+struct resource_spec mv_gpio_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		2,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		3,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+const struct decode_win cpu_win_tbl[] = {
+	/* PCIE IO */
+	{ 4, 0x51, MV_PCIE_IO_PHYS_BASE, MV_PCIE_IO_SIZE, -1 },
+
+	/* PCI IO */
+	{ 3, 0x51, MV_PCI_IO_PHYS_BASE, MV_PCI_IO_SIZE, -1 },
+
+	/* PCIE MEM */
+	{ 4, 0x59, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
+
+	/* PCI MEM */
+	{ 3, 0x59, MV_PCI_MEM_PHYS_BASE, MV_PCI_MEM_SIZE, -1 },
+
+	/* Device bus BOOT */
+	{ 1, 0x0f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
+
+	/* Device bus CS0 */
+	{ 1, 0x1e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
+
+	/* Device bus CS1 */
+	{ 1, 0x1d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
+
+	/* Device bus CS2 */
+	{ 1, 0x1b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
+};
+const struct decode_win *cpu_wins = cpu_win_tbl;
+int cpu_wins_no = sizeof(cpu_win_tbl) / sizeof(struct decode_win);
+
+/*
+ * Note: the decode windows table for IDMA does not explicitly have DRAM
+ * entries, which are not statically defined: active DDR banks (== windows)
+ * are established in run time from actual DDR windows settings. All active
+ * DDR banks are mapped into IDMA decode windows, so at least one IDMA decode
+ * window is occupied by the DDR bank; in case when all (MV_WIN_DDR_MAX)
+ * DDR banks are active, the remaining available IDMA decode windows for other
+ * targets is only MV_WIN_IDMA_MAX - MV_WIN_DDR_MAX.
+ */
+const struct decode_win idma_win_tbl[] = {
+	/* PCIE MEM */
+	{ 4, 0x59, MV_PCIE_MEM_PHYS_BASE, MV_PCIE_MEM_SIZE, -1 },
+
+	/* PCI MEM */
+	{ 3, 0x59, MV_PCI_MEM_PHYS_BASE, MV_PCI_MEM_SIZE, -1 },
+
+	/* Device bus BOOT */
+	{ 1, 0x0f, MV_DEV_BOOT_PHYS_BASE, MV_DEV_BOOT_SIZE, -1 },
+
+	/* Device bus CS0 */
+	{ 1, 0x1e, MV_DEV_CS0_PHYS_BASE, MV_DEV_CS0_SIZE, -1 },
+
+	/* Device bus CS1 */
+	{ 1, 0x1d, MV_DEV_CS1_PHYS_BASE, MV_DEV_CS1_SIZE, -1 },
+
+	/* Device bus CS2 */
+	{ 1, 0x1b, MV_DEV_CS2_PHYS_BASE, MV_DEV_CS2_SIZE, -1 },
+};
+const struct decode_win *idma_wins = idma_win_tbl;
+int idma_wins_no = sizeof(idma_win_tbl) / sizeof(struct decode_win);
diff --git a/sys/arm/mv/orion/std.db88f5xxx b/sys/arm/mv/orion/std.db88f5xxx
new file mode 100644
index 000000000000..e5a0dd21dc6e
--- /dev/null
+++ b/sys/arm/mv/orion/std.db88f5xxx
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+include	"../mv/std.mv"
+files	"../mv/orion/files.db88f5xxx"
+
+makeoptions	KERNPHYSADDR=0x00400000
+makeoptions	KERNVIRTADDR=0xc0400000
+
+options		KERNPHYSADDR=0x00400000
+options		KERNVIRTADDR=0xc0400000
+options		PHYSADDR=0x00000000
+options		PHYSMEM_SIZE=0x08000000
+options		STARTUP_PAGETABLE_ADDR=0x00100000
diff --git a/sys/arm/mv/rtc.c b/sys/arm/mv/rtc.c
new file mode 100644
index 000000000000..80b8343c7e02
--- /dev/null
+++ b/sys/arm/mv/rtc.c
@@ -0,0 +1,184 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/time.h>
+#include <sys/clock.h>
+#include <sys/resource.h>
+#include <sys/systm.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include "clock_if.h"
+
+#define MV_RTC_TIME_REG		0x00
+#define MV_RTC_DATE_REG		0x04
+#define YEAR_BASE		2000
+
+struct mv_rtc_softc {
+	device_t dev;
+	struct resource *res[1];
+};
+
+static struct resource_spec res_spec[] = {
+	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static int mv_rtc_probe(device_t dev);
+static int mv_rtc_attach(device_t dev);
+
+static int mv_rtc_gettime(device_t dev, struct timespec *ts);
+static int mv_rtc_settime(device_t dev, struct timespec *ts);
+
+static uint32_t mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off);
+static int mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off,
+    uint32_t val);
+
+static device_method_t mv_rtc_methods[] = {
+	DEVMETHOD(device_probe,		mv_rtc_probe),
+	DEVMETHOD(device_attach,	mv_rtc_attach),
+
+	DEVMETHOD(clock_gettime,	mv_rtc_gettime),
+	DEVMETHOD(clock_settime,	mv_rtc_settime),
+
+	{ 0, 0 },
+};
+
+static driver_t mv_rtc_driver = {
+	"rtc",
+	mv_rtc_methods,
+	sizeof(struct mv_rtc_softc),
+};
+static devclass_t mv_rtc_devclass;
+
+DRIVER_MODULE(mv_rtc, mbus, mv_rtc_driver, mv_rtc_devclass, 0, 0);
+
+static int
+mv_rtc_probe(device_t dev)
+{
+
+	device_set_desc(dev, "Marvell Integrated RTC");
+	return (0);
+}
+
+static int
+mv_rtc_attach(device_t dev)
+{
+	struct mv_rtc_softc *sc;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	clock_register(dev, 1000000);
+
+	if (bus_alloc_resources(dev, res_spec, sc->res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	return (0);
+}
+
+static int
+mv_rtc_gettime(device_t dev, struct timespec *ts)
+{
+	struct clocktime ct;
+	struct mv_rtc_softc *sc;
+	uint32_t val;
+
+	sc = device_get_softc(dev);
+
+	val = mv_rtc_reg_read(sc, MV_RTC_TIME_REG);
+
+	ct.nsec = 0;
+	ct.sec = FROMBCD(val & 0x7f);
+	ct.min = FROMBCD((val & 0x7f00) >> 8);
+	ct.hour = FROMBCD((val & 0x3f0000) >> 16);
+	ct.dow = FROMBCD((val & 0x7000000) >> 24) - 1;
+
+	val = mv_rtc_reg_read(sc, MV_RTC_DATE_REG);
+
+	ct.day = FROMBCD(val & 0x7f);
+	ct.mon = FROMBCD((val & 0x1f00) >> 8);
+	ct.year = YEAR_BASE + FROMBCD((val & 0xff0000) >> 16);
+
+	return (clock_ct_to_ts(&ct, ts));
+}
+
+static int
+mv_rtc_settime(device_t dev, struct timespec *ts)
+{
+	struct clocktime ct;
+	struct mv_rtc_softc *sc;
+	uint32_t val;
+
+	sc = device_get_softc(dev);
+
+	/* Resolution: 1 sec */
+	if (ts->tv_nsec >= 500000000)
+		ts->tv_sec++;
+	ts->tv_nsec = 0;
+	clock_ts_to_ct(ts, &ct);
+
+	val = TOBCD(ct.sec) | (TOBCD(ct.min) << 8) |
+	    (TOBCD(ct.hour) << 16) | (TOBCD( ct.dow + 1) << 24);
+	mv_rtc_reg_write(sc, MV_RTC_TIME_REG, val);
+
+	val = TOBCD(ct.day) | (TOBCD(ct.mon) << 8) |
+	    (TOBCD(ct.year - YEAR_BASE) << 16);
+	mv_rtc_reg_write(sc, MV_RTC_DATE_REG, val);
+
+	return (0);
+}
+
+static uint32_t
+mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off)
+{
+
+	return (bus_read_4(sc->res[0], off));
+}
+
+static int
+mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, uint32_t val)
+{
+
+	bus_write_4(sc->res[0], off, val);
+	return (0);
+}
diff --git a/sys/arm/mv/std.mv b/sys/arm/mv/std.mv
new file mode 100644
index 000000000000..621010260459
--- /dev/null
+++ b/sys/arm/mv/std.mv
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+files		"../mv/files.mv"
+cpu		CPU_ARM9E
+makeoptions	CONF_CFLAGS="-march=armv5te"
diff --git a/sys/arm/mv/timer.c b/sys/arm/mv/timer.c
new file mode 100644
index 000000000000..d239b9acc484
--- /dev/null
+++ b/sys/arm/mv/timer.c
@@ -0,0 +1,381 @@
+/*-
+ * Copyright (c) 2006 Benno Rice.
+ * Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Adapted to Marvell SoC by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_timer.c, rev 1
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+#define MV_TIMER_TICK	(get_tclk() / hz)
+#define INITIAL_TIMECOUNTER	(0xffffffff)
+#define MAX_WATCHDOG_TICKS	(0xffffffff)
+
+struct mv_timer_softc {
+	struct resource	*	timer_res[2];
+	bus_space_tag_t		timer_bst;
+	bus_space_handle_t	timer_bsh;
+	struct mtx		timer_mtx;
+};
+
+static struct resource_spec mv_timer_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static struct mv_timer_softc *timer_softc = NULL;
+static int timers_initialized = 0;
+
+static int	mv_timer_probe(device_t);
+static int	mv_timer_attach(device_t);
+
+static int	mv_hardclock(void *);
+static unsigned mv_timer_get_timecount(struct timecounter *);
+
+static uint32_t	mv_get_timer_control(void);
+static void	mv_set_timer_control(uint32_t);
+static uint32_t	mv_get_timer(uint32_t);
+static void	mv_set_timer(uint32_t, uint32_t);
+static void	mv_set_timer_rel(uint32_t, uint32_t);
+static void	mv_watchdog_enable(void);
+static void	mv_watchdog_disable(void);
+static void	mv_watchdog_event(void *, unsigned int, int *);
+static void	mv_setup_timer(void);
+static void	mv_setup_timercount(void);
+
+static struct timecounter mv_timer_timecounter = {
+	.tc_get_timecount = mv_timer_get_timecount,
+	.tc_name = "CPU Timer",
+	.tc_frequency = 0,	/* This is assigned on the fly in the init sequence */
+	.tc_counter_mask = ~0u,
+	.tc_quality = 1000,
+};
+
+static int
+mv_timer_probe(device_t dev)
+{
+
+	device_set_desc(dev, "Marvell CPU Timer");
+	return (0);
+}
+
+static int
+mv_timer_attach(device_t dev)
+{
+	int	error;
+	void	*ihl;
+	struct	mv_timer_softc *sc;
+
+	if (timer_softc != NULL)
+		return (ENXIO);
+
+	sc = (struct mv_timer_softc *)device_get_softc(dev);
+	timer_softc = sc;
+
+	error = bus_alloc_resources(dev, mv_timer_spec, sc->timer_res);
+	if (error) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->timer_bst = rman_get_bustag(sc->timer_res[0]);
+	sc->timer_bsh = rman_get_bushandle(sc->timer_res[0]);
+
+	mtx_init(&timer_softc->timer_mtx, "watchdog", NULL, MTX_DEF);
+	mv_watchdog_disable();
+	EVENTHANDLER_REGISTER(watchdog_list, mv_watchdog_event, sc, 0);
+
+	if (bus_setup_intr(dev, sc->timer_res[1], INTR_TYPE_CLK,
+	    mv_hardclock, NULL, NULL, &ihl) != 0) {
+		bus_release_resources(dev, mv_timer_spec, sc->timer_res);
+		device_printf(dev, "could not setup hardclock interrupt\n");
+		return (ENXIO);
+	}
+
+	mv_setup_timercount();
+	timers_initialized = 1;
+
+	return (0);
+}
+
+static int
+mv_hardclock(void *arg)
+{
+	uint32_t irq_cause;
+	struct	trapframe *frame;
+
+	frame = (struct trapframe *)arg;
+	hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
+
+	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
+	irq_cause &= ~(IRQ_TIMER0);
+	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
+
+	return (FILTER_HANDLED);
+}
+
+static device_method_t mv_timer_methods[] = {
+	DEVMETHOD(device_probe, mv_timer_probe),
+	DEVMETHOD(device_attach, mv_timer_attach),
+
+	{ 0, 0 }
+};
+
+static driver_t mv_timer_driver = {
+	"timer",
+	mv_timer_methods,
+	sizeof(struct mv_timer_softc),
+};
+
+static devclass_t mv_timer_devclass;
+
+DRIVER_MODULE(timer, mbus, mv_timer_driver, mv_timer_devclass, 0, 0);
+
+static unsigned
+mv_timer_get_timecount(struct timecounter *tc)
+{
+
+	return (INITIAL_TIMECOUNTER - mv_get_timer(1));
+}
+
+void
+cpu_initclocks(void)
+{
+	uint32_t irq_cause, irq_mask;
+
+	mv_setup_timer();
+
+	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
+	irq_cause &= ~(IRQ_TIMER0);
+	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
+
+	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
+	irq_mask |= IRQ_TIMER0_MASK;
+	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
+
+	mv_timer_timecounter.tc_frequency = get_tclk();
+	tc_init(&mv_timer_timecounter);
+}
+
+void
+cpu_startprofclock(void)
+{
+
+}
+
+void
+cpu_stopprofclock(void)
+{
+
+}
+
+void
+DELAY(int usec)
+{
+	uint32_t	val, val_temp;
+	int32_t		nticks;
+
+	if (!timers_initialized) {
+		for (; usec > 0; usec--)
+			for (val = 100; val > 0; val--)
+				;
+		return;
+	}
+
+	val = mv_get_timer(1);
+	nticks = ((get_tclk() / 1000000 + 1) * usec);
+
+	while (nticks > 0) {
+		val_temp = mv_get_timer(1);
+		if (val > val_temp)
+			nticks -= (val - val_temp);
+		else
+			nticks -= (val + (INITIAL_TIMECOUNTER - val_temp));
+
+		val = val_temp;
+	}
+}
+
+static uint32_t
+mv_get_timer_control(void)
+{
+
+	return (bus_space_read_4(timer_softc->timer_bst,
+	    timer_softc->timer_bsh, CPU_TIMER_CONTROL));
+}
+
+static void
+mv_set_timer_control(uint32_t val)
+{
+
+	bus_space_write_4(timer_softc->timer_bst,
+	    timer_softc->timer_bsh, CPU_TIMER_CONTROL, val);
+}
+
+static uint32_t
+mv_get_timer(uint32_t timer)
+{
+
+	return (bus_space_read_4(timer_softc->timer_bst,
+	    timer_softc->timer_bsh, CPU_TIMER0 + timer * 0x8));
+}
+
+static void
+mv_set_timer(uint32_t timer, uint32_t val)
+{
+
+	bus_space_write_4(timer_softc->timer_bst,
+	    timer_softc->timer_bsh, CPU_TIMER0 + timer * 0x8, val);
+}
+
+static void
+mv_set_timer_rel(uint32_t timer, uint32_t val)
+{
+
+	bus_space_write_4(timer_softc->timer_bst,
+	    timer_softc->timer_bsh, CPU_TIMER0_REL + timer * 0x8, val);
+}
+
+static void
+mv_watchdog_enable(void)
+{
+	uint32_t val;
+	uint32_t irq_cause, irq_mask;
+
+	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
+	irq_cause &= ~(IRQ_TIMER_WD);
+	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
+
+	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
+	irq_mask |= IRQ_TIMER_WD_MASK;
+	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
+
+	val = read_cpu_ctrl(RSTOUTn_MASK);
+	val |= WD_RST_OUT_EN;
+	write_cpu_ctrl(RSTOUTn_MASK, val);
+
+	val = mv_get_timer_control();
+	val |= CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO;
+	mv_set_timer_control(val);
+}
+
+static void
+mv_watchdog_disable(void)
+{
+	uint32_t val;
+	uint32_t irq_cause, irq_mask;
+
+	val = mv_get_timer_control();
+	val &= ~(CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO);
+	mv_set_timer_control(val);
+
+	val = read_cpu_ctrl(RSTOUTn_MASK);
+	val &= ~WD_RST_OUT_EN;
+	write_cpu_ctrl(RSTOUTn_MASK, val);
+
+	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
+	irq_mask &= ~(IRQ_TIMER_WD_MASK);
+	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
+
+	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
+	irq_cause &= ~(IRQ_TIMER_WD);
+	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
+}
+
+
+/*
+ * Watchdog event handler.
+ */
+static void
+mv_watchdog_event(void *arg, unsigned int cmd, int *error)
+{
+	uint64_t ns;
+	uint64_t ticks;
+
+	mtx_lock(&timer_softc->timer_mtx);
+	if (cmd == 0)
+		mv_watchdog_disable();
+	else {
+		/*
+		 * Watchdog timeout is in nanosecs, calculation according to
+		 * watchdog(9)
+		 */
+		ns = (uint64_t)1 << (cmd & WD_INTERVAL);
+		ticks = (uint64_t)(ns * get_tclk()) / 1000000000;
+		if (ticks > MAX_WATCHDOG_TICKS)
+			mv_watchdog_disable();
+		else {
+			/* Timer 2 is the watchdog */
+			mv_set_timer(2, ticks);
+			mv_watchdog_enable();
+			*error = 0;
+		}
+	}
+	mtx_unlock(&timer_softc->timer_mtx);
+}
+
+static void
+mv_setup_timer(void)
+{
+	uint32_t val;
+
+	mv_set_timer_rel(0, MV_TIMER_TICK);
+	mv_set_timer(0, MV_TIMER_TICK);
+	val = mv_get_timer_control();
+	val |= CPU_TIMER0_EN | CPU_TIMER0_AUTO;
+	mv_set_timer_control(val);
+}
+
+static void
+mv_setup_timercount(void)
+{
+	uint32_t val;
+
+	mv_set_timer_rel(1, INITIAL_TIMECOUNTER);
+	mv_set_timer(1, INITIAL_TIMECOUNTER);
+	val = mv_get_timer_control();
+	val |= CPU_TIMER1_EN | CPU_TIMER1_AUTO;
+	mv_set_timer_control(val);
+}
diff --git a/sys/arm/mv/twsi.c b/sys/arm/mv/twsi.c
new file mode 100644
index 000000000000..15ec4150f560
--- /dev/null
+++ b/sys/arm/mv/twsi.c
@@ -0,0 +1,523 @@
+/*-
+ * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+/*
+ * Driver for the TWSI (aka I2C, aka IIC) bus controller found on Marvell
+ * SoCs. Supports master operation only, and works in polling mode.
+ *
+ * Calls to DELAY() are needed per Application Note AN-179 "TWSI Software
+ * Guidelines for Discovery(TM), Horizon (TM) and Feroceon(TM) Devices".
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/resource.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <sys/rman.h>
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+#include "iicbus_if.h"
+
+#define MV_TWSI_NAME		"twsi"
+
+#define TWSI_SLAVE_ADDR		0x00
+#define TWSI_EXT_SLAVE_ADDR	0x10
+#define TWSI_DATA		0x04
+
+#define TWSI_CONTROL		0x08
+#define TWSI_CONTROL_ACK	(1 << 2)
+#define TWSI_CONTROL_IFLG	(1 << 3)
+#define TWSI_CONTROL_STOP	(1 << 4)
+#define TWSI_CONTROL_START	(1 << 5)
+#define TWSI_CONTROL_TWSIEN	(1 << 6)
+#define TWSI_CONTROL_INTEN	(1 << 7)
+
+#define TWSI_STATUS			0x0c
+#define TWSI_STATUS_START		0x08
+#define TWSI_STATUS_RPTD_START		0x10
+#define TWSI_STATUS_ADDR_W_ACK		0x18
+#define TWSI_STATUS_DATA_WR_ACK		0x28
+#define TWSI_STATUS_ADDR_R_ACK		0x40
+#define TWSI_STATUS_DATA_RD_ACK		0x50
+#define TWSI_STATUS_DATA_RD_NOACK	0x58
+
+#define TWSI_BAUD_RATE		0x0c
+#define TWSI_BAUD_RATE_94DOT3	0x53 /* N=3, M=10 */
+#define TWSI_BAUD_RATE_74DOT1	0x6b /* N=3, M=13 */
+#define TWSI_BAUD_RATE_51DOT8	0x4c /* N=4, M=9  */
+#define TWSI_BAUD_RATE_99DOT7	0x66 /* N=6, M=12 */
+
+#define TWSI_SOFT_RESET		0x1c
+
+#define TWSI_DEBUG
+#undef TWSI_DEBUG
+
+#ifdef  TWSI_DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+struct mv_twsi_softc {
+	device_t	dev;
+	struct resource	*res[1];	/* SYS_RES_MEMORY */
+	struct mtx	mutex;
+	device_t	iicbus;
+};
+
+static int mv_twsi_probe(device_t);
+static int mv_twsi_attach(device_t);
+static int mv_twsi_detach(device_t);
+
+static int mv_twsi_reset(device_t dev, u_char speed, u_char addr,
+    u_char *oldaddr);
+static int mv_twsi_repeated_start(device_t dev, u_char slave, int timeout);
+static int mv_twsi_start(device_t dev, u_char slave, int timeout);
+static int mv_twsi_stop(device_t dev);
+static int mv_twsi_read(device_t dev, char *buf, int len, int *read, int last,
+    int delay);
+static int mv_twsi_write(device_t dev, char *buf, int len, int *sent,
+    int timeout);
+
+static struct resource_spec res_spec[] = {
+	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static device_method_t mv_twsi_methods[] = {
+	/* device interface */
+	DEVMETHOD(device_probe,		mv_twsi_probe),
+	DEVMETHOD(device_attach,	mv_twsi_attach),
+	DEVMETHOD(device_detach,	mv_twsi_detach),
+
+	/* iicbus interface */
+	DEVMETHOD(iicbus_callback, iicbus_null_callback),
+	DEVMETHOD(iicbus_repeated_start, mv_twsi_repeated_start),
+	DEVMETHOD(iicbus_start,		mv_twsi_start),
+	DEVMETHOD(iicbus_stop,		mv_twsi_stop),
+	DEVMETHOD(iicbus_write,		mv_twsi_write),
+	DEVMETHOD(iicbus_read,		mv_twsi_read),
+	DEVMETHOD(iicbus_reset,		mv_twsi_reset),
+	DEVMETHOD(iicbus_transfer,	iicbus_transfer_gen),
+	{ 0, 0 }
+};
+
+static devclass_t mv_twsi_devclass;
+
+static driver_t mv_twsi_driver = {
+	MV_TWSI_NAME,
+	mv_twsi_methods,
+	sizeof(struct mv_twsi_softc),
+};
+
+DRIVER_MODULE(twsi, mbus, mv_twsi_driver, mv_twsi_devclass, 0, 0);
+DRIVER_MODULE(iicbus, twsi, iicbus_driver, iicbus_devclass, 0, 0);
+MODULE_DEPEND(twsi, iicbus, 1, 1, 1);
+
+static __inline uint32_t
+TWSI_READ(struct mv_twsi_softc *sc, bus_size_t off)
+{
+
+	return (bus_read_4(sc->res[0], off));
+}
+
+static __inline void
+TWSI_WRITE(struct mv_twsi_softc *sc, bus_size_t off, uint32_t val)
+{
+
+	bus_write_4(sc->res[0], off, val);
+}
+
+static __inline void
+twsi_control_clear(struct mv_twsi_softc *sc, uint32_t mask)
+{
+	uint32_t val;
+
+	val = TWSI_READ(sc, TWSI_CONTROL);
+	val &= ~mask;
+	TWSI_WRITE(sc, TWSI_CONTROL, val);
+}
+
+static __inline void
+twsi_control_set(struct mv_twsi_softc *sc, uint32_t mask)
+{
+	uint32_t val;
+
+	val = TWSI_READ(sc, TWSI_CONTROL);
+	val |= mask;
+	TWSI_WRITE(sc, TWSI_CONTROL, val);
+}
+
+static __inline void
+twsi_clear_iflg(struct mv_twsi_softc *sc)
+{
+
+	DELAY(1000);
+	twsi_control_clear(sc, TWSI_CONTROL_IFLG);
+	DELAY(1000);
+}
+
+
+/*
+ * timeout given in us
+ * returns
+ *   0 on sucessfull mask change
+ *   non-zero on timeout
+ */
+static int
+twsi_poll_ctrl(struct mv_twsi_softc *sc, int timeout, uint32_t mask)
+{
+
+	timeout /= 10;
+	while (!(TWSI_READ(sc, TWSI_CONTROL) & mask)) {
+		DELAY(10);
+		if (--timeout < 0)
+			return (timeout);
+	}
+	return (0);
+}
+
+
+/*
+ * 'timeout' is given in us. Note also that timeout handling is not exact --
+ * twsi_locked_start() total wait can be more than 2 x timeout
+ * (twsi_poll_ctrl() is called twice). 'mask' can be either TWSI_STATUS_START
+ * or TWSI_STATUS_RPTD_START
+ */
+static int
+twsi_locked_start(device_t dev, struct mv_twsi_softc *sc, int32_t mask,
+    u_char slave, int timeout)
+{
+	int read_access, iflg_set = 0;
+	uint32_t status;
+
+	mtx_assert(&sc->mutex, MA_OWNED);
+
+	if (mask == TWSI_STATUS_RPTD_START)
+		/* read IFLG to know if it should be cleared later; from NBSD */
+		iflg_set = TWSI_READ(sc, TWSI_CONTROL) & TWSI_CONTROL_IFLG;
+
+	twsi_control_set(sc, TWSI_CONTROL_START);
+
+	if (mask == TWSI_STATUS_RPTD_START && iflg_set) {
+		debugf("IFLG set, clearing\n");
+		twsi_clear_iflg(sc);
+	}
+
+	/*
+	 * Without this delay we timeout checking IFLG if the timeout is 0.
+	 * NBSD driver always waits here too.
+	 */
+	DELAY(1000);
+
+	if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
+		debugf("timeout sending %sSTART condition\n",
+		    mask == TWSI_STATUS_START ? "" : "repeated ");
+		return (IIC_ETIMEOUT);
+	}
+
+	status = TWSI_READ(sc, TWSI_STATUS);
+	if (status != mask) {
+		debugf("wrong status (%02x) after sending %sSTART condition\n",
+		    status, mask == TWSI_STATUS_START ? "" : "repeated ");
+		return (IIC_ESTATUS);
+	}
+
+	TWSI_WRITE(sc, TWSI_DATA, slave);
+	DELAY(1000);
+	twsi_clear_iflg(sc);
+
+	if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
+		debugf("timeout sending slave address\n");
+		return (IIC_ETIMEOUT);
+	}
+	
+	read_access = (slave & 0x1) ? 1 : 0;
+	status = TWSI_READ(sc, TWSI_STATUS);
+	if (status != (read_access ?
+	    TWSI_STATUS_ADDR_R_ACK : TWSI_STATUS_ADDR_W_ACK)) {
+		debugf("no ACK (status: %02x) after sending slave address\n",
+		    status);
+		return (IIC_ENOACK);
+	}
+
+	return (IIC_NOERR);
+}
+
+static int
+mv_twsi_probe(device_t dev)
+{
+
+	device_set_desc(dev, "Marvell Integrated I2C Bus Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+mv_twsi_attach(device_t dev)
+{
+	struct mv_twsi_softc *sc;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+
+	mtx_init(&sc->mutex, device_get_nameunit(dev), MV_TWSI_NAME, MTX_DEF);
+
+	/* Allocate IO resources */
+	if (bus_alloc_resources(dev, res_spec, sc->res)) {
+		device_printf(dev, "could not allocate resources\n");
+		mv_twsi_detach(dev);
+		return (ENXIO);
+	}
+
+	sc->iicbus = device_add_child(dev, "iicbus", -1);
+	if (sc->iicbus == NULL) {
+		device_printf(dev, "could not add iicbus child\n");
+		mv_twsi_detach(dev);
+		return (ENXIO);
+	}
+
+	bus_generic_attach(dev);
+	return (0);
+}
+
+static int
+mv_twsi_detach(device_t dev)
+{
+	struct mv_twsi_softc *sc;
+	int rv;
+
+	sc = device_get_softc(dev);
+
+	if ((rv = bus_generic_detach(dev)) != 0)
+		return (rv);
+
+	if (sc->iicbus != NULL)
+		if ((rv = device_delete_child(dev, sc->iicbus)) != 0)
+			return (rv);
+
+	bus_release_resources(dev, res_spec, sc->res);
+
+	mtx_destroy(&sc->mutex);
+	return (0);
+}
+
+/*
+ * Only slave mode supported, disregard [old]addr
+ */
+static int
+mv_twsi_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+	struct mv_twsi_softc *sc;
+	uint32_t baud_rate;
+
+	sc = device_get_softc(dev);
+
+	switch (speed) {
+	case IIC_SLOW:
+		baud_rate = TWSI_BAUD_RATE_51DOT8;
+		break;
+	case IIC_FAST:
+		baud_rate = TWSI_BAUD_RATE_51DOT8;
+		break;
+	case IIC_UNKNOWN:
+	case IIC_FASTEST:
+	default:
+		baud_rate = TWSI_BAUD_RATE_99DOT7;
+		break;
+	}
+
+	mtx_lock(&sc->mutex);
+	TWSI_WRITE(sc, TWSI_SOFT_RESET, 0x0);
+	DELAY(2000);
+	TWSI_WRITE(sc, TWSI_BAUD_RATE, baud_rate);
+	TWSI_WRITE(sc, TWSI_CONTROL, TWSI_CONTROL_TWSIEN | TWSI_CONTROL_ACK);
+	DELAY(1000);
+	mtx_unlock(&sc->mutex);
+
+	return (0);
+}
+
+/*
+ * timeout is given in us
+ */
+static int
+mv_twsi_repeated_start(device_t dev, u_char slave, int timeout)
+{
+	struct mv_twsi_softc *sc;
+	int rv;
+
+	sc = device_get_softc(dev);
+
+	mtx_lock(&sc->mutex);
+	rv = twsi_locked_start(dev, sc, TWSI_STATUS_RPTD_START, slave,
+	    timeout);
+	mtx_unlock(&sc->mutex);
+
+	if (rv) {
+		mv_twsi_stop(dev);
+		return (rv);
+	} else
+		return (IIC_NOERR);
+}
+
+/*
+ * timeout is given in us
+ */
+static int
+mv_twsi_start(device_t dev, u_char slave, int timeout)
+{
+	struct mv_twsi_softc *sc;
+	int rv;
+
+	sc = device_get_softc(dev);
+
+	mtx_lock(&sc->mutex);
+	rv = twsi_locked_start(dev, sc, TWSI_STATUS_START, slave, timeout);
+	mtx_unlock(&sc->mutex);
+
+	if (rv) {
+		mv_twsi_stop(dev);
+		return (rv);
+	} else
+		return (IIC_NOERR);
+}
+
+static int
+mv_twsi_stop(device_t dev)
+{
+	struct mv_twsi_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	mtx_lock(&sc->mutex);
+	twsi_control_set(sc, TWSI_CONTROL_STOP);
+	DELAY(1000);
+	twsi_clear_iflg(sc);
+	mtx_unlock(&sc->mutex);
+
+	return (IIC_NOERR);
+}
+
+static int
+mv_twsi_read(device_t dev, char *buf, int len, int *read, int last, int delay)
+{
+	struct mv_twsi_softc *sc;
+	uint32_t status;
+	int last_byte, rv;
+
+	sc = device_get_softc(dev);
+
+	mtx_lock(&sc->mutex);
+	*read = 0;
+	while (*read < len) {
+		/*
+		 * Check if we are reading last byte of the last buffer,
+		 * do not send ACK then, per I2C specs
+		 */
+		last_byte = ((*read == len - 1) && last) ? 1 : 0;
+		if (last_byte)
+			twsi_control_clear(sc, TWSI_CONTROL_ACK);
+		else
+			twsi_control_set(sc, TWSI_CONTROL_ACK);
+
+		DELAY (1000);
+		twsi_clear_iflg(sc);
+
+		if (twsi_poll_ctrl(sc, delay, TWSI_CONTROL_IFLG)) {
+			debugf("timeout reading data\n");
+			rv = IIC_ETIMEOUT;
+			goto out;
+		}
+
+		status = TWSI_READ(sc, TWSI_STATUS);
+		if (status != (last_byte ?
+		    TWSI_STATUS_DATA_RD_NOACK : TWSI_STATUS_DATA_RD_ACK)) {
+			debugf("wrong status (%02x) while reading\n", status);
+			rv = IIC_ESTATUS;
+			goto out;
+		}
+
+		*buf++ = TWSI_READ(sc, TWSI_DATA);
+		(*read)++;
+	}
+	rv = IIC_NOERR;
+out:
+	mtx_unlock(&sc->mutex);
+	return (rv);
+}
+
+static int
+mv_twsi_write(device_t dev, char *buf, int len, int *sent, int timeout)
+{
+	struct mv_twsi_softc *sc;
+	uint32_t status;
+	int rv;
+
+	sc = device_get_softc(dev);
+
+	mtx_lock(&sc->mutex);
+	*sent = 0;
+	while (*sent < len) {
+		TWSI_WRITE(sc, TWSI_DATA, *buf++);
+
+		twsi_clear_iflg(sc);
+		if (twsi_poll_ctrl(sc, timeout, TWSI_CONTROL_IFLG)) {
+			debugf("timeout writing data\n");
+			rv = IIC_ETIMEOUT;
+			goto out;
+		}
+
+		status = TWSI_READ(sc, TWSI_STATUS);
+		if (status != TWSI_STATUS_DATA_WR_ACK) {
+			debugf("wrong status (%02x) while writing\n", status);
+			rv = IIC_ESTATUS;
+			goto out;
+		}
+		(*sent)++;
+	}
+	rv = IIC_NOERR;
+out:
+	mtx_unlock(&sc->mutex);
+	return (rv);
+}
diff --git a/sys/conf/Makefile.arm b/sys/conf/Makefile.arm
index da7763443396..99fc300409da 100644
--- a/sys/conf/Makefile.arm
+++ b/sys/conf/Makefile.arm
@@ -75,7 +75,8 @@ FILES_CPU_FUNC =	$S/$M/$M/cpufunc_asm_arm7tdmi.S \
 	$S/$M/$M/cpufunc_asm_arm8.S $S/$M/$M/cpufunc_asm_arm9.S \
 	$S/$M/$M/cpufunc_asm_sa1.S $S/$M/$M/cpufunc_asm_arm10.S \
 	$S/$M/$M/cpufunc_asm_xscale.S $S/$M/$M/cpufunc_asm.S \
-	$S/$M/$M/cpufunc_asm_xscale_c3.S $S/$M/$M/cpufunc_asm_armv5_ec.S
+	$S/$M/$M/cpufunc_asm_xscale_c3.S $S/$M/$M/cpufunc_asm_armv5_ec.S \
+	$S/$M/$M/cpufunc_asm_feroceon.S
 KERNEL_EXTRA=trampoline
 KERNEL_EXTRA_INSTALL=kernel.gz.tramp
 trampoline: ${KERNEL_KO}.tramp
diff --git a/sys/conf/options.arm b/sys/conf/options.arm
index 484634713cab..eb5a291f38c4 100644
--- a/sys/conf/options.arm
+++ b/sys/conf/options.arm
@@ -20,7 +20,11 @@ KERNPHYSADDR		opt_global.h
 KERNVIRTADDR		opt_global.h
 LOADERRAMADDR		opt_global.h
 PHYSADDR		opt_global.h
+PHYSMEM_SIZE		opt_global.h
 SKYEYE_WORKAROUNDS	opt_global.h
+SOC_MV_DISCOVERY	opt_global.h
+SOC_MV_KIRKWOOD		opt_global.h
+SOC_MV_ORION		opt_global.h
 STARTUP_PAGETABLE_ADDR	opt_global.h
 XSCALE_CACHE_READ_WRITE_ALLOCATE	opt_global.h
 XSACLE_DISABLE_CCNT	opt_timer.h
diff --git a/sys/dev/uart/uart_bus_mbus.c b/sys/dev/uart/uart_bus_mbus.c
new file mode 100644
index 000000000000..0d08ad1c023a
--- /dev/null
+++ b/sys/dev/uart/uart_bus_mbus.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (C) 2007 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <arm/mv/mvvar.h>
+
+static int uart_mbus_probe(device_t dev);
+
+static device_method_t uart_mbus_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		uart_mbus_probe),
+	DEVMETHOD(device_attach,	uart_bus_attach),
+	DEVMETHOD(device_detach,	uart_bus_detach),
+	{ 0, 0 }
+};
+
+static driver_t uart_mbus_driver = {
+	uart_driver_name,
+	uart_mbus_methods,
+	sizeof(struct uart_softc),
+};
+
+static int
+uart_mbus_probe(device_t dev)
+{
+	struct	uart_softc *sc;
+	int 	status;
+
+	sc = device_get_softc(dev);
+	sc->sc_class = &uart_ns8250_class;
+	status = uart_bus_probe(dev, 2, get_tclk(), 0, 0);
+
+	return(status);
+}
+
+DRIVER_MODULE(uart, mbus, uart_mbus_driver, uart_devclass, 0, 0);
diff --git a/sys/dev/uart/uart_cpu_mv.c b/sys/dev/uart/uart_cpu_mv.c
new file mode 100644
index 000000000000..ec9adbe2b068
--- /dev/null
+++ b/sys/dev/uart/uart_cpu_mv.c
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (C) 2007 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+	return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+	struct uart_class *class = &uart_ns8250_class;
+
+	/*
+	 * If env specification for UART exists it takes precedence:
+	 * hw.uart.console="mm:0xf1012000" or similar
+	 */
+	if (uart_getenv(devtype, di, class) == 0)
+		return (0);
+	/*
+	 * Fall back to default UART0 console settings
+	 */
+	di->ops = uart_getops(class);
+	di->bas.chan = 0;
+	di->bas.bst = obio_tag;
+	if (bus_space_map(di->bas.bst, MV_UART0_BASE, MV_UART_SIZE,
+	    0, &di->bas.bsh) != 0)
+		return (ENXIO);
+
+	di->baudrate = 115200;
+	di->bas.regshft = 2;
+	di->bas.rclk = get_tclk();
+	di->databits = 8;
+	di->stopbits = 1;
+	di->parity = UART_PARITY_NONE;
+	uart_bus_space_mem = obio_tag;
+	uart_bus_space_io = NULL;
+
+	return (0);
+}