* [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching
@ 2015-09-17 5:50 Yangbo Lu
2015-09-17 5:50 ` [v2, 2/8] mmc: sdhci: add a callback of tuning block setting Yangbo Lu
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Yangbo Lu @ 2015-09-17 5:50 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: Yangbo Lu
Add a signal voltage switching callback to let host use its own
switching process.
Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
---
Changes for v2:
- Modified commit message
- Added SDR50 support patches
---
drivers/mmc/host/sdhci.c | 5 +++++
drivers/mmc/host/sdhci.h | 2 ++
2 files changed, 7 insertions(+)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 64b7fdb..9b3d4c2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1757,6 +1757,11 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
if (host->version < SDHCI_SPEC_300)
return 0;
+ if (host->ops->signal_voltage_switch) {
+ host->ops->signal_voltage_switch(host, ios->signal_voltage);
+ return 0;
+ }
+
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 7c02ff4..723f034 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -544,6 +544,8 @@ struct sdhci_ops {
struct mmc_card *card,
unsigned int max_dtr, int host_drv,
int card_drv, int *drv_type);
+ void (*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] 9+ messages in thread
* [v2, 2/8] mmc: sdhci: add a callback of tuning block setting
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
@ 2015-09-17 5:50 ` Yangbo Lu
2015-09-17 5:50 ` [v2, 3/8] mmc: dt: add DT bindings for Freescale eSDHC Yangbo Lu
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yangbo Lu @ 2015-09-17 5:50 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: Yangbo Lu
Add a tuning block setting callback to let host set its
tuning block before executing tuning procedure.
Signed-off-by: Yangbo Lu <yangbo.lu@freescale.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 9b3d4c2..9da4644 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1939,6 +1939,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
return err;
}
+ if (host->ops->set_tuning_block)
+ host->ops->set_tuning_block(host);
+
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl |= SDHCI_CTRL_EXEC_TUNING;
if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 723f034..98f239b 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -546,6 +546,7 @@ struct sdhci_ops {
int card_drv, int *drv_type);
void (*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] 9+ messages in thread
* [v2, 3/8] mmc: dt: add DT bindings for Freescale eSDHC
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
2015-09-17 5:50 ` [v2, 2/8] mmc: sdhci: add a callback of tuning block setting Yangbo Lu
@ 2015-09-17 5:50 ` Yangbo Lu
2015-09-17 5:50 ` [v2, 4/8] mmc: sdhci-of-esdhc: add eMMC Adapter Card HS200 mode support Yangbo Lu
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yangbo Lu @ 2015-09-17 5:50 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: Yangbo Lu
Document Freescale eSDHC 'adapter-type' and 'peripheral-frequency'
properties.
Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
---
Documentation/devicetree/bindings/mmc/fsl-esdhc.txt | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
index b7943f3..2006408 100644
--- a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
+++ b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
@@ -22,6 +22,18 @@ Optional properties:
- voltage-ranges : two cells are required, first cell specifies minimum
slot voltage (mV), second cell specifies maximum slot voltage (mV).
Several ranges could be specified.
+ - adapter-tye: specifies SDHC Adapter card type. The Adapter card types are
+ as below.
+ TYPE_1 0x1 /* eMMC Card Rev4.5 */
+ TYPE_2 0x2 /* SD/MMC Legacy Card */
+ TYPE_3 0x3 /* eMMC Card Rev4.4 */
+ TYPE_4 0x4 /* Reserved */
+ TYPE_5 0x5 /* MMC Card */
+ TYPE_6 0x6 /* SD Card Rev2.0 Rev3.0 */
+ NO_ADAPTER 0x7 /* No Card is Present*/
+ - peripheral-frequency: specifies peripheral clock frequency value.
+
+
Example:
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [v2, 4/8] mmc: sdhci-of-esdhc: add eMMC Adapter Card HS200 mode support
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
2015-09-17 5:50 ` [v2, 2/8] mmc: sdhci: add a callback of tuning block setting Yangbo Lu
2015-09-17 5:50 ` [v2, 3/8] mmc: dt: add DT bindings for Freescale eSDHC Yangbo Lu
@ 2015-09-17 5:50 ` Yangbo Lu
2015-09-17 5:50 ` [v2, 5/8] mmc: sdhci: add SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES quirk Yangbo Lu
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yangbo Lu @ 2015-09-17 5:50 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: Yangbo Lu
Freescale QorIQ QDS boards use different SDHC Adapter card types as below.
To support SDHC Adapter card type 1(eMMC card Rev4.5) HS200 mode, select
to use peripheral clock and add callbacks for signal voltage switching and
tuning block setting for eSDHC.
SDHC_ADAPTER_TYPE:
ADAPTER_TYPE_1 0x1 /* eMMC Card Rev4.5 */
ADAPTER_TYPE_2 0x2 /* SD/MMC Legacy Card */
ADAPTER_TYPE_3 0x3 /* eMMC Card Rev4.4 */
ADAPTER_TYPE_4 0x4 /* Reserved */
ADAPTER_TYPE_5 0x5 /* MMC Card */
ADAPTER_TYPE_6 0x6 /* SD Card Rev2.0 Rev3.0 */
NO_ADAPTER 0x7 /* No Card is Present*/
Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
---
drivers/mmc/host/sdhci-esdhc.h | 22 ++++++++
drivers/mmc/host/sdhci-of-esdhc.c | 116 +++++++++++++++++++++++++++++++++++++-
2 files changed, 136 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 163ac99..de9be18 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -24,14 +24,34 @@
SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_NO_HISPD_BIT)
+#define ESDHCI_PRESENT_STATE 0x24
+#define ESDHC_CLK_STABLE 0x00000008
+
+#define ESDHC_PROCTL 0x28
+#define ESDHC_VOLT_SEL 0x00000400
+
#define ESDHC_SYSTEM_CONTROL 0x2c
#define ESDHC_CLOCK_MASK 0x0000fff0
#define ESDHC_PREDIV_SHIFT 8
#define ESDHC_DIVIDER_SHIFT 4
+#define ESDHC_CLOCK_CRDEN 0x00000008
#define ESDHC_CLOCK_PEREN 0x00000004
#define ESDHC_CLOCK_HCKEN 0x00000002
#define ESDHC_CLOCK_IPGEN 0x00000001
+#define ESDHC_CAPABILITIES_1 0x114
+#define ESDHC_MODE_MASK 0x00000007
+#define ESDHC_MODE_DDR50_SEL 0xfffffffc
+#define ESDHC_MODE_SDR104 0x00000002
+#define ESDHC_MODE_DDR50 0x00000004
+
+#define ESDHC_TBCTL 0x120
+#define ESDHC_TB_EN 0x00000004
+
+#define ESDHC_CLOCK_CONTROL 0x144
+#define ESDHC_CLKLPBK_EXTPIN 0x80000000
+#define ESDHC_CMDCLK_SHIFTED 0x00008000
+
/* pltfm-specific */
#define ESDHC_HOST_CONTROL_LE 0x20
@@ -45,6 +65,8 @@
/* OF-specific */
#define ESDHC_DMA_SYSCTL 0x40c
#define ESDHC_DMA_SNOOP 0x00000040
+#define ESDHC_FLUSH_ASYNC_FIFO 0x00040000
+#define ESDHC_USE_PERICLK 0x00080000
#define ESDHC_HOST_CONTROL_RES 0x01
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 653f335..bffc8c4 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -24,11 +24,35 @@
#define VENDOR_V_22 0x12
#define VENDOR_V_23 0x13
+
+/* SDHC Adapter Card Type */
+#define ESDHC_ADAPTER_TYPE_1 0x1 /* eMMC Card Rev4.5 */
+#define ESDHC_ADAPTER_TYPE_2 0x2 /* SD/MMC Legacy Card */
+#define ESDHC_ADAPTER_TYPE_3 0x3 /* eMMC Card Rev4.4 */
+#define ESDHC_ADAPTER_TYPE_4 0x4 /* Reserved */
+#define ESDHC_ADAPTER_TYPE_5 0x5 /* MMC Card */
+#define ESDHC_ADAPTER_TYPE_6 0x6 /* SD Card Rev2.0 Rev3.0 */
+#define ESDHC_NO_ADAPTER 0x7 /* No Card is Present*/
+
+static u32 adapter_type;
+
static u32 esdhc_readl(struct sdhci_host *host, int reg)
{
u32 ret;
- ret = in_be32(host->ioaddr + reg);
+ if (reg == SDHCI_CAPABILITIES_1) {
+ ret = in_be32(host->ioaddr + ESDHC_CAPABILITIES_1);
+ switch (adapter_type) {
+ case ESDHC_ADAPTER_TYPE_1:
+ if (ret & ESDHC_MODE_SDR104)
+ host->mmc->caps2 |= MMC_CAP2_HS200;
+ ret &= ~ESDHC_MODE_MASK;
+ break;
+ default:
+ ret &= ~ESDHC_MODE_MASK;
+ }
+ } else
+ ret = in_be32(host->ioaddr + reg);
/*
* The bit of ADMA flag in eSDHC is not compatible with standard
* SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is
@@ -137,8 +161,11 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
}
/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
- if (reg == SDHCI_HOST_CONTROL)
+ if (reg == SDHCI_HOST_CONTROL) {
val &= ~ESDHC_HOST_CONTROL_RES;
+ val &= ~SDHCI_CTRL_HISPD;
+ val |= (in_be32(host->ioaddr + reg) & SDHCI_CTRL_HISPD);
+ }
sdhci_be32bs_writeb(host, val, reg);
}
@@ -197,6 +224,33 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
return pltfm_host->clock / 256 / 16;
}
+void esdhc_clock_control(struct sdhci_host *host, bool enable)
+{
+ u32 value;
+ u32 time_out;
+
+ value = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+
+ if (enable)
+ value |= ESDHC_CLOCK_CRDEN;
+ else
+ value &= ~ESDHC_CLOCK_CRDEN;
+
+ sdhci_writel(host, value, ESDHC_SYSTEM_CONTROL);
+
+ time_out = 20;
+ value = ESDHC_CLK_STABLE;
+ while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & value)) {
+ if (time_out == 0) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ break;
+ }
+ time_out--;
+ mdelay(1);
+ }
+}
+
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
{
int pre_div = 1;
@@ -282,6 +336,42 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
}
+void esdhc_set_tuning_block(struct sdhci_host *host)
+{
+ u32 value;
+
+ esdhc_clock_control(host, false);
+ value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+ value |= ESDHC_FLUSH_ASYNC_FIFO;
+ sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
+
+ value = sdhci_readl(host, ESDHC_TBCTL);
+ value |= ESDHC_TB_EN;
+ sdhci_writel(host, value, ESDHC_TBCTL);
+ esdhc_clock_control(host, true);
+}
+
+void esdhc_signal_voltage_switch(struct sdhci_host *host,
+ unsigned char signal_voltage)
+{
+ u32 value;
+
+ value = sdhci_readl(host, ESDHC_PROCTL);
+
+ switch (signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ value &= (~ESDHC_VOLT_SEL);
+ sdhci_writel(host, value, ESDHC_PROCTL);
+ break;
+ case MMC_SIGNAL_VOLTAGE_180:
+ value |= ESDHC_VOLT_SEL;
+ sdhci_writel(host, value, ESDHC_PROCTL);
+ break;
+ default:
+ return;
+ }
+}
+
static void esdhc_reset(struct sdhci_host *host, u8 mask)
{
sdhci_reset(host, mask);
@@ -306,6 +396,8 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
.set_bus_width = esdhc_pltfm_set_bus_width,
.reset = esdhc_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
+ .set_tuning_block = esdhc_set_tuning_block,
+ .signal_voltage_switch = esdhc_signal_voltage_switch,
};
#ifdef CONFIG_PM
@@ -358,6 +450,10 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct device_node *np;
+ struct sdhci_pltfm_host *pltfm_host;
+ const __be32 *value;
+ u32 val;
+ int size;
int ret;
host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
@@ -382,6 +478,22 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL;
}
+ value = of_get_property(np, "adapter-type", &size);
+ if (value && size == sizeof(*value) && *value)
+ adapter_type = be32_to_cpup(value);
+
+ /* If getting a peripheral-frequency, use it instead */
+ value = of_get_property(np, "peripheral-frequency", &size);
+ if (value && size == sizeof(*value) && *value) {
+ pltfm_host = sdhci_priv(host);
+ pltfm_host->clock = be32_to_cpup(value);
+ esdhc_clock_control(host, false);
+ val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+ val |= ESDHC_USE_PERICLK;
+ sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
+ esdhc_clock_control(host, true);
+ }
+
/* 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] 9+ messages in thread
* [v2, 5/8] mmc: sdhci: add SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES quirk
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
` (2 preceding siblings ...)
2015-09-17 5:50 ` [v2, 4/8] mmc: sdhci-of-esdhc: add eMMC Adapter Card HS200 mode support Yangbo Lu
@ 2015-09-17 5:50 ` Yangbo Lu
2015-09-17 5:50 ` [v2, 6/8] mmc: sdhci-of-esdhc: add tuning cycles delay quirk for t2080/t1040 Yangbo Lu
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yangbo Lu @ 2015-09-17 5:50 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: Yangbo Lu
Although eMMC spec does not require a delay between tuning cycles,
some hosts need it to avoid tuning failure.
Signed-off-by: Yangbo Lu <yangbo.lu@freescale.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 9da4644..d61061b5 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -2038,7 +2038,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
/* 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);
} while (ctrl & SDHCI_CTRL_EXEC_TUNING);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 98f239b..7223f96 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -412,6 +412,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)
+/* Need delay 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] 9+ messages in thread
* [v2, 6/8] mmc: sdhci-of-esdhc: add tuning cycles delay quirk for t2080/t1040
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
` (3 preceding siblings ...)
2015-09-17 5:50 ` [v2, 5/8] mmc: sdhci: add SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES quirk Yangbo Lu
@ 2015-09-17 5:50 ` Yangbo Lu
2015-09-17 5:50 ` [v2, 7/8] mmc: sd: set 4bit bus width after IO signal voltage switching Yangbo Lu
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Yangbo Lu @ 2015-09-17 5:50 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: Yangbo Lu
Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
---
drivers/mmc/host/sdhci-of-esdhc.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index bffc8c4..5aabadf 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -470,6 +470,10 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
of_device_is_compatible(np, "fsl,t1040-esdhc"))
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+ if (of_device_is_compatible(np, "fsl,t1040-esdhc") ||
+ of_device_is_compatible(np, "fsl,t2080-esdhc"))
+ host->quirks2 |= SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES;
+
if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
/*
* Freescale messed up with P2020 as it has a non-standard
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [v2, 7/8] mmc: sd: set 4bit bus width after IO signal voltage switching
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
` (4 preceding siblings ...)
2015-09-17 5:50 ` [v2, 6/8] mmc: sdhci-of-esdhc: add tuning cycles delay quirk for t2080/t1040 Yangbo Lu
@ 2015-09-17 5:50 ` Yangbo Lu
2015-09-17 5:50 ` [v2, 8/8] mmc: sdhci-of-esdhc: add SDR50 mode support for SD/MMC Legacy Adapter Card Yangbo Lu
2015-10-16 13:18 ` [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Ulf Hansson
7 siblings, 0 replies; 9+ messages in thread
From: Yangbo Lu @ 2015-09-17 5:50 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: Yangbo Lu
IO signal voltage switching is used for UHS speed mode. After the
voltage switching, the card is in UHS mode and it's needed to
set 4bit bus width before any data transfer command.
Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
---
drivers/mmc/core/sd.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index e28ebf3..d861ee0 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -947,6 +947,15 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
goto free_card;
}
+ /* If the signal voltage was switched to 1.8v for UHS mode,
+ * it's needed to set 4bit bus width for card and host.
+ */
+ if (host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+ if (mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4))
+ goto free_card;
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+ }
+
err = mmc_sd_setup_card(host, card, oldcard != NULL);
if (err)
goto free_card;
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [v2, 8/8] mmc: sdhci-of-esdhc: add SDR50 mode support for SD/MMC Legacy Adapter Card
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
` (5 preceding siblings ...)
2015-09-17 5:50 ` [v2, 7/8] mmc: sd: set 4bit bus width after IO signal voltage switching Yangbo Lu
@ 2015-09-17 5:50 ` Yangbo Lu
2015-10-16 13:18 ` [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Ulf Hansson
7 siblings, 0 replies; 9+ messages in thread
From: Yangbo Lu @ 2015-09-17 5:50 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: Yangbo Lu
The eSDHC is not compatible with SD spec well, so we need
to use eSDHC-special code to switch to SDR50 mode.
1. IO signal voltage switching, eSDHC uses SDHC_VS to switch
io voltage and it's needed to configure a global utilities
register SCFG_SDHCIOVSELCR(if it has) and SDHC_VS signal.
2. Before executing tuning procedure, eSDHC should set its own
tuning block.
static const struct sdhci_ops sdhci_esdhc_ops = {
...
.set_tuning_block = esdhc_set_tuning_block,
.signal_voltage_switch = esdhc_signal_voltage_switch,
};
Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
---
drivers/mmc/host/sdhci-esdhc.h | 2 ++
drivers/mmc/host/sdhci-of-esdhc.c | 62 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index de9be18..a04b8bb 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -26,6 +26,8 @@
#define ESDHCI_PRESENT_STATE 0x24
#define ESDHC_CLK_STABLE 0x00000008
+#define ESDHC_DLSL 0x0f000000
+#define ESDHC_CLSL 0x00800000
#define ESDHC_PROCTL 0x28
#define ESDHC_VOLT_SEL 0x00000400
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 5aabadf..c887b8e 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/mmc/host.h>
+#include <linux/of_address.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -39,6 +40,17 @@ static u32 adapter_type;
static u32 esdhc_readl(struct sdhci_host *host, int reg)
{
u32 ret;
+ u32 clsl;
+ u32 dlsl;
+
+ if (reg == SDHCI_PRESENT_STATE) {
+ ret = in_be32(host->ioaddr + reg);
+ clsl = ret & ESDHC_CLSL;
+ dlsl = ret & ESDHC_DLSL;
+ ret &= ~((ESDHC_CLSL << 1) | (ESDHC_DLSL >> 4));
+ ret |= ((clsl << 1) | (dlsl >> 4));
+ return ret;
+ }
if (reg == SDHCI_CAPABILITIES_1) {
ret = in_be32(host->ioaddr + ESDHC_CAPABILITIES_1);
@@ -48,6 +60,15 @@ static u32 esdhc_readl(struct sdhci_host *host, int reg)
host->mmc->caps2 |= MMC_CAP2_HS200;
ret &= ~ESDHC_MODE_MASK;
break;
+ case ESDHC_ADAPTER_TYPE_2:
+ if (ret & ESDHC_MODE_MASK) {
+ ret &= ~ESDHC_MODE_MASK;
+ /* If it exists UHS-I support, enable SDR50 */
+ host->mmc->caps |= (MMC_CAP_UHS_SDR50 |
+ MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR12);
+ }
+ break;
default:
ret &= ~ESDHC_MODE_MASK;
}
@@ -256,11 +277,14 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
int pre_div = 1;
int div = 1;
u32 temp;
+ int timeout;
host->mmc->actual_clock = 0;
- if (clock == 0)
+ if (clock == 0) {
+ esdhc_clock_control(host, false);
return;
+ }
/* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
temp = esdhc_readw(host, SDHCI_HOST_VERSION);
@@ -298,6 +322,22 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
| (div << ESDHC_DIVIDER_SHIFT)
| (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+ /* Wait max 20 ms */
+ timeout = 20;
+ while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & ESDHC_CLK_STABLE)) {
+ if (timeout == 0) {
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
+ return;
+ }
+ timeout--;
+ mdelay(1);
+ }
+
+ temp |= ESDHC_CLOCK_CRDEN;
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
mdelay(1);
}
@@ -351,9 +391,17 @@ void esdhc_set_tuning_block(struct sdhci_host *host)
esdhc_clock_control(host, true);
}
+static const struct of_device_id scfg_device_ids[] = {
+ { .compatible = "fsl,t1040-scfg", },
+ {}
+};
+
void esdhc_signal_voltage_switch(struct sdhci_host *host,
unsigned char signal_voltage)
{
+ struct device_node *scfg_node;
+ void __iomem *scfg_base;
+ u32 scfg_sdhciovselcr;
u32 value;
value = sdhci_readl(host, ESDHC_PROCTL);
@@ -364,6 +412,18 @@ void esdhc_signal_voltage_switch(struct sdhci_host *host,
sdhci_writel(host, value, ESDHC_PROCTL);
break;
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);
+ of_node_put(scfg_node);
+ if (scfg_base) {
+ scfg_sdhciovselcr = 0x408;
+ out_be32(scfg_base + scfg_sdhciovselcr,
+ 0x80000001);
+ iounmap(scfg_base);
+ }
+ }
+
value |= ESDHC_VOLT_SEL;
sdhci_writel(host, value, ESDHC_PROCTL);
break;
--
2.1.0.27.g96db324
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
` (6 preceding siblings ...)
2015-09-17 5:50 ` [v2, 8/8] mmc: sdhci-of-esdhc: add SDR50 mode support for SD/MMC Legacy Adapter Card Yangbo Lu
@ 2015-10-16 13:18 ` Ulf Hansson
7 siblings, 0 replies; 9+ messages in thread
From: Ulf Hansson @ 2015-10-16 13:18 UTC (permalink / raw)
To: Yangbo Lu; +Cc: linux-mmc
On 17 September 2015 at 07:50, Yangbo Lu <yangbo.lu@freescale.com> wrote:
> Add a signal voltage switching callback to let host use its own
> switching process.
>
> Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
Sorry for the delay!
Unless you haven't noticed my recent statement around sdhci's
callbacks and quirks, please read these.
https://lkml.org/lkml/2015/10/8/734
https://lkml.org/lkml/2015/10/6/158
That said, I won't pick any of the patches from these patchset.
I would also encourage you and other people to help turning shdci into
a bunch of library functions.
Kind regards
Uffe
> ---
> Changes for v2:
> - Modified commit message
> - Added SDR50 support patches
> ---
> drivers/mmc/host/sdhci.c | 5 +++++
> drivers/mmc/host/sdhci.h | 2 ++
> 2 files changed, 7 insertions(+)
>
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 64b7fdb..9b3d4c2 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -1757,6 +1757,11 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
> if (host->version < SDHCI_SPEC_300)
> return 0;
>
> + if (host->ops->signal_voltage_switch) {
> + host->ops->signal_voltage_switch(host, ios->signal_voltage);
> + return 0;
> + }
> +
> 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 7c02ff4..723f034 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -544,6 +544,8 @@ struct sdhci_ops {
> struct mmc_card *card,
> unsigned int max_dtr, int host_drv,
> int card_drv, int *drv_type);
> + void (*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 [flat|nested] 9+ messages in thread
end of thread, other threads:[~2015-10-16 13:18 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-17 5:50 [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Yangbo Lu
2015-09-17 5:50 ` [v2, 2/8] mmc: sdhci: add a callback of tuning block setting Yangbo Lu
2015-09-17 5:50 ` [v2, 3/8] mmc: dt: add DT bindings for Freescale eSDHC Yangbo Lu
2015-09-17 5:50 ` [v2, 4/8] mmc: sdhci-of-esdhc: add eMMC Adapter Card HS200 mode support Yangbo Lu
2015-09-17 5:50 ` [v2, 5/8] mmc: sdhci: add SDHCI_QUIRK2_DELAY_BETWEEN_TUNING_CYCLES quirk Yangbo Lu
2015-09-17 5:50 ` [v2, 6/8] mmc: sdhci-of-esdhc: add tuning cycles delay quirk for t2080/t1040 Yangbo Lu
2015-09-17 5:50 ` [v2, 7/8] mmc: sd: set 4bit bus width after IO signal voltage switching Yangbo Lu
2015-09-17 5:50 ` [v2, 8/8] mmc: sdhci-of-esdhc: add SDR50 mode support for SD/MMC Legacy Adapter Card Yangbo Lu
2015-10-16 13:18 ` [v2, 1/8] mmc: sdhci: add a callback of signal voltage switching Ulf Hansson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).