diff --git a/docker_build.sh b/docker_build.sh index cc795e5..7f580b7 100755 --- a/docker_build.sh +++ b/docker_build.sh @@ -20,8 +20,8 @@ docker run \ --rm \ --user $(id -u):$(id -g) \ --mac-address ${MAC_ADDRESS:-F8:12:34:56:78:90} \ - --mount type=bind,src="$(pwd)/fw/project/lcmxo2/license.dat",target="/flexlm/license.dat" \ - --mount type=bind,src="$(pwd)",target="/workdir" \ + -v "$(pwd)"/fw/project/lcmxo2/license.dat:/flexlm/license.dat \ + -v "$(pwd)":/workdir \ -h=`hostname` \ -e GIT_BRANCH="$GIT_BRANCH" \ -e GIT_TAG="$GIT_TAG" \ diff --git a/sw/bootloader/N64.ld b/sw/bootloader/N64.ld index 0d88ed9..70f94f4 100644 --- a/sw/bootloader/N64.ld +++ b/sw/bootloader/N64.ld @@ -23,12 +23,13 @@ SECTIONS { *(.framebuffer .framebuffer.*) } > framebuffer - .text : SUBALIGN(4) { + .text : SUBALIGN(8) { *(.text.entry_handler) *(.text .text.* .gnu.linkonce.t.*) *(.assets .assets.*) *(.rodata .rodata.* .gnu.linkonce.r.*) *(.data .data.* .gnu.linkonce.d.*) + . = ALIGN(8); _gp = . + 0x8000; *(.sdata .sdata.* .gnu.linkonce.s.*) *(.lit8 .lit4) diff --git a/sw/bootloader/src/display.c b/sw/bootloader/src/display.c index d67a34e..5a49b05 100644 --- a/sw/bootloader/src/display.c +++ b/sw/bootloader/src/display.c @@ -1,3 +1,4 @@ +#include #include #include "display.h" #include "font.h" @@ -19,6 +20,7 @@ static io32_t display_framebuffer[SCREEN_WIDTH * SCREEN_HEIGHT] __attribute__((section(".framebuffer, \"aw\", %nobits#"))); static int char_x; static int char_y; +static bool vi_configured = false; static const vi_regs_t vi_config[] = {{ .CR = VI_CR, .H_WIDTH = SCREEN_WIDTH, @@ -99,6 +101,22 @@ static void display_draw_character (char c) { return; } + if (c == '\b') { + char_x -= FONT_WIDTH; + for (int i = 0; i < (FONT_WIDTH * FONT_HEIGHT); i++) { + int c_x = char_x + (i % FONT_WIDTH); + int c_y = char_y + (i / FONT_WIDTH); + + if ((c_x >= (SCREEN_WIDTH - BORDER_WIDTH)) || (c_y >= (SCREEN_HEIGHT - BORDER_HEIGHT))) { + continue; + } + + int screen_offset = c_x + (c_y * SCREEN_WIDTH); + cpu_io_write(&display_framebuffer[screen_offset], BACKGROUND_COLOR); + } + return; + } + if ((char_x + FONT_WIDTH) > (SCREEN_WIDTH - BORDER_WIDTH)) { char_x = BORDER_WIDTH; char_y += FONT_HEIGHT + LINE_SPACING; @@ -113,7 +131,7 @@ static void display_draw_character (char c) { int c_y = char_y + (i / FONT_WIDTH); if ((c_x >= (SCREEN_WIDTH - BORDER_WIDTH)) || (c_y >= (SCREEN_HEIGHT - BORDER_HEIGHT))) { - break; + continue; } if (font_data[c - ' '][i / 8] & (1 << (i % 8))) { @@ -133,8 +151,6 @@ static void display_draw_string (const char *s) { void display_init (uint32_t *background) { - const vi_regs_t *cfg = &vi_config[OS_INFO->tv_type]; - char_x = BORDER_WIDTH; char_y = BORDER_HEIGHT; @@ -144,20 +160,26 @@ void display_init (uint32_t *background) { display_clear_background(); } - cpu_io_write(&VI->MADDR, (uint32_t) (display_framebuffer)); - cpu_io_write(&VI->H_WIDTH, cfg->H_WIDTH); - cpu_io_write(&VI->V_INTR, cfg->V_INTR); - cpu_io_write(&VI->CURR_LINE, cfg->CURR_LINE); - cpu_io_write(&VI->TIMING, cfg->TIMING); - cpu_io_write(&VI->V_SYNC, cfg->V_SYNC); - cpu_io_write(&VI->H_SYNC, cfg->H_SYNC); - cpu_io_write(&VI->H_SYNC_LEAP, cfg->H_SYNC_LEAP); - cpu_io_write(&VI->H_LIMITS, cfg->H_LIMITS); - cpu_io_write(&VI->V_LIMITS, cfg->V_LIMITS); - cpu_io_write(&VI->COLOR_BURST, cfg->COLOR_BURST); - cpu_io_write(&VI->H_SCALE, cfg->H_SCALE); - cpu_io_write(&VI->V_SCALE, cfg->V_SCALE); - cpu_io_write(&VI->CR, cfg->CR); + if (!vi_configured) { + vi_configured = true; + + const vi_regs_t *cfg = &vi_config[OS_INFO->tv_type]; + + cpu_io_write(&VI->MADDR, (uint32_t) (display_framebuffer)); + cpu_io_write(&VI->H_WIDTH, cfg->H_WIDTH); + cpu_io_write(&VI->V_INTR, cfg->V_INTR); + cpu_io_write(&VI->CURR_LINE, cfg->CURR_LINE); + cpu_io_write(&VI->TIMING, cfg->TIMING); + cpu_io_write(&VI->V_SYNC, cfg->V_SYNC); + cpu_io_write(&VI->H_SYNC, cfg->H_SYNC); + cpu_io_write(&VI->H_SYNC_LEAP, cfg->H_SYNC_LEAP); + cpu_io_write(&VI->H_LIMITS, cfg->H_LIMITS); + cpu_io_write(&VI->V_LIMITS, cfg->V_LIMITS); + cpu_io_write(&VI->COLOR_BURST, cfg->COLOR_BURST); + cpu_io_write(&VI->H_SCALE, cfg->H_SCALE); + cpu_io_write(&VI->V_SCALE, cfg->V_SCALE); + cpu_io_write(&VI->CR, cfg->CR); + } } void display_vprintf (const char *fmt, va_list args) { diff --git a/sw/bootloader/src/fatfs/diskio.c b/sw/bootloader/src/fatfs/diskio.c index c2df333..0afa1e9 100644 --- a/sw/bootloader/src/fatfs/diskio.c +++ b/sw/bootloader/src/fatfs/diskio.c @@ -1,6 +1,7 @@ #include #include "ff.h" #include "diskio.h" +#include "../error.h" #include "../io.h" #include "../sc64.h" @@ -15,7 +16,12 @@ DSTATUS disk_status (BYTE pdrv) { } DSTATUS status = 0; - sc64_sd_card_status_t sd_card_status = sc64_sd_card_get_status(); + sc64_error_t error; + sc64_sd_card_status_t sd_card_status; + + if ((error = sc64_sd_card_get_status(&sd_card_status)) != SC64_OK) { + error_display("Could not get SD card status: %d", error); + } if (!(sd_card_status & SD_CARD_STATUS_INSERTED)) { status |= STA_NODISK; @@ -47,7 +53,7 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { while (count > 0) { uint32_t blocks = ((count > BUFFER_BLOCKS_MAX) ? BUFFER_BLOCKS_MAX : count); size_t length = (blocks * SD_SECTOR_SIZE); - if (sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) { + if (sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks) != SC64_OK) { return RES_ERROR; } if (((uint32_t) (buff) % 8) == 0) { @@ -61,7 +67,7 @@ DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) { count -= blocks; } } else { - if (sc64_sd_read_sectors(physical_address, sector, count)) { + if (sc64_sd_read_sectors(physical_address, sector, count) != SC64_OK) { return RES_ERROR; } } @@ -85,7 +91,7 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { memcpy(aligned_buffer, buff, length); pi_dma_write((io32_t *) (SC64_BUFFERS->BUFFER), aligned_buffer, length); } - if (sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) { + if (sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks) != SC64_OK) { return RES_ERROR; } buff += length; @@ -93,7 +99,7 @@ DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { count -= blocks; } } else { - if (sc64_sd_write_sectors(physical_address, sector, count)) { + if (sc64_sd_write_sectors(physical_address, sector, count) != SC64_OK) { return RES_ERROR; } } @@ -112,8 +118,13 @@ DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void *buff) { } DWORD get_fattime(void) { + sc64_error_t error; sc64_rtc_time_t t; - sc64_get_time(&t); + + if ((error = sc64_get_time(&t)) != SC64_OK) { + error_display("Command TIME_GET failed: %d", error); + } + return ( ((FROM_BCD(t.year) + 20) << 25) | (FROM_BCD(t.month) << 21) | diff --git a/sw/bootloader/src/init.c b/sw/bootloader/src/init.c index 50cfef1..98d6e81 100644 --- a/sw/bootloader/src/init.c +++ b/sw/bootloader/src/init.c @@ -6,6 +6,8 @@ void init (void) { + sc64_error_t error; + uint32_t pifram = si_io_read((io32_t *) (PIFRAM_STATUS)); si_io_write((io32_t *) (PIFRAM_STATUS), pifram | PIFRAM_TERMINATE_BOOT); @@ -20,12 +22,14 @@ void init (void) { exception_enable_watchdog(); exception_enable_interrupts(); + if ((error = sc64_set_config(CFG_ID_BOOTLOADER_SWITCH, false)) != SC64_OK) { + error_display("Command SET_CONFIG [BOOTLOADER_SWITCH] failed: %d", error); + } + if (test_check()) { exception_disable_watchdog(); test_execute(); } - - sc64_set_config(CFG_ID_BOOTLOADER_SWITCH, false); } void deinit (void) { diff --git a/sw/bootloader/src/io.c b/sw/bootloader/src/io.c index cd1c978..9ef6264 100644 --- a/sw/bootloader/src/io.c +++ b/sw/bootloader/src/io.c @@ -26,6 +26,27 @@ void cache_inst_hit_invalidate (void *address, size_t length) { cache_operation(HIT_INVALIDATE_I, CACHE_LINE_SIZE_I, address, length); } +uint32_t c0_count (void) { + uint32_t value; + asm volatile ( + "mfc0 %[value], $9 \n" : + [value] "=r" (value) + ); + return value; +} + +void delay_ms (int ms) { + uint64_t start = c0_count(); + uint64_t end = start + (ms * ((93750000 / 2) / 1000)); + uint64_t current; + do { + current = c0_count(); + if (current < start) { + current += 0x100000000ULL; + } + } while (current < end); +} + uint32_t cpu_io_read (io32_t *address) { io32_t *uncached = UNCACHED(address); uint32_t value = *uncached; @@ -37,6 +58,15 @@ void cpu_io_write (io32_t *address, uint32_t value) { *uncached = value; } +void pi_io_config (uint8_t page_size, uint8_t latency, uint8_t pulse_width, uint8_t release) { + for (int domain = 0; domain < 2; domain += 1) { + cpu_io_write(&PI->DOM[domain].PGS, page_size); + cpu_io_write(&PI->DOM[domain].LAT, latency); + cpu_io_write(&PI->DOM[domain].PWD, pulse_width); + cpu_io_write(&PI->DOM[domain].RLS, release); + } +} + uint32_t pi_busy (void) { return (cpu_io_read(&PI->SR) & (PI_SR_IO_BUSY | PI_SR_DMA_BUSY)); } diff --git a/sw/bootloader/src/io.h b/sw/bootloader/src/io.h index bd51656..49a7d22 100644 --- a/sw/bootloader/src/io.h +++ b/sw/bootloader/src/io.h @@ -254,8 +254,11 @@ typedef struct { #define OS_INFO_RESET_TYPE_NMI (1) +uint32_t c0_count (void); +void delay_ms (int ms); uint32_t cpu_io_read (io32_t *address); void cpu_io_write (io32_t *address, uint32_t value); +void pi_io_config (uint8_t page_size, uint8_t latency, uint8_t pulse_width, uint8_t release); uint32_t pi_busy (void); uint32_t pi_io_read (io32_t *address); void pi_io_write (io32_t *address, uint32_t value); diff --git a/sw/bootloader/src/main.c b/sw/bootloader/src/main.c index 431cb2b..a4de2a1 100644 --- a/sw/bootloader/src/main.c +++ b/sw/bootloader/src/main.c @@ -7,10 +7,13 @@ void main (void) { + sc64_error_t error; boot_info_t boot_info; sc64_boot_info_t sc64_boot_info; - sc64_get_boot_info(&sc64_boot_info); + if ((error = sc64_get_boot_info(&sc64_boot_info)) != SC64_OK) { + error_display("Could not obtain boot info: %d", error); + } switch (sc64_boot_info.boot_mode) { case BOOT_MODE_MENU: diff --git a/sw/bootloader/src/menu.c b/sw/bootloader/src/menu.c index ebad210..67af086 100644 --- a/sw/bootloader/src/menu.c +++ b/sw/bootloader/src/menu.c @@ -3,6 +3,7 @@ #include "init.h" #include "io.h" #include "menu.h" +#include "sc64.h" extern const void __bootloader_start __attribute__((section(".data"))); @@ -65,6 +66,19 @@ static void menu_check_load_address (void *address, size_t size) { void menu_load_and_run (void) { + sc64_error_t error; + bool writeback_pending; + + do { + if ((error = sc64_writeback_pending(&writeback_pending)) != SC64_OK) { + error_display("Command WRITEBACK_PENDING failed: %d", error); + } + } while (writeback_pending); + + if ((error = sc64_writeback_disable()) != SC64_OK) { + error_display("Could not disable writeback: %d", error); + } + void (* menu)(void); FRESULT fresult; FATFS fs; diff --git a/sw/bootloader/src/sc64.c b/sw/bootloader/src/sc64.c index e8387bf..d2c9a45 100644 --- a/sw/bootloader/src/sc64.c +++ b/sw/bootloader/src/sc64.c @@ -12,6 +12,7 @@ typedef struct { #define SC64_REGS_BASE (0x1FFF0000UL) #define SC64_REGS ((sc64_regs_t *) SC64_REGS_BASE) + #define SC64_SR_IRQ_PENDING (1 << 29) #define SC64_SR_CMD_ERROR (1 << 30) #define SC64_SR_CPU_BUSY (1 << 31) @@ -23,29 +24,31 @@ typedef struct { #define SC64_KEY_UNLOCK_2 (0x4F434B5FUL) #define SC64_KEY_LOCK (0xFFFFFFFFUL) + typedef enum { - SC64_CMD_IDENTIFIER_GET = 'v', - SC64_CMD_VERSION_GET = 'V', - SC64_CMD_CONFIG_GET = 'c', - SC64_CMD_CONFIG_SET = 'C', - SC64_CMD_SETTING_GET = 'a', - SC64_CMD_SETTING_SET = 'A', - SC64_CMD_TIME_GET = 't', - SC64_CMD_TIME_SET = 'T', - SC64_CMD_USB_READ = 'm', - SC64_CMD_USB_WRITE = 'M', - SC64_CMD_USB_READ_STATUS = 'u', - SC64_CMD_USB_WRITE_STATUS = 'U', - SC64_CMD_SD_CARD_OP = 'i', - SC64_CMD_SD_SECTOR_SET = 'I', - SC64_CMD_SD_READ = 's', - SC64_CMD_SD_WRITE = 'S', - SC64_CMD_DD_SD_INFO = 'D', - SC64_CMD_WRITEBACK_SD_INFO = 'W', - SC64_CMD_FLASH_PROGRAM = 'K', - SC64_CMD_FLASH_WAIT_BUSY = 'p', - SC64_CMD_FLASH_ERASE_BLOCK = 'P', -} cmd_id_t; + CMD_ID_IDENTIFIER_GET = 'v', + CMD_ID_VERSION_GET = 'V', + CMD_ID_CONFIG_GET = 'c', + CMD_ID_CONFIG_SET = 'C', + CMD_ID_SETTING_GET = 'a', + CMD_ID_SETTING_SET = 'A', + CMD_ID_TIME_GET = 't', + CMD_ID_TIME_SET = 'T', + CMD_ID_USB_READ = 'm', + CMD_ID_USB_WRITE = 'M', + CMD_ID_USB_READ_STATUS = 'u', + CMD_ID_USB_WRITE_STATUS = 'U', + CMD_ID_SD_CARD_OP = 'i', + CMD_ID_SD_SECTOR_SET = 'I', + CMD_ID_SD_READ = 's', + CMD_ID_SD_WRITE = 'S', + CMD_ID_DD_SD_INFO = 'D', + CMD_ID_WRITEBACK_PENDING = 'w', + CMD_ID_WRITEBACK_SD_INFO = 'W', + CMD_ID_FLASH_PROGRAM = 'K', + CMD_ID_FLASH_WAIT_BUSY = 'p', + CMD_ID_FLASH_ERASE_BLOCK = 'P', +} sc64_cmd_id_t; typedef enum { SD_CARD_OP_DEINIT = 0, @@ -56,37 +59,35 @@ typedef enum { SD_CARD_OP_BYTE_SWAP_OFF = 5, } sd_card_op_t; +typedef struct { + sc64_cmd_id_t id; + uint32_t arg[2]; + uint32_t rsp[2]; +} sc64_cmd_t; + + +static sc64_error_t sc64_execute_cmd (sc64_cmd_t *cmd) { + pi_io_write(&SC64_REGS->DATA[0], cmd->arg[0]); + pi_io_write(&SC64_REGS->DATA[1], cmd->arg[1]); + + pi_io_write(&SC64_REGS->SR_CMD, (cmd->id & 0xFF)); -static bool sc64_wait_cpu_busy (void) { uint32_t sr; do { sr = pi_io_read(&SC64_REGS->SR_CMD); } while (sr & SC64_SR_CPU_BUSY); - return (sr & SC64_SR_CMD_ERROR); -} -static bool sc64_execute_cmd (uint8_t cmd, uint32_t *args, uint32_t *result) { - if (args != NULL) { - pi_io_write(&SC64_REGS->DATA[0], args[0]); - pi_io_write(&SC64_REGS->DATA[1], args[1]); - } - pi_io_write(&SC64_REGS->SR_CMD, ((uint32_t) (cmd)) & 0xFF); - bool error = sc64_wait_cpu_busy(); - if (result != NULL) { - result[0] = pi_io_read(&SC64_REGS->DATA[0]); - result[1] = pi_io_read(&SC64_REGS->DATA[1]); - } - return error; -} - - -sc64_error_t sc64_get_error (void) { - if (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_CMD_ERROR) { + if (sr & SC64_SR_CMD_ERROR) { return (sc64_error_t) (pi_io_read(&SC64_REGS->DATA[0])); } + + cmd->rsp[0] = pi_io_read(&SC64_REGS->DATA[0]); + cmd->rsp[1] = pi_io_read(&SC64_REGS->DATA[1]); + return SC64_OK; } + void sc64_unlock (void) { pi_io_write(&SC64_REGS->KEY, SC64_KEY_RESET); pi_io_write(&SC64_REGS->KEY, SC64_KEY_UNLOCK_1); @@ -99,204 +100,334 @@ void sc64_lock (void) { } bool sc64_check_presence (void) { - uint32_t identifier = pi_io_read(&SC64_REGS->IDENTIFIER); - if (identifier == SC64_V2_IDENTIFIER) { - sc64_wait_cpu_busy(); - return true; + bool detected = (pi_io_read(&SC64_REGS->IDENTIFIER) == SC64_V2_IDENTIFIER); + if (detected) { + while (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_CPU_BUSY); } - return false; + return detected; } + bool sc64_irq_pending (void) { - if (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_IRQ_PENDING) { - return true; - } - return false; + return (pi_io_read(&SC64_REGS->SR_CMD) & SC64_SR_IRQ_PENDING); } void sc64_irq_clear (void) { pi_io_write(&SC64_REGS->IDENTIFIER, 0); } -uint32_t sc64_get_config (sc64_cfg_id_t id) { - uint32_t args[2] = { id, 0 }; - uint32_t result[2]; - sc64_execute_cmd(SC64_CMD_CONFIG_GET, args, result); - return result[1]; -} -void sc64_set_config (sc64_cfg_id_t id, uint32_t value) { - uint32_t args[2] = { id, value }; - sc64_execute_cmd(SC64_CMD_CONFIG_SET, args, NULL); -} - -uint32_t sc64_get_setting (sc64_setting_id_t id) { - uint32_t args[2] = { id, 0 }; - uint32_t result[2]; - sc64_execute_cmd(SC64_CMD_SETTING_GET, args, result); - return result[1]; -} - -void sc64_set_setting (sc64_setting_id_t id, uint32_t value) { - uint32_t args[2] = { id, value }; - sc64_execute_cmd(SC64_CMD_SETTING_SET, args, NULL); -} - -void sc64_get_boot_info (sc64_boot_info_t *info) { - info->boot_mode = (sc64_boot_mode_t) sc64_get_config(CFG_ID_BOOT_MODE); - info->cic_seed = (sc64_cic_seed_t) sc64_get_config(CFG_ID_CIC_SEED); - info->tv_type = (sc64_tv_type_t) sc64_get_config(CFG_ID_TV_TYPE); -} - -void sc64_get_time (sc64_rtc_time_t *t) { - uint32_t result[2]; - sc64_execute_cmd(SC64_CMD_TIME_GET, NULL, result); - t->second = (result[0] & 0xFF); - t->minute = ((result[0] >> 8) & 0xFF); - t->hour = ((result[0] >> 16) & 0xFF); - t->weekday = ((result[1] >> 24) & 0xFF); - t->day = (result[1] & 0xFF); - t->month = ((result[1] >> 8) & 0xFF); - t->year = ((result[1] >> 16) & 0xFF); -} - -void sc64_set_time (sc64_rtc_time_t *t) { - uint32_t args[2] = { - ((t->hour << 16) | (t->minute << 8) | t->second), - ((t->weekday << 24) | (t->year << 16) | (t->month << 8) | t->day), +sc64_error_t sc64_get_identifier (uint32_t *identifier) { + sc64_cmd_t cmd = { + .id = CMD_ID_IDENTIFIER_GET }; - sc64_execute_cmd(SC64_CMD_TIME_SET, args, NULL); + sc64_error_t error = sc64_execute_cmd(&cmd); + *identifier = cmd.rsp[0]; + return error; } -bool sc64_usb_read_ready (uint8_t *type, uint32_t *length) { - uint32_t result[2]; - sc64_execute_cmd(SC64_CMD_USB_READ_STATUS, NULL, result); - if (type != NULL) { - *type = result[0] & 0xFF; +sc64_error_t sc64_get_version (uint16_t *major, uint16_t *minor, uint32_t *revision) { + sc64_cmd_t cmd = { + .id = CMD_ID_VERSION_GET + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *major = ((cmd.rsp[0] >> 16) & 0xFFFF); + *minor = (cmd.rsp[0] & 0xFFFF); + *revision = cmd.rsp[1]; + return error; +} + + +sc64_error_t sc64_get_config (sc64_cfg_id_t id, uint32_t *value) { + sc64_cmd_t cmd = { + .id = CMD_ID_CONFIG_GET, + .arg = { id } + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *value = cmd.rsp[1]; + return error; +} + +sc64_error_t sc64_set_config (sc64_cfg_id_t id, uint32_t value) { + sc64_cmd_t cmd = { + .id = CMD_ID_CONFIG_SET, + .arg = { id, value } + }; + return sc64_execute_cmd(&cmd); +} + +sc64_error_t sc64_get_setting (sc64_setting_id_t id, uint32_t *value) { + sc64_cmd_t cmd = { + .id = CMD_ID_SETTING_GET, + .arg = { id } + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *value = cmd.rsp[1]; + return error; +} + +sc64_error_t sc64_set_setting (sc64_setting_id_t id, uint32_t value) { + sc64_cmd_t cmd = { + .id = CMD_ID_SETTING_SET, + .arg = { id, value } + }; + return sc64_execute_cmd(&cmd); +} + +sc64_error_t sc64_get_boot_info (sc64_boot_info_t *info) { + sc64_error_t error; + uint32_t value; + + if ((error = sc64_get_config(CFG_ID_BOOT_MODE, &value)) != SC64_OK) { + return error; } - if (length != NULL) { - *length = result[1]; + info->boot_mode = value; + + if ((error = sc64_get_config(CFG_ID_CIC_SEED, &value)) != SC64_OK) { + return error; } - return (result[1] > 0); -} + info->cic_seed = value; -bool sc64_usb_read (void *address, uint32_t length) { - uint32_t args[2] = { (uint32_t) (address), length }; - uint32_t result[2]; - if (sc64_execute_cmd(SC64_CMD_USB_READ, args, NULL)) { - return true; + if ((error = sc64_get_config(CFG_ID_TV_TYPE, &value)) != SC64_OK) { + return error; } - do { - sc64_execute_cmd(SC64_CMD_USB_READ_STATUS, NULL, result); - } while(result[0] & (1 << 31)); - return false; + info->tv_type = value; + + return SC64_OK; } -bool sc64_usb_write_ready (void) { - uint32_t result[2]; - sc64_execute_cmd(SC64_CMD_USB_WRITE_STATUS, NULL, result); - return (!(result[0] & (1 << 31))); + +sc64_error_t sc64_get_time (sc64_rtc_time_t *t) { + sc64_cmd_t cmd = { + .id = CMD_ID_TIME_GET + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + t->hour = ((cmd.rsp[0] >> 16) & 0xFF); + t->minute = ((cmd.rsp[0] >> 8) & 0xFF); + t->second = (cmd.rsp[0] & 0xFF); + t->weekday = ((cmd.rsp[1] >> 24) & 0xFF); + t->year = ((cmd.rsp[1] >> 16) & 0xFF); + t->month = ((cmd.rsp[1] >> 8) & 0xFF); + t->day = (cmd.rsp[1] & 0xFF); + return error; } -bool sc64_usb_write (void *address, uint8_t type, uint32_t length) { - while (!sc64_usb_write_ready()); - uint32_t args[2] = { (uint32_t) (address), ((type << 24) | (length & 0xFFFFFF)) }; - return sc64_execute_cmd(SC64_CMD_USB_WRITE, args, NULL); +sc64_error_t sc64_set_time (sc64_rtc_time_t *t) { + uint32_t time[2] = {( + ((t->hour << 16) & 0xFF) | + ((t->minute << 8) & 0xFF) | + (t->second & 0xFF) + ), ( + ((t->weekday << 24) & 0xFF) | + ((t->year << 16) & 0xFF) | + ((t->month << 8) & 0xFF) | + (t->day & 0xFF) + )}; + sc64_cmd_t cmd = { + .id = CMD_ID_TIME_SET, + .arg = { time[0], time[1] } + }; + return sc64_execute_cmd(&cmd); } -bool sc64_sd_card_init (void) { - uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_INIT }; - if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) { - return true; + +sc64_error_t sc64_usb_get_status (bool *reset_state, bool *cable_unplugged) { + sc64_cmd_t cmd = { + .id = CMD_ID_USB_READ_STATUS, + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *reset_state = (bool) (cmd.rsp[0] & (1 << 30)); + *cable_unplugged = (bool) (cmd.rsp[0] & (1 << 29)); + return error; +} + +sc64_error_t sc64_usb_read_info (uint8_t *type, uint32_t *length) { + sc64_cmd_t cmd = { + .id = CMD_ID_USB_READ_STATUS, + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *type = (cmd.rsp[0] & 0xFF); + *length = cmd.rsp[1]; + return error; +} + +sc64_error_t sc64_usb_read_busy (bool *read_busy) { + sc64_cmd_t cmd = { + .id = CMD_ID_USB_READ_STATUS, + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *read_busy = (bool) (cmd.rsp[0] & (1 << 31)); + return error; +} + +sc64_error_t sc64_usb_write_busy (bool *write_busy) { + sc64_cmd_t cmd = { + .id = CMD_ID_USB_WRITE_STATUS, + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *write_busy = (bool) (cmd.rsp[0] & (1 << 31)); + return error; +} + +sc64_error_t sc64_usb_read (void *address, uint32_t length) { + sc64_cmd_t cmd = { + .id = CMD_ID_USB_READ, + .arg = { (uint32_t) (address), length } + }; + return sc64_execute_cmd(&cmd); +} + +sc64_error_t sc64_usb_write (void *address, uint8_t type, uint32_t length) { + sc64_cmd_t cmd = { + .id = CMD_ID_USB_WRITE, + .arg = { (uint32_t) (address), ((type << 24) | (length & 0xFFFFFF)) } + }; + return sc64_execute_cmd(&cmd); +} + + +sc64_error_t sc64_sd_card_init (void) { + sc64_cmd_t cmd = { + .id = CMD_ID_SD_CARD_OP, + .arg = { (uint32_t) (NULL), SD_CARD_OP_INIT } + }; + return sc64_execute_cmd(&cmd); +} + +sc64_error_t sc64_sd_card_deinit (void) { + sc64_cmd_t cmd = { + .id = CMD_ID_SD_CARD_OP, + .arg = { (uint32_t) (NULL), SD_CARD_OP_DEINIT } + }; + return sc64_execute_cmd(&cmd); +} + +sc64_error_t sc64_sd_card_get_status (sc64_sd_card_status_t *sd_card_status) { + sc64_cmd_t cmd = { + .id = CMD_ID_SD_CARD_OP, + .arg = { (uint32_t) (NULL), SD_CARD_OP_GET_STATUS } + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *sd_card_status = (sc64_sd_card_status_t) (cmd.rsp[1]); + return error; +} + +sc64_error_t sc64_sd_card_get_info (void *address) { + sc64_cmd_t cmd = { + .id = CMD_ID_SD_CARD_OP, + .arg = { (uint32_t) (address), SD_CARD_OP_GET_INFO } + }; + return sc64_execute_cmd(&cmd); +} + +sc64_error_t sc64_sd_set_byte_swap (bool enabled) { + sc64_cmd_t cmd = { + .id = CMD_ID_SD_CARD_OP, + .arg = { (uint32_t) (NULL), enabled ? SD_CARD_OP_BYTE_SWAP_ON : SD_CARD_OP_BYTE_SWAP_OFF } + }; + return sc64_execute_cmd(&cmd); +} + +static sc64_error_t sc64_sd_sector_set (uint32_t sector) { + sc64_cmd_t cmd = { + .id = CMD_ID_SD_SECTOR_SET, + .arg = { sector } + }; + return sc64_execute_cmd(&cmd); +} + +sc64_error_t sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count) { + sc64_error_t error; + if ((error = sc64_sd_sector_set(sector)) != SC64_OK) { + return error; } - return false; + sc64_cmd_t cmd = { + .id = CMD_ID_SD_READ, + .arg = { (uint32_t) (address), count } + }; + return sc64_execute_cmd(&cmd); } -bool sc64_sd_card_deinit (void) { - uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_DEINIT }; - if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) { - return true; +sc64_error_t sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count) { + sc64_error_t error; + if ((error = sc64_sd_sector_set(sector)) != SC64_OK) { + return error; } - return false; + sc64_cmd_t cmd = { + .id = CMD_ID_SD_WRITE, + .arg = { (uint32_t) (address), count } + }; + return sc64_execute_cmd(&cmd); } -sc64_sd_card_status_t sc64_sd_card_get_status (void) { - uint32_t args[2] = { (uint32_t) (NULL), SD_CARD_OP_GET_STATUS }; - uint32_t result[2]; - if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, result)) { - return false; + +sc64_error_t sc64_dd_set_sd_info (void *address, uint32_t length) { + sc64_cmd_t cmd = { + .id = CMD_ID_DD_SD_INFO, + .arg = { (uint32_t) (address), length } + }; + return sc64_execute_cmd(&cmd); +} + + +sc64_error_t sc64_writeback_pending (bool *pending) { + sc64_cmd_t cmd = { + .id = CMD_ID_WRITEBACK_PENDING + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *pending = (cmd.rsp[0] != 0); + return error; +} + +sc64_error_t sc64_writeback_enable (void *address) { + sc64_cmd_t cmd = { + .id = CMD_ID_WRITEBACK_SD_INFO, + .arg = { (uint32_t) (address) } + }; + return sc64_execute_cmd(&cmd); +} + +sc64_error_t sc64_writeback_disable (void) { + sc64_error_t error; + uint32_t save_type; + error = sc64_get_config(CFG_ID_SAVE_TYPE, &save_type); + if (error != SC64_OK) { + return error; } - return (sc64_sd_card_status_t) (result[1]); + return sc64_set_config(CFG_ID_SAVE_TYPE, save_type); } -bool sc64_sd_card_get_info (void *address) { - uint32_t args[2] = { (uint32_t) (address), SD_CARD_OP_GET_INFO }; - if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) { - return true; - } - return false; + +sc64_error_t sc64_flash_program (void *address, uint32_t length) { + sc64_cmd_t cmd = { + .id = CMD_ID_FLASH_PROGRAM, + .arg = { (uint32_t) (address), length } + }; + return sc64_execute_cmd(&cmd); } -bool sc64_sd_set_byte_swap (bool enabled) { - uint32_t args[2] = { (uint32_t) (NULL), enabled ? SD_CARD_OP_BYTE_SWAP_ON : SD_CARD_OP_BYTE_SWAP_OFF }; - if (sc64_execute_cmd(SC64_CMD_SD_CARD_OP, args, NULL)) { - return true; - } - return false; +sc64_error_t sc64_flash_wait_busy (void) { + sc64_cmd_t cmd = { + .id = CMD_ID_FLASH_WAIT_BUSY, + .arg = { true } + }; + return sc64_execute_cmd(&cmd); } -bool sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count) { - uint32_t sector_set_args[2] = { sector, 0 }; - uint32_t read_args[2] = { (uint32_t) (address), count }; - if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) { - return true; - } - return sc64_execute_cmd(SC64_CMD_SD_READ, read_args, NULL); +sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size) { + sc64_cmd_t cmd = { + .id = CMD_ID_FLASH_WAIT_BUSY, + .arg = { false } + }; + sc64_error_t error = sc64_execute_cmd(&cmd); + *erase_block_size = (size_t) (cmd.rsp[0]); + return error; } -bool sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count) { - uint32_t sector_set_args[2] = { sector, 0 }; - uint32_t write_args[2] = { (uint32_t) (address), count }; - if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) { - return true; - } - return sc64_execute_cmd(SC64_CMD_SD_WRITE, write_args, NULL); -} - -bool sc64_dd_set_sd_info (void *address, uint32_t length) { - uint32_t args[2] = { (uint32_t) (address), length }; - if (sc64_execute_cmd(SC64_CMD_DD_SD_INFO, args, NULL)) { - return true; - } - return false; -} - -bool sc64_writeback_enable (void *address) { - uint32_t args[2] = { (uint32_t) (address), 0 }; - if (sc64_execute_cmd(SC64_CMD_WRITEBACK_SD_INFO, args, NULL)) { - return true; - } - return false; -} - -bool sc64_flash_program (void *address, uint32_t length) { - uint32_t args[2] = { (uint32_t) (address), length }; - return sc64_execute_cmd(SC64_CMD_FLASH_PROGRAM, args, NULL); -} - -void sc64_flash_wait_busy (void) { - uint32_t args[2] = { true, 0 }; - sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, args, NULL); -} - -uint32_t sc64_flash_get_erase_block_size (void) { - uint32_t args[2] = { false, 0 }; - uint32_t result[2]; - sc64_execute_cmd(SC64_CMD_FLASH_WAIT_BUSY, args, result); - return result[0]; -} - -bool sc64_flash_erase_block (void *address) { - uint32_t args[2] = { (uint32_t) (address), 0 }; - return sc64_execute_cmd(SC64_CMD_FLASH_ERASE_BLOCK, args, NULL); +sc64_error_t sc64_flash_erase_block (void *address) { + sc64_cmd_t cmd = { + .id = CMD_ID_FLASH_ERASE_BLOCK, + .arg = { (uint32_t) (address) } + }; + return sc64_execute_cmd(&cmd); } diff --git a/sw/bootloader/src/sc64.h b/sw/bootloader/src/sc64.h index e77cff6..f8b5b57 100644 --- a/sw/bootloader/src/sc64.h +++ b/sw/bootloader/src/sc64.h @@ -21,7 +21,7 @@ typedef enum { CFG_ID_ROM_WRITE_ENABLE, CFG_ID_ROM_SHADOW_ENABLE, CFG_ID_DD_MODE, - CFG_ID_ISV_ENABLE, + CFG_ID_ISV_ADDRESS, CFG_ID_BOOT_MODE, CFG_ID_SAVE_TYPE, CFG_ID_CIC_SEED, @@ -74,6 +74,17 @@ typedef enum { TV_TYPE_PASSTHROUGH = 3 } sc64_tv_type_t; +typedef enum { + DRIVE_TYPE_RETAIL, + DRIVE_TYPE_DEVELOPMENT, +} sc64_drive_type_t; + +typedef enum { + DISK_STATE_EJECTED, + DISK_STATE_INSERTED, + DISK_STATE_CHANGED, +} sc64_disk_state_t; + typedef enum { BUTTON_MODE_NONE, BUTTON_MODE_N64_IRQ, @@ -81,14 +92,6 @@ typedef enum { BUTTON_MODE_DD_DISK_SWAP, } sc64_button_mode_t; -typedef enum { - SD_CARD_STATUS_INSERTED = (1 << 0), - SD_CARD_STATUS_INITIALIZED = (1 << 1), - SD_CARD_STATUS_TYPE_BLOCK = (1 << 2), - SD_CARD_STATUS_50MHZ_MODE = (1 << 3), - SD_CARD_STATUS_BYTE_SWAP = (1 << 4), -} sc64_sd_card_status_t; - typedef struct { sc64_boot_mode_t boot_mode; sc64_cic_seed_t cic_seed; @@ -105,6 +108,14 @@ typedef struct { uint8_t year; } sc64_rtc_time_t; +typedef enum { + SD_CARD_STATUS_INSERTED = (1 << 0), + SD_CARD_STATUS_INITIALIZED = (1 << 1), + SD_CARD_STATUS_TYPE_BLOCK = (1 << 2), + SD_CARD_STATUS_50MHZ_MODE = (1 << 3), + SD_CARD_STATUS_BYTE_SWAP = (1 << 4), +} sc64_sd_card_status_t; + typedef struct { volatile uint8_t BUFFER[8192]; @@ -117,8 +128,6 @@ typedef struct { #define SC64_BUFFERS ((sc64_buffers_t *) SC64_BUFFERS_BASE) -sc64_error_t sc64_get_error (void); - void sc64_unlock (void); void sc64_lock (void); bool sc64_check_presence (void); @@ -126,34 +135,43 @@ bool sc64_check_presence (void); bool sc64_irq_pending (void); void sc64_irq_clear (void); -uint32_t sc64_get_config (sc64_cfg_id_t id); -void sc64_set_config (sc64_cfg_id_t id, uint32_t value); -uint32_t sc64_get_setting (sc64_setting_id_t id); -void sc64_set_setting (sc64_setting_id_t id, uint32_t value); -void sc64_get_boot_info (sc64_boot_info_t *info); +sc64_error_t sc64_get_identifier (uint32_t *identifier); +sc64_error_t sc64_get_version (uint16_t *major, uint16_t *minor, uint32_t *revision); -void sc64_get_time (sc64_rtc_time_t *t); -void sc64_set_time (sc64_rtc_time_t *t); +sc64_error_t sc64_get_config (sc64_cfg_id_t id, uint32_t *value); +sc64_error_t sc64_set_config (sc64_cfg_id_t id, uint32_t value); +sc64_error_t sc64_get_setting (sc64_setting_id_t id, uint32_t *value); +sc64_error_t sc64_set_setting (sc64_setting_id_t id, uint32_t value); +sc64_error_t sc64_get_boot_info (sc64_boot_info_t *info); -bool sc64_usb_read_ready (uint8_t *type, uint32_t *length); -bool sc64_usb_read (void *address, uint32_t length); -bool sc64_usb_write_ready (void); -bool sc64_usb_write (void *address, uint8_t type, uint32_t length); +sc64_error_t sc64_get_time (sc64_rtc_time_t *t); +sc64_error_t sc64_set_time (sc64_rtc_time_t *t); -bool sc64_sd_card_init (void); -bool sc64_sd_card_deinit (void); -sc64_sd_card_status_t sc64_sd_card_get_status (void); -bool sc64_sd_card_get_info (void *address); -bool sc64_sd_set_byte_swap (bool enabled); -bool sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count); -bool sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count); -bool sc64_dd_set_sd_disk_info (void *address, uint32_t length); -bool sc64_writeback_enable (void *address); +sc64_error_t sc64_usb_get_status (bool *reset_state, bool *cable_unplugged); +sc64_error_t sc64_usb_read_info (uint8_t *type, uint32_t *length); +sc64_error_t sc64_usb_read_busy (bool *read_busy); +sc64_error_t sc64_usb_write_busy (bool *write_busy); +sc64_error_t sc64_usb_read (void *address, uint32_t length); +sc64_error_t sc64_usb_write (void *address, uint8_t type, uint32_t length); -bool sc64_flash_program (void *address, uint32_t length); -void sc64_flash_wait_busy (void); -uint32_t sc64_flash_get_erase_block_size (void); -bool sc64_flash_erase_block (void *address); +sc64_error_t sc64_sd_card_init (void); +sc64_error_t sc64_sd_card_deinit (void); +sc64_error_t sc64_sd_card_get_status (sc64_sd_card_status_t *sd_card_status); +sc64_error_t sc64_sd_card_get_info (void *address); +sc64_error_t sc64_sd_set_byte_swap (bool enabled); +sc64_error_t sc64_sd_read_sectors (void *address, uint32_t sector, uint32_t count); +sc64_error_t sc64_sd_write_sectors (void *address, uint32_t sector, uint32_t count); + +sc64_error_t sc64_dd_set_sd_info (void *address, uint32_t length); + +sc64_error_t sc64_writeback_pending (bool *pending); +sc64_error_t sc64_writeback_enable (void *address); +sc64_error_t sc64_writeback_disable (void); + +sc64_error_t sc64_flash_program (void *address, uint32_t length); +sc64_error_t sc64_flash_wait_busy (void); +sc64_error_t sc64_flash_get_erase_block_size (size_t *erase_block_size); +sc64_error_t sc64_flash_erase_block (void *address); #endif diff --git a/sw/bootloader/src/test.c b/sw/bootloader/src/test.c index 8aa194d..567153e 100644 --- a/sw/bootloader/src/test.c +++ b/sw/bootloader/src/test.c @@ -1,12 +1,38 @@ #include +#include #include "display.h" +#include "error.h" #include "io.h" #include "sc64.h" #include "test.h" +static void test_sc64_cfg (void) { + sc64_error_t error; + uint32_t identifier; + uint16_t major; + uint16_t minor; + uint32_t revision; + + if ((error = sc64_get_identifier(&identifier)) != SC64_OK) { + error_display("Command IDENTIFIER_GET failed: %d", error); + return; + } + + if ((error = sc64_get_version(&major, &minor, &revision)) != SC64_OK) { + error_display("Command VERSION_GET failed: %d", error); + return; + } + + display_printf("Identifier: 0x%08X\n\n", identifier); + + display_printf("SC64 firmware version: %d.%d.%d\n", major, minor, revision); +} + static void test_rtc (void) { + sc64_error_t error; sc64_rtc_time_t t; + const char *weekdays[8] = { "", "Monday", @@ -18,7 +44,9 @@ static void test_rtc (void) { "Sunday", }; - sc64_get_time(&t); + if ((error = sc64_get_time(&t)) != SC64_OK) { + error_display("Command TIME_GET failed: %d", error); + } display_printf("RTC current time:\n "); display_printf("%04d-%02d-%02d", 2000 + FROM_BCD(t.year), FROM_BCD(t.month), FROM_BCD(t.day)); @@ -29,11 +57,14 @@ static void test_rtc (void) { } static void test_sd_card (void) { + sc64_error_t error; sc64_sd_card_status_t card_status; uint8_t card_info[32] __attribute__((aligned(8))); uint8_t sector[512] __attribute__((aligned(8))); - card_status = sc64_sd_card_get_status(); + if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) { + error_display("Could not get SD card info: %d", error); + } if (card_status & SD_CARD_STATUS_INSERTED) { display_printf("SD card is inserted\n"); @@ -41,12 +72,14 @@ static void test_sd_card (void) { display_printf("SD card is not inserted\n"); } - if (sc64_sd_card_init()) { - display_printf("SD card init error!\n"); + if ((error = sc64_sd_card_init()) != SC64_OK) { + display_printf("SD card init error: %d\n", error); return; } - card_status = sc64_sd_card_get_status(); + if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) { + error_display("Could not get SD card info: %d", error); + } if (card_status & SD_CARD_STATUS_INITIALIZED) { display_printf("SD card is initialized\n"); @@ -61,8 +94,8 @@ static void test_sd_card (void) { display_printf("SD card read byte swap is enabled\n"); } - if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) { - display_printf("SD card get info error!\n"); + if ((error = sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) != SC64_OK) { + display_printf("SD card get info error: %d\n", error); return; } @@ -82,8 +115,8 @@ static void test_sd_card (void) { } display_printf("\n"); - if (sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) { - display_printf("SD card read sector 0 error!\n"); + if ((error = sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) != SC64_OK) { + display_printf("SD card read sector 0 error: %d\n", error); return; } @@ -101,25 +134,138 @@ static void test_sd_card (void) { display_printf(" Boot signature: 0x%02X%02X\n", sector[510], sector[511]); } +#define SDRAM_ADDRESS (0x10000000) +#define SDRAM_SIZE (64 * 1024 * 1024) +#define BUFFER_SIZE (128 * 1024) + +static uint32_t w_buffer[BUFFER_SIZE / sizeof(uint32_t)] __attribute__((aligned(8))); +static uint32_t r_buffer[BUFFER_SIZE / sizeof(uint32_t)] __attribute__((aligned(8))); + +static void test_sdram (void) { + sc64_error_t error; + + if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true))) { + error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed: %d", error); + return; + } + + if ((error = sc64_set_config(CFG_ID_ROM_SHADOW_ENABLE, false))) { + error_display("Command CONFIG_SET [ROM_SHADOW_ENABLE] failed: %d", error); + return; + } + + pi_io_config(0x0B, 0x05, 0x0C, 0x02); + display_printf("PI config - PGS: 0x0B, LAT: 0x05, PWD: 0x0C, RLS: 0x02\n"); + + const struct patterns_s { + bool constant; + uint32_t value; + } patterns[] = { + { .constant = true, .value = 0x00000000 }, + { .constant = true, .value = 0xFFFFFFFF }, + { .constant = true, .value = 0xFFFF0000 }, + { .constant = true, .value = 0x0000FFFF }, + { .constant = true, .value = 0xF0F0F0F0 }, + { .constant = true, .value = 0x0F0F0F0F }, + { .constant = true, .value = 0xAAAAAAAA }, + { .constant = true, .value = 0x55555555 }, + { .constant = true, .value = 0xA5A5A5A5 }, + { .constant = true, .value = 0x5A5A5A5A }, + { .constant = false }, + { .constant = false }, + }; + + srand(c0_count()); + + for (int pattern = 0; pattern < sizeof(patterns) / sizeof(patterns[0]); pattern++) { + if (patterns[pattern].constant) { + display_printf("Pattern: 0x%08X ", patterns[pattern].value); + for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) { + w_buffer[i] = patterns[pattern].value; + } + } else { + display_printf("Pattern: random "); + } + + for (int offset = 0; offset < SDRAM_SIZE; offset += BUFFER_SIZE) { + if (!patterns[pattern].constant) { + for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) { + *UNCACHED(&w_buffer[i]) = (rand() << 31) | rand(); + } + } + + pi_dma_write((io32_t *) (SDRAM_ADDRESS + offset), w_buffer, BUFFER_SIZE); + + pi_dma_read((io32_t *) (SDRAM_ADDRESS + offset), r_buffer, BUFFER_SIZE); + + for (int i = 0; i < BUFFER_SIZE / sizeof(uint32_t); i++) { + if (*UNCACHED(&w_buffer[i]) != *UNCACHED(&r_buffer[i])) { + display_printf( + "\nMISMATCH: [0x%08X]: 0x%08X (R) != 0x%08X (W)\n", + SDRAM_ADDRESS + offset, + *UNCACHED(&r_buffer[i]), + *UNCACHED(&w_buffer[i]) + ); + while (true); + } + } + + if ((offset % (SDRAM_SIZE / 32)) == 0) { + display_printf("."); + } + } + + display_printf(" OK\n"); + } +} + bool test_check (void) { + sc64_error_t error; + uint32_t button_state; + if (OS_INFO->reset_type != OS_INFO_RESET_TYPE_COLD) { return false; } - return sc64_get_config(CFG_ID_BUTTON_STATE); + + if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) { + error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error); + } + + return button_state != 0; } +static struct { + const char *title; + void (*fn) (void); +} tests[] = { + { "SC64 CFG", test_sc64_cfg }, + { "RTC", test_rtc }, + { "SD card", test_sd_card }, + { "SDRAM", test_sdram }, +}; + void test_execute (void) { - display_init(NULL); - display_printf("SC64 Test suite\n\n"); + const int test_count = sizeof(tests) / sizeof(tests[0]); + int current = 0; - display_printf("[ RTC tests ]\n"); - test_rtc(); - display_printf("\n"); + while (true) { + display_init(NULL); + display_printf("SC64 Test suite (%d / %d)\n\n", current + 1, test_count); - display_printf("[ SD card tests ]\n"); - test_sd_card(); - display_printf("\n"); + display_printf("[ %s tests ]\n\n", tests[current].title); + tests[current].fn(); + display_printf("\n"); - while (1); + current += 1; + if (current == test_count) { + current = 0; + } + + display_printf("Next test [ %s ] starts in: ", tests[current].title); + for (int delay = 5; delay > 0; delay--) { + display_printf("\b%d", delay); + delay_ms(1000); + } + } }