/** * Kneron Peripheral API - SDC * * Copyright (C) 2019 Kneron, Inc. All rights reserved. * */ #include #include #include "kdrv_sdc.h" //#include "kmdw_console.h" #include "kdrv_clock.h" #include "kdrv_scu_ext.h" #include "kdrv_pwm.h" //#define KDRV_SDC_DBG //debug message flag #ifdef KDRV_SDC_DBG #define kmdw_dbg_printf kmdw_printf #else #define kmdw_dbg_printf(fmt, ...) #endif typedef signed long clock_t; #define FTSDC021_BASE_CLOCK 100 /* 100MHz */ #define SDC_AHB_CHANNEL 0 #define USE_PIO /* SDC0 Resources */ kdrv_sdc_res_t sdc0_res = { (kdrv_sdc_reg_t *)SDC_FTSDC021_PA_BASE, NULL, NULL, INFINITE_NO, 0, 0,//timeout ns 0, 0, //insert interrupt 0, //insert nop 0, //response type 0, //inhibit_datchk }; static const uint32_t tran_exp[] = { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; static const uint8_t tran_mant[] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; static kdrv_sdc_res_t *gdev = &sdc0_res; uint32_t sdma_bound_mask; kdrv_sdc_adma2desc_table_t sdc_adma2_desc_table[ADMA2_NUM_OF_LINES]; volatile uint8_t err_recover = 0; uint32_t rd_bl_len, wr_bl_len; //volatile BOOL cardChanged = false; static kdrv_status_t kdrv_sdc_auto_cmd_error_recovery(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_error_recovery(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_wait_for_state(kdrv_sdc_res_t *dev, uint32_t state, uint32_t ms); static kdrv_status_t kdrv_sdc_transfer_data(kdrv_sdc_res_t *dev, kdrv_sdc_transfer_act_e act, uint32_t * buffer, uint32_t length); static kdrv_status_t kdrv_sdc_set_transfer_mode(kdrv_sdc_res_t *dev, uint8_t blk_cnt_en, uint8_t auto_cmd, uint8_t dir, uint8_t multi_blk); static kdrv_status_t kdrv_sdc_send_command(kdrv_sdc_res_t *dev, uint8_t cmd_idx, uint8_t cmd_type, uint8_t data_present, uint8_t resp_type, uint8_t inhibit_datchk, uint32_t argu); static kdrv_status_t kdrv_sdc_prepare_data(kdrv_sdc_res_t *dev,uint32_t blk_cnt, uint16_t blk_sz, uint32_t buff_addr, kdrv_sdc_transfer_act_e act); /* * MMC card related operations */ static kdrv_status_t kdrv_sdc_ops_send_op_cond(kdrv_sdc_res_t *dev, uint32_t ocr, volatile uint32_t * rocr); static kdrv_status_t kdrv_sdc_ops_mmc_switch(kdrv_sdc_res_t *dev, uint8_t set, uint8_t index, uint8_t value); static kdrv_status_t kdrv_sdc_ops_send_ext_csd(kdrv_sdc_res_t *dev); /* * SD card related operations(Some applies to MMC) */ static kdrv_status_t kdrv_sdc_ops_go_idle_state(kdrv_sdc_res_t *dev, uint32_t arg); static kdrv_status_t kdrv_sdc_ops_send_if_cond(kdrv_sdc_res_t *dev, uint32_t arg); static kdrv_status_t kdrv_sdc_ops_send_app_op_cond(kdrv_sdc_res_t *dev, uint32_t ocr, volatile uint32_t * rocr); static kdrv_status_t kdrv_sdc_ops_all_send_cid(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_ops_send_rca(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_ops_send_csd(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_ops_select_card(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_ops_app_send_scr(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_ops_app_set_bus_width(kdrv_sdc_res_t *dev, uint32_t width); static kdrv_status_t kdrv_sdc_ops_sd_switch(kdrv_sdc_res_t *dev, uint32_t mode, uint32_t group, uint8_t value, volatile uint8_t * resp); static kdrv_status_t kdrv_sdc_ops_send_tune_block(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_ops_send_card_status(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_card_read(kdrv_sdc_res_t *dev, uint32_t startAddr, uint32_t blkcnt, uint8_t * read_buf); static kdrv_status_t kdrv_sdc_card_write(kdrv_sdc_res_t *dev, uint32_t startAddr, uint32_t blkcnt, uint8_t * write_buf); static kdrv_status_t kdrv_sdc_set_bus_width(kdrv_sdc_res_t *dev, uint8_t width); static void kdrv_sdc_set_sd_clock(kdrv_sdc_res_t *dev, uint32_t clock); static kdrv_status_t kdrv_sdc_read_scr(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_read_ext_csd(kdrv_sdc_res_t *dev); static kdrv_status_t kdrv_sdc_set_bus_speed_mode(kdrv_sdc_res_t *dev, uint8_t speed); static void kdrv_sdc_set_sd_clock(kdrv_sdc_res_t *dev, uint32_t clock); /* * MMC card related operations */ /** * @brief kdrv_sdc_ops_send_op_cond() send CMD1 op_cond command to wakeup device * * @param[in] ocr ocr input information * @param[out] rocr * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_send_op_cond(kdrv_sdc_res_t *dev, uint32_t ocr, volatile uint32_t * rocr) { kdrv_status_t err; uint32_t i; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; for (i = 100; i; i--) { err = kdrv_sdc_send_command(dev, SDHCI_CMD1_MMC_SEND_OP_COND, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R3R4, 0, ocr); if (err) break; /* if we're just probing, do a single pass */ if (ocr == 0) break; /* otherwise wait until reset completes */ if (card->resp_lo & MMC_CARD_BUSY) break; kdrv_delay_us(10000); } if (rocr) *rocr = card->resp_lo; return err; } /** * @brief kdrv_sdc_ops_mmc_switch() send CMD6 switch command to change the EXT_CSD data * * @param[in] dev device structure * @param[in] sw_type switch type (normal, secure, cpsecure) * @param[in] index data index * @param[in] speed speed attribute * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_mmc_switch(kdrv_sdc_res_t *dev, uint8_t sw_type, uint8_t index, uint8_t value) { kdrv_status_t err; uint32_t arg; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; if (card->card_type != MEMORY_CARD_TYPE_MMC) { //kmdw_dbg_printf( "Switch Function: This is not MMC Card !\n"); return KDRV_STATUS_SDC_CARD_TYPE_ERR; } arg = (EXT_CSD_WRITE_BYTE << 24) | (index << 16) | (value << 8) | sw_type; err = kdrv_sdc_send_command(dev, SDHCI_CMD6_SWITCH_FUNC, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1BR5B, 1, arg); return err; } /** * @brief kdrv_sdc_ops_send_ext_csd() send ext_csd(CMD8) request command * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_send_ext_csd(kdrv_sdc_res_t *dev) { kdrv_status_t err; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; if (card_info->card_type == MEMORY_CARD_TYPE_MMC && card_info->csd_mmc.spec_vers < 4) { //kmdw_dbg_printf(" Commmand 8 is not supported in this MMC system spec.\n"); return KDRV_STATUS_OK; } memset((void *)&card_info->ext_csd_mmc, 0, EXT_CSD_LENGTH); kdrv_sdc_set_transfer_mode(dev, 0, 0, SDHCI_TXMODE_READ_DIRECTION, 0); kdrv_sdc_prepare_data(dev, 1, EXT_CSD_LENGTH, (uint32_t) & (card_info->ext_csd_mmc), READ); /* CMD 8 */ if ((err = kdrv_sdc_send_command(dev, SDHCI_CMD8_SEND_EXT_CSD, SDHCI_CMD_TYPE_NORMAL, 1, SDHCI_CMD_RTYPE_R1R5R6R7, 0, 0)) != KDRV_STATUS_OK) { //kmdw_dbg_printf("Getting the Ext-CSD failed\n"); return err; } return kdrv_sdc_transfer_data(dev, READ, (uint32_t *) & (card_info->ext_csd_mmc), EXT_CSD_LENGTH); } /** * @brief kdrv_sdc_ops_go_idle_state() enter idle state * MMC4.4: * argument = 0x00000000, Resets the card to idle state. * argument = 0xF0F0F0F0, Resets the card to pre-idle state. * argument = 0xFFFFFFFA, Initiate alternative boot operation. * * SD Card: Argument always 0x00000000. * * @param dev device structure * @param arg input argument * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_go_idle_state(kdrv_sdc_res_t *dev, uint32_t arg) { uint8_t data; data = (arg == 0xFFFFFFFA) ? 1 : 0; return (kdrv_sdc_send_command(dev, SDHCI_CMD0_GO_IDLE_STATE, SDHCI_CMD_TYPE_NORMAL, data, SDHCI_CMD_NO_RESPONSE, 0, arg)); } /* SD card related operations */ /** * @brief kdrv_sdc_ops_send_if_cond() send ext_csd(CMD8) request command * CMD8 SD card * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_send_if_cond(kdrv_sdc_res_t *dev, uint32_t arg) { kdrv_status_t err; uint8_t test_pattern = (arg & 0xFF); uint8_t result_pattern; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; err = kdrv_sdc_send_command(dev, SDHCI_CMD8_SEND_IF_COND, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 0, arg); if (err) return err; result_pattern = card->resp_lo & 0xFF; if (result_pattern != test_pattern) return KDRV_STATUS_ERROR; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_ops_send_if_cond() send ocr(ACMD41) request command * * @param[in] dev device structure * @param[in] ocr ocr input data * @param[out] rocr recevied ocr data * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_send_app_op_cond(kdrv_sdc_res_t *dev, uint32_t ocr, volatile uint32_t *rocr) { uint32_t i; kdrv_status_t err; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; for (i = 100; i; i--) { /* CMD 55: Indicate to the card the next cmd is app-specific command */ if ((err = kdrv_sdc_send_command(dev, SDHCI_CMD55_APP, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 0, 0)) != KDRV_STATUS_OK) break; if ((err = kdrv_sdc_send_command(dev, SDHCI_CMD41_SD_SEND_OP_COND, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R3R4, 0, ocr)) != KDRV_STATUS_OK) break; /* if we're just probing, do a single pass */ if (ocr == 0) break; if (card->resp_lo & MMC_CARD_BUSY) break; kdrv_delay_us(80000); } if (rocr) *rocr = card->resp_lo; return err; } /** * @brief kdrv_sdc_ops_all_send_cid() send cid(CMD2) request command * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_all_send_cid(kdrv_sdc_res_t *dev) { volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; if (kdrv_sdc_send_command(dev, SDHCI_CMD2_SEND_ALL_CID, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R2, 1, 0)) { //kmdw_dbg_printf("ALL SEND CID failed !\n"); return KDRV_STATUS_SDC_CID_READ_ERR; } card->cid_lo = card->resp_lo; card->cid_hi = card->resp_hi; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_ops_send_rca() send CMD3 to request rca information * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_send_rca(kdrv_sdc_res_t *dev) { uint32_t i; kdrv_status_t err; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; for (i = 100; i; i--) { err = kdrv_sdc_send_command(dev, SDHCI_CMD3_SEND_RELATIVE_ADDR, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 0, (card->rca << 16)); if (err) break; /* MMC card, Host assign rca to card. * SD card, Host ask for rca. */ if (card->rca != 0) break; if ((card->resp_lo >> 16) & 0xffff) break; //err = 1; kdrv_delay_us(10000); } if (!err) if (!card->rca) card->rca = (uint16_t) ((card->resp_lo >> 16) & 0xffff); return err; } /** * @brief kdrv_sdc_ops_send_csd() send csd(CMD9) command request * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_send_csd(kdrv_sdc_res_t *dev) { kdrv_status_t err; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; /* CMD 9: Getting the CSD register from SD memory card */ err = kdrv_sdc_send_command(dev, SDHCI_CMD9_SEND_CSD, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R2, 0, card->rca << 16); if (err) return err; card->csd_lo = card->resp_lo; card->csd_hi = card->resp_hi; if (card->card_type == MEMORY_CARD_TYPE_SD) { if ((card->csd_hi >> 54) == 0) { card->csd_ver1.csd_structure = (card->csd_hi >> 54) & 0x3; card->csd_ver1.reserved1 = (card->csd_hi >> 48) & 0x3F; card->csd_ver1.taac = (card->csd_hi >> 40) & 0xFF; card->csd_ver1.nsac = (card->csd_hi >> 32) & 0xFF; card->csd_ver1.tran_speed = (card->csd_hi >> 24) & 0xFF; card->csd_ver1.ccc = (card->csd_hi >> 12) & 0xFFF; card->csd_ver1.read_bl_len = (card->csd_hi >> 8) & 0xF; card->csd_ver1.read_bl_partial = (card->csd_hi >> 7) & 0x1; card->csd_ver1.write_blk_misalign = (card->csd_hi >> 6) & 0x1; card->csd_ver1.read_blk_misalign = (card->csd_hi >> 5) & 0x1; card->csd_ver1.dsr_imp = (card->csd_hi >> 4) & 0x1; card->csd_ver1.reserved2 = (card->csd_hi >> 2) & 0x3; card->csd_ver1.c_size = (((card->csd_hi & 0x3) << 10) | ((card->csd_lo >> 54) & 0x3FF)); card->csd_ver1.vdd_r_curr_min = (card->csd_lo >> 51) & 0x7; card->csd_ver1.vdd_r_curr_max = (card->csd_lo >> 48) & 0x7; card->csd_ver1.vdd_w_curr_min = (card->csd_lo >> 45) & 0x7; card->csd_ver1.vdd_w_curr_max = (card->csd_lo >> 42) & 0x7; card->csd_ver1.c_size_mult = (card->csd_lo >> 39) & 0x7; card->csd_ver1.erase_blk_en = (card->csd_lo >> 38) & 0x1; card->csd_ver1.sector_size = (card->csd_lo >> 31) & 0x7F; card->csd_ver1.wp_grp_size = (card->csd_lo >> 24) & 0x7F; card->csd_ver1.wp_grp_enable = (card->csd_lo >> 23) & 0x1; card->csd_ver1.reserved3 = (card->csd_lo >> 21) & 0x3; card->csd_ver1.r2w_factor = (card->csd_lo >> 18) & 0x7; card->csd_ver1.write_bl_len = (card->csd_lo >> 14) & 0xF; card->csd_ver1.write_bl_partial = (card->csd_lo >> 13) & 0x1; card->csd_ver1.reserved4 = (card->csd_lo >> 8) & 0x1F; card->csd_ver1.file_format_grp = (card->csd_lo >> 7) & 0x1; card->csd_ver1.copy = (card->csd_lo >> 6) & 0x1; card->csd_ver1.perm_write_protect = (card->csd_lo >> 5) & 0x1; card->csd_ver1.tmp_write_protect = (card->csd_lo >> 4) & 0x1; card->csd_ver1.file_format = (card->csd_lo >> 2) & 0x3; card->csd_ver1.Reserver5 = (card->csd_lo) & 0x3; } else if ((card->csd_hi >> 54) == 1) { card->csd_ver2.csd_structure = (card->csd_hi >> 54) & 0x3; card->csd_ver2.reserved1 = (card->csd_hi >> 48) & 0x3F; card->csd_ver2.taac = (card->csd_hi >> 40) & 0xFF; card->csd_ver2.nsac = (card->csd_hi >> 32) & 0xFF; card->csd_ver2.tran_speed = (card->csd_hi >> 24) & 0xFF; card->csd_ver2.ccc = (card->csd_hi >> 12) & 0xFFF; card->csd_ver2.read_bl_len = (card->csd_hi >> 8) & 0xF; card->csd_ver2.read_bl_partial = (card->csd_hi >> 7) & 0x1; card->csd_ver2.write_blk_misalign = (card->csd_hi >> 6) & 0x1; card->csd_ver2.read_blk_misalign = (card->csd_hi >> 5) & 0x1; card->csd_ver2.dsr_imp = (card->csd_hi >> 4) & 0x1; card->csd_ver2.reserved2 = (((card->csd_hi >> 2) & 0x3) << 2) | ((card->csd_lo >> 62) & 0x3); card->csd_ver2.c_size = ((card->csd_lo >> 40) & 0x3FFFFF); card->csd_ver2.reserved3 = (card->csd_lo >> 39) & 0x1; card->csd_ver2.erase_blk_en = (card->csd_lo >> 38) & 0x1; card->csd_ver2.sector_size = (card->csd_lo >> 31) & 0x7F; card->csd_ver2.wp_grp_size = (card->csd_lo >> 24) & 0x7F; card->csd_ver2.wp_grp_enable = (card->csd_lo >> 23) & 0x1; card->csd_ver2.reserved4 = (card->csd_lo >> 21) & 0x3; card->csd_ver2.r2w_factor = (card->csd_lo >> 18) & 0x7; card->csd_ver2.write_bl_len = (card->csd_lo >> 14) & 0xF; card->csd_ver2.write_bl_partial = (card->csd_lo >> 13) & 0x1; card->csd_ver2.reserved5 = (card->csd_lo >> 8) & 0x1F; card->csd_ver2.file_format_grp = (card->csd_lo >> 7) & 0x1; card->csd_ver2.copy = (card->csd_lo >> 6) & 0x1; card->csd_ver2.perm_write_protect = (card->csd_lo >> 5) & 0x1; card->csd_ver2.tmp_write_protect = (card->csd_lo >> 4) & 0x1; card->csd_ver2.file_format = (card->csd_lo >> 2) & 0x3; card->csd_ver2.reserver6 = (card->csd_lo) & 0x3; } } else if (card->card_type == MEMORY_CARD_TYPE_MMC) { card->csd_mmc.csd_structure = (card->csd_hi >> 54) & 0x3; card->csd_mmc.spec_vers = (card->csd_hi >> 50) & 0xF; card->csd_mmc.reserved1 = (card->csd_hi >> 48) & 0x3; card->csd_mmc.taac = (card->csd_hi >> 40) & 0xFF; card->csd_mmc.nsac = (card->csd_hi >> 32) & 0xFF; card->csd_mmc.tran_speed = (card->csd_hi >> 24) & 0xFF; card->csd_mmc.ccc = (card->csd_hi >> 12) & 0xFFF; card->csd_mmc.read_bl_len = (card->csd_hi >> 8) & 0xF; card->csd_mmc.read_bl_partial = (card->csd_hi >> 7) & 0x1; card->csd_mmc.write_blk_misalign = (card->csd_hi >> 6) & 0x1; card->csd_mmc.read_blk_misalign = (card->csd_hi >> 5) & 0x1; card->csd_mmc.dsr_imp = (card->csd_hi >> 4) & 0x1; card->csd_mmc.reserved2 = (card->csd_hi >> 2) & 0x3; card->csd_mmc.c_size = (((card->csd_hi & 0x3) << 10) | (card->csd_lo >> 54) & 0x3FF); card->csd_mmc.vdd_r_curr_min = (card->csd_lo >> 51) & 0x7; card->csd_mmc.vdd_r_curr_max = (card->csd_lo >> 48) & 0x7; card->csd_mmc.vdd_w_curr_min = (card->csd_lo >> 45) & 0x7; card->csd_mmc.vdd_w_curr_max = (card->csd_lo >> 42) & 0x7; card->csd_mmc.c_size_mult = (card->csd_lo >> 39) & 0x7; card->csd_mmc.erase_grp_size = (card->csd_lo >> 34) & 0x1F; card->csd_mmc.erase_grp_mult = (card->csd_lo >> 29) & 0x1F; card->csd_mmc.wp_grp_size = (card->csd_lo >> 24) & 0x1F; card->csd_mmc.wp_grp_enable = (card->csd_lo >> 23) & 0x1; card->csd_mmc.default_ecc = (card->csd_lo >> 21) & 0x3; card->csd_mmc.r2w_factor = (card->csd_lo >> 18) & 0x7; card->csd_mmc.write_bl_len = (card->csd_lo >> 14) & 0xF; card->csd_mmc.write_bl_partial = (card->csd_lo >> 13) & 0x1; card->csd_mmc.reserved3 = (card->csd_lo >> 9) & 0xF; card->csd_mmc.content_prot_app = (card->csd_lo >> 8) & 0x1; card->csd_mmc.file_format_grp = (card->csd_lo >> 7) & 0x1; card->csd_mmc.COPY = (card->csd_lo >> 6) & 0x1; card->csd_mmc.perm_write_protect = (card->csd_lo >> 5) & 0x1; card->csd_mmc.tmp_write_protect = (card->csd_lo >> 4) & 0x1; card->csd_mmc.file_format = (card->csd_lo >> 2) & 0x3; card->csd_mmc.ecc = (card->csd_lo) & 0x3; } return err; } /** * @brief kdrv_sdc_ops_send_csd() send select card command(CMD7) * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_select_card(kdrv_sdc_res_t *dev) { volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; /* send CMD7 to enter transfer mode */ return kdrv_sdc_send_command(dev, SDHCI_CMD7_SELECT_CARD, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 0, card_info->rca << 16); } /** * @brief kdrv_sdc_ops_app_send_scr() send scr request command * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_app_send_scr(kdrv_sdc_res_t *dev) { volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; // Reading the scr through PIO /* CMD 55 */ kdrv_sdc_send_command(dev, SDHCI_CMD55_APP, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 1, (card->rca << 16)); kdrv_sdc_set_transfer_mode(dev, 0, 0, SDHCI_TXMODE_READ_DIRECTION, 0); kdrv_sdc_prepare_data(dev, 1, SCR_LENGTH, (uint32_t) & (card->scr), READ); /* ACMD 51 */ kdrv_sdc_send_command(dev, SDHCI_CMD51_SEND_SCR, SDHCI_CMD_TYPE_NORMAL, 1, SDHCI_CMD_RTYPE_R1R5R6R7, 1, 0); return (kdrv_sdc_transfer_data(dev, READ, (uint32_t *) & (card->scr), SCR_LENGTH)); } /** * @brief kdrv_sdc_ops_app_set_bus_width() send bus width set command(ACM6) * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_app_set_bus_width(kdrv_sdc_res_t *dev, uint32_t width) { kdrv_status_t err; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; /* CMD 55: Indicate to the card the next cmd is app-specific command */ err = kdrv_sdc_send_command(dev, SDHCI_CMD55_APP, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 0,(card->rca << 16)); if (err) return err; err = kdrv_sdc_send_command(dev, SDHCI_CMD6_SET_BUS_WIDTH, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 0, width); if (err) return err; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_ops_sd_switch() send switch command(CMD6) * Switch Function returns 64 bytes status data. Caller must * make sure "resp" pointer has allocated enough space. * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_sd_switch(kdrv_sdc_res_t *dev, uint32_t mode, uint32_t group, uint8_t value, volatile uint8_t * resp) { uint32_t arg; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; if (card->card_type != MEMORY_CARD_TYPE_SD) { kmdw_dbg_printf("Switch Function: This is not SD Card !\n"); return KDRV_STATUS_SDC_CARD_TYPE_ERR; } kdrv_sdc_set_transfer_mode(dev, 0, 0, SDHCI_TXMODE_READ_DIRECTION, 0); kdrv_sdc_prepare_data(dev, 1, 64, (uint32_t) resp, READ); //Check Function arg = mode << 31 | 0x00FFFFFF; arg &= ~(0xF << (group * 4)); arg |= value << (group * 4); // Commented by MikeYeh 081201: The 31st bit of argument for CMD6 is zero to indicate "Check Function". // Check function used to query if the card supported a specific function. /* CMD 6 */ if (kdrv_sdc_send_command(dev, SDHCI_CMD6_SWITCH_FUNC, SDHCI_CMD_TYPE_NORMAL, 1, SDHCI_CMD_RTYPE_R1R5R6R7, 1, arg)) { //kmdw_dbg_printf("CMD6 Failed.\n"); return KDRV_STATUS_SDC_SWITCH_ERR; } return kdrv_sdc_transfer_data(dev, READ, (uint32_t *) resp, 64); } /** * @brief kdrv_sdc_ops_send_tune_block() send tunning command(CMD19) to device * 64bytes tunning pattern for SDR50/SDR104 * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_send_tune_block(kdrv_sdc_res_t *dev) { kdrv_status_t err; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; if (!(sdc_reg->host_ctl2 & SDHCI_EXECUTE_TUNING)) { return KDRV_STATUS_OK; } kdrv_sdc_set_transfer_mode(dev, 0, 0, SDHCI_TXMODE_READ_DIRECTION, 0); kdrv_sdc_prepare_data(dev, 1, 64, NULL, READ); if ((err = kdrv_sdc_send_command(dev, SDHCI_CMD19_SEND_TUNE_BLOCK, SDHCI_CMD_TYPE_NORMAL, 1, SDHCI_CMD_NO_RESPONSE, 1, 0)) != KDRV_STATUS_OK) return err; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_ops_send_card_status() send status request command(CMD13) * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_ops_send_card_status(kdrv_sdc_res_t *dev) { kdrv_status_t err; volatile kdrv_sdc_sdcard_info_t *card = dev->card_info; if ((err = kdrv_sdc_send_command(dev, SDHCI_CMD13_SEND_STATUS, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 0, (card->rca << 16))) != KDRV_STATUS_OK) return err; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_set_base_clock(), set host base clock information * * @param[in] host host structure * @param[in] clk clock frequency * @return N/A */ static void kdrv_sdc_set_base_clock(kdrv_sdc_sd_host_t *host,uint32_t clk) { host->max_clk = clk * 1000000; host->min_clk = host->max_clk / 256; } /** * @brief kdrv_sdc_transfer_data() transfer R/W data to device * Return the "residual" number of bytes write. * Caller check for this for correctness. * Do not use interrupt signal for PIO mode. * The unit of length is bytes. * @param[in] dev device * @param[in] act read/write action * @param[in] buffer read/write buffer * @param[in] length read/write length bytes * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_transfer_data(kdrv_sdc_res_t *dev, kdrv_sdc_transfer_act_e act, uint32_t *buffer, uint32_t length) { //kdrv_status_t rstatus; uint32_t trans_sz, len, wait_t; uint16_t mask; clock_t t0; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; if (length == 0) { return KDRV_STATUS_OK; } if (card_info->flow_set.use_dma == PIO) { uint32_t dsize; uint8_t *u8_buf; uint16_t *u16_buf; wait_t = dev->timeout_ms; dsize = card_info->flow_set.line_bound; switch (dsize) { case 1: u8_buf = (uint8_t *) buffer; break; case 2: u16_buf = (uint16_t *) buffer; break; default: break; } if (act == WRITE) mask = SDHCI_INTR_STS_BUFF_WRITE_READY; else mask = SDHCI_INTR_STS_BUFF_READ_READY; trans_sz = dev->fifo_depth; while (length || (dev->infinite_mode && (sdc_reg->txmode & SDHCI_TXMODE_MULTI_SEL))) { t0 = kdrv_current_t1_tick(); while (!(sdc_reg->intr_sts & mask)) { if (kdrv_current_t1_tick() - t0 > wait_t) { /* check R/W ready time out */ //rstatus = KDRV_STATUS_SDC_TX_TIEMOUT; goto out; } } /* Clear Interrupt status */ sdc_reg->intr_sts = mask; len = (length < trans_sz) ? length : trans_sz; length -= len; while (len) { switch (dsize) { case 1: /* byte read/write */ if (act == WRITE) { outb(KDRV_SDC_BASE + SDHCI_REG_DATA_PORT, *u8_buf); } else { *u8_buf = inb((KDRV_SDC_BASE + SDHCI_REG_DATA_PORT)); } len -= 1; u8_buf++; break; case 2: /* 16bits read/write */ if (act == WRITE) { outhw(KDRV_SDC_BASE + SDHCI_REG_DATA_PORT, *u16_buf); } else { *u16_buf = inhw(KDRV_SDC_BASE + SDHCI_REG_DATA_PORT); } len -= 2; u16_buf++; break; default: /* 32bits read/write */ if (act == WRITE) { outw(KDRV_SDC_BASE + SDHCI_REG_DATA_PORT, *buffer); } else { *buffer = inw(KDRV_SDC_BASE + SDHCI_REG_DATA_PORT); } len -= 4; buffer++; break; } } } /* Wait for last block to be completed */ if (dev->infinite_mode) { /* Actually no Transfer Complete for infite transfer, * But if we set Stop at Block Gap, then there will be * Transfer Complete. */ if (act == WRITE) { card_info->cmpl_mask |= WAIT_BLOCK_GAP; sdc_reg->blk_gap_ctl |= SDHCI_STOP_AT_BLOCK_GAP_REQ; } else { card_info->cmpl_mask &= ~WAIT_TRANS_COMPLETE; } } } else if (card_info->flow_set.use_dma == SDMA) { uint32_t next_addr; trans_sz = sdma_bound_mask + 1; wait_t = dev->timeout_ms * (trans_sz >> 9); do { t0 = kdrv_current_t1_tick(); /* Make sure SDMA finish before we lacth the next address */ while (card_info->cmpl_mask) { if (card_info->err_sts) goto out; if ((kdrv_current_t1_tick() - t0) > wait_t) { /* try err recovery */ //rstatus = KDRV_STATUS_SDC_TX_TIEMOUT; goto out; } } next_addr = sdc_reg->sdma_addr; /* Transfered bytes count */ len = next_addr - (uint32_t) buffer; /* Minus the total desired bytes count. SDMA stops at boundary * but it might already exceed our intended bytes */ if ((int32_t) (length - len) < 0) length = 0; else length -= len; if (!length) break; /* Boundary Checking */ if (next_addr & sdma_bound_mask) { return KDRV_STATUS_SDC_TRANSFER_FAIL; } /* Remaining bytes less than SDMA boundary. * For finite transfer, Wait for transfer complete interrupt. * Infinite transfer, wait for DMA interrupt. */ if ((length > trans_sz) || ((length <= trans_sz) && dev->infinite_mode)) card_info->cmpl_mask = WAIT_DMA_INTR; else { card_info->cmpl_mask = WAIT_TRANS_COMPLETE; } buffer = (uint32_t*)next_addr; sdc_reg->sdma_addr = next_addr; } while (1); /* Wait for last block to be completed */ if (dev->infinite_mode) { /* Actually no Transfer Complete for infite transfer, * But if we set Stop at Block Gap, then there will be * Transfer Complete. */ if (act == WRITE) { card_info->cmpl_mask |= (WAIT_BLOCK_GAP | WAIT_TRANS_COMPLETE); sdc_reg->blk_gap_ctl |= SDHCI_STOP_AT_BLOCK_GAP_REQ; } } } else { wait_t = dev->timeout_ms * 10; length = 0; } /* Only need to wait transfer complete for DMA */ t0 = kdrv_current_t1_tick(); while (card_info->cmpl_mask && !card_info->err_sts) { if ((kdrv_current_t1_tick() - t0) > wait_t) { /* time out */ if (card_info->cmpl_mask) length = card_info->cmpl_mask; else if (card_info->err_sts) length = card_info->err_sts; goto out; } } out: if (card_info->err_sts) { if (card_info->err_sts & SDHCI_INTR_ERR_AUTOCMD) kdrv_sdc_auto_cmd_error_recovery(dev); else kdrv_sdc_error_recovery(dev); if(card_info->err_sts) { return KDRV_STATUS_SDC_RECOVERABLE_ERR; } } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_set_bus_width() set sdcard bus width * * @param[in] dev device structure * @param[in] width 1: 1bit, 4:4bits, 8:8bits * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_set_bus_width(kdrv_sdc_res_t *dev, uint8_t width) { uint8_t wdth; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; /* Setting the Bus width */ if (card_info->card_type == MEMORY_CARD_TYPE_MMC) { if (card_info->csd_mmc.spec_vers < 4) { //kmdw_dbg_printf(" MMC: Change width not allowed for version less than MMC4.1.\n"); return KDRV_STATUS_OK; } kmdw_dbg_printf("kdrv_sdc_set_bus_width=%d\n",width); /** * MMC bus_width[183] of Extended CSD. * 0=1 bit, 1=4bits, 2=8bits. */ switch (width) { case 1: wdth = 0; break; case 4: wdth = 1; break; case 8: wdth = 2; break; default: //kmdw_dbg_printf(" ERR## ... MMC: Not supported bus witdth %d.\n", width); return KDRV_STATUS_SDC_BUS_WIDTH_NOT_SUPPORT; } if (kdrv_sdc_ops_mmc_switch(dev, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, wdth)) { //kmdw_dbg_printf(" ERR## ... MMC: Set Bus width failed.\n"); return KDRV_STATUS_SDC_BUS_WIDTH_NOT_SUPPORT; } } else if (card_info->card_type == MEMORY_CARD_TYPE_SD) { /** * The Bit2 in scr shows whether the "4bit bus width(DAT0-3)" is supported. * ACMD6 command, '00'=1bit or '10'=4bit bus. */ switch (width) { case 1: if (!(card_info->scr.sd_bus_widths & SDHCI_SCR_SUPPORT_1BIT_BUS)) { //kmdw_dbg_printf(" ERR## ... SD: 1 bit width not support by this card.\n"); return KDRV_STATUS_SDC_BUS_WIDTH_NOT_SUPPORT; } wdth = SDHCI_1BIT_BUS_WIDTH; break; case 4: if (!(card_info->scr.sd_bus_widths & SDHCI_SCR_SUPPORT_4BIT_BUS)) { //kmdw_dbg_printf(" ERR## ... SD: 4 bit width not support by this card.\n"); return KDRV_STATUS_SDC_BUS_WIDTH_NOT_SUPPORT; } wdth = SDHCI_4BIT_BUS_WIDTH; break; default: //kmdw_dbg_printf(" ERR## ... SD: Not supported bus witdth %d.\n", width); return KDRV_STATUS_SDC_BUS_WIDTH_NOT_SUPPORT; } if (kdrv_sdc_ops_app_set_bus_width(dev, wdth)) { //kmdw_dbg_printf(" ERR## ... SD: Set Bus Width %d failed !\n", width); return KDRV_STATUS_SDC_BUS_WIDTH_ERR; } } sdc_reg->hcreg &= ~(SDHCI_HC_BUS_WIDTH_8BIT | SDHCI_HC_BUS_WIDTH_4BIT); switch (width) { case 1: card_info->bus_width = 1; break; case 4: sdc_reg->hcreg |= SDHCI_HC_BUS_WIDTH_4BIT; card_info->bus_width = 4; break; case 8: sdc_reg->hcreg |= SDHCI_HC_BUS_WIDTH_8BIT; card_info->bus_width = 8; break; default: kmdw_dbg_printf(" Unsupport bus width %d for HW register setting.\n", width); break; } kmdw_dbg_printf(" Set Bus width %d bit(s), Host Control Register: 0x%x.\n", width, sdc_reg->hcreg); return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_set_transfer_mode() set transfer mode */ static kdrv_status_t kdrv_sdc_set_transfer_mode(kdrv_sdc_res_t *dev, uint8_t blk_cnt_en, uint8_t auto_cmd, uint8_t dir, uint8_t multi_blk) { uint16_t mode; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; if ((dir != SDHCI_TXMODE_READ_DIRECTION) && (dir != 0)) { //kmdw_dbg_printf(" ERR## ... Transder Mode, direction value not correct.\n"); return KDRV_STATUS_SDC_TRANSFER_FAIL; } /*SDMA can not use ACMD23 */ if ((card_info->flow_set.use_dma == SDMA) && (auto_cmd == 2)) auto_cmd = 1; auto_cmd <<= 2; if ((auto_cmd != SDHCI_TXMODE_AUTOCMD12_EN) && (auto_cmd != SDHCI_TXMODE_AUTOCMD23_EN) && (auto_cmd != 0)) { //kmdw_dbg_printf(" ERR## ... Transder Mode, auto cmd value not correct.\n"); return KDRV_STATUS_SDC_TRANSFER_FAIL; } mode = (auto_cmd | dir); if ((card_info->flow_set.use_dma == ADMA) || (card_info->flow_set.use_dma == SDMA)) mode |= SDHCI_TXMODE_DMA_EN; if (blk_cnt_en) mode |= SDHCI_TXMODE_BLKCNT_EN; if (multi_blk) mode |= SDHCI_TXMODE_MULTI_SEL; sdc_reg->txmode = mode; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_set_bus_speed_mode() set bus speed * * @param[in] dev device structure * @param[in] speed bus speed * 0x0 : Default/SDR12/Normal Speed * 0x1 : SDR25/High Speed * 0x2 : SDR50 * 0x3 : SDR104 * 0x4 : DDR50 * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_set_bus_speed_mode(kdrv_sdc_res_t *dev, uint8_t speed) { uint32_t err, i; kdrv_status_t rstatus; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; kdrv_sdc_sd_host_t *host = dev->host; if (speed > 4) { kmdw_dbg_printf(" ERR## ... Bus Speed Mode value %d error.\n", speed); return KDRV_STATUS_SDC_SPEED_MOD_ERR; } if (card_info->card_type == MEMORY_CARD_TYPE_SD) { if (card_info->scr.sd_spec == 0) { /* Version 1.01 Card does not support CMD6 */ speed = 0; goto out; } /* Check Group 1 function support */ //kmdw_dbg_printf(" Checking function Group 1 (Bus Speed Mode) ..."); for (i = 0; i < 5; i++) { if ((rstatus = kdrv_sdc_ops_sd_switch(dev, 0, 0, i, &card_info->switch_sts[0])) != KDRV_STATUS_OK) { kmdw_dbg_printf(" ERR## ... Problem reading Switch function(Bus Speed Mode).\n"); return rstatus; } if (card_info->switch_sts[13] & (1 << i)) { card_info->bs_mode |= (1 << i); } } if (!(sdc_reg->host_ctl2 & SDHCI_18V_SIGNAL) && (speed > 1)) { kmdw_dbg_printf(" No 1.8V Signaling Can not set speed more than 1"); return KDRV_STATUS_ERROR; } /* Check function support */ if (!(card_info->bs_mode & (1 << speed))) { //kmdw_dbg_printf(" ERR## ... %s not support by Card.\n", SDC_ShowTransferSpeed(speed)); return KDRV_STATUS_SDC_VOL_ERR; } //kdrv_sdc_set_sd_clock(25 * 1000000); /* Read it back for confirmation */ err = kdrv_sdc_ops_sd_switch(dev, 1, 0, speed, &card_info->switch_sts[0]); if (err || ((card_info->switch_sts[16] & 0xF) != speed)) { kmdw_dbg_printf(" ERR## ... Problem switching(Group 1) card into %d mode!\n", speed); return KDRV_STATUS_ERROR; } } else if (card_info->card_type == MEMORY_CARD_TYPE_MMC) { if (card_info->csd_mmc.spec_vers < 4) { speed = 0; kmdw_dbg_printf(" MMC: Change speed not allowed for version less than MMC4.1.\n"); goto out; } /* * MMC Card only has Default and Hight speed. */ if (speed > 1) { kmdw_dbg_printf(" ERR## ... Bus Speed Mode value %d error.\n", speed); } if (kdrv_sdc_ops_mmc_switch(dev, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, speed)) { kmdw_dbg_printf(" ERR## ... MMC: Problem switching card into %d mode!\n", speed); return KDRV_STATUS_ERROR; } // Insure that the state has returned to "Transfer State" according to P.43 in MMC spec. if (kdrv_sdc_wait_for_state(dev, CUR_STATE_TRAN, 2000)) return KDRV_STATUS_ERROR; } out: /* SDR mode only valid for 1.8v IO signal */ if (sdc_reg->host_ctl2 & SDHCI_18V_SIGNAL) { sdc_reg->host_ctl2 &= ~0x7; sdc_reg->host_ctl2 |= speed; } else { if (speed == 0) sdc_reg->hcreg &= ~(uint8_t) 0x4; else if (speed == 1) sdc_reg->hcreg |= 0x4; else { kmdw_dbg_printf(" No 1.8V Signaling Can not set speed more than 1.\n"); return KDRV_STATUS_ERROR; } } card_info->speed = (kdrv_sdc_bus_speed_e) speed; if (speed < 4) { if (speed < 3) { card_info->max_dtr = 25000000 << speed; } else { /* current controller stable @ max 130 MHz */ card_info->max_dtr = host->max_clk; } } else card_info->max_dtr = 50000000; kmdw_dbg_printf("Set Switch function(Bus Speed Mode = %d), Host Control Register: 0x%x, 0x%04x.\n", speed, sdc_reg->hcreg, sdc_reg->host_ctl2); return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_execute_tuning() tuning for clock setting */ static kdrv_status_t kdrv_sdc_execute_tuning(kdrv_sdc_res_t *dev, uint32_t try) { kdrv_sdc_transfer_type_e dma; uint8_t delay, cnt, hndshk; clock_t t0; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; if (!((sdc_reg->host_ctl2 & SDHCI_SDR104) && (sdc_reg->host_ctl2 & SDHCI_18V_SIGNAL))) { kmdw_dbg_printf(" ERR## ... Tuning only require for SDR104 mode.\n"); return KDRV_STATUS_ERROR; } /* Must tune 4 data lines */ if (card_info->bus_width != 4) kdrv_sdc_set_bus_width(dev,4); /* Prevent using DMA when do tuning */ dma = card_info->flow_set.use_dma; card_info->flow_set.use_dma = PIO; hndshk = sdc_reg->dma_hndshk & 1; sdc_reg->dma_hndshk = 0; cnt = 0; retune: delay = 0; sdc_reg->vendor_reg3 &= ~((uint32_t)0xff << 24); sdc_reg->vendor_reg3 = 0x00000804 | (try << 24); sdc_reg->softrst |= SDHCI_SOFTRST_DAT; /* Set Execute Tuning at Host Control2 Register */ sdc_reg->host_ctl2 |= SDHCI_EXECUTE_TUNING; /* Issue CMD19 repeatedly until Execute Tuning is zero. * Abort the loop if reached 40 times or 150 ms */ do { if (kdrv_sdc_ops_send_tune_block(dev)) break; /* Wait until Buffer Read Ready */ t0 = kdrv_current_t1_tick(); do { if ((kdrv_current_t1_tick() - t0 > 100)) { kmdw_dbg_printf(" ERR##: Tuning wait for BUFFER READ READY timeout.\n"); //sdc_reg->softrst |= (SDHCI_SOFTRST_CMD | SDHCI_SOFTRST_DAT); //while (sdc_reg->softrst & (SDHCI_SOFTRST_CMD | SDHCI_SOFTRST_DAT)); break; } } while (!(sdc_reg->intr_sts & SDHCI_INTR_STS_BUFF_READ_READY)); sdc_reg->intr_sts &= SDHCI_INTR_STS_BUFF_READ_READY; } while (sdc_reg->host_ctl2 & SDHCI_EXECUTE_TUNING); /* Check Sampling Clock Select */ if (sdc_reg->host_ctl2 & SDHCI_SMPL_CLCK_SELECT) { /* FPGA only */ delay = (sdc_reg->vendor_reg3 >> 16) & 0x1F; kmdw_dbg_printf("Tuning Complete(0x%08x), SD Delay : 0x%x.\n", sdc_reg->vendor_reg4, delay); if (!(sdc_reg->vendor_reg4 & (1 << delay))) { kmdw_dbg_printf("SD Delay does not match tuning record(0x%08x).\n", sdc_reg->vendor_reg4); if (cnt++ < 3) { goto retune; } else { kmdw_dbg_printf("Re-Tuning Failed.\n"); card_info->flow_set.use_dma = dma; return KDRV_STATUS_ERROR; } } } else { kmdw_dbg_printf("Tuning Failed.\n"); card_info->flow_set.use_dma = dma; return KDRV_STATUS_ERROR; } card_info->flow_set.use_dma = dma; sdc_reg->dma_hndshk |= hndshk; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_set_sd_clock() set sdc clcok * * @param[in] dev device structure * @param[in] clock * @return N/A */ static void kdrv_sdc_set_sd_clock(kdrv_sdc_res_t *dev, uint32_t clock) { int div, timeout, s_clk; uint16_t clk; uint32_t try; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; kdrv_sdc_sd_host_t *host = dev->host; sdc_reg->clk_ctl = 0; if (card_info->max_dtr < clock) kmdw_dbg_printf(" WARN## ... Set clock(%d Hz) larger than Max Rate(%d Hz).\n", clock, card_info->max_dtr); if (clock == 0) goto out; if (host->max_clk <= clock) div =0; else { for (div = 1; div < 0x3FF; div++) { if ((host->max_clk / (2 * div)) <= clock) break; } } //div=3; kmdw_dbg_printf(" SDLK Freq select, Div: %d, Clock: (%d/%d) Hz, ", div, (host->max_clk / div), clock); clk = div << SDHCI_CLK_CTRL_LOW_CLK_SEL_SHIFT; clk |= SDHCI_CLK_CTRL_INTERNALCLK_EN; kmdw_dbg_printf("sdc_reg->clk_ctl: 0x%x\n", sdc_reg->clk_ctl); sdc_reg->clk_ctl = clk; /* Wait max 10 ms */ timeout = 10; while (!(sdc_reg->clk_ctl & SDHCI_CLK_CTRL_INTERNALCLK_STABLE)) { if (timeout == 0) { //fail(" ERR## ... Internal clock never estabilised.\n"); kmdw_dbg_printf(" ERR## ... Internal clock never estabilised.\n"); break; } timeout--; kdrv_delay_us(1000); } clk |= SDHCI_CLK_CTRL_SDCLK_EN; sdc_reg->clk_ctl = clk; kmdw_dbg_printf("div=0x%x, clk=0x%x\n",div, clk); /* Make sure to use pulse latching when run below 50 MHz */ /* SDR104 use multiphase DLL latching, others use pulse latching */ if (!div) div = 1; else div *= 2; s_clk = host->max_clk / div; if (s_clk < 100000000) { sdc_reg->vendor_reg0 |= 1; kmdw_dbg_printf("sdc_reg->vendor_reg0=0x%x\n",sdc_reg->vendor_reg0); /* Adjust the Pulse Latch Offset if div > 0 */ if (div > 1) sdc_reg->vendor_reg0 |= 0x200; //legend: pulse-latching } else { /* Sampling tuning for SDR104 and SDR50 if required */ sdc_reg->vendor_reg0 &= ~1; if (s_clk == 100000000) try = 16; else { s_clk /= 1000000; try = ((8 * s_clk) / 25) - 16; } kdrv_sdc_execute_tuning(dev, try); } out: host->clock = clock; kmdw_dbg_printf(" Clock Control Register: 0x%04x.\n", sdc_reg->clk_ctl); } /** * @brief kdrv_sdc_set_power() set power voltage * @param[in] dev device structure * @param[in] power power level bit poistion * OCR power bit position * 7: low voltage * 17: 2.9~3.0 * 18: 3.0~3.1 * 20: 3.2~3.3 * 21: 3.3~3.4 * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_set_power(kdrv_sdc_res_t *dev, int16_t power) { uint8_t pwr; kdrv_status_t err = KDRV_STATUS_OK; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; kdrv_sdc_sd_host_t *host = dev->host; if (power == (int16_t) - 1) { sdc_reg->pwr_ctl = 0; err = KDRV_STATUS_SDC_PWR_SET_ERR; goto out; } /* * Spec says that we should clear the power reg before setting * a new value. */ sdc_reg->pwr_ctl = 0; pwr = SDHCI_POWER_ON; switch (power) { case 7: pwr |= SDHCI_POWER_180; break; case 17: case 18: pwr |= SDHCI_POWER_300; break; case 20: case 21: pwr |= SDHCI_POWER_330; break; default: err = KDRV_STATUS_SDC_PWR_SET_ERR; kmdw_dbg_printf(" ERR## ... Voltage value not correct.\n"); } sdc_reg->pwr_ctl = pwr; out: host->power = power; kmdw_dbg_printf(" Power Control Register: 0x%01x.\n", sdc_reg->pwr_ctl); return err; } /** * @brief kdrv_sdc_check_card_insert() check card insert * @param[in] dev device structure * @return kdrv_status_t * kl520 do not havw cd/wp pin, so it will always return pin inserted. */ static kdrv_status_t kdrv_sdc_check_card_insert(kdrv_sdc_res_t *dev) { volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; /* * kl520 does not have CD(card detect) and WP(card protect pin), so it will * always return inserted status */ card_info->card_insert = 1; return KDRV_STATUS_OK; } /** * SDMA: line_bound is Buffer Boundary value. * ADMA: line_boud is bytes per descriptor line. */ static void kdrv_sdc_set_transfer_type(kdrv_sdc_res_t *dev, kdrv_sdc_transfer_type_e type, uint32_t line_bound, uint8_t ran_mode) { volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; sdc_reg->hcreg &= ~(uint8_t) (0x3 << 3); sdc_reg->dma_hndshk &= ~1; card_info->flow_set.use_dma = type; card_info->flow_set.line_bound = line_bound; card_info->flow_set.adma2rand = ran_mode; if (type == PIO) { sdc_reg->intr_sig_en = SDHCI_INTR_SIGN_EN_PIO; } else if (type == SDMA) { sdma_bound_mask = (1 << (card_info->flow_set.line_bound + 12)) - 1; sdc_reg->intr_sig_en = SDHCI_INTR_SIGN_EN_SDMA; } else if (type == ADMA) { sdc_reg->adma_addr = (uint64_t)&sdc_adma2_desc_table;//ADMA2_DESC_TABLE; sdc_reg->hcreg |= (uint8_t) SDHCI_HC_USE_ADMA2; sdc_reg->intr_sig_en = SDHCI_INTR_SIGN_EN_ADMA; } else { sdc_reg->dma_hndshk |= 1; } sdc_reg->err_sig_en = SDHCI_ERR_SIG_EN_ALL; } static kdrv_status_t kdrv_sdc_fill_adma_desc_table(kdrv_sdc_res_t *dev, uint32_t total_data, uint8_t *data_addr) { uint8_t act, tmp, adma2_random; uint32_t byte_cnt, i, ran, bytes_per_line; uint8_t *buff; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; kdrv_sdc_adma2desc_table_t *ptr = (kdrv_sdc_adma2desc_table_t *) &sdc_adma2_desc_table;//ADMA2_DESC_TABLE; kdrv_sdc_adma2desc_table_t *tptr; if (total_data < 4) { kmdw_dbg_printf("Data less than 4 bytes !!\n"); return KDRV_STATUS_ERROR; } adma2_random = card_info->flow_set.adma2rand; if (!card_info->flow_set.line_bound) bytes_per_line = 65536; else bytes_per_line = card_info->flow_set.line_bound; if (!adma2_random) { act = ADMA2_TRAN; } buff = (uint8_t *) data_addr; i = 0; do { /* Random Mode = 1, we only random the length inside the descriptor */ /* Random Mode = 2, we random the action and fix length inside the descriptor */ /* Random Mode = 3, we random the action and length inside the descriptor */ if ((adma2_random > 1) && (i < (ADMA2_NUM_OF_LINES - 2))) { ran = rand(); /* Occupy percentage to prevent too many Noop and reserved */ tmp = ran & 0xF; if (tmp < 8) act = ADMA2_TRAN; else if (tmp < 13) act = ADMA2_LINK; else act = ADMA2_NOP; } else { act = ADMA2_TRAN; } tptr = ptr + i; memset(tptr, 0, sizeof(kdrv_sdc_adma2desc_table_t)); switch (act) { case ADMA2_TRAN: if ((total_data > 256) && (i < (ADMA2_NUM_OF_LINES - 2))) { if (!adma2_random || (adma2_random == 2)) /* Must be 4 bytes alignment */ if (total_data < bytes_per_line) byte_cnt = total_data; else byte_cnt = bytes_per_line; else byte_cnt = (ran % total_data) & 0xfffc; } else { if (total_data > 0xFFFF) { kmdw_dbg_printf(" ERR## ... Not enough descriptor to fill.\n"); tptr->attr |= ADMA2_ENTRY_END; return KDRV_STATUS_ERROR; } byte_cnt = total_data; } if (byte_cnt < 4) //bad result from randGen() byte_cnt = 4; tptr->addr = (uint32_t) buff;//CVS_working_folder tptr->attr = ADMA2_TRAN | ADMA2_ENTRY_VALID; tptr->lgth = byte_cnt; buff += byte_cnt; total_data -= byte_cnt; i++; break; case ADMA2_LINK: tmp = ran & 0x7; i += tmp; if (i > (ADMA2_NUM_OF_LINES - 2)) i = ADMA2_NUM_OF_LINES - 2; tptr->addr = (uint32_t) ptr + i;//CVS_working_folder tptr->attr = ADMA2_LINK | ADMA2_ENTRY_VALID; break; /* Do not execute this line, go to next line */ case ADMA2_NOP: case ADMA2_SET: default: tptr->attr = ADMA2_NOP | ADMA2_ENTRY_VALID; i++; break; } } while (total_data > 0); if (dev->adma2_insert_nop) { tptr = ptr + i; memset(tptr, 0, sizeof(kdrv_sdc_adma2desc_table_t)); } tptr->attr |= (ADMA2_ENTRY_VALID | ADMA2_ENTRY_END | dev->adma2_use_interrupt); return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_send_abort_command() send abort command */ static kdrv_status_t kdrv_sdc_send_abort_command(kdrv_sdc_res_t *dev) { uint16_t val; clock_t t0; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; card_info->err_sts = 0; card_info->cmpl_mask = (WAIT_CMD_COMPLETE | WAIT_TRANS_COMPLETE); sdc_reg->cmd_argu = 0; val = ((SDHCI_CMD12_STOP_TRANS & 0x3f) << 8) | ((SDHCI_CMD_TYPE_ABORT & 0x3) << 6) | ((SDHCI_CMD_RTYPE_R1BR5B & 0x1F)); sdc_reg->cmd_reg = val; t0 = kdrv_current_t1_tick(); while (card_info->cmpl_mask) { /* 1 secs */ if ((kdrv_current_t1_tick() - t0) > (dev->timeout_ms << 1)) { return KDRV_STATUS_SDC_TIMEOUT; } } // Reset the Data and Cmd line due to the None-auto CMD12. sdc_reg->softrst |= (SDHCI_SOFTRST_CMD | SDHCI_SOFTRST_DAT); while (sdc_reg->softrst & (SDHCI_SOFTRST_CMD | SDHCI_SOFTRST_DAT)) ; if (card_info->err_sts != 0) { return KDRV_STATUS_SDC_ABORT_ERR; } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_wait_for_state() wait state function */ kdrv_status_t kdrv_sdc_wait_for_state(kdrv_sdc_res_t *dev, uint32_t state, uint32_t ms) { clock_t t0; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; t0 = kdrv_current_t1_tick(); do { if (kdrv_sdc_ops_send_card_status(dev)) { kmdw_dbg_printf(" ERR## ... Send Card Status Failed.\n"); return KDRV_STATUS_ERROR; } if ((kdrv_current_t1_tick() - t0) > ms) { kmdw_dbg_printf(" ERR## ... Card Status not return to define(%d) state.\n", state); return KDRV_STATUS_ERROR; } kdrv_delay_us(3000); } while (((card_info->resp_lo >> 9) & 0xF) != state); return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_error_recovery(), try abort and recovery the sdc status * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_error_recovery(kdrv_sdc_res_t *dev) { uint8_t delayCount = 10; // more than 40us, The max. freq. for SD is 50MHz. volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; //kdrv_sdc_print_err_msg(dev, card_info->err_sts); /* Step 8 and Step 9 to save previous error status and * clear error interrupt signal status. This are already * done at IRQ handler. */ if (err_recover) { /* CMD12 */ /* Step 10: Issue Abort CMD */ kdrv_sdc_send_abort_command(dev); /* Step 11: Check Command Inhibit DAT and CMD */ while (sdc_reg->present_state & (SDHCI_STS_CMD_INHIBIT | SDHCI_STS_CMD_DAT_INHIBIT)) ; /* Step 12 */ if (card_info->err_sts & SDHCI_INTR_ERR_CMD_LINE) { //kmdw_dbg_printf("Non-recoverable Error:CMD Line Error\n"); return KDRV_STATUS_SDC_RECOVERABLE_ERR; } /* Step 13 */ if (card_info->err_sts & SDHCI_INTR_ERR_DATA_TIMEOUT) { //kmdw_dbg_printf("Non-recoverable Error:Data Line Timeout\n"); return KDRV_STATUS_SDC_RECOVERABLE_ERR; } /* Step 14 */ while (delayCount > 0) { delayCount--; } /* Step 15 */ if (sdc_reg->present_state & SDHCI_STS_DAT_LINE_LEVEL) { /* Step 17 */ //kmdw_dbg_printf("Recoverable Error\n"); return KDRV_STATUS_SDC_RECOVERABLE_ERR; } } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_auto_cmd_error_recovery(), auto command recovery * SD card related operations */ static kdrv_status_t kdrv_sdc_auto_cmd_error_recovery(kdrv_sdc_res_t *dev) { uint8_t pcmd; kdrv_status_t err; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; //kmdw_dbg_printf("Err: ACMD12 !!\n"); /* Step 1: Check Auto CMD12 not executed status. * Host Controller cannot issue CMD12 to stop multiple * block transfer due to some error. */ if (card_info->auto_err & SDHCI_AUTOCMD12_ERR_NOT_EXECUTED) { pcmd = 1; /* Step 2: Wait for Error Interrupt Recovery for CMD_wo_DAT. */ err = kdrv_sdc_error_recovery(dev); if (err != KDRV_STATUS_SDC_RECOVERABLE_ERR) return err; } else { pcmd = 0; /* Step 6: Set Software Reset for CMD line (CR) */ sdc_reg->softrst |= 0x2; /* Step 7: Check DR */ while (sdc_reg->softrst & 0x2) ; } /* Step 4 & 8: Issue CMD12 */ if (kdrv_sdc_send_abort_command(dev)) return KDRV_STATUS_SDC_ABORT_ERR; if (kdrv_sdc_wait_for_state(dev,CUR_STATE_TRAN, 1000)) { //kmdw_dbg_printf("ERR## ... Get Card Status failed(ACMD12 Error Recovery) !\n"); return KDRV_STATUS_SDC_RECOVERABLE_ERR; } /* Step 5 & 9: Check the result of CMD12 */ if ((card_info->err_sts & 0xF) != 0) { /* Step 16 */ //kmdw_dbg_printf("non-recoverable Error\n"); return KDRV_STATUS_SDC_RECOVERABLE_ERR; } if (pcmd == 1 && !(card_info->err_sts & 0x10)) { /* Step 17 */ //kmdw_dbg_printf("Error has occured in both CMD_wo_DAT, but not in the SD memory transfer.\n"); } else { /* Step 11 & 14 */ sdc_reg->softrst |= 0x4; /* Step 12 & 15 */ while (sdc_reg->softrst & 0x4) ; /* Step 10: CMD12 not issued */ if (!(card_info->auto_err & SDHCI_AUTOCMD12_ERR_CMD_NOT_ISSUE)) { if (pcmd) { /* Step 18 */ //kmdw_dbg_printf("Error has occured in CMD_wo_DAT, and also in the SD memory transfer.\n"); } else { /* Step 19 */ //kmdw_dbg_printf("Error did not occur in CMD_wo_DAT, but in the SD memory transfer.\n"); } } else { /* Step 20 */ // kmdw_dbg_printf // ("CMD_wo_DAT has not been issued, and an error errored in the SD memory transfer.\n"); } } return KDRV_STATUS_SDC_RECOVERABLE_ERR; } /** * @brief kdrv_sdc_read_scr() read scr information * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_read_scr(kdrv_sdc_res_t *dev) { volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; if (card_info->card_type != MEMORY_CARD_TYPE_SD) return KDRV_STATUS_SDC_READ_FAIL; memset((void *)&card_info->scr, 0, sizeof(kdrv_sdc_sd_scr_t)); if (kdrv_sdc_ops_app_send_scr(dev)) { return KDRV_STATUS_SDC_READ_FAIL; } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_read_ext_csd read ext_csd information * * @param[in] dev structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_read_ext_csd(kdrv_sdc_res_t *dev) { volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; if (card_info->card_type != MEMORY_CARD_TYPE_MMC) return KDRV_STATUS_SDC_CARD_TYPE_ERR; if (card_info->card_type == MEMORY_CARD_TYPE_MMC && card_info->csd_mmc.spec_vers < 4) { kmdw_dbg_printf(" Commmand 8 is not supported in this MMC system spec.\n"); goto fail; } if (kdrv_sdc_ops_send_ext_csd(dev)) { kmdw_dbg_printf(" ERR## ... MMC: Get EXT-CSD from card is failed\n"); goto fail; } if (card_info->ext_csd_mmc.cardtype & 0xE) card_info->max_dtr = 52000000; else if (card_info->ext_csd_mmc.cardtype & 1) card_info->max_dtr = 26000000; else kmdw_dbg_printf(" WARN## ... Unknown Max Speed at EXT-CSD.\n"); if (card_info->card_type == MEMORY_CARD_TYPE_MMC) { card_info->num_of_boot_blks = (card_info->ext_csd_mmc.reserved6 << 8 | card_info->ext_csd_mmc.boot_size_mult) * 128 * 1024; card_info->num_of_boot_blks >>= 9; } fail: /* The block number of MMC card, which capacity is more than 2GB, shall be fetched from Ext-CSD. */ if (card_info->ext_csd_mmc.ext_csd_rev >= 2) { kmdw_dbg_printf(" MMC EXT CSD Version %d\n", card_info->ext_csd_mmc.ext_csd_rev); if (card_info->ext_csd_mmc.sec_count) { card_info->num_of_blks = card_info->ext_csd_mmc.sec_count; card_info->blk_addr = 1; } kmdw_dbg_printf("Ext-CSD: Block number %d\n", card_info->num_of_blks, card_info->max_dtr); } else { kmdw_dbg_printf("MMC CSD Version 1.%d\n", card_info->csd_mmc.csd_structure); card_info->num_of_blks = (card_info->csd_mmc.c_size + 1) << (card_info->csd_mmc.c_size_mult + 2); /* Change to 512 bytes unit */ card_info->num_of_blks = card_info->num_of_blks << (card_info->csd_mmc.read_bl_len - 9); card_info->blk_addr = 0; kmdw_dbg_printf("CSD: Block number %d\n", card_info->num_of_blks, card_info->max_dtr); } /* Index start from zero */ card_info->num_of_blks -= 1; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_scan_card() scan sd/mmc memory card * * @param[in] dev device structure * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_scan_cards(kdrv_sdc_res_t *dev) { uint32_t resp; uint32_t ocr, s18r; kdrv_status_t err; uint8_t F8 = 0; uint16_t bit_pos; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; kdrv_sdc_sd_host_t *host = dev->host; /* * It's not necessary to save from error_recovery function until the card is in transfer state. * Because some commands are not supported in MMC/SD/SDIO in the mix-initiation. * Error_recover function may destoried the initial procedure. */ err_recover = 0; if (card_info->already_init == true && card_info->card_type == SDIO_TYPE_CARD) { /* CMD 52: Reset the SDIO only card.(Write the specified bit after fetching the content.) */ kdrv_sdc_send_command(dev, SDHCI_CMD52_IO_RW_DIRECT, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 1, ((SD_CMD52_RW_in_R) | (SD_CMD52_no_RAW) | SD_CMD52_FUNC(0) | SD_CMD52_Reg_Addr(0x06))); resp = (uint32_t) sdc_reg->cmd_resplo; resp = resp & 0xF; resp = resp | 0x8; // Setting the reset bit in 6th byte of function 0 kdrv_sdc_send_command(dev, SDHCI_CMD52_IO_RW_DIRECT, SDHCI_CMD_TYPE_NORMAL, 0, SDHCI_CMD_RTYPE_R1R5R6R7, 1, (SD_CMD52_RW_in_W | SD_CMD52_RAW | SD_CMD52_FUNC(0) | SD_CMD52_Reg_Addr(0x06) | resp)); } else { s18r = (sdc_reg->cap_reg2 & (SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_DDR50)) ? 1 : 0; /* CMD0, reset the device to idle state */ if (kdrv_sdc_ops_go_idle_state(dev, 0)) { return KDRV_STATUS_ERROR; } card_info->card_type = CARD_TYPE_UNKNOWN; /* CMD8 of SD card, F8 is only referenced by SD and SDIO flow */ err = kdrv_sdc_ops_send_if_cond(dev, ((host->ocr_avail & 0xFF8000) != 0) << 8 | 0xAA); F8 = err ? 0 : 1; /* * ...then normal SD... ACMD41 */ err = kdrv_sdc_ops_send_app_op_cond(dev, 0, &ocr); if (!err) { card_info->card_type = MEMORY_CARD_TYPE_SD; goto set_voltage; } /* * ...and finally MMC. CMD1 */ err = kdrv_sdc_ops_send_op_cond(dev, 0, &ocr); if (!err) { card_info->card_type = MEMORY_CARD_TYPE_MMC; goto set_voltage; } } set_voltage: if (card_info->card_type == CARD_TYPE_UNKNOWN) { kmdw_dbg_printf("No Supported Card found !\n"); return KDRV_STATUS_SDC_CARD_TYPE_ERR; } if (ocr & 0x7F) { kmdw_dbg_printf("Card claims to support voltages below the defined range. These will be ignored.\n"); ocr &= ~0x7F; } if (ocr & (1 << 7)) { kmdw_dbg_printf(" WARN## ... SD card claims to support the incompletely defined 'low voltage range'." "This will be ignored.\n"); ocr &= ~(1 << 7); } /* Mask off any voltage we do not support */ ocr &= host->ocr_avail; /* Select the lowest voltage */ for (bit_pos = 0; bit_pos < 24; bit_pos++) { if (ocr & (1 << bit_pos)) break; } if (bit_pos >= 24) { kmdw_dbg_printf(" ERR## ... Can not find correct voltage value.\n"); return KDRV_STATUS_SDC_VOL_ERR; } kdrv_sdc_set_power(dev, bit_pos); ocr |= (3 << bit_pos); if (card_info->card_type == MEMORY_CARD_TYPE_MMC) { /* Bit 30 indicate Host support high capacity */ err = kdrv_sdc_ops_send_op_cond(dev, (ocr | (1 << 30)), &card_info->ocr); if (err) { kmdw_dbg_printf("MMC card init failed ... CMD1 !\n'"); return KDRV_STATUS_SDC_INIT_ERR; } if (((card_info->ocr >> 29) & 3) == 2) { card_info->blk_addr = 1; kmdw_dbg_printf(" Found MMC Card .... sector mode \n"); } else { card_info->blk_addr = 0; kmdw_dbg_printf(" Found MMC Card .... byte mode \n"); } } else { if (card_info->card_type == MEMORY_CARD_TYPE_SD) { if (F8 == 1) { ocr |= ((s18r << 24) | (1 << 30)); } if (kdrv_sdc_ops_send_app_op_cond(dev, ocr, &card_info->ocr)) { kmdw_dbg_printf(" SD Card init failed ... ACMD41\n"); return KDRV_STATUS_SDC_INIT_ERR; } if (card_info->ocr & (1 << 30)) { kmdw_dbg_printf(" Found SD Memory Card (SDHC or SDXC).\n"); } else { kmdw_dbg_printf(" Found SD Memory Card Version 1.X.\n"); } /* Accept IO Signal Voltage switch to 1.8v */ } } if (card_info->card_type != SDIO_TYPE_CARD) { // Commented by MikeYeh 081127 /* Sending the CMD2 to all card to get each CID number */ /* CMD 2 */ err = kdrv_sdc_ops_all_send_cid(dev); if (err) return err; } card_info->rca = (card_info->card_type != MEMORY_CARD_TYPE_MMC) ? 0 : 2; if ((err = kdrv_sdc_ops_send_rca(dev)) != KDRV_STATUS_OK) { kmdw_dbg_printf("ERR## Card init failed ... CMD3 !\n"); return err; } card_info->resp_lo = (uint32_t) (sdc_reg->cmd_resplo); if ((card_info->card_type == MEMORY_CARD_TYPE_SD) || (card_info->card_type == MEMORY_CARD_TYPE_MMC)) { uint32_t e, m; if ((err = kdrv_sdc_ops_send_csd(dev)) != KDRV_STATUS_OK) { kmdw_dbg_printf("ERR## Card init failed ... CMD9 !\n"); return err; } wr_bl_len = rd_bl_len = 9; if (card_info->card_type == MEMORY_CARD_TYPE_SD) { if ((card_info->csd_hi >> 54) == 0) { card_info->num_of_blks = (card_info->csd_ver1.c_size + 1) << (card_info->csd_ver1.c_size_mult + 2); e = card_info->csd_ver1.tran_speed & 7; m = (card_info->csd_ver1.tran_speed >> 3) & 0xF; card_info->blk_addr = 0; } else if ((card_info->csd_hi >> 54) == 1) { rd_bl_len = wr_bl_len = 9; card_info->num_of_blks = (card_info->csd_ver2.c_size + 1) << 10; e = card_info->csd_ver2.tran_speed & 7; m = (card_info->csd_ver2.tran_speed >> 3) & 0xF; card_info->blk_addr = 1; } else { card_info->num_of_blks = 0; return KDRV_STATUS_ERROR; } card_info->max_dtr = tran_exp[e] * tran_mant[m]; /* Index start from zero */ card_info->num_of_blks -= 1; } if ((err = kdrv_sdc_ops_send_card_status(dev)) != KDRV_STATUS_OK) { kmdw_dbg_printf("ERR## Get Card Status Failed after CMD9 !\n"); return err; } } /* Commented by MikeYeh 081127 */ /* The following checks whether the card state is in standby or not */ if ((((card_info->resp_lo >> 9) & 0xF) == CUR_STATE_STBY) || card_info->card_type == SDIO_TYPE_CARD) { if (kdrv_sdc_ops_select_card(dev)) { kmdw_dbg_printf("ERR## Card init failed ... CMD7 !\n"); return KDRV_STATUS_ERROR; } } else { kmdw_dbg_printf("Initialization is failed due to state changing from stand-by to transfer\n"); return KDRV_STATUS_ERROR; } /* enable error recovery */ err_recover = 0; if (card_info->card_type != SDIO_TYPE_CARD) { if (kdrv_sdc_ops_send_card_status(dev)) { kmdw_dbg_printf("ERR## Get Card Status Failed (Init) !\n"); return KDRV_STATUS_ERROR; } } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_prepare_data() prepare data */ static kdrv_status_t kdrv_sdc_prepare_data(kdrv_sdc_res_t *dev,uint32_t blk_cnt, uint16_t blk_sz, uint32_t buff_addr, kdrv_sdc_transfer_act_e act) { uint32_t bound, length; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; sdc_reg->blk_size = blk_sz; if (!dev->infinite_mode) /* Block Count Reg = Desired Blocks */ sdc_reg->blk_cnt = blk_cnt; else if (dev->infinite_mode == INFINITE_MODE_1) /* Block Count Reg = 2 * Desired Blocks */ sdc_reg->blk_cnt = blk_cnt << 1; else if (dev->infinite_mode == INFINITE_MODE_2) /* Block Count Reg = 0 */ sdc_reg->blk_cnt = 0; if (sdc_reg->txmode & SDHCI_TXMODE_AUTOCMD23_EN) sdc_reg->sdma_addr = blk_cnt; card_info->cmpl_mask = WAIT_TRANS_COMPLETE; //kmdw_dbg_printf("card_info->cmpl_mask=%x\n",card_info->cmpl_mask); if (card_info->flow_set.use_dma == SDMA) { sdc_reg->sdma_addr = buff_addr; sdc_reg->blk_size |= (card_info->flow_set.line_bound << 12); length = blk_cnt * blk_sz; bound = sdma_bound_mask + 1; /* "Infinite transfer" Or "buff_addr + length cross the SDMA boundary", Wait for DMA interrupt, no Transfer Complete interrupt */ if ((dev->infinite_mode && (sdc_reg->txmode & SDHCI_TXMODE_MULTI_SEL)) || ((buff_addr + length) > ((buff_addr & ~sdma_bound_mask) + bound)) ) { card_info->cmpl_mask &= ~WAIT_TRANS_COMPLETE; card_info->cmpl_mask |= WAIT_DMA_INTR; } } else if (card_info->flow_set.use_dma == ADMA) { if (kdrv_sdc_fill_adma_desc_table(dev, blk_cnt * blk_sz, (uint8_t*)buff_addr)) return KDRV_STATUS_ERROR; sdc_reg->adma_addr = (uint32_t) &sdc_adma2_desc_table;//CPU_TO_AHB_ADDRSPACE(ADMA2_DESC_TABLE); if (dev->adma2_use_interrupt) card_info->cmpl_mask |= WAIT_DMA_INTR; } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_send_data_command() write data to sd/emmc memory card * * @param[in] dev device structure * @param[in] start_addr address for read * @param[in] blkcnt block count * @param[in] blksz block size * @param[in] buf write buffer * @return kdrv_staus */ static kdrv_status_t kdrv_sdc_send_data_command(kdrv_sdc_res_t *dev, kdrv_sdc_transfer_act_e act, uint32_t start_addr, uint32_t blkcnt, uint32_t blksz, uint32_t *buf) { uint8_t blk_cnt_en, auto_cmd, multi_blk, cmd_idx; kdrv_status_t err; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; /* set Tx mode */ if (blkcnt > 1 || dev->infinite_mode) { /* Infinite Mode can not use Auto CMD12/CMD23 */ auto_cmd = (dev->infinite_mode) ? 0 : card_info->flow_set.auto_cmd; multi_blk = 1; if (dev->infinite_mode) { /* For infinite transfer test, Disable the Block Count register */ blk_cnt_en = 0; } else if (blkcnt > 65535) { /* Block Count register limits the maximum of 65535 block transfer. */ if (card_info->flow_set.use_dma == ADMA) blk_cnt_en = 0; else { kmdw_dbg_printf(" Non-ADMA transfer can not larger than 65535 blocks.\n"); return KDRV_STATUS_ERROR; } } else { blk_cnt_en = 1; } } else multi_blk = auto_cmd = blk_cnt_en = 0; if ((err = kdrv_sdc_set_transfer_mode(dev, blk_cnt_en, auto_cmd, (act == READ) ? SDHCI_TXMODE_READ_DIRECTION : SDHCI_TXMODE_WRITE_DIRECTION, multi_blk))!= KDRV_STATUS_OK) return err; if ((err = kdrv_sdc_prepare_data(dev, blkcnt, (1 << blksz), (uint32_t)buf, act)) != KDRV_STATUS_OK) return err; if (!card_info->blk_addr) start_addr = start_addr * (1 << blksz); /* Read : Single block use CMD17 and multi block uses CMD18 */ /* Write : Single block uses CMD24 and multi block uses CMD25 */ if (blkcnt == 1 && !dev->infinite_mode) cmd_idx = (act == READ) ? SDHCI_CMD17_READ_SINGLE_BLOCK : SDHCI_CMD24_WRITE_BLOCK; else cmd_idx = (act == READ) ? SDHCI_CMD18_READ_MULTI_BLOCK : SDHCI_CMD25_WRITE_MULTI_BLOCK; if ((err = kdrv_sdc_send_command(dev, cmd_idx, SDHCI_CMD_TYPE_NORMAL, 1, SDHCI_CMD_RTYPE_R1R5R6R7, 1, start_addr)) != KDRV_STATUS_OK) return err; if (card_info->resp_lo & SD_STATUS_ERROR_BITS) { kmdw_dbg_printf(" Card Status indicate error 0x%08x.\n", card_info->resp_lo); return KDRV_STATUS_ERROR; } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_card_write() write data to sd/emmc memory card * * @param[in] dev device structure * @param[in] addr address for read * @param[in] blkcnt block count * @param[in] buf write buffer * @return kdrv_staus */ static kdrv_status_t kdrv_sdc_card_write(kdrv_sdc_res_t *dev, uint32_t addr, uint32_t blkcnt, uint8_t *buf) { kdrv_status_t err; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; if ((err = kdrv_sdc_send_data_command(dev, WRITE, addr, blkcnt, wr_bl_len, (uint32_t *)buf)) != KDRV_STATUS_OK) return err; if ((err = kdrv_sdc_transfer_data(dev, WRITE, (uint32_t *)buf, (blkcnt << wr_bl_len))) != KDRV_STATUS_OK) return err; if (((blkcnt > 1) && !card_info->flow_set.auto_cmd) || dev->infinite_mode) { if ((card_info->flow_set.use_dma == PIO) && dev->infinite_mode) { sdc_reg->blk_gap_ctl &= ~SDHCI_STOP_AT_BLOCK_GAP_REQ; } /* CMD12 */ if ((err = kdrv_sdc_send_abort_command(dev)) != KDRV_STATUS_OK) return err; } if ((err = kdrv_sdc_wait_for_state(dev, CUR_STATE_TRAN, 5000)) != KDRV_STATUS_OK) return err; return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_card_read() read sd/emmc memory card * * @param[in] dev device structure * @param[in] addr address for read * @param[in] blkcnt block count * @param[in] buf read buffer * @return kdrv_status */ static kdrv_status_t kdrv_sdc_card_read(kdrv_sdc_res_t *dev, uint32_t addr, uint32_t blkcnt, uint8_t *buf) { kdrv_status_t err; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; if ((err = kdrv_sdc_send_data_command(dev, READ, addr, blkcnt, rd_bl_len, (uint32_t *) buf)) != KDRV_STATUS_OK) { return err; } if ((err = kdrv_sdc_transfer_data(dev, READ, (uint32_t *) buf, (blkcnt << rd_bl_len))) != KDRV_STATUS_OK) { return err; } if (((blkcnt > 1) && !card_info->flow_set.auto_cmd) || dev->infinite_mode) { if ((card_info->flow_set.use_dma == PIO) && dev->infinite_mode) { sdc_reg->blk_gap_ctl &= ~SDHCI_STOP_AT_BLOCK_GAP_REQ; } /* CMD12 */ //err = kdrv_sdc_send_abort_command(dev); if ((err = kdrv_sdc_send_abort_command(dev)) != KDRV_STATUS_OK) return err; } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_send_command() send command * @param[in] dev device * @param[in] cmd_idx command index * @param[in] cmd_type command type * @param[in] data_present data presetn * @param[in] resp_type response type * @param[in] inhibit_dat_chk inhibit data check * @param[in] argu arguments * Set block count, block size, DMA table address. */ static kdrv_status_t kdrv_sdc_send_command(kdrv_sdc_res_t *dev, uint8_t cmd_idx, uint8_t cmd_type, uint8_t data_present, uint8_t resp_type, uint8_t inhibit_datchk, uint32_t argu) { uint16_t val; clock_t t0; uint8_t wait; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; uint32_t CmdType = SDHCI_CMD_TYPE_NORMAL ; dev->inhibit_datchk = inhibit_datchk; dev->data_present = data_present; dev->response_type = resp_type; //kmdw_dbg_printf("cmd=%d \n", cmd_idx); // Checking the MMC system spec. version more than 4.0 or newer. if (card_info->card_type == MEMORY_CARD_TYPE_MMC && card_info->csd_mmc.spec_vers < 4) { if (cmd_idx == 6 || cmd_idx == 8) { //kmdw_dbg_printf(" ERR## ... Commmand 6 or 8 is not supported in this MMC system spec.\n"); return KDRV_STATUS_SDC_CMD_NOT_SUPPORT; } } if (sdc_reg->present_state & SDHCI_STS_CMD_INHIBIT) { //kmdw_dbg_printf(" ERR## CMD INHIBIT is one(Index = %d).\n", cmd_idx); return KDRV_STATUS_SDC_INHIBIT_ERR; } card_info->err_sts = 0; wait = WAIT_CMD_COMPLETE; card_info->cmpl_mask |= WAIT_CMD_COMPLETE; if (dev->inhibit_datchk || (dev->response_type == SDHCI_CMD_RTYPE_R1BR5B)) { if (sdc_reg->present_state & SDHCI_STS_CMD_DAT_INHIBIT) { //kmdw_dbg_printf(" ERR## CMD DATA INHIBIT is one.\n"); return KDRV_STATUS_SDC_INHIBIT_ERR; } /* If this is R1B, we need to wait transfer complete here. * Otherwise, wait transfer complete after read/write data. */ if (dev->response_type == SDHCI_CMD_RTYPE_R1BR5B) { card_info->cmpl_mask |= WAIT_TRANS_COMPLETE; wait |= WAIT_TRANS_COMPLETE; } } sdc_reg->cmd_argu = argu; if(cmd_idx == SDHCI_CMD12_STOP_TRANS) CmdType = SDHCI_CMD_TYPE_ABORT; val = ((cmd_idx & 0x3f) << SDHCI_CMD_IDX_SHIFT) | ((CmdType & 0x3) << SDHCI_CMD_TYPE_SHIFT) | ((dev->data_present & 0x1) << SDHCI_CMD_DATA_PRESEL_SHIFT) | (dev->response_type & 0x1F); sdc_reg->cmd_reg = val; if (cmd_idx == SDHCI_CMD19_SEND_TUNE_BLOCK) return KDRV_STATUS_OK; t0 = kdrv_current_t1_tick(); while (!card_info->err_sts && (card_info->cmpl_mask & wait)) { /* 1 secs */ if ((kdrv_current_t1_tick() - t0) > 1000) { kmdw_dbg_printf(" Wait for Interrupt timeout.\n"); return KDRV_STATUS_SDC_TIMEOUT; } } /* Read Response Data */ card_info->resp_lo = sdc_reg->cmd_resplo; card_info->resp_hi = sdc_reg->cmd_resphi; if (card_info->err_sts) { kmdw_dbg_printf("SEND: ERR=0x%x", card_info->err_sts); if (card_info->err_sts & SDHCI_INTR_ERR_AUTOCMD) kdrv_sdc_auto_cmd_error_recovery(dev); else { kmdw_dbg_printf("ErrorRecovery\n"); kdrv_sdc_error_recovery(dev); } return KDRV_STATUS_ERROR; } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_hw_attr_init() init the hardware attribute setting * @return kdrv_status_t */ static kdrv_status_t kdrv_sdc_hw_attr_init(kdrv_sdc_res_t *dev) { uint32_t clk; // ip clock kdrv_status_t rstatus; volatile kdrv_sdc_reg_t *sdc_reg = dev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = dev->card_info; kdrv_sdc_sd_host_t *host = dev->host; if(sdc_reg==NULL || card_info == NULL || host ==NULL) { return KDRV_STATUS_SDC_MEM_ALLOC_ERR; } //infinite_mode = 0; //cardChanged = false; memset ((void *)card_info, 0, sizeof(kdrv_sdc_sdcard_info_t)); /* Reset the controller */ sdc_reg->softrst = SDHCI_SOFTRST_ALL; //SDC does not provide the correct Base Clock Frequency value to the Capability //register (Offset = 0x40), bits[15:8]. FWSDC021 assigns 100-MHz as the default value. clk = (sdc_reg->cap_reg >> 8) & 0xFF; if (clk == 0) { //kmdw_dbg_printf(" ERR## Hardware doesn't specify base clock frequency.\n"); /* Controller does not specify the base clock frequency. * Current design base clock = SD ODC frequency x 2. */ clk = FTSDC021_BASE_CLOCK; /* (sdc_reg->cap_reg >> 8) & 0xFF; */ } //clk = FTSDC021_BASE_CLOCK; kdrv_sdc_set_base_clock(host, clk); if (sdc_reg->cap_reg & SDHCI_CAP_VOLTAGE_33V) host->ocr_avail = (3 << 20); if (sdc_reg->cap_reg & SDHCI_CAP_VOLTAGE_30V) host->ocr_avail |= (3 << 17); if (sdc_reg->cap_reg & SDHCI_CAP_VOLTAGE_18V) host->ocr_avail |= (1 << 7); #ifdef KDRV_SDC_DBG kmdw_dbg_printf(" - Base Clock Frequency: Min %d Hz, Max %d Hz.\n", host->min_clk, host->max_clk); kmdw_dbg_printf(" - Max Block Length: 0x%x bytes.\n", 0x200 << ((sdc_reg->cap_reg >> 16) & 0x3)); kmdw_dbg_printf(" - 8-bit: %s, ADMA2: %s, HS: %s, SDMA: %s, S/R: %s, Voltage: 0x%x,SDR50/104,DDR50: 0x%x.\n\n", ((sdc_reg->cap_reg >> 18) & 1) ? "Yes" : "No", ((sdc_reg->cap_reg >> 19) & 1) ? "Yes" : "No", ((sdc_reg->cap_reg >> 21) & 1) ? "Yes" : "No", ((sdc_reg->cap_reg >> 22) & 1) ? "Yes" : "No", ((sdc_reg->cap_reg >> 23) & 1) ? "Yes" : "No", ((sdc_reg->cap_reg >> 24) & 7), (sdc_reg->cap_reg2 & 7)); #endif /* Support SDR50, SDR104 and DDR50, we might request wot switch 1.8V IO signal */ if (sdc_reg->cap_reg2 & 7) { host->ocr_avail |= (1 << 24); } /* Clock must be < 400KHz for initialization */ kdrv_sdc_set_sd_clock(dev, host->min_clk); kdrv_sdc_set_power(dev, 17); if (sdc_reg->hw_attr & 0x1C) { /* FIFO use SRAM: 1K, 2K or 4K */ dev->fifo_depth = 512; } else if (sdc_reg->hw_attr & 0x2) dev->fifo_depth = 16 << 2; else if (sdc_reg->hw_attr & 0x1) dev->fifo_depth = 8 << 2; #ifdef KDRV_SDC_DBG kmdw_dbg_printf(" - FIFO depth %d bytes.\n", dev->fifo_depth); #endif /* set timeout ctl */ sdc_reg->timeout_ctl = 13; //Refer to chapter 2.2.15(Timeout control register(0x2E) of SD Host Controller Spec. v2.0 dev->timeout_ms = (1 << (sdc_reg->timeout_ctl + 13)) / (clk * 1000); //13 for shift value #ifdef __FREERTOS__ NVIC_SetPriority(SDC_FTSDC021_0_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY ); #endif NVIC_EnableIRQ(SDC_FTSDC021_IRQ); /* Always enable all interrupt */ sdc_reg->intr_en = SDHCI_INTR_EN_ALL; sdc_reg->err_en = SDHCI_ERR_EN_ALL; kmdw_dbg_printf(" Checking card ... "); if ((rstatus=kdrv_sdc_check_card_insert(dev)) != KDRV_STATUS_OK) { return rstatus; } /* Do not require to enable Error Interrupt Signal. * Bit 15 of Normal Interrupt Status will tell if * error happens. */ card_info->already_init = true; /* Optionally enable interrupt signal to CPU */ #ifdef USE_PIO kdrv_sdc_set_transfer_type(dev, PIO, 4, 0); #else kdrv_sdc_set_transfer_type(dev, ADMA, 4, 0); #endif return KDRV_STATUS_OK; } /** * @brief SDC_IRQHandler() sdc isr function. */ //void SDC_IRQHandler() static void sdc_isr() { uint16_t sts; volatile kdrv_sdc_reg_t *sdc_reg = gdev->sdc_reg; volatile kdrv_sdc_sdcard_info_t *card_info = gdev->card_info; kdrv_sdc_sd_host_t *host = gdev->host; /* Read Interrupt Status */ sts = sdc_reg->intr_sts; /* As soon as the command complete, data ready to be read/write. * Buffer Read/Write Ready usually used when PIO mode. * We don't expect to use interrupt here, but polling. * Leave it to read/write data function. */ sts &= ~(SDHCI_INTR_STS_BUFF_READ_READY | SDHCI_INTR_STS_BUFF_WRITE_READY); /* Clear Interrupt Status immediately */ sdc_reg->intr_sts &= sts; /* Writing 1 to Card Interrupt Status does not clear it. * Instead, disable the Interrupt Status to clear. */ /* * WARNING ! * KL520 does not have the CD/WP pin, so it will not receive the insert/remove INT */ if (sts & SDHCI_INTR_STS_CARD_INTR) { sdc_reg->intr_en &= ~SDHCI_INTR_STS_CARD_INTR; kmdw_dbg_printf("INTR: Card Interrupt.\n"); sdc_reg->intr_en |= SDHCI_INTR_STS_CARD_INTR; } #if (STANDARD_SD==1) if (sts & SDHCI_INTR_STS_CARD_INSERT) { #else if (sts & SDHCI_INTR_STS_CARD_REMOVE) { #endif kmdw_dbg_printf("INTR: Card Insert\n"); card_info->card_insert = 1; //cardChanged = true; if (card_info->already_init == false) { kdrv_sdc_hw_attr_init(gdev); } else { kdrv_sdc_set_sd_clock(gdev,host->min_clk); kdrv_sdc_set_power(gdev,17); } } #if (STANDARD_SD==1) if (sts & SDHCI_INTR_STS_CARD_REMOVE) { #else if (sts & SDHCI_INTR_STS_CARD_INSERT) { #endif //cardChanged = true; card_info->card_insert = 0; // Stop to provide clock kdrv_sdc_set_sd_clock(gdev,0); // Stop to provide power kdrv_sdc_set_power(gdev,-1); } if (sts & SDHCI_INTR_STS_CMD_COMPLETE) { card_info->cmpl_mask &= ~WAIT_CMD_COMPLETE; } if (sts & SDHCI_INTR_STS_TXR_COMPLETE) { if (card_info->cmpl_mask & WAIT_TRANS_COMPLETE) { card_info->cmpl_mask &= ~WAIT_TRANS_COMPLETE; } else { while(1); } } if (sts & SDHCI_INTR_STS_BLKGAP) { card_info->cmpl_mask &= ~WAIT_BLOCK_GAP; } if (sts & SDHCI_INTR_STS_DMA) { card_info->cmpl_mask &= ~WAIT_DMA_INTR; } if (sts & SDHCI_INTR_STS_ERR) { card_info->err_sts = sdc_reg->err_sts; kmdw_dbg_printf(" INTR: ERR## &0x%x 0x%x\n", &(sdc_reg->err_sts),sdc_reg->err_sts); /* Step 2: Check CMD Line Error */ if (card_info->err_sts & SDHCI_INTR_ERR_CMD_LINE) { /* Step 3: Software Reset for CMD line */ sdc_reg->softrst |= SDHCI_SOFTRST_CMD; /* Step 4 */ while (sdc_reg->softrst & SDHCI_SOFTRST_CMD) ; } /* Step 5: Check DAT Line Error */ if (card_info->err_sts & SDHCI_INTR_ERR_DAT_LINE) { /* Step 6: Software Reset for DAT line */ sdc_reg->softrst |= SDHCI_SOFTRST_DAT; /* Step 7 */ while (sdc_reg->softrst & SDHCI_SOFTRST_DAT) ; } /* Auto CMD Error Status register is reset */ if (card_info->err_sts & SDHCI_INTR_ERR_AUTOCMD) card_info->auto_err = sdc_reg->auto_cmd_err; sdc_reg->err_sts = card_info->err_sts; if (card_info->err_sts & SDHCI_INTR_ERR_TUNING) { kdrv_sdc_execute_tuning(gdev, 16); } } return; } //============================================================================= // KDRV SDC API //============================================================================= /** * @brief kdrv_sdc_initialize, initail sd/emmc card interface * 1. reset sdc status * 2. allocate resource and initail driving * 3. turn on sdc clock * @return kdrv_status_t */ kdrv_status_t kdrv_sdc_initialize(void) { //initialize memory structure and hardware attribute uint8_t i; kdrv_status_t err; kdrv_sdc_sdcard_info_t *card_info; kdrv_sdc_sd_host_t *host; uint32_t data; /* clear SD ctrl register */ outw(SCU_EXTREG_SD_CTRL, 0x0); NVIC_SetVector((IRQn_Type)SDC_FTSDC021_IRQ, (uint32_t)sdc_isr); /* resource allocate */ card_info = (kdrv_sdc_sdcard_info_t *)malloc(sizeof(kdrv_sdc_sdcard_info_t)); if(!card_info) { return KDRV_STATUS_SDC_MEM_ALLOC_ERR; } gdev->card_info = card_info; host = (kdrv_sdc_sd_host_t *)malloc(sizeof(kdrv_sdc_sd_host_t)); if(!host) { free((void *)gdev->card_info); return KDRV_STATUS_SDC_MEM_ALLOC_ERR; } for(i = 0; i < 6; i++) { /* set sdc pins output driven to 8mA */ data = inw(SCU_EXTREG_SD_CLK_IOCTRL + i*4); outw(SCU_EXTREG_SD_CLK_IOCTRL+ i * 4, (data & ~0x1FF) | 0x48); } /* sdc clock enable */ SCU_EXTREG_CLK_EN1_SET_sdclk(1); gdev->host = host; /* initialize hw attribute setting */ if ((err = kdrv_sdc_hw_attr_init(gdev)) != KDRV_STATUS_OK) { free((void *)gdev->card_info); free((void *)gdev->host); return err; } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_uninitialize, uninitail sd card interface and resource * 1. reset sdc status and initail driven * 2. turn on sdc clock */ kdrv_status_t kdrv_sdc_uninitialize(void) { /* uninitialize resource */ if(gdev->card_info) free((void*)gdev->card_info); if(gdev->host) free((void*)gdev->host); /* sdc clock disable */ SCU_EXTREG_CLK_EN1_SET_sdclk(0); return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_dev_scan() scan sd/mmc memory card * * @return kdrv_status_t */ kdrv_status_t kdrv_sdc_dev_scan(void) { kdrv_status_t err; volatile kdrv_sdc_sdcard_info_t *card_info = gdev->card_info; if ((err = kdrv_sdc_scan_cards(gdev)) != KDRV_STATUS_OK) { return err; } if (card_info->card_type == MEMORY_CARD_TYPE_SD) { kdrv_sdc_read_scr(gdev); } else if (card_info->card_type == MEMORY_CARD_TYPE_MMC) { kdrv_sdc_read_ext_csd(gdev); } if (!kdrv_sdc_set_bus_speed_mode(gdev, SPEED_SDR25)) { kdrv_sdc_set_sd_clock(gdev, (card_info->max_dtr)); } return KDRV_STATUS_OK; } /** * @brief kdrv_sdc_get_dev() get device infromation * * @return kdrv_status_t */ kdrv_sdc_res_t* kdrv_sdc_get_dev(void) { return gdev; } /** * @brief kdrv_sdc_read read data from sd/mmc card * * @param[in] buf buffer to write. * @param[in] sd_offset sd/mmc offset address * @param[in] size read size(Multiple of 512, 1sector=512Bytes) * @return kdrv_status_t */ kdrv_status_t kdrv_sdc_read(uint8_t *buf, uint32_t sd_offset, uint32_t size) { uint32_t blk_cnt, blk_size; blk_size = 1 << rd_bl_len; blk_cnt = (size + blk_size - 1) / blk_size; return(kdrv_sdc_card_read(gdev, sd_offset, blk_cnt, buf)); } /** * @brief kdrv_sdc_write write data from sd/mmc card * * @param[in] buf buffer to write. * @param[in] sd_offset sd/mmc offset address * @param[in] size write size(Multiple of 512, 1sector=512Bytes) * @return kdrv_status_t */ kdrv_status_t kdrv_sdc_write(uint8_t *buf, uint32_t sd_offset, uint32_t size) { uint32_t blk_cnt, blk_size; blk_size = 1 << rd_bl_len; blk_cnt = (size + blk_size - 1) / blk_size; return(kdrv_sdc_card_write(gdev, sd_offset, blk_cnt, buf)); }