[SC64][SW] Fix SD deinit error when the card is not locked + SD module refactor

This commit is contained in:
Mateusz Faderewski 2024-11-16 13:47:13 +01:00
parent e2c100ae7f
commit 6eef811cd6
5 changed files with 123 additions and 83 deletions

View File

@ -178,7 +178,7 @@ static void test_sd_card_io (void) {
uint8_t sector[512] __attribute__((aligned(8))); uint8_t sector[512] __attribute__((aligned(8)));
if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) { if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) {
error_display("Could not get SD card info\n (%08X) - %s", error, sc64_error_description(error)); error_display("Could not get SD card status\n (%08X) - %s", error, sc64_error_description(error));
} }
if (card_status & SD_CARD_STATUS_INSERTED) { if (card_status & SD_CARD_STATUS_INSERTED) {
@ -188,11 +188,11 @@ static void test_sd_card_io (void) {
} }
if ((error = sc64_sd_card_deinit()) != SC64_OK) { if ((error = sc64_sd_card_deinit()) != SC64_OK) {
error_display("SD card deinit error\n (%08X) - %s", error, sc64_error_description(error)); return display_printf("SD card deinit error, skipping test\n (%08X) - %s", error, sc64_error_description(error));
} }
if ((error = sc64_sd_card_init()) != SC64_OK) { if ((error = sc64_sd_card_init()) != SC64_OK) {
return display_printf("SD card init error\n (%08X) - %s\n", error, sc64_error_description(error)); return display_printf("SD card init error, skipping test\n (%08X) - %s\n", error, sc64_error_description(error));
} }
if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) { if ((error = sc64_sd_card_get_status(&card_status)) != SC64_OK) {
@ -261,7 +261,7 @@ static void test_sd_card_fatfs (void) {
UINT bytes; UINT bytes;
if ((error = sc64_sd_card_deinit()) != SC64_OK) { if ((error = sc64_sd_card_deinit()) != SC64_OK) {
error_display("SD card deinit error\n (%08X) - %s", error, sc64_error_description(error)); return display_printf("SD card deinit error, skipping test\n (%08X) - %s", error, sc64_error_description(error));
} }
if ((fresult = f_mount(&fs, "", 1)) != FR_OK) { if ((fresult = f_mount(&fs, "", 1)) != FR_OK) {

View File

@ -92,15 +92,6 @@ typedef enum {
TV_TYPE_PASSTHROUGH = 3 TV_TYPE_PASSTHROUGH = 3
} tv_type_t; } tv_type_t;
typedef enum {
SD_CARD_OP_DEINIT = 0,
SD_CARD_OP_INIT = 1,
SD_CARD_OP_GET_STATUS = 2,
SD_CARD_OP_GET_INFO = 3,
SD_CARD_OP_BYTE_SWAP_ON = 4,
SD_CARD_OP_BYTE_SWAP_OFF = 5,
} sd_card_op_t;
typedef enum { typedef enum {
DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE = 0, DIAGNOSTIC_ID_VOLTAGE_TEMPERATURE = 0,
} diagnostic_id_t; } diagnostic_id_t;
@ -641,15 +632,15 @@ void cfg_process (void) {
case CMD_ID_SD_CARD_OP: { case CMD_ID_SD_CARD_OP: {
sd_error_t error = SD_OK; sd_error_t error = SD_OK;
switch (p.data[1]) { switch (p.data[1]) {
case SD_CARD_OP_DEINIT: case SD_OP_DEINIT:
error = sd_get_lock(SD_LOCK_N64); error = sd_try_lock(SD_LOCK_N64);
if (error == SD_OK) { if (error == SD_OK) {
sd_card_deinit(); sd_card_deinit();
sd_release_lock(SD_LOCK_N64); sd_release_lock(SD_LOCK_N64);
} }
break; break;
case SD_CARD_OP_INIT: case SD_OP_INIT:
error = sd_try_lock(SD_LOCK_N64); error = sd_try_lock(SD_LOCK_N64);
if (error == SD_OK) { if (error == SD_OK) {
led_activity_on(); led_activity_on();
@ -661,11 +652,11 @@ void cfg_process (void) {
} }
break; break;
case SD_CARD_OP_GET_STATUS: case SD_OP_GET_STATUS:
p.data[1] = sd_card_get_status(); p.data[1] = sd_card_get_status();
break; break;
case SD_CARD_OP_GET_INFO: case SD_OP_GET_INFO:
if (cfg_translate_address(&p.data[0], SD_CARD_INFO_SIZE, (SDRAM | BRAM))) { if (cfg_translate_address(&p.data[0], SD_CARD_INFO_SIZE, (SDRAM | BRAM))) {
return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS); return cfg_cmd_reply_error(ERROR_TYPE_SD_CARD, SD_ERROR_INVALID_ADDRESS);
} }
@ -675,14 +666,14 @@ void cfg_process (void) {
} }
break; break;
case SD_CARD_OP_BYTE_SWAP_ON: case SD_OP_BYTE_SWAP_ON:
error = sd_get_lock(SD_LOCK_N64); error = sd_get_lock(SD_LOCK_N64);
if (error == SD_OK) { if (error == SD_OK) {
error = sd_set_byte_swap(true); error = sd_set_byte_swap(true);
} }
break; break;
case SD_CARD_OP_BYTE_SWAP_OFF: case SD_OP_BYTE_SWAP_OFF:
error = sd_get_lock(SD_LOCK_N64); error = sd_get_lock(SD_LOCK_N64);
if (error == SD_OK) { if (error == SD_OK) {
error = sd_set_byte_swap(false); error = sd_set_byte_swap(false);

View File

@ -4,7 +4,7 @@
#include "timer.h" #include "timer.h"
#define SD_INIT_BUFFER_ADDRESS (0x05002BB8UL) #define SD_INIT_BUFFER_ADDRESS (0x05002A00UL)
#define BYTE_SWAP_ADDRESS_END (0x05000000UL) #define BYTE_SWAP_ADDRESS_END (0x05000000UL)
#define CMD6_ARG_CHECK_HS (0x00FFFFF1UL) #define CMD6_ARG_CHECK_HS (0x00FFFFF1UL)
@ -35,11 +35,10 @@
#define R7_CHECK_PATTERN (0xAA << 0) #define R7_CHECK_PATTERN (0xAA << 0)
#define TIMEOUT_INIT_MS (1000) #define TIMEOUT_INIT_MS (1000)
#define TIMEOUT_DATA_MS (5000)
#define DAT_CRC16_LENGTH (8) #define DAT_CRC16_LENGTH (8)
#define DAT_BLOCK_MAX_COUNT (256) #define DAT_BLOCK_MAX_COUNT (256)
#define DAT_TIMEOUT_INIT_MS (2000)
#define DAT_TIMEOUT_DATA_MS (5000)
typedef enum { typedef enum {
@ -59,16 +58,12 @@ typedef enum {
RSP_R7, RSP_R7,
} rsp_type_t; } rsp_type_t;
typedef enum {
DAT_READ,
DAT_WRITE,
} dat_mode_t;
typedef enum { typedef enum {
DAT_OK, DAT_OK,
DAT_BUSY,
DAT_ERROR_IO, DAT_ERROR_IO,
DAT_ERROR_TIMEOUT, DAT_ERROR_TIMEOUT,
} dat_error_t; } dat_status_t;
typedef enum { typedef enum {
CMD6_OK, CMD6_OK,
@ -176,51 +171,98 @@ static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp)
return false; return false;
} }
static void sd_dat_prepare (uint32_t address, uint32_t count, dat_mode_t mode) { static void sd_dat_start_write (uint32_t count) {
uint32_t length = (count * SD_SECTOR_SIZE); uint32_t dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_START_WRITE | SD_DAT_FIFO_FLUSH);
uint32_t sd_dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_FIFO_FLUSH); fpga_reg_set(REG_SD_DAT, dat);
uint32_t sd_dma_scr = DMA_SCR_START;
if (mode == DAT_READ) {
sd_dat |= SD_DAT_START_READ;
sd_dma_scr |= DMA_SCR_DIRECTION;
if (p.byte_swap && (address < BYTE_SWAP_ADDRESS_END)) {
sd_dma_scr |= DMA_SCR_BYTE_SWAP;
}
} else {
sd_dat |= SD_DAT_START_WRITE;
} }
fpga_reg_set(REG_SD_DAT, sd_dat); static void sd_dat_start_read (uint32_t count) {
fpga_reg_set(REG_SD_DMA_ADDRESS, address); uint32_t dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_START_READ | SD_DAT_FIFO_FLUSH);
fpga_reg_set(REG_SD_DMA_LENGTH, length); fpga_reg_set(REG_SD_DAT, dat);
fpga_reg_set(REG_SD_DMA_SCR, sd_dma_scr);
} }
static void sd_dat_abort (void) { static dat_status_t sd_dat_status (void) {
fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP); uint32_t dat = fpga_reg_get(REG_SD_DAT);
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); if (dat & SD_DAT_BUSY) {
return DAT_BUSY;
} }
if (dat & SD_DAT_ERROR) {
static dat_error_t sd_dat_wait (uint16_t timeout_ms) {
timer_countdown_start(TIMER_ID_SD, timeout_ms);
do {
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR);
if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) {
if (sd_dat & SD_DAT_ERROR) {
sd_dat_abort();
return DAT_ERROR_IO; return DAT_ERROR_IO;
} }
return DAT_OK; return DAT_OK;
} }
} while (!timer_countdown_elapsed(TIMER_ID_SD));
static void sd_dat_abort (void) {
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
}
static void sd_dma_start_write (uint32_t address, uint32_t count) {
uint32_t length = (count * SD_SECTOR_SIZE);
uint32_t scr = DMA_SCR_START;
fpga_reg_set(REG_SD_DMA_ADDRESS, address);
fpga_reg_set(REG_SD_DMA_LENGTH, length);
fpga_reg_set(REG_SD_DMA_SCR, scr);
}
static void sd_dma_start_read (uint32_t address, uint32_t count) {
uint32_t length = (count * SD_SECTOR_SIZE);
uint32_t scr = (DMA_SCR_DIRECTION | DMA_SCR_START);
if (p.byte_swap && (address < BYTE_SWAP_ADDRESS_END)) {
scr |= DMA_SCR_BYTE_SWAP;
}
fpga_reg_set(REG_SD_DMA_ADDRESS, address);
fpga_reg_set(REG_SD_DMA_LENGTH, length);
fpga_reg_set(REG_SD_DMA_SCR, scr);
}
static void sd_dma_wait_busy (void) {
while (fpga_reg_get(REG_SD_DMA_SCR) & DMA_SCR_BUSY);
}
static void sd_dma_abort (void) {
fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP);
sd_dma_wait_busy();
}
static void sd_start_write (uint32_t address, uint32_t count) {
sd_dat_start_write(count);
sd_dma_start_write(address, count);
}
static void sd_start_read (uint32_t address, uint32_t count) {
sd_dat_start_read(count);
sd_dma_start_read(address, count);
}
static void sd_abort (void) {
sd_dma_abort();
sd_dat_abort(); sd_dat_abort();
}
static dat_status_t sd_sync (uint16_t timeout_ms) {
timer_countdown_start(TIMER_ID_SD, timeout_ms);
while (true) {
dat_status_t status = sd_dat_status();
if (status != DAT_BUSY) {
if (status != DAT_OK) {
sd_abort();
}
return status;
}
if (timer_countdown_elapsed(TIMER_ID_SD)) {
sd_abort();
return DAT_ERROR_TIMEOUT; return DAT_ERROR_TIMEOUT;
} }
}
}
static bool sd_dat_check_crc16 (uint8_t *data, uint32_t length) { static bool sd_dat_check_crc16 (uint8_t *data, uint32_t length) {
uint16_t device_crc[4]; uint16_t device_crc[4];
@ -266,15 +308,15 @@ static bool sd_dat_check_crc16 (uint8_t *data, uint32_t length) {
static cmd6_error_t sd_cmd6 (uint32_t arg, uint8_t *buffer) { static cmd6_error_t sd_cmd6 (uint32_t arg, uint8_t *buffer) {
uint32_t rsp; uint32_t rsp;
sd_dat_prepare(SD_INIT_BUFFER_ADDRESS, 1, DAT_READ); sd_start_read(SD_INIT_BUFFER_ADDRESS, 1);
if (sd_cmd(6, arg, RSP_R1, NULL)) { if (sd_cmd(6, arg, RSP_R1, NULL)) {
sd_dat_abort(); sd_abort();
if ((!sd_cmd(13, p.rca, RSP_R1, &rsp)) && (rsp & R1_ILLEGAL_COMMAND)) { if ((!sd_cmd(13, p.rca, RSP_R1, &rsp)) && (rsp & R1_ILLEGAL_COMMAND)) {
return CMD6_ERROR_ILLEGAL_CMD; return CMD6_ERROR_ILLEGAL_CMD;
} }
return CMD6_ERROR_IO; return CMD6_ERROR_IO;
} }
if (sd_dat_wait(DAT_TIMEOUT_INIT_MS) == DAT_ERROR_TIMEOUT) { if (sd_sync(TIMEOUT_DATA_MS) == DAT_ERROR_TIMEOUT) {
return CMD6_ERROR_TIMEOUT; return CMD6_ERROR_TIMEOUT;
} }
fpga_mem_read(SD_INIT_BUFFER_ADDRESS, CMD6_DATA_LENGTH + DAT_CRC16_LENGTH, buffer); fpga_mem_read(SD_INIT_BUFFER_ADDRESS, CMD6_DATA_LENGTH + DAT_CRC16_LENGTH, buffer);
@ -495,13 +537,12 @@ sd_error_t sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count)
if (sd_cmd(25, sector, RSP_R1, NULL)) { if (sd_cmd(25, sector, RSP_R1, NULL)) {
return SD_ERROR_CMD25_IO; return SD_ERROR_CMD25_IO;
} }
sd_dat_prepare(address, blocks, DAT_WRITE); sd_start_write(address, blocks);
dat_error_t error = sd_dat_wait(DAT_TIMEOUT_DATA_MS); dat_status_t status = sd_sync(TIMEOUT_DATA_MS);
if (error != DAT_OK) {
sd_cmd(12, 0, RSP_R1b, NULL); sd_cmd(12, 0, RSP_R1b, NULL);
return (error == DAT_ERROR_IO) ? SD_ERROR_CMD25_CRC : SD_ERROR_CMD25_TIMEOUT; if (status != DAT_OK) {
return (status == DAT_ERROR_IO) ? SD_ERROR_CMD25_CRC : SD_ERROR_CMD25_TIMEOUT;
} }
sd_cmd(12, 0, RSP_R1b, NULL);
address += (blocks * SD_SECTOR_SIZE); address += (blocks * SD_SECTOR_SIZE);
sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE)); sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE));
count -= blocks; count -= blocks;
@ -529,17 +570,16 @@ sd_error_t sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) {
while (count > 0) { while (count > 0) {
uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count);
sd_dat_prepare(address, blocks, DAT_READ); sd_start_read(address, blocks);
if (sd_cmd(18, sector, RSP_R1, NULL)) { if (sd_cmd(18, sector, RSP_R1, NULL)) {
sd_dat_abort(); sd_abort();
return SD_ERROR_CMD18_IO; return SD_ERROR_CMD18_IO;
} }
dat_error_t error = sd_dat_wait(DAT_TIMEOUT_DATA_MS); dat_status_t status = sd_sync(TIMEOUT_DATA_MS);
if (error != DAT_OK) {
sd_cmd(12, 0, RSP_R1b, NULL); sd_cmd(12, 0, RSP_R1b, NULL);
return (error == DAT_ERROR_IO) ? SD_ERROR_CMD18_CRC : SD_ERROR_CMD18_TIMEOUT; if (status != DAT_OK) {
return (status == DAT_ERROR_IO) ? SD_ERROR_CMD18_CRC : SD_ERROR_CMD18_TIMEOUT;
} }
sd_cmd(12, 0, RSP_R1b, NULL);
address += (blocks * SD_SECTOR_SIZE); address += (blocks * SD_SECTOR_SIZE);
sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE)); sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE));
count -= blocks; count -= blocks;

View File

@ -52,6 +52,15 @@ typedef enum {
SD_LOCK_USB, SD_LOCK_USB,
} sd_lock_t; } sd_lock_t;
typedef enum {
SD_OP_DEINIT = 0,
SD_OP_INIT = 1,
SD_OP_GET_STATUS = 2,
SD_OP_GET_INFO = 3,
SD_OP_BYTE_SWAP_ON = 4,
SD_OP_BYTE_SWAP_OFF = 5,
} sd_op_t;
sd_error_t sd_card_init (void); sd_error_t sd_card_init (void);
void sd_card_deinit (void); void sd_card_deinit (void);

View File

@ -390,15 +390,15 @@ static void usb_rx_process (void) {
case 'i': { case 'i': {
sd_error_t error = SD_OK; sd_error_t error = SD_OK;
switch (p.rx_args[1]) { switch (p.rx_args[1]) {
case 0: case SD_OP_DEINIT:
error = sd_get_lock(SD_LOCK_USB); error = sd_try_lock(SD_LOCK_USB);
if (error == SD_OK) { if (error == SD_OK) {
sd_card_deinit(); sd_card_deinit();
sd_release_lock(SD_LOCK_USB); sd_release_lock(SD_LOCK_USB);
} }
break; break;
case 1: case SD_OP_INIT:
error = sd_try_lock(SD_LOCK_USB); error = sd_try_lock(SD_LOCK_USB);
if (error == SD_OK) { if (error == SD_OK) {
led_activity_on(); led_activity_on();
@ -410,10 +410,10 @@ static void usb_rx_process (void) {
} }
break; break;
case 2: case SD_OP_GET_STATUS:
break; break;
case 3: case SD_OP_GET_INFO:
if (usb_validate_address_length(p.rx_args[0], SD_CARD_INFO_SIZE, true)) { if (usb_validate_address_length(p.rx_args[0], SD_CARD_INFO_SIZE, true)) {
error = SD_ERROR_INVALID_ADDRESS; error = SD_ERROR_INVALID_ADDRESS;
} else { } else {
@ -424,14 +424,14 @@ static void usb_rx_process (void) {
} }
break; break;
case 4: case SD_OP_BYTE_SWAP_ON:
error = sd_get_lock(SD_LOCK_USB); error = sd_get_lock(SD_LOCK_USB);
if (error == SD_OK) { if (error == SD_OK) {
error = sd_set_byte_swap(true); error = sd_set_byte_swap(true);
} }
break; break;
case 5: case SD_OP_BYTE_SWAP_OFF:
error = sd_get_lock(SD_LOCK_USB); error = sd_get_lock(SD_LOCK_USB);
if (error == SD_OK) { if (error == SD_OK) {
error = sd_set_byte_swap(false); error = sd_set_byte_swap(false);