diff options
-rw-r--r-- | sys/arm/at91/at91_machdep.c | 27 | ||||
-rw-r--r-- | sys/arm/at91/at91_pit.c | 63 | ||||
-rw-r--r-- | sys/arm/at91/at91_rst.c | 107 | ||||
-rw-r--r-- | sys/arm/at91/at91_st.c | 70 | ||||
-rw-r--r-- | sys/arm/at91/at91var.h | 5 |
5 files changed, 149 insertions, 123 deletions
diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c index 63aa644..b0508de 100644 --- a/sys/arm/at91/at91_machdep.c +++ b/sys/arm/at91/at91_machdep.c @@ -201,11 +201,22 @@ const struct pmap_devmap at91_devmap[] = { { 0, 0, 0, 0, 0, } }; +#ifdef LINUX_BOOT_ABI +extern int membanks; +extern int memstart[]; +extern int memsize[]; +#endif + long at91_ramsize(void) { uint32_t cr, mr; int banks, rows, cols, bw; +#ifdef LINUX_BOOT_ABI + // If we found any ATAGs that were for memory, return the first bank. + if (membanks > 0) + return memsize[0]; +#endif if (at91_is_rm92()) { uint32_t *SDRAMC = (uint32_t *)(AT91_BASE + AT91RM92_SDRAMC_BASE); @@ -593,3 +604,19 @@ cpu_initclocks(void) { } + +void +DELAY(int n) +{ + if (soc_data.delay) + soc_data.delay(n); +} + +void +cpu_reset(void) +{ + if (soc_data.reset) + soc_data.reset(); + while (1) + continue; +} diff --git a/sys/arm/at91/at91_pit.c b/sys/arm/at91/at91_pit.c index 4eb8f0f..2a9656a 100644 --- a/sys/arm/at91/at91_pit.c +++ b/sys/arm/at91/at91_pit.c @@ -48,6 +48,10 @@ __FBSDID("$FreeBSD$"); #include <arm/at91/at91var.h> #include <arm/at91/at91_pitreg.h> +#ifndef PIT_PRESCALE +#define PIT_PRESCALE (16) +#endif + static struct pit_softc { struct resource *mem_res; /* Memory resource */ void *intrhand; /* Interrupt handle */ @@ -55,6 +59,8 @@ static struct pit_softc { } *sc; static uint32_t timecount = 0; +static unsigned at91pit_get_timecount(struct timecounter *tc); +static int pit_intr(void *arg); static inline uint32_t RD4(struct pit_softc *sc, bus_size_t off) @@ -70,12 +76,28 @@ WR4(struct pit_softc *sc, bus_size_t off, uint32_t val) bus_write_4(sc->mem_res, off, val); } -static unsigned at91pit_get_timecount(struct timecounter *tc); -static int pit_intr(void *arg); +static void +at91pit_delay(int us) +{ + int32_t cnt, last, piv; + uint64_t pit_freq; + const uint64_t mhz = 1E6; -#ifndef PIT_PRESCALE -#define PIT_PRESCALE (16) -#endif + last = PIT_PIV(RD4(sc, PIT_PIIR)); + + /* Max delay ~= 260s. @ 133Mhz */ + pit_freq = at91_master_clock / PIT_PRESCALE; + cnt = ((pit_freq * us) + (mhz -1)) / mhz; + cnt = (cnt <= 0) ? 1 : cnt; + + while (cnt > 0) { + piv = PIT_PIV(RD4(sc, PIT_PIIR)); + cnt -= piv - last ; + if (piv < last) + cnt -= PIT_PIV(~0u) - last; + last = piv; + } +} static struct timecounter at91pit_timecounter = { at91pit_get_timecount, /* get_timecount */ @@ -90,11 +112,8 @@ static int at91pit_probe(device_t dev) { - if (at91_is_sam9() || at91_is_sam9xe()) { - device_set_desc(dev, "AT91SAM9 PIT"); - return (0); - } - return (ENXIO); + device_set_desc(dev, "AT91SAM9 PIT"); + return (0); } static int @@ -135,6 +154,7 @@ at91pit_attach(device_t dev) /* Enable the PIT here. */ WR4(sc, PIT_MR, PIT_PIV(at91_master_clock / PIT_PRESCALE / hz) | PIT_EN | PIT_IEN); + soc_data.delay = at91pit_delay; out: return (err); } @@ -183,26 +203,3 @@ at91pit_get_timecount(struct timecounter *tc) icnt = piir >> 20; /* Overflows */ return (timecount + PIT_PIV(piir) + PIT_PIV(RD4(sc, PIT_MR)) * icnt); } - -void -DELAY(int us) -{ - int32_t cnt, last, piv; - uint64_t pit_freq; - const uint64_t mhz = 1E6; - - last = PIT_PIV(RD4(sc, PIT_PIIR)); - - /* Max delay ~= 260s. @ 133Mhz */ - pit_freq = at91_master_clock / PIT_PRESCALE; - cnt = ((pit_freq * us) + (mhz -1)) / mhz; - cnt = (cnt <= 0) ? 1 : cnt; - - while (cnt > 0) { - piv = PIT_PIV(RD4(sc, PIT_PIIR)); - cnt -= piv - last ; - if (piv < last) - cnt -= PIT_PIV(~0u) - last; - last = piv; - } -} diff --git a/sys/arm/at91/at91_rst.c b/sys/arm/at91/at91_rst.c index 76cc43c..dbd041b 100644 --- a/sys/arm/at91/at91_rst.c +++ b/sys/arm/at91/at91_rst.c @@ -42,50 +42,70 @@ __FBSDID("$FreeBSD$"); #define RST_TIMEOUT (5) /* Seconds to hold NRST for hard reset */ #define RST_TICK (20) /* sample NRST at hz/RST_TICK intervals */ -static int rst_intr(void *arg); +static int at91rst_intr(void *arg); -static struct rst_softc { +static struct at91rst_softc { struct resource *mem_res; /* Memory resource */ struct resource *irq_res; /* IRQ resource */ void *intrhand; /* Interrupt handle */ struct callout tick_ch; /* Tick callout */ device_t sc_dev; u_int shutdown; /* Shutdown in progress */ -} *rst_sc; +} *at91rst_sc; static inline uint32_t -RD4(struct rst_softc *sc, bus_size_t off) +RD4(struct at91rst_softc *sc, bus_size_t off) { return (bus_read_4(sc->mem_res, off)); } static inline void -WR4(struct rst_softc *sc, bus_size_t off, uint32_t val) +WR4(struct at91rst_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } -static int -at91_rst_probe(device_t dev) +void cpu_reset_sam9g20(void) __attribute__((weak)); +void cpu_reset_sam9g20(void) {} + +static void +at91rst_cpu_reset(void) { - if (at91_is_sam9() || at91_is_sam9xe()) { - device_set_desc(dev, "AT91SAM9 Reset Controller"); - return (0); + if (at91rst_sc) { + cpu_reset_sam9g20(); /* May be null */ + + WR4(at91rst_sc, RST_MR, + RST_MR_ERSTL(0xd) | RST_MR_URSTEN | RST_MR_KEY); + + WR4(at91rst_sc, RST_CR, + RST_CR_PROCRST | + RST_CR_PERRST | + RST_CR_EXTRST | + RST_CR_KEY); } - return (ENXIO); + while(1) + continue; +} + +static int +at91rst_probe(device_t dev) +{ + + device_set_desc(dev, "AT91SAM9 Reset Controller"); + return (0); } static int -at91_rst_attach(device_t dev) +at91rst_attach(device_t dev) { - struct rst_softc *sc; + struct at91rst_softc *sc; const char *cause; int rid, err; - rst_sc = sc = device_get_softc(dev); + at91rst_sc = sc = device_get_softc(dev); sc->sc_dev = dev; callout_init(&sc->tick_ch, 0); @@ -109,11 +129,11 @@ at91_rst_attach(device_t dev) /* Activate the interrupt. */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, - rst_intr, NULL, sc, &sc->intrhand); + at91rst_intr, NULL, sc, &sc->intrhand); if (err) device_printf(dev, "could not establish interrupt handler.\n"); - WR4(rst_sc, RST_MR, RST_MR_ERSTL(0xd) | RST_MR_URSIEN | RST_MR_KEY); + WR4(at91rst_sc, RST_MR, RST_MR_ERSTL(0xd) | RST_MR_URSIEN | RST_MR_KEY); switch (RD4(sc, RST_SR) & RST_SR_RST_MASK) { case RST_SR_RST_POW: @@ -137,16 +157,15 @@ at91_rst_attach(device_t dev) } device_printf(dev, "Reset cause: %s.\n", cause); - /* cpu_reset_addr = cpu_reset; */ - + soc_data.reset = at91rst_cpu_reset; out: return (err); } static void -rst_tick(void *argp) +at91rst_tick(void *argp) { - struct rst_softc *sc = argp; + struct at91rst_softc *sc = argp; if (sc->shutdown++ >= RST_TIMEOUT * RST_TICK) { /* User released the button in morre than RST_TIMEOUT */ @@ -157,60 +176,36 @@ rst_tick(void *argp) device_printf(sc->sc_dev, "shutting down...\n"); shutdown_nice(0); } else { - callout_reset(&sc->tick_ch, hz/RST_TICK, rst_tick, sc); + callout_reset(&sc->tick_ch, hz/RST_TICK, at91rst_tick, sc); } } static int -rst_intr(void *argp) +at91rst_intr(void *argp) { - struct rst_softc *sc = argp; + struct at91rst_softc *sc = argp; if (RD4(sc, RST_SR) & RST_SR_URSTS) { if (sc->shutdown == 0) - callout_reset(&sc->tick_ch, hz/RST_TICK, rst_tick, sc); + callout_reset(&sc->tick_ch, hz/RST_TICK, at91rst_tick, sc); return (FILTER_HANDLED); } return (FILTER_STRAY); } -static device_method_t at91_rst_methods[] = { - DEVMETHOD(device_probe, at91_rst_probe), - DEVMETHOD(device_attach, at91_rst_attach), +static device_method_t at91rst_methods[] = { + DEVMETHOD(device_probe, at91rst_probe), + DEVMETHOD(device_attach, at91rst_attach), DEVMETHOD_END }; -static driver_t at91_rst_driver = { +static driver_t at91rst_driver = { "at91_rst", - at91_rst_methods, - sizeof(struct rst_softc), + at91rst_methods, + sizeof(struct at91rst_softc), }; -static devclass_t at91_rst_devclass; +static devclass_t at91rst_devclass; -DRIVER_MODULE(at91_rst, atmelarm, at91_rst_driver, at91_rst_devclass, NULL, +DRIVER_MODULE(at91_rst, atmelarm, at91rst_driver, at91rst_devclass, NULL, NULL); - -void cpu_reset_sam9g20(void) __attribute__((weak)); -void cpu_reset_sam9g20(void) {} - -void -cpu_reset(void) -{ - - if (rst_sc) { - cpu_reset_sam9g20(); /* May be null */ - - WR4(rst_sc, RST_MR, - RST_MR_ERSTL(0xd) | RST_MR_URSTEN | RST_MR_KEY); - - WR4(rst_sc, RST_CR, - RST_CR_PROCRST | - RST_CR_PERRST | - RST_CR_EXTRST | - RST_CR_KEY); - } - - for(;;) - ; -} diff --git a/sys/arm/at91/at91_st.c b/sys/arm/at91/at91_st.c index 6203fb2e..6a3284e 100644 --- a/sys/arm/at91/at91_st.c +++ b/sys/arm/at91/at91_st.c @@ -84,6 +84,40 @@ static struct timecounter at91st_timecounter = { 1000 /* quality */ }; +static void +at91st_delay(int n) +{ + uint32_t start, end, cur; + + start = st_crtr(); + n = (n * 1000) / 32768; + if (n <= 0) + n = 1; + end = (start + n) & ST_CRTR_MASK; + cur = start; + if (start > end) { + while (cur >= start || cur < end) + cur = st_crtr(); + } else { + while (cur < end) + cur = st_crtr(); + } +} + +static void +at91st_cpu_reset(void) +{ + /* + * Reset the CPU by programmig the watchdog timer to reset the + * CPU after 128 'slow' clocks, or about ~4ms. Loop until + * the reset happens for safety. + */ + WR4(ST_WDMR, ST_WDMR_RSTEN | 2); + WR4(ST_CR, ST_CR_WDRST); + while (1) + continue; +} + static int at91st_probe(device_t dev) { @@ -112,6 +146,8 @@ at91st_attach(device_t dev) WR4(ST_IDR, 0xffffffff); /* disable watchdog timer */ WR4(ST_WDMR, 0); + soc_data.delay = at91st_delay; + soc_data.reset = at91st_cpu_reset; // XXX kinda late to be setting this... timer_softc->sc_wet = EVENTHANDLER_REGISTER(watchdog_list, at91st_watchdog, dev, 0); @@ -221,37 +257,3 @@ at91st_initclocks(struct at91st_softc *sc) WR4(ST_IER, ST_SR_PITS); tc_init(&at91st_timecounter); } - -void -DELAY(int n) -{ - uint32_t start, end, cur; - - start = st_crtr(); - n = (n * 1000) / 32768; - if (n <= 0) - n = 1; - end = (start + n) & ST_CRTR_MASK; - cur = start; - if (start > end) { - while (cur >= start || cur < end) - cur = st_crtr(); - } else { - while (cur < end) - cur = st_crtr(); - } -} - -void -cpu_reset(void) -{ - /* - * Reset the CPU by programmig the watchdog timer to reset the - * CPU after 128 'slow' clocks, or about ~4ms. Loop until - * the reset happens for safety. - */ - WR4(ST_WDMR, ST_WDMR_RSTEN | 2); - WR4(ST_CR, ST_CR_WDRST); - while (1) - continue; -} diff --git a/sys/arm/at91/at91var.h b/sys/arm/at91/at91var.h index a8df717..7a3ce95 100644 --- a/sys/arm/at91/at91var.h +++ b/sys/arm/at91/at91var.h @@ -102,6 +102,9 @@ enum at91_soc_family { #define AT91_SOC_NAME_MAX 50 +typedef void (*DELAY_t)(int); +typedef void (*cpu_reset_t)(void); + struct at91_soc_info { enum at91_soc_type type; enum at91_soc_subtype subtype; @@ -109,6 +112,8 @@ struct at91_soc_info { uint32_t cidr; uint32_t exid; char name[AT91_SOC_NAME_MAX]; + DELAY_t delay; + cpu_reset_t reset; }; extern struct at91_soc_info soc_data; |