Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F174604054
D58259.id182067.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D58259.id182067.diff
View Options
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3138,6 +3138,7 @@
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
Index: sys/dev/sdhci/sdhci_fsl.h
===================================================================
--- /dev/null
+++ 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-ends.
+ */
+
+#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_endian,
+ * 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_ */
Index: sys/dev/sdhci/sdhci_fsl_acpi.c
===================================================================
--- /dev/null
+++ 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 NXP0003).
+ *
+ * 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 shared
+ * sdhci_fsl_attach_common(), letting the OS access the SD/TF card (e.g. to
+ * 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[] = {
+ "NXP0003",
+ NULL
+};
+
+static int
+sdhci_fsl_acpi_probe(device_t dev)
+{
+ int err;
+
+ err = ACPI_ID_PROBE(device_get_parent(dev), dev, sdhci_fsl_acpi_hids,
+ NULL);
+ if (err <= 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 = 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 = &sdhci_fsl_fdt_lx2160a_soc_data;
+ sc->acpi = true;
+ sc->little_endian = true; /* _DSD "little-endian"; LX2160A eSDHC */
+
+ /* Base (peripheral) clock from the _DSD "clock-frequency" property. */
+ clk_hz = 0;
+ if (device_get_property(dev, "clock-frequency", &clk_hz, sizeof(clk_hz),
+ DEVICE_PROP_UINT32) <= 0 || clk_hz == 0) {
+ device_printf(dev, "missing 'clock-frequency' property\n");
+ return (ENXIO);
+ }
+ sc->baseclk_hz = 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) != 0)
+ return (ENXIO);
+
+ /*
+ * Cap to high speed (25 MHz). UHS modes (SDR50/SDR104) require a tuning
+ * sequence with voltage switching that is not yet wired up on the ACPI
+ * front-end, so restrict to a non-tuned speed for reliable enumeration.
+ */
+ if (sc->slot.host.f_max > 25000000)
+ sc->slot.host.f_max = 25000000;
+
+ return (sdhci_fsl_attach_common(dev));
+}
+
+static const device_method_t sdhci_fsl_acpi_methods[] = {
+ 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-detect
+ * (present-state register) instead.
+ */
+ DEVMETHOD(sdhci_get_card_present, sdhci_generic_get_card_present),
+
+ 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
Index: sys/dev/sdhci/sdhci_fsl_fdt.c
===================================================================
--- sys/dev/sdhci/sdhci_fsl_fdt.c
+++ 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 = 200ms */
-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 in
+ * <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 = {
.quirks = 0,
@@ -234,7 +211,8 @@
.syscon_compat = "fsl,ls1046a-scfg",
};
-static const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_lx2160a_soc_data = {
+/* Shared with the ACPI front-end (declared in sdhci_fsl.h). */
+const struct sdhci_fsl_fdt_soc_data sdhci_fsl_fdt_lx2160a_soc_data = {
.quirks = 0,
.baseclk_div = 2,
.errata = SDHCI_FSL_UNRELIABLE_PULSE_DET |
@@ -755,6 +733,9 @@
struct sdhci_fsl_fdt_softc *sc;
sc = device_get_softc(bus);
+ /* No FDT write-protect GPIO (e.g. ACPI front-end): use the std reg. */
+ if (sc->gpio == NULL)
+ return (sdhci_generic_get_ro(bus, child));
return (sdhci_fdt_gpio_get_readonly(sc->gpio));
}
@@ -803,8 +784,12 @@
return (vdd_mask);
}
+/*
+ * Apply the FDT "voltage-ranges" property over the capabilities that
+ * sdhci_fsl_attach_common() already read from hardware. FDT front-end only.
+ */
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 @@
sc = device_get_softc(dev);
node = 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 |= SDHCI_QUIRK_MISSING_CAPS;
- sc->slot.caps = sdhci_fsl_fdt_read_4(dev, &sc->slot,
- SDHCI_CAPABILITIES) & ~(SDHCI_CAN_DO_SUSPEND);
- sc->slot.caps2 = sdhci_fsl_fdt_read_4(dev, &sc->slot,
- SDHCI_CAPABILITIES2);
-
- /* Parse the "voltage-ranges" dts property. */
num_ranges = OF_getencprop_alloc(node, "voltage-ranges",
(void **) &voltage_ranges);
if (num_ranges <= 0)
@@ -859,39 +834,37 @@
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 = ofw_bus_get_node(dev);
sc = device_get_softc(dev);
- ocd_data = ofw_bus_search_compatible(dev,
- sdhci_fsl_fdt_compat_data)->ocd_data;
sc->dev = dev;
sc->flags = 0;
host = &sc->slot.host;
- rid = 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 here.
- */
- if (ofw_bus_node_is_compatible(OF_finddevice("/"), "fsl,lx2160a"))
- sc->soc_data = &sdhci_fsl_fdt_lx2160a_soc_data;
- else
- sc->soc_data = (struct sdhci_fsl_fdt_soc_data *)ocd_data;
-
sc->slot.quirks = sc->soc_data->quirks;
+ /* eSDHC block endianness; chosen by the bus front-end. */
+ if (sc->little_endian) {
+ sc->read = read_le;
+ sc->write = write_le;
+ buf_order = SDHCI_FSL_PROT_CTRL_BYTE_NATIVE;
+ } else {
+ sc->read = read_be;
+ sc->write = write_be;
+ buf_order = SDHCI_FSL_PROT_CTRL_BYTE_SWAP;
+ }
+
+ rid = 0;
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (sc->mem_res == NULL) {
@@ -917,36 +890,20 @@
goto err_free_irq_res;
}
- ret = clk_get_by_ofw_index(dev, node, 0, &clk);
- if (ret != 0) {
- device_printf(dev, "Parent clock not found\n");
- goto err_free_irq;
- }
-
- ret = clk_get_freq(clk, &clk_hz);
- if (ret != 0) {
- device_printf(dev,
- "Could not get parent clock frequency\n");
- goto err_free_irq;
- }
-
- sc->baseclk_hz = 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 = read_le;
- sc->write = write_le;
- buf_order = SDHCI_FSL_PROT_CTRL_BYTE_NATIVE;
- } else {
- sc->read = read_be;
- sc->write = write_be;
- buf_order = SDHCI_FSL_PROT_CTRL_BYTE_SWAP;
- }
-
sc->vendor_ver = (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 |= SDHCI_QUIRK_MISSING_CAPS;
+ sc->slot.caps = sdhci_fsl_fdt_read_4(dev, &sc->slot,
+ SDHCI_CAPABILITIES) & ~(SDHCI_CAN_DO_SUSPEND);
+ sc->slot.caps2 = 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 = host->f_max ? host->f_max : sc->baseclk_hz;
/*
@@ -971,7 +928,10 @@
val = RD4(sc, SDHCI_FSL_ESDHC_CTRL);
WR4(sc, SDHCI_FSL_ESDHC_CTRL, val | SDHCI_FSL_ESDHC_CTRL_CLK_DIV2);
sc->slot.max_clk = sc->maxclk_hz;
- sc->gpio = sdhci_fdt_gpio_setup(dev, &sc->slot);
+
+ /* GPIO card-detect is an FDT-only facility. */
+ if (!sc->acpi)
+ sc->gpio = sdhci_fdt_gpio_setup(dev, &sc->slot);
/*
* Set the buffer watermark level to 128 words (512 bytes) for both
@@ -992,6 +952,16 @@
ret = sdhci_init_slot(dev, &sc->slot, 0);
if (ret != 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 is not
+ * available under ACPI. Mark the slot non-removable so sdhci attaches
+ * the mmc bus without waiting for a (never-stable) card-detect.
+ */
+ if (sc->acpi)
+ sc->slot.opt |= SDHCI_NON_REMOVABLE;
+
sc->slot_init_done = true;
sdhci_start_slot(&sc->slot);
@@ -999,8 +969,8 @@
return (0);
err_free_gpio:
- sdhci_fdt_gpio_teardown(sc->gpio);
-err_free_irq:
+ if (sc->gpio != 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 @@
}
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 = ofw_bus_get_node(dev);
+ sc = device_get_softc(dev);
+ ocd_data = 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 here.
+ */
+ if (ofw_bus_node_is_compatible(OF_finddevice("/"), "fsl,lx2160a"))
+ sc->soc_data = &sdhci_fsl_fdt_lx2160a_soc_data;
+ else
+ sc->soc_data = (const struct sdhci_fsl_fdt_soc_data *)ocd_data;
+
+ /* Parent (peripheral) clock comes from the FDT clock framework. */
+ ret = clk_get_by_ofw_index(dev, node, 0, &clk);
+ if (ret != 0) {
+ device_printf(dev, "Parent clock not found\n");
+ return (ret);
+ }
+ ret = clk_get_freq(clk, &clk_hz);
+ if (ret != 0) {
+ device_printf(dev, "Could not get parent clock frequency\n");
+ return (ret);
+ }
+ sc->baseclk_hz = clk_hz / sc->soc_data->baseclk_div;
+
+ sc->little_endian = OF_hasprop(node, "little-endian");
+ sc->acpi = 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 @@
}
}
-static const device_method_t sdhci_fsl_fdt_methods[] = {
- /* 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[] = {
/* Bus interface. */
DEVMETHOD(bus_read_ivar, sdhci_fsl_fdt_read_ivar),
DEVMETHOD(bus_write_ivar, sdhci_fsl_fdt_write_ivar),
@@ -1549,12 +1565,29 @@
DEVMETHOD_END
};
-static driver_t sdhci_fsl_fdt_driver = {
- "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[] = {
+ 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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Oct 5, 2:52 PM (13 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40243276
Default Alt Text
D58259.id182067.diff (16 KB)
Attached To
Mode
D58259: sdhci_fsl: add ACPI front-end for NXP Layerscape eSDHC (NXP0003)
Attached
Detach File
Event Timeline
Log In to Comment