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
This commit is contained in:
Bartlomiej Grzesik 2021-07-15 14:29:15 +02:00 committed by Marcin Wojtas
parent 5aa9f8dae3
commit d78e464d23
4 changed files with 264 additions and 147 deletions

View File

@ -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

View File

@ -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;
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
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);
}
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);
sdhci_xenon_parse_prop(dev);
/*
* 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_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 @@ sdhci_xenon_attach(device_t dev)
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

View File

@ -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_ */

View File

@ -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