summaryrefslogtreecommitdiffstats
path: root/sys/arm/freescale
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-05-15 22:35:04 +0000
committerian <ian@FreeBSD.org>2014-05-15 22:35:04 +0000
commitdbea31deb0f37bf5ff55e4cd39230b347deba1c1 (patch)
treecef68e1a6c248da2baa48f4d75039c40c41bf65d /sys/arm/freescale
parentedd0d85b77e836c83c4c913351ed136b5b963f9d (diff)
downloadFreeBSD-src-dbea31deb0f37bf5ff55e4cd39230b347deba1c1.zip
FreeBSD-src-dbea31deb0f37bf5ff55e4cd39230b347deba1c1.tar.gz
MFC r261938, r261939, r261940, r261944, r261945, r261946, r261947, r261956, r261957, r261983, r261094,
r261955, r261958, Add a driver to provide access to imx6 on-chip one-time-programmble data. Make it possible to access the ocotp registers before the ocotp device is attached, by establishing a temporary mapping of the registers when necessary. It turns out Freescale cleverly made the ocotp device compatible across several different families of SoCs, so move it to the freescale directory and prefix everything with fsl rather than imx6. Convert the imx6 sdhci "R1B fix" from a busy-loop in the interrupt handler to a callout. Increase the wait time for acquiring the SD bus from 10 to 250ms. If no compatible cards were found after probing the SD bus, say so. Add timeout logic to sdhci, separate from the timeouts done by the hardware. After a timeout, reset the controller using SDHCI_RESET_CMD|SDHCI_RESET_DATA rather than SDHCI_RESET_ALL; the latter turns off clocks and power, removing any possibility of recovering from the error. Add a helper routine to depth-search the device tree for a node with a matching 'compatible' property.
Diffstat (limited to 'sys/arm/freescale')
-rw-r--r--sys/arm/freescale/fsl_ocotp.c204
-rw-r--r--sys/arm/freescale/fsl_ocotpreg.h88
-rw-r--r--sys/arm/freescale/fsl_ocotpvar.h34
-rw-r--r--sys/arm/freescale/imx/files.imx61
-rw-r--r--sys/arm/freescale/imx/imx_sdhci.c124
5 files changed, 425 insertions, 26 deletions
diff --git a/sys/arm/freescale/fsl_ocotp.c b/sys/arm/freescale/fsl_ocotp.c
new file mode 100644
index 0000000..f097d4c
--- /dev/null
+++ b/sys/arm/freescale/fsl_ocotp.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 2014 Steven Lawrance <stl@koffein.net>
+ * All rights reserved.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$");
+
+/*
+ * Access to the Freescale i.MX6 On-Chip One-Time-Programmable Memory
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+
+#include <arm/freescale/fsl_ocotpreg.h>
+#include <arm/freescale/fsl_ocotpvar.h>
+
+/*
+ * Find the physical address and size of the ocotp registers and devmap them,
+ * returning a pointer to the virtual address of the base.
+ *
+ * XXX This is temporary until we've worked out all the details of controlling
+ * the load order of devices. In an ideal world this device would be up and
+ * running before anything that needs it. When we're at a point to make that
+ * happen, this little block of code, and the few lines in fsl_ocotp_read_4()
+ * that refer to it can be deleted.
+ */
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <dev/fdt/fdt_common.h>
+#include <machine/devmap.h>
+
+static uint32_t *ocotp_regs;
+static vm_size_t ocotp_size;
+
+static void
+fsl_ocotp_devmap(void)
+{
+ phandle_t child, root;
+ u_long base, size;
+
+ if ((root = OF_finddevice("/")) == 0)
+ goto fatal;
+ if ((child = fdt_depth_search_compatible(root, "fsl,imx6q-ocotp", 0)) == 0)
+ goto fatal;
+ if (fdt_regsize(child, &base, &size) != 0)
+ goto fatal;
+
+ ocotp_size = (vm_size_t)size;
+
+ if ((ocotp_regs = pmap_mapdev((vm_offset_t)base, ocotp_size)) == NULL)
+ goto fatal;
+
+ return;
+fatal:
+ panic("cannot find/map the ocotp registers");
+}
+/* XXX end of temporary code */
+
+struct ocotp_softc {
+ device_t dev;
+ struct resource *mem_res;
+};
+
+static struct ocotp_softc *ocotp_sc;
+
+static inline uint32_t
+RD4(struct ocotp_softc *sc, bus_size_t off)
+{
+
+ return (bus_read_4(sc->mem_res, off));
+}
+
+static int
+ocotp_detach(device_t dev)
+{
+
+ /* The ocotp registers are always accessible. */
+ return (EBUSY);
+}
+
+static int
+ocotp_attach(device_t dev)
+{
+ struct ocotp_softc *sc;
+ int err, rid;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ /* Allocate bus_space resources. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Cannot allocate memory resources\n");
+ err = ENXIO;
+ goto out;
+ }
+
+ ocotp_sc = sc;
+
+ /* We're done with the temporary mapping now. */
+ if (ocotp_regs != NULL)
+ pmap_unmapdev((vm_offset_t)ocotp_regs, ocotp_size);
+
+ err = 0;
+
+out:
+ if (err != 0)
+ ocotp_detach(dev);
+
+ return (err);
+}
+
+static int
+ocotp_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_is_compatible(dev, "fsl,imx6q-ocotp") == 0)
+ return (ENXIO);
+
+ device_set_desc(dev,
+ "Freescale On-Chip One-Time-Programmable Memory");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+uint32_t
+fsl_ocotp_read_4(bus_size_t off)
+{
+
+ if (off > FSL_OCOTP_LAST_REG)
+ panic("fsl_ocotp_read_4: offset out of range");
+
+ /* If we have a softcontext use the regular bus_space read. */
+ if (ocotp_sc != NULL)
+ return (RD4(ocotp_sc, off));
+
+ /*
+ * Otherwise establish a tempory device mapping if necessary, and read
+ * the device without any help from bus_space.
+ *
+ * XXX Eventually the code from there down can be deleted.
+ */
+ if (ocotp_regs == NULL)
+ fsl_ocotp_devmap();
+
+ return (ocotp_regs[off / 4]);
+}
+
+static device_method_t ocotp_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ocotp_probe),
+ DEVMETHOD(device_attach, ocotp_attach),
+ DEVMETHOD(device_detach, ocotp_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t ocotp_driver = {
+ "ocotp",
+ ocotp_methods,
+ sizeof(struct ocotp_softc)
+};
+
+static devclass_t ocotp_devclass;
+
+DRIVER_MODULE(ocotp, simplebus, ocotp_driver, ocotp_devclass, 0, 0);
+
diff --git a/sys/arm/freescale/fsl_ocotpreg.h b/sys/arm/freescale/fsl_ocotpreg.h
new file mode 100644
index 0000000..686e97e
--- /dev/null
+++ b/sys/arm/freescale/fsl_ocotpreg.h
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2014 Steven Lawrance <stl@koffein.net>
+ * All rights reserved.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef FSL_OCOTPREG_H
+#define FSL_OCOTPREG_H
+
+#define FSL_OCOTP_CTRL 0x000
+#define FSL_OCOTP_CTRL_SET 0x004
+#define FSL_OCOTP_CTRL_CLR 0x008
+#define FSL_OCOTP_CTRL_TOG 0x00C
+#define FSL_OCOTP_TIMING 0x010
+#define FSL_OCOTP_DATA 0x020
+#define FSL_OCOTP_READ_CTRL 0x030
+#define FSL_OCOTP_READ_FUSE_DATA 0x040
+#define FSL_OCOTP_SW_STICKY 0x050
+#define FSL_OCOTP_SCS 0x060
+#define FSL_OCOTP_SCS_SET 0x064
+#define FSL_OCOTP_SCS_CLR 0x068
+#define FSL_OCOTP_SCS_TOG 0x06C
+#define FSL_OCOTP_VERSION 0x090
+#define FSL_OCOTP_LOCK 0x400
+#define FSL_OCOTP_CFG0 0x410
+#define FSL_OCOTP_CFG1 0x420
+#define FSL_OCOTP_CFG2 0x430
+#define FSL_OCOTP_CFG3 0x440
+#define FSL_OCOTP_CFG3_SPEED_SHIFT 16
+#define FSL_OCOTP_CFG3_SPEED_MASK \
+ (0x03 << FSL_OCOTP_CFG3_SPEED_SHIFT)
+#define FSL_OCOTP_CFG3_SPEED_792MHZ 0
+#define FSL_OCOTP_CFG3_SPEED_852MHZ 1
+#define FSL_OCOTP_CFG3_SPEED_996MHZ 2
+#define FSL_OCOTP_CFG3_SPEED_1200MHZ 3
+#define FSL_OCOTP_CFG4 0x450
+#define FSL_OCOTP_CFG5 0x460
+#define FSL_OCOTP_CFG6 0x470
+#define FSL_OCOTP_MEM0 0x480
+#define FSL_OCOTP_MEM1 0x490
+#define FSL_OCOTP_MEM2 0x4A0
+#define FSL_OCOTP_MEM3 0x4B0
+#define FSL_OCOTP_ANA0 0x4D0
+#define FSL_OCOTP_ANA1 0x4E0
+#define FSL_OCOTP_ANA2 0x4F0
+#define FSL_OCOTP_SRK0 0x580
+#define FSL_OCOTP_SRK1 0x590
+#define FSL_OCOTP_SRK2 0x5A0
+#define FSL_OCOTP_SRK3 0x5B0
+#define FSL_OCOTP_SRK4 0x5C0
+#define FSL_OCOTP_SRK5 0x5D0
+#define FSL_OCOTP_SRK6 0x5E0
+#define FSL_OCOTP_SRK7 0x5F0
+#define FSL_OCOTP_HSJC_RESP0 0x600
+#define FSL_OCOTP_HSJC_RESP1 0x610
+#define FSL_OCOTP_MAC0 0x620
+#define FSL_OCOTP_MAC1 0x630
+#define FSL_OCOTP_GP1 0x660
+#define FSL_OCOTP_GP2 0x670
+#define FSL_OCOTP_MISC_CONF 0x6D0
+#define FSL_OCOTP_FIELD_RETURN 0x6E0
+#define FSL_OCOTP_SRK_REVOKE 0x6F0
+
+#define FSL_OCOTP_LAST_REG FSL_OCOTP_SRK_REVOKE
+
+#endif
diff --git a/sys/arm/freescale/fsl_ocotpvar.h b/sys/arm/freescale/fsl_ocotpvar.h
new file mode 100644
index 0000000..c3f5ecf
--- /dev/null
+++ b/sys/arm/freescale/fsl_ocotpvar.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2014 Steven Lawrance <stl@koffein.net>
+ * All rights reserved.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef FSL_OCOTPVAR_H
+#define FSL_OCOTPVAR_H
+
+uint32_t fsl_ocotp_read_4(bus_size_t _offset);
+
+#endif
diff --git a/sys/arm/freescale/imx/files.imx6 b/sys/arm/freescale/imx/files.imx6
index 7cee049..943c679 100644
--- a/sys/arm/freescale/imx/files.imx6
+++ b/sys/arm/freescale/imx/files.imx6
@@ -17,6 +17,7 @@ kern/kern_clocksource.c standard
arm/arm/gic.c standard
arm/arm/pl310.c standard
arm/freescale/imx/bus_space.c standard
+arm/freescale/fsl_ocotp.c standard
arm/freescale/imx/common.c standard
arm/freescale/imx/imx6_anatop.c standard
arm/freescale/imx/imx6_ccm.c standard
diff --git a/sys/arm/freescale/imx/imx_sdhci.c b/sys/arm/freescale/imx/imx_sdhci.c
index 7c9af18..2d83fd6 100644
--- a/sys/arm/freescale/imx/imx_sdhci.c
+++ b/sys/arm/freescale/imx/imx_sdhci.c
@@ -35,13 +35,18 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/types.h>
#include <sys/bus.h>
+#include <sys/callout.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/resource.h>
#include <sys/rman.h>
#include <sys/taskqueue.h>
+#include <sys/time.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -65,6 +70,8 @@ struct imx_sdhci_softc {
struct resource * irq_res;
void * intr_cookie;
struct sdhci_slot slot;
+ struct callout r1bfix_callout;
+ sbintime_t r1bfix_timeout_at;
uint32_t baseclk_hz;
uint32_t sdclockreg_freq_bits;
uint32_t cmd_and_mode;
@@ -130,6 +137,8 @@ struct imx_sdhci_softc {
#define SDHC_PROT_CDTL (1 << 6)
#define SDHC_PROT_CDSS (1 << 7)
+#define SDHC_INT_STATUS 0x30
+
#define SDHC_CLK_IPGEN (1 << 0)
#define SDHC_CLK_HCKEN (1 << 1)
#define SDHC_CLK_PEREN (1 << 2)
@@ -147,6 +156,7 @@ static struct ofw_compat_data compat_data[] = {
};;
static void imx_sdhc_set_clock(struct imx_sdhci_softc *sc, int enable);
+static void imx_sdhci_r1bfix_func(void *arg);
static inline uint32_t
RD4(struct imx_sdhci_softc *sc, bus_size_t off)
@@ -532,46 +542,107 @@ imx_sdhc_set_clock(struct imx_sdhci_softc *sc, int enable)
RD4(sc, SDHC_VEND_SPEC) | SDHC_VEND_FRC_SDCLK_ON);
}
+static boolean_t
+imx_sdhci_r1bfix_is_wait_done(struct imx_sdhci_softc *sc)
+{
+ uint32_t inhibit;
+
+ mtx_assert(&sc->slot.mtx, MA_OWNED);
+
+ /*
+ * Check the DAT0 line status using both the DLA (data line active) and
+ * CDIHB (data inhibit) bits in the present state register. In theory
+ * just DLA should do the trick, but in practice it takes both. If the
+ * DAT0 line is still being held and we're not yet beyond the timeout
+ * point, just schedule another callout to check again later.
+ */
+ inhibit = RD4(sc, SDHC_PRES_STATE) & (SDHC_PRES_DLA | SDHC_PRES_CDIHB);
+
+ if (inhibit && getsbinuptime() < sc->r1bfix_timeout_at) {
+ callout_reset_sbt(&sc->r1bfix_callout, SBT_1MS, 0,
+ imx_sdhci_r1bfix_func, sc, 0);
+ return (false);
+ }
+
+ /*
+ * If we reach this point with the inhibit bits still set, we've got a
+ * timeout, synthesize a DATA_TIMEOUT interrupt. Otherwise the DAT0
+ * line has been released, and we synthesize a DATA_END, and if the type
+ * of fix needed was on a command-without-data we also now add in the
+ * original INT_RESPONSE that we suppressed earlier.
+ */
+ if (inhibit)
+ sc->r1bfix_intmask |= SDHCI_INT_DATA_TIMEOUT;
+ else {
+ sc->r1bfix_intmask |= SDHCI_INT_DATA_END;
+ if (sc->r1bfix_type == R1BFIX_NODATA)
+ sc->r1bfix_intmask |= SDHCI_INT_RESPONSE;
+ }
+
+ sc->r1bfix_type = R1BFIX_NONE;
+ return (true);
+}
+
+static void
+imx_sdhci_r1bfix_func(void * arg)
+{
+ struct imx_sdhci_softc *sc = arg;
+ boolean_t r1bwait_done;
+
+ mtx_lock(&sc->slot.mtx);
+ r1bwait_done = imx_sdhci_r1bfix_is_wait_done(sc);
+ mtx_unlock(&sc->slot.mtx);
+ if (r1bwait_done)
+ sdhci_generic_intr(&sc->slot);
+}
+
static void
imx_sdhci_intr(void *arg)
{
struct imx_sdhci_softc *sc = arg;
uint32_t intmask;
- intmask = RD4(sc, SDHCI_INT_STATUS);
+ mtx_lock(&sc->slot.mtx);
/*
* Manually check the DAT0 line for R1B response types that the
- * controller fails to handle properly.
+ * controller fails to handle properly. The controller asserts the done
+ * interrupt while the card is still asserting busy with the DAT0 line.
*
- * To do the NODATA fix, when the RESPONSE (COMMAND_COMPLETE) interrupt
- * occurs, we have to wait for the DAT0 line to be released, then
- * synthesize a DATA_END (TRANSFER_COMPLETE) interrupt, which we do by
- * storing SDHCI_INT_DATA_END into a variable that gets ORed into the
- * return value when the SDHCI_INT_STATUS register is read.
+ * We check DAT0 immediately because most of the time, especially on a
+ * read, the card will actually be done by time we get here. If it's
+ * not, then the wait_done routine will schedule a callout to re-check
+ * periodically until it is done. In that case we clear the interrupt
+ * out of the hardware now so that we can present it later when the DAT0
+ * line is released.
*
- * For the AC12 fix, when the DATA_END interrupt occurs we wait for the
- * DAT0 line to be released, and the waiting is all the fix we need.
+ * If we need to wait for the the DAT0 line to be released, we set up a
+ * timeout point 250ms in the future. This number comes from the SD
+ * spec, which allows a command to take that long. In the real world,
+ * cards tend to take 10-20ms for a long-running command such as a write
+ * or erase that spans two pages.
*/
- if ((sc->r1bfix_type == R1BFIX_NODATA &&
- (intmask & SDHCI_INT_RESPONSE)) ||
- (sc->r1bfix_type == R1BFIX_AC12 &&
- (intmask & SDHCI_INT_DATA_END))) {
- uint32_t count;
- count = 0;
- /* XXX use a callout or something instead of busy-waiting. */
- while (count < 250000 &&
- (RD4(sc, SDHC_PRES_STATE) & SDHC_PRES_DLA)) {
- ++count;
- DELAY(1);
+ switch (sc->r1bfix_type) {
+ case R1BFIX_NODATA:
+ intmask = RD4(sc, SDHC_INT_STATUS) & SDHCI_INT_RESPONSE;
+ break;
+ case R1BFIX_AC12:
+ intmask = RD4(sc, SDHC_INT_STATUS) & SDHCI_INT_DATA_END;
+ break;
+ default:
+ intmask = 0;
+ break;
+ }
+ if (intmask) {
+ sc->r1bfix_timeout_at = getsbinuptime() + 250 * SBT_1MS;
+ if (!imx_sdhci_r1bfix_is_wait_done(sc)) {
+ WR4(sc, SDHC_INT_STATUS, intmask);
+ bus_barrier(sc->mem_res, SDHC_INT_STATUS, 4,
+ BUS_SPACE_BARRIER_WRITE);
}
- if (count >= 250000)
- sc->r1bfix_intmask = SDHCI_INT_DATA_TIMEOUT;
- else if (sc->r1bfix_type == R1BFIX_NODATA)
- sc->r1bfix_intmask = SDHCI_INT_DATA_END;
- sc->r1bfix_type = R1BFIX_NONE;
}
+ mtx_unlock(&sc->slot.mtx);
sdhci_generic_intr(&sc->slot);
}
@@ -660,6 +731,7 @@ imx_sdhci_attach(device_t dev)
}
sdhci_init_slot(dev, &sc->slot, 0);
+ callout_init(&sc->r1bfix_callout, true);
/*
* If the slot is flagged with the non-removable property, set our flag
@@ -670,7 +742,7 @@ imx_sdhci_attach(device_t dev)
* We don't have gpio support yet. If there's a cd-gpios property just
* force the SDHCI_CARD_PRESENT bit on for now. If there isn't really a
* card there it will fail to probe at the mmc layer and nothing bad
- * happens except instantiating a /dev/mmcN device for an empty slot.
+ * happens except instantiating an mmcN device for an empty slot.
*/
node = ofw_bus_get_node(dev);
if (OF_hasprop(node, "non-removable"))
OpenPOWER on IntegriCloud