[SC64][SW] bootloader/controller: added more meaningful errors in the SD card module

Also added manual CRC16 check in the software for data blocks smaller than 512 bytes
This commit is contained in:
Mateusz Faderewski 2024-05-14 01:36:34 +02:00
parent 92838da349
commit e6751c262d
16 changed files with 468 additions and 221 deletions

View File

@ -10,6 +10,9 @@
#define BUFFER_BLOCKS_MAX (sizeof(SC64_BUFFERS->BUFFER) / SD_SECTOR_SIZE)
sc64_error_t sc64_error_fatfs;
DSTATUS disk_status (BYTE pdrv) {
if (pdrv > 0) {
return STA_NODISK;
@ -20,7 +23,7 @@ DSTATUS disk_status (BYTE pdrv) {
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);
error_display("Could not get SD card status\n (%08X) - %s", error, sc64_error_description(error));
}
if (!(sd_card_status & SD_CARD_STATUS_INSERTED)) {
@ -38,7 +41,7 @@ DSTATUS disk_initialize (BYTE pdrv) {
return STA_NODISK;
}
sc64_sd_card_init();
sc64_error_fatfs = sc64_sd_card_init();
return disk_status(pdrv);
}
@ -53,7 +56,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) != SC64_OK) {
if ((sc64_error_fatfs = sc64_sd_read_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) != SC64_OK) {
return RES_ERROR;
}
if (((uint32_t) (buff) % 8) == 0) {
@ -67,7 +70,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) != SC64_OK) {
if ((sc64_error_fatfs = sc64_sd_read_sectors(physical_address, sector, count)) != SC64_OK) {
return RES_ERROR;
}
}
@ -91,7 +94,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) != SC64_OK) {
if ((sc64_error_fatfs = sc64_sd_write_sectors((uint32_t *) (SC64_BUFFERS->BUFFER), sector, blocks)) != SC64_OK) {
return RES_ERROR;
}
buff += length;
@ -99,7 +102,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) != SC64_OK) {
if ((sc64_error_fatfs = sc64_sd_write_sectors(physical_address, sector, count)) != SC64_OK) {
return RES_ERROR;
}
}
@ -122,7 +125,7 @@ DWORD get_fattime(void) {
sc64_rtc_time_t t;
if ((error = sc64_get_time(&t)) != SC64_OK) {
error_display("Command TIME_GET failed: %d", error);
error_display("Command TIME_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
return (

View File

@ -28,7 +28,7 @@ void init (init_tv_type_t tv_type, init_reset_type_t reset_type, uint32_t entrop
exception_enable_interrupts();
if ((error = sc64_set_config(CFG_ID_BOOTLOADER_SWITCH, false)) != SC64_OK) {
error_display("Command CONFIG_SET [BOOTLOADER_SWITCH] failed: %d", error);
error_display("Command CONFIG_SET [BOOTLOADER_SWITCH] failed\n (%08X) - %s", error, sc64_error_description(error));
}
if (test_check()) {

View File

@ -12,7 +12,7 @@ void main (void) {
sc64_boot_params_t sc64_boot_params;
if ((error = sc64_get_boot_params(&sc64_boot_params)) != SC64_OK) {
error_display("Could not obtain boot info: %d", error);
error_display("Could not obtain boot info\n (%08X) - %s", error, sc64_error_description(error));
}
boot_params_t boot_params;
@ -40,7 +40,7 @@ void main (void) {
break;
default:
error_display("Unknown boot mode selected [%d]\n", sc64_boot_params.boot_mode);
error_display("Unknown boot mode selected (%d)\n", sc64_boot_params.boot_mode);
break;
}

View File

@ -8,8 +8,11 @@
#define ROM_ADDRESS (0x10000000)
extern sc64_error_t sc64_error_fatfs;
static const char *fatfs_error_codes[] = {
"Succeeded",
"No error",
"A hard error occurred in the low level disk I/O layer",
"Assertion failed",
"The physical drive cannot work",
@ -35,7 +38,14 @@ static const char *fatfs_error_codes[] = {
#define FF_CHECK(x, message, ...) { \
fresult = x; \
if (fresult != FR_OK) { \
error_display(message ".\nReason: %s", __VA_ARGS__ __VA_OPT__(,) fatfs_error_codes[fresult]); \
error_display( \
message "\n" \
" > FatFs error: %s\n" \
" > SD card error: %s (%08X)", \
__VA_ARGS__ __VA_OPT__(,) \
fatfs_error_codes[fresult], \
sc64_error_description(sc64_error_fatfs), sc64_error_fatfs \
); \
} \
}
@ -55,15 +65,15 @@ void menu_load (void) {
do {
if ((error = sc64_writeback_pending(&writeback_pending)) != SC64_OK) {
error_display("Command WRITEBACK_PENDING failed: %d", error);
error_display("Command WRITEBACK_PENDING failed\n (%08X) - %s", error, sc64_error_description(error));
}
} while (writeback_pending);
if ((error = sc64_writeback_disable()) != SC64_OK) {
error_display("Could not disable writeback: %d", error);
error_display("Could not disable save writeback\n (%08X) - %s", error, sc64_error_description(error));
}
FF_CHECK(f_mount(&fs, "", 1), "SD card initialize error. No SD card or invalid partition table");
FF_CHECK(f_mount(&fs, "", 1), "SD card initialize error");
FF_CHECK(f_open(&fil, "sc64menu.n64", FA_READ), "Could not open menu executable (sc64menu.n64)");
fix_menu_file_size(&fil);
FF_CHECK(f_read(&fil, (void *) (ROM_ADDRESS), f_size(&fil), &bytes_read), "Could not read menu file");

View File

@ -89,6 +89,61 @@ static sc64_error_t sc64_execute_cmd (sc64_cmd_t *cmd) {
}
const char *sc64_error_description (sc64_error_t error) {
sc64_error_type_t type = (sc64_error_type_t) ((error >> 24) & 0xFF);
error &= 0xFFFFFF;
if (type == ERROR_TYPE_CFG) {
switch ((sc64_cfg_error_t) (error)) {
case SC64_OK: return "No error";
case CFG_ERROR_UNKNOWN_COMMAND: return "Unknown command";
case CFG_ERROR_INVALID_ARGUMENT: return "Invalid argument";
case CFG_ERROR_INVALID_ADDRESS: return "Invalid address";
case CFG_ERROR_INVALID_ID: return "Invalid ID";
default: return "Unknown error (CFG)";
}
}
if (type == ERROR_TYPE_SD_CARD) {
switch ((sc64_sd_error_t) (error)) {
case SD_OK: return "No error (SD)";
case SD_ERROR_NO_CARD_IN_SLOT: return "No SD card in the slot";
case SD_ERROR_NOT_INITIALIZED: return "SD card is not initialized";
case SD_ERROR_INVALID_ARGUMENT: return "Invalid argument (SD)";
case SD_ERROR_INVALID_ADDRESS: return "Invalid address (SD)";
case SD_ERROR_INVALID_OPERATION: return "Invalid operation (SD)";
case SD_ERROR_CMD2_IO: return "CMD2 I/O";
case SD_ERROR_CMD3_IO: return "CMD3 I/O";
case SD_ERROR_CMD6_CHECK_IO: return "CMD6 I/O (check)";
case SD_ERROR_CMD6_CHECK_CRC: return "CMD6 CRC (check)";
case SD_ERROR_CMD6_CHECK_TIMEOUT: return "CMD6 timeout (check)";
case SD_ERROR_CMD6_CHECK_RESPONSE: return "CMD6 invalid response (check)";
case SD_ERROR_CMD6_SWITCH_IO: return "CMD6 I/O (switch)";
case SD_ERROR_CMD6_SWITCH_CRC: return "CMD6 CRC (switch)";
case SD_ERROR_CMD6_SWITCH_TIMEOUT: return "CMD6 timeout (switch)";
case SD_ERROR_CMD6_SWITCH_RESPONSE: return "CMD6 invalid response (switch)";
case SD_ERROR_CMD7_IO: return "CMD7 I/O";
case SD_ERROR_CMD8_IO: return "CMD8 I/O";
case SD_ERROR_CMD9_IO: return "CMD9 I/O";
case SD_ERROR_CMD10_IO: return "CMD10 I/O";
case SD_ERROR_CMD18_IO: return "CMD18 I/O";
case SD_ERROR_CMD18_CRC: return "CMD18 CRC";
case SD_ERROR_CMD18_TIMEOUT: return "CMD18 timeout";
case SD_ERROR_CMD25_IO: return "CMD25 I/O";
case SD_ERROR_CMD25_CRC: return "CMD25 CRC";
case SD_ERROR_CMD25_TIMEOUT: return "CMD25 timeout";
case SD_ERROR_ACMD6_IO: return "ACMD6 I/O";
case SD_ERROR_ACMD41_IO: return "ACMD41 I/O";
case SD_ERROR_ACMD41_OCR: return "ACMD41 OCR";
case SD_ERROR_ACMD41_TIMEOUT: return "ACMD41 timeout";
default: return "Unknown error (SD)";
}
}
return "Unknown error (type)";
}
void sc64_unlock (void) {
pi_io_write(&SC64_REGS->KEY, SC64_KEY_RESET);
pi_io_write(&SC64_REGS->KEY, SC64_KEY_UNLOCK_1);
@ -396,8 +451,7 @@ sc64_error_t sc64_writeback_enable (void *address) {
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) {
if ((error = sc64_get_config(CFG_ID_SAVE_TYPE, &save_type)) != SC64_OK) {
return error;
}
return sc64_set_config(CFG_ID_SAVE_TYPE, save_type);

View File

@ -8,14 +8,52 @@
typedef enum {
SC64_OK,
SC64_ERROR_BAD_ARGUMENT,
SC64_ERROR_BAD_ADDRESS,
SC64_ERROR_BAD_CONFIG_ID,
SC64_ERROR_TIMEOUT,
SC64_ERROR_SD_CARD,
SC64_ERROR_UNKNOWN_CMD = -1
} sc64_error_t;
ERROR_TYPE_CFG = 0,
ERROR_TYPE_SD_CARD = 1,
} sc64_error_type_t;
typedef enum {
SC64_OK = 0,
CFG_ERROR_UNKNOWN_COMMAND = 1,
CFG_ERROR_INVALID_ARGUMENT = 2,
CFG_ERROR_INVALID_ADDRESS = 3,
CFG_ERROR_INVALID_ID = 4,
} sc64_cfg_error_t;
typedef enum {
SD_OK = 0,
SD_ERROR_NO_CARD_IN_SLOT = 1,
SD_ERROR_NOT_INITIALIZED = 2,
SD_ERROR_INVALID_ARGUMENT = 3,
SD_ERROR_INVALID_ADDRESS = 4,
SD_ERROR_INVALID_OPERATION = 5,
SD_ERROR_CMD2_IO = 6,
SD_ERROR_CMD3_IO = 7,
SD_ERROR_CMD6_CHECK_IO = 8,
SD_ERROR_CMD6_CHECK_CRC = 9,
SD_ERROR_CMD6_CHECK_TIMEOUT = 10,
SD_ERROR_CMD6_CHECK_RESPONSE = 11,
SD_ERROR_CMD6_SWITCH_IO = 12,
SD_ERROR_CMD6_SWITCH_CRC = 13,
SD_ERROR_CMD6_SWITCH_TIMEOUT = 14,
SD_ERROR_CMD6_SWITCH_RESPONSE = 15,
SD_ERROR_CMD7_IO = 16,
SD_ERROR_CMD8_IO = 17,
SD_ERROR_CMD9_IO = 18,
SD_ERROR_CMD10_IO = 19,
SD_ERROR_CMD18_IO = 20,
SD_ERROR_CMD18_CRC = 21,
SD_ERROR_CMD18_TIMEOUT = 22,
SD_ERROR_CMD25_IO = 23,
SD_ERROR_CMD25_CRC = 24,
SD_ERROR_CMD25_TIMEOUT = 25,
SD_ERROR_ACMD6_IO = 26,
SD_ERROR_ACMD41_IO = 27,
SD_ERROR_ACMD41_OCR = 28,
SD_ERROR_ACMD41_TIMEOUT = 29,
} sc64_sd_error_t;
typedef uint32_t sc64_error_t;
typedef enum {
CFG_ID_BOOTLOADER_SWITCH,
@ -133,6 +171,8 @@ typedef struct {
#define SC64_BUFFERS ((sc64_buffers_t *) SC64_BUFFERS_BASE)
const char *sc64_error_description (sc64_error_t error);
void sc64_unlock (void);
void sc64_lock (void);
bool sc64_check_presence (void);

View File

@ -63,22 +63,22 @@ static void test_sc64_cfg (void) {
do {
if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) {
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
error_display("Command CONFIG_GET [BUTTON_STATE] failed\n (%08X) - %s", error, sc64_error_description(error));
}
} while (button_state != 0);
display_printf("done\n\n");
if ((error = sc64_get_identifier(&identifier)) != SC64_OK) {
error_display("Command IDENTIFIER_GET failed: %d", error);
error_display("Command IDENTIFIER_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
if ((error = sc64_get_version(&major, &minor, &revision)) != SC64_OK) {
error_display("Command VERSION_GET failed: %d", error);
error_display("Command VERSION_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
if ((error = sc64_get_diagnostic(DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE, &tmp)) != SC64_OK) {
error_display("Command DIAGNOSTIC_GET failed: %d", error);
error_display("Command DIAGNOSTIC_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
uint16_t voltage = (uint16_t) (tmp >> 16);
@ -104,7 +104,7 @@ static void test_sc64_cfg (void) {
sc64_rtc_time_t t;
if ((error = sc64_get_time(&t)) != SC64_OK) {
error_display("Command TIME_GET failed: %d", error);
error_display("Command TIME_GET failed\n (%08X) - %s", error, sc64_error_description(error));
}
display_printf("RTC current time:\n ");
@ -136,16 +136,14 @@ static void test_pi (void) {
for (int i = 0; i < size / sizeof(uint32_t); i++) {
if (w_buffer[i] != r_buffer[i]) {
display_printf(
"\n"
error_display(
"PI test failed:\n"
" > Mismatch error at address 0x%08lX\n"
" > 0x%08lX (W) != 0x%08lX (R)",
(uint32_t) (SC64_BUFFERS->BUFFER) + (i * sizeof(uint32_t)),
w_buffer[i],
r_buffer[i]
);
while (true);
}
}
}
@ -162,7 +160,7 @@ static void test_sd_card_io (void) {
uint8_t sector[512] __attribute__((aligned(8)));
if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) {
error_display("Could not get SD card info: %d", error);
error_display("Could not get SD card info\n (%08X) - %s", error, sc64_error_description(error));
}
if (card_status & SD_CARD_STATUS_INSERTED) {
@ -172,15 +170,15 @@ static void test_sd_card_io (void) {
}
if ((error = sc64_sd_card_deinit()) != SC64_OK) {
return display_printf("SD card deinit error: %d", error);
error_display("SD card deinit error\n (%08X) - %s", error, sc64_error_description(error));
}
if ((error = sc64_sd_card_init()) != SC64_OK) {
return display_printf("SD card init error: %d\n", error);
return display_printf("SD card init error\n (%08X) - %s\n", error, sc64_error_description(error));
}
if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) {
error_display("Could not get SD card info: %d", error);
error_display("Could not get SD card info\n (%08X) - %s", error, sc64_error_description(error));
}
if (card_status & SD_CARD_STATUS_INITIALIZED) {
@ -197,7 +195,7 @@ static void test_sd_card_io (void) {
}
if ((error = sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) != SC64_OK) {
return display_printf("SD card get info error: %d\n", error);
error_display("SD card get info error\n (%08X) - %s", error, sc64_error_description(error));
}
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), card_info, sizeof(card_info));
@ -217,7 +215,7 @@ static void test_sd_card_io (void) {
display_printf("\n");
if ((error = sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) != SC64_OK) {
return display_printf("SD card read sector 0 error: %d\n", error);
return display_printf("SD card read sector 0 error\n (%08X) - %s\n", error, sc64_error_description(error));
}
pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), sector, sizeof(sector));
@ -245,21 +243,21 @@ static void test_sd_card_fatfs (void) {
UINT bytes;
if ((error = sc64_sd_card_deinit()) != SC64_OK) {
return display_printf("SD card deinit error: %d", error);
error_display("SD card deinit error\n (%08X) - %s", error, sc64_error_description(error));
}
if ((fresult = f_mount(&fs, "", 1)) != FR_OK) {
return display_printf("f_mount error: %d\n", fresult);
display_printf("f_mount error: %d\n", fresult);
}
if ((fresult = f_getlabel("", label, &vsn)) != FR_OK) {
return display_printf("f_getlabel error: %d\n", fresult);
display_printf("f_getlabel error: %d\n", fresult);
} else {
display_printf("Volume [%s] / [%08lX]\n\n", label, vsn);
}
display_printf("Volume [%s] / [%08lX]\n\n", label, vsn);
if ((fresult = f_open(&fil, "sc64test.bin", FA_CREATE_ALWAYS | FA_WRITE)) != FR_OK) {
return display_printf("f_open (write) error: %d\n", fresult);
display_printf("f_open (write) error: %d\n", fresult);
}
srand(random_seed);
@ -276,11 +274,13 @@ static void test_sd_card_fatfs (void) {
fill_random(w_buffer, block_size, 0, 0);
if ((fresult = f_write(&fil, w_buffer, block_size, &bytes)) != FR_OK) {
return display_printf("\nf_write error: %d\n", fresult);
display_printf("\nf_write error: %d", fresult);
break;
}
if (bytes != block_size) {
return display_printf("\nf_write (%ld!=%ld) error: %d\n", bytes, block_size, fresult);
display_printf("\nf_write (%ld!=%ld) error: %d", bytes, block_size, fresult);
break;
}
left -= block_size;
@ -289,15 +289,15 @@ static void test_sd_card_fatfs (void) {
display_printf("\n");
if ((fresult = f_close(&fil)) != FR_OK) {
return display_printf("f_close (write) error: %d\n", fresult);
display_printf("f_close (write) error: %d\n", fresult);
}
if ((fresult = f_open(&fil, "sc64test.bin", FA_OPEN_EXISTING | FA_READ)) != FR_OK) {
return display_printf("f_open (read) error: %d\n", fresult);
display_printf("f_open (read) error: %d\n", fresult);
}
if (f_size(&fil) != SD_TEST_FILE_SIZE) {
return display_printf("f_size (%d!=%d) error\n", f_size(&fil), SD_TEST_FILE_SIZE);
display_printf("f_size (%d!=%d) error\n", f_size(&fil), SD_TEST_FILE_SIZE);
}
srand(random_seed);
@ -314,25 +314,25 @@ static void test_sd_card_fatfs (void) {
fill_random(w_buffer, block_size, 0, 0);
if ((fresult = f_read(&fil, r_buffer, block_size, &bytes)) != FR_OK) {
return display_printf("\nf_read error: %d\n", fresult);
display_printf("\nf_read error: %d", fresult);
break;
}
if (bytes != block_size) {
return display_printf("\nf_read (%ld!=%ld) error: %d\n", bytes, block_size, fresult);
display_printf("\nf_read (%ld!=%ld) error: %d", bytes, block_size, fresult);
break;
}
for (UINT i = 0; i < (block_size / sizeof(uint32_t)); i++) {
if (w_buffer[i] != r_buffer[i]) {
display_printf(
"\n"
error_display(
"SD card (FatFs) test failed:\n"
" > Mismatch error at file offset 0x%08lX\n"
" > 0x%08lX (W) != 0x%08lX (R)",
f_tell(&fil) + (i * sizeof(uint32_t)),
w_buffer[i],
r_buffer[i]
);
while (true);
}
}
@ -342,15 +342,15 @@ static void test_sd_card_fatfs (void) {
display_printf("\n");
if ((fresult = f_close(&fil)) != FR_OK) {
return display_printf("f_close (read) error: %d\n", fresult);
display_printf("f_close (read) error: %d\n", fresult);
}
if ((fresult = f_unlink("sc64test.bin")) != FR_OK) {
return display_printf("f_unlink error: %d\n", fresult);
display_printf("f_unlink error: %d\n", fresult);
}
if ((fresult = f_unmount("")) != FR_OK) {
return display_printf("f_unmount error: %d\n", fresult);
display_printf("f_unmount error: %d\n", fresult);
}
random_seed += c0_count();
@ -473,16 +473,15 @@ static void test_sdram (void) {
for (int i = 0; i < TEST_BUFFER_SIZE / sizeof(uint64_t); i++) {
if (test_data[i] != check_data[i]) {
display_printf(
"\n"
error_display(
"SDRAM test failed, %s\n"
" > Mismatch error at address 0x%08lX\n"
" > 0x%016llX (W) != 0x%016llX (R)",
test->name,
SDRAM_ADDRESS + offset + (i * sizeof(uint64_t)),
test_data[i],
check_data[i]
);
while (true);
}
}
}
@ -511,7 +510,7 @@ bool test_check (void) {
}
if ((error = sc64_get_config(CFG_ID_BUTTON_STATE, &button_state)) != SC64_OK) {
error_display("Command CONFIG_GET [BUTTON_STATE] failed: %d", error);
error_display("Command CONFIG_GET [BUTTON_STATE] failed\n (%08X) - %s", error, sc64_error_description(error));
}
return (button_state != 0);
@ -538,12 +537,12 @@ void test_execute (void) {
pi_io_config(0x0F, 0x05, 0x0C, 0x02);
if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true))) {
error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed: %d", error);
if ((error = sc64_set_config(CFG_ID_ROM_WRITE_ENABLE, true)) != SC64_OK) {
error_display("Command CONFIG_SET [ROM_WRITE_ENABLE] failed\n (%08X) - %s", error, sc64_error_description(error));
}
if ((error = sc64_set_config(CFG_ID_ROM_SHADOW_ENABLE, false))) {
error_display("Command CONFIG_SET [ROM_SHADOW_ENABLE] failed: %d", error);
if ((error = sc64_set_config(CFG_ID_ROM_SHADOW_ENABLE, false)) != SC64_OK) {
error_display("Command CONFIG_SET [ROM_SHADOW_ENABLE] failed\n (%08X) - %s", error, sc64_error_description(error));
}
random_seed = __entropy + c0_count();

View File

@ -66,16 +66,6 @@ typedef enum {
TV_TYPE_PASSTHROUGH = 3
} tv_type_t;
typedef enum {
CFG_ERROR_OK = 0,
CFG_ERROR_BAD_ARGUMENT = 1,
CFG_ERROR_BAD_ADDRESS = 2,
CFG_ERROR_BAD_CONFIG_ID = 3,
CFG_ERROR_TIMEOUT = 4,
CFG_ERROR_SD_CARD = 5,
CFG_ERROR_UNKNOWN_CMD = -1,
} cfg_error_t;
typedef enum {
SD_CARD_OP_DEINIT = 0,
SD_CARD_OP_INIT = 1,
@ -95,6 +85,18 @@ typedef enum {
BRAM = (1 << 2),
} translate_type_t;
typedef enum {
ERROR_TYPE_CFG = 0,
ERROR_TYPE_SD_CARD = 1,
} error_type_t;
typedef enum {
CFG_OK = 0,
CFG_ERROR_UNKNOWN_COMMAND = 1,
CFG_ERROR_INVALID_ARGUMENT = 2,
CFG_ERROR_INVALID_ADDRESS = 3,
CFG_ERROR_INVALID_ID = 4,
} cfg_error_t;
struct process {
boot_mode_t boot_mode;
@ -169,8 +171,8 @@ static bool cfg_translate_address (uint32_t *address, uint32_t length, translate
return true;
}
static void cfg_set_error (cfg_error_t error) {
fpga_reg_set(REG_CFG_DATA_0, error);
static void cfg_set_error (error_type_t type, uint32_t error) {
fpga_reg_set(REG_CFG_DATA_0, ((type & 0xFF) << 24) | (error & 0xFFFFFF));
fpga_reg_set(REG_CFG_DATA_1, 0);
fpga_reg_set(REG_CFG_CMD, CFG_CMD_ERROR | CFG_CMD_DONE);
}
@ -504,7 +506,7 @@ void cfg_process (void) {
case 'c':
if (cfg_query(args)) {
cfg_set_error(CFG_ERROR_BAD_CONFIG_ID);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
return;
}
break;
@ -513,7 +515,7 @@ void cfg_process (void) {
prev_cfg[0] = args[0];
cfg_query(prev_cfg);
if (cfg_update(args)) {
cfg_set_error(CFG_ERROR_BAD_CONFIG_ID);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
return;
}
args[1] = prev_cfg[1];
@ -521,14 +523,14 @@ void cfg_process (void) {
case 'a':
if (cfg_query_setting(args)) {
cfg_set_error(CFG_ERROR_BAD_CONFIG_ID);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
return;
}
break;
case 'A':
if (cfg_update_setting(args)) {
cfg_set_error(CFG_ERROR_BAD_CONFIG_ID);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
return;
}
break;
@ -543,7 +545,7 @@ void cfg_process (void) {
case 'm':
if (cfg_translate_address(&args[0], args[1], (SDRAM | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
return;
}
if (!usb_prepare_read(args)) {
@ -553,7 +555,7 @@ void cfg_process (void) {
case 'M':
if (cfg_translate_address(&args[0], args[1] & 0xFFFFFF, (SDRAM | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
return;
}
usb_create_packet(&packet_info, PACKET_CMD_DEBUG_OUTPUT);
@ -584,10 +586,10 @@ void cfg_process (void) {
break;
case SD_CARD_OP_INIT: {
led_activity_on();
bool error = sd_card_init();
sd_error_t error = sd_card_init();
led_activity_off();
if (error) {
cfg_set_error(CFG_ERROR_SD_CARD);
if (error != SD_OK) {
cfg_set_error(ERROR_TYPE_SD_CARD, error);
return;
}
break;
@ -595,30 +597,36 @@ void cfg_process (void) {
case SD_CARD_OP_GET_STATUS:
args[1] = sd_card_get_status();
break;
case SD_CARD_OP_GET_INFO:
case SD_CARD_OP_GET_INFO: {
if (cfg_translate_address(&args[0], SD_CARD_INFO_SIZE, (SDRAM | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS);
return;
}
if (sd_card_get_info(args[0])) {
cfg_set_error(CFG_ERROR_SD_CARD);
sd_error_t error = sd_card_get_info(args[0]);
if (error != SD_OK) {
cfg_set_error(ERROR_TYPE_SD_CARD, error);
return;
}
break;
case SD_CARD_OP_BYTE_SWAP_ON:
if (sd_set_byte_swap(true)) {
cfg_set_error(CFG_ERROR_SD_CARD);
}
case SD_CARD_OP_BYTE_SWAP_ON: {
sd_error_t error = sd_set_byte_swap(true);
if (error != SD_OK) {
cfg_set_error(ERROR_TYPE_SD_CARD, error);
return;
}
break;
case SD_CARD_OP_BYTE_SWAP_OFF:
if (sd_set_byte_swap(false)) {
cfg_set_error(CFG_ERROR_SD_CARD);
}
case SD_CARD_OP_BYTE_SWAP_OFF: {
sd_error_t error = sd_set_byte_swap(false);
if (error != SD_OK) {
cfg_set_error(ERROR_TYPE_SD_CARD, error);
return;
}
break;
}
default:
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_OPERATION);
return;
}
break;
@ -629,18 +637,18 @@ void cfg_process (void) {
case 's': {
if (args[1] >= 0x800000) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ARGUMENT);
return;
}
if (cfg_translate_address(&args[0], args[1] * SD_SECTOR_SIZE, (SDRAM | FLASH | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS);
return;
}
led_activity_on();
bool error = sd_read_sectors(args[0], p.sd_card_sector, args[1]);
sd_error_t error = sd_read_sectors(args[0], p.sd_card_sector, args[1]);
led_activity_off();
if (error) {
cfg_set_error(CFG_ERROR_SD_CARD);
if (error != SD_OK) {
cfg_set_error(ERROR_TYPE_SD_CARD, error);
return;
}
p.sd_card_sector += args[1];
@ -649,18 +657,18 @@ void cfg_process (void) {
case 'S': {
if (args[1] >= 0x800000) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ARGUMENT);
return;
}
if (cfg_translate_address(&args[0], args[1] * SD_SECTOR_SIZE, (SDRAM | FLASH | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS);
return;
}
led_activity_on();
bool error = sd_write_sectors(args[0], p.sd_card_sector, args[1]);
sd_error_t error = sd_write_sectors(args[0], p.sd_card_sector, args[1]);
led_activity_off();
if (error) {
cfg_set_error(CFG_ERROR_SD_CARD);
if (error != SD_OK) {
cfg_set_error(ERROR_TYPE_SD_CARD, error);
return;
}
p.sd_card_sector += args[1];
@ -669,7 +677,7 @@ void cfg_process (void) {
case 'D':
if (cfg_translate_address(&args[0], args[1], (SDRAM | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
return;
}
dd_set_disk_mapping(args[0], args[1]);
@ -681,7 +689,7 @@ void cfg_process (void) {
case 'W':
if (cfg_translate_address(&args[0], WRITEBACK_SECTOR_TABLE_SIZE, (SDRAM | BRAM))) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
return;
}
writeback_load_sector_table(args[0]);
@ -690,15 +698,15 @@ void cfg_process (void) {
case 'K':
if (args[1] >= DATA_BUFFER_SIZE) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT);
return;
}
if (cfg_translate_address(&args[0], args[1], FLASH)) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
return;
}
if (flash_program(DATA_BUFFER_ADDRESS, args[0], args[1])) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT);
return;
}
break;
@ -712,24 +720,24 @@ void cfg_process (void) {
case 'P':
if (cfg_translate_address(&args[0], FLASH_ERASE_BLOCK_SIZE, FLASH)) {
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ADDRESS);
return;
}
if (flash_erase_block(args[0])) {
cfg_set_error(CFG_ERROR_BAD_ARGUMENT);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ARGUMENT);
return;
}
break;
case '%':
if (cfg_read_diagnostic_data(args)) {
cfg_set_error(CFG_ERROR_BAD_CONFIG_ID);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_INVALID_ID);
return;
}
break;
default:
cfg_set_error(CFG_ERROR_UNKNOWN_CMD);
cfg_set_error(ERROR_TYPE_CFG, CFG_ERROR_UNKNOWN_COMMAND);
return;
}

View File

@ -137,9 +137,9 @@ static bool dd_block_read_request (void) {
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, false);
led_activity_on();
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors);
sd_error_t error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_read_sectors);
led_activity_off();
dd_set_block_ready(!error);
dd_set_block_ready(error == SD_OK);
} else {
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST);
@ -161,9 +161,9 @@ static bool dd_block_write_request (void) {
uint32_t sector_table[DD_SD_SECTOR_TABLE_SIZE];
uint32_t sectors = dd_fill_sd_sector_table(index, sector_table, true);
led_activity_on();
bool error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors);
sd_error_t error = sd_optimize_sectors(buffer_address, sector_table, sectors, sd_write_sectors);
led_activity_off();
dd_set_block_ready(!error);
dd_set_block_ready(error == SD_OK);
} else {
usb_tx_info_t packet_info;
usb_create_packet(&packet_info, PACKET_CMD_DD_REQUEST);

View File

@ -61,7 +61,6 @@ typedef enum {
#define ALIGN(value, align) (((value) + ((typeof(value))(align) - 1)) & ~((typeof(value))(align) - 1))
#define SWAP16(x) ((((x) & 0xFF) << 8) | (((x) & 0xFF00) >> 8))
#define SWAP32(x) (((x) & 0xFF) << 24 | ((x) & 0xFF00) << 8 | ((x) & 0xFF0000) >> 8 | ((x) & 0xFF000000) >> 24)
#define FPGA_ID (0x64)

View File

@ -339,12 +339,12 @@ static void hw_i2c_init (void) {
I2C1->CR1 |= I2C_CR1_PE;
}
i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
i2c_error_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length) {
hw_timeout_start();
while (I2C1->ISR & I2C_ISR_BUSY) {
if (hw_timeout_elapsed(I2C_TIMEOUT_US_BUSY)) {
return I2C_ERR_BUSY;
return I2C_ERROR_BUSY;
}
}
@ -372,11 +372,11 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint
}
if (isr & I2C_ISR_NACKF) {
return I2C_ERR_NACK;
return I2C_ERROR_NACK;
}
if (hw_timeout_elapsed(tx_timeout)) {
return I2C_ERR_TIMEOUT;
return I2C_ERROR_TIMEOUT;
}
}
@ -386,7 +386,7 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint
while (!(I2C1->ISR & I2C_ISR_TC)) {
if (hw_timeout_elapsed(tx_timeout)) {
return I2C_ERR_TIMEOUT;
return I2C_ERROR_TIMEOUT;
}
}
}
@ -415,7 +415,7 @@ i2c_err_t hw_i2c_trx (uint8_t address, uint8_t *tx_data, uint8_t tx_length, uint
}
if (hw_timeout_elapsed(rx_timeout)) {
return I2C_ERR_TIMEOUT;
return I2C_ERROR_TIMEOUT;
}
}
}

View File

@ -27,10 +27,10 @@ typedef enum {
typedef enum {
I2C_OK,
I2C_ERR_BUSY,
I2C_ERR_TIMEOUT,
I2C_ERR_NACK,
} i2c_err_t;
I2C_ERROR_BUSY,
I2C_ERROR_TIMEOUT,
I2C_ERROR_NACK,
} i2c_error_t;
typedef uint64_t hw_flash_t;
@ -72,7 +72,7 @@ void hw_spi_stop (void);
void hw_spi_rx (uint8_t *data, int length);
void hw_spi_tx (uint8_t *data, int length);
i2c_err_t hw_i2c_trx (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
i2c_error_t hw_i2c_trx (uint8_t i2c_address, uint8_t *tx_data, uint8_t tx_length, uint8_t *rx_data, uint8_t rx_length);
void hw_crc32_reset (void);
uint32_t hw_crc32_calculate (uint8_t *data, uint32_t length);

View File

@ -133,9 +133,9 @@ static bool lcmxo2_execute_cmd (uint8_t cmd, uint32_t arg, cmd_type_t type, uint
packet_length += length;
}
i2c_err_t err = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
i2c_error_t error = hw_i2c_trx(LCMXO2_I2C_ADDR_CFG, packet, packet_length, buffer, (write ? 0 : length));
return (err != I2C_OK);
return (error != I2C_OK);
#else
lcmxo2_reg_set(LCMXO2_CFGCR, CFGCR_WBCE);

View File

@ -9,6 +9,10 @@
#define CMD6_ARG_CHECK_HS (0x00FFFFF1UL)
#define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL)
#define CMD6_DATA_LENGTH (64)
#define CMD6_INVALID_CURRENT_LIMIT(b) ((((b)[0] << 8) | (b)[1]) == 0)
#define CMD6_HS_SUPPORTED(b) ((b)[13] & (1 << 1))
#define CMD6_HS_ENABLED(b) (((b)[16] & 0x0F) == 0x01)
#define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define CMD8_ARG_CHECK_PATTERN (0xAA << 0)
@ -18,6 +22,9 @@
#define ACMD41_ARG_OCR (0x300000 << 0)
#define ACMD41_ARG_HCS (1 << 30)
#define R1_APP_CMD (1 << 5)
#define R1_ILLEGAL_COMMAND (1 << 22)
#define R3_OCR (0x300000 << 0)
#define R3_CCS (1 << 30)
#define R3_BUSY (1 << 31)
@ -27,12 +34,9 @@
#define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8)
#define R7_CHECK_PATTERN (0xAA << 0)
#define SWITCH_FUNCTION_CURRENT_LIMIT (SD_INIT_BUFFER_ADDRESS + 0)
#define SWITCH_FUNCTION_GROUP_1 (SD_INIT_BUFFER_ADDRESS + 12)
#define SWITCH_FUNCTION_GROUP_1_HS (1 << 1)
#define TIMEOUT_INIT_MS (1000)
#define DAT_CRC16_LENGTH (8)
#define DAT_BLOCK_MAX_COUNT (256)
#define DAT_TIMEOUT_INIT_MS (2000)
#define DAT_TIMEOUT_DATA_MS (5000)
@ -62,9 +66,17 @@ typedef enum {
typedef enum {
DAT_OK,
DAT_ERR_IO,
DAT_ERR_TIMEOUT,
} dat_err_t;
DAT_ERROR_IO,
DAT_ERROR_TIMEOUT,
} dat_error_t;
typedef enum {
CMD6_OK,
CMD6_ERROR_ILLEGAL_CMD,
CMD6_ERROR_IO,
CMD6_ERROR_CRC,
CMD6_ERROR_TIMEOUT,
} cmd6_error_t;
struct process {
@ -150,7 +162,11 @@ static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
}
static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
if (sd_cmd(55, p.rca, RSP_R1, NULL)) {
uint32_t acmd_rsp;
if (sd_cmd(55, p.rca, RSP_R1, &acmd_rsp)) {
return true;
}
if (!(acmd_rsp & R1_APP_CMD)) {
return true;
}
if (sd_cmd(acmd, arg, rsp_type, rsp)) {
@ -185,7 +201,7 @@ static void sd_dat_abort (void) {
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
}
static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
static dat_error_t sd_dat_wait (uint16_t timeout_ms) {
timer_countdown_start(TIMER_ID_SD, timeout_ms);
do {
@ -194,7 +210,7 @@ static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
if (sd_dat & SD_DAT_ERROR) {
sd_dat_abort();
return DAT_ERR_IO;
return DAT_ERROR_IO;
}
return DAT_OK;
}
@ -202,19 +218,87 @@ static dat_err_t sd_dat_wait (uint16_t timeout_ms) {
sd_dat_abort();
return DAT_ERR_TIMEOUT;
return DAT_ERROR_TIMEOUT;
}
static bool sd_dat_check_crc16 (uint8_t *data, uint32_t length) {
uint16_t device_crc[4];
uint16_t controller_crc[4];
for (int crc = 0; crc < 4; crc++) {
device_crc[crc] = 0;
controller_crc[crc] = 0;
}
for (uint32_t index = length; index < (length + DAT_CRC16_LENGTH); index++) {
uint8_t byte = data[index];
for (int nibble = 0; nibble < 2; nibble++) {
for (int crc = 0; crc < 4; crc++) {
device_crc[crc] <<= 1;
device_crc[crc] |= (byte >> (7 - crc)) & (1 << 0);
}
byte <<= 4;
}
}
for (uint32_t index = 0; index < length; index++) {
uint8_t byte = data[index];
for (int nibble = 0; nibble < 2; nibble++) {
for (int crc = 0; crc < 4; crc++) {
uint8_t inv = ((controller_crc[crc] >> 15) ^ (byte >> (7 - crc))) & (1 << 0);
controller_crc[crc] ^= (inv << 11) | (inv << 4);
controller_crc[crc] <<= 1;
controller_crc[crc] |= inv;
}
byte <<= 4;
}
}
for (int crc = 0; crc < 4; crc++) {
if (controller_crc[crc] != device_crc[crc]) {
return true;
}
}
return false;
}
static cmd6_error_t sd_cmd6 (uint32_t arg, uint8_t *buffer) {
uint32_t rsp;
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, arg, RSP_R1, &rsp)) {
sd_dat_abort();
return CMD6_ERROR_IO;
}
if (rsp & R1_ILLEGAL_COMMAND) {
sd_dat_abort();
return CMD6_ERROR_ILLEGAL_CMD;
}
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERROR_TIMEOUT) {
return CMD6_ERROR_TIMEOUT;
}
fpga_mem_read(SD_INIT_BUFFER_ADDRESS, CMD6_DATA_LENGTH + DAT_CRC16_LENGTH, buffer);
if (sd_dat_check_crc16(buffer, CMD6_DATA_LENGTH)) {
return CMD6_ERROR_CRC;
}
return SD_OK;
}
bool sd_card_init (void) {
sd_error_t sd_card_init (void) {
uint32_t arg;
uint32_t rsp;
uint16_t tmp;
cmd6_error_t cmd6_error;
uint8_t cmd6_buffer[CMD6_DATA_LENGTH + DAT_CRC16_LENGTH];
p.byte_swap = false;
if (p.card_initialized) {
return false;
return SD_OK;
}
if (!sd_card_is_inserted()) {
return SD_ERROR_NO_CARD_IN_SLOT;
}
p.card_initialized = true;
@ -230,7 +314,7 @@ bool sd_card_init (void) {
} else {
if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD8_IO;
}
arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR);
}
@ -239,16 +323,16 @@ bool sd_card_init (void) {
do {
if (timer_countdown_elapsed(TIMER_ID_SD)) {
sd_card_deinit();
return true;
return SD_ERROR_ACMD41_TIMEOUT;
}
if (sd_acmd(41, arg, RSP_R3, &rsp)) {
sd_card_deinit();
return true;
return SD_ERROR_ACMD41_IO;
}
if (rsp & R3_BUSY) {
if ((rsp & R3_OCR) == 0) {
sd_card_deinit();
return true;
return SD_ERROR_ACMD41_OCR;
}
p.card_type_block = (rsp & R3_CCS);
break;
@ -257,71 +341,78 @@ bool sd_card_init (void) {
if (sd_cmd(2, 0, RSP_R2, NULL)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD2_IO;
}
if (sd_cmd(3, 0, RSP_R6, &rsp)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD3_IO;
}
p.rca = (rsp & R6_RCA_MASK);
if (sd_cmd(9, p.rca, RSP_R2, p.csd)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD9_IO;
}
if (sd_cmd(10, p.rca, RSP_R2, p.cid)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD10_IO;
}
if (sd_cmd(7, p.rca, RSP_R1b, NULL)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD7_IO;
}
sd_set_clock(CLOCK_25MHZ);
if (sd_acmd(6, ACMD6_ARG_BUS_WIDTH_4BIT, RSP_R1, NULL)) {
sd_card_deinit();
return true;
return SD_ERROR_ACMD6_IO;
}
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_CHECK_HS, RSP_R1, NULL)) {
sd_dat_abort();
sd_card_deinit();
return true;
if ((cmd6_error = sd_cmd6(CMD6_ARG_CHECK_HS, cmd6_buffer)) == CMD6_ERROR_ILLEGAL_CMD) {
return SD_OK;
}
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
if (cmd6_error != CMD6_OK) {
sd_card_deinit();
return true;
switch (cmd6_error) {
case CMD6_ERROR_IO: return SD_ERROR_CMD6_CHECK_IO;
case CMD6_ERROR_CRC: return SD_ERROR_CMD6_CHECK_CRC;
case CMD6_ERROR_TIMEOUT: return SD_ERROR_CMD6_CHECK_TIMEOUT;
default: return SD_ERROR_CMD6_CHECK_IO;
}
fpga_mem_read(SWITCH_FUNCTION_CURRENT_LIMIT, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) == 0) {
}
if (CMD6_INVALID_CURRENT_LIMIT(cmd6_buffer)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD6_CHECK_RESPONSE;
}
fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) {
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ);
if (sd_cmd(6, CMD6_ARG_SWITCH_HS, RSP_R1, NULL)) {
sd_dat_abort();
if (CMD6_HS_SUPPORTED(cmd6_buffer)) {
if ((cmd6_error = sd_cmd6(CMD6_ARG_SWITCH_HS, cmd6_buffer)) != CMD6_OK) {
sd_card_deinit();
return true;
switch (cmd6_error) {
case CMD6_ERROR_IO: return SD_ERROR_CMD6_SWITCH_IO;
case CMD6_ERROR_CRC: return SD_ERROR_CMD6_SWITCH_CRC;
case CMD6_ERROR_TIMEOUT: return SD_ERROR_CMD6_SWITCH_TIMEOUT;
default: return SD_ERROR_CMD6_SWITCH_IO;
}
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERR_TIMEOUT) {
}
if (CMD6_INVALID_CURRENT_LIMIT(cmd6_buffer)) {
sd_card_deinit();
return true;
return SD_ERROR_CMD6_SWITCH_RESPONSE;
}
fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp));
if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) {
if (CMD6_HS_ENABLED(cmd6_buffer)) {
sd_set_clock(CLOCK_50MHZ);
}
}
return false;
return SD_OK;
}
void sd_card_deinit (void) {
@ -354,29 +445,33 @@ uint32_t sd_card_get_status (void) {
);
}
bool sd_card_get_info (uint32_t address) {
sd_error_t sd_card_get_info (uint32_t address) {
if (!p.card_initialized) {
return true;
return SD_ERROR_NOT_INITIALIZED;
}
fpga_mem_write(address, sizeof(p.csd), p.csd);
address += sizeof(p.csd);
fpga_mem_write(address, sizeof(p.cid), p.cid);
address += sizeof(p.cid);
return false;
return SD_OK;
}
bool sd_set_byte_swap (bool enabled) {
sd_error_t sd_set_byte_swap (bool enabled) {
if (!p.card_initialized) {
return true;
return SD_ERROR_NOT_INITIALIZED;
}
p.byte_swap = enabled;
return false;
return SD_OK;
}
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) {
return true;
sd_error_t sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized) {
return SD_ERROR_NOT_INITIALIZED;
}
if (count == 0) {
return SD_ERROR_INVALID_ARGUMENT;
}
if (!p.card_type_block) {
@ -386,12 +481,13 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
while (count > 0) {
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
if (sd_cmd(25, sector, RSP_R1, NULL)) {
return true;
return SD_ERROR_CMD25_IO;
}
sd_dat_prepare(address, blocks, DAT_WRITE);
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
dat_error_t error = sd_dat_wait(DAT_TIMEOUT_DATA_MS);
if (error != DAT_OK) {
sd_cmd(12, 0, RSP_R1b, NULL);
return true;
return (error == DAT_ERROR_IO) ? SD_ERROR_CMD25_CRC : SD_ERROR_CMD25_TIMEOUT;
}
sd_cmd(12, 0, RSP_R1b, NULL);
address += (blocks * SD_SECTOR_SIZE);
@ -402,13 +498,17 @@ bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) {
return false;
}
bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized || (count == 0)) {
return true;
sd_error_t sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
if (!p.card_initialized) {
return SD_ERROR_NOT_INITIALIZED;
}
if (count == 0) {
return SD_ERROR_INVALID_ARGUMENT;
}
if (p.byte_swap && ((address % 2) != 0)) {
return true;
return SD_ERROR_INVALID_ARGUMENT;
}
if (!p.card_type_block) {
@ -420,11 +520,12 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
sd_dat_prepare(address, blocks, DAT_READ);
if (sd_cmd(18, sector, RSP_R1, NULL)) {
sd_dat_abort();
return true;
return SD_ERROR_CMD18_IO;
}
if (sd_dat_wait(DAT_TIMEOUT_DATA_MS) != DAT_OK) {
dat_error_t error = sd_dat_wait(DAT_TIMEOUT_DATA_MS);
if (error != DAT_OK) {
sd_cmd(12, 0, RSP_R1b, NULL);
return true;
return (error == DAT_ERROR_IO) ? SD_ERROR_CMD18_CRC : SD_ERROR_CMD18_TIMEOUT;
}
sd_cmd(12, 0, RSP_R1b, NULL);
address += (blocks * SD_SECTOR_SIZE);
@ -432,21 +533,21 @@ bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
count -= blocks;
}
return false;
return SD_OK;
}
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) {
sd_error_t sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors) {
uint32_t starting_sector = 0;
uint32_t sectors_to_process = 0;
if (count == 0) {
return true;
return SD_ERROR_INVALID_ARGUMENT;
}
for (uint32_t i = 0; i < count; i++) {
if (sector_table[i] == 0) {
return true;
return SD_ERROR_INVALID_ARGUMENT;
}
sectors_to_process += 1;
if ((i < (count - 1)) && ((sector_table[i] + 1) == sector_table[i + 1])) {
@ -454,14 +555,14 @@ bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t cou
}
bool error = sd_process_sectors(address, sector_table[starting_sector], sectors_to_process);
if (error) {
return true;
return error;
}
address += (sectors_to_process * SD_SECTOR_SIZE);
starting_sector += sectors_to_process;
sectors_to_process = 0;
}
return false;
return SD_OK;
}

View File

@ -10,20 +10,53 @@
#define SD_CARD_INFO_SIZE (32)
typedef bool sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t count);
typedef enum {
SD_OK = 0,
SD_ERROR_NO_CARD_IN_SLOT = 1,
SD_ERROR_NOT_INITIALIZED = 2,
SD_ERROR_INVALID_ARGUMENT = 3,
SD_ERROR_INVALID_ADDRESS = 4,
SD_ERROR_INVALID_OPERATION = 5,
SD_ERROR_CMD2_IO = 6,
SD_ERROR_CMD3_IO = 7,
SD_ERROR_CMD6_CHECK_IO = 8,
SD_ERROR_CMD6_CHECK_CRC = 9,
SD_ERROR_CMD6_CHECK_TIMEOUT = 10,
SD_ERROR_CMD6_CHECK_RESPONSE = 11,
SD_ERROR_CMD6_SWITCH_IO = 12,
SD_ERROR_CMD6_SWITCH_CRC = 13,
SD_ERROR_CMD6_SWITCH_TIMEOUT = 14,
SD_ERROR_CMD6_SWITCH_RESPONSE = 15,
SD_ERROR_CMD7_IO = 16,
SD_ERROR_CMD8_IO = 17,
SD_ERROR_CMD9_IO = 18,
SD_ERROR_CMD10_IO = 19,
SD_ERROR_CMD18_IO = 20,
SD_ERROR_CMD18_CRC = 21,
SD_ERROR_CMD18_TIMEOUT = 22,
SD_ERROR_CMD25_IO = 23,
SD_ERROR_CMD25_CRC = 24,
SD_ERROR_CMD25_TIMEOUT = 25,
SD_ERROR_ACMD6_IO = 26,
SD_ERROR_ACMD41_IO = 27,
SD_ERROR_ACMD41_OCR = 28,
SD_ERROR_ACMD41_TIMEOUT = 29,
} sd_error_t;
typedef sd_error_t sd_process_sectors_t (uint32_t address, uint32_t sector, uint32_t count);
bool sd_card_init (void);
sd_error_t sd_card_init (void);
void sd_card_deinit (void);
bool sd_card_is_inserted (void);
uint32_t sd_card_get_status (void);
bool sd_card_get_info (uint32_t address);
bool sd_set_byte_swap (bool enabled);
sd_error_t sd_card_get_info (uint32_t address);
sd_error_t sd_set_byte_swap (bool enabled);
bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count);
bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count);
sd_error_t sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count);
sd_error_t sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count);
bool sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors);
sd_error_t sd_optimize_sectors (uint32_t address, uint32_t *sector_table, uint32_t count, sd_process_sectors_t sd_process_sectors);
void sd_init (void);

View File

@ -82,9 +82,9 @@ static void writeback_save_to_sd (void) {
return;
}
bool error = sd_optimize_sectors(address, p.sectors, (length / SD_SECTOR_SIZE), sd_write_sectors);
sd_error_t error = sd_optimize_sectors(address, p.sectors, (length / SD_SECTOR_SIZE), sd_write_sectors);
if (error) {
if (error != SD_OK) {
writeback_disable();
return;
}