summaryrefslogtreecommitdiffstats
path: root/sys/dev/mmc/host/dwmmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mmc/host/dwmmc.c')
-rw-r--r--sys/dev/mmc/host/dwmmc.c118
1 files changed, 43 insertions, 75 deletions
diff --git a/sys/dev/mmc/host/dwmmc.c b/sys/dev/mmc/host/dwmmc.c
index 81e3083..a80c8f6 100644
--- a/sys/dev/mmc/host/dwmmc.c
+++ b/sys/dev/mmc/host/dwmmc.c
@@ -56,11 +56,11 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
-#include <machine/fdt.h>
#include <machine/cpu.h>
#include <machine/intr.h>
-#include <dev/mmc/host/dwmmc.h>
+#include <dev/mmc/host/dwmmc_reg.h>
+#include <dev/mmc/host/dwmmc_var.h>
#include "mmcbr_if.h"
@@ -112,44 +112,10 @@ struct idmac_desc {
uint32_t des3; /* buf2 phys addr or next descr */
};
-#define DESC_COUNT 256
-#define DESC_SIZE (sizeof(struct idmac_desc) * DESC_COUNT)
+#define DESC_MAX 256
+#define DESC_SIZE (sizeof(struct idmac_desc) * DESC_MAX)
#define DEF_MSIZE 0x2 /* Burst size of multiple transaction */
-struct dwmmc_softc {
- struct resource *res[2];
- bus_space_tag_t bst;
- bus_space_handle_t bsh;
- device_t dev;
- void *intr_cookie;
- struct mmc_host host;
- struct mtx sc_mtx;
- struct mmc_request *req;
- struct mmc_command *curcmd;
- uint32_t flags;
- uint32_t hwtype;
- uint32_t use_auto_stop;
- uint32_t use_pio;
- uint32_t pwren_inverted;
-
- bus_dma_tag_t desc_tag;
- bus_dmamap_t desc_map;
- struct idmac_desc *desc_ring;
- bus_addr_t desc_ring_paddr;
- bus_dma_tag_t buf_tag;
- bus_dmamap_t buf_map;
-
- uint32_t bus_busy;
- uint32_t dto_rcvd;
- uint32_t acd_rcvd;
- uint32_t cmd_done;
- uint32_t bus_hz;
- uint32_t fifo_depth;
- uint32_t num_slots;
- uint32_t sdr_timing;
- uint32_t ddr_timing;
-};
-
static void dwmmc_next_operation(struct dwmmc_softc *);
static int dwmmc_setup_bus(struct dwmmc_softc *, int);
static int dma_done(struct dwmmc_softc *, struct mmc_command *);
@@ -163,13 +129,6 @@ static struct resource_spec dwmmc_spec[] = {
{ -1, 0 }
};
-enum {
- HWTYPE_NONE,
- HWTYPE_ALTERA,
- HWTYPE_EXYNOS,
- HWTYPE_ROCKCHIP,
-};
-
#define HWTYPE_MASK (0x0000ffff)
#define HWFLAG_MASK (0xffff << 16)
@@ -284,10 +243,10 @@ dma_setup(struct dwmmc_softc *sc)
return (1);
}
- for (idx = 0; idx < DESC_COUNT; idx++) {
+ for (idx = 0; idx < sc->desc_count; idx++) {
sc->desc_ring[idx].des0 = DES0_CH;
sc->desc_ring[idx].des1 = 0;
- nidx = (idx + 1) % DESC_COUNT;
+ nidx = (idx + 1) % sc->desc_count;
sc->desc_ring[idx].des3 = sc->desc_ring_paddr + \
(nidx * sizeof(struct idmac_desc));
}
@@ -298,8 +257,8 @@ dma_setup(struct dwmmc_softc *sc)
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
BUS_SPACE_MAXADDR, /* highaddr */
NULL, NULL, /* filter, filterarg */
- DESC_COUNT*MMC_SECTOR_SIZE, /* maxsize */
- DESC_COUNT, /* nsegments */
+ sc->desc_count * MMC_SECTOR_SIZE, /* maxsize */
+ sc->desc_count, /* nsegments */
MMC_SECTOR_SIZE, /* maxsegsize */
0, /* flags */
NULL, NULL, /* lockfunc, lockarg */
@@ -466,26 +425,29 @@ parse_fdt(struct dwmmc_softc *sc)
return (ENXIO);
/* fifo-depth */
- if ((len = OF_getproplen(node, "fifo-depth")) <= 0)
- return (ENXIO);
- OF_getencprop(node, "fifo-depth", dts_value, len);
- sc->fifo_depth = dts_value[0];
+ if ((len = OF_getproplen(node, "fifo-depth")) > 0) {
+ OF_getencprop(node, "fifo-depth", dts_value, len);
+ sc->fifo_depth = dts_value[0];
+ }
/* num-slots */
- if ((len = OF_getproplen(node, "num-slots")) <= 0)
- return (ENXIO);
- OF_getencprop(node, "num-slots", dts_value, len);
- sc->num_slots = dts_value[0];
+ sc->num_slots = 1;
+ if ((len = OF_getproplen(node, "num-slots")) > 0) {
+ OF_getencprop(node, "num-slots", dts_value, len);
+ sc->num_slots = dts_value[0];
+ }
/*
* We need some platform-specific code to know
* what the clock is supplied for our device.
* For now rely on the value specified in FDT.
*/
- if ((len = OF_getproplen(node, "bus-frequency")) <= 0)
- return (ENXIO);
- OF_getencprop(node, "bus-frequency", dts_value, len);
- sc->bus_hz = dts_value[0];
+ if (sc->bus_hz == 0) {
+ if ((len = OF_getproplen(node, "bus-frequency")) <= 0)
+ return (ENXIO);
+ OF_getencprop(node, "bus-frequency", dts_value, len);
+ sc->bus_hz = dts_value[0];
+ }
/*
* Platform-specific stuff
@@ -533,18 +495,20 @@ dwmmc_probe(device_t dev)
return (BUS_PROBE_DEFAULT);
}
-static int
+int
dwmmc_attach(device_t dev)
{
struct dwmmc_softc *sc;
- device_t child;
int error;
int slot;
sc = device_get_softc(dev);
sc->dev = dev;
- sc->hwtype = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ if (sc->hwtype == HWTYPE_NONE) {
+ sc->hwtype =
+ ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ }
/* Why not to use Auto Stop? It save a hundred of irq per second */
sc->use_auto_stop = 1;
@@ -562,10 +526,6 @@ dwmmc_attach(device_t dev)
return (ENXIO);
}
- /* Memory interface */
- sc->bst = rman_get_bustag(sc->res[0]);
- sc->bsh = rman_get_bushandle(sc->res[0]);
-
/* Setup interrupt handler. */
error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE,
NULL, dwmmc_intr, sc, &sc->intr_cookie);
@@ -577,13 +537,13 @@ dwmmc_attach(device_t dev)
device_printf(dev, "Hardware version ID is %04x\n",
READ4(sc, SDMMC_VERID) & 0xffff);
- sc->use_pio = 0;
- sc->pwren_inverted = 0;
+ if (sc->desc_count == 0)
+ sc->desc_count = DESC_MAX;
if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_ROCKCHIP) {
sc->use_pio = 1;
sc->pwren_inverted = 1;
- } else {
+ } else if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_EXYNOS) {
WRITE4(sc, EMMCP_MPSBEGIN0, 0);
WRITE4(sc, EMMCP_SEND0, 0);
WRITE4(sc, EMMCP_CTRL0, (MPSCTRL_SECURE_READ_BIT |
@@ -609,6 +569,13 @@ dwmmc_attach(device_t dev)
dwmmc_setup_bus(sc, sc->host.f_min);
+ if (sc->fifo_depth == 0) {
+ sc->fifo_depth = 1 +
+ ((READ4(sc, SDMMC_FIFOTH) >> SDMMC_FIFOTH_RXWMARK_S) & 0xfff);
+ device_printf(dev, "No fifo-depth, using FIFOTH %x\n",
+ sc->fifo_depth);
+ }
+
if (!sc->use_pio) {
if (dma_setup(sc))
return (ENXIO);
@@ -642,11 +609,11 @@ dwmmc_attach(device_t dev)
WRITE4(sc, SDMMC_CTRL, SDMMC_CTRL_INT_ENABLE);
sc->host.f_min = 400000;
- sc->host.f_max = 200000000;
+ sc->host.f_max = min(200000000, sc->bus_hz);
sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
sc->host.caps = MMC_CAP_4_BIT_DATA;
- child = device_add_child(dev, "mmc", 0);
+ device_add_child(dev, "mmc", -1);
return (bus_generic_attach(dev));
}
@@ -1132,7 +1099,7 @@ dwmmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
*(int *)result = sc->host.caps;
break;
case MMCBR_IVAR_MAX_DATA:
- *(int *)result = DESC_COUNT;
+ *(int *)result = sc->desc_count;
}
return (0);
}
@@ -1200,7 +1167,7 @@ static device_method_t dwmmc_methods[] = {
DEVMETHOD_END
};
-static driver_t dwmmc_driver = {
+driver_t dwmmc_driver = {
"dwmmc",
dwmmc_methods,
sizeof(struct dwmmc_softc),
@@ -1209,4 +1176,5 @@ static driver_t dwmmc_driver = {
static devclass_t dwmmc_devclass;
DRIVER_MODULE(dwmmc, simplebus, dwmmc_driver, dwmmc_devclass, 0, 0);
+DRIVER_MODULE(dwmmc, ofwbus, dwmmc_driver, dwmmc_devclass, 0, 0);
OpenPOWER on IntegriCloud