]> Zhao Yanbai Git Server - minix.git/commitdiff
arm:mmc driver refactor. 57/657/1
authorKees Jongenburger <kees.jongenburger@gmail.com>
Thu, 13 Jun 2013 12:53:59 +0000 (14:53 +0200)
committerKees Jongenburger <keesj@minix3.org>
Tue, 18 Jun 2013 12:35:44 +0000 (14:35 +0200)
Generalize the usage of mmc_send_cmd function to allow
it to transfer data and remove direct invocations to
mmchs_send_cmd.

Change-Id: Iabb9a7d3f4ec57536407b369531ded2b8b649cce

drivers/mmc/mmchost_mmchs.c

index add21753890593fb77160eb462ca4647791b5960..58390ef72da8023bf27c75982c0b7b9b8b5c5250 100644 (file)
@@ -3,6 +3,7 @@
 #include <minix/com.h>
 #include <minix/vm.h>
 #include <minix/spin.h>
+#include <minix/mmio.h>
 #include <sys/mman.h>
 #include <sys/time.h>
 
@@ -36,11 +37,12 @@ static int hook_id = 1;
 #define OMAP3_MMC1_IRQ      83 /* MMC/SD module 1 */
 #endif
 #ifdef AM335X
-#define OMAP3_MMC1_IRQ     64  /* MMC/SD module 1 */
+#define OMAP3_MMC1_IRQ     64  /* MMC/SD module 1 */
 #endif
 #endif
 
 #define SANE_TIMEOUT 500000    /* 500 MS */
+
 /*
  * Define a structure to be used for logging
  */
@@ -50,37 +52,6 @@ static struct mmclog log = {
        .log_func = default_log
 };
 
-#define REG(x)(*((volatile uint32_t *)(x)))
-#define BIT(x)(0x1 << x)
-
-/* Write a uint32_t value to a memory address. */
-static inline void
-write32(uint32_t address, uint32_t value)
-{
-       REG(address) = value;
-}
-
-/* Read an uint32_t from a memory address */
-static inline uint32_t
-read32(uint32_t address)
-{
-
-       return REG(address);
-}
-
-/* Set a 32 bits value depending on a mask */
-static 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;
 
 /*
@@ -150,7 +121,7 @@ mmchs_init(uint32_t instance)
        value |= MMCHS_SD_SYSCONFIG_ENAWAKEUP_EN;
        /* Smart-idle */
        value |= MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE;
-       /* Booth the interface and functional can be switched off */
+       /* Both 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;
@@ -199,8 +170,8 @@ mmchs_init(uint32_t instance)
 
        // @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,
+       // (0x20 << 6));
        set32(base_address + MMCHS_SD_SYSCTL, MMCHS_SD_SYSCTL_CLKD,
            (0x5 << 6));
 
@@ -233,7 +204,7 @@ mmchs_init(uint32_t instance)
         * raised for unknown reasons */
        set32(base_address + MMCHS_SD_IE, MMCHS_SD_IE_ERROR_MASK, 0x0fffffffu);
 
-       /* clean the error interrupts */
+       /* clear the error interrupts */
        set32(base_address + MMCHS_SD_STAT, MMCHS_SD_STAT_ERROR_MASK,
            0xffffffffu);
 
@@ -312,12 +283,13 @@ intr_wait(int mask)
 #ifdef USE_INTR
        if (sys_irqenable(&hook_id) != OK)
                printf("Failed to enable irqenable irq\n");
-/* Wait for a task completion interrupt. */
+       /* Wait for a task completion interrupt. */
        message m;
        int ipc_status;
-       int ticks = SANE_TIMEOUT * sys_hz() / 1000000;
+       int ticks = SANE_TIMEOUT * sys_hz() / 1000000;
 
-       if (ticks <= 0) ticks =1;
+       if (ticks <= 0)
+               ticks = 1;
        while (1) {
                int rr;
                sys_setalarm(ticks, 0);
@@ -337,10 +309,12 @@ intr_wait(int mask)
                                if (v & mask) {
                                        sys_setalarm(0, 0);
                                        return 0;
-                               } else if (v & (1 << 15)){
-                                       return 1; /* error */
+                               } else if (v & (1 << 15)) {
+                                       return 1;       /* error */
                                } else {
-                                       mmc_log_debug(&log, "unexpected HW interrupt 0x%08x mask 0X%08x\n", v, mask);
+                                       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");
@@ -363,24 +337,28 @@ intr_wait(int mask)
                        blockdriver_mq_queue(&m, ipc_status);
                }
        }
-       sys_setalarm(0, 0); /* cancel the alarm */
+       sys_setalarm(0, 0);     /* cancel the alarm */
 
 #else
        spin_t spin;
        spin_init(&spin, SANE_TIMEOUT);
        /* Wait for completion */
-       int counter =0;
+       int counter = 0;
        while (1 == 1) {
-               counter ++;
+               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);
+                       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);
+               } else if (v & 0xFF00) {
+                       mmc_log_debug(&log,
+                           "unexpected HW interrupt (%d) 0x%08x mask 0x%08x\n",
+                           v, mask);
                        return 1;
                }
        }
@@ -448,6 +426,8 @@ mmc_send_cmd(struct mmc_command *c)
        /* convert the command to a hsmmc command */
        int ret;
        uint32_t cmd, arg;
+       uint32_t count;
+       uint32_t value;
        cmd = MMCHS_SD_CMD_INDX_CMD(c->cmd);
        arg = c->args;
 
@@ -468,6 +448,45 @@ mmc_send_cmd(struct mmc_command *c)
                return 1;
        }
 
+       /* read single block */
+       if (c->cmd == MMC_READ_BLOCK_SINGLE) {
+               cmd |= MMCHS_SD_CMD_DP_DATA;    /* Command with data transfer */
+               cmd |= MMCHS_SD_CMD_MSBS_SINGLE;        /* single block */
+               cmd |= MMCHS_SD_CMD_DDIR_READ;  /* read data from card */
+
+       }
+
+       /* write single block */
+       if (c->cmd == MMC_WRITE_BLOCK_SINGLE) {
+               cmd |= MMCHS_SD_CMD_DP_DATA;    /* Command with data transfer */
+               cmd |= MMCHS_SD_CMD_MSBS_SINGLE;        /* single block */
+               cmd |= MMCHS_SD_CMD_DDIR_WRITE; /* write to the card */
+       }
+
+       /* check we are in a sane state */
+       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);
+       }
+
+       if (cmd & MMCHS_SD_CMD_DP_DATA) {
+               if (cmd & MMCHS_SD_CMD_DDIR_READ) {
+                       /* if we are going to read enable the buffer ready
+                        * interrupt */
+                       set32(base_address + MMCHS_SD_IE,
+                           MMCHS_SD_IE_BRR_ENABLE,
+                           MMCHS_SD_IE_BRR_ENABLE_ENABLE);
+               } else {
+                       set32(base_address + MMCHS_SD_IE,
+                           MMCHS_SD_IE_BWR_ENABLE,
+                           MMCHS_SD_IE_BWR_ENABLE_ENABLE);
+               }
+       }
+
+       set32(base_address + MMCHS_SD_BLK, MMCHS_SD_BLK_BLEN, 512);
+
        ret = mmchs_send_cmd(cmd, arg);
 
        /* copy response into cmd->resp */
@@ -488,14 +507,120 @@ mmc_send_cmd(struct mmc_command *c)
                return 1;
        }
 
+       if (cmd & MMCHS_SD_CMD_DP_DATA) {
+               count = 0;
+               assert(c->data_len);
+               if (cmd & MMCHS_SD_CMD_DDIR_READ) {
+                       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 */
+                       }
+
+                       for (count = 0; count < c->data_len; count += 4) {
+                               value = read32(base_address + MMCHS_SD_DATA);
+                               c->data[count] = *((char *) &value);
+                               c->data[count + 1] = *((char *) &value + 1);
+                               c->data[count + 2] = *((char *) &value + 2);
+                               c->data[count + 3] = *((char *) &value + 3);
+                       }
+
+                       /* Wait for TC */
+                       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 */
+                       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);
+               } else {
+                       /* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */
+                       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) = c->data[count];
+                               *((char *) &value + 1) = c->data[count + 1];
+                               *((char *) &value + 2) = c->data[count + 2];
+                               *((char *) &value + 3) = c->data[count + 3];
+                               write32(base_address + MMCHS_SD_DATA, value);
+                       }
+
+                       /* Wait for TC */
+                       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;
+                       }
+                       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 ret;
 }
 
-static struct mmc_command command;
+int
+mmc_send_app_cmd(struct sd_card_regs *card, struct mmc_command *c)
+{
+       struct mmc_command command;
+       command.cmd = MMC_APP_CMD;
+       command.resp_type = RESP_LEN_48;
+       command.args = MMC_ARG_RCA(card->rca);
+
+       if (mmc_send_cmd(&command)) {
+               return 1;
+       }
+
+       return mmc_send_cmd(c);
+}
 
 int
 card_goto_idle_state()
 {
+       struct mmc_command command;
        command.cmd = MMC_GO_IDLE_STATE;
        command.resp_type = NO_RESPONSE;
        command.args = 0x00;
@@ -509,12 +634,16 @@ card_goto_idle_state()
 int
 card_identification()
 {
+       struct mmc_command command;
        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,
+               /* We currently only support 2.0, and 1.0 won't respond to
+                * this request */
+               mmc_log_warn(&log, "%s,  non SDHC card inserted\n",
+                   __FUNCTION__);
                return 1;
        }
 
@@ -530,6 +659,7 @@ card_identification()
 int
 card_query_voltage_and_type(struct sd_card_regs *card)
 {
+       struct mmc_command command;
        spin_t spin;
        command.cmd = MMC_APP_CMD;
        command.resp_type = RESP_LEN_48;
@@ -594,7 +724,7 @@ card_query_voltage_and_type(struct sd_card_regs *card)
 int
 card_identify(struct sd_card_regs *card)
 {
-
+       struct mmc_command command;
        /* Send cmd 2 (all_send_cid) and expect 136 bits response */
        command.cmd = MMC_ALL_SEND_CID;
        command.resp_type = RESP_LEN_136;
@@ -629,6 +759,9 @@ card_identify(struct sd_card_regs *card)
 int
 card_csd(struct sd_card_regs *card)
 {
+       /* Read the Card Specific Data register */
+       struct mmc_command command;
+
        /* send_csd -> r2 response */
        command.cmd = MMC_SEND_CSD;
        command.resp_type = RESP_LEN_136;
@@ -657,6 +790,7 @@ card_csd(struct sd_card_regs *card)
 int
 select_card(struct sd_card_regs *card)
 {
+       struct mmc_command command;
 
        command.cmd = MMC_SELECT_CARD;
        command.resp_type = RESP_LEN_48_CHK_BUSY;
@@ -672,60 +806,19 @@ int
 read_single_block(struct sd_card_regs *card,
     uint32_t blknr, unsigned char *buf)
 {
-       uint32_t count;
-       uint32_t value;
-
-       count = 0;
+       struct mmc_command command;
 
-       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);
+       command.cmd = MMC_READ_BLOCK_SINGLE;
+       command.args = blknr;
+       command.resp_type = RESP_LEN_48;
+       command.data = buf;
+       command.data_len = 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)) {
+       if (mmc_send_cmd(&command)) {
                mmc_log_warn(&log, "Error sending command\n");
                return 1;
        }
 
-       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 */
-       }
-
-       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 */
-       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 */
-       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;
 }
 
@@ -733,74 +826,22 @@ int
 write_single_block(struct sd_card_regs *card,
     uint32_t blknr, unsigned char *buf)
 {
-       uint32_t count;
-       uint32_t value;
+       struct mmc_command command;
 
-       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);
 
+       command.cmd = MMC_WRITE_BLOCK_SINGLE;
+       command.args = blknr;
+       command.resp_type = RESP_LEN_48;
+       command.data = buf;
+       command.data_len = 512;
+
        /* 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)) {
+       if (mmc_send_cmd(&command)) {
                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 */
-       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];
-               *((char *) &value + 3) = buf[count + 3];
-               write32(base_address + MMCHS_SD_DATA, value);
-       }
-
-
-       /* Wait for TC */
-       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;
-       }
-       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;
 }