Commit 51424b28 authored by Hans de Goede's avatar Hans de Goede Committed by Ulf Hansson

mmc: sunxi: Fix clk-delay settings

In recent allwinner kernel sources the mmc clk-delay settings have been
slightly tweaked, and for sun9i they are completely different then what
we are using.

This commit brings us in sync with what allwinner does, fixing problems
accessing sdcards on some A33 devices (and likely others).

For pre sun9i hardware this makes the following changes:
-At 400Khz change the sample delay from 7 to 0 (introduced in A31 sdk)
-At 50 Mhz change the sample delay from 5 to 4 (introduced in A23 sdk)

This also drops the clk-delay calculation for clocks > 50 MHz, we do
not need this as we've: mmc->f_max = 50000000, and the delays in the
old code were not correct (at 100 MHz the delay must be a multiple of 60,
at 200 MHz a multiple of 120).
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 43934ece
...@@ -210,6 +210,16 @@ ...@@ -210,6 +210,16 @@
#define SDXC_IDMAC_DES0_CES BIT(30) /* card error summary */ #define SDXC_IDMAC_DES0_CES BIT(30) /* card error summary */
#define SDXC_IDMAC_DES0_OWN BIT(31) /* 1-idma owns it, 0-host owns it */ #define SDXC_IDMAC_DES0_OWN BIT(31) /* 1-idma owns it, 0-host owns it */
#define SDXC_CLK_400K 0
#define SDXC_CLK_25M 1
#define SDXC_CLK_50M 2
#define SDXC_CLK_50M_DDR 3
struct sunxi_mmc_clk_delay {
u32 output;
u32 sample;
};
struct sunxi_idma_des { struct sunxi_idma_des {
u32 config; u32 config;
u32 buf_size; u32 buf_size;
...@@ -229,6 +239,7 @@ struct sunxi_mmc_host { ...@@ -229,6 +239,7 @@ struct sunxi_mmc_host {
struct clk *clk_mmc; struct clk *clk_mmc;
struct clk *clk_sample; struct clk *clk_sample;
struct clk *clk_output; struct clk *clk_output;
const struct sunxi_mmc_clk_delay *clk_delays;
/* irq */ /* irq */
spinlock_t lock; spinlock_t lock;
...@@ -654,25 +665,19 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host, ...@@ -654,25 +665,19 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
/* determine delays */ /* determine delays */
if (rate <= 400000) { if (rate <= 400000) {
oclk_dly = 180; oclk_dly = host->clk_delays[SDXC_CLK_400K].output;
sclk_dly = 42; sclk_dly = host->clk_delays[SDXC_CLK_400K].sample;
} else if (rate <= 25000000) { } else if (rate <= 25000000) {
oclk_dly = 180; oclk_dly = host->clk_delays[SDXC_CLK_25M].output;
sclk_dly = 75; sclk_dly = host->clk_delays[SDXC_CLK_25M].sample;
} else if (rate <= 50000000) { } else if (rate <= 50000000) {
if (ios->timing == MMC_TIMING_UHS_DDR50) { if (ios->timing == MMC_TIMING_UHS_DDR50) {
oclk_dly = 60; oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output;
sclk_dly = 120; sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample;
} else { } else {
oclk_dly = 90; oclk_dly = host->clk_delays[SDXC_CLK_50M].output;
sclk_dly = 150; sclk_dly = host->clk_delays[SDXC_CLK_50M].sample;
} }
} else if (rate <= 100000000) {
oclk_dly = 6;
sclk_dly = 24;
} else if (rate <= 200000000) {
oclk_dly = 3;
sclk_dly = 12;
} else { } else {
return -EINVAL; return -EINVAL;
} }
...@@ -871,6 +876,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -871,6 +876,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
static const struct of_device_id sunxi_mmc_of_match[] = { static const struct of_device_id sunxi_mmc_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-mmc", }, { .compatible = "allwinner,sun4i-a10-mmc", },
{ .compatible = "allwinner,sun5i-a13-mmc", }, { .compatible = "allwinner,sun5i-a13-mmc", },
{ .compatible = "allwinner,sun9i-a80-mmc", },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match); MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
...@@ -884,6 +890,20 @@ static struct mmc_host_ops sunxi_mmc_ops = { ...@@ -884,6 +890,20 @@ static struct mmc_host_ops sunxi_mmc_ops = {
.hw_reset = sunxi_mmc_hw_reset, .hw_reset = sunxi_mmc_hw_reset,
}; };
static const struct sunxi_mmc_clk_delay sunxi_mmc_clk_delays[] = {
[SDXC_CLK_400K] = { .output = 180, .sample = 180 },
[SDXC_CLK_25M] = { .output = 180, .sample = 75 },
[SDXC_CLK_50M] = { .output = 90, .sample = 120 },
[SDXC_CLK_50M_DDR] = { .output = 60, .sample = 120 },
};
static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = {
[SDXC_CLK_400K] = { .output = 180, .sample = 180 },
[SDXC_CLK_25M] = { .output = 180, .sample = 75 },
[SDXC_CLK_50M] = { .output = 150, .sample = 120 },
[SDXC_CLK_50M_DDR] = { .output = 90, .sample = 120 },
};
static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
struct platform_device *pdev) struct platform_device *pdev)
{ {
...@@ -895,6 +915,11 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, ...@@ -895,6 +915,11 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
else else
host->idma_des_size_bits = 16; host->idma_des_size_bits = 16;
if (of_device_is_compatible(np, "allwinner,sun9i-a80-mmc"))
host->clk_delays = sun9i_mmc_clk_delays;
else
host->clk_delays = sunxi_mmc_clk_delays;
ret = mmc_regulator_get_supply(host->mmc); ret = mmc_regulator_get_supply(host->mmc);
if (ret) { if (ret) {
if (ret != -EPROBE_DEFER) if (ret != -EPROBE_DEFER)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment