summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/export/s5l8702.h32
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c27
-rw-r--r--firmware/target/arm/s5l8702/timer-s5l8702.c57
3 files changed, 69 insertions, 47 deletions
diff --git a/firmware/export/s5l8702.h b/firmware/export/s5l8702.h
index 8e1d827f54..a83fe371e0 100644
--- a/firmware/export/s5l8702.h
+++ b/firmware/export/s5l8702.h
@@ -28,8 +28,6 @@
28#define REG16_PTR_T volatile uint16_t * 28#define REG16_PTR_T volatile uint16_t *
29#define REG32_PTR_T volatile uint32_t * 29#define REG32_PTR_T volatile uint32_t *
30 30
31#define TIMER_FREQ 54000000
32
33#define CACHEALIGN_BITS (5) /* 2^5 = 32 bytes */ 31#define CACHEALIGN_BITS (5) /* 2^5 = 32 bytes */
34 32
35#define DRAM_ORIG 0x08000000 33#define DRAM_ORIG 0x08000000
@@ -65,6 +63,34 @@
65 63
66 64
67/////TIMER///// 65/////TIMER/////
66/* 16/32-bit timers:
67 *
68 * - Timers A..D: 16-bit counter, very similar to 16-bit timers described
69 * in S5L8700 DS, it seems that the timers C and D are disabled or not
70 * implemented.
71 *
72 * - Timers E..H: 32-bit counter, they are like 16-bit timers, but the
73 * interrupt status for all 32-bit timers is located in TSTAT register.
74 *
75 * - Clock source configuration:
76 *
77 * TCON[10:8] (Tx_CS) TCON[6]=0 TCON[6]=1
78 * ------------------ --------- ---------
79 * 000 PCLK / 2 ECLK / 2
80 * 001 PCLK / 4 ECLK / 4
81 * 010 PCLK / 16 ECLK / 16
82 * 011 PCLK / 64 ECLK / 64
83 * 10x (timers E..H) PCLK ECLK
84 * 10x (timers A..D) Ext. Clock 0 Ext. Clock 0
85 * 11x Ext. Clock 1 Ext. Clock 1
86 *
87 * On Classic:
88 * - Ext. Clock 0: not connected or disabled
89 * - Ext. Clock 1: 32768 Hz, external OSC1?, PMU?
90 * - ECLK: 12 MHz, external OSC0?
91 */
92#define TIMER_FREQ 12000000 /* ECLK */
93
68#define TACON (*((uint32_t volatile*)(0x3C700000))) 94#define TACON (*((uint32_t volatile*)(0x3C700000)))
69#define TACMD (*((uint32_t volatile*)(0x3C700004))) 95#define TACMD (*((uint32_t volatile*)(0x3C700004)))
70#define TADATA0 (*((uint32_t volatile*)(0x3C700008))) 96#define TADATA0 (*((uint32_t volatile*)(0x3C700008)))
@@ -113,6 +139,7 @@
113#define THDATA1 (*((uint32_t volatile*)(0x3C70010C))) 139#define THDATA1 (*((uint32_t volatile*)(0x3C70010C)))
114#define THPRE (*((uint32_t volatile*)(0x3C700110))) 140#define THPRE (*((uint32_t volatile*)(0x3C700110)))
115#define THCNT (*((uint32_t volatile*)(0x3C700114))) 141#define THCNT (*((uint32_t volatile*)(0x3C700114)))
142#define TSTAT (*((uint32_t volatile*)(0x3C700118)))
116#define USEC_TIMER TECNT 143#define USEC_TIMER TECNT
117 144
118 145
@@ -816,6 +843,7 @@ struct dma_lli
816 843
817 844
818/////INTERRUPTS///// 845/////INTERRUPTS/////
846#define IRQ_TIMER32 7
819#define IRQ_TIMER 8 847#define IRQ_TIMER 8
820#define IRQ_USB_FUNC 19 848#define IRQ_USB_FUNC 19
821#define IRQ_DMAC(d) 16 + d 849#define IRQ_DMAC(d) 16 + d
diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c
index c3f20c506b..09aff3d84e 100644
--- a/firmware/target/arm/s5l8702/system-s5l8702.c
+++ b/firmware/target/arm/s5l8702/system-s5l8702.c
@@ -39,15 +39,14 @@ default_interrupt(INT_IRQ3);
39default_interrupt(INT_IRQ4); 39default_interrupt(INT_IRQ4);
40default_interrupt(INT_IRQ5); 40default_interrupt(INT_IRQ5);
41default_interrupt(INT_IRQ6); 41default_interrupt(INT_IRQ6);
42default_interrupt(INT_IRQ7); 42default_interrupt(INT_TIMERE); /* IRQ7: 32-bit timers */
43default_interrupt(INT_TIMERA);
44default_interrupt(INT_TIMERB);
45default_interrupt(INT_TIMERC);
46default_interrupt(INT_TIMERD);
47default_interrupt(INT_TIMERE);
48default_interrupt(INT_TIMERF); 43default_interrupt(INT_TIMERF);
49default_interrupt(INT_TIMERG); 44default_interrupt(INT_TIMERG);
50default_interrupt(INT_TIMERH); 45default_interrupt(INT_TIMERH);
46default_interrupt(INT_TIMERA); /* IRQ8: 16-bit timers */
47default_interrupt(INT_TIMERB);
48default_interrupt(INT_TIMERC);
49default_interrupt(INT_TIMERD);
51default_interrupt(INT_IRQ9); 50default_interrupt(INT_IRQ9);
52default_interrupt(INT_IRQ10); 51default_interrupt(INT_IRQ10);
53default_interrupt(INT_IRQ11); 52default_interrupt(INT_IRQ11);
@@ -129,9 +128,16 @@ void INT_TIMER()
129 if (TBCON & (TBCON >> 4) & 0x7000) INT_TIMERB(); 128 if (TBCON & (TBCON >> 4) & 0x7000) INT_TIMERB();
130 if (TCCON & (TCCON >> 4) & 0x7000) INT_TIMERC(); 129 if (TCCON & (TCCON >> 4) & 0x7000) INT_TIMERC();
131 if (TDCON & (TDCON >> 4) & 0x7000) INT_TIMERD(); 130 if (TDCON & (TDCON >> 4) & 0x7000) INT_TIMERD();
132 if (TFCON & (TFCON >> 4) & 0x7000) INT_TIMERF(); 131}
133 if (TGCON & (TGCON >> 4) & 0x7000) INT_TIMERG(); 132
134 if (THCON & (THCON >> 4) & 0x7000) INT_TIMERH(); 133void INT_TIMER32(void) ICODE_ATTR;
134void INT_TIMER32()
135{
136 uint32_t tstat = TSTAT;
137 /*if ((TECON >> 12) & 0x7 & (tstat >> 24)) INT_TIMERE();*/
138 if ((TFCON >> 12) & 0x7 & (tstat >> 16)) INT_TIMERF();
139 if ((TGCON >> 12) & 0x7 & (tstat >> 8)) INT_TIMERG();
140 if ((THCON >> 12) & 0x7 & tstat) INT_TIMERH();
135} 141}
136 142
137void INT_DMAC0(void) ICODE_ATTR; 143void INT_DMAC0(void) ICODE_ATTR;
@@ -164,7 +170,7 @@ void INT_DMAC1()
164 170
165static void (* const irqvector[])(void) = 171static void (* const irqvector[])(void) =
166{ 172{
167 INT_IRQ0,INT_IRQ1,INT_IRQ2,INT_IRQ3,INT_IRQ4,INT_IRQ5,INT_IRQ6,INT_IRQ7, 173 INT_IRQ0,INT_IRQ1,INT_IRQ2,INT_IRQ3,INT_IRQ4,INT_IRQ5,INT_IRQ6,INT_TIMER32,
168 INT_TIMER,INT_IRQ9,INT_IRQ10,INT_IRQ11,INT_IRQ12,INT_IRQ13,INT_IRQ14,INT_IRQ15, 174 INT_TIMER,INT_IRQ9,INT_IRQ10,INT_IRQ11,INT_IRQ12,INT_IRQ13,INT_IRQ14,INT_IRQ15,
169 INT_DMAC0,INT_DMAC1,INT_IRQ18,INT_USB_FUNC,INT_IRQ20,INT_IRQ21,INT_IRQ22,INT_WHEEL, 175 INT_DMAC0,INT_DMAC1,INT_IRQ18,INT_USB_FUNC,INT_IRQ20,INT_IRQ21,INT_IRQ22,INT_WHEEL,
170 INT_IRQ24,INT_IRQ25,INT_IRQ26,INT_IRQ27,INT_IRQ28,INT_ATA,INT_IRQ30,INT_IRQ31, 176 INT_IRQ24,INT_IRQ25,INT_IRQ26,INT_IRQ27,INT_IRQ28,INT_ATA,INT_IRQ30,INT_IRQ31,
@@ -220,6 +226,7 @@ void system_init(void)
220 VIC0INTENABLE = 1 << IRQ_WHEEL; 226 VIC0INTENABLE = 1 << IRQ_WHEEL;
221 VIC0INTENABLE = 1 << IRQ_ATA; 227 VIC0INTENABLE = 1 << IRQ_ATA;
222 VIC1INTENABLE = 1 << (IRQ_MMC - 32); 228 VIC1INTENABLE = 1 << (IRQ_MMC - 32);
229 VIC0INTENABLE = 1 << IRQ_TIMER32;
223} 230}
224 231
225void system_reboot(void) 232void system_reboot(void)
diff --git a/firmware/target/arm/s5l8702/timer-s5l8702.c b/firmware/target/arm/s5l8702/timer-s5l8702.c
index 61d4d590e4..7c69ab123a 100644
--- a/firmware/target/arm/s5l8702/timer-s5l8702.c
+++ b/firmware/target/arm/s5l8702/timer-s5l8702.c
@@ -26,13 +26,11 @@
26#include "system.h" 26#include "system.h"
27#include "timer.h" 27#include "timer.h"
28 28
29//TODO: This needs calibration once we figure out the clocking 29void INT_TIMERF(void)
30
31void INT_TIMERC(void)
32{ 30{
33 /* clear interrupt */ 31 /* clear interrupt */
34 TCCON = TCCON; 32 TSTAT = (0x07 << 16);
35 33
36 if (pfn_timer != NULL) { 34 if (pfn_timer != NULL) {
37 pfn_timer(); 35 pfn_timer();
38 } 36 }
@@ -40,12 +38,8 @@ void INT_TIMERC(void)
40 38
41bool timer_set(long cycles, bool start) 39bool timer_set(long cycles, bool start)
42{ 40{
43 static const int cs_table[] = {1, 2, 4, 6}; 41 /* stop timer */
44 int prescale, cs; 42 TFCMD = (0 << 0); /* TF_ENABLE */
45 long count;
46
47 /* stop and clear timer */
48 TCCMD = (1 << 1); /* TD_CLR */
49 43
50 /* optionally unregister any previously registered timer user */ 44 /* optionally unregister any previously registered timer user */
51 if (start) { 45 if (start) {
@@ -55,40 +49,33 @@ bool timer_set(long cycles, bool start)
55 } 49 }
56 } 50 }
57 51
58 /* scale the count down with the clock select */ 52 /* There is an odd behaviour when the 32-bit timers are launched
59 for (cs = 0; cs < 4; cs++) { 53 for the first time, the interrupt status bits are set and an
60 count = cycles >> cs_table[cs]; 54 unexpected interrupt is generated if they are enabled. A way to
61 if ((count < 65536) || (cs == 3)) { 55 workaround this is to write the data registers before clearing
62 break; 56 the counter. */
63 } 57 TFDATA0 = cycles;
64 } 58 TFCMD = (1 << 1); /* TF_CLR */
65
66 /* scale the count down with the prescaler */
67 prescale = 1;
68 while (count >= 65536) {
69 count >>= 1;
70 prescale <<= 1;
71 }
72 59
73 /* configure timer */ 60 /* configure timer */
74 TCCON = (1 << 12) | /* TD_INT0_EN */ 61 TFCON = (1 << 12) | /* TF_INT0_EN */
75 (cs << 8) | /* TS_CS */ 62 (4 << 8) | /* TF_CS, 4 = ECLK / 1 */
76 (0 << 4); /* TD_MODE_SEL, 0 = interval mode */ 63 (1 << 6) | /* use ECLK (12MHz) */
77 TCPRE = prescale - 1; 64 (0 << 4); /* TF_MODE_SEL, 0 = interval mode */
78 TCDATA0 = count; 65 TFPRE = 0; /* no prescaler */
79 TCCMD = (1 << 0); /* TD_ENABLE */ 66
80 67 TFCMD = (1 << 0); /* TF_ENABLE */
68
81 return true; 69 return true;
82} 70}
83 71
84bool timer_start(void) 72bool timer_start(void)
85{ 73{
86 TCCMD = (1 << 0); /* TD_ENABLE */ 74 TFCMD = (1 << 0); /* TF_ENABLE */
87 return true; 75 return true;
88} 76}
89 77
90void timer_stop(void) 78void timer_stop(void)
91{ 79{
92 TCCMD = (0 << 0); /* TD_ENABLE */ 80 TFCMD = (0 << 0); /* TF_ENABLE */
93} 81}
94