diff --git a/arch/arm/src/imxrt/imxrt_usdhc.c b/arch/arm/src/imxrt/imxrt_usdhc.c index eaad361e77..7583823c79 100644 --- a/arch/arm/src/imxrt/imxrt_usdhc.c +++ b/arch/arm/src/imxrt/imxrt_usdhc.c @@ -77,6 +77,10 @@ /* Configuration ************************************************************/ +#if !defined(CONFIG_IMXRT_MAX_SDHCDEV_SLOTS) +# define CONFIG_IMXRT_MAX_SDHCDEV_SLOTS 2 +#endif + #if !defined(CONFIG_IMXRT_USDHC_DMA) # warning "Large Non-DMA transfer may result in RX overrun failures" #elif !defined(CONFIG_SDIO_DMA) @@ -97,47 +101,51 @@ /* Timing in ms for commands wait response */ -#define USDHC_CMDTIMEOUT MSEC2TICK(100) -#define USDHC_LONGTIMEOUT MSEC2TICK(500) +#define USDHC_CMDTIMEOUT MSEC2TICK(100) +#define USDHC_LONGTIMEOUT MSEC2TICK(500) /* Big DTOCV setting. Range is 0 = SDCLK * 2^13 through 15 = SDCLK * 2^29 */ -#define USDHC_DTOCV_MAXTIMEOUT (15) +#define USDHC_DTOCV_MAXTIMEOUT (15) /* Maximum watermark value */ -#define USDHC_MAX_WATERMARK 128 +#define USDHC_MAX_WATERMARK 128 /* Data transfer / Event waiting interrupt mask bits */ -#define USDHC_RESPERR_INTS (USDHC_INT_CCE | USDHC_INT_CTOE | \ - USDHC_INT_CEBE | USDHC_INT_CIE) -#define USDHC_RESPDONE_INTS (USDHC_RESPERR_INTS | USDHC_INT_CC) +#define USDHC_RESPERR_INTS (USDHC_INT_CCE | USDHC_INT_CTOE | \ + USDHC_INT_CEBE | USDHC_INT_CIE) +#define USDHC_RESPDONE_INTS (USDHC_RESPERR_INTS | USDHC_INT_CC) -#define USDHC_XFRERR_INTS (USDHC_INT_DCE | USDHC_INT_DTOE | \ - USDHC_INT_DEBE) -#define USDHC_RCVDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BRR | \ - USDHC_INT_TC) -#define USDHC_SNDDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BWR | \ - USDHC_INT_TC) -#define USDHC_XFRDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BRR | \ - USDHC_INT_BWR | USDHC_INT_TC) +#define USDHC_XFRERR_INTS (USDHC_INT_DCE | USDHC_INT_DTOE | \ + USDHC_INT_DEBE) +#define USDHC_RCVDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BRR | \ + USDHC_INT_TC) +#define USDHC_SNDDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BWR | \ + USDHC_INT_TC) +#define USDHC_XFRDONE_INTS (USDHC_XFRERR_INTS | USDHC_INT_BRR | \ + USDHC_INT_BWR | USDHC_INT_TC) + +/* CD Detect Types */ /* For DMA operations DINT is not interesting TC will indicate completions */ -#define USDHC_DMAERR_INTS (USDHC_XFRERR_INTS | USDHC_INT_DMAE) -#define USDHC_DMADONE_INTS (USDHC_DMAERR_INTS | USDHC_INT_TC) +#define USDHC_DMAERR_INTS (USDHC_XFRERR_INTS | USDHC_INT_DMAE) +#define USDHC_DMADONE_INTS (USDHC_DMAERR_INTS | USDHC_INT_TC) -#define USDHC_WAITALL_INTS (USDHC_RESPDONE_INTS | USDHC_XFRDONE_INTS | \ - USDHC_DMADONE_INTS) +#define USDHC_WAITALL_INTS (USDHC_RESPDONE_INTS | \ + USDHC_XFRDONE_INTS | \ + USDHC_DMADONE_INTS) /* Register logging support */ #ifdef CONFIG_SDIO_XFRDEBUG -# define SAMPLENDX_BEFORE_SETUP 0 -# define SAMPLENDX_AFTER_SETUP 1 -# define SAMPLENDX_END_TRANSFER 2 -# define DEBUG_NSAMPLES 3 +# define DBG_BASE_ADDR IMXRT_USDHC1_BASE +# define SAMPLENDX_BEFORE_SETUP 0 +# define SAMPLENDX_AFTER_SETUP 1 +# define SAMPLENDX_END_TRANSFER 2 +# define DEBUG_NSAMPLES 3 #endif /**************************************************************************** @@ -148,39 +156,48 @@ struct imxrt_dev_s { - struct sdio_dev_s dev; /* Standard, base SDIO interface */ + struct sdio_dev_s dev; /* Standard, base SDIO interface */ /* Imxrt-specific extensions */ + /* Event support */ - sem_t waitsem; /* Implements event waiting */ - sdio_eventset_t waitevents; /* Set of events to be waited for */ - uint32_t waitints; /* Interrupt enables for event waiting */ + sem_t waitsem; /* Implements event waiting */ + sdio_eventset_t waitevents; /* Set of events to be waited for */ + uint32_t waitints; /* Interrupt enables for event waiting */ volatile sdio_eventset_t wkupevent; /* The event that caused the wakeup */ - WDOG_ID waitwdog; /* Watchdog that handles event timeouts */ + WDOG_ID waitwdog; /* Watchdog that handles event timeouts */ /* Callback support */ - sdio_statset_t cdstatus; /* Card status */ - sdio_eventset_t cbevents; /* Set of events to be cause callbacks */ - worker_t callback; /* Registered callback function */ - void *cbarg; /* Registered callback argument */ - struct work_s cbwork; /* Callback work queue structure */ + sdio_statset_t cdstatus; /* Card status */ + sdio_eventset_t cbevents; /* Set of events to be cause callbacks */ + worker_t callback; /* Registered callback function */ + void *cbarg; /* Registered callback argument */ + struct work_s cbwork; /* Callback work queue structure */ /* Interrupt mode data transfer support */ - uint32_t *buffer; /* Address of current R/W buffer */ - size_t remaining; /* Number of bytes remaining in the transfer */ - uint32_t xfrints; /* Interrupt enables for data transfer */ - - /* DMA data transfer support */ + uint32_t *buffer; /* Address of current R/W buffer */ + size_t remaining; /* Number of bytes remaining in the transfer */ + uint32_t xfrints; /* Interrupt enables for data transfer */ #ifdef CONFIG_IMXRT_USDHC_DMA - volatile uint8_t xfrflags; /* Used to synchronize SDIO and DMA - * completion events */ - uint32_t *bufferend; /* Far end of R/W buffer for cache - * invalidation purposes */ + /* DMA data transfer support */ + + volatile uint8_t xfrflags; /* Used to synchronize SDIO and DMA completion */ + uint32_t *bufferend; /* Far end of R/W buffer for cache invalidation */ #endif + + /* Card interrupt support for SDIO */ + + uint32_t cintints; /* Interrupt enables for card ints */ + int (*do_sdio_card)(void *); /* SDIO card ISR */ + void *do_sdio_arg; /* arg for SDIO card ISR */ + + /* Direct address of this instances registers */ + + uint32_t addr; }; /* Register logging support */ @@ -190,35 +207,35 @@ struct imxrt_sdhcregs_s { /* All read-able USDHC registers */ - uint32_t dsaddr; /* DMA System Address Register */ - uint32_t blkattr; /* Block Attributes Register */ - uint32_t cmdarg; /* Command Argument Register */ - uint32_t xferty; /* Transfer Type Register */ - uint32_t cmdrsp0; /* Command Response 0 */ - uint32_t cmdrsp1; /* Command Response 1 */ - uint32_t cmdrsp2; /* Command Response 2 */ - uint32_t cmdrsp3; /* Command Response 3 */ - uint32_t dbap; /* Data buffer access port */ - uint32_t prsstat; /* Present State Register */ - uint32_t proctl; /* Protocol Control Register */ - uint32_t sysctl; /* System Control Register */ - uint32_t irqstat; /* Interrupt Status Register */ - uint32_t irqstaten; /* Interrupt Status Enable Register */ - uint32_t irqsigen; /* Interrupt Signal Enable Register */ - uint32_t ac12err; /* Auto CMD12 Error Status Register */ - uint32_t htcapblt; /* Host Controller Capabilities */ - uint32_t wml; /* Watermark Level Register */ - uint32_t mixctrl; /* Mixer Control */ - uint32_t fevent; /* Force Event */ - uint32_t admaes; /* ADMA Error Status Register */ - uint32_t adsaddr; /* ADMA System Address Register */ - uint32_t dllctrl; /* Delay line control */ - uint32_t dllstat; /* Delay line status */ - uint32_t clktune; /* Clock tune and control */ - uint32_t vendor; /* Vendor Specific Register */ - uint32_t mmcboot; /* MMC Boot Register */ - uint32_t vendor2; /* Vendor Specific Register 2 */ - uint32_t tuningctrl; /* Tuning Control */ + uint32_t dsaddr; /* DMA System Address Register */ + uint32_t blkattr; /* Block Attributes Register */ + uint32_t cmdarg; /* Command Argument Register */ + uint32_t xferty; /* Transfer Type Register */ + uint32_t cmdrsp0; /* Command Response 0 */ + uint32_t cmdrsp1; /* Command Response 1 */ + uint32_t cmdrsp2; /* Command Response 2 */ + uint32_t cmdrsp3; /* Command Response 3 */ + uint32_t dbap; /* Data buffer access port */ + uint32_t prsstat; /* Present State Register */ + uint32_t proctl; /* Protocol Control Register */ + uint32_t sysctl; /* System Control Register */ + uint32_t irqstat; /* Interrupt Status Register */ + uint32_t irqstaten; /* Interrupt Status Enable Register */ + uint32_t irqsigen; /* Interrupt Signal Enable Register */ + uint32_t ac12err; /* Auto CMD12 Error Status Register */ + uint32_t htcapblt; /* Host Controller Capabilities */ + uint32_t wml; /* Watermark Level Register */ + uint32_t mixctrl; /* Mixer Control */ + uint32_t fevent; /* Force Event */ + uint32_t admaes; /* ADMA Error Status Register */ + uint32_t adsaddr; /* ADMA System Address Register */ + uint32_t dllctrl; /* Delay line control */ + uint32_t dllstat; /* Delay line status */ + uint32_t clktune; /* Clock tune and control */ + uint32_t vendor; /* Vendor Specific Register */ + uint32_t mmcboot; /* MMC Boot Register */ + uint32_t vendor2; /* Vendor Specific Register 2 */ + uint32_t tuningctrl; /* Tuning Control */ }; #endif @@ -244,21 +261,24 @@ static void imxrt_dumpsample(struct imxrt_dev_s *priv, struct imxrt_sdhcregs_s *regs, const char *msg); static void imxrt_dumpsamples(struct imxrt_dev_s *priv); static void imxrt_showregs(struct imxrt_dev_s *priv, const char *msg); + #else # define imxrt_sampleinit() -# define imxrt_sample(priv,index) +# define imxrt_sample(priv, index) # define imxrt_dumpsamples(priv) -# define imxrt_showregs(priv,msg) +# define imxrt_showregs(priv, msg) #endif /* Data Transfer Helpers ****************************************************/ static void imxrt_dataconfig(struct imxrt_dev_s *priv, bool bwrite, - unsigned int dataLen, unsigned int timeout); + unsigned int datalen, unsigned int timeout); + #ifndef CONFIG_IMXRT_USDHC_DMA static void imxrt_transmit(struct imxrt_dev_s *priv); static void imxrt_receive(struct imxrt_dev_s *priv); #endif + static void imxrt_eventtimeout(int argc, uint32_t arg); static void imxrt_endwait(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent); @@ -283,17 +303,19 @@ static void imxrt_reset(FAR struct sdio_dev_s *dev); static sdio_capset_t imxrt_capabilities(FAR struct sdio_dev_s *dev); static sdio_statset_t imxrt_status(FAR struct sdio_dev_s *dev); static void imxrt_widebus(FAR struct sdio_dev_s *dev, bool enable); + #ifdef CONFIG_IMXRT_USDHC_ABSFREQ static void imxrt_frequency(FAR struct sdio_dev_s *dev, uint32_t frequency); #endif -static void imxrt_clock(FAR struct sdio_dev_s *dev, - enum sdio_clock_e rate); + +static void imxrt_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate); static int imxrt_attach(FAR struct sdio_dev_s *dev); /* Command/Status/Data Transfer */ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg); + #ifdef CONFIG_SDIO_BLOCKSETUP static void imxrt_blocksetup(FAR struct sdio_dev_s *dev, unsigned int blocklen, unsigned int nblocks); @@ -305,8 +327,8 @@ static int imxrt_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, static int imxrt_sendsetup(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer, uint32_t nbytes); #endif -static int imxrt_cancel(FAR struct sdio_dev_s *dev); +static int imxrt_cancel(FAR struct sdio_dev_s *dev); static int imxrt_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd); static int imxrt_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rshort); @@ -321,8 +343,8 @@ static int imxrt_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, static void imxrt_waitenable(FAR struct sdio_dev_s *dev, sdio_eventset_t eventset); -static sdio_eventset_t - imxrt_eventwait(FAR struct sdio_dev_s *dev, uint32_t timeout); +static sdio_eventset_t imxrt_eventwait(FAR struct sdio_dev_s *dev, + uint32_t timeout); static void imxrt_callbackenable(FAR struct sdio_dev_s *dev, sdio_eventset_t eventset); static int imxrt_registercallback(FAR struct sdio_dev_s *dev, @@ -345,59 +367,113 @@ static void imxrt_callback(void *arg); * Private Data ****************************************************************************/ -struct imxrt_dev_s g_sdhcdev = +struct imxrt_dev_s g_sdhcdev[CONFIG_IMXRT_MAX_SDHCDEV_SLOTS] = { - .dev = { + .addr = IMXRT_USDHC1_BASE, + .dev = + { #ifdef CONFIG_SDIO_MUXBUS - .lock = imxrt_lock, + .lock = imxrt_lock, #endif - .reset = imxrt_reset, - .capabilities = imxrt_capabilities, - .status = imxrt_status, - .widebus = imxrt_widebus, - .clock = imxrt_clock, - .attach = imxrt_attach, - .sendcmd = imxrt_sendcmd, + .reset = imxrt_reset, + .capabilities = imxrt_capabilities, + .status = imxrt_status, + .widebus = imxrt_widebus, + .clock = imxrt_clock, + .attach = imxrt_attach, + .sendcmd = imxrt_sendcmd, #ifdef CONFIG_SDIO_BLOCKSETUP - .blocksetup = imxrt_blocksetup, + .blocksetup = imxrt_blocksetup, #endif #ifndef CONFIG_IMXRT_USDHC_DMA - .recvsetup = imxrt_recvsetup, - .sendsetup = imxrt_sendsetup, + .recvsetup = imxrt_recvsetup, + .sendsetup = imxrt_sendsetup, #else - .recvsetup = imxrt_dmarecvsetup, - .sendsetup = imxrt_dmasendsetup, + .recvsetup = imxrt_dmarecvsetup, + .sendsetup = imxrt_dmasendsetup, #endif - .cancel = imxrt_cancel, - .waitresponse = imxrt_waitresponse, - .recvR1 = imxrt_recvshortcrc, - .recvR2 = imxrt_recvlong, - .recvR3 = imxrt_recvshort, - .recvR4 = imxrt_recvnotimpl, - .recvR5 = imxrt_recvnotimpl, - .recvR6 = imxrt_recvshortcrc, - .recvR7 = imxrt_recvshort, - .waitenable = imxrt_waitenable, - .eventwait = imxrt_eventwait, - .callbackenable = imxrt_callbackenable, - .registercallback = imxrt_registercallback, + .cancel = imxrt_cancel, + .waitresponse = imxrt_waitresponse, + .recvR1 = imxrt_recvshortcrc, + .recvR2 = imxrt_recvlong, + .recvR3 = imxrt_recvshort, + .recvR4 = imxrt_recvshort, + .recvR5 = imxrt_recvshortcrc, + .recvR6 = imxrt_recvshortcrc, + .recvR7 = imxrt_recvshort, + .waitenable = imxrt_waitenable, + .eventwait = imxrt_eventwait, + .callbackenable = imxrt_callbackenable, + .registercallback = imxrt_registercallback, #ifdef CONFIG_SDIO_DMA #ifdef CONFIG_IMXRT_USDHC_DMA - .dmarecvsetup = imxrt_dmarecvsetup, - .dmasendsetup = imxrt_dmasendsetup, + .dmarecvsetup = imxrt_dmarecvsetup, + .dmasendsetup = imxrt_dmasendsetup, #else - .dmarecvsetup = imxrt_recvsetup, - .dmasendsetup = imxrt_sendsetup, + .dmarecvsetup = imxrt_recvsetup, + .dmasendsetup = imxrt_sendsetup, #endif #endif + } }, +#if (CONFIG_IMXRT_MAX_SDHCDEV_SLOTS > 1) + { + .addr = IMXRT_USDHC2_BASE, + .dev = + { +#ifdef CONFIG_SDIO_MUXBUS + .lock = imxrt_lock, +#endif + .reset = imxrt_reset, + .capabilities = imxrt_capabilities, + .status = imxrt_status, + .widebus = imxrt_widebus, + .clock = imxrt_clock, + .attach = imxrt_attach, + .sendcmd = imxrt_sendcmd, +#ifdef CONFIG_SDIO_BLOCKSETUP + .blocksetup = imxrt_blocksetup, +#endif + +#ifndef CONFIG_IMXRT_USDHC_DMA + .recvsetup = imxrt_recvsetup, + .sendsetup = imxrt_sendsetup, +#else + .recvsetup = imxrt_dmarecvsetup, + .sendsetup = imxrt_dmasendsetup, +#endif + .cancel = imxrt_cancel, + .waitresponse = imxrt_waitresponse, + .recvR1 = imxrt_recvshortcrc, + .recvR2 = imxrt_recvlong, + .recvR3 = imxrt_recvshort, + .recvR4 = imxrt_recvshort, + .recvR5 = imxrt_recvshortcrc, + .recvR6 = imxrt_recvshortcrc, + .recvR7 = imxrt_recvshort, + .waitenable = imxrt_waitenable, + .eventwait = imxrt_eventwait, + .callbackenable = imxrt_callbackenable, + .registercallback = imxrt_registercallback, +#ifdef CONFIG_SDIO_DMA +#ifdef CONFIG_IMXRT_USDHC_DMA + .dmarecvsetup = imxrt_dmarecvsetup, + .dmasendsetup = imxrt_dmasendsetup, +#else + .dmarecvsetup = imxrt_recvsetup, + .dmasendsetup = imxrt_sendsetup, +#endif + } + } +#endif +#endif }; +#ifdef CONFIG_SDIO_XFRDEBUG /* Register logging support */ -#ifdef CONFIG_SDIO_XFRDEBUG static struct imxrt_sdhcregs_s g_sampleregs[DEBUG_NSAMPLES]; #endif @@ -470,10 +546,12 @@ static void imxrt_configwaitints(struct imxrt_dev_s *priv, uint32_t waitints, priv->waitevents = waitevents; priv->wkupevent = wkupevent; priv->waitints = waitints; + #ifdef CONFIG_IMXRT_USDHC_DMA priv->xfrflags = 0; #endif - putreg32(priv->xfrints | priv->waitints, IMXRT_USDHC1_IRQSIGEN); + putreg32(priv->xfrints | priv->waitints | priv->cintints, + priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); leave_critical_section(flags); } @@ -498,7 +576,8 @@ static void imxrt_configxfrints(struct imxrt_dev_s *priv, uint32_t xfrints) flags = enter_critical_section(); priv->xfrints = xfrints; - putreg32(priv->xfrints | priv->waitints, IMXRT_USDHC1_IRQSIGEN); + putreg32(priv->xfrints | priv->waitints | priv->cintints, + priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); leave_critical_section(flags); } @@ -513,7 +592,8 @@ static void imxrt_configxfrints(struct imxrt_dev_s *priv, uint32_t xfrints) #ifdef CONFIG_SDIO_XFRDEBUG static void imxrt_sampleinit(void) { - memset(g_sampleregs, 0xff, DEBUG_NSAMPLES * sizeof(struct imxrt_sdhcregs_s)); + memset(g_sampleregs, 0xff, + DEBUG_NSAMPLES * sizeof(struct imxrt_sdhcregs_s)); } #endif @@ -528,27 +608,27 @@ static void imxrt_sampleinit(void) #ifdef CONFIG_SDIO_XFRDEBUG static void imxrt_sdhcsample(struct imxrt_sdhcregs_s *regs) { - regs->dsaddr = getreg32(IMXRT_USDHC1_DSADDR); /* DMA System Address Register */ - regs->blkattr = getreg32(IMXRT_USDHC1_BLKATTR); /* Block Attributes Register */ - regs->cmdarg = getreg32(IMXRT_USDHC1_CMDARG); /* Command Argument Register */ - regs->xferty = getreg32(IMXRT_USDHC1_XFERTYP); /* Transfer Type Register */ - regs->cmdrsp0 = getreg32(IMXRT_USDHC1_CMDRSP0); /* Command Response 0 */ - regs->cmdrsp1 = getreg32(IMXRT_USDHC1_CMDRSP1); /* Command Response 1 */ - regs->cmdrsp2 = getreg32(IMXRT_USDHC1_CMDRSP2); /* Command Response 2 */ - regs->cmdrsp3 = getreg32(IMXRT_USDHC1_CMDRSP3); /* Command Response 3 */ - regs->prsstat = getreg32(IMXRT_USDHC1_PRSSTAT); /* Present State Register */ - regs->proctl = getreg32(IMXRT_USDHC1_PROCTL); /* Protocol Control Register */ - regs->sysctl = getreg32(IMXRT_USDHC1_SYSCTL); /* System Control Register */ - regs->irqstat = getreg32(IMXRT_USDHC1_IRQSTAT); /* Interrupt Status Register */ - regs->irqstaten = getreg32(IMXRT_USDHC1_IRQSTATEN); /* Interrupt Status Enable Register */ - regs->irqsigen = getreg32(IMXRT_USDHC1_IRQSIGEN); /* Interrupt Signal Enable Register */ - regs->ac12err = getreg32(IMXRT_USDHC1_AC12ERR); /* Auto CMD12 Error Status Register */ - regs->htcapblt = getreg32(IMXRT_USDHC1_HTCAPBLT); /* Host Controller Capabilities */ - regs->wml = getreg32(IMXRT_USDHC1_WML); /* Watermark Level Register */ - regs->admaes = getreg32(IMXRT_USDHC1_ADMAES); /* ADMA Error Status Register */ - regs->adsaddr = getreg32(IMXRT_USDHC1_ADSADDR); /* ADMA System Address Register */ - regs->vendor = getreg32(IMXRT_USDHC1_VENDOR); /* Vendor Specific Register */ - regs->mmcboot = getreg32(IMXRT_USDHC1_MMCBOOT); /* MMC Boot Register */ + regs->dsaddr = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_DSADDRL_OFFSET); + regs->blkattr = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_BLKATTRL_OFFSET); + regs->cmdarg = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_CMDARGL_OFFSET); + regs->xferty = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_XFERTYPL_OFFSET); + regs->cmdrsp0 = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_CMDRSP0L_OFFSET); + regs->cmdrsp1 = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_CMDRSP1L_OFFSET); + regs->cmdrsp2 = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_CMDRSP2L_OFFSET); + regs->cmdrsp3 = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_CMDRSP3L_OFFSET); + regs->prsstat = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_PRSSTATL_OFFSET); + regs->proctl = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_PROCTLL_OFFSET); + regs->sysctl = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_SYSCTLL_OFFSET); + regs->irqstat = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_IRQSTATL_OFFSET); + regs->irqstaten = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_IRQSTATENL_OFFSET); + regs->irqsigen = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_IRQSIGENL_OFFSET); + regs->ac12err = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_AC12ERRL_OFFSET); + regs->htcapblt = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_HTCAPBLTL_OFFSET); + regs->wml = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_WMLL_OFFSET); + regs->admaes = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_ADMAESL_OFFSET); + regs->adsaddr = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_ADSADDRL_OFFSET); + regs->vendor = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_VENDORL_OFFSET); + regs->mmcboot = getreg32(DBG_BASE_ADDR + IMXRT_USDHC_MMCBOOTL_OFFSET); } #endif @@ -563,7 +643,10 @@ static void imxrt_sdhcsample(struct imxrt_sdhcregs_s *regs) #ifdef CONFIG_SDIO_XFRDEBUG static void imxrt_sample(struct imxrt_dev_s *priv, int index) { - imxrt_sdhcsample(&g_sampleregs[index]); + if (priv->addr == DBG_BASE_ADDR) + { + imxrt_sdhcsample(&g_sampleregs[index]); + } } #endif @@ -577,30 +660,51 @@ static void imxrt_sample(struct imxrt_dev_s *priv, int index) #ifdef CONFIG_SDIO_XFRDEBUG static void imxrt_dumpsample(struct imxrt_dev_s *priv, - struct imxrt_sdhcregs_s *regs, const char *msg) + struct imxrt_sdhcregs_s *regs, const char *msg) { mcinfo("USDHC Registers: %s\n", msg); - mcinfo(" DSADDR[%08x]: %08x\n", IMXRT_USDHC1_DSADDR, regs->dsaddr); - mcinfo(" BLKATTR[%08x]: %08x\n", IMXRT_USDHC1_BLKATTR, regs->blkattr); - mcinfo(" CMDARG[%08x]: %08x\n", IMXRT_USDHC1_CMDARG, regs->cmdarg); - mcinfo(" XFERTY[%08x]: %08x\n", IMXRT_USDHC1_XFERTYP, regs->xferty); - mcinfo(" CMDRSP0[%08x]: %08x\n", IMXRT_USDHC1_CMDRSP0, regs->cmdrsp0); - mcinfo(" CMDRSP1[%08x]: %08x\n", IMXRT_USDHC1_CMDRSP1, regs->cmdrsp1); - mcinfo(" CMDRSP2[%08x]: %08x\n", IMXRT_USDHC1_CMDRSP2, regs->cmdrsp2); - mcinfo(" CMDRSP3[%08x]: %08x\n", IMXRT_USDHC1_CMDRSP3, regs->cmdrsp3); - mcinfo(" PRSSTAT[%08x]: %08x\n", IMXRT_USDHC1_PRSSTAT, regs->prsstat); - mcinfo(" PROCTL[%08x]: %08x\n", IMXRT_USDHC1_PROCTL, regs->proctl); - mcinfo(" SYSCTL[%08x]: %08x\n", IMXRT_USDHC1_SYSCTL, regs->sysctl); - mcinfo(" IRQSTAT[%08x]: %08x\n", IMXRT_USDHC1_IRQSTAT, regs->irqstat); - mcinfo("IRQSTATEN[%08x]: %08x\n", IMXRT_USDHC1_IRQSTATEN, regs->irqstaten); - mcinfo(" IRQSIGEN[%08x]: %08x\n", IMXRT_USDHC1_IRQSIGEN, regs->irqsigen); - mcinfo(" AC12ERR[%08x]: %08x\n", IMXRT_USDHC1_AC12ERR, regs->ac12err); - mcinfo(" HTCAPBLT[%08x]: %08x\n", IMXRT_USDHC1_HTCAPBLT, regs->htcapblt); - mcinfo(" WML[%08x]: %08x\n", IMXRT_USDHC1_WML, regs->wml); - mcinfo(" ADMAES[%08x]: %08x\n", IMXRT_USDHC1_ADMAES, regs->admaes); - mcinfo(" ADSADDR[%08x]: %08x\n", IMXRT_USDHC1_ADSADDR, regs->adsaddr); - mcinfo(" VENDOR[%08x]: %08x\n", IMXRT_USDHC1_VENDOR, regs->vendor); - mcinfo(" MMCBOOT[%08x]: %08x\n", IMXRT_USDHC1_MMCBOOT, regs->mmcboot); + mcinfo(" DSADDR[%08x]: %08x\n", + IMXRT_USDHC_DSADDR_OFFSET, regs->dsaddr); + mcinfo(" BLKATTR[%08x]: %08x\n", + IMXRT_USDHC_BLKATTR_OFFSET, regs->blkattr); + mcinfo(" CMDARG[%08x]: %08x\n", + IMXRT_USDHC_CMDARG_OFFSET, regs->cmdarg); + mcinfo(" XFERTY[%08x]: %08x\n", + IMXRT_USDHC_XFERTYP_OFFSET, regs->xferty); + mcinfo(" CMDRSP0[%08x]: %08x\n", + IMXRT_USDHC_CMDRSP0_OFFSET, regs->cmdrsp0); + mcinfo(" CMDRSP1[%08x]: %08x\n", + IMXRT_USDHC_CMDRSP1_OFFSET, regs->cmdrsp1); + mcinfo(" CMDRSP2[%08x]: %08x\n", + IMXRT_USDHC_CMDRSP2_OFFSET, regs->cmdrsp2); + mcinfo(" CMDRSP3[%08x]: %08x\n", + IMXRT_USDHC_CMDRSP3_OFFSET, regs->cmdrsp3); + mcinfo(" PRSSTAT[%08x]: %08x\n", + IMXRT_USDHC_PRSSTAT_OFFSET, regs->prsstat); + mcinfo(" PROCTL[%08x]: %08x\n", + IMXRT_USDHC_PROCTL_OFFSET, regs->proctl); + mcinfo(" SYSCTL[%08x]: %08x\n", + IMXRT_USDHC_SYSCTL_OFFSET, regs->sysctl); + mcinfo(" IRQSTAT[%08x]: %08x\n", + IMXRT_USDHC_IRQSTAT_OFFSET, regs->irqstat); + mcinfo("IRQSTATEN[%08x]: %08x\n", + IMXRT_USDHC_IRQSTATEN_OFFSET, regs->irqstaten); + mcinfo(" IRQSIGEN[%08x]: %08x\n", + IMXRT_USDHC_IRQSIGEN_OFFSET, regs->irqsigen); + mcinfo(" AC12ERR[%08x]: %08x\n", + IMXRT_USDHC_AC12ERR_OFFSET, regs->ac12err); + mcinfo(" HTCAPBLT[%08x]: %08x\n", + IMXRT_USDHC_HTCAPBLT_OFFSET, regs->htcapblt); + mcinfo(" WML[%08x]: %08x\n", + IMXRT_USDHC_WML_OFFSET, regs->wml); + mcinfo(" ADMAES[%08x]: %08x\n", + IMXRT_USDHC_ADMAES_OFFSET, regs->admaes); + mcinfo(" ADSADDR[%08x]: %08x\n", + IMXRT_USDHC_ADSADDR_OFFSET, regs->adsaddr); + mcinfo(" VENDOR[%08x]: %08x\n", + IMXRT_USDHC_VENDOR_OFFSET, regs->vendor); + mcinfo(" MMCBOOT[%08x]: %08x\n", + IMXRT_USDHC_MMCBOOT_OFFSET, regs->mmcboot); } #endif @@ -613,7 +717,7 @@ static void imxrt_dumpsample(struct imxrt_dev_s *priv, ****************************************************************************/ #ifdef CONFIG_SDIO_XFRDEBUG -static void imxrt_dumpsamples(struct imxrt_dev_s *priv) +static void imxrt_dumpsamples(struct imxrt_dev_s *priv) { imxrt_dumpsample(priv, &g_sampleregs[SAMPLENDX_BEFORE_SETUP], "Before setup"); @@ -655,7 +759,7 @@ static void imxrt_showregs(struct imxrt_dev_s *priv, const char *msg) ****************************************************************************/ static void imxrt_dataconfig(struct imxrt_dev_s *priv, bool bwrite, - unsigned int dataLen, unsigned int timeout) + unsigned int datalen, unsigned int timeout) { unsigned int watermark; uint32_t regval = 0; @@ -664,51 +768,50 @@ static void imxrt_dataconfig(struct imxrt_dev_s *priv, bool bwrite, * value. */ - regval = getreg32(IMXRT_USDHC1_SYSCTL); + regval = getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); regval &= ~USDHC_SYSCTL_DTOCV_MASK; regval |= timeout << USDHC_SYSCTL_DTOCV_SHIFT; - putreg32(regval, IMXRT_USDHC1_SYSCTL); + putreg32(regval, priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); /* Set the watermark level */ - /* Set the Read Watermark Level to the dataLen to be read - * (limited to half of the maximum watermark value). BRR will be - * set when the number of queued words is greater than or equal - * to this value. + /* Set the Read Watermark Level to the datalen to be read (limited to half + * of the maximum watermark value). BRR will be set when the number of + * queued words is greater than or equal to this value. */ - watermark = (dataLen + 3) >> 2; + watermark = (datalen + 3) >> 2; if (watermark > (USDHC_MAX_WATERMARK / 2)) { watermark = (USDHC_MAX_WATERMARK / 2); } /* When the watermark level requirement is met in data transfer, and the - * internal DMA is enabled, the data buffer block sends a DMA request to - * the crossbar switch interface. + * internal DMA is enabled, the data buffer block sends a DMA request to the + * crossbar switch interface. */ if (bwrite) { - /* The USDHC will not start data transmission until the number of - * words set in the WML register can be held in the buffer. If the - * buffer is empty and the host system does not write data in time, - * the USDHC will stop the SD_CLK to avoid the data buffer under-run - * situation. + /* The USDHC will not start data transmission until the number of words + * set in the WML register can be held in the buffer. If the buffer is + * empty and the host system does not write data in time, the USDHC will + * stop the SD_CLK to avoid the data buffer under-run situation. */ - putreg32(watermark << USDHC_WML_WR_SHIFT, IMXRT_USDHC1_WML); + putreg32(watermark << USDHC_WML_WR_SHIFT, + priv->addr + IMXRT_USDHC_WML_OFFSET); } else { - /* The USDHC will not start data transmission until the number of - * words set in the WML register are in the buffer. If the buffer - * is full and the Host System does not read data in time, the - * USDHC will stop the USDHC_DCLK to avoid the data buffer over-run - * situation. + /* The USDHC will not start data transmission until the number of words + * set in the WML register are in the buffer. If the buffer is full and + * the Host System does not read data in time, the USDHC will stop the + * USDHC_DCLK to avoid the data buffer over-run situation. */ - putreg32(watermark << USDHC_WML_RD_SHIFT, IMXRT_USDHC1_WML); + putreg32(watermark << USDHC_WML_RD_SHIFT, + priv->addr + IMXRT_USDHC_WML_OFFSET); } } @@ -739,11 +842,12 @@ static void imxrt_transmit(struct imxrt_dev_s *priv) * (PRSSTAT.BWEN) */ - mcinfo("Entry: remaining: %d IRQSTAT: %08x\n", - priv->remaining, getreg32(IMXRT_USDHC1_IRQSTAT)); + mcinfo("Entry: remaining: %d IRQSTAT: %08x\n", priv->remaining, + getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET)); while (priv->remaining > 0 && - (getreg32(IMXRT_USDHC1_PRSSTAT) & USDHC_PRSSTAT_BWEN) != 0) + (getreg32(priv->addr + IMXRT_USDHC_PRSSTAT_OFFSET) & + USDHC_PRSSTAT_BWEN) != 0) { /* Is there a full word remaining in the user buffer? */ @@ -766,7 +870,7 @@ static void imxrt_transmit(struct imxrt_dev_s *priv) data.w = 0; for (i = 0; i < priv->remaining; i++) { - data.b[i] = *ptr++; + data.b[i] = *ptr++; } /* Now the transfer is finished */ @@ -776,17 +880,17 @@ static void imxrt_transmit(struct imxrt_dev_s *priv) /* Put the word in the FIFO */ - putreg32(data.w, IMXRT_USDHC1_DATPORT); + putreg32(data.w, priv->addr + IMXRT_USDHC_DATAPORT_OFFSET); } - /* Clear BWR. If there is more data in the buffer, writing to the - * buffer should reset BWR. + /* Clear BWR. If there is more data in the buffer, writing to the buffer + * should reset BWR. */ - putreg32(USDHC_INT_BWR, IMXRT_USDHC1_IRQSTAT); + putreg32(USDHC_INT_BWR, priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); - mcinfo("Exit: remaining: %d IRQSTAT: %08x\n", - priv->remaining, getreg32(IMXRT_USDHC1_IRQSTAT)); + mcinfo("Exit: remaining: %d IRQSTAT: %08x\n", priv->remaining, + getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET)); } #endif @@ -814,31 +918,32 @@ static void imxrt_receive(struct imxrt_dev_s *priv) uint8_t b[4]; } data; - /* Set the Read Watermark Level to 1: BRR will be set when the number of + /* Set the Read Watermark Level to 1: BRR will be set when the number of * queued words is greater than or equal to 1. */ - putreg32(1 << USDHC_WML_RD_SHIFT, IMXRT_USDHC1_WML); + putreg32(1 << USDHC_WML_RD_SHIFT, priv->addr + IMXRT_USDHC_WML_OFFSET); - /* Loop while there is space to store the data, waiting for buffer read - * ready (BRR) + /* Loop while there is space to store the data, waiting for buffer + * read ready (BRR) */ - mcinfo("Entry: remaining: %d IRQSTAT: %08x\n", - priv->remaining, getreg32(IMXRT_USDHC1_IRQSTAT)); + mcinfo("Entry: remaining: %d IRQSTAT: %08x\n", priv->remaining, + getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET)); while (priv->remaining > 0 && - (getreg32(IMXRT_USDHC1_IRQSTAT) & USDHC_INT_BRR) != 0) + (getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET) & + USDHC_INT_BRR) != 0) { /* Clear BRR. If there is more data in the buffer, reading from the * buffer should reset BRR. */ - putreg32(USDHC_INT_BRR, IMXRT_USDHC1_IRQSTAT); + putreg32(USDHC_INT_BRR, priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); /* Read the next word from the RX buffer */ - data.w = getreg32(IMXRT_USDHC1_DATPORT); + data.w = getreg32(priv->addr + IMXRT_USDHC_DATAPORT_OFFSET); if (priv->remaining >= sizeof(uint32_t)) { /* Transfer the whole word to the user buffer */ @@ -850,12 +955,12 @@ static void imxrt_receive(struct imxrt_dev_s *priv) { /* Transfer any trailing fractional word */ - uint8_t *ptr = (uint8_t *)priv->buffer; + uint8_t *ptr = (uint8_t *) priv->buffer; int i; for (i = 0; i < priv->remaining; i++) { - *ptr++ = data.b[i]; + *ptr++ = data.b[i]; } /* Now the transfer is finished */ @@ -874,11 +979,12 @@ static void imxrt_receive(struct imxrt_dev_s *priv) watermark = (USDHC_MAX_WATERMARK / 2); } - putreg32(watermark << USDHC_WML_RD_SHIFT, IMXRT_USDHC1_WML); + putreg32(watermark << USDHC_WML_RD_SHIFT, + priv->addr + IMXRT_USDHC_WML_OFFSET); - mcinfo("Exit: remaining: %d IRQSTAT: %08x WML: %08x\n", - priv->remaining, getreg32(IMXRT_USDHC1_IRQSTAT), - getreg32(IMXRT_USDHC1_WML)); + mcinfo("Exit: remaining: %d IRQSTAT: %08x WML: %08x\n", priv->remaining, + getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); + getreg32(priv->addr + IMXRT_USDHC_WML_OFFSET)); } #endif @@ -941,8 +1047,7 @@ static void imxrt_eventtimeout(int argc, uint32_t arg) * ****************************************************************************/ -static void imxrt_endwait(struct imxrt_dev_s *priv, - sdio_eventset_t wkupevent) +static void imxrt_endwait(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent) { /* Cancel the watchdog timeout */ @@ -980,14 +1085,14 @@ static void imxrt_endwait(struct imxrt_dev_s *priv, static void imxrt_endtransfer(struct imxrt_dev_s *priv, sdio_eventset_t wkupevent) { - /* Disable all transfer related interrupts */ imxrt_configxfrints(priv, 0); /* Clearing pending interrupt status on all transfer related interrupts */ - putreg32(USDHC_XFRDONE_INTS | USDHC_DMADONE_INTS, IMXRT_USDHC1_IRQSTAT); + putreg32(USDHC_XFRDONE_INTS | USDHC_DMADONE_INTS, + priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); /* Mark the transfer finished */ @@ -995,8 +1100,7 @@ static void imxrt_endtransfer(struct imxrt_dev_s *priv, /* DMA modified the buffer, so we need to flush its cache lines. */ - up_invalidate_dcache((uintptr_t)priv->buffer, - (uintptr_t)priv->bufferend); + up_invalidate_dcache((uintptr_t) priv->buffer, (uintptr_t) priv->bufferend); /* Debug instrumentation */ @@ -1028,34 +1132,34 @@ static void imxrt_endtransfer(struct imxrt_dev_s *priv, static int imxrt_interrupt(int irq, void *context, FAR void *arg) { - struct imxrt_dev_s *priv = &g_sdhcdev; + struct imxrt_dev_s *priv = (struct imxrt_dev_s *)arg; uint32_t enabled; uint32_t pending; uint32_t regval; /* Check the USDHC IRQSTAT register. Mask out all bits that don't * correspond to enabled interrupts. (This depends on the fact that bits - * are ordered the same in both the IRQSTAT and IRQSIGEN registers). If - * there are non-zero bits remaining, then we have work to do here. + * are ordered the same in both the IRQSTAT and IRQSIGEN registers). + * If there are non-zero bits remaining, then we have work to do here. */ - regval = getreg32(IMXRT_USDHC1_IRQSIGEN); - enabled = getreg32(IMXRT_USDHC1_IRQSTAT) & regval; + regval = getreg32(priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); + enabled = getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET) & regval; mcinfo("IRQSTAT: %08x IRQSIGEN %08x enabled: %08x\n", - getreg32(IMXRT_USDHC1_IRQSTAT), regval, enabled); + getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET), regval, enabled); /* Clear all pending interrupts */ - putreg32(enabled, IMXRT_USDHC1_IRQSTAT); + putreg32(enabled, priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); /* Handle in progress, interrupt driven data transfers ********************/ - pending = enabled & priv->xfrints; + pending = enabled & priv->xfrints; if (pending != 0) { #ifndef CONFIG_IMXRT_USDHC_DMA - /* Is the RX buffer read ready? Is so then we must be processing a + /* Is the RX buffer read ready? Is so then we must be processing a * non-DMA receive transaction. */ @@ -1066,9 +1170,8 @@ static int imxrt_interrupt(int irq, void *context, FAR void *arg) imxrt_receive(priv); } - /* Otherwise, Is the TX buffer write ready? If so we must - * be processing a non-DMA send transaction. NOTE: We can't be - * processing both! + /* Otherwise, Is the TX buffer write ready? If so we must be processing + * non-DMA send transaction. NOTE: We can't be processing both! */ else if ((pending & USDHC_INT_BWR) != 0) @@ -1094,7 +1197,8 @@ static int imxrt_interrupt(int irq, void *context, FAR void *arg) { /* Terminate the transfer with an error */ - mcerr("ERROR: Data block CRC failure, remaining: %d\n", priv->remaining); + mcerr("ERROR: Data block CRC failure, remaining: %d\n", + priv->remaining); imxrt_endtransfer(priv, SDIOWAIT_TRANSFERDONE | SDIOWAIT_ERROR); } @@ -1111,7 +1215,7 @@ static int imxrt_interrupt(int irq, void *context, FAR void *arg) /* Handle wait events *****************************************************/ - pending = enabled & priv->waitints; + pending = enabled & priv->waitints; if (pending != 0) { /* Is this a response completion event? */ @@ -1120,13 +1224,14 @@ static int imxrt_interrupt(int irq, void *context, FAR void *arg) { /* Yes.. Is their a thread waiting for response done? */ - if ((priv->waitevents & (SDIOWAIT_CMDDONE | SDIOWAIT_RESPONSEDONE)) != 0) + if ((priv->waitevents & + (SDIOWAIT_CMDDONE | SDIOWAIT_RESPONSEDONE)) != 0) { /* Yes.. mask further interrupts and wake the thread up */ - regval = getreg32(IMXRT_USDHC1_IRQSIGEN); + regval = getreg32(priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); regval &= ~USDHC_RESPDONE_INTS; - putreg32(regval, IMXRT_USDHC1_IRQSIGEN); + putreg32(regval, priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); imxrt_endwait(priv, SDIOWAIT_RESPONSEDONE); } @@ -1159,11 +1264,10 @@ static int imxrt_interrupt(int irq, void *context, FAR void *arg) #ifdef CONFIG_SDIO_MUXBUS static int imxrt_lock(FAR struct sdio_dev_s *dev, bool lock) { - /* Single SDIO instance so there is only one possibility. The multiplex - * bus is part of board support package. - */ + /* The multiplex bus is part of board support package. */ - imxrt_muxbus_sdio_lock(lock); + imxrt_muxbus_sdio_lock((dev - g_sdhcdev) / + sizeof(struct imxrt_dev_s), lock); return OK; } #endif @@ -1188,22 +1292,23 @@ static void imxrt_reset(FAR struct sdio_dev_s *dev) /* Disable all interrupts so that nothing interferes with the following. */ - putreg32(0, IMXRT_USDHC1_IRQSIGEN); + putreg32(0, priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); /* Reset the USDHC block, putting registers in their default, reset state. * Initiate the reset by setting the RSTA bit in the SYSCTL register. */ - modifyreg32(IMXRT_USDHC1_VENDOR2, 0, USDHC_VS2_BUSRESET); - modifyreg32(IMXRT_USDHC1_SYSCTL , 0, USDHC_SYSCTL_RSTA); - modifyreg32(IMXRT_USDHC1_VENDOR2, + modifyreg32(priv->addr + IMXRT_USDHC_VENDOR2_OFFSET, 0, USDHC_VS2_BUSRESET); + modifyreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET, 0, USDHC_SYSCTL_RSTA); + modifyreg32(priv->addr + IMXRT_USDHC_VENDOR2_OFFSET, USDHC_VS2_BUSRESET | USDHC_VS2_ACMD23ARGU2, 0); - /* The USDHC will reset the RSTA bit to 0 when the capabilities - * registers are valid and the host driver can read them. + /* The USDHC will reset the RSTA bit to 0 when the capabilities registers + * are valid and the host driver can read them. */ - while ((getreg32(IMXRT_USDHC1_SYSCTL) & USDHC_SYSCTL_RSTA) != 0) + while ((getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET) & + USDHC_SYSCTL_RSTA) != 0) { } @@ -1217,11 +1322,12 @@ static void imxrt_reset(FAR struct sdio_dev_s *dev) * interrupts. */ - putreg32(USDHC_INT_ALL, IMXRT_USDHC1_IRQSTATEN); + putreg32(USDHC_INT_ALL, priv->addr + IMXRT_USDHC_IRQSTATEN_OFFSET); mcinfo("SYSCTL: %08x PRSSTAT: %08x IRQSTATEN: %08x\n", - getreg32(IMXRT_USDHC1_SYSCTL), getreg32(IMXRT_USDHC1_PRSSTAT), - getreg32(IMXRT_USDHC1_IRQSTATEN)); + getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET), + getreg32(priv->addr + IMXRT_USDHC_PRSSTAT_OFFSET), + getreg32(priv->addr + IMXRT_USDHC_IRQSTATEN_OFFSET)); /* The next phase of the hardware reset would be to set the SYSCTRL INITA * bit to send 80 clock ticks for card to power up and then reset the card @@ -1230,21 +1336,20 @@ static void imxrt_reset(FAR struct sdio_dev_s *dev) /* Reset state data */ - priv->waitevents = 0; /* Set of events to be waited for */ - priv->waitints = 0; /* Interrupt enables for event waiting */ - priv->wkupevent = 0; /* The event that caused the wakeup */ + priv->waitevents = 0; /* Set of events to be waited for */ + priv->waitints = 0; /* Interrupt enables for event waiting */ + priv->wkupevent = 0; /* The event that caused the wakeup */ #ifdef CONFIG_IMXRT_USDHC_DMA - priv->xfrflags = 0; /* Used to synchronize SDIO and DMA completion - * events */ + priv->xfrflags = 0; /* Used to synchronize SDIO and DMA completion */ #endif - wd_cancel(priv->waitwdog); /* Cancel any timeouts */ + wd_cancel(priv->waitwdog); /* Cancel any timeouts */ /* Interrupt mode data transfer support */ - priv->buffer = 0; /* Address of current R/W buffer */ - priv->remaining = 0; /* Number of bytes remaining in the transfer */ - priv->xfrints = 0; /* Interrupt enables for data transfer */ + priv->buffer = 0; /* Address of current R/W buffer */ + priv->remaining = 0; /* Number of bytes remaining in the transfer */ + priv->xfrints = 0; /* Interrupt enables for data transfer */ } /**************************************************************************** @@ -1295,9 +1400,15 @@ static sdio_statset_t imxrt_status(FAR struct sdio_dev_s *dev) struct imxrt_dev_s *priv = (struct imxrt_dev_s *)dev; #if defined(CONFIG_MMCSD_HAVE_CARDDETECT) && defined(PIN_USDHC1_CD) + + /* Note that a CD pin is only supported on port1 for now - just check this + * if appropriately for more. + */ + if (!imxrt_gpio_read(PIN_USDHC1_CD)) #else - if ((getreg32(IMXRT_USDHC1_PRSSTAT) & USDHC_PRSSTAT_CINS) != 0) + if ((getreg32(priv->addr + IMXRT_USDHC_PRSSTAT_OFFSET) & + USDHC_PRSSTAT_CINS) != 0) #endif { priv->cdstatus |= SDIO_STATUS_PRESENT; @@ -1311,6 +1422,7 @@ static sdio_statset_t imxrt_status(FAR struct sdio_dev_s *dev) return priv->cdstatus; } + /**************************************************************************** * Name: imxrt_widebus * @@ -1330,11 +1442,12 @@ static sdio_statset_t imxrt_status(FAR struct sdio_dev_s *dev) static void imxrt_widebus(FAR struct sdio_dev_s *dev, bool wide) { + FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev; uint32_t regval; /* Set the Data Transfer Width (DTW) field in the PROCTL register. */ - regval = getreg32(IMXRT_USDHC1_PROCTL); + regval = getreg32(priv->addr + IMXRT_USDHC_PROCTL_OFFSET); regval &= ~USDHC_PROCTL_DTW_MASK; if (wide) { @@ -1345,7 +1458,7 @@ static void imxrt_widebus(FAR struct sdio_dev_s *dev, bool wide) regval |= USDHC_PROCTL_DTW_1BIT; } - putreg32(regval, IMXRT_USDHC1_PROCTL); + putreg32(regval, priv->addr + IMXRT_USDHC_PROCTL_OFFSET); } /**************************************************************************** @@ -1372,32 +1485,32 @@ static void imxrt_frequency(FAR struct sdio_dev_s *dev, uint32_t frequency) unsigned int prescaler; unsigned int divisor; - /* The SDCLK frequency is determined by (1) the frequency of the base clock - * that was selected as the input clock, and (2) by a prescaler and a - * divisor that are selected here: + /* The SDCLK frequency is determined by + * (1) the frequency of the base clock that was selected as the + * input clock, and + * (2) by a prescaler and a divisor that are selected here: * - * SDCLK frequency = (base clock) / (prescaler * divisor) + * SDCLK frequency = (base clock) / (prescaler * divisor) * - * The prescaler is avalable only for the values: 2, 4, 8, 16, 32, 64, 128, - * and 256. Pick the smallest value of SDCLKFS that would result in an - * in-range frequency. + * The prescaler is available only for the values: 2, 4, 8, 16, 32, + * 64, 128, and 256. Pick the smallest value of SDCLKFS that would + * result in an in-range frequency. For example, if the base clock frequency + * is 96 MHz, and the target frequency is 25 MHz, the following logic + * will select prescaler: * - * For example, if the base clock frequency is 96 MHz, and the target - * frequency is 25 MHz, the following logic will select prescaler. + * 96MHz / 2 <= 25MHz <= 96MHz / 2 /16 -- YES, prescaler == 2 * - * 96MHz / 2 <= 25MHz <= 96MHz / 2 /16 -- YES, prescaler == 2 + * If the target frequency is 400 kHz, the following logic will + * select prescaler: * - * If the target frequency is 400 kHz, the following logic will select - * prescaler: - * - * 96MHz / 2 <= 400KHz <= 96MHz / 2 / 16 -- NO - * 96MHz / 4 <= 400KHz <= 96MHz / 4 / 16 -- NO - * 96MHz / 8 <= 400KHz <= 96MHz / 8 / 16 -- NO - * 96MHz / 16 <= 400KHz <= 96MHz / 16 / 16 -- YES, prescaler == 16 + * 96MHz / 2 <= 400KHz <= 96MHz / 2 / 16 -- NO + * 96MHz / 4 <= 400KHz <= 96MHz / 4 / 16 -- NO + * 96MHz / 8 <= 400KHz <= 96MHz / 8 / 16 -- NO + * 96MHz / 16 <=400KHz <= 96MHz / 16 / 16 -- YES, prescaler == 16 */ if (/* frequency >= (BOARD_CORECLK_FREQ / 2) && */ - frequency <= (BOARD_CORECLK_FREQ / 2 / 16)) + frequency <= (BOARD_CORECLK_FREQ / 2 / 16)) { sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV2; prescaler = 2; @@ -1438,49 +1551,45 @@ static void imxrt_frequency(FAR struct sdio_dev_s *dev, uint32_t frequency) sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV128; prescaler = 128; } - else /* if (frequency >= (BOARD_CORECLK_FREQ / 256) && - * frequency <= (BOARD_CORECLK_FREQ / 256 / 16)) */ + else { sdclkfs = USDHC_SYSCTL_SDCLKFS_DIV256; prescaler = 256; } - /* The optimal divider can than be calculated. - * - * For example, if the base clock frequency is 96 MHz, the target - * frequency is 25 MHz, and the selected prescaler value is 2, then + /* The optimal divider can than be calculated. For example, if the base + * clock frequency is 96 MHz, the target frequency is 25 MHz, and the + * selected prescaler value is 2, then * * prescaled = 96MHz / 2 = 48MHz - * divisor = (48MHz + 12.5HMz/ 25MHz = 2 + * divisor = (48MHz + 12.5HMz/ 25MHz = 2 * - * And the resulting frequency will be 24MHz. - * - * Or, for example, if the target frequency is 400 kHz and the selected - * prescaler is 16, the following* logic will select prescaler: + * And the resulting frequency will be 24MHz. Or, for example, if the + * target frequency is 400 kHz and the selected prescaler is 16, the + * following logic will select prescaler: * * prescaled = 96MHz / 16 = 6MHz - * divisor = (6MHz + 200KHz) / 400KHz = 15 + * divisor = (6MHz + 200KHz) / 400KHz = 15 * - * And the restuling frequency will be exactly 400KHz. + * And the resulting frequency will be exactly 400KHz. */ prescaled = frequency / prescaler; divisor = (prescaled + (frequency >> 1)) / frequency; /* Set the new divisor information and enable all clocks in the SYSCTRL - * register. - * - * TODO: Investigate using the automatically gated clocks to reduce power - * consumption. + * register. TODO: Investigate using the automatically gated clocks to + * reduce power consumption. */ - regval = getreg32(IMXRT_USDHC1_SYSCTL); + regval = getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); regval &= ~(USDHC_SYSCTL_SDCLKFS_MASK | USDHC_SYSCTL_DVS_MASK); regval |= (sdclkfs | USDHC_SYSCTL_DVS_DIV(divisor)); - regval |= (USDHC_SYSCTL_SDCLKEN | USDHC_SYSCTL_PEREN | USDHC_SYSCTL_HCKEN | - USDHC_SYSCTL_IPGEN); - putreg32(regval, IMXRT_USDHC1_SYSCTL); - mcinfo("SYSCTRL: %08x\n", getreg32(IMXRT_USDHC1_SYSCTL)); + regval |= (USDHC_SYSCTL_SDCLKEN | USDHC_SYSCTL_PEREN | + USDHC_SYSCTL_HCKEN | USDHC_SYSCTL_IPGEN); + + putreg32(regval, priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); + mcinfo("SYSCTRL: %08x\n", getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET)); } #endif @@ -1501,78 +1610,92 @@ static void imxrt_frequency(FAR struct sdio_dev_s *dev, uint32_t frequency) static void imxrt_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) { - uint32_t regval; + FAR struct imxrt_dev_s *priv = + (FAR struct imxrt_dev_s *)dev; uint32_t regval; - /* Clear the old prescaler and divisor values so that new ones can be ORed - * in. + /* Clear the old prescaler and divisor values so that new ones can be + * ORed in. */ - regval = getreg32(IMXRT_USDHC1_SYSCTL); + regval = getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); regval &= ~(USDHC_SYSCTL_SDCLKFS_MASK | USDHC_SYSCTL_DVS_MASK); - /* Select the new prescaler and divisor values based on the requested mode - * and the settings from the board.h file. - * - * Clocks are automatically gated by the driver when not needed. - * + /* Select the new prescaler and divisor values based on the requested + * mode and the settings from the board.h file. Clocks are automatically + * gated by the driver when not needed. */ switch (rate) { - default: - case CLOCK_SDIO_DISABLED : /* Clock is disabled */ - { - /* Clear the prescaler and divisor settings */ + default: + case CLOCK_SDIO_DISABLED: /* Clock is disabled */ + { + /* Clear the prescaler and divisor settings */ - putreg32(regval, IMXRT_USDHC1_SYSCTL); - mcinfo("DISABLED, SYSCTRL: %08x\n", getreg32(IMXRT_USDHC1_SYSCTL)); - return; - } + putreg32(regval, priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); + mcinfo("DISABLED, SYSCTRL: %08x\n", + getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET)); return; + } + break; + + case CLOCK_IDMODE: + { + /* Initial ID mode clocking (<400KHz) */ - case CLOCK_IDMODE : /* Initial ID mode clocking (<400KHz) */ mcinfo("IDMODE\n"); /* Put out an additional 80 clocks in case this is a power-up sequence */ regval |= (BOARD_USDHC_IDMODE_PRESCALER | - BOARD_USDHC_IDMODE_DIVISOR | USDHC_SYSCTL_INITA); - break; + BOARD_USDHC_IDMODE_DIVISOR | + USDHC_SYSCTL_INITA); + } + break; + + case CLOCK_MMC_TRANSFER: + { + /* MMC normal operation clocking */ - case CLOCK_MMC_TRANSFER : /* MMC normal operation clocking */ mcinfo("MMCTRANSFER\n"); - regval |= (BOARD_USDHC_MMCMODE_PRESCALER | BOARD_USDHC_MMCMODE_DIVISOR); - break; + } + break; - case CLOCK_SD_TRANSFER_1BIT : /* SD normal operation clocking (narrow - * 1-bit mode) */ + case CLOCK_SD_TRANSFER_1BIT: + { #ifndef CONFIG_IMXRT_USDHC_WIDTH_D1_ONLY - mcinfo("1BITTRANSFER\n"); + /* SD normal operation clocking (narrow 1-bit mode) */ + mcinfo("1BITTRANSFER\n"); regval |= (BOARD_USDHC_SD1MODE_PRESCALER | BOARD_USDHC_SD1MODE_DIVISOR); - break; + } + break; #endif - case CLOCK_SD_TRANSFER_4BIT : /* SD normal operation clocking (wide - * 4-bit mode) */ - mcinfo("4BITTRANSFER\n"); + case CLOCK_SD_TRANSFER_4BIT: + { + /* SD normal operation clocking (wide 4-bit mode) */ + mcinfo("4BITTRANSFER\n"); regval |= (BOARD_USDHC_SD4MODE_PRESCALER | - BOARD_USDHC_SD4MODE_DIVISOR); - break; + BOARD_USDHC_SD4MODE_DIVISOR); + } + break; } - putreg32(regval, IMXRT_USDHC1_SYSCTL); + putreg32(regval, priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); /* Wait for clock to become stable */ - while ((getreg32(IMXRT_USDHC1_PRSSTAT) & USDHC_PRSSTAT_SDSTB) == 0) + while ((getreg32(priv->addr + IMXRT_USDHC_PRSSTAT_OFFSET) & + USDHC_PRSSTAT_SDSTB) == 0) { } - mcinfo("SYSCTRL: %08x\n", getreg32(IMXRT_USDHC1_SYSCTL)); + mcinfo("SYSCTRL: %08x\n", + getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET)); } /**************************************************************************** @@ -1592,24 +1715,47 @@ static void imxrt_clock(FAR struct sdio_dev_s *dev, enum sdio_clock_e rate) static int imxrt_attach(FAR struct sdio_dev_s *dev) { int ret; + FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev; /* Attach the SDIO interrupt handler */ - ret = irq_attach(IMXRT_IRQ_USDHC1, imxrt_interrupt, NULL); + if (priv->addr == IMXRT_USDHC1_BASE) + { + ret = irq_attach(IMXRT_IRQ_USDHC1, imxrt_interrupt, &g_sdhcdev[0]); + } + else + { + if (priv->addr == IMXRT_USDHC2_BASE) + { + ret = irq_attach(IMXRT_IRQ_USDHC2, imxrt_interrupt, &g_sdhcdev[1]); + } + else + { + ASSERT(false); + } + } + if (ret == OK) { /* Disable all interrupts at the SDIO controller and clear all pending * interrupts. */ - putreg32(0 , IMXRT_USDHC1_IRQSIGEN); - putreg32(USDHC_INT_ALL, IMXRT_USDHC1_IRQSTAT); + putreg32(0, priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); + putreg32(USDHC_INT_ALL, priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); - /* Enable SDIO interrupts at the NVIC. They can now be enabled at - * the SDIO controller as needed. + /* Enable SDIO interrupts at the NVIC. They can now be enabled at the + * SDIO controller as needed. */ - up_enable_irq(IMXRT_IRQ_USDHC1); + if (priv->addr == IMXRT_USDHC1_BASE) + { + up_enable_irq(IMXRT_IRQ_USDHC1); + } + else if (priv->addr == IMXRT_USDHC2_BASE) + { + up_enable_irq(IMXRT_IRQ_USDHC2); + } } return ret; @@ -1634,6 +1780,7 @@ static int imxrt_attach(FAR struct sdio_dev_s *dev) static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t arg) { + FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev; clock_t timeout; clock_t start; clock_t elapsed; @@ -1647,33 +1794,79 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, regval = cmdidx << USDHC_XFERTYP_CMDINX_SHIFT; mcrregval = USDHC_MC_DEFAULTVAL; + if (cmdidx == SDIO_ACMDIDX53) + { + /* Dynamically set parameters for ACMD53 because it can accomodate + * different transmission characteristics (single and multi-block, + * rx & tx). + */ + + if (arg & (1 << 31)) + { + /* Transmit mode */ + + cmd |= MMCSD_WRDATAXFR; + } + else + { + /* Receive mode */ + + cmd |= MMCSD_RDDATAXFR; + } + + if (arg & (1 << 27)) + { + /* In block mode */ + + cmd |= MMCSD_MULTIBLOCK; + } + } + /* Check if a data transfer accompanies the command */ switch (cmd & MMCSD_DATAXFR_MASK) { - default: - case MMCSD_NODATAXFR : /* No.. no data transfer */ - break; + default: + case MMCSD_NODATAXFR: + { + /* No.. no data transfer */ + } + break; /* The following two cases are probably missing some setup logic */ - case MMCSD_RDSTREAM : /* Yes.. streaming read data transfer */ - regval |= USDHC_XFERTYP_DPSEL; - mcrregval |= USDHC_MC_DTDSEL; - break; + case MMCSD_RDSTREAM: + { + /* Yes.. streaming read data transfer */ - case MMCSD_WRSTREAM : /* Yes.. streaming write data transfer */ - regval |= USDHC_XFERTYP_DPSEL; - break; + regval |= USDHC_XFERTYP_DPSEL; mcrregval |= USDHC_MC_DTDSEL; + } + break; - case MMCSD_RDDATAXFR : /* Yes.. normal read data transfer */ - regval |= USDHC_XFERTYP_DPSEL; - mcrregval |= USDHC_MC_DTDSEL; - break; + case MMCSD_WRSTREAM: + { + /* Yes.. streaming write data transfer */ - case MMCSD_WRDATAXFR : /* Yes.. normal write data transfer */ - regval |= USDHC_XFERTYP_DPSEL; - break; + regval |= USDHC_XFERTYP_DPSEL; + } + break; + + case MMCSD_RDDATAXFR: + { + /* Yes.. normal read data transfer */ + + regval |= USDHC_XFERTYP_DPSEL; + mcrregval |= USDHC_MC_DTDSEL; + } + break; + + case MMCSD_WRDATAXFR: + { + /* Yes.. normal write data transfer */ + + regval |= USDHC_XFERTYP_DPSEL; + } + break; } /* Is it a multi-block transfer? */ @@ -1700,36 +1893,54 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, switch (cmd & MMCSD_RESPONSE_MASK) { - case MMCSD_NO_RESPONSE: /* No response */ + case MMCSD_NO_RESPONSE: + { + /* No response */ + regval |= USDHC_XFERTYP_RSPTYP_NONE; - break; + } + break; - case MMCSD_R1B_RESPONSE: /* Response length 48, check busy & cmdindex */ - regval |= (USDHC_XFERTYP_RSPTYP_LEN48BSY | USDHC_XFERTYP_CICEN | - USDHC_XFERTYP_CCCEN); - break; + case MMCSD_R1B_RESPONSE: + { + /* Response length 48, check busy & cmdindex */ - case MMCSD_R1_RESPONSE: /* Response length 48, check cmdindex */ - case MMCSD_R5_RESPONSE: - case MMCSD_R6_RESPONSE: - regval |= (USDHC_XFERTYP_RSPTYP_LEN48 | USDHC_XFERTYP_CICEN | - USDHC_XFERTYP_CCCEN); - break; + regval |= + (USDHC_XFERTYP_RSPTYP_LEN48BSY | USDHC_XFERTYP_CICEN | + USDHC_XFERTYP_CCCEN); + } + break; + + case MMCSD_R1_RESPONSE: /* Response length 48, check cmdindex */ + case MMCSD_R5_RESPONSE: + case MMCSD_R6_RESPONSE: + { + regval |= + (USDHC_XFERTYP_RSPTYP_LEN48 | USDHC_XFERTYP_CICEN | + USDHC_XFERTYP_CCCEN); + } + break; + + case MMCSD_R2_RESPONSE: + { + /* Response length 136, check CRC */ - case MMCSD_R2_RESPONSE: /* Response length 136, check CRC */ regval |= (USDHC_XFERTYP_RSPTYP_LEN136 | USDHC_XFERTYP_CCCEN); - break; + } + break; - case MMCSD_R3_RESPONSE: /* Response length 48 */ - case MMCSD_R4_RESPONSE: - case MMCSD_R7_RESPONSE: + case MMCSD_R3_RESPONSE: /* Response length 48 */ + case MMCSD_R4_RESPONSE: + case MMCSD_R7_RESPONSE: + { regval |= USDHC_XFERTYP_RSPTYP_LEN48; - break; + } + break; } +#ifdef CONFIG_IMXRT_USDHC_DMA /* Enable DMA */ -#ifdef CONFIG_IMXRT_USDHC_DMA /* Internal DMA is used */ mcrregval |= USDHC_MC_DMAEN; @@ -1737,23 +1948,22 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, /* Other bits? What about CMDTYP? */ - mcinfo("cmd: %08x arg: %08x regval: %08x mcrval: %08x\n", - cmd, arg, regval, mcrregval); + mcinfo("cmd: %08x arg: %08x regval: %08x mcrval: %08x\n", cmd, arg, + regval, mcrregval); /* The Command Inhibit (CIHB) bit is set in the PRSSTAT bit immediately - * after the transfer type register is written. This bit is cleared when - * the command response is received. If this status bit is 0, it + * after the transfer type register is written. This bit is cleared + * when the command response is received. If this status bit is 0, it * indicates that the CMD line is not in use and the USDHC can issue a - * SD/MMC Command using the CMD line. - * - * CIHB should always be clear before this function is called, but this - * check is performed here to provide overlap and maximum performance. + * SD/MMC Command using the CMD line. CIHB should always be clear before + * this function is called, but this check is performed here to provide + * overlap and maximum performance. */ timeout = USDHC_CMDTIMEOUT; start = clock_systimer(); - - while ((getreg32(IMXRT_USDHC1_PRSSTAT) & USDHC_PRSSTAT_CIHB) != 0) + while ((getreg32(priv->addr + IMXRT_USDHC_PRSSTAT_OFFSET) & + USDHC_PRSSTAT_CIHB) != 0) { /* Calculate the elapsed time */ @@ -1761,23 +1971,20 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, if (elapsed >= timeout) { mcerr("ERROR: Timeout (waiting CIHB) cmd: %08x PRSSTAT: %08x\n", - cmd, getreg32(IMXRT_USDHC1_PRSSTAT)); - + cmd, getreg32(priv->addr + IMXRT_USDHC_PRSSTAT_OFFSET)); return -EBUSY; } } /* Set the USDHC Argument value */ - putreg32(arg, IMXRT_USDHC1_CMDARG); + putreg32(arg, priv->addr + IMXRT_USDHC_CMDARG_OFFSET); /* Clear interrupt status and write the USDHC CMD */ - putreg32(USDHC_RESPDONE_INTS, IMXRT_USDHC1_IRQSTAT); - putreg32(mcrregval, IMXRT_USDHC1_MIX); - putreg32(regval, IMXRT_USDHC1_XFERTYP); - - return OK; + putreg32(USDHC_RESPDONE_INTS, priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); + putreg32(mcrregval, priv->addr + IMXRT_USDHC_MIX_OFFSET); + putreg32(regval, priv->addr + IMXRT_USDHC_XFERTYP_OFFSET); return OK; } /**************************************************************************** @@ -1798,15 +2005,18 @@ static int imxrt_sendcmd(FAR struct sdio_dev_s *dev, uint32_t cmd, #ifdef CONFIG_SDIO_BLOCKSETUP static void imxrt_blocksetup(FAR struct sdio_dev_s *dev, - unsigned int blocklen, unsigned int nblocks) + unsigned int blocklen, + unsigned int nblocks) { - mcinfo("blocklen=%ld, total transfer=%ld (%ld blocks)\n", - blocklen, blocklen * nblocks, nblocks); + FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev; + + mcinfo("blocklen=%ld, total transfer=%ld (%ld blocks)\n", blocklen, + blocklen * nblocks, nblocks); /* Configure block size for next transfer */ putreg32(USDHC_BLKATTR_SIZE(blocklen) | USDHC_BLKATTR_CNT(nblocks), - IMXRT_USDHC1_BLKATTR); + priv->addr + IMXRT_USDHC_BLKATTR_OFFSET); } #endif @@ -1833,24 +2043,22 @@ static void imxrt_blocksetup(FAR struct sdio_dev_s *dev, #ifndef CONFIG_IMXRT_USDHC_DMA static int imxrt_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, - size_t nbytes) + size_t nbytes) { struct imxrt_dev_s *priv = (struct imxrt_dev_s *)dev; - DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0); - DEBUGASSERT(((uint32_t)buffer & 3) == 0); + DEBUGASSERT(((uint32_t) buffer & 3) == 0); /* Reset the DPSM configuration */ imxrt_sampleinit(); imxrt_sample(priv, SAMPLENDX_BEFORE_SETUP); - /* Save the destination buffer information for use by the interrupt handler - * and DMA memory invalidation. + /* Save the destination buffer information for use by the interrupt + * handler and DMA memory invalidation. */ - priv->buffer = (uint32_t *)buffer; - priv->remaining = nbytes; + priv->buffer = (uint32_t *) buffer; priv->remaining = nbytes; /* Then set up the SDIO data path */ @@ -1859,8 +2067,7 @@ static int imxrt_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, /* And enable interrupts */ imxrt_configxfrints(priv, USDHC_RCVDONE_INTS); - imxrt_sample(priv, SAMPLENDX_AFTER_SETUP); - return OK; + imxrt_sample(priv, SAMPLENDX_AFTER_SETUP); return OK; } #endif @@ -1885,12 +2092,12 @@ static int imxrt_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, #ifndef CONFIG_IMXRT_USDHC_DMA static int imxrt_sendsetup(FAR struct sdio_dev_s *dev, - FAR const uint8_t *buffer, size_t nbytes) + FAR const uint8_t *buffer, + size_t nbytes) { struct imxrt_dev_s *priv = (struct imxrt_dev_s *)dev; - DEBUGASSERT(priv != NULL && buffer != NULL && nbytes > 0); - DEBUGASSERT(((uint32_t)buffer & 3) == 0); + DEBUGASSERT(((uint32_t) buffer & 3) == 0); /* Reset the DPSM configuration */ @@ -1899,8 +2106,7 @@ static int imxrt_sendsetup(FAR struct sdio_dev_s *dev, /* Save the source buffer information for use by the interrupt handler */ - priv->buffer = (uint32_t *)buffer; - priv->remaining = nbytes; + priv->buffer = (uint32_t *) buffer; priv->remaining = nbytes; /* Then set up the SDIO data path */ @@ -1909,8 +2115,7 @@ static int imxrt_sendsetup(FAR struct sdio_dev_s *dev, /* Enable TX interrupts */ imxrt_configxfrints(priv, USDHC_SNDDONE_INTS); - imxrt_sample(priv, SAMPLENDX_AFTER_SETUP); - return OK; + imxrt_sample(priv, SAMPLENDX_AFTER_SETUP); return OK; } #endif @@ -1934,20 +2139,20 @@ static int imxrt_sendsetup(FAR struct sdio_dev_s *dev, static int imxrt_cancel(FAR struct sdio_dev_s *dev) { struct imxrt_dev_s *priv = (struct imxrt_dev_s *)dev; + #ifdef CONFIG_IMXRT_USDHC_DMA uint32_t regval; #endif /* Disable all transfer- and event- related interrupts */ - imxrt_configxfrints(priv, 0); - imxrt_configwaitints(priv, 0, 0, 0); + imxrt_configxfrints(priv, 0); imxrt_configwaitints(priv, 0, 0, 0); /* Clearing pending interrupt status on all transfer- and event- related * interrupts */ - putreg32(USDHC_WAITALL_INTS, IMXRT_USDHC1_IRQSTAT); + putreg32(USDHC_WAITALL_INTS, priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); /* Cancel any watchdog timeout */ @@ -1956,17 +2161,17 @@ static int imxrt_cancel(FAR struct sdio_dev_s *dev) /* If this was a DMA transfer, make sure that DMA is stopped */ #ifdef CONFIG_IMXRT_USDHC_DMA + /* Stop the DMA by resetting the data path */ - regval = getreg32(IMXRT_USDHC1_SYSCTL); + regval = getreg32(priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); regval |= USDHC_SYSCTL_RSTD; - putreg32(regval, IMXRT_USDHC1_SYSCTL); + putreg32(regval, priv->addr + IMXRT_USDHC_SYSCTL_OFFSET); #endif /* Mark no transfer in progress */ - priv->remaining = 0; - return OK; + priv->remaining = 0; return OK; } /**************************************************************************** @@ -1993,35 +2198,40 @@ static int imxrt_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd) clock_t start; clock_t elapsed; uint32_t errors; + FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev; int ret = OK; switch (cmd & MMCSD_RESPONSE_MASK) { - case MMCSD_NO_RESPONSE: + case MMCSD_NO_RESPONSE: + { timeout = USDHC_CMDTIMEOUT; errors = 0; return OK; + } - case MMCSD_R1_RESPONSE: - case MMCSD_R1B_RESPONSE: - case MMCSD_R2_RESPONSE: - case MMCSD_R6_RESPONSE: + case MMCSD_R1_RESPONSE: + case MMCSD_R1B_RESPONSE: + case MMCSD_R2_RESPONSE: + case MMCSD_R4_RESPONSE: + case MMCSD_R5_RESPONSE: + case MMCSD_R6_RESPONSE: + { timeout = USDHC_LONGTIMEOUT; errors = USDHC_RESPERR_INTS; - break; + } + break; - case MMCSD_R4_RESPONSE: - case MMCSD_R5_RESPONSE: - return -ENOSYS; - - case MMCSD_R3_RESPONSE: - case MMCSD_R7_RESPONSE: + case MMCSD_R3_RESPONSE: + case MMCSD_R7_RESPONSE: + { timeout = USDHC_CMDTIMEOUT; errors = USDHC_RESPERR_INTS; - break; + } + break; - default: - return -EINVAL; + default: + return -EINVAL; } /* Then wait for the Command Complete (CC) indication (or timeout). The @@ -2030,33 +2240,31 @@ static int imxrt_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd) */ start = clock_systimer(); - - while ((getreg32(IMXRT_USDHC1_IRQSTAT) & USDHC_INT_CC) == 0) + while ((getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET) & + USDHC_INT_CC) == 0) { /* Calculate the elapsed time */ elapsed = clock_systimer() - start; if (elapsed >= timeout) { - mcerr("ERROR: Timeout cmd: %08x IRQSTAT: %08x\n", - cmd, getreg32(IMXRT_USDHC1_IRQSTAT)); - + mcerr("ERROR: Timeout cmd: %08x IRQSTAT: %08x\n", cmd, + getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET)); return -ETIMEDOUT; } } /* Check for hardware detected errors */ - if ((getreg32(IMXRT_USDHC1_IRQSTAT) & errors) != 0) + if ((getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET) & errors) != 0) { - mcerr("ERROR: cmd: %08x errors: %08x IRQSTAT: %08x\n", - cmd, errors, getreg32(IMXRT_USDHC1_IRQSTAT)); - ret = -EIO; + mcerr("ERROR: cmd: %08x errors: %08x IRQSTAT: %08x\n", cmd, errors, + getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET)); ret = -EIO; } /* Clear the response wait status bits */ - putreg32(USDHC_RESPDONE_INTS, IMXRT_USDHC1_IRQSTAT); + putreg32(USDHC_RESPDONE_INTS, priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); return ret; } @@ -2083,31 +2291,32 @@ static int imxrt_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd) ****************************************************************************/ static int imxrt_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, - uint32_t *rshort) + uint32_t *rshort) { + FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev; uint32_t regval; int ret = OK; - /* R1 Command response (48-bit) - * 47 0 Start bit - * 46 0 Transmission bit (0=from card) - * 45:40 bit5 - bit0 Command index (0-63) - * 39:8 bit31 - bit0 32-bit card status - * 7:1 bit6 - bit0 CRC7 - * 0 1 End bit + /* R1 Command response (48-bit) + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Command index (0-63) + * 39:8 bit31- bit0 32-bit card status + * 7:1 bit6 - bit0 CRC7 + * 0 1 End bit * * R1b Identical to R1 with the additional busy signalling via the data * line. - * * R6 Published RCA Response (48-bit, SD card only) - * 47 0 Start bit - * 46 0 Transmission bit (0=from card) - * 45:40 bit5 - bit0 Command index (0-63) - * 39:8 bit31 - bit0 32-bit Argument Field, consisting of: - * [31:16] New published RCA of card - * [15:0] Card status bits {23,22,19,12:0} - * 7:1 bit6 - bit0 CRC7 - * 0 1 End bit + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Command index (0-63) + * 39:8 bit31 - bit0 32-bit Argument Field, consisting of: + * [31:16] New published RCA of card + * [15:0] Card status bits + * {23,22,19,12:0} + * 7:1 bit6 - bit0 CRC7 + * 0 1 End bit */ #ifdef CONFIG_DEBUG_FEATURES @@ -2121,6 +2330,7 @@ static int imxrt_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, else if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1_RESPONSE && (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R1B_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R5_RESPONSE && (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R6_RESPONSE) { mcerr("ERROR: Wrong response CMD=%08x\n", cmd); @@ -2131,7 +2341,7 @@ static int imxrt_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, { /* Check if a timeout or CRC error occurred */ - regval = getreg32(IMXRT_USDHC1_IRQSTAT); + regval = getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); if ((regval & USDHC_INT_CTOE) != 0) { mcerr("ERROR: Command timeout: %08x\n", regval); @@ -2139,33 +2349,32 @@ static int imxrt_recvshortcrc(FAR struct sdio_dev_s *dev, uint32_t cmd, } else if ((regval & USDHC_INT_CCE) != 0) { - mcerr("ERROR: CRC failure: %08x\n", regval); - ret = -EIO; + mcerr("ERROR: CRC failure: %08x\n", regval); ret = -EIO; } } - /* Return the R1/R1b/R6 response. These responses are returned in - * CDMRSP0. NOTE: This is not true for R1b (Auto CMD12 response) which - * is returned in CMDRSP3. + /* Return the R1/R1b/R6 response. These responses are returned in CDMRSP0. + * NOTE: This is not true for R1b (Auto CMD12 response) which is returned in + * CMDRSP3. */ - *rshort = getreg32(IMXRT_USDHC1_CMDRSP0); + *rshort = getreg32(priv->addr + IMXRT_USDHC_CMDRSP0_OFFSET); return ret; } static int imxrt_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, - uint32_t rlong[4]) + uint32_t rlong[4]) { + FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev; uint32_t regval; int ret = OK; - /* R2 CID, CSD register (136-bit) - * 135 0 Start bit - * 134 0 Transmission bit (0=from card) - * 133:128 bit5 - bit0 Reserved - * 127:1 bit127 - bit1 127-bit CID or CSD register - * (including internal CRC) - * 0 1 End bit + /* R2 CID, CSD register (136-bit) + * 135 0 Start bit + * 134 0 Transmission bit (0=from card) + * 133:128 bit5 - bit0 Reserved + * 127:1 bit127 - bit1 127-bit CID or CSD register (including int. CRC) + * 0 1 End bit */ #ifdef CONFIG_DEBUG_FEATURES @@ -2181,7 +2390,7 @@ static int imxrt_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, { /* Check if a timeout or CRC error occurred */ - regval = getreg32(IMXRT_USDHC1_IRQSTAT); + regval = getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); if (regval & USDHC_INT_CTOE) { mcerr("ERROR: Timeout IRQSTAT: %08x\n", regval); @@ -2198,46 +2407,40 @@ static int imxrt_recvlong(FAR struct sdio_dev_s *dev, uint32_t cmd, if (rlong) { -#if 0 - rlong[0] = getreg32(IMXRT_USDHC1_CMDRSP3); - rlong[1] = getreg32(IMXRT_USDHC1_CMDRSP2); - rlong[2] = getreg32(IMXRT_USDHC1_CMDRSP1); - rlong[3] = getreg32(IMXRT_USDHC1_CMDRSP0); -#else - uint32_t rsp3 = getreg32(IMXRT_USDHC1_CMDRSP3); - uint32_t rsp2 = getreg32(IMXRT_USDHC1_CMDRSP2); - uint32_t rsp1 = getreg32(IMXRT_USDHC1_CMDRSP1); - uint32_t rsp0 = getreg32(IMXRT_USDHC1_CMDRSP0); + uint32_t rsp3 = getreg32(priv->addr + IMXRT_USDHC_CMDRSP3_OFFSET); + uint32_t rsp2 = getreg32(priv->addr + IMXRT_USDHC_CMDRSP2_OFFSET); + uint32_t rsp1 = getreg32(priv->addr + IMXRT_USDHC_CMDRSP1_OFFSET); + uint32_t rsp0 = getreg32(priv->addr + IMXRT_USDHC_CMDRSP0_OFFSET); rlong[0] = rsp3 << 8 | rsp2 >> 24; rlong[1] = rsp2 << 8 | rsp1 >> 24; - rlong[2] = rsp1 << 8 | rsp0 >> 24; - rlong[3] = rsp0 << 8; -#endif + rlong[2] = rsp1 << 8 | rsp0 >> 24; rlong[3] = rsp0 << 8; } return ret; } static int imxrt_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, - uint32_t *rshort) + uint32_t *rshort) { + FAR struct imxrt_dev_s *priv = (FAR struct imxrt_dev_s *)dev; uint32_t regval; int ret = OK; - /* R3 OCR (48-bit) - * 47 0 Start bit - * 46 0 Transmission bit (0=from card) - * 45:40 bit5 - bit0 Reserved - * 39:8 bit31 - bit0 32-bit OCR register - * 7:1 bit6 - bit0 Reserved - * 0 1 End bit + /* R3 OCR (48-bit) + * 47 0 Start bit + * 46 0 Transmission bit (0=from card) + * 45:40 bit5 - bit0 Reserved + * 39:8 bit31- bit0 32-bit OCR register + * 7:1 bit6 - bit0 Reserved + * 0 1 End bit */ /* Check that this is the correct response to this command */ #ifdef CONFIG_DEBUG_FEATURES if ((cmd & MMCSD_RESPONSE_MASK) != MMCSD_R3_RESPONSE && + (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R4_RESPONSE && (cmd & MMCSD_RESPONSE_MASK) != MMCSD_R7_RESPONSE) { mcerr("ERROR: Wrong response CMD=%08x\n", cmd); @@ -2246,11 +2449,11 @@ static int imxrt_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, else #endif { - /* Check if a timeout occurred (Apparently a CRC error can terminate - * a good response) + /* Check if a timeout occurred (Apparently a CRC error can terminate a + * good response) */ - regval = getreg32(IMXRT_USDHC1_IRQSTAT); + regval = getreg32(priv->addr + IMXRT_USDHC_IRQSTAT_OFFSET); if (regval & USDHC_INT_CTOE) { mcerr("ERROR: Timeout IRQSTAT: %08x\n", regval); @@ -2262,7 +2465,7 @@ static int imxrt_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, if (rshort) { - *rshort = getreg32(IMXRT_USDHC1_CMDRSP0); + *rshort = getreg32(priv->addr + IMXRT_USDHC_CMDRSP0_OFFSET); } return ret; @@ -2270,7 +2473,8 @@ static int imxrt_recvshort(FAR struct sdio_dev_s *dev, uint32_t cmd, /* MMC responses not supported */ -static int imxrt_recvnotimpl(FAR struct sdio_dev_s *dev, uint32_t cmd, uint32_t *rnotimpl) +static int imxrt_recvnotimpl(FAR struct sdio_dev_s *dev, + uint32_t cmd, uint32_t *rnotimpl) { /* Just return an error */ @@ -2326,7 +2530,6 @@ static void imxrt_waitenable(FAR struct sdio_dev_s *dev, if ((eventset & SDIOWAIT_TRANSFERDONE) != 0) { #ifdef CONFIG_IMXRT_USDHC_DMA - waitints |= USDHC_DMADONE_INTS; #else waitints |= USDHC_XFRDONE_INTS; @@ -2363,12 +2566,12 @@ static sdio_eventset_t imxrt_eventwait(FAR struct sdio_dev_s *dev, uint32_t timeout) { struct imxrt_dev_s *priv = (struct imxrt_dev_s *)dev; - sdio_eventset_t wkupevent = 0; - int ret; + sdio_eventset_t wkupevent = 0; int ret; /* There is a race condition here... the event may have completed before - * we get here. In this case waitevents will be zero, but wkupevents will - * be non-zero (and, hopefully, the semaphore count will also be non-zero. + * we get here. In this case waitevents will be zero, but wkupevents + * will be non-zero (and, hopefully, the semaphore count will also be + * non-zero. */ DEBUGASSERT((priv->waitevents != 0 && priv->wkupevent == 0) || @@ -2390,32 +2593,35 @@ static sdio_eventset_t imxrt_eventwait(FAR struct sdio_dev_s *dev, /* Start the watchdog timer */ delay = MSEC2TICK(timeout); - ret = wd_start(priv->waitwdog, delay, (wdentry_t)imxrt_eventtimeout, - 1, (uint32_t)priv); + ret = wd_start(priv->waitwdog, delay, (wdentry_t) imxrt_eventtimeout, + 1, (uint32_t) priv); + if (ret < 0) { mcerr("ERROR: wd_start failed: %d\n", ret); } } - /* Loop until the event (or the timeout occurs). Race conditions are avoided - * by calling imxrt_waitenable prior to triggering the logic that will cause - * the wait to terminate. Under certain race conditions, the waited-for - * may have already occurred before this function was called! + /* Loop until the event (or the timeout occurs). Race conditions are + * avoided by calling imxrt_waitenable prior to triggering the logic + * that will cause the wait to terminate. Under certain race + * conditions, the waited-for may have already occurred before this + * function was called! */ for (; ; ) { - /* Wait for an event in event set to occur. If this the event has already - * occurred, then the semaphore will already have been incremented and - * there will be no wait. + /* Wait for an event in event set to occur. If this the event has + * already occurred, then the semaphore will already have been + * incremented and there will be no wait. */ imxrt_takesem(priv); wkupevent = priv->wkupevent; /* Check if the event has occurred. When the event has occurred, then - * evenset will be set to 0 and wkupevent will be set to a non-zero value. + * evenset will be set to 0 and wkupevent will be set to a non-zero + * value. */ if (wkupevent != 0) @@ -2430,9 +2636,8 @@ static sdio_eventset_t imxrt_eventwait(FAR struct sdio_dev_s *dev, imxrt_configwaitints(priv, 0, 0, 0); #ifdef CONFIG_IMXRT_USDHC_DMA - priv->xfrflags = 0; + priv->xfrflags = 0; #endif - imxrt_dumpsamples(priv); return wkupevent; } @@ -2501,10 +2706,10 @@ static int imxrt_registercallback(FAR struct sdio_dev_s *dev, /* Disable callbacks and register this callback and is argument */ mcinfo("Register %p(%p)\n", callback, arg); - DEBUGASSERT(priv != NULL); + DEBUGASSERT(priv != NULL); priv->cbevents = 0; - priv->cbarg = arg; + priv->cbarg = arg; priv->callback = callback; return OK; } @@ -2529,22 +2734,23 @@ static int imxrt_registercallback(FAR struct sdio_dev_s *dev, ****************************************************************************/ #ifdef CONFIG_IMXRT_USDHC_DMA -static int imxrt_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, - size_t buflen) +static int imxrt_dmarecvsetup(FAR struct sdio_dev_s *dev, + FAR uint8_t *buffer, size_t buflen) { struct imxrt_dev_s *priv = (struct imxrt_dev_s *)dev; - DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); - DEBUGASSERT(((uint32_t)buffer & 3) == 0); + DEBUGASSERT(((uint32_t) buffer & 3) == 0); /* Begin sampling register values */ imxrt_sampleinit(); imxrt_sample(priv, SAMPLENDX_BEFORE_SETUP); - /* Save the destination buffer information for use by the interrupt handler */ + /* Save the destination buffer information for use by the interrupt + * handler + */ - priv->buffer = (uint32_t *)buffer; + priv->buffer = (uint32_t *)buffer; priv->remaining = buflen; priv->bufferend = (uint32_t *)(buffer + buflen); @@ -2555,7 +2761,7 @@ static int imxrt_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer, /* Configure the RX DMA */ imxrt_configxfrints(priv, USDHC_DMADONE_INTS); - putreg32((uint32_t)buffer, IMXRT_USDHC1_DSADDR); + putreg32((uint32_t) buffer, priv->addr + IMXRT_USDHC_DSADDR_OFFSET); /* Sample the register state */ @@ -2588,9 +2794,8 @@ static int imxrt_dmasendsetup(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer, size_t buflen) { struct imxrt_dev_s *priv = (struct imxrt_dev_s *)dev; - DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0); - DEBUGASSERT(((uint32_t)buffer & 3) == 0); + DEBUGASSERT(((uint32_t) buffer & 3) == 0); /* Begin sampling register values */ @@ -2599,7 +2804,7 @@ static int imxrt_dmasendsetup(FAR struct sdio_dev_s *dev, /* Save the source buffer information for use by the interrupt handler */ - priv->buffer = (uint32_t *)buffer; + priv->buffer = (uint32_t *) buffer; priv->remaining = buflen; /* Then set up the SDIO data path */ @@ -2608,7 +2813,7 @@ static int imxrt_dmasendsetup(FAR struct sdio_dev_s *dev, /* Configure the TX DMA */ - putreg32((uint32_t)buffer, IMXRT_USDHC1_DSADDR); + putreg32((uint32_t) buffer, priv->addr + IMXRT_USDHC_DSADDR_OFFSET); /* Sample the register state */ @@ -2624,7 +2829,7 @@ static int imxrt_dmasendsetup(FAR struct sdio_dev_s *dev, /**************************************************************************** * Name: imxrt_callback * - * Description: + * Description: * Perform callback. * * Assumptions: @@ -2641,8 +2846,8 @@ static void imxrt_callback(void *arg) /* Is a callback registered? */ DEBUGASSERT(priv != NULL); - mcinfo("Callback %p(%p) cbevents: %02x cdstatus: %02x\n", - priv->callback, priv->cbarg, priv->cbevents, priv->cdstatus); + mcinfo("Callback %p(%p) cbevents: %02x cdstatus: %02x\n", priv->callback, + priv->cbarg, priv->cbevents, priv->cdstatus); if (priv->callback) { @@ -2686,10 +2891,8 @@ static void imxrt_callback(void *arg) { /* Yes.. queue it */ - mcinfo("Queuing callback to %p(%p)\n", - priv->callback, priv->cbarg); - - (void)work_queue(HPWORK, &priv->cbwork, (worker_t)priv->callback, + mcinfo("Queuing callback to %p(%p)\n", priv->callback, priv->cbarg); + (void)work_queue(HPWORK, &priv->cbwork, (worker_t) priv->callback, priv->cbarg, 0); } else @@ -2697,7 +2900,6 @@ static void imxrt_callback(void *arg) /* No.. then just call the callback here */ mcinfo("Callback to %p(%p)\n", priv->callback, priv->cbarg); - priv->callback(priv->cbarg); } } @@ -2707,6 +2909,48 @@ static void imxrt_callback(void *arg) * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: imxrt_usdhc_set_sdio_card_isr + * + * Description: + * SDIO card generates interrupt via SDIO_DATA_1 pin. + * Called by board-specific logic to register an ISR for SDIO card. + * + * Input Parameters: + * func - callback function. + * arg - arg to be passed to the function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imxrt_usdhc_set_sdio_card_isr(FAR struct sdio_dev_s *dev, + int (*func)(void *), void *arg) +{ + irqstate_t flags; + uint32_t regval; + struct imxrt_dev_s *priv = (struct imxrt_dev_s *)dev; + + priv->do_sdio_card = func; + priv->do_sdio_arg = arg; + + if (priv->do_sdio_card != NULL) + { + priv->cintints = USDHC_INT_CINT; + } + else + { + priv->cintints = 0; + } + + flags = enter_critical_section(); + regval = getreg32(priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); + regval = (regval & ~USDHC_INT_CINT) | priv->cintints; + putreg32(regval, priv->addr + IMXRT_USDHC_IRQSIGEN_OFFSET); + leave_critical_section(flags); +} + /**************************************************************************** * Name: imxrt_sdhc_initialize * @@ -2717,82 +2961,97 @@ static void imxrt_callback(void *arg) * slotno - Not used. * * Returned Value: - * A reference to an SDIO interface structure. NULL is returned on failures. + * A reference to an SDIO interface structure. + * NULL is returned on failures. * ****************************************************************************/ FAR struct sdio_dev_s *imxrt_usdhc_initialize(int slotno) { - /* There is only one slot */ + DEBUGASSERT(slotno < CONFIG_IMXRT_MAX_SDHCDEV_SLOTS); + struct imxrt_dev_s *priv = &g_sdhcdev[slotno]; - struct imxrt_dev_s *priv = &g_sdhcdev; - DEBUGASSERT(slotno == 0); - - /* Initialize the USDHC slot structure data structure */ - /* Initialize semaphores */ + /* Initialize the USDHC slot structure data structure + * Initialize semaphores + */ nxsem_init(&priv->waitsem, 0, 0); - /* The waitsem semaphore is used for signaling and, hence, should not have - * priority inheritance enabled. + /* The waitsem semaphore is used for signaling and, hence, should not + * have priority inheritance enabled. */ nxsem_setprotocol(&priv->waitsem, SEM_PRIO_NONE); /* Create a watchdog timer */ - priv->waitwdog = wd_create(); - DEBUGASSERT(priv->waitwdog); + priv->waitwdog = wd_create(); DEBUGASSERT(priv->waitwdog); - /* Configure pins for 1 or 4-bit, wide-bus operation (the chip is capable - * of 8-bit wide bus operation but D4-D7 are not configured). - * - * If bus is multiplexed then there is a custom bus configuration utility + /* Configure pins for 1 or 4-bit, wide-bus operation (the chip is + * capable of 8-bit wide bus operation but D4-D7 are not configured). If + * bus is multiplexed then there is a custom bus configuration utility * in the scope of the board support package. */ #ifndef CONFIG_SDIO_MUXBUS - /* Data width 1, 4 or 8 */ + if (slotno == 0) + { + /* Data width 1, 4 */ - (void)imxrt_config_gpio(PIN_USDHC1_D0); + (void)imxrt_config_gpio(PIN_USDHC1_D0); - /* Data width 4 or 8 */ + /* Data width 4 */ #ifndef CONFIG_IMXRT_USDHC_WIDTH_D1_ONLY - (void)imxrt_config_gpio(PIN_USDHC1_D1); - (void)imxrt_config_gpio(PIN_USDHC1_D2); - (void)imxrt_config_gpio(PIN_USDHC1_D3); - - /* Data width 8 (not supported) */ - -#if 0 - (void)imxrt_config_gpio(PIN_USDHC1_D4); - (void)imxrt_config_gpio(PIN_USDHC1_D5); - (void)imxrt_config_gpio(PIN_USDHC1_D6); - (void)imxrt_config_gpio(PIN_USDHC1_D7); -#endif + (void)imxrt_config_gpio(PIN_USDHC1_D1); + (void)imxrt_config_gpio(PIN_USDHC1_D2); + (void)imxrt_config_gpio(PIN_USDHC1_D3); #endif - /* Clocking and CMD pins (all data widths) */ + /* Clocking and CMD pins (all data widths) */ - (void)imxrt_config_gpio(PIN_USDHC1_DCLK); - (void)imxrt_config_gpio(PIN_USDHC1_CMD); + (void)imxrt_config_gpio(PIN_USDHC1_DCLK); + (void)imxrt_config_gpio(PIN_USDHC1_CMD); #endif #if defined(CONFIG_MMCSD_HAVE_CARDDETECT) && defined(PIN_USDHC1_CD) - (void)imxrt_config_gpio(PIN_USDHC1_CD); + (void)imxrt_config_gpio(PIN_USDHC1_CD); #endif - /* Reset the card and assure that it is in the initial, unconfigured - * state. - */ + /* Reset the card and assure that it is in the initial, unconfigured + * state. + */ - imxrt_clockall_usdhc1(); + imxrt_clockall_usdhc1(); + imxrt_reset(&priv->dev); + imxrt_showregs(priv, "After reset"); + } - imxrt_reset(&priv->dev); - imxrt_showregs(priv, "After reset"); +#if (CONFIG_IMXRT_MAX_SDHCDEV_SLOTS > 1) + else if (slotno == 1) + { + (void)imxrt_config_gpio(PIN_USDHC2_D0); + (void)imxrt_config_gpio(PIN_USDHC2_D1); + (void)imxrt_config_gpio(PIN_USDHC2_D2); + (void)imxrt_config_gpio(PIN_USDHC2_D3); + (void)imxrt_config_gpio(PIN_USDHC2_DCLK); + (void)imxrt_config_gpio(PIN_USDHC2_CMD); - return &g_sdhcdev.dev; + /* Reset the card and assure that it is in the initial, unconfigured + * state. + */ + + imxrt_clockall_usdhc2(); + imxrt_reset(&priv->dev); + imxrt_showregs(priv, "After reset"); + } +#endif + else + { + return NULL; + } + + return &g_sdhcdev[slotno].dev; } -#endif /* CONFIG_IMXRT_USDHC */ +#endif /* CONFIG_IMXRT_USDHC */ diff --git a/arch/arm/src/imxrt/imxrt_usdhc.h b/arch/arm/src/imxrt/imxrt_usdhc.h index d2e6fd5d7f..dff7fed217 100644 --- a/arch/arm/src/imxrt/imxrt_usdhc.h +++ b/arch/arm/src/imxrt/imxrt_usdhc.h @@ -51,6 +51,25 @@ * Public Function Prototypes ****************************************************************************/ +/**************************************************************************** + * Name: imxrt_usdhc_set_sdio_card_isr + * + * Description: + * SDIO card generates interrupt via SDIO_DATA_1 pin. + * Called by board-specific logic to register an ISR for SDIO card. + * + * Input Parameters: + * func - callback function. + * arg - arg to be passed to the function. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void imxrt_usdhc_set_sdio_card_isr(FAR struct sdio_dev_s *dev, + int (*func)(void *), void *arg); + /**************************************************************************** * Name: imxrt_usdhc_initialize * @@ -61,7 +80,8 @@ * slotno - Not used. * * Returned Value: - * A reference to an USDIO interface structure. NULL is returned on failures. + * A reference to an USDIO interface structure. NULL is returned on + * failures. * ****************************************************************************/