[PATCH v4] mmc: meson: Add driver for the SD/MMC host found on Amlogic MesonX SoCs

Carlo Caione carlo at caione.org
Tue Dec 8 08:22:55 PST 2015


On Tue, Dec 8, 2015 at 4:06 PM, Ulf Hansson <ulf.hansson at linaro.org> wrote:
> On 1 December 2015 at 17:41, Carlo Caione <carlo at caione.org> wrote:

>> +Required properties:
>> + - compatible : "amlogic,meson-mmc"
>> + - reg : mmc controller base registers
>> + - interrupts : mmc controller interrupt
>> + - clocks : phandle to clock provider
>> + - pinctrl-names : should contain "sdio_a" or "sdio_b"
>
> This is weird. I don't think you need this specific states.
> You should be able to cope with common used "default" state.
>
> Later in the driver code I realize that you have some register bits
> that is related to either using port a or port b. But I don't think
> that is the same thing as having different pinctrls states.

Unfortunately documentation is not really clear about this. A
multi-slot capable device maybe?

> If you can't detect whether port a or b is used in runtime by the
> driver, I suggest you add a separate meson mmc DT binding telling what
> port is being used.

That was my initial idea. In v3 I had the "meson,sdio-port" property
for that. I'll put it back in the next revision.

>> + - pinctrl-0: Should specify pin control groups used for this controller
>> +
>> +Optional properties:
>> + - for cd, bus-width and additional generic mmc parameters
>> +   please refer to mmc.txt within this directory
>> +
>> +Examples:
>> +       mmc0: mmc at c1108c20 {
>> +               pinctrl-names = "sdio_b";
>> +               pinctrl-0 = <&mmc0_sd_b_pins>;
>> +               compatible = "amlogic,meson-mmc";
>> +               reg = <0xc1108c20 0x20>;
>> +               interrupts = <0 28 1>;
>> +               clocks = <&clkc CLKID_CLK81>;
>> +       };
>
> Overall the DT documentation looks okay (beside the comments above).
> Although, please separate it to become a patch 1/2. The rest below
> shoud go into a patch 2/2.
>
> For the DT patch please include the DT maintainers when posting the new version.

I'll do.

[...]

>> +       clk_rate >>= 1;
>> +       clk_div = clk_rate / clk_ios - !(clk_rate % clk_ios);
>> +
>> +       conf_reg = readl(host->base + SDIO_CONF);
>> +       conf_reg &= ~REG_CONF_CLK_DIV_M;
>> +       conf_reg |= clk_div;
>> +       writel(conf_reg, host->base + SDIO_CONF);
>> +
>> +       dev_dbg(mmc_dev(mmc), "clk_ios: %d, clk_div: %d, clk_rate: %ld\n",
>> +               clk_ios, clk_div, clk_rate);
>
> It's good practice to update mmc->actual_clock, as it's being used
> from mmc core's debugfs support.

Ok

[...]

>> +
>> +       host = mmc_priv(mmc);
>> +       host->mmc = mmc;
>> +       host->timeout = msecs_to_jiffies(2000);
>
> I don't think this timeout will cover all cases, although I can't
> really tell what a proper value should be as it's dynamically
> changning between requests.
>
> Perhaps try to pick a value that's already being used by other hosts
> is good enough!?

Other drivers use 10s, so I'll try to pick the same value.

I have actually a problem and a question related to this value. On the
boards I'm currently using to test this driver I have no CD GPIO. In
this case do I have to specify the MMC as "non-removable"? Also if I
try to change an SD card at runtime I have to wait 3 times the timeout
before being able to do it successfully.

[...]

>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       host->base = devm_ioremap_resource(&pdev->dev, res);
>> +       if (IS_ERR(host->base)) {
>> +               ret = PTR_ERR(host->base);
>> +               goto error_free_host;
>> +       }
>> +
>> +       irq = platform_get_irq(pdev, 0);
>> +       ret = devm_request_threaded_irq(&pdev->dev, irq, meson_mmc_irq,
>> +                                       meson_mmc_irq_thread, 0, "meson_mmc",
>> +                                       host);
>> +       if (ret)
>> +               goto error_free_host;
>> +
>> +       host->clk = devm_clk_get(&pdev->dev, NULL);
>> +       if (IS_ERR(host->clk)) {
>> +               ret = PTR_ERR(host->clk);
>> +               goto error_free_host;
>> +       }
>
> A clk_prepare_enable() is missing somwhere around here and of course
> then the clock needs to be gated as well. Both in the error handling
> of ->probe() but also in meson_mmc_remove().

No clock gatings yet on this platform but I'll fix it.

>> +
>> +       /* we do not support scatter lists in hardware */
>> +       mmc->max_segs = 1;
>> +       mmc->max_req_size = SDIO_BOUNCE_REQ_SIZE;
>> +       mmc->max_seg_size = mmc->max_req_size;
>> +       mmc->max_blk_count = 256;
>> +       mmc->max_blk_size = mmc->max_req_size / mmc->max_blk_count;
>> +       mmc->f_min = 300000;
>> +       mmc->f_max = 50000000;
>> +       mmc->caps |= MMC_CAP_4_BIT_DATA;
>> +       mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
>> +       mmc->caps2 |= MMC_CAP2_NO_SDIO;
>> +       mmc->ocr_avail = MMC_VDD_33_34;
>> +       mmc->ops = &meson_mmc_ops;
>> +
>> +       spin_lock_init(&host->lock);
>> +
>> +       INIT_DELAYED_WORK(&host->timeout_work, meson_mmc_timeout);
>> +
>> +       pinctrl = devm_pinctrl_get(&pdev->dev);
>> +       if (IS_ERR(pinctrl)) {
>> +               ret = PTR_ERR(pinctrl);
>> +               goto error_free_host;
>> +       }
>> +
>> +       /* We need to know at runtime which port we are using */
>> +       pins = pinctrl_lookup_state(pinctrl, "sdio_b");
>> +       if (!IS_ERR(pins))
>> +               host->port = 1; /* PORT_B */
>> +       else
>> +               host->port = 0; /* PORT_A */
>> +
>
> I think the pinctrl code can be removed, according to my eariler
> comments for the DT documentation.

Agree

> Instead you need a way to find out the currently used port...

I really do not think this is feasible from the driver at runtime. So
I'll go with the new DT property.

[...]

Thanks,

-- 
Carlo Caione



More information about the linux-arm-kernel mailing list