#include "sys_config.h" #include "typesdef.h" #include "devid.h" #include "list.h" #include "dev.h" #include "osal/task.h" #include "osal/semaphore.h" #include "osal/mutex.h" #include "lib/sdhost/sdhost.h" #include "hal/gpio.h" #include "osal/irq.h" #include "osal/string.h" #include "osal/mutex.h" #include "osal/irq.h" #include "osal/task.h" #include "osal/sleep.h" #include "osal/timer.h" #include "osal/work.h" #ifdef PIN_FROM_PARAM #include "pin_param.h" #endif extern uint8_t get_fat_isready(); struct sdh_device *sdh_test; struct os_semaphore sem; #define SD_SAMPLE_VALUE_PRINT (1) #ifdef PSRAM_HEAP #define SDHC_HEAP_MALLOC os_malloc_psram #define SDHC_HEAP_FREE os_free_psram #else #define SDHC_HEAP_MALLOC os_malloc #define SDHC_HEAP_FREE os_free #endif volatile uint32 sdhc_curr_write_byte = 0; volatile uint32 sdhc_curr_read_byte = 0; volatile uint32 sdhc_last_write_byte = 0; volatile uint32 sdhc_last_read_byte = 0; #define be32_to_cpu(x) ((uint32)( \ (((uint32)(x) & (uint32)0x000000ffUL) << 24) | \ (((uint32)(x) & (uint32)0x0000ff00UL) << 8) | \ (((uint32)(x) & (uint32)0x00ff0000UL) >> 8) | \ (((uint32)(x) & (uint32)0xff000000UL) >> 24))) static uint32 __rt_fls(uint32 val) { uint32 bit = 32; if (!val) return 0; if (!(val & 0xffff0000u)) { val <<= 16; bit -= 16; } if (!(val & 0xff000000u)) { val <<= 8; bit -= 8; } if (!(val & 0xf0000000u)) { val <<= 4; bit -= 4; } if (!(val & 0xc0000000u)) { val <<= 2; bit -= 2; } if (!(val & 0x80000000u)) { bit -= 1; } return bit; } static const uint32 tran_unit[] = { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; static const uint8 tran_value[] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; static const uint32 tacc_uint[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, }; static const uint8 tacc_value[] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80, }; uint32 GET_BITS(uint32 *resp, uint32 start, uint32 size) { const int32_t __size = size; const uint32 __mask = (__size < 32 ? 1 << __size : 0) - 1; const int32_t __off = 3 - ((start) / 32); const int32_t __shft = (start) & 31; uint32 __res; __res = resp[__off] >> __shft; if (__size + __shft > 32) __res |= resp[__off-1] << ((32 - __shft) % 32); return __res & __mask; } void sdhost_io_func_init(uint32 req){ if(req == 1) pin_func(HG_SDIOHOST_DEVID,4); else pin_func(HG_SDIOHOST_DEVID,1); } static int32_t sd_parse_scr(struct sdh_device *host) { struct rt_sd_scr *scr = &host->scr; uint32 resp[4]; resp[3] = host->resp_scr[1]; resp[2] = host->resp_scr[0]; scr->sd_version = GET_BITS(resp, 56, 4); scr->sd_bus_widths = GET_BITS(resp, 48, 4); SDHC_WARN_PRINTF("sd_version : %d \t %d\r\n", scr->sd_version, scr->sd_bus_widths); return 0; } #if 1//(defined (TXW81X) || defined (TXW82X)) static int32_t sd_switch(struct sdh_device *host) { int32_t ret; struct rt_mmcsd_cmd cmd; uint8 *buf = os_malloc(64); if (!buf) { SDHC_ERR_PRINTF("mallo err!\r\n"); return 1; } host->data.blksize = 64; host->data.blks = 1; host->data.err = 0; if (((const struct sdhc_hal_ops *)host->dev.ops)->read) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->read(host, buf); if (ret) return 1; } memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_SWITCH; cmd.arg = 0x00FFFFF1; cmd.flags = RESP_R1 | CMD_ADTC; if (((const struct sdhc_hal_ops *)host->dev.ops)->cmd) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd); if (ret) return 1; } if (((const struct sdhc_hal_ops *)host->dev.ops)->complete) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->complete(host); if (ret) return 1; } if (buf[13] & 0x02) host->max_data_rate = 50*1000*1000; #if 0 for(int itk = 0;itk <64;itk++){ if(itk%32 == 0) SDHC_WARN_PRINTF("\r\n"); SDHC_WARN_PRINTF("%02x ",buf[itk]); } #endif memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); host->data.blksize = 64; host->data.blks = 1; host->data.err = 0; if (((const struct sdhc_hal_ops *)host->dev.ops)->read) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->read(host, buf); if (ret) return 1; } cmd.cmd_code = SD_SWITCH; cmd.arg = 0x80FFFFF1; cmd.flags = RESP_R1 | CMD_ADTC; if (((const struct sdhc_hal_ops *)host->dev.ops)->cmd) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd); if (ret) return 1; } if (((const struct sdhc_hal_ops *)host->dev.ops)->complete) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->complete(host); if (ret) return 1; } #if 0 for(int itk = 0;itk <64;itk++){ if(itk%32 == 0) SDHC_WARN_PRINTF("\r\n"); SDHC_WARN_PRINTF("%02x ",buf[itk]); } SDHC_WARN_PRINTF("\r\n"); #endif if ((buf[16] & 0xF) != 1) { SDHC_ERR_PRINTF("switching card to high speed failed!"); return 1; } SDHC_WARN_PRINTF("switch finish\r\n"); host->cardflags |= CARD_FLAG_HIGHSPEED; os_free(buf); return 0; } #endif unsigned int sd_dwCap; static int32_t sd_parse_csd(struct sdh_device *host) { struct rt_mmcsd_csd *csd = &host->csd; uint32 *resp = host->resp_csd; csd->csd_structure = GET_BITS(resp, 126, 2); switch (csd->csd_structure) { case 0: host->cardflags &= ~CARD_FLAG_SDHC; csd->taac = GET_BITS(resp, 112, 8); csd->nsac = GET_BITS(resp, 104, 8); csd->tran_speed = GET_BITS(resp, 96, 8); csd->card_cmd_class = GET_BITS(resp, 84, 12); csd->rd_blk_len = GET_BITS(resp, 80, 4); csd->rd_blk_part = GET_BITS(resp, 79, 1); csd->wr_blk_misalign = GET_BITS(resp, 78, 1); csd->rd_blk_misalign = GET_BITS(resp, 77, 1); csd->dsr_imp = GET_BITS(resp, 76, 1); csd->c_size = GET_BITS(resp, 62, 12); csd->c_size_mult = GET_BITS(resp, 47, 3); csd->r2w_factor = GET_BITS(resp, 26, 3); csd->wr_blk_len = GET_BITS(resp, 22, 4); csd->wr_blk_partial = GET_BITS(resp, 21, 1); csd->csd_crc = GET_BITS(resp, 1, 7); host->card_blksize = 1 << csd->rd_blk_len; host->card_capacity = (csd->c_size + 1) << (csd->c_size_mult + 2); host->card_capacity *= host->card_blksize; host->card_capacity >>= 10; /* unit:KB */ host->tacc_clks = csd->nsac * 100; host->tacc_ns = (tacc_uint[csd->taac&0x07] * tacc_value[(csd->taac&0x78)>>3] + 9) / 10; host->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3]; #if 0 val = GET_BITS(resp, 115, 4); unit = GET_BITS(resp, 112, 3); csd->tacc_ns = (tacc_uint[unit] * tacc_value[val] + 9) / 10; csd->tacc_clks = GET_BITS(resp, 104, 8) * 100; val = GET_BITS(resp, 99, 4); unit = GET_BITS(resp, 96, 3); csd->max_data_rate = tran_unit[unit] * tran_value[val]; csd->ccc = GET_BITS(resp, 84, 12); unit = GET_BITS(resp, 47, 3); val = GET_BITS(resp, 62, 12); csd->device_size = (1 + val) << (unit + 2); csd->read_bl_len = GET_BITS(resp, 80, 4); csd->write_bl_len = GET_BITS(resp, 22, 4); csd->r2w_factor = GET_BITS(resp, 26, 3); #endif break; case 1: host->cardflags |= CARD_FLAG_SDHC; /*This field is fixed to 0Eh, which indicates 1 ms. The host should not use TAAC, NSAC, and R2W_FACTOR to calculate timeout and should uses fixed timeout values for read and write operations*/ csd->taac = GET_BITS(resp, 112, 8); csd->nsac = GET_BITS(resp, 104, 8); csd->tran_speed = GET_BITS(resp, 96, 8); csd->card_cmd_class = GET_BITS(resp, 84, 12); csd->rd_blk_len = GET_BITS(resp, 80, 4); csd->rd_blk_part = GET_BITS(resp, 79, 1); csd->wr_blk_misalign = GET_BITS(resp, 78, 1); csd->rd_blk_misalign = GET_BITS(resp, 77, 1); csd->dsr_imp = GET_BITS(resp, 76, 1); csd->c_size = GET_BITS(resp, 48, 22); csd->r2w_factor = GET_BITS(resp, 26, 3); csd->wr_blk_len = GET_BITS(resp, 22, 4); csd->wr_blk_partial = GET_BITS(resp, 21, 1); csd->csd_crc = GET_BITS(resp, 1, 7); host->card_blksize = 512; host->card_capacity = (csd->c_size + 1) * 512; /* unit:KB */ host->tacc_clks = 0; host->tacc_ns = 0; host->max_data_rate = tran_unit[csd->tran_speed&0x07] * tran_value[(csd->tran_speed&0x78)>>3]; #if 0 csd->tacc_ns = 0; csd->tacc_clks = 0; val = GET_BITS(resp, 99, 4); unit = GET_BITS(resp, 96, 3); csd->max_data_rate = tran_unit[unit] * tran_value[val]; csd->ccc = GET_BITS(resp, 84, 12); val = GET_BITS(resp, 48, 22); csd->device_size = (1 + val) << 10; csd->read_bl_len = 9; csd->write_bl_len = 9; /* host should not use this factor and should use 250ms for write timeout */ csd->r2w_factor = 2; #endif break; default: SDHC_ERR_PRINTF("unrecognised CSD structure version %d!", csd->csd_structure); return -EINVAL; } host->card_max_blk_num = host->card_capacity << 1; SDHC_WARN_PRINTF("SD card capacity %d KB.\r\n", host->card_capacity); SDHC_WARN_PRINTF("SD card max block num %d\r\n", host->card_max_blk_num); sd_dwCap = host->card_capacity; return 0; } uint32 select_voltage(struct sdh_device *host, uint32 ocr) { int bit; //extern int ffs32_lsb(uint32 value); ocr &= host->valid_ocr; bit = 15;//ffs32_lsb(ocr); if (bit) { bit -= 1; ocr &= 3 << bit; host->io_cfg.vdd = bit; //mmcsd_set_iocfg(host); if(((const struct sdhc_hal_ops *)host->dev.ops)->iocfg) ((const struct sdhc_hal_ops *)host->dev.ops)->iocfg(host,&host->io_cfg); } else { SDHC_ERR_PRINTF("host doesn't support card's voltages!"); ocr = 0; } return ocr; } uint32 sd_power_up(struct sdh_device *host,uint8 bus_w) { int bit = __rt_fls(host->valid_ocr) - 1; host->io_cfg.vdd = bit; if (controller_is_spi(host)) { host->io_cfg.chip_select = MMCSD_CS_HIGH; host->io_cfg.bus_mode = MMCSD_BUSMODE_PUSHPULL; } else { host->io_cfg.chip_select = MMCSD_CS_IGNORE; host->io_cfg.bus_mode = MMCSD_BUSMODE_OPENDRAIN; } host->io_cfg.power_mode = MMCSD_POWER_UP; if(bus_w == MMCSD_BUSWIDTH_4) host->io_cfg.bus_width = MMCSD_BUS_WIDTH_4; else host->io_cfg.bus_width = MMCSD_BUS_WIDTH_1; host->io_cfg.clock = 400000; if(((const struct sdhc_hal_ops *)host->dev.ops)->iocfg) ((const struct sdhc_hal_ops *)host->dev.ops)->iocfg(host,&host->io_cfg); /* * This delay should be sufficient to allow the power supply * to reach the minimum voltage. */ os_sleep_ms(10); host->io_cfg.clock = host->freq_min; host->io_cfg.power_mode = MMCSD_POWER_ON; if(((const struct sdhc_hal_ops *)host->dev.ops)->iocfg) ((const struct sdhc_hal_ops *)host->dev.ops)->iocfg(host,&host->io_cfg); /* * This delay must be at least 74 clock sizes, or 1 ms, or the * time required to reach a stable voltage. */ os_sleep_ms(10); return 0; } void sd_set_clk(struct sdh_device * host,uint32 clk) { host->io_cfg.clock = clk; host->io_cfg.ioctl_type = LL_SDHC_IOCTRL_SET_CLOCK; ((const struct sdhc_hal_ops *)host->dev.ops)->iocfg(host,&host->io_cfg); } void sd_set_bus_width(struct sdh_device * host,uint32 width) { host->io_cfg.bus_width = width; host->io_cfg.ioctl_type = LL_SDHC_IOCTRL_SET_BUS_WIDTH; ((const struct sdhc_hal_ops *)host->dev.ops)->iocfg(host,&host->io_cfg); } #if (defined (TXW81X) || defined (TXW82X)) void sd_set_sample(struct sdh_device *host, TYPE_LL_SDHC_SMP_CFG type, uint8 cmd_cmp, uint8 dat_cmp) { host->io_cfg.smp_type = type; host->io_cfg.cmd_crc_sample = cmd_cmp; host->io_cfg.dat_crc_sample = dat_cmp; host->io_cfg.ioctl_type = LL_SDHC_IOCTRL_SET_SMP; ((const struct sdhc_hal_ops *)host->dev.ops)->iocfg(host, &host->io_cfg); } void sd_delay_config(struct sdh_device *host, TYPE_LL_SDHC_DELAY_SYSCLK dly_cfg, uint8 chain) { if (dly_cfg == LL_SDHC_DLY_NONE) { host->io_cfg.delay_flag = 0; }else{ host->io_cfg.delay_flag = 1; host->io_cfg.delay_type = ((chain == 0) && (dly_cfg == LL_SDHC_DLY_CHAIN)) ? (LL_SDHC_DLY_NONE) : (dly_cfg); host->io_cfg.delay_chain_cnt = chain; } host->io_cfg.ioctl_type = LL_SDHC_IOCTRL_SET_DELAY_TYPE; ((const struct sdhc_hal_ops *)host->dev.ops)->iocfg(host, &host->io_cfg); } void sd_dat_of_stop_clk_cfg(struct sdh_device *host, uint8 flag) { host->io_cfg.dat_overflow_stop_flag = flag; host->io_cfg.ioctl_type = LL_SDHC_IOCTRL_SET_DAT_OF_STOP_CLK; ((const struct sdhc_hal_ops *)host->dev.ops)->iocfg(host, &host->io_cfg); } #endif uint32 send_idle(struct sdh_device * host) { uint32 ret; struct rt_mmcsd_cmd cmd; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = GO_IDLE_STATE; cmd.arg = 0; cmd.flags = RESP_SPI_R1 | RESP_NONE | CMD_BC; if(((const struct sdhc_hal_ops *)host->dev.ops)->cmd) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); else{ SDHC_ERR_PRINTF("no cmd action register\r\n"); return 0; } return ret; } uint32 send_all_get_cid(struct sdh_device * host,uint32 *cid) { uint32 ret; struct rt_mmcsd_cmd cmd; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = ALL_SEND_CID; cmd.arg = 0; cmd.flags = RESP_R2 | CMD_BCR; ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); if(ret==0) memcpy(cid, cmd.resp, sizeof(uint32) * 4); return ret; } uint32 send_get_card_addr(struct sdh_device * host,uint32 *rca) { uint32 ret; struct rt_mmcsd_cmd cmd; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_SEND_RELATIVE_ADDR; cmd.arg = 0; cmd.flags = RESP_R6 | CMD_BCR; ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); *rca = cmd.resp[0] >> 16; return 0; } int32 sd_get_card_status(struct sdh_device * host, uint32 *status){ struct rt_mmcsd_cmd cmd; int ret = RET_OK; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SEND_STATUS; cmd.arg = host->rca << 16; cmd.flags = RESP_R1 | CMD_AC; if(((const struct sdhc_hal_ops *)host->dev.ops)->cmd) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); *status = cmd.resp[0]; return ret; } uint32 send_card_status(struct sdh_device * host){ int ret = RET_OK; uint32 status = 0; sd_get_card_status(host, &status); status = (status >> 9) & 0xf; if (status != MMCSD_CARD_STATUS_TRAN) { // SDHC_WARN_PRINTF("card status : %d\r\n", status); return RET_ERR; } return ret; } uint32 send_select_card(struct sdh_device * host) { struct rt_mmcsd_cmd cmd; int ret = 0; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SELECT_CARD; if (host->rca) { cmd.arg = host->rca << 16; cmd.flags = RESP_R1 | CMD_AC; } else { cmd.arg = 0; cmd.flags = RESP_NONE | CMD_AC; } if(((const struct sdhc_hal_ops *)host->dev.ops)->cmd) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); return ret; } uint32 send_if_cond(struct sdh_device * host,uint32 ocr) { struct rt_mmcsd_cmd cmd; int ret = 0; uint8 pattern; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_SEND_IF_COND; cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | 0xAA; cmd.flags = RESP_SPI_R7 | RESP_R7 | CMD_BCR; if(((const struct sdhc_hal_ops *)host->dev.ops)->cmd) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); //if (controller_is_spi(host)) // pattern = cmd.resp[1] & 0xFF; //else pattern = cmd.resp[0] & 0xFF; if (pattern != 0xAA) return -EINVAL; return ret; } uint32 send_get_csd(struct sdh_device * host,uint32 *csd) { int ret; struct rt_mmcsd_cmd cmd; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SEND_CSD; cmd.arg = host->rca << 16; cmd.flags = RESP_R2 | CMD_AC; ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); memcpy(csd, cmd.resp, sizeof(uint32) * 4); return ret; } uint32 send_app_cmd(struct sdh_device *host,uint32 rca) { struct rt_mmcsd_cmd cmd = {0}; int ret = 0; cmd.cmd_code = APP_CMD; if(rca){ cmd.arg = rca << 16; cmd.flags = RESP_R1 | CMD_AC; } else { cmd.arg = 0; cmd.flags = RESP_R1 | CMD_BCR; } if(((const struct sdhc_hal_ops *)host->dev.ops)->cmd) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); return ret; } uint32 sd_app_set_bus_width(struct sdh_device *host,int32_t width) { int ret = 0; struct rt_mmcsd_cmd cmd; send_app_cmd(host,host->rca); memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_APP_SET_BUS_WIDTH; cmd.flags = RESP_R1 | CMD_AC; switch (width) { case MMCSD_BUS_WIDTH_1: cmd.arg = MMCSD_BUS_WIDTH_1; break; case MMCSD_BUS_WIDTH_4: cmd.arg = MMCSD_BUS_WIDTH_4; break; default: return -EINVAL; } if(((const struct sdhc_hal_ops *)host->dev.ops)->cmd) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); return ret; } uint32 send_get_scr(struct sdh_device *host,uint32* scr) { struct rt_mmcsd_cmd cmd; int ret; if(host->flags & MMCSD_BUSWIDTH_4) sd_set_bus_width(host, MMCSD_BUS_WIDTH_1); host->data.blksize = 8; host->data.blks = 1; host->data.err = 0; if(((const struct sdhc_hal_ops *)host->dev.ops)->read) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->read(host,(uint8*)scr); send_app_cmd(host,host->rca); memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_APP_SEND_SCR; cmd.arg = 0; cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC; if(((const struct sdhc_hal_ops *)host->dev.ops)->cmd) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); if (((const struct sdhc_hal_ops *)host->dev.ops)->complete) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->complete(host); if (ret) return 0; } if(host->data.err != 0) return 0; scr[0] = be32_to_cpu(scr[0]); scr[1] = be32_to_cpu(scr[1]); SDHC_WARN_PRINTF("scr:%x %x\r\n",scr[0],scr[1]); return 1; } int32 sd_cmd_stop(struct sdh_device * host) { int ret = RET_OK; if (!(((const struct sdhc_hal_ops *)host->dev.ops)->cmd)) { return RET_ERR; } struct rt_mmcsd_cmd cmd; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = STOP_TRANSMISSION; cmd.arg = 0; cmd.flags = RESP_SPI_R1B | RESP_R1B | CMD_AC; for (int i = 0; i < 2; i++) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd (host, &cmd); if (!ret) { return RET_OK; } } return RET_ERR; } uint32 sd_tran_stop(struct sdh_device * host) { int ret = RET_OK; // os_printf("%s %d addr : %d\r\n", __func__, __LINE__, __builtin_return_address(0)); if ((host->sd_stop)) { sd_cmd_stop(host); } uint32 sd_status = 0; for (int i = 0; i < 5; i++) { ret = sd_get_card_status(host, &sd_status); if (RET_OK == ret) { if (sd_status & 0xFFFF0000) { /* sd err */ os_printf(KERN_ERR"sd-sta:%x\r\n", sd_status); } sd_status = (sd_status >> 9) & 0xF; if (sd_status == MMCSD_CARD_STATUS_TRAN) { host->sd_opt = SD_IDLE; host->sd_stop = 0; return RET_OK; } else if ((sd_status == MMCSD_CARD_STATUS_STBY) || (sd_status == MMCSD_CARD_STATUS_DIS)) { /* need app reselect card */ send_select_card(host); } else if (sd_status > MMCSD_CARD_STATUS_TRAN) { sd_cmd_stop(host); } else { /* card not init ok,kick SD_OFF */ break; } } } host->sd_opt = SD_OFF; return RET_ERR; } //给外部接口专门用的停止命令,现在暂时是给文件系统 uint32 fatfs_sd_tran_stop(struct sdh_device * host) { int ret; os_mutex_lock(&host->lock,osWaitForever); ret = sd_tran_stop(host); os_mutex_unlock(&host->lock); return ret; } int sd_multiple_write(struct sdh_device * host,uint32 lba,uint32 len,uint8 *buf) { int ret; int send_cmd = 1; uint32 curr_lba = lba; uint32 backup_lba = host->new_lba; uint32 block_num = len/SECTOR_SIZE; struct rt_mmcsd_cmd cmd; uint8 retry_cnt = 0; uint8 curr_index = 0; uint8 retry_sample_cnt = 0; uint8 sample_point_bak = 0; uint8 *kick_buf = buf; os_mutex_lock(&host->lock,osWaitForever); __retry: if(((curr_lba != host->new_lba)||(host->sd_opt != SD_M_W))&& host->sd_stop) { ret = sd_tran_stop(host); if (ret) goto __err; host->new_lba = curr_lba; send_cmd = 1; } else if ((host->sd_opt == SD_IDLE) || (!host->sd_stop)){ send_cmd = 1; if (curr_lba != host->new_lba) { host->new_lba = curr_lba; } } else { send_cmd = 0; } if ((host->new_lba + block_num) > host->card_max_blk_num) { SDHC_ERR_PRINTF("%s operation lba %d size %d max : %d err\r\n", __func__, host->new_lba, block_num, host->card_max_blk_num); host->new_lba = backup_lba; ret = RET_ERR; goto __err; } if (send_cmd) host->sd_stop = (host->single_support) ? (block_num > 1) : (1);//; host->new_lba = host->new_lba + block_num; host->sd_opt = SD_M_W; /////////////////////////////////////////////////////// memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = (host->single_support) ? ((block_num > 1) ? (WRITE_MULTIPLE_BLOCK) : (WRITE_BLOCK)) : (WRITE_MULTIPLE_BLOCK); cmd.arg = curr_lba; if (!(host->cardflags & CARD_FLAG_SDHC)) { cmd.arg <<= 9; } cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC; if((((const struct sdhc_hal_ops *)host->dev.ops)) && send_cmd){ ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); if(ret){ sd_tran_stop(host); ret = -1; goto __err; } } #if defined(TXW82X) || defined(TXW81X) if (host->io_cfg.self_adaption_flag != MMCSD_SMP_DIS) { sd_delay_config(host, LL_SDHC_DLY_CHAIN, host->sd_write_dly_chain); sd_set_sample(host, LL_SDHC_DAT_SMP_CFG_EN, 0, host->sd_write_sample); } #endif /////////////////////////////////////////////////////// host->data.blksize = SECTOR_SIZE; host->data.blks = block_num; host->data.err = 0; if((!retry_cnt) && ((uint32)kick_buf >= PSRAM_BASE) ){ sys_dcache_clean_range_unaligned((void *)kick_buf, len); } if(((const struct sdhc_hal_ops *)host->dev.ops)->write) ret = ((const struct sdhc_hal_ops *)host->dev.ops)->write(host,kick_buf); if (((const struct sdhc_hal_ops *)host->dev.ops)->complete) { ret = ((const struct sdhc_hal_ops *)host->dev.ops)->complete(host); #if defined(TXW82X) if ((host->sd_write_retry_flag == 0) && (ret == MMCSD_CMP_DATERR) && (host->io_cfg.self_adaption_flag != MMCSD_SMP_EN)) { if (host->sd_write_retry == LL_SDHC_RETRY_SELECT_POINT) { /* goto retry */ host->sd_write_retry = LL_SDHC_RETRY_DEFAULT; /* find current pos & change sample point to next */ for (curr_index = 0; curr_index < host->sd_write_sample_num; curr_index++) { if ((host->sd_write_sample_value[curr_index] == host->sd_write_sample)) { if (!retry_sample_cnt) { sample_point_bak = host->sd_write_sample; } curr_index++; if (curr_index < host->sd_write_sample_num) { host->sd_write_sample = host->sd_write_sample_value[curr_index]; } else { host->sd_write_sample = host->sd_write_sample_value[0]; } retry_sample_cnt++; break; } } if (retry_sample_cnt >= host->sd_write_sample_num) { host->sd_write_sample = sample_point_bak; host->sd_write_retry = LL_SDHC_RETRY_ERR; /* disable retry */ // host->sd_write_retry_flag = 1; SDHC_ERR_PRINTF("sd err: sel all wr point!\r\n"); } else { SDHC_WARN_PRINTF("sd sel wr point : %d\r\n", host->sd_write_sample); } } if (host->sd_write_retry != LL_SDHC_RETRY_ERR) { retry_cnt++; /* retry 3 times @ every sample point */ if (0 == (retry_cnt % 3)) { host->sd_write_retry = (host->sd_write_retry == LL_SDHC_RETRY_DEFAULT) ? LL_SDHC_RETRY_SELECT_POINT : LL_SDHC_RETRY_DEFAULT; } curr_lba = host->new_lba - host->data.blks; block_num = host->data.blks; kick_buf = kick_buf + (block_num - host->data.blks) * SECTOR_SIZE; goto __retry; } } if (ret == MMCSD_NO_ERR) { host->sd_write_retry = LL_SDHC_RETRY_DEFAULT; } #endif } if (ret) { sd_tran_stop(host); } __err: os_mutex_unlock(&host->lock); return ret; } int sd_multiple_read(struct sdh_device * host,uint32 lba, uint32 len, uint8* buf) { struct rt_mmcsd_cmd cmd; int ret = 0; int send_cmd = 1; uint32 curr_lba = lba; uint32 backup_lba = host->new_lba; uint32 block_num = len/SECTOR_SIZE; uint8 retry_cnt = 0; uint8 curr_index = 0; uint8 retry_sample_cnt = 0; uint8 sample_point_bak = 0; uint8 *kick_buf = buf; // uint8 data_rev = 0; // uint8 *s = NULL; os_mutex_lock(&host->lock,osWaitForever); __retry: if(((curr_lba != host->new_lba)||(host->sd_opt != SD_M_R)) && host->sd_stop) { ret = sd_tran_stop(host); if (ret) goto __err; host->new_lba = curr_lba; send_cmd = 1; } else if ((host->sd_opt == SD_IDLE) || (!host->sd_stop)){ send_cmd = 1; if (curr_lba != host->new_lba) host->new_lba = curr_lba; } else { send_cmd = 0; } if ((host->new_lba + block_num) > host->card_max_blk_num) { SDHC_ERR_PRINTF(KERN_ERR"%s operation lba %d size %d max : %d err\r\n", __func__, host->new_lba, block_num, host->card_max_blk_num); host->new_lba = backup_lba; ret = RET_ERR; goto __err; } if (send_cmd) host->sd_stop = (host->single_support) ? (block_num > 1) : (1); host->new_lba = host->new_lba + block_num; host->sd_opt = SD_M_R; /////////////////////////////////////////////////////// host->data.blksize = SECTOR_SIZE; host->data.blks = block_num; host->data.err = 0; #if defined(TXW82X) || defined(TXW81X) if (host->io_cfg.self_adaption_flag != MMCSD_SMP_DIS) { sd_delay_config(host, LL_SDHC_DLY_CHAIN, host->sd_read_dly_chain); sd_set_sample(host, LL_SDHC_DAT_SMP_CFG_EN, 0, host->sd_read_sample); } #endif if(!retry_cnt && ((uint32)kick_buf >= PSRAM_BASE) ) { sys_dcache_invalid_range_unaligned((void *)kick_buf, len); } if(((const struct sdhc_hal_ops *)host->dev.ops)->read != NULL){ ret = ((const struct sdhc_hal_ops *)host->dev.ops)->read(host,kick_buf); } /////////////////////////////////////////////////////// memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = (host->single_support) ? ((block_num > 1) ? (READ_MULTIPLE_BLOCK) : (READ_SINGLE_BLOCK)) : (READ_MULTIPLE_BLOCK); cmd.arg = curr_lba; if (!(host->cardflags & CARD_FLAG_SDHC)) { cmd.arg <<= 9; } cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC; if((((const struct sdhc_hal_ops *)host->dev.ops)) && send_cmd){ ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); if(ret){ sd_tran_stop(host); ret = MMCSD_CMD_ERR; goto __err; } } if (((const struct sdhc_hal_ops *)host->dev.ops)->complete != NULL){ ret = ((const struct sdhc_hal_ops *)host->dev.ops)->complete(host); #if defined(TXW82X) if ((host->sd_read_retry_flag == 0) && (ret == MMCSD_CMP_DATERR) && (host->io_cfg.self_adaption_flag != MMCSD_SMP_EN)) { if (host->sd_read_retry == LL_SDHC_RETRY_SELECT_POINT) { /* find current pos & change sample point to next */ for (curr_index = 0; curr_index < host->sd_read_sample_num; curr_index++) { if ((host->sd_read_sample_value[curr_index] == host->sd_read_sample)) { if (!retry_sample_cnt) { sample_point_bak = host->sd_read_sample; } curr_index++; if (curr_index < host->sd_read_sample_num) { host->sd_read_sample = host->sd_read_sample_value[curr_index]; } else { host->sd_read_sample = host->sd_read_sample_value[0]; } retry_sample_cnt++; break; } } if (retry_sample_cnt >= host->sd_read_sample_num) { host->sd_read_sample = sample_point_bak; host->sd_write_retry = LL_SDHC_RETRY_ERR; /* disable retry */ // host->sd_write_retry_flag = 1; SDHC_ERR_PRINTF("sd err: sel all rd point!\r\n"); } else { SDHC_WARN_PRINTF("sd sel rd point : %d\r\n", host->sd_read_sample); } } if (host->sd_read_retry != LL_SDHC_RETRY_ERR) { retry_cnt++; /* retry 3 times @ every sample point */ if (0 == (retry_cnt % 3)) { host->sd_read_retry = (host->sd_read_retry == LL_SDHC_RETRY_DEFAULT) ? LL_SDHC_RETRY_SELECT_POINT : LL_SDHC_RETRY_DEFAULT; } curr_lba = host->new_lba - host->data.blks; block_num = host->data.blks; kick_buf = kick_buf + (block_num - host->data.blks) * SECTOR_SIZE; goto __retry; } } if((ret == MMCSD_NO_ERR)) { host->sd_read_retry = LL_SDHC_RETRY_DEFAULT; } #endif // SDHC_WARN_PRINTF("%s %d status : %d flag : %d\r\n", __func__, __LINE__, host->sd_read_retry, host->sd_read_retry_flag); } if (ret) { sd_tran_stop(host); } __err: os_mutex_unlock(&host->lock); return ret; } uint32 send_app_op_cond(struct sdh_device *host, uint32 ocr, uint32 *rocr) { struct rt_mmcsd_cmd cmd; uint32 i; int ret; memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd)); cmd.cmd_code = SD_APP_OP_COND; cmd.arg = ocr; cmd.flags = RESP_SPI_R1 | RESP_R3 | CMD_BCR; for(i = 100;i;i--){ ret = send_app_cmd(host,0); if(ret){ SDHC_ERR_PRINTF("cmd err\r\n"); break; } // memset(cmd->resp, 0, sizeof(cmd->resp)); ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host,&cmd); if(ret){ SDHC_ERR_PRINTF("cmd2 err\r\n"); break; } // SDHC_WARN_PRINTF("cmd resp:%x\r\n",cmd.resp[0]); if (cmd.resp[0] & CARD_BUSY){ SDHC_WARN_PRINTF("card busy ok\r\n"); break; } os_sleep_ms(10); } if(rocr) *rocr = cmd.resp[0]; if(!(cmd.resp[0] & CARD_BUSY)) { SDHC_ERR_PRINTF("card no busy\r\n"); return RET_ERR; } return ret; } void stop_card(){ sd_tran_stop(sdh_test); } uint8 get_sd_status(void) { //SDHC_WARN_PRINTF("%s:%d\r\n",__FUNCTION__,sdh_test->sd_opt); return sdh_test->sd_opt; } uint8 get_sd_status2(void) { return sdh_test->sd_opt == SD_OFF; } int sd_scsi_read2(uint32 lba,uint8* buf) { return sd_multiple_read(sdh_test,lba,SECTOR_SIZE ,buf); } int sd_scsi_write2(uint32 lba,uint8* buf) { return sd_multiple_write(sdh_test,lba,SECTOR_SIZE ,buf); } int usb_sd_scsi_read(uint32 lba, uint32 count, uint8* buf) { return sd_multiple_read(sdh_test,lba,SECTOR_SIZE*count,buf); } int usb_sd_scsi_write(uint32 lba, uint32 count, uint8* buf) { return sd_multiple_write(sdh_test,lba,SECTOR_SIZE*count,buf); } //返回sd卡的扇区大小,现在是固定的 uint32_t get_sd_sector_size() { return 512; } uint32 get_sd_cap() { return sd_dwCap * 2;//Blocks } #if (defined (TXW81X) || defined (TXW82X)) uint16 sd_spi_mode_baud_cfg(uint32 clk) { return (((peripheral_clock_get(HG_APB0_PT_SPI0) / 2 + clk - 1) / clk) - 1); } void sd_sample_print(uint8 *buf, uint8 cnt, char *str, uint8 print_en) { if (print_en) { SDHC_WARN_PRINTF("%s\r\n", str); for (int z = 0; z < cnt; z++) { _os_printf("%d, ", buf[z]); } _os_printf("\r\n"); } } uint32 sd_cmd_sample_retry(struct sdh_device *host, uint8 sample_max) { uint32 result = RET_OK; uint8 buf_index = 0; uint32 ret = 0; uint32 last_ret = MMCSD_INT_VLE; for (int i = 0; i < sample_max; i++) { (host->sd_mode_type) ? (host->spi_delay_cycle = i) : (sd_set_sample(host, LL_SDHC_CMD_SMP_CFG_EN, i, 0));// ret = send_card_status(host); if (!ret) { host->sd_cmd_sample_value[buf_index++] = i; } else if (!last_ret && (last_ret != ret) && buf_index) { break; } last_ret = ret; } if (buf_index) { sd_sample_print(host->sd_cmd_sample_value, buf_index, "cmd", SD_SAMPLE_VALUE_PRINT); host->sd_cmd_sample_num = buf_index; host->sd_cmd_sample = host->sd_cmd_sample_value[(buf_index)>>1]; SDHC_WARN_PRINTF("%s %d sd_cmd_sample : %d\r\n", __func__, __LINE__, host->sd_cmd_sample); (host->sd_mode_type) ? (host->spi_delay_cycle = host->sd_cmd_sample) : (sd_set_sample(host, LL_SDHC_CMD_SMP_CFG_EN, host->sd_cmd_sample, 0)); } else { SDHC_ERR_PRINTF("sd sample point num : %d err\r\n", buf_index); result = RET_ERR; } return result; } uint32 sd_read_dat_sample_retry(struct sdh_device *host, uint8 sample_max, uint8 *p_read, uint8 *p_write) { uint32 result = RET_OK; uint8 buf_index = 0; uint8 sel_index = 0; uint32 ret = 0; uint32 last_ret = MMCSD_INT_VLE; uint32 write_block = 0; for (int i = 0; i < sample_max; i++) { host->sd_read_sample = (i + sample_max - 2) % sample_max; ret = sd_multiple_read(host, 0, SECTOR_SIZE, p_read); if (ret == MMCSD_NO_ERR) { host->sd_read_sample_value[buf_index++] = host->sd_read_sample; } else if (ret == MMCSD_CMD_ERR) { buf_index = 0; result = RET_ERR; break; } else if (!last_ret && (last_ret != ret) && buf_index) { break; } last_ret = ret; } if (buf_index) { write_block = host->card_max_blk_num - sample_max - 1; host->sd_read_sample_num = buf_index; sel_index = (buf_index - 1) >> 1; host->sd_read_sample = (host->sd_read_sample_value[sel_index] == 0) ? (host->sd_read_sample_value[(sel_index + buf_index - 1) % buf_index]) : (host->sd_read_sample_value[sel_index]); ret = sd_multiple_read(host, write_block, SECTOR_SIZE*sample_max, (void *)p_write); if (!ret) { sd_sample_print(host->sd_read_sample_value, buf_index, "read", SD_SAMPLE_VALUE_PRINT); SDHC_WARN_PRINTF("%s %d sd_read_sample : %d\r\n", __func__, __LINE__, host->sd_read_sample); } else { result = RET_ERR; } } else { result = RET_ERR; } return result; } uint32 sd_write_dat_sample_retry(struct sdh_device *host, uint8 sample_max, uint8 *p_write) { uint32 result = RET_OK; uint8 buf_index = 0; uint32 ret = 0; uint32 last_ret = MMCSD_INT_VLE; uint32 write_block = host->card_max_blk_num - sample_max - 1; for (int i = 0; i < sample_max; i++) { host->sd_write_sample = i; ret = sd_multiple_write(host, write_block+i, SECTOR_SIZE, (void *)&p_write[SECTOR_SIZE*i]); if (!ret) { host->sd_write_sample_value[buf_index++] = i; } else if (ret == MMCSD_CMD_ERR) { buf_index = 0; break; } else if (!last_ret && (last_ret != ret) && buf_index) { break; } last_ret = ret; } if (buf_index) { sd_sample_print(host->sd_write_sample_value, buf_index, "write\r\n", SD_SAMPLE_VALUE_PRINT); host->sd_write_sample = host->sd_write_sample_value[(buf_index - 1)>>1]; host->sd_write_sample_num = buf_index; } else { result = RET_ERR; } return result; } uint32 sd_sample_point_cfg(struct sdh_device *host, uint32 clk) { uint32 ret_val = RET_OK; uint32 ret = 0; uint8 flag = 0; uint8 sample_max = 0;//host->io_cfg.crc_sample_max; uint8 *test_data = NULL;//os_malloc(SECTOR_SIZE); uint8 *write_data = NULL;//os_malloc(SECTOR_SIZE * sample_max); uint32 src_clk = host->io_cfg.clock; if ((host->card_type != CARD_TYPE_SD)) { ret_val = RET_ERR; goto __err; } sd_set_clk(host, clk); sample_max = host->io_cfg.crc_sample_max; #if defined(TXW82X) host->spi_mode_baud = sd_spi_mode_baud_cfg(clk); if(!host->sd_read_sample_value ) host->sd_read_sample_value = SDHC_HEAP_MALLOC(sample_max); if(!host->sd_write_sample_value) host->sd_write_sample_value = SDHC_HEAP_MALLOC(sample_max); if(!host->sd_cmd_sample_value ) host->sd_cmd_sample_value = SDHC_HEAP_MALLOC(sample_max); os_printf("read : %08x write : %08x cmd : %08x\r\n", (uint32)host->sd_read_sample_value , (uint32)host->sd_write_sample_value, (uint32)host->sd_cmd_sample_value ); #endif test_data = os_malloc(SECTOR_SIZE); write_data = os_malloc(SECTOR_SIZE * sample_max); if ((test_data == NULL) || (write_data == NULL)|| (!host->sd_read_sample_value) || (!host->sd_write_sample_value) || (!host->sd_cmd_sample_value)) { os_printf("test_data : %08x write_data : %08x num : %d read : %08x write : %08x cmd : %08x err\r\n", (uint32)test_data, (uint32)write_data, sample_max, (uint32)host->sd_read_sample_value, (uint32)host->sd_write_sample_value, (uint32)host->sd_cmd_sample_value); ret_val = RET_ERR; sd_set_clk(host, src_clk); #if defined(TXW82X) host->spi_mode_baud = sd_spi_mode_baud_cfg(src_clk); #endif goto __err; } host->sd_write_dly_chain = 0x3; host->sd_read_dly_chain = 0x0; host->io_cfg.self_adaption_flag = MMCSD_SMP_EN; sd_set_sample(host, LL_SDHC_ALL_SMP_CFG_DIS, 0, 0); os_memset(host->sd_read_sample_value , 0xff, sample_max); os_memset(host->sd_write_sample_value, 0xff, sample_max); os_memset(host->sd_cmd_sample_value , 0xff, sample_max); ret = sd_cmd_sample_retry(host, sample_max); if (ret) { goto __adjust; } else { flag |= SDHC_SMP_CMD_SUCC; } while (1) { ret = sd_read_dat_sample_retry(host, sample_max, test_data, write_data); if (ret) { host->sd_read_dly_chain += 2; if (host->sd_read_dly_chain > 7) goto __adjust; } else { flag |= SDHC_SMP_DAT_SUCC; break; } } while(1) { ret = sd_write_dat_sample_retry(host, sample_max, write_data); if (ret) { host->sd_write_dly_chain += 2; if (host->sd_write_dly_chain > 7) goto __adjust; } else { flag |= SDHC_SMP_WRITE_CRC_SUCC; break; } } __adjust: if(flag != SDHC_SMP_ALL_SUCC) { sd_set_sample(host, LL_SDHC_ALL_SMP_CFG_DIS, 0, 0); SDHC_WARN_PRINTF("******** write : %d read : %d cmd : %d read_chain : %d write_chain : %d***********\r\n", host->sd_write_sample, host->sd_read_sample, host->sd_cmd_sample, host->sd_read_dly_chain, host->sd_write_dly_chain); ret_val = RET_ERR; #if defined(TXW82X) if(host->sd_read_sample_value ) SDHC_HEAP_FREE(host->sd_read_sample_value ); if(host->sd_write_sample_value) SDHC_HEAP_FREE(host->sd_write_sample_value); if(host->sd_cmd_sample_value ) SDHC_HEAP_FREE(host->sd_cmd_sample_value ); #endif } else { SDHC_WARN_PRINTF("******** write : %d read : %d cmd : %d read_chain : %d write_chain : %d***********\r\n", host->sd_write_sample, host->sd_read_sample, host->sd_cmd_sample, host->sd_read_dly_chain, host->sd_write_dly_chain); } __err: // sd_tran_stop(host); if (test_data ) os_free(test_data ); if (write_data) os_free(write_data); return ret_val; } #endif /* flags : TYPE_SDHC_INIT_FLAGS */ uint32 sd_init(struct sdh_device * host, uint32 clk, uint32 flags) { uint32 ret; uint32 resp[4]; uint32 ocr; uint8 bw = 1; SDHC_WARN_PRINTF("open_width:%d\r\n",bw); if(((const struct sdhc_hal_ops *)host->dev.ops)->open) ((const struct sdhc_hal_ops *)host->dev.ops)->open(host,bw, SD_MODE_TYPE); #if defined (TXW82X) host->sd_clk_io = MACRO_PIN(PIN_SDH_CLK); #endif host->opt_timeout = 2; host->cmd12_timeout = 5; host->single_support = flags & SDHC_INIT_FLAGS_SINGLE_BLK_RW_EN; host->busy_filter_cnt = (flags & SDHC_INIT_FLAGS_BUSY_FILTER_EN) ? 2 : 0; sdhost_io_func_init(host->flags&MMCSD_BUSWIDTH_4); SDHC_WARN_PRINTF("host->flags:%x\r\n",host->flags); if(bw == 4) sd_power_up(host,MMCSD_BUSWIDTH_4); else sd_power_up(host,0); void __delay_asm(uint32 n); ret = send_idle(host); if(ret) { SDHC_ERR_PRINTF("idle cmd err\r\n"); return RET_ERR; } delay_us(100); ret = send_if_cond(host,host->valid_ocr); ret = send_app_op_cond(host,0x40ff8000,&ocr); if(ret){ SDHC_ERR_PRINTF("init card err\r\n"); return RET_ERR; } SDHC_WARN_PRINTF("ocr:%x\r\n",ocr); ocr = select_voltage(host,ocr); SDHC_WARN_PRINTF("cur_ocr:%x\r\n",ocr); if (!ocr) { SDHC_ERR_PRINTF("cal ocr error\r\n"); return RET_ERR; } send_idle(host); delay_us(100); ret = send_if_cond(host,ocr); if(ret==0) ocr |= 1 << 30; ret = send_app_op_cond(host,ocr,NULL); if(ret){ SDHC_ERR_PRINTF("init card app_op_cond err\r\n"); return RET_ERR; } send_all_get_cid(host,resp); host->card_type = CARD_TYPE_SD; memcpy(host->resp_cid,resp,sizeof(host->resp_cid)); send_get_card_addr(host,&host->rca); send_get_csd(host,host->resp_csd); sd_parse_csd(host); send_select_card(host); ret = send_get_scr(host,host->resp_scr); if (ret == 0) { SDHC_ERR_PRINTF("get src err\r\n"); return RET_ERR; } sd_parse_scr(host); /*switch bus width*/ if ((host->flags & MMCSD_BUSWIDTH_4) && (host->scr.sd_bus_widths & SD_SCR_BUS_WIDTH_4)) { ret = sd_app_set_bus_width(host, MMCSD_BUS_WIDTH_4); if (ret){ SDHC_ERR_PRINTF("set bus width 4 err\r\n"); return RET_ERR; } sd_set_bus_width(host, MMCSD_BUS_WIDTH_4); } host->sd_opt = SD_IDLE; #if (defined (TXW81X) || defined (TXW82X)) if ((host->flags & MMCSD_SUP_HIGHSPEED) && (!host->io_cfg.self_adaption_flag) && (host->scr.sd_version) && (clk > 25*1000*1000)) { ret = sd_switch(host); if (ret) { sd_set_clk(host, 24*1000*1000); }else{ SDHC_WARN_PRINTF("********** test SD start ********\r\n"); ret = sd_sample_point_cfg(host, clk); SDHC_WARN_PRINTF("********** test SD finish ********\r\n"); if (ret) { SDHC_ERR_PRINTF("set highspeed sampling point err\r\n"); host->io_cfg.self_adaption_flag = MMCSD_SMP_DIS; sd_set_clk(host, 24*1000*1000); } host->io_cfg.self_adaption_flag = MMCSD_SMP_SUCC; } }else{ sd_set_clk(host, 24*1000*1000); } #else sd_set_clk(host, clk); #endif ((struct hgsdh *)host)->opened = 1; #if defined(TXW82X) host->spi_mode_baud =sd_spi_mode_baud_cfg(host->io_cfg.clock); #endif return RET_OK; } extern bool fatfs_register(); extern void fatfs_unregister(); void sd_open() { sdh_test = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID); #if SDH_I2C2_REUSE os_sema_init(&sem,1); #endif } void sdhost_test() { SDHC_WARN_PRINTF("enter sdhost test\r\n"); sdh_test = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID); //sdhost_io_func_init();f sd_init(sdh_test, 24*1000*1000, 0); } struct sdhost_hdl { struct os_work wk; struct sdh_device *host; uint32_t lba; uint8_t opt:3,isregister:1,count:2; }; static struct sdhost_hdl sdhost_wk = { .wk.running=0 }; int32 sdh_loop(struct os_work *work) { struct sdhost_hdl *hdl = (struct sdhost_hdl*)work; struct sdh_device *host = hdl->host; uint32 sleep_time = 500; uint32 ret; if(SD_OFF == host->sd_opt || !hdl->isregister) { SDHC_ERR_PRINTF("sdh no online2\r\n"); if(get_fat_isready()) { fatfs_unregister(); hdl->isregister = 0; } //判断状态,是否重新挂在文件系统 fatfs_register(); if(get_fat_isready()) { hdl->isregister = 1; } } else { ret = os_mutex_lock(&host->lock,0); if(ret) { sleep_time = 1; //获取锁失败 goto sdh_loop_end; } if (host->sd_stop && (SD_IDLE != host->sd_opt)) { if((hdl->opt != host->sd_opt)||(hdl->lba != host->new_lba)) { hdl->opt = host->sd_opt; hdl->lba = host->new_lba; hdl->count = 0; } else { hdl->count++; } } else { ret = send_card_status(host); if(ret != 0) { host->sd_opt = SD_OFF; hdl->count = 0; } } if(hdl->count >= 2) { sd_tran_stop(host); } os_mutex_unlock(&host->lock); } sdh_loop_end: os_run_work_delay(work, sleep_time); return 0; } uint32 sdhost_reinit_for_wakeup() { if(sdhost_wk.wk.init == 0 && sdhost_wk.wk.running == 0) { sdhost_wk.isregister = 1; OS_WORK_INIT(&sdhost_wk.wk, sdh_loop, 0); os_run_work_delay(&sdhost_wk.wk, 500); } } uint32 sdhost_deinit_for_sleep() { uint32 err = 0; struct sdh_device *sdh = NULL; sdh = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID); os_work_cancle2(&sdhost_wk.wk,1); return err; } uint32 sdhost_init(uint32 clk, uint32 flags) { uint32 err = 1; struct sdh_device *sdh = NULL; sdh = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID); #if SDH_I2C2_REUSE os_sema_down(&sem,osWaitForever); #endif if(sdh) { err = sd_init(sdh, clk, flags); if(err) sdh->sd_opt = SD_OFF; if(sdhost_wk.wk.init == 0 && sdhost_wk.wk.running == 0) { sdhost_wk.host = sdh; sdhost_wk.isregister = 1; OS_WORK_INIT(&sdhost_wk.wk, sdh_loop, 0); os_run_work_delay(&sdhost_wk.wk, 500); } } #if SDH_I2C2_REUSE os_sema_up(&sem); #endif return err; } #if SDH_I2C2_REUSE /** * @brief 该函数用于SDH和I2C2端口复用的切换 * * @param sdh_stop_en 停止SDH、使用I2C2,则置1,否则置0 * @return uint32 */ uint32 sdhost_i2c2_exchange(int sdh_stop_en) { if(sdh_stop_en) { os_sema_down(&sem,osWaitForever); os_work_cancle2(&sdhost_wk.wk,1); pin_func(HG_I2C2_DEVID,1); } else { os_sema_up(&sem); OS_WORK_INIT(&sdhost_wk.wk, sdh_loop, 0); os_run_work_delay(&sdhost_wk.wk, 500); } } #endif uint32 get_sdhost_status(struct sdh_device *host) { if(host->sd_opt == SD_OFF) { return 1; } return 0; }