diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c | 51 | ||||
-rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c | 127 | ||||
-rw-r--r-- | firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h | 39 | ||||
-rw-r--r-- | firmware/target/arm/system-arm.h | 44 |
4 files changed, 229 insertions, 32 deletions
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c index 9df90a2344..39e4efab49 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/kernel-meg-fx.c | |||
@@ -1,13 +1,49 @@ | |||
1 | #include "config.h" | ||
2 | #include "system.h" | ||
1 | #include "kernel.h" | 3 | #include "kernel.h" |
4 | #include "timer.h" | ||
2 | #include "thread.h" | 5 | #include "thread.h" |
3 | 6 | ||
4 | #include <stdio.h> | ||
5 | #include "lcd.h" | ||
6 | |||
7 | extern void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); | 7 | extern void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); |
8 | 8 | ||
9 | void timer4(void) { | 9 | void tick_start(unsigned int interval_in_ms) |
10 | int i; | 10 | { |
11 | /* | ||
12 | * Based on default PCLK of 49.1568MHz - scaling chosen to give | ||
13 | * remainder-free result for tick interval of 10ms (100Hz) | ||
14 | * Timer input clock frequency = | ||
15 | * fPCLK / {prescaler value+1} / {divider value} | ||
16 | * TIMER_FREQ = 49156800 / 2 | ||
17 | * 13300 = TIMER_FREQ / 231 / 8 | ||
18 | * 49156800 = 19*(11)*(7)*7*5*5*(3)*2*2*2*2*2*2 | ||
19 | * 231 = 11*7*3 | ||
20 | */ | ||
21 | |||
22 | /* stop timer 4 */ | ||
23 | TCON &= ~(1 << 20); | ||
24 | /* Set the count for timer 4 */ | ||
25 | TCNTB4 = (TIMER_FREQ / 231 / 8) * interval_in_ms / 1000; | ||
26 | /* Set the the prescaler value for timers 2,3, and 4 */ | ||
27 | TCFG0 = (TCFG0 & ~0xff00) | ((231-1) << 8); | ||
28 | /* MUX4 = 1/16 */ | ||
29 | TCFG1 = (TCFG1 & ~0xff0000) | 0x030000; | ||
30 | /* set manual bit */ | ||
31 | TCON |= 1 << 21; | ||
32 | /* reset manual bit */ | ||
33 | TCON &= ~(1 << 21); | ||
34 | /* interval mode */ | ||
35 | TCON |= 1 << 22; | ||
36 | /* start timer 4 */ | ||
37 | TCON |= (1 << 20); | ||
38 | |||
39 | /* timer 4 unmask interrupts */ | ||
40 | INTMSK &= ~TIMER4_MASK; | ||
41 | } | ||
42 | |||
43 | void TIMER4(void) | ||
44 | { | ||
45 | int i; | ||
46 | |||
11 | /* Run through the list of tick tasks */ | 47 | /* Run through the list of tick tasks */ |
12 | for(i = 0; i < MAX_NUM_TICK_TASKS; i++) | 48 | for(i = 0; i < MAX_NUM_TICK_TASKS; i++) |
13 | { | 49 | { |
@@ -19,7 +55,6 @@ void timer4(void) { | |||
19 | 55 | ||
20 | current_tick++; | 56 | current_tick++; |
21 | 57 | ||
22 | /* following needs to be fixed. */ | 58 | SRCPND = TIMER4_MASK; |
23 | /*wake_up_thread();*/ | 59 | INTPND = TIMER4_MASK; |
24 | } | 60 | } |
25 | |||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c new file mode 100644 index 0000000000..4654c7c845 --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c | |||
@@ -0,0 +1,127 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Michael Sevakis | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "config.h" | ||
20 | #include "cpu.h" | ||
21 | #include "system.h" | ||
22 | #include "timer.h" | ||
23 | #include "logf.h" | ||
24 | |||
25 | /* GPB0/TOUT0 should already have been configured as output so that pin | ||
26 | should not be a functional pin and TIMER0 output unseen there */ | ||
27 | void TIMER0(void) | ||
28 | { | ||
29 | if (pfn_timer != NULL) | ||
30 | pfn_timer(); | ||
31 | |||
32 | SRCPND = TIMER0_MASK; | ||
33 | INTPND = TIMER0_MASK; | ||
34 | } | ||
35 | |||
36 | static void stop_timer(void) | ||
37 | { | ||
38 | /* mask interrupt */ | ||
39 | INTMSK |= TIMER0_MASK; | ||
40 | |||
41 | /* stop any running TIMER0 */ | ||
42 | TCON &= ~(1 << 0); | ||
43 | |||
44 | /* clear pending */ | ||
45 | SRCPND = TIMER0_MASK; | ||
46 | INTPND = TIMER0_MASK; | ||
47 | } | ||
48 | |||
49 | bool __timer_set(long cycles, bool start) | ||
50 | { | ||
51 | bool retval = false; | ||
52 | |||
53 | /* Find the minimum factor that puts the counter in range 1-65535 */ | ||
54 | unsigned int prescaler = (cycles + 65534) / 65535; | ||
55 | |||
56 | /* Maximum divider setting is x / 256 / 16 = x / 4096 */ | ||
57 | if (prescaler <= 4096) | ||
58 | { | ||
59 | int oldlevel; | ||
60 | unsigned int divider; | ||
61 | |||
62 | if (start && pfn_unregister != NULL) | ||
63 | { | ||
64 | pfn_unregister(); | ||
65 | pfn_unregister = NULL; | ||
66 | } | ||
67 | |||
68 | oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
69 | |||
70 | TCMPB0 = 0; | ||
71 | TCNTB0 = (unsigned int)cycles / prescaler; | ||
72 | |||
73 | /* Max prescale is 255+1 */ | ||
74 | for (divider = 0; prescaler > 256; prescaler >>= 1, divider++); | ||
75 | |||
76 | TCFG0 = (TCFG0 & ~0xff) | (prescaler - 1); | ||
77 | TCFG1 = (TCFG1 & ~0xf) | divider; | ||
78 | |||
79 | set_irq_level(oldlevel); | ||
80 | |||
81 | retval = true; | ||
82 | } | ||
83 | |||
84 | return retval; | ||
85 | } | ||
86 | |||
87 | bool __timer_register(void) | ||
88 | { | ||
89 | bool retval = true; | ||
90 | |||
91 | int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); | ||
92 | |||
93 | stop_timer(); | ||
94 | |||
95 | /* neurosis - make sure something didn't set GPB0 to TOUT0 */ | ||
96 | if ((GPBCON & 0x3) != 0x2) | ||
97 | { | ||
98 | /* manual update: on (to reset count) */ | ||
99 | TCON |= (1 << 1); | ||
100 | /* dead zone: off, inverter: off, manual off */ | ||
101 | TCON &= ~((1 << 4) | (1 << 2) | (1 << 1)); | ||
102 | /* interval mode (auto reload): on */ | ||
103 | TCON |= (1 << 3); | ||
104 | /* start timer */ | ||
105 | TCON |= (1 << 0); | ||
106 | /* unmask interrupt */ | ||
107 | INTMSK &= ~TIMER0_MASK; | ||
108 | } | ||
109 | |||
110 | if (!(TCON & (1 << 0))) | ||
111 | { | ||
112 | /* timer could not be started due to config error */ | ||
113 | logf("Timer error: GPB0 set to TOUT0"); | ||
114 | retval = false; | ||
115 | } | ||
116 | |||
117 | set_interrupt_status(oldstatus, IRQ_FIQ_STATUS); | ||
118 | |||
119 | return retval; | ||
120 | } | ||
121 | |||
122 | void __timer_unregister(void) | ||
123 | { | ||
124 | int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS); | ||
125 | stop_timer(); | ||
126 | set_interrupt_status(oldstatus, IRQ_FIQ_STATUS); | ||
127 | } | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h b/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h new file mode 100644 index 0000000000..e9f330cf8e --- /dev/null +++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-target.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Michael Sevakis | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef TIMER_TARGET_H | ||
20 | #define TIMER_TARGET_H | ||
21 | |||
22 | /* timer is based on PCLK and minimum division is 2 */ | ||
23 | #define TIMER_FREQ (49156800/2) | ||
24 | |||
25 | bool __timer_set(long cycles, bool set); | ||
26 | bool __timer_register(void); | ||
27 | void __timer_unregister(void); | ||
28 | |||
29 | #define __TIMER_SET(cycles, set) \ | ||
30 | __timer_set(cycles, set) | ||
31 | |||
32 | #define __TIMER_REGISTER(reg_prio, unregister_callback, cycles, \ | ||
33 | int_prio, timer_callback) \ | ||
34 | __timer_register() | ||
35 | |||
36 | #define __TIMER_UNREGISTER(...) \ | ||
37 | __timer_unregister() | ||
38 | |||
39 | #endif /* TIMER_TARGET_H */ | ||
diff --git a/firmware/target/arm/system-arm.h b/firmware/target/arm/system-arm.h index 99cab9e1a3..37c367fdc4 100644 --- a/firmware/target/arm/system-arm.h +++ b/firmware/target/arm/system-arm.h | |||
@@ -87,23 +87,6 @@ static inline uint32_t swap_odd_even32(uint32_t value) | |||
87 | return value; | 87 | return value; |
88 | } | 88 | } |
89 | 89 | ||
90 | #define HIGHEST_IRQ_LEVEL (0x80) | ||
91 | |||
92 | static inline int set_irq_level(int level) | ||
93 | { | ||
94 | unsigned long cpsr; | ||
95 | int oldlevel; | ||
96 | /* Read the old level and set the new one */ | ||
97 | asm volatile ( | ||
98 | "mrs %1, cpsr \n" | ||
99 | "bic %0, %1, #0x80 \n" | ||
100 | "orr %0, %0, %2 \n" | ||
101 | "msr cpsr_c, %0 \n" | ||
102 | : "=&r,r"(cpsr), "=&r,r"(oldlevel) : "r,i"(level & 0x80) | ||
103 | ); | ||
104 | return oldlevel; | ||
105 | } | ||
106 | |||
107 | static inline void set_fiq_handler(void(*fiq_handler)(void)) | 90 | static inline void set_fiq_handler(void(*fiq_handler)(void)) |
108 | { | 91 | { |
109 | /* Install the FIQ handler */ | 92 | /* Install the FIQ handler */ |
@@ -133,22 +116,35 @@ static inline void disable_fiq(void) | |||
133 | } | 116 | } |
134 | 117 | ||
135 | /* This one returns the old status */ | 118 | /* This one returns the old status */ |
136 | #define FIQ_ENABLED 0x00 | 119 | #define IRQ_ENABLED 0x00 |
137 | #define FIQ_DISABLED 0x40 | 120 | #define IRQ_DISABLED 0x80 |
138 | static inline int set_fiq_status(int status) | 121 | #define IRQ_STATUS 0x80 |
122 | #define FIQ_ENABLED 0x00 | ||
123 | #define FIQ_DISABLED 0x40 | ||
124 | #define FIQ_STATUS 0x40 | ||
125 | #define IRQ_FIQ_ENABLED 0x00 | ||
126 | #define IRQ_FIQ_DISABLED 0xc0 | ||
127 | #define IRQ_FIQ_STATUS 0xc0 | ||
128 | #define HIGHEST_IRQ_LEVEL IRQ_DISABLED | ||
129 | |||
130 | #define set_irq_level(status) set_interrupt_status((status), IRQ_STATUS) | ||
131 | #define set_fiq_status(status) set_interrupt_status((status), FIQ_STATUS) | ||
132 | |||
133 | static inline int set_interrupt_status(int status, int mask) | ||
139 | { | 134 | { |
140 | unsigned long cpsr; | 135 | unsigned long cpsr; |
141 | int oldstatus; | 136 | int oldstatus; |
142 | /* Read the old level and set the new one */ | 137 | /* Read the old levels and set the new ones */ |
143 | asm volatile ( | 138 | asm volatile ( |
144 | "mrs %1, cpsr \n" | 139 | "mrs %1, cpsr \n" |
145 | "bic %0, %1, #0x40 \n" | 140 | "bic %0, %1, %[mask] \n" |
146 | "orr %0, %0, %2 \n" | 141 | "orr %0, %0, %2 \n" |
147 | "msr cpsr_c, %0 \n" | 142 | "msr cpsr_c, %0 \n" |
148 | : "=&r,r"(cpsr), "=&r,r"(oldstatus) : "r,i"(status & 0x40) | 143 | : "=&r,r"(cpsr), "=&r,r"(oldstatus) |
144 | : "r,i"(status & mask), [mask]"i,i"(mask) | ||
149 | ); | 145 | ); |
146 | |||
150 | return oldstatus; | 147 | return oldstatus; |
151 | } | 148 | } |
152 | 149 | ||
153 | |||
154 | #endif /* SYSTEM_ARM_H */ | 150 | #endif /* SYSTEM_ARM_H */ |