diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2008-11-26 14:39:15 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2008-11-26 14:39:15 +0000 |
commit | c6d65e6e11637f113bb9637929b7a7ba1382553e (patch) | |
tree | e36388ee6fd0f8a0a087b2a91e036a00a9d78f80 /sys/arch | |
parent | 84c57e61bdc36075d5bb64f1f8ba3f0c35829934 (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.c | 275 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2410_intr.c | 374 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2410_intr.h | 40 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2410reg.h | 230 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2410var.h | 46 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c24x0_clk.c | 337 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c24x0_intr.h | 57 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c24x0var.h | 48 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2xx0_busdma.c | 73 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2xx0_intr.c | 363 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2xx0_intr.h | 266 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2xx0_mutex.c | 67 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2xx0_space.c | 268 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2xx0reg.h | 137 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/s3c2xx0var.h | 79 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/sscom.c | 2196 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/sscom_s3c2410.c | 177 | ||||
-rw-r--r-- | sys/arch/arm/s3c2xx0/sscom_var.h | 281 |
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 */ |