diff --git a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c b/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c index 9b03519fe87e0939ca95976c04e27c171cc5076c..59aacbe674951ec473a67a18c34b44574d010478 100644 --- a/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c +++ b/bsp/raspberry-pi/raspi4-64/drivers/drv_sdio.c @@ -11,9 +11,12 @@ #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), @@ -81,6 +84,26 @@ static rt_uint32_t sdCommandTable[] = { 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))); @@ -96,8 +119,11 @@ 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--) + 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)) { @@ -116,6 +142,90 @@ rt_err_t sd_int(struct sdhci_pdata_t * pdat, rt_uint32_t mask) return RT_EOK; } +/*****************************************************************************/ +/** +* +* @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; @@ -140,20 +250,35 @@ static rt_err_t raspi_transfer_command(struct sdhci_pdata_t * pdat, struct sdhci 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; } cmdidx = sdCommandTable[cmd->cmdidx]; if (cmdidx == 0xFFFFFFFF) return -RT_EINVAL; - if (cmd->datarw == DATA_READ) - cmdidx |= SD_DATA_READ; - 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)); + 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; + 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); @@ -193,10 +318,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) { int c = 0; @@ -248,7 +375,7 @@ static rt_err_t raspi_transfer_data(struct sdhci_pdata_t * pdat, struct sdhci_cm 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) @@ -269,21 +396,28 @@ 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; + 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 ); - ret = read_bytes(pdat, (rt_uint32_t *)dat->buf, 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); + mmcsd_dbg("write_block %d, %d\n", dat->blkcnt, dat->blksz ); + } + ret = sd_int(pdat, INT_DATA_DONE); + if (ret) + { + return ret; } return ret; } @@ -347,6 +481,10 @@ rt_int32_t mmc_card_status(struct rt_mmcsd_host *host) 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; } @@ -450,7 +588,7 @@ static rt_err_t sdhci_setclock(struct sdhci_t * sdhci, rt_uint32_t clock) 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); @@ -473,7 +611,6 @@ 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; } @@ -485,12 +622,21 @@ static void mmc_set_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io 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_get_adma_ver, }; static rt_err_t reset_emmc(struct sdhci_pdata_t * pdat) @@ -522,8 +668,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"); @@ -563,6 +707,27 @@ 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) { @@ -589,7 +754,7 @@ int raspi_sdmmc_init(void) 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(); if (!host) @@ -622,6 +787,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 +803,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 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..14a8ba8c20c4b0d03c1e1654626f246718282817 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 */ +} __attribute__((__packed__))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 */ +} __attribute__((__packed__))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