Re: Task completed
Cristian Trinidad <[email protected]> Fri, 10 Jul 2026 17:25:32 +0000
| Newsgroups | gmane.os.freebsd.devel.arm |
|---|---|
| Message-ID | <SN7PR20MB6186520D792017F3EE287A8EECFD2@SN7PR20MB6186.namprd20.prod.outlook.com> |
--_000_SN7PR20MB6186520D792017F3EE287A8EECFD2SN7PR20MB6186namp_ Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable [Included] sdhci_fsl: add ACPI front-end for NXP Layerscape eSDHC (NXP0003) ________________________________ From: [email protected] <[email protected]> on beha= lf of yarshure <[email protected]> Sent: Thursday, July 9, 2026 7:22 PM To: [email protected] <[email protected]> Cc: [email protected] <[email protected]> Subject: [PATCH] sdhci_fsl: add ACPI front-end for NXP Layerscape eSDHC (NX= P0003) Refactor the FDT-only sdhci_fsl driver into a bus-agnostic base class (DEFINE_CLASS_0 "sdhci_fsl") plus FDT and ACPI subclasses, mirroring sdhci_xenon. A shared sdhci_fsl_attach_common() does the controller bring-up; each front-end supplies the bus-specific bits (soc_data, base clock, endianness, mmc host properties, card-detect). The new ACPI front-end (sdhci_fsl_acpi.c) matches _HID NXP0003, reads the base clock from the _DSD "clock-frequency" property (there is no FDT clock framework under ACPI), and brings up the eSDHC controllers described by UEFI/EDK2 firmware. On a SolidRun LX2160A CEX7 booting via EDK2 this exposes the SD/TF card (/dev/mmcsd0) and eMMC (/dev/mmcsd1) that were previously invisible because no driver matched NXP0003. - New sdhci_fsl.h: shared softc, soc_data and DECLARE_CLASS(sdhci_fsl_drive= r). - sdhci_fsl_fdt.c: split attach into an FDT prologue + bus-agnostic sdhci_fsl_attach_common(); base class + FDT subclass; declare the mmc bridge on the shared "sdhci_fsl" devclass; guard get_ro for the no-GPIO (ACPI) case. - sdhci_fsl_acpi.c: NXP0003 ACPI binding; base clock from _DSD; generic card-present; mark the slot non-removable (eSDHC present-state card detect is unreliable); cap to high speed pending UHS tuning support. MFC after: 2 weeks Signed-off-by: yarshure <[email protected]> --- Notes for review (not part of the commit message): * Verification. Hardware-tested on a SolidRun HoneyComb / CEX7 (LX2160A) booting via EDK2/UEFI (ACPI). Before this change nothing matched _HID NXP0003, so the eSDHC controllers were unattached; after it both slots probe and come up: mmc0: <MMC/SD bus> ... on sdhci_fsl_acpi0 mmcsd0: <MMCHC ...> ... (SD/TF card) mmc1: <MMC/SD bus> ... on sdhci_fsl_acpi1 mmcsd1: <MMCHC ...> ... (eMMC) /dev/mmcsd0 and /dev/mmcsd1 read and write correctly. * The FDT path is preserved unchanged -- the refactor only splits the existing sdhci_fsl_attach() into an FDT prologue plus a bus-agnostic sdhci_fsl_attach_common(), mirroring sdhci_xenon's base/FDT/ACPI split, so existing FDT (device-tree) boots behave exactly as before. It has not been re-tested on an FDT-booted board; a smoke test there is welcome. * Two ACPI-specific choices worth a look: the base clock is read from the _DSD "clock-frequency" property (no FDT clock framework under ACPI), and the slot is marked non-removable + capped to high speed (eSDHC present-state card detect is unreliable; UHS tuning is future work). * Disclosure: developed with AI assistance; the hardware bring-up above was done by hand. sys/conf/files | 1 + sys/dev/sdhci/sdhci_fsl.h | 61 +++++++++ sys/dev/sdhci/sdhci_fsl_acpi.c | 124 +++++++++++++++++ sys/dev/sdhci/sdhci_fsl_fdt.c | 237 +++++++++++++++++++-------------- 4 files changed, 321 insertions(+), 102 deletions(-) create mode 100644 sys/dev/sdhci/sdhci_fsl.h create mode 100644 sys/dev/sdhci/sdhci_fsl_acpi.c diff --git a/sys/conf/files b/sys/conf/files index cc18ecbb9..face1c207 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3138,6 +3138,7 @@ dev/sdhci/sdhci.c optional sdhci dev/sdhci/sdhci_fdt.c optional sdhci fdt regulator clk dev/sdhci/sdhci_fdt_gpio.c optional sdhci fdt gpio dev/sdhci/sdhci_fsl_fdt.c optional sdhci fdt gpio regulator clk +dev/sdhci/sdhci_fsl_acpi.c optional sdhci fdt gpio regulator clk acpi dev/sdhci/sdhci_if.m optional sdhci dev/sdhci/sdhci_acpi.c optional sdhci acpi dev/sdhci/sdhci_pci.c optional sdhci pci diff --git a/sys/dev/sdhci/sdhci_fsl.h b/sys/dev/sdhci/sdhci_fsl.h new file mode 100644 index 000000000..a623b3b96 --- /dev/null +++ b/sys/dev/sdhci/sdhci_fsl.h @@ -0,0 +1,61 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Shared definitions for the NXP QorIQ Layerscape eSDHC controller, used = by + * both the FDT (sdhci_fsl_fdt.c) and ACPI (sdhci_fsl_acpi.c) bus front-en= ds. + */ + +#ifndef _SDHCI_FSL_H_ +#define _SDHCI_FSL_H_ + +#include <dev/mmc/mmc_helpers.h> +#include <dev/sdhci/sdhci.h> + +struct sdhci_fdt_gpio; + +struct sdhci_fsl_fdt_soc_data { + int quirks; + int baseclk_div; + uint8_t errata; + char *syscon_compat; +}; + +extern const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_lx2160a_soc_data; + +struct sdhci_fsl_fdt_softc { + device_t dev; + const struct sdhci_fsl_fdt_soc_data *soc_data; + struct resource *mem_res; + struct resource *irq_res; + void *irq_cookie; + uint32_t baseclk_hz; + uint32_t maxclk_hz; + struct sdhci_fdt_gpio *gpio; + struct sdhci_slot slot; + bool slot_init_done; + uint32_t cmd_and_mode; + uint16_t sdclk_bits; + struct mmc_helper fdt_helper; + uint32_t div_ratio; + uint8_t vendor_ver; + uint32_t flags; + + /* Set by the bus front-end before calling sdhci_fsl_attach_common(= ). */ + bool little_endian; + bool acpi; /* ACPI front-end (= no FDT node) */ + + uint32_t (* read)(struct sdhci_fsl_fdt_softc *, bus_size_t); + void (* write)(struct sdhci_fsl_fdt_softc *, bus_size_t, uint32_t); +}; + +DECLARE_CLASS(sdhci_fsl_driver); + +/* + * Bus-agnostic attach: allocate resources, configure the eSDHC block and = bring + * up the slot. The caller must first fill soc_data, baseclk_hz, little_en= dian, + * acpi and the parsed mmc host properties (slot.host) in the softc. + */ +int sdhci_fsl_attach_common(device_t dev); +int sdhci_fsl_detach(device_t dev); + +#endif /* _SDHCI_FSL_H_ */ diff --git a/sys/dev/sdhci/sdhci_fsl_acpi.c b/sys/dev/sdhci/sdhci_fsl_acpi.= c new file mode 100644 index 000000000..b9abfdfa9 --- /dev/null +++ b/sys/dev/sdhci/sdhci_fsl_acpi.c @@ -0,0 +1,124 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * ACPI front-end for the NXP QorIQ Layerscape eSDHC controller (_HID NXP0= 003). + * + * Under UEFI/ACPI the eSDHC is described in the DSDT (MMIO + IRQ in _CRS,= base + * clock and bus properties in _DSD) but there is no FDT clock framework. = This + * binding reads the firmware-provided properties and hands off to the sha= red + * sdhci_fsl_attach_common(), letting the OS access the SD/TF card (e.g. t= o + * rewrite the boot firmware) without booting under u-boot/FDT. + */ + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/taskqueue.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <dev/mmc/bridge.h> +#include <dev/mmc/mmcbrvar.h> +#include <dev/mmc/mmc_helpers.h> + +#include <contrib/dev/acpica/include/acpi.h> +#include <contrib/dev/acpica/include/accommon.h> +#include <dev/acpica/acpivar.h> + +#include <dev/sdhci/sdhci.h> +#include <dev/sdhci/sdhci_fsl.h> + +#include "mmcbr_if.h" +#include "sdhci_if.h" + +#include "opt_mmccam.h" + +static char *sdhci_fsl_acpi_hids[] =3D { + "NXP0003", + NULL +}; + +static int +sdhci_fsl_acpi_probe(device_t dev) +{ + int err; + + err =3D ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_fsl_acpi_h= ids, + NULL); + if (err <=3D 0) { + device_set_desc(dev, + "NXP QorIQ Layerscape eSDHC controller"); + return (err); + } + + return (ENXIO); +} + +static int +sdhci_fsl_acpi_attach(device_t dev) +{ + struct sdhci_fsl_fdt_softc *sc; + struct mmc_helper mmc_helper; + uint32_t clk_hz; + + sc =3D device_get_softc(dev); + + /* + * NXP0003 identifies the LX2160A-class eSDHC; use its SoC data for= the + * quirks/errata and the base-clock divider. + */ + sc->soc_data =3D &sdhci_fsl_fdt_lx2160a_soc_data; + sc->acpi =3D true; + sc->little_endian =3D true; /* _DSD "little-endian"; LX2160A = eSDHC */ + + /* Base (peripheral) clock from the _DSD "clock-frequency" property= . */ + clk_hz =3D 0; + if (device_get_property(dev, "clock-frequency", &clk_hz, sizeof(clk= _hz), + DEVICE_PROP_UINT32) <=3D 0 || clk_hz =3D=3D 0) { + device_printf(dev, "missing 'clock-frequency' property\n"); + return (ENXIO); + } + sc->baseclk_hz =3D clk_hz / sc->soc_data->baseclk_div; + + /* mmc host properties (bus-width, max-frequency, ...) from _DSD. *= / + memset(&mmc_helper, 0, sizeof(mmc_helper)); + if (mmc_parse(dev, &mmc_helper, &sc->slot.host) !=3D 0) + return (ENXIO); + + /* + * Cap to high speed (25 MHz). UHS modes (SDR50/SDR104) require a t= uning + * sequence with voltage switching that is not yet wired up on the = ACPI + * front-end, so restrict to a non-tuned speed for reliable enumera= tion. + */ + if (sc->slot.host.f_max > 25000000) + sc->slot.host.f_max =3D 25000000; + + return (sdhci_fsl_attach_common(dev)); +} + +static const device_method_t sdhci_fsl_acpi_methods[] =3D { + DEVMETHOD(device_probe, sdhci_fsl_acpi_probe), + DEVMETHOD(device_attach, sdhci_fsl_acpi_attach), + DEVMETHOD(device_detach, sdhci_fsl_detach), + + /* + * No FDT GPIO line under ACPI; use the controller's own card-detec= t + * (present-state register) instead. + */ + DEVMETHOD(sdhci_get_card_present, sdhci_generic_get_card_pres= ent), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(sdhci_fsl, sdhci_fsl_acpi_driver, sdhci_fsl_acpi_methods, + sizeof(struct sdhci_fsl_fdt_softc), sdhci_fsl_driver); + +DRIVER_MODULE(sdhci_fsl_acpi, acpi, sdhci_fsl_acpi_driver, NULL, NULL); +SDHCI_DEPEND(sdhci_fsl_acpi); + +#ifndef MMCCAM +MMC_DECLARE_BRIDGE(sdhci_fsl_acpi); +#endif diff --git a/sys/dev/sdhci/sdhci_fsl_fdt.c b/sys/dev/sdhci/sdhci_fsl_fdt.c index 185b53a6d..185c31e50 100644 --- a/sys/dev/sdhci/sdhci_fsl_fdt.c +++ b/sys/dev/sdhci/sdhci_fsl_fdt.c @@ -48,6 +48,7 @@ #include <dev/ofw/ofw_bus_subr.h> #include <dev/sdhci/sdhci.h> #include <dev/sdhci/sdhci_fdt_gpio.h> +#include <dev/sdhci/sdhci_fsl.h> #include "mmcbr_if.h" #include "sdhci_if.h" @@ -183,34 +184,10 @@ #define SDHCI_FSL_MAX_RETRIES 20000 /* DELAY(10) * this =3D 20= 0ms */ -struct sdhci_fsl_fdt_softc { - device_t dev; - const struct sdhci_fsl_fdt_soc_data *soc_data; - struct resource *mem_res; - struct resource *irq_res; - void *irq_cookie; - uint32_t baseclk_hz; - uint32_t maxclk_hz; - struct sdhci_fdt_gpio *gpio; - struct sdhci_slot slot; - bool slot_init_done; - uint32_t cmd_and_mode; - uint16_t sdclk_bits; - struct mmc_helper fdt_helper; - uint32_t div_ratio; - uint8_t vendor_ver; - uint32_t flags; - - uint32_t (* read)(struct sdhci_fsl_fdt_softc *, bus_size_t); - void (* write)(struct sdhci_fsl_fdt_softc *, bus_size_t, uint32_t); -}; - -struct sdhci_fsl_fdt_soc_data { - int quirks; - int baseclk_div; - uint8_t errata; - char *syscon_compat; -}; +/* + * struct sdhci_fsl_fdt_softc and struct sdhci_fsl_fdt_soc_data now live i= n + * <dev/sdhci/sdhci_fsl.h> so they can be shared with the ACPI front-end. + */ static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_ls1012a_soc_data = =3D { .quirks =3D 0, @@ -234,7 +211,8 @@ static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fd= t_ls1046a_soc_data =3D { .syscon_compat =3D "fsl,ls1046a-scfg", }; -static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_lx2160a_soc_data = =3D { +/* Shared with the ACPI front-end (declared in sdhci_fsl.h). */ +const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_lx2160a_soc_data =3D { .quirks =3D 0, .baseclk_div =3D 2, .errata =3D SDHCI_FSL_UNRELIABLE_PULSE_DET | @@ -755,6 +733,9 @@ sdhci_fsl_fdt_get_ro(device_t bus, device_t child) struct sdhci_fsl_fdt_softc *sc; sc =3D device_get_softc(bus); + /* No FDT write-protect GPIO (e.g. ACPI front-end): use the std reg= . */ + if (sc->gpio =3D=3D NULL) + return (sdhci_generic_get_ro(bus, child)); return (sdhci_fdt_gpio_get_readonly(sc->gpio)); } @@ -803,8 +784,12 @@ sdhci_fsl_fdt_vddrange_to_mask(device_t dev, uint32_t = *vdd_ranges, int len) return (vdd_mask); } +/* + * Apply the FDT "voltage-ranges" property over the capabilities that + * sdhci_fsl_attach_common() already read from hardware. FDT front-end onl= y. + */ static void -sdhci_fsl_fdt_of_parse(device_t dev) +sdhci_fsl_fdt_voltage_fixup(device_t dev) { struct sdhci_fsl_fdt_softc *sc; phandle_t node; @@ -815,16 +800,6 @@ sdhci_fsl_fdt_of_parse(device_t dev) sc =3D device_get_softc(dev); node =3D ofw_bus_get_node(dev); - /* Call mmc_fdt_parse in order to get mmc related properties. */ - mmc_fdt_parse(dev, node, &sc->fdt_helper, &sc->slot.host); - - sc->slot.quirks |=3D SDHCI_QUIRK_MISSING_CAPS; - sc->slot.caps =3D sdhci_fsl_fdt_read_4(dev, &sc->slot, - SDHCI_CAPABILITIES) & ~(SDHCI_CAN_DO_SUSPEND); - sc->slot.caps2 =3D sdhci_fsl_fdt_read_4(dev, &sc->slot, - SDHCI_CAPABILITIES2); - - /* Parse the "voltage-ranges" dts property. */ num_ranges =3D OF_getencprop_alloc(node, "voltage-ranges", (void **) &voltage_ranges); if (num_ranges <=3D 0) @@ -859,39 +834,37 @@ sdhci_fsl_poll_register(struct sdhci_fsl_fdt_softc *s= c, return (0); } -static int -sdhci_fsl_fdt_attach(device_t dev) +/* + * Bus-agnostic attach. The bus front-end must have filled soc_data, + * baseclk_hz, little_endian, acpi and the parsed mmc host properties + * (slot.host) in the softc before calling this. + */ +int +sdhci_fsl_attach_common(device_t dev) { struct sdhci_fsl_fdt_softc *sc; struct mmc_host *host; uint32_t val, buf_order; - uintptr_t ocd_data; - uint64_t clk_hz; - phandle_t node; int rid, ret; - clk_t clk; - node =3D ofw_bus_get_node(dev); sc =3D device_get_softc(dev); - ocd_data =3D ofw_bus_search_compatible(dev, - sdhci_fsl_fdt_compat_data)->ocd_data; sc->dev =3D dev; sc->flags =3D 0; host =3D &sc->slot.host; - rid =3D 0; - - /* - * LX2160A needs its own soc_data in order to apply SoC - * specific quriks. Since the controller is identified - * only with a generic compatible string we need to do this dance h= ere. - */ - if (ofw_bus_node_is_compatible(OF_finddevice("/"), "fsl,lx2160a")) - sc->soc_data =3D &sdhci_fsl_fdt_lx2160a_soc_data; - else - sc->soc_data =3D (struct sdhci_fsl_fdt_soc_data *)ocd_data; - sc->slot.quirks =3D sc->soc_data->quirks; + /* eSDHC block endianness; chosen by the bus front-end. */ + if (sc->little_endian) { + sc->read =3D read_le; + sc->write =3D write_le; + buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_NATIVE; + } else { + sc->read =3D read_be; + sc->write =3D write_be; + buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_SWAP; + } + + rid =3D 0; sc->mem_res =3D bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res =3D=3D NULL) { @@ -917,36 +890,20 @@ sdhci_fsl_fdt_attach(device_t dev) goto err_free_irq_res; } - ret =3D clk_get_by_ofw_index(dev, node, 0, &clk); - if (ret !=3D 0) { - device_printf(dev, "Parent clock not found\n"); - goto err_free_irq; - } - - ret =3D clk_get_freq(clk, &clk_hz); - if (ret !=3D 0) { - device_printf(dev, - "Could not get parent clock frequency\n"); - goto err_free_irq; - } - - sc->baseclk_hz =3D clk_hz / sc->soc_data->baseclk_div; - - /* Figure out eSDHC block endianness before we touch any HW regs. *= / - if (OF_hasprop(node, "little-endian")) { - sc->read =3D read_le; - sc->write =3D write_le; - buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_NATIVE; - } else { - sc->read =3D read_be; - sc->write =3D write_be; - buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_SWAP; - } - sc->vendor_ver =3D (RD4(sc, SDHCI_FSL_HOST_VERSION) & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; - sdhci_fsl_fdt_of_parse(dev); + /* Capabilities are missing from the standard registers; read them.= */ + sc->slot.quirks |=3D SDHCI_QUIRK_MISSING_CAPS; + sc->slot.caps =3D sdhci_fsl_fdt_read_4(dev, &sc->slot, + SDHCI_CAPABILITIES) & ~(SDHCI_CAN_DO_SUSPEND); + sc->slot.caps2 =3D sdhci_fsl_fdt_read_4(dev, &sc->slot, + SDHCI_CAPABILITIES2); + + /* FDT may override the voltage caps via "voltage-ranges". */ + if (!sc->acpi) + sdhci_fsl_fdt_voltage_fixup(dev); + sc->maxclk_hz =3D host->f_max ? host->f_max : sc->baseclk_hz; /* @@ -971,7 +928,10 @@ sdhci_fsl_fdt_attach(device_t dev) val =3D RD4(sc, SDHCI_FSL_ESDHC_CTRL); WR4(sc, SDHCI_FSL_ESDHC_CTRL, val | SDHCI_FSL_ESDHC_CTRL_CLK_DIV2)= ; sc->slot.max_clk =3D sc->maxclk_hz; - sc->gpio =3D sdhci_fdt_gpio_setup(dev, &sc->slot); + + /* GPIO card-detect is an FDT-only facility. */ + if (!sc->acpi) + sc->gpio =3D sdhci_fdt_gpio_setup(dev, &sc->slot); /* * Set the buffer watermark level to 128 words (512 bytes) for bot= h @@ -992,6 +952,16 @@ sdhci_fsl_fdt_attach(device_t dev) ret =3D sdhci_init_slot(dev, &sc->slot, 0); if (ret !=3D 0) goto err_free_gpio; + + /* + * The eSDHC's SDHCI present-state card-detect bits are unreliable;= the + * FDT path works around this with a GPIO card-detect line, which i= s not + * available under ACPI. Mark the slot non-removable so sdhci attac= hes + * the mmc bus without waiting for a (never-stable) card-detect. + */ + if (sc->acpi) + sc->slot.opt |=3D SDHCI_NON_REMOVABLE; + sc->slot_init_done =3D true; sdhci_start_slot(&sc->slot); @@ -999,8 +969,8 @@ sdhci_fsl_fdt_attach(device_t dev) return (0); err_free_gpio: - sdhci_fdt_gpio_teardown(sc->gpio); -err_free_irq: + if (sc->gpio !=3D NULL) + sdhci_fdt_gpio_teardown(sc->gpio); bus_teardown_intr(dev, sc->irq_res, sc->irq_cookie); err_free_irq_res: bus_free_resource(dev, SYS_RES_IRQ, sc->irq_res); @@ -1010,7 +980,54 @@ sdhci_fsl_fdt_attach(device_t dev) } static int -sdhci_fsl_fdt_detach(device_t dev) +sdhci_fsl_fdt_attach(device_t dev) +{ + struct sdhci_fsl_fdt_softc *sc; + uintptr_t ocd_data; + uint64_t clk_hz; + phandle_t node; + clk_t clk; + int ret; + + node =3D ofw_bus_get_node(dev); + sc =3D device_get_softc(dev); + ocd_data =3D ofw_bus_search_compatible(dev, + sdhci_fsl_fdt_compat_data)->ocd_data; + + /* + * LX2160A needs its own soc_data in order to apply SoC + * specific quriks. Since the controller is identified + * only with a generic compatible string we need to do this dance h= ere. + */ + if (ofw_bus_node_is_compatible(OF_finddevice("/"), "fsl,lx2160a")) + sc->soc_data =3D &sdhci_fsl_fdt_lx2160a_soc_data; + else + sc->soc_data =3D (const struct sdhci_fsl_fdt_soc_data *)ocd= _data; + + /* Parent (peripheral) clock comes from the FDT clock framework. */ + ret =3D clk_get_by_ofw_index(dev, node, 0, &clk); + if (ret !=3D 0) { + device_printf(dev, "Parent clock not found\n"); + return (ret); + } + ret =3D clk_get_freq(clk, &clk_hz); + if (ret !=3D 0) { + device_printf(dev, "Could not get parent clock frequency\n"= ); + return (ret); + } + sc->baseclk_hz =3D clk_hz / sc->soc_data->baseclk_div; + + sc->little_endian =3D OF_hasprop(node, "little-endian"); + sc->acpi =3D false; + + /* mmc host properties from the FDT node. */ + mmc_fdt_parse(dev, node, &sc->fdt_helper, &sc->slot.host); + + return (sdhci_fsl_attach_common(dev)); +} + +int +sdhci_fsl_detach(device_t dev) { struct sdhci_fsl_fdt_softc *sc; @@ -1514,12 +1531,11 @@ sdhci_fsl_fdt_set_uhs_timing(device_t dev, struct s= dhci_slot *slot) } } -static const device_method_t sdhci_fsl_fdt_methods[] =3D { - /* Device interface. */ - DEVMETHOD(device_probe, sdhci_fsl_fdt_probe), - DEVMETHOD(device_attach, sdhci_fsl_fdt_attach), - DEVMETHOD(device_detach, sdhci_fsl_fdt_detach), - +/* + * Bus-agnostic base class. The FDT and ACPI front-ends subclass this and + * override only device_probe/attach/detach (and, for ACPI, card-present). + */ +static const device_method_t sdhci_fsl_methods[] =3D { /* Bus interface. */ DEVMETHOD(bus_read_ivar, sdhci_fsl_fdt_read_ivar), DEVMETHOD(bus_write_ivar, sdhci_fsl_fdt_write_ivar), @@ -1549,12 +1565,29 @@ static const device_method_t sdhci_fsl_fdt_methods[= ] =3D { DEVMETHOD_END }; -static driver_t sdhci_fsl_fdt_driver =3D { - "sdhci_fsl_fdt", - sdhci_fsl_fdt_methods, - sizeof(struct sdhci_fsl_fdt_softc), +DEFINE_CLASS_0(sdhci_fsl, sdhci_fsl_driver, sdhci_fsl_methods, + sizeof(struct sdhci_fsl_fdt_softc)); + +/* + * Attach the mmc bus to the shared "sdhci_fsl" devclass (both the FDT and= ACPI + * subclasses create devices of this class). Without this the controller + * attaches but the mmc bridge never does, so no card enumerates. + */ +#ifndef MMCCAM +MMC_DECLARE_BRIDGE(sdhci_fsl); +#endif + +/* FDT front-end. */ +static const device_method_t sdhci_fsl_fdt_methods[] =3D { + DEVMETHOD(device_probe, sdhci_fsl_fdt_probe), + DEVMETHOD(device_attach, sdhci_fsl_fdt_attach), + DEVMETHOD(device_detach, sdhci_fsl_detach), + DEVMETHOD_END }; +DEFINE_CLASS_1(sdhci_fsl, sdhci_fsl_fdt_driver, sdhci_fsl_fdt_methods, + sizeof(struct sdhci_fsl_fdt_softc), sdhci_fsl_driver); + DRIVER_MODULE(sdhci_fsl_fdt, simplebus, sdhci_fsl_fdt_driver, NULL, NULL); SDHCI_DEPEND(sdhci_fsl_fdt); -- 2.39.3 (Apple Git-146) --_000_SN7PR20MB6186520D792017F3EE287A8EECFD2SN7PR20MB6186namp_ Content-Type: text/html; charset="us-ascii" Content-Transfer-Encoding: quoted-printable <html> <head> <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dus-ascii"= > </head> <body> <div style=3D"font-family: inherit; font-size: inherit; color: inherit; bac= kground-color: transparent;"> [Included] sdhci_fsl: add ACPI front-end for NXP Layerscape eSDHC (NXP0003)= <br> </div> <br> <hr style=3D"display:inline-block;width:98%" tabindex=3D"-1"> <div id=3D"divRplyFwdMsg" dir=3D"ltr"><font face=3D"Calibri, sans-serif" st= yle=3D"font-size:11pt" color=3D"#000000"><b>From:</b> owner-freebsd-arm@Fre= eBSD.org <[email protected]> on behalf of yarshure <ya= [email protected]><br> <b>Sent:</b> Thursday, July 9, 2026 7:22 PM<br> <b>To:</b> [email protected] <[email protected]><br> <b>Cc:</b> [email protected] <[email protected]><br> <b>Subject:</b> [PATCH] sdhci_fsl: add ACPI front-end for NXP Layerscape eS= DHC (NXP0003)</font> <div> </div> </div> <div class=3D"BodyFragment"><font size=3D"2"><span style=3D"font-size:11pt;= "> <div class=3D"PlainText">Refactor the FDT-only sdhci_fsl driver into a bus-= agnostic base class<br> (DEFINE_CLASS_0 "sdhci_fsl") plus FDT and ACPI subclasses, mirror= ing<br> sdhci_xenon. A shared sdhci_fsl_attach_common() does the controller<br> bring-up; each front-end supplies the bus-specific bits (soc_data, base<br> clock, endianness, mmc host properties, card-detect).<br> <br> The new ACPI front-end (sdhci_fsl_acpi.c) matches _HID NXP0003, reads<br> the base clock from the _DSD "clock-frequency" property (there is= no FDT<br> clock framework under ACPI), and brings up the eSDHC controllers<br> described by UEFI/EDK2 firmware. On a SolidRun LX2160A CEX7 booting via<br> EDK2 this exposes the SD/TF card (/dev/mmcsd0) and eMMC (/dev/mmcsd1)<br> that were previously invisible because no driver matched NXP0003.<br> <br> - New sdhci_fsl.h: shared softc, soc_data and DECLARE_CLASS(sdhci_fsl_drive= r).<br> - sdhci_fsl_fdt.c: split attach into an FDT prologue + bus-agnostic<br> sdhci_fsl_attach_common(); base class + FDT subclass; declare the mm= c<br> bridge on the shared "sdhci_fsl" devclass; guard get_ro fo= r the<br> no-GPIO (ACPI) case.<br> - sdhci_fsl_acpi.c: NXP0003 ACPI binding; base clock from _DSD; generic<br> card-present; mark the slot non-removable (eSDHC present-state card<= br> detect is unreliable); cap to high speed pending UHS tuning support.= <br> <br> MFC after: 2 weeks<br> Signed-off-by: yarshure <[email protected]><br> ---<br> Notes for review (not part of the commit message):<br> <br> * Verification. Hardware-tested on a SolidRun HoneyComb / CEX7 (LX216= 0A)<br> booting via EDK2/UEFI (ACPI). Before this change nothing match= ed _HID<br> NXP0003, so the eSDHC controllers were unattached; after it both slo= ts<br> probe and come up:<br> <br> mmc0: <MMC/SD bus> ... on sdhci_fsl_ac= pi0<br> mmcsd0: <MMCHC ...> ... (SD/TF card)<b= r> mmc1: <MMC/SD bus> ... on sdhci_fsl_ac= pi1<br> mmcsd1: <MMCHC ...> ... (eMMC)<br> <br> /dev/mmcsd0 and /dev/mmcsd1 read and write correctly.<br> <br> * The FDT path is preserved unchanged -- the refactor only splits the<br> existing sdhci_fsl_attach() into an FDT prologue plus a bus-agnostic= <br> sdhci_fsl_attach_common(), mirroring sdhci_xenon's base/FDT/ACPI spl= it,<br> so existing FDT (device-tree) boots behave exactly as before. = It has<br> not been re-tested on an FDT-booted board; a smoke test there is wel= come.<br> <br> * Two ACPI-specific choices worth a look: the base clock is read from the<b= r> _DSD "clock-frequency" property (no FDT clock framework un= der ACPI), and<br> the slot is marked non-removable + capped to high speed (eSDHC<br> present-state card detect is unreliable; UHS tuning is future work).= <br> <br> * Disclosure: developed with AI assistance; the hardware bring-up above<br> was done by hand.<br> <br> sys/conf/files &= nbsp; | 1 +<br> sys/dev/sdhci/sdhci_fsl.h | 61 ++= +++++++<br> sys/dev/sdhci/sdhci_fsl_acpi.c | 124 +++++++++++++++++<br> sys/dev/sdhci/sdhci_fsl_fdt.c | 237 +++++++++++++++++++--------= ------<br> 4 files changed, 321 insertions(+), 102 deletions(-)<br> create mode 100644 sys/dev/sdhci/sdhci_fsl.h<br> create mode 100644 sys/dev/sdhci/sdhci_fsl_acpi.c<br> <br> diff --git a/sys/conf/files b/sys/conf/files<br> index cc18ecbb9..face1c207 100644<br> --- a/sys/conf/files<br> +++ b/sys/conf/files<br> @@ -3138,6 +3138,7 @@ dev/sdhci/sdhci.c = optional sdhci<br> dev/sdhci/sdhci_fdt.c = optional sdhci fdt regulator clk<br> dev/sdhci/sdhci_fdt_gpio.c optional sdh= ci fdt gpio<br> dev/sdhci/sdhci_fsl_fdt.c optiona= l sdhci fdt gpio regulator clk<br> +dev/sdhci/sdhci_fsl_acpi.c optional sdhci fdt gpio= regulator clk acpi<br> dev/sdhci/sdhci_if.m &= nbsp; optional sdhci<br> dev/sdhci/sdhci_acpi.c  = ; optional sdhci acpi<br> dev/sdhci/sdhci_pci.c = optional sdhci pci<br> diff --git a/sys/dev/sdhci/sdhci_fsl.h b/sys/dev/sdhci/sdhci_fsl.h<br> new file mode 100644<br> index 000000000..a623b3b96<br> --- /dev/null<br> +++ b/sys/dev/sdhci/sdhci_fsl.h<br> @@ -0,0 +1,61 @@<br> +/*-<br> + * SPDX-License-Identifier: BSD-2-Clause<br> + *<br> + * Shared definitions for the NXP QorIQ Layerscape eSDHC controller, used = by<br> + * both the FDT (sdhci_fsl_fdt.c) and ACPI (sdhci_fsl_acpi.c) bus front-en= ds.<br> + */<br> +<br> +#ifndef _SDHCI_FSL_H_<br> +#define _SDHCI_FSL_H_<br> +<br> +#include <dev/mmc/mmc_helpers.h><br> +#include <dev/sdhci/sdhci.h><br> +<br> +struct sdhci_fdt_gpio;<br> +<br> +struct sdhci_fsl_fdt_soc_data {<br> + int quirks;<br> + int baseclk_div;<br> + uint8_t errata;<br> + char *syscon_compat;<br> +};<br> +<br> +extern const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_lx2160a_soc_data;= <br> +<br> +struct sdhci_fsl_fdt_softc {<br> + device_t  = ; &n= bsp;  = ; dev;<br> + const struct sdhci_fsl_fdt_soc_data&n= bsp; *soc_data;<br> + struct resource &nbs= p; &= nbsp; *mem_res;<br> + struct resource &nbs= p; &= nbsp; *irq_res;<br> + void &nb= sp; = &nb= sp; *irq_cookie;<br> + uint32_t  = ; &n= bsp;  = ; baseclk_hz;<br> + uint32_t  = ; &n= bsp;  = ; maxclk_hz;<br> + struct sdhci_fdt_gpio &nbs= p; &= nbsp; *gpio;<br> + struct sdhci_slot &n= bsp;  = ; slot;<br> + bool &nb= sp; = &nb= sp; slot_init_done;<br> + uint32_t  = ; &n= bsp;  = ; cmd_and_mode;<br> + uint16_t  = ; &n= bsp;  = ; sdclk_bits;<br> + struct mmc_helper &n= bsp;  = ; fdt_helper;<br> + uint32_t  = ; &n= bsp;  = ; div_ratio;<br> + uint8_t = &nb= sp; = vendor_ver;<br> + uint32_t  = ; &n= bsp;  = ; flags;<br> +<br> + /* Set by the bus front-end before ca= lling sdhci_fsl_attach_common(). */<br> + bool &nb= sp; = &nb= sp; little_endian;<br> + bool &nb= sp; = &nb= sp; acpi; /* ACPI front-end (no FDT nod= e) */<br> +<br> + uint32_t (* read)(struct sdhci_fsl_fd= t_softc *, bus_size_t);<br> + void (* write)(struct sdhci_fsl_fdt_s= oftc *, bus_size_t, uint32_t);<br> +};<br> +<br> +DECLARE_CLASS(sdhci_fsl_driver);<br> +<br> +/*<br> + * Bus-agnostic attach: allocate resources, configure the eSDHC block and = bring<br> + * up the slot. The caller must first fill soc_data, baseclk_hz, little_en= dian,<br> + * acpi and the parsed mmc host properties (slot.host) in the softc.<br> + */<br> +int sdhci_fsl_attach_common(device_t dev);<br> +int sdhci_fsl_detach(device_t dev);<br> +<br> +#endif /* _SDHCI_FSL_H_ */<br> diff --git a/sys/dev/sdhci/sdhci_fsl_acpi.c b/sys/dev/sdhci/sdhci_fsl_acpi.= c<br> new file mode 100644<br> index 000000000..b9abfdfa9<br> --- /dev/null<br> +++ b/sys/dev/sdhci/sdhci_fsl_acpi.c<br> @@ -0,0 +1,124 @@<br> +/*-<br> + * SPDX-License-Identifier: BSD-2-Clause<br> + *<br> + * ACPI front-end for the NXP QorIQ Layerscape eSDHC controller (_HID NXP0= 003).<br> + *<br> + * Under UEFI/ACPI the eSDHC is described in the DSDT (MMIO + IRQ in _CRS,= base<br> + * clock and bus properties in _DSD) but there is no FDT clock framework. = This<br> + * binding reads the firmware-provided properties and hands off to the sha= red<br> + * sdhci_fsl_attach_common(), letting the OS access the SD/TF card (e.g. t= o<br> + * rewrite the boot firmware) without booting under u-boot/FDT.<br> + */<br> +<br> +#include <sys/param.h><br> +#include <sys/bus.h><br> +#include <sys/kernel.h><br> +#include <sys/module.h><br> +#include <sys/rman.h><br> +#include <sys/taskqueue.h><br> +<br> +#include <machine/bus.h><br> +#include <machine/resource.h><br> +<br> +#include <dev/mmc/bridge.h><br> +#include <dev/mmc/mmcbrvar.h><br> +#include <dev/mmc/mmc_helpers.h><br> +<br> +#include <contrib/dev/acpica/include/acpi.h><br> +#include <contrib/dev/acpica/include/accommon.h><br> +#include <dev/acpica/acpivar.h><br> +<br> +#include <dev/sdhci/sdhci.h><br> +#include <dev/sdhci/sdhci_fsl.h><br> +<br> +#include "mmcbr_if.h"<br> +#include "sdhci_if.h"<br> +<br> +#include "opt_mmccam.h"<br> +<br> +static char *sdhci_fsl_acpi_hids[] =3D {<br> + "NXP0003",<br> + NULL<br> +};<br> +<br> +static int<br> +sdhci_fsl_acpi_probe(device_t dev)<br> +{<br> + int err;<br> +<br> + err =3D ACPI_ID_PROBE(device_get_pare= nt(dev), dev, sdhci_fsl_acpi_hids,<br> + NULL);<br> + if (err <=3D 0) {<br> + &n= bsp; device_set_desc(dev,<br> + &n= bsp; "NXP QorIQ Layerscape eSDHC control= ler");<br> + &n= bsp; return (err);<br> + }<br> +<br> + return (ENXIO);<br> +}<br> +<br> +static int<br> +sdhci_fsl_acpi_attach(device_t dev)<br> +{<br> + struct sdhci_fsl_fdt_softc *sc;<br> + struct mmc_helper mmc_helper;<br> + uint32_t clk_hz;<br> +<br> + sc =3D device_get_softc(dev);<br> +<br> + /*<br> + * NXP0003 identifies the LX2160= A-class eSDHC; use its SoC data for the<br> + * quirks/errata and the base-cl= ock divider.<br> + */<br> + sc->soc_data =3D &sdhci_fsl_fd= t_lx2160a_soc_data;<br> + sc->acpi =3D true;<br> + sc->little_endian =3D true; &= nbsp; /* _DSD "little-endian"; LX2160A eS= DHC */<br> +<br> + /* Base (peripheral) clock from the _= DSD "clock-frequency" property. */<br> + clk_hz =3D 0;<br> + if (device_get_property(dev, "cl= ock-frequency", &clk_hz, sizeof(clk_hz),<br> + DEVICE_PROP_U= INT32) <=3D 0 || clk_hz =3D=3D 0) {<br> + &n= bsp; device_printf(dev, "missing 'clock-frequency' property\n&qu= ot;);<br> + &n= bsp; return (ENXIO);<br> + }<br> + sc->baseclk_hz =3D clk_hz / sc->= ;soc_data->baseclk_div;<br> +<br> + /* mmc host properties (bus-width, ma= x-frequency, ...) from _DSD. */<br> + memset(&mmc_helper, 0, sizeof(mmc= _helper));<br> + if (mmc_parse(dev, &mmc_helper, &= amp;sc->slot.host) !=3D 0)<br> + &n= bsp; return (ENXIO);<br> +<br> + /*<br> + * Cap to high speed (25 MHz). U= HS modes (SDR50/SDR104) require a tuning<br> + * sequence with voltage switchi= ng that is not yet wired up on the ACPI<br> + * front-end, so restrict to a n= on-tuned speed for reliable enumeration.<br> + */<br> + if (sc->slot.host.f_max > 25000= 000)<br> + &n= bsp; sc->slot.host.f_max =3D 25000000;<br> +<br> + return (sdhci_fsl_attach_common(dev))= ;<br> +}<br> +<br> +static const device_method_t sdhci_fsl_acpi_methods[] =3D {<br> + DEVMETHOD(device_probe, &n= bsp;  = ; sdhci_fsl_acpi_probe),<br> + DEVMETHOD(device_attach, &= nbsp; &nbs= p; sdhci_fsl_acpi_attach),<br> + DEVMETHOD(device_detach, &= nbsp; &nbs= p; sdhci_fsl_detach),<br> +<br> + /*<br> + * No FDT GPIO line under ACPI; = use the controller's own card-detect<br> + * (present-state register) inst= ead.<br> + */<br> + DEVMETHOD(sdhci_get_card_present,&nbs= p; sdhci_generic_get_card_present),<br> +<br> + DEVMETHOD_END<br> +};<br> +<br> +DEFINE_CLASS_1(sdhci_fsl, sdhci_fsl_acpi_driver, sdhci_fsl_acpi_methods,<b= r> + sizeof(struct sdhci_fsl_fdt_softc), sdhci_fsl_driver);<= br> +<br> +DRIVER_MODULE(sdhci_fsl_acpi, acpi, sdhci_fsl_acpi_driver, NULL, NULL);<br= > +SDHCI_DEPEND(sdhci_fsl_acpi);<br> +<br> +#ifndef MMCCAM<br> +MMC_DECLARE_BRIDGE(sdhci_fsl_acpi);<br> +#endif<br> diff --git a/sys/dev/sdhci/sdhci_fsl_fdt.c b/sys/dev/sdhci/sdhci_fsl_fdt.c<= br> index 185b53a6d..185c31e50 100644<br> --- a/sys/dev/sdhci/sdhci_fsl_fdt.c<br> +++ b/sys/dev/sdhci/sdhci_fsl_fdt.c<br> @@ -48,6 +48,7 @@<br> #include <dev/ofw/ofw_bus_subr.h><br> #include <dev/sdhci/sdhci.h><br> #include <dev/sdhci/sdhci_fdt_gpio.h><br> +#include <dev/sdhci/sdhci_fsl.h><br> <br> #include "mmcbr_if.h"<br> #include "sdhci_if.h"<br> @@ -183,34 +184,10 @@<br> <br> #define SDHCI_FSL_MAX_RETRIES &nbs= p; 20000 /* DELAY(10) * this =3D 200ms */<br> <br> -struct sdhci_fsl_fdt_softc {<br> - device_t  = ; &n= bsp;  = ; dev;<br> - const struct sdhci_fsl_fdt_soc_data&n= bsp; *soc_data;<br> - struct resource &nbs= p; &= nbsp; *mem_res;<br> - struct resource &nbs= p; &= nbsp; *irq_res;<br> - void &nb= sp; = &nb= sp; *irq_cookie;<br> - uint32_t  = ; &n= bsp;  = ; baseclk_hz;<br> - uint32_t  = ; &n= bsp;  = ; maxclk_hz;<br> - struct sdhci_fdt_gpio &nbs= p; &= nbsp; *gpio;<br> - struct sdhci_slot &n= bsp;  = ; slot;<br> - bool &nb= sp; = &nb= sp; slot_init_done;<br> - uint32_t  = ; &n= bsp;  = ; cmd_and_mode;<br> - uint16_t  = ; &n= bsp;  = ; sdclk_bits;<br> - struct mmc_helper &n= bsp;  = ; fdt_helper;<br> - uint32_t  = ; &n= bsp;  = ; div_ratio;<br> - uint8_t = &nb= sp; = vendor_ver;<br> - uint32_t  = ; &n= bsp;  = ; flags;<br> -<br> - uint32_t (* read)(struct sdhci_fsl_fd= t_softc *, bus_size_t);<br> - void (* write)(struct sdhci_fsl_fdt_s= oftc *, bus_size_t, uint32_t);<br> -};<br> -<br> -struct sdhci_fsl_fdt_soc_data {<br> - int quirks;<br> - int baseclk_div;<br> - uint8_t errata;<br> - char *syscon_compat;<br> -};<br> +/*<br> + * struct sdhci_fsl_fdt_softc and struct sdhci_fsl_fdt_soc_data now live i= n<br> + * <dev/sdhci/sdhci_fsl.h> so they can be shared with the ACPI front= -end.<br> + */<br> <br> static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_ls1012a_soc_= data =3D {<br> .quirks =3D 0,<br> @@ -234,7 +211,8 @@ static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fd= t_ls1046a_soc_data =3D {<br> .syscon_compat =3D "f= sl,ls1046a-scfg",<br> };<br> <br> -static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_lx2160a_soc_data = =3D {<br> +/* Shared with the ACPI front-end (declared in sdhci_fsl.h). */<br> +const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_lx2160a_soc_data =3D {<b= r> .quirks =3D 0,<br> .baseclk_div =3D 2,<br> .errata =3D SDHCI_FSL_UNRE= LIABLE_PULSE_DET |<br> @@ -755,6 +733,9 @@ sdhci_fsl_fdt_get_ro(device_t bus, device_t child)<br> struct sdhci_fsl_fdt_softc= *sc;<br> <br> sc =3D device_get_softc(bu= s);<br> + /* No FDT write-protect GPIO (e.g. AC= PI front-end): use the std reg. */<br> + if (sc->gpio =3D=3D NULL)<br> + &n= bsp; return (sdhci_generic_get_ro(bus, child));<br> return (sdhci_fdt_gpio_get= _readonly(sc->gpio));<br> }<br> <br> @@ -803,8 +784,12 @@ sdhci_fsl_fdt_vddrange_to_mask(device_t dev, uint32_t = *vdd_ranges, int len)<br> return (vdd_mask);<br> }<br> <br> +/*<br> + * Apply the FDT "voltage-ranges" property over the capabilities= that<br> + * sdhci_fsl_attach_common() already read from hardware. FDT front-end onl= y.<br> + */<br> static void<br> -sdhci_fsl_fdt_of_parse(device_t dev)<br> +sdhci_fsl_fdt_voltage_fixup(device_t dev)<br> {<br> struct sdhci_fsl_fdt_softc= *sc;<br> phandle_t node;<br> @@ -815,16 +800,6 @@ sdhci_fsl_fdt_of_parse(device_t dev)<br> sc =3D device_get_softc(de= v);<br> node =3D ofw_bus_get_node(= dev);<br> <br> - /* Call mmc_fdt_parse in order to get= mmc related properties. */<br> - mmc_fdt_parse(dev, node, &sc->= fdt_helper, &sc->slot.host);<br> -<br> - sc->slot.quirks |=3D SDHCI_QUIRK_M= ISSING_CAPS;<br> - sc->slot.caps =3D sdhci_fsl_fdt_re= ad_4(dev, &sc->slot,<br> - SDHCI_CAPABIL= ITIES) & ~(SDHCI_CAN_DO_SUSPEND);<br> - sc->slot.caps2 =3D sdhci_fsl_fdt_r= ead_4(dev, &sc->slot,<br> - SDHCI_CAPABIL= ITIES2);<br> -<br> - /* Parse the "voltage-ranges&quo= t; dts property. */<br> num_ranges =3D OF_getencpr= op_alloc(node, "voltage-ranges",<br> (v= oid **) &voltage_ranges);<br> if (num_ranges <=3D 0)<= br> @@ -859,39 +834,37 @@ sdhci_fsl_poll_register(struct sdhci_fsl_fdt_softc *s= c,<br> return (0);<br> }<br> <br> -static int<br> -sdhci_fsl_fdt_attach(device_t dev)<br> +/*<br> + * Bus-agnostic attach. The bus front-end must have filled soc_data,<br> + * baseclk_hz, little_endian, acpi and the parsed mmc host properties<br> + * (slot.host) in the softc before calling this.<br> + */<br> +int<br> +sdhci_fsl_attach_common(device_t dev)<br> {<br> struct sdhci_fsl_fdt_softc= *sc;<br> struct mmc_host *host;<br> uint32_t val, buf_order;<b= r> - uintptr_t ocd_data;<br> - uint64_t clk_hz;<br> - phandle_t node;<br> int rid, ret;<br> - clk_t clk;<br> <br> - node =3D ofw_bus_get_node(dev);<br> sc =3D device_get_softc(de= v);<br> - ocd_data =3D ofw_bus_search_compatibl= e(dev,<br> - sdhci_fsl_fdt= _compat_data)->ocd_data;<br> sc->dev =3D dev;<br> sc->flags =3D 0;<br> host =3D &sc->slot.= host;<br> - rid =3D 0;<br> -<br> - /*<br> - * LX2160A needs its own soc_dat= a in order to apply SoC<br> - * specific quriks. Since the co= ntroller is identified<br> - * only with a generic compatibl= e string we need to do this dance here.<br> - */<br> - if (ofw_bus_node_is_compatible(OF_fin= ddevice("/"), "fsl,lx2160a"))<br> - &n= bsp; sc->soc_data =3D &sdhci_fsl_fdt_lx2160a_soc_data;<br> - else<br> - &n= bsp; sc->soc_data =3D (struct sdhci_fsl_fdt_soc_data *)ocd_data;<b= r> -<br> sc->slot.quirks =3D sc-= >soc_data->quirks;<br> <br> + /* eSDHC block endianness; chosen by = the bus front-end. */<br> + if (sc->little_endian) {<br> + &n= bsp; sc->read =3D read_le;<br> + &n= bsp; sc->write =3D write_le;<br> + &n= bsp; buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_NATIVE;<br> + } else {<br> + &n= bsp; sc->read =3D read_be;<br> + &n= bsp; sc->write =3D write_be;<br> + &n= bsp; buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_SWAP;<br> + }<br> +<br> + rid =3D 0;<br> sc->mem_res =3D bus_all= oc_resource_any(dev, SYS_RES_MEMORY, &rid,<br> RF= _ACTIVE);<br> if (sc->mem_res =3D=3D = NULL) {<br> @@ -917,36 +890,20 @@ sdhci_fsl_fdt_attach(device_t dev)<br> &nb= sp; goto err_free_irq_res;<br> }<br> <br> - ret =3D clk_get_by_ofw_index(dev, nod= e, 0, &clk);<br> - if (ret !=3D 0) {<br> - &n= bsp; device_printf(dev, "Parent clock not found\n");<br> - &n= bsp; goto err_free_irq;<br> - }<br> -<br> - ret =3D clk_get_freq(clk, &clk_hz= );<br> - if (ret !=3D 0) {<br> - &n= bsp; device_printf(dev,<br> - &n= bsp; "Could not get parent clock frequen= cy\n");<br> - &n= bsp; goto err_free_irq;<br> - }<br> -<br> - sc->baseclk_hz =3D clk_hz / sc->= ;soc_data->baseclk_div;<br> -<br> - /* Figure out eSDHC block endianness = before we touch any HW regs. */<br> - if (OF_hasprop(node, "little-end= ian")) {<br> - &n= bsp; sc->read =3D read_le;<br> - &n= bsp; sc->write =3D write_le;<br> - &n= bsp; buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_NATIVE;<br> - } else {<br> - &n= bsp; sc->read =3D read_be;<br> - &n= bsp; sc->write =3D write_be;<br> - &n= bsp; buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_SWAP;<br> - }<br> -<br> sc->vendor_ver =3D (RD4= (sc, SDHCI_FSL_HOST_VERSION) &<br> SD= HCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;<br> <br> - sdhci_fsl_fdt_of_parse(dev);<br> + /* Capabilities are missing from the = standard registers; read them. */<br> + sc->slot.quirks |=3D SDHCI_QUIRK_M= ISSING_CAPS;<br> + sc->slot.caps =3D sdhci_fsl_fdt_re= ad_4(dev, &sc->slot,<br> + SDHCI_CAPABIL= ITIES) & ~(SDHCI_CAN_DO_SUSPEND);<br> + sc->slot.caps2 =3D sdhci_fsl_fdt_r= ead_4(dev, &sc->slot,<br> + SDHCI_CAPABIL= ITIES2);<br> +<br> + /* FDT may override the voltage caps = via "voltage-ranges". */<br> + if (!sc->acpi)<br> + &n= bsp; sdhci_fsl_fdt_voltage_fixup(dev);<br> +<br> sc->maxclk_hz =3D host-= >f_max ? host->f_max : sc->baseclk_hz;<br> <br> /*<br> @@ -971,7 +928,10 @@ sdhci_fsl_fdt_attach(device_t dev)<br> val =3D RD4(sc, SDHCI_FSL_= ESDHC_CTRL);<br> WR4(sc, SDHCI_FSL_ESDHC_CT= RL, val | SDHCI_FSL_ESDHC_CTRL_CLK_DIV2);<br> sc->slot.max_clk =3D sc= ->maxclk_hz;<br> - sc->gpio =3D sdhci_fdt_gpio_setup(= dev, &sc->slot);<br> +<br> + /* GPIO card-detect is an FDT-only fa= cility. */<br> + if (!sc->acpi)<br> + &n= bsp; sc->gpio =3D sdhci_fdt_gpio_setup(dev, &sc->slot);<br> <br> /*<br> * Set the buffer wat= ermark level to 128 words (512 bytes) for both<br> @@ -992,6 +952,16 @@ sdhci_fsl_fdt_attach(device_t dev)<br> ret =3D sdhci_init_slot(de= v, &sc->slot, 0);<br> if (ret !=3D 0)<br> &nb= sp; goto err_free_gpio;<br> +<br> + /*<br> + * The eSDHC's SDHCI present-sta= te card-detect bits are unreliable; the<br> + * FDT path works around this wi= th a GPIO card-detect line, which is not<br> + * available under ACPI. Mark th= e slot non-removable so sdhci attaches<br> + * the mmc bus without waiting f= or a (never-stable) card-detect.<br> + */<br> + if (sc->acpi)<br> + &n= bsp; sc->slot.opt |=3D SDHCI_NON_REMOVABLE;<br> +<br> sc->slot_init_done =3D = true;<br> sdhci_start_slot(&sc-&= gt;slot);<br> <br> @@ -999,8 +969,8 @@ sdhci_fsl_fdt_attach(device_t dev)<br> return (0);<br> <br> err_free_gpio:<br> - sdhci_fdt_gpio_teardown(sc->gpio);= <br> -err_free_irq:<br> + if (sc->gpio !=3D NULL)<br> + &n= bsp; sdhci_fdt_gpio_teardown(sc->gpio);<br> bus_teardown_intr(dev, sc-= >irq_res, sc->irq_cookie);<br> err_free_irq_res:<br> bus_free_resource(dev, SYS= _RES_IRQ, sc->irq_res);<br> @@ -1010,7 +980,54 @@ sdhci_fsl_fdt_attach(device_t dev)<br> }<br> <br> static int<br> -sdhci_fsl_fdt_detach(device_t dev)<br> +sdhci_fsl_fdt_attach(device_t dev)<br> +{<br> + struct sdhci_fsl_fdt_softc *sc;<br> + uintptr_t ocd_data;<br> + uint64_t clk_hz;<br> + phandle_t node;<br> + clk_t clk;<br> + int ret;<br> +<br> + node =3D ofw_bus_get_node(dev);<br> + sc =3D device_get_softc(dev);<br> + ocd_data =3D ofw_bus_search_compatibl= e(dev,<br> + sdhci_fsl_fdt= _compat_data)->ocd_data;<br> +<br> + /*<br> + * LX2160A needs its own soc_dat= a in order to apply SoC<br> + * specific quriks. Since the co= ntroller is identified<br> + * only with a generic compatibl= e string we need to do this dance here.<br> + */<br> + if (ofw_bus_node_is_compatible(OF_fin= ddevice("/"), "fsl,lx2160a"))<br> + &n= bsp; sc->soc_data =3D &sdhci_fsl_fdt_lx2160a_soc_data;<br> + else<br> + &n= bsp; sc->soc_data =3D (const struct sdhci_fsl_fdt_soc_data *)ocd_d= ata;<br> +<br> + /* Parent (peripheral) clock comes fr= om the FDT clock framework. */<br> + ret =3D clk_get_by_ofw_index(dev, nod= e, 0, &clk);<br> + if (ret !=3D 0) {<br> + &n= bsp; device_printf(dev, "Parent clock not found\n");<br> + &n= bsp; return (ret);<br> + }<br> + ret =3D clk_get_freq(clk, &clk_hz= );<br> + if (ret !=3D 0) {<br> + &n= bsp; device_printf(dev, "Could not get parent clock frequency\n&= quot;);<br> + &n= bsp; return (ret);<br> + }<br> + sc->baseclk_hz =3D clk_hz / sc->= ;soc_data->baseclk_div;<br> +<br> + sc->little_endian =3D OF_hasprop(n= ode, "little-endian");<br> + sc->acpi =3D false;<br> +<br> + /* mmc host properties from the FDT n= ode. */<br> + mmc_fdt_parse(dev, node, &sc->= fdt_helper, &sc->slot.host);<br> +<br> + return (sdhci_fsl_attach_common(dev))= ;<br> +}<br> +<br> +int<br> +sdhci_fsl_detach(device_t dev)<br> {<br> struct sdhci_fsl_fdt_softc= *sc;<br> <br> @@ -1514,12 +1531,11 @@ sdhci_fsl_fdt_set_uhs_timing(device_t dev, struct s= dhci_slot *slot)<br> }<br> }<br> <br> -static const device_method_t sdhci_fsl_fdt_methods[] =3D {<br> - /* Device interface. */<br> - DEVMETHOD(device_probe, &n= bsp;  = ; sdhci_fsl_fdt_probe),<br> - DEVMETHOD(device_attach, &= nbsp; &nbs= p; sdhci_fsl_fdt_attach),<br> - DEVMETHOD(device_detach, &= nbsp; &nbs= p; sdhci_fsl_fdt_detach),<br> -<br> +/*<br> + * Bus-agnostic base class. The FDT and ACPI front-ends subclass this and<= br> + * override only device_probe/attach/detach (and, for ACPI, card-present).= <br> + */<br> +static const device_method_t sdhci_fsl_methods[] =3D {<br> /* Bus interface. */<br> DEVMETHOD(bus_read_ivar,&n= bsp;  = ; sdhci_fsl_fdt_read_ivar),<br> DEVMETHOD(bus_write_ivar,&= nbsp; &nbs= p; sdhci_fsl_fdt_write_ivar),<br> @@ -1549,12 +1565,29 @@ static const device_method_t sdhci_fsl_fdt_methods[= ] =3D {<br> DEVMETHOD_END<br> };<br> <br> -static driver_t sdhci_fsl_fdt_driver =3D {<br> - "sdhci_fsl_fdt",<br> - sdhci_fsl_fdt_methods,<br> - sizeof(struct sdhci_fsl_fdt_softc),<b= r> +DEFINE_CLASS_0(sdhci_fsl, sdhci_fsl_driver, sdhci_fsl_methods,<br> + sizeof(struct sdhci_fsl_fdt_softc));<br> +<br> +/*<br> + * Attach the mmc bus to the shared "sdhci_fsl" devclass (both t= he FDT and ACPI<br> + * subclasses create devices of this class). Without this the controller<b= r> + * attaches but the mmc bridge never does, so no card enumerates.<br> + */<br> +#ifndef MMCCAM<br> +MMC_DECLARE_BRIDGE(sdhci_fsl);<br> +#endif<br> +<br> +/* FDT front-end. */<br> +static const device_method_t sdhci_fsl_fdt_methods[] =3D {<br> + DEVMETHOD(device_probe, &n= bsp;  = ; sdhci_fsl_fdt_probe),<br> + DEVMETHOD(device_attach, &= nbsp; &nbs= p; sdhci_fsl_fdt_attach),<br> + DEVMETHOD(device_detach, &= nbsp; &nbs= p; sdhci_fsl_detach),<br> + DEVMETHOD_END<br> };<br> <br> +DEFINE_CLASS_1(sdhci_fsl, sdhci_fsl_fdt_driver, sdhci_fsl_fdt_methods,<br> + sizeof(struct sdhci_fsl_fdt_softc), sdhci_fsl_driver);<= br> +<br> DRIVER_MODULE(sdhci_fsl_fdt, simplebus, sdhci_fsl_fdt_driver, NULL, N= ULL);<br> SDHCI_DEPEND(sdhci_fsl_fdt);<br> <br> -- <br> 2.39.3 (Apple Git-146)<br> <br> <br> </div> </span></font></div> </body> </html> --_000_SN7PR20MB6186520D792017F3EE287A8EECFD2SN7PR20MB6186namp_--