/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 by Alan Korr * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include #include "config.h" #include "system.h" #include "lcd.h" #include "font.h" #define default_interrupt(name) \ extern __attribute__((weak,alias("UIE"))) void name (void) static const char* const irqname[] = { "", "", "AccessErr","AddrErr","IllInstr", "DivX0", "","", "PrivVio","Trace","Line-A", "Line-F","Debug","","FormErr","Uninit", "","","","","","","","", "Spurious","Level1","Level2","Level3","Level4","Level5","Level6","Level7", "Trap0","Trap1","Trap2","Trap3","Trap4","Trap5","Trap6","Trap7", "Trap8","Trap9","Trap10","Trap11","Trap12","Trap13","Trap14","Trap15", "SWT","Timer0","Timer1","I2C","UART1","UART2","DMA0","DMA1", "DMA2","DMA3","QSPI","","","","","", "PDIR1FULL","PDIR2FULL","EBUTXEMPTY","IIS2TXEMPTY", "IIS1TXEMPTY","PDIR3FULL","PDIR3RESYN","UQ2CHANERR", "AUDIOTICK","PDIR2RESYN","PDIR2UNOV","PDIR1RESYN", "PDIR1UNOV","UQ1CHANERR","IEC2BUFATTEN","IEC2PARERR", "IEC2VALNOGOOD","IEC2CNEW","IEC1BUFATTEN","UCHANTXNF", "UCHANTXUNDER","UCHANTXEMPTY","PDIR3UNOV","IEC1PARERR", "IEC1VALNOGOOD","IEC1CNEW","EBUTXRESYN","EBUTXUNOV", "IIS2TXRESYN","IIS2TXUNOV","IIS1TXRESYN","IIS1TXUNOV", "GPI0","GPI1","GPI2","GPI3","GPI4","GPI5","GPI6","GPI7", "","","","","","","","SOFTINT0", "SOFTINT1","SOFTINT2","SOFTINT3","", "","CDROMCRCERR","CDROMNOSYNC","CDROMILSYNC", "CDROMNEWBLK","","","","","","","", "","","","","","","","", "","","","","","","","", "","","","","","","","", "","","","","","","","", "","","","","","","","", "","","","","","","","", "","","","","","","","", "","","","","","","","" }; default_interrupt (TRAP0); /* Trap #0 */ default_interrupt (TRAP1); /* Trap #1 */ default_interrupt (TRAP2); /* Trap #2 */ default_interrupt (TRAP3); /* Trap #3 */ default_interrupt (TRAP4); /* Trap #4 */ default_interrupt (TRAP5); /* Trap #5 */ default_interrupt (TRAP6); /* Trap #6 */ default_interrupt (TRAP7); /* Trap #7 */ default_interrupt (TRAP8); /* Trap #8 */ default_interrupt (TRAP9); /* Trap #9 */ default_interrupt (TRAP10); /* Trap #10 */ default_interrupt (TRAP11); /* Trap #11 */ default_interrupt (TRAP12); /* Trap #12 */ default_interrupt (TRAP13); /* Trap #13 */ default_interrupt (TRAP14); /* Trap #14 */ default_interrupt (TRAP15); /* Trap #15 */ default_interrupt (SWT); /* Software Watchdog Timer */ default_interrupt (TIMER0); /* Timer 0 */ default_interrupt (TIMER1); /* Timer 1 */ default_interrupt (I2C); /* I2C */ default_interrupt (UART1); /* UART 1 */ default_interrupt (UART2); /* UART 2 */ default_interrupt (DMA0); /* DMA 0 */ default_interrupt (DMA1); /* DMA 1 */ default_interrupt (DMA2); /* DMA 2 */ default_interrupt (DMA3); /* DMA 3 */ default_interrupt (QSPI); /* QSPI */ default_interrupt (PDIR1FULL); /* Processor data in 1 full */ default_interrupt (PDIR2FULL); /* Processor data in 2 full */ default_interrupt (EBUTXEMPTY); /* EBU transmit FIFO empty */ default_interrupt (IIS2TXEMPTY); /* IIS2 transmit FIFO empty */ default_interrupt (IIS1TXEMPTY); /* IIS1 transmit FIFO empty */ default_interrupt (PDIR3FULL); /* Processor data in 3 full */ default_interrupt (PDIR3RESYN); /* Processor data in 3 resync */ default_interrupt (UQ2CHANERR); /* IEC958-2 Rx U/Q channel error */ default_interrupt (AUDIOTICK); /* "tick" interrupt */ default_interrupt (PDIR2RESYN); /* Processor data in 2 resync */ default_interrupt (PDIR2UNOV); /* Processor data in 2 under/overrun */ default_interrupt (PDIR1RESYN); /* Processor data in 1 resync */ default_interrupt (PDIR1UNOV); /* Processor data in 1 under/overrun */ default_interrupt (UQ1CHANERR); /* IEC958-1 Rx U/Q channel error */ default_interrupt (IEC2BUFATTEN);/* IEC958-2 channel buffer full */ default_interrupt (IEC2PARERR); /* IEC958-2 Rx parity or symbol error */ default_interrupt (IEC2VALNOGOOD);/* IEC958-2 flag not good */ default_interrupt (IEC2CNEW); /* IEC958-2 New C-channel received */ default_interrupt (IEC1BUFATTEN);/* IEC958-1 channel buffer full */ default_interrupt (UCHANTXNF); /* U channel Tx reg next byte is first */ default_interrupt (UCHANTXUNDER);/* U channel Tx reg underrun */ default_interrupt (UCHANTXEMPTY);/* U channel Tx reg is empty */ default_interrupt (PDIR3UNOV); /* Processor data in 3 under/overrun */ default_interrupt (IEC1PARERR); /* IEC958-1 Rx parity or symbol error */ default_interrupt (IEC1VALNOGOOD);/* IEC958-1 flag not good */ default_interrupt (IEC1CNEW); /* IEC958-1 New C-channel received */ default_interrupt (EBUTXRESYN); /* EBU Tx FIFO resync */ default_interrupt (EBUTXUNOV); /* EBU Tx FIFO under/overrun */ default_interrupt (IIS2TXRESYN); /* IIS2 Tx FIFO resync */ default_interrupt (IIS2TXUNOV); /* IIS2 Tx FIFO under/overrun */ default_interrupt (IIS1TXRESYN); /* IIS1 Tx FIFO resync */ default_interrupt (IIS1TXUNOV); /* IIS1 Tx FIFO under/overrun */ default_interrupt (GPI0); /* GPIO interrupt 0 */ default_interrupt (GPI1); /* GPIO interrupt 1 */ default_interrupt (GPI2); /* GPIO interrupt 2 */ default_interrupt (GPI3); /* GPIO interrupt 3 */ default_interrupt (GPI4); /* GPIO interrupt 4 */ default_interrupt (GPI5); /* GPIO interrupt 5 */ default_interrupt (GPI6); /* GPIO interrupt 6 */ default_interrupt (GPI7); /* GPIO interrupt 7 */ default_interrupt (SOFTINT0); /* Software interrupt 0 */ default_interrupt (SOFTINT1); /* Software interrupt 1 */ default_interrupt (SOFTINT2); /* Software interrupt 2 */ default_interrupt (SOFTINT3); /* Software interrupt 3 */ default_interrupt (CDROMCRCERR); /* CD-ROM CRC error */ default_interrupt (CDROMNOSYNC); /* CD-ROM No sync */ default_interrupt (CDROMILSYNC); /* CD-ROM Illegal sync */ default_interrupt (CDROMNEWBLK); /* CD-ROM New block */ #ifdef IAUDIO_X5 #define EXCP_BUTTON_GPIO_READ GPIO_READ #define EXCP_BUTTON_MASK 0x0c000000 #define EXCP_BUTTON_VALUE 0x08000000 /* On button and !hold */ #define EXCP_PLLCR 0x10400000 #else #define EXCP_BUTTON_GPIO_READ GPIO1_READ #define EXCP_BUTTON_MASK 0x00000022 #define EXCP_BUTTON_VALUE 0x00000000 #define EXCP_PLLCR 0x10800000 #endif static void system_display_exception_info(unsigned long format, unsigned long pc) __attribute__ ((noreturn)); static void system_display_exception_info(unsigned long format, unsigned long pc) { int vector = (format >> 18) & 0xff; char str[32]; /* clear screen */ lcd_clear_display (); lcd_setfont(FONT_SYSFIXED); snprintf(str, sizeof(str), "I%02x:%s", vector, irqname[vector]); lcd_puts(0, 0, str); snprintf(str, sizeof(str), "at %08x", pc); lcd_puts(0, 1, str); lcd_update(); /* set cpu frequency to 11mhz (to prevent overheating) */ DCR = (DCR & ~0x01ff) | 1; PLLCR = EXCP_PLLCR; while (1) { if ((EXCP_BUTTON_GPIO_READ & EXCP_BUTTON_MASK) == EXCP_BUTTON_VALUE) SYPCR = 0xc0; /* Start watchdog timer with 512 cycles timeout. Don't service it. */ } /* We need a reset method that works in all cases. Calling system_reboot() doesn't work when we're called from the debug interrupt, because then the CPU is in emulator mode and the only ways leaving it are exexcuting an rte instruction or performing a reset. Even disabling the breakpoint logic and performing special rte magic doesn't make system_reboot() reliable. The system restarts, but boot often fails with ata error -42. */ } static void UIE(void) __attribute__ ((noreturn)); static void UIE(void) { asm volatile("subq.l #4,%sp"); /* phony return address - never used */ asm volatile("jmp system_display_exception_info"); while (1); /* loop to silence 'noreturn' function does return */ } /* reset vectors are handled in crt0.S */ void (* const vbr[]) (void) __attribute__ ((section (".vectors"))) = { UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,TIMER0,TIMER1,UIE,UIE,UIE, /* lvl 3 lvl 4 */ TRAP0,TRAP1,TRAP2,TRAP3,TRAP4,TRAP5,TRAP6,TRAP7, TRAP8,TRAP9,TRAP10,TRAP11,TRAP12,TRAP13,TRAP14,TRAP15, SWT,UIE,UIE,I2C,UART1,UART2,DMA0,DMA1, DMA2,DMA3,QSPI,UIE,UIE,UIE,UIE,UIE, PDIR1FULL,PDIR2FULL,EBUTXEMPTY,IIS2TXEMPTY, IIS1TXEMPTY,PDIR3FULL,PDIR3RESYN,UQ2CHANERR, AUDIOTICK,PDIR2RESYN,PDIR2UNOV,PDIR1RESYN, PDIR1UNOV,UQ1CHANERR,IEC2BUFATTEN,IEC2PARERR, IEC2VALNOGOOD,IEC2CNEW,IEC1BUFATTEN,UCHANTXNF, UCHANTXUNDER,UCHANTXEMPTY,PDIR3UNOV,IEC1PARERR, IEC1VALNOGOOD,IEC1CNEW,EBUTXRESYN,EBUTXUNOV, IIS2TXRESYN,IIS2TXUNOV,IIS1TXRESYN,IIS1TXUNOV, GPI0,GPI1,GPI2,GPI3,GPI4,GPI5,GPI6,GPI7, UIE,UIE,UIE,UIE,UIE,UIE,UIE,SOFTINT0, SOFTINT1,SOFTINT2,SOFTINT3,UIE, UIE,CDROMCRCERR,CDROMNOSYNC,CDROMILSYNC, CDROMNEWBLK,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE, UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE,UIE }; void system_init(void) { /* Clear the accumulators. From here on it's the responsibility of whoever uses them to clear them after use (use movclr instruction). */ asm volatile ("movclr.l %%acc0, %%d0\n\t" "movclr.l %%acc1, %%d0\n\t" "movclr.l %%acc2, %%d0\n\t" "movclr.l %%acc3, %%d0\n\t" : : : "d0"); /* Set EMAC unit to saturating and rounding fractional mode, since that's what'll be the most useful for most things which the main thread will do. */ coldfire_set_macsr(EMAC_FRACTIONAL | EMAC_SATURATE | EMAC_ROUND); /* Set INTBASE and SPURVEC */ INTBASE = 64; SPURVEC = 24; } void system_reboot (void) { set_cpu_frequency(0); asm(" move.w #0x2700,%sr"); /* Reset the cookie for the crt0 crash check */ asm(" move.l #0,%d0"); asm(" move.l %d0,0x10017ffc"); asm(" movec.l %d0,%vbr"); asm(" move.l 0,%sp"); asm(" move.l 4,%a0"); asm(" jmp (%a0)"); } /* Utilise the breakpoint hardware to catch invalid memory accesses. */ int system_memory_guard(int newmode) { static const unsigned long modes[MAXMEMGUARD][8] = { { /* catch nothing */ 0x2C870000, 0x00000000, /* TDR = 0x00000000 */ 0x2C8D0000, 0x00000000, /* ABLR = 0x00000000 */ 0x2C8C0000, 0x00000000, /* ABHR = 0x00000000 */ 0x2C860000, 0x00050000, /* AATR = 0x0005 */ }, { /* catch flash ROM writes */ 0x2C8D0000, 0x00000000, /* ABLR = 0x00000000 */ 0x2C8C0FFF, 0xFFFF0000, /* ABHR = 0x0FFFFFFF */ 0x2C860000, 0x6F050000, /* AATR = 0x6F05 */ 0x2C878000, 0x20080000, /* TDR = 0x80002008 */ }, { /* catch all accesses to zero area */ 0x2C8D0000, 0x00000000, /* ABLR = 0x00000000 */ 0x2C8C0FFF, 0xFFFF0000, /* ABHR = 0x0FFFFFFF */ 0x2C860000, 0xEF050000, /* AATR = 0xEF05 */ 0x2C878000, 0x20080000, /* TDR = 0x80002008 */ } /* Note: CPU space accesses (movec instruction), interrupt acknowledges and emulator mode accesses are never caught. */ }; static int cur_mode = MEMGUARD_NONE; int oldmode = cur_mode; const unsigned long *ptr; int i; if (newmode == MEMGUARD_KEEP) newmode = oldmode; /* Always set the new mode, we don't know the old settings as we cannot read back */ ptr = modes[newmode]; for (i = 0; i < 4; i++) { asm ( "wdebug (%0) \n" : : "a"(ptr)); ptr += 2; } cur_mode = newmode; return oldmode; } /* allow setting of audio clock related bits */ void coldfire_set_pllcr_audio_bits(long bits) { PLLCR = (PLLCR & ~0x70400000) | (bits & 0x70400000); }