* [PATCH 1/9] mmc: sdhci-of-esdhc: add peripheral clock support
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
2017-03-02 9:47 ` [PATCH 2/9] mmc: sdhci: add a callback for signal voltage switching Yangbo Lu
` (7 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
eSDHC could select peripheral clock or platform clock as clock source by
the PCS bit of eSDHC Control Register, and this bit couldn't be reset by
software reset for all. In default, the platform clock is used. But we have
to use peripheral clock since it has a higher frequency to support eMMC
HS200 mode and SD UHS-I mode. This patch is to add peripheral clock support
and use it instead of platform clock if it's declared in eSDHC dts node.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/mmc/host/sdhci-esdhc.h | 1 +
drivers/mmc/host/sdhci-of-esdhc.c | 70 +++++++++++++++++++++++++++++++++++++--
2 files changed, 69 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index ece8b37..5343fc0 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -54,6 +54,7 @@
/* Control Register for DMA transfer */
#define ESDHC_DMA_SYSCTL 0x40c
+#define ESDHC_PERIPHERAL_CLK_SEL 0x00080000
#define ESDHC_DMA_SNOOP 0x00000040
#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index d3aa671..84865b0 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/sys_soc.h>
+#include <linux/clk.h>
#include <linux/mmc/host.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -30,6 +31,7 @@ struct sdhci_esdhc {
u8 vendor_ver;
u8 spec_ver;
bool quirk_incorrect_hostver;
+ unsigned int peripheral_clock;
};
/**
@@ -414,15 +416,25 @@ static int esdhc_of_enable_dma(struct sdhci_host *host)
static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
- return pltfm_host->clock;
+ if (esdhc->peripheral_clock)
+ return esdhc->peripheral_clock;
+ else
+ return pltfm_host->clock;
}
static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
+ unsigned int clock;
- return pltfm_host->clock / 256 / 16;
+ if (esdhc->peripheral_clock)
+ clock = esdhc->peripheral_clock;
+ else
+ clock = pltfm_host->clock;
+ return clock / 256 / 16;
}
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
@@ -512,6 +524,33 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
sdhci_writel(host, ctrl, ESDHC_PROCTL);
}
+static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
+{
+ u32 val;
+ u32 timeout;
+
+ val = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+
+ if (enable)
+ val |= ESDHC_CLOCK_SDCLKEN;
+ else
+ val &= ~ESDHC_CLOCK_SDCLKEN;
+
+ sdhci_writel(host, val, ESDHC_SYSTEM_CONTROL);
+
+ timeout = 20;
+ val = ESDHC_CLOCK_STABLE;
+ while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) {
+ if (timeout == 0) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ break;
+ }
+ timeout--;
+ mdelay(1);
+ }
+}
+
static void esdhc_reset(struct sdhci_host *host, u8 mask)
{
sdhci_reset(host, mask);
@@ -610,6 +649,9 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_esdhc *esdhc;
+ struct device_node *np;
+ struct clk *clk;
+ u32 val;
u16 host_ver;
pltfm_host = sdhci_priv(host);
@@ -623,6 +665,30 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
esdhc->quirk_incorrect_hostver = true;
else
esdhc->quirk_incorrect_hostver = false;
+
+ np = pdev->dev.of_node;
+ clk = of_clk_get(np, 0);
+ if (!IS_ERR(clk)) {
+ /*
+ * esdhc->peripheral_clock would be assigned with a value
+ * which is eSDHC base clock when use periperal clock.
+ * For ls1046a, the clock value got by common clk API is
+ * peripheral clock while the eSDHC base clock is 1/2
+ * peripheral clock.
+ */
+ if (of_device_is_compatible(np, "fsl,ls1046a-esdhc"))
+ esdhc->peripheral_clock = clk_get_rate(clk) / 2;
+ else
+ esdhc->peripheral_clock = clk_get_rate(clk);
+ }
+
+ if (esdhc->peripheral_clock) {
+ esdhc_clock_enable(host, false);
+ val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+ val |= ESDHC_PERIPHERAL_CLK_SEL;
+ sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
+ esdhc_clock_enable(host, true);
+ }
}
static int sdhci_esdhc_probe(struct platform_device *pdev)
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/9] mmc: sdhci: add a callback for signal voltage switching
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
2017-03-02 9:47 ` [PATCH 1/9] mmc: sdhci-of-esdhc: add peripheral clock support Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
2017-03-02 14:19 ` Adrian Hunter
2017-03-02 9:47 ` [PATCH 3/9] mmc: sdhci-of-esdhc: add support for signal voltage switch Yangbo Lu
` (6 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
Add a callback for signal voltage switching to let host driver
switch signal voltage in its own way.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/mmc/host/sdhci.c | 6 ++++++
drivers/mmc/host/sdhci.h | 2 ++
2 files changed, 8 insertions(+)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 6fdd7a7..3c9a924 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1852,6 +1852,12 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
if (host->version < SDHCI_SPEC_300)
return 0;
+ if (host->ops->start_signal_voltage_switch) {
+ ret = host->ops->start_signal_voltage_switch(
+ host, ios->signal_voltage);
+ return ret;
+ }
+
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
switch (ios->signal_voltage) {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index edf3adf..04af687 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -566,6 +566,8 @@ struct sdhci_ops {
struct mmc_card *card,
unsigned int max_dtr, int host_drv,
int card_drv, int *drv_type);
+ int (*start_signal_voltage_switch)(struct sdhci_host *host,
+ unsigned char signal_voltage);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/9] mmc: sdhci: add a callback for signal voltage switching
2017-03-02 9:47 ` [PATCH 2/9] mmc: sdhci: add a callback for signal voltage switching Yangbo Lu
@ 2017-03-02 14:19 ` Adrian Hunter
2017-03-03 7:38 ` Y.B. Lu
0 siblings, 1 reply; 14+ messages in thread
From: Adrian Hunter @ 2017-03-02 14:19 UTC (permalink / raw)
To: linux-arm-kernel
On 02/03/17 11:47, Yangbo Lu wrote:
> Add a callback for signal voltage switching to let host driver
> switch signal voltage in its own way.
That is not how we do things now. Please just replace the host operation
instead e.g.
host->mmc_host_ops.start_signal_voltage_switch =
esdhc_signal_voltage_switch;
>
> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> ---
> drivers/mmc/host/sdhci.c | 6 ++++++
> drivers/mmc/host/sdhci.h | 2 ++
> 2 files changed, 8 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 6fdd7a7..3c9a924 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -1852,6 +1852,12 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> if (host->version < SDHCI_SPEC_300)
> return 0;
>
> + if (host->ops->start_signal_voltage_switch) {
> + ret = host->ops->start_signal_voltage_switch(
> + host, ios->signal_voltage);
> + return ret;
> + }
> +
> ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>
> switch (ios->signal_voltage) {
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index edf3adf..04af687 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -566,6 +566,8 @@ struct sdhci_ops {
> struct mmc_card *card,
> unsigned int max_dtr, int host_drv,
> int card_drv, int *drv_type);
> + int (*start_signal_voltage_switch)(struct sdhci_host *host,
> + unsigned char signal_voltage);
> };
>
> #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/9] mmc: sdhci: add a callback for signal voltage switching
2017-03-02 14:19 ` Adrian Hunter
@ 2017-03-03 7:38 ` Y.B. Lu
0 siblings, 0 replies; 14+ messages in thread
From: Y.B. Lu @ 2017-03-03 7:38 UTC (permalink / raw)
To: linux-arm-kernel
> -----Original Message-----
> From: Adrian Hunter [mailto:adrian.hunter at intel.com]
> Sent: Thursday, March 02, 2017 10:19 PM
> To: Y.B. Lu; linux-mmc at vger.kernel.org; ulf.hansson at linaro.org; Rob
> Herring; Mark Rutland; Catalin Marinas; Will Deacon
> Cc: devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> Xiaobo Xie
> Subject: Re: [PATCH 2/9] mmc: sdhci: add a callback for signal voltage
> switching
>
> On 02/03/17 11:47, Yangbo Lu wrote:
> > Add a callback for signal voltage switching to let host driver switch
> > signal voltage in its own way.
>
> That is not how we do things now. Please just replace the host operation
> instead e.g.
>
> host->mmc_host_ops.start_signal_voltage_switch =
> esdhc_signal_voltage_switch;
>
[Lu Yangbo-B47093] Hi Adrian, your method is great! I will use this in v2.
Thanks.
>
>
> >
> > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> > ---
> > drivers/mmc/host/sdhci.c | 6 ++++++
> > drivers/mmc/host/sdhci.h | 2 ++
> > 2 files changed, 8 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index
> > 6fdd7a7..3c9a924 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -1852,6 +1852,12 @@ static int
> sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> > if (host->version < SDHCI_SPEC_300)
> > return 0;
> >
> > + if (host->ops->start_signal_voltage_switch) {
> > + ret = host->ops->start_signal_voltage_switch(
> > + host, ios->signal_voltage);
> > + return ret;
> > + }
> > +
> > ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> >
> > switch (ios->signal_voltage) {
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index
> > edf3adf..04af687 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -566,6 +566,8 @@ struct sdhci_ops {
> > struct mmc_card *card,
> > unsigned int max_dtr, int host_drv,
> > int card_drv, int *drv_type);
> > + int (*start_signal_voltage_switch)(struct sdhci_host *host,
> > + unsigned char signal_voltage);
> > };
> >
> > #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> >
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 3/9] mmc: sdhci-of-esdhc: add support for signal voltage switch
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
2017-03-02 9:47 ` [PATCH 1/9] mmc: sdhci-of-esdhc: add peripheral clock support Yangbo Lu
2017-03-02 9:47 ` [PATCH 2/9] mmc: sdhci: add a callback for signal voltage switching Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
2017-03-02 9:47 ` [PATCH 4/9] mmc: sdhci: add a callback for using tuning block Yangbo Lu
` (5 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
eSDHC supports signal voltage switch from 3.3v to 1.8v by
eSDHC_PROCTL[VOLT_SEL] bit. This bit changes the value of output
signal SDHC_VS, and there must be a control circuit out of eSDHC
to change the signal voltage according to SDHC_VS output signal.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/mmc/host/sdhci-esdhc.h | 1 +
drivers/mmc/host/sdhci-of-esdhc.c | 65 +++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 5343fc0..6869567 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -37,6 +37,7 @@
/* Protocol Control Register */
#define ESDHC_PROCTL 0x28
+#define ESDHC_VOLT_SEL 0x00000400
#define ESDHC_CTRL_4BITBUS (0x1 << 1)
#define ESDHC_CTRL_8BITBUS (0x2 << 1)
#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 84865b0..c2619f1 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/sys_soc.h>
@@ -559,6 +560,68 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
}
+/* The SCFG, Supplemental Configuration Unit, provides SoC specific
+ * configuration and status registers for the device. There is a
+ * SDHC IO VSEL control register on SCFG for some platforms. It's
+ * used to support SDHC IO voltage switching.
+ */
+static const struct of_device_id scfg_device_ids[] = {
+ { .compatible = "fsl,t1040-scfg", },
+ { .compatible = "fsl,ls1012a-scfg", },
+ { .compatible = "fsl,ls1046a-scfg", },
+ {}
+};
+
+/* SDHC IO VSEL control register definition */
+#define SCFG_SDHCIOVSELCR 0x408
+#define SDHCIOVSELCR_TGLEN 0x80000000
+#define SDHCIOVSELCR_VSELVAL 0x60000000
+#define SDHCIOVSELCR_SDHC_VS 0x00000001
+
+static int esdhc_signal_voltage_switch(struct sdhci_host *host,
+ unsigned char signal_voltage)
+{
+ struct device_node *scfg_node;
+ void __iomem *scfg_base = NULL;
+ u32 sdhciovselcr;
+ u32 val;
+
+ val = sdhci_readl(host, ESDHC_PROCTL);
+
+ switch (signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ val &= ~ESDHC_VOLT_SEL;
+ sdhci_writel(host, val, ESDHC_PROCTL);
+ return 0;
+ case MMC_SIGNAL_VOLTAGE_180:
+ scfg_node = of_find_matching_node(NULL, scfg_device_ids);
+ if (scfg_node)
+ scfg_base = of_iomap(scfg_node, 0);
+ if (scfg_base) {
+ sdhciovselcr = SDHCIOVSELCR_TGLEN |
+ SDHCIOVSELCR_VSELVAL;
+ iowrite32be(sdhciovselcr,
+ scfg_base + SCFG_SDHCIOVSELCR);
+
+ val |= ESDHC_VOLT_SEL;
+ sdhci_writel(host, val, ESDHC_PROCTL);
+ mdelay(5);
+
+ sdhciovselcr = SDHCIOVSELCR_TGLEN |
+ SDHCIOVSELCR_SDHC_VS;
+ iowrite32be(sdhciovselcr,
+ scfg_base + SCFG_SDHCIOVSELCR);
+ iounmap(scfg_base);
+ } else {
+ val |= ESDHC_VOLT_SEL;
+ sdhci_writel(host, val, ESDHC_PROCTL);
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
#ifdef CONFIG_PM_SLEEP
static u32 esdhc_proctl;
static int esdhc_of_suspend(struct device *dev)
@@ -603,6 +666,7 @@ static const struct sdhci_ops sdhci_esdhc_be_ops = {
.set_bus_width = esdhc_pltfm_set_bus_width,
.reset = esdhc_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
+ .start_signal_voltage_switch = esdhc_signal_voltage_switch,
};
static const struct sdhci_ops sdhci_esdhc_le_ops = {
@@ -620,6 +684,7 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = {
.set_bus_width = esdhc_pltfm_set_bus_width,
.reset = esdhc_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
+ .start_signal_voltage_switch = esdhc_signal_voltage_switch,
};
static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = {
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/9] mmc: sdhci: add a callback for using tuning block
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
` (2 preceding siblings ...)
2017-03-02 9:47 ` [PATCH 3/9] mmc: sdhci-of-esdhc: add support for signal voltage switch Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
2017-03-02 14:25 ` Adrian Hunter
2017-03-02 9:47 ` [PATCH 5/9] mmc: sdhci-of-esdhc: add tuning block support Yangbo Lu
` (4 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
Some non-standard SD host controllers may use tuning block
for executing tuning procedure.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/mmc/host/sdhci.c | 3 +++
drivers/mmc/host/sdhci.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 3c9a924..051b192 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2166,6 +2166,9 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
goto out_unlock;
}
+ if (host->ops->set_tuning_block)
+ host->ops->set_tuning_block(host);
+
host->mmc->retune_period = tuning_count;
sdhci_start_tuning(host);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 04af687..d43519b 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -568,6 +568,7 @@ struct sdhci_ops {
int card_drv, int *drv_type);
int (*start_signal_voltage_switch)(struct sdhci_host *host,
unsigned char signal_voltage);
+ void (*set_tuning_block)(struct sdhci_host *host);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/9] mmc: sdhci: add a callback for using tuning block
2017-03-02 9:47 ` [PATCH 4/9] mmc: sdhci: add a callback for using tuning block Yangbo Lu
@ 2017-03-02 14:25 ` Adrian Hunter
2017-03-03 7:39 ` Y.B. Lu
0 siblings, 1 reply; 14+ messages in thread
From: Adrian Hunter @ 2017-03-02 14:25 UTC (permalink / raw)
To: linux-arm-kernel
On 02/03/17 11:47, Yangbo Lu wrote:
> Some non-standard SD host controllers may use tuning block
> for executing tuning procedure.
If you need to set something up before tuning, you should be able to do that
by hooking the host operation, for example see xenon_execute_tuning() in
sdhci-xenon.c
>
> Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> ---
> drivers/mmc/host/sdhci.c | 3 +++
> drivers/mmc/host/sdhci.h | 1 +
> 2 files changed, 4 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 3c9a924..051b192 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -2166,6 +2166,9 @@ int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
> goto out_unlock;
> }
>
> + if (host->ops->set_tuning_block)
> + host->ops->set_tuning_block(host);
> +
> host->mmc->retune_period = tuning_count;
>
> sdhci_start_tuning(host);
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 04af687..d43519b 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -568,6 +568,7 @@ struct sdhci_ops {
> int card_drv, int *drv_type);
> int (*start_signal_voltage_switch)(struct sdhci_host *host,
> unsigned char signal_voltage);
> + void (*set_tuning_block)(struct sdhci_host *host);
> };
>
> #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 4/9] mmc: sdhci: add a callback for using tuning block
2017-03-02 14:25 ` Adrian Hunter
@ 2017-03-03 7:39 ` Y.B. Lu
0 siblings, 0 replies; 14+ messages in thread
From: Y.B. Lu @ 2017-03-03 7:39 UTC (permalink / raw)
To: linux-arm-kernel
> -----Original Message-----
> From: Adrian Hunter [mailto:adrian.hunter at intel.com]
> Sent: Thursday, March 02, 2017 10:26 PM
> To: Y.B. Lu; linux-mmc at vger.kernel.org; ulf.hansson at linaro.org; Rob
> Herring; Mark Rutland; Catalin Marinas; Will Deacon
> Cc: devicetree at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
> Xiaobo Xie
> Subject: Re: [PATCH 4/9] mmc: sdhci: add a callback for using tuning
> block
>
> On 02/03/17 11:47, Yangbo Lu wrote:
> > Some non-standard SD host controllers may use tuning block for
> > executing tuning procedure.
>
> If you need to set something up before tuning, you should be able to do
> that by hooking the host operation, for example see xenon_execute_tuning()
> in sdhci-xenon.c
>
[Lu Yangbo-B47093] Hi Adrian, this is very helpful. I will generate the v2 patchset with this method.
Thanks you very much!
> >
> > Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
> > ---
> > drivers/mmc/host/sdhci.c | 3 +++
> > drivers/mmc/host/sdhci.h | 1 +
> > 2 files changed, 4 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index
> > 3c9a924..051b192 100644
> > --- a/drivers/mmc/host/sdhci.c
> > +++ b/drivers/mmc/host/sdhci.c
> > @@ -2166,6 +2166,9 @@ int sdhci_execute_tuning(struct mmc_host *mmc,
> u32 opcode)
> > goto out_unlock;
> > }
> >
> > + if (host->ops->set_tuning_block)
> > + host->ops->set_tuning_block(host);
> > +
> > host->mmc->retune_period = tuning_count;
> >
> > sdhci_start_tuning(host);
> > diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index
> > 04af687..d43519b 100644
> > --- a/drivers/mmc/host/sdhci.h
> > +++ b/drivers/mmc/host/sdhci.h
> > @@ -568,6 +568,7 @@ struct sdhci_ops {
> > int card_drv, int *drv_type);
> > int (*start_signal_voltage_switch)(struct sdhci_host *host,
> > unsigned char signal_voltage);
> > + void (*set_tuning_block)(struct sdhci_host *host);
> > };
> >
> > #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> >
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 5/9] mmc: sdhci-of-esdhc: add tuning block support
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
` (3 preceding siblings ...)
2017-03-02 9:47 ` [PATCH 4/9] mmc: sdhci: add a callback for using tuning block Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
2017-03-02 9:47 ` [PATCH 6/9] mmc: sdhci: add a quirk to restore delay in tuning Yangbo Lu
` (3 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
Add tuning block support for eSDHC.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/mmc/host/sdhci-esdhc.h | 5 +++++
drivers/mmc/host/sdhci-of-esdhc.c | 17 +++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 6869567..c4bbd74 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -53,9 +53,14 @@
#define ESDHC_CLOCK_HCKEN 0x00000002
#define ESDHC_CLOCK_IPGEN 0x00000001
+/* Tuning Block Control Register */
+#define ESDHC_TBCTL 0x120
+#define ESDHC_TB_EN 0x00000004
+
/* Control Register for DMA transfer */
#define ESDHC_DMA_SYSCTL 0x40c
#define ESDHC_PERIPHERAL_CLK_SEL 0x00080000
+#define ESDHC_FLUSH_ASYNC_FIFO 0x00040000
#define ESDHC_DMA_SNOOP 0x00000040
#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index c2619f1..b26a780 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -622,6 +622,21 @@ static int esdhc_signal_voltage_switch(struct sdhci_host *host,
}
}
+void esdhc_set_tuning_block(struct sdhci_host *host)
+{
+ u32 val;
+
+ esdhc_clock_enable(host, false);
+ val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+ val |= ESDHC_FLUSH_ASYNC_FIFO;
+ sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
+
+ val = sdhci_readl(host, ESDHC_TBCTL);
+ val |= ESDHC_TB_EN;
+ sdhci_writel(host, val, ESDHC_TBCTL);
+ esdhc_clock_enable(host, true);
+}
+
#ifdef CONFIG_PM_SLEEP
static u32 esdhc_proctl;
static int esdhc_of_suspend(struct device *dev)
@@ -667,6 +682,7 @@ static const struct sdhci_ops sdhci_esdhc_be_ops = {
.reset = esdhc_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.start_signal_voltage_switch = esdhc_signal_voltage_switch,
+ .set_tuning_block = esdhc_set_tuning_block,
};
static const struct sdhci_ops sdhci_esdhc_le_ops = {
@@ -685,6 +701,7 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = {
.reset = esdhc_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.start_signal_voltage_switch = esdhc_signal_voltage_switch,
+ .set_tuning_block = esdhc_set_tuning_block,
};
static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = {
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 6/9] mmc: sdhci: add a quirk to restore delay in tuning
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
` (4 preceding siblings ...)
2017-03-02 9:47 ` [PATCH 5/9] mmc: sdhci-of-esdhc: add tuning block support Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
2017-03-02 9:47 ` [PATCH 7/9] mmc: sdhci-of-esdhc: add delay between tuning cycles Yangbo Lu
` (2 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
There was a mdelay between tuning cycles which is removed since
eMMC spec didn't require that. However it's observed that eSDHC
needed this delay for HS200 successful tuning. Maybe it's also
needed for some other controllers. This patch is to add a quirk
to fix it.
Fixes: 197160d52e85 ("mmc: sdhci: remove mdelay in eMMC tuning")
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/mmc/host/sdhci.c | 3 ++-
drivers/mmc/host/sdhci.h | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 051b192..b1b6fd3 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2100,7 +2100,8 @@ static void __sdhci_execute_tuning(struct sdhci_host *host, u32 opcode,
}
/* eMMC spec does not require a delay between tuning cycles */
- if (opcode == MMC_SEND_TUNING_BLOCK)
+ if ((opcode == MMC_SEND_TUNING_BLOCK) ||
+ (host->quirks2 & SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES))
mdelay(1);
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d43519b..b6643bc 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -427,6 +427,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14)
/* Broken Clock divider zero in controller */
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15)
+/* Delay is needed between tuning cycles */
+#define SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES (1<<16)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 7/9] mmc: sdhci-of-esdhc: add delay between tuning cycles
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
` (5 preceding siblings ...)
2017-03-02 9:47 ` [PATCH 6/9] mmc: sdhci: add a quirk to restore delay in tuning Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
2017-03-02 9:47 ` [PATCH 8/9] arm64: dts: ls1046a: add clocks property and compatible for eSDHC node Yangbo Lu
2017-03-02 9:47 ` [PATCH 9/9] arm64: dts: ls1046ardb: add MMC HS200/UHS-1 modes support Yangbo Lu
8 siblings, 0 replies; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
It's observed that eSDHC needed delay between tuning cycles for
HS200 successful tuning. This patch is to add the quirk
SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES to fix it.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
drivers/mmc/host/sdhci-of-esdhc.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index b26a780..3672c5a 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -823,6 +823,8 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL;
}
+ host->quirks2 |= SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES;
+
/* call to generic mmc_of_parse to support additional capabilities */
ret = mmc_of_parse(host->mmc);
if (ret)
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 8/9] arm64: dts: ls1046a: add clocks property and compatible for eSDHC node
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
` (6 preceding siblings ...)
2017-03-02 9:47 ` [PATCH 7/9] mmc: sdhci-of-esdhc: add delay between tuning cycles Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
2017-03-02 9:47 ` [PATCH 9/9] arm64: dts: ls1046ardb: add MMC HS200/UHS-1 modes support Yangbo Lu
8 siblings, 0 replies; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
The eSDHC could select peripheral clock or platform clock as clock source.
In default, we use platform clock. This patch is to add clocks property
describing peripheral clock for eSDHC node. The driver could use common clk
APIs to get peripheral clock. Also add a compatible for ls1046a eSDHC node.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
index 4a164b8..141a513 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi
@@ -209,10 +209,11 @@
};
esdhc: esdhc at 1560000 {
- compatible = "fsl,esdhc";
+ compatible = "fsl,ls1046a-esdhc", "fsl,esdhc";
reg = <0x0 0x1560000 0x0 0x10000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <0>;
+ clocks = <&clockgen 2 1>;
voltage-ranges = <1800 1800 3300 3300>;
sdhci,auto-cmd12;
big-endian;
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 9/9] arm64: dts: ls1046ardb: add MMC HS200/UHS-1 modes support
2017-03-02 9:47 [PATCH 0/9] Add SD UHS-I and eMMC HS200 support for eSDHC Yangbo Lu
` (7 preceding siblings ...)
2017-03-02 9:47 ` [PATCH 8/9] arm64: dts: ls1046a: add clocks property and compatible for eSDHC node Yangbo Lu
@ 2017-03-02 9:47 ` Yangbo Lu
8 siblings, 0 replies; 14+ messages in thread
From: Yangbo Lu @ 2017-03-02 9:47 UTC (permalink / raw)
To: linux-arm-kernel
Add HS200/UHS-1 properties in eSDHC node to support these
speed modes in driver.
Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
---
arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
index d1ccc00..08528c2 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls1046a-rdb.dts
@@ -64,6 +64,14 @@
};
};
+&esdhc {
+ mmc-hs200-1_8v;
+ sd-uhs-sdr104;
+ sd-uhs-sdr50;
+ sd-uhs-sdr25;
+ sd-uhs-sdr12;
+};
+
&duart0 {
status = "okay";
};
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 14+ messages in thread