Date   

[PATCH 4.4.y-cip 60/83] mmc: host: tmio: use defines for CTL_STOP_INTERNAL_ACTION values

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit 9afcbf4a6f1995f3b47088764eaef7b56154beb9 upstream.

Reviewed-by: Simon Horman <horms+renesas@...>
Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc.h | 4 ++++
drivers/mmc/host/tmio_mmc_pio.c | 6 +++---
2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index f864be46..3164e7c 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -49,6 +49,10 @@
#define CTL_CLK_AND_WAIT_CTL 0x138
#define CTL_RESET_SDIO 0x1e0

+/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
+#define TMIO_STOP_STP BIT(0)
+#define TMIO_STOP_SEC BIT(8)
+
/* Definitions for values the CTRL_STATUS register can take. */
#define TMIO_STAT_CMDRESPEND BIT(0)
#define TMIO_STAT_DATAEND BIT(2)
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 2fecd22..477cac8 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -340,7 +340,7 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command

/* CMD12 is handled by hardware */
if (cmd->opcode == MMC_STOP_TRANSMISSION && !cmd->arg) {
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
+ sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, TMIO_STOP_STP);
return 0;
}

@@ -367,7 +367,7 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
if (data) {
c |= DATA_PRESENT;
if (data->blocks > 1) {
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100);
+ sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, TMIO_STOP_SEC);
c |= TRANSFER_MULTI;

/*
@@ -554,7 +554,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)

if (stop) {
if (stop->opcode == MMC_STOP_TRANSMISSION && !stop->arg)
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
+ sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0);
else
BUG();
}
--
2.7.4


[PATCH 4.4.y-cip 59/83] mmc: tmio: ensure end of DMA and SD access are in sync

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit 52ad9a8e854ca13151f4af8140297f73d49e318a upstream.

The current code assumes that DMA is finished before SD access end is
flagged. Thus, it schedules the 'dma_complete' tasklet in the SD card
interrupt routine when DATAEND is set. The assumption is not safe,
though. Even by mounting an SD card, it can be seen that sometimes DMA
complete is first, sometimes DATAEND. It seems they are usually close
enough timewise to not cause problems. However, a customer reported that
with CMD53 sometimes things really break apart. As a result, the BSP has
a patch which introduces flags for both events and makes sure both flags
are set before scheduling the tasklet. The customer accepted the patch,
yet it doesn't seem a proper upstream solution to me.

This patch refactors the code to replace the tasklet with already
existing and more lightweight mechanisms. First of all, we set the
callback in a DMA descriptor to automatically get notified when DMA is
done. In the callback, we then use a completion to make sure the SD
access has already ended. Then, we proceed as before.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc.h | 2 +-
drivers/mmc/host/tmio_mmc_dma.c | 58 ++++++++++++++++++++++++-----------------
drivers/mmc/host/tmio_mmc_pio.c | 4 +--
3 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index e414670..f864be46 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -136,7 +136,7 @@ struct tmio_mmc_host {
bool force_pio;
struct dma_chan *chan_rx;
struct dma_chan *chan_tx;
- struct tasklet_struct dma_complete;
+ struct completion dma_dataend;
struct tasklet_struct dma_issue;
struct scatterlist bounce_sg;
u8 *bounce_buf;
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
index d157368..cef1eb4 100644
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ b/drivers/mmc/host/tmio_mmc_dma.c
@@ -43,6 +43,31 @@ void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
tmio_mmc_enable_dma(host, true);
}

+static void tmio_mmc_dma_callback(void *arg)
+{
+ struct tmio_mmc_host *host = arg;
+
+ wait_for_completion(&host->dma_dataend);
+
+ spin_lock_irq(&host->lock);
+
+ if (!host->data)
+ goto out;
+
+ if (host->data->flags & MMC_DATA_READ)
+ dma_unmap_sg(host->chan_rx->device->dev,
+ host->sg_ptr, host->sg_len,
+ DMA_FROM_DEVICE);
+ else
+ dma_unmap_sg(host->chan_tx->device->dev,
+ host->sg_ptr, host->sg_len,
+ DMA_TO_DEVICE);
+
+ tmio_mmc_do_data_irq(host);
+out:
+ spin_unlock_irq(&host->lock);
+}
+
static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
{
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
@@ -88,6 +113,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
DMA_DEV_TO_MEM, DMA_CTRL_ACK);

if (desc) {
+ reinit_completion(&host->dma_dataend);
+ desc->callback = tmio_mmc_dma_callback;
+ desc->callback_param = host;
+
cookie = dmaengine_submit(desc);
if (cookie < 0) {
desc = NULL;
@@ -162,6 +191,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
DMA_MEM_TO_DEV, DMA_CTRL_ACK);

if (desc) {
+ reinit_completion(&host->dma_dataend);
+ desc->callback = tmio_mmc_dma_callback;
+ desc->callback_param = host;
+
cookie = dmaengine_submit(desc);
if (cookie < 0) {
desc = NULL;
@@ -221,29 +254,6 @@ static void tmio_mmc_issue_tasklet_fn(unsigned long priv)
dma_async_issue_pending(chan);
}

-static void tmio_mmc_tasklet_fn(unsigned long arg)
-{
- struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
-
- spin_lock_irq(&host->lock);
-
- if (!host->data)
- goto out;
-
- if (host->data->flags & MMC_DATA_READ)
- dma_unmap_sg(host->chan_rx->device->dev,
- host->sg_ptr, host->sg_len,
- DMA_FROM_DEVICE);
- else
- dma_unmap_sg(host->chan_tx->device->dev,
- host->sg_ptr, host->sg_len,
- DMA_TO_DEVICE);
-
- tmio_mmc_do_data_irq(host);
-out:
- spin_unlock_irq(&host->lock);
-}
-
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
{
/* We can only either use DMA for both Tx and Rx or not use it at all */
@@ -306,7 +316,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
if (!host->bounce_buf)
goto ebouncebuf;

- tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host);
+ init_completion(&host->dma_dataend);
tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
}

diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index a152999..2fecd22 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -596,11 +596,11 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat)

if (done) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- tasklet_schedule(&host->dma_complete);
+ complete(&host->dma_dataend);
}
} else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) {
tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- tasklet_schedule(&host->dma_complete);
+ complete(&host->dma_dataend);
} else {
tmio_mmc_do_data_irq(host);
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP);
--
2.7.4


[PATCH 4.4.y-cip 58/83] mmc: tmio: discard obsolete SDIO irqs before enabling irqs

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit ee28981535f4261ed5d127ddf4d1a3f8778f520d upstream.

Before enabling SDIO irqs, clear the status bit, so we discard old and
stale interrupts. Needed to get two wireless cards working. Use the
newly introduced macro in all places.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc.h | 2 ++
drivers/mmc/host/tmio_mmc_pio.c | 13 +++++++++++--
2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index ba2838c..e414670 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -90,6 +90,8 @@
#define TMIO_SDIO_STAT_EXWT 0x8000
#define TMIO_SDIO_MASK_ALL 0xc007

+#define TMIO_SDIO_SETBITS_MASK 0x0006
+
/* Define some IRQ masks */
/* This is the mask used at reset by the chip */
#define TMIO_MASK_ALL 0x837f031d
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index a0b5db3..a152999 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -134,12 +134,21 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
struct tmio_mmc_host *host = mmc_priv(mmc);

if (enable && !host->sdio_irq_enabled) {
+ u16 sdio_status;
+
/* Keep device active while SDIO irq is enabled */
pm_runtime_get_sync(mmc_dev(mmc));
- host->sdio_irq_enabled = true;

+ host->sdio_irq_enabled = true;
host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
~TMIO_SDIO_STAT_IOIRQ;
+
+ /* Clear obsolete interrupts before enabling */
+ sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS) & ~TMIO_SDIO_MASK_ALL;
+ if (host->pdata->flags & TMIO_MMC_SDIO_STATUS_SETBITS)
+ sdio_status |= TMIO_SDIO_SETBITS_MASK;
+ sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status);
+
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
} else if (!enable && host->sdio_irq_enabled) {
host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
@@ -725,7 +734,7 @@ static bool __tmio_mmc_sdio_irq(int irq, void *devid)

sdio_status = status & ~TMIO_SDIO_MASK_ALL;
if (pdata->flags & TMIO_MMC_SDIO_STATUS_SETBITS)
- sdio_status |= 6;
+ sdio_status |= TMIO_SDIO_SETBITS_MASK;

sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status);

--
2.7.4


[PATCH 4.4.y-cip 57/83] mmc: host: tmio: SDIO_STATUS_QUIRK is rather SDIO_STATUS_SETBITS

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit 20dd03734cac41a0545dd24f5e81d8ff0c80874b upstream.

QUIRK sounds like there is something wrong, but actually there are just
some bits which need to be 1. Rename it to be more clear.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 6 ++----
drivers/mmc/host/tmio_mmc_pio.c | 2 +-
include/linux/mfd/tmio.h | 6 ++----
3 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 8e90670..a723550 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -640,10 +640,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
*/
mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL;

- /*
- * All SDHI need SDIO_INFO1 reserved bit
- */
- mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK;
+ /* All SDHI have SDIO status bits which must be 1 */
+ mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;

ret = tmio_mmc_host_probe(host, mmc_data);
if (ret < 0)
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 0a3f411..a0b5db3 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -724,7 +724,7 @@ static bool __tmio_mmc_sdio_irq(int irq, void *devid)
ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdio_irq_mask;

sdio_status = status & ~TMIO_SDIO_MASK_ALL;
- if (pdata->flags & TMIO_MMC_SDIO_STATUS_QUIRK)
+ if (pdata->flags & TMIO_MMC_SDIO_STATUS_SETBITS)
sdio_status |= 6;

sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status);
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index fba44ab..a1520d8 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -94,10 +94,8 @@
*/
#define TMIO_MMC_HAVE_CMD12_CTRL (1 << 7)

-/*
- * Some controllers needs to set 1 on SDIO status reserved bits
- */
-#define TMIO_MMC_SDIO_STATUS_QUIRK (1 << 8)
+/* Controller has some SDIO status bits which must be 1 */
+#define TMIO_MMC_SDIO_STATUS_SETBITS (1 << 8)

/*
* Some controllers have a 32-bit wide data port register
--
2.7.4


[PATCH 4.4.y-cip 56/83] mmc: host: tmio: refactor calls to sdio irq

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit e4f38eb18aedd098b3019e82df07f583a5cbcc58 upstream.

tmio_mmc_sdio_irq() is not used as a seperate irq handler anymore, so we
can make it similar to the other irq helper functions, namely:

* only give the host as argument function which is what it really needs
* prefix function name with __

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Acked-by: Simon Horman <horms+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc_pio.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 9fe6d65..0a3f411 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -709,7 +709,7 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host,
return false;
}

-static bool tmio_mmc_sdio_irq(int irq, void *devid)
+static bool __tmio_mmc_sdio_irq(int irq, void *devid)
{
struct tmio_mmc_host *host = devid;
struct mmc_host *mmc = host->mmc;
@@ -754,7 +754,7 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
if (__tmio_mmc_sdcard_irq(host, ireg, status))
return IRQ_HANDLED;

- if (tmio_mmc_sdio_irq(irq, devid))
+ if (__tmio_mmc_sdio_irq(irq, devid))
return IRQ_HANDLED;

return IRQ_NONE;
--
2.7.4


[PATCH 4.4.y-cip 55/83] mmc: host: tmio: disable clocks when unbinding

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit dfcba5ffca989749d1fc49d5b82a2d007b1295b7 upstream.

Create a helper function to disable clocks and use it in remove(), too.
Now, clk_summary in debugfs reports the clocks as disabled and
unprepared after unbinding.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Reviewed-by: Geert Uytterhoeven <geert+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc_pio.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 0f766f4..9fe6d65 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -903,6 +903,12 @@ static int tmio_mmc_clk_enable(struct tmio_mmc_host *host)
return host->clk_enable(host);
}

+static void tmio_mmc_clk_disable(struct tmio_mmc_host *host)
+{
+ if (host->clk_disable)
+ host->clk_disable(host);
+}
+
static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd)
{
struct mmc_host *mmc = host->mmc;
@@ -1287,6 +1293,8 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)

pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+
+ tmio_mmc_clk_disable(host);
}
EXPORT_SYMBOL(tmio_mmc_host_remove);

@@ -1301,8 +1309,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
if (host->clk_cache)
tmio_mmc_clk_stop(host);

- if (host->clk_disable)
- host->clk_disable(host);
+ tmio_mmc_clk_disable(host);

return 0;
}
--
2.7.4


[PATCH 4.4.y-cip 54/83] mmc: tmio: Remove redundant check of mmc->slot.cd_irq

Biju Das <biju.das@...>
 

From: Ulf Hansson <ulf.hansson@...>

commit efd7be7bfc8eb8942ba3dc319f323cfd0eda99e2 upstream.

To validate whether native hotplug needs to be used, the tmio driver checks
whether the mmc->slot.cd_irq has been successfully assigned.

This check is redundant at its current place in tmio_mmc_host_probe(), as
the mmc core assigns mmc->slot.cd_irq a valid value first when
mmc_gpiod_request_cd_irq() is called. Therefore, let's just remove the
check for now, as that also removes a layering violation of the tmio driver
accessing core specific data via ->slot.cd_irq.

Signed-off-by: Ulf Hansson <ulf.hansson@...>
Reviewed-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc_pio.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 4e38fcc..0f766f4 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -1178,8 +1178,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,

_host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
mmc->caps & MMC_CAP_NEEDS_POLL ||
- mmc->caps & MMC_CAP_NONREMOVABLE ||
- mmc->slot.cd_irq >= 0);
+ !mmc_card_is_removable(mmc));

/*
* On Gen2+, eMMC with NONREMOVABLE currently fails because native
--
2.7.4


[PATCH 4.4.y-cip 53/83] mmc: host: tmio: drop superfluous exit path

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit ad7014b3949b6c2b6ce46a546d6d204b5643e621 upstream.

The probe exit path on error does nothing since commit 94b110aff8679b
("mmc: tmio: add tmio_mmc_host_alloc/free()"), so we can bail out
immediately.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Reviewed-by: Simon Horman <horms+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc_pio.c | 20 ++++++--------------
1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 87f7aa7..4e38fcc 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -1146,7 +1146,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,

ret = mmc_of_parse(mmc);
if (ret < 0)
- goto host_free;
+ return ret;

_host->pdata = pdata;
platform_set_drvdata(pdev, mmc);
@@ -1156,14 +1156,12 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,

ret = tmio_mmc_init_ocr(_host);
if (ret < 0)
- goto host_free;
+ return ret;

_host->ctl = devm_ioremap(&pdev->dev,
res_ctl->start, resource_size(res_ctl));
- if (!_host->ctl) {
- ret = -ENOMEM;
- goto host_free;
- }
+ if (!_host->ctl)
+ return -ENOMEM;

tmio_mmc_ops.card_busy = _host->card_busy;
tmio_mmc_ops.start_signal_voltage_switch = _host->start_signal_voltage_switch;
@@ -1201,10 +1199,8 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
* Check the sanity of mmc->f_min to prevent tmio_mmc_set_clock() from
* looping forever...
*/
- if (mmc->f_min == 0) {
- ret = -EINVAL;
- goto host_free;
- }
+ if (mmc->f_min == 0)
+ return -EINVAL;

/*
* While using internal tmio hardware logic for card detection, we need
@@ -1269,10 +1265,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
}

return 0;
-
-host_free:
-
- return ret;
}
EXPORT_SYMBOL(tmio_mmc_host_probe);

--
2.7.4


[PATCH 4.4.y-cip 52/83] mmc: sh_mobile_sdhi: enable HS200

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit b1c95170f97ef19ff63a6da1eb2c70899186aecc upstream.

Setup tuning when the board is HS200 enabled.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index d851535..8e90670 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -650,7 +650,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
goto efree;

/* Enable tuning iff we have an SCC and a supported mode */
- if (of_data && of_data->scc_offset && host->mmc->caps & MMC_CAP_UHS_SDR104) {
+ if (of_data && of_data->scc_offset &&
+ (host->mmc->caps & MMC_CAP_UHS_SDR104 ||
+ host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) {
const struct sh_mobile_sdhi_scc *taps = of_data->taps;
bool hit = false;

--
2.7.4


[PATCH 4.4.y-cip 51/83] mmc: sh_mobile_sdhi: remove superfluous check in init_tuning

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit 7f9096f1c89ea698c22fde91285de2ef3eabd614 upstream.

The function will only be available if SDR104 was detected in probe,
so no need to check in the function itself again.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 3 ---
1 file changed, 3 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 59cc513..d851535 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -335,9 +335,6 @@ static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host)
{
struct sh_mobile_sdhi *priv;

- if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
- return 0;
-
priv = host_to_priv(host);

/* set sampling clock selection range */
--
2.7.4


[PATCH 4.4.y-cip 50/83] mmc: sh_mobile_sdhi: remove superfluous check in SCC error check

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit 03c5b0d90300fc725fc1fb644872b522483a2d7e upstream.

The function will only be available if SDR104 was detected in probe,
so no need to check in the function itself again.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 30956c7..59cc513 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -444,12 +444,7 @@ static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)

static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host)
{
- struct sh_mobile_sdhi *priv;
-
- if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
- return 0;
-
- priv = host_to_priv(host);
+ struct sh_mobile_sdhi *priv = host_to_priv(host);

/* Check SCC error */
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
--
2.7.4


[PATCH 4.4.y-cip 49/83] mmc: sh_mobile_sdhi: improve prerequisites for tuning

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit e831ead3b3ddc4227cef10dc63d919fd7242d7b8 upstream.

Prerequisites for tuning are the same as for hw_reset. We need an SCC
and a supported mode. Populate the tuning related functions only when
those conditions are met. This also removes a tiny race window.
Previously, the functions were populated when the SCC offset was not
initialized which could have led to an OOPS.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index d3d1db0..30956c7 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -617,11 +617,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
host->card_busy = sh_mobile_sdhi_card_busy;
host->start_signal_voltage_switch =
sh_mobile_sdhi_start_signal_voltage_switch;
- host->init_tuning = sh_mobile_sdhi_init_tuning;
- host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
- host->select_tuning = sh_mobile_sdhi_select_tuning;
- host->check_scc_error = sh_mobile_sdhi_check_scc_error;
- host->hw_reset = sh_mobile_sdhi_hw_reset;
}

/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@@ -662,6 +657,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
if (ret < 0)
goto efree;

+ /* Enable tuning iff we have an SCC and a supported mode */
if (of_data && of_data->scc_offset && host->mmc->caps & MMC_CAP_UHS_SDR104) {
const struct sh_mobile_sdhi_scc *taps = of_data->taps;
bool hit = false;
@@ -681,6 +677,11 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");

priv->scc_ctl = host->ctl + of_data->scc_offset;
+ host->init_tuning = sh_mobile_sdhi_init_tuning;
+ host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
+ host->select_tuning = sh_mobile_sdhi_select_tuning;
+ host->check_scc_error = sh_mobile_sdhi_check_scc_error;
+ host->hw_reset = sh_mobile_sdhi_hw_reset;
}

i = 0;
--
2.7.4


[PATCH 4.4.y-cip 48/83] mmc: sh_mobile_sdhi: remove superfluous check in hw_reset

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit 97c64b2cd57608f7064810780056d17944f49128 upstream.

The capability for HW_RESET is only activated if SDR104 is present, so
no need to check for SDR104 in the function itself again.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 3 ---
1 file changed, 3 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 9bf1f5e..d3d1db0 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -468,9 +468,6 @@ static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
{
struct sh_mobile_sdhi *priv;

- if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
- return;
-
priv = host_to_priv(host);

/* Reset SCC */
--
2.7.4


[PATCH 4.4.y-cip 47/83] mmc: sh_mobile_sdhi: improve prerequisite for hw_reset

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit 6ade9a2c2da855ff38e74c4298976400feca968e upstream.

We need a SCC unit for hw_reset. Those units can only be described in
of_data. So, of_data and a valid SCC offset are prerequisites for
enabling the hw_reset capability. Merge the two 'if' conditions into one
and add a check for an scc offset.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Reviewed-by: Geert Uytterhoeven <geert+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 30 ++++++++++++++----------------
1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 9af62dd..9bf1f5e 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -665,27 +665,25 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
if (ret < 0)
goto efree;

- if (host->mmc->caps & MMC_CAP_UHS_SDR104) {
+ if (of_data && of_data->scc_offset && host->mmc->caps & MMC_CAP_UHS_SDR104) {
+ const struct sh_mobile_sdhi_scc *taps = of_data->taps;
+ bool hit = false;
+
host->mmc->caps |= MMC_CAP_HW_RESET;

- if (of_data) {
- const struct sh_mobile_sdhi_scc *taps = of_data->taps;
- bool hit = false;
-
- for (i = 0; i < of_data->taps_num; i++) {
- if (taps[i].clk_rate == 0 ||
- taps[i].clk_rate == host->mmc->f_max) {
- host->scc_tappos = taps->tap;
- hit = true;
- break;
- }
+ for (i = 0; i < of_data->taps_num; i++) {
+ if (taps[i].clk_rate == 0 ||
+ taps[i].clk_rate == host->mmc->f_max) {
+ host->scc_tappos = taps->tap;
+ hit = true;
+ break;
}
+ }

- if (!hit)
- dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
+ if (!hit)
+ dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");

- priv->scc_ctl = host->ctl + of_data->scc_offset;
- }
+ priv->scc_ctl = host->ctl + of_data->scc_offset;
}

i = 0;
--
2.7.4


[PATCH 4.4.y-cip 46/83] mmc: sh_mobile_sdhi: simplify accessing DT data

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit dc9f1a8d790ee766c47eca163261225680691e64 upstream.

By using the helper of_device_get_match_data(), we can skip some
checking and make the code simpler.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Reviewed-by: Geert Uytterhoeven <geert+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index d1ec75c..9af62dd 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -555,8 +555,7 @@ static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)

static int sh_mobile_sdhi_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id =
- of_match_device(sh_mobile_sdhi_of_match, &pdev->dev);
+ const struct sh_mobile_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev);
struct sh_mobile_sdhi *priv;
struct tmio_mmc_data *mmc_data;
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
@@ -597,9 +596,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
goto eprobe;
}

- if (of_id && of_id->data) {
- const struct sh_mobile_sdhi_of_data *of_data = of_id->data;

+ if (of_data) {
mmc_data->flags |= of_data->tmio_flags;
mmc_data->ocr_mask = of_data->tmio_ocr_mask;
mmc_data->capabilities |= of_data->capabilities;
@@ -670,14 +668,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
if (host->mmc->caps & MMC_CAP_UHS_SDR104) {
host->mmc->caps |= MMC_CAP_HW_RESET;

- if (of_id && of_id->data) {
- const struct sh_mobile_sdhi_of_data *of_data;
- const struct sh_mobile_sdhi_scc *taps;
+ if (of_data) {
+ const struct sh_mobile_sdhi_scc *taps = of_data->taps;
bool hit = false;

- of_data = of_id->data;
- taps = of_data->taps;
-
for (i = 0; i < of_data->taps_num; i++) {
if (taps[i].clk_rate == 0 ||
taps[i].clk_rate == host->mmc->f_max) {
--
2.7.4


[PATCH 4.4.y-cip 45/83] mmc: tmio: use SDIO master interrupt bit only when allowed

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit c51ff6c6180e76a1ba96aef799a9c41aa80fcc95 upstream.

The master bit to enable SDIO interrupts can only be accessed if
SCLKDIVEN bit allows that. However, the core uses the SDIO enable
callback at times when SCLKDIVEN forbids the change. This leads to
"timeout waiting for SD bus idle" messages.

We now activate the master bit in probe once if SDIO is supported. IRQ
en-/disabling will be done now by the individual IRQ enablement bits
only.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Reviewed-by: Yasushi SHOJI <yashi@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc_pio.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index fee72a9..87f7aa7 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -140,12 +140,10 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)

host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
~TMIO_SDIO_STAT_IOIRQ;
- sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
} else if (!enable && host->sdio_irq_enabled) {
host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
- sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);

host->sdio_irq_enabled = false;
pm_runtime_mark_last_busy(mmc_dev(mmc));
@@ -1235,7 +1233,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
_host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
sd_ctrl_write16(_host, CTL_SDIO_IRQ_MASK, _host->sdio_irq_mask);
- sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0000);
+ sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0001);
}

spin_lock_init(&_host->lock);
@@ -1283,6 +1281,9 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
struct platform_device *pdev = host->pdev;
struct mmc_host *mmc = host->mmc;

+ if (host->pdata->flags & TMIO_MMC_SDIO_IRQ)
+ sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
+
if (!host->native_hotplug)
pm_runtime_get_sync(&pdev->dev);

--
2.7.4


[PATCH 4.4.y-cip 44/83] mmc: tmio: remove SDIO from TODO list

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit e726e8c959fc735473f248e142de4d4f77ed342b upstream.

We surely have SDIO support by now :)

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Reviewed-by: Simon Horman <horms+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc_pio.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 3a69ff5..fee72a9 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -22,7 +22,6 @@
* TODO:
* Investigate using a workqueue for PIO transfers
* Eliminate FIXMEs
- * SDIO support
* Better Power management
* Handle MMC errors better
* double buffer support
--
2.7.4


[PATCH 4.4.y-cip 43/83] mmc: tmio: fix wrong bitmask for SDIO irqs

Biju Das <biju.das@...>
 

From: Wolfram Sang <wsa+renesas@...>

commit 0c4bf5beff79fd32c5a3b2b511ed6527861ada18 upstream.

Commit 7729c7a232a953 ("mmc: tmio: Provide separate interrupt handlers")
refactored the sdio irq handler and wrongly used the mask for SD irqs,
not for SDIO irqs. This doesn't really matter in practice because both
values keep the only interrupt we are interested in. But still, this is
wrong and wants to be fixed.

Signed-off-by: Wolfram Sang <wsa+renesas@...>
Reviewed-by: Simon Horman <horms+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc_pio.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 37703bf..3a69ff5 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -724,7 +724,7 @@ static bool tmio_mmc_sdio_irq(int irq, void *devid)
return false;

status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
- ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
+ ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdio_irq_mask;

sdio_status = status & ~TMIO_SDIO_MASK_ALL;
if (pdata->flags & TMIO_MMC_SDIO_STATUS_QUIRK)
--
2.7.4


[PATCH 4.4.y-cip 42/83] mmc: sh_mobile_sdhi: Add tuning support

Biju Das <biju.das@...>
 

From: Simon Horman <horms+renesas@...>

commit 06f438dd389a699d27585f2a4d3685fd1ce05a75 upstream.

Add tuning support for use with SDR104 mode
This includes adding support for the sampling clock controller (SCC).

Based on work by Ai Kyuse.

Cc: Ai Kyuse <ai.kyuse.uw@...>
Signed-off-by: Simon Horman <horms+renesas@...>
Acked-by: Wolfram Sang <wsa+renesas@...>
Tested-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/sh_mobile_sdhi.c | 265 +++++++++++++++++++++++++++++++++++++-
1 file changed, 264 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 9124246..d1ec75c 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -47,6 +47,11 @@

#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)

+struct sh_mobile_sdhi_scc {
+ unsigned long clk_rate; /* clock rate for SDR104 */
+ u32 tap; /* sampling clock position for SDR104 */
+};
+
struct sh_mobile_sdhi_of_data {
unsigned long tmio_flags;
u32 tmio_ocr_mask;
@@ -55,6 +60,9 @@ struct sh_mobile_sdhi_of_data {
enum dma_slave_buswidth dma_buswidth;
dma_addr_t dma_rx_offset;
unsigned bus_shift;
+ int scc_offset;
+ struct sh_mobile_sdhi_scc *taps;
+ int taps_num;
};

static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
@@ -69,12 +77,35 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
};

+/* Definitions for sampling clocks */
+static struct sh_mobile_sdhi_scc rcar_gen2_scc_taps[] = {
+ {
+ .clk_rate = 156000000,
+ .tap = 0x00000703,
+ },
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
.dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
.dma_rx_offset = 0x2000,
+ .scc_offset = 0x0300,
+ .taps = rcar_gen2_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
+};
+
+/* Definitions for sampling clocks */
+static struct sh_mobile_sdhi_scc rcar_gen3_scc_taps[] = {
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
};

static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
@@ -82,6 +113,9 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
.capabilities = MMC_CAP_SD_HIGHSPEED,
.bus_shift = 2,
+ .scc_offset = 0x1000,
+ .taps = rcar_gen3_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
};

static const struct of_device_id sh_mobile_sdhi_of_match[] = {
@@ -109,6 +143,7 @@ struct sh_mobile_sdhi {
struct tmio_mmc_dma dma_priv;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default, *pins_uhs;
+ void __iomem *scc_ctl;
};

static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
@@ -263,6 +298,201 @@ static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
return 0;
}

+/* SCC registers */
+#define SH_MOBILE_SDHI_SCC_DTCNTL 0x000
+#define SH_MOBILE_SDHI_SCC_TAPSET 0x002
+#define SH_MOBILE_SDHI_SCC_DT2FF 0x004
+#define SH_MOBILE_SDHI_SCC_CKSEL 0x006
+#define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008
+#define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A
+
+/* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */
+#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0)
+#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16
+#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff
+
+/* Definitions for values the SH_MOBILE_SDHI_SCC_CKSEL register */
+#define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSCNTL register */
+#define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ register */
+#define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2)
+
+static inline u32 sd_scc_read32(struct tmio_mmc_host *host,
+ struct sh_mobile_sdhi *priv, int addr)
+{
+ return readl(priv->scc_ctl + (addr << host->bus_shift));
+}
+
+static inline void sd_scc_write32(struct tmio_mmc_host *host,
+ struct sh_mobile_sdhi *priv,
+ int addr, u32 val)
+{
+ writel(val, priv->scc_ctl + (addr << host->bus_shift));
+}
+
+static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host)
+{
+ struct sh_mobile_sdhi *priv;
+
+ if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
+ return 0;
+
+ priv = host_to_priv(host);
+
+ /* set sampling clock selection range */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
+ 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT);
+
+ /* Initialize SCC */
+ sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, 0x0);
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
+ SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN |
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL));
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
+ SH_MOBILE_SDHI_SCC_CKSEL_DTSEL |
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
+ ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, host->scc_tappos);
+
+ /* Read TAPNUM */
+ return (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL) >>
+ SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) &
+ SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK;
+}
+
+static void sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host,
+ unsigned long tap)
+{
+ struct sh_mobile_sdhi *priv = host_to_priv(host);
+
+ /* Set sampling clock position */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap);
+}
+
+#define SH_MOBILE_SDHI_MAX_TAP 3
+
+static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)
+{
+ struct sh_mobile_sdhi *priv = host_to_priv(host);
+ unsigned long tap_cnt; /* counter of tuning success */
+ unsigned long tap_set; /* tap position */
+ unsigned long tap_start;/* start position of tuning success */
+ unsigned long tap_end; /* end position of tuning success */
+ unsigned long ntap; /* temporary counter of tuning success */
+ unsigned long i;
+
+ /* Clear SCC_RVSREQ */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+
+ /*
+ * Find the longest consecutive run of successful probes. If that
+ * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the
+ * center index as the tap.
+ */
+ tap_cnt = 0;
+ ntap = 0;
+ tap_start = 0;
+ tap_end = 0;
+ for (i = 0; i < host->tap_num * 2; i++) {
+ if (test_bit(i, host->taps))
+ ntap++;
+ else {
+ if (ntap > tap_cnt) {
+ tap_start = i - ntap;
+ tap_end = i - 1;
+ tap_cnt = ntap;
+ }
+ ntap = 0;
+ }
+ }
+
+ if (ntap > tap_cnt) {
+ tap_start = i - ntap;
+ tap_end = i - 1;
+ tap_cnt = ntap;
+ }
+
+ if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP)
+ tap_set = (tap_start + tap_end) / 2 % host->tap_num;
+ else
+ return -EIO;
+
+ /* Set SCC */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap_set);
+
+ /* Enable auto re-tuning */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
+ SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN |
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+ return 0;
+}
+
+
+static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host)
+{
+ struct sh_mobile_sdhi *priv;
+
+ if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
+ return 0;
+
+ priv = host_to_priv(host);
+
+ /* Check SCC error */
+ if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
+ SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &&
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) &
+ SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
+ /* Clear SCC error */
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
+ return true;
+ }
+
+ return false;
+}
+
+static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
+{
+ struct sh_mobile_sdhi *priv;
+
+ if (!(host->mmc->caps & MMC_CAP_UHS_SDR104))
+ return;
+
+ priv = host_to_priv(host);
+
+ /* Reset SCC */
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
+ ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));
+
+ sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
+ sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
+ ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
+ ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+}
+
static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
{
int timeout = 1000;
@@ -332,7 +562,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
struct tmio_mmc_host *host;
struct resource *res;
- int irq, ret, i = 0;
+ int irq, ret, i;
struct tmio_mmc_dma *dma_priv;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -392,6 +622,11 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
host->card_busy = sh_mobile_sdhi_card_busy;
host->start_signal_voltage_switch =
sh_mobile_sdhi_start_signal_voltage_switch;
+ host->init_tuning = sh_mobile_sdhi_init_tuning;
+ host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
+ host->select_tuning = sh_mobile_sdhi_select_tuning;
+ host->check_scc_error = sh_mobile_sdhi_check_scc_error;
+ host->hw_reset = sh_mobile_sdhi_hw_reset;
}

/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@@ -432,6 +667,34 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
if (ret < 0)
goto efree;

+ if (host->mmc->caps & MMC_CAP_UHS_SDR104) {
+ host->mmc->caps |= MMC_CAP_HW_RESET;
+
+ if (of_id && of_id->data) {
+ const struct sh_mobile_sdhi_of_data *of_data;
+ const struct sh_mobile_sdhi_scc *taps;
+ bool hit = false;
+
+ of_data = of_id->data;
+ taps = of_data->taps;
+
+ for (i = 0; i < of_data->taps_num; i++) {
+ if (taps[i].clk_rate == 0 ||
+ taps[i].clk_rate == host->mmc->f_max) {
+ host->scc_tappos = taps->tap;
+ hit = true;
+ break;
+ }
+ }
+
+ if (!hit)
+ dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
+
+ priv->scc_ctl = host->ctl + of_data->scc_offset;
+ }
+ }
+
+ i = 0;
while (1) {
irq = platform_get_irq(pdev, i);
if (irq < 0)
--
2.7.4


[PATCH 4.4.y-cip 41/83] mmc: tmio: Add tuning support

Biju Das <biju.das@...>
 

From: Ai Kyuse <ai.kyuse.uw@...>

commit 4f11997773b6b452b5a0d620c5ac5050e75c227e upstream.

Add tuning support for use with SDR104 mode

Signed-off-by: Ai Kyuse <ai.kyuse.uw@...>
Signed-off-by: Simon Horman <horms+renesas@...>
Acked-by: Wolfram Sang <wsa+renesas@...>
Tested-by: Wolfram Sang <wsa+renesas@...>
Signed-off-by: Ulf Hansson <ulf.hansson@...>
Signed-off-by: Biju Das <biju.das@...>
---
drivers/mmc/host/tmio_mmc.h | 14 ++++++++++
drivers/mmc/host/tmio_mmc_pio.c | 62 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+)

diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 8b4869e..ba2838c 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -153,6 +153,7 @@ struct tmio_mmc_host {
struct mutex ios_lock; /* protect set_ios() context */
bool native_hotplug;
bool sdio_irq_enabled;
+ u32 scc_tappos;

/* Mandatory callback */
int (*clk_enable)(struct tmio_mmc_host *host);
@@ -168,6 +169,19 @@ struct tmio_mmc_host {
struct mmc_ios *ios);
int (*write16_hook)(struct tmio_mmc_host *host, int addr);
void (*hw_reset)(struct tmio_mmc_host *host);
+ void (*prepare_tuning)(struct tmio_mmc_host *host, unsigned long tap);
+ bool (*check_scc_error)(struct tmio_mmc_host *host);
+
+ /*
+ * Mandatory callback for tuning to occur which is optional for SDR50
+ * and mandatory for SDR104.
+ */
+ unsigned int (*init_tuning)(struct tmio_mmc_host *host);
+ int (*select_tuning)(struct tmio_mmc_host *host);
+
+ /* Tuning values: 1 for success, 0 for failure */
+ DECLARE_BITMAP(taps, BITS_PER_BYTE * sizeof(long));
+ unsigned int tap_num;
};

struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev);
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 4bb0553..37703bf 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -36,6 +36,7 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/mfd/tmio.h>
+#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
@@ -298,6 +299,9 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
if (mrq->cmd->error || (mrq->data && mrq->data->error))
tmio_mmc_abort_dma(host);

+ if (host->check_scc_error)
+ host->check_scc_error(host);
+
mmc_request_done(host->mmc, mrq);
}

@@ -800,6 +804,55 @@ static void tmio_mmc_hw_reset(struct mmc_host *mmc)
host->hw_reset(host);
}

+static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ int i, ret = 0;
+
+ if (!host->tap_num) {
+ if (!host->init_tuning || !host->select_tuning)
+ /* Tuning is not supported */
+ goto out;
+
+ host->tap_num = host->init_tuning(host);
+ if (!host->tap_num)
+ /* Tuning is not supported */
+ goto out;
+ }
+
+ if (host->tap_num * 2 >= sizeof(host->taps) * BITS_PER_BYTE) {
+ dev_warn_once(&host->pdev->dev,
+ "Too many taps, skipping tuning. Please consider updating size of taps field of tmio_mmc_host\n");
+ goto out;
+ }
+
+ bitmap_zero(host->taps, host->tap_num * 2);
+
+ /* Issue CMD19 twice for each tap */
+ for (i = 0; i < 2 * host->tap_num; i++) {
+ if (host->prepare_tuning)
+ host->prepare_tuning(host, i % host->tap_num);
+
+ ret = mmc_send_tuning(mmc, opcode, NULL);
+ if (ret && ret != -EILSEQ)
+ goto out;
+ if (ret == 0)
+ set_bit(i, host->taps);
+
+ mdelay(1);
+ }
+
+ ret = host->select_tuning(host);
+
+out:
+ if (ret < 0) {
+ dev_warn(&host->pdev->dev, "Tuning procedure failed\n");
+ tmio_mmc_hw_reset(mmc);
+ }
+
+ return ret;
+}
+
/* Process requests from the MMC layer */
static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
@@ -1017,6 +1070,7 @@ static struct mmc_host_ops tmio_mmc_ops = {
.enable_sdio_irq = tmio_mmc_enable_sdio_irq,
.multi_io_quirk = tmio_multi_io_quirk,
.hw_reset = tmio_mmc_hw_reset,
+ .execute_tuning = tmio_mmc_execute_tuning,
};

static int tmio_mmc_init_ocr(struct tmio_mmc_host *host)
@@ -1263,6 +1317,11 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
}
EXPORT_SYMBOL(tmio_mmc_host_runtime_suspend);

+static bool tmio_mmc_can_retune(struct tmio_mmc_host *host)
+{
+ return host->tap_num && mmc_can_retune(host->mmc);
+}
+
int tmio_mmc_host_runtime_resume(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -1276,6 +1335,9 @@ int tmio_mmc_host_runtime_resume(struct device *dev)

tmio_mmc_enable_dma(host, true);

+ if (tmio_mmc_can_retune(host) && host->select_tuning(host))
+ dev_warn(&host->pdev->dev, "Tuning selection failed\n");
+
return 0;
}
EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
--
2.7.4

6481 - 6500 of 10124