/* * 2013 by Fabian Vogt */ #include <stdint.h> #include "interrupt.h" #define NSPIRE_GPIO_SECTION_SIZE 0x40 #define NSPIRE_GPIO_DIRECTION_OFFSET 0x10 #define NSPIRE_GPIO_OUTPUT_OFFSET 0x14 #define NSPIRE_GPIO_BIT(x) (x&7) #define NSPIRE_GPIO_SECTION_OFFSET(x) (((x>>3)&3)*NSPIRE_GPIO_SECTION_SIZE) #define NSPIRE_GPIO(x, t) (*(uint32_t*)(0x90000000 + \ NSPIRE_GPIO_SECTION_OFFSET(x) + NSPIRE_GPIO_##t##_OFFSET)) static inline void gpio_dir_out(uint8_t pin, uint8_t value) { uint32_t val = NSPIRE_GPIO(pin, OUTPUT); if(value) val |= 1<<NSPIRE_GPIO_BIT(pin); else val &= ~(1<<NSPIRE_GPIO_BIT(pin)); NSPIRE_GPIO(pin, OUTPUT) = val; val = NSPIRE_GPIO(pin, DIRECTION); val &= ~(1<<NSPIRE_GPIO_BIT(pin)); NSPIRE_GPIO(pin, DIRECTION) = val; } #define TIMER_CONTROL_ONESHOT (1<<0) #define TIMER_CONTROL_32BIT (1<<1) #define TIMER_CONTROL_DIV16 (0b01<<2) #define TIMER_CONTROL_DIV256 (0b10<<2) #define TIMER_CONTROL_INTEN (1<<5) #define TIMER_CONTROL_MODE_PERIODIC (1<<6) #define TIMER_CONTROL_ENABLE (1<<7) #define TIMER_LOAD 0x0 #define TIMER_CONTROL 0x8 #define TIMER_IRQ_CLEAR 0xC #define TIMER_BG_LOAD 0x18 #define SECOND_TIMER_IRQ 19 #define FIRST_TIMER_IRQ 18 #define FAST_TIMER_IRQ 17 #define FAST_TIMER_1 0x90010000 #define FAST_TIMER_2 0x90010020 #define FIRST_TIMER 0x900C0000 #define SECOND_TIMER 0x900d0000 #define FAST_TIMER_FREQ 33000000 #define GPIO 0x90000000 #define REG(base, x) (*(uint32_t*)(base + x)) static void setup_timer(uint32_t timer, uint32_t control, uint32_t load) { REG(timer, TIMER_CONTROL) = 0; REG(timer, TIMER_IRQ_CLEAR) = 1; if(control & TIMER_CONTROL_MODE_PERIODIC) REG(timer, TIMER_BG_LOAD) = load; else REG(timer, TIMER_LOAD) = load; REG(timer, TIMER_CONTROL) = control; } static uint32_t fast_timer_control; static uint32_t second_timer_control; static uint32_t fast_timer_load; static uint32_t second_timer_load; static uint32_t gpio_save_dir; static uint32_t gpio_save_out; extern uint32_t* buffer; extern uint32_t buffer_size; extern void do_pwm(); static uint8_t setup = 0; void play(uint32_t* abuffer, uint32_t abuffer_size, uint32_t samplerate) { if(!setup) { /* Save GPIO state */ gpio_save_out = REG(GPIO, 0x14); gpio_save_dir = REG(GPIO, 0x10); /* As output (and low) */ gpio_dir_out(4, 0); /* Register FIQ handler */ init_interrupts(do_pwm, 0); /* Save timer state */ second_timer_control = REG(FAST_TIMER_2, TIMER_CONTROL); fast_timer_control = REG(FAST_TIMER_1, TIMER_CONTROL); second_timer_load = REG(FAST_TIMER_2, TIMER_LOAD); fast_timer_load = REG(FAST_TIMER_1, TIMER_LOAD); /* Setup pwm */ setup_timer(FAST_TIMER_1, TIMER_CONTROL_ENABLE | TIMER_CONTROL_INTEN | TIMER_CONTROL_ONESHOT | TIMER_CONTROL_MODE_PERIODIC, 1); /* Set fast timer as FIQ source */ set_as_fiq(FAST_TIMER_IRQ); enable_irq(FAST_TIMER_IRQ); setup = 1; } buffer = abuffer; buffer_size = abuffer_size; setup_timer(FAST_TIMER_2, TIMER_CONTROL_ENABLE | TIMER_CONTROL_INTEN | TIMER_CONTROL_32BIT | TIMER_CONTROL_MODE_PERIODIC, FAST_TIMER_FREQ / samplerate); } void stop() { if(setup) { deactivate_ints(); REG(GPIO, 0x14) = gpio_save_out; REG(GPIO, 0x10) = gpio_save_dir; REG(FAST_TIMER_2, TIMER_LOAD) = second_timer_load; REG(FAST_TIMER_1, TIMER_LOAD) = fast_timer_load; REG(FAST_TIMER_2, TIMER_CONTROL) = second_timer_control & ~TIMER_CONTROL_ENABLE; REG(FAST_TIMER_1, TIMER_CONTROL) = fast_timer_control & ~TIMER_CONTROL_ENABLE; REG(FAST_TIMER_2, TIMER_IRQ_CLEAR) = 1; REG(FAST_TIMER_1, TIMER_IRQ_CLEAR) = 1; /* This enables interrupts again */ unregister(); REG(FAST_TIMER_2, TIMER_CONTROL) = second_timer_control; REG(FAST_TIMER_1, TIMER_CONTROL) = fast_timer_control; setup = 0; } }