]> Zhao Yanbai Git Server - minix.git/commitdiff
MMC driver. 58/58/3
authorKees Jongenburger <kees.jongenburger@gmail.com>
Wed, 3 Oct 2012 08:55:40 +0000 (10:55 +0200)
committerKees Jongenburger <kees.jongenburger@gmail.com>
Mon, 8 Oct 2012 07:11:17 +0000 (09:11 +0200)
Change-Id: I0d460d63070855df9b11eaf3d33eb7bb89c570f1

drivers/mmc/Makefile [new file with mode: 0644]
drivers/mmc/README.txt [new file with mode: 0644]
drivers/mmc/mmcblk.c [new file with mode: 0644]
drivers/mmc/mmchost.h [new file with mode: 0644]
drivers/mmc/mmchost_mmchs.c [new file with mode: 0644]
drivers/mmc/mmclog.h [new file with mode: 0644]
drivers/mmc/omap_mmc.h [new file with mode: 0644]
etc/system.conf

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
new file mode 100644 (file)
index 0000000..52afdb2
--- /dev/null
@@ -0,0 +1,17 @@
+# Makefile for the mmc driver.
+PROG=  mmc
+SRCS=  mmcblk.c mmchost_mmchs.c mmclog.h sdhcreg.h sdmmcreg.h
+
+DPADD+=        ${LIBBLOCKDRIVER} ${LIBSYS}
+LDADD+=        -lblockdriver -lsys
+CLEANFILES+=.depend mmcblk.d
+
+#
+# This is a system driver.
+CPPFLAGS+= -D_SYSTEM=1
+
+MAN=
+
+BINDIR?= /usr/sbin
+
+.include <minix.service.mk>
diff --git a/drivers/mmc/README.txt b/drivers/mmc/README.txt
new file mode 100644 (file)
index 0000000..cd353ed
--- /dev/null
@@ -0,0 +1,56 @@
+This directory contains code to access MMC based devices.
+
+It was created during the initial port of MINIX to the ARM platform. mmbclk
+implements a normal MINIX block device. It uses the interfaces defined in
+mmchost.h to perform it's operations.
+
+mmchost_mmchs is the MMC host controller driver for the TI omap device range.
+It contains the logic to access SD cards on that device.
+
+ drivers/mmc
+ |-- Makefile        (The makefile)
+ |-- mmclog.h        (A simpel logging system)
+ |-- omap_mmc.h      (TI Omap register definitions)
+ |-- sdhcreg.h       (BSD headers for the MMC layer)
+ |-- sdmmcreg.h      (BSD headers for the MMC layer)
+ |-- mmcblk.c        (MINIX 3 block device)
+ |-- mmchost.h       (interface between the block device and the MMC layer)
+ |-- mmchost_mmchs.c (Driver to use on the ARM port/beagle) 
+ '-- README.txt      (This file)
+
+
+Future work:
+============
+
+* Creating a more generic MMC layer
+The SD protocol is well defined and the imported the netbsd sdhcreg and
+sdmmcreg headers will allow us to make the MMC interface more generic. We would
+like  mmchost_mmchs to be split in a generic part and a specific part. 
+
+* Using interrupts
+At time of writing the interrupt handlers on the ARM port are not implemented.
+Once that is done we will be able to rewrite the code to use proper interrupt
+handlers.
+
+* 4 and 8 bits access
+The driver currently only reads data over a single data line. Adding support
+for 4 or 8 bits(for movinands) mode is very welcome.
+
+* DMA.
+The OMAP driver allows the usage of DMA. Adding DMA support will increase the
+performance of the driver
+
+* Removal of the PRIVCTL call.
+The MMC driver uses memory mapped IO to perform it's operations. On i386 it is
+the pci driver that will grant access to certain piece of memory to a driver.
+On the ARM port we lack pci and other self describing busses. In the current
+driver the driver will itself grant itself access to the correct piece of
+memory but this is unwanted behavior.  We currently as thinking about two
+possible solutions. The first would be to add the memory ranges in system.conf.
+The second would be to modify the PCI driver to grant access to memory based on
+a fixed configuration. For example we could use the driver tree to perform
+device discovery and granting access to devices.
+
+
+* TODO removal
+The driver contains (quite a few) TODO's where the code need to be improved.
diff --git a/drivers/mmc/mmcblk.c b/drivers/mmc/mmcblk.c
new file mode 100644 (file)
index 0000000..c5a1550
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * Block driver for Multi Media Cards (MMC).
+ */
+/* kernel headers */
+#include <minix/syslib.h>
+#include <minix/driver.h>
+#include <minix/blockdriver.h>
+#include <minix/drvlib.h>
+
+/* system headers */
+#include <sys/ioc_disk.h>      /* disk IOCTL's */
+
+/* usr headers */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+
+/* local headers */
+#include "mmchost.h"
+#include "mmclog.h"
+
+/* used for logging */
+static struct mmclog log = {
+       .name = "mmc_block",
+       .log_level = LEVEL_DEBUG,
+       .log_func = default_log
+};
+
+/* holding the current host controller */
+static struct mmc_host host;
+
+/*@TODO REMOVE THIS */
+void
+read_tsc_64(u64_t * t)
+{
+}
+
+u32_t
+tsc_64_to_micros(u64_t tsc)
+{
+       return 0;
+}
+
+#define SUB_PER_DRIVE           (NR_PARTITIONS * NR_PARTITIONS)
+#define NR_SUBDEVS              (MAX_DRIVES * SUB_PER_DRIVE)
+
+/* When passing data over a grant one needs to pass
+ * a buffer to sys_safecopy copybuff is used for that*/
+#define COPYBUFF_SIZE 0x1000   /* 4k buff */
+static unsigned char copybuff[COPYBUFF_SIZE];
+
+static struct sd_slot *get_slot(dev_t minor);
+
+/* Prototypes for the block device */
+static int block_open(dev_t minor, int access);
+static int block_close(dev_t minor);
+static int block_transfer(dev_t minor,
+    int do_write,
+    u64_t position,
+    endpoint_t endpt, iovec_t * iov, unsigned int nr_req, int flags);
+
+static int block_ioctl(dev_t minor,
+    unsigned int request, endpoint_t endpt, cp_grant_id_t grant);
+static struct device *block_part(dev_t minor);
+
+/* System even handling */
+static void sef_local_startup();
+static int block_system_event_cb(int type, sef_init_info_t * info);
+static void block_signal_handler_cb(int signo);
+
+static int apply_env();
+
+#if 0
+/* set the global logging level */
+static void set_log_level(int level);
+#endif
+
+/* Entry points for the BLOCK driver. */
+static struct blockdriver mmc_driver = {
+       BLOCKDRIVER_TYPE_DISK,  /* handle partition requests */
+       block_open,             /* open or mount */
+       block_close,            /* on a close */
+       block_transfer,         /* does the I/O */
+       block_ioctl,            /* ioclt's */
+       NULL,                   /* no need to clean up (yet) */
+       block_part,             /* return partition information */
+       NULL,                   /* no geometry */
+       NULL,                   /* no interrupt processing */
+       NULL,                   /* no alarm processing */
+       NULL,                   /* no processing of other messages */
+       NULL                    /* no threading support */
+};
+
+static int
+apply_env()
+{
+#if 0
+       /* @TODO: re-enable this function when __aeabi_idiv will be present
+        * The following code(env_parse) uses strtol.c and needs __aeabi_idiv */
+       /* apply the env setting passed to this driver parameters accepted
+        * log_level=[0-4] (NONE,WARNING,INFO,DEBUG,TRACE) instance=[0-3]
+        * instance/bus number to use for this driver Passing these arguments
+        * is done when starting the driver using the service command in the
+        * following way service up /sbin/mmcblk -args "log_level=2
+        * instance=1" */
+       long v;
+
+       /* Initialize the verbosity level. */
+       v = 0;
+       if (env_parse("log_level", "d", 0, &v, LEVEL_NONE,
+               LEVEL_TRACE) == EP_SET) {
+               set_log_level(v);
+       }
+
+       /* Find out which driver instance we are. */
+       v = 0;
+       env_parse("instance", "d", 0, &v, 0, 3);
+       if (host.host_set_instance(&host, v)) {
+               mmc_log_warn(&log, "Failed to set mmc instance to  %d\n", v);
+               return -1;      /* NOT OK */
+       }
+#endif
+       return OK;
+}
+
+;
+
+/*===========================================================================*
+ *                    block_open                                             *
+ *===========================================================================*/
+static int
+block_open(dev_t minor, int access)
+{
+       struct sd_slot *slot;
+       slot = get_slot(minor);
+       int i, j;
+       int part_count, sub_part_count;
+
+       i = j = part_count = sub_part_count = 0;
+
+       if (!slot) {
+               mmc_log_debug(&log,
+                   "Not handling open on non existing slot\n");
+               return EIO;
+       }
+
+       assert(slot->host != NULL);
+
+       if (!slot->host->card_detect(slot)) {
+               mmc_log_debug(&log, "No card inserted in the SD slot\n");
+               return EIO;
+       }
+
+       /* If we are already open just increase the open count and return */
+       if (slot->card.state == SD_MODE_DATA_TRANSFER_MODE) {
+               assert(slot->card.open_ct >= 0);
+               slot->card.open_ct++;
+               mmc_log_trace(&log, "increased open count to %d\n",
+                   slot->card.open_ct);
+               return OK;
+       }
+
+       /* We did not have an sd-card inserted so we are going to probe for it 
+        */
+       mmc_log_debug(&log, "First open on (%d)\n", minor);
+       if (!host.card_initialize(slot)) {
+               // * TODO: set card state to INVALID until removed? */
+               return EIO;
+       }
+
+       partition(&mmc_driver, 0 /* first card on bus */ , P_PRIMARY,
+           0 /* atapi device?? */ );
+
+       mmc_log_debug(&log, "descr \toffset(bytes)      size(bytes)\n", minor);
+
+       mmc_log_debug(&log, "disk %d\t0x%016llx 0x%016llx\n", i,
+           slot->card.part[0].dv_base, slot->card.part[0].dv_size);
+       for (i = 1; i < 5; i++) {
+               if (slot->card.part[i].dv_size == 0)
+                       continue;
+               part_count++;
+               mmc_log_debug(&log, "part %d\t0x%016llx 0x%016llx\n", i,
+                   slot->card.part[i].dv_base, slot->card.part[i].dv_size);
+               for (j = 0; j < 4; j++) {
+                       if (slot->card.part[i * 4 + j].dv_size == 0)
+                               continue;
+                       sub_part_count++;
+                       mmc_log_debug(&log,
+                           " sub %d/%d\t0x%016llx 0x%016llx\n", i, j,
+                           slot->card.part[i * 4 + j].dv_base,
+                           slot->card.part[i * 4 + j].dv_size);
+               }
+       }
+       mmc_log_info(&log, "Found %d partitions and %d sub partitions\n",
+           part_count, sub_part_count);
+       slot->card.open_ct++;
+       assert(slot->card.open_ct == 1);
+       return OK;
+}
+
+/*===========================================================================*
+ *                    block_close                                            *
+ *===========================================================================*/
+static int
+block_close(dev_t minor)
+{
+       struct sd_slot *slot;
+
+       slot = get_slot(minor);
+       if (!slot) {
+               mmc_log_debug(&log,
+                   "Not handling open on non existing slot\n");
+               return EIO;
+       }
+
+       /* if we arrived here we expect a card to be present, we will need do
+        * deal with removal later */
+       assert(slot->host != NULL);
+       assert(slot->card.open_ct >= 1);
+
+       /* If this is not the last open count simply decrease the counter and
+        * return */
+       if (slot->card.open_ct > 1) {
+               slot->card.open_ct--;
+               mmc_log_trace(&log, "decreased open count to %d\n",
+                   slot->card.open_ct);
+               return OK;
+       }
+
+       assert(slot->card.open_ct == 1);
+       mmc_log_debug(&log,
+           "freeing the block device as it is no longer used\n");
+
+       /* release the card as check the open_ct should be 0 */
+       slot->host->card_release(&slot->card);
+       assert(slot->card.open_ct == 0);
+       return OK;
+}
+
+static int
+copyto(endpoint_t dst_e,
+    cp_grant_id_t gr_id, vir_bytes offset, vir_bytes address, size_t bytes)
+{
+       /* Helper function that used memcpy to copy data when the endpoint ==
+        * SELF */
+       if (dst_e == SELF) {
+               memcpy((char *) gr_id + offset, (char *) address, bytes);
+               return OK;
+       } else {
+               /* Read io_size bytes from our data at the correct * offset
+                * and write it to the output buffer at 0 */
+               return sys_safecopyto(dst_e, gr_id, offset, address, bytes);
+       }
+}
+
+static int
+copyfrom(endpoint_t src_e,
+    cp_grant_id_t gr_id, vir_bytes offset, vir_bytes address, size_t bytes)
+{
+       /* Helper function that used memcpy to copy data when the endpoint ==
+        * SELF */
+       if (src_e == SELF) {
+               memcpy((char *) address, (char *) gr_id + offset, bytes);
+               return OK;
+       } else {
+               return sys_safecopyfrom(src_e, gr_id, offset, address, bytes);
+       }
+}
+
+/*===========================================================================*
+ *                    block_transfer                                         *
+ *===========================================================================*/
+static int
+block_transfer(dev_t minor,    /* minor device number */
+    int do_write,              /* read or write? */
+    u64_t position,            /* offset on device to read or write */
+    endpoint_t endpt,          /* process doing the request */
+    iovec_t * iov,             /* pointer to read or write request vector */
+    unsigned int nr_req,       /* length of request vector */
+    int flags                  /* transfer flags */
+    )
+{
+       unsigned long counter;
+       iovec_t *ciov;          /* Current IO Vector */
+       struct device *dev;     /* The device used */
+       struct sd_slot *slot;   /* The sd slot the requests is pointed to */
+       vir_bytes io_size;      /* Size to read/write to/from the iov */
+       vir_bytes io_offset;    /* Size to read/write to/from the iov */
+       vir_bytes bytes_written;
+
+       int r, blk_size, i;
+
+       /* Get the current "device" geometry */
+       dev = block_part(minor);
+       if (dev == NULL) {
+               mmc_log_warn(&log,
+                   "Transfer requested on unknown device minor(%d)\n", minor);
+               /* Unknown device */
+               return ENXIO;
+       }
+       mmc_log_trace(&log, "I/O %d %s 0x%llx\n", minor,
+           (do_write) ? "Write" : "Read", position);
+
+       slot = get_slot(minor);
+       assert(slot);
+
+       if (slot->card.blk_size == 0) {
+               mmc_log_warn(&log, "Request on a card with block size of 0\n");
+               return EINVAL;
+       }
+       if (slot->card.blk_size > COPYBUFF_SIZE) {
+               mmc_log_warn(&log,
+                   "Card block size (%d) exceeds internal buffer size %d\n",
+                   slot->card.blk_size, COPYBUFF_SIZE);
+               return EINVAL;
+       }
+
+       /* It is fully up to the driver to decide on restrictions for the
+        * parameters of transfers, in those cases we return EINVAL */
+       if (position % slot->card.blk_size != 0) {
+               /* Starting at a block boundary */
+               mmc_log_warn(&log,
+                   "Requests must start at a block boundary"
+                   "(start,block size)=(%016llx,%08x)\n", position,
+                   slot->card.blk_size);
+               return EINVAL;
+       }
+
+       blk_size = slot->card.blk_size;
+
+       bytes_written = 0;
+
+       /* Are we trying to start reading past the end */
+       if (position >= dev->dv_size) {
+               mmc_log_warn(&log, "start reading past drive size\n");
+               return 0;
+       };
+
+       ciov = iov;
+       /* do some more validation */
+       for (counter = 0; counter < nr_req; counter++) {
+               assert(ciov != NULL);
+               if (ciov->iov_size % blk_size != 0) {
+                       /* transfer a multiple of blk_size */
+                       mmc_log_warn(&log,
+                           "Requests must start at a block boundary "
+                           "(start,block size)=(%016llx,%08x)\n", position,
+                           slot->card.blk_size);
+                       return EINVAL;
+               }
+
+               if (ciov->iov_size == 0 || ciov->iov_size < 0) {
+                       mmc_log_warn(&log,
+                           "Invalid iov size for iov %d of %d size\n",
+                           counter, nr_req, ciov->iov_size);
+                       return EINVAL;
+               }
+               ciov++;
+       }
+
+       ciov = iov;
+       for (counter = 0; counter < nr_req; counter++) {
+               /* Assume we are to transfer the amount of data given in the
+                * input/output vector but ensure we are not doing i/o past
+                * our own boundaries */
+               io_size = ciov->iov_size;
+               io_offset = position + bytes_written;
+
+               /* Check we are not reading/writing past the end */
+               if (position + bytes_written + io_size > dev->dv_size) {
+                       io_size = dev->dv_size - (position + bytes_written);
+               };
+
+               mmc_log_trace(&log,
+                   "I/O %s request(%d/%d) iov(grant,size,iosize,"
+                   "offset)=(%d,%d,%d,%d)\n",
+                   (do_write) ? "write" : "read", counter + 1, nr_req,
+                   ciov->iov_addr, ciov->iov_size, io_size, io_offset);
+               /* transfer max one block at the time */
+               for (i = 0; i < io_size / blk_size; i++) {
+                       if (do_write) {
+                               /* Read io_size bytes from i/o vector starting
+                                * at 0 and write it to out buffer at the
+                                * correct offset */
+                               r = copyfrom(endpt, ciov->iov_addr,
+                                   i * blk_size, (vir_bytes) copybuff,
+                                   blk_size);
+                               if (r != OK) {
+                                       mmc_log_warn(&log,
+                                           "I/O write error: %s iov(base,size)=(%d,%d)"
+                                           " at offset=%d\n",
+                                           strerror(_SIGN r), ciov->iov_addr,
+                                           ciov->iov_size, io_offset);
+                                       return EINVAL;
+                               }
+
+                               /* write a single block */
+                               slot->host->write(&slot->card,
+                                   (dev->dv_base / blk_size) +
+                                   (io_offset / blk_size) + i, 1, copybuff);
+                               bytes_written += blk_size;
+                       } else {
+                               /* read a single block info copybuff */
+                               slot->host->read(&slot->card,
+                                   (dev->dv_base / blk_size) +
+                                   (io_offset / blk_size) + i, 1, copybuff);
+                               /* Read io_size bytes from our data at the
+                                * correct offset and write it to the output
+                                * buffer at 0 */
+                               r = copyto(endpt, ciov->iov_addr, i * blk_size,
+                                   (vir_bytes) copybuff, blk_size);
+                               if (r != OK) {
+                                       mmc_log_warn(&log,
+                                           "I/O read error: %s iov(base,size)=(%d,%d)"
+                                           " at offset=%d\n",
+                                           strerror(_SIGN r), ciov->iov_addr,
+                                           ciov->iov_size, io_offset);
+                                       return EINVAL;
+                               }
+                               bytes_written += blk_size;
+                       }
+               }
+               ciov++;
+       }
+       return bytes_written;
+}
+
+/*===========================================================================*
+ *                             block_ioctl                                  *
+ *===========================================================================*/
+static int
+block_ioctl(dev_t minor,
+    unsigned int request, endpoint_t endpt, cp_grant_id_t grant)
+{
+       /* IOCTL handling */
+       struct sd_slot *slot;
+       mmc_log_trace(&log,
+           "enter (minor,request,endpoint,grant)=(%d,%lu,%d)\n", minor,
+           request, endpt, grant);
+
+       slot = get_slot(minor);
+       if (!slot) {
+               mmc_log_warn(&log,
+                   "Doing ioctl on non existing block device(%d)\n", minor);
+               return EINVAL;
+       }
+
+       switch (request) {
+       case DIOCOPENCT:
+               // TODO: add a check for card validity */
+               mmc_log_trace(&log, "returning open count %d\n",
+                   slot->card.open_ct);
+               /* return the current open count */
+               return sys_safecopyto(endpt, grant, 0,
+                   (vir_bytes) & slot->card.open_ct,
+                   sizeof(slot->card.open_ct));
+       case DIOCFLUSH:
+               /* No need to flush but some devices like movinands require
+                * 500 ms inactivity */
+               return OK;
+       }
+
+       return EINVAL;
+}
+
+/*===========================================================================*
+ *                    block_part                                             *
+ *===========================================================================*/
+static struct device *
+block_part(dev_t minor)
+{
+       /* 
+        * Reuse the existing MINIX major/minor partitioning scheme.
+        * - 8 drives
+        * - 5 devices per drive allowing direct access to the disk and up to 4
+        *   partitions (IBM style partitioning without extended partitions)
+        * - 4 Minix style sub partitions per partitions
+        */
+       struct device *dev;
+       struct sd_slot *slot;
+
+       dev = NULL;
+       slot = get_slot(minor);
+       if (!slot) {
+               mmc_log_warn(&log,
+                   "Device information requested for non existing partition "
+                   "minor(%d)\n", minor);
+               return NULL;
+       }
+
+       if (!slot->host->card_detect(slot)) {
+               mmc_log_warn(&log,
+                   "Device information requested from empty slot(%d)\n",
+                   minor);
+               return NULL;
+       }
+
+       if (minor < 5) {
+               /* we are talking about the first disk */
+               dev = &slot->card.part[minor];
+               mmc_log_trace(&log,
+                   "returning partition(%d) (base,size)=(0x%016llx,0x%016llx)\n",
+                   minor, dev->dv_base, dev->dv_size);
+       } else if (minor >= 128 && minor <= 128 + 16) {
+               /* sub partitions of the first disk we don't care about the
+                * rest */
+               dev = &slot->card.subpart[minor - 128];
+               mmc_log_trace(&log,
+                   "returning sub partition(%d) (base,size)=(0x%016llx,0x%016llx)\n",
+                   minor - 128, dev->dv_base, dev->dv_size);
+
+       } else {
+               mmc_log_warn(&log,
+                   "Device information requested for non existing "
+                   "partition minor(%d)\n", minor);
+       }
+       return dev;
+}
+
+/*===========================================================================*
+ *                         sef_local_startup                                 *
+ *===========================================================================*/
+static void
+sef_local_startup()
+{
+       mmc_log_info(&log, "Initializing the MMC block device\n");
+       if (apply_env()) {
+               mmc_log_warn(&log,
+                   "Failed while applying environment settings\n");
+               exit(EXIT_FAILURE);
+       }
+
+       if (host.host_init(&host)) {
+               mmc_log_warn(&log,
+                   "Failed to initialize the host controller\n");
+               exit(EXIT_FAILURE);
+       }
+       /* 
+        * Register callbacks for fresh start, live update and restart.
+        *  Use the same function for all event types
+        */
+       sef_setcb_init_fresh(block_system_event_cb);
+       sef_setcb_init_lu(block_system_event_cb);
+       sef_setcb_init_restart(block_system_event_cb);
+
+       /* Register a signal handler */
+       sef_setcb_signal_handler(block_signal_handler_cb);
+
+       /* SEF startup */
+       sef_startup();
+}
+
+/*===========================================================================*
+ *                         block_system_event_cb                             *
+ *===========================================================================*/
+static int
+block_system_event_cb(int type, sef_init_info_t * info)
+{
+       /* 
+        * Callbacks for the System event framework as registered in 
+        * sef_local_startup */
+       switch (type) {
+       case SEF_INIT_FRESH:
+               mmc_log_info(&log, "System event framework fresh start\n");
+               break;
+
+       case SEF_INIT_LU:
+               /* Restore the state. post update */
+               mmc_log_info(&log, "System event framework live update\n");
+               break;
+
+       case SEF_INIT_RESTART:
+               mmc_log_info(&log, "System event framework post restart\n");
+               break;
+       }
+       return OK;
+}
+
+/*===========================================================================*
+ *                         block_signal_handler_cb                           *
+ *===========================================================================*/
+static void
+block_signal_handler_cb(int signo)
+{
+       mmc_log_debug(&log, "System event framework signal handler sig(%d)\n",
+           signo);
+       /* Only check for termination signal, ignore anything else. */
+       if (signo != SIGTERM)
+               return;
+       // FIXME shutdown
+       exit(0);
+}
+
+#define IS_MINIX_SUB_PARTITION_MINOR(minor) (minor >= MINOR_d0p0s0 )
+
+static struct sd_slot *
+get_slot(dev_t minor)
+{
+       /* 
+        * Get an sd_slot based on the minor number.
+        *
+        * This driver only supports a single card at at time. Also as
+        * we are following the major/minor scheme of other driver we
+        * must return a slot for all minors on disk 0 these are  0-5
+        * for the disk and 4 main partitions and
+        * number 128 till 144 for sub partitions.
+        */
+       /* If this is a minor for the first disk (e.g. minor 0 till 5) */
+       if (minor / DEV_PER_DRIVE == 0) {
+               /* we are talking about the first disk and that is all we
+                * support */
+               return &host.slot[0];
+       } else if ( IS_MINIX_SUB_PARTITION_MINOR(minor) 
+           && (((minor - MINOR_d0p0s0) / SUB_PER_DRIVE) == 0)) {
+               /* a minor from the first disk */
+               return &host.slot[0];
+       } else {
+               mmc_log_trace(&log,
+                   "Device information requested for non existing partition "
+                   "minor(%d)\n", minor);
+               return NULL;
+       }
+}
+
+#if 0
+static void
+set_log_level(int level)
+{
+       if (level < 0 || level >= 4) {
+               return;
+       }
+       mmc_log_debug(&log, "Setting verbosity level to %d\n", level);
+       log.log_level = level;
+       if (host.set_log_level) {
+               host.set_log_level(level);
+       }
+}
+#endif
+
+int
+main(int argc, char **argv)
+{
+       /* early init of host mmc host controller. This code should depend on
+        * knowing the hardware that is running bellow. */
+       host_initialize_host_structure(&host);
+
+       /* Set and apply the environment */
+       env_setargs(argc, argv);
+
+       sef_local_startup();
+       blockdriver_task(&mmc_driver);
+       return EXIT_SUCCESS;
+}
diff --git a/drivers/mmc/mmchost.h b/drivers/mmc/mmchost.h
new file mode 100644 (file)
index 0000000..b4827fa
--- /dev/null
@@ -0,0 +1,149 @@
+
+#define SUBPARTITION_PER_PARTITION 4   /* 4 sub partitions per partition */
+#define PARTITONS_PER_DISK 4   /* 4 partitions per disk */
+#define MINOR_PER_DISK  1      /* one additional minor to point to */
+
+/**
+ * We can have multiple MMC host controller present on the hardware. The MINIX
+ * approach to handle this is to run a driver for each instance. Every driver
+ * will therefore be stated with an "instance" id and the rest of the code here
+ * will assume a single host controller to be present.
+ *
+ * The SD specification allows multiple cards to be attached to a single host
+ * controller using the same lines. I recommend reading SD Specifications Part 1
+ * Physical layer Simplified Specification chapter 3 about SD Memory Card system
+ * concepts if you want to get a better understanding of this.
+ *
+ * In practice an MMC host will usually have a single slot attached to it and that
+ * Slot may or may not contain a card. On sudden card removal we might want to
+ * keep track of the last inserted card and we might therefore at later stage
+ * add an additional "last_card" attribute to the card.
+ *
+ * The following diagram shows the structure that will be used to modulate the
+ * hardware written in umlwiki  syntax.
+ *
+ * [/host/
+ *   +instance:int] 1 --- 0..4 [ /slot/
+ *                                +card_detect:func ] 1 --- 0..1 [ /card/ ]
+ *                                 `
+ */
+
+#define MAX_SD_SLOTS 4
+
+struct mmc_host;
+
+//TODO Add more modes like INACTIVE STATE and such
+#define SD_MODE_UNINITIALIZED 0
+#define SD_MODE_CARD_IDENTIFICATION 1
+#define SD_MODE_DATA_TRANSFER_MODE 2
+
+
+struct sd_card_regs
+{
+       uint32_t cid[4]; /* Card Identification */
+       uint32_t rca; /* Relative card address */
+       uint32_t dsr; /* Driver stage register */
+       uint32_t csd[4]; /* Card specific data */
+       uint32_t scr[2]; /* SD configuration */
+       uint32_t ocr; /* Operation conditions */
+       uint32_t ssr[5]; /* SD Status */
+       uint32_t csr; /* Card status */
+};
+
+/* struct representing an mmc command */
+struct mmc_command
+{
+       uint32_t cmd;
+       uint32_t args;
+       uint32_t resp_type;
+
+#define  RESP_LEN_48_CHK_BUSY (3<<0)
+#define  RESP_LEN_48             (2<<0)
+#define  RESP_LEN_136            (1<<0)
+#define  NO_RESPONSE             (0<<0)
+
+       uint32_t resp[4];
+       unsigned char* data;
+       uint32_t data_len;
+};
+
+/* structure representing an SD card */
+struct sd_card
+{
+       /* pointer back to the SD slot for convenience */
+       struct sd_slot *slot;
+
+       struct sd_card_regs regs;
+
+       /* some helpers (data comming from the csd) */
+       uint32_t blk_size;
+       uint32_t blk_count;
+
+       /* drive state: deaf, initialized, dead */
+       unsigned state;
+
+       /* MINIX/block driver related things */
+       int open_ct;            /* in-use count */
+
+       /* 1 disks + 4 partitions and 16 possible sub partitions */
+       struct device part[MINOR_PER_DISK + PARTITONS_PER_DISK];
+       struct device subpart[PARTITONS_PER_DISK * SUBPARTITION_PER_PARTITION];
+};
+
+/* structure representing an SD slot */
+struct sd_slot
+{
+       /* pointer back to the host for convenience */
+       struct mmc_host *host;
+
+       unsigned state;
+       struct sd_card card;
+};
+
+/* structure for the host controller */
+struct mmc_host
+{
+       /* MMC host configuration */
+       int (*host_set_instance) (struct mmc_host * host, int instance);
+       /* MMC host configuration */
+       int (*host_init) (struct mmc_host * host);
+       /* Set log level */
+       void(*set_log_level) (int level);
+       /* Host controller reset */
+       int (*host_reset) (struct mmc_host * host);
+       /* Card detection (binary yes/no) */
+       int (*card_detect) (struct sd_slot * slot);
+       /* Perform card detection e.g. card type */
+       struct sd_card *(*card_initialize) (struct sd_slot * slot);
+       /* Release the card */
+       int (*card_release) (struct sd_card * card);
+
+       /* read count blocks into existing buf */
+       int (*read) (struct sd_card * card,
+           uint32_t blknr, uint32_t count, unsigned char *buf);
+
+       /* write count blocks */
+       int (*write) (struct sd_card * card,
+           uint32_t blknr, uint32_t count, unsigned char *buf);
+
+       /* up to 4 slots with 4 SD cards */
+       struct sd_slot slot[MAX_SD_SLOTS];
+};
+
+#if 0
+/* Command execution */
+int (*send_cmd) (struct sd_card * card, struct mmc_command *);
+
+/* struct representing an mmc command */
+struct mmc_command
+{
+       uint32_t cmd;
+       uint32_t args;
+       uint32_t resp[4];
+       unsigned char *data;
+       uint32_t data_len;
+};
+#endif
+
+/* Hack done for driver registration */
+void host_initialize_host_structure(struct mmc_host *host);
diff --git a/drivers/mmc/mmchost_mmchs.c b/drivers/mmc/mmchost_mmchs.c
new file mode 100644 (file)
index 0000000..2ee0425
--- /dev/null
@@ -0,0 +1,788 @@
+/* kernel headers */
+#include <minix/blockdriver.h>
+#include <minix/com.h>
+#include <minix/vm.h>
+#include <sys/mman.h>
+
+/* usr headers */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+#include <limits.h>
+
+/* local headers */
+#include "mmclog.h"
+#include "mmchost.h"
+
+/* header imported from netbsd */
+#include "sdmmcreg.h"
+#include "sdmmcreg.h"
+#include "sdhcreg.h"
+
+/* omap /hardware related */
+#include "omap_mmc.h"
+
+#define REG(x)(*((volatile uint32_t *)(x)))
+#define BIT(x)(0x1 << x)
+
+/* Write a uint32_t value to a memory address. */
+inline void
+write32(uint32_t address, uint32_t value)
+{
+       REG(address) = value;
+}
+
+/* Read an uint32_t from a memory address */
+inline uint32_t
+read32(uint32_t address)
+{
+
+       return REG(address);
+}
+
+/* Set a 32 bits value depending on a mask */
+inline void
+set32(uint32_t address, uint32_t mask, uint32_t value)
+{
+       uint32_t val;
+       val = read32(address);
+       /* clear the bits */
+       val &= ~(mask);
+       /* apply the value using the mask */
+       val |= (value & mask);
+       write32(address, val);
+}
+
+static uint32_t base_address;
+
+/*
+ * Initialize the MMC controller given a certain
+ * instance. this driver only handles a single
+ * mmchs controller at a given time.
+ */
+int
+mmchs_init(uint32_t instance)
+{
+       int counter;
+       uint32_t value;
+
+       counter = 0;
+       value = 0;
+
+       struct minix_mem_range mr;
+
+       mr.mr_base = MMCHS1_REG_BASE;
+       mr.mr_limit = MMCHS1_REG_BASE + 0x400;
+
+       if (sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr) != 0) {
+               panic("Unable to request permission to map memory");
+       }
+
+       /* Set the base address to use */
+       base_address =
+           (uint32_t) vm_map_phys(SELF, (void *) MMCHS1_REG_BASE, 0x400);
+       if (base_address == (uint32_t) MAP_FAILED)
+               panic("Unable to map MMC memory");
+
+       base_address = (unsigned long) base_address - 0x100;
+
+       /*  Soft reset of the controller. This section is documented in the TRM */
+
+       /* Write 1 to sysconfig[0] to trigger a reset */
+       set32(base_address + MMCHS_SD_SYSCONFIG, MMCHS_SD_SYSCONFIG_SOFTRESET,
+           MMCHS_SD_SYSCONFIG_SOFTRESET);
+
+       /* Read sysstatus to know when it's done */
+       while (!(read32(base_address + MMCHS_SD_SYSSTATUS)
+               & MMCHS_SD_SYSSTATUS_RESETDONE)) {
+               /* TODO:Add proper delay and escape route */
+
+               counter++;
+       }
+
+       /* Set SD default capabilities */
+       set32(base_address + MMCHS_SD_CAPA, MMCHS_SD_CAPA_VS_MASK,
+           MMCHS_SD_CAPA_VS18 | MMCHS_SD_CAPA_VS30);
+
+       /* TRM mentions MMCHS_SD_CUR_CAPA but does not describe how to limit
+        * the current */
+
+       uint32_t mask =
+           MMCHS_SD_SYSCONFIG_AUTOIDLE | MMCHS_SD_SYSCONFIG_ENAWAKEUP |
+           MMCHS_SD_SYSCONFIG_STANDBYMODE | MMCHS_SD_SYSCONFIG_CLOCKACTIVITY |
+           MMCHS_SD_SYSCONFIG_SIDLEMODE;
+
+       /* Automatic clock gating strategy */
+       value = MMCHS_SD_SYSCONFIG_AUTOIDLE_EN;
+       /* Enable wake-up capability */
+       value |= MMCHS_SD_SYSCONFIG_ENAWAKEUP_EN;
+       /* Smart-idle */
+       value |= MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE;
+       /* Booth the interface and functional can be switched off */
+       value |= MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_OFF;
+       /* Go into wake-up mode when possible */
+       value |= MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_INTERNAL;
+
+       /* 
+        * wake-up configuration
+        */
+       set32(base_address + MMCHS_SD_SYSCONFIG, mask, value);
+
+       /* Wake-up on sd interrupt for SDIO */
+       set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_IWE,
+           MMCHS_SD_HCTL_IWE_EN);
+
+       /* 
+        * MMC host and bus configuration
+        */
+
+       /* Configure data and command transfer (1 bit mode) */
+       set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_DW8,
+           MMCHS_SD_CON_DW8_1BIT);
+       set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_DTW,
+           MMCHS_SD_HCTL_DTW_1BIT);
+
+       /* Configure card voltage to 3.0 volt */
+       set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDVS,
+           MMCHS_SD_HCTL_SDVS_VS30);
+
+       /* Power on the host controller and wait for the
+        * MMCHS_SD_HCTL_SDBP_POWER_ON to be set */
+       set32(base_address + MMCHS_SD_HCTL, MMCHS_SD_HCTL_SDBP,
+           MMCHS_SD_HCTL_SDBP_ON);
+
+       /* TODO: Add padconf stuff here as documented in the TRM*/
+
+       while ((read32(base_address + MMCHS_SD_HCTL) & MMCHS_SD_HCTL_SDBP)
+           != MMCHS_SD_HCTL_SDBP_ON) {
+               /* TODO:Add proper delay and escape route */
+               counter++;
+       }
+
+       /* Enable internal clock and clock to the card */
+       set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_ICE,
+           MMCHS_SD_SYSCTL_ICE_EN);
+
+       // @TODO Fix external clock enable , this one is very slow
+       set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
+           (0x3ff << 6));
+       set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CEN,
+           MMCHS_SD_SYSCTL_CEN_EN);
+       counter = 0;
+
+       while ((read32(base_address + MMCHS_SD_SYSCTL) & MMCHS_SD_SYSCTL_ICS)
+           != MMCHS_SD_SYSCTL_ICS_STABLE) {
+               /* TODO:Add proper delay and escape route */
+               counter++;
+       }
+
+       /* 
+        * See spruh73e page 3576  Card Detection, Identification, and Selection
+        */
+
+       /* Enable command interrupt */
+       set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_CC_ENABLE,
+           MMCHS_SD_IE_CC_ENABLE_ENABLE);
+       /* Enable transfer complete interrupt */
+       set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_TC_ENABLE,
+           MMCHS_SD_IE_TC_ENABLE_ENABLE);
+
+       /* enable error interrupts */
+       /* NOTE: We are currently skipping the BADA interrupt it does get
+        * raised for unknown reasons */
+       set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_ERROR_MASK, 0x0fffffffu);
+
+       /* clean the error interrupts */
+       set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
+           0xffffffffu);
+
+       /* send a init signal to the host controller. This does not actually
+        * send a command to a card manner */
+       set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT,
+           MMCHS_SD_CON_INIT_INIT);
+       /* command 0 , type other commands not response etc) */
+       write32(base_address + MMCHS_SD_CMD, 0x00);
+
+       counter = 0;
+       while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_STAT_CC)
+           != MMCHS_SD_STAT_CC_RAISED) {
+               if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
+                       printf("%s, error stat  %x\n", __FUNCTION__,
+                           read32(base_address + MMCHS_SD_STAT));
+                       return 1;
+               }
+               counter++;
+       }
+
+       /* clear the cc interrupt status */
+       set32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE,
+           MMCHS_SD_IE_CC_ENABLE_ENABLE);
+
+       /* 
+        * Set Set SD_CON[1] INIT bit to 0x0 to end the initialization sequence
+        */
+       set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT,
+           MMCHS_SD_CON_INIT_NOINIT);
+
+       /* Clean the MMCHS_SD_STAT register */
+       write32(base_address + MMCHS_SD_STAT, 0xffffffffu);
+       return 0;
+}
+
+int
+mmchs_send_cmd(uint32_t command, uint32_t arg)
+{
+       int count = 0;
+
+       /* Read current interrupt status and fail it an interrupt is already
+        * asserted */
+       if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) {
+               printf("%s, interrupt already raised stat  %08x\n",
+                   __FUNCTION__, read32(base_address + MMCHS_SD_STAT));
+               write32(base_address + MMCHS_SD_STAT,
+                   MMCHS_SD_IE_CC_ENABLE_CLEAR);
+               // return 1;
+       }
+
+       /* Set arguments */
+       write32(base_address + MMCHS_SD_ARG, arg);
+       /* Set command */
+       set32(base_address + MMCHS_SD_CMD, MMCHS_SD_CMD_MASK, command);
+
+       /* Wait for completion */
+       while ((read32(base_address + MMCHS_SD_STAT) & 0xffffu) == 0x0) {
+               count++;
+       }
+
+       if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
+               printf("%s, error stat  %08x\n", __FUNCTION__,
+                   read32(base_address + MMCHS_SD_STAT));
+               set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
+                   0xffffffffu);
+               return 1;
+       }
+
+       if ((command & MMCHS_SD_CMD_RSP_TYPE) ==
+           MMCHS_SD_CMD_RSP_TYPE_48B_BUSY) {
+               /* 
+                * Command with busy response *CAN* also set the TC bit if they exit busy
+                */
+               while ((read32(base_address + MMCHS_SD_STAT)
+                       & MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) {
+                       count++;
+               }
+               write32(base_address + MMCHS_SD_STAT,
+                   MMCHS_SD_IE_TC_ENABLE_CLEAR);
+       }
+
+       /* clear the cc status */
+       write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR);
+       return 0;
+}
+
+int
+mmc_send_cmd(struct mmc_command *c)
+{
+
+       /* convert the command to a hsmmc command */
+       int ret;
+       uint32_t cmd, arg;
+       cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd);
+       arg = c->args;
+
+       switch (c->resp_type) {
+       case RESP_LEN_48_CHK_BUSY:
+               cmd |= MMCHS_SD_CMD_RSP_TYPE_48B_BUSY;
+               break;
+       case RESP_LEN_48:
+               cmd |= MMCHS_SD_CMD_RSP_TYPE_48B;
+               break;
+       case RESP_LEN_136:
+               cmd |= MMCHS_SD_CMD_RSP_TYPE_136B;
+               break;
+       case NO_RESPONSE:
+               cmd |= MMCHS_SD_CMD_RSP_TYPE_NO_RESP;
+               break;
+       default:
+               return 1;
+       }
+
+       ret = mmchs_send_cmd(cmd, arg);
+
+       /* copy response into cmd->resp */
+       switch (c->resp_type) {
+       case RESP_LEN_48_CHK_BUSY:
+       case RESP_LEN_48:
+               c->resp[0] = read32(base_address + MMCHS_SD_RSP10);
+               break;
+       case RESP_LEN_136:
+               c->resp[0] = read32(base_address + MMCHS_SD_RSP10);
+               c->resp[1] = read32(base_address + MMCHS_SD_RSP32);
+               c->resp[2] = read32(base_address + MMCHS_SD_RSP54);
+               c->resp[3] = read32(base_address + MMCHS_SD_RSP76);
+               break;
+       case NO_RESPONSE:
+               break;
+       default:
+               return 1;
+       }
+
+       return ret;
+}
+
+static struct mmc_command command;
+
+int
+card_goto_idle_state()
+{
+       command.cmd = MMC_GO_IDLE_STATE;
+       command.resp_type = NO_RESPONSE;
+       command.args = 0x00;
+       if (mmc_send_cmd(&command)) {
+               // Failure
+               return 1;
+       }
+       return 0;
+}
+
+int
+card_identification()
+{
+       command.cmd = MMC_SEND_EXT_CSD;
+       command.resp_type = RESP_LEN_48;
+       command.args = MMCHS_SD_ARG_CMD8_VHS | MMCHS_SD_ARG_CMD8_CHECK_PATTERN;
+
+       if (mmc_send_cmd(&command)) {
+               // We currently only support 2.0,
+               return 1;
+       }
+
+       if (!(command.resp[0]
+               == (MMCHS_SD_ARG_CMD8_VHS | MMCHS_SD_ARG_CMD8_CHECK_PATTERN))) {
+               printf("%s, check pattern check failed  %08x\n", __FUNCTION__,
+                   command.resp[0]);
+               return 1;
+       }
+       return 0;
+}
+
+int
+card_query_voltage_and_type(struct sd_card_regs *card)
+{
+
+       command.cmd = MMC_APP_CMD;
+       command.resp_type = RESP_LEN_48;
+       command.args = MMC_ARG_RCA(0x0);        /* RCA=0000 */
+       if (mmc_send_cmd(&command)) {
+               return 1;
+       }
+
+       command.cmd = SD_APP_OP_COND;
+       command.resp_type = RESP_LEN_48;
+
+       /* 0x1 << 30 == send HCS (Host capacity support) and get OCR register */
+       command.args =
+           MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V | MMC_OCR_3_1V_3_2V |
+           MMC_OCR_3_0V_3_1V | MMC_OCR_2_9V_3_0V | MMC_OCR_2_8V_2_9V |
+           MMC_OCR_2_7V_2_8V;
+       command.args |= MMC_OCR_HCS;    /* RCA=0000 */
+
+       if (mmc_send_cmd(&command)) {
+               return 1;
+       }
+       /* @todo wait for max 1 ms */
+       while (!(command.resp[0] & MMC_OCR_MEM_READY)) {
+               command.cmd = MMC_APP_CMD;
+               command.resp_type = RESP_LEN_48;
+               command.args = MMC_ARG_RCA(0x0);        /* RCA=0000 */
+               if (mmc_send_cmd(&command)) {
+                       return 1;
+               }
+
+               /* Send ADMD41 */
+               /* 0x1 << 30 == send HCS (Host capacity support) and get OCR
+                * register */
+               command.cmd = SD_APP_OP_COND;
+               command.resp_type = RESP_LEN_48;
+               /* 0x1 << 30 == send HCS (Host capacity support) */
+               command.args = MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V
+                   | MMC_OCR_3_1V_3_2V | MMC_OCR_3_0V_3_1V | MMC_OCR_2_9V_3_0V
+                   | MMC_OCR_2_8V_2_9V | MMC_OCR_2_7V_2_8V;
+               command.args |= MMC_OCR_HCS;    /* RCA=0000 */
+
+               if (mmc_send_cmd(&command)) {
+                       return 1;
+               }
+
+               /* if bit 31 is set the response is valid */
+               if ((command.resp[0] & MMC_OCR_MEM_READY)) {
+                       break;
+               }
+
+       }
+       card->ocr = command.resp[3];
+       return 0;
+}
+
+int
+card_identify(struct sd_card_regs *card)
+{
+
+       /* Send cmd 2 (all_send_cid) and expect 136 bits response */
+       command.cmd = MMC_ALL_SEND_CID;
+       command.resp_type = RESP_LEN_136;
+       command.args = MMC_ARG_RCA(0x0);        /* RCA=0000 */
+
+       if (mmc_send_cmd(&command)) {
+               return 1;
+       }
+
+       card->cid[0] = command.resp[0];
+       card->cid[1] = command.resp[1];
+       card->cid[2] = command.resp[2];
+       card->cid[3] = command.resp[3];
+
+       command.cmd = MMC_SET_RELATIVE_ADDR;
+       command.resp_type = RESP_LEN_48;
+       command.args = 0x0;     /* RCA=0000 */
+
+       /* R6 response */
+       if (mmc_send_cmd(&command)) {
+               return 1;
+       }
+
+       card->rca = SD_R6_RCA(command.resp);
+       /* MMHCS only supports a single card so sending MMCHS_SD_CMD_CMD2 is
+        * useless Still we should make it possible in the API to support
+        * multiple cards */
+
+       return 0;
+}
+
+int
+card_csd(struct sd_card_regs *card)
+{
+       /* send_csd -> r2 response */
+       command.cmd = MMC_SEND_CSD;
+       command.resp_type = RESP_LEN_136;
+       command.args = MMC_ARG_RCA(card->rca);  /* card rca */
+
+       if (mmc_send_cmd(&command)) {
+               return 1;
+       }
+
+       card->csd[0] = command.resp[0];
+       card->csd[1] = command.resp[1];
+       card->csd[2] = command.resp[2];
+       card->csd[3] = command.resp[3];
+
+       if (SD_CSD_CSDVER(card->csd) != SD_CSD_CSDVER_2_0) {
+               printf("Version 2.0 of CSD register expected\n");
+               return 1;
+       }
+
+       /* sanity check */
+       // printf("size = %llu bytes\n", (long long
+       // unsigned)SD_CSD_V2_CAPACITY( card->csd) * 512);
+       return 0;
+}
+
+int
+select_card(struct sd_card_regs *card)
+{
+
+       command.cmd = MMC_SELECT_CARD;
+       command.resp_type = RESP_LEN_48_CHK_BUSY;
+       command.args = MMC_ARG_RCA(card->rca);  /* card rca */
+
+       if (mmc_send_cmd(&command)) {
+               return 1;
+       }
+       return 0;
+}
+
+int
+read_single_block(struct sd_card_regs *card,
+    uint32_t blknr, unsigned char *buf)
+{
+       uint32_t count;
+       uint32_t value;
+
+       count = 0;
+
+       set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BRR_ENABLE,
+           MMCHS_SD_IE_BRR_ENABLE_ENABLE);
+
+       set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);
+
+       /* read single block */
+       if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_READ_BLOCK_SINGLE)
+               | MMCHS_SD_CMD_DP_DATA  /* Command with data transfer */
+               | MMCHS_SD_CMD_RSP_TYPE_48B     /* type (R1) */
+               | MMCHS_SD_CMD_MSBS_SINGLE      /* single block */
+               | MMCHS_SD_CMD_DDIR_READ        /* read data from card */
+               , blknr)) {
+               return 1;
+       }
+
+       while ((read32(base_address + MMCHS_SD_STAT)
+               & MMCHS_SD_IE_BRR_ENABLE_ENABLE) == 0) {
+               count++;
+       }
+
+       if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN)) {
+               return 1;       /* We are not allowed to read data from the
+                                * data buffer */
+       }
+
+       for (count = 0; count < 512; count += 4) {
+               value = read32(base_address + MMCHS_SD_DATA);
+               buf[count] = *((char *) &value);
+               buf[count + 1] = *((char *) &value + 1);
+               buf[count + 2] = *((char *) &value + 2);
+               buf[count + 3] = *((char *) &value + 3);
+       }
+
+       /* Wait for TC */
+       while ((read32(base_address +
+                   MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
+           == 0) {
+               count++;
+       }
+       write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
+
+       /* clear and disable the bbr interrupt */
+       write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BRR_ENABLE_CLEAR);
+       set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BRR_ENABLE,
+           MMCHS_SD_IE_BRR_ENABLE_DISABLE);
+       return 0;
+}
+
+int
+write_single_block(struct sd_card_regs *card,
+    uint32_t blknr, unsigned char *buf)
+{
+       uint32_t count;
+       uint32_t value;
+
+       count = 0;
+
+       set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
+           MMCHS_SD_IE_BWR_ENABLE_ENABLE);
+       // set32(base_address + MMCHS_SD_IE, 0xfff , 0xfff);
+       set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);
+
+       /* Set timeout */
+       set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO,
+           MMCHS_SD_SYSCTL_DTO_2POW27);
+
+       /* write single block */
+       if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE)
+               | MMCHS_SD_CMD_DP_DATA  /* Command with data transfer */
+               | MMCHS_SD_CMD_RSP_TYPE_48B     /* type (R1b) */
+               | MMCHS_SD_CMD_MSBS_SINGLE      /* single block */
+               | MMCHS_SD_CMD_DDIR_WRITE       /* write to the card */
+               , blknr)) {
+               return 1;
+       }
+
+       /* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */
+       while ((read32(base_address +
+                   MMCHS_SD_STAT) & MMCHS_SD_IE_BWR_ENABLE) == 0) {
+               count++;
+       }
+
+       if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) {
+               return 1;       /* not ready to write data */
+       }
+       for (count = 0; count < 512; count += 4) {
+               *((char *) &value) = buf[count];
+               *((char *) &value + 1) = buf[count + 1];
+               *((char *) &value + 2) = buf[count + 2];
+               *((char *) &value + 3) = buf[count + 3];
+               write32(base_address + MMCHS_SD_DATA, value);
+       }
+
+       /* Wait for TC */
+       while ((read32(base_address +
+                   MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
+           == 0) {
+               count++;
+       }
+       write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
+       write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_CC_ENABLE_CLEAR);     /* finished. 
+                                                                                */
+       /* clear the bwr interrupt FIXME is this right when writing? */
+       write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_BWR_ENABLE_CLEAR);
+       set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
+           MMCHS_SD_IE_BWR_ENABLE_DISABLE);
+       return 0;
+}
+
+/*
+ * Define a structure to be used for logging
+ */
+static struct mmclog log = {
+       .name = "mmc_host_mmchs",
+       .log_level = LEVEL_INFO,
+       .log_func = default_log
+};
+
+int
+mmchs_host_init(struct mmc_host *host)
+{
+       mmchs_init(1);
+       return 0;
+}
+
+void
+mmchs_set_log_level(int level)
+{
+       if (level >= 0 && level <= 4) {
+               log.log_level = level;
+       }
+}
+
+int
+mmchs_host_set_instance(struct mmc_host *host, int instance)
+{
+       mmc_log_info(&log, "Using instance number %d\n", instance);
+       if (instance != 0) {
+               return EIO;
+       }
+       return OK;
+}
+
+int
+mmchs_host_reset(struct mmc_host *host)
+{
+       mmchs_init(1);
+       return 0;
+}
+
+int
+mmchs_card_detect(struct sd_slot *slot)
+{
+       /* @TODO implement proper card detect */
+       return 1;
+}
+
+struct sd_card *
+mmchs_card_initialize(struct sd_slot *slot)
+{
+       mmchs_init(1);
+
+       struct sd_card *card;
+       card = &slot->card;
+       memset(card, 0, sizeof(struct sd_card));
+       card->slot = slot;
+
+       if (card_identification()) {
+               printf("Failed to do card_identification\n");
+               return NULL;
+       }
+
+       if (card_query_voltage_and_type(&slot->card.regs)) {
+               printf("Failed to do card_query_voltage_and_type\n");
+               return NULL;
+       }
+       if (card_identify(&slot->card.regs)) {
+               printf("Failed to identify card\n");
+               return NULL;
+       }
+       /* We have now initialized the hardware identified the card */
+       if (card_csd(&slot->card.regs)) {
+               printf("failed to read csd (card specific data)\n");
+               return NULL;
+       }
+
+       if (select_card(&slot->card.regs)) {
+               printf("Failed to select card\n");
+               return NULL;
+       }
+
+       if (SD_CSD_READ_BL_LEN(slot->card.regs.csd) != 0x09) {
+               /* for CSD version 2.0 the value is fixed to 0x09 and means a
+                * block size of 512 */
+               printf("Block size expect to be 512\n");
+               return NULL;
+       }
+
+       slot->card.blk_size = 512;      /* HARDCODED value */
+       slot->card.blk_count = SD_CSD_V2_CAPACITY(slot->card.regs.csd);
+       slot->card.state = SD_MODE_DATA_TRANSFER_MODE;
+
+       memset(slot->card.part, 0, sizeof(slot->card.part));
+       memset(slot->card.subpart, 0, sizeof(slot->card.subpart));
+       slot->card.part[0].dv_base = 0;
+       slot->card.part[0].dv_size =
+           (unsigned long long) SD_CSD_V2_CAPACITY(slot->card.regs.csd) * 512;
+       return &slot->card;
+}
+
+/* read count blocks into existing buf */
+static int
+mmchs_host_read(struct sd_card *card,
+    uint32_t blknr, uint32_t count, unsigned char *buf)
+{
+       uint32_t i;
+       i = count;
+       for (i = 0; i < count; i++) {
+               read_single_block(&card->regs, blknr + i,
+                   buf + (i * card->blk_size));
+       }
+       return OK;
+}
+
+/* write count blocks */
+static int
+mmchs_host_write(struct sd_card *card,
+    uint32_t blknr, uint32_t count, unsigned char *buf)
+{
+       uint32_t i;
+
+       i = count;
+       for (i = 0; i < count; i++) {
+               write_single_block(&card->regs, blknr + i,
+                   buf + (i * card->blk_size));
+       }
+
+       return OK;
+}
+
+int
+mmchs_card_release(struct sd_card *card)
+{
+       assert(card->open_ct == 1);
+       card->open_ct--;
+       card->state = SD_MODE_UNINITIALIZED;
+       /* TODO:Set card state */
+       return OK;
+}
+
+void
+host_initialize_host_structure(struct mmc_host *host)
+{
+       /* Initialize the basic data structures host slots and cards */
+       int i;
+
+       host->host_set_instance = mmchs_host_set_instance;
+       host->host_init = mmchs_host_init;
+       host->set_log_level = mmchs_set_log_level;
+       host->host_reset = mmchs_host_reset;
+       host->card_detect = mmchs_card_detect;
+       host->card_initialize = mmchs_card_initialize;
+       host->card_release = mmchs_card_release;
+       host->read = mmchs_host_read;
+       host->write = mmchs_host_write;
+
+       /* initialize data structures */
+       for (i = 0; i < sizeof(host->slot) / sizeof(host->slot[0]); i++) {
+               // @TODO set initial card and slot state
+               host->slot[i].host = host;
+               host->slot[i].card.slot = &host->slot[i];
+       }
+}
diff --git a/drivers/mmc/mmclog.h b/drivers/mmc/mmclog.h
new file mode 100644 (file)
index 0000000..872823a
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef __MMCLOG_H__
+#define __MMCLOG_H__
+/*
+ * Simple logging functions for the MMC layer
+ */
+
+/*
+ * LEVEL_NONE  do not log anything.
+ * LEVEL_WARN  Information that needs to be known.
+ * LEVEL_INFO  Basic information like startup messages and occasional events.
+ * LEVEL_DEBUG debug statements about things happening that are less expected.
+ * LEVEL_TRACE Way to much information for anybody.
+ */
+
+#define LEVEL_NONE 0
+#define LEVEL_WARN 1
+#define LEVEL_INFO 2
+#define LEVEL_DEBUG 3
+#define LEVEL_TRACE 4
+
+static const char *level_string[5] = {
+       "none",
+       "warn",
+       "info",
+       "debug",
+       "trace"
+};
+
+/*
+ * struct to be initialized by the user of the logging system.
+ *
+ * name: The name attribute is used in logging statements do differentiate
+ * drivers
+ *
+ * log_level The level attribute describes the requested logging level. a level
+ * of 1 will only print warnings while a level of 4 will print all the trace
+ * information.
+ *
+ * log_func The logging function to use to log, mmclog.h provides default_log
+ * to display information on the kernel output buffer. As a bonus if the
+ * requested log level is debug or trace the method , file and line number will
+ * be printed to the steam.
+ */
+struct mmclog { const char *name; int log_level;
+
+       /* the logging function itself */
+       void (*log_func) (struct mmclog * driver,
+           int level,
+           const char *file,
+           const char *function, int line, const char *fmt, ...);
+
+};
+
+#define __mmc_log(driver,log_level, fmt, args...) \
+               ((driver)->log_func(driver,log_level, \
+                               __FILE__, __FUNCTION__, __LINE__,\
+                               fmt, ## args))
+
+/* Log a warning */
+#define mmc_log_warn(driver, fmt, args...) \
+               __mmc_log(driver, LEVEL_WARN, fmt, ## args)
+
+/* Log an information message  */
+#define mmc_log_info(driver, fmt, args...) \
+               __mmc_log(driver, LEVEL_INFO, fmt, ## args)
+
+/* log debugging output  */
+#define mmc_log_debug(driver, fmt, args...) \
+               __mmc_log(driver, LEVEL_DEBUG, fmt, ## args)
+
+/* log trace output  */
+#define mmc_log_trace(driver, fmt, args...) \
+               __mmc_log(driver, LEVEL_TRACE, fmt, ## args)
+
+#endif /* __MMCLOG_H__ */
+
+static void
+default_log(struct mmclog *driver,
+    int level,
+    const char *file, const char *function, int line, const char *fmt, ...)
+{
+       va_list args;
+
+       if (level > driver->log_level) {
+               return;
+       }
+       /* If the wanted level is debug also display line/method information */
+       if (driver->log_level >= LEVEL_DEBUG) {
+               fprintf(stderr, "%s(%s):%s+%d(%s):", driver->name,
+                   level_string[level], file, line, function);
+       } else {
+               fprintf(stderr, "%s(%s)", driver->name, level_string[level]);
+       }
+
+       va_start(args, fmt);
+       vfprintf(stderr, fmt, args);
+       va_end(args);
+}
+
+#ifdef hacks
+static void
+hexdump(unsigned char *d, unsigned int size)
+{
+       int s;
+       for (s = 0; s < size; s += 4) {
+               fprintf(stdout, "0x%04x 0x%02X%02X%02X%02X %c%c%c%c\n", s,
+                   (unsigned int) d[s], (unsigned int) d[s + 1],
+                   (unsigned int) d[s + 2], (unsigned int) d[s + 3], d[s],
+                   d[s + 1], d[s + 2], d[s + 3]);
+       }
+}
+#endif
diff --git a/drivers/mmc/omap_mmc.h b/drivers/mmc/omap_mmc.h
new file mode 100644 (file)
index 0000000..46011eb
--- /dev/null
@@ -0,0 +1,181 @@
+///* TODO: Rename to MMCH_0_REG_BASE and add the base address for the other items */
+//#define MMCHS1_REG_BASE 0x48060000
+
+//#ifdef AM_DM37x_Multimedia_Device
+#define MMCHS1_REG_BASE 0x4809C000
+//#define MMCHS2_REG_BASE 0x480B4000
+//#define MMCHS3_REG_BASE 0x480AD000
+//#endif
+
+#define MMCHS_SD_SYSCONFIG 0x110 /* SD system configuration */
+#define MMCHS_SD_SYSSTATUS 0x114 /* SD system status */
+#define MMCHS_SD_CON       0x12c /* Configuration (functional mode,card initialization etc) */
+#define MMCHS_SD_BLK       0x204 /* Transfer length configuration */
+#define MMCHS_SD_ARG       0x208 /* Command argument bit 38-8 of command format*/
+#define MMCHS_SD_CMD       0x20c /* Command and transfer mode */
+#define MMCHS_SD_RSP10     0x210 /* Command response 0 and 1 */
+#define MMCHS_SD_RSP32     0x214 /* Command response 2 and 3  */
+#define MMCHS_SD_RSP54     0x218 /* Command response 4 and 5  */
+#define MMCHS_SD_RSP76     0x21c /* Command response 6 and 7  */
+#define MMCHS_SD_DATA      0x220 /* Data register */
+#define MMCHS_SD_PSTATE    0x224 /* Present state */
+#define MMCHS_SD_HCTL      0x228 /* Host control(power ,wake-up and transfer) */
+#define MMCHS_SD_SYSCTL    0x22c /* SD System control (reset,clocks and timeout) */
+#define MMCHS_SD_STAT      0x230 /* SD Interrupt status */
+#define MMCHS_SD_IE        0x234 /* SD Interrupt Enable register */
+#define MMCHS_SD_CAPA      0x240 /* Capabilities of the host controller */
+#define MMCHS_SD_CUR_CAPA  0x248 /* Current capabilities of the host controller */
+
+#define MMCHS_SD_SYSCONFIG_AUTOIDLE                    (0x1 << 0)  /* Internal clock gating strategy */
+#define MMCHS_SD_SYSCONFIG_AUTOIDLE_DIS                (0x0 << 0)  /* Clocks are free running */
+#define MMCHS_SD_SYSCONFIG_AUTOIDLE_EN                 (0x1 << 0)  /* Automatic clock gating strategy */
+#define MMCHS_SD_SYSCONFIG_SOFTRESET                   (0x1 << 1)  /* Software reset bit writing  */
+#define MMCHS_SD_SYSCONFIG_ENAWAKEUP                   (0x1 << 2)  /* Wake-up feature control */
+#define MMCHS_SD_SYSCONFIG_ENAWAKEUP_DIS               (0x0 << 2)  /* Disable wake-up capability */
+#define MMCHS_SD_SYSCONFIG_ENAWAKEUP_EN                (0x1 << 2)  /* Enable wake-up capability */
+#define MMCHS_SD_SYSCONFIG_SIDLEMODE                   (0x3 << 3)  /* Power management */
+#define MMCHS_SD_SYSCONFIG_SIDLEMODE_UNCONDITIONAL     (0x0 << 3)  /* Go into idle mode unconditionally upon request */
+#define MMCHS_SD_SYSCONFIG_SIDLEMODE_IGNORE            (0x1 << 3)  /* Ignore ILDE requests */
+#define MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE              (0x2 << 3)  /* Acknowledge IDLE request switch to wake-up mode */
+#define MMCHS_SD_SYSCONFIG_SIDLEMODE_SMART_IDLE        (0x3 << 3)  /* Smart-idle */
+#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY               (0x3 << 8)  /* Clock activity during wake-up */
+#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_OFF           (0x0 << 8)  /* Interface and functional clock can be switched off */
+#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_IF            (0x1 << 8)  /* Only Interface clock (functional can be switched off*/
+#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_FUNC          (0x2 << 8)  /* Only Functional clock (interface clock can be switched off) */
+#define MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_BOOTH         (0x3 << 8)  /* Booth the interface and functional clock are maintained */
+#define MMCHS_SD_SYSCONFIG_STANDBYMODE                 (0x3 << 12) /* Configuration for standby */
+#define MMCHS_SD_SYSCONFIG_STANDBYMODE_FORCE_STANDBY   (0x0 << 12) /* Force standby mode upon idle request*/
+#define MMCHS_SD_SYSCONFIG_STANDBYMODE_NO_STANDBY      (0x1 << 12) /* Never go into standby mode */
+#define MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_INTERNAL (0x2 << 12) /* Go into wake-up mode based on internal knowledge */
+#define MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_SMART    (0x3 << 12) /* Go info wake-up mode when possible */
+
+#define MMCHS_SD_SYSSTATUS_RESETDONE 0x01
+
+#define MMCHS_SD_CON_DW8          (0x1 << 5) /* 8-bit mode MMC select , For SD clear this bit */
+#define MMCHS_SD_CON_DW8_1BIT     (0x0 << 5) /* 1 or 4 bits data width configuration(also set SD_HCTL) */
+#define MMCHS_SD_CON_DW8_8BITS    (0x1 << 5) /* 8 bits data width configuration */
+#define MMCHS_SD_CON_INIT         (0x1 << 1) /* Send initialization stream (all cards) */
+#define MMCHS_SD_CON_INIT_NOINIT  (0x0 << 1) /* Do nothing */
+#define MMCHS_SD_CON_INIT_INIT    (0x1 << 1) /* Send initialization stream */
+
+#define MMCHS_SD_BLK_NBLK             (0xffffu << 16) /* Block count for the current transfer */
+#define MMCHS_SD_BLK_BLEN             (0xfff << 0)     /* Transfer block size */
+#define MMCHS_SD_BLK_BLEN_NOTRANSFER  (0x0 << 0)       /* No transfer */
+
+#define MMCHS_SD_CMD_INDX                 (0x3f << 24) /* Command index */
+#define MMCHS_SD_CMD_INDX_CMD(x)          (x << 24)    /* MMC command index binary encoded values from 0 to 63 */
+
+#define MMCHS_SD_ARG_MASK                 (0xffffffffu)      /* Mask everything */
+#define MMCHS_SD_ARG_CMD8_VHS             (0x1 << (16 - 8))  /* Voltage between 2.7 and 3.6 v*/
+#define MMCHS_SD_ARG_CMD8_CHECK_PATTERN   (0xaa <<(8 - 8))   /* 10101010b pattern */
+
+#define MMCHS_SD_CMD_TYPE                 (0x3 << 22) /* Command type. */
+#define MMCHS_SD_CMD_TYPE_OTHER           (0x0 << 22) /* Other type of commands (like go idle) */
+#define MMCHS_SD_CMD_TYPE_BUS_SUSPEND     (0x1 << 22) /* Upon CMD52 "Bus Suspend" operation */
+#define MMCHS_SD_CMD_TYPE_FUNCTION_SELECT (0x2 << 22) /* Upon CMD52 "Function Select" operation */
+#define MMCHS_SD_CMD_TYPE_IOABORT         (0x3 << 22) /* Upon CMD12 and CMD21 "I/O Abort */
+#define MMCHS_SD_CMD_DP                   (0x1 << 21) /* Data present select */
+#define MMCHS_SD_CMD_DP_DATA              (0x1 << 21) /* Additional data is present on the data lines */
+#define MMCHS_SD_CMD_DP_NODATA            (0x0 << 21) /* No additional data is present on the data lines */
+#define MMCHS_SD_CMD_CICE                 (0x1 << 20) /* Command index response check enable */
+#define MMCHS_SD_CMD_CICE_ENABLE          (0x1 << 20) /* Enable index check response  */
+#define MMCHS_SD_CMD_CICE_DISABLE         (0x0 << 20) /* Disable index check response */
+#define MMCHS_SD_CMD_CCCE                 (0x1 << 19) /* Command CRC7 Check enable on responses*/
+#define MMCHS_SD_CMD_CCCE_ENABLE          (0x1 << 19) /* Enable CRC7 Check on response */
+#define MMCHS_SD_CMD_CCCE_DISABLE         (0x0 << 19) /* Disable CRC7 Check on response */
+#define MMCHS_SD_CMD_RSP_TYPE             (0x3 << 16) /* Response type */
+#define MMCHS_SD_CMD_RSP_TYPE_NO_RESP     (0x0 << 16) /* No response */
+#define MMCHS_SD_CMD_RSP_TYPE_136B        (0x1 << 16) /* Response length 136 bits */
+#define MMCHS_SD_CMD_RSP_TYPE_48B         (0x2 << 16) /* Response length 48 bits */
+#define MMCHS_SD_CMD_RSP_TYPE_48B_BUSY    (0x3 << 16) /* Response length 48 bits with busy after response */
+#define MMCHS_SD_CMD_MSBS                 (0x1 << 5)  /* Multi/Single block select */
+#define MMCHS_SD_CMD_MSBS_SINGLE          (0x0 << 5)  /* Single block mode */
+#define MMCHS_SD_CMD_MSBS_MULTI           (0x0 << 5)  /* Multi block mode */
+#define MMCHS_SD_CMD_DDIR                 (0x1 << 4)  /* Data transfer direction */
+#define MMCHS_SD_CMD_DDIR_READ            (0x1 << 4)  /* Data read (card to host) */
+#define MMCHS_SD_CMD_DDIR_WRITE           (0x0 << 4)  /* Data write (host to card)  */
+#define MMCHS_SD_CMD_ACEN                 (0x1 << 2)  /* Auto CMD12 Enable */
+#define MMCHS_SD_CMD_ACEN_DIS             (0x0 << 2)  /* Auto CMD12 Disable */
+#define MMCHS_SD_CMD_ACEN_EN              (0x1 << 2)  /* Auto CMD12 Enable */
+#define MMCHS_SD_CMD_BCE                  (0x1 << 1)  /* Block Count Enable(for multi block transfer) */
+#define MMCHS_SD_CMD_BCE_DIS              (0x0 << 1)  /* Disabled block count for infinite transfer*/
+#define MMCHS_SD_CMD_BCE_EN               (0x1 << 1)  /* Enabled for multi block transfer with know amount of blocks */
+#define MMCHS_SD_CMD_DE                   (0x1 << 0)  /* DMA enable */
+#define MMCHS_SD_CMD_DE_DIS               (0x0 << 0)  /* Disable DMA */
+#define MMCHS_SD_CMD_DE_EN                (0x1 << 0)  /* Enable DMA  */
+#define MMCHS_SD_CMD_MASK                                 ~(0x1 << 30  | 0x1 << 31 | 0x1 << 18 | 0x1 <<3) /* bits 30 , 31 and 18 are reserved */
+
+#define MMCHS_SD_PSTATE_CI           (0x1 << 16) /* Card Inserted */
+#define MMCHS_SD_PSTATE_CI_INSERTED  (0x1 << 16) /* Card Inserted  is inserted*/
+#define MMCHS_SD_PSTATE_BRE          (0x0 << 11) /* Buffer read enable */
+#define MMCHS_SD_PSTATE_BRE_DIS      (0x0 << 11) /* Read BLEN bytes disabled*/
+#define MMCHS_SD_PSTATE_BRE_EN       (0x1 << 11) /* Read BLEN bytes enabled*/
+#define MMCHS_SD_PSTATE_BWE          (0x0 << 10) /* Buffer Write enable */
+#define MMCHS_SD_PSTATE_BWE_DIS      (0x0 << 10) /* There is no room left in the buffer to write BLEN bytes of data */
+#define MMCHS_SD_PSTATE_BWE_EN       (0x1 << 10) /* There is enough space in the buffer to write BLEN bytes of data*/
+
+#define MMCHS_SD_HCTL_DTW            (0x1 << 1) /*Data transfer width.(must be set after a successful ACMD6) */
+#define MMCHS_SD_HCTL_DTW_1BIT       (0x0 << 1) /*1 bit transfer with */
+#define MMCHS_SD_HCTL_DTW_4BIT       (0x1 << 1) /*4 bit transfer with */
+#define MMCHS_SD_HCTL_SDBP           (0x1 << 8) /*SD bus power */
+#define MMCHS_SD_HCTL_SDBP_OFF       (0x0 << 8) /*SD Power off (start card detect?) */
+#define MMCHS_SD_HCTL_SDBP_ON        (0x1 << 8) /*SD Power on (start card detect?) */
+#define MMCHS_SD_HCTL_SDVS           (0x7 << 9) /*SD bus voltage select */
+#define MMCHS_SD_HCTL_SDVS_VS18      (0x5 << 9) /*1.8 V */
+#define MMCHS_SD_HCTL_SDVS_VS30      (0x6 << 9) /*3.0 V */
+#define MMCHS_SD_HCTL_SDVS_VS33      (0x7 << 9) /*3.3 V */
+#define MMCHS_SD_HCTL_IWE            (0x1 << 24)/* wake-up event on SD interrupt */
+#define MMCHS_SD_HCTL_IWE_DIS        (0x0 << 24)/* Disable wake-up on SD interrupt */
+#define MMCHS_SD_HCTL_IWE_EN         (0x1 << 24)/* Enable wake-up on SD interrupt */
+
+#define MMCHS_SD_SYSCTL_CLKD (0x3ff << 6)  /* 10 bits clock frequency select */
+#define MMCHS_SD_SYSCTL_SRD  (0x1   << 26)  /* Soft reset for mmc_dat line */
+#define MMCHS_SD_SYSCTL_SRC  (0x1   << 25)  /* Soft reset for mmc_cmd line */
+#define MMCHS_SD_SYSCTL_SRA  (0x1   << 24)  /* Soft reset all (host controller) */
+
+#define MMCHS_SD_SYSCTL_ICE     (0x1 << 0) /* Internal clock enable register  */
+#define MMCHS_SD_SYSCTL_ICE_DIS (0x0 << 0) /* Disable internal clock */
+#define MMCHS_SD_SYSCTL_ICE_EN  (0x1 << 0) /* Enable internal clock */
+#define MMCHS_SD_SYSCTL_ICS          (0x1 << 1) /* Internal clock stable register  */
+#define MMCHS_SD_SYSCTL_ICS_UNSTABLE (0x0 << 1) /* Internal clock is unstable */
+#define MMCHS_SD_SYSCTL_ICS_STABLE   (0x1 << 1) /* Internal clock is stable   */
+#define MMCHS_SD_SYSCTL_CEN          (0x1 << 2) /* Card lock enable provide clock to the card */
+#define MMCHS_SD_SYSCTL_CEN_DIS      (0x0 << 2) /* Internal clock is unstable */
+#define MMCHS_SD_SYSCTL_CEN_EN       (0x1 << 2) /* Internal clock is stable   */
+
+#define MMCHS_SD_SYSCTL_DTO          (0xf << 16) /* Data timeout counter  */
+#define MMCHS_SD_SYSCTL_DTO_2POW13   (0x0 << 16) /* TCF x 2^13  */
+#define MMCHS_SD_SYSCTL_DTO_2POW14   (0x1 << 16) /* TCF x 2^14  */
+#define MMCHS_SD_SYSCTL_DTO_2POW27   (0x3 << 16) /* TCF x 2^27  */
+
+#define MMCHS_SD_STAT_ERRI            (0x01 << 15) /* Error interrupt */
+#define MMCHS_SD_STAT_ERROR_MASK     (0xff << 15 | 0x3 << 24 | 0x03 << 28)
+#define MMCHS_SD_STAT_CC              (0x1 << 0) /* Command complete status */
+#define MMCHS_SD_STAT_CC_UNRAISED     (0x0 << 0) /* Command not completed */
+#define MMCHS_SD_STAT_CC_RAISED       (0x1 << 0) /* Command completed */
+
+#define MMCHS_SD_IE_ERROR_MASK     (0xff << 15 | 0x3 << 24 | 0x03 << 28)
+
+#define MMCHS_SD_IE_CC_ENABLE        (0x1 << 0) /* Command complete interrupt enable */
+#define MMCHS_SD_IE_CC_ENABLE_ENABLE (0x1 << 0) /* Command complete Interrupts are enabled */
+#define MMCHS_SD_IE_CC_ENABLE_CLEAR  (0x1 << 0) /* Clearing is done by writing a 0x1 */
+
+#define MMCHS_SD_IE_TC_ENABLE        (0x1 << 1) /* Transfer complete interrupt enable */
+#define MMCHS_SD_IE_TC_ENABLE_ENABLE (0x1 << 1) /* Transfer complete Interrupts are enabled */
+#define MMCHS_SD_IE_TC_ENABLE_CLEAR  (0x1 << 1) /* Clearing TC is done by writing a 0x1 */
+
+#define MMCHS_SD_IE_BRR_ENABLE         (0x1 << 5) /* Buffer read ready interrupt  */
+#define MMCHS_SD_IE_BRR_ENABLE_DISABLE (0x0 << 5) /* Buffer read ready interrupt disable */
+#define MMCHS_SD_IE_BRR_ENABLE_ENABLE  (0x1 << 5) /* Buffer read ready interrupt enable */
+#define MMCHS_SD_IE_BRR_ENABLE_CLEAR   (0x1 << 5) /* Buffer read ready interrupt clear */
+
+#define MMCHS_SD_IE_BWR_ENABLE         (0x1 << 4) /* Buffer write ready interrupt  */
+#define MMCHS_SD_IE_BWR_ENABLE_DISABLE (0x0 << 4) /* Buffer write ready interrupt disable */
+#define MMCHS_SD_IE_BWR_ENABLE_ENABLE  (0x1 << 4) /* Buffer write ready interrupt enable */
+#define MMCHS_SD_IE_BWR_ENABLE_CLEAR   (0x1 << 4) /* Buffer write ready interrupt clear */
+
+#define MMCHS_SD_CAPA_VS_MASK (0x7 << 24 )  /* voltage mask */
+#define MMCHS_SD_CAPA_VS18 (0x01 << 26 )  /* 1.8 volt */
+#define MMCHS_SD_CAPA_VS30 (0x01 << 25 )  /* 3.0 volt */
+#define MMCHS_SD_CAPA_VS33 (0x01 << 24 )  /* 3.3 volt */
+
index cbe543db33e9bf7e1d36e784da9a22e4f46fabd1..0bed9ddffa8e9774732515dedc13b3c5ef1216de 100644 (file)
@@ -532,6 +532,13 @@ service devman
        uid 0;
 };
 
+service mmc
+{
+       system
+               PRIVCTL         #  4
+       ;
+};
+
 service vbox
 {
        system