Merge branch 'master' of git://git.denx.de/u-boot-sh

- MMC fixes for R-Car Gen3
This commit is contained in:
Tom Rini 2018-12-03 17:51:45 -05:00
commit ec0d0d8742
15 changed files with 361 additions and 84 deletions

View File

@ -46,6 +46,54 @@
regulator-boot-on;
regulator-always-on;
};
vcc_sdhi0: regulator-vcc-sdhi0 {
compatible = "regulator-fixed";
regulator-name = "SDHI0 Vcc";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio5 17 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
vccq_sdhi0: regulator-vccq-sdhi0 {
compatible = "regulator-gpio";
regulator-name = "SDHI0 VccQ";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
gpios = <&gpio5 18 GPIO_ACTIVE_HIGH>;
gpios-states = <1>;
states = <3300000 1
1800000 0>;
};
vcc_sdhi1: regulator-vcc-sdhi1 {
compatible = "regulator-fixed";
regulator-name = "SDHI1 Vcc";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
gpio = <&gpio0 4 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
vccq_sdhi1: regulator-vccq-sdhi1 {
compatible = "regulator-gpio";
regulator-name = "SDHI1 VccQ";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
gpios-states = <1>;
states = <3300000 1
1800000 0>;
};
};
&avb {
@ -94,14 +142,38 @@
function = "scif_clk";
};
sdhi0_pins: sd0 {
groups = "sdhi0_data4", "sdhi0_ctrl";
function = "sdhi0";
power-source = <3300>;
};
sdhi0_pins_uhs: sd0_uhs {
groups = "sdhi0_data4", "sdhi0_ctrl";
function = "sdhi0";
power-source = <1800>;
};
sdhi1_pins: sd1 {
groups = "sdhi1_data4", "sdhi1_ctrl";
function = "sdhi1";
power-source = <3300>;
};
sdhi1_pins_uhs: sd1_uhs {
groups = "sdhi1_data4", "sdhi1_ctrl";
function = "sdhi1";
power-source = <1800>;
};
sdhi3_pins: sd2 {
groups = "sdhi3_data8", "sdhi3_ctrl";
groups = "sdhi3_data8", "sdhi3_ctrl", "sdhi3_ds";
function = "sdhi3";
power-source = <1800>;
};
sdhi3_pins_uhs: sd2_uhs {
groups = "sdhi3_data8", "sdhi3_ctrl";
groups = "sdhi3_data8", "sdhi3_ctrl", "sdhi3_ds";
function = "sdhi3";
power-source = <1800>;
};
@ -120,11 +192,40 @@
};
&sdhi0 {
/* full size SD */
pinctrl-0 = <&sdhi0_pins>;
pinctrl-1 = <&sdhi0_pins_uhs>;
pinctrl-names = "default", "state_uhs";
vmmc-supply = <&vcc_sdhi0>;
vqmmc-supply = <&vccq_sdhi0>;
cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
wp-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
bus-width = <4>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-sdr104;
status = "okay";
max-frequency = <208000000>;
};
&sdhi1 {
/* microSD */
pinctrl-0 = <&sdhi1_pins>;
pinctrl-1 = <&sdhi1_pins_uhs>;
pinctrl-names = "default", "state_uhs";
vmmc-supply = <&vcc_sdhi1>;
vqmmc-supply = <&vccq_sdhi1>;
cd-gpios = <&gpio3 14 GPIO_ACTIVE_LOW>;
bus-width = <4>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-sdr104;
status = "okay";
max-frequency = <208000000>;
};
&sdhi3 {
@ -137,6 +238,7 @@
vqmmc-supply = <&reg_1p8v>;
bus-width = <8>;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
non-removable;
status = "okay";
};

View File

@ -480,13 +480,13 @@
};
sdhi2_pins: sd2 {
groups = "sdhi2_data8", "sdhi2_ctrl";
groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds";
function = "sdhi2";
power-source = <1800>;
};
sdhi2_pins_uhs: sd2_uhs {
groups = "sdhi2_data8", "sdhi2_ctrl";
groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds";
function = "sdhi2";
power-source = <1800>;
};
@ -618,8 +618,13 @@
cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
wp-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
bus-width = <4>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-sdr104;
status = "okay";
max-frequency = <208000000>;
};
&sdhi2 {
@ -632,9 +637,11 @@
vqmmc-supply = <&reg_1p8v>;
bus-width = <8>;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
non-removable;
fixed-emmc-driver-type = <1>;
status = "okay";
max-frequency = <200000000>;
};
&sdhi3 {
@ -647,8 +654,12 @@
cd-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>;
wp-gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>;
bus-width = <4>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-sdr104;
status = "okay";
max-frequency = <208000000>;
};
&ssi1 {

View File

@ -308,13 +308,13 @@
};
sdhi2_pins: sd2 {
groups = "sdhi2_data8", "sdhi2_ctrl";
groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds";
function = "sdhi2";
power-source = <1800>;
};
sdhi2_pins_uhs: sd2_uhs {
groups = "sdhi2_data8", "sdhi2_ctrl";
groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds";
function = "sdhi2";
power-source = <1800>;
};
@ -396,8 +396,12 @@
vqmmc-supply = <&vccq_sdhi0>;
cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
bus-width = <4>;
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-sdr104;
status = "okay";
max-frequency = <208000000>;
};
&sdhi2 {
@ -410,8 +414,10 @@
vqmmc-supply = <&reg_1p8v>;
bus-width = <8>;
mmc-hs200-1_8v;
mmc-hs400-1_8v;
non-removable;
status = "okay";
max-frequency = <200000000>;
};
&ssi1 {

View File

@ -41,6 +41,7 @@ CONFIG_DM_MMC=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_RENESAS_SDHI=y
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y

View File

@ -41,6 +41,7 @@ CONFIG_DM_MMC=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_RENESAS_SDHI=y
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y

View File

@ -42,6 +42,7 @@ CONFIG_DM_MMC=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_RENESAS_SDHI=y
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y

View File

@ -42,6 +42,7 @@ CONFIG_DM_MMC=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_RENESAS_SDHI=y
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y

View File

@ -42,6 +42,7 @@ CONFIG_DM_MMC=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_RENESAS_SDHI=y
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y

View File

@ -42,6 +42,7 @@ CONFIG_DM_MMC=y
CONFIG_MMC_IO_VOLTAGE=y
CONFIG_MMC_UHS_SUPPORT=y
CONFIG_MMC_HS200_SUPPORT=y
CONFIG_MMC_HS400_SUPPORT=y
CONFIG_RENESAS_SDHI=y
CONFIG_PHY_MICREL=y
CONFIG_PHY_MICREL_KSZ90X1=y

View File

@ -107,7 +107,7 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk,
return renesas_clk_get_parent(clk, info, parent);
}
static int gen3_clk_setup_sdif_div(struct clk *clk)
static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate)
{
struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
struct cpg_mssr_info *info = priv->info;
@ -133,7 +133,7 @@ static int gen3_clk_setup_sdif_div(struct clk *clk)
debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset);
writel(1, priv->base + core->offset);
writel((rate == 400000000) ? 0x4 : 0x1, priv->base + core->offset);
return 0;
}
@ -141,10 +141,6 @@ static int gen3_clk_setup_sdif_div(struct clk *clk)
static int gen3_clk_enable(struct clk *clk)
{
struct gen3_clk_priv *priv = dev_get_priv(clk->dev);
int ret = gen3_clk_setup_sdif_div(clk);
if (ret)
return ret;
return renesas_clk_endisable(clk, priv->base, true);
}
@ -328,7 +324,7 @@ static ulong gen3_clk_get_rate(struct clk *clk)
static ulong gen3_clk_set_rate(struct clk *clk, ulong rate)
{
/* Force correct SD-IF divider configuration if applicable */
gen3_clk_setup_sdif_div(clk);
gen3_clk_setup_sdif_div(clk, rate);
return gen3_clk_get_rate64(clk);
}

View File

@ -166,6 +166,10 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
cfg->host_caps |= MMC_CAP(MMC_HS_200);
if (dev_read_bool(dev, "mmc-hs200-1_2v"))
cfg->host_caps |= MMC_CAP(MMC_HS_200);
if (dev_read_bool(dev, "mmc-hs400-1_8v"))
cfg->host_caps |= MMC_CAP(MMC_HS_400);
if (dev_read_bool(dev, "mmc-hs400-1_2v"))
cfg->host_caps |= MMC_CAP(MMC_HS_400);
return 0;
}

View File

@ -17,7 +17,9 @@
#include "tmio-common.h"
#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
/* SCC registers */
#define RENESAS_SDHI_SCC_DTCNTL 0x800
@ -107,6 +109,56 @@ static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv)
tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
}
static int renesas_sdhi_hs400(struct udevice *dev)
{
struct tmio_sd_priv *priv = dev_get_priv(dev);
struct mmc *mmc = mmc_get_mmc_dev(dev);
bool hs400 = (mmc->selected_mode == MMC_HS_400);
int ret, taps = hs400 ? priv->nrtaps : 8;
u32 reg;
if (taps == 4) /* HS400 on 4tap SoC needs different clock */
ret = clk_set_rate(&priv->clk, 400000000);
else
ret = clk_set_rate(&priv->clk, 200000000);
if (ret < 0)
return ret;
tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ);
reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT2);
if (hs400) {
reg |= RENESAS_SDHI_SCC_TMPPORT2_HS400EN |
RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL;
} else {
reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN |
RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL);
}
tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2);
tmio_sd_writel(priv, (taps << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) |
RENESAS_SDHI_SCC_DTCNTL_TAPEN,
RENESAS_SDHI_SCC_DTCNTL);
if (taps == 4) {
tmio_sd_writel(priv, priv->tap_set >> 1,
RENESAS_SDHI_SCC_TAPSET);
} else {
tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET);
}
reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL);
reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL;
tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL);
reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN;
tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL);
return 0;
}
static void renesas_sdhi_prepare_tuning(struct tmio_sd_priv *priv,
unsigned long tap)
{
@ -125,7 +177,6 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv,
unsigned int smpcmp)
{
unsigned long tap_cnt; /* counter of tuning success */
unsigned long tap_set; /* tap position */
unsigned long tap_start;/* start position of tuning success */
unsigned long tap_end; /* end position of tuning success */
unsigned long ntap; /* temporary counter of tuning success */
@ -209,12 +260,12 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv,
select = true;
if (select)
tap_set = ((tap_start + tap_end) / 2) % tap_num;
priv->tap_set = ((tap_start + tap_end) / 2) % tap_num;
else
return -EIO;
/* Set SCC */
tmio_sd_writel(priv, tap_set, RENESAS_SDHI_SCC_TAPSET);
tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET);
/* Enable auto re-tuning */
reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
@ -240,6 +291,7 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode)
/* clock tuning is not needed for upto 52MHz */
if (!((mmc->selected_mode == MMC_HS_200) ||
(mmc->selected_mode == MMC_HS_400) ||
(mmc->selected_mode == UHS_SDR104) ||
(mmc->selected_mode == UHS_SDR50)))
return 0;
@ -287,19 +339,42 @@ out:
return ret;
}
#else
static int renesas_sdhi_hs400(struct udevice *dev)
{
return 0;
}
#endif
static int renesas_sdhi_set_ios(struct udevice *dev)
{
int ret = tmio_sd_set_ios(dev);
struct tmio_sd_priv *priv = dev_get_priv(dev);
u32 tmp;
int ret;
/* Stop the clock before changing its rate to avoid a glitch signal */
tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
tmp &= ~TMIO_SD_CLKCTL_SCLKEN;
tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
ret = renesas_sdhi_hs400(dev);
if (ret)
return ret;
ret = tmio_sd_set_ios(dev);
mdelay(10);
#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
struct tmio_sd_priv *priv = dev_get_priv(dev);
if (priv->caps & TMIO_SD_CAP_RCAR_UHS)
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
struct mmc *mmc = mmc_get_mmc_dev(dev);
if ((priv->caps & TMIO_SD_CAP_RCAR_UHS) &&
(mmc->selected_mode != UHS_SDR104) &&
(mmc->selected_mode != MMC_HS_200) &&
(mmc->selected_mode != MMC_HS_400)) {
renesas_sdhi_reset_tuning(priv);
}
#endif
return ret;
@ -331,7 +406,9 @@ static const struct dm_mmc_ops renesas_sdhi_ops = {
.send_cmd = tmio_sd_send_cmd,
.set_ios = renesas_sdhi_set_ios,
.get_cd = tmio_sd_get_cd,
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
.execute_tuning = renesas_sdhi_execute_tuning,
#endif
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
@ -358,15 +435,45 @@ static const struct udevice_id renesas_sdhi_match[] = {
{ /* sentinel */ }
};
static ulong renesas_sdhi_clk_get_rate(struct tmio_sd_priv *priv)
{
return clk_get_rate(&priv->clk);
}
static void renesas_sdhi_filter_caps(struct udevice *dev)
{
struct tmio_sd_plat *plat = dev_get_platdata(dev);
struct tmio_sd_priv *priv = dev_get_priv(dev);
if (!(priv->caps & TMIO_SD_CAP_RCAR_GEN3))
return;
/* HS400 is not supported on H3 ES1.x and M3W ES1.0,ES1.1 */
if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
(rmobile_get_cpu_rev_integer() <= 1)) ||
((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
(rmobile_get_cpu_rev_integer() == 1) &&
(rmobile_get_cpu_rev_fraction() <= 1)))
plat->cfg.host_caps &= ~MMC_MODE_HS400;
/* H3 ES2.0 uses 4 tuning taps */
if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
(rmobile_get_cpu_rev_integer() == 2))
priv->nrtaps = 4;
else
priv->nrtaps = 8;
}
static int renesas_sdhi_probe(struct udevice *dev)
{
struct tmio_sd_priv *priv = dev_get_priv(dev);
u32 quirks = dev_get_driver_data(dev);
struct fdt_resource reg_res;
struct clk clk;
DECLARE_GLOBAL_DATA_PTR;
int ret;
priv->clk_get_rate = renesas_sdhi_clk_get_rate;
if (quirks == RENESAS_GEN2_QUIRKS) {
ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev),
"reg", 0, &reg_res);
@ -380,29 +487,33 @@ static int renesas_sdhi_probe(struct udevice *dev)
quirks |= TMIO_SD_CAP_16BIT;
}
ret = clk_get_by_index(dev, 0, &clk);
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret < 0) {
dev_err(dev, "failed to get host clock\n");
return ret;
}
/* set to max rate */
priv->mclk = clk_set_rate(&clk, ULONG_MAX);
if (IS_ERR_VALUE(priv->mclk)) {
ret = clk_set_rate(&priv->clk, 200000000);
if (ret < 0) {
dev_err(dev, "failed to set rate for host clock\n");
clk_free(&clk);
return priv->mclk;
clk_free(&priv->clk);
return ret;
}
ret = clk_enable(&clk);
clk_free(&clk);
ret = clk_enable(&priv->clk);
if (ret) {
dev_err(dev, "failed to enable host clock\n");
return ret;
}
ret = tmio_sd_probe(dev, quirks);
#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
renesas_sdhi_filter_caps(dev);
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS))
renesas_sdhi_reset_tuning(priv);
#endif

View File

@ -555,55 +555,76 @@ static void tmio_sd_set_ddr_mode(struct tmio_sd_priv *priv,
tmio_sd_writel(priv, tmp, TMIO_SD_IF_MODE);
}
static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv,
struct mmc *mmc)
static ulong tmio_sd_clk_get_rate(struct tmio_sd_priv *priv)
{
return priv->clk_get_rate(priv);
}
static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, struct mmc *mmc)
{
unsigned int divisor;
u32 val, tmp;
u32 tmp, val = 0;
ulong mclk;
if (!mmc->clock)
return;
if (mmc->clock) {
mclk = tmio_sd_clk_get_rate(priv);
divisor = DIV_ROUND_UP(priv->mclk, mmc->clock);
divisor = DIV_ROUND_UP(mclk, mmc->clock);
if (divisor <= 1)
val = (priv->caps & TMIO_SD_CAP_RCAR) ?
TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1;
else if (divisor <= 2)
val = TMIO_SD_CLKCTL_DIV2;
else if (divisor <= 4)
val = TMIO_SD_CLKCTL_DIV4;
else if (divisor <= 8)
val = TMIO_SD_CLKCTL_DIV8;
else if (divisor <= 16)
val = TMIO_SD_CLKCTL_DIV16;
else if (divisor <= 32)
val = TMIO_SD_CLKCTL_DIV32;
else if (divisor <= 64)
val = TMIO_SD_CLKCTL_DIV64;
else if (divisor <= 128)
val = TMIO_SD_CLKCTL_DIV128;
else if (divisor <= 256)
val = TMIO_SD_CLKCTL_DIV256;
else if (divisor <= 512 || !(priv->caps & TMIO_SD_CAP_DIV1024))
val = TMIO_SD_CLKCTL_DIV512;
else
val = TMIO_SD_CLKCTL_DIV1024;
/* Do not set divider to 0xff in DDR mode */
if (mmc->ddr_mode && (divisor == 1))
divisor = 2;
if (divisor <= 1)
val = (priv->caps & TMIO_SD_CAP_RCAR) ?
TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1;
else if (divisor <= 2)
val = TMIO_SD_CLKCTL_DIV2;
else if (divisor <= 4)
val = TMIO_SD_CLKCTL_DIV4;
else if (divisor <= 8)
val = TMIO_SD_CLKCTL_DIV8;
else if (divisor <= 16)
val = TMIO_SD_CLKCTL_DIV16;
else if (divisor <= 32)
val = TMIO_SD_CLKCTL_DIV32;
else if (divisor <= 64)
val = TMIO_SD_CLKCTL_DIV64;
else if (divisor <= 128)
val = TMIO_SD_CLKCTL_DIV128;
else if (divisor <= 256)
val = TMIO_SD_CLKCTL_DIV256;
else if (divisor <= 512 || !(priv->caps & TMIO_SD_CAP_DIV1024))
val = TMIO_SD_CLKCTL_DIV512;
else
val = TMIO_SD_CLKCTL_DIV1024;
}
tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL);
if (tmp & TMIO_SD_CLKCTL_SCLKEN &&
(tmp & TMIO_SD_CLKCTL_DIV_MASK) == val)
return;
if (mmc->clock &&
!((tmp & TMIO_SD_CLKCTL_SCLKEN) &&
((tmp & TMIO_SD_CLKCTL_DIV_MASK) == val))) {
/*
* Stop the clock before changing its rate
* to avoid a glitch signal
*/
tmp &= ~TMIO_SD_CLKCTL_SCLKEN;
tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
/* stop the clock before changing its rate to avoid a glitch signal */
tmp &= ~TMIO_SD_CLKCTL_SCLKEN;
tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
/* Change the clock rate. */
tmp &= ~TMIO_SD_CLKCTL_DIV_MASK;
tmp |= val;
}
tmp &= ~TMIO_SD_CLKCTL_DIV_MASK;
tmp |= val | TMIO_SD_CLKCTL_OFFEN;
tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
/* Enable or Disable the clock */
if (mmc->clk_disable) {
tmp |= TMIO_SD_CLKCTL_OFFEN;
tmp &= ~TMIO_SD_CLKCTL_SCLKEN;
} else {
tmp &= ~TMIO_SD_CLKCTL_OFFEN;
tmp |= TMIO_SD_CLKCTL_SCLKEN;
}
tmp |= TMIO_SD_CLKCTL_SCLKEN;
tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
udelay(1000);
@ -708,6 +729,7 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks)
struct tmio_sd_priv *priv = dev_get_priv(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
fdt_addr_t base;
ulong mclk;
int ret;
base = devfdt_get_addr(dev);
@ -750,10 +772,12 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks)
tmio_sd_host_init(priv);
mclk = tmio_sd_clk_get_rate(priv);
plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
plat->cfg.f_min = priv->mclk /
plat->cfg.f_min = mclk /
(priv->caps & TMIO_SD_CAP_DIV1024 ? 1024 : 512);
plat->cfg.f_max = priv->mclk;
plat->cfg.f_max = mclk;
plat->cfg.b_max = U32_MAX; /* max value of TMIO_SD_SECCNT */
upriv->mmc = &plat->mmc;

View File

@ -117,7 +117,6 @@ struct tmio_sd_plat {
struct tmio_sd_priv {
void __iomem *regbase;
unsigned long mclk;
unsigned int version;
u32 caps;
#define TMIO_SD_CAP_NONREMOVABLE BIT(0) /* Nonremovable e.g. eMMC */
@ -133,6 +132,14 @@ struct tmio_sd_priv {
#ifdef CONFIG_DM_REGULATOR
struct udevice *vqmmc_dev;
#endif
#if CONFIG_IS_ENABLED(CLK)
struct clk clk;
#endif
#if CONFIG_IS_ENABLED(RENESAS_SDHI)
u8 tap_set;
u8 nrtaps;
#endif
ulong (*clk_get_rate)(struct tmio_sd_priv *);
};
int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,

View File

@ -31,35 +31,45 @@ static const struct udevice_id uniphier_sd_match[] = {
{ /* sentinel */ }
};
static ulong uniphier_sd_clk_get_rate(struct tmio_sd_priv *priv)
{
#if CONFIG_IS_ENABLED(CLK)
return clk_get_rate(&priv->clk);
#elif CONFIG_SPL_BUILD
return 100000000;
#else
return 0;
#endif
}
static int uniphier_sd_probe(struct udevice *dev)
{
struct tmio_sd_priv *priv = dev_get_priv(dev);
priv->clk_get_rate = uniphier_sd_clk_get_rate;
#ifndef CONFIG_SPL_BUILD
struct clk clk;
int ret;
ret = clk_get_by_index(dev, 0, &clk);
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret < 0) {
dev_err(dev, "failed to get host clock\n");
return ret;
}
/* set to max rate */
priv->mclk = clk_set_rate(&clk, ULONG_MAX);
if (IS_ERR_VALUE(priv->mclk)) {
ret = clk_set_rate(&priv->clk, ULONG_MAX);
if (ret < 0) {
dev_err(dev, "failed to set rate for host clock\n");
clk_free(&clk);
return priv->mclk;
clk_free(&priv->clk);
return ret;
}
ret = clk_enable(&clk);
clk_free(&clk);
ret = clk_enable(&priv->clk);
if (ret) {
dev_err(dev, "failed to enable host clock\n");
return ret;
}
#else
priv->mclk = 100000000;
#endif
return tmio_sd_probe(dev, 0);