Skip to content

Commit 1bcfbfd

Browse files
Christophe Kerellostorulf
authored andcommitted
mmc: mmci: stm32: add SDIO in-band interrupt mode
Add the support of SDIO in-band interrupt mode for STM32 and Ux500 variants. It allows the SD I/O card to interrupt the host on SDMMC_D1 data line. It is not enabled by default on Ux500 variant as this is unstable and Ux500 users should use out-of-band IRQs. Signed-off-by: Christophe Kerello <[email protected]> Signed-off-by: Yann Gautier <[email protected]> Reviewed-by: Linus Walleij <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent 37c8ceb commit 1bcfbfd

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

drivers/mmc/host/mmci.c

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ static struct variant_data variant_stm32_sdmmc = {
273273
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
274274
.stm32_idmabsize_mask = GENMASK(12, 5),
275275
.stm32_idmabsize_align = BIT(5),
276+
.supports_sdio_irq = true,
276277
.busy_timeout = true,
277278
.busy_detect = true,
278279
.busy_detect_flag = MCI_STM32_BUSYD0,
@@ -300,6 +301,7 @@ static struct variant_data variant_stm32_sdmmcv2 = {
300301
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
301302
.stm32_idmabsize_mask = GENMASK(16, 5),
302303
.stm32_idmabsize_align = BIT(5),
304+
.supports_sdio_irq = true,
303305
.dma_lli = true,
304306
.busy_timeout = true,
305307
.busy_detect = true,
@@ -328,6 +330,7 @@ static struct variant_data variant_stm32_sdmmcv3 = {
328330
.datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN,
329331
.stm32_idmabsize_mask = GENMASK(16, 6),
330332
.stm32_idmabsize_align = BIT(6),
333+
.supports_sdio_irq = true,
331334
.dma_lli = true,
332335
.busy_timeout = true,
333336
.busy_detect = true,
@@ -421,8 +424,9 @@ void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
421424
*/
422425
static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
423426
{
424-
/* Keep busy mode in DPSM if enabled */
425-
datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
427+
/* Keep busy mode in DPSM and SDIO mask if enabled */
428+
datactrl |= host->datactrl_reg & (host->variant->busy_dpsm_flag |
429+
host->variant->datactrl_mask_sdio);
426430

427431
if (host->datactrl_reg != datactrl) {
428432
host->datactrl_reg = datactrl;
@@ -1762,6 +1766,25 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
17621766
return IRQ_HANDLED;
17631767
}
17641768

1769+
static void mmci_write_sdio_irq_bit(struct mmci_host *host, int enable)
1770+
{
1771+
void __iomem *base = host->base;
1772+
u32 mask = readl_relaxed(base + MMCIMASK0);
1773+
1774+
if (enable)
1775+
writel_relaxed(mask | MCI_ST_SDIOITMASK, base + MMCIMASK0);
1776+
else
1777+
writel_relaxed(mask & ~MCI_ST_SDIOITMASK, base + MMCIMASK0);
1778+
}
1779+
1780+
static void mmci_signal_sdio_irq(struct mmci_host *host, u32 status)
1781+
{
1782+
if (status & MCI_ST_SDIOIT) {
1783+
mmci_write_sdio_irq_bit(host, 0);
1784+
sdio_signal_irq(host->mmc);
1785+
}
1786+
}
1787+
17651788
/*
17661789
* Handle completion of command and data transfers.
17671790
*/
@@ -1806,6 +1829,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
18061829
mmci_data_irq(host, host->data, status);
18071830
}
18081831

1832+
if (host->variant->supports_sdio_irq)
1833+
mmci_signal_sdio_irq(host, status);
1834+
18091835
/*
18101836
* Busy detection has been handled by mmci_cmd_irq() above.
18111837
* Clear the status bit to prevent polling in IRQ context.
@@ -2042,6 +2068,35 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
20422068
return ret;
20432069
}
20442070

2071+
static void mmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
2072+
{
2073+
struct mmci_host *host = mmc_priv(mmc);
2074+
unsigned long flags;
2075+
2076+
if (enable)
2077+
/* Keep the SDIO mode bit if SDIO irqs are enabled */
2078+
pm_runtime_get_sync(mmc_dev(mmc));
2079+
2080+
spin_lock_irqsave(&host->lock, flags);
2081+
mmci_write_sdio_irq_bit(host, enable);
2082+
spin_unlock_irqrestore(&host->lock, flags);
2083+
2084+
if (!enable) {
2085+
pm_runtime_mark_last_busy(mmc_dev(mmc));
2086+
pm_runtime_put_autosuspend(mmc_dev(mmc));
2087+
}
2088+
}
2089+
2090+
static void mmci_ack_sdio_irq(struct mmc_host *mmc)
2091+
{
2092+
struct mmci_host *host = mmc_priv(mmc);
2093+
unsigned long flags;
2094+
2095+
spin_lock_irqsave(&host->lock, flags);
2096+
mmci_write_sdio_irq_bit(host, 1);
2097+
spin_unlock_irqrestore(&host->lock, flags);
2098+
}
2099+
20452100
static struct mmc_host_ops mmci_ops = {
20462101
.request = mmci_request,
20472102
.pre_req = mmci_pre_request,
@@ -2317,6 +2372,16 @@ static int mmci_probe(struct amba_device *dev,
23172372
mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
23182373
}
23192374

2375+
if (variant->supports_sdio_irq && host->mmc->caps & MMC_CAP_SDIO_IRQ) {
2376+
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
2377+
2378+
mmci_ops.enable_sdio_irq = mmci_enable_sdio_irq;
2379+
mmci_ops.ack_sdio_irq = mmci_ack_sdio_irq;
2380+
2381+
mmci_write_datactrlreg(host,
2382+
host->variant->datactrl_mask_sdio);
2383+
}
2384+
23202385
/* Variants with mandatory busy timeout in HW needs R1B responses. */
23212386
if (variant->busy_timeout)
23222387
mmc->caps |= MMC_CAP_NEED_RSP_BUSY;

drivers/mmc/host/mmci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ enum mmci_busy_state {
331331
* register.
332332
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
333333
* @dma_lli: true if variant has dma link list feature.
334+
* @supports_sdio_irq: allow SD I/O card to interrupt the host
334335
* @stm32_idmabsize_mask: stm32 sdmmc idma buffer size.
335336
* @dma_flow_controller: use peripheral as flow controller for DMA.
336337
*/
@@ -377,6 +378,7 @@ struct variant_data {
377378
u32 start_err;
378379
u32 opendrain;
379380
u8 dma_lli:1;
381+
bool supports_sdio_irq;
380382
u32 stm32_idmabsize_mask;
381383
u32 stm32_idmabsize_align;
382384
bool dma_flow_controller;

0 commit comments

Comments
 (0)