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.
This commit is contained in:
parent
7e7f083f94
commit
b44f8e5e1e
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
at91_rst_attach(device_t dev)
|
||||
at91rst_probe(device_t dev)
|
||||
{
|
||||
struct rst_softc *sc;
|
||||
|
||||
device_set_desc(dev, "AT91SAM9 Reset Controller");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
at91rst_attach(device_t dev)
|
||||
{
|
||||
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(;;)
|
||||
;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user