On 2018/2/15 21:34, Ludovic Barre wrote:
From: Ludovic Barre <ludovic.barre@xxxxxx>
...
+
+static ssize_t stm32_sdmmc_stat_reset(struct file *filp,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ const char __user *ubuf,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ size_t count, loff_t *ppos)
+{
+ÂÂÂ struct seq_file *seqf = filp->private_data;
+ÂÂÂ struct sdmmc_host *host = seqf->private;
+
+ÂÂÂ mutex_lock(&seqf->lock);
+ÂÂÂ memset(&host->stat, 0, sizeof(host->stat));
+ÂÂÂ mutex_unlock(&seqf->lock);
+
+ÂÂÂ return count;
+}
+
+static int stm32_sdmmc_stat_open(struct inode *inode, struct file *file)
+{
+ÂÂÂ return single_open(file, stm32_sdmmc_stat_show, inode->i_private);
+}
+
+static const struct file_operations stm32_sdmmc_stat_fops = {
+ÂÂÂ .ownerÂÂÂÂÂÂÂ = THIS_MODULE,
+ÂÂÂ .openÂÂÂÂÂÂÂ = stm32_sdmmc_stat_open,
+ÂÂÂ .readÂÂÂÂÂÂÂ = seq_read,
+ÂÂÂ .writeÂÂÂÂÂÂÂ = stm32_sdmmc_stat_reset,
+ÂÂÂ .llseekÂÂÂÂÂÂÂ = seq_lseek,
+ÂÂÂ .releaseÂÂÂ = single_release,
+};
+
Could you simply use DEFINE_SHOW_ATTRIBUTE(stm32_sdmmc_stat) instead?
+static void stm32_sdmmc_stat_init(struct sdmmc_host *host)
+{
+ÂÂÂ struct mmc_hostÂÂÂ *mmc = host->mmc;
+ÂÂÂ struct dentry *root;
+
+ÂÂÂ root = mmc->debugfs_root;
+ÂÂÂ if (!root)
+ÂÂÂÂÂÂÂ return;
+
+ÂÂÂ if (!debugfs_create_file("stat", 0600, root, host,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ &stm32_sdmmc_stat_fops))
+ÂÂÂÂÂÂÂ dev_err(mmc_dev(host->mmc), "failed to initialize debugfs\n");
+}
+
+#define STAT_INC(stat) ((stat)++)
+#else
+static void stm32_sdmmc_stat_init(struct sdmmc_host *host)
+{
+}
+
+#define STAT_INC(stat)
+#endif
+
+static inline u32 enable_imask(struct sdmmc_host *host, u32 imask)
+{
+ÂÂÂ u32 newmask;
+
+ÂÂÂ newmask = readl_relaxed(host->base + SDMMC_MASKR);
+ÂÂÂ newmask |= imask;
+
+ÂÂÂ dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", newmask);
+
+ÂÂÂ writel_relaxed(newmask, host->base + SDMMC_MASKR);
+
+ÂÂÂ return newmask;
+}
+
I don't see you use the return value eleswhere, perhaps
remove it?
+static inline u32 disable_imask(struct sdmmc_host *host, u32 imask)
+{
+ÂÂÂ u32 newmask;
+
+ÂÂÂ newmask = readl_relaxed(host->base + SDMMC_MASKR);
+ÂÂÂ newmask &= ~imask;
+
+ÂÂÂ dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", newmask);
+
+ÂÂÂ writel_relaxed(newmask, host->base + SDMMC_MASKR);
+
+ÂÂÂ return newmask;
+}
+
Ditto?
+static inline void clear_imask(struct sdmmc_host *host)
+{
+ÂÂÂ u32 mask = readl_relaxed(host->base + SDMMC_MASKR);
+
+ÂÂÂ /* preserve the SDIO IRQ mask state */
+ÂÂÂ mask &= MASKR_SDIOITIE;
+
+ÂÂÂ dev_vdbg(mmc_dev(host->mmc), "mask:%#x\n", mask);
+
+ÂÂÂ writel_relaxed(mask, host->base + SDMMC_MASKR);
+}
+
Not clear to me why couldn't you use :
imask = 0xffffffff ^ MASKR_SDIOITIE;
disable_imask(imask)
+static int stm32_sdmmc_card_busy(struct mmc_host *mmc)
+{
+ÂÂÂ struct sdmmc_host *host = mmc_priv(mmc);
+ÂÂÂ unsigned long flags;
+ÂÂÂ u32 status;
+
+ÂÂÂ spin_lock_irqsave(&host->lock, flags);
+ÂÂÂ status = readl_relaxed(host->base + SDMMC_STAR);
+ÂÂÂ spin_unlock_irqrestore(&host->lock, flags);
+
+ÂÂÂ return !!(status & STAR_BUSYD0);
+}
+
I don't think you need to hold the lock here.
+static void stm32_sdmmc_request_end(struct sdmmc_host *host,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct mmc_request *mrq)
+{
+ÂÂÂ writel_relaxed(0, host->base + SDMMC_CMDR);
+ÂÂÂ writel_relaxed(ICR_STATIC_FLAG, host->base + SDMMC_ICR);
+
+ÂÂÂ host->mrq = NULL;
+ÂÂÂ host->cmd = NULL;
+ÂÂÂ host->data = NULL;
+
+ÂÂÂ clear_imask(host);
+
+ÂÂÂ mmc_request_done(host->mmc, mrq);
+}
+
+static void stm32_sdmmc_pwroff(struct sdmmc_host *host)
+{
+ÂÂÂ /* Only a reset could disable sdmmc */
+ÂÂÂ reset_control_assert(host->rst);
+ÂÂÂ udelay(2);
+ÂÂÂ reset_control_deassert(host->rst);
+
+ÂÂÂ /*
+ÂÂÂÂ * Set the SDMMC in Power-cycle state. This will make that the
+ÂÂÂÂ * SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are driven low,
+ÂÂÂÂ * to prevent the Card from being powered through the signal lines.
+ÂÂÂÂ */
+ÂÂÂ writel_relaxed(POWERCTRL_CYC | host->pwr_reg_add,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ host->base + SDMMC_POWER);
+}
+
+static void stm32_sdmmc_pwron(struct sdmmc_host *host)
+{
+ÂÂÂ /*
+ÂÂÂÂ * After a power-cycle state, we must set the SDMMC in Power-off.
+ÂÂÂÂ * The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are driven high.
+ÂÂÂÂ * Then we can set the SDMMC to Power-on state
+ÂÂÂÂ */
+ÂÂÂ writel_relaxed(POWERCTRL_OFF | host->pwr_reg_add,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ host->base + SDMMC_POWER);
+ÂÂÂ mdelay(1);
+ÂÂÂ writel_relaxed(POWERCTRL_ON | host->pwr_reg_add,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ host->base + SDMMC_POWER);
+}
+
+static void stm32_sdmmc_set_clkreg(struct sdmmc_host *host, struct mmc_ios *ios)
+{
+ÂÂÂ u32 desired = ios->clock;
+ÂÂÂ u32 clk = 0;
+
+ÂÂÂ /*
+ÂÂÂÂ * sdmmc_ck = sdmmcclk/(2*clkdiv)
+ÂÂÂÂ * clkdiv 0 => bypass
+ÂÂÂÂ */
+ÂÂÂ if (desired) {
+ÂÂÂÂÂÂÂ if (desired >= host->sdmmcclk) {
+ÂÂÂÂÂÂÂÂÂÂÂ clk = 0;
+ÂÂÂÂÂÂÂÂÂÂÂ host->sdmmc_ck = host->sdmmcclk;
+ÂÂÂÂÂÂÂ } else {
+ÂÂÂÂÂÂÂÂÂÂÂ clk = DIV_ROUND_UP(host->sdmmcclk, 2 * desired);
+ÂÂÂÂÂÂÂÂÂÂÂ if (clk > CLKCR_CLKDIV_MAX)
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ clk = CLKCR_CLKDIV_MAX;
+
Don't you need to check if the desired clock rate is the
same with the current clock rate?
+ÂÂÂÂÂÂÂÂÂÂÂ host->sdmmc_ck = host->sdmmcclk / (2 * clk);
+ÂÂÂÂÂÂÂ }
+ÂÂÂ }
+
+ÂÂÂ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ÂÂÂÂÂÂÂ clk |= CLKCR_WIDBUS_4;
+ÂÂÂ if (ios->bus_width == MMC_BUS_WIDTH_8)
+ÂÂÂÂÂÂÂ clk |= CLKCR_WIDBUS_8;
+
also it looks wired to me you set bus width in a function called
stm32_sdmmc_set_clkreg which seems do the clock setting.
+ÂÂÂ clk |= CLKCR_HWFC_EN;
+
+ÂÂÂ writel_relaxed(clk | host->clk_reg_add, host->base + SDMMC_CLKCR);
+}
+
+static void stm32_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ÂÂÂ struct sdmmc_host *host = mmc_priv(mmc);
+
+ÂÂÂ stm32_sdmmc_set_clkreg(host, ios);
+
+ÂÂÂ switch (ios->power_mode) {
+ÂÂÂ case MMC_POWER_OFF:
+ÂÂÂÂÂÂÂ if (!IS_ERR(mmc->supply.vmmc))
+ÂÂÂÂÂÂÂÂÂÂÂ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
+
+ÂÂÂÂÂÂÂ stm32_sdmmc_pwroff(host);
+ÂÂÂÂÂÂÂ return;
+ÂÂÂ case MMC_POWER_UP:
+ÂÂÂÂÂÂÂ if (!IS_ERR(mmc->supply.vmmc))
+ÂÂÂÂÂÂÂÂÂÂÂ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
+ÂÂÂÂÂÂÂ break;
+ÂÂÂ case MMC_POWER_ON:
+ÂÂÂÂÂÂÂ stm32_sdmmc_pwron(host);
+ÂÂÂÂÂÂÂ break;
+ÂÂÂ }
+}
+
+static int stm32_sdmmc_validate_data(struct sdmmc_host *host,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct mmc_data *data, int cookie)
+{
+ÂÂÂ int n_elem;
+
+ÂÂÂ if (!data || data->host_cookie == COOKIE_PRE_MAPPED)
+ÂÂÂÂÂÂÂ return 0;
+
+ÂÂÂ if (!is_power_of_2(data->blksz)) {
+ÂÂÂÂÂÂÂ dev_err(mmc_dev(host->mmc),
+ÂÂÂÂÂÂÂÂÂÂÂ "unsupported block size (%d bytes)\n", data->blksz);
+ÂÂÂÂÂÂÂ return -EINVAL;
+ÂÂÂ }
+
+ÂÂÂ if (data->sg->offset & 3 || data->sg->length & 3) {
+ÂÂÂÂÂÂÂ dev_err(mmc_dev(host->mmc),
+ÂÂÂÂÂÂÂÂÂÂÂ "unaligned scatterlist: ofst:%x length:%d\n",
+ÂÂÂÂÂÂÂÂÂÂÂ data->sg->offset, data->sg->length);
+ÂÂÂÂÂÂÂ return -EINVAL;
+ÂÂÂ }
+
+ÂÂÂ n_elem = dma_map_sg(mmc_dev(host->mmc),
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ data->sg,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ data->sg_len,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ mmc_get_dma_dir(data));
+
+ÂÂÂ if (n_elem != 1) {
+ÂÂÂÂÂÂÂ dev_err(mmc_dev(host->mmc), "nr segment >1 not supported\n");
I don't get this check. Your IDMA can't do scatter lists, but
n_elem == 0 means failed to do dma_map_sg.
+ÂÂÂÂÂÂÂ return -EINVAL;
+ÂÂÂ }
+
+ÂÂÂ data->host_cookie = cookie;
+
+ÂÂÂ return 0;
+}
+
+static void stm32_sdmmc_start_data(struct sdmmc_host *host,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct mmc_data *data)
+{
+ÂÂÂ u32 datactrl, timeout, imask, idmactrl;
+ÂÂÂ unsigned long long clks;
+
+ÂÂÂ dev_dbg(mmc_dev(host->mmc), "blksz %d blks %d flags %08x\n",
+ÂÂÂÂÂÂÂ data->blksz, data->blocks, data->flags);
+
+ÂÂÂ STAT_INC(host->stat.n_datareq);
+ÂÂÂ host->data = data;
+ÂÂÂ host->size = data->blksz * data->blocks;
+ÂÂÂ data->bytes_xfered = 0;
+
+ÂÂÂ clks = (unsigned long long)data->timeout_ns * host->sdmmc_ck;
+ÂÂÂ do_div(clks, NSEC_PER_SEC);
+ÂÂÂ timeout = data->timeout_clks + (unsigned int)clks;
+
+ÂÂÂ writel_relaxed(timeout, host->base + SDMMC_DTIMER);
+ÂÂÂ writel_relaxed(host->size, host->base + SDMMC_DLENR);
+
+ÂÂÂ datactrl = FIELD_PREP(DCTRLR_DBLOCKSIZE_MASK, ilog2(data->blksz));
+
+ÂÂÂ if (data->flags & MMC_DATA_READ) {
+ÂÂÂÂÂÂÂ datactrl |= DCTRLR_DTDIR;
+ÂÂÂÂÂÂÂ imask = MASKR_RXOVERRIE;
+ÂÂÂ } else {
+ÂÂÂÂÂÂÂ imask = MASKR_TXUNDERRIE;
+ÂÂÂ }
+
+ÂÂÂ if (host->mmc->card && mmc_card_sdio(host->mmc->card))
+ÂÂÂÂÂÂÂ datactrl |= DCTRLR_SDIOEN | DCTRLR_DTMODE_SDIO;
+
+ÂÂÂ idmactrl = IDMACTRLR_IDMAEN;
+
+ÂÂÂ writel_relaxed(sg_dma_address(data->sg),
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂ host->base + SDMMC_IDMABASE0R);
+ÂÂÂ writel_relaxed(idmactrl, host->base + SDMMC_IDMACTRLR);
+
+ÂÂÂ imask |= MASKR_DATAENDIE | MASKR_DTIMEOUTIE | MASKR_DCRCFAILIE;
+ÂÂÂ enable_imask(host, imask);
+
+ÂÂÂ writel_relaxed(datactrl, host->base + SDMMC_DCTRLR);
+}
+
+static void stm32_sdmmc_start_cmd(struct sdmmc_host *host,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ struct mmc_command *cmd, u32 c)
+{
+ÂÂÂ void __iomem *base = host->base;
Not need to introduce this variable.
+ÂÂÂ u32 imsk;
+
+ÂÂÂ dev_dbg(mmc_dev(host->mmc), "op %u arg %08x flags %08x\n",
+ÂÂÂÂÂÂÂ cmd->opcode, cmd->arg, cmd->flags);
+
+ÂÂÂ STAT_INC(host->stat.n_req);
+
+ÂÂÂ if (readl_relaxed(base + SDMMC_CMDR) & CMDR_CPSMEM)
+ÂÂÂÂÂÂÂ writel_relaxed(0, base + SDMMC_CMDR);
+
+ÂÂÂ c |= cmd->opcode | CMDR_CPSMEM;
+ÂÂÂ if (cmd->flags & MMC_RSP_PRESENT) {
+ÂÂÂÂÂÂÂ imsk = MASKR_CMDRENDIE | MASKR_CTIMEOUTIE;
+ÂÂÂÂÂÂÂ if (cmd->flags & MMC_RSP_CRC)
+ÂÂÂÂÂÂÂÂÂÂÂ imsk |= MASKR_CCRCFAILIE;
+
+ÂÂÂÂÂÂÂ if (cmd->flags & MMC_RSP_136)
+ÂÂÂÂÂÂÂÂÂÂÂ c |= CMDR_WAITRESP_LRSP_CRC;
+ÂÂÂÂÂÂÂ else if (cmd->flags & MMC_RSP_CRC)
+ÂÂÂÂÂÂÂÂÂÂÂ c |= CMDR_WAITRESP_SRSP_CRC;
+ÂÂÂÂÂÂÂ else
+ÂÂÂÂÂÂÂÂÂÂÂ c |= CMDR_WAITRESP_SRSP;
+ÂÂÂ } else {
+ÂÂÂÂÂÂÂ c &= ~CMDR_WAITRESP_MASK;
+ÂÂÂÂÂÂÂ imsk = MASKR_CMDSENTIE;
+ÂÂÂ }
+
+ÂÂÂ host->cmd = cmd;
+
+ÂÂÂ enable_imask(host, imsk);
+
+ÂÂÂ writel_relaxed(cmd->arg, base + SDMMC_ARGR);
+ÂÂÂ writel_relaxed(c, base + SDMMC_CMDR);
+}
+
+static void stm32_sdmmc_cmd_irq(struct sdmmc_host *host, u32 status)
+{
+ÂÂÂ struct mmc_command *cmd = host->cmd;
+
+ÂÂÂ if (!cmd)
+ÂÂÂÂÂÂÂ return;
+
+ÂÂÂ host->cmd = NULL;
+
+ÂÂÂ if (status & STAR_CTIMEOUT) {
+ÂÂÂÂÂÂÂ STAT_INC(host->stat.n_ctimeout);
+ÂÂÂÂÂÂÂ cmd->error = -ETIMEDOUT;
+ÂÂÂÂÂÂÂ host->dpsm_abort = true;
+ÂÂÂ } else if (status & STAR_CCRCFAIL && cmd->flags & MMC_RSP_CRC) {
+ÂÂÂÂÂÂÂ STAT_INC(host->stat.n_ccrcfail);
+ÂÂÂÂÂÂÂ cmd->error = -EILSEQ;
+ÂÂÂÂÂÂÂ host->dpsm_abort = true;
+ÂÂÂ } else if (status & STAR_CMDREND && cmd->flags & MMC_RSP_PRESENT) {
+ÂÂÂÂÂÂÂ cmd->resp[0] = readl_relaxed(host->base + SDMMC_RESP1R);
+ÂÂÂÂÂÂÂ cmd->resp[1] = readl_relaxed(host->base + SDMMC_RESP2R);
+ÂÂÂÂÂÂÂ cmd->resp[2] = readl_relaxed(host->base + SDMMC_RESP3R);
+ÂÂÂÂÂÂÂ cmd->resp[3] = readl_relaxed(host->base + SDMMC_RESP4R);
+ÂÂÂ }
+
+ÂÂÂ if (!host->data)
+ÂÂÂÂÂÂÂ stm32_sdmmc_request_end(host, host->mrq);
+}
+
+static void stm32_sdmmc_data_irq(struct sdmmc_host *host, u32 status)
+{
+ÂÂÂ struct mmc_dataÂÂÂ *data = host->data;
+ÂÂÂ struct mmc_command *stop = &host->stop_abort;
+
+ÂÂÂ if (!data)
+ÂÂÂÂÂÂÂ return;
+
+ÂÂÂ if (status & STAR_DCRCFAIL) {
+ÂÂÂÂÂÂÂ STAT_INC(host->stat.n_dcrcfail);
+ÂÂÂÂÂÂÂ data->error = -EILSEQ;
+ÂÂÂÂÂÂÂ if (readl_relaxed(host->base + SDMMC_DCNTR))
+ÂÂÂÂÂÂÂÂÂÂÂ host->dpsm_abort = true;
+ÂÂÂ } else if (status & STAR_DTIMEOUT) {
+ÂÂÂÂÂÂÂ STAT_INC(host->stat.n_dtimeout);
+ÂÂÂÂÂÂÂ data->error = -ETIMEDOUT;
+ÂÂÂÂÂÂÂ host->dpsm_abort = true;
+ÂÂÂ } else if (status & STAR_TXUNDERR) {
+ÂÂÂÂÂÂÂ STAT_INC(host->stat.n_txunderrun);
+ÂÂÂÂÂÂÂ data->error = -EIO;
+ÂÂÂÂÂÂÂ host->dpsm_abort = true;
+ÂÂÂ } else if (status & STAR_RXOVERR) {
+ÂÂÂÂÂÂÂ STAT_INC(host->stat.n_rxoverrun);
+ÂÂÂÂÂÂÂ data->error = -EIO;
+ÂÂÂÂÂÂÂ host->dpsm_abort = true;
+ÂÂÂ }
+
+ÂÂÂ if (status & STAR_DATAEND || data->error || host->dpsm_abort) {
+ÂÂÂÂÂÂÂ host->data = NULL;
+
+ÂÂÂÂÂÂÂ writel_relaxed(0, host->base + SDMMC_IDMACTRLR);
+
+ÂÂÂÂÂÂÂ if (!data->error)
+ÂÂÂÂÂÂÂÂÂÂÂ data->bytes_xfered = data->blocks * data->blksz;
+
+ÂÂÂÂÂÂÂ /*
+ÂÂÂÂÂÂÂÂ * To stop Data Path State Machine, a stop_transmission command
+ÂÂÂÂÂÂÂÂ * shall be send on cmd or data errors of single, multi,
+ÂÂÂÂÂÂÂÂ * pre-defined block and stream request.
+ÂÂÂÂÂÂÂÂ */
+ÂÂÂÂÂÂÂ if (host->dpsm_abort && !data->stop) {
+ÂÂÂÂÂÂÂÂÂÂÂ memset(stop, 0, sizeof(struct mmc_command));
+ÂÂÂÂÂÂÂÂÂÂÂ stop->opcode = MMC_STOP_TRANSMISSION;
+ÂÂÂÂÂÂÂÂÂÂÂ stop->arg = 0;
+ÂÂÂÂÂÂÂÂÂÂÂ stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
+ÂÂÂÂÂÂÂÂÂÂÂ data->stop = stop;
+ÂÂÂÂÂÂÂ }
+
+ÂÂÂÂÂÂÂ disable_imask(host, MASKR_RXOVERRIE | MASKR_TXUNDERRIE
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ | MASKR_DCRCFAILIE | MASKR_DATAENDIE
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ | MASKR_DTIMEOUTIE);
+
+ÂÂÂÂÂÂÂ if (!data->stop)
+ÂÂÂÂÂÂÂÂÂÂÂ stm32_sdmmc_request_end(host, data->mrq);
+ÂÂÂÂÂÂÂ else
+ÂÂÂÂÂÂÂÂÂÂÂ stm32_sdmmc_start_cmd(host, data->stop, CMDR_CMDSTOP);
+ÂÂÂ }
+}
+
+static irqreturn_t stm32_sdmmc_irq(int irq, void *dev_id)
+{
+ÂÂÂ struct sdmmc_host *host = dev_id;
+ÂÂÂ u32 status;
+
+ÂÂÂ spin_lock(&host->lock);
+
+ÂÂÂ status = readl_relaxed(host->base + SDMMC_STAR);
+ÂÂÂ dev_dbg(mmc_dev(host->mmc), "irq sta:%#x\n", status);
+ÂÂÂ writel_relaxed(status & ICR_STATIC_FLAG, host->base + SDMMC_ICR);
+
+ÂÂÂ stm32_sdmmc_cmd_irq(host, status);
+ÂÂÂ stm32_sdmmc_data_irq(host, status);
+
+ÂÂÂ spin_unlock(&host->lock);
+
+ÂÂÂ return IRQ_HANDLED;
+}
+
+static void stm32_sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ÂÂÂ struct sdmmc_host *host = mmc_priv(mmc);
+ÂÂÂ struct mmc_data *data = mrq->data;
+
+ÂÂÂ if (!data)
+ÂÂÂÂÂÂÂ return;
+
+ÂÂÂ /* This data might be unmapped at this time */
+ÂÂÂ data->host_cookie = COOKIE_UNMAPPED;
+
+ÂÂÂ if (!stm32_sdmmc_validate_data(host, mrq->data, COOKIE_PRE_MAPPED))
+ÂÂÂÂÂÂÂ data->host_cookie = COOKIE_UNMAPPED;
+}
+
+static void stm32_sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ int err)
+{
+ÂÂÂ struct sdmmc_host *host = mmc_priv(mmc);
+ÂÂÂ struct mmc_data *data = mrq->data;
+
+ÂÂÂ if (!data)
+ÂÂÂÂÂÂÂ return;
+
+ÂÂÂ if (data->host_cookie != COOKIE_UNMAPPED)
+ÂÂÂÂÂÂÂ dma_unmap_sg(mmc_dev(host->mmc),
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ data->sg,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ data->sg_len,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ mmc_get_dma_dir(data));
+
+ÂÂÂ data->host_cookie = COOKIE_UNMAPPED;
+}
+
+static void stm32_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ÂÂÂ unsigned int cmdat = 0;
+ÂÂÂ struct sdmmc_host *host = mmc_priv(mmc);
+ÂÂÂ unsigned long flags;
+
+ÂÂÂ mrq->cmd->error = stm32_sdmmc_validate_data(host, mrq->data,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ COOKIE_MAPPED);
+ÂÂÂ if (mrq->cmd->error) {
+ÂÂÂÂÂÂÂ mmc_request_done(mmc, mrq);
+ÂÂÂÂÂÂÂ return;
+ÂÂÂ }
+
+ÂÂÂ spin_lock_irqsave(&host->lock, flags);
+
+ÂÂÂ host->mrq = mrq;
+
+ÂÂÂ if (mrq->data) {
+ÂÂÂÂÂÂÂ host->dpsm_abort = false;
+ÂÂÂÂÂÂÂ stm32_sdmmc_start_data(host, mrq->data);
+ÂÂÂÂÂÂÂ cmdat |= CMDR_CMDTRANS;
+ÂÂÂ }
+
+ÂÂÂ stm32_sdmmc_start_cmd(host, mrq->cmd, cmdat);
+
+ÂÂÂ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static struct mmc_host_ops stm32_sdmmc_ops = {
+ÂÂÂ .requestÂÂÂ = stm32_sdmmc_request,
+ÂÂÂ .pre_reqÂÂÂ = stm32_sdmmc_pre_req,
+ÂÂÂ .post_reqÂÂÂ = stm32_sdmmc_post_req,
+ÂÂÂ .set_iosÂÂÂ = stm32_sdmmc_set_ios,
+ÂÂÂ .get_cdÂÂÂÂÂÂÂ = mmc_gpio_get_cd,
+ÂÂÂ .card_busyÂÂÂ = stm32_sdmmc_card_busy,
+};
+
+static const struct of_device_id stm32_sdmmc_match[] = {
+ÂÂÂ { .compatible = "st,stm32h7-sdmmc",},
+ÂÂÂ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_sdmmc_match);
+
+static int stm32_sdmmc_of_parse(struct device_node *np, struct mmc_host *mmc)
+{
+ÂÂÂ struct sdmmc_host *host = mmc_priv(mmc);
+ÂÂÂ int ret = mmc_of_parse(mmc);
+
+ÂÂÂ if (ret)
+ÂÂÂÂÂÂÂ return ret;
+
+ÂÂÂ if (of_get_property(np, "st,negedge", NULL))
+ÂÂÂÂÂÂÂ host->clk_reg_add |= CLKCR_NEGEDGE;
+ÂÂÂ if (of_get_property(np, "st,dirpol", NULL))
+ÂÂÂÂÂÂÂ host->pwr_reg_add |= POWER_DIRPOL;
+ÂÂÂ if (of_get_property(np, "st,pin-ckin", NULL))
+ÂÂÂÂÂÂÂ host->clk_reg_add |= CLKCR_SELCLKRX_CKIN;
+
Use device_property_present?
BR
+ÂÂÂ return 0;
+}
+
+static int stm32_sdmmc_probe(struct platform_device *pdev)
+{
+ÂÂÂ struct device_node *np = pdev->dev.of_node;
+ÂÂÂ struct sdmmc_host *host;
+ÂÂÂ struct mmc_host *mmc;
+ÂÂÂ struct resource *res;
+ÂÂÂ int irq, ret;
+
+ÂÂÂ if (!np) {
+ÂÂÂÂÂÂÂ dev_err(&pdev->dev, "No DT found\n");
+ÂÂÂÂÂÂÂ return -EINVAL;
+ÂÂÂ }
+
+ÂÂÂ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ÂÂÂ irq = platform_get_irq(pdev, 0);
+ÂÂÂ if (irq < 0)
+ÂÂÂÂÂÂÂ return -EINVAL;
+
+ÂÂÂ mmc = mmc_alloc_host(sizeof(struct sdmmc_host), &pdev->dev);
+ÂÂÂ if (!mmc)
+ÂÂÂÂÂÂÂ return -ENOMEM;
+
+ÂÂÂ host = mmc_priv(mmc);
+ÂÂÂ host->mmc = mmc;
+ÂÂÂ platform_set_drvdata(pdev, mmc);
+
+ÂÂÂ host->base = devm_ioremap_resource(&pdev->dev, res);
+ÂÂÂ if (IS_ERR(host->base)) {
+ÂÂÂÂÂÂÂ ret = PTR_ERR(host->base);
+ÂÂÂÂÂÂÂ goto host_free;
+ÂÂÂ }
+
+ÂÂÂ writel_relaxed(0, host->base + SDMMC_MASKR);
+ÂÂÂ writel_relaxed(~0UL, host->base + SDMMC_ICR);
+
+ÂÂÂ ret = devm_request_irq(&pdev->dev, irq, stm32_sdmmc_irq, IRQF_SHARED,
+ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂ DRIVER_NAME " (cmd)", host);
+ÂÂÂ if (ret)
+ÂÂÂÂÂÂÂ goto host_free;
+
+ÂÂÂ host->clk = devm_clk_get(&pdev->dev, NULL);
+ÂÂÂ if (IS_ERR(host->clk)) {
+ÂÂÂÂÂÂÂ ret = PTR_ERR(host->clk);
+ÂÂÂÂÂÂÂ goto host_free;
+ÂÂÂ }
+
+ÂÂÂ ret = clk_prepare_enable(host->clk);
+ÂÂÂ if (ret)
+ÂÂÂÂÂÂÂ goto host_free;
+
+ÂÂÂ host->sdmmcclk = clk_get_rate(host->clk);
+ÂÂÂ mmc->f_min = DIV_ROUND_UP(host->sdmmcclk, 2 * CLKCR_CLKDIV_MAX);
+ÂÂÂ mmc->f_max = host->sdmmcclk;
+
+ÂÂÂ ret = stm32_sdmmc_of_parse(np, mmc);
+ÂÂÂ if (ret)
+ÂÂÂÂÂÂÂ goto clk_disable;
+
+ÂÂÂ host->rst = devm_reset_control_get(&pdev->dev, NULL);
+ÂÂÂ if (IS_ERR(host->rst)) {
+ÂÂÂÂÂÂÂ ret = PTR_ERR(host->rst);
+ÂÂÂÂÂÂÂ goto clk_disable;
+ÂÂÂ }
+
+ÂÂÂ stm32_sdmmc_pwroff(host);
+
+ÂÂÂ /* Get regulators and the supported OCR mask */
+ÂÂÂ ret = mmc_regulator_get_supply(mmc);
+ÂÂÂ if (ret == -EPROBE_DEFER)
+ÂÂÂÂÂÂÂ goto clk_disable;
+
+ÂÂÂ if (!mmc->ocr_avail)
+ÂÂÂÂÂÂÂ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ÂÂÂ mmc->ops = &stm32_sdmmc_ops;
+
+ÂÂÂ /* IDMA cannot do scatter lists */
+ÂÂÂ mmc->max_segs = 1;
+ÂÂÂ mmc->max_req_size = DLENR_DATALENGHT_MAX;
+ÂÂÂ mmc->max_seg_size = mmc->max_req_size;
+ÂÂÂ mmc->max_blk_size = 1 << DCTRLR_DBLOCKSIZE_MAX;
+
+ÂÂÂ /*
+ÂÂÂÂ * Limit the number of blocks transferred so that we don't overflow
+ÂÂÂÂ * the maximum request size.
+ÂÂÂÂ */
+ÂÂÂ mmc->max_blk_count = mmc->max_req_size >> DCTRLR_DBLOCKSIZE_MAX;
+
+ÂÂÂ spin_lock_init(&host->lock);
+
+ÂÂÂ ret = mmc_add_host(mmc);
+ÂÂÂ if (ret)
+ÂÂÂÂÂÂÂ goto clk_disable;
+
+ÂÂÂ stm32_sdmmc_stat_init(host);
+
+ÂÂÂ host->ip_ver = readl_relaxed(host->base + SDMMC_IPVR);
+ÂÂÂ dev_info(&pdev->dev, "%s: rev:%ld.%ld irq:%d\n",
+ÂÂÂÂÂÂÂÂ mmc_hostname(mmc),
+ÂÂÂÂÂÂÂÂ FIELD_GET(IPVR_MAJREV_MASK, host->ip_ver),
+ÂÂÂÂÂÂÂÂ FIELD_GET(IPVR_MINREV_MASK, host->ip_ver), irq);
+
+ÂÂÂ return 0;
+
+clk_disable:
+ÂÂÂ clk_disable_unprepare(host->clk);
+host_free:
+ÂÂÂ mmc_free_host(mmc);
+ÂÂÂ return ret;
+}
+
+static int stm32_sdmmc_remove(struct platform_device *pdev)
+{
+ÂÂÂ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ÂÂÂ struct sdmmc_host *host = mmc_priv(mmc);
+
+ÂÂÂ /* Debugfs stuff is cleaned up by mmc core */
+ÂÂÂ mmc_remove_host(mmc);
+ÂÂÂ clk_disable_unprepare(host->clk);
+ÂÂÂ mmc_free_host(mmc);
+
+ÂÂÂ return 0;
+}
+
+static struct platform_driver stm32_sdmmc_driver = {
+ÂÂÂ .probeÂÂÂÂÂÂÂ = stm32_sdmmc_probe,
+ÂÂÂ .removeÂÂÂÂÂÂÂ = stm32_sdmmc_remove,
+ÂÂÂ .driverÂÂÂ = {
+ÂÂÂÂÂÂÂ .nameÂÂÂ = DRIVER_NAME,
+ÂÂÂÂÂÂÂ .of_match_table = stm32_sdmmc_match,
+ÂÂÂ },
+};
+
+module_platform_driver(stm32_sdmmc_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 MMC/SD Card Interface driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Ludovic Barre <ludovic.barre@xxxxxx>");
diff --git a/drivers/mmc/host/stm32-sdmmc.h b/drivers/mmc/host/stm32-sdmmc.h
new file mode 100644
index 0000000..e39578e
--- /dev/null
+++ b/drivers/mmc/host/stm32-sdmmc.h
@@ -0,0 +1,220 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Ludovic Barre <ludovic.barre@xxxxxx> for STMicroelectronics.
+ */
+#define SDMMC_POWERÂÂÂÂÂÂÂÂÂÂÂ 0x000
+#define POWERCTRL_MASKÂÂÂÂÂÂÂÂÂÂÂ GENMASK(1, 0)
+#define POWERCTRL_OFFÂÂÂÂÂÂÂÂÂÂÂ 0x00
+#define POWERCTRL_CYCÂÂÂÂÂÂÂÂÂÂÂ 0x02
+#define POWERCTRL_ONÂÂÂÂÂÂÂÂÂÂÂ 0x03
+#define POWER_VSWITCHÂÂÂÂÂÂÂÂÂÂÂ BIT(2)
+#define POWER_VSWITCHENÂÂÂÂÂÂÂÂÂÂÂ BIT(3)
+#define POWER_DIRPOLÂÂÂÂÂÂÂÂÂÂÂ BIT(4)
+
+#define SDMMC_CLKCRÂÂÂÂÂÂÂÂÂÂÂ 0x004
+#define CLKCR_CLKDIV_MASKÂÂÂÂÂÂÂ GENMASK(9, 0)
+#define CLKCR_CLKDIV_MAXÂÂÂÂÂÂÂ CLKCR_CLKDIV_MASK
+#define CLKCR_PWRSAVÂÂÂÂÂÂÂÂÂÂÂ BIT(12)
+#define CLKCR_WIDBUS_4ÂÂÂÂÂÂÂÂÂÂÂ BIT(14)
+#define CLKCR_WIDBUS_8ÂÂÂÂÂÂÂÂÂÂÂ BIT(15)
+#define CLKCR_NEGEDGEÂÂÂÂÂÂÂÂÂÂÂ BIT(16)
+#define CLKCR_HWFC_ENÂÂÂÂÂÂÂÂÂÂÂ BIT(17)
+#define CLKCR_DDRÂÂÂÂÂÂÂÂÂÂÂ BIT(18)
+#define CLKCR_BUSSPEEDÂÂÂÂÂÂÂÂÂÂÂ BIT(19)
+#define CLKCR_SELCLKRX_MASKÂÂÂÂÂÂÂ GENMASK(21, 20)
+#define CLKCR_SELCLKRX_CKÂÂÂÂÂÂÂ (0 << 20)
+#define CLKCR_SELCLKRX_CKINÂÂÂÂÂÂÂ (1 << 20)
+#define CLKCR_SELCLKRX_FBCKÂÂÂÂÂÂÂ (2 << 20)
+
+#define SDMMC_ARGRÂÂÂÂÂÂÂÂÂÂÂ 0x008
+
+#define SDMMC_CMDRÂÂÂÂÂÂÂÂÂÂÂ 0x00c
+#define CMDR_CMDTRANSÂÂÂÂÂÂÂÂÂÂÂ BIT(6)
+#define CMDR_CMDSTOPÂÂÂÂÂÂÂÂÂÂÂ BIT(7)
+#define CMDR_WAITRESP_MASKÂÂÂÂÂÂÂ GENMASK(9, 8)
+#define CMDR_WAITRESP_NORSPÂÂÂÂÂÂÂ (0 << 8)
+#define CMDR_WAITRESP_SRSP_CRCÂÂÂÂÂÂÂ (1 << 8)
+#define CMDR_WAITRESP_SRSPÂÂÂÂÂÂÂ (2 << 8)
+#define CMDR_WAITRESP_LRSP_CRCÂÂÂÂÂÂÂ (3 << 8)
+#define CMDR_WAITINTÂÂÂÂÂÂÂÂÂÂÂ BIT(10)
+#define CMDR_WAITPENDÂÂÂÂÂÂÂÂÂÂÂ BIT(11)
+#define CMDR_CPSMEMÂÂÂÂÂÂÂÂÂÂÂ BIT(12)
+#define CMDR_DTHOLDÂÂÂÂÂÂÂÂÂÂÂ BIT(13)
+#define CMDR_BOOTMODEÂÂÂÂÂÂÂÂÂÂÂ BIT(14)
+#define CMDR_BOOTENÂÂÂÂÂÂÂÂÂÂÂ BIT(15)
+#define CMDR_CMDSUSPENDÂÂÂÂÂÂÂÂÂÂÂ BIT(16)
+
+#define SDMMC_RESPCMDRÂÂÂÂÂÂÂÂÂÂÂ 0x010
+#define SDMMC_RESP1RÂÂÂÂÂÂÂÂÂÂÂ 0x014
+#define SDMMC_RESP2RÂÂÂÂÂÂÂÂÂÂÂ 0x018
+#define SDMMC_RESP3RÂÂÂÂÂÂÂÂÂÂÂ 0x01c
+#define SDMMC_RESP4RÂÂÂÂÂÂÂÂÂÂÂ 0x020
+
+#define SDMMC_DTIMERÂÂÂÂÂÂÂÂÂÂÂ 0x024
+
+#define SDMMC_DLENRÂÂÂÂÂÂÂÂÂÂÂ 0x028
+#define DLENR_DATALENGHT_MASKÂÂÂÂÂÂÂ GENMASK(24, 0)
+#define DLENR_DATALENGHT_MAXÂÂÂÂÂÂÂ DLENR_DATALENGHT_MASK
+
+#define SDMMC_DCTRLRÂÂÂÂÂÂÂÂÂÂÂ 0x02c
+#define DCTRLR_DTENÂÂÂÂÂÂÂÂÂÂÂ BIT(0)
+#define DCTRLR_DTDIRÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
+#define DCTRLR_DTMODE_MASKÂÂÂÂÂÂÂ GENMASK(3, 2)
+#define DCTRLR_DTMODE_BLOCKÂÂÂÂÂÂÂ (0 << 2)
+#define DCTRLR_DTMODE_SDIOÂÂÂÂÂÂÂ (1 << 2)
+#define DCTRLR_DTMODE_MMCÂÂÂÂÂÂÂ (2 << 2)
+#define DCTRLR_DBLOCKSIZE_MASKÂÂÂÂÂÂÂ GENMASK(7, 4)
+#define DCTRLR_DBLOCKSIZE_MAXÂÂÂÂÂÂÂ 14
+#define DCTRLR_RWSTARTÂÂÂÂÂÂÂÂÂÂÂ BIT(8)
+#define DCTRLR_RWSTOPÂÂÂÂÂÂÂÂÂÂÂ BIT(9)
+#define DCTRLR_RWMODÂÂÂÂÂÂÂÂÂÂÂ BIT(10)
+#define DCTRLR_SDIOENÂÂÂÂÂÂÂÂÂÂÂ BIT(11)
+#define DCTRLR_BOOTACKENÂÂÂÂÂÂÂ BIT(12)
+#define DCTRLR_FIFORSTÂÂÂÂÂÂÂÂÂÂÂ BIT(13)
+
+#define SDMMC_DCNTRÂÂÂÂÂÂÂÂÂÂÂ 0x030
+
+#define SDMMC_STARÂÂÂÂÂÂÂÂÂÂÂ 0x034
+#define STAR_CCRCFAILÂÂÂÂÂÂÂÂÂÂÂ BIT(0)
+#define STAR_DCRCFAILÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
+#define STAR_CTIMEOUTÂÂÂÂÂÂÂÂÂÂÂ BIT(2)
+#define STAR_DTIMEOUTÂÂÂÂÂÂÂÂÂÂÂ BIT(3)
+#define STAR_TXUNDERRÂÂÂÂÂÂÂÂÂÂÂ BIT(4)
+#define STAR_RXOVERRÂÂÂÂÂÂÂÂÂÂÂ BIT(5)
+#define STAR_CMDRENDÂÂÂÂÂÂÂÂÂÂÂ BIT(6)
+#define STAR_CMDSENTÂÂÂÂÂÂÂÂÂÂÂ BIT(7)
+#define STAR_DATAENDÂÂÂÂÂÂÂÂÂÂÂ BIT(8)
+#define STAR_DHOLDÂÂÂÂÂÂÂÂÂÂÂ BIT(9)
+#define STAR_DBCKENDÂÂÂÂÂÂÂÂÂÂÂ BIT(10)
+#define STAR_DABORTÂÂÂÂÂÂÂÂÂÂÂ BIT(11)
+#define STAR_DPSMACTÂÂÂÂÂÂÂÂÂÂÂ BIT(12)
+#define STAR_CPSMACTÂÂÂÂÂÂÂÂÂÂÂ BIT(13)
+#define STAR_TXFIFOHEÂÂÂÂÂÂÂÂÂÂÂ BIT(14)
+#define STAR_TXFIFOHFÂÂÂÂÂÂÂÂÂÂÂ BIT(15)
+#define STAR_TXFIFOFÂÂÂÂÂÂÂÂÂÂÂ BIT(16)
+#define STAR_RXFIFOFÂÂÂÂÂÂÂÂÂÂÂ BIT(17)
+#define STAR_TXFIFOEÂÂÂÂÂÂÂÂÂÂÂ BIT(18)
+#define STAR_RXFIFOEÂÂÂÂÂÂÂÂÂÂÂ BIT(19)
+#define STAR_BUSYD0ÂÂÂÂÂÂÂÂÂÂÂ BIT(20)
+#define STAR_BUSYD0ENDÂÂÂÂÂÂÂÂÂÂÂ BIT(21)
+#define STAR_SDIOITÂÂÂÂÂÂÂÂÂÂÂ BIT(22)
+#define STAR_ACKFAILÂÂÂÂÂÂÂÂÂÂÂ BIT(23)
+#define STAR_ACKTIMEOUTÂÂÂÂÂÂÂÂÂÂÂ BIT(24)
+#define STAR_VSWENDÂÂÂÂÂÂÂÂÂÂÂ BIT(25)
+#define STAR_CKSTOPÂÂÂÂÂÂÂÂÂÂÂ BIT(26)
+#define STAR_IDMATEÂÂÂÂÂÂÂÂÂÂÂ BIT(27)
+#define STAR_IDMABTCÂÂÂÂÂÂÂÂÂÂÂ BIT(28)
+
+#define SDMMC_ICRÂÂÂÂÂÂÂÂÂÂÂ 0x038
+#define ICR_CCRCFAILCÂÂÂÂÂÂÂÂÂÂÂ BIT(0)
+#define ICR_DCRCFAILCÂÂÂÂÂÂÂÂÂÂÂ BIT(1)
+#define ICR_CTIMEOUTCÂÂÂÂÂÂÂÂÂÂÂ BIT(2)
+#define ICR_DTIMEOUTCÂÂÂÂÂÂÂÂÂÂÂ BIT(3)
+#define ICR_TXUNDERRCÂÂÂÂÂÂÂÂÂÂÂ BIT(4)
+#define ICR_RXOVERRCÂÂÂÂÂÂÂÂÂÂÂ BIT(5)
+#define ICR_CMDRENDCÂÂÂÂÂÂÂÂÂÂÂ BIT(6)
+#define ICR_CMDSENTCÂÂÂÂÂÂÂÂÂÂÂ BIT(7)
+#define ICR_DATAENDCÂÂÂÂÂÂÂÂÂÂÂ BIT(8)
+#define ICR_DHOLDCÂÂÂÂÂÂÂÂÂÂÂ BIT(9)
+#define ICR_DBCKENDCÂÂÂÂÂÂÂÂÂÂÂ BIT(10)
+#define ICR_DABORTCÂÂÂÂÂÂÂÂÂÂÂ BIT(11)
+#define ICR_BUSYD0ENDCÂÂÂÂÂÂÂÂÂÂÂ BIT(21)
+#define ICR_SDIOITCÂÂÂÂÂÂÂÂÂÂÂ BIT(22)
+#define ICR_ACKFAILCÂÂÂÂÂÂÂÂÂÂÂ BIT(23)
+#define ICR_ACKTIMEOUTCÂÂÂÂÂÂÂÂÂÂÂ BIT(24)
+#define ICR_VSWENDCÂÂÂÂÂÂÂÂÂÂÂ BIT(25)
+#define ICR_CKSTOPCÂÂÂÂÂÂÂÂÂÂÂ BIT(26)
+#define ICR_IDMATECÂÂÂÂÂÂÂÂÂÂÂ BIT(27)
+#define ICR_IDMABTCCÂÂÂÂÂÂÂÂÂÂÂ BIT(28)
+#define ICR_STATIC_FLAGÂÂÂÂÂÂÂÂÂÂÂ ((GENMASK(28, 21)) | (GENMASK(11, 0)))
+
+#define SDMMC_MASKRÂÂÂÂÂÂÂÂÂÂÂ 0x03c
+#define MASKR_CCRCFAILIEÂÂÂÂÂÂÂ BIT(0)
+#define MASKR_DCRCFAILIEÂÂÂÂÂÂÂ BIT(1)
+#define MASKR_CTIMEOUTIEÂÂÂÂÂÂÂ BIT(2)
+#define MASKR_DTIMEOUTIEÂÂÂÂÂÂÂ BIT(3)
+#define MASKR_TXUNDERRIEÂÂÂÂÂÂÂ BIT(4)
+#define MASKR_RXOVERRIEÂÂÂÂÂÂÂÂÂÂÂ BIT(5)
+#define MASKR_CMDRENDIEÂÂÂÂÂÂÂÂÂÂÂ BIT(6)
+#define MASKR_CMDSENTIEÂÂÂÂÂÂÂÂÂÂÂ BIT(7)
+#define MASKR_DATAENDIEÂÂÂÂÂÂÂÂÂÂÂ BIT(8)
+#define MASKR_DHOLDIEÂÂÂÂÂÂÂÂÂÂÂ BIT(9)
+#define MASKR_DBCKENDIEÂÂÂÂÂÂÂÂÂÂÂ BIT(10)
+#define MASKR_DABORTIEÂÂÂÂÂÂÂÂÂÂÂ BIT(11)
+#define MASKR_TXFIFOHEIEÂÂÂÂÂÂÂ BIT(14)
+#define MASKR_RXFIFOHFIEÂÂÂÂÂÂÂ BIT(15)
+#define MASKR_RXFIFOFIEÂÂÂÂÂÂÂÂÂÂÂ BIT(17)
+#define MASKR_TXFIFOEIEÂÂÂÂÂÂÂÂÂÂÂ BIT(18)
+#define MASKR_BUSYD0ENDIEÂÂÂÂÂÂÂ BIT(21)
+#define MASKR_SDIOITIEÂÂÂÂÂÂÂÂÂÂÂ BIT(22)
+#define MASKR_ACKFAILIEÂÂÂÂÂÂÂÂÂÂÂ BIT(23)
+#define MASKR_ACKTIMEOUTIEÂÂÂÂÂÂÂ BIT(24)
+#define MASKR_VSWENDIEÂÂÂÂÂÂÂÂÂÂÂ BIT(25)
+#define MASKR_CKSTOPIEÂÂÂÂÂÂÂÂÂÂÂ BIT(26)
+#define MASKR_IDMABTCIEÂÂÂÂÂÂÂÂÂÂÂ BIT(28)
+
+#define SDMMC_ACKTIMERÂÂÂÂÂÂÂÂÂÂÂ 0x040
+#define ACKTIMER_ACKTIME_MASKÂÂÂÂÂÂÂ GENMASK(24, 0)
+
+#define SDMMC_FIFORÂÂÂÂÂÂÂÂÂÂÂ 0x080
+
+#define SDMMC_IDMACTRLRÂÂÂÂÂÂÂÂÂÂÂ 0x050
+#define IDMACTRLR_IDMAENÂÂÂÂÂÂÂ BIT(0)
+#define IDMACTRLR_IDMABMODEÂÂÂÂÂÂÂ BIT(1)
+#define IDMACTRLR_IDMABACTÂÂÂÂÂÂÂ BIT(2)
+
+#define SDMMC_IDMABSIZERÂÂÂÂÂÂÂ 0x054
+#define IDMABSIZER_IDMABNDT_MASKÂÂÂ GENMASK(12, 5)
+
+#define SDMMC_IDMABASE0RÂÂÂÂÂÂÂ 0x058
+#define SDMMC_IDMABASE1RÂÂÂÂÂÂÂ 0x05c
+
+#define SDMMC_IPVRÂÂÂÂÂÂÂÂÂÂÂ 0x3fc
+#define IPVR_MINREV_MASKÂÂÂÂÂÂÂ GENMASK(3, 0)
+#define IPVR_MAJREV_MASKÂÂÂÂÂÂÂ GENMASK(7, 4)
+
+enum stm32_sdmmc_cookie {
+ÂÂÂ COOKIE_UNMAPPED,
+ÂÂÂ COOKIE_PRE_MAPPED,ÂÂÂ /* mapped by pre_req() of stm32 */
+ÂÂÂ COOKIE_MAPPED,ÂÂÂÂÂÂÂ /* mapped by prepare_data() of stm32 */
+};
+
+struct sdmmc_stat {
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ n_req;
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ n_datareq;
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ n_ctimeout;
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ n_ccrcfail;
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ n_dtimeout;
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ n_dcrcfail;
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ n_txunderrun;
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ n_rxoverrun;
+ÂÂÂ unsigned longÂÂÂÂÂÂÂ nb_dma_err;
+};
+
+struct sdmmc_host {
+ÂÂÂ void __iomemÂÂÂÂÂÂÂ *base;
+ÂÂÂ struct mmc_hostÂÂÂÂÂÂÂ *mmc;
+ÂÂÂ struct clkÂÂÂÂÂÂÂ *clk;
+ÂÂÂ struct reset_controlÂÂÂ *rst;
+
+ÂÂÂ u32ÂÂÂÂÂÂÂÂÂÂÂ clk_reg_add;
+ÂÂÂ u32ÂÂÂÂÂÂÂÂÂÂÂ pwr_reg_add;
+
+ÂÂÂ struct mmc_requestÂÂÂ *mrq;
+ÂÂÂ struct mmc_commandÂÂÂ *cmd;
+ÂÂÂ struct mmc_dataÂÂÂÂÂÂÂ *data;
+ÂÂÂ struct mmc_commandÂÂÂ stop_abort;
+ÂÂÂ boolÂÂÂÂÂÂÂÂÂÂÂ dpsm_abort;
+
+ÂÂÂ /* protect host registers access */
+ÂÂÂ spinlock_tÂÂÂÂÂÂÂ lock;
+
+ÂÂÂ unsigned intÂÂÂÂÂÂÂ sdmmcclk;
+ÂÂÂ unsigned intÂÂÂÂÂÂÂ sdmmc_ck;
+
+ÂÂÂ u32ÂÂÂÂÂÂÂÂÂÂÂ size;
+
+ÂÂÂ u32ÂÂÂÂÂÂÂÂÂÂÂ ip_ver;
+ÂÂÂ struct sdmmc_statÂÂÂ stat;
+};