diff options
Diffstat (limited to 'firmware/target/arm/tcc780x/system-tcc780x.c')
-rw-r--r-- | firmware/target/arm/tcc780x/system-tcc780x.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/firmware/target/arm/tcc780x/system-tcc780x.c b/firmware/target/arm/tcc780x/system-tcc780x.c new file mode 100644 index 0000000000..30221d180e --- /dev/null +++ b/firmware/target/arm/tcc780x/system-tcc780x.c | |||
@@ -0,0 +1,275 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Rob Purchase | ||
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 | |||
20 | #include "kernel.h" | ||
21 | #include "system.h" | ||
22 | #include "panic.h" | ||
23 | |||
24 | #if !defined(BOOTLOADER) | ||
25 | |||
26 | #define default_interrupt(name) \ | ||
27 | extern __attribute__((weak,alias("UIRQ"))) void name (void) | ||
28 | |||
29 | void irq_handler(void) __attribute__((interrupt ("IRQ"), naked)); | ||
30 | void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked)); | ||
31 | |||
32 | default_interrupt(EXT0); | ||
33 | default_interrupt(EXT1); | ||
34 | default_interrupt(EXT2); | ||
35 | default_interrupt(EXT3); | ||
36 | default_interrupt(IRQ4); | ||
37 | default_interrupt(IRQ5); | ||
38 | default_interrupt(TIMER); | ||
39 | default_interrupt(IRQ7); | ||
40 | default_interrupt(IRQ8); | ||
41 | default_interrupt(IRQ9); | ||
42 | default_interrupt(IRQ10); | ||
43 | default_interrupt(IRQ11); | ||
44 | default_interrupt(IRQ12); | ||
45 | default_interrupt(IRQ13); | ||
46 | default_interrupt(DAI_RX); | ||
47 | default_interrupt(DAI_TX); | ||
48 | default_interrupt(IRQ16); | ||
49 | default_interrupt(IRQ17); | ||
50 | default_interrupt(IRQ18); | ||
51 | default_interrupt(IRQ19); | ||
52 | default_interrupt(IRQ20); | ||
53 | default_interrupt(IRQ21); | ||
54 | default_interrupt(IRQ22); | ||
55 | default_interrupt(IRQ23); | ||
56 | default_interrupt(IRQ24); | ||
57 | default_interrupt(IRQ25); | ||
58 | default_interrupt(IRQ26); | ||
59 | default_interrupt(IRQ27); | ||
60 | default_interrupt(IRQ28); | ||
61 | default_interrupt(IRQ29); | ||
62 | default_interrupt(IRQ30); | ||
63 | default_interrupt(IRQ31); | ||
64 | |||
65 | static void (* const irqvector[])(void) = | ||
66 | { | ||
67 | EXT0,EXT1,EXT2,EXT3,IRQ4,IRQ5,TIMER,IRQ7, | ||
68 | IRQ8,IRQ9,IRQ10,IRQ11,IRQ12,IRQ13,DAI_RX,DAI_TX, | ||
69 | IRQ16,IRQ17,IRQ18,IRQ19,IRQ20,IRQ21,IRQ22,IRQ23, | ||
70 | IRQ24,IRQ25,IRQ26,IRQ27,IRQ28,IRQ29,IRQ30,IRQ31 | ||
71 | }; | ||
72 | |||
73 | static const char * const irqname[] = | ||
74 | { | ||
75 | "EXT0","EXT1","EXT2","EXT3","IRQ4","IRQ5","TIMER","IRQ7", | ||
76 | "IRQ8","IRQ9","IRQ10","IRQ11","IRQ12","IRQ13","DAI_RX","DAI_TX", | ||
77 | "IRQ16","IRQ17","IRQ18","IRQ19","IRQ20","IRQ21","IRQ22","IRQ23", | ||
78 | "IRQ24","IRQ25","IRQ26","IRQ27","IRQ28","IRQ29","IRQ30","IRQ31" | ||
79 | }; | ||
80 | |||
81 | static void UIRQ(void) | ||
82 | { | ||
83 | unsigned int offset = VNIRQ; | ||
84 | panicf("Unhandled IRQ %02X: %s", offset, irqname[offset]); | ||
85 | } | ||
86 | |||
87 | void irq_handler(void) | ||
88 | { | ||
89 | /* | ||
90 | * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c | ||
91 | */ | ||
92 | |||
93 | asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */ | ||
94 | "sub sp, sp, #8 \n"); /* Reserve stack */ | ||
95 | irqvector[VNIRQ](); | ||
96 | asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */ | ||
97 | "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ | ||
98 | "subs pc, lr, #4 \n"); /* Return from FIQ */ | ||
99 | } | ||
100 | |||
101 | void fiq_handler(void) | ||
102 | { | ||
103 | asm volatile ( | ||
104 | "sub lr, lr, #4 \r\n" | ||
105 | "movs lr,pc \r\n" | ||
106 | ); | ||
107 | } | ||
108 | #endif /* !defined(BOOTLOADER) */ | ||
109 | |||
110 | |||
111 | /* TODO: | ||
112 | a) this is not the place for this function | ||
113 | b) it currently ignores the supplied frequency and uses default values | ||
114 | c) if the PLL being set drives any PCKs, an appropriate new clock divider | ||
115 | will have to be re-calculated for those PCKs (the OF maintains a list of | ||
116 | PCK frequencies for this purpose). | ||
117 | */ | ||
118 | void set_pll_frequency(unsigned int pll_number, unsigned int frequency) | ||
119 | { | ||
120 | int i = 0; | ||
121 | |||
122 | if (pll_number > 1) return; | ||
123 | |||
124 | /* The frequency parameter is currently ignored and temporary values are | ||
125 | used (PLL0=192Mhz, PLL1=216Mhz). The D2 firmware uses a lookup table | ||
126 | to derive the values of PLLxCFG from a the supplied frequency. | ||
127 | Presumably we will need to do something similar. */ | ||
128 | if (pll_number == 0) | ||
129 | { | ||
130 | /* drive CPU off Xin while switching */ | ||
131 | CLKCTRL = 0xB00FF014; /* Xin enable, Fsys driven by Xin, Fbus = Fsys, | ||
132 | MCPU=Fbus, SCPU=Fbus */ | ||
133 | |||
134 | asm volatile ( | ||
135 | "nop \n\t" | ||
136 | "nop \n\t" | ||
137 | ); | ||
138 | |||
139 | PLL0CFG |= (1<<31); /* power down */ | ||
140 | CLKDIVC = CLKDIVC &~ (0xff << 24); /* disable PLL0 divider */ | ||
141 | PLL0CFG = 0x80019808; /* set for 192Mhz (with power down) */ | ||
142 | PLL0CFG = PLL0CFG &~ (1<<31); /* power up */ | ||
143 | |||
144 | CLKCTRL = (CLKCTRL & ~0x1f) | 0x800FF010; | ||
145 | |||
146 | asm volatile ( | ||
147 | "nop \n\t" | ||
148 | "nop \n\t" | ||
149 | ); | ||
150 | } | ||
151 | else if (pll_number == 1) | ||
152 | { | ||
153 | PLL1CFG |= (1<<31); /* power down */ | ||
154 | CLKDIVC = CLKDIVC &~ (0xff << 16); /* disable PLL1 divider */ | ||
155 | PLL1CFG = 0x80002503; /* set for 216Mhz (with power down)*/ | ||
156 | PLL1CFG = PLL1CFG &~ (1<<31); /* power up */ | ||
157 | } | ||
158 | |||
159 | i = 0x1000; | ||
160 | while (--i) {}; | ||
161 | } | ||
162 | |||
163 | |||
164 | /* TODO - these should live in the target-specific directories and | ||
165 | once we understand what all the GPIO pins do, move the init to the | ||
166 | specific driver for that hardware. For now, we just perform the | ||
167 | same GPIO init as the original firmware - this makes it easier to | ||
168 | investigate what the GPIO pins do. | ||
169 | */ | ||
170 | |||
171 | #ifdef COWON_D2 | ||
172 | static void gpio_init(void) | ||
173 | { | ||
174 | /* Do what the original firmware does */ | ||
175 | GPIOA = 0x07000C83; | ||
176 | GPIOA_DIR = 0x0F010CE3; | ||
177 | GPIOB = 0; | ||
178 | GPIOB_DIR = 0x00080000; | ||
179 | GPIOC = 0x39000000; | ||
180 | GPIOC_DIR = 0xB9000000; | ||
181 | GPIOD = 0; | ||
182 | GPIOD_DIR = 0; | ||
183 | GPIOD = 0; | ||
184 | GPIOD_DIR = 0x00480000; | ||
185 | |||
186 | PORTCFG0 = 0x00034540; | ||
187 | PORTCFG1 = 0x0566A000; | ||
188 | PORTCFG2 = 0x000004C0; | ||
189 | PORTCFG3 = 0x0AA40455; | ||
190 | } | ||
191 | #endif | ||
192 | |||
193 | |||
194 | /* Second function called in the original firmware's startup code - we just | ||
195 | set up the clocks in the same way as the original firmware for now. */ | ||
196 | #ifdef COWON_D2 | ||
197 | static void clock_init(void) | ||
198 | { | ||
199 | int i; | ||
200 | |||
201 | CSCFG3 = (CSCFG3 &~ 0x3fff) | 0x841; | ||
202 | CLKCTRL = (CLKCTRL & ~0xff) | 0x14; | ||
203 | |||
204 | PCLK_RFREQ = 0x1401002d; /* RAM refresh source = Xin (4) / 0x2d = 266kHz */ | ||
205 | |||
206 | MCFG |= 1; | ||
207 | SDCFG = (SDCFG &~ 0x7000) | 0x2000; | ||
208 | |||
209 | MCFG1 |= 1; | ||
210 | SDCFG1 = (SDCFG &~ 0x7000) | 0x2000; | ||
211 | |||
212 | PLL0CFG |= 0x80000000; /* power down */ | ||
213 | PLL0CFG = 0x14010000; /* power up, source = Xin (4) undivided = 12Mhz */ | ||
214 | |||
215 | i = 0x8000; | ||
216 | while (--i) {}; | ||
217 | |||
218 | CLKCTRL = (CLKCTRL &~ 0x1f) | 0x800FF010; /* CPU and COP driven by PLL0 */ | ||
219 | |||
220 | asm volatile ( | ||
221 | "nop \n\t" | ||
222 | "nop \n\t" | ||
223 | ); | ||
224 | |||
225 | /* configure PCK_TCT to 2Mhz (clock source 4 (Xin) divided by 6) */ | ||
226 | PCLK_TCT = PCK_EN | (CKSEL_XIN<<24) | 5; | ||
227 | } | ||
228 | #endif | ||
229 | |||
230 | |||
231 | #ifdef COWON_D2 | ||
232 | void system_init(void) | ||
233 | { | ||
234 | MBCFG = 0x19; | ||
235 | |||
236 | if (TCC780_VER == 0) | ||
237 | ECFG0 = 0x309; | ||
238 | else | ||
239 | ECFG0 = 0x30d; | ||
240 | |||
241 | /* mask all interrupts */ | ||
242 | MIRQ = -1; | ||
243 | |||
244 | gpio_init(); | ||
245 | clock_init(); | ||
246 | |||
247 | /* TODO: these almost certainly shouldn't be here */ | ||
248 | set_pll_frequency(0, 192000000); /* drives CPU */ | ||
249 | set_pll_frequency(1, 216000000); /* drives LCD PXCLK - divided by 2 */ | ||
250 | } | ||
251 | #endif | ||
252 | |||
253 | |||
254 | void system_reboot(void) | ||
255 | { | ||
256 | #warning function not implemented | ||
257 | } | ||
258 | |||
259 | int system_memory_guard(int newmode) | ||
260 | { | ||
261 | #warning function not implemented | ||
262 | |||
263 | (void)newmode; | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
268 | |||
269 | void set_cpu_frequency(long frequency) | ||
270 | { | ||
271 | #warning function not implemented | ||
272 | (void)frequency; | ||
273 | } | ||
274 | |||
275 | #endif | ||