? arch/evbarm/conf/MINI2440_INSTALL Index: arch/arm/arm/cpufunc_asm.S =================================================================== RCS file: /cvsroot/src/sys/arch/arm/arm/cpufunc_asm.S,v retrieving revision 1.14 diff -u -r1.14 cpufunc_asm.S --- arch/arm/arm/cpufunc_asm.S 27 Apr 2008 18:58:43 -0000 1.14 +++ arch/arm/arm/cpufunc_asm.S 28 Dec 2009 10:35:33 -0000 @@ -148,3 +148,26 @@ ldr r0, [sp] sub r0, r0, r1 ldmdb fp, {fp, sp, pc} + +ENTRY_NP(__set_cpsr_c) + mov ip, sp + stmdb sp!, {fp, ip, lr, pc} + sub fp, ip, #4 + sub sp, sp, #16 + str r0, [fp, #-24] + str r1, [fp, #-28] + ldr r2, [fp, #-24] + ldr r3, [fp, #-28] + mrs r0, CPSR + bic r1, r0, r2 + eor r1, r1, r3 + msr CPSR_c, r1 + mov r2, r1 + mov r3, r0 + str r3, [fp, #-16] + str r2, [fp, #-20] + ldr r3, [fp, #-16] + mov r0, r3 + sub sp, fp, #12 + ldmia sp, {fp, sp, pc} + Index: arch/arm/include/cpufunc.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/include/cpufunc.h,v retrieving revision 1.49 diff -u -r1.49 cpufunc.h --- arch/arm/include/cpufunc.h 21 Oct 2008 19:01:54 -0000 1.49 +++ arch/arm/include/cpufunc.h 28 Dec 2009 10:35:33 -0000 @@ -532,10 +532,12 @@ * Macros for manipulating CPU interrupts */ #ifdef __PROG32 -static __inline u_int32_t __set_cpsr_c(uint32_t bic, uint32_t eor) __attribute__((__unused__)); +/*static __inline u_int32_t __set_cpsr_c(uint32_t bic, uint32_t eor) __attribute__((__unused__));*/ +u_int32_t __set_cpsr_c(uint32_t bic, uint32_t eor); static __inline u_int32_t disable_interrupts(uint32_t mask) __attribute__((__unused__)); static __inline u_int32_t enable_interrupts(uint32_t mask) __attribute__((__unused__)); +#if 0 static __inline uint32_t __set_cpsr_c(uint32_t bic, uint32_t eor) { @@ -551,6 +553,7 @@ return ret; } +#endif static __inline uint32_t disable_interrupts(uint32_t mask) Index: arch/arm/s3c2xx0/files.s3c2440 =================================================================== RCS file: arch/arm/s3c2xx0/files.s3c2440 diff -N arch/arm/s3c2xx0/files.s3c2440 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/files.s3c2440 28 Dec 2009 10:35:33 -0000 @@ -0,0 +1,43 @@ +# $NetBSD: $ +# +# Configuration info for Samsung S3C2440 +# + +# Pull in common info for s3c2800/2400X/2410X +include arch/arm/s3c2xx0/files.s3c2xx0 + + +file arch/arm/s3c2xx0/s3c2440_intr.c +file arch/arm/s3c2xx0/s3c24x0_clk.c +file arch/arm/s3c2xx0/s3c2440.c +file arch/arm/s3c2xx0/s3c2440_dma.c # DMA controller + +device ssextio { [index=-1], [addr=0], [size=0], [intr=-1] } : bus_space_generic +attach ssextio at ssio +# maximum external interrupt. defaults to 23 to allow all external +# interrupts. valid values are 4..23. +defparam opt_s3c2440.h S3C2440_MAX_EXTINT +file arch/arm/s3c2xx0/s3c2440_extint.c ssextio + +# UART +file arch/arm/s3c2xx0/sscom_s3c2440.c sscom + +# OHCI USB controller +attach ohci at ssio with ohci_ssio +file arch/arm/s3c2xx0/ohci_s3c24x0.c ohci_ssio + +# LCD controller +#device lcd: wsemuldisplaydev, rasops16, rasops8 +#file arch/arm/s3c2xx0/s3c24x0_lcd.c lcd needs-flag + +# SPI port +# intr locator is for an additional interrupt other than SPI[01] interrupts. +device ssspi {[intr=-1]} +attach ssspi at ssio +file arch/arm/s3c2xx0/s3c2440_spi.c ssspi + +# SDI controller +device sssdi: sdmmcbus +attach sssdi at ssio +file arch/arm/s3c2xx0/s3c2440_sdi.c sssdi + Index: arch/arm/s3c2xx0/s3c2440.c =================================================================== RCS file: arch/arm/s3c2xx0/s3c2440.c diff -N arch/arm/s3c2xx0/s3c2440.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/s3c2440.c 28 Dec 2009 10:35:34 -0000 @@ -0,0 +1,291 @@ +/* $NetBSD: */ + +/* + * 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 +__KERNEL_RCSID(0, "$NetBSD:$"); + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "locators.h" +#include "opt_cpuoptions.h" + +/* prototypes */ +static int s3c2440_match(struct device *, struct cfdata *, void *); +static void s3c2440_attach(struct device *, struct device *, void *); +static int s3c2440_search(struct device *, struct cfdata *, + const int *, void *); + +/* attach structures */ +CFATTACH_DECL(ssio, sizeof(struct s3c24x0_softc), s3c2440_match, s3c2440_attach, + NULL, NULL); + +extern struct bus_space s3c2xx0_bs_tag; + +struct s3c2xx0_softc *s3c2xx0_softc; + +#ifdef DEBUG_PORTF +volatile uint8_t *portf; /* for debug */ +#endif + +static int +s3c2440_print(void *aux, const char *name) +{ + struct s3c2xx0_attach_args *sa = (struct s3c2xx0_attach_args *) aux; + + if (sa->sa_size) + aprint_normal(" addr 0x%lx", sa->sa_addr); + if (sa->sa_size > 1) + aprint_normal("-0x%lx", sa->sa_addr + sa->sa_size - 1); + if (sa->sa_intr != SSIOCF_INTR_DEFAULT) + aprint_normal(" intr %d", sa->sa_intr); + if (sa->sa_index != SSIOCF_INDEX_DEFAULT) + aprint_normal(" unit %d", sa->sa_index); + + return (UNCONF); +} + +int +s3c2440_match(struct device *parent, struct cfdata *match, void *aux) +{ + return 1; +} + +void +s3c2440_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, + S3C2440_INTCTL_BASE, S3C2440_INTCTL_SIZE, + BUS_SPACE_MAP_LINEAR, &sc->sc_sx.sc_intctl_ioh)) + FAIL("intc"); + /* tell register addresses to interrupt handler */ + s3c2440_intr_init(sc); + + /* Map the GPIO registers */ + if (bus_space_map(iot, S3C2440_GPIO_BASE, S3C2440_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 1 + /* Map the DMA controller registers */ + if (bus_space_map(iot, S3C2440_DMAC_BASE, S3C2440_DMAC_SIZE, + 0, &sc->sc_sx.sc_dmach)) + FAIL("DMAC"); +#endif + + /* Memory controller */ + if (bus_space_map(iot, S3C2440_MEMCTL_BASE, + S3C24X0_MEMCTL_SIZE, 0, &sc->sc_sx.sc_memctl_ioh)) + FAIL("MEMC"); + /* Clock manager */ + if (bus_space_map(iot, S3C2440_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, S3C2440_TIMER_BASE, + S3C24X0_TIMER_SIZE, 0, &sc->sc_timer_ioh)) + FAIL("TIMER"); + + /* calculate current clock frequency */ + s3c24x0_clock_freq(&sc->sc_sx); + aprint_normal(": 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); + + aprint_naive("\n"); + + /* get busdma tag for the platform */ + sc->sc_sx.sc_dmat = s3c2xx0_bus_dma_init(&s3c2xx0_bus_dma); + + s3c2440_dma_init(); + + /* + * Attach devices. + */ + config_search_ia(s3c2440_search, self, "ssio", NULL); + return; + +abort: + panic("%s: unable to map %s registers", + self->dv_xname, which_registers); + +#undef FAIL +} + +int +s3c2440_search(struct device * parent, struct cfdata * cf, + const int *ldesc, void *aux) +{ + struct s3c24x0_softc *sc = (struct s3c24x0_softc *) parent; + struct s3c2xx0_attach_args aa; + + aa.sa_sc = sc; + aa.sa_iot = sc->sc_sx.sc_iot; + 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]; + + aa.sa_dmat = sc->sc_sx.sc_dmat; + + if (config_match(parent, cf, &aa)) + config_attach(parent, cf, &aa, s3c2440_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, camdivn; + int mdiv, pdiv, sdiv; + uint32_t f, h, p; + + pllcon = *(volatile uint32_t *)(clkman_base + CLKMAN_MPLLCON); + divn = *(volatile uint32_t *)(clkman_base + CLKMAN_CLKDIVN); + camdivn = *(volatile uint32_t *)(clkman_base + CLKMAN_CAMDIVN); + + 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)) * 2; + h = f; + + /* HDIVN of CLKDIVN can have 4 distinct values */ + switch( (divn & CLKDIVN_HDIVN_MASK) >> CLKDIVN_HDIVN_SHIFT ) + { + case 0: + /* 00b: HCLK = FCLK/1*/ + break; + case 1: + /* 01b: HCLK = FCLK/2*/ + h /= 2; + break; + case 2: + /* 10b: HCLK = FCLK/4 when CAMDIVN[9] (HCLK4_HALF) = 0 + * HCLK = FCLK/8 when CAMDIVN[9] (HCLK4_HALF) = 1 */ + if( camdivn & CLKCAMDIVN_HCLK4_HALF ) + h /= 8; + else + h /= 4; + break; + case 3: + /* 11b: HCLK = FCLK/3 when CAMDIVN[8] (HCLK3_HALF) = 0 + * HCLK = FCLK/6 when CAMDIVN[8] (HCLK3_HALF) = 1 */ + if( camdivn & CLKCAMDIVN_HCLK3_HALF ) + h /= 6; + else + h /= 3; + break; + } + + 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 +s3c2440_softreset(void) +{ + disable_interrupts(I32_bit|F32_bit); + + *(volatile unsigned int *)(S3C2440_WDT_BASE + WDT_WTCON) + = (0 << WTCON_PRESCALE_SHIFT) | WTCON_ENABLE | + WTCON_CLKSEL_16 | WTCON_ENRST; +} + + Index: arch/arm/s3c2xx0/s3c2440_dma.c =================================================================== RCS file: arch/arm/s3c2xx0/s3c2440_dma.c diff -N arch/arm/s3c2xx0/s3c2440_dma.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/s3c2440_dma.c 28 Dec 2009 10:35:34 -0000 @@ -0,0 +1,326 @@ +/* $NetBSD:$ */ + +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#ifdef S3C2440_DMA_DEBUG +#define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) +#else +#define DPRINTF(s) do {} while (/*CONSTCOND*/0) +#endif + + +struct kmutex dma_intr_mutex; +struct kcondvar dma_intr_cv; +uint32_t dma_intr_status; + +s3c2440_dma_xfer_t dma_channel_xfer[4]; + +void +s3c2440_dma_init(void) +{ + mutex_init(&dma_intr_mutex, MUTEX_DEFAULT, IPL_BIO); + cv_init(&dma_intr_cv, "s3c2440_dmaintr"); + dma_intr_status = 0; + + for(int i=0; i<4; i++) { + dma_channel_xfer[i] = NULL; + } + + /* Setup interrupt handler for DMA controller */ + s3c24x0_intr_establish(S3C24X0_INT_DMA0, IPL_BIO, IST_EDGE_RISING, s3c2440_dma_intr, NULL); +} + +int +s3c2440_dma_intr(void *arg) +{ + struct s3c2xx0_softc *sc = s3c2xx0_softc; + uint32_t status; + int i; + int someone_completed = FALSE; + + DPRINTF(("s3c2440_dma_intr\n")); + DPRINTF(("dma_intr_status: %x\n", dma_intr_status)); + + for(i=0;i<4;i++) { + status = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_STAT(i)); + DPRINTF(("Channel %d status: %d\n", i, status)); + + if ( !(status & DMASTAT_BUSY) ) { + uint32_t st = dma_intr_status; + dma_intr_status &= ~(1<dx_remaining > 0 && + xfer->dx_aborted == FALSE) { + + DPRINTF(("Preparing next transfer\n")); + + s3c2440_dma_xfer_start(xfer); + } else { + xfer->dx_complete = TRUE; + someone_completed = TRUE; + } + } + } + +#ifdef S3C2440_DMA_DEBUG + status = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_CSRC(i)); + printf("Current source for channel %d: 0x%x\n", i, status); + + status = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_CDST(i)); + printf("Current dest for channel %d: 0x%x\n", i, status); +#endif + } +#ifdef S3C2440_DMA_DEBUG + printf("dma_intr_status after: %x\n", dma_intr_status); +#endif + + if (someone_completed) + cv_broadcast(&dma_intr_cv); + + return 1; +} + +#if 0 +/* Wait for interrupt from DMA controller regarding a specific channel */ +int +s3c2440_dma_wait_intr(int channel) +{ + uint32_t status; + mutex_enter(&dma_intr_mutex); + status = dma_intr_status & (1<dx_mem = dmap; + xfer->dx_next_segment = 0; + xfer->dx_dev.dd_addr = device_addr; + if (flags & DX_DIR_IN) + xfer->dx_dir = DX_DIR_IN; + else + xfer->dx_dir = DX_DIR_OUT; + + /* Set options from input flags and options */ + xfer->dx_options = options | DMACON_DSZ_W | DMACON_SERVMODE_SINGLE | + DMACON_DEMAND | DMACON_SYNC_APB | + DMACON_INT_INT | DMACON_RELOAD_NO_AUTO; + if (flags & DX_REQ_HW_BIT) { + xfer->dx_options |= DMACON_HW_REQ | + DMACON_HW_SRCSEL( DX_REQ_HW_EXTRACT(flags) ); + } else { + xfer->dx_options |= DMACON_SW_REQ; + } + + xfer->dx_channel = channel; + xfer->dx_complete = FALSE; + xfer->dx_remaining = xfer->dx_mem->dm_nsegs; + xfer->dx_aborted = FALSE; + + return xfer; +} + +void +s3c2440_dma_xfer_start(s3c2440_dma_xfer_t xfer) +{ + struct s3c2xx0_softc *sc = s3c2xx0_softc; + int seg; + uint32_t reg; + + if (dma_channel_xfer[xfer->dx_channel] != NULL) { + panic("DMA channel is allready active, queuing is not supported"); + } + + reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, DMA_STAT(xfer->dx_channel)); + if (reg & DMASTAT_BUSY) + panic("DMA channel is busy, cannot start new transfer!"); + + dma_channel_xfer[xfer->dx_channel] = xfer; + + seg = xfer->dx_next_segment; + xfer->dx_next_segment++; + xfer->dx_remaining--; + + if (xfer->dx_dir == DX_DIR_IN) { + uint32_t options; + + DPRINTF(("Preparing DMA transfer IN of %ld bytes from %lx to %lx\n", xfer->dx_mem->dm_segs[seg].ds_len, + xfer->dx_dev.dd_addr, xfer->dx_mem->dm_segs[seg].ds_addr)); + + /* Source is device, setup address */ + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DISRC(xfer->dx_channel), xfer->dx_dev.dd_addr); + + /* Devices are for now assumed to be on the peripheral bus, and they are accessed through a fixed address */ + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DISRCC(xfer->dx_channel), DISRCC_INC_FIXED | DISRCC_LOC_APB); + + /* Destination is memory, take next segment of the DMA map */ + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DIDST(xfer->dx_channel), xfer->dx_mem->dm_segs[seg].ds_addr); + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DIDSTC(xfer->dx_channel), DIDSTC_INC_INC | DIDSTC_LOC_AHB); + + + /* NOTE: We assume word transfers! */ + options = xfer->dx_options | DMACON_TC(xfer->dx_mem->dm_segs[seg].ds_len/4); + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_CON(xfer->dx_channel), options); + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_MASKTRIG(xfer->dx_channel), DMAMASKTRIG_ON); + dma_intr_status |= (1<dx_channel); + } else { + uint32_t options; + DPRINTF(("Preparing DMA transfer OUT of %ld bytes from %lx to %lx\n", xfer->dx_mem->dm_segs[seg].ds_len, + xfer->dx_mem->dm_segs[seg].ds_addr, xfer->dx_dev.dd_addr)); + + /* Source is memory, take next segment of the DMA map */ + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DISRC(xfer->dx_channel), xfer->dx_mem->dm_segs[seg].ds_addr); + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DISRCC(xfer->dx_channel), DIDSTC_INC_INC | DIDSTC_LOC_AHB); + + /* Destination is memory, take next segment of the DMA map */ + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DIDST(xfer->dx_channel), xfer->dx_dev.dd_addr); + /* Devices are for now assumed to be on the peripheral bus, and they are accessed through a fixed address */ + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_DIDSTC(xfer->dx_channel), DISRCC_INC_FIXED | DISRCC_LOC_APB); + + /* NOTE: We assume word transfers! */ + options = xfer->dx_options | DMACON_TC(xfer->dx_mem->dm_segs[seg].ds_len/4); + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_CON(xfer->dx_channel), options); + bus_space_write_4(sc->sc_iot, sc->sc_dmach, DMA_MASKTRIG(xfer->dx_channel), DMAMASKTRIG_ON); + dma_intr_status |= (1<dx_channel); + } +} + +int +s3c2440_dma_xfer_wait(s3c2440_dma_xfer_t xfer, int timeout) +{ + uint32_t complete; + int err = 0; + + mutex_enter(&dma_intr_mutex); + complete = xfer->dx_complete; + while(complete == 0) { + DPRINTF(("s3c2440_dma_xfer_wait: Complete: %x\n", complete)); + + if (cv_timedwait(&dma_intr_cv, &dma_intr_mutex, timeout) == + EWOULDBLOCK ) { + DPRINTF(("s3c2440_dma_xfer_wait: Timed out\n")); + complete = 1; + err = ETIMEDOUT; + break; + } + + complete = xfer->dx_complete; + } + + mutex_exit(&dma_intr_mutex); + + if (err == 0 && xfer->dx_aborted == 1) { + /* Transfer was aborted */ + err = EIO; + } + + return err; +} + +void +s3c2440_dma_xfer_abort(s3c2440_dma_xfer_t xfer) +{ + struct s3c2xx0_softc *sc = s3c2xx0_softc; + uint32_t reg; + + bus_space_write_4(sc->sc_iot, sc->sc_dmach, + DMA_MASKTRIG(xfer->dx_channel), + DMAMASKTRIG_STOP); + + xfer->dx_aborted = TRUE; + + reg = bus_space_read_4(sc->sc_iot, sc->sc_dmach, + DMA_MASKTRIG(xfer->dx_channel)); + DPRINTF(("s3c2440_dma: channel %d mask trigger %x\n", xfer->dx_channel, reg)); + + if ( !(reg & DMAMASKTRIG_ON) ) { + /* No transfer was in progress, notify about the + abortion immediatly. */ + xfer->dx_complete = TRUE; + + /* Free the DMA channel */ + dma_channel_xfer[xfer->dx_channel] = NULL; + + cv_broadcast(&dma_intr_cv); + } + + DPRINTF(("s3c2440_dma: Aborted xfer %p\n", xfer)); +} + +void +s3c2440_dma_xfer_free(s3c2440_dma_xfer_t xfer) +{ + FREE(xfer, M_TEMP); +} Index: arch/arm/s3c2xx0/s3c2440_dma.h =================================================================== RCS file: arch/arm/s3c2xx0/s3c2440_dma.h diff -N arch/arm/s3c2xx0/s3c2440_dma.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/s3c2440_dma.h 28 Dec 2009 10:35:34 -0000 @@ -0,0 +1,134 @@ +/* $NetBSD:$ */ + +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +/* This file implements a simple interface towards the S3C2440 DMA controller. + At this point queueing of transfers is not supported. In other words, one + has to be very careful that noone else is using a DMA channel when trying to use it. + + Only device<->memory transfers are supported at this time. + + Currently, the only usage of S3C2440 DMA is in the S3C2440 SD-Interface driver + (s3c2440_sdi.c). + */ + +#ifndef __S3C2440_DMA_H__ +#define __S3C2440_DMA_H__ + +#include + +void s3c2440_dma_init(void); +int s3c2440_dma_intr(void *arg); + +/* Bit 0 of flags: Transfer direction */ +#define DX_DIR_OUT 0 /* Mem -> Dev */ +#define DX_DIR_IN 1 /* Mem <- Dev */ + +/* Bit 1-4 of flags: Request source + Bit 1: 0 Sofware, 1 Hardware + Bit [4:2] Hardware Request source, according to bit [26:24] of S3C2440 DMA CONTROL Register + */ +#define DX_REQ_MASK 0x1E +#define DX_REQ_SHIFT 1 +#define DX_REQ_SW ((0<> (DX_REQ_SHIFT+1)) + +/* Datastructure representing a DMA device. + Currently only the physical address of a single, non-increment + register to access the device is available. + This will probably grow. + */ +struct s3c2440_dma_device { + paddr_t dd_addr; /* Physical address non-incrementing + address to use when accessing the device*/ +}; + +/* Datastructure used to describe a DMA transfer. + Allocated by s3c2440_dma_xfer_alloc() and freed by s3c2440_dma_xfer_free(). + */ +struct s3c2440_dma_xfer { + bus_dmamap_t dx_mem; /* DMA map for memory part of the DMA + transfer */ + uint32_t dx_next_segment; /* Next segment to use from the DMA map */ + struct s3c2440_dma_device dx_dev; /* Device part of the transfer */ + uint8_t dx_dir; /* Direction: DX_DIR_OUT or DX_DIR_IN */ + + uint32_t dx_options; /* Options to be OR'ed into DMA CONTROL register */ + uint8_t dx_channel; /* DMA Channel used by this transfer */ + + uint8_t dx_complete; /* Set to 1 when the transfer is complete + (i.e. all of the DMA memory map has either + been read or written) or has been aborted.*/ + uint8_t dx_aborted; /* Set to 1 when the transfer has been requested + to be aborted. */ + uint32_t dx_remaining; /* Number of segments that still remain to be + transferred */ +}; + +typedef struct s3c2440_dma_xfer* s3c2440_dma_xfer_t; + +/* Allocate a DMA transfer structure and initialize it with the given arguments. + channel: The DMA channel to use, 0-3. + + dmap: The DMA memory map to use for memory accesses. + + device_addr: Physical address of single non-increment register used to access device. + + flags: Encodes the direction and the request source. + Bitwise OR'ed of one of DX_DIR_IN, DX_DIR_OUT and DX_REQ_SW, DX_REQ_HW(c). + DX_DIR_IN indicates transfer from device to memory, while DX_DIR_OUT indicates + transfer from memory to device. + DX_REQ_SW indicates that the request source is software. DX_REQ_HW(c) indicates that the + request source is hardware, and source 'c' is used. Refer to section 8 of the S3C2440 User's Manual. + + options: Extra options which will be OR'ed with all internal options before the value is written to the + DMA Control Register for the DMA channel. + */ +s3c2440_dma_xfer_t s3c2440_dma_xfer_alloc(uint8_t channel, + bus_dmamap_t dmap, + paddr_t device_addr, + uint32_t flags, + uint32_t options); + +/* Start a DMA transfer. Unfortunately a DMA transfer cannot be aborted. */ +void s3c2440_dma_xfer_start(s3c2440_dma_xfer_t xfer); + +/* Wait for a DMA transfer to complete. + Returns 0 if transfer is completed, and 1 if it was aborted. + */ +int s3c2440_dma_xfer_wait(s3c2440_dma_xfer_t xfer, int timeout); + +/* Abort the DMA transfer. */ +void s3c2440_dma_xfer_abort(s3c2440_dma_xfer_t xfer); + +/* Free the DMA transfer structure. */ +void s3c2440_dma_xfer_free(s3c2440_dma_xfer_t xfer); + +#endif Index: arch/arm/s3c2xx0/s3c2440_extint.c =================================================================== RCS file: arch/arm/s3c2xx0/s3c2440_extint.c diff -N arch/arm/s3c2xx0/s3c2440_extint.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/s3c2440_extint.c 28 Dec 2009 10:35:34 -0000 @@ -0,0 +1,300 @@ +/* $NetBSD:$ */ + +/* + * 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. + */ + +/* + * device driver to handle cascaded external interrupts of S3C2440. + * + * EXTINT [8..23] are cascaded to IRQ #5 + * EXTINT [4..7] are cascaded to IRQ #4 + * EXTINT [0..3] are not cascaded and connected directly as IRQ #[0..3]. + * EXTINT [0..3] are handled by main interrupt handler in s3c2440_intr.c. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD:$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "locators.h" +#include "opt_s3c2440.h" /* for S3C2410_EXTINT_MAX */ + +#ifndef S3C2440_EXTINT_MAX +#define S3C2440_EXTINT_MAX 23 +#endif + +#define EXTINT_CASCADE_MIN 4 + +#if S3C2440_EXTINT_MAX < EXTINT_CASCADE_MIN +#error "Don't enable ssextio if you don't use extint[4..23]." +#endif + +#define N_EXTINT (S3C2440_EXTINT_MAX - EXTINT_CASCADE_MIN +1) + +struct ssextio_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + uint32_t sc_pending; + uint32_t sc_mask; + + struct extint_handler { + int (* func)(void *); + void *arg; + void *sh; /* softintr handler */ + int level; /* IPL */ + } sc_handler[N_EXTINT]; + +}; + +static struct ssextio_softc *ssextio_softc = NULL; + +/* cookies */ +#define EXTINT_4_7 1 +#define EXTINT_8_23 2 + +/* prototypes */ +static int ssextio_match(struct device *, struct cfdata *, void *); +static void ssextio_attach(struct device *, struct device *, void *); +static int ssextio_search(struct device *, struct cfdata *, + const int *, void *); +static int ssextio_print(void *, const char *); + +static int ssextio_cascaded_intr(void *); +static void ssextio_softintr(void *); + +static inline void +update_hw_mask(void) +{ + bus_space_write_4(ssextio_softc->sc_iot, ssextio_softc->sc_ioh, + GPIO_EINTMASK, ssextio_softc->sc_mask | ssextio_softc->sc_pending); +} + + +/* attach structures */ +CFATTACH_DECL(ssextio, sizeof(struct ssextio_softc), ssextio_match, ssextio_attach, + NULL, NULL); + +static int +ssextio_print(void *aux, const char *name) +{ + struct s3c2xx0_attach_args *sa = (struct s3c2xx0_attach_args*)aux; + + if (sa->sa_addr != SSEXTIOCF_ADDR_DEFAULT) + aprint_normal(" addr 0x%lx", sa->sa_addr); + if (sa->sa_intr > 0) + aprint_normal(" intr %d", sa->sa_intr); + return (UNCONF); +} + +int +ssextio_match(struct device *parent, struct cfdata *match, void *aux) +{ +#if S3C2440_EXTINT_MAX < 4 + /* better not configure this driver */ + return 0; +#else + if (ssextio_softc != NULL) + return 0; + + return 1; +#endif +} + +void +ssextio_attach(struct device *parent, struct device *self, void *aux) +{ + struct ssextio_softc *sc = (struct ssextio_softc*)self; + struct s3c24x0_softc *cpuc = (struct s3c24x0_softc *)parent; + + aprint_normal("\n"); + + ssextio_softc = sc; + + sc->sc_iot = cpuc->sc_sx.sc_iot; + sc->sc_ioh = cpuc->sc_sx.sc_gpio_ioh; + + sc->sc_pending = 0; + sc->sc_mask = ~0; + + s3c24x0_intr_establish(S3C2440_INT_4_7, IPL_HIGH, IST_NONE, + ssextio_cascaded_intr, (void *)EXTINT_4_7); +#if S3C2440_EXTINT_MAX >= 8 + s3c24x0_intr_establish(S3C2440_INT_8_23, IPL_HIGH, IST_NONE, + ssextio_cascaded_intr, (void *)EXTINT_8_23); +#endif + + /* + * Attach each devices + */ + config_search_ia(ssextio_search, self, "ssextio", NULL); +} + +static int +ssextio_search(struct device *parent, struct cfdata *cf, + const int *ldesc, void *aux) +{ + struct ssextio_softc *sc = (struct ssextio_softc *)parent; + struct s3c24x0_softc *cpuc =(struct s3c24x0_softc *) device_parent(&sc->sc_dev); + struct s3c2xx0_attach_args sa; + + sa.sa_sc = sc; + sa.sa_iot = sc->sc_iot; + sa.sa_addr = cf->cf_loc[SSEXTIOCF_ADDR]; + sa.sa_size = cf->cf_loc[SSEXTIOCF_SIZE]; + sa.sa_intr = cf->cf_loc[SSEXTIOCF_INTR]; + sa.sa_dmat = cpuc->sc_sx.sc_dmat; + + if (config_match(parent, cf, &sa)) + config_attach(parent, cf, &sa, ssextio_print); + + return 0; +} + +void * +s3c2440_extint_establish(int extint, int ipl, int type, + int (*func)(void *), void *arg) +{ + int save; + int idx; + int soft_level; + + if (extint < 0 || N_EXTINT <= extint) + panic("Bad interrupt no for extio"); + + if (extint < EXTINT_CASCADE_MIN) { + /* + * EXINT[0..3] are not cascaded. they are handled by + * the main interrupt controller. + */ + return s3c24x0_intr_establish(extint, ipl, type, func, arg); + } + + soft_level = SOFTINT_SERIAL; + + idx = extint - EXTINT_CASCADE_MIN; + + save = disable_interrupts(I32_bit); + + ssextio_softc->sc_handler[idx].func = func; + ssextio_softc->sc_handler[idx].arg = arg; + ssextio_softc->sc_handler[idx].level = ipl; + + ssextio_softc->sc_handler[idx].sh = softint_establish(soft_level, + ssextio_softintr, &ssextio_softc->sc_handler[idx]); + + s3c2440_setup_extint(extint, type); + + bus_space_write_4(ssextio_softc->sc_iot, ssextio_softc->sc_ioh, + GPIO_EINTPEND, 1U << extint); + ssextio_softc->sc_mask &= ~(1U << extint); + update_hw_mask(); + + restore_interrupts(save); + return &ssextio_softc->sc_handler[idx]; +} + + +static int +ssextio_cascaded_intr(void *cookie) +{ + uint32_t pending_mask, pending; + int int_min; + bus_space_tag_t iot = ssextio_softc->sc_iot; + bus_space_handle_t ioh = ssextio_softc->sc_ioh; + int save, i; + + switch((int)cookie) { + case EXTINT_4_7: + pending_mask = 0x000000f0; + int_min = 4; + break; + + case EXTINT_8_23: + pending_mask = 0x00ffff00; + int_min = 8; + break; + + default: + panic("Bad cookie for %s", __func__); + } + + + save = disable_interrupts(I32_bit);; + pending = pending_mask & bus_space_read_4(iot, ioh, GPIO_EINTPEND); + pending &= ~ssextio_softc->sc_mask; + ssextio_softc->sc_pending |= pending; + /* disable the extint until the handler is called. */ + update_hw_mask(); + restore_interrupts(save); + + for (i=int_min; pending; ++i) { + if (pending & (1<sc_handler[i-EXTINT_CASCADE_MIN].sh != NULL); + + softint_schedule( + ssextio_softc->sc_handler[i-EXTINT_CASCADE_MIN].sh); + pending &= ~ (1<sc_handler; + int s, save; + + save = disable_interrupts(I32_bit); + /* clear hardware pending bits */ + bus_space_write_4(ssextio_softc->sc_iot, ssextio_softc->sc_ioh, + GPIO_EINTPEND, 1<sc_pending &= ~(1<level); + h->func(h->arg); + splx(s); +} Index: arch/arm/s3c2xx0/s3c2440_intr.c =================================================================== RCS file: arch/arm/s3c2xx0/s3c2440_intr.c diff -N arch/arm/s3c2xx0/s3c2440_intr.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/s3c2440_intr.c 28 Dec 2009 10:35:34 -0000 @@ -0,0 +1,389 @@ +/* $NetBSD:$ */ + +/* + * 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 S3C2440 processor. + * It has integrated interrupt controller. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD:$"); + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * interrupt dispatch table. + */ + +struct s3c2xx0_intr_dispatch handler[ICU_LEN]; + + +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_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 s3c2440_irq_handler(struct clockframe *); +void +s3c2440_irq_handler(struct clockframe *frame) +{ + uint32_t irqbits; + int irqno; + int saved_spl_level; + + saved_spl_level = 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< 1000 ) { + printf("Served more than 1000 irqs in one go, breaking out....(0x%X)\n", icreg(INTCTL_INTPND)); + break; + }*/ + } + +#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<= 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 >= S3C2440_SUBIRQ_MIN) { + /* cascaded interrupts. */ + int main_irqno; + int i = (irqno - S3C2440_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<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 +s3c2440_mask_subinterrupts(int bits) +{ + atomic_set_bit((uint32_t *)__UNVOLATILE(&icreg(INTCTL_INTSUBMSK)), + bits); +} + +void +s3c2440_unmask_subinterrupts(int bits) +{ + atomic_clear_bit((uint32_t *)__UNVOLATILE(&icreg(INTCTL_INTSUBMSK)), + bits); +} + +/* + * 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 +s3c2440_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; + uint32_t gpio; + uint32_t offset; + + 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); + + /* Setup GPIO-pin to serve as interrupt */ + if (extint < 8 ) { + gpio = GPIO_PFCON; + offset = extint; + } else { + gpio = GPIO_PGCON; + offset = 8-extint; + } + reg = bus_space_read_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh, + gpio); + reg = GPIO_SET_FUNC(reg, offset, 2); + bus_space_write_4(s3c2xx0_softc->sc_iot, s3c2xx0_softc->sc_gpio_ioh, + gpio, reg); + + + restore_interrupts(save); +} Index: arch/arm/s3c2xx0/s3c2440_intr.h =================================================================== RCS file: arch/arm/s3c2xx0/s3c2440_intr.h diff -N arch/arm/s3c2xx0/s3c2440_intr.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/s3c2440_intr.h 28 Dec 2009 10:35:34 -0000 @@ -0,0 +1,39 @@ +/* $NetBSD:$ */ + +/* + * 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 _S3C2440_INTR_H_ +#define _S3C2440_INTR_H_ + +#define ARM_IRQ_HANDLER _C_LABEL(s3c2440_irq_handler) + +#include + +#endif /* _S3C2410_INTR_H_ */ Index: arch/arm/s3c2xx0/s3c2440_sdi.c =================================================================== RCS file: arch/arm/s3c2xx0/s3c2440_sdi.c diff -N arch/arm/s3c2xx0/s3c2440_sdi.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/s3c2440_sdi.c 28 Dec 2009 10:35:35 -0000 @@ -0,0 +1,825 @@ +/* $NetBSD:$ */ + +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +//#include + +#include +#include + +#include + +#ifdef SSSDI_DEBUG +#define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) +#else +#define DPRINTF(s) do {} while (/*CONSTCOND*/0) +#endif + +struct sssdi_softc { + struct device dev; + + bus_space_tag_t iot; + + bus_space_handle_t ioh; + bus_space_handle_t card_ioh; /* Card detect I/O*/ + + device_t sdmmc; + + uint32_t caps; + + int width; /* Transfer width */ + void *sc_ih; /* SSSDI Interrupt handler */ + + struct kmutex intr_mtx; + struct kcondvar intr_cv; + uint32_t intr_status; /* Set by the interrupt handler */ + + s3c2440_dma_xfer_t dma_xfer; /* Active DMA transfer, NULL if none. */ +}; + +/* Basic driver stuff */ +static int sssdi_match(struct device *, struct cfdata *, void *); +static void sssdi_attach(struct device *, struct device *, void *); +//static int sssdi_search(struct device *, struct cfdata *, const int *, void *); + +CFATTACH_DECL(sssdi, sizeof(struct sssdi_softc), sssdi_match, sssdi_attach, + NULL, NULL); + +/* SD/MMC chip functions */ +static int sssdi_host_reset(sdmmc_chipset_handle_t); +static uint32_t sssdi_host_ocr(sdmmc_chipset_handle_t); +static int sssdi_maxblklen(sdmmc_chipset_handle_t); +static int sssdi_card_detect(sdmmc_chipset_handle_t); +static int sssdi_write_protect(sdmmc_chipset_handle_t); +static int sssdi_bus_power(sdmmc_chipset_handle_t, uint32_t); +static int sssdi_bus_clock(sdmmc_chipset_handle_t, int); +static int sssdi_bus_width(sdmmc_chipset_handle_t, int); +static void sssdi_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command*); +static void sssdi_card_enable_intr(sdmmc_chipset_handle_t, int); +static void sssdi_card_intr_ack(sdmmc_chipset_handle_t); + +/* Interrupt Handlers */ +int sssdi_intr(void *arg); +int sssdi_intr_card(void *arg); + +/* Interrupt helper functions */ +static void sssdi_enable_intr(struct sssdi_softc *, uint32_t ); +void sssdi_disable_intr(struct sssdi_softc *sc, uint32_t i); +void sssdi_clear_intr(struct sssdi_softc *sc); +static int sssdi_wait_intr(struct sssdi_softc *sc, uint32_t mask, int timeout); + +/* Programmed I/O transfer helpers */ +void sssdi_perform_pio_read(struct sssdi_softc *sc, struct sdmmc_command *cmd); +void sssdi_perform_pio_write(struct sssdi_softc *sc, struct sdmmc_command *cmd); + +/* Interrupt helper defines */ +#define SDI_CMD_SENT SDIINTMASK_CMD_SENT +#define SDI_CMD_TIMEOUT SDIINTMASK_CMD_TIMEOUT +#define SDI_RESP_FIN SDIINTMASK_RESP +#define SDI_FIFO_RX_FULL SDIINTMASK_RF_FULL +#define SDI_FIFO_RX_LAST SDIINTMASK_RF_LAST +#define SDI_FIFO_TX_EMPTY SDIINTMASK_TF_EMPTY +#define SDI_DATA_FIN SDIINTMASK_DATA_FIN +#define SDI_DATA_TIMEOUT SDIINTMASK_DATA_TIMEOUT + +/* SDMMC function structure */ +struct sdmmc_chip_functions sssdi_functions = { + /* host controller reset */ + sssdi_host_reset, + + /* host capabilities */ + sssdi_host_ocr, + sssdi_maxblklen, + + /* card detection */ + sssdi_card_detect, + + /* write protect */ + sssdi_write_protect, + + /* bus power, clock frequency and width */ + sssdi_bus_power, + sssdi_bus_clock, + sssdi_bus_width, + + /* command execution */ + sssdi_exec_command, + + /* card interrupt */ + sssdi_card_enable_intr, + sssdi_card_intr_ack +}; + +int +sssdi_match(struct device *parent, struct cfdata *match, void *aux) +{ +/* struct s3c2xx0_attach_args *sa = aux;*/ + + /* Not sure how to match here, maybe CPU type? */ + return 1; +} + +void +sssdi_attach(struct device *parent, struct device *self, void *aux) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)self; + struct s3c2xx0_attach_args *sa = (struct s3c2xx0_attach_args *)aux; + struct sdmmcbus_attach_args saa; + bus_space_tag_t iot = sa->sa_iot; + uint32_t data; + + sc->iot = iot; + + if (bus_space_map(iot, S3C2440_SDI_BASE, S3C2440_SDI_SIZE, 0, &sc->ioh) ) { + printf(": failed to map registers"); + return; + } + + if (bus_space_map(iot, S3C2440_GPIO_BASE, S3C2440_GPIO_SIZE, 0, &sc->card_ioh) ) { + printf(": failed to map GPIO memory for card detection"); + return; + } + + /* Set GPG8 to EINT[16], as it is the card detect line. */ + data = bus_space_read_4(sc->iot, sc->card_ioh, GPIO_PGCON); + data = GPIO_SET_FUNC(data, 8, 0x2); + bus_space_write_4(sc->iot, sc->card_ioh, GPIO_PGCON, data); + + /* Set GPH8 to input, as it is used to detect write protection. */ + data = bus_space_read_4(sc->iot, sc->card_ioh, GPIO_PHCON); + data = GPIO_SET_FUNC(data, 8, 0x00); + bus_space_write_4(sc->iot, sc->card_ioh, GPIO_PHCON, data); + + mutex_init(&sc->intr_mtx, MUTEX_DEFAULT, IPL_SDMMC); + cv_init(&sc->intr_cv, "s3c2440_sdiintr"); + sc->intr_status = 0; + sc->caps = SMC_CAPS_4BIT_MODE | SMC_CAPS_DMA; + + memset(&saa, 0, sizeof(saa)); + saa.saa_busname = "sdmmc"; + saa.saa_sct = &sssdi_functions; + saa.saa_sch = sc; + saa.saa_dmat = sa->sa_dmat; + saa.saa_clkmin = s3c2xx0_softc->sc_pclk / 256; + saa.saa_clkmax = s3c2xx0_softc->sc_pclk / 1; /* PCLK/1 or PCLK/2 depending on how the spec is read */ + saa.saa_caps = sc->caps; + + /* Attach our interrupt handler */ + sc->sc_ih = s3c24x0_intr_establish(S3C2410_INT_SDI, IPL_SDMMC, IST_EDGE_RISING, sssdi_intr, sc); + + /* Attach interrupt handler to detect change in card status */ + s3c2440_extint_establish(16, IPL_SDMMC, IST_EDGE_BOTH, sssdi_intr_card, sc); + + (void) sssdi_host_reset(sc); + + printf("\n"); + + /* Attach to the generic SD/MMC bus */ + /* Is it a good idea to get the private parts of sdmmc ? */ + sc->sdmmc = config_found(&sc->dev, &saa, NULL); + + sc->dma_xfer = NULL; +} + +int +sssdi_host_reset(sdmmc_chipset_handle_t sch) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)sch; + + /* Note that we do not enable the clock just yet. */ + bus_space_write_4(sc->iot, sc->ioh, SDI_CON, SDICON_SD_RESET | + SDICON_CTYP_SD | SDICON_RCV_IO_INT ); + /* bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_STA, SDICMDSTA_RSP_CRC | SDICMDSTA_CMD_SENT | + SDICMDSTA_CMD_TIMEOUT | SDICMDSTA_RSP_FIN);*/ + + sssdi_clear_intr(sc); + sssdi_enable_intr(sc, SDI_CMD_SENT | SDI_CMD_TIMEOUT | SDI_DATA_TIMEOUT + | SDI_RESP_FIN); + + return 0; +} + +uint32_t +sssdi_host_ocr(sdmmc_chipset_handle_t sch) +{ + /* This really ought to be made configurable, I guess... */ + return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; +} + +int +sssdi_maxblklen(sdmmc_chipset_handle_t sch) +{ + /* The S3C2440 user's manual mentions 4095 as a maximum */ + return 4095; +} + +int +sssdi_card_detect(sdmmc_chipset_handle_t sch) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)sch; + uint32_t data; + + DPRINTF(("sssdi_card_detect\n")); + + data = bus_space_read_4(sc->iot, sc->card_ioh, GPIO_PGDAT); + + /* GPIO Port G, pin 8 is high when card is inserted. */ + if ( (data & (1<<8)) == 0) { + return 1; /* Card Present */ + } else { + return 0; /* No Card */ + } +} + +int +sssdi_write_protect(sdmmc_chipset_handle_t sch) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)sch; + uint32_t data; + + data = bus_space_read_4(sc->iot, sc->card_ioh, GPIO_PHDAT); + + + /* If GPIO Port H Pin 8 is high, the card is write protected. */ + if ( (data & (1<<8)) ) { + return 1; /* Write protected */ + } else { + return 0; /* Writable */ + } +} + +int +sssdi_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) +{ + /* Do nothing, we can't adjust the bus power */ + return 0; +} + +int +sssdi_bus_clock(sdmmc_chipset_handle_t sch, int freq) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)sch; + int div; + int clock_set = 0; + int control; + int pclk = s3c2xx0_softc->sc_pclk/1000; /*Peripheral bus clock in KHz*/ + + /* Round peripheral bus clock down to nearest MHz */ + pclk = (pclk / 1000) * 1000; + + control = bus_space_read_4(sc->iot, sc->ioh, SDI_CON); + bus_space_write_4(sc->iot, sc->ioh, SDI_CON, control & ~SDICON_ENCLK); + + DPRINTF(("sssdi_bus_clock (freq: %d KHz)\n", freq)); + + /* If the frequency is zero just keep the clock disabled */ + if (freq == 0) + return 0; + + for (div = 1; div <= 256; div++) { + if ( pclk / div <= freq) { + DPRINTF(("Using divisor %d: %d/%d = %d\n", div, pclk, + div, pclk/div)); + clock_set = 1; + bus_space_write_1(sc->iot, sc->ioh, SDI_PRE, div-1); + break; + } + } + + if (clock_set) { + bus_space_write_4(sc->iot, sc->ioh, + SDI_CON, control | SDICON_ENCLK); + if (div-1 == bus_space_read_4(sc->iot, sc->ioh, SDI_PRE)) { + /* Clock successfully set, TODO: how do we fail?! */ + } + + /* TODO: Wait for 74 SDCLK */ + sdmmc_delay(100000); + return 0; + } else { + return 1; + } +} + +int +sssdi_bus_width(sdmmc_chipset_handle_t sch, int width) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)sch; + printf("s3c2440_sdi: sssdi_bus_width (%d)\n", width); + + sc->width = width; + return 0; +} + +#define SSSDI_TRANSFER_NONE 0 +#define SSSDI_TRANSFER_READ 1 +#define SSSDI_TRANSFER_WRITE 2 + +void +sssdi_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)sch; + uint32_t cmd_control; + int status = 0; + uint32_t data_status; + int transfer = SSSDI_TRANSFER_NONE; + + /* Reset all status registers prior to sending a command */ + bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_FSTA, 0xFFFFFFFF); + bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_STA, 0xFFFFFFFF); + bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_STA, 0xFFFFFFFF); + + /* Set the argument */ + bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_ARG, cmd->c_arg); + + /* Prepare the value for the command control register */ + cmd_control = (cmd->c_opcode & SDICMDCON_CMD_MASK) | + SDICMDCON_HOST_CMD | SDICMDCON_CMST; + if (cmd->c_flags & SCF_RSP_PRESENT) + cmd_control |= SDICMDCON_WAIT_RSP; + if (cmd->c_flags & SCF_RSP_136) + cmd_control |= SDICMDCON_LONG_RSP; + + if (cmd->c_datalen > 0 && cmd->c_data != NULL) { + /* TODO: Ensure that the above condition matches the semantics + of SDICMDCON_WITH_DATA*/ + DPRINTF(("DATA, datalen: %d, blk_size: %d\n", cmd->c_datalen, + cmd->c_blklen)); + cmd_control |= SDICMDCON_WITH_DATA; + } + + /* Unfortunately we have to set the ABORT_CMD bit when using CMD12 and + CMD52. + CMD12 is MMC_STOP_TRANSMISSION. I currently do not know what CMD52 + is, but it is related to SDIO. + */ + if (cmd->c_opcode == MMC_STOP_TRANSMISSION) { + cmd_control |= SDICMDCON_ABORT_CMD; + } + + /* Prepare SDI for data transfer */ + bus_space_write_4(sc->iot, sc->ioh, SDI_BSIZE, cmd->c_blklen); + + /* Set maximum transfer timeout */ + bus_space_write_4(sc->iot, sc->ioh, SDI_DTIMER, 0x007FFFFF); + + /* Set the timeout as low as possible to trigger timeouts for debugging purposes */ + /*bus_space_write_4(sc->iot, sc->ioh, SDI_DTIMER, 0x00005000);*/ + + if ( (cmd->c_flags & SCF_CMD_READ) && + (cmd_control & SDICMDCON_WITH_DATA)) { + uint32_t data_control; + DPRINTF(("Reading %d bytes\n", cmd->c_datalen)); + transfer = SSSDI_TRANSFER_READ; + + data_control = SDIDATCON_DATMODE_RECEIVE | SDIDATCON_RACMD | + SDIDATCON_DTST | SDIDATCON_BLKMODE | + ((cmd->c_datalen / cmd->c_blklen) & SDIDATCON_BLKNUM_MASK) | + SDIDATCON_DATA_WORD; + + if (sc->caps & SMC_CAPS_DMA) { + data_control |= SDIDATCON_ENDMA; + sc->dma_xfer = s3c2440_dma_xfer_alloc(0, cmd->c_dmamap, + S3C2440_SDI_BASE+SDI_DAT_LI_W, + DX_REQ_HW(2)|DX_DIR_IN, 0); + /* Note that we do not start the DMA transfer right away. This is because starting it + now results in a timeout when trying to receive command ACK. + */ + } + + bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_CON, data_control); + } else if (cmd_control & SDICMDCON_WITH_DATA) { + /* Write data */ + + uint32_t data_control; + DPRINTF(("Writing %d bytes\n", cmd->c_datalen)); + DPRINTF(("Requesting %d blocks\n", + cmd->c_datalen / cmd->c_blklen)); + transfer = SSSDI_TRANSFER_WRITE; + data_control = SDIDATCON_DATMODE_TRANSMIT | SDIDATCON_BLKMODE | + SDIDATCON_TARSP | SDIDATCON_DTST | + ((cmd->c_datalen / cmd->c_blklen) & SDIDATCON_BLKNUM_MASK) | + SDIDATCON_DATA_WORD; + + if (sc->caps & SMC_CAPS_DMA) { + data_control |= SDIDATCON_ENDMA; + sc->dma_xfer = s3c2440_dma_xfer_alloc(0, cmd->c_dmamap, S3C2440_SDI_BASE+SDI_DAT_LI_W, + DX_REQ_HW(2)|DX_DIR_OUT, 0); + } + bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_CON, data_control); + } + + /* Send command to SDI */ + bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_CON, cmd_control); + + /* Wait for command sent acknowledgement, timeout set to 100ms */ + status = sssdi_wait_intr(sc, SDI_CMD_SENT | SDI_CMD_TIMEOUT, 100); + + if (status & SDI_CMD_TIMEOUT) { + DPRINTF(("Timeout waiting for command acknowledgement\n")); + cmd->c_error = ETIMEDOUT; + goto out; + } else if (status & SDICMDSTA_CMD_SENT) { + /* Interrupt handler has acknowledged already, we do not need + to do anything further here */ + } + + if (!(cmd_control & SDICMDCON_WAIT_RSP)) { + cmd->c_flags |= SCF_ITSDONE; + goto out; + } + + DPRINTF(("waiting for response\n")); + + status = sssdi_wait_intr(sc, SDI_RESP_FIN, 100); + if (status & SDI_CMD_TIMEOUT) { + cmd->c_error = ETIMEDOUT; + DPRINTF(("Timeout waiting for response\n")); + goto out; + } + DPRINTF(("Got Response\n")); + + /* It seems very awkward that this is needed, but it is: + When receiving long responses the order of the response registers + have been switched around. + The reason for this is probably that with short responses only half + the registers are needed. It would be better not to read the unused + registers. For now, however, this works like a charm. + */ + if (cmd->c_flags & SCF_RSP_136 ) { + cmd->c_resp[0] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP3); + cmd->c_resp[1] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP2); + cmd->c_resp[2] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP1); + cmd->c_resp[3] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP0); + } else { + cmd->c_resp[0] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP0); + cmd->c_resp[1] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP1); + + /* These two are probably not needed */ + /*cmd->c_resp[2] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP2); + cmd->c_resp[3] = bus_space_read_4(sc->iot, sc->ioh, SDI_RSP3);*/ + } + + DPRINTF(("Response: %X %X %X %X\n", + cmd->c_resp[0], + cmd->c_resp[1], + cmd->c_resp[2], + cmd->c_resp[3])); + + status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_CNT); + + DPRINTF(("Remaining bytes of current block: %d\n", + SDIDATCNT_BLK_CNT(status))); + DPRINTF(("Remaining Block Number : %d\n", + SDIDATCNT_BLK_NUM_CNT(status))); + + data_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_STA); +#ifdef SSSDI_DEBUG + printf("SDI Data Status Register Before xfer: 0x%X\n", data_status); +#endif + if (transfer == SSSDI_TRANSFER_READ) { + DPRINTF(("Waiting for transfer to complete\n")); + + if (sc->dma_xfer != NULL ) { + int dma_error = 0; + /* It might not be very efficient to delay the start of + the DMA transfer until now, but it works :-). + */ + s3c2440_dma_xfer_start(sc->dma_xfer); + + /* Wait until the transfer has completed, timeout is + 500ms */ + dma_error = s3c2440_dma_xfer_wait(sc->dma_xfer, 500); + if (dma_error != 0) { + s3c2440_dma_xfer_abort(sc->dma_xfer); + cmd->c_error = dma_error; + DPRINTF(("DMA xfer failed: %d\n", dma_error)); + goto out; + } + } else { + DPRINTF(("PIO READ\n")); + sssdi_perform_pio_read(sc, cmd); + } + } else if (transfer == SSSDI_TRANSFER_WRITE) { + DPRINTF(("Waiting for WRITE transfer to complete\n")); + + if (sc->dma_xfer != NULL) { + int dma_error = 0; + s3c2440_dma_xfer_start(sc->dma_xfer); + + dma_error = s3c2440_dma_xfer_wait(sc->dma_xfer, 500); + if (dma_error != 0) { + s3c2440_dma_xfer_abort(sc->dma_xfer); + cmd->c_error = dma_error; + DPRINTF(("DMA xfer failed: %d\n", dma_error)); + goto out; + } + } else { + DPRINTF(("PIO WRITE\n")); + sssdi_perform_pio_write(sc, cmd); + } + + if (cmd->c_error == ETIMEDOUT) + goto out; + + DPRINTF(("Waiting for transfer to complete\n")); + status = sssdi_wait_intr(sc, SDI_DATA_FIN, 1000); + if (status & SDI_CMD_TIMEOUT) { + cmd->c_error = ETIMEDOUT; + DPRINTF(("Timeout waiting for data to complete\n")); + goto out; + } + DPRINTF(("Done\n")); + + } + + + /* Response has been received, and any data transfer needed has been + performed */ + cmd->c_flags |= SCF_ITSDONE; + + out: + /* Ensure that we free the allocated DMA xfer structure, even if no + data was transferred */ + if (sc->dma_xfer != NULL) { + s3c2440_dma_xfer_free(sc->dma_xfer); + sc->dma_xfer = NULL; + } + +#ifdef SSSDI_DEBUG + data_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_STA); + printf("SDI Data Status Register after execute: 0x%X\n", data_status); +#endif + + /* Clear status register. Their are cleared on the + next sssdi_exec_command */ + bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_STA, 0xFFFFFFFF); + bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_CON, 0x0); +} + +void sssdi_perform_pio_read(struct sssdi_softc *sc, struct sdmmc_command *cmd) +{ + uint32_t status; + uint32_t fifo_status; + int count; + uint32_t written; + uint32_t *dest = (uint32_t*)cmd->c_data; + + written = 0; + + while (written < cmd->c_datalen ) { + /* Wait until the FIFO is full or has the final data. + In the latter case it might not get filled. */ + status = sssdi_wait_intr(sc, SDI_FIFO_RX_FULL | SDI_FIFO_RX_LAST, 1000); + + fifo_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_FSTA); + count = SDIDATFSTA_FFCNT(fifo_status); + + for(int i=0; iiot, sc->ioh, SDI_DAT_LI_W); + *dest = buf; + written += 4; + dest++; + } + } +} + +void +sssdi_perform_pio_write(struct sssdi_softc *sc, struct sdmmc_command *cmd) +{ + uint32_t status; + uint32_t fifo_status; + int count; + uint32_t written; + uint32_t *dest = (uint32_t*)cmd->c_data; + + written = 0; + + while (written < cmd->c_datalen ) { + /* Wait until the FIFO is full or has the final data. + In the latter case it might not get filled. */ + DPRINTF(("Waiting for FIFO to become empty\n")); + status = sssdi_wait_intr(sc, SDI_FIFO_TX_EMPTY, 1000); + + fifo_status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_FSTA); + DPRINTF(("PIO Write FIFO Status: 0x%X\n", fifo_status)); + count = 64-SDIDATFSTA_FFCNT(fifo_status); + + status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_CNT); + DPRINTF(("Remaining bytes of current block: %d\n", + SDIDATCNT_BLK_CNT(status))); + DPRINTF(("Remaining Block Number : %d\n", + SDIDATCNT_BLK_NUM_CNT(status))); + + + status = bus_space_read_4(sc->iot,sc->ioh, SDI_DAT_STA); + DPRINTF(("PIO Write Data Status: 0x%X\n", status)); + + if (status & SDIDATSTA_DATA_TIMEOUT) { + cmd->c_error = ETIMEDOUT; + /* Acknowledge the timeout*/ + bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_STA, + SDIDATSTA_DATA_TIMEOUT); + printf("%s: Data timeout\n", device_xname(&sc->dev)); + break; + } + + DPRINTF(("Filling FIFO with %d bytes\n", count)); + for(int i=0; iiot, sc->ioh, SDI_DAT_LI_W, *dest); + written += 4; + dest++; + } + } +} + + +void +sssdi_card_enable_intr(sdmmc_chipset_handle_t sch, int enable) +{ + printf("sssdi_card_enable_intr not implemented\n"); +} + +void +sssdi_card_intr_ack(sdmmc_chipset_handle_t sch) +{ + printf("sssdi_card_intr_ack not implemented\n"); +} + +int +sssdi_intr(void *arg) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)arg; + uint32_t status; + uint32_t ack_status; + + /* Start by dealing with Command Status */ + ack_status = 0; + status = bus_space_read_4(sc->iot, sc->ioh, SDI_CMD_STA); + + if (status & SDICMDSTA_CMD_TIMEOUT) { + ack_status |= SDICMDSTA_CMD_TIMEOUT; + sc->intr_status |= SDI_CMD_TIMEOUT; + /*sssdi_disable_intr(sc, SDI_CMD_TIMEOUT);*/ + } + if (status & SDICMDSTA_CMD_SENT) { + ack_status |= SDICMDSTA_CMD_SENT; + sc->intr_status |= SDI_CMD_SENT; + /* sssdi_disable_intr(sc, SDI_CMD_SENT);*/ + } + if (status & SDICMDSTA_RSP_FIN) { + ack_status |= SDICMDSTA_RSP_FIN; + sc->intr_status |= SDI_RESP_FIN; + /* sssdi_disable_intr(sc, SDI_RESP_FIN);*/ + } + bus_space_write_4(sc->iot, sc->ioh, SDI_CMD_STA, ack_status); + + /* Next: FIFO Status */ + ack_status = 0; + status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_FSTA); + if (status & SDIDATFSTA_RF_FULL) { + ack_status |= SDIDATFSTA_RF_FULL; + sc->intr_status |= SDI_FIFO_RX_FULL; + sssdi_disable_intr(sc, SDI_FIFO_RX_FULL); + } + if (status & SDIDATFSTA_RF_LAST) { + ack_status |= SDIDATFSTA_RF_LAST | SDIDATFSTA_RESET; + sc->intr_status |= SDI_FIFO_RX_LAST; + sssdi_disable_intr(sc, SDI_FIFO_RX_LAST); + } + if (status & SDIDATFSTA_TF_EMPTY) { + ack_status |= SDIDATFSTA_TF_EMPTY; + sc->intr_status |= SDI_FIFO_TX_EMPTY; + sssdi_disable_intr(sc, SDI_FIFO_TX_EMPTY); + } + bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_FSTA, ack_status); + + ack_status = 0; + status = bus_space_read_4(sc->iot, sc->ioh, SDI_DAT_STA); + if (status & SDIDATSTA_DATA_FIN) { + DPRINTF(("sssdi_intr: DATA FINISHED\n")); + ack_status |= SDIDATSTA_DATA_FIN; + sc->intr_status |= SDI_DATA_FIN; + sssdi_disable_intr(sc, SDI_DATA_FIN); + } + if (status & SDIDATSTA_DATA_TIMEOUT) { + printf("sssdi_intr: DATA TIMEOUT\n"); + ack_status |= SDIDATSTA_DATA_TIMEOUT; + sc->intr_status |= SDI_DATA_TIMEOUT; + /* Data timeout interrupt is always enabled, thus + we do not disable it when we have received one. */ + /*sssdi_disable_intr(sc, SDI_DATA_TIMEOUT);*/ + + if (sc->dma_xfer != NULL) { + s3c2440_dma_xfer_abort(sc->dma_xfer); + } + } + bus_space_write_4(sc->iot, sc->ioh, SDI_DAT_STA, ack_status); + + cv_broadcast(&sc->intr_cv); + + return 1; +} + +int +sssdi_intr_card(void *arg) +{ + struct sssdi_softc *sc = (struct sssdi_softc*)arg; + + /* TODO: If card was removed then abort any current command */ + + sdmmc_needs_discover(sc->sdmmc); + + return 1; /* handled */ +} + +static void +sssdi_enable_intr(struct sssdi_softc *sc, uint32_t i) +{ + uint32_t v = bus_space_read_4(sc->iot, sc->ioh, SDI_INT_MASK); + bus_space_write_4(sc->iot, sc->ioh, SDI_INT_MASK, v | i ); +} + + void +sssdi_disable_intr(struct sssdi_softc *sc, uint32_t i) +{ + uint32_t v = bus_space_read_4(sc->iot, sc->ioh, SDI_INT_MASK); + bus_space_write_4(sc->iot, sc->ioh, SDI_INT_MASK, v & ~i ); +} + + void +sssdi_clear_intr(struct sssdi_softc *sc) +{ + bus_space_write_4(sc->iot, sc->ioh, SDI_INT_MASK, 0x0); +} + +static int +sssdi_wait_intr(struct sssdi_softc *sc, uint32_t mask, int timeout) +{ + uint32_t status; + + /* Wait until the command has been sent */ + mutex_enter(&sc->intr_mtx); + sssdi_enable_intr(sc, mask); + status = sc->intr_status & mask; + while(status == 0) { + + if (cv_timedwait(&sc->intr_cv, &sc->intr_mtx, timeout) == + EWOULDBLOCK ) { + DPRINTF(("Timed out waiting for interrupt from SDI controller\n")); + status |= SDI_CMD_TIMEOUT; + break; + } + + status = sc->intr_status & mask; + } + + sc->intr_status &= ~status; + mutex_exit(&sc->intr_mtx); + + return status; +} Index: arch/arm/s3c2xx0/s3c2440reg.h =================================================================== RCS file: arch/arm/s3c2xx0/s3c2440reg.h diff -N arch/arm/s3c2xx0/s3c2440reg.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/s3c2440reg.h 28 Dec 2009 10:35:35 -0000 @@ -0,0 +1,435 @@ +/* $NetBSD: $ */ + +/* + * 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 S3C2440X processor is ARM920T based integrated CPU + * + * Reference: + * S3C2440X User's Manual + */ +#ifndef _ARM_S3C2XX0_S3C2440REG_H_ +#define _ARM_S3C2XX0_S3C2440REG_H_ + +/* common definitions for S3C2800, S3C2400 and S3C2410 */ +#include +/* common definitions for S3C2400 and S3C2410 */ +#include + +/* + * Memory Map + */ +#define S3C2440_BANK_SIZE 0x08000000 +#define S3C2440_BANK_START(n) (S3C2440_BANK_SIZE*(n)) +#define S3C2440_SDRAM_START S3C2440_BANK_START(6) + +/* + * Physical address of integrated peripherals + */ +#define S3C2440_MEMCTL_BASE 0x48000000 /* memory controller */ +#define S3C2440_USBHC_BASE 0x49000000 /* USB Host controller */ +#define S3C2440_INTCTL_BASE 0x4a000000 /* Interrupt controller */ +#define S3C2440_DMAC_BASE 0x4b000000 +#define S3C2440_DMAC_SIZE 0xe4 +#define S3C2440_CLKMAN_BASE 0x4c000000 /* clock & power management */ +#define S3C2440_LCDC_BASE 0x4d000000 /* LCD controller */ +#define S3C2440_NANDFC_BASE 0x4e000000 /* NAND Flash controller */ +#define S3C2440_NANDFC_SIZE 0x18 +#define S3C2440_UART0_BASE 0x50000000 +#define S3C2440_UART_BASE(n) (S3C2440_UART0_BASE+0x4000*(n)) +#define S3C2440_TIMER_BASE 0x51000000 +#define S3C2440_USBDC_BASE 0x5200140 +#define S3C2440_USBDC_SIZE 0x130 +#define S3C2440_WDT_BASE 0x53000000 +#define S3C2440_IIC_BASE 0x54000000 +#define S3C2440_IIS_BASE 0x55000000 +#define S3C2440_GPIO_BASE 0x56000000 +#define S3C2440_GPIO_SIZE 0xd0 +#define S3C2440_ADC_BASE 0x58000000 +#define S3C2440_ADC_SIZE 0x18 +#define S3C2440_SPI0_BASE 0x59000000 +#define S3C2440_SPI1_BASE 0x59000020 +#define S3C2440_SDI_BASE 0x5a000000 /* SD Interface */ +#define S3C2440_SDI_SIZE 0x44 + +/* interrupt control (additional defs for 2440) */ +#define ICU_LEN (32+11) + +#define INTCTL_SUBSRCPND 0x18 /* sub source pending (2410+2440 only) */ +#define INTCTL_INTSUBMSK 0x1c /* sub mask (2410+2440 only) */ + +/* 2440 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 S3C2440_SUBIRQ_MIN 32 +#define S3C2440_SUBIRQ_MAX (32+10) + +/* cascaded to INT_ADCTC */ +#define S3C2440_INT_ADC (S3C2440_SUBIRQ_MIN+10) /* AD converter */ +#define S3C2440_INT_TC (S3C2440_SUBIRQ_MIN+9) /* Touch screen */ +/* cascaded to INT_UART2 */ +#define S3C2440_INT_ERR2 (S3C2440_SUBIRQ_MIN+8) /* UART2 Error interrupt */ +#define S3C2440_INT_TXD2 (S3C2440_SUBIRQ_MIN+7) /* UART2 Tx interrupt */ +#define S3C2440_INT_RXD2 (S3C2440_SUBIRQ_MIN+6) /* UART2 Rx interrupt */ +/* cascaded to INT_UART1 */ +#define S3C2440_INT_ERR1 (S3C2440_SUBIRQ_MIN+5) /* UART1 Error interrupt */ +#define S3C2440_INT_TXD1 (S3C2440_SUBIRQ_MIN+4) /* UART1 Tx interrupt */ +#define S3C2440_INT_RXD1 (S3C2440_SUBIRQ_MIN+3) /* UART1 Rx interrupt */ +/* cascaded to INT_UART0 */ +#define S3C2440_INT_ERR0 (S3C2440_SUBIRQ_MIN+2) /* UART0 Error interrupt */ +#define S3C2440_INT_TXD0 (S3C2440_SUBIRQ_MIN+1) /* UART0 Tx interrupt */ +#define S3C2440_INT_RXD0 (S3C2440_SUBIRQ_MIN+0) /* UART0 Rx interrupt */ + +#define S3C2440_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_MASK 0x6 +#define CLKDIVN_HDIVN_SHIFT 1 +#define CLKDIVN_PDIVN (1<<0) /* pclk=hclk/2 */ +#define CLKMAN_CAMDIVN 0x18 +#define CLKCAMDIVN_HCLK4_HALF (1<<8) /* Modifies HDIVN division rate if CLKDIVN[2:1] == 10b*/ +#define CLKCAMDIVN_HCLK3_HALF (1<<9) /* Modifies HDIVN division rate if CLKDIVN[2:1] == 11b*/ + +/* NAND Flash controller */ +#define NANDFC_NFCONF 0x00 /* Configuration */ +#define NANDFC_NFCMD 0x08 /* command */ +#define NANDFC_NFADDR 0x0C /* address */ +#define NANDFC_NFDATA 0x10 /* data */ +#define NANDFC_NFSTAT 0x20 /* operation status */ +#define NANDFC_NFECC 0x34 /* 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 + +/* UART */ +#undef UFCON_TXTRIGGER_0 +#undef UFCON_TXTRIGGER_4 +#undef UFCON_TXTRIGGER_8 +#undef UFCON_TXTRIGGER_16 +#undef UFCON_RXTRIGGER_4 +#undef UFCON_RXTRIGGER_8 +#undef UFCON_RXTRIGGER_12 +#undef UFCON_RXTRIGGER_16 +#define UFCON_TXTRIGGER_0 (0<<6) +#define UFCON_TXTRIGGER_16 (1<<6) +#define UFCON_TXTRIGGER_32 (2<<6) +#define UFCON_TXTRIGGER_48 (3<<6) +#define UFCON_RXTRIGGER_1 (0<<4) +#define UFCON_RXTRIGGER_8 (1<<4) +#define UFCON_RXTRIGGER_16 (2<<4) +#define UFCON_RXTRIGGER_32 (3<<4) +#undef UFSTAT_TXFULL +#define UFSTAT_TXFULL (1<<14) /* Tx fifo full */ +#undef UFSTAT_RXFULL +#define UFSTAT_RXFULL (1<<6) /* Rx fifo full */ +#undef UFSTAT_TXCOUNT_SHIFT +#undef UFSTAT_TXCOUNT +#define UFSTAT_TXCOUNT_SHIFT 8 +#define UFSTAT_TXCOUNT (0x3f<> SDIDATCNT_BLK_NUM_CNT_SHIFT) +#define SDI_DAT_STA 0x34 +#define SDIDATSTA_RX (1 << 0) +#define SDIDATSTA_TX (1 << 1) +#define SDIDATSTA_BUSY_FIN (1 << 3) +#define SDIDATSTA_DATA_FIN (1 << 4) +#define SDIDATSTA_DATA_TIMEOUT (1 << 5) +#define SDIDATSTA_CRC_DAT_FAIL (1 << 6) +#define SDIDATSTA_CRC_STATUS_FAIL (1 << 7) +#define SDIDATSTA_SDIO_INT (1 << 9) +#define SDIDATSTA_RWAIT_REQ (1 << 10) +#define SDIDATSTA_NO_BUSY (1 << 11) +#define SDI_DAT_FSTA 0x38 +#define SDIDATFSTA_FFCNT_MASK 0x7F +#define SDIDATFSTA_FFCNT(reg) (reg & SDIDATFSTA_FFCNT_MASK) +#define SDIDATFSTA_RF_HALF (1 << 7) +#define SDIDATFSTA_RF_FULL (1 << 8) +#define SDIDATFSTA_RF_LAST (1 << 9) +#define SDIDATFSTA_TF_EMPTY (1 << 10) +#define SDIDATFSTA_TF_HALF (1 << 11) +#define SDIDATFSTA_RF_DETECT (1 << 12) +#define SDIDATFSTA_TX_DETECT (1 << 13) +#define SDIDATFSTA_FAIL_NO_DETECT (0 << 14) +#define SDIDATFSTA_FAIL_FIFO (1 << 14) +#define SDIDATFSTA_FAIL_FIFO_LAST (2 << 14) +#define SDIDATFSTA_RESET (1 << 16) +#define SDI_INT_MASK 0x3C +#define SDIINTMASK_RF_HALF (1<<0) +#define SDIINTMASK_RF_FULL (1<<1) +#define SDIINTMASK_RF_LAST (1<<2) +#define SDIINTMASK_TF_EMPTY (1<<3) +#define SDIINTMASK_TF_HALF (1<<4) +#define SDIINTMASK_BUSY_FIN (1<<6) +#define SDIINTMASK_DATA_FIN (1<<7) +#define SDIINTMASK_DATA_TIMEOUT (1<<8) +#define SDIINTMASK_DATA_CRC (1<<9) +#define SDIINTMASK_STATUS_CRC (1<<10) +#define SDIINTMASK_FIFO_FAIL (1<<11) +#define SDIINTMASK_IO (1<<12) +#define SDIINTMASK_READ_WAIT (1<<13) +#define SDIINTMASK_RESP (1<<14) +#define SDIINTMASK_CMD_TIMEOUT (1<<15) +#define SDIINTMASK_CMD_SENT (1<<16) +#define SDIINTMASK_RESP_CRC (1<<17) +#define SDIINTMASK_NO_BUSY (1<<18) +#define SDI_DAT_LI_W 0x40 /* Word access in Little Endian mode */ +#define SDI_DAT_LI_HW 0x44 /* Half-Word access in Little Endian mode */ +#define SDI_DAT_LI_B 0x48 /* Byte access in Little Endian mode */ +#define SDI_DAT_BI_W 0x4C /* Word access in Big Endian mode */ +#define SDI_DAT_BI_HW 0x41 /* Half-Word access in Big Endian mode */ +#define SDI_DAT_BI_B 0x43 /* Byte access in Big Endian mode */ + +/* 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< + +int s3c2440_sscom_cnattach(bus_space_tag_t, int, int, int, tcflag_t); +int s3c2440_sscom_kgdb_attach(bus_space_tag_t, int, int, int, tcflag_t); +void s3c2440_intr_init(struct s3c24x0_softc *); +void s3c2440_softreset(void); + +void s3c2440_mask_subinterrupts(int); +void s3c2440_unmask_subinterrupts(int); + +void *s3c2440_extint_establish(int, int, int, int (*)(void *), void *); +void s3c2440_setup_extint(int, int); +#endif /* _ARM_S3C2410VAR_H_ */ Index: arch/arm/s3c2xx0/s3c24x0_clk.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/s3c2xx0/s3c24x0_clk.c,v retrieving revision 1.10 diff -u -r1.10 s3c24x0_clk.c --- arch/arm/s3c2xx0/s3c24x0_clk.c 4 Jul 2008 11:59:45 -0000 1.10 +++ arch/arm/s3c2xx0/s3c24x0_clk.c 28 Dec 2009 10:35:35 -0000 @@ -205,6 +205,14 @@ return 1; } +static int +statintr(void *arg) +{ + statclock((struct clockframe *)arg); + + return 1; +} + void cpu_initclocks(void) { @@ -252,12 +260,10 @@ bus_space_write_4(iot, ioh, TIMER_TCNTB(3), ((prescaler - 1) << 16) | (time_constant(stathz) - 1)); - s3c24x0_intr_establish(S3C24X0_INT_TIMER4, IPL_CLOCK, + s3c24x0_intr_establish(S3C24X0_INT_TIMER4, IPL_CLOCK, IST_NONE, hardintr, 0); -#ifdef IPL_STATCLOCK - s3c24x0_intr_establish(S3C24X0_INT_TIMER3, IPL_STATCLOCK, + s3c24x0_intr_establish(S3C24X0_INT_TIMER3, IPL_HIGH, IST_NONE, statintr, 0); -#endif /* set prescaler1 */ reg = bus_space_read_4(iot, ioh, TIMER_TCFG0); Index: arch/arm/s3c2xx0/s3c24x0reg.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/s3c2xx0/s3c24x0reg.h,v retrieving revision 1.8 diff -u -r1.8 s3c24x0reg.h --- arch/arm/s3c2xx0/s3c24x0reg.h 11 Dec 2005 12:16:51 -0000 1.8 +++ arch/arm/s3c2xx0/s3c24x0reg.h 28 Dec 2009 10:35:35 -0000 @@ -109,12 +109,14 @@ #define S3C2410_INT_SPI1 29 /* SPI 1 (2410 only) */ #define S3C2400_INT_UTXD0 28 /* UART0 Tx INT (2400 only) */ #define S3C2410_INT_UART0 28 /* UART0 (2410 only) */ +#define S3C2440_INT_UART0 28 /* UART0 (2440 only) */ #define S3C24X0_INT_IIC 27 #define S3C24X0_INT_USBH 26 /* USB Host */ #define S3C24X0_INT_USBD 25 /* USB Device */ #define S3C2400_INT_URXD1 24 /* UART1 Rx INT (2400 only) */ #define S3C2400_INT_URXD0 23 /* UART0 Rx INT (2400 only) */ #define S3C2410_INT_UART1 23 /* UART0 (2410 only) */ +#define S3C2440_INT_UART1 23 /* UART0 (2440 only) */ #define S3C24X0_INT_SPI0 22 /* SPI 0 */ #define S3C2400_INT_MMC 21 #define S3C2410_INT_SDI 21 @@ -126,6 +128,7 @@ #define S3C2400_INT_UERR 15 /* UART 0/1 Error int (2400) */ #define S3C2410_INT_UART2 15 /* UART2 int (2410) */ +#define S3C2440_INT_UART2 15 /* UART2 int (2440) */ #define S3C24X0_INT_TIMER4 14 #define S3C24X0_INT_TIMER3 13 #define S3C24X0_INT_TIMER2 12 @@ -136,7 +139,9 @@ #define S3C24X0_INT_TICK 8 #define S3C2410_INT_BFLT 7 /* Battery fault */ #define S3C2410_INT_8_23 5 /* Ext int 8..23 */ +#define S3C2440_INT_8_23 5 /* EXT int 8..23 */ #define S3C2410_INT_4_7 4 /* Ext int 4..7 */ +#define S3C2440_INT_4_7 4 /* Ext int 4..7 */ #define S3C24X0_INT_EXT(n) (n) /* External interrupt [7:0] for 2400, * [3:0] for 2410 */ /* DMA controller */ Index: arch/arm/s3c2xx0/s3c2xx0var.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/s3c2xx0/s3c2xx0var.h,v retrieving revision 1.4 diff -u -r1.4 s3c2xx0var.h --- arch/arm/s3c2xx0/s3c2xx0var.h 11 Dec 2005 12:16:51 -0000 1.4 +++ arch/arm/s3c2xx0/s3c2xx0var.h 28 Dec 2009 10:35:36 -0000 @@ -47,6 +47,7 @@ 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_space_handle_t sc_dmach; /* DMA Controller */ bus_dma_tag_t sc_dmat; Index: arch/arm/s3c2xx0/sscom.c =================================================================== RCS file: /cvsroot/src/sys/arch/arm/s3c2xx0/sscom.c,v retrieving revision 1.29 diff -u -r1.29 sscom.c --- arch/arm/s3c2xx0/sscom.c 11 Jun 2008 22:37:21 -0000 1.29 +++ arch/arm/s3c2xx0/sscom.c 28 Dec 2009 10:35:37 -0000 @@ -146,7 +146,7 @@ #include #include -#if defined(SSCOM_S3C2410) || defined(SSCOM_S3C2400) +#if defined(SSCOM_S3C2410) || defined(SSCOM_S3C2400) || defined(SSCOM_S3C2440) #include #elif defined(SSCOM_S3C2800) #include @@ -445,7 +445,11 @@ } bus_space_write_1(iot, ioh, SSCOM_UFCON, +#ifdef SSCOM_S3C2440 + UFCON_TXTRIGGER_16|UFCON_RXTRIGGER_16|UFCON_FIFO_ENABLE| +#else UFCON_TXTRIGGER_8|UFCON_RXTRIGGER_8|UFCON_FIFO_ENABLE| +#endif /* S3C2440 */ UFCON_TXFIFO_RESET|UFCON_RXFIFO_RESET); bus_space_write_1(iot, ioh, SSCOM_UCON, sc->sc_ucon); @@ -1824,7 +1828,11 @@ bus_space_write_2(iot, ioh, SSCOM_UCON, 0); bus_space_write_1(iot, ioh, SSCOM_UFCON, +#ifdef SSCOM_S3C2440 + UFCON_TXTRIGGER_16 | UFCON_RXTRIGGER_16 | +#else UFCON_TXTRIGGER_8 | UFCON_RXTRIGGER_8 | +#endif /* S3C2440 */ UFCON_TXFIFO_RESET | UFCON_RXFIFO_RESET | UFCON_FIFO_ENABLE ); /* tx/rx fifo reset are auto-cleared */ Index: arch/arm/s3c2xx0/sscom_s3c2440.c =================================================================== RCS file: arch/arm/s3c2xx0/sscom_s3c2440.c diff -N arch/arm/s3c2xx0/sscom_s3c2440.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/arm/s3c2xx0/sscom_s3c2440.c 28 Dec 2009 10:35:37 -0000 @@ -0,0 +1,163 @@ +/* $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 +__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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +static int sscom_match(struct device *, struct cfdata *, void *); +static void sscom_attach(struct device *, struct device *, void *); + +CFATTACH_DECL(sscom, sizeof(struct sscom_softc), sscom_match, + sscom_attach, NULL, NULL); + +const struct sscom_uart_info s3c2440_uart_config[] = { + /* UART 0 */ + { + 0, + S3C2440_INT_TXD0, + S3C2440_INT_RXD0, + S3C2440_INT_ERR0, + S3C2440_UART_BASE(0), + }, + /* UART 1 */ + { + 1, + S3C2440_INT_TXD1, + S3C2440_INT_RXD1, + S3C2440_INT_ERR1, + S3C2440_UART_BASE(1), + }, + /* UART 2 */ + { + 2, + S3C2440_INT_TXD2, + S3C2440_INT_RXD2, + S3C2440_INT_ERR2, + S3C2440_UART_BASE(2), + }, +}; + +static int +sscom_match(struct device *parent, struct cfdata *cf, void *aux) +{ + struct s3c2xx0_attach_args *sa = aux; + int unit = sa->sa_index; + + return unit == 0 || unit == 1; +} + +static 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 = s3c2440_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 = s3c2440_uart_config[sa->sa_index].rx_int; + sc->sc_tx_irqno = s3c2440_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(s3c2440_uart_config[unit].tx_int, + IPL_SERIAL, IST_LEVEL, sscomtxintr, sc); + s3c24x0_intr_establish(s3c2440_uart_config[unit].rx_int, + IPL_SERIAL, IST_LEVEL, sscomrxintr, sc); + s3c24x0_intr_establish(s3c2440_uart_config[unit].err_int, + IPL_SERIAL, IST_LEVEL, sscomrxintr, sc); + sscom_disable_txrxint(sc); + + sscom_attach_subr(sc); +} + + + +int +s3c2440_sscom_cnattach(bus_space_tag_t iot, int unit, int rate, + int frequency, tcflag_t cflag) +{ + return sscom_cnattach(iot, s3c2440_uart_config + unit, + rate, frequency, cflag); +} + +#ifdef KGDB +int +s3c2440_sscom_kgdb_attach(bus_space_tag_t iot, int unit, int rate, + int frequency, tcflag_t cflag) +{ + return sscom_kgdb_attach(iot, s3c2440_uart_config + unit, + rate, frequency, cflag); +} +#endif /* KGDB */ Index: arch/arm/s3c2xx0/sscom_var.h =================================================================== RCS file: /cvsroot/src/sys/arch/arm/s3c2xx0/sscom_var.h,v retrieving revision 1.7 diff -u -r1.7 sscom_var.h --- arch/arm/s3c2xx0/sscom_var.h 6 Mar 2006 20:21:25 -0000 1.7 +++ arch/arm/s3c2xx0/sscom_var.h 28 Dec 2009 10:35:37 -0000 @@ -80,6 +80,9 @@ #ifdef SSCOM_S3C2410 #include #include +#elif defined(SSCOM_S3C2440) +#include +#include #endif /* Hardware flag masks */ @@ -223,6 +226,25 @@ s3c2410_mask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno) | \ _sscom_intbit((sc)->sc_rx_irqno)) +#elif defined(SSCOM_S3C2440) +/* RXINTn, TXINTn and ERRn interrupts are cascaded to UARTn irq. */ + +#define _sscom_intbit(irqno) (1<<((irqno)-S3C2440_SUBIRQ_MIN)) + +#define sscom_unmask_rxint(sc) \ + s3c2440_unmask_subinterrupts(_sscom_intbit((sc)->sc_rx_irqno)) +#define sscom_mask_rxint(sc) \ + s3c2440_mask_subinterrupts(_sscom_intbit((sc)->sc_rx_irqno)) +#define sscom_unmask_txint(sc) \ + s3c2440_unmask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno)) +#define sscom_mask_txint(sc) \ + s3c2440_mask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno)) +#define sscom_unmask_txrxint(sc) \ + s3c2440_unmask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno) | \ + _sscom_intbit((sc)->sc_rx_irqno)) +#define sscom_mask_txrxint(sc) \ + s3c2440_mask_subinterrupts(_sscom_intbit((sc)->sc_tx_irqno) | \ + _sscom_intbit((sc)->sc_rx_irqno)) #else /* for S3C2800 and S3C2400 */ Index: arch/evbarm/conf/MINI2440 =================================================================== RCS file: arch/evbarm/conf/MINI2440 diff -N arch/evbarm/conf/MINI2440 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/conf/MINI2440 28 Dec 2009 10:35:38 -0000 @@ -0,0 +1,13 @@ +# $NetBSD:$ +# +# MINI2440 -- Friendly ARM evaluation board based on Samsung S3C2440 +# +include "arch/evbarm/conf/MINI2440_BASE" + +options MEMORY_DISK_HOOKS +#options MEMORY_DISK_DYNAMIC +#options MEMORY_DISK_IS_ROOT # force root on memory disk +#options MEMORY_DISK_SERVER=1 # no userspace memory disk support +#options MEMORY_DISK_ROOT_SIZE=4096 # size of memory disk, in blocks +#options MEMORY_DISK_ROOT_SIZE=2880 # 1.44M, same as a floppy +config netbsd root on ld0b type ? Index: arch/evbarm/conf/MINI2440_BASE =================================================================== RCS file: arch/evbarm/conf/MINI2440_BASE diff -N arch/evbarm/conf/MINI2440_BASE --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/conf/MINI2440_BASE 28 Dec 2009 10:35:38 -0000 @@ -0,0 +1,387 @@ +# $NetBSD:$ +# +# MINI2440 -- Friendly ARM evaluation board based on Samsung S3C2440 +# + +include "arch/evbarm/conf/std.mini2440" + +#options LOCKDEBUG +#options SYMTAB_SPACE=450000 +#makeoptions DEBUG="-g3" # compile full symbol table +#makeoptions PROF="-pg" +#options GPROF + +#options DEBUG_DMA +#options SSSDI_DEBUG +#options SDMMC_DEBUG +#options SDMMC_DUMP_CSD +#options MSDOSFS_DEBUG + +#options INCLUDE_CONFIG_FILE # embed config file in kernel binary + +# Enable the hooks used for initializing the root memory-disk. +#options MEMORY_DISK_HOOKS +#options MEMORY_DISK_DYNAMIC +#options MEMORY_DISK_IS_ROOT # force root on memory disk +#options MEMORY_DISK_SERVER=1 # no userspace memory disk support +#options MEMORY_DISK_ROOT_SIZE=4096 # size of memory disk, in blocks +#options MEMORY_DISK_ROOT_SIZE=2880 # 1.44M, same as a floppy + + +# estimated number of users + +maxusers 2 + +# Standard system options + +options RTC_OFFSET=0 # hardware clock is this many mins. west of GMT +options NTP # NTP phase/frequency locked loop + +# CPU options + +options CPU_ARM9 # Support the ARM9TDMI core +makeoptions CPUFLAGS="-march=armv4" +#options ARM9_CACHE_WRITE_THROUGH + +# Architecture options + +options S3C2XX0_XTAL_CLK=12000000 # 12MHz Xtal + +# File systems + +file-system FFS # UFS +file-system LFS # log-structured file system +file-system MFS # memory file system +file-system NFS # Network file system +#file-system ADOSFS # AmigaDOS-compatible file system +file-system EXT2FS # second extended file system (linux) +file-system CD9660 # ISO 9660 + Rock Ridge file system +file-system MSDOSFS # MS-DOS file system +#file-system FDESC # /dev/fd +file-system KERNFS # /kern +#file-system NULLFS # loopback file system +#file-system PORTAL # portal filesystem (still experimental) +file-system PROCFS # /proc +#file-system UMAPFS # NULLFS + uid and gid remapping +#file-system UNION # union file system +file-system PTYFS # /dev/pts/N support + +# File system options +#options QUOTA # UFS quotas +#options FFS_EI # FFS Endian Independant support +#options NFSSERVER +options SOFTDEP +options WAPBL # File system journaling support - Experimental +#options FFS_NO_SNAPSHOT # No FFS snapshot support + +# Networking options + +options GATEWAY # packet forwarding +options INET # IP + ICMP + TCP + UDP +options INET6 # IPV6 +#options IPSEC # IP security +#options IPSEC_ESP # IP security (encryption part; define w/ IPSEC) +#options IPSEC_NAT_T # IPsec NAT traversal (NAT-T) +#options IPSEC_DEBUG # debug for IP security +#options MROUTING # IP multicast routing +#options PIM # Protocol Independent Multicast +#options ISO,TPIP # OSI +#options EON # OSI tunneling over IP +#options NETATALK # AppleTalk networking +#options PFIL_HOOKS # pfil(9) packet filter hooks +#options PPP_BSDCOMP # BSD-Compress compression support for PPP +#options PPP_DEFLATE # Deflate compression support for PPP +#options PPP_FILTER # Active filter support for PPP (requires bpf) +#options TCP_DEBUG # Record last TCP_NDEBUG packets with SO_DEBUG + +# These options enable verbose messages for several subsystems. +# Warning, these may compile large string tables into the kernel! +#options MIIVERBOSE # verbose PHY autoconfig messages +#options PCMCIAVERBOSE # verbose PCMCIA configuration messages +#options SCSIVERBOSE # human readable SCSI error messages +options USBVERBOSE # verbose USB device autoconfig messages + +options NFS_BOOT_BOOTP +options NFS_BOOT_DHCP +options NFS_BOOT_BOOTPARAM + + +# Compatibility options + +#options COMPAT_43 # 4.3BSD compatibility. +options COMPAT_40 # NetBSD 4.0 compatibility. +options COMPAT_30 # NetBSD 3.0 compatibility. +options COMPAT_20 # NetBSD 2.0 compatibility. +options COMPAT_16 # NetBSD 1.6 compatibility. +#options COMPAT_15 # NetBSD 1.5 compatibility. +#options COMPAT_14 # NetBSD 1.4 compatibility. +#options COMPAT_13 # NetBSD 1.3 compatibility. +#options COMPAT_12 # NetBSD 1.2 compatibility. +#options COMPAT_11 # NetBSD 1.1 compatibility. +#options COMPAT_10 # NetBSD 1.0 compatibility. +#options COMPAT_09 # NetBSD 0.9 compatibility. +#options TCP_COMPAT_42 # 4.2BSD TCP/IP bug compat. Not recommended. +options COMPAT_BSDPTY # /dev/[pt]ty?? ptys. + +# Shared memory options + +options SYSVMSG # System V-like message queues +options SYSVSEM # System V-like semaphores +#options SEMMNI=10 # number of semaphore identifiers +#options SEMMNS=60 # number of semaphores in system +#options SEMUME=10 # max number of undo entries per process +#options SEMMNU=30 # number of undo structures in system +options SYSVSHM # System V-like memory sharing +#options SHMMAXPGS=1024 # 1024 pages is the default + +# Miscellaneous kernel options +options KTRACE # system call tracing, a la ktrace(1) +options IRQSTATS # manage IRQ statistics +#options LKM # loadable kernel modules +options KMEMSTATS # kernel memory statistics +options SCSIVERBOSE # Verbose SCSI errors +options PCIVERBOSE # Verbose PCI descriptions +options MIIVERBOSE # Verbose MII autoconfuration messages +#options PCI_CONFIG_DUMP # verbosely dump PCI config space +options PCI_NETBSD_CONFIGURE # Do not rely on BIOS/whatever to + # configure PCI devices +#options PCI_CONFIGURE_VERBOSE # Show PCI config information +#options PCI_DEBUG +options DDB_KEYCODE=0x1d # Enter ddb on ^] +options USERCONF # userconf(4) support +#options PIPE_SOCKETPAIR # smaller, but slower pipe(2) +#options SYSCTL_INCLUDE_DESCR # Include sysctl descriptions in kernel + +# Development and Debugging options + +#options ARM700BUGTRACK # track the ARM700 swi bug +#options PORTMASTER # Enable PortMaster only options +options DIAGNOSTIC # internal consistency checks +#options PMAP_DEBUG # Enable pmap_debug_level code +options UVMHIST +options VERBOSE_INIT_ARM # verbose bootstraping messages +#options KGDB +#options DEBUG_KGDB +options DDB # in-kernel debugger +options DDB_HISTORY_SIZE=100 # Enable history editing in DDB +#makeoptions DEBUG="-g3" # compile full symbol table + +#config netbsd root on md0a type ? + +# The main bus device +mainbus0 at root + +# The boot CPU +cpu0 at mainbus? + +# Core logic on Samsung S3C2440 +ssio0 at mainbus? +ssextio0 at ssio0 + +# integrated UART +sscom0 at ssio? index 0 +sscom1 at ssio? index 1 +#sscom2 at ssio? index 2 +options SSCOM0CONSOLE +options SSCOM1CONSOLE +options CONSPEED=115200 +#options KGDB_DEVNAME="\"sscom1\"" # sscom0 or sscom1 +#options KGDB_DEVRATE=115200 + +# LCD +#device-major lcd char 145 +#lcd0 at ssio? +#wsdisplay* at lcd? console ? +options WSEMUL_VT100 # VT100 / VT220 emulation +#options FONT_VT220L8x16 +#options FONT_VT220L8x10 +#options LCD_DEBUG + +sssdi0 at ssio? +sdmmc* at sssdi0 +ld* at sdmmc? + +# SPI port +#ssspi0 at ssio? index 0 +#ssspi1 at ssio? index 1 + +# on-board keyboard controller (Semtech SPICoder-SA01) via SPI1 +#sskbd0 at ssspi1 intr 1 +#wskbd* at sskbd? # console ? + +# SCSI bus support +#scsibus* at scsi? + +# SCSI devices +#sd* at scsibus? target ? lun ? # SCSI disk drives +#st* at scsibus? target ? lun ? # SCSI tape drives +#cd* at scsibus? target ? lun ? # SCSI CD-ROM drives +#ch* at scsibus? target ? lun ? # SCSI autochangers +#ses* at scsibus? target ? lun ? # SCSI Enclosure Services devices +#ss* at scsibus? target ? lun ? # SCSI scanners +#uk* at scsibus? target ? lun ? # SCSI unknown + +# ATAPI bus support +#atapibus* at atapi? + +# ATAPI devices +# flags have the same meaning as for IDE drives. +#cd* at atapibus? drive ? flags 0x0000 # ATAPI CD-ROM drives +#sd* at atapibus? drive ? flags 0x0000 # ATAPI disk drives +#st* at atapibus? drive ? flags 0x0000 # ATAPI tape drives +#uk* at atapibus? drive ? flags 0x0000 # ATAPI unknown + +# MIDI support +#midi* at midibus? +# midi* at pcppi? # MIDI interface to the PC speaker + +# Audio support +#audio* at audiobus? + +dm9000nic* at ssextio? intr 7 addr 0x20000300 + +options MINI2440_ETHER_ADDR_FIXED="0,0x0a,0xb1,0,1,0xff" + +# built-in OHCI USB controller +#ohci0 at ssio? addr 0x49000000 intr 26 +#options OHCI_DEBUG +# +#usb* at ohci0 + +# USB Hubs +#uhub* at usb? +#uhub* at uhub? port ? + +# USB HID device +#uhidev* at uhub? port ? configuration ? interface ? + +# USB Mice +#ums* at uhidev? reportid ? +#wsmouse* at ums? mux 0 + +# USB Keyboards +#ukbd* at uhidev? reportid ? +#wskbd* at ukbd? console ? mux 1 + +# USB serial adapter +#ucycom* at uhidev? reportid ? + +# USB Generic HID devices +#uhid* at uhidev? reportid ? + +# USB Printer +#ulpt* at uhub? port ? configuration ? interface ? + +# USB Modem +#umodem* at uhub? port ? configuration ? +#ucom* at umodem? + +# USB Mass Storage +#umass* at uhub? port ? configuration ? interface ? +#wd* at umass? + +# USB audio +#uaudio* at uhub? port ? configuration ? + +# USB MIDI +#umidi* at uhub? port ? configuration ? + +# USB IrDA +# USB-IrDA bridge spec +#uirda* at uhub? port ? configuration ? interface ? +#irframe* at uirda? + +# SigmaTel STIr4200 USB/IrDA Bridge +#ustir* at uhub? port ? +#irframe* at ustir? + +# USB Ethernet adapters +#aue* at uhub? port ? # ADMtek AN986 Pegasus based adapters +#axe* at uhub? port ? # ASIX AX88172 based adapters +#cue* at uhub? port ? # CATC USB-EL1201A based adapters +#kue* at uhub? port ? # Kawasaki LSI KL5KUSB101B based adapters +#url* at uhub? port ? # Realtek RTL8150L based adapters + +# Prolific PL2301/PL2302 host-to-host adapter +#upl* at uhub? port ? + +# Serial adapters +#ubsa* at uhub? port ? # Belkin serial adapter +#ucom* at ubsa? portno ? +# +#uftdi* at uhub? port ? # FTDI FT8U100AX serial adapter +#ucom* at uftdi? portno ? +# +#umct* at uhub? port ? # MCT USB-RS232 serial adapter +#ucom* at umct? portno ? +# +#uplcom* at uhub? port ? # I/O DATA USB-RSAQ2 serial adapter +#ucom* at uplcom? portno ? +# +#uvscom* at uhub? port ? # SUNTAC Slipper U VS-10U serial adapter +#ucom* at uvscom? portno ? + +# Diamond Multimedia Rio 500 +#urio* at uhub? port ? + +# USB Handspring Visor +#uvisor* at uhub? port ? +#ucom* at uvisor? + +# Kyocera AIR-EDGE PHONE +#ukyopon* at uhub? port ? +#ucom* at ukyopon? portno ? + +# USB scanners +#uscanner* at uhub? port ? + +# USB scanners that use SCSI emulation, e.g., HP5300 +#usscanner* at uhub? port ? + +# Y@P firmware loader +#uyap* at uhub? port ? + +# D-Link DSB-R100 USB radio +#udsbr* at uhub? port ? +#radio* at udsbr? + +# USB Generic driver +#ugen* at uhub? port ? + +# Pseudo-Devices + +# disk/mass storage pseudo-devices +pseudo-device md 1 # memory disk device (ramdisk) +pseudo-device vnd # disk-like interface to files +#pseudo-device fss 4 # file system snapshot device + +# network pseudo-devices +#pseudo-device bpfilter # Berkeley packet filter +pseudo-device ipfilter # IP filter (firewall) and NAT +pseudo-device loop # network loopback +#pseudo-device ppp # Point-to-Point Protocol +#pseudo-device pppoe # PPP over Ethernet (RFC 2516) +#pseudo-device sl # Serial Line IP +#pseudo-device strip # Starmode Radio IP (Metricom) +#pseudo-device irframetty # IrDA frame line discipline +#pseudo-device tun # network tunneling over tty +#pseudo-device tap # virtual Ethernet +#pseudo-device gre # generic L3 over IP tunnel +#pseudo-device gif # IPv[46] over IPv[46] tunnel (RFC1933) +#pseudo-device faith # IPv[46] tcp relay translation i/f +#pseudo-device stf # 6to4 IPv6 over IPv4 encapsulation +#pseudo-device vlan # IEEE 802.1q encapsulation +#pseudo-device bridge # simple inter-network bridging +#options BRIDGE_IPF # bridge uses IP/IPv6 pfil hooks too + +# miscellaneous pseudo-devices +pseudo-device pty # pseudo-terminals +pseudo-device rnd # /dev/random and in-kernel generator +pseudo-device clockctl # user control of clock subsystem + +# wscons pseudo-devices +#pseudo-device wsmux # mouse & keyboard multiplexor +#pseudo-device wsfont + +#pseudo-device ksyms # /dev/ksyms + Index: arch/evbarm/conf/MINI2440_NFSROOT =================================================================== RCS file: arch/evbarm/conf/MINI2440_NFSROOT diff -N arch/evbarm/conf/MINI2440_NFSROOT --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/conf/MINI2440_NFSROOT 28 Dec 2009 10:35:38 -0000 @@ -0,0 +1,20 @@ +# $NetBSD:$ +# +# MINI2440 -- Friendly ARM evaluation board based on Samsung S3C2440 +# +include "arch/evbarm/conf/MINI2440_BASE" + +options MEMORY_DISK_HOOKS +options MEMORY_DISK_DYNAMIC +options MEMORY_DISK_IS_ROOT # force root on memory disk +options MEMORY_DISK_SERVER=1 # no userspace memory disk support + + +options NFS_BOOT_BOOTSTATIC +options NFS_BOOTSTATIC_MYIP="\"10.0.0.111\"" +options NFS_BOOTSTATIC_GWIP="\"10.0.0.1\"" +options NFS_BOOTSTATIC_MASK="\"255.255.255.0\"" +options NFS_BOOTSTATIC_SERVADDR="\"10.0.0.20\"" +options NFS_BOOTSTATIC_SERVER="\"server:/srv/mini2440-netbsd\"" + +config netbsd root on dm9000nic0 type nfs Index: arch/evbarm/conf/files.mini2440 =================================================================== RCS file: arch/evbarm/conf/files.mini2440 diff -N arch/evbarm/conf/files.mini2440 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/conf/files.mini2440 28 Dec 2009 10:35:38 -0000 @@ -0,0 +1,29 @@ +# $NetBSD: files.smdk2410,v 1.5 2005/12/11 12:17:07 christos Exp $ +# +# FriendlyARM MINI2440 board configuration info +# + +include "dev/sdmmc/files.sdmmc" + +# CPU support and integrated peripherals +include "arch/arm/s3c2xx0/files.s3c2440" + +file arch/evbarm/mini2440/mini2440_machdep.c + +# on-board DM9000 +attach dm9000nic at ssextio with dm_ssextio +file arch/evbarm/mini2440/if_dm_mini2440.c dm_ssextio + +# there's no EEPROM hooked to on-board DM9000. +# This is the easiest way to set MAC address. +defparam opt_mini2440.h MINI2440_ETHER_ADDR_FIXED + +# LCD +#attach lcd at ssio with lcd_ssio +#file arch/evbarm/smdk2xx0/smdk2440_lcd.c lcd_ssio + +# on-board Semtech SPICoder (keyboard controller) +# connected to SPI1 +#device sskbd: wskbddev +#attach sskbd at ssspi +#file arch/evbarm/smdk2xx0/smdk2410_kbd.c sskbd Index: arch/evbarm/conf/mk.mini2440 =================================================================== RCS file: arch/evbarm/conf/mk.mini2440 diff -N arch/evbarm/conf/mk.mini2440 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/conf/mk.mini2440 28 Dec 2009 10:35:38 -0000 @@ -0,0 +1,16 @@ +# $NetBSD: mk.smdk2xx0,v 1.3 2005/12/11 12:17:07 christos Exp $ + +SYSTEM_FIRST_OBJ= ${BOARDTYPE}_start.o +SYSTEM_FIRST_SFILE= ${THISARM}/mini2440/${BOARDTYPE}_start.S + +KERNEL_BASE_VIRT=0xc0200000 + +SYSTEM_LD_TAIL_EXTRA+=; \ + echo ${OBJCOPY} -S -O srec $@ $@.srec; \ + ${OBJCOPY} -S -O srec $@ $@.srec; \ + echo ${OBJCOPY} -S -O binary $@ $@.bin; \ + ${OBJCOPY} -O binary $@ $@.bin; +# ${OBJCOPY} -S -O binary $@ $@.bin; + +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.srec@} +EXTRA_KERNELS+= ${KERNELS:@.KERNEL.@${.KERNEL.}.bin@} Index: arch/evbarm/conf/std.mini2440 =================================================================== RCS file: arch/evbarm/conf/std.mini2440 diff -N arch/evbarm/conf/std.mini2440 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/conf/std.mini2440 28 Dec 2009 10:35:38 -0000 @@ -0,0 +1,28 @@ +# $NetBSD: std.smdk2410,v 1.5 2008/06/30 08:18:11 bsh Exp $ +# +# standard NetBSD/evbarm for MINI2440 options + +machine evbarm arm +include "conf/std" # MI standard options +include "arch/arm/conf/std.arm" # arch standard options + +# Config definitions for MINI2440 +include "arch/evbarm/conf/files.mini2440" + +options EXEC_ELF32 +options EXEC_AOUT +options EXEC_SCRIPT + +# To support easy transit to ../arch/arm/arm32 +options ARM32 + +#options ARM32_NEW_VM_LAYOUT # Not yet ready for prime-time + +options SSCOM_S3C2440 + +makeoptions BOARDTYPE="mini2440" +makeoptions BOARDMKFRAG="${THISARM}/conf/mk.mini2440" +makeoptions KERNEL_BASE_PHYS=0x30200000 +options KERNEL_BASE_EXT=0xc0000000 + +options ARM_INTR_IMPL="" Index: arch/evbarm/mini2440/if_dm_mini2440.c =================================================================== RCS file: arch/evbarm/mini2440/if_dm_mini2440.c diff -N arch/evbarm/mini2440/if_dm_mini2440.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/mini2440/if_dm_mini2440.c 28 Dec 2009 10:35:39 -0000 @@ -0,0 +1,200 @@ +/* $NetBSD:$ */ + +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +/* based on sys/arch/evbarm/smdk2xx0/if_cs_smdk24x0.c */ +/* + * 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. + */ + +/* derived from sys/dev/isa/if_cs_isa.c */ +/* + * Copyright 1997 + * Digital Equipment Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and conditions. + * Subject to these conditions, you may download, copy, install, + * use, modify and distribute this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Digital Equipment Corporation. Neither the "Digital Equipment + * Corporation" name nor any trademark or logo of Digital Equipment + * Corporation may be used to endorse or promote products derived + * from this software without the prior written permission of + * Digital Equipment Corporation. + * + * 3) This software is provided "AS-IS" and any express or implied + * warranties, including but not limited to, any implied warranties + * of merchantability, fitness for a particular purpose, or + * non-infringement are disclaimed. In no event shall DIGITAL be + * liable for any damages whatsoever, and in particular, DIGITAL + * shall not be liable for special, indirect, consequential, or + * incidental damages or damages for lost profits, loss of + * revenue or loss of use, whether such damages arise in contract, + * negligence, tort, under statute, in equity, at law or otherwise, + * even if advised of the possibility of such damage. + */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "opt_mini2440.h" + +int dm_ssextio_probe(struct device *, struct cfdata *, void *); +void dm_ssextio_attach(struct device *, struct device *, void *); + +CFATTACH_DECL(dm_ssextio, sizeof(struct dm_softc), + dm_ssextio_probe, dm_ssextio_attach, NULL, NULL); + +int +dm_ssextio_probe(struct device *parent, struct cfdata *cf, void *aux) +{ + struct s3c2xx0_attach_args *sa = aux; + bus_space_tag_t iot = sa->sa_iot; + bus_space_handle_t ioh; + vaddr_t ioaddr; + struct dm_softc sc; /* Used to temporarily access the device for + probing */ + int have_io = 0; + int result = 0; + uint8_t vendorId[2]; + uint8_t productId[2]; + + /* Map memory to access the device during probing */ + ioaddr = sa->sa_addr; + if (bus_space_map(iot, ioaddr, DM9000_IOSIZE, 0, &ioh)) + goto out; + have_io = 1; + + /* Zero the device description */ + memset(&sc, 0, sizeof sc); + sc.sc_iot = iot; + sc.sc_ioh = ioh; + sc.dm_io = 0x0; + sc.dm_data = 0x4; + + vendorId[0] = dm_read(&sc, DM9000_VID0); + vendorId[1] = dm_read(&sc, DM9000_VID1); + + productId[0] = dm_read(&sc, DM9000_PID0); + productId[1] = dm_read(&sc, DM9000_PID1); + + if (vendorId[0] == 0x46 && vendorId[1] == 0x0a && + productId[0] == 0x00 && productId[1] == 0x90 ) { + result = 1; + } + +out: + if (have_io) + bus_space_unmap(iot, ioh, DM9000_IOSIZE); + + return result; +} + + +void +dm_ssextio_attach(struct device *parent, struct device *self, void *aux) +{ + struct dm_softc *sc = (struct dm_softc*)self; + struct s3c2xx0_attach_args *sa = aux; + vaddr_t ioaddr; +#ifdef MINI2440_ETHER_ADDR_FIXED + static u_int8_t enaddr[ETHER_ADDR_LEN] = {MINI2440_ETHER_ADDR_FIXED}; +#else +#define enaddr NULL +#endif + + sc->sc_iot = sa->sa_iot; + + ioaddr = sa->sa_addr; + if (bus_space_map(sc->sc_iot, ioaddr, DM9000_IOSIZE, 0, &sc->sc_ioh)) { + aprint_error(": unable to map i/o space\n"); + return; + } + + + sc->sc_ih = s3c2440_extint_establish(sa->sa_intr, IPL_NET, IST_EDGE_RISING, dm_intr, sc); + if (sc->sc_ih == NULL) { + aprint_error(": unable to establish interrupt\n"); + return; + } + + sc->dm_io = 0x0; + sc->dm_data = 0x4; + + aprint_normal("\n"); + + dm_attach(sc, enaddr); +} Index: arch/evbarm/mini2440/mini2440_machdep.c =================================================================== RCS file: arch/evbarm/mini2440/mini2440_machdep.c diff -N arch/evbarm/mini2440/mini2440_machdep.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/mini2440/mini2440_machdep.c 28 Dec 2009 10:35:39 -0000 @@ -0,0 +1,1084 @@ +/* $NetBSD: $ */ +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ +/* + * Copyright (c) 2002, 2003 Fujitsu Component Limited + * Copyright (c) 2002, 2003, 2005 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) 2001,2002 ARM Ltd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``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 ARM LTD + * 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) 1997,1998 Mark Brinicombe. + * Copyright (c) 1997,1998 Causality Limited. + * 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 Mark Brinicombe + * for the NetBSD Project. + * 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. + * + * Machine dependant functions for kernel setup for integrator board + * + * Created : 24/11/97 + */ + +/* + * Machine dependant functions for kernel setup for FriendlyARM MINI2440 + */ + +#include +__KERNEL_RCSID(0, "$NetBSD:$"); + +#include "opt_ddb.h" +#include "opt_kgdb.h" +#include "opt_pmap_debug.h" +#include "opt_md.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#ifdef KGDB +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "ksyms.h" + +#ifndef SDRAM_START +#define SDRAM_START S3C2440_SDRAM_START +#endif +#ifndef SDRAM_SIZE +#define SDRAM_SIZE (64*1024*1024) +#endif + +/* + * Address to map I/O registers in early initialize stage. + */ +#define MINI2440_IO_VBASE 0xfd000000 + +/* Kernel text starts 2MB in from the bottom of the kernel address space. */ +#define KERNEL_TEXT_BASE (KERNEL_BASE + 0x00200000) +#define KERNEL_VM_BASE (KERNEL_BASE + 0x01000000) + +/* + * The range 0xc1000000 - 0xccffffff is available for kernel VM space + * Core-logic registers and I/O mappings occupy 0xfd000000 - 0xffffffff + */ +#define KERNEL_VM_SIZE 0x0C000000 + +/* Memory disk support */ +#if defined(MEMORY_DISK_DYNAMIC) && defined(MEMORY_DISK_ROOT_ADDR) +#define DO_MEMORY_DISK +/* We have memory disk image outside of the kernel on ROM. */ +#ifdef MEMORY_DISK_ROOT_ROM +/* map the image directory and use read-only */ +#else +/* copy the image to RAM */ +#endif +#endif + + +/* + * Address to call from cpu_reset() to reset the machine. + * This is machine architecture dependant as it varies depending + * on where the ROM appears when you turn the MMU off. + */ +u_int cpu_reset_address = (u_int)0; + +/* Define various stack sizes in pages */ +#define IRQ_STACK_SIZE 1 +#define ABT_STACK_SIZE 1 +#define UND_STACK_SIZE 1 + +BootConfig bootconfig; /* Boot config storage */ +char *boot_args = NULL; +char *boot_file = NULL; + +vm_offset_t physical_start; +vm_offset_t physical_freestart; +vm_offset_t physical_freeend; +vm_offset_t physical_end; +u_int free_pages; +vm_offset_t pagetables_start; +int physmem = 0; + +/*int debug_flags;*/ +#ifndef PMAP_STATIC_L1S +int max_processes = 64; /* Default number */ +#endif /* !PMAP_STATIC_L1S */ + +/* Physical and virtual addresses for some global pages */ +pv_addr_t irqstack; +pv_addr_t undstack; +pv_addr_t abtstack; +pv_addr_t kernelstack; + +vm_offset_t msgbufphys; + +extern u_int data_abort_handler_address; +extern u_int prefetch_abort_handler_address; +extern u_int undefined_handler_address; + +#ifdef PMAP_DEBUG +extern int pmap_debug_level; +#endif + +#define KERNEL_PT_SYS 0 /* L2 table for mapping zero page */ +#define KERNEL_PT_KERNEL 1 /* L2 table for mapping kernel */ +#define KERNEL_PT_KERNEL_NUM 2 /* L2 tables for mapping kernel VM */ + +#define KERNEL_PT_VMDATA (KERNEL_PT_KERNEL + KERNEL_PT_KERNEL_NUM) + +#define KERNEL_PT_VMDATA_NUM 4 /* start with 16MB of KVM */ +#define NUM_KERNEL_PTS (KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM) + +pv_addr_t kernel_pt_table[NUM_KERNEL_PTS]; + +struct user *proc0paddr; + +/* Prototypes */ + +void consinit(void); +void kgdb_port_init(void); + + +#include "com.h" +#if NCOM > 0 +#include +#include +#endif + +#include "sscom.h" +#if NSSCOM > 0 +#include "opt_sscom.h" +#include +#endif + +/* + * Define the default console speed for the board. This is generally + * what the firmware provided with the board defaults to. + */ +#ifndef CONSPEED +#define CONSPEED B115200 /* TTYDEF_SPEED */ +#endif +#ifndef CONMODE +#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ +#endif + +int comcnspeed = CONSPEED; +int comcnmode = CONMODE; + + +/* + * void cpu_reboot(int howto, char *bootstr) + * + * Reboots the system + * + * Deal with any syncing, unmounting, dumping and shutdown hooks, + * then reset the CPU. + */ +void +cpu_reboot(int howto, char *bootstr) +{ +#ifdef DIAGNOSTIC + /* info */ + printf("boot: howto=%08x curproc=%p\n", howto, curproc); +#endif + + cpu_reset_address = vtophys((u_int)s3c2440_softreset); + + /* + * If we are still cold then hit the air brakes + * and crash to earth fast + */ + if (cold) { + doshutdownhooks(); + printf("The operating system has halted.\n"); + printf("Please press any key to reboot.\n\n"); + cngetc(); + printf("rebooting...\n"); + cpu_reset(); + /* NOTREACHED */ + } + /* Disable console buffering */ + + /* + * If RB_NOSYNC was not specified sync the discs. + * Note: Unless cold is set to 1 here, syslogd will die during the + * unmount. It looks like syslogd is getting woken up only to find + * that it cannot page part of the binary in as the filesystem has + * been unmounted. + */ + if (!(howto & RB_NOSYNC)) + bootsync(); + + /* Say NO to interrupts */ + splhigh(); + + /* Do a dump if requested. */ + if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) + dumpsys(); + + /* Run any shutdown hooks */ + doshutdownhooks(); + + /* Make sure IRQ's are disabled */ + IRQdisable; + + if (howto & RB_HALT) { + printf("The operating system has halted.\n"); + printf("Please press any key to reboot.\n\n"); + cngetc(); + } + printf("rebooting...\n"); + cpu_reset(); + /* NOTREACHED */ +} + +/* + * Static device mappings. These peripheral registers are mapped at + * fixed virtual addresses very early in initarm() so that we can use + * them while booting the kernel , and stay at the same address + * throughout whole kernel's life time. + * + * We use this table twice; once with bootstrap page table, and once + * with kernel's page table which we build up in initarm(). + * + * Since we map these registers into the bootstrap page table using + * pmap_devmap_bootstrap() which calls pmap_map_chunk(), we map + * registers segment-aligned and segment-rounded in order to avoid + * using the 2nd page tables. + */ + +#define _A(a) ((a) & ~L1_S_OFFSET) +#define _S(s) (((s) + L1_S_SIZE - 1) & ~(L1_S_SIZE-1)) + +#define _V(n) (MINI2440_IO_VBASE + (n) * L1_S_SIZE) + +#define GPIO_VBASE _V(0) +#define INTCTL_VBASE _V(1) +#define CLKMAN_VBASE _V(2) +#define UART_VBASE _V(3) +#ifdef MEMORY_DISK_DYNAMIC +#define MEMORY_DISK_VADDR _V(4) +#endif + +static const struct pmap_devmap mini2440_devmap[] = { + /* GPIO registers */ + { + GPIO_VBASE, + _A(S3C2440_GPIO_BASE), + _S(S3C2440_GPIO_SIZE), + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, + }, + { + INTCTL_VBASE, + _A(S3C2440_INTCTL_BASE), + _S(S3C2440_INTCTL_SIZE), + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, + }, + { + CLKMAN_VBASE, + _A(S3C2440_CLKMAN_BASE), + _S(S3C24X0_CLKMAN_SIZE), + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, + }, + { /* UART registers for UART0, 1, 2. */ + UART_VBASE, + _A(S3C2440_UART0_BASE), + _S(S3C2440_UART_BASE(3) - S3C2440_UART0_BASE), + VM_PROT_READ|VM_PROT_WRITE, PTE_NOCACHE, + }, + + { 0, 0, 0, 0 } +}; + +#undef _A +#undef _S + +static inline pd_entry_t * +read_ttb(void) +{ + long ttb; + + __asm volatile("mrc p15, 0, %0, c2, c0, 0" : "=r"(ttb)); + + + return (pd_entry_t *)(ttb & ~((1 << 14) - 1)); +} + + +#define ioreg_read8(a) (*(volatile uint8_t *)(a)) +#define ioreg_write8(a,v) (*(volatile uint8_t *)(a)=(v)) +#define ioreg_read32(a) (*(volatile uint32_t *)(a)) +#define ioreg_write32(a,v) (*(volatile uint32_t *)(a)=(v)) + +/* + * u_int initarm(...) + * + * Initial entry point on startup. This gets called before main() is + * entered. + * It should be responsible for setting up everything that must be + * in place when main is called. + * This includes + * Taking a copy of the boot configuration structure. + * Initialising the physical console so characters can be printed. + * Setting up page tables for the kernel + * Relocating the kernel to the bottom of physical memory + */ + +u_int +initarm(void *arg) +{ + int loop; + int loop1; + u_int l1pagetable; + extern int etext __asm("_etext"); + extern int end __asm("_end"); + //int progress_counter = 0; + +#ifdef DO_MEMORY_DISK + vm_offset_t md_root_start; +#define MD_ROOT_SIZE (MEMORY_DISK_ROOT_SIZE * DEV_BSIZE) +#endif + +#define gpio_read8(reg) ioreg_read8(GPIO_VBASE + (reg)) + +//#define LEDSTEP() __LED(progress_counter++) +#define LEDSTEP() + +#define pdatb (*(volatile uint8_t *)(S3C2440_GPIO_BASE+GPIO_PBDAT)) + +// 0x1E0 is the mask for GPB5, GPB6, GPB7, and GPB8 +#define __LED(x) (pdatb = (pdatb & ~0x1e0) | (~(1<<(x+5)) & 0x1e0)) + + __LED(0); + LEDSTEP(); + + /* CS8900A on CS3 and CL-PD7610 need nBE1 signal. make sure + * memory controller is set correctly. (USB download firmware + * doesn't do this right) Also, we use WAIT signal for them. + */ + /*ioreg_write32(S3C2440_MEMCTL_BASE + MEMCTL_BWSCON, + (BWSCON_ST|BWSCON_WS) << BWSCON_BANK_SHIFT(2) | + (BWSCON_ST|BWSCON_WS) << BWSCON_BANK_SHIFT(3) | + ioreg_read32(S3C2440_MEMCTL_BASE + MEMCTL_BWSCON));*/ + /* tweak access timing for CS8900A */ + /*ioreg_write32(S3C2440_MEMCTL_BASE + MEMCTL_BANKCON(3), + (0< 0x%08lx\n", physmem, + physical_start, physical_end - 1); + printf("phys_end: 0x%08lx\n", physical_end); +#endif + + /* + * XXX + * Okay, the kernel starts 2MB in from the bottom of physical + * memory. We are going to allocate our bootstrap pages downwards + * from there. + * + * We need to allocate some fixed page tables to get the kernel + * going. We allocate one page directory and a number of page + * tables and store the physical addresses in the kernel_pt_table + * array. + * + * The kernel page directory must be on a 16K boundary. The page + * tables must be on 4K boundaries. What we do is allocate the + * page directory on the first 16K boundary that we encounter, and + * the page tables on 4K boundaries otherwise. Since we allocate + * at least 3 L2 page tables, we are guaranteed to encounter at + * least one 16K aligned region. + */ + +#ifdef VERBOSE_INIT_ARM + printf("Allocating page tables\n"); +#endif + + free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; + +#ifdef VERBOSE_INIT_ARM + printf("freestart = 0x%08lx, free_pages = %d (0x%08x), freeend = 0x%08lx\n", + physical_freestart, free_pages, free_pages, physical_freeend); +#endif + + /* Define a macro to simplify memory allocation */ +#define valloc_pages(var, np) \ + alloc_pages((var).pv_pa, (np)); \ + (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start; + +#define alloc_pages(var, np) \ + physical_freeend -= ((np) * PAGE_SIZE); \ + if (physical_freeend < physical_freestart) \ + panic("initarm: out of memory"); \ + (var) = physical_freeend; \ + free_pages -= (np); \ + memset((char *)(var), 0, ((np) * PAGE_SIZE)); + + loop1 = 0; + for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) { + /* Are we 16KB aligned for an L1 ? */ + if (((physical_freeend - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) == 0 + && kernel_l1pt.pv_pa == 0) { + valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); + } else { + valloc_pages(kernel_pt_table[loop1], + L2_TABLE_SIZE / PAGE_SIZE); + ++loop1; + } + } + + /* This should never be able to happen but better confirm that. */ + if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE - 1)) != 0) + panic("initarm: Failed to align the kernel page directory\n"); + + /* + * Allocate a page for the system page mapped to V0x00000000 + * This page will just contain the system vectors and can be + * shared by all processes. + */ + alloc_pages(systempage.pv_pa, 1); + + /* Allocate stacks for all modes */ + valloc_pages(irqstack, IRQ_STACK_SIZE); + valloc_pages(abtstack, ABT_STACK_SIZE); + valloc_pages(undstack, UND_STACK_SIZE); + valloc_pages(kernelstack, UPAGES); + +#ifdef VERBOSE_INIT_ARM + printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa, + irqstack.pv_va); + printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa, + abtstack.pv_va); + printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa, + undstack.pv_va); + printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa, + kernelstack.pv_va); +#endif + + alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / PAGE_SIZE); + + LEDSTEP(); + + /* + * Ok we have allocated physical pages for the primary kernel + * page tables + */ + +#ifdef VERBOSE_INIT_ARM + printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa); +#endif + + /* + * Now we start construction of the L1 page table + * We start by mapping the L2 page tables into the L1. + * This means that we can replace L1 mappings later on if necessary + */ + l1pagetable = kernel_l1pt.pv_pa; + + /* Map the L2 pages tables in the L1 page table */ + pmap_link_l2pt(l1pagetable, 0x00000000, + &kernel_pt_table[KERNEL_PT_SYS]); + for (loop = 0; loop < KERNEL_PT_KERNEL_NUM; loop++) + pmap_link_l2pt(l1pagetable, KERNEL_BASE + loop * 0x00400000, + &kernel_pt_table[KERNEL_PT_KERNEL + loop]); + for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; loop++) + pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000, + &kernel_pt_table[KERNEL_PT_VMDATA + loop]); + + /* update the top of the kernel VM */ + pmap_curmaxkvaddr = + KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000); + +#ifdef VERBOSE_INIT_ARM + printf("Mapping kernel\n"); +#endif + + /* Now we fill in the L2 pagetable for the kernel static code/data */ + { + size_t textsize = (uintptr_t)&etext - KERNEL_TEXT_BASE; + size_t totalsize = (uintptr_t)&end - KERNEL_TEXT_BASE; + u_int logical; + + printf("Textsize: %u, totalsize: %u\n", (uint)textsize, (uint)totalsize); + printf("&etext: 0x%x\n", (uint)&etext); + printf("&end: 0x%x\n", (uint)&end); + printf("KERNEL_TEXT_BASE: 0x%x\n", KERNEL_TEXT_BASE); + + textsize = (textsize + PGOFSET) & ~PGOFSET; + totalsize = (totalsize + PGOFSET) & ~PGOFSET; + + logical = 0x00200000; /* offset of kernel in RAM */ + + logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, + physical_start + logical, textsize, + VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE); + logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, + physical_start + logical, totalsize - textsize, + VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE); + } + +#ifdef VERBOSE_INIT_ARM + printf("Constructing L2 page tables\n"); +#endif + + /* Map the stack pages */ + pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, + IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, + PTE_CACHE); + pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, + ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, + PTE_CACHE); + pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, + UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, + PTE_CACHE); + pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, + UPAGES * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, + L1_TABLE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_PAGETABLE); + + for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { + pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va, + kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); + } + + /* Map the vector page. */ +#if 1 + /* MULTI-ICE requires that page 0 is NC/NB so that it can download the + * cache-clean code there. */ + pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa, + VM_PROT_READ | VM_PROT_WRITE, PTE_NOCACHE); +#else + pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa, + VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE); +#endif + +#ifdef MEMORY_DISK_DYNAMIC + /* map MD root image */ + /*pmap_map_chunk(l1pagetable, MEMORY_DISK_VADDR, md_root_start, + MD_ROOT_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE);*/ + + /*md_root_setconf((void *)md_root_start, MD_ROOT_SIZE);*/ +// md_root_setconf(memory_disk, sizeof memory_disk); +#endif /* MEMORY_DISK_DYNAMIC */ + /* + * map integrated peripherals at same address in l1pagetable + * so that we can continue to use console. + */ + pmap_devmap_bootstrap(l1pagetable, mini2440_devmap); + + /* + * Now we have the real page tables in place so we can switch to them. + * Once this is done we will be running with the REAL kernel page + * tables. + */ + + /* + * Update the physical_freestart/physical_freeend/free_pages + * variables. + */ + { + physical_freestart = physical_start + + (((((uintptr_t)&end) + PGOFSET) & ~PGOFSET) - KERNEL_BASE); + physical_freeend = physical_end; + free_pages = + (physical_freeend - physical_freestart) / PAGE_SIZE; + } + + /* Switch tables */ +#ifdef VERBOSE_INIT_ARM + printf("freestart = 0x%08lx, free_pages = %d (0x%x)\n", + physical_freestart, free_pages, free_pages); + printf("switching to new L1 page table @%#lx...", kernel_l1pt.pv_pa); +#endif + LEDSTEP(); + cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); + setttb(kernel_l1pt.pv_pa); + cpu_tlb_flushID(); + cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); + + /* + * Moved from cpu_startup() as data_abort_handler() references + * this during uvm init + */ + proc0paddr = (struct user *)kernelstack.pv_va; + lwp0.l_addr = proc0paddr; + +#ifdef VERBOSE_INIT_ARM + printf("done!\n"); +#endif + + LEDSTEP(); +#ifdef VERBOSE_INIT_ARM + printf("bootstrap done.\n"); +#endif + + arm32_vector_init(ARM_VECTORS_LOW, ARM_VEC_ALL); + + /* + * Pages were allocated during the secondary bootstrap for the + * stacks for different CPU modes. + * We must now set the r13 registers in the different CPU modes to + * point to these stacks. + * Since the ARM stacks use STMFD etc. we must set r13 to the top end + * of the stack memory. + */ +#ifdef VERBOSE_INIT_ARM + printf("init subsystems: stacks "); +#endif + + set_stackptr(PSR_IRQ32_MODE, + irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_ABT32_MODE, + abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_UND32_MODE, + undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); + + LEDSTEP(); + + cpu_idcache_wbinv_all(); + + + /* + * Well we should set a data abort handler. + * Once things get going this will change as we will need a proper + * handler. + * Until then we will use a handler that just panics but tells us + * why. + * Initialisation of the vectors will just panic on a data abort. + * This just fills in a slightly better one. + */ +#ifdef VERBOSE_INIT_ARM + printf("vectors "); +#endif + data_abort_handler_address = (u_int)data_abort_handler; + prefetch_abort_handler_address = (u_int)prefetch_abort_handler; + undefined_handler_address = (u_int)undefinedinstruction_bounce; + + /* Initialise the undefined instruction handlers */ +#ifdef VERBOSE_INIT_ARM + printf("undefined "); +#endif + undefined_init(); + + LEDSTEP(); + + /* Load memory into UVM. */ +#ifdef VERBOSE_INIT_ARM + printf("page "); +#endif + uvm_setpagesize(); /* initialize PAGE_SIZE-dependent variables */ + uvm_page_physload(atop(physical_freestart), atop(physical_freeend), + atop(physical_freestart), atop(physical_freeend), + VM_FREELIST_DEFAULT); + + LEDSTEP(); + /* Boot strap pmap telling it where the kernel page table is */ +#ifdef VERBOSE_INIT_ARM + printf("pmap "); +#endif + __LED(2); + pmap_bootstrap(KERNEL_VM_BASE, KERNEL_VM_BASE + KERNEL_VM_SIZE); + __LED(1); + + LEDSTEP(); + + /* Setup the IRQ system */ +#ifdef VERBOSE_INIT_ARM + printf("irq "); +#endif + /* XXX irq_init(); */ + +#ifdef VERBOSE_INIT_ARM + printf("done.\n"); +#endif + +#ifdef BOOTHOWTO + boothowto |= BOOTHOWTO; +#endif + +#ifdef KGDB + if (boothowto & RB_KDB) { + kgdb_debug_init = 1; + kgdb_connect(1); + } +#endif + +#if NKSYMS || defined(DDB) || defined(LKM) + /* Firmware doesn't load symbols. */ + ksyms_init(0, NULL, NULL); +#endif + +#ifdef DDB + db_machine_init(); + if (boothowto & RB_KDB) + Debugger(); +#endif + + /* We return the new stack pointer address */ + return (kernelstack.pv_va + USPACE_SVC_STACK_TOP); +} + +void +consinit(void) +{ + static int consinit_done = 0; + bus_space_tag_t iot = &s3c2xx0_bs_tag; + int pclk; + + if (consinit_done != 0) + return; + + consinit_done = 1; + + s3c24x0_clock_freq2(CLKMAN_VBASE, NULL, NULL, &pclk); + +#if NSSCOM > 0 +#ifdef SSCOM0CONSOLE + if (0 == s3c2440_sscom_cnattach(iot, 0, comcnspeed, + pclk, comcnmode)) + return; +#endif +#ifdef SSCOM1CONSOLE + if (0 == s3c2440_sscom_cnattach(iot, 1, comcnspeed, + pclk, comcnmode)) + return; +#endif +#endif /* NSSCOM */ +#if NCOM>0 && defined(CONCOMADDR) + if (comcnattach(&isa_io_bs_tag, CONCOMADDR, comcnspeed, + COM_FREQ, COM_TYPE_NORMAL, comcnmode)) + panic("can't init serial console @%x", CONCOMADDR); + return; +#endif + + consinit_done = 0; +} + + +#ifdef KGDB + +#if (NSSCOM > 0) + +#ifdef KGDB_DEVNAME +const char kgdb_devname[] = KGDB_DEVNAME; +#else +const char kgdb_devname[] = ""; +#endif + +#ifndef KGDB_DEVMODE +#define KGDB_DEVMODE ((TTYDEF_CFLAG & ~(CSIZE|CSTOPB|PARENB))|CS8) /* 8N1 */ +#endif +int kgdb_sscom_mode = KGDB_DEVMODE; + +#endif /* NSSCOM */ + +void +kgdb_port_init(void) +{ +#if (NSSCOM > 0) + int unit = -1; + int pclk; + + if (strcmp(kgdb_devname, "sscom0") == 0) + unit = 0; + else if (strcmp(kgdb_devname, "sscom1") == 0) + unit = 1; + + if (unit >= 0) { + s3c24x0_clock_freq2(CLKMAN_VBASE, NULL, NULL, &pclk); + + s3c2440_sscom_kgdb_attach(&s3c2xx0_bs_tag, + unit, kgdb_rate, pclk, kgdb_sscom_mode); + } +#endif +} +#endif + +static inline void +writeback_dcache_line(vaddr_t va) +{ + /* writeback Dcache line */ + /* we can't use cpu_dcache_wb_range() here, because cpufuncs for ARM9 + * assume write-through cache, and always flush Dcache instead of + * cleaning it. Since Boot loader maps page table with write-back + * cached, we really need to clean Dcache. */ + __asm("mcr p15, 0, %0, c7, c10, 1" + : : "r"(va)); +} + +static inline void +clean_dcache_line(vaddr_t va) +{ + /* writeback and invalidate Dcache line */ + __asm("mcr p15, 0, %0, c7, c14, 1" + : : "r"(va)); +} + +static struct arm32_dma_range mini2440_dma_ranges[1]; + +bus_dma_tag_t +s3c2xx0_bus_dma_init(struct arm32_bus_dma_tag *dma_tag_template) +{ + extern paddr_t physical_start, physical_end; + struct arm32_bus_dma_tag *dmat; + + mini2440_dma_ranges[0].dr_sysbase = physical_start; + mini2440_dma_ranges[0].dr_busbase = physical_start; + mini2440_dma_ranges[0].dr_len = physical_end - physical_start; + +#if 1 + dmat = dma_tag_template; +#else + dmat = malloc(sizeof *dmat, M_DEVBUF, M_NOWAIT); + if (dmat == NULL) + return NULL; + *dmat = *dma_tag_template; +#endif + + dmat->_ranges = mini2440_dma_ranges; + dmat->_nranges = 1; + + return dmat; +} Index: arch/evbarm/mini2440/mini2440_start.S =================================================================== RCS file: arch/evbarm/mini2440/mini2440_start.S diff -N arch/evbarm/mini2440/mini2440_start.S --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/evbarm/mini2440/mini2440_start.S 28 Dec 2009 10:35:40 -0000 @@ -0,0 +1,222 @@ +/* $NetBSD: $ */ + +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +/* + * 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 +#include +#include +#include /* for PMAP_DOMAIN_KERNEL */ + +#include /* for S3C2440_SDRAM_START */ + +/* + * Kernel start routine for Friendly ARM Mini2440. + * This code is excuted at the very first after the kernel is loaded + * by boot program. + */ + .text + +#ifndef SDRAM_START +#define SDRAM_START S3C2440_SDRAM_START +#endif +#define KERNEL_TEXT_ADDR (SDRAM_START+0x00200000) + +#define LED1 (1<<5) +#define LED2 (1<<6) +#define LED3 (1<<7) +#define LED4 (1<<8) + + .global _C_LABEL(mini2440_start) +_C_LABEL(mini2440_start): + /* Disable interrupt */ + mrs r0, cpsr + orr r0, r0, #I32_bit + msr cpsr, r0 + + /* Turn off LED1-LED4 */ + mov r1, #S3C2440_GPIO_BASE + add r1, r1, #0x14 + ldr r3, [r1] + orr r3, r3, #LED1 //LEDS are active-low, so we set their bit to turn them off + orr r3, r3, #LED2 + orr r3, r3, #LED3 + orr r3, r3, #LED4 + str r3, [r1] + + /* Setup BANK6/7 memory map */ + mov r1, #S3C2440_MEMCTL_BASE + ldr r2, [r1, #MEMCTL_BANKSIZE] + bic r2, r2, #0x7 // Clear the three lowest bits (BK67MAP) + add r2, r2, #0x1 // Set BK67MAP to b001 = 64MB/64MB + str r2, [r1, #MEMCTL_BANKSIZE] + + /* Are we running on right place ? */ + adr r0, _C_LABEL(mini2440_start) + ldr r2, =KERNEL_TEXT_ADDR + cmp r0, r2 + beq mini2440_start_ram + + /* + * move me to RAM + */ + ldr r1, Lcopy_size + adr r0, _C_LABEL(mini2440_start) + add r1, r1, #3 + mov r1, r1, LSR #2 + mov r4, r2 + + cmp r0, r2 + bhs 5f + + /* src < dest. copy from top */ + add r0,r0,r1,LSL #2 + add r2,r2,r1,LSL #2 + +3: ldr r3,[r0,#-4]! + str r3,[r2,#-4]! + subs r1,r1,#1 + bhi 3b + b 7f + + /* src >= dest. copy from bottom */ +5: ldr r3,[r0],#4 + str r3,[r2],#4 + subs r1,r1,#1 + bhi 5b + +7: + /* Jump to RAM */ + ldr r0, Lstart_off + add pc, r4, r0 + +Lcopy_size: .word _edata-_C_LABEL(mini2440_start) +Lstart_off: .word mini2440_start_ram-_C_LABEL(mini2440_start) + +mini2440_start_ram: + /* + * Kernel is loaded in SDRAM (0x30200000..), and is expected to run + * in VA 0xc0200000.. + */ + + /* Disable MMU for a while */ + mrc p15, 0, r2, c1, c0, 0 + bic r2, r2, #CPU_CONTROL_MMU_ENABLE + mcr p15, 0, r2, c1, c0, 0 + + nop + nop + nop + + mov r0,#SDRAM_START /* pagetable */ + adr r4, mmu_init_table + b 2f +1: + str r3, [r0, r2] + add r2, r2, #4 + add r3, r3, #(L1_S_SIZE) + adds r1, r1, #-1 + bhi 1b +2: + ldmia r4!, {r1,r2,r3} /* # of sections, PA|attr, VA */ + cmp r1, #0 + bne 1b + + mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ + mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ + + /* Set the Domain Access register. Very important! */ + mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) + mcr p15, 0, r0, c3, c0, 0 + + /* Enable MMU */ + mrc p15, 0, r0, c1, c0, 0 + orr r0, r0, #CPU_CONTROL_MMU_ENABLE + mcr p15, 0, r0, c1, c0, 0 + + nop + nop + nop + + /* Jump to kernel code in TRUE VA */ + adr r0, Lstart + ldr pc, [r0] + +Lstart: + .word start + + .macro clock_data hdivn, pdivn, mdiv, pdiv, sdiv + .word (\hdivn)<<1 | \pdivn + .word (\mdiv)<>L1_S_SHIFT) ; \ + .word (pa)|(attr) ; + +mmu_init_table: + /* fill all table VA==PA */ + MMU_INIT(0x00000000, 0x00000000, 1<<(32-L1_S_SHIFT), L1_TYPE_S|L1_S_AP(AP_KRW)) + /* map SDRAM VA==PA, WT cacheable */ + MMU_INIT(SDRAM_START, SDRAM_START, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) + /* map VA 0xc0000000..0xc3ffffff to PA 0x30000000..0x33ffffff */ + MMU_INIT(0xc0000000, SDRAM_START, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) + + .word 0 /* end of table */ + Index: conf/files =================================================================== RCS file: /cvsroot/src/sys/conf/files,v retrieving revision 1.924.4.6 diff -u -r1.924.4.6 files --- conf/files 8 Oct 2009 09:47:09 -0000 1.924.4.6 +++ conf/files 28 Dec 2009 10:35:51 -0000 @@ -1002,6 +1002,10 @@ device tscs: arp, ether, ifnet file dev/ic/cs89x0.c cs | tscs +# Davicom DM9000 Fast Ethernet Controller +device dm9000nic: arp, ether, ifnet +file dev/ic/dm9000.c dm9000nic + # Radio device attributes # define tea5757 Index: dev/DEVNAMES =================================================================== RCS file: /cvsroot/src/sys/dev/DEVNAMES,v retrieving revision 1.242.4.2 diff -u -r1.242.4.2 DEVNAMES --- dev/DEVNAMES 16 Oct 2009 11:56:11 -0000 1.242.4.2 +++ dev/DEVNAMES 28 Dec 2009 10:35:52 -0000 @@ -323,6 +323,7 @@ dhu MI dio hp300 dl MI +dm9000nic MI dma MI dma sun3 dmac newsmips Index: dev/ic/dm9000.c =================================================================== RCS file: dev/ic/dm9000.c diff -N dev/ic/dm9000.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/ic/dm9000.c 28 Dec 2009 10:35:53 -0000 @@ -0,0 +1,784 @@ +/* $NetBSD:$ */ + +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +/* based on sys/dev/ic/cs89x0.c */ +/* + * Copyright (c) 2004 Christopher Gilbert + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +/* + * Copyright 1997 + * Digital Equipment Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and conditions. + * Subject to these conditions, you may download, copy, install, + * use, modify and distribute this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Digital Equipment Corporation. Neither the "Digital Equipment + * Corporation" name nor any trademark or logo of Digital Equipment + * Corporation may be used to endorse or promote products derived + * from this software without the prior written permission of + * Digital Equipment Corporation. + * + * 3) This software is provided "AS-IS" and any express or implied + * warranties, including but not limited to, any implied warranties + * of merchantability, fitness for a particular purpose, or + * non-infringement are disclaimed. In no event shall DIGITAL be + * liable for any damages whatsoever, and in particular, DIGITAL + * shall not be liable for special, indirect, consequential, or + * incidental damages or damages for lost profits, loss of + * revenue or loss of use, whether such damages arise in contract, + * negligence, tort, under statute, in equity, at law or otherwise, + * even if advised of the possibility of such damage. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef INET +#include +#include +#endif + +#include "bpfilter.h" +#if NBPFILTER > 0 +#include +#include +#endif + +#include +#include + +#include +#include + +#undef DM9000_DEBUG +#undef DM9000_TX_DEBUG +#undef DM9000_TX_DATA_DEBUG +#undef DM9000_RX_DEBUG +#undef DM9000_RX_DATA_DEBUG + +#ifdef DM9000_DEBUG +#define DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) +#else +#define DPRINTF(s) do {} while (/*CONSTCOND*/0) +#endif + +#ifdef DM9000_TX_DEBUG +#define TX_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) +#else +#define TX_DPRINTF(s) do {} while (/*CONSTCOND*/0) +#endif + +#ifdef DM9000_RX_DEBUG +#define RX_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) +#else +#define RX_DPRINTF(s) do {} while (/*CONSTCOND*/0) +#endif + +#ifdef DM9000_RX_DATA_DEBUG +#define RX_DATA_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) +#else +#define RX_DATA_DPRINTF(s) do {} while (/*CONSTCOND*/0) +#endif + +#ifdef DM9000_TX_DATA_DEBUG +#define TX_DATA_DPRINTF(s) do {printf s; } while (/*CONSTCOND*/0) +#else +#define TX_DATA_DPRINTF(s) do {} while (/*CONSTCOND*/0) +#endif + + +u_int16_t dm_phy_read(struct dm_softc *sc, int reg); +void dm_phy_write(struct dm_softc *sc, int reg, u_int16_t value); + +/*** Methods registered in struct ifnet ***/ +void dm_start_output(struct ifnet *ifp); +int dm_init(struct ifnet *ifp); +int dm_ioctl(struct ifnet *ifp, u_long cmd, void *data); +void dm_stop(struct ifnet *ifp, int disable); + +int dm_mediachange(struct ifnet *ifp); +void dm_mediastatus(struct ifnet *ufp, struct ifmediareq *ifmr); + +/*** Internal methods ***/ + +/* Prepare data to be transmitted (i.e. dequeue and load it into the DM9000) */ +void dm_prepare(struct dm_softc *sc, struct ifnet *ifp); + +/* Transmit prepared data */ +void dm_transmit(struct dm_softc *sc); + +/* Receive data */ +void dm_receive(struct dm_softc *sc, struct ifnet *ifp); + +/* Software Initialize/Reset of the DM9000 */ +void dm_reset(struct dm_softc *sc); + +u_int16_t +dm_phy_read(struct dm_softc *sc, int reg) +{ + u_int16_t val; + /* Select Register to read*/ + dm_write(sc, DM9000_EPAR, DM9000_EPAR_INT_PHY + (reg & DM9000_EPAR_EROA_MASK)); + /* Select read operation (DM9000_EPCR_ERPRR) from the PHY */ + dm_write(sc, DM9000_EPCR, DM9000_EPCR_ERPRR + DM9000_EPCR_EPOS_PHY); + + /* Wait until access to PHY has completed */ + while(dm_read(sc, DM9000_EPCR) & DM9000_EPCR_ERRE); + + /* XXX: The delay is probably not necessary as we just busy-waited */ + delay(200); + + /* Reset ERPRR-bit */ + dm_write(sc, DM9000_EPCR, DM9000_EPCR_EPOS_PHY); + + val = dm_read(sc, DM9000_EPDRL); + val += dm_read(sc, DM9000_EPDRH) << 8; + + return val; +} + +void +dm_phy_write(struct dm_softc *sc, int reg, u_int16_t value) +{ + /* Select Register to write*/ + dm_write(sc, DM9000_EPAR, DM9000_EPAR_INT_PHY + (reg & DM9000_EPAR_EROA_MASK)); + + /* Write data to the two data registers */ + dm_write(sc, DM9000_EPDRL, value & 0xFF); + dm_write(sc, DM9000_EPDRH, (value >> 8) & 0xFF); + + /* Select write operation (DM9000_EPCR_ERPRW) from the PHY */ + dm_write(sc, DM9000_EPCR, DM9000_EPCR_ERPRW + DM9000_EPCR_EPOS_PHY); + + /* Wait until access to PHY has completed */ + while(dm_read(sc, DM9000_EPCR) & DM9000_EPCR_ERRE); + + + /* XXX: The delay is probably not necessary as we just busy-waited */ + delay(200); + + /* Reset ERPRR-bit */ + dm_write(sc, DM9000_EPCR, DM9000_EPCR_EPOS_PHY); +} + +int +dm_attach(struct dm_softc *sc, uint8_t *enaddr) +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + uint8_t b[2]; + + dm_read_c(sc, DM9000_VID0, b, 2); + sc->vendorId = b[0]; + sc->vendorId += (b[1] << 8 ); + + dm_read_c(sc, DM9000_PID0, b, 2); + sc->productId = b[0]; + sc->productId += (b[1] << 8); + + /* TODO: Check the vendor ID as well */ + if( sc->productId != 0x9000 ) { + panic("dm_attach: impossible"); + } + +#if 0 + { + /* Force 10Mbps to test dm_phy_write */ + u_int16_t bmcr; + bmcr = dm_phy_read(sc, DM9000_PHY_BMCR); + bmcr &= ~DM9000_PHY_BMCR_AUTO_NEG_EN; + bmcr &= ~DM9000_PHY_BMCR_SPEED_SELECT; /* select 100Mbps */ + dm_phy_write(sc, DM9000_PHY_BMCR, bmcr); + } +#endif + /* Initialize ifnet structure. */ + strlcpy(ifp->if_xname, device_xname(&sc->sc_dev), IFNAMSIZ); + ifp->if_softc = sc; + ifp->if_start = dm_start_output; + ifp->if_init = dm_init; + ifp->if_ioctl = dm_ioctl; + ifp->if_stop = dm_stop; + ifp->if_watchdog = NULL; /* no watchdog at this stage */ + ifp->if_flags = IFF_SIMPLEX | IFF_NOTRAILERS | + IFF_BROADCAST; /* No multicast support for now */ + IFQ_SET_READY(&ifp->if_snd); + + /* Initialize ifmedia structures. */ + ifmedia_init(&sc->sc_media, 0, dm_mediachange, dm_mediastatus); + ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_T|IFM_100_TX, 0, NULL); + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_10_T|IFM_100_TX); + + if (enaddr != NULL) + memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr)); + + /* Configure DM9000 with the MAC address */ + dm_write_c(sc, DM9000_PAB0, sc->sc_enaddr, 6); + +#ifdef DM9000_DEBUG + { + uint8_t macAddr[6]; + dm_read_c(sc, DM9000_PAB0, macAddr, 6); + printf("DM9000 configured with MAC address: "); + for(int i = 0; i<6; i++) { + printf("%02X:", macAddr[i]); + } + printf("\n"); + } +#endif + + if_attach(ifp); + ether_ifattach(ifp, sc->sc_enaddr); + +#ifdef DM9000_DEBUG + { + uint8_t network_state; + network_state = dm_read(sc, DM9000_NSR); + printf("DM9000 Link status: "); + if( network_state & DM9000_NSR_LINKST ) { + if( network_state & DM9000_NSR_SPEED ) + printf("10Mbps"); + else + printf("100Mbps"); + } else { + printf("Down"); + } + printf("\n"); + } +#endif + + sc->io_mode = (dm_read(sc, DM9000_ISR) & DM9000_IOMODE_MASK) >> DM9000_IOMODE_SHIFT; + if (sc->io_mode != DM9000_MODE_16BIT ) + panic("DM9000: Only 16-bit mode is supported!\n"); +#ifdef DM9000_DEBUG + printf("DM9000 Operation Mode: "); + switch( sc->io_mode) + { + case DM9000_MODE_16BIT: + printf("16-bit mode"); + break; + case DM9000_MODE_32BIT: + printf("32-bit mode"); + break; + case DM9000_MODE_8BIT: + printf("8-bit mode"); + break; + case 3: + printf("Invalid mode"); + break; + } + printf("\n"); +#endif + + return 0; +} + +int dm_intr(void *arg) +{ + struct dm_softc *sc = (struct dm_softc*)arg; + struct ifnet *ifp; + u_int8_t status; + + ifp = &sc->sc_ethercom.ec_if; + + /* Disable interrupts */ + dm_write(sc, DM9000_IMR, DM9000_IMR_PAR ); + + status = dm_read(sc, DM9000_ISR); + dm_write(sc, DM9000_ISR, status); + + if (status & DM9000_ISR_PRS) { + if (ifp->if_flags & IFF_RUNNING ) + dm_receive(sc, ifp); + } + if ( status & DM9000_ISR_PTS ) { + u_int8_t nsr; + u_int8_t tx_status = 0x01; /* Initialize to an error value */ + + /* A packet has been transmitted */ + sc->txbusy = 0; + + nsr = dm_read(sc, DM9000_NSR); + + if (nsr & DM9000_NSR_TX1END) { + tx_status = dm_read(sc, DM9000_TSR1); + TX_DPRINTF(("dm_intr: Sent using channel 0\n")); + } else if (nsr & DM9000_NSR_TX2END) { + tx_status = dm_read(sc, DM9000_TSR2); + TX_DPRINTF(("dm_intr: Sent using channel 1\n")); + } + + if (tx_status == 0x0) { + /* Frame successfully sent */ + ifp->if_opackets++; + } else { + ifp->if_oerrors++; + } + + /* If we have nothing ready to transmit, prepare something */ + if (!sc->txready) { + dm_prepare(sc, ifp); + } + + if (sc->txready) + dm_transmit(sc); + + /* Prepare the next frame */ + dm_prepare(sc, ifp); + + } + + /* Enable interrupts again */ + dm_write(sc, DM9000_IMR, DM9000_IMR_PAR | DM9000_IMR_PRM | + DM9000_IMR_PTM); + + return 1; +} + +void +dm_start_output(struct ifnet *ifp) +{ + struct dm_softc *sc; + + sc = ifp->if_softc; + + if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) { + printf("No output\n"); + return; + } + + if( sc->txbusy && sc->txready ) { + panic("DM9000: Internal error, trying to sent without any empty queue\n"); + } + + dm_prepare(sc, ifp); + + if (sc->txbusy == 0) { + /* We are ready to transmit right away */ + dm_transmit(sc); + dm_prepare(sc, ifp); /* Prepare next one */ + } else { + /* We need to wait until the current packet has been transmitted. */ + ifp->if_flags |= IFF_OACTIVE; + } + +} + +void +dm_prepare(struct dm_softc *sc, struct ifnet *ifp) +{ + struct mbuf *buf; + struct mbuf *bufChain; + u_int16_t length; + u_int8_t *write_ptr; + + TX_DPRINTF(("dm_prepare: Entering\n")); + + if (sc->txready) + panic("dm_prepare: Someone called us with txready set\n"); + + IFQ_DEQUEUE(&ifp->if_snd, bufChain); + if( bufChain == NULL ) { + TX_DPRINTF(("dm_prepare: Nothing to transmit\n")); + ifp->if_flags &= ~IFF_OACTIVE; /* Clear OACTIVE bit */ + return; /* Nothing to transmit */ + } + + /* Element has now been removed from the queue, so we better send it */ + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, bufChain); +#endif + + + length = 0; + + /* XXX: This support 16-bit I/O mode only. */ + /* XXX: This code must be factored out, such that architecture + dependant versions can be supplied */ + + int left_over_count = 0; /* Number of bytes from previous mbuf, which + need to be written with the next.*/ + u_int16_t left_over_buf = 0; + + /* Setup the DM9000 to accept the writes, and then write each buf in + the chain. */ + + TX_DATA_DPRINTF(("dm_prepare: Writing data: ")); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dm_io, DM9000_MWCMD); + for(buf = bufChain; buf != NULL; buf = buf->m_next ) { + int to_write = buf->m_len; + + length += to_write; + + write_ptr = buf->m_data; + while (to_write > 0 || + (buf->m_next == NULL && left_over_count > 0) + ) { + if (left_over_count > 0) { + uint8_t b = 0; + DPRINTF(("dm_prepare: Writing left over byte\n")); + + if (to_write > 0) { + b = *write_ptr; + to_write--; + write_ptr++; + + DPRINTF(("Took single byte\n")); + } else { + DPRINTF(("Leftover in last run\n")); + length++; + } + + /* Does shift direction depend on endianess? */ + left_over_buf = left_over_buf | (b << 8); + + bus_space_write_2(sc->sc_iot, sc->sc_ioh, + sc->dm_data, left_over_buf); + TX_DATA_DPRINTF(("%02X ", left_over_buf)); + left_over_count = 0; + } else if ((long)write_ptr % 2 != 0) { + /* Misaligned data */ + DPRINTF(("dm_prepare: Detected misaligned data\n")); + left_over_buf = *write_ptr; + left_over_count = 1; + write_ptr++; + to_write--; + } else { + int i; + u_int16_t *dptr = (u_int16_t*)write_ptr; + + /* A block of aligned data. */ + for(i = 0; i < to_write/2; i++) { + /* buf will be half-word aligned all the time */ + bus_space_write_2(sc->sc_iot, sc->sc_ioh, + sc->dm_data, *dptr); + TX_DATA_DPRINTF(("%02X %02X ", *dptr & 0xFF, + (*dptr>>8) & 0xFF)); + dptr++; + } + + write_ptr += i*2; + if ( to_write % 2 != 0 ) { + DPRINTF(("dm_prepare: to_write %% 2: %d\n", to_write % 2)); + left_over_count = 1; + left_over_buf = *write_ptr; /* XXX: Does this depend on the endianess? */ + write_ptr++; + to_write--; + DPRINTF(("dm_prepare: to_write (after): %d\n", to_write)); + DPRINTF(("dm_prepare: i*2: %d\n", i*2)); + } + to_write -= i*2; + } + } /* while(...) */ + } /* for(...) */ + + TX_DATA_DPRINTF(("\n")); + + if (length % 2 == 1) { + panic("dm_prepare: length is not a word-length"); + } + + sc->txready_length = length; + sc->txready = 1; + + TX_DPRINTF(("dm_prepare: txbusy: %d\ndm_prepare: txready: %d, txready_length: %d\n", + sc->txbusy, sc->txready, sc->txready_length)); + + m_freem(bufChain); + + TX_DPRINTF(("dm_prepare: Leaving\n")); +} + +int +dm_init(struct ifnet *ifp) +{ + int state; + struct dm_softc *sc = ifp->if_softc; + + dm_stop(ifp, 0); + + state = splnet(); + + dm_reset(sc); + + sc->sc_ethercom.ec_if.if_flags |= IFF_RUNNING; + sc->sc_ethercom.ec_if.if_flags &= ~IFF_OACTIVE; + sc->sc_ethercom.ec_if.if_timer = 0; + + splx(state); + + return 0; +} + +int +dm_ioctl(struct ifnet *ifp, u_long cmd, void *data) +{ + struct dm_softc *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *) data; + int result; + int state; + + state = splnet(); + result = 0; + + switch(cmd) { + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + result = ifmedia_ioctl(ifp, ifr, &sc->sc_media,cmd); + break; + default: + result = ether_ioctl(ifp, cmd, data); + break; + } + + return result; +} + +void +dm_stop(struct ifnet *ifp, int disable) +{ + struct dm_softc *sc = ifp->if_softc; + + /* Not quite sure what to do when called with disable == 0 */ + if( disable ) { + /* Disable RX */ + dm_write(sc, DM9000_RCR, 0x0); + } + + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); +} + +int +dm_mediachange(struct ifnet *ifp) +{ + /* TODO: Make this function do something useful. */ + return 0; +} + +void +dm_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + /* TODO: Make this function do something useful. */ + struct dm_softc *sc = ifp->if_softc; + ifmr->ifm_active = sc->sc_media.ifm_cur->ifm_media; + + if (ifp->if_flags & IFF_UP) { + ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; + } else { + ifmr->ifm_status = 0; + } +} + +void +dm_transmit(struct dm_softc *sc) +{ + u_int8_t status; + + TX_DPRINTF(("dm_transmit: PRE: txready: %d, txbusy: %d\n", sc->txready, + sc->txbusy)); + + dm_write(sc, DM9000_TXPLL, sc->txready_length & 0xFF); + dm_write(sc, DM9000_TXPLH, sc->txready_length >> 8 ); + + /* Request to send the packet */ + status = dm_read(sc, DM9000_ISR); + + dm_write(sc, DM9000_TCR, DM9000_TCR_TXREQ); + + sc->txready = 0; + sc->txbusy = 1; + sc->txready_length = 0; +} + +void +dm_receive(struct dm_softc *sc, struct ifnet *ifp) +{ + uint8_t ready = 0x01; + + while(ready == 0x01) { + /* Packet received, retrieve it */ + + /* Read without address increment to get the ready byte without moving past it. */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dm_io, DM9000_MRCMDX); + ready = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dm_data); /* Dummy ready */ + ready = bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dm_data); + if( ready == 0x01 ) { + uint8_t rx_status; + + uint16_t data; + uint16_t frame_length; + uint16_t i; + struct mbuf *m; + uint16_t *buf; + int pad; + + /* TODO: Add support for 8-bit and 32-bit transfer modes. */ + + /* Read with address increment. */ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dm_io, DM9000_MRCMD); + data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, sc->dm_data); + + rx_status = data & 0xFF; + frame_length = bus_space_read_2(sc->sc_iot, sc->sc_ioh, sc->dm_data); + + RX_DPRINTF(("dm_receive: rx_statux: 0x%x, frame_length: %d\n", + rx_status, frame_length)); + + + MGETHDR(m, M_DONTWAIT, MT_DATA); + m->m_pkthdr.rcvif = ifp; + /* Ensure that we always allocate an even number of bytes in order to avoid writing + beyond the buffer.*/ + m->m_pkthdr.len = frame_length + (frame_length % 2); + pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header); + m->m_flags |= M_HASFCS; /* All our frames have the CRC attached */ + if (m->m_pkthdr.len + pad > MHLEN ) + MCLGET(m, M_DONTWAIT); + + m->m_data += pad; + m->m_len = frame_length + (frame_length % 2); + buf = mtod(m, uint16_t*); + + RX_DPRINTF(("dm_receive: ")); + + for(i=0; i< frame_length; i+=2 ) { + data = bus_space_read_2(sc->sc_iot, sc->sc_ioh, sc->dm_data); + if ( (frame_length % 2 != 0) && (i == frame_length-1) ) { + data = data & 0xFF; + RX_DPRINTF((" L ")); + } + *buf = data; + buf++; + RX_DATA_DPRINTF(("%02X %02X ", data & 0xFF, + (data>>8) & 0xFF)); + } + + RX_DATA_DPRINTF(("\n")); + RX_DPRINTF(("Read %d bytes\n", i)); + + if (rx_status & ( DM9000_RSR_CE | DM9000_RSR_PLE ) ) { + /* Error while receiving the packet, discard it and keep track of counters. */ + ifp->if_ierrors++; + RX_DPRINTF(("dm_receive: Error reciving packet\n")); + } else if (rx_status & DM9000_RSR_LCS) { + ifp->if_collisions++; + } else { +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m); +#endif + ifp->if_ipackets++; + (*ifp->if_input)(ifp, m); + } + + } else if (ready != 0x00 ) { + /* Should this be logged somehow? */ + DPRINTF(("DM9000: Resetting chip\n")); + dm_reset(sc); + } + } +} + +void +dm_reset(struct dm_softc *sc) +{ + uint8_t var; + + /* Enable PHY */ + var = dm_read(sc, DM9000_GPCR); + dm_write(sc, DM9000_GPCR, var | 0x1 ); /* Set bit 0 to 1 */ + var = dm_read(sc, DM9000_GPR); + dm_write(sc, DM9000_GPR, var & ~0x1 ); /* Set bit 0 to 0 to enable PHY */ + + /* Reset the DM9000 twice, as describe din section 5.2 of the Application Notes */ + dm_write(sc, DM9000_NCR, DM9000_NCR_RST | DM9000_NCR_LBK_MAC_INTERNAL ); + delay(20); + dm_write(sc, DM9000_NCR, 0x0); + + dm_write(sc, DM9000_NCR, DM9000_NCR_RST | DM9000_NCR_LBK_MAC_INTERNAL); + delay(20); + dm_write(sc, DM9000_NCR, 0x0); + + /* Select internal PHY, no wakeup event, no collosion mode, normal loopback mode, and no full duplex mode */ + dm_write(sc, DM9000_NCR, DM9000_NCR_LBK_NORMAL ); + + /* Will clear TX1END, TX2END, and WAKEST fields by reading DM9000_NSR*/ + dm_read(sc, DM9000_NSR); + + /* Enable wraparound of read/write pointer, packet received latch, and packet transmitted latch. */ + dm_write(sc, DM9000_IMR, DM9000_IMR_PAR | DM9000_IMR_PRM | DM9000_IMR_PTM); + + /* Enable RX without watchdog */ + dm_write(sc, DM9000_RCR, DM9000_RCR_RXEN | DM9000_RCR_WTDIS); + + sc->txbusy = 0; + sc->txready = 0; +} Index: dev/ic/dm9000reg.h =================================================================== RCS file: dev/ic/dm9000reg.h diff -N dev/ic/dm9000reg.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/ic/dm9000reg.h 28 Dec 2009 10:35:53 -0000 @@ -0,0 +1,198 @@ +/* $NetBSD:$ */ + +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +/* Registers accesible on the DM9000, extracted from pp. 11-12 from the data sheet */ + +/* There are two interesting addresses for the DM9000 + * (at least in the context of the FriendlyARM MINI2440) + * The I/O or register select address, which is the base address. + * The DATA address, which is located at offset 4 from the base address. + * + * Chances are that this will not work generally, as it really depends on how the address lines are + * mapped from the CPU to the DM9000. But for now it is a good starting point. + */ +#define DM9000_IOSIZE 4 /* XXX: Depends on the wiring of the address lines. */ + +#define DM9000_NCR 0x00 +#define DM9000_NCR_RST (1 << 0) +#define DM9000_NCR_LBK_MASK (0x06) +#define DM9000_NCR_LBK_SHIFT (1) +#define DM9000_NCR_LBK_MAC_INTERNAL ( 1 << DM9000_NCR_LBK_SHIFT ) +#define DM9000_NCR_LBK_NORMAL ( 0 << DM9000_NCR_LBK_SHIFT) +#define DM9000_NCR_LBK_INT_PHY ( 2 << DM9000_NCR_LBK_SHIFT) +#define DM9000_NCR_FDX (1 << 3) +#define DM9000_NCR_FCOL (1 << 4) +#define DM9000_NCR_WAKEEN (1 << 6) +#define DM9000_NCR_EXY_PHY (1 << 7) +#define DM9000_NSR 0x01 +#define DM9000_NSR_RXOV (1 << 1) +#define DM9000_NSR_TX1END (1 << 2) +#define DM9000_NSR_TX2END (1 << 3) +#define DM9000_NSR_WAKEST (1 << 5) +#define DM9000_NSR_LINKST (1 << 6) +#define DM9000_NSR_SPEED (1 << 7) +#define DM9000_TCR 0x02 +#define DM9000_TCR_TXREQ (1 << 0) +#define DM9000_TCR_CRC_DIS1 (1 << 1) +#define DM9000_TCR_PAD_DIS1 (1 << 2) +#define DM9000_TCR_CRC_DIS2 (1 << 3) +#define DM9000_TCR_PAD_DIS2 (1 << 4) +#define DM9000_TCR_EXCECM (1 << 5) +#define DM9000_TCR_TJDIS (1 << 6) +#define DM9000_TSR1 0x03 +#define DM9000_TSR2 0x04 +#define DM9000_RCR 0x05 +#define DM9000_RCR_RXEN (1 << 0) +#define DM9000_RCR_PRMSC (1 << 1) +#define DM9000_RCR_RUNT (1 << 2) +#define DM9000_RCR_ALL (1 << 3) +#define DM9000_RCR_DIS_CRC (1 << 4) +#define DM9000_RCR_DIS_LONG (1 << 5) +#define DM9000_RCR_WTDIS (1 << 6) +#define DM9000_RSR 0x06 +#define DM9000_RSR_FOE (1<<0) +#define DM9000_RSR_CE (1<<1) +#define DM9000_RSR_AE (1<<2) +#define DM9000_RSR_PLE (1<<3) +#define DM9000_RSR_RWTO (1<<4) +#define DM9000_RSR_LCS (1<<5) +#define DM9000_RSR_MF (1<<6) +#define DM9000_RSR_RF (1<<7) +#define DM9000_ROCR 0x07 +#define DM9000_BPTR 0x08 +#define DM9000_FCTR 0x09 +#define DM9000_FCR 0x0A +#define DM9000_FCR_FLCE (1 << 0) +#define DM9000_FCR_RXPCS (1 << 1) +#define DM9000_FCR_RXPS (1 << 2) +#define DM9000_FCR_BKPM (1 << 3) +#define DM9000_FCR_BKPA (1 << 4) +#define DM9000_FCR_TXPEN (1 << 5) +#define DM9000_FCR_TXPF (1 << 6) +#define DM9000_FCR_TXP0 (1 << 7) +#define DM9000_EPCR 0x0B +#define DM9000_EPCR_ERRE (1 << 0) +#define DM9000_EPCR_ERPRW (1 << 1) +#define DM9000_EPCR_ERPRR (1 << 2) +#define DM9000_EPCR_EPOS_EEPROM (0 << 3) +#define DM9000_EPCR_EPOS_PHY (1 << 3) +#define DM9000_EPCR_WEP (1 << 4) +#define DM9000_EPCR_REEP (1 << 5) +#define DM9000_EPAR 0x0C +#define DM9000_EPAR_EROA_MASK 0x3F /* bits 0-5 */ +#define DM9000_EPAR_INT_PHY 0x40 /* EPAR[7:6] = 01 for internal PHY */ +#define DM9000_EPDRL 0x0D +#define DM9000_EPDRH 0x0E +#define DM9000_WCR 0x0F + +#define DM9000_PAB0 0x10 +#define DM9000_PAB1 0x11 +#define DM9000_PAB2 0x12 +#define DM9000_PAB3 0x13 +#define DM9000_PAB4 0x14 +#define DM9000_PAB5 0x15 + +#define DM9000_MAB0 0x16 +#define DM9000_MAB1 0x17 +#define DM9000_MAB2 0x18 +#define DM9000_MAB3 0x19 +#define DM9000_MAB4 0x1A +#define DM9000_MAB5 0x1B +#define DM9000_MAB6 0x1C +#define DM9000_MAB7 0x1D + +#define DM9000_GPCR 0x1E +#define DM9000_GPR 0x1F +#define DM9000_TRPAL 0x22 +#define DM9000_TRPAH 0x23 +#define DM9000_RWPAL 0x24 +#define DM9000_RWPAH 0x25 + +#define DM9000_VID0 0x28 +#define DM9000_VID1 0x29 + +#define DM9000_PID0 0x2A +#define DM9000_PID1 0x2B + +#define DM9000_CHIPR 0x2C +#define DM9000_SMCR 0x2F +#define DM9000_MRCMDX 0xF0 +#define DM9000_MRCMD 0xF2 +#define DM9000_MRRL 0xF4 +#define DM9000_MRRH 0xF5 +#define DM9000_MWCMDX 0xF6 +#define DM9000_MWCMD 0xF8 +#define DM9000_MWRL 0xFA +#define DM9000_MWRH 0xFB +#define DM9000_TXPLL 0xFC +#define DM9000_TXPLH 0xFD +#define DM9000_ISR 0xFE +#define DM9000_IOMODE_MASK 0xC0 +#define DM9000_IOMODE_SHIFT 6 +#define DM9000_ISR_PRS (1<<0) +#define DM9000_ISR_PTS (1<<1) +#define DM9000_ISR_ROS (1<<2) +#define DM9000_ISR_ROOS (1<<3) +#define DM9000_IMR 0xFF +#define DM9000_IMR_PRM (1<<0) +#define DM9000_IMR_PTM (1<<1) +#define DM9000_IMR_ROM (1<<2) +#define DM9000_IMR_ROOM (1<<3) +#define DM9000_IMR_PAR (1<<7) + +#define DM9000_PHY_BMCR 0x00 +#define DM9000_PHY_BMCR_COLL_TEST (1<<7) +#define DM9000_PHY_BMCR_DUPLEX_MODE (1<<8) +#define DM9000_PHY_BMCR_RESTART_AN (1<<9) +#define DM9000_PHY_BMCR_ISOLATE (1<<10) +#define DM9000_PHY_BMCR_POWER_DOWN (1<<11) +#define DM9000_PHY_BMCR_AUTO_NEG_EN (1<<12) +#define DM9000_PHY_BMCR_SPEED_SELECT (1<<13) +#define DM9000_PHY_BMCR_LOOPBACK (1<<14) +#define DM9000_PHY_BMCR_RESET (1<<15) +#define DM9000_PHY_BMSR 0x01 +#define DM9000_PHY_BMSR_EXT_CAP (1<<0) +#define DM9000_PHY_BMSR_JAB_DET (1<<1) +#define DM9000_PHY_BMSR_LINK_ST (1<<2) +#define DM9000_PHY_BMSR_AUTO_NEG_AB (1<<3) +#define DM9000_PHY_BMSR_REMOTE_FAULT (1<<4) +#define DM9000_PHY_BMSR_AUTO_NEG_COM (1<<5) +#define DM9000_PHY_BMSR_MF_PRE_SUP (1<<6) +#define DM9000_PHY_BMSR_10BASE_HALF_DUPLEX (1<<11) +#define DM9000_PHY_BMSR_10BASE_FULL_DUPLEX (1<<12) +#define DM9000_PHY_BMSR_100BASE_HALF_DUPLEX (1<<13) +#define DM9000_PHY_BMSR_100BASE_FULL_DUPLEX (1<<14) +#define DM9000_PHY_BMSR_100BASE_T4 (1<<15) +#define DM9000_PHY_PHYID1 0x02 +#define DM9000_PHY_PHYID2 0x03 +#define DM9000_PHY_ANAR 0x04 +#define DM9000_PHY_ANLPAR 0x05 +#define DM9000_PHY_ANER 0x06 +#define DM9000_PHY_DSCR 0x16 +#define DM9000_PHY_DSCSR 0x17 +#define DM9000_PHY_10BTCSR 0x18 Index: dev/ic/dm9000var.h =================================================================== RCS file: dev/ic/dm9000var.h diff -N dev/ic/dm9000var.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/ic/dm9000var.h 28 Dec 2009 10:35:53 -0000 @@ -0,0 +1,142 @@ +/* $NetBSD:$ */ + +/* + * Copyright (c) 2009 Paul Fleischer + * All rights reserved. + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the 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. + */ + +/* Based on sys/dev/ic/cs89x0var.h */ +/* + * Copyright 1997 + * Digital Equipment Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and conditions. + * Subject to these conditions, you may download, copy, install, + * use, modify and distribute this software in source and/or binary + * form. No title or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions as + * they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or logo of + * Digital Equipment Corporation. Neither the "Digital Equipment + * Corporation" name nor any trademark or logo of Digital Equipment + * Corporation may be used to endorse or promote products derived + * from this software without the prior written permission of + * Digital Equipment Corporation. + * + * 3) This software is provided "AS-IS" and any express or implied + * warranties, including but not limited to, any implied warranties + * of merchantability, fitness for a particular purpose, or + * non-infringement are disclaimed. In no event shall DIGITAL be + * liable for any damages whatsoever, and in particular, DIGITAL + * shall not be liable for special, indirect, consequential, or + * incidental damages or damages for lost profits, loss of + * revenue or loss of use, whether such damages arise in contract, + * negligence, tort, under statute, in equity, at law or otherwise, + * even if advised of the possibility of such damage. + */ + +#ifndef _DEV_IC_DM9000VAR_H_ +#define _DEV_IC_DM9000VAR_H_ + +#include + +#define DM9000_MODE_8BIT 2 +#define DM9000_MODE_16BIT 0 +#define DM9000_MODE_32BIT 1 + +struct dm_softc { + struct device sc_dev; /* Generic Base Device */ + + struct ethercom sc_ethercom; /* Ethernet common data */ + struct ifmedia sc_media; /* Media control structures */ + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + void *sc_ih; + + uint dm_io; + uint dm_data; + + uint16_t vendorId; + uint16_t productId; + + uint16_t io_mode; + + u_int8_t sc_enaddr[ETHER_ADDR_LEN]; + + int txbusy; /* A packet is being transmitted. */ + int txready; /* A packet has been sent to the DM9000 + for transmission. */ + u_int16_t txready_length; +}; + +/* Function declarations */ +int dm_attach(struct dm_softc *, uint8_t *); +int dm_detach(struct dm_softc *); +int dm_intr(void *); + +/* Inline memory access methods */ +static inline uint8_t +dm_read(struct dm_softc *sc, int reg) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dm_io, reg); + return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->dm_data)); +} + +static inline void +dm_write(struct dm_softc *sc, int reg, uint8_t value) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dm_io, reg); + bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dm_data, value); +} + +static inline void +dm_write2(struct dm_softc *sc, int reg, uint16_t value) +{ + bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->dm_io, reg); + bus_space_write_2(sc->sc_iot, sc->sc_ioh, sc->dm_data, value); +} + +static inline void +dm_write_c(struct dm_softc *sc, int reg, uint8_t value[], uint count) +{ + for(int i=0; i