diff options
Diffstat (limited to 'firmware/target')
102 files changed, 2142 insertions, 1713 deletions
diff --git a/firmware/target/arm/as3525/lcd-ssd1303.c b/firmware/target/arm/as3525/lcd-ssd1303.c index 2aa0b844c5..186fdcacbe 100644 --- a/firmware/target/arm/as3525/lcd-ssd1303.c +++ b/firmware/target/arm/as3525/lcd-ssd1303.c @@ -310,6 +310,7 @@ static void internal_update_rect(int x, int y, int width, int height) const int column_high = get_column_high_byte(x); const int column_low = get_column_low_byte(x); + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectange bitmap to hardware */ for (; y <= height; y++) { @@ -320,7 +321,7 @@ static void internal_update_rect(int x, int y, int width, int height) (column_low) ); - lcd_write_data (FBADDR(x,y), width); + lcd_write_data (fbaddr(x,y), width); } lcd_write_command (LCD_NOP); /* return to command mode */ diff --git a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c index 03ed1de5d5..48594a2ac9 100644 --- a/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c +++ b/firmware/target/arm/as3525/sansa-clipzip/lcd-clipzip.c @@ -440,9 +440,10 @@ void lcd_update_rect(int x, int y, int width, int height) /* setup GRAM write window */ lcd_setup_rect(x, x_end - 1, y, y_end - 1); + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* write to GRAM */ for (row = y; row < y_end; row++) { - lcd_write_data(FBADDR(x,row), width); + lcd_write_data(fbaddr(x,row), width); } } 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/imx233/creative-zen/lcd-zenmozaic.c b/firmware/target/arm/imx233/creative-zen/lcd-zenmozaic.c index c1bc379a49..ab4466300b 100644 --- a/firmware/target/arm/imx233/creative-zen/lcd-zenmozaic.c +++ b/firmware/target/arm/imx233/creative-zen/lcd-zenmozaic.c @@ -149,6 +149,8 @@ void lcd_update_rect(int x, int y, int w, int h) lcd_write_reg(0x17, y | (y + h - 1) << 8); lcd_write_reg(0x21, y * LCD_WIDTH + x); lcd_write_reg(0x22, 0); + + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(int yy = y; yy < y + h; yy++) - imx233_lcdif_pio_send(true, 2 * w, FBADDR(x, yy)); + imx233_lcdif_pio_send(true, 2 * w, fbaddr(x,yy)); } diff --git a/firmware/target/arm/imx233/creative-zen/lcd-zenv.c b/firmware/target/arm/imx233/creative-zen/lcd-zenv.c index 06b0f158f3..75d2775814 100644 --- a/firmware/target/arm/imx233/creative-zen/lcd-zenv.c +++ b/firmware/target/arm/imx233/creative-zen/lcd-zenv.c @@ -172,8 +172,9 @@ void lcd_update_rect(int x, int y, int w, int h) lcd_send(false, 0x75); lcd_send(true, y); lcd_send(true, y + h - 1); lcd_send(false, 0x5c); imx233_lcdif_set_word_length(16); + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(int yy = y; yy < y + h; yy++) - imx233_lcdif_pio_send(true, w, FBADDR(x, yy)); + imx233_lcdif_pio_send(true, w, fbaddr(x,yy)); } #ifndef BOOTLOADER diff --git a/firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c b/firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c index ce0bcc3885..825b0072a3 100644 --- a/firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c +++ b/firmware/target/arm/imx233/creative-zen/lcd-zenxfistyle.c @@ -282,8 +282,9 @@ void lcd_update_rect(int x, int y, int w, int h) } else { + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(int i = 0; i < h; i++) - memcpy((fb_data *)FRAME + i * w, FBADDR(x,y + i), w * sizeof(fb_data)); + memcpy((fb_data *)FRAME + i * w, fbaddr(x,y + i), w * sizeof(fb_data)); } /* WARNING The LCDIF has a limitation on the vertical count ! In 16-bit packed mode * (which we used, ie 16-bit per pixel, 2 pixels per 32-bit words), the v_count diff --git a/firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c b/firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c index 890ff0b586..d0084900e7 100644 --- a/firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c +++ b/firmware/target/arm/imx233/creative-zenxfi2/lcd-zenxfi2.c @@ -241,8 +241,9 @@ void lcd_update_rect(int x, int y, int w, int h) } else { + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(int i = 0; i < h; i++) - memcpy((fb_data *)FRAME + i * w, FBADDR(x,y + i), w * sizeof(fb_data)); + memcpy((fb_data *)FRAME + i * w, fbaddr(x,y + i), w * sizeof(fb_data)); } /* WARNING The LCDIF has a limitation on the vertical count ! In 16-bit packed mode * (which we used, ie 16-bit per pixel, 2 pixels per 32-bit words), the v_count diff --git a/firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c b/firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c index 59496f2d24..d5f25a523c 100644 --- a/firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c +++ b/firmware/target/arm/imx233/creative-zenxfi3/lcd-zenxfi3.c @@ -188,8 +188,9 @@ void lcd_update_rect(int x, int y, int w, int h) } else { + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(int i = 0; i < h; i++) - memcpy((fb_data *)FRAME + i * w, FBADDR(x,y + i), w * sizeof(fb_data)); + memcpy((fb_data *)FRAME + i * w, fbaddr(x,y + i), w * sizeof(fb_data)); } /* WARNING The LCDIF has a limitation on the vertical count ! In 16-bit packed mode * (which we used, ie 16-bit per pixel, 2 pixels per 32-bit words), the v_count diff --git a/firmware/target/arm/imx233/debug-imx233.c b/firmware/target/arm/imx233/debug-imx233.c index bfc38b20dc..4487952162 100644 --- a/firmware/target/arm/imx233/debug-imx233.c +++ b/firmware/target/arm/imx233/debug-imx233.c @@ -940,8 +940,8 @@ bool dbg_hw_info_emi(void) bool dbg_hw_info_audio(void) { - static const char *hp_sel[2] = {"DAC", "Line1"}; - static const char *mux_sel[4] = {"Mic", "Line1", "HP", "Line2"}; + static const char * const hp_sel[2] = {"DAC", "Line1"}; + static const char * const mux_sel[4] = {"Mic", "Line1", "HP", "Line2"}; lcd_setfont(FONT_SYSFIXED); while(1) @@ -1171,7 +1171,7 @@ bool dbg_hw_info_button(void) } else if(MAP[i].periph == IMX233_BUTTON_LRADC) { - static const char *op_name[] = + static const char * const op_name[] = { [IMX233_BUTTON_EQ] = "eq", [IMX233_BUTTON_GT] = "gt", diff --git a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c index 92864c9ed7..ceb7b4e090 100644 --- a/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c +++ b/firmware/target/arm/imx233/sansa-fuzeplus/lcd-fuzeplus.c @@ -637,8 +637,9 @@ void lcd_update_rect(int x, int y, int w, int h) } else { + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(int i = 0; i < h; i++) - memcpy((fb_data *)FRAME + i * w, FBADDR(x,y + i), w * sizeof(fb_data)); + memcpy((fb_data *)FRAME + i * w, fbaddr(x,y + i), w * sizeof(fb_data)); } /* WARNING The LCDIF has a limitation on the vertical count ! In 16-bit packed mode * (which we used, ie 16-bit per pixel, 2 pixels per 32-bit words), the v_count diff --git a/firmware/target/arm/imx233/sony-nwz/lcd-nwze360.c b/firmware/target/arm/imx233/sony-nwz/lcd-nwze360.c index cfcf85bfc0..8f49bfa3eb 100644 --- a/firmware/target/arm/imx233/sony-nwz/lcd-nwze360.c +++ b/firmware/target/arm/imx233/sony-nwz/lcd-nwze360.c @@ -228,8 +228,9 @@ void lcd_update_rect(int x, int y, int w, int h) } else { + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(int i = 0; i < h; i++) - memcpy((fb_data *)FRAME + i * w, FBADDR(x,y + i), w * sizeof(fb_data)); + memcpy((fb_data *)FRAME + i * w, fbaddr(x,y + i), w * sizeof(fb_data)); } /* WARNING The LCDIF has a limitation on the vertical count ! In 16-bit packed mode * (which we used, ie 16-bit per pixel, 2 pixels per 32-bit words), the v_count diff --git a/firmware/target/arm/imx233/sony-nwz/lcd-nwze370.c b/firmware/target/arm/imx233/sony-nwz/lcd-nwze370.c index 999f4ee525..862522da15 100644 --- a/firmware/target/arm/imx233/sony-nwz/lcd-nwze370.c +++ b/firmware/target/arm/imx233/sony-nwz/lcd-nwze370.c @@ -189,8 +189,9 @@ void lcd_update_rect(int x, int y, int w, int h) } else { + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(int i = 0; i < h; i++) - memcpy((fb_data *)FRAME + i * w, FBADDR(x,y + i), w * sizeof(fb_data)); + memcpy((fb_data *)FRAME + i * w, fbaddr(x,y + i), w * sizeof(fb_data)); } /* WARNING The LCDIF has a limitation on the vertical count ! In 16-bit packed mode * (which we used, ie 16-bit per pixel, 2 pixels per 32-bit words), the v_count diff --git a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c index 5b0c71110d..c84f1cf41c 100644 --- a/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c @@ -125,53 +125,30 @@ bool si4700_st(void) return (GPIO1_DR & (1 << 28)) >> 28; } - /* Low-level RDS Support */ -static bool int_restore; - -/* Called after I2C read cycle completes */ -static void si4700_rds_read_raw_async_callback(struct i2c_transfer_desc *xfer) -{ - if (xfer->rxcount == 0) - si4700_rds_process(); - /* else read didn't finish */ - - if (int_restore) - gpio_int_enable(SI4700_EVENT_ID); -} - -/* Called to read registers from ISR context */ -void si4700_rds_read_raw_async(unsigned char *buf, int count) -{ - /* transfer descriptor for RDS async operations */ - static struct i2c_transfer_desc xfer = { .node = &si4700_i2c_node }; - - xfer.txdata = NULL; - xfer.txcount = 0; - xfer.rxdata = buf; - xfer.rxcount = count; - xfer.callback = si4700_rds_read_raw_async_callback; - xfer.next = NULL; - - i2c_transfer(&xfer); -} +static struct semaphore rds_sema; +static uint32_t rds_stack[DEFAULT_STACK_SIZE/sizeof(uint32_t)]; /* RDS GPIO interrupt handler - start RDS data read */ void INT_SI4700_RDS(void) { - /* mask and clear the interrupt until we're done */ - gpio_int_disable(SI4700_EVENT_ID); gpio_int_clear(SI4700_EVENT_ID); + semaphore_release(&rds_sema); +} - /* tell radio driver about it */ - si4700_rds_interrupt(); +/* Captures RDS data and processes it */ +static void NORETURN_ATTR rds_thread(void) +{ + while (true) { + semaphore_wait(&rds_sema, TIMEOUT_BLOCK); + si4700_rds_process(); + } } /* Called with on=true after full radio power up, and with on=false before powering down */ void si4700_rds_powerup(bool on) { - int_restore = on; gpio_int_disable(SI4700_EVENT_ID); gpio_int_clear(SI4700_EVENT_ID); gpio_enable_event(SI4700_EVENT_ID, on); @@ -180,5 +157,7 @@ void si4700_rds_powerup(bool on) /* One-time RDS init at startup */ void si4700_rds_init(void) { - /* nothing to do */ + semaphore_init(&rds_sema, 1, 0); + create_thread(rds_thread, rds_stack, sizeof(rds_stack), 0, "rds" + IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); } 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/lcd-gray.c b/firmware/target/arm/ipod/lcd-gray.c index d8695cdb10..883897b997 100644 --- a/firmware/target/arm/ipod/lcd-gray.c +++ b/firmware/target/arm/ipod/lcd-gray.c @@ -333,17 +333,18 @@ void lcd_update_rect(int x, int y, int width, int height) x >>= 3; width = xmax - x + 1; - for (; y <= ymax; y++) + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; + for (; y <= ymax; y++) { lcd_cmd_and_data(R_RAM_ADDR_SET, (y << 5) + addr_offset - x); lcd_prepare_cmd(R_RAM_DATA); - + fb_data *data = fbaddr(2*x,y); #if defined(IPOD_MINI) || defined(IPOD_MINI2G) if (pix_offset == -2) - lcd_write_data_shifted(FBADDR(2*x, y), width); + lcd_write_data_shifted(data, width); else #endif - lcd_write_data(FBADDR(2*x, y), width); + lcd_write_data(data, width); } } 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/lcd-ssd1815.c b/firmware/target/arm/lcd-ssd1815.c index 028362f91c..0af20cd34f 100644 --- a/firmware/target/arm/lcd-ssd1815.c +++ b/firmware/target/arm/lcd-ssd1815.c @@ -221,6 +221,7 @@ void lcd_update(void) { int y; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy display bitmap to hardware */ for (y = 0; y < LCD_FBHEIGHT; y++) { @@ -228,7 +229,7 @@ void lcd_update(void) lcd_write_command (LCD_CNTL_HIGHCOL | ((xoffset >> 4) & 0xf)); lcd_write_command (LCD_CNTL_LOWCOL | (xoffset & 0xf)); - lcd_write_data (FBADDR(0, y), LCD_WIDTH); + lcd_write_data (fbaddr(0,y), LCD_WIDTH); } } @@ -249,6 +250,7 @@ void lcd_update_rect(int x, int y, int width, int height) if(ymax >= LCD_FBHEIGHT) ymax = LCD_FBHEIGHT-1; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectange bitmap to hardware */ for (; y <= ymax; y++) { @@ -256,6 +258,6 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_command (LCD_CNTL_HIGHCOL | (((x+xoffset) >> 4) & 0xf)); lcd_write_command (LCD_CNTL_LOWCOL | ((x+xoffset) & 0xf)); - lcd_write_data (FBADDR(x,y), width); + lcd_write_data (fbaddr(x,y), width); } } diff --git a/firmware/target/arm/olympus/mrobe-100/lcd-mr100.c b/firmware/target/arm/olympus/mrobe-100/lcd-mr100.c index d336ad7419..c10b4ca8f6 100644 --- a/firmware/target/arm/olympus/mrobe-100/lcd-mr100.c +++ b/firmware/target/arm/olympus/mrobe-100/lcd-mr100.c @@ -232,6 +232,7 @@ void lcd_update(void) cmd1 = LCD_CNTL_HIGHCOL | (((xoffset) >> 4) & 0xf); cmd2 = LCD_CNTL_LOWCOL | ((xoffset) & 0xf); + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy display bitmap to hardware */ for (y = 0; y < LCD_FBHEIGHT; y++) { @@ -239,7 +240,7 @@ void lcd_update(void) lcd_write_command(cmd1); lcd_write_command(cmd2); - lcd_write_data (FBADDR(0, y), LCD_WIDTH); + lcd_write_data (fbaddr(0,y), LCD_WIDTH); } } @@ -264,6 +265,7 @@ void lcd_update_rect(int x, int y, int width, int height) cmd1 = LCD_CNTL_HIGHCOL | (((x + xoffset) >> 4) & 0xf); cmd2 = LCD_CNTL_LOWCOL | ((x + xoffset) & 0xf); + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectange bitmap to hardware */ for (; y <= ymax; y++) { @@ -271,6 +273,6 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_command(cmd1); lcd_write_command(cmd2); - lcd_write_data (FBADDR(x,y), width); + lcd_write_data (fbaddr(x,y), width); } } 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/mi4-loader.c b/firmware/target/arm/pp/mi4-loader.c index 0104496e9d..f609e3ff7a 100644 --- a/firmware/target/arm/pp/mi4-loader.c +++ b/firmware/target/arm/pp/mi4-loader.c @@ -30,96 +30,9 @@ #include "crc32.h" #include "file.h" #if defined(HAVE_BOOTDATA) -#include "system.h" -#include "bootdata.h" - -/* Write bootdata into location in FIRMWARE marked by magic header - * Assumes buffer is already loaded with the firmware image - * We just need to find the location and write data into the - * payload region along with the crc for later verification and use. - * Returns payload len on success, - * On error returns EKEY_NOT_FOUND - */ -int write_bootdata(unsigned char* buf, int len, unsigned int boot_volume) -{ - struct boot_data_t bl_boot_data; - struct boot_data_t *fw_boot_data = NULL; - int search_len = MIN(len, BOOT_DATA_SEARCH_SIZE) - sizeof(struct boot_data_t); - int payload_len = EKEY_NOT_FOUND; - - /* search for boot data header prior to search_len */ - for(int i = 0;i < search_len;i++) - { - fw_boot_data = (struct boot_data_t*) &buf[i]; - if (fw_boot_data->magic[0] != BOOT_DATA_MAGIC0 || - fw_boot_data->magic[1] != BOOT_DATA_MAGIC1) - continue; - - memset(&bl_boot_data.payload, 0, BOOT_DATA_PAYLOAD_SIZE); - bl_boot_data.boot_volume = boot_volume; - - memset(fw_boot_data->payload, 0, fw_boot_data->length); - /* determine maximum bytes we can write to firmware - BOOT_DATA_PAYLOAD_SIZE is the size the bootloader expects */ - payload_len = MIN(BOOT_DATA_PAYLOAD_SIZE, fw_boot_data->length); - fw_boot_data->length = payload_len; - /* copy data to FIRMWARE bootdata struct */ - memcpy(fw_boot_data->payload, &bl_boot_data.payload, payload_len); - /* crc will be used within the firmware to check validity of bootdata */ - fw_boot_data->crc = crc_32(fw_boot_data->payload, payload_len, 0xffffffff); - break; - - } - return payload_len; -} +#include "multiboot.h" #endif /* HAVE_BOOTDATA */ -#ifdef HAVE_MULTIBOOT /* defined by config.h */ -/* Check in root of this <volume> for rockbox_main.<playername> - * if this file empty or there is a single slash '/' - * buf = '<volume#>/<rootdir>/<firmware(name)>\0' - * If instead '/<*DIRECTORY*>' is supplied - * addpath will be set to this DIRECTORY buf = - * '/<volume#>/addpath/<rootdir>/<firmware(name)>\0' - * On error returns Negative number or 0 - * On success returns bytes from snprintf - * and generated path will be placed in buf - * note: if supplied buffer is too small return will be - * the number of bytes that would have been written - */ -int get_redirect_dir(char* buf, int buffer_size, int volume, - const char* rootdir, const char* firmware) -{ - int fd; - int f_offset; - char add_path[MAX_PATH]; - /* Check in root of volume for rockbox_main.<playername> redirect */ - snprintf(add_path, sizeof(add_path), "/<%d>/"BOOT_REDIR, volume); - fd = open(add_path, O_RDONLY); - if (fd < 0) - return EFILE_NOT_FOUND; - - /*clear add_path for re-use*/ - memset(add_path, 0, sizeof(add_path)); - f_offset = read(fd, add_path,sizeof(add_path)); - close(fd); - - for(int i = f_offset - 1;i > 0; i--) - { - /* strip control chars < SPACE or all if path doesn't start with '/' */ - if (add_path[i] < 0x20 || add_path[0] != '/') - add_path[i] = '\0'; - } - /* if '/add_path' is specified in rockbox_main.<playername> - path is /<vol#>/add_path/rootdir/firmwarename - if add_path is empty or '/' is missing from beginning - path is /<vol#>/rootdir/firmwarename - */ - return snprintf(buf, buffer_size, "/<%d>%s/%s/%s", volume, add_path, - rootdir, firmware); -} -#endif /* HAVE_MULTIBOOT */ - static inline unsigned int le2int(unsigned char* buf) { int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; 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/rk27xx/lcdif-rk27xx.c b/firmware/target/arm/rk27xx/lcdif-rk27xx.c index e6af0d978a..618b476480 100644 --- a/firmware/target/arm/rk27xx/lcdif-rk27xx.c +++ b/firmware/target/arm/rk27xx/lcdif-rk27xx.c @@ -198,9 +198,10 @@ static void create_llp(int x, int y, int width, int height) width = width>>1; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* build LLPs */ for (i=0; i<height; i++) - llp_setup((void *)FBADDR(x,y+i), + llp_setup((void *)fbaddr(x,y+i), (void*)(LCD_BUFF+((i%4)*4*width)), &(scr_llp[i]), width); 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/debug-s5l8700.c b/firmware/target/arm/s5l8700/debug-s5l8700.c index ecb15df5d0..c42eac0438 100644 --- a/firmware/target/arm/s5l8700/debug-s5l8700.c +++ b/firmware/target/arm/s5l8700/debug-s5l8700.c @@ -112,7 +112,7 @@ bool dbg_hw_info(void) _DEBUG_PRINTF("PMU:"); for(i=0;i<7;i++) { - char *device[] = {"(unknown)", + static const char * const device[] = {"(unknown)", "(CLICKWHEEL)", "(LCD)", "(AUDIO)", @@ -139,7 +139,7 @@ bool dbg_hw_info(void) char line_cfg[4]; int abr_stat; uint32_t abr_cnt; - char *abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"}; + static const char * const abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"}; uartc_port_get_line_info(&ser_port, &tx_stat, &rx_stat, &tx_speed, &rx_speed, line_cfg); 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/s5l8700/yps3/lcd-yps3.c b/firmware/target/arm/s5l8700/yps3/lcd-yps3.c index a9830bca57..eec11e34b8 100644 --- a/firmware/target/arm/s5l8700/yps3/lcd-yps3.c +++ b/firmware/target/arm/s5l8700/yps3/lcd-yps3.c @@ -299,14 +299,15 @@ void lcd_update_rect(int x, int y, int width, int height) { fb_data* p; int h, w; - + + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; if (lcd_type == 1) { /* TODO implement and test */ lcd_set_window1(x, y, width, height); lcd_set_position1(x, y); - + for (h = 0; h < height; h++) { - p = FBADDR(0,y); + p = fbaddr(0,y); for (w = 0; w < LCD_WIDTH; w++) { while (LCD_STATUS & 0x10); LCD_WDATA = *p++; @@ -317,9 +318,9 @@ void lcd_update_rect(int x, int y, int width, int height) else { lcd_set_window2(x, y, width, height); lcd_set_position2(x, y); - + for (h = 0; h < height; h++) { - p = FBADDR(x,y); + p = fbaddr(x,y); for (w = 0; w < width; w++) { while (LCD_STATUS & 0x10); LCD_WDATA = *p++; diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c index 68b16f39f7..26b8e557a0 100644 --- a/firmware/target/arm/s5l8702/debug-s5l8702.c +++ b/firmware/target/arm/s5l8702/debug-s5l8702.c @@ -104,7 +104,7 @@ bool dbg_hw_info(void) _DEBUG_PRINTF("PMU:"); for(i=0;i<7;i++) { - char *device[] = {"unknown", + static const char *const device[] = {"unknown", "unknown", "LCD", "AUDIO", @@ -157,7 +157,7 @@ bool dbg_hw_info(void) char line_cfg[4]; int abr_stat; uint32_t abr_cnt; - char *abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"}; + static const char * const abrstatus[] = {"Idle", "Launched", "Counting", "Abnormal"}; uartc_port_get_line_info(&ser_port, &tx_stat, &rx_stat, &tx_speed, &rx_speed, line_cfg); 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/samsung/yh920/lcd-yh920.c b/firmware/target/arm/samsung/yh920/lcd-yh920.c index 06aa3d718d..6a579f382a 100644 --- a/firmware/target/arm/samsung/yh920/lcd-yh920.c +++ b/firmware/target/arm/samsung/yh920/lcd-yh920.c @@ -253,13 +253,14 @@ void lcd_update_rect(int x, int y, int width, int height) if(ymax >= LCD_FBHEIGHT) ymax = LCD_FBHEIGHT-1; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectange bitmap to hardware */ for (; y <= ymax; y++) { lcd_write_reg(LCD_CNTL_PAGE, y); lcd_write_reg(LCD_CNTL_COLUMN, x); - addr = FBADDR(x,y); + addr = fbaddr(x,y); lcd_send_cmd(LCD_CNTL_DATA_WRITE); lcd_write_data(addr, width); 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/coldfire/iaudio/m3/lcd-m3.c b/firmware/target/coldfire/iaudio/m3/lcd-m3.c index 3da608a0ef..5e84cbacd3 100644 --- a/firmware/target/coldfire/iaudio/m3/lcd-m3.c +++ b/firmware/target/coldfire/iaudio/m3/lcd-m3.c @@ -258,6 +258,7 @@ void lcd_update(void) int y; if (initialized) { + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; for(y = 0;y < LCD_FBHEIGHT;y++) { /* Copy display bitmap to hardware. @@ -266,7 +267,7 @@ void lcd_update(void) have to update one page at a time. */ lcd_write_command(LCD_SET_PAGE | (y > 5 ? y + 2 : y)); lcd_write_command_e(LCD_SET_COLUMN | 0, 0); - lcd_write_data(FBADDR(0, y), LCD_WIDTH); + lcd_write_data(fbaddr(0,y), LCD_WIDTH); } } } @@ -289,6 +290,7 @@ void lcd_update_rect(int x, int y, int width, int height) if(ymax >= LCD_FBHEIGHT) ymax = LCD_FBHEIGHT-1; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectangle bitmap to hardware COM48-COM63 are not connected, so we need to skip those */ for (; y <= ymax; y++) @@ -296,7 +298,7 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_command(LCD_SET_PAGE | ((y > 5 ? y + 2 : y) & 0xf)); lcd_write_command_e(LCD_SET_COLUMN | ((x >> 4) & 0xf), x & 0xf); - lcd_write_data(FBADDR(x,y), width); + lcd_write_data(fbaddr(x,y), width); } } } diff --git a/firmware/target/coldfire/iaudio/m5/lcd-m5.c b/firmware/target/coldfire/iaudio/m5/lcd-m5.c index 8f022adf96..35fd173f18 100644 --- a/firmware/target/coldfire/iaudio/m5/lcd-m5.c +++ b/firmware/target/coldfire/iaudio/m5/lcd-m5.c @@ -200,6 +200,7 @@ void lcd_update(void) { int y; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy display bitmap to hardware */ for (y = 0; y < LCD_FBHEIGHT; y++) { @@ -207,7 +208,7 @@ void lcd_update(void) lcd_write_command_ex(LCD_CNTL_COLUMN, 0, -1); lcd_write_command(LCD_CNTL_DATA_WRITE); - lcd_write_data (FBADDR(0, y), LCD_WIDTH); + lcd_write_data (fbaddr(0,y), LCD_WIDTH); } } @@ -228,6 +229,7 @@ void lcd_update_rect(int x, int y, int width, int height) if(ymax >= LCD_FBHEIGHT) ymax = LCD_FBHEIGHT-1; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectange bitmap to hardware */ for (; y <= ymax; y++) { @@ -235,6 +237,6 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1); lcd_write_command(LCD_CNTL_DATA_WRITE); - lcd_write_data (FBADDR(x,y), width); + lcd_write_data (fbaddr(x,y), width); } } diff --git a/firmware/target/coldfire/iriver/h100/lcd-h100.c b/firmware/target/coldfire/iriver/h100/lcd-h100.c index b13751b9eb..b6eea1dfa3 100644 --- a/firmware/target/coldfire/iriver/h100/lcd-h100.c +++ b/firmware/target/coldfire/iriver/h100/lcd-h100.c @@ -209,6 +209,7 @@ void lcd_update(void) { int y; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy display bitmap to hardware */ for (y = 0; y < LCD_FBHEIGHT; y++) { @@ -216,7 +217,7 @@ void lcd_update(void) lcd_write_command_ex(LCD_CNTL_COLUMN, 0, -1); lcd_write_command(LCD_CNTL_DATA_WRITE); - lcd_write_data (FBADDR(0, y), LCD_WIDTH); + lcd_write_data (fbaddr(0,y), LCD_WIDTH); } } @@ -237,6 +238,7 @@ void lcd_update_rect(int x, int y, int width, int height) if(ymax >= LCD_FBHEIGHT) ymax = LCD_FBHEIGHT-1; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectange bitmap to hardware */ for (; y <= ymax; y++) { @@ -244,6 +246,6 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1); lcd_write_command(LCD_CNTL_DATA_WRITE); - lcd_write_data (FBADDR(x,y), width); + lcd_write_data (fbaddr(x,y), width); } } diff --git a/firmware/target/coldfire/mpio/hd300/lcd-hd300.c b/firmware/target/coldfire/mpio/hd300/lcd-hd300.c index 509ed4cd53..9cff9cd712 100644 --- a/firmware/target/coldfire/mpio/hd300/lcd-hd300.c +++ b/firmware/target/coldfire/mpio/hd300/lcd-hd300.c @@ -231,6 +231,7 @@ void lcd_update_rect(int x, int y, int width, int height) if(ymax >= LCD_FBHEIGHT) ymax = LCD_FBHEIGHT-1; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectange bitmap to hardware */ for (; y <= ymax; y++) { @@ -238,6 +239,6 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1); lcd_write_command(LCD_CNTL_DATA_WRITE); - lcd_write_data (FBADDR(x,y), width); + lcd_write_data (fbaddr(x,y), width); } } 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/mips/ingenic_x1000/fiiom3k/powermgmt-target.h b/firmware/target/hosted/ibasso/dx50/adc-target.h index e69de29bb2..e69de29bb2 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/powermgmt-target.h +++ b/firmware/target/hosted/ibasso/dx50/adc-target.h diff --git a/firmware/target/hosted/ibasso/dx90/adc-target.h b/firmware/target/hosted/ibasso/dx90/adc-target.h new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/firmware/target/hosted/ibasso/dx90/adc-target.h diff --git a/firmware/target/hosted/ibasso/pcm-ibasso.c b/firmware/target/hosted/ibasso/pcm-ibasso.c index 5c68ded3e1..889386b7c6 100644 --- a/firmware/target/hosted/ibasso/pcm-ibasso.c +++ b/firmware/target/hosted/ibasso/pcm-ibasso.c @@ -123,7 +123,7 @@ static void* pcm_thread_run(void* nothing) /* https://github.com/tinyalsa/tinyalsa/blob/master/tinypcminfo.c */ -static const char* format_lookup[] = +static const char* const format_lookup[] = { /*[0] =*/ "S8", "U8", diff --git a/firmware/target/hosted/ibasso/sysfs-ibasso.c b/firmware/target/hosted/ibasso/sysfs-ibasso.c index 8f62e3fec2..e3a0f911af 100644 --- a/firmware/target/hosted/ibasso/sysfs-ibasso.c +++ b/firmware/target/hosted/ibasso/sysfs-ibasso.c @@ -32,7 +32,7 @@ #include "sysfs-ibasso.h" -static const char* SYSFS_PATHS[] = +static const char* const SYSFS_PATHS[] = { /* SYSFS_DX50_CODEC_VOLUME */ "/dev/codec_volume", diff --git a/firmware/target/hosted/rolo.c b/firmware/target/hosted/rolo.c index 04b21d553e..dfe483c964 100644 --- a/firmware/target/hosted/rolo.c +++ b/firmware/target/hosted/rolo.c @@ -37,12 +37,6 @@ //#define LOGF_ENABLE #include "logf.h" -#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR) -#include "bootdata.h" -#include "crc32.h" -extern int write_bootdata(unsigned char* buf, int len, unsigned int boot_volume); /*rb-loader.c*/ -#endif - static void rolo_error(const char *text, const char *text2) { lcd_clear_display(); @@ -72,16 +66,6 @@ int rolo_load(const char* filename) audio_stop(); -#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR) - /* write the bootdata as if rolo were the bootloader */ - unsigned int crc = 0; - if (strcmp(filename, BOOTDIR "/" BOOTFILE) == 0) - crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff); - - if(crc > 0 && crc == boot_data.crc) - write_bootdata(filebuf, filebuf_size, boot_data.boot_volume); /* rb-loader.c */ -#endif - #ifdef HAVE_STORAGE_FLUSH lcd_puts(0, 2, "Flushing storage buffers"); lcd_update(); 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/sim-ui-defines.h b/firmware/target/hosted/sdl/sim-ui-defines.h index baba357ccc..7d60deac34 100644 --- a/firmware/target/hosted/sdl/sim-ui-defines.h +++ b/firmware/target/hosted/sdl/sim-ui-defines.h @@ -523,10 +523,10 @@ #elif defined(FIIO_M3K) || defined(FIIO_M3K_LINUX) #define UI_TITLE "FiiO M3K" -#define UI_WIDTH 287 /* width of GUI window */ -#define UI_HEIGHT 589 /* height of GUI window */ -#define UI_LCD_POSX 25 -#define UI_LCD_POSY 15 +#define UI_WIDTH 334 /* width of GUI window */ +#define UI_HEIGHT 684 /* height of GUI window */ +#define UI_LCD_POSX 49 +#define UI_LCD_POSY 37 #elif defined(SHANLING_Q1) 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/hosted/system-hosted.c b/firmware/target/hosted/system-hosted.c index ce47fd5f5c..c4ae5a404f 100644 --- a/firmware/target/hosted/system-hosted.c +++ b/firmware/target/hosted/system-hosted.c @@ -90,6 +90,7 @@ static void sig_handler(int sig, siginfo_t *siginfo, void *context) void power_off(void) { backlight_hw_off(); + sync(); system("/sbin/poweroff"); while (1); /* halt */ } diff --git a/firmware/target/hosted/usb-hiby.c b/firmware/target/hosted/usb-hiby.c index b82fa5c4ce..050c86e446 100644 --- a/firmware/target/hosted/usb-hiby.c +++ b/firmware/target/hosted/usb-hiby.c @@ -63,8 +63,8 @@ void usb_enable(bool on) */ int disk_mount_all(void) { - const char *dev[] = {"/dev/mmcblk0p1", "/dev/mmcblk0"}; - const char *fs[] = {"vfat", "exfat"}; + const char * const dev[] = {"/dev/mmcblk0p1", "/dev/mmcblk0"}; + const char * const fs[] = {"vfat", "exfat"}; sysfs_set_string("/sys/class/android_usb/android0/f_mass_storage/lun/file", ""); 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 258a5c02fc..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 - ssnop - - - /* - * 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 + move ra, zero /* init backtrace root */ -_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_jz47xx/xduoo_x3/lcd-xduoo_x3.c b/firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c index 47b646be34..2c1c3a226e 100644 --- a/firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c +++ b/firmware/target/mips/ingenic_jz47xx/xduoo_x3/lcd-xduoo_x3.c @@ -532,6 +532,7 @@ void lcd_update(void) const int column_high = get_column_high_byte(0); const int column_low = get_column_low_byte(0); + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy display bitmap to hardware */ for (y = 0; y < LCD_FBHEIGHT; y++) { @@ -542,7 +543,7 @@ void lcd_update(void) (column_low) ); - lcd_write_data (FBADDR(0, y), LCD_WIDTH); + lcd_write_data (fbaddr(0,y), LCD_WIDTH); } } @@ -586,6 +587,7 @@ void lcd_update_rect(int x, int y, int width, int height) ymax = (y + height-1) >> 3; y >>= 3; + void* (*fbaddr)(int x, int y) = FB_CURRENTVP_BUFFER->get_address_fn; /* Copy specified rectange bitmap to hardware */ for (; y <= ymax; y++) { @@ -596,6 +598,6 @@ void lcd_update_rect(int x, int y, int width, int height) (column_low) ); - lcd_write_data (FBADDR(x,y), width); + lcd_write_data (fbaddr(x,y), width); } } diff --git a/firmware/target/mips/ingenic_x1000/app.lds b/firmware/target/mips/ingenic_x1000/app.lds index 26b2854728..fe06e1cd8d 100644 --- a/firmware/target/mips/ingenic_x1000/app.lds +++ b/firmware/target/mips/ingenic_x1000/app.lds @@ -5,6 +5,19 @@ 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 */ #define ENDAUDIOADDR (X1000_DRAM_END - PLUGIN_BUFFER_SIZE - CODEC_SIZE) @@ -12,20 +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); @@ -41,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 */ @@ -58,9 +90,29 @@ SECTIONS *(.irodata); *(.idata); _iramend = .; - } > IRAM + } > IRAM AT> DRAM _iramcopy = LOADADDR(.iram); + .tcsm : + { + _tcsmstart = .; + KEEP(*(.tcsm*)); + _tcsmend = .; + } > 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) : { @@ -73,7 +125,7 @@ SECTIONS _irqstackend = .; } > IRAM - .bss (NOLOAD) : + .bss _noloaddram (NOLOAD) : { _bssbegin = .; *(.sbss*); @@ -88,10 +140,8 @@ SECTIONS { . = ALIGN(4); audiobuffer = .; - loadbuffer = .; } > DRAM - loadbufferend = ENDAUDIOADDR; audiobufend = ENDAUDIOADDR; codecbuf = ENDAUDIOADDR; pluginbuf = ENDCODECADDR; diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.c b/firmware/target/mips/ingenic_x1000/boot-x1000.c new file mode 100644 index 0000000000..2f2714c67a --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.c @@ -0,0 +1,285 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "usb.h" +#include "boot-x1000.h" +#include "nand-x1000.h" +#include "gpio-x1000.h" +#include "clk-x1000.h" +#include "x1000/cpm.h" +#include "x1000/lcd.h" +#include "x1000/uart.h" +#include <string.h> + +#define HDR_BEGIN 128 /* header must begin within this many bytes */ +#define HDR_LEN 256 /* header length cannot exceed this */ + +/* search for header value, label must be a 4-character string. + * Returns the found value or 0 if the label wasn't found. */ +static uint32_t search_header(const unsigned char* source, size_t length, + const char* label) +{ + size_t search_len = MIN(length, HDR_BEGIN); + if(search_len < 8) + return 0; + search_len -= 7; + + /* find the beginning marker */ + size_t i; + for(i = 8; i < search_len; i += 4) + if(!memcmp(&source[i], "BEGINHDR", 8)) + break; + if(i >= search_len) + return 0; + i += 8; + + /* search within the header */ + search_len = MIN(length, i + HDR_LEN) - 7; + for(; i < search_len; i += 8) { + if(!memcmp(&source[i], "ENDH", 4)) { + break; + } else if(!memcmp(&source[i], label, 4)) { + i += 4; + /* read little-endian value */ + uint32_t ret = source[i]; + ret |= source[i+1] << 8; + ret |= source[i+2] << 16; + ret |= source[i+3] << 24; + return ret; + } + } + + return 0; +} + +static void iram_memmove(void* dest, const void* source, size_t length) + __attribute__((section(".icode"))); + +static void iram_memmove(void* dest, const void* source, size_t length) +{ + unsigned char* d = dest; + const unsigned char* s = source; + + if(s < d && d < s + length) { + d += length; + s += length; + while(length--) + *--d = *--s; + } else { + while(length--) + *d++ = *s++; + } +} + +void x1000_boot_rockbox(const void* source, size_t length) +{ + uint32_t load_addr = search_header(source, length, "LOAD"); + if(!load_addr) + load_addr = X1000_STANDARD_DRAM_BASE; + + disable_irq(); + + /* --- Beyond this point, do not call into DRAM --- */ + + iram_memmove((void*)load_addr, source, length); + commit_discard_idcache(); + + typedef void(*entry_fn)(void); + entry_fn fn = (entry_fn)load_addr; + fn(); + while(1); +} + +void x1000_boot_linux(const void* source, size_t length, + void* load, void* entry, const char* args) +{ + 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 --- */ + + void* safe_mem = (void*)X1000_IRAM_END; + + /* copy argument string to a safe location */ + char* args_copy = safe_mem + 32; + iram_memmove(args_copy, args, args_len+1); + + /* generate argv array */ + char** argv = safe_mem; + argv[0] = NULL; + argv[1] = args_copy; + + iram_memmove(load, source, length); + commit_discard_idcache(); + + typedef void(*entry_fn)(long, char**, long, long); + entry_fn fn = (entry_fn)entry; + fn(2, argv, 0, 0); + while(1); +} + +void rolo_restart(const unsigned char* source, unsigned char* dest, int length) +{ + (void)dest; + x1000_boot_rockbox(source, length); +} + +void x1000_dualboot_cleanup(void) +{ + /* - disable all LCD interrupts since the M3K can't cope with them + * - disable BEDN bit since it creates garbled graphics on the Q1 */ + jz_writef(CPM_CLKGR, LCD(0)); + jz_writef(LCD_CTRL, BEDN(0), EOFM(0), SOFM(0), IFUM(0), QDM(0)); + jz_writef(CPM_CLKGR, LCD(1)); + +#if defined(FIIO_M3K) || defined(EROS_QN) + /* + * Need to bring up MPLL before booting Linux + * (Doesn't apply to Q1 since it sticks with the default Ingenic config) + */ + + /* 24 MHz * 25 = 600 MHz */ + jz_writef(CPM_MPCR, BS(1), PLLM(25 - 1), PLLN(0), PLLOD(0), ENABLE(1)); + while(jz_readf(CPM_MPCR, ON) == 0); + + /* 600 MHz / 3 = 200 MHz */ + clk_set_ddr(X1000_CLK_MPLL, 3); + + clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | + CLKMUX_CPU(SCLK_A) | + CLKMUX_AHB0(MPLL) | + CLKMUX_AHB2(MPLL)); + clk_set_ccr_div(CLKDIV_CPU(1) | /* 1008 MHz */ + CLKDIV_L2(2) | /* 504 MHz */ + CLKDIV_AHB0(3) | /* 200 MHz */ + CLKDIV_AHB2(3) | /* 200 MHz */ + CLKDIV_PCLK(6)); /* 100 MHz */ +#endif +} + +void x1000_dualboot_init_clocktree(void) +{ + /* Make sure these are gated to match the OF behavior. */ + jz_writef(CPM_CLKGR, PCM(1), MAC(1), LCD(1), MSC0(1), MSC1(1), OTG(1), CIM(1)); + + /* Set clock sources, and make sure every clock starts out stopped */ + jz_writef(CPM_I2SCDR, CS_V(EXCLK)); + jz_writef(CPM_PCMCDR, CS_V(EXCLK)); + + jz_writef(CPM_MACCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); + while(jz_readf(CPM_MACCDR, BUSY)); + + jz_writef(CPM_LPCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); + while(jz_readf(CPM_LPCDR, BUSY)); + + jz_writef(CPM_MSC0CDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); + while(jz_readf(CPM_MSC0CDR, BUSY)); + + jz_writef(CPM_MSC1CDR, CE(1), STOP(1), CLKDIV(0xfe)); + while(jz_readf(CPM_MSC1CDR, BUSY)); + + jz_writef(CPM_CIMCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); + while(jz_readf(CPM_CIMCDR, BUSY)); + + jz_writef(CPM_USBCDR, CLKSRC_V(EXCLK), CE(1), STOP(1)); + while(jz_readf(CPM_USBCDR, BUSY)); +} + +void x1000_dualboot_init_uart2(void) +{ + /* Ungate the clock and select UART2 device function */ + jz_writef(CPM_CLKGR, UART2(0)); + gpioz_configure(GPIO_C, 3 << 30, GPIOF_DEVICE(1)); + + /* Disable all interrupts */ + jz_write(UART_UIER(2), 0); + + /* FIFO configuration */ + jz_overwritef(UART_UFCR(2), + RDTR(3), /* FIFO trigger level = 60? */ + UME(0), /* UART module disable */ + DME(1), /* DMA mode enable? */ + TFRT(1), /* transmit FIFO reset */ + RFRT(1), /* receive FIFO reset */ + FME(1)); /* FIFO mode enable */ + + /* IR mode configuration */ + jz_overwritef(UART_ISR(2), + RDPL(1), /* Zero is negative pulse for receive */ + TDPL(1), /* ... and for transmit */ + XMODE(1), /* Pulse width 1.6us */ + RCVEIR(0), /* Disable IR for recieve */ + XMITIR(0)); /* ... and for transmit */ + + /* Line configuration */ + jz_overwritef(UART_ULCR(2), DLAB(0), + WLS_V(8BITS), /* 8 bit words */ + SBLS_V(1_STOP_BIT), /* 1 stop bit */ + PARE(0), /* no parity */ + SBK(0)); /* don't set break */ + + /* Set the baud rate... not too sure how this works. (Docs unclear!) */ + const unsigned divisor = 0x0004; + jz_writef(UART_ULCR(2), DLAB(1)); + jz_write(UART_UDLHR(2), (divisor >> 8) & 0xff); + jz_write(UART_UDLLR(2), divisor & 0xff); + jz_write(UART_UMR(2), 16); + jz_write(UART_UACR(2), 0); + jz_writef(UART_ULCR(2), DLAB(0)); + + /* Enable UART */ + jz_overwritef(UART_UFCR(2), + RDTR(0), /* FIFO trigger level = 1 */ + DME(0), /* DMA mode disable */ + UME(1), /* UART module enable */ + TFRT(1), /* transmit FIFO reset */ + RFRT(1), /* receive FIFO reset */ + FME(1)); /* FIFO mode enable */ +} + +int x1000_dualboot_load_pdma_fw(void) +{ + struct nand_drv* n = nand_init(); + nand_lock(n); + + int ret = nand_open(n); + if(ret != NAND_SUCCESS) + goto err_unlock; + + /* NOTE: hardcoded address is used by all current targets */ + jz_writef(CPM_CLKGR, PDMA(0)); + ret = nand_read_bytes(n, 0x4000, 0x2000, (void*)0xb3422000); + + nand_close(n); + err_unlock: + nand_unlock(n); + return ret; +} diff --git a/firmware/target/mips/ingenic_x1000/boot-x1000.h b/firmware/target/mips/ingenic_x1000/boot-x1000.h index 400eb93dc1..eb476c513d 100644 --- a/firmware/target/mips/ingenic_x1000/boot-x1000.h +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.h @@ -24,18 +24,10 @@ #include "x1000/cpm.h" #include <stdbool.h> +#include <stdint.h> +#include <stddef.h> enum { - BOOT_OPTION_ROCKBOX = 0, - BOOT_OPTION_OFW_PLAYER, - BOOT_OPTION_OFW_RECOVERY, -}; - -enum { - /* 3 bits to store the boot option selected by the SPL */ - BOOT_OPTION_MASK = 0x7, - BOOT_OPTION_SHIFT = 0, - /* Set after running clk_init() and setting up system clocks */ BOOT_FLAG_CLK_INIT = (1 << 31), @@ -43,6 +35,18 @@ enum { BOOT_FLAG_USB_BOOT = (1 << 30), }; +void x1000_boot_rockbox(const void* source, size_t length) + __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.x1000_boot_linux"))); + +/* dual boot support code */ +void x1000_dualboot_cleanup(void); +void x1000_dualboot_init_clocktree(void); +void x1000_dualboot_init_uart2(void); +int x1000_dualboot_load_pdma_fw(void); + /* Note: these functions are inlined to minimize SPL code size. * They are private to the X1000 early boot code anyway... */ @@ -74,18 +78,4 @@ static inline void clr_boot_flag(uint32_t bit) cpm_scratch_set(REG_CPM_SCRATCH & ~bit); } -static inline void set_boot_option(int opt) -{ - uint32_t r = REG_CPM_SCRATCH; - r &= ~(BOOT_OPTION_MASK << BOOT_OPTION_SHIFT); - r |= (opt & BOOT_OPTION_MASK) << BOOT_OPTION_SHIFT; - cpm_scratch_set(r); -} - -static inline int get_boot_option(void) -{ - uint32_t r = REG_CPM_SCRATCH; - return (r >> BOOT_OPTION_SHIFT) & BOOT_OPTION_MASK; -} - #endif /* __BOOT_X1000_H__ */ diff --git a/firmware/target/mips/ingenic_x1000/clk-x1000.c b/firmware/target/mips/ingenic_x1000/clk-x1000.c index 4988e7c3bf..e3b0f792bb 100644 --- a/firmware/target/mips/ingenic_x1000/clk-x1000.c +++ b/firmware/target/mips/ingenic_x1000/clk-x1000.c @@ -265,39 +265,36 @@ void clk_init(void) jz_writef(CPM_APCR, BS(1), PLLM(42 - 1), PLLN(0), PLLOD(0), ENABLE(1)); while(jz_readf(CPM_APCR, ON) == 0); -#if (defined(FIIO_M3K) || defined(EROS_QN)) +#if defined(FIIO_M3K) || defined(EROS_QN) /* TODO: Allow targets to define their clock frequencies in their config, * instead of having this be a random special case. */ - if(get_boot_option() == BOOT_OPTION_ROCKBOX) { - clk_set_ccr_div(CLKDIV_CPU(1) | /* 1008 MHz */ - CLKDIV_L2(2) | /* 504 MHz */ - CLKDIV_AHB0(5) | /* 201.6 MHz */ - CLKDIV_AHB2(5) | /* 201.6 MHz */ - CLKDIV_PCLK(10)); /* 100.8 MHz */ - clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | - CLKMUX_CPU(SCLK_A) | - CLKMUX_AHB0(SCLK_A) | - CLKMUX_AHB2(SCLK_A)); - - /* DDR to 201.6 MHz */ - clk_set_ddr(X1000_CLK_SCLK_A, 5); - - /* Disable MPLL */ - jz_writef(CPM_MPCR, ENABLE(0)); - while(jz_readf(CPM_MPCR, ON)); - } else { -#endif - clk_set_ccr_div(CLKDIV_CPU(1) | /* 1008 MHz */ - CLKDIV_L2(2) | /* 504 MHz */ - CLKDIV_AHB0(3) | /* 200 MHz */ - CLKDIV_AHB2(3) | /* 200 MHz */ - CLKDIV_PCLK(6)); /* 100 MHz */ - clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | - CLKMUX_CPU(SCLK_A) | - CLKMUX_AHB0(MPLL) | - CLKMUX_AHB2(MPLL)); -#if (defined(FIIO_M3K) || defined(EROS_QN)) - } + clk_set_ccr_div(CLKDIV_CPU(1) | /* 1008 MHz */ + CLKDIV_L2(2) | /* 504 MHz */ + CLKDIV_AHB0(5) | /* 201.6 MHz */ + CLKDIV_AHB2(5) | /* 201.6 MHz */ + CLKDIV_PCLK(10)); /* 100.8 MHz */ + clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | + CLKMUX_CPU(SCLK_A) | + CLKMUX_AHB0(SCLK_A) | + CLKMUX_AHB2(SCLK_A)); + + /* DDR to 201.6 MHz */ + clk_set_ddr(X1000_CLK_SCLK_A, 5); + + /* Disable MPLL */ + jz_writef(CPM_MPCR, ENABLE(0)); + while(jz_readf(CPM_MPCR, ON)); +#else + /* Default configuration matching the Ingenic OF */ + clk_set_ccr_div(CLKDIV_CPU(1) | /* 1008 MHz */ + CLKDIV_L2(2) | /* 504 MHz */ + CLKDIV_AHB0(3) | /* 200 MHz */ + CLKDIV_AHB2(3) | /* 200 MHz */ + CLKDIV_PCLK(6)); /* 100 MHz */ + clk_set_ccr_mux(CLKMUX_SCLK_A(APLL) | + CLKMUX_CPU(SCLK_A) | + CLKMUX_AHB0(MPLL) | + CLKMUX_AHB2(MPLL)); #endif /* mark that clocks have been initialized */ diff --git a/firmware/target/mips/ingenic_x1000/clk-x1000.h b/firmware/target/mips/ingenic_x1000/clk-x1000.h index e19c56d0ba..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,26 +68,26 @@ 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 */ -inline uint32_t clk_calc_div(uint32_t infreq, uint32_t outfreq) +static inline uint32_t clk_calc_div(uint32_t infreq, uint32_t outfreq) { return (infreq + (outfreq - 1)) / outfreq; } /* Returns the smallest n such that (infreq >> n) <= outfreq */ -inline uint32_t clk_calc_shift(uint32_t infreq, uint32_t outfreq) +static inline uint32_t clk_calc_shift(uint32_t infreq, uint32_t outfreq) { uint32_t div = clk_calc_div(infreq, outfreq); return __builtin_clz(div) ^ 31; diff --git a/firmware/target/mips/ingenic_x1000/crt0.S b/firmware/target/mips/ingenic_x1000/crt0.S index 304f8d682f..6c0942b0db 100644 --- a/firmware/target/mips/ingenic_x1000/crt0.S +++ b/firmware/target/mips/ingenic_x1000/crt0.S @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2021 Aidan MacDonald + * Copyright (C) 2021-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 @@ -21,10 +21,12 @@ #include "config.h" #include "mips.h" +#include "bootdata.h" .text .extern main .extern system_early_init + .extern _loadaddress .global _start .set push @@ -32,204 +34,126 @@ .set noreorder .set noat - .section .init.text + .section .startup.text,"ax",%progbits _start: - /* Cache init */ - li v0, 0x80000000 - ori v1, v0, 0x4000 - mtc0 zero, C0_TAGLO - mtc0 zero, C0_TAGHI -_cache_loop: - cache ICIndexStTag, 0(v0) - cache DCIndexStTag, 0(v0) - addiu v0, v0, 32 - bne v0, v1, _cache_loop - nop + b _realstart + nop + + /* Header entries are 4-byte string labels (not null terminated!) followed + * by 4-byte values. Header should begin in the first 128 bytes and should + * be no more than 256 bytes in length. */ +_header: + .ascii "BEGINHDR" /* beginning of header */ + .ascii "LOAD" + .word _loadaddress + .ascii "ENDH" /* end of header structure */ + +#ifndef BOOTLOADER + /* Multiboot support header; this is not part of the above header. */ + put_boot_data_here +#endif + +_realstart: + /* Save bootloader arguments. */ + move s0, a0 + move s1, a1 + move s2, a2 + move s3, a3 - /* Invalidate BTB */ - mfc0 v0, C0_Config, 7 + /* Copy IRAM from BSS to low memory. */ + la a0, _iramcopy + la a1, _iramstart + la a2, _iramend + bal _copy nop - ori v0, v0, 2 - mtc0 v0, C0_Config, 7 + + /* Copy TCSM from BSS */ + la a0, _tcsmcopy + la a1, _tcsmstart + la a2, _tcsmend + bal _copy nop - /* Copy IRAM from BSS to low memory. */ - la t0, _iramcopy - la t1, _iramstart - la t2, _iramend -_iram_loop: - lw t3, 0(t0) - addiu t1, 4 - addiu t0, 4 - bne t1, t2, _iram_loop - sw t3, -4(t1) +#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 t0, _bssbegin - la t1, _bssend - beq t0, t1, _bss_done -_bss_loop: - addiu t0, 4 - bne t0, t1, _bss_loop - sw zero, -4(t0) -_bss_done: + la a0, _bssbegin + la a1, _bssend + bal _clear + move a2, $0 /* Set stack pointer and clear the stack */ la sp, stackend - la t0, stackbegin - li t1, 0xDEADBEEF -_stack_loop: - addiu t0, 4 - bne t0, sp, _stack_loop - sw t1, -4(t0) + la a0, stackbegin + li a2, 0xDEADBEEF + bal _clear + move a1, sp /* Clear the IRQ stack */ la k0, _irqstackend - la t0, _irqstackbegin -_irqstack_loop: - addiu t0, 4 - bne t0, k0, _irqstack_loop - sw t1, -4(t0) + la a0, _irqstackbegin + bal _clear + move a1, k0 - /* Jump to C code */ - jal system_early_init - nop - j main - nop - - /* Exception entry points */ - .section .vectors.1, "ax", %progbits - j tlb_refill_handler - nop - - .section .vectors.2, "ax", %progbits - j real_exception_handler - nop + /* Write back D-cache and invalidate I-cache */ + li v0, 0x80000000 + ori v1, v0, (0x4000 - 32) + mtc0 zero, C0_TAGLO + mtc0 zero, C0_TAGHI +1: + cache DCIndexWBInv, 0(v0) + cache ICIndexStTag, 0(v0) + bne v0, v1, 1b + addiu v0, v0, 32 - .section .vectors.3, "ax", %progbits - j real_exception_handler + /* Invalidate BTB */ + mfc0 v0, C0_Config, 7 nop - - .section .vectors.4, "ax", %progbits - j real_exception_handler + ori v0, v0, 2 + mtc0 v0, C0_Config, 7 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 + /* Jump to C code */ + jal system_early_init 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 + /* Restore bootloader arguments, jump to main. */ + move a0, s0 + move a1, s1 + move a2, s2 + move a3, s3 -_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 + j main + move ra, zero /* init backtrace root */ + + /* copy(void* src, void* dst, void* dst_end) */ +_copy: + beq a1, a2, 1f + addiu a1, 4 + lw t0, 0(a0) + addiu a0, 4 + b _copy + sw t0, -4(a1) +1: + jr ra + nop + + /* clear(void* dst, void* dst_end, int value) */ +_clear: + beq a0, a1, 1f + addiu a0, 4 + b _clear + sw a2, -4(a0) +1: + jr ra nop .set pop diff --git a/firmware/target/mips/ingenic_x1000/debug-x1000.c b/firmware/target/mips/ingenic_x1000/debug-x1000.c index 98b8f95fb5..827bb37855 100644 --- a/firmware/target/mips/ingenic_x1000/debug-x1000.c +++ b/firmware/target/mips/ingenic_x1000/debug-x1000.c @@ -118,12 +118,31 @@ static bool dbg_gpios(void) } 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) { do { lcd_clear_display(); lcd_putsf(0, 0, "TX underruns: %u", aic_tx_underruns); +#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/erosqnative/lcd-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/lcd-erosqnative.c index 073bddb8b4..0d43a3f010 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/lcd-erosqnative.c +++ b/firmware/target/mips/ingenic_x1000/erosqnative/lcd-erosqnative.c @@ -99,6 +99,20 @@ static const uint32_t erosqnative_lcd_cmd_enable[] = { /* Display On */ LCD_INSTR_CMD, 0x29, LCD_INSTR_UDELAY, 20000, + LCD_INSTR_END, +}; + +static const uint32_t erosqnative_lcd_of_compat_cmd[] = { + /* Pixel Format Set */ + LCD_INSTR_CMD, 0x3a, + LCD_INSTR_DAT, 0x66, /* 18 bpp */ + /* Exit Sleep */ + LCD_INSTR_CMD, 0x11, + LCD_INSTR_UDELAY, 120000, + /* Display On */ + LCD_INSTR_CMD, 0x29, + LCD_INSTR_UDELAY, 20000, + LCD_INSTR_END, }; /* sleep and wake copied directly from m3k */ @@ -179,6 +193,15 @@ void lcd_tgt_enable(bool enable) } } +void lcd_tgt_enable_of(bool enable) +{ + /* silence the unused parameter warning */ + if (enable) + {} + + lcd_exec_commands(&erosqnative_lcd_of_compat_cmd[0]); +} + void lcd_tgt_sleep(bool sleep) { if(sleep) diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c b/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c index 5573919aa2..ab6393a9fe 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c +++ b/firmware/target/mips/ingenic_x1000/erosqnative/power-erosqnative.c @@ -63,10 +63,15 @@ void power_init(void) /* Set lowest sample rate */ axp_adc_set_rate(AXP_ADC_RATE_25HZ); - /* Ensure battery voltage ADC is enabled */ - int bits = axp_adc_get_enabled(); - bits |= (1 << ADC_BATTERY_VOLTAGE); - axp_adc_set_enabled(bits); + /* Enable required ADCs */ + axp_adc_set_enabled( + (1 << ADC_BATTERY_VOLTAGE) | + (1 << ADC_CHARGE_CURRENT) | + (1 << ADC_DISCHARGE_CURRENT) | + (1 << ADC_VBUS_VOLTAGE) | + (1 << ADC_VBUS_CURRENT) | + (1 << ADC_INTERNAL_TEMP) | + (1 << ADC_APS_VOLTAGE)); /* Turn on all power outputs */ i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, @@ -78,11 +83,13 @@ void power_init(void) * OF's setting, although it's not strictly within the USB spec. */ axp_set_charge_current(780); +#ifdef BOOTLOADER /* Delay to give power outputs time to stabilize. * With the power thread delay, this can apparently go as low as 50, * Keeping a higher value here just to ensure the bootloader works * correctly. */ mdelay(200); +#endif } #ifdef HAVE_USB_CHARGING_ENABLE @@ -111,3 +118,13 @@ int _battery_voltage(void) { return axp_adc_read(ADC_BATTERY_VOLTAGE); } + +#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE +int _battery_current(void) +{ + if(charging_state()) + return axp_adc_read(ADC_CHARGE_CURRENT); + else + return axp_adc_read(ADC_DISCHARGE_CURRENT); +} +#endif diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c index 8528b803f7..9374d23a81 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/audiohw-fiiom3k.c @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2021 Aidan MacDonald + * Copyright (C) 2021-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 @@ -20,6 +20,7 @@ ****************************************************************************/ #include "audiohw.h" +#include "audio.h" #include "system.h" #include "pcm_sampr.h" #include "aic-x1000.h" @@ -27,8 +28,13 @@ #include "gpio-x1000.h" #include "logf.h" +static int cur_audio_source = AUDIO_SRC_PLAYBACK; +static int cur_vol_r = AK4376_MIN_VOLUME; +static int cur_vol_l = AK4376_MIN_VOLUME; +static int cur_recvol = 0; +static int cur_filter_roll_off = 0; static int cur_fsel = HW_FREQ_48; -static int cur_power_mode = 0; +static int cur_power_mode = SOUND_HIGH_POWER; static void set_ak_freqmode(void) { @@ -60,29 +66,138 @@ void audiohw_postinit(void) void audiohw_close(void) { - ak4376_close(); + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + ak4376_close(); + else if(cur_audio_source == AUDIO_SRC_MIC) + x1000_icodec_close(); +} + +void audio_set_output_source(int source) +{ + /* this is a no-op */ + (void)source; +} + +void audio_input_mux(int source, unsigned flags) +{ + (void)flags; + + if(source == cur_audio_source) + return; + + /* close whatever codec is currently in use */ + audiohw_close(); + aic_enable_i2s_bit_clock(false); + + /* switch to new source */ + cur_audio_source = source; + + if(source == AUDIO_SRC_PLAYBACK) { + /* power on DAC */ + aic_set_external_codec(true); + aic_set_i2s_mode(AIC_I2S_MASTER_MODE); + ak4376_open(); + + /* apply the old settings */ + audiohw_set_volume(cur_vol_l, cur_vol_r); + audiohw_set_filter_roll_off(cur_filter_roll_off); + set_ak_freqmode(); + } else if(source == AUDIO_SRC_MIC) { + aic_set_external_codec(false); + aic_set_i2s_mode(AIC_I2S_SLAVE_MODE); + /* Note: Sampling frequency is irrelevant here */ + aic_set_i2s_clock(X1000_CLK_EXCLK, 48000, 0); + aic_enable_i2s_bit_clock(true); + + x1000_icodec_open(); + + /* configure the mic */ + x1000_icodec_mic1_enable(true); + x1000_icodec_mic1_bias_enable(true); + x1000_icodec_mic1_configure(JZCODEC_MIC1_DIFFERENTIAL | + JZCODEC_MIC1_BIAS_2_08V); + + /* configure the ADC */ + x1000_icodec_adc_mic_sel(JZCODEC_MIC_SEL_ANALOG); + x1000_icodec_adc_highpass_filter(true); + x1000_icodec_adc_frequency(cur_fsel); + x1000_icodec_adc_enable(true); + + /* configure the mixer to put mic input in both channels */ + x1000_icodec_mixer_enable(true); + x1000_icodec_write(JZCODEC_MIX2, 0x10); + + /* set gain and unmute */ + audiohw_set_recvol(cur_recvol, 0, AUDIO_GAIN_MIC); + x1000_icodec_adc_mute(false); + } else { + logf("bad audio input source: %d (flags: %x)", source, flags); + } } void audiohw_set_volume(int vol_l, int vol_r) { - ak4376_set_volume(vol_l, vol_r); + cur_vol_l = vol_l; + cur_vol_r = vol_r; + + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + ak4376_set_volume(vol_l, vol_r); } void audiohw_set_filter_roll_off(int val) { - ak4376_set_filter_roll_off(val); + cur_filter_roll_off = val; + + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + ak4376_set_filter_roll_off(val); } void audiohw_set_frequency(int fsel) { cur_fsel = fsel; - set_ak_freqmode(); + + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + set_ak_freqmode(); + else + x1000_icodec_adc_frequency(fsel); } void audiohw_set_power_mode(int mode) { cur_power_mode = mode; - set_ak_freqmode(); + + if(cur_audio_source == AUDIO_SRC_PLAYBACK) + set_ak_freqmode(); +} + +static int round_step_up(int x, int step) +{ + int rem = x % step; + if(rem > 0) + rem -= step; + return x - rem; +} + +void audiohw_set_recvol(int left, int right, int type) +{ + (void)right; + + if(type == AUDIO_GAIN_MIC) { + cur_recvol = left; + + if(cur_audio_source == AUDIO_SRC_MIC) { + int mic_gain = round_step_up(left, X1000_ICODEC_MIC_GAIN_STEP); + mic_gain = MIN(mic_gain, X1000_ICODEC_MIC_GAIN_MAX); + mic_gain = MAX(mic_gain, X1000_ICODEC_MIC_GAIN_MIN); + + int adc_gain = left - mic_gain; + adc_gain = MIN(adc_gain, X1000_ICODEC_ADC_GAIN_MAX); + adc_gain = MAX(adc_gain, X1000_ICODEC_ADC_GAIN_MIN); + + x1000_icodec_adc_gain(adc_gain); + x1000_icodec_mic1_gain(mic_gain); + } + } } void ak4376_set_pdn_pin(int level) diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c index 5c92fa81e2..840be36a75 100644 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c +++ b/firmware/target/mips/ingenic_x1000/fiiom3k/power-fiiom3k.c @@ -61,10 +61,15 @@ void power_init(void) /* Set lowest sample rate */ axp_adc_set_rate(AXP_ADC_RATE_25HZ); - /* Ensure battery voltage ADC is enabled */ - int bits = axp_adc_get_enabled(); - bits |= (1 << ADC_BATTERY_VOLTAGE); - axp_adc_set_enabled(bits); + /* Enable required ADCs */ + axp_adc_set_enabled( + (1 << ADC_BATTERY_VOLTAGE) | + (1 << ADC_CHARGE_CURRENT) | + (1 << ADC_DISCHARGE_CURRENT) | + (1 << ADC_VBUS_VOLTAGE) | + (1 << ADC_VBUS_CURRENT) | + (1 << ADC_INTERNAL_TEMP) | + (1 << ADC_APS_VOLTAGE)); /* Turn on all power outputs */ i2c_reg_modify1(AXP_PMU_BUS, AXP_PMU_ADDR, @@ -106,3 +111,13 @@ int _battery_voltage(void) { return axp_adc_read(ADC_BATTERY_VOLTAGE); } + +#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE +int _battery_current(void) +{ + if(charging_state()) + return axp_adc_read(ADC_CHARGE_CURRENT); + else + return axp_adc_read(ADC_DISCHARGE_CURRENT); +} +#endif diff --git a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c b/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c deleted file mode 100644 index cbbe8b1d5d..0000000000 --- a/firmware/target/mips/ingenic_x1000/fiiom3k/spl-fiiom3k.c +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2021 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 "clk-x1000.h" -#include "spl-x1000.h" -#include "gpio-x1000.h" - -#define CMDLINE_COMMON \ - "mem=64M@0x0 no_console_suspend console=ttyS2,115200n8 lpj=5009408 ip=off" -#define CMDLINE_NORMAL \ - " init=/linuxrc ubi.mtd=3 root=ubi0:rootfs ubi.mtd=4 rootfstype=ubifs rw loglevel=8" - -static int dualboot_setup(void) -{ - spl_dualboot_init_clocktree(); - spl_dualboot_init_uart2(); - - /* load PDMA MCU firmware */ - jz_writef(CPM_CLKGR, PDMA(0)); - return spl_storage_read(0x4000, 0x2000, (void*)0xb3422000); -} - -const struct spl_boot_option spl_boot_options[] = { - [BOOT_OPTION_ROCKBOX] = { - .storage_addr = 0x6800, - .storage_size = 102 * 1024, - .load_addr = X1000_DRAM_BASE, - .exec_addr = X1000_DRAM_BASE, - .flags = BOOTFLAG_UCLPACK, - }, - [BOOT_OPTION_OFW_PLAYER] = { - .storage_addr = 0x20000, - .storage_size = 4 * 1024 * 1024, - .load_addr = 0x80efffc0, - .exec_addr = 0x80f00000, - .cmdline = CMDLINE_COMMON CMDLINE_NORMAL, - .cmdline_addr = 0x80004000, - .setup = dualboot_setup, - }, - [BOOT_OPTION_OFW_RECOVERY] = { - .storage_addr = 0x420000, - .storage_size = 5 * 1024 * 1024, - .load_addr = 0x80efffc0, - .exec_addr = 0x80f00000, - .cmdline = CMDLINE_COMMON, - .cmdline_addr = 0x80004000, - .setup = dualboot_setup, - }, -}; - -int spl_get_boot_option(void) -{ - /* Button debounce time in OST clock cycles */ - const uint32_t btn_stable_time = 100 * (X1000_EXCLK_FREQ / 4000); - - /* Buttons to poll */ - const unsigned port = GPIO_A; - const uint32_t recov_pin = (1 << 19); /* Volume Up */ - const uint32_t orig_fw_pin = (1 << 17); /* Play */ - - uint32_t pin = -1, lastpin = 0; - uint32_t deadline = 0; - int iter_count = 30; /* to avoid an infinite loop */ - - /* set GPIOs to input state */ - gpioz_configure(port, recov_pin|orig_fw_pin, GPIOF_INPUT); - - /* Poll until we get a stable reading */ - do { - lastpin = pin; - pin = ~REG_GPIO_PIN(port) & (recov_pin|orig_fw_pin); - if(pin != lastpin) { - deadline = __ost_read32() + btn_stable_time; - iter_count -= 1; - } - } while(iter_count > 0 && __ost_read32() < deadline); - - if(iter_count >= 0 && (pin & orig_fw_pin)) { - if(pin & recov_pin) - return BOOT_OPTION_OFW_RECOVERY; - else - return BOOT_OPTION_OFW_PLAYER; - } - - return BOOT_OPTION_ROCKBOX; -} - -void spl_error(void) -{ - /* Flash the buttonlight */ - int level = 0; - while(1) { - gpio_set_function(GPIO_PC(24), GPIOF_OUTPUT(level)); - mdelay(100); - level = 1 - level; - } -} 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 0a09ad0e91..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("boot_image", u->buf_len); + 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/lcd-x1000.h b/firmware/target/mips/ingenic_x1000/lcd-x1000.h index 749fac8240..e88a8733ed 100644 --- a/firmware/target/mips/ingenic_x1000/lcd-x1000.h +++ b/firmware/target/mips/ingenic_x1000/lcd-x1000.h @@ -105,6 +105,14 @@ extern void lcd_exec_commands(const uint32_t* cmdseq); */ extern void lcd_tgt_enable(bool on); +/* Enable/disable the LCD controller, but intended for booting the OF. + * + * This is only used for the Eros Q Native port, as the OF seems to be + * unable to initialize the LCD in the kernel boot rather than having + * the bootloader do it. + */ +extern void lcd_tgt_enable_of(bool on); + /* Enter or exit sleep mode to save power, normally by sending the necessary * commands with lcd_exec_commands(). */ diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.c b/firmware/target/mips/ingenic_x1000/nand-x1000.c index a818ba10aa..af0f972eae 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c @@ -22,75 +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, - .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, +}; + +#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 nand_drv static_nand_drv; +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) { @@ -103,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; @@ -123,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) { @@ -181,22 +198,38 @@ 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) + if(drv->refcount > 0) { + drv->refcount++; return NAND_SUCCESS; + } /* 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); @@ -207,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); @@ -220,9 +252,10 @@ int nand_open(nand_drv* drv) return NAND_SUCCESS; } -void nand_close(nand_drv* drv) +void nand_close(struct nand_drv* drv) { - if(drv->refcount == 0) + --drv->refcount; + if(drv->refcount > 0) return; /* Let's reset the chip... the idea is to restore the registers @@ -231,10 +264,15 @@ void nand_close(nand_drv* drv) mdelay(10); sfc_close(); - drv->refcount--; } -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 { @@ -243,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) @@ -255,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) @@ -268,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; @@ -290,21 +343,21 @@ int nand_read_bytes(nand_drv* drv, uint32_t byte_addr, uint32_t byte_len, void* if(rc < 0) return rc; - memcpy(buffer, &drv->page_buf[offset], MIN(pg_size, byte_len)); + memcpy(buffer, &drv->page_buf[offset], MIN(pg_size - offset, byte_len)); - if(byte_len <= pg_size) + if(byte_len <= pg_size - offset) break; + byte_len -= pg_size - offset; + buffer += pg_size - offset; offset = 0; - byte_len -= pg_size; - buffer += pg_size; page++; } 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 711bf190b5..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; @@ -78,6 +114,9 @@ typedef struct nand_chip { /* Total number of blocks in the chip */ unsigned nr_blocks; + /* Bad block marker offset within the 1st page of a bad block */ + unsigned bbm_pos; + /* Clock frequency to use */ uint32_t clock_freq; @@ -86,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; @@ -110,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. @@ -138,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); } @@ -159,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. @@ -168,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 ef54d45e62..4b9cb85b57 100644 --- a/firmware/target/mips/ingenic_x1000/pcm-x1000.c +++ b/firmware/target/mips/ingenic_x1000/pcm-x1000.c @@ -7,7 +7,7 @@ * \/ \/ \/ \/ \/ * $Id$ * - * Copyright (C) 2021 Aidan MacDonald + * Copyright (C) 2021-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 @@ -31,28 +31,31 @@ #include "x1000/aic.h" #include "x1000/cpm.h" -#define AIC_STATE_STOPPED 0 -#define AIC_STATE_PLAYING 1 +#define AIC_STATE_STOPPED 0x00 +#define AIC_STATE_PLAYING 0x01 +#define AIC_STATE_RECORDING 0x02 volatile unsigned aic_tx_underruns = 0; static int aic_state = AIC_STATE_STOPPED; -static int aic_lock = 0; -static volatile int aic_dma_pending_event = DMA_EVENT_NONE; - -static dma_desc aic_dma_desc; - +static int play_lock = 0; +static volatile int play_dma_pending_event = DMA_EVENT_NONE; +static dma_desc play_dma_desc; static void pcm_play_dma_int_cb(int event); + #ifdef HAVE_RECORDING +volatile unsigned aic_rx_overruns = 0; +static int rec_lock = 0; +static volatile int rec_dma_pending_event = DMA_EVENT_NONE; +static dma_desc rec_dma_desc; + static void pcm_rec_dma_int_cb(int event); #endif void pcm_play_dma_init(void) { - /* Ungate clock, assign pins. NB this overlaps with pins labeled "sa0-sa4" - * on Ingenic's datasheets but I'm not sure what they are. Probably safe to - * assume they are not useful to Rockbox... */ + /* Ungate clock */ jz_writef(CPM_CLKGR, AIC(0)); /* Configure AIC with some sane defaults */ @@ -79,7 +82,7 @@ void pcm_play_dma_init(void) #endif /* Set DMA settings */ - jz_writef(AIC_CFG, TFTH(16), RFTH(16)); + jz_writef(AIC_CFG, TFTH(16), RFTH(15)); dma_set_callback(DMA_CHANNEL_AUDIO, pcm_play_dma_int_cb); #ifdef HAVE_RECORDING dma_set_callback(DMA_CHANNEL_RECORD, pcm_rec_dma_int_cb); @@ -106,23 +109,23 @@ void pcm_dma_apply_settings(void) audiohw_set_frequency(pcm_fsel); } -static void pcm_dma_start(const void* addr, size_t size) +static void play_dma_start(const void* addr, size_t size) { - aic_dma_desc.cm = jz_orf(DMA_CHN_CM, SAI(1), DAI(0), RDIL(9), - SP_V(32BIT), DP_V(32BIT), TSZ_V(AUTO), - STDE(0), TIE(1), LINK(0)); - aic_dma_desc.sa = PHYSADDR(addr); - aic_dma_desc.ta = PHYSADDR(JA_AIC_DR); - aic_dma_desc.tc = size; - aic_dma_desc.sd = 0; - aic_dma_desc.rt = jz_orf(DMA_CHN_RT, TYPE_V(I2S_TX)); - aic_dma_desc.pad0 = 0; - aic_dma_desc.pad1 = 0; - - commit_dcache_range(&aic_dma_desc, sizeof(dma_desc)); + play_dma_desc.cm = jz_orf(DMA_CHN_CM, SAI(1), DAI(0), RDIL(9), + SP_V(32BIT), DP_V(32BIT), TSZ_V(AUTO), + STDE(0), TIE(1), LINK(0)); + play_dma_desc.sa = PHYSADDR(addr); + play_dma_desc.ta = PHYSADDR(JA_AIC_DR); + play_dma_desc.tc = size; + play_dma_desc.sd = 0; + play_dma_desc.rt = jz_orf(DMA_CHN_RT, TYPE_V(I2S_TX)); + play_dma_desc.pad0 = 0; + play_dma_desc.pad1 = 0; + + commit_dcache_range(&play_dma_desc, sizeof(dma_desc)); commit_dcache_range(addr, size); - REG_DMA_CHN_DA(DMA_CHANNEL_AUDIO) = PHYSADDR(&aic_dma_desc); + REG_DMA_CHN_DA(DMA_CHANNEL_AUDIO) = PHYSADDR(&play_dma_desc); jz_writef(DMA_CHN_CS(DMA_CHANNEL_AUDIO), DES8(1), NDES(0)); jz_set(DMA_DB, 1 << DMA_CHANNEL_AUDIO); jz_writef(DMA_CHN_CS(DMA_CHANNEL_AUDIO), CTE(1)); @@ -130,13 +133,13 @@ static void pcm_dma_start(const void* addr, size_t size) pcm_play_dma_status_callback(PCM_DMAST_STARTED); } -static void pcm_dma_handle_event(int event) +static void play_dma_handle_event(int event) { if(event == DMA_EVENT_COMPLETE) { const void* addr; size_t size; if(pcm_play_dma_complete_callback(PCM_DMAST_OK, &addr, &size)) - pcm_dma_start(addr, size); + play_dma_start(addr, size); } else if(event == DMA_EVENT_NONE) { /* ignored, so callers don't need to check for this */ } else { @@ -146,43 +149,60 @@ static void pcm_dma_handle_event(int event) static void pcm_play_dma_int_cb(int event) { - if(aic_lock) { - aic_dma_pending_event = event; + if(play_lock) { + play_dma_pending_event = event; return; } else { - pcm_dma_handle_event(event); + play_dma_handle_event(event); } } void pcm_play_dma_start(const void* addr, size_t size) { - aic_dma_pending_event = DMA_EVENT_NONE; - aic_state = AIC_STATE_PLAYING; + play_dma_pending_event = DMA_EVENT_NONE; + aic_state |= AIC_STATE_PLAYING; - pcm_dma_start(addr, size); + play_dma_start(addr, size); jz_writef(AIC_CCR, TDMS(1), ETUR(1), ERPL(1)); } 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)); - aic_dma_pending_event = DMA_EVENT_NONE; - aic_state = AIC_STATE_STOPPED; + play_dma_pending_event = DMA_EVENT_NONE; + aic_state &= ~AIC_STATE_PLAYING; } void pcm_play_lock(void) { - ++aic_lock; + int irq = disable_irq_save(); + ++play_lock; + restore_irq(irq); } void pcm_play_unlock(void) { int irq = disable_irq_save(); - if(--aic_lock == 0 && aic_state == AIC_STATE_PLAYING) { - pcm_dma_handle_event(aic_dma_pending_event); - aic_dma_pending_event = DMA_EVENT_NONE; + if(--play_lock == 0 && (aic_state & AIC_STATE_PLAYING)) { + play_dma_handle_event(play_dma_pending_event); + play_dma_pending_event = DMA_EVENT_NONE; } restore_irq(irq); @@ -193,11 +213,56 @@ void pcm_play_unlock(void) * Recording */ -/* FIXME need to implement this!! */ +static void rec_dma_start(void* addr, size_t size) +{ + /* NOTE: Rockbox always records in stereo and the AIC pushes in the + * sample for each channel separately. One frame therefore requires + * two 16-bit transfers from the AIC. */ + rec_dma_desc.cm = jz_orf(DMA_CHN_CM, SAI(0), DAI(1), RDIL(6), + SP_V(16BIT), DP_V(16BIT), TSZ_V(16BIT), + STDE(0), TIE(1), LINK(0)); + rec_dma_desc.sa = PHYSADDR(JA_AIC_DR); + rec_dma_desc.ta = PHYSADDR(addr); + rec_dma_desc.tc = size / 2; + rec_dma_desc.sd = 0; + rec_dma_desc.rt = jz_orf(DMA_CHN_RT, TYPE_V(I2S_RX)); + rec_dma_desc.pad0 = 0; + rec_dma_desc.pad1 = 0; + + commit_dcache_range(&rec_dma_desc, sizeof(dma_desc)); + if((unsigned long)addr < 0xa0000000ul) + discard_dcache_range(addr, size); + + REG_DMA_CHN_DA(DMA_CHANNEL_RECORD) = PHYSADDR(&rec_dma_desc); + jz_writef(DMA_CHN_CS(DMA_CHANNEL_RECORD), DES8(1), NDES(0)); + jz_set(DMA_DB, 1 << DMA_CHANNEL_RECORD); + jz_writef(DMA_CHN_CS(DMA_CHANNEL_RECORD), CTE(1)); + + pcm_rec_dma_status_callback(PCM_DMAST_STARTED); +} + +static void rec_dma_handle_event(int event) +{ + if(event == DMA_EVENT_COMPLETE) { + void* addr; + size_t size; + if(pcm_rec_dma_complete_callback(PCM_DMAST_OK, &addr, &size)) + rec_dma_start(addr, size); + } else if(event == DMA_EVENT_NONE) { + /* ignored, so callers don't need to check for this */ + } else { + pcm_rec_dma_status_callback(PCM_DMAST_ERR_DMA); + } +} static void pcm_rec_dma_int_cb(int event) { - (void)event; + if(rec_lock) { + rec_dma_pending_event = event; + return; + } else { + rec_dma_handle_event(event); + } } void pcm_rec_dma_init(void) @@ -210,40 +275,52 @@ void pcm_rec_dma_close(void) void pcm_rec_dma_start(void* addr, size_t size) { - (void)addr; - (void)size; + rec_dma_pending_event = DMA_EVENT_NONE; + aic_state |= AIC_STATE_RECORDING; + + rec_dma_start(addr, size); + jz_writef(AIC_CCR, RDMS(1), EROR(1), EREC(1)); } void pcm_rec_dma_stop(void) { + jz_writef(AIC_CCR, RDMS(0), EROR(0), EREC(0)); + jz_writef(AIC_CCR, RFLUSH(1)); + + rec_dma_pending_event = DMA_EVENT_NONE; + aic_state &= ~AIC_STATE_RECORDING; } void pcm_rec_lock(void) { - + int irq = disable_irq_save(); + ++rec_lock; + restore_irq(irq); } void pcm_rec_unlock(void) { + int irq = disable_irq_save(); + if(--rec_lock == 0 && (aic_state & AIC_STATE_RECORDING)) { + rec_dma_handle_event(rec_dma_pending_event); + rec_dma_pending_event = DMA_EVENT_NONE; + } + restore_irq(irq); } const void* pcm_rec_dma_get_peak_buffer(void) { - return NULL; -} - -void audio_set_output_source(int source) -{ - (void)source; + return (const void*)UNCACHEDADDR(REG_DMA_CHN_TA(DMA_CHANNEL_RECORD)); } +#endif /* HAVE_RECORDING */ -void audio_input_mux(int source, unsigned flags) +#ifdef HAVE_PCM_DMA_ADDRESS +void* pcm_dma_addr(void* addr) { - (void)source; - (void)flags; + return (void*)UNCACHEDADDR(addr); } -#endif /* HAVE_RECORDING */ +#endif void AIC(void) { @@ -251,4 +328,11 @@ void AIC(void) aic_tx_underruns += 1; jz_writef(AIC_SR, TUR(0)); } + +#ifdef HAVE_RECORDING + if(jz_readf(AIC_SR, ROR)) { + aic_rx_overruns += 1; + jz_writef(AIC_SR, ROR(0)); + } +#endif /* HAVE_RECORDING */ } diff --git a/firmware/target/mips/ingenic_x1000/sfc-x1000.h b/firmware/target/mips/ingenic_x1000/sfc-x1000.h index d28bcb6740..afb4aa3ce6 100644 --- a/firmware/target/mips/ingenic_x1000/sfc-x1000.h +++ b/firmware/target/mips/ingenic_x1000/sfc-x1000.h @@ -87,13 +87,13 @@ extern void sfc_irq_end(void); extern void sfc_set_clock(uint32_t freq); /* Set the device configuration register */ -inline void sfc_set_dev_conf(uint32_t conf) +static inline void sfc_set_dev_conf(uint32_t conf) { REG_SFC_DEV_CONF = conf; } /* Control the state of the write protect pin */ -inline void sfc_set_wp_enable(bool en) +static inline void sfc_set_wp_enable(bool en) { jz_writef(SFC_GLB, WP_EN(en ? 1 : 0)); } diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c index 7314f20412..787c35c494 100644 --- a/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/audiohw-shanlingq1.c @@ -59,7 +59,7 @@ static void codec_stop(void) { es9218_mute(true); es9218_close(); - mdelay(1); + mdelay(4); } void audiohw_init(void) @@ -154,7 +154,7 @@ void audiohw_set_filter_roll_off(int value) void audiohw_set_power_mode(int mode) { enum es9218_amp_mode new_amp_mode; - if(mode == 0) + if(mode == SOUND_HIGH_POWER) new_amp_mode = ES9218_AMP_MODE_2VRMS; else new_amp_mode = ES9218_AMP_MODE_1VRMS; diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c index 17fbe1cede..59a2262f25 100644 --- a/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c +++ b/firmware/target/mips/ingenic_x1000/shanlingq1/power-shanlingq1.c @@ -78,6 +78,19 @@ void power_init(void) cw2015_init(); #endif + /* Set lowest sample rate */ + axp_adc_set_rate(AXP_ADC_RATE_25HZ); + + /* Enable required ADCs */ + axp_adc_set_enabled( + (1 << ADC_BATTERY_VOLTAGE) | + (1 << ADC_CHARGE_CURRENT) | + (1 << ADC_DISCHARGE_CURRENT) | + (1 << ADC_VBUS_VOLTAGE) | + (1 << ADC_VBUS_CURRENT) | + (1 << ADC_INTERNAL_TEMP) | + (1 << ADC_APS_VOLTAGE)); + /* Change supply voltage from the default of 1250 mV to 1200 mV, * this matches the original firmware's settings. Didn't observe * any obviously bad behavior at 1250 mV, but better to be safe. */ @@ -121,6 +134,16 @@ int _battery_voltage(void) return axp_adc_read(ADC_BATTERY_VOLTAGE); } +#if CONFIG_BATTERY_MEASURE & CURRENT_MEASURE +int _battery_current(void) +{ + if(charging_state()) + return axp_adc_read(ADC_CHARGE_CURRENT); + else + return axp_adc_read(ADC_DISCHARGE_CURRENT); +} +#endif + #if defined(HAVE_CW2015) && (CONFIG_BATTERY_MEASURE & PERCENTAGE_MEASURE) != 0 int _battery_level(void) { diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c deleted file mode 100644 index 33303c5e6b..0000000000 --- a/firmware/target/mips/ingenic_x1000/shanlingq1/spl-shanlingq1.c +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2021 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 "clk-x1000.h" -#include "spl-x1000.h" -#include "gpio-x1000.h" - -#define CMDLINE_COMMON \ - "mem=64M@0x0 no_console_suspend console=ttyS2,115200n8 lpj=5009408 ip=off" -#define CMDLINE_NORMAL \ - " init=/linuxrc ubi.mtd=5 root=ubi0:rootfs ubi.mtd=6 rootfstype=ubifs rw" - -static int dualboot_setup(void) -{ - spl_dualboot_init_clocktree(); - spl_dualboot_init_uart2(); - - /* load PDMA MCU firmware */ - jz_writef(CPM_CLKGR, PDMA(0)); - return spl_storage_read(0x4000, 0x2000, (void*)0xb3422000); -} - -const struct spl_boot_option spl_boot_options[] = { - [BOOT_OPTION_ROCKBOX] = { - .storage_addr = 0x6800, - .storage_size = 102 * 1024, - .load_addr = X1000_DRAM_BASE, - .exec_addr = X1000_DRAM_BASE, - .flags = BOOTFLAG_UCLPACK, - }, - [BOOT_OPTION_OFW_PLAYER] = { - .storage_addr = 0x140000, - .storage_size = 8 * 1024 * 1024, - .load_addr = 0x80efffc0, - .exec_addr = 0x80f00000, - .cmdline = CMDLINE_COMMON CMDLINE_NORMAL, - .cmdline_addr = 0x80004000, - .setup = dualboot_setup, - }, - [BOOT_OPTION_OFW_RECOVERY] = { - .storage_addr = 0x940000, - .storage_size = 10 * 1024 * 1024, - .load_addr = 0x80efffc0, - .exec_addr = 0x80f00000, - .cmdline = CMDLINE_COMMON, - .cmdline_addr = 0x80004000, - .setup = dualboot_setup, - }, -}; - -int spl_get_boot_option(void) -{ - /* Button debounce time in OST clock cycles */ - const uint32_t btn_stable_time = 100 * (X1000_EXCLK_FREQ / 4000); - - /* Buttons to poll */ - const unsigned port = GPIO_B; - const uint32_t recov_pin = (1 << 22); /* Next */ - const uint32_t orig_fw_pin = (1 << 21); /* Prev */ - - uint32_t pin = -1, lastpin = 0; - uint32_t deadline = 0; - int iter_count = 30; /* to avoid an infinite loop */ - - /* set GPIOs to input state */ - gpioz_configure(port, recov_pin|orig_fw_pin, GPIOF_INPUT); - - /* Poll until we get a stable reading */ - do { - lastpin = pin; - pin = ~REG_GPIO_PIN(port) & (recov_pin|orig_fw_pin); - if(pin != lastpin) { - deadline = __ost_read32() + btn_stable_time; - iter_count -= 1; - } - } while(iter_count > 0 && __ost_read32() < deadline); - - if(iter_count >= 0 && (pin & orig_fw_pin)) { - if(pin & recov_pin) - return BOOT_OPTION_OFW_RECOVERY; - else - return BOOT_OPTION_OFW_PLAYER; - } - - return BOOT_OPTION_ROCKBOX; -} - -void spl_error(void) -{ - /* Flash the backlight */ - int level = 0; - while(1) { - gpio_set_function(GPIO_PC(25), GPIOF_OUTPUT(level)); - mdelay(100); - level = 1 - level; - } -} diff --git a/firmware/target/mips/ingenic_x1000/erosqnative/spl-erosqnative.c b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c index 9d7a1d118a..24eb42081e 100644 --- a/firmware/target/mips/ingenic_x1000/erosqnative/spl-erosqnative.c +++ b/firmware/target/mips/ingenic_x1000/spl-nand-x1000.c @@ -19,45 +19,32 @@ * ****************************************************************************/ -#include "system.h" -#include "clk-x1000.h" #include "spl-x1000.h" #include "gpio-x1000.h" +#include "nand-x1000.h" -/* TODO: get dual-boot working */ +static struct nand_drv* ndrv = NULL; -const struct spl_boot_option spl_boot_options[] = { - [BOOT_OPTION_ROCKBOX] = { - .storage_addr = 0x6800, - .storage_size = 102 * 1024, - .load_addr = X1000_DRAM_BASE, - .exec_addr = X1000_DRAM_BASE, - .flags = BOOTFLAG_UCLPACK, - }, -}; - -int spl_get_boot_option(void) +int spl_storage_open(void) { - return BOOT_OPTION_ROCKBOX; -} + /* We need to assign the GPIOs manually */ + gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1)); -void spl_error(void) -{ - const uint32_t pin = (1 << 25); + /* Allocate NAND driver manually in DRAM */ + 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; - /* Turn on backlight */ - jz_clr(GPIO_INT(GPIO_C), pin); - jz_set(GPIO_MSK(GPIO_C), pin); - jz_clr(GPIO_PAT1(GPIO_C), pin); - jz_set(GPIO_PAT0(GPIO_C), pin); + return nand_open(ndrv); +} - while(1) { - /* Turn it off */ - mdelay(100); - jz_set(GPIO_PAT0(GPIO_C), pin); +void spl_storage_close(void) +{ + nand_close(ndrv); +} - /* Turn it on */ - mdelay(100); - jz_clr(GPIO_PAT0(GPIO_C), pin); - } +int spl_storage_read(uint32_t addr, uint32_t length, void* buffer) +{ + return nand_read_bytes(ndrv, addr, length, buffer); } 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 afaf5a7dd6..08f88f506c 100644 --- a/firmware/target/mips/ingenic_x1000/spl-x1000.c +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.c @@ -34,20 +34,49 @@ #include "ucl_decompress.h" #include <string.h> -#if defined(FIIO_M3K) || defined(SHANLING_Q1) -# define SPL_DDR_MEMORYSIZE 64 -# define SPL_DDR_AUTOSR_EN 1 -# define SPL_DDR_NEED_BYPASS 1 +#if defined(FIIO_M3K) +/* Size of memory, either 64 or 32 is legal. */ +# define SPL_DDR_MEMORYSIZE 64 +/* Pin to flash on spl_error(). Should be a backlight. */ +# define SPL_ERROR_PIN GPIO_PC(24) +/* Address and size of the bootloader on the storage medium used by the SPL */ +# define BOOT_STORAGE_ADDR 0x6800 +# define BOOT_STORAGE_SIZE (102 * 1024) +#elif defined(SHANLING_Q1) +# define SPL_DDR_MEMORYSIZE 64 +# define SPL_ERROR_PIN GPIO_PC(25) +# define BOOT_STORAGE_ADDR 0x6800 +# define BOOT_STORAGE_SIZE (102 * 1024) #elif defined(EROS_QN) -# define SPL_DDR_MEMORYSIZE 32 -# define SPL_DDR_AUTOSR_EN 1 -# define SPL_DDR_NEED_BYPASS 1 +# define SPL_DDR_MEMORYSIZE 32 +# define SPL_ERROR_PIN GPIO_PC(25) +# define BOOT_STORAGE_ADDR 0x6800 +# define BOOT_STORAGE_SIZE (102 * 1024) #else -# error "please define DRAM settings" +# error "please define SPL config" +#endif + +/* Hardcode this since the SPL is considered part of the bootloader, + * and should never get built or updated separately. */ +#define BOOT_LOAD_ADDR X1000_DRAM_BASE +#define BOOT_EXEC_ADDR BOOT_LOAD_ADDR + +/* Whether the bootloader is UCL-compressed */ +#ifndef SPL_USE_UCLPACK +# define SPL_USE_UCLPACK 1 +#endif + +/* Whether auto-self-refresh should be enabled (seems it always should be?) */ +#ifndef SPL_DDR_AUTOSR_EN +# define SPL_DDR_AUTOSR_EN 1 +#endif + +/* Whether DLL bypass is necessary (probably always?) */ +#ifndef SPL_DDR_NEED_BYPASS +# define SPL_DDR_NEED_BYPASS 1 #endif static void* heap = (void*)(X1000_SDRAM_BASE + X1000_SDRAM_SIZE); -static nand_drv* ndrv = NULL; void* spl_alloc(size_t count) { @@ -56,114 +85,14 @@ void* spl_alloc(size_t count) return heap; } -int spl_storage_open(void) -{ - /* We need to assign the GPIOs manually */ - gpioz_configure(GPIO_A, 0x3f << 26, GPIOF_DEVICE(1)); - - /* Allocate NAND driver manually in DRAM */ - ndrv = spl_alloc(sizeof(nand_drv)); - ndrv->page_buf = spl_alloc(NAND_DRV_MAXPAGESIZE); - ndrv->scratch_buf = spl_alloc(NAND_DRV_SCRATCHSIZE); - ndrv->refcount = 0; - - return nand_open(ndrv); -} - -void spl_storage_close(void) +void spl_error(void) { - nand_close(ndrv); -} - -int spl_storage_read(uint32_t addr, uint32_t length, void* buffer) -{ - return nand_read_bytes(ndrv, addr, length, buffer); -} - -/* Used by: - * - FiiO M3K - * - Shanling Q1 - * - * Amend it and add #ifdefs for other targets if needed. - */ -void spl_dualboot_init_clocktree(void) -{ - /* Make sure these are gated to match the OF behavior. */ - jz_writef(CPM_CLKGR, PCM(1), MAC(1), LCD(1), MSC0(1), MSC1(1), OTG(1), CIM(1)); - - /* Set clock sources, and make sure every clock starts out stopped */ - jz_writef(CPM_I2SCDR, CS_V(EXCLK)); - jz_writef(CPM_PCMCDR, CS_V(EXCLK)); - - jz_writef(CPM_MACCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); - while(jz_readf(CPM_MACCDR, BUSY)); - - jz_writef(CPM_LPCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); - while(jz_readf(CPM_LPCDR, BUSY)); - - jz_writef(CPM_MSC0CDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); - while(jz_readf(CPM_MSC0CDR, BUSY)); - - jz_writef(CPM_MSC1CDR, CE(1), STOP(1), CLKDIV(0xfe)); - while(jz_readf(CPM_MSC1CDR, BUSY)); - - jz_writef(CPM_CIMCDR, CLKSRC_V(MPLL), CE(1), STOP(1), CLKDIV(0xfe)); - while(jz_readf(CPM_CIMCDR, BUSY)); - - jz_writef(CPM_USBCDR, CLKSRC_V(EXCLK), CE(1), STOP(1)); - while(jz_readf(CPM_USBCDR, BUSY)); -} - -void spl_dualboot_init_uart2(void) -{ - /* Ungate the clock and select UART2 device function */ - jz_writef(CPM_CLKGR, UART2(0)); - gpioz_configure(GPIO_C, 3 << 30, GPIOF_DEVICE(1)); - - /* Disable all interrupts */ - jz_write(UART_UIER(2), 0); - - /* FIFO configuration */ - jz_overwritef(UART_UFCR(2), - RDTR(3), /* FIFO trigger level = 60? */ - UME(0), /* UART module disable */ - DME(1), /* DMA mode enable? */ - TFRT(1), /* transmit FIFO reset */ - RFRT(1), /* receive FIFO reset */ - FME(1)); /* FIFO mode enable */ - - /* IR mode configuration */ - jz_overwritef(UART_ISR(2), - RDPL(1), /* Zero is negative pulse for receive */ - TDPL(1), /* ... and for transmit */ - XMODE(1), /* Pulse width 1.6us */ - RCVEIR(0), /* Disable IR for recieve */ - XMITIR(0)); /* ... and for transmit */ - - /* Line configuration */ - jz_overwritef(UART_ULCR(2), DLAB(0), - WLS_V(8BITS), /* 8 bit words */ - SBLS_V(1_STOP_BIT), /* 1 stop bit */ - PARE(0), /* no parity */ - SBK(0)); /* don't set break */ - - /* Set the baud rate... not too sure how this works. (Docs unclear!) */ - const unsigned divisor = 0x0004; - jz_writef(UART_ULCR(2), DLAB(1)); - jz_write(UART_UDLHR(2), (divisor >> 8) & 0xff); - jz_write(UART_UDLLR(2), divisor & 0xff); - jz_write(UART_UMR(2), 16); - jz_write(UART_UACR(2), 0); - jz_writef(UART_ULCR(2), DLAB(0)); - - /* Enable UART */ - jz_overwritef(UART_UFCR(2), - RDTR(0), /* FIFO trigger level = 1 */ - DME(0), /* DMA mode disable */ - UME(1), /* UART module enable */ - TFRT(1), /* transmit FIFO reset */ - RFRT(1), /* receive FIFO reset */ - FME(1)); /* FIFO mode enable */ + int level = 0; + while(1) { + gpio_set_function(SPL_ERROR_PIN, GPIOF_OUTPUT(level)); + mdelay(100); + level = 1 - level; + } } static void init_ost(void) @@ -346,14 +275,14 @@ static int init_dram(void) return 0; } -static void* get_load_buffer(const struct spl_boot_option* opt) +static void* get_load_buffer(void) { /* read to a temporary location if we need to decompress, * otherwise simply read directly to the load address. */ - if(opt->flags & BOOTFLAG_UCLPACK) - return spl_alloc(opt->storage_size); + if(SPL_USE_UCLPACK) + return spl_alloc(BOOT_STORAGE_SIZE); else - return (void*)opt->load_addr; + return (void*)BOOT_LOAD_ADDR; } /* Mapping of boot_sel[1:0] pins. @@ -377,15 +306,10 @@ static uint32_t get_boot_sel(void) return (*(uint32_t*)0xf40001ec) & 3; } -typedef void(*entry_fn)(int, char**, int, int) __attribute__((noreturn)); - void spl_main(void) { - int rc, boot_option; - const struct spl_boot_option* opt; + int rc; void* load_buffer; - char** kargv = NULL; - int kargc = 0; /* magic */ REG_CPM_PSWC0ST = 0x00; @@ -393,9 +317,11 @@ 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(); - set_boot_option(BOOT_OPTION_ROCKBOX); /* early clock and DRAM init */ clk_init_early(); @@ -409,14 +335,6 @@ void spl_main(void) return; } - /* find out what we should boot */ - boot_option = spl_get_boot_option(); - opt = &spl_boot_options[boot_option]; - load_buffer = get_load_buffer(opt); - - /* save the selection for later */ - set_boot_option(boot_option); - /* finish up clock init */ clk_init(); @@ -425,44 +343,29 @@ void spl_main(void) if(rc != 0) spl_error(); - rc = spl_storage_read(opt->storage_addr, opt->storage_size, load_buffer); + load_buffer = get_load_buffer(); + rc = spl_storage_read(BOOT_STORAGE_ADDR, BOOT_STORAGE_SIZE, load_buffer); if(rc != 0) spl_error(); - /* handle compression */ - switch(opt->flags & BOOTFLAG_COMPRESSED) { - case BOOTFLAG_UCLPACK: { - uint32_t out_size = X1000_DRAM_END - opt->load_addr; - rc = ucl_unpack((uint8_t*)load_buffer, opt->storage_size, - (uint8_t*)opt->load_addr, &out_size); - } break; - - default: - break; + /* decompress */ + if(SPL_USE_UCLPACK) { + uint32_t out_size = X1000_SDRAM_END - BOOT_LOAD_ADDR; + rc = ucl_unpack((uint8_t*)load_buffer, BOOT_STORAGE_SIZE, + (uint8_t*)BOOT_LOAD_ADDR, &out_size); + } else { + rc = 0; } if(rc != 0) spl_error(); - /* call the setup hook */ - if(opt->setup) { - rc = opt->setup(); - if(rc != 0) - spl_error(); - } - /* close off storage access */ spl_storage_close(); - /* handle kernel command line, if specified */ - if(opt->cmdline) { - kargv = (char**)opt->cmdline_addr; - kargv[kargc++] = 0; - kargv[kargc++] = (char*)opt->cmdline; - } - /* jump to the entry point */ - entry_fn fn = (entry_fn)opt->exec_addr; + typedef void(*entry_fn)(uint32_t); + entry_fn fn = (entry_fn)BOOT_EXEC_ADDR; commit_discard_idcache(); - fn(kargc, kargv, 0, 0); + fn(saved_cpm_scratch); } diff --git a/firmware/target/mips/ingenic_x1000/spl-x1000.h b/firmware/target/mips/ingenic_x1000/spl-x1000.h index 6d60dbf880..9ee1aa768e 100644 --- a/firmware/target/mips/ingenic_x1000/spl-x1000.h +++ b/firmware/target/mips/ingenic_x1000/spl-x1000.h @@ -26,23 +26,6 @@ #include <stddef.h> #include <stdint.h> -#define BOOTFLAG_COMPRESSED 0x0f /* mask for compression flags */ -#define BOOTFLAG_UCLPACK 0x01 /* image is compressed with 'uclpack' */ - -struct spl_boot_option { - uint32_t storage_addr; /* image's location in storage */ - uint32_t storage_size; /* number of bytes to load */ - uint32_t load_addr; /* address to load image to */ - uint32_t exec_addr; /* address of the entry point */ - uint32_t flags; /* any special flags */ - const char* cmdline; /* command line; use NULL if not needed */ - uint32_t cmdline_addr; /* address to contain command line 'argv[]' */ - int(*setup)(void); /* setup hook, called before jumping to image */ -}; - -/* array of boot option descriptions */ -extern const struct spl_boot_option spl_boot_options[]; - /* Memory allocator. Allocation starts from the top of DRAM and counts down. * Allocation sizes are rounded up to a multiple of the cacheline size, so * the returned address is always suitably aligned for DMA. */ @@ -58,13 +41,6 @@ extern int spl_storage_open(void); extern void spl_storage_close(void); extern int spl_storage_read(uint32_t addr, uint32_t length, void* buffer); -/* Helpers for dual-booting with the Ingenic Linux OF */ -extern void spl_dualboot_init_clocktree(void); -extern void spl_dualboot_init_uart2(void); - -/* Get the boot option selected by the user, eg. by a key press */ -extern int spl_get_boot_option(void); - /* Called on a fatal error -- it should do something visible to the user * like flash the backlight repeatedly. */ extern void spl_error(void) __attribute__((noreturn)); diff --git a/firmware/target/mips/ingenic_x1000/spl.lds b/firmware/target/mips/ingenic_x1000/spl.lds index b0169ab1aa..b3e508e9c3 100644 --- a/firmware/target/mips/ingenic_x1000/spl.lds +++ b/firmware/target/mips/ingenic_x1000/spl.lds @@ -7,19 +7,18 @@ ENTRY(_spl_start) STARTUP(target/mips/ingenic_x1000/spl-start.o) MEMORY { - /* First 4k of TCSM is used by mask ROM for stack + variables, - * and the next 2k are occupied by SPL header */ - TCSM : ORIGIN = X1000_TCSM_BASE + 0x1800, - LENGTH = X1000_TCSM_SIZE - 0x1800 + TCSM : ORIGIN = X1000_SPL_EXEC_ADDR, + LENGTH = X1000_SPL_SIZE } 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 d43c8e67e4..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 */ @@ -72,7 +73,6 @@ void system_early_init(void) * This hack should keep everything working as usual. */ if(jz_readf(CPM_MPCR, ON) == 0) { init_boot_flags(); - set_boot_option(BOOT_OPTION_ROCKBOX); set_boot_flag(BOOT_FLAG_CLK_INIT); } #endif @@ -344,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(); @@ -364,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 */ |