summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2012-06-15 08:37:50 +0000
committerimp <imp@FreeBSD.org>2012-06-15 08:37:50 +0000
commit88f68062a5f9d1e85489c6f104cc59e12b41c7bb (patch)
tree9c000993641ecca80a8e61c6a9d90d36c19c762c
parent968a30af3f039378ca81b54c0f3ba5cdd06dcb58 (diff)
downloadFreeBSD-src-88f68062a5f9d1e85489c6f104cc59e12b41c7bb.zip
FreeBSD-src-88f68062a5f9d1e85489c6f104cc59e12b41c7bb.tar.gz
Make it possible to link together a sam and an rm kernel. The results
aren't very pretty yet, but this takes DELAY and cpu_reset and makes them pointers. # I worry that these are set too late in the boot, especially cpu_reset.
-rw-r--r--sys/arm/at91/at91_machdep.c27
-rw-r--r--sys/arm/at91/at91_pit.c63
-rw-r--r--sys/arm/at91/at91_rst.c107
-rw-r--r--sys/arm/at91/at91_st.c70
-rw-r--r--sys/arm/at91/at91var.h5
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;
OpenPOWER on IntegriCloud