diff options
Diffstat (limited to 'firmware/target')
56 files changed, 1199 insertions, 902 deletions
diff --git a/firmware/target/arm/ata-as-arm.S b/firmware/target/arm/ata-as-arm.S index 101bc4dcc1..16c2928bf1 100644 --- a/firmware/target/arm/ata-as-arm.S +++ b/firmware/target/arm/ata-as-arm.S @@ -139,9 +139,9 @@ copy_read_sectors: .r_end2_u: tst r1, #1 /* one halfword left? */ - ldrneh r4, [r2] + ldrhne r4, [r2] orrne r3, r3, r4, lsl #8 - strneh r3, [r0], #2 + strhne r3, [r0], #2 movne r3, r4, lsr #8 strb r3, [r0], #1 /* store final byte */ @@ -151,8 +151,8 @@ copy_read_sectors: /* 16-bit aligned */ .r_aligned: tst r0, #2 /* 32 bit aligned? */ - ldrneh r3, [r2] /* no: read first halfword */ - strneh r3, [r0], #2 /* store */ + ldrhne r3, [r2] /* no: read first halfword */ + strhne r3, [r0], #2 /* store */ subne r1, r1, #1 /* one halfword taken */ sub r1, r1, #8 /* adjust for zero-check and doing 8 halfwords/loop */ @@ -186,14 +186,14 @@ copy_read_sectors: .r_end4_a: tst r1, #2 /* 2 or more halfwords left? */ - ldrneh r3, [r2] - ldrneh r4, [r2] + ldrhne r3, [r2] + ldrhne r4, [r2] orrne r3, r3, r4, lsl #16 strne r3, [r0], #4 tst r1, #1 /* one halfword left? */ - ldrneh r3, [r2] - strneh r3, [r0], #2 + ldrhne r3, [r2] + strhne r3, [r0], #2 ldmpc regs=r4-r5 @@ -291,9 +291,9 @@ copy_write_sectors: .w_end2_u: tst r1, #1 /* one halfword left? */ - ldrneh r4, [r0], #2 + ldrhne r4, [r0], #2 orrne r3, r3, r4, lsl #8 - strneh r3, [r2] + strhne r3, [r2] movne r3, r3, lsr #16 ldrb r4, [r0], #1 /* load final byte */ @@ -305,8 +305,8 @@ copy_write_sectors: /* 16-bit aligned */ .w_aligned: tst r0, #2 /* 32 bit aligned? */ - ldrneh r3, [r0], #2 /* no: load first halfword */ - strneh r3, [r2] /* write */ + ldrhne r3, [r0], #2 /* no: load first halfword */ + strhne r3, [r2] /* write */ subne r1, r1, #1 /* one halfword taken */ sub r1, r1, #8 /* adjust for zero-check and doing 8 halfwords/loop */ @@ -341,13 +341,13 @@ copy_write_sectors: tst r1, #2 /* 2 or more halfwords left? */ ldrne r3, [r0], #4 - strneh r3, [r2] + strhne r3, [r2] movne r3, r3, lsr #16 - strneh r3, [r2] + strhne r3, [r2] tst r1, #1 /* one halfword left? */ - ldrneh r3, [r0], #2 - strneh r3, [r2] + ldrhne r3, [r0], #2 + strhne r3, [r2] ldmpc regs=r4-r5 diff --git a/firmware/target/arm/ata-nand-telechips.c b/firmware/target/arm/ata-nand-telechips.c index 55f6b1f3f7..d61c223219 100644 --- a/firmware/target/arm/ata-nand-telechips.c +++ b/firmware/target/arm/ata-nand-telechips.c @@ -915,7 +915,7 @@ int nand_init(void) #ifndef BOOTLOADER /* Use chip info to allocate the correct size LPT buffer */ lptbuf_size = sizeof(struct lpt_entry) * segments_per_bank * total_banks; - lpt_handle = core_alloc("lpt lookup", lptbuf_size); + lpt_handle = core_alloc(lptbuf_size); struct lpt_entry* lpt_lookup = core_get_data(lpt_handle); #else /* Use a static array in the bootloader */ diff --git a/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c index d7ebeea024..22873bfef0 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/system-gigabeat-s.c @@ -199,7 +199,7 @@ void system_exception_wait(void) system_halt(); } -void INIT_ATTR system_init(void) +void system_init(void) { static const enum IMX31_CG_LIST disable_clocks[] INITDATA_ATTR = { diff --git a/firmware/target/arm/imx31/i2c-imx31.c b/firmware/target/arm/imx31/i2c-imx31.c index 972c7d465b..ce5e4cc8f8 100644 --- a/firmware/target/arm/imx31/i2c-imx31.c +++ b/firmware/target/arm/imx31/i2c-imx31.c @@ -367,7 +367,7 @@ int i2c_write(struct i2c_node *node, const unsigned char *data, return -1; } -void INIT_ATTR i2c_init(void) +void i2c_init(void) { /* Do one-time inits for each module that will be used - leave * module disabled and unclocked until something wants it. */ diff --git a/firmware/target/arm/imx31/i2c-imx31.h b/firmware/target/arm/imx31/i2c-imx31.h index b7305931d1..dad5a3da00 100644 --- a/firmware/target/arm/imx31/i2c-imx31.h +++ b/firmware/target/arm/imx31/i2c-imx31.h @@ -76,7 +76,7 @@ struct i2c_sync_transfer_desc }; /* One-time init of i2c driver */ -void i2c_init(void); +void i2c_init(void) INIT_ATTR; /* Enable or disable the node - modules will be switched on/off accordingly. */ void i2c_enable_node(struct i2c_node *node, bool enable); diff --git a/firmware/target/arm/ipod/button-target.h b/firmware/target/arm/ipod/button-target.h index 82f600d302..75bc191608 100644 --- a/firmware/target/arm/ipod/button-target.h +++ b/firmware/target/arm/ipod/button-target.h @@ -47,15 +47,20 @@ void ipod_4g_button_int(void); /* Remote control's buttons */ #ifdef IPOD_ACCESSORY_PROTOCOL +#define BUTTON_RC_DOWN 0x01000000 +#define BUTTON_RC_UP 0x00800000 +#define BUTTON_RC_SELECT 0x00400000 +#define BUTTON_RC_MENU 0x00200000 #define BUTTON_RC_PLAY 0x00100000 #define BUTTON_RC_STOP 0x00080000 - #define BUTTON_RC_LEFT 0x00040000 #define BUTTON_RC_RIGHT 0x00020000 #define BUTTON_RC_VOL_UP 0x00010000 #define BUTTON_RC_VOL_DOWN 0x00008000 -#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\ +#define BUTTON_REMOTE (BUTTON_RC_UP|BUTTON_RC_DOWN \ + |BUTTON_RC_SELECT|BUTTON_RC_PLAY \ + |BUTTON_RC_PLAY|BUTTON_RC_STOP \ |BUTTON_RC_LEFT|BUTTON_RC_RIGHT\ |BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN) #endif diff --git a/firmware/target/arm/ipod/video/lcd-as-video.S b/firmware/target/arm/ipod/video/lcd-as-video.S index 47155b8c75..7d6caef448 100644 --- a/firmware/target/arm/ipod/video/lcd-as-video.S +++ b/firmware/target/arm/ipod/video/lcd-as-video.S @@ -40,24 +40,24 @@ lcd_write_data: /* r1 = pixel count, must be even */ subs r1, r1, #16 .loop16: - ldmgeia r0!, {r2-r3} - stmgeia lr, {r2-r3} - ldmgeia r0!, {r2-r3} - stmgeia lr, {r2-r3} - ldmgeia r0!, {r2-r3} - stmgeia lr, {r2-r3} - ldmgeia r0!, {r2-r3} - stmgeia lr, {r2-r3} - subges r1, r1, #16 + ldmiage r0!, {r2-r3} + stmiage lr, {r2-r3} + ldmiage r0!, {r2-r3} + stmiage lr, {r2-r3} + ldmiage r0!, {r2-r3} + stmiage lr, {r2-r3} + ldmiage r0!, {r2-r3} + stmiage lr, {r2-r3} + subsge r1, r1, #16 bge .loop16 /* no need to correct the count, we're just checking bits from now */ tst r1, #8 - ldmneia r0!, {r2-r4, r12} - stmneia lr, {r2-r4, r12} + ldmiane r0!, {r2-r4, r12} + stmiane lr, {r2-r4, r12} tst r1, #4 - ldmneia r0!, {r2-r3} - stmneia lr, {r2-r3} + ldmiane r0!, {r2-r3} + stmiane lr, {r2-r3} tst r1, #2 ldrne r3, [r0], #4 strne r3, [lr] diff --git a/firmware/target/arm/pcm-telechips.c b/firmware/target/arm/pcm-telechips.c index 336b5626ca..45044bc664 100644 --- a/firmware/target/arm/pcm-telechips.c +++ b/firmware/target/arm/pcm-telechips.c @@ -218,6 +218,7 @@ void fiq_handler(void) * r0-r3 and r12 is a working register. */ asm volatile ( + BEGIN_ARM_ASM_SYNTAX_UNIFIED "sub lr, lr, #4 \n" "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ "mov r14, #0 \n" /* Was the callback called? */ @@ -251,7 +252,7 @@ void fiq_handler(void) "stmia r11, { r8-r9 } \n" /* save p and size */ "cmp r14, #0 \n" /* Callback called? */ - "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */ + "ldmfdeq sp!, { r0-r3, pc }^ \n" /* no? -> exit */ "ldr r1, =pcm_play_status_callback \n" "ldr r1, [r1] \n" @@ -268,11 +269,12 @@ void fiq_handler(void) "mov lr, pc \n" "ldr pc, =pcm_play_dma_complete_callback \n" "cmp r0, #0 \n" /* any more to play? */ - "ldmneia r11, { r8-r9 } \n" /* load new p and size */ + "ldmiane r11, { r8-r9 } \n" /* load new p and size */ "cmpne r9, #0x0f \n" /* did we actually get enough data? */ "bhi .fill_fifo \n" /* not stop and enough? refill */ "ldmfd sp!, { r0-r3, pc }^ \n" /* exit */ ".ltorg \n" + END_ARM_ASM_SYNTAX_UNIFIED : : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED) ); } diff --git a/firmware/target/arm/pp/pcm-pp.c b/firmware/target/arm/pp/pcm-pp.c index 0d61eb44ff..94b1c5ae10 100644 --- a/firmware/target/arm/pp/pcm-pp.c +++ b/firmware/target/arm/pp/pcm-pp.c @@ -327,6 +327,7 @@ void fiq_playback(void) */ asm volatile ( /* No external calls */ + BEGIN_ARM_ASM_SYNTAX_UNIFIED "sub lr, lr, #4 \n" /* Prepare return address */ "stmfd sp!, { lr } \n" /* stack lr so we can use it */ "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux ... */ @@ -349,8 +350,8 @@ void fiq_playback(void) "bhi 0b \n" /* ... yes, continue */ "cmp r9, #0 \n" /* either FIFO full or size empty? */ - "stmneia r11, { r8-r9 } \n" /* save p and size, if not empty */ - "ldmnefd sp!, { pc }^ \n" /* RFE if not empty */ + "stmiane r11, { r8-r9 } \n" /* save p and size, if not empty */ + "ldmfdne sp!, { pc }^ \n" /* RFE if not empty */ /* Making external calls */ "1: \n" @@ -363,7 +364,7 @@ void fiq_playback(void) "mov lr, pc \n" /* long call (not in same section) */ "bx r3 \n" "cmp r0, #0 \n" /* more data? */ - "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */ + "ldmfdeq sp!, { r0-r3, pc }^ \n" /* no? -> exit */ "ldr r14, [r10, #0x1c] \n" /* read IISFIFO_CFG to check FIFO status */ "ands r14, r14, #(0xe<<23) \n" /* r14 = (IIS_TX_FREE_COUNT & ~1) << 23 */ @@ -394,6 +395,7 @@ void fiq_playback(void) "bne 3b \n" /* no? -> go return */ "b 2b \n" /* yes -> get even more */ ".ltorg \n" + END_ARM_ASM_SYNTAX_UNIFIED : /* These must only be integers! No regs */ : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED)); } diff --git a/firmware/target/arm/s3c2440/i2c-s3c2440.h b/firmware/target/arm/s3c2440/i2c-s3c2440.h index 793ee213fd..8b739358af 100644 --- a/firmware/target/arm/s3c2440/i2c-s3c2440.h +++ b/firmware/target/arm/s3c2440/i2c-s3c2440.h @@ -41,6 +41,6 @@ /* IICLC */ #define I2C_FLT_ENB (1 << 2) -void i2c_init(void); +void i2c_init(void) INIT_ATTR; void i2c_write(int addr, const unsigned char *data, int count); diff --git a/firmware/target/arm/s5l8700/ipodnano2g/button-target.h b/firmware/target/arm/s5l8700/ipodnano2g/button-target.h index 82f600d302..75bc191608 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/button-target.h +++ b/firmware/target/arm/s5l8700/ipodnano2g/button-target.h @@ -47,15 +47,20 @@ void ipod_4g_button_int(void); /* Remote control's buttons */ #ifdef IPOD_ACCESSORY_PROTOCOL +#define BUTTON_RC_DOWN 0x01000000 +#define BUTTON_RC_UP 0x00800000 +#define BUTTON_RC_SELECT 0x00400000 +#define BUTTON_RC_MENU 0x00200000 #define BUTTON_RC_PLAY 0x00100000 #define BUTTON_RC_STOP 0x00080000 - #define BUTTON_RC_LEFT 0x00040000 #define BUTTON_RC_RIGHT 0x00020000 #define BUTTON_RC_VOL_UP 0x00010000 #define BUTTON_RC_VOL_DOWN 0x00008000 -#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\ +#define BUTTON_REMOTE (BUTTON_RC_UP|BUTTON_RC_DOWN \ + |BUTTON_RC_SELECT|BUTTON_RC_PLAY \ + |BUTTON_RC_PLAY|BUTTON_RC_STOP \ |BUTTON_RC_LEFT|BUTTON_RC_RIGHT\ |BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN) #endif diff --git a/firmware/target/arm/s5l8702/ipod6g/button-target.h b/firmware/target/arm/s5l8702/ipod6g/button-target.h index ed17fc4baa..a5c4771b7c 100644 --- a/firmware/target/arm/s5l8702/ipod6g/button-target.h +++ b/firmware/target/arm/s5l8702/ipod6g/button-target.h @@ -47,15 +47,20 @@ void ipod_4g_button_int(void); /* Remote control's buttons */ #ifdef IPOD_ACCESSORY_PROTOCOL +#define BUTTON_RC_DOWN 0x01000000 +#define BUTTON_RC_UP 0x00800000 +#define BUTTON_RC_SELECT 0x00400000 +#define BUTTON_RC_MENU 0x00200000 #define BUTTON_RC_PLAY 0x00100000 #define BUTTON_RC_STOP 0x00080000 - #define BUTTON_RC_LEFT 0x00040000 #define BUTTON_RC_RIGHT 0x00020000 #define BUTTON_RC_VOL_UP 0x00010000 #define BUTTON_RC_VOL_DOWN 0x00008000 -#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\ +#define BUTTON_REMOTE (BUTTON_RC_UP|BUTTON_RC_DOWN \ + |BUTTON_RC_SELECT|BUTTON_RC_PLAY \ + |BUTTON_RC_PLAY|BUTTON_RC_STOP \ |BUTTON_RC_LEFT|BUTTON_RC_RIGHT\ |BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN) #endif diff --git a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c index f13904628d..a1985472a0 100644 --- a/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c +++ b/firmware/target/arm/tms320dm320/creative-zvm/ata-creativezvm.c @@ -303,7 +303,7 @@ static void cfs_init(void) _ata_read_sectors(CFS_CLUSTER2CLUSTER(vfat_inodes_nr[1]), 1, §or); inode = (struct cfs_inode*)§or; #ifndef BOOTLOADER - sectors_handle = core_alloc("ata sectors", VFAT_SECTOR_SIZE(inode->filesize)); + sectors_handle = core_alloc(VFAT_SECTOR_SIZE(inode->filesize)); unsigned long *sectors = core_get_data(sectors_handle); #else static unsigned long _sector[VFAT_SECTOR_SIZE(1024*1024*1024)]; /* 1GB guess */ diff --git a/firmware/target/arm/tms320dm320/i2c-dm320.h b/firmware/target/arm/tms320dm320/i2c-dm320.h index 43271692eb..89a8e6f1a4 100644 --- a/firmware/target/arm/tms320dm320/i2c-dm320.h +++ b/firmware/target/arm/tms320dm320/i2c-dm320.h @@ -24,7 +24,7 @@ #include "system.h" -void i2c_init(void); +void i2c_init(void) INIT_ATTR; int i2c_write(unsigned short address, const unsigned char *data, int count); int i2c_read(unsigned short address, unsigned char* buf, int count); diff --git a/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c index d952d3d40d..8620c672e1 100644 --- a/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c +++ b/firmware/target/arm/tms320dm320/mrobe-500/lcd-mr500.c @@ -38,7 +38,7 @@ #if CONFIG_ORIENTATION == SCREEN_PORTRAIT #define LCD_USE_DMA -#elif defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#elif LCD_STRIDEFORMAT == VERTICAL_STRIDE #define LCD_USE_DMA #endif @@ -511,7 +511,7 @@ void lcd_update_rect(int x, int y, int width, int height) #else -#if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE +#if LCD_STRIDEFORMAT == VERTICAL_STRIDE #if defined(LCD_USE_DMA) dma_start_transfer16( (char *)FBADDR(0,0), x, y, LCD_HEIGHT, diff --git a/firmware/target/hosted/filesystem-app.c b/firmware/target/hosted/filesystem-app.c index 2121af7752..09b3365a9e 100644 --- a/firmware/target/hosted/filesystem-app.c +++ b/firmware/target/hosted/filesystem-app.c @@ -43,6 +43,10 @@ #undef PIVOT_ROOT #endif +#if defined(DBTOOL) +#define PIVOT_ROOT "." +#endif + #if defined(__PCTOOL__) /* We don't want this for tools */ #undef HAVE_SPECIAL_DIRS @@ -222,7 +226,7 @@ const char * handle_special_dirs(const char *dir, unsigned flags, #define PIVOT_ROOT_LEN (sizeof(PIVOT_ROOT)-1) /* Prepend root prefix to find actual path */ if (strncmp(PIVOT_ROOT, dir, PIVOT_ROOT_LEN) -#ifdef MULTIDRIVE_DIR +#if defined(MULTIDRIVE_DIR) && defined(MULTIDRIVE_DIR_LEN) /* Unless it's a MULTIDRIVE dir, in which case use as-is */ && strncmp(MULTIDRIVE_DIR, dir, MULTIDRIVE_DIR_LEN) #endif @@ -580,10 +584,11 @@ ssize_t app_readlink(const char *path, char *buf, size_t bufsiz) int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize) { -#ifdef HAVE_MULTIVOLUME +#if defined(HAVE_MULTIVOLUME) && !(CONFIG_PLATFORM & PLATFORM_HOSTED) char volname[VOL_MAX_LEN + 1]; get_volume_name(volume, volname); #else + IF_MV((void)volume;) const char *volname = "/"; #endif @@ -595,3 +600,8 @@ int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize) return 0; } + +const char* app_root_realpath(void) +{ + return PATH_ROOTSTR; +} diff --git a/firmware/target/hosted/sdl/lcd-sdl.c b/firmware/target/hosted/sdl/lcd-sdl.c index de19de365a..8cbb6c5651 100644 --- a/firmware/target/hosted/sdl/lcd-sdl.c +++ b/firmware/target/hosted/sdl/lcd-sdl.c @@ -31,9 +31,9 @@ void sdl_update_rect(SDL_Surface *surface, int x_start, int y_start, int width, unsigned long (*getpixel)(int, int)) { SDL_Rect dest; -#if LCD_DEPTH >= 8 && (LCD_PIXELFORMAT == RGB565) \ - && !defined(LCD_STRIDEFORMAT) && !defined(HAVE_LCD_SPLIT) \ - && !defined(HAVE_REMOTE_LCD) +#if LCD_DEPTH >= 8 && (LCD_PIXELFORMAT == RGB565) && \ + (LCD_STRIDEFORMAT == HORIZONTAL_STRIDE) && \ + !defined(HAVE_LCD_SPLIT) && !defined(HAVE_REMOTE_LCD) SDL_Rect src; (void)max_x; (void)max_y; diff --git a/firmware/target/hosted/sdl/thread-sdl.c b/firmware/target/hosted/sdl/thread-sdl.c index a76941f103..17a0f847b5 100644 --- a/firmware/target/hosted/sdl/thread-sdl.c +++ b/firmware/target/hosted/sdl/thread-sdl.c @@ -215,7 +215,7 @@ void switch_thread(void) } /* STATE_SLEEPING: */ } -#ifdef DEBUG +#ifdef BUFLIB_DEBUG_CHECK_VALID core_check_valid(); #endif __running_self_entry() = current; diff --git a/firmware/target/mips/exception-mips.S b/firmware/target/mips/exception-mips.S new file mode 100644 index 0000000000..605817c7d5 --- /dev/null +++ b/firmware/target/mips/exception-mips.S @@ -0,0 +1,181 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2022 Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "mips.h" + + .text + .set push + .set mips32 + + .section .vectors.1, "ax", %progbits + la k1, tlb_refill_handler + j _exception_enter + + .section .vectors.2, "ax", %progbits + la k1, cache_error_handler + j _exception_enter + + .section .vectors.3, "ax", %progbits + li k1, M_CauseExcCode + mfc0 k0, C0_CAUSE + and k0, k1 + beq zero, k0, 1f + la k1, exception_handler + j _exception_enter +1: + la k1, intr_handler + j _exception_enter + + .section .vectors.4, "ax", %progbits + /* same as above */ + li k1, M_CauseExcCode + mfc0 k0, C0_CAUSE + and k0, k1 + beq zero, k0, 1f + nop + la k1, exception_handler + j _exception_enter +1: + la k1, intr_handler + j _exception_enter + + .set push + .set noat + .set noreorder + .section .vectors, "ax", %progbits + +_exception_enter: + la k0, _irqstackend + addiu k0, -0x84 + + sw $1, 0x00(k0) + sw $2, 0x04(k0) + sw $3, 0x08(k0) + sw $4, 0x0c(k0) + sw $5, 0x10(k0) + sw $6, 0x14(k0) + sw $7, 0x18(k0) + sw $8, 0x1c(k0) + sw $9, 0x20(k0) + sw $10, 0x24(k0) + sw $11, 0x28(k0) + sw $12, 0x2c(k0) + sw $13, 0x30(k0) + sw $14, 0x34(k0) + sw $15, 0x38(k0) + sw $16, 0x3c(k0) + sw $17, 0x40(k0) + sw $18, 0x44(k0) + sw $19, 0x48(k0) + sw $20, 0x4c(k0) + sw $21, 0x50(k0) + sw $22, 0x54(k0) + sw $23, 0x58(k0) + sw $24, 0x5c(k0) + sw $25, 0x60(k0) + sw $28, 0x64(k0) + sw $29, 0x68(k0) + sw $30, 0x6c(k0) + sw $31, 0x70(k0) + + mflo t0 + ssnop + sw t0, 0x74(k0) + + mfhi t0 + ssnop + sw t0, 0x78(k0) + + mfc0 t0, C0_STATUS + ssnop + ssnop + ssnop + sw t0, 0x7c(k0) + + mfc0 a1, C0_EPC + ssnop + ssnop + ssnop + sw a1, 0x80(k0) + + move sp, k0 + + jalr k1 + move a0, sp + +_exception_return: + /* restore all GPRs except sp */ + lw $1, 0x00(sp) + lw $2, 0x04(sp) + lw $3, 0x08(sp) + lw $4, 0x0c(sp) + lw $5, 0x10(sp) + lw $6, 0x14(sp) + lw $7, 0x18(sp) + lw $8, 0x1c(sp) + lw $9, 0x20(sp) + lw $10, 0x24(sp) + lw $11, 0x28(sp) + lw $12, 0x2c(sp) + lw $13, 0x30(sp) + lw $14, 0x34(sp) + lw $15, 0x38(sp) + lw $16, 0x3c(sp) + lw $17, 0x40(sp) + lw $18, 0x44(sp) + lw $19, 0x48(sp) + lw $20, 0x4c(sp) + lw $21, 0x50(sp) + lw $22, 0x54(sp) + lw $23, 0x58(sp) + lw $24, 0x5c(sp) + lw $25, 0x60(sp) + lw $28, 0x64(sp) + lw $30, 0x6c(sp) + lw $31, 0x70(sp) + + lw k0, 0x74(sp) + mtlo k0 + ssnop + + lw k0, 0x78(sp) + mthi k0 + ssnop + + lw k0, 0x7c(sp) + mtc0 k0, C0_STATUS + ssnop + ssnop + ssnop + + lw k0, 0x80(sp) + mtc0 k0, C0_EPC + ssnop + ssnop + ssnop + + /* restore stack pointer last */ + lw sp, 0x68(sp) + eret + ssnop + + .set pop + .set pop diff --git a/firmware/target/mips/ingenic_jz47xx/app.lds b/firmware/target/mips/ingenic_jz47xx/app.lds index 89deb63f89..1d300fed82 100644 --- a/firmware/target/mips/ingenic_jz47xx/app.lds +++ b/firmware/target/mips/ingenic_jz47xx/app.lds @@ -1,9 +1,13 @@ #include "config.h" +#define __ASSEMBLY__ +#include "cpu.h" OUTPUT_FORMAT("elf32-littlemips") OUTPUT_ARCH(MIPS) ENTRY(_start) STARTUP(target/mips/ingenic_jz47xx/crt0.o) +INPUT(target/mips/exception-mips.o) +INPUT(target/mips/system-mips.o) #define STUBOFFSET 0x4000 @@ -18,22 +22,34 @@ STARTUP(target/mips/ingenic_jz47xx/crt0.o) /* Where the codec buffer ends, and the plugin buffer starts */ #define ENDCODECADDR (ENDAUDIOADDR + CODEC_SIZE) +/* Place init code in the codec buffer */ +#define INITBASE ENDAUDIOADDR +#define INITSIZE CODEC_SIZE + MEMORY { DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE + INIT : ORIGIN = INITBASE, LENGTH = INITSIZE } SECTIONS { . = DRAMORIG; - .text : + .startup : { loadaddress = .; _loadaddress = .; - *(.init.text); + *(.startup.text); + } > DRAM + + .text : + { *(.text*); +#ifndef HAVE_INIT_ATTR + *(.init*); +#endif } > DRAM . = ALIGN(4); @@ -75,6 +91,16 @@ SECTIONS } > IRAM _iramcopy = LOADADDR(.iram); +#ifdef HAVE_INIT_ATTR + .init : + { + _initstart = .; + *(.init*); + _initend = .; + } > INIT AT> DRAM + _initcopy = LOADADDR(.init); +#endif + . = ALIGN(4); .stack (NOLOAD): @@ -83,9 +109,9 @@ SECTIONS stackbegin = .; . += 0x1d00; stackend = .; - irqstackbegin = .; + _irqstackbegin = .; . += 0x400; - irqstackend = .; + _irqstackend = .; } > IRAM .bss (NOLOAD): diff --git a/firmware/target/mips/ingenic_jz47xx/boot.lds b/firmware/target/mips/ingenic_jz47xx/boot.lds index b5a3f51c01..b1ea5ddf13 100644 --- a/firmware/target/mips/ingenic_jz47xx/boot.lds +++ b/firmware/target/mips/ingenic_jz47xx/boot.lds @@ -4,6 +4,8 @@ OUTPUT_FORMAT("elf32-littlemips") OUTPUT_ARCH(MIPS) ENTRY(_start) STARTUP(target/mips/ingenic_jz47xx/crt0.o) +INPUT(target/mips/exception-mips.o) +INPUT(target/mips/system-mips.o) #define DRAMSIZE ((MEMORYSIZE-4) * 0x100000) @@ -87,9 +89,9 @@ SECTIONS stackbegin = .; . += 0x1d00; stackend = .; - irqstackbegin = .; + _irqstackbegin = .; . += 0x400; - irqstackend = .; + _irqstackend = .; } > IRAM /DISCARD/ : diff --git a/firmware/target/mips/ingenic_jz47xx/crt0.S b/firmware/target/mips/ingenic_jz47xx/crt0.S index 1652bea8e5..b73a43d8f2 100644 --- a/firmware/target/mips/ingenic_jz47xx/crt0.S +++ b/firmware/target/mips/ingenic_jz47xx/crt0.S @@ -40,11 +40,12 @@ .text - .extern system_main + .extern system_early_init .extern main .global _start - .section .init.text + .section .startup.text,"ax",%progbits + .set push .set mips32 .set noreorder .set noat @@ -138,6 +139,19 @@ _iram_loop: bne t1, t2, _iram_loop sw t3, -4(t1) +#ifdef HAVE_INIT_ATTR + /* Copy init code */ + la t0, _initcopy + la t1, _initstart + la t2, _initend +_init_loop: + lw t3, 0(t0) + addiu t1, 4 + addiu t0, 4 + bne t1, t2, _init_loop + sw t3, -4(t1) +#endif + /* ---------------------------------------------------- Clear BSS section @@ -169,8 +183,8 @@ _stack_loop: Set up interrupt stack ---------------------------------------------------- */ - la k0, irqstackend - la t0, irqstackbegin + la k0, _irqstackend + la t0, _irqstackbegin _irq_stack_loop: addiu t0, 4 @@ -182,167 +196,9 @@ _irq_stack_loop: Jump to C code ---------------------------------------------------- */ - jal system_main /* Init clocks etc first */ + jal system_early_init /* Init clocks etc first */ ssnop j main move ra, zero /* init backtrace root */ - - /* - * 0x0 - Simple TLB refill handler - * 0x100 - Cache error handler - * 0x180 - Exception/Interrupt handler - * 0x200 - Special Exception Interrupt handler (when IV is set in CP0_CAUSE) - */ - - .section .vectors.1, "ax", %progbits - j tlb_refill_handler - ssnop - - .section .vectors.2, "ax", %progbits - j real_exception_handler - ssnop - - .section .vectors.3, "ax", %progbits - j real_exception_handler - ssnop - - .section .vectors.4, "ax", %progbits - j real_exception_handler - ssnop - - .section .vectors, "ax", %progbits -real_exception_handler: - - /* Store stack pointer */ - move k0, sp - /* jump to IRQ stack */ - la sp, irqstackend - - /* Push crap on frame */ - addiu sp, -0x84 - /* store current stack pointer */ - sw k0, 0x80(sp) - - sw ra, 0(sp) - sw fp, 4(sp) - sw gp, 8(sp) - sw t9, 0xC(sp) - sw t8, 0x10(sp) - sw s7, 0x14(sp) - sw s6, 0x18(sp) - sw s5, 0x1C(sp) - sw s4, 0x20(sp) - sw s3, 0x24(sp) - sw s2, 0x28(sp) - sw s1, 0x2C(sp) - sw s0, 0x30(sp) - sw t7, 0x34(sp) - sw t6, 0x38(sp) - sw t5, 0x3C(sp) - sw t4, 0x40(sp) - sw t3, 0x44(sp) - sw t2, 0x48(sp) - sw t1, 0x4C(sp) - sw t0, 0x50(sp) - sw a3, 0x54(sp) - sw a2, 0x58(sp) - sw a1, 0x5C(sp) - sw a0, 0x60(sp) - sw v1, 0x64(sp) - sw v0, 0x68(sp) - sw $1, 0x6C(sp) - mflo k0 - ssnop - sw k0, 0x70(sp) - mfhi k0 - ssnop - sw k0, 0x74(sp) - mfc0 k0, C0_STATUS - ssnop - ssnop - ssnop - sw k0, 0x78(sp) - mfc0 k0, C0_EPC - ssnop - ssnop - ssnop - sw k0, 0x7C(sp) - - li k1, M_CauseExcCode - mfc0 k0, C0_CAUSE - and k0, k1 - beq zero, k0, _int - ssnop - j _exception - ssnop - -_int: - jal intr_handler - ssnop - j _exception_return - -_exception: - move a0, sp - mfc0 a1, C0_CAUSE - ssnop - ssnop - ssnop - mfc0 a2, C0_EPC - ssnop - ssnop - ssnop - jal exception_handler - ssnop - -_exception_return: - lw ra, 0(sp) - lw fp, 4(sp) - lw gp, 8(sp) - lw t9, 0xC(sp) - lw t8, 0x10(sp) - lw s7, 0x14(sp) - lw s6, 0x18(sp) - lw s5, 0x1C(sp) - lw s4, 0x20(sp) - lw s3, 0x24(sp) - lw s2, 0x28(sp) - lw s1, 0x2C(sp) - lw s0, 0x30(sp) - lw t7, 0x34(sp) - lw t6, 0x38(sp) - lw t5, 0x3C(sp) - lw t4, 0x40(sp) - lw t3, 0x44(sp) - lw t2, 0x48(sp) - lw t1, 0x4C(sp) - lw t0, 0x50(sp) - lw a3, 0x54(sp) - lw a2, 0x58(sp) - lw a1, 0x5C(sp) - lw a0, 0x60(sp) - lw v1, 0x64(sp) - lw v0, 0x68(sp) - lw $1, 0x6C(sp) - lw k0, 0x70(sp) - mtlo k0 - ssnop - lw k0, 0x74(sp) - mthi k0 - ssnop - lw k0, 0x78(sp) - mtc0 k0, C0_STATUS - ssnop - ssnop - ssnop - lw k0, 0x7C(sp) - mtc0 k0, C0_EPC - ssnop - ssnop - ssnop - /* Restore previous stack pointer */ - lw sp, 0x80(sp) - eret - ssnop - .set reorder - .set at + .set pop diff --git a/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c b/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c index 65b5e93887..f5624cf469 100644 --- a/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/debug-jz4760.c @@ -537,7 +537,7 @@ static const char* hw_info_menu_get_name(int item, void * data, (void)data; struct tm *cur_time; uint32_t *stackptr; - extern uint32_t irqstackend,irqstackbegin; + extern uint32_t _irqstackend,_irqstackbegin; int btn; #ifdef HAVE_TOUCHSCREEN int touch; @@ -557,10 +557,10 @@ static const char* hw_info_menu_get_name(int item, void * data, read_cp0_15(), (REG_CPM_CLKGR0 & BIT31) >> 31); return buffer; case 2: /*IRQstack*/ - stackptr = &irqstackbegin; - for ( ; stackptr < &irqstackend && *stackptr == 0xDEADBEEF; stackptr++) {} + stackptr = &_irqstackbegin; + for ( ; stackptr < &_irqstackend && *stackptr == 0xDEADBEEF; stackptr++) {} snprintf(buffer, buffer_len, "IRQ stack max: %lu", - (uint32_t)&irqstackend - (uint32_t)stackptr); + (uint32_t)&_irqstackend - (uint32_t)stackptr); return buffer; case 5: /*Touch/BTN*/ #ifdef HAVE_TOUCHSCREEN diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c index fdc335ad21..5aff144327 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c @@ -219,80 +219,6 @@ void intr_handler(void) irqvector[irq-1](); } -#define EXC(x,y) case (x): return (y); -static char* parse_exception(unsigned int cause) -{ - switch(cause & M_CauseExcCode) - { - EXC(EXC_INT, "Interrupt"); - EXC(EXC_MOD, "TLB Modified"); - EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)"); - EXC(EXC_ADEL, "Address Error (Load or Ifetch)"); - EXC(EXC_ADES, "Address Error (Store)"); - EXC(EXC_TLBS, "TLB Exception (Store)"); - EXC(EXC_IBE, "Instruction Bus Error"); - EXC(EXC_DBE, "Data Bus Error"); - EXC(EXC_SYS, "Syscall"); - EXC(EXC_BP, "Breakpoint"); - EXC(EXC_RI, "Reserved Instruction"); - EXC(EXC_CPU, "Coprocessor Unusable"); - EXC(EXC_OV, "Overflow"); - EXC(EXC_TR, "Trap Instruction"); - EXC(EXC_FPE, "Floating Point Exception"); - EXC(EXC_C2E, "COP2 Exception"); - EXC(EXC_MDMX, "MDMX Exception"); - EXC(EXC_WATCH, "Watch Exception"); - EXC(EXC_MCHECK, "Machine Check Exception"); - EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode"); - default: - return NULL; - } -} - -void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc) -{ -#if EXTENDED_EXCEPTION_DESC - (void)epc; - - /* Depends on crt0.S ! */ - char *registers[] = { "ra", "fp", "gp", "t9", "t8", "s7", "s6", "s5", "s4", - "s3", "s2", "s1", "s0", "t7", "t6", "t5", "t4", "t3", - "t2", "t1", "t0", "a3", "a2", "a1", "a0", "v1", "v0", - "$1", "LO", "HI", "STATUS", "EPC" }; - int i; - -#if LCD_DEPTH > 1 - lcd_set_backdrop(NULL); - lcd_set_drawmode(DRMODE_SOLID); - lcd_set_foreground(LCD_BLACK); - lcd_set_background(LCD_WHITE); -#endif - lcd_setfont(FONT_SYSFIXED); - lcd_set_viewport(NULL); - - lcd_clear_display(); - backlight_hw_on(); - - lcd_puts(0, 0, parse_exception(cause)); - lcd_putsf(0, 1, "0x%08x at 0x%08x", read_c0_badvaddr(), epc); - for(i=0; i< 0x80/4; i+=2) - { - unsigned int* ptr = (unsigned int*)(stack_ptr + i*4); - lcd_putsf(0, 3 + i/2, "%s: 0x%08x %s: 0x%08x", registers[i], *ptr, registers[i+1], *(ptr+1)); - } - lcd_update(); - - system_exception_wait(); -#else - panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr); -#endif -} - -void tlb_refill_handler(void) -{ - panicf("TLB refill handler at 0x%08lx! [0x%x]", read_c0_epc(), read_c0_badvaddr()); -} - void udelay(unsigned int usec) { unsigned int i = usec * (__cpm_get_cclk() / 2000000); @@ -508,7 +434,7 @@ static void sdram_init(void) } /* Gets called *before* main */ -void ICODE_ATTR system_main(void) +void ICODE_ATTR system_early_init(void) { int i; diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4760.c b/firmware/target/mips/ingenic_jz47xx/system-jz4760.c index 10973f3e2b..3a1321b992 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/system-jz4760.c @@ -301,46 +301,6 @@ top: goto top; } -#define EXC(x,y) case (x): return (y); -static char* parse_exception(unsigned int cause) -{ - switch(cause & M_CauseExcCode) - { - EXC(EXC_INT, "Interrupt"); - EXC(EXC_MOD, "TLB Modified"); - EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)"); - EXC(EXC_ADEL, "Address Error (Load or Ifetch)"); - EXC(EXC_ADES, "Address Error (Store)"); - EXC(EXC_TLBS, "TLB Exception (Store)"); - EXC(EXC_IBE, "Instruction Bus Error"); - EXC(EXC_DBE, "Data Bus Error"); - EXC(EXC_SYS, "Syscall"); - EXC(EXC_BP, "Breakpoint"); - EXC(EXC_RI, "Reserved Instruction"); - EXC(EXC_CPU, "Coprocessor Unusable"); - EXC(EXC_OV, "Overflow"); - EXC(EXC_TR, "Trap Instruction"); - EXC(EXC_FPE, "Floating Point Exception"); - EXC(EXC_C2E, "COP2 Exception"); - EXC(EXC_MDMX, "MDMX Exception"); - EXC(EXC_WATCH, "Watch Exception"); - EXC(EXC_MCHECK, "Machine Check Exception"); - EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode"); - default: - return NULL; - } -} - -void exception_handler(void* stack_ptr, unsigned int cause, unsigned int epc) -{ - panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", parse_exception(cause), read_c0_badvaddr(), epc, (unsigned int)stack_ptr); -} - -void tlb_refill_handler(void) -{ - panicf("TLB refill handler at 0x%08lx! [0x%x]", read_c0_epc(), read_c0_badvaddr()); -} - #ifdef HW_UDELAY_TIMER /* This enables the HW timer, set to EXT_XTAL / 4 (so @ 12/4 = 3MHz, 1 us = 3 ticks) */ static void init_delaytimer(void) @@ -573,7 +533,7 @@ static void serial_setbrg(void) *uart_lcr = tmp; } -int serial_preinit(void) +static int serial_preinit(void) { volatile u8 *uart_fcr = (volatile u8 *)(CFG_UART_BASE + OFF_FCR); volatile u8 *uart_lcr = (volatile u8 *)(CFG_UART_BASE + OFF_LCR); @@ -609,7 +569,7 @@ int serial_preinit(void) #define cpu_frequency CPU_FREQ #endif -void usb_preinit(void) +static void usb_preinit(void) { /* Clear ECS bit of CPCCR, 0:clock source is EXCLK, 1:clock source is EXCLK/2 */ REG_CPM_CPCCR &= ~CPCCR_ECS; @@ -661,7 +621,7 @@ void usb_preinit(void) udelay(300); } -void dma_preinit(void) +static void dma_preinit(void) { __cpm_start_mdma(); __cpm_start_dmac(); @@ -676,7 +636,7 @@ void dma_preinit(void) } /* Gets called *before* main */ -void ICODE_ATTR system_main(void) +void ICODE_ATTR system_early_init(void) { int i; diff --git a/firmware/target/mips/ingenic_jz47xx/system-target.h b/firmware/target/mips/ingenic_jz47xx/system-target.h index 2725944452..1db0ee4671 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-target.h +++ b/firmware/target/mips/ingenic_jz47xx/system-target.h @@ -27,6 +27,7 @@ #include "config.h" #include "cpu.h" #include "mipsregs.h" +#include "system-mips.h" #define CACHE_SIZE 16*1024 #define CACHEALIGN_BITS 5 diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c index 474d45edee..8ff6d4bc1e 100644 --- a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c @@ -54,16 +54,14 @@ OUT = HOST->DEV, (ie we recv) */ -enum ep_type -{ +enum ep_type { ep_control, ep_bulk, ep_interrupt, ep_isochronous }; -struct usb_endpoint -{ +struct usb_endpoint { const enum ep_type type; const long fifo_addr; unsigned short fifo_size; @@ -76,8 +74,7 @@ struct usb_endpoint volatile void *buf; volatile size_t length; - union - { + union { volatile size_t sent; volatile size_t received; }; @@ -94,8 +91,7 @@ struct usb_endpoint #define short_not_ok 1 /* only works for mass storage.. */ #define ep_doublebuf(__ep) 0 -static union -{ +static union { int buf[64 / sizeof(int)]; struct usb_ctrlrequest request; } ep0_rx; @@ -106,7 +102,7 @@ static volatile bool ep0_data_requested = false; static struct usb_endpoint endpoints[] = { EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL), - EP_INIT(ep_control, USB_FIFO_EP(0), 64, ep0_rx.buf), + EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL), EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL), EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL), EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL), @@ -127,19 +123,14 @@ static void readFIFO(struct usb_endpoint *ep, unsigned int size) register unsigned int s = size >> 2; register unsigned int x; - if(size > 0) - { - if( ((unsigned int)ptr & 3) == 0 ) - { - while(s--) + if(size > 0) { + if (((unsigned int)ptr & 3) == 0) { + while(s--) { *ptr32++ = REG32(ep->fifo_addr); - + } ptr = (unsigned char*)ptr32; - } - else - { - while(s--) - { + } else { + while(s--) { x = REG32(ep->fifo_addr); *ptr++ = x & 0xFF; x >>= 8; *ptr++ = x & 0xFF; x >>= 8; @@ -147,10 +138,10 @@ static void readFIFO(struct usb_endpoint *ep, unsigned int size) *ptr++ = x; } } - s = size & 3; - while(s--) + while(s--) { *ptr++ = REG8(ep->fifo_addr); + } } } @@ -163,18 +154,14 @@ static void writeFIFO(struct usb_endpoint *ep, size_t size) register size_t s = size >> 2; register unsigned int x; - if(size > 0) - { - if( ((unsigned int)d8 & 3) == 0 ) - { - while (s--) + if (size > 0) { + if (((unsigned int)d8 & 3) == 0) { + while (s--) { REG32(ep->fifo_addr) = *d32++; + } d8 = (unsigned char *)d32; - } - else - { - while (s--) - { + } else { + while (s--) { x = (unsigned int)(*d8++) & 0xff; x |= ((unsigned int)(*d8++) & 0xff) << 8; x |= ((unsigned int)(*d8++) & 0xff) << 16; @@ -182,11 +169,9 @@ static void writeFIFO(struct usb_endpoint *ep, size_t size) REG32(ep->fifo_addr) = x; } } - - if( (s = size & 3) ) - { - while (s--) - REG8(ep->fifo_addr) = *d8++; + s = size & 3; + while (s--) { + REG8(ep->fifo_addr) = *d8++; } } } @@ -195,18 +180,17 @@ static void flushFIFO(struct usb_endpoint *ep) { logf("%s(%d)", __func__, EP_NUMBER(ep)); - switch (ep->type) - { - case ep_control: + switch (ep->type) { + case ep_control: break; - - case ep_bulk: - case ep_interrupt: - case ep_isochronous: - if(EP_IS_IN(ep)) - REG_USB_INCSR |= (USB_INCSR_FF | USB_INCSR_CDT); - else - REG_USB_OUTCSR |= (USB_OUTCSR_FF | USB_OUTCSR_CDT); + case ep_bulk: + case ep_interrupt: + case ep_isochronous: + if (EP_IS_IN(ep)) { + REG_USB_INCSR |= (USB_INCSR_FF | USB_INCSR_CDT); + } else { + REG_USB_OUTCSR |= (USB_OUTCSR_FF | USB_OUTCSR_CDT); + } break; } } @@ -217,8 +201,9 @@ static inline void ep_transfer_completed(struct usb_endpoint* ep) ep->length = 0; ep->buf = NULL; ep->busy = false; - if(ep->wait) + if (ep->wait) { semaphore_release(&ep->complete); + } } static void EP0_send(void) @@ -232,27 +217,26 @@ static void EP0_send(void) logf("%s(): 0x%x %d %d", __func__, csr0, ep->sent, ep->length); - if(ep->sent == 0) - { + if (ep->sent == 0) { length = MIN(ep->length, ep->fifo_size); REG_USB_CSR0 = (csr0 | USB_CSR0_FLUSHFIFO); - } - else + } else { length = MIN(EP_BUF_LEFT(ep), ep->fifo_size); + } writeFIFO(ep, length); ep->sent += length; - if(ep->sent >= ep->length) - { + if (ep->sent >= ep->length) { REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY | USB_CSR0_DATAEND); /* Set data end! */ - if (!ep->wait) + if (!ep->wait) { usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, 0, ep->sent); + } ep->rc = 0; ep_transfer_completed(ep); - } - else + } else { REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY); + } } static void EP0_handler(void) @@ -270,8 +254,7 @@ static void EP0_handler(void) /* Check for SentStall: This bit is set when a STALL handshake is transmitted. The CPU should clear this bit. */ - if(csr0 & USB_CSR0_SENTSTALL) - { + if (csr0 & USB_CSR0_SENTSTALL) { REG_USB_CSR0 = csr0 & ~USB_CSR0_SENTSTALL; return; } @@ -281,68 +264,62 @@ static void EP0_handler(void) An interrupt will be generated and the FIFO flushed at this time. The bit is cleared by the CPU writing a 1 to the ServicedSetupEnd bit. */ - if(csr0 & USB_CSR0_SETUPEND) - { + if (csr0 & USB_CSR0_SETUPEND) { csr0 |= USB_CSR0_SVDSETUPEND; REG_USB_CSR0 = csr0; ep0_data_supplied = false; ep0_data_requested = false; - if (ep_send->busy) - { + if (ep_send->busy) { if (!ep_send->wait) usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, -1, 0); ep_transfer_completed(ep_send); } - if (ep_recv->busy) - { + if (ep_recv->busy) { usb_core_transfer_complete(EP_CONTROL, USB_DIR_OUT, -1, 0); ep_transfer_completed(ep_recv); } } /* Call relevant routines for endpoint 0 state */ - if(csr0 & USB_CSR0_OUTPKTRDY) /* There is a packet in the fifo */ - { - if (ep_send->busy) - { - if (!ep_send->wait) + if (csr0 & USB_CSR0_OUTPKTRDY) { /* There is a packet in the fifo */ + if (ep_send->busy) { + if (!ep_send->wait) { usb_core_transfer_complete(EP_CONTROL, USB_DIR_IN, -1, 0); + } ep_transfer_completed(ep_send); } - if (ep_recv->busy && ep_recv->buf && ep_recv->length) - { + if (ep_recv->busy && ep_recv->buf && ep_recv->length) { unsigned int size = REG_USB_COUNT0; readFIFO(ep_recv, size); ep_recv->received += size; - if (size < ep_recv->fifo_size || ep_recv->received >= ep_recv->length) - { + if (size < ep_recv->fifo_size || ep_recv->received >= ep_recv->length) { REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND; /* Set data end! */ usb_core_transfer_complete(EP_CONTROL, USB_DIR_OUT, 0, ep_recv->received); ep_transfer_completed(ep_recv); + } else { + REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */ } - else REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */ - } - else if (!ep0_data_supplied) - { + } else if (!ep0_data_supplied) { ep_recv->buf = ep0_rx.buf; readFIFO(ep_recv, REG_USB_COUNT0); csr0 |= USB_CSR0_SVDOUTPKTRDY; - if (!ep0_rx.request.wLength) - { + if (!ep0_rx.request.wLength) { csr0 |= USB_CSR0_DATAEND; /* Set data end! */ ep0_data_requested = false; ep0_data_supplied = false; - } - else if (ep0_rx.request.bRequestType & USB_DIR_IN) + } else if (ep0_rx.request.bRequestType & USB_DIR_IN) { ep0_data_requested = true; - else ep0_data_supplied = true; + } else { + ep0_data_supplied = true; + } REG_USB_CSR0 = csr0; usb_core_legacy_control_request(&ep0_rx.request); ep_transfer_completed(ep_recv); } } - else if (ep_send->busy) + else if (ep_send->busy) { EP0_send(); + } } /* Does new work */ @@ -429,7 +406,7 @@ static void EPIN_send(unsigned int endpoint) #endif /* Non-DMA code */ - if(ep->sent == 0) + if (ep->sent == 0) length = MIN(ep->length, ep->fifo_size); else length = MIN(EP_BUF_LEFT(ep), ep->fifo_size); @@ -494,7 +471,7 @@ static void EPIN_complete(unsigned int endpoint) logf("EP%d: %d -> %d", endpoint, ep->sent, ep->length); - if(ep->sent >= ep->length) { + if (ep->sent >= ep->length) { if (!ep->wait) usb_core_transfer_complete(endpoint, USB_DIR_IN, 0, ep->sent); ep->rc = 0; @@ -516,9 +493,9 @@ static void EPOUT_handler(unsigned int endpoint) } select_endpoint(endpoint); - while((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) { + while ((csr = REG_USB_OUTCSR) & (USB_OUTCSR_SENTSTALL|USB_OUTCSR_OUTPKTRDY)) { logf("%s(%d): 0x%x", __func__, endpoint, csr); - if(csr & USB_OUTCSR_SENTSTALL) { + if (csr & USB_OUTCSR_SENTSTALL) { logf("stall sent, flushing fifo.."); flushFIFO(ep); REG_USB_OUTCSR = csr & ~USB_OUTCSR_SENTSTALL; @@ -593,7 +570,7 @@ static void EPOUT_handler(unsigned int endpoint) logf("received: %d max length: %d", ep->received, ep->length); - if(size < ep->fifo_size || ep->received >= ep->length) { + if (size < ep->fifo_size || ep->received >= ep->length) { usb_core_transfer_complete(endpoint, USB_DIR_OUT, 0, ep->received); ep_transfer_completed(ep); logf("receive transfer_complete"); @@ -613,8 +590,7 @@ static void EPOUT_ready(unsigned int endpoint) select_endpoint(endpoint); csr = REG_USB_OUTCSR; - if(!ep->busy) - { + if (!ep->busy) { logf("Entered EPOUT handler without work!"); return; } @@ -717,15 +693,15 @@ static void setup_endpoint(struct usb_endpoint *ep) select_endpoint(endpoint); - if (ep->busy) - { - if(EP_IS_IN(ep)) - { + if (ep->busy) { + if (EP_IS_IN(ep)) { if (ep->wait) semaphore_release(&ep->complete); - else usb_core_transfer_complete(endpoint, USB_DIR_IN, -1, 0); + else + usb_core_transfer_complete(endpoint, USB_DIR_IN, -1, 0); + } else { + usb_core_transfer_complete(endpoint, USB_DIR_OUT, -1, 0); } - else usb_core_transfer_complete(endpoint, USB_DIR_OUT, -1, 0); } ep->busy = false; @@ -733,17 +709,16 @@ static void setup_endpoint(struct usb_endpoint *ep) ep->sent = 0; ep->length = 0; - if(ep->type != ep_control) + if (ep->type != ep_control) ep->fifo_size = usb_drv_port_speed() ? 512 : 64; ep->config = REG_USB_CONFIGDATA; - if(EP_IS_IN(ep)) - { + if(EP_IS_IN(ep)) { csr = (USB_INCSR_FF | USB_INCSR_CDT); csrh = USB_INCSRH_MODE; - if(ep->type == ep_interrupt) + if (ep->type == ep_interrupt) csrh |= USB_INCSRH_FRCDATATOG; REG_USB_INMAXP = ep->fifo_size; @@ -754,9 +729,7 @@ static void setup_endpoint(struct usb_endpoint *ep) if (ep->allocated) REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep)); - } - else - { + } else { csr = (USB_OUTCSR_FF | USB_OUTCSR_CDT); csrh = 0; @@ -813,8 +786,7 @@ static void udc_reset(void) endpoints[0].config = REG_USB_CONFIGDATA; endpoints[1].config = REG_USB_CONFIGDATA; - if (endpoints[0].busy) - { + if (endpoints[0].busy) { if (endpoints[0].wait) semaphore_release(&endpoints[0].complete); else @@ -837,7 +809,7 @@ static void udc_reset(void) endpoints[1].allocated = true; /* Reset other endpoints */ - for(i=2; i<TOTAL_EP(); i++) + for (i=2; i<TOTAL_EP(); i++) setup_endpoint(&endpoints[i]); ep0_data_supplied = false; @@ -864,26 +836,26 @@ void OTG(void) logf("IRQ %x %x %x %x", intrUSB, intrIn, intrOut, intrDMA); /* EPIN & EPOUT are all handled in DMA */ - if(intrIn & USB_INTR_EP(0)) + if (intrIn & USB_INTR_EP(0)) EP0_handler(); - if(intrIn & USB_INTR_EP(1)) + if (intrIn & USB_INTR_EP(1)) EPIN_complete(1); - if(intrIn & USB_INTR_EP(2)) + if (intrIn & USB_INTR_EP(2)) EPIN_complete(2); - if(intrOut & USB_INTR_EP(1)) + if (intrOut & USB_INTR_EP(1)) EPOUT_ready(1); - if(intrOut & USB_INTR_EP(2)) + if (intrOut & USB_INTR_EP(2)) EPOUT_ready(2); - if(intrUSB & USB_INTR_RESET) + if (intrUSB & USB_INTR_RESET) udc_reset(); - if(intrUSB & USB_INTR_SUSPEND) + if (intrUSB & USB_INTR_SUSPEND) logf("USB suspend"); - if(intrUSB & USB_INTR_RESUME) + if (intrUSB & USB_INTR_RESUME) logf("USB resume"); #ifdef USE_USB_DMA - if(intrDMA & (1<<USB_INTR_DMA_BULKIN)) + if (intrDMA & (1<<USB_INTR_DMA_BULKIN)) EPDMA_handler(USB_INTR_DMA_BULKIN); - if(intrDMA & (1<<USB_INTR_DMA_BULKOUT)) + if (intrDMA & (1<<USB_INTR_DMA_BULKOUT)) EPDMA_handler(USB_INTR_DMA_BULKOUT); #endif } @@ -896,11 +868,10 @@ bool usb_drv_stalled(int endpoint, bool in) select_endpoint(endpoint); - if(endpoint == EP_CONTROL) + if (endpoint == EP_CONTROL) { return (REG_USB_CSR0 & USB_CSR0_SENDSTALL) != 0; - else - { - if(in) + } else { + if (in) return (REG_USB_INCSR & USB_INCSR_SENDSTALL) != 0; else return (REG_USB_OUTCSR & USB_OUTCSR_SENDSTALL) != 0; @@ -915,24 +886,18 @@ void usb_drv_stall(int endpoint, bool stall, bool in) select_endpoint(endpoint); - if(endpoint == EP_CONTROL) - { + if(endpoint == EP_CONTROL) { if(stall) REG_USB_CSR0 |= USB_CSR0_SENDSTALL; else REG_USB_CSR0 &= ~USB_CSR0_SENDSTALL; - } - else - { - if(in) - { + } else { + if(in) { if(stall) REG_USB_INCSR |= USB_INCSR_SENDSTALL; else REG_USB_INCSR = (REG_USB_INCSR & ~USB_INCSR_SENDSTALL) | USB_INCSR_CDT; - } - else - { + } else { if(stall) REG_USB_OUTCSR |= USB_OUTCSR_SENDSTALL; else @@ -965,7 +930,7 @@ void usb_init_device(void) system_enable_irq(IRQ_OTG); - for(unsigned i=0; i<TOTAL_EP(); i++) + for (unsigned i=0; i<TOTAL_EP(); i++) semaphore_init(&endpoints[i].complete, 1, 0); } @@ -979,7 +944,7 @@ static int usb_oneshot_callback(struct timeout *tmo) * and post appropriate event. */ usb_status_event(state); - if(state == USB_EXTRACTED) + if (state == USB_EXTRACTED) __gpio_as_irq_rise_edge(PIN_USB_DET); else __gpio_as_irq_fall_edge(PIN_USB_DET); @@ -996,7 +961,7 @@ void GPIO_USB_DET(void) void usb_enable(bool on) { - if(on) + if (on) usb_core_init(); else usb_core_exit(); @@ -1070,7 +1035,7 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length ep->sent = 0; ep->length = length; ep->busy = true; - if(blocking) { + if (blocking) { ep->rc = -1; ep->wait = true; } else { @@ -1085,7 +1050,7 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length restore_irq(flags); - if(blocking) { + if (blocking) { semaphore_wait(&ep->complete, HZ); ep->wait = false; } @@ -1097,8 +1062,7 @@ int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); - if (ep->allocated) - { + if (ep->allocated) { usb_drv_send_internal(ep, ptr, length, false); return 0; } @@ -1112,8 +1076,7 @@ int usb_drv_send(int endpoint, void* ptr, int length) logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); - if (ep->allocated) - { + if (ep->allocated) { usb_drv_send_internal(ep, ptr, length, true); return ep->rc; } @@ -1188,7 +1151,8 @@ void usb_drv_cancel_all_transfers(void) { logf("%s()", __func__); - unsigned int i, flags = disable_irq_save(); + unsigned int i; + unsigned int flags = disable_irq_save(); #ifdef USE_USB_DMA /* Disable DMA */ @@ -1204,7 +1168,8 @@ void usb_drv_cancel_all_transfers(void) usb_core_transfer_complete(i >> 1, USB_DIR_OUT, -1, 0); else if (endpoints[i].wait) semaphore_release(&endpoints[i].complete); - else usb_core_transfer_complete(i >> 1, USB_DIR_IN, -1, 0); + else + usb_core_transfer_complete(i >> 1, USB_DIR_IN, -1, 0); } if(i != 1) /* ep0 out needs special handling */ diff --git a/firmware/target/mips/ingenic_x1000/app.lds b/firmware/target/mips/ingenic_x1000/app.lds index 2943329ba7..fe06e1cd8d 100644 --- a/firmware/target/mips/ingenic_x1000/app.lds +++ b/firmware/target/mips/ingenic_x1000/app.lds @@ -5,12 +5,18 @@ OUTPUT_FORMAT("elf32-littlemips") OUTPUT_ARCH(MIPS) ENTRY(_start) STARTUP(target/mips/ingenic_x1000/crt0.o) +INPUT(target/mips/exception-mips.o) +INPUT(target/mips/system-mips.o) #ifdef BOOTLOADER # undef PLUGIN_BUFFER_SIZE # undef CODEC_SIZE # define PLUGIN_BUFFER_SIZE 0 # define CODEC_SIZE 0 +# if defined(HAVE_INIT_ATTR) +/* This needs to be fixed for the bootloader */ +# error "bootloader does not support INIT_ATTR" +# endif #endif /* End of the audio buffer, where the codec buffer starts */ @@ -19,21 +25,33 @@ STARTUP(target/mips/ingenic_x1000/crt0.o) /* Where the codec buffer ends, and the plugin buffer starts */ #define ENDCODECADDR (ENDAUDIOADDR + CODEC_SIZE) +/* Place init code in the codec buffer */ +#define INIT_BASE ENDAUDIOADDR +#define INIT_SIZE CODEC_SIZE + MEMORY { IRAM : ORIGIN = X1000_IRAM_BASE, LENGTH = X1000_IRAM_SIZE DRAM : ORIGIN = X1000_DRAM_BASE, LENGTH = X1000_DRAM_SIZE TCSM : ORIGIN = X1000_TCSM_BASE, LENGTH = X1000_TCSM_SIZE + INIT : ORIGIN = INIT_BASE, LENGTH = INIT_SIZE } SECTIONS { - .text : + .startup : { loadaddress = .; _loadaddress = .; - *(.init.text); + *(.startup.text); + } > DRAM + + .text : + { *(.text*); +#ifndef HAVE_INIT_ATTR + *(.init*); +#endif } > DRAM . = ALIGN(4); @@ -49,7 +67,13 @@ SECTIONS *(.sdata*); } > DRAM - .iram X1000_IRAM_BASE: AT (_bssbegin) + /* + * The following sections are loaded after normal DRAM sections + * but are copied elsewhere by the startup code. + */ + _noloaddram = .; + + .iram : { _iramstart = .; . = 0x000; /* TLB refill */ @@ -66,17 +90,29 @@ SECTIONS *(.irodata); *(.idata); _iramend = .; - } > IRAM + } > IRAM AT> DRAM _iramcopy = LOADADDR(.iram); - .tcsm X1000_TCSM_BASE: AT (_bssbegin + SIZEOF(.iram)) + .tcsm : { _tcsmstart = .; KEEP(*(.tcsm*)); _tcsmend = .; - } > TCSM + } > TCSM AT> DRAM _tcsmcopy = LOADADDR(.tcsm); +#ifdef HAVE_INIT_ATTR + .init : + { + _initstart = .; + *(.init*); + _initend = .; + } > INIT AT> DRAM + _initcopy = LOADADDR(.init); +#endif + + /* Sections below have no data. */ + . = ALIGN(4); .stack (NOLOAD) : { @@ -89,7 +125,7 @@ SECTIONS _irqstackend = .; } > IRAM - .bss (NOLOAD) : + .bss _noloaddram (NOLOAD) : { _bssbegin = .; *(.sbss*); diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.c b/firmware/target/mips/ingenic_x1000/boot-x1000.c index aa97bfcd85..2f2714c67a 100644 --- a/firmware/target/mips/ingenic_x1000/boot-x1000.c +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.c @@ -20,6 +20,7 @@ ****************************************************************************/ #include "system.h" +#include "usb.h" #include "boot-x1000.h" #include "nand-x1000.h" #include "gpio-x1000.h" @@ -113,6 +114,14 @@ void x1000_boot_linux(const void* source, size_t length, { size_t args_len = strlen(args); + /* Shut off USB to avoid "irq 21 nobody cared" error */ + usb_close(); + usb_enable(false); + + /* clear USB PHY voodoo bits, not all kernels use them */ + jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0)); + jz_writef(CPM_USBCDR, PHY_GATE(0)); + disable_irq(); /* --- Beyond this point, do not call into DRAM --- */ @@ -121,7 +130,7 @@ void x1000_boot_linux(const void* source, size_t length, /* copy argument string to a safe location */ char* args_copy = safe_mem + 32; - iram_memmove(args_copy, args, args_len); + iram_memmove(args_copy, args, args_len+1); /* generate argv array */ char** argv = safe_mem; @@ -151,10 +160,6 @@ void x1000_dualboot_cleanup(void) jz_writef(LCD_CTRL, BEDN(0), EOFM(0), SOFM(0), IFUM(0), QDM(0)); jz_writef(CPM_CLKGR, LCD(1)); - /* clear USB PHY voodoo bits, not all kernels use them */ - jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0)); - jz_writef(CPM_USBCDR, PHY_GATE(0)); - #if defined(FIIO_M3K) || defined(EROS_QN) /* * Need to bring up MPLL before booting Linux @@ -262,7 +267,7 @@ void x1000_dualboot_init_uart2(void) int x1000_dualboot_load_pdma_fw(void) { - nand_drv* n = nand_init(); + struct nand_drv* n = nand_init(); nand_lock(n); int ret = nand_open(n); diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.h b/firmware/target/mips/ingenic_x1000/boot-x1000.h index 1b7a0db1e9..eb476c513d 100644 --- a/firmware/target/mips/ingenic_x1000/boot-x1000.h +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.h @@ -36,10 +36,10 @@ enum { }; void x1000_boot_rockbox(const void* source, size_t length) - __attribute__((section(".icode"))); + __attribute__((section(".icode.x1000_boot_rockbox"))); void x1000_boot_linux(const void* source, size_t length, void* load, void* entry, const char* args) - __attribute__((section(".icode"))); + __attribute__((section(".icode.x1000_boot_linux"))); /* dual boot support code */ void x1000_dualboot_cleanup(void); diff --git a/firmware/target/mips/ingenic_x1000/clk-x1000.h b/firmware/target/mips/ingenic_x1000/clk-x1000.h index f7153da564..4b1d4ef838 100644 --- a/firmware/target/mips/ingenic_x1000/clk-x1000.h +++ b/firmware/target/mips/ingenic_x1000/clk-x1000.h @@ -22,8 +22,9 @@ #ifndef __CLK_X1000_H__ #define __CLK_X1000_H__ -#include <stdint.h> +#include "config.h" #include "x1000/cpm.h" +#include <stdint.h> /* Used as arguments to clk_set_ccr_mux() */ #define CLKMUX_SCLK_A(x) jz_orf(CPM_CCR, SEL_SRC_V(x)) @@ -67,17 +68,17 @@ extern uint32_t clk_get(x1000_clk_t clk); extern const char* clk_get_name(x1000_clk_t clk); /* Clock initialization */ -extern void clk_init_early(void); -extern void clk_init(void); +extern void clk_init_early(void) INIT_ATTR; +extern void clk_init(void) INIT_ATTR; /* Sets system clock multiplexers */ -extern void clk_set_ccr_mux(uint32_t muxbits); +extern void clk_set_ccr_mux(uint32_t muxbits) INIT_ATTR; /* Sets system clock dividers */ -extern void clk_set_ccr_div(uint32_t divbits); +extern void clk_set_ccr_div(uint32_t divbits) INIT_ATTR; /* Sets DDR clock source and divider */ -extern void clk_set_ddr(x1000_clk_t src, uint32_t div); +extern void clk_set_ddr(x1000_clk_t src, uint32_t div) INIT_ATTR; /* Returns the smallest n such that infreq/n <= outfreq */ static inline uint32_t clk_calc_div(uint32_t infreq, uint32_t outfreq) diff --git a/firmware/target/mips/ingenic_x1000/crt0.S b/firmware/target/mips/ingenic_x1000/crt0.S index 9d89ac1227..6c0942b0db 100644 --- a/firmware/target/mips/ingenic_x1000/crt0.S +++ b/firmware/target/mips/ingenic_x1000/crt0.S @@ -34,7 +34,7 @@ .set noreorder .set noat - .section .init.text + .section .startup.text,"ax",%progbits _start: b _realstart @@ -55,6 +55,12 @@ _header: #endif _realstart: + /* Save bootloader arguments. */ + move s0, a0 + move s1, a1 + move s2, a2 + move s3, a3 + /* Copy IRAM from BSS to low memory. */ la a0, _iramcopy la a1, _iramstart @@ -69,6 +75,15 @@ _realstart: bal _copy nop +#ifdef HAVE_INIT_ATTR + /* Copy init code */ + la a0, _initcopy + la a1, _initstart + la a2, _initend + bal _copy + nop +#endif + /* Clear the BSS segment (needed to zero-initialize C static values) */ la a0, _bssbegin la a1, _bssend @@ -109,6 +124,13 @@ _realstart: /* Jump to C code */ jal system_early_init nop + + /* Restore bootloader arguments, jump to main. */ + move a0, s0 + move a1, s1 + move a2, s2 + move a3, s3 + j main move ra, zero /* init backtrace root */ @@ -134,138 +156,4 @@ _clear: jr ra nop - /* Exception entry points */ - .section .vectors.1, "ax", %progbits - j tlb_refill_handler - nop - - .section .vectors.2, "ax", %progbits - j real_exception_handler - nop - - .section .vectors.3, "ax", %progbits - j real_exception_handler - nop - - .section .vectors.4, "ax", %progbits - j real_exception_handler - nop - - .section .vectors, "ax", %progbits -real_exception_handler: - move k0, sp - la sp, _irqstackend - addiu sp, -0x84 - sw k0, 0x80(sp) - sw ra, 0x00(sp) - sw fp, 0x04(sp) - sw gp, 0x08(sp) - sw t9, 0x0c(sp) - sw t8, 0x10(sp) - sw s7, 0x14(sp) - sw s6, 0x18(sp) - sw s5, 0x1c(sp) - sw s4, 0x20(sp) - sw s3, 0x24(sp) - sw s2, 0x28(sp) - sw s1, 0x2c(sp) - sw s0, 0x30(sp) - sw t7, 0x34(sp) - sw t6, 0x38(sp) - sw t5, 0x3c(sp) - sw t4, 0x40(sp) - sw t3, 0x44(sp) - sw t2, 0x48(sp) - sw t1, 0x4c(sp) - sw t0, 0x50(sp) - sw a3, 0x54(sp) - sw a2, 0x58(sp) - sw a1, 0x5c(sp) - sw a0, 0x60(sp) - sw v1, 0x64(sp) - sw v0, 0x68(sp) - sw $1, 0x6c(sp) - mflo k0 - nop - sw k0, 0x70(sp) - mfhi k0 - nop - sw k0, 0x74(sp) - mfc0 k0, C0_STATUS - nop - nop - nop - sw k0, 0x78(sp) - mfc0 k0, C0_EPC - nop - nop - nop - sw k0, 0x7c(sp) - - li k1, M_CauseExcCode - mfc0 a0, C0_CAUSE - and k0, a0, k1 - bnez k0, _exception - nop - jal intr_handler - nop - j _exception_return - -_exception: - mfc0 a1, C0_EPC - nop - nop - nop - jal exception_handler - move a2, sp - -_exception_return: - lw ra, 0x00(sp) - lw fp, 0x04(sp) - lw gp, 0x08(sp) - lw t9, 0x0c(sp) - lw t8, 0x10(sp) - lw s7, 0x14(sp) - lw s6, 0x18(sp) - lw s5, 0x1c(sp) - lw s4, 0x20(sp) - lw s3, 0x24(sp) - lw s2, 0x28(sp) - lw s1, 0x2c(sp) - lw s0, 0x30(sp) - lw t7, 0x34(sp) - lw t6, 0x38(sp) - lw t5, 0x3c(sp) - lw t4, 0x40(sp) - lw t3, 0x44(sp) - lw t2, 0x48(sp) - lw t1, 0x4c(sp) - lw t0, 0x50(sp) - lw a3, 0x54(sp) - lw a2, 0x58(sp) - lw a1, 0x5c(sp) - lw a0, 0x60(sp) - lw v1, 0x64(sp) - lw v0, 0x68(sp) - lw $1, 0x6c(sp) - lw k0, 0x70(sp) - mtlo k0 - nop - lw k0, 0x74(sp) - mthi k0 - nop - lw k0, 0x78(sp) - mtc0 k0, C0_STATUS - nop - nop - nop - lw k0, 0x7c(sp) - mtc0 k0, C0_EPC - nop - nop - nop - lw sp, 0x80(sp) - eret - nop - .set pop diff --git a/firmware/target/mips/ingenic_x1000/debug-x1000.c b/firmware/target/mips/ingenic_x1000/debug-x1000.c index 236442a880..827bb37855 100644 --- a/firmware/target/mips/ingenic_x1000/debug-x1000.c +++ b/firmware/target/mips/ingenic_x1000/debug-x1000.c @@ -121,6 +121,9 @@ extern volatile unsigned aic_tx_underruns; #ifdef HAVE_RECORDING extern volatile unsigned aic_rx_overruns; #endif +#ifdef HAVE_EROS_QN_CODEC +extern int es9018k2m_present_flag; +#endif static bool dbg_audio(void) { @@ -130,6 +133,16 @@ static bool dbg_audio(void) #ifdef HAVE_RECORDING lcd_putsf(0, 1, "RX overruns: %u", aic_rx_overruns); #endif +#ifdef HAVE_EROS_QN_CODEC + if (es9018k2m_present_flag) + { + lcd_putsf(0, 2, "(%d) ES9018K2M HWVOL", es9018k2m_present_flag); + } + else + { + lcd_putsf(0, 2, "(%d) SWVOL", es9018k2m_present_flag); + } +#endif lcd_update(); } while(get_action(CONTEXT_STD, HZ) != ACTION_STD_CANCEL); diff --git a/firmware/target/mips/ingenic_x1000/dma-x1000.h b/firmware/target/mips/ingenic_x1000/dma-x1000.h index 8bb5f1ddaa..4a526cec02 100644 --- a/firmware/target/mips/ingenic_x1000/dma-x1000.h +++ b/firmware/target/mips/ingenic_x1000/dma-x1000.h @@ -64,7 +64,7 @@ typedef struct dma_desc dma_desc; typedef void(*dma_cb_func)(int event); -extern void dma_init(void); +extern void dma_init(void) INIT_ATTR; extern void dma_set_callback(int chn, dma_cb_func cb); #endif /* __DMA_X1000_H__ */ diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c index b32a32a3a3..df97aba0c8 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c +++ b/firmware/target/mips/ingenic_x1000/erosqnative/audiohw-erosqnative.c @@ -19,28 +19,36 @@ * ****************************************************************************/ -#include "audiohw.h" #include "system.h" +#include "audiohw.h" +#include "pcm_sw_volume.h" #include "pcm_sampr.h" +#include "i2c-target.h" +#include "button.h" + +// #define LOGF_ENABLE +#include "logf.h" + #include "aic-x1000.h" #include "i2c-x1000.h" #include "gpio-x1000.h" -#include "logf.h" -/* Audio path appears to be: - * DAC --> HP Amp --> Stereo Switch --> HP OUT - * \--> LO OUT +/* + * Earlier devices audio path appears to be: + * DAC \--> HP Amp --> Stereo Switch --> HP OUT + * \-> LO OUT * - * The real purpose of the Stereo Switch is not clear. - * It appears to switch sources between the HP amp and something, - * likely something unimplemented. */ + * Recent devices, the audio path seems to have changed to: + * DAC --> HP Amp --> Stereo Switch \--> HP OUT + * \-> LO OUT + */ void audiohw_init(void) { /* explicitly mute everything */ - gpio_set_level(GPIO_MAX97220_SHDN, 0); - gpio_set_level(GPIO_ISL54405_MUTE, 1); - gpio_set_level(GPIO_PCM5102A_XMIT, 0); + gpio_set_level(GPIO_HPAMP_SHDN, 0); + gpio_set_level(GPIO_STEREOSW_MUTE, 1); + gpio_set_level(GPIO_DAC_PWR, 0); aic_set_play_last_sample(true); aic_set_external_codec(true); @@ -53,8 +61,8 @@ void audiohw_init(void) mdelay(10); /* power on DAC and HP Amp */ - gpio_set_level(GPIO_PCM5102A_ANALOG_PWR, 1); - gpio_set_level(GPIO_MAX97220_POWER, 1); + gpio_set_level(GPIO_DAC_ANALOG_PWR, 1); + gpio_set_level(GPIO_HPAMP_POWER, 1); } void audiohw_postinit(void) @@ -76,23 +84,39 @@ void audiohw_postinit(void) jz_writef(AIC_CCR, ERPL(0)); /* unmute - attempt to make power-on pop-free */ - gpio_set_level(GPIO_ISL54405_SEL, 0); - gpio_set_level(GPIO_MAX97220_SHDN, 1); + gpio_set_level(GPIO_STEREOSW_SEL, 0); + gpio_set_level(GPIO_HPAMP_SHDN, 1); mdelay(10); - gpio_set_level(GPIO_PCM5102A_XMIT, 1); + gpio_set_level(GPIO_DAC_PWR, 1); mdelay(10); - gpio_set_level(GPIO_ISL54405_MUTE, 0); + gpio_set_level(GPIO_STEREOSW_MUTE, 0); + + i2c_x1000_set_freq(ES9018K2M_BUS, I2C_FREQ_400K); + + int ret = es9018k2m_read_reg(ES9018K2M_REG0_SYSTEM_SETTINGS); + if (ret >= 0) /* Detected ES9018K2M DAC */ + { + logf("ES9018K2M found: ret=%d", ret); + es9018k2m_present_flag = 1; + + /* Default is 32-bit data, and it works ok. Enabling the following + * causes issue. Which is weird, I definitely thought AIC was configured + * for 24-bit data... */ + // es9018k2m_write_reg(ES9018K2M_REG1_INPUT_CONFIG, 0b01001100); // 24-bit data + + } else { /* Default to SWVOL for PCM5102A DAC */ + logf("Default to SWVOL: ret=%d", ret); + } } -/* TODO: get shutdown just right according to dac datasheet */ void audiohw_close(void) { /* mute - attempt to make power-off pop-free */ - gpio_set_level(GPIO_ISL54405_MUTE, 1); + gpio_set_level(GPIO_STEREOSW_MUTE, 1); mdelay(10); - gpio_set_level(GPIO_PCM5102A_XMIT, 0); + gpio_set_level(GPIO_DAC_PWR, 0); mdelay(10); - gpio_set_level(GPIO_MAX97220_SHDN, 0); + gpio_set_level(GPIO_HPAMP_SHDN, 0); } void audiohw_set_frequency(int fsel) @@ -105,3 +129,54 @@ void audiohw_set_frequency(int fsel) aic_enable_i2s_bit_clock(true); } +void audiohw_set_volume(int vol_l, int vol_r) +{ + int l, r; + + eros_qn_set_last_vol(vol_l, vol_r); + + l = vol_l; + r = vol_r; + +#if (defined(HAVE_HEADPHONE_DETECTION) && defined(HAVE_LINEOUT_DETECTION)) + /* make sure headphones aren't present - don't want to + * blow out our eardrums cranking it to full */ + if (lineout_inserted() && !headphones_inserted()) + { + eros_qn_switch_output(1); + + l = r = eros_qn_get_volume_limit(); + } + else + { + eros_qn_switch_output(0); + } +#endif + + if (es9018k2m_present_flag) /* ES9018K2M */ + { + /* Same volume range and mute point for both DACs, so use PCM5102A_VOLUME_MIN */ + l = l <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : l; + r = r <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : r; + + /* set software volume just below unity due to + * DAC offset. We don't want to overflow the PCM system. */ + pcm_set_master_volume(-1, -1); + es9018k2m_set_volume_async(l, r); + } + else /* PCM5102A */ + { + l = l <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : (l / 20); + r = r <= PCM5102A_VOLUME_MIN ? PCM_MUTE_LEVEL : (r / 20); + + pcm_set_master_volume(l, r); + } +} + +void audiohw_set_filter_roll_off(int value) +{ + if (es9018k2m_present_flag) + { + es9018k2m_set_filter_roll_off(value); + } +}
\ No newline at end of file diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c index 1583db175a..0d2207af2a 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c +++ b/firmware/target/mips/ingenic_x1000/erosqnative/button-erosqnative.c @@ -127,7 +127,7 @@ bool headphones_inserted(void) { hp_detect_reg_old = hp_detect_reg; #if !defined(BOOTLOADER) - pcm5102_set_outputs(); + eros_qn_set_outputs(); #endif } return hp_detect_reg & 0x10 ? false : true; @@ -140,7 +140,7 @@ bool lineout_inserted(void) { hp_detect_reg_old = hp_detect_reg; #if !defined(BOOTLOADER) - pcm5102_set_outputs(); + eros_qn_set_outputs(); #endif } return hp_detect_reg & 0x20 ? false : true; @@ -233,6 +233,8 @@ int button_read_device(void) * Rockbox treats these buttons differently. */ queue_post(&button_queue, BUTTON_SCROLL_FWD, 0); enc_position = 0; + reset_poweroff_timer(); + backlight_on(); } else if (enc_position < -1) { @@ -240,6 +242,8 @@ int button_read_device(void) * Rockbox treats these buttons differently. */ queue_post(&button_queue, BUTTON_SCROLL_BACK, 0); enc_position = 0; + reset_poweroff_timer(); + backlight_on(); } return r; diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h b/firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h index 376eae136e..72052c261f 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h +++ b/firmware/target/mips/ingenic_x1000/erosqnative/gpio-target.h @@ -15,35 +15,39 @@ /* ---------------------------------------------- */ + /* Name Port Pins Function */ DEFINE_PINGROUP(LCD_DATA, GPIO_A, 0xffff << 0, GPIOF_DEVICE(1)) DEFINE_PINGROUP(LCD_CONTROL, GPIO_B, 0x1a << 16, GPIOF_DEVICE(1)) DEFINE_PINGROUP(MSC0, GPIO_A, 0x3f << 20, GPIOF_DEVICE(1)) DEFINE_PINGROUP(SFC, GPIO_A, 0x3f << 26, GPIOF_DEVICE(1)) DEFINE_PINGROUP(I2S, GPIO_B, 0x1f << 0, GPIOF_DEVICE(1)) +DEFINE_PINGROUP(I2C1, GPIO_C, 3 << 26, GPIOF_DEVICE(0)) DEFINE_PINGROUP(I2C2, GPIO_D, 3 << 0, GPIOF_DEVICE(1)) /* Name Pin Function */ -/* mute DAC - 0 - mute, 1 - play. Affects both HP and LO. */ -DEFINE_GPIO(PCM5102A_XMIT, GPIO_PB(12), GPIOF_OUTPUT(0)) +/* mute DAC: 0 - mute, 1 - play */ +/* Note: This seems to actually be power to the DAC in general, + * at least on the ES9018K2M devices. Was "DAC_XMIT". */ +DEFINE_GPIO(DAC_PWR, GPIO_PB(12), GPIOF_OUTPUT(0)) -/* mute HP amp, no effect on LO. 0 - mute, 1 - play */ -DEFINE_GPIO(MAX97220_SHDN, GPIO_PB(8), GPIOF_OUTPUT(0)) +/* mute HP amp: 0 - mute, 1 - play */ +DEFINE_GPIO(HPAMP_SHDN, GPIO_PB(8), GPIOF_OUTPUT(0)) -/* mute audio mux, only affects Headphone out. - * 0 - play, 1 - mute */ -DEFINE_GPIO(ISL54405_MUTE, GPIO_PB(15), GPIOF_OUTPUT(1)) +/* mute audio mux: 0 - play, 1 - mute */ +DEFINE_GPIO(STEREOSW_MUTE, GPIO_PB(15), GPIOF_OUTPUT(1)) -/* switches HP on/off - 0 HP on, 1 hp off, has no effect on LO. - * As best I can tell, it switches HP Out sources between HP amp and something - * not implemented - there seem to be resistors missing. */ -DEFINE_GPIO(ISL54405_SEL, GPIO_PB(5), GPIOF_OUTPUT(0)) +/* + * Original devices: switches HP on/off - 0 HP on, 1 HP off, no effect on LO. + * Newer devices: switches between HP and LO - 0 HP, 1 LO. + */ +DEFINE_GPIO(STEREOSW_SEL, GPIO_PB(5), GPIOF_OUTPUT(0)) /* DAC AVDD */ -DEFINE_GPIO(PCM5102A_ANALOG_PWR, GPIO_PB(9), GPIOF_OUTPUT(0)) +DEFINE_GPIO(DAC_ANALOG_PWR, GPIO_PB(9), GPIOF_OUTPUT(0)) /* Headphone Amp power */ -DEFINE_GPIO(MAX97220_POWER, GPIO_PB(6), GPIOF_OUTPUT(0)) +DEFINE_GPIO(HPAMP_POWER, GPIO_PB(6), GPIOF_OUTPUT(0)) /* SD card */ DEFINE_GPIO(MSC0_CD, GPIO_PB(11), GPIOF_INPUT) diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h b/firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h index 8d0b8a6e20..89d995f33a 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h +++ b/firmware/target/mips/ingenic_x1000/erosqnative/i2c-target.h @@ -25,6 +25,9 @@ #define I2C_ASYNC_BUS_COUNT 3 #define I2C_ASYNC_QUEUE_SIZE 4 +#define ES9018K2M_BUS 1 +#define ES9018K2M_ADDR 0x48 + #define AXP_PMU_BUS 2 #define AXP_PMU_ADDR 0x34 diff --git a/firmware/target/mips/ingenic_x1000/gpio-x1000.c b/firmware/target/mips/ingenic_x1000/gpio-x1000.c index 14195359df..0ebe424566 100644 --- a/firmware/target/mips/ingenic_x1000/gpio-x1000.c +++ b/firmware/target/mips/ingenic_x1000/gpio-x1000.c @@ -21,7 +21,7 @@ #include "gpio-x1000.h" -const struct gpio_setting gpio_settings[PIN_COUNT] = { +static const struct gpio_setting gpio_settings[PIN_COUNT] INITDATA_ATTR = { #define DEFINE_GPIO(_name, _gpio, _func) \ {.gpio = _gpio, .func = _func}, #define DEFINE_PINGROUP(...) @@ -30,7 +30,7 @@ const struct gpio_setting gpio_settings[PIN_COUNT] = { #undef DEFINE_PINGROUP }; -const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] = { +static const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] INITDATA_ATTR = { #define DEFINE_GPIO(...) #define DEFINE_PINGROUP(_name, _port, _pins, _func) \ {.port = _port, .pins = _pins, .func = _func}, @@ -39,7 +39,8 @@ const struct pingroup_setting pingroup_settings[PINGROUP_COUNT] = { #undef DEFINE_PINGROUP }; -const char* const gpio_names[PIN_COUNT] = { +#if 0 /* not needed for the time being */ +static const char* const gpio_names[PIN_COUNT] = { #define DEFINE_GPIO(_name, ...) #_name, #define DEFINE_PINGROUP(...) #include "gpio-target.h" @@ -47,13 +48,14 @@ const char* const gpio_names[PIN_COUNT] = { #undef DEFINE_PINGROUP }; -const char* const pingroup_names[PINGROUP_COUNT] = { +static const char* const pingroup_names[PINGROUP_COUNT] = { #define DEFINE_GPIO(...) #define DEFINE_PINGROUP(_name, ...) #_name, #include "gpio-target.h" #undef DEFINE_GPIO #undef DEFINE_PINGROUP }; +#endif void gpio_init(void) { diff --git a/firmware/target/mips/ingenic_x1000/gpio-x1000.h b/firmware/target/mips/ingenic_x1000/gpio-x1000.h index eac5f8651f..310a457ab5 100644 --- a/firmware/target/mips/ingenic_x1000/gpio-x1000.h +++ b/firmware/target/mips/ingenic_x1000/gpio-x1000.h @@ -23,6 +23,7 @@ #define __GPIO_X1000_H__ #include "x1000/gpio.h" +#include "config.h" /* GPIO port numbers */ #define GPIO_A 0 @@ -103,16 +104,8 @@ enum { PINGROUP_COUNT, }; -/* arrays which define the target's GPIO settings */ -extern const struct gpio_setting gpio_settings[PIN_COUNT]; -extern const struct pingroup_setting pingroup_settings[PINGROUP_COUNT]; - -/* stringified names for use in debug menus */ -extern const char* const gpio_names[PIN_COUNT]; -extern const char* const pingroup_names[PINGROUP_COUNT]; - /* called at early init to set up GPIOs */ -extern void gpio_init(void); +extern void gpio_init(void) INIT_ATTR; /* Use GPIO Z to reconfigure several pins atomically */ extern void gpioz_configure(int port, uint32_t pins, int func); diff --git a/firmware/target/mips/ingenic_x1000/i2c-x1000.h b/firmware/target/mips/ingenic_x1000/i2c-x1000.h index e76624d511..9b9ba5e088 100644 --- a/firmware/target/mips/ingenic_x1000/i2c-x1000.h +++ b/firmware/target/mips/ingenic_x1000/i2c-x1000.h @@ -27,7 +27,7 @@ #define I2C_FREQ_100K 100000 #define I2C_FREQ_400K 400000 -extern void i2c_init(void); +extern void i2c_init(void) INIT_ATTR; /* Configure the I2C controller prior to use. * diff --git a/firmware/target/mips/ingenic_x1000/installer-x1000.c b/firmware/target/mips/ingenic_x1000/installer-x1000.c index 66aa42d4a1..d2f9e4e5e0 100644 --- a/firmware/target/mips/ingenic_x1000/installer-x1000.c +++ b/firmware/target/mips/ingenic_x1000/installer-x1000.c @@ -62,10 +62,13 @@ static const struct update_part updates[] = { static const int num_updates = sizeof(updates) / sizeof(struct update_part); +static const uint8_t flash_sig_magic[8] = + {0x06, 0x05, 0x04, 0x03, 0x02, 0x55, 0xaa, 0x55}; + /* calculate the offset and length of the update image; this is constant * for a given target, based on the update parts and the NAND chip geometry. */ -static void get_image_loc(nand_drv* ndrv, size_t* offptr, size_t* lenptr) +static void get_image_loc(struct nand_drv* ndrv, size_t* offptr, size_t* lenptr) { size_t blk_size = ndrv->chip->page_size << ndrv->chip->log2_ppb; size_t img_off = 0; @@ -119,7 +122,7 @@ struct updater { size_t img_len; /* image length in flash = size of the buffer */ mtar_t* tar; - nand_drv* ndrv; + struct nand_drv* ndrv; }; static int updater_init(struct updater* u) @@ -148,7 +151,7 @@ static int updater_init(struct updater* u) /* buf_len is a bit oversized here, but it's not really important */ u->buf_len = u->img_len + sizeof(mtar_t) + 2*CACHEALIGN_SIZE; - u->buf_hnd = core_alloc_ex("boot_image", u->buf_len, &buflib_ops_locked); + u->buf_hnd = core_alloc_ex(u->buf_len, &buflib_ops_locked); if(u->buf_hnd < 0) { rc = IERR_OUT_OF_MEMORY; goto error; @@ -178,8 +181,7 @@ static void updater_cleanup(struct updater* u) if(u->tar && mtar_is_open(u->tar)) mtar_close(u->tar); - if(u->buf_hnd >= 0) - core_free(u->buf_hnd); + core_free(u->buf_hnd); if(u->ndrv) { nand_close(u->ndrv); @@ -250,6 +252,12 @@ int backup_bootloader(const char* filename) goto error; } + /* bail if we're backing up something that looks like garbage */ + if (memcmp(u.img_buf, flash_sig_magic, 8)) { + rc = IERR_CORRUPTED_BACKUP; + goto error; + } + /* write to file */ fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY); if(fd < 0) { @@ -294,6 +302,12 @@ int restore_bootloader(const char* filename) goto error; } + /* safety check to reduce risk of flashing complete garbage */ + if (memcmp(u.img_buf, flash_sig_magic, 8)) { + rc = IERR_CORRUPTED_BACKUP; + goto error; + } + /* write image */ rc = nand_write_bytes(u.ndrv, u.img_off, u.img_len, u.img_buf); if(rc != NAND_SUCCESS) { @@ -321,6 +335,7 @@ const char* installer_strerror(int rc) case IERR_NAND_OPEN: return "NAND open error"; case IERR_NAND_READ: return "NAND read error"; case IERR_NAND_WRITE: return "NAND write error"; + case IERR_CORRUPTED_BACKUP: return "Backup is corrupt"; default: return "Unknown error!?"; } } diff --git a/firmware/target/mips/ingenic_x1000/installer-x1000.h b/firmware/target/mips/ingenic_x1000/installer-x1000.h index b71839a907..9b0f1e4bd6 100644 --- a/firmware/target/mips/ingenic_x1000/installer-x1000.h +++ b/firmware/target/mips/ingenic_x1000/installer-x1000.h @@ -45,6 +45,7 @@ enum { IERR_NAND_OPEN, IERR_NAND_READ, IERR_NAND_WRITE, + IERR_CORRUPTED_BACKUP, }; extern int install_bootloader(const char* filename); diff --git a/firmware/target/mips/ingenic_x1000/lcd-x1000.c b/firmware/target/mips/ingenic_x1000/lcd-x1000.c index b66359a598..979febf066 100644 --- a/firmware/target/mips/ingenic_x1000/lcd-x1000.c +++ b/firmware/target/mips/ingenic_x1000/lcd-x1000.c @@ -428,7 +428,10 @@ void lcd_enable(bool en) /* Handle turning the LCD back on */ if(!bit && en) + { + send_event(LCD_EVENT_ACTIVATION, NULL); lcd_dma_start(); + } } #endif diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c index 5838b21b39..af0f972eae 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c @@ -22,76 +22,98 @@ #include "nand-x1000.h" #include "sfc-x1000.h" #include "system.h" +#include "logf.h" #include <string.h> -/* cmd mode a d phase format has data */ -#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) -#define NANDCMD_READID(x,y) SFC_CMD(0x9f, SFC_TMODE_1_1_1, x, y, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_WR_EN SFC_CMD(0x06, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) -#define NANDCMD_GET_FEATURE SFC_CMD(0x0f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_SET_FEATURE SFC_CMD(0x1f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_PAGE_READ(x) SFC_CMD(0x13, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0) -#define NANDCMD_READ_CACHE(x) SFC_CMD(0x0b, SFC_TMODE_1_1_1, x, 8, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_READ_CACHE_x4(x) SFC_CMD(0x6b, SFC_TMODE_1_1_4, x, 8, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_PROGRAM_LOAD(x) SFC_CMD(0x02, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_PROGRAM_LOAD_x4(x) SFC_CMD(0x32, SFC_TMODE_1_1_4, x, 0, SFC_PFMT_ADDR_FIRST, 1) -#define NANDCMD_PROGRAM_EXECUTE(x) SFC_CMD(0x10, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0) -#define NANDCMD_BLOCK_ERASE(x) SFC_CMD(0xd8, SFC_TMODE_1_1_1, x, 0, SFC_PFMT_ADDR_FIRST, 0) - -/* Feature registers are found in linux/mtd/spinand.h, - * apparently these are pretty standardized */ -#define FREG_PROT 0xa0 -#define FREG_PROT_UNLOCK 0x00 - -#define FREG_CFG 0xb0 -#define FREG_CFG_OTP_ENABLE (1 << 6) -#define FREG_CFG_ECC_ENABLE (1 << 4) -#define FREG_CFG_QUAD_ENABLE (1 << 0) - -#define FREG_STATUS 0xc0 -#define FREG_STATUS_BUSY (1 << 0) -#define FREG_STATUS_EFAIL (1 << 2) -#define FREG_STATUS_PFAIL (1 << 3) -#define FREG_STATUS_ECC_MASK (3 << 4) -#define FREG_STATUS_ECC_NO_FLIPS (0 << 4) -#define FREG_STATUS_ECC_HAS_FLIPS (1 << 4) -#define FREG_STATUS_ECC_UNCOR_ERR (2 << 4) - -const nand_chip supported_nand_chips[] = { -#if defined(FIIO_M3K) || defined(SHANLING_Q1) || defined(EROS_QN) - { - /* ATO25D1GA */ - .mf_id = 0x9b, - .dev_id = 0x12, - .row_cycles = 3, - .col_cycles = 2, - .log2_ppb = 6, /* 64 pages */ - .page_size = 2048, - .oob_size = 64, - .nr_blocks = 1024, - .bbm_pos = 2048, - .clock_freq = 150000000, - .dev_conf = jz_orf(SFC_DEV_CONF, - CE_DL(1), HOLD_DL(1), WP_DL(1), - CPHA(0), CPOL(0), - TSH(7), TSETUP(0), THOLD(0), - STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), - SMP_DELAY(1)), - .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT, - }, -#else - { 0 }, -#endif +static void winbond_setup_chip(struct nand_drv* drv); + +static const struct nand_chip chip_ato25d1ga = { + .log2_ppb = 6, /* 64 pages */ + .page_size = 2048, + .oob_size = 64, + .nr_blocks = 1024, + .bbm_pos = 2048, + .clock_freq = 150000000, + .dev_conf = jz_orf(SFC_DEV_CONF, + CE_DL(1), HOLD_DL(1), WP_DL(1), + CPHA(0), CPOL(0), + TSH(7), TSETUP(0), THOLD(0), + STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), + SMP_DELAY(1)), + .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT, + .cmd_page_read = NANDCMD_PAGE_READ, + .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE, + .cmd_block_erase = NANDCMD_BLOCK_ERASE, + .cmd_read_cache = NANDCMD_READ_CACHE_x4, + .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4, }; -const size_t nr_supported_nand_chips = - sizeof(supported_nand_chips) / sizeof(nand_chip); +static const struct nand_chip chip_w25n01gvxx = { + .log2_ppb = 6, /* 64 pages */ + .page_size = 2048, + .oob_size = 64, + .nr_blocks = 1024, + .bbm_pos = 2048, + .clock_freq = 150000000, + .dev_conf = jz_orf(SFC_DEV_CONF, + CE_DL(1), HOLD_DL(1), WP_DL(1), + CPHA(0), CPOL(0), + TSH(11), TSETUP(0), THOLD(0), + STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), + SMP_DELAY(1)), + .flags = NAND_CHIPFLAG_ON_DIE_ECC, + /* TODO: quad mode? */ + .cmd_page_read = NANDCMD_PAGE_READ, + .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE, + .cmd_block_erase = NANDCMD_BLOCK_ERASE, + .cmd_read_cache = NANDCMD_READ_CACHE_SLOW, + .cmd_program_load = NANDCMD_PROGRAM_LOAD, + .setup_chip = winbond_setup_chip, +}; + +static const struct nand_chip chip_gd5f1gq4xexx = { + .log2_ppb = 6, /* 64 pages */ + .page_size = 2048, + .oob_size = 64, /* 128B when hardware ECC is disabled */ + .nr_blocks = 1024, + .bbm_pos = 2048, + .clock_freq = 150000000, + .dev_conf = jz_orf(SFC_DEV_CONF, + CE_DL(1), HOLD_DL(1), WP_DL(1), + CPHA(0), CPOL(0), + TSH(7), TSETUP(0), THOLD(0), + STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), + SMP_DELAY(1)), + .flags = NAND_CHIPFLAG_QUAD | NAND_CHIPFLAG_HAS_QE_BIT | + NAND_CHIPFLAG_ON_DIE_ECC, + .cmd_page_read = NANDCMD_PAGE_READ, + .cmd_program_execute = NANDCMD_PROGRAM_EXECUTE, + .cmd_block_erase = NANDCMD_BLOCK_ERASE, + .cmd_read_cache = NANDCMD_READ_CACHE_x4, + .cmd_program_load = NANDCMD_PROGRAM_LOAD_x4, +}; -static nand_drv static_nand_drv; +#define chip_ds35x1gaxxx chip_gd5f1gq4xexx +#define chip_gd5f1gq5xexxg chip_gd5f1gq4xexx + +const struct nand_chip_id supported_nand_chips[] = { + NAND_CHIP_ID(&chip_ato25d1ga, NAND_READID_ADDR, 0x9b, 0x12), + NAND_CHIP_ID(&chip_w25n01gvxx, NAND_READID_ADDR, 0xef, 0xaa, 0x21), + NAND_CHIP_ID(&chip_gd5f1gq4xexx, NAND_READID_ADDR, 0xc8, 0xd1), + NAND_CHIP_ID(&chip_gd5f1gq4xexx, NAND_READID_ADDR, 0xc8, 0xc1), + NAND_CHIP_ID(&chip_ds35x1gaxxx, NAND_READID_ADDR, 0xe5, 0x71), /* 3.3 V */ + NAND_CHIP_ID(&chip_ds35x1gaxxx, NAND_READID_ADDR, 0xe5, 0x21), /* 1.8 V */ + NAND_CHIP_ID(&chip_gd5f1gq5xexxg, NAND_READID_ADDR, 0xc8, 0x51), /* 3.3 V */ + NAND_CHIP_ID(&chip_gd5f1gq5xexxg, NAND_READID_ADDR, 0xc8, 0x41), /* 1.8 V */ +}; + +const size_t nr_supported_nand_chips = ARRAYLEN(supported_nand_chips); + +static struct nand_drv static_nand_drv; static uint8_t static_scratch_buf[NAND_DRV_SCRATCHSIZE] CACHEALIGN_ATTR; static uint8_t static_page_buf[NAND_DRV_MAXPAGESIZE] CACHEALIGN_ATTR; -nand_drv* nand_init(void) +struct nand_drv* nand_init(void) { static bool inited = false; if(!inited) { @@ -104,19 +126,19 @@ nand_drv* nand_init(void) return &static_nand_drv; } -static uint8_t nand_get_reg(nand_drv* drv, uint8_t reg) +static uint8_t nand_get_reg(struct nand_drv* drv, uint8_t reg) { sfc_exec(NANDCMD_GET_FEATURE, reg, drv->scratch_buf, 1|SFC_READ); return drv->scratch_buf[0]; } -static void nand_set_reg(nand_drv* drv, uint8_t reg, uint8_t val) +static void nand_set_reg(struct nand_drv* drv, uint8_t reg, uint8_t val) { drv->scratch_buf[0] = val; sfc_exec(NANDCMD_SET_FEATURE, reg, drv->scratch_buf, 1|SFC_WRITE); } -static void nand_upd_reg(nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val) +static void nand_upd_reg(struct nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val) { uint8_t x = nand_get_reg(drv, reg); x &= ~msk; @@ -124,56 +146,50 @@ static void nand_upd_reg(nand_drv* drv, uint8_t reg, uint8_t msk, uint8_t val) nand_set_reg(drv, reg, x); } -static bool identify_chip(nand_drv* drv) +static const struct nand_chip* identify_chip_method(uint8_t method, + const uint8_t* id_buf) +{ + for (size_t i = 0; i < nr_supported_nand_chips; ++i) { + const struct nand_chip_id* chip_id = &supported_nand_chips[i]; + if (chip_id->method == method && + !memcmp(chip_id->id_bytes, id_buf, chip_id->num_id_bytes)) + return chip_id->chip; + } + + return NULL; +} + +static bool identify_chip(struct nand_drv* drv) { /* Read ID command has some variations; Linux handles these 3: * - no address or dummy bytes * - 1 byte address, no dummy byte * - no address byte, 1 byte dummy * - * Right now there is only a need for the 2nd variation, as that is - * the method used by the ATO25D1GA. - * - * Some chips also output more than 2 ID bytes. + * Currently we use the 2nd method, aka. address read ID, the + * other methods can be added when needed. */ - sfc_exec(NANDCMD_READID(1, 0), 0, drv->scratch_buf, 2|SFC_READ); - drv->mf_id = drv->scratch_buf[0]; - drv->dev_id = drv->scratch_buf[1]; - - for(size_t i = 0; i < nr_supported_nand_chips; ++i) { - const nand_chip* chip = &supported_nand_chips[i]; - if(chip->mf_id == drv->mf_id && chip->dev_id == drv->dev_id) { - drv->chip = chip; - return true; - } - } + sfc_exec(NANDCMD_READID_ADDR, 0, drv->scratch_buf, 4|SFC_READ); + drv->chip = identify_chip_method(NAND_READID_ADDR, drv->scratch_buf); + if (drv->chip) + return true; return false; } -static void setup_chip_data(nand_drv* drv) +static void setup_chip_data(struct nand_drv* drv) { drv->ppb = 1 << drv->chip->log2_ppb; drv->fpage_size = drv->chip->page_size + drv->chip->oob_size; } -static void setup_chip_commands(nand_drv* drv) +static void winbond_setup_chip(struct nand_drv* drv) { - /* Select commands appropriate for the chip */ - drv->cmd_page_read = NANDCMD_PAGE_READ(drv->chip->row_cycles); - drv->cmd_program_execute = NANDCMD_PROGRAM_EXECUTE(drv->chip->row_cycles); - drv->cmd_block_erase = NANDCMD_BLOCK_ERASE(drv->chip->row_cycles); - - if(drv->chip->flags & NAND_CHIPFLAG_QUAD) { - drv->cmd_read_cache = NANDCMD_READ_CACHE_x4(drv->chip->col_cycles); - drv->cmd_program_load = NANDCMD_PROGRAM_LOAD_x4(drv->chip->col_cycles); - } else { - drv->cmd_read_cache = NANDCMD_READ_CACHE(drv->chip->col_cycles); - drv->cmd_program_load = NANDCMD_PROGRAM_LOAD(drv->chip->col_cycles); - } + /* Ensure we are in buffered read mode. */ + nand_upd_reg(drv, FREG_CFG, FREG_CFG_WINBOND_BUF, FREG_CFG_WINBOND_BUF); } -static void setup_chip_registers(nand_drv* drv) +static void setup_chip_registers(struct nand_drv* drv) { /* Set chip registers to enter normal operation */ if(drv->chip->flags & NAND_CHIPFLAG_HAS_QE_BIT) { @@ -182,14 +198,23 @@ static void setup_chip_registers(nand_drv* drv) en ? FREG_CFG_QUAD_ENABLE : 0); } + if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) { + /* Enable on-die ECC */ + nand_upd_reg(drv, FREG_CFG, FREG_CFG_ECC_ENABLE, FREG_CFG_ECC_ENABLE); + } + /* Clear OTP bit to access the main data array */ nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE, 0); /* Clear write protection bits */ nand_set_reg(drv, FREG_PROT, FREG_PROT_UNLOCK); + + /* Call any chip-specific hooks */ + if(drv->chip->setup_chip) + drv->chip->setup_chip(drv); } -int nand_open(nand_drv* drv) +int nand_open(struct nand_drv* drv) { if(drv->refcount > 0) { drv->refcount++; @@ -198,8 +223,13 @@ int nand_open(nand_drv* drv) /* Initialize the controller */ sfc_open(); - sfc_set_dev_conf(supported_nand_chips[0].dev_conf); - sfc_set_clock(supported_nand_chips[0].clock_freq); + sfc_set_dev_conf(jz_orf(SFC_DEV_CONF, + CE_DL(1), HOLD_DL(1), WP_DL(1), + CPHA(0), CPOL(0), + TSH(15), TSETUP(0), THOLD(0), + STA_TYPE_V(1BYTE), CMD_TYPE_V(8BITS), + SMP_DELAY(0))); + sfc_set_clock(X1000_EXCLK_FREQ); /* Send the software reset command */ sfc_exec(NANDCMD_RESET, 0, NULL, 0); @@ -210,7 +240,6 @@ int nand_open(nand_drv* drv) return NAND_ERR_UNKNOWN_CHIP; setup_chip_data(drv); - setup_chip_commands(drv); /* Set new SFC parameters */ sfc_set_dev_conf(drv->chip->dev_conf); @@ -223,7 +252,7 @@ int nand_open(nand_drv* drv) return NAND_SUCCESS; } -void nand_close(nand_drv* drv) +void nand_close(struct nand_drv* drv) { --drv->refcount; if(drv->refcount > 0) @@ -237,7 +266,13 @@ void nand_close(nand_drv* drv) sfc_close(); } -static uint8_t nand_wait_busy(nand_drv* drv) +void nand_enable_otp(struct nand_drv* drv, bool enable) +{ + nand_upd_reg(drv, FREG_CFG, FREG_CFG_OTP_ENABLE, + enable ? FREG_CFG_OTP_ENABLE : 0); +} + +static uint8_t nand_wait_busy(struct nand_drv* drv) { uint8_t reg; do { @@ -246,10 +281,10 @@ static uint8_t nand_wait_busy(nand_drv* drv) return reg; } -int nand_block_erase(nand_drv* drv, nand_block_t block) +int nand_block_erase(struct nand_drv* drv, nand_block_t block) { sfc_exec(NANDCMD_WR_EN, 0, NULL, 0); - sfc_exec(drv->cmd_block_erase, block, NULL, 0); + sfc_exec(drv->chip->cmd_block_erase, block, NULL, 0); uint8_t status = nand_wait_busy(drv); if(status & FREG_STATUS_EFAIL) @@ -258,11 +293,12 @@ int nand_block_erase(nand_drv* drv, nand_block_t block) return NAND_SUCCESS; } -int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer) +int nand_page_program(struct nand_drv* drv, nand_page_t page, const void* buffer) { sfc_exec(NANDCMD_WR_EN, 0, NULL, 0); - sfc_exec(drv->cmd_program_load, 0, (void*)buffer, drv->fpage_size|SFC_WRITE); - sfc_exec(drv->cmd_program_execute, page, NULL, 0); + sfc_exec(drv->chip->cmd_program_load, + 0, (void*)buffer, drv->fpage_size|SFC_WRITE); + sfc_exec(drv->chip->cmd_program_execute, page, NULL, 0); uint8_t status = nand_wait_busy(drv); if(status & FREG_STATUS_PFAIL) @@ -271,15 +307,29 @@ int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer) return NAND_SUCCESS; } -int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer) +int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer) { - sfc_exec(drv->cmd_page_read, page, NULL, 0); + sfc_exec(drv->chip->cmd_page_read, page, NULL, 0); nand_wait_busy(drv); - sfc_exec(drv->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ); + sfc_exec(drv->chip->cmd_read_cache, 0, buffer, drv->fpage_size|SFC_READ); + + if(drv->chip->flags & NAND_CHIPFLAG_ON_DIE_ECC) { + uint8_t status = nand_get_reg(drv, FREG_STATUS); + + if(status & FREG_STATUS_ECC_UNCOR_ERR) { + logf("ecc uncorrectable error on page %08lx", (unsigned long)page); + return NAND_ERR_ECC_FAIL; + } + + if(status & FREG_STATUS_ECC_HAS_FLIPS) { + logf("ecc corrected bitflips on page %08lx", (unsigned long)page); + } + } + return NAND_SUCCESS; } -int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer) +int nand_read_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer) { if(byte_len == 0) return NAND_SUCCESS; @@ -307,7 +357,7 @@ int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* return NAND_SUCCESS; } -int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer) +int nand_write_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer) { if(byte_len == 0) return NAND_SUCCESS; diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h index 668b3e3f82..0ccd075079 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.h +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h @@ -32,6 +32,7 @@ #define NAND_ERR_PROGRAM_FAIL (-2) #define NAND_ERR_ERASE_FAIL (-3) #define NAND_ERR_UNALIGNED (-4) +#define NAND_ERR_ECC_FAIL (-5) /* keep max page size in sync with the NAND chip table in the .c file */ #define NAND_DRV_SCRATCHSIZE 32 @@ -41,6 +42,47 @@ #define NAND_CHIPFLAG_QUAD 0x0001 /* Chip requires QE bit set to enable quad I/O mode */ #define NAND_CHIPFLAG_HAS_QE_BIT 0x0002 +/* True if the chip has on-die ECC */ +#define NAND_CHIPFLAG_ON_DIE_ECC 0x0004 + +/* cmd mode a d phase format has data */ +#define NANDCMD_RESET SFC_CMD(0xff, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) +#define NANDCMD_READID_OPCODE SFC_CMD(0x9f, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_READID_ADDR SFC_CMD(0x9f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_READID_DUMMY SFC_CMD(0x9f, SFC_TMODE_1_1_1, 0, 8, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_WR_EN SFC_CMD(0x06, SFC_TMODE_1_1_1, 0, 0, SFC_PFMT_ADDR_FIRST, 0) +#define NANDCMD_GET_FEATURE SFC_CMD(0x0f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_SET_FEATURE SFC_CMD(0x1f, SFC_TMODE_1_1_1, 1, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_PAGE_READ SFC_CMD(0x13, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0) +#define NANDCMD_READ_CACHE_SLOW SFC_CMD(0x03, SFC_TMODE_1_1_1, 2, 8, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_READ_CACHE SFC_CMD(0x0b, SFC_TMODE_1_1_1, 2, 8, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_READ_CACHE_x4 SFC_CMD(0x6b, SFC_TMODE_1_1_4, 2, 8, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_PROGRAM_EXECUTE SFC_CMD(0x10, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0) +#define NANDCMD_PROGRAM_LOAD SFC_CMD(0x02, SFC_TMODE_1_1_1, 2, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_PROGRAM_LOAD_x4 SFC_CMD(0x32, SFC_TMODE_1_1_4, 2, 0, SFC_PFMT_ADDR_FIRST, 1) +#define NANDCMD_BLOCK_ERASE SFC_CMD(0xd8, SFC_TMODE_1_1_1, 3, 0, SFC_PFMT_ADDR_FIRST, 0) + +/* Feature registers are found in linux/mtd/spinand.h, + * apparently these are pretty standardized */ +#define FREG_PROT 0xa0 +#define FREG_PROT_UNLOCK 0x00 + +#define FREG_CFG 0xb0 +#define FREG_CFG_OTP_ENABLE (1 << 6) +#define FREG_CFG_ECC_ENABLE (1 << 4) +#define FREG_CFG_QUAD_ENABLE (1 << 0) + +/* Winbond-specific bit used on the W25N01GVxx */ +#define FREG_CFG_WINBOND_BUF (1 << 3) + +#define FREG_STATUS 0xc0 +#define FREG_STATUS_BUSY (1 << 0) +#define FREG_STATUS_EFAIL (1 << 2) +#define FREG_STATUS_PFAIL (1 << 3) +#define FREG_STATUS_ECC_MASK (3 << 4) +#define FREG_STATUS_ECC_NO_FLIPS (0 << 4) +#define FREG_STATUS_ECC_HAS_FLIPS (1 << 4) +#define FREG_STATUS_ECC_UNCOR_ERR (2 << 4) /* Types to distinguish between block & page addresses in the API. * @@ -59,15 +101,9 @@ typedef uint32_t nand_block_t; typedef uint32_t nand_page_t; -typedef struct nand_chip { - /* Manufacturer and device ID bytes */ - uint8_t mf_id; - uint8_t dev_id; - - /* Row/column address width */ - uint8_t row_cycles; - uint8_t col_cycles; +struct nand_drv; +struct nand_chip { /* Base2 logarithm of the number of pages per block */ unsigned log2_ppb; @@ -89,9 +125,38 @@ typedef struct nand_chip { /* Chip specific flags */ uint32_t flags; -} nand_chip; -typedef struct nand_drv { + /* SFC commands for issuing I/O ops */ + uint32_t cmd_page_read; + uint32_t cmd_program_execute; + uint32_t cmd_block_erase; + uint32_t cmd_read_cache; + uint32_t cmd_program_load; + + /* Chip-specific setup routine */ + void(*setup_chip)(struct nand_drv* drv); +}; + +enum nand_readid_method { + NAND_READID_OPCODE, + NAND_READID_ADDR, + NAND_READID_DUMMY, +}; + +struct nand_chip_id { + uint8_t method; + uint8_t num_id_bytes; + uint8_t id_bytes[4]; + const struct nand_chip* chip; +}; + +#define NAND_CHIP_ID(_chip, _method, ...) \ + { .method = _method, \ + .num_id_bytes = ARRAYLEN(((uint8_t[]){__VA_ARGS__})), \ + .id_bytes = {__VA_ARGS__}, \ + .chip = _chip } + +struct nand_drv { /* NAND access lock. Needs to be held during any operations. */ struct mutex mutex; @@ -113,27 +178,16 @@ typedef struct nand_drv { uint8_t* page_buf; /* Pointer to the chip data. */ - const nand_chip* chip; + const struct nand_chip* chip; /* Pages per block = 1 << chip->log2_ppb */ unsigned ppb; /* Full page size = chip->page_size + chip->oob_size */ unsigned fpage_size; +}; - /* Probed mf_id / dev_id for debugging, in case identification fails. */ - uint8_t mf_id; - uint8_t dev_id; - - /* SFC commands used for I/O, these are set based on chip data */ - uint32_t cmd_page_read; - uint32_t cmd_read_cache; - uint32_t cmd_program_load; - uint32_t cmd_program_execute; - uint32_t cmd_block_erase; -} nand_drv; - -extern const nand_chip supported_nand_chips[]; +extern const struct nand_chip_id supported_nand_chips[]; extern const size_t nr_supported_nand_chips; /* Return the static NAND driver instance. @@ -141,14 +195,14 @@ extern const size_t nr_supported_nand_chips; * ALL normal Rockbox code should use this instance. The SPL does not * use it, because it needs to manually place buffers in external RAM. */ -extern nand_drv* nand_init(void); +extern struct nand_drv* nand_init(void); -static inline void nand_lock(nand_drv* drv) +static inline void nand_lock(struct nand_drv* drv) { mutex_lock(&drv->mutex); } -static inline void nand_unlock(nand_drv* drv) +static inline void nand_unlock(struct nand_drv* drv) { mutex_unlock(&drv->mutex); } @@ -162,8 +216,11 @@ static inline void nand_unlock(nand_drv* drv) * * These functions require the lock to be held. */ -extern int nand_open(nand_drv* drv); -extern void nand_close(nand_drv* drv); +extern int nand_open(struct nand_drv* drv); +extern void nand_close(struct nand_drv* drv); + +/* Enable/disable OTP access. OTP data pages are usually vendor-specific. */ +void nand_enable_otp(struct nand_drv* drv, bool enable); /* Read / program / erase operations. Buffer needs to be cache-aligned for DMA. * Read and program operate on full page data, ie. including OOB data areas. @@ -171,15 +228,15 @@ extern void nand_close(nand_drv* drv); * NOTE: ECC is not implemented. If it ever needs to be, these functions will * probably use ECC transparently. All code should be written to expect this. */ -extern int nand_block_erase(nand_drv* drv, nand_block_t block); -extern int nand_page_program(nand_drv* drv, nand_page_t page, const void* buffer); -extern int nand_page_read(nand_drv* drv, nand_page_t page, void* buffer); +extern int nand_block_erase(struct nand_drv* drv, nand_block_t block); +extern int nand_page_program(struct nand_drv* drv, nand_page_t page, const void* buffer); +extern int nand_page_read(struct nand_drv* drv, nand_page_t page, void* buffer); /* Wrappers to read/write bytes. For simple access to the main data area only. * The write address / length must align to a block boundary. Reads do not have * any alignment requirement. OOB data is never read, and is written as 0xff. */ -extern int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer); -extern int nand_write_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer); +extern int nand_read_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* buffer); +extern int nand_write_bytes(struct nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, const void* buffer); #endif /* __NAND_X1000_H__ */ diff --git a/firmware/target/mips/ingenic_x1000/pcm-x1000.c b/firmware/target/mips/ingenic_x1000/pcm-x1000.c index 7d1c83a35a..4b9cb85b57 100644 --- a/firmware/target/mips/ingenic_x1000/pcm-x1000.c +++ b/firmware/target/mips/ingenic_x1000/pcm-x1000.c @@ -168,8 +168,23 @@ void pcm_play_dma_start(const void* addr, size_t size) void pcm_play_dma_stop(void) { - jz_writef(AIC_CCR, TDMS(0), ETUR(0), ERPL(0)); - jz_writef(AIC_CCR, TFLUSH(1)); + /* disable DMA and underrun interrupts */ + jz_writef(AIC_CCR, TDMS(0), ETUR(0)); + + /* + * wait for FIFO to be empty - on targets + * with >16bit samples, flushing the fifo + * may result in swapping l and r channels! + * (ensure bit clock is running first) + */ + if (jz_readf(AIC_I2SCR, STPBK) == 0) { + while(jz_readf(AIC_SR, TFL) != 0); + } else { + panicf("pcm_play_dma_stop: No bit clock running!"); + } + + /* disable playback */ + jz_writef(AIC_CCR, ERPL(0)); play_dma_pending_event = DMA_EVENT_NONE; aic_state &= ~AIC_STATE_PLAYING; diff --git a/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c index 82a05abf75..24eb42081e 100644 --- a/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c @@ -23,7 +23,7 @@ #include "gpio-x1000.h" #include "nand-x1000.h" -static nand_drv* ndrv = NULL; +static struct nand_drv* ndrv = NULL; int spl_storage_open(void) { @@ -31,7 +31,7 @@ int spl_storage_open(void) gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1)); /* Allocate NAND driver manually in DRAM */ - ndrv = spl_alloc(sizeof(nand_drv)); + ndrv = spl_alloc(sizeof(struct nand_drv)); ndrv->page_buf = spl_alloc(NAND_DRV_MAXPAGESIZE); ndrv->scratch_buf = spl_alloc(NAND_DRV_SCRATCHSIZE); ndrv->refcount = 0; diff --git a/firmware/target/mips/ingenic_x1000/spl-start.S b/firmware/target/mips/ingenic_x1000/spl-start.S index 58346fe750..ecdc47f283 100644 --- a/firmware/target/mips/ingenic_x1000/spl-start.S +++ b/firmware/target/mips/ingenic_x1000/spl-start.S @@ -31,7 +31,7 @@ .set noreorder .set noat - .section .init.spl + .section .startup.spl _spl_start: /* Clear data watchpoint */ diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c index b9ee6cc1c1..08f88f506c 100644 --- a/firmware/target/mips/ingenic_x1000/spl-x1000.c +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c @@ -317,6 +317,9 @@ void spl_main(void) REG_CPM_PSWC2ST = 0x18; REG_CPM_PSWC3ST = 0x08; + /* Save this, it's needed on some targets */ + uint32_t saved_cpm_scratch = REG_CPM_SCRATCH; + /* set up boot flags */ init_boot_flags(); @@ -361,8 +364,8 @@ void spl_main(void) spl_storage_close(); /* jump to the entry point */ - typedef void(*entry_fn)(void); + typedef void(*entry_fn)(uint32_t); entry_fn fn = (entry_fn)BOOT_EXEC_ADDR; commit_discard_idcache(); - fn(); + fn(saved_cpm_scratch); } diff --git a/firmware/target/mips/ingenic_x1000/spl.lds b/firmware/target/mips/ingenic_x1000/spl.lds index 09ab75d520..b3e508e9c3 100644 --- a/firmware/target/mips/ingenic_x1000/spl.lds +++ b/firmware/target/mips/ingenic_x1000/spl.lds @@ -15,9 +15,10 @@ SECTIONS { .text : { - *(.init.spl); + *(.startup.spl); *(.text*); *(.icode*); + *(.init*); } > TCSM . = ALIGN(4); diff --git a/firmware/target/mips/ingenic_x1000/system-target.h b/firmware/target/mips/ingenic_x1000/system-target.h index 7cea654865..ed077a3cce 100644 --- a/firmware/target/mips/ingenic_x1000/system-target.h +++ b/firmware/target/mips/ingenic_x1000/system-target.h @@ -31,6 +31,7 @@ #include "mmu-mips.h" #include "mipsregs.h" #include "mipsr2-endian.h" +#include "system-mips.h" #include <stdint.h> /* Rockbox API */ @@ -96,6 +97,8 @@ extern irq_handler_t system_set_irq_handler(int irq, irq_handler_t handler); extern void system_enable_irq(int irq); extern void system_disable_irq(int irq); +extern void system_early_init(void) INIT_ATTR; + /* Simple delay API */ #define OST_FREQUENCY (X1000_EXCLK_FREQ / 4) #define OST_TICKS_PER_US (OST_FREQUENCY / 1000000) diff --git a/firmware/target/mips/ingenic_x1000/system-x1000.c b/firmware/target/mips/ingenic_x1000/system-x1000.c index 7542b97a3d..64890a6c3a 100644 --- a/firmware/target/mips/ingenic_x1000/system-x1000.c +++ b/firmware/target/mips/ingenic_x1000/system-x1000.c @@ -44,6 +44,7 @@ uint32_t __cpu_idle_reftick = 0; #endif /* Prepare the CPU to process interrupts, but don't enable them yet */ +static void system_init_irq(void) INIT_ATTR; static void system_init_irq(void) { /* Mask all interrupts */ @@ -343,8 +344,10 @@ static int vector_irq(void) return n; } -void intr_handler(unsigned cause) +void intr_handler(void) { + unsigned long cause = read_c0_cause(); + /* OST interrupt is handled separately */ if(cause & M_CauseIP3) { OST(); @@ -363,49 +366,6 @@ void intr_handler(unsigned cause) irqvector[irq](); } -void tlb_refill_handler(void) -{ - panicf("TLB refill handler at 0x%08lx! [0x%x]", - read_c0_epc(), read_c0_badvaddr()); -} - -#define EXC(x,y) case (x): return (y); -static char* parse_exception(unsigned cause) -{ - switch(cause & M_CauseExcCode) - { - EXC(EXC_INT, "Interrupt"); - EXC(EXC_MOD, "TLB Modified"); - EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)"); - EXC(EXC_ADEL, "Address Error (Load or Ifetch)"); - EXC(EXC_ADES, "Address Error (Store)"); - EXC(EXC_TLBS, "TLB Exception (Store)"); - EXC(EXC_IBE, "Instruction Bus Error"); - EXC(EXC_DBE, "Data Bus Error"); - EXC(EXC_SYS, "Syscall"); - EXC(EXC_BP, "Breakpoint"); - EXC(EXC_RI, "Reserved Instruction"); - EXC(EXC_CPU, "Coprocessor Unusable"); - EXC(EXC_OV, "Overflow"); - EXC(EXC_TR, "Trap Instruction"); - EXC(EXC_FPE, "Floating Point Exception"); - EXC(EXC_C2E, "COP2 Exception"); - EXC(EXC_MDMX, "MDMX Exception"); - EXC(EXC_WATCH, "Watch Exception"); - EXC(EXC_MCHECK, "Machine Check Exception"); - EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode"); - default: - return 0; - } -} -#undef EXC - -void exception_handler(unsigned cause, unsigned epc, unsigned stack_ptr) -{ - panicf("Exception occurred: %s [0x%08x] at 0x%08x (stack at 0x%08x)", - parse_exception(cause), read_c0_badvaddr(), epc, stack_ptr); -} - void system_exception_wait(void) { #ifdef FIIO_M3K diff --git a/firmware/target/mips/mmu-mips.h b/firmware/target/mips/mmu-mips.h index b8f5ff0143..ca865f9909 100644 --- a/firmware/target/mips/mmu-mips.h +++ b/firmware/target/mips/mmu-mips.h @@ -36,7 +36,11 @@ void map_address(unsigned long virtual, unsigned long physical, void mmu_init(void); /* Commits entire DCache */ -MIPS_CACHEFUNC_API(void, commit_dcache, (void)); +#if 0 /* NOTE: This is currently aliased to commit_discard_dcache. Causes compilation errors with newer GCC if we try to assign it to a section here */ +//MIPS_CACHEFUNC_API(void, commit_dcache, (void)); +#else +void commit_dcache(void); +#endif /* Commit and discard entire DCache, will do writeback */ MIPS_CACHEFUNC_API(void, commit_discard_dcache, (void)); diff --git a/firmware/target/mips/system-mips.c b/firmware/target/mips/system-mips.c new file mode 100644 index 0000000000..e6bb2d8ea6 --- /dev/null +++ b/firmware/target/mips/system-mips.c @@ -0,0 +1,175 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2022 Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "system.h" +#include "backtrace.h" +#include "lcd.h" +#include "backlight-target.h" +#include "font.h" +#include "logf.h" +#include "mips.h" +#undef sp /* breaks backtrace lib */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +/* copies exception frame info and error pc to the backtrace context */ +static void setup_exception_bt(struct mips_exception_frame* frame, + unsigned long epc, struct mips_bt_context* ctx) +{ + ctx->pc = (void*)epc; + ctx->sp = (void*)frame->gpr[29 - 3]; + ctx->depth = 0; + ctx->valid = (1 << MIPSBT_RA); + ctx->reg[MIPSBT_RA] = frame->gpr[31 - 3]; +} + +/* dump backtrace for an exception */ +static void exception_bt(void* frame, unsigned long epc, unsigned* line) +{ + struct mips_bt_context ctx; + setup_exception_bt(frame, epc, &ctx); + rb_backtrace_ctx(&ctx, line); +} + +/* + * TODO: This should be converted into a generic panic routine that accepts + * a backtrace context argument but the ARM backtrace setup will need to be + * refactored in order to do that + */ +static void exception_dump(void* frame, unsigned long epc, + const char* fmt, ...) +{ + extern char panic_buf[128]; + va_list ap; + + set_irq_level(DISABLE_INTERRUPTS); + + va_start(ap, fmt); + vsnprintf(panic_buf, sizeof(panic_buf), fmt, ap); + va_end(ap); + + lcd_set_viewport(NULL); +#if LCD_DEPTH > 1 + lcd_set_backdrop(NULL); + lcd_set_drawmode(DRMODE_SOLID); + lcd_set_foreground(LCD_BLACK); + lcd_set_background(LCD_WHITE); +#endif + + lcd_clear_display(); + lcd_setfont(FONT_SYSFIXED); + + unsigned y = 1; + lcd_puts(1, y++, "*EXCEPTION*"); + + /* wrap panic message */ + { + const int linechars = (LCD_WIDTH / SYSFONT_WIDTH) - 2; + + int pos = 0, len = strlen(panic_buf); + while(len > 0) { + int idx = pos + MIN(len, linechars); + char c = panic_buf[idx]; + panic_buf[idx] = 0; + lcd_puts(1, y++, &panic_buf[pos]); + panic_buf[idx] = c; + + len -= linechars; + pos += linechars; + } + } + + exception_bt(frame, epc, &y); +#ifdef ROCKBOX_HAS_LOGF + logf_panic_dump(&y); +#endif + + lcd_update(); + backlight_hw_on(); + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ + if (cpu_boost_lock()) + { + set_cpu_frequency(0); + cpu_boost_unlock(); + } +#endif + +#ifdef HAVE_ATA_POWER_OFF + ide_power_enable(false); +#endif + + system_exception_wait(); + system_reboot(); + while(1); +} + +#define EXC(x,y) case (x): return (y); +static char* parse_exception(unsigned long cause) +{ + switch(cause & M_CauseExcCode) + { + EXC(EXC_INT, "Interrupt"); + EXC(EXC_MOD, "TLB Modified"); + EXC(EXC_TLBL, "TLB Exception (Load or Ifetch)"); + EXC(EXC_ADEL, "Address Error (Load or Ifetch)"); + EXC(EXC_ADES, "Address Error (Store)"); + EXC(EXC_TLBS, "TLB Exception (Store)"); + EXC(EXC_IBE, "Instruction Bus Error"); + EXC(EXC_DBE, "Data Bus Error"); + EXC(EXC_SYS, "Syscall"); + EXC(EXC_BP, "Breakpoint"); + EXC(EXC_RI, "Reserved Instruction"); + EXC(EXC_CPU, "Coprocessor Unusable"); + EXC(EXC_OV, "Overflow"); + EXC(EXC_TR, "Trap Instruction"); + EXC(EXC_FPE, "Floating Point Exception"); + EXC(EXC_C2E, "COP2 Exception"); + EXC(EXC_MDMX, "MDMX Exception"); + EXC(EXC_WATCH, "Watch Exception"); + EXC(EXC_MCHECK, "Machine Check Exception"); + EXC(EXC_CacheErr, "Cache error caused re-entry to Debug Mode"); + default: + return 0; + } +} +#undef EXC + +void exception_handler(void* frame, unsigned long epc) +{ + unsigned long cause = read_c0_cause(); + + exception_dump(frame, epc, "%s [0x%08x] at %08lx", + parse_exception(cause), read_c0_badvaddr(), epc); +} + +void cache_error_handler(void* frame, unsigned long epc) +{ + exception_dump(frame, epc, "Cache Error [0x%08x] at %08lx", + read_c0_cacheerr(), epc); +} + +void tlb_refill_handler(void* frame, unsigned long epc) +{ + exception_dump(frame, epc, "TLB refill at %08lx [0x%x]", + epc, read_c0_badvaddr()); +} diff --git a/firmware/target/mips/system-mips.h b/firmware/target/mips/system-mips.h new file mode 100644 index 0000000000..d9108ef7c2 --- /dev/null +++ b/firmware/target/mips/system-mips.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2022 Aidan MacDonald + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef SYSTEM_MIPS_H +#define SYSTEM_MIPS_H + +#include <stdint.h> + +struct mips_exception_frame { + uint32_t gpr[29]; /* GPRs $1-$25, $28-$31 */ + uint32_t lo; + uint32_t hi; + uint32_t c0_status; + uint32_t c0_epc; +}; + +void intr_handler(void); +void exception_handler(void* frame, unsigned long epc); +void cache_error_handler(void* frame, unsigned long epc); +void tlb_refill_handler(void* frame, unsigned long epc); + +#endif /* SYSTEM_MIPS_H */ |