1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 by Karl Kurbjun
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 ****************************************************************************/
26 #include "uart-target.h"
27 #include "system-arm.h"
30 #include "dma-target.h"
32 #include "usb-mr500.h"
35 #define default_interrupt(name) \
36 extern __attribute__((weak,alias("UIRQ"))) void name (void)
38 void irq_handler(void) __attribute__((interrupt ("IRQ"), naked
, section(".icode")));
39 void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked
, section(".icode")));
41 default_interrupt(TIMER0
);
42 default_interrupt(TIMER1
);
43 default_interrupt(TIMER2
);
44 default_interrupt(TIMER3
);
45 default_interrupt(CCD_VD0
);
46 default_interrupt(CCD_VD1
);
47 default_interrupt(CCD_WEN
);
48 default_interrupt(VENC
);
49 default_interrupt(SERIAL0
);
50 default_interrupt(SERIAL1
);
51 default_interrupt(EXT_HOST
);
52 default_interrupt(DSPHINT
);
53 default_interrupt(UART0
);
54 default_interrupt(UART1
);
55 default_interrupt(USB_DMA
);
56 default_interrupt(USB_CORE
);
57 default_interrupt(VLYNQ
);
58 default_interrupt(MTC0
);
59 default_interrupt(MTC1
);
60 default_interrupt(SD_MMC
);
61 default_interrupt(SDIO_MS
);
62 default_interrupt(GIO0
);
63 default_interrupt(GIO1
);
64 default_interrupt(GIO2
);
65 default_interrupt(GIO3
);
66 default_interrupt(GIO4
);
67 default_interrupt(GIO5
);
68 default_interrupt(GIO6
);
69 default_interrupt(GIO7
);
70 default_interrupt(GIO8
);
71 default_interrupt(GIO9
);
72 default_interrupt(GIO10
);
73 default_interrupt(GIO11
);
74 default_interrupt(GIO12
);
75 default_interrupt(GIO13
);
76 default_interrupt(GIO14
);
77 default_interrupt(GIO15
);
78 default_interrupt(PREVIEW0
);
79 default_interrupt(PREVIEW1
);
80 default_interrupt(WATCHDOG
);
81 default_interrupt(I2C
);
82 default_interrupt(CLKC
);
83 default_interrupt(ICE
);
84 default_interrupt(ARMCOM_RX
);
85 default_interrupt(ARMCOM_TX
);
86 default_interrupt(RESERVED
);
88 /* The entry address is equal to base address plus an offset.
89 * The offset is based on the priority of the interrupt. So if
90 * the priority of an interrupt is changed, the user should also
91 * change the offset for the interrupt in the entry table.
94 static const unsigned short const irqpriority
[] =
96 IRQ_TIMER0
,IRQ_TIMER1
,IRQ_TIMER2
,IRQ_TIMER3
,IRQ_CCD_VD0
,IRQ_CCD_VD1
,
97 IRQ_CCD_WEN
,IRQ_VENC
,IRQ_SERIAL0
,IRQ_SERIAL1
,IRQ_EXT_HOST
,IRQ_DSPHINT
,
98 IRQ_UART0
,IRQ_UART1
,IRQ_USB_DMA
,IRQ_USB_CORE
,IRQ_VLYNQ
,IRQ_MTC0
,IRQ_MTC1
,
99 IRQ_SD_MMC
,IRQ_SDIO_MS
,IRQ_GIO0
,IRQ_GIO1
,IRQ_GIO2
,IRQ_GIO3
,IRQ_GIO4
,IRQ_GIO5
,
100 IRQ_GIO6
,IRQ_GIO7
,IRQ_GIO8
,IRQ_GIO9
,IRQ_GIO10
,IRQ_GIO11
,IRQ_GIO12
,IRQ_GIO13
,
101 IRQ_GIO14
,IRQ_GIO15
,IRQ_PREVIEW0
,IRQ_PREVIEW1
,IRQ_WATCHDOG
,IRQ_I2C
,IRQ_CLKC
,
102 IRQ_ICE
,IRQ_ARMCOM_RX
,IRQ_ARMCOM_TX
,IRQ_RESERVED
103 }; /* IRQ priorities, ranging from highest to lowest */
105 static void (* const irqvector
[])(void) __attribute__ ((section(".idata"))) =
107 TIMER0
,TIMER1
,TIMER2
,TIMER3
,CCD_VD0
,CCD_VD1
,
108 CCD_WEN
,VENC
,SERIAL0
,SERIAL1
,EXT_HOST
,DSPHINT
,
109 UART0
,UART1
,USB_DMA
,USB_CORE
,VLYNQ
,MTC0
,MTC1
,
110 SD_MMC
,SDIO_MS
,GIO0
,GIO1
,GIO2
,GIO3
,GIO4
,GIO5
,
111 GIO6
,GIO7
,GIO8
,GIO9
,GIO10
,GIO11
,GIO12
,GIO13
,
112 GIO14
,GIO15
,PREVIEW0
,PREVIEW1
,WATCHDOG
,I2C
,CLKC
,
113 ICE
,ARMCOM_RX
,ARMCOM_TX
,RESERVED
116 static const char * const irqname
[] =
118 "TIMER0","TIMER1","TIMER2","TIMER3","CCD_VD0","CCD_VD1",
119 "CCD_WEN","VENC","SERIAL0","SERIAL1","EXT_HOST","DSPHINT",
120 "UART0","UART1","USB_DMA","USB_CORE","VLYNQ","MTC0","MTC1",
121 "SD_MMC","SDIO_MS","GIO0","GIO1","GIO2","GIO3","GIO4","GIO5",
122 "GIO6","GIO7","GIO8","GIO9","GIO10","GIO11","GIO12","GIO13",
123 "GIO14","GIO15","PREVIEW0","PREVIEW1","WATCHDOG","I2C","CLKC",
124 "ICE","ARMCOM_RX","ARMCOM_TX","RESERVED"
127 static void UIRQ(void)
129 unsigned int offset
= (IO_INTC_IRQENTRY0
>>2)-1;
130 panicf("Unhandled IRQ %02X: %s", offset
, irqname
[offset
]);
133 void irq_handler(void)
136 * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c
139 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
140 "sub sp, sp, #8 \n"); /* Reserve stack */
141 unsigned short addr
= IO_INTC_IRQENTRY0
>>2;
147 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
148 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
149 "subs pc, lr, #4 \n"); /* Return from IRQ */
152 void fiq_handler(void)
155 * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c
158 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
159 "sub sp, sp, #8 \n"); /* Reserve stack */
160 unsigned short addr
= IO_INTC_FIQENTRY0
>>2;
166 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
167 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
168 "subs pc, lr, #4 \n"); /* Return from FIQ */
171 void system_reboot(void)
173 /* Code taken from linux/include/asm-arm/arch-itdm320-20/system.h at NeuroSVN */
174 __asm__
__volatile__(
176 "mcr p15, 0, ip, c7, c7, 0 @ invalidate cache \n"
177 "mcr p15, 0, ip, c7, c10,4 @ drain WB \n"
178 "mcr p15, 0, ip, c8, c7, 0 @ flush TLB (v4) \n"
179 "mrc p15, 0, ip, c1, c0, 0 @ get ctrl register\n"
180 "bic ip, ip, #0x000f @ ............wcam \n"
181 "bic ip, ip, #0x2100 @ ..v....s........ \n"
182 "mcr p15, 0, ip, c1, c0, 0 @ ctrl register \n"
183 "mov ip, #0xFF000000 \n"
184 "orr pc, ip, #0xFF0000 @ ip = 0xFFFF0000 \n"
191 void system_exception_wait(void)
193 /* Mask all Interrupts. */
197 while ((IO_GIO_BITSET0
&0x01) != 0); /* Wait for power button */
200 void system_init(void)
202 /* Pin 33 is connected to a buzzer, for an annoying sound set
206 * Since this is not used in the FW, set it to a normal output at a zero
208 /* 33: output, non-inverted, no-irq, falling edge, no-chat, normal */
209 dm320_set_io(33, false, false, false, false, false, 0x00);
210 IO_GIO_BITCLR2
= 1<<1;
212 /* Pin 1 is the power button. Right now it is setup without IRQ, but that
213 * may be needed for wakeup if a different shutdown method is used. */
214 /* 1: input , non-inverted, no-irq, falling edge, no-chat, normal */
215 dm320_set_io(1, true, false, false, false, false, 0x00);
217 /* taken from linux/arch/arm/mach-itdm320-20/irq.c */
219 /* Clearing all FIQs and IRQs. */
220 IO_INTC_IRQ0
= 0xFFFF;
221 IO_INTC_IRQ1
= 0xFFFF;
222 IO_INTC_IRQ2
= 0xFFFF;
224 IO_INTC_FIQ0
= 0xFFFF;
225 IO_INTC_FIQ1
= 0xFFFF;
226 IO_INTC_FIQ2
= 0xFFFF;
228 /* Masking all Interrupts. */
233 /* Setting INTC to all IRQs. */
238 /* setup the clocks */
241 /* SDRAM Divide by 3 */
247 /* 27 MHz input clock:
257 /* need to wait before bypassing */
261 /* turn off some unneeded modules */
262 IO_CLK_MOD0
&= ~0x0018;
263 IO_CLK_MOD1
= 0x0918;
264 IO_CLK_MOD2
= ~0x7C58;
266 /* IRQENTRY only reflects enabled interrupts */
269 IO_INTC_ENTRY_TBA0
= 0;
270 IO_INTC_ENTRY_TBA1
= 0;
273 /* Set interrupt priorities to predefined values */
274 for(i
= 0; i
< 23; i
++)
275 DM320_REG(0x0540+i
*2) = ((irqpriority
[i
*2+1] & 0x3F) << 8) | (irqpriority
[i
*2] & 0x3F); /* IO_INTC_PRIORITYx */
277 /* Turn off all timers */
278 IO_TIMER0_TMMD
= CONFIG_TIMER0_TMMD_STOP
;
279 IO_TIMER1_TMMD
= CONFIG_TIMER1_TMMD_STOP
;
280 IO_TIMER2_TMMD
= CONFIG_TIMER2_TMMD_STOP
;
281 IO_TIMER3_TMMD
= CONFIG_TIMER3_TMMD_STOP
;
284 /* set GIO26 (reset pin) to output and low */
285 IO_GIO_BITCLR1
=(1<<10);
286 IO_GIO_DIR1
&=~(1<<10);
296 #if !defined(LCD_NATIVE_WIDTH) && !defined(LCD_NATIVE_HEIGHT)
297 #define LCD_NATIVE_WIDTH LCD_WIDTH
298 #define LCD_NATIVE_HEIGHT LCD_HEIGHT
301 #define LCD_FUDGE LCD_NATIVE_WIDTH%32
302 #define LCD_BUFFER_SIZE ((LCD_NATIVE_WIDTH+LCD_FUDGE)*LCD_NATIVE_HEIGHT*2)
303 #define LCD_TTB_AREA ((LCD_BUFFER_SIZE>>19)+1)
305 /* MMU initialization (Starts data and instruction cache) */
307 /* Make sure everything is mapped on itself */
308 map_section(0, 0, 0x1000, CACHE_NONE
);
310 /* Enable caching for RAM */
311 map_section(CONFIG_SDRAM_START
, CONFIG_SDRAM_START
, MEM
, CACHE_ALL
);
312 /* enable buffered writing for the framebuffer */
313 map_section((int)FRAME
, (int)FRAME
, LCD_TTB_AREA
, BUFFERED
);
316 map_section(0x00100000, 0x00100000, 4, CACHE_NONE
);
317 map_section(0x04700000, 0x04700000, 2, BUFFERED
);
318 map_section(0x40000000, 0x40000000, 16, CACHE_NONE
);
319 map_section(0x50000000, 0x50000000, 16, CACHE_NONE
);
320 map_section(0x60000000, 0x60000000, 16, CACHE_NONE
);
321 map_section(0x80000000, 0x80000000, 1, CACHE_NONE
);
326 int system_memory_guard(int newmode
)
332 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
333 void set_cpu_frequency(long frequency
)
335 if (frequency
== CPUFREQ_MAX
) {
336 IO_CLK_DIV0
= 0x0101; /* 175 MHz ARM */
338 IO_CLK_DIV0
= 0x0003; /* 87.5 MHz ARM - not much savings, about 3 mA */
343 /* This function is pretty crude. It is not acurate to a usec, but errors on
346 void udelay(int usec
) {
347 volatile int temp
=usec
*(175000/200);
354 /* This function sets the specified pin up */
355 void dm320_set_io (char pin_num
, bool input
, bool invert
, bool irq
, bool irqany
,
356 bool chat
, char func_num
)
359 char reg_offset
; /* Holds the offset to the register */
360 char shift_val
; /* Holds the shift offset to the GPIO bit(s) */
361 short io_val
; /* Used as an intermediary to prevent glitchy
364 /* Make sure this is a valid pin number */
365 if( (unsigned) pin_num
> 40 )
368 /* Clamp the function number */
371 /* Note that these are integer calculations */
372 reg_offset
= (pin_num
/ 16);
373 shift_val
= (pin_num
- (16 * reg_offset
));
375 /* Handle the direction */
376 /* Calculate the pointer to the direction register */
377 pio
= &IO_GIO_DIR0
+ reg_offset
;
380 *pio
|= ( 1 << shift_val
);
382 *pio
&= ~( 1 << shift_val
);
384 /* Handle the inversion */
385 /* Calculate the pointer to the inversion register */
386 pio
= &IO_GIO_INV0
+ reg_offset
;
389 *pio
|= ( 1 << shift_val
);
391 *pio
&= ~( 1 << shift_val
);
393 /* Handle the chat */
394 /* Calculate the pointer to the chat register */
395 pio
= &IO_GIO_CHAT0
+ reg_offset
;
398 *pio
|= ( 1 << shift_val
);
400 *pio
&= ~( 1 << shift_val
);
402 /* Handle interrupt configuration */
405 /* Sets whether the pin is an irq or not */
407 IO_GIO_IRQPORT
|= (1 << pin_num
);
409 IO_GIO_IRQPORT
&= ~(1 << pin_num
);
411 /* Set whether this is a falling or any edge sensitive irq */
413 IO_GIO_IRQEDGE
|= (1 << pin_num
);
415 IO_GIO_IRQEDGE
&= ~(1 << pin_num
);
418 /* Handle the function number */
419 /* Calculate the pointer to the function register */
420 reg_offset
= ( (pin_num
- 9) / 8 );
421 shift_val
= ( ((pin_num
- 9) - (8 * reg_offset
)) * 2 );
429 /* Calculate the pointer to the function register */
430 pio
= &IO_GIO_FSEL0
+ reg_offset
;
433 io_val
&= ~( 3 << shift_val
); /* zero previous value */
434 io_val
|= ( func_num
<< shift_val
); /* Store new value */