[PATCH v2 06/10] mmc: am654_sdhci: Implement workaround for card detect
Simon Goldschmidt
simon.k.r.goldschmidt at gmail.com
Mon Feb 10 12:26:07 CET 2020
+Simon Glass for the xxx_get_ops() functions in DM
On Mon, Feb 10, 2020 at 10:46 AM Faiz Abbas <faiz_abbas at ti.com> wrote:
>
> Simon,
>
> On 29/01/20 7:48 pm, Simon Goldschmidt wrote:
> > On Fri, Jan 24, 2020 at 12:52 PM Faiz Abbas <faiz_abbas at ti.com> wrote:
> >>
> >> The 4 bit MMC controllers have an internal debounce for the SDCD line
> >> with a debounce delay of 1 second. Therefore, after clocks to the IP are
> >> enabled, software has to wait for this time before it can power on the
> >> controller.
> >>
> >> Add an init() callback which polls on sdcd for a maximum of 2 seconds
> >> before switching on power to the controller or (in the case of no card)
> >> returning a ENOMEDIUM. This pushes the 1 second wait time to when the
> >> card is actually needed rather than at every probe() making sure that
> >> users who don't insert an SD card in the slot don't have to wait such a
> >> long time.
> >>
> >> Signed-off-by: Faiz Abbas <faiz_abbas at ti.com>
> >> Signed-off-by: Lokesh Vutla <lokeshvutla at ti.com>
> >> ---
> >> drivers/mmc/am654_sdhci.c | 35 ++++++++++++++++++++++++++++++++---
> >> 1 file changed, 32 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/drivers/mmc/am654_sdhci.c b/drivers/mmc/am654_sdhci.c
> >> index ff0a81eaab..ccae3fea31 100644
> >> --- a/drivers/mmc/am654_sdhci.c
> >> +++ b/drivers/mmc/am654_sdhci.c
> >> @@ -254,7 +254,7 @@ const struct am654_driver_data j721e_4bit_drv_data = {
> >> .flags = IOMUX_PRESENT,
> >> };
> >>
> >> -int am654_sdhci_init(struct am654_sdhci_plat *plat)
> >> +int am654_sdhci_init_phy(struct am654_sdhci_plat *plat)
> >> {
> >> u32 ctl_cfg_2 = 0;
> >> u32 mask, val;
> >> @@ -331,8 +331,37 @@ static int sdhci_am654_get_otap_delay(struct udevice *dev,
> >> return 0;
> >> }
> >>
> >> +#define MAX_SDCD_DEBOUNCE_TIME 2000
> >> +int am654_sdhci_init(struct udevice *dev)
> >> +{
> >> + struct am654_sdhci_plat *plat = dev_get_platdata(dev);
> >> + struct mmc *mmc = mmc_get_mmc_dev(dev);
> >> + struct sdhci_host *host = mmc->priv;
> >> + unsigned long start;
> >> + int val;
> >> +
> >> + /*
> >> + * The controller takes about 1 second to debounce the card detect line
> >> + * and doesn't let us power on until that time is up. Instead of waiting
> >> + * for 1 second at every stage, poll on the CARD_PRESENT bit upto a
> >> + * maximum of 2 seconds to be safe..
> >> + */
> >> + start = get_timer(0);
> >> + do {
> >> + if (get_timer(start) > MAX_SDCD_DEBOUNCE_TIME)
> >> + return -ENOMEDIUM;
> >> +
> >> + val = mmc_getcd(host->mmc);
> >> + } while (!val);
> >> +
> >> + am654_sdhci_init_phy(plat);
> >> +
> >> + return sdhci_init(mmc);
> >> +}
> >> +
> >> static int am654_sdhci_probe(struct udevice *dev)
> >> {
> >> + struct dm_mmc_ops *ops = mmc_get_ops(dev);
> >> struct am654_driver_data *drv_data =
> >> (struct am654_driver_data *)dev_get_driver_data(dev);
> >> struct am654_sdhci_plat *plat = dev_get_platdata(dev);
> >> @@ -373,9 +402,9 @@ static int am654_sdhci_probe(struct udevice *dev)
> >>
> >> regmap_init_mem_index(dev_ofnode(dev), &plat->base, 1);
> >>
> >> - am654_sdhci_init(plat);
> >> + ops->init = am654_sdhci_init;
> >
> > Is this a valid approach? I mean, many drivers create their 'ops' const like
> > this:
> > static const struct ram_ops altera_gen5_sdram_ops (...)
> >
> > That would mean you write to a const region. I know the U-Boot sources make
> > this easy for you by providing the ops non-const via mmc_get_ops, but I still
> > think this is not good.
> >
>
> Sorry I missed this earlier.
>
> I do see other drivers following this approach (see
> drivers/mmc/sdhci-cadence.c). The issue is that I then have to export
> every API in drivers/mmc/sdhci.c:694
>
> const struct dm_mmc_ops sdhci_ops = {
> .send_cmd = sdhci_send_command,
> .set_ios = sdhci_set_ios,
> .get_cd = sdhci_get_cd,
> #ifdef MMC_SUPPORTS_TUNING
> .execute_tuning = sdhci_execute_tuning,
> #endif
> };
>
> and create a duplicate structure in my platform driver with an extra .init
>
> OR
>
> I have to create one more wrapper sdhci_pltaform_init() API in the sdhci
> driver that just calls a platform init function inside it. So its
>
> include/sdhci.h:
>
> struct sdhci_ops {
> ..
> + int (*platform_init)()
>
> and then drivers/mmc/sdhci.c:
>
>
> +dm_sdhci_platform_init()
> +{
> +...
> + host->ops->platform_init();
> +}
>
> const struct dm_mmc_ops sdhci_ops = {
> ...
> + .init = dm_sdhci_platform_init,
> };
>
>
> Both of these approaches are too much boiler plate code for nothing so
> its just simpler to use my approach itself.
>
> Anyways, please comment here or in my next version if you have a better
> idea.
Honestly, I don't know the mmc code well enough to give you an alternative.
However, I do know that most drivers define 'ops' as const, so to prevent
writing to const memory, mmc_get_ops() and other similar accessors should return
a const pointer. I know that they don't currently, but strictly speaking, this
is a bug.
Your adding this code here makes it harder to fix that bug and change
mmc_get_ops() to return a const pointer.
Regards,
Simon
More information about the U-Boot
mailing list