summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2008-11-26 14:39:15 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2008-11-26 14:39:15 +0000
commitc6d65e6e11637f113bb9637929b7a7ba1382553e (patch)
treee36388ee6fd0f8a0a087b2a91e036a00a9d78f80 /sys/arch
parent84c57e61bdc36075d5bb64f1f8ba3f0c35829934 (diff)
Add a number of driver files necessary for OpenMoko support,
from NetBSD with mods
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2410.c275
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2410_intr.c374
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2410_intr.h40
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2410reg.h230
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2410var.h46
-rw-r--r--sys/arch/arm/s3c2xx0/s3c24x0_clk.c337
-rw-r--r--sys/arch/arm/s3c2xx0/s3c24x0_intr.h57
-rw-r--r--sys/arch/arm/s3c2xx0/s3c24x0var.h48
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2xx0_busdma.c73
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2xx0_intr.c363
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2xx0_intr.h266
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2xx0_mutex.c67
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2xx0_space.c268
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2xx0reg.h137
-rw-r--r--sys/arch/arm/s3c2xx0/s3c2xx0var.h79
-rw-r--r--sys/arch/arm/s3c2xx0/sscom.c2196
-rw-r--r--sys/arch/arm/s3c2xx0/sscom_s3c2410.c177
-rw-r--r--sys/arch/arm/s3c2xx0/sscom_var.h281
18 files changed, 5314 insertions, 0 deletions
diff --git a/sys/arch/arm/s3c2xx0/s3c2410.c b/sys/arch/arm/s3c2xx0/s3c2410.c
new file mode 100644
index 00000000000..d31d4c1d996
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2410.c
@@ -0,0 +1,275 @@
+/* $OpenBSD: s3c2410.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2410.c,v 1.10 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2003, 2005 Genetec corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec corporation.
+ *
+ * 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 Genetec corporation may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``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 GENETEC CORP.
+ * 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>
+//__KERNEL_RCSID(0, "$NetBSD: s3c2410.c,v 1.10 2005/12/11 12:16:51 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/reboot.h>
+
+#include <machine/cpu.h>
+#include <machine/bus.h>
+
+#include <arm/cpufunc.h>
+#include <arm/mainbus/mainbus.h>
+#include <arm/s3c2xx0/s3c2410reg.h>
+#include <arm/s3c2xx0/s3c2410var.h>
+
+/* prototypes */
+int s3c2410_match(struct device *, void *, void *);
+void s3c2410_attach(struct device *, struct device *, void *);
+int s3c2410_search(struct device *, void *, void *);
+
+/* attach structures */
+/*
+#if 0
+CFATTACH_DECL(ssio, sizeof(struct s3c24x0_softc), s3c2410_match, s3c2410_attach,
+ NULL, NULL);
+#endif
+*/
+
+struct cfattach ssio_ca = {
+ sizeof(struct s3c24x0_softc), s3c2410_match, s3c2410_attach
+};
+
+struct cfdriver ssio_cd = {
+ NULL, "ssio", DV_DULL
+};
+
+
+extern struct bus_space s3c2xx0_bs_tag;
+
+struct s3c2xx0_softc *s3c2xx0_softc;
+
+#ifdef DEBUG_PORTF
+volatile uint8_t *portf; /* for debug */
+#endif
+
+static int
+s3c2410_print(void *aux, const char *name)
+{
+ struct s3c2xx0_attach_args *sa = (struct s3c2xx0_attach_args *) aux;
+
+ if (sa->sa_size)
+ printf(" addr 0x%lx", sa->sa_addr);
+ if (sa->sa_size > 1)
+ printf("-0x%lx", sa->sa_addr + sa->sa_size - 1);
+ if (sa->sa_intr != -1)
+ printf(" intr %d", sa->sa_intr);
+ if (sa->sa_index != -1)
+ printf(" unit %d", sa->sa_index);
+
+ return (UNCONF);
+}
+
+int
+s3c2410_match(struct device *parent, void *match, void *aux)
+{
+ return 1;
+}
+
+void
+s3c2410_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct s3c24x0_softc *sc = (struct s3c24x0_softc *) self;
+ bus_space_tag_t iot;
+ const char *which_registers; /* for panic message */
+
+#define FAIL(which) do { \
+ which_registers=(which); goto abort; }while(/*CONSTCOND*/0)
+
+ s3c2xx0_softc = &(sc->sc_sx);
+ sc->sc_sx.sc_iot = iot = &s3c2xx0_bs_tag;
+
+ if (bus_space_map(iot,
+ S3C2410_INTCTL_BASE, S3C2410_INTCTL_SIZE,
+ BUS_SPACE_MAP_LINEAR, &sc->sc_sx.sc_intctl_ioh))
+ FAIL("intc");
+ /* tell register addresses to interrupt handler */
+ s3c2410_intr_init(sc);
+
+ /* Map the GPIO registers */
+ if (bus_space_map(iot, S3C2410_GPIO_BASE, S3C2410_GPIO_SIZE,
+ 0, &sc->sc_sx.sc_gpio_ioh))
+ FAIL("GPIO");
+#ifdef DEBUG_PORTF
+ {
+ extern volatile uint8_t *portf;
+ /* make all ports output */
+ bus_space_write_2(iot, sc->sc_sx.sc_gpio_ioh, GPIO_PCONF, 0x5555);
+ portf = (volatile uint8_t *)
+ ((char *)bus_space_vaddr(iot, sc->sc_sx.sc_gpio_ioh) + GPIO_PDATF);
+ }
+#endif
+
+#if 0
+ /* Map the DMA controller registers */
+ if (bus_space_map(iot, S3C2410_DMAC_BASE, S3C2410_DMAC_SIZE,
+ 0, &sc->sc_sx.sc_dmach))
+ FAIL("DMAC");
+#endif
+
+ /* Memory controller */
+ if (bus_space_map(iot, S3C2410_MEMCTL_BASE,
+ S3C24X0_MEMCTL_SIZE, 0, &sc->sc_sx.sc_memctl_ioh))
+ FAIL("MEMC");
+ /* Clock manager */
+ if (bus_space_map(iot, S3C2410_CLKMAN_BASE,
+ S3C24X0_CLKMAN_SIZE, 0, &sc->sc_sx.sc_clkman_ioh))
+ FAIL("CLK");
+
+#if 0
+ /* Real time clock */
+ if (bus_space_map(iot, S3C2410_RTC_BASE,
+ S3C24X0_RTC_SIZE, 0, &sc->sc_sx.sc_rtc_ioh))
+ FAIL("RTC");
+#endif
+
+ if (bus_space_map(iot, S3C2410_TIMER_BASE,
+ S3C24X0_TIMER_SIZE, 0, &sc->sc_timer_ioh))
+ FAIL("TIMER");
+
+ /* calculate current clock frequency */
+ s3c24x0_clock_freq(&sc->sc_sx);
+ printf(": fclk %d MHz hclk %d MHz pclk %d MHz\n",
+ sc->sc_sx.sc_fclk / 1000000, sc->sc_sx.sc_hclk / 1000000,
+ sc->sc_sx.sc_pclk / 1000000);
+
+ /* get busdma tag for the platform */
+ sc->sc_sx.sc_dmat = s3c2xx0_bus_dma_init(&s3c2xx0_bus_dma);
+
+ /*
+ * Attach devices.
+ */
+ config_search(s3c2410_search, self, sc);
+
+ return;
+
+abort:
+ panic("%s: unable to map %s registers",
+ self->dv_xname, which_registers);
+
+#undef FAIL
+}
+
+int
+s3c2410_search(struct device * parent, void * c, void *aux)
+{
+ struct s3c24x0_softc *sc = (struct s3c24x0_softc *) parent;
+ struct s3c2xx0_attach_args aa;
+ struct cfdata *cf = c;
+
+
+ aa.sa_sc = sc;
+ aa.sa_iot = sc->sc_sx.sc_iot;
+ #if 0
+ aa.sa_addr = cf->cf_loc[SSIOCF_ADDR];
+ aa.sa_size = cf->cf_loc[SSIOCF_SIZE];
+ aa.sa_index = cf->cf_loc[SSIOCF_INDEX];
+ aa.sa_intr = cf->cf_loc[SSIOCF_INTR];
+ #else
+ aa.sa_addr = cf->cf_loc[0];
+ aa.sa_size = cf->cf_loc[1];
+ aa.sa_index = cf->cf_loc[2];
+ aa.sa_intr = cf->cf_loc[3];
+ #endif
+
+ aa.sa_dmat = sc->sc_sx.sc_dmat;
+
+ config_found(parent, &aa, s3c2410_print);
+
+ return 0;
+}
+
+/*
+ * fill sc_pclk, sc_hclk, sc_fclk from values of clock controller register.
+ *
+ * s3c24x0_clock_freq2() is meant to be called from kernel startup routines.
+ * s3c24x0_clock_freq() is for after kernel initialization is done.
+ */
+void
+s3c24x0_clock_freq2(vaddr_t clkman_base, int *fclk, int *hclk, int *pclk)
+{
+ uint32_t pllcon, divn;
+ int mdiv, pdiv, sdiv;
+ int f, h, p;
+
+ pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON);
+ divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN);
+
+ mdiv = (pllcon & PLLCON_MDIV_MASK) >> PLLCON_MDIV_SHIFT;
+ pdiv = (pllcon & PLLCON_PDIV_MASK) >> PLLCON_PDIV_SHIFT;
+ sdiv = (pllcon & PLLCON_SDIV_MASK) >> PLLCON_SDIV_SHIFT;
+
+ f = ((mdiv + 8) * S3C2XX0_XTAL_CLK) / ((pdiv + 2) * (1 << sdiv));
+ h = f;
+ if (divn & CLKDIVN_HDIVN)
+ h /= 2;
+ p = h;
+ if (divn & CLKDIVN_PDIVN)
+ p /= 2;
+
+ if (fclk) *fclk = f;
+ if (hclk) *hclk = h;
+ if (pclk) *pclk = p;
+
+}
+
+void
+s3c24x0_clock_freq(struct s3c2xx0_softc *sc)
+{
+ s3c24x0_clock_freq2(
+ (vaddr_t)bus_space_vaddr(sc->sc_iot, sc->sc_clkman_ioh),
+ &sc->sc_fclk, &sc->sc_hclk, &sc->sc_pclk);
+}
+
+/*
+ * Issue software reset command.
+ * called with MMU off.
+ *
+ * S3C2410 doesn't have sowtware reset bit like S3C2800.
+ * use watch dog timer and make it fire immediately.
+ */
+void
+s3c2410_softreset(void)
+{
+ disable_interrupts(I32_bit|F32_bit);
+
+ *(volatile unsigned int *)(S3C2410_WDT_BASE + WDT_WTCON)
+ = (0 << WTCON_PRESCALE_SHIFT) | WTCON_ENABLE |
+ WTCON_CLKSEL_16 | WTCON_ENRST;
+}
+
+
diff --git a/sys/arch/arm/s3c2xx0/s3c2410_intr.c b/sys/arch/arm/s3c2xx0/s3c2410_intr.c
new file mode 100644
index 00000000000..79089f8ddd2
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2410_intr.c
@@ -0,0 +1,374 @@
+/* $OpenBSD: s3c2410_intr.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2410_intr.c,v 1.11 2008/11/24 11:29:52 dogcow Exp $ */
+
+/*
+ * Copyright (c) 2003 Genetec corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec corporation.
+ *
+ * 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 Genetec corporation may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``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 GENETEC CORP.
+ * 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.
+ */
+
+/*
+ * IRQ handler for Samsung S3C2410 processor.
+ * It has integrated interrupt controller.
+ */
+
+#include <sys/cdefs.h>
+/*
+__KERNEL_RCSID(0, "$NetBSD: s3c2410_intr.c,v 1.11 2008/11/24 11:29:52 dogcow Exp $");
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <uvm/uvm_extern.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <arm/cpufunc.h>
+
+#include <arm/s3c2xx0/s3c2410reg.h>
+#include <arm/s3c2xx0/s3c2410var.h>
+
+/*
+ * interrupt dispatch table.
+ */
+
+struct s3c2xx0_intr_dispatch handler[ICU_LEN];
+
+extern volatile uint32_t *s3c2xx0_intr_mask_reg;
+
+volatile int intr_mask;
+#ifdef __HAVE_FAST_SOFTINTS
+volatile int softint_pending;
+volatile int soft_intr_mask;
+#endif
+volatile int global_intr_mask = 0; /* mask some interrupts at all spl level */
+
+/* interrupt masks for each level */
+int s3c2xx0_imask[NIPL];
+int s3c2xx0_smask[NIPL];
+int s3c2xx0_ilevel[ICU_LEN];
+#ifdef __HAVE_FAST_SOFTINTS
+int s3c24x0_soft_imask[NIPL];
+#endif
+
+vaddr_t intctl_base; /* interrupt controller registers */
+#define icreg(offset) \
+ (*(volatile uint32_t *)(intctl_base+(offset)))
+
+#ifdef __HAVE_FAST_SOFTINTS
+/*
+ * Map a software interrupt queue to an interrupt priority level.
+ */
+static const int si_to_ipl[] = {
+ [SI_SOFTBIO] = IPL_SOFTBIO,
+ [SI_SOFTCLOCK] = IPL_SOFTCLOCK,
+ [SI_SOFTNET] = IPL_SOFTNET,
+ [SI_SOFTSERIAL] = IPL_SOFTSERIAL,
+};
+#endif
+
+#define PENDING_CLEAR_MASK (~0)
+
+/*
+ * called from irq_entry.
+ */
+void s3c2410_irq_handler(struct clockframe *);
+void
+s3c2410_irq_handler(struct clockframe *frame)
+{
+ uint32_t irqbits;
+ int irqno;
+ int saved_spl_level;
+
+ saved_spl_level = s3c2xx0_curcpl();
+
+#ifdef DIAGNOSTIC
+ if (curcpu()->ci_intr_depth > 10)
+ panic("nested intr too deep");
+#endif
+
+ while ((irqbits = icreg(INTCTL_INTPND)) != 0) {
+
+ /* Note: Only one bit in INTPND register is set */
+
+ irqno = icreg(INTCTL_INTOFFSET);
+
+#ifdef DIAGNOSTIC
+ if (__predict_false((irqbits & (1<<irqno)) == 0)) {
+ /* This shouldn't happen */
+ printf("INTOFFSET=%d, INTPND=%x\n", irqno, irqbits);
+ break;
+ }
+#endif
+ /* raise spl to stop interrupts of lower priorities */
+ if (saved_spl_level < handler[irqno].level)
+ s3c2xx0_setipl(handler[irqno].level);
+
+ /* clear pending bit */
+ icreg(INTCTL_SRCPND) = PENDING_CLEAR_MASK & (1 << irqno);
+ icreg(INTCTL_INTPND) = PENDING_CLEAR_MASK & (1 << irqno);
+
+ enable_interrupts(I32_bit); /* allow nested interrupts */
+
+ (*handler[irqno].func) (
+ handler[irqno].cookie == 0
+ ? frame : handler[irqno].cookie);
+
+ disable_interrupts(I32_bit);
+
+ /* restore spl to that was when this interrupt happen */
+ s3c2xx0_setipl(saved_spl_level);
+
+ }
+
+#ifdef __HAVE_FAST_SOFTINTS
+ cpu_dosoftints();
+#endif
+}
+
+/*
+ * Handler for main IRQ of cascaded interrupts.
+ */
+static int
+cascade_irq_handler(void *cookie)
+{
+ int index = (int)cookie - 1;
+ uint32_t irqbits;
+ int irqno, i;
+ int save = disable_interrupts(I32_bit);
+
+ KASSERT(0 <= index && index <= 3);
+
+ irqbits = icreg(INTCTL_SUBSRCPND) &
+ ~icreg(INTCTL_INTSUBMSK) & (0x07 << (3*index));
+
+ for (irqno = 3*index; irqbits; ++irqno) {
+ if ((irqbits & (1<<irqno)) == 0)
+ continue;
+
+ /* clear pending bit */
+ irqbits &= ~(1<<irqno);
+ icreg(INTCTL_SUBSRCPND) = (1 << irqno);
+
+ /* allow nested interrupts. SPL is already set
+ * correctly by main handler. */
+ restore_interrupts(save);
+
+ i = S3C2410_SUBIRQ_MIN + irqno;
+ (* handler[i].func)(handler[i].cookie);
+
+ disable_interrupts(I32_bit);
+ }
+
+ return 1;
+}
+
+
+static const uint8_t subirq_to_main[] = {
+ S3C2410_INT_UART0,
+ S3C2410_INT_UART0,
+ S3C2410_INT_UART0,
+ S3C2410_INT_UART1,
+ S3C2410_INT_UART1,
+ S3C2410_INT_UART1,
+ S3C2410_INT_UART2,
+ S3C2410_INT_UART2,
+ S3C2410_INT_UART2,
+ S3C24X0_INT_ADCTC,
+ S3C24X0_INT_ADCTC,
+};
+
+void *
+s3c24x0_intr_establish(int irqno, int level, int type,
+ int (* func) (void *), void *cookie)
+{
+ int save;
+
+ if (irqno < 0 || irqno >= ICU_LEN ||
+ type < IST_NONE || IST_EDGE_BOTH < type)
+ panic("intr_establish: bogus irq or type");
+
+ save = disable_interrupts(I32_bit);
+
+ handler[irqno].cookie = cookie;
+ handler[irqno].func = func;
+ handler[irqno].level = level;
+
+ if (irqno >= S3C2410_SUBIRQ_MIN) {
+ /* cascaded interrupts. */
+ int main_irqno;
+ int i = (irqno - S3C2410_SUBIRQ_MIN);
+
+ main_irqno = subirq_to_main[i];
+
+ /* establish main irq if first time
+ * be careful that cookie shouldn't be 0 */
+ if (handler[main_irqno].func != cascade_irq_handler)
+ s3c24x0_intr_establish(main_irqno, level, type,
+ cascade_irq_handler, (void *)((i/3) + 1));
+
+ /* unmask it in submask register */
+ icreg(INTCTL_INTSUBMSK) &= ~(1<<i);
+
+ restore_interrupts(save);
+ return &handler[irqno];
+ }
+
+ s3c2xx0_update_intr_masks(irqno, level);
+
+ /*
+ * set trigger type for external interrupts 0..3
+ */
+ if (irqno <= S3C24X0_INT_EXT(3)) {
+ /*
+ * Update external interrupt control
+ */
+ s3c2410_setup_extint(irqno, type);
+ }
+
+ s3c2xx0_setipl(s3c2xx0_curcpl());
+
+ restore_interrupts(save);
+
+ return &handler[irqno];
+}
+
+
+static void
+init_interrupt_masks(void)
+{
+ int i;
+
+ for (i=0; i < NIPL; ++i)
+ s3c2xx0_imask[i] = 0;
+
+#ifdef __HAVE_FAST_SOFTINTS
+ s3c24x0_soft_imask[IPL_NONE] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
+ SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK) |
+ SI_TO_IRQBIT(SI_SOFT);
+
+ s3c24x0_soft_imask[IPL_SOFT] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
+ SI_TO_IRQBIT(SI_SOFTNET) | SI_TO_IRQBIT(SI_SOFTCLOCK);
+
+ /*
+ * splsoftclock() is the only interface that users of the
+ * generic software interrupt facility have to block their
+ * soft intrs, so splsoftclock() must also block IPL_SOFT.
+ */
+ s3c24x0_soft_imask[IPL_SOFTCLOCK] = SI_TO_IRQBIT(SI_SOFTSERIAL) |
+ SI_TO_IRQBIT(SI_SOFTNET);
+
+ /*
+ * splsoftnet() must also block splsoftclock(), since we don't
+ * want timer-driven network events to occur while we're
+ * processing incoming packets.
+ */
+ s3c24x0_soft_imask[IPL_SOFTNET] = SI_TO_IRQBIT(SI_SOFTSERIAL);
+
+ for (i = IPL_BIO; i < IPL_SOFTSERIAL; ++i)
+ s3c24x0_soft_imask[i] = SI_TO_IRQBIT(SI_SOFTSERIAL);
+#endif
+}
+
+void
+s3c2410_intr_init(struct s3c24x0_softc *sc)
+{
+ intctl_base = (vaddr_t) bus_space_vaddr(sc->sc_sx.sc_iot,
+ sc->sc_sx.sc_intctl_ioh);
+
+ s3c2xx0_intr_mask_reg = (uint32_t *)(intctl_base + INTCTL_INTMSK);
+
+ /* clear all pending interrupt */
+ icreg(INTCTL_SRCPND) = ~0;
+ icreg(INTCTL_INTPND) = ~0;
+
+ /* mask all sub interrupts */
+ icreg(INTCTL_INTSUBMSK) = 0x7ff;
+
+ init_interrupt_masks();
+
+ s3c2xx0_intr_init(handler, ICU_LEN);
+
+}
+
+
+/*
+ * mask/unmask sub interrupts
+ */
+void
+s3c2410_mask_subinterrupts(int bits)
+{
+ int psw = disable_interrupts(I32_bit|F32_bit);
+ icreg(INTCTL_INTSUBMSK) |= bits;
+ restore_interrupts(psw);
+}
+
+void
+s3c2410_unmask_subinterrupts(int bits)
+{
+ int psw = disable_interrupts(I32_bit|F32_bit);
+ icreg(INTCTL_INTSUBMSK) &= ~bits;
+ restore_interrupts(psw);
+}
+
+/*
+ * Update external interrupt control
+ */
+static const u_char s3c24x0_ist[] = {
+ EXTINTR_LOW, /* NONE */
+ EXTINTR_FALLING, /* PULSE */
+ EXTINTR_FALLING, /* EDGE */
+ EXTINTR_LOW, /* LEVEL */
+ EXTINTR_HIGH,
+ EXTINTR_RISING,
+ EXTINTR_BOTH,
+};
+
+void
+s3c2410_setup_extint(int extint, int type)
+{
+ uint32_t reg;
+ u_int trig;
+ int i = extint % 8;
+ int regidx = extint/8; /* GPIO_EXTINT[0:2] */
+ int save;
+
+ trig = s3c24x0_ist[type];
+
+ save = disable_interrupts(I32_bit);
+
+ reg = bus_space_read_4(s3c2xx0_softc->sc_iot,
+ s3c2xx0_softc->sc_gpio_ioh,
+ GPIO_EXTINT(regidx));
+
+ reg = reg & ~(0x07 << (4*i));
+ reg |= trig << (4*i);
+
+ bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh,
+ GPIO_EXTINT(regidx), reg);
+
+ restore_interrupts(save);
+}
diff --git a/sys/arch/arm/s3c2xx0/s3c2410_intr.h b/sys/arch/arm/s3c2xx0/s3c2410_intr.h
new file mode 100644
index 00000000000..8f03fa5d639
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2410_intr.h
@@ -0,0 +1,40 @@
+/* $OpenBSD: s3c2410_intr.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2410_intr.h,v 1.2 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2003 Genetec corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec corporation.
+ *
+ * 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 Genetec corporation may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``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 GENETEC CORP.
+ * 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 _S3C2410_INTR_H_
+#define _S3C2410_INTR_H_
+
+#define ARM_IRQ_HANDLER _C_LABEL(s3c2410_irq_handler)
+
+#include <arm/s3c2xx0/s3c24x0_intr.h>
+
+#endif /* _S3C2410_INTR_H_ */
diff --git a/sys/arch/arm/s3c2xx0/s3c2410reg.h b/sys/arch/arm/s3c2xx0/s3c2410reg.h
new file mode 100644
index 00000000000..a939a96ef44
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2410reg.h
@@ -0,0 +1,230 @@
+/* $OpenBSD: s3c2410reg.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2410reg.h,v 1.7 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 Genetec corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec corporation.
+ *
+ * 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 Genetec corporation may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``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 GENETEC CORP.
+ * 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.
+ */
+
+
+/*
+ * Samsung S3C2410X processor is ARM920T based integrated CPU
+ *
+ * Reference:
+ * S3C2410X User's Manual
+ */
+#ifndef _ARM_S3C2XX0_S3C2410REG_H_
+#define _ARM_S3C2XX0_S3C2410REG_H_
+
+/* common definitions for S3C2800, S3C2400 and S3C2410 */
+#include <arm/s3c2xx0/s3c2xx0reg.h>
+/* common definitions for S3C2400 and S3C2410 */
+#include <arm/s3c2xx0/s3c24x0reg.h>
+
+/*
+ * Memory Map
+ */
+#define S3C2410_BANK_SIZE 0x08000000
+#define S3C2410_BANK_START(n) (S3C2410_BANK_SIZE*(n))
+#define S3C2410_SDRAM_START S3C2410_BANK_START(6)
+
+/*
+ * Physical address of integrated peripherals
+ */
+#define S3C2410_MEMCTL_BASE 0x48000000 /* memory controller */
+#define S3C2410_USBHC_BASE 0x49000000 /* USB Host controller */
+#define S3C2410_INTCTL_BASE 0x4a000000 /* Interrupt controller */
+#define S3C2410_DMAC_BASE 0x4b000000
+#define S3C2410_DMAC_SIZE 0xe4
+#define S3C2410_CLKMAN_BASE 0x4c000000 /* clock & power management */
+#define S3C2410_LCDC_BASE 0x4d000000 /* LCD controller */
+#define S3C2410_NANDFC_BASE 0x4e000000 /* NAND Flash controller */
+#define S3C2410_NANDFC_SIZE 0x18
+#define S3C2410_UART0_BASE 0x50000000
+#define S3C2410_UART_BASE(n) (S3C2410_UART0_BASE+0x4000*(n))
+#define S3C2410_TIMER_BASE 0x51000000
+#define S3C2410_USBDC_BASE 0x5200140
+#define S3C2410_USBDC_SIZE 0x130
+#define S3C2410_WDT_BASE 0x53000000
+#define S3C2410_IIC_BASE 0x54000000
+#define S3C2410_IIS_BASE 0x55000000
+#define S3C2410_GPIO_BASE 0x56000000
+#define S3C2410_GPIO_SIZE 0xb4
+#define S3C2410_ADC_BASE 0x58000000
+#define S3C2410_ADC_SIZE 0x14
+#define S3C2410_SPI0_BASE 0x59000000
+#define S3C2410_SPI1_BASE 0x59000020
+#define S3C2410_SDI_BASE 0x5a000000 /* SD Interface */
+#define S3C2410_SDI_SIZE 0x44
+
+/* interrupt control (additional defs for 2410) */
+#define ICU_LEN (32+11)
+
+#define INTCTL_SUBSRCPND 0x18 /* sub source pending (2410 only) */
+#define INTCTL_INTSUBMSK 0x1c /* sub mask (2410 only) */
+
+/* 2410 has more than 32 interrupt sources. These are sub-sources
+ * that are OR-ed into main interrupt sources, and controlled via
+ * SUBSRCPND and SUBSRCMSK registers */
+
+#define S3C2410_SUBIRQ_MIN 32
+#define S3C2410_SUBIRQ_MAX (32+10)
+
+/* cascaded to INT_ADCTC */
+#define S3C2410_INT_ADC (S3C2410_SUBIRQ_MIN+10) /* AD converter */
+#define S3C2410_INT_TC (S3C2410_SUBIRQ_MIN+9) /* Touch screen */
+/* cascaded to INT_UART2 */
+#define S3C2410_INT_ERR2 (S3C2410_SUBIRQ_MIN+8) /* UART2 Error interrupt */
+#define S3C2410_INT_TXD2 (S3C2410_SUBIRQ_MIN+7) /* UART2 Tx interrupt */
+#define S3C2410_INT_RXD2 (S3C2410_SUBIRQ_MIN+6) /* UART2 Rx interrupt */
+/* cascaded to INT_UART1 */
+#define S3C2410_INT_ERR1 (S3C2410_SUBIRQ_MIN+5) /* UART1 Error interrupt */
+#define S3C2410_INT_TXD1 (S3C2410_SUBIRQ_MIN+4) /* UART1 Tx interrupt */
+#define S3C2410_INT_RXD1 (S3C2410_SUBIRQ_MIN+3) /* UART1 Rx interrupt */
+/* cascaded to INT_UART0 */
+#define S3C2410_INT_ERR0 (S3C2410_SUBIRQ_MIN+2) /* UART0 Error interrupt */
+#define S3C2410_INT_TXD0 (S3C2410_SUBIRQ_MIN+1) /* UART0 Tx interrupt */
+#define S3C2410_INT_RXD0 (S3C2410_SUBIRQ_MIN+0) /* UART0 Rx interrupt */
+
+#define S3C2410_INTCTL_SIZE 0x20
+
+
+/* Clock control */
+#define CLKMAN_LOCKTIME 0x00
+#define CLKMAN_MPLLCON 0x04
+#define CLKMAN_UPLLCON 0x08
+#define CLKMAN_CLKCON 0x0c
+#define CLKCON_SPI (1<<18)
+#define CLKCON_IIS (1<<17)
+#define CLKCON_IIC (1<<16)
+#define CLKCON_ADC (1<<15)
+#define CLKCON_RTC (1<<14)
+#define CLKCON_GPIO (1<<13)
+#define CLKCON_UART2 (1<<12)
+#define CLKCON_UART1 (1<<11)
+#define CLKCON_UART0 (1<<10) /* PCLK to UART0 */
+#define CLKCON_SDI (1<<9)
+#define CLKCON_TIMER (1<<8) /* PCLK to TIMER */
+#define CLKCON_USBD (1<<7) /* PCLK to USB device controller */
+#define CLKCON_USBH (1<<6) /* PCLK to USB host controller */
+#define CLKCON_LCDC (1<<5) /* PCLK to LCD controller */
+#define CLKCON_NANDFC (1<<4) /* PCLK to NAND Flash controller */
+#define CLKCON_IDLE (1<<2) /* 1=transition to IDLE mode */
+#define CLKCON_STOP (1<<0) /* 1=transition to STOP mode */
+#define CLKMAN_CLKSLOW 0x10
+#define CLKMAN_CLKDIVN 0x14
+#define CLKDIVN_HDIVN (1<<1) /* hclk=fclk/2 */
+#define CLKDIVN_PDIVN (1<<0) /* pclk=hclk/2 */
+
+/* NAND Flash controller */
+#define NANDFC_NFCONF 0x00 /* Configuration */
+#define NANDFC_NFCMD 0x04 /* command */
+#define NANDFC_NFADDR 0x08 /* address */
+#define NANDFC_NFDATA 0x0c /* data */
+#define NANDFC_NFSTAT 0x10 /* operation status */
+#define NANDFC_NFECC 0x14 /* ecc */
+
+/* GPIO */
+#define GPIO_PACON 0x00 /* port A configuration */
+#define PCON_INPUT 0 /* Input port */
+#define PCON_OUTPUT 1 /* Output port */
+#define PCON_ALTFUN 2 /* Alternate function */
+#define PCON_ALTFUN2 3 /* Alternate function */
+#define GPIO_PADAT 0x04 /* port A data */
+#define GPIO_PBCON 0x10
+#define GPIO_PBDAT 0x14
+#define GPIO_PBUP 0x18
+#define GPIO_PCCON 0x20
+#define GPIO_PCDAT 0x24
+#define GPIO_PCUP 0x28
+#define GPIO_PDCON 0x30
+#define GPIO_PDDAT 0x34
+#define GPIO_PDUP 0x38
+#define GPIO_PECON 0x40
+#define GPIO_PEDAT 0x44
+#define GPIO_PEUP 0x48
+#define GPIO_PFCON 0x50
+#define GPIO_PFDAT 0x54
+#define GPIO_PFUP 0x58
+#define GPIO_PGCON 0x60
+#define GPIO_PGDAT 0x64
+#define GPIO_PGUP 0x68
+#define GPIO_PHCON 0x70
+#define GPIO_PHDAT 0x74
+#define GPIO_PHUP 0x78
+#define GPIO_MISCCR 0x80 /* miscellaneous control */
+#define GPIO_DCLKCON 0x84 /* DCLK 0/1 */
+#define GPIO_EXTINT(n) (0x88+4*(n)) /* external int control 0/1/2 */
+#define GPIO_EINTFLT(n) (0x94+4*(n)) /* external int filter control 0..3 */
+#define GPIO_EINTMASK 0xa4
+#define GPIO_EINTPEND 0xa8
+#define GPIO_GSTATUS0 0xac /* external pin status */
+#define GPIO_GSTATUS1 0xb0 /* external pin status */
+
+#define GPIO_SET_FUNC(v,port,func) \
+ (((v) & ~(3<<(2*(port))))|((func)<<(2*(port))))
+
+#define EXTINTR_LOW 0x00
+#define EXTINTR_HIGH 0x01
+#define EXTINTR_FALLING 0x02
+#define EXTINTR_RISING 0x04
+#define EXTINTR_BOTH 0x06
+
+/* SD interface */
+/* XXX */
+
+/* ADC */
+/* XXX: ADCCON register is common to both S3C2410 and S3C2400,
+ * but other registers are different.
+ */
+#define ADC_ADCCON 0x00
+#define ADCCON_ENABLE_START (1<<0)
+#define ADCCON_READ_START (1<<1)
+#define ADCCON_STDBM (1<<2)
+#define ADCCON_SEL_MUX_SHIFT 3
+#define ADCCON_SEL_MUX_MASK (0x7<<ADCCON_SEL_MUX_SHIFT)
+#define ADCCON_PRSCVL_SHIFT 6
+#define ADCCON_PRSCVL_MASK (0xff<<ADCCON_PRSCVL_SHIFT)
+#define ADCCON_PRSCEN (1<<14)
+#define ADCCON_ECFLG (1<<15)
+
+#define ADC_ADCTSC 0x04
+#define ADCTSC_XY_PST 0x03
+#define ADCTSC_AUTO_PST (1<<2)
+#define ADCTSC_PULL_UP (1<<3)
+#define ADCTSC_XP_SEN (1<<4)
+#define ADCTSC_XM_SEN (1<<5)
+#define ADCTSC_YP_SEN (1<<6)
+#define ADCTSC_YM_SEN (1<<7)
+#define ADCTSC_UD_SEN (1<<8)
+#define ADC_ADCDLY 0x08
+#define ADC_ADCDAT0 0x0c
+#define ADC_ADCDAT1 0x10
+
+#define ADCDAT_DATAMASK 0x3ff
+
+#endif /* _ARM_S3C2XX0_S3C2410REG_H_ */
diff --git a/sys/arch/arm/s3c2xx0/s3c2410var.h b/sys/arch/arm/s3c2xx0/s3c2410var.h
new file mode 100644
index 00000000000..d8e1658d44c
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2410var.h
@@ -0,0 +1,46 @@
+/* $OpenBSD: s3c2410var.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2410var.h,v 1.3 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2003 Genetec corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec corporation.
+ *
+ * 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 Genetec corporation may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``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 GENETEC CORP.
+ * 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 _ARM_S3C2410VAR_H_
+#define _ARM_S3C2410VAR_H_
+
+#include <arm/s3c2xx0/s3c24x0var.h>
+
+void s3c2410_intr_init(struct s3c24x0_softc *);
+void s3c2410_softreset(void);
+
+void s3c2410_mask_subinterrupts(int);
+void s3c2410_unmask_subinterrupts(int);
+
+void *s3c2410_extint_establish(int, int, int, int (*)(void *), void *);
+void s3c2410_setup_extint(int, int);
+#endif /* _ARM_S3C2410VAR_H_ */
diff --git a/sys/arch/arm/s3c2xx0/s3c24x0_clk.c b/sys/arch/arm/s3c2xx0/s3c24x0_clk.c
new file mode 100644
index 00000000000..0f9ff9adaad
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c24x0_clk.c
@@ -0,0 +1,337 @@
+/* $OpenBSD: s3c24x0_clk.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c24x0_clk.c,v 1.10 2008/07/04 11:59:45 bsh Exp $ */
+
+/*
+ * Copyright (c) 2003 Genetec corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec corporation.
+ *
+ * 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 Genetec corporation may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``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 GENETEC CORP.
+ * 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>
+/*
+__KERNEL_RCSID(0, "$NetBSD: s3c24x0_clk.c,v 1.10 2008/07/04 11:59:45 bsh Exp $");
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <arm/cpufunc.h>
+
+#include <arm/s3c2xx0/s3c24x0reg.h>
+#include <arm/s3c2xx0/s3c24x0var.h>
+#include <arm/s3c2xx0/s3c2xx0reg.h>
+
+
+#ifndef STATHZ
+#define STATHZ 64
+#endif
+
+#define TIMER_FREQUENCY(pclk) ((pclk)/16) /* divider=1/16 */
+
+static unsigned int timer4_reload_value;
+static unsigned int timer4_prescaler;
+static unsigned int timer4_mseccount;
+
+#define usec_to_counter(t) \
+ ((timer4_mseccount*(t))/1000)
+
+#define counter_to_usec(c,pclk) \
+ (((c)*timer4_prescaler*1000)/(TIMER_FREQUENCY(pclk)/1000))
+
+static u_int s3c24x0_get_timecount(struct timecounter *);
+
+static struct timecounter s3c24x0_timecounter = {
+ s3c24x0_get_timecount, /* get_timecount */
+ 0, /* no poll_pps */
+ 0xffffffff, /* counter_mask */
+ 0, /* frequency */
+ "s3c234x0", /* name */
+ 100, /* quality */
+ NULL, /* prev */
+ NULL, /* next */
+};
+
+static volatile uint32_t s3c24x0_base;
+
+static u_int
+s3c24x0_get_timecount(struct timecounter *tc)
+{
+ struct s3c24x0_softc *sc = (struct s3c24x0_softc *) s3c2xx0_softc;
+ int save, int_pend0, int_pend1, count;
+
+ save = disable_interrupts(I32_bit);
+
+ again:
+ int_pend0 = S3C24X0_INT_TIMER4 &
+ bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_intctl_ioh,
+ INTCTL_SRCPND);
+ count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh,
+ TIMER_TCNTO(4));
+
+ for (;;) {
+
+ int_pend1 = S3C24X0_INT_TIMER4 &
+ bus_space_read_4(sc->sc_sx.sc_iot, sc->sc_sx.sc_intctl_ioh,
+ INTCTL_SRCPND);
+ if( int_pend0 == int_pend1 )
+ break;
+
+ /*
+ * Down counter reached to zero while we were reading
+ * timer values. do it again to get consistent values.
+ */
+ int_pend0 = int_pend1;
+ count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh,
+ TIMER_TCNTO(4));
+ }
+
+ if (__predict_false(count > timer4_reload_value)) {
+ /*
+ * Buggy Hardware Warning --- sometimes timer counter
+ * reads bogus value like 0xffff. I guess it happens when
+ * the timer is reloaded.
+ */
+ printf("Bogus value from timer counter: %d\n", count);
+ goto again;
+ }
+
+ restore_interrupts(save);
+
+ if (int_pend1)
+ count -= timer4_reload_value;
+
+ return s3c24x0_base - count;
+}
+
+static inline int
+read_timer(struct s3c24x0_softc *sc)
+{
+ int count;
+
+ do {
+ count = bus_space_read_2(sc->sc_sx.sc_iot, sc->sc_timer_ioh,
+ TIMER_TCNTO(4));
+ } while ( __predict_false(count > timer4_reload_value) );
+
+ return count;
+}
+
+/*
+ * delay:
+ *
+ * Delay for at least N microseconds.
+ */
+void
+delay(u_int n)
+{
+ struct s3c24x0_softc *sc = (struct s3c24x0_softc *) s3c2xx0_softc;
+ int v0, v1, delta;
+ u_int ucnt;
+
+ if ( timer4_reload_value == 0 ){
+ /* not initialized yet */
+ while ( n-- > 0 ){
+ int m;
+
+ for (m=0; m<100; ++m )
+ ;
+ }
+ return;
+ }
+
+ /* read down counter */
+ v0 = read_timer(sc);
+
+ ucnt = usec_to_counter(n);
+
+ while( ucnt > 0 ) {
+ v1 = read_timer(sc);
+ delta = v0 - v1;
+ if ( delta < 0 )
+ delta += timer4_reload_value;
+#ifdef DEBUG
+ if (delta < 0 || delta > timer4_reload_value)
+ panic("wrong value from timer counter");
+#endif
+
+ if((u_int)delta < ucnt){
+ ucnt -= (u_int)delta;
+ v0 = v1;
+ }
+ else {
+ ucnt = 0;
+ }
+ }
+ /*NOTREACHED*/
+}
+
+void
+setstatclockrate(int newhz)
+{
+}
+
+static int
+hardintr(void *arg)
+{
+ #if 0
+ atomic_add_32(&s3c24x0_base, timer4_reload_value);
+ #else
+ s3c24x0_base += timer4_reload_value;
+ #endif
+
+ hardclock((struct clockframe *)arg);
+
+ return 1;
+}
+
+void
+cpu_initclocks(void)
+{
+ struct s3c24x0_softc *sc = (struct s3c24x0_softc *)s3c2xx0_softc;
+ long tc;
+ int prescaler, h;
+ int pclk = s3c2xx0_softc->sc_pclk;
+ bus_space_tag_t iot = sc->sc_sx.sc_iot;
+ bus_space_handle_t ioh = sc->sc_timer_ioh;
+ uint32_t reg;
+
+ stathz = STATHZ;
+ profhz = stathz;
+
+#define time_constant(hz) (TIMER_FREQUENCY(pclk) /(hz)/ prescaler)
+#define calc_time_constant(hz) \
+ do { \
+ prescaler = 1; \
+ do { \
+ ++prescaler; \
+ tc = time_constant(hz); \
+ } while( tc > 65536 ); \
+ } while(0)
+
+
+ /* Use the channels 4 and 3 for hardclock and statclock, respectively */
+
+ /* stop all timers */
+ bus_space_write_4(iot, ioh, TIMER_TCON, 0);
+
+ /* calc suitable prescaler value */
+ h = MIN(hz,stathz);
+ calc_time_constant(h);
+
+ timer4_prescaler = prescaler;
+ timer4_reload_value = TIMER_FREQUENCY(pclk) / hz / prescaler;
+ timer4_mseccount = TIMER_FREQUENCY(pclk)/timer4_prescaler/1000 ;
+
+ bus_space_write_4(iot, ioh, TIMER_TCNTB(4),
+ ((prescaler - 1) << 16) | (timer4_reload_value - 1));
+
+ printf("clock: hz=%d stathz = %d PCLK=%d prescaler=%d tc=%ld\n",
+ hz, stathz, pclk, prescaler, tc);
+
+ bus_space_write_4(iot, ioh, TIMER_TCNTB(3),
+ ((prescaler - 1) << 16) | (time_constant(stathz) - 1));
+
+ s3c24x0_intr_establish(S3C24X0_INT_TIMER4, IPL_CLOCK,
+ IST_NONE, hardintr, 0);
+#if 0
+#ifdef IPL_STATCLOCK
+ s3c24x0_intr_establish(S3C24X0_INT_TIMER3, IPL_STATCLOCK,
+ IST_NONE, statintr, 0);
+#endif
+#endif
+
+ /* set prescaler1 */
+ reg = bus_space_read_4(iot, ioh, TIMER_TCFG0);
+ bus_space_write_4(iot, ioh, TIMER_TCFG0,
+ (reg & ~0xff00) | ((prescaler-1) << 8));
+
+ /* divider 1/16 for ch #3 and #4 */
+ reg = bus_space_read_4(iot, ioh, TIMER_TCFG1);
+ bus_space_write_4(iot, ioh, TIMER_TCFG1,
+ (reg & ~(TCFG1_MUX_MASK(3)|TCFG1_MUX_MASK(4))) |
+ (TCFG1_MUX_DIV16 << TCFG1_MUX_SHIFT(3)) |
+ (TCFG1_MUX_DIV16 << TCFG1_MUX_SHIFT(4)) );
+
+
+ /* start timers */
+ reg = bus_space_read_4(iot, ioh, TIMER_TCON);
+ reg &= ~(TCON_MASK(3)|TCON_MASK(4));
+
+ /* load the time constant */
+ bus_space_write_4(iot, ioh, TIMER_TCON, reg |
+ TCON_MANUALUPDATE(3) | TCON_MANUALUPDATE(4));
+ /* set auto reload and start */
+ bus_space_write_4(iot, ioh, TIMER_TCON, reg |
+ TCON_AUTORELOAD(3) | TCON_START(3) |
+ TCON_AUTORELOAD(4) | TCON_START(4) );
+
+ s3c24x0_timecounter.tc_frequency = TIMER_FREQUENCY(pclk) / timer4_prescaler;
+ tc_init(&s3c24x0_timecounter);
+}
+
+
+#if 0
+/* test routine for delay() */
+
+void delay_test(void);
+void
+delay_test(void)
+{
+ struct s3c2xx0_softc *sc = s3c2xx0_softc;
+ volatile int *pdatc = (volatile int *)
+ ((char *)bus_space_vaddr(sc->sc_iot, sc->sc_gpio_ioh) + GPIO_PDATC);
+ static const int d[] = {0, 1, 5, 10, 50, 100, 500, 1000, -1};
+ int i;
+ int v = *pdatc & ~0x07;
+
+ for (;;) {
+ *pdatc = v | 2;
+
+ for (i=0; d[i] >= 0; ++i) {
+ *pdatc = v | 3;
+ delay(d[i]);
+ *pdatc = v | 2;
+ }
+ *pdatc = v;
+ }
+}
+#endif
+
+
+void
+inittodr(time_t base)
+{
+}
+
+void
+resettodr(void)
+{
+}
diff --git a/sys/arch/arm/s3c2xx0/s3c24x0_intr.h b/sys/arch/arm/s3c2xx0/s3c24x0_intr.h
new file mode 100644
index 00000000000..79f86bc1b43
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c24x0_intr.h
@@ -0,0 +1,57 @@
+/* $OpenBSD: s3c24x0_intr.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c24x0_intr.h,v 1.8 2008/04/27 18:58:45 matt Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Genetec corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec corporation.
+ *
+ * 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 Genetec corporation may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``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 GENETEC CORP.
+ * 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 _S3C24X0_INTR_H_
+#define _S3C24X0_INTR_H_
+
+#ifndef _LOCORE
+
+#ifdef __HAVE_FAST_SOFTINTS
+#define SI_TO_IRQBIT(si) (1<<(si))
+
+/* no room for softinterrupts in intr_mask. */
+extern int volatile soft_intr_mask;
+extern int s3c24x0_soft_imask[];
+
+#define get_pending_softint() (softint_pending & soft_intr_mask)
+#define update_softintr_mask() \
+ (soft_intr_mask = s3c24x0_soft_imask[curcpl()])
+#endif
+
+#define s3c2xx0_update_hw_mask() \
+ (*s3c2xx0_intr_mask_reg = ~(intr_mask & global_intr_mask))
+
+#include <arm/s3c2xx0/s3c2xx0_intr.h>
+
+#endif /* ! _LOCORE */
+
+#endif /* _S3C24X0_INTR_H_ */
diff --git a/sys/arch/arm/s3c2xx0/s3c24x0var.h b/sys/arch/arm/s3c2xx0/s3c24x0var.h
new file mode 100644
index 00000000000..6510ad923de
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c24x0var.h
@@ -0,0 +1,48 @@
+/* $OpenBSD: s3c24x0var.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c24x0var.h,v 1.3 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2003 Genetec corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec corporation.
+ *
+ * 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 Genetec corporation may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORP. ``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 GENETEC CORP.
+ * 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 _ARM_S3C24X0VAR_H_
+#define _ARM_S3C24X0VAR_H_
+
+#include <arm/s3c2xx0/s3c2xx0var.h>
+
+struct s3c24x0_softc {
+ struct s3c2xx0_softc sc_sx;
+
+ bus_space_handle_t sc_timer_ioh; /* Timer control registers */
+};
+
+void s3c24x0_clock_freq(struct s3c2xx0_softc *);
+void s3c24x0_clock_freq2(vaddr_t, int *, int *, int *);
+void *s3c24x0_intr_establish(int, int, int, s3c2xx0_irq_handler_t, void *);
+
+#endif /* _ARM_S3C24X0VAR_H_ */
diff --git a/sys/arch/arm/s3c2xx0/s3c2xx0_busdma.c b/sys/arch/arm/s3c2xx0/s3c2xx0_busdma.c
new file mode 100644
index 00000000000..7cb05861311
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2xx0_busdma.c
@@ -0,0 +1,73 @@
+/* $OpenBSD: s3c2xx0_busdma.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2xx0_busdma.c,v 1.3 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Fujitsu Component Limited
+ * Copyright (c) 2002, 2003 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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.
+ */
+
+/*
+ * bus_dma tag for s3c2xx0 CPUs
+ */
+
+#include <sys/cdefs.h>
+/*
+__KERNEL_RCSID(0, "$NetBSD: s3c2xx0_busdma.c,v 1.3 2005/12/11 12:16:51 christos Exp $");
+*/
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/extent.h>
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
+#include <arm/s3c2xx0/s3c2xx0var.h>
+
+struct arm32_bus_dma_tag s3c2xx0_bus_dma = {
+ 0,
+ 0,
+ NULL,
+ _bus_dmamap_create,
+ _bus_dmamap_destroy,
+ _bus_dmamap_load,
+ _bus_dmamap_load_mbuf,
+ _bus_dmamap_load_uio,
+ _bus_dmamap_load_raw,
+ _bus_dmamap_unload,
+ _bus_dmamap_sync,
+ _bus_dmamem_alloc,
+ _bus_dmamem_free,
+ _bus_dmamem_map,
+ _bus_dmamem_unmap,
+ _bus_dmamem_mmap,
+};
diff --git a/sys/arch/arm/s3c2xx0/s3c2xx0_intr.c b/sys/arch/arm/s3c2xx0/s3c2xx0_intr.c
new file mode 100644
index 00000000000..d737885eaa0
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2xx0_intr.c
@@ -0,0 +1,363 @@
+/* $OpenBSD: s3c2xx0_intr.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2xx0_intr.c,v 1.13 2008/04/27 18:58:45 matt Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Fujitsu Component Limited
+ * Copyright (c) 2002, 2003 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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.
+ */
+
+/*
+ * Common part of IRQ handlers for Samsung S3C2800/2400/2410 processors.
+ * derived from i80321_icu.c
+ */
+
+/*
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+/*
+__KERNEL_RCSID(0, "$NetBSD: s3c2xx0_intr.c,v 1.13 2008/04/27 18:58:45 matt Exp $");
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <uvm/uvm_extern.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <arm/cpufunc.h>
+
+#include <arm/s3c2xx0/s3c2xx0reg.h>
+#include <arm/s3c2xx0/s3c2xx0var.h>
+
+#include <arm/s3c2xx0/s3c2xx0_intr.h>
+
+volatile uint32_t *s3c2xx0_intr_mask_reg;
+extern volatile int intr_mask;
+extern volatile int global_intr_mask;
+
+int s3c2xx0_cpl;
+
+#define SI_TO_IRQBIT(x) (1 << (x))
+
+int
+s3c2xx0_curcpl()
+{
+ return s3c2xx0_cpl;
+}
+
+void
+s3c2xx0_set_curcpl(int new)
+{
+ s3c2xx0_cpl = new;
+}
+
+static inline void
+__raise(int ipl)
+{
+ if (s3c2xx0_curcpl() < ipl) {
+ s3c2xx0_setipl(ipl);
+ }
+}
+
+/*
+ * modify interrupt mask table for SPL levels
+ */
+void
+s3c2xx0_update_intr_masks(int irqno, int level)
+{
+ int mask = 1 << irqno;
+ int i;
+
+
+ s3c2xx0_ilevel[irqno] = level;
+
+ for (i = 0; i < level; ++i)
+ s3c2xx0_imask[i] |= mask; /* Enable interrupt at lower
+ * level */
+ for (; i < NIPL - 1; ++i)
+ s3c2xx0_imask[i] &= ~mask; /* Disable interrupt at upper
+ * level */
+
+ /*
+ * Enforce a hierarchy that gives "slow" device (or devices with
+ * limited input buffer space/"real-time" requirements) a better
+ * chance at not dropping data.
+ */
+ s3c2xx0_imask[IPL_VM] &= s3c2xx0_imask[IPL_SOFTSERIAL];
+ s3c2xx0_imask[IPL_CLOCK] &= s3c2xx0_imask[IPL_VM];
+ s3c2xx0_imask[IPL_HIGH] &= s3c2xx0_imask[IPL_CLOCK];
+
+ /* initialize soft interrupt mask */
+ for (i = IPL_NONE; i <= IPL_HIGH; i++) {
+ s3c2xx0_smask[i] = 0;
+ if (i < IPL_SOFT)
+ s3c2xx0_smask[i] |= SI_TO_IRQBIT(SI_SOFT);
+ if (i < IPL_SOFTCLOCK)
+ s3c2xx0_smask[i] |= SI_TO_IRQBIT(SI_SOFTCLOCK);
+ if (i < IPL_SOFTNET)
+ s3c2xx0_smask[i] |= SI_TO_IRQBIT(SI_SOFTNET);
+ if (i < IPL_SOFTSERIAL)
+ s3c2xx0_smask[i] |= SI_TO_IRQBIT(SI_SOFTSERIAL);
+#if 0
+ printf("mask[%d]: %x %x\n", i, s3c2xx0_smask[i],
+ s3c2xx0_sk[i]);
+#endif
+ }
+
+}
+
+static int
+stray_interrupt(void *cookie)
+{
+ int save;
+ int irqno = (int) cookie;
+ printf("stray interrupt %d\n", irqno);
+
+ save = disable_interrupts(I32_bit);
+ *s3c2xx0_intr_mask_reg &= ~(1U << irqno);
+ restore_interrupts(save);
+
+ return 0;
+}
+
+/*
+ * Initialize interrupt dispatcher.
+ */
+void
+s3c2xx0_intr_init(struct s3c2xx0_intr_dispatch * dispatch_table, int icu_len)
+{
+ int i;
+
+ for (i = 0; i < icu_len; ++i) {
+ dispatch_table[i].func = stray_interrupt;
+ dispatch_table[i].cookie = (void *) (i);
+ dispatch_table[i].level = IPL_VM;
+ }
+
+ global_intr_mask = ~0; /* no intr is globally blocked. */
+
+ _splraise(IPL_VM);
+ enable_interrupts(I32_bit);
+}
+
+/*
+ * initialize variables so that splfoo() doesn't touch illegal address.
+ * called during bootstrap.
+ */
+void
+s3c2xx0_intr_bootstrap(vaddr_t icureg)
+{
+ s3c2xx0_intr_mask_reg = (volatile uint32_t *)(icureg + INTCTL_INTMSK);
+}
+
+
+
+#undef splx
+void
+splx(int ipl)
+{
+ s3c2xx0_splx(ipl);
+}
+
+#undef _splraise
+int
+_splraise(int ipl)
+{
+ return s3c2xx0_splraise(ipl);
+}
+
+#undef _spllower
+int
+_spllower(int ipl)
+{
+ return s3c2xx0_spllower(ipl);
+}
+
+void
+s3c2xx0_mask_interrupts(int mask)
+{
+ int save = disable_interrupts(I32_bit);
+ global_intr_mask &= ~mask;
+ s3c2xx0_update_hw_mask();
+ restore_interrupts(save);
+}
+
+void
+s3c2xx0_unmask_interrupts(int mask)
+{
+ int save = disable_interrupts(I32_bit);
+ global_intr_mask |= mask;
+ s3c2xx0_update_hw_mask();
+ restore_interrupts(save);
+}
+
+void
+s3c2xx0_setipl(int new)
+{
+ s3c2xx0_set_curcpl(new);
+ intr_mask = s3c2xx0_imask[s3c2xx0_curcpl()];
+ s3c2xx0_update_hw_mask();
+#ifdef __HAVE_FAST_SOFTINTS
+ update_softintr_mask();
+#endif
+}
+
+
+void
+s3c2xx0_splx(int new)
+{
+ int psw;
+
+ psw = disable_interrupts(I32_bit);
+ s3c2xx0_setipl(new);
+ restore_interrupts(psw);
+
+#ifdef __HAVE_FAST_SOFTINTS
+ cpu_dosoftints();
+#endif
+}
+
+
+int
+s3c2xx0_splraise(int ipl)
+{
+ int old, psw;
+
+ old = s3c2xx0_curcpl();
+ if( ipl > old ){
+ psw = disable_interrupts(I32_bit);
+ s3c2xx0_setipl(ipl);
+ restore_interrupts(psw);
+ }
+
+ return (old);
+}
+
+int
+s3c2xx0_spllower(int ipl)
+{
+ int old = s3c2xx0_curcpl();
+ int psw = disable_interrupts(I32_bit);
+ s3c2xx0_splx(ipl);
+ restore_interrupts(psw);
+ return(old);
+}
+
+/* XXX */
+void s3c2xx0_do_pending(void);
+
+int softint_pending;
+void
+s3c2xx0_setsoftintr(int si)
+{
+ int oldirqstate;
+
+ oldirqstate = disable_interrupts(I32_bit);
+ softint_pending |= SI_TO_IRQBIT(si);
+ restore_interrupts(oldirqstate);
+
+ /* Process unmasked pending soft interrupts. */
+ if (softint_pending & s3c2xx0_smask[s3c2xx0_curcpl()])
+ s3c2xx0_do_pending();
+}
+
+
+void
+s3c2xx0_do_pending(void)
+{
+ static int processing = 0;
+ int oldirqstate, spl_save;
+
+ oldirqstate = disable_interrupts(I32_bit);
+
+ spl_save = s3c2xx0_curcpl();
+
+ if (processing == 1) {
+ restore_interrupts(oldirqstate);
+ return;
+ }
+
+#define DO_SOFTINT(si, ipl) \
+ if ((softint_pending & s3c2xx0_smask[s3c2xx0_curcpl()]) & \
+ SI_TO_IRQBIT(si)) { \
+ softint_pending &= ~SI_TO_IRQBIT(si); \
+ if (s3c2xx0_curcpl() < ipl) \
+ s3c2xx0_setipl(ipl); \
+ restore_interrupts(oldirqstate); \
+ softintr_dispatch(si); \
+ oldirqstate = disable_interrupts(I32_bit); \
+ s3c2xx0_setipl(spl_save); \
+ }
+
+ do {
+ DO_SOFTINT(SI_SOFTSERIAL, IPL_SOFTSERIAL);
+ DO_SOFTINT(SI_SOFTNET, IPL_SOFTNET);
+ DO_SOFTINT(SI_SOFTCLOCK, IPL_SOFTCLOCK);
+ DO_SOFTINT(SI_SOFT, IPL_SOFT);
+ } while (softint_pending & s3c2xx0_smask[s3c2xx0_curcpl()]);
+
+
+ processing = 0;
+ restore_interrupts(oldirqstate);
+}
+
diff --git a/sys/arch/arm/s3c2xx0/s3c2xx0_intr.h b/sys/arch/arm/s3c2xx0/s3c2xx0_intr.h
new file mode 100644
index 00000000000..e311e265747
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2xx0_intr.h
@@ -0,0 +1,266 @@
+/* $OpenBSD: s3c2xx0_intr.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2xx0_intr.h,v 1.13 2008/11/19 06:35:55 matt Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Fujitsu Component Limited
+ * Copyright (c) 2002, 2003 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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.
+ */
+
+/* Derived from i80321_intr.h */
+
+/*
+ * 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.
+ */
+
+#ifndef _S3C2XX0_INTR_H_
+#define _S3C2XX0_INTR_H_
+
+#ifndef _LOCORE
+
+#include <arm/cpu.h>
+#include <arm/armreg.h>
+#include <arm/cpufunc.h>
+#include <arm/softintr.h>
+
+void s3c2xx0_setipl(int new);
+void s3c2xx0_splx(int new);
+int s3c2xx0_splraise(int ipl);
+int s3c2xx0_spllower(int ipl);
+void s3c2xx0_setsoftintr(int si);
+
+int s3c2xx0_curcpl(void);
+
+void s3c2xx0_set_curcpl(int new);
+
+int _splraise(int);
+int _spllower(int);
+void splx(int);
+void _setsoftintr(int);
+
+#define splx(new) s3c2xx0_splx(new)
+#define _spllower(ipl) s3c2xx0_spllower(ipl)
+#define _splraise(ipl) s3c2xx0_splraise(ipl)
+#define _setsoftintr(ipl) s3c2xx0_setsoftintr(ipl)
+
+typedef int (* s3c2xx0_irq_handler_t)(void *);
+
+void s3c2xx0_update_intr_masks( int, int );
+
+extern int s3c2xx0_imask[];
+extern int s3c2xx0_smask[];
+extern int s3c2xx0_ilevel[];
+
+void s3c2xx0_mask_interrupts(int mask);
+void s3c2xx0_unmask_interrupts(int mask);
+
+
+
+#if 0
+
+#include <arm/s3c2xx0/s3c2xx0reg.h>
+
+typedef int (* s3c2xx0_irq_handler_t)(void *);
+
+extern volatile uint32_t *s3c2xx0_intr_mask_reg;
+
+extern volatile int intr_mask;
+extern volatile int global_intr_mask;
+#ifdef __HAVE_FAST_SOFTINTS
+extern volatile int softint_pending;
+#endif
+extern int s3c2xx0_imask[];
+extern int s3c2xx0_ilevel[];
+
+void s3c2xx0_update_intr_masks( int, int );
+
+static inline void
+s3c2xx0_mask_interrupts(int mask)
+{
+ int save = disable_interrupts(I32_bit);
+ global_intr_mask &= ~mask;
+ s3c2xx0_update_hw_mask();
+ restore_interrupts(save);
+}
+
+static inline void
+s3c2xx0_unmask_interrupts(int mask)
+{
+ int save = disable_interrupts(I32_bit);
+ global_intr_mask |= mask;
+ s3c2xx0_update_hw_mask();
+ restore_interrupts(save);
+}
+
+static inline void
+s3c2xx0_setipl(int new)
+{
+ set_curcpl(new);
+ intr_mask = s3c2xx0_imask[curcpl()];
+ s3c2xx0_update_hw_mask();
+#ifdef __HAVE_FAST_SOFTINTS
+ update_softintr_mask();
+#endif
+}
+
+
+static inline void
+s3c2xx0_splx(int new)
+{
+ int psw;
+
+ psw = disable_interrupts(I32_bit);
+ s3c2xx0_setipl(new);
+ restore_interrupts(psw);
+
+#ifdef __HAVE_FAST_SOFTINTS
+ cpu_dosoftints();
+#endif
+}
+
+
+static inline int
+s3c2xx0_splraise(int ipl)
+{
+ int old, psw;
+
+ old = curcpl();
+ if( ipl > old ){
+ psw = disable_interrupts(I32_bit);
+ s3c2xx0_setipl(ipl);
+ restore_interrupts(psw);
+ }
+
+ return (old);
+}
+
+static inline int
+s3c2xx0_spllower(int ipl)
+{
+ int old = curcpl();
+ int psw = disable_interrupts(I32_bit);
+ s3c2xx0_splx(ipl);
+ restore_interrupts(psw);
+ return(old);
+}
+
+int _splraise(int);
+int _spllower(int);
+void splx(int);
+
+#if !defined(EVBARM_SPL_NOINLINE)
+
+#define splx(new) s3c2xx0_splx(new)
+#define _spllower(ipl) s3c2xx0_spllower(ipl)
+#define _splraise(ipl) s3c2xx0_splraise(ipl)
+
+#endif /* !EVBARM_SPL_NOINTR */
+
+#endif
+
+#ifdef DIAGNOSTIC
+/*
+ * Although this function is implemented in MI code, it must be in this MD
+ * header because we don't want this header to include MI includes.
+ */
+void splassert_fail(int, int, const char *);
+extern int splassert_ctl;
+void pxa2x0_splassert_check(int, const char *);
+#define splassert(__wantipl) do { \
+ if (splassert_ctl > 0) { \
+ pxa2x0_splassert_check(__wantipl, __func__); \
+ } \
+} while (0)
+#else
+#define splassert(wantipl) do { /* nothing */ } while (0)
+#endif
+
+
+/*
+ * interrupt dispatch table.
+ */
+#ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
+struct intrhand {
+ TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */
+ s3c2xx0_irq_handler_t ih_func; /* handler */
+ void *ih_arg; /* arg for handler */
+};
+#endif
+
+struct s3c2xx0_intr_dispatch {
+#ifdef MULTIPLE_HANDLERS_ON_ONE_IRQ
+ TAILQ_HEAD(,intrhand) list;
+#else
+ s3c2xx0_irq_handler_t func;
+#endif
+ void *cookie; /* NULL for stackframe */
+ int level;
+ /* struct evbnt ev; */
+};
+
+/* used by s3c2{80,40,41}0 interrupt handler */
+void s3c2xx0_intr_init(struct s3c2xx0_intr_dispatch *, int );
+
+/* initialize some variable so that splfoo() doesn't touch ileegal
+ address during bootstrap */
+void s3c2xx0_intr_bootstrap(vaddr_t);
+#endif
+
+#endif /* _S3C2XX0_INTR_H_ */
diff --git a/sys/arch/arm/s3c2xx0/s3c2xx0_mutex.c b/sys/arch/arm/s3c2xx0/s3c2xx0_mutex.c
new file mode 100644
index 00000000000..04c3332a1e5
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2xx0_mutex.c
@@ -0,0 +1,67 @@
+/* $OpenBSD: s3c2xx0_mutex.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+
+/*
+ * Copyright (c) 2004 Artur Grabowski <art@openbsd.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. 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 ``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/param.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <machine/intr.h>
+
+#ifdef MULTIPROCESSOR
+#error This code needs work
+#endif
+
+/*
+ * Single processor systems don't need any mutexes, but they need the spl
+ * raising semantics of the mutexes.
+ */
+void
+mtx_init(struct mutex *mtx, int wantipl)
+{
+ mtx->mtx_oldipl = 0;
+ mtx->mtx_wantipl = wantipl;
+ mtx->mtx_lock = 0;
+}
+
+void
+mtx_enter(struct mutex *mtx)
+{
+ if (mtx->mtx_wantipl != IPL_NONE)
+ mtx->mtx_oldipl = _splraise(mtx->mtx_wantipl);
+
+ MUTEX_ASSERT_UNLOCKED(mtx);
+ mtx->mtx_lock = 1;
+}
+
+void
+mtx_leave(struct mutex *mtx)
+{
+ MUTEX_ASSERT_LOCKED(mtx);
+ mtx->mtx_lock = 0;
+ if (mtx->mtx_wantipl != IPL_NONE)
+ splx(mtx->mtx_oldipl);
+}
diff --git a/sys/arch/arm/s3c2xx0/s3c2xx0_space.c b/sys/arch/arm/s3c2xx0/s3c2xx0_space.c
new file mode 100644
index 00000000000..c7b741eae2d
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2xx0_space.c
@@ -0,0 +1,268 @@
+/* $OpenBSD: s3c2xx0_space.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2xx0_space.c,v 1.7 2005/11/24 13:08:32 yamt Exp $ */
+
+/*
+ * Copyright (c) 2002 Fujitsu Component Limited
+ * Copyright (c) 2002 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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.
+ */
+/* derived from sa11x0_io.c */
+
+/*
+ * Copyright (c) 1997 Mark Brinicombe.
+ * Copyright (c) 1997 Causality Limited.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Ichiro FUKUHARA.
+ *
+ * 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 Mark Brinicombe.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY 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 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.
+ */
+
+/*
+ * bus_space functions for Samsung S3C2800/2400/2410.
+ */
+
+#include <sys/cdefs.h>
+/*
+__KERNEL_RCSID(0, "$NetBSD: s3c2xx0_space.c,v 1.7 2005/11/24 13:08:32 yamt Exp $");
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <uvm/uvm_extern.h>
+#include <arm/pmap.h>
+
+#include <machine/bus.h>
+
+/* Prototypes for all the bus_space structure functions */
+bs_protos(s3c2xx0);
+bs_protos(generic);
+bs_protos(generic_armv4);
+bs_protos(bs_notimpl);
+
+struct bus_space s3c2xx0_bs_tag = {
+ /* cookie */
+ (void *) 0,
+
+ /* mapping/unmapping */
+ s3c2xx0_bs_map,
+ s3c2xx0_bs_unmap,
+ s3c2xx0_bs_subregion,
+
+ /* allocation/deallocation */
+ s3c2xx0_bs_alloc, /* not implemented */
+ s3c2xx0_bs_free, /* not implemented */
+
+ /* get kernel virtual address */
+ s3c2xx0_bs_vaddr,
+
+ /* mmap */
+ bs_notimpl_bs_mmap,
+
+ /* barrier */
+ s3c2xx0_bs_barrier,
+
+ /* read (single) */
+ generic_bs_r_1,
+ generic_armv4_bs_r_2,
+ generic_bs_r_4,
+ bs_notimpl_bs_r_8,
+
+ /* read multiple */
+ generic_bs_rm_1,
+ generic_armv4_bs_rm_2,
+ generic_bs_rm_4,
+ bs_notimpl_bs_rm_8,
+
+ /* read region */
+ generic_bs_rr_1,
+ generic_armv4_bs_rr_2,
+ generic_bs_rr_4,
+ bs_notimpl_bs_rr_8,
+
+ /* write (single) */
+ generic_bs_w_1,
+ generic_armv4_bs_w_2,
+ generic_bs_w_4,
+ bs_notimpl_bs_w_8,
+
+ /* write multiple */
+ generic_bs_wm_1,
+ generic_armv4_bs_wm_2,
+ generic_bs_wm_4,
+ bs_notimpl_bs_wm_8,
+
+ /* write region */
+ generic_bs_wr_1,
+ generic_armv4_bs_wr_2,
+ generic_bs_wr_4,
+ bs_notimpl_bs_wr_8,
+
+ /* set multiple */
+ bs_notimpl_bs_sm_1,
+ bs_notimpl_bs_sm_2,
+ bs_notimpl_bs_sm_4,
+ bs_notimpl_bs_sm_8,
+
+ /* set region */
+ generic_bs_sr_1,
+ generic_armv4_bs_sr_2,
+ bs_notimpl_bs_sr_4,
+ bs_notimpl_bs_sr_8,
+
+ /* copy */
+ bs_notimpl_bs_c_1,
+ generic_armv4_bs_c_2,
+ bs_notimpl_bs_c_4,
+ bs_notimpl_bs_c_8,
+};
+
+int
+s3c2xx0_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int flag, bus_space_handle_t * bshp)
+{
+ u_long startpa, endpa, pa;
+ vaddr_t va;
+ pt_entry_t *pte;
+ const struct pmap_devmap *pd;
+
+ if ((pd = pmap_devmap_find_pa(bpa, size)) != NULL) {
+ /* Device was statically mapped. */
+ *bshp = pd->pd_va + (bpa - pd->pd_pa);
+ return 0;
+ }
+ startpa = trunc_page(bpa);
+ endpa = round_page(bpa + size);
+
+ /* XXX use extent manager to check duplicate mapping */
+
+ va = uvm_km_alloc(kernel_map, endpa - startpa);
+ if (!va)
+ return (ENOMEM);
+
+ *bshp = (bus_space_handle_t) (va + (bpa - startpa));
+
+ for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE) {
+ pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
+ pte = vtopte(va);
+ if ((flag & BUS_SPACE_MAP_CACHEABLE) == 0)
+ *pte &= ~L2_S_CACHE_MASK;
+ }
+ pmap_update(pmap_kernel());
+
+ return (0);
+}
+
+void
+s3c2xx0_bs_unmap(void *t, bus_space_handle_t bsh, bus_size_t size)
+{
+ vaddr_t va;
+ vaddr_t endva;
+
+ if (pmap_devmap_find_va(bsh, size) != NULL) {
+ /* Device was statically mapped; nothing to do. */
+ return;
+ }
+
+ endva = round_page(bsh + size);
+ va = trunc_page(bsh);
+
+ pmap_kremove(va, endva - va);
+ pmap_update(pmap_kernel());
+ uvm_km_free(kernel_map, va, endva - va);
+}
+
+
+int
+s3c2xx0_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t size, bus_space_handle_t * nbshp)
+{
+
+ *nbshp = bsh + offset;
+ return (0);
+}
+
+void
+s3c2xx0_bs_barrier(void *t, bus_space_handle_t bsh, bus_size_t offset,
+ bus_size_t len, int flags)
+{
+
+ /* Nothing to do. */
+}
+
+void *
+s3c2xx0_bs_vaddr(void *t, bus_space_handle_t bsh)
+{
+
+ return ((void *) bsh);
+}
+
+
+int
+s3c2xx0_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend,
+ bus_size_t size, bus_size_t alignment, bus_size_t boundary,
+ int flags, bus_addr_t * bpap, bus_space_handle_t * bshp)
+{
+
+ panic("s3c2xx0_io_bs_alloc(): not implemented\n");
+}
+
+void
+s3c2xx0_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size)
+{
+
+ panic("s3c2xx0_io_bs_free(): not implemented\n");
+}
diff --git a/sys/arch/arm/s3c2xx0/s3c2xx0reg.h b/sys/arch/arm/s3c2xx0/s3c2xx0reg.h
new file mode 100644
index 00000000000..551b4132506
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2xx0reg.h
@@ -0,0 +1,137 @@
+/* $OpenBSD: s3c2xx0reg.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2xx0reg.h,v 1.5 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Fujitsu Component Limited
+ * Copyright (c) 2002, 2003 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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.
+ */
+
+
+/*
+ * Register definitions common to S3C2800 and S3C24[01]0
+ */
+#ifndef _ARM_S3C2XX0_S3C2XX0REG_H_
+#define _ARM_S3C2XX0_S3C2XX0REG_H_
+
+/* UART */
+/*
+ * S3C2800, 2410 and 2400 have a common built-in UART block. However,
+ * there are small diffs in bit position of some registers.
+ * Following definitions can be foune in s3c{2800,24x0}reg.h for
+ * that reason.
+ *
+ * ULCON_IR (Infra-red mode)
+ * ULCON_PARITY_SHIFT (Parity mode bit position)
+ * UMCON_AFC (Auto flow control)
+ * UMSTAT_DCTS (CTS change)
+ */
+
+#define SSCOM_ULCON 0x00 /* UART line control */
+/* ULCON_PARITY_SHIFT and ULCON_IR is defined in s3c{2800,24x0}reg.h */
+#define ULCON_PARITY_NONE (0<<ULCON_PARITY_SHIFT)
+#define ULCON_PARITY_ODD (4<<ULCON_PARITY_SHIFT)
+#define ULCON_PARITY_EVEN (5<<ULCON_PARITY_SHIFT)
+#define ULCON_PARITY_ONE (6<<ULCON_PARITY_SHIFT)
+#define ULCON_PARITY_ZERO (7<<ULCON_PARITY_SHIFT)
+#define ULCON_STOP (1<<2)
+#define ULCON_LENGTH_5 0
+#define ULCON_LENGTH_6 1
+#define ULCON_LENGTH_7 2
+#define ULCON_LENGTH_8 3
+#define SSCOM_UCON 0x04 /* UART control */
+#define UCON_TXINT_TYPE (1<<9) /* Tx interrupt. 0=pulse,1=level */
+#define UCON_TXINT_TYPE_LEVEL UCON_TXINT_TYPE
+#define UCON_TXINT_TYPE_PULSE 0
+#define UCON_RXINT_TYPE (1<<8) /* Rx interrupt */
+#define UCON_RXINT_TYPE_LEVEL UCON_RXINT_TYPE
+#define UCON_RXINT_TYPE_PULSE 0
+#define UCON_TOINT (1<<7) /* Rx timeout interrupt */
+#define UCON_ERRINT (1<<6) /* receive error interrupt */
+#define UCON_LOOP (1<<5) /* loopback */
+#define UCON_SBREAK (1<<4) /* send break */
+#define UCON_TXMODE_DISABLE (0<<2)
+#define UCON_TXMODE_INT (1<<2)
+#define UCON_TXMODE_DMA (2<<2)
+#define UCON_TXMODE_MASK (3<<2)
+#define UCON_RXMODE_DISABLE (0<<0)
+#define UCON_RXMODE_INT (1<<0)
+#define UCON_RXMODE_DMA (2<<0)
+#define UCON_RXMODE_MASK (3<<0)
+#define SSCOM_UFCON 0x08 /* FIFO control */
+#define UFCON_TXTRIGGER_0 (0<<6)
+#define UFCON_TXTRIGGER_4 (1<<6)
+#define UFCON_TXTRIGGER_8 (2<<6)
+#define UFCON_TXTRIGGER_16 (3<<6)
+#define UFCON_RXTRIGGER_4 (0<<4)
+#define UFCON_RXTRIGGER_8 (1<<4)
+#define UFCON_RXTRIGGER_12 (2<<4)
+#define UFCON_RXTRIGGER_16 (3<<4)
+#define UFCON_TXFIFO_RESET (1<<2)
+#define UFCON_RXFIFO_RESET (1<<1)
+#define UFCON_FIFO_ENABLE (1<<0)
+#define SSCOM_UMCON 0x0c /* MODEM control */
+/* UMCON_AFC is defined in s3c{2800,24x0}reg.h */
+#define UMCON_RTS (1<<0) /* Request to send */
+#define SSCOM_UTRSTAT 0x10 /* Status register */
+#define UTRSTAT_TXSHIFTER_EMPTY (1<<2)
+#define UTRSTAT_TXEMPTY (1<<1) /* TX fifo or buffer empty */
+#define UTRSTAT_RXREADY (1<<0) /* RX fifo or buffer is not empty */
+#define SSCOM_UERSTAT 0x14 /* Error status register */
+#define UERSTAT_BREAK (1<<3) /* Break signal */
+#define UERSTAT_FRAME (1<<2) /* Frame error */
+#define UERSTAT_PARITY (1<<1) /* Parity error */
+#define UERSTAT_OVERRUN (1<<0) /* Overrun */
+#define UERSTAT_ALL_ERRORS (UERSTAT_OVERRUN|UERSTAT_BREAK|UERSTAT_FRAME|UERSTAT_PARITY)
+#define SSCOM_UFSTAT 0x18 /* Fifo status register */
+#define UFSTAT_TXFULL (1<<9) /* Tx fifo full */
+#define UFSTAT_RXFULL (1<<8) /* Rx fifo full */
+#define UFSTAT_TXCOUNT_SHIFT 4 /* TX FIFO count */
+#define UFSTAT_TXCOUNT (0x0f<<UFSTAT_TXCOUNT_SHIFT)
+#define UFSTAT_RXCOUNT_SHIFT 0 /* RX FIFO count */
+#define UFSTAT_RXCOUNT (0x0f<<UFSTAT_RXCOUNT_SHIFT)
+#define SSCOM_UMSTAT 0x1c /* Modem status register */
+/* UMSTAT_DCTS is defined in s3c{2800,24x0}reg.h */
+#define UMSTAT_CTS (1<<0) /* Clear to send */
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#define SSCOM_UTXH 0x20 /* Transmit data register */
+#define SSCOM_URXH 0x24 /* Receive data register */
+#else
+#define SSCOM_UTXH 0x23 /* Transmit data register */
+#define SSCOM_URXH 0x27 /* Receive data register */
+#endif
+#define SSCOM_UBRDIV 0x28 /* baud-reate divisor */
+#define SSCOM_SIZE 0x2c
+
+/* Interrupt controller (Common to S3c2800/2400X/2410X) */
+#define INTCTL_SRCPND 0x00 /* Interrupt request status */
+#define INTCTL_INTMOD 0x04 /* Interrupt mode (FIQ/IRQ) */
+#define INTCTL_INTMSK 0x08 /* Interrupt mask */
+
+#endif /* _ARM_S3C2XX0_S3C2XX0REG_H_ */
diff --git a/sys/arch/arm/s3c2xx0/s3c2xx0var.h b/sys/arch/arm/s3c2xx0/s3c2xx0var.h
new file mode 100644
index 00000000000..bd8fa38ceb4
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/s3c2xx0var.h
@@ -0,0 +1,79 @@
+/* $OpenBSD: s3c2xx0var.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: s3c2xx0var.h,v 1.4 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2002 Fujitsu Component Limited
+ * Copyright (c) 2002 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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 _ARM_S3C2XX0VAR_H_
+#define _ARM_S3C2XX0VAR_H_
+
+#include <machine/bus.h>
+
+struct s3c2xx0_softc {
+ struct device sc_dev;
+
+ bus_space_tag_t sc_iot;
+
+ bus_space_handle_t sc_intctl_ioh;
+ bus_space_handle_t sc_memctl_ioh; /* Memory controller */
+ bus_space_handle_t sc_clkman_ioh; /* Clock manager */
+ bus_space_handle_t sc_gpio_ioh; /* GPIO */
+ bus_space_handle_t sc_rtc_ioh; /* real time clock */
+
+ bus_dma_tag_t sc_dmat;
+
+ /* clock frequency */
+ int sc_fclk; /* CPU clock */
+ int sc_hclk; /* AHB bus clock */
+ int sc_pclk; /* peripheral clock */
+};
+
+typedef void *s3c2xx0_chipset_tag_t;
+
+struct s3c2xx0_attach_args {
+ s3c2xx0_chipset_tag_t sa_sc;
+ bus_space_tag_t sa_iot;
+ bus_addr_t sa_addr;
+ bus_size_t sa_size;
+ int sa_intr;
+ int sa_index;
+ bus_dma_tag_t sa_dmat;
+};
+
+extern struct bus_space s3c2xx0_bs_tag;
+extern struct s3c2xx0_softc *s3c2xx0_softc;
+extern struct arm32_bus_dma_tag s3c2xx0_bus_dma;
+
+/* Platform needs to provide this */
+bus_dma_tag_t s3c2xx0_bus_dma_init(struct arm32_bus_dma_tag *);
+
+#endif /* _ARM_S3C2XX0VAR_H_ */
diff --git a/sys/arch/arm/s3c2xx0/sscom.c b/sys/arch/arm/s3c2xx0/sscom.c
new file mode 100644
index 00000000000..67d665f8fa4
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/sscom.c
@@ -0,0 +1,2196 @@
+/* $OpenBSD: sscom.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: sscom.c,v 1.29 2008/06/11 22:37:21 cegger Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Fujitsu Component Limited
+ * Copyright (c) 2002, 2003 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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) 1998, 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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 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.
+ */
+
+/*
+ * Copyright (c) 1991 The Regents of the University of California.
+ * 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. Neither the name of the University 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 REGENTS 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 REGENTS 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.
+ *
+ * @(#)com.c 7.5 (Berkeley) 5/16/91
+ */
+
+/*
+ * Support integrated UARTs of Samsung S3C2800/2400X/2410X
+ * Derived from sys/dev/ic/com.c
+ */
+
+#include <sys/cdefs.h>
+/*
+__KERNEL_RCSID(0, "$NetBSD: sscom.c,v 1.29 2008/06/11 22:37:21 cegger Exp $");
+
+#include "opt_sscom.h"
+#include "opt_ddb.h"
+#include "opt_kgdb.h"
+#include "opt_multiprocessor.h"
+#include "opt_lockdebug.h"
+
+#include "rnd.h"
+#if NRND > 0 && defined(RND_COM)
+#include <sys/rnd.h>
+#endif
+*/
+
+/*
+ * Override cnmagic(9) macro before including <sys/systm.h>.
+ * We need to know if cn_check_magic triggered debugger, so set a flag.
+ * Callers of cn_check_magic must declare int cn_trapped = 0;
+ * XXX: this is *ugly*!
+ */
+#define cn_trap() \
+ do { \
+ console_debugger(); \
+ cn_trapped = 1; \
+ } while (/* CONSTCOND */ 0)
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/selinfo.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <arm/s3c2xx0/s3c2xx0reg.h>
+#include <arm/s3c2xx0/s3c2xx0var.h>
+#if defined(SSCOM_S3C2410) || defined(SSCOM_S3C2400)
+#include <arm/s3c2xx0/s3c24x0reg.h>
+#elif defined(SSCOM_S3C2800)
+#include <arm/s3c2xx0/s3c2800reg.h>
+#endif
+#include <arm/s3c2xx0/sscom_var.h>
+#include <dev/cons.h>
+
+dev_type_open(sscomopen);
+dev_type_close(sscomclose);
+dev_type_read(sscomread);
+dev_type_write(sscomwrite);
+dev_type_ioctl(sscomioctl);
+dev_type_stop(sscomstop);
+dev_type_tty(sscomtty);
+dev_type_poll(sscompoll);
+
+int sscomcngetc (dev_t);
+void sscomcnputc (dev_t, int);
+void sscomcnpollc (dev_t, int);
+
+#define integrate static inline
+void sscomsoft (void *);
+
+void sscom_rxsoft (struct sscom_softc *, struct tty *);
+void sscom_txsoft (struct sscom_softc *, struct tty *);
+void sscom_stsoft (struct sscom_softc *, struct tty *);
+void sscom_schedrx (struct sscom_softc *);
+
+static void sscom_modem(struct sscom_softc *, int);
+static void sscom_break(struct sscom_softc *, int);
+static void sscom_iflush(struct sscom_softc *);
+static void sscom_hwiflow(struct sscom_softc *);
+static void sscom_loadchannelregs(struct sscom_softc *);
+static void tiocm_to_sscom(struct sscom_softc *, u_long, int);
+static int sscom_to_tiocm(struct sscom_softc *);
+static void tiocm_to_sscom(struct sscom_softc *, u_long, int);
+static int sscom_to_tiocm(struct sscom_softc *);
+static void sscom_iflush(struct sscom_softc *);
+
+static int sscomhwiflow(struct tty *tp, int block);
+#if 0
+static int sscom_init(bus_space_tag_t, const struct sscom_uart_info *,
+ int, int, tcflag_t, bus_space_handle_t *);
+#endif
+
+extern struct cfdriver sscom_cd;
+
+/*
+ * Make this an option variable one can patch.
+ * But be warned: this must be a power of 2!
+ */
+u_int sscom_rbuf_size = SSCOM_RING_SIZE;
+
+/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
+u_int sscom_rbuf_hiwat = (SSCOM_RING_SIZE * 1) / 4;
+u_int sscom_rbuf_lowat = (SSCOM_RING_SIZE * 3) / 4;
+
+static int sscomconsunit = -1;
+static bus_space_tag_t sscomconstag;
+static bus_space_handle_t sscomconsioh;
+static int sscomconsattached;
+static int sscomconsrate;
+static tcflag_t sscomconscflag;
+#if 0
+static struct cnm_state sscom_cnm_state;
+#endif
+
+#ifdef KGDB
+#include <sys/kgdb.h>
+
+static int sscom_kgdb_unit = -1;
+static bus_space_tag_t sscom_kgdb_iot;
+static bus_space_handle_t sscom_kgdb_ioh;
+static int sscom_kgdb_attached;
+
+int sscom_kgdb_getc (void *);
+void sscom_kgdb_putc (void *, int);
+#endif /* KGDB */
+
+#define SSCOMUNIT_MASK 0x7f
+#define SSCOMDIALOUT_MASK 0x80
+
+#define DEVUNIT(x) (minor(x) & SSCOMUNIT_MASK)
+#define SSCOMDIALOUT(x) (minor(x) & SSCOMDIALOUT_MASK)
+
+#if 0
+#define SSCOM_ISALIVE(sc) ((sc)->enabled != 0 && \
+ device_is_active(&(sc)->sc_dev))
+#else
+#define SSCOM_ISALIVE(sc) device_is_active(&(sc)->sc_dev)
+#endif
+
+#define BR BUS_SPACE_BARRIER_READ
+#define BW BUS_SPACE_BARRIER_WRITE
+#define SSCOM_BARRIER(t, h, f) /* no-op */
+
+#if (defined(MULTIPROCESSOR) || defined(LOCKDEBUG)) && defined(SSCOM_MPLOCK)
+
+#define SSCOM_LOCK(sc) simple_lock(&(sc)->sc_lock)
+#define SSCOM_UNLOCK(sc) simple_unlock(&(sc)->sc_lock)
+
+#else
+
+#define SSCOM_LOCK(sc)
+#define SSCOM_UNLOCK(sc)
+
+#endif
+
+#ifndef SSCOM_TOLERANCE
+#define SSCOM_TOLERANCE 30 /* XXX: baud rate tolerance, in 0.1% units */
+#endif
+
+/* value for UCON */
+#define UCON_RXINT_MASK \
+ (UCON_RXMODE_MASK|UCON_ERRINT|UCON_TOINT|UCON_RXINT_TYPE)
+#define UCON_RXINT_ENABLE \
+ (UCON_RXMODE_INT|UCON_ERRINT|UCON_TOINT|UCON_RXINT_TYPE_LEVEL)
+#define UCON_TXINT_MASK (UCON_TXMODE_MASK|UCON_TXINT_TYPE)
+#define UCON_TXINT_ENABLE (UCON_TXMODE_INT|UCON_TXINT_TYPE_LEVEL)
+
+/* we don't want tx interrupt on debug port, but it is needed to
+ have transmitter active */
+#define UCON_DEBUGPORT (UCON_RXINT_ENABLE|UCON_TXINT_ENABLE)
+
+
+static inline void
+__sscom_output_chunk(struct sscom_softc *sc, int ufstat)
+{
+ int n, space;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ n = sc->sc_tbc;
+ space = 16 - ((ufstat & UFSTAT_TXCOUNT) >> UFSTAT_TXCOUNT_SHIFT);
+
+ if (n > space)
+ n = space;
+
+ if (n > 0) {
+ bus_space_write_multi_1(iot, ioh, SSCOM_UTXH, sc->sc_tba, n);
+ sc->sc_tbc -= n;
+ sc->sc_tba += n;
+ }
+}
+
+static void
+sscom_output_chunk(struct sscom_softc *sc)
+{
+ int ufstat = bus_space_read_2(sc->sc_iot, sc->sc_ioh, SSCOM_UFSTAT);
+
+ if (!(ufstat & UFSTAT_TXFULL))
+ __sscom_output_chunk(sc, ufstat);
+}
+
+int
+sscomspeed(long speed, long frequency)
+{
+#define divrnd(n, q) (((n)*2/(q)+1)/2) /* divide and round off */
+
+ int x, err;
+
+ if (speed <= 0)
+ return -1;
+ x = divrnd(frequency / 16, speed);
+ if (x <= 0)
+ return -1;
+ err = divrnd(((quad_t)frequency) * 1000 / 16, speed * x) - 1000;
+ if (err < 0)
+ err = -err;
+ if (err > SSCOM_TOLERANCE)
+ return -1;
+ return x-1;
+
+#undef divrnd
+}
+
+void sscomstatus (struct sscom_softc *, const char *);
+
+#ifdef SSCOM_DEBUG
+int sscom_debug = 0;
+
+void
+sscomstatus(struct sscom_softc *sc, const char *str)
+{
+ struct tty *tp = sc->sc_tty;
+ int umstat = bus_space_read_1(sc->sc_iot, sc->sc_iot, SSCOM_UMSTAT);
+ int umcon = bus_space_read_1(sc->sc_iot, sc->sc_iot, SSCOM_UMCON);
+
+ printf("%s: %s %sclocal %sdcd %sts_carr_on %sdtr %stx_stopped\n",
+ sc->sc_dev.dv_xname, str,
+ ISSET(tp->t_cflag, CLOCAL) ? "+" : "-",
+ "+", /* DCD */
+ ISSET(tp->t_state, TS_CARR_ON) ? "+" : "-",
+ "+", /* DTR */
+ sc->sc_tx_stopped ? "+" : "-");
+
+ printf("%s: %s %scrtscts %scts %sts_ttstop %srts %xrx_flags\n",
+ sc->sc_dev.dv_xname, str,
+ ISSET(tp->t_cflag, CRTSCTS) ? "+" : "-",
+ ISSET(umstat, UMSTAT_CTS) ? "+" : "-",
+ ISSET(tp->t_state, TS_TTSTOP) ? "+" : "-",
+ ISSET(umcon, UMCON_RTS) ? "+" : "-",
+ sc->sc_rx_flags);
+}
+#else
+#define sscom_debug 0
+#endif
+
+static void
+sscom_enable_debugport(struct sscom_softc *sc)
+{
+ int s;
+
+ /* Turn on line break interrupt, set carrier. */
+ s = splserial();
+ SSCOM_LOCK(sc);
+ sc->sc_ucon = UCON_DEBUGPORT;
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON, sc->sc_ucon);
+ sc->sc_umcon = UMCON_RTS|UMCON_DTR;
+ sc->set_modem_control(sc);
+ sscom_enable_rxint(sc);
+ sscom_disable_txint(sc);
+ SSCOM_UNLOCK(sc);
+ splx(s);
+}
+
+static void
+sscom_set_modem_control(struct sscom_softc *sc)
+{
+ /* flob RTS */
+ bus_space_write_1(sc->sc_iot, sc->sc_ioh,
+ SSCOM_UMCON, sc->sc_umcon & UMCON_HW_MASK);
+ /* ignore DTR */
+}
+
+static int
+sscom_read_modem_status(struct sscom_softc *sc)
+{
+ int msts;
+
+ msts = bus_space_read_1(sc->sc_iot, sc->sc_ioh, SSCOM_UMSTAT);
+
+ /* DCD and DSR are always on */
+ return (msts & UMSTAT_CTS) | MSTS_DCD | MSTS_DSR;
+}
+
+void
+sscom_attach_subr(struct sscom_softc *sc)
+{
+ int unit = sc->sc_unit;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ struct tty *tp;
+
+ timeout_set(&sc->sc_diag_timeout, sscomdiag, sc);
+#if (defined(MULTIPROCESSOR) || defined(LOCKDEBUG)) && defined(SSCOM_MPLOCK)
+ simple_lock_init(&sc->sc_lock);
+#endif
+
+ sc->sc_ucon = UCON_RXINT_ENABLE|UCON_TXINT_ENABLE;
+
+ /*
+ * set default for modem control hook
+ */
+ if (sc->set_modem_control == NULL)
+ sc->set_modem_control = sscom_set_modem_control;
+ if (sc->read_modem_status == NULL)
+ sc->read_modem_status = sscom_read_modem_status;
+
+ /* Disable interrupts before configuring the device. */
+ sscom_disable_txrxint(sc);
+
+#ifdef KGDB
+ /*
+ * Allow kgdb to "take over" this port. If this is
+ * the kgdb device, it has exclusive use.
+ */
+ if (unit == sscom_kgdb_unit) {
+ SET(sc->sc_hwflags, SSCOM_HW_KGDB);
+ sc->sc_ucon = UCON_DEBUGPORT;
+ }
+#endif
+
+ if (unit == sscomconsunit) {
+ sscomconsattached = 1;
+
+ sscomconstag = iot;
+ sscomconsioh = ioh;
+
+ /* Make sure the console is always "hardwired". */
+ delay(1000); /* XXX: wait for output to finish */
+ SET(sc->sc_hwflags, SSCOM_HW_CONSOLE);
+ SET(sc->sc_swflags, TIOCFLAG_SOFTCAR);
+
+ sc->sc_ucon = UCON_DEBUGPORT;
+ }
+
+ bus_space_write_1(iot, ioh, SSCOM_UFCON,
+ UFCON_TXTRIGGER_8|UFCON_RXTRIGGER_8|UFCON_FIFO_ENABLE|
+ UFCON_TXFIFO_RESET|UFCON_RXFIFO_RESET);
+
+ bus_space_write_1(iot, ioh, SSCOM_UCON, sc->sc_ucon);
+
+#ifdef KGDB
+ if (ISSET(sc->sc_hwflags, SSCOM_HW_KGDB)) {
+ sscom_kgdb_attached = 1;
+ printf("%s: kgdb\n", sc->sc_dev.dv_xname);
+ sscom_enable_debugport(sc);
+ return;
+ }
+#endif
+
+
+
+ tp = ttymalloc();
+ tp->t_oproc = sscomstart;
+ tp->t_param = sscomparam;
+ tp->t_hwiflow = sscomhwiflow;
+
+ sc->sc_tty = tp;
+ sc->sc_rbuf = malloc(sscom_rbuf_size << 1, M_DEVBUF, M_NOWAIT);
+ sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
+ sc->sc_rbavail = sscom_rbuf_size;
+ if (sc->sc_rbuf == NULL) {
+ printf("%s: unable to allocate ring buffer\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ sc->sc_ebuf = sc->sc_rbuf + (sscom_rbuf_size << 1);
+
+#if 0 /* XXX */
+ tty_attach(tp);
+#endif
+
+ if (ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE)) {
+ int maj;
+
+ /* Locate the major number. */
+ for (maj = 0; maj < nchrdev; maj++)
+ if (cdevsw[maj].d_open == sscomopen)
+ break;
+
+
+ cn_tab->cn_dev = makedev(maj, sc->sc_dev.dv_unit);
+
+ printf("%s: console (major=%d)\n", sc->sc_dev.dv_xname, maj);
+ }
+
+
+#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+ sc->sc_si = softintr_establish(IPL_TTY, sscomsoft, sc);
+ if (sc->sc_si == NULL)
+ panic("%s: can't establish soft interrupt",
+ sc->sc_dev.dv_xname);
+#else
+ timeout_set(&sc->sc_comsoft_tmo, comsoft, sc);
+#endif
+
+
+#if NRND > 0 && defined(RND_COM)
+ rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
+ RND_TYPE_TTY, 0);
+#endif
+
+ /* if there are no enable/disable functions, assume the device
+ is always enabled */
+
+ if (ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE))
+ sscom_enable_debugport(sc);
+ else
+ sscom_disable_txrxint(sc);
+
+ SET(sc->sc_hwflags, SSCOM_HW_DEV_OK);
+}
+
+int
+sscom_detach(struct device *self, int flags)
+{
+ return 0;
+}
+
+int
+sscom_activate(struct device *self, enum devact act)
+{
+#ifdef notyet
+ struct sscom_softc *sc = (struct sscom_softc *)self;
+ int s, rv = 0;
+
+ s = splserial();
+ SSCOM_LOCK(sc);
+ switch (act) {
+ case DVACT_ACTIVATE:
+ rv = EOPNOTSUPP;
+ break;
+
+ case DVACT_DEACTIVATE:
+ if (sc->sc_hwflags & (SSCOM_HW_CONSOLE|SSCOM_HW_KGDB)) {
+ rv = EBUSY;
+ break;
+ }
+
+ sc->enabled = 0;
+ break;
+ }
+
+ SSCOM_UNLOCK(sc);
+ splx(s);
+ return rv;
+#else
+ return 0;
+#endif
+}
+
+void
+sscom_shutdown(struct sscom_softc *sc)
+{
+#ifdef notyet
+ struct tty *tp = sc->sc_tty;
+ int s;
+
+ s = splserial();
+ SSCOM_LOCK(sc);
+
+ /* If we were asserting flow control, then deassert it. */
+ SET(sc->sc_rx_flags, RX_IBUF_BLOCKED);
+ sscom_hwiflow(sc);
+
+ /* Clear any break condition set with TIOCSBRK. */
+ sscom_break(sc, 0);
+
+ /*
+ * Hang up if necessary. Wait a bit, so the other side has time to
+ * notice even if we immediately open the port again.
+ * Avoid tsleeping above splhigh().
+ */
+ if (ISSET(tp->t_cflag, HUPCL)) {
+ sscom_modem(sc, 0);
+ SSCOM_UNLOCK(sc);
+ splx(s);
+ /* XXX tsleep will only timeout */
+ (void) tsleep(sc, TTIPRI, ttclos, hz);
+ s = splserial();
+ SSCOM_LOCK(sc);
+ }
+
+ if (ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE))
+ /* interrupt on break */
+ sc->sc_ucon = UCON_DEBUGPORT;
+ else
+ sc->sc_ucon = 0;
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON, sc->sc_ucon);
+
+#ifdef DIAGNOSTIC
+ if (!sc->enabled)
+ panic("sscom_shutdown: not enabled?");
+#endif
+ sc->enabled = 0;
+ SSCOM_UNLOCK(sc);
+ splx(s);
+#endif
+}
+
+int
+sscomopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct sscom_softc *sc;
+ struct tty *tp;
+ int s, s2;
+ int error;
+ int unit = DEVUNIT(dev);
+
+ if (unit >= sscom_cd.cd_ndevs)
+ return ENXIO;
+ sc = sscom_cd.cd_devs[unit];
+
+ if (sc == NULL || !ISSET(sc->sc_hwflags, SSCOM_HW_DEV_OK) ||
+ sc->sc_rbuf == NULL)
+ return ENXIO;
+
+#if 0
+ if (!device_is_active(&sc->sc_dev))
+ return ENXIO;
+#endif
+
+#ifdef KGDB
+ /*
+ * If this is the kgdb port, no other use is permitted.
+ */
+ if (ISSET(sc->sc_hwflags, SSCOM_HW_KGDB))
+ return EBUSY;
+#endif
+
+ tp = sc->sc_tty;
+
+ s = spltty();
+
+ /*
+ * Do the following iff this is a first open.
+ */
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ tp->t_dev = dev;
+
+ s2 = splserial();
+ SSCOM_LOCK(sc);
+
+ /* Turn on interrupts. */
+ sscom_enable_txrxint(sc);
+
+ /* Fetch the current modem control status, needed later. */
+ sc->sc_msts = sc->read_modem_status(sc);
+
+#if 0
+ /* Clear PPS capture state on first open. */
+ sc->sc_ppsmask = 0;
+ sc->ppsparam.mode = 0;
+#endif
+
+ SSCOM_UNLOCK(sc);
+ splx(s2);
+
+ /*
+ * Initialize the termios status to the defaults. Add in the
+ * sticky bits from TIOCSFLAGS.
+ */
+ if (ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE)) {
+ tp->t_ispeed = tp->t_ospeed = sscomconsrate;
+ tp->t_cflag = sscomconscflag;
+ } else {
+ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
+ tp->t_cflag = TTYDEF_CFLAG;
+ }
+ if (ISSET(sc->sc_swflags, TIOCFLAG_CLOCAL))
+ SET(tp->t_cflag, CLOCAL);
+ if (ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS))
+ SET(tp->t_cflag, CRTSCTS);
+ if (ISSET(sc->sc_swflags, TIOCFLAG_MDMBUF))
+ SET(tp->t_cflag, MDMBUF);
+ /* Make sure sscomparam() will do something. */
+ tp->t_ospeed = 0;
+ (void) sscomparam(tp, &tp->t_termios);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+ tp->t_lflag = TTYDEF_LFLAG;
+ ttychars(tp);
+ ttsetwater(tp);
+
+ s2 = splserial();
+ SSCOM_LOCK(sc);
+
+ /*
+ * Turn on DTR. We must always do this, even if carrier is not
+ * present, because otherwise we'd have to use TIOCSDTR
+ * immediately after setting CLOCAL, which applications do not
+ * expect. We always assert DTR while the device is open
+ * unless explicitly requested to deassert it.
+ */
+ sscom_modem(sc, 1);
+
+ /* Clear the input ring, and unblock. */
+ sc->sc_rbput = sc->sc_rbget = sc->sc_rbuf;
+ sc->sc_rbavail = sscom_rbuf_size;
+ sscom_iflush(sc);
+ CLR(sc->sc_rx_flags, RX_ANY_BLOCK);
+ sscom_hwiflow(sc);
+
+ if (sscom_debug)
+ sscomstatus(sc, "sscomopen ");
+
+ SSCOM_UNLOCK(sc);
+ splx(s2);
+ }
+
+#if 0
+ splx(s);
+
+ error = ttyopen(tp, SSCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
+ if (error)
+ goto bad;
+#else
+ if (SSCOMDIALOUT(dev)) {
+ if (ISSET(tp->t_state, TS_ISOPEN)) {
+ /* Ah, but someone already is dialed in... */
+ splx(s);
+ return EBUSY;
+ }
+ sc->sc_cua = 1; /* We go into CUA mode. */
+ } else {
+ /* tty (not cua) device; wait for carrier if necessary. */
+ if (ISSET(flag, O_NONBLOCK)) {
+ if (sc->sc_cua) {
+ /* Opening TTY non-blocking... but the CUA is busy. */
+ splx(s);
+ return EBUSY;
+ }
+ } else {
+ while (sc->sc_cua ||
+ (!ISSET(tp->t_cflag, CLOCAL) &&
+ !ISSET(tp->t_state, TS_CARR_ON))) {
+ SET(tp->t_state, TS_WOPEN);
+ error = ttysleep(tp, &tp->t_rawq, TTIPRI | PCATCH, ttopen, 0);
+ /*
+ * If TS_WOPEN has been reset, that means the cua device
+ * has been closed. We don't want to fail in that case,
+ * so just go around again.
+ */
+ if (error && ISSET(tp->t_state, TS_WOPEN)) {
+ CLR(tp->t_state, TS_WOPEN);
+ splx(s);
+ return error;
+ }
+ }
+ }
+ }
+ splx(s);
+#endif
+
+ error = (*linesw[tp->t_line].l_open)(dev, tp);
+ if (error)
+ goto bad;
+
+ return 0;
+
+bad:
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ /*
+ * We failed to open the device, and nobody else had it opened.
+ * Clean up the state as appropriate.
+ */
+ sscom_shutdown(sc);
+ }
+
+ return error;
+}
+
+int
+sscomclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ struct sscom_softc *sc;
+ struct tty *tp;
+ int unit = DEVUNIT(dev);
+ if (unit >= sscom_cd.cd_ndevs)
+ return ENXIO;
+ sc = sscom_cd.cd_devs[unit];
+
+ tp = sc->sc_tty;
+
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flag);
+ ttyclose(tp);
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return 0;
+#endif
+
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ /*
+ * Although we got a last close, the device may still be in
+ * use; e.g. if this was the dialout node, and there are still
+ * processes waiting for carrier on the non-dialout node.
+ */
+ sscom_shutdown(sc);
+ }
+
+ return 0;
+}
+
+int
+sscomread(dev_t dev, struct uio *uio, int flag)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return EIO;
+#endif
+
+ return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
+}
+
+int
+sscomwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return EIO;
+#endif
+
+ return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
+}
+
+#if 0
+int
+sscompoll(dev_t dev, int events, struct proc *p)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return EIO;
+#endif
+
+ return ((*linesw[tp->t_line].l_poll)(tp, uio, flag));
+}
+#endif
+
+struct tty *
+sscomtty(dev_t dev)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+
+ return (tp);
+}
+
+int
+sscomioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(dev)];
+ struct tty *tp = sc->sc_tty;
+ int error;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return EIO;
+#endif
+
+ error = ((*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p));
+ if (error >= 0)
+ return error;
+
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return error;
+
+ error = 0;
+
+#if 0
+ SSCOM_LOCK(sc);
+#endif
+
+ switch (cmd) {
+ case TIOCSBRK:
+ sscom_break(sc, 1);
+ break;
+
+ case TIOCCBRK:
+ sscom_break(sc, 0);
+ break;
+
+ case TIOCSDTR:
+ sscom_modem(sc, 1);
+ break;
+
+ case TIOCCDTR:
+ sscom_modem(sc, 0);
+ break;
+
+ case TIOCGFLAGS:
+ *(int *)data = sc->sc_swflags;
+ break;
+
+ case TIOCSFLAGS:
+ error = suser(p, 0);
+ if (error)
+ break;
+ sc->sc_swflags = *(int *)data;
+ break;
+
+ case TIOCMSET:
+ case TIOCMBIS:
+ case TIOCMBIC:
+ tiocm_to_sscom(sc, cmd, *(int *)data);
+ break;
+
+ case TIOCMGET:
+ *(int *)data = sscom_to_tiocm(sc);
+ break;
+
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+#if 0
+ SSCOM_UNLOCK(sc);
+#endif
+
+ if (sscom_debug)
+ sscomstatus(sc, "sscomioctl ");
+
+ return error;
+}
+
+void
+sscom_schedrx(struct sscom_softc *sc)
+{
+
+ sc->sc_rx_ready = 1;
+
+ /* Wake up the poller. */
+#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+ softintr_schedule(sc->sc_si);
+#endif
+}
+
+static void
+sscom_break(struct sscom_softc *sc, int onoff)
+{
+
+ if (onoff)
+ SET(sc->sc_ucon, UCON_SBREAK);
+ else
+ CLR(sc->sc_ucon, UCON_SBREAK);
+
+ if (!sc->sc_heldchange) {
+ if (sc->sc_tx_busy) {
+ sc->sc_heldtbc = sc->sc_tbc;
+ sc->sc_tbc = 0;
+ sc->sc_heldchange = 1;
+ } else
+ sscom_loadchannelregs(sc);
+ }
+}
+
+static void
+sscom_modem(struct sscom_softc *sc, int onoff)
+{
+ if (onoff)
+ SET(sc->sc_umcon, UMCON_DTR);
+ else
+ CLR(sc->sc_umcon, UMCON_DTR);
+
+ if (!sc->sc_heldchange) {
+ if (sc->sc_tx_busy) {
+ sc->sc_heldtbc = sc->sc_tbc;
+ sc->sc_tbc = 0;
+ sc->sc_heldchange = 1;
+ } else
+ sscom_loadchannelregs(sc);
+ }
+}
+
+static void
+tiocm_to_sscom(struct sscom_softc *sc, u_long how, int ttybits)
+{
+ u_char sscombits;
+
+ sscombits = 0;
+ if (ISSET(ttybits, TIOCM_DTR))
+ sscombits = UMCON_DTR;
+ if (ISSET(ttybits, TIOCM_RTS))
+ SET(sscombits, UMCON_RTS);
+
+ switch (how) {
+ case TIOCMBIC:
+ CLR(sc->sc_umcon, sscombits);
+ break;
+
+ case TIOCMBIS:
+ SET(sc->sc_umcon, sscombits);
+ break;
+
+ case TIOCMSET:
+ CLR(sc->sc_umcon, UMCON_DTR);
+ SET(sc->sc_umcon, sscombits);
+ break;
+ }
+
+ if (!sc->sc_heldchange) {
+ if (sc->sc_tx_busy) {
+ sc->sc_heldtbc = sc->sc_tbc;
+ sc->sc_tbc = 0;
+ sc->sc_heldchange = 1;
+ } else
+ sscom_loadchannelregs(sc);
+ }
+}
+
+static int
+sscom_to_tiocm(struct sscom_softc *sc)
+{
+ u_char sscombits;
+ int ttybits = 0;
+
+ sscombits = sc->sc_umcon;
+#if 0
+ if (ISSET(sscombits, MCR_DTR))
+ SET(ttybits, TIOCM_DTR);
+#endif
+ if (ISSET(sscombits, UMCON_RTS))
+ SET(ttybits, TIOCM_RTS);
+
+ sscombits = sc->sc_msts;
+ if (ISSET(sscombits, MSTS_DCD))
+ SET(ttybits, TIOCM_CD);
+ if (ISSET(sscombits, MSTS_DSR))
+ SET(ttybits, TIOCM_DSR);
+ if (ISSET(sscombits, MSTS_CTS))
+ SET(ttybits, TIOCM_CTS);
+
+ if (sc->sc_ucon != 0)
+ SET(ttybits, TIOCM_LE);
+
+ return ttybits;
+}
+
+static int
+cflag2lcr(tcflag_t cflag)
+{
+ u_char lcr = ULCON_PARITY_NONE;
+
+ switch (cflag & (PARENB|PARODD)) {
+ case PARENB|PARODD:
+ lcr = ULCON_PARITY_ODD;
+ break;
+ case PARENB:
+ lcr = ULCON_PARITY_EVEN;
+ }
+
+ switch (ISSET(cflag, CSIZE)) {
+ case CS5:
+ SET(lcr, ULCON_LENGTH_5);
+ break;
+ case CS6:
+ SET(lcr, ULCON_LENGTH_6);
+ break;
+ case CS7:
+ SET(lcr, ULCON_LENGTH_7);
+ break;
+ case CS8:
+ SET(lcr, ULCON_LENGTH_8);
+ break;
+ }
+ if (ISSET(cflag, CSTOPB))
+ SET(lcr, ULCON_STOP);
+
+ return lcr;
+}
+
+int
+sscomparam(struct tty *tp, struct termios *t)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ int ospeed;
+ u_char lcr;
+ int s;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return EIO;
+#endif
+
+ ospeed = sscomspeed(t->c_ospeed, sc->sc_frequency);
+
+ /* Check requested parameters. */
+ if (ospeed < 0)
+ return EINVAL;
+ if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
+ return EINVAL;
+
+ /*
+ * For the console, always force CLOCAL and !HUPCL, so that the port
+ * is always active.
+ */
+ if (ISSET(sc->sc_swflags, TIOCFLAG_SOFTCAR) ||
+ ISSET(sc->sc_hwflags, SSCOM_HW_CONSOLE)) {
+ SET(t->c_cflag, CLOCAL);
+ CLR(t->c_cflag, HUPCL);
+ }
+
+ /*
+ * If there were no changes, don't do anything. This avoids dropping
+ * input and improves performance when all we did was frob things like
+ * VMIN and VTIME.
+ */
+ if (tp->t_ospeed == t->c_ospeed &&
+ tp->t_cflag == t->c_cflag)
+ return 0;
+
+ lcr = cflag2lcr(t->c_cflag);
+
+ s = splserial();
+ SSCOM_LOCK(sc);
+
+ sc->sc_ulcon = lcr;
+
+ /*
+ * If we're not in a mode that assumes a connection is present, then
+ * ignore carrier changes.
+ */
+ if (ISSET(t->c_cflag, CLOCAL | MDMBUF))
+ sc->sc_msr_dcd = 0;
+ else
+ sc->sc_msr_dcd = MSTS_DCD;
+
+ /*
+ * Set the flow control pins depending on the current flow control
+ * mode.
+ */
+ if (ISSET(t->c_cflag, CRTSCTS)) {
+ sc->sc_mcr_dtr = UMCON_DTR;
+ sc->sc_mcr_rts = UMCON_RTS;
+ sc->sc_msr_cts = MSTS_CTS;
+ }
+ else if (ISSET(t->c_cflag, MDMBUF)) {
+ /*
+ * For DTR/DCD flow control, make sure we don't toggle DTR for
+ * carrier detection.
+ */
+ sc->sc_mcr_dtr = 0;
+ sc->sc_mcr_rts = UMCON_DTR;
+ sc->sc_msr_cts = MSTS_DCD;
+ }
+ else {
+ /*
+ * If no flow control, then always set RTS. This will make
+ * the other side happy if it mistakenly thinks we're doing
+ * RTS/CTS flow control.
+ */
+ sc->sc_mcr_dtr = UMCON_DTR | UMCON_RTS;
+ sc->sc_mcr_rts = 0;
+ sc->sc_msr_cts = 0;
+ if (ISSET(sc->sc_umcon, UMCON_DTR))
+ SET(sc->sc_umcon, UMCON_RTS);
+ else
+ CLR(sc->sc_umcon, UMCON_RTS);
+ }
+ sc->sc_msr_mask = sc->sc_msr_cts | sc->sc_msr_dcd;
+
+ if (ospeed == 0)
+ CLR(sc->sc_umcon, sc->sc_mcr_dtr);
+ else
+ SET(sc->sc_umcon, sc->sc_mcr_dtr);
+
+ sc->sc_ubrdiv = ospeed;
+
+ /* And copy to tty. */
+ tp->t_ispeed = 0;
+ tp->t_ospeed = t->c_ospeed;
+ tp->t_cflag = t->c_cflag;
+
+ if (!sc->sc_heldchange) {
+ if (sc->sc_tx_busy) {
+ sc->sc_heldtbc = sc->sc_tbc;
+ sc->sc_tbc = 0;
+ sc->sc_heldchange = 1;
+ } else
+ sscom_loadchannelregs(sc);
+ }
+
+ if (!ISSET(t->c_cflag, CHWFLOW)) {
+ /* Disable the high water mark. */
+ sc->sc_r_hiwat = 0;
+ sc->sc_r_lowat = 0;
+ if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
+ CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
+ sscom_schedrx(sc);
+ }
+ if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
+ CLR(sc->sc_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
+ sscom_hwiflow(sc);
+ }
+ } else {
+ sc->sc_r_hiwat = sscom_rbuf_hiwat;
+ sc->sc_r_lowat = sscom_rbuf_lowat;
+ }
+
+ SSCOM_UNLOCK(sc);
+ splx(s);
+
+ /*
+ * Update the tty layer's idea of the carrier bit, in case we changed
+ * CLOCAL or MDMBUF. We don't hang up here; we only do that by
+ * explicit request.
+ */
+ (*linesw[tp->t_line].l_modem)(tp, ISSET(sc->sc_msts, MSTS_DCD));
+
+
+ if (sscom_debug)
+ sscomstatus(sc, "sscomparam ");
+
+ if (!ISSET(t->c_cflag, CHWFLOW)) {
+ if (sc->sc_tx_stopped) {
+ sc->sc_tx_stopped = 0;
+ sscomstart(tp);
+ }
+ }
+
+ return 0;
+}
+
+static void
+sscom_iflush(struct sscom_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int timo;
+
+
+ timo = 50000;
+ /* flush any pending I/O */
+ while ( sscom_rxrdy(iot, ioh) && --timo)
+ (void)sscom_getc(iot,ioh);
+#ifdef DIAGNOSTIC
+ if (!timo)
+ printf("%s: sscom_iflush timeout\n", sc->sc_dev.dv_xname);
+#endif
+}
+
+static void
+sscom_loadchannelregs(struct sscom_softc *sc)
+{
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ /* XXXXX necessary? */
+ sscom_iflush(sc);
+
+ bus_space_write_2(iot, ioh, SSCOM_UCON, 0);
+
+#if 0
+ if (ISSET(sc->sc_hwflags, COM_HW_FLOW)) {
+ bus_space_write_1(iot, ioh, com_lcr, LCR_EERS);
+ bus_space_write_1(iot, ioh, com_efr, sc->sc_efr);
+ }
+#endif
+
+ bus_space_write_2(iot, ioh, SSCOM_UBRDIV, sc->sc_ubrdiv);
+ bus_space_write_1(iot, ioh, SSCOM_ULCON, sc->sc_ulcon);
+ sc->set_modem_control(sc);
+ bus_space_write_2(iot, ioh, SSCOM_UCON, sc->sc_ucon);
+}
+
+static int
+sscomhwiflow(struct tty *tp, int block)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ int s;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return 0;
+#endif
+
+ if (sc->sc_mcr_rts == 0)
+ return 0;
+
+ s = splserial();
+ SSCOM_LOCK(sc);
+
+ if (block) {
+ if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
+ SET(sc->sc_rx_flags, RX_TTY_BLOCKED);
+ sscom_hwiflow(sc);
+ }
+ } else {
+ if (ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED)) {
+ CLR(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
+ sscom_schedrx(sc);
+ }
+ if (ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
+ CLR(sc->sc_rx_flags, RX_TTY_BLOCKED);
+ sscom_hwiflow(sc);
+ }
+ }
+
+ SSCOM_UNLOCK(sc);
+ splx(s);
+ return 1;
+}
+
+/*
+ * (un)block input via hw flowcontrol
+ */
+static void
+sscom_hwiflow(struct sscom_softc *sc)
+{
+ if (sc->sc_mcr_rts == 0)
+ return;
+
+ if (ISSET(sc->sc_rx_flags, RX_ANY_BLOCK)) {
+ CLR(sc->sc_umcon, sc->sc_mcr_rts);
+ CLR(sc->sc_mcr_active, sc->sc_mcr_rts);
+ } else {
+ SET(sc->sc_umcon, sc->sc_mcr_rts);
+ SET(sc->sc_mcr_active, sc->sc_mcr_rts);
+ }
+ sc->set_modem_control(sc);
+}
+
+
+void
+sscomstart(struct tty *tp)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ int s;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return;
+#endif
+
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
+ goto out;
+ if (sc->sc_tx_stopped)
+ goto out;
+#if 0
+ if (!ttypull(tp))
+ goto out;
+
+ /* Grab the first contiguous region of buffer space. */
+ {
+ u_char *tba;
+ int tbc;
+
+ tba = tp->t_outq.c_cf;
+ tbc = ndqb(&tp->t_outq, 0);
+
+ (void)splserial();
+ SSCOM_LOCK(sc);
+
+ sc->sc_tba = tba;
+ sc->sc_tbc = tbc;
+ }
+#else
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (ISSET(tp->t_state, TS_ASLEEP)) {
+ CLR(tp->t_state, TS_ASLEEP);
+ wakeup(&tp->t_outq);
+ }
+ if (tp->t_outq.c_cc == 0)
+ goto out;
+ selwakeup(&tp->t_wsel);
+ }
+ SET(tp->t_state, TS_BUSY);
+#endif
+
+ SET(tp->t_state, TS_BUSY);
+ sc->sc_tx_busy = 1;
+
+ /* Output the first chunk of the contiguous buffer. */
+ sscom_output_chunk(sc);
+
+ /* Enable transmit completion interrupts if necessary. */
+ if ((sc->sc_hwflags & SSCOM_HW_TXINT) == 0)
+ sscom_enable_txint(sc);
+
+ SSCOM_UNLOCK(sc);
+out:
+ splx(s);
+ return;
+}
+
+/*
+ * Stop output on a line.
+ */
+int
+sscomstop(struct tty *tp, int flag)
+{
+ struct sscom_softc *sc = sscom_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ int s;
+
+ s = splserial();
+ SSCOM_LOCK(sc);
+ if (ISSET(tp->t_state, TS_BUSY)) {
+ /* Stop transmitting at the next chunk. */
+ sc->sc_tbc = 0;
+ sc->sc_heldtbc = 0;
+ if (!ISSET(tp->t_state, TS_TTSTOP))
+ SET(tp->t_state, TS_FLUSH);
+ }
+ SSCOM_UNLOCK(sc);
+ splx(s);
+ return 0;
+}
+
+void
+sscomdiag(void *arg)
+{
+ struct sscom_softc *sc = arg;
+ int overflows, floods;
+ int s;
+
+ s = splserial();
+ SSCOM_LOCK(sc);
+ overflows = sc->sc_overflows;
+ sc->sc_overflows = 0;
+ floods = sc->sc_floods;
+ sc->sc_floods = 0;
+ sc->sc_errors = 0;
+ SSCOM_UNLOCK(sc);
+ splx(s);
+
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n",
+ sc->sc_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+void
+sscom_rxsoft(struct sscom_softc *sc, struct tty *tp)
+{
+ u_char *get, *end;
+ u_int cc, scc;
+ u_char rsr;
+ int code;
+ int s;
+
+ end = sc->sc_ebuf;
+ get = sc->sc_rbget;
+ scc = cc = sscom_rbuf_size - sc->sc_rbavail;
+
+ if (cc == sscom_rbuf_size) {
+ sc->sc_floods++;
+ if (sc->sc_errors++ == 0)
+ timeout_add(&sc->sc_diag_timeout, 60 * hz);
+ }
+
+ while (cc) {
+ code = get[0];
+ rsr = get[1];
+ if (rsr) {
+ if (ISSET(rsr, UERSTAT_OVERRUN)) {
+ sc->sc_overflows++;
+ if (sc->sc_errors++ == 0)
+ timeout_add(&sc->sc_diag_timeout,
+ 60 * hz);
+ }
+ if (ISSET(rsr, UERSTAT_BREAK | UERSTAT_FRAME))
+ SET(code, TTY_FE);
+ if (ISSET(rsr, UERSTAT_PARITY))
+ SET(code, TTY_PE);
+ }
+ (*linesw[tp->t_line].l_rint)(rsr << 8 | code, tp);
+
+#if 0
+ if ((*rint)(code, tp) == -1) {
+ /*
+ * The line discipline's buffer is out of space.
+ */
+ if (!ISSET(sc->sc_rx_flags, RX_TTY_BLOCKED)) {
+ /*
+ * We're either not using flow control, or the
+ * line discipline didn't tell us to block for
+ * some reason. Either way, we have no way to
+ * know when there's more space available, so
+ * just drop the rest of the data.
+ */
+ get += cc << 1;
+ if (get >= end)
+ get -= sscom_rbuf_size << 1;
+ cc = 0;
+ } else {
+ /*
+ * Don't schedule any more receive processing
+ * until the line discipline tells us there's
+ * space available (through sscomhwiflow()).
+ * Leave the rest of the data in the input
+ * buffer.
+ */
+ SET(sc->sc_rx_flags, RX_TTY_OVERFLOWED);
+ }
+ break;
+ }
+#endif
+ get += 2;
+ if (get >= end)
+ get = sc->sc_rbuf;
+ cc--;
+ }
+
+ if (cc != scc) {
+ sc->sc_rbget = get;
+ s = splserial();
+ SSCOM_LOCK(sc);
+
+ cc = sc->sc_rbavail += scc - cc;
+ /* Buffers should be ok again, release possible block. */
+ if (cc >= sc->sc_r_lowat) {
+ if (ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
+ CLR(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
+ sscom_enable_rxint(sc);
+ sc->sc_ucon |= UCON_ERRINT;
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, SSCOM_UCON,
+ sc->sc_ucon);
+
+ }
+ if (ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED)) {
+ CLR(sc->sc_rx_flags, RX_IBUF_BLOCKED);
+ sscom_hwiflow(sc);
+ }
+ }
+ SSCOM_UNLOCK(sc);
+ splx(s);
+ }
+}
+
+void
+sscom_txsoft(struct sscom_softc *sc, struct tty *tp)
+{
+
+ CLR(tp->t_state, TS_BUSY);
+ if (ISSET(tp->t_state, TS_FLUSH))
+ CLR(tp->t_state, TS_FLUSH);
+ else
+ ndflush(&tp->t_outq, (int)(sc->sc_tba - tp->t_outq.c_cf));
+ (*linesw[tp->t_line].l_start)(tp);
+
+}
+
+void
+sscom_stsoft(struct sscom_softc *sc, struct tty *tp)
+{
+ u_char msr, delta;
+ int s;
+
+ s = splserial();
+ SSCOM_LOCK(sc);
+ msr = sc->sc_msts;
+ delta = sc->sc_msr_delta;
+ sc->sc_msr_delta = 0;
+ SSCOM_UNLOCK(sc);
+ splx(s);
+
+ if (ISSET(delta, sc->sc_msr_dcd)) {
+ /*
+ * Inform the tty layer that carrier detect changed.
+ */
+ (*linesw[tp->t_line].l_modem)(tp, ISSET(msr, MSTS_DCD));
+
+ }
+
+ if (ISSET(delta, sc->sc_msr_cts)) {
+ /* Block or unblock output according to flow control. */
+ if (ISSET(msr, sc->sc_msr_cts)) {
+ sc->sc_tx_stopped = 0;
+ (*linesw[tp->t_line].l_start)(tp);
+ } else {
+ sc->sc_tx_stopped = 1;
+ }
+ }
+
+ if (sscom_debug)
+ sscomstatus(sc, "sscom_stsoft");
+}
+
+void
+sscomsoft(void *arg)
+{
+ struct sscom_softc *sc = arg;
+ struct tty *tp;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return;
+#endif
+
+ {
+ tp = sc->sc_tty;
+
+ if (sc->sc_rx_ready) {
+ sc->sc_rx_ready = 0;
+ sscom_rxsoft(sc, tp);
+ }
+
+ if (sc->sc_st_check) {
+ sc->sc_st_check = 0;
+ sscom_stsoft(sc, tp);
+ }
+
+ if (sc->sc_tx_done) {
+ sc->sc_tx_done = 0;
+ sscom_txsoft(sc, tp);
+ }
+ }
+#ifndef __HAVE_GENERIC_SOFT_INTERRUPTS
+ timeout_add(&sc->sc_comsoft_tmo, 1);
+#else
+ ;
+#endif
+
+}
+
+
+int
+sscomrxintr(void *arg)
+{
+ struct sscom_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ u_char *put, *end;
+ u_int cc;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return 0;
+#endif
+
+ SSCOM_LOCK(sc);
+
+ end = sc->sc_ebuf;
+ put = sc->sc_rbput;
+ cc = sc->sc_rbavail;
+
+ do {
+ u_char msts, delta;
+ u_char uerstat;
+ uint16_t ufstat;
+
+ ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
+
+ /* XXX: break interrupt with no character? */
+
+ if ( (ufstat & (UFSTAT_RXCOUNT|UFSTAT_RXFULL)) &&
+ !ISSET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED)) {
+
+ while (cc > 0) {
+ int cn_trapped = 0;
+
+ /* get status and received character.
+ read status register first */
+ uerstat = sscom_geterr(iot, ioh);
+ put[0] = sscom_getc(iot, ioh);
+
+ if (ISSET(uerstat, UERSTAT_BREAK)) {
+ int con_trapped = 0;
+#if 0
+ cn_check_magic(sc->sc_tty->t_dev,
+ CNC_BREAK, sscom_cnm_state);
+#endif
+ if (con_trapped)
+ continue;
+#if defined(KGDB)
+ if (ISSET(sc->sc_hwflags,
+ SSCOM_HW_KGDB)) {
+ kgdb_connect(1);
+ continue;
+ }
+#endif
+ }
+
+ put[1] = uerstat;
+#if 0
+ cn_check_magic(sc->sc_tty->t_dev,
+ put[0], sscom_cnm_state);
+#endif
+ if (!cn_trapped) {
+ put += 2;
+ if (put >= end)
+ put = sc->sc_rbuf;
+ cc--;
+ }
+
+ ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
+ if ( (ufstat & (UFSTAT_RXFULL|UFSTAT_RXCOUNT)) == 0 )
+ break;
+ }
+
+ /*
+ * Current string of incoming characters ended because
+ * no more data was available or we ran out of space.
+ * Schedule a receive event if any data was received.
+ * If we're out of space, turn off receive interrupts.
+ */
+ sc->sc_rbput = put;
+ sc->sc_rbavail = cc;
+ if (!ISSET(sc->sc_rx_flags, RX_TTY_OVERFLOWED))
+ sc->sc_rx_ready = 1;
+
+ /*
+ * See if we are in danger of overflowing a buffer. If
+ * so, use hardware flow control to ease the pressure.
+ */
+ if (!ISSET(sc->sc_rx_flags, RX_IBUF_BLOCKED) &&
+ cc < sc->sc_r_hiwat) {
+ SET(sc->sc_rx_flags, RX_IBUF_BLOCKED);
+ sscom_hwiflow(sc);
+ }
+
+ /*
+ * If we're out of space, disable receive interrupts
+ * until the queue has drained a bit.
+ */
+ if (!cc) {
+ SET(sc->sc_rx_flags, RX_IBUF_OVERFLOWED);
+ sscom_disable_rxint(sc);
+ sc->sc_ucon &= ~UCON_ERRINT;
+ bus_space_write_2(iot, ioh, SSCOM_UCON, sc->sc_ucon);
+ }
+ }
+
+
+ msts = sc->read_modem_status(sc);
+ delta = msts ^ sc->sc_msts;
+ sc->sc_msts = msts;
+
+#ifdef notyet
+ /*
+ * Pulse-per-second (PSS) signals on edge of DCD?
+ * Process these even if line discipline is ignoring DCD.
+ */
+ if (delta & sc->sc_ppsmask) {
+ struct timeval tv;
+ if ((msr & sc->sc_ppsmask) == sc->sc_ppsassert) {
+ /* XXX nanotime() */
+ microtime(&tv);
+ TIMEVAL_TO_TIMESPEC(&tv,
+ &sc->ppsinfo.assert_timestamp);
+ if (sc->ppsparam.mode & PPS_OFFSETASSERT) {
+ timespecadd(&sc->ppsinfo.assert_timestamp,
+ &sc->ppsparam.assert_offset,
+ &sc->ppsinfo.assert_timestamp);
+ }
+
+#ifdef PPS_SYNC
+ if (sc->ppsparam.mode & PPS_HARDPPSONASSERT)
+ hardpps(&tv, tv.tv_usec);
+#endif
+ sc->ppsinfo.assert_sequence++;
+ sc->ppsinfo.current_mode = sc->ppsparam.mode;
+
+ } else if ((msr & sc->sc_ppsmask) == sc->sc_ppsclear) {
+ /* XXX nanotime() */
+ microtime(&tv);
+ TIMEVAL_TO_TIMESPEC(&tv,
+ &sc->ppsinfo.clear_timestamp);
+ if (sc->ppsparam.mode & PPS_OFFSETCLEAR) {
+ timespecadd(&sc->ppsinfo.clear_timestamp,
+ &sc->ppsparam.clear_offset,
+ &sc->ppsinfo.clear_timestamp);
+ }
+
+#ifdef PPS_SYNC
+ if (sc->ppsparam.mode & PPS_HARDPPSONCLEAR)
+ hardpps(&tv, tv.tv_usec);
+#endif
+ sc->ppsinfo.clear_sequence++;
+ sc->ppsinfo.current_mode = sc->ppsparam.mode;
+ }
+ }
+#endif
+
+ /*
+ * Process normal status changes
+ */
+ if (ISSET(delta, sc->sc_msr_mask)) {
+ SET(sc->sc_msr_delta, delta);
+
+ /*
+ * Stop output immediately if we lose the output
+ * flow control signal or carrier detect.
+ */
+ if (ISSET(~msts, sc->sc_msr_mask)) {
+ sc->sc_tbc = 0;
+ sc->sc_heldtbc = 0;
+#ifdef SSCOM_DEBUG
+ if (sscom_debug)
+ sscomstatus(sc, "sscomintr ");
+#endif
+ }
+
+ sc->sc_st_check = 1;
+ }
+
+ /*
+ * Done handling any receive interrupts.
+ */
+
+ /*
+ * If we've delayed a parameter change, do it
+ * now, and restart * output.
+ */
+ if ((ufstat & UFSTAT_TXCOUNT) == 0) {
+ /* XXX: we should check transmitter empty also */
+
+ if (sc->sc_heldchange) {
+ sscom_loadchannelregs(sc);
+ sc->sc_heldchange = 0;
+ sc->sc_tbc = sc->sc_heldtbc;
+ sc->sc_heldtbc = 0;
+ }
+ }
+
+
+ } while (0);
+
+ SSCOM_UNLOCK(sc);
+
+ /* Wake up the poller. */
+#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS
+ softintr_schedule(sc->sc_si);
+#endif
+
+
+
+#if NRND > 0 && defined(RND_COM)
+ rnd_add_uint32(&sc->rnd_source, iir | rsr);
+#endif
+
+ return 1;
+}
+
+int
+sscomtxintr(void *arg)
+{
+ struct sscom_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ uint16_t ufstat;
+
+#if 0
+ if (SSCOM_ISALIVE(sc) == 0)
+ return 0;
+#endif
+
+ SSCOM_LOCK(sc);
+
+ ufstat = bus_space_read_2(iot, ioh, SSCOM_UFSTAT);
+
+ /*
+ * If we've delayed a parameter change, do it
+ * now, and restart * output.
+ */
+ if (sc->sc_heldchange && (ufstat & UFSTAT_TXCOUNT) == 0) {
+ /* XXX: we should check transmitter empty also */
+ sscom_loadchannelregs(sc);
+ sc->sc_heldchange = 0;
+ sc->sc_tbc = sc->sc_heldtbc;
+ sc->sc_heldtbc = 0;
+ }
+
+ /*
+ * See if data can be transmitted as well. Schedule tx
+ * done event if no data left and tty was marked busy.
+ */
+ if (!ISSET(ufstat,UFSTAT_TXFULL)) {
+ /*
+ * Output the next chunk of the contiguous
+ * buffer, if any.
+ */
+ if (sc->sc_tbc > 0) {
+ __sscom_output_chunk(sc, ufstat);
+ }
+ else {
+ /*
+ * Disable transmit sscompletion
+ * interrupts if necessary.
+ */
+ if (sc->sc_hwflags & SSCOM_HW_TXINT)
+ sscom_disable_txint(sc);
+ if (sc->sc_tx_busy) {
+ sc->sc_tx_busy = 0;
+ sc->sc_tx_done = 1;
+ }
+ }
+ }
+
+ SSCOM_UNLOCK(sc);
+
+ /* Wake up the poller. */
+ softintr_schedule(sc->sc_si);
+
+#if NRND > 0 && defined(RND_COM)
+ rnd_add_uint32(&sc->rnd_source, iir | rsr);
+#endif
+
+ return 1;
+}
+
+
+#if defined(KGDB) || defined(SSCOM0CONSOLE) || defined(SSCOM1CONSOLE)
+/*
+ * Initialize UART for use as console or KGDB line.
+ */
+static int
+sscom_init(bus_space_tag_t iot, const struct sscom_uart_info *config,
+ int rate, int frequency, tcflag_t cflag, bus_space_handle_t *iohp)
+{
+ bus_space_handle_t ioh;
+ bus_addr_t iobase = config->iobase;
+
+ if (bus_space_map(iot, iobase, SSCOM_SIZE, 0, &ioh))
+ return ENOMEM; /* ??? */
+
+ bus_space_write_2(iot, ioh, SSCOM_UCON, 0);
+ bus_space_write_1(iot, ioh, SSCOM_UFCON,
+ UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 |
+ UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET |
+ UFCON_FIFO_ENABLE );
+ /* tx/rx fifo reset are auto-cleared */
+
+ rate = sscomspeed(rate, frequency);
+ bus_space_write_2(iot, ioh, SSCOM_UBRDIV, rate);
+ bus_space_write_2(iot, ioh, SSCOM_ULCON, cflag2lcr(cflag));
+
+ /* enable UART */
+ bus_space_write_2(iot, ioh, SSCOM_UCON,
+ UCON_TXMODE_INT|UCON_RXMODE_INT);
+ bus_space_write_2(iot, ioh, SSCOM_UMCON, UMCON_RTS);
+
+ *iohp = ioh;
+ return 0;
+}
+
+#endif
+
+#if defined(SSCOM0CONSOLE) || defined(SSCOM1CONSOLE)
+/*
+ * Following are all routines needed for SSCOM to act as console
+ */
+struct consdev sscomcons = {
+ NULL, NULL, sscomcngetc, sscomcnputc, sscomcnpollc, NULL,
+ NODEV, CN_HIGHPRI
+};
+
+
+int
+sscom_cnattach(bus_space_tag_t iot, const struct sscom_uart_info *config,
+ int rate, int frequency, tcflag_t cflag)
+{
+ int res;
+
+ res = sscom_init(iot, config, rate, frequency, cflag, &sscomconsioh);
+ if (res)
+ return res;
+
+ cn_tab = &sscomcons;
+#if 0
+ cn_init_magic(&sscom_cnm_state);
+ cn_set_magic("\047\001"); /* default magic is BREAK */
+#endif
+
+ sscomconstag = iot;
+ sscomconsunit = config->unit;
+ sscomconsrate = rate;
+ sscomconscflag = cflag;
+
+ return 0;
+}
+
+void
+sscom_cndetach(void)
+{
+ bus_space_unmap(sscomconstag, sscomconsioh, SSCOM_SIZE);
+ sscomconstag = NULL;
+
+ cn_tab = NULL;
+}
+
+/*
+ * The read-ahead code is so that you can detect pending in-band
+ * cn_magic in polled mode while doing output rather than having to
+ * wait until the kernel decides it needs input.
+ */
+
+#define MAX_READAHEAD 20
+static int sscom_readahead[MAX_READAHEAD];
+static int sscom_readaheadcount = 0;
+
+int
+sscomcngetc(dev_t dev)
+{
+ int s = splserial();
+ u_char stat, c;
+
+ /* got a character from reading things earlier */
+ if (sscom_readaheadcount > 0) {
+ int i;
+
+ c = sscom_readahead[0];
+ for (i = 1; i < sscom_readaheadcount; i++) {
+ sscom_readahead[i-1] = sscom_readahead[i];
+ }
+ sscom_readaheadcount--;
+ splx(s);
+ return c;
+ }
+
+ /* block until a character becomes available */
+ while (!sscom_rxrdy(sscomconstag, sscomconsioh))
+ ;
+
+ c = sscom_getc(sscomconstag, sscomconsioh);
+ stat = sscom_geterr(sscomconstag, sscomconsioh);
+ {
+#ifdef DDB
+ extern int db_active;
+ if (!db_active)
+#endif
+#if 0
+ cn_check_magic(dev, c, sscom_cnm_state);
+#else
+ ;
+#endif
+ }
+ splx(s);
+ return c;
+}
+
+/*
+ * Console kernel output character routine.
+ */
+void
+sscomcnputc(dev_t dev, int c)
+{
+ int s = splserial();
+ int timo;
+
+ int cin, stat;
+ if (sscom_readaheadcount < MAX_READAHEAD &&
+ sscom_rxrdy(sscomconstag, sscomconsioh)) {
+
+ cin = sscom_getc(sscomconstag, sscomconsioh);
+ stat = sscom_geterr(sscomconstag, sscomconsioh);
+#if 0
+ cn_check_magic(dev, cin, sscom_cnm_state);
+#endif
+ sscom_readahead[sscom_readaheadcount++] = cin;
+ }
+
+ /* wait for any pending transmission to finish */
+ timo = 150000;
+ while (ISSET(bus_space_read_2(sscomconstag, sscomconsioh, SSCOM_UFSTAT),
+ UFSTAT_TXFULL) && --timo)
+ continue;
+
+ bus_space_write_1(sscomconstag, sscomconsioh, SSCOM_UTXH, c);
+ SSCOM_BARRIER(sscomconstag, sscomconsioh, BR | BW);
+
+#if 0
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (!ISSET(bus_space_read_1(sscomconstag, sscomconsioh, SSCOM_UTRSTAT),
+ UTRSTAT_TXEMPTY) && --timo)
+ continue;
+#endif
+ splx(s);
+}
+
+void
+sscomcnpollc(dev_t dev, int on)
+{
+
+}
+
+#endif /* SSCOM0CONSOLE||SSCOM1CONSOLE */
+
+#ifdef KGDB
+int
+sscom_kgdb_attach(bus_space_tag_t iot, const struct sscom_uart_info *config,
+ int rate, int frequency, tcflag_t cflag)
+{
+ int res;
+
+ if (iot == sscomconstag && config->unit == sscomconsunit) {
+ printf( "console==kgdb_port (%d): kgdb disabled\n", sscomconsunit);
+ return EBUSY; /* cannot share with console */
+ }
+
+ res = sscom_init(iot, config, rate, frequency, cflag, &sscom_kgdb_ioh);
+ if (res)
+ return res;
+
+ kgdb_attach(sscom_kgdb_getc, sscom_kgdb_putc, NULL);
+ kgdb_dev = 123; /* unneeded, only to satisfy some tests */
+
+ sscom_kgdb_iot = iot;
+ sscom_kgdb_unit = config->unit;
+
+ return 0;
+}
+
+/* ARGSUSED */
+int
+sscom_kgdb_getc(void *arg)
+{
+ int c, stat;
+
+ /* block until a character becomes available */
+ while (!sscom_rxrdy(sscom_kgdb_iot, sscom_kgdb_ioh))
+ ;
+
+ c = sscom_getc(sscom_kgdb_iot, sscom_kgdb_ioh);
+ stat = sscom_geterr(sscom_kgdb_iot, sscom_kgdb_ioh);
+
+ return c;
+}
+
+/* ARGSUSED */
+void
+sscom_kgdb_putc(void *arg, int c)
+{
+ int timo;
+
+ /* wait for any pending transmission to finish */
+ timo = 150000;
+ while (ISSET(bus_space_read_2(sscom_kgdb_iot, sscom_kgdb_ioh,
+ SSCOM_UFSTAT), UFSTAT_TXFULL) && --timo)
+ continue;
+
+ bus_space_write_1(sscom_kgdb_iot, sscom_kgdb_ioh, SSCOM_UTXH, c);
+ SSCOM_BARRIER(sscom_kgdb_iot, sscom_kgdb_ioh, BR | BW);
+
+#if 0
+ /* wait for this transmission to complete */
+ timo = 1500000;
+ while (!ISSET(bus_space_read_1(sscom_kgdb_iot, sscom_kgdb_ioh,
+ SSCOM_UTRSTAT), UTRSTAT_TXEMPTY) && --timo)
+ continue;
+#endif
+}
+#endif /* KGDB */
+
+/* helper function to identify the sscom ports used by
+ console or KGDB (and not yet autoconf attached) */
+int
+sscom_is_console(bus_space_tag_t iot, int unit,
+ bus_space_handle_t *ioh)
+{
+ bus_space_handle_t help;
+
+ if (!sscomconsattached &&
+ iot == sscomconstag && unit == sscomconsunit)
+ help = sscomconsioh;
+#ifdef KGDB
+ else if (!sscom_kgdb_attached &&
+ iot == sscom_kgdb_iot && unit == sscom_kgdb_unit)
+ help = sscom_kgdb_ioh;
+#endif
+ else
+ return 0;
+
+ if (ioh)
+ *ioh = help;
+ return 1;
+}
diff --git a/sys/arch/arm/s3c2xx0/sscom_s3c2410.c b/sys/arch/arm/s3c2xx0/sscom_s3c2410.c
new file mode 100644
index 00000000000..07c03b9b762
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/sscom_s3c2410.c
@@ -0,0 +1,177 @@
+/* $OpenBSD: sscom_s3c2410.c,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: sscom_s3c2410.c,v 1.2 2005/12/11 12:16:51 christos Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Fujitsu Component Limited
+ * Copyright (c) 2002, 2003 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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>
+/*
+__KERNEL_RCSID(0, "$NetBSD: sscom_s3c2410.c,v 1.2 2005/12/11 12:16:51 christos Exp $");
+
+#include "opt_sscom.h"
+#include "opt_ddb.h"
+#include "opt_kgdb.h"
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/tty.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/uio.h>
+#include <sys/kernel.h>
+#include <sys/syslog.h>
+#include <sys/types.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <arm/s3c2xx0/s3c2410reg.h>
+#include <arm/s3c2xx0/s3c2410var.h>
+#include <arm/s3c2xx0/sscom_var.h>
+#include <sys/termios.h>
+
+int sscom_match(struct device *, void *, void *);
+void sscom_attach(struct device *, struct device *, void *);
+
+int s3c2410_sscom_cnattach(bus_space_tag_t iot, int unit, int rate,
+ int frequency, tcflag_t cflag);
+
+#if 0
+CFATTACH_DECL(sscom, sizeof(struct sscom_softc), sscom_match,
+ sscom_attach, NULL, NULL);
+#endif
+
+struct cfdriver sscom_cd = {
+ NULL, "com", DV_TTY
+};
+struct cfattach sscom_ca = {
+ sizeof(struct sscom_softc), sscom_match, sscom_attach
+};
+
+const struct sscom_uart_info s3c2410_uart_config[] = {
+ /* UART 0 */
+ {
+ 0,
+ S3C2410_INT_TXD0,
+ S3C2410_INT_RXD0,
+ S3C2410_INT_ERR0,
+ S3C2410_UART_BASE(0),
+ },
+ /* UART 1 */
+ {
+ 1,
+ S3C2410_INT_TXD1,
+ S3C2410_INT_RXD1,
+ S3C2410_INT_ERR1,
+ S3C2410_UART_BASE(1),
+ },
+ /* UART 2 */
+ {
+ 2,
+ S3C2410_INT_TXD2,
+ S3C2410_INT_RXD2,
+ S3C2410_INT_ERR2,
+ S3C2410_UART_BASE(2),
+ },
+};
+
+int
+sscom_match(struct device *parent, void *c, void *aux)
+{
+ struct s3c2xx0_attach_args *sa = aux;
+ int unit = sa->sa_index;
+
+ return unit == 0 || unit == 1;
+}
+
+void
+sscom_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct sscom_softc *sc = (struct sscom_softc *)self;
+ struct s3c2xx0_attach_args *sa = aux;
+ int unit = sa->sa_index;
+ bus_addr_t iobase = s3c2410_uart_config[unit].iobase;
+
+ printf( ": UART%d addr=%lx", sa->sa_index, iobase );
+
+ sc->sc_iot = s3c2xx0_softc->sc_iot;
+ sc->sc_unit = unit;
+ sc->sc_frequency = s3c2xx0_softc->sc_pclk;
+
+ sc->sc_rx_irqno = s3c2410_uart_config[sa->sa_index].rx_int;
+ sc->sc_tx_irqno = s3c2410_uart_config[sa->sa_index].tx_int;
+
+ if (bus_space_map(sc->sc_iot, iobase, SSCOM_SIZE, 0, &sc->sc_ioh)) {
+ printf( ": failed to map registers\n" );
+ return;
+ }
+
+ printf("\n");
+
+ s3c24x0_intr_establish(s3c2410_uart_config[unit].tx_int,
+ IPL_SERIAL, IST_LEVEL, sscomtxintr, sc);
+ s3c24x0_intr_establish(s3c2410_uart_config[unit].rx_int,
+ IPL_SERIAL, IST_LEVEL, sscomrxintr, sc);
+ s3c24x0_intr_establish(s3c2410_uart_config[unit].err_int,
+ IPL_SERIAL, IST_LEVEL, sscomrxintr, sc);
+ sscom_disable_txrxint(sc);
+
+ sscom_attach_subr(sc);
+}
+
+
+
+int
+s3c2410_sscom_cnattach(bus_space_tag_t iot, int unit, int rate,
+ int frequency, tcflag_t cflag)
+{
+ return sscom_cnattach(iot, s3c2410_uart_config + unit,
+ rate, frequency, cflag);
+}
+
+#ifdef KGDB
+int
+s3c2410_sscom_kgdb_attach(bus_space_tag_t iot, int unit, int rate,
+ int frequency, tcflag_t cflag)
+{
+ return sscom_kgdb_attach(iot, s3c2410_uart_config + unit,
+ rate, frequency, cflag);
+}
+#endif /* KGDB */
diff --git a/sys/arch/arm/s3c2xx0/sscom_var.h b/sys/arch/arm/s3c2xx0/sscom_var.h
new file mode 100644
index 00000000000..4311fe602c4
--- /dev/null
+++ b/sys/arch/arm/s3c2xx0/sscom_var.h
@@ -0,0 +1,281 @@
+/* $OpenBSD: sscom_var.h,v 1.1 2008/11/26 14:39:14 drahn Exp $ */
+/* $NetBSD: sscom_var.h,v 1.7 2006/03/06 20:21:25 rjs Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Fujitsu Component Limited
+ * Copyright (c) 2002, 2003 Genetec Corporation
+ * 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. Neither the name of The Fujitsu Component Limited nor the name of
+ * Genetec corporation may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY FUJITSU COMPONENT LIMITED AND GENETEC
+ * CORPORATION ``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 FUJITSU COMPONENT LIMITED OR GENETEC
+ * CORPORATION 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.
+ */
+/* derived from sys/dev/ic/comvar.h */
+
+/*
+ * Copyright (c) 1996 Christopher G. Demetriou. 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Christopher G. Demetriou
+ * for the NetBSD Project.
+ * 4. 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.
+ */
+
+#ifndef _ARM_S3C2XX0_SSCOM_VAR_H
+#define _ARM_S3C2XX0_SSCOM_VAR_H
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/timeout.h>
+#include <machine/bus.h>
+
+#ifdef SSCOM_S3C2410
+#include <arm/s3c2xx0/s3c2410reg.h>
+#include <arm/s3c2xx0/s3c2410var.h>
+#endif
+
+/* Hardware flag masks */
+#define SSCOM_HW_FLOW 0x02
+#define SSCOM_HW_DEV_OK 0x04
+#define SSCOM_HW_CONSOLE 0x08
+#define SSCOM_HW_KGDB 0x10
+#define SSCOM_HW_TXINT 0x20
+#define SSCOM_HW_RXINT 0x40
+
+/* Buffer size for character buffer */
+#define SSCOM_RING_SIZE 2048
+
+struct sscom_softc {
+ struct device sc_dev;
+ void *sc_si;
+ struct tty *sc_tty;
+
+ struct timeout sc_diag_timeout;
+
+ int sc_unit; /* UART0/UART1 */
+ int sc_frequency;
+
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ u_int sc_overflows,
+ sc_floods,
+ sc_errors;
+
+ int sc_hwflags,
+ sc_swflags;
+
+ u_int sc_r_hiwat,
+ sc_r_lowat;
+ u_char *volatile sc_rbget,
+ *volatile sc_rbput;
+ volatile u_int sc_rbavail;
+ u_char *sc_rbuf,
+ *sc_ebuf;
+
+ u_char *sc_tba;
+ u_int sc_tbc,
+ sc_heldtbc;
+
+ volatile u_char sc_rx_flags,
+#define RX_TTY_BLOCKED 0x01
+#define RX_TTY_OVERFLOWED 0x02
+#define RX_IBUF_BLOCKED 0x04
+#define RX_IBUF_OVERFLOWED 0x08
+#define RX_ANY_BLOCK 0x0f
+ sc_tx_busy,
+ sc_tx_done,
+ sc_tx_stopped,
+ sc_st_check,
+ sc_rx_ready;
+
+ /* data to stored in UART registers.
+ actual write to UART register is pended while sc_tx_busy */
+ uint16_t sc_ucon; /* control register */
+ uint16_t sc_ubrdiv; /* baudrate register */
+ uint8_t sc_heldchange; /* register changes are pended */
+ uint8_t sc_ulcon; /* line control */
+ uint8_t sc_umcon; /* modem control */
+#define UMCON_HW_MASK (UMCON_RTS)
+#define UMCON_DTR (1<<4) /* provided by other means such as GPIO */
+ uint8_t sc_msts; /* modem status */
+#define MSTS_CTS UMSTAT_CTS /* bit0 */
+#define MSTS_DCD (1<<1)
+#define MSTS_DSR (1<<2)
+
+ uint8_t sc_msr_dcd; /* DCD or 0 */
+ uint8_t sc_mcr_dtr; /* DTR or 0 or DTR|RTS*/
+ uint8_t sc_mcr_rts; /* RTS or DTR in sc_umcon */
+ uint8_t sc_msr_cts; /* CTS or DCD in sc_msts */
+
+ uint8_t sc_msr_mask; /* sc_msr_cts|sc_msr_dcd */
+ uint8_t sc_mcr_active;
+ uint8_t sc_msr_delta;
+
+ uint8_t sc_rx_irqno, sc_tx_irqno;
+
+#if 0
+ /* PPS signal on DCD, with or without inkernel clock disciplining */
+ u_char sc_ppsmask; /* pps signal mask */
+ u_char sc_ppsassert; /* pps leading edge */
+ u_char sc_ppsclear; /* pps trailing edge */
+ pps_info_t ppsinfo;
+ pps_params_t ppsparam;
+#endif
+
+#if NRND > 0 && defined(RND_COM)
+ rndsource_element_t rnd_source;
+#endif
+#if (defined(MULTIPROCESSOR) || defined(LOCKDEBUG)) && defined(SSCOM_MPLOCK)
+ struct simplelock sc_lock;
+#endif
+
+ /*
+ * S3C2XX0's UART doesn't have modem control/status pins.
+ * On platforms with S3C2XX0, those pins are simply unavailable
+ * or provided by other means such as GPIO. Platform specific attach routine
+ * have to provide functions to read/write modem control/status pins.
+ */
+ int (* read_modem_status)( struct sscom_softc * );
+ void (* set_modem_control)( struct sscom_softc * );
+ int sc_cua;
+};
+
+/* UART register address, etc. */
+struct sscom_uart_info {
+ int unit;
+ char tx_int, rx_int, err_int;
+ bus_addr_t iobase;
+};
+
+#define sscom_rxrdy(iot,ioh) \
+ (bus_space_read_1((iot), (ioh), SSCOM_UTRSTAT) & UTRSTAT_RXREADY)
+#define sscom_getc(iot,ioh) bus_space_read_1((iot), (ioh), SSCOM_URXH)
+#define sscom_geterr(iot,ioh) bus_space_read_1((iot), (ioh), SSCOM_UERSTAT)
+
+/*
+ * we need to tweak interrupt controller to mask/unmask rxint and/or txint.
+ */
+#ifdef SSCOM_S3C2410
+/* RXINTn, TXINTn and ERRn interrupts are cascaded to UARTn irq. */
+
+#define _sscom_intbit(irqno) (1<<((irqno)-S3C2410_SUBIRQ_MIN))
+
+#define sscom_unmask_rxint(sc) \
+ s3c2410_unmask_subinterrupts(_sscom_intbit((sc)->sc_rx_irqno))
+#define sscom_mask_rxint(sc) \
+ s3c2410_mask_subinterrupts(_sscom_intbit((sc)->sc_rx_irqno))
+#define sscom_unmask_txint(sc) \
+ s3c2410_unmask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno))
+#define sscom_mask_txint(sc) \
+ s3c2410_mask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno))
+#define sscom_unmask_txrxint(sc) \
+ s3c2410_unmask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno) | \
+ _sscom_intbit((sc)->sc_rx_irqno))
+#define sscom_mask_txrxint(sc) \
+ s3c2410_mask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno) | \
+ _sscom_intbit((sc)->sc_rx_irqno))
+
+int sscom_cnattach(bus_space_tag_t, const struct sscom_uart_info *,
+ int, int, tcflag_t);
+int s3c2410_sscom_cnattach(bus_space_tag_t iot, int unit, int rate,
+ int frequency, tcflag_t cflag);
+#else
+
+/* for S3C2800 and S3C2400 */
+#define sscom_unmask_rxint(sc) s3c2xx0_unmask_interrupts(1<<(sc)->sc_rx_irqno)
+#define sscom_mask_rxint(sc) s3c2xx0_mask_interrupts(1<<(sc)->sc_rx_irqno)
+#define sscom_unmask_txint(sc) s3c2xx0_unmask_interrupts(1<<(sc)->sc_tx_irqno)
+#define sscom_mask_txint(sc) s3c2xx0_mask_interrupts(1<<(sc)->sc_tx_irqno)
+#define sscom_unmask_txrxint(sc) \
+ s3c2xx0_unmask_interrupts((1<<(sc)->sc_tx_irqno)|(1<<(sc)->sc_rx_irqno))
+#define sscom_mask_txrxint(sc) \
+ s3c2xx0_mask_interrupts((1<<(sc)->sc_tx_irqno)|(1<<(sc)->sc_rx_irqno))
+
+#endif /* SSCOM_S3C2410 */
+
+#define sscom_enable_rxint(sc) \
+ (sscom_unmask_rxint(sc), ((sc)->sc_hwflags |= SSCOM_HW_RXINT))
+#define sscom_disable_rxint(sc) \
+ (sscom_mask_rxint(sc), ((sc)->sc_hwflags &= ~SSCOM_HW_RXINT))
+#define sscom_enable_txint(sc) \
+ (sscom_unmask_txint(sc), ((sc)->sc_hwflags |= SSCOM_HW_TXINT))
+#define sscom_disable_txint(sc) \
+ (sscom_mask_txint(sc),((sc)->sc_hwflags &= ~SSCOM_HW_TXINT))
+#define sscom_enable_txrxint(sc) \
+ (sscom_unmask_txrxint(sc),((sc)->sc_hwflags |= (SSCOM_HW_TXINT|SSCOM_HW_RXINT)))
+#define sscom_disable_txrxint(sc) \
+ (sscom_mask_txrxint(sc),((sc)->sc_hwflags &= ~(SSCOM_HW_TXINT|SSCOM_HW_RXINT)))
+
+
+int sscomspeed(long, long);
+void sscom_attach_subr(struct sscom_softc *);
+
+int sscom_detach(struct device *, int);
+int sscom_activate(struct device *, enum devact);
+void sscom_shutdown(struct sscom_softc *);
+void sscomdiag (void *);
+void sscomstart(struct tty *);
+int sscomparam(struct tty *, struct termios *);
+int sscomread(dev_t, struct uio *, int);
+void sscom_config(struct sscom_softc *);
+
+int sscomtxintr(void *);
+int sscomrxintr(void *);
+
+int sscom_cnattach(bus_space_tag_t, const struct sscom_uart_info *,
+ int, int, tcflag_t);
+void sscom_cndetach(void);
+int sscom_is_console(bus_space_tag_t, int, bus_space_handle_t *);
+
+
+#ifdef KGDB
+int sscom_kgdb_attach(bus_space_tag_t, const struct sscom_uart_info *,
+ int, int, tcflag_t);
+#endif
+
+#endif /* _ARM_S3C2XX0_SSCOM_VAR_H */