#include "ab32vg1_hal.h" #ifdef HAL_SD_MODULE_ENABLED #define HAL_LOG(...) hal_printf(__VA_ARGS__) /************************* LL ************************************/ #define CK8E BIT(11) //在命令/数据包后加上8CLK #define CBUSY BIT(10) //Busy Check #define CLRSP BIT(9) //17Byte Long Rsp #define CRSP BIT(8) //Need Rsp //0x40是CMD中的 01 开头。 #define RSP_NO (0x40 | CK8E) #define RSP_1 (0x40 | CRSP | CK8E) //接收6BYTE #define RSP_1B (0x40 | CBUSY | CRSP | CK8E) //接收6BYTE,并等待BUSY #define RSP_2 (0x40 | CLRSP | CRSP | CK8E) //接收17BYTE #define RSP_3 (0x40 | CRSP | CK8E) //接收6BYTE #define RSP_6 (0x40 | CRSP | CK8E) //接收6BYTE #define RSP_7 (0x40 | CRSP | CK8E) //接收6BYTE #define REQ_MULTREAD (18 | 0x40 | CRSP) //多块读时,不需要增加8CLK。其实,多块读先KICK DATA,这个是无所谓的 #define RSP_BUSY_TIMEOUT 2400000 //大约2s #define RSP_TIMEOUT 6000 //大约5ms uint8_t sysclk_update_baud(uint8_t baud); void sdio_setbaud(hal_sfr_t sdiox, uint8_t baud) { sdiox[SDxBAUD] = sysclk_update_baud(baud); } void sdio_init(hal_sfr_t sdiox, sdio_init_t init) { sdiox[SDxCON] = 0; hal_udelay(20); sdiox[SDxCON] |= BIT(0); /* SD control enable */ sdio_setbaud(sdiox, init->clock_div); /* Set clock */ if (init->clock_power_save == SDMMC_CLOCK_POWER_SAVE_DISABLE) { sdiox[SDxCON] |= BIT(3); /* Keep clock output */ } else { sdiox[SDxCON] &= ~BIT(3); /* Keep clock output */ } sdiox[SDxCON] |= BIT(5); /* Data interrupt enable */ hal_mdelay(40); } /** * @brief Check if SDIO command is finished. * * @param sdiox * @return true is finished * @return false */ bool sdio_check_finish(hal_sfr_t sdiox) { if (sdiox[SDxCON] & BIT(12)) { sdiox[SDxCPND] = BIT(12); return true; } return false; } /** * @brief Check if SDIO has a response. * * @param sdiox * @return true Have a response. * @return false No response. */ bool sdio_check_rsp(hal_sfr_t sdiox) { return !(sdiox[SDxCON] & BIT(15)); } bool sdio_send_cmd(hal_sfr_t sdiox, uint32_t cmd, uint32_t arg, uint8_t *abend) { uint32_t time_out = (cmd & CBUSY) ? RSP_BUSY_TIMEOUT : RSP_TIMEOUT; sdiox[SDxARG3] = arg; sdiox[SDxCMD] = cmd; while (sdio_check_finish(sdiox) == false) { if (--time_out == 0) { HAL_LOG("cmd time out\n"); if (abend != HAL_NULL) { *abend = 1; } return false; } } return sdio_check_rsp(sdiox); } uint8_t sdio_get_cmd_rsp(hal_sfr_t sdiox) { return sdiox[SDxCMD]; } uint32_t sdio_get_rsp(hal_sfr_t sdiox, uint32_t rsp_reg) { return sdiox[rsp_reg]; } void sdio_read_kick(hal_sfr_t sdiox, void* buf) { sdiox[SDxDMAADR] = DMA_ADR(buf); sdiox[SDxDMACNT] = 512; } void sdio_write_kick(hal_sfr_t sdiox, void* buf) { sdiox[SDxDMAADR] = DMA_ADR(buf); sdiox[SDxDMACNT] = BIT(18) | BIT(17) | BIT(16) | 512; } bool sdio_isbusy(hal_sfr_t sdiox) { return false; } bool sdmmc_cmd_go_idle_state(sd_handle_t hsd) { return sdio_send_cmd(hsd->instance, 0 | RSP_NO, hsd->sdcard.rca, &(hsd->sdcard.abend)); } bool sdmmc_cmd_send_if_cond(sd_handle_t hsd) { return sdio_send_cmd(hsd->instance, 8 | RSP_7, SDMMC_CHECK_PATTERM, &(hsd->sdcard.abend)); } bool sdmmc_cmd_all_send_cid(sd_handle_t hsd) { return sdio_send_cmd(hsd->instance, 2 | RSP_2, 0, &(hsd->sdcard.abend)); } void sdmmc_cmd_set_rel_addr(sd_handle_t hsd) { hal_sfr_t sdiox = hsd->instance; if (hsd->sdcard.type == CARD_MMC) { hsd->sdcard.rca = 0x00010000; sdio_send_cmd(sdiox, 3 | RSP_1, hsd->sdcard.rca, &(hsd->sdcard.abend)); } else { sdio_send_cmd(sdiox, 3 | RSP_6, 0, &(hsd->sdcard.abend)); hsd->sdcard.rca = sdio_get_rsp(sdiox, SDxARG3) & 0xffff0000; } } void sdmmc_cmd_send_csd(sd_handle_t hsd) { hal_sfr_t sdiox = hsd->instance; sdio_send_cmd(sdiox, 9 | RSP_2, hsd->sdcard.rca, &(hsd->sdcard.abend)); if (hsd->sdcard.type == CARD_MMC) { // } else { if (hsd->sdcard.flag_sdhc == 1) { hsd->sdcard.capacity = (sdio_get_rsp(sdiox, SDxARG2) << 24) & 0x00ff0000; /* rspbuf[8] */ hsd->sdcard.capacity |= ((sdio_get_rsp(sdiox, SDxARG1) >> 16) & 0x0000ffff); /* rspbuf[9] rspbuf[10] */ hsd->sdcard.capacity += 1; hsd->sdcard.capacity <<= 10; } } HAL_LOG("sd capacity=%d\n", hsd->sdcard.capacity); } void sdmmc_cmd_select_card(sd_handle_t hsd) { sdio_send_cmd(hsd->instance, 7 | RSP_1B, hsd->sdcard.rca, &(hsd->sdcard.abend)); } bool sdmmc_cmd_read_multiblock(sd_handle_t hsd) { return sdio_send_cmd(hsd->instance, REQ_MULTREAD, hsd->sdcard.rca, &(hsd->sdcard.abend)); } bool sdmmc_cmd_app(sd_handle_t hsd) { return sdio_send_cmd(hsd->instance, 55 | RSP_1, hsd->sdcard.rca, &(hsd->sdcard.abend)); } bool sdmmc_acmd_op_cond(sd_handle_t hsd, uint32_t voltage) { /* SEND CMD55 APP_CMD with RCA */ if (sdmmc_cmd_app(hsd)) { /* Send CMD41 */ if (sdio_send_cmd(hsd->instance, 41 | RSP_3, voltage, &(hsd->sdcard.abend))) { return true; } } return false; } /************************* HAL ************************************/ static bool sd_type_identification(sd_handle_t hsd) { uint8_t retry = hsd->cfg.identification_retry; while (retry-- > 0) { /* CMD0: GO_IDLE_STATE */ sdmmc_cmd_go_idle_state(hsd); /* CMD8: SEND_IF_COND: Command available only on V2.0 cards */ if (sdmmc_cmd_send_if_cond(hsd)) { if (sdio_get_cmd_rsp(hsd->instance) == 0x08) { hsd->sdcard.type = CARD_V2; HAL_LOG("SD 2.0\n"); return true; } continue; } if (sdmmc_acmd_op_cond(hsd, 0x00ff8000)) { hsd->sdcard.type = CARD_V1; HAL_LOG("SD 1.0\n"); return true; } hal_mdelay(20); } return false; } static bool sd_go_ready_try(sd_handle_t hsd) { uint32_t tmp = 0; switch (hsd->sdcard.type) { case CARD_V1: sdmmc_acmd_op_cond(hsd, 0x00ff8000); break; case CARD_V2: sdmmc_acmd_op_cond(hsd, 0x40ff8000); break; default: break; } if (0 == (hsd->instance[SDxARG3] & BIT(31))) { return false; // no ready } if ((hsd->sdcard.type == CARD_V2) && (hsd->instance[SDxARG3] & BIT(30))) { HAL_LOG("SDHC\n"); hsd->sdcard.flag_sdhc = 1; } return true; } static bool sd_go_ready(sd_handle_t hsd) { if (hsd->sdcard.type == CARD_INVAL) { return false; } uint8_t retry = hsd->cfg.go_ready_retry; while (retry-- > 0) { if (sd_go_ready_try(hsd) == true) { return true; } hal_mdelay(20); } return false; } static bool sd_poweron(sd_handle_t hsd) { if (sd_type_identification(hsd) == false) { HAL_LOG("card invalid\n"); return false; } if (sd_go_ready(hsd) == false) { HAL_LOG("no ready\n"); return false; } return true; } static void sd_init_card(sd_handle_t hsd) { /* Send CMD2 ALL_SEND_CID */ sdmmc_cmd_all_send_cid(hsd); /* Send CMD3 SET_REL_ADDR */ sdmmc_cmd_set_rel_addr(hsd); /* Send CMD9 SEND_CSD */ sdmmc_cmd_send_csd(hsd); /* Select the Card */ sdmmc_cmd_select_card(hsd); hsd->init.clock_div = 3; hsd->init.clock_power_save = SDMMC_CLOCK_POWER_SAVE_ENABLE; sdio_init(hsd->instance, &(hsd->init)); } static bool sd_read_wait(sd_handle_t hsd) { bool ret = false; hal_sfr_t sdiox = hsd->instance; return ret; } static void sd_read_start(sd_handle_t hsd, void *buf, uint32_t lba) { if (hsd->sdcard.rw_state == HAL_SD_RW_STATE_READ) { } else { if (hsd->sdcard.rw_state == HAL_SD_RW_STATE_WRITE) { } sdio_read_kick(hsd->instance, buf); sdmmc_cmd_read_multiblock(hsd); } hsd->sdcard.rw_state = HAL_SD_RW_STATE_READ; // hsd->sdcard.rw_lba } static bool sd_read_try(sd_handle_t hsd, void *buf, uint32_t lba) { HAL_LOG("read: %08x\n", lba); if (hsd->sdcard.capacity < lba) { lba = hsd->sdcard.capacity - 1; } sd_read_start(hsd, buf, lba); return 0; } void hal_sd_initcard(sd_handle_t hsd) { hal_sfr_t sdiox = hsd->instance; hsd->init.clock_div = 119; /* SD clk 240KHz when system clk is 48MHz */ hsd->init.clock_power_save = SDMMC_CLOCK_POWER_SAVE_DISABLE; sdio_init(sdiox, &(hsd->init)); sd_poweron(hsd); sd_init_card(hsd); } WEAK void hal_sd_mspinit(sd_handle_t hsd) { } hal_error_t hal_sd_init(sd_handle_t hsd) { if (hsd == HAL_NULL) { return -HAL_ERROR; } hsd->cfg.go_ready_retry = 200; hsd->cfg.identification_retry = 5; hsd->cfg.rw_init_retry = 3; hsd->cfg.rw_retry = 3; hal_sd_mspinit(hsd); hal_sd_initcard(hsd); return -HAL_ERROR; } void hal_sd_deinit(uint32_t sdx) { } bool hal_sd_read(sd_handle_t hsd, void *buf, uint32_t lba) { uint8_t init_retry = hsd->cfg.rw_init_retry; while (init_retry-- > 0) { uint8_t retry = hsd->cfg.rw_retry; while (retry-- > 0) { if (sd_read_try(hsd, buf, lba)) { return true; } } hsd->sdcard.state = HAL_SD_STATE_INVAL; hal_mdelay(20); } return false; } #endif