Re: HS400 tuning and presets

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 20, 2020 at 2:56 AM Adrian Hunter <adrian.hunter@xxxxxxxxx> wrote:
>
> On 20/08/20 1:56 am, Raul Rangel wrote:
> > I noticed some odd things with the MMC/SDHCI code while debugging an
> > HS400 tuning issue.
> >
> > 1) Is it expected that we never enable SDHCI_CTRL_PRESET_VAL_ENABLE
> > for an eMMC running at HS200 or HS400?
>
> Seems like an oversight.  eMMC transfer modes are not supported by the SDHCI
> specification, and many drivers use SDHCI_QUIRK2_PRESET_VALUE_BROKEN, so it
> looks like it has never been noticeable.
>

Thanks for the confirmation. I'll get a patch sent to fix it.

> > The flow for enabling HS400 is: Legacy -> HS200 -> Perform Tuning ->
> > HS -> HS400.
> > Looking at [sdhci_set_ios](https://source.chromium.org/chromiumos/chromiumos/codesearch/+/master:src/third_party/kernel/v5.4/drivers/mmc/host/sdhci.c;l=2019),
> > it looks like it's responsible for enabling presets.
> >
> >     if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
> >                     ((ios->timing == MMC_TIMING_UHS_SDR12) ||
> >                      (ios->timing == MMC_TIMING_UHS_SDR25) ||
> >                      (ios->timing == MMC_TIMING_UHS_SDR50) ||
> >                      (ios->timing == MMC_TIMING_UHS_SDR104) ||
> >                      (ios->timing == MMC_TIMING_UHS_DDR50) ||
> >                      (ios->timing == MMC_TIMING_MMC_DDR52))) {
> >             u16 preset;
> >
> >             sdhci_enable_preset_value(host, true);
> >             preset = sdhci_get_preset_value(host);
> >             ios->drv_type = (preset & SDHCI_PRESET_DRV_MASK)
> >                     >> SDHCI_PRESET_DRV_SHIFT;
> >     }
> >
> > MMC_TIMING_MMC_HS200 and MMC_TIMING_MMC_HS400 are missing from the
> > conditions, so we never enable presets. This means that by default
> > (only 2 controllers provide select_drive_strength) we use drive
> > strength B for both the card and the controller.
> >
> >     int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
> >                                   int card_drv_type, int *drv_type)
> >     {
> >             struct mmc_host *host = card->host;
> >             int host_drv_type = SD_DRIVER_TYPE_B;
> >
> >             *drv_type = 0;
> >
> >             if (!host->ops->select_drive_strength)
> >                     return 0;
> >             ...
> >     }
> >
> > Here is a trace log showing HS400 initialization: https://0paste.com/79874
> >
> > 2) When performing HS400 tuning we end up enabling presets.
> > The re-tuning sequence is: HS400->DDR52->HS->HS200->Perform Tuning->HS->HS400
> >
> > So when we transition to DDR52 the code above enables presets. You can
> > see this happening in this trace log: https://0paste.com/79875. Look
> > at timestamp 1926.173800.
> >
> > This means that the card and controller have the potential to have
> > mismatching drive strengths. This can be seen at timestamp
> > 1926.175813.The HS200 preset on my controller is configured to A, but
> > the card would be set up as B (if the controller didn't override
> > select_drive_strength).
> >
> > Should we be enabling presets for HS200/HS400 (and potentially
> > MMC_HS), or should we remove MMC_DDR52 from the condition above?
>
> The only things that matter are:
> 1. don't break other drivers
> 2. do make it work for your driver
>
> So we can't universally enable presets for HS200 and HS400, nor remove
> MMC_DDR52, but we can do something to make it work for you.
>

Makes sense. I'll see what direction I want to take.

> >
> > It looks like 0dafa60eb2506 ("mmc: sdhci: also get preset value and
> > driver type for MMC_DDR52") was the CL that added MMC_DDR52 to the
> > condition.
> >
> > 3) How do we ensure that card drive strength and controller drive
> > strength stay in sync when presets are enabled?
>
> Is that your requirement? Which driver is it?

We want to provide a knob for our OEMs so they can choose the best
drive strength for their design. Right now for the AMD controller it's
hard coded to A:
https://source.chromium.org/chromiumos/chromiumos/codesearch/+/master:src/third_party/kernel/v5.4/drivers/mmc/host/sdhci-acpi.c;l=542

I was hoping to use the SDHCI presets to not introduce a non-standard
convention of passing in the drive strength. I wasn't aware that the
SDHCI driver doesn't use presets for eMMC. So maybe the path of least
resistance is to add an ACPI property that is read by
amd_select_drive_strength. Like `mmc_of_parse` does with
`fixed-emmc-driver-type`. This ensures that both the card and
controller drive strengths are set.

It looks like `host->fixed_drv_type` is only for the card. It doesn't
set the same drive strength on the controller. Is this intentional?

    static void mmc_select_driver_type(struct mmc_card *card)
    {
            int card_drv_type, drive_strength, drv_type = 0;
            int fixed_drv_type = card->host->fixed_drv_type;

            card_drv_type = card->ext_csd.raw_driver_strength |
                            mmc_driver_type_mask(0);

            if (fixed_drv_type >= 0) <--- Never updates drv_type
                    drive_strength = card_drv_type &
mmc_driver_type_mask(fixed_drv_type)
                                     ? fixed_drv_type : 0;
            else
                    drive_strength = mmc_select_drive_strength(card,

card->ext_csd.hs200_max_dtr,

card_drv_type, &drv_type);

            card->drive_strength = drive_strength;

            if (drv_type)
                    mmc_set_driver_type(card->host, drv_type);
    }

>
> > Right now mmc_select_driver_type is only called from
> > `mmc_select_hs400es` and `mmc_select_hs200`. `mmc_select_driver_type
> > doesn't currently take the timing into account when making a decision.
> > Only two devices currently provide the `select_drive_strength`
> > override, so we are setting the card to drive strength B for most
> > controllers.
> >
> > Should we modify mmc_select_drive_strength to take in the target
> > timing so it can return the correct card drive strength. We could then
> > add an sdhci_select_drive_strength that queries the preset registers
> > (if enabled) and returns the target drive strength.
> >
> > 4) Should we be calling `mmc_select_driver_type` from
> > `mmc_hs400_to_hs200` and `mmc_hs200_to_hs400` during the transitions?
>
> The same driver strength continues to be used for HS200 and HS400 i.e.
> card->driver_strength
>
> > Or do we not care?
> >
> > Sorry for the long email...
> > Once I get some guidance, I can send some patches.
>
> Generally people first want to know what problem you are trying to solve.
I was just thinking we need to keep the drive strengths in sync
between controller and card.


Thanks for reading my long email :)



[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux