diff options
Diffstat (limited to 'firmware/target')
60 files changed, 961 insertions, 829 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/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/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/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/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/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/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/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/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/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/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/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/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/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..2943329ba7 100644 --- a/firmware/target/mips/ingenic_x1000/app.lds +++ b/firmware/target/mips/ingenic_x1000/app.lds @@ -6,6 +6,13 @@ OUTPUT_ARCH(MIPS) ENTRY(_start) STARTUP(target/mips/ingenic_x1000/crt0.o) +#ifdef BOOTLOADER +# undef PLUGIN_BUFFER_SIZE +# undef CODEC_SIZE +# define PLUGIN_BUFFER_SIZE 0 +# define CODEC_SIZE 0 +#endif + /* End of the audio buffer, where the codec buffer starts */ #define ENDAUDIOADDR (X1000_DRAM_END - PLUGIN_BUFFER_SIZE - CODEC_SIZE) @@ -16,6 +23,7 @@ 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 } SECTIONS @@ -61,6 +69,14 @@ SECTIONS } > IRAM _iramcopy = LOADADDR(.iram); + .tcsm X1000_TCSM_BASE: AT (_bssbegin + SIZEOF(.iram)) + { + _tcsmstart = .; + KEEP(*(.tcsm*)); + _tcsmend = .; + } > TCSM + _tcsmcopy = LOADADDR(.tcsm); + . = ALIGN(4); .stack (NOLOAD) : { @@ -88,10 +104,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..aa97bfcd85 --- /dev/null +++ b/firmware/target/mips/ingenic_x1000/boot-x1000.c @@ -0,0 +1,280 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "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); + + 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); + + /* 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)); + + /* clear USB PHY voodoo bits, not all kernels use them */ + jz_writef(CPM_OPCR, GATE_USBPHY_CLK(0)); + jz_writef(CPM_USBCDR, PHY_GATE(0)); + +#if defined(FIIO_M3K) || defined(EROS_QN) + /* + * Need to bring up MPLL before booting Linux + * (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) +{ + 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..1b7a0db1e9 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"))); +void x1000_boot_linux(const void* source, size_t length, + void* load, void* entry, const char* args) + __attribute__((section(".icode"))); + +/* 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..f7153da564 100644 --- a/firmware/target/mips/ingenic_x1000/clk-x1000.h +++ b/firmware/target/mips/ingenic_x1000/clk-x1000.h @@ -80,13 +80,13 @@ extern void clk_set_ccr_div(uint32_t divbits); extern void clk_set_ddr(x1000_clk_t src, uint32_t div); /* 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..d079b01e2a 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 @@ -35,62 +37,74 @@ .section .init.text _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 + b _realstart nop - /* Invalidate BTB */ - mfc0 v0, C0_Config, 7 - nop - ori v0, v0, 2 - mtc0 v0, C0_Config, 7 - 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: /* 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) + la a0, _iramcopy + la a1, _iramstart + la a2, _iramend + bal _copy + nop + + /* Copy TCSM from BSS */ + la a0, _tcsmcopy + la a1, _tcsmstart + la a2, _tcsmend + bal _copy + nop /* 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 + + /* 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 + + /* Invalidate BTB */ + mfc0 v0, C0_Config, 7 + nop + ori v0, v0, 2 + mtc0 v0, C0_Config, 7 + nop /* Jump to C code */ jal system_early_init @@ -98,6 +112,28 @@ _irqstack_loop: j main nop + /* 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 + /* Exception entry points */ .section .vectors.1, "ax", %progbits j tlb_refill_handler diff --git a/firmware/target/mips/ingenic_x1000/debug-x1000.c b/firmware/target/mips/ingenic_x1000/debug-x1000.c index 98b8f95fb5..236442a880 100644 --- a/firmware/target/mips/ingenic_x1000/debug-x1000.c +++ b/firmware/target/mips/ingenic_x1000/debug-x1000.c @@ -118,12 +118,18 @@ static bool dbg_gpios(void) } extern volatile unsigned aic_tx_underruns; +#ifdef HAVE_RECORDING +extern volatile unsigned aic_rx_overruns; +#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 lcd_update(); } while(get_action(CONTEXT_STD, HZ) != ACTION_STD_CANCEL); 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/installer-x1000.c b/firmware/target/mips/ingenic_x1000/installer-x1000.c index 0a09ad0e91..66aa42d4a1 100644 --- a/firmware/target/mips/ingenic_x1000/installer-x1000.c +++ b/firmware/target/mips/ingenic_x1000/installer-x1000.c @@ -148,7 +148,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("boot_image", u->buf_len, &buflib_ops_locked); if(u->buf_hnd < 0) { rc = IERR_OUT_OF_MEMORY; goto error; 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..5838b21b39 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.c +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.c @@ -69,6 +69,7 @@ const nand_chip supported_nand_chips[] = { .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), @@ -190,8 +191,10 @@ static void setup_chip_registers(nand_drv* drv) int nand_open(nand_drv* drv) { - if(drv->refcount > 0) + if(drv->refcount > 0) { + drv->refcount++; return NAND_SUCCESS; + } /* Initialize the controller */ sfc_open(); @@ -222,7 +225,8 @@ int nand_open(nand_drv* drv) void nand_close(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,7 +235,6 @@ void nand_close(nand_drv* drv) mdelay(10); sfc_close(); - drv->refcount--; } static uint8_t nand_wait_busy(nand_drv* drv) @@ -290,14 +293,14 @@ 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++; } diff --git a/firmware/target/mips/ingenic_x1000/nand-x1000.h b/firmware/target/mips/ingenic_x1000/nand-x1000.h index 711bf190b5..668b3e3f82 100644 --- a/firmware/target/mips/ingenic_x1000/nand-x1000.h +++ b/firmware/target/mips/ingenic_x1000/nand-x1000.h @@ -78,6 +78,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; diff --git a/firmware/target/mips/ingenic_x1000/pcm-x1000.c b/firmware/target/mips/ingenic_x1000/pcm-x1000.c index ef54d45e62..7d1c83a35a 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,20 +149,20 @@ 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)); } @@ -168,21 +171,23 @@ void pcm_play_dma_stop(void) jz_writef(AIC_CCR, TDMS(0), ETUR(0), ERPL(0)); jz_writef(AIC_CCR, TFLUSH(1)); - 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 +198,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 +260,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 +313,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..82a05abf75 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 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(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-x1000.c b/firmware/target/mips/ingenic_x1000/spl-x1000.c index afaf5a7dd6..b9ee6cc1c1 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) -{ - 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) +void spl_error(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; @@ -395,7 +319,6 @@ void spl_main(void) /* set up boot flags */ init_boot_flags(); - set_boot_option(BOOT_OPTION_ROCKBOX); /* early clock and DRAM init */ clk_init_early(); @@ -409,14 +332,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 +340,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)(void); + entry_fn fn = (entry_fn)BOOT_EXEC_ADDR; commit_discard_idcache(); - fn(kargc, kargv, 0, 0); + fn(); } 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..09ab75d520 100644 --- a/firmware/target/mips/ingenic_x1000/spl.lds +++ b/firmware/target/mips/ingenic_x1000/spl.lds @@ -7,10 +7,8 @@ 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 diff --git a/firmware/target/mips/ingenic_x1000/system-x1000.c b/firmware/target/mips/ingenic_x1000/system-x1000.c index d43c8e67e4..7542b97a3d 100644 --- a/firmware/target/mips/ingenic_x1000/system-x1000.c +++ b/firmware/target/mips/ingenic_x1000/system-x1000.c @@ -72,7 +72,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 |