123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- #include "xil_exception.h"
- #include "xsdps.h"
- #include <stdio.h>
- #include "xparameters.h"
- #include "rtthread.h"
- #include <rtdevice.h>
- #define DBG_TAG "drv.mmc"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #define EMMC_BLOCK_SIZE (512)
- extern u16 TransferMode;
- extern s32 XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt);
- extern void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff);
- // replace XSdPs_ReadPolled, using `rt_thread_mdelay`
- s32 XSdPs_ReadPolled_rtt(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, u8 *Buff)
- {
- s32 Status;
- u32 PresentStateReg;
- u32 StatusReg;
- if ((InstancePtr->HC_Version != XSDPS_HC_SPEC_V3) ||
- ((InstancePtr->Host_Caps & XSDPS_CAPS_SLOT_TYPE_MASK)
- != XSDPS_CAPS_EMB_SLOT)) {
- if(InstancePtr->Config.CardDetect != 0U) {
- /* Check status to ensure card is initialized */
- PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
- XSDPS_PRES_STATE_OFFSET);
- if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0x0U) {
- Status = XST_FAILURE;
- goto RETURN_PATH;
- }
- }
- }
- /* Set block size to 512 if not already set */
- if( XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
- XSDPS_BLK_SIZE_OFFSET) != XSDPS_BLK_SIZE_512_MASK ) {
- Status = XSdPs_SetBlkSize(InstancePtr,
- XSDPS_BLK_SIZE_512_MASK);
- if (Status != XST_SUCCESS) {
- Status = XST_FAILURE;
- goto RETURN_PATH;
- }
- }
- XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, Buff);
- TransferMode = XSDPS_TM_AUTO_CMD12_EN_MASK |
- XSDPS_TM_BLK_CNT_EN_MASK | XSDPS_TM_DAT_DIR_SEL_MASK |
- XSDPS_TM_DMA_EN_MASK | XSDPS_TM_MUL_SIN_BLK_SEL_MASK;
- if (InstancePtr->Config.IsCacheCoherent == 0) {
- Xil_DCacheInvalidateRange((INTPTR)Buff,
- BlkCnt * XSDPS_BLK_SIZE_512_MASK);
- }
- /* Send block read command */
- Status = XSdPs_CmdTransfer(InstancePtr, CMD18, Arg, BlkCnt);
- if (Status != XST_SUCCESS) {
- Status = XST_FAILURE;
- goto RETURN_PATH;
- }
- /* Check for transfer complete */
- do {
- StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
- XSDPS_NORM_INTR_STS_OFFSET);
- if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
- /* Write to clear error bits */
- XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
- XSDPS_ERR_INTR_STS_OFFSET,
- XSDPS_ERROR_INTR_ALL_MASK);
- Status = XST_FAILURE;
- goto RETURN_PATH;
- }
- // delay 1ms
- if ((StatusReg & XSDPS_INTR_TC_MASK) == 0U)
- rt_thread_mdelay(1);
- } while((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
- /* Write to clear bit */
- XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
- XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
- Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
- XSDPS_RESP0_OFFSET);
- Status = XST_SUCCESS;
- RETURN_PATH:
- return Status;
- }
- // replace XSdPs_WritePolled, using rt_thread_mdelay
- s32 XSdPs_WritePolled_rtt(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, const u8 *Buff)
- {
- s32 Status;
- u32 PresentStateReg;
- u32 StatusReg;
- if ((InstancePtr->HC_Version != XSDPS_HC_SPEC_V3) ||
- ((InstancePtr->Host_Caps & XSDPS_CAPS_SLOT_TYPE_MASK)
- != XSDPS_CAPS_EMB_SLOT)) {
- if(InstancePtr->Config.CardDetect != 0U) {
- /* Check status to ensure card is initialized */
- PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
- XSDPS_PRES_STATE_OFFSET);
- if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0x0U) {
- Status = XST_FAILURE;
- goto RETURN_PATH;
- }
- }
- }
- /* Set block size to 512 if not already set */
- if( XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
- XSDPS_BLK_SIZE_OFFSET) != XSDPS_BLK_SIZE_512_MASK ) {
- Status = XSdPs_SetBlkSize(InstancePtr,
- XSDPS_BLK_SIZE_512_MASK);
- if (Status != XST_SUCCESS) {
- Status = XST_FAILURE;
- goto RETURN_PATH;
- }
- }
- XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, Buff);
- if (InstancePtr->Config.IsCacheCoherent == 0) {
- Xil_DCacheFlushRange((INTPTR)Buff,
- BlkCnt * XSDPS_BLK_SIZE_512_MASK);
- }
- TransferMode = XSDPS_TM_AUTO_CMD12_EN_MASK |
- XSDPS_TM_BLK_CNT_EN_MASK |
- XSDPS_TM_MUL_SIN_BLK_SEL_MASK | XSDPS_TM_DMA_EN_MASK;
- /* Send block write command */
- Status = XSdPs_CmdTransfer(InstancePtr, CMD25, Arg, BlkCnt);
- if (Status != XST_SUCCESS) {
- Status = XST_FAILURE;
- goto RETURN_PATH;
- }
- /*
- * Check for transfer complete
- * Polling for response for now
- */
- do {
- StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
- XSDPS_NORM_INTR_STS_OFFSET);
- if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
- /* Write to clear error bits */
- XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
- XSDPS_ERR_INTR_STS_OFFSET,
- XSDPS_ERROR_INTR_ALL_MASK);
- Status = XST_FAILURE;
- goto RETURN_PATH;
- }
- if ((StatusReg & XSDPS_INTR_TC_MASK) == 0U)
- rt_thread_mdelay(1);
- } while((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
- /* Write to clear bit */
- XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
- XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
- Status = XST_SUCCESS;
- RETURN_PATH:
- return Status;
- }
- struct rt_hw_emmc_device {
- struct rt_device dev;
- XSdPs emmc;
- XSdPs_Config *cfg;
- struct rt_mutex lock;
- u16 dev_id;
- };
- #ifdef BSP_USING_SDIO0
- static struct rt_hw_emmc_device emmc0 = {
- .dev_id = XPAR_PS7_SD_0_DEVICE_ID,
- };
- #endif
- #ifdef BSP_USING_SDIO1
- static struct rt_hw_emmc_device emmc1 = {
- .dev_id = XPAR_PS7_SD_1_DEVICE_ID,
- };
- #endif
- #define __INIT_CHECK_CFG(cfg) \
- if (Status != XST_SUCCESS) \
- { \
- rt_kprintf("EMMC Config '%s' failed: err: %d\n", cfg, Status); \
- return -RT_EIO; \
- }
- static rt_err_t rt_sdcard_init(rt_device_t dev)
- {
- RT_ASSERT(dev);
- struct rt_hw_emmc_device *pdev = rt_container_of(dev, struct rt_hw_emmc_device, dev);
- RT_ASSERT(pdev != RT_NULL);
- rt_mutex_take(&pdev->lock, RT_WAITING_FOREVER);
- if (pdev->cfg != RT_NULL)
- {
- LOG_I("init '%s' success", pdev->dev.parent.name);
- rt_mutex_release(&pdev->lock);
- return RT_EOK;
- }
- pdev->cfg = XSdPs_LookupConfig(pdev->dev_id);
- RT_ASSERT(pdev->cfg != RT_NULL);
- s32 Status = XSdPs_CfgInitialize(&pdev->emmc, pdev->cfg, pdev->cfg->BaseAddress);
- __INIT_CHECK_CFG("cfg");
- Status = XSdPs_CardInitialize(&pdev->emmc);
- __INIT_CHECK_CFG("init");
- LOG_I("init '%s' success", pdev->dev.parent.name);
- rt_mutex_release(&pdev->lock);
- return RT_EOK;
- }
- rt_inline rt_uint32_t _emmc_start_addr(struct rt_hw_emmc_device *pdev)
- {
- return 0;
- }
- rt_inline rt_uint32_t _emmc_size(struct rt_hw_emmc_device *pdev)
- {
- return pdev->emmc.SectorCount;
- }
- rt_inline rt_uint32_t _emmc_end_addr(struct rt_hw_emmc_device *pdev)
- {
- return pdev->emmc.SectorCount;
- }
- static rt_err_t rt_sdcard_open(rt_device_t dev, rt_uint16_t oflag)
- {
- return RT_EOK;
- }
- static rt_err_t rt_sdcard_close(rt_device_t dev)
- {
- return RT_EOK;
- }
- static rt_ssize_t rt_sdcard_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
- {
- s32 status;
- RT_ASSERT(dev);
- struct rt_hw_emmc_device *pdev = rt_container_of(dev, struct rt_hw_emmc_device, dev);
- RT_ASSERT(pdev != RT_NULL);
- pos += _emmc_start_addr(pdev);
- if (size + pos >= _emmc_end_addr(pdev))
- {
- LOG_E("addr out of ranger: %d %d", pos, size);
- return 0;
- }
- rt_mutex_take(&pdev->lock, RT_WAITING_FOREVER);
- status = XSdPs_ReadPolled_rtt(&pdev->emmc, pos, size, buffer);
- rt_mutex_release(&pdev->lock);
- if (status == XST_SUCCESS)
- return size;
- rt_kprintf("sdcard read failed: %d\n", status);
- return 0;
- }
- static rt_uint8_t sdio_write_buf[2][EMMC_BLOCK_SIZE] __attribute__((aligned(32)));
- static rt_ssize_t rt_sdcard_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
- {
- s32 status;
- rt_ssize_t rt = 0;
- RT_ASSERT(dev);
- struct rt_hw_emmc_device *pdev = rt_container_of(dev, struct rt_hw_emmc_device, dev);
- RT_ASSERT(pdev != RT_NULL);
- pos += _emmc_start_addr(pdev);
- if (size + pos >= _emmc_end_addr(pdev))
- {
- LOG_E("addr out of ranger: %d %d", pos, size);
- return 0;
- }
- rt_mutex_take(&pdev->lock, RT_WAITING_FOREVER);
- for (int i = 0; i < size; i++)
- {
- rt_memcpy(sdio_write_buf[pdev->dev_id], ((rt_uint8_t *)buffer) + EMMC_BLOCK_SIZE * i, EMMC_BLOCK_SIZE);
- status = XSdPs_WritePolled_rtt(&pdev->emmc, pos + i, 1, sdio_write_buf[pdev->dev_id]);
- if (status != XST_SUCCESS)
- {
- rt_kprintf("sdcard write failed: %d\n", status);
- break;
- }
- rt++;
- }
- rt_mutex_release(&pdev->lock);
- return rt;
- }
- static rt_err_t rt_sdcard_control(rt_device_t dev, int cmd, void *args)
- {
- RT_ASSERT(dev);
- struct rt_hw_emmc_device *pdev = rt_container_of(dev, struct rt_hw_emmc_device, dev);
- RT_ASSERT(pdev != RT_NULL);
- if (cmd == RT_DEVICE_CTRL_BLK_GETGEOME)
- {
- struct rt_device_blk_geometry *geometry;
- geometry = (struct rt_device_blk_geometry *)args;
- if (geometry == RT_NULL)
- return -RT_ERROR;
- geometry->bytes_per_sector = EMMC_BLOCK_SIZE;
- geometry->block_size = EMMC_BLOCK_SIZE;
- geometry->sector_count = _emmc_size(pdev);
- }
- return RT_EOK;
- }
- static void _init_emmc_dev(struct rt_hw_emmc_device *pdev, const char *name)
- {
- rt_mutex_init(&pdev->lock, name, RT_IPC_FLAG_PRIO);
- pdev->dev.type = RT_Device_Class_Block;
- pdev->dev.init = rt_sdcard_init;
- pdev->dev.open = rt_sdcard_open;
- pdev->dev.close = rt_sdcard_close;
- pdev->dev.read = rt_sdcard_read;
- pdev->dev.write = rt_sdcard_write;
- pdev->dev.control = rt_sdcard_control;
- pdev->dev.user_data = RT_NULL;
- rt_device_register(&pdev->dev, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
- }
- int rt_hw_emmc_init(void)
- {
- #ifdef BSP_USING_SDIO0
- _init_emmc_dev(&emmc0, "sd0");
- #endif
- #ifdef BSP_USING_SDIO1
- _init_emmc_dev(&emmc1, "sd1");
- #endif
- return RT_EOK;
- }
- INIT_BOARD_EXPORT(rt_hw_emmc_init);
|