#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;idev.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;tidarg.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); } }