1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by Rob Purchase
12 * 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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
27 #define default_interrupt(name) \
28 extern __attribute__((weak,alias("UIRQ"))) void name (void)
30 void irq_handler(void) __attribute__((interrupt ("IRQ"), naked
));
31 void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked
));
33 default_interrupt(EXT0
);
34 default_interrupt(EXT1
);
35 default_interrupt(EXT2
);
36 default_interrupt(EXT3
);
37 default_interrupt(RTC
);
38 default_interrupt(GPSB0
);
39 default_interrupt(TIMER0
);
40 default_interrupt(TIMER1
);
41 default_interrupt(SCORE
);
42 default_interrupt(SPDTX
);
43 default_interrupt(VIDEO
);
44 default_interrupt(GSIO
);
45 default_interrupt(SCALER
);
46 default_interrupt(I2C
);
47 default_interrupt(DAI_RX
);
48 default_interrupt(DAI_TX
);
49 default_interrupt(CDRX
);
50 default_interrupt(HPI
);
51 default_interrupt(UART0
);
52 default_interrupt(UART1
);
53 default_interrupt(G2D
);
54 default_interrupt(USB_DEVICE
);
55 default_interrupt(USB_HOST
);
56 default_interrupt(DMA
);
57 default_interrupt(HDD
);
58 default_interrupt(MSTICK
);
59 default_interrupt(NFC
);
60 default_interrupt(SDMMC
);
61 default_interrupt(CAM
);
62 default_interrupt(LCD
);
63 default_interrupt(ADC
);
64 default_interrupt(GPSB1
);
66 /* TODO: Establish IRQ priorities (0 = highest priority) */
67 static const char irqpriority
[] =
103 static void (* const irqvector
[])(void) =
105 EXT0
,EXT1
,EXT2
,EXT3
,RTC
,GPSB0
,TIMER0
,TIMER1
,
106 SCORE
,SPDTX
,VIDEO
,GSIO
,SCALER
,I2C
,DAI_RX
,DAI_TX
,
107 CDRX
,HPI
,UART0
,UART1
,G2D
,USB_DEVICE
,USB_HOST
,DMA
,
108 HDD
,MSTICK
,NFC
,SDMMC
,CAM
,LCD
,ADC
,GPSB1
111 static const char * const irqname
[] =
113 "EXT0","EXT1","EXT2","EXT3","RTC","GPSB0","TIMER0","TIMER1",
114 "SCORE","SPDTX","VIDEO","GSIO","SCALER","I2C","DAI_RX","DAI_TX",
115 "CDRX","HPI","UART0","UART1","G2D","USB_DEVICE","USB_HOST","DMA",
116 "HDD","MSTICK","NFC","SDMMC","CAM","LCD","ADC","GPSB1"
119 static void UIRQ(void)
121 unsigned int offset
= VNIRQ
;
122 panicf("Unhandled IRQ %02X: %s", offset
, irqname
[offset
]);
125 void irq_handler(void)
128 * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c
131 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
132 "sub sp, sp, #8 \n"); /* Reserve stack */
134 int irq_no
= VNIRQ
; /* Read clears the corresponding IRQ status */
136 if ((irq_no
& (1<<31)) == 0) /* Ensure invalid flag is not set */
141 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
142 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
143 "subs pc, lr, #4 \n"); /* Return from IRQ */
147 /* TODO - these should live in the target-specific directories and
148 once we understand what all the GPIO pins do, move the init to the
149 specific driver for that hardware. For now, we just perform the
150 same GPIO init as the original firmware - this makes it easier to
151 investigate what the GPIO pins do.
155 static void gpio_init(void)
157 /* Do what the original firmware does */
159 GPIOA_DIR
= 0x0F010CE3;
161 GPIOB_DIR
= 0x00080000;
163 GPIOC_DIR
= 0xB9000000;
167 GPIOD_DIR
= 0x00480000;
169 PORTCFG0
= 0x00034540;
170 PORTCFG1
= 0x0566A000;
171 PORTCFG2
= 0x000004C0;
172 PORTCFG3
= 0x0AA40455;
177 /* Second function called in the original firmware's startup code - we just
178 set up the clocks in the same way as the original firmware for now. */
180 static void clock_init(void)
184 CSCFG3
= (CSCFG3
&~ 0x3fff) | 0x841;
186 /* Enable Xin (12Mhz), Fsys = Xin, Fbus = Fsys/2, MCPU=Fsys, SCPU=Fsys */
187 CLKCTRL
= 0x800FF014;
194 PCLK_RFREQ
= 0x1401002d; /* RAM refresh source = Xin (4) / 0x2d = 266kHz */
197 SDCFG
= (SDCFG
&~ 0x7000) | 0x2000;
200 SDCFG1
= (SDCFG
&~ 0x7000) | 0x2000;
202 /* Configure PLL0 to 192Mhz, for CPU scaling */
203 PLL0CFG
|= (1<<31); /* power down */
204 CLKDIVC
= CLKDIVC
&~ (0xff << 24); /* disable PLL0 divider */
205 PLL0CFG
= 0x80019808; /* set for 192Mhz (with power down) */
206 PLL0CFG
= PLL0CFG
&~ (1<<31); /* power up */
208 /* Configure PLL1 to 216Mz, for LCD clock (when divided by 2) */
209 PLL1CFG
|= (1<<31); /* power down */
210 CLKDIVC
= CLKDIVC
&~ (0xff << 16); /* disable PLL1 divider */
211 PLL1CFG
= 0x80002503; /* set for 216Mhz (with power down)*/
212 PLL1CFG
= PLL1CFG
&~ (1<<31); /* power up */
217 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
218 set_cpu_frequency(CPUFREQ_NORMAL
);
220 /* 48Mhz: Fsys = PLL0 (192Mhz) Fbus = Fsys/4 CPU = Fbus, COP = Fbus */
221 CLKCTRL
= (1<<31) | (3<<28) | (3<<4);
229 /* Configure PCK_TCT to 2Mhz (Xin divided by 6) */
230 PCLK_TCT
= PCK_EN
| (CKSEL_XIN
<<24) | 5;
232 /* Set TC32 timer to be our USEC_TIMER (Xin divided by 12 = 1MHz) */
233 TC32EN
= (1<<24) | 11;
235 /* Unmask common timer IRQ (shared by tick and user timer) */
236 IEN
|= TIMER0_IRQ_MASK
;
242 void system_init(void)
251 /* mask all interrupts */
254 /* Set DAI interrupts as FIQ, all others are IRQ. */
255 IRQSEL
= ~(DAI_RX_IRQ_MASK
| DAI_TX_IRQ_MASK
);
257 POL
= 0x200108; /* IRQs 3,8,21 active low (as OF) */
258 TMODE
= 0x20ce07c0; /* IRQs 6-10,17-19,22-23,29 level-triggered (as OF) */
260 VCTRL
|= (1<<31); /* Reading from VNIRQ clears that interrupt */
262 /* Write IRQ priority registers using ints - a freeze occurs otherwise */
264 for (i
= 0; i
< 7; i
++)
266 IRQ_PRIORITY_TABLE
[i
] = ((int*)irqpriority
)[i
];
269 ALLMASK
= 3; /* Global FIQ/IRQ unmask */
277 void system_reboot(void)
279 disable_interrupt(IRQ_FIQ_DISABLED
);
281 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
282 set_cpu_frequency(CPUFREQ_DEFAULT
);
285 /* TODO: implement reboot (eg. jump to boot ROM?) */
289 void system_exception_wait(void)
292 while ((GPIOA
& 0x4) != 0); /* check for power button */
294 #error "system_exception_wait not implemented for this target"
298 int system_memory_guard(int newmode
)
304 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
306 void set_cpu_frequency(long frequency
)
308 if (cpu_frequency
== frequency
)
311 /* CPU/COP frequencies can be scaled between Fbus (min) and Fsys (max).
312 Fbus should not be set below ~32Mhz with LCD enabled or the display
314 if (frequency
== CPUFREQ_MAX
)
319 CPU = Fsys, COP = Fsys */
320 CLKCTRL
= (1<<31) | (0xFF<<12) | (1<<4);
322 else if (frequency
== CPUFREQ_NORMAL
)
327 CPU = Fbus, COP = Fbus */
328 CLKCTRL
= (1<<31) | (3<<28) | (3<<4);
335 CPU = Fbus, COP = Fbus */
336 CLKCTRL
= (1<<31) | (3<<28) | (5<<4);
345 cpu_frequency
= frequency
;