* [PATCH v3 0/4] mmc: dw_mmc: exynos: Add HS400 support
@ 2014-12-31 6:43 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-mmc
Cc: chris, ulf.hansson, jh80.chung, tgih.jun, dianders, alim.akhtar,
kgene, linux-arm-kernel, devicetree, linux-samsung-soc,
a.kesavan
This serise is second part of [1] which was posted by Seungwon Jeon few months back.
This adds HS400 mode support for exynos dw_mmc host controller.
Currently tested on Exynos5800-peach-pi platform and exynos7 platform for HS400 mode.
Appreciate testing on other exynos5 platform which supports emmc5.0
[1] http://www.spinics.net/lists/linux-mmc/msg25599.html
Changes in V3:
rebased on ulf's next (commit: 607b448 mmc: core: Make tuning block patterns static)
Seungwon Jeon (4):
mmc: dw_mmc: exynos: incorporate ciu_div into timing property
mmc: dw_mmc: exynos: support eMMC's HS400 mode
ARM: dts: drop dw-mshc-ciu-div property from Exynos
ARM: dts: add HS400 support for Exynos5420 and exynos5800
.../devicetree/bindings/mmc/exynos-dw-mshc.txt | 21 +-
arch/arm/boot/dts/exynos3250-monk.dts | 5 +-
arch/arm/boot/dts/exynos3250-rinato.dts | 5 +-
arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 5 +-
arch/arm/boot/dts/exynos4412-origen.dts | 5 +-
arch/arm/boot/dts/exynos4412-trats2.dts | 5 +-
arch/arm/boot/dts/exynos5250-arndale.dts | 10 +-
arch/arm/boot/dts/exynos5250-smdk5250.dts | 10 +-
arch/arm/boot/dts/exynos5250-snow.dts | 15 +-
arch/arm/boot/dts/exynos5250-spring.dts | 10 +-
arch/arm/boot/dts/exynos5260-xyref5260.dts | 10 +-
arch/arm/boot/dts/exynos5410-smdk5410.dts | 10 +-
arch/arm/boot/dts/exynos5420-arndale-octa.dts | 10 +-
arch/arm/boot/dts/exynos5420-peach-pit.dts | 15 +-
arch/arm/boot/dts/exynos5420-pinctrl.dtsi | 7 +
arch/arm/boot/dts/exynos5420-smdk5420.dts | 15 +-
arch/arm/boot/dts/exynos5800-peach-pi.dts | 15 +-
drivers/mmc/host/dw_mmc-exynos.c | 242 +++++++++++++++-----
drivers/mmc/host/dw_mmc-exynos.h | 18 +-
drivers/mmc/host/dw_mmc.c | 16 +-
drivers/mmc/host/dw_mmc.h | 2 +
21 files changed, 308 insertions(+), 143 deletions(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 0/4] mmc: dw_mmc: exynos: Add HS400 support
@ 2014-12-31 6:43 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-arm-kernel
This serise is second part of [1] which was posted by Seungwon Jeon few months back.
This adds HS400 mode support for exynos dw_mmc host controller.
Currently tested on Exynos5800-peach-pi platform and exynos7 platform for HS400 mode.
Appreciate testing on other exynos5 platform which supports emmc5.0
[1] http://www.spinics.net/lists/linux-mmc/msg25599.html
Changes in V3:
rebased on ulf's next (commit: 607b448 mmc: core: Make tuning block patterns static)
Seungwon Jeon (4):
mmc: dw_mmc: exynos: incorporate ciu_div into timing property
mmc: dw_mmc: exynos: support eMMC's HS400 mode
ARM: dts: drop dw-mshc-ciu-div property from Exynos
ARM: dts: add HS400 support for Exynos5420 and exynos5800
.../devicetree/bindings/mmc/exynos-dw-mshc.txt | 21 +-
arch/arm/boot/dts/exynos3250-monk.dts | 5 +-
arch/arm/boot/dts/exynos3250-rinato.dts | 5 +-
arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 5 +-
arch/arm/boot/dts/exynos4412-origen.dts | 5 +-
arch/arm/boot/dts/exynos4412-trats2.dts | 5 +-
arch/arm/boot/dts/exynos5250-arndale.dts | 10 +-
arch/arm/boot/dts/exynos5250-smdk5250.dts | 10 +-
arch/arm/boot/dts/exynos5250-snow.dts | 15 +-
arch/arm/boot/dts/exynos5250-spring.dts | 10 +-
arch/arm/boot/dts/exynos5260-xyref5260.dts | 10 +-
arch/arm/boot/dts/exynos5410-smdk5410.dts | 10 +-
arch/arm/boot/dts/exynos5420-arndale-octa.dts | 10 +-
arch/arm/boot/dts/exynos5420-peach-pit.dts | 15 +-
arch/arm/boot/dts/exynos5420-pinctrl.dtsi | 7 +
arch/arm/boot/dts/exynos5420-smdk5420.dts | 15 +-
arch/arm/boot/dts/exynos5800-peach-pi.dts | 15 +-
drivers/mmc/host/dw_mmc-exynos.c | 242 +++++++++++++++-----
drivers/mmc/host/dw_mmc-exynos.h | 18 +-
drivers/mmc/host/dw_mmc.c | 16 +-
drivers/mmc/host/dw_mmc.h | 2 +
21 files changed, 308 insertions(+), 143 deletions(-)
--
1.7.9.5
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
2014-12-31 6:43 ` Alim Akhtar
@ 2014-12-31 6:43 ` Alim Akhtar
-1 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-mmc
Cc: chris, ulf.hansson, jh80.chung, tgih.jun, dianders, alim.akhtar,
kgene, linux-arm-kernel, devicetree, linux-samsung-soc,
a.kesavan
From: Seungwon Jeon <tgih.jun@samsung.com>
ciu_div may not be common value for all speed mode.
So, it needs to be attached to CLKSEL timing.
This also introduce a new compatibale 'dw-mshc-hs200-timing'
for selecting hs200 timing value
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
.../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
drivers/mmc/host/dw_mmc-exynos.h | 1 +
3 files changed, 67 insertions(+), 30 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
index ee4fc05..06455de 100644
--- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
@@ -23,10 +23,6 @@ Required Properties:
- "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
specific extensions having an SMU.
-* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
- unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
- ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
-
* samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
in transmit mode and CIU clock phase shift value in receive mode for single
data rate mode operation. Refer notes below for the order of the cells and the
@@ -37,11 +33,16 @@ Required Properties:
data rate mode operation. Refer notes below for the order of the cells and the
valid values.
+* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
+
Notes for the sdr-timing and ddr-timing values:
The order of the cells should be
- First Cell: CIU clock phase shift value for tx mode.
- Second Cell: CIU clock phase shift value for rx mode.
+ - Thrid Cell: Specifies the divider value for the card interface
+ unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
+ ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
Valid values for SDR and DDR CIU clock timing for Exynos5250:
- valid value for tx phase shift and rx phase shift is 0 to 7.
@@ -79,8 +80,8 @@ Example:
broken-cd;
fifo-depth = <0x80>;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
+ samsung,dw-mshc-hs200-timing = <0 2 3>;
bus-width = <8>;
};
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 12a5eaa..be6530e 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -40,6 +40,7 @@ struct dw_mci_exynos_priv_data {
u8 ciu_div;
u32 sdr_timing;
u32 ddr_timing;
+ u32 hs200_timing;
u32 cur_speed;
};
@@ -71,6 +72,21 @@ static struct dw_mci_exynos_compatible {
},
};
+static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
+ return EXYNOS4412_FIXED_CIU_CLK_DIV;
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+ return EXYNOS4210_FIXED_CIU_CLK_DIV;
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
+ else
+ return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
+}
+
static int dw_mci_exynos_priv_init(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
@@ -85,6 +101,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
}
+ priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
+
return 0;
}
@@ -92,7 +110,7 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
- host->bus_hz /= (priv->ciu_div + 1);
+ host->bus_hz /= priv->ciu_div;
return 0;
}
@@ -177,9 +195,14 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
struct dw_mci_exynos_priv_data *priv = host->priv;
unsigned int wanted = ios->clock;
unsigned long actual;
- u8 div = priv->ciu_div + 1;
- if (ios->timing == MMC_TIMING_MMC_DDR52) {
+ if (ios->timing == MMC_TIMING_MMC_HS200) {
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, priv->hs200_timing);
+ else
+ mci_writel(host, CLKSEL, priv->hs200_timing);
+ } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, priv->ddr_timing);
@@ -208,6 +231,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
wanted = EXYNOS_CCLKIN_MIN;
if (wanted != priv->cur_speed) {
+ u8 div = dw_mci_exynos_get_ciu_div(host);
int ret = clk_set_rate(host->ciu_clk, wanted * div);
if (ret)
dev_warn(host->dev,
@@ -220,14 +244,34 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
}
}
+static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
+ unsigned int ctrl_type,
+ const char *propname,
+ u32 *out_values)
+{
+ struct device_node *np = host->dev->of_node;
+ u32 timing[3];
+ int ret;
+
+ ret = of_property_read_u32_array(np, propname, timing, 3);
+ if (ret)
+ return ret;
+
+ if (ctrl_type == DW_MCI_TYPE_EXYNOS4412 ||
+ ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+ timing[2] = 0;
+
+ *out_values = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2]);
+
+ return 0;
+}
+
+
static int dw_mci_exynos_parse_dt(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv;
struct device_node *np = host->dev->of_node;
- u32 timing[2];
- u32 div = 0;
- int idx;
- int ret;
+ int idx, ret;
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -238,29 +282,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
priv->ctrl_type = exynos_compat[idx].ctrl_type;
}
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
- priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
- else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
- priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
- else {
- of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
- priv->ciu_div = div;
- }
-
- ret = of_property_read_u32_array(np,
- "samsung,dw-mshc-sdr-timing", timing, 2);
+ ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
+ "samsung,dw-mshc-sdr-timing", &priv->sdr_timing);
if (ret)
return ret;
- priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
-
- ret = of_property_read_u32_array(np,
- "samsung,dw-mshc-ddr-timing", timing, 2);
+ ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
+ "samsung,dw-mshc-ddr-timing", &priv->ddr_timing);
if (ret)
return ret;
- priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+ dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
+ "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
host->priv = priv;
+
return 0;
}
diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
index 7872ce5..c04ecef 100644
--- a/drivers/mmc/host/dw_mmc-exynos.h
+++ b/drivers/mmc/host/dw_mmc-exynos.h
@@ -21,6 +21,7 @@
#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
+#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
SDMMC_CLKSEL_CCLK_DRIVE(y) | \
SDMMC_CLKSEL_CCLK_DIVIDER(z))
--
1.7.9.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
@ 2014-12-31 6:43 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-arm-kernel
From: Seungwon Jeon <tgih.jun@samsung.com>
ciu_div may not be common value for all speed mode.
So, it needs to be attached to CLKSEL timing.
This also introduce a new compatibale 'dw-mshc-hs200-timing'
for selecting hs200 timing value
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
.../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
drivers/mmc/host/dw_mmc-exynos.h | 1 +
3 files changed, 67 insertions(+), 30 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
index ee4fc05..06455de 100644
--- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
@@ -23,10 +23,6 @@ Required Properties:
- "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
specific extensions having an SMU.
-* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
- unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
- ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
-
* samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
in transmit mode and CIU clock phase shift value in receive mode for single
data rate mode operation. Refer notes below for the order of the cells and the
@@ -37,11 +33,16 @@ Required Properties:
data rate mode operation. Refer notes below for the order of the cells and the
valid values.
+* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
+
Notes for the sdr-timing and ddr-timing values:
The order of the cells should be
- First Cell: CIU clock phase shift value for tx mode.
- Second Cell: CIU clock phase shift value for rx mode.
+ - Thrid Cell: Specifies the divider value for the card interface
+ unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
+ ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
Valid values for SDR and DDR CIU clock timing for Exynos5250:
- valid value for tx phase shift and rx phase shift is 0 to 7.
@@ -79,8 +80,8 @@ Example:
broken-cd;
fifo-depth = <0x80>;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
+ samsung,dw-mshc-hs200-timing = <0 2 3>;
bus-width = <8>;
};
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 12a5eaa..be6530e 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -40,6 +40,7 @@ struct dw_mci_exynos_priv_data {
u8 ciu_div;
u32 sdr_timing;
u32 ddr_timing;
+ u32 hs200_timing;
u32 cur_speed;
};
@@ -71,6 +72,21 @@ static struct dw_mci_exynos_compatible {
},
};
+static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
+ return EXYNOS4412_FIXED_CIU_CLK_DIV;
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+ return EXYNOS4210_FIXED_CIU_CLK_DIV;
+ else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
+ else
+ return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
+}
+
static int dw_mci_exynos_priv_init(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
@@ -85,6 +101,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
}
+ priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
+
return 0;
}
@@ -92,7 +110,7 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
- host->bus_hz /= (priv->ciu_div + 1);
+ host->bus_hz /= priv->ciu_div;
return 0;
}
@@ -177,9 +195,14 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
struct dw_mci_exynos_priv_data *priv = host->priv;
unsigned int wanted = ios->clock;
unsigned long actual;
- u8 div = priv->ciu_div + 1;
- if (ios->timing == MMC_TIMING_MMC_DDR52) {
+ if (ios->timing == MMC_TIMING_MMC_HS200) {
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, priv->hs200_timing);
+ else
+ mci_writel(host, CLKSEL, priv->hs200_timing);
+ } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, priv->ddr_timing);
@@ -208,6 +231,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
wanted = EXYNOS_CCLKIN_MIN;
if (wanted != priv->cur_speed) {
+ u8 div = dw_mci_exynos_get_ciu_div(host);
int ret = clk_set_rate(host->ciu_clk, wanted * div);
if (ret)
dev_warn(host->dev,
@@ -220,14 +244,34 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
}
}
+static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
+ unsigned int ctrl_type,
+ const char *propname,
+ u32 *out_values)
+{
+ struct device_node *np = host->dev->of_node;
+ u32 timing[3];
+ int ret;
+
+ ret = of_property_read_u32_array(np, propname, timing, 3);
+ if (ret)
+ return ret;
+
+ if (ctrl_type == DW_MCI_TYPE_EXYNOS4412 ||
+ ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+ timing[2] = 0;
+
+ *out_values = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2]);
+
+ return 0;
+}
+
+
static int dw_mci_exynos_parse_dt(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv;
struct device_node *np = host->dev->of_node;
- u32 timing[2];
- u32 div = 0;
- int idx;
- int ret;
+ int idx, ret;
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -238,29 +282,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
priv->ctrl_type = exynos_compat[idx].ctrl_type;
}
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
- priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
- else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
- priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
- else {
- of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
- priv->ciu_div = div;
- }
-
- ret = of_property_read_u32_array(np,
- "samsung,dw-mshc-sdr-timing", timing, 2);
+ ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
+ "samsung,dw-mshc-sdr-timing", &priv->sdr_timing);
if (ret)
return ret;
- priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
-
- ret = of_property_read_u32_array(np,
- "samsung,dw-mshc-ddr-timing", timing, 2);
+ ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
+ "samsung,dw-mshc-ddr-timing", &priv->ddr_timing);
if (ret)
return ret;
- priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+ dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
+ "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
host->priv = priv;
+
return 0;
}
diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
index 7872ce5..c04ecef 100644
--- a/drivers/mmc/host/dw_mmc-exynos.h
+++ b/drivers/mmc/host/dw_mmc-exynos.h
@@ -21,6 +21,7 @@
#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
+#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
SDMMC_CLKSEL_CCLK_DRIVE(y) | \
SDMMC_CLKSEL_CCLK_DIVIDER(z))
--
1.7.9.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v3 2/4] mmc: dw_mmc: exynos: support eMMC's HS400 mode
2014-12-31 6:43 ` Alim Akhtar
@ 2014-12-31 6:43 ` Alim Akhtar
-1 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-mmc
Cc: chris, ulf.hansson, jh80.chung, tgih.jun, dianders, alim.akhtar,
kgene, linux-arm-kernel, devicetree, linux-samsung-soc,
a.kesavan
From: Seungwon Jeon <tgih.jun@samsung.com>
Implements HS400 support for exynos host driver.
And this patch includes some updates as new mode is added.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
.../devicetree/bindings/mmc/exynos-dw-mshc.txt | 6 +
drivers/mmc/host/dw_mmc-exynos.c | 177 +++++++++++++++-----
drivers/mmc/host/dw_mmc-exynos.h | 17 +-
drivers/mmc/host/dw_mmc.c | 16 +-
drivers/mmc/host/dw_mmc.h | 2 +
5 files changed, 178 insertions(+), 40 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
index 06455de..be30c94 100644
--- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
@@ -34,6 +34,7 @@ Required Properties:
valid values.
* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
+* samsung,dw-mshc-hs400-timing: Similar with dw-mshc-ddr-timing.
Notes for the sdr-timing and ddr-timing values:
@@ -51,6 +52,9 @@ Required Properties:
- if CIU clock divider value is 0 (that is divide by 1), both tx and rx
phase shift clocks should be 0.
+* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
+ (Latency value for delay line in Read path)
+
Required properties for a slot (Deprecated - Recommend to use one slot per host):
* gpios: specifies a list of gpios used for command, clock and data bus. The
@@ -83,5 +87,7 @@ Example:
samsung,dw-mshc-sdr-timing = <2 3 3>;
samsung,dw-mshc-ddr-timing = <1 2 3>;
samsung,dw-mshc-hs200-timing = <0 2 3>;
+ samsung,dw-mshc-hs400-timing = <0 2 1>;
+ read-strobe-delay = <90>;
bus-width = <8>;
};
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index be6530e..d37a631 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -41,7 +41,12 @@ struct dw_mci_exynos_priv_data {
u32 sdr_timing;
u32 ddr_timing;
u32 hs200_timing;
+ u32 hs400_timing;
+ u32 tuned_sample;
u32 cur_speed;
+ u32 dqs_delay;
+ u32 saved_dqs_en;
+ u32 saved_strobe_ctrl;
};
static struct dw_mci_exynos_compatible {
@@ -101,6 +106,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
}
+ if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
+ priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
+ priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
+ priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
+ mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
+ if (!priv->dqs_delay)
+ priv->dqs_delay =
+ DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
+ }
+
priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
return 0;
@@ -115,6 +130,25 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
return 0;
}
+static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+ u32 clksel;
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+ clksel = mci_readl(host, CLKSEL);
+
+ clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+ mci_writel(host, CLKSEL, clksel);
+}
+
#ifdef CONFIG_PM_SLEEP
static int dw_mci_exynos_suspend(struct device *dev)
{
@@ -190,35 +224,37 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
}
}
-static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
- unsigned int wanted = ios->clock;
- unsigned long actual;
+ u32 dqs, strobe;
- if (ios->timing == MMC_TIMING_MMC_HS200) {
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
- mci_writel(host, CLKSEL64, priv->hs200_timing);
- else
- mci_writel(host, CLKSEL, priv->hs200_timing);
- } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
- mci_writel(host, CLKSEL64, priv->ddr_timing);
- else
- mci_writel(host, CLKSEL, priv->ddr_timing);
- /* Should be double rate for DDR mode */
- if (ios->bus_width == MMC_BUS_WIDTH_8)
- wanted <<= 1;
+ /*
+ * Exynos5420 and above controller supports HS400 mode
+ */
+ if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
+ return;
+
+ dqs = priv->saved_dqs_en;
+ strobe = priv->saved_strobe_ctrl;
+
+ if (timing == MMC_TIMING_MMC_HS400) {
+ dqs |= DATA_STROBE_EN;
+ strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
} else {
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
- mci_writel(host, CLKSEL64, priv->sdr_timing);
- else
- mci_writel(host, CLKSEL, priv->sdr_timing);
+ dqs &= ~DATA_STROBE_EN;
}
+ mci_writel(host, HS400_DQS_EN, dqs);
+ mci_writel(host, HS400_DLINE_CTRL, strobe);
+}
+
+static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+ unsigned long actual;
+ u8 div;
+ int ret;
/*
* Don't care if wanted clock is zero or
* ciu clock is unavailable
@@ -230,18 +266,55 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
if (wanted < EXYNOS_CCLKIN_MIN)
wanted = EXYNOS_CCLKIN_MIN;
- if (wanted != priv->cur_speed) {
- u8 div = dw_mci_exynos_get_ciu_div(host);
- int ret = clk_set_rate(host->ciu_clk, wanted * div);
- if (ret)
- dev_warn(host->dev,
- "failed to set clk-rate %u error: %d\n",
- wanted * div, ret);
- actual = clk_get_rate(host->ciu_clk);
- host->bus_hz = actual / div;
- priv->cur_speed = wanted;
- host->current_speed = 0;
+ if (wanted == priv->cur_speed)
+ return;
+
+ div = dw_mci_exynos_get_ciu_div(host);
+ ret = clk_set_rate(host->ciu_clk, wanted * div);
+ if (ret)
+ dev_warn(host->dev,
+ "failed to set clk-rate %u error: %d\n",
+ wanted * div, ret);
+ actual = clk_get_rate(host->ciu_clk);
+ host->bus_hz = actual / div;
+ priv->cur_speed = wanted;
+ host->current_speed = 0;
+}
+
+static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+ unsigned int wanted = ios->clock;
+ u32 timing = ios->timing, clksel;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS400:
+ /* Update tuned sample timing */
+ clksel = SDMMC_CLKSEL_UP_SAMPLE(
+ priv->hs400_timing, priv->tuned_sample);
+ wanted <<= 1;
+ break;
+ case MMC_TIMING_MMC_HS200:
+ clksel = priv->hs200_timing;
+ break;
+ case MMC_TIMING_MMC_DDR52:
+ clksel = priv->ddr_timing;
+ /* Should be double rate for DDR mode */
+ if (ios->bus_width == MMC_BUS_WIDTH_8)
+ wanted <<= 1;
+ break;
+ default:
+ clksel = priv->sdr_timing;
}
+
+ /* Set clock timing for the requested speed mode*/
+ dw_mci_exynos_set_clksel_timing(host, clksel);
+
+ /* Configure setting for HS400 */
+ dw_mci_exynos_config_hs400(host, timing);
+
+ /* Configure clock rate */
+ dw_mci_exynos_adjust_clock(host, wanted);
}
static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
@@ -294,6 +367,14 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
"samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
+
+ ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
+ "samsung,dw-mshc-hs400-timing", &priv->hs400_timing);
+ if (!ret && of_property_read_u32(np,
+ "read-strobe-delay", &priv->dqs_delay))
+ dev_info(host->dev,
+ "read-strobe-delay is not found, assuming usage of default value\n");
+
host->priv = priv;
return 0;
@@ -320,7 +401,9 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
clksel = mci_readl(host, CLKSEL64);
else
clksel = mci_readl(host, CLKSEL);
- clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
+
+ clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
+
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel);
@@ -339,13 +422,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
clksel = mci_readl(host, CLKSEL64);
else
clksel = mci_readl(host, CLKSEL);
+
sample = (clksel + 1) & 0x7;
- clksel = (clksel & ~0x7) | sample;
+ clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
+
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel);
else
mci_writel(host, CLKSEL, clksel);
+
return sample;
}
@@ -378,6 +464,7 @@ out:
static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
{
struct dw_mci *host = slot->host;
+ struct dw_mci_exynos_priv_data *priv = host->priv;
struct mmc_host *mmc = slot->mmc;
u8 start_smpl, smpl, candiates = 0;
s8 found = -1;
@@ -395,14 +482,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
} while (start_smpl != smpl);
found = dw_mci_exynos_get_best_clksmpl(candiates);
- if (found >= 0)
+ if (found >= 0) {
dw_mci_exynos_set_clksmpl(host, found);
- else
+ priv->tuned_sample = found;
+ } else {
ret = -EIO;
+ }
return ret;
}
+int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
+ struct mmc_ios *ios)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+
+ dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
+ dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
+
+ return 0;
+}
+
/* Common capabilities of Exynos4/Exynos5 SoC */
static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
@@ -419,6 +519,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
.set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt,
.execute_tuning = dw_mci_exynos_execute_tuning,
+ .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
};
static const struct of_device_id dw_mci_exynos_match[] = {
diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
index c04ecef..e7faffe 100644
--- a/drivers/mmc/host/dw_mmc-exynos.h
+++ b/drivers/mmc/host/dw_mmc-exynos.h
@@ -12,21 +12,36 @@
#ifndef _DW_MMC_EXYNOS_H_
#define _DW_MMC_EXYNOS_H_
-/* Extended Register's Offset */
#define SDMMC_CLKSEL 0x09C
#define SDMMC_CLKSEL64 0x0A8
+/* Extended Register's Offset */
+#define SDMMC_HS400_DQS_EN 0x180
+#define SDMMC_HS400_ASYNC_FIFO_CTRL 0x184
+#define SDMMC_HS400_DLINE_CTRL 0x188
+
/* CLKSEL register defines */
#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
+#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
+ SDMMC_CLKSEL_CCLK_SAMPLE(y))
#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
SDMMC_CLKSEL_CCLK_DRIVE(y) | \
SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
#define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
+/* HS400 control defines */
+#define DATA_STROBE_EN BIT(0)
+#define AXI_NON_BLOCKING_WR BIT(7)
+
+/* Delay Line Control defines */
+#define DQS_CTRL_RD_DELAY(x, y) (((x) & ~0x3FF) | ((y) & 0x3FF))
+#define DQS_CTRL_GET_RD_DELAY(x) ((x) & 0x3FF)
+
/* Protector Register */
#define SDMMC_EMMCP_BASE 0x1000
#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 2e8abc8..43a3a5b 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
regs = mci_readl(slot->host, UHS_REG);
/* DDR mode set */
- if (ios->timing == MMC_TIMING_MMC_DDR52)
+ if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+ ios->timing == MMC_TIMING_MMC_HS400)
regs |= ((0x1 << slot->id) << 16);
else
regs &= ~((0x1 << slot->id) << 16);
@@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
return err;
}
+int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
+
+ if (drv_data && drv_data->prepare_hs400_tuning)
+ return drv_data->prepare_hs400_tuning(host, ios);
+
+ return 0;
+}
+
static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request,
.pre_req = dw_mci_pre_req,
@@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
.card_busy = dw_mci_card_busy,
.start_signal_voltage_switch = dw_mci_switch_voltage,
.init_card = dw_mci_init_card,
+ .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
};
static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 18c4afe..d239867 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -271,5 +271,7 @@ struct dw_mci_drv_data {
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 (*prepare_hs400_tuning)(struct dw_mci *host,
+ struct mmc_ios *ios);
};
#endif /* _DW_MMC_H_ */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v3 2/4] mmc: dw_mmc: exynos: support eMMC's HS400 mode
@ 2014-12-31 6:43 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-arm-kernel
From: Seungwon Jeon <tgih.jun@samsung.com>
Implements HS400 support for exynos host driver.
And this patch includes some updates as new mode is added.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
.../devicetree/bindings/mmc/exynos-dw-mshc.txt | 6 +
drivers/mmc/host/dw_mmc-exynos.c | 177 +++++++++++++++-----
drivers/mmc/host/dw_mmc-exynos.h | 17 +-
drivers/mmc/host/dw_mmc.c | 16 +-
drivers/mmc/host/dw_mmc.h | 2 +
5 files changed, 178 insertions(+), 40 deletions(-)
diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
index 06455de..be30c94 100644
--- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
@@ -34,6 +34,7 @@ Required Properties:
valid values.
* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
+* samsung,dw-mshc-hs400-timing: Similar with dw-mshc-ddr-timing.
Notes for the sdr-timing and ddr-timing values:
@@ -51,6 +52,9 @@ Required Properties:
- if CIU clock divider value is 0 (that is divide by 1), both tx and rx
phase shift clocks should be 0.
+* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
+ (Latency value for delay line in Read path)
+
Required properties for a slot (Deprecated - Recommend to use one slot per host):
* gpios: specifies a list of gpios used for command, clock and data bus. The
@@ -83,5 +87,7 @@ Example:
samsung,dw-mshc-sdr-timing = <2 3 3>;
samsung,dw-mshc-ddr-timing = <1 2 3>;
samsung,dw-mshc-hs200-timing = <0 2 3>;
+ samsung,dw-mshc-hs400-timing = <0 2 1>;
+ read-strobe-delay = <90>;
bus-width = <8>;
};
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index be6530e..d37a631 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -41,7 +41,12 @@ struct dw_mci_exynos_priv_data {
u32 sdr_timing;
u32 ddr_timing;
u32 hs200_timing;
+ u32 hs400_timing;
+ u32 tuned_sample;
u32 cur_speed;
+ u32 dqs_delay;
+ u32 saved_dqs_en;
+ u32 saved_strobe_ctrl;
};
static struct dw_mci_exynos_compatible {
@@ -101,6 +106,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
}
+ if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
+ priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
+ priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
+ priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
+ mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
+ if (!priv->dqs_delay)
+ priv->dqs_delay =
+ DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
+ }
+
priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
return 0;
@@ -115,6 +130,25 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
return 0;
}
+static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+ u32 clksel;
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+ clksel = mci_readl(host, CLKSEL);
+
+ clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+ mci_writel(host, CLKSEL, clksel);
+}
+
#ifdef CONFIG_PM_SLEEP
static int dw_mci_exynos_suspend(struct device *dev)
{
@@ -190,35 +224,37 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
}
}
-static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
- unsigned int wanted = ios->clock;
- unsigned long actual;
+ u32 dqs, strobe;
- if (ios->timing == MMC_TIMING_MMC_HS200) {
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
- mci_writel(host, CLKSEL64, priv->hs200_timing);
- else
- mci_writel(host, CLKSEL, priv->hs200_timing);
- } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
- mci_writel(host, CLKSEL64, priv->ddr_timing);
- else
- mci_writel(host, CLKSEL, priv->ddr_timing);
- /* Should be double rate for DDR mode */
- if (ios->bus_width == MMC_BUS_WIDTH_8)
- wanted <<= 1;
+ /*
+ * Exynos5420 and above controller supports HS400 mode
+ */
+ if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
+ return;
+
+ dqs = priv->saved_dqs_en;
+ strobe = priv->saved_strobe_ctrl;
+
+ if (timing == MMC_TIMING_MMC_HS400) {
+ dqs |= DATA_STROBE_EN;
+ strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
} else {
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
- priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
- mci_writel(host, CLKSEL64, priv->sdr_timing);
- else
- mci_writel(host, CLKSEL, priv->sdr_timing);
+ dqs &= ~DATA_STROBE_EN;
}
+ mci_writel(host, HS400_DQS_EN, dqs);
+ mci_writel(host, HS400_DLINE_CTRL, strobe);
+}
+
+static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+ unsigned long actual;
+ u8 div;
+ int ret;
/*
* Don't care if wanted clock is zero or
* ciu clock is unavailable
@@ -230,18 +266,55 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
if (wanted < EXYNOS_CCLKIN_MIN)
wanted = EXYNOS_CCLKIN_MIN;
- if (wanted != priv->cur_speed) {
- u8 div = dw_mci_exynos_get_ciu_div(host);
- int ret = clk_set_rate(host->ciu_clk, wanted * div);
- if (ret)
- dev_warn(host->dev,
- "failed to set clk-rate %u error: %d\n",
- wanted * div, ret);
- actual = clk_get_rate(host->ciu_clk);
- host->bus_hz = actual / div;
- priv->cur_speed = wanted;
- host->current_speed = 0;
+ if (wanted == priv->cur_speed)
+ return;
+
+ div = dw_mci_exynos_get_ciu_div(host);
+ ret = clk_set_rate(host->ciu_clk, wanted * div);
+ if (ret)
+ dev_warn(host->dev,
+ "failed to set clk-rate %u error: %d\n",
+ wanted * div, ret);
+ actual = clk_get_rate(host->ciu_clk);
+ host->bus_hz = actual / div;
+ priv->cur_speed = wanted;
+ host->current_speed = 0;
+}
+
+static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+ unsigned int wanted = ios->clock;
+ u32 timing = ios->timing, clksel;
+
+ switch (timing) {
+ case MMC_TIMING_MMC_HS400:
+ /* Update tuned sample timing */
+ clksel = SDMMC_CLKSEL_UP_SAMPLE(
+ priv->hs400_timing, priv->tuned_sample);
+ wanted <<= 1;
+ break;
+ case MMC_TIMING_MMC_HS200:
+ clksel = priv->hs200_timing;
+ break;
+ case MMC_TIMING_MMC_DDR52:
+ clksel = priv->ddr_timing;
+ /* Should be double rate for DDR mode */
+ if (ios->bus_width == MMC_BUS_WIDTH_8)
+ wanted <<= 1;
+ break;
+ default:
+ clksel = priv->sdr_timing;
}
+
+ /* Set clock timing for the requested speed mode*/
+ dw_mci_exynos_set_clksel_timing(host, clksel);
+
+ /* Configure setting for HS400 */
+ dw_mci_exynos_config_hs400(host, timing);
+
+ /* Configure clock rate */
+ dw_mci_exynos_adjust_clock(host, wanted);
}
static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
@@ -294,6 +367,14 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
"samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
+
+ ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
+ "samsung,dw-mshc-hs400-timing", &priv->hs400_timing);
+ if (!ret && of_property_read_u32(np,
+ "read-strobe-delay", &priv->dqs_delay))
+ dev_info(host->dev,
+ "read-strobe-delay is not found, assuming usage of default value\n");
+
host->priv = priv;
return 0;
@@ -320,7 +401,9 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
clksel = mci_readl(host, CLKSEL64);
else
clksel = mci_readl(host, CLKSEL);
- clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
+
+ clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
+
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel);
@@ -339,13 +422,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
clksel = mci_readl(host, CLKSEL64);
else
clksel = mci_readl(host, CLKSEL);
+
sample = (clksel + 1) & 0x7;
- clksel = (clksel & ~0x7) | sample;
+ clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
+
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel);
else
mci_writel(host, CLKSEL, clksel);
+
return sample;
}
@@ -378,6 +464,7 @@ out:
static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
{
struct dw_mci *host = slot->host;
+ struct dw_mci_exynos_priv_data *priv = host->priv;
struct mmc_host *mmc = slot->mmc;
u8 start_smpl, smpl, candiates = 0;
s8 found = -1;
@@ -395,14 +482,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
} while (start_smpl != smpl);
found = dw_mci_exynos_get_best_clksmpl(candiates);
- if (found >= 0)
+ if (found >= 0) {
dw_mci_exynos_set_clksmpl(host, found);
- else
+ priv->tuned_sample = found;
+ } else {
ret = -EIO;
+ }
return ret;
}
+int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
+ struct mmc_ios *ios)
+{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+
+ dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
+ dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
+
+ return 0;
+}
+
/* Common capabilities of Exynos4/Exynos5 SoC */
static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
@@ -419,6 +519,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
.set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt,
.execute_tuning = dw_mci_exynos_execute_tuning,
+ .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
};
static const struct of_device_id dw_mci_exynos_match[] = {
diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
index c04ecef..e7faffe 100644
--- a/drivers/mmc/host/dw_mmc-exynos.h
+++ b/drivers/mmc/host/dw_mmc-exynos.h
@@ -12,21 +12,36 @@
#ifndef _DW_MMC_EXYNOS_H_
#define _DW_MMC_EXYNOS_H_
-/* Extended Register's Offset */
#define SDMMC_CLKSEL 0x09C
#define SDMMC_CLKSEL64 0x0A8
+/* Extended Register's Offset */
+#define SDMMC_HS400_DQS_EN 0x180
+#define SDMMC_HS400_ASYNC_FIFO_CTRL 0x184
+#define SDMMC_HS400_DLINE_CTRL 0x188
+
/* CLKSEL register defines */
#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
+#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
+ SDMMC_CLKSEL_CCLK_SAMPLE(y))
#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
SDMMC_CLKSEL_CCLK_DRIVE(y) | \
SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
#define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
+/* HS400 control defines */
+#define DATA_STROBE_EN BIT(0)
+#define AXI_NON_BLOCKING_WR BIT(7)
+
+/* Delay Line Control defines */
+#define DQS_CTRL_RD_DELAY(x, y) (((x) & ~0x3FF) | ((y) & 0x3FF))
+#define DQS_CTRL_GET_RD_DELAY(x) ((x) & 0x3FF)
+
/* Protector Register */
#define SDMMC_EMMCP_BASE 0x1000
#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 2e8abc8..43a3a5b 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
regs = mci_readl(slot->host, UHS_REG);
/* DDR mode set */
- if (ios->timing == MMC_TIMING_MMC_DDR52)
+ if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+ ios->timing == MMC_TIMING_MMC_HS400)
regs |= ((0x1 << slot->id) << 16);
else
regs &= ~((0x1 << slot->id) << 16);
@@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
return err;
}
+int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
+
+ if (drv_data && drv_data->prepare_hs400_tuning)
+ return drv_data->prepare_hs400_tuning(host, ios);
+
+ return 0;
+}
+
static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request,
.pre_req = dw_mci_pre_req,
@@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
.card_busy = dw_mci_card_busy,
.start_signal_voltage_switch = dw_mci_switch_voltage,
.init_card = dw_mci_init_card,
+ .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
};
static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 18c4afe..d239867 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -271,5 +271,7 @@ struct dw_mci_drv_data {
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 (*prepare_hs400_tuning)(struct dw_mci *host,
+ struct mmc_ios *ios);
};
#endif /* _DW_MMC_H_ */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v3 3/4] ARM: dts: drop dw-mshc-ciu-div property from Exynos
2014-12-31 6:43 ` Alim Akhtar
@ 2014-12-31 6:43 ` Alim Akhtar
-1 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-mmc
Cc: chris, ulf.hansson, jh80.chung, tgih.jun, dianders, alim.akhtar,
kgene, linux-arm-kernel, devicetree, linux-samsung-soc,
a.kesavan
From: Seungwon Jeon <tgih.jun@samsung.com>
As dw-mshc-ciu-div is strongly close to timing property,
it is merged with each timing property.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
arch/arm/boot/dts/exynos3250-monk.dts | 5 ++---
arch/arm/boot/dts/exynos3250-rinato.dts | 5 ++---
arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 5 ++---
arch/arm/boot/dts/exynos4412-origen.dts | 5 ++---
arch/arm/boot/dts/exynos4412-trats2.dts | 5 ++---
arch/arm/boot/dts/exynos5250-arndale.dts | 10 ++++------
arch/arm/boot/dts/exynos5250-smdk5250.dts | 10 ++++------
arch/arm/boot/dts/exynos5250-snow.dts | 15 ++++++---------
arch/arm/boot/dts/exynos5250-spring.dts | 10 ++++------
arch/arm/boot/dts/exynos5260-xyref5260.dts | 10 ++++------
arch/arm/boot/dts/exynos5410-smdk5410.dts | 10 ++++------
arch/arm/boot/dts/exynos5420-arndale-octa.dts | 10 ++++------
arch/arm/boot/dts/exynos5420-peach-pit.dts | 10 ++++------
arch/arm/boot/dts/exynos5420-smdk5420.dts | 10 ++++------
arch/arm/boot/dts/exynos5800-peach-pi.dts | 10 ++++------
15 files changed, 52 insertions(+), 78 deletions(-)
diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts
index 24822aa..faeca4f 100644
--- a/arch/arm/boot/dts/exynos3250-monk.dts
+++ b/arch/arm/boot/dts/exynos3250-monk.dts
@@ -390,9 +390,8 @@
vmmc-supply = <&vemmc_reg>;
clock-frequency = <100000000>;
clock-freq-min-max = <400000 100000000>;
- samsung,dw-mshc-ciu-div = <1>;
- samsung,dw-mshc-sdr-timing = <0 1>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <0 1 1>;
+ samsung,dw-mshc-ddr-timing = <1 2 1>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 80aa8b4..8578d26 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -493,9 +493,8 @@
vmmc-supply = <&ldo12_reg>;
clock-frequency = <100000000>;
clock-freq-min-max = <400000 100000000>;
- samsung,dw-mshc-ciu-div = <1>;
- samsung,dw-mshc-sdr-timing = <0 1>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <0 1 1>;
+ samsung,dw-mshc-ddr-timing = <1 2 1>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index 3fbf588..5d82a81 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -66,9 +66,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
bus-width = <8>;
cap-mmc-highspeed;
};
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts
index de15114..bd4a672 100644
--- a/arch/arm/boot/dts/exynos4412-origen.dts
+++ b/arch/arm/boot/dts/exynos4412-origen.dts
@@ -139,9 +139,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
bus-width = <8>;
cap-mmc-highspeed;
};
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 29231b4..fada9f6 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -559,9 +559,8 @@
card-detect-delay = <200>;
vmmc-supply = <&vemmc_reg>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <0>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 0>;
+ samsung,dw-mshc-ddr-timing = <1 2 0>;
pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
pinctrl-names = "default";
status = "okay";
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index 7e728a1..afbe508 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -523,9 +523,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
vmmc-supply = <&mmc_reg>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
@@ -537,9 +536,8 @@
status = "okay";
num-slots = <1>;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
vmmc-supply = <&mmc_reg>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index bc27cc2..6c2180e 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -347,9 +347,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -360,9 +359,8 @@
status = "okay";
num-slots = <1>;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index effaf2a..812959c 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -498,9 +498,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -511,9 +510,8 @@
status = "okay";
num-slots = <1>;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
@@ -530,9 +528,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd3_clk &sd3_cmd &sd3_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts
index f027754..5bac70b 100644
--- a/arch/arm/boot/dts/exynos5250-spring.dts
+++ b/arch/arm/boot/dts/exynos5250-spring.dts
@@ -432,9 +432,8 @@
supports-highspeed;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_bus4 &sd0_bus8>;
@@ -454,9 +453,8 @@
supports-highspeed;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd1_clk &sd1_cmd &sd1_cd &sd1_bus4>;
diff --git a/arch/arm/boot/dts/exynos5260-xyref5260.dts b/arch/arm/boot/dts/exynos5260-xyref5260.dts
index a803b60..6ee8b86 100644
--- a/arch/arm/boot/dts/exynos5260-xyref5260.dts
+++ b/arch/arm/boot/dts/exynos5260-xyref5260.dts
@@ -72,9 +72,8 @@
cap-mmc-highspeed;
supports-hs200-mode; /* 200 Mhz */
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_rdqs &sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -85,9 +84,8 @@
num-slots = <1>;
cap-sd-highspeed;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5410-smdk5410.dts b/arch/arm/boot/dts/exynos5410-smdk5410.dts
index be3e025..e0956b2 100644
--- a/arch/arm/boot/dts/exynos5410-smdk5410.dts
+++ b/arch/arm/boot/dts/exynos5410-smdk5410.dts
@@ -43,9 +43,8 @@
cap-mmc-highspeed;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
bus-width = <8>;
};
@@ -54,9 +53,8 @@
num-slots = <1>;
cap-sd-highspeed;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
bus-width = <4>;
disable-wp;
};
diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
index aa7a7d7..2e7ecce 100644
--- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts
+++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
@@ -51,9 +51,8 @@
status = "okay";
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
vmmc-supply = <&ldo10_reg>;
@@ -64,9 +63,8 @@
mmc@12220000 {
status = "okay";
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
vmmc-supply = <&ldo19_reg>;
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index 9a050e1..e9f5a6c 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -566,9 +566,8 @@
non-removable;
card-detect-delay = <200>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -580,9 +579,8 @@
cap-sd-highspeed;
card-detect-delay = <200>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index 8be3d7b..140ea54 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -77,9 +77,8 @@
status = "okay";
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -89,9 +88,8 @@
mmc@12220000 {
status = "okay";
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index e8fdda8..9a4875b 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -554,9 +554,8 @@
non-removable;
card-detect-delay = <200>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -568,9 +567,8 @@
cap-sd-highspeed;
card-detect-delay = <200>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v3 3/4] ARM: dts: drop dw-mshc-ciu-div property from Exynos
@ 2014-12-31 6:43 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-arm-kernel
From: Seungwon Jeon <tgih.jun@samsung.com>
As dw-mshc-ciu-div is strongly close to timing property,
it is merged with each timing property.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
arch/arm/boot/dts/exynos3250-monk.dts | 5 ++---
arch/arm/boot/dts/exynos3250-rinato.dts | 5 ++---
arch/arm/boot/dts/exynos4412-odroid-common.dtsi | 5 ++---
arch/arm/boot/dts/exynos4412-origen.dts | 5 ++---
arch/arm/boot/dts/exynos4412-trats2.dts | 5 ++---
arch/arm/boot/dts/exynos5250-arndale.dts | 10 ++++------
arch/arm/boot/dts/exynos5250-smdk5250.dts | 10 ++++------
arch/arm/boot/dts/exynos5250-snow.dts | 15 ++++++---------
arch/arm/boot/dts/exynos5250-spring.dts | 10 ++++------
arch/arm/boot/dts/exynos5260-xyref5260.dts | 10 ++++------
arch/arm/boot/dts/exynos5410-smdk5410.dts | 10 ++++------
arch/arm/boot/dts/exynos5420-arndale-octa.dts | 10 ++++------
arch/arm/boot/dts/exynos5420-peach-pit.dts | 10 ++++------
arch/arm/boot/dts/exynos5420-smdk5420.dts | 10 ++++------
arch/arm/boot/dts/exynos5800-peach-pi.dts | 10 ++++------
15 files changed, 52 insertions(+), 78 deletions(-)
diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts
index 24822aa..faeca4f 100644
--- a/arch/arm/boot/dts/exynos3250-monk.dts
+++ b/arch/arm/boot/dts/exynos3250-monk.dts
@@ -390,9 +390,8 @@
vmmc-supply = <&vemmc_reg>;
clock-frequency = <100000000>;
clock-freq-min-max = <400000 100000000>;
- samsung,dw-mshc-ciu-div = <1>;
- samsung,dw-mshc-sdr-timing = <0 1>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <0 1 1>;
+ samsung,dw-mshc-ddr-timing = <1 2 1>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 80aa8b4..8578d26 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -493,9 +493,8 @@
vmmc-supply = <&ldo12_reg>;
clock-frequency = <100000000>;
clock-freq-min-max = <400000 100000000>;
- samsung,dw-mshc-ciu-div = <1>;
- samsung,dw-mshc-sdr-timing = <0 1>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <0 1 1>;
+ samsung,dw-mshc-ddr-timing = <1 2 1>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index 3fbf588..5d82a81 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -66,9 +66,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
bus-width = <8>;
cap-mmc-highspeed;
};
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts
index de15114..bd4a672 100644
--- a/arch/arm/boot/dts/exynos4412-origen.dts
+++ b/arch/arm/boot/dts/exynos4412-origen.dts
@@ -139,9 +139,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
bus-width = <8>;
cap-mmc-highspeed;
};
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 29231b4..fada9f6 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -559,9 +559,8 @@
card-detect-delay = <200>;
vmmc-supply = <&vemmc_reg>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <0>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 0>;
+ samsung,dw-mshc-ddr-timing = <1 2 0>;
pinctrl-0 = <&sd4_clk &sd4_cmd &sd4_bus4 &sd4_bus8>;
pinctrl-names = "default";
status = "okay";
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index 7e728a1..afbe508 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -523,9 +523,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
vmmc-supply = <&mmc_reg>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
@@ -537,9 +536,8 @@
status = "okay";
num-slots = <1>;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
vmmc-supply = <&mmc_reg>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index bc27cc2..6c2180e 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -347,9 +347,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -360,9 +359,8 @@
status = "okay";
num-slots = <1>;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index effaf2a..812959c 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -498,9 +498,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -511,9 +510,8 @@
status = "okay";
num-slots = <1>;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
@@ -530,9 +528,8 @@
num-slots = <1>;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd3_clk &sd3_cmd &sd3_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts
index f027754..5bac70b 100644
--- a/arch/arm/boot/dts/exynos5250-spring.dts
+++ b/arch/arm/boot/dts/exynos5250-spring.dts
@@ -432,9 +432,8 @@
supports-highspeed;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_bus4 &sd0_bus8>;
@@ -454,9 +453,8 @@
supports-highspeed;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd1_clk &sd1_cmd &sd1_cd &sd1_bus4>;
diff --git a/arch/arm/boot/dts/exynos5260-xyref5260.dts b/arch/arm/boot/dts/exynos5260-xyref5260.dts
index a803b60..6ee8b86 100644
--- a/arch/arm/boot/dts/exynos5260-xyref5260.dts
+++ b/arch/arm/boot/dts/exynos5260-xyref5260.dts
@@ -72,9 +72,8 @@
cap-mmc-highspeed;
supports-hs200-mode; /* 200 Mhz */
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_rdqs &sd0_clk &sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -85,9 +84,8 @@
num-slots = <1>;
cap-sd-highspeed;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus1 &sd2_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5410-smdk5410.dts b/arch/arm/boot/dts/exynos5410-smdk5410.dts
index be3e025..e0956b2 100644
--- a/arch/arm/boot/dts/exynos5410-smdk5410.dts
+++ b/arch/arm/boot/dts/exynos5410-smdk5410.dts
@@ -43,9 +43,8 @@
cap-mmc-highspeed;
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
bus-width = <8>;
};
@@ -54,9 +53,8 @@
num-slots = <1>;
cap-sd-highspeed;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
bus-width = <4>;
disable-wp;
};
diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
index aa7a7d7..2e7ecce 100644
--- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts
+++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
@@ -51,9 +51,8 @@
status = "okay";
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
vmmc-supply = <&ldo10_reg>;
@@ -64,9 +63,8 @@
mmc at 12220000 {
status = "okay";
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
vmmc-supply = <&ldo19_reg>;
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index 9a050e1..e9f5a6c 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -566,9 +566,8 @@
non-removable;
card-detect-delay = <200>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -580,9 +579,8 @@
cap-sd-highspeed;
card-detect-delay = <200>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index 8be3d7b..140ea54 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -77,9 +77,8 @@
status = "okay";
broken-cd;
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -89,9 +88,8 @@
mmc at 12220000 {
status = "okay";
card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index e8fdda8..9a4875b 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -554,9 +554,8 @@
non-removable;
card-detect-delay = <200>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <0 4>;
- samsung,dw-mshc-ddr-timing = <0 2>;
+ samsung,dw-mshc-sdr-timing = <0 4 3>;
+ samsung,dw-mshc-ddr-timing = <0 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
bus-width = <8>;
@@ -568,9 +567,8 @@
cap-sd-highspeed;
card-detect-delay = <200>;
clock-frequency = <400000000>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
+ samsung,dw-mshc-sdr-timing = <2 3 3>;
+ samsung,dw-mshc-ddr-timing = <1 2 3>;
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v3 4/4] ARM: dts: add HS400 support for Exynos5420 and exynos5800
2014-12-31 6:43 ` Alim Akhtar
@ 2014-12-31 6:43 ` Alim Akhtar
-1 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-mmc
Cc: chris, ulf.hansson, jh80.chung, tgih.jun, dianders, alim.akhtar,
kgene, linux-arm-kernel, devicetree, linux-samsung-soc,
a.kesavan
From: Seungwon Jeon <tgih.jun@samsung.com>
HS400 timing value set is added for SMDK5420, peach-pit and
exynos5800 peach-pi.
And GPIO line for RCLK should be pull-down state.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
arch/arm/boot/dts/exynos5420-peach-pit.dts | 5 ++++-
arch/arm/boot/dts/exynos5420-pinctrl.dtsi | 7 +++++++
arch/arm/boot/dts/exynos5420-smdk5420.dts | 5 ++++-
arch/arm/boot/dts/exynos5800-peach-pi.dts | 5 ++++-
4 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index e9f5a6c..151ae7d 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -568,8 +568,11 @@
clock-frequency = <400000000>;
samsung,dw-mshc-sdr-timing = <0 4 3>;
samsung,dw-mshc-ddr-timing = <0 2 3>;
+ samsung,dw-mshc-hs200-timing = <0 2 3>;
+ samsung,dw-mshc-hs400-timing = <0 2 1>;
+ read-strobe-delay = <90>;
pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
bus-width = <8>;
};
diff --git a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
index ba686e4..dd85fe2 100644
--- a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
@@ -194,6 +194,13 @@
samsung,pin-drv = <3>;
};
+ sd0_rclk: sd0-rclk {
+ samsung,pins = "gpc0-7";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <3>;
+ };
+
sd1_clk: sd1-clk {
samsung,pins = "gpc1-0";
samsung,pin-function = <2>;
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index 140ea54..685e2a4 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -79,8 +79,11 @@
card-detect-delay = <200>;
samsung,dw-mshc-sdr-timing = <0 4 3>;
samsung,dw-mshc-ddr-timing = <0 2 3>;
+ samsung,dw-mshc-hs200-timing = <0 2 3>;
+ samsung,dw-mshc-hs400-timing = <0 2 1>;
+ read-strobe-delay = <90>;
pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
bus-width = <8>;
cap-mmc-highspeed;
};
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 9a4875b..28d4109 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -556,8 +556,11 @@
clock-frequency = <400000000>;
samsung,dw-mshc-sdr-timing = <0 4 3>;
samsung,dw-mshc-ddr-timing = <0 2 3>;
+ samsung,dw-mshc-hs200-timing = <0 2 3>;
+ samsung,dw-mshc-hs400-timing = <0 2 1>;
+ read-strobe-delay = <90>;
pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
bus-width = <8>;
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v3 4/4] ARM: dts: add HS400 support for Exynos5420 and exynos5800
@ 2014-12-31 6:43 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2014-12-31 6:43 UTC (permalink / raw)
To: linux-arm-kernel
From: Seungwon Jeon <tgih.jun@samsung.com>
HS400 timing value set is added for SMDK5420, peach-pit and
exynos5800 peach-pi.
And GPIO line for RCLK should be pull-down state.
Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
---
arch/arm/boot/dts/exynos5420-peach-pit.dts | 5 ++++-
arch/arm/boot/dts/exynos5420-pinctrl.dtsi | 7 +++++++
arch/arm/boot/dts/exynos5420-smdk5420.dts | 5 ++++-
arch/arm/boot/dts/exynos5800-peach-pi.dts | 5 ++++-
4 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index e9f5a6c..151ae7d 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -568,8 +568,11 @@
clock-frequency = <400000000>;
samsung,dw-mshc-sdr-timing = <0 4 3>;
samsung,dw-mshc-ddr-timing = <0 2 3>;
+ samsung,dw-mshc-hs200-timing = <0 2 3>;
+ samsung,dw-mshc-hs400-timing = <0 2 1>;
+ read-strobe-delay = <90>;
pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
bus-width = <8>;
};
diff --git a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
index ba686e4..dd85fe2 100644
--- a/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos5420-pinctrl.dtsi
@@ -194,6 +194,13 @@
samsung,pin-drv = <3>;
};
+ sd0_rclk: sd0-rclk {
+ samsung,pins = "gpc0-7";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <3>;
+ };
+
sd1_clk: sd1-clk {
samsung,pins = "gpc1-0";
samsung,pin-function = <2>;
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index 140ea54..685e2a4 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -79,8 +79,11 @@
card-detect-delay = <200>;
samsung,dw-mshc-sdr-timing = <0 4 3>;
samsung,dw-mshc-ddr-timing = <0 2 3>;
+ samsung,dw-mshc-hs200-timing = <0 2 3>;
+ samsung,dw-mshc-hs400-timing = <0 2 1>;
+ read-strobe-delay = <90>;
pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
bus-width = <8>;
cap-mmc-highspeed;
};
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 9a4875b..28d4109 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -556,8 +556,11 @@
clock-frequency = <400000000>;
samsung,dw-mshc-sdr-timing = <0 4 3>;
samsung,dw-mshc-ddr-timing = <0 2 3>;
+ samsung,dw-mshc-hs200-timing = <0 2 3>;
+ samsung,dw-mshc-hs400-timing = <0 2 1>;
+ read-strobe-delay = <90>;
pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8 &sd0_rclk>;
bus-width = <8>;
};
--
1.7.9.5
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
2014-12-31 6:43 ` Alim Akhtar
@ 2015-01-02 10:30 ` Ulf Hansson
-1 siblings, 0 replies; 28+ messages in thread
From: Ulf Hansson @ 2015-01-02 10:30 UTC (permalink / raw)
To: Alim Akhtar
Cc: linux-mmc, Chris Ball, Jaehoon Chung, tgih.jun, Doug Anderson,
Alim Akhtar, Kukjin Kim, linux-arm-kernel, devicetree,
linux-samsung-soc, ABHILASH KESAVAN
On 31 December 2014 at 07:43, Alim Akhtar <alim.akhtar@samsung.com> wrote:
> From: Seungwon Jeon <tgih.jun@samsung.com>
>
> ciu_div may not be common value for all speed mode.
> So, it needs to be attached to CLKSEL timing.
> This also introduce a new compatibale 'dw-mshc-hs200-timing'
> for selecting hs200 timing value
According to the patch you are adding a new DT property not a
"compatible". Please update the commit message.
The rest looks good to me.
Kind regards
Uffe
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
> drivers/mmc/host/dw_mmc-exynos.h | 1 +
> 3 files changed, 67 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> index ee4fc05..06455de 100644
> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> @@ -23,10 +23,6 @@ Required Properties:
> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
> specific extensions having an SMU.
>
> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
> -
> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
> in transmit mode and CIU clock phase shift value in receive mode for single
> data rate mode operation. Refer notes below for the order of the cells and the
> @@ -37,11 +33,16 @@ Required Properties:
> data rate mode operation. Refer notes below for the order of the cells and the
> valid values.
>
> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
> +
> Notes for the sdr-timing and ddr-timing values:
>
> The order of the cells should be
> - First Cell: CIU clock phase shift value for tx mode.
> - Second Cell: CIU clock phase shift value for rx mode.
> + - Thrid Cell: Specifies the divider value for the card interface
> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>
> Valid values for SDR and DDR CIU clock timing for Exynos5250:
> - valid value for tx phase shift and rx phase shift is 0 to 7.
> @@ -79,8 +80,8 @@ Example:
> broken-cd;
> fifo-depth = <0x80>;
> card-detect-delay = <200>;
> - samsung,dw-mshc-ciu-div = <3>;
> - samsung,dw-mshc-sdr-timing = <2 3>;
> - samsung,dw-mshc-ddr-timing = <1 2>;
> + samsung,dw-mshc-sdr-timing = <2 3 3>;
> + samsung,dw-mshc-ddr-timing = <1 2 3>;
> + samsung,dw-mshc-hs200-timing = <0 2 3>;
> bus-width = <8>;
> };
> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
> index 12a5eaa..be6530e 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.c
> +++ b/drivers/mmc/host/dw_mmc-exynos.c
> @@ -40,6 +40,7 @@ struct dw_mci_exynos_priv_data {
> u8 ciu_div;
> u32 sdr_timing;
> u32 ddr_timing;
> + u32 hs200_timing;
> u32 cur_speed;
> };
>
> @@ -71,6 +72,21 @@ static struct dw_mci_exynos_compatible {
> },
> };
>
> +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> +
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
> + return EXYNOS4412_FIXED_CIU_CLK_DIV;
> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> + return EXYNOS4210_FIXED_CIU_CLK_DIV;
> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
> + else
> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
> +}
> +
> static int dw_mci_exynos_priv_init(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
> @@ -85,6 +101,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
> }
>
> + priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
> +
> return 0;
> }
>
> @@ -92,7 +110,7 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
>
> - host->bus_hz /= (priv->ciu_div + 1);
> + host->bus_hz /= priv->ciu_div;
>
> return 0;
> }
> @@ -177,9 +195,14 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> struct dw_mci_exynos_priv_data *priv = host->priv;
> unsigned int wanted = ios->clock;
> unsigned long actual;
> - u8 div = priv->ciu_div + 1;
>
> - if (ios->timing == MMC_TIMING_MMC_DDR52) {
> + if (ios->timing == MMC_TIMING_MMC_HS200) {
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + mci_writel(host, CLKSEL64, priv->hs200_timing);
> + else
> + mci_writel(host, CLKSEL, priv->hs200_timing);
> + } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> mci_writel(host, CLKSEL64, priv->ddr_timing);
> @@ -208,6 +231,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> wanted = EXYNOS_CCLKIN_MIN;
>
> if (wanted != priv->cur_speed) {
> + u8 div = dw_mci_exynos_get_ciu_div(host);
> int ret = clk_set_rate(host->ciu_clk, wanted * div);
> if (ret)
> dev_warn(host->dev,
> @@ -220,14 +244,34 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> }
> }
>
> +static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
> + unsigned int ctrl_type,
> + const char *propname,
> + u32 *out_values)
> +{
> + struct device_node *np = host->dev->of_node;
> + u32 timing[3];
> + int ret;
> +
> + ret = of_property_read_u32_array(np, propname, timing, 3);
> + if (ret)
> + return ret;
> +
> + if (ctrl_type == DW_MCI_TYPE_EXYNOS4412 ||
> + ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> + timing[2] = 0;
> +
> + *out_values = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2]);
> +
> + return 0;
> +}
> +
> +
> static int dw_mci_exynos_parse_dt(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv;
> struct device_node *np = host->dev->of_node;
> - u32 timing[2];
> - u32 div = 0;
> - int idx;
> - int ret;
> + int idx, ret;
>
> priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
> if (!priv)
> @@ -238,29 +282,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
> priv->ctrl_type = exynos_compat[idx].ctrl_type;
> }
>
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
> - priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
> - else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> - priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
> - else {
> - of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
> - priv->ciu_div = div;
> - }
> -
> - ret = of_property_read_u32_array(np,
> - "samsung,dw-mshc-sdr-timing", timing, 2);
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-sdr-timing", &priv->sdr_timing);
> if (ret)
> return ret;
>
> - priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
> -
> - ret = of_property_read_u32_array(np,
> - "samsung,dw-mshc-ddr-timing", timing, 2);
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-ddr-timing", &priv->ddr_timing);
> if (ret)
> return ret;
>
> - priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
> + dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
> host->priv = priv;
> +
> return 0;
> }
>
> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
> index 7872ce5..c04ecef 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.h
> +++ b/drivers/mmc/host/dw_mmc-exynos.h
> @@ -21,6 +21,7 @@
> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
> +#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
> SDMMC_CLKSEL_CCLK_DIVIDER(z))
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
@ 2015-01-02 10:30 ` Ulf Hansson
0 siblings, 0 replies; 28+ messages in thread
From: Ulf Hansson @ 2015-01-02 10:30 UTC (permalink / raw)
To: linux-arm-kernel
On 31 December 2014 at 07:43, Alim Akhtar <alim.akhtar@samsung.com> wrote:
> From: Seungwon Jeon <tgih.jun@samsung.com>
>
> ciu_div may not be common value for all speed mode.
> So, it needs to be attached to CLKSEL timing.
> This also introduce a new compatibale 'dw-mshc-hs200-timing'
> for selecting hs200 timing value
According to the patch you are adding a new DT property not a
"compatible". Please update the commit message.
The rest looks good to me.
Kind regards
Uffe
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
> drivers/mmc/host/dw_mmc-exynos.h | 1 +
> 3 files changed, 67 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> index ee4fc05..06455de 100644
> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> @@ -23,10 +23,6 @@ Required Properties:
> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
> specific extensions having an SMU.
>
> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
> -
> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
> in transmit mode and CIU clock phase shift value in receive mode for single
> data rate mode operation. Refer notes below for the order of the cells and the
> @@ -37,11 +33,16 @@ Required Properties:
> data rate mode operation. Refer notes below for the order of the cells and the
> valid values.
>
> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
> +
> Notes for the sdr-timing and ddr-timing values:
>
> The order of the cells should be
> - First Cell: CIU clock phase shift value for tx mode.
> - Second Cell: CIU clock phase shift value for rx mode.
> + - Thrid Cell: Specifies the divider value for the card interface
> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>
> Valid values for SDR and DDR CIU clock timing for Exynos5250:
> - valid value for tx phase shift and rx phase shift is 0 to 7.
> @@ -79,8 +80,8 @@ Example:
> broken-cd;
> fifo-depth = <0x80>;
> card-detect-delay = <200>;
> - samsung,dw-mshc-ciu-div = <3>;
> - samsung,dw-mshc-sdr-timing = <2 3>;
> - samsung,dw-mshc-ddr-timing = <1 2>;
> + samsung,dw-mshc-sdr-timing = <2 3 3>;
> + samsung,dw-mshc-ddr-timing = <1 2 3>;
> + samsung,dw-mshc-hs200-timing = <0 2 3>;
> bus-width = <8>;
> };
> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
> index 12a5eaa..be6530e 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.c
> +++ b/drivers/mmc/host/dw_mmc-exynos.c
> @@ -40,6 +40,7 @@ struct dw_mci_exynos_priv_data {
> u8 ciu_div;
> u32 sdr_timing;
> u32 ddr_timing;
> + u32 hs200_timing;
> u32 cur_speed;
> };
>
> @@ -71,6 +72,21 @@ static struct dw_mci_exynos_compatible {
> },
> };
>
> +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> +
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
> + return EXYNOS4412_FIXED_CIU_CLK_DIV;
> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> + return EXYNOS4210_FIXED_CIU_CLK_DIV;
> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
> + else
> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
> +}
> +
> static int dw_mci_exynos_priv_init(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
> @@ -85,6 +101,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
> }
>
> + priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
> +
> return 0;
> }
>
> @@ -92,7 +110,7 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
>
> - host->bus_hz /= (priv->ciu_div + 1);
> + host->bus_hz /= priv->ciu_div;
>
> return 0;
> }
> @@ -177,9 +195,14 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> struct dw_mci_exynos_priv_data *priv = host->priv;
> unsigned int wanted = ios->clock;
> unsigned long actual;
> - u8 div = priv->ciu_div + 1;
>
> - if (ios->timing == MMC_TIMING_MMC_DDR52) {
> + if (ios->timing == MMC_TIMING_MMC_HS200) {
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + mci_writel(host, CLKSEL64, priv->hs200_timing);
> + else
> + mci_writel(host, CLKSEL, priv->hs200_timing);
> + } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> mci_writel(host, CLKSEL64, priv->ddr_timing);
> @@ -208,6 +231,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> wanted = EXYNOS_CCLKIN_MIN;
>
> if (wanted != priv->cur_speed) {
> + u8 div = dw_mci_exynos_get_ciu_div(host);
> int ret = clk_set_rate(host->ciu_clk, wanted * div);
> if (ret)
> dev_warn(host->dev,
> @@ -220,14 +244,34 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> }
> }
>
> +static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
> + unsigned int ctrl_type,
> + const char *propname,
> + u32 *out_values)
> +{
> + struct device_node *np = host->dev->of_node;
> + u32 timing[3];
> + int ret;
> +
> + ret = of_property_read_u32_array(np, propname, timing, 3);
> + if (ret)
> + return ret;
> +
> + if (ctrl_type == DW_MCI_TYPE_EXYNOS4412 ||
> + ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> + timing[2] = 0;
> +
> + *out_values = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2]);
> +
> + return 0;
> +}
> +
> +
> static int dw_mci_exynos_parse_dt(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv;
> struct device_node *np = host->dev->of_node;
> - u32 timing[2];
> - u32 div = 0;
> - int idx;
> - int ret;
> + int idx, ret;
>
> priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
> if (!priv)
> @@ -238,29 +282,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
> priv->ctrl_type = exynos_compat[idx].ctrl_type;
> }
>
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
> - priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
> - else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> - priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
> - else {
> - of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
> - priv->ciu_div = div;
> - }
> -
> - ret = of_property_read_u32_array(np,
> - "samsung,dw-mshc-sdr-timing", timing, 2);
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-sdr-timing", &priv->sdr_timing);
> if (ret)
> return ret;
>
> - priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
> -
> - ret = of_property_read_u32_array(np,
> - "samsung,dw-mshc-ddr-timing", timing, 2);
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-ddr-timing", &priv->ddr_timing);
> if (ret)
> return ret;
>
> - priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
> + dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
> host->priv = priv;
> +
> return 0;
> }
>
> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
> index 7872ce5..c04ecef 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.h
> +++ b/drivers/mmc/host/dw_mmc-exynos.h
> @@ -21,6 +21,7 @@
> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
> +#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
> SDMMC_CLKSEL_CCLK_DIVIDER(z))
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
2014-12-31 6:43 ` Alim Akhtar
@ 2015-01-02 16:58 ` Doug Anderson
-1 siblings, 0 replies; 28+ messages in thread
From: Doug Anderson @ 2015-01-02 16:58 UTC (permalink / raw)
To: Alim Akhtar
Cc: linux-mmc, Chris Ball, Ulf Hansson, Jaehoon Chung, Seungwon Jeon,
Alim Akhtar, kgene, linux-arm-kernel, devicetree,
linux-samsung-soc, Abhilash Kesavan, Alexandru Stan,
Heiko Stübner, Javier Martinez Canillas
Alim,
On Tue, Dec 30, 2014 at 10:43 PM, Alim Akhtar <alim.akhtar@samsung.com> wrote:
> From: Seungwon Jeon <tgih.jun@samsung.com>
>
> ciu_div may not be common value for all speed mode.
> So, it needs to be attached to CLKSEL timing.
The more time I've spent looking at all of this stuff the less I like
the exynos bindings. Personally I'd prefer to see the exynos bindings
fixed rather than go further down the path of these bindings.
Specifically:
1. The "drive" really should be specified quite differently.
According to the DesignWare docs, the "drive" phase is there to meet
hold time requirements. Hold time requirements are different for
different SD/MMC modes and are specified in nanoseconds (SDR104 is
.8ns, ID mode is 5.0ns). There is a per-SoC parameter needed that
indicates some built-in delay (in nanoseconds) and that shouldn't
change based on clock speed or card mode.
2. The ciu_div really ought to be automatic. Start out at a divide by
4. If you end up with both drive and sample at phases of 0, 90, 180,
270 then you can change to divide by 2.
I still haven't looked at every last detail of these delays though, so
please correct me if I'm wrong. I've added Alex who may have looked
at this more than I have.
With all of the above, there's also the fact that (I think) we should
be moving towards working with the clock phase API since all of your
values are effectively specifying clock phases, just in a very arcane
way.
> This also introduce a new compatibale 'dw-mshc-hs200-timing'
> for selecting hs200 timing value
As per above, I don't think this is needed.
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
> drivers/mmc/host/dw_mmc-exynos.h | 1 +
> 3 files changed, 67 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> index ee4fc05..06455de 100644
> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> @@ -23,10 +23,6 @@ Required Properties:
> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
> specific extensions having an SMU.
>
> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
> -
> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
> in transmit mode and CIU clock phase shift value in receive mode for single
> data rate mode operation. Refer notes below for the order of the cells and the
> @@ -37,11 +33,16 @@ Required Properties:
> data rate mode operation. Refer notes below for the order of the cells and the
> valid values.
>
> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
> +
> Notes for the sdr-timing and ddr-timing values:
>
> The order of the cells should be
> - First Cell: CIU clock phase shift value for tx mode.
> - Second Cell: CIU clock phase shift value for rx mode.
> + - Thrid Cell: Specifies the divider value for the card interface
> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>
> Valid values for SDR and DDR CIU clock timing for Exynos5250:
> - valid value for tx phase shift and rx phase shift is 0 to 7.
> @@ -79,8 +80,8 @@ Example:
> broken-cd;
> fifo-depth = <0x80>;
> card-detect-delay = <200>;
> - samsung,dw-mshc-ciu-div = <3>;
> - samsung,dw-mshc-sdr-timing = <2 3>;
> - samsung,dw-mshc-ddr-timing = <1 2>;
> + samsung,dw-mshc-sdr-timing = <2 3 3>;
> + samsung,dw-mshc-ddr-timing = <1 2 3>;
> + samsung,dw-mshc-hs200-timing = <0 2 3>;
You are breaking backward compatibility here. If your change is
merged then all old boards will instantly break. Since the "dts" and
code changes will likely be merged through different trees you'll end
up with a bunch of broken trees until everything is merged together.
Even if you don't subscribe to the stable bindings theory this is not
acceptable.
-Doug
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
@ 2015-01-02 16:58 ` Doug Anderson
0 siblings, 0 replies; 28+ messages in thread
From: Doug Anderson @ 2015-01-02 16:58 UTC (permalink / raw)
To: linux-arm-kernel
Alim,
On Tue, Dec 30, 2014 at 10:43 PM, Alim Akhtar <alim.akhtar@samsung.com> wrote:
> From: Seungwon Jeon <tgih.jun@samsung.com>
>
> ciu_div may not be common value for all speed mode.
> So, it needs to be attached to CLKSEL timing.
The more time I've spent looking at all of this stuff the less I like
the exynos bindings. Personally I'd prefer to see the exynos bindings
fixed rather than go further down the path of these bindings.
Specifically:
1. The "drive" really should be specified quite differently.
According to the DesignWare docs, the "drive" phase is there to meet
hold time requirements. Hold time requirements are different for
different SD/MMC modes and are specified in nanoseconds (SDR104 is
.8ns, ID mode is 5.0ns). There is a per-SoC parameter needed that
indicates some built-in delay (in nanoseconds) and that shouldn't
change based on clock speed or card mode.
2. The ciu_div really ought to be automatic. Start out at a divide by
4. If you end up with both drive and sample at phases of 0, 90, 180,
270 then you can change to divide by 2.
I still haven't looked at every last detail of these delays though, so
please correct me if I'm wrong. I've added Alex who may have looked
at this more than I have.
With all of the above, there's also the fact that (I think) we should
be moving towards working with the clock phase API since all of your
values are effectively specifying clock phases, just in a very arcane
way.
> This also introduce a new compatibale 'dw-mshc-hs200-timing'
> for selecting hs200 timing value
As per above, I don't think this is needed.
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
> drivers/mmc/host/dw_mmc-exynos.h | 1 +
> 3 files changed, 67 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> index ee4fc05..06455de 100644
> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> @@ -23,10 +23,6 @@ Required Properties:
> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
> specific extensions having an SMU.
>
> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
> -
> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
> in transmit mode and CIU clock phase shift value in receive mode for single
> data rate mode operation. Refer notes below for the order of the cells and the
> @@ -37,11 +33,16 @@ Required Properties:
> data rate mode operation. Refer notes below for the order of the cells and the
> valid values.
>
> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
> +
> Notes for the sdr-timing and ddr-timing values:
>
> The order of the cells should be
> - First Cell: CIU clock phase shift value for tx mode.
> - Second Cell: CIU clock phase shift value for rx mode.
> + - Thrid Cell: Specifies the divider value for the card interface
> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>
> Valid values for SDR and DDR CIU clock timing for Exynos5250:
> - valid value for tx phase shift and rx phase shift is 0 to 7.
> @@ -79,8 +80,8 @@ Example:
> broken-cd;
> fifo-depth = <0x80>;
> card-detect-delay = <200>;
> - samsung,dw-mshc-ciu-div = <3>;
> - samsung,dw-mshc-sdr-timing = <2 3>;
> - samsung,dw-mshc-ddr-timing = <1 2>;
> + samsung,dw-mshc-sdr-timing = <2 3 3>;
> + samsung,dw-mshc-ddr-timing = <1 2 3>;
> + samsung,dw-mshc-hs200-timing = <0 2 3>;
You are breaking backward compatibility here. If your change is
merged then all old boards will instantly break. Since the "dts" and
code changes will likely be merged through different trees you'll end
up with a bunch of broken trees until everything is merged together.
Even if you don't subscribe to the stable bindings theory this is not
acceptable.
-Doug
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
2015-01-02 16:58 ` Doug Anderson
@ 2015-01-04 22:43 ` Alim Akhtar
-1 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2015-01-04 22:43 UTC (permalink / raw)
To: Doug Anderson
Cc: Alim Akhtar, linux-mmc, Chris Ball, Ulf Hansson, Jaehoon Chung,
Seungwon Jeon, kgene, linux-arm-kernel, devicetree,
linux-samsung-soc, Abhilash Kesavan, Alexandru Stan,
Heiko Stübner, Javier Martinez Canillas
Hi Doug,
Thanks for looking into this series.
On Fri, Jan 2, 2015 at 10:28 PM, Doug Anderson <dianders@chromium.org> wrote:
> Alim,
>
> On Tue, Dec 30, 2014 at 10:43 PM, Alim Akhtar <alim.akhtar@samsung.com> wrote:
>> From: Seungwon Jeon <tgih.jun@samsung.com>
>>
>> ciu_div may not be common value for all speed mode.
>> So, it needs to be attached to CLKSEL timing.
>
> The more time I've spent looking at all of this stuff the less I like
> the exynos bindings. Personally I'd prefer to see the exynos bindings
> fixed rather than go further down the path of these bindings.
>
> Specifically:
>
> 1. The "drive" really should be specified quite differently.
> According to the DesignWare docs, the "drive" phase is there to meet
> hold time requirements. Hold time requirements are different for
> different SD/MMC modes and are specified in nanoseconds (SDR104 is
> .8ns, ID mode is 5.0ns). There is a per-SoC parameter needed that
> indicates some built-in delay (in nanoseconds) and that shouldn't
> change based on clock speed or card mode.
>
Yes, "drive" phase shift are there to meet hold time requirements. And
that why we in general don't change it as those are fixed for a
SoC/Board based on actual measurement of the same.
> 2. The ciu_div really ought to be automatic. Start out at a divide by
> 4. If you end up with both drive and sample at phases of 0, 90, 180,
> 270 then you can change to divide by 2.
>
> I still haven't looked at every last detail of these delays though, so
> please correct me if I'm wrong. I've added Alex who may have looked
> at this more than I have.
>
Thanks, suggestions/comments are welcome.
>
> With all of the above, there's also the fact that (I think) we should
> be moving towards working with the clock phase API since all of your
> values are effectively specifying clock phases, just in a very arcane
> way.
>
That is something nice to have, and should be done at some point.
As you know exynos implements a custom register called CLKSEL, and it
allows us to set the required "sample" phase shift. And exynos uses
"variable delay tuning" as per DW databook to set "sample" phase shift
based on tuning data.
>
>> This also introduce a new compatibale 'dw-mshc-hs200-timing'
>> for selecting hs200 timing value
>
> As per above, I don't think this is needed.
>
>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
>> ---
>> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
>> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
>> drivers/mmc/host/dw_mmc-exynos.h | 1 +
>> 3 files changed, 67 insertions(+), 30 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> index ee4fc05..06455de 100644
>> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> @@ -23,10 +23,6 @@ Required Properties:
>> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
>> specific extensions having an SMU.
>>
>> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
>> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
>> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>> -
>> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
>> in transmit mode and CIU clock phase shift value in receive mode for single
>> data rate mode operation. Refer notes below for the order of the cells and the
>> @@ -37,11 +33,16 @@ Required Properties:
>> data rate mode operation. Refer notes below for the order of the cells and the
>> valid values.
>>
>> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
>> +
>> Notes for the sdr-timing and ddr-timing values:
>>
>> The order of the cells should be
>> - First Cell: CIU clock phase shift value for tx mode.
>> - Second Cell: CIU clock phase shift value for rx mode.
>> + - Thrid Cell: Specifies the divider value for the card interface
>> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
>> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>>
>> Valid values for SDR and DDR CIU clock timing for Exynos5250:
>> - valid value for tx phase shift and rx phase shift is 0 to 7.
>> @@ -79,8 +80,8 @@ Example:
>> broken-cd;
>> fifo-depth = <0x80>;
>> card-detect-delay = <200>;
>> - samsung,dw-mshc-ciu-div = <3>;
>> - samsung,dw-mshc-sdr-timing = <2 3>;
>> - samsung,dw-mshc-ddr-timing = <1 2>;
>> + samsung,dw-mshc-sdr-timing = <2 3 3>;
>> + samsung,dw-mshc-ddr-timing = <1 2 3>;
>> + samsung,dw-mshc-hs200-timing = <0 2 3>;
>
> You are breaking backward compatibility here. If your change is
> merged then all old boards will instantly break. Since the "dts" and
> code changes will likely be merged through different trees you'll end
> up with a bunch of broken trees until everything is merged together.
> Even if you don't subscribe to the stable bindings theory this is not
> acceptable.
>
yes the major concern in this series is probably this, which breaks
things unless everything merge in one go and via one tree. Thats why I
re-based everything including dts change on mmc-tree for this case and
added device-tree mailing list for more opinion etc.
> -Doug
--
Regards,
Alim
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
@ 2015-01-04 22:43 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2015-01-04 22:43 UTC (permalink / raw)
To: linux-arm-kernel
Hi Doug,
Thanks for looking into this series.
On Fri, Jan 2, 2015 at 10:28 PM, Doug Anderson <dianders@chromium.org> wrote:
> Alim,
>
> On Tue, Dec 30, 2014 at 10:43 PM, Alim Akhtar <alim.akhtar@samsung.com> wrote:
>> From: Seungwon Jeon <tgih.jun@samsung.com>
>>
>> ciu_div may not be common value for all speed mode.
>> So, it needs to be attached to CLKSEL timing.
>
> The more time I've spent looking at all of this stuff the less I like
> the exynos bindings. Personally I'd prefer to see the exynos bindings
> fixed rather than go further down the path of these bindings.
>
> Specifically:
>
> 1. The "drive" really should be specified quite differently.
> According to the DesignWare docs, the "drive" phase is there to meet
> hold time requirements. Hold time requirements are different for
> different SD/MMC modes and are specified in nanoseconds (SDR104 is
> .8ns, ID mode is 5.0ns). There is a per-SoC parameter needed that
> indicates some built-in delay (in nanoseconds) and that shouldn't
> change based on clock speed or card mode.
>
Yes, "drive" phase shift are there to meet hold time requirements. And
that why we in general don't change it as those are fixed for a
SoC/Board based on actual measurement of the same.
> 2. The ciu_div really ought to be automatic. Start out at a divide by
> 4. If you end up with both drive and sample at phases of 0, 90, 180,
> 270 then you can change to divide by 2.
>
> I still haven't looked at every last detail of these delays though, so
> please correct me if I'm wrong. I've added Alex who may have looked
> at this more than I have.
>
Thanks, suggestions/comments are welcome.
>
> With all of the above, there's also the fact that (I think) we should
> be moving towards working with the clock phase API since all of your
> values are effectively specifying clock phases, just in a very arcane
> way.
>
That is something nice to have, and should be done at some point.
As you know exynos implements a custom register called CLKSEL, and it
allows us to set the required "sample" phase shift. And exynos uses
"variable delay tuning" as per DW databook to set "sample" phase shift
based on tuning data.
>
>> This also introduce a new compatibale 'dw-mshc-hs200-timing'
>> for selecting hs200 timing value
>
> As per above, I don't think this is needed.
>
>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
>> ---
>> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
>> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
>> drivers/mmc/host/dw_mmc-exynos.h | 1 +
>> 3 files changed, 67 insertions(+), 30 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> index ee4fc05..06455de 100644
>> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> @@ -23,10 +23,6 @@ Required Properties:
>> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
>> specific extensions having an SMU.
>>
>> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
>> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
>> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>> -
>> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
>> in transmit mode and CIU clock phase shift value in receive mode for single
>> data rate mode operation. Refer notes below for the order of the cells and the
>> @@ -37,11 +33,16 @@ Required Properties:
>> data rate mode operation. Refer notes below for the order of the cells and the
>> valid values.
>>
>> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
>> +
>> Notes for the sdr-timing and ddr-timing values:
>>
>> The order of the cells should be
>> - First Cell: CIU clock phase shift value for tx mode.
>> - Second Cell: CIU clock phase shift value for rx mode.
>> + - Thrid Cell: Specifies the divider value for the card interface
>> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
>> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>>
>> Valid values for SDR and DDR CIU clock timing for Exynos5250:
>> - valid value for tx phase shift and rx phase shift is 0 to 7.
>> @@ -79,8 +80,8 @@ Example:
>> broken-cd;
>> fifo-depth = <0x80>;
>> card-detect-delay = <200>;
>> - samsung,dw-mshc-ciu-div = <3>;
>> - samsung,dw-mshc-sdr-timing = <2 3>;
>> - samsung,dw-mshc-ddr-timing = <1 2>;
>> + samsung,dw-mshc-sdr-timing = <2 3 3>;
>> + samsung,dw-mshc-ddr-timing = <1 2 3>;
>> + samsung,dw-mshc-hs200-timing = <0 2 3>;
>
> You are breaking backward compatibility here. If your change is
> merged then all old boards will instantly break. Since the "dts" and
> code changes will likely be merged through different trees you'll end
> up with a bunch of broken trees until everything is merged together.
> Even if you don't subscribe to the stable bindings theory this is not
> acceptable.
>
yes the major concern in this series is probably this, which breaks
things unless everything merge in one go and via one tree. Thats why I
re-based everything including dts change on mmc-tree for this case and
added device-tree mailing list for more opinion etc.
> -Doug
--
Regards,
Alim
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
2015-01-04 22:43 ` Alim Akhtar
@ 2015-01-06 1:07 ` Doug Anderson
-1 siblings, 0 replies; 28+ messages in thread
From: Doug Anderson @ 2015-01-06 1:07 UTC (permalink / raw)
To: Alim Akhtar
Cc: Alim Akhtar, linux-mmc-u79uwXL29TY76Z2rM5mHXA, Chris Ball,
Ulf Hansson, Jaehoon Chung, Seungwon Jeon, kgene,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, linux-samsung-soc,
Abhilash Kesavan, Alexandru Stan, Heiko Stübner,
Javier Martinez Canillas, Olof Johansson, Kevin Hilman
Alim,
On Sun, Jan 4, 2015 at 2:43 PM, Alim Akhtar <alim.akhtar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> You are breaking backward compatibility here. If your change is
>> merged then all old boards will instantly break. Since the "dts" and
>> code changes will likely be merged through different trees you'll end
>> up with a bunch of broken trees until everything is merged together.
>> Even if you don't subscribe to the stable bindings theory this is not
>> acceptable.
>>
> yes the major concern in this series is probably this, which breaks
> things unless everything merge in one go and via one tree. Thats why I
> re-based everything including dts change on mmc-tree for this case and
> added device-tree mailing list for more opinion etc.
Got it. I doubt that folks will like this, but I could be wrong. In
order for this to work, you'd need all changes in the series to land
in _both_ the ARMSoC tree and the MMC tree. That's not unheard of,
but it doesn't seem ideal.
You also break bisect-ability here since without the code the DTS
change will break things and without the DTS change the code will
break things.
If you add all the above to the fact that bindings are supposed to be
stable (ish) I'm not convinced this will land.
-Doug
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
@ 2015-01-06 1:07 ` Doug Anderson
0 siblings, 0 replies; 28+ messages in thread
From: Doug Anderson @ 2015-01-06 1:07 UTC (permalink / raw)
To: linux-arm-kernel
Alim,
On Sun, Jan 4, 2015 at 2:43 PM, Alim Akhtar <alim.akhtar@gmail.com> wrote:
>> You are breaking backward compatibility here. If your change is
>> merged then all old boards will instantly break. Since the "dts" and
>> code changes will likely be merged through different trees you'll end
>> up with a bunch of broken trees until everything is merged together.
>> Even if you don't subscribe to the stable bindings theory this is not
>> acceptable.
>>
> yes the major concern in this series is probably this, which breaks
> things unless everything merge in one go and via one tree. Thats why I
> re-based everything including dts change on mmc-tree for this case and
> added device-tree mailing list for more opinion etc.
Got it. I doubt that folks will like this, but I could be wrong. In
order for this to work, you'd need all changes in the series to land
in _both_ the ARMSoC tree and the MMC tree. That's not unheard of,
but it doesn't seem ideal.
You also break bisect-ability here since without the code the DTS
change will break things and without the DTS change the code will
break things.
If you add all the above to the fact that bindings are supposed to be
stable (ish) I'm not convinced this will land.
-Doug
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
2014-12-31 6:43 ` Alim Akhtar
@ 2015-01-08 1:36 ` Jaehoon Chung
-1 siblings, 0 replies; 28+ messages in thread
From: Jaehoon Chung @ 2015-01-08 1:36 UTC (permalink / raw)
To: Alim Akhtar, linux-mmc
Cc: chris, ulf.hansson, tgih.jun, dianders, alim.akhtar, kgene,
linux-arm-kernel, devicetree, linux-samsung-soc, a.kesavan
Hi,
On 12/31/2014 03:43 PM, Alim Akhtar wrote:
> From: Seungwon Jeon <tgih.jun@samsung.com>
>
> ciu_div may not be common value for all speed mode.
> So, it needs to be attached to CLKSEL timing.
> This also introduce a new compatibale 'dw-mshc-hs200-timing'
> for selecting hs200 timing value
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
> drivers/mmc/host/dw_mmc-exynos.h | 1 +
> 3 files changed, 67 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> index ee4fc05..06455de 100644
> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> @@ -23,10 +23,6 @@ Required Properties:
> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
> specific extensions having an SMU.
>
> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
> -
> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
> in transmit mode and CIU clock phase shift value in receive mode for single
> data rate mode operation. Refer notes below for the order of the cells and the
> @@ -37,11 +33,16 @@ Required Properties:
> data rate mode operation. Refer notes below for the order of the cells and the
> valid values.
>
> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
What does this comment mean? "Similar with dw-mshc-sdr-timing"
how about adding the comment "optional"?
And i think this timing doesn't need, we can reuse the sdr-timing or ddr-timing.
Because it's re-configurated at tuning time, isn't?
> +
> Notes for the sdr-timing and ddr-timing values:
>
> The order of the cells should be
> - First Cell: CIU clock phase shift value for tx mode.
> - Second Cell: CIU clock phase shift value for rx mode.
> + - Thrid Cell: Specifies the divider value for the card interface
> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>
> Valid values for SDR and DDR CIU clock timing for Exynos5250:
> - valid value for tx phase shift and rx phase shift is 0 to 7.
> @@ -79,8 +80,8 @@ Example:
> broken-cd;
> fifo-depth = <0x80>;
> card-detect-delay = <200>;
> - samsung,dw-mshc-ciu-div = <3>;
> - samsung,dw-mshc-sdr-timing = <2 3>;
> - samsung,dw-mshc-ddr-timing = <1 2>;
> + samsung,dw-mshc-sdr-timing = <2 3 3>;
> + samsung,dw-mshc-ddr-timing = <1 2 3>;
> + samsung,dw-mshc-hs200-timing = <0 2 3>;
> bus-width = <8>;
> };
> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
> index 12a5eaa..be6530e 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.c
> +++ b/drivers/mmc/host/dw_mmc-exynos.c
> @@ -40,6 +40,7 @@ struct dw_mci_exynos_priv_data {
> u8 ciu_div;
> u32 sdr_timing;
> u32 ddr_timing;
> + u32 hs200_timing;
> u32 cur_speed;
> };
>
> @@ -71,6 +72,21 @@ static struct dw_mci_exynos_compatible {
> },
> };
>
> +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> +
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
> + return EXYNOS4412_FIXED_CIU_CLK_DIV;
> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> + return EXYNOS4210_FIXED_CIU_CLK_DIV;
> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
> + else
> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
If need this, I think more readable that use the switch-case statement. how about?
switch (priv->ctrl_type) {
case DW_MCI_TYPE_EXYNOS4412:
return EXYNOS4412_FIXED_CIU_CLK_DIV;
case DW_MCI_TYPE_EXYNOS4210:
return EXYNOS4210_FIXED_CIU_CLK_DIV;
case DW_MCI_TYPE_EXYNOS7:
case DW_MCI_TYPE_EXYNOS7_SMU:
return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
default:
return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
}
> +}
> +
> static int dw_mci_exynos_priv_init(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
> @@ -85,6 +101,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
> }
>
> + priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
> +
> return 0;
> }
>
> @@ -92,7 +110,7 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
>
> - host->bus_hz /= (priv->ciu_div + 1);
> + host->bus_hz /= priv->ciu_div;
>
> return 0;
> }
> @@ -177,9 +195,14 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> struct dw_mci_exynos_priv_data *priv = host->priv;
> unsigned int wanted = ios->clock;
> unsigned long actual;
> - u8 div = priv->ciu_div + 1;
>
> - if (ios->timing == MMC_TIMING_MMC_DDR52) {
> + if (ios->timing == MMC_TIMING_MMC_HS200) {
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + mci_writel(host, CLKSEL64, priv->hs200_timing);
> + else
> + mci_writel(host, CLKSEL, priv->hs200_timing);
> + } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> mci_writel(host, CLKSEL64, priv->ddr_timing);
> @@ -208,6 +231,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> wanted = EXYNOS_CCLKIN_MIN;
>
> if (wanted != priv->cur_speed) {
> + u8 div = dw_mci_exynos_get_ciu_div(host);
> int ret = clk_set_rate(host->ciu_clk, wanted * div);
> if (ret)
> dev_warn(host->dev,
> @@ -220,14 +244,34 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> }
> }
>
> +static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
> + unsigned int ctrl_type,
> + const char *propname,
> + u32 *out_values)
> +{
> + struct device_node *np = host->dev->of_node;
> + u32 timing[3];
> + int ret;
> +
> + ret = of_property_read_u32_array(np, propname, timing, 3);
> + if (ret)
> + return ret;
> +
> + if (ctrl_type == DW_MCI_TYPE_EXYNOS4412 ||
> + ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> + timing[2] = 0;
Is it set to 0 into dt-file?
> +
> + *out_values = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2]);
> +
> + return 0;
> +}
> +
> +
> static int dw_mci_exynos_parse_dt(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv;
> struct device_node *np = host->dev->of_node;
> - u32 timing[2];
> - u32 div = 0;
> - int idx;
> - int ret;
> + int idx, ret;
>
> priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
> if (!priv)
> @@ -238,29 +282,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
> priv->ctrl_type = exynos_compat[idx].ctrl_type;
> }
>
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
> - priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
> - else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> - priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
> - else {
> - of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
> - priv->ciu_div = div;
> - }
> -
> - ret = of_property_read_u32_array(np,
> - "samsung,dw-mshc-sdr-timing", timing, 2);
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-sdr-timing", &priv->sdr_timing);
> if (ret)
> return ret;
>
> - priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
> -
> - ret = of_property_read_u32_array(np,
> - "samsung,dw-mshc-ddr-timing", timing, 2);
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-ddr-timing", &priv->ddr_timing);
> if (ret)
> return ret;
>
> - priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
> + dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
hs200-timing is optional, so it needs not to check return value, right?
Best Regards,
Jaehoon Chung
> host->priv = priv;
> +
> return 0;
> }
>
> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
> index 7872ce5..c04ecef 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.h
> +++ b/drivers/mmc/host/dw_mmc-exynos.h
> @@ -21,6 +21,7 @@
> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
> +#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
> SDMMC_CLKSEL_CCLK_DIVIDER(z))
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
@ 2015-01-08 1:36 ` Jaehoon Chung
0 siblings, 0 replies; 28+ messages in thread
From: Jaehoon Chung @ 2015-01-08 1:36 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
On 12/31/2014 03:43 PM, Alim Akhtar wrote:
> From: Seungwon Jeon <tgih.jun@samsung.com>
>
> ciu_div may not be common value for all speed mode.
> So, it needs to be attached to CLKSEL timing.
> This also introduce a new compatibale 'dw-mshc-hs200-timing'
> for selecting hs200 timing value
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
> drivers/mmc/host/dw_mmc-exynos.h | 1 +
> 3 files changed, 67 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> index ee4fc05..06455de 100644
> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> @@ -23,10 +23,6 @@ Required Properties:
> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
> specific extensions having an SMU.
>
> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
> -
> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
> in transmit mode and CIU clock phase shift value in receive mode for single
> data rate mode operation. Refer notes below for the order of the cells and the
> @@ -37,11 +33,16 @@ Required Properties:
> data rate mode operation. Refer notes below for the order of the cells and the
> valid values.
>
> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
What does this comment mean? "Similar with dw-mshc-sdr-timing"
how about adding the comment "optional"?
And i think this timing doesn't need, we can reuse the sdr-timing or ddr-timing.
Because it's re-configurated at tuning time, isn't?
> +
> Notes for the sdr-timing and ddr-timing values:
>
> The order of the cells should be
> - First Cell: CIU clock phase shift value for tx mode.
> - Second Cell: CIU clock phase shift value for rx mode.
> + - Thrid Cell: Specifies the divider value for the card interface
> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>
> Valid values for SDR and DDR CIU clock timing for Exynos5250:
> - valid value for tx phase shift and rx phase shift is 0 to 7.
> @@ -79,8 +80,8 @@ Example:
> broken-cd;
> fifo-depth = <0x80>;
> card-detect-delay = <200>;
> - samsung,dw-mshc-ciu-div = <3>;
> - samsung,dw-mshc-sdr-timing = <2 3>;
> - samsung,dw-mshc-ddr-timing = <1 2>;
> + samsung,dw-mshc-sdr-timing = <2 3 3>;
> + samsung,dw-mshc-ddr-timing = <1 2 3>;
> + samsung,dw-mshc-hs200-timing = <0 2 3>;
> bus-width = <8>;
> };
> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
> index 12a5eaa..be6530e 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.c
> +++ b/drivers/mmc/host/dw_mmc-exynos.c
> @@ -40,6 +40,7 @@ struct dw_mci_exynos_priv_data {
> u8 ciu_div;
> u32 sdr_timing;
> u32 ddr_timing;
> + u32 hs200_timing;
> u32 cur_speed;
> };
>
> @@ -71,6 +72,21 @@ static struct dw_mci_exynos_compatible {
> },
> };
>
> +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> +
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
> + return EXYNOS4412_FIXED_CIU_CLK_DIV;
> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> + return EXYNOS4210_FIXED_CIU_CLK_DIV;
> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
> + else
> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
If need this, I think more readable that use the switch-case statement. how about?
switch (priv->ctrl_type) {
case DW_MCI_TYPE_EXYNOS4412:
return EXYNOS4412_FIXED_CIU_CLK_DIV;
case DW_MCI_TYPE_EXYNOS4210:
return EXYNOS4210_FIXED_CIU_CLK_DIV;
case DW_MCI_TYPE_EXYNOS7:
case DW_MCI_TYPE_EXYNOS7_SMU:
return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
default:
return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
}
> +}
> +
> static int dw_mci_exynos_priv_init(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
> @@ -85,6 +101,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
> }
>
> + priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
> +
> return 0;
> }
>
> @@ -92,7 +110,7 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
>
> - host->bus_hz /= (priv->ciu_div + 1);
> + host->bus_hz /= priv->ciu_div;
>
> return 0;
> }
> @@ -177,9 +195,14 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> struct dw_mci_exynos_priv_data *priv = host->priv;
> unsigned int wanted = ios->clock;
> unsigned long actual;
> - u8 div = priv->ciu_div + 1;
>
> - if (ios->timing == MMC_TIMING_MMC_DDR52) {
> + if (ios->timing == MMC_TIMING_MMC_HS200) {
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + mci_writel(host, CLKSEL64, priv->hs200_timing);
> + else
> + mci_writel(host, CLKSEL, priv->hs200_timing);
> + } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> mci_writel(host, CLKSEL64, priv->ddr_timing);
> @@ -208,6 +231,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> wanted = EXYNOS_CCLKIN_MIN;
>
> if (wanted != priv->cur_speed) {
> + u8 div = dw_mci_exynos_get_ciu_div(host);
> int ret = clk_set_rate(host->ciu_clk, wanted * div);
> if (ret)
> dev_warn(host->dev,
> @@ -220,14 +244,34 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> }
> }
>
> +static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
> + unsigned int ctrl_type,
> + const char *propname,
> + u32 *out_values)
> +{
> + struct device_node *np = host->dev->of_node;
> + u32 timing[3];
> + int ret;
> +
> + ret = of_property_read_u32_array(np, propname, timing, 3);
> + if (ret)
> + return ret;
> +
> + if (ctrl_type == DW_MCI_TYPE_EXYNOS4412 ||
> + ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> + timing[2] = 0;
Is it set to 0 into dt-file?
> +
> + *out_values = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2]);
> +
> + return 0;
> +}
> +
> +
> static int dw_mci_exynos_parse_dt(struct dw_mci *host)
> {
> struct dw_mci_exynos_priv_data *priv;
> struct device_node *np = host->dev->of_node;
> - u32 timing[2];
> - u32 div = 0;
> - int idx;
> - int ret;
> + int idx, ret;
>
> priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
> if (!priv)
> @@ -238,29 +282,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
> priv->ctrl_type = exynos_compat[idx].ctrl_type;
> }
>
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
> - priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
> - else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
> - priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
> - else {
> - of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
> - priv->ciu_div = div;
> - }
> -
> - ret = of_property_read_u32_array(np,
> - "samsung,dw-mshc-sdr-timing", timing, 2);
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-sdr-timing", &priv->sdr_timing);
> if (ret)
> return ret;
>
> - priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
> -
> - ret = of_property_read_u32_array(np,
> - "samsung,dw-mshc-ddr-timing", timing, 2);
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-ddr-timing", &priv->ddr_timing);
> if (ret)
> return ret;
>
> - priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
> + dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
hs200-timing is optional, so it needs not to check return value, right?
Best Regards,
Jaehoon Chung
> host->priv = priv;
> +
> return 0;
> }
>
> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
> index 7872ce5..c04ecef 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.h
> +++ b/drivers/mmc/host/dw_mmc-exynos.h
> @@ -21,6 +21,7 @@
> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
> +#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
> SDMMC_CLKSEL_CCLK_DIVIDER(z))
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 2/4] mmc: dw_mmc: exynos: support eMMC's HS400 mode
2014-12-31 6:43 ` Alim Akhtar
@ 2015-01-08 1:46 ` Jaehoon Chung
-1 siblings, 0 replies; 28+ messages in thread
From: Jaehoon Chung @ 2015-01-08 1:46 UTC (permalink / raw)
To: Alim Akhtar, linux-mmc
Cc: chris, ulf.hansson, tgih.jun, dianders, alim.akhtar, kgene,
linux-arm-kernel, devicetree, linux-samsung-soc, a.kesavan
On 12/31/2014 03:43 PM, Alim Akhtar wrote:
> From: Seungwon Jeon <tgih.jun@samsung.com>
>
> Implements HS400 support for exynos host driver.
> And this patch includes some updates as new mode is added.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 6 +
> drivers/mmc/host/dw_mmc-exynos.c | 177 +++++++++++++++-----
> drivers/mmc/host/dw_mmc-exynos.h | 17 +-
> drivers/mmc/host/dw_mmc.c | 16 +-
> drivers/mmc/host/dw_mmc.h | 2 +
> 5 files changed, 178 insertions(+), 40 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> index 06455de..be30c94 100644
> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> @@ -34,6 +34,7 @@ Required Properties:
> valid values.
>
> * samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
> +* samsung,dw-mshc-hs400-timing: Similar with dw-mshc-ddr-timing.
>
> Notes for the sdr-timing and ddr-timing values:
>
> @@ -51,6 +52,9 @@ Required Properties:
> - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
> phase shift clocks should be 0.
>
> +* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
> + (Latency value for delay line in Read path)
> +
> Required properties for a slot (Deprecated - Recommend to use one slot per host):
>
> * gpios: specifies a list of gpios used for command, clock and data bus. The
> @@ -83,5 +87,7 @@ Example:
> samsung,dw-mshc-sdr-timing = <2 3 3>;
> samsung,dw-mshc-ddr-timing = <1 2 3>;
> samsung,dw-mshc-hs200-timing = <0 2 3>;
> + samsung,dw-mshc-hs400-timing = <0 2 1>;
> + read-strobe-delay = <90>;
> bus-width = <8>;
> };
> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
> index be6530e..d37a631 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.c
> +++ b/drivers/mmc/host/dw_mmc-exynos.c
> @@ -41,7 +41,12 @@ struct dw_mci_exynos_priv_data {
> u32 sdr_timing;
> u32 ddr_timing;
> u32 hs200_timing;
> + u32 hs400_timing;
> + u32 tuned_sample;
> u32 cur_speed;
> + u32 dqs_delay;
> + u32 saved_dqs_en;
> + u32 saved_strobe_ctrl;
> };
>
> static struct dw_mci_exynos_compatible {
> @@ -101,6 +106,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
> }
>
> + if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
> + priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
> + priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
> + priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
> + mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
> + if (!priv->dqs_delay)
> + priv->dqs_delay =
> + DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
> + }
> +
> priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
>
> return 0;
> @@ -115,6 +130,25 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
> return 0;
> }
>
> +static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> + u32 clksel;
> +
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + clksel = mci_readl(host, CLKSEL64);
> + else
> + clksel = mci_readl(host, CLKSEL);
> +
> + clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + mci_writel(host, CLKSEL64, clksel);
> + else
> + mci_writel(host, CLKSEL, clksel);
> +}
> +
> #ifdef CONFIG_PM_SLEEP
> static int dw_mci_exynos_suspend(struct device *dev)
> {
> @@ -190,35 +224,37 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
> }
> }
>
> -static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> +static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
> - unsigned int wanted = ios->clock;
> - unsigned long actual;
> + u32 dqs, strobe;
>
> - if (ios->timing == MMC_TIMING_MMC_HS200) {
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> - mci_writel(host, CLKSEL64, priv->hs200_timing);
> - else
> - mci_writel(host, CLKSEL, priv->hs200_timing);
> - } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> - mci_writel(host, CLKSEL64, priv->ddr_timing);
> - else
> - mci_writel(host, CLKSEL, priv->ddr_timing);
> - /* Should be double rate for DDR mode */
> - if (ios->bus_width == MMC_BUS_WIDTH_8)
> - wanted <<= 1;
> + /*
> + * Exynos5420 and above controller supports HS400 mode
> + */
> + if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
> + return;
> +
> + dqs = priv->saved_dqs_en;
> + strobe = priv->saved_strobe_ctrl;
> +
> + if (timing == MMC_TIMING_MMC_HS400) {
> + dqs |= DATA_STROBE_EN;
> + strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
> } else {
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> - mci_writel(host, CLKSEL64, priv->sdr_timing);
> - else
> - mci_writel(host, CLKSEL, priv->sdr_timing);
> + dqs &= ~DATA_STROBE_EN;
> }
>
> + mci_writel(host, HS400_DQS_EN, dqs);
> + mci_writel(host, HS400_DLINE_CTRL, strobe);
> +}
> +
> +static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> + unsigned long actual;
> + u8 div;
> + int ret;
> /*
> * Don't care if wanted clock is zero or
> * ciu clock is unavailable
> @@ -230,18 +266,55 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> if (wanted < EXYNOS_CCLKIN_MIN)
> wanted = EXYNOS_CCLKIN_MIN;
>
> - if (wanted != priv->cur_speed) {
> - u8 div = dw_mci_exynos_get_ciu_div(host);
> - int ret = clk_set_rate(host->ciu_clk, wanted * div);
> - if (ret)
> - dev_warn(host->dev,
> - "failed to set clk-rate %u error: %d\n",
> - wanted * div, ret);
> - actual = clk_get_rate(host->ciu_clk);
> - host->bus_hz = actual / div;
> - priv->cur_speed = wanted;
> - host->current_speed = 0;
> + if (wanted == priv->cur_speed)
> + return;
> +
> + div = dw_mci_exynos_get_ciu_div(host);
> + ret = clk_set_rate(host->ciu_clk, wanted * div);
> + if (ret)
> + dev_warn(host->dev,
> + "failed to set clk-rate %u error: %d\n",
> + wanted * div, ret);
> + actual = clk_get_rate(host->ciu_clk);
> + host->bus_hz = actual / div;
> + priv->cur_speed = wanted;
> + host->current_speed = 0;
> +}
> +
> +static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> + unsigned int wanted = ios->clock;
> + u32 timing = ios->timing, clksel;
> +
> + switch (timing) {
> + case MMC_TIMING_MMC_HS400:
> + /* Update tuned sample timing */
> + clksel = SDMMC_CLKSEL_UP_SAMPLE(
> + priv->hs400_timing, priv->tuned_sample);
> + wanted <<= 1;
> + break;
> + case MMC_TIMING_MMC_HS200:
> + clksel = priv->hs200_timing;
> + break;
> + case MMC_TIMING_MMC_DDR52:
> + clksel = priv->ddr_timing;
> + /* Should be double rate for DDR mode */
> + if (ios->bus_width == MMC_BUS_WIDTH_8)
> + wanted <<= 1;
> + break;
> + default:
> + clksel = priv->sdr_timing;
> }
> +
> + /* Set clock timing for the requested speed mode*/
> + dw_mci_exynos_set_clksel_timing(host, clksel);
> +
> + /* Configure setting for HS400 */
> + dw_mci_exynos_config_hs400(host, timing);
> +
> + /* Configure clock rate */
> + dw_mci_exynos_adjust_clock(host, wanted);
> }
>
> static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
> @@ -294,6 +367,14 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
>
> dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
> +
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-hs400-timing", &priv->hs400_timing);
> + if (!ret && of_property_read_u32(np,
> + "read-strobe-delay", &priv->dqs_delay))
> + dev_info(host->dev,
> + "read-strobe-delay is not found, assuming usage of default value\n");
> +
> host->priv = priv;
>
> return 0;
> @@ -320,7 +401,9 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
> clksel = mci_readl(host, CLKSEL64);
> else
> clksel = mci_readl(host, CLKSEL);
> - clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
> +
> + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
> +
> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> mci_writel(host, CLKSEL64, clksel);
> @@ -339,13 +422,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
> clksel = mci_readl(host, CLKSEL64);
> else
> clksel = mci_readl(host, CLKSEL);
> +
> sample = (clksel + 1) & 0x7;
> - clksel = (clksel & ~0x7) | sample;
> + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
> +
> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> mci_writel(host, CLKSEL64, clksel);
> else
> mci_writel(host, CLKSEL, clksel);
> +
> return sample;
> }
>
> @@ -378,6 +464,7 @@ out:
> static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
> {
> struct dw_mci *host = slot->host;
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> struct mmc_host *mmc = slot->mmc;
> u8 start_smpl, smpl, candiates = 0;
> s8 found = -1;
> @@ -395,14 +482,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
> } while (start_smpl != smpl);
>
> found = dw_mci_exynos_get_best_clksmpl(candiates);
> - if (found >= 0)
> + if (found >= 0) {
> dw_mci_exynos_set_clksmpl(host, found);
> - else
> + priv->tuned_sample = found;
> + } else {
> ret = -EIO;
> + }
>
> return ret;
> }
>
> +int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
> + struct mmc_ios *ios)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> +
> + dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
> + dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
> +
> + return 0;
> +}
> +
> /* Common capabilities of Exynos4/Exynos5 SoC */
> static unsigned long exynos_dwmmc_caps[4] = {
> MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> @@ -419,6 +519,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
> .set_ios = dw_mci_exynos_set_ios,
> .parse_dt = dw_mci_exynos_parse_dt,
> .execute_tuning = dw_mci_exynos_execute_tuning,
> + .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
> };
>
> static const struct of_device_id dw_mci_exynos_match[] = {
> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
> index c04ecef..e7faffe 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.h
> +++ b/drivers/mmc/host/dw_mmc-exynos.h
> @@ -12,21 +12,36 @@
> #ifndef _DW_MMC_EXYNOS_H_
> #define _DW_MMC_EXYNOS_H_
>
> -/* Extended Register's Offset */
> #define SDMMC_CLKSEL 0x09C
> #define SDMMC_CLKSEL64 0x0A8
>
> +/* Extended Register's Offset */
> +#define SDMMC_HS400_DQS_EN 0x180
> +#define SDMMC_HS400_ASYNC_FIFO_CTRL 0x184
> +#define SDMMC_HS400_DLINE_CTRL 0x188
> +
> /* CLKSEL register defines */
> #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
> #define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
> +#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
> + SDMMC_CLKSEL_CCLK_SAMPLE(y))
> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
> SDMMC_CLKSEL_CCLK_DIVIDER(z))
> +#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
> #define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
>
> +/* HS400 control defines */
> +#define DATA_STROBE_EN BIT(0)
Add comment "xxx register defines."
> +#define AXI_NON_BLOCKING_WR BIT(7)
I can't find this bit and comment..where?
> +
> +/* Delay Line Control defines */
> +#define DQS_CTRL_RD_DELAY(x, y) (((x) & ~0x3FF) | ((y) & 0x3FF))
I'm not understanding this define... clear and set?
Best Regards,
Jaehoon Chung
> +#define DQS_CTRL_GET_RD_DELAY(x) ((x) & 0x3FF)
> +
> /* Protector Register */
> #define SDMMC_EMMCP_BASE 0x1000
> #define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 2e8abc8..43a3a5b 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> regs = mci_readl(slot->host, UHS_REG);
>
> /* DDR mode set */
> - if (ios->timing == MMC_TIMING_MMC_DDR52)
> + if (ios->timing == MMC_TIMING_MMC_DDR52 ||
> + ios->timing == MMC_TIMING_MMC_HS400)
> regs |= ((0x1 << slot->id) << 16);
> else
> regs &= ~((0x1 << slot->id) << 16);
> @@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
> return err;
> }
>
> +int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> + struct dw_mci_slot *slot = mmc_priv(mmc);
> + struct dw_mci *host = slot->host;
> + const struct dw_mci_drv_data *drv_data = host->drv_data;
> +
> + if (drv_data && drv_data->prepare_hs400_tuning)
> + return drv_data->prepare_hs400_tuning(host, ios);
> +
> + return 0;
> +}
> +
> static const struct mmc_host_ops dw_mci_ops = {
> .request = dw_mci_request,
> .pre_req = dw_mci_pre_req,
> @@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
> .card_busy = dw_mci_card_busy,
> .start_signal_voltage_switch = dw_mci_switch_voltage,
> .init_card = dw_mci_init_card,
> + .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
> };
>
> static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 18c4afe..d239867 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -271,5 +271,7 @@ struct dw_mci_drv_data {
> 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 (*prepare_hs400_tuning)(struct dw_mci *host,
> + struct mmc_ios *ios);
> };
> #endif /* _DW_MMC_H_ */
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 2/4] mmc: dw_mmc: exynos: support eMMC's HS400 mode
@ 2015-01-08 1:46 ` Jaehoon Chung
0 siblings, 0 replies; 28+ messages in thread
From: Jaehoon Chung @ 2015-01-08 1:46 UTC (permalink / raw)
To: linux-arm-kernel
On 12/31/2014 03:43 PM, Alim Akhtar wrote:
> From: Seungwon Jeon <tgih.jun@samsung.com>
>
> Implements HS400 support for exynos host driver.
> And this patch includes some updates as new mode is added.
>
> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
> ---
> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 6 +
> drivers/mmc/host/dw_mmc-exynos.c | 177 +++++++++++++++-----
> drivers/mmc/host/dw_mmc-exynos.h | 17 +-
> drivers/mmc/host/dw_mmc.c | 16 +-
> drivers/mmc/host/dw_mmc.h | 2 +
> 5 files changed, 178 insertions(+), 40 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> index 06455de..be30c94 100644
> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
> @@ -34,6 +34,7 @@ Required Properties:
> valid values.
>
> * samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
> +* samsung,dw-mshc-hs400-timing: Similar with dw-mshc-ddr-timing.
>
> Notes for the sdr-timing and ddr-timing values:
>
> @@ -51,6 +52,9 @@ Required Properties:
> - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
> phase shift clocks should be 0.
>
> +* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
> + (Latency value for delay line in Read path)
> +
> Required properties for a slot (Deprecated - Recommend to use one slot per host):
>
> * gpios: specifies a list of gpios used for command, clock and data bus. The
> @@ -83,5 +87,7 @@ Example:
> samsung,dw-mshc-sdr-timing = <2 3 3>;
> samsung,dw-mshc-ddr-timing = <1 2 3>;
> samsung,dw-mshc-hs200-timing = <0 2 3>;
> + samsung,dw-mshc-hs400-timing = <0 2 1>;
> + read-strobe-delay = <90>;
> bus-width = <8>;
> };
> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
> index be6530e..d37a631 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.c
> +++ b/drivers/mmc/host/dw_mmc-exynos.c
> @@ -41,7 +41,12 @@ struct dw_mci_exynos_priv_data {
> u32 sdr_timing;
> u32 ddr_timing;
> u32 hs200_timing;
> + u32 hs400_timing;
> + u32 tuned_sample;
> u32 cur_speed;
> + u32 dqs_delay;
> + u32 saved_dqs_en;
> + u32 saved_strobe_ctrl;
> };
>
> static struct dw_mci_exynos_compatible {
> @@ -101,6 +106,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
> }
>
> + if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
> + priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
> + priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
> + priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
> + mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
> + if (!priv->dqs_delay)
> + priv->dqs_delay =
> + DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
> + }
> +
> priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
>
> return 0;
> @@ -115,6 +130,25 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
> return 0;
> }
>
> +static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> + u32 clksel;
> +
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + clksel = mci_readl(host, CLKSEL64);
> + else
> + clksel = mci_readl(host, CLKSEL);
> +
> + clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> + mci_writel(host, CLKSEL64, clksel);
> + else
> + mci_writel(host, CLKSEL, clksel);
> +}
> +
> #ifdef CONFIG_PM_SLEEP
> static int dw_mci_exynos_suspend(struct device *dev)
> {
> @@ -190,35 +224,37 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
> }
> }
>
> -static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> +static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
> {
> struct dw_mci_exynos_priv_data *priv = host->priv;
> - unsigned int wanted = ios->clock;
> - unsigned long actual;
> + u32 dqs, strobe;
>
> - if (ios->timing == MMC_TIMING_MMC_HS200) {
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> - mci_writel(host, CLKSEL64, priv->hs200_timing);
> - else
> - mci_writel(host, CLKSEL, priv->hs200_timing);
> - } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> - mci_writel(host, CLKSEL64, priv->ddr_timing);
> - else
> - mci_writel(host, CLKSEL, priv->ddr_timing);
> - /* Should be double rate for DDR mode */
> - if (ios->bus_width == MMC_BUS_WIDTH_8)
> - wanted <<= 1;
> + /*
> + * Exynos5420 and above controller supports HS400 mode
> + */
> + if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
> + return;
> +
> + dqs = priv->saved_dqs_en;
> + strobe = priv->saved_strobe_ctrl;
> +
> + if (timing == MMC_TIMING_MMC_HS400) {
> + dqs |= DATA_STROBE_EN;
> + strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
> } else {
> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> - mci_writel(host, CLKSEL64, priv->sdr_timing);
> - else
> - mci_writel(host, CLKSEL, priv->sdr_timing);
> + dqs &= ~DATA_STROBE_EN;
> }
>
> + mci_writel(host, HS400_DQS_EN, dqs);
> + mci_writel(host, HS400_DLINE_CTRL, strobe);
> +}
> +
> +static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> + unsigned long actual;
> + u8 div;
> + int ret;
> /*
> * Don't care if wanted clock is zero or
> * ciu clock is unavailable
> @@ -230,18 +266,55 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> if (wanted < EXYNOS_CCLKIN_MIN)
> wanted = EXYNOS_CCLKIN_MIN;
>
> - if (wanted != priv->cur_speed) {
> - u8 div = dw_mci_exynos_get_ciu_div(host);
> - int ret = clk_set_rate(host->ciu_clk, wanted * div);
> - if (ret)
> - dev_warn(host->dev,
> - "failed to set clk-rate %u error: %d\n",
> - wanted * div, ret);
> - actual = clk_get_rate(host->ciu_clk);
> - host->bus_hz = actual / div;
> - priv->cur_speed = wanted;
> - host->current_speed = 0;
> + if (wanted == priv->cur_speed)
> + return;
> +
> + div = dw_mci_exynos_get_ciu_div(host);
> + ret = clk_set_rate(host->ciu_clk, wanted * div);
> + if (ret)
> + dev_warn(host->dev,
> + "failed to set clk-rate %u error: %d\n",
> + wanted * div, ret);
> + actual = clk_get_rate(host->ciu_clk);
> + host->bus_hz = actual / div;
> + priv->cur_speed = wanted;
> + host->current_speed = 0;
> +}
> +
> +static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> + unsigned int wanted = ios->clock;
> + u32 timing = ios->timing, clksel;
> +
> + switch (timing) {
> + case MMC_TIMING_MMC_HS400:
> + /* Update tuned sample timing */
> + clksel = SDMMC_CLKSEL_UP_SAMPLE(
> + priv->hs400_timing, priv->tuned_sample);
> + wanted <<= 1;
> + break;
> + case MMC_TIMING_MMC_HS200:
> + clksel = priv->hs200_timing;
> + break;
> + case MMC_TIMING_MMC_DDR52:
> + clksel = priv->ddr_timing;
> + /* Should be double rate for DDR mode */
> + if (ios->bus_width == MMC_BUS_WIDTH_8)
> + wanted <<= 1;
> + break;
> + default:
> + clksel = priv->sdr_timing;
> }
> +
> + /* Set clock timing for the requested speed mode*/
> + dw_mci_exynos_set_clksel_timing(host, clksel);
> +
> + /* Configure setting for HS400 */
> + dw_mci_exynos_config_hs400(host, timing);
> +
> + /* Configure clock rate */
> + dw_mci_exynos_adjust_clock(host, wanted);
> }
>
> static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
> @@ -294,6 +367,14 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
>
> dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
> +
> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
> + "samsung,dw-mshc-hs400-timing", &priv->hs400_timing);
> + if (!ret && of_property_read_u32(np,
> + "read-strobe-delay", &priv->dqs_delay))
> + dev_info(host->dev,
> + "read-strobe-delay is not found, assuming usage of default value\n");
> +
> host->priv = priv;
>
> return 0;
> @@ -320,7 +401,9 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
> clksel = mci_readl(host, CLKSEL64);
> else
> clksel = mci_readl(host, CLKSEL);
> - clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
> +
> + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
> +
> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> mci_writel(host, CLKSEL64, clksel);
> @@ -339,13 +422,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
> clksel = mci_readl(host, CLKSEL64);
> else
> clksel = mci_readl(host, CLKSEL);
> +
> sample = (clksel + 1) & 0x7;
> - clksel = (clksel & ~0x7) | sample;
> + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
> +
> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
> mci_writel(host, CLKSEL64, clksel);
> else
> mci_writel(host, CLKSEL, clksel);
> +
> return sample;
> }
>
> @@ -378,6 +464,7 @@ out:
> static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
> {
> struct dw_mci *host = slot->host;
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> struct mmc_host *mmc = slot->mmc;
> u8 start_smpl, smpl, candiates = 0;
> s8 found = -1;
> @@ -395,14 +482,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
> } while (start_smpl != smpl);
>
> found = dw_mci_exynos_get_best_clksmpl(candiates);
> - if (found >= 0)
> + if (found >= 0) {
> dw_mci_exynos_set_clksmpl(host, found);
> - else
> + priv->tuned_sample = found;
> + } else {
> ret = -EIO;
> + }
>
> return ret;
> }
>
> +int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
> + struct mmc_ios *ios)
> +{
> + struct dw_mci_exynos_priv_data *priv = host->priv;
> +
> + dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
> + dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
> +
> + return 0;
> +}
> +
> /* Common capabilities of Exynos4/Exynos5 SoC */
> static unsigned long exynos_dwmmc_caps[4] = {
> MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
> @@ -419,6 +519,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
> .set_ios = dw_mci_exynos_set_ios,
> .parse_dt = dw_mci_exynos_parse_dt,
> .execute_tuning = dw_mci_exynos_execute_tuning,
> + .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
> };
>
> static const struct of_device_id dw_mci_exynos_match[] = {
> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
> index c04ecef..e7faffe 100644
> --- a/drivers/mmc/host/dw_mmc-exynos.h
> +++ b/drivers/mmc/host/dw_mmc-exynos.h
> @@ -12,21 +12,36 @@
> #ifndef _DW_MMC_EXYNOS_H_
> #define _DW_MMC_EXYNOS_H_
>
> -/* Extended Register's Offset */
> #define SDMMC_CLKSEL 0x09C
> #define SDMMC_CLKSEL64 0x0A8
>
> +/* Extended Register's Offset */
> +#define SDMMC_HS400_DQS_EN 0x180
> +#define SDMMC_HS400_ASYNC_FIFO_CTRL 0x184
> +#define SDMMC_HS400_DLINE_CTRL 0x188
> +
> /* CLKSEL register defines */
> #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
> #define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
> +#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
> + SDMMC_CLKSEL_CCLK_SAMPLE(y))
> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
> SDMMC_CLKSEL_CCLK_DIVIDER(z))
> +#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
> #define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
>
> +/* HS400 control defines */
> +#define DATA_STROBE_EN BIT(0)
Add comment "xxx register defines."
> +#define AXI_NON_BLOCKING_WR BIT(7)
I can't find this bit and comment..where?
> +
> +/* Delay Line Control defines */
> +#define DQS_CTRL_RD_DELAY(x, y) (((x) & ~0x3FF) | ((y) & 0x3FF))
I'm not understanding this define... clear and set?
Best Regards,
Jaehoon Chung
> +#define DQS_CTRL_GET_RD_DELAY(x) ((x) & 0x3FF)
> +
> /* Protector Register */
> #define SDMMC_EMMCP_BASE 0x1000
> #define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 2e8abc8..43a3a5b 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
> regs = mci_readl(slot->host, UHS_REG);
>
> /* DDR mode set */
> - if (ios->timing == MMC_TIMING_MMC_DDR52)
> + if (ios->timing == MMC_TIMING_MMC_DDR52 ||
> + ios->timing == MMC_TIMING_MMC_HS400)
> regs |= ((0x1 << slot->id) << 16);
> else
> regs &= ~((0x1 << slot->id) << 16);
> @@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
> return err;
> }
>
> +int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
> +{
> + struct dw_mci_slot *slot = mmc_priv(mmc);
> + struct dw_mci *host = slot->host;
> + const struct dw_mci_drv_data *drv_data = host->drv_data;
> +
> + if (drv_data && drv_data->prepare_hs400_tuning)
> + return drv_data->prepare_hs400_tuning(host, ios);
> +
> + return 0;
> +}
> +
> static const struct mmc_host_ops dw_mci_ops = {
> .request = dw_mci_request,
> .pre_req = dw_mci_pre_req,
> @@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
> .card_busy = dw_mci_card_busy,
> .start_signal_voltage_switch = dw_mci_switch_voltage,
> .init_card = dw_mci_init_card,
> + .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
> };
>
> static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 18c4afe..d239867 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -271,5 +271,7 @@ struct dw_mci_drv_data {
> 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 (*prepare_hs400_tuning)(struct dw_mci *host,
> + struct mmc_ios *ios);
> };
> #endif /* _DW_MMC_H_ */
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 2/4] mmc: dw_mmc: exynos: support eMMC's HS400 mode
2015-01-08 1:46 ` Jaehoon Chung
@ 2015-01-08 14:17 ` Alim Akhtar
-1 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2015-01-08 14:17 UTC (permalink / raw)
To: Jaehoon Chung
Cc: devicetree, Ulf Hansson, linux-samsung-soc, Seungwon Jeon,
linux-mmc, Chris Ball, Douglas Anderson, kgene, Alim Akhtar,
Abhilash Kesavan, linux-arm-kernel
Hi Jaehoon,
On Thu, Jan 8, 2015 at 7:16 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> On 12/31/2014 03:43 PM, Alim Akhtar wrote:
>> From: Seungwon Jeon <tgih.jun@samsung.com>
>>
>> Implements HS400 support for exynos host driver.
>> And this patch includes some updates as new mode is added.
>>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
>> ---
>> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 6 +
>> drivers/mmc/host/dw_mmc-exynos.c | 177 +++++++++++++++-----
>> drivers/mmc/host/dw_mmc-exynos.h | 17 +-
>> drivers/mmc/host/dw_mmc.c | 16 +-
>> drivers/mmc/host/dw_mmc.h | 2 +
>> 5 files changed, 178 insertions(+), 40 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> index 06455de..be30c94 100644
>> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> @@ -34,6 +34,7 @@ Required Properties:
>> valid values.
>>
>> * samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
>> +* samsung,dw-mshc-hs400-timing: Similar with dw-mshc-ddr-timing.
>>
>> Notes for the sdr-timing and ddr-timing values:
>>
>> @@ -51,6 +52,9 @@ Required Properties:
>> - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
>> phase shift clocks should be 0.
>>
>> +* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
>> + (Latency value for delay line in Read path)
>> +
>> Required properties for a slot (Deprecated - Recommend to use one slot per host):
>>
>> * gpios: specifies a list of gpios used for command, clock and data bus. The
>> @@ -83,5 +87,7 @@ Example:
>> samsung,dw-mshc-sdr-timing = <2 3 3>;
>> samsung,dw-mshc-ddr-timing = <1 2 3>;
>> samsung,dw-mshc-hs200-timing = <0 2 3>;
>> + samsung,dw-mshc-hs400-timing = <0 2 1>;
>> + read-strobe-delay = <90>;
>> bus-width = <8>;
>> };
>> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
>> index be6530e..d37a631 100644
>> --- a/drivers/mmc/host/dw_mmc-exynos.c
>> +++ b/drivers/mmc/host/dw_mmc-exynos.c
>> @@ -41,7 +41,12 @@ struct dw_mci_exynos_priv_data {
>> u32 sdr_timing;
>> u32 ddr_timing;
>> u32 hs200_timing;
>> + u32 hs400_timing;
>> + u32 tuned_sample;
>> u32 cur_speed;
>> + u32 dqs_delay;
>> + u32 saved_dqs_en;
>> + u32 saved_strobe_ctrl;
>> };
>>
>> static struct dw_mci_exynos_compatible {
>> @@ -101,6 +106,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
>> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
>> }
>>
>> + if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
>> + priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
>> + priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
>> + priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
>> + mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
>> + if (!priv->dqs_delay)
>> + priv->dqs_delay =
>> + DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
>> + }
>> +
>> priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
>>
>> return 0;
>> @@ -115,6 +130,25 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
>> return 0;
>> }
>>
>> +static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> + u32 clksel;
>> +
>> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> + clksel = mci_readl(host, CLKSEL64);
>> + else
>> + clksel = mci_readl(host, CLKSEL);
>> +
>> + clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
>> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> + mci_writel(host, CLKSEL64, clksel);
>> + else
>> + mci_writel(host, CLKSEL, clksel);
>> +}
>> +
>> #ifdef CONFIG_PM_SLEEP
>> static int dw_mci_exynos_suspend(struct device *dev)
>> {
>> @@ -190,35 +224,37 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
>> }
>> }
>>
>> -static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> +static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
>> {
>> struct dw_mci_exynos_priv_data *priv = host->priv;
>> - unsigned int wanted = ios->clock;
>> - unsigned long actual;
>> + u32 dqs, strobe;
>>
>> - if (ios->timing == MMC_TIMING_MMC_HS200) {
>> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> - mci_writel(host, CLKSEL64, priv->hs200_timing);
>> - else
>> - mci_writel(host, CLKSEL, priv->hs200_timing);
>> - } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
>> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> - mci_writel(host, CLKSEL64, priv->ddr_timing);
>> - else
>> - mci_writel(host, CLKSEL, priv->ddr_timing);
>> - /* Should be double rate for DDR mode */
>> - if (ios->bus_width == MMC_BUS_WIDTH_8)
>> - wanted <<= 1;
>> + /*
>> + * Exynos5420 and above controller supports HS400 mode
>> + */
>> + if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
>> + return;
>> +
>> + dqs = priv->saved_dqs_en;
>> + strobe = priv->saved_strobe_ctrl;
>> +
>> + if (timing == MMC_TIMING_MMC_HS400) {
>> + dqs |= DATA_STROBE_EN;
>> + strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
>> } else {
>> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> - mci_writel(host, CLKSEL64, priv->sdr_timing);
>> - else
>> - mci_writel(host, CLKSEL, priv->sdr_timing);
>> + dqs &= ~DATA_STROBE_EN;
>> }
>>
>> + mci_writel(host, HS400_DQS_EN, dqs);
>> + mci_writel(host, HS400_DLINE_CTRL, strobe);
>> +}
>> +
>> +static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> + unsigned long actual;
>> + u8 div;
>> + int ret;
>> /*
>> * Don't care if wanted clock is zero or
>> * ciu clock is unavailable
>> @@ -230,18 +266,55 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> if (wanted < EXYNOS_CCLKIN_MIN)
>> wanted = EXYNOS_CCLKIN_MIN;
>>
>> - if (wanted != priv->cur_speed) {
>> - u8 div = dw_mci_exynos_get_ciu_div(host);
>> - int ret = clk_set_rate(host->ciu_clk, wanted * div);
>> - if (ret)
>> - dev_warn(host->dev,
>> - "failed to set clk-rate %u error: %d\n",
>> - wanted * div, ret);
>> - actual = clk_get_rate(host->ciu_clk);
>> - host->bus_hz = actual / div;
>> - priv->cur_speed = wanted;
>> - host->current_speed = 0;
>> + if (wanted == priv->cur_speed)
>> + return;
>> +
>> + div = dw_mci_exynos_get_ciu_div(host);
>> + ret = clk_set_rate(host->ciu_clk, wanted * div);
>> + if (ret)
>> + dev_warn(host->dev,
>> + "failed to set clk-rate %u error: %d\n",
>> + wanted * div, ret);
>> + actual = clk_get_rate(host->ciu_clk);
>> + host->bus_hz = actual / div;
>> + priv->cur_speed = wanted;
>> + host->current_speed = 0;
>> +}
>> +
>> +static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> + unsigned int wanted = ios->clock;
>> + u32 timing = ios->timing, clksel;
>> +
>> + switch (timing) {
>> + case MMC_TIMING_MMC_HS400:
>> + /* Update tuned sample timing */
>> + clksel = SDMMC_CLKSEL_UP_SAMPLE(
>> + priv->hs400_timing, priv->tuned_sample);
>> + wanted <<= 1;
>> + break;
>> + case MMC_TIMING_MMC_HS200:
>> + clksel = priv->hs200_timing;
>> + break;
>> + case MMC_TIMING_MMC_DDR52:
>> + clksel = priv->ddr_timing;
>> + /* Should be double rate for DDR mode */
>> + if (ios->bus_width == MMC_BUS_WIDTH_8)
>> + wanted <<= 1;
>> + break;
>> + default:
>> + clksel = priv->sdr_timing;
>> }
>> +
>> + /* Set clock timing for the requested speed mode*/
>> + dw_mci_exynos_set_clksel_timing(host, clksel);
>> +
>> + /* Configure setting for HS400 */
>> + dw_mci_exynos_config_hs400(host, timing);
>> +
>> + /* Configure clock rate */
>> + dw_mci_exynos_adjust_clock(host, wanted);
>> }
>>
>> static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
>> @@ -294,6 +367,14 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
>>
>> dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
>> +
>> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> + "samsung,dw-mshc-hs400-timing", &priv->hs400_timing);
>> + if (!ret && of_property_read_u32(np,
>> + "read-strobe-delay", &priv->dqs_delay))
>> + dev_info(host->dev,
>> + "read-strobe-delay is not found, assuming usage of default value\n");
>> +
>> host->priv = priv;
>>
>> return 0;
>> @@ -320,7 +401,9 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
>> clksel = mci_readl(host, CLKSEL64);
>> else
>> clksel = mci_readl(host, CLKSEL);
>> - clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
>> +
>> + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
>> +
>> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> mci_writel(host, CLKSEL64, clksel);
>> @@ -339,13 +422,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
>> clksel = mci_readl(host, CLKSEL64);
>> else
>> clksel = mci_readl(host, CLKSEL);
>> +
>> sample = (clksel + 1) & 0x7;
>> - clksel = (clksel & ~0x7) | sample;
>> + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
>> +
>> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> mci_writel(host, CLKSEL64, clksel);
>> else
>> mci_writel(host, CLKSEL, clksel);
>> +
>> return sample;
>> }
>>
>> @@ -378,6 +464,7 @@ out:
>> static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
>> {
>> struct dw_mci *host = slot->host;
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> struct mmc_host *mmc = slot->mmc;
>> u8 start_smpl, smpl, candiates = 0;
>> s8 found = -1;
>> @@ -395,14 +482,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
>> } while (start_smpl != smpl);
>>
>> found = dw_mci_exynos_get_best_clksmpl(candiates);
>> - if (found >= 0)
>> + if (found >= 0) {
>> dw_mci_exynos_set_clksmpl(host, found);
>> - else
>> + priv->tuned_sample = found;
>> + } else {
>> ret = -EIO;
>> + }
>>
>> return ret;
>> }
>>
>> +int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
>> + struct mmc_ios *ios)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> +
>> + dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
>> + dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
>> +
>> + return 0;
>> +}
>> +
>> /* Common capabilities of Exynos4/Exynos5 SoC */
>> static unsigned long exynos_dwmmc_caps[4] = {
>> MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
>> @@ -419,6 +519,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
>> .set_ios = dw_mci_exynos_set_ios,
>> .parse_dt = dw_mci_exynos_parse_dt,
>> .execute_tuning = dw_mci_exynos_execute_tuning,
>> + .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
>> };
>>
>> static const struct of_device_id dw_mci_exynos_match[] = {
>> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
>> index c04ecef..e7faffe 100644
>> --- a/drivers/mmc/host/dw_mmc-exynos.h
>> +++ b/drivers/mmc/host/dw_mmc-exynos.h
>> @@ -12,21 +12,36 @@
>> #ifndef _DW_MMC_EXYNOS_H_
>> #define _DW_MMC_EXYNOS_H_
>>
>> -/* Extended Register's Offset */
>> #define SDMMC_CLKSEL 0x09C
>> #define SDMMC_CLKSEL64 0x0A8
>>
>> +/* Extended Register's Offset */
>> +#define SDMMC_HS400_DQS_EN 0x180
>> +#define SDMMC_HS400_ASYNC_FIFO_CTRL 0x184
>> +#define SDMMC_HS400_DLINE_CTRL 0x188
>> +
>> /* CLKSEL register defines */
>> #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
>> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
>> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
>> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
>> #define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
>> +#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
>> + SDMMC_CLKSEL_CCLK_SAMPLE(y))
>> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
>> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
>> SDMMC_CLKSEL_CCLK_DIVIDER(z))
>> +#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
>> #define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
>>
>> +/* HS400 control defines */
>> +#define DATA_STROBE_EN BIT(0)
> Add comment "xxx register defines."
>
Ok, will add
>> +#define AXI_NON_BLOCKING_WR BIT(7)
>
> I can't find this bit and comment..where?
>
This is Bit[7] of RCLK_EN register.
>> +
>> +/* Delay Line Control defines */
>> +#define DQS_CTRL_RD_DELAY(x, y) (((x) & ~0x3FF) | ((y) & 0x3FF))
>
> I'm not understanding this define... clear and set?
>
yes, clear default and set the one pass from Device Tree.
> Best Regards,
> Jaehoon Chung
>
>> +#define DQS_CTRL_GET_RD_DELAY(x) ((x) & 0x3FF)
>> +
>> /* Protector Register */
>> #define SDMMC_EMMCP_BASE 0x1000
>> #define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 2e8abc8..43a3a5b 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>> regs = mci_readl(slot->host, UHS_REG);
>>
>> /* DDR mode set */
>> - if (ios->timing == MMC_TIMING_MMC_DDR52)
>> + if (ios->timing == MMC_TIMING_MMC_DDR52 ||
>> + ios->timing == MMC_TIMING_MMC_HS400)
>> regs |= ((0x1 << slot->id) << 16);
>> else
>> regs &= ~((0x1 << slot->id) << 16);
>> @@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
>> return err;
>> }
>>
>> +int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
>> +{
>> + struct dw_mci_slot *slot = mmc_priv(mmc);
>> + struct dw_mci *host = slot->host;
>> + const struct dw_mci_drv_data *drv_data = host->drv_data;
>> +
>> + if (drv_data && drv_data->prepare_hs400_tuning)
>> + return drv_data->prepare_hs400_tuning(host, ios);
>> +
>> + return 0;
>> +}
>> +
>> static const struct mmc_host_ops dw_mci_ops = {
>> .request = dw_mci_request,
>> .pre_req = dw_mci_pre_req,
>> @@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
>> .card_busy = dw_mci_card_busy,
>> .start_signal_voltage_switch = dw_mci_switch_voltage,
>> .init_card = dw_mci_init_card,
>> + .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
>> };
>>
>> static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> index 18c4afe..d239867 100644
>> --- a/drivers/mmc/host/dw_mmc.h
>> +++ b/drivers/mmc/host/dw_mmc.h
>> @@ -271,5 +271,7 @@ struct dw_mci_drv_data {
>> 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 (*prepare_hs400_tuning)(struct dw_mci *host,
>> + struct mmc_ios *ios);
>> };
>> #endif /* _DW_MMC_H_ */
>>
>
--
Regards,
Alim
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 2/4] mmc: dw_mmc: exynos: support eMMC's HS400 mode
@ 2015-01-08 14:17 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2015-01-08 14:17 UTC (permalink / raw)
To: linux-arm-kernel
Hi Jaehoon,
On Thu, Jan 8, 2015 at 7:16 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> On 12/31/2014 03:43 PM, Alim Akhtar wrote:
>> From: Seungwon Jeon <tgih.jun@samsung.com>
>>
>> Implements HS400 support for exynos host driver.
>> And this patch includes some updates as new mode is added.
>>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
>> ---
>> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 6 +
>> drivers/mmc/host/dw_mmc-exynos.c | 177 +++++++++++++++-----
>> drivers/mmc/host/dw_mmc-exynos.h | 17 +-
>> drivers/mmc/host/dw_mmc.c | 16 +-
>> drivers/mmc/host/dw_mmc.h | 2 +
>> 5 files changed, 178 insertions(+), 40 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> index 06455de..be30c94 100644
>> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> @@ -34,6 +34,7 @@ Required Properties:
>> valid values.
>>
>> * samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
>> +* samsung,dw-mshc-hs400-timing: Similar with dw-mshc-ddr-timing.
>>
>> Notes for the sdr-timing and ddr-timing values:
>>
>> @@ -51,6 +52,9 @@ Required Properties:
>> - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
>> phase shift clocks should be 0.
>>
>> +* read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
>> + (Latency value for delay line in Read path)
>> +
>> Required properties for a slot (Deprecated - Recommend to use one slot per host):
>>
>> * gpios: specifies a list of gpios used for command, clock and data bus. The
>> @@ -83,5 +87,7 @@ Example:
>> samsung,dw-mshc-sdr-timing = <2 3 3>;
>> samsung,dw-mshc-ddr-timing = <1 2 3>;
>> samsung,dw-mshc-hs200-timing = <0 2 3>;
>> + samsung,dw-mshc-hs400-timing = <0 2 1>;
>> + read-strobe-delay = <90>;
>> bus-width = <8>;
>> };
>> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
>> index be6530e..d37a631 100644
>> --- a/drivers/mmc/host/dw_mmc-exynos.c
>> +++ b/drivers/mmc/host/dw_mmc-exynos.c
>> @@ -41,7 +41,12 @@ struct dw_mci_exynos_priv_data {
>> u32 sdr_timing;
>> u32 ddr_timing;
>> u32 hs200_timing;
>> + u32 hs400_timing;
>> + u32 tuned_sample;
>> u32 cur_speed;
>> + u32 dqs_delay;
>> + u32 saved_dqs_en;
>> + u32 saved_strobe_ctrl;
>> };
>>
>> static struct dw_mci_exynos_compatible {
>> @@ -101,6 +106,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
>> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
>> }
>>
>> + if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
>> + priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
>> + priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
>> + priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
>> + mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
>> + if (!priv->dqs_delay)
>> + priv->dqs_delay =
>> + DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
>> + }
>> +
>> priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
>>
>> return 0;
>> @@ -115,6 +130,25 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
>> return 0;
>> }
>>
>> +static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> + u32 clksel;
>> +
>> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> + clksel = mci_readl(host, CLKSEL64);
>> + else
>> + clksel = mci_readl(host, CLKSEL);
>> +
>> + clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
>> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> + mci_writel(host, CLKSEL64, clksel);
>> + else
>> + mci_writel(host, CLKSEL, clksel);
>> +}
>> +
>> #ifdef CONFIG_PM_SLEEP
>> static int dw_mci_exynos_suspend(struct device *dev)
>> {
>> @@ -190,35 +224,37 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
>> }
>> }
>>
>> -static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> +static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
>> {
>> struct dw_mci_exynos_priv_data *priv = host->priv;
>> - unsigned int wanted = ios->clock;
>> - unsigned long actual;
>> + u32 dqs, strobe;
>>
>> - if (ios->timing == MMC_TIMING_MMC_HS200) {
>> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> - mci_writel(host, CLKSEL64, priv->hs200_timing);
>> - else
>> - mci_writel(host, CLKSEL, priv->hs200_timing);
>> - } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
>> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> - mci_writel(host, CLKSEL64, priv->ddr_timing);
>> - else
>> - mci_writel(host, CLKSEL, priv->ddr_timing);
>> - /* Should be double rate for DDR mode */
>> - if (ios->bus_width == MMC_BUS_WIDTH_8)
>> - wanted <<= 1;
>> + /*
>> + * Exynos5420 and above controller supports HS400 mode
>> + */
>> + if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
>> + return;
>> +
>> + dqs = priv->saved_dqs_en;
>> + strobe = priv->saved_strobe_ctrl;
>> +
>> + if (timing == MMC_TIMING_MMC_HS400) {
>> + dqs |= DATA_STROBE_EN;
>> + strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
>> } else {
>> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> - priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> - mci_writel(host, CLKSEL64, priv->sdr_timing);
>> - else
>> - mci_writel(host, CLKSEL, priv->sdr_timing);
>> + dqs &= ~DATA_STROBE_EN;
>> }
>>
>> + mci_writel(host, HS400_DQS_EN, dqs);
>> + mci_writel(host, HS400_DLINE_CTRL, strobe);
>> +}
>> +
>> +static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> + unsigned long actual;
>> + u8 div;
>> + int ret;
>> /*
>> * Don't care if wanted clock is zero or
>> * ciu clock is unavailable
>> @@ -230,18 +266,55 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> if (wanted < EXYNOS_CCLKIN_MIN)
>> wanted = EXYNOS_CCLKIN_MIN;
>>
>> - if (wanted != priv->cur_speed) {
>> - u8 div = dw_mci_exynos_get_ciu_div(host);
>> - int ret = clk_set_rate(host->ciu_clk, wanted * div);
>> - if (ret)
>> - dev_warn(host->dev,
>> - "failed to set clk-rate %u error: %d\n",
>> - wanted * div, ret);
>> - actual = clk_get_rate(host->ciu_clk);
>> - host->bus_hz = actual / div;
>> - priv->cur_speed = wanted;
>> - host->current_speed = 0;
>> + if (wanted == priv->cur_speed)
>> + return;
>> +
>> + div = dw_mci_exynos_get_ciu_div(host);
>> + ret = clk_set_rate(host->ciu_clk, wanted * div);
>> + if (ret)
>> + dev_warn(host->dev,
>> + "failed to set clk-rate %u error: %d\n",
>> + wanted * div, ret);
>> + actual = clk_get_rate(host->ciu_clk);
>> + host->bus_hz = actual / div;
>> + priv->cur_speed = wanted;
>> + host->current_speed = 0;
>> +}
>> +
>> +static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> + unsigned int wanted = ios->clock;
>> + u32 timing = ios->timing, clksel;
>> +
>> + switch (timing) {
>> + case MMC_TIMING_MMC_HS400:
>> + /* Update tuned sample timing */
>> + clksel = SDMMC_CLKSEL_UP_SAMPLE(
>> + priv->hs400_timing, priv->tuned_sample);
>> + wanted <<= 1;
>> + break;
>> + case MMC_TIMING_MMC_HS200:
>> + clksel = priv->hs200_timing;
>> + break;
>> + case MMC_TIMING_MMC_DDR52:
>> + clksel = priv->ddr_timing;
>> + /* Should be double rate for DDR mode */
>> + if (ios->bus_width == MMC_BUS_WIDTH_8)
>> + wanted <<= 1;
>> + break;
>> + default:
>> + clksel = priv->sdr_timing;
>> }
>> +
>> + /* Set clock timing for the requested speed mode*/
>> + dw_mci_exynos_set_clksel_timing(host, clksel);
>> +
>> + /* Configure setting for HS400 */
>> + dw_mci_exynos_config_hs400(host, timing);
>> +
>> + /* Configure clock rate */
>> + dw_mci_exynos_adjust_clock(host, wanted);
>> }
>>
>> static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
>> @@ -294,6 +367,14 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
>>
>> dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
>> +
>> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> + "samsung,dw-mshc-hs400-timing", &priv->hs400_timing);
>> + if (!ret && of_property_read_u32(np,
>> + "read-strobe-delay", &priv->dqs_delay))
>> + dev_info(host->dev,
>> + "read-strobe-delay is not found, assuming usage of default value\n");
>> +
>> host->priv = priv;
>>
>> return 0;
>> @@ -320,7 +401,9 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
>> clksel = mci_readl(host, CLKSEL64);
>> else
>> clksel = mci_readl(host, CLKSEL);
>> - clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
>> +
>> + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
>> +
>> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> mci_writel(host, CLKSEL64, clksel);
>> @@ -339,13 +422,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
>> clksel = mci_readl(host, CLKSEL64);
>> else
>> clksel = mci_readl(host, CLKSEL);
>> +
>> sample = (clksel + 1) & 0x7;
>> - clksel = (clksel & ~0x7) | sample;
>> + clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
>> +
>> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> mci_writel(host, CLKSEL64, clksel);
>> else
>> mci_writel(host, CLKSEL, clksel);
>> +
>> return sample;
>> }
>>
>> @@ -378,6 +464,7 @@ out:
>> static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
>> {
>> struct dw_mci *host = slot->host;
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> struct mmc_host *mmc = slot->mmc;
>> u8 start_smpl, smpl, candiates = 0;
>> s8 found = -1;
>> @@ -395,14 +482,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
>> } while (start_smpl != smpl);
>>
>> found = dw_mci_exynos_get_best_clksmpl(candiates);
>> - if (found >= 0)
>> + if (found >= 0) {
>> dw_mci_exynos_set_clksmpl(host, found);
>> - else
>> + priv->tuned_sample = found;
>> + } else {
>> ret = -EIO;
>> + }
>>
>> return ret;
>> }
>>
>> +int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
>> + struct mmc_ios *ios)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> +
>> + dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
>> + dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
>> +
>> + return 0;
>> +}
>> +
>> /* Common capabilities of Exynos4/Exynos5 SoC */
>> static unsigned long exynos_dwmmc_caps[4] = {
>> MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
>> @@ -419,6 +519,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
>> .set_ios = dw_mci_exynos_set_ios,
>> .parse_dt = dw_mci_exynos_parse_dt,
>> .execute_tuning = dw_mci_exynos_execute_tuning,
>> + .prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
>> };
>>
>> static const struct of_device_id dw_mci_exynos_match[] = {
>> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
>> index c04ecef..e7faffe 100644
>> --- a/drivers/mmc/host/dw_mmc-exynos.h
>> +++ b/drivers/mmc/host/dw_mmc-exynos.h
>> @@ -12,21 +12,36 @@
>> #ifndef _DW_MMC_EXYNOS_H_
>> #define _DW_MMC_EXYNOS_H_
>>
>> -/* Extended Register's Offset */
>> #define SDMMC_CLKSEL 0x09C
>> #define SDMMC_CLKSEL64 0x0A8
>>
>> +/* Extended Register's Offset */
>> +#define SDMMC_HS400_DQS_EN 0x180
>> +#define SDMMC_HS400_ASYNC_FIFO_CTRL 0x184
>> +#define SDMMC_HS400_DLINE_CTRL 0x188
>> +
>> /* CLKSEL register defines */
>> #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
>> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
>> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
>> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
>> #define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
>> +#define SDMMC_CLKSEL_UP_SAMPLE(x, y) (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
>> + SDMMC_CLKSEL_CCLK_SAMPLE(y))
>> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
>> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
>> SDMMC_CLKSEL_CCLK_DIVIDER(z))
>> +#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
>> #define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
>>
>> +/* HS400 control defines */
>> +#define DATA_STROBE_EN BIT(0)
> Add comment "xxx register defines."
>
Ok, will add
>> +#define AXI_NON_BLOCKING_WR BIT(7)
>
> I can't find this bit and comment..where?
>
This is Bit[7] of RCLK_EN register.
>> +
>> +/* Delay Line Control defines */
>> +#define DQS_CTRL_RD_DELAY(x, y) (((x) & ~0x3FF) | ((y) & 0x3FF))
>
> I'm not understanding this define... clear and set?
>
yes, clear default and set the one pass from Device Tree.
> Best Regards,
> Jaehoon Chung
>
>> +#define DQS_CTRL_GET_RD_DELAY(x) ((x) & 0x3FF)
>> +
>> /* Protector Register */
>> #define SDMMC_EMMCP_BASE 0x1000
>> #define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 2e8abc8..43a3a5b 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -1084,7 +1084,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>> regs = mci_readl(slot->host, UHS_REG);
>>
>> /* DDR mode set */
>> - if (ios->timing == MMC_TIMING_MMC_DDR52)
>> + if (ios->timing == MMC_TIMING_MMC_DDR52 ||
>> + ios->timing == MMC_TIMING_MMC_HS400)
>> regs |= ((0x1 << slot->id) << 16);
>> else
>> regs &= ~((0x1 << slot->id) << 16);
>> @@ -1321,6 +1322,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
>> return err;
>> }
>>
>> +int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
>> +{
>> + struct dw_mci_slot *slot = mmc_priv(mmc);
>> + struct dw_mci *host = slot->host;
>> + const struct dw_mci_drv_data *drv_data = host->drv_data;
>> +
>> + if (drv_data && drv_data->prepare_hs400_tuning)
>> + return drv_data->prepare_hs400_tuning(host, ios);
>> +
>> + return 0;
>> +}
>> +
>> static const struct mmc_host_ops dw_mci_ops = {
>> .request = dw_mci_request,
>> .pre_req = dw_mci_pre_req,
>> @@ -1333,6 +1346,7 @@ static const struct mmc_host_ops dw_mci_ops = {
>> .card_busy = dw_mci_card_busy,
>> .start_signal_voltage_switch = dw_mci_switch_voltage,
>> .init_card = dw_mci_init_card,
>> + .prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
>> };
>>
>> static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> index 18c4afe..d239867 100644
>> --- a/drivers/mmc/host/dw_mmc.h
>> +++ b/drivers/mmc/host/dw_mmc.h
>> @@ -271,5 +271,7 @@ struct dw_mci_drv_data {
>> 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 (*prepare_hs400_tuning)(struct dw_mci *host,
>> + struct mmc_ios *ios);
>> };
>> #endif /* _DW_MMC_H_ */
>>
>
--
Regards,
Alim
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
2015-01-06 1:07 ` Doug Anderson
@ 2015-01-12 13:52 ` Alim Akhtar
-1 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2015-01-12 13:52 UTC (permalink / raw)
To: Doug Anderson
Cc: Alim Akhtar, linux-mmc, Chris Ball, Ulf Hansson, Jaehoon Chung,
Seungwon Jeon, kgene, linux-arm-kernel, devicetree,
linux-samsung-soc, Abhilash Kesavan, Alexandru Stan,
Heiko Stübner, Javier Martinez Canillas, Olof Johansson,
Kevin Hilman
Hi Doug,
On Tue, Jan 6, 2015 at 6:37 AM, Doug Anderson <dianders@chromium.org> wrote:
> Alim,
>
> On Sun, Jan 4, 2015 at 2:43 PM, Alim Akhtar <alim.akhtar@gmail.com> wrote:
>>> You are breaking backward compatibility here. If your change is
>>> merged then all old boards will instantly break. Since the "dts" and
>>> code changes will likely be merged through different trees you'll end
>>> up with a bunch of broken trees until everything is merged together.
>>> Even if you don't subscribe to the stable bindings theory this is not
>>> acceptable.
>>>
>> yes the major concern in this series is probably this, which breaks
>> things unless everything merge in one go and via one tree. Thats why I
>> re-based everything including dts change on mmc-tree for this case and
>> added device-tree mailing list for more opinion etc.
>
> Got it. I doubt that folks will like this, but I could be wrong. In
> order for this to work, you'd need all changes in the series to land
> in _both_ the ARMSoC tree and the MMC tree. That's not unheard of,
> but it doesn't seem ideal.
>
> You also break bisect-ability here since without the code the DTS
> change will break things and without the DTS change the code will
> break things.
>
> If you add all the above to the fact that bindings are supposed to be
> stable (ish) I'm not convinced this will land.
>
Hmmm......Ok, let me take a re-look on this, I will try to use
existing bindings.
>
> -Doug
--
Regards,
Alim
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
@ 2015-01-12 13:52 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2015-01-12 13:52 UTC (permalink / raw)
To: linux-arm-kernel
Hi Doug,
On Tue, Jan 6, 2015 at 6:37 AM, Doug Anderson <dianders@chromium.org> wrote:
> Alim,
>
> On Sun, Jan 4, 2015 at 2:43 PM, Alim Akhtar <alim.akhtar@gmail.com> wrote:
>>> You are breaking backward compatibility here. If your change is
>>> merged then all old boards will instantly break. Since the "dts" and
>>> code changes will likely be merged through different trees you'll end
>>> up with a bunch of broken trees until everything is merged together.
>>> Even if you don't subscribe to the stable bindings theory this is not
>>> acceptable.
>>>
>> yes the major concern in this series is probably this, which breaks
>> things unless everything merge in one go and via one tree. Thats why I
>> re-based everything including dts change on mmc-tree for this case and
>> added device-tree mailing list for more opinion etc.
>
> Got it. I doubt that folks will like this, but I could be wrong. In
> order for this to work, you'd need all changes in the series to land
> in _both_ the ARMSoC tree and the MMC tree. That's not unheard of,
> but it doesn't seem ideal.
>
> You also break bisect-ability here since without the code the DTS
> change will break things and without the DTS change the code will
> break things.
>
> If you add all the above to the fact that bindings are supposed to be
> stable (ish) I'm not convinced this will land.
>
Hmmm......Ok, let me take a re-look on this, I will try to use
existing bindings.
>
> -Doug
--
Regards,
Alim
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
2015-01-08 1:36 ` Jaehoon Chung
@ 2015-01-12 13:55 ` Alim Akhtar
-1 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2015-01-12 13:55 UTC (permalink / raw)
To: Jaehoon Chung
Cc: Alim Akhtar, linux-mmc, Chris Ball, Ulf Hansson, Seungwon Jeon,
Douglas Anderson, kgene, linux-arm-kernel, devicetree,
linux-samsung-soc, Abhilash Kesavan
Hi Jaehoon,
On Thu, Jan 8, 2015 at 7:06 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> Hi,
>
> On 12/31/2014 03:43 PM, Alim Akhtar wrote:
>> From: Seungwon Jeon <tgih.jun@samsung.com>
>>
>> ciu_div may not be common value for all speed mode.
>> So, it needs to be attached to CLKSEL timing.
>> This also introduce a new compatibale 'dw-mshc-hs200-timing'
>> for selecting hs200 timing value
>>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
>> ---
>> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
>> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
>> drivers/mmc/host/dw_mmc-exynos.h | 1 +
>> 3 files changed, 67 insertions(+), 30 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> index ee4fc05..06455de 100644
>> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> @@ -23,10 +23,6 @@ Required Properties:
>> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
>> specific extensions having an SMU.
>>
>> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
>> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
>> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>> -
>> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
>> in transmit mode and CIU clock phase shift value in receive mode for single
>> data rate mode operation. Refer notes below for the order of the cells and the
>> @@ -37,11 +33,16 @@ Required Properties:
>> data rate mode operation. Refer notes below for the order of the cells and the
>> valid values.
>>
>> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
>
> What does this comment mean? "Similar with dw-mshc-sdr-timing"
> how about adding the comment "optional"?
>
> And i think this timing doesn't need, we can reuse the sdr-timing or ddr-timing.
> Because it's re-configurated at tuning time, isn't?
>
Ok, I will rework/drop this patch, I will try to use existing binding
as much as mush possible.
>> +
>> Notes for the sdr-timing and ddr-timing values:
>>
>> The order of the cells should be
>> - First Cell: CIU clock phase shift value for tx mode.
>> - Second Cell: CIU clock phase shift value for rx mode.
>> + - Thrid Cell: Specifies the divider value for the card interface
>> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
>> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>>
>> Valid values for SDR and DDR CIU clock timing for Exynos5250:
>> - valid value for tx phase shift and rx phase shift is 0 to 7.
>> @@ -79,8 +80,8 @@ Example:
>> broken-cd;
>> fifo-depth = <0x80>;
>> card-detect-delay = <200>;
>> - samsung,dw-mshc-ciu-div = <3>;
>> - samsung,dw-mshc-sdr-timing = <2 3>;
>> - samsung,dw-mshc-ddr-timing = <1 2>;
>> + samsung,dw-mshc-sdr-timing = <2 3 3>;
>> + samsung,dw-mshc-ddr-timing = <1 2 3>;
>> + samsung,dw-mshc-hs200-timing = <0 2 3>;
>> bus-width = <8>;
>> };
>> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
>> index 12a5eaa..be6530e 100644
>> --- a/drivers/mmc/host/dw_mmc-exynos.c
>> +++ b/drivers/mmc/host/dw_mmc-exynos.c
>> @@ -40,6 +40,7 @@ struct dw_mci_exynos_priv_data {
>> u8 ciu_div;
>> u32 sdr_timing;
>> u32 ddr_timing;
>> + u32 hs200_timing;
>> u32 cur_speed;
>> };
>>
>> @@ -71,6 +72,21 @@ static struct dw_mci_exynos_compatible {
>> },
>> };
>>
>> +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> +
>> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
>> + return EXYNOS4412_FIXED_CIU_CLK_DIV;
>> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
>> + return EXYNOS4210_FIXED_CIU_CLK_DIV;
>> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
>> + else
>> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
>
> If need this, I think more readable that use the switch-case statement. how about?
>
> switch (priv->ctrl_type) {
> case DW_MCI_TYPE_EXYNOS4412:
> return EXYNOS4412_FIXED_CIU_CLK_DIV;
> case DW_MCI_TYPE_EXYNOS4210:
> return EXYNOS4210_FIXED_CIU_CLK_DIV;
> case DW_MCI_TYPE_EXYNOS7:
> case DW_MCI_TYPE_EXYNOS7_SMU:
> return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
> default:
> return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
> }
>
>
>> +}
>> +
>> static int dw_mci_exynos_priv_init(struct dw_mci *host)
>> {
>> struct dw_mci_exynos_priv_data *priv = host->priv;
>> @@ -85,6 +101,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
>> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
>> }
>>
>> + priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
>> +
>> return 0;
>> }
>>
>> @@ -92,7 +110,7 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
>> {
>> struct dw_mci_exynos_priv_data *priv = host->priv;
>>
>> - host->bus_hz /= (priv->ciu_div + 1);
>> + host->bus_hz /= priv->ciu_div;
>>
>> return 0;
>> }
>> @@ -177,9 +195,14 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> struct dw_mci_exynos_priv_data *priv = host->priv;
>> unsigned int wanted = ios->clock;
>> unsigned long actual;
>> - u8 div = priv->ciu_div + 1;
>>
>> - if (ios->timing == MMC_TIMING_MMC_DDR52) {
>> + if (ios->timing == MMC_TIMING_MMC_HS200) {
>> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> + mci_writel(host, CLKSEL64, priv->hs200_timing);
>> + else
>> + mci_writel(host, CLKSEL, priv->hs200_timing);
>> + } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
>> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> mci_writel(host, CLKSEL64, priv->ddr_timing);
>> @@ -208,6 +231,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> wanted = EXYNOS_CCLKIN_MIN;
>>
>> if (wanted != priv->cur_speed) {
>> + u8 div = dw_mci_exynos_get_ciu_div(host);
>> int ret = clk_set_rate(host->ciu_clk, wanted * div);
>> if (ret)
>> dev_warn(host->dev,
>> @@ -220,14 +244,34 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> }
>> }
>>
>> +static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
>> + unsigned int ctrl_type,
>> + const char *propname,
>> + u32 *out_values)
>> +{
>> + struct device_node *np = host->dev->of_node;
>> + u32 timing[3];
>> + int ret;
>> +
>> + ret = of_property_read_u32_array(np, propname, timing, 3);
>> + if (ret)
>> + return ret;
>> +
>> + if (ctrl_type == DW_MCI_TYPE_EXYNOS4412 ||
>> + ctrl_type == DW_MCI_TYPE_EXYNOS4210)
>> + timing[2] = 0;
>
> Is it set to 0 into dt-file?
>
>> +
>> + *out_values = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2]);
>> +
>> + return 0;
>> +}
>> +
>> +
>> static int dw_mci_exynos_parse_dt(struct dw_mci *host)
>> {
>> struct dw_mci_exynos_priv_data *priv;
>> struct device_node *np = host->dev->of_node;
>> - u32 timing[2];
>> - u32 div = 0;
>> - int idx;
>> - int ret;
>> + int idx, ret;
>>
>> priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
>> if (!priv)
>> @@ -238,29 +282,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
>> priv->ctrl_type = exynos_compat[idx].ctrl_type;
>> }
>>
>> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
>> - priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
>> - else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
>> - priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
>> - else {
>> - of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
>> - priv->ciu_div = div;
>> - }
>> -
>> - ret = of_property_read_u32_array(np,
>> - "samsung,dw-mshc-sdr-timing", timing, 2);
>> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> + "samsung,dw-mshc-sdr-timing", &priv->sdr_timing);
>> if (ret)
>> return ret;
>>
>> - priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
>> -
>> - ret = of_property_read_u32_array(np,
>> - "samsung,dw-mshc-ddr-timing", timing, 2);
>> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> + "samsung,dw-mshc-ddr-timing", &priv->ddr_timing);
>> if (ret)
>> return ret;
>>
>> - priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
>> + dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> + "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
>
> hs200-timing is optional, so it needs not to check return value, right?
>
> Best Regards,
> Jaehoon Chung
>
>> host->priv = priv;
>> +
>> return 0;
>> }
>>
>> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
>> index 7872ce5..c04ecef 100644
>> --- a/drivers/mmc/host/dw_mmc-exynos.h
>> +++ b/drivers/mmc/host/dw_mmc-exynos.h
>> @@ -21,6 +21,7 @@
>> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
>> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
>> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
>> +#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
>> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
>> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
>> SDMMC_CLKSEL_CCLK_DIVIDER(z))
>>
>
--
Regards,
Alim
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property
@ 2015-01-12 13:55 ` Alim Akhtar
0 siblings, 0 replies; 28+ messages in thread
From: Alim Akhtar @ 2015-01-12 13:55 UTC (permalink / raw)
To: linux-arm-kernel
Hi Jaehoon,
On Thu, Jan 8, 2015 at 7:06 AM, Jaehoon Chung <jh80.chung@samsung.com> wrote:
> Hi,
>
> On 12/31/2014 03:43 PM, Alim Akhtar wrote:
>> From: Seungwon Jeon <tgih.jun@samsung.com>
>>
>> ciu_div may not be common value for all speed mode.
>> So, it needs to be attached to CLKSEL timing.
>> This also introduce a new compatibale 'dw-mshc-hs200-timing'
>> for selecting hs200 timing value
>>
>> Signed-off-by: Seungwon Jeon <tgih.jun@samsung.com>
>> Signed-off-by: Alim Akhtar <alim.akhtar@samsung.com>
>> ---
>> .../devicetree/bindings/mmc/exynos-dw-mshc.txt | 15 ++--
>> drivers/mmc/host/dw_mmc-exynos.c | 81 ++++++++++++++------
>> drivers/mmc/host/dw_mmc-exynos.h | 1 +
>> 3 files changed, 67 insertions(+), 30 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> index ee4fc05..06455de 100644
>> --- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
>> @@ -23,10 +23,6 @@ Required Properties:
>> - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
>> specific extensions having an SMU.
>>
>> -* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
>> - unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
>> - ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>> -
>> * samsung,dw-mshc-sdr-timing: Specifies the value of CIU clock phase shift value
>> in transmit mode and CIU clock phase shift value in receive mode for single
>> data rate mode operation. Refer notes below for the order of the cells and the
>> @@ -37,11 +33,16 @@ Required Properties:
>> data rate mode operation. Refer notes below for the order of the cells and the
>> valid values.
>>
>> +* samsung,dw-mshc-hs200-timing: Similar with dw-mshc-sdr-timing.
>
> What does this comment mean? "Similar with dw-mshc-sdr-timing"
> how about adding the comment "optional"?
>
> And i think this timing doesn't need, we can reuse the sdr-timing or ddr-timing.
> Because it's re-configurated at tuning time, isn't?
>
Ok, I will rework/drop this patch, I will try to use existing binding
as much as mush possible.
>> +
>> Notes for the sdr-timing and ddr-timing values:
>>
>> The order of the cells should be
>> - First Cell: CIU clock phase shift value for tx mode.
>> - Second Cell: CIU clock phase shift value for rx mode.
>> + - Thrid Cell: Specifies the divider value for the card interface
>> + unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
>> + ignored for Exynos4 SoC's. The valid range of divider value is 0 to 7.
>>
>> Valid values for SDR and DDR CIU clock timing for Exynos5250:
>> - valid value for tx phase shift and rx phase shift is 0 to 7.
>> @@ -79,8 +80,8 @@ Example:
>> broken-cd;
>> fifo-depth = <0x80>;
>> card-detect-delay = <200>;
>> - samsung,dw-mshc-ciu-div = <3>;
>> - samsung,dw-mshc-sdr-timing = <2 3>;
>> - samsung,dw-mshc-ddr-timing = <1 2>;
>> + samsung,dw-mshc-sdr-timing = <2 3 3>;
>> + samsung,dw-mshc-ddr-timing = <1 2 3>;
>> + samsung,dw-mshc-hs200-timing = <0 2 3>;
>> bus-width = <8>;
>> };
>> diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
>> index 12a5eaa..be6530e 100644
>> --- a/drivers/mmc/host/dw_mmc-exynos.c
>> +++ b/drivers/mmc/host/dw_mmc-exynos.c
>> @@ -40,6 +40,7 @@ struct dw_mci_exynos_priv_data {
>> u8 ciu_div;
>> u32 sdr_timing;
>> u32 ddr_timing;
>> + u32 hs200_timing;
>> u32 cur_speed;
>> };
>>
>> @@ -71,6 +72,21 @@ static struct dw_mci_exynos_compatible {
>> },
>> };
>>
>> +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
>> +{
>> + struct dw_mci_exynos_priv_data *priv = host->priv;
>> +
>> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
>> + return EXYNOS4412_FIXED_CIU_CLK_DIV;
>> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
>> + return EXYNOS4210_FIXED_CIU_CLK_DIV;
>> + else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
>> + else
>> + return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
>
> If need this, I think more readable that use the switch-case statement. how about?
>
> switch (priv->ctrl_type) {
> case DW_MCI_TYPE_EXYNOS4412:
> return EXYNOS4412_FIXED_CIU_CLK_DIV;
> case DW_MCI_TYPE_EXYNOS4210:
> return EXYNOS4210_FIXED_CIU_CLK_DIV;
> case DW_MCI_TYPE_EXYNOS7:
> case DW_MCI_TYPE_EXYNOS7_SMU:
> return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
> default:
> return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
> }
>
>
>> +}
>> +
>> static int dw_mci_exynos_priv_init(struct dw_mci *host)
>> {
>> struct dw_mci_exynos_priv_data *priv = host->priv;
>> @@ -85,6 +101,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
>> SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
>> }
>>
>> + priv->ciu_div = dw_mci_exynos_get_ciu_div(host);
>> +
>> return 0;
>> }
>>
>> @@ -92,7 +110,7 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
>> {
>> struct dw_mci_exynos_priv_data *priv = host->priv;
>>
>> - host->bus_hz /= (priv->ciu_div + 1);
>> + host->bus_hz /= priv->ciu_div;
>>
>> return 0;
>> }
>> @@ -177,9 +195,14 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> struct dw_mci_exynos_priv_data *priv = host->priv;
>> unsigned int wanted = ios->clock;
>> unsigned long actual;
>> - u8 div = priv->ciu_div + 1;
>>
>> - if (ios->timing == MMC_TIMING_MMC_DDR52) {
>> + if (ios->timing == MMC_TIMING_MMC_HS200) {
>> + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> + priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> + mci_writel(host, CLKSEL64, priv->hs200_timing);
>> + else
>> + mci_writel(host, CLKSEL, priv->hs200_timing);
>> + } else if (ios->timing == MMC_TIMING_MMC_DDR52) {
>> if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
>> priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
>> mci_writel(host, CLKSEL64, priv->ddr_timing);
>> @@ -208,6 +231,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> wanted = EXYNOS_CCLKIN_MIN;
>>
>> if (wanted != priv->cur_speed) {
>> + u8 div = dw_mci_exynos_get_ciu_div(host);
>> int ret = clk_set_rate(host->ciu_clk, wanted * div);
>> if (ret)
>> dev_warn(host->dev,
>> @@ -220,14 +244,34 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>> }
>> }
>>
>> +static int dw_mci_exynos_dt_populate_timing(struct dw_mci *host,
>> + unsigned int ctrl_type,
>> + const char *propname,
>> + u32 *out_values)
>> +{
>> + struct device_node *np = host->dev->of_node;
>> + u32 timing[3];
>> + int ret;
>> +
>> + ret = of_property_read_u32_array(np, propname, timing, 3);
>> + if (ret)
>> + return ret;
>> +
>> + if (ctrl_type == DW_MCI_TYPE_EXYNOS4412 ||
>> + ctrl_type == DW_MCI_TYPE_EXYNOS4210)
>> + timing[2] = 0;
>
> Is it set to 0 into dt-file?
>
>> +
>> + *out_values = SDMMC_CLKSEL_TIMING(timing[0], timing[1], timing[2]);
>> +
>> + return 0;
>> +}
>> +
>> +
>> static int dw_mci_exynos_parse_dt(struct dw_mci *host)
>> {
>> struct dw_mci_exynos_priv_data *priv;
>> struct device_node *np = host->dev->of_node;
>> - u32 timing[2];
>> - u32 div = 0;
>> - int idx;
>> - int ret;
>> + int idx, ret;
>>
>> priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
>> if (!priv)
>> @@ -238,29 +282,20 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
>> priv->ctrl_type = exynos_compat[idx].ctrl_type;
>> }
>>
>> - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
>> - priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
>> - else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
>> - priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
>> - else {
>> - of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
>> - priv->ciu_div = div;
>> - }
>> -
>> - ret = of_property_read_u32_array(np,
>> - "samsung,dw-mshc-sdr-timing", timing, 2);
>> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> + "samsung,dw-mshc-sdr-timing", &priv->sdr_timing);
>> if (ret)
>> return ret;
>>
>> - priv->sdr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
>> -
>> - ret = of_property_read_u32_array(np,
>> - "samsung,dw-mshc-ddr-timing", timing, 2);
>> + ret = dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> + "samsung,dw-mshc-ddr-timing", &priv->ddr_timing);
>> if (ret)
>> return ret;
>>
>> - priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
>> + dw_mci_exynos_dt_populate_timing(host, priv->ctrl_type,
>> + "samsung,dw-mshc-hs200-timing", &priv->hs200_timing);
>
> hs200-timing is optional, so it needs not to check return value, right?
>
> Best Regards,
> Jaehoon Chung
>
>> host->priv = priv;
>> +
>> return 0;
>> }
>>
>> diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
>> index 7872ce5..c04ecef 100644
>> --- a/drivers/mmc/host/dw_mmc-exynos.h
>> +++ b/drivers/mmc/host/dw_mmc-exynos.h
>> @@ -21,6 +21,7 @@
>> #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
>> #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
>> #define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
>> +#define SDMMC_CLKSEL_GET_DIV(x) (((x) >> 24) & 0x7)
>> #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
>> SDMMC_CLKSEL_CCLK_DRIVE(y) | \
>> SDMMC_CLKSEL_CCLK_DIVIDER(z))
>>
>
--
Regards,
Alim
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2015-01-12 13:55 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-12-31 6:43 [PATCH v3 0/4] mmc: dw_mmc: exynos: Add HS400 support Alim Akhtar
2014-12-31 6:43 ` Alim Akhtar
2014-12-31 6:43 ` [PATCH v3 1/4] mmc: dw_mmc: exynos: incorporate ciu_div into timing property Alim Akhtar
2014-12-31 6:43 ` Alim Akhtar
2015-01-02 10:30 ` Ulf Hansson
2015-01-02 10:30 ` Ulf Hansson
2015-01-02 16:58 ` Doug Anderson
2015-01-02 16:58 ` Doug Anderson
2015-01-04 22:43 ` Alim Akhtar
2015-01-04 22:43 ` Alim Akhtar
[not found] ` <CAGOxZ509kASim7keNkAGj5gAGO02=7vZM=VL-MRMObv3x+CzTg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-01-06 1:07 ` Doug Anderson
2015-01-06 1:07 ` Doug Anderson
2015-01-12 13:52 ` Alim Akhtar
2015-01-12 13:52 ` Alim Akhtar
2015-01-08 1:36 ` Jaehoon Chung
2015-01-08 1:36 ` Jaehoon Chung
2015-01-12 13:55 ` Alim Akhtar
2015-01-12 13:55 ` Alim Akhtar
2014-12-31 6:43 ` [PATCH v3 2/4] mmc: dw_mmc: exynos: support eMMC's HS400 mode Alim Akhtar
2014-12-31 6:43 ` Alim Akhtar
2015-01-08 1:46 ` Jaehoon Chung
2015-01-08 1:46 ` Jaehoon Chung
2015-01-08 14:17 ` Alim Akhtar
2015-01-08 14:17 ` Alim Akhtar
2014-12-31 6:43 ` [PATCH v3 3/4] ARM: dts: drop dw-mshc-ciu-div property from Exynos Alim Akhtar
2014-12-31 6:43 ` Alim Akhtar
2014-12-31 6:43 ` [PATCH v3 4/4] ARM: dts: add HS400 support for Exynos5420 and exynos5800 Alim Akhtar
2014-12-31 6:43 ` Alim Akhtar
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.