Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources
This commit is contained in:
136
sdk/lib/sdhost/emmc.c
Normal file
136
sdk/lib/sdhost/emmc.c
Normal file
@@ -0,0 +1,136 @@
|
||||
#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 "lib/sdhost/mmc.h"
|
||||
#include "lib/sdhost/mmc_ops.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"
|
||||
|
||||
extern void sdhost_io_func_init(uint32 req);
|
||||
extern uint32 sd_power_up(struct sdh_device *host,uint8 bus_w);
|
||||
extern void sd_set_clk(struct sdh_device * host,uint32 clk);
|
||||
#if 1
|
||||
#define EMMC_PRINTF(fmt, arg...) printf(fmt, ##arg)
|
||||
#else
|
||||
#define EMMC_PRINTF(fmt, arg...)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
uint32_t send_op_cond(struct sdh_device *host,
|
||||
uint32_t ocr,
|
||||
uint32_t *rocr)
|
||||
{
|
||||
struct rt_mmcsd_cmd cmd;
|
||||
int ret;
|
||||
memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
cmd.cmd_code = SEND_OP_COND;
|
||||
cmd.arg = ocr;
|
||||
cmd.flags = RESP_SPI_R1 | RESP_R3 | CMD_BCR;
|
||||
|
||||
ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd);
|
||||
if(ret){
|
||||
EMMC_PRINTF("cmd%d err\r\n", cmd.cmd_code);
|
||||
}
|
||||
EMMC_PRINTF("cmd resp:%x\r\n",cmd.resp[0]);
|
||||
|
||||
if(rocr)
|
||||
*rocr = cmd.resp[0];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int emmc_init(struct sdh_device * host, uint32 clk)
|
||||
{
|
||||
uint32_t ocr;
|
||||
uint8_t bw = 1;
|
||||
uint8_t *ext_csd = NULL;
|
||||
|
||||
if(((const struct sdhc_hal_ops *)host->dev.ops)->open)
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->open(host, 1, SD_MODE_TYPE);
|
||||
|
||||
host->flags |= MMCSD_BUSWIDTH_4;
|
||||
os_printf("host->flags:%x\r\n",host->flags);
|
||||
sdhost_io_func_init(host->flags);
|
||||
|
||||
|
||||
if(bw == 4)
|
||||
sd_power_up(host, MMCSD_BUSWIDTH_4);
|
||||
else
|
||||
sd_power_up(host,0);
|
||||
|
||||
sd_set_clk(host, 400*1000);
|
||||
|
||||
send_idle(host);
|
||||
|
||||
send_op_cond(host, 0x40FF8080, &ocr);
|
||||
while(!(ocr & 0x80000000))
|
||||
{
|
||||
os_sleep_ms(5);
|
||||
send_op_cond(host, 0x40FF8080, &ocr);
|
||||
}
|
||||
|
||||
send_all_get_cid(host, host->resp_cid);
|
||||
|
||||
EMMC_PRINTF("cid0: 0x%x cid1: 0x%x\r\n", host->resp_cid[0], host->resp_cid[1]);
|
||||
|
||||
host->rca = 1;
|
||||
mmc_set_card_addr(host, host->rca);
|
||||
|
||||
EMMC_PRINTF("rca: 0x%x\r\n", host->rca);
|
||||
|
||||
//解析csd (to do)
|
||||
send_get_csd(host, host->resp_csd);
|
||||
host->card_blksize = 1 << GET_BITS(host->resp_csd, 80, 4);
|
||||
EMMC_PRINTF("emmc spec verision: 0x%x\r\n", GET_BITS(host->resp_csd, 122, 4));
|
||||
EMMC_PRINTF("max clock frequency %d\r\n", GET_BITS(host->resp_csd, 96, 3) * GET_BITS(host->resp_csd, 99, 4));
|
||||
EMMC_PRINTF("block len: %d\r\n", host->card_blksize);
|
||||
|
||||
//select card
|
||||
send_select_card(host);
|
||||
|
||||
//解析ext_csd (to do)
|
||||
ext_csd = os_malloc(512);
|
||||
if(!ext_csd) {
|
||||
EMMC_PRINTF("ext_csd malloc fail\r\n");
|
||||
}
|
||||
|
||||
mmc_get_ext_csd(host, ext_csd);
|
||||
|
||||
mmc_parse_ext_csd(host, ext_csd);
|
||||
|
||||
//切换bus width
|
||||
// mmc_select_bus_width(host, ext_csd);
|
||||
|
||||
//配置驱动能力
|
||||
|
||||
|
||||
//设置频率 & 采样调谐
|
||||
#ifndef FPGA_SUPPORT
|
||||
|
||||
#endif
|
||||
|
||||
sd_set_clk(host, clk);
|
||||
|
||||
host->cardflags |= CARD_FLAG_SDHC;
|
||||
|
||||
os_free(ext_csd);
|
||||
EMMC_PRINTF("emmc init done\r\n");
|
||||
return 0;
|
||||
}
|
||||
284
sdk/lib/sdhost/mmc_cq.c
Normal file
284
sdk/lib/sdhost/mmc_cq.c
Normal file
@@ -0,0 +1,284 @@
|
||||
#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/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"
|
||||
#include "lib/sdhost/sdhost.h"
|
||||
#include "lib/sdhost/mmc.h"
|
||||
#include "lib/sdhost/mmc_ops.h"
|
||||
#include "lib/common/rbuffer.h"
|
||||
#include "hal/gpio.h"
|
||||
|
||||
|
||||
#define QSR_SET(n, qsr) (qsr) |= (1<<(n))
|
||||
#define QSR_CLR(n, qsr) (qsr) &= ~(1<<(n))
|
||||
#define QSR_ISSET(n, qsr) ((qsr) & (1<<(n)))
|
||||
|
||||
#define TID_CNT (16)
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
|
||||
uint32 blks :16,
|
||||
tid : 5,
|
||||
rev : 2,
|
||||
prio : 1,
|
||||
forced : 1,
|
||||
cid : 4,
|
||||
is_tag : 1,
|
||||
dir : 1,
|
||||
rwrq : 1;
|
||||
} field;
|
||||
uint32 w;
|
||||
} TASK_ARG;
|
||||
|
||||
struct cq_req {
|
||||
TASK_ARG arg;
|
||||
uint32 lba;
|
||||
uint8 *data;
|
||||
void (*cb)(void* arg);
|
||||
void *cb_arg;
|
||||
};
|
||||
|
||||
struct cqe_mgr {
|
||||
uint32 tmask;
|
||||
struct cq_req * reqs[32];
|
||||
struct os_mutex lock;
|
||||
struct os_mutex tid_lock;
|
||||
struct os_semaphore tid_src;
|
||||
struct os_semaphore req_done;
|
||||
// RBUFFER_DEF_R(reqs, struct cq_req);
|
||||
};
|
||||
|
||||
struct cqe_mgr g_cqe;
|
||||
|
||||
int tid_alloc()
|
||||
{
|
||||
int tid = -1;
|
||||
os_sema_down(&g_cqe.tid_src, osWaitForever);
|
||||
for(int i = 0;i<TID_CNT;i++)
|
||||
{
|
||||
if(!QSR_ISSET(i, g_cqe.tmask)) {
|
||||
QSR_SET(i, g_cqe.tmask);
|
||||
tid = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("tid: %d alloc\r\n", tid);
|
||||
return tid;
|
||||
}
|
||||
|
||||
void tid_free(int tid)
|
||||
{
|
||||
QSR_CLR(tid, g_cqe.tmask);
|
||||
printf("tid: %d free\r\n", tid);
|
||||
os_sema_up(&g_cqe.tid_src);
|
||||
}
|
||||
|
||||
int mmc_enqueue_task(struct sdh_device *host, uint32 lba, TASK_ARG arg)
|
||||
{
|
||||
int err = 0;
|
||||
struct rt_mmcsd_cmd cmd44;
|
||||
struct rt_mmcsd_cmd cmd45;
|
||||
|
||||
cmd44.cmd_code = MMC_QUE_TASK_PARAMS;
|
||||
cmd44.arg = arg.w;
|
||||
cmd44.flags = RESP_R1 | CMD_AC;
|
||||
|
||||
cmd45.cmd_code = MMC_QUE_TASK_ADDR;
|
||||
cmd45.arg = lba;
|
||||
cmd45.flags = RESP_R1 | CMD_AC;
|
||||
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd44);
|
||||
err |= ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd45);
|
||||
if(err) {
|
||||
printf("task enqueue fail\r\n");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_rtask_exe(struct sdh_device *host, uint8 *buf, TASK_ARG arg)
|
||||
{
|
||||
int err = 0;
|
||||
struct rt_mmcsd_cmd cmd46;
|
||||
printf("rtask_Exe: tid=[%d]\r\n", arg.field.tid);
|
||||
cmd46.cmd_code = MMC_EXECUTE_READ_TASK;
|
||||
cmd46.arg = arg.w;
|
||||
cmd46.flags = RESP_R1 | CMD_ADTC;
|
||||
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd46);
|
||||
|
||||
host->data.blksize = SECTOR_SIZE;
|
||||
host->data.buf = buf;
|
||||
host->data.blks = arg.field.blks;
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->read(host, buf);
|
||||
|
||||
if(((const struct sdhc_hal_ops *)host->dev.ops)->complete) {
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->complete(host);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_wtask_exe(struct sdh_device *host, uint8 *buf, TASK_ARG arg)
|
||||
{
|
||||
int err = 0;
|
||||
struct rt_mmcsd_cmd cmd47;
|
||||
|
||||
cmd47.cmd_code = MMC_EXECUTE_WRITE_TASK;
|
||||
cmd47.arg = arg.w;
|
||||
cmd47.flags = RESP_R1 | CMD_ADTC;
|
||||
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd47);
|
||||
|
||||
host->data.blksize = SECTOR_SIZE;
|
||||
host->data.buf = buf;
|
||||
host->data.blks = arg.field.blks;
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->write(host, buf);
|
||||
|
||||
if(((const struct sdhc_hal_ops *)host->dev.ops)->complete) {
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->complete(host);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
void mmc_dequeue_task(struct sdh_device *host, uint8 *buf, TASK_ARG arg)
|
||||
{
|
||||
if(arg.field.dir == 1) {
|
||||
mmc_rtask_exe(host, buf, arg);
|
||||
} else {
|
||||
mmc_wtask_exe(host, buf, arg);
|
||||
}
|
||||
}
|
||||
//cmd queue function
|
||||
int mmc_send_qsr(struct sdh_device *host, uint32* qsr)
|
||||
{
|
||||
if(os_mutex_lock(&g_cqe.lock, 2000)) {
|
||||
return 1;
|
||||
}
|
||||
int err;
|
||||
struct rt_mmcsd_cmd cmd;
|
||||
|
||||
cmd.cmd_code = SEND_STATUS;
|
||||
cmd.arg = host->rca << 16 | (1<<15);
|
||||
cmd.flags = RESP_R1 | CMD_AC;
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (qsr)
|
||||
*qsr = cmd.resp[0];
|
||||
os_mutex_unlock(&g_cqe.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_cqe_req(struct sdh_device* host, struct cq_req* req)
|
||||
{
|
||||
if(os_mutex_lock(&g_cqe.lock, 2000)) {
|
||||
return 1;
|
||||
}
|
||||
int tid = tid_alloc();
|
||||
int ret = 0;
|
||||
if(tid == -1) {
|
||||
ret |= 1;
|
||||
goto _mmc_cqe_req_end;
|
||||
}
|
||||
|
||||
req->arg.field.tid = tid;
|
||||
g_cqe.reqs[tid] = req;
|
||||
mmc_enqueue_task(host, req->lba, req->arg);
|
||||
os_sema_up(&g_cqe.req_done);
|
||||
printf("req cmdq tid: %d lba: %d\t\n", req->arg.field.tid, req->lba);
|
||||
_mmc_cqe_req_end:
|
||||
os_mutex_unlock(&g_cqe.lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mmc_cqe_ereq(struct sdh_device* host, uint32 qsr)
|
||||
{
|
||||
os_mutex_lock(&g_cqe.lock, osWaitForever);
|
||||
for(int tid = 0;tid<TID_CNT;tid++)
|
||||
{
|
||||
if(QSR_ISSET(tid, qsr)) {
|
||||
printf("qsr: 0x%x, [tid]: [%d], [req_arg]: 0x%x\r\n", qsr, tid, g_cqe.reqs[tid]->arg.w);
|
||||
mmc_dequeue_task(host, g_cqe.reqs[tid]->data, (TASK_ARG)(uint32)(tid << 16));
|
||||
tid_free(tid);
|
||||
}
|
||||
}
|
||||
os_mutex_unlock(&g_cqe.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cqe_task_func(void *arg)
|
||||
{
|
||||
uint32 qsr;
|
||||
struct sdh_device *host = (struct sdh_device*)arg;
|
||||
while(1)
|
||||
{
|
||||
os_sema_down(&g_cqe.req_done, osWaitForever);
|
||||
qsr = 0;
|
||||
mmc_send_qsr(host, &qsr);
|
||||
if(!qsr) {
|
||||
os_sema_up(&g_cqe.req_done);
|
||||
continue;
|
||||
}
|
||||
mmc_cqe_ereq(host, qsr);
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
|
||||
struct os_task cqe_task;
|
||||
int mmc_cqe_init(struct sdh_device *host)
|
||||
{
|
||||
g_cqe.tmask = 0;
|
||||
os_mutex_init(&g_cqe.lock);
|
||||
os_mutex_init(&g_cqe.tid_lock);
|
||||
os_sema_init(&g_cqe.req_done, 0);
|
||||
os_sema_init(&g_cqe.tid_src, TID_CNT);
|
||||
|
||||
//cmd queue en
|
||||
if(mmc_cmdq_switch(host, 1)) {
|
||||
printf("%s fail\r\n", __FUNCTION__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
OS_TASK_INIT("mmc_cqe", &cqe_task, cqe_task_func, host, OS_TASK_PRIORITY_NORMAL, NULL, 2048);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void cqe_test(struct sdh_device* host)
|
||||
{
|
||||
emmc_init(host, 1000*1000);
|
||||
if(mmc_cqe_init(host)) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct cq_req req = {
|
||||
.arg.w = (1<<30) | 1,
|
||||
.lba = 0,
|
||||
};
|
||||
req.data = os_malloc(512);
|
||||
while(1)
|
||||
{
|
||||
req.lba *= 1664525;
|
||||
req.lba += 1013904223;
|
||||
req.lba &= 0x3ff;
|
||||
if(mmc_cqe_req(host, &req)) {
|
||||
os_sleep_ms(1);
|
||||
}
|
||||
// os_sleep_ms(5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
336
sdk/lib/sdhost/mmc_fs.c
Normal file
336
sdk/lib/sdhost/mmc_fs.c
Normal file
@@ -0,0 +1,336 @@
|
||||
#include "sys_config.h"
|
||||
#include "typesdef.h"
|
||||
#include "devid.h"
|
||||
#include "list.h"
|
||||
#include "dev.h"
|
||||
|
||||
#include "hal/gpio.h"
|
||||
#include "osal/irq.h"
|
||||
#include "osal/string.h"
|
||||
#include "osal/semaphore.h"
|
||||
#include "osal/mutex.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"
|
||||
|
||||
#include "lib/sdhost/sdhost.h"
|
||||
#include "lib/sdhost/mmc.h"
|
||||
#include "lib/sdhost/mmc_ops.h"
|
||||
|
||||
#include "fatfs/integer.h"
|
||||
#include "fatfs/diskio.h"
|
||||
#include "fatfs/ff.h"
|
||||
|
||||
#if 0
|
||||
#define MMCFS_PRIN(fmt, arg...) printf(fmt, ##arg)
|
||||
#else
|
||||
#define MMCFS_PRIN(fmt, arg...)
|
||||
#endif
|
||||
|
||||
|
||||
static DSTATUS fatfs_status(void *status);
|
||||
static DSTATUS fatfs_init(void *init_dev);
|
||||
static DRESULT fatfs_read(void *dev, BYTE* buf, DWORD sector, UINT count);
|
||||
static DRESULT fatfs_write(void *dev, BYTE* buf, DWORD sector, UINT count);
|
||||
static DRESULT fatfs_ioctl(void *init_dev, BYTE cmd, void* buf);
|
||||
void mmc_fatfs_unregister(uint32_t dev_id);
|
||||
int mmc_fatfs_register(uint32_t dev_id);
|
||||
uint32_t get_sdhost_status(struct sdh_device *host);
|
||||
uint32_t sd_tran_stop(struct sdh_device * host);
|
||||
|
||||
extern void sdhost_io_func_init(uint32 req);
|
||||
extern uint32 sd_power_up(struct sdh_device *host,uint8 bus_w);
|
||||
extern void sd_set_clk(struct sdh_device * host,uint32 clk);
|
||||
|
||||
|
||||
static struct os_work host_wk = {
|
||||
.running=0
|
||||
};
|
||||
|
||||
static int32 sdh_loop(struct os_work *work)
|
||||
{
|
||||
struct sdh_device *host = NULL;
|
||||
host = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID);
|
||||
static uint8_t opt = SD_IDLE;
|
||||
static uint32_t lba = 0;
|
||||
static uint8_t flag = 0;
|
||||
static uint8_t count = 0;
|
||||
uint32_t sleep_time = 500;
|
||||
uint32 ret;
|
||||
|
||||
if(SD_OFF == host->sd_opt)
|
||||
{
|
||||
os_printf("sdh no online2\r\n");
|
||||
if(flag == 1)
|
||||
{
|
||||
flag = 0;
|
||||
os_mutex_del(&host->lock);
|
||||
mmc_fatfs_unregister(HG_SDIOHOST_DEVID);
|
||||
}
|
||||
|
||||
//判断状态,是否重新挂在文件系统
|
||||
mmc_fatfs_register(HG_SDIOHOST_DEVID);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = os_mutex_lock(&host->lock,0);
|
||||
if(ret)
|
||||
{
|
||||
sleep_time = 1;
|
||||
//获取锁失败
|
||||
goto sdh_loop_end;
|
||||
}
|
||||
if(SD_IDLE != host->sd_opt)
|
||||
{
|
||||
if((opt != host->sd_opt)||(lba != host->new_lba))
|
||||
{
|
||||
opt = host->sd_opt;
|
||||
lba = host->new_lba;
|
||||
count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = send_card_status(host);
|
||||
if(ret != 0)
|
||||
{
|
||||
host->sd_opt = SD_OFF;
|
||||
count = 0;
|
||||
flag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(count >= 2){
|
||||
count = 0;
|
||||
sd_tran_stop(host);
|
||||
}
|
||||
os_mutex_unlock(&host->lock);
|
||||
}
|
||||
sdh_loop_end:
|
||||
os_run_work_delay(work, sleep_time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_init(struct sdh_device * host, uint32_t clk)
|
||||
{
|
||||
uint32_t ret;
|
||||
uint32_t ocr;
|
||||
uint8_t bw = 1;
|
||||
uint8_t *ext_csd = NULL;
|
||||
|
||||
|
||||
if(((const struct sdhc_hal_ops *)host->dev.ops)->open)
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->open(host, 1, SD_MODE_TYPE);
|
||||
os_mutex_init(&host->lock);
|
||||
|
||||
sdhost_io_func_init(host->flags);
|
||||
|
||||
if(bw == 4)
|
||||
sd_power_up(host, MMCSD_BUSWIDTH_4);
|
||||
else
|
||||
sd_power_up(host,0);
|
||||
|
||||
sd_set_clk(host, 400*1000);
|
||||
|
||||
send_idle(host);
|
||||
|
||||
send_op_cond(host, 0x40FF8080, &ocr);
|
||||
while(!(ocr & 0x80000000))
|
||||
{
|
||||
os_sleep_ms(5);
|
||||
send_op_cond(host, 0x40FF8080, &ocr);
|
||||
}
|
||||
|
||||
send_all_get_cid(host, host->resp_cid);
|
||||
|
||||
host->rca = 1;
|
||||
mmc_set_card_addr(host, host->rca);
|
||||
|
||||
//解析csd (to do)
|
||||
send_get_csd(host, host->resp_csd);
|
||||
host->card_blksize = 1 << GET_BITS(host->resp_csd, 80, 4);
|
||||
|
||||
//select card
|
||||
send_select_card(host);
|
||||
|
||||
//解析ext_csd (to do)
|
||||
ext_csd = os_malloc(512);
|
||||
if(!ext_csd) {
|
||||
printf("ext_csd malloc fail\r\n");
|
||||
}
|
||||
|
||||
ret = mmc_get_ext_csd(host, ext_csd);
|
||||
|
||||
//de select
|
||||
host->rca = 0;
|
||||
send_select_card(host);
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->close(host);
|
||||
os_free(ext_csd);
|
||||
|
||||
|
||||
if(ret == 1) {
|
||||
//sd 卡
|
||||
host->card_type = CARD_TYPE_SD;
|
||||
sd_init(host, clk, 0);
|
||||
} else {
|
||||
host->card_type = CARD_TYPE_MMC;
|
||||
emmc_init(host, clk);
|
||||
}
|
||||
|
||||
if(host_wk.running == 0)
|
||||
{
|
||||
OS_WORK_INIT(&host_wk, sdh_loop, 0);
|
||||
os_run_work_delay(&host_wk, 500);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static struct fatfs_diskio sdcdisk_driver = {
|
||||
.status = fatfs_status,
|
||||
.init = fatfs_init,
|
||||
.read = fatfs_read,
|
||||
.write = fatfs_write,
|
||||
.ioctl = fatfs_ioctl
|
||||
};
|
||||
|
||||
|
||||
static DSTATUS fatfs_status(void *status){
|
||||
//TEST_INFO_SHOW ("fatfs_status_test\r\n");
|
||||
DSTATUS err = get_sdhost_status(status);
|
||||
return err;
|
||||
}
|
||||
|
||||
static DSTATUS fatfs_init(void *init_dev){
|
||||
//TEST_INFO_SHOW ("fatfs_init_test\r\n");
|
||||
DSTATUS err;
|
||||
err = mmc_init((struct sdh_device*)init_dev, 24*1000*1000);
|
||||
return err;
|
||||
}
|
||||
|
||||
static DRESULT fatfs_read(void *dev, BYTE* buf, DWORD sector, UINT count){
|
||||
DRESULT err;
|
||||
|
||||
err = sd_multiple_read((struct sdh_device*)dev, sector, count*512, buf);
|
||||
MMCFS_PRIN ("fatfs_read_test:%d %x %d %d\r\n",sector,buf,count, err);
|
||||
//printf("E");
|
||||
return err;
|
||||
}
|
||||
|
||||
static DRESULT fatfs_write(void *dev, BYTE* buf, DWORD sector, UINT count){
|
||||
DRESULT err;
|
||||
|
||||
err = sd_multiple_write((struct sdh_device*)dev,sector,count*512,buf);
|
||||
MMCFS_PRIN ("fatfs_write_test:%d %x %d %d\r\n",sector,buf,count, err);
|
||||
//printf("E");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
extern uint32 fatfs_sd_tran_stop(struct sdh_device * host);
|
||||
static DRESULT fatfs_ioctl(void *init_dev, BYTE cmd, void* buf){
|
||||
uint8 ret = RES_OK;
|
||||
switch(cmd)
|
||||
{
|
||||
case CTRL_SYNC:
|
||||
fatfs_sd_tran_stop(init_dev);
|
||||
break;
|
||||
case GET_SECTOR_COUNT:
|
||||
*(DWORD *)buf = ((struct sdh_device *)init_dev)->card_capacity * 2;
|
||||
ret = RES_OK;
|
||||
break;
|
||||
|
||||
case GET_SECTOR_SIZE:
|
||||
*(WORD *)buf = 512;
|
||||
ret = RES_OK;
|
||||
|
||||
break;
|
||||
case GET_BLOCK_SIZE:
|
||||
*(DWORD *)buf = 4;
|
||||
// printf("*0B:%d\n",*B);
|
||||
ret = RES_OK;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = RES_ERROR; //not finish
|
||||
printf("rtos_sd_ioctl err\n");
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
FATFS fatfs[2];
|
||||
int mmc_fatfs_register(uint32_t dev_id){
|
||||
|
||||
int ret = 1;
|
||||
int ldnum;
|
||||
char vpath[8];
|
||||
struct sdh_device *fatfs_sdh;
|
||||
|
||||
printf("enter %s test\r\n", __func__);
|
||||
fatfs_sdh = (struct sdh_device *)dev_get(dev_id);
|
||||
|
||||
if(dev_id == HG_SDIOHOST_DEVID) {
|
||||
ldnum = 1;
|
||||
} else if(dev_id == HG_SDIOHOST1_DEVID) {
|
||||
ldnum = 2;
|
||||
} else {
|
||||
os_printf("%s err parameter\r\n", __FUNCTION__);
|
||||
return 1;
|
||||
}
|
||||
sprintf(vpath, "%d:", ldnum);
|
||||
|
||||
if(fatfs_sdh)
|
||||
{
|
||||
fatfs_register_drive(ldnum, &sdcdisk_driver, fatfs_sdh);
|
||||
ret = f_mount (&fatfs[ldnum-1], vpath, 1);
|
||||
if (ret) {
|
||||
printf("%s ret:%d\n",__FUNCTION__,ret);
|
||||
f_mount (NULL, vpath, 0);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
printf("mmc fatfs mounted\r\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mmc_fatfs_unregister(uint32_t dev_id)
|
||||
{
|
||||
int ret = 1;
|
||||
int ldnum;
|
||||
char vpath[8];
|
||||
struct sdh_device *fatfs_sdh;
|
||||
fatfs_sdh = (struct sdh_device *)dev_get(HG_SDIOHOST_DEVID);
|
||||
if(dev_id == HG_SDIOHOST_DEVID) {
|
||||
ldnum = 1;
|
||||
} else if(dev_id == HG_SDIOHOST1_DEVID) {
|
||||
ldnum = 2;
|
||||
} else {
|
||||
os_printf("%s err parameter\r\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
sprintf(vpath, "%d:", ldnum);
|
||||
|
||||
if(fatfs_sdh)
|
||||
{
|
||||
ret = f_mount (NULL, vpath, 1);
|
||||
fatfs_register_drive(ldnum, NULL, NULL);
|
||||
if (ret) {
|
||||
printf("%s ret:%d\n",__FUNCTION__,ret);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
517
sdk/lib/sdhost/mmc_ops.c
Normal file
517
sdk/lib/sdhost/mmc_ops.c
Normal file
@@ -0,0 +1,517 @@
|
||||
#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 "lib/sdhost/mmc.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"
|
||||
|
||||
|
||||
#if 1
|
||||
#define EMMC_PRINTF(fmt, arg...) printf(fmt, ##arg)
|
||||
#else
|
||||
#define EMMC_PRINTF(fmt, arg...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Read extended CSD.
|
||||
*/
|
||||
int mmc_get_ext_csd(struct sdh_device *host, uint8_t *ext_csd)
|
||||
{
|
||||
int ret;
|
||||
struct rt_mmcsd_cmd cmd;
|
||||
struct rt_mmcsd_data data;
|
||||
|
||||
if (GET_BITS(host->resp_csd, 122, 4) < 4) {
|
||||
EMMC_PRINTF("can't get ext csd\r\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* As the ext_csd is so large and mostly unused, we don't store the
|
||||
* raw block in mmc_card.
|
||||
*/
|
||||
|
||||
memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
memset(&data, 0, sizeof(struct rt_mmcsd_data));
|
||||
|
||||
cmd.cmd_code = SEND_EXT_CSD;
|
||||
cmd.arg = 0;
|
||||
|
||||
/* NOTE HACK: the RESP_SPI_R1 is always correct here, but we
|
||||
* rely on callers to never use this with "native" calls for reading
|
||||
* CSD or CID. Native versions of those commands use the R2 type,
|
||||
* not R1 plus a data block.
|
||||
*/
|
||||
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
|
||||
|
||||
host->data.blksize = 512;
|
||||
host->data.blks = 1;
|
||||
host->data.flags = DATA_DIR_READ;
|
||||
host->data.buf = ext_csd;
|
||||
|
||||
/*
|
||||
* Some cards require longer data read timeout than indicated in CSD.
|
||||
* Address this by setting the read timeout to a "reasonably high"
|
||||
* value. For the cards tested, 300ms has proven enough. If necessary,
|
||||
* this value can be increased if other problematic cards require this.
|
||||
*/
|
||||
host->data.timeout_ns = 300000000;
|
||||
host->data.timeout_clks = 0;
|
||||
|
||||
ret = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd);
|
||||
if(ret) {
|
||||
EMMC_PRINTF("%s cmd error\r\n", __FUNCTION__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = ((const struct sdhc_hal_ops *)host->dev.ops)->read(host, ext_csd);
|
||||
|
||||
if (((const struct sdhc_hal_ops *)host->dev.ops)->complete)
|
||||
ret |= ((const struct sdhc_hal_ops *)host->dev.ops)->complete(host);
|
||||
|
||||
if(ret) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_parse_ext_csd(struct sdh_device *host, uint8_t *ext_csd)
|
||||
{
|
||||
uint32_t card_capacity = 0;
|
||||
if (ext_csd == NULL)
|
||||
{
|
||||
EMMC_PRINTF("emmc parse ext csd fail, invaild args");
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
// uint8_t device_type = ext_csd[EXT_CSD_CARD_TYPE];
|
||||
// if ((host->flags & MMCSD_SUP_HS400) && (device_type & EXT_CSD_CARD_TYPE_HS400))
|
||||
// {
|
||||
// card->flags |= CARD_FLAG_HS400;
|
||||
// card->max_data_rate = 200000000;
|
||||
// }
|
||||
// else if ((host->flags & MMCSD_SUP_HS200) && (device_type & EXT_CSD_CARD_TYPE_HS200))
|
||||
// {
|
||||
// card->flags |= CARD_FLAG_HS200;
|
||||
// card->max_data_rate = 200000000;
|
||||
// }
|
||||
// else if ((host->flags & MMCSD_SUP_HIGHSPEED_DDR) && (device_type & EXT_CSD_CARD_TYPE_DDR_52))
|
||||
// {
|
||||
// card->flags |= CARD_FLAG_HIGHSPEED_DDR;
|
||||
// card->hs_max_data_rate = 52000000;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// card->flags |= CARD_FLAG_HIGHSPEED;
|
||||
// card->hs_max_data_rate = 52000000;
|
||||
// }
|
||||
|
||||
// host->flags |= CARD_FLAG_HIGHSPEED;
|
||||
// card->hs_max_data_rate = 52000000;
|
||||
|
||||
// if (ext_csd[EXT_CSD_STROBE_SUPPORT] != 0)
|
||||
// {
|
||||
// card->ext_csd.enhanced_data_strobe = 1;
|
||||
// }
|
||||
|
||||
// host->ext_csd.cache_size =
|
||||
// ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
|
||||
// ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
|
||||
// ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
|
||||
// ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
|
||||
|
||||
card_capacity = *((uint32_t*)&ext_csd[EXT_CSD_SEC_CNT]);
|
||||
card_capacity /= 2; //unit: KB
|
||||
host->card_capacity = card_capacity;
|
||||
|
||||
EMMC_PRINTF("emmc card capacity %d KB, card sec count:0x%x \r\n", card_capacity, card_capacity*2);
|
||||
EMMC_PRINTF("bus mode: %d\r\n", ext_csd[EXT_CSD_BUS_WIDTH]);
|
||||
// switch (ext_csd[EXT_CSD_PART_CONFIG] & 7)
|
||||
// {
|
||||
// case 0:
|
||||
// EMMC_PRINTF("access default partition\r\n");
|
||||
// break;
|
||||
// case 1:
|
||||
// case 2:
|
||||
// EMMC_PRINTF("access boot partition-%d\r\n", (ext_csd[EXT_CSD_PART_CONFIG]&7));
|
||||
// break;
|
||||
// case 3:
|
||||
// EMMC_PRINTF("access RPMB partition\r\n");
|
||||
// break;
|
||||
// case 4:
|
||||
// case 5:
|
||||
// case 6:
|
||||
// case 7:
|
||||
// EMMC_PRINTF("access to gp partition-%d\r\n", (ext_csd[EXT_CSD_PART_CONFIG]&7) - 3);
|
||||
// break;
|
||||
// default:
|
||||
// EMMC_PRINTF("access to ?\r\n");
|
||||
// }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_switch(struct sdh_device *host, uint8_t set, uint8_t index, uint8_t value)
|
||||
{
|
||||
int err;
|
||||
struct rt_mmcsd_cmd cmd = {0};
|
||||
|
||||
cmd.cmd_code = SWITCH;
|
||||
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
|
||||
(index << 16) | (value << 8) | set;
|
||||
cmd.flags = RESP_R1B | CMD_AC;
|
||||
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_compare_ext_csds(struct sdh_device *host, uint8_t *ext_csd, uint32_t bus_width)
|
||||
{
|
||||
uint8_t *bw_ext_csd = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (bus_width == MMCSD_BUS_WIDTH_1)
|
||||
return 0;
|
||||
|
||||
bw_ext_csd = os_malloc(512);
|
||||
if(!bw_ext_csd) {
|
||||
EMMC_PRINTF("%s malloc fail\r\n", __FUNCTION__);
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
err = mmc_get_ext_csd(host, bw_ext_csd);
|
||||
|
||||
/* only compare read only fields */
|
||||
err = !((ext_csd[EXT_CSD_PARTITION_SUPPORT] == bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
|
||||
(ext_csd[EXT_CSD_ERASED_MEM_CONT] == bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
|
||||
(ext_csd[EXT_CSD_REV] == bw_ext_csd[EXT_CSD_REV]) &&
|
||||
(ext_csd[EXT_CSD_STRUCTURE] == bw_ext_csd[EXT_CSD_STRUCTURE]) &&
|
||||
(ext_csd[EXT_CSD_CARD_TYPE] == bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
|
||||
(ext_csd[EXT_CSD_S_A_TIMEOUT] == bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
|
||||
(ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
|
||||
(ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] == bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
|
||||
(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
|
||||
(ext_csd[EXT_CSD_SEC_TRIM_MULT] == bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
|
||||
(ext_csd[EXT_CSD_SEC_ERASE_MULT] == bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
|
||||
(ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] == bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
|
||||
(ext_csd[EXT_CSD_TRIM_MULT] == bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
|
||||
(ext_csd[EXT_CSD_SEC_CNT + 0] == bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
|
||||
(ext_csd[EXT_CSD_SEC_CNT + 1] == bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
|
||||
(ext_csd[EXT_CSD_SEC_CNT + 2] == bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
|
||||
(ext_csd[EXT_CSD_SEC_CNT + 3] == bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_26_195] == bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_26_360] == bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_200_195] == bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_DDR_52_195] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_DDR_52_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
|
||||
(ext_csd[EXT_CSD_PWR_CL_DDR_200_360] == bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
|
||||
|
||||
if (err)
|
||||
err = -RET_ERR;
|
||||
|
||||
os_free(bw_ext_csd);
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_select_bus_width(struct sdh_device *host, uint8_t *ext_csd)
|
||||
{
|
||||
|
||||
unsigned bus_width = 0;
|
||||
int err = 0;
|
||||
|
||||
if (GET_BITS(host->resp_csd, 122, 4) < 4)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Unlike SD, MMC cards don't have a configuration register to notify
|
||||
* supported bus width. So bus test command should be run to identify
|
||||
* the supported bus width or compare the EXT_CSD values of current
|
||||
* bus width and EXT_CSD values of 1 bit mode read earlier.
|
||||
*/
|
||||
|
||||
err = mmc_switch(host, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
EXT_CSD_BUS_WIDTH_4);
|
||||
|
||||
//2就是EXT_CSD_BUS_WIDTH_4
|
||||
sd_set_bus_width(host, 2);
|
||||
err = mmc_compare_ext_csds(host, ext_csd, bus_width);
|
||||
|
||||
if(err) {
|
||||
mmc_switch(host, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
EXT_CSD_BUS_WIDTH_1);
|
||||
//0就是EXT_CSD_BUS_WIDTH_1
|
||||
sd_set_bus_width(host, 0);
|
||||
err = mmc_compare_ext_csds(host, ext_csd, bus_width);
|
||||
if(err) {
|
||||
EMMC_PRINTF("%s dangenrous error ocurr\r\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
EMMC_PRINTF("bus width: %d\r\n", 1 << host->io_cfg.bus_width);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmc_set_card_addr(struct sdh_device *host, uint32_t rca)
|
||||
{
|
||||
int err;
|
||||
struct rt_mmcsd_cmd cmd;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
|
||||
cmd.cmd_code = SET_RELATIVE_ADDR;
|
||||
cmd.arg = rca << 16;
|
||||
cmd.flags = RESP_R1 | CMD_AC;
|
||||
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __send_status(struct sdh_device *host, uint32_t *status, unsigned retries)
|
||||
{
|
||||
int err;
|
||||
struct rt_mmcsd_cmd cmd;
|
||||
|
||||
cmd.cmd_code = SEND_STATUS;
|
||||
cmd.arg = host->rca << 16;
|
||||
cmd.flags = RESP_R1 | CMD_AC;
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (status)
|
||||
*status = cmd.resp[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int card_busy_detect(struct sdh_device *host, unsigned int timeout_ms,
|
||||
uint32_t *resp_errs)
|
||||
{
|
||||
int err = 0;
|
||||
uint32_t status;
|
||||
uint32_t start;
|
||||
uint32_t is_to;
|
||||
|
||||
start = os_jiffies();
|
||||
do
|
||||
{
|
||||
is_to = (int)(os_jiffies() - start) > timeout_ms;
|
||||
|
||||
err = __send_status(host, &status, 5);
|
||||
if (err)
|
||||
{
|
||||
EMMC_PRINTF("error %d requesting status", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Accumulate any response error bits seen */
|
||||
if (resp_errs)
|
||||
*resp_errs |= status;
|
||||
|
||||
if (is_to)
|
||||
{
|
||||
EMMC_PRINTF("wait card busy timeout");
|
||||
return -RET_ERR;
|
||||
}
|
||||
/*
|
||||
* Some cards mishandle the status bits,
|
||||
* so make sure to check both the busy
|
||||
* indication and the card state.
|
||||
*/
|
||||
}
|
||||
while (!(status & (1 << 8)) ||
|
||||
(((status & 0x00001E00) >> 9) == 7));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int mmcsd_req_blk1(struct sdh_device *host,
|
||||
uint32_t sector,
|
||||
void *buf,
|
||||
uint32_t blks,
|
||||
uint8_t dir)
|
||||
{
|
||||
struct rt_mmcsd_cmd cmd, stop;
|
||||
uint32_t r_cmd, w_cmd;
|
||||
int err;
|
||||
|
||||
memset(&cmd, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
memset(&stop, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
|
||||
cmd.arg = sector;
|
||||
if (!(host->flags & CARD_FLAG_SDHC))
|
||||
{
|
||||
cmd.arg <<= 9;
|
||||
}
|
||||
cmd.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
|
||||
|
||||
host->data.blksize = SECTOR_SIZE;
|
||||
host->data.blks = blks;
|
||||
|
||||
|
||||
stop.cmd_code = STOP_TRANSMISSION;
|
||||
stop.arg = 0;
|
||||
stop.flags = RESP_SPI_R1B | RESP_R1B | CMD_AC;
|
||||
r_cmd = READ_MULTIPLE_BLOCK;
|
||||
w_cmd = WRITE_MULTIPLE_BLOCK;
|
||||
|
||||
|
||||
if (host->flags & 0x8000)
|
||||
{
|
||||
/* last request is WRITE,need check busy */
|
||||
card_busy_detect(host, 10000, NULL);
|
||||
}
|
||||
|
||||
if (!dir) {
|
||||
cmd.cmd_code = r_cmd;
|
||||
host->data.flags |= DATA_DIR_READ;
|
||||
host->flags &= 0x7fff;
|
||||
} else {
|
||||
cmd.cmd_code = w_cmd;
|
||||
host->data.flags |= DATA_DIR_WRITE;
|
||||
host->flags |= 0x8000;
|
||||
}
|
||||
host->data.buf = buf;
|
||||
host->data.blks = blks;
|
||||
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd);
|
||||
if(err) {
|
||||
EMMC_PRINTF("%s start err", __FUNCTION__);
|
||||
}
|
||||
|
||||
if(!dir) {
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->read(host, buf);
|
||||
} else {
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->write(host, buf);
|
||||
}
|
||||
|
||||
if(((const struct sdhc_hal_ops *)host->dev.ops)->complete) {
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->complete(host);
|
||||
}
|
||||
|
||||
os_sleep_ms(1);
|
||||
err = ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &stop);
|
||||
if(err) {
|
||||
EMMC_PRINTF("%s stop err", __FUNCTION__);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
|
||||
int mmcsd_req_blk(struct sdh_device *host,
|
||||
uint32_t sector,
|
||||
void *buf,
|
||||
uint32_t blks,
|
||||
uint8_t dir)
|
||||
{
|
||||
struct rt_mmcsd_cmd cmd1, cmd2;
|
||||
uint32_t r_cmd, w_cmd;
|
||||
int err = 0;
|
||||
|
||||
memset(&cmd1, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
memset(&cmd2, 0, sizeof(struct rt_mmcsd_cmd));
|
||||
|
||||
cmd1.arg = sector;
|
||||
if (!(host->flags & CARD_FLAG_SDHC))
|
||||
{
|
||||
cmd1.arg <<= 9;
|
||||
}
|
||||
cmd1.flags = RESP_SPI_R1 | RESP_R1 | CMD_ADTC;
|
||||
|
||||
r_cmd = READ_MULTIPLE_BLOCK;
|
||||
w_cmd = WRITE_MULTIPLE_BLOCK;
|
||||
|
||||
if (host->flags & 0x8000)
|
||||
{
|
||||
/* last request is WRITE,need check busy */
|
||||
card_busy_detect(host, 10000, NULL);
|
||||
}
|
||||
|
||||
if (!dir) {
|
||||
cmd1.cmd_code = r_cmd;
|
||||
host->sd_opt = SD_M_R;
|
||||
host->data.flags |= DATA_DIR_READ;
|
||||
host->flags &= 0x7fff;
|
||||
} else {
|
||||
cmd1.cmd_code = w_cmd;
|
||||
host->sd_opt = SD_M_W;
|
||||
host->data.flags |= DATA_DIR_WRITE;
|
||||
host->flags |= 0x8000;
|
||||
}
|
||||
|
||||
cmd2.cmd_code = SET_BLOCK_COUNT;
|
||||
cmd2.arg = blks;
|
||||
cmd2.flags = RESP_SPI_R1 | RESP_R1 | CMD_AC;
|
||||
|
||||
if(((const struct sdhc_hal_ops *)host->dev.ops)->cmd) {
|
||||
err |= ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd2);
|
||||
err |= ((const struct sdhc_hal_ops *)host->dev.ops)->cmd(host, &cmd1);
|
||||
}
|
||||
|
||||
|
||||
if(err) {
|
||||
EMMC_PRINTF("%s start err", __FUNCTION__);
|
||||
}
|
||||
|
||||
host->data.blksize = SECTOR_SIZE;
|
||||
host->data.buf = buf;
|
||||
host->data.blks = blks;
|
||||
|
||||
if(!dir) {
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->read(host, buf);
|
||||
} else {
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->write(host, buf);
|
||||
}
|
||||
|
||||
if(((const struct sdhc_hal_ops *)host->dev.ops)->complete) {
|
||||
((const struct sdhc_hal_ops *)host->dev.ops)->complete(host);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int mmc_cmdq_switch(struct sdh_device *host, bool enable)
|
||||
{
|
||||
uint8_t val = enable ? 1 : 0;
|
||||
int err;
|
||||
|
||||
#define EXT_CSD_CMDQ_MODE_EN 15 /* R/W */
|
||||
|
||||
err = mmc_switch(host, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_CMDQ_MODE_EN, val);
|
||||
if (err)
|
||||
printf("cmdq switch fail %d\r\n", enable);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
1725
sdk/lib/sdhost/sdhost.c
Normal file
1725
sdk/lib/sdhost/sdhost.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user