1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
27 #include "ascodec-target.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 */
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)
89 int status
= VIC_IRQ_STATUS
;
92 status
= VIC_RAW_INTR
; /* masked interrupts */
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
);
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
},
120 { INT_SRC_USB
, INT_USB
, },
121 #ifdef HAVE_RECORDING
122 { INT_SRC_I2SIN
, INT_I2SIN
, },
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
, },
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]);
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
;
156 void sd_gpioa_isr(void);
159 #if defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING
160 void button_gpioa_isr(void);
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 #include "dbop-as3525.h"
178 int c200v2_variant
= 0;
180 static void check_model_variant(void)
183 unsigned int saved_dir
= GPIOA_DIR
;
186 GPIOA_DIR
&= ~(1<<7);
187 /* wait a little to allow the pullup/pulldown resistor
188 * to charge the input capacitance */
189 for (i
=0; i
<1000; i
++) asm volatile ("nop\n");
190 /* read the pullup/pulldown value on A7 to determine the variant */
191 if (GPIOA_PIN(7) == 0) {
202 GPIOA_DIR
= saved_dir
;
205 static inline void check_model_variant(void)
208 #endif /* SANSA_C200V2*/
210 void system_init(void)
212 #if CONFIG_CPU == AS3525v2
216 & ~CCU_SRC_IDE_EN
; /* FIXME */
219 unsigned int reset_loops
= 640;
221 CCU_SRL
= CCU_SRL_MAGIC_NUMBER
;
222 CCU_SRC
= CCU_SRL
= 0;
224 CCU_SCON
= 1; /* AHB master's priority configuration :
225 TIC (Test Interface Controller) > DMA > USB > IDE > ARM */
227 CGU_PROC
= 0; /* fclk 24 MHz */
228 #if CONFIG_CPU == AS3525v2
229 /* pclk is always based on PLLA, since we don't know the current PLLA speed,
230 * avoid having pclk too fast and hope it's not too low */
231 CGU_PERI
|= 0xf << 2; /* pclk lowest */
233 CGU_PERI
&= ~0x7f; /* pclk 24 MHz */
236 /* bits 31:30 should be set to 0 in arm926-ejs */
238 "mrc p15, 0, r0, c1, c0 \n" /* control register */
239 "bic r0, r0, #3<<30 \n" /* clears bus bits : sets fastbus */
240 "mcr p15, 0, r0, c1, c0 \n"
243 CGU_COUNTA
= CGU_LOCK_CNT
;
244 CGU_PLLA
= AS3525_PLLA_SETTING
;
245 CGU_PLLASUP
= 0; /* enable PLLA */
246 while(!(CGU_INTCTRL
& CGU_PLLA_LOCK
)); /* wait until PLLA is locked */
248 #if AS3525_MCLK_SEL == AS3525_CLK_PLLB
249 CGU_COUNTB
= CGU_LOCK_CNT
;
250 CGU_PLLB
= AS3525_PLLB_SETTING
;
251 CGU_PLLBSUP
= 0; /* enable PLLB */
252 while(!(CGU_INTCTRL
& CGU_PLLB_LOCK
)); /* wait until PLLB is locked */
255 /* Set FCLK frequency */
256 CGU_PROC
= ((AS3525_FCLK_POSTDIV
<< 4) |
257 (AS3525_FCLK_PREDIV
<< 2) |
260 /* Set PCLK frequency */
261 CGU_PERI
= ((CGU_PERI
& ~0x7F) | /* reset divider & clksel bits */
262 (AS3525_PCLK_DIV0
<< 2) |
263 #if CONFIG_CPU == AS3525
264 (AS3525_PCLK_DIV1
<< 6) |
268 #if CONFIG_CPU == AS3525
269 cpu_frequency
= CPUFREQ_DEFAULT
; /* fastbus */
271 cpu_frequency
= CPUFREQ_MAX
;
274 #if !defined(BOOTLOADER) && defined(SANSA_FUZE) || defined(SANSA_CLIP) || defined(SANSA_E200V2)
275 /* XXX: remove me when we have a new bootloader */
276 MPMC_DYNAMIC_CONTROL
= 0x0; /* MPMCCLKOUT stops when all SDRAMs are idle */
277 #endif /* BOOTLOADER */
279 #if 0 /* the GPIO clock is already enabled by the dualboot function */
280 CGU_PERI
|= CGU_GPIO_CLOCK_ENABLE
;
283 /* enable timer interface for TIMER1 & TIMER2 */
284 CGU_PERI
|= CGU_TIMERIF_CLOCK_ENABLE
;
293 /* setup isr for microsd monitoring and for fuzev2 scrollwheel irq */
294 #if defined(HAVE_HOTSWAP) || \
295 (defined(SANSA_FUZEV2) && !INCREASED_SCROLLWHEEL_POLLING)
296 VIC_INT_ENABLE
= (INTERRUPT_GPIOA
);
297 /* pin selection for irq happens in the drivers */
300 /* Initialize power management settings */
301 ascodec_write(AS3514_CVDD_DCDC3
, AS314_CP_DCDC3_SETTING
);
305 #endif /* !BOOTLOADER */
306 check_model_variant();
309 void system_reboot(void)
312 /* use watchdog to reset */
313 CGU_PERI
|= (CGU_WDOCNT_CLOCK_ENABLE
| CGU_WDOIF_CLOCK_ENABLE
);
314 WDT_LOAD
= 1; /* set counter to 1 */
315 WDT_CONTROL
= 3; /* enable watchdog counter & reset */
319 void system_exception_wait(void)
321 /* make sure lcd+backlight are on */
322 _backlight_panic_on();
323 /* wait until button release (if a button is pressed) */
324 while(button_read_device());
325 /* then wait until next button press */
326 while(!button_read_device());
329 int system_memory_guard(int newmode
)
335 /* usecs may be at most 2^32/248 (17 seconds) for 248MHz max cpu freq */
336 void udelay(unsigned usecs
)
338 unsigned cycles_per_usec
;
341 if (cpu_frequency
== CPUFREQ_MAX
) {
342 cycles_per_usec
= (CPUFREQ_MAX
+ 999999) / 1000000;
344 cycles_per_usec
= (CPUFREQ_NORMAL
+ 999999) / 1000000;
347 delay
= (usecs
* cycles_per_usec
+ 3) / 4;
350 "1: subs %0, %0, #1 \n" /* 1 cycle */
351 " bne 1b \n" /* 3 cycles */
357 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
359 #if CONFIG_CPU == AS3525
360 void set_cpu_frequency(long frequency
)
362 if(frequency
== CPUFREQ_MAX
)
364 #ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
365 /* Increasing frequency so boost voltage before change */
366 ascodec_write(AS3514_CVDD_DCDC3
, (AS314_CP_DCDC3_SETTING
| CVDD_1_20
));
368 /* Some players run a bit low so use 1.175 volts instead of 1.20 */
369 /* Wait for voltage to be at least 1.175v before making fclk > 200 MHz */
370 while(adc_read(ADC_CVDD
) < 470); /* 470 * .0025 = 1.175V */
371 #endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */
374 "mrc p15, 0, r0, c1, c0 \n"
376 #ifdef ASYNCHRONOUS_BUS
377 "orr r0, r0, #3<<30 \n" /* asynchronous bus clocking */
379 "bic r0, r0, #3<<30 \n" /* clear bus bits */
380 "orr r0, r0, #1<<30 \n" /* synchronous bus clocking */
383 "mcr p15, 0, r0, c1, c0 \n"
386 cpu_frequency
= CPUFREQ_MAX
;
391 "mrc p15, 0, r0, c1, c0 \n"
392 "bic r0, r0, #3<<30 \n" /* fastbus clocking */
393 "mcr p15, 0, r0, c1, c0 \n"
397 #ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
398 /* Decreasing frequency so reduce voltage after change */
399 ascodec_write(AS3514_CVDD_DCDC3
, (AS314_CP_DCDC3_SETTING
| CVDD_1_10
));
400 #endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */
402 cpu_frequency
= CPUFREQ_NORMAL
;
406 /* FIXME : disabled for now, seems to cause buggy memory accesses
407 * Disabling MMU or putting the function in uncached memory seems to help? */
408 void set_cpu_frequency(long frequency
)
410 int oldstatus
= disable_irq_save();
412 /* We only have 2 settings */
413 cpu_frequency
= (frequency
== CPUFREQ_MAX
) ? frequency
: CPUFREQ_NORMAL
;
415 if(frequency
== CPUFREQ_MAX
)
417 /* Change PCLK while FCLK is low, so it doesn't go too high */
418 CGU_PERI
= (CGU_PERI
& ~(0xF << 2)) | (AS3525_PCLK_DIV0
<< 2);
420 CGU_PROC
= ((AS3525_FCLK_POSTDIV
<< 4) |
421 (AS3525_FCLK_PREDIV
<< 2) |
426 CGU_PROC
= ((AS3525_FCLK_POSTDIV_UNBOOSTED
<< 4) |
427 (AS3525_FCLK_PREDIV
<< 2) |
430 /* Change PCLK after FCLK is low, so it doesn't go too high */
431 CGU_PERI
= (CGU_PERI
& ~(0xF << 2)) | (AS3525_PCLK_DIV0_UNBOOSTED
<< 2);
434 restore_irq(oldstatus
);
438 #endif /* HAVE_ADJUSTABLE_CPU_FREQ */
439 #endif /* !BOOTLOADER */