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"
36 #include "backlight-target.h"
38 #define default_interrupt(name) \
39 extern __attribute__((weak,alias("UIRQ"))) void name (void)
41 void irq_handler(void) __attribute__((interrupt ("IRQ"), naked
));
42 void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked
));
44 default_interrupt(INT_WATCHDOG
);
45 default_interrupt(INT_TIMER1
);
46 default_interrupt(INT_TIMER2
);
47 default_interrupt(INT_USB
);
48 default_interrupt(INT_DMAC
);
49 default_interrupt(INT_NAND
);
50 default_interrupt(INT_IDE
);
51 default_interrupt(INT_MCI0
);
52 default_interrupt(INT_MCI1
);
53 default_interrupt(INT_AUDIO
);
54 default_interrupt(INT_SSP
);
55 default_interrupt(INT_I2C_MS
);
56 default_interrupt(INT_I2C_AUDIO
);
57 default_interrupt(INT_I2SIN
);
58 default_interrupt(INT_I2SOUT
);
59 default_interrupt(INT_UART
);
60 default_interrupt(INT_GPIOD
);
61 default_interrupt(RESERVED1
); /* Interrupt 17 : unused */
62 default_interrupt(INT_CGU
);
63 default_interrupt(INT_MEMORY_STICK
);
64 default_interrupt(INT_DBOP
);
65 default_interrupt(RESERVED2
); /* Interrupt 21 : unused */
66 default_interrupt(RESERVED3
); /* Interrupt 22 : unused */
67 default_interrupt(RESERVED4
); /* Interrupt 23 : unused */
68 default_interrupt(RESERVED5
); /* Interrupt 24 : unused */
69 default_interrupt(RESERVED6
); /* Interrupt 25 : unused */
70 default_interrupt(RESERVED7
); /* Interrupt 26 : unused */
71 default_interrupt(RESERVED8
); /* Interrupt 27 : unused */
72 default_interrupt(RESERVED9
); /* Interrupt 28 : unused */
73 /* INT_GPIOA is declared in this file */
75 default_interrupt(INT_GPIOB
);
76 default_interrupt(INT_GPIOC
);
78 static const char * const irqname
[] =
80 "INT_WATCHDOG", "INT_TIMER1", "INT_TIMER2", "INT_USB", "INT_DMAC", "INT_NAND",
81 "INT_IDE", "INT_MCI0", "INT_MCI1", "INT_AUDIO", "INT_SSP", "INT_I2C_MS",
82 "INT_I2C_AUDIO", "INT_I2SIN", "INT_I2SOUT", "INT_UART", "INT_GPIOD", "RESERVED1",
83 "INT_CGU", "INT_MEMORY_STICK", "INT_DBOP", "RESERVED2", "RESERVED3", "RESERVED4",
84 "RESERVED5", "RESERVED6", "RESERVED7", "RESERVED8", "RESERVED9", "INT_GPIOA",
85 "INT_GPIOB", "INT_GPIOC"
88 static void UIRQ(void)
90 unsigned int irq_no
= 0;
91 int status
= VIC_IRQ_STATUS
;
94 panicf("Unhandled IRQ (source unknown!)");
99 panicf("Unhandled IRQ %02X: %s", irq_no
, irqname
[irq_no
]);
108 /* Vectored interrupts (16 available) */
109 struct vec_int_src vec_int_srcs
[] =
111 { INT_SRC_TIMER1
, INT_TIMER1
},
112 { INT_SRC_TIMER2
, INT_TIMER2
},
113 { INT_SRC_DMAC
, INT_DMAC
},
114 { INT_SRC_NAND
, INT_NAND
},
115 { INT_SRC_I2C_AUDIO
, INT_I2C_AUDIO
},
116 { INT_SRC_AUDIO
, INT_AUDIO
},
117 #if (defined HAVE_MULTIDRIVE && CONFIG_CPU == AS3525)
118 { INT_SRC_MCI0
, INT_MCI0
},
121 { INT_SRC_GPIOA
, INT_GPIOA
, },
123 #ifdef HAVE_RECORDING
124 { INT_SRC_I2SIN
, INT_I2SIN
, },
128 static void setup_vic(void)
130 volatile unsigned long *vic_vect_addrs
= VIC_VECT_ADDRS
;
131 volatile unsigned long *vic_vect_cntls
= VIC_VECT_CNTLS
;
132 const unsigned int n
= sizeof(vec_int_srcs
)/sizeof(vec_int_srcs
[0]);
135 CGU_PERI
|= CGU_VIC_CLOCK_ENABLE
; /* enable VIC */
136 VIC_INT_EN_CLEAR
= 0xffffffff; /* disable all interrupt lines */
137 VIC_INT_SELECT
= 0; /* only IRQ, no FIQ */
139 VIC_DEF_VECT_ADDR
= (unsigned long)UIRQ
;
141 for(i
= 0; i
< n
; i
++)
143 vic_vect_addrs
[i
] = (unsigned long)vec_int_srcs
[i
].isr
;
144 vic_vect_cntls
[i
] = (1<<5) | vec_int_srcs
[i
].source
;
150 #ifdef HAVE_MULTIDRIVE
151 void sd_gpioa_isr(void);
154 #if (defined(HAVE_SCROLLWHEEL) && CONFIG_CPU != AS3525)
155 void button_gpioa_isr(void);
160 void irq_handler(void)
162 asm volatile( "stmfd sp!, {r0-r5,ip,lr} \n" /* Store context */
163 "ldr r5, =0xC6010030 \n" /* VIC_VECT_ADDR */
164 "mov lr, pc \n" /* Return from ISR */
165 "ldr pc, [r5] \n" /* execute ISR */
166 "str r0, [r5] \n" /* Ack interrupt */
167 "ldmfd sp!, {r0-r5,ip,lr} \n" /* Restore context */
168 "subs pc, lr, #4 \n" /* Return from IRQ */
172 void fiq_handler(void)
175 "subs pc, lr, #4 \r\n"
179 #if defined(SANSA_C200V2)
180 #include "dbop-as3525.h"
182 int c200v2_variant
= 0;
184 static void check_model_variant(void)
187 unsigned int saved_dir
= GPIOA_DIR
;
190 GPIOA_DIR
&= ~(1<<7);
191 /* wait a little to allow the pullup/pulldown resistor
192 * to charge the input capacitance */
193 for (i
=0; i
<1000; i
++) asm volatile ("nop\n");
194 /* read the pullup/pulldown value on A7 to determine the variant */
195 if (GPIOA_PIN(7) == 0) {
206 GPIOA_DIR
= saved_dir
;
209 static inline void check_model_variant(void)
212 #endif /* SANSA_C200V2*/
214 #if defined(BOOTLOADER)
215 static void sdram_delay(void)
217 int delay
= 1024; /* arbitrary */
221 /* Use the same initialization than OF */
222 static void sdram_init(void)
224 CGU_PERI
|= (CGU_EXTMEM_CLOCK_ENABLE
|CGU_EXTMEMIF_CLOCK_ENABLE
);
226 MPMC_CONTROL
= 0x1; /* enable MPMC */
228 MPMC_DYNAMIC_CONTROL
= 0x183; /* SDRAM NOP, all clocks high */
231 MPMC_DYNAMIC_CONTROL
= 0x103; /* SDRAM PALL, all clocks high */
234 MPMC_DYNAMIC_REFRESH
= 0x138; /* 0x138 * 16 HCLK ticks between SDRAM refresh cycles */
236 MPMC_CONFIG
= 0; /* little endian, HCLK:MPMCCLKOUT[3:0] ratio = 1:1 */
238 if(MPMC_PERIPH_ID2
& 0xf0)
239 MPMC_DYNAMIC_READ_CONFIG
= 0x1; /* command delayed, clock out not delayed */
242 MPMC_DYNAMIC_tRP
= 2;
243 MPMC_DYNAMIC_tRAS
= 4;
244 MPMC_DYNAMIC_tSREX
= 5;
245 MPMC_DYNAMIC_tAPR
= 0;
246 MPMC_DYNAMIC_tDAL
= 4;
247 MPMC_DYNAMIC_tWR
= 2;
248 MPMC_DYNAMIC_tRC
= 5;
249 MPMC_DYNAMIC_tRFC
= 5;
250 MPMC_DYNAMIC_tXSR
= 5;
251 MPMC_DYNAMIC_tRRD
= 2;
252 MPMC_DYNAMIC_tMRD
= 2;
254 #if defined(SANSA_CLIP) || defined(SANSA_M200V4) || defined(SANSA_C200V2)
255 /* 16 bits external bus, low power SDRAM, 16 Mbits = 2 Mbytes */
256 #define MEMORY_MODEL 0x21
258 #elif defined(SANSA_E200V2) || defined(SANSA_FUZE) || defined(SANSA_CLIPV2) \
259 || defined(SANSA_CLIPPLUS) || defined(SANSA_FUZEV2)
260 /* 16 bits external bus, high performance SDRAM, 64 Mbits = 8 Mbytes */
261 #define MEMORY_MODEL 0x5
264 #error "The external memory in your player is unknown"
267 MPMC_DYNAMIC_RASCAS_0
= (2<<8)|2; /* CAS & RAS latency = 2 clock cycles */
268 MPMC_DYNAMIC_CONFIG_0
= (MEMORY_MODEL
<< 7);
270 MPMC_DYNAMIC_RASCAS_1
= MPMC_DYNAMIC_CONFIG_1
=
271 MPMC_DYNAMIC_RASCAS_2
= MPMC_DYNAMIC_CONFIG_2
=
272 MPMC_DYNAMIC_RASCAS_3
= MPMC_DYNAMIC_CONFIG_3
= 0;
274 MPMC_DYNAMIC_CONTROL
= 0x82; /* SDRAM MODE, MPMCCLKOUT runs continuously */
276 /* program the SDRAM mode register */
277 /* FIXME: details the exact settings of mode register */
280 : : "p"(0x30000000+0x2300*MEM
) : "r4");
282 MPMC_DYNAMIC_CONTROL
= 0x2; /* SDRAM NORMAL, MPMCCLKOUT runs continuously */
284 MPMC_DYNAMIC_CONFIG_0
|= (1<<19); /* buffer enable */
286 #endif /* BOOTLOADER */
288 void system_init(void)
290 #if CONFIG_CPU == AS3525v2
294 & ~CCU_SRC_IDE_EN
; /* FIXME */
297 unsigned int reset_loops
= 640;
299 CCU_SRL
= CCU_SRL_MAGIC_NUMBER
;
300 CCU_SRC
= CCU_SRL
= 0;
302 CCU_SCON
= 1; /* AHB master's priority configuration :
303 TIC (Test Interface Controller) > DMA > USB > IDE > ARM */
305 CGU_PROC
= 0; /* fclk 24 MHz */
306 #if CONFIG_CPU == AS3525v2
307 /* pclk is always based on PLLA, since we don't know the current PLLA speed,
308 * avoid having pclk too fast and hope it's not too low */
309 CGU_PERI
|= 0xf << 2; /* pclk lowest */
311 CGU_PERI
&= ~0x7f; /* pclk 24 MHz */
314 /* bits 31:30 should be set to 0 in arm926-ejs */
316 "mrc p15, 0, r0, c1, c0 \n" /* control register */
317 "bic r0, r0, #3<<30 \n" /* clears bus bits : sets fastbus */
318 "mcr p15, 0, r0, c1, c0 \n"
322 CGU_PLLA
= AS3525_PLLA_SETTING
;
323 CGU_PLLASUP
= 0; /* enable PLLA */
324 while(!(CGU_INTCTRL
& (1<<0))); /* wait until PLLA is locked */
326 #if (AS3525_MCLK_SEL == AS3525_CLK_PLLB)
328 CGU_PLLB
= AS3525_PLLB_SETTING
;
329 CGU_PLLBSUP
= 0; /* enable PLLB */
330 while(!(CGU_INTCTRL
& (1<<1))); /* wait until PLLB is locked */
333 /* Set FCLK frequency */
334 CGU_PROC
= ((AS3525_FCLK_POSTDIV
<< 4) |
335 (AS3525_FCLK_PREDIV
<< 2) |
338 /* Set PCLK frequency */
339 CGU_PERI
= ((CGU_PERI
& ~0x7F) | /* reset divider & clksel bits */
340 (AS3525_PCLK_DIV0
<< 2) |
341 #if CONFIG_CPU == AS3525
342 (AS3525_PCLK_DIV1
<< 6) |
348 #endif /* BOOTLOADER */
350 #if 0 /* the GPIO clock is already enabled by the dualboot function */
351 CGU_PERI
|= CGU_GPIO_CLOCK_ENABLE
;
354 /* enable timer interface for TIMER1 & TIMER2 */
355 CGU_PERI
|= CGU_TIMERIF_CLOCK_ENABLE
;
364 /* setup isr for microsd monitoring and for scrollwheel irq */
365 #if defined(HAVE_MULTIDRIVE) || (defined(HAVE_SCROLLWHEEL) && CONFIG_CPU != AS3525)
366 VIC_INT_ENABLE
= (INTERRUPT_GPIOA
);
367 /* pin selection for irq happens in the drivers */
370 /* Initialize power management settings */
371 ascodec_write(AS3514_CVDD_DCDC3
, AS314_CP_DCDC3_SETTING
);
375 #endif /* !BOOTLOADER */
376 check_model_variant();
379 void system_reboot(void)
382 /* use watchdog to reset */
383 CGU_PERI
|= (CGU_WDOCNT_CLOCK_ENABLE
| CGU_WDOIF_CLOCK_ENABLE
);
384 WDT_LOAD
= 1; /* set counter to 1 */
385 WDT_CONTROL
= 3; /* enable watchdog counter & reset */
389 void system_exception_wait(void)
391 /* wait until button release (if a button is pressed) */
392 while(button_read_device());
393 /* then wait until next button press */
394 while(!button_read_device());
397 int system_memory_guard(int newmode
)
404 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
406 #if CONFIG_CPU == AS3525
407 void set_cpu_frequency(long frequency
)
409 if(frequency
== CPUFREQ_MAX
)
411 #ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
412 /* Increasing frequency so boost voltage before change */
413 ascodec_write(AS3514_CVDD_DCDC3
, (AS314_CP_DCDC3_SETTING
| CVDD_1_20
));
415 /* Some players run a bit low so use 1.175 volts instead of 1.20 */
416 /* Wait for voltage to be at least 1.175v before making fclk > 200 MHz */
417 while(adc_read(ADC_CVDD
) < 470); /* 470 * .0025 = 1.175V */
418 #endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */
421 "mrc p15, 0, r0, c1, c0 \n"
423 #ifdef ASYNCHRONOUS_BUS
424 "orr r0, r0, #3<<30 \n" /* asynchronous bus clocking */
426 "bic r0, r0, #3<<30 \n" /* clear bus bits */
427 "orr r0, r0, #1<<30 \n" /* synchronous bus clocking */
430 "mcr p15, 0, r0, c1, c0 \n"
433 cpu_frequency
= CPUFREQ_MAX
;
438 "mrc p15, 0, r0, c1, c0 \n"
439 "bic r0, r0, #3<<30 \n" /* fastbus clocking */
440 "mcr p15, 0, r0, c1, c0 \n"
444 #ifdef HAVE_ADJUSTABLE_CPU_VOLTAGE
445 /* Decreasing frequency so reduce voltage after change */
446 ascodec_write(AS3514_CVDD_DCDC3
, (AS314_CP_DCDC3_SETTING
| CVDD_1_10
));
447 #endif /* HAVE_ADJUSTABLE_CPU_VOLTAGE */
449 cpu_frequency
= CPUFREQ_NORMAL
;
453 void set_cpu_frequency(long frequency
)
455 int oldstatus
= disable_irq_save();
457 /* We only have 2 settings */
458 cpu_frequency
= (frequency
== CPUFREQ_MAX
) ? frequency
: CPUFREQ_NORMAL
;
460 if(frequency
== CPUFREQ_MAX
)
462 /* Change PCLK while FCLK is low, so it doesn't go too high */
463 CGU_PERI
= (CGU_PERI
& ~(0xF << 2)) | (AS3525_PCLK_DIV0
<< 2);
465 CGU_PROC
= ((AS3525_FCLK_POSTDIV
<< 4) |
466 (AS3525_FCLK_PREDIV
<< 2) |
471 CGU_PROC
= ((AS3525_FCLK_POSTDIV_UNBOOSTED
<< 4) |
472 (AS3525_FCLK_PREDIV
<< 2) |
475 /* Change PCLK after FCLK is low, so it doesn't go too high */
476 CGU_PERI
= (CGU_PERI
& ~(0xF << 2)) | (AS3525_PCLK_DIV0_UNBOOSTED
<< 2);
479 restore_irq(oldstatus
);
483 #endif /* HAVE_ADJUSTABLE_CPU_FREQ */
484 #endif /* !BOOTLOADER */