[linux-sunxi] Re: [PATCH] mmc: sunxi: Fix clk-delay settings
Hans de Goede
hdegoede at redhat.com
Thu Sep 24 02:52:36 PDT 2015
Hi,
On 23-09-15 23:50, Ulf Hansson wrote:
> On 23 September 2015 at 22:06, Hans de Goede <hdegoede at redhat.com> wrote:
>> 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: Hans de Goede <hdegoede at redhat.com>
>
> I assume you want me to take this as a fix?
With that you mean take it into 4.3-rcX ? Yes please.
> If so, can we point to what commit it fixes?
Erm, the clk-sample settings this adjusts have been there more or less
unchanged since the driver was introduced, and were taken directly from
the allwinner A10 kernel source / SDK.
This just syncs them with improvements done to the settings in later
allwinner SDK-s, improvements which I found when I could not get multiple
cards to work on certain A33 based tablets.
Regards,
Hans
>> ---
>> drivers/mmc/host/sunxi-mmc.c | 53 ++++++++++++++++++++++++++++++++------------
>> 1 file changed, 39 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
>> index e6226cd..83de82b 100644
>> --- a/drivers/mmc/host/sunxi-mmc.c
>> +++ b/drivers/mmc/host/sunxi-mmc.c
>> @@ -210,6 +210,16 @@
>> #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_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 {
>> u32 config;
>> u32 buf_size;
>> @@ -229,6 +239,7 @@ struct sunxi_mmc_host {
>> struct clk *clk_mmc;
>> struct clk *clk_sample;
>> struct clk *clk_output;
>> + const struct sunxi_mmc_clk_delay *clk_delays;
>>
>> /* irq */
>> spinlock_t lock;
>> @@ -654,25 +665,19 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
>>
>> /* determine delays */
>> if (rate <= 400000) {
>> - oclk_dly = 180;
>> - sclk_dly = 42;
>> + oclk_dly = host->clk_delays[SDXC_CLK_400K].output;
>> + sclk_dly = host->clk_delays[SDXC_CLK_400K].sample;
>> } else if (rate <= 25000000) {
>> - oclk_dly = 180;
>> - sclk_dly = 75;
>> + oclk_dly = host->clk_delays[SDXC_CLK_25M].output;
>> + sclk_dly = host->clk_delays[SDXC_CLK_25M].sample;
>> } else if (rate <= 50000000) {
>> if (ios->timing == MMC_TIMING_UHS_DDR50) {
>> - oclk_dly = 60;
>> - sclk_dly = 120;
>> + oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output;
>> + sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample;
>> } else {
>> - oclk_dly = 90;
>> - sclk_dly = 150;
>> + oclk_dly = host->clk_delays[SDXC_CLK_50M].output;
>> + 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 {
>> return -EINVAL;
>> }
>> @@ -878,6 +883,7 @@ static int sunxi_mmc_card_busy(struct mmc_host *mmc)
>> static const struct of_device_id sunxi_mmc_of_match[] = {
>> { .compatible = "allwinner,sun4i-a10-mmc", },
>> { .compatible = "allwinner,sun5i-a13-mmc", },
>> + { .compatible = "allwinner,sun9i-a80-mmc", },
>> { /* sentinel */ }
>> };
>> MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
>> @@ -892,6 +898,20 @@ static struct mmc_host_ops sunxi_mmc_ops = {
>> .card_busy = sunxi_mmc_card_busy,
>> };
>>
>> +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,
>> struct platform_device *pdev)
>> {
>> @@ -903,6 +923,11 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
>> else
>> 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);
>> if (ret) {
>> if (ret != -EPROBE_DEFER)
>> --
>> 2.5.0
>>
More information about the linux-arm-kernel
mailing list