Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2007 by Rob Purchase |
| 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 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. |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 16 | * |
| 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 | |
| 31 | void irq_handler(void) __attribute__((interrupt ("IRQ"), naked)); |
| 32 | void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked)); |
| 33 | |
| 34 | default_interrupt(EXT0); |
| 35 | default_interrupt(EXT1); |
| 36 | default_interrupt(EXT2); |
| 37 | default_interrupt(EXT3); |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 38 | default_interrupt(RTC); |
| 39 | default_interrupt(GPSB0); |
| 40 | default_interrupt(TIMER0); |
| 41 | default_interrupt(TIMER1); |
| 42 | default_interrupt(SCORE); |
| 43 | default_interrupt(SPDTX); |
| 44 | default_interrupt(VIDEO); |
| 45 | default_interrupt(GSIO); |
| 46 | default_interrupt(SCALER); |
| 47 | default_interrupt(I2C); |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 48 | default_interrupt(DAI_RX); |
| 49 | default_interrupt(DAI_TX); |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 50 | default_interrupt(CDRX); |
| 51 | default_interrupt(HPI); |
| 52 | default_interrupt(UART0); |
| 53 | default_interrupt(UART1); |
| 54 | default_interrupt(G2D); |
| 55 | default_interrupt(USB_DEVICE); |
| 56 | default_interrupt(USB_HOST); |
| 57 | default_interrupt(DMA); |
| 58 | default_interrupt(HDD); |
| 59 | default_interrupt(MSTICK); |
| 60 | default_interrupt(NFC); |
| 61 | default_interrupt(SDMMC); |
| 62 | default_interrupt(CAM); |
| 63 | default_interrupt(LCD); |
| 64 | default_interrupt(ADC); |
| 65 | default_interrupt(GPSB1); |
| 66 | |
| 67 | /* TODO: Establish IRQ priorities (0 = highest priority) */ |
| 68 | static 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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 103 | |
| 104 | static void (* const irqvector[])(void) = |
| 105 | { |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 106 | 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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 110 | }; |
| 111 | |
| 112 | static const char * const irqname[] = |
| 113 | { |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 114 | "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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 118 | }; |
| 119 | |
| 120 | static void UIRQ(void) |
| 121 | { |
| 122 | unsigned int offset = VNIRQ; |
| 123 | panicf("Unhandled IRQ %02X: %s", offset, irqname[offset]); |
| 124 | } |
| 125 | |
| 126 | void 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 Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 134 | |
| 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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 142 | asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */ |
| 143 | "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 144 | "subs pc, lr, #4 \n"); /* Return from IRQ */ |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 145 | } |
| 146 | |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 147 | #endif /* !defined(BOOTLOADER) */ |
| 148 | |
| 149 | |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 150 | /* 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 |
| 158 | static 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 |
| 183 | static void clock_init(void) |
| 184 | { |
| 185 | int i; |
| 186 | |
| 187 | CSCFG3 = (CSCFG3 &~ 0x3fff) | 0x841; |
Rob Purchase | 3d36f4e | 2008-03-29 20:40:38 +0000 | [diff] [blame] | 188 | |
| 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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 196 | |
| 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 Purchase | 3d36f4e | 2008-03-29 20:40:38 +0000 | [diff] [blame] | 205 | /* 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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 216 | |
| 217 | i = 0x8000; |
| 218 | while (--i) {}; |
Rob Purchase | 3d36f4e | 2008-03-29 20:40:38 +0000 | [diff] [blame] | 219 | |
| 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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 226 | |
| 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 |
| 239 | void system_init(void) |
| 240 | { |
| 241 | MBCFG = 0x19; |
| 242 | |
| 243 | if (TCC780_VER == 0) |
| 244 | ECFG0 = 0x309; |
| 245 | else |
| 246 | ECFG0 = 0x30d; |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 247 | |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 248 | /* mask all interrupts */ |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 249 | IEN = 0; |
| 250 | |
| 251 | #if !defined(BOOTLOADER) |
| 252 | |
Rob Purchase | fd773cb | 2008-04-21 20:16:18 +0000 | [diff] [blame] | 253 | /* Set DAI interrupts as FIQ, all others are IRQ. */ |
| 254 | IRQSEL = ~(DAI_RX_IRQ_MASK | DAI_TX_IRQ_MASK); |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 255 | |
| 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 Purchase | 3d36f4e | 2008-03-29 20:40:38 +0000 | [diff] [blame] | 262 | int i; |
Rob Purchase | 4dc2d8d | 2008-03-22 19:41:51 +0000 | [diff] [blame] | 263 | 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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 271 | |
| 272 | gpio_init(); |
| 273 | clock_init(); |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 274 | } |
| 275 | #endif |
| 276 | |
| 277 | |
| 278 | void system_reboot(void) |
| 279 | { |
Rob Purchase | 3f7f5d7 | 2008-05-31 11:30:24 +0000 | [diff] [blame] | 280 | 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 Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 288 | } |
| 289 | |
| 290 | int system_memory_guard(int newmode) |
| 291 | { |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 292 | (void)newmode; |
| 293 | return 0; |
| 294 | } |
| 295 | |
| 296 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
| 297 | |
| 298 | void set_cpu_frequency(long frequency) |
| 299 | { |
Rob Purchase | 6fd72c7 | 2008-03-31 22:43:20 +0000 | [diff] [blame] | 300 | if (cpu_frequency == frequency) |
| 301 | return; |
| 302 | |
Rob Purchase | 3d36f4e | 2008-03-29 20:40:38 +0000 | [diff] [blame] | 303 | /* 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 Purchase | 6fd72c7 | 2008-03-31 22:43:20 +0000 | [diff] [blame] | 334 | "nop \n\t" |
Rob Purchase | 3d36f4e | 2008-03-29 20:40:38 +0000 | [diff] [blame] | 335 | ); |
| 336 | |
| 337 | cpu_frequency = frequency; |
Rob Purchase | 47ea030 | 2008-01-14 22:04:48 +0000 | [diff] [blame] | 338 | } |
| 339 | |
| 340 | #endif |