Re: I could use some help
- In reply to: Mark Millard : "Re: I could use some help"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 14 Nov 2022 09:34:13 UTC
My understanding is that HS400 and HS200 requires "tuining the phase" to be supported and this involves CMD21 to generate test patterns used for the tuning process. https://lists.freebsd.org/archives/freebsd-hackers/2022-November/001648.html reports: mmc0: CMD7 RESULT: 1 mmc0: CMD7 failed, RESULT: 1 sdhci_fdt0-slot0: sdhci_generic_write_ivar: var=0 mmc0: setting transfer rate to 50.000MHz (HS400 with enhanced strobe timing) mmc0: REQUEST: CMD7 arg 0 flags 0 but shows not even one CMD21: no actual tuning for HS400 (or HS200) was done. An old quote of mine was: QUOTE HS400 needs CMD21 use for synchronizing the command responses on the CMD line to the CLK (a temporary use of HS200 mode to do the tuning). . . . But there is more context that I should have referenced: For HS400, when Enhanced Strobe is disabled, the CMD-out line (from device to host) has no matching strobe to go with it in any fixed signal-timing relationship from what I've read. . . . (Data Out and CRC Response always are synced to the Strobe.) END QUOTE This issue exists on Rock64 and in an exchange about that Andriy Gapon wrote: QUOTE On 2021-Dec-10, at 02:35, Andriy Gapon <avg@FreeBSD.org> wrote: > On 10/12/2021 11:51, Kornel Dulęba wrote: >> On Thu, Dec 9, 2021 at 11:54 PM Mark Millard <marklmi@yahoo.com> wrote: >>> Note the "tuned phase to 245" as part of that. >> Yep, it looks like in Linux they're doing some custom tuning logic >> specific to this controller. >> FreeBSD only executes generic tuning code, which apparently is not enough. > > > AFAICS, we do not have any support for setting clock phases at all. END QUOTE I came to the same conclusion that there is not such thing as generic tuning involved and there is no support for any specific controller for the tuning needed for HS200 and HS400. (There is also a Drive Strength setting involved for HS200 --and HS400 has possibly one more Drive Strength alternative by count. More missing support?) I eventually got into the JEDEC standard and wrote . . . QUOTE Looking some more, it looks like the Tuning-Process-Completed-No loop for HS200 in JESD84-B51 that can involve CMD21 is implicitly always there to allow adjusting implicit parameters. Otherwise, nothing changes: CMD21 use of itself does not adjust anything. . . . In fact there is a sequence of steps listed in another place about the concept-explanation that is explicit about: Sampling Control Block of Host is incremented by one step. in the looping (along with comparisons to a known tuning block pattern). . . . It also does report that any other implementation may be used: it is just an example for illustration. Possibly using the center of an observed valid window is mentioned. So I would expect that any time there is not a device-specific definition for how to do the adjustment for the loop, HS200 and HS400 should be disabled for lack of device specific driver software to support the activity. JESD84-B51 does not define any specific method of adjustment of itself as far as I can tell: there is no general/default technique. END QUOTE This traced back to FreeBSD using null_tune and null_return, which were (from old notes): static int null_retune(device_t brdev __unused, device_t reqdev __unused, bool reset __unused) { return (0); } static int null_tune(device_t brdev __unused, device_t reqdev __unused, bool hs400 __unused) { return (0); } e.MMC support can be made operational (with a speed tradeoff) by just not picking to use HS200 or HS400 so that the tune/return activity is not involved. I use a patch for that to allow the Rock64 to use its user-replacable e.MMC . (I've no other context where I use e.MMC these days.) QUOTE What I've done in my patch is analogous to what the the code shown after the #define SDHCI_CAP_MODES_TUNING above does, translated to fit the mmc's pre-existing code structure. END QUOTE My patch to main [so: 14] looks like (some whitespace details may not survive): # git -C /usr/main-src/ diff sys/dev/mmc/ diff --git a/sys/dev/mmc/mmc.c b/sys/dev/mmc/mmc.c index 5fce6cbf47a1..ff6896f35678 100644 --- a/sys/dev/mmc/mmc.c +++ b/sys/dev/mmc/mmc.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/kobj.h> #include <sys/malloc.h> #include <sys/lock.h> #include <sys/module.h> @@ -1512,6 +1513,8 @@ mmc_timing_to_string(enum mmc_bus_timing timing) static bool mmc_host_timing(device_t dev, enum mmc_bus_timing timing) { + kobjop_desc_t kobj_desc; + kobj_method_t *kobj_method; int host_caps; host_caps = mmcbr_get_caps(dev); @@ -1543,14 +1546,37 @@ mmc_host_timing(device_t dev, enum mmc_bus_timing timing) case bus_timing_mmc_ddr52: return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_DDR52)); case bus_timing_mmc_hs200: - return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS200_120) || - HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS200_180)); case bus_timing_mmc_hs400: - return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400_120) || - HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400_180)); case bus_timing_mmc_hs400es: - return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400 | - MMC_CAP_MMC_ENH_STROBE)); + /* + * Disable eMMC modes that require use of + * MMC_SEND_TUNING_BLOCK_HS200 to set things up if either the + * tune or re-tune method is the default NULL implementation. + */ + kobj_desc = &mmcbr_tune_desc; + kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL, + kobj_desc); + if (kobj_method == &kobj_desc->deflt) + return (false); + kobj_desc = &mmcbr_retune_desc; + kobj_method = kobj_lookup_method(((kobj_t)dev)->ops->cls, NULL, + kobj_desc); + if (kobj_method == &kobj_desc->deflt) { + return (false); + } + + /* + * Otherwise track the host capabilities. + */ + if (timing == bus_timing_mmc_hs200) + return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS200_120) || + HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS200_180)); + if (timing == bus_timing_mmc_hs400) + return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400_120) || + HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400_180)); + if (timing == bus_timing_mmc_hs400es) + return (HOST_TIMING_CAP(host_caps, MMC_CAP_MMC_HS400 | + MMC_CAP_MMC_ENH_STROBE)); } #undef HOST_TIMING_CAP === Mark Millard marklmi at yahoo.com