]> Zhao Yanbai Git Server - minix.git/commitdiff
mmc:development 71/271/2
authorKees Jongenburger <kees.jongenburger@gmail.com>
Fri, 19 Oct 2012 13:44:10 +0000 (15:44 +0200)
committerKees Jongenburger <keesj@minix3.org>
Fri, 1 Feb 2013 12:31:10 +0000 (13:31 +0100)
* let busy loops timeout.
* Start using interrupt handlers.
* Allocate the ramdisk only when used.

Change-Id: Ie08d66eefef3c8cd3ee16c04f74a9a50cc12b021

drivers/mmc/mmcblk.c
drivers/mmc/mmchost.h
drivers/mmc/mmchost_dummy.c
drivers/mmc/mmchost_mmchs.c
drivers/mmc/omap_mmc.h
etc/system.conf

index 4951b33b7019b52dba26feccdbf9753295b8be51..d2da50a3fc8ad5d275725c96979b8db2d1214e07 100644 (file)
@@ -6,6 +6,8 @@
 #include <minix/driver.h>
 #include <minix/blockdriver.h>
 #include <minix/drvlib.h>
+#include <minix/minlib.h>
+
 
 /* system headers */
 #include <sys/ioc_disk.h>      /* disk IOCTL's */
 /* used for logging */
 static struct mmclog log = {
        .name = "mmc_block",
-       .log_level = LEVEL_DEBUG,
+       .log_level = LEVEL_INFO,
        .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)
 
@@ -70,12 +60,18 @@ 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);
 
+void
+bdr_alarm(clock_t stamp)
+{
+       mmc_log_debug(&log, "alarm %d\n", stamp);
+
+}
+
 static int apply_env();
+static void hw_intr(unsigned int irqs);
 
-#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 = {
@@ -87,20 +83,28 @@ static struct blockdriver mmc_driver = {
        NULL,                   /* no need to clean up (yet) */
        block_part,             /* return partition information */
        NULL,                   /* no geometry */
-       NULL,                   /* no interrupt processing */
-       NULL,                   /* no alarm processing */
+       hw_intr,                /* left over interrupts */
+       bdr_alarm,              /* no alarm processing */
        NULL,                   /* no processing of other messages */
        NULL                    /* no threading support */
 };
 
+static void
+hw_intr(unsigned int irqs)
+{
+       mmc_log_debug(&log, "Hardware inter left over\n");
+       host.hw_intr(irqs);
+}
+
 static int
 apply_env()
 {
+       long v;
        /* apply the env setting passed to this driver parameters accepted
-        * log_level=[0-4] (NONE,WARNING,INFO,DEBUG,TRACE) instance=[0-3]
+        * log_level=[0-4] (NONE,WARN,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/mmc -args "log_level=2 instance=1 
+        * following way service up /sbin/mmc -args "log_level=2 instance=1
         * driver=dummy" -dev /dev/c2d0 */
        char driver[16];
        memset(driver, '\0', 16);
@@ -115,10 +119,6 @@ apply_env()
        } else {
                mmc_log_warn(&log, "Unknown driver %s\n", driver);
        }
-#if 0
-       long v;
-       /* The following code(env_parse) uses strtol.c and needs __aeabi_idiv */
-       /* @TODO: re-enable this function when __aeabi_idiv will be present */
        /* Initialize the verbosity level. */
        v = 0;
        if (env_parse("log_level", "d", 0, &v, LEVEL_NONE,
@@ -133,7 +133,6 @@ apply_env()
                mmc_log_warn(&log, "Failed to set mmc instance to  %d\n", v);
                return -1;      /* NOT OK */
        }
-#endif
        return OK;
 }
 
@@ -185,27 +184,27 @@ block_open(dev_t minor, int access)
        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_trace(&log, "descr \toffset(bytes)      size(bytes)\n", minor);
 
-       mmc_log_debug(&log, "disk %d\t0x%016llx 0x%016llx\n", i,
+       mmc_log_trace(&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,
+               mmc_log_trace(&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.subpart[(i - 1) * 4 + j].dv_size == 0)
                                continue;
                        sub_part_count++;
-                       mmc_log_debug(&log,
+                       mmc_log_trace(&log,
                            " sub %d/%d\t0x%016llx 0x%016llx\n", i, j,
                            slot->card.subpart[(i - 1) * 4 + j].dv_base,
                            slot->card.subpart[(i - 1) * 4 + j].dv_size);
                }
        }
-       mmc_log_info(&log, "Found %d partitions and %d sub partitions\n",
+       mmc_log_debug(&log, "Found %d partitions and %d sub partitions\n",
            part_count, sub_part_count);
        slot->card.open_ct++;
        assert(slot->card.open_ct == 1);
@@ -312,7 +311,7 @@ block_transfer(dev_t minor, /* minor device number */
                /* Unknown device */
                return ENXIO;
        }
-       mmc_log_trace(&log, "I/O %d %s 0x%llx\n", minor,
+       mmc_log_trace(&log, "I/O on minor(%d) %s at 0x%016llx\n", minor,
            (do_write) ? "Write" : "Read", position);
 
        slot = get_slot(minor);
@@ -636,20 +635,18 @@ get_slot(dev_t minor)
        }
 }
 
-#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);
+       mmc_log_info(&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)
@@ -657,7 +654,6 @@ main(int argc, char **argv)
 
        /* Set and apply the environment */
        env_setargs(argc, argv);
-
        sef_local_startup();
        blockdriver_task(&mmc_driver);
        return EXIT_SUCCESS;
index 37e44c4fa1a7c0989154da468a1493f7bd60fae1..bad9d0911d81a82e3c67b473623b839386761d44 100644 (file)
@@ -117,6 +117,9 @@ struct mmc_host
        /* Release the card */
        int (*card_release) (struct sd_card * card);
 
+       /* Additional hardware interrupts */
+       void (*hw_intr) (unsigned int irqs);
+
        /* read count blocks into existing buf */
        int (*read) (struct sd_card * card,
            uint32_t blknr, uint32_t count, unsigned char *buf);
index 3d560abae1d32564a0d779eb5fb0f07a74a9a4cb..15a74128447181ba25e26e21f55ea5c8e8eb8599 100644 (file)
@@ -1,11 +1,13 @@
 /* kernel headers */
 #include <minix/blockdriver.h>
+#include <minix/minlib.h>
 
 /* usr headers */
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <assert.h>
+#include <unistd.h>
 
 /* local headers */
 #include "mmclog.h"
  */
 static struct mmclog log = {
        .name = "mmc_host_memory",
-       .log_level = LEVEL_TRACE,
+       .log_level = LEVEL_INFO,
        .log_func = default_log
 };
 
 /* This is currently a dummy driver using an in-memory structure */
-#define DUMMY_SIZE_IN_BLOCKS 0xFFFu
+#define DUMMY_SIZE_IN_BLOCKS 0xFFFFFu
 #define DUMMY_BLOCK_SIZE 512
-static char dummy_data[DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS];
+static char *dummy_data = NULL;
 
 static struct sd_card *
 init_dummy_sdcard(struct sd_slot *slot)
@@ -35,6 +37,13 @@ init_dummy_sdcard(struct sd_slot *slot)
        assert(slot != NULL);
 
        mmc_log_info(&log, "Using a dummy card \n");
+       if (dummy_data == NULL) {
+               dummy_data = malloc(DUMMY_BLOCK_SIZE * DUMMY_SIZE_IN_BLOCKS);
+               if (dummy_data == NULL) {
+                       panic
+                           ("Failed to allocate data for dummy mmc driver\n");
+               }
+       }
 
        card = &slot->card;
        memset(card, 0, sizeof(struct sd_card));
index cbf5a838479f4f4460757a804673d7ad68232680..1797febaeb3c058ef0ce08cadcc5ac5928fdedae 100644 (file)
@@ -2,7 +2,9 @@
 #include <minix/blockdriver.h>
 #include <minix/com.h>
 #include <minix/vm.h>
+#include <minix/spin.h>
 #include <sys/mman.h>
+#include <sys/time.h>
 
 /* usr headers */
 #include <assert.h>
@@ -12,6 +14,7 @@
 #include <string.h>
 #include <inttypes.h>
 #include <limits.h>
+#include <unistd.h>
 
 /* local headers */
 #include "mmclog.h"
 /* omap /hardware related */
 #include "omap_mmc.h"
 
+#define USE_INTR
+
+#ifdef USE_INTR
+static int hook_id = 1;
+#define OMAP3_MMC1_IRQ      83 /* MMC/SD module 1 */
+#endif
+
+#define SANE_TIMEOUT 500000    /* 500 MS */
 /*
  * Define a structure to be used for logging
  */
@@ -38,14 +49,14 @@ static struct mmclog log = {
 #define BIT(x)(0x1 << x)
 
 /* Write a uint32_t value to a memory address. */
-inline void
+static inline void
 write32(uint32_t address, uint32_t value)
 {
        REG(address) = value;
 }
 
 /* Read an uint32_t from a memory address */
-inline uint32_t
+static inline uint32_t
 read32(uint32_t address)
 {
 
@@ -53,7 +64,7 @@ read32(uint32_t address)
 }
 
 /* Set a 32 bits value depending on a mask */
-inline void
+static inline void
 set32(uint32_t address, uint32_t mask, uint32_t value)
 {
        uint32_t val;
@@ -75,13 +86,11 @@ static uint32_t base_address;
 int
 mmchs_init(uint32_t instance)
 {
-       int counter;
-       uint32_t value;
 
-       counter = 0;
+       uint32_t value;
        value = 0;
-
        struct minix_mem_range mr;
+       spin_t spin;
 
        mr.mr_base = MMCHS1_REG_BASE;
        mr.mr_limit = MMCHS1_REG_BASE + 0x400;
@@ -106,11 +115,14 @@ mmchs_init(uint32_t instance)
            MMCHS_SD_SYSCONFIG_SOFTRESET);
 
        /* Read sysstatus to know when it's done */
+
+       spin_init(&spin, SANE_TIMEOUT);
        while (!(read32(base_address + MMCHS_SD_SYSSTATUS)
                & MMCHS_SD_SYSSTATUS_RESETDONE)) {
-               /* TODO:Add proper delay and escape route */
-
-               counter++;
+               if (spin_check(&spin) == FALSE) {
+                       mmc_log_warn(&log, "mmc init timeout\n");
+                       return 1;
+               }
        }
 
        /* Set SD default capabilities */
@@ -164,12 +176,14 @@ mmchs_init(uint32_t instance)
        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 */
-
+       // /* TODO: Add padconf/pinmux stuff here as documented in the TRM */
+       spin_init(&spin, SANE_TIMEOUT);
        while ((read32(base_address + MMCHS_SD_HCTL) & MMCHS_SD_HCTL_SDBP)
            != MMCHS_SD_HCTL_SDBP_ON) {
-               /* TODO:Add proper delay and escape route */
-               counter++;
+               if (spin_check(&spin) == FALSE) {
+                       mmc_log_warn(&log, "mmc init timeout SDBP not set\n");
+                       return 1;
+               }
        }
 
        /* Enable internal clock and clock to the card */
@@ -177,16 +191,23 @@ mmchs_init(uint32_t instance)
            MMCHS_SD_SYSCTL_ICE_EN);
 
        // @TODO Fix external clock enable , this one is very slow
+       // but we first need faster context switching
+       //set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
+        //   (0x20 << 6));
        set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
-           (0x3ff << 6));
+           (0x5 << 6));
+
        set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CEN,
            MMCHS_SD_SYSCTL_CEN_EN);
-       counter = 0;
 
+       spin_init(&spin, SANE_TIMEOUT);
        while ((read32(base_address + MMCHS_SD_SYSCTL) & MMCHS_SD_SYSCTL_ICS)
            != MMCHS_SD_SYSCTL_ICS_STABLE) {
-               /* TODO:Add proper delay and escape route */
-               counter++;
+
+               if (spin_check(&spin) == FALSE) {
+                       mmc_log_warn(&log, "clock not stable\n");
+                       return 1;
+               }
        }
 
        /* 
@@ -216,7 +237,7 @@ mmchs_init(uint32_t instance)
        /* command 0 , type other commands not response etc) */
        write32(base_address + MMCHS_SD_CMD, 0x00);
 
-       counter = 0;
+       spin_init(&spin, SANE_TIMEOUT);
        while ((read32(base_address + MMCHS_SD_STAT) & MMCHS_SD_STAT_CC)
            != MMCHS_SD_STAT_CC_RAISED) {
                if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
@@ -225,7 +246,12 @@ mmchs_init(uint32_t instance)
                            read32(base_address + MMCHS_SD_STAT));
                        return 1;
                }
-               counter++;
+
+               if (spin_check(&spin) == FALSE) {
+                       mmc_log_warn(&log,
+                           "Interrupt not raised during init\n");
+                       return 1;
+               }
        }
 
        /* clear the cc interrupt status */
@@ -238,41 +264,151 @@ mmchs_init(uint32_t instance)
        set32(base_address + MMCHS_SD_CON, MMCHS_SD_CON_INIT,
            MMCHS_SD_CON_INIT_NOINIT);
 
+       /* Set timeout */
+       set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_DTO,
+           MMCHS_SD_SYSCTL_DTO_2POW27);
+
        /* Clean the MMCHS_SD_STAT register */
        write32(base_address + MMCHS_SD_STAT, 0xffffffffu);
+#ifdef USE_INTR
+       hook_id = 1;
+       if (sys_irqsetpolicy(OMAP3_MMC1_IRQ, 0, &hook_id) != OK) {
+               printf("mmc: couldn't set IRQ policy %d\n", OMAP3_MMC1_IRQ);
+               return 1;
+       }
+       /* enable signaling from MMC controller towards interrupt controller */
+       write32(base_address + MMCHS_SD_ISE, 0xffffffffu);
+#endif
+
        return 0;
 }
 
+static void
+mmchs_hw_intr(unsigned int irqs)
+{
+       mmc_log_warn(&log, "Hardware interrupt left over\n");
+
+#ifdef USE_INTR
+       if (sys_irqenable(&hook_id) != OK)
+               printf("couldn't re-enable interrupt \n");
+#endif
+       /* Leftover interrupt(s) received; ack it/them. */
+}
+
+/*===========================================================================*
+ *                             w_intr_wait                                  *
+ *===========================================================================*/
+static int
+intr_wait(int mask)
+{
+       long v;
+#ifdef USE_INTR
+       if (sys_irqenable(&hook_id) != OK)
+               printf("Failed to enable irqenable irq\n");
+/* Wait for a task completion interrupt. */
+       message m;
+       int ipc_status;
+       int ticks = SANE_TIMEOUT * sys_hz() / 1000000;
+
+       if (ticks <= 0) ticks =1;
+       while (1) {
+               int rr;
+               sys_setalarm(ticks, 0);
+               if ((rr = driver_receive(ANY, &m, &ipc_status)) != OK) {
+                       panic("driver_receive failed: %d", rr);
+               };
+               if (is_ipc_notify(ipc_status)) {
+                       switch (_ENDPOINT_P(m.m_source)) {
+                       case CLOCK:
+                               /* Timeout. */
+                               // w_timeout(); /* a.o. set w_status */
+                               mmc_log_warn(&log, "TIMEOUT\n");
+                               return 1;
+                               break;
+                       case HARDWARE:
+                               v = read32(base_address + MMCHS_SD_STAT);
+                               if (v & mask) {
+                                       sys_setalarm(0, 0);
+                                       return 0;
+                               } else if (v & (1 << 15)){
+                                       return 1; /* error */
+                               } else {
+                                       mmc_log_debug(&log, "unexpected HW interrupt 0x%08x mask 0X%08x\n", v, mask);
+                                       if (sys_irqenable(&hook_id) != OK)
+                                               printf
+                                                   ("Failed to re-enable irqenable irq\n");
+                                       continue;
+                                       // return 1;
+                               }
+                       default:
+                               /* 
+                                * unhandled message.  queue it and
+                                * handle it in the blockdriver loop.
+                                */
+                               blockdriver_mq_queue(&m, ipc_status);
+                       }
+               } else {
+                       mmc_log_debug(&log, "Other\n");
+                       /* 
+                        * unhandled message.  queue it and handle it in the
+                        * blockdriver loop.
+                        */
+                       blockdriver_mq_queue(&m, ipc_status);
+               }
+       }
+       sys_setalarm(0, 0); /* cancel the alarm */
+
+#else
+       spin_t spin;
+       spin_init(&spin, SANE_TIMEOUT);
+       /* Wait for completion */
+       int counter =0;
+       while (1 == 1) {
+               counter ++;
+               v = read32(base_address + MMCHS_SD_STAT);
+               if (spin_check(&spin) == FALSE) {
+                       mmc_log_warn(&log, "Timeout waiting for interrupt (%d) value 0x%08x mask 0x%08x\n",counter, v,mask);
+                       return 1;
+               }
+               if (v & mask) {
+                       return 0;
+               } else if (v  & 0xFF00) {
+                       mmc_log_debug(&log, "unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n", v, mask);
+                       return 1;
+               }
+       }
+       return 1;               /* unreached */
+#endif /* USE_INTR */
+}
+
+void
+intr_assert(int mask)
+{
+       if (read32(base_address + MMCHS_SD_STAT) & 0x8000) {
+               mmc_log_debug(&log, "%s, error stat  %08x\n", __FUNCTION__,
+                   read32(base_address + MMCHS_SD_STAT));
+               set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
+                   0xffffffffu);
+       } else {
+               write32(base_address + MMCHS_SD_STAT, mask);
+       }
+}
+
 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)) {
-               mmc_log_warn(&log, "%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) {
-               mmc_log_warn(&log, "%s, error stat  %08x\n", __FUNCTION__,
-                   read32(base_address + MMCHS_SD_STAT));
-               set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
-                   0xffffffffu);
+       if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
+               intr_assert(MMCHS_SD_STAT_CC);
+               mmc_log_warn(&log, "Failure waiting for interrupt\n");
                return 1;
        }
 
@@ -281,16 +417,20 @@ mmchs_send_cmd(uint32_t command, uint32_t arg)
                /* 
                 * Command with busy response *CAN* also set the TC bit if they exit busy
                 */
-               while ((read32(base_address + MMCHS_SD_STAT)
+               if ((read32(base_address + MMCHS_SD_STAT)
                        & MMCHS_SD_IE_TC_ENABLE_ENABLE) == 0) {
-                       count++;
+                       mmc_log_warn(&log, "TC should be raised\n");
                }
                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);
+               if (intr_wait(MMCHS_SD_STAT_CC | MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
+                       intr_assert(MMCHS_SD_STAT_CC);
+                       mmc_log_warn(&log, "Failure waiting for clear\n");
+                       return 1;
+               }
+       }
+       intr_assert(MMCHS_SD_STAT_CC);
        return 0;
 }
 
@@ -383,10 +523,11 @@ card_identification()
 int
 card_query_voltage_and_type(struct sd_card_regs *card)
 {
-
+       spin_t spin;
        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;
        }
@@ -405,6 +546,7 @@ card_query_voltage_and_type(struct sd_card_regs *card)
                return 1;
        }
        /* @todo wait for max 1 ms */
+       spin_init(&spin, SANE_TIMEOUT);
        while (!(command.resp[0] & MMC_OCR_MEM_READY)) {
                command.cmd = MMC_APP_CMD;
                command.resp_type = RESP_LEN_48;
@@ -432,6 +574,10 @@ card_query_voltage_and_type(struct sd_card_regs *card)
                if ((command.resp[0] & MMC_OCR_MEM_READY)) {
                        break;
                }
+               if (spin_check(&spin) == FALSE) {
+                       mmc_log_warn(&log,
+                           "TIMEOUT waiting for the SD card\n");
+               }
 
        }
        card->ocr = command.resp[3];
@@ -536,15 +682,18 @@ read_single_block(struct sd_card_regs *card,
                | MMCHS_SD_CMD_MSBS_SINGLE      /* single block */
                | MMCHS_SD_CMD_DDIR_READ        /* read data from card */
                , blknr)) {
+               mmc_log_warn(&log, "Error sending command\n");
                return 1;
        }
 
-       while ((read32(base_address + MMCHS_SD_STAT)
-               & MMCHS_SD_IE_BRR_ENABLE_ENABLE) == 0) {
-               count++;
+       if (intr_wait(MMCHS_SD_IE_BRR_ENABLE_ENABLE)) {
+               intr_assert(MMCHS_SD_IE_BRR_ENABLE_ENABLE);
+               mmc_log_warn(&log, "Timeout waiting for interrupt\n");
+               return 1;
        }
 
        if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BRE_EN)) {
+               mmc_log_warn(&log, "Problem BRE should be true\n");
                return 1;       /* We are not allowed to read data from the
                                 * data buffer */
        }
@@ -558,11 +707,12 @@ read_single_block(struct sd_card_regs *card,
        }
 
        /* Wait for TC */
-       while ((read32(base_address +
-                   MMCHS_SD_STAT) & MMCHS_SD_IE_TC_ENABLE_ENABLE)
-           == 0) {
-               count++;
+       if (intr_wait(MMCHS_SD_IE_TC_ENABLE_ENABLE)) {
+               intr_assert(MMCHS_SD_IE_TC_ENABLE_ENABLE);
+               mmc_log_warn(&log, "Timeout waiting for interrupt\n");
+               return 1;
        }
+
        write32(base_address + MMCHS_SD_STAT, MMCHS_SD_IE_TC_ENABLE_CLEAR);
 
        /* clear and disable the bbr interrupt */
@@ -579,17 +729,21 @@ write_single_block(struct sd_card_regs *card,
        uint32_t count;
        uint32_t value;
 
-       count = 0;
+       if ((read32(base_address + MMCHS_SD_STAT) & 0xffffu)) {
+               mmc_log_warn(&log, "%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;
+       }
 
        set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
            MMCHS_SD_IE_BWR_ENABLE_ENABLE);
+       count = 0;
+
        // 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 */
@@ -597,19 +751,32 @@ write_single_block(struct sd_card_regs *card,
                | MMCHS_SD_CMD_MSBS_SINGLE      /* single block */
                | MMCHS_SD_CMD_DDIR_WRITE       /* write to the card */
                , blknr)) {
+               mmc_log_warn(&log, "Write single block command failed\n");
+               mmc_log_trace(&log, "STAT=(0x%08x)\n",
+                   read32(base_address + MMCHS_SD_STAT));
                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 (intr_wait(MMCHS_SD_IE_BWR_ENABLE)) {
+               intr_assert(MMCHS_SD_IE_BWR_ENABLE);
+               mmc_log_warn(&log, "WFI failed\n");
+               return 1;
        }
+       /* clear the interrupt directly */
+       intr_assert(MMCHS_SD_IE_BWR_ENABLE);
 
        if (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)) {
+               mmc_log_warn(&log,
+                   "Error expected Buffer to be write enabled\n");
                return 1;       /* not ready to write data */
        }
+
+
        for (count = 0; count < 512; count += 4) {
+               while (!(read32(base_address + MMCHS_SD_PSTATE) & MMCHS_SD_PSTATE_BWE_EN)){
+                       mmc_log_trace(&log, "Error expected Buffer to be write enabled(%d)\n", count);
+               }
                *((char *) &value) = buf[count];
                *((char *) &value + 1) = buf[count + 1];
                *((char *) &value + 2) = buf[count + 2];
@@ -617,17 +784,14 @@ write_single_block(struct sd_card_regs *card,
                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++;
+       if (intr_wait(MMCHS_SD_IE_TC_ENABLE_CLEAR)) {
+               intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
+               mmc_log_warn(&log, "(Write) Timeout waiting for transfer complete\n");
+               return 1;
        }
-       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);
+       intr_assert(MMCHS_SD_IE_TC_ENABLE_CLEAR);
        set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_BWR_ENABLE,
            MMCHS_SD_IE_BWR_ENABLE_DISABLE);
        return 0;
@@ -661,7 +825,7 @@ mmchs_host_set_instance(struct mmc_host *host, int instance)
 int
 mmchs_host_reset(struct mmc_host *host)
 {
-       mmchs_init(1);
+       // mmchs_init(1);
        return 0;
 }
 
@@ -675,7 +839,7 @@ mmchs_card_detect(struct sd_slot *slot)
 struct sd_card *
 mmchs_card_initialize(struct sd_slot *slot)
 {
-       mmchs_init(1);
+       // mmchs_init(1);
 
        struct sd_card *card;
        card = &slot->card;
@@ -785,6 +949,7 @@ host_initialize_host_structure_mmchs(struct mmc_host *host)
        host->card_detect = mmchs_card_detect;
        host->card_initialize = mmchs_card_initialize;
        host->card_release = mmchs_card_release;
+       host->hw_intr = mmchs_hw_intr;
        host->read = mmchs_host_read;
        host->write = mmchs_host_write;
 
index 46011ebdaac97e026a0b31cfc5131731d553708f..02dca94ea8c7b8004ef0e60b34fd1492d6a9e0f3 100644 (file)
@@ -23,6 +23,7 @@
 #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_ISE       0x238 /* SD Interrupt Signal 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_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_SYSCTL_DTO_2POW27   (0xe << 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)
index 5bd104950e17bae8aa3125abb5d43db80487e82b..154e940ace731b5f007195cede081d2c1f2363bf 100644 (file)
@@ -549,6 +549,9 @@ service mmc
 {
        system
                PRIVCTL         #  4
+               IRQCTL          # 19
+       ;
+       irq     83;             # IRQ 83 allowed
        ;
 };