forked from len0rd/rockbox
TCC78x: Implement the user timer, rework some of the timer register #defines, and use udelay() instead of the hacky sleep_ms() in the D2 LCD driver. Doom works now.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20585 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
8739af490e
commit
75b37696fb
7 changed files with 102 additions and 63 deletions
|
|
@ -132,20 +132,37 @@
|
||||||
|
|
||||||
/* Timer / Counters */
|
/* Timer / Counters */
|
||||||
|
|
||||||
#define TCFG0 (*(volatile unsigned long *)0xF3003000)
|
/* Note: Timers 0-3 have a 16 bit counter, 4-5 have 20 bits */
|
||||||
#define TCNT0 (*(volatile unsigned long *)0xF3003004)
|
#define TCFG(_x_) (*(volatile unsigned int *)(0xF3003000+0x10*(_x_)))
|
||||||
#define TREF0 (*(volatile unsigned long *)0xF3003008)
|
#define TCNT(_x_) (*(volatile unsigned int *)(0xF3003004+0x10*(_x_)))
|
||||||
#define TCFG1 (*(volatile unsigned long *)0xF3003010)
|
#define TREF(_x_) (*(volatile unsigned int *)(0xF3003008+0x10*(_x_)))
|
||||||
#define TCNT1 (*(volatile unsigned long *)0xF3003014)
|
|
||||||
#define TREF1 (*(volatile unsigned long *)0xF3003018)
|
|
||||||
|
|
||||||
#define TIREQ (*(volatile unsigned long *)0xF3003060)
|
#define TIREQ (*(volatile unsigned long *)0xF3003060)
|
||||||
|
|
||||||
|
/* TCFG flags */
|
||||||
|
#define TCFG_EN (1<<0) /* enable timer */
|
||||||
|
#define TCFG_CONT (1<<1) /* continue from zero once TREF is reached */
|
||||||
|
#define TCFG_PWM (1<<2) /* PWM mode */
|
||||||
|
#define TCFG_IEN (1<<3) /* IRQ enable */
|
||||||
|
#define TCFG_SEL (1<<4) /* clock source & divider */
|
||||||
|
#define TCFG_POL (1<<7) /* polarity */
|
||||||
|
#define TCFG_CLEAR (1<<8) /* reset TCNT to zero */
|
||||||
|
#define TCFG_STOP (1<<9) /* stop counting once TREF reached */
|
||||||
|
|
||||||
/* TIREQ flags */
|
/* TIREQ flags */
|
||||||
#define TF0 (1<<8) /* Timer 0 reference value reached */
|
#define TIREQ_TI0 (1<<0) /* Timer N IRQ flag */
|
||||||
#define TF1 (1<<9) /* Timer 1 reference value reached */
|
#define TIREQ_TI1 (1<<1)
|
||||||
#define TI0 (1<<0) /* Timer 0 IRQ flag */
|
#define TIREQ_TI2 (1<<2)
|
||||||
#define TI1 (1<<1) /* Timer 1 IRQ flag */
|
#define TIREQ_TI3 (1<<3)
|
||||||
|
#define TIREQ_TI4 (1<<4)
|
||||||
|
#define TIREQ_TI5 (1<<5)
|
||||||
|
|
||||||
|
#define TIREQ_TF0 (1<<8) /* Timer N reference value reached */
|
||||||
|
#define TIREQ_TF1 (1<<9)
|
||||||
|
#define TIREQ_TF2 (1<<10)
|
||||||
|
#define TIREQ_TF3 (1<<11)
|
||||||
|
#define TIREQ_TF4 (1<<12)
|
||||||
|
#define TIREQ_TF5 (1<<13)
|
||||||
|
|
||||||
#define TC32EN (*(volatile unsigned long *)0xF3003080)
|
#define TC32EN (*(volatile unsigned long *)0xF3003080)
|
||||||
#define TC32LDV (*(volatile unsigned long *)0xF3003084)
|
#define TC32LDV (*(volatile unsigned long *)0xF3003084)
|
||||||
|
|
|
||||||
|
|
@ -116,33 +116,11 @@ static void lcd_write_reg(unsigned char reg, unsigned short val)
|
||||||
restore_irq(level);
|
restore_irq(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
TEMP: Rough millisecond delay routine used by the LCD panel init sequence.
|
|
||||||
PCK_TCT must first have been initialised to 2Mhz by calling clock_init().
|
|
||||||
*/
|
|
||||||
static void sleep_ms(unsigned int ms)
|
|
||||||
{
|
|
||||||
/* disable timer */
|
|
||||||
TCFG1 = 0;
|
|
||||||
|
|
||||||
/* set Timer1 reference value based on 125kHz tick */
|
|
||||||
TREF1 = ms * 125;
|
|
||||||
|
|
||||||
/* single count, zero the counter, divider = 16 [2^(3+1)], enable */
|
|
||||||
TCFG1 = (1<<9) | (1<<8) | (3<<4) | 1;
|
|
||||||
|
|
||||||
/* wait until Timer1 ref reached */
|
|
||||||
while (!(TIREQ & TF1)) {};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void lcd_display_on(void)
|
static void lcd_display_on(void)
|
||||||
{
|
{
|
||||||
/* power on sequence as per the D2 firmware */
|
/* power on sequence as per the D2 firmware */
|
||||||
GPIOA_SET = (1<<16);
|
GPIOA_SET = (1<<16);
|
||||||
|
udelay(10000);
|
||||||
sleep_ms(10);
|
|
||||||
|
|
||||||
lcd_write_reg(1, 0x1D);
|
lcd_write_reg(1, 0x1D);
|
||||||
lcd_write_reg(2, 0x0);
|
lcd_write_reg(2, 0x0);
|
||||||
|
|
@ -164,14 +142,14 @@ static void lcd_display_on(void)
|
||||||
lcd_write_reg(23, 0x0);
|
lcd_write_reg(23, 0x0);
|
||||||
lcd_write_reg(24, 0x0);
|
lcd_write_reg(24, 0x0);
|
||||||
lcd_write_reg(25, 0x0);
|
lcd_write_reg(25, 0x0);
|
||||||
sleep_ms(10);
|
udelay(10000);
|
||||||
|
|
||||||
lcd_write_reg(9, 0x4055);
|
lcd_write_reg(9, 0x4055);
|
||||||
lcd_write_reg(10, 0x0);
|
lcd_write_reg(10, 0x0);
|
||||||
sleep_ms(40);
|
udelay(40000);
|
||||||
|
|
||||||
lcd_write_reg(10, 0x2000);
|
lcd_write_reg(10, 0x2000);
|
||||||
sleep_ms(40);
|
udelay(40000);
|
||||||
|
|
||||||
lcd_write_reg(1, 0xC01D);
|
lcd_write_reg(1, 0xC01D);
|
||||||
lcd_write_reg(2, 0x204);
|
lcd_write_reg(2, 0x204);
|
||||||
|
|
@ -191,11 +169,11 @@ static void lcd_display_on(void)
|
||||||
lcd_write_reg(23, 0x406);
|
lcd_write_reg(23, 0x406);
|
||||||
lcd_write_reg(24, 0x2);
|
lcd_write_reg(24, 0x2);
|
||||||
lcd_write_reg(25, 0x0);
|
lcd_write_reg(25, 0x0);
|
||||||
sleep_ms(60);
|
udelay(60000);
|
||||||
|
|
||||||
lcd_write_reg(9, 0xA55);
|
lcd_write_reg(9, 0xA55);
|
||||||
lcd_write_reg(10, 0x111F);
|
lcd_write_reg(10, 0x111F);
|
||||||
sleep_ms(10);
|
udelay(10000);
|
||||||
|
|
||||||
/* tell that we're on now */
|
/* tell that we're on now */
|
||||||
display_on = true;
|
display_on = true;
|
||||||
|
|
@ -210,10 +188,10 @@ static void lcd_display_off(void)
|
||||||
lcd_write_reg(9, 0x55);
|
lcd_write_reg(9, 0x55);
|
||||||
lcd_write_reg(10, 0x1417);
|
lcd_write_reg(10, 0x1417);
|
||||||
lcd_write_reg(5, 0x4003);
|
lcd_write_reg(5, 0x4003);
|
||||||
sleep_ms(10);
|
udelay(10000);
|
||||||
|
|
||||||
lcd_write_reg(9, 0x0);
|
lcd_write_reg(9, 0x0);
|
||||||
sleep_ms(10);
|
udelay(10000);
|
||||||
|
|
||||||
/* kill power to LCD panel (unconfirmed) */
|
/* kill power to LCD panel (unconfirmed) */
|
||||||
GPIOA_CLEAR = (1<<16);
|
GPIOA_CLEAR = (1<<16);
|
||||||
|
|
|
||||||
|
|
@ -29,16 +29,13 @@
|
||||||
void tick_start(unsigned int interval_in_ms)
|
void tick_start(unsigned int interval_in_ms)
|
||||||
{
|
{
|
||||||
/* disable Timer0 */
|
/* disable Timer0 */
|
||||||
TCFG0 &= ~1;
|
TCFG(0) &= ~TCFG_EN;
|
||||||
|
|
||||||
/* set counter reference value based on 1Mhz tick */
|
/* set counter reference value based on 1Mhz tick */
|
||||||
TREF0 = interval_in_ms * 1000;
|
TREF(0) = interval_in_ms * 1000;
|
||||||
|
|
||||||
/* Timer0 = reset to 0, divide=2, IRQ enable, enable (continuous) */
|
/* Timer0 = reset to 0, divide=2, IRQ enable, enable (continuous) */
|
||||||
TCFG0 = (1<<8) | (0<<4) | (1<<3) | 1;
|
TCFG(0) = TCFG_CLEAR | (0 << TCFG_SEL) | TCFG_IEN | TCFG_EN;
|
||||||
|
|
||||||
/* Unmask timer IRQ */
|
|
||||||
IEN |= TIMER0_IRQ_MASK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NB: Since we are using a single timer IRQ, tick tasks are dispatched as
|
/* NB: Since we are using a single timer IRQ, tick tasks are dispatched as
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,12 @@
|
||||||
#define outw(a,b) (*(volatile unsigned short *) (b) = (a))
|
#define outw(a,b) (*(volatile unsigned short *) (b) = (a))
|
||||||
|
|
||||||
/* TC32 is configured to 1MHz in clock_init() */
|
/* TC32 is configured to 1MHz in clock_init() */
|
||||||
|
#define USEC_TIMER TC32MCNT
|
||||||
|
|
||||||
static inline void udelay(unsigned usecs)
|
static inline void udelay(unsigned usecs)
|
||||||
{
|
{
|
||||||
unsigned stop = TC32MCNT + usecs;
|
unsigned stop = USEC_TIMER + usecs;
|
||||||
while (TIME_BEFORE(TC32MCNT, stop));
|
while (TIME_BEFORE(USEC_TIMER, stop));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* SYSTEM_TARGET_H */
|
#endif /* SYSTEM_TARGET_H */
|
||||||
|
|
|
||||||
|
|
@ -229,11 +229,14 @@ static void clock_init(void)
|
||||||
"nop \n\t"
|
"nop \n\t"
|
||||||
);
|
);
|
||||||
|
|
||||||
/* configure PCK_TCT to 2Mhz (clock source 4 (Xin) divided by 6) */
|
/* Configure PCK_TCT to 2Mhz (Xin divided by 6) */
|
||||||
PCLK_TCT = PCK_EN | (CKSEL_XIN<<24) | 5;
|
PCLK_TCT = PCK_EN | (CKSEL_XIN<<24) | 5;
|
||||||
|
|
||||||
/* set TC32 timer to XIN divided by 12 (1MHz) */
|
/* Set TC32 timer to be our USEC_TIMER (Xin divided by 12 = 1MHz) */
|
||||||
TC32EN = (1<<24) | 11;
|
TC32EN = (1<<24) | 11;
|
||||||
|
|
||||||
|
/* Unmask common timer IRQ (shared by tick and user timer) */
|
||||||
|
IEN |= TIMER0_IRQ_MASK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
#ifndef TIMER_TARGET_H
|
#ifndef TIMER_TARGET_H
|
||||||
#define TIMER_TARGET_H
|
#define TIMER_TARGET_H
|
||||||
|
|
||||||
/* timers are based on XIN (12Mhz) */
|
/* Timer is based on PCK_TCT (set to 2Mhz in system.c) */
|
||||||
#define TIMER_FREQ (12000000)
|
#define TIMER_FREQ (2000000)
|
||||||
|
|
||||||
bool __timer_set(long cycles, bool set);
|
bool __timer_set(long cycles, bool set);
|
||||||
bool __timer_register(void);
|
bool __timer_register(void);
|
||||||
|
|
|
||||||
|
|
@ -25,40 +25,82 @@
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "logf.h"
|
#include "logf.h"
|
||||||
|
|
||||||
/* Use the TC32 counter [sourced by Xin:12Mhz] for this timer, as it's the
|
static const int prescale_shifts[] = {1, 2, 3, 4, 5, 10, 12};
|
||||||
only one that allows a 32-bit counter (Timer0-5 are 16/20 bit only). */
|
|
||||||
|
|
||||||
bool __timer_set(long cycles, bool start)
|
bool __timer_set(long cycles, bool start)
|
||||||
{
|
{
|
||||||
(void)cycles;
|
bool found = false;
|
||||||
(void)start;
|
|
||||||
return false;
|
int prescale_option = 0;
|
||||||
|
int actual_cycles = 0;
|
||||||
|
|
||||||
|
/* Use the first prescale that fits Timer4's 20-bit counter */
|
||||||
|
while (!found && prescale_option < 7)
|
||||||
|
{
|
||||||
|
actual_cycles = cycles >> prescale_shifts[prescale_option];
|
||||||
|
|
||||||
|
if (actual_cycles < 0x100000)
|
||||||
|
found = true;
|
||||||
|
else
|
||||||
|
prescale_option++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Stop the timer and set new prescale & ref count */
|
||||||
|
TCFG(4) &= ~TCFG_EN;
|
||||||
|
TCFG(4) = prescale_option << TCFG_SEL;
|
||||||
|
TREF(4) = actual_cycles;
|
||||||
|
|
||||||
|
if (start && pfn_unregister != NULL)
|
||||||
|
{
|
||||||
|
pfn_unregister();
|
||||||
|
pfn_unregister = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __timer_register(void)
|
bool __timer_register(void)
|
||||||
{
|
{
|
||||||
return false;
|
int oldstatus = disable_interrupt_save(IRQ_STATUS);
|
||||||
|
|
||||||
|
TCFG(4) |= TCFG_CLEAR | TCFG_IEN | TCFG_EN;
|
||||||
|
|
||||||
|
restore_interrupt(oldstatus);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __timer_unregister(void)
|
void __timer_unregister(void)
|
||||||
{
|
{
|
||||||
|
int oldstatus = disable_interrupt_save(IRQ_STATUS);
|
||||||
|
|
||||||
|
TCFG(4) &= ~TCFG_EN;
|
||||||
|
|
||||||
|
restore_interrupt(oldstatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Timer interrupt processing - all timers (inc. tick) have a single IRQ */
|
/* Timer interrupt processing - all timers (inc. tick) have a single IRQ */
|
||||||
void TIMER0(void)
|
void TIMER0(void)
|
||||||
{
|
{
|
||||||
if (TIREQ & TF0) /* Timer0 reached ref value */
|
if (TIREQ & TIREQ_TF0) /* Timer0 reached ref value */
|
||||||
{
|
{
|
||||||
/* Run through the list of tick tasks */
|
/* Run through the list of tick tasks */
|
||||||
call_tick_tasks();
|
call_tick_tasks();
|
||||||
|
|
||||||
/* reset Timer 0 IRQ & ref flags */
|
/* reset Timer 0 IRQ & ref flags */
|
||||||
TIREQ |= TI0 | TF0;
|
TIREQ = TIREQ_TI0 | TIREQ_TF0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TC32IRQ & (1<<3)) /* end of TC32 prescale */
|
if (TIREQ & TIREQ_TF4) /* Timer4 reached ref value */
|
||||||
{
|
{
|
||||||
/* dispatch timer */
|
/* dispatch user timer */
|
||||||
|
if (pfn_timer != NULL)
|
||||||
|
pfn_timer();
|
||||||
|
|
||||||
|
TIREQ = TIREQ_TI4 | TIREQ_TF4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue