summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/mips/mips32/adm5120/adm5120_machdep.c157
-rw-r--r--sys/mips/mips32/adm5120/adm5120reg.h294
-rw-r--r--sys/mips/mips32/adm5120/admpci.c503
-rw-r--r--sys/mips/mips32/adm5120/console.c93
-rw-r--r--sys/mips/mips32/adm5120/files.adm512011
-rw-r--r--sys/mips/mips32/adm5120/if_admsw.c1339
-rw-r--r--sys/mips/mips32/adm5120/if_admswreg.h678
-rw-r--r--sys/mips/mips32/adm5120/if_admswvar.h212
-rw-r--r--sys/mips/mips32/adm5120/obio.c510
-rw-r--r--sys/mips/mips32/adm5120/obiovar.h66
-rw-r--r--sys/mips/mips32/adm5120/std.adm512010
-rw-r--r--sys/mips/mips32/adm5120/uart_bus_adm5120.c93
-rw-r--r--sys/mips/mips32/adm5120/uart_cpu_adm5120.c83
-rw-r--r--sys/mips/mips32/adm5120/uart_dev_adm5120.c452
-rw-r--r--sys/mips/mips32/adm5120/uart_dev_adm5120.h80
-rw-r--r--sys/mips/mips32/idt/files.idt8
-rw-r--r--sys/mips/mips32/idt/idt_machdep.c188
-rw-r--r--sys/mips/mips32/idt/idtpci.c565
-rw-r--r--sys/mips/mips32/idt/idtreg.h153
-rw-r--r--sys/mips/mips32/idt/if_kr.c1615
-rw-r--r--sys/mips/mips32/idt/if_krreg.h284
-rw-r--r--sys/mips/mips32/idt/obio.c514
-rw-r--r--sys/mips/mips32/idt/obiovar.h67
-rw-r--r--sys/mips/mips32/idt/std.idt5
-rw-r--r--sys/mips/mips32/idt/uart_bus_rc32434.c100
-rw-r--r--sys/mips/mips32/idt/uart_cpu_rc32434.c85
-rw-r--r--sys/mips/mips32/malta/files.malta9
-rw-r--r--sys/mips/mips32/malta/gt.c131
-rw-r--r--sys/mips/mips32/malta/gt_pci.c723
-rw-r--r--sys/mips/mips32/malta/gtreg.h126
-rw-r--r--sys/mips/mips32/malta/gtvar.h36
-rw-r--r--sys/mips/mips32/malta/malta_machdep.c305
-rw-r--r--sys/mips/mips32/malta/maltareg.h243
-rw-r--r--sys/mips/mips32/malta/obio.c185
-rw-r--r--sys/mips/mips32/malta/obiovar.h58
-rw-r--r--sys/mips/mips32/malta/std.malta9
-rw-r--r--sys/mips/mips32/malta/uart_bus_maltausart.c98
-rw-r--r--sys/mips/mips32/malta/uart_cpu_maltausart.c82
-rw-r--r--sys/mips/mips32/malta/yamon.c65
-rw-r--r--sys/mips/mips32/malta/yamon.h93
-rw-r--r--sys/mips/mips32/sentry5/files.sentry514
-rw-r--r--sys/mips/mips32/sentry5/obio.c187
-rw-r--r--sys/mips/mips32/sentry5/obiovar.h58
-rw-r--r--sys/mips/mips32/sentry5/s5_machdep.c241
-rw-r--r--sys/mips/mips32/sentry5/s5reg.h58
-rw-r--r--sys/mips/mips32/sentry5/siba_cc.c154
-rw-r--r--sys/mips/mips32/sentry5/siba_mips.c113
-rw-r--r--sys/mips/mips32/sentry5/siba_sdram.c114
-rw-r--r--sys/mips/mips32/sentry5/uart_bus_sbusart.c95
-rw-r--r--sys/mips/mips32/sentry5/uart_cpu_sbusart.c82
50 files changed, 11444 insertions, 0 deletions
diff --git a/sys/mips/mips32/adm5120/adm5120_machdep.c b/sys/mips/mips32/adm5120/adm5120_machdep.c
new file mode 100644
index 0000000..eca9b18
--- /dev/null
+++ b/sys/mips/mips32/adm5120/adm5120_machdep.c
@@ -0,0 +1,157 @@
+/*-
+ * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 OR HIS RELATIVES 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 MIND, 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 "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/cons.h>
+#include <sys/exec.h>
+#include <sys/ucontext.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/cache.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/intr_machdep.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+#include <machine/pte.h>
+#include <machine/sigframe.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+extern int *edata;
+extern int *end;
+
+static void
+mips_init(void)
+{
+ int i;
+
+ printf("entry: mips_init()\n");
+
+ bootverbose = 1;
+ realmem = btoc(16 << 20);
+
+ for (i = 0; i < 10; i++) {
+ phys_avail[i] = 0;
+ }
+
+ /* phys_avail regions are in bytes */
+ phys_avail[0] = MIPS_KSEG0_TO_PHYS((vm_offset_t)&end);
+ phys_avail[1] = ctob(realmem);
+
+ physmem = realmem;
+
+ init_param1();
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+#ifdef DDB
+ kdb_init();
+#endif
+}
+
+void
+platform_halt(void)
+{
+
+}
+
+
+void
+platform_identify(void)
+{
+
+}
+
+void
+platform_reset(void)
+{
+
+ __asm __volatile("li $25, 0xbfc00000");
+ __asm __volatile("j $25");
+}
+
+void
+platform_trap_enter(void)
+{
+
+}
+
+void
+platform_trap_exit(void)
+{
+
+}
+
+void
+platform_start(__register_t a0 __unused, __register_t a1 __unused,
+ __register_t a2 __unused, __register_t a3 __unused)
+{
+ vm_offset_t kernend;
+ uint64_t platform_counter_freq = 175 * 1000 * 1000;
+
+ /* clear the BSS and SBSS segments */
+ kernend = round_page((vm_offset_t)&end);
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+ cninit();
+ mips_init();
+ /* Set counter_freq for tick_init_params() */
+ platform_counter_freq = 175 * 1000 * 1000;
+
+ mips_timer_init_params(platform_counter_freq, 0);
+}
diff --git a/sys/mips/mips32/adm5120/adm5120reg.h b/sys/mips/mips32/adm5120/adm5120reg.h
new file mode 100644
index 0000000..2f15e46
--- /dev/null
+++ b/sys/mips/mips32/adm5120/adm5120reg.h
@@ -0,0 +1,294 @@
+/* $NetBSD: adm5120reg.h,v 1.1 2007/03/20 08:52:03 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS
+ * 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 _ADM5120REG_H_
+#define _ADM5120REG_H_
+
+/* Helpers from NetBSD */
+/* __BIT(n): nth bit, where __BIT(0) == 0x1. */
+#define __BIT(__n) \
+ (((__n) >= NBBY * sizeof(uintmax_t)) ? 0 : ((uintmax_t)1 << (__n)))
+
+/* __BITS(m, n): bits m through n, m < n. */
+#define __BITS(__m, __n) \
+ ((__BIT(MAX((__m), (__n)) + 1) - 1) ^ (__BIT(MIN((__m), (__n))) - 1))
+
+/* Last byte of physical address space. */
+#define ADM5120_TOP 0x1fffffff
+#define ADM5120_BOTTOM 0x0
+
+/* Flash addresses */
+#define ADM5120_BASE_SRAM0 0x1fc00000
+
+/* UARTs */
+#define ADM5120_BASE_UART1 0x12800000
+#define ADM5120_BASE_UART0 0x12600000
+
+/* ICU */
+#define ADM5120_BASE_ICU 0x12200000
+#define ICU_STATUS_REG 0x00
+#define ICU_RAW_STATUS_REG 0x04
+#define ICU_ENABLE_REG 0x08
+#define ICU_DISABLE_REG 0x0c
+#define ICU_SOFT_REG 0x10
+#define ICU_MODE_REG 0x14
+#define ICU_FIQ_STATUS_REG 0x18
+#define ICU_TESTSRC_REG 0x1c
+#define ICU_SRCSEL_REG 0x20
+#define ICU_LEVEL_REG 0x24
+#define ICU_INT_MASK 0x3ff
+
+/* Switch */
+#define ADM5120_BASE_SWITCH 0x12000000
+#define SW_CODE_REG 0x00
+#define CLKS_MASK 0x00300000
+#define CLKS_175MHZ 0x00000000
+#define CLKS_200MHZ 0x00100000
+#define SW_SFTRES_REG 0x04
+#define SW_MEMCONT_REG 0x1c
+#define SDRAM_SIZE_4MBYTES 0x0001
+#define SDRAM_SIZE_8MBYTES 0x0002
+#define SDRAM_SIZE_16MBYTES 0x0003
+#define SDRAM_SIZE_64MBYTES 0x0004
+#define SDRAM_SIZE_128MBYTES 0x0005
+#define SDRAM_SIZE_MASK 0x0007
+#define SRAM0_SIZE_SHIFT 8
+#define SRAM1_SIZE_SHIFT 16
+#define SRAM_MASK 0x0007
+#define SRAM_SSIZE 0x40000
+
+#define ADM5120_BASE_PCI_CONFDATA 0x115ffff8
+#define ADM5120_BASE_PCI_CONFADDR 0x115ffff0
+#define ADM5120_BASE_PCI_IO 0x11500000
+#define ADM5120_BASE_PCI_MEM 0x11400000
+#define ADM5120_BASE_USB 0x11200000
+#define ADM5120_BASE_MPMC 0x11000000
+#define ADM5120_BASE_EXTIO1 0x10e00000
+#define ADM5120_BASE_EXTIO0 0x10c00000
+#define ADM5120_BASE_RSVD0 0x10800000
+#define ADM5120_BASE_SRAM1 0x10000000
+
+#define _REG_READ(b, o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((b) + (o)))
+#define SW_READ(o) _REG_READ(ADM5120_BASE_SWITCH, o)
+
+#define _REG_WRITE(b, o, v) (_REG_READ(b, o)) = (v)
+#define SW_WRITE(o, v) _REG_WRITE(ADM5120_BASE_SWITCH,o, v)
+
+/* USB */
+
+/* Watchdog Timers: base address is switch controller */
+
+#define ADM5120_WDOG0 0x00c0
+#define ADM5120_WDOG1 0x00c4
+
+#define ADM5120_WDOG0_WTTR __BIT(31) /* 0: do not reset,
+ * 1: reset on wdog expiration
+ */
+#define ADM5120_WDOG1_WDE __BIT(31) /* 0: deactivate,
+ * 1: drop all CPU-bound
+ * packets, disable flow
+ * control on all ports.
+ */
+#define ADM5120_WDOG_WTS_MASK __BITS(30, 16) /* Watchdog Timer Set:
+ * timer expires when it
+ * reaches WTS. Units of
+ * 10ms.
+ */
+#define ADM5120_WDOG_RSVD __BIT(15)
+#define ADM5120_WDOG_WT_MASK __BITS(14, 0) /* Watchdog Timer:
+ * counts up, write to clear.
+ */
+
+/* GPIO: base address is switch controller */
+#define ADM5120_GPIO0 0x00b8
+
+#define ADM5120_GPIO0_OV __BITS(31, 24) /* rw: output value */
+#define ADM5120_GPIO0_OE __BITS(23, 16) /* rw: output enable,
+ * bit[n] = 0 -> input
+ * bit[n] = 1 -> output
+ */
+#define ADM5120_GPIO0_IV __BITS(15, 8) /* ro: input value */
+#define ADM5120_GPIO0_RSVD __BITS(7, 0) /* rw: reserved */
+
+#define ADM5120_GPIO2 0x00bc
+#define ADM5120_GPIO2_EW __BIT(6) /* 1: enable wait state pin,
+ * pin GPIO[0], for GPIO[1]
+ * or GPIO[3] Chip Select:
+ * memory controller waits for
+ * WAIT# inactive (high).
+ */
+#define ADM5120_GPIO2_CSX1 __BIT(5) /* 1: GPIO[3:4] act as
+ * Chip Select for
+ * External I/O 1 (CSX1)
+ * and External Interrupt 1
+ * (INTX1), respectively.
+ * 0: CSX1/INTX1 disabled
+ */
+#define ADM5120_GPIO2_CSX0 __BIT(4) /* 1: GPIO[1:2] act as
+ * Chip Select for
+ * External I/O 0 (CSX0)
+ * and External Interrupt 0
+ * (INTX0), respectively.
+ * 0: CSX0/INTX0 disabled
+ */
+
+/* MultiPort Memory Controller (MPMC) */
+
+#define ADM5120_MPMC_CONTROL 0x000
+#define ADM5120_MPMC_CONTROL_DWB __BIT(3) /* write 1 to
+ * drain write
+ * buffers. write 0
+ * for normal buffer
+ * operation.
+ */
+#define ADM5120_MPMC_CONTROL_LPM __BIT(2) /* 1: activate low-power
+ * mode. SDRAM is
+ * still refreshed.
+ */
+#define ADM5120_MPMC_CONTROL_AM __BIT(1) /* 1: address mirror:
+ * static memory
+ * chip select 0
+ * is mapped to chip
+ * select 1.
+ */
+#define ADM5120_MPMC_CONTROL_ME __BIT(0) /* 0: disable MPMC.
+ * DRAM is not
+ * refreshed.
+ * 1: enable MPMC.
+ */
+
+#define ADM5120_MPMC_STATUS 0x004
+#define ADM5120_MPMC_STATUS_SRA __BIT(2) /* read-only
+ * MPMC operating mode
+ * indication,
+ * 1: self-refresh
+ * acknowledge
+ * 0: normal mode
+ */
+#define ADM5120_MPMC_STATUS_WBS __BIT(1) /* read-only
+ * write-buffer status,
+ * 0: buffers empty
+ * 1: contain data
+ */
+#define ADM5120_MPMC_STATUS_BU __BIT(0) /* read-only MPMC
+ * "busy" indication,
+ * 0: MPMC idle
+ * 1: MPMC is performing
+ * memory transactions
+ */
+
+#define ADM5120_MPMC_SEW 0x080
+#define ADM5120_MPMC_SEW_RSVD __BITS(31, 10)
+#define ADM5120_MPMC_SEW_EWTO __BITS(9, 0) /* timeout access after
+ * 16 * (n + 1) clock cycles
+ * (XXX which clock?)
+ */
+
+#define ADM5120_MPMC_SC(__i) (0x200 + 0x020 * (__i))
+#define ADM5120_MPMC_SC_RSVD0 __BITS(31, 21)
+#define ADM5120_MPMC_SC_WP __BIT(20) /* 1: write protect */
+#define ADM5120_MPMC_SC_BE __BIT(20) /* 1: enable write buffer */
+#define ADM5120_MPMC_SC_RSVD1 __BITS(18, 9)
+#define ADM5120_MPMC_SC_EW __BIT(8) /* 1: enable extended wait;
+ */
+#define ADM5120_MPMC_SC_BLS __BIT(7) /* 0: byte line state pins
+ * are active high on read,
+ * active low on write.
+ *
+ * 1: byte line state pins
+ * are active low on read and
+ * on write.
+ */
+#define ADM5120_MPMC_SC_CCP __BIT(6) /* 0: chip select is active low,
+ * 1: active high
+ */
+#define ADM5120_MPMC_SC_RSVD2 __BITS(5, 4)
+#define ADM5120_MPMC_SC_PM __BIT(3) /* 0: page mode disabled,
+ * 1: enable asynchronous
+ * page mode four
+ */
+#define ADM5120_MPMC_SC_RSVD3 __BIT(2)
+#define ADM5120_MPMC_SC_MW_MASK __BITS(1, 0) /* memory width, bits */
+#define ADM5120_MPMC_SC_MW_8B __SHIFTIN(0, ADM5120_MPMC_SC_MW_MASK)
+#define ADM5120_MPMC_SC_MW_16B __SHIFTIN(1, ADM5120_MPMC_SC_MW_MASK)
+#define ADM5120_MPMC_SC_MW_32B __SHIFTIN(2, ADM5120_MPMC_SC_MW_MASK)
+#define ADM5120_MPMC_SC_MW_RSVD __SHIFTIN(3, ADM5120_MPMC_SC_MW_MASK)
+
+#define ADM5120_MPMC_SWW(__i) (0x204 + 0x020 * (__i))
+#define ADM5120_MPMC_SWW_RSVD __BITS(31, 4)
+#define ADM5120_MPMC_SWW_WWE __BITS(3, 0) /* delay (n + 1) * HCLK cycles
+ * after asserting chip select
+ * (CS) before asserting write
+ * enable (WE)
+ */
+
+#define ADM5120_MPMC_SWO(__i) (0x208 + 0x020 * (__i))
+#define ADM5120_MPMC_SWO_RSVD __BITS(31, 4)
+#define ADM5120_MPMC_SWO_WOE __BITS(3, 0) /* delay n * HCLK cycles
+ * after asserting chip select
+ * before asserting output
+ * enable (OE)
+ */
+
+#define ADM5120_MPMC_SWR(__i) (0x20c + 0x020 * (__i))
+#define ADM5120_MPMC_SWR_RSVD __BITS(31, 5)
+#define ADM5120_MPMC_SWR_NMRW __BITS(4, 0) /* read wait states for
+ * either first page-mode
+ * access or for non-page mode
+ * read, (n + 1) * HCLK cycles
+ */
+
+#define ADM5120_MPMC_SWP(__i) (0x210 + 0x020 * (__i))
+#define ADM5120_MPMC_SWP_RSVD __BITS(31, 5)
+#define ADM5120_MPMC_SWP_WPS __BITS(4, 0) /* read wait states for
+ * second and subsequent
+ * page-mode read,
+ * (n + 1) * HCLK cycles
+ */
+
+#define ADM5120_MPMC_SWWR(__i) (0x214 + 0x020 * (__i))
+#define ADM5120_MPMC_SWWR_RSVD __BITS(31, 5)
+#define ADM5120_MPMC_SWWR_WWS __BITS(4, 0) /* write wait states after
+ * the first read (??),
+ * (n + 2) * HCLK cycles
+ */
+
+#define ADM5120_MPMC_SWT(__i) (0x218 + 0x020 * (__i))
+#define ADM5120_MPMC_SWT_RSVD __BITS(31, 4)
+#define ADM5120_MPMC_SWT_WAITTURN __BITS(3, 0) /* bus turnaround time,
+ * (n + 1) * HCLK cycles
+ */
+
+#endif /* _ADM5120REG_H_ */
diff --git a/sys/mips/mips32/adm5120/admpci.c b/sys/mips/mips32/adm5120/admpci.c
new file mode 100644
index 0000000..741a2fa
--- /dev/null
+++ b/sys/mips/mips32/adm5120/admpci.c
@@ -0,0 +1,503 @@
+/* $NetBSD: admpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2007 David Young. 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * 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.
+ */
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix 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. The name of Itronix Inc. may not be used to endorse
+ * or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX 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 ITRONIX 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/pmap.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/pci/pcib_private.h>
+#include "pcib_if.h"
+
+#include <mips/mips32/adm5120/adm5120reg.h>
+
+#ifdef ADMPCI_DEBUG
+int admpci_debug = 1;
+#define ADMPCI_DPRINTF(__fmt, ...) \
+do { \
+ if (admpci_debug) \
+ printf((__fmt), __VA_ARGS__); \
+} while (/*CONSTCOND*/0)
+#else /* !ADMPCI_DEBUG */
+#define ADMPCI_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0)
+#endif /* ADMPCI_DEBUG */
+
+#define ADMPCI_TAG_BUS_MASK __BITS(23, 16)
+/* Bit 11 is reserved. It selects the AHB-PCI bridge. Let device 0
+ * be the bridge. For all other device numbers, let bit[11] == 0.
+ */
+#define ADMPCI_TAG_DEVICE_MASK __BITS(15, 11)
+#define ADMPCI_TAG_DEVICE_SUBMASK __BITS(15, 12)
+#define ADMPCI_TAG_DEVICE_BRIDGE __BIT(11)
+#define ADMPCI_TAG_FUNCTION_MASK __BITS(10, 8)
+#define ADMPCI_TAG_REGISTER_MASK __BITS(7, 0)
+
+#define ADMPCI_MAX_DEVICE
+
+struct admpci_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_st;
+
+ /* Access to PCI config registers */
+ bus_space_handle_t sc_addrh;
+ bus_space_handle_t sc_datah;
+
+ int sc_busno;
+ struct rman sc_mem_rman;
+ struct rman sc_io_rman;
+ struct rman sc_irq_rman;
+ uint32_t sc_mem;
+ uint32_t sc_io;
+};
+
+static int
+admpci_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+admpci_attach(device_t dev)
+{
+ int busno = 0;
+ struct admpci_softc *sc = device_get_softc(dev);
+
+ sc->sc_dev = dev;
+ sc->sc_busno = busno;
+
+ /* Use KSEG1 to access IO ports for it is uncached */
+ sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO);
+ sc->sc_io_rman.rm_type = RMAN_ARRAY;
+ sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports";
+ if (rman_init(&sc->sc_io_rman) != 0 ||
+ rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) {
+ panic("admpci_attach: failed to set up I/O rman");
+ }
+
+ /* Use KSEG1 to access PCI memory for it is uncached */
+ sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM);
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory";
+ if (rman_init(&sc->sc_mem_rman) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman,
+ sc->sc_mem, sc->sc_mem + 0x100000) != 0) {
+ panic("admpci_attach: failed to set up memory rman");
+ }
+
+ sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+ sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs";
+ if (rman_init(&sc->sc_irq_rman) != 0 ||
+ rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
+ panic("admpci_attach: failed to set up IRQ rman");
+
+ if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0,
+ &sc->sc_addrh) != 0) {
+ device_printf(sc->sc_dev, "unable to address space\n");
+ panic("bus_space_map failed");
+ }
+
+ if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0,
+ &sc->sc_datah) != 0) {
+ device_printf(sc->sc_dev, "unable to address space\n");
+ panic("bus_space_map failed");
+ }
+
+ device_add_child(dev, "pci", busno);
+ return (bus_generic_attach(dev));
+}
+
+static int
+admpci_maxslots(device_t dev)
+{
+
+ return (PCI_SLOTMAX);
+}
+
+static uint32_t
+admpci_make_addr(int bus, int slot, int func, int reg)
+{
+
+ return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg);
+}
+
+static uint32_t
+admpci_read_config(device_t dev, int bus, int slot, int func, int reg,
+ int bytes)
+{
+ struct admpci_softc *sc = device_get_softc(dev);
+ uint32_t data;
+ uint32_t shift, mask;
+ bus_addr_t addr;
+
+ ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__,
+ (void *)sc, bus, slot, func, reg);
+
+ addr = admpci_make_addr(bus, slot, func, reg);
+
+ ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
+ (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
+
+ bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
+ data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0);
+
+ switch (reg % 4) {
+ case 3:
+ shift = 24;
+ break;
+ case 2:
+ shift = 16;
+ break;
+ case 1:
+ shift = 8;
+ break;
+ default:
+ shift = 0;
+ break;
+ }
+
+ switch (bytes) {
+ case 1:
+ mask = 0xff;
+ data = (data >> shift) & mask;
+ break;
+ case 2:
+ mask = 0xffff;
+ if (reg % 4 == 0)
+ data = data & mask;
+ else
+ data = (data >> 16) & mask;
+ break;
+ case 4:
+ break;
+ default:
+ panic("%s: wrong bytes count", __func__);
+ break;
+ }
+
+ ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data);
+ return (data);
+}
+
+static void
+admpci_write_config(device_t dev, int bus, int slot, int func, int reg,
+ uint32_t data, int bytes)
+{
+ struct admpci_softc *sc = device_get_softc(dev);
+ bus_addr_t addr;
+ uint32_t reg_data;
+ uint32_t shift, mask;
+
+ ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__,
+ (void *)sc, bus, slot, func, reg);
+
+ if (bytes != 4) {
+ reg_data = admpci_read_config(dev, bus, slot, func, reg, 4);
+
+ switch (reg % 4) {
+ case 3:
+ shift = 24;
+ break;
+ case 2:
+ shift = 16;
+ break;
+ case 1:
+ shift = 8;
+ break;
+ default:
+ shift = 0;
+ break;
+ }
+
+ switch (bytes) {
+ case 1:
+ mask = 0xff;
+ data = (reg_data & ~ (mask << shift)) | (data << shift);
+ break;
+ case 2:
+ mask = 0xffff;
+ if (reg % 4 == 0)
+ data = (reg_data & ~mask) | data;
+ else
+ data = (reg_data & ~ (mask << shift)) |
+ (data << shift);
+ break;
+ case 4:
+ break;
+ default:
+ panic("%s: wrong bytes count", __func__);
+ break;
+ }
+ }
+
+ addr = admpci_make_addr(bus, slot, func, reg);
+
+ ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__,
+ (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr);
+
+ bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr);
+ bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data);
+}
+
+static int
+admpci_route_interrupt(device_t pcib, device_t dev, int pin)
+{
+ /* TODO: implement */
+ return (0);
+}
+
+static int
+admpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct admpci_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = 0;
+ return (0);
+ case PCIB_IVAR_BUS:
+ *result = sc->sc_busno;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static int
+admpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
+{
+ struct admpci_softc * sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_busno = result;
+ return (0);
+ }
+ return (ENOENT);
+}
+
+static struct resource *
+admpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+
+ return (NULL);
+#if 0
+ struct admpci_softc *sc = device_get_softc(bus);
+ struct resource *rv = NULL;
+ struct rman *rm;
+ bus_space_handle_t bh = 0;
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->sc_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_mem_rman;
+ bh = sc->sc_mem;
+ break;
+ case SYS_RES_IOPORT:
+ rm = &sc->sc_io_rman;
+ bh = sc->sc_io;
+ break;
+ default:
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == NULL)
+ return (NULL);
+ rman_set_rid(rv, *rid);
+ if (type != SYS_RES_IRQ) {
+ bh += (rman_get_start(rv));
+
+ rman_set_bustag(rv, sc->sc_st);
+ rman_set_bushandle(rv, bh);
+ if (flags & RF_ACTIVE) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+ }
+ return (rv);
+#endif
+}
+
+static int
+admpci_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ bus_space_handle_t p;
+ int error;
+
+ if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
+ error = bus_space_map(rman_get_bustag(r),
+ rman_get_bushandle(r), rman_get_size(r), 0, &p);
+ if (error)
+ return (error);
+ rman_set_bushandle(r, p);
+ }
+ return (rman_activate_resource(r));
+}
+
+static int
+admpci_setup_intr(device_t dev, device_t child, struct resource *ires,
+ int flags, driver_filter_t *filt, driver_intr_t *handler,
+ void *arg, void **cookiep)
+{
+
+#if 0
+ struct admpci_softc *sc = device_get_softc(dev);
+ struct intr_event *event;
+ int irq, error;
+
+ irq = rman_get_start(ires);
+ if (irq >= ICU_LEN || irq == 2)
+ panic("%s: bad irq or type", __func__);
+
+ event = sc->sc_eventstab[irq];
+ if (event == NULL) {
+ error = intr_event_create(&event, (void *)irq, 0,
+ (void (*)(void *))NULL, "admpci intr%d:", irq);
+ if (error)
+ return 0;
+ sc->sc_eventstab[irq] = event;
+ }
+
+ intr_event_add_handler(event, device_get_nameunit(child), filt,
+ handler, arg, intr_priority(flags), flags, cookiep);
+
+ /* Enable it, set trigger mode. */
+ sc->sc_imask &= ~(1 << irq);
+ sc->sc_elcr &= ~(1 << irq);
+
+ admpci_set_icus(sc);
+#endif
+
+ return (0);
+}
+
+static int
+admpci_teardown_intr(device_t dev, device_t child, struct resource *res,
+ void *cookie)
+{
+
+ return (intr_event_remove_handler(cookie));
+}
+
+static device_method_t admpci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, admpci_probe),
+ DEVMETHOD(device_attach, admpci_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, admpci_read_ivar),
+ DEVMETHOD(bus_write_ivar, admpci_write_ivar),
+ DEVMETHOD(bus_alloc_resource, admpci_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, admpci_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, admpci_setup_intr),
+ DEVMETHOD(bus_teardown_intr, admpci_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, admpci_maxslots),
+ DEVMETHOD(pcib_read_config, admpci_read_config),
+ DEVMETHOD(pcib_write_config, admpci_write_config),
+ DEVMETHOD(pcib_route_interrupt, admpci_route_interrupt),
+
+ {0, 0}
+};
+
+static driver_t admpci_driver = {
+ "pcib",
+ admpci_methods,
+ sizeof(struct admpci_softc),
+};
+
+static devclass_t admpci_devclass;
+
+DRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0);
diff --git a/sys/mips/mips32/adm5120/console.c b/sys/mips/mips32/adm5120/console.c
new file mode 100644
index 0000000..899aa5b
--- /dev/null
+++ b/sys/mips/mips32/adm5120/console.c
@@ -0,0 +1,93 @@
+/* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */
+
+/*-
+ * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS
+ * 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/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+
+#include <sys/cons.h>
+#include <sys/consio.h>
+
+static cn_probe_t uart_cnprobe;
+static cn_init_t uart_cninit;
+static cn_term_t uart_cnterm;
+static cn_getc_t uart_cngetc;
+static cn_putc_t uart_cnputc;
+
+static void
+uart_cnprobe(struct consdev *cp)
+{
+
+ sprintf(cp->cn_name, "uart");
+ cp->cn_pri = CN_NORMAL;
+}
+
+static void
+uart_cninit(struct consdev *cp)
+{
+
+}
+
+
+void
+uart_cnputc(struct consdev *cp, int c)
+{
+ char chr;
+
+ chr = c;
+ while ((*((volatile unsigned long *)0xb2600018)) & 0x20) ;
+ (*((volatile unsigned long *)0xb2600000)) = c;
+ while ((*((volatile unsigned long *)0xb2600018)) & 0x20) ;
+}
+
+int
+uart_cngetc(struct consdev * cp)
+{
+
+ while ((*((volatile unsigned long *)0xb2600018)) & 0x10) ;
+ return (*((volatile unsigned long *)0xb2600000)) & 0xff;
+}
+
+static void
+uart_cnterm(struct consdev * cp)
+{
+
+}
+
+CONSOLE_DRIVER(uart);
diff --git a/sys/mips/mips32/adm5120/files.adm5120 b/sys/mips/mips32/adm5120/files.adm5120
new file mode 100644
index 0000000..31b92c8
--- /dev/null
+++ b/sys/mips/mips32/adm5120/files.adm5120
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+# ADM5120 on-board devices
+# mips/mips32/adm5120/console.c standard
+mips/mips32/adm5120/adm5120_machdep.c standard
+mips/mips32/adm5120/admpci.c optional admpci
+mips/mips32/adm5120/if_admsw.c optional admsw
+mips/mips32/adm5120/obio.c standard
+mips/mips32/adm5120/uart_bus_adm5120.c optional uart
+mips/mips32/adm5120/uart_cpu_adm5120.c optional uart
+mips/mips32/adm5120/uart_dev_adm5120.c optional uart
diff --git a/sys/mips/mips32/adm5120/if_admsw.c b/sys/mips/mips32/adm5120/if_admsw.c
new file mode 100644
index 0000000..c6f57e5
--- /dev/null
+++ b/sys/mips/mips32/adm5120/if_admsw.c
@@ -0,0 +1,1339 @@
+/* $NetBSD: if_admsw.c,v 1.3 2007/04/22 19:26:25 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS
+ * 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.
+ */
+/*
+ * Copyright (c) 2001 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.
+ */
+
+/*
+ * Device driver for Alchemy Semiconductor Au1x00 Ethernet Media
+ * Access Controller.
+ *
+ * TODO:
+ *
+ * Better Rx buffer management; we want to get new Rx buffers
+ * to the chip more quickly than we currently do.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <machine/bus.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+
+#include <mips/mips32/adm5120/adm5120reg.h>
+#include <mips/mips32/adm5120/if_admswreg.h>
+#include <mips/mips32/adm5120/if_admswvar.h>
+
+/* TODO: add locking */
+#define ADMSW_LOCK(sc) do {} while(0);
+#define ADMSW_UNLOCK(sc) do {} while(0);
+
+static uint8_t vlan_matrix[SW_DEVS] = {
+ (1 << 6) | (1 << 0), /* CPU + port0 */
+ (1 << 6) | (1 << 1), /* CPU + port1 */
+ (1 << 6) | (1 << 2), /* CPU + port2 */
+ (1 << 6) | (1 << 3), /* CPU + port3 */
+ (1 << 6) | (1 << 4), /* CPU + port4 */
+ (1 << 6) | (1 << 5), /* CPU + port5 */
+};
+
+/* ifnet entry points */
+static void admsw_start(struct ifnet *);
+static void admsw_watchdog(struct ifnet *);
+static int admsw_ioctl(struct ifnet *, u_long, caddr_t);
+static void admsw_init(void *);
+static void admsw_stop(struct ifnet *, int);
+
+static void admsw_shutdown(void *);
+
+static void admsw_reset(struct admsw_softc *);
+static void admsw_set_filter(struct admsw_softc *);
+
+static void admsw_txintr(struct admsw_softc *, int);
+static void admsw_rxintr(struct admsw_softc *, int);
+static int admsw_add_rxbuf(struct admsw_softc *, int, int);
+#define admsw_add_rxhbuf(sc, idx) admsw_add_rxbuf(sc, idx, 1)
+#define admsw_add_rxlbuf(sc, idx) admsw_add_rxbuf(sc, idx, 0)
+
+static int admsw_mediachange(struct ifnet *);
+static void admsw_mediastatus(struct ifnet *, struct ifmediareq *);
+
+static int admsw_intr(void *);
+
+/* bus entry points */
+static int admsw_probe(device_t dev);
+static int admsw_attach(device_t dev);
+static int admsw_detach(device_t dev);
+
+static void
+admsw_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ uint32_t *addr;
+
+ if (error)
+ return;
+
+ KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+ addr = arg;
+ *addr = segs->ds_addr;
+}
+
+static void
+admsw_rxbuf_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct admsw_descsoft *ds;
+
+ if (error)
+ return;
+
+ KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg));
+
+ ds = arg;
+ ds->ds_nsegs = nseg;
+ ds->ds_addr[0] = segs[0].ds_addr;
+ ds->ds_len[0] = segs[0].ds_len;
+
+}
+
+static void
+admsw_mbuf_map_addr(void *arg, bus_dma_segment_t *segs, int nseg,
+ bus_size_t mapsize, int error)
+{
+ struct admsw_descsoft *ds;
+
+ if (error)
+ return;
+
+ ds = arg;
+
+ if((nseg != 1) && (nseg != 2))
+ panic("%s: nseg == %d\n", __func__, nseg);
+
+ ds->ds_nsegs = nseg;
+ ds->ds_addr[0] = segs[0].ds_addr;
+ ds->ds_len[0] = segs[0].ds_len;
+
+ if(nseg > 1) {
+ ds->ds_addr[1] = segs[1].ds_addr;
+ ds->ds_len[1] = segs[1].ds_len;
+ }
+}
+
+
+
+static int
+admsw_probe(device_t dev)
+{
+
+ device_set_desc(dev, "ADM5120 Switch Engine");
+ return (0);
+}
+
+#define REG_READ(o) bus_read_4((sc)->mem_res, (o))
+#define REG_WRITE(o,v) bus_write_4((sc)->mem_res, (o),(v))
+
+static void
+admsw_init_bufs(struct admsw_softc *sc)
+{
+ int i;
+ struct admsw_desc *desc;
+
+ for (i = 0; i < ADMSW_NTXHDESC; i++) {
+ if (sc->sc_txhsoft[i].ds_mbuf != NULL) {
+ m_freem(sc->sc_txhsoft[i].ds_mbuf);
+ sc->sc_txhsoft[i].ds_mbuf = NULL;
+ }
+ desc = &sc->sc_txhdescs[i];
+ desc->data = 0;
+ desc->cntl = 0;
+ desc->len = MAC_BUFLEN;
+ desc->status = 0;
+ ADMSW_CDTXHSYNC(sc, i,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ }
+ sc->sc_txhdescs[ADMSW_NTXHDESC - 1].data |= ADM5120_DMA_RINGEND;
+ ADMSW_CDTXHSYNC(sc, ADMSW_NTXHDESC - 1,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ for (i = 0; i < ADMSW_NRXHDESC; i++) {
+ if (sc->sc_rxhsoft[i].ds_mbuf == NULL) {
+ if (admsw_add_rxhbuf(sc, i) != 0)
+ panic("admsw_init_bufs\n");
+ } else
+ ADMSW_INIT_RXHDESC(sc, i);
+ }
+
+ for (i = 0; i < ADMSW_NTXLDESC; i++) {
+ if (sc->sc_txlsoft[i].ds_mbuf != NULL) {
+ m_freem(sc->sc_txlsoft[i].ds_mbuf);
+ sc->sc_txlsoft[i].ds_mbuf = NULL;
+ }
+ desc = &sc->sc_txldescs[i];
+ desc->data = 0;
+ desc->cntl = 0;
+ desc->len = MAC_BUFLEN;
+ desc->status = 0;
+ ADMSW_CDTXLSYNC(sc, i,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ }
+ sc->sc_txldescs[ADMSW_NTXLDESC - 1].data |= ADM5120_DMA_RINGEND;
+ ADMSW_CDTXLSYNC(sc, ADMSW_NTXLDESC - 1,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ for (i = 0; i < ADMSW_NRXLDESC; i++) {
+ if (sc->sc_rxlsoft[i].ds_mbuf == NULL) {
+ if (admsw_add_rxlbuf(sc, i) != 0)
+ panic("admsw_init_bufs\n");
+ } else
+ ADMSW_INIT_RXLDESC(sc, i);
+ }
+
+ REG_WRITE(SEND_HBADDR_REG, ADMSW_CDTXHADDR(sc, 0));
+ REG_WRITE(SEND_LBADDR_REG, ADMSW_CDTXLADDR(sc, 0));
+ REG_WRITE(RECV_HBADDR_REG, ADMSW_CDRXHADDR(sc, 0));
+ REG_WRITE(RECV_LBADDR_REG, ADMSW_CDRXLADDR(sc, 0));
+
+ sc->sc_txfree = ADMSW_NTXLDESC;
+ sc->sc_txnext = 0;
+ sc->sc_txdirty = 0;
+ sc->sc_rxptr = 0;
+}
+
+static void
+admsw_setvlan(struct admsw_softc *sc, char matrix[6])
+{
+ uint32_t i;
+
+ i = matrix[0] + (matrix[1] << 8) + (matrix[2] << 16) + (matrix[3] << 24);
+ REG_WRITE(VLAN_G1_REG, i);
+ i = matrix[4] + (matrix[5] << 8);
+ REG_WRITE(VLAN_G2_REG, i);
+}
+
+static void
+admsw_reset(struct admsw_softc *sc)
+{
+ uint32_t wdog1;
+ int i;
+
+ REG_WRITE(PORT_CONF0_REG,
+ REG_READ(PORT_CONF0_REG) | PORT_CONF0_DP_MASK);
+ REG_WRITE(CPUP_CONF_REG,
+ REG_READ(CPUP_CONF_REG) | CPUP_CONF_DCPUP);
+
+ /* Wait for DMA to complete. Overkill. In 3ms, we can
+ * send at least two entire 1500-byte packets at 10 Mb/s.
+ */
+ DELAY(3000);
+
+ /* The datasheet recommends that we move all PHYs to reset
+ * state prior to software reset.
+ */
+ REG_WRITE(PHY_CNTL2_REG,
+ REG_READ(PHY_CNTL2_REG) & ~PHY_CNTL2_PHYR_MASK);
+
+ /* Reset the switch. */
+ REG_WRITE(ADMSW_SW_RES, 0x1);
+
+ DELAY(100 * 1000);
+
+ REG_WRITE(ADMSW_BOOT_DONE, ADMSW_BOOT_DONE_BO);
+
+ /* begin old code */
+ REG_WRITE(CPUP_CONF_REG,
+ CPUP_CONF_DCPUP | CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK |
+ CPUP_CONF_DMCP_MASK);
+
+ REG_WRITE(PORT_CONF0_REG, PORT_CONF0_EMCP_MASK | PORT_CONF0_EMBP_MASK);
+
+ REG_WRITE(PHY_CNTL2_REG,
+ REG_READ(PHY_CNTL2_REG) | PHY_CNTL2_ANE_MASK | PHY_CNTL2_PHYR_MASK |
+ PHY_CNTL2_AMDIX_MASK);
+
+ REG_WRITE(PHY_CNTL3_REG, REG_READ(PHY_CNTL3_REG) | PHY_CNTL3_RNT);
+
+ REG_WRITE(ADMSW_INT_MASK, INT_MASK);
+ REG_WRITE(ADMSW_INT_ST, INT_MASK);
+
+ /*
+ * While in DDB, we stop servicing interrupts, RX ring
+ * fills up and when free block counter falls behind FC
+ * threshold, the switch starts to emit 802.3x PAUSE
+ * frames. This can upset peer switches.
+ *
+ * Stop this from happening by disabling FC and D2
+ * thresholds.
+ */
+ REG_WRITE(FC_TH_REG,
+ REG_READ(FC_TH_REG) & ~(FC_TH_FCS_MASK | FC_TH_D2S_MASK));
+
+ admsw_setvlan(sc, vlan_matrix);
+
+ for (i = 0; i < SW_DEVS; i++) {
+ REG_WRITE(MAC_WT1_REG,
+ sc->sc_enaddr[2] |
+ (sc->sc_enaddr[3]<<8) |
+ (sc->sc_enaddr[4]<<16) |
+ ((sc->sc_enaddr[5]+i)<<24));
+ REG_WRITE(MAC_WT0_REG, (i<<MAC_WT0_VLANID_SHIFT) |
+ (sc->sc_enaddr[0]<<16) | (sc->sc_enaddr[1]<<24) |
+ MAC_WT0_WRITE | MAC_WT0_VLANID_EN);
+
+ while (!(REG_READ(MAC_WT0_REG) & MAC_WT0_WRITE_DONE));
+ }
+
+ wdog1 = REG_READ(ADM5120_WDOG1);
+ REG_WRITE(ADM5120_WDOG1, wdog1 & ~ADM5120_WDOG1_WDE);
+}
+
+static int
+admsw_attach(device_t dev)
+{
+ uint8_t enaddr[ETHER_ADDR_LEN];
+ struct admsw_softc *sc = (struct admsw_softc *) device_get_softc(dev);
+ struct ifnet *ifp;
+ int error, i, rid;
+
+ sc->sc_dev = dev;
+ device_printf(dev, "ADM5120 Switch Engine, %d ports\n", SW_DEVS);
+ sc->ndevs = 0;
+
+ /* XXXMIPS: fix it */
+ enaddr[0] = 0x00;
+ enaddr[1] = 0x0C;
+ enaddr[2] = 0x42;
+ enaddr[3] = 0x07;
+ enaddr[4] = 0xB2;
+ enaddr[5] = 0x4E;
+
+ memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr));
+
+ device_printf(sc->sc_dev, "base Ethernet address %s\n",
+ ether_sprintf(enaddr));
+
+ rid = 0;
+ if ((sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate memory resource\n");
+ return (ENXIO);
+ }
+
+ /* Hook up the interrupt handler. */
+ rid = 0;
+ if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return (ENXIO);
+ }
+
+ if ((error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
+ admsw_intr, NULL, sc, &sc->sc_ih)) != 0) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return (error);
+ }
+
+ /*
+ * Allocate the control data structures, and create and load the
+ * DMA map for it.
+ */
+ if ((error = bus_dma_tag_create(NULL, 4, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
+ NULL, NULL, sizeof(struct admsw_control_data), 1,
+ sizeof(struct admsw_control_data), 0, NULL, NULL,
+ &sc->sc_control_dmat)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create control data DMA map, error = %d\n",
+ error);
+ return (error);
+ }
+
+ if ((error = bus_dmamem_alloc(sc->sc_control_dmat,
+ (void **)&sc->sc_control_data, BUS_DMA_NOWAIT,
+ &sc->sc_cddmamap)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to allocate control data, error = %d\n", error);
+ return (error);
+ }
+
+ if ((error = bus_dmamap_load(sc->sc_control_dmat, sc->sc_cddmamap,
+ sc->sc_control_data, sizeof(struct admsw_control_data),
+ admsw_dma_map_addr, &sc->sc_cddma, 0)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to load control data DMA map, error = %d\n", error);
+ return (error);
+ }
+
+ /*
+ * Create the transmit buffer DMA maps.
+ */
+ if ((error = bus_dma_tag_create(NULL, 1, 0,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
+ NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, NULL,
+ &sc->sc_bufs_dmat)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create control data DMA map, error = %d\n",
+ error);
+ return (error);
+ }
+
+ for (i = 0; i < ADMSW_NTXHDESC; i++) {
+ if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0,
+ &sc->sc_txhsoft[i].ds_dmamap)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create txh DMA map %d, error = %d\n",
+ i, error);
+ return (error);
+ }
+ sc->sc_txhsoft[i].ds_mbuf = NULL;
+ }
+
+ for (i = 0; i < ADMSW_NTXLDESC; i++) {
+ if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0,
+ &sc->sc_txlsoft[i].ds_dmamap)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create txl DMA map %d, error = %d\n",
+ i, error);
+ return (error);
+ }
+ sc->sc_txlsoft[i].ds_mbuf = NULL;
+ }
+
+ /*
+ * Create the receive buffer DMA maps.
+ */
+ for (i = 0; i < ADMSW_NRXHDESC; i++) {
+ if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0,
+ &sc->sc_rxhsoft[i].ds_dmamap)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create rxh DMA map %d, error = %d\n",
+ i, error);
+ return (error);
+ }
+ sc->sc_rxhsoft[i].ds_mbuf = NULL;
+ }
+
+ for (i = 0; i < ADMSW_NRXLDESC; i++) {
+ if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0,
+ &sc->sc_rxlsoft[i].ds_dmamap)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create rxl DMA map %d, error = %d\n",
+ i, error);
+ return (error);
+ }
+ sc->sc_rxlsoft[i].ds_mbuf = NULL;
+ }
+
+ admsw_init_bufs(sc);
+ admsw_reset(sc);
+
+ for (i = 0; i < SW_DEVS; i++) {
+ ifmedia_init(&sc->sc_ifmedia[i], 0, admsw_mediachange,
+ admsw_mediastatus);
+ ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T, 0, NULL);
+ ifmedia_add(&sc->sc_ifmedia[i],
+ IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
+ ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX, 0, NULL);
+ ifmedia_add(&sc->sc_ifmedia[i],
+ IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
+ ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO, 0, NULL);
+ ifmedia_set(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO);
+
+ ifp = sc->sc_ifnet[i] = if_alloc(IFT_ETHER);;
+
+ /* Setup interface parameters */
+ ifp->if_softc = sc;
+ if_initname(ifp, device_get_name(dev), i);
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = admsw_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = admsw_start;
+ ifp->if_watchdog = admsw_watchdog;
+ ifp->if_timer = 0;
+ ifp->if_init = admsw_init;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_baudrate = IF_Mbps(100);
+ IFQ_SET_MAXLEN(&ifp->if_snd, max(ADMSW_NTXLDESC, IFQ_MAXLEN));
+ ifp->if_snd.ifq_drv_maxlen = max(ADMSW_NTXLDESC, IFQ_MAXLEN);
+ IFQ_SET_READY(&ifp->if_snd);
+ ifp->if_capabilities |= IFCAP_VLAN_MTU;
+
+ /* Attach the interface. */
+ ether_ifattach(ifp, enaddr);
+ enaddr[5]++;
+ }
+
+ /* XXX: admwdog_attach(sc); */
+
+ /* leave interrupts and cpu port disabled */
+ return (0);
+}
+
+static int
+admsw_detach(device_t dev)
+{
+
+ printf("TODO: DETACH\n");
+ return (0);
+}
+
+/*
+ * admsw_shutdown:
+ *
+ * Make sure the interface is stopped at reboot time.
+ */
+static void
+admsw_shutdown(void *arg)
+{
+ struct admsw_softc *sc = arg;
+ int i;
+
+ for (i = 0; i < SW_DEVS; i++)
+ admsw_stop(sc->sc_ifnet[i], 1);
+}
+
+/*
+ * admsw_start: [ifnet interface function]
+ *
+ * Start packet transmission on the interface.
+ */
+static void
+admsw_start(struct ifnet *ifp)
+{
+ struct admsw_softc *sc = ifp->if_softc;
+ struct mbuf *m0, *m;
+ struct admsw_descsoft *ds;
+ struct admsw_desc *desc;
+ bus_dmamap_t dmamap;
+ struct ether_header *eh;
+ int error, nexttx, len, i;
+ static int vlan = 0;
+
+ /*
+ * Loop through the send queues, setting up transmit descriptors
+ * unitl we drain the queues, or use up all available transmit
+ * descriptors.
+ */
+ for (;;) {
+ vlan++;
+ if (vlan == SW_DEVS)
+ vlan = 0;
+ i = vlan;
+ for (;;) {
+ ifp = sc->sc_ifnet[i];
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE))
+ == IFF_DRV_RUNNING) {
+ /* Grab a packet off the queue. */
+ IF_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 != NULL)
+ break;
+ }
+ i++;
+ if (i == SW_DEVS)
+ i = 0;
+ if (i == vlan)
+ return;
+ }
+ vlan = i;
+ m = NULL;
+
+ /* Get a spare descriptor. */
+ if (sc->sc_txfree == 0) {
+ /* No more slots left; notify upper layer. */
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ break;
+ }
+ nexttx = sc->sc_txnext;
+ desc = &sc->sc_txldescs[nexttx];
+ ds = &sc->sc_txlsoft[nexttx];
+ dmamap = ds->ds_dmamap;
+
+ /*
+ * Load the DMA map. If this fails, the packet either
+ * didn't fit in the alloted number of segments, or we
+ * were short on resources. In this case, we'll copy
+ * and try again.
+ */
+ if (m0->m_pkthdr.len < ETHER_MIN_LEN ||
+ bus_dmamap_load_mbuf(sc->sc_bufs_dmat, dmamap, m0,
+ admsw_mbuf_map_addr, ds, BUS_DMA_NOWAIT) != 0) {
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ device_printf(sc->sc_dev,
+ "unable to allocate Tx mbuf\n");
+ break;
+ }
+ if (m0->m_pkthdr.len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ device_printf(sc->sc_dev,
+ "unable to allocate Tx cluster\n");
+ m_freem(m);
+ break;
+ }
+ }
+ m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags;
+ m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *));
+ m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
+ if (m->m_pkthdr.len < ETHER_MIN_LEN) {
+ if (M_TRAILINGSPACE(m) < ETHER_MIN_LEN - m->m_pkthdr.len)
+ panic("admsw_start: M_TRAILINGSPACE\n");
+ memset(mtod(m, uint8_t *) + m->m_pkthdr.len, 0,
+ ETHER_MIN_LEN - ETHER_CRC_LEN - m->m_pkthdr.len);
+ m->m_pkthdr.len = m->m_len = ETHER_MIN_LEN;
+ }
+ error = bus_dmamap_load_mbuf(sc->sc_bufs_dmat,
+ dmamap, m, admsw_mbuf_map_addr, ds, BUS_DMA_NOWAIT);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "unable to load Tx buffer, error = %d\n",
+ error);
+ break;
+ }
+ }
+
+ if (m != NULL) {
+ m_freem(m0);
+ m0 = m;
+ }
+
+ /*
+ * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET.
+ */
+
+ /* Sync the DMA map. */
+ bus_dmamap_sync(sc->sc_bufs_dmat, dmamap, BUS_DMASYNC_PREWRITE);
+
+ if (ds->ds_nsegs != 1 && ds->ds_nsegs != 2)
+ panic("admsw_start: nsegs == %d\n", ds->ds_nsegs);
+ desc->data = ds->ds_addr[0];
+ desc->len = len = ds->ds_len[0];
+ if (ds->ds_nsegs > 1) {
+ len += ds->ds_len[1];
+ desc->cntl = ds->ds_addr[1] | ADM5120_DMA_BUF2ENABLE;
+ } else
+ desc->cntl = 0;
+ desc->status = (len << ADM5120_DMA_LENSHIFT) | (1 << vlan);
+ eh = mtod(m0, struct ether_header *);
+ if (ntohs(eh->ether_type) == ETHERTYPE_IP &&
+ m0->m_pkthdr.csum_flags & CSUM_IP)
+ desc->status |= ADM5120_DMA_CSUM;
+ if (nexttx == ADMSW_NTXLDESC - 1)
+ desc->data |= ADM5120_DMA_RINGEND;
+ desc->data |= ADM5120_DMA_OWN;
+
+ /* Sync the descriptor. */
+ ADMSW_CDTXLSYNC(sc, nexttx,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ REG_WRITE(SEND_TRIG_REG, 1);
+ /* printf("send slot %d\n",nexttx); */
+
+ /*
+ * Store a pointer to the packet so we can free it later.
+ */
+ ds->ds_mbuf = m0;
+
+ /* Advance the Tx pointer. */
+ sc->sc_txfree--;
+ sc->sc_txnext = ADMSW_NEXTTXL(nexttx);
+
+ /* Pass the packet to any BPF listeners. */
+ BPF_MTAP(ifp, m0);
+
+ /* Set a watchdog timer in case the chip flakes out. */
+ sc->sc_ifnet[0]->if_timer = 5;
+ }
+}
+
+/*
+ * admsw_watchdog: [ifnet interface function]
+ *
+ * Watchdog timer handler.
+ */
+static void
+admsw_watchdog(struct ifnet *ifp)
+{
+ struct admsw_softc *sc = ifp->if_softc;
+ int vlan;
+
+ /* Check if an interrupt was lost. */
+ if (sc->sc_txfree == ADMSW_NTXLDESC) {
+ device_printf(sc->sc_dev, "watchdog false alarm\n");
+ return;
+ }
+ if (sc->sc_ifnet[0]->if_timer != 0)
+ device_printf(sc->sc_dev, "watchdog timer is %d!\n",
+ sc->sc_ifnet[0]->if_timer);
+ admsw_txintr(sc, 0);
+ if (sc->sc_txfree == ADMSW_NTXLDESC) {
+ device_printf(sc->sc_dev, "tx IRQ lost (queue empty)\n");
+ return;
+ }
+ if (sc->sc_ifnet[0]->if_timer != 0) {
+ device_printf(sc->sc_dev, "tx IRQ lost (timer recharged)\n");
+ return;
+ }
+
+ device_printf(sc->sc_dev, "device timeout, txfree = %d\n",
+ sc->sc_txfree);
+ for (vlan = 0; vlan < SW_DEVS; vlan++)
+ admsw_stop(sc->sc_ifnet[vlan], 0);
+ admsw_init(sc);
+
+ /* Try to get more packets going. */
+ admsw_start(ifp);
+}
+
+/*
+ * admsw_ioctl: [ifnet interface function]
+ *
+ * Handle control requests from the operator.
+ */
+static int
+admsw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct admsw_softc *sc = ifp->if_softc;
+ struct ifdrv *ifd;
+ int error, port;
+
+ ADMSW_LOCK(sc);
+
+ switch (cmd) {
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ port = 0;
+ while(port < SW_DEVS)
+ if(ifp == sc->sc_ifnet[port])
+ break;
+ else
+ port++;
+ if (port >= SW_DEVS)
+ error = EOPNOTSUPP;
+ else
+ error = ifmedia_ioctl(ifp, (struct ifreq *)data,
+ &sc->sc_ifmedia[port], cmd);
+ break;
+
+ case SIOCGDRVSPEC:
+ case SIOCSDRVSPEC:
+ ifd = (struct ifdrv *) data;
+ if (ifd->ifd_cmd != 0 || ifd->ifd_len != sizeof(vlan_matrix)) {
+ error = EINVAL;
+ break;
+ }
+ if (cmd == SIOCGDRVSPEC) {
+ error = copyout(vlan_matrix, ifd->ifd_data,
+ sizeof(vlan_matrix));
+ } else {
+ error = copyin(ifd->ifd_data, vlan_matrix,
+ sizeof(vlan_matrix));
+ admsw_setvlan(sc, vlan_matrix);
+ }
+ break;
+
+ default:
+ error = ether_ioctl(ifp, cmd, data);
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+ admsw_set_filter(sc);
+ error = 0;
+ }
+ break;
+ }
+
+ /* Try to get more packets going. */
+ admsw_start(ifp);
+
+ ADMSW_UNLOCK(sc);
+ return (error);
+}
+
+
+/*
+ * admsw_intr:
+ *
+ * Interrupt service routine.
+ */
+static int
+admsw_intr(void *arg)
+{
+ struct admsw_softc *sc = arg;
+ uint32_t pending;
+
+ pending = REG_READ(ADMSW_INT_ST);
+ REG_WRITE(ADMSW_INT_ST, pending);
+
+ if (sc->ndevs == 0)
+ return (FILTER_STRAY);
+
+ if ((pending & ADMSW_INTR_RHD) != 0)
+ admsw_rxintr(sc, 1);
+
+ if ((pending & ADMSW_INTR_RLD) != 0)
+ admsw_rxintr(sc, 0);
+
+ if ((pending & ADMSW_INTR_SHD) != 0)
+ admsw_txintr(sc, 1);
+
+ if ((pending & ADMSW_INTR_SLD) != 0)
+ admsw_txintr(sc, 0);
+
+ return (FILTER_HANDLED);
+}
+
+/*
+ * admsw_txintr:
+ *
+ * Helper; handle transmit interrupts.
+ */
+static void
+admsw_txintr(struct admsw_softc *sc, int prio)
+{
+ struct ifnet *ifp;
+ struct admsw_desc *desc;
+ struct admsw_descsoft *ds;
+ int i, vlan;
+ int gotone = 0;
+
+ /* printf("txintr: txdirty: %d, txfree: %d\n",sc->sc_txdirty, sc->sc_txfree); */
+ for (i = sc->sc_txdirty; sc->sc_txfree != ADMSW_NTXLDESC;
+ i = ADMSW_NEXTTXL(i)) {
+
+ ADMSW_CDTXLSYNC(sc, i,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+ desc = &sc->sc_txldescs[i];
+ ds = &sc->sc_txlsoft[i];
+ if (desc->data & ADM5120_DMA_OWN) {
+ ADMSW_CDTXLSYNC(sc, i,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ break;
+ }
+
+ bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_bufs_dmat, ds->ds_dmamap);
+ m_freem(ds->ds_mbuf);
+ ds->ds_mbuf = NULL;
+
+ vlan = ffs(desc->status & 0x3f) - 1;
+ if (vlan < 0 || vlan >= SW_DEVS)
+ panic("admsw_txintr: bad vlan\n");
+ ifp = sc->sc_ifnet[vlan];
+ gotone = 1;
+ /* printf("clear tx slot %d\n",i); */
+
+ ifp->if_opackets++;
+
+ sc->sc_txfree++;
+ }
+
+ if (gotone) {
+ sc->sc_txdirty = i;
+ for (vlan = 0; vlan < SW_DEVS; vlan++)
+ sc->sc_ifnet[vlan]->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ ifp = sc->sc_ifnet[0];
+
+ /* Try to queue more packets. */
+ admsw_start(ifp);
+
+ /*
+ * If there are no more pending transmissions,
+ * cancel the watchdog timer.
+ */
+ if (sc->sc_txfree == ADMSW_NTXLDESC)
+ ifp->if_timer = 0;
+
+ }
+
+ /* printf("txintr end: txdirty: %d, txfree: %d\n",sc->sc_txdirty, sc->sc_txfree); */
+}
+
+/*
+ * admsw_rxintr:
+ *
+ * Helper; handle receive interrupts.
+ */
+static void
+admsw_rxintr(struct admsw_softc *sc, int high)
+{
+ struct ifnet *ifp;
+ struct admsw_descsoft *ds;
+ struct mbuf *m;
+ uint32_t stat;
+ int i, len, port, vlan;
+
+ /* printf("rxintr\n"); */
+
+ if (high)
+ panic("admsw_rxintr: high priority packet\n");
+
+#if 1
+ ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0)
+ ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ else {
+ i = sc->sc_rxptr;
+ do {
+ ADMSW_CDRXLSYNC(sc, i,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ i = ADMSW_NEXTRXL(i);
+ /* the ring is empty, just return. */
+ if (i == sc->sc_rxptr)
+ return;
+ ADMSW_CDRXLSYNC(sc, i,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+ } while (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN);
+
+ ADMSW_CDRXLSYNC(sc, i,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+ ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+ if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0)
+ ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ else {
+ ADMSW_CDRXLSYNC(sc, sc->sc_rxptr,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ /* We've fallen behind the chip: catch it. */
+#if 0
+ device_printf(sc->sc_dev,
+ "RX ring resync, base=%x, work=%x, %d -> %d\n",
+ REG_READ(RECV_LBADDR_REG),
+ REG_READ(RECV_LWADDR_REG), sc->sc_rxptr, i);
+#endif
+ sc->sc_rxptr = i;
+ /* ADMSW_EVCNT_INCR(&sc->sc_ev_rxsync); */
+ }
+ }
+#endif
+ for (i = sc->sc_rxptr;; i = ADMSW_NEXTRXL(i)) {
+ ds = &sc->sc_rxlsoft[i];
+
+ ADMSW_CDRXLSYNC(sc, i,
+ BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+ if (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN) {
+ ADMSW_CDRXLSYNC(sc, i,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ break;
+ }
+
+ /* printf("process slot %d\n",i); */
+
+ bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap,
+ BUS_DMASYNC_POSTREAD);
+
+ stat = sc->sc_rxldescs[i].status;
+ len = (stat & ADM5120_DMA_LEN) >> ADM5120_DMA_LENSHIFT;
+ len -= ETHER_CRC_LEN;
+ port = (stat & ADM5120_DMA_PORTID) >> ADM5120_DMA_PORTSHIFT;
+
+ for (vlan = 0; vlan < SW_DEVS; vlan++)
+ if ((1 << port) & vlan_matrix[vlan])
+ break;
+
+ if (vlan == SW_DEVS)
+ vlan = 0;
+
+ ifp = sc->sc_ifnet[vlan];
+
+ m = ds->ds_mbuf;
+ if (admsw_add_rxlbuf(sc, i) != 0) {
+ ifp->if_ierrors++;
+ ADMSW_INIT_RXLDESC(sc, i);
+ bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap,
+ BUS_DMASYNC_PREREAD);
+ continue;
+ }
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = len;
+ if ((stat & ADM5120_DMA_TYPE) == ADM5120_DMA_TYPE_IP) {
+ m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
+ if (!(stat & ADM5120_DMA_CSUMFAIL))
+ m->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+ }
+
+ BPF_MTAP(ifp, m);
+
+ /* Pass it on. */
+ (*ifp->if_input)(ifp, m);
+ ifp->if_ipackets++;
+ }
+
+ /* Update the receive pointer. */
+ sc->sc_rxptr = i;
+}
+
+/*
+ * admsw_init: [ifnet interface function]
+ *
+ * Initialize the interface. Must be called at splnet().
+ */
+static void
+admsw_init(void *xsc)
+{
+ struct admsw_softc *sc = xsc;
+ struct ifnet *ifp;
+ int i;
+
+ for (i = 0; i < SW_DEVS; i++) {
+ ifp = sc->sc_ifnet[i];
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ if (sc->ndevs == 0) {
+ admsw_init_bufs(sc);
+ admsw_reset(sc);
+ REG_WRITE(CPUP_CONF_REG,
+ CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK |
+ CPUP_CONF_DMCP_MASK);
+ /* clear all pending interrupts */
+ REG_WRITE(ADMSW_INT_ST, INT_MASK);
+
+ /* enable needed interrupts */
+ REG_WRITE(ADMSW_INT_MASK,
+ REG_READ(ADMSW_INT_MASK) &
+ ~(ADMSW_INTR_SHD | ADMSW_INTR_SLD |
+ ADMSW_INTR_RHD | ADMSW_INTR_RLD |
+ ADMSW_INTR_HDF | ADMSW_INTR_LDF));
+ }
+ sc->ndevs++;
+ }
+
+
+ /* mark iface as running */
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ }
+
+ /* Set the receive filter. */
+ admsw_set_filter(sc);
+}
+
+/*
+ * admsw_stop: [ifnet interface function]
+ *
+ * Stop transmission on the interface.
+ */
+static void
+admsw_stop(struct ifnet *ifp, int disable)
+{
+ struct admsw_softc *sc = ifp->if_softc;
+
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ return;
+
+ if (--sc->ndevs == 0) {
+ /* printf("debug: de-initializing hardware\n"); */
+
+ /* disable cpu port */
+ REG_WRITE(CPUP_CONF_REG,
+ CPUP_CONF_DCPUP | CPUP_CONF_CRCP |
+ CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK);
+
+ /* XXX We should disable, then clear? --dyoung */
+ /* clear all pending interrupts */
+ REG_WRITE(ADMSW_INT_ST, INT_MASK);
+
+ /* disable interrupts */
+ REG_WRITE(ADMSW_INT_MASK, INT_MASK);
+ }
+
+ /* Mark the interface as down and cancel the watchdog timer. */
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ ifp->if_timer = 0;
+
+ return;
+}
+
+/*
+ * admsw_set_filter:
+ *
+ * Set up the receive filter.
+ */
+static void
+admsw_set_filter(struct admsw_softc *sc)
+{
+ int i;
+ uint32_t allmc, anymc, conf, promisc;
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+
+ /* Find which ports should be operated in promisc mode. */
+ allmc = anymc = promisc = 0;
+ for (i = 0; i < SW_DEVS; i++) {
+ ifp = sc->sc_ifnet[i];
+ if (ifp->if_flags & IFF_PROMISC)
+ promisc |= vlan_matrix[i];
+
+ ifp->if_flags &= ~IFF_ALLMULTI;
+
+ IF_ADDR_LOCK(ifp);
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
+ {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+
+ anymc |= vlan_matrix[i];
+ }
+ IF_ADDR_UNLOCK(ifp);
+ }
+
+ conf = REG_READ(CPUP_CONF_REG);
+ /* 1 Disable forwarding of unknown & multicast packets to
+ * CPU on all ports.
+ * 2 Enable forwarding of unknown & multicast packets to
+ * CPU on ports where IFF_PROMISC or IFF_ALLMULTI is set.
+ */
+ conf |= CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK;
+ /* Enable forwarding of unknown packets to CPU on selected ports. */
+ conf ^= ((promisc << CPUP_CONF_DUNP_SHIFT) & CPUP_CONF_DUNP_MASK);
+ conf ^= ((allmc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK);
+ conf ^= ((anymc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK);
+ REG_WRITE(CPUP_CONF_REG, conf);
+}
+
+/*
+ * admsw_add_rxbuf:
+ *
+ * Add a receive buffer to the indicated descriptor.
+ */
+int
+admsw_add_rxbuf(struct admsw_softc *sc, int idx, int high)
+{
+ struct admsw_descsoft *ds;
+ struct mbuf *m;
+ int error;
+
+ if (high)
+ ds = &sc->sc_rxhsoft[idx];
+ else
+ ds = &sc->sc_rxlsoft[idx];
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (ENOBUFS);
+
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+
+ if (ds->ds_mbuf != NULL)
+ bus_dmamap_unload(sc->sc_bufs_dmat, ds->ds_dmamap);
+
+ ds->ds_mbuf = m;
+
+ error = bus_dmamap_load(sc->sc_bufs_dmat, ds->ds_dmamap,
+ m->m_ext.ext_buf, m->m_ext.ext_size, admsw_rxbuf_map_addr,
+ ds, BUS_DMA_NOWAIT);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't load rx DMA map %d, error = %d\n", idx, error);
+ panic("admsw_add_rxbuf"); /* XXX */
+ }
+
+ bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, BUS_DMASYNC_PREREAD);
+
+ if (high)
+ ADMSW_INIT_RXHDESC(sc, idx);
+ else
+ ADMSW_INIT_RXLDESC(sc, idx);
+
+ return (0);
+}
+
+int
+admsw_mediachange(struct ifnet *ifp)
+{
+ struct admsw_softc *sc = ifp->if_softc;
+ int port = 0;
+ struct ifmedia *ifm;
+ int old, new, val;
+
+ while(port < SW_DEVS) {
+ if(ifp == sc->sc_ifnet[port])
+ break;
+ else
+ port++;
+ }
+
+ ifm = &sc->sc_ifmedia[port];
+
+ if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
+ return (EINVAL);
+
+ if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
+ val = PHY_CNTL2_AUTONEG|PHY_CNTL2_100M|PHY_CNTL2_FDX;
+ } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
+ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
+ val = PHY_CNTL2_100M|PHY_CNTL2_FDX;
+ else
+ val = PHY_CNTL2_100M;
+ } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) {
+ if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
+ val = PHY_CNTL2_FDX;
+ else
+ val = 0;
+ } else
+ return (EINVAL);
+
+ old = REG_READ(PHY_CNTL2_REG);
+ new = old & ~((PHY_CNTL2_AUTONEG|PHY_CNTL2_100M|PHY_CNTL2_FDX) << port);
+ new |= (val << port);
+
+ if (new != old)
+ REG_WRITE(PHY_CNTL2_REG, new);
+
+ return (0);
+}
+
+void
+admsw_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct admsw_softc *sc = ifp->if_softc;
+ int port = 0;
+ int status;
+
+ while(port < SW_DEVS) {
+ if(ifp == sc->sc_ifnet[port])
+ break;
+ else
+ port++;
+ }
+
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER;
+
+ status = REG_READ(PHY_ST_REG) >> port;
+
+ if ((status & PHY_ST_LINKUP) == 0) {
+ ifmr->ifm_active |= IFM_NONE;
+ return;
+ }
+
+ ifmr->ifm_status |= IFM_ACTIVE;
+ ifmr->ifm_active |= (status & PHY_ST_100M) ? IFM_100_TX : IFM_10_T;
+ if (status & PHY_ST_FDX)
+ ifmr->ifm_active |= IFM_FDX;
+}
+
+static device_method_t admsw_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, admsw_probe),
+ DEVMETHOD(device_attach, admsw_attach),
+ DEVMETHOD(device_detach, admsw_detach),
+ DEVMETHOD(device_shutdown, admsw_shutdown),
+
+ { 0, 0 }
+};
+
+static devclass_t admsw_devclass;
+
+static driver_t admsw_driver = {
+ "admsw",
+ admsw_methods,
+ sizeof(struct admsw_softc),
+};
+
+DRIVER_MODULE(admsw, obio, admsw_driver, admsw_devclass, 0, 0);
+MODULE_DEPEND(admsw, ether, 1, 1, 1);
diff --git a/sys/mips/mips32/adm5120/if_admswreg.h b/sys/mips/mips32/adm5120/if_admswreg.h
new file mode 100644
index 0000000..a4cfa33
--- /dev/null
+++ b/sys/mips/mips32/adm5120/if_admswreg.h
@@ -0,0 +1,678 @@
+/* $NetBSD: if_admswreg.h,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS
+ * 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 _IF_ADMSWREG_H_
+#define _IF_ADMSWREG_H_
+
+#define ADMSW_BOOT_DONE 0x0008
+#define ADMSW_BOOT_DONE_BO __BIT(0)
+#define ADMSW_SW_RES 0x000c
+#define ADMSW_SW_RES_SWR __BITS(31, 0)
+#define ADMSW_INT_ST 0x00b0
+#define ADMSW_INT_MASK 0x00b4
+
+#define ADMSW_INTR_RSVD __BITS(31, 25)
+#define ADMSW_INTR_CPUH __BIT(24)
+#define ADMSW_INTR_SDE __BIT(23)
+#define ADMSW_INTR_RDE __BIT(22)
+#define ADMSW_INTR_W1TE __BIT(21)
+#define ADMSW_INTR_W0TE __BIT(20)
+#define ADMSW_INTR_MI __BIT(19)
+#define ADMSW_INTR_PSC __BIT(18)
+#define ADMSW_INTR_BCS __BIT(16)
+#define ADMSW_INTR_MD __BIT(15)
+#define ADMSW_INTR_GQF __BIT(14)
+#define ADMSW_INTR_CPQ __BIT(13)
+#define ADMSW_INTR_P5QF __BIT(11)
+#define ADMSW_INTR_P4QF __BIT(10)
+#define ADMSW_INTR_P3QF __BIT(9)
+#define ADMSW_INTR_P2QF __BIT(8)
+#define ADMSW_INTR_P1QF __BIT(7)
+#define ADMSW_INTR_P0QF __BIT(6)
+#define ADMSW_INTR_LDF __BIT(5)
+#define ADMSW_INTR_HDF __BIT(4)
+#define ADMSW_INTR_RLD __BIT(3)
+#define ADMSW_INTR_RHD __BIT(2)
+#define ADMSW_INTR_SLD __BIT(1)
+#define ADMSW_INTR_SHD __BIT(0)
+
+#define ADMSW_INT_FMT \
+ "\x10"\
+ "\x01SHD"\
+ "\x02SLD"\
+ "\x03RHD"\
+ "\x04RLD"\
+ "\x05HDF"\
+ "\x06LDF"\
+ "\x07P0QF"\
+ "\x08P1QF"\
+ "\x09P2QF"\
+ "\x0aP3QF"\
+ "\x0bP4QF"\
+ "\x0cP5QF"\
+ "\x0e"\
+ "CPQ"\
+ "\x0fGQF"\
+ "\x10MD"\
+ "\x11"\
+ "BCS"\
+ "\x13PSC"\
+ "\x14MI"\
+ "\x15W0TE"\
+ "\x16W1TE"\
+ "\x17RDE"\
+ "\x18SDE"\
+ "\x19"\
+ "CPUH"
+
+#define CODE_REG 0x0000
+#define SFTREST_REG 0x0004
+#define BOOT_DONE_REG 0x0008
+#define GLOBAL_ST_REG 0x0010
+#define PHY_ST_REG 0x0014
+#define PHY_ST_LINKUP (1 << 0)
+#define PHY_ST_100M (1 << 8)
+#define PHY_ST_FDX (1 << 16)
+#define PORT_ST_REG 0x0018
+#define MEM_CONTROL_REG 0x001C
+#define SW_CONF_REG 0x0020
+
+#define CPUP_CONF_REG 0x0024
+#define CPUP_CONF_DCPUP 0x00000001
+#define CPUP_CONF_CRCP 0x00000002
+#define CPUP_CONF_BTM 0x00000004
+#define CPUP_CONF_DUNP_SHIFT 9
+#define CPUP_CONF_DUNP_MASK (0x3F << CPUP_CONF_DUNP_SHIFT)
+#define CPUP_CONF_DMCP_SHIFT 16
+#define CPUP_CONF_DMCP_MASK (0x3F << CPUP_CONF_DMCP_SHIFT)
+#define CPUP_CONF_DBCP_SHIFT 24
+#define CPUP_CONF_DBCP_MASK (0x3F << CPUP_CONF_DBCP_SHIFT)
+
+#define PORT_CONF0_REG 0x0028
+#define PORT_CONF0_DP_MASK 0x0000003F
+#define PORT_CONF0_EMCP_MASK 0x00003F00
+#define PORT_CONF0_EMCP_SHIFT 8
+#define PORT_CONF0_EMBP_MASK 0x003F0000
+#define PORT_CONF0_EMBP_SHIFT 16
+#define PORT_CONF1_REG 0x002C
+#define PORT_CONF2_REG 0x0030
+
+#define VLAN_G1_REG 0x0040
+#define VLAN_G2_REG 0x0044
+#define SEND_TRIG_REG 0x0048
+#define SRCH_CMD_REG 0x004C
+#define ADDR_ST0_REG 0x0050
+#define ADDR_ST1_REG 0x0054
+#define MAC_WT0_REG 0x0058
+#define MAC_WT0_WRITE 0x00000001
+#define MAC_WT0_WRITE_DONE 0x00000002
+#define MAC_WT0_FILTER_EN 0x00000004
+#define MAC_WT0_VLANID_SHIFT 3
+#define MAC_WT0_VLANID_MASK 0x00000038
+#define MAC_WT0_VLANID_EN 0x00000040
+#define MAC_WT0_PORTMAP_MASK 0x00001F80
+#define MAC_WT0_PORTMAP_SHIFT 7
+#define MAC_WT0_AGE_MASK (0x7 << 13)
+#define MAC_WT0_AGE_STATIC (0x7 << 13)
+#define MAC_WT0_AGE_VALID (0x1 << 13)
+#define MAC_WT0_AGE_EMPTY 0
+#define MAC_WT1_REG 0x005C
+#define BW_CNTL0_REG 0x0060
+#define BW_CNTL1_REG 0x0064
+#define PHY_CNTL0_REG 0x0068
+#define PHY_CNTL1_REG 0x006C
+#define FC_TH_REG 0x0070
+#define FC_TH_FCS_MASK 0x01FF0000
+#define FC_TH_D2R_MASK 0x0000FF00
+#define FC_TH_D2S_MASK 0x000000FF
+#define ADJ_PORT_TH_REG 0x0074
+#define PORT_TH_REG 0x0078
+#define PHY_CNTL2_REG 0x007C
+#define PHY_CNTL2_AUTONEG (1 << 0)
+#define PHY_CNTL2_ANE_MASK 0x0000001F
+#define PHY_CNTL2_SC_MASK 0x000003E0
+#define PHY_CNTL2_SC_SHIFT 5
+#define PHY_CNTL2_100M (1 << PHY_CNTL2_SC_SHIFT)
+#define PHY_CNTL2_DC_MASK 0x00007C00
+#define PHY_CNTL2_DC_SHIFT 10
+#define PHY_CNTL2_FDX (1 << PHY_CNTL2_DC_SHIFT)
+#define PHY_CNTL2_RFCV_MASK 0x000F8000
+#define PHY_CNTL2_RFCV_SHIFT 15
+#define PHY_CNTL2_PHYR_MASK 0x01F00000
+#define PHY_CNTL2_PHYR_SHIFT 20
+#define PHY_CNTL2_AMDIX_MASK 0x3E000000
+#define PHY_CNTL2_AMDIX_SHIFT 25
+#define PHY_CNTL2_RMAE 0x40000000
+#define PHY_CNTL3_REG 0x0080
+#define PHY_CNTL3_RNT 0x00000400
+
+#define PRI_CNTL_REG 0x0084
+#define VLAN_PRI_REG 0x0088
+#define TOS_EN_REG 0x008C
+#define TOS_MAP0_REG 0x0090
+#define TOS_MAP1_REG 0x0094
+#define CUSTOM_PRI1_REG 0x0098
+#define CUSTOM_PRI2_REG 0x009C
+
+#define EMPTY_CNT_REG 0x00A4
+#define PORT_CNT_SEL_REG 0x00A8
+#define PORT_CNT_REG 0x00AC
+
+#define INT_MASK 0x1FDEFFF
+
+#define GPIO_CONF0_REG 0x00B8
+#define GPIO_CONF2_REG 0x00BC
+
+#define SWAP_IN_REG 0x00C8
+#define SWAP_OUT_REG 0x00CC
+
+#define SEND_HBADDR_REG 0x00D0
+#define SEND_LBADDR_REG 0x00D4
+#define RECV_HBADDR_REG 0x00D8
+#define RECV_LBADDR_REG 0x00DC
+#define SEND_HWADDR_REG 0x00E0
+#define SEND_LWADDR_REG 0x00E4
+#define RECV_HWADDR_REG 0x00E8
+#define RECV_LWADDR_REG 0x00EC
+
+#define TIMER_INT_REG 0x00F0
+#define TIMER_REG 0x00F4
+
+#define PORT0_LED_REG 0x0100
+#define PORT1_LED_REG 0x0104
+#define PORT2_LED_REG 0x0108
+#define PORT3_LED_REG 0x010c
+#define PORT4_LED_REG 0x0110
+
+/* Hardware descriptor format */
+struct admsw_desc {
+ volatile uint32_t data;
+ volatile uint32_t cntl;
+ volatile uint32_t len;
+ volatile uint32_t status;
+} __attribute__((__packed__, __aligned__(4)));
+
+#define ADM5120_DMA_MASK 0x01ffffff
+#define ADM5120_DMA_OWN 0x80000000 /* buffer owner */
+#define ADM5120_DMA_RINGEND 0x10000000 /* Last in DMA ring */
+#define ADM5120_DMA_BUF2ENABLE 0x80000000
+
+#define ADM5120_DMA_PORTID 0x00007000
+#define ADM5120_DMA_PORTSHIFT 12
+#define ADM5120_DMA_LEN 0x07ff0000
+#define ADM5120_DMA_LENSHIFT 16
+#define ADM5120_DMA_TYPE 0x00000003
+#define ADM5120_DMA_TYPE_IP 0x00000000
+#define ADM5120_DMA_TYPE_PPPOE 0x00000001
+#define ADM5120_DMA_CSUM 0x80000000
+#define ADM5120_DMA_CSUMFAIL 0x00000008
+
+#define SW_DEVS 6
+
+#if 0
+/* CODE_REG */
+#define CODE_ID_MASK 0x00FFFF
+#define CODE_ADM5120_ID 0x5120
+
+#define CODE_REV_MASK 0x0F0000
+#define CODE_REV_SHIFT 16
+#define CODE_REV_ADM5120_0 0x8
+
+#define CODE_CLK_MASK 0x300000
+#define CODE_CLK_SHIFT 20
+
+#define CPU_CLK_175MHZ 0x0
+#define CPU_CLK_200MHZ 0x1
+#define CPU_CLK_225MHZ 0x2
+#define CPU_CLK_250MHZ 0x3
+
+#define CPU_SPEED_175M (175000000/2)
+#define CPU_SPEED_200M (200000000/2)
+#define CPU_SPEED_225M (225000000/2)
+#define CPU_SPEED_250M (250000000/2)
+
+#define CPU_NAND_BOOT 0x01000000
+#define CPU_DCACHE_2K_WAY (0x1 << 25)
+#define CPU_DCACHE_2WAY (0x1 << 26)
+#define CPU_ICACHE_2K_WAY (0x1 << 27)
+#define CPU_ICACHE_2WAY (0x1 << 28)
+
+#define CPU_GMII_SUPPORT 0x20000000
+
+#define CPU_PQFP_MODE (0x1 << 29)
+
+#define CPU_CACHE_LINE_SIZE 16
+
+/* SftRest_REG */
+#define SOFTWARE_RESET 0x1
+
+/* Boot_done_REG */
+#define BOOT_DONE 0x1
+
+/* SWReset_REG */
+#define SWITCH_RESET 0x1
+
+/* Global_St_REG */
+#define DATA_BUF_BIST_FAILED (0x1 << 0)
+#define LINK_TAB_BIST_FAILED (0x1 << 1)
+#define MC_TAB_BIST_FAILED (0x1 << 2)
+#define ADDR_TAB_BIST_FAILED (0x1 << 3)
+#define DCACHE_D_FAILED (0x3 << 4)
+#define DCACHE_T_FAILED (0x1 << 6)
+#define ICACHE_D_FAILED (0x3 << 7)
+#define ICACHE_T_FAILED (0x1 << 9)
+#define BIST_FAILED_MASK 0x03FF
+
+#define ALLMEM_TEST_DONE (0x1 << 10)
+
+#define SKIP_BLK_CNT_MASK 0x1FF000
+#define SKIP_BLK_CNT_SHIFT 12
+
+
+/* PHY_st_REG */
+#define PORT_LINK_MASK 0x0000001F
+#define PORT_MII_LINKFAIL 0x00000020
+#define PORT_SPEED_MASK 0x00001F00
+
+#define PORT_GMII_SPD_MASK 0x00006000
+#define PORT_GMII_SPD_10M 0
+#define PORT_GMII_SPD_100M 0x00002000
+#define PORT_GMII_SPD_1000M 0x00004000
+
+#define PORT_DUPLEX_MASK 0x003F0000
+#define PORT_FLOWCTRL_MASK 0x1F000000
+
+#define PORT_GMII_FLOWCTRL_MASK 0x60000000
+#define PORT_GMII_FC_ON 0x20000000
+#define PORT_GMII_RXFC_ON 0x20000000
+#define PORT_GMII_TXFC_ON 0x40000000
+
+/* Port_st_REG */
+#define PORT_SECURE_ST_MASK 0x001F
+#define MII_PORT_TXC_ERR 0x0080
+
+/* Mem_control_REG */
+#define SDRAM_SIZE_4MBYTES 0x0001
+#define SDRAM_SIZE_8MBYTES 0x0002
+#define SDRAM_SIZE_16MBYTES 0x0003
+#define SDRAM_SIZE_64MBYTES 0x0004
+#define SDRAM_SIZE_128MBYTES 0x0005
+#define SDRAM_SIZE_MASK 0x0007
+
+#define MEMCNTL_SDRAM1_EN (0x1 << 5)
+
+#define ROM_SIZE_DISABLE 0x0000
+#define ROM_SIZE_512KBYTES 0x0001
+#define ROM_SIZE_1MBYTES 0x0002
+#define ROM_SIZE_2MBYTES 0x0003
+#define ROM_SIZE_4MBYTES 0x0004
+#define ROM_SIZE_8MBYTES 0x0005
+#define ROM_SIZE_MASK 0x0007
+
+#define ROM0_SIZE_SHIFT 8
+#define ROM1_SIZE_SHIFT 16
+
+
+/* SW_conf_REG */
+#define SW_AGE_TIMER_MASK 0x000000F0
+#define SW_AGE_TIMER_DISABLE 0x0
+#define SW_AGE_TIMER_FAST 0x00000080
+#define SW_AGE_TIMER_300SEC 0x00000010
+#define SW_AGE_TIMER_600SEC 0x00000020
+#define SW_AGE_TIMER_1200SEC 0x00000030
+#define SW_AGE_TIMER_2400SEC 0x00000040
+#define SW_AGE_TIMER_4800SEC 0x00000050
+#define SW_AGE_TIMER_9600SEC 0x00000060
+#define SW_AGE_TIMER_19200SEC 0x00000070
+//#define SW_AGE_TIMER_38400SEC 0x00000070
+
+#define SW_BC_PREV_MASK 0x00000300
+#define SW_BC_PREV_DISABLE 0
+#define SW_BC_PREV_64BC 0x00000100
+#define SW_BC_PREV_48BC 0x00000200
+#define SW_BC_PREV_32BC 0x00000300
+
+#define SW_MAX_LEN_MASK 0x00000C00
+#define SW_MAX_LEN_1536 0
+#define SW_MAX_LEN_1522 0x00000800
+#define SW_MAX_LEN_1518 0x00000400
+
+#define SW_DIS_COLABT 0x00001000
+
+#define SW_HASH_ALG_MASK 0x00006000
+#define SW_HASH_ALG_DIRECT 0
+#define SW_HASH_ALG_XOR48 0x00002000
+#define SW_HASH_ALG_XOR32 0x00004000
+
+#define SW_DISABLE_BACKOFF_TIMER 0x00008000
+
+#define SW_BP_NUM_MASK 0x000F0000
+#define SW_BP_NUM_SHIFT 16
+#define SW_BP_MODE_MASK 0x00300000
+#define SW_BP_MODE_DISABLE 0
+#define SW_BP_MODE_JAM 0x00100000
+#define SW_BP_MODE_JAMALL 0x00200000
+#define SW_BP_MODE_CARRIER 0x00300000
+#define SW_RESRV_MC_FILTER 0x00400000
+#define SW_BISR_DISABLE 0x00800000
+
+#define SW_DIS_MII_WAS_TX 0x01000000
+#define SW_BISS_EN 0x02000000
+#define SW_BISS_TH_MASK 0x0C000000
+#define SW_BISS_TH_SHIFT 26
+#define SW_REQ_LATENCY_MASK 0xF0000000
+#define SW_REQ_LATENCY_SHIFT 28
+
+
+/* CPUp_conf_REG */
+#define SW_CPU_PORT_DISABLE 0x00000001
+#define SW_PADING_CRC 0x00000002
+#define SW_BRIDGE_MODE 0x00000004
+
+#define SW_DIS_UN_SHIFT 9
+#define SW_DIS_UN_MASK (0x3F << SW_DIS_UN_SHIFT)
+#define SW_DIS_MC_SHIFT 16
+#define SW_DIS_MC_MASK (0x3F << SW_DIS_MC_SHIFT)
+#define SW_DIS_BC_SHIFT 24
+#define SW_DIS_BC_MASK (0x3F << SW_DIS_BC_SHIFT)
+
+
+/* Port_conf0_REG */
+#define SW_DISABLE_PORT_MASK 0x0000003F
+#define SW_EN_MC_MASK 0x00003F00
+#define SW_EN_MC_SHIFT 8
+#define SW_EN_BP_MASK 0x003F0000
+#define SW_EN_BP_SHIFT 16
+#define SW_EN_FC_MASK 0x3F000000
+#define SW_EN_FC_SHIFT 24
+
+
+/* Port_conf1_REG */
+#define SW_DIS_SA_LEARN_MASK 0x0000003F
+#define SW_PORT_BLOCKING_MASK 0x00000FC0
+#define SW_PORT_BLOCKING_SHIFT 6
+#define SW_PORT_BLOCKING_ON 0x1
+
+#define SW_PORT_BLOCKING_MODE_MASK 0x0003F000
+#define SW_PORT_BLOCKING_MODE_SHIFT 12
+#define SW_PORT_BLOCKING_CTRLONLY 0x1
+
+#define SW_EN_PORT_AGE_MASK 0x03F00000
+#define SW_EN_PORT_AGE_SHIFT 20
+#define SW_EN_SA_SECURED_MASK 0xFC000000
+#define SW_EN_SA_SECURED_SHIFT 26
+
+
+/* Port_conf2_REG */
+#define SW_GMII_AN_EN 0x00000001
+#define SW_GMII_FORCE_SPD_MASK 0x00000006
+#define SW_GMII_FORCE_SPD_10M 0
+#define SW_GMII_FORCE_SPD_100M 0x2
+#define SW_GMII_FORCE_SPD_1000M 0x4
+
+#define SW_GMII_FORCE_FULL_DUPLEX 0x00000008
+
+#define SW_GMII_FORCE_RXFC 0x00000010
+#define SW_GMII_FORCE_TXFC 0x00000020
+
+#define SW_GMII_EN 0x00000040
+#define SW_GMII_REVERSE 0x00000080
+
+#define SW_GMII_TXC_CHECK_EN 0x00000100
+
+#define SW_LED_FLASH_TIME_MASK 0x00030000
+#define SW_LED_FLASH_TIME_30MS 0
+#define SW_LED_FLASH_TIME_60MS 0x00010000
+#define SW_LED_FLASH_TIME_240MS 0x00020000
+#define SW_LED_FLASH_TIME_480MS 0x00030000
+
+
+/* Send_trig_REG */
+#define SEND_TRIG_LOW 0x0001
+#define SEND_TRIG_HIGH 0x0002
+
+
+/* Srch_cmd_REG */
+#define SW_MAC_SEARCH_START 0x000001
+#define SW_MAX_SEARCH_AGAIN 0x000002
+
+
+/* MAC_wt0_REG */
+#define SW_MAC_WRITE 0x00000001
+#define SW_MAC_WRITE_DONE 0x00000002
+#define SW_MAC_FILTER_EN 0x00000004
+#define SW_MAC_VLANID_SHIFT 3
+#define SW_MAC_VLANID_MASK 0x00000038
+#define SW_MAC_VLANID_EN 0x00000040
+#define SW_MAC_PORTMAP_MASK 0x00001F80
+#define SW_MAC_PORTMAP_SHIFT 7
+#define SW_MAC_AGE_MASK (0x7 << 13)
+#define SW_MAC_AGE_STATIC (0x7 << 13)
+#define SW_MAC_AGE_VALID (0x1 << 13)
+#define SW_MAC_AGE_EMPTY 0
+
+/* BW_cntl0_REG */
+#define SW_PORT_TX_NOLIMIT 0
+#define SW_PORT_TX_64K 1
+#define SW_PORT_TX_128K 2
+#define SW_PORT_TX_256K 3
+#define SW_PORT_TX_512K 4
+#define SW_PORT_TX_1M 5
+#define SW_PORT_TX_4M 6
+#define SW_PORT_TX_10MK 7
+
+/* BW_cntl1_REG */
+#define SW_TRAFFIC_SHAPE_IPG (0x1 << 31)
+
+/* PHY_cntl0_REG */
+#define SW_PHY_ADDR_MASK 0x0000001F
+#define PHY_ADDR_MAX 0x1f
+#define SW_PHY_REG_ADDR_MASK 0x00001F00
+#define SW_PHY_REG_ADDR_SHIFT 8
+#define PHY_REG_ADDR_MAX 0x1f
+#define SW_PHY_WRITE 0x00002000
+#define SW_PHY_READ 0x00004000
+#define SW_PHY_WDATA_MASK 0xFFFF0000
+#define SW_PHY_WDATA_SHIFT 16
+
+
+/* PHY_cntl1_REG */
+#define SW_PHY_WRITE_DONE 0x00000001
+#define SW_PHY_READ_DONE 0x00000002
+#define SW_PHY_RDATA_MASK 0xFFFF0000
+#define SW_PHY_RDATA_SHIFT 16
+
+/* FC_th_REG */
+/* Adj_port_th_REG */
+/* Port_th_REG */
+
+/* PHY_cntl2_REG */
+#define SW_PHY_AN_MASK 0x0000001F
+#define SW_PHY_SPD_MASK 0x000003E0
+#define SW_PHY_SPD_SHIFT 5
+#define SW_PHY_DPX_MASK 0x00007C00
+#define SW_PHY_DPX_SHIFT 10
+#define SW_FORCE_FC_MASK 0x000F8000
+#define SW_FORCE_FC_SHIFT 15
+#define SW_PHY_NORMAL_MASK 0x01F00000
+#define SW_PHY_NORMAL_SHIFT 20
+#define SW_PHY_AUTOMDIX_MASK 0x3E000000
+#define SW_PHY_AUTOMDIX_SHIFT 25
+#define SW_PHY_REC_MCCAVERAGE 0x40000000
+
+
+/* PHY_cntl3_REG */
+/* Pri_cntl_REG */
+/* VLAN_pri_REG */
+/* TOS_en_REG */
+/* TOS_map0_REG */
+/* TOS_map1_REG */
+/* Custom_pri1_REG */
+/* Custom_pri2_REG */
+/* Empty_cnt_REG */
+/* Port_cnt_sel_REG */
+/* Port_cnt_REG */
+
+
+/* SW_Int_st_REG & SW_Int_mask_REG */
+#define SEND_H_DONE_INT 0x0000001
+#define SEND_L_DONE_INT 0x0000002
+#define RX_H_DONE_INT 0x0000004
+#define RX_L_DONE_INT 0x0000008
+#define RX_H_DESC_FULL_INT 0x0000010
+#define RX_L_DESC_FULL_INT 0x0000020
+#define PORT0_QUE_FULL_INT 0x0000040
+#define PORT1_QUE_FULL_INT 0x0000080
+#define PORT2_QUE_FULL_INT 0x0000100
+#define PORT3_QUE_FULL_INT 0x0000200
+#define PORT4_QUE_FULL_INT 0x0000400
+#define PORT5_QUE_FULL_INT 0x0000800
+
+#define CPU_QUE_FULL_INT 0x0002000
+#define GLOBAL_QUE_FULL_INT 0x0004000
+#define MUST_DROP_INT 0x0008000
+#define BC_STORM_INT 0x0010000
+
+#define PORT_STATUS_CHANGE_INT 0x0040000
+#define INTRUDER_INT 0x0080000
+#define WATCHDOG0_EXPR_INT 0x0100000
+#define WATCHDOG1_EXPR_INT 0x0200000
+#define RX_DESC_ERR_INT 0x0400000
+#define SEND_DESC_ERR_INT 0x0800000
+#define CPU_HOLD_INT 0x1000000
+#define SWITCH_INT_MASK 0x1FDEFFF
+
+
+/* GPIO_conf0_REG */
+#define GPIO0_INPUT_MODE 0x00000001
+#define GPIO1_INPUT_MODE 0x00000002
+#define GPIO2_INPUT_MODE 0x00000004
+#define GPIO3_INPUT_MODE 0x00000008
+#define GPIO4_INPUT_MODE 0x00000010
+#define GPIO5_INPUT_MODE 0x00000020
+#define GPIO6_INPUT_MODE 0x00000040
+#define GPIO7_INPUT_MODE 0x00000080
+
+#define GPIO0_OUTPUT_MODE 0
+#define GPIO1_OUTPUT_MODE 0
+#define GPIO2_OUTPUT_MODE 0
+#define GPIO3_OUTPUT_MODE 0
+#define GPIO4_OUTPUT_MODE 0
+#define GPIO5_OUTPUT_MODE 0
+#define GPIO6_OUTPUT_MODE 0
+#define GPIO7_OUTPUT_MODE 0
+
+#define GPIO0_INPUT_MASK 0x00000100
+#define GPIO1_INPUT_MASK 0x00000200
+#define GPIO2_INPUT_MASK 0x00000400
+#define GPIO3_INPUT_MASK 0x00000800
+#define GPIO4_INPUT_MASK 0x00001000
+#define GPIO5_INPUT_MASK 0x00002000
+#define GPIO6_INPUT_MASK 0x00004000
+#define GPIO7_INPUT_MASK 0x00008000
+
+#define GPIO0_OUTPUT_EN 0x00010000
+#define GPIO1_OUTPUT_EN 0x00020000
+#define GPIO2_OUTPUT_EN 0x00040000
+#define GPIO3_OUTPUT_EN 0x00080000
+#define GPIO4_OUTPUT_EN 0x00100000
+#define GPIO5_OUTPUT_EN 0x00200000
+#define GPIO6_OUTPUT_EN 0x00400000
+#define GPIO7_OUTPUT_EN 0x00800000
+
+#define GPIO_CONF0_OUTEN_MASK 0x00ff0000
+
+#define GPIO0_OUTPUT_HI 0x01000000
+#define GPIO1_OUTPUT_HI 0x02000000
+#define GPIO2_OUTPUT_HI 0x04000000
+#define GPIO3_OUTPUT_HI 0x08000000
+#define GPIO4_OUTPUT_HI 0x10000000
+#define GPIO5_OUTPUT_HI 0x20000000
+#define GPIO6_OUTPUT_HI 0x40000000
+#define GPIO7_OUTPUT_HI 0x80000000
+
+#define GPIO0_OUTPUT_LOW 0
+#define GPIO1_OUTPUT_LOW 0
+#define GPIO2_OUTPUT_LOW 0
+#define GPIO3_OUTPUT_LOW 0
+#define GPIO4_OUTPUT_LOW 0
+#define GPIO5_OUTPUT_LOW 0
+#define GPIO6_OUTPUT_LOW 0
+#define GPIO7_OUTPUT_LOW 0
+
+
+/* GPIO_conf2_REG */
+#define EXTIO_WAIT_EN (0x1 << 6)
+#define EXTIO_CS1_INT1_EN (0x1 << 5)
+#define EXTIO_CS0_INT0_EN (0x1 << 4)
+
+/* Timer_int_REG */
+#define SW_TIMER_INT_DISABLE 0x10000
+#define SW_TIMER_INT 0x1
+
+/* Timer_REG */
+#define SW_TIMER_EN 0x10000
+#define SW_TIMER_MASK 0xffff
+#define SW_TIMER_10MS_TICKS 0x3D09
+#define SW_TIMER_1MS_TICKS 0x61A
+#define SW_TIMER_100US_TICKS 0x9D
+
+
+/* Port0_LED_REG, Port1_LED_REG, Port2_LED_REG, Port3_LED_REG, Port4_LED_REG*/
+#define GPIOL_INPUT_MODE 0x00
+#define GPIOL_OUTPUT_FLASH 0x01
+#define GPIOL_OUTPUT_LOW 0x02
+#define GPIOL_OUTPUT_HIGH 0x03
+#define GPIOL_LINK_LED 0x04
+#define GPIOL_SPEED_LED 0x05
+#define GPIOL_DUPLEX_LED 0x06
+#define GPIOL_ACT_LED 0x07
+#define GPIOL_COL_LED 0x08
+#define GPIOL_LINK_ACT_LED 0x09
+#define GPIOL_DUPLEX_COL_LED 0x0A
+#define GPIOL_10MLINK_ACT_LED 0x0B
+#define GPIOL_100MLINK_ACT_LED 0x0C
+#define GPIOL_CTRL_MASK 0x0F
+
+#define GPIOL_INPUT_MASK 0x7000
+#define GPIOL_INPUT_0_MASK 0x1000
+#define GPIOL_INPUT_1_MASK 0x2000
+#define GPIOL_INPUT_2_MASK 0x4000
+
+#define PORT_LED0_SHIFT 0
+#define PORT_LED1_SHIFT 4
+#define PORT_LED2_SHIFT 8
+#endif
+
+#endif /* _IF_ADMSWREG_H_ */
diff --git a/sys/mips/mips32/adm5120/if_admswvar.h b/sys/mips/mips32/adm5120/if_admswvar.h
new file mode 100644
index 0000000..ea25288
--- /dev/null
+++ b/sys/mips/mips32/adm5120/if_admswvar.h
@@ -0,0 +1,212 @@
+/* $NetBSD: if_admswvar.h,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS
+ * 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.
+ */
+#ifndef _IF_ADMSWVAR_H_
+#define _IF_ADMSWVAR_H_
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <machine/bus.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <mips/mips32/adm5120/adm5120reg.h>
+#include <mips/mips32/adm5120/if_admswreg.h>
+
+#define MAC_BUFLEN 0x07ff
+
+#define ADMSW_NTXHDESC 4
+#define ADMSW_NRXHDESC 32
+#define ADMSW_NTXLDESC 32
+#define ADMSW_NRXLDESC 32
+
+#define ADMSW_NTXHDESC_MASK (ADMSW_NTXHDESC - 1)
+#define ADMSW_NRXHDESC_MASK (ADMSW_NRXHDESC - 1)
+#define ADMSW_NTXLDESC_MASK (ADMSW_NTXLDESC - 1)
+#define ADMSW_NRXLDESC_MASK (ADMSW_NRXLDESC - 1)
+
+#define ADMSW_NEXTTXH(x) (((x) + 1) & ADMSW_NTXHDESC_MASK)
+#define ADMSW_NEXTRXH(x) (((x) + 1) & ADMSW_NRXHDESC_MASK)
+#define ADMSW_NEXTTXL(x) (((x) + 1) & ADMSW_NTXLDESC_MASK)
+#define ADMSW_NEXTRXL(x) (((x) + 1) & ADMSW_NRXLDESC_MASK)
+
+#define ADMSW_IRQ 9
+
+struct admsw_control_data {
+ /* The transmit descriptors. */
+ struct admsw_desc acd_txhdescs[ADMSW_NTXHDESC];
+
+ /* The receive descriptors. */
+ struct admsw_desc acd_rxhdescs[ADMSW_NRXHDESC];
+
+ /* The transmit descriptors. */
+ struct admsw_desc acd_txldescs[ADMSW_NTXLDESC];
+
+ /* The receive descriptors. */
+ struct admsw_desc acd_rxldescs[ADMSW_NRXLDESC];
+};
+
+#define ADMSW_CDOFF(x) offsetof(struct admsw_control_data, x)
+#define ADMSW_CDTXHOFF(x) ADMSW_CDOFF(acd_txhdescs[(x)])
+#define ADMSW_CDTXLOFF(x) ADMSW_CDOFF(acd_txldescs[(x)])
+#define ADMSW_CDRXHOFF(x) ADMSW_CDOFF(acd_rxhdescs[(x)])
+#define ADMSW_CDRXLOFF(x) ADMSW_CDOFF(acd_rxldescs[(x)])
+
+struct admsw_descsoft {
+ struct mbuf *ds_mbuf;
+ bus_dmamap_t ds_dmamap;
+ /* Up to 2 segments */
+ uint32_t ds_addr[2];
+ uint32_t ds_len[2];
+ uint32_t ds_nsegs;
+};
+
+/*
+ * Software state per device.
+ */
+struct admsw_softc {
+ device_t sc_dev; /* generic device information */
+ uint8_t sc_enaddr[ETHER_ADDR_LEN];
+ bus_dma_tag_t sc_control_dmat;
+ /* bus DMA tag for control structs*/
+ bus_dma_tag_t sc_bufs_dmat; /* bus DMA tag for buffers */
+ struct ifmedia sc_ifmedia[SW_DEVS];
+ int ndevs; /* number of IFF_RUNNING interfaces */
+ struct ifnet *sc_ifnet[SW_DEVS];
+ /* Ethernet common data */
+ void *sc_ih; /* interrupt cookie */
+ struct resource *irq_res;
+ struct resource *mem_res;
+ bus_dmamap_t sc_cddmamap; /* control data DMA map */
+ uint32_t sc_cddma;
+ struct admsw_control_data *sc_control_data;
+
+ struct admsw_descsoft sc_txhsoft[ADMSW_NTXHDESC];
+ struct admsw_descsoft sc_rxhsoft[ADMSW_NRXHDESC];
+ struct admsw_descsoft sc_txlsoft[ADMSW_NTXLDESC];
+ struct admsw_descsoft sc_rxlsoft[ADMSW_NRXLDESC];
+#define sc_txhdescs sc_control_data->acd_txhdescs
+#define sc_rxhdescs sc_control_data->acd_rxhdescs
+#define sc_txldescs sc_control_data->acd_txldescs
+#define sc_rxldescs sc_control_data->acd_rxldescs
+
+ int sc_txfree; /* number of free Tx descriptors */
+ int sc_txnext; /* next Tx descriptor to use */
+ int sc_txdirty; /* first dirty Tx descriptor */
+ int sc_rxptr; /* next ready Rx descriptor */
+};
+
+#define ADMSW_CDTXHADDR(sc, x) ((sc)->sc_cddma + ADMSW_CDTXHOFF((x)))
+#define ADMSW_CDTXLADDR(sc, x) ((sc)->sc_cddma + ADMSW_CDTXLOFF((x)))
+#define ADMSW_CDRXHADDR(sc, x) ((sc)->sc_cddma + ADMSW_CDRXHOFF((x)))
+#define ADMSW_CDRXLADDR(sc, x) ((sc)->sc_cddma + ADMSW_CDRXLOFF((x)))
+
+#define ADMSW_CDTXHSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_control_dmat, (sc)->sc_cddmamap, (ops))
+
+#define ADMSW_CDTXLSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_control_dmat, (sc)->sc_cddmamap, (ops))
+
+#define ADMSW_CDRXHSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_control_dmat, (sc)->sc_cddmamap, (ops))
+
+#define ADMSW_CDRXLSYNC(sc, x, ops) \
+ bus_dmamap_sync((sc)->sc_control_dmat, (sc)->sc_cddmamap, (ops))
+
+#define ADMSW_INIT_RXHDESC(sc, x) \
+do { \
+ struct admsw_descsoft *__ds = &(sc)->sc_rxhsoft[(x)]; \
+ struct admsw_desc *__desc = &(sc)->sc_rxhdescs[(x)]; \
+ struct mbuf *__m = __ds->ds_mbuf; \
+ \
+ __m->m_data = __m->m_ext.ext_buf + 2; \
+ __desc->data = __ds->ds_addr[0] + 2; \
+ __desc->cntl = 0; \
+ __desc->len = min(MCLBYTES - 2, MAC_BUFLEN - 2); \
+ __desc->status = 0; \
+ if ((x) == ADMSW_NRXHDESC - 1) \
+ __desc->data |= ADM5120_DMA_RINGEND; \
+ __desc->data |= ADM5120_DMA_OWN; \
+ ADMSW_CDRXHSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
+} while (0)
+
+#define ADMSW_INIT_RXLDESC(sc, x) \
+do { \
+ struct admsw_descsoft *__ds = &(sc)->sc_rxlsoft[(x)]; \
+ struct admsw_desc *__desc = &(sc)->sc_rxldescs[(x)]; \
+ struct mbuf *__m = __ds->ds_mbuf; \
+ \
+ __m->m_data = __m->m_ext.ext_buf + 2; \
+ __desc->data = __ds->ds_addr[0] + 2; \
+ __desc->cntl = 0; \
+ __desc->len = min(MCLBYTES - 2, MAC_BUFLEN - 2); \
+ __desc->status = 0; \
+ if ((x) == ADMSW_NRXLDESC - 1) \
+ __desc->data |= ADM5120_DMA_RINGEND; \
+ __desc->data |= ADM5120_DMA_OWN; \
+ ADMSW_CDRXLSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \
+} while (0)
+
+void admwdog_attach(struct admsw_softc *);
+
+#endif /* _IF_ADMSWVAR_H_ */
diff --git a/sys/mips/mips32/adm5120/obio.c b/sys/mips/mips32/adm5120/obio.c
new file mode 100644
index 0000000..e4ca264
--- /dev/null
+++ b/sys/mips/mips32/adm5120/obio.c
@@ -0,0 +1,510 @@
+/* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */
+
+/*-
+ * Copyright (c) 2001, 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <mips/mips32/adm5120/adm5120reg.h>
+#include <mips/mips32/adm5120/obiovar.h>
+
+/* MIPS HW interrupts of IRQ/FIQ respectively */
+#define ADM5120_INTR 0
+#define ADM5120_FAST_INTR 1
+
+/* Interrupt levels */
+#define INTR_IRQ 0
+#define INTR_FIQ 1
+
+int irq_priorities[NIRQS] = {
+ INTR_IRQ, /* flash */
+ INTR_FIQ, /* uart0 */
+ INTR_FIQ, /* uart1 */
+ INTR_IRQ, /* ahci */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* admsw */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+ INTR_IRQ, /* unknown */
+};
+
+
+#define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(ADM5120_BASE_ICU + (o)))
+#define REG_WRITE(o,v) (REG_READ(o)) = (v)
+
+static int obio_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static device_t obio_add_child(device_t, int, const char *, int);
+static struct resource *
+ obio_alloc_resource(device_t, device_t, int, int *, u_long,
+ u_long, u_long, u_int);
+static int obio_attach(device_t);
+static int obio_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+static struct resource_list *
+ obio_get_resource_list(device_t, device_t);
+static void obio_hinted_child(device_t, const char *, int);
+static int obio_intr(void *);
+static int obio_probe(device_t);
+static int obio_release_resource(device_t, device_t, int, int,
+ struct resource *);
+static int obio_setup_intr(device_t, device_t, struct resource *, int,
+ driver_filter_t *, driver_intr_t *, void *, void **);
+static int obio_teardown_intr(device_t, device_t, struct resource *,
+ void *);
+
+static int
+obio_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+obio_attach(device_t dev)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ int rid;
+
+ sc->oba_mem_rman.rm_type = RMAN_ARRAY;
+ sc->oba_mem_rman.rm_descr = "OBIO memeory";
+ if (rman_init(&sc->oba_mem_rman) != 0 ||
+ rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START,
+ OBIO_MEM_START + OBIO_MEM_SIZE) != 0)
+ panic("obio_attach: failed to set up I/O rman");
+
+ sc->oba_irq_rman.rm_type = RMAN_ARRAY;
+ sc->oba_irq_rman.rm_descr = "OBIO IRQ";
+
+ if (rman_init(&sc->oba_irq_rman) != 0 ||
+ rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0)
+ panic("obio_attach: failed to set up IRQ rman");
+
+ /* Hook up our interrupt handler. */
+ if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ ADM5120_INTR, ADM5120_INTR, 1,
+ RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return (ENXIO);
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL,
+ sc, &sc->sc_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+
+ /* Hook up our FAST interrupt handler. */
+ if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ ADM5120_FAST_INTR, ADM5120_FAST_INTR, 1,
+ RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return (ENXIO);
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr,
+ NULL, sc, &sc->sc_fast_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+
+ /* disable all interrupts */
+ REG_WRITE(ICU_ENABLE_REG, ICU_INT_MASK);
+
+ bus_generic_probe(dev);
+ bus_enumerate_hinted_children(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static struct resource *
+obio_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct obio_softc *sc = device_get_softc(bus);
+ struct obio_ivar *ivar = device_get_ivars(child);
+ struct resource *rv;
+ struct resource_list_entry *rle;
+ struct rman *rm;
+ int isdefault, needactivate, passthrough;
+
+ isdefault = (start == 0UL && end == ~0UL && count == 1);
+ needactivate = flags & RF_ACTIVE;
+ passthrough = (device_get_parent(child) != bus);
+ rle = NULL;
+
+ if (passthrough)
+ return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
+ rid, start, end, count, flags));
+
+ /*
+ * If this is an allocation of the "default" range for a given RID,
+ * and we know what the resources for this device are (ie. they aren't
+ * maintained by a child bus), then work out the start/end values.
+ */
+ if (isdefault) {
+ rle = resource_list_find(&ivar->resources, type, *rid);
+ if (rle == NULL)
+ return (NULL);
+ if (rle->res != NULL) {
+ panic("%s: resource entry is busy", __func__);
+ }
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+ }
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->oba_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ rm = &sc->oba_mem_rman;
+ break;
+ default:
+ printf("%s: unknown resource type %d\n", __func__, type);
+ return (0);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == 0) {
+ printf("%s: could not reserve resource\n", __func__);
+ return (0);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ printf("%s: could not activate resource\n", __func__);
+ rman_release_resource(rv);
+ return (0);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+obio_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ /*
+ * If this is a memory resource, track the direct mapping
+ * in the uncached MIPS KSEG1 segment.
+ */
+ if (type == SYS_RES_MEMORY) {
+ void *vaddr;
+
+ vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r));
+ rman_set_virtual(r, vaddr);
+ rman_set_bustag(r, MIPS_BUS_SPACE_MEM);
+ rman_set_bushandle(r, (bus_space_handle_t)vaddr);
+ }
+
+ return (rman_activate_resource(r));
+}
+
+static int
+obio_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ return (rman_deactivate_resource(r));
+}
+
+static int
+obio_release_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+
+ rl = obio_get_resource_list(dev, child);
+ if (rl == NULL)
+ return (EINVAL);
+ rle = resource_list_find(rl, type, rid);
+ if (rle == NULL)
+ return (EINVAL);
+ rman_release_resource(r);
+ rle->res = NULL;
+
+ return (0);
+}
+
+static int
+obio_setup_intr(device_t dev, device_t child, struct resource *ires,
+ int flags, driver_filter_t *filt, driver_intr_t *handler,
+ void *arg, void **cookiep)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ struct intr_event *event;
+ int irq, error, priority;
+ uint32_t irqmask;
+
+ irq = rman_get_start(ires);
+
+ if (irq >= NIRQS)
+ panic("%s: bad irq %d", __func__, irq);
+
+ event = sc->sc_eventstab[irq];
+ if (event == NULL) {
+ error = intr_event_create(&event, (void *)irq, 0,
+ (mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq,
+ NULL, NULL, "obio intr%d:", irq);
+
+ sc->sc_eventstab[irq] = event;
+ }
+ else
+ panic("obio: Can't share IRQs");
+
+ intr_event_add_handler(event, device_get_nameunit(child), filt,
+ handler, arg, intr_priority(flags), flags, cookiep);
+
+ irqmask = 1 << irq;
+ priority = irq_priorities[irq];
+
+ if (priority == INTR_FIQ)
+ REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) | irqmask);
+ else
+ REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) & ~irqmask);
+
+ /* enable */
+ REG_WRITE(ICU_ENABLE_REG, irqmask);
+
+ return (0);
+}
+
+static int
+obio_teardown_intr(device_t dev, device_t child, struct resource *ires,
+ void *cookie)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ int irq, result;
+ uint32_t irqmask;
+
+ irq = rman_get_start(ires);
+ if (irq >= NIRQS)
+ panic("%s: bad irq %d", __func__, irq);
+
+ if (sc->sc_eventstab[irq] == NULL)
+ panic("Trying to teardown unoccupied IRQ");
+
+ irqmask = 1 << irq; /* only used as a mask from here on */
+
+ /* disable this irq in HW */
+ REG_WRITE(ICU_DISABLE_REG, irqmask);
+
+ result = intr_event_remove_handler(cookie);
+ if (!result) {
+ sc->sc_eventstab[irq] = NULL;
+ }
+
+ return (result);
+}
+
+static int
+obio_intr(void *arg)
+{
+ struct obio_softc *sc = arg;
+ struct intr_event *event;
+ struct intr_handler *ih;
+ uint32_t irqstat;
+ int irq, thread = 0;
+
+ irqstat = REG_READ(ICU_FIQ_STATUS_REG);
+ irqstat |= REG_READ(ICU_STATUS_REG);
+
+ irq = 0;
+ while (irqstat != 0) {
+ if ((irqstat & 1) == 1) {
+ event = sc->sc_eventstab[irq];
+ if (event && !TAILQ_EMPTY(&event->ie_handlers)) {
+ /* Execute fast handlers. */
+ TAILQ_FOREACH(ih, &event->ie_handlers,
+ ih_next) {
+ if (ih->ih_filter == NULL)
+ thread = 1;
+ else
+ ih->ih_filter(ih->ih_argument);
+ }
+ }
+
+ /* Schedule thread if needed. */
+ if (thread)
+ intr_event_schedule_thread(event);
+ }
+
+ irq++;
+ irqstat >>= 1;
+ }
+
+ return (FILTER_HANDLED);
+}
+
+static void
+obio_hinted_child(device_t bus, const char *dname, int dunit)
+{
+ device_t child;
+ long maddr;
+ int msize;
+ int irq;
+ int result;
+
+ child = BUS_ADD_CHILD(bus, 0, dname, dunit);
+
+ /*
+ * Set hard-wired resources for hinted child using
+ * specific RIDs.
+ */
+ resource_long_value(dname, dunit, "maddr", &maddr);
+ resource_int_value(dname, dunit, "msize", &msize);
+
+
+ result = bus_set_resource(child, SYS_RES_MEMORY, 0,
+ maddr, msize);
+ if (result != 0)
+ device_printf(bus, "warning: bus_set_resource() failed\n");
+
+ if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
+ result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ if (result != 0)
+ device_printf(bus,
+ "warning: bus_set_resource() failed\n");
+ }
+}
+
+static device_t
+obio_add_child(device_t bus, int order, const char *name, int unit)
+{
+ device_t child;
+ struct obio_ivar *ivar;
+
+ ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
+ if (ivar == NULL) {
+ printf("Failed to allocate ivar\n");
+ return (0);
+ }
+ resource_list_init(&ivar->resources);
+
+ child = device_add_child_ordered(bus, order, name, unit);
+ if (child == NULL) {
+ printf("Can't add child %s%d ordered\n", name, unit);
+ return (0);
+ }
+
+ device_set_ivars(child, ivar);
+
+ return (child);
+}
+
+/*
+ * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
+ * Provides pointer to resource_list for these routines
+ */
+static struct resource_list *
+obio_get_resource_list(device_t dev, device_t child)
+{
+ struct obio_ivar *ivar;
+
+ ivar = device_get_ivars(child);
+ return (&(ivar->resources));
+}
+
+static device_method_t obio_methods[] = {
+ DEVMETHOD(bus_activate_resource, obio_activate_resource),
+ DEVMETHOD(bus_add_child, obio_add_child),
+ DEVMETHOD(bus_alloc_resource, obio_alloc_resource),
+ DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list, obio_get_resource_list),
+ DEVMETHOD(bus_hinted_child, obio_hinted_child),
+ DEVMETHOD(bus_release_resource, obio_release_resource),
+ DEVMETHOD(bus_setup_intr, obio_setup_intr),
+ DEVMETHOD(bus_teardown_intr, obio_teardown_intr),
+ DEVMETHOD(device_attach, obio_attach),
+ DEVMETHOD(device_probe, obio_probe),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+
+ {0, 0},
+};
+
+static driver_t obio_driver = {
+ "obio",
+ obio_methods,
+ sizeof(struct obio_softc),
+};
+static devclass_t obio_devclass;
+
+DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0);
diff --git a/sys/mips/mips32/adm5120/obiovar.h b/sys/mips/mips32/adm5120/obiovar.h
new file mode 100644
index 0000000..f09972c
--- /dev/null
+++ b/sys/mips/mips32/adm5120/obiovar.h
@@ -0,0 +1,66 @@
+/* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */
+
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _ADM5120_OBIOVAR_H_
+#define _ADM5120_OBIOVAR_H_
+
+#include <sys/rman.h>
+
+/* Number of IRQs */
+#define NIRQS 32
+
+#define OBIO_MEM_START 0x10C00000L
+#define OBIO_MEM_SIZE 0x1e00000
+
+struct obio_softc {
+ struct rman oba_mem_rman;
+ struct rman oba_irq_rman;
+ struct intr_event *sc_eventstab[NIRQS]; /* IRQ events structs */
+ struct resource *sc_irq; /* IRQ resource */
+ void *sc_ih; /* interrupt cookie */
+ struct resource *sc_fast_irq; /* IRQ resource */
+ void *sc_fast_ih; /* interrupt cookie */
+};
+
+struct obio_ivar {
+ struct resource_list resources;
+};
+
+#endif /* _ADM5120_OBIOVAR_H_ */
diff --git a/sys/mips/mips32/adm5120/std.adm5120 b/sys/mips/mips32/adm5120/std.adm5120
new file mode 100644
index 0000000..5c96cd3
--- /dev/null
+++ b/sys/mips/mips32/adm5120/std.adm5120
@@ -0,0 +1,10 @@
+# $FreeBSD$
+# Standard include file for ADM5120
+
+cpu CPU_MIPS4KC
+files "../mips32/adm5120/files.adm5120"
+options ISA_MIPS32
+
+# device admpci
+device admsw
+device pci
diff --git a/sys/mips/mips32/adm5120/uart_bus_adm5120.c b/sys/mips/mips32/adm5120/uart_bus_adm5120.c
new file mode 100644
index 0000000..b3b7b67
--- /dev/null
+++ b/sys/mips/mips32/adm5120/uart_bus_adm5120.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * 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 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 THE 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
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/mips32/adm5120/adm5120reg.h>
+
+#include "uart_if.h"
+
+static int uart_adm5120_probe(device_t dev);
+
+extern struct uart_class uart_adm5120_uart_class;
+
+static device_method_t uart_adm5120_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_adm5120_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_adm5120_driver = {
+ uart_driver_name,
+ uart_adm5120_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+uart_adm5120_probe(device_t dev)
+{
+ struct uart_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ sc->sc_class = &uart_adm5120_uart_class;
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+
+ return (uart_bus_probe(dev, 0, 0, 0, 0));
+}
+
+DRIVER_MODULE(uart, obio, uart_adm5120_driver, uart_devclass, 0, 0);
diff --git a/sys/mips/mips32/adm5120/uart_cpu_adm5120.c b/sys/mips/mips32/adm5120/uart_cpu_adm5120.c
new file mode 100644
index 0000000..0f1ebab
--- /dev/null
+++ b/sys/mips/mips32/adm5120/uart_cpu_adm5120.c
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
+ * 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 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 THE 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.
+ *
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/mips32/adm5120/adm5120reg.h>
+
+extern struct uart_class uart_adm5120_uart_class;
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+
+ di->ops = uart_getops(&uart_adm5120_uart_class);
+ di->bas.chan = 0;
+ di->bas.bst = 0;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+
+ uart_bus_space_io = 0;
+ uart_bus_space_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_UART0);
+ di->bas.bsh = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_UART0);
+
+ return (0);
+}
diff --git a/sys/mips/mips32/adm5120/uart_dev_adm5120.c b/sys/mips/mips32/adm5120/uart_dev_adm5120.c
new file mode 100644
index 0000000..8cef8f8
--- /dev/null
+++ b/sys/mips/mips32/adm5120/uart_dev_adm5120.c
@@ -0,0 +1,452 @@
+/* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */
+
+/*-
+ * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
+ * Copyright (c) 2007 Oleksandr Tymoshenko.
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+
+#include <mips/mips32/adm5120/uart_dev_adm5120.h>
+
+#include "uart_if.h"
+
+/*
+ * Low-level UART interface.
+ */
+static int adm5120_uart_probe(struct uart_bas *bas);
+static void adm5120_uart_init(struct uart_bas *bas, int, int, int, int);
+static void adm5120_uart_term(struct uart_bas *bas);
+static void adm5120_uart_putc(struct uart_bas *bas, int);
+static int adm5120_uart_rxready(struct uart_bas *bas);
+static int adm5120_uart_getc(struct uart_bas *bas, struct mtx *);
+
+static struct uart_ops uart_adm5120_uart_ops = {
+ .probe = adm5120_uart_probe,
+ .init = adm5120_uart_init,
+ .term = adm5120_uart_term,
+ .putc = adm5120_uart_putc,
+ .rxready = adm5120_uart_rxready,
+ .getc = adm5120_uart_getc,
+};
+
+static int
+adm5120_uart_probe(struct uart_bas *bas)
+{
+
+ return (0);
+}
+
+static void
+adm5120_uart_init(struct uart_bas *bas, int baudrate, int databits,
+ int stopbits, int parity)
+{
+
+ /* TODO: Set parameters for uart, meanwhile stick with 115200N1 */
+}
+
+static void
+adm5120_uart_term(struct uart_bas *bas)
+{
+
+}
+
+static void
+adm5120_uart_putc(struct uart_bas *bas, int c)
+{
+ char chr;
+ chr = c;
+ while (uart_getreg(bas, UART_FR_REG) & UART_FR_TX_FIFO_FULL)
+ ;
+ uart_setreg(bas, UART_DR_REG, c);
+ while (uart_getreg(bas, UART_FR_REG) & UART_FR_BUSY)
+ ;
+ uart_barrier(bas);
+}
+
+static int
+adm5120_uart_rxready(struct uart_bas *bas)
+{
+ if (uart_getreg(bas, UART_FR_REG) & UART_FR_RX_FIFO_EMPTY)
+ return (0);
+
+ return (1);
+}
+
+static int
+adm5120_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
+{
+ int c;
+
+ uart_lock(hwmtx);
+
+ while (uart_getreg(bas, UART_FR_REG) & UART_FR_RX_FIFO_EMPTY) {
+ uart_unlock(hwmtx);
+ DELAY(10);
+ uart_lock(hwmtx);
+ }
+
+ c = uart_getreg(bas, UART_DR_REG);
+
+ uart_unlock(hwmtx);
+
+ return (c);
+}
+
+/*
+ * High-level UART interface.
+ */
+struct adm5120_uart_softc {
+ struct uart_softc base;
+};
+
+static int adm5120_uart_bus_attach(struct uart_softc *);
+static int adm5120_uart_bus_detach(struct uart_softc *);
+static int adm5120_uart_bus_flush(struct uart_softc *, int);
+static int adm5120_uart_bus_getsig(struct uart_softc *);
+static int adm5120_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int adm5120_uart_bus_ipend(struct uart_softc *);
+static int adm5120_uart_bus_param(struct uart_softc *, int, int, int, int);
+static int adm5120_uart_bus_probe(struct uart_softc *);
+static int adm5120_uart_bus_receive(struct uart_softc *);
+static int adm5120_uart_bus_setsig(struct uart_softc *, int);
+static int adm5120_uart_bus_transmit(struct uart_softc *);
+
+static kobj_method_t adm5120_uart_methods[] = {
+ KOBJMETHOD(uart_attach, adm5120_uart_bus_attach),
+ KOBJMETHOD(uart_detach, adm5120_uart_bus_detach),
+ KOBJMETHOD(uart_flush, adm5120_uart_bus_flush),
+ KOBJMETHOD(uart_getsig, adm5120_uart_bus_getsig),
+ KOBJMETHOD(uart_ioctl, adm5120_uart_bus_ioctl),
+ KOBJMETHOD(uart_ipend, adm5120_uart_bus_ipend),
+ KOBJMETHOD(uart_param, adm5120_uart_bus_param),
+ KOBJMETHOD(uart_probe, adm5120_uart_bus_probe),
+ KOBJMETHOD(uart_receive, adm5120_uart_bus_receive),
+ KOBJMETHOD(uart_setsig, adm5120_uart_bus_setsig),
+ KOBJMETHOD(uart_transmit, adm5120_uart_bus_transmit),
+ { 0, 0 }
+};
+
+struct uart_class uart_adm5120_uart_class = {
+ "adm5120",
+ adm5120_uart_methods,
+ sizeof(struct adm5120_uart_softc),
+ .uc_ops = &uart_adm5120_uart_ops,
+ .uc_range = 1, /* use hinted range */
+ .uc_rclk = 62500000
+};
+
+#define SIGCHG(c, i, s, d) \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ }
+
+/*
+ * Disable TX interrupt. uart should be locked
+ */
+static __inline void
+adm5120_uart_disable_txintr(struct uart_softc *sc)
+{
+ uint8_t cr;
+
+ cr = uart_getreg(&sc->sc_bas, UART_CR_REG);
+ cr &= ~UART_CR_TX_INT_EN;
+ uart_setreg(&sc->sc_bas, UART_CR_REG, cr);
+}
+
+/*
+ * Enable TX interrupt. uart should be locked
+ */
+static __inline void
+adm5120_uart_enable_txintr(struct uart_softc *sc)
+{
+ uint8_t cr;
+
+ cr = uart_getreg(&sc->sc_bas, UART_CR_REG);
+ cr |= UART_CR_TX_INT_EN;
+ uart_setreg(&sc->sc_bas, UART_CR_REG, cr);
+}
+
+static int
+adm5120_uart_bus_attach(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ struct uart_devinfo *di;
+
+ bas = &sc->sc_bas;
+ if (sc->sc_sysdev != NULL) {
+ di = sc->sc_sysdev;
+ /* TODO: set parameters from di */
+ } else {
+ /* TODO: set parameters 115200, 8N1 */
+ }
+
+ sc->sc_rxfifosz = 16;
+ sc->sc_txfifosz = 16;
+
+ (void)adm5120_uart_bus_getsig(sc);
+
+#if 1
+ /* Enable FIFO */
+ uart_setreg(bas, UART_LCR_H_REG,
+ uart_getreg(bas, UART_LCR_H_REG) | UART_LCR_H_FEN);
+#endif
+ /* Enable interrupts */
+ uart_setreg(bas, UART_CR_REG,
+ UART_CR_PORT_EN|UART_CR_RX_INT_EN|UART_CR_RX_TIMEOUT_INT_EN|
+ UART_CR_MODEM_STATUS_INT_EN);
+
+ return (0);
+}
+
+static int
+adm5120_uart_bus_detach(struct uart_softc *sc)
+{
+
+ return (0);
+}
+
+static int
+adm5120_uart_bus_flush(struct uart_softc *sc, int what)
+{
+
+ return (0);
+}
+
+static int
+adm5120_uart_bus_getsig(struct uart_softc *sc)
+{
+ uint32_t new, old, sig;
+ uint8_t bes;
+
+ do {
+ old = sc->sc_hwsig;
+ sig = old;
+ uart_lock(sc->sc_hwmtx);
+ bes = uart_getreg(&sc->sc_bas, UART_FR_REG);
+ uart_unlock(sc->sc_hwmtx);
+ SIGCHG(bes & UART_FR_CTS, sig, SER_CTS, SER_DCTS);
+ SIGCHG(bes & UART_FR_DCD, sig, SER_DCD, SER_DDCD);
+ SIGCHG(bes & UART_FR_DSR, sig, SER_DSR, SER_DDSR);
+ new = sig & ~SER_MASK_DELTA;
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+
+ return (sig);
+}
+
+static int
+adm5120_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
+{
+ struct uart_bas *bas;
+ int baudrate, divisor, error;
+
+ bas = &sc->sc_bas;
+ error = 0;
+ uart_lock(sc->sc_hwmtx);
+ switch (request) {
+ case UART_IOCTL_BREAK:
+ /* TODO: Send BREAK */
+ break;
+ case UART_IOCTL_BAUD:
+ divisor = uart_getreg(bas, UART_LCR_M_REG);
+ divisor = (divisor << 8) |
+ uart_getreg(bas, UART_LCR_L_REG);
+ baudrate = bas->rclk / 2 / (divisor + 2);
+ *(int*)data = baudrate;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ uart_unlock(sc->sc_hwmtx);
+ return (error);
+}
+
+static int
+adm5120_uart_bus_ipend(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int ipend;
+ uint8_t ir, fr, rsr;
+
+ bas = &sc->sc_bas;
+ ipend = 0;
+
+ uart_lock(sc->sc_hwmtx);
+ ir = uart_getreg(&sc->sc_bas, UART_IR_REG);
+ fr = uart_getreg(&sc->sc_bas, UART_FR_REG);
+ rsr = uart_getreg(&sc->sc_bas, UART_RSR_REG);
+
+ if (ir & UART_IR_RX_INT)
+ ipend |= SER_INT_RXREADY;
+
+ if (ir & UART_IR_RX_TIMEOUT_INT)
+ ipend |= SER_INT_RXREADY;
+
+ if (ir & UART_IR_MODEM_STATUS_INT)
+ ipend |= SER_INT_SIGCHG;
+
+ if (rsr & UART_RSR_BE)
+ ipend |= SER_INT_BREAK;
+
+ if (rsr & UART_RSR_OE)
+ ipend |= SER_INT_OVERRUN;
+
+ if (fr & UART_FR_TX_FIFO_EMPTY) {
+ if (ir & UART_IR_TX_INT) {
+ adm5120_uart_disable_txintr(sc);
+ ipend |= SER_INT_TXIDLE;
+ }
+ }
+
+ if (ipend)
+ uart_setreg(bas, UART_IR_REG, ir | UART_IR_UICR);
+
+ uart_unlock(sc->sc_hwmtx);
+
+ return (ipend);
+}
+
+static int
+adm5120_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
+ int stopbits, int parity)
+{
+
+ /* TODO: Set parameters for uart, meanwhile stick with 115200 8N1 */
+ return (0);
+}
+
+static int
+adm5120_uart_bus_probe(struct uart_softc *sc)
+{
+ char buf[80];
+ int error;
+ char ch;
+
+ error = adm5120_uart_probe(&sc->sc_bas);
+ if (error)
+ return (error);
+
+ ch = sc->sc_bas.chan + 'A';
+
+ snprintf(buf, sizeof(buf), "adm5120_uart, channel %c", ch);
+ device_set_desc_copy(sc->sc_dev, buf);
+
+ return (0);
+}
+
+static int
+adm5120_uart_bus_receive(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+ int xc;
+ uint8_t fr, rsr;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+ fr = uart_getreg(bas, UART_FR_REG);
+ while (!(fr & UART_FR_RX_FIFO_EMPTY)) {
+ if (uart_rx_full(sc)) {
+ sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
+ break;
+ }
+ xc = 0;
+ rsr = uart_getreg(bas, UART_RSR_REG);
+ if (rsr & UART_RSR_FE)
+ xc |= UART_STAT_FRAMERR;
+ if (rsr & UART_RSR_PE)
+ xc |= UART_STAT_PARERR;
+ if (rsr & UART_RSR_OE)
+ xc |= UART_STAT_OVERRUN;
+ xc |= uart_getreg(bas, UART_DR_REG);
+ uart_barrier(bas);
+ uart_rx_put(sc, xc);
+ if (rsr & (UART_RSR_FE | UART_RSR_PE | UART_RSR_OE)) {
+ uart_setreg(bas, UART_ECR_REG, UART_ECR_RSR);
+ uart_barrier(bas);
+ }
+ fr = uart_getreg(bas, UART_FR_REG);
+ }
+
+ /* Discard everything left in the Rx FIFO. */
+ while (!(fr & UART_FR_RX_FIFO_EMPTY)) {
+ ( void)uart_getreg(bas, UART_DR_REG);
+ uart_barrier(bas);
+ rsr = uart_getreg(bas, UART_RSR_REG);
+ if (rsr & (UART_RSR_FE | UART_RSR_PE | UART_RSR_OE)) {
+ uart_setreg(bas, UART_ECR_REG, UART_ECR_RSR);
+ uart_barrier(bas);
+ }
+ fr = uart_getreg(bas, UART_FR_REG);
+ }
+ uart_unlock(sc->sc_hwmtx);
+ return (0);
+}
+
+static int
+adm5120_uart_bus_setsig(struct uart_softc *sc, int sig)
+{
+
+ /* TODO: implement (?) */
+ return (0);
+}
+
+static int
+adm5120_uart_bus_transmit(struct uart_softc *sc)
+{
+ struct uart_bas *bas;
+
+ bas = &sc->sc_bas;
+ uart_lock(sc->sc_hwmtx);
+ sc->sc_txbusy = 1;
+ for (int i = 0; i < sc->sc_txdatasz; i++) {
+ if (uart_getreg(bas, UART_FR_REG) & UART_FR_TX_FIFO_FULL)
+ break;
+ uart_setreg(bas, UART_DR_REG, sc->sc_txbuf[i]);
+ }
+
+ /* Enable TX interrupt */
+ adm5120_uart_enable_txintr(sc);
+ uart_unlock(sc->sc_hwmtx);
+ return (0);
+}
diff --git a/sys/mips/mips32/adm5120/uart_dev_adm5120.h b/sys/mips/mips32/adm5120/uart_dev_adm5120.h
new file mode 100644
index 0000000..e7165f1
--- /dev/null
+++ b/sys/mips/mips32/adm5120/uart_dev_adm5120.h
@@ -0,0 +1,80 @@
+/* $NetBSD: uart.h,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko.
+ * 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.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS
+ * 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 _ADMUART_H
+#define _ADMUART_H
+/* UART registers */
+#define UART_DR_REG 0x00
+#define UART_RSR_REG 0x04
+#define UART_RSR_FE 0x01
+#define UART_RSR_PE 0x02
+#define UART_RSR_BE 0x04
+#define UART_RSR_OE 0x08
+#define UART_ECR_REG 0x04
+#define UART_ECR_RSR 0x80
+#define UART_LCR_H_REG 0x08
+#define UART_LCR_H_FEN 0x10
+#define UART_LCR_M_REG 0x0c
+#define UART_LCR_L_REG 0x10
+#define UART_CR_REG 0x14
+#define UART_CR_PORT_EN 0x01
+#define UART_CR_SIREN 0x02
+#define UART_CR_SIRLP 0x04
+#define UART_CR_MODEM_STATUS_INT_EN 0x08
+#define UART_CR_RX_INT_EN 0x10
+#define UART_CR_TX_INT_EN 0x20
+#define UART_CR_RX_TIMEOUT_INT_EN 0x40
+#define UART_CR_LOOPBACK_EN 0x80
+#define UART_FR_REG 0x18
+#define UART_FR_CTS 0x01
+#define UART_FR_DSR 0x02
+#define UART_FR_DCD 0x04
+#define UART_FR_BUSY 0x08
+#define UART_FR_RX_FIFO_EMPTY 0x10
+#define UART_FR_TX_FIFO_FULL 0x20
+#define UART_FR_RX_FIFO_FULL 0x40
+#define UART_FR_TX_FIFO_EMPTY 0x80
+#define UART_IR_REG 0x1c
+#define UART_IR_MODEM_STATUS_INT 0x01
+#define UART_IR_RX_INT 0x02
+#define UART_IR_TX_INT 0x04
+#define UART_IR_RX_TIMEOUT_INT 0x08
+#define UART_IR_INT_MASK 0x0f
+#define UART_IR_UICR 0x80
+#define UART_ILPR_REG 0x20
+
+/* UART interrupts */
+
+int uart_cnattach(void);
+#endif /* _ADMUART_H */
diff --git a/sys/mips/mips32/idt/files.idt b/sys/mips/mips32/idt/files.idt
new file mode 100644
index 0000000..2782edc
--- /dev/null
+++ b/sys/mips/mips32/idt/files.idt
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+mips/mips32/idt/idt_machdep.c standard
+mips/mips32/idt/idtpci.c optional pci
+mips/mips32/idt/if_kr.c optional kr
+mips/mips32/idt/obio.c standard
+mips/mips32/idt/uart_cpu_rc32434.c optional uart
+mips/mips32/idt/uart_bus_rc32434.c optional uart
diff --git a/sys/mips/mips32/idt/idt_machdep.c b/sys/mips/mips32/idt/idt_machdep.c
new file mode 100644
index 0000000..040c3f9
--- /dev/null
+++ b/sys/mips/mips32/idt/idt_machdep.c
@@ -0,0 +1,188 @@
+/*-
+ * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 OR HIS RELATIVES 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 MIND, 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.
+ *
+ * $Id: $
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/cons.h>
+#include <sys/exec.h>
+#include <sys/ucontext.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/cache.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/intr_machdep.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+#include <machine/pte.h>
+#include <machine/sigframe.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+extern int *edata;
+extern int *end;
+
+void
+platform_halt(void)
+{
+
+}
+
+
+void
+platform_identify(void)
+{
+
+}
+
+void
+platform_reset(void)
+{
+ volatile unsigned int * p = (void *)0xb8008000;
+ /*
+ * TODO: we should take care of TLB stuff here. Otherwise
+ * board does not boots properly next time
+ */
+
+ /* Write 0x8000_0001 to the Reset register */
+ *p = 0x80000001;
+
+ __asm __volatile("li $25, 0xbfc00000");
+ __asm __volatile("j $25");
+}
+
+void
+platform_trap_enter(void)
+{
+
+}
+
+void
+platform_trap_exit(void)
+{
+
+}
+
+void
+platform_start(__register_t a0, __register_t a1,
+ __register_t a2 __unused, __register_t a3 __unused)
+{
+ uint64_t platform_counter_freq;
+ vm_offset_t kernend;
+ int argc = a0;
+ char **argv = (char **)a1;
+ int i, mem;
+
+
+ /* clear the BSS and SBSS segments */
+ kernend = round_page((vm_offset_t)&end);
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+ /*
+ * Looking for mem=XXM argument
+ */
+ mem = 0; /* Just something to start with */
+ for (i=0; i < argc; i++) {
+ if (strncmp(argv[i], "mem=", 4) == 0) {
+ mem = strtol(argv[i] + 4, NULL, 0);
+ break;
+ }
+ }
+
+ bootverbose = 1;
+ if (mem > 0)
+ realmem = btoc(mem << 20);
+ else
+ realmem = btoc(32 << 20);
+
+ for (i = 0; i < 10; i++) {
+ phys_avail[i] = 0;
+ }
+
+ /* phys_avail regions are in bytes */
+ phys_avail[0] = MIPS_KSEG0_TO_PHYS((vm_offset_t)&end);
+ phys_avail[1] = ctob(realmem);
+
+ physmem = realmem;
+
+ /*
+ * ns8250 uart code uses DELAY so ticker should be inititalized
+ * before cninit. And tick_init_params refers to hz, so * init_param1
+ * should be called first.
+ */
+ init_param1();
+ /* TODO: parse argc,argv */
+ platform_counter_freq = 330000000UL;
+ mips_timer_init_params(platform_counter_freq, 1);
+ cninit();
+ /* Panic here, after cninit */
+ if (mem == 0)
+ panic("No mem=XX parameter in arguments");
+
+ printf("cmd line: ");
+ for (i=0; i < argc; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+#ifdef DDB
+ kdb_init();
+#endif
+}
diff --git a/sys/mips/mips32/idt/idtpci.c b/sys/mips/mips32/idt/idtpci.c
new file mode 100644
index 0000000..7e4414f
--- /dev/null
+++ b/sys/mips/mips32/idt/idtpci.c
@@ -0,0 +1,565 @@
+/* $NetBSD: idtpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2007 David Young.
+ * Copyright (c) 2007 Oleskandr Tymoshenko. 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.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * 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.
+ */
+/*-
+ * Copyright (c) 2006 Itronix Inc.
+ * All rights reserved.
+ *
+ * Written by Garrett D'Amore for Itronix 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. The name of Itronix Inc. may not be used to endorse
+ * or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ITRONIX 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 ITRONIX 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/pmap.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/pci/pcib_private.h>
+#include "pcib_if.h"
+
+#include <mips/mips32/idt/idtreg.h>
+
+#ifdef IDTPCI_DEBUG
+int idtpci_debug = 1;
+#define IDTPCI_DPRINTF(__fmt, ...) \
+do { \
+ if (idtpci_debug) \
+ printf((__fmt), __VA_ARGS__); \
+} while (/*CONSTCOND*/0)
+#else /* !IDTPCI_DEBUG */
+#define IDTPCI_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0)
+#endif /* IDTPCI_DEBUG */
+
+#define IDTPCI_TAG_BUS_MASK 0x007f0000
+#define IDTPCI_TAG_DEVICE_MASK 0x00007800
+#define IDTPCI_TAG_FUNCTION_MASK 0x00000300
+#define IDTPCI_TAG_REGISTER_MASK 0x0000007c
+
+#define IDTPCI_MAX_DEVICE
+
+#define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_PCI + (o)))
+#define REG_WRITE(o,v) (REG_READ(o)) = (v)
+
+unsigned int korina_fixup[24] = {
+ 0x00000157, 0x00000000, 0x00003c04, 0x00000008, 0x18800001, 0x18000001,
+ 0x48000008, 0x00000000, 0x00000000, 0x00000000, 0x011d0214, 0x00000000,
+ 0x00000000, 0x00000000, 0x38080101, 0x00008080, 0x00000d6e, 0x00000000,
+ 0x00000051, 0x00000000, 0x00000055, 0x18000000, 0x00000000, 0x00000000
+};
+
+struct idtpci_softc {
+ device_t sc_dev;
+
+ int sc_busno;
+ struct rman sc_mem_rman[2];
+ struct rman sc_io_rman[2];
+ struct rman sc_irq_rman;
+ uint32_t sc_mem;
+ uint32_t sc_io;
+};
+
+static uint32_t
+idtpci_make_addr(int bus, int slot, int func, int reg)
+{
+
+ return 0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg;
+}
+
+static int
+idtpci_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+idtpci_attach(device_t dev)
+{
+ int busno = 0;
+ struct idtpci_softc *sc = device_get_softc(dev);
+ unsigned int pci_data, force_endianess = 0;
+ int i;
+ bus_addr_t addr;
+
+ sc->sc_dev = dev;
+ sc->sc_busno = busno;
+
+ sc->sc_io = 0;
+ sc->sc_mem = 0;
+
+ /* TODO: Check for host mode */
+
+ /* Enabled PCI, IG mode, EAP mode */
+ REG_WRITE(IDT_PCI_CNTL, IDT_PCI_CNTL_IGM | IDT_PCI_CNTL_EAP |
+ IDT_PCI_CNTL_EN);
+ /* Wait while "Reset in progress bit" set */
+ while(1) {
+ pci_data = REG_READ(IDT_PCI_STATUS);
+ if((pci_data & IDT_PCI_STATUS_RIP) == 0)
+ break;
+ }
+
+ /* Reset status register */
+ REG_WRITE(IDT_PCI_STATUS, 0);
+ /* Mask interrupts related to status register */
+ REG_WRITE(IDT_PCI_STATUS_MASK, 0xffffffff);
+
+ /* Disable PCI decoupled access */
+ REG_WRITE(IDT_PCI_DAC, 0);
+ /* Zero status and mask DA interrupts */
+ REG_WRITE(IDT_PCI_DAS, 0);
+ REG_WRITE(IDT_PCI_DASM, 0x7f);
+
+ /* Init PCI messaging unit */
+ /* Disable messaging interrupts */
+ REG_WRITE(IDT_PCI_IIC, 0);
+ REG_WRITE(IDT_PCI_IIM, 0xffffffff);
+ REG_WRITE(IDT_PCI_OIC, 0);
+ REG_WRITE(IDT_PCI_OIM, 0);
+
+#ifdef __MIPSEB__
+ force_endianess = IDT_PCI_LBA_FE;
+#endif
+
+ /* LBA0 -- memory window */
+ REG_WRITE(IDT_PCI_LBA0, IDT_PCIMEM0_BASE);
+ REG_WRITE(IDT_PCI_LBA0_MAP, IDT_PCIMEM0_BASE);
+ REG_WRITE(IDT_PCI_LBA0_CNTL, IDT_PCI_LBA_SIZE_16MB | force_endianess);
+ pci_data = REG_READ(IDT_PCI_LBA0_CNTL);
+
+ /* LBA1 -- memory window */
+ REG_WRITE(IDT_PCI_LBA1, IDT_PCIMEM1_BASE);
+ REG_WRITE(IDT_PCI_LBA1_MAP, IDT_PCIMEM1_BASE);
+ REG_WRITE(IDT_PCI_LBA1_CNTL, IDT_PCI_LBA_SIZE_256MB | force_endianess);
+ pci_data = REG_READ(IDT_PCI_LBA1_CNTL);
+
+ /* LBA2 -- IO window */
+ REG_WRITE(IDT_PCI_LBA2, IDT_PCIMEM2_BASE);
+ REG_WRITE(IDT_PCI_LBA2_MAP, IDT_PCIMEM2_BASE);
+ REG_WRITE(IDT_PCI_LBA2_CNTL, IDT_PCI_LBA_SIZE_4MB | IDT_PCI_LBA_MSI |
+ force_endianess);
+ pci_data = REG_READ(IDT_PCI_LBA2_CNTL);
+
+ /* LBA3 -- IO window */
+ REG_WRITE(IDT_PCI_LBA3, IDT_PCIMEM3_BASE);
+ REG_WRITE(IDT_PCI_LBA3_MAP, IDT_PCIMEM3_BASE);
+ REG_WRITE(IDT_PCI_LBA3_CNTL, IDT_PCI_LBA_SIZE_1MB | IDT_PCI_LBA_MSI |
+ force_endianess);
+ pci_data = REG_READ(IDT_PCI_LBA3_CNTL);
+
+
+ pci_data = REG_READ(IDT_PCI_CNTL) & ~IDT_PCI_CNTL_TNR;
+ REG_WRITE(IDT_PCI_CNTL, pci_data);
+ pci_data = REG_READ(IDT_PCI_CNTL);
+
+ /* Rewrite Target Control register with default values */
+ REG_WRITE(IDT_PCI_TC, (IDT_PCI_TC_DTIMER << 8) | IDT_PCI_TC_RTIMER);
+
+ /* Perform Korina fixup */
+ addr = idtpci_make_addr(0, 0, 0, 4);
+ for (i = 0; i < 24; i++) {
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, addr);
+ REG_WRITE(IDT_PCI_CFG_DATA, korina_fixup[i]);
+ __asm__ volatile ("sync");
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, 0);
+ REG_WRITE(IDT_PCI_CFG_DATA, 0);
+ addr += 4;
+ }
+
+ /* Use KSEG1 to access IO ports for it is uncached */
+ sc->sc_io = 0;
+ sc->sc_io_rman[0].rm_type = RMAN_ARRAY;
+ sc->sc_io_rman[0].rm_descr = "IDTPCI I/O Ports window 1";
+ if (rman_init(&sc->sc_io_rman[0]) != 0 ||
+ rman_manage_region(&sc->sc_io_rman[0],
+ IDT_PCIMEM2_BASE, IDT_PCIMEM2_BASE + IDT_PCIMEM2_SIZE - 1) != 0) {
+ panic("idtpci_attach: failed to set up I/O rman");
+ }
+
+ sc->sc_io_rman[1].rm_type = RMAN_ARRAY;
+ sc->sc_io_rman[1].rm_descr = "IDTPCI I/O Ports window 2";
+ if (rman_init(&sc->sc_io_rman[1]) != 0 ||
+ rman_manage_region(&sc->sc_io_rman[1],
+ IDT_PCIMEM3_BASE, IDT_PCIMEM3_BASE + IDT_PCIMEM3_SIZE - 1) != 0) {
+ panic("idtpci_attach: failed to set up I/O rman");
+ }
+
+ /* Use KSEG1 to access PCI memory for it is uncached */
+ sc->sc_mem = 0;
+ sc->sc_mem_rman[0].rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman[0].rm_descr = "IDTPCI PCI Memory window 1";
+ if (rman_init(&sc->sc_mem_rman[0]) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman[0],
+ IDT_PCIMEM0_BASE, IDT_PCIMEM0_BASE + IDT_PCIMEM0_SIZE) != 0) {
+ panic("idtpci_attach: failed to set up memory rman");
+ }
+
+ sc->sc_mem_rman[1].rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman[1].rm_descr = "IDTPCI PCI Memory window 2";
+ if (rman_init(&sc->sc_mem_rman[1]) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman[1],
+ IDT_PCIMEM1_BASE, IDT_PCIMEM1_BASE + IDT_PCIMEM1_SIZE) != 0) {
+ panic("idtpci_attach: failed to set up memory rman");
+ }
+
+ sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+ sc->sc_irq_rman.rm_descr = "IDTPCI PCI IRQs";
+ if (rman_init(&sc->sc_irq_rman) != 0 ||
+ rman_manage_region(&sc->sc_irq_rman, PCI_IRQ_BASE,
+ PCI_IRQ_END) != 0)
+ panic("idtpci_attach: failed to set up IRQ rman");
+
+ device_add_child(dev, "pci", busno);
+ return (bus_generic_attach(dev));
+}
+
+static int
+idtpci_maxslots(device_t dev)
+{
+
+ return (PCI_SLOTMAX);
+}
+
+static uint32_t
+idtpci_read_config(device_t dev, int bus, int slot, int func, int reg,
+ int bytes)
+{
+ uint32_t data;
+ uint32_t shift, mask;
+ bus_addr_t addr;
+
+ IDTPCI_DPRINTF("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__,
+ bus, slot, func, reg, bytes);
+
+ addr = idtpci_make_addr(bus, slot, func, reg);
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, addr);
+ data = REG_READ(IDT_PCI_CFG_DATA);
+
+ switch (reg % 4) {
+ case 3:
+ shift = 24;
+ break;
+ case 2:
+ shift = 16;
+ break;
+ case 1:
+ shift = 8;
+ break;
+ default:
+ shift = 0;
+ break;
+ }
+
+ switch (bytes) {
+ case 1:
+ mask = 0xff;
+ data = (data >> shift) & mask;
+ break;
+ case 2:
+ mask = 0xffff;
+ if (reg % 4 == 0)
+ data = data & mask;
+ else
+ data = (data >> 16) & mask;
+ break;
+ case 4:
+ break;
+ default:
+ panic("%s: wrong bytes count", __func__);
+ break;
+ }
+
+ __asm__ volatile ("sync");
+ IDTPCI_DPRINTF("%s: read 0x%x\n", __func__, data);
+
+ return (data);
+}
+
+static void
+idtpci_write_config(device_t dev, int bus, int slot, int func, int reg,
+ uint32_t data, int bytes)
+{
+ bus_addr_t addr;
+ uint32_t reg_data;
+ uint32_t shift, mask;
+
+ IDTPCI_DPRINTF("%s: tag (%x, %x, %x) reg %d(%d) data %08x\n", __func__,
+ bus, slot, func, reg, bytes, data);
+
+ if (bytes != 4) {
+ reg_data = idtpci_read_config(dev, bus, slot, func, reg, 4);
+
+ switch (reg % 4) {
+ case 3:
+ shift = 24;
+ break;
+ case 2:
+ shift = 16;
+ break;
+ case 1:
+ shift = 8;
+ break;
+ default:
+ shift = 0;
+ break;
+ }
+
+ switch (bytes) {
+ case 1:
+ mask = 0xff;
+ data = (reg_data & ~ (mask << shift)) | (data << shift);
+ break;
+ case 2:
+ mask = 0xffff;
+ if (reg % 4 == 0)
+ data = (reg_data & ~mask) | data;
+ else
+ data = (reg_data & ~ (mask << shift)) |
+ (data << shift);
+ break;
+ case 4:
+ break;
+ default:
+ panic("%s: wrong bytes count", __func__);
+ break;
+ }
+ }
+
+ addr = idtpci_make_addr(bus, slot, func, reg);
+
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, addr);
+ REG_WRITE(IDT_PCI_CFG_DATA, data);
+ __asm__ volatile ("sync");
+
+ REG_WRITE(IDT_PCI_CFG_ADDR, 0);
+ REG_WRITE(IDT_PCI_CFG_DATA, 0);
+}
+
+static int
+idtpci_route_interrupt(device_t pcib, device_t device, int pin)
+{
+ static int idt_pci_table[2][12] =
+ {
+ { 0, 0, 2, 3, 2, 3, 0, 0, 0, 0, 0, 1 },
+ { 0, 0, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3 }
+ };
+ int dev, bus, irq;
+
+ dev = pci_get_slot(device);
+ bus = pci_get_bus(device);
+ if (bootverbose)
+ device_printf(pcib, "routing pin %d for %s\n", pin,
+ device_get_nameunit(device));
+ if (bus >= 0 && bus <= 1 &&
+ dev >= 0 && dev <= 11) {
+ irq = IP_IRQ(6, idt_pci_table[bus][dev] + 4);
+ if (bootverbose)
+ printf("idtpci: %d/%d/%d -> IRQ%d\n",
+ pci_get_bus(device), dev, pci_get_function(device),
+ irq);
+ return (irq);
+ } else
+ printf("idtpci: no mapping for %d/%d/%d\n",
+ pci_get_bus(device), dev, pci_get_function(device));
+
+ return (-1);
+}
+
+static int
+idtpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct idtpci_softc *sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = 0;
+ return (0);
+ case PCIB_IVAR_BUS:
+ *result = sc->sc_busno;
+ return (0);
+ }
+
+ return (ENOENT);
+}
+
+static int
+idtpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
+{
+ struct idtpci_softc * sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_busno = result;
+ return (0);
+ }
+ return (ENOENT);
+}
+
+static struct resource *
+idtpci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+
+ struct idtpci_softc *sc = device_get_softc(bus);
+ struct resource *rv = NULL;
+ struct rman *rm1, *rm2;
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm1 = &sc->sc_irq_rman;
+ rm2 = NULL;
+ break;
+ case SYS_RES_MEMORY:
+ rm1 = &sc->sc_mem_rman[0];
+ rm2 = &sc->sc_mem_rman[1];
+ break;
+ case SYS_RES_IOPORT:
+ rm1 = &sc->sc_io_rman[0];
+ rm2 = &sc->sc_io_rman[1];
+ break;
+ default:
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm1, start, end, count, flags, child);
+
+ /* Try second window if it exists */
+ if ((rv == NULL) && (rm2 != NULL))
+ rv = rman_reserve_resource(rm2, start, end, count, flags,
+ child);
+
+ if (rv == NULL)
+ return (NULL);
+
+ rman_set_rid(rv, *rid);
+
+ if (flags & RF_ACTIVE) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+idtpci_teardown_intr(device_t dev, device_t child, struct resource *res,
+ void *cookie)
+{
+
+ return (intr_event_remove_handler(cookie));
+}
+
+static device_method_t idtpci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, idtpci_probe),
+ DEVMETHOD(device_attach, idtpci_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, idtpci_read_ivar),
+ DEVMETHOD(bus_write_ivar, idtpci_write_ivar),
+ DEVMETHOD(bus_alloc_resource, idtpci_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, idtpci_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, idtpci_maxslots),
+ DEVMETHOD(pcib_read_config, idtpci_read_config),
+ DEVMETHOD(pcib_write_config, idtpci_write_config),
+ DEVMETHOD(pcib_route_interrupt, idtpci_route_interrupt),
+
+ {0, 0}
+};
+
+static driver_t idtpci_driver = {
+ "pcib",
+ idtpci_methods,
+ sizeof(struct idtpci_softc),
+};
+
+static devclass_t idtpci_devclass;
+
+DRIVER_MODULE(idtpci, obio, idtpci_driver, idtpci_devclass, 0, 0);
diff --git a/sys/mips/mips32/idt/idtreg.h b/sys/mips/mips32/idt/idtreg.h
new file mode 100644
index 0000000..3a088e7
--- /dev/null
+++ b/sys/mips/mips32/idt/idtreg.h
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 OR HIS RELATIVES 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 MIND, 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 __IDTREG_H__
+#define __IDTREG_H__
+
+/* Interrupt controller */
+#define IDT_BASE_ICU 0x18038000
+#define ICU_IPEND2 0x00
+#define ICU_ITEST2 0x04
+#define ICU_IMASK2 0x08
+#define ICU_IPEND3 0x0C
+#define ICU_ITEST3 0x10
+#define ICU_IMASK3 0x14
+#define ICU_IPEND4 0x18
+#define ICU_ITEST4 0x1c
+#define ICU_IMASK4 0x20
+#define ICU_IPEND5 0x24
+#define ICU_ITEST5 0x28
+#define ICU_IMASK5 0x2c
+#define ICU_IPEND6 0x30
+#define ICU_ITEST6 0x34
+#define ICU_IMASK6 0x38
+#define ICU_NMIPS 0x3c
+
+#define IDT_BASE_GPIO 0x18050000
+#define GPIO_FUNC 0x00
+#define GPIO_CFG 0x04
+#define GPIO_DATA 0x08
+#define GPIO_ILEVEL 0x0C
+#define GPIO_ISTAT 0x10
+#define GPIO_NMIEN 0x14
+
+#define IDT_BASE_UART0 0x18058000
+
+/* PCI controller */
+#define IDT_BASE_PCI 0x18080000
+#define IDT_PCI_CNTL 0x00
+#define IDT_PCI_CNTL_EN 0x001
+#define IDT_PCI_CNTL_TNR 0x002
+#define IDT_PCI_CNTL_SCE 0x004
+#define IDT_PCI_CNTL_IEN 0x008
+#define IDT_PCI_CNTL_AAA 0x010
+#define IDT_PCI_CNTL_EAP 0x020
+#define IDT_PCI_CNTL_IGM 0x200
+#define IDT_PCI_STATUS 0x04
+#define IDT_PCI_STATUS_RIP 0x20000
+#define IDT_PCI_STATUS_MASK 0x08
+#define IDT_PCI_CFG_ADDR 0x0C
+#define IDT_PCI_CFG_DATA 0x10
+/* LBA stuff */
+#define IDT_PCI_LBA0 0x14
+#define IDT_PCI_LBA0_CNTL 0x18
+#define IDT_PCI_LBA_MSI 0x01
+#define IDT_PCI_LBA_SIZE_1MB (0x14 << 2)
+#define IDT_PCI_LBA_SIZE_2MB (0x15 << 2)
+#define IDT_PCI_LBA_SIZE_4MB (0x16 << 2)
+#define IDT_PCI_LBA_SIZE_8MB (0x17 << 2)
+#define IDT_PCI_LBA_SIZE_16MB (0x18 << 2)
+#define IDT_PCI_LBA_SIZE_32MB (0x19 << 2)
+#define IDT_PCI_LBA_SIZE_64MB (0x1A << 2)
+#define IDT_PCI_LBA_SIZE_128MB (0x1B << 2)
+#define IDT_PCI_LBA_SIZE_256MB (0x1C << 2)
+#define IDT_PCI_LBA_FE 0x80
+#define IDT_PCI_LBA_RT 0x100
+#define IDT_PCI_LBA0_MAP 0x1C
+#define IDT_PCI_LBA1 0x20
+#define IDT_PCI_LBA1_CNTL 0x24
+#define IDT_PCI_LBA1_MAP 0x28
+#define IDT_PCI_LBA2 0x2C
+#define IDT_PCI_LBA2_CNTL 0x30
+#define IDT_PCI_LBA2_MAP 0x34
+#define IDT_PCI_LBA3 0x38
+#define IDT_PCI_LBA3_CNTL 0x3C
+#define IDT_PCI_LBA3_MAP 0x40
+/* decoupled registers */
+#define IDT_PCI_DAC 0x44
+#define IDT_PCI_DAS 0x48
+#define IDT_PCI_DASM 0x4C
+
+#define IDT_PCI_TC 0x5C
+#define IDT_PCI_TC_RTIMER 0x10
+#define IDT_PCI_TC_DTIMER 0x08
+/* Messaging unit of PCI controller */
+#define IDT_PCI_IIC 0x8024
+#define IDT_PCI_IIM 0x8028
+#define IDT_PCI_OIC 0x8030
+#define IDT_PCI_OIM 0x8034
+
+/* PCI-related stuff */
+#define IDT_PCIMEM0_BASE 0x50000000
+#define IDT_PCIMEM0_SIZE 0x01000000
+
+#define IDT_PCIMEM1_BASE 0x60000000
+#define IDT_PCIMEM1_SIZE 0x10000000
+
+#define IDT_PCIMEM2_BASE 0x18C00000
+#define IDT_PCIMEM2_SIZE 0x00400000
+
+#define IDT_PCIMEM3_BASE 0x18800000
+#define IDT_PCIMEM3_SIZE 0x00100000
+
+/* Interrupts-related stuff */
+#define IRQ_BASE 8
+/* Convert <IPbit, irq_offset> pair to IRQ number */
+#define IP_IRQ(IPbit, offset) ((IPbit - 2) * 32 + (offset) + IRQ_BASE)
+/* The last one available IRQ */
+#define IRQ_END IP_IRQ(6, 31)
+#define ICU_GROUP_REG_OFFSET 0x0C
+
+#define ICU_IP(irq) (((irq) - IRQ_BASE) & 0x1f)
+#define ICU_IP_BIT(irq) (1 << ICU_IP(irq))
+#define ICU_GROUP(irq) (((irq) - IRQ_BASE) >> 5)
+
+#define ICU_GROUP_MASK_REG(group) \
+ (ICU_IMASK2 + ((((group) - 2) * ICU_GROUP_REG_OFFSET)))
+#define ICU_GROUP_IPEND_REG(group) \
+ (ICU_IPEND2 + ((((group) - 2) * ICU_GROUP_REG_OFFSET)))
+
+#define ICU_IRQ_MASK_REG(irq) \
+ (ICU_IMASK2 + ((ICU_GROUP(irq) * ICU_GROUP_REG_OFFSET)))
+#define ICU_IRQ_IPEND_REG(irq) \
+ (ICU_IPEND2 + ((ICU_GROUP(irq) * ICU_GROUP_REG_OFFSET)))
+
+#define PCI_IRQ_BASE IP_IRQ(6, 4)
+#define PCI_IRQ_END IP_IRQ(6, 7)
+
+#endif /* __IDTREG_H__ */
+
diff --git a/sys/mips/mips32/idt/if_kr.c b/sys/mips/mips32/idt/if_kr.c
new file mode 100644
index 0000000..817cff2
--- /dev/null
+++ b/sys/mips/mips32/idt/if_kr.c
@@ -0,0 +1,1615 @@
+/*-
+ * Copyright (C) 2007
+ * Oleksandr Tymoshenko <gonzo@freebsd.org>. 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 OR HIS RELATIVES 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 MIND, 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.
+ *
+ * $Id: $
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * RC32434 Ethernet interface driver
+ */
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/taskqueue.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <net/bpf.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+MODULE_DEPEND(kr, ether, 1, 1, 1);
+MODULE_DEPEND(kr, miibus, 1, 1, 1);
+
+#include "miibus_if.h"
+
+#include <mips/mips32/idt/if_krreg.h>
+
+#define KR_DEBUG
+
+static int kr_attach(device_t);
+static int kr_detach(device_t);
+static int kr_ifmedia_upd(struct ifnet *);
+static void kr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int kr_ioctl(struct ifnet *, u_long, caddr_t);
+static void kr_init(void *);
+static void kr_init_locked(struct kr_softc *);
+static void kr_link_task(void *, int);
+static int kr_miibus_readreg(device_t, int, int);
+static void kr_miibus_statchg(device_t);
+static int kr_miibus_writereg(device_t, int, int, int);
+static int kr_probe(device_t);
+static void kr_reset(struct kr_softc *);
+static int kr_resume(device_t);
+static int kr_rx_ring_init(struct kr_softc *);
+static int kr_tx_ring_init(struct kr_softc *);
+static void kr_shutdown(device_t);
+static void kr_start(struct ifnet *);
+static void kr_start_locked(struct ifnet *);
+static void kr_stop(struct kr_softc *);
+static int kr_suspend(device_t);
+
+static void kr_rx(struct kr_softc *);
+static void kr_tx(struct kr_softc *);
+static void kr_rx_intr(void *);
+static void kr_tx_intr(void *);
+static void kr_rx_und_intr(void *);
+static void kr_tx_ovr_intr(void *);
+static void kr_tick(void *);
+
+static void kr_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int kr_dma_alloc(struct kr_softc *);
+static void kr_dma_free(struct kr_softc *);
+static int kr_newbuf(struct kr_softc *, int);
+static __inline void kr_fixup_rx(struct mbuf *);
+
+static device_method_t kr_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, kr_probe),
+ DEVMETHOD(device_attach, kr_attach),
+ DEVMETHOD(device_detach, kr_detach),
+ DEVMETHOD(device_suspend, kr_suspend),
+ DEVMETHOD(device_resume, kr_resume),
+ DEVMETHOD(device_shutdown, kr_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, kr_miibus_readreg),
+ DEVMETHOD(miibus_writereg, kr_miibus_writereg),
+ DEVMETHOD(miibus_statchg, kr_miibus_statchg),
+
+ { 0, 0 }
+};
+
+static driver_t kr_driver = {
+ "kr",
+ kr_methods,
+ sizeof(struct kr_softc)
+};
+
+static devclass_t kr_devclass;
+
+DRIVER_MODULE(kr, obio, kr_driver, kr_devclass, 0, 0);
+DRIVER_MODULE(kr, cardbus, kr_driver, kr_devclass, 0, 0);
+DRIVER_MODULE(miibus, kr, miibus_driver, miibus_devclass, 0, 0);
+
+static int
+kr_probe(device_t dev)
+{
+
+ device_set_desc(dev, "RC32434 Ethernet interface");
+ return (0);
+}
+
+static int
+kr_attach(device_t dev)
+{
+ uint8_t eaddr[ETHER_ADDR_LEN];
+ struct ifnet *ifp;
+ struct kr_softc *sc;
+ int error = 0, rid;
+ int unit;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+ sc->kr_dev = dev;
+
+ mtx_init(&sc->kr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF);
+ callout_init_mtx(&sc->kr_stat_callout, &sc->kr_mtx, 0);
+ TASK_INIT(&sc->kr_link_task, 0, kr_link_task, sc);
+ pci_enable_busmaster(dev);
+
+ /* Map control/status registers. */
+ sc->kr_rid = 0;
+ sc->kr_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->kr_rid,
+ RF_ACTIVE);
+
+ if (sc->kr_res == NULL) {
+ device_printf(dev, "couldn't map memory\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ sc->kr_btag = rman_get_bustag(sc->kr_res);
+ sc->kr_bhandle = rman_get_bushandle(sc->kr_res);
+
+ /* Allocate interrupts */
+ rid = 0;
+ sc->kr_rx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_RX_IRQ,
+ KR_RX_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->kr_rx_irq == NULL) {
+ device_printf(dev, "couldn't map rx interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = 0;
+ sc->kr_tx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_TX_IRQ,
+ KR_TX_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->kr_tx_irq == NULL) {
+ device_printf(dev, "couldn't map tx interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = 0;
+ sc->kr_rx_und_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ KR_RX_UND_IRQ, KR_RX_UND_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->kr_rx_und_irq == NULL) {
+ device_printf(dev, "couldn't map rx underrun interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ rid = 0;
+ sc->kr_tx_ovr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ KR_TX_OVR_IRQ, KR_TX_OVR_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
+
+ if (sc->kr_tx_ovr_irq == NULL) {
+ device_printf(dev, "couldn't map tx overrun interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Allocate ifnet structure. */
+ ifp = sc->kr_ifp = if_alloc(IFT_ETHER);
+
+ if (ifp == NULL) {
+ device_printf(dev, "couldn't allocate ifnet structure\n");
+ error = ENOSPC;
+ goto fail;
+ }
+ ifp->if_softc = sc;
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = kr_ioctl;
+ ifp->if_start = kr_start;
+ ifp->if_init = kr_init;
+
+ /* XXX: add real size */
+ IFQ_SET_MAXLEN(&ifp->if_snd, 9);
+ ifp->if_snd.ifq_maxlen = 9;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ ifp->if_capenable = ifp->if_capabilities;
+
+ eaddr[0] = 0x00;
+ eaddr[1] = 0x0C;
+ eaddr[2] = 0x42;
+ eaddr[3] = 0x09;
+ eaddr[4] = 0x5E;
+ eaddr[5] = 0x6B;
+
+ if (kr_dma_alloc(sc) != 0) {
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* TODO: calculate prescale */
+ CSR_WRITE_4(sc, KR_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
+
+ CSR_WRITE_4(sc, KR_MIIMCFG, KR_MIIMCFG_R);
+ DELAY(1000);
+ CSR_WRITE_4(sc, KR_MIIMCFG, 0);
+
+ /* Do MII setup. */
+ if (mii_phy_probe(dev, &sc->kr_miibus,
+ kr_ifmedia_upd, kr_ifmedia_sts)) {
+ device_printf(dev, "MII without any phy!\n");
+ error = ENXIO;
+ goto fail;
+ }
+
+ /* Call MI attach routine. */
+ ether_ifattach(ifp, eaddr);
+
+ /* Hook interrupt last to avoid having to lock softc */
+ error = bus_setup_intr(dev, sc->kr_rx_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, kr_rx_intr, sc, &sc->kr_rx_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up rx irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->kr_tx_irq, INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, kr_tx_intr, sc, &sc->kr_tx_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up tx irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->kr_rx_und_irq,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_rx_und_intr, sc,
+ &sc->kr_rx_und_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up rx underrun irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+ error = bus_setup_intr(dev, sc->kr_tx_ovr_irq,
+ INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_tx_ovr_intr, sc,
+ &sc->kr_tx_ovr_intrhand);
+
+ if (error) {
+ device_printf(dev, "couldn't set up tx overrun irq\n");
+ ether_ifdetach(ifp);
+ goto fail;
+ }
+
+fail:
+ if (error)
+ kr_detach(dev);
+
+ return (error);
+}
+
+static int
+kr_detach(device_t dev)
+{
+ struct kr_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->kr_ifp;
+
+ KASSERT(mtx_initialized(&sc->kr_mtx), ("vr mutex not initialized"));
+
+ /* These should only be active if attach succeeded */
+ if (device_is_attached(dev)) {
+ KR_LOCK(sc);
+ sc->kr_detach = 1;
+ kr_stop(sc);
+ KR_UNLOCK(sc);
+ taskqueue_drain(taskqueue_swi, &sc->kr_link_task);
+ ether_ifdetach(ifp);
+ }
+ if (sc->kr_miibus)
+ device_delete_child(dev, sc->kr_miibus);
+ bus_generic_detach(dev);
+
+ if (sc->kr_rx_intrhand)
+ bus_teardown_intr(dev, sc->kr_rx_irq, sc->kr_rx_intrhand);
+ if (sc->kr_rx_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_rx_irq);
+ if (sc->kr_tx_intrhand)
+ bus_teardown_intr(dev, sc->kr_tx_irq, sc->kr_tx_intrhand);
+ if (sc->kr_tx_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_tx_irq);
+ if (sc->kr_rx_und_intrhand)
+ bus_teardown_intr(dev, sc->kr_rx_und_irq,
+ sc->kr_rx_und_intrhand);
+ if (sc->kr_rx_und_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_rx_und_irq);
+ if (sc->kr_tx_ovr_intrhand)
+ bus_teardown_intr(dev, sc->kr_tx_ovr_irq,
+ sc->kr_tx_ovr_intrhand);
+ if (sc->kr_tx_ovr_irq)
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_tx_ovr_irq);
+
+ if (sc->kr_res)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->kr_rid,
+ sc->kr_res);
+
+ if (ifp)
+ if_free(ifp);
+
+ kr_dma_free(sc);
+
+ mtx_destroy(&sc->kr_mtx);
+
+ return (0);
+
+}
+
+static int
+kr_suspend(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static int
+kr_resume(device_t dev)
+{
+
+ panic("%s", __func__);
+ return 0;
+}
+
+static void
+kr_shutdown(device_t dev)
+{
+ struct kr_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ KR_LOCK(sc);
+ kr_stop(sc);
+ KR_UNLOCK(sc);
+}
+
+static int
+kr_miibus_readreg(device_t dev, int phy, int reg)
+{
+ struct kr_softc * sc = device_get_softc(dev);
+ int i, result;
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ CSR_WRITE_4(sc, KR_MIIMADDR, (phy << 8) | reg);
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ CSR_WRITE_4(sc, KR_MIIMCMD, KR_MIIMCMD_RD);
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii read is timed out %d:%d\n", phy,
+ reg);
+
+ if (CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_NV)
+ printf("phy mii readreg failed %d:%d: data not valid\n",
+ phy, reg);
+
+ result = CSR_READ_4(sc , KR_MIIMRDD);
+ CSR_WRITE_4(sc, KR_MIIMCMD, 0);
+
+ return (result);
+}
+
+static int
+kr_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+ struct kr_softc * sc = device_get_softc(dev);
+ int i;
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ CSR_WRITE_4(sc, KR_MIIMADDR, (phy << 8) | reg);
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ CSR_WRITE_4(sc, KR_MIIMWTD, data);
+
+ i = KR_MII_TIMEOUT;
+ while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
+ i--;
+
+ if (i == 0)
+ device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
+
+ return (0);
+}
+
+static void
+kr_miibus_statchg(device_t dev)
+{
+ struct kr_softc *sc;
+
+ sc = device_get_softc(dev);
+ taskqueue_enqueue(taskqueue_swi, &sc->kr_link_task);
+}
+
+static void
+kr_link_task(void *arg, int pending)
+{
+ struct kr_softc *sc;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ /* int lfdx, mfdx; */
+
+ sc = (struct kr_softc *)arg;
+
+ KR_LOCK(sc);
+ mii = device_get_softc(sc->kr_miibus);
+ ifp = sc->kr_ifp;
+ if (mii == NULL || ifp == NULL ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ KR_UNLOCK(sc);
+ return;
+ }
+
+ if (mii->mii_media_status & IFM_ACTIVE) {
+ if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
+ sc->kr_link_status = 1;
+ } else
+ sc->kr_link_status = 0;
+
+ KR_UNLOCK(sc);
+}
+
+static void
+kr_reset(struct kr_softc *sc)
+{
+ int i;
+
+ CSR_WRITE_4(sc, KR_ETHINTFC, 0);
+
+ for (i = 0; i < KR_TIMEOUT; i++) {
+ DELAY(10);
+ if (!(CSR_READ_4(sc, KR_ETHINTFC) & ETH_INTFC_RIP))
+ break;
+ }
+
+ if (i == KR_TIMEOUT)
+ device_printf(sc->kr_dev, "reset time out\n");
+}
+
+static void
+kr_init(void *xsc)
+{
+ struct kr_softc *sc = xsc;
+
+ KR_LOCK(sc);
+ kr_init_locked(sc);
+ KR_UNLOCK(sc);
+}
+
+static void
+kr_init_locked(struct kr_softc *sc)
+{
+ struct ifnet *ifp = sc->kr_ifp;
+ struct mii_data *mii;
+
+ KR_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->kr_miibus);
+
+ kr_stop(sc);
+ kr_reset(sc);
+
+ CSR_WRITE_4(sc, KR_ETHINTFC, ETH_INTFC_EN);
+
+ /* Init circular RX list. */
+ if (kr_rx_ring_init(sc) != 0) {
+ device_printf(sc->kr_dev,
+ "initialization failed: no memory for rx buffers\n");
+ kr_stop(sc);
+ return;
+ }
+
+ /* Init tx descriptors. */
+ kr_tx_ring_init(sc);
+
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, 0);
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_NDPTR, 0);
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR,
+ sc->kr_rdata.kr_rx_ring_paddr);
+
+
+ KR_DMA_CLEARBITS_REG(KR_DMA_RXCHAN, DMA_SM,
+ DMA_SM_H | DMA_SM_E | DMA_SM_D) ;
+
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, 0);
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, 0);
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_DPTR, 0);
+ KR_DMA_CLEARBITS_REG(KR_DMA_TXCHAN, DMA_SM,
+ DMA_SM_F | DMA_SM_E);
+
+
+ /* Accept only packets destined for THIS Ethernet device address */
+ CSR_WRITE_4(sc, KR_ETHARC, 1);
+
+ /*
+ * Set all Ethernet address registers to the same initial values
+ * set all four addresses to 66-88-aa-cc-dd-ee
+ */
+ CSR_WRITE_4(sc, KR_ETHSAL0, 0x42095E6B);
+ CSR_WRITE_4(sc, KR_ETHSAH0, 0x0000000C);
+
+ CSR_WRITE_4(sc, KR_ETHSAL1, 0x42095E6B);
+ CSR_WRITE_4(sc, KR_ETHSAH1, 0x0000000C);
+
+ CSR_WRITE_4(sc, KR_ETHSAL2, 0x42095E6B);
+ CSR_WRITE_4(sc, KR_ETHSAH2, 0x0000000C);
+
+ CSR_WRITE_4(sc, KR_ETHSAL3, 0x42095E6B);
+ CSR_WRITE_4(sc, KR_ETHSAH3, 0x0000000C);
+
+ CSR_WRITE_4(sc, KR_ETHMAC2,
+ KR_ETH_MAC2_PEN | KR_ETH_MAC2_CEN | KR_ETH_MAC2_FD);
+
+ CSR_WRITE_4(sc, KR_ETHIPGT, KR_ETHIPGT_FULL_DUPLEX);
+ CSR_WRITE_4(sc, KR_ETHIPGR, 0x12); /* minimum value */
+
+ CSR_WRITE_4(sc, KR_MIIMCFG, KR_MIIMCFG_R);
+ DELAY(1000);
+ CSR_WRITE_4(sc, KR_MIIMCFG, 0);
+
+ /* TODO: calculate prescale */
+ CSR_WRITE_4(sc, KR_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
+
+ /* FIFO Tx threshold level */
+ CSR_WRITE_4(sc, KR_ETHFIFOTT, 0x30);
+
+ CSR_WRITE_4(sc, KR_ETHMAC1, KR_ETH_MAC1_RE);
+
+ sc->kr_link_status = 0;
+ mii_mediachg(mii);
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ callout_reset(&sc->kr_stat_callout, hz, kr_tick, sc);
+}
+
+static void
+kr_start(struct ifnet *ifp)
+{
+ struct kr_softc *sc;
+
+ sc = ifp->if_softc;
+
+ KR_LOCK(sc);
+ kr_start_locked(ifp);
+ KR_UNLOCK(sc);
+}
+
+/*
+ * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
+ * pointers to the fragment pointers.
+ */
+static int
+kr_encap(struct kr_softc *sc, struct mbuf **m_head)
+{
+ struct kr_txdesc *txd;
+ struct kr_desc *desc, *prev_desc;
+ bus_dma_segment_t txsegs[KR_MAXFRAGS];
+ uint32_t link_addr;
+ int error, i, nsegs, prod, si, prev_prod;
+
+ KR_LOCK_ASSERT(sc);
+
+ prod = sc->kr_cdata.kr_tx_prod;
+ txd = &sc->kr_cdata.kr_txdesc[prod];
+ error = bus_dmamap_load_mbuf_sg(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
+ *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ panic("EFBIG");
+ } else if (error != 0)
+ return (error);
+ if (nsegs == 0) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (EIO);
+ }
+
+ /* Check number of available descriptors. */
+ if (sc->kr_cdata.kr_tx_cnt + nsegs >= (KR_TX_RING_CNT - 1)) {
+ bus_dmamap_unload(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap);
+ return (ENOBUFS);
+ }
+
+ txd->tx_m = *m_head;
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+ si = prod;
+
+ /*
+ * Make a list of descriptors for this packet. DMA controller will
+ * walk through it while kr_link is not zero. The last one should
+ * have COF flag set, to pickup next chain from NDPTR
+ */
+ prev_prod = prod;
+ desc = prev_desc = NULL;
+ for (i = 0; i < nsegs; i++) {
+ desc = &sc->kr_rdata.kr_tx_ring[prod];
+ desc->kr_ctl = KR_DMASIZE(txsegs[i].ds_len) | KR_CTL_IOF;
+ if (i == 0)
+ desc->kr_devcs = KR_DMATX_DEVCS_FD;
+ desc->kr_ca = txsegs[i].ds_addr;
+ desc->kr_link = 0;
+ /* link with previous descriptor */
+ if (prev_desc)
+ prev_desc->kr_link = KR_TX_RING_ADDR(sc, prod);
+
+ sc->kr_cdata.kr_tx_cnt++;
+ prev_desc = desc;
+ KR_INC(prod, KR_TX_RING_CNT);
+ }
+
+ /*
+ * Set COF for last descriptor and mark last fragment with LD flag
+ */
+ if (desc) {
+ desc->kr_ctl |= KR_CTL_COF;
+ desc->kr_devcs |= KR_DMATX_DEVCS_LD;
+ }
+
+ /* Update producer index. */
+ sc->kr_cdata.kr_tx_prod = prod;
+
+ /* Sync descriptors. */
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Start transmitting */
+ /* Check if new list is queued in NDPTR */
+ if (KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_NDPTR) == 0) {
+ /* NDPTR is not busy - start new list */
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR,
+ KR_TX_RING_ADDR(sc, si));
+ }
+ else {
+ link_addr = KR_TX_RING_ADDR(sc, si);
+ /* Get previous descriptor */
+ si = (si + KR_TX_RING_CNT - 1) % KR_TX_RING_CNT;
+ desc = &sc->kr_rdata.kr_tx_ring[si];
+ desc->kr_link = link_addr;
+ }
+
+ return (0);
+}
+
+static void
+kr_start_locked(struct ifnet *ifp)
+{
+ struct kr_softc *sc;
+ struct mbuf *m_head;
+ int enq;
+
+ sc = ifp->if_softc;
+
+ KR_LOCK_ASSERT(sc);
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING || sc->kr_link_status == 0 )
+ return;
+
+ for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
+ sc->kr_cdata.kr_tx_cnt < KR_TX_RING_CNT - 2; ) {
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+ /*
+ * Pack the data into the transmit ring. If we
+ * don't have room, set the OACTIVE flag and wait
+ * for the NIC to drain the ring.
+ */
+ if (kr_encap(sc, &m_head)) {
+ if (m_head == NULL)
+ break;
+ IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ break;
+ }
+
+ enq++;
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ ETHER_BPF_MTAP(ifp, m_head);
+ }
+}
+
+static void
+kr_stop(struct kr_softc *sc)
+{
+ struct ifnet *ifp;
+
+ KR_LOCK_ASSERT(sc);
+
+
+ ifp = sc->kr_ifp;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ callout_stop(&sc->kr_stat_callout);
+
+ /* mask out RX interrupts */
+ KR_DMA_SETBITS_REG(KR_DMA_RXCHAN, DMA_SM,
+ DMA_SM_D | DMA_SM_H | DMA_SM_E);
+
+ /* mask out TX interrupts */
+ KR_DMA_SETBITS_REG(KR_DMA_TXCHAN, DMA_SM,
+ DMA_SM_F | DMA_SM_E);
+
+ /* Abort RX DMA transactions */
+ if (KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_C) & DMA_C_R) {
+ /* Set ABORT bit if trunsuction is in progress */
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_C, DMA_C_ABORT);
+ /* XXX: Add timeout */
+ while ((KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S) & DMA_S_H) == 0)
+ DELAY(10);
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, 0);
+ }
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR, 0);
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_NDPTR, 0);
+
+ /* Abort TX DMA transactions */
+ if (KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_C) & DMA_C_R) {
+ /* Set ABORT bit if trunsuction is in progress */
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_C, DMA_C_ABORT);
+ /* XXX: Add timeout */
+ while ((KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_S) & DMA_S_H) == 0)
+ DELAY(10);
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, 0);
+ }
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_DPTR, 0);
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, 0);
+
+ CSR_WRITE_4(sc, KR_ETHINTFC, 0);
+}
+
+
+static int
+kr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct kr_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *) data;
+ struct mii_data *mii;
+ int error;
+
+ switch (command) {
+ case SIOCSIFFLAGS:
+#if 0
+ KR_LOCK(sc);
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ if ((ifp->if_flags ^ sc->kr_if_flags) &
+ (IFF_PROMISC | IFF_ALLMULTI))
+ kr_set_filter(sc);
+ } else {
+ if (sc->kr_detach == 0)
+ kr_init_locked(sc);
+ }
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ kr_stop(sc);
+ }
+ sc->kr_if_flags = ifp->if_flags;
+ KR_UNLOCK(sc);
+#endif
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+#if 0
+ KR_LOCK(sc);
+ kr_set_filter(sc);
+ KR_UNLOCK(sc);
+#endif
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = device_get_softc(sc->kr_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+ case SIOCSIFCAP:
+ error = 0;
+#if 0
+ mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+ if ((mask & IFCAP_HWCSUM) != 0) {
+ ifp->if_capenable ^= IFCAP_HWCSUM;
+ if ((IFCAP_HWCSUM & ifp->if_capenable) &&
+ (IFCAP_HWCSUM & ifp->if_capabilities))
+ ifp->if_hwassist = KR_CSUM_FEATURES;
+ else
+ ifp->if_hwassist = 0;
+ }
+ if ((mask & IFCAP_VLAN_HWTAGGING) != 0) {
+ ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
+ if (IFCAP_VLAN_HWTAGGING & ifp->if_capenable &&
+ IFCAP_VLAN_HWTAGGING & ifp->if_capabilities &&
+ ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ KR_LOCK(sc);
+ kr_vlan_setup(sc);
+ KR_UNLOCK(sc);
+ }
+ }
+ VLAN_CAPABILITIES(ifp);
+#endif
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ return (error);
+}
+
+/*
+ * Set media options.
+ */
+static int
+kr_ifmedia_upd(struct ifnet *ifp)
+{
+ struct kr_softc *sc;
+ struct mii_data *mii;
+ struct mii_softc *miisc;
+ int error;
+
+ sc = ifp->if_softc;
+ KR_LOCK(sc);
+ mii = device_get_softc(sc->kr_miibus);
+ if (mii->mii_instance) {
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ error = mii_mediachg(mii);
+ KR_UNLOCK(sc);
+
+ return (error);
+}
+
+/*
+ * Report current media status.
+ */
+static void
+kr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct kr_softc *sc = ifp->if_softc;
+ struct mii_data *mii;
+
+ mii = device_get_softc(sc->kr_miibus);
+ KR_LOCK(sc);
+ mii_pollstat(mii);
+ KR_UNLOCK(sc);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+}
+
+struct kr_dmamap_arg {
+ bus_addr_t kr_busaddr;
+};
+
+static void
+kr_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+ struct kr_dmamap_arg *ctx;
+
+ if (error != 0)
+ return;
+ ctx = arg;
+ ctx->kr_busaddr = segs[0].ds_addr;
+}
+
+static int
+kr_dma_alloc(struct kr_softc *sc)
+{
+ struct kr_dmamap_arg ctx;
+ struct kr_txdesc *txd;
+ struct kr_rxdesc *rxd;
+ int error, i;
+
+ /* Create parent DMA tag. */
+ error = bus_dma_tag_create(
+ bus_get_dma_tag(sc->kr_dev), /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
+ 0, /* nsegments */
+ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->kr_cdata.kr_parent_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create parent DMA tag\n");
+ goto fail;
+ }
+ /* Create tag for Tx ring. */
+ error = bus_dma_tag_create(
+ sc->kr_cdata.kr_parent_tag, /* parent */
+ KR_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ KR_TX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ KR_TX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->kr_cdata.kr_tx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create Tx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx ring. */
+ error = bus_dma_tag_create(
+ sc->kr_cdata.kr_parent_tag, /* parent */
+ KR_RING_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ KR_RX_RING_SIZE, /* maxsize */
+ 1, /* nsegments */
+ KR_RX_RING_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->kr_cdata.kr_rx_ring_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create Rx ring DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Tx buffers. */
+ error = bus_dma_tag_create(
+ sc->kr_cdata.kr_parent_tag, /* parent */
+ sizeof(uint32_t), 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES * KR_MAXFRAGS, /* maxsize */
+ KR_MAXFRAGS, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->kr_cdata.kr_tx_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create Tx DMA tag\n");
+ goto fail;
+ }
+
+ /* Create tag for Rx buffers. */
+ error = bus_dma_tag_create(
+ sc->kr_cdata.kr_parent_tag, /* parent */
+ KR_RX_ALIGN, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MCLBYTES, /* maxsize */
+ 1, /* nsegments */
+ MCLBYTES, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->kr_cdata.kr_rx_tag);
+ if (error != 0) {
+ device_printf(sc->kr_dev, "failed to create Rx DMA tag\n");
+ goto fail;
+ }
+
+ /* Allocate DMA'able memory and load the DMA map for Tx ring. */
+ error = bus_dmamem_alloc(sc->kr_cdata.kr_tx_ring_tag,
+ (void **)&sc->kr_rdata.kr_tx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->kr_cdata.kr_tx_ring_map);
+ if (error != 0) {
+ device_printf(sc->kr_dev,
+ "failed to allocate DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+
+ ctx.kr_busaddr = 0;
+ error = bus_dmamap_load(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map, sc->kr_rdata.kr_tx_ring,
+ KR_TX_RING_SIZE, kr_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.kr_busaddr == 0) {
+ device_printf(sc->kr_dev,
+ "failed to load DMA'able memory for Tx ring\n");
+ goto fail;
+ }
+ sc->kr_rdata.kr_tx_ring_paddr = ctx.kr_busaddr;
+
+ /* Allocate DMA'able memory and load the DMA map for Rx ring. */
+ error = bus_dmamem_alloc(sc->kr_cdata.kr_rx_ring_tag,
+ (void **)&sc->kr_rdata.kr_rx_ring, BUS_DMA_WAITOK |
+ BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->kr_cdata.kr_rx_ring_map);
+ if (error != 0) {
+ device_printf(sc->kr_dev,
+ "failed to allocate DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+
+ ctx.kr_busaddr = 0;
+ error = bus_dmamap_load(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map, sc->kr_rdata.kr_rx_ring,
+ KR_RX_RING_SIZE, kr_dmamap_cb, &ctx, 0);
+ if (error != 0 || ctx.kr_busaddr == 0) {
+ device_printf(sc->kr_dev,
+ "failed to load DMA'able memory for Rx ring\n");
+ goto fail;
+ }
+ sc->kr_rdata.kr_rx_ring_paddr = ctx.kr_busaddr;
+
+ /* Create DMA maps for Tx buffers. */
+ for (i = 0; i < KR_TX_RING_CNT; i++) {
+ txd = &sc->kr_cdata.kr_txdesc[i];
+ txd->tx_m = NULL;
+ txd->tx_dmamap = NULL;
+ error = bus_dmamap_create(sc->kr_cdata.kr_tx_tag, 0,
+ &txd->tx_dmamap);
+ if (error != 0) {
+ device_printf(sc->kr_dev,
+ "failed to create Tx dmamap\n");
+ goto fail;
+ }
+ }
+ /* Create DMA maps for Rx buffers. */
+ if ((error = bus_dmamap_create(sc->kr_cdata.kr_rx_tag, 0,
+ &sc->kr_cdata.kr_rx_sparemap)) != 0) {
+ device_printf(sc->kr_dev,
+ "failed to create spare Rx dmamap\n");
+ goto fail;
+ }
+ for (i = 0; i < KR_RX_RING_CNT; i++) {
+ rxd = &sc->kr_cdata.kr_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->rx_dmamap = NULL;
+ error = bus_dmamap_create(sc->kr_cdata.kr_rx_tag, 0,
+ &rxd->rx_dmamap);
+ if (error != 0) {
+ device_printf(sc->kr_dev,
+ "failed to create Rx dmamap\n");
+ goto fail;
+ }
+ }
+
+fail:
+ return (error);
+}
+
+static void
+kr_dma_free(struct kr_softc *sc)
+{
+ struct kr_txdesc *txd;
+ struct kr_rxdesc *rxd;
+ int i;
+
+ /* Tx ring. */
+ if (sc->kr_cdata.kr_tx_ring_tag) {
+ if (sc->kr_cdata.kr_tx_ring_map)
+ bus_dmamap_unload(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map);
+ if (sc->kr_cdata.kr_tx_ring_map &&
+ sc->kr_rdata.kr_tx_ring)
+ bus_dmamem_free(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_rdata.kr_tx_ring,
+ sc->kr_cdata.kr_tx_ring_map);
+ sc->kr_rdata.kr_tx_ring = NULL;
+ sc->kr_cdata.kr_tx_ring_map = NULL;
+ bus_dma_tag_destroy(sc->kr_cdata.kr_tx_ring_tag);
+ sc->kr_cdata.kr_tx_ring_tag = NULL;
+ }
+ /* Rx ring. */
+ if (sc->kr_cdata.kr_rx_ring_tag) {
+ if (sc->kr_cdata.kr_rx_ring_map)
+ bus_dmamap_unload(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map);
+ if (sc->kr_cdata.kr_rx_ring_map &&
+ sc->kr_rdata.kr_rx_ring)
+ bus_dmamem_free(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_rdata.kr_rx_ring,
+ sc->kr_cdata.kr_rx_ring_map);
+ sc->kr_rdata.kr_rx_ring = NULL;
+ sc->kr_cdata.kr_rx_ring_map = NULL;
+ bus_dma_tag_destroy(sc->kr_cdata.kr_rx_ring_tag);
+ sc->kr_cdata.kr_rx_ring_tag = NULL;
+ }
+ /* Tx buffers. */
+ if (sc->kr_cdata.kr_tx_tag) {
+ for (i = 0; i < KR_TX_RING_CNT; i++) {
+ txd = &sc->kr_cdata.kr_txdesc[i];
+ if (txd->tx_dmamap) {
+ bus_dmamap_destroy(sc->kr_cdata.kr_tx_tag,
+ txd->tx_dmamap);
+ txd->tx_dmamap = NULL;
+ }
+ }
+ bus_dma_tag_destroy(sc->kr_cdata.kr_tx_tag);
+ sc->kr_cdata.kr_tx_tag = NULL;
+ }
+ /* Rx buffers. */
+ if (sc->kr_cdata.kr_rx_tag) {
+ for (i = 0; i < KR_RX_RING_CNT; i++) {
+ rxd = &sc->kr_cdata.kr_rxdesc[i];
+ if (rxd->rx_dmamap) {
+ bus_dmamap_destroy(sc->kr_cdata.kr_rx_tag,
+ rxd->rx_dmamap);
+ rxd->rx_dmamap = NULL;
+ }
+ }
+ if (sc->kr_cdata.kr_rx_sparemap) {
+ bus_dmamap_destroy(sc->kr_cdata.kr_rx_tag,
+ sc->kr_cdata.kr_rx_sparemap);
+ sc->kr_cdata.kr_rx_sparemap = 0;
+ }
+ bus_dma_tag_destroy(sc->kr_cdata.kr_rx_tag);
+ sc->kr_cdata.kr_rx_tag = NULL;
+ }
+
+ if (sc->kr_cdata.kr_parent_tag) {
+ bus_dma_tag_destroy(sc->kr_cdata.kr_parent_tag);
+ sc->kr_cdata.kr_parent_tag = NULL;
+ }
+}
+
+/*
+ * Initialize the transmit descriptors.
+ */
+static int
+kr_tx_ring_init(struct kr_softc *sc)
+{
+ struct kr_ring_data *rd;
+ struct kr_txdesc *txd;
+ bus_addr_t addr;
+ int i;
+
+ sc->kr_cdata.kr_tx_prod = 0;
+ sc->kr_cdata.kr_tx_cons = 0;
+ sc->kr_cdata.kr_tx_cnt = 0;
+ sc->kr_cdata.kr_tx_pkts = 0;
+
+ rd = &sc->kr_rdata;
+ bzero(rd->kr_tx_ring, KR_TX_RING_SIZE);
+ for (i = 0; i < KR_TX_RING_CNT; i++) {
+ if (i == KR_TX_RING_CNT - 1)
+ addr = KR_TX_RING_ADDR(sc, 0);
+ else
+ addr = KR_TX_RING_ADDR(sc, i + 1);
+ rd->kr_tx_ring[i].kr_ctl = KR_CTL_IOF;
+ rd->kr_tx_ring[i].kr_ca = 0;
+ rd->kr_tx_ring[i].kr_devcs = 0;
+ rd->kr_tx_ring[i].kr_link = 0;
+ txd = &sc->kr_cdata.kr_txdesc[i];
+ txd->tx_m = NULL;
+ }
+
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize the RX descriptors and allocate mbufs for them. Note that
+ * we arrange the descriptors in a closed ring, so that the last descriptor
+ * points back to the first.
+ */
+static int
+kr_rx_ring_init(struct kr_softc *sc)
+{
+ struct kr_ring_data *rd;
+ struct kr_rxdesc *rxd;
+ bus_addr_t addr;
+ int i;
+
+ sc->kr_cdata.kr_rx_cons = 0;
+
+ rd = &sc->kr_rdata;
+ bzero(rd->kr_rx_ring, KR_RX_RING_SIZE);
+ for (i = 0; i < KR_RX_RING_CNT; i++) {
+ rxd = &sc->kr_cdata.kr_rxdesc[i];
+ rxd->rx_m = NULL;
+ rxd->desc = &rd->kr_rx_ring[i];
+ if (i == KR_RX_RING_CNT - 1)
+ addr = KR_RX_RING_ADDR(sc, 0);
+ else
+ addr = KR_RX_RING_ADDR(sc, i + 1);
+ rd->kr_rx_ring[i].kr_ctl = KR_CTL_IOD;
+ if (i == KR_RX_RING_CNT - 1)
+ rd->kr_rx_ring[i].kr_ctl |= KR_CTL_COD;
+ rd->kr_rx_ring[i].kr_devcs = 0;
+ rd->kr_rx_ring[i].kr_ca = 0;
+ rd->kr_rx_ring[i].kr_link = addr;
+ if (kr_newbuf(sc, i) != 0)
+ return (ENOBUFS);
+ }
+
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ return (0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+static int
+kr_newbuf(struct kr_softc *sc, int idx)
+{
+ struct kr_desc *desc;
+ struct kr_rxdesc *rxd;
+ struct mbuf *m;
+ bus_dma_segment_t segs[1];
+ bus_dmamap_t map;
+ int nsegs;
+
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL)
+ return (ENOBUFS);
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+ m_adj(m, sizeof(uint64_t));
+
+ if (bus_dmamap_load_mbuf_sg(sc->kr_cdata.kr_rx_tag,
+ sc->kr_cdata.kr_rx_sparemap, m, segs, &nsegs, 0) != 0) {
+ m_freem(m);
+ return (ENOBUFS);
+ }
+ KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
+
+ rxd = &sc->kr_cdata.kr_rxdesc[idx];
+ if (rxd->rx_m != NULL) {
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap);
+ }
+ map = rxd->rx_dmamap;
+ rxd->rx_dmamap = sc->kr_cdata.kr_rx_sparemap;
+ sc->kr_cdata.kr_rx_sparemap = map;
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ rxd->rx_m = m;
+ desc = rxd->desc;
+ desc->kr_ca = segs[0].ds_addr;
+ desc->kr_ctl |= KR_DMASIZE(segs[0].ds_len);
+ rxd->saved_ca = desc->kr_ca ;
+ rxd->saved_ctl = desc->kr_ctl ;
+
+ return (0);
+}
+
+static __inline void
+kr_fixup_rx(struct mbuf *m)
+{
+ int i;
+ uint16_t *src, *dst;
+
+ src = mtod(m, uint16_t *);
+ dst = src - 1;
+
+ for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
+ *dst++ = *src++;
+
+ m->m_data -= ETHER_ALIGN;
+}
+
+
+static void
+kr_tx(struct kr_softc *sc)
+{
+ struct kr_txdesc *txd;
+ struct kr_desc *cur_tx;
+ struct ifnet *ifp;
+ uint32_t ctl, devcs;
+ int cons, prod;
+
+ KR_LOCK_ASSERT(sc);
+
+ cons = sc->kr_cdata.kr_tx_cons;
+ prod = sc->kr_cdata.kr_tx_prod;
+ if (cons == prod)
+ return;
+
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ ifp = sc->kr_ifp;
+ /*
+ * Go through our tx list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ for (; cons != prod; KR_INC(cons, KR_TX_RING_CNT)) {
+ cur_tx = &sc->kr_rdata.kr_tx_ring[cons];
+ ctl = cur_tx->kr_ctl;
+ devcs = cur_tx->kr_devcs;
+ /* Check if descriptor has "finished" flag */
+ if ((ctl & KR_CTL_F) == 0)
+ break;
+
+ sc->kr_cdata.kr_tx_cnt--;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ txd = &sc->kr_cdata.kr_txdesc[cons];
+
+ if (devcs & KR_DMATX_DEVCS_TOK)
+ ifp->if_opackets++;
+ else {
+ ifp->if_oerrors++;
+ /* collisions: medium busy, late collision */
+ if ((devcs & KR_DMATX_DEVCS_EC) ||
+ (devcs & KR_DMATX_DEVCS_LC))
+ ifp->if_collisions++;
+ }
+
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap);
+
+ /* Free only if it's first descriptor in list */
+ if (txd->tx_m)
+ m_freem(txd->tx_m);
+ txd->tx_m = NULL;
+
+ /* reset descriptor */
+ cur_tx->kr_ctl = KR_CTL_IOF;
+ cur_tx->kr_devcs = 0;
+ cur_tx->kr_ca = 0;
+ cur_tx->kr_link = 0;
+ }
+
+ sc->kr_cdata.kr_tx_cons = cons;
+
+ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
+ sc->kr_cdata.kr_tx_ring_map, BUS_DMASYNC_PREWRITE);
+}
+
+
+static void
+kr_rx(struct kr_softc *sc)
+{
+ struct kr_rxdesc *rxd;
+ struct ifnet *ifp = sc->kr_ifp;
+ int cons, prog, packet_len, count, error;
+ struct kr_desc *cur_rx;
+ struct mbuf *m;
+
+ KR_LOCK_ASSERT(sc);
+
+ cons = sc->kr_cdata.kr_rx_cons;
+
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ for (prog = 0; prog < KR_RX_RING_CNT; KR_INC(cons, KR_RX_RING_CNT)) {
+ cur_rx = &sc->kr_rdata.kr_rx_ring[cons];
+ rxd = &sc->kr_cdata.kr_rxdesc[cons];
+ m = rxd->rx_m;
+
+ if ((cur_rx->kr_ctl & KR_CTL_D) == 0)
+ break;
+
+ prog++;
+
+ packet_len = KR_PKTSIZE(cur_rx->kr_devcs);
+ count = m->m_len - KR_DMASIZE(cur_rx->kr_ctl);
+ /* Assume it's error */
+ error = 1;
+
+ if (packet_len != count)
+ ifp->if_ierrors++;
+ else if (count < 64)
+ ifp->if_ierrors++;
+ else if ((cur_rx->kr_devcs & KR_DMARX_DEVCS_LD) == 0)
+ ifp->if_ierrors++;
+ else if ((cur_rx->kr_devcs & KR_DMARX_DEVCS_ROK) != 0) {
+ error = 0;
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
+ BUS_DMASYNC_PREREAD);
+ m = rxd->rx_m;
+ kr_fixup_rx(m);
+ m->m_pkthdr.rcvif = ifp;
+ /* Skip 4 bytes of CRC */
+ m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
+ ifp->if_ipackets++;
+
+ KR_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ KR_LOCK(sc);
+ }
+
+ if (error) {
+ /* Restore CONTROL and CA values, reset DEVCS */
+ cur_rx->kr_ctl = rxd->saved_ctl;
+ cur_rx->kr_ca = rxd->saved_ca;
+ cur_rx->kr_devcs = 0;
+ }
+ else {
+ /* Reinit descriptor */
+ cur_rx->kr_ctl = KR_CTL_IOD;
+ if (cons == KR_RX_RING_CNT - 1)
+ cur_rx->kr_ctl |= KR_CTL_COD;
+ cur_rx->kr_devcs = 0;
+ cur_rx->kr_ca = 0;
+ if (kr_newbuf(sc, cons) != 0) {
+ device_printf(sc->kr_dev,
+ "Failed to allocate buffer\n");
+ break;
+ }
+ }
+
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ }
+
+ if (prog > 0) {
+ sc->kr_cdata.kr_rx_cons = cons;
+
+ bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
+ sc->kr_cdata.kr_rx_ring_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ }
+}
+
+static void
+kr_rx_intr(void *arg)
+{
+ struct kr_softc *sc = arg;
+ uint32_t status;
+
+ KR_LOCK(sc);
+
+ /* mask out interrupts */
+ KR_DMA_SETBITS_REG(KR_DMA_RXCHAN, DMA_SM,
+ DMA_SM_D | DMA_SM_H | DMA_SM_E);
+
+ status = KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S);
+ if (status & (DMA_S_D | DMA_S_E | DMA_S_H)) {
+ kr_rx(sc);
+
+ if (status & DMA_S_E)
+ device_printf(sc->kr_dev, "RX DMA error\n");
+ }
+
+ /* Reread status */
+ status = KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S);
+
+ /* restart DMA RX if it has been halted */
+ if (status & DMA_S_H) {
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR,
+ KR_RX_RING_ADDR(sc, sc->kr_cdata.kr_rx_cons));
+ }
+
+ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, ~status);
+
+ /* Enable F, H, E interrupts */
+ KR_DMA_CLEARBITS_REG(KR_DMA_RXCHAN, DMA_SM,
+ DMA_SM_D | DMA_SM_H | DMA_SM_E);
+
+ KR_UNLOCK(sc);
+}
+
+static void
+kr_tx_intr(void *arg)
+{
+ struct kr_softc *sc = arg;
+ uint32_t status;
+
+ KR_LOCK(sc);
+
+ /* mask out interrupts */
+ KR_DMA_SETBITS_REG(KR_DMA_TXCHAN, DMA_SM,
+ DMA_SM_F | DMA_SM_E);
+
+ status = KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_S);
+ if (status & (DMA_S_F | DMA_S_E)) {
+ kr_tx(sc);
+ if (status & DMA_S_E)
+ device_printf(sc->kr_dev, "DMA error\n");
+ }
+
+ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, ~status);
+
+ /* Enable F, E interrupts */
+ KR_DMA_CLEARBITS_REG(KR_DMA_TXCHAN, DMA_SM,
+ DMA_SM_F | DMA_SM_E);
+
+ KR_UNLOCK(sc);
+
+}
+
+static void
+kr_rx_und_intr(void *arg)
+{
+
+ panic("interrupt: %s\n", __func__);
+}
+
+static void
+kr_tx_ovr_intr(void *arg)
+{
+
+ panic("interrupt: %s\n", __func__);
+}
+
+static void
+kr_tick(void *xsc)
+{
+ struct kr_softc *sc = xsc;
+ struct mii_data *mii;
+
+ KR_LOCK_ASSERT(sc);
+
+ mii = device_get_softc(sc->kr_miibus);
+ mii_tick(mii);
+ callout_reset(&sc->kr_stat_callout, hz, kr_tick, sc);
+}
diff --git a/sys/mips/mips32/idt/if_krreg.h b/sys/mips/mips32/idt/if_krreg.h
new file mode 100644
index 0000000..b20900a
--- /dev/null
+++ b/sys/mips/mips32/idt/if_krreg.h
@@ -0,0 +1,284 @@
+/*-
+ * Copyright (C) 2007
+ * Oleksandr Tymoshenko <gonzo@freebsd.org>. 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 OR HIS RELATIVES 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 MIND, 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 __IF_KRREG_H__
+#define __IF_KRREG_H__
+
+#define KR_ETHINTFC 0x0000 /* Ethernet interface control */
+#define ETH_INTFC_EN 0x0001
+#define ETH_INTFC_RIP 0x0004
+#define ETH_INTFC_EN 0x0001
+#define KR_ETHFIFOTT 0x0004 /* Ethernet FIFO transmit threshold */
+#define KR_ETHARC 0x0008 /* Ethernet address recognition control */
+#define KR_ETHHASH0 0x000C /* Ethernet hash table 0 */
+#define KR_ETHHASH1 0x0010 /* Ethernet hash table 1 */
+#define KR_ETHPFS 0x0024 /* Ethernet pause frame status */
+#define KR_ETHMCP 0x0028 /* Ethernet management clock prescalar */
+#define KR_ETHSAL0 0x0100 /* Ethernet station address 0 low */
+#define KR_ETHSAH0 0x0104 /* Ethernet station address 0 high */
+#define KR_ETHSAL1 0x0108 /* Ethernet station address 1 low */
+#define KR_ETHSAH1 0x010C /* Ethernet station address 1 high */
+#define KR_ETHSAL2 0x0110 /* Ethernet station address 2 low */
+#define KR_ETHSAH2 0x0114 /* Ethernet station address 2 high */
+#define KR_ETHSAL3 0x0118 /* Ethernet station address 3 low */
+#define KR_ETHSAH3 0x011C /* Ethernet station address 3 high */
+#define KR_ETHRBC 0x0120 /* Ethernet receive byte count */
+#define KR_ETHRPC 0x0124 /* Ethernet receive packet count */
+#define KR_ETHRUPC 0x0128 /* Ethernet receive undersized packet cnt */
+#define KR_ETHRFC 0x012C /* Ethernet receive fragment count */
+#define KR_ETHTBC 0x0130 /* Ethernet transmit byte count */
+#define KR_ETHGPF 0x0134 /* Ethernet generate pause frame */
+#define KR_ETHMAC1 0x0200 /* Ethernet MAC configuration 1 */
+#define KR_ETH_MAC1_RE 0x01
+#define KR_ETH_MAC1_PAF 0x02
+#define KR_ETH_MAC1_MR 0x80
+#define KR_ETHMAC2 0x0204 /* Ethernet MAC configuration 2 */
+#define KR_ETH_MAC2_FD 0x01
+#define KR_ETH_MAC2_FLC 0x02
+#define KR_ETH_MAC2_HFE 0x04
+#define KR_ETH_MAC2_DC 0x08
+#define KR_ETH_MAC2_CEN 0x10
+#define KR_ETH_MAC2_PEN 0x20
+#define KR_ETH_MAC2_VPE 0x08
+#define KR_ETHIPGT 0x0208 /* Ethernet back-to-back inter-packet gap */
+#define KR_ETHIPGR 0x020C /* Ethernet non back-to-back inter-packet gap */
+#define KR_ETHCLRT 0x0210 /* Ethernet collision window retry */
+#define KR_ETHMAXF 0x0214 /* Ethernet maximum frame length */
+#define KR_ETHMTEST 0x021C /* Ethernet MAC test */
+#define KR_MIIMCFG 0x0220 /* MII management configuration */
+#define KR_MIIMCFG_R 0x8000
+#define KR_MIIMCMD 0x0224 /* MII management command */
+#define KR_MIIMCMD_RD 0x01
+#define KR_MIIMCMD_SCN 0x02
+#define KR_MIIMADDR 0x0228 /* MII management address */
+#define KR_MIIMWTD 0x022C /* MII management write data */
+#define KR_MIIMRDD 0x0230 /* MII management read data */
+#define KR_MIIMIND 0x0234 /* MII management indicators */
+#define KR_MIIMIND_BSY 0x1
+#define KR_MIIMIND_SCN 0x2
+#define KR_MIIMIND_NV 0x4
+#define KR_ETHCFSA0 0x0240 /* Ethernet control frame station address 0 */
+#define KR_ETHCFSA1 0x0244 /* Ethernet control frame station address 1 */
+#define KR_ETHCFSA2 0x0248 /* Ethernet control frame station address 2 */
+
+#define KR_ETHIPGT_HALF_DUPLEX 0x12
+#define KR_ETHIPGT_FULL_DUPLEX 0x15
+
+#define KR_TIMEOUT 0xf000
+#define KR_MII_TIMEOUT 0xf000
+
+#define KR_RX_IRQ 40
+#define KR_TX_IRQ 41
+#define KR_RX_UND_IRQ 42
+#define KR_TX_OVR_IRQ 43
+#define RC32434_DMA_BASE_ADDR MIPS_PHYS_TO_KSEG1(0x18040000)
+#define DMA_C 0x00
+#define DMA_C_R 0x01
+#define DMA_C_ABORT 0x10
+#define DMA_S 0x04
+#define DMA_S_F 0x01
+#define DMA_S_D 0x02
+#define DMA_S_C 0x04
+#define DMA_S_E 0x08
+#define DMA_S_H 0x10
+#define DMA_SM 0x08
+#define DMA_SM_F 0x01
+#define DMA_SM_D 0x02
+#define DMA_SM_C 0x04
+#define DMA_SM_E 0x08
+#define DMA_SM_H 0x10
+#define DMA_DPTR 0x0C
+#define DMA_NDPTR 0x10
+
+#define RC32434_DMA_CHAN_SIZE 0x14
+#define KR_DMA_RXCHAN 0
+#define KR_DMA_TXCHAN 1
+
+#define KR_DMA_READ_REG(chan, reg) \
+ (*(volatile uint32_t *) \
+ (RC32434_DMA_BASE_ADDR + chan * RC32434_DMA_CHAN_SIZE + reg))
+
+#define KR_DMA_WRITE_REG(chan, reg, val) \
+ ((*(volatile uint32_t *) \
+ (RC32434_DMA_BASE_ADDR + chan * RC32434_DMA_CHAN_SIZE + reg)) = val)
+
+#define KR_DMA_SETBITS_REG(chan, reg, bits) \
+ KR_DMA_WRITE_REG((chan), (reg), KR_DMA_READ_REG((chan), (reg)) | (bits))
+
+#define KR_DMA_CLEARBITS_REG(chan, reg, bits) \
+ KR_DMA_WRITE_REG((chan), (reg), \
+ KR_DMA_READ_REG((chan), (reg)) & ~(bits))
+
+struct kr_desc {
+ uint32_t kr_ctl;
+ uint32_t kr_ca;
+ uint32_t kr_devcs;
+ uint32_t kr_link;
+};
+
+
+#define KR_DMASIZE(len) ((len) & ((1 << 18)-1))
+#define KR_PKTSIZE(len) ((len & 0xffff0000) >> 16)
+
+#define KR_CTL_COF 0x02000000
+#define KR_CTL_COD 0x04000000
+#define KR_CTL_IOF 0x08000000
+#define KR_CTL_IOD 0x10000000
+#define KR_CTL_T 0x20000000
+#define KR_CTL_D 0x40000000
+#define KR_CTL_F 0x80000000
+
+#define KR_DMARX_DEVCS_RSV 0x00000001
+#define KR_DMARX_DEVCS_LD 0x00000002
+#define KR_DMARX_DEVCS_ROK 0x00000004
+#define KR_DMARX_DEVCS_FM 0x00000008
+#define KR_DMARX_DEVCS_MP 0x00000010
+#define KR_DMARX_DEVCS_BP 0x00000020
+#define KR_DMARX_DEVCS_VLT 0x00000040
+#define KR_DMARX_DEVCS_CF 0x00000080
+#define KR_DMARX_DEVCS_OVR 0x00000100
+#define KR_DMARX_DEVCS_CRC 0x00000200
+#define KR_DMARX_DEVCS_CV 0x00000400
+#define KR_DMARX_DEVCS_DB 0x00000800
+#define KR_DMARX_DEVCS_LE 0x00001000
+#define KR_DMARX_DEVCS_LOR 0x00002000
+#define KR_DMARX_DEVCS_CES 0x00004000
+
+#define KR_DMATX_DEVCS_FD 0x00000001
+#define KR_DMATX_DEVCS_LD 0x00000002
+#define KR_DMATX_DEVCS_OEN 0x00000004
+#define KR_DMATX_DEVCS_PEN 0x00000008
+#define KR_DMATX_DEVCS_CEN 0x00000010
+#define KR_DMATX_DEVCS_HEN 0x00000020
+#define KR_DMATX_DEVCS_TOK 0x00000040
+#define KR_DMATX_DEVCS_MP 0x00000080
+#define KR_DMATX_DEVCS_BP 0x00000100
+#define KR_DMATX_DEVCS_UND 0x00000200
+#define KR_DMATX_DEVCS_OF 0x00000400
+#define KR_DMATX_DEVCS_ED 0x00000800
+#define KR_DMATX_DEVCS_EC 0x00001000
+#define KR_DMATX_DEVCS_LC 0x00002000
+#define KR_DMATX_DEVCS_TD 0x00004000
+#define KR_DMATX_DEVCS_CRC 0x00008000
+#define KR_DMATX_DEVCS_LE 0x00010000
+
+#define KR_RX_RING_CNT 128
+#define KR_TX_RING_CNT 128
+#define KR_TX_RING_SIZE sizeof(struct kr_desc) * KR_TX_RING_CNT
+#define KR_RX_RING_SIZE sizeof(struct kr_desc) * KR_RX_RING_CNT
+#define KR_RING_ALIGN sizeof(struct kr_desc)
+#define KR_RX_ALIGN sizeof(uint32_t)
+#define KR_MAXFRAGS 8
+#define KR_TX_INTR_THRESH 8
+
+#define KR_TX_RING_ADDR(sc, i) \
+ ((sc)->kr_rdata.kr_tx_ring_paddr + sizeof(struct kr_desc) * (i))
+#define KR_RX_RING_ADDR(sc, i) \
+ ((sc)->kr_rdata.kr_rx_ring_paddr + sizeof(struct kr_desc) * (i))
+#define KR_INC(x,y) (x) = (((x) + 1) % y)
+
+struct kr_txdesc {
+ struct mbuf *tx_m;
+ bus_dmamap_t tx_dmamap;
+};
+
+struct kr_rxdesc {
+ struct mbuf *rx_m;
+ bus_dmamap_t rx_dmamap;
+ struct kr_desc *desc;
+ /* Use this values on error instead of allocating new mbuf */
+ uint32_t saved_ctl, saved_ca;
+};
+
+struct kr_chain_data {
+ bus_dma_tag_t kr_parent_tag;
+ bus_dma_tag_t kr_tx_tag;
+ struct kr_txdesc kr_txdesc[KR_TX_RING_CNT];
+ bus_dma_tag_t kr_rx_tag;
+ struct kr_rxdesc kr_rxdesc[KR_RX_RING_CNT];
+ bus_dma_tag_t kr_tx_ring_tag;
+ bus_dma_tag_t kr_rx_ring_tag;
+ bus_dmamap_t kr_tx_ring_map;
+ bus_dmamap_t kr_rx_ring_map;
+ bus_dmamap_t kr_rx_sparemap;
+ int kr_tx_pkts;
+ int kr_tx_prod;
+ int kr_tx_cons;
+ int kr_tx_cnt;
+ int kr_rx_cons;
+};
+
+struct kr_ring_data {
+ struct kr_desc *kr_rx_ring;
+ struct kr_desc *kr_tx_ring;
+ bus_addr_t kr_rx_ring_paddr;
+ bus_addr_t kr_tx_ring_paddr;
+};
+
+struct kr_softc {
+ struct ifnet *kr_ifp; /* interface info */
+ bus_space_handle_t kr_bhandle; /* bus space handle */
+ bus_space_tag_t kr_btag; /* bus space tag */
+ device_t kr_dev;
+ struct resource *kr_res;
+ int kr_rid;
+ struct resource *kr_rx_irq;
+ void *kr_rx_intrhand;
+ struct resource *kr_tx_irq;
+ void *kr_tx_intrhand;
+ struct resource *kr_rx_und_irq;
+ void *kr_rx_und_intrhand;
+ struct resource *kr_tx_ovr_irq;
+ void *kr_tx_ovr_intrhand;
+ device_t kr_miibus;
+ bus_dma_tag_t kr_parent_tag;
+ bus_dma_tag_t kr_tag;
+ struct mtx kr_mtx;
+ struct callout kr_stat_callout;
+ struct task kr_link_task;
+ struct kr_chain_data kr_cdata;
+ struct kr_ring_data kr_rdata;
+ int kr_link_status;
+ int kr_detach;
+};
+
+#define KR_LOCK(_sc) mtx_lock(&(_sc)->kr_mtx)
+#define KR_UNLOCK(_sc) mtx_unlock(&(_sc)->kr_mtx)
+#define KR_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->kr_mtx, MA_OWNED)
+
+/*
+ * register space access macros
+ */
+#define CSR_WRITE_4(sc, reg, val) \
+ bus_space_write_4(sc->kr_btag, sc->kr_bhandle, reg, val)
+
+#define CSR_READ_4(sc, reg) \
+ bus_space_read_4(sc->kr_btag, sc->kr_bhandle, reg)
+
+#endif /* __IF_KRREG_H__ */
diff --git a/sys/mips/mips32/idt/obio.c b/sys/mips/mips32/idt/obio.c
new file mode 100644
index 0000000..c938f72
--- /dev/null
+++ b/sys/mips/mips32/idt/obio.c
@@ -0,0 +1,514 @@
+/*-
+ * Copyright (c) 2007, Oleksandr Tymoshenko <gonzo@freebsd.org>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <mips/mips32/idt/idtreg.h>
+#include <mips/mips32/idt/obiovar.h>
+
+#define ICU_REG_READ(o) \
+ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_ICU + (o)))
+#define ICU_REG_WRITE(o,v) (ICU_REG_READ(o)) = (v)
+
+#define GPIO_REG_READ(o) \
+ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_GPIO + (o)))
+#define GPIO_REG_WRITE(o,v) (GPIO_REG_READ(o)) = (v)
+
+static int obio_activate_resource(device_t, device_t, int, int,
+ struct resource *);
+static device_t obio_add_child(device_t, int, const char *, int);
+static struct resource *
+ obio_alloc_resource(device_t, device_t, int, int *, u_long,
+ u_long, u_long, u_int);
+static int obio_attach(device_t);
+static int obio_deactivate_resource(device_t, device_t, int, int,
+ struct resource *);
+static struct resource_list *
+ obio_get_resource_list(device_t, device_t);
+static void obio_hinted_child(device_t, const char *, int);
+static int obio_intr(void *);
+static int obio_probe(device_t);
+static int obio_release_resource(device_t, device_t, int, int,
+ struct resource *);
+static int obio_setup_intr(device_t, device_t, struct resource *, int,
+ driver_filter_t *, driver_intr_t *, void *, void **);
+static int obio_teardown_intr(device_t, device_t, struct resource *,
+ void *);
+
+static void obio_mask_irq(unsigned int irq)
+{
+ int ip_bit, mask, mask_register;
+
+ /* mask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask | ip_bit);
+}
+
+static void obio_unmask_irq(unsigned int irq)
+{
+ int ip_bit, mask, mask_register;
+
+ /* unmask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask & ~ip_bit);
+}
+
+static int
+obio_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+obio_attach(device_t dev)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ int rid, irq;
+
+ sc->oba_mem_rman.rm_type = RMAN_ARRAY;
+ sc->oba_mem_rman.rm_descr = "OBIO memeory";
+ if (rman_init(&sc->oba_mem_rman) != 0 ||
+ rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START,
+ OBIO_MEM_START + OBIO_MEM_SIZE) != 0)
+ panic("obio_attach: failed to set up I/O rman");
+
+ sc->oba_irq_rman.rm_type = RMAN_ARRAY;
+ sc->oba_irq_rman.rm_descr = "OBIO IRQ";
+
+ if (rman_init(&sc->oba_irq_rman) != 0 ||
+ rman_manage_region(&sc->oba_irq_rman, IRQ_BASE, IRQ_END) != 0)
+ panic("obio_attach: failed to set up IRQ rman");
+
+ /* Hook up our interrupt handlers. We should handle IRQ0..IRQ4*/
+ for(irq = 0; irq < 5; irq++) {
+ if ((sc->sc_irq[irq] = bus_alloc_resource(dev, SYS_RES_IRQ,
+ &rid, irq, irq, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return (ENXIO);
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_irq[irq], INTR_TYPE_MISC,
+ obio_intr, NULL, sc, &sc->sc_ih[irq]))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+ }
+
+ bus_generic_probe(dev);
+ bus_enumerate_hinted_children(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static struct resource *
+obio_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct obio_softc *sc = device_get_softc(bus);
+ struct obio_ivar *ivar = device_get_ivars(child);
+ struct resource *rv;
+ struct resource_list_entry *rle;
+ struct rman *rm;
+ int isdefault, needactivate, passthrough;
+
+ isdefault = (start == 0UL && end == ~0UL);
+ needactivate = flags & RF_ACTIVE;
+ passthrough = (device_get_parent(child) != bus);
+ rle = NULL;
+
+ if (passthrough)
+ return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
+ rid, start, end, count, flags));
+
+ /*
+ * If this is an allocation of the "default" range for a given RID,
+ * and we know what the resources for this device are (ie. they aren't
+ * maintained by a child bus), then work out the start/end values.
+ */
+ if (isdefault) {
+ rle = resource_list_find(&ivar->resources, type, *rid);
+ if (rle == NULL)
+ return (NULL);
+ if (rle->res != NULL) {
+ panic("%s: resource entry is busy", __func__);
+ }
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+ }
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->oba_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ rm = &sc->oba_mem_rman;
+ break;
+ default:
+ printf("%s: unknown resource type %d\n", __func__, type);
+ return (0);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == 0) {
+ printf("%s: could not reserve resource\n", __func__);
+ return (0);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ if (needactivate) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ printf("%s: could not activate resource\n", __func__);
+ rman_release_resource(rv);
+ return (0);
+ }
+ }
+
+ return (rv);
+}
+
+static int
+obio_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ /* XXX: should we mask/unmask IRQ here? */
+ return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child,
+ type, rid, r));
+}
+
+static int
+obio_deactivate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+
+ /* XXX: should we mask/unmask IRQ here? */
+ return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child,
+ type, rid, r));
+}
+
+static int
+obio_release_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+
+ rl = obio_get_resource_list(dev, child);
+ if (rl == NULL)
+ return (EINVAL);
+ rle = resource_list_find(rl, type, rid);
+ if (rle == NULL)
+ return (EINVAL);
+ rman_release_resource(r);
+ rle->res = NULL;
+
+ return (0);
+}
+
+static int
+obio_setup_intr(device_t dev, device_t child, struct resource *ires,
+ int flags, driver_filter_t *filt, driver_intr_t *handler,
+ void *arg, void **cookiep)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ struct intr_event *event;
+ int irq, ip_bit, error, mask, mask_register;
+
+ irq = rman_get_start(ires);
+
+ if (irq >= NIRQS)
+ panic("%s: bad irq %d", __func__, irq);
+
+ event = sc->sc_eventstab[irq];
+ if (event == NULL) {
+ error = intr_event_create(&event, (void *)irq, 0,
+ (mask_fn)obio_mask_irq, (mask_fn)obio_unmask_irq,
+ NULL, NULL,
+ "obio intr%d:", irq);
+
+ sc->sc_eventstab[irq] = event;
+ }
+
+ intr_event_add_handler(event, device_get_nameunit(child), filt,
+ handler, arg, intr_priority(flags), flags, cookiep);
+
+ /* unmask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask & ~ip_bit);
+
+ return (0);
+}
+
+static int
+obio_teardown_intr(device_t dev, device_t child, struct resource *ires,
+ void *cookie)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+ int irq, result;
+ uint32_t mask_register, mask, ip_bit;
+
+ irq = rman_get_start(ires);
+ if (irq >= NIRQS)
+ panic("%s: bad irq %d", __func__, irq);
+
+ if (sc->sc_eventstab[irq] == NULL)
+ panic("Trying to teardown unoccupied IRQ");
+
+ /* mask IRQ */
+ mask_register = ICU_IRQ_MASK_REG(irq);
+ ip_bit = ICU_IP_BIT(irq);
+
+ mask = ICU_REG_READ(mask_register);
+ ICU_REG_WRITE(mask_register, mask | ip_bit);
+
+ result = intr_event_remove_handler(cookie);
+ if (!result)
+ sc->sc_eventstab[irq] = NULL;
+
+ return (result);
+}
+
+static int
+obio_intr(void *arg)
+{
+ struct obio_softc *sc = arg;
+ struct intr_event *event;
+ struct intr_handler *ih;
+ uint32_t irqstat, ipend, imask, xpend;
+ int irq, thread, group, i, ret;
+
+ irqstat = 0;
+ irq = 0;
+ for (group = 2; group <= 6; group++) {
+ ipend = ICU_REG_READ(ICU_GROUP_IPEND_REG(group));
+ imask = ICU_REG_READ(ICU_GROUP_MASK_REG(group));
+ xpend = ipend;
+ ipend &= ~imask;
+
+ while ((i = fls(xpend)) != 0) {
+ xpend &= ~(1 << (i - 1));
+ irq = IP_IRQ(group, i - 1);
+ }
+
+ while ((i = fls(ipend)) != 0) {
+ ipend &= ~(1 << (i - 1));
+ irq = IP_IRQ(group, i - 1);
+ event = sc->sc_eventstab[irq];
+ thread = 0;
+#ifndef INTR_FILTER
+ obio_mask_irq(irq);
+#endif
+ if (!event || TAILQ_EMPTY(&event->ie_handlers)) {
+#ifdef INTR_FILTER
+ obio_unmask_irq(irq);
+#endif
+ continue;
+ }
+
+#ifdef INTR_FILTER
+ /* TODO: frame instead of NULL? */
+ intr_event_handle(event, NULL);
+ /* XXX: Log stray IRQs */
+#else
+ /* Execute fast handlers. */
+ TAILQ_FOREACH(ih, &event->ie_handlers,
+ ih_next) {
+ if (ih->ih_filter == NULL)
+ thread = 1;
+ else
+ ret = ih->ih_filter(ih->ih_argument);
+ /*
+ * Wrapper handler special case: see
+ * intr_execute_handlers() in
+ * i386/intr_machdep.c
+ */
+ if (!thread) {
+ if (ret == FILTER_SCHEDULE_THREAD)
+ thread = 1;
+ }
+ }
+
+ /* Schedule thread if needed. */
+ if (thread)
+ intr_event_schedule_thread(event);
+ else
+ obio_unmask_irq(irq);
+ }
+ }
+#endif
+#if 0
+ ipend = ICU_REG_READ(ICU_IPEND2);
+ printf("ipend2 = %08x!\n", ipend);
+
+ ipend = ICU_REG_READ(ICU_IPEND3);
+ printf("ipend3 = %08x!\n", ipend);
+
+ ipend = ICU_REG_READ(ICU_IPEND4);
+ printf("ipend4 = %08x!\n", ipend);
+ ipend = ICU_REG_READ(ICU_IPEND5);
+ printf("ipend5 = %08x!\n", ipend);
+
+ ipend = ICU_REG_READ(ICU_IPEND6);
+ printf("ipend6 = %08x!\n", ipend);
+#endif
+ while (irqstat != 0) {
+ if ((irqstat & 1) == 1) {
+ }
+
+ irq++;
+ irqstat >>= 1;
+ }
+
+ return (FILTER_HANDLED);
+}
+
+static void
+obio_hinted_child(device_t bus, const char *dname, int dunit)
+{
+ device_t child;
+ long maddr;
+ int msize;
+ int irq;
+ int result;
+
+ child = BUS_ADD_CHILD(bus, 0, dname, dunit);
+
+ /*
+ * Set hard-wired resources for hinted child using
+ * specific RIDs.
+ */
+ resource_long_value(dname, dunit, "maddr", &maddr);
+ resource_int_value(dname, dunit, "msize", &msize);
+
+
+ result = bus_set_resource(child, SYS_RES_MEMORY, 0,
+ maddr, msize);
+ if (result != 0)
+ device_printf(bus, "warning: bus_set_resource() failed\n");
+
+ if (resource_int_value(dname, dunit, "irq", &irq) == 0) {
+ result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ if (result != 0)
+ device_printf(bus,
+ "warning: bus_set_resource() failed\n");
+ }
+}
+
+static device_t
+obio_add_child(device_t bus, int order, const char *name, int unit)
+{
+ device_t child;
+ struct obio_ivar *ivar;
+
+ ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO);
+ if (ivar == NULL) {
+ printf("Failed to allocate ivar\n");
+ return (0);
+ }
+ resource_list_init(&ivar->resources);
+
+ child = device_add_child_ordered(bus, order, name, unit);
+ if (child == NULL) {
+ printf("Can't add child %s%d ordered\n", name, unit);
+ return (0);
+ }
+
+ device_set_ivars(child, ivar);
+
+ return (child);
+}
+
+/*
+ * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource
+ * Provides pointer to resource_list for these routines
+ */
+static struct resource_list *
+obio_get_resource_list(device_t dev, device_t child)
+{
+ struct obio_ivar *ivar;
+
+ ivar = device_get_ivars(child);
+ return (&(ivar->resources));
+}
+
+static device_method_t obio_methods[] = {
+ DEVMETHOD(bus_activate_resource, obio_activate_resource),
+ DEVMETHOD(bus_add_child, obio_add_child),
+ DEVMETHOD(bus_alloc_resource, obio_alloc_resource),
+ DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list, obio_get_resource_list),
+ DEVMETHOD(bus_hinted_child, obio_hinted_child),
+ DEVMETHOD(bus_release_resource, obio_release_resource),
+ DEVMETHOD(bus_setup_intr, obio_setup_intr),
+ DEVMETHOD(bus_teardown_intr, obio_teardown_intr),
+ DEVMETHOD(device_attach, obio_attach),
+ DEVMETHOD(device_probe, obio_probe),
+ DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
+ DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
+
+ {0, 0},
+};
+
+static driver_t obio_driver = {
+ "obio",
+ obio_methods,
+ sizeof(struct obio_softc),
+};
+static devclass_t obio_devclass;
+
+DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0);
diff --git a/sys/mips/mips32/idt/obiovar.h b/sys/mips/mips32/idt/obiovar.h
new file mode 100644
index 0000000..526efac
--- /dev/null
+++ b/sys/mips/mips32/idt/obiovar.h
@@ -0,0 +1,67 @@
+/* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */
+
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _ADM5120_OBIOVAR_H_
+#define _ADM5120_OBIOVAR_H_
+
+#include <sys/rman.h>
+
+/* Number of controller's IRQs */
+#define NIRQS 32*5
+
+/* Number of CPU IRQ lines */
+#define MIPS_IRQS 5
+
+#define OBIO_MEM_START 0x18000000L
+#define OBIO_MEM_SIZE 0x200000
+
+struct obio_softc {
+ struct rman oba_mem_rman;
+ struct rman oba_irq_rman;
+ struct intr_event *sc_eventstab[NIRQS]; /* IRQ events structs */
+ struct resource *sc_irq[MIPS_IRQS]; /* IRQ resource */
+ void *sc_ih[MIPS_IRQS]; /* interrupt cookie */
+};
+
+struct obio_ivar {
+ struct resource_list resources;
+};
+
+#endif /* _ADM5120_OBIOVAR_H_ */
diff --git a/sys/mips/mips32/idt/std.idt b/sys/mips/mips32/idt/std.idt
new file mode 100644
index 0000000..fa067e7
--- /dev/null
+++ b/sys/mips/mips32/idt/std.idt
@@ -0,0 +1,5 @@
+# $FreeBSD$
+# Standard include file for IDT
+
+files "../mips32/idt/files.idt"
+options ISA_MIPS32
diff --git a/sys/mips/mips32/idt/uart_bus_rc32434.c b/sys/mips/mips32/idt/uart_bus_rc32434.c
new file mode 100644
index 0000000..0626b52
--- /dev/null
+++ b/sys/mips/mips32/idt/uart_bus_rc32434.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * 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 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 THE 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
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <mips/mips32/idt/idtreg.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <dev/ic/ns16550.h>
+
+#include "uart_if.h"
+
+static int uart_rc32434_probe(device_t dev);
+
+extern struct uart_class uart_rc32434_uart_class;
+
+static device_method_t uart_rc32434_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_rc32434_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_rc32434_driver = {
+ uart_driver_name,
+ uart_rc32434_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static int
+uart_rc32434_probe(device_t dev)
+{
+ struct uart_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ sc->sc_class = &uart_ns8250_class;
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+ sc->sc_sysdev->bas.regshft = 2;
+ sc->sc_sysdev->bas.bst = 0;
+ sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(IDT_BASE_UART0);
+ sc->sc_bas.regshft = 2;
+ sc->sc_bas.bst = 0;
+ sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(IDT_BASE_UART0);
+
+ return (uart_bus_probe(dev, 2, 330000000UL/2, 0, 0));
+}
+
+DRIVER_MODULE(uart, obio, uart_rc32434_driver, uart_devclass, 0, 0);
diff --git a/sys/mips/mips32/idt/uart_cpu_rc32434.c b/sys/mips/mips32/idt/uart_cpu_rc32434.c
new file mode 100644
index 0000000..6bbc5bd
--- /dev/null
+++ b/sys/mips/mips32/idt/uart_cpu_rc32434.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
+ * 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 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 THE 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.
+ *
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+extern struct uart_class uart_rc32434_uart_class;
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ uint32_t maddr;
+
+ if (resource_int_value("uart", 0, "maddr", &maddr) != 0 ||
+ maddr == 0)
+ return (ENXIO);
+
+ /* Got it. Fill in the instance and return it. */
+ di->ops = uart_getops(&uart_ns8250_class);
+ di->bas.chan = 0;
+ di->bas.bst = 0;
+ di->bas.regshft = 2;
+ di->bas.rclk = 330000000UL/2; /* IPbus clock */
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+ uart_bus_space_io = 0;
+ uart_bus_space_mem = 0;
+ di->bas.bsh = MIPS_PHYS_TO_KSEG1(maddr);
+ return (0);
+}
diff --git a/sys/mips/mips32/malta/files.malta b/sys/mips/mips32/malta/files.malta
new file mode 100644
index 0000000..04b46ef
--- /dev/null
+++ b/sys/mips/mips32/malta/files.malta
@@ -0,0 +1,9 @@
+# $FreeBSD$
+mips/mips32/malta/gt.c standard
+mips/mips32/malta/gt_pci.c standard
+mips/mips32/malta/obio.c optional uart
+mips/mips32/malta/uart_cpu_maltausart.c optional uart
+mips/mips32/malta/uart_bus_maltausart.c optional uart
+dev/uart/uart_dev_ns8250.c optional uart
+mips/mips32/malta/malta_machdep.c standard
+mips/mips32/malta/yamon.c standard
diff --git a/sys/mips/mips32/malta/gt.c b/sys/mips/mips32/malta/gt.c
new file mode 100644
index 0000000..daa9e25
--- /dev/null
+++ b/sys/mips/mips32/malta/gt.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. 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.
+ */
+
+#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 <sys/module.h>
+#include <sys/rman.h>
+#include <sys/types.h>
+
+#include <vm/vm.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+
+#include <dev/ic/i8259.h>
+
+#include <machine/bus.h>
+#include <machine/intr_machdep.h>
+
+#include <mips/mips32/malta/gtvar.h>
+
+static int
+gt_probe(device_t dev)
+{
+ device_set_desc(dev, "GT64120 chip");
+ return (0);
+}
+
+static void
+gt_identify(driver_t *drv, device_t parent)
+{
+ BUS_ADD_CHILD(parent, 0, "gt", 0);
+}
+
+static int
+gt_attach(device_t dev)
+{
+ struct gt_softc *sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ device_add_child(dev, "pcib", 0);
+ bus_generic_probe(dev);
+ bus_generic_attach(dev);
+
+
+ return (0);
+}
+
+static struct resource *
+gt_alloc_resource(device_t dev, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
+ type, rid, start, end, count, flags));
+
+}
+
+static int
+gt_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)
+{
+ return BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
+ filt, intr, arg, cookiep);
+}
+
+static int
+gt_teardown_intr(device_t dev, device_t child, struct resource *res,
+ void *cookie)
+{
+ return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie));
+}
+
+static int
+gt_activate_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ return (BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child,
+ type, rid, r));
+}
+
+static device_method_t gt_methods[] = {
+ DEVMETHOD(device_probe, gt_probe),
+ DEVMETHOD(device_identify, gt_identify),
+ DEVMETHOD(device_attach, gt_attach),
+
+ DEVMETHOD(bus_setup_intr, gt_setup_intr),
+ DEVMETHOD(bus_teardown_intr, gt_teardown_intr),
+ DEVMETHOD(bus_alloc_resource, gt_alloc_resource),
+ DEVMETHOD(bus_activate_resource, gt_activate_resource),
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ {0, 0},
+};
+
+static driver_t gt_driver = {
+ "gt",
+ gt_methods,
+ sizeof(struct gt_softc),
+};
+static devclass_t gt_devclass;
+
+DRIVER_MODULE(gt, nexus, gt_driver, gt_devclass, 0, 0);
diff --git a/sys/mips/mips32/malta/gt_pci.c b/sys/mips/mips32/malta/gt_pci.c
new file mode 100644
index 0000000..2521058
--- /dev/null
+++ b/sys/mips/mips32/malta/gt_pci.c
@@ -0,0 +1,723 @@
+/* $NetBSD: gt_pci.c,v 1.4 2003/07/15 00:24:54 lukem Exp $ */
+
+/*-
+ * Copyright (c) 2001, 2002 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.
+ */
+
+/*
+ * PCI configuration support for gt I/O Processor chip.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_extern.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/pmap.h>
+
+#include <mips/mips32/malta/maltareg.h>
+
+#include <mips/mips32/malta/gtreg.h>
+#include <mips/mips32/malta/gtvar.h>
+
+#include <isa/isareg.h>
+#include <dev/ic/i8259.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <dev/pci/pcib_private.h>
+#include "pcib_if.h"
+
+
+#define ICU_LEN 16 /* number of ISA IRQs */
+
+/*
+ * XXX: These defines are from NetBSD's <dev/ic/i8259reg.h>. Respective file
+ * from FreeBSD src tree <dev/ic/i8259.h> lacks some definitions.
+ */
+#define PIC_OCW1 1
+#define PIC_OCW2 0
+#define PIC_OCW3 0
+
+#define OCW2_SELECT 0
+#define OCW2_ILS(x) ((x) << 0) /* interrupt level select */
+
+#define OCW3_POLL_IRQ(x) ((x) & 0x7f)
+#define OCW3_POLL_PENDING (1U << 7)
+
+struct gt_pci_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_st;
+ bus_space_tag_t sc_pciio;
+ bus_space_tag_t sc_pcimem;
+ bus_space_handle_t sc_ioh_icu1;
+ bus_space_handle_t sc_ioh_icu2;
+ bus_space_handle_t sc_ioh_elcr;
+
+ int sc_busno;
+ struct rman sc_mem_rman;
+ struct rman sc_io_rman;
+ struct rman sc_irq_rman;
+ uint32_t sc_mem;
+ uint32_t sc_io;
+
+ struct resource *sc_irq;
+ struct intr_event *sc_eventstab[ICU_LEN];
+ uint16_t sc_imask;
+ uint16_t sc_elcr;
+
+ uint16_t sc_reserved;
+
+ void *sc_ih;
+};
+
+static void
+gt_pci_set_icus(struct gt_pci_softc *sc)
+{
+ /* Enable the cascade IRQ (2) if 8-15 is enabled. */
+ if ((sc->sc_imask & 0xff00) != 0xff00)
+ sc->sc_imask &= ~(1U << 2);
+ else
+ sc->sc_imask |= (1U << 2);
+
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, PIC_OCW1,
+ sc->sc_imask & 0xff);
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, PIC_OCW1,
+ (sc->sc_imask >> 8) & 0xff);
+
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_elcr, 0,
+ sc->sc_elcr & 0xff);
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_elcr, 1,
+ (sc->sc_elcr >> 8) & 0xff);
+}
+
+static int
+gt_pci_intr(void *v)
+{
+ struct gt_pci_softc *sc = v;
+ struct intr_event *event;
+ struct intr_handler *ih;
+ int irq, thread;
+
+ for (;;) {
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, PIC_OCW3,
+ OCW3_SEL | OCW3_P);
+ irq = bus_space_read_1(sc->sc_pciio, sc->sc_ioh_icu1, PIC_OCW3);
+ if ((irq & OCW3_POLL_PENDING) == 0)
+ {
+ return FILTER_HANDLED;
+ }
+
+ irq = OCW3_POLL_IRQ(irq);
+
+ if (irq == 2) {
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2,
+ PIC_OCW3, OCW3_SEL | OCW3_P);
+ irq = bus_space_read_1(sc->sc_pciio, sc->sc_ioh_icu2,
+ PIC_OCW3);
+ if (irq & OCW3_POLL_PENDING)
+ irq = OCW3_POLL_IRQ(irq) + 8;
+ else
+ irq = 2;
+ }
+
+ event = sc->sc_eventstab[irq];
+ thread = 0;
+
+ if (event && !TAILQ_EMPTY(&event->ie_handlers))
+ {
+ /* Execute fast handlers. */
+ TAILQ_FOREACH(ih, &event->ie_handlers, ih_next) {
+ if (ih->ih_filter == NULL)
+ thread = 1;
+ else
+ ih->ih_filter(ih->ih_argument);
+ }
+ }
+
+ /* Schedule thread if needed. */
+ if (thread)
+ intr_event_schedule_thread(event);
+
+ /* Send a specific EOI to the 8259. */
+ if (irq > 7) {
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2,
+ PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL |
+ OCW2_ILS(irq & 7));
+ irq = 2;
+ }
+
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, PIC_OCW2,
+ OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq));
+ }
+
+ return FILTER_HANDLED;
+}
+
+static int
+gt_pci_probe(device_t dev)
+{
+ device_set_desc(dev, "GT64120 PCI bridge");
+ return (0);
+}
+
+static int
+gt_pci_attach(device_t dev)
+{
+
+ uint32_t busno;
+ struct gt_pci_softc *sc = device_get_softc(dev);
+ int rid;
+
+ busno = 0;
+ sc->sc_dev = dev;
+ sc->sc_busno = busno;
+ sc->sc_pciio = MIPS_BUS_SPACE_IO;
+ sc->sc_pcimem = MIPS_BUS_SPACE_MEM;
+
+ /* Use KSEG1 to access IO ports for it is uncached */
+ sc->sc_io = MIPS_PHYS_TO_KSEG1(MALTA_PCI0_IO_BASE);
+ sc->sc_io_rman.rm_type = RMAN_ARRAY;
+ sc->sc_io_rman.rm_descr = "GT64120 PCI I/O Ports";
+ if (rman_init(&sc->sc_io_rman) != 0 ||
+ rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) {
+ panic("gt_pci_attach: failed to set up I/O rman");
+ }
+
+ /* Use KSEG1 to access PCI memory for it is uncached */
+ sc->sc_mem = MIPS_PHYS_TO_KSEG1(MALTA_PCIMEM1_BASE);
+ sc->sc_mem_rman.rm_type = RMAN_ARRAY;
+ sc->sc_mem_rman.rm_descr = "GT64120 PCI Memory";
+ if (rman_init(&sc->sc_mem_rman) != 0 ||
+ rman_manage_region(&sc->sc_mem_rman,
+ sc->sc_mem, sc->sc_mem + MALTA_PCIMEM1_SIZE) != 0) {
+ panic("gt_pci_attach: failed to set up memory rman");
+ }
+ sc->sc_irq_rman.rm_type = RMAN_ARRAY;
+ sc->sc_irq_rman.rm_descr = "GT64120 PCI IRQs";
+ if (rman_init(&sc->sc_irq_rman) != 0 ||
+ rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0)
+ panic("gt_pci_attach: failed to set up IRQ rman");
+
+ /*
+ * Map the PIC/ELCR registers.
+ */
+#if 0
+ if (bus_space_map(sc->sc_pciio, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0)
+ device_printf(dev, "unable to map ELCR registers\n");
+ if (bus_space_map(sc->sc_pciio, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0)
+ device_printf(dev, "unable to map ICU1 registers\n");
+ if (bus_space_map(sc->sc_pciio, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0)
+ device_printf(dev, "unable to map ICU2 registers\n");
+#else
+ sc->sc_ioh_elcr = sc->sc_io + 0x4d0;
+ sc->sc_ioh_icu1 = sc->sc_io + IO_ICU1;
+ sc->sc_ioh_icu2 = sc->sc_io + IO_ICU2;
+#endif
+
+
+ /* All interrupts default to "masked off". */
+ sc->sc_imask = 0xffff;
+
+ /* All interrupts default to edge-triggered. */
+ sc->sc_elcr = 0;
+
+ /*
+ * Initialize the 8259s.
+ */
+ /* reset, program device, 4 bytes */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 0,
+ ICW1_RESET | ICW1_IC4);
+ /*
+ * XXX: values from NetBSD's <dev/ic/i8259reg.h>
+ */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
+ 0/*XXX*/);
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
+ 1 << 2);
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
+ ICW4_8086);
+
+ /* mask all interrupts */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 0,
+ sc->sc_imask & 0xff);
+
+ /* enable special mask mode */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
+ OCW3_SEL | OCW3_ESMM | OCW3_SMM);
+
+ /* read IRR by default */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu1, 1,
+ OCW3_SEL | OCW3_RR);
+
+ /* reset, program device, 4 bytes */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 0,
+ ICW1_RESET | ICW1_IC4);
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
+ 0/*XXX*/);
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
+ 1 << 2);
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
+ ICW4_8086);
+
+ /* mask all interrupts */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 0,
+ sc->sc_imask & 0xff);
+
+ /* enable special mask mode */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
+ OCW3_SEL | OCW3_ESMM | OCW3_SMM);
+
+ /* read IRR by default */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_icu2, 1,
+ OCW3_SEL | OCW3_RR);
+
+ /*
+ * Default all interrupts to edge-triggered.
+ */
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_elcr, 0,
+ sc->sc_elcr & 0xff);
+ bus_space_write_1(sc->sc_pciio, sc->sc_ioh_elcr, 1,
+ (sc->sc_elcr >> 8) & 0xff);
+
+ /*
+ * Some ISA interrupts are reserved for devices that
+ * we know are hard-wired to certain IRQs.
+ */
+ sc->sc_reserved =
+ (1U << 0) | /* timer */
+ (1U << 1) | /* keyboard controller (keyboard) */
+ (1U << 2) | /* PIC cascade */
+ (1U << 3) | /* COM 2 */
+ (1U << 4) | /* COM 1 */
+ (1U << 6) | /* floppy */
+ (1U << 7) | /* centronics */
+ (1U << 8) | /* RTC */
+ (1U << 9) | /* I2C */
+ (1U << 12) | /* keyboard controller (mouse) */
+ (1U << 14) | /* IDE primary */
+ (1U << 15); /* IDE secondary */
+
+ /* Hook up our interrupt handler. */
+ if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
+ MALTA_SOUTHBRIDGE_INTR, MALTA_SOUTHBRIDGE_INTR, 1,
+ RF_SHAREABLE | RF_ACTIVE)) == NULL) {
+ device_printf(dev, "unable to allocate IRQ resource\n");
+ return ENXIO;
+ }
+
+ if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC,
+ gt_pci_intr, NULL, sc, &sc->sc_ih))) {
+ device_printf(dev,
+ "WARNING: unable to register interrupt handler\n");
+ return ENXIO;
+ }
+
+ /* Initialize memory and i/o rmans. */
+ device_add_child(dev, "pci", busno);
+ return (bus_generic_attach(dev));
+}
+
+static int
+gt_pci_maxslots(device_t dev)
+{
+ return (PCI_SLOTMAX);
+}
+
+static int
+gt_pci_conf_setup(struct gt_pci_softc *sc, int bus, int slot, int func,
+ int reg, uint32_t *addr)
+{
+ *addr = (bus << 16) | (slot << 11) | (func << 8) | reg;
+
+ return (0);
+}
+
+static uint32_t
+gt_pci_read_config(device_t dev, int bus, int slot, int func, int reg,
+ int bytes)
+{
+ struct gt_pci_softc *sc = device_get_softc(dev);
+ uint32_t data;
+ uint32_t addr;
+ uint32_t shift, mask;
+
+ if (gt_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr))
+ return (uint32_t)(-1);
+
+ /* Clear cause register bits. */
+ GT_REGVAL(GT_INTR_CAUSE) = 0;
+
+ GT_REGVAL(GT_PCI0_CFG_ADDR) = (1 << 31) | addr;
+ data = GT_REGVAL(GT_PCI0_CFG_DATA);
+
+ /* Check for master abort. */
+ if (GT_REGVAL(GT_INTR_CAUSE) & (GTIC_MASABORT0 | GTIC_TARABORT0))
+ data = (uint32_t) -1;
+
+ /*
+ * XXX: We assume that words readed from GT chip are BE.
+ * Should we set the mode explicitly during chip
+ * Initialization?
+ */
+ switch(reg % 4)
+ {
+ case 3:
+ shift = 24;
+ break;
+ case 2:
+ shift = 16;
+ break;
+ case 1:
+ shift = 8;
+ break;
+ default:
+ shift = 0;
+ break;
+ }
+
+ switch(bytes)
+ {
+ case 1:
+ mask = 0xff;
+ data = (data >> shift) & mask;
+ break;
+ case 2:
+ mask = 0xffff;
+ if(reg % 4 == 0)
+ data = data & mask;
+ else
+ data = (data >> 16) & mask;
+ break;
+ case 4:
+ break;
+ default:
+ panic("gt_pci_readconfig: wrong bytes count");
+ break;
+ }
+#if 0
+ printf("PCICONF_READ(%02x:%02x.%02x[%04x] -> %02x(%d)\n",
+ bus, slot, func, reg, data, bytes);
+#endif
+
+ return (data);
+}
+
+static void
+gt_pci_write_config(device_t dev, int bus, int slot, int func, int reg,
+ uint32_t data, int bytes)
+{
+ struct gt_pci_softc *sc = device_get_softc(dev);
+ uint32_t addr;
+ uint32_t reg_data;
+ uint32_t shift, mask;
+
+ if(bytes != 4)
+ {
+ reg_data = gt_pci_read_config(dev, bus, slot, func, reg, 4);
+
+ /*
+ * XXX: We assume that words readed from GT chip are BE.
+ * Should we set the mode explicitly during chip
+ * Initialization?
+ */
+ switch(reg % 4)
+ {
+ case 3:
+ shift = 24;
+ break;
+ case 2:
+ shift = 16;
+ break;
+ case 1:
+ shift = 8;
+ break;
+ default:
+ shift = 0;
+ break;
+ }
+
+ switch(bytes)
+ {
+ case 1:
+ mask = 0xff;
+ data = (reg_data & ~ (mask << shift)) | (data << shift);
+ break;
+ case 2:
+ mask = 0xffff;
+ if(reg % 4 == 0)
+ data = (reg_data & ~mask) | data;
+ else
+ data = (reg_data & ~ (mask << shift)) |
+ (data << shift);
+ break;
+ case 4:
+ break;
+ default:
+ panic("gt_pci_readconfig: wrong bytes count");
+ break;
+ }
+ }
+
+ if (gt_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr))
+ return;
+
+ /* The galileo has problems accessing device 31. */
+ if (bus == 0 && slot == 31)
+ return;
+
+ /* XXX: no support for bus > 0 yet */
+ if (bus > 0)
+ return;
+
+ /* Clear cause register bits. */
+ GT_REGVAL(GT_INTR_CAUSE) = 0;
+
+ GT_REGVAL(GT_PCI0_CFG_ADDR) = (1 << 31) | addr;
+ GT_REGVAL(GT_PCI0_CFG_DATA) = data;
+}
+
+static int
+gt_pci_route_interrupt(device_t pcib, device_t dev, int pin)
+{
+ int bus;
+ int device;
+ int func;
+ /* struct gt_pci_softc *sc = device_get_softc(pcib); */
+ bus = pci_get_bus(dev);
+ device = pci_get_slot(dev);
+ func = pci_get_function(dev);
+ /*
+ * XXXMIPS: We need routing logic. This is just a stub .
+ */
+ switch (device) {
+ case 9: /*
+ * PIIX4 IDE adapter. HW IRQ0
+ */
+ return 0;
+ default:
+ printf("No mapping for %d/%d/%d/%d\n", bus, device, func, pin);
+
+ }
+ return (0);
+
+}
+
+static int
+gt_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
+{
+ struct gt_pci_softc *sc = device_get_softc(dev);
+ switch (which) {
+ case PCIB_IVAR_DOMAIN:
+ *result = 0;
+ return (0);
+ case PCIB_IVAR_BUS:
+ *result = sc->sc_busno;
+ return (0);
+
+ }
+ return (ENOENT);
+}
+
+static int
+gt_write_ivar(device_t dev, device_t child, int which, uintptr_t result)
+{
+ struct gt_pci_softc * sc = device_get_softc(dev);
+
+ switch (which) {
+ case PCIB_IVAR_BUS:
+ sc->sc_busno = result;
+ return (0);
+ }
+ return (ENOENT);
+}
+
+static struct resource *
+gt_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct gt_pci_softc *sc = device_get_softc(bus);
+ struct resource *rv = NULL;
+ struct rman *rm;
+ bus_space_tag_t bt = 0;
+ bus_space_handle_t bh = 0;
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->sc_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ rm = &sc->sc_mem_rman;
+ bt = sc->sc_pcimem;
+ bh = sc->sc_mem;
+ break;
+ case SYS_RES_IOPORT:
+ rm = &sc->sc_io_rman;
+ bt = sc->sc_pciio;
+ bh = sc->sc_io;
+ break;
+ default:
+ return (NULL);
+ }
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == NULL)
+ return (NULL);
+ rman_set_rid(rv, *rid);
+ if (type != SYS_RES_IRQ) {
+ bh += (rman_get_start(rv));
+
+ rman_set_bustag(rv, bt);
+ rman_set_bushandle(rv, bh);
+ if (flags & RF_ACTIVE) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+ }
+ return (rv);
+}
+
+static int
+gt_pci_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ bus_space_handle_t p;
+ int error;
+
+ if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
+ error = bus_space_map(rman_get_bustag(r),
+ rman_get_bushandle(r), rman_get_size(r), 0, &p);
+ if (error)
+ return (error);
+ rman_set_bushandle(r, p);
+ }
+ return (rman_activate_resource(r));
+}
+
+static int
+gt_pci_setup_intr(device_t dev, device_t child, struct resource *ires,
+ int flags, driver_filter_t *filt, driver_intr_t *handler,
+ void *arg, void **cookiep)
+{
+ struct gt_pci_softc *sc = device_get_softc(dev);
+ struct intr_event *event;
+ int irq, error;
+
+ irq = rman_get_start(ires);
+ if (irq >= ICU_LEN || irq == 2)
+ panic("%s: bad irq or type", __func__);
+
+ event = sc->sc_eventstab[irq];
+ if (event == NULL) {
+ error = intr_event_create(&event, (void *)irq, 0,
+ (mask_fn)mips_mask_irq, (mask_fn)mips_unmask_irq,
+ (mask_fn)mips_unmask_irq, NULL, "gt_pci intr%d:", irq);
+ if (error)
+ return 0;
+ sc->sc_eventstab[irq] = event;
+ }
+
+ intr_event_add_handler(event, device_get_nameunit(child), filt,
+ handler, arg, intr_priority(flags), flags, cookiep);
+
+ /* Enable it, set trigger mode. */
+ sc->sc_imask &= ~(1 << irq);
+ sc->sc_elcr &= ~(1 << irq);
+
+ gt_pci_set_icus(sc);
+
+ return 0;
+}
+
+static int
+gt_pci_teardown_intr(device_t dev, device_t child, struct resource *res,
+ void *cookie)
+{
+ return (intr_event_remove_handler(cookie));
+}
+
+static device_method_t gt_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, gt_pci_probe),
+ DEVMETHOD(device_attach, gt_pci_attach),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_read_ivar, gt_read_ivar),
+ DEVMETHOD(bus_write_ivar, gt_write_ivar),
+ DEVMETHOD(bus_alloc_resource, gt_pci_alloc_resource),
+ DEVMETHOD(bus_release_resource, bus_generic_release_resource),
+ DEVMETHOD(bus_activate_resource, gt_pci_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+ DEVMETHOD(bus_setup_intr, gt_pci_setup_intr),
+ DEVMETHOD(bus_teardown_intr, gt_pci_teardown_intr),
+
+ /* pcib interface */
+ DEVMETHOD(pcib_maxslots, gt_pci_maxslots),
+ DEVMETHOD(pcib_read_config, gt_pci_read_config),
+ DEVMETHOD(pcib_write_config, gt_pci_write_config),
+ DEVMETHOD(pcib_route_interrupt, gt_pci_route_interrupt),
+
+ {0, 0}
+};
+
+static driver_t gt_pci_driver = {
+ "pcib",
+ gt_pci_methods,
+ sizeof(struct gt_pci_softc),
+};
+
+static devclass_t gt_pci_devclass;
+
+DRIVER_MODULE(gt_pci, gt, gt_pci_driver, gt_pci_devclass, 0, 0);
diff --git a/sys/mips/mips32/malta/gtreg.h b/sys/mips/mips32/malta/gtreg.h
new file mode 100644
index 0000000..8fa05a0
--- /dev/null
+++ b/sys/mips/mips32/malta/gtreg.h
@@ -0,0 +1,126 @@
+/* $NetBSD: gtreg.h,v 1.2 2005/12/24 20:07:03 perry Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION 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$
+ */
+
+
+
+#define GT_REGVAL(x) *((volatile u_int32_t *) \
+ (MIPS_PHYS_TO_KSEG1(MALTA_CORECTRL_BASE + (x))))
+
+/* CPU Configuration Register Map */
+#define GT_CPU_INT 0x000
+#define GT_MULTIGT 0x120
+
+/* CPU Address Decode Register Map */
+
+/* CPU Error Report Register Map */
+
+/* CPU Sync Barrier Register Map */
+
+/* SDRAM and Device Address Decode Register Map */
+
+/* SDRAM Configuration Register Map */
+
+/* SDRAM Parameters Register Map */
+
+/* ECC Register Map */
+
+/* Device Parameters Register Map */
+
+/* DMA Record Register Map */
+
+/* DMA Arbiter Register Map */
+
+/* Timer/Counter Register Map */
+//#define GT_TC_0 0x850
+//#define GT_TC_1 0x854
+//#define GT_TC_2 0x858
+//#define GT_TC_3 0x85c
+//#define GT_TC_CONTROL 0x864
+
+/* PCI Internal Register Map */
+#define GT_PCI0_CFG_ADDR 0xcf8
+#define GT_PCI0_CFG_DATA 0xcfc
+#define GT_PCI0_INTR_ACK 0xc34
+
+/* Interrupts Register Map */
+#define GT_INTR_CAUSE 0xc18
+#define GTIC_INTSUM 0x00000001
+#define GTIC_MEMOUT 0x00000002
+#define GTIC_DMAOUT 0x00000004
+#define GTIC_CPUOUT 0x00000008
+#define GTIC_DMA0COMP 0x00000010
+#define GTIC_DMA1COMP 0x00000020
+#define GTIC_DMA2COMP 0x00000040
+#define GTIC_DMA3COMP 0x00000080
+#define GTIC_T0EXP 0x00000100
+#define GTIC_T1EXP 0x00000200
+#define GTIC_T2EXP 0x00000400
+#define GTIC_T3EXP 0x00000800
+#define GTIC_MASRDERR0 0x00001000
+#define GTIC_SLVWRERR0 0x00002000
+#define GTIC_MASWRERR0 0x00004000
+#define GTIC_SLVRDERR0 0x00008000
+#define GTIC_ADDRERR0 0x00010000
+#define GTIC_MEMERR 0x00020000
+#define GTIC_MASABORT0 0x00040000
+#define GTIC_TARABORT0 0x00080000
+#define GTIC_RETRYCNT0 0x00100000
+#define GTIC_PMCINT_0 0x00200000
+#define GTIC_CPUINT 0x0c300000
+#define GTIC_PCINT 0xc3000000
+#define GTIC_CPUINTSUM 0x40000000
+#define GTIC_PCIINTSUM 0x80000000
+
+/* PCI Configuration Register Map */
+//#define GT_PCICONFIGBASE 0
+//#define GT_PCIDID BONITO(GT_PCICONFIGBASE + 0x00)
+//#define GT_PCICMD BONITO(GT_PCICONFIGBASE + 0x04)
+//#define GT_PCICLASS BONITO(GT_PCICONFIGBASE + 0x08)
+//#define GT_PCILTIMER BONITO(GT_PCICONFIGBASE + 0x0c)
+//#define GT_PCIBASE0 BONITO(GT_PCICONFIGBASE + 0x10)
+//#define GT_PCIBASE1 BONITO(GT_PCICONFIGBASE + 0x14)
+//#define GT_PCIBASE2 BONITO(GT_PCICONFIGBASE + 0x18)
+//#define GT_PCIEXPRBASE BONITO(GT_PCICONFIGBASE + 0x30)
+//#define GT_PCIINT BONITO(GT_PCICONFIGBASE + 0x3c)
+
+/* PCI Configuration, Function 1, Register Map */
+
+/* I2O Support Register Map */
diff --git a/sys/mips/mips32/malta/gtvar.h b/sys/mips/mips32/malta/gtvar.h
new file mode 100644
index 0000000..f7830ef
--- /dev/null
+++ b/sys/mips/mips32/malta/gtvar.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2005 Olivier Houchard. 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.
+ */
+
+/* $FreeBSD$ */
+
+#ifndef _GTVAR_H_
+#define _GTVAR_H_
+
+#include <sys/rman.h>
+
+struct gt_softc {
+ device_t dev;
+};
+
+#endif /* _GTVAR_H_ */
diff --git a/sys/mips/mips32/malta/malta_machdep.c b/sys/mips/mips32/malta/malta_machdep.c
new file mode 100644
index 0000000..7464c60
--- /dev/null
+++ b/sys/mips/mips32/malta/malta_machdep.c
@@ -0,0 +1,305 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
+ * 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 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 THE 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$
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/cons.h>
+#include <sys/exec.h>
+#include <sys/ucontext.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/md_var.h>
+#include <machine/pmap.h>
+#include <machine/trap.h>
+
+#ifdef TICK_USE_YAMON_FREQ
+#include <mips/mips32/malta/yamon.h>
+#endif
+
+#ifdef TICK_USE_MALTA_RTC
+#include <mips/mips4k/malta/maltareg.h>
+#include <dev/mc146818/mc146818reg.h>
+#include <isa/rtc.h>
+#endif
+
+#include <mips/mips32/malta/maltareg.h>
+
+extern int *edata;
+extern int *end;
+
+void lcd_init(void);
+void lcd_puts(char *);
+void malta_reset(void);
+
+/*
+ * Offsets to MALTA LCD characters.
+ */
+static int malta_lcd_offs[] = {
+ MALTA_ASCIIPOS0,
+ MALTA_ASCIIPOS1,
+ MALTA_ASCIIPOS2,
+ MALTA_ASCIIPOS3,
+ MALTA_ASCIIPOS4,
+ MALTA_ASCIIPOS5,
+ MALTA_ASCIIPOS6,
+ MALTA_ASCIIPOS7
+};
+
+/*
+ * Put character to Malta LCD at given position.
+ */
+static void
+malta_lcd_putc(int pos, char c)
+{
+ void *addr;
+ char *ch;
+
+ if (pos < 0 || pos > 7)
+ return;
+ addr = (void *)(MALTA_ASCII_BASE + malta_lcd_offs[pos]);
+ ch = (char *)MIPS_PHYS_TO_KSEG0(addr);
+ *ch = c;
+}
+
+/*
+ * Print given string on LCD.
+ */
+static void
+malta_lcd_print(char *str)
+{
+ int i;
+
+ if (str == NULL)
+ return;
+
+ for (i = 0; *str != '\0'; i++, str++)
+ malta_lcd_putc(i, *str);
+}
+
+void
+lcd_init(void)
+{
+ malta_lcd_print("FreeBSD_");
+}
+
+void
+lcd_puts(char *s)
+{
+ malta_lcd_print(s);
+}
+
+#ifdef TICK_USE_MALTA_RTC
+static __inline uint8_t
+rtcin(uint8_t addr)
+{
+
+ *((volatile uint8_t *)
+ MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCADR))) = addr;
+ return (*((volatile uint8_t *)
+ MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCDAT))));
+}
+
+static __inline void
+writertc(uint8_t addr, uint8_t val)
+{
+
+ *((volatile uint8_t *)
+ MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCADR))) = addr;
+ *((volatile uint8_t *)
+ MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCDAT))) = val;
+}
+#endif
+
+static void
+mips_init(void)
+{
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ phys_avail[i] = 0;
+ }
+
+ /* phys_avail regions are in bytes */
+ phys_avail[0] = MIPS_KSEG0_TO_PHYS((vm_offset_t)&end);
+ phys_avail[1] = ctob(realmem);
+
+ physmem = realmem;
+
+ init_param1();
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+#ifdef DDB
+ kdb_init();
+#endif
+}
+
+void
+platform_halt(void)
+{
+
+}
+
+
+void
+platform_identify(void)
+{
+
+}
+
+/*
+ * Perform a board-level soft-reset.
+ * Note that this is not emulated by gxemul.
+ */
+void
+platform_reset(void)
+{
+ char *c;
+
+ c = (char *)MIPS_PHYS_TO_KSEG0(MALTA_SOFTRES);
+ *c = MALTA_GORESET;
+}
+
+void
+platform_trap_enter(void)
+{
+
+}
+
+void
+platform_trap_exit(void)
+{
+
+}
+
+void
+platform_start(__register_t a0, __register_t a1, __register_t a2,
+ __register_t a3)
+{
+ vm_offset_t kernend;
+ uint64_t platform_counter_freq;
+ int argc = a0;
+ char **argv = (char **)a1;
+ char **envp = (char **)a2;
+ unsigned int memsize = a3;
+ int i;
+
+ /* clear the BSS and SBSS segments */
+ kernend = round_page((vm_offset_t)&end);
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+ cninit();
+ printf("entry: platform_start()\n");
+
+ bootverbose = 1;
+ if (bootverbose) {
+ printf("cmd line: ");
+ for (i = 0; i < argc; i++)
+ printf("%s ", argv[i]);
+ printf("\n");
+
+ printf("envp:\n");
+ for (i = 0; envp[i]; i += 2)
+ printf("\t%s = %s\n", envp[i], envp[i+1]);
+
+ printf("memsize = %08x\n", memsize);
+ }
+
+ realmem = btoc(memsize);
+ mips_init();
+
+ do {
+#if defined(TICK_USE_YAMON_FREQ)
+ /*
+ * If we are running on a board which uses YAMON firmware,
+ * then query CPU pipeline clock from the syscon object.
+ * If unsuccessful, use hard-coded default.
+ */
+ platform_counter_freq = yamon_getcpufreq();
+ if (platform_counter_freq == 0)
+ platform_counter_freq = MIPS_DEFAULT_HZ;
+
+#elif defined(TICK_USE_MALTA_RTC)
+ /*
+ * If we are running on a board with the MC146818 RTC,
+ * use it to determine CPU pipeline clock frequency.
+ */
+ u_int64_t counterval[2];
+
+ /* Set RTC to binary mode. */
+ writertc(RTC_STATUSB, (rtcin(RTC_STATUSB) | RTCSB_BCD));
+
+ /* Busy-wait for falling edge of RTC update. */
+ while (((rtcin(RTC_STATUSA) & RTCSA_TUP) == 0))
+ ;
+ while (((rtcin(RTC_STATUSA)& RTCSA_TUP) != 0))
+ ;
+ counterval[0] = mips_rd_count();
+
+ /* Busy-wait for falling edge of RTC update. */
+ while (((rtcin(RTC_STATUSA) & RTCSA_TUP) == 0))
+ ;
+ while (((rtcin(RTC_STATUSA)& RTCSA_TUP) != 0))
+ ;
+ counterval[1] = mips_rd_count();
+
+ platform_counter_freq = counterval[1] - counterval[0];
+#endif
+ } while(0);
+
+ mips_timer_init_params(platform_counter_freq, 0);
+}
diff --git a/sys/mips/mips32/malta/maltareg.h b/sys/mips/mips32/malta/maltareg.h
new file mode 100644
index 0000000..f2a7d08
--- /dev/null
+++ b/sys/mips/mips32/malta/maltareg.h
@@ -0,0 +1,243 @@
+/* $NetBSD: maltareg.h,v 1.1 2002/03/07 14:44:04 simonb Exp $ */
+
+/*
+ * Copyright 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Simon Burge 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.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ Memory Map
+
+ 0000.0000 * 128MB Typically SDRAM (on Core Board)
+ 0800.0000 * 256MB Typically PCI
+ 1800.0000 * 62MB Typically PCI
+ 1be0.0000 * 2MB Typically System controller's internal registers
+ 1c00.0000 * 32MB Typically not used
+ 1e00.0000 4MB Monitor Flash
+ 1e40.0000 12MB reserved
+ 1f00.0000 12MB Switches
+ LEDs
+ ASCII display
+ Soft reset
+ FPGA revision number
+ CBUS UART (tty2)
+ General Purpose I/O
+ I2C controller
+ 1f10.0000 * 11MB Typically System Controller specific
+ 1fc0.0000 4MB Maps to Monitor Flash
+ 1fd0.0000 * 3MB Typically System Controller specific
+
+ * depends on implementation of the Core Board and of software
+ */
+
+/*
+ CPU interrupts
+
+ NMI South Bridge or NMI button
+ 0 South Bridge INTR
+ 1 South Bridge SMI
+ 2 CBUS UART (tty2)
+ 3 COREHI (Core Card)
+ 4 CORELO (Core Card)
+ 5 Not used, driven inactive (typically CPU internal timer interrupt
+
+ IRQ mapping (as used by YAMON)
+
+ 0 Timer South Bridge
+ 1 Keyboard SuperIO
+ 2 Reserved by South Bridge (for cascading)
+ 3 UART (tty1) SuperIO
+ 4 UART (tty0) SuperIO
+ 5 Not used
+ 6 Floppy Disk SuperIO
+ 7 Parallel Port SuperIO
+ 8 Real Time Clock South Bridge
+ 9 I2C bus South Bridge
+ 10 PCI A,B,eth PCI slot 1..4, Ethernet
+ 11 PCI C,audio PCI slot 1..4, Audio, USB (South Bridge)
+ PCI D,USB
+ 12 Mouse SuperIO
+ 13 Reserved by South Bridge
+ 14 Primary IDE Primary IDE slot
+ 15 Secondary IDE Secondary IDE slot/Compact flash connector
+ */
+
+#define MALTA_SYSTEMRAM_BASE 0x00000000 /* System RAM: */
+#define MALTA_SYSTEMRAM_SIZE 0x08000000 /* 128 MByte */
+
+#define MALTA_PCIMEM1_BASE 0x08000000 /* PCI 1 memory: */
+#define MALTA_PCIMEM1_SIZE 0x08000000 /* 128 MByte */
+
+#define MALTA_PCIMEM2_BASE 0x10000000 /* PCI 2 memory: */
+#define MALTA_PCIMEM2_SIZE 0x08000000 /* 128 MByte */
+
+#define MALTA_PCIMEM3_BASE 0x18000000 /* PCI 3 memory */
+#define MALTA_PCIMEM3_SIZE 0x03e00000 /* 62 MByte */
+
+#define MALTA_CORECTRL_BASE 0x1be00000 /* Core control: */
+#define MALTA_CORECTRL_SIZE 0x00200000 /* 2 MByte */
+
+#define MALTA_RESERVED_BASE1 0x1c000000 /* Reserved: */
+#define MALTA_RESERVED_SIZE1 0x02000000 /* 32 MByte */
+
+#define MALTA_MONITORFLASH_BASE 0x1e000000 /* Monitor Flash: */
+#define MALTA_MONITORFLASH_SIZE 0x003e0000 /* 4 MByte */
+#define MALTA_MONITORFLASH_SECTORSIZE 0x00010000 /* Sect. = 64 KB */
+
+#define MALTA_FILEFLASH_BASE 0x1e3e0000 /* File Flash (for monitor): */
+#define MALTA_FILEFLASH_SIZE 0x00020000 /* 128 KByte */
+
+#define MALTA_FILEFLASH_SECTORSIZE 0x00010000 /* Sect. = 64 KB */
+
+#define MALTA_RESERVED_BASE2 0x1e400000 /* Reserved: */
+#define MALTA_RESERVED_SIZE2 0x00c00000 /* 12 MByte */
+
+#define MALTA_FPGA_BASE 0x1f000000 /* FPGA: */
+#define MALTA_FPGA_SIZE 0x00c00000 /* 12 MByte */
+
+#define MALTA_NMISTATUS (MALTA_FPGA_BASE + 0x24)
+#define MALTA_NMI_SB 0x2 /* Pending NMI from the South Bridge */
+#define MALTA_NMI_ONNMI 0x1 /* Pending NMI from the ON/NMI push button */
+
+#define MALTA_NMIACK (MALTA_FPGA_BASE + 0x104)
+#define MALTA_NMIACK_ONNMI 0x1 /* Write 1 to acknowledge ON/NMI */
+
+#define MALTA_SWITCH (MALTA_FPGA_BASE + 0x200)
+#define MALTA_SWITCH_MASK 0xff /* settings of DIP switch S2 */
+
+#define MALTA_STATUS (MALTA_FPGA_BASE + 0x208)
+#define MALTA_ST_MFWR 0x10 /* Monitor Flash is write protected (JP1) */
+#define MALTA_S54 0x08 /* switch S5-4 - set YAMON factory default mode */
+#define MALTA_S53 0x04 /* switch S5-3 */
+#define MALTA_BIGEND 0x02 /* switch S5-2 - big endian mode */
+
+#define MALTA_JMPRS (MALTA_FPGA_BASE + 0x210)
+#define MALTA_JMPRS_PCICLK 0x1c /* PCI clock frequency */
+#define MALTA_JMPRS_EELOCK 0x02 /* I2C EEPROM is write protected */
+
+#define MALTA_LEDBAR (MALTA_FPGA_BASE + 0x408)
+#define MALTA_ASCIIWORD (MALTA_FPGA_BASE + 0x410)
+#define MALTA_ASCII_BASE (MALTA_FPGA_BASE + 0x418)
+#define MALTA_ASCIIPOS0 0x00
+#define MALTA_ASCIIPOS1 0x08
+#define MALTA_ASCIIPOS2 0x10
+#define MALTA_ASCIIPOS3 0x18
+#define MALTA_ASCIIPOS4 0x20
+#define MALTA_ASCIIPOS5 0x28
+#define MALTA_ASCIIPOS6 0x30
+#define MALTA_ASCIIPOS7 0x38
+
+#define MALTA_SOFTRES (MALTA_FPGA_BASE + 0x500)
+#define MALTA_GORESET 0x42 /* write this to MALTA_SOFTRES for board reset */
+
+/*
+ * BRKRES is the number of milliseconds before a "break" on tty will
+ * trigger a reset. A value of 0 will disable the reset.
+ */
+#define MALTA_BRKRES (MALTA_FPGA_BASE + 0x508)
+#define MALTA_BRKRES_MASK 0xff
+
+#define MALTA_CBUSUART (MALTA_FPGA_BASE + 0x900)
+/* 16C550C UART, 8 bit registers on 8 byte boundaries */
+/* RXTX 0x00 */
+/* INTEN 0x08 */
+/* IIFIFO 0x10 */
+/* LCTRL 0x18 */
+/* MCTRL 0x20 */
+/* LSTAT 0x28 */
+/* MSTAT 0x30 */
+/* SCRATCH 0x38 */
+#define MALTA_CBUSUART_INTR 2
+
+#define MALTA_GPIO_BASE (MALTA_FPGA_BASE + 0xa00)
+#define MALTA_GPOUT 0x0
+#define MALTA_GPINP 0x8
+
+#define MALTA_I2C_BASE (MALTA_FPGA_BASE + 0xb00)
+#define MALTA_I2CINP 0x00
+#define MALTA_I2COE 0x08
+#define MALTA_I2COUT 0x10
+#define MALTA_I2CSEL 0x18
+
+#define MALTA_BOOTROM_BASE 0x1fc00000 /* Boot ROM: */
+#define MALTA_BOOTROM_SIZE 0x00400000 /* 4 MByte */
+
+#define MALTA_REVISION 0x1fc00010
+#define MALTA_REV_FPGRV 0xff0000 /* CBUS FPGA revision */
+#define MALTA_REV_CORID 0x00fc00 /* Core Board ID */
+#define MALTA_REV_CORRV 0x000300 /* Core Board Revision */
+#define MALTA_REV_PROID 0x0000f0 /* Product ID */
+#define MALTA_REV_PRORV 0x00000f /* Product Revision */
+
+/* PCI definitions */
+#define MALTA_SOUTHBRIDGE_INTR 0
+
+#define MALTA_PCI0_IO_BASE MALTA_PCIMEM3_BASE
+#define MALTA_PCI0_ADDR( addr ) (MALTA_PCI0_IO_BASE + (addr))
+
+#define MALTA_RTCADR 0x70 // MALTA_PCI_IO_ADDR8(0x70)
+#define MALTA_RTCDAT 0x71 // MALTA_PCI_IO_ADDR8(0x71)
+
+#define MALTA_SMSC_COM1_ADR 0x3f8
+#define MALTA_SMSC_COM2_ADR 0x2f8
+#define MALTA_UART0ADR MALTA_PCI0_ADDR(MALTA_SMSC_COM1_ADR)
+#define MALTA_UART1ADR MALTA_SMSC_COM2_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_COM2_ADR)
+
+#define MALTA_SMSC_1284_ADR 0x378
+#define MALTA_1284ADR MALTA_SMSC_1284_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_1284_ADR)
+
+#define MALTA_SMSC_FDD_ADR 0x3f0
+#define MALTA_FDDADR MALTA_SMSC_FDD_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_FDD_ADR)
+
+#define MALTA_SMSC_KYBD_ADR 0x60 /* Fixed 0x60, 0x64 */
+#define MALTA_KYBDADR MALTA_SMSC_KYBD_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_KYBD_ADR)
+#define MALTA_SMSC_MOUSE_ADR MALTA_SMSC_KYBD_ADR
+#define MALTA_MOUSEADR MALTA_KYBDADR
+
+
+#define MALTA_DMA_PCI_PCIBASE 0x00000000UL
+#define MALTA_DMA_PCI_PHYSBASE 0x00000000UL
+#define MALTA_DMA_PCI_SIZE (256 * 1024 * 1024)
+
+#define MALTA_DMA_ISA_PCIBASE 0x00800000UL
+#define MALTA_DMA_ISA_PHYSBASE 0x00000000UL
+#define MALTA_DMA_ISA_SIZE (8 * 1024 * 1024)
+
+#ifndef _LOCORE
+void led_bar(uint8_t);
+void led_display_word(uint32_t);
+void led_display_str(const char *);
+void led_display_char(int, uint8_t);
+#endif
diff --git a/sys/mips/mips32/malta/obio.c b/sys/mips/mips32/malta/obio.c
new file mode 100644
index 0000000..9e2fd7e
--- /dev/null
+++ b/sys/mips/mips32/malta/obio.c
@@ -0,0 +1,185 @@
+/* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */
+
+/*-
+ * Copyright (c) 2001, 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.
+ */
+
+/*
+ * On-board device autoconfiguration support for Intel IQ80321
+ * evaluation boards.
+ */
+
+#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 <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <mips/mips32/malta/maltareg.h>
+#include <mips/mips32/malta/obiovar.h>
+
+int obio_probe(device_t);
+int obio_attach(device_t);
+
+/*
+ * A bit tricky and hackish. Since we need OBIO to rely
+ * on PCI we make it pseudo-pci device. But there should
+ * be only one such device, so we use this static flag
+ * to prevent false positives on every realPCI device probe.
+ */
+static int have_one = 0;
+
+int
+obio_probe(device_t dev)
+{
+ if(!have_one)
+ {
+ have_one = 1;
+ return 0;
+ }
+ else
+ return (ENXIO);
+}
+
+int
+obio_attach(device_t dev)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+
+ sc->oba_st = MIPS_BUS_SPACE_IO;
+ sc->oba_addr = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR);
+ sc->oba_size = MALTA_PCIMEM3_SIZE;
+ sc->oba_rman.rm_type = RMAN_ARRAY;
+ sc->oba_rman.rm_descr = "OBIO I/O";
+ if (rman_init(&sc->oba_rman) != 0 ||
+ rman_manage_region(&sc->oba_rman,
+ sc->oba_addr, sc->oba_addr + sc->oba_size) != 0)
+ panic("obio_attach: failed to set up I/O rman");
+ sc->oba_irq_rman.rm_type = RMAN_ARRAY;
+ sc->oba_irq_rman.rm_descr = "OBIO IRQ";
+
+ /*
+ * This module is intended for UART purposes only and
+ * it's IRQ is 4
+ */
+ if (rman_init(&sc->oba_irq_rman) != 0 ||
+ rman_manage_region(&sc->oba_irq_rman, 4, 4) != 0)
+ panic("obio_attach: failed to set up IRQ rman");
+
+ device_add_child(dev, "uart", 0);
+ bus_generic_probe(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static struct resource *
+obio_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct resource *rv;
+ struct rman *rm;
+ bus_space_tag_t bt = 0;
+ bus_space_handle_t bh = 0;
+ struct obio_softc *sc = device_get_softc(bus);
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->oba_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ return (NULL);
+ case SYS_RES_IOPORT:
+ rm = &sc->oba_rman;
+ bt = sc->oba_st;
+ bh = sc->oba_addr;
+ start = bh;
+ break;
+ default:
+ return (NULL);
+ }
+
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == NULL)
+ return (NULL);
+ if (type == SYS_RES_IRQ)
+ return (rv);
+ rman_set_rid(rv, *rid);
+ rman_set_bustag(rv, bt);
+ rman_set_bushandle(rv, bh);
+
+ if (0) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+ return (rv);
+
+}
+
+static int
+obio_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ return (0);
+}
+static device_method_t obio_methods[] = {
+ DEVMETHOD(device_probe, obio_probe),
+ DEVMETHOD(device_attach, obio_attach),
+
+ DEVMETHOD(bus_alloc_resource, obio_alloc_resource),
+ DEVMETHOD(bus_activate_resource, obio_activate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ {0, 0},
+};
+
+static driver_t obio_driver = {
+ "obio",
+ obio_methods,
+ sizeof(struct obio_softc),
+};
+static devclass_t obio_devclass;
+
+DRIVER_MODULE(obio, pci, obio_driver, obio_devclass, 0, 0);
diff --git a/sys/mips/mips32/malta/obiovar.h b/sys/mips/mips32/malta/obiovar.h
new file mode 100644
index 0000000..801d461
--- /dev/null
+++ b/sys/mips/mips32/malta/obiovar.h
@@ -0,0 +1,58 @@
+/* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */
+
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _MALTA_OBIOVAR_H_
+#define _MALTA_OBIOVAR_H_
+
+#include <sys/rman.h>
+
+struct obio_softc {
+ bus_space_tag_t oba_st; /* bus space tag */
+ bus_addr_t oba_addr; /* address of device */
+ bus_size_t oba_size; /* size of device */
+ int oba_width; /* bus width */
+ int oba_irq; /* XINT interrupt bit # */
+ struct rman oba_rman;
+ struct rman oba_irq_rman;
+
+};
+extern struct bus_space obio_bs_tag;
+
+#endif /* _MALTA_OBIOVAR_H_ */
diff --git a/sys/mips/mips32/malta/std.malta b/sys/mips/mips32/malta/std.malta
new file mode 100644
index 0000000..d7ab116
--- /dev/null
+++ b/sys/mips/mips32/malta/std.malta
@@ -0,0 +1,9 @@
+# $FreeBSD$
+files "../mips32/malta/files.malta"
+
+cpu CPU_MIPS4KC
+options ISA_MIPS32
+options SOFTFLOAT
+device pci
+device ata
+device atadisk
diff --git a/sys/mips/mips32/malta/uart_bus_maltausart.c b/sys/mips/mips32/malta/uart_bus_maltausart.c
new file mode 100644
index 0000000..0d95694
--- /dev/null
+++ b/sys/mips/mips32/malta/uart_bus_maltausart.c
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
+ * 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 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 THE 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
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+/*
+ * XXXMIPS:
+ */
+#include <mips/mips32/malta/maltareg.h>
+
+#include "uart_if.h"
+
+static int uart_malta_probe(device_t dev);
+
+extern struct uart_class malta_uart_class;
+
+static device_method_t uart_malta_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_malta_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_malta_driver = {
+ uart_driver_name,
+ uart_malta_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+static int
+uart_malta_probe(device_t dev)
+{
+ struct uart_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ sc->sc_class = &uart_ns8250_class;
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+ sc->sc_sysdev->bas.bst = 0;
+ sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR);
+ sc->sc_bas.bst = 0;
+ sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR);
+ return(uart_bus_probe(dev, 0, 0, 0, 0));
+}
+
+DRIVER_MODULE(uart, obio, uart_malta_driver, uart_devclass, 0, 0);
diff --git a/sys/mips/mips32/malta/uart_cpu_maltausart.c b/sys/mips/mips32/malta/uart_cpu_maltausart.c
new file mode 100644
index 0000000..ee5b163
--- /dev/null
+++ b/sys/mips/mips32/malta/uart_cpu_maltausart.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
+ * 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 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 THE 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.
+ *
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/mips32/malta/maltareg.h>
+
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+extern struct uart_ops malta_usart_ops;
+extern struct bus_space malta_bs_tag;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ di->ops = uart_getops(&uart_ns8250_class);
+ di->bas.chan = 0;
+ di->bas.bst = 0;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+
+ uart_bus_space_io = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR);
+ uart_bus_space_mem = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR);
+ di->bas.bsh = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR);
+ return (0);
+}
diff --git a/sys/mips/mips32/malta/yamon.c b/sys/mips/mips32/malta/yamon.c
new file mode 100644
index 0000000..71ea109
--- /dev/null
+++ b/sys/mips/mips32/malta/yamon.c
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2006 Fill this file and put your name here
+ * 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,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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 THE 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 <mips/mips32/malta/yamon.h>
+
+char *
+yamon_getenv(char *name)
+{
+ char *value;
+ yamon_env_t *p;
+
+ value = NULL;
+ for (p = *fenvp; p->name != NULL; ++p) {
+ if (!strcmp(name, p->name)) {
+ value = p->value;
+ break;
+ }
+ }
+
+ return (value);
+}
+
+uint32_t
+yamon_getcpufreq(void)
+{
+ uint32_t freq;
+ int ret;
+
+ ret = YAMON_SYSCON_READ(SYSCON_BOARD_CPU_CLOCK_FREQ_ID, &freq,
+ sizeof(freq));
+ if (ret != 0)
+ freq = 0;
+
+ return (freq);
+}
diff --git a/sys/mips/mips32/malta/yamon.h b/sys/mips/mips32/malta/yamon.h
new file mode 100644
index 0000000..6970510
--- /dev/null
+++ b/sys/mips/mips32/malta/yamon.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright 2002 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Simon Burge 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MALTA_YAMON_H_
+#define _MALTA_YAMON_H_
+
+#define YAMON_FUNCTION_BASE 0x1fc00500
+
+#define YAMON_PRINT_COUNT_OFS (YAMON_FUNCTION_BASE + 0x04)
+#define YAMON_EXIT_OFS (YAMON_FUNCTION_BASE + 0x20)
+#define YAMON_FLUSH_CACHE_OFS (YAMON_FUNCTION_BASE + 0x2c)
+#define YAMON_PRINT_OFS (YAMON_FUNCTION_BASE + 0x34)
+#define YAMON_REG_CPU_ISR_OFS (YAMON_FUNCTION_BASE + 0x38)
+#define YAMON_DEREG_CPU_ISR_OFS (YAMON_FUNCTION_BASE + 0x3c)
+#define YAMON_REG_IC_ISR_OFS (YAMON_FUNCTION_BASE + 0x40)
+#define YAMON_DEREG_IC_ISR_OFS (YAMON_FUNCTION_BASE + 0x44)
+#define YAMON_REG_ESR_OFS (YAMON_FUNCTION_BASE + 0x48)
+#define YAMON_DEREG_ESR_OFS (YAMON_FUNCTION_BASE + 0x4c)
+#define YAMON_GETCHAR_OFS (YAMON_FUNCTION_BASE + 0x50)
+#define YAMON_SYSCON_READ_OFS (YAMON_FUNCTION_BASE + 0x54)
+
+#define YAMON_FUNC(ofs) (*(uint32_t *)(MIPS_PHYS_TO_KSEG0(ofs)))
+
+typedef void (*t_yamon_print_count)(uint32_t port, char *s, uint32_t count);
+#define YAMON_PRINT_COUNT(s, count) \
+ ((t_yamon_print_count)(YAMON_FUNC(YAMON_PRINT_COUNT_OFS)))(0, s, count)
+
+typedef void (*t_yamon_exit)(uint32_t rc);
+#define YAMON_EXIT(rc) ((t_yamon_exit)(YAMON_FUNC(YAMON_EXIT_OFS)))(rc)
+
+typedef void (*t_yamon_print)(uint32_t port, const char *s);
+#define YAMON_PRINT(s) ((t_yamon_print)(YAMON_FUNC(YAMON_PRINT_OFS)))(0, s)
+
+typedef int (*t_yamon_getchar)(uint32_t port, char *ch);
+#define YAMON_GETCHAR(ch) \
+ ((t_yamon_getchar)(YAMON_FUNC(YAMON_GETCHAR_OFS)))(0, ch)
+
+typedef int t_yamon_syscon_id;
+typedef int (*t_yamon_syscon_read)(t_yamon_syscon_id id, void *param,
+ uint32_t size);
+#define YAMON_SYSCON_READ(id, param, size) \
+ ((t_yamon_syscon_read)(YAMON_FUNC(YAMON_SYSCON_READ_OFS))) \
+ (id, param, size)
+
+typedef struct {
+ char *name;
+ char *value;
+} yamon_env_t;
+
+#define SYSCON_BOARD_CPU_CLOCK_FREQ_ID 34 /* UINT32 */
+#define SYSCON_BOARD_BUS_CLOCK_FREQ_ID 35 /* UINT32 */
+#define SYSCON_BOARD_PCI_FREQ_KHZ_ID 36 /* UINT32 */
+
+char* yamon_getenv(char *name);
+uint32_t yamon_getcpufreq(void);
+
+extern yamon_env_t *fenvp[];
+
+#endif /* _MALTA_YAMON_H_ */
diff --git a/sys/mips/mips32/sentry5/files.sentry5 b/sys/mips/mips32/sentry5/files.sentry5
new file mode 100644
index 0000000..db35232
--- /dev/null
+++ b/sys/mips/mips32/sentry5/files.sentry5
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+# TODO: Add attachment elsehwere in the tree
+# for USB 1.1 OHCI, Ethernet and IPSEC cores
+# which are believed to be devices we have drivers for
+# which just need to be tweaked for attachment to an SSB system bus.
+
+mips/mips32/sentry5/s5_machdep.c standard
+dev/siba/siba.c optional siba
+dev/siba/siba_pcib.c optional siba pci
+mips/mips32/sentry5/siba_cc.c optional siba
+
+# notyet
+#mips/mips32/sentry5/siba_mips.c optional siba
diff --git a/sys/mips/mips32/sentry5/obio.c b/sys/mips/mips32/sentry5/obio.c
new file mode 100644
index 0000000..1c1b9c9
--- /dev/null
+++ b/sys/mips/mips32/sentry5/obio.c
@@ -0,0 +1,187 @@
+/* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */
+
+/*-
+ * Copyright (c) 2001, 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.
+ */
+
+/*
+ * On-board device autoconfiguration support for Broadcom Sentry5
+ * based boards.
+ * XXX This is totally bogus and is just enough to get the console hopefully
+ * running on the sentry5.
+ */
+
+#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 <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <mips/mips32/sentry5/obiovar.h>
+#include <mips/mips32/sentry5/sentry5reg.h>
+
+int obio_probe(device_t);
+int obio_attach(device_t);
+
+/*
+ * A bit tricky and hackish. Since we need OBIO to rely
+ * on PCI we make it pseudo-pci device. But there should
+ * be only one such device, so we use this static flag
+ * to prevent false positives on every realPCI device probe.
+ */
+static int have_one = 0;
+
+int
+obio_probe(device_t dev)
+{
+ if(!have_one)
+ {
+ have_one = 1;
+ return 0;
+ }
+ else
+ return (ENXIO);
+}
+
+int
+obio_attach(device_t dev)
+{
+ struct obio_softc *sc = device_get_softc(dev);
+
+ sc->oba_st = MIPS_BUS_SPACE_IO;
+ sc->oba_addr = MIPS_PHYS_TO_KSEG1(SENTRY5_UART1ADR);
+ sc->oba_size = 0x03FFFFFF; /* XXX sb pci bus 0 aperture size? */
+ sc->oba_rman.rm_type = RMAN_ARRAY;
+ sc->oba_rman.rm_descr = "OBIO I/O";
+ if (rman_init(&sc->oba_rman) != 0 ||
+ rman_manage_region(&sc->oba_rman,
+ sc->oba_addr, sc->oba_addr + sc->oba_size) != 0)
+ panic("obio_attach: failed to set up I/O rman");
+ sc->oba_irq_rman.rm_type = RMAN_ARRAY;
+ sc->oba_irq_rman.rm_descr = "OBIO IRQ";
+
+ /*
+ * This module is intended for UART purposes only and
+ * it's IRQ is 4
+ */
+ if (rman_init(&sc->oba_irq_rman) != 0 ||
+ rman_manage_region(&sc->oba_irq_rman, 4, 4) != 0)
+ panic("obio_attach: failed to set up IRQ rman");
+
+ device_add_child(dev, "uart", 0);
+ bus_generic_probe(dev);
+ bus_generic_attach(dev);
+
+ return (0);
+}
+
+static struct resource *
+obio_alloc_resource(device_t bus, device_t child, int type, int *rid,
+ u_long start, u_long end, u_long count, u_int flags)
+{
+ struct resource *rv;
+ struct rman *rm;
+ bus_space_tag_t bt = 0;
+ bus_space_handle_t bh = 0;
+ struct obio_softc *sc = device_get_softc(bus);
+
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->oba_irq_rman;
+ break;
+ case SYS_RES_MEMORY:
+ return (NULL);
+ case SYS_RES_IOPORT:
+ rm = &sc->oba_rman;
+ bt = sc->oba_st;
+ bh = sc->oba_addr;
+ start = bh;
+ break;
+ default:
+ return (NULL);
+ }
+
+
+ rv = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (rv == NULL)
+ return (NULL);
+ if (type == SYS_RES_IRQ)
+ return (rv);
+ rman_set_rid(rv, *rid);
+ rman_set_bustag(rv, bt);
+ rman_set_bushandle(rv, bh);
+
+ if (0) {
+ if (bus_activate_resource(child, type, *rid, rv)) {
+ rman_release_resource(rv);
+ return (NULL);
+ }
+ }
+ return (rv);
+
+}
+
+static int
+obio_activate_resource(device_t bus, device_t child, int type, int rid,
+ struct resource *r)
+{
+ return (0);
+}
+static device_method_t obio_methods[] = {
+ DEVMETHOD(device_probe, obio_probe),
+ DEVMETHOD(device_attach, obio_attach),
+
+ DEVMETHOD(bus_alloc_resource, obio_alloc_resource),
+ DEVMETHOD(bus_activate_resource, obio_activate_resource),
+ DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
+ DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
+
+ {0, 0},
+};
+
+static driver_t obio_driver = {
+ "obio",
+ obio_methods,
+ sizeof(struct obio_softc),
+};
+static devclass_t obio_devclass;
+
+DRIVER_MODULE(obio, pci, obio_driver, obio_devclass, 0, 0);
diff --git a/sys/mips/mips32/sentry5/obiovar.h b/sys/mips/mips32/sentry5/obiovar.h
new file mode 100644
index 0000000..27c1b37
--- /dev/null
+++ b/sys/mips/mips32/sentry5/obiovar.h
@@ -0,0 +1,58 @@
+/* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */
+
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ */
+
+#ifndef _SENTRY5_OBIOVAR_H_
+#define _SENTRY5_OBIOVAR_H_
+
+#include <sys/rman.h>
+
+struct obio_softc {
+ bus_space_tag_t oba_st; /* bus space tag */
+ bus_addr_t oba_addr; /* address of device */
+ bus_size_t oba_size; /* size of device */
+ int oba_width; /* bus width */
+ int oba_irq; /* XINT interrupt bit # */
+ struct rman oba_rman;
+ struct rman oba_irq_rman;
+
+};
+extern struct bus_space obio_bs_tag;
+
+#endif /* _SENTRY5_OBIOVAR_H_ */
diff --git a/sys/mips/mips32/sentry5/s5_machdep.c b/sys/mips/mips32/sentry5/s5_machdep.c
new file mode 100644
index 0000000..c8a2bae
--- /dev/null
+++ b/sys/mips/mips32/sentry5/s5_machdep.c
@@ -0,0 +1,241 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * 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 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 THE 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 <machine/cpuregs.h>
+
+#include <mips/mips32/sentry5/s5reg.h>
+
+#include "opt_ddb.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/imgact.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/bus.h>
+#include <sys/cpu.h>
+#include <sys/cons.h>
+#include <sys/exec.h>
+#include <sys/ucontext.h>
+#include <sys/proc.h>
+#include <sys/kdb.h>
+#include <sys/ptrace.h>
+#include <sys/reboot.h>
+#include <sys/signalvar.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/user.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pager.h>
+
+#include <machine/cache.h>
+#include <machine/clock.h>
+#include <machine/cpu.h>
+#include <machine/cpuinfo.h>
+#include <machine/cpufunc.h>
+#include <machine/cpuregs.h>
+#include <machine/hwfunc.h>
+#include <machine/intr_machdep.h>
+#include <machine/locore.h>
+#include <machine/md_var.h>
+#include <machine/pte.h>
+#include <machine/sigframe.h>
+#include <machine/tlb.h>
+#include <machine/trap.h>
+#include <machine/vmparam.h>
+
+#ifdef CFE
+#include <dev/cfe/cfe_api.h>
+#endif
+
+#ifdef CFE
+extern uint32_t cfe_handle;
+extern uint32_t cfe_vector;
+#endif
+
+extern int *edata;
+extern int *end;
+
+static void
+mips_init(void)
+{
+ int i;
+
+ printf("entry: mips_init()\n");
+
+#ifdef CFE
+ /*
+ * Query DRAM memory map from CFE.
+ */
+ physmem = 0;
+ for (i = 0; i < 10; i += 2) {
+ int result;
+ uint64_t addr, len, type;
+
+ result = cfe_enummem(i, 0, &addr, &len, &type);
+ if (result < 0) {
+ phys_avail[i] = phys_avail[i + 1] = 0;
+ break;
+ }
+ if (type != CFE_MI_AVAILABLE)
+ continue;
+
+ phys_avail[i] = addr;
+ if (i == 0 && addr == 0) {
+ /*
+ * If this is the first physical memory segment probed
+ * from CFE, omit the region at the start of physical
+ * memory where the kernel has been loaded.
+ */
+ phys_avail[i] += MIPS_KSEG0_TO_PHYS((vm_offset_t)&end);
+ }
+ phys_avail[i + 1] = addr + len;
+ physmem += len;
+ }
+
+ realmem = btoc(physmem);
+#endif
+
+ physmem = realmem;
+
+ init_param1();
+ init_param2(physmem);
+ mips_cpu_init();
+ pmap_bootstrap();
+ mips_proc0_init();
+ mutex_init();
+#ifdef DDB
+ kdb_init();
+#endif
+}
+
+void
+platform_halt(void)
+{
+
+}
+
+
+void
+platform_identify(void)
+{
+
+}
+
+void
+platform_reset(void)
+{
+
+#if defined(CFE)
+ cfe_exit(0, 0);
+#else
+ *((volatile uint8_t *)MIPS_PHYS_TO_KSEG1(SENTRY5_EXTIFADR)) = 0x80;
+#endif
+}
+
+void
+platform_trap_enter(void)
+{
+
+}
+
+void
+platform_trap_exit(void)
+{
+
+}
+
+void
+platform_start(__register_t a0 __unused, __register_t a1 __unused,
+ __register_t a2 __unused, __register_t a3 __unused)
+{
+ vm_offset_t kernend;
+ uint64_t platform_counter_freq;
+
+ /* clear the BSS and SBSS segments */
+ kernend = round_page((vm_offset_t)&end);
+ memset(&edata, 0, kernend - (vm_offset_t)(&edata));
+
+#ifdef CFE
+ /*
+ * Initialize CFE firmware trampolines before
+ * we initialize the low-level console.
+ */
+ if (cfe_handle != 0)
+ cfe_init(cfe_handle, cfe_vector);
+#endif
+ cninit();
+
+#ifdef CFE
+ if (cfe_handle == 0)
+ panic("CFE was not detected by locore.\n");
+#endif
+ mips_init();
+
+# if 0
+ /*
+ * Probe the Broadcom Sentry5's on-chip PLL clock registers
+ * and discover the CPU pipeline clock and bus clock
+ * multipliers from this.
+ * XXX: Wrong place. You have to ask the ChipCommon
+ * or External Interface cores on the SiBa.
+ */
+ uint32_t busmult, cpumult, refclock, clkcfg1;
+#define S5_CLKCFG1_REFCLOCK_MASK 0x0000001F
+#define S5_CLKCFG1_BUSMULT_MASK 0x000003E0
+#define S5_CLKCFG1_BUSMULT_SHIFT 5
+#define S5_CLKCFG1_CPUMULT_MASK 0xFFFFFC00
+#define S5_CLKCFG1_CPUMULT_SHIFT 10
+
+ counter_freq = 100000000; /* XXX */
+
+ clkcfg1 = s5_rd_clkcfg1();
+ printf("clkcfg1 = 0x%08x\n", clkcfg1);
+
+ refclock = clkcfg1 & 0x1F;
+ busmult = ((clkcfg1 & 0x000003E0) >> 5) + 1;
+ cpumult = ((clkcfg1 & 0xFFFFFC00) >> 10) + 1;
+
+ printf("refclock = %u\n", refclock);
+ printf("busmult = %u\n", busmult);
+ printf("cpumult = %u\n", cpumult);
+
+ counter_freq = cpumult * refclock;
+# else
+ platform_counter_freq = 200 * 1000 * 1000; /* Sentry5 is 200MHz */
+# endif
+
+ mips_timer_init_params(platform_counter_freq, 0);
+}
diff --git a/sys/mips/mips32/sentry5/s5reg.h b/sys/mips/mips32/sentry5/s5reg.h
new file mode 100644
index 0000000..71643d0
--- /dev/null
+++ b/sys/mips/mips32/sentry5/s5reg.h
@@ -0,0 +1,58 @@
+/* $FreeBSD$ */
+
+#ifndef _MIPS32_SENTRY5_SENTRY5REG_H_
+#define _MIPS32_SENTRY5_SENTRY5REG_H_
+
+#define SENTRY5_UART0ADR 0x18000300
+#define SENTRY5_UART1ADR 0x18000400
+
+/* Reset register implemented here in a PLD device. */
+#define SENTRY5_EXTIFADR 0x1F000000
+#define SENTRY5_DORESET 0x80
+
+/*
+ * Custom CP0 register macros.
+ * XXX: This really needs the mips cpuregs.h file for the barrier.
+ */
+#define S5_RDRW32_C0P0_CUST22(n,r) \
+static __inline u_int32_t \
+s5_rd_ ## n (void) \
+{ \
+ int v0; \
+ __asm __volatile ("mfc0 %[v0], $22, "__XSTRING(r)" ;" \
+ : [v0] "=&r"(v0)); \
+ /*mips_barrier();*/ \
+ return (v0); \
+} \
+static __inline void \
+s5_wr_ ## n (u_int32_t a0) \
+{ \
+ __asm __volatile ("mtc0 %[a0], $22, "__XSTRING(r)" ;" \
+ __XSTRING(COP0_SYNC)";" \
+ "nop;" \
+ "nop;" \
+ : \
+ : [a0] "r"(a0)); \
+ /*mips_barrier();*/ \
+} struct __hack
+
+/*
+ * All 5 of these sub-registers are used by Linux.
+ * There is a further custom register at 25 which is not used.
+ */
+#define S5_CP0_DIAG 0
+#define S5_CP0_CLKCFG1 1
+#define S5_CP0_CLKCFG2 2
+#define S5_CP0_SYNC 3
+#define S5_CP0_CLKCFG3 4
+#define S5_CP0_RESET 5
+
+/* s5_[rd|wr]_xxx() */
+S5_RDRW32_C0P0_CUST22(diag, S5_CP0_DIAG);
+S5_RDRW32_C0P0_CUST22(clkcfg1, S5_CP0_CLKCFG1);
+S5_RDRW32_C0P0_CUST22(clkcfg2, S5_CP0_CLKCFG2);
+S5_RDRW32_C0P0_CUST22(sync, S5_CP0_SYNC);
+S5_RDRW32_C0P0_CUST22(clkcfg3, S5_CP0_CLKCFG3);
+S5_RDRW32_C0P0_CUST22(reset, S5_CP0_RESET);
+
+#endif /* _MIPS32_SENTRY5_SENTRY5REG_H_ */
diff --git a/sys/mips/mips32/sentry5/siba_cc.c b/sys/mips/mips32/sentry5/siba_cc.c
new file mode 100644
index 0000000..cd78f0b
--- /dev/null
+++ b/sys/mips/mips32/sentry5/siba_cc.c
@@ -0,0 +1,154 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * 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 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 THE 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.
+ */
+
+/*
+ * Child driver for ChipCommon core.
+ * This is not MI code at the moment.
+ * Two 16C550 compatible UARTs live here. On the WGT634U, uart1 is the
+ * system console, and uart0 is not pinned out.
+ * Because their presence is conditional, they should probably
+ * be attached from here.
+ * GPIO lives here.
+ * The hardware watchdog lives here.
+ * Clock control registers live here.
+ * You don't need to read them to determine the clock speed on the 5365,
+ * which is always 200MHz and thus may be hardcoded (for now).
+ * Flash config registers live here. There may or may not be system flash.
+ * The external interface bus lives here (conditionally).
+ * There is a JTAG interface here which may be used to attach probes to
+ * the SoC for debugging.
+ */
+
+#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 <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <dev/siba/sibavar.h>
+#include <dev/siba/sibareg.h>
+#include <dev/siba/siba_ids.h>
+
+static int siba_cc_attach(device_t);
+static int siba_cc_probe(device_t);
+static void siba_cc_intr(void *v);
+
+static int
+siba_cc_probe(device_t dev)
+{
+
+ if (siba_get_vendor(dev) == SIBA_VID_BROADCOM &&
+ siba_get_device(dev) == SIBA_DEVID_CHIPCOMMON) {
+ device_set_desc(dev, "ChipCommon core");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+struct siba_cc_softc {
+ void *notused;
+};
+
+static int
+siba_cc_attach(device_t dev)
+{
+ //struct siba_cc_softc *sc = device_get_softc(dev);
+ struct resource *mem;
+ struct resource *irq;
+ int rid;
+
+ /*
+ * Allocate the resources which the parent bus has already
+ * determined for us.
+ * TODO: interrupt routing
+ */
+#define MIPS_MEM_RID 0x20
+ rid = MIPS_MEM_RID;
+ mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (mem == NULL) {
+ device_printf(dev, "unable to allocate memory\n");
+ return (ENXIO);
+ }
+
+ rid = 0;
+ irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
+ if (irq == NULL) {
+ device_printf(dev, "unable to allocate irq\n");
+ return (ENXIO);
+ }
+
+ /* now setup the interrupt */
+ /* may be fast, exclusive or mpsafe at a later date */
+
+ /*
+ * XXX is this interrupt line in ChipCommon used for anything
+ * other than the uart? in that case we shouldn't hog it ourselves
+ * and let uart claim it to avoid polled mode.
+ */
+ int err;
+ void *cookie;
+ err = bus_setup_intr(dev, irq, INTR_TYPE_TTY, NULL, siba_cc_intr, NULL,
+ &cookie);
+ if (err != 0) {
+ device_printf(dev, "unable to setup intr\n");
+ return (ENXIO);
+ }
+
+ /* TODO: attach uart child */
+
+ return (0);
+}
+
+static void
+siba_cc_intr(void *v)
+{
+
+}
+
+static device_method_t siba_cc_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_attach, siba_cc_attach),
+ DEVMETHOD(device_probe, siba_cc_probe),
+
+ {0, 0},
+};
+
+static driver_t siba_cc_driver = {
+ "siba_cc",
+ siba_cc_methods,
+ sizeof(struct siba_softc),
+};
+static devclass_t siba_cc_devclass;
+
+DRIVER_MODULE(siba_cc, siba, siba_cc_driver, siba_cc_devclass, 0, 0);
diff --git a/sys/mips/mips32/sentry5/siba_mips.c b/sys/mips/mips32/sentry5/siba_mips.c
new file mode 100644
index 0000000..676da83
--- /dev/null
+++ b/sys/mips/mips32/sentry5/siba_mips.c
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * 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 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 THE 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.
+ */
+
+/*
+ * Child driver for MIPS 3302 core.
+ * Interrupt controller registers live here. Interrupts may not be routed
+ * to the MIPS core if they are masked out.
+ */
+
+#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 <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <dev/siba/sibavar.h>
+#include <dev/siba/sibareg.h>
+#include <dev/siba/siba_ids.h>
+
+static int siba_mips_attach(device_t);
+static int siba_mips_probe(device_t);
+
+static int
+siba_mips_probe(device_t dev)
+{
+
+ if (siba_get_vendor(dev) == SIBA_VID_BROADCOM &&
+ siba_get_device(dev) == SIBA_DEVID_MIPS_3302) {
+ device_set_desc(dev, "MIPS 3302 processor");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+struct siba_mips_softc {
+ void *notused;
+};
+
+static int
+siba_mips_attach(device_t dev)
+{
+ //struct siba_mips_softc *sc = device_get_softc(dev);
+ struct resource *mem;
+ int rid;
+
+ /*
+ * Allocate the resources which the parent bus has already
+ * determined for us.
+ * TODO: interrupt routing
+ */
+#define MIPS_MEM_RID 0x20
+ rid = MIPS_MEM_RID;
+ mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (mem == NULL) {
+ device_printf(dev, "unable to allocate memory\n");
+ return (ENXIO);
+ }
+#if 0
+ device_printf(dev, "start %08lx size %04lx\n",
+ rman_get_start(mem), rman_get_size(mem));
+#endif
+
+ return (0);
+}
+
+static device_method_t siba_mips_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_attach, siba_mips_attach),
+ DEVMETHOD(device_probe, siba_mips_probe),
+
+ {0, 0},
+};
+
+static driver_t siba_mips_driver = {
+ "siba_mips",
+ siba_mips_methods,
+ sizeof(struct siba_softc),
+};
+static devclass_t siba_mips_devclass;
+
+DRIVER_MODULE(siba_mips, siba, siba_mips_driver, siba_mips_devclass, 0, 0);
diff --git a/sys/mips/mips32/sentry5/siba_sdram.c b/sys/mips/mips32/sentry5/siba_sdram.c
new file mode 100644
index 0000000..8e74e53
--- /dev/null
+++ b/sys/mips/mips32/sentry5/siba_sdram.c
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * 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 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 THE 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.
+ */
+
+/*
+ * Child driver for SDRAM/DDR controller core.
+ * Generally the OS should not need to access this device unless the
+ * firmware has not configured the SDRAM controller.
+ */
+
+#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 <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <dev/siba/sibavar.h>
+#include <dev/siba/sibareg.h>
+#include <dev/siba/siba_ids.h>
+
+static int siba_sdram_attach(device_t);
+static int siba_sdram_probe(device_t);
+
+static int
+siba_sdram_probe(device_t dev)
+{
+
+ if (siba_get_vendor(dev) == SIBA_VID_BROADCOM &&
+ siba_get_device(dev) == SIBA_DEVID_SDRAMDDR) {
+ device_set_desc(dev, "SDRAM/DDR core");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+struct siba_sdram_softc {
+ void *notused;
+};
+
+static int
+siba_sdram_attach(device_t dev)
+{
+ //struct siba_sdram_softc *sc = device_get_softc(dev);
+ struct resource *mem;
+ int rid;
+
+ /*
+ * Allocate the resources which the parent bus has already
+ * determined for us.
+ * TODO: interrupt routing
+ */
+#define MIPS_MEM_RID 0x20
+ rid = MIPS_MEM_RID;
+ mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (mem == NULL) {
+ device_printf(dev, "unable to allocate memory\n");
+ return (ENXIO);
+ }
+
+#if 0
+ device_printf(dev, "start %08lx size %04lx\n",
+ rman_get_start(mem), rman_get_size(mem));
+#endif
+
+ return (0);
+}
+
+static device_method_t siba_sdram_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_attach, siba_sdram_attach),
+ DEVMETHOD(device_probe, siba_sdram_probe),
+
+ {0, 0},
+};
+
+static driver_t siba_sdram_driver = {
+ "siba_sdram",
+ siba_sdram_methods,
+ sizeof(struct siba_softc),
+};
+static devclass_t siba_sdram_devclass;
+
+DRIVER_MODULE(siba_sdram, siba, siba_sdram_driver, siba_sdram_devclass, 0, 0);
diff --git a/sys/mips/mips32/sentry5/uart_bus_sbusart.c b/sys/mips/mips32/sentry5/uart_bus_sbusart.c
new file mode 100644
index 0000000..e4808cd
--- /dev/null
+++ b/sys/mips/mips32/sentry5/uart_bus_sbusart.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2007 Bruce M. Simpson.
+ * 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 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 THE 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
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/pci/pcivar.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_bus.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/mips32/sentry5/sentry5reg.h>
+
+#include "uart_if.h"
+
+static int uart_malta_probe(device_t dev);
+
+extern struct uart_class malta_uart_class;
+
+static device_method_t uart_malta_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, uart_malta_probe),
+ DEVMETHOD(device_attach, uart_bus_attach),
+ DEVMETHOD(device_detach, uart_bus_detach),
+ { 0, 0 }
+};
+
+static driver_t uart_malta_driver = {
+ uart_driver_name,
+ uart_malta_methods,
+ sizeof(struct uart_softc),
+};
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+static int
+uart_malta_probe(device_t dev)
+{
+ struct uart_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
+ sc->sc_class = &uart_ns8250_class;
+ bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
+ sc->sc_sysdev->bas.bst = 0;
+ sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(SENTRY5_UART1ADR);
+ sc->sc_bas.bst = 0;
+ sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(SENTRY5_UART1ADR);
+ return(uart_bus_probe(dev, 0, 0, 0, 0));
+}
+
+DRIVER_MODULE(uart, obio, uart_malta_driver, uart_devclass, 0, 0);
diff --git a/sys/mips/mips32/sentry5/uart_cpu_sbusart.c b/sys/mips/mips32/sentry5/uart_cpu_sbusart.c
new file mode 100644
index 0000000..e1da9b2
--- /dev/null
+++ b/sys/mips/mips32/sentry5/uart_cpu_sbusart.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2006 Wojciech A. Koszek <wkoszek@FreeBSD.org>
+ * 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 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 THE 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.
+ *
+ * $Id$
+ */
+/*
+ * Skeleton of this file was based on respective code for ARM
+ * code written by Olivier Houchard.
+ */
+/*
+ * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is
+ * experimental and was written for MIPS32 port.
+ */
+#include "opt_uart.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/cons.h>
+
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+
+#include <mips/mips32/sentry5/sentry5reg.h>
+
+bus_space_tag_t uart_bus_space_io;
+bus_space_tag_t uart_bus_space_mem;
+
+extern struct uart_ops malta_usart_ops;
+extern struct bus_space malta_bs_tag;
+
+int
+uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2)
+{
+ return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0);
+}
+
+int
+uart_cpu_getdev(int devtype, struct uart_devinfo *di)
+{
+ di->ops = uart_getops(&uart_ns8250_class);
+ di->bas.chan = 0;
+ di->bas.bst = 0;
+ di->bas.regshft = 0;
+ di->bas.rclk = 0;
+ di->baudrate = 115200;
+ di->databits = 8;
+ di->stopbits = 1;
+ di->parity = UART_PARITY_NONE;
+
+ uart_bus_space_io = MIPS_PHYS_TO_KSEG1(SENTRY5_UART1ADR);
+ uart_bus_space_mem = MIPS_PHYS_TO_KSEG1(SENTRY5_UART1ADR);
+ di->bas.bsh = MIPS_PHYS_TO_KSEG1(SENTRY5_UART1ADR);
+ return (0);
+}
OpenPOWER on IntegriCloud