blob: 973dbaf719ac0c5784db4838dc199273b9182d7c [file] [log] [blame]
Rob Purchase47ea0302008-01-14 22:04:48 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 by Rob Purchase
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Rob Purchase47ea0302008-01-14 22:04:48 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "kernel.h"
23#include "system.h"
24#include "panic.h"
25
26#if !defined(BOOTLOADER)
27
28#define default_interrupt(name) \
29 extern __attribute__((weak,alias("UIRQ"))) void name (void)
30
31void irq_handler(void) __attribute__((interrupt ("IRQ"), naked));
32void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked));
33
34default_interrupt(EXT0);
35default_interrupt(EXT1);
36default_interrupt(EXT2);
37default_interrupt(EXT3);
Rob Purchase4dc2d8d2008-03-22 19:41:51 +000038default_interrupt(RTC);
39default_interrupt(GPSB0);
40default_interrupt(TIMER0);
41default_interrupt(TIMER1);
42default_interrupt(SCORE);
43default_interrupt(SPDTX);
44default_interrupt(VIDEO);
45default_interrupt(GSIO);
46default_interrupt(SCALER);
47default_interrupt(I2C);
Rob Purchase47ea0302008-01-14 22:04:48 +000048default_interrupt(DAI_RX);
49default_interrupt(DAI_TX);
Rob Purchase4dc2d8d2008-03-22 19:41:51 +000050default_interrupt(CDRX);
51default_interrupt(HPI);
52default_interrupt(UART0);
53default_interrupt(UART1);
54default_interrupt(G2D);
55default_interrupt(USB_DEVICE);
56default_interrupt(USB_HOST);
57default_interrupt(DMA);
58default_interrupt(HDD);
59default_interrupt(MSTICK);
60default_interrupt(NFC);
61default_interrupt(SDMMC);
62default_interrupt(CAM);
63default_interrupt(LCD);
64default_interrupt(ADC);
65default_interrupt(GPSB1);
66
67/* TODO: Establish IRQ priorities (0 = highest priority) */
68static const char irqpriority[] =
69{
70 0, /* EXT0 */
71 1, /* EXT1 */
72 2, /* EXT2 */
73 3, /* EXT3 */
74 4, /* RTC */
75 5, /* GPSB0 */
76 6, /* TIMER0 */
77 7, /* TIMER1 */
78 8, /* SCORE */
79 9, /* SPDTX */
80 10, /* VIDEO */
81 11, /* GSIO */
82 12, /* SCALER */
83 13, /* I2C */
84 14, /* DAI_RX */
85 15, /* DAI_TX */
86 16, /* CDRX */
87 17, /* HPI */
88 18, /* UART0 */
89 19, /* UART1 */
90 20, /* G2D */
91 21, /* USB_DEVICE */
92 22, /* USB_HOST */
93 23, /* DMA */
94 24, /* HDD */
95 25, /* MSTICK */
96 26, /* NFC */
97 27, /* SDMMC */
98 28, /* CAM */
99 29, /* LCD */
100 30, /* ADC */
101 31, /* GPSB */
102};
Rob Purchase47ea0302008-01-14 22:04:48 +0000103
104static void (* const irqvector[])(void) =
105{
Rob Purchase4dc2d8d2008-03-22 19:41:51 +0000106 EXT0,EXT1,EXT2,EXT3,RTC,GPSB0,TIMER0,TIMER1,
107 SCORE,SPDTX,VIDEO,GSIO,SCALER,I2C,DAI_RX,DAI_TX,
108 CDRX,HPI,UART0,UART1,G2D,USB_DEVICE,USB_HOST,DMA,
109 HDD,MSTICK,NFC,SDMMC,CAM,LCD,ADC,GPSB1
Rob Purchase47ea0302008-01-14 22:04:48 +0000110};
111
112static const char * const irqname[] =
113{
Rob Purchase4dc2d8d2008-03-22 19:41:51 +0000114 "EXT0","EXT1","EXT2","EXT3","RTC","GPSB0","TIMER0","TIMER1",
115 "SCORE","SPDTX","VIDEO","GSIO","SCALER","I2C","DAI_RX","DAI_TX",
116 "CDRX","HPI","UART0","UART1","G2D","USB_DEVICE","USB_HOST","DMA",
117 "HDD","MSTICK","NFC","SDMMC","CAM","LCD","ADC","GPSB1"
Rob Purchase47ea0302008-01-14 22:04:48 +0000118};
119
120static void UIRQ(void)
121{
122 unsigned int offset = VNIRQ;
123 panicf("Unhandled IRQ %02X: %s", offset, irqname[offset]);
124}
125
126void irq_handler(void)
127{
128 /*
129 * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c
130 */
131
132 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
133 "sub sp, sp, #8 \n"); /* Reserve stack */
Rob Purchase4dc2d8d2008-03-22 19:41:51 +0000134
135 int irq_no = VNIRQ; /* Read clears the corresponding IRQ status */
136
137 if ((irq_no & (1<<31)) == 0) /* Ensure invalid flag is not set */
138 {
139 irqvector[irq_no]();
140 }
141
Rob Purchase47ea0302008-01-14 22:04:48 +0000142 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
143 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
Rob Purchase4dc2d8d2008-03-22 19:41:51 +0000144 "subs pc, lr, #4 \n"); /* Return from IRQ */
Rob Purchase47ea0302008-01-14 22:04:48 +0000145}
146
Rob Purchase47ea0302008-01-14 22:04:48 +0000147#endif /* !defined(BOOTLOADER) */
148
149
Rob Purchase47ea0302008-01-14 22:04:48 +0000150/* TODO - these should live in the target-specific directories and
151 once we understand what all the GPIO pins do, move the init to the
152 specific driver for that hardware. For now, we just perform the
153 same GPIO init as the original firmware - this makes it easier to
154 investigate what the GPIO pins do.
155*/
156
157#ifdef COWON_D2
158static void gpio_init(void)
159{
160 /* Do what the original firmware does */
161 GPIOA = 0x07000C83;
162 GPIOA_DIR = 0x0F010CE3;
163 GPIOB = 0;
164 GPIOB_DIR = 0x00080000;
165 GPIOC = 0x39000000;
166 GPIOC_DIR = 0xB9000000;
167 GPIOD = 0;
168 GPIOD_DIR = 0;
169 GPIOD = 0;
170 GPIOD_DIR = 0x00480000;
171
172 PORTCFG0 = 0x00034540;
173 PORTCFG1 = 0x0566A000;
174 PORTCFG2 = 0x000004C0;
175 PORTCFG3 = 0x0AA40455;
176}
177#endif
178
179
180/* Second function called in the original firmware's startup code - we just
181 set up the clocks in the same way as the original firmware for now. */
182#ifdef COWON_D2
183static void clock_init(void)
184{
185 int i;
186
187 CSCFG3 = (CSCFG3 &~ 0x3fff) | 0x841;
Rob Purchase3d36f4e2008-03-29 20:40:38 +0000188
189 /* Enable Xin (12Mhz), Fsys = Xin, Fbus = Fsys/2, MCPU=Fsys, SCPU=Fsys */
190 CLKCTRL = 0x800FF014;
191
192 asm volatile (
193 "nop \n\t"
194 "nop \n\t"
195 );
Rob Purchase47ea0302008-01-14 22:04:48 +0000196
197 PCLK_RFREQ = 0x1401002d; /* RAM refresh source = Xin (4) / 0x2d = 266kHz */
198
199 MCFG |= 1;
200 SDCFG = (SDCFG &~ 0x7000) | 0x2000;
201
202 MCFG1 |= 1;
203 SDCFG1 = (SDCFG &~ 0x7000) | 0x2000;
204
Rob Purchase3d36f4e2008-03-29 20:40:38 +0000205 /* Configure PLL0 to 192Mhz, for CPU scaling */
206 PLL0CFG |= (1<<31); /* power down */
207 CLKDIVC = CLKDIVC &~ (0xff << 24); /* disable PLL0 divider */
208 PLL0CFG = 0x80019808; /* set for 192Mhz (with power down) */
209 PLL0CFG = PLL0CFG &~ (1<<31); /* power up */
210
211 /* Configure PLL1 to 216Mz, for LCD clock (when divided by 2) */
212 PLL1CFG |= (1<<31); /* power down */
213 CLKDIVC = CLKDIVC &~ (0xff << 16); /* disable PLL1 divider */
214 PLL1CFG = 0x80002503; /* set for 216Mhz (with power down)*/
215 PLL1CFG = PLL1CFG &~ (1<<31); /* power up */
Rob Purchase47ea0302008-01-14 22:04:48 +0000216
217 i = 0x8000;
218 while (--i) {};
Rob Purchase3d36f4e2008-03-29 20:40:38 +0000219
220#ifdef HAVE_ADJUSTABLE_CPU_FREQ
221 set_cpu_frequency(CPUFREQ_NORMAL);
222#else
223 /* 48Mhz: Fsys = PLL0 (192Mhz) Fbus = Fsys/4 CPU = Fbus, COP = Fbus */
224 CLKCTRL = (1<<31) | (3<<28) | (3<<4);
225#endif
Rob Purchase47ea0302008-01-14 22:04:48 +0000226
227 asm volatile (
228 "nop \n\t"
229 "nop \n\t"
230 );
231
232 /* configure PCK_TCT to 2Mhz (clock source 4 (Xin) divided by 6) */
233 PCLK_TCT = PCK_EN | (CKSEL_XIN<<24) | 5;
234}
235#endif
236
237
238#ifdef COWON_D2
239void system_init(void)
240{
241 MBCFG = 0x19;
242
243 if (TCC780_VER == 0)
244 ECFG0 = 0x309;
245 else
246 ECFG0 = 0x30d;
Rob Purchase4dc2d8d2008-03-22 19:41:51 +0000247
Rob Purchase47ea0302008-01-14 22:04:48 +0000248 /* mask all interrupts */
Rob Purchase4dc2d8d2008-03-22 19:41:51 +0000249 IEN = 0;
250
251#if !defined(BOOTLOADER)
252
Rob Purchasefd773cb2008-04-21 20:16:18 +0000253 /* Set DAI interrupts as FIQ, all others are IRQ. */
254 IRQSEL = ~(DAI_RX_IRQ_MASK | DAI_TX_IRQ_MASK);
Rob Purchase4dc2d8d2008-03-22 19:41:51 +0000255
256 POL = 0x200108; /* IRQs 3,8,21 active low (as OF) */
257 MODE = 0x20ce07c0; /* IRQs 6-10,17-19,22-23,29 level-triggered (as OF) */
258
259 VCTRL |= (1<<31); /* Reading from VNIRQ clears that interrupt */
260
261 /* Write IRQ priority registers using ints - a freeze occurs otherwise */
Rob Purchase3d36f4e2008-03-29 20:40:38 +0000262 int i;
Rob Purchase4dc2d8d2008-03-22 19:41:51 +0000263 for (i = 0; i < 7; i++)
264 {
265 IRQ_PRIORITY_TABLE[i] = ((int*)irqpriority)[i];
266 }
267
268 ALLMASK = 3; /* Global FIQ/IRQ unmask */
269
270#endif /* !defined(BOOTLOADER) */
Rob Purchase47ea0302008-01-14 22:04:48 +0000271
272 gpio_init();
273 clock_init();
Rob Purchase47ea0302008-01-14 22:04:48 +0000274}
275#endif
276
277
278void system_reboot(void)
279{
Rob Purchase3f7f5d72008-05-31 11:30:24 +0000280 disable_interrupt(IRQ_FIQ_DISABLED);
281
282#ifdef HAVE_ADJUSTABLE_CPU_FREQ
283 set_cpu_frequency(CPUFREQ_DEFAULT);
284#endif
285
286 /* TODO: implement reboot (eg. jump to boot ROM?) */
287 while (1);
Rob Purchase47ea0302008-01-14 22:04:48 +0000288}
289
290int system_memory_guard(int newmode)
291{
Rob Purchase47ea0302008-01-14 22:04:48 +0000292 (void)newmode;
293 return 0;
294}
295
296#ifdef HAVE_ADJUSTABLE_CPU_FREQ
297
298void set_cpu_frequency(long frequency)
299{
Rob Purchase6fd72c72008-03-31 22:43:20 +0000300 if (cpu_frequency == frequency)
301 return;
302
Rob Purchase3d36f4e2008-03-29 20:40:38 +0000303 /* CPU/COP frequencies can be scaled between Fbus (min) and Fsys (max).
304 Fbus should not be set below ~32Mhz with LCD enabled or the display
305 will be garbled. */
306 if (frequency == CPUFREQ_MAX)
307 {
308 /* 192Mhz:
309 Fsys = PLL0 (192Mhz)
310 Fbus = Fsys/2
311 CPU = Fsys, COP = Fsys */
312 CLKCTRL = (1<<31) | (0xFF<<12) | (1<<4);
313 }
314 else if (frequency == CPUFREQ_NORMAL)
315 {
316 /* 48Mhz:
317 Fsys = PLL0 (192Mhz)
318 Fbus = Fsys/4
319 CPU = Fbus, COP = Fbus */
320 CLKCTRL = (1<<31) | (3<<28) | (3<<4);
321 }
322 else
323 {
324 /* 32Mhz:
325 Fsys = PLL0 (192Mhz)
326 Fbus = Fsys/6
327 CPU = Fbus, COP = Fbus */
328 CLKCTRL = (1<<31) | (3<<28) | (5<<4);
329 }
330
331 asm volatile (
332 "nop \n\t"
333 "nop \n\t"
Rob Purchase6fd72c72008-03-31 22:43:20 +0000334 "nop \n\t"
Rob Purchase3d36f4e2008-03-29 20:40:38 +0000335 );
336
337 cpu_frequency = frequency;
Rob Purchase47ea0302008-01-14 22:04:48 +0000338}
339
340#endif