summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2017-03-01 21:02:26 +0000
committerian <ian@FreeBSD.org>2017-03-01 21:02:26 +0000
commitde0f5cf4ff4c40f2ca56f781456366447d24d494 (patch)
tree9e19c9be5c236523fb38312fde0cbc27f1636509
parent729b5d708ca03f0facd9c13337866fa1cb306ebe (diff)
downloadFreeBSD-src-de0f5cf4ff4c40f2ca56f781456366447d24d494.zip
FreeBSD-src-de0f5cf4ff4c40f2ca56f781456366447d24d494.tar.gz
MFC r308186, r308188, r308231, r308232:
Move imx_sdhci driver over to a dev/sdhci in preparation for QorIQ support. Freescale uses eSDHC in both i.MX (ARM) and QorIQ (PowerPC), with slight differences. This is part one in unifying the drivers. Merge i.MX and PowerPC SDHCI drivers Summary: i.MX5 and PowerPC use a very similar eSDHC controller, which is also similar to the uSDHC controller used by i.MX6. The imx_sdhci driver works almost completely with PowerPC, with some minor tweaks. Fix the build. protctl is only used on powerpc. While here, remove the need to check the SVR SPR, as others may be compatible with the p1022-esdhc type. Since it's no longer accessing a powerpc-specific register, drop the #ifdef.
-rw-r--r--sys/arm/freescale/imx/files.imx52
-rw-r--r--sys/arm/freescale/imx/files.imx62
-rw-r--r--sys/conf/files.powerpc2
-rw-r--r--sys/dev/sdhci/fsl_sdhci.c (renamed from sys/arm/freescale/imx/imx_sdhci.c)256
-rw-r--r--sys/powerpc/mpc85xx/fsl_sdhc.c1303
-rw-r--r--sys/powerpc/mpc85xx/fsl_sdhc.h297
6 files changed, 173 insertions, 1689 deletions
diff --git a/sys/arm/freescale/imx/files.imx5 b/sys/arm/freescale/imx/files.imx5
index aaea851..c2214c1 100644
--- a/sys/arm/freescale/imx/files.imx5
+++ b/sys/arm/freescale/imx/files.imx5
@@ -32,7 +32,7 @@ arm/freescale/imx/imx51_ccm.c standard
dev/ata/chipsets/ata-fsl.c optional imxata
# SDHCI/MMC
-arm/freescale/imx/imx_sdhci.c optional sdhci
+dev/sdhci/fsl_sdhci.c optional sdhci
# USB OH3 controller (1 OTG, 3 EHCI)
arm/freescale/imx/imx_nop_usbphy.c optional ehci
diff --git a/sys/arm/freescale/imx/files.imx6 b/sys/arm/freescale/imx/files.imx6
index de4ff6e..6fb8e2f 100644
--- a/sys/arm/freescale/imx/files.imx6
+++ b/sys/arm/freescale/imx/files.imx6
@@ -32,7 +32,7 @@ arm/freescale/imx/imx6_ipu.c optional vt
#
# Optional devices.
#
-arm/freescale/imx/imx_sdhci.c optional sdhci
+dev/sdhci/fsl_sdhci.c optional sdhci
arm/freescale/imx/imx_wdog.c optional imxwdt
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
index dc5d52d..d1d5312 100644
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -63,6 +63,7 @@ dev/ofw/ofw_subr.c optional aim powerpc
dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac
dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx
dev/scc/scc_bfe_macio.c optional scc powermac
+dev/sdhci/fsl_sdhci.c optional mpc85xx sdhci
dev/sec/sec.c optional sec mpc85xx
dev/sound/macio/aoa.c optional snd_davbus | snd_ai2s powermac
dev/sound/macio/davbus.c optional snd_davbus powermac
@@ -135,7 +136,6 @@ powerpc/mikrotik/platform_rb.c optional mikrotik
powerpc/mpc85xx/atpic.c optional mpc85xx isa
powerpc/mpc85xx/ds1553_bus_fdt.c optional ds1553 fdt
powerpc/mpc85xx/ds1553_core.c optional ds1553
-powerpc/mpc85xx/fsl_sdhc.c optional mpc85xx sdhc | qoriq_dpaa sdhc
powerpc/mpc85xx/i2c.c optional iicbus fdt
powerpc/mpc85xx/isa.c optional mpc85xx isa
powerpc/mpc85xx/lbc.c optional mpc85xx | qoriq_dpaa
diff --git a/sys/arm/freescale/imx/imx_sdhci.c b/sys/dev/sdhci/fsl_sdhci.c
index 39c9508..4e667bd 100644
--- a/sys/arm/freescale/imx/imx_sdhci.c
+++ b/sys/dev/sdhci/fsl_sdhci.c
@@ -28,7 +28,7 @@
__FBSDID("$FreeBSD$");
/*
- * SDHCI driver glue for Freescale i.MX SoC family.
+ * SDHCI driver glue for Freescale i.MX SoC and QorIQ families.
*
* This supports both eSDHC (earlier SoCs) and uSDHC (more recent SoCs).
*/
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/callout.h>
+#include <sys/endian.h>
#include <sys/kernel.h>
#include <sys/libkern.h>
#include <sys/lock.h>
@@ -52,9 +53,11 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h>
#include <machine/resource.h>
+#ifdef __arm__
#include <machine/intr.h>
#include <arm/freescale/imx/imx_ccmvar.h>
+#endif
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
@@ -66,7 +69,7 @@ __FBSDID("$FreeBSD$");
#include <dev/sdhci/sdhci.h>
#include "sdhci_if.h"
-struct imx_sdhci_softc {
+struct fsl_sdhci_softc {
device_t dev;
struct resource * mem_res;
struct resource * irq_res;
@@ -88,8 +91,8 @@ struct imx_sdhci_softc {
#define R1BFIX_AC12 2 /* Wait for busy after auto command 12. */
#define HWTYPE_NONE 0 /* Hardware not recognized/supported. */
-#define HWTYPE_ESDHC 1 /* imx5x and earlier. */
-#define HWTYPE_USDHC 2 /* imx6. */
+#define HWTYPE_ESDHC 1 /* fsl5x and earlier. */
+#define HWTYPE_USDHC 2 /* fsl6. */
/*
* Freescale-specific registers, or in some cases the layout of bits within the
@@ -146,7 +149,6 @@ struct imx_sdhci_softc {
#define SDHC_PROT_CDSS (1 << 7)
#define SDHC_SYS_CTRL 0x2c
-#define SDHC_INT_STATUS 0x30
/*
* The clock enable bits exist in different registers for ESDHC vs USDHC, but
@@ -169,31 +171,32 @@ static struct ofw_compat_data compat_data[] = {
{"fsl,imx6sl-usdhc", HWTYPE_USDHC},
{"fsl,imx53-esdhc", HWTYPE_ESDHC},
{"fsl,imx51-esdhc", HWTYPE_ESDHC},
+ {"fsl,esdhc", HWTYPE_ESDHC},
{NULL, HWTYPE_NONE},
};
-static uint16_t imx_sdhc_get_clock(struct imx_sdhci_softc *sc);
-static void imx_sdhc_set_clock(struct imx_sdhci_softc *sc, uint16_t val);
-static void imx_sdhci_r1bfix_func(void *arg);
+static uint16_t fsl_sdhc_get_clock(struct fsl_sdhci_softc *sc);
+static void fsl_sdhc_set_clock(struct fsl_sdhci_softc *sc, uint16_t val);
+static void fsl_sdhci_r1bfix_func(void *arg);
static inline uint32_t
-RD4(struct imx_sdhci_softc *sc, bus_size_t off)
+RD4(struct fsl_sdhci_softc *sc, bus_size_t off)
{
return (bus_read_4(sc->mem_res, off));
}
static inline void
-WR4(struct imx_sdhci_softc *sc, bus_size_t off, uint32_t val)
+WR4(struct fsl_sdhci_softc *sc, bus_size_t off, uint32_t val)
{
bus_write_4(sc->mem_res, off, val);
}
static uint8_t
-imx_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
+fsl_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
uint32_t val32, wrk32;
/*
@@ -246,9 +249,9 @@ imx_sdhci_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
}
static uint16_t
-imx_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
+fsl_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
uint32_t val32;
if (sc->hwtype == HWTYPE_USDHC) {
@@ -297,16 +300,16 @@ imx_sdhci_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
* hardware type, complex enough to have their own function.
*/
if (off == SDHCI_CLOCK_CONTROL) {
- return (imx_sdhc_get_clock(sc));
+ return (fsl_sdhc_get_clock(sc));
}
return ((RD4(sc, off & ~3) >> (off & 3) * 8) & 0xffff);
}
static uint32_t
-imx_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
+fsl_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
uint32_t val32, wrk32;
val32 = RD4(sc, off);
@@ -348,7 +351,7 @@ imx_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
}
/*
- * imx_sdhci_intr() can synthesize a DATA_END interrupt following a
+ * fsl_sdhci_intr() can synthesize a DATA_END interrupt following a
* command with an R1B response, mix it into the hardware status.
*/
if (off == SDHCI_INT_STATUS) {
@@ -359,18 +362,18 @@ imx_sdhci_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
}
static void
-imx_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
+fsl_sdhci_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
uint32_t *data, bus_size_t count)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
bus_read_multi_4(sc->mem_res, off, data, count);
}
static void
-imx_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
+fsl_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t val)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
uint32_t val32;
/*
@@ -397,6 +400,11 @@ imx_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t
if (off == SDHCI_POWER_CONTROL) {
return;
}
+#ifdef __powerpc__
+ /* XXX Reset doesn't seem to work as expected. Do nothing for now. */
+ if (off == SDHCI_SOFTWARE_RESET)
+ return;
+#endif
val32 = RD4(sc, off & ~3);
val32 &= ~(0xff << (off & 3) * 8);
@@ -406,9 +414,9 @@ imx_sdhci_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint8_t
}
static void
-imx_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
+fsl_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
uint32_t val32;
/*
@@ -416,7 +424,7 @@ imx_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_
* that can handle the ESDHC versus USDHC differences.
*/
if (off == SDHCI_CLOCK_CONTROL) {
- imx_sdhc_set_clock(sc, val);
+ fsl_sdhc_set_clock(sc, val);
return;
}
@@ -432,7 +440,7 @@ imx_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_
* there's a control bit for it (bit 3) in the vendor register.
* When we're starting a command that needs a manual DAT0 line check at
* interrupt time, we leave ourselves a note in r1bfix_type so that we
- * can do the extra work in imx_sdhci_intr().
+ * can do the extra work in fsl_sdhci_intr().
*/
if (off == SDHCI_COMMAND_FLAGS) {
if (val & SDHCI_CMD_DATA) {
@@ -485,9 +493,9 @@ imx_sdhci_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_
}
static void
-imx_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
+fsl_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
/* Clear synthesized interrupts, then pass the value to the hardware. */
if (off == SDHCI_INT_STATUS) {
@@ -498,16 +506,16 @@ imx_sdhci_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_
}
static void
-imx_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
+fsl_sdhci_write_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
uint32_t *data, bus_size_t count)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
bus_write_multi_4(sc->mem_res, off, data, count);
}
static uint16_t
-imx_sdhc_get_clock(struct imx_sdhci_softc *sc)
+fsl_sdhc_get_clock(struct fsl_sdhci_softc *sc)
{
uint16_t val;
@@ -531,17 +539,20 @@ imx_sdhc_get_clock(struct imx_sdhci_softc *sc)
val |= SDHCI_CLOCK_INT_STABLE;
/*
- * On ESDHC hardware the card bus clock enable is in the usual sdhci
- * register but it's a different bit, so transcribe it (note the
+ * On i.MX ESDHC hardware the card bus clock enable is in the usual
+ * sdhci register but it's a different bit, so transcribe it (note the
* difference between standard SDHCI_ and Freescale SDHC_ prefixes
- * here). On USDHC hardware there is a force-on bit, but no force-off
- * for the card bus clock (the hardware runs the clock when transfers
- * are active no matter what), so we always say the clock is on.
+ * here). On USDHC and QorIQ ESDHC hardware there is a force-on bit, but
+ * no force-off for the card bus clock (the hardware runs the clock when
+ * transfers are active no matter what), so we always say the clock is
+ * on.
* XXX Maybe we should say it's in whatever state the sdhci driver last
* set it to.
*/
if (sc->hwtype == HWTYPE_ESDHC) {
+#ifdef __arm__
if (RD4(sc, SDHC_SYS_CTRL) & SDHC_CLK_SDCLKEN)
+#endif
val |= SDHCI_CLOCK_CARD_EN;
} else {
val |= SDHCI_CLOCK_CARD_EN;
@@ -551,7 +562,7 @@ imx_sdhc_get_clock(struct imx_sdhci_softc *sc)
}
static void
-imx_sdhc_set_clock(struct imx_sdhci_softc *sc, uint16_t val)
+fsl_sdhc_set_clock(struct fsl_sdhci_softc *sc, uint16_t val)
{
uint32_t divisor, freq, prescale, val32;
@@ -565,15 +576,18 @@ imx_sdhc_set_clock(struct imx_sdhci_softc *sc, uint16_t val)
sc->sdclockreg_freq_bits = val & SDHCI_DIVIDERS_MASK;
if (sc->hwtype == HWTYPE_ESDHC) {
/*
- * The ESDHC hardware requires the driver to manually start and
- * stop the sd bus clock. If the enable bit is not set, turn
- * off the clock in hardware and we're done, otherwise decode
- * the requested frequency. ESDHC hardware is sdhci 2.0; the
- * sdhci driver will use the original 8-bit divisor field and
- * the "base / 2^N" divisor scheme.
+ * The i.MX5 ESDHC hardware requires the driver to manually
+ * start and stop the sd bus clock. If the enable bit is not
+ * set, turn off the clock in hardware and we're done, otherwise
+ * decode the requested frequency. ESDHC hardware is sdhci 2.0;
+ * the sdhci driver will use the original 8-bit divisor field
+ * and the "base / 2^N" divisor scheme.
*/
if ((val & SDHCI_CLOCK_CARD_EN) == 0) {
+#ifdef __arm__
+ /* On QorIQ, this is a reserved bit. */
WR4(sc, SDHCI_CLOCK_CONTROL, val32 & ~SDHC_CLK_SDCLKEN);
+#endif
return;
}
@@ -625,11 +639,12 @@ imx_sdhc_set_clock(struct imx_sdhci_softc *sc, uint16_t val)
val32 &= ~(SDHC_CLK_DIVISOR_MASK | SDHC_CLK_PRESCALE_MASK);
val32 |= divisor << SDHC_CLK_DIVISOR_SHIFT;
val32 |= prescale << SDHC_CLK_PRESCALE_SHIFT;
+ val32 |= SDHC_CLK_IPGEN;
WR4(sc, SDHCI_CLOCK_CONTROL, val32);
}
static boolean_t
-imx_sdhci_r1bfix_is_wait_done(struct imx_sdhci_softc *sc)
+fsl_sdhci_r1bfix_is_wait_done(struct fsl_sdhci_softc *sc)
{
uint32_t inhibit;
@@ -646,7 +661,7 @@ imx_sdhci_r1bfix_is_wait_done(struct imx_sdhci_softc *sc)
if (inhibit && getsbinuptime() < sc->r1bfix_timeout_at) {
callout_reset_sbt(&sc->r1bfix_callout, SBT_1MS, 0,
- imx_sdhci_r1bfix_func, sc, 0);
+ fsl_sdhci_r1bfix_func, sc, 0);
return (false);
}
@@ -670,22 +685,22 @@ imx_sdhci_r1bfix_is_wait_done(struct imx_sdhci_softc *sc)
}
static void
-imx_sdhci_r1bfix_func(void * arg)
+fsl_sdhci_r1bfix_func(void * arg)
{
- struct imx_sdhci_softc *sc = arg;
+ struct fsl_sdhci_softc *sc = arg;
boolean_t r1bwait_done;
mtx_lock(&sc->slot.mtx);
- r1bwait_done = imx_sdhci_r1bfix_is_wait_done(sc);
+ r1bwait_done = fsl_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)
+fsl_sdhci_intr(void *arg)
{
- struct imx_sdhci_softc *sc = arg;
+ struct fsl_sdhci_softc *sc = arg;
uint32_t intmask;
mtx_lock(&sc->slot.mtx);
@@ -710,10 +725,10 @@ imx_sdhci_intr(void *arg)
*/
switch (sc->r1bfix_type) {
case R1BFIX_NODATA:
- intmask = RD4(sc, SDHC_INT_STATUS) & SDHCI_INT_RESPONSE;
+ intmask = RD4(sc, SDHCI_INT_STATUS) & SDHCI_INT_RESPONSE;
break;
case R1BFIX_AC12:
- intmask = RD4(sc, SDHC_INT_STATUS) & SDHCI_INT_DATA_END;
+ intmask = RD4(sc, SDHCI_INT_STATUS) & SDHCI_INT_DATA_END;
break;
default:
intmask = 0;
@@ -721,9 +736,9 @@ imx_sdhci_intr(void *arg)
}
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,
+ if (!fsl_sdhci_r1bfix_is_wait_done(sc)) {
+ WR4(sc, SDHCI_INT_STATUS, intmask);
+ bus_barrier(sc->mem_res, SDHCI_INT_STATUS, 4,
BUS_SPACE_BARRIER_WRITE);
}
}
@@ -733,31 +748,78 @@ imx_sdhci_intr(void *arg)
}
static int
-imx_sdhci_get_ro(device_t bus, device_t child)
+fsl_sdhci_get_ro(device_t bus, device_t child)
{
+ struct fsl_sdhci_softc *sc = device_get_softc(bus);
- return (false);
+ if (RD4(sc, SDHCI_PRESENT_STATE) & SDHC_PRES_WPSPL)
+ return (false);
+ return (true);
}
+#ifdef __powerpc__
+static uint32_t
+fsl_sdhci_get_platform_clock(device_t dev)
+{
+ device_t parent;
+ phandle_t node;
+ uint32_t clock;
+
+ node = ofw_bus_get_node(dev);
+
+ /* Get sdhci node properties */
+ if((OF_getprop(node, "clock-frequency", (void *)&clock,
+ sizeof(clock)) <= 0) || (clock == 0)) {
+
+ /*
+ * Trying to get clock from parent device (soc) if correct
+ * clock cannot be acquired from sdhci node.
+ */
+ parent = device_get_parent(dev);
+ node = ofw_bus_get_node(parent);
+
+ /* Get soc properties */
+ if ((OF_getprop(node, "bus-frequency", (void *)&clock,
+ sizeof(clock)) <= 0) || (clock == 0)) {
+ device_printf(dev,"Cannot acquire correct sdhci "
+ "frequency from DTS.\n");
+
+ return (0);
+ }
+ /* eSDHC clock is 1/2 platform clock. */
+ clock /= 2;
+ }
+
+ if (bootverbose)
+ device_printf(dev, "Acquired clock: %d from DTS\n", clock);
+
+ return (clock);
+}
+#endif
+
+
static int
-imx_sdhci_detach(device_t dev)
+fsl_sdhci_detach(device_t dev)
{
return (EBUSY);
}
static int
-imx_sdhci_attach(device_t dev)
+fsl_sdhci_attach(device_t dev)
{
- struct imx_sdhci_softc *sc = device_get_softc(dev);
+ struct fsl_sdhci_softc *sc = device_get_softc(dev);
int rid, err;
phandle_t node;
+#ifdef __powerpc__
+ uint32_t protctl;
+#endif
sc->dev = dev;
sc->hwtype = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
if (sc->hwtype == HWTYPE_NONE)
- panic("Impossible: not compatible in imx_sdhci_attach()");
+ panic("Impossible: not compatible in fsl_sdhci_attach()");
rid = 0;
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
@@ -778,7 +840,7 @@ imx_sdhci_attach(device_t dev)
}
if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
- NULL, imx_sdhci_intr, sc, &sc->intr_cookie)) {
+ NULL, fsl_sdhci_intr, sc, &sc->intr_cookie)) {
device_printf(dev, "cannot setup interrupt handler\n");
err = ENXIO;
goto fail;
@@ -807,9 +869,21 @@ imx_sdhci_attach(device_t dev)
*
* XXX need named constants for this stuff.
*/
- WR4(sc, SDHC_WTMK_LVL, 0x08800880);
+ /* P1022 has the '*_BRST_LEN' fields as reserved, always reading 0x10 */
+ if (ofw_bus_is_compatible(dev, "fsl,p1022-esdhc"))
+ WR4(sc, SDHC_WTMK_LVL, 0x10801080);
+ else
+ WR4(sc, SDHC_WTMK_LVL, 0x08800880);
+ /*
+ * We read in native byte order in the main driver, but the register
+ * defaults to little endian.
+ */
+#ifdef __powerpc__
+ sc->baseclk_hz = fsl_sdhci_get_platform_clock(dev);
+#else
sc->baseclk_hz = imx_ccm_sdhci_hz();
+#endif
sc->slot.max_clk = sc->baseclk_hz;
/*
@@ -830,6 +904,16 @@ imx_sdhci_attach(device_t dev)
/* XXX put real gpio hookup here. */
sc->force_card_present = true;
}
+#ifdef __powerpc__
+ /* Default to big-endian on powerpc */
+ protctl = RD4(sc, SDHC_PROT_CTRL);
+ protctl &= ~SDHC_PROT_EMODE_MASK;
+ if (OF_hasprop(node, "little-endian"))
+ protctl |= SDHC_PROT_EMODE_LITTLE;
+ else
+ protctl |= SDHC_PROT_EMODE_BIG;
+ WR4(sc, SDHC_PROT_CTRL, protctl);
+#endif
callout_init(&sc->r1bfix_callout, 1);
sdhci_init_slot(dev, &sc->slot, 0);
@@ -853,7 +937,7 @@ fail:
}
static int
-imx_sdhci_probe(device_t dev)
+fsl_sdhci_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
@@ -872,11 +956,11 @@ imx_sdhci_probe(device_t dev)
return (ENXIO);
}
-static device_method_t imx_sdhci_methods[] = {
+static device_method_t fsl_sdhci_methods[] = {
/* Device interface */
- DEVMETHOD(device_probe, imx_sdhci_probe),
- DEVMETHOD(device_attach, imx_sdhci_attach),
- DEVMETHOD(device_detach, imx_sdhci_detach),
+ DEVMETHOD(device_probe, fsl_sdhci_probe),
+ DEVMETHOD(device_attach, fsl_sdhci_attach),
+ DEVMETHOD(device_detach, fsl_sdhci_detach),
/* Bus interface */
DEVMETHOD(bus_read_ivar, sdhci_generic_read_ivar),
@@ -886,32 +970,32 @@ static device_method_t imx_sdhci_methods[] = {
/* MMC bridge interface */
DEVMETHOD(mmcbr_update_ios, sdhci_generic_update_ios),
DEVMETHOD(mmcbr_request, sdhci_generic_request),
- DEVMETHOD(mmcbr_get_ro, imx_sdhci_get_ro),
+ DEVMETHOD(mmcbr_get_ro, fsl_sdhci_get_ro),
DEVMETHOD(mmcbr_acquire_host, sdhci_generic_acquire_host),
DEVMETHOD(mmcbr_release_host, sdhci_generic_release_host),
/* SDHCI registers accessors */
- DEVMETHOD(sdhci_read_1, imx_sdhci_read_1),
- DEVMETHOD(sdhci_read_2, imx_sdhci_read_2),
- DEVMETHOD(sdhci_read_4, imx_sdhci_read_4),
- DEVMETHOD(sdhci_read_multi_4, imx_sdhci_read_multi_4),
- DEVMETHOD(sdhci_write_1, imx_sdhci_write_1),
- DEVMETHOD(sdhci_write_2, imx_sdhci_write_2),
- DEVMETHOD(sdhci_write_4, imx_sdhci_write_4),
- DEVMETHOD(sdhci_write_multi_4, imx_sdhci_write_multi_4),
+ DEVMETHOD(sdhci_read_1, fsl_sdhci_read_1),
+ DEVMETHOD(sdhci_read_2, fsl_sdhci_read_2),
+ DEVMETHOD(sdhci_read_4, fsl_sdhci_read_4),
+ DEVMETHOD(sdhci_read_multi_4, fsl_sdhci_read_multi_4),
+ DEVMETHOD(sdhci_write_1, fsl_sdhci_write_1),
+ DEVMETHOD(sdhci_write_2, fsl_sdhci_write_2),
+ DEVMETHOD(sdhci_write_4, fsl_sdhci_write_4),
+ DEVMETHOD(sdhci_write_multi_4, fsl_sdhci_write_multi_4),
{ 0, 0 }
};
-static devclass_t imx_sdhci_devclass;
+static devclass_t fsl_sdhci_devclass;
-static driver_t imx_sdhci_driver = {
- "sdhci_imx",
- imx_sdhci_methods,
- sizeof(struct imx_sdhci_softc),
+static driver_t fsl_sdhci_driver = {
+ "sdhci_fsl",
+ fsl_sdhci_methods,
+ sizeof(struct fsl_sdhci_softc),
};
-DRIVER_MODULE(sdhci_imx, simplebus, imx_sdhci_driver, imx_sdhci_devclass, 0, 0);
-MODULE_DEPEND(sdhci_imx, sdhci, 1, 1, 1);
-DRIVER_MODULE(mmc, sdhci_imx, mmc_driver, mmc_devclass, NULL, NULL);
-MODULE_DEPEND(sdhci_imx, mmc, 1, 1, 1);
+DRIVER_MODULE(sdhci_fsl, simplebus, fsl_sdhci_driver, fsl_sdhci_devclass, 0, 0);
+MODULE_DEPEND(sdhci_fsl, sdhci, 1, 1, 1);
+DRIVER_MODULE(mmc, sdhci_fsl, mmc_driver, mmc_devclass, NULL, NULL);
+MODULE_DEPEND(sdhci_fsl, mmc, 1, 1, 1);
diff --git a/sys/powerpc/mpc85xx/fsl_sdhc.c b/sys/powerpc/mpc85xx/fsl_sdhc.c
deleted file mode 100644
index 03e6bdd..0000000
--- a/sys/powerpc/mpc85xx/fsl_sdhc.c
+++ /dev/null
@@ -1,1303 +0,0 @@
-/*-
- * Copyright (c) 2011-2012 Semihalf
- * 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.
- */
-
-/*
- * Driver for Freescale integrated eSDHC controller.
- * Limitations:
- * - No support for multi-block transfers.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/rman.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
-#include <sys/taskqueue.h>
-
-#include <machine/bus.h>
-#include <machine/vmparam.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/mmcreg.h>
-#include <dev/mmc/mmcvar.h>
-#include <dev/mmc/mmcbrvar.h>
-
-#include <powerpc/mpc85xx/mpc85xx.h>
-
-#include "opt_platform.h"
-
-#include "mmcbr_if.h"
-
-#include "fsl_sdhc.h"
-
-#ifdef DEBUG
-#define DPRINTF(fmt, arg...) printf("DEBUG %s(): " fmt, __FUNCTION__, ##arg)
-#else
-#define DPRINTF(fmt, arg...)
-#endif
-
-
-/*****************************************************************************
- * Register the driver
- *****************************************************************************/
-/* Forward declarations */
-static int fsl_sdhc_probe(device_t);
-static int fsl_sdhc_attach(device_t);
-static int fsl_sdhc_detach(device_t);
-
-static int fsl_sdhc_read_ivar(device_t, device_t, int, uintptr_t *);
-static int fsl_sdhc_write_ivar(device_t, device_t, int, uintptr_t);
-
-static int fsl_sdhc_update_ios(device_t, device_t);
-static int fsl_sdhc_request(device_t, device_t, struct mmc_request *);
-static int fsl_sdhc_get_ro(device_t, device_t);
-static int fsl_sdhc_acquire_host(device_t, device_t);
-static int fsl_sdhc_release_host(device_t, device_t);
-
-static device_method_t fsl_sdhc_methods[] = {
- /* device_if */
- DEVMETHOD(device_probe, fsl_sdhc_probe),
- DEVMETHOD(device_attach, fsl_sdhc_attach),
- DEVMETHOD(device_detach, fsl_sdhc_detach),
-
- /* Bus interface */
- DEVMETHOD(bus_read_ivar, fsl_sdhc_read_ivar),
- DEVMETHOD(bus_write_ivar, fsl_sdhc_write_ivar),
-
- /* OFW bus interface */
- DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
- DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
- DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
- DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
- DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
-
- /* mmcbr_if */
- DEVMETHOD(mmcbr_update_ios, fsl_sdhc_update_ios),
- DEVMETHOD(mmcbr_request, fsl_sdhc_request),
- DEVMETHOD(mmcbr_get_ro, fsl_sdhc_get_ro),
- DEVMETHOD(mmcbr_acquire_host, fsl_sdhc_acquire_host),
- DEVMETHOD(mmcbr_release_host, fsl_sdhc_release_host),
-
- {0, 0},
-};
-
-/* kobj_class definition */
-static driver_t fsl_sdhc_driver = {
- "sdhci_fsl",
- fsl_sdhc_methods,
- sizeof(struct fsl_sdhc_softc)
-};
-
-static devclass_t fsl_sdhc_devclass;
-
-DRIVER_MODULE(sdhci_fsl, simplebus, fsl_sdhc_driver, fsl_sdhc_devclass, 0, 0);
-DRIVER_MODULE(mmc, sdhci_fsl, mmc_driver, mmc_devclass, NULL, NULL);
-MODULE_DEPEND(sdhci_fsl, mmc, 1, 1, 1);
-
-/*****************************************************************************
- * Private methods
- *****************************************************************************/
-static inline int
-read4(struct fsl_sdhc_softc *sc, unsigned int offset)
-{
-
- return bus_space_read_4(sc->bst, sc->bsh, offset);
-}
-
-static inline void
-write4(struct fsl_sdhc_softc *sc, unsigned int offset, int value)
-{
-
- bus_space_write_4(sc->bst, sc->bsh, offset, value);
-}
-
-static inline void
-set_bit(struct fsl_sdhc_softc *sc, uint32_t offset, uint32_t mask)
-{
- uint32_t x = read4(sc, offset);
-
- write4(sc, offset, x | mask);
-}
-
-static inline void
-clear_bit(struct fsl_sdhc_softc *sc, uint32_t offset, uint32_t mask)
-{
- uint32_t x = read4(sc, offset);
-
- write4(sc, offset, x & ~mask);
-}
-
-static int
-wait_for_bit_clear(struct fsl_sdhc_softc *sc, enum sdhc_reg_off reg,
- uint32_t bit)
-{
- uint32_t timeout = 10;
- uint32_t stat;
-
- stat = read4(sc, reg);
- while (stat & bit) {
- if (timeout == 0) {
- return (-1);
- }
- --timeout;
- DELAY(1000);
- stat = read4(sc, reg);
- }
-
- return (0);
-}
-
-static int
-wait_for_free_line(struct fsl_sdhc_softc *sc, enum sdhc_line line)
-{
- uint32_t timeout = 100;
- uint32_t stat;
-
- stat = read4(sc, SDHC_PRSSTAT);
- while (stat & line) {
- if (timeout == 0) {
- return (-1);
- }
- --timeout;
- DELAY(1000);
- stat = read4(sc, SDHC_PRSSTAT);
- }
-
- return (0);
-}
-
-static uint32_t
-get_platform_clock(struct fsl_sdhc_softc *sc)
-{
- device_t self, parent;
- phandle_t node;
- uint32_t clock;
-
- self = sc->self;
- node = ofw_bus_get_node(self);
-
- /* Get sdhci node properties */
- if((OF_getprop(node, "clock-frequency", (void *)&clock,
- sizeof(clock)) <= 0) || (clock == 0)) {
-
- /*
- * Trying to get clock from parent device (soc) if correct
- * clock cannot be acquired from sdhci node.
- */
- parent = device_get_parent(self);
- node = ofw_bus_get_node(parent);
-
- /* Get soc properties */
- if ((OF_getprop(node, "bus-frequency", (void *)&clock,
- sizeof(clock)) <= 0) || (clock == 0)) {
- device_printf(self,"Cannot acquire correct sdhci "
- "frequency from DTS.\n");
-
- return (0);
- }
- }
-
- DPRINTF("Acquired clock: %d from DTS\n", clock);
-
- return (clock);
-}
-
-/**
- * Set clock driving card.
- * @param sc
- * @param clock Desired clock frequency in Hz
- */
-static void
-set_clock(struct fsl_sdhc_softc *sc, uint32_t clock)
-{
- uint32_t base_clock;
- uint32_t divisor, prescaler = 1;
- uint32_t round = 0;
-
- if (clock == sc->slot.clock)
- return;
-
- if (clock == 0) {
- clear_bit(sc, SDHC_SYSCTL, MASK_CLOCK_CONTROL | SYSCTL_PEREN |
- SYSCTL_HCKEN | SYSCTL_IPGEN);
- return;
- }
-
- base_clock = sc->platform_clock;
- round = base_clock & 0x2;
- base_clock >>= 2;
- base_clock += round;
- round = 0;
-
- /* SD specification 1.1 doesn't allow frequences above 50 MHz */
- if (clock > FSL_SDHC_MAX_CLOCK)
- clock = FSL_SDHC_MAX_CLOCK;
-
- /*
- * divisor = ceil(base_clock / clock)
- * TODO: Reconsider symmetric rounding here instead of ceiling.
- */
- divisor = howmany(base_clock, clock);
-
- while (divisor > 16) {
- round = divisor & 0x1;
- divisor >>= 1;
-
- prescaler <<= 1;
- }
- divisor += round - 1;
-
- /* Turn off the clock. */
- clear_bit(sc, SDHC_SYSCTL, MASK_CLOCK_CONTROL);
-
- /* Write clock settings. */
- set_bit(sc, SDHC_SYSCTL, (prescaler << SHIFT_SDCLKFS) |
- (divisor << SHIFT_DVS));
-
- /*
- * Turn on clocks.
- * TODO: This actually disables clock automatic gating off feature of
- * the controller which eventually should be enabled but as for now
- * it prevents controller from generating card insertion/removal
- * interrupts correctly.
- */
- set_bit(sc, SDHC_SYSCTL, SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN);
-
- sc->slot.clock = clock;
-
- DPRINTF("given clock = %d, computed clock = %d\n", clock,
- (base_clock / prescaler) / (divisor + 1));
-}
-
-static inline void
-send_80_clock_ticks(struct fsl_sdhc_softc *sc)
-{
- int err;
-
- err = wait_for_free_line(sc, SDHC_CMD_LINE | SDHC_DAT_LINE);
- if (err != 0) {
- device_printf(sc->self, "Can't acquire data/cmd lines\n");
- return;
- }
-
- set_bit(sc, SDHC_SYSCTL, SYSCTL_INITA);
- err = wait_for_bit_clear(sc, SDHC_SYSCTL, SYSCTL_INITA);
- if (err != 0) {
- device_printf(sc->self, "Can't send 80 clocks to the card.\n");
- }
-}
-
-static void
-set_bus_width(struct fsl_sdhc_softc *sc, enum mmc_bus_width width)
-{
-
- DPRINTF("setting bus width to %d\n", width);
- switch (width) {
- case bus_width_1:
- set_bit(sc, SDHC_PROCTL, DTW_1);
- break;
- case bus_width_4:
- set_bit(sc, SDHC_PROCTL, DTW_4);
- break;
- case bus_width_8:
- set_bit(sc, SDHC_PROCTL, DTW_8);
- break;
- default:
- device_printf(sc->self, "Unsupported bus width\n");
- }
-}
-
-static void
-reset_controller_all(struct fsl_sdhc_softc *sc)
-{
- uint32_t count = 5;
-
- set_bit(sc, SDHC_SYSCTL, SYSCTL_RSTA);
- while (read4(sc, SDHC_SYSCTL) & SYSCTL_RSTA) {
- DELAY(FSL_SDHC_RESET_DELAY);
- --count;
- if (count == 0) {
- device_printf(sc->self,
- "Can't reset the controller\n");
- return;
- }
- }
-}
-
-static void
-reset_controller_dat_cmd(struct fsl_sdhc_softc *sc)
-{
- int err;
-
- set_bit(sc, SDHC_SYSCTL, SYSCTL_RSTD | SYSCTL_RSTC);
- err = wait_for_bit_clear(sc, SDHC_SYSCTL, SYSCTL_RSTD | SYSCTL_RSTC);
- if (err != 0) {
- device_printf(sc->self, "Can't reset data & command part!\n");
- return;
- }
-}
-
-static void
-init_controller(struct fsl_sdhc_softc *sc)
-{
-
- /* Enable interrupts. */
-#ifdef FSL_SDHC_NO_DMA
- write4(sc, SDHC_IRQSTATEN, MASK_IRQ_ALL & ~IRQ_DINT & ~IRQ_DMAE);
- write4(sc, SDHC_IRQSIGEN, MASK_IRQ_ALL & ~IRQ_DINT & ~IRQ_DMAE);
-#else
- write4(sc, SDHC_IRQSTATEN, MASK_IRQ_ALL & ~IRQ_BRR & ~IRQ_BWR);
- write4(sc, SDHC_IRQSIGEN, MASK_IRQ_ALL & ~IRQ_BRR & ~IRQ_BWR);
-
- /* Write DMA address */
- write4(sc, SDHC_DSADDR, sc->dma_phys);
-
- /* Enable snooping and fix for AHB2MAG bypass. */
- write4(sc, SDHC_DCR, DCR_SNOOP | DCR_AHB2MAG_BYPASS);
-#endif
- /* Set data timeout. */
- set_bit(sc, SDHC_SYSCTL, 0xe << SHIFT_DTOCV);
-
- /* Set water-mark levels (FIFO buffer size). */
- write4(sc, SDHC_WML, (FSL_SDHC_FIFO_BUF_WORDS << 16) |
- FSL_SDHC_FIFO_BUF_WORDS);
-}
-
-static void
-init_mmc_host_struct(struct fsl_sdhc_softc *sc)
-{
- struct mmc_host *host = &sc->mmc_host;
-
- /* Clear host structure. */
- bzero(host, sizeof(struct mmc_host));
-
- /* Calculate minimum and maximum operating frequencies. */
- host->f_min = sc->platform_clock / FSL_SDHC_MAX_DIV;
- host->f_max = FSL_SDHC_MAX_CLOCK;
-
- /* Set operation conditions (voltage). */
- host->host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
-
- /* Set additional host controller capabilities. */
- host->caps = MMC_CAP_4_BIT_DATA;
-
- /* Set mode. */
- host->mode = mode_sd;
-}
-
-static void
-card_detect_task(void *arg, int pending)
-{
- struct fsl_sdhc_softc *sc = (struct fsl_sdhc_softc *)arg;
- int err;
- int insert;
-
- insert = read4(sc, SDHC_PRSSTAT) & PRSSTAT_CINS;
-
- mtx_lock(&sc->mtx);
-
- if (insert) {
- if (sc->child != NULL) {
- mtx_unlock(&sc->mtx);
- return;
- }
-
- sc->child = device_add_child(sc->self, "mmc", -1);
- if (sc->child == NULL) {
- device_printf(sc->self, "Couldn't add MMC bus!\n");
- mtx_unlock(&sc->mtx);
- return;
- }
-
- /* Initialize MMC bus host structure. */
- init_mmc_host_struct(sc);
- device_set_ivars(sc->child, &sc->mmc_host);
-
- } else {
- if (sc->child == NULL) {
- mtx_unlock(&sc->mtx);
- return;
- }
- }
-
- mtx_unlock(&sc->mtx);
-
- if (insert) {
- if ((err = device_probe_and_attach(sc->child)) != 0) {
- device_printf(sc->self, "MMC bus failed on probe "
- "and attach! error %d\n", err);
- device_delete_child(sc->self, sc->child);
- sc->child = NULL;
- }
- } else {
- if (device_delete_child(sc->self, sc->child) != 0)
- device_printf(sc->self, "Could not delete MMC bus!\n");
- sc->child = NULL;
- }
-}
-
-static void
-card_detect_delay(void *arg)
-{
- struct fsl_sdhc_softc *sc = arg;
-
- taskqueue_enqueue(taskqueue_swi_giant, &sc->card_detect_task);
-}
-
-static void
-finalize_request(struct fsl_sdhc_softc *sc)
-{
-
- DPRINTF("finishing request %p\n", sc->request);
-
- sc->request->done(sc->request);
- sc->request = NULL;
-}
-
-/**
- * Read response from card.
- * @todo Implement Auto-CMD responses being held in R3 for multi-block xfers.
- * @param sc
- */
-static void
-get_response(struct fsl_sdhc_softc *sc)
-{
- struct mmc_command *cmd = sc->request->cmd;
- int i;
- uint32_t val;
- uint8_t ext = 0;
-
- if (cmd->flags & MMC_RSP_136) {
- /* CRC is stripped, need to shift one byte left. */
- for (i = 0; i < 4; i++) {
- val = read4(sc, SDHC_CMDRSP0 + i * 4);
- cmd->resp[3 - i] = (val << 8) + ext;
- ext = val >> 24;
- }
- } else {
- cmd->resp[0] = read4(sc, SDHC_CMDRSP0);
- }
-}
-
-#ifdef FSL_SDHC_NO_DMA
-/**
- * Read all content of a fifo buffer.
- * @warning Assumes data buffer is 32-bit aligned.
- * @param sc
- */
-static void
-read_block_pio(struct fsl_sdhc_softc *sc)
-{
- struct mmc_data *data = sc->request->cmd->data;
- size_t left = min(FSL_SDHC_FIFO_BUF_SIZE, data->len);
- uint8_t *buf = data->data;
- uint32_t word;
-
- buf += sc->data_offset;
- bus_space_read_multi_4(sc->bst, sc->bsh, SDHC_DATPORT, (uint32_t *)buf,
- left >> 2);
-
- sc->data_offset += left;
-
- /* Handle 32-bit unaligned size case. */
- left &= 0x3;
- if (left > 0) {
- buf = (uint8_t *)data->data + (sc->data_offset & ~0x3);
- word = read4(sc, SDHC_DATPORT);
- while (left > 0) {
- *(buf++) = word;
- word >>= 8;
- --left;
- }
- }
-}
-
-/**
- * Write a fifo buffer.
- * @warning Assumes data buffer size is 32-bit aligned.
- * @param sc
- */
-static void
-write_block_pio(struct fsl_sdhc_softc *sc)
-{
- struct mmc_data *data = sc->request->cmd->data;
- size_t left = min(FSL_SDHC_FIFO_BUF_SIZE, data->len);
- uint8_t *buf = data->data;
- uint32_t word = 0;
-
- DPRINTF("sc->data_offset %d\n", sc->data_offset);
-
- buf += sc->data_offset;
- bus_space_write_multi_4(sc->bst, sc->bsh, SDHC_DATPORT, (uint32_t *)buf,
- left >> 2);
-
- sc->data_offset += left;
-
- /* Handle 32-bit unaligned size case. */
- left &= 0x3;
- if (left > 0) {
- buf = (uint8_t *)data->data + (sc->data_offset & ~0x3);
- while (left > 0) {
- word += *(buf++);
- word <<= 8;
- --left;
- }
- write4(sc, SDHC_DATPORT, word);
- }
-}
-
-static void
-pio_read_transfer(struct fsl_sdhc_softc *sc)
-{
-
- while (read4(sc, SDHC_PRSSTAT) & PRSSTAT_BREN) {
- read_block_pio(sc);
-
- /*
- * TODO: should we check here whether data_offset >= data->len?
- */
- }
-}
-
-static void
-pio_write_transfer(struct fsl_sdhc_softc *sc)
-{
-
- while (read4(sc, SDHC_PRSSTAT) & PRSSTAT_BWEN) {
- write_block_pio(sc);
-
- /*
- * TODO: should we check here whether data_offset >= data->len?
- */
- }
-}
-#endif /* FSL_SDHC_USE_DMA */
-
-static inline void
-handle_command_intr(struct fsl_sdhc_softc *sc, uint32_t irq_stat)
-{
- struct mmc_command *cmd = sc->request->cmd;
-
- /* Handle errors. */
- if (irq_stat & IRQ_CTOE) {
- cmd->error = MMC_ERR_TIMEOUT;
- } else if (irq_stat & IRQ_CCE) {
- cmd->error = MMC_ERR_BADCRC;
- } else if (irq_stat & (IRQ_CEBE | IRQ_CIE)) {
- cmd->error = MMC_ERR_FIFO;
- }
-
- if (cmd->error) {
- device_printf(sc->self, "Error interrupt occured\n");
- reset_controller_dat_cmd(sc);
- return;
- }
-
- if (sc->command_done)
- return;
-
- if (irq_stat & IRQ_CC) {
- sc->command_done = 1;
-
- if (cmd->flags & MMC_RSP_PRESENT)
- get_response(sc);
- }
-}
-
-static inline void
-handle_data_intr(struct fsl_sdhc_softc *sc, uint32_t irq_stat)
-{
- struct mmc_command *cmd = sc->request->cmd;
-
- /* Handle errors. */
- if (irq_stat & IRQ_DTOE) {
- cmd->error = MMC_ERR_TIMEOUT;
- } else if (irq_stat & (IRQ_DCE | IRQ_DEBE)) {
- cmd->error = MMC_ERR_BADCRC;
- } else if (irq_stat & IRQ_ERROR_DATA_MASK) {
- cmd->error = MMC_ERR_FAILED;
- }
-
- if (cmd->error) {
- device_printf(sc->self, "Error interrupt occured\n");
- sc->data_done = 1;
- reset_controller_dat_cmd(sc);
- return;
- }
-
- if (sc->data_done)
- return;
-
-#ifdef FSL_SDHC_NO_DMA
- if (irq_stat & IRQ_BRR) {
- pio_read_transfer(sc);
- }
-
- if (irq_stat & IRQ_BWR) {
- pio_write_transfer(sc);
- }
-#else
- if (irq_stat & IRQ_DINT) {
- struct mmc_data *data = sc->request->cmd->data;
-
- /* Synchronize DMA. */
- if (data->flags & MMC_DATA_READ) {
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_POSTREAD);
- memcpy(data->data, sc->dma_mem, data->len);
- } else {
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_POSTWRITE);
- }
-
- /*
- * TODO: For multiple block transfers, address of dma memory
- * in DSADDR register should be set to the beginning of the
- * segment here. Also offset to data pointer should be handled.
- */
- }
-#endif
-
- if (irq_stat & IRQ_TC)
- sc->data_done = 1;
-}
-
-static void
-interrupt_handler(void *arg)
-{
- struct fsl_sdhc_softc *sc = (struct fsl_sdhc_softc *)arg;
- uint32_t irq_stat;
-
- mtx_lock(&sc->mtx);
-
- irq_stat = read4(sc, SDHC_IRQSTAT);
-
- /* Card interrupt. */
- if (irq_stat & IRQ_CINT) {
- DPRINTF("Card interrupt recievied\n");
-
- }
-
- /* Card insertion interrupt. */
- if (irq_stat & IRQ_CINS) {
- clear_bit(sc, SDHC_IRQSIGEN, IRQ_CINS);
- clear_bit(sc, SDHC_IRQSTATEN, IRQ_CINS);
- set_bit(sc, SDHC_IRQSIGEN, IRQ_CRM);
- set_bit(sc, SDHC_IRQSTATEN, IRQ_CRM);
-
- callout_reset(&sc->card_detect_callout, hz / 2,
- card_detect_delay, sc);
- }
-
- /* Card removal interrupt. */
- if (irq_stat & IRQ_CRM) {
- clear_bit(sc, SDHC_IRQSIGEN, IRQ_CRM);
- clear_bit(sc, SDHC_IRQSTATEN, IRQ_CRM);
- set_bit(sc, SDHC_IRQSIGEN, IRQ_CINS);
- set_bit(sc, SDHC_IRQSTATEN, IRQ_CINS);
-
- callout_stop(&sc->card_detect_callout);
- taskqueue_enqueue(taskqueue_swi_giant, &sc->card_detect_task);
- }
-
- /* Handle request interrupts. */
- if (sc->request) {
- handle_command_intr(sc, irq_stat);
- handle_data_intr(sc, irq_stat);
-
- /*
- * Finalize request when transfer is done successfully
- * or was interrupted due to error.
- */
- if ((sc->data_done && sc->command_done) ||
- (sc->request->cmd->error))
- finalize_request(sc);
- }
-
- /* Clear status register. */
- write4(sc, SDHC_IRQSTAT, irq_stat);
-
- mtx_unlock(&sc->mtx);
-}
-
-#ifndef FSL_SDHC_NO_DMA
-static void
-dma_get_phys_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
-{
-
- if (error != 0)
- return;
-
- /* Get first segment's physical address. */
- *(bus_addr_t *)arg = segs->ds_addr;
-}
-
-static int
-init_dma(struct fsl_sdhc_softc *sc)
-{
- device_t self = sc->self;
- int err;
-
- err = bus_dma_tag_create(bus_get_dma_tag(self),
- FSL_SDHC_DMA_BLOCK_SIZE, 0, BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR, NULL, NULL, FSL_SDHC_DMA_BLOCK_SIZE, 1,
- FSL_SDHC_DMA_BLOCK_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL,
- &sc->dma_tag);
-
- if (err) {
- device_printf(self, "Could not create DMA tag!\n");
- return (-1);
- }
-
- err = bus_dmamem_alloc(sc->dma_tag, (void **)&(sc->dma_mem),
- BUS_DMA_NOWAIT | BUS_DMA_NOCACHE, &sc->dma_map);
- if (err) {
- device_printf(self, "Could not allocate DMA memory!\n");
- goto fail1;
- }
-
- err = bus_dmamap_load(sc->dma_tag, sc->dma_map, (void *)sc->dma_mem,
- FSL_SDHC_DMA_BLOCK_SIZE, dma_get_phys_addr, &sc->dma_phys, 0);
- if (err) {
- device_printf(self, "Could not load DMA map!\n");
- goto fail2;
- }
-
- return (0);
-
-fail2:
- bus_dmamem_free(sc->dma_tag, sc->dma_mem, sc->dma_map);
-fail1:
- bus_dma_tag_destroy(sc->dma_tag);
-
- return (-1);
-}
-#endif /* FSL_SDHC_NO_DMA */
-
-static uint32_t
-set_xfertyp_register(const struct mmc_command *cmd)
-{
- uint32_t xfertyp = 0;
-
- /* Set command index. */
- xfertyp |= cmd->opcode << CMDINX_SHIFT;
-
- /* Set command type. */
- if (cmd->opcode == MMC_STOP_TRANSMISSION)
- xfertyp |= CMDTYP_ABORT;
-
- /* Set data preset select. */
- if (cmd->data) {
- xfertyp |= XFERTYP_DPSEL;
-
- /* Set transfer direction. */
- if (cmd->data->flags & MMC_DATA_READ)
- xfertyp |= XFERTYP_DTDSEL;
- }
-
- /* Set command index check. */
- if (cmd->flags & MMC_RSP_OPCODE)
- xfertyp |= XFERTYP_CICEN;
-
- /* Set command CRC check. */
- if (cmd->flags & MMC_RSP_CRC)
- xfertyp |= XFERTYP_CCCEN;
-
- /* Set response type */
- if (!(cmd->flags & MMC_RSP_PRESENT))
- xfertyp |= RSPTYP_NONE;
- else if (cmd->flags & MMC_RSP_136)
- xfertyp |= RSPTYP_136;
- else if (cmd->flags & MMC_RSP_BUSY)
- xfertyp |= RSPTYP_48_BUSY;
- else
- xfertyp |= RSPTYP_48;
-
-#ifndef FSL_SDHC_NO_DMA
- /* Enable DMA */
- xfertyp |= XFERTYP_DMAEN;
-#endif
-
- return (xfertyp);
-}
-
-static uint32_t
-set_blkattr_register(const struct mmc_data *data)
-{
-
- if (data->len <= FSL_SDHC_MAX_BLOCK_SIZE) {
- /* One block transfer. */
- return (BLKATTR_BLOCK_COUNT(1) | ((data->len) &
- BLKATTR_BLKSZE));
- }
-
- /* TODO: Write code here for multi-block transfers. */
- return (0);
-}
-
-/**
- * Initiate data transfer. Interrupt handler will finalize it.
- * @todo Implement multi-block transfers.
- * @param sc
- * @param cmd
- */
-static int
-start_data(struct fsl_sdhc_softc *sc, struct mmc_data *data)
-{
- uint32_t reg;
-
- if ((uint32_t)data->data & 0x3) {
- device_printf(sc->self, "32-bit unaligned data pointer in "
- "request\n");
- return (-1);
- }
-
- sc->data_done = 0;
-
-#ifdef FSL_SDHC_NO_DMA
- sc->data_ptr = data->data;
- sc->data_offset = 0;
-#else
- /* Write DMA address register. */
- write4(sc, SDHC_DSADDR, sc->dma_phys);
-
- /* Synchronize DMA. */
- if (data->flags & MMC_DATA_READ) {
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_PREREAD);
- } else {
- memcpy(sc->dma_mem, data->data, data->len);
- bus_dmamap_sync(sc->dma_tag, sc->dma_map,
- BUS_DMASYNC_PREWRITE);
- }
-#endif
- /* Set block size and count. */
- reg = set_blkattr_register(data);
- if (reg == 0) {
- device_printf(sc->self, "Requested unsupported multi-block "
- "transfer.\n");
- return (-1);
- }
- write4(sc, SDHC_BLKATTR, reg);
-
- return (0);
-}
-
-static int
-start_command(struct fsl_sdhc_softc *sc, struct mmc_command *cmd)
-{
- struct mmc_request *req = sc->request;
- uint32_t mask;
- uint32_t xfertyp;
- int err;
-
- DPRINTF("opcode %d, flags 0x%08x\n", cmd->opcode, cmd->flags);
- DPRINTF("PRSSTAT = 0x%08x\n", read4(sc, SDHC_PRSSTAT));
-
- sc->command_done = 0;
-
- cmd->error = MMC_ERR_NONE;
-
- /* TODO: should we check here for card presence and clock settings? */
-
- /* Always wait for free CMD line. */
- mask = SDHC_CMD_LINE;
- /* Wait for free DAT if we have data or busy signal. */
- if (cmd->data || (cmd->flags & MMC_RSP_BUSY))
- mask |= SDHC_DAT_LINE;
- /* We shouldn't wait for DAT for stop commands. */
- if (cmd == req->stop)
- mask &= ~SDHC_DAT_LINE;
- err = wait_for_free_line(sc, mask);
- if (err != 0) {
- device_printf(sc->self, "Controller never released inhibit "
- "bit(s).\n");
- reset_controller_dat_cmd(sc);
- cmd->error = MMC_ERR_FAILED;
- sc->request = NULL;
- req->done(req);
- return (-1);
- }
-
- xfertyp = set_xfertyp_register(cmd);
-
- if (cmd->data != NULL) {
- err = start_data(sc, cmd->data);
- if (err != 0) {
- device_printf(sc->self,
- "Data transfer request failed\n");
- reset_controller_dat_cmd(sc);
- cmd->error = MMC_ERR_FAILED;
- sc->request = NULL;
- req->done(req);
- return (-1);
- }
- }
-
- write4(sc, SDHC_CMDARG, cmd->arg);
- write4(sc, SDHC_XFERTYP, xfertyp);
-
- DPRINTF("XFERTYP = 0x%08x\n", xfertyp);
- DPRINTF("CMDARG = 0x%08x\n", cmd->arg);
-
- return (0);
-}
-
-#ifdef DEBUG
-static void
-dump_registers(struct fsl_sdhc_softc *sc)
-{
- printf("PRSSTAT = 0x%08x\n", read4(sc, SDHC_PRSSTAT));
- printf("PROCTL = 0x%08x\n", read4(sc, SDHC_PROCTL));
- printf("HOSTCAPBLT = 0x%08x\n", read4(sc, SDHC_HOSTCAPBLT));
- printf("IRQSTAT = 0x%08x\n", read4(sc, SDHC_IRQSTAT));
- printf("IRQSTATEN = 0x%08x\n", read4(sc, SDHC_IRQSTATEN));
- printf("IRQSIGEN = 0x%08x\n", read4(sc, SDHC_IRQSIGEN));
- printf("WML = 0x%08x\n", read4(sc, SDHC_WML));
- printf("DSADDR = 0x%08x\n", read4(sc, SDHC_DSADDR));
- printf("XFERTYP = 0x%08x\n", read4(sc, SDHC_XFERTYP));
- printf("DCR = 0x%08x\n", read4(sc, SDHC_DCR));
-}
-#endif
-
-/*****************************************************************************
- * Public methods
- *****************************************************************************/
-/*
- * Device interface methods.
- */
-static int
-fsl_sdhc_probe(device_t self)
-{
- static const char *desc =
- "Freescale Enhanced Secure Digital Host Controller";
-
- if (!ofw_bus_is_compatible(self, "fsl,p2020-esdhc") &&
- !ofw_bus_is_compatible(self, "fsl,esdhc"))
- return (ENXIO);
-
- device_set_desc(self, desc);
-
- return (BUS_PROBE_VENDOR);
-}
-
-static int
-fsl_sdhc_attach(device_t self)
-{
- struct fsl_sdhc_softc *sc;
-
- sc = device_get_softc(self);
-
- sc->self = self;
-
- mtx_init(&sc->mtx, device_get_nameunit(self), NULL, MTX_DEF);
-
- /* Setup memory resource */
- sc->mem_rid = 0;
- sc->mem_resource = bus_alloc_resource_any(self, SYS_RES_MEMORY,
- &sc->mem_rid, RF_ACTIVE);
- if (sc->mem_resource == NULL) {
- device_printf(self, "Could not allocate memory.\n");
- goto fail;
- }
- sc->bst = rman_get_bustag(sc->mem_resource);
- sc->bsh = rman_get_bushandle(sc->mem_resource);
-
- /* Setup interrupt resource. */
- sc->irq_rid = 0;
- sc->irq_resource = bus_alloc_resource_any(self, SYS_RES_IRQ,
- &sc->irq_rid, RF_ACTIVE);
- if (sc->irq_resource == NULL) {
- device_printf(self, "Could not allocate interrupt.\n");
- goto fail;
- }
- if (bus_setup_intr(self, sc->irq_resource, INTR_TYPE_MISC |
- INTR_MPSAFE, NULL, interrupt_handler, sc, &sc->ihl) != 0) {
- device_printf(self, "Could not setup interrupt.\n");
- goto fail;
- }
-
- /* Setup DMA. */
-#ifndef FSL_SDHC_NO_DMA
- if (init_dma(sc) != 0) {
- device_printf(self, "Could not setup DMA\n");
- }
-#endif
- sc->bus_busy = 0;
- sc->platform_clock = get_platform_clock(sc);
- if (sc->platform_clock == 0) {
- device_printf(self, "Could not get platform clock.\n");
- goto fail;
- }
- sc->command_done = 1;
- sc->data_done = 1;
-
- /* Init card detection task. */
- TASK_INIT(&sc->card_detect_task, 0, card_detect_task, sc);
- callout_init(&sc->card_detect_callout, 1);
-
- reset_controller_all(sc);
- init_controller(sc);
- set_clock(sc, 400000);
- send_80_clock_ticks(sc);
-
-#ifdef DEBUG
- dump_registers(sc);
-#endif
-
- return (0);
-
-fail:
- fsl_sdhc_detach(self);
- return (ENXIO);
-}
-
-static int
-fsl_sdhc_detach(device_t self)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
- int err;
-
- if (sc->child)
- device_delete_child(self, sc->child);
-
- taskqueue_drain(taskqueue_swi_giant, &sc->card_detect_task);
-
-#ifndef FSL_SDHC_NO_DMA
- bus_dmamap_unload(sc->dma_tag, sc->dma_map);
- bus_dmamem_free(sc->dma_tag, sc->dma_mem, sc->dma_map);
- bus_dma_tag_destroy(sc->dma_tag);
-#endif
-
- if (sc->ihl != NULL) {
- err = bus_teardown_intr(self, sc->irq_resource, sc->ihl);
- if (err)
- return (err);
- }
- if (sc->irq_resource != NULL) {
- err = bus_release_resource(self, SYS_RES_IRQ, sc->irq_rid,
- sc->irq_resource);
- if (err)
- return (err);
-
- }
- if (sc->mem_resource != NULL) {
- err = bus_release_resource(self, SYS_RES_MEMORY, sc->mem_rid,
- sc->mem_resource);
- if (err)
- return (err);
- }
-
- mtx_destroy(&sc->mtx);
-
- return (0);
-}
-
-
-/*
- * Bus interface methods.
- */
-static int
-fsl_sdhc_read_ivar(device_t self, device_t child, int index,
- uintptr_t *result)
-{
- struct mmc_host *host = device_get_ivars(child);
-
- switch (index) {
- case MMCBR_IVAR_BUS_MODE:
- *(int *)result = host->ios.bus_mode;
- break;
- case MMCBR_IVAR_BUS_WIDTH:
- *(int *)result = host->ios.bus_width;
- break;
- case MMCBR_IVAR_CHIP_SELECT:
- *(int *)result = host->ios.chip_select;
- break;
- case MMCBR_IVAR_CLOCK:
- *(int *)result = host->ios.clock;
- break;
- case MMCBR_IVAR_F_MIN:
- *(int *)result = host->f_min;
- break;
- case MMCBR_IVAR_F_MAX:
- *(int *)result = host->f_max;
- break;
- case MMCBR_IVAR_HOST_OCR:
- *(int *)result = host->host_ocr;
- break;
- case MMCBR_IVAR_MODE:
- *(int *)result = host->mode;
- break;
- case MMCBR_IVAR_OCR:
- *(int *)result = host->ocr;
- break;
- case MMCBR_IVAR_POWER_MODE:
- *(int *)result = host->ios.power_mode;
- break;
- case MMCBR_IVAR_VDD:
- *(int *)result = host->ios.vdd;
- break;
- default:
- return (EINVAL);
- }
-
- return (0);
-}
-
-static int
-fsl_sdhc_write_ivar(device_t self, device_t child, int index,
- uintptr_t value)
-{
- struct mmc_host *host = device_get_ivars(child);
-
- switch (index) {
- case MMCBR_IVAR_BUS_MODE:
- host->ios.bus_mode = value;
- break;
- case MMCBR_IVAR_BUS_WIDTH:
- host->ios.bus_width = value;
- break;
- case MMCBR_IVAR_CHIP_SELECT:
- host->ios.chip_select = value;
- break;
- case MMCBR_IVAR_CLOCK:
- host->ios.clock = value;
- break;
- case MMCBR_IVAR_MODE:
- host->mode = value;
- break;
- case MMCBR_IVAR_OCR:
- host->ocr = value;
- break;
- case MMCBR_IVAR_POWER_MODE:
- host->ios.power_mode = value;
- break;
- case MMCBR_IVAR_VDD:
- host->ios.vdd = value;
- break;
- case MMCBR_IVAR_HOST_OCR:
- case MMCBR_IVAR_F_MIN:
- case MMCBR_IVAR_F_MAX:
- default:
- /* Instance variable not writable. */
- return (EINVAL);
- }
-
- return (0);
-}
-
-
-/*
- * MMC bridge methods.
- */
-static int
-fsl_sdhc_update_ios(device_t self, device_t reqdev)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
- struct mmc_host *host = device_get_ivars(reqdev);
- struct mmc_ios *ios = &host->ios;
-
- mtx_lock(&sc->mtx);
-
- /* Full reset on bus power down to clear from any state. */
- if (ios->power_mode == power_off) {
- reset_controller_all(sc);
- init_controller(sc);
- }
-
- set_clock(sc, ios->clock);
- set_bus_width(sc, ios->bus_width);
-
- mtx_unlock(&sc->mtx);
-
- return (0);
-}
-
-static int
-fsl_sdhc_request(device_t self, device_t reqdev, struct mmc_request *req)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
- int err;
-
- mtx_lock(&sc->mtx);
-
- sc->request = req;
- err = start_command(sc, req->cmd);
-
- mtx_unlock(&sc->mtx);
-
- return (err);
-}
-
-static int
-fsl_sdhc_get_ro(device_t self, device_t reqdev)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
-
- /* Wouldn't it be faster using branching (if {}) ?? */
- return (((read4(sc, SDHC_PRSSTAT) & PRSSTAT_WPSPL) >> 19) ^ 0x1);
-}
-
-static int
-fsl_sdhc_acquire_host(device_t self, device_t reqdev)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
- int retval = 0;
-
- mtx_lock(&sc->mtx);
-
- while (sc->bus_busy)
- retval = mtx_sleep(sc, &sc->mtx, PZERO, "sdhcah", 0);
- ++(sc->bus_busy);
-
- mtx_unlock(&sc->mtx);
-
- return (retval);
-}
-
-static int
-fsl_sdhc_release_host(device_t self, device_t reqdev)
-{
- struct fsl_sdhc_softc *sc = device_get_softc(self);
-
- mtx_lock(&sc->mtx);
- --(sc->bus_busy);
- mtx_unlock(&sc->mtx);
- wakeup(sc);
-
- return (0);
-}
diff --git a/sys/powerpc/mpc85xx/fsl_sdhc.h b/sys/powerpc/mpc85xx/fsl_sdhc.h
deleted file mode 100644
index 9bd2e3d3..0000000
--- a/sys/powerpc/mpc85xx/fsl_sdhc.h
+++ /dev/null
@@ -1,297 +0,0 @@
-/*-
- * Copyright (c) 2011-2012 Semihalf
- * 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_SDHC_H_
-#define FSL_SDHC_H_
-
-#include <sys/cdefs.h>
-
-#include <sys/param.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/module.h>
-#include <sys/mutex.h>
-#include <sys/rman.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
-#include <sys/taskqueue.h>
-
-#include <machine/bus.h>
-
-#include <dev/mmc/bridge.h>
-#include <dev/mmc/mmcreg.h>
-#include <dev/mmc/mmcvar.h>
-#include <dev/mmc/mmcbrvar.h>
-
-#include "mmcbr_if.h"
-
-
-/*****************************************************************************
- * Private defines
- *****************************************************************************/
-struct slot {
- uint32_t clock;
-};
-
-struct fsl_sdhc_softc {
- device_t self;
- device_t child;
-
- bus_space_handle_t bsh;
- bus_space_tag_t bst;
-
- struct resource *mem_resource;
- int mem_rid;
- struct resource *irq_resource;
- int irq_rid;
- void *ihl;
-
- bus_dma_tag_t dma_tag;
- bus_dmamap_t dma_map;
- uint32_t* dma_mem;
- bus_addr_t dma_phys;
-
- struct mtx mtx;
-
- struct task card_detect_task;
- struct callout card_detect_callout;
-
- struct mmc_host mmc_host;
-
- struct slot slot;
- uint32_t bus_busy;
- uint32_t platform_clock;
-
- struct mmc_request *request;
- int data_done;
- int command_done;
- int use_dma;
- uint32_t* data_ptr;
- uint32_t data_offset;
-};
-
-#define FSL_SDHC_RESET_DELAY 50
-
-#define FSL_SDHC_BASE_CLOCK_DIV (2)
-#define FSL_SDHC_MAX_DIV (FSL_SDHC_BASE_CLOCK_DIV * 256 * 16)
-#define FSL_SDHC_MIN_DIV (FSL_SDHC_BASE_CLOCK_DIV * 2)
-#define FSL_SDHC_MAX_CLOCK (50000000)
-
-#define FSL_SDHC_MAX_BLOCK_COUNT (65535)
-#define FSL_SDHC_MAX_BLOCK_SIZE (4096)
-
-#define FSL_SDHC_FIFO_BUF_SIZE (64) /* Water-mark level. */
-#define FSL_SDHC_FIFO_BUF_WORDS (FSL_SDHC_FIFO_BUF_SIZE / 4)
-
-#define FSL_SDHC_DMA_SEGMENT_SIZE (1024)
-#define FSL_SDHC_DMA_ALIGNMENT (4)
-#define FSL_SDHC_DMA_BLOCK_SIZE FSL_SDHC_MAX_BLOCK_SIZE
-
-
-/*
- * Offsets of SD HC registers
- */
-enum sdhc_reg_off {
- SDHC_DSADDR = 0x000,
- SDHC_BLKATTR = 0x004,
- SDHC_CMDARG = 0x008,
- SDHC_XFERTYP = 0x00c,
- SDHC_CMDRSP0 = 0x010,
- SDHC_CMDRSP1 = 0x014,
- SDHC_CMDRSP2 = 0x018,
- SDHC_CMDRSP3 = 0x01c,
- SDHC_DATPORT = 0x020,
- SDHC_PRSSTAT = 0x024,
- SDHC_PROCTL = 0x028,
- SDHC_SYSCTL = 0x02c,
- SDHC_IRQSTAT = 0x030,
- SDHC_IRQSTATEN = 0x034,
- SDHC_IRQSIGEN = 0x038,
- SDHC_AUTOC12ERR = 0x03c,
- SDHC_HOSTCAPBLT = 0x040,
- SDHC_WML = 0x044,
- SDHC_FEVT = 0x050,
- SDHC_HOSTVER = 0x0fc,
- SDHC_DCR = 0x40c
-};
-
-enum sysctl_bit {
- SYSCTL_INITA = 0x08000000,
- SYSCTL_RSTD = 0x04000000,
- SYSCTL_RSTC = 0x02000000,
- SYSCTL_RSTA = 0x01000000,
- SYSCTL_DTOCV = 0x000f0000,
- SYSCTL_SDCLKFS = 0x0000ff00,
- SYSCTL_DVS = 0x000000f0,
- SYSCTL_PEREN = 0x00000004,
- SYSCTL_HCKEN = 0x00000002,
- SYSCTL_IPGEN = 0x00000001
-};
-
-#define HEX_LEFT_SHIFT(x) (4 * x)
-enum sysctl_shift {
- SHIFT_DTOCV = HEX_LEFT_SHIFT(4),
- SHIFT_SDCLKFS = HEX_LEFT_SHIFT(2),
- SHIFT_DVS = HEX_LEFT_SHIFT(1)
-};
-
-enum proctl_bit {
- PROCTL_WECRM = 0x04000000,
- PROCTL_WECINS = 0x02000000,
- PROCTL_WECINT = 0x01000000,
- PROCTL_RWCTL = 0x00040000,
- PROCTL_CREQ = 0x00020000,
- PROCTL_SABGREQ = 0x00010000,
- PROCTL_CDSS = 0x00000080,
- PROCTL_CDTL = 0x00000040,
- PROCTL_EMODE = 0x00000030,
- PROCTL_D3CD = 0x00000008,
- PROCTL_DTW = 0x00000006
-};
-
-enum dtw {
- DTW_1 = 0x00000000,
- DTW_4 = 0x00000002,
- DTW_8 = 0x00000004
-};
-
-enum prsstat_bit {
- PRSSTAT_DLSL = 0xff000000,
- PRSSTAT_CLSL = 0x00800000,
- PRSSTAT_WPSPL = 0x00080000,
- PRSSTAT_CDPL = 0x00040000,
- PRSSTAT_CINS = 0x00010000,
- PRSSTAT_BREN = 0x00000800,
- PRSSTAT_BWEN = 0x00000400,
- PRSSTAT_RTA = 0x00000200,
- PRSSTAT_WTA = 0x00000100,
- PRSSTAT_SDOFF = 0x00000080,
- PRSSTAT_PEROFF = 0x00000040,
- PRSSTAT_HCKOFF = 0x00000020,
- PRSSTAT_IPGOFF = 0x00000010,
- PRSSTAT_DLA = 0x00000004,
- PRSSTAT_CDIHB = 0x00000002,
- PRSSTAT_CIHB = 0x00000001
-
-};
-
-enum irq_bits {
- IRQ_DMAE = 0x10000000,
- IRQ_AC12E = 0x01000000,
- IRQ_DEBE = 0x00400000,
- IRQ_DCE = 0x00200000,
- IRQ_DTOE = 0x00100000,
- IRQ_CIE = 0x00080000,
- IRQ_CEBE = 0x00040000,
- IRQ_CCE = 0x00020000,
- IRQ_CTOE = 0x00010000,
- IRQ_CINT = 0x00000100,
- IRQ_CRM = 0x00000080,
- IRQ_CINS = 0x00000040,
- IRQ_BRR = 0x00000020,
- IRQ_BWR = 0x00000010,
- IRQ_DINT = 0x00000008,
- IRQ_BGE = 0x00000004,
- IRQ_TC = 0x00000002,
- IRQ_CC = 0x00000001
-};
-
-enum irq_masks {
- IRQ_ERROR_DATA_MASK = IRQ_DMAE | IRQ_DEBE | IRQ_DCE | IRQ_DTOE,
- IRQ_ERROR_CMD_MASK = IRQ_AC12E | IRQ_CIE | IRQ_CTOE | IRQ_CCE |
- IRQ_CEBE
-};
-
-enum dcr_bits {
- DCR_PRI = 0x0000c000,
- DCR_SNOOP = 0x00000040,
- DCR_AHB2MAG_BYPASS = 0x00000020,
- DCR_RD_SAFE = 0x00000004,
- DCR_RD_PFE = 0x00000002,
- DCR_RD_PF_SIZE = 0x00000001
-};
-
-#define DCR_PRI_SHIFT (14)
-
-enum xfertyp_bits {
- XFERTYP_CMDINX = 0x3f000000,
- XFERTYP_CMDTYP = 0x00c00000,
- XFERTYP_DPSEL = 0x00200000,
- XFERTYP_CICEN = 0x00100000,
- XFERTYP_CCCEN = 0x00080000,
- XFERTYP_RSPTYP = 0x00030000,
- XFERTYP_MSBSEL = 0x00000020,
- XFERTYP_DTDSEL = 0x00000010,
- XFERTYP_AC12EN = 0x00000004,
- XFERTYP_BCEN = 0x00000002,
- XFERTYP_DMAEN = 0x00000001
-};
-
-#define CMDINX_SHIFT (24)
-
-enum xfertyp_cmdtyp {
- CMDTYP_NORMAL = 0x00000000,
- CMDYTP_SUSPEND = 0x00400000,
- CMDTYP_RESUME = 0x00800000,
- CMDTYP_ABORT = 0x00c00000
-};
-
-enum xfertyp_rsptyp {
- RSPTYP_NONE = 0x00000000,
- RSPTYP_136 = 0x00010000,
- RSPTYP_48 = 0x00020000,
- RSPTYP_48_BUSY = 0x00030000
-};
-
-enum blkattr_bits {
- BLKATTR_BLKSZE = 0x00001fff,
- BLKATTR_BLKCNT = 0xffff0000
-};
-#define BLKATTR_BLOCK_COUNT(x) (x << 16)
-
-enum wml_bits {
- WR_WML = 0x00ff0000,
- RD_WML = 0x000000ff,
-};
-
-enum sdhc_bit_mask {
- MASK_CLOCK_CONTROL = 0x0000ffff,
- MASK_IRQ_ALL = IRQ_DMAE | IRQ_AC12E | IRQ_DEBE | IRQ_DCE |
- IRQ_DTOE | IRQ_CIE | IRQ_CEBE | IRQ_CCE |
- IRQ_CTOE | IRQ_CINT | IRQ_CRM | IRQ_CINS |
- IRQ_BRR | IRQ_BWR | IRQ_DINT | IRQ_BGE |
- IRQ_TC | IRQ_CC,
-};
-
-enum sdhc_line {
- SDHC_DAT_LINE = 0x2,
- SDHC_CMD_LINE = 0x1
-};
-
-#endif /* FSL_SDHC_H_ */
OpenPOWER on IntegriCloud