summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Purchase <shotofadds@rockbox.org>2009-03-30 21:15:15 +0000
committerRob Purchase <shotofadds@rockbox.org>2009-03-30 21:15:15 +0000
commit75b37696fba2e0c5c1e9f28449fda7d6c7f9a9ac (patch)
tree30d308bcc748733e5eefd7684aafa2d7e62c67a1
parent8739af490e03e243848720c5987f566a56479136 (diff)
downloadrockbox-75b37696fba2e0c5c1e9f28449fda7d6c7f9a9ac.tar.gz
rockbox-75b37696fba2e0c5c1e9f28449fda7d6c7f9a9ac.zip
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
-rw-r--r--firmware/export/tcc780x.h41
-rw-r--r--firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c38
-rw-r--r--firmware/target/arm/tcc780x/kernel-tcc780x.c9
-rw-r--r--firmware/target/arm/tcc780x/system-target.h6
-rw-r--r--firmware/target/arm/tcc780x/system-tcc780x.c7
-rw-r--r--firmware/target/arm/tcc780x/timer-target.h4
-rw-r--r--firmware/target/arm/tcc780x/timer-tcc780x.c62
7 files changed, 103 insertions, 64 deletions
diff --git a/firmware/export/tcc780x.h b/firmware/export/tcc780x.h
index b10b311fed..3ff910fce7 100644
--- a/firmware/export/tcc780x.h
+++ b/firmware/export/tcc780x.h
@@ -132,20 +132,37 @@
132 132
133/* Timer / Counters */ 133/* Timer / Counters */
134 134
135#define TCFG0 (*(volatile unsigned long *)0xF3003000) 135/* Note: Timers 0-3 have a 16 bit counter, 4-5 have 20 bits */
136#define TCNT0 (*(volatile unsigned long *)0xF3003004) 136#define TCFG(_x_) (*(volatile unsigned int *)(0xF3003000+0x10*(_x_)))
137#define TREF0 (*(volatile unsigned long *)0xF3003008) 137#define TCNT(_x_) (*(volatile unsigned int *)(0xF3003004+0x10*(_x_)))
138#define TCFG1 (*(volatile unsigned long *)0xF3003010) 138#define TREF(_x_) (*(volatile unsigned int *)(0xF3003008+0x10*(_x_)))
139#define TCNT1 (*(volatile unsigned long *)0xF3003014) 139
140#define TREF1 (*(volatile unsigned long *)0xF3003018) 140#define TIREQ (*(volatile unsigned long *)0xF3003060)
141 141
142#define TIREQ (*(volatile unsigned long *)0xF3003060) 142/* TCFG flags */
143#define TCFG_EN (1<<0) /* enable timer */
144#define TCFG_CONT (1<<1) /* continue from zero once TREF is reached */
145#define TCFG_PWM (1<<2) /* PWM mode */
146#define TCFG_IEN (1<<3) /* IRQ enable */
147#define TCFG_SEL (1<<4) /* clock source & divider */
148#define TCFG_POL (1<<7) /* polarity */
149#define TCFG_CLEAR (1<<8) /* reset TCNT to zero */
150#define TCFG_STOP (1<<9) /* stop counting once TREF reached */
143 151
144/* TIREQ flags */ 152/* TIREQ flags */
145#define TF0 (1<<8) /* Timer 0 reference value reached */ 153#define TIREQ_TI0 (1<<0) /* Timer N IRQ flag */
146#define TF1 (1<<9) /* Timer 1 reference value reached */ 154#define TIREQ_TI1 (1<<1)
147#define TI0 (1<<0) /* Timer 0 IRQ flag */ 155#define TIREQ_TI2 (1<<2)
148#define TI1 (1<<1) /* Timer 1 IRQ flag */ 156#define TIREQ_TI3 (1<<3)
157#define TIREQ_TI4 (1<<4)
158#define TIREQ_TI5 (1<<5)
159
160#define TIREQ_TF0 (1<<8) /* Timer N reference value reached */
161#define TIREQ_TF1 (1<<9)
162#define TIREQ_TF2 (1<<10)
163#define TIREQ_TF3 (1<<11)
164#define TIREQ_TF4 (1<<12)
165#define TIREQ_TF5 (1<<13)
149 166
150#define TC32EN (*(volatile unsigned long *)0xF3003080) 167#define TC32EN (*(volatile unsigned long *)0xF3003080)
151#define TC32LDV (*(volatile unsigned long *)0xF3003084) 168#define TC32LDV (*(volatile unsigned long *)0xF3003084)
diff --git a/firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c b/firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c
index 7b64493c0a..d0b7e9214e 100644
--- a/firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c
+++ b/firmware/target/arm/tcc780x/cowond2/lcd-cowond2.c
@@ -116,33 +116,11 @@ static void lcd_write_reg(unsigned char reg, unsigned short val)
116 restore_irq(level); 116 restore_irq(level);
117} 117}
118 118
119
120/*
121 TEMP: Rough millisecond delay routine used by the LCD panel init sequence.
122 PCK_TCT must first have been initialised to 2Mhz by calling clock_init().
123*/
124static void sleep_ms(unsigned int ms)
125{
126 /* disable timer */
127 TCFG1 = 0;
128
129 /* set Timer1 reference value based on 125kHz tick */
130 TREF1 = ms * 125;
131
132 /* single count, zero the counter, divider = 16 [2^(3+1)], enable */
133 TCFG1 = (1<<9) | (1<<8) | (3<<4) | 1;
134
135 /* wait until Timer1 ref reached */
136 while (!(TIREQ & TF1)) {};
137}
138
139
140static void lcd_display_on(void) 119static void lcd_display_on(void)
141{ 120{
142 /* power on sequence as per the D2 firmware */ 121 /* power on sequence as per the D2 firmware */
143 GPIOA_SET = (1<<16); 122 GPIOA_SET = (1<<16);
144 123 udelay(10000);
145 sleep_ms(10);
146 124
147 lcd_write_reg(1, 0x1D); 125 lcd_write_reg(1, 0x1D);
148 lcd_write_reg(2, 0x0); 126 lcd_write_reg(2, 0x0);
@@ -164,14 +142,14 @@ static void lcd_display_on(void)
164 lcd_write_reg(23, 0x0); 142 lcd_write_reg(23, 0x0);
165 lcd_write_reg(24, 0x0); 143 lcd_write_reg(24, 0x0);
166 lcd_write_reg(25, 0x0); 144 lcd_write_reg(25, 0x0);
167 sleep_ms(10); 145 udelay(10000);
168 146
169 lcd_write_reg(9, 0x4055); 147 lcd_write_reg(9, 0x4055);
170 lcd_write_reg(10, 0x0); 148 lcd_write_reg(10, 0x0);
171 sleep_ms(40); 149 udelay(40000);
172 150
173 lcd_write_reg(10, 0x2000); 151 lcd_write_reg(10, 0x2000);
174 sleep_ms(40); 152 udelay(40000);
175 153
176 lcd_write_reg(1, 0xC01D); 154 lcd_write_reg(1, 0xC01D);
177 lcd_write_reg(2, 0x204); 155 lcd_write_reg(2, 0x204);
@@ -191,11 +169,11 @@ static void lcd_display_on(void)
191 lcd_write_reg(23, 0x406); 169 lcd_write_reg(23, 0x406);
192 lcd_write_reg(24, 0x2); 170 lcd_write_reg(24, 0x2);
193 lcd_write_reg(25, 0x0); 171 lcd_write_reg(25, 0x0);
194 sleep_ms(60); 172 udelay(60000);
195 173
196 lcd_write_reg(9, 0xA55); 174 lcd_write_reg(9, 0xA55);
197 lcd_write_reg(10, 0x111F); 175 lcd_write_reg(10, 0x111F);
198 sleep_ms(10); 176 udelay(10000);
199 177
200 /* tell that we're on now */ 178 /* tell that we're on now */
201 display_on = true; 179 display_on = true;
@@ -210,10 +188,10 @@ static void lcd_display_off(void)
210 lcd_write_reg(9, 0x55); 188 lcd_write_reg(9, 0x55);
211 lcd_write_reg(10, 0x1417); 189 lcd_write_reg(10, 0x1417);
212 lcd_write_reg(5, 0x4003); 190 lcd_write_reg(5, 0x4003);
213 sleep_ms(10); 191 udelay(10000);
214 192
215 lcd_write_reg(9, 0x0); 193 lcd_write_reg(9, 0x0);
216 sleep_ms(10); 194 udelay(10000);
217 195
218 /* kill power to LCD panel (unconfirmed) */ 196 /* kill power to LCD panel (unconfirmed) */
219 GPIOA_CLEAR = (1<<16); 197 GPIOA_CLEAR = (1<<16);
diff --git a/firmware/target/arm/tcc780x/kernel-tcc780x.c b/firmware/target/arm/tcc780x/kernel-tcc780x.c
index e5d96d288a..dee5e040e2 100644
--- a/firmware/target/arm/tcc780x/kernel-tcc780x.c
+++ b/firmware/target/arm/tcc780x/kernel-tcc780x.c
@@ -29,16 +29,13 @@
29void tick_start(unsigned int interval_in_ms) 29void tick_start(unsigned int interval_in_ms)
30{ 30{
31 /* disable Timer0 */ 31 /* disable Timer0 */
32 TCFG0 &= ~1; 32 TCFG(0) &= ~TCFG_EN;
33 33
34 /* set counter reference value based on 1Mhz tick */ 34 /* set counter reference value based on 1Mhz tick */
35 TREF0 = interval_in_ms * 1000; 35 TREF(0) = interval_in_ms * 1000;
36 36
37 /* Timer0 = reset to 0, divide=2, IRQ enable, enable (continuous) */ 37 /* Timer0 = reset to 0, divide=2, IRQ enable, enable (continuous) */
38 TCFG0 = (1<<8) | (0<<4) | (1<<3) | 1; 38 TCFG(0) = TCFG_CLEAR | (0 << TCFG_SEL) | TCFG_IEN | TCFG_EN;
39
40 /* Unmask timer IRQ */
41 IEN |= TIMER0_IRQ_MASK;
42} 39}
43 40
44/* NB: Since we are using a single timer IRQ, tick tasks are dispatched as 41/* NB: Since we are using a single timer IRQ, tick tasks are dispatched as
diff --git a/firmware/target/arm/tcc780x/system-target.h b/firmware/target/arm/tcc780x/system-target.h
index 0802bb92e0..6e2e7be980 100644
--- a/firmware/target/arm/tcc780x/system-target.h
+++ b/firmware/target/arm/tcc780x/system-target.h
@@ -35,10 +35,12 @@
35#define outw(a,b) (*(volatile unsigned short *) (b) = (a)) 35#define outw(a,b) (*(volatile unsigned short *) (b) = (a))
36 36
37/* TC32 is configured to 1MHz in clock_init() */ 37/* TC32 is configured to 1MHz in clock_init() */
38#define USEC_TIMER TC32MCNT
39
38static inline void udelay(unsigned usecs) 40static inline void udelay(unsigned usecs)
39{ 41{
40 unsigned stop = TC32MCNT + usecs; 42 unsigned stop = USEC_TIMER + usecs;
41 while (TIME_BEFORE(TC32MCNT, stop)); 43 while (TIME_BEFORE(USEC_TIMER, stop));
42} 44}
43 45
44#endif /* SYSTEM_TARGET_H */ 46#endif /* SYSTEM_TARGET_H */
diff --git a/firmware/target/arm/tcc780x/system-tcc780x.c b/firmware/target/arm/tcc780x/system-tcc780x.c
index 77ae3a4cd9..ab8a6cf218 100644
--- a/firmware/target/arm/tcc780x/system-tcc780x.c
+++ b/firmware/target/arm/tcc780x/system-tcc780x.c
@@ -229,11 +229,14 @@ static void clock_init(void)
229 "nop \n\t" 229 "nop \n\t"
230 ); 230 );
231 231
232 /* configure PCK_TCT to 2Mhz (clock source 4 (Xin) divided by 6) */ 232 /* Configure PCK_TCT to 2Mhz (Xin divided by 6) */
233 PCLK_TCT = PCK_EN | (CKSEL_XIN<<24) | 5; 233 PCLK_TCT = PCK_EN | (CKSEL_XIN<<24) | 5;
234 234
235 /* set TC32 timer to XIN divided by 12 (1MHz) */ 235 /* Set TC32 timer to be our USEC_TIMER (Xin divided by 12 = 1MHz) */
236 TC32EN = (1<<24) | 11; 236 TC32EN = (1<<24) | 11;
237
238 /* Unmask common timer IRQ (shared by tick and user timer) */
239 IEN |= TIMER0_IRQ_MASK;
237} 240}
238#endif 241#endif
239 242
diff --git a/firmware/target/arm/tcc780x/timer-target.h b/firmware/target/arm/tcc780x/timer-target.h
index 991d949447..10090ceddc 100644
--- a/firmware/target/arm/tcc780x/timer-target.h
+++ b/firmware/target/arm/tcc780x/timer-target.h
@@ -21,8 +21,8 @@
21#ifndef TIMER_TARGET_H 21#ifndef TIMER_TARGET_H
22#define TIMER_TARGET_H 22#define TIMER_TARGET_H
23 23
24/* timers are based on XIN (12Mhz) */ 24/* Timer is based on PCK_TCT (set to 2Mhz in system.c) */
25#define TIMER_FREQ (12000000) 25#define TIMER_FREQ (2000000)
26 26
27bool __timer_set(long cycles, bool set); 27bool __timer_set(long cycles, bool set);
28bool __timer_register(void); 28bool __timer_register(void);
diff --git a/firmware/target/arm/tcc780x/timer-tcc780x.c b/firmware/target/arm/tcc780x/timer-tcc780x.c
index 17956131c0..ca6613a3ff 100644
--- a/firmware/target/arm/tcc780x/timer-tcc780x.c
+++ b/firmware/target/arm/tcc780x/timer-tcc780x.c
@@ -25,40 +25,82 @@
25#include "timer.h" 25#include "timer.h"
26#include "logf.h" 26#include "logf.h"
27 27
28/* Use the TC32 counter [sourced by Xin:12Mhz] for this timer, as it's the 28static const int prescale_shifts[] = {1, 2, 3, 4, 5, 10, 12};
29 only one that allows a 32-bit counter (Timer0-5 are 16/20 bit only). */
30 29
31bool __timer_set(long cycles, bool start) 30bool __timer_set(long cycles, bool start)
32{ 31{
33 (void)cycles; 32 bool found = false;
34 (void)start; 33
35 return false; 34 int prescale_option = 0;
35 int actual_cycles = 0;
36
37 /* Use the first prescale that fits Timer4's 20-bit counter */
38 while (!found && prescale_option < 7)
39 {
40 actual_cycles = cycles >> prescale_shifts[prescale_option];
41
42 if (actual_cycles < 0x100000)
43 found = true;
44 else
45 prescale_option++;
46 }
47
48 if (!found)
49 return false;
50
51 /* Stop the timer and set new prescale & ref count */
52 TCFG(4) &= ~TCFG_EN;
53 TCFG(4) = prescale_option << TCFG_SEL;
54 TREF(4) = actual_cycles;
55
56 if (start && pfn_unregister != NULL)
57 {
58 pfn_unregister();
59 pfn_unregister = NULL;
60 }
61
62 return true;
36} 63}
37 64
38bool __timer_register(void) 65bool __timer_register(void)
39{ 66{
40 return false; 67 int oldstatus = disable_interrupt_save(IRQ_STATUS);
68
69 TCFG(4) |= TCFG_CLEAR | TCFG_IEN | TCFG_EN;
70
71 restore_interrupt(oldstatus);
72
73 return true;
41} 74}
42 75
43void __timer_unregister(void) 76void __timer_unregister(void)
44{ 77{
78 int oldstatus = disable_interrupt_save(IRQ_STATUS);
79
80 TCFG(4) &= ~TCFG_EN;
81
82 restore_interrupt(oldstatus);
45} 83}
46 84
47 85
48/* Timer interrupt processing - all timers (inc. tick) have a single IRQ */ 86/* Timer interrupt processing - all timers (inc. tick) have a single IRQ */
49void TIMER0(void) 87void TIMER0(void)
50{ 88{
51 if (TIREQ & TF0) /* Timer0 reached ref value */ 89 if (TIREQ & TIREQ_TF0) /* Timer0 reached ref value */
52 { 90 {
53 /* Run through the list of tick tasks */ 91 /* Run through the list of tick tasks */
54 call_tick_tasks(); 92 call_tick_tasks();
55 93
56 /* reset Timer 0 IRQ & ref flags */ 94 /* reset Timer 0 IRQ & ref flags */
57 TIREQ |= TI0 | TF0; 95 TIREQ = TIREQ_TI0 | TIREQ_TF0;
58 } 96 }
59 97
60 if (TC32IRQ & (1<<3)) /* end of TC32 prescale */ 98 if (TIREQ & TIREQ_TF4) /* Timer4 reached ref value */
61 { 99 {
62 /* dispatch timer */ 100 /* dispatch user timer */
101 if (pfn_timer != NULL)
102 pfn_timer();
103
104 TIREQ = TIREQ_TI4 | TIREQ_TF4;
63 } 105 }
64} 106}