diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c index 9b03519fe87e0939ca95976c04e27c171cc5076c..c2ce6e8e750bddab19f8fd503f31aceac1015780 100644 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c +++ b/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c @@ -11,16 +11,19 @@ #include "mbox.h" #include "raspi4.h" #include "drv_sdio.h" +#include "rthw.h" static rt_uint32_t mmc_base_clock = 0; +static sdhci_Adma2Descriptor32 Adma2_DescrTbl[32] __attribute__((aligned(32))); + static rt_uint32_t sdCommandTable[] = { SD_CMD_INDEX(0), SD_CMD_RESERVED(1), SD_CMD_INDEX(2) | SD_RESP_R2, SD_CMD_INDEX(3) | SD_RESP_R1, SD_CMD_INDEX(4), - SD_CMD_RESERVED(5), //SD_CMD_INDEX(5) | SD_RESP_R4, + SD_CMD_RESERVED(5), // SD_CMD_INDEX(5) | SD_RESP_R4, SD_CMD_INDEX(6) | SD_RESP_R1, SD_CMD_INDEX(7) | SD_RESP_R1b, SD_CMD_INDEX(8) | SD_RESP_R1, @@ -41,7 +44,7 @@ static rt_uint32_t sdCommandTable[] = { SD_CMD_INDEX(23) | SD_RESP_R1, SD_CMD_INDEX(24) | SD_RESP_R1 | SD_DATA_WRITE, SD_CMD_INDEX(25) | SD_RESP_R1 | SD_DATA_WRITE | SD_CMD_MULTI_BLOCK | SD_CMD_BLKCNT_EN, - SD_CMD_INDEX(26) | SD_RESP_R1 | SD_DATA_WRITE, //add + SD_CMD_INDEX(26) | SD_RESP_R1 | SD_DATA_WRITE, // add SD_CMD_INDEX(27) | SD_RESP_R1 | SD_DATA_WRITE, SD_CMD_INDEX(28) | SD_RESP_R1b, SD_CMD_INDEX(29) | SD_RESP_R1b, @@ -50,13 +53,13 @@ static rt_uint32_t sdCommandTable[] = { SD_CMD_INDEX(32) | SD_RESP_R1, SD_CMD_INDEX(33) | SD_RESP_R1, SD_CMD_RESERVED(34), - SD_CMD_INDEX(35) | SD_RESP_R1, //add - SD_CMD_INDEX(36) | SD_RESP_R1, //add + SD_CMD_INDEX(35) | SD_RESP_R1, // add + SD_CMD_INDEX(36) | SD_RESP_R1, // add SD_CMD_RESERVED(37), SD_CMD_INDEX(38) | SD_RESP_R1b, - SD_CMD_INDEX(39) | SD_RESP_R4, //add - SD_CMD_INDEX(40) | SD_RESP_R5, //add - SD_CMD_INDEX(41) | SD_RESP_R3, //add, mov from harbote + SD_CMD_INDEX(39) | SD_RESP_R4, // add + SD_CMD_INDEX(40) | SD_RESP_R5, // add + SD_CMD_INDEX(41) | SD_RESP_R3, // add, mov from harbote SD_CMD_RESERVED(42) | SD_RESP_R1, SD_CMD_RESERVED(43), SD_CMD_RESERVED(44), @@ -78,45 +81,155 @@ static rt_uint32_t sdCommandTable[] = { SD_CMD_RESERVED(60), SD_CMD_RESERVED(61), SD_CMD_RESERVED(62), - SD_CMD_RESERVED(63) -}; + SD_CMD_RESERVED(63)}; + +static inline void write8(size_t addr, rt_uint8_t value) +{ + (*((volatile unsigned char *)(addr))) = value; +} + +static inline rt_uint8_t read8(size_t addr) +{ + return (*((volatile unsigned char *)(addr))); +} + +static inline rt_uint16_t read16(size_t addr) +{ + return (*((volatile unsigned short *)(addr))); +} + +static inline rt_uint16_t write16(size_t addr, rt_uint16_t value) +{ + return (*((volatile unsigned short *)(addr))) = value; +} static inline rt_uint32_t read32(size_t addr) { - return (*((volatile unsigned int*)(addr))); + return (*((volatile unsigned int *)(addr))); } static inline void write32(size_t addr, rt_uint32_t value) { - (*((volatile unsigned int*)(addr))) = value; + (*((volatile unsigned int *)(addr))) = value; } -rt_err_t sd_int(struct sdhci_pdata_t * pdat, rt_uint32_t mask) +rt_err_t sd_int(struct sdhci_pdata_t *pdat, rt_uint32_t mask) { rt_uint32_t r; rt_uint32_t m = mask | INT_ERROR_MASK; int cnt = 1000000; while (!(read32(pdat->virt + EMMC_INTERRUPT) & (m | INT_ERROR_MASK)) && cnt--) + { DELAY_MICROS(1); + if (cnt % 10000 == 0) + mmcsd_dbg("wait %d\n", cnt); + } r = read32(pdat->virt + EMMC_INTERRUPT); if (cnt <= 0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT)) { write32(pdat->virt + EMMC_INTERRUPT, r); - //qemu maybe can not use sdcard - rt_kprintf("send cmd/data timeout wait for %x int: %x, status: %x\n",mask, r, read32(pdat->virt + EMMC_STATUS)); + // qemu maybe can not use sdcard + rt_kprintf("send cmd/data timeout wait for %x int: %x, status: %x\n", mask, r, read32(pdat->virt + EMMC_STATUS)); return -RT_ETIMEOUT; } else if (r & INT_ERROR_MASK) { write32(pdat->virt + EMMC_INTERRUPT, r); - rt_kprintf("send cmd/data error %x -> %x\n",r, read32(pdat->virt + EMMC_INTERRUPT)); + rt_kprintf("send cmd/data error %x -> %x\n", r, read32(pdat->virt + EMMC_INTERRUPT)); return -RT_ERROR; } write32(pdat->virt + EMMC_INTERRUPT, mask); return RT_EOK; } -rt_err_t sd_status(struct sdhci_pdata_t * pdat, unsigned int mask) +/*****************************************************************************/ +/** + * + * @brief + * API to setup ADMA2 descriptor table for 32-bit DMA + * + * + * @param InstancePtr is a pointer to the XSdPs instance. + * @param BlkCnt - block count. + * @param Buff pointer to data buffer. + * + * @return None + * + * @note None. + * + ******************************************************************************/ +void sdhci_Setup32ADMA2DescTbl(size_t base_addr, const uint8_t *Buff, uint32_t BlkSize, uint32_t BlkCnt) +{ + uint32_t TotalDescLines; + uint32_t DescNum; + + void *Adma2_DescrTbl_p = virtual_to_physical(Adma2_DescrTbl); + const uint8_t *Buff_p = (const uint8_t *)virtual_to_physical(Buff); + + /* Setup ADMA2 - Write descriptor table and point ADMA SAR to it */ + + if ((BlkCnt * BlkSize) < SDHCI_DESC_MAX_LENGTH) + { + TotalDescLines = 1U; + } + else + { + TotalDescLines = ((BlkCnt * BlkSize) / SDHCI_DESC_MAX_LENGTH); + if (((BlkCnt * BlkSize) % SDHCI_DESC_MAX_LENGTH) != 0U) + { + TotalDescLines += 1U; + } + } + + for (DescNum = 0U; DescNum < (TotalDescLines - 1); DescNum++) + { + Adma2_DescrTbl[DescNum].Address = + (uint32_t)((uintptr_t)Buff_p + (DescNum * SDHCI_DESC_MAX_LENGTH)); + Adma2_DescrTbl[DescNum].Attribute = + SDHCI_DESC_TRAN | SDHCI_DESC_VALID | SDHCI_DESC_INT; + Adma2_DescrTbl[DescNum].Length = 0U; + rt_kprintf("Adma2_desc: %x\n", Adma2_DescrTbl[DescNum].Address); + } + Adma2_DescrTbl[TotalDescLines - 1].Address = (uint32_t)((uintptr_t)Buff_p + (DescNum * SDHCI_DESC_MAX_LENGTH)); + + Adma2_DescrTbl[TotalDescLines - 1].Attribute = + SDHCI_DESC_TRAN | SDHCI_DESC_END | SDHCI_DESC_VALID | SDHCI_DESC_INT; + + Adma2_DescrTbl[TotalDescLines - 1].Length = + (uint16_t)((BlkCnt * BlkSize) - (uint32_t)(DescNum * SDHCI_DESC_MAX_LENGTH)); + + write32(base_addr + EMMC_ADMA_SAR_OFFSET, (uint32_t)((uintptr_t)Adma2_DescrTbl_p & (uint32_t)~0x0)); + rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, Adma2_DescrTbl, sizeof(sdhci_Adma2Descriptor32) * 32U); +} + +/*****************************************************************************/ +/** + * @brief + * This function is used to do the DMA transfer to or from SD card. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param BlkCnt - Block count passed by the user. + * @param BlkSize - Block size passed by the user. + * @param Buff - Pointer to the data buffer for a DMA transfer. + * + * @return + * - XST_SUCCESS if initialization was successful + * - XST_FAILURE if failure - could be because another transfer + * is in progress or command or data inhibit is set + * + ******************************************************************************/ +void XSdPs_SetupRWDma(size_t base_addr, uint8_t *Buff) +{ + uint32_t BlkSize; + uint32_t BlkCnt; + + BlkSize = (uint32_t)read16(base_addr + EMMC_BLKSIZECNT) & SDHCI_BLK_SIZE_MASK; + BlkCnt = (uint32_t)read16(base_addr + EMMC_BLKCOUNT) & SDHCI_BLK_CNT_MASK; + sdhci_Setup32ADMA2DescTbl(base_addr, Buff, BlkSize, BlkCnt); + rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, Buff, BlkCnt * BlkSize); +} + +rt_err_t sd_status(struct sdhci_pdata_t *pdat, unsigned int mask) { int cnt = 500000; while ((read32(pdat->virt + EMMC_STATUS) & mask) && !(read32(pdat->virt + EMMC_INTERRUPT) & INT_ERROR_MASK) && cnt--) @@ -127,20 +240,20 @@ rt_err_t sd_status(struct sdhci_pdata_t * pdat, unsigned int mask) } else if (read32(pdat->virt + EMMC_INTERRUPT) & INT_ERROR_MASK) { - return -RT_ERROR; - } + return -RT_ERROR; + } return RT_EOK; } -static rt_err_t raspi_transfer_command(struct sdhci_pdata_t * pdat, struct sdhci_cmd_t * cmd) +static rt_err_t raspi_transfer_command(struct sdhci_pdata_t *pdat, struct sdhci_cmd_t *cmd) { rt_uint32_t cmdidx; rt_err_t ret = RT_EOK; ret = sd_status(pdat, SR_CMD_INHIBIT); if (ret) { - rt_kprintf("ERROR: EMMC busy %d\n", ret); + rt_kprintf("ERROR: EMMC cmd busy %d\n", ret); return ret; } @@ -148,12 +261,31 @@ static rt_err_t raspi_transfer_command(struct sdhci_pdata_t * pdat, struct sdhci if (cmdidx == 0xFFFFFFFF) return -RT_EINVAL; if (cmd->datarw == DATA_READ) + { cmdidx |= SD_DATA_READ; + cmdidx |= SDHCI_TM_DMA_EN_MASK; + cmdidx |= (SD_CMD_IXCHK_EN | SD_CMD_CRCCHK_EN | SD_CMD_BLKCNT_EN); + if (cmd->cmdidx == READ_MULTIPLE_BLOCK) + { + cmdidx |= (SD_CMD_AUTO_CMD_EN_CMD23 | SDHCI_TM_MUL_SIN_BLK_SEL_MASK); + } + } if (cmd->datarw == DATA_WRITE) + { cmdidx |= SD_DATA_WRITE; - mmcsd_dbg("transfer cmd %x(%d) %x %x\n", cmdidx, cmd->cmdidx, cmd->cmdarg, read32(pdat->virt + EMMC_INTERRUPT)); - write32(pdat->virt + EMMC_INTERRUPT,read32(pdat->virt + EMMC_INTERRUPT)); + cmdidx |= SDHCI_TM_DMA_EN_MASK; + cmdidx |= (SD_CMD_IXCHK_EN | SD_CMD_CRCCHK_EN | SD_CMD_BLKCNT_EN); + if (cmd->cmdidx == WRITE_MULTIPLE_BLOCK) + { + cmdidx |= (SD_CMD_AUTO_CMD_EN_CMD23 | SDHCI_TM_MUL_SIN_BLK_SEL_MASK); + } + } + write8(pdat->virt + EMMC_TIMECTL, 0xEU); write32(pdat->virt + EMMC_ARG1, cmd->cmdarg); + + write16(pdat->virt + EMMC_INTERRUPT, SDHCI_NORM_INTR_ALL_MASK); + write16(pdat->virt + EMMC_ERR_INTERRUPT, SDHCI_ERROR_INTR_ALL_MASK); + write32(pdat->virt + EMMC_CMDTM, cmdidx); if (cmd->cmdidx == SD_APP_OP_COND) DELAY_MICROS(1000); @@ -177,10 +309,10 @@ static rt_err_t raspi_transfer_command(struct sdhci_pdata_t * pdat, struct sdhci resp[3] = read32(pdat->virt + EMMC_RESP3); if (cmd->resptype == RESP_R2) { - cmd->response[0] = resp[3]<<8 |((resp[2]>>24)&0xff); - cmd->response[1] = resp[2]<<8 |((resp[1]>>24)&0xff); - cmd->response[2] = resp[1]<<8 |((resp[0]>>24)&0xff); - cmd->response[3] = resp[0]<<8 ; + cmd->response[0] = resp[3] << 8 | ((resp[2] >> 24) & 0xff); + cmd->response[1] = resp[2] << 8 | ((resp[1] >> 24) & 0xff); + cmd->response[2] = resp[1] << 8 | ((resp[0] >> 24) & 0xff); + cmd->response[3] = resp[0] << 8; } else { @@ -193,11 +325,12 @@ static rt_err_t raspi_transfer_command(struct sdhci_pdata_t * pdat, struct sdhci else cmd->response[0] = read32(pdat->virt + EMMC_RESP0); } - mmcsd_dbg("response: %x: %x %x %x %x (%x, %x)\n", cmd->resptype, cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3], read32(pdat->virt + EMMC_STATUS),read32(pdat->virt + EMMC_INTERRUPT)); + mmcsd_dbg("response: %x: %x %x %x %x (%x, %x)\n", cmd->resptype, cmd->response[0], cmd->response[1], cmd->response[2], cmd->response[3], read32(pdat->virt + EMMC_STATUS), read32(pdat->virt + EMMC_INTERRUPT)); + mmcsd_dbg("response: %x: %x \n", cmd->resptype, cmd->response[0]); return ret; } -static rt_err_t read_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_uint32_t blkcount, rt_uint32_t blksize) +static rt_err_t read_bytes(struct sdhci_pdata_t *pdat, rt_uint32_t *buf, rt_uint32_t blkcount, rt_uint32_t blksize) { int c = 0; rt_err_t ret; @@ -206,10 +339,10 @@ static rt_err_t read_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_ui { if ((ret = sd_int(pdat, INT_READ_RDY))) { - rt_kprintf("timeout happens when reading block %d\n",c); + rt_kprintf("timeout happens when reading block %d\n", c); return ret; } - for (d=0; d < blksize / 4; d++) + for (d = 0; d < blksize / 4; d++) if (read32(pdat->virt + EMMC_STATUS) & SR_READ_AVAILABLE) buf[d] = read32(pdat->virt + EMMC_DATA); c++; @@ -218,7 +351,7 @@ static rt_err_t read_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_ui return RT_EOK; } -static rt_err_t write_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_uint32_t blkcount, rt_uint32_t blksize) +static rt_err_t write_bytes(struct sdhci_pdata_t *pdat, rt_uint32_t *buf, rt_uint32_t blkcount, rt_uint32_t blksize) { int c = 0; rt_err_t ret; @@ -229,7 +362,7 @@ static rt_err_t write_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_u { return ret; } - for (d=0; d < blksize / 4; d++) + for (d = 0; d < blksize / 4; d++) write32(pdat->virt + EMMC_DATA, buf[d]); c++; buf += blksize / 4; @@ -242,13 +375,13 @@ static rt_err_t write_bytes(struct sdhci_pdata_t * pdat, rt_uint32_t * buf, rt_u return RT_EOK; } -static rt_err_t raspi_transfer_data(struct sdhci_pdata_t * pdat, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat) +static rt_err_t raspi_transfer_data(struct sdhci_pdata_t *pdat, struct sdhci_cmd_t *cmd, struct sdhci_data_t *dat) { rt_uint32_t dlen = (rt_uint32_t)(dat->blkcnt * dat->blksz); rt_err_t ret = sd_status(pdat, SR_DAT_INHIBIT); if (ret) { - rt_kprintf("ERROR: EMMC busy\n"); + rt_kprintf("ERROR: EMMC data busy\n"); return ret; } if (dat->blkcnt > 1) @@ -258,10 +391,11 @@ static rt_err_t raspi_transfer_data(struct sdhci_pdata_t * pdat, struct sdhci_cm newcmd.cmdarg = dat->blkcnt; newcmd.resptype = RESP_R1; ret = raspi_transfer_command(pdat, &newcmd); - if (ret) return ret; + if (ret) + return ret; } - if(dlen < 512) + if (dlen < 512) { write32(pdat->virt + EMMC_BLKSIZECNT, dlen | 1 << 16); } @@ -269,28 +403,37 @@ static rt_err_t raspi_transfer_data(struct sdhci_pdata_t * pdat, struct sdhci_cm { write32(pdat->virt + EMMC_BLKSIZECNT, 512 | (dat->blkcnt) << 16); } + if (dat->flag & DATA_DIR_READ) { cmd->datarw = DATA_READ; + XSdPs_SetupRWDma(pdat->virt, dat->buf); ret = raspi_transfer_command(pdat, cmd); - if (ret) return ret; - mmcsd_dbg("read_block %d, %d\n", dat->blkcnt, dat->blksz ); - ret = read_bytes(pdat, (rt_uint32_t *)dat->buf, dat->blkcnt, dat->blksz); + if (ret) + return ret; + rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, dat->buf, dat->blkcnt * dat->blksz); + mmcsd_dbg("read_block %d, %d\n", dat->blkcnt, dat->blksz); } else if (dat->flag & DATA_DIR_WRITE) { cmd->datarw = DATA_WRITE; + XSdPs_SetupRWDma(pdat->virt, dat->buf); ret = raspi_transfer_command(pdat, cmd); - if (ret) return ret; - mmcsd_dbg("write_block %d, %d", dat->blkcnt, dat->blksz ); - ret = write_bytes(pdat, (rt_uint32_t *)dat->buf, dat->blkcnt, dat->blksz); + if (ret) + return ret; + mmcsd_dbg("write_block %d, %d\n", dat->blkcnt, dat->blksz); + } + ret = sd_int(pdat, INT_DATA_DONE); + if (ret) + { + return ret; } return ret; } -static rt_err_t sdhci_transfer(struct sdhci_t * sdhci, struct sdhci_cmd_t * cmd, struct sdhci_data_t * dat) +static rt_err_t sdhci_transfer(struct sdhci_t *sdhci, struct sdhci_cmd_t *cmd, struct sdhci_data_t *dat) { - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)sdhci->priv; + struct sdhci_pdata_t *pdat = (struct sdhci_pdata_t *)sdhci->priv; if (!dat) return raspi_transfer_command(pdat, cmd); @@ -309,7 +452,7 @@ static void mmc_request_send(struct rt_mmcsd_host *host, struct rt_mmcsd_req *re cmd.cmdidx = req->cmd->cmd_code; cmd.cmdarg = req->cmd->arg; - cmd.resptype =resp_type(req->cmd); + cmd.resptype = resp_type(req->cmd); if (req->data) { dat.buf = (rt_uint8_t *)req->data->buf; @@ -333,7 +476,7 @@ static void mmc_request_send(struct rt_mmcsd_host *host, struct rt_mmcsd_req *re { stop.cmdidx = req->stop->cmd_code; stop.cmdarg = req->stop->arg; - cmd.resptype =resp_type(req->stop); + cmd.resptype = resp_type(req->stop); req->stop->err = sdhci_transfer(sdhci, &stop, RT_NULL); } @@ -345,40 +488,43 @@ rt_int32_t mmc_card_status(struct rt_mmcsd_host *host) return 0; } -static rt_err_t sdhci_detect(struct sdhci_t * sdhci) +static rt_err_t sdhci_detect(struct sdhci_t *sdhci) { + struct sdhci_pdata_t *pdat = (struct sdhci_pdata_t *)sdhci->priv; + // sdhci_version + sdhci->sdhci_version4 = read16(pdat->virt + EMMC_MY_CONTROL2) & SDHCI_CTL2_SHCVER_MASK; + sdhci->dma_64bit_addr = read16(pdat->virt + EMMC_MY_CONTROL2) & SDHCI_CTL2_BITADDR_MASK; return RT_EOK; } -static rt_err_t sdhci_setwidth(struct sdhci_t * sdhci, rt_uint32_t width) +static rt_err_t sdhci_setwidth(struct sdhci_t *sdhci, rt_uint32_t width) { rt_uint32_t temp = 0; - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)sdhci->priv; + struct sdhci_pdata_t *pdat = (struct sdhci_pdata_t *)sdhci->priv; if (width == MMCSD_BUS_WIDTH_4) { temp = read32((pdat->virt + EMMC_CONTROL0)); temp |= C0_HCTL_HS_EN; - temp |= C0_HCTL_DWITDH; // always use 4 data lines: + temp |= C0_HCTL_DWITDH; // always use 4 data lines: write32((pdat->virt + EMMC_CONTROL0), temp); } return RT_EOK; } - -static uint32_t sd_get_clock_divider(rt_uint32_t sdHostVer ,rt_uint32_t base_clock, rt_uint32_t target_rate) +static uint32_t sd_get_clock_divider(rt_uint32_t sdHostVer, rt_uint32_t base_clock, rt_uint32_t target_rate) { rt_uint32_t targetted_divisor = 0; rt_uint32_t freq_select = 0; rt_uint32_t upper_bits = 0; rt_uint32_t ret = 0; - if(target_rate > base_clock) + if (target_rate > base_clock) targetted_divisor = 1; else { targetted_divisor = base_clock / target_rate; rt_uint32_t mod = base_clock % target_rate; - if(mod) + if (mod) targetted_divisor--; } @@ -391,14 +537,14 @@ static uint32_t sd_get_clock_divider(rt_uint32_t sdHostVer ,rt_uint32_t base_clo // Find the first bit set int divisor = -1; - for(int first_bit = 31; first_bit >= 0; first_bit--) + for (int first_bit = 31; first_bit >= 0; first_bit--) { rt_uint32_t bit_test = (1 << first_bit); - if(targetted_divisor & bit_test) + if (targetted_divisor & bit_test) { divisor = first_bit; targetted_divisor &= ~bit_test; - if(targetted_divisor) + if (targetted_divisor) { // The divisor is not a power-of-two, increase it divisor++; @@ -407,15 +553,15 @@ static uint32_t sd_get_clock_divider(rt_uint32_t sdHostVer ,rt_uint32_t base_clo } } - if(divisor == -1) + if (divisor == -1) divisor = 31; - if(divisor >= 32) + if (divisor >= 32) divisor = 31; - if(divisor != 0) + if (divisor != 0) divisor = (1 << (divisor - 1)); - if(divisor >= 0x400) + if (divisor >= 0x400) divisor = 0x3ff; freq_select = divisor & 0xff; @@ -425,43 +571,43 @@ static uint32_t sd_get_clock_divider(rt_uint32_t sdHostVer ,rt_uint32_t base_clo return ret; } -static rt_err_t sdhci_setclock(struct sdhci_t * sdhci, rt_uint32_t clock) +static rt_err_t sdhci_setclock(struct sdhci_t *sdhci, rt_uint32_t clock) { rt_uint32_t temp = 0; rt_uint32_t sdHostVer = 0; int count = 100000; - struct sdhci_pdata_t * pdat = (struct sdhci_pdata_t *)(sdhci->priv); + struct sdhci_pdata_t *pdat = (struct sdhci_pdata_t *)(sdhci->priv); while ((read32(pdat->virt + EMMC_STATUS) & (SR_CMD_INHIBIT | SR_DAT_INHIBIT)) && (--count)) DELAY_MICROS(1); if (count <= 0) { - rt_kprintf("EMMC: Set clock: timeout waiting for inhibit flags. Status %08x.\n",read32(pdat->virt + EMMC_STATUS)); + rt_kprintf("EMMC: Set clock: timeout waiting for inhibit flags. Status %08x.\n", read32(pdat->virt + EMMC_STATUS)); return RT_ERROR; } // Switch clock off. temp = read32((pdat->virt + EMMC_CONTROL1)); temp &= ~C1_CLK_EN; - write32((pdat->virt + EMMC_CONTROL1),temp); + write32((pdat->virt + EMMC_CONTROL1), temp); DELAY_MICROS(10); // Request the new clock setting and enable the clock temp = read32(pdat->virt + EMMC_SLOTISR_VER); sdHostVer = (temp & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT; int cdiv = sd_get_clock_divider(sdHostVer, mmc_base_clock, clock); temp = read32((pdat->virt + EMMC_CONTROL1)); - temp |= 1; + temp |= 1; temp |= cdiv; temp |= (7 << 16); temp = (temp & 0xffff003f) | cdiv; - write32((pdat->virt + EMMC_CONTROL1),temp); + write32((pdat->virt + EMMC_CONTROL1), temp); DELAY_MICROS(10); // Enable the clock. temp = read32(pdat->virt + EMMC_CONTROL1); temp |= C1_CLK_EN; - write32((pdat->virt + EMMC_CONTROL1),temp); + write32((pdat->virt + EMMC_CONTROL1), temp); DELAY_MICROS(10); // Wait for clock to be stable. @@ -473,44 +619,51 @@ static rt_err_t sdhci_setclock(struct sdhci_t * sdhci, rt_uint32_t clock) rt_kprintf("EMMC: ERROR: failed to get stable clock %d.\n", clock); return RT_ERROR; } - mmcsd_dbg("set stable clock %d.\n", clock); return RT_EOK; } static void mmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg) { - struct sdhci_t * sdhci = (struct sdhci_t *)host->private_data; + struct sdhci_t *sdhci = (struct sdhci_t *)host->private_data; sdhci_setclock(sdhci, io_cfg->clock); sdhci_setwidth(sdhci, io_cfg->bus_width); } +static rt_uint32_t mmc_get_adma_ver(struct rt_mmcsd_host *host) +{ + struct sdhci_t *sdhci = (struct sdhci_t *)host->private_data; + struct sdhci_pdata_t *pdat = (struct sdhci_pdata_t *)(sdhci->priv); + return read32(pdat->virt + EMMC_CAPABILITIES_0); +} + static const struct rt_mmcsd_host_ops ops = { - mmc_request_send, - mmc_set_iocfg, - RT_NULL, - RT_NULL, + mmc_request_send, + mmc_set_iocfg, + RT_NULL, + RT_NULL, + mmc_get_adma_ver, }; -static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat) +static rt_err_t reset_emmc(struct sdhci_pdata_t *pdat) { rt_uint32_t control1; - //Reset the controller + // Reset the controller control1 = read32((pdat->virt + EMMC_CONTROL1)); control1 |= (1 << 24); // Disable clock control1 &= ~(1 << 2); control1 &= ~(1 << 0); - //temp |= C1_CLK_INTLEN | C1_TOUNIT_MAX; - write32((pdat->virt + EMMC_CONTROL1),control1); + // temp |= C1_CLK_INTLEN | C1_TOUNIT_MAX; + write32((pdat->virt + EMMC_CONTROL1), control1); int cnt = 10000; do { DELAY_MICROS(10); cnt = cnt - 1; - if(cnt == 0) + if (cnt == 0) { break; } @@ -522,8 +675,6 @@ static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat) write32(pdat->virt + EMMC_CONTROL0, control0); rt_thread_delay(100); - //usleep(2000); - // Check for a valid card mmcsd_dbg("EMMC: checking for an inserted card\n"); @@ -532,7 +683,7 @@ static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat) { DELAY_MICROS(10); cnt = cnt - 1; - if(cnt == 0) + if (cnt == 0) { break; } @@ -540,7 +691,7 @@ static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat) rt_uint32_t status_reg = read32(pdat->virt + EMMC_STATUS); - if((status_reg & (1 << 16)) == 0) + if ((status_reg & (1 << 16)) == 0) { rt_kprintf("EMMC: no card inserted\n"); return -1; @@ -554,7 +705,7 @@ static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat) write32(pdat->virt + EMMC_CONTROL2, 0); // Get the base clock rate //12 mmc_base_clock = bcm271x_mbox_clock_get_rate(EMMC_CLK_ID); - if(mmc_base_clock == 0) + if (mmc_base_clock == 0) { rt_kprintf("EMMC: assuming clock rate to be 100MHz\n"); mmc_base_clock = 100000000; @@ -563,8 +714,28 @@ static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat) return RT_EOK; } +/*****************************************************************************/ +/** + * @brief + * This function is used configure the Interrupts. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return None + * + ******************************************************************************/ +void sdhci_ConfigInterrupt(struct sdhci_pdata_t *pdat) +{ + /* Enable all interrupt status except card interrupt initially */ + write16(pdat->virt + EMMC_NOR_IRTR_STS_EN_OFFSET, SDHCI_NORM_INTR_ALL_MASK); + write16(pdat->virt + EMMC_ERR_INTR_STS_EN_OFFSET, SDHCI_ERROR_INTR_ALL_MASK); + + write16(pdat->virt + EMMC_IRPT_EN, 0x13b); + write16(pdat->virt + SDHCI_ERR_INTR_SIG_EN_OFFSET, 0x13b); +} + #ifdef RT_MMCSD_DBG -void dump_registers(struct sdhci_pdata_t * pdat) +void dump_registers(struct sdhci_pdata_t *pdat) { rt_kprintf("EMMC registers:"); int i = EMMC_ARG2; @@ -586,9 +757,9 @@ void dump_registers(struct sdhci_pdata_t * pdat) int raspi_sdmmc_init(void) { size_t virt; - struct rt_mmcsd_host * host = RT_NULL; - struct sdhci_pdata_t * pdat = RT_NULL; - struct sdhci_t * sdhci = RT_NULL; + struct rt_mmcsd_host *host = RT_NULL; + struct sdhci_pdata_t *pdat = RT_NULL; + struct sdhci_t *sdhci = RT_NULL; #ifdef BSP_USING_SDIO0 host = mmcsd_alloc_host(); @@ -622,6 +793,14 @@ int raspi_sdmmc_init(void) sdhci->setclock = sdhci_setclock; sdhci->transfer = sdhci_transfer; sdhci->priv = pdat; + sdhci->detect(sdhci); + + /* Enable ADMA2 in 32bit mode. */ + rt_uint8_t tmp = read8(pdat->virt + EMMC_CONTROL0); + write8(pdat->virt + EMMC_CONTROL0, 0x10 | tmp); + tmp = read8(pdat->virt + EMMC_HOST_CONTROL2); + write8(pdat->virt + EMMC_HOST_CONTROL2, 0x4000 | tmp); + host->ops = &ops; host->freq_min = 400000; host->freq_max = 50000000; @@ -630,11 +809,11 @@ int raspi_sdmmc_init(void) host->max_seg_size = 2048; host->max_dma_segs = 10; host->max_blk_size = 512; - host->max_blk_count = 1; + host->max_blk_count = 16; host->private_data = sdhci; - write32((pdat->virt + EMMC_IRPT_EN),0xffffffff); - write32((pdat->virt + EMMC_IRPT_MASK),0xffffffff); + + sdhci_ConfigInterrupt(pdat); #ifdef RT_MMCSD_DBG dump_registers(pdat); #endif @@ -642,9 +821,15 @@ int raspi_sdmmc_init(void) #endif return RT_EOK; err: - if (host) rt_free(host); - if (sdhci) rt_free(sdhci); + if (host) + { + rt_free(host); + } + if (sdhci) + { + rt_free(sdhci); + } return -RT_EIO; } diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.h b/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.h index 1abedf2a0ba7ec52e271e9e8b5529ef212a6bd6b..11bd10163b8c7430d6ec06ca5af23f4edef4fe7c 100644 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.h +++ b/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.h @@ -86,6 +86,12 @@ struct sdhci_t rt_uint32_t clock; rt_err_t removeable; void * sdcard; + int dma_64bit_addr; + int sdhci_version4; + int support_adma2; + int support_adma3; + int support_v4addr64; + sdhci_Adma2Descriptor32 *adma32dec; rt_err_t (*detect)(struct sdhci_t * sdhci); rt_err_t (*setwidth)(struct sdhci_t * sdhci, rt_uint32_t width); @@ -148,6 +154,8 @@ struct sdhci_pdata_t #define EMMC_ARG2 (0x00) #define EMMC_BLKSIZECNT (0x04) +#define EMMC_BLKCOUNT (0x06) + #define EMMC_ARG1 (0x08) #define EMMC_CMDTM (0x0c) #define EMMC_RESP0 (0x10) @@ -157,17 +165,84 @@ struct sdhci_pdata_t #define EMMC_DATA (0x20) #define EMMC_STATUS (0x24) #define EMMC_CONTROL0 (0x28) +#define EMMC_BLKGAP_CTL (0x2a) +#define EMMC_WAKE_CONTROL (0x2B) #define EMMC_CONTROL1 (0x2c) +#define EMMC_TIMECTL (0x2e) #define EMMC_INTERRUPT (0x30) -#define EMMC_IRPT_MASK (0x34) +#define EMMC_ERR_INTERRUPT (0x32) + +#define EMMC_NOR_IRTR_STS_EN_OFFSET (0x34) +#define EMMC_ERR_INTR_STS_EN_OFFSET (0x36U) + #define EMMC_IRPT_EN (0x38) +#define SDHCI_ERR_INTR_SIG_EN_OFFSET 0x3AU /**< Error Interrupt + Signal Enable Register */ + #define EMMC_CONTROL2 (0x3c) +#define EMMC_HOST_CONTROL2 (0x3e) + #define EMMC_CAPABILITIES_0 (0x40) #define EMMC_CAPABILITIES_1 (0x44) +#define EMMC_ADMA_SAR_OFFSET (0x58) #define EMMC_BOOT_TIMEOUT (0x70) #define EMMC_EXRDFIFO_EN (0x84) #define EMMC_SPI_INT_SPT (0xf0) #define EMMC_SLOTISR_VER (0xfc) +#define EMMC_HOST_VERSION (0xfe) +#define EMMC_MY_CONTROL2 (0x3e) + +//CONTROL2 MASK +#define SDHCI_CTL2_SHCVER_MASK (1 << 12) +#define SDHCI_CTL2_BITADDR_MASK (1 << 13) + +//Capabilities1 MASK +#define SDHCI_CAPA_ADMA2_MASK (1 << 19) + +//Capabilities2 MASK +#define SDHCI_CAPA_ADMA3_MASK (1 << 27) + +#define SDHCI_BLK_SIZE_MASK 0x00000FFFU +#define SDHCI_BLK_CNT_MASK 0x00000FFFU + +//Interrupt +#define SDHCI_INTR_ALL_MASK 0xFFFFFFFFU +#define SDHCI_NORM_INTR_ALL_MASK 0x0000FFFFU +#define SDHCI_ERROR_INTR_ALL_MASK 0x0000F3FFU /**< Mask for error bits */ +#define SDHCI_INTR_CARD_MASK 0x00000100U /**< Card Interrupt */ + + + +/** @} */ + +/** @name Transfer Mode and Command Register + * + * The Transfer Mode register is used to control the data transfers and + * Command register is used for command generation + * Read/Write except for reserved bits. + * @{ + */ + +#define SDHCI_TM_DMA_EN_MASK 0x00000001U /**< DMA Enable */ +#define SDHCI_TM_BLK_CNT_EN_MASK 0x00000002U /**< Block Count Enable */ +#define SDHCI_TM_AUTO_CMD12_EN_MASK 0x00000004U /**< Auto CMD12 Enable */ +#define SDHCI_TM_DAT_DIR_SEL_MASK 0x00000010U /**< Data Transfer + Direction Select */ +#define SDHCI_TM_MUL_SIN_BLK_SEL_MASK 0x00000020U /**< Multi/Single + Block Select */ +/** + *@name ADMA2 Descriptor related definitions + * @{ + */ +/** + * ADMA2 Descriptor related definitions + */ +#define SDHCI_DESC_MAX_LENGTH 65536U + +#define SDHCI_DESC_VALID (0x1U << 0) +#define SDHCI_DESC_END (0x1U << 1) +#define SDHCI_DESC_INT (0x1U << 2) +#define SDHCI_DESC_TRAN (0x2U << 4) // CONTROL register settings #define C0_SPI_MODE_EN (0x00100000) diff --git a/bsp/raspberry-pi/raspi4-64/drivers/raspi4.h b/bsp/raspberry-pi/raspi4-64/drivers/raspi4.h index f3e6ed89274fd7a91452bafb4f950cc2437ba5c2..c03d0edc8791d11179003c4b6a2e802fb7081ebe 100644 --- a/bsp/raspberry-pi/raspi4-64/drivers/raspi4.h +++ b/bsp/raspberry-pi/raspi4-64/drivers/raspi4.h @@ -186,4 +186,26 @@ rt_inline size_t platform_get_gic_cpu_base(void) return GIC_PL400_CONTROLLER_PPTR; } +/** + * ADMA2 64-Bit descriptor table + */ +typedef struct { + uint16_t Attribute; /**< Attributes of descriptor */ + uint16_t Length; /**< Length of current dma transfer */ + uint64_t Address; /**< Address of current dma transfer */ +}sdhci_Adma2Descriptor64; + +/** + * ADMA2 32-Bit descriptor table + */ +typedef struct { + uint16_t Attribute; /**< Attributes of descriptor */ + uint16_t Length; /**< Length of current dma transfer */ + uint32_t Address; /**< Address of current dma transfer */ +}sdhci_Adma2Descriptor32; + +#define virtual_to_physical(v) ((void *)((uint64_t)v + PV_OFFSET)) +#define physical_to_virtual(p) ((void *)((uint64_t)p - PV_OFFSET)) + + #endif