linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/10] Add tune support of Mediatek MMC driver
@ 2015-10-27  6:24 Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 01/10] mmc: core: Add DT bindings for eMMC hardware reset support Chaotian Jing
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

Change in v3:
Fix checkpatch errors and warnings for patch 8
Split patch 9, make DT parts enabling hw reset separately

Change in v2:
Drop the 400mhz and use assigned-clock-parents to instead
Split the original tune patch to several independent patches
Re-write the mmc_send_tuning()
Fix GPD checksum error
Move the HS400 setting to ops->prepare_hs400_tuning()	
Modify SD driving settings

Change in v1:
Add DT bindings for eMMC hardware reset
Add pinctrl of data strobe pin for HS400 mode
Modify eMMC driving settings
Add 400mhz source clock for HS400 mode
Add eMMC HS200/HS400 mode support
Add SD SDR50/SDR104 mode support
Add implement of tune function with CMD19/CMD21

Chaotian Jing (10):
  mmc: core: Add DT bindings for eMMC hardware reset support
  mmc: dt-bindings: update Mediatek MMC bindings
  mmc: mediatek: make cmd_ints_mask to const
  mmc: mediatek: change the argument "ddr" to "timing"
  mmc: mediatek: fix got GPD checksum error interrupt when data transfer
  mmc: mediatek: add implement of ops->hw_reset()
  arm64: dts: mediatek: add eMMC hw reset support
  mmc: mmc: extend the mmc_send_tuning()
  mmc: mediatek: add HS400 support
  arm64: dts: mediatek: add HS200/HS400/SDR50/SDR104 support

 Documentation/devicetree/bindings/mmc/mmc.txt    |   1 +
 Documentation/devicetree/bindings/mmc/mtk-sd.txt |  11 +-
 arch/arm64/boot/dts/mediatek/mt8173-evb.dts      |  27 +-
 drivers/mmc/core/host.c                          |   2 +
 drivers/mmc/core/mmc_ops.c                       |   8 +-
 drivers/mmc/host/dw_mmc-exynos.c                 |   4 +-
 drivers/mmc/host/dw_mmc.c                        |   2 +-
 drivers/mmc/host/dw_mmc.h                        |   2 +-
 drivers/mmc/host/mtk-sd.c                        | 304 ++++++++++++++++++++---
 drivers/mmc/host/sdhci-esdhc-imx.c               |   6 +-
 drivers/mmc/host/sdhci-msm.c                     |   2 +-
 drivers/mmc/host/sdhci-sirf.c                    |   2 +-
 include/linux/mmc/core.h                         |   2 +-
 13 files changed, 322 insertions(+), 51 deletions(-)

-- 
1.8.1.1.dirty

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v3 01/10] mmc: core: Add DT bindings for eMMC hardware reset support
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 02/10] mmc: dt-bindings: update Mediatek MMC bindings Chaotian Jing
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

Sometime only need set MMC_CAP_HW_RESET for one of MMC hosts,
So set it in device tree is better.

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
 drivers/mmc/core/host.c                       | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 0384fc3..f693baf 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -37,6 +37,7 @@ Optional properties:
 - sd-uhs-sdr104: SD UHS SDR104 speed is supported
 - sd-uhs-ddr50: SD UHS DDR50 speed is supported
 - cap-power-off-card: powering off the card is safe
+- cap-mmc-hw-reset: eMMC hardware reset is supported
 - cap-sdio-irq: enable SDIO IRQ signalling on this interface
 - full-pwr-cycle: full power cycle of the card is supported
 - mmc-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index abd933b..04fdc2f 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -507,6 +507,8 @@ int mmc_of_parse(struct mmc_host *host)
 		host->caps |= MMC_CAP_UHS_DDR50;
 	if (of_property_read_bool(np, "cap-power-off-card"))
 		host->caps |= MMC_CAP_POWER_OFF_CARD;
+	if (of_property_read_bool(np, "cap-mmc-hw-reset"))
+		host->caps |= MMC_CAP_HW_RESET;
 	if (of_property_read_bool(np, "cap-sdio-irq"))
 		host->caps |= MMC_CAP_SDIO_IRQ;
 	if (of_property_read_bool(np, "full-pwr-cycle"))
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 02/10] mmc: dt-bindings: update Mediatek MMC bindings
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 01/10] mmc: core: Add DT bindings for eMMC hardware reset support Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 03/10] mmc: mediatek: make cmd_ints_mask to const Chaotian Jing
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

Add 400Mhz clock source for HS400 mode

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 Documentation/devicetree/bindings/mmc/mtk-sd.txt | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/mmc/mtk-sd.txt b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
index a1adfa4..0120c7f 100644
--- a/Documentation/devicetree/bindings/mmc/mtk-sd.txt
+++ b/Documentation/devicetree/bindings/mmc/mtk-sd.txt
@@ -17,6 +17,11 @@ Required properties:
 - vmmc-supply: power to the Core
 - vqmmc-supply: power to the IO
 
+Optional properties:
+- assigned-clocks: PLL of the source clock
+- assigned-clock-parents: parent of source clock, used for HS400 mode to get 400Mhz source clock
+- hs400-ds-delay: HS400 DS delay setting
+
 Examples:
 mmc0: mmc at 11230000 {
 	compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc";
@@ -24,9 +29,13 @@ mmc0: mmc at 11230000 {
 	interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
 	vmmc-supply = <&mt6397_vemc_3v3_reg>;
 	vqmmc-supply = <&mt6397_vio18_reg>;
-	clocks = <&pericfg CLK_PERI_MSDC30_0>, <&topckgen CLK_TOP_MSDC50_0_H_SEL>;
+	clocks = <&pericfg CLK_PERI_MSDC30_0>,
+	         <&topckgen CLK_TOP_MSDC50_0_H_SEL>;
 	clock-names = "source", "hclk";
 	pinctrl-names = "default", "state_uhs";
 	pinctrl-0 = <&mmc0_pins_default>;
 	pinctrl-1 = <&mmc0_pins_uhs>;
+	assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
+	assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
+	hs400-ds-delay = <0x14015>;
 };
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 03/10] mmc: mediatek: make cmd_ints_mask to const
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 01/10] mmc: core: Add DT bindings for eMMC hardware reset support Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 02/10] mmc: dt-bindings: update Mediatek MMC bindings Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 04/10] mmc: mediatek: change the argument "ddr" to "timing" Chaotian Jing
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

cmd_ints_mask and data_ints_mask are constant value,
so make it to const

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 drivers/mmc/host/mtk-sd.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index b2e89d3..8b3e15d 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -353,7 +353,10 @@ static void msdc_reset_hw(struct msdc_host *host)
 static void msdc_cmd_next(struct msdc_host *host,
 		struct mmc_request *mrq, struct mmc_command *cmd);
 
-static u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
+static const u32 cmd_ints_mask = MSDC_INTEN_CMDRDY | MSDC_INTEN_RSPCRCERR |
+			MSDC_INTEN_CMDTMO | MSDC_INTEN_ACMDRDY |
+			MSDC_INTEN_ACMDCRCERR | MSDC_INTEN_ACMDTMO;
+static const u32 data_ints_mask = MSDC_INTEN_XFER_COMPL | MSDC_INTEN_DATTMO |
 			MSDC_INTEN_DATCRCERR | MSDC_INTEN_DMA_BDCSERR |
 			MSDC_INTEN_DMA_GPDCSERR | MSDC_INTEN_DMA_PROTECT;
 
@@ -725,10 +728,7 @@ static bool msdc_cmd_done(struct msdc_host *host, int events,
 	if (done)
 		return true;
 
-	sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
-			MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
-			MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
-			MSDC_INTEN_ACMDTMO);
+	sdr_clr_bits(host->base + MSDC_INTEN, cmd_ints_mask);
 
 	if (cmd->flags & MMC_RSP_PRESENT) {
 		if (cmd->flags & MMC_RSP_136) {
@@ -818,10 +818,7 @@ static void msdc_start_command(struct msdc_host *host,
 	rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
 	mod_delayed_work(system_wq, &host->req_timeout, DAT_TIMEOUT);
 
-	sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_CMDRDY |
-			MSDC_INTEN_RSPCRCERR | MSDC_INTEN_CMDTMO |
-			MSDC_INTEN_ACMDRDY | MSDC_INTEN_ACMDCRCERR |
-			MSDC_INTEN_ACMDTMO);
+	sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
 	writel(cmd->arg, host->base + SDC_ARG);
 	writel(rawcmd, host->base + SDC_CMD);
 }
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 04/10] mmc: mediatek: change the argument "ddr" to "timing"
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
                   ` (2 preceding siblings ...)
  2015-10-27  6:24 ` [PATCH v3 03/10] mmc: mediatek: make cmd_ints_mask to const Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 05/10] mmc: mediatek: fix got GPD checksum error interrupt when data transfer Chaotian Jing
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

use the ios->timing directly is better
It can reflect current timing and do settings by timing

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 drivers/mmc/host/mtk-sd.c | 20 ++++++++------------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 8b3e15d..c877ded 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -297,7 +297,7 @@ struct msdc_host {
 	u32 mclk;		/* mmc subsystem clock frequency */
 	u32 src_clk_freq;	/* source clock frequency */
 	u32 sclk;		/* SD/MS bus clock frequency */
-	bool ddr;
+	unsigned char timing;
 	bool vqmmc_enabled;
 	struct msdc_save_para save_para; /* used when gate HCLK */
 };
@@ -488,7 +488,7 @@ static void msdc_ungate_clock(struct msdc_host *host)
 		cpu_relax();
 }
 
-static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
+static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
 {
 	u32 mode;
 	u32 flags;
@@ -504,7 +504,8 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
 
 	flags = readl(host->base + MSDC_INTEN);
 	sdr_clr_bits(host->base + MSDC_INTEN, flags);
-	if (ddr) { /* may need to modify later */
+	if (timing == MMC_TIMING_UHS_DDR50 ||
+	    timing == MMC_TIMING_MMC_DDR52) {
 		mode = 0x2; /* ddr mode and use divisor */
 		if (hz >= (host->src_clk_freq >> 2)) {
 			div = 0; /* mean div = 1/4 */
@@ -535,12 +536,12 @@ static void msdc_set_mclk(struct msdc_host *host, int ddr, u32 hz)
 		cpu_relax();
 	host->sclk = sclk;
 	host->mclk = hz;
-	host->ddr = ddr;
+	host->timing = timing;
 	/* need because clk changed. */
 	msdc_set_timeout(host, host->timeout_ns, host->timeout_clks);
 	sdr_set_bits(host->base + MSDC_INTEN, flags);
 
-	dev_dbg(host->dev, "sclk: %d, ddr: %d\n", host->sclk, ddr);
+	dev_dbg(host->dev, "sclk: %d, timing: %d\n", host->sclk, timing);
 }
 
 static inline u32 msdc_cmd_find_resp(struct msdc_host *host,
@@ -1158,14 +1159,9 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
 	struct msdc_host *host = mmc_priv(mmc);
 	int ret;
-	u32 ddr = 0;
 
 	pm_runtime_get_sync(host->dev);
 
-	if (ios->timing == MMC_TIMING_UHS_DDR50 ||
-	    ios->timing == MMC_TIMING_MMC_DDR52)
-		ddr = 1;
-
 	msdc_set_buswidth(host, ios->bus_width);
 
 	/* Suspend/Resume will do power off/on */
@@ -1202,8 +1198,8 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 		break;
 	}
 
-	if (host->mclk != ios->clock || host->ddr != ddr)
-		msdc_set_mclk(host, ddr, ios->clock);
+	if (host->mclk != ios->clock || host->timing != ios->timing)
+		msdc_set_mclk(host, ios->timing, ios->clock);
 
 end:
 	pm_runtime_mark_last_busy(host->dev);
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 05/10] mmc: mediatek: fix got GPD checksum error interrupt when data transfer
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
                   ` (3 preceding siblings ...)
  2015-10-27  6:24 ` [PATCH v3 04/10] mmc: mediatek: change the argument "ddr" to "timing" Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 06/10] mmc: mediatek: add implement of ops->hw_reset() Chaotian Jing
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

Even if we only use one gpd, we need alloc 2 gpd and make
the gpd->next pointer to the second gpd, or may get gpd checksum
error, this was checked by hardware

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 drivers/mmc/host/mtk-sd.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index c877ded..3858163 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -1145,11 +1145,14 @@ static void msdc_init_gpd_bd(struct msdc_host *host, struct msdc_dma *dma)
 	struct mt_bdma_desc *bd = dma->bd;
 	int i;
 
-	memset(gpd, 0, sizeof(struct mt_gpdma_desc));
+	memset(gpd, 0, sizeof(struct mt_gpdma_desc) * 2);
 
 	gpd->gpd_info = GPDMA_DESC_BDP; /* hwo, cs, bd pointer */
 	gpd->ptr = (u32)dma->bd_addr; /* physical address */
-
+	/* gpd->next is must set for desc DMA
+	 * That's why must alloc 2 gpd structure.
+	 */
+	gpd->next = (u32)dma->gpd_addr + sizeof(struct mt_gpdma_desc);
 	memset(bd, 0, sizeof(struct mt_bdma_desc) * MAX_BD_NUM);
 	for (i = 0; i < (MAX_BD_NUM - 1); i++)
 		bd[i].next = (u32)dma->bd_addr + sizeof(*bd) * (i + 1);
@@ -1306,7 +1309,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
 
 	host->timeout_clks = 3 * 1048576;
 	host->dma.gpd = dma_alloc_coherent(&pdev->dev,
-				sizeof(struct mt_gpdma_desc),
+				2 * sizeof(struct mt_gpdma_desc),
 				&host->dma.gpd_addr, GFP_KERNEL);
 	host->dma.bd = dma_alloc_coherent(&pdev->dev,
 				MAX_BD_NUM * sizeof(struct mt_bdma_desc),
@@ -1347,7 +1350,7 @@ release:
 release_mem:
 	if (host->dma.gpd)
 		dma_free_coherent(&pdev->dev,
-			sizeof(struct mt_gpdma_desc),
+			2 * sizeof(struct mt_gpdma_desc),
 			host->dma.gpd, host->dma.gpd_addr);
 	if (host->dma.bd)
 		dma_free_coherent(&pdev->dev,
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 06/10] mmc: mediatek: add implement of ops->hw_reset()
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
                   ` (4 preceding siblings ...)
  2015-10-27  6:24 ` [PATCH v3 05/10] mmc: mediatek: fix got GPD checksum error interrupt when data transfer Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 07/10] arm64: dts: mediatek: add eMMC hw reset support Chaotian Jing
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

add implement of ops->hw_reset() for eMMC

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>

---
 drivers/mmc/host/mtk-sd.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 3858163..5627644 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -64,6 +64,7 @@
 #define SDC_RESP2        0x48
 #define SDC_RESP3        0x4c
 #define SDC_BLK_NUM      0x50
+#define EMMC_IOCON       0x7c
 #define SDC_ACMD_RESP    0x80
 #define MSDC_DMA_SA      0x90
 #define MSDC_DMA_CTRL    0x98
@@ -1209,6 +1210,15 @@ end:
 	pm_runtime_put_autosuspend(host->dev);
 }
 
+static void msdc_hw_reset(struct mmc_host *mmc)
+{
+	struct msdc_host *host = mmc_priv(mmc);
+
+	sdr_set_bits(host->base + EMMC_IOCON, 1);
+	udelay(10); /* 10us is enough */
+	sdr_clr_bits(host->base + EMMC_IOCON, 1);
+}
+
 static struct mmc_host_ops mt_msdc_ops = {
 	.post_req = msdc_post_req,
 	.pre_req = msdc_pre_req,
@@ -1216,6 +1226,7 @@ static struct mmc_host_ops mt_msdc_ops = {
 	.set_ios = msdc_ops_set_ios,
 	.start_signal_voltage_switch = msdc_ops_switch_volt,
 	.card_busy = msdc_card_busy,
+	.hw_reset = msdc_hw_reset,
 };
 
 static int msdc_drv_probe(struct platform_device *pdev)
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 07/10] arm64: dts: mediatek: add eMMC hw reset support
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
                   ` (5 preceding siblings ...)
  2015-10-27  6:24 ` [PATCH v3 06/10] mmc: mediatek: add implement of ops->hw_reset() Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 08/10] mmc: mmc: extend the mmc_send_tuning() Chaotian Jing
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

Add eMMC hardware reset support

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 4be66ca..6d79ffc 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -72,6 +72,7 @@
 	bus-width = <8>;
 	max-frequency = <50000000>;
 	cap-mmc-highspeed;
+	cap-mmc-hw-reset;
 	vmmc-supply = <&mt6397_vemc_3v3_reg>;
 	vqmmc-supply = <&mt6397_vio18_reg>;
 	non-removable;
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 08/10] mmc: mmc: extend the mmc_send_tuning()
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
                   ` (6 preceding siblings ...)
  2015-10-27  6:24 ` [PATCH v3 07/10] arm64: dts: mediatek: add eMMC hw reset support Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 09/10] mmc: mediatek: add HS400 support Chaotian Jing
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

The mmc_execute_tuning() has already prepared the opcode,
there is no need to prepare it again at mmc_send_tuning(),
and, there is a BUG of mmc_send_tuning() to determine the opcode
by bus width, assume eMMC was running at HS200, 4bit mode,
then the mmc_send_tuning() will overwrite the opcode from CMD21
to CMD19, then got error.

in addition, extend an argument of "cmd_error" to allow getting
if there was cmd error when tune response.

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 drivers/mmc/core/mmc_ops.c         | 8 ++++----
 drivers/mmc/host/dw_mmc-exynos.c   | 4 ++--
 drivers/mmc/host/dw_mmc.c          | 2 +-
 drivers/mmc/host/dw_mmc.h          | 2 +-
 drivers/mmc/host/sdhci-esdhc-imx.c | 6 +++---
 drivers/mmc/host/sdhci-msm.c       | 2 +-
 drivers/mmc/host/sdhci-sirf.c      | 2 +-
 include/linux/mmc/core.h           | 2 +-
 8 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 0e9ae1c..4305f75 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -589,7 +589,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 }
 EXPORT_SYMBOL_GPL(mmc_switch);
 
-int mmc_send_tuning(struct mmc_host *host)
+int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
 {
 	struct mmc_request mrq = {NULL};
 	struct mmc_command cmd = {0};
@@ -599,16 +599,13 @@ int mmc_send_tuning(struct mmc_host *host)
 	const u8 *tuning_block_pattern;
 	int size, err = 0;
 	u8 *data_buf;
-	u32 opcode;
 
 	if (ios->bus_width == MMC_BUS_WIDTH_8) {
 		tuning_block_pattern = tuning_blk_pattern_8bit;
 		size = sizeof(tuning_blk_pattern_8bit);
-		opcode = MMC_SEND_TUNING_BLOCK_HS200;
 	} else if (ios->bus_width == MMC_BUS_WIDTH_4) {
 		tuning_block_pattern = tuning_blk_pattern_4bit;
 		size = sizeof(tuning_blk_pattern_4bit);
-		opcode = MMC_SEND_TUNING_BLOCK;
 	} else
 		return -EINVAL;
 
@@ -639,6 +636,9 @@ int mmc_send_tuning(struct mmc_host *host)
 
 	mmc_wait_for_req(host, &mrq);
 
+	if (cmd_error)
+		*cmd_error = cmd.error;
+
 	if (cmd.error) {
 		err = cmd.error;
 		goto out;
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 1e75309..3a7e835 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -446,7 +446,7 @@ out:
 	return loc;
 }
 
-static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
+static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
 {
 	struct dw_mci *host = slot->host;
 	struct dw_mci_exynos_priv_data *priv = host->priv;
@@ -461,7 +461,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
 		mci_writel(host, TMOUT, ~0);
 		smpl = dw_mci_exynos_move_next_clksmpl(host);
 
-		if (!mmc_send_tuning(mmc))
+		if (!mmc_send_tuning(mmc, opcode, NULL))
 			candiates |= (1 << smpl);
 
 	} while (start_smpl != smpl);
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index fcbf552..be8441d 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1427,7 +1427,7 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 	int err = -EINVAL;
 
 	if (drv_data && drv_data->execute_tuning)
-		err = drv_data->execute_tuning(slot);
+		err = drv_data->execute_tuning(slot, opcode);
 	return err;
 }
 
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 8ce4674..394340f 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -281,7 +281,7 @@ struct dw_mci_drv_data {
 	void		(*prepare_command)(struct dw_mci *host, u32 *cmdr);
 	void		(*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
 	int		(*parse_dt)(struct dw_mci *host);
-	int		(*execute_tuning)(struct dw_mci_slot *slot);
+	int		(*execute_tuning)(struct dw_mci_slot *slot, u32 opcode);
 	int		(*prepare_hs400_tuning)(struct dw_mci *host,
 						struct mmc_ios *ios);
 	int		(*switch_voltage)(struct mmc_host *mmc,
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 886d230..1f1582f 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -759,7 +759,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
 	min = ESDHC_TUNE_CTRL_MIN;
 	while (min < ESDHC_TUNE_CTRL_MAX) {
 		esdhc_prepare_tuning(host, min);
-		if (!mmc_send_tuning(host->mmc))
+		if (!mmc_send_tuning(host->mmc, opcode, NULL))
 			break;
 		min += ESDHC_TUNE_CTRL_STEP;
 	}
@@ -768,7 +768,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
 	max = min + ESDHC_TUNE_CTRL_STEP;
 	while (max < ESDHC_TUNE_CTRL_MAX) {
 		esdhc_prepare_tuning(host, max);
-		if (mmc_send_tuning(host->mmc)) {
+		if (mmc_send_tuning(host->mmc, opcode, NULL)) {
 			max -= ESDHC_TUNE_CTRL_STEP;
 			break;
 		}
@@ -778,7 +778,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
 	/* use average delay to get the best timing */
 	avg = (min + max) / 2;
 	esdhc_prepare_tuning(host, avg);
-	ret = mmc_send_tuning(host->mmc);
+	ret = mmc_send_tuning(host->mmc, opcode, NULL);
 	esdhc_post_tuning(host);
 
 	dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 4bcee03..4695bee 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -373,7 +373,7 @@ retry:
 		if (rc)
 			return rc;
 
-		rc = mmc_send_tuning(mmc);
+		rc = mmc_send_tuning(mmc, opcode, NULL);
 		if (!rc) {
 			/* Tuning is successful at this tuning point */
 			tuned_phases[tuned_phase_cnt++] = phase;
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index 8842945..d0c7ffe 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -97,7 +97,7 @@ retry:
 			clock_setting | phase,
 			SDHCI_CLK_DELAY_SETTING);
 
-		if (!mmc_send_tuning(mmc)) {
+		if (!mmc_send_tuning(mmc, opcode, NULL)) {
 			/* Tuning is successful at this tuning point */
 			tuned_phase_cnt++;
 			dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 258daf9..43a283a 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -155,7 +155,7 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
 extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
 			bool, bool);
 extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
-extern int mmc_send_tuning(struct mmc_host *host);
+extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
 extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
 
 #define MMC_ERASE_ARG		0x00000000
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 09/10] mmc: mediatek: add HS400 support
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
                   ` (7 preceding siblings ...)
  2015-10-27  6:24 ` [PATCH v3 08/10] mmc: mmc: extend the mmc_send_tuning() Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  6:24 ` [PATCH v3 10/10] arm64: dts: mediatek: add HS200/HS400/SDR50/SDR104 support Chaotian Jing
  2015-10-27  9:54 ` [PATCH v3 00/10] Add tune support of Mediatek MMC driver Ulf Hansson
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

add HS400 mode and tune support

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 drivers/mmc/host/mtk-sd.c | 249 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 244 insertions(+), 5 deletions(-)

diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 5627644..39568cc 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -26,6 +26,7 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 
 #include <linux/mmc/card.h>
@@ -72,6 +73,8 @@
 #define MSDC_PATCH_BIT   0xb0
 #define MSDC_PATCH_BIT1  0xb4
 #define MSDC_PAD_TUNE    0xec
+#define PAD_DS_TUNE      0x188
+#define EMMC50_CFG0      0x208
 
 /*--------------------------------------------------------------------------*/
 /* Register Mask                                                            */
@@ -88,6 +91,7 @@
 #define MSDC_CFG_CKSTB          (0x1 << 7)	/* R  */
 #define MSDC_CFG_CKDIV          (0xff << 8)	/* RW */
 #define MSDC_CFG_CKMOD          (0x3 << 16)	/* RW */
+#define MSDC_CFG_HS400_CK_MODE  (0x1 << 18)	/* RW */
 
 /* MSDC_IOCON mask */
 #define MSDC_IOCON_SDR104CKS    (0x1 << 0)	/* RW */
@@ -205,6 +209,17 @@
 #define MSDC_PATCH_BIT_SPCPUSH    (0x1 << 29)	/* RW */
 #define MSDC_PATCH_BIT_DECRCTMO   (0x1 << 30)	/* RW */
 
+#define MSDC_PAD_TUNE_DATRRDLY	  (0x1f <<  8)	/* RW */
+#define MSDC_PAD_TUNE_CMDRDLY	  (0x1f << 16)  /* RW */
+
+#define PAD_DS_TUNE_DLY1	  (0x1f << 2)   /* RW */
+#define PAD_DS_TUNE_DLY2	  (0x1f << 7)   /* RW */
+#define PAD_DS_TUNE_DLY3	  (0x1f << 12)  /* RW */
+
+#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0)   /* RW */
+#define EMMC50_CFG_CRCSTS_EDGE    (0x1 << 3)   /* RW */
+#define EMMC50_CFG_CFCSTS_SEL     (0x1 << 4)   /* RW */
+
 #define REQ_CMD_EIO  (0x1 << 0)
 #define REQ_CMD_TMO  (0x1 << 1)
 #define REQ_DAT_ERR  (0x1 << 2)
@@ -220,6 +235,7 @@
 #define CMD_TIMEOUT         (HZ/10 * 5)	/* 100ms x5 */
 #define DAT_TIMEOUT         (HZ    * 5)	/* 1000ms x5 */
 
+#define PAD_DELAY_MAX	32 /* PAD delay cells */
 /*--------------------------------------------------------------------------*/
 /* Descriptor Structure                                                     */
 /*--------------------------------------------------------------------------*/
@@ -266,6 +282,14 @@ struct msdc_save_para {
 	u32 pad_tune;
 	u32 patch_bit0;
 	u32 patch_bit1;
+	u32 pad_ds_tune;
+	u32 emmc50_cfg0;
+};
+
+struct msdc_delay_phase {
+	u8 maxlen;
+	u8 start;
+	u8 final_phase;
 };
 
 struct msdc_host {
@@ -300,6 +324,7 @@ struct msdc_host {
 	u32 sclk;		/* SD/MS bus clock frequency */
 	unsigned char timing;
 	bool vqmmc_enabled;
+	u32 hs400_ds_delay;
 	struct msdc_save_para save_para; /* used when gate HCLK */
 };
 
@@ -505,9 +530,15 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
 
 	flags = readl(host->base + MSDC_INTEN);
 	sdr_clr_bits(host->base + MSDC_INTEN, flags);
+	sdr_clr_bits(host->base + MSDC_CFG, MSDC_CFG_HS400_CK_MODE);
 	if (timing == MMC_TIMING_UHS_DDR50 ||
-	    timing == MMC_TIMING_MMC_DDR52) {
-		mode = 0x2; /* ddr mode and use divisor */
+	    timing == MMC_TIMING_MMC_DDR52 ||
+	    timing == MMC_TIMING_MMC_HS400) {
+		if (timing == MMC_TIMING_MMC_HS400)
+			mode = 0x3;
+		else
+			mode = 0x2; /* ddr mode and use divisor */
+
 		if (hz >= (host->src_clk_freq >> 2)) {
 			div = 0; /* mean div = 1/4 */
 			sclk = host->src_clk_freq >> 2; /* sclk = clk / 4 */
@@ -516,6 +547,14 @@ static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz)
 			sclk = (host->src_clk_freq >> 2) / div;
 			div = (div >> 1);
 		}
+
+		if (timing == MMC_TIMING_MMC_HS400 &&
+		    hz >= (host->src_clk_freq >> 1)) {
+			sdr_set_bits(host->base + MSDC_CFG,
+				     MSDC_CFG_HS400_CK_MODE);
+			sclk = host->src_clk_freq >> 1;
+			div = 0; /* div is ignore when bit18 is set */
+		}
 	} else if (hz >= host->src_clk_freq) {
 		mode = 0x1; /* no divisor */
 		div = 0;
@@ -894,7 +933,7 @@ static void msdc_data_xfer_next(struct msdc_host *host,
 				struct mmc_request *mrq, struct mmc_data *data)
 {
 	if (mmc_op_multi(mrq->cmd->opcode) && mrq->stop && !mrq->stop->error &&
-	    (!data->bytes_xfered || !mrq->sbc))
+	    !mrq->sbc)
 		msdc_start_command(host, mrq, mrq->stop);
 	else
 		msdc_request_done(host, mrq);
@@ -940,6 +979,8 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
 
 			if (events & MSDC_INT_DATTMO)
 				data->error = -ETIMEDOUT;
+			else if (events & MSDC_INT_DATCRCERR)
+				data->error = -EILSEQ;
 
 			dev_err(host->dev, "%s: cmd=%d; blocks=%d",
 				__func__, mrq->cmd->opcode, data->blocks);
@@ -1111,10 +1152,12 @@ static void msdc_init_hw(struct msdc_host *host)
 
 	writel(0, host->base + MSDC_PAD_TUNE);
 	writel(0, host->base + MSDC_IOCON);
-	sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 1);
-	writel(0x403c004f, host->base + MSDC_PATCH_BIT);
+	sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0);
+	writel(0x403c0046, host->base + MSDC_PATCH_BIT);
 	sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1);
 	writel(0xffff0089, host->base + MSDC_PATCH_BIT1);
+	sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL);
+
 	/* Configure to enable SDIO mode.
 	 * it's must otherwise sdio cmd5 failed
 	 */
@@ -1172,6 +1215,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	switch (ios->power_mode) {
 	case MMC_POWER_UP:
 		if (!IS_ERR(mmc->supply.vmmc)) {
+			msdc_init_hw(host);
 			ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
 					ios->vdd);
 			if (ret) {
@@ -1210,6 +1254,190 @@ end:
 	pm_runtime_put_autosuspend(host->dev);
 }
 
+static u32 test_delay_bit(u32 delay, u32 bit)
+{
+	bit %= PAD_DELAY_MAX;
+	return delay & (1 << bit);
+}
+
+static int get_delay_len(u32 delay, u32 start_bit)
+{
+	int i;
+
+	for (i = 0; i < (PAD_DELAY_MAX - start_bit); i++) {
+		if (test_delay_bit(delay, start_bit + i) == 0)
+			return i;
+	}
+	return PAD_DELAY_MAX - start_bit;
+}
+
+static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
+{
+	int start = 0, len = 0;
+	int start_final = 0, len_final = 0;
+	u8 final_phase = 0xff;
+	struct msdc_delay_phase delay_phase;
+
+	if (delay == 0) {
+		dev_err(host->dev, "phase error: [map:%x]\n", delay);
+		delay_phase.final_phase = final_phase;
+		return delay_phase;
+	}
+
+	while (start < PAD_DELAY_MAX) {
+		len = get_delay_len(delay, start);
+		if (len_final < len) {
+			start_final = start;
+			len_final = len;
+		}
+		start += len ? len : 1;
+		if (len >= 8 && start_final < 4)
+			break;
+	}
+
+	/* The rule is that to find the smallest delay cell */
+	if (start_final == 0)
+		final_phase = (start_final + len_final / 3) % PAD_DELAY_MAX;
+	else
+		final_phase = (start_final + len_final / 2) % PAD_DELAY_MAX;
+	dev_info(host->dev, "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+		 delay, len_final, final_phase);
+
+	delay_phase.maxlen = len_final;
+	delay_phase.start = start_final;
+	delay_phase.final_phase = final_phase;
+	return delay_phase;
+}
+
+static int msdc_tune_response(struct mmc_host *mmc, u32 opcode)
+{
+	struct msdc_host *host = mmc_priv(mmc);
+	u32 rise_delay = 0, fall_delay = 0;
+	struct msdc_delay_phase final_rise_delay, final_fall_delay;
+	u8 final_delay, final_maxlen;
+	int cmd_err;
+	int i;
+
+	sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+	for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+		sdr_set_field(host->base + MSDC_PAD_TUNE,
+			      MSDC_PAD_TUNE_CMDRDLY, i);
+		mmc_send_tuning(mmc, opcode, &cmd_err);
+		if (!cmd_err)
+			rise_delay |= (1 << i);
+	}
+
+	sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+	for (i = 0; i < PAD_DELAY_MAX; i++) {
+		sdr_set_field(host->base + MSDC_PAD_TUNE,
+			      MSDC_PAD_TUNE_CMDRDLY, i);
+		mmc_send_tuning(mmc, opcode, &cmd_err);
+		if (!cmd_err)
+			fall_delay |= (1 << i);
+	}
+
+	final_rise_delay = get_best_delay(host, rise_delay);
+	final_fall_delay = get_best_delay(host, fall_delay);
+
+	final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+	if (final_maxlen == final_rise_delay.maxlen) {
+		sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+		sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+			      final_rise_delay.final_phase);
+		final_delay = final_rise_delay.final_phase;
+	} else {
+		sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_RSPL);
+		sdr_set_field(host->base + MSDC_PAD_TUNE, MSDC_PAD_TUNE_CMDRDLY,
+			      final_fall_delay.final_phase);
+		final_delay = final_fall_delay.final_phase;
+	}
+
+	return final_delay == 0xff ? -EIO : 0;
+}
+
+static int msdc_tune_data(struct mmc_host *mmc, u32 opcode)
+{
+	struct msdc_host *host = mmc_priv(mmc);
+	u32 rise_delay = 0, fall_delay = 0;
+	struct msdc_delay_phase final_rise_delay, final_fall_delay;
+	u8 final_delay, final_maxlen;
+	int i, ret;
+
+	sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+	sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+	for (i = 0 ; i < PAD_DELAY_MAX; i++) {
+		sdr_set_field(host->base + MSDC_PAD_TUNE,
+			      MSDC_PAD_TUNE_DATRRDLY, i);
+		ret = mmc_send_tuning(mmc, opcode, NULL);
+		if (!ret)
+			rise_delay |= (1 << i);
+	}
+
+	sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+	sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+	for (i = 0; i < PAD_DELAY_MAX; i++) {
+		sdr_set_field(host->base + MSDC_PAD_TUNE,
+			      MSDC_PAD_TUNE_DATRRDLY, i);
+		ret = mmc_send_tuning(mmc, opcode, NULL);
+		if (!ret)
+			fall_delay |= (1 << i);
+	}
+
+	final_rise_delay = get_best_delay(host, rise_delay);
+	final_fall_delay = get_best_delay(host, fall_delay);
+
+	final_maxlen = max(final_rise_delay.maxlen, final_fall_delay.maxlen);
+	/* Rising edge is more stable, prefer to use it */
+	if (final_rise_delay.maxlen >= 10)
+		final_maxlen = final_rise_delay.maxlen;
+	if (final_maxlen == final_rise_delay.maxlen) {
+		sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+		sdr_clr_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+		sdr_set_field(host->base + MSDC_PAD_TUNE,
+			      MSDC_PAD_TUNE_DATRRDLY,
+			      final_rise_delay.final_phase);
+		final_delay = final_rise_delay.final_phase;
+	} else {
+		sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_DSPL);
+		sdr_set_bits(host->base + MSDC_IOCON, MSDC_IOCON_W_DSPL);
+		sdr_set_field(host->base + MSDC_PAD_TUNE,
+			      MSDC_PAD_TUNE_DATRRDLY,
+			      final_fall_delay.final_phase);
+		final_delay = final_fall_delay.final_phase;
+	}
+
+	return final_delay == 0xff ? -EIO : 0;
+}
+
+static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct msdc_host *host = mmc_priv(mmc);
+	int ret;
+
+	pm_runtime_get_sync(host->dev);
+	ret = msdc_tune_response(mmc, opcode);
+	if (ret == -EIO) {
+		dev_err(host->dev, "Tune response fail!\n");
+		goto out;
+	}
+	ret = msdc_tune_data(mmc, opcode);
+	if (ret == -EIO)
+		dev_err(host->dev, "Tune data fail!\n");
+
+out:
+	pm_runtime_mark_last_busy(host->dev);
+	pm_runtime_put_autosuspend(host->dev);
+	return ret;
+}
+
+static int msdc_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct msdc_host *host = mmc_priv(mmc);
+
+	writel(host->hs400_ds_delay, host->base + PAD_DS_TUNE);
+	return 0;
+}
+
 static void msdc_hw_reset(struct mmc_host *mmc)
 {
 	struct msdc_host *host = mmc_priv(mmc);
@@ -1226,6 +1454,8 @@ static struct mmc_host_ops mt_msdc_ops = {
 	.set_ios = msdc_ops_set_ios,
 	.start_signal_voltage_switch = msdc_ops_switch_volt,
 	.card_busy = msdc_card_busy,
+	.execute_tuning = msdc_execute_tuning,
+	.prepare_hs400_tuning = msdc_prepare_hs400_tuning,
 	.hw_reset = msdc_hw_reset,
 };
 
@@ -1300,6 +1530,11 @@ static int msdc_drv_probe(struct platform_device *pdev)
 		goto host_free;
 	}
 
+	if (!of_property_read_u32(pdev->dev.of_node, "hs400-ds-delay",
+				  &host->hs400_ds_delay))
+		dev_dbg(&pdev->dev, "hs400-ds-delay: %x\n",
+			host->hs400_ds_delay);
+
 	host->dev = &pdev->dev;
 	host->mmc = mmc;
 	host->src_clk_freq = clk_get_rate(host->src_clk);
@@ -1410,6 +1645,8 @@ static void msdc_save_reg(struct msdc_host *host)
 	host->save_para.pad_tune = readl(host->base + MSDC_PAD_TUNE);
 	host->save_para.patch_bit0 = readl(host->base + MSDC_PATCH_BIT);
 	host->save_para.patch_bit1 = readl(host->base + MSDC_PATCH_BIT1);
+	host->save_para.pad_ds_tune = readl(host->base + PAD_DS_TUNE);
+	host->save_para.emmc50_cfg0 = readl(host->base + EMMC50_CFG0);
 }
 
 static void msdc_restore_reg(struct msdc_host *host)
@@ -1420,6 +1657,8 @@ static void msdc_restore_reg(struct msdc_host *host)
 	writel(host->save_para.pad_tune, host->base + MSDC_PAD_TUNE);
 	writel(host->save_para.patch_bit0, host->base + MSDC_PATCH_BIT);
 	writel(host->save_para.patch_bit1, host->base + MSDC_PATCH_BIT1);
+	writel(host->save_para.pad_ds_tune, host->base + PAD_DS_TUNE);
+	writel(host->save_para.emmc50_cfg0, host->base + EMMC50_CFG0);
 }
 
 static int msdc_runtime_suspend(struct device *dev)
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 10/10] arm64: dts: mediatek: add HS200/HS400/SDR50/SDR104 support
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
                   ` (8 preceding siblings ...)
  2015-10-27  6:24 ` [PATCH v3 09/10] mmc: mediatek: add HS400 support Chaotian Jing
@ 2015-10-27  6:24 ` Chaotian Jing
  2015-10-27  9:54 ` [PATCH v3 00/10] Add tune support of Mediatek MMC driver Ulf Hansson
  10 siblings, 0 replies; 12+ messages in thread
From: Chaotian Jing @ 2015-10-27  6:24 UTC (permalink / raw)
  To: linux-arm-kernel

add HS200/HS400 support for eMMC
add SDR50/SDR104 support for SD

Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
---
 arch/arm64/boot/dts/mediatek/mt8173-evb.dts | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 6d79ffc..a061221 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -70,11 +70,16 @@
 	pinctrl-0 = <&mmc0_pins_default>;
 	pinctrl-1 = <&mmc0_pins_uhs>;
 	bus-width = <8>;
-	max-frequency = <50000000>;
+	max-frequency = <200000000>;
 	cap-mmc-highspeed;
+	mmc-hs200-1_8v;
+	mmc-hs400-1_8v;
 	cap-mmc-hw-reset;
+	hs400-ds-delay = <0x14015>;
 	vmmc-supply = <&mt6397_vemc_3v3_reg>;
 	vqmmc-supply = <&mt6397_vio18_reg>;
+	assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
+	assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
 	non-removable;
 };
 
@@ -84,9 +89,10 @@
 	pinctrl-0 = <&mmc1_pins_default>;
 	pinctrl-1 = <&mmc1_pins_uhs>;
 	bus-width = <4>;
-	max-frequency = <50000000>;
+	max-frequency = <200000000>;
 	cap-sd-highspeed;
-	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
 	cd-gpios = <&pio 132 0>;
 	vmmc-supply = <&mt6397_vmch_reg>;
 	vqmmc-supply = <&mt6397_vmc_reg>;
@@ -155,13 +161,19 @@
 				 <MT8173_PIN_64_MSDC0_DAT7__FUNC_MSDC0_DAT7>,
 				 <MT8173_PIN_66_MSDC0_CMD__FUNC_MSDC0_CMD>;
 			input-enable;
-			drive-strength = <MTK_DRIVE_2mA>;
+			drive-strength = <MTK_DRIVE_4mA>;
 			bias-pull-up = <MTK_PUPD_SET_R1R0_01>;
 		};
 
 		pins_clk {
 			pinmux = <MT8173_PIN_65_MSDC0_CLK__FUNC_MSDC0_CLK>;
-			drive-strength = <MTK_DRIVE_2mA>;
+			drive-strength = <MTK_DRIVE_4mA>;
+			bias-pull-down = <MTK_PUPD_SET_R1R0_01>;
+		};
+
+		pins_ds {
+			pinmux = <MT8173_PIN_67_MSDC0_DSL__FUNC_MSDC0_DSL>;
+			drive-strength = <MTK_DRIVE_6mA>;
 			bias-pull-down = <MTK_PUPD_SET_R1R0_01>;
 		};
 
@@ -179,13 +191,13 @@
 				 <MT8173_PIN_76_MSDC1_DAT3__FUNC_MSDC1_DAT3>,
 				 <MT8173_PIN_78_MSDC1_CMD__FUNC_MSDC1_CMD>;
 			input-enable;
-			drive-strength = <MTK_DRIVE_4mA>;
+			drive-strength = <MTK_DRIVE_6mA>;
 			bias-pull-up = <MTK_PUPD_SET_R1R0_10>;
 		};
 
 		pins_clk {
 			pinmux = <MT8173_PIN_77_MSDC1_CLK__FUNC_MSDC1_CLK>;
-			drive-strength = <MTK_DRIVE_4mA>;
+			drive-strength = <MTK_DRIVE_8mA>;
 			bias-pull-down = <MTK_PUPD_SET_R1R0_10>;
 		};
 	};
-- 
1.8.1.1.dirty

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 00/10] Add tune support of Mediatek MMC driver
  2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
                   ` (9 preceding siblings ...)
  2015-10-27  6:24 ` [PATCH v3 10/10] arm64: dts: mediatek: add HS200/HS400/SDR50/SDR104 support Chaotian Jing
@ 2015-10-27  9:54 ` Ulf Hansson
  10 siblings, 0 replies; 12+ messages in thread
From: Ulf Hansson @ 2015-10-27  9:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 27 October 2015 at 07:24, Chaotian Jing <chaotian.jing@mediatek.com> wrote:
> Change in v3:
> Fix checkpatch errors and warnings for patch 8
> Split patch 9, make DT parts enabling hw reset separately
>
> Change in v2:
> Drop the 400mhz and use assigned-clock-parents to instead
> Split the original tune patch to several independent patches
> Re-write the mmc_send_tuning()
> Fix GPD checksum error
> Move the HS400 setting to ops->prepare_hs400_tuning()
> Modify SD driving settings
>
> Change in v1:
> Add DT bindings for eMMC hardware reset
> Add pinctrl of data strobe pin for HS400 mode
> Modify eMMC driving settings
> Add 400mhz source clock for HS400 mode
> Add eMMC HS200/HS400 mode support
> Add SD SDR50/SDR104 mode support
> Add implement of tune function with CMD19/CMD21
>
> Chaotian Jing (10):
>   mmc: core: Add DT bindings for eMMC hardware reset support
>   mmc: dt-bindings: update Mediatek MMC bindings
>   mmc: mediatek: make cmd_ints_mask to const
>   mmc: mediatek: change the argument "ddr" to "timing"
>   mmc: mediatek: fix got GPD checksum error interrupt when data transfer
>   mmc: mediatek: add implement of ops->hw_reset()
>   arm64: dts: mediatek: add eMMC hw reset support
>   mmc: mmc: extend the mmc_send_tuning()
>   mmc: mediatek: add HS400 support
>   arm64: dts: mediatek: add HS200/HS400/SDR50/SDR104 support
>
>  Documentation/devicetree/bindings/mmc/mmc.txt    |   1 +
>  Documentation/devicetree/bindings/mmc/mtk-sd.txt |  11 +-
>  arch/arm64/boot/dts/mediatek/mt8173-evb.dts      |  27 +-
>  drivers/mmc/core/host.c                          |   2 +
>  drivers/mmc/core/mmc_ops.c                       |   8 +-
>  drivers/mmc/host/dw_mmc-exynos.c                 |   4 +-
>  drivers/mmc/host/dw_mmc.c                        |   2 +-
>  drivers/mmc/host/dw_mmc.h                        |   2 +-
>  drivers/mmc/host/mtk-sd.c                        | 304 ++++++++++++++++++++---
>  drivers/mmc/host/sdhci-esdhc-imx.c               |   6 +-
>  drivers/mmc/host/sdhci-msm.c                     |   2 +-
>  drivers/mmc/host/sdhci-sirf.c                    |   2 +-
>  include/linux/mmc/core.h                         |   2 +-
>  13 files changed, 322 insertions(+), 51 deletions(-)
>
> --
> 1.8.1.1.dirty
>

Chaotian,

I have applied this except the ARM patches (patch7 and patch10) as I
think those should go via ARM SoC (unless I get acks for them).

Regarding patch8, it didn't apply since it needed a re-base. This time
it was trivial to fix, so I decided to pick it up anyway.

Future wise I also advise you to significantly trim the cc/to list
when posting patches. Likely what happens when that many people are
requested for input, is that *none* cares. :-)

Thanks and kind regards!
Uffe

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2015-10-27  9:54 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-27  6:24 [PATCH v3 00/10] Add tune support of Mediatek MMC driver Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 01/10] mmc: core: Add DT bindings for eMMC hardware reset support Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 02/10] mmc: dt-bindings: update Mediatek MMC bindings Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 03/10] mmc: mediatek: make cmd_ints_mask to const Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 04/10] mmc: mediatek: change the argument "ddr" to "timing" Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 05/10] mmc: mediatek: fix got GPD checksum error interrupt when data transfer Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 06/10] mmc: mediatek: add implement of ops->hw_reset() Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 07/10] arm64: dts: mediatek: add eMMC hw reset support Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 08/10] mmc: mmc: extend the mmc_send_tuning() Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 09/10] mmc: mediatek: add HS400 support Chaotian Jing
2015-10-27  6:24 ` [PATCH v3 10/10] arm64: dts: mediatek: add HS200/HS400/SDR50/SDR104 support Chaotian Jing
2015-10-27  9:54 ` [PATCH v3 00/10] Add tune support of Mediatek MMC driver 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).