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 &lt;[email protected]&gt; on behalf of yarshure &lt;ya=
[email protected]&gt;<br>
<b>Sent:</b> Thursday, July 9, 2026 7:22 PM<br>
<b>To:</b> [email protected] &lt;[email protected]&gt;<br>
<b>Cc:</b> [email protected] &lt;[email protected]&gt;<br>
<b>Subject:</b> [PATCH] sdhci_fsl: add ACPI front-end for NXP Layerscape eS=
DHC (NXP0003)</font>
<div>&nbsp;</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 &quot;sdhci_fsl&quot;) 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 &quot;clock-frequency&quot; 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>
&nbsp; sdhci_fsl_attach_common(); base class + FDT subclass; declare the mm=
c<br>
&nbsp; bridge on the shared &quot;sdhci_fsl&quot; devclass; guard get_ro fo=
r the<br>
&nbsp; no-GPIO (ACPI) case.<br>
- sdhci_fsl_acpi.c: NXP0003 ACPI binding; base clock from _DSD; generic<br>
&nbsp; card-present; mark the slot non-removable (eSDHC present-state card<=
br>
&nbsp; detect is unreliable); cap to high speed pending UHS tuning support.=
<br>
<br>
MFC after:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 weeks<br>
Signed-off-by: yarshure &lt;[email protected]&gt;<br>
---<br>
Notes for review (not part of the commit message):<br>
<br>
* Verification.&nbsp; Hardware-tested on a SolidRun HoneyComb / CEX7 (LX216=
0A)<br>
&nbsp; booting via EDK2/UEFI (ACPI).&nbsp; Before this change nothing match=
ed _HID<br>
&nbsp; NXP0003, so the eSDHC controllers were unattached; after it both slo=
ts<br>
&nbsp; probe and come up:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmc0: &lt;MMC/SD bus&gt; ... on sdhci_fsl_ac=
pi0<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmcsd0: &lt;MMCHC ...&gt; ... (SD/TF card)<b=
r>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmc1: &lt;MMC/SD bus&gt; ... on sdhci_fsl_ac=
pi1<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmcsd1: &lt;MMCHC ...&gt; ... (eMMC)<br>
<br>
&nbsp; /dev/mmcsd0 and /dev/mmcsd1 read and write correctly.<br>
<br>
* The FDT path is preserved unchanged -- the refactor only splits the<br>
&nbsp; existing sdhci_fsl_attach() into an FDT prologue plus a bus-agnostic=
<br>
&nbsp; sdhci_fsl_attach_common(), mirroring sdhci_xenon's base/FDT/ACPI spl=
it,<br>
&nbsp; so existing FDT (device-tree) boots behave exactly as before.&nbsp; =
It has<br>
&nbsp; 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>
&nbsp; _DSD &quot;clock-frequency&quot; property (no FDT clock framework un=
der ACPI), and<br>
&nbsp; the slot is marked non-removable + capped to high speed (eSDHC<br>
&nbsp; present-state card detect is unreliable; UHS tuning is future work).=
<br>
<br>
* Disclosure: developed with AI assistance; the hardware bring-up above<br>
&nbsp; was done by hand.<br>
<br>
&nbsp;sys/conf/files&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; 1 +<br>
&nbsp;sys/dev/sdhci/sdhci_fsl.h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |&nbsp; 61 ++=
+++++++<br>
&nbsp;sys/dev/sdhci/sdhci_fsl_acpi.c | 124 +++++++++++++++++<br>
&nbsp;sys/dev/sdhci/sdhci_fsl_fdt.c&nbsp; | 237 +++++++++++++++++++--------=
------<br>
&nbsp;4 files changed, 321 insertions(+), 102 deletions(-)<br>
&nbsp;create mode 100644 sys/dev/sdhci/sdhci_fsl.h<br>
&nbsp;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&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp; optional sdhci<br>
&nbsp;dev/sdhci/sdhci_fdt.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp; optional sdhci fdt regulator clk<br>
&nbsp;dev/sdhci/sdhci_fdt_gpio.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; optional sdh=
ci fdt gpio<br>
&nbsp;dev/sdhci/sdhci_fsl_fdt.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; optiona=
l sdhci fdt gpio regulator clk<br>
+dev/sdhci/sdhci_fsl_acpi.c&nbsp;&nbsp;&nbsp;&nbsp; optional sdhci fdt gpio=
 regulator clk acpi<br>
&nbsp;dev/sdhci/sdhci_if.m&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp; optional sdhci<br>
&nbsp;dev/sdhci/sdhci_acpi.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; optional sdhci acpi<br>
&nbsp;dev/sdhci/sdhci_pci.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp; 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 &lt;dev/mmc/mmc_helpers.h&gt;<br>
+#include &lt;dev/sdhci/sdhci.h&gt;<br>
+<br>
+struct sdhci_fdt_gpio;<br>
+<br>
+struct sdhci_fsl_fdt_soc_data {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int quirks;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int baseclk_div;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t errata;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; device_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; dev;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const struct sdhci_fsl_fdt_soc_data&n=
bsp;&nbsp;&nbsp;&nbsp; *soc_data;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct resource&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *mem_res;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct resource&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *irq_res;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp; *irq_cookie;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; baseclk_hz;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; maxclk_hz;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_fdt_gpio&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp; *gpio;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_slot&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp; slot_init_done;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; cmd_and_mode;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; sdclk_bits;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct mmc_helper&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fdt_helper;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; div_ratio;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp; vendor_ver;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; flags;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Set by the bus front-end before ca=
lling sdhci_fsl_attach_common(). */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp; little_endian;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp; acpi;&nbsp;&nbsp; /* ACPI front-end (no FDT nod=
e) */<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t (* read)(struct sdhci_fsl_fd=
t_softc *, bus_size_t);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 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&nbsp;&nbsp;&nbsp; sdhci_fsl_attach_common(device_t dev);<br>
+int&nbsp;&nbsp;&nbsp; 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 &lt;sys/param.h&gt;<br>
+#include &lt;sys/bus.h&gt;<br>
+#include &lt;sys/kernel.h&gt;<br>
+#include &lt;sys/module.h&gt;<br>
+#include &lt;sys/rman.h&gt;<br>
+#include &lt;sys/taskqueue.h&gt;<br>
+<br>
+#include &lt;machine/bus.h&gt;<br>
+#include &lt;machine/resource.h&gt;<br>
+<br>
+#include &lt;dev/mmc/bridge.h&gt;<br>
+#include &lt;dev/mmc/mmcbrvar.h&gt;<br>
+#include &lt;dev/mmc/mmc_helpers.h&gt;<br>
+<br>
+#include &lt;contrib/dev/acpica/include/acpi.h&gt;<br>
+#include &lt;contrib/dev/acpica/include/accommon.h&gt;<br>
+#include &lt;dev/acpica/acpivar.h&gt;<br>
+<br>
+#include &lt;dev/sdhci/sdhci.h&gt;<br>
+#include &lt;dev/sdhci/sdhci_fsl.h&gt;<br>
+<br>
+#include &quot;mmcbr_if.h&quot;<br>
+#include &quot;sdhci_if.h&quot;<br>
+<br>
+#include &quot;opt_mmccam.h&quot;<br>
+<br>
+static char *sdhci_fsl_acpi_hids[] =3D {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;NXP0003&quot;,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL<br>
+};<br>
+<br>
+static int<br>
+sdhci_fsl_acpi_probe(device_t dev)<br>
+{<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int err;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err =3D ACPI_ID_PROBE(device_get_pare=
nt(dev), dev, sdhci_fsl_acpi_hids,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NULL);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (err &lt;=3D 0) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; device_set_desc(dev,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;NXP QorIQ Layerscape eSDHC control=
ler&quot;);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; return (err);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (ENXIO);<br>
+}<br>
+<br>
+static int<br>
+sdhci_fsl_acpi_attach(device_t dev)<br>
+{<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_fsl_fdt_softc *sc;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct mmc_helper mmc_helper;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t clk_hz;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc =3D device_get_softc(dev);<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * NXP0003 identifies the LX2160=
A-class eSDHC; use its SoC data for the<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * quirks/errata and the base-cl=
ock divider.<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;soc_data =3D &amp;sdhci_fsl_fd=
t_lx2160a_soc_data;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;acpi =3D true;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;little_endian =3D true;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* _DSD &quot;little-endian&quot;; LX2160A eS=
DHC */<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Base (peripheral) clock from the _=
DSD &quot;clock-frequency&quot; property. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clk_hz =3D 0;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (device_get_property(dev, &quot;cl=
ock-frequency&quot;, &amp;clk_hz, sizeof(clk_hz),<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVICE_PROP_U=
INT32) &lt;=3D 0 || clk_hz =3D=3D 0) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; device_printf(dev, &quot;missing 'clock-frequency' property\n&qu=
ot;);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; return (ENXIO);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;baseclk_hz =3D clk_hz / sc-&gt=
;soc_data-&gt;baseclk_div;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* mmc host properties (bus-width, ma=
x-frequency, ...) from _DSD. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memset(&amp;mmc_helper, 0, sizeof(mmc=
_helper));<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (mmc_parse(dev, &amp;mmc_helper, &=
amp;sc-&gt;slot.host) !=3D 0)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; return (ENXIO);<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Cap to high speed (25 MHz). U=
HS modes (SDR50/SDR104) require a tuning<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * sequence with voltage switchi=
ng that is not yet wired up on the ACPI<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * front-end, so restrict to a n=
on-tuned speed for reliable enumeration.<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sc-&gt;slot.host.f_max &gt; 25000=
000)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;slot.host.f_max =3D 25000000;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (sdhci_fsl_attach_common(dev))=
;<br>
+}<br>
+<br>
+static const device_method_t sdhci_fsl_acpi_methods[] =3D {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_probe,&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; sdhci_fsl_acpi_probe),<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_attach,&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; sdhci_fsl_acpi_attach),<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_detach,&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; sdhci_fsl_detach),<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * No FDT GPIO line under ACPI; =
use the controller's own card-detect<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (present-state register) inst=
ead.<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(sdhci_get_card_present,&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sdhci_generic_get_card_present),<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD_END<br>
+};<br>
+<br>
+DEFINE_CLASS_1(sdhci_fsl, sdhci_fsl_acpi_driver, sdhci_fsl_acpi_methods,<b=
r>
+&nbsp;&nbsp;&nbsp; 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>
&nbsp;#include &lt;dev/ofw/ofw_bus_subr.h&gt;<br>
&nbsp;#include &lt;dev/sdhci/sdhci.h&gt;<br>
&nbsp;#include &lt;dev/sdhci/sdhci_fdt_gpio.h&gt;<br>
+#include &lt;dev/sdhci/sdhci_fsl.h&gt;<br>
&nbsp;<br>
&nbsp;#include &quot;mmcbr_if.h&quot;<br>
&nbsp;#include &quot;sdhci_if.h&quot;<br>
@@ -183,34 +184,10 @@<br>
&nbsp;<br>
&nbsp;#define SDHCI_FSL_MAX_RETRIES&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp; 20000&nbsp;&nbsp; /* DELAY(10) * this =3D 200ms */<br>
&nbsp;<br>
-struct sdhci_fsl_fdt_softc {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; device_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; dev;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; const struct sdhci_fsl_fdt_soc_data&n=
bsp;&nbsp;&nbsp;&nbsp; *soc_data;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct resource&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *mem_res;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct resource&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *irq_res;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp; *irq_cookie;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; baseclk_hz;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; maxclk_hz;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_fdt_gpio&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp; *gpio;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_slot&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; slot;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bool&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp; slot_init_done;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; cmd_and_mode;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint16_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; sdclk_bits;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct mmc_helper&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fdt_helper;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; div_ratio;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=
&nbsp;&nbsp; vendor_ver;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; flags;<br>
-<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t (* read)(struct sdhci_fsl_fd=
t_softc *, bus_size_t);<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void (* write)(struct sdhci_fsl_fdt_s=
oftc *, bus_size_t, uint32_t);<br>
-};<br>
-<br>
-struct sdhci_fsl_fdt_soc_data {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int quirks;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int baseclk_div;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint8_t errata;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *syscon_compat;<br>
-};<br>
+/*<br>
+ * struct sdhci_fsl_fdt_softc and struct sdhci_fsl_fdt_soc_data now live i=
n<br>
+ * &lt;dev/sdhci/sdhci_fsl.h&gt; so they can be shared with the ACPI front=
-end.<br>
+ */<br>
&nbsp;<br>
&nbsp;static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_ls1012a_soc_=
data =3D {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .syscon_compat =3D &quot;f=
sl,ls1046a-scfg&quot;,<br>
&nbsp;};<br>
&nbsp;<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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .quirks =3D 0,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .baseclk_div =3D 2,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_fsl_fdt_softc=
 *sc;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc =3D device_get_softc(bu=
s);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* No FDT write-protect GPIO (e.g. AC=
PI front-end): use the std reg. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sc-&gt;gpio =3D=3D NULL)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; return (sdhci_generic_get_ro(bus, child));<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (sdhci_fdt_gpio_get=
_readonly(sc-&gt;gpio));<br>
&nbsp;}<br>
&nbsp;<br>
@@ -803,8 +784,12 @@ sdhci_fsl_fdt_vddrange_to_mask(device_t dev, uint32_t =
*vdd_ranges, int len)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (vdd_mask);<br>
&nbsp;}<br>
&nbsp;<br>
+/*<br>
+ * Apply the FDT &quot;voltage-ranges&quot; property over the capabilities=
 that<br>
+ * sdhci_fsl_attach_common() already read from hardware. FDT front-end onl=
y.<br>
+ */<br>
&nbsp;static void<br>
-sdhci_fsl_fdt_of_parse(device_t dev)<br>
+sdhci_fsl_fdt_voltage_fixup(device_t dev)<br>
&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_fsl_fdt_softc=
 *sc;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phandle_t node;<br>
@@ -815,16 +800,6 @@ sdhci_fsl_fdt_of_parse(device_t dev)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc =3D device_get_softc(de=
v);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node =3D ofw_bus_get_node(=
dev);<br>
&nbsp;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Call mmc_fdt_parse in order to get=
 mmc related properties. */<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmc_fdt_parse(dev, node, &amp;sc-&gt;=
fdt_helper, &amp;sc-&gt;slot.host);<br>
-<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot.quirks |=3D SDHCI_QUIRK_M=
ISSING_CAPS;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot.caps =3D sdhci_fsl_fdt_re=
ad_4(dev, &amp;sc-&gt;slot,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SDHCI_CAPABIL=
ITIES) &amp; ~(SDHCI_CAN_DO_SUSPEND);<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot.caps2 =3D sdhci_fsl_fdt_r=
ead_4(dev, &amp;sc-&gt;slot,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SDHCI_CAPABIL=
ITIES2);<br>
-<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Parse the &quot;voltage-ranges&quo=
t; dts property. */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; num_ranges =3D OF_getencpr=
op_alloc(node, &quot;voltage-ranges&quot;,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (v=
oid **) &amp;voltage_ranges);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (num_ranges &lt;=3D 0)<=
br>
@@ -859,39 +834,37 @@ sdhci_fsl_poll_register(struct sdhci_fsl_fdt_softc *s=
c,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (0);<br>
&nbsp;}<br>
&nbsp;<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>
&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_fsl_fdt_softc=
 *sc;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct mmc_host *host;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint32_t val, buf_order;<b=
r>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uintptr_t ocd_data;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t clk_hz;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phandle_t node;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int rid, ret;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clk_t clk;<br>
&nbsp;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node =3D ofw_bus_get_node(dev);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc =3D device_get_softc(de=
v);<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ocd_data =3D ofw_bus_search_compatibl=
e(dev,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sdhci_fsl_fdt=
_compat_data)-&gt;ocd_data;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;dev =3D dev;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;flags =3D 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; host =3D &amp;sc-&gt;slot.=
host;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rid =3D 0;<br>
-<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * LX2160A needs its own soc_dat=
a in order to apply SoC<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * specific quriks. Since the co=
ntroller is identified<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * only with a generic compatibl=
e string we need to do this dance here.<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ofw_bus_node_is_compatible(OF_fin=
ddevice(&quot;/&quot;), &quot;fsl,lx2160a&quot;))<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;soc_data =3D &amp;sdhci_fsl_fdt_lx2160a_soc_data;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;soc_data =3D (struct sdhci_fsl_fdt_soc_data *)ocd_data;<b=
r>
-<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot.quirks =3D sc-=
&gt;soc_data-&gt;quirks;<br>
&nbsp;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* eSDHC block endianness; chosen by =
the bus front-end. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sc-&gt;little_endian) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;read =3D read_le;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;write =3D write_le;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_NATIVE;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;read =3D read_be;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;write =3D write_be;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_SWAP;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rid =3D 0;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;mem_res =3D bus_all=
oc_resource_any(dev, SYS_RES_MEMORY, &amp;rid,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RF=
_ACTIVE);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sc-&gt;mem_res =3D=3D =
NULL) {<br>
@@ -917,36 +890,20 @@ sdhci_fsl_fdt_attach(device_t dev)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp; goto err_free_irq_res;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret =3D clk_get_by_ofw_index(dev, nod=
e, 0, &amp;clk);<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret !=3D 0) {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; device_printf(dev, &quot;Parent clock not found\n&quot;);<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; goto err_free_irq;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
-<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret =3D clk_get_freq(clk, &amp;clk_hz=
);<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret !=3D 0) {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; device_printf(dev,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;Could not get parent clock frequen=
cy\n&quot;);<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; goto err_free_irq;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
-<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;baseclk_hz =3D clk_hz / sc-&gt=
;soc_data-&gt;baseclk_div;<br>
-<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Figure out eSDHC block endianness =
before we touch any HW regs. */<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (OF_hasprop(node, &quot;little-end=
ian&quot;)) {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;read =3D read_le;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;write =3D write_le;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_NATIVE;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;read =3D read_be;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;write =3D write_be;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; buf_order =3D SDHCI_FSL_PROT_CTRL_BYTE_SWAP;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
-<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;vendor_ver =3D (RD4=
(sc, SDHCI_FSL_HOST_VERSION) &amp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SD=
HCI_VENDOR_VER_MASK) &gt;&gt; SDHCI_VENDOR_VER_SHIFT;<br>
&nbsp;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sdhci_fsl_fdt_of_parse(dev);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Capabilities are missing from the =
standard registers; read them. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot.quirks |=3D SDHCI_QUIRK_M=
ISSING_CAPS;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot.caps =3D sdhci_fsl_fdt_re=
ad_4(dev, &amp;sc-&gt;slot,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SDHCI_CAPABIL=
ITIES) &amp; ~(SDHCI_CAN_DO_SUSPEND);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot.caps2 =3D sdhci_fsl_fdt_r=
ead_4(dev, &amp;sc-&gt;slot,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SDHCI_CAPABIL=
ITIES2);<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* FDT may override the voltage caps =
via &quot;voltage-ranges&quot;. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!sc-&gt;acpi)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sdhci_fsl_fdt_voltage_fixup(dev);<br>
+<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;maxclk_hz =3D host-=
&gt;f_max ? host-&gt;f_max : sc-&gt;baseclk_hz;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
@@ -971,7 +928,10 @@ sdhci_fsl_fdt_attach(device_t dev)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; val =3D RD4(sc, SDHCI_FSL_=
ESDHC_CTRL);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WR4(sc, SDHCI_FSL_ESDHC_CT=
RL, val | SDHCI_FSL_ESDHC_CTRL_CLK_DIV2);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot.max_clk =3D sc=
-&gt;maxclk_hz;<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;gpio =3D sdhci_fdt_gpio_setup(=
dev, &amp;sc-&gt;slot);<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* GPIO card-detect is an FDT-only fa=
cility. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!sc-&gt;acpi)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;gpio =3D sdhci_fdt_gpio_setup(dev, &amp;sc-&gt;slot);<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret =3D sdhci_init_slot(de=
v, &amp;sc-&gt;slot, 0);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret !=3D 0)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nb=
sp;&nbsp;&nbsp;&nbsp; goto err_free_gpio;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * The eSDHC's SDHCI present-sta=
te card-detect bits are unreliable; the<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * FDT path works around this wi=
th a GPIO card-detect line, which is not<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * available under ACPI. Mark th=
e slot non-removable so sdhci attaches<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * the mmc bus without waiting f=
or a (never-stable) card-detect.<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sc-&gt;acpi)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;slot.opt |=3D SDHCI_NON_REMOVABLE;<br>
+<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;slot_init_done =3D =
true;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sdhci_start_slot(&amp;sc-&=
gt;slot);<br>
&nbsp;<br>
@@ -999,8 +969,8 @@ sdhci_fsl_fdt_attach(device_t dev)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (0);<br>
&nbsp;<br>
&nbsp;err_free_gpio:<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sdhci_fdt_gpio_teardown(sc-&gt;gpio);=
<br>
-err_free_irq:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (sc-&gt;gpio !=3D NULL)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sdhci_fdt_gpio_teardown(sc-&gt;gpio);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bus_teardown_intr(dev, sc-=
&gt;irq_res, sc-&gt;irq_cookie);<br>
&nbsp;err_free_irq_res:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bus_free_resource(dev, SYS=
_RES_IRQ, sc-&gt;irq_res);<br>
@@ -1010,7 +980,54 @@ sdhci_fsl_fdt_attach(device_t dev)<br>
&nbsp;}<br>
&nbsp;<br>
&nbsp;static int<br>
-sdhci_fsl_fdt_detach(device_t dev)<br>
+sdhci_fsl_fdt_attach(device_t dev)<br>
+{<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_fsl_fdt_softc *sc;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uintptr_t ocd_data;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; uint64_t clk_hz;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; phandle_t node;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; clk_t clk;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node =3D ofw_bus_get_node(dev);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc =3D device_get_softc(dev);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ocd_data =3D ofw_bus_search_compatibl=
e(dev,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sdhci_fsl_fdt=
_compat_data)-&gt;ocd_data;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * LX2160A needs its own soc_dat=
a in order to apply SoC<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * specific quriks. Since the co=
ntroller is identified<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * only with a generic compatibl=
e string we need to do this dance here.<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ofw_bus_node_is_compatible(OF_fin=
ddevice(&quot;/&quot;), &quot;fsl,lx2160a&quot;))<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;soc_data =3D &amp;sdhci_fsl_fdt_lx2160a_soc_data;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; sc-&gt;soc_data =3D (const struct sdhci_fsl_fdt_soc_data *)ocd_d=
ata;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Parent (peripheral) clock comes fr=
om the FDT clock framework. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret =3D clk_get_by_ofw_index(dev, nod=
e, 0, &amp;clk);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret !=3D 0) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; device_printf(dev, &quot;Parent clock not found\n&quot;);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; return (ret);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret =3D clk_get_freq(clk, &amp;clk_hz=
);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ret !=3D 0) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; device_printf(dev, &quot;Could not get parent clock frequency\n&=
quot;);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n=
bsp;&nbsp; return (ret);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;baseclk_hz =3D clk_hz / sc-&gt=
;soc_data-&gt;baseclk_div;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;little_endian =3D OF_hasprop(n=
ode, &quot;little-endian&quot;);<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sc-&gt;acpi =3D false;<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* mmc host properties from the FDT n=
ode. */<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mmc_fdt_parse(dev, node, &amp;sc-&gt;=
fdt_helper, &amp;sc-&gt;slot.host);<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (sdhci_fsl_attach_common(dev))=
;<br>
+}<br>
+<br>
+int<br>
+sdhci_fsl_detach(device_t dev)<br>
&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct sdhci_fsl_fdt_softc=
 *sc;<br>
&nbsp;<br>
@@ -1514,12 +1531,11 @@ sdhci_fsl_fdt_set_uhs_timing(device_t dev, struct s=
dhci_slot *slot)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&nbsp;}<br>
&nbsp;<br>
-static const device_method_t sdhci_fsl_fdt_methods[] =3D {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Device interface. */<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_probe,&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; sdhci_fsl_fdt_probe),<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_attach,&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; sdhci_fsl_fdt_attach),<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_detach,&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Bus interface. */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(bus_read_ivar,&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp; sdhci_fsl_fdt_read_ivar),<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(bus_write_ivar,&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp; sdhci_fsl_fdt_write_ivar),<br>
@@ -1549,12 +1565,29 @@ static const device_method_t sdhci_fsl_fdt_methods[=
] =3D {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD_END<br>
&nbsp;};<br>
&nbsp;<br>
-static driver_t sdhci_fsl_fdt_driver =3D {<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;sdhci_fsl_fdt&quot;,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sdhci_fsl_fdt_methods,<br>
-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sizeof(struct sdhci_fsl_fdt_softc),<b=
r>
+DEFINE_CLASS_0(sdhci_fsl, sdhci_fsl_driver, sdhci_fsl_methods,<br>
+&nbsp;&nbsp;&nbsp; sizeof(struct sdhci_fsl_fdt_softc));<br>
+<br>
+/*<br>
+ * Attach the mmc bus to the shared &quot;sdhci_fsl&quot; 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>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_probe,&nbsp;&nbsp;&n=
bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp; sdhci_fsl_fdt_probe),<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_attach,&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; sdhci_fsl_fdt_attach),<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD(device_detach,&nbsp;&nbsp;&=
nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p; sdhci_fsl_detach),<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DEVMETHOD_END<br>
&nbsp;};<br>
&nbsp;<br>
+DEFINE_CLASS_1(sdhci_fsl, sdhci_fsl_fdt_driver, sdhci_fsl_fdt_methods,<br>
+&nbsp;&nbsp;&nbsp; sizeof(struct sdhci_fsl_fdt_softc), sdhci_fsl_driver);<=
br>
+<br>
&nbsp;DRIVER_MODULE(sdhci_fsl_fdt, simplebus, sdhci_fsl_fdt_driver, NULL, N=
ULL);<br>
&nbsp;SDHCI_DEPEND(sdhci_fsl_fdt);<br>
&nbsp;<br>
-- <br>
2.39.3 (Apple Git-146)<br>
<br>
<br>
</div>
</span></font></div>
</body>
</html>

--_000_SN7PR20MB6186520D792017F3EE287A8EECFD2SN7PR20MB6186namp_--