arm: allwinner: aw_mmc: Use the mmc_fdt_helper

The fdt properties are now parsed via the help of mmc_fdt_helper functions.
This also adds card detection.
Note that on some boards (like the Pine64) card detection is broken due to
a missing resistor on the cd pin.

MFC after:	1 month
Differential Revision:	https://reviews.freebsd.org/D23268
This commit is contained in:
Emmanuel Vadot
2020-04-14 16:34:13 +00:00
parent e63fbd7bb7
commit 9ed8321078
+61 -66
View File
@@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$");
#include <sys/resource.h>
#include <sys/rman.h>
#include <sys/sysctl.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
@@ -49,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <dev/mmc/bridge.h>
#include <dev/mmc/mmcbrvar.h>
#include <dev/mmc/mmc_fdt_helpers.h>
#include <arm/allwinner/aw_mmc.h>
#include <dev/extres/clk/clk.h>
@@ -122,6 +125,7 @@ struct aw_mmc_softc {
int aw_timeout;
struct callout aw_timeoutc;
struct mmc_host aw_host;
struct mmc_fdt_helper mmc_helper;
#ifdef MMCCAM
union ccb * ccb;
struct cam_devq * devq;
@@ -136,9 +140,8 @@ struct aw_mmc_softc {
uint32_t aw_intr;
uint32_t aw_intr_wait;
void * aw_intrhand;
regulator_t aw_reg_vmmc;
regulator_t aw_reg_vqmmc;
unsigned int aw_clock;
device_t child;
/* Fields required for DMA access. */
bus_addr_t aw_dma_desc_phys;
@@ -164,6 +167,7 @@ static int aw_mmc_reset(struct aw_mmc_softc *);
static int aw_mmc_init(struct aw_mmc_softc *);
static void aw_mmc_intr(void *);
static int aw_mmc_update_clock(struct aw_mmc_softc *, uint32_t);
static void aw_mmc_helper_cd_handler(device_t, bool);
static void aw_mmc_print_error(uint32_t);
static int aw_mmc_update_ios(device_t, device_t);
@@ -360,6 +364,40 @@ aw_mmc_cam_request(struct aw_mmc_softc *sc, union ccb *ccb)
}
#endif /* MMCCAM */
static void
aw_mmc_helper_cd_handler(device_t dev, bool present)
{
struct aw_mmc_softc *sc;
sc = device_get_softc(dev);
AW_MMC_LOCK(sc);
if (present) {
if (sc->child == NULL) {
if (bootverbose)
device_printf(sc->aw_dev, "Card inserted\n");
sc->child = device_add_child(sc->aw_dev, "mmc", -1);
AW_MMC_UNLOCK(sc);
if (sc->child) {
device_set_ivars(sc->child, sc);
(void)device_probe_and_attach(sc->child);
}
} else
AW_MMC_UNLOCK(sc);
} else {
/* Card isn't present, detach if necessary */
if (sc->child != NULL) {
if (bootverbose)
device_printf(sc->aw_dev, "Card removed\n");
AW_MMC_UNLOCK(sc);
device_delete_child(sc->aw_dev, sc->child);
sc->child = NULL;
} else
AW_MMC_UNLOCK(sc);
}
}
static int
aw_mmc_probe(device_t dev)
{
@@ -377,15 +415,11 @@ aw_mmc_probe(device_t dev)
static int
aw_mmc_attach(device_t dev)
{
device_t child;
struct aw_mmc_softc *sc;
struct sysctl_ctx_list *ctx;
struct sysctl_oid_list *tree;
uint32_t bus_width, max_freq;
phandle_t node;
int error;
node = ofw_bus_get_node(dev);
sc = device_get_softc(dev);
sc->aw_dev = dev;
@@ -399,7 +433,7 @@ aw_mmc_attach(device_t dev)
return (ENXIO);
}
if (bus_setup_intr(dev, sc->aw_res[AW_MMC_IRQRES],
INTR_TYPE_MISC | INTR_MPSAFE, NULL, aw_mmc_intr, sc,
INTR_TYPE_NET | INTR_MPSAFE, NULL, aw_mmc_intr, sc,
&sc->aw_intrhand)) {
bus_release_resources(dev, aw_mmc_res_spec, sc->aw_res);
device_printf(dev, "cannot setup interrupt handler\n");
@@ -463,47 +497,15 @@ aw_mmc_attach(device_t dev)
goto fail;
}
if (OF_getencprop(node, "bus-width", &bus_width, sizeof(uint32_t)) <= 0)
bus_width = 4;
if (regulator_get_by_ofw_property(dev, 0, "vmmc-supply",
&sc->aw_reg_vmmc) == 0) {
if (bootverbose)
device_printf(dev, "vmmc-supply regulator found\n");
}
if (regulator_get_by_ofw_property(dev, 0, "vqmmc-supply",
&sc->aw_reg_vqmmc) == 0 && bootverbose) {
if (bootverbose)
device_printf(dev, "vqmmc-supply regulator found\n");
}
/* Set some defaults for freq and supported mode */
sc->aw_host.f_min = 400000;
if (OF_getencprop(node, "max-frequency", &max_freq,
sizeof(uint32_t)) <= 0)
max_freq = 52000000;
sc->aw_host.f_max = max_freq;
sc->aw_host.f_max = 52000000;
sc->aw_host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
sc->aw_host.caps = MMC_CAP_HSPEED | MMC_CAP_UHS_SDR12 |
MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
MMC_CAP_UHS_DDR50 | MMC_CAP_MMC_DDR52;
if (sc->aw_reg_vqmmc != NULL) {
if (regulator_check_voltage(sc->aw_reg_vqmmc, 1800000) == 0)
sc->aw_host.caps |= MMC_CAP_SIGNALING_180;
if (regulator_check_voltage(sc->aw_reg_vqmmc, 3300000) == 0)
sc->aw_host.caps |= MMC_CAP_SIGNALING_330;
} else
sc->aw_host.caps |= MMC_CAP_SIGNALING_330;
if (bus_width >= 4)
sc->aw_host.caps |= MMC_CAP_4_BIT_DATA;
if (bus_width >= 8)
sc->aw_host.caps |= MMC_CAP_8_BIT_DATA;
sc->aw_host.caps |= MMC_CAP_HSPEED | MMC_CAP_SIGNALING_330;
mmc_fdt_parse(dev, 0, &sc->mmc_helper, &sc->aw_host);
mmc_fdt_gpio_setup(dev, 0, &sc->mmc_helper, aw_mmc_helper_cd_handler);
#ifdef MMCCAM
child = NULL; /* Not used by MMCCAM, need to silence compiler warnings */
sc->ccb = NULL;
if ((sc->devq = cam_simq_alloc(1)) == NULL) {
goto fail;
@@ -530,18 +532,8 @@ aw_mmc_attach(device_t dev)
}
mtx_unlock(&sc->sim_mtx);
#else /* !MMCCAM */
child = device_add_child(dev, "mmc", -1);
if (child == NULL) {
device_printf(dev, "attaching MMC bus failed!\n");
goto fail;
}
if (device_probe_and_attach(child) != 0) {
device_printf(dev, "attaching MMC child failed!\n");
device_delete_child(dev, child);
goto fail;
}
#endif /* MMCCAM */
return (0);
fail:
@@ -1301,7 +1293,7 @@ aw_mmc_switch_vccq(device_t bus, device_t child)
sc = device_get_softc(bus);
if (sc->aw_reg_vqmmc == NULL)
if (sc->mmc_helper.vqmmc_supply == NULL)
return EOPNOTSUPP;
switch (sc->aw_host.ios.vccq) {
@@ -1315,7 +1307,7 @@ aw_mmc_switch_vccq(device_t bus, device_t child)
return EINVAL;
}
err = regulator_set_voltage(sc->aw_reg_vqmmc, uvolt, uvolt);
err = regulator_set_voltage(sc->mmc_helper.vqmmc_supply, uvolt, uvolt);
if (err != 0) {
device_printf(sc->aw_dev,
"Cannot set vqmmc to %d<->%d\n",
@@ -1360,10 +1352,10 @@ aw_mmc_update_ios(device_t bus, device_t child)
if (bootverbose)
device_printf(sc->aw_dev, "Powering down sd/mmc\n");
if (sc->aw_reg_vmmc)
regulator_disable(sc->aw_reg_vmmc);
if (sc->aw_reg_vqmmc)
regulator_disable(sc->aw_reg_vqmmc);
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);
aw_mmc_reset(sc);
break;
@@ -1371,10 +1363,10 @@ aw_mmc_update_ios(device_t bus, device_t child)
if (bootverbose)
device_printf(sc->aw_dev, "Powering up sd/mmc\n");
if (sc->aw_reg_vmmc)
regulator_enable(sc->aw_reg_vmmc);
if (sc->aw_reg_vqmmc)
regulator_enable(sc->aw_reg_vqmmc);
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);
aw_mmc_init(sc);
break;
};
@@ -1450,8 +1442,11 @@ aw_mmc_update_ios(device_t bus, device_t child)
static int
aw_mmc_get_ro(device_t bus, device_t child)
{
struct aw_mmc_softc *sc;
return (0);
sc = device_get_softc(bus);
return (mmc_fdt_gpio_get_readonly(&sc->mmc_helper));
}
static int