Files
TAIXIN/sdk/lib/sdhost/sdhost.c

1726 lines
49 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 okkick 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;
}