summaryrefslogtreecommitdiffstats
path: root/rtemsbsd
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2015-03-16 22:10:36 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2015-03-26 13:53:24 +0100
commitfc9e83bb68ff851be89a4b24097b0948ef160c4f (patch)
tree011b08058ff03d0c130c742a9f82e462b285a26e /rtemsbsd
parentnexus-devices: Fix for QorIQ T variants (diff)
downloadrtems-libbsd-fc9e83bb68ff851be89a4b24097b0948ef160c4f.tar.bz2
mmc: Import MMC/SDCard support from libusb
Diffstat (limited to 'rtemsbsd')
-rw-r--r--rtemsbsd/include/bsp/nexus-devices.h7
-rw-r--r--rtemsbsd/include/rtems/bsd/local/mmcbr_if.h79
-rw-r--r--rtemsbsd/include/rtems/bsd/local/mmcbus_if.h55
-rw-r--r--rtemsbsd/local/mmcbr_if.c64
-rw-r--r--rtemsbsd/local/mmcbus_if.c47
-rw-r--r--rtemsbsd/rtems/rtems-bsd-cam.c16
-rw-r--r--rtemsbsd/rtems/rtems-bsd-configintrhook.c58
-rw-r--r--rtemsbsd/sys/dev/dw_mmc/dw_mmc.c1106
-rw-r--r--rtemsbsd/sys/dev/dw_mmc/dw_mmcreg.h220
9 files changed, 1646 insertions, 6 deletions
diff --git a/rtemsbsd/include/bsp/nexus-devices.h b/rtemsbsd/include/bsp/nexus-devices.h
index 4d6e767e..f615e4e4 100644
--- a/rtemsbsd/include/bsp/nexus-devices.h
+++ b/rtemsbsd/include/bsp/nexus-devices.h
@@ -88,6 +88,13 @@ RTEMS_BSD_DEFINE_NEXUS_DEVICE(cgem, 0, RTEMS_ARRAY_SIZE(cgem0_res),
SYSINIT_DRIVER_REFERENCE(e1000phy, miibus);
+#elif defined(LIBBSP_ARM_ALTERA_CYCLONE_V_BSP_H)
+
+RTEMS_BSD_DEFINE_NEXUS_DEVICE(dw_mmc, 0, 0, NULL);
+
+SYSINIT_DRIVER_REFERENCE(mmc, dw_mmc);
+SYSINIT_DRIVER_REFERENCE(mmcsd, mmc);
+
#elif defined(LIBBSP_POWERPC_QORIQ_BSP_H)
#if !QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)
diff --git a/rtemsbsd/include/rtems/bsd/local/mmcbr_if.h b/rtemsbsd/include/rtems/bsd/local/mmcbr_if.h
new file mode 100644
index 00000000..f11e201d
--- /dev/null
+++ b/rtemsbsd/include/rtems/bsd/local/mmcbr_if.h
@@ -0,0 +1,79 @@
+/*
+ * This file is produced automatically.
+ * Do not modify anything in here by hand.
+ *
+ * Created from source file
+ * dev/mmc/mmcbr_if.m
+ * with
+ * makeobjops.awk
+ *
+ * See the source file for legal information
+ */
+
+
+#ifndef _mmcbr_if_h_
+#define _mmcbr_if_h_
+
+/** @brief Unique descriptor for the MMCBR_UPDATE_IOS() method */
+extern struct kobjop_desc mmcbr_update_ios_desc;
+/** @brief A function implementing the MMCBR_UPDATE_IOS() method */
+typedef int mmcbr_update_ios_t(device_t brdev, device_t reqdev);
+
+static __inline int MMCBR_UPDATE_IOS(device_t brdev, device_t reqdev)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbr_update_ios);
+ return ((mmcbr_update_ios_t *) _m)(brdev, reqdev);
+}
+
+/** @brief Unique descriptor for the MMCBR_REQUEST() method */
+extern struct kobjop_desc mmcbr_request_desc;
+/** @brief A function implementing the MMCBR_REQUEST() method */
+typedef int mmcbr_request_t(device_t brdev, device_t reqdev,
+ struct mmc_request *req);
+
+static __inline int MMCBR_REQUEST(device_t brdev, device_t reqdev,
+ struct mmc_request *req)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbr_request);
+ return ((mmcbr_request_t *) _m)(brdev, reqdev, req);
+}
+
+/** @brief Unique descriptor for the MMCBR_GET_RO() method */
+extern struct kobjop_desc mmcbr_get_ro_desc;
+/** @brief A function implementing the MMCBR_GET_RO() method */
+typedef int mmcbr_get_ro_t(device_t brdev, device_t reqdev);
+
+static __inline int MMCBR_GET_RO(device_t brdev, device_t reqdev)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbr_get_ro);
+ return ((mmcbr_get_ro_t *) _m)(brdev, reqdev);
+}
+
+/** @brief Unique descriptor for the MMCBR_ACQUIRE_HOST() method */
+extern struct kobjop_desc mmcbr_acquire_host_desc;
+/** @brief A function implementing the MMCBR_ACQUIRE_HOST() method */
+typedef int mmcbr_acquire_host_t(device_t brdev, device_t reqdev);
+
+static __inline int MMCBR_ACQUIRE_HOST(device_t brdev, device_t reqdev)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbr_acquire_host);
+ return ((mmcbr_acquire_host_t *) _m)(brdev, reqdev);
+}
+
+/** @brief Unique descriptor for the MMCBR_RELEASE_HOST() method */
+extern struct kobjop_desc mmcbr_release_host_desc;
+/** @brief A function implementing the MMCBR_RELEASE_HOST() method */
+typedef int mmcbr_release_host_t(device_t brdev, device_t reqdev);
+
+static __inline int MMCBR_RELEASE_HOST(device_t brdev, device_t reqdev)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbr_release_host);
+ return ((mmcbr_release_host_t *) _m)(brdev, reqdev);
+}
+
+#endif /* _mmcbr_if_h_ */
diff --git a/rtemsbsd/include/rtems/bsd/local/mmcbus_if.h b/rtemsbsd/include/rtems/bsd/local/mmcbus_if.h
new file mode 100644
index 00000000..5e0e2da0
--- /dev/null
+++ b/rtemsbsd/include/rtems/bsd/local/mmcbus_if.h
@@ -0,0 +1,55 @@
+/*
+ * This file is produced automatically.
+ * Do not modify anything in here by hand.
+ *
+ * Created from source file
+ * dev/mmc/mmcbus_if.m
+ * with
+ * makeobjops.awk
+ *
+ * See the source file for legal information
+ */
+
+
+#ifndef _mmcbus_if_h_
+#define _mmcbus_if_h_
+
+/** @brief Unique descriptor for the MMCBUS_WAIT_FOR_REQUEST() method */
+extern struct kobjop_desc mmcbus_wait_for_request_desc;
+/** @brief A function implementing the MMCBUS_WAIT_FOR_REQUEST() method */
+typedef int mmcbus_wait_for_request_t(device_t brdev, device_t reqdev,
+ struct mmc_request *req);
+
+static __inline int MMCBUS_WAIT_FOR_REQUEST(device_t brdev, device_t reqdev,
+ struct mmc_request *req)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbus_wait_for_request);
+ return ((mmcbus_wait_for_request_t *) _m)(brdev, reqdev, req);
+}
+
+/** @brief Unique descriptor for the MMCBUS_ACQUIRE_BUS() method */
+extern struct kobjop_desc mmcbus_acquire_bus_desc;
+/** @brief A function implementing the MMCBUS_ACQUIRE_BUS() method */
+typedef int mmcbus_acquire_bus_t(device_t brdev, device_t reqdev);
+
+static __inline int MMCBUS_ACQUIRE_BUS(device_t brdev, device_t reqdev)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbus_acquire_bus);
+ return ((mmcbus_acquire_bus_t *) _m)(brdev, reqdev);
+}
+
+/** @brief Unique descriptor for the MMCBUS_RELEASE_BUS() method */
+extern struct kobjop_desc mmcbus_release_bus_desc;
+/** @brief A function implementing the MMCBUS_RELEASE_BUS() method */
+typedef int mmcbus_release_bus_t(device_t brdev, device_t reqdev);
+
+static __inline int MMCBUS_RELEASE_BUS(device_t brdev, device_t reqdev)
+{
+ kobjop_t _m;
+ KOBJOPLOOKUP(((kobj_t)brdev)->ops,mmcbus_release_bus);
+ return ((mmcbus_release_bus_t *) _m)(brdev, reqdev);
+}
+
+#endif /* _mmcbus_if_h_ */
diff --git a/rtemsbsd/local/mmcbr_if.c b/rtemsbsd/local/mmcbr_if.c
new file mode 100644
index 00000000..1ce2d263
--- /dev/null
+++ b/rtemsbsd/local/mmcbr_if.c
@@ -0,0 +1,64 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ * This file is produced automatically.
+ * Do not modify anything in here by hand.
+ *
+ * Created from source file
+ * freebsd-org/sys/dev/mmc/mmcbr_if.m
+ * with
+ * makeobjops.awk
+ *
+ * See the source file for legal information
+ */
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <rtems/bsd/local/mmcbr_if.h>
+
+struct kobj_method mmcbr_update_ios_method_default = {
+ &mmcbr_update_ios_desc, (kobjop_t) kobj_error_method
+};
+
+struct kobjop_desc mmcbr_update_ios_desc = {
+ 0, &mmcbr_update_ios_method_default
+};
+
+struct kobj_method mmcbr_request_method_default = {
+ &mmcbr_request_desc, (kobjop_t) kobj_error_method
+};
+
+struct kobjop_desc mmcbr_request_desc = {
+ 0, &mmcbr_request_method_default
+};
+
+struct kobj_method mmcbr_get_ro_method_default = {
+ &mmcbr_get_ro_desc, (kobjop_t) kobj_error_method
+};
+
+struct kobjop_desc mmcbr_get_ro_desc = {
+ 0, &mmcbr_get_ro_method_default
+};
+
+struct kobj_method mmcbr_acquire_host_method_default = {
+ &mmcbr_acquire_host_desc, (kobjop_t) kobj_error_method
+};
+
+struct kobjop_desc mmcbr_acquire_host_desc = {
+ 0, &mmcbr_acquire_host_method_default
+};
+
+struct kobj_method mmcbr_release_host_method_default = {
+ &mmcbr_release_host_desc, (kobjop_t) kobj_error_method
+};
+
+struct kobjop_desc mmcbr_release_host_desc = {
+ 0, &mmcbr_release_host_method_default
+};
+
diff --git a/rtemsbsd/local/mmcbus_if.c b/rtemsbsd/local/mmcbus_if.c
new file mode 100644
index 00000000..a757a561
--- /dev/null
+++ b/rtemsbsd/local/mmcbus_if.c
@@ -0,0 +1,47 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*
+ * This file is produced automatically.
+ * Do not modify anything in here by hand.
+ *
+ * Created from source file
+ * freebsd-org/sys/dev/mmc/mmcbus_if.m
+ * with
+ * makeobjops.awk
+ *
+ * See the source file for legal information
+ */
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/queue.h>
+#include <sys/kernel.h>
+#include <sys/kobj.h>
+#include <sys/bus.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/mmc/bridge.h>
+#include <rtems/bsd/local/mmcbus_if.h>
+
+struct kobj_method mmcbus_wait_for_request_method_default = {
+ &mmcbus_wait_for_request_desc, (kobjop_t) kobj_error_method
+};
+
+struct kobjop_desc mmcbus_wait_for_request_desc = {
+ 0, &mmcbus_wait_for_request_method_default
+};
+
+struct kobj_method mmcbus_acquire_bus_method_default = {
+ &mmcbus_acquire_bus_desc, (kobjop_t) kobj_error_method
+};
+
+struct kobjop_desc mmcbus_acquire_bus_desc = {
+ 0, &mmcbus_acquire_bus_method_default
+};
+
+struct kobj_method mmcbus_release_bus_method_default = {
+ &mmcbus_release_bus_desc, (kobjop_t) kobj_error_method
+};
+
+struct kobjop_desc mmcbus_release_bus_desc = {
+ 0, &mmcbus_release_bus_method_default
+};
+
diff --git a/rtemsbsd/rtems/rtems-bsd-cam.c b/rtemsbsd/rtems/rtems-bsd-cam.c
index ab15f426..0f518586 100644
--- a/rtemsbsd/rtems/rtems-bsd-cam.c
+++ b/rtemsbsd/rtems/rtems-bsd-cam.c
@@ -151,7 +151,7 @@ rtems_bsd_scsi_inquiry(union ccb *ccb, struct scsi_inquiry_data *inq_data)
rtems_bsd_ccb_callback,
BSD_SCSI_TAG,
(u_int8_t *) inq_data,
- sizeof(*inq_data) - 1,
+ SHORT_INQUIRY_LENGTH,
FALSE,
0,
SSD_MIN_SIZE,
@@ -339,11 +339,11 @@ rtems_bsd_sim_attach_worker(rtems_media_state state, const char *src, char **des
}
sc = rtems_bsd_scsi_inquiry(&sim->ccb, &inq_data);
- if (sc != RTEMS_SUCCESSFUL) {
+ if (sc == RTEMS_SUCCESSFUL) {
+ scsi_print_inquiry(&inq_data);
+ } else {
BSD_PRINTF("OOPS: inquiry failed\n");
- goto error;
}
- scsi_print_inquiry(&inq_data);
for (retries = 0; retries <= 3; ++retries) {
sc = rtems_bsd_scsi_test_unit_ready(&sim->ccb);
@@ -353,10 +353,14 @@ rtems_bsd_sim_attach_worker(rtems_media_state state, const char *src, char **des
}
if (sc != RTEMS_SUCCESSFUL) {
BSD_PRINTF("OOPS: test unit ready failed\n");
- goto error;
}
- sc = rtems_bsd_scsi_read_capacity(&sim->ccb, &block_count, &block_size);
+ for (retries = 0; retries <= 3; ++retries) {
+ sc = rtems_bsd_scsi_read_capacity(&sim->ccb, &block_count, &block_size);
+ if (sc == RTEMS_SUCCESSFUL) {
+ break;
+ }
+ }
if (sc != RTEMS_SUCCESSFUL) {
BSD_PRINTF("OOPS: read capacity failed\n");
goto error;
diff --git a/rtemsbsd/rtems/rtems-bsd-configintrhook.c b/rtemsbsd/rtems/rtems-bsd-configintrhook.c
new file mode 100644
index 00000000..baf737e1
--- /dev/null
+++ b/rtemsbsd/rtems/rtems-bsd-configintrhook.c
@@ -0,0 +1,58 @@
+/**
+ * @file
+ *
+ * @ingroup rtems_bsd_rtems
+ *
+ * @brief TODO.
+ */
+
+/*
+ * Copyright (c) 2011 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <info@embedded-brains.de>
+ *
+ * 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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 <machine/rtems-bsd-kernel-space.h>
+
+#include <rtems/bsd/sys/param.h>
+#include <rtems/bsd/sys/types.h>
+#include <sys/kernel.h>
+
+int
+config_intrhook_establish(struct intr_config_hook *hook)
+{
+ (*hook->ich_func)(hook->ich_arg);
+
+ return (0);
+}
+
+void
+config_intrhook_disestablish(struct intr_config_hook *hook)
+{
+ /* Do nothing */
+}
diff --git a/rtemsbsd/sys/dev/dw_mmc/dw_mmc.c b/rtemsbsd/sys/dev/dw_mmc/dw_mmc.c
new file mode 100644
index 00000000..681bf95a
--- /dev/null
+++ b/rtemsbsd/sys/dev/dw_mmc/dw_mmc.c
@@ -0,0 +1,1106 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2006 Bernd Walter. All rights reserved.
+ * Copyright (c) 2006 M. Warner Losh. All rights reserved.
+ * Copyright (c) 2010 Greg Ansley. All rights reserved.
+ * Copyright (c) 2014 embedded brains GmbH. 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 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 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 <rtems/bsd/sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+
+#include <dev/dw_mmc/dw_mmcreg.h>
+
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/mmc/mmcbrvar.h>
+
+#include <rtems/bsd/local/mmcbr_if.h>
+
+#include <rtems/irq-extension.h>
+
+#include <bsp.h>
+
+#ifdef LIBBSP_ARM_ALTERA_CYCLONE_V_BSP_H
+
+#define DW_MMC_ALTERA_CYCLONE_V
+
+#include <bsp/socal/hps.h>
+#include <bsp/socal/socal.h>
+#include <bsp/socal/alt_sysmgr.h>
+#include <bsp/alt_clock_manager.h>
+#include <bsp/irq.h>
+
+#endif /* DW_MMC_ALTERA_CYCLONE_V */
+
+struct dw_mmc_softc {
+ device_t dev;
+ struct mtx sc_mtx;
+ struct mtx bus_mtx;
+ bus_space_handle_t bushandle;
+ uint32_t biu_clock;
+ uint32_t ciu_clock;
+ uint32_t card_clock;
+ struct mmc_host host;
+ uint32_t cmdr_flags;
+ volatile struct dw_mmc_des *des;
+ rtems_id task_id;
+};
+
+#define DW_MMC_MAX_DES_COUNT 32
+
+#define DW_MMC_MAX_DMA_TRANSFER_BYTES \
+ (DW_MMC_MAX_DES_COUNT * 2 * DW_MMC_DES1_MAX_BS)
+
+static inline uint32_t
+RD4(struct dw_mmc_softc *sc, bus_size_t off)
+{
+ return (bus_space_read_4(0, sc->bushandle, off));
+}
+
+static inline void
+WR4(struct dw_mmc_softc *sc, bus_size_t off, uint32_t val)
+{
+ bus_space_write_4(0, sc->bushandle, off, val);
+}
+
+/* bus entry points */
+static int dw_mmc_probe(device_t dev);
+static int dw_mmc_attach(device_t dev);
+static int dw_mmc_detach(device_t dev);
+static void dw_mmc_intr(void *);
+
+static void
+DW_MMC_LOCK(struct dw_mmc_softc *sc)
+{
+ mtx_lock(&sc->sc_mtx);
+ sc->task_id = rtems_task_self();
+}
+
+#define DW_MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define DW_MMC_LOCK_INIT(_sc) \
+ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \
+ "dw_mmc", MTX_DEF)
+
+#define DW_MMC_BUS_LOCK(_sc) mtx_lock(&(_sc)->bus_mtx)
+#define DW_MMC_BUS_UNLOCK(_sc) mtx_unlock(&(_sc)->bus_mtx)
+#define DW_MMC_BUS_LOCK_INIT(_sc) \
+ mtx_init(&_sc->bus_mtx, device_get_nameunit(_sc->dev), \
+ "dw_mmc", MTX_DEF)
+
+static int
+dw_mmc_poll_reset_completion(struct dw_mmc_softc *sc, uint32_t ctrl_resets)
+{
+ rtems_interval timeout = rtems_clock_tick_later_usec(250000);
+
+ do {
+ if ((RD4(sc, DW_MMC_CTRL) & ctrl_resets) == 0) {
+ return 0;
+ }
+ } while (rtems_clock_tick_before(timeout));
+
+ return EBUSY;
+}
+
+static uint32_t
+dw_mmc_poll_intsts(struct dw_mmc_softc *sc, uint32_t mask)
+{
+ uint32_t ret_intsts = 0;
+
+ while (1) {
+ uint32_t intsts = RD4(sc, DW_MMC_RINTSTS);
+
+ if ((intsts & DW_MMC_INT_ERROR) != 0) {
+ WR4(sc, DW_MMC_RINTSTS, intsts);
+ ret_intsts = intsts;
+ break;
+ }
+
+ if ((intsts & mask) != 0) {
+ WR4(sc, DW_MMC_RINTSTS, intsts & mask);
+ break;
+ }
+ }
+
+ return ret_intsts;
+}
+
+static void
+dw_mmc_wait_for_interrupt(struct dw_mmc_softc *sc, uint32_t intmask)
+{
+ rtems_status_code rs;
+
+ WR4(sc, DW_MMC_INTMASK, intmask);
+
+ rs = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+ BSD_ASSERT(rs == RTEMS_SUCCESSFUL);
+}
+
+static int
+dw_mmc_init(struct dw_mmc_softc *sc)
+{
+ uint32_t ctrl;
+ uint32_t fifoth;
+ int err;
+
+ err = dw_mmc_poll_reset_completion(sc, DW_MMC_CTRL_RESET);
+ if (err != 0) {
+ return err;
+ }
+
+ sc->card_clock = UINT32_MAX;
+
+ /* Clear interrupt status */
+ WR4(sc, DW_MMC_RINTSTS, 0xffffffff);
+
+ /* Disable all interrupts */
+ WR4(sc, DW_MMC_INTMASK, 0x0);
+
+ /* Enable interrupts in general */
+ ctrl = RD4(sc, DW_MMC_CTRL);
+ ctrl |= DW_MMC_CTRL_INT_ENABLE;
+ WR4(sc, DW_MMC_CTRL, ctrl);
+
+ /* Set data and response timeout to maximum values */
+ WR4(sc, DW_MMC_TMOUT, 0xffffffff);
+
+ /* Set debounce value to 25ms */
+ WR4(sc, DW_MMC_DEBNCE, (sc->biu_clock / 1000) * 25);
+
+ /* Set FIFO watermarks */
+ fifoth = RD4(sc, DW_MMC_FIFOTH);
+ fifoth &= ~(DW_MMC_FIFOTH_RX_WMARK_MSK | DW_MMC_FIFOTH_TX_WMARK_MSK);
+ fifoth |= DW_MMC_FIFOTH_RX_WMARK(511) | DW_MMC_FIFOTH_TX_WMARK(512);
+ WR4(sc, DW_MMC_FIFOTH, fifoth);
+
+ /* Set DMA descriptor */
+ WR4(sc, DW_MMC_DBADDR, (uint32_t) sc->des);
+
+ return 0;
+}
+
+static void
+dw_mmc_fini(struct dw_mmc_softc *sc)
+{
+ WR4(sc, DW_MMC_CTRL, DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_RESET);
+}
+
+static int
+dw_mmc_probe(device_t dev)
+{
+
+ device_set_desc(dev, "DesignWare Mobile Storage Host");
+ return (0);
+}
+
+static int
+dw_mmc_platform_init(struct dw_mmc_softc *sc)
+{
+#ifdef DW_MMC_ALTERA_CYCLONE_V
+ size_t des_size = DW_MMC_MAX_DES_COUNT * sizeof(*sc->des);
+ ALT_STATUS_CODE as;
+
+ /* Module base address */
+ sc->bushandle = (bus_space_handle_t) ALT_SDMMC_ADDR;
+
+ /* BIU clock */
+ as = alt_clk_freq_get(ALT_CLK_L4_MP, &sc->biu_clock);
+ BSD_ASSERT(as == ALT_E_SUCCESS);
+
+ /* CIU clock */
+ as = alt_clk_clock_enable(ALT_CLK_SDMMC);
+ BSD_ASSERT(as == ALT_E_SUCCESS);
+ as = alt_clk_freq_get(ALT_CLK_SDMMC, &sc->ciu_clock);
+ BSD_ASSERT(as == ALT_E_SUCCESS);
+ sc->ciu_clock /= 4;
+
+ sc->des = rtems_cache_coherent_allocate(des_size, 0, 0);
+ if (sc->des == NULL) {
+ return (ENOMEM);
+ }
+ memset(__DEVOLATILE(void *, sc->des), 0, des_size);
+#endif
+
+ return (0);
+}
+
+static void
+dw_mmc_platform_install_intr(struct dw_mmc_softc *sc)
+{
+ rtems_vector_number irq =
+#ifdef DW_MMC_ALTERA_CYCLONE_V
+ ALT_INT_INTERRUPT_SDMMC_IRQ;
+#else
+ UINT32_MAX;
+#endif
+ rtems_status_code rs;
+
+ /*
+ * Activate the interrupt
+ */
+ rs = rtems_interrupt_handler_install(irq, "DW MMC",
+ RTEMS_INTERRUPT_SHARED, dw_mmc_intr, sc);
+ BSD_ASSERT(rs == RTEMS_SUCCESSFUL);
+}
+
+static bool
+dw_mmc_platform_set_clock(struct dw_mmc_softc *sc, uint32_t card_clock)
+{
+ bool use_hold_reg;
+
+#ifdef DW_MMC_ALTERA_CYCLONE_V
+ uint32_t drvsel;
+ uint32_t smplsel;
+ uint32_t ctl;
+ ALT_STATUS_CODE as;
+
+ /* FIXME: Values taken from U-Boot, not clear how they are determined */
+ if (card_clock > 25000000) {
+ drvsel = 3;
+ smplsel = 7;
+ } else {
+ drvsel = 3;
+ smplsel = 0;
+ }
+
+ use_hold_reg = drvsel != 0;
+
+ as = alt_clk_clock_disable(ALT_CLK_SDMMC);
+ BSD_ASSERT(as == ALT_E_SUCCESS);
+
+ ctl = alt_read_word(ALT_SYSMGR_SDMMC_CTL_ADDR);
+ ctl &= ALT_SYSMGR_SDMMC_CTL_DRVSEL_CLR_MSK
+ & ALT_SYSMGR_SDMMC_CTL_SMPLSEL_CLR_MSK;
+ ctl |= ALT_SYSMGR_SDMMC_CTL_DRVSEL_SET(drvsel)
+ | ALT_SYSMGR_SDMMC_CTL_SMPLSEL_SET(smplsel);
+ alt_write_word(ALT_SYSMGR_SDMMC_CTL_ADDR, ctl);
+
+ as = alt_clk_clock_enable(ALT_CLK_SDMMC);
+ BSD_ASSERT(as == ALT_E_SUCCESS);
+#else
+ use_hold_reg = false;
+#endif
+
+ return use_hold_reg;
+}
+
+static void
+dw_mmc_platform_fini(struct dw_mmc_softc *sc)
+{
+#ifdef DW_MMC_ALTERA_CYCLONE_V
+ rtems_cache_coherent_free(__DEVOLATILE(void *, sc->des));
+#endif
+}
+
+static int
+dw_mmc_attach(device_t dev)
+{
+ struct dw_mmc_softc *sc = device_get_softc(dev);
+ int err;
+
+ sc->dev = dev;
+
+ err = dw_mmc_platform_init(sc);
+ if (err != 0) {
+ return (err);
+ }
+
+ dw_mmc_fini(sc);
+ err = dw_mmc_init(sc);
+ if (err != 0) {
+ dw_mmc_platform_fini(sc);
+
+ return (err);
+ }
+
+ DW_MMC_LOCK_INIT(sc);
+ DW_MMC_BUS_LOCK_INIT(sc);
+
+ dw_mmc_platform_install_intr(sc);
+
+ sc->host.f_min = 400000;
+ sc->host.f_max = (int) sc->ciu_clock;
+ if (sc->host.f_max > 50000000)
+ sc->host.f_max = 50000000; /* Limit to 50MHz */
+
+ sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
+
+ /* FIXME: MMC_CAP_8_BIT_DATA for eSDIO? */
+ sc->host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_HSPEED;
+
+ device_add_child(dev, "mmc", 0);
+ device_set_ivars(dev, &sc->host);
+ err = bus_generic_attach(dev);
+
+ return (err);
+}
+
+static int
+dw_mmc_detach(device_t dev)
+{
+ struct dw_mmc_softc *sc = device_get_softc(dev);
+
+ dw_mmc_fini(sc);
+
+ /* FIXME: Implement */
+ BSD_ASSERT(0);
+
+ return (EBUSY);
+}
+
+static int
+dw_mmc_cmd_wait(struct dw_mmc_softc *sc)
+{
+ rtems_interval timeout = rtems_clock_tick_later_usec(250000);
+
+ do {
+ if ((RD4(sc, DW_MMC_CMD) & DW_MMC_CMD_START) == 0) {
+ return 0;
+ }
+ } while (rtems_clock_tick_before(timeout));
+
+ return EBUSY;
+}
+
+static void
+dw_mmc_cmd_start(struct dw_mmc_softc *sc, uint32_t cmd, uint32_t cmdarg)
+{
+ WR4(sc, DW_MMC_CMDARG, cmdarg);
+ cmd |= DW_MMC_CMD_START;
+ WR4(sc, DW_MMC_CMD, cmd);
+}
+
+static int
+dw_mmc_cmd_update_clock(struct dw_mmc_softc *sc)
+{
+ dw_mmc_cmd_start(sc,
+ DW_MMC_CMD_UPDATE_CLK | DW_MMC_CMD_PRV_DATA_WAIT, 0);
+
+ return dw_mmc_cmd_wait(sc);
+}
+
+static int
+dw_mmc_set_clock(struct dw_mmc_softc *sc, uint32_t card_clock)
+{
+ uint32_t clkdiv;
+ int err;
+
+ if (sc->card_clock == card_clock) {
+ return 0;
+ }
+
+ sc->card_clock = card_clock;
+
+ /* Disable card clock */
+ WR4(sc, DW_MMC_CLKENA, 0);
+
+ err = dw_mmc_cmd_update_clock(sc);
+ if (err != 0) {
+ return err;
+ }
+
+ if (card_clock == 0) {
+ return 0;
+ }
+
+ if (dw_mmc_platform_set_clock(sc, card_clock)) {
+ sc->cmdr_flags |= DW_MMC_CMD_USE_HOLD_REG;
+ } else {
+ sc->cmdr_flags &= ~DW_MMC_CMD_USE_HOLD_REG;
+ }
+
+ if (card_clock == sc->ciu_clock) {
+ clkdiv = 0;
+ } else {
+ uint32_t s = 2 * card_clock;
+
+ clkdiv = (sc->ciu_clock + s - 1) / s;
+ }
+
+ WR4(sc, DW_MMC_CLKDIV, clkdiv);
+ WR4(sc, DW_MMC_CLKSRC, 0);
+
+ err = dw_mmc_cmd_update_clock(sc);
+ if (err != 0) {
+ return err;
+ }
+
+ /* Enable card clock */
+ WR4(sc, DW_MMC_CLKENA, DW_MMC_CLKEN_ENABLE);
+
+ return dw_mmc_cmd_update_clock(sc);
+}
+
+static int
+dw_mmc_update_ios(device_t brdev, device_t reqdev)
+{
+ struct dw_mmc_softc *sc = device_get_softc(brdev);
+ struct mmc_host *host;
+ struct mmc_ios *ios;
+ uint32_t ctype;
+ int err;
+
+ DW_MMC_LOCK(sc);
+
+ host = &sc->host;
+ ios = &host->ios;
+
+ err = dw_mmc_set_clock(sc, (uint32_t) ios->clock);
+ if (err != 0) {
+ return (err);
+ }
+
+ if (ios->power_mode == power_off) {
+ WR4(sc, DW_MMC_PWREN, 0);
+ } else {
+ sc->cmdr_flags |= DW_MMC_CMD_SEND_INIT;
+ WR4(sc, DW_MMC_PWREN, DW_MMC_PWREN_ENABLE);
+ }
+
+ switch (ios->bus_width) {
+ default:
+ BSD_ASSERT(ios->bus_width == bus_width_1);
+ ctype = DW_MMC_CTYPE_1BIT;
+ break;
+ case bus_width_4:
+ ctype = DW_MMC_CTYPE_4BIT;
+ break;
+ case bus_width_8:
+ ctype = DW_MMC_CTYPE_8BIT;
+ break;
+ }
+
+ WR4(sc, DW_MMC_CTYPE, ctype);
+
+ DW_MMC_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+dw_mmc_fifo_and_dma_reset(struct dw_mmc_softc *sc)
+{
+ uint32_t ctrl_resets = DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET;
+ uint32_t ctrl = RD4(sc, DW_MMC_CTRL);
+
+ ctrl |= ctrl_resets;
+
+ WR4(sc, DW_MMC_CTRL, ctrl);
+
+ return dw_mmc_poll_reset_completion(sc, ctrl_resets);
+}
+
+static int
+dw_mmc_cmd_read_response(struct dw_mmc_softc *sc, struct mmc_command *cmd,
+ uint32_t intsts)
+{
+ if ((intsts & DW_MMC_INT_RTO) != 0) {
+ return MMC_ERR_TIMEOUT;
+ } else if ((intsts & DW_MMC_INT_RCRC) != 0
+ && (cmd->flags & MMC_RSP_CRC) != 0) {
+ return MMC_ERR_BADCRC;
+ } else if ((intsts & DW_MMC_INT_RE) != 0) {
+ return MMC_ERR_FAILED;
+ }
+
+ if ((cmd->flags & MMC_RSP_PRESENT) != 0) {
+ uint32_t *resp = &cmd->resp[0];
+
+ if ((cmd->flags & MMC_RSP_136) != 0) {
+ resp[3] = RD4(sc, DW_MMC_RESP0);
+ resp[2] = RD4(sc, DW_MMC_RESP1);
+ resp[1] = RD4(sc, DW_MMC_RESP2);
+ resp[0] = RD4(sc, DW_MMC_RESP3);
+ } else {
+ resp[0] = RD4(sc, DW_MMC_RESP0);
+ }
+ }
+
+ return MMC_ERR_NONE;
+}
+
+static uint32_t
+dw_mmc_cmd_data_read(struct dw_mmc_softc *sc, struct mmc_data *data,
+ uint32_t *data32, size_t count_bytes)
+{
+ uint32_t intsts = 0;
+
+ while (count_bytes > 0) {
+ uint32_t status;
+ size_t available_words;
+ size_t dangling_bytes = 0;
+ size_t i;
+
+ intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_RXDR
+ | DW_MMC_INT_DTO | DW_MMC_INT_HTO);
+
+ if (intsts != 0) {
+ return intsts;
+ }
+
+ status = RD4(sc, DW_MMC_STATUS);
+ available_words = DW_MMC_STATUS_GET_FIFO_CNT(status);
+
+ if (available_words * DW_MMC_FIFO_WIDTH > count_bytes) {
+ dangling_bytes = count_bytes % DW_MMC_FIFO_WIDTH;
+ --available_words;
+ }
+
+ for (i = 0; i < available_words; i++) {
+ data32[i] = RD4(sc, DW_MMC_DATA);
+ }
+
+ data32 += available_words;
+ count_bytes -= available_words * DW_MMC_FIFO_WIDTH;
+
+ if (dangling_bytes != 0) {
+ uint32_t tmp = RD4(sc, DW_MMC_DATA);
+
+ memcpy(data32, &tmp, dangling_bytes);
+ BSD_ASSERT(count_bytes == dangling_bytes);
+ count_bytes = 0;
+ }
+ }
+
+ if ((data->flags & MMC_DATA_MULTI) != 0) {
+ intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_ACD);
+ }
+
+ return intsts;
+}
+
+static uint32_t
+dw_mmc_cmd_data_write(struct dw_mmc_softc *sc, struct mmc_data *data,
+ uint32_t *data32, size_t count_bytes)
+{
+ uint32_t intsts;
+
+ while (count_bytes > 0) {
+ uint32_t status;
+ size_t pending_words = count_bytes / DW_MMC_FIFO_WIDTH;
+ size_t free_words;
+ size_t dangling_bytes;
+ size_t words_to_write;
+ size_t i;
+
+ intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_TXDR
+ | DW_MMC_INT_HTO);
+
+ if (intsts != 0) {
+ return intsts;
+ }
+
+ status = RD4(sc, DW_MMC_STATUS);
+ free_words = DW_MMC_FIFO_DEPTH - DW_MMC_STATUS_GET_FIFO_CNT(status);
+
+ if (pending_words >= free_words) {
+ words_to_write = free_words;
+ dangling_bytes = 0;
+ } else {
+ words_to_write = pending_words;
+ dangling_bytes = count_bytes % DW_MMC_FIFO_WIDTH;
+ }
+
+ for (i = 0; i < words_to_write; i++) {
+ WR4(sc, DW_MMC_DATA, data32[i]);
+ }
+
+ data32 += words_to_write;
+ count_bytes -= words_to_write * DW_MMC_FIFO_WIDTH;
+
+ if (dangling_bytes != 0) {
+ uint32_t tmp = 0;
+
+ memcpy(&tmp, &data32[0], dangling_bytes);
+ WR4(sc, DW_MMC_DATA, tmp);
+ BSD_ASSERT(count_bytes == dangling_bytes);
+ count_bytes = 0;
+ }
+ }
+
+ intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_DTO);
+
+ if ((data->flags & MMC_DATA_MULTI) != 0 && intsts == 0) {
+ dw_mmc_poll_intsts(sc, DW_MMC_INT_ACD);
+ }
+
+ return intsts;
+}
+
+static uint32_t
+dw_mmc_cmd_data_transfer(struct dw_mmc_softc *sc, struct mmc_data *data,
+ size_t done_bytes, bool use_dma)
+{
+ uint32_t *data32 = (uint32_t *) ((char *) data->data + done_bytes);
+ bool do_write = (data->flags & MMC_DATA_WRITE) != 0;
+ uint32_t intsts;
+
+ if (use_dma) {
+ dw_mmc_wait_for_interrupt(sc, DW_MMC_INT_DTO);
+ intsts = dw_mmc_poll_intsts(sc, DW_MMC_INT_DTO);
+
+ if ((data->flags & MMC_DATA_MULTI) != 0 && intsts == 0) {
+ dw_mmc_poll_intsts(sc, DW_MMC_INT_ACD);
+ }
+
+ if (!do_write) {
+ rtems_cache_invalidate_multiple_data_lines(data->data,
+ data->len);
+ }
+ } else {
+ size_t count_bytes = data->len - done_bytes;
+
+ if (do_write) {
+ intsts = dw_mmc_cmd_data_write(sc, data, data32, count_bytes);
+ } else {
+ intsts = dw_mmc_cmd_data_read(sc, data, data32, count_bytes);
+ }
+ }
+
+ return intsts;
+}
+
+static int
+dw_mmc_cmd_data_finish(struct dw_mmc_softc *sc, uint32_t intsts)
+{
+ int mmc_err = MMC_ERR_NONE;
+
+ if ((intsts & DW_MMC_INT_ERROR) != 0) {
+ if ((intsts & DW_MMC_INT_DCRC) != 0) {
+ mmc_err = MMC_ERR_BADCRC;
+ } else if ((intsts & DW_MMC_INT_EBE) != 0) {
+ mmc_err = MMC_ERR_FAILED;
+ } else if ((intsts & DW_MMC_INT_DRTO) != 0) {
+ mmc_err = MMC_ERR_TIMEOUT;
+ } else {
+ mmc_err = MMC_ERR_FAILED;
+ }
+ }
+
+ return mmc_err;
+}
+
+static int
+dw_mmc_cmd_done(struct dw_mmc_softc *sc, struct mmc_command *cmd,
+ struct mmc_data *data, size_t done_bytes, bool use_dma)
+{
+ uint32_t intsts;
+ int mmc_err;
+
+ dw_mmc_wait_for_interrupt(sc, DW_MMC_INT_CMD_DONE);
+
+ intsts = RD4(sc, DW_MMC_RINTSTS);
+ WR4(sc, DW_MMC_RINTSTS,
+ intsts & (DW_MMC_INT_ERROR | DW_MMC_INT_CMD_DONE));
+
+ mmc_err = dw_mmc_cmd_read_response(sc, cmd, intsts);
+ if (mmc_err != 0) {
+ return mmc_err;
+ }
+
+ if (data != NULL) {
+ intsts = dw_mmc_cmd_data_transfer(sc, data, done_bytes, use_dma);
+ mmc_err = dw_mmc_cmd_data_finish(sc, intsts);
+ }
+
+ return mmc_err;
+}
+
+static size_t
+dw_mmc_fill_fifo(struct dw_mmc_softc *sc, struct mmc_data *data)
+{
+ uint32_t *data32 = data->data;
+ size_t count_bytes = data->len;
+ size_t count_words = 0;
+ size_t dangling_bytes;
+ size_t i;
+
+ if (count_bytes >= DW_MMC_FIFO_DEPTH * DW_MMC_FIFO_WIDTH) {
+ count_words = DW_MMC_FIFO_DEPTH;
+ dangling_bytes = 0;
+ } else {
+ count_words = count_bytes / DW_MMC_FIFO_WIDTH;
+ dangling_bytes = count_bytes % DW_MMC_FIFO_WIDTH;
+ }
+
+ for (i = 0; i < count_words; ++i) {
+ WR4(sc, DW_MMC_DATA, data32[i]);
+ }
+
+ if (dangling_bytes) {
+ uint32_t tmp = 0;
+
+ memcpy(&tmp, &data32[i], dangling_bytes);
+ WR4(sc, DW_MMC_DATA, tmp);
+ }
+
+ return count_words * DW_MMC_FIFO_WIDTH + dangling_bytes;
+}
+
+static bool dw_mmc_dma_can_use(const struct mmc_data *data)
+{
+ uintptr_t cache_line = 32;
+
+ return data->len >= cache_line
+ && ((data->len | (uintptr_t) data->data) & (cache_line - 1)) == 0;
+}
+
+static void
+dw_mmc_dma_setup(struct dw_mmc_softc *sc, struct mmc_data *data)
+{
+ volatile struct dw_mmc_des *des = sc->des;
+ uint32_t buf = (uint32_t) data->data;
+ size_t count_bytes = data->len;
+ uint32_t fs = DW_MMC_DES0_FS;
+ size_t s = 2 * DW_MMC_DES1_MAX_BS;
+ size_t n = (count_bytes + s - 1) / s;
+ size_t m = count_bytes % s;
+ size_t i;
+
+ for (i = 0; i < n - 1; ++i) {
+ des[i].des1 = DW_MMC_DES1_BS1(DW_MMC_DES1_MAX_BS)
+ | DW_MMC_DES1_BS2(DW_MMC_DES1_MAX_BS);
+ des[i].des2 = buf;
+ buf += DW_MMC_DES1_MAX_BS;
+ des[i].des3 = buf;
+ buf += DW_MMC_DES1_MAX_BS;
+ des[i].des0 = DW_MMC_DES0_OWN | fs;
+ fs = 0;
+ }
+
+ if (m > DW_MMC_DES1_MAX_BS) {
+ des[i].des1 = DW_MMC_DES1_BS1(DW_MMC_DES1_MAX_BS)
+ | DW_MMC_DES1_BS2(m - DW_MMC_DES1_MAX_BS);
+ des[i].des2 = buf;
+ buf += DW_MMC_DES1_MAX_BS;
+ des[i].des3 = buf;
+ } else {
+ des[i].des1 = DW_MMC_DES1_BS1(m);
+ des[i].des2 = buf;
+ des[i].des3 = 0;
+ }
+
+ des[i].des0 = DW_MMC_DES0_OWN | DW_MMC_DES0_ER | fs | DW_MMC_DES0_LD;
+
+#ifdef __arm__
+ _ARM_Data_synchronization_barrier();
+#else
+ /* TODO */
+#endif
+}
+
+
+static void
+dw_mmc_cmd_do(struct dw_mmc_softc *sc, struct mmc_request *req,
+ struct mmc_command *cmd)
+{
+ size_t done_bytes = 0;
+ bool use_dma = false;
+ struct mmc_data *data;
+ uint32_t cmdr;
+
+ data = cmd->data;
+ cmdr = cmd->opcode;
+
+ if (cmd->opcode == MMC_STOP_TRANSMISSION) {
+ cmdr |= DW_MMC_CMD_SEND_STOP;
+ } else {
+ cmdr |= DW_MMC_CMD_PRV_DATA_WAIT;
+ }
+
+ cmdr |= sc->cmdr_flags;
+ sc->cmdr_flags &= ~DW_MMC_CMD_SEND_INIT;
+
+ if (MMC_RSP(cmd->flags) != MMC_RSP_NONE) {
+ cmdr |= DW_MMC_CMD_RESP_EXP;
+
+ if ((cmd->flags & MMC_RSP_136) != 0) {
+ cmdr |= DW_MMC_CMD_RESP_LONG;
+ }
+ }
+
+ if ((cmd->flags & MMC_RSP_CRC) != 0) {
+ cmdr |= DW_MMC_CMD_RESP_CRC;
+ }
+
+ if (data != NULL) {
+ size_t count_bytes = data->len;
+ uint32_t ctrl;
+ int mmc_err;
+
+ cmdr |= DW_MMC_CMD_DATA_EXP;
+
+ if ((data->flags & MMC_DATA_MULTI) != 0) {
+ cmdr |= DW_MMC_CMD_SEND_STOP;
+ }
+
+ mmc_err = dw_mmc_fifo_and_dma_reset(sc);
+ if (mmc_err != 0) {
+ cmd->error = mmc_err;
+ return;
+ }
+
+ use_dma = dw_mmc_dma_can_use(data);
+
+ ctrl = RD4(sc, DW_MMC_CTRL);
+
+ if (use_dma) {
+ ctrl |= DW_MMC_CTRL_DMA_ENABLE;
+ } else {
+ ctrl &= ~DW_MMC_CTRL_DMA_ENABLE;
+ }
+
+ WR4(sc, DW_MMC_CTRL, ctrl);
+ WR4(sc, DW_MMC_BLKSIZ, MIN(count_bytes, MMC_SECTOR_SIZE));
+ WR4(sc, DW_MMC_BYTCNT, count_bytes);
+
+ if ((data->flags & MMC_DATA_WRITE) != 0) {
+ cmdr |= DW_MMC_CMD_DATA_WR;
+
+ if (use_dma) {
+ rtems_cache_flush_multiple_data_lines(data->data,
+ count_bytes);
+ } else {
+ done_bytes = dw_mmc_fill_fifo(sc, data);
+ }
+ } else if (use_dma) {
+ rtems_cache_invalidate_multiple_data_lines(data->data,
+ count_bytes);
+ }
+
+ if (use_dma) {
+ if (count_bytes > DW_MMC_MAX_DMA_TRANSFER_BYTES) {
+ cmd->error = MMC_ERR_INVALID;
+ return;
+ }
+
+ dw_mmc_dma_setup(sc, data);
+ }
+ }
+
+ dw_mmc_cmd_start(sc, cmdr, cmd->arg);
+
+ if (use_dma) {
+ WR4(sc, DW_MMC_PLDMND, 0);
+ }
+
+ cmd->error = dw_mmc_cmd_done(sc, cmd, data, done_bytes, use_dma);
+}
+
+static int
+dw_mmc_request(device_t brdev, device_t reqdev, struct mmc_request *req)
+{
+ struct dw_mmc_softc *sc = device_get_softc(brdev);
+
+ DW_MMC_LOCK(sc);
+ dw_mmc_cmd_do(sc, req, req->cmd);
+ DW_MMC_UNLOCK(sc);
+
+ (*req->done)(req);
+
+ return (0);
+}
+
+static int
+dw_mmc_get_ro(device_t brdev, device_t reqdev)
+{
+ return (0);
+}
+
+static int
+dw_mmc_acquire_host(device_t brdev, device_t reqdev)
+{
+ struct dw_mmc_softc *sc = device_get_softc(brdev);
+
+ DW_MMC_BUS_LOCK(sc);
+
+ return (0);
+}
+
+static int
+dw_mmc_release_host(device_t brdev, device_t reqdev)
+{
+ struct dw_mmc_softc *sc = device_get_softc(brdev);
+
+ DW_MMC_BUS_UNLOCK(sc);
+
+ return (0);
+}
+
+static void
+dw_mmc_intr(void *arg)
+{
+ struct dw_mmc_softc *sc = (struct dw_mmc_softc *) arg;
+ rtems_status_code rs;
+
+ WR4(sc, DW_MMC_INTMASK, 0);
+
+ rs = rtems_event_transient_send(sc->task_id);
+ BSD_ASSERT(rs == RTEMS_SUCCESSFUL);
+}
+
+static int
+dw_mmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
+{
+ struct dw_mmc_softc *sc = device_get_softc(bus);
+
+ switch (which) {
+ default:
+ return (EINVAL);
+ case MMCBR_IVAR_BUS_MODE:
+ *(int *)result = sc->host.ios.bus_mode;
+ break;
+ case MMCBR_IVAR_BUS_WIDTH:
+ *(int *)result = sc->host.ios.bus_width;
+ break;
+ case MMCBR_IVAR_CHIP_SELECT:
+ *(int *)result = sc->host.ios.chip_select;
+ break;
+ case MMCBR_IVAR_CLOCK:
+ *(int *)result = sc->host.ios.clock;
+ break;
+ case MMCBR_IVAR_F_MIN:
+ *(int *)result = sc->host.f_min;
+ break;
+ case MMCBR_IVAR_F_MAX:
+ *(int *)result = sc->host.f_max;
+ break;
+ case MMCBR_IVAR_HOST_OCR:
+ *(int *)result = sc->host.host_ocr;
+ break;
+ case MMCBR_IVAR_MODE:
+ *(int *)result = sc->host.mode;
+ break;
+ case MMCBR_IVAR_OCR:
+ *(int *)result = sc->host.ocr;
+ break;
+ case MMCBR_IVAR_POWER_MODE:
+ *(int *)result = sc->host.ios.power_mode;
+ break;
+ case MMCBR_IVAR_VDD:
+ *(int *)result = sc->host.ios.vdd;
+ break;
+ case MMCBR_IVAR_CAPS:
+ *(int *)result = sc->host.caps;
+ break;
+ case MMCBR_IVAR_MAX_DATA:
+ *(int *)result = 1;
+ break;
+ }
+ return (0);
+}
+
+static int
+dw_mmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
+{
+ struct dw_mmc_softc *sc = device_get_softc(bus);
+
+ switch (which) {
+ default:
+ return (EINVAL);
+ case MMCBR_IVAR_BUS_MODE:
+ sc->host.ios.bus_mode = value;
+ break;
+ case MMCBR_IVAR_BUS_WIDTH:
+ sc->host.ios.bus_width = value;
+ break;
+ case MMCBR_IVAR_CHIP_SELECT:
+ sc->host.ios.chip_select = value;
+ break;
+ case MMCBR_IVAR_CLOCK:
+ sc->host.ios.clock = value;
+ break;
+ case MMCBR_IVAR_MODE:
+ sc->host.mode = value;
+ break;
+ case MMCBR_IVAR_OCR:
+ sc->host.ocr = value;
+ break;
+ case MMCBR_IVAR_POWER_MODE:
+ sc->host.ios.power_mode = value;
+ break;
+ case MMCBR_IVAR_VDD:
+ sc->host.ios.vdd = value;
+ break;
+ /* These are read-only */
+ case MMCBR_IVAR_CAPS:
+ case MMCBR_IVAR_HOST_OCR:
+ case MMCBR_IVAR_F_MIN:
+ case MMCBR_IVAR_F_MAX:
+ case MMCBR_IVAR_MAX_DATA:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+static device_method_t dw_mmc_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, dw_mmc_probe),
+ DEVMETHOD(device_attach, dw_mmc_attach),
+ DEVMETHOD(device_detach, dw_mmc_detach),
+
+ /* Bus interface */
+ DEVMETHOD(bus_read_ivar, dw_mmc_read_ivar),
+ DEVMETHOD(bus_write_ivar, dw_mmc_write_ivar),
+
+ /* mmcbr_if */
+ DEVMETHOD(mmcbr_update_ios, dw_mmc_update_ios),
+ DEVMETHOD(mmcbr_request, dw_mmc_request),
+ DEVMETHOD(mmcbr_get_ro, dw_mmc_get_ro),
+ DEVMETHOD(mmcbr_acquire_host, dw_mmc_acquire_host),
+ DEVMETHOD(mmcbr_release_host, dw_mmc_release_host),
+
+ DEVMETHOD_END
+};
+
+static driver_t dw_mmc_driver = {
+ "dw_mmc",
+ dw_mmc_methods,
+ sizeof(struct dw_mmc_softc)
+};
+
+static devclass_t dw_mmc_devclass;
+
+DRIVER_MODULE(dw_mmc, nexus, dw_mmc_driver, dw_mmc_devclass, NULL, NULL);
diff --git a/rtemsbsd/sys/dev/dw_mmc/dw_mmcreg.h b/rtemsbsd/sys/dev/dw_mmc/dw_mmcreg.h
new file mode 100644
index 00000000..d6936a56
--- /dev/null
+++ b/rtemsbsd/sys/dev/dw_mmc/dw_mmcreg.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2014 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <info@embedded-brains.de>
+ *
+ * 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ */
+
+#ifndef DW_MMC_DW_MMCREG_H
+#define DW_MMC_DW_MMCREG_H
+
+#define DW_MMC_CTRL 0x000
+#define DW_MMC_PWREN 0x004
+#define DW_MMC_CLKDIV 0x008
+#define DW_MMC_CLKSRC 0x00c
+#define DW_MMC_CLKENA 0x010
+#define DW_MMC_TMOUT 0x014
+#define DW_MMC_CTYPE 0x018
+#define DW_MMC_BLKSIZ 0x01c
+#define DW_MMC_BYTCNT 0x020
+#define DW_MMC_INTMASK 0x024
+#define DW_MMC_CMDARG 0x028
+#define DW_MMC_CMD 0x02c
+#define DW_MMC_RESP0 0x030
+#define DW_MMC_RESP1 0x034
+#define DW_MMC_RESP2 0x038
+#define DW_MMC_RESP3 0x03c
+#define DW_MMC_MINTSTS 0x040
+#define DW_MMC_RINTSTS 0x044
+#define DW_MMC_STATUS 0x048
+#define DW_MMC_FIFOTH 0x04c
+#define DW_MMC_CDETECT 0x050
+#define DW_MMC_WRTPRT 0x054
+#define DW_MMC_GPIO 0x058
+#define DW_MMC_TCBCNT 0x05c
+#define DW_MMC_TBBCNT 0x060
+#define DW_MMC_DEBNCE 0x064
+#define DW_MMC_USRID 0x068
+#define DW_MMC_VERID 0x06c
+#define DW_MMC_HCON 0x070
+#define DW_MMC_UHS_REG 0x074
+#define DW_MMC_RST_N 0x078
+#define DW_MMC_BMOD 0x080
+#define DW_MMC_PLDMND 0x084
+#define DW_MMC_DBADDR 0x088
+#define DW_MMC_IDSTS 0x08c
+#define DW_MMC_IDINTEN 0x090
+#define DW_MMC_DSCADDR 0x094
+#define DW_MMC_BUFADDR 0x098
+#define DW_MMC_DATA 0x200
+
+/* Control Register */
+#define DW_MMC_CTRL_DMA_ENABLE (1u << 25)
+#define DW_MMC_CTRL_CEATA_INT_EN (1u << 11)
+#define DW_MMC_CTRL_SEND_AS_CCSD (1u << 10)
+#define DW_MMC_CTRL_SEND_CCSD (1u << 9)
+#define DW_MMC_CTRL_ABRT_READ_DATA (1u << 8)
+#define DW_MMC_CTRL_SEND_IRQ_RESP (1u << 7)
+#define DW_MMC_CTRL_READ_WAIT (1u << 6)
+#define DW_MMC_CTRL_INT_ENABLE (1u << 4)
+#define DW_MMC_CTRL_DMA_RESET (1u << 2)
+#define DW_MMC_CTRL_FIFO_RESET (1u << 1)
+#define DW_MMC_CTRL_RESET (1u << 0)
+
+/* Power Enable Register */
+#define DW_MMC_PWREN_ENABLE (1u << 0)
+
+/* Clock Enable Register */
+#define DW_MMC_CLKEN_LOW_PWR (1u << 16)
+#define DW_MMC_CLKEN_ENABLE (1u << 0)
+
+/* Timeout Register */
+#define DW_MMC_TMOUT_DATA(x) ((x) << 8)
+#define DW_MMC_TMOUT_DATA_MSK 0xffffff00
+#define DW_MMC_TMOUT_RESP(x) ((x) & 0xFF)
+#define DW_MMC_TMOUT_RESP_MSK 0xff
+
+/* Card Type Register */
+#define DW_MMC_CTYPE_8BIT (1u << 16)
+#define DW_MMC_CTYPE_4BIT (1u << 0)
+#define DW_MMC_CTYPE_1BIT 0
+
+/* Interrupt Status and Interrupt Mask Register */
+#define DW_MMC_INT_SDIO(x) (1u << (16 + (x)))
+#define DW_MMC_INT_EBE (1u << 15)
+#define DW_MMC_INT_ACD (1u << 14)
+#define DW_MMC_INT_SBE (1u << 13)
+#define DW_MMC_INT_HLE (1u << 12)
+#define DW_MMC_INT_FRUN (1u << 11)
+#define DW_MMC_INT_HTO (1u << 10)
+#define DW_MMC_INT_DRTO (1u << 9)
+#define DW_MMC_INT_RTO (1u << 8)
+#define DW_MMC_INT_DCRC (1u << 7)
+#define DW_MMC_INT_RCRC (1u << 6)
+#define DW_MMC_INT_RXDR (1u << 5)
+#define DW_MMC_INT_TXDR (1u << 4)
+#define DW_MMC_INT_DTO (1u << 3)
+#define DW_MMC_INT_CMD_DONE (1u << 2)
+#define DW_MMC_INT_RE (1u << 1)
+#define DW_MMC_INT_CD (1u << 0)
+#define DW_MMC_INT_ERROR (DW_MMC_INT_RE | DW_MMC_INT_RCRC | DW_MMC_INT_DCRC \
+ | DW_MMC_INT_DRTO | DW_MMC_INT_RTO | DW_MMC_INT_EBE)
+
+/* Command Register */
+#define DW_MMC_CMD_START (1u << 31)
+#define DW_MMC_CMD_USE_HOLD_REG (1u << 29)
+#define DW_MMC_CMD_VOLT_SWITCH (1u << 28)
+#define DW_MMC_CMD_BOOT_MODE (1u << 27)
+#define DW_MMC_CMD_DISABLE_BOOT (1u << 26)
+#define DW_MMC_CMD_EXP_BOOT_ACK (1u << 25)
+#define DW_MMC_CMD_ENABLE_BOOT (1u << 24)
+#define DW_MMC_CMD_CCS_EXP (1u << 23)
+#define DW_MMC_CMD_CEATA_RD (1u << 22)
+#define DW_MMC_CMD_UPDATE_CLK (1u << 21)
+#define DW_MMC_CMD_SEND_INIT (1u << 15)
+#define DW_MMC_CMD_STOP_ABRT (1u << 14)
+#define DW_MMC_CMD_PRV_DATA_WAIT (1u << 13)
+#define DW_MMC_CMD_SEND_STOP (1u << 12)
+#define DW_MMC_CMD_STREAM_MODE (1u << 11)
+#define DW_MMC_CMD_DATA_WR (1u << 10)
+#define DW_MMC_CMD_DATA_EXP (1u << 9)
+#define DW_MMC_CMD_RESP_CRC (1u << 8)
+#define DW_MMC_CMD_RESP_LONG (1u << 7)
+#define DW_MMC_CMD_RESP_EXP (1u << 6)
+#define DW_MMC_CMD_INDEX(x) ((x) & 0x1f)
+
+/* Status Register */
+#define DW_MMC_STATUS_GET_FIFO_CNT(x) (((x) >> 17) & 0x1fff)
+#define DW_MMC_STATUS_GET_RESP_IDX(x) (((x) >> 11) & 0x3f)
+#define DW_MMC_STATUS_DS_MC_BUSY (1u << 10)
+#define DW_MMC_STATUS_CARD_DATA_BUSY (1u << 9)
+#define DW_MMC_STATUS_CARD_PRESENT (1u << 8)
+#define DW_MMC_STATUS_GET_FSM_STATE(x) (((x) >> 4) & 0xf)
+#define DW_MMC_STATUS_FIFO_FULL (1u << 3)
+#define DW_MMC_STATUS_FIFO_EMPTY (1u << 2)
+#define DW_MMC_STATUS_FIFO_TX_WM (1u << 1)
+#define DW_MMC_STATUS_FIFO_RX_WM (1u << 0)
+
+/* DMA and FIFO Control Register */
+#define DW_MMC_FIFOTH_BSZ(x) ((x) << 28)
+#define DW_MMC_FIFOTH_BSZ_MSK DW_MMC_FIFOTH_BSZ(0x7)
+#define DW_MMC_FIFOTH_RX_WMARK(x) ((x) << 16)
+#define DW_MMC_FIFOTH_RX_WMARK_MSK DW_MMC_FIFOTH_RX_WMARK(0xfff)
+#define DW_MMC_FIFOTH_TX_WMARK(x) ((x) << 0)
+#define DW_MMC_FIFOTH_TX_WMARK_MSK DW_MMC_FIFOTH_TX_WMARK(0xfff)
+
+/* Card Detect Register */
+#define DW_MMC_CDETECT_NOT_DETECTED (1u << 0)
+
+/* Write Protect Register */
+#define DW_MMC_WRTPRT_ENABLED (1u << 0)
+
+/* Hardware Reset Register */
+#define DW_MMC_RST_N_ACTIVE_MODE (1u << 0)
+
+/* Bus Mode Register */
+#define DW_MMC_BMOD_DE (1u << 7)
+#define DW_MMC_BMOD_FB (1u << 1)
+#define DW_MMC_BMOD_SWR (1u << 0)
+
+/* Internal DMAC Status and Interrupt DMAC Interrupt Enable Register */
+#define DW_MMC_IDMAC_INT_GET_FSM(x) (((x) >> 13) & 0xf)
+#define DW_MMC_IDMAC_INT_GET_EB(x) (((x) >> 10) & 0x7)
+#define DW_MMC_IDMAC_INT_AIS (1u << 9)
+#define DW_MMC_IDMAC_INT_NIS (1u << 8)
+#define DW_MMC_IDMAC_INT_CES (1u << 5)
+#define DW_MMC_IDMAC_INT_DU (1u << 4)
+#define DW_MMC_IDMAC_INT_FBE (1u << 2)
+#define DW_MMC_IDMAC_INT_RI (1u << 1)
+#define DW_MMC_IDMAC_INT_TI (1u << 0)
+
+/* Internal DMA descriptor */
+
+struct dw_mmc_des {
+ uint32_t des0;
+ uint32_t des1;
+ uint32_t des2;
+ uint32_t des3;
+};
+
+#define DW_MMC_DES0_OWN (1u << 31)
+#define DW_MMC_DES0_CES (1u << 30)
+#define DW_MMC_DES0_ER (1u << 5)
+#define DW_MMC_DES0_CH (1u << 4)
+#define DW_MMC_DES0_FS (1u << 3)
+#define DW_MMC_DES0_LD (1u << 2)
+#define DW_MMC_DES0_DIC (1u << 1)
+
+#define DW_MMC_DES1_BS2(x) ((x) << 13)
+#define DW_MMC_DES1_BS1(x) ((x) << 0)
+#define DW_MMC_DES1_MAX_BS 4096
+
+/* FIFO dimensions */
+#define DW_MMC_FIFO_DEPTH 1024
+#define DW_MMC_FIFO_WIDTH 4
+
+#endif /* DW_MMC_DW_MMCREG_H */