This set of fixes pushes AM335x support closer to working. With these patches and the previously submitted bootloader fix (https://github.com/seL4/elfloader-tool/issues/2) sel4 can boot and the sel4test project can run through some of the test cases. There are still some notable ommissions like missing timer and uart features and lack of uart IRQ support. - sel4 kernel - fix up sel4 kernel support for the am335x timer - note: this still receives lots of spurious interrupts - libplatsupport - bring code into line with conventions used by other ports - bring the uart code to life. PIO only for now - support multiple timers - libsel4platsupport - bring code into line with conventions used by other ports project kernel/ diff --git a/src/plat/am335x/machine/hardware.c b/src/plat/am335x/machine/hardware.c index 199baf0..130b71e 100644 --- a/src/plat/am335x/machine/hardware.c +++ b/src/plat/am335x/machine/hardware.c @@ -108,6 +108,11 @@ map_kernel_devices(void) #endif } + +#define INTCPS_SYSCONFIG_SOFTRESET BIT(1) +#define INTCPS_SYSSTATUS_RESETDONE BIT(0) +#define INTCPS_SIR_IRQ_SPURIOUSIRQFLAG 0xffffff80 + /* * The struct below is used to discourage the compiler from generating literals * for every single address we might access. @@ -136,9 +141,8 @@ volatile struct INTC_map { uint32_t intcps_isr_clear; uint32_t intcps_pending_irq; uint32_t intcps_pending_fiq; - } intcps_n[3]; - uint32_t padding5[8]; - uint32_t intcps_ilr[96]; + } intcps_n[4]; + uint32_t intcps_ilr[128]; } *intc = (volatile void*)INTC_PPTR; /** @@ -148,23 +152,31 @@ volatile struct INTC_map { interrupt_t getActiveIRQ(void) { - interrupt_t irq = intc->intcps_sir_irq; + uint32_t intcps_sir_irq = intc->intcps_sir_irq; + interrupt_t irq = (interrupt_t)(intcps_sir_irq & 0x7f); + /* Ignore spurious interrupts. */ - if ((irq & ~0b1111111) == 0) { - assert(irq <= maxIRQ); + if ((intcps_sir_irq & INTCPS_SIR_IRQ_SPURIOUSIRQFLAG) == 0) { + assert((irq / 32) < (sizeof intc->intcps_n / sizeof intc->intcps_n[0])); if (intc->intcps_n[irq / 32].intcps_pending_irq & (1 << (irq & 31))) { return irq; + } else { + // XXX why is this happening for IRQ 66?! + //printf("spurious irq - %d not pending\n", irq); } + } else { + /* should never happen */ + printf("spurious irq %d / %x\n", irq, intcps_sir_irq); } - + /* No interrupt. */ - return 0xff; + return irqInvalid; } /* Check for pending IRQ */ bool_t isIRQPending(void) { - return getActiveIRQ() != 0xff; + return getActiveIRQ() != irqInvalid; } /* Enable or disable irq according to the 'disable' flag. */ @@ -185,16 +197,16 @@ maskInterrupt(bool_t disable, interrupt_t irq) bool_t isReservedIRQ(interrupt_t irq) { - return false; + return irq == KERNEL_TIMER_IRQ; } /* Handle a platform-reserved IRQ. */ void handleReservedIRQ(irq_t irq) { + printf("Received reserved IRQ: %d\n", (int)irq); /* We shouldn't be receiving any reserved IRQs anyway. */ - maskInterrupt(true, irq); - - return; + //maskInterrupt(true, irq); + //return; } void @@ -269,10 +281,11 @@ initTimer(void) for (timeout = 10000; (timer->cfg & TIOCP_CFG_SOFTRESET) && timeout > 0; timeout--) ; if (!timeout) { + printf("init timer failed\n"); return; } - maskInterrupt(/*disable*/ true, DMTIMER0_IRQ); + //maskInterrupt(/*disable*/ true, DMTIMER0_IRQ); /* Set the reload value */ timer->tldr = 0xFFFFFFFFUL - TIMER_INTERVAL_TICKS; @@ -293,12 +306,15 @@ initTimer(void) BOOT_CODE void initIRQController(void) { - /* Do nothing */ + intc->intcps_sysconfig = INTCPS_SYSCONFIG_SOFTRESET; + while (!(intc->intcps_sysstatus & INTCPS_SYSSTATUS_RESETDONE)) ; } void handleSpuriousIRQ(void) { - /* Do nothing */ + /* Reset and re-enable IRQs. */ + intc->intcps_control = 1; + dsb(); } project libs/libplatsupport/ diff --git a/plat_include/am335x/platsupport/plat/dm.h b/plat_include/am335x/platsupport/plat/dm.h deleted file mode 100644 index 1053d7f..0000000 --- a/plat_include/am335x/platsupport/plat/dm.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2014, NICTA - * - * This software may be distributed and modified according to the terms of - * the BSD 2-Clause license. Note that NO WARRANTY is provided. - * See "LICENSE_BSD2.txt" for details. - * - * @TAG(NICTA_BSD) - */ - -#ifndef __PLAT_SUPPORT_EPIT_H -#define __PLAT_SUPPORT_EPIT_H - -#include - -#define DMTIMER2_PADDR 0x48040000 -#define DMTIMER2_INTERRUPT 68 - -/** - * Get the dm timer interface. - * - * @param vaddr that DMTIMER2_PADDR is mapped in to. - * @return NULL on error. - */ -pstimer_t *dm_get_timer(void *vaddr); - -#endif /* __PLAT_SUPPORT_EPIT_H */ diff --git a/plat_include/am335x/platsupport/plat/mux.h b/plat_include/am335x/platsupport/plat/mux.h index 538df72..34e8763 100644 --- a/plat_include/am335x/platsupport/plat/mux.h +++ b/plat_include/am335x/platsupport/plat/mux.h @@ -11,7 +11,7 @@ #define _PLATSUPPORT_PLAT_MUX_H enum mux_feature { - NMUX_FEATURES = 0 + NMUX_FEATURES }; #endif /* _PLATSUPPORT_PLAT_MUX_H */ diff --git a/plat_include/am335x/platsupport/plat/timer.h b/plat_include/am335x/platsupport/plat/timer.h index 4cbbfc6..b99be6d 100644 --- a/plat_include/am335x/platsupport/plat/timer.h +++ b/plat_include/am335x/platsupport/plat/timer.h @@ -10,6 +10,57 @@ #ifndef _PLATSUPPORT_PLAT_TIMER_H #define _PLATSUPPORT_PLAT_TIMER_H -#include +/* Memory maps */ +#define DMTIMER2_PADDR 0x48040000 +#define DMTIMER3_PADDR 0x48042000 +#define DMTIMER4_PADDR 0x48044000 +#define DMTIMER5_PADDR 0x48046000 +#define DMTIMER6_PADDR 0x48048000 +#define DMTIMER7_PADDR 0x4804A000 + +/* IRQs */ +#define DMTIMER2_INTERRUPT 68 +#define DMTIMER3_INTERRUPT 69 +#define DMTIMER4_INTERRUPT 92 +#define DMTIMER5_INTERRUPT 93 +#define DMTIMER6_INTERRUPT 94 +#define DMTIMER7_INTERRUPT 95 + +/* Timers */ +enum timer_id { + DMTIMER2, + DMTIMER3, + DMTIMER4, + DMTIMER5, + DMTIMER6, + DMTIMER7, + NTIMERS +}; +#define TMR_DEFAULT DMTIMER2 + +static const uintptr_t dm_timer_paddrs[] = { + [DMTIMER2] = DMTIMER2_PADDR, + [DMTIMER3] = DMTIMER3_PADDR, + [DMTIMER4] = DMTIMER4_PADDR, + [DMTIMER5] = DMTIMER5_PADDR, + [DMTIMER6] = DMTIMER6_PADDR, + [DMTIMER7] = DMTIMER7_PADDR, +}; + +static const int dm_timer_irqs[] = { + [DMTIMER2] = DMTIMER2_INTERRUPT, + [DMTIMER3] = DMTIMER3_INTERRUPT, + [DMTIMER4] = DMTIMER4_INTERRUPT, + [DMTIMER5] = DMTIMER5_INTERRUPT, + [DMTIMER6] = DMTIMER6_INTERRUPT, + [DMTIMER7] = DMTIMER7_INTERRUPT, +}; + +typedef struct { + /* vaddr pwm is mapped to */ + void *vaddr; +} timer_config_t; + +pstimer_t *ps_get_timer(enum timer_id id, timer_config_t *config); #endif /* _PLATSUPPORT_PLAT_TIMER_H */ diff --git a/src/plat/am335x/dm.c b/src/plat/am335x/dm.c index 6c5777c..1417800 100644 --- a/src/plat/am335x/dm.c +++ b/src/plat/am335x/dm.c @@ -8,11 +8,14 @@ * @TAG(NICTA_BSD) */ -#include -#include #include #include +#include + +#include +#include + #define TIOCP_CFG_SOFTRESET BIT(0) #define TIER_MATCHENABLE BIT(0) @@ -51,25 +54,28 @@ typedef volatile struct dm { } dm_t; static int -dm_stop_timer(const pstimer_t *device) +dm_timer_stop(const pstimer_t *timer) { dm_t *dm = (dm_t *) timer->data; /* Disable timer. */ dm->tier = 0; dm->tclr = 0; dm->tisr = TISR_OVF_FLAG; + return 0; } static int -dm_start_timer(const pstimer_t *device) +dm_timer_start(const pstimer_t *timer) { /* Do nothing */ + return 0; } static int -dm_periodic(uint64_t ns) +dm_periodic(const pstimer_t *timer, uint64_t ns) { + dm_t *dm = (dm_t *) timer->data; /* Stop time. */ dm->tclr = 0; @@ -82,6 +88,7 @@ dm_periodic(uint64_t ns) dm->tier = TIER_OVERFLOWENABLE; /* Set the reload value. */ + /* XXX handle invalid arguments with an error return */ dm->tldr = ~0UL - TIMER_INTERVAL_TICKS(ns); /* Reset the read register. */ @@ -92,17 +99,18 @@ dm_periodic(uint64_t ns) /* Set autoreload and start the timer. */ dm->tclr = TCLR_AUTORELOAD | TCLR_STARTTIMER; + return 0; } static int -dm_oneshot_absolute(uint64_t ns) +dm_oneshot_absolute(const pstimer_t *timer, uint64_t ns) { assert(!"Not implemented"); return ENOSYS; } static int -dm_oneshot_relative(uint64_t ns) +dm_oneshot_relative(const pstimer_t *timer, uint64_t ns) { assert(!"Not implemented"); return ENOSYS; @@ -116,7 +124,7 @@ dm_get_time(const pstimer_t *timer) } static void -dm_handle_irq(const pstimer_t *timer) +dm_handle_irq(const pstimer_t *timer, uint32_t irq) { /* nothing */ } @@ -124,7 +132,7 @@ dm_handle_irq(const pstimer_t *timer) static uint32_t dm_get_nth_irq(const pstimer_t *timer, uint32_t n) { - return DMTIMER2_INTTERRUPT; + return DMTIMER2_INTERRUPT; } static pstimer_t singleton_timer; @@ -135,8 +143,8 @@ dm_get_timer(void *vaddr) pstimer_t *timer = &singleton_timer; timer->properties.upcounter = false; - timer->properties.timeouts = 1; - timer->properties.bitwidth = 32; + timer->properties.timeouts = true; + timer->properties.bit_width = 32; timer->properties.irqs = 1; /* data just points to the dm itself for now */ diff --git a/src/plat/am335x/serial.c b/src/plat/am335x/serial.c index 1b42493..aa4409b 100644 --- a/src/plat/am335x/serial.c +++ b/src/plat/am335x/serial.c @@ -1,5 +1,3 @@ - -#if 0 /* * Copyright 2014, NICTA * @@ -9,49 +7,86 @@ * * @TAG(NICTA_BSD) */ -/* - * Provide serial UART glue to hardware. This file is not used on debug - * kernels, as we use a seL4 debug syscall to print to the serial console. - */ -#include "../../plat_internal.h" -#include +#include +#include +#include "serial.h" -#define UART_PADDR 0x44E09000 -#define UART_REG(x) ((volatile seL4_Word *)(uart_page + (x))) -#define UART_SR1_TRDY 5 +#define UART_SR1_TRDY BIT(5) #define UTXD 0x00 #define USR1 0x14 -static void* uart_page; +#define REG_PTR(base, off) ((volatile uint32_t *)((base) + (off))) -void -__plat_serial_input_init_IRQ(void) +static int uart_getchar(ps_chardevice_t *d) { + return EOF; // XXX } -void -__plat_serial_init(void) +static int uart_putchar(ps_chardevice_t* d, int c) { - uart_page = __map_device_page(UART_PADDR, 12); + while (!(*REG_PTR(d->vaddr, USR1) & UART_SR1_TRDY)); + *REG_PTR(d->vaddr, UTXD) = c; + return c; } -void -__plat_putchar(int c) +static void +uart_handle_irq(ps_chardevice_t* d UNUSED) +{ + /* TODO */ +} + + +static ssize_t +uart_write(ps_chardevice_t* d, const void* vdata, size_t count, chardev_callback_t rcb UNUSED, void* token UNUSED) { - /* Wait for serial to become ready. */ - while (!(*UART_REG(USR1) & BIT(UART_SR1_TRDY))); + const char* data = (const char*)vdata; + int i; + for (i = 0; i < count; i++) { + if (uart_putchar(d, *data++) < 0) { + return i; + } + } + return count; +} - /* Write out the next character. */ - *UART_REG(UTXD) = c; - if (c == '\n') { - __plat_putchar('\r'); +static ssize_t +uart_read(ps_chardevice_t* d, void* vdata, size_t count, chardev_callback_t rcb UNUSED, void* token UNUSED) +{ + char* data; + int ret; + int i; + data = (char*)vdata; + for (i = 0; i < count; i++) { + ret = uart_getchar(d); + if (ret != EOF) { + *data++ = ret; + } else { + return i; + } } + return count; } -int -__plat_getchar(void) +int uart_init(const struct dev_defn* defn, + const ps_io_ops_t* ops, + ps_chardevice_t* dev) { - return EOF; + memset(dev, 0, sizeof(*dev)); + void* vaddr = chardev_map(defn, ops); + if (vaddr == NULL) { + return -1; + } + + /* Set up all the device properties. */ + dev->id = defn->id; + dev->vaddr = (void*)vaddr; + dev->read = &uart_read; + dev->write = &uart_write; + dev->handle_irq = &uart_handle_irq; + dev->irqs = defn->irqs; + dev->ioops = *ops; + + return 0; } -#endif + project libs/libsel4platsupport/ diff --git a/plat_include/am335x/sel4platsupport/plat/timer.h b/plat_include/am335x/sel4platsupport/plat/timer.h index 217c6b6..340649f 100644 --- a/plat_include/am335x/sel4platsupport/plat/timer.h +++ b/plat_include/am335x/sel4platsupport/plat/timer.h @@ -10,6 +10,16 @@ #ifndef _SEL4PLATSUPPORT_PLAT_TIMER_H #define _SEL4PLATSUPPORT_PLAT_TIMER_H -/* no timers implemented yet */ +#include +#include + +#define DEFAULT_TIMER_PADDR DMTIMER2_PADDR +#define DEFAULT_TIMER_INTERRUPT DMTIMER2_INTERRUPT + +seL4_timer_t *sel4platsupport_get_timer(enum timer_id id, + vka_t *vka, + vspace_t *vspace, + simple_t *simple, + seL4_CPtr aep); #endif /* _SEL4PLATSUPPORT_PLAT_TIMER_H */ diff --git a/src/plat/am335x/dm.c b/src/plat/am335x/dm.c deleted file mode 100644 index cfedd2e..0000000 --- a/src/plat/am335x/dm.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2014, NICTA - * - * This software may be distributed and modified according to the terms of - * the BSD 2-Clause license. Note that NO WARRANTY is provided. - * See "LICENSE_BSD2.txt" for details. - * - * @TAG(NICTA_BSD) - */ - -#include - -#include -#include - -#include - -#include -#include - -seL4_timer_t * -sel4platsupport_get_dm(vspace_t *vspace, simple_t *simple, vka_t *vka, seL4_CPtr aep) { - - seL4_timer_t *timer = calloc(1, sizeof(seL4_timer_t)); - if (timer == NULL) { - LOG_ERROR("Failed to allocate object of size %u\n", sizeof(seL4_timer_t)); - goto error; - } - - - timer_common_data_t *data = timer_common_init(vspace, simple, vka, aep, irq, DMTIMER2_PADDR); - timer->data = data; - - if (timer->data == NULL) { - goto error; - } - - timer->handle_irq = timer_common_handle_irq; - timer->timer = dm_get_timer(data->vaddr); - - if (timer->timer == NULL) { - goto error; - } - - /* success */ - return timer; - -error: - - if (timer != NULL) { - timer_common_destroy(timer->data, vka, vspace); - free(timer); - } - - return NULL; -}