as3525*: disable_irq in system_reboot()
[maemo-rb.git] / firmware / target / arm / as3525 / system-as3525.c
blobf822819f4c1437f534d38454c75380f953bac44a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 by Rob Purchase
11 * Copyright © 2008 Rafaël Carré
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #include "config.h"
24 #include "kernel.h"
25 #include "system.h"
26 #include "panic.h"
27 #include "ascodec-target.h"
28 #include "adc.h"
29 #include "dma-target.h"
30 #include "clock-target.h"
31 #include "fmradio_i2c.h"
32 #include "button-target.h"
33 #include "backlight-target.h"
35 #define default_interrupt(name) \
36 extern __attribute__((weak,alias("UIRQ"))) void name (void)
38 static void UIRQ (void) __attribute__((interrupt ("IRQ")));
39 void irq_handler(void) __attribute__((interrupt ("IRQ")));
40 void fiq_handler(void) __attribute__((interrupt ("FIQ")));
42 default_interrupt(INT_WATCHDOG);
43 default_interrupt(INT_TIMER1);
44 default_interrupt(INT_TIMER2);
45 default_interrupt(INT_USB);
46 default_interrupt(INT_DMAC);
47 default_interrupt(INT_NAND);
48 default_interrupt(INT_IDE);
49 default_interrupt(INT_MCI0);
50 default_interrupt(INT_MCI1);
51 default_interrupt(INT_AUDIO);
52 default_interrupt(INT_SSP);
53 default_interrupt(INT_I2C_MS);
54 default_interrupt(INT_I2C_AUDIO);
55 default_interrupt(INT_I2SIN);
56 default_interrupt(INT_I2SOUT);
57 default_interrupt(INT_UART);
58 default_interrupt(INT_GPIOD);
59 default_interrupt(RESERVED1); /* Interrupt 17 : unused */
60 default_interrupt(INT_CGU);
61 default_interrupt(INT_MEMORY_STICK);
62 default_interrupt(INT_DBOP);
63 default_interrupt(RESERVED2); /* Interrupt 21 : unused */
64 default_interrupt(RESERVED3); /* Interrupt 22 : unused */
65 default_interrupt(RESERVED4); /* Interrupt 23 : unused */
66 default_interrupt(RESERVED5); /* Interrupt 24 : unused */
67 default_interrupt(RESERVED6); /* Interrupt 25 : unused */
68 default_interrupt(RESERVED7); /* Interrupt 26 : unused */
69 default_interrupt(RESERVED8); /* Interrupt 27 : unused */
70 default_interrupt(RESERVED9); /* Interrupt 28 : unused */
71 /* INT_GPIOA is declared in this file */
72 void INT_GPIOA(void);
73 default_interrupt(INT_GPIOB);
74 default_interrupt(INT_GPIOC);
76 static const char * const irqname[] =
78 "INT_WATCHDOG", "INT_TIMER1", "INT_TIMER2", "INT_USB", "INT_DMAC", "INT_NAND",
79 "INT_IDE", "INT_MCI0", "INT_MCI1", "INT_AUDIO", "INT_SSP", "INT_I2C_MS",
80 "INT_I2C_AUDIO", "INT_I2SIN", "INT_I2SOUT", "INT_UART", "INT_GPIOD", "RESERVED1",
81 "INT_CGU", "INT_MEMORY_STICK", "INT_DBOP", "RESERVED2", "RESERVED3", "RESERVED4",
82 "RESERVED5", "RESERVED6", "RESERVED7", "RESERVED8", "RESERVED9", "INT_GPIOA",
83 "INT_GPIOB", "INT_GPIOC"
86 static void UIRQ(void)
88 bool masked = false;
89 int status = VIC_IRQ_STATUS;
90 if(status == 0)
92 status = VIC_RAW_INTR; /* masked interrupts */
93 masked = true;
96 if(status == 0)
97 panicf("Unhandled IRQ (source unknown!)");
99 unsigned irq_no = 31 - __builtin_clz(status);
101 panicf("Unhandled %smasked IRQ %02X: %s (status 0x%8X)",
102 masked ? "" : "un", irq_no, irqname[irq_no], status);
105 struct vec_int_src
107 int source;
108 void (*isr) (void);
111 /* Vectored interrupts (16 available) */
112 struct vec_int_src vec_int_srcs[] =
114 /* Highest priority at the top of the list */
115 { INT_SRC_DMAC, INT_DMAC },
116 { INT_SRC_NAND, INT_NAND },
117 #if (defined HAVE_MULTIDRIVE && CONFIG_CPU == AS3525)
118 { INT_SRC_MCI0, INT_MCI0 },
119 #endif
120 { INT_SRC_USB, INT_USB, },
121 #ifdef HAVE_RECORDING
122 { INT_SRC_I2SIN, INT_I2SIN, },
123 #endif
124 { INT_SRC_TIMER1, INT_TIMER1 },
125 { INT_SRC_TIMER2, INT_TIMER2 },
126 { INT_SRC_I2C_AUDIO, INT_I2C_AUDIO },
127 { INT_SRC_AUDIO, INT_AUDIO },
128 #if defined(HAVE_HOTSWAP) || \
129 (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING)
130 { INT_SRC_GPIOA, INT_GPIOA, },
131 #endif
132 /* Lowest priority at the end of the list */
135 static void setup_vic(void)
137 const unsigned int n = sizeof(vec_int_srcs)/sizeof(vec_int_srcs[0]);
138 unsigned int i;
140 CGU_PERI |= CGU_VIC_CLOCK_ENABLE; /* enable VIC */
141 VIC_INT_EN_CLEAR = 0xffffffff; /* disable all interrupt lines */
142 VIC_INT_SELECT = 0; /* only IRQ, no FIQ */
144 *VIC_DEF_VECT_ADDR = UIRQ;
146 for(i = 0; i < n; i++)
148 VIC_VECT_ADDRS[i] = vec_int_srcs[i].isr;
149 VIC_VECT_CNTLS[i] = (1<<5) | vec_int_srcs[i].source;
153 void INT_GPIOA(void)
155 #ifdef HAVE_HOTSWAP
156 void sd_gpioa_isr(void);
157 sd_gpioa_isr();
158 #endif
159 #if defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING
160 void button_gpioa_isr(void);
161 button_gpioa_isr();
162 #endif
165 void irq_handler(void)
167 (*VIC_VECT_ADDR)(); /* call the isr */
168 *VIC_VECT_ADDR = (void*)VIC_VECT_ADDR; /* any write will ack the irq */
171 void fiq_handler(void)
175 #if defined(SANSA_C200V2)
176 int c200v2_variant;
178 static void check_model_variant(void)
180 unsigned int i;
181 unsigned int saved_dir = GPIOA_DIR;
183 /* Make A7 input */
184 GPIOA_DIR &= ~(1<<7);
185 /* wait a little to allow the pullup/pulldown resistor
186 * to charge the input capacitance */
187 for (i=0; i<1000; i++) asm volatile ("nop\n");
188 /* read the pullup/pulldown value on A7 to determine the variant */
189 c200v2_variant = !GPIOA_PIN(7);
190 GPIOA_DIR = saved_dir;
192 #elif defined(SANSA_FUZEV2)
193 int fuzev2_variant;
195 static void check_model_variant(void)
197 GPIOB_DIR &= ~(1<<5);
198 fuzev2_variant = !!GPIOB_PIN(5);
200 #else
201 static inline void check_model_variant(void)
204 #endif /* model selection */
206 void system_init(void)
208 #if CONFIG_CPU == AS3525v2
209 CCU_SRC = 0x57D7BF0;
210 #else
211 CCU_SRC = 0x1fffff0
212 & ~CCU_SRC_IDE_EN; /* FIXME */
213 #endif
215 unsigned int reset_loops = 640;
216 while(reset_loops--)
217 CCU_SRL = CCU_SRL_MAGIC_NUMBER;
218 CCU_SRC = CCU_SRL = 0;
220 CCU_SCON = 1; /* AHB master's priority configuration :
221 TIC (Test Interface Controller) > DMA > USB > IDE > ARM */
223 CGU_PROC = 0; /* fclk 24 MHz */
224 #if CONFIG_CPU == AS3525v2
225 /* pclk is always based on PLLA, since we don't know the current PLLA speed,
226 * avoid having pclk too fast and hope it's not too low */
227 CGU_PERI |= 0xf << 2; /* pclk lowest */
228 #else
229 CGU_PERI &= ~0x7f; /* pclk 24 MHz */
230 #endif
232 /* bits 31:30 should be set to 0 in arm926-ejs */
233 asm volatile(
234 "mrc p15, 0, r0, c1, c0 \n" /* control register */
235 "bic r0, r0, #3<<30 \n" /* clears bus bits : sets fastbus */
236 "mcr p15, 0, r0, c1, c0 \n"
237 : : : "r0" );
239 CGU_COUNTA = CGU_LOCK_CNT;
240 CGU_PLLA = AS3525_PLLA_SETTING;
241 CGU_PLLASUP = 0; /* enable PLLA */
242 while(!(CGU_INTCTRL & CGU_PLLA_LOCK)); /* wait until PLLA is locked */
244 #if AS3525_MCLK_SEL == AS3525_CLK_PLLB
245 CGU_COUNTB = CGU_LOCK_CNT;
246 CGU_PLLB = AS3525_PLLB_SETTING;
247 CGU_PLLBSUP = 0; /* enable PLLB */
248 while(!(CGU_INTCTRL & CGU_PLLB_LOCK)); /* wait until PLLB is locked */
249 #endif
251 /* Set FCLK frequency */
252 CGU_PROC = ((AS3525_FCLK_POSTDIV << 4) |
253 (AS3525_FCLK_PREDIV << 2) |
254 AS3525_FCLK_SEL);
256 /* Set PCLK frequency */
257 CGU_PERI = ((CGU_PERI & ~0x7F) | /* reset divider & clksel bits */
258 (AS3525_PCLK_DIV0 << 2) |
259 #if CONFIG_CPU == AS3525
260 (AS3525_PCLK_DIV1 << 6) |
261 #endif
262 AS3525_PCLK_SEL);
264 #if CONFIG_CPU == AS3525
265 cpu_frequency = CPUFREQ_DEFAULT; /* fastbus */
266 #else
267 cpu_frequency = CPUFREQ_MAX;
268 #endif
270 #if !defined(BOOTLOADER) && defined(SANSA_FUZE) || defined(SANSA_CLIP) || defined(SANSA_E200V2)
271 /* XXX: remove me when we have a new bootloader */
272 MPMC_DYNAMIC_CONTROL = 0x0; /* MPMCCLKOUT stops when all SDRAMs are idle */
273 #endif /* BOOTLOADER */
275 #if 0 /* the GPIO clock is already enabled by the dualboot function */
276 CGU_PERI |= CGU_GPIO_CLOCK_ENABLE;
277 #endif
279 /* enable timer interface for TIMER1 & TIMER2 */
280 CGU_PERI |= CGU_TIMERIF_CLOCK_ENABLE;
282 setup_vic();
284 dma_init();
286 ascodec_init();
288 #ifndef BOOTLOADER
289 /* setup isr for microsd monitoring and for fuzev2 scrollwheel irq */
290 #if defined(HAVE_HOTSWAP) || \
291 (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING)
292 VIC_INT_ENABLE = (INTERRUPT_GPIOA);
293 /* pin selection for irq happens in the drivers */
294 #endif
296 /* Initialize power management settings */
297 ascodec_write(AS3514_CVDD_DCDC3, AS314_CP_DCDC3_SETTING);
298 #if CONFIG_TUNER
299 fmradio_i2c_init();
300 #endif
301 #endif /* !BOOTLOADER */
302 check_model_variant();
305 void system_reboot(void)
307 _backlight_off();
309 disable_irq();
311 /* use watchdog to reset */
312 CGU_PERI |= (CGU_WDOCNT_CLOCK_ENABLE | CGU_WDOIF_CLOCK_ENABLE);
313 WDT_LOAD = 1; /* set counter to 1 */
314 WDT_CONTROL = 3; /* enable watchdog counter & reset */
315 while(1);
318 void system_exception_wait(void)
320 /* make sure lcd+backlight are on */
321 _backlight_panic_on();
322 /* wait until button release (if a button is pressed) */
323 while(button_read_device());
324 /* then wait until next button press */
325 while(!button_read_device());
328 int system_memory_guard(int newmode)
330 (void)newmode;
331 return 0;
334 /* usecs may be at most 2^32/248 (17 seconds) for 248MHz max cpu freq */
335 void udelay(unsigned usecs)
337 unsigned cycles_per_usec;
338 unsigned delay;
340 if (cpu_frequency == CPUFREQ_MAX) {
341 cycles_per_usec = (CPUFREQ_MAX + 999999) / 1000000;
342 } else {
343 cycles_per_usec = (CPUFREQ_NORMAL + 999999) / 1000000;
346 delay = (usecs * cycles_per_usec + 3) / 4;
348 asm volatile(
349 "1: subs %0, %0, #1 \n" /* 1 cycle */
350 " bne 1b \n" /* 3 cycles */
351 : : "r"(delay)
355 #ifndef BOOTLOADER
356 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
358 #if CONFIG_CPU == AS3525
359 void set_cpu_frequency(long frequency)
361 if(frequency == CPUFREQ_MAX)
363 #ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
364 /* Increasing frequency so boost voltage before change */
365 ascodec_write(AS3514_CVDD_DCDC3, (AS314_CP_DCDC3_SETTING | CVDD_1_20));
367 /* Some players run a bit low so use 1.175 volts instead of 1.20 */
368 /* Wait for voltage to be at least 1.175v before making fclk > 200 MHz */
369 while(adc_read(ADC_CVDD) < 470); /* 470 * .0025 = 1.175V */
370 #endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */
372 asm volatile(
373 "mrc p15, 0, r0, c1, c0 \n"
375 #ifdef ASYNCHRONOUS_BUS
376 "orr r0, r0, #3<<30 \n" /* asynchronous bus clocking */
377 #else
378 "bic r0, r0, #3<<30 \n" /* clear bus bits */
379 "orr r0, r0, #1<<30 \n" /* synchronous bus clocking */
380 #endif
382 "mcr p15, 0, r0, c1, c0 \n"
383 : : : "r0" );
385 cpu_frequency = CPUFREQ_MAX;
387 else
389 asm volatile(
390 "mrc p15, 0, r0, c1, c0 \n"
391 "bic r0, r0, #3<<30 \n" /* fastbus clocking */
392 "mcr p15, 0, r0, c1, c0 \n"
393 : : : "r0" );
396 #ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
397 /* Decreasing frequency so reduce voltage after change */
398 ascodec_write(AS3514_CVDD_DCDC3, (AS314_CP_DCDC3_SETTING | CVDD_1_10));
399 #endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */
401 cpu_frequency = CPUFREQ_NORMAL;
404 #else /* as3525v2 */
405 /* FIXME : disabled for now, seems to cause buggy memory accesses
406 * Disabling MMU or putting the function in uncached memory seems to help? */
407 void set_cpu_frequency(long frequency)
409 int oldstatus = disable_irq_save();
411 /* We only have 2 settings */
412 cpu_frequency = (frequency == CPUFREQ_MAX) ? frequency : CPUFREQ_NORMAL;
414 if(frequency == CPUFREQ_MAX)
416 /* Change PCLK while FCLK is low, so it doesn't go too high */
417 CGU_PERI = (CGU_PERI & ~(0xF << 2)) | (AS3525_PCLK_DIV0 << 2);
419 CGU_PROC = ((AS3525_FCLK_POSTDIV << 4) |
420 (AS3525_FCLK_PREDIV << 2) |
421 AS3525_FCLK_SEL);
423 else
425 CGU_PROC = ((AS3525_FCLK_POSTDIV_UNBOOSTED << 4) |
426 (AS3525_FCLK_PREDIV << 2) |
427 AS3525_FCLK_SEL);
429 /* Change PCLK after FCLK is low, so it doesn't go too high */
430 CGU_PERI = (CGU_PERI & ~(0xF << 2)) | (AS3525_PCLK_DIV0_UNBOOSTED << 2);
433 restore_irq(oldstatus);
435 #endif
437 #endif /* HAVE_ADJUSTABLE_CPU_FREQ */
438 #endif /* !BOOTLOADER */