aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartlomiej Grzesik <bag@semihalf.com>2021-07-15 12:29:15 +0000
committerMarcin Wojtas <mw@FreeBSD.org>2021-09-29 14:19:28 +0000
commitd78e464d23304084be17cb8db8981558f2829d6c (patch)
tree44b5f897f2c1cda7dd51569fa263812825680810
parent5aa9f8dae3d40e1780a688ce01401e799b25e7c3 (diff)
downloadsrc-d78e464d23304084be17cb8db8981558f2829d6c.tar.gz
src-d78e464d23304084be17cb8db8981558f2829d6c.zip
sdhci_xenon: split driver file into generic file and fdt parts
This patch splits driver code into two seperate files sdhci_xenon.c and sdhci_xenon_fdt.c. This will allow future implementation of ACPI discovery of sdhci on Xenon chips. Reviewed by: mw Sponsored by: Semihalf Differential revision: https://reviews.freebsd.org/D31599
-rw-r--r--sys/conf/files.arm643
-rw-r--r--sys/dev/sdhci/sdhci_xenon.c206
-rw-r--r--sys/dev/sdhci/sdhci_xenon.h29
-rw-r--r--sys/dev/sdhci/sdhci_xenon_fdt.c173
4 files changed, 264 insertions, 147 deletions
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 2362c7817025..0d33e315db65 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -274,7 +274,8 @@ dev/psci/smccc.c standard
dev/safexcel/safexcel.c optional safexcel fdt
-dev/sdhci/sdhci_xenon.c optional sdhci_xenon sdhci fdt
+dev/sdhci/sdhci_xenon.c optional sdhci_xenon sdhci
+dev/sdhci/sdhci_xenon_fdt.c optional sdhci_xenon sdhci fdt
dev/uart/uart_cpu_arm64.c optional uart
dev/uart/uart_dev_mu.c optional uart uart_mu
diff --git a/sys/dev/sdhci/sdhci_xenon.c b/sys/dev/sdhci/sdhci_xenon.c
index d88514d8fd8f..6dc0974c4e4e 100644
--- a/sys/dev/sdhci/sdhci_xenon.c
+++ b/sys/dev/sdhci/sdhci_xenon.c
@@ -48,17 +48,12 @@ __FBSDID("$FreeBSD$");
#include <machine/resource.h>
#include <dev/extres/regulator/regulator.h>
-#include <dev/fdt/fdt_common.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmc_fdt_helpers.h>
#include <dev/mmc/mmcbrvar.h>
#include <dev/mmc/mmcreg.h>
#include <dev/sdhci/sdhci.h>
-#include <dev/sdhci/sdhci_fdt_gpio.h>
#include <dev/sdhci/sdhci_xenon.h>
#include "mmcbr_if.h"
@@ -69,34 +64,6 @@ __FBSDID("$FreeBSD$");
#define MAX_SLOTS 6
-static struct ofw_compat_data compat_data[] = {
- { "marvell,armada-3700-sdhci", 1 },
-#ifdef SOC_MARVELL_8K
- { "marvell,armada-cp110-sdhci", 1 },
- { "marvell,armada-ap806-sdhci", 1 },
- { "marvell,armada-ap807-sdhci", 1 },
-#endif
- { NULL, 0 }
-};
-
-struct sdhci_xenon_softc {
- device_t dev; /* Controller device */
- int slot_id; /* Controller ID */
- phandle_t node; /* FDT node */
- struct resource *irq_res; /* IRQ resource */
- void *intrhand; /* Interrupt handle */
- struct sdhci_fdt_gpio *gpio; /* GPIO pins for CD detection. */
-
- struct sdhci_slot *slot; /* SDHCI internal data */
- struct resource *mem_res; /* Memory resource */
-
- uint8_t znr; /* PHY ZNR */
- uint8_t zpr; /* PHY ZPR */
- bool slow_mode; /* PHY slow mode */
-
- struct mmc_helper mmc_helper; /* MMC helper for parsing FDT */
-};
-
static uint8_t
sdhci_xenon_read_1(device_t dev, struct sdhci_slot *slot __unused,
bus_size_t off)
@@ -182,16 +149,7 @@ sdhci_xenon_get_ro(device_t bus, device_t dev)
{
struct sdhci_xenon_softc *sc = device_get_softc(bus);
- return (sdhci_generic_get_ro(bus, dev) ^
- (sc->mmc_helper.props & MMC_PROP_WP_INVERTED));
-}
-
-static bool
-sdhci_xenon_get_card_present(device_t dev, struct sdhci_slot *slot)
-{
- struct sdhci_xenon_softc *sc = device_get_softc(dev);
-
- return (sdhci_fdt_gpio_get_present(sc->gpio));
+ return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted);
}
static void
@@ -387,19 +345,19 @@ sdhci_xenon_update_ios(device_t brdev, device_t reqdev)
if (bootverbose)
device_printf(sc->dev, "Powering down sd/mmc\n");
- if (sc->mmc_helper.vmmc_supply)
- regulator_disable(sc->mmc_helper.vmmc_supply);
- if (sc->mmc_helper.vqmmc_supply)
- regulator_disable(sc->mmc_helper.vqmmc_supply);
+ if (sc->vmmc_supply)
+ regulator_disable(sc->vmmc_supply);
+ if (sc->vqmmc_supply)
+ regulator_disable(sc->vqmmc_supply);
break;
case power_up:
if (bootverbose)
device_printf(sc->dev, "Powering up sd/mmc\n");
- if (sc->mmc_helper.vmmc_supply)
- regulator_enable(sc->mmc_helper.vmmc_supply);
- if (sc->mmc_helper.vqmmc_supply)
- regulator_enable(sc->mmc_helper.vqmmc_supply);
+ if (sc->vmmc_supply)
+ regulator_enable(sc->vmmc_supply);
+ if (sc->vqmmc_supply)
+ regulator_enable(sc->vqmmc_supply);
break;
};
@@ -432,8 +390,8 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
sc = device_get_softc(brdev);
- if (sc->mmc_helper.vqmmc_supply == NULL)
- return EOPNOTSUPP;
+ if (sc->vqmmc_supply == NULL && !sc->skip_regulators)
+ return (EOPNOTSUPP);
err = 0;
@@ -445,15 +403,17 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
hostctrl2 &= ~SDHCI_CTRL2_S18_ENABLE;
bus_write_2(sc->mem_res, SDHCI_HOST_CONTROL2, hostctrl2);
- uvolt = 3300000;
- err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply,
- uvolt, uvolt);
- if (err != 0) {
- device_printf(sc->dev,
- "Cannot set vqmmc to %d<->%d\n",
- uvolt,
- uvolt);
- return (err);
+ if (!sc->skip_regulators) {
+ uvolt = 3300000;
+ err = regulator_set_voltage(sc->vqmmc_supply,
+ uvolt, uvolt);
+ if (err != 0) {
+ device_printf(sc->dev,
+ "Cannot set vqmmc to %d<->%d\n",
+ uvolt,
+ uvolt);
+ return (err);
+ }
}
/*
@@ -466,25 +426,27 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2);
if (!(hostctrl2 & SDHCI_CTRL2_S18_ENABLE))
return (0);
- return EAGAIN;
+ return (EAGAIN);
case vccq_180:
if (!(slot->host.caps & MMC_CAP_SIGNALING_180)) {
- return EINVAL;
+ return (EINVAL);
}
if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE)
return (0);
hostctrl2 |= SDHCI_CTRL2_S18_ENABLE;
bus_write_2(sc->mem_res, SDHCI_HOST_CONTROL2, hostctrl2);
- uvolt = 1800000;
- err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply,
- uvolt, uvolt);
- if (err != 0) {
- device_printf(sc->dev,
- "Cannot set vqmmc to %d<->%d\n",
- uvolt,
- uvolt);
- return (err);
+ if (!sc->skip_regulators) {
+ uvolt = 1800000;
+ err = regulator_set_voltage(sc->vqmmc_supply,
+ uvolt, uvolt);
+ if (err != 0) {
+ device_printf(sc->dev,
+ "Cannot set vqmmc to %d<->%d\n",
+ uvolt,
+ uvolt);
+ return (err);
+ }
}
/*
@@ -497,62 +459,46 @@ sdhci_xenon_switch_vccq(device_t brdev, device_t reqdev)
hostctrl2 = bus_read_2(sc->mem_res, SDHCI_HOST_CONTROL2);
if (hostctrl2 & SDHCI_CTRL2_S18_ENABLE)
return (0);
- return EAGAIN;
+ return (EAGAIN);
default:
device_printf(brdev,
"Attempt to set unsupported signaling voltage\n");
- return EINVAL;
+ return (EINVAL);
}
}
static void
-sdhci_xenon_fdt_parse(device_t dev, struct sdhci_slot *slot)
+sdhci_xenon_parse_prop(device_t dev)
{
- struct sdhci_xenon_softc *sc = device_get_softc(dev);
- pcell_t cid;
+ struct sdhci_xenon_softc *sc;
+ uint64_t val;
- mmc_fdt_parse(dev, 0, &sc->mmc_helper, &slot->host);
+ sc = device_get_softc(dev);
+ val = 0;
- /* Allow dts to patch quirks, slots, and max-frequency. */
- if ((OF_getencprop(sc->node, "quirks", &cid, sizeof(cid))) > 0)
- slot->quirks = cid;
- if (OF_hasprop(sc->node, "marvell,xenon-phy-slow-mode"))
- sc->slow_mode = true;
+ if (device_get_property(dev, "quirks", &val, sizeof(val)) > 0)
+ sc->slot->quirks = val;
sc->znr = XENON_ZNR_DEF_VALUE;
- if ((OF_getencprop(sc->node, "marvell,xenon-phy-znr", &cid,
- sizeof(cid))) > 0)
- sc->znr = cid & XENON_ZNR_MASK;
+ if (device_get_property(dev, "marvell,xenon-phy-znr",
+ &val, sizeof(val)) > 0)
+ sc->znr = val & XENON_ZNR_MASK;
sc->zpr = XENON_ZPR_DEF_VALUE;
- if ((OF_getencprop(sc->node, "marvell,xenon-phy-zpr", &cid,
- sizeof(cid))) > 0)
- sc->zpr = cid & XENON_ZPR_MASK;
-}
-
-static int
-sdhci_xenon_probe(device_t dev)
-{
- if (!ofw_bus_status_okay(dev))
- return (ENXIO);
-
- if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
- return (ENXIO);
-
- device_set_desc(dev, "Armada Xenon SDHCI controller");
-
- return (0);
+ if (device_get_property(dev, "marvell,xenon-phy-zpr",
+ &val, sizeof(val)) > 0)
+ sc->zpr = val & XENON_ZPR_MASK;
+ if (device_has_property(dev, "marvell,xenon-phy-slow-mode"))
+ sc->slow_mode = true;
}
-static int
+int
sdhci_xenon_attach(device_t dev)
{
struct sdhci_xenon_softc *sc = device_get_softc(dev);
- struct sdhci_slot *slot;
int err, rid;
uint32_t reg;
sc->dev = dev;
sc->slot_id = 0;
- sc->node = ofw_bus_get_node(dev);
/* Allocate IRQ. */
rid = 0;
@@ -574,27 +520,11 @@ sdhci_xenon_attach(device_t dev)
return (ENOMEM);
}
- slot = malloc(sizeof(*slot), M_DEVBUF, M_ZERO | M_WAITOK);
-
- /*
- * Set up any gpio pin handling described in the FDT data. This cannot
- * fail; see comments in sdhci_fdt_gpio.h for details.
- */
- sc->gpio = sdhci_fdt_gpio_setup(dev, slot);
+ sdhci_xenon_parse_prop(dev);
- sdhci_xenon_fdt_parse(dev, slot);
-
- slot->max_clk = XENON_MMC_MAX_CLK;
- if (slot->host.f_max > 0)
- slot->max_clk = slot->host.f_max;
- /* Check if the device is flagged as non-removable. */
- if (sc->mmc_helper.props & MMC_PROP_NON_REMOVABLE) {
- slot->opt |= SDHCI_NON_REMOVABLE;
- if (bootverbose)
- device_printf(dev, "Non-removable media\n");
- }
-
- sc->slot = slot;
+ sc->slot->max_clk = XENON_MMC_MAX_CLK;
+ if (sc->slot->host.f_max > 0)
+ sc->slot->max_clk = sc->slot->host.f_max;
if (sdhci_init_slot(dev, sc->slot, 0))
goto fail;
@@ -658,14 +588,11 @@ fail:
return (ENXIO);
}
-static int
+int
sdhci_xenon_detach(device_t dev)
{
struct sdhci_xenon_softc *sc = device_get_softc(dev);
- if (sc->gpio != NULL)
- sdhci_fdt_gpio_teardown(sc->gpio);
-
bus_generic_detach(dev);
bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res),
@@ -680,11 +607,6 @@ sdhci_xenon_detach(device_t dev)
}
static device_method_t sdhci_xenon_methods[] = {
- /* device_if */
- DEVMETHOD(device_probe, sdhci_xenon_probe),
- DEVMETHOD(device_attach, sdhci_xenon_attach),
- DEVMETHOD(device_detach, sdhci_xenon_detach),
-
/* Bus interface */
DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar),
DEVMETHOD(bus_write_ivar, sdhci_generic_write_ivar),
@@ -708,21 +630,13 @@ static device_method_t sdhci_xenon_methods[] = {
DEVMETHOD(sdhci_write_2, sdhci_xenon_write_2),
DEVMETHOD(sdhci_write_4, sdhci_xenon_write_4),
DEVMETHOD(sdhci_write_multi_4, sdhci_xenon_write_multi_4),
- DEVMETHOD(sdhci_get_card_present, sdhci_xenon_get_card_present),
DEVMETHOD(sdhci_set_uhs_timing, sdhci_xenon_set_uhs_timing),
DEVMETHOD_END
};
-static driver_t sdhci_xenon_driver = {
- "sdhci_xenon",
- sdhci_xenon_methods,
- sizeof(struct sdhci_xenon_softc),
-};
-static devclass_t sdhci_xenon_devclass;
-
-DRIVER_MODULE(sdhci_xenon, simplebus, sdhci_xenon_driver, sdhci_xenon_devclass,
- NULL, NULL);
+DEFINE_CLASS_0(sdhci_xenon, sdhci_xenon_driver, sdhci_xenon_methods,
+ sizeof(struct sdhci_xenon_softc));
SDHCI_DEPEND(sdhci_xenon);
#ifndef MMCCAM
diff --git a/sys/dev/sdhci/sdhci_xenon.h b/sys/dev/sdhci/sdhci_xenon.h
index 07ed99339b8d..9d8449b90c82 100644
--- a/sys/dev/sdhci/sdhci_xenon.h
+++ b/sys/dev/sdhci/sdhci_xenon.h
@@ -101,4 +101,33 @@
#define XENON_EMMC_PHY_LOGIC_TIMING_ADJUST (XENON_EMMC_PHY_REG_BASE + 0x18)
#define XENON_LOGIC_TIMING_VALUE 0x00AA8977
+DECLARE_CLASS(sdhci_xenon_driver);
+
+struct sdhci_xenon_softc {
+ device_t dev; /* Controller device */
+ int slot_id; /* Controller ID */
+
+ struct resource *mem_res; /* Memory resource */
+ struct resource *irq_res; /* IRQ resource */
+ void *intrhand; /* Interrupt handle */
+
+ struct sdhci_slot *slot; /* SDHCI internal data */
+
+ uint8_t znr; /* PHY ZNR */
+ uint8_t zpr; /* PHY ZPR */
+ bool slow_mode; /* PHY slow mode */
+ bool wp_inverted;
+ bool skip_regulators; /* Don't switch regulators */
+
+ regulator_t vmmc_supply;
+ regulator_t vqmmc_supply;
+
+#ifdef FDT
+ struct sdhci_fdt_gpio *gpio; /* GPIO pins for CD detection. */
+#endif
+};
+
+device_attach_t sdhci_xenon_attach;
+device_detach_t sdhci_xenon_detach;
+
#endif /* _SDHCI_XENON_H_ */
diff --git a/sys/dev/sdhci/sdhci_xenon_fdt.c b/sys/dev/sdhci/sdhci_xenon_fdt.c
new file mode 100644
index 000000000000..2d96105bd7e9
--- /dev/null
+++ b/sys/dev/sdhci/sdhci_xenon_fdt.c
@@ -0,0 +1,173 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Semihalf
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+#include <sys/taskqueue.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcbrvar.h>
+#include <dev/mmc/mmcreg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/mmc/mmc_fdt_helpers.h>
+
+#include <dev/sdhci/sdhci.h>
+#include <dev/sdhci/sdhci_fdt_gpio.h>
+#include <dev/sdhci/sdhci_xenon.h>
+
+#include "mmcbr_if.h"
+#include "sdhci_if.h"
+
+#include "opt_mmccam.h"
+#include "opt_soc.h"
+
+static struct ofw_compat_data compat_data[] = {
+ { "marvell,armada-3700-sdhci", 1 },
+#ifdef SOC_MARVELL_8K
+ { "marvell,armada-cp110-sdhci", 1 },
+ { "marvell,armada-ap806-sdhci", 1 },
+ { "marvell,armada-ap807-sdhci", 1 },
+#endif
+ { NULL, 0 }
+};
+
+static bool
+sdhci_xenon_fdt_get_card_present(device_t dev, struct sdhci_slot *slot)
+{
+ struct sdhci_xenon_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ return (sdhci_fdt_gpio_get_present(sc->gpio));
+}
+
+static int
+sdhci_xenon_fdt_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ return (ENXIO);
+
+ device_set_desc(dev, "Armada Xenon SDHCI controller");
+
+ return (BUS_PROBE_SPECIFIC);
+}
+
+static void
+sdhci_xenon_fdt_parse(device_t dev, struct sdhci_slot *slot)
+{
+ struct sdhci_xenon_softc *sc;
+ struct mmc_helper mmc_helper;
+
+ sc = device_get_softc(dev);
+ memset(&mmc_helper, 0, sizeof(mmc_helper));
+
+ /* MMC helper for parsing FDT */
+ mmc_fdt_parse(dev, 0, &mmc_helper, &slot->host);
+
+ sc->skip_regulators = false;
+ sc->vmmc_supply = mmc_helper.vmmc_supply;
+ sc->vqmmc_supply = mmc_helper.vqmmc_supply;
+ sc->wp_inverted = mmc_helper.props & MMC_PROP_WP_INVERTED;
+
+ /* Check if the device is flagged as non-removable. */
+ if (mmc_helper.props & MMC_PROP_NON_REMOVABLE) {
+ slot->opt |= SDHCI_NON_REMOVABLE;
+ if (bootverbose)
+ device_printf(dev, "Non-removable media\n");
+ }
+}
+
+static int
+sdhci_xenon_fdt_attach(device_t dev)
+{
+ struct sdhci_xenon_softc *sc;
+ struct sdhci_slot *slot;
+
+ sc = device_get_softc(dev);
+ slot = malloc(sizeof(*slot), M_DEVBUF, M_ZERO | M_WAITOK);
+
+ sdhci_xenon_fdt_parse(dev, slot);
+
+ /*
+ * Set up any gpio pin handling described in the FDT data. This cannot
+ * fail; see comments in sdhci_fdt_gpio.h for details.
+ */
+ sc->gpio = sdhci_fdt_gpio_setup(dev, slot);
+ sc->slot = slot;
+
+ return (sdhci_xenon_attach(dev));
+}
+
+static int
+sdhci_xenon_fdt_detach(device_t dev)
+{
+ struct sdhci_xenon_softc *sc;
+
+ sc = device_get_softc(dev);
+ if (sc->gpio != NULL)
+ sdhci_fdt_gpio_teardown(sc->gpio);
+
+ return (sdhci_xenon_detach(dev));
+}
+
+static device_method_t sdhci_xenon_fdt_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, sdhci_xenon_fdt_probe),
+ DEVMETHOD(device_attach, sdhci_xenon_fdt_attach),
+ DEVMETHOD(device_detach, sdhci_xenon_fdt_detach),
+
+ DEVMETHOD(sdhci_get_card_present, sdhci_xenon_fdt_get_card_present),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(sdhci_xenon, sdhci_xenon_fdt_driver, sdhci_xenon_fdt_methods,
+ sizeof(struct sdhci_xenon_softc), sdhci_xenon_driver);
+
+static devclass_t sdhci_xenon_fdt_devclass;
+
+DRIVER_MODULE(sdhci_xenon, simplebus, sdhci_xenon_fdt_driver,
+ sdhci_xenon_fdt_devclass, NULL, NULL);
+
+#ifndef MMCCAM
+MMC_DECLARE_BRIDGE(sdhci_xenon_fdt);
+#endif