summaryrefslogtreecommitdiffstats
path: root/sys/mips
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2008-04-13 07:44:55 +0000
committerimp <imp@FreeBSD.org>2008-04-13 07:44:55 +0000
commit17ff03f1da844ff9629231c097e4aa87762b3a7a (patch)
treeaf930385c53aa66443ab946e90999ff6deaa25f3 /sys/mips
parent352e51d169c4877beae82a6316142f70d0742025 (diff)
downloadFreeBSD-src-17ff03f1da844ff9629231c097e4aa87762b3a7a.zip
FreeBSD-src-17ff03f1da844ff9629231c097e4aa87762b3a7a.tar.gz
FreeBSD/mips port. The FreeBSD/mips port targets mips32, mips64,
mips32r2 and mips64r2 (and close relatives) processors. There presently is support for ADMtek ADM5120, A mips 4Kc in a malta board, the RB533 routerboard (based on IDT RC32434) and some preliminary support for sibtye/broadcom designs. Other hardware support will be forthcomcing. This port boots multiuser under gxemul emulating the malta board and also bootstraps on the hardware whose support is forthcoming... Oleksandr Tymoshenko, Wojciech Koszek, Warner Losh, Olivier Houchard, Randall Stewert and others that have contributed to the mips2 and/or mips2-jnpr perforce branches. Juniper contirbuted a generic mips port late in the life cycle of the misp2 branch. Warner Losh merged the mips2 and Juniper code bases, and others list above have worked for the past several months to get to multiuser. In addition, the mips2 work owe a debt to the trail blazing efforts of the original mips branch in perforce done by Juli Mallett.
Diffstat (limited to 'sys/mips')
-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