From 98fa69e4d71977daf2ca423bad60acde1c58c361 Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Tue, 21 Feb 2023 01:02:40 +0100 Subject: [PATCH] [SC64][SW] (#30) Remove usage of CMD23 in SD card sector read/write --- sw/bootloader/src/test.c | 243 +++++----- sw/controller/src/sd.c | 951 +++++++++++++++++++-------------------- sw/pc/sc64.py | 19 +- 3 files changed, 609 insertions(+), 604 deletions(-) diff --git a/sw/bootloader/src/test.c b/sw/bootloader/src/test.c index c6d506d..392c860 100644 --- a/sw/bootloader/src/test.c +++ b/sw/bootloader/src/test.c @@ -1,121 +1,122 @@ -#include -#include "display.h" -#include "io.h" -#include "sc64.h" -#include "test.h" - - -static void test_rtc (void) { - sc64_rtc_time_t t; - const char *weekdays[8] = { - "", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", - "Sunday", - }; - - sc64_get_time(&t); - - display_printf("RTC current time:\n "); - display_printf("%04d-%02d-%02d", 2000 + FROM_BCD(t.year), FROM_BCD(t.month), FROM_BCD(t.day)); - display_printf("T"); - display_printf("%02d:%02d:%02d", FROM_BCD(t.hour), FROM_BCD(t.minute), FROM_BCD(t.second)); - display_printf(" (%s)", weekdays[FROM_BCD(t.weekday)]); - display_printf("\n"); -} - -static void test_sd_card (void) { - 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 (card_status & SD_CARD_STATUS_INSERTED) { - display_printf("SD card is inserted\n"); - } else { - display_printf("SD card is not inserted\n"); - } - - if (sc64_sd_card_init()) { - display_printf("SD card init error!\n"); - return; - } - - card_status = sc64_sd_card_get_status(); - - if (card_status & SD_CARD_STATUS_INITIALIZED) { - display_printf("SD card is initialized\n"); - } - if (card_status & SD_CARD_STATUS_TYPE_BLOCK) { - display_printf("SD card type is block\n"); - } - if (card_status & SD_CARD_STATUS_50MHZ_MODE) { - display_printf("SD card runs at 50 MHz clock speed\n"); - } - - if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) { - display_printf("SD card get info error!\n"); - return; - } - - pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), card_info, sizeof(card_info)); - - display_printf("SD Card registers:\n CSD: 0x"); - for (int i = 0; i < 16; i++) { - display_printf("%02X ", card_info[i]); - } - display_printf("\n CID: 0x"); - for (int i = 16; i < 32; i++) { - display_printf("%02X ", card_info[i]); - } - display_printf("\n "); - for (int i = 16; i < 32; i++) { - display_printf(" %c ", card_info[i] >= ' ' ? card_info[i] : 0xFF); - } - display_printf("\n"); - - if (sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) { - display_printf("SD card read sector 0 error!\n"); - } - - pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), sector, sizeof(sector)); - - display_printf("Sector 0 (0x1BE-0x1DD), partition entry 1/2:\n 0x"); - for (int i = 0; i < 16; i++) { - display_printf("%02X ", sector[0x1BE + i]); - } - display_printf("\n 0x"); - for (int i = 0; i < 16; i++) { - display_printf("%02X ", sector[0x1CE + i]); - } - display_printf("\n"); - display_printf(" Boot signature: 0x%02X%02X", sector[510], sector[511]); -} - - -bool test_check (void) { - if (OS_INFO->reset_type != OS_INFO_RESET_TYPE_COLD) { - return false; - } - return sc64_get_config(CFG_ID_BUTTON_STATE); -} - -void test_execute (void) { - display_init(NULL); - display_printf("SC64 Test suite\n\n"); - - display_printf("[ RTC tests ]\n"); - test_rtc(); - display_printf("\n"); - - display_printf("[ SD card tests ]\n"); - test_sd_card(); - display_printf("\n"); - - while (1); -} +#include +#include "display.h" +#include "io.h" +#include "sc64.h" +#include "test.h" + + +static void test_rtc (void) { + sc64_rtc_time_t t; + const char *weekdays[8] = { + "", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday", + }; + + sc64_get_time(&t); + + display_printf("RTC current time:\n "); + display_printf("%04d-%02d-%02d", 2000 + FROM_BCD(t.year), FROM_BCD(t.month), FROM_BCD(t.day)); + display_printf("T"); + display_printf("%02d:%02d:%02d", FROM_BCD(t.hour), FROM_BCD(t.minute), FROM_BCD(t.second)); + display_printf(" (%s)", weekdays[FROM_BCD(t.weekday)]); + display_printf("\n"); +} + +static void test_sd_card (void) { + 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 (card_status & SD_CARD_STATUS_INSERTED) { + display_printf("SD card is inserted\n"); + } else { + display_printf("SD card is not inserted\n"); + } + + if (sc64_sd_card_init()) { + display_printf("SD card init error!\n"); + return; + } + + card_status = sc64_sd_card_get_status(); + + if (card_status & SD_CARD_STATUS_INITIALIZED) { + display_printf("SD card is initialized\n"); + } + if (card_status & SD_CARD_STATUS_TYPE_BLOCK) { + display_printf("SD card type is block\n"); + } + if (card_status & SD_CARD_STATUS_50MHZ_MODE) { + display_printf("SD card runs at 50 MHz clock speed\n"); + } + + if (sc64_sd_card_get_info((uint32_t *) (SC64_BUFFERS->BUFFER))) { + display_printf("SD card get info error!\n"); + return; + } + + pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), card_info, sizeof(card_info)); + + display_printf("SD Card registers:\n CSD: 0x"); + for (int i = 0; i < 16; i++) { + display_printf("%02X ", card_info[i]); + } + display_printf("\n CID: 0x"); + for (int i = 16; i < 32; i++) { + display_printf("%02X ", card_info[i]); + } + display_printf("\n "); + for (int i = 16; i < 32; i++) { + display_printf(" %c ", card_info[i] >= ' ' ? card_info[i] : 0xFF); + } + display_printf("\n"); + + if (sc64_sd_read_sectors((void *) (SC64_BUFFERS->BUFFER), 0, 1)) { + display_printf("SD card read sector 0 error!\n"); + return; + } + + pi_dma_read((io32_t *) (SC64_BUFFERS->BUFFER), sector, sizeof(sector)); + + display_printf("Sector 0 (0x1BE-0x1DD), partition entry 1/2:\n 0x"); + for (int i = 0; i < 16; i++) { + display_printf("%02X ", sector[0x1BE + i]); + } + display_printf("\n 0x"); + for (int i = 0; i < 16; i++) { + display_printf("%02X ", sector[0x1CE + i]); + } + display_printf("\n"); + display_printf(" Boot signature: 0x%02X%02X\n", sector[510], sector[511]); +} + + +bool test_check (void) { + if (OS_INFO->reset_type != OS_INFO_RESET_TYPE_COLD) { + return false; + } + return sc64_get_config(CFG_ID_BUTTON_STATE); +} + +void test_execute (void) { + display_init(NULL); + display_printf("SC64 Test suite\n\n"); + + display_printf("[ RTC tests ]\n"); + test_rtc(); + display_printf("\n"); + + display_printf("[ SD card tests ]\n"); + test_sd_card(); + display_printf("\n"); + + while (1); +} diff --git a/sw/controller/src/sd.c b/sw/controller/src/sd.c index 87682ac..f25df99 100644 --- a/sw/controller/src/sd.c +++ b/sw/controller/src/sd.c @@ -1,478 +1,473 @@ -#include -#include -#include "fpga.h" -#include "hw.h" -#include "led.h" -#include "sd.h" - - -#define SD_INIT_BUFFER_ADDRESS (0x05002800UL) - -#define CMD6_ARG_CHECK_HS (0x00FFFFF1UL) -#define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL) - -#define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8) -#define CMD8_ARG_CHECK_PATTERN (0xAA << 0) - -#define ACMD6_ARG_BUS_WIDTH_4BIT (2 << 0) - -#define ACMD41_ARG_OCR (0x300000 << 0) -#define ACMD41_ARG_HCS (1 << 30) - -#define R3_OCR (0x300000 << 0) -#define R3_CCS (1 << 30) -#define R3_BUSY (1 << 31) - -#define R6_RCA_MASK (0xFFFF0000UL) - -#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 DAT_BLOCK_MAX_COUNT (256) -#define DAT_TIMEOUT_MS (1000) - - -typedef enum { - CLOCK_STOP, - CLOCK_400KHZ, - CLOCK_25MHZ, - CLOCK_50MHZ, -} sd_clock_t; - -typedef enum { - RSP_NONE, - RSP_R1, - RSP_R1b, - RSP_R2, - RSP_R3, - RSP_R6, - RSP_R7, -} rsp_type_t; - -typedef enum { - DAT_READ, - DAT_WRITE, -} dat_mode_t; - - -struct process { - bool card_initialized; - bool card_type_block; - uint32_t rca; - uint8_t csd[16]; - uint8_t cid[16]; - volatile bool timeout; -}; - - -static struct process p; - - -static void sd_trigger_timeout (void) { - p.timeout = true; -} - -static void sd_prepare_timeout (uint16_t value) { - p.timeout = false; - hw_tim_setup(TIM_ID_SD, value, sd_trigger_timeout); -} - -static bool sd_did_timeout (void) { - return p.timeout; -} - -static void sd_clear_timeout (void) { - hw_tim_stop(TIM_ID_SD); - p.timeout = false; -} - -static void sd_set_clock (sd_clock_t mode) { - fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF); - - switch (mode) { - case CLOCK_400KHZ: - fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_400KHZ); - break; - case CLOCK_25MHZ: - fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_25MHZ); - break; - case CLOCK_50MHZ: - fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_50MHZ); - break; - default: - break; - } -} - -static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) { - uint32_t scr; - uint32_t cmd_data; - - cmd_data = ((cmd << SD_CMD_INDEX_BIT) & SD_CMD_INDEX_MASK); - switch (rsp_type) { - case RSP_NONE: - cmd_data |= SD_CMD_SKIP_RESPONSE; - break; - case RSP_R2: - cmd_data |= (SD_CMD_LONG_RESPONSE | SD_CMD_RESERVED_RESPONSE); - break; - case RSP_R3: - cmd_data |= (SD_CMD_IGNORE_CRC | SD_CMD_RESERVED_RESPONSE); - break; - default: - break; - } - - fpga_reg_set(REG_SD_ARG, arg); - fpga_reg_set(REG_SD_CMD, cmd_data); - - do { - scr = fpga_reg_get(REG_SD_SCR); - } while (scr & SD_SCR_CMD_BUSY); - - if (rsp != NULL) { - if (cmd_data & SD_CMD_LONG_RESPONSE) { - uint8_t *rsp_8 = (uint8_t *) (rsp); - for (int i = 0; i < 4; i++) { - uint32_t rsp_data = fpga_reg_get(REG_SD_RSP_3 - i); - uint8_t *rsp_data_8 = (uint8_t *) (&rsp_data); - rsp_data = SWAP32(rsp_data); - for (int i = 0; i < 4; i++) { - *rsp_8++ = *rsp_data_8++; - } - } - } else { - (*(uint32_t *) (rsp)) = fpga_reg_get(REG_SD_RSP_0); - } - } - - if (rsp_type == RSP_R1b) { - do { - scr = fpga_reg_get(REG_SD_SCR); - } while (scr & SD_SCR_CARD_BUSY); - } - - return (scr & SD_SCR_CMD_ERROR); -} - -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)) { - return true; - } - if (sd_cmd(acmd, arg, rsp_type, rsp)) { - return true; - } - return false; -} - -static void sd_dat_prepare (uint32_t address, uint32_t count, dat_mode_t mode) { - uint32_t length = (count * SD_SECTOR_SIZE); - uint32_t sd_dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_FIFO_FLUSH); - uint32_t sd_dma_scr = DMA_SCR_START; - - if (mode == DAT_READ) { - sd_dat |= SD_DAT_START_READ; - sd_dma_scr |= DMA_SCR_DIRECTION; - } else { - sd_dat |= SD_DAT_START_WRITE; - } - - fpga_reg_set(REG_SD_DAT, sd_dat); - fpga_reg_set(REG_SD_DMA_ADDRESS, address); - fpga_reg_set(REG_SD_DMA_LENGTH, length); - fpga_reg_set(REG_SD_DMA_SCR, sd_dma_scr); -} - -static void sd_dat_abort (void) { - fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP); - fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); -} - -static bool sd_dat_wait (uint16_t timeout) { - sd_prepare_timeout(timeout); - - do { - uint32_t sd_dat = fpga_reg_get(REG_SD_DAT); - uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR); - led_blink_act(); - if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) { - sd_clear_timeout(); - return (sd_dat & SD_DAT_ERROR); - } - } while (!sd_did_timeout()); - - sd_dat_abort(); - - return true; -} - - -bool sd_card_init (void) { - uint32_t arg; - uint32_t rsp; - uint16_t tmp; - - if (p.card_initialized) { - return false; - } - - p.card_initialized = true; - p.rca = 0; - - led_blink_act(); - - sd_set_clock(CLOCK_400KHZ); - - sd_cmd(0, 0, RSP_NONE, NULL); - - arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN); - if (sd_cmd(8, arg, RSP_R7, &rsp)) { - arg = ACMD41_ARG_OCR; - } else { - if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) { - sd_card_deinit(); - return true; - } - arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR); - } - - sd_prepare_timeout(1000); - do { - if (sd_did_timeout()) { - sd_card_deinit(); - return true; - } - if (sd_acmd(41, arg, RSP_R3, &rsp)) { - sd_card_deinit(); - return true; - } - if (rsp & R3_BUSY) { - if ((rsp & R3_OCR) == 0) { - sd_card_deinit(); - return true; - } - p.card_type_block = (rsp & R3_CCS); - break; - } - } while (1); - sd_clear_timeout(); - - if (sd_cmd(2, 0, RSP_R2, NULL)) { - sd_card_deinit(); - return true; - } - - if (sd_cmd(3, 0, RSP_R6, &rsp)) { - sd_card_deinit(); - return true; - } - p.rca = (rsp & R6_RCA_MASK); - - if (sd_cmd(9, p.rca, RSP_R2, p.csd)) { - sd_card_deinit(); - return true; - } - - if (sd_cmd(10, p.rca, RSP_R2, p.cid)) { - sd_card_deinit(); - return true; - } - - if (sd_cmd(7, p.rca, RSP_R1b, NULL)) { - sd_card_deinit(); - return true; - } - - sd_set_clock(CLOCK_25MHZ); - - if (sd_acmd(6, ACMD6_ARG_BUS_WIDTH_4BIT, RSP_R1, NULL)) { - sd_card_deinit(); - return true; - } - - 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; - } - sd_dat_wait(DAT_TIMEOUT_MS); - if (sd_did_timeout()) { - sd_card_deinit(); - return true; - } - fpga_mem_read(SWITCH_FUNCTION_CURRENT_LIMIT, 2, (uint8_t *) (&tmp)); - if (SWAP16(tmp) == 0) { - sd_card_deinit(); - return true; - } - 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(); - sd_card_deinit(); - return true; - } - sd_dat_wait(DAT_TIMEOUT_MS); - if (sd_did_timeout()) { - sd_card_deinit(); - return true; - } - fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp)); - if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) { - sd_set_clock(CLOCK_50MHZ); - } - } - - return false; -} - -void sd_card_deinit (void) { - if (p.card_initialized) { - p.card_initialized = false; - sd_set_clock(CLOCK_400KHZ); - sd_cmd(0, 0, RSP_NONE, NULL); - sd_set_clock(CLOCK_STOP); - } -} - -bool sd_card_is_inserted (void) { - return (fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED); -} - -uint32_t sd_card_get_status (void) { - uint32_t scr = fpga_reg_get(REG_SD_SCR); - uint32_t clock_mode_50mhz = ((scr & SD_SCR_CLOCK_MODE_MASK) == SD_SCR_CLOCK_MODE_50MHZ) ? 1 : 0; - uint32_t card_type_block = p.card_type_block ? 1 : 0; - uint32_t card_initialized = p.card_initialized ? 1 : 0; - uint32_t card_inserted = (scr & SD_SCR_CARD_INSERTED) ? 1 : 0; - return ( - (clock_mode_50mhz << 3) | - (card_type_block << 2) | - (card_initialized << 1) | - (card_inserted << 0) - ); -} - -bool sd_card_get_info (uint32_t address) { - if (!p.card_initialized) { - return true; - } - 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; -} - -bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { - if (!p.card_initialized || (count == 0)) { - return true; - } - - if (!p.card_type_block) { - sector *= SD_SECTOR_SIZE; - } - - while (count > 0) { - uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); - led_blink_act(); - if (sd_cmd(23, blocks, RSP_R1, NULL)) { - return true; - } - if (sd_cmd(25, sector, RSP_R1, NULL)) { - return true; - } - sd_dat_prepare(address, blocks, DAT_WRITE); - if (sd_dat_wait(DAT_TIMEOUT_MS)) { - sd_dat_abort(); - sd_cmd(12, 0, RSP_R1b, NULL); - return true; - } - sd_cmd(12, 0, RSP_R1b, NULL); - address += (blocks * SD_SECTOR_SIZE); - sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE)); - count -= blocks; - } - - return false; -} - -bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { - if (!p.card_initialized || (count == 0)) { - return true; - } - - if (!p.card_type_block) { - sector *= SD_SECTOR_SIZE; - } - - while (count > 0) { - uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); - led_blink_act(); - sd_dat_prepare(address, blocks, DAT_READ); - if (sd_cmd(23, blocks, RSP_R1, NULL)) { - sd_dat_abort(); - return true; - } - if (sd_cmd(18, sector, RSP_R1, NULL)) { - sd_dat_abort(); - return true; - } - if (sd_dat_wait(DAT_TIMEOUT_MS)) { - if (sd_did_timeout()) { - sd_cmd(12, 0, RSP_R1b, NULL); - } - return true; - } - address += (blocks * SD_SECTOR_SIZE); - sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE)); - count -= blocks; - } - - return false; -} - -bool 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; - } - - for (uint32_t i = 0; i < count; i++) { - if (sector_table[i] == 0) { - return true; - } - sectors_to_process += 1; - if ((i < (count - 1)) && ((sector_table[i] + 1) == sector_table[i + 1])) { - continue; - } - bool error = sd_process_sectors(address, sector_table[starting_sector], sectors_to_process); - if (error) { - return true; - } - address += (sectors_to_process * SD_SECTOR_SIZE); - starting_sector += sectors_to_process; - sectors_to_process = 0; - } - - return false; -} - -void sd_init (void) { - p.card_initialized = false; - sd_set_clock(CLOCK_STOP); -} - -void sd_process (void) { - if (!sd_card_is_inserted()) { - sd_card_deinit(); - } -} +#include +#include +#include "fpga.h" +#include "hw.h" +#include "led.h" +#include "sd.h" + + +#define SD_INIT_BUFFER_ADDRESS (0x05002800UL) + +#define CMD6_ARG_CHECK_HS (0x00FFFFF1UL) +#define CMD6_ARG_SWITCH_HS (0x80FFFFF1UL) + +#define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8) +#define CMD8_ARG_CHECK_PATTERN (0xAA << 0) + +#define ACMD6_ARG_BUS_WIDTH_4BIT (2 << 0) + +#define ACMD41_ARG_OCR (0x300000 << 0) +#define ACMD41_ARG_HCS (1 << 30) + +#define R3_OCR (0x300000 << 0) +#define R3_CCS (1 << 30) +#define R3_BUSY (1 << 31) + +#define R6_RCA_MASK (0xFFFF0000UL) + +#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 DAT_BLOCK_MAX_COUNT (256) +#define DAT_TIMEOUT_INIT_MS (2000) +#define DAT_TIMEOUT_DATA_MS (5000) + + +typedef enum { + CLOCK_STOP, + CLOCK_400KHZ, + CLOCK_25MHZ, + CLOCK_50MHZ, +} sd_clock_t; + +typedef enum { + RSP_NONE, + RSP_R1, + RSP_R1b, + RSP_R2, + RSP_R3, + RSP_R6, + RSP_R7, +} rsp_type_t; + +typedef enum { + DAT_READ, + DAT_WRITE, +} dat_mode_t; + + +struct process { + bool card_initialized; + bool card_type_block; + uint32_t rca; + uint8_t csd[16]; + uint8_t cid[16]; + volatile bool timeout; +}; + + +static struct process p; + + +static void sd_trigger_timeout (void) { + p.timeout = true; +} + +static void sd_prepare_timeout (uint16_t value) { + p.timeout = false; + hw_tim_setup(TIM_ID_SD, value, sd_trigger_timeout); +} + +static bool sd_did_timeout (void) { + return p.timeout; +} + +static void sd_clear_timeout (void) { + hw_tim_stop(TIM_ID_SD); + p.timeout = false; +} + +static void sd_set_clock (sd_clock_t mode) { + fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF); + + switch (mode) { + case CLOCK_400KHZ: + fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_400KHZ); + break; + case CLOCK_25MHZ: + fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_25MHZ); + break; + case CLOCK_50MHZ: + fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_50MHZ); + break; + default: + break; + } +} + +static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) { + uint32_t scr; + uint32_t cmd_data; + + cmd_data = ((cmd << SD_CMD_INDEX_BIT) & SD_CMD_INDEX_MASK); + switch (rsp_type) { + case RSP_NONE: + cmd_data |= SD_CMD_SKIP_RESPONSE; + break; + case RSP_R2: + cmd_data |= (SD_CMD_LONG_RESPONSE | SD_CMD_RESERVED_RESPONSE); + break; + case RSP_R3: + cmd_data |= (SD_CMD_IGNORE_CRC | SD_CMD_RESERVED_RESPONSE); + break; + default: + break; + } + + fpga_reg_set(REG_SD_ARG, arg); + fpga_reg_set(REG_SD_CMD, cmd_data); + + do { + scr = fpga_reg_get(REG_SD_SCR); + } while (scr & SD_SCR_CMD_BUSY); + + if (rsp != NULL) { + if (cmd_data & SD_CMD_LONG_RESPONSE) { + uint8_t *rsp_8 = (uint8_t *) (rsp); + for (int i = 0; i < 4; i++) { + uint32_t rsp_data = fpga_reg_get(REG_SD_RSP_3 - i); + uint8_t *rsp_data_8 = (uint8_t *) (&rsp_data); + rsp_data = SWAP32(rsp_data); + for (int i = 0; i < 4; i++) { + *rsp_8++ = *rsp_data_8++; + } + } + } else { + (*(uint32_t *) (rsp)) = fpga_reg_get(REG_SD_RSP_0); + } + } + + if (rsp_type == RSP_R1b) { + do { + scr = fpga_reg_get(REG_SD_SCR); + } while (scr & SD_SCR_CARD_BUSY); + } + + return (scr & SD_SCR_CMD_ERROR); +} + +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)) { + return true; + } + if (sd_cmd(acmd, arg, rsp_type, rsp)) { + return true; + } + return false; +} + +static void sd_dat_prepare (uint32_t address, uint32_t count, dat_mode_t mode) { + uint32_t length = (count * SD_SECTOR_SIZE); + uint32_t sd_dat = (((count - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_FIFO_FLUSH); + uint32_t sd_dma_scr = DMA_SCR_START; + + if (mode == DAT_READ) { + sd_dat |= SD_DAT_START_READ; + sd_dma_scr |= DMA_SCR_DIRECTION; + } else { + sd_dat |= SD_DAT_START_WRITE; + } + + fpga_reg_set(REG_SD_DAT, sd_dat); + fpga_reg_set(REG_SD_DMA_ADDRESS, address); + fpga_reg_set(REG_SD_DMA_LENGTH, length); + fpga_reg_set(REG_SD_DMA_SCR, sd_dma_scr); +} + +static void sd_dat_abort (void) { + fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP); + fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH); +} + +static bool sd_dat_wait (uint16_t timeout) { + sd_prepare_timeout(timeout); + + do { + uint32_t sd_dat = fpga_reg_get(REG_SD_DAT); + uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR); + led_blink_act(); + if ((!(sd_dat & SD_DAT_BUSY)) && (!(sd_dma_scr & DMA_SCR_BUSY))) { + sd_clear_timeout(); + return (sd_dat & SD_DAT_ERROR); + } + } while (!sd_did_timeout()); + + sd_dat_abort(); + + return true; +} + + +bool sd_card_init (void) { + uint32_t arg; + uint32_t rsp; + uint16_t tmp; + + if (p.card_initialized) { + return false; + } + + p.card_initialized = true; + p.rca = 0; + + led_blink_act(); + + sd_set_clock(CLOCK_400KHZ); + + sd_cmd(0, 0, RSP_NONE, NULL); + + arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN); + if (sd_cmd(8, arg, RSP_R7, &rsp)) { + arg = ACMD41_ARG_OCR; + } else { + if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) { + sd_card_deinit(); + return true; + } + arg = (ACMD41_ARG_HCS | ACMD41_ARG_OCR); + } + + sd_prepare_timeout(1000); + do { + if (sd_did_timeout()) { + sd_card_deinit(); + return true; + } + if (sd_acmd(41, arg, RSP_R3, &rsp)) { + sd_card_deinit(); + return true; + } + if (rsp & R3_BUSY) { + if ((rsp & R3_OCR) == 0) { + sd_card_deinit(); + return true; + } + p.card_type_block = (rsp & R3_CCS); + break; + } + } while (1); + sd_clear_timeout(); + + if (sd_cmd(2, 0, RSP_R2, NULL)) { + sd_card_deinit(); + return true; + } + + if (sd_cmd(3, 0, RSP_R6, &rsp)) { + sd_card_deinit(); + return true; + } + p.rca = (rsp & R6_RCA_MASK); + + if (sd_cmd(9, p.rca, RSP_R2, p.csd)) { + sd_card_deinit(); + return true; + } + + if (sd_cmd(10, p.rca, RSP_R2, p.cid)) { + sd_card_deinit(); + return true; + } + + if (sd_cmd(7, p.rca, RSP_R1b, NULL)) { + sd_card_deinit(); + return true; + } + + sd_set_clock(CLOCK_25MHZ); + + if (sd_acmd(6, ACMD6_ARG_BUS_WIDTH_4BIT, RSP_R1, NULL)) { + sd_card_deinit(); + return true; + } + + 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; + } + sd_dat_wait(DAT_TIMEOUT_INIT_MS); + if (sd_did_timeout()) { + sd_card_deinit(); + return true; + } + fpga_mem_read(SWITCH_FUNCTION_CURRENT_LIMIT, 2, (uint8_t *) (&tmp)); + if (SWAP16(tmp) == 0) { + sd_card_deinit(); + return true; + } + 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(); + sd_card_deinit(); + return true; + } + sd_dat_wait(DAT_TIMEOUT_INIT_MS); + if (sd_did_timeout()) { + sd_card_deinit(); + return true; + } + fpga_mem_read(SWITCH_FUNCTION_GROUP_1, 2, (uint8_t *) (&tmp)); + if (SWAP16(tmp) & SWITCH_FUNCTION_GROUP_1_HS) { + sd_set_clock(CLOCK_50MHZ); + } + } + + return false; +} + +void sd_card_deinit (void) { + if (p.card_initialized) { + p.card_initialized = false; + sd_set_clock(CLOCK_400KHZ); + sd_cmd(0, 0, RSP_NONE, NULL); + sd_set_clock(CLOCK_STOP); + } +} + +bool sd_card_is_inserted (void) { + return (fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED); +} + +uint32_t sd_card_get_status (void) { + uint32_t scr = fpga_reg_get(REG_SD_SCR); + uint32_t clock_mode_50mhz = ((scr & SD_SCR_CLOCK_MODE_MASK) == SD_SCR_CLOCK_MODE_50MHZ) ? 1 : 0; + uint32_t card_type_block = p.card_type_block ? 1 : 0; + uint32_t card_initialized = p.card_initialized ? 1 : 0; + uint32_t card_inserted = (scr & SD_SCR_CARD_INSERTED) ? 1 : 0; + return ( + (clock_mode_50mhz << 3) | + (card_type_block << 2) | + (card_initialized << 1) | + (card_inserted << 0) + ); +} + +bool sd_card_get_info (uint32_t address) { + if (!p.card_initialized) { + return true; + } + 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; +} + +bool sd_write_sectors (uint32_t address, uint32_t sector, uint32_t count) { + if (!p.card_initialized || (count == 0)) { + return true; + } + + if (!p.card_type_block) { + sector *= SD_SECTOR_SIZE; + } + + while (count > 0) { + uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); + led_blink_act(); + if (sd_cmd(25, sector, RSP_R1, NULL)) { + return true; + } + sd_dat_prepare(address, blocks, DAT_WRITE); + if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) { + sd_dat_abort(); + sd_cmd(12, 0, RSP_R1b, NULL); + return true; + } + sd_cmd(12, 0, RSP_R1b, NULL); + address += (blocks * SD_SECTOR_SIZE); + sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE)); + count -= blocks; + } + + return false; +} + +bool sd_read_sectors (uint32_t address, uint32_t sector, uint32_t count) { + if (!p.card_initialized || (count == 0)) { + return true; + } + + if (!p.card_type_block) { + sector *= SD_SECTOR_SIZE; + } + + while (count > 0) { + uint32_t blocks = ((count > DAT_BLOCK_MAX_COUNT) ? DAT_BLOCK_MAX_COUNT : count); + led_blink_act(); + sd_dat_prepare(address, blocks, DAT_READ); + if (sd_cmd(18, sector, RSP_R1, NULL)) { + sd_dat_abort(); + return true; + } + if (sd_dat_wait(DAT_TIMEOUT_DATA_MS)) { + if (sd_did_timeout()) { + sd_cmd(12, 0, RSP_R1b, NULL); + } + return true; + } + sd_cmd(12, 0, RSP_R1b, NULL); + address += (blocks * SD_SECTOR_SIZE); + sector += (blocks * (p.card_type_block ? 1 : SD_SECTOR_SIZE)); + count -= blocks; + } + + return false; +} + +bool 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; + } + + for (uint32_t i = 0; i < count; i++) { + if (sector_table[i] == 0) { + return true; + } + sectors_to_process += 1; + if ((i < (count - 1)) && ((sector_table[i] + 1) == sector_table[i + 1])) { + continue; + } + bool error = sd_process_sectors(address, sector_table[starting_sector], sectors_to_process); + if (error) { + return true; + } + address += (sectors_to_process * SD_SECTOR_SIZE); + starting_sector += sectors_to_process; + sectors_to_process = 0; + } + + return false; +} + +void sd_init (void) { + p.card_initialized = false; + sd_set_clock(CLOCK_STOP); +} + +void sd_process (void) { + if (!sd_card_is_inserted()) { + sd_card_deinit(); + } +} diff --git a/sw/pc/sc64.py b/sw/pc/sc64.py index e15d2f8..912b139 100755 --- a/sw/pc/sc64.py +++ b/sw/pc/sc64.py @@ -338,7 +338,7 @@ class SC64: def __get_int(self, data: bytes) -> int: return int.from_bytes(data[:4], byteorder='big') - def check_firmware_version(self) -> None: + def check_firmware_version(self) -> tuple[str, bool]: try: version = self.__link.execute_cmd(cmd=b'V') major = self.__get_int(version[0:2]) @@ -347,8 +347,9 @@ class SC64: raise ConnectionException() if (minor < self.__SUPPORTED_MINOR_VERSION): raise ConnectionException() + return (f'{major}.{minor}', minor > self.__SUPPORTED_MINOR_VERSION) except ConnectionException: - raise ConnectionException(f'Unsupported SC64 version ({major}.{minor}), please update firmware') + raise ConnectionException(f'Unsupported SC64 version [{major}.{minor}], please update firmware') def __set_config(self, config: __CfgId, value: int) -> None: try: @@ -1054,7 +1055,15 @@ if __name__ == '__main__': sc64.update_firmware(f.read(), status_callback) print('done') - sc64.check_firmware_version() + (version, script_outdated) = sc64.check_firmware_version() + + print(f'SC64 firmware version: [{version}]') + if (script_outdated): + print('\x1b[33m') + print('[ SC64 firmware is newer than last known version. ]') + print('[ Consider downloading latest script from ]') + print('[ https://github.com/Polprzewodnikowy/SummerCart64/releases ]') + print('\x1b[0m') if (args.reset_state): sc64.reset_state() @@ -1142,6 +1151,6 @@ if __name__ == '__main__': f.write(sc64.download_memory(address, length)) print('done') except ValueError as e: - print(f'\nValue error: {e}') + print(f'\n\x1b[31mValue error: {e}\x1b[0m\n') except ConnectionException as e: - print(f'\nSC64 error: {e}') + print(f'\n\x1b[31mSC64 error: {e}\x1b[0m\n')