Here's an updated set of patches, inclusive of the last. I haven't seen the earlier ones show up in git yet, but if they do, I can send out incrementals based on those if necessary.
With these, the sel4test can now run to completion, passing all the tests. There are still spurious interrupts being reported, and you may want to comment out the printf that reports them for now (not included in my patches)... On Fri, Feb 13, 2015 at 6:32 PM, Tim Newsham <tim.newsham+s...@gmail.com> wrote: > 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 > > -- > Tim Newsham | www.thenewsh.com/~newsham | @newshtwit | thenewsh.blogspot.com
From bb58c8a9515b74ad4eaae4f722a31c2007be4f35 Mon Sep 17 00:00:00 2001 From: Tim Newsham <tim.news...@gmail.com> Date: Sun, 15 Feb 2015 20:52:53 -1000 Subject: [PATCH] - fix am335x interrupt handling and disable watchdog --- include/plat/am335x/plat/machine/devices.h | 4 ++ src/plat/am335x/machine/hardware.c | 84 ++++++++++++++++++++++++------ 2 files changed, 72 insertions(+), 16 deletions(-) diff --git a/include/plat/am335x/plat/machine/devices.h b/include/plat/am335x/plat/machine/devices.h index 58f2928..adbe875 100644 --- a/include/plat/am335x/plat/machine/devices.h +++ b/include/plat/am335x/plat/machine/devices.h @@ -15,6 +15,8 @@ #define INTC_PPTR 0xfff01000 #define UART0_PPTR 0xfff02000 #define DMTIMER0_PPTR 0xfff03000 +#define WDT1_PPTR 0xfff04000 + /* Other devices on the SoC. */ #define INTC_PADDR 0x48200000 @@ -26,5 +28,7 @@ #define DMTIMER5_PADDR 0x48046000 #define DMTIMER6_PADDR 0x48048000 #define DMTIMER7_PADDR 0x4804A000 +#define WDT1_PADDR 0x44e35000 + #endif diff --git a/src/plat/am335x/machine/hardware.c b/src/plat/am335x/machine/hardware.c index 199baf0..6a57712 100644 --- a/src/plat/am335x/machine/hardware.c +++ b/src/plat/am335x/machine/hardware.c @@ -51,6 +51,7 @@ const p_region_t BOOT_RODATA dev_p_regs[] = { { /* .start = */ DMTIMER5_PADDR, /* .end = */ DMTIMER5_PADDR + (1 << PAGE_BITS) }, { /* .start = */ DMTIMER6_PADDR, /* .end = */ DMTIMER6_PADDR + (1 << PAGE_BITS) }, { /* .start = */ DMTIMER7_PADDR, /* .end = */ DMTIMER7_PADDR + (1 << PAGE_BITS) }, + { /* .start = */ WDT1_PADDR, /* .end = */ WDT1_PADDR + (1 << PAGE_BITS) }, /* Board devices. */ /* TODO: This should ultimately be replaced with a more general solution. */ }; @@ -93,6 +94,18 @@ map_kernel_devices(void) ) ); + /* map kernel device: WDT1 */ + map_kernel_frame( + WDT1_PADDR, + WDT1_PPTR, + VMKernelOnly, + vm_attributes_new( + false, /* armExecuteNever */ + false, /* armParityEnabled */ + false /* armPageCacheable */ + ) + ); + #ifdef DEBUG /* map kernel device: UART */ map_kernel_frame( @@ -108,6 +121,12 @@ map_kernel_devices(void) #endif } + +#define INTCPS_SYSCONFIG_SOFTRESET BIT(1) +#define INTCPS_SYSSTATUS_RESETDONE BIT(0) +#define INTCPS_CONTROL_NEWIRQAGR 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,11 +155,11 @@ 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; + /** DONT_TRANSLATE */ @@ -148,23 +167,30 @@ 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 happening a lot for irq=66! */ } + } else { + /* XXX - 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. */ @@ -174,6 +200,7 @@ bool_t isIRQPending(void) void maskInterrupt(bool_t disable, interrupt_t irq) { + assert(irq <= maxIRQ); if (disable) { intc->intcps_n[irq / 32].intcps_mir_set = 1 << (irq & 31); } else { @@ -185,22 +212,22 @@ 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 ackInterrupt(irq_t irq) { - intc->intcps_control = 1; + intc->intcps_control = INTCPS_CONTROL_NEWIRQAGR; /* Ensure the ack has hit the interrupt controller before potentially * re-enabling interrupts. */ dsb(); @@ -255,6 +282,25 @@ resetTimer(void) ackInterrupt(DMTIMER0_IRQ); } +#define WDT_REG(base, off) ((volatile uint32_t *)((base) + (off))) +#define WDT_REG_WWPS 0x34 +#define WDT_REG_WSPR 0x48 +#define WDT_WWPS_PEND_WSPR BIT(4) + +static BOOT_CODE void +disableWatchdog(void) +{ + uint32_t wdt = WDT1_PPTR; + + // am335x ref man, sec 20.4.3.8 + *WDT_REG(wdt, WDT_REG_WSPR) = 0xaaaa; + while((*WDT_REG(wdt, WDT_REG_WWPS) & WDT_WWPS_PEND_WSPR)) + continue; + *WDT_REG(wdt, WDT_REG_WSPR) = 0x5555; + while((*WDT_REG(wdt, WDT_REG_WWPS) & WDT_WWPS_PEND_WSPR)) + continue; +} + /* Configure dmtimer0 as kernel preemption timer */ /** DONT_TRANSLATE @@ -264,11 +310,14 @@ initTimer(void) { int timeout; + disableWatchdog(); + timer->cfg = TIOCP_CFG_SOFTRESET; for (timeout = 10000; (timer->cfg & TIOCP_CFG_SOFTRESET) && timeout > 0; timeout--) ; if (!timeout) { + printf("init timer failed\n"); return; } @@ -293,12 +342,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 = INTCPS_CONTROL_NEWIRQAGR; + dsb(); } -- 1.9.1
From 4326fc21b5fb338e8a9fc14afdf327d3b7043653 Mon Sep 17 00:00:00 2001 From: Tim Newsham <tim.news...@gmail.com> Date: Sun, 15 Feb 2015 20:43:00 -1000 Subject: [PATCH 1/2] - rework timer and serial code for am335x --- plat_include/am335x/platsupport/plat/clock.h | 27 ++++ plat_include/am335x/platsupport/plat/serial.h | 37 +++++ src/plat/am335x/chardev.c | 49 +++++++ src/plat/am335x/serial.h | 14 ++ src/plat/am335x/timer.c | 186 ++++++++++++++++++++++++++ 5 files changed, 313 insertions(+) create mode 100644 plat_include/am335x/platsupport/plat/clock.h create mode 100644 plat_include/am335x/platsupport/plat/serial.h create mode 100644 src/plat/am335x/chardev.c create mode 100644 src/plat/am335x/serial.h create mode 100644 src/plat/am335x/timer.c diff --git a/plat_include/am335x/platsupport/plat/clock.h b/plat_include/am335x/platsupport/plat/clock.h new file mode 100644 index 0000000..ada8610 --- /dev/null +++ b/plat_include/am335x/platsupport/plat/clock.h @@ -0,0 +1,27 @@ +/* + * 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 _PLATSUPPORT_PLAT_CLOCK_H_ +#define _PLATSUPPORT_PLAT_CLOCK_H_ + +enum clk_id { + CLK_MASTER, + /* ----- */ + NCLOCKS, + /* Custom clock */ + CLK_CUSTOM, +}; + +enum clock_gate { + NCLKGATES +}; + + +#endif /* _PLATSUPPORT_PLAT_CLOCK_H_ */ diff --git a/plat_include/am335x/platsupport/plat/serial.h b/plat_include/am335x/platsupport/plat/serial.h new file mode 100644 index 0000000..accff9a --- /dev/null +++ b/plat_include/am335x/platsupport/plat/serial.h @@ -0,0 +1,37 @@ +/* + * 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 __PLATSUPPORT_PLAT_SERIAL_H__ +#define __PLATSUPPORT_PLAT_SERIAL_H__ + +#define UART0_PADDR 0x44E09000 +#define UART1_PADDR 0x48022000 +#define UART2_PADDR 0x48024000 + +#define UART0_IRQ 72 +#define UART1_IRQ 73 +#define UART2_IRQ 74 + +enum chardev_id { + DM_UART0, + DM_UART1, + DM_UART2, + /* Aliases */ + PS_SERIAL0 = DM_UART0, + PS_SERIAL1 = DM_UART1, + PS_SERIAL2 = DM_UART2, + /* defaults */ + PS_SERIAL_DEFAULT = DM_UART0 +}; + + +#endif /* __PLATSUPPORT_PLAT_SERIAL_H__ */ + + diff --git a/src/plat/am335x/chardev.c b/src/plat/am335x/chardev.c new file mode 100644 index 0000000..6dd8fc0 --- /dev/null +++ b/src/plat/am335x/chardev.c @@ -0,0 +1,49 @@ +/* + * 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) + */ + +/** + * Contains the definition for all character devices on this platform. + * Currently this is just a simple patch. + */ + +#include "../../chardev.h" +#include "../../common.h" +#include <utils/util.h> + +#include "serial.h" + +static const int uart0_irqs[] = {UART0_IRQ, -1}; +static const int uart1_irqs[] = {UART1_IRQ, -1}; +static const int uart2_irqs[] = {UART2_IRQ, -1}; + +#define UART_DEFN(devid) { \ + .id = DM_UART##devid, \ + .paddr = UART##devid##_PADDR, \ + .size = BIT(12), \ + .irqs = uart##devid##_irqs, \ + .init_fn = &uart_init \ +} + +static const struct dev_defn dev_defn[] = { + UART_DEFN(0), + UART_DEFN(1), + UART_DEFN(2), +}; + +struct ps_chardevice* +ps_cdev_init(enum chardev_id id, const ps_io_ops_t* o, struct ps_chardevice* d) { + unsigned int i; + for (i = 0; i < ARRAY_SIZE(dev_defn); i++) { + if (dev_defn[i].id == id) { + return (dev_defn[i].init_fn(dev_defn + i, o, d)) ? NULL : d; + } + } + return NULL; +} diff --git a/src/plat/am335x/serial.h b/src/plat/am335x/serial.h new file mode 100644 index 0000000..73f890b --- /dev/null +++ b/src/plat/am335x/serial.h @@ -0,0 +1,14 @@ +/* + * 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 "../../chardev.h" + +int uart_init(const struct dev_defn* defn, const ps_io_ops_t* ops, ps_chardevice_t* dev); + diff --git a/src/plat/am335x/timer.c b/src/plat/am335x/timer.c new file mode 100644 index 0000000..841a734 --- /dev/null +++ b/src/plat/am335x/timer.c @@ -0,0 +1,186 @@ +/* + * 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 <stdio.h> +#include <assert.h> + +#include <utils/util.h> + +#include <platsupport/timer.h> +#include <platsupport/plat/timer.h> + +#define TIOCP_CFG_SOFTRESET BIT(0) + +#define TIER_MATCHENABLE BIT(0) +#define TIER_OVERFLOWENABLE BIT(1) +#define TIER_COMPAREENABLE BIT(2) + +#define TCLR_AUTORELOAD BIT(1) +#define TCLR_COMPAREENABLE BIT(6) +#define TCLR_STARTTIMER BIT(0) + +#define TISR_OVF_FLAG (BIT(0) | BIT(1) | BIT(2)) + +#define TICKS_PER_SECOND 24000000 /* TODO: Pin this frequency down without relying on u-boot. */ +#define TIMER_INTERVAL_TICKS(ns) ((uint32_t)(1ULL * (ns) * TICKS_PER_SECOND / 1000 / 1000 / 1000)) +#define TICKS_TIMER_INTERVAL(x) (((uint64_t)x * 1000 * 1000 * 1000) / TICKS_PER_SECOND) + +struct dmt_map { + uint32_t tidr; // 00h TIDR Identification Register + uint32_t padding1[3]; + uint32_t cfg; // 10h TIOCP_CFG Timer OCP Configuration Register + uint32_t padding2[3]; + uint32_t tieoi; // 20h IRQ_EOI Timer IRQ End-Of-Interrupt Register + uint32_t tisrr; // 24h IRQSTATUS_RAW Timer IRQSTATUS Raw Register + uint32_t tisr; // 28h IRQSTATUS Timer IRQSTATUS Register + uint32_t tier; // 2Ch IRQENABLE_SET Timer IRQENABLE Set Register + uint32_t ticr; // 30h IRQENABLE_CLR Timer IRQENABLE Clear Register + uint32_t twer; // 34h IRQWAKEEN Timer IRQ Wakeup Enable Register + uint32_t tclr; // 38h TCLR Timer Control Register + uint32_t tcrr; // 3Ch TCRR Timer Counter Register + uint32_t tldr; // 40h TLDR Timer Load Register + uint32_t ttgr; // 44h TTGR Timer Trigger Register + uint32_t twps; // 48h TWPS Timer Write Posted Status Register + uint32_t tmar; // 4Ch TMAR Timer Match Register + uint32_t tcar1; // 50h TCAR1 Timer Capture Register + uint32_t tsicr; // 54h TSICR Timer Synchronous Interface Control Register + uint32_t tcar2; // 58h TCAR2 Timer Capture Register +}; + +typedef struct dmt { + volatile struct dmt_map *hw; + uint32_t irq; +} dmt_t; + +static void +dm_timer_reset(const pstimer_t *timer) +{ + dmt_t *dmt = (dmt_t*) timer->data; + dmt->hw->tclr = 0; /* stop */ + dmt->hw->cfg = TIOCP_CFG_SOFTRESET; + while (dmt->hw->cfg & TIOCP_CFG_SOFTRESET); + dmt->hw->tier = TIER_OVERFLOWENABLE; +} + +static int +dm_timer_stop(const pstimer_t *timer) +{ + dmt_t *dmt = (dmt_t*) timer->data; + dmt->hw->tclr = dmt->hw->tclr & ~TCLR_STARTTIMER; + return 0; +} + +static int +dm_timer_start(const pstimer_t *timer) +{ + dmt_t *dmt = (dmt_t*) timer->data; + dmt->hw->tclr = dmt->hw->tclr | TCLR_STARTTIMER; + return 0; +} + +static int +dm_set_timeo(const pstimer_t *timer, uint64_t ns, int tclrFlags) +{ + dmt_t *dmt = (dmt_t*) timer->data; + + dmt->hw->tclr = 0; /* stop */ + + /* XXX handle prescaler */ + /* XXX handle invalid arguments with an error return */ + + uint32_t ticks = TIMER_INTERVAL_TICKS(ns); + if (ticks < 2) + return EINVAL; + //printf("timer %lld ns = %x ticks (cntr %x)\n", ns, ticks, (uint32_t)(~0UL - ticks)); + dmt->hw->tldr = ~0UL - ticks; /* reload value */ + dmt->hw->tcrr = ~0UL - ticks; /* counter */ + dmt->hw->tisr = TISR_OVF_FLAG; /* ack any pending overflows */ + dmt->hw->tclr = TCLR_STARTTIMER | tclrFlags; + return 0; +} + +static int +dm_periodic(const pstimer_t *timer, uint64_t ns) +{ + return dm_set_timeo(timer, ns, TCLR_AUTORELOAD); +} + +static int +dm_oneshot_absolute(const pstimer_t *timer, uint64_t ns) +{ + return ENOSYS; /* not available for downcounters */ +} + +static int +dm_oneshot_relative(const pstimer_t *timer, uint64_t ns) +{ + return dm_set_timeo(timer, ns, 0); +} + +// XXX write test case to verify this... +static uint64_t +dm_get_time(const pstimer_t *timer) +{ + dmt_t *dmt = (dmt_t*) timer->data; + uint32_t ticks = ~0UL - dmt->hw->tcrr; + //printf("get time has %x ticks left or %lld ns\n", ticks, TICKS_TIMER_INTERVAL(ticks)); + return TICKS_TIMER_INTERVAL(ticks); +} + +static void +dm_handle_irq(const pstimer_t *timer, uint32_t irq) +{ + dmt_t *dmt = (dmt_t*) timer->data; + dmt->hw->tisr = TISR_OVF_FLAG; /* ack any pending overflows */ +} + +static uint32_t +dm_get_nth_irq(const pstimer_t *timer, uint32_t n) +{ + dmt_t *dmt = (dmt_t*) timer->data; + return dmt->irq; +} + +static pstimer_t timers[NTIMERS]; +static dmt_t dmts[NTIMERS]; + +pstimer_t * +ps_get_timer(enum timer_id id, timer_config_t *config) +{ + pstimer_t *timer; + dmt_t *dmt; + + if(id >= NTIMERS) + return NULL; + timer = &timers[id]; + dmt = &dmts[id]; + + timer->properties.upcounter = false; + timer->properties.timeouts = true; + timer->properties.bit_width = 32; + timer->properties.irqs = 1; + + timer->data = dmt; + timer->start = dm_timer_start; + timer->stop = dm_timer_stop; + timer->get_time = dm_get_time; + timer->oneshot_absolute = dm_oneshot_absolute; + timer->oneshot_relative = dm_oneshot_relative; + timer->periodic = dm_periodic; + timer->handle_irq = dm_handle_irq; + timer->get_nth_irq = dm_get_nth_irq; + + dmt->hw = (struct dmt_map *)config->vaddr; + dmt->irq = config->irq; + // XXX support config->prescaler. + + dm_timer_reset(timer); + return timer; +} -- 1.9.1
From 18be6504a91d9805ebd0de243393825ebd160a98 Mon Sep 17 00:00:00 2001 From: Tim Newsham <tim.news...@gmail.com> Date: Sun, 15 Feb 2015 20:43:44 -1000 Subject: [PATCH 2/2] - rework serial and timer code for am335x --- plat_include/am335x/platsupport/plat/dm.h | 27 -------- plat_include/am335x/platsupport/plat/mux.h | 2 +- plat_include/am335x/platsupport/plat/timer.h | 54 +++++++++++++++- src/plat/am335x/dm.c | 30 +++++---- src/plat/am335x/serial.c | 93 +++++++++++++++++++--------- 5 files changed, 137 insertions(+), 69 deletions(-) delete mode 100644 plat_include/am335x/platsupport/plat/dm.h 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 <platsupport/timer.h> - -#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..ff2707c 100644 --- a/plat_include/am335x/platsupport/plat/timer.h +++ b/plat_include/am335x/platsupport/plat/timer.h @@ -10,6 +10,58 @@ #ifndef _PLATSUPPORT_PLAT_TIMER_H #define _PLATSUPPORT_PLAT_TIMER_H -#include <platsupport/plat/dm.h> +/* 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; + uint32_t irq; +} 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 <platsupport/timer.h> -#include <platsupport/plat/timer.h> #include <stdio.h> #include <assert.h> +#include <utils/util.h> + +#include <platsupport/timer.h> +#include <platsupport/plat/timer.h> + #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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#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 + -- 1.9.1
From 67b2aa41a187b5304201261b60a54fb2e2373535 Mon Sep 17 00:00:00 2001 From: Tim Newsham <tim.news...@gmail.com> Date: Sun, 15 Feb 2015 20:54:43 -1000 Subject: [PATCH] - rework am335x timer support --- plat_include/am335x/sel4platsupport/plat/timer.h | 12 +++- src/plat/am335x/dm.c | 56 ------------------ src/plat/am335x/timer.c | 72 ++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 57 deletions(-) delete mode 100644 src/plat/am335x/dm.c create mode 100644 src/plat/am335x/timer.c 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 <sel4platsupport/timer.h> +#include <platsupport/plat/timer.h> + +#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 <sel4platsupport/device.h> - -#include <platsupport/dm.h> -#include <stdio.h> - -#include <assert.h> - -#include <sel4utils/mapping.h> -#include <vka/object.h> - -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; -} diff --git a/src/plat/am335x/timer.c b/src/plat/am335x/timer.c new file mode 100644 index 0000000..6a7063e --- /dev/null +++ b/src/plat/am335x/timer.c @@ -0,0 +1,72 @@ +/* + * 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 <stdlib.h> +#include <vka/vka.h> +#include <simple/simple.h> +#include <sel4platsupport/timer.h> +#include <sel4platsupport/plat/timer.h> +#include <sel4utils/util.h> +#include "../../timer_common.h" + +seL4_timer_t * +sel4platsupport_get_timer(enum timer_id id, vka_t *vka, vspace_t *vspace, + simple_t *simple, seL4_CPtr aep) +{ + switch(id) { + case DMTIMER2: + case DMTIMER3: + case DMTIMER4: + case DMTIMER5: + case DMTIMER6: + case DMTIMER7: + break; + default: + LOG_ERROR("Bad timer ID %d\n", id); + return NULL; + } + + 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)); + return NULL; + } + + timer->handle_irq = timer_common_handle_irq; + timer_common_data_t *data = timer_common_init(vspace, simple, vka, aep, + dm_timer_irqs[id], (void*)dm_timer_paddrs[id]); + timer->data = data; + if (timer->data == NULL) { + free(timer); + return NULL; + } + + timer_config_t config = { + .vaddr = data->vaddr, + .irq = dm_timer_irqs[id], + }; + timer->timer = ps_get_timer(id, &config); + if(timer->timer == NULL) { + timer_common_destroy(timer->data, vka, vspace); + free(timer); + return NULL; + } + + /* success */ + return timer; +} + +seL4_timer_t * +sel4platsupport_get_default_timer(vka_t *vka, vspace_t *vspace, simple_t *simple, + seL4_CPtr aep) +{ + return sel4platsupport_get_timer(TMR_DEFAULT, vka, vspace, simple, aep); +} + -- 1.9.1
_______________________________________________ Devel mailing list Devel@sel4.systems https://sel4.systems/lists/listinfo/devel