summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorraj <raj@FreeBSD.org>2008-10-13 20:07:13 +0000
committerraj <raj@FreeBSD.org>2008-10-13 20:07:13 +0000
commit3226c137788c6c0c6b82bd1b88fd42a2a8ea4cb8 (patch)
treed96b4a1062d4a3a8f75bdb30e300bd1a50f23e4f /sys/arm
parent000539b88803ce11f549bc8d24154dc9a6b1c386 (diff)
downloadFreeBSD-src-3226c137788c6c0c6b82bd1b88fd42a2a8ea4cb8.zip
FreeBSD-src-3226c137788c6c0c6b82bd1b88fd42a2a8ea4cb8.tar.gz
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
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/arm/elf_trampoline.c2
-rw-r--r--sys/arm/include/intr.h4
-rw-r--r--sys/arm/include/resource.h1
-rw-r--r--sys/arm/mv/bus_space.c162
-rw-r--r--sys/arm/mv/common.c965
-rw-r--r--sys/arm/mv/discovery/db78xxx.c110
-rw-r--r--sys/arm/mv/discovery/discovery.c160
-rw-r--r--sys/arm/mv/discovery/files.db78xxx4
-rw-r--r--sys/arm/mv/discovery/std.db78xxx13
-rw-r--r--sys/arm/mv/files.mv34
-rw-r--r--sys/arm/mv/gpio.c516
-rw-r--r--sys/arm/mv/ic.c289
-rw-r--r--sys/arm/mv/kirkwood/db88f6xxx.c124
-rw-r--r--sys/arm/mv/kirkwood/files.db88f6xxx5
-rw-r--r--sys/arm/mv/kirkwood/kirkwood.c161
-rw-r--r--sys/arm/mv/kirkwood/std.db88f6xxx13
-rw-r--r--sys/arm/mv/mv_machdep.c643
-rw-r--r--sys/arm/mv/mvreg.h540
-rw-r--r--sys/arm/mv/mvvar.h122
-rw-r--r--sys/arm/mv/obio.c355
-rw-r--r--sys/arm/mv/orion/db88f5xxx.c177
-rw-r--r--sys/arm/mv/orion/files.db88f5xxx4
-rw-r--r--sys/arm/mv/orion/orion.c189
-rw-r--r--sys/arm/mv/orion/std.db88f5xxx13
-rw-r--r--sys/arm/mv/rtc.c184
-rw-r--r--sys/arm/mv/std.mv5
-rw-r--r--sys/arm/mv/timer.c381
-rw-r--r--sys/arm/mv/twsi.c523
28 files changed, 5698 insertions, 1 deletions
diff --git a/sys/arm/arm/elf_trampoline.c b/sys/arm/arm/elf_trampoline.c
index 9902546..98e76fe 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 bf2bf6d..d75f14e 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 229d14f..90dd5cd 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 0000000..2cdc454
--- /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 0000000..5489874
--- /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 0000000..f472793
--- /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 0000000..33f0bf5
--- /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 0000000..b01285f
--- /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 0000000..b2f6049
--- /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 0000000..bba8c83
--- /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 0000000..bb7f04b
--- /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 0000000..47db7c4
--- /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 0000000..8db9258
--- /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 0000000..c0de03c
--- /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 0000000..416c141
--- /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 0000000..84af354
--- /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 0000000..fa5ddbd
--- /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 0000000..68c2314
--- /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 0000000..cdf87c9
--- /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 0000000..bd757a5
--- /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 0000000..5c333b4
--- /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 0000000..9bdbc3b
--- /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 0000000..8eb4908a
--- /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 0000000..e5a0dd2
--- /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 0000000..80b8343
--- /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 0000000..6210102
--- /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 0000000..d239b9a
--- /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 0000000..15ec415
--- /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);
+}
OpenPOWER on IntegriCloud