fix csd2/fifo retardation
authorKristina <tinab@hush.ai>
Tue, 6 Sep 2016 06:56:01 +0000 (07:56 +0100)
committerKristina <tinab@hush.ai>
Tue, 6 Sep 2016 06:56:01 +0000 (07:56 +0100)
arm_chainloader/drivers/sdhost_impl.cc

index 42099d6..a7be4a3 100644 (file)
@@ -42,6 +42,23 @@ SDHOST driver. This used to be known as ALTMMC.
 #define SDHSTS_CRC7_ERROR               0x10\r
 #define SDHSTS_FIFO_ERROR               0x08\r
 \r
+#define SDEDM_FSM_MASK           0xf\r
+#define SDEDM_FSM_IDENTMODE      0x0\r
+#define SDEDM_FSM_DATAMODE       0x1\r
+#define SDEDM_FSM_READDATA       0x2\r
+#define SDEDM_FSM_WRITEDATA      0x3\r
+#define SDEDM_FSM_READWAIT       0x4\r
+#define SDEDM_FSM_READCRC        0x5\r
+#define SDEDM_FSM_WRITECRC       0x6\r
+#define SDEDM_FSM_WRITEWAIT1     0x7\r
+#define SDEDM_FSM_POWERDOWN      0x8\r
+#define SDEDM_FSM_POWERUP        0x9\r
+#define SDEDM_FSM_WRITESTART1    0xa\r
+#define SDEDM_FSM_WRITESTART2    0xb\r
+#define SDEDM_FSM_GENPULSES      0xc\r
+#define SDEDM_FSM_WRITEWAIT2     0xd\r
+#define SDEDM_FSM_STARTPOWDOWN   0xf\r
+\r
 #define SDHSTS_TRANSFER_ERROR_MASK      (SDHSTS_CRC7_ERROR|SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR)\r
 #define SDHSTS_ERROR_MASK               (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK)\r
 \r
@@ -189,7 +206,7 @@ struct SdhostImpl : BlockDevice {
                wait_and_get_response();\r
 \r
                /* set voltage */\r
-               t = MMC_OCR_3_2V_3_3V;\r
+               t = MMC_OCR_3_3V_3_4V;\r
                if (r[0] == 0x1AA) {\r
                        t |= MMC_OCR_HCS;\r
                        is_sdhc = true;\r
@@ -197,8 +214,8 @@ struct SdhostImpl : BlockDevice {
 \r
                /* query voltage and type */\r
                for (;;) {\r
-                       send(MMC_APP_CMD);\r
-                       send(SD_APP_OP_COND, t);\r
+                       send(MMC_APP_CMD); /* 55 */\r
+                       send_no_resp(SD_APP_OP_COND, t);\r
 \r
                        if (!wait_and_get_response())\r
                                return false;\r
@@ -259,81 +276,116 @@ struct SdhostImpl : BlockDevice {
                return true;\r
        }\r
 \r
-       inline bool wait_for_data_xfer() {\r
-               for (int i = 0; i < 1000; i++) {\r
-                       if (SH_HSTS & SH_HSTS_DATA_FLAG_SET) {\r
-                               SH_HSTS = SH_HSTS_DATA_FLAG_SET;\r
-                               return true;\r
-                       }       \r
-                       udelay(100);\r
+//#define DUMP_READ\r
+\r
+       bool wait_for_fifo_data(uint32_t timeout = 100000) {\r
+               uint32_t t = timeout;\r
+\r
+               while ((SH_HSTS & SH_HSTS_DATA_FLAG_SET) == 0) {\r
+                       if (t == 0) {\r
+                               putchar('\n');\r
+                               logf("ERROR: no FIFO data, timed out after %dus!\n", timeout)\r
+                               return false;\r
+                       }\r
+                       t--;\r
+                       udelay(10);\r
                }\r
-               return false;\r
+\r
+               return true;\r
        }\r
 \r
-//#define DUMP_READ\r
 \r
-       virtual bool read_block(uint32_t sector, uint32_t* buf) override {\r
-               if (!card_ready)\r
-                       panic("card not ready");\r
+       void drain_fifo() {\r
+               /* fuck me with a rake ... genlty */\r
+\r
+               wait();\r
+\r
+               int i = 0;\r
+\r
+#ifdef DUMP_READ\r
+               logf("Draining FIFO ...\n");\r
+#endif\r
+\r
+               while (SH_HSTS & SH_HSTS_DATA_FLAG_SET) {\r
+                       SH_DATA;\r
+                       mfence();\r
+                       i++;\r
+               }\r
 \r
 #ifdef DUMP_READ\r
-               logf("Reading %d bytes from sector %d ...\n", block_size, sector);\r
+               logf("Drained %d words from the FIFO!\n", i);\r
 #endif\r
+       }\r
+\r
+       virtual bool read_block(uint32_t sector, uint32_t* buf) override {\r
+               if (!card_ready)\r
+                       panic("card not ready");\r
 \r
                if (!is_high_capacity)\r
                        sector <<= 9;\r
 \r
-               send_raw(MMC_READ_BLOCK_SINGLE | SH_CMD_READ_CMD_SET | SH_CMD_BUSY_CMD_SET, sector);\r
-               if (!wait()) {\r
-                       return false;\r
-               }\r
+               /* drain junk from FIFO */\r
+               drain_fifo();\r
+\r
+               /* enter READ mode */\r
+               send_raw(MMC_READ_BLOCK_MULTIPLE | SH_CMD_READ_CMD_SET, sector);\r
 \r
-               uint32_t remaining = block_size;\r
+               int i;\r
+               uint32_t hsts_err = 0;\r
 \r
 #ifdef DUMP_READ\r
-               printf("----------------------------------------------------\n");\r
+               if (buf)\r
+                       logf("Reading %d bytes from sector %d using FIFO ...\n", block_size, sector);\r
 #endif\r
 \r
-               while (remaining) {\r
-                       if (!wait_for_data_xfer()) {\r
 #ifdef DUMP_READ\r
-                               putchar('\n');\r
+               printf("----------------------------------------------------\n");\r
 #endif\r
-                               logf("ERROR: Timeout while reading block\n");\r
+\r
+               /* drain useful data from FIFO */\r
+               for (i = 0; i < 128; i++) {\r
+                       /* wait for FIFO */\r
+                       if (!wait_for_fifo_data()) {\r
+                               break;\r
+                       }\r
+\r
+                       uint32_t hsts_err = SH_HSTS & SDHSTS_ERROR_MASK;\r
+                       if (hsts_err) {\r
+                               logf("ERROR: transfer error on FIFO word %d: 0x%x\n", i, SH_HSTS);\r
                                break;\r
                        }\r
+\r
+\r
+                       volatile uint32_t data = SH_DATA;\r
                        \r
-                       *buf = SH_DATA;\r
 #ifdef DUMP_READ\r
-                       printf("%08x ", *buf);\r
+                       printf("%08x ", data);\r
 #endif\r
-                       buf++;\r
-                       remaining -= 4;\r
+                       if (buf)\r
+                               *(buf++) = data;\r
                }\r
 \r
+               send_raw(MMC_STOP_TRANSMISSION | SH_CMD_BUSY_CMD_SET);\r
+\r
 #ifdef DUMP_READ\r
-               printf("\n----------------------------------------------------\n");\r
+               if (buf)\r
+                       printf("\n----------------------------------------------------\n");\r
 #endif\r
 \r
-               send(MMC_STOP_TRANSMISSION);\r
-\r
-               uint32_t sdhsts_errs = SH_HSTS & SDHSTS_ERROR_MASK;\r
-               if (sdhsts_errs) {\r
+               if (hsts_err) {\r
                        logf("ERROR: Transfer error, status: 0x%x\n", SH_HSTS);\r
-               }\r
-\r
-               if (remaining) {\r
-                       logf("ERROR: Read failed, %d bytes left to copy\n", remaining);\r
                        return false;\r
                }\r
-               else {\r
+\r
 #ifdef DUMP_READ\r
+               if (buf)\r
                        logf("Completed read for %d\n", sector);\r
 #endif\r
-                       return true;\r
-               }\r
+               return true;\r
        }\r
 \r
+\r
+\r
        bool select_card() {\r
                send(MMC_SELECT_CARD, MMC_ARG_RCA(rca));\r
 \r
@@ -347,7 +399,7 @@ struct SdhostImpl : BlockDevice {
                char pnm[8];\r
                uint32_t block_length;\r
 \r
-               send_no_resp(MMC_GO_IDLE_STATE | SH_CMD_NO_RESPONSE_SET);\r
+               send_no_resp(MMC_GO_IDLE_STATE);\r
 \r
                if (!query_voltage_and_type()) {\r
                        logf("ERROR: Failed to query card voltage!\n");\r
@@ -369,7 +421,10 @@ struct SdhostImpl : BlockDevice {
                        printf("    Capacity: %d\n", SD_CSD_V2_CAPACITY(csd));\r
                        printf("    Size    : %d\n", SD_CSD_V2_C_SIZE(csd));\r
 \r
-                       block_length = SD_CSD_V2_BL_LEN;\r
+                       block_length = 1 << SD_CSD_V2_BL_LEN;\r
+\r
+                       /* work out the capacity of the card in bytes */\r
+                       capacity_bytes = (SD_CSD_V2_CAPACITY(csd) * block_length);\r
                }\r
                else if (SD_CSD_CSDVER(csd) == SD_CSD_CSDVER_1_0) {\r
                        printf("    CSD     : Ver 1.0\n");\r
@@ -377,19 +432,17 @@ struct SdhostImpl : BlockDevice {
                        printf("    Size    : %d\n", SD_CSD_C_SIZE(csd));\r
 \r
                        block_length = 1 << SD_CSD_READ_BL_LEN(csd);\r
+\r
+                       /* work out the capacity of the card in bytes */\r
+                       capacity_bytes = (SD_CSD_CAPACITY(csd) * block_length); \r
                }\r
                else {\r
                        printf("ERROR: Unknown CSD version 0x%x!\n", SD_CSD_CSDVER(csd));\r
-\r
-\r
                        return false;\r
                }\r
        \r
                printf("    BlockLen: 0x%x\n", block_length);\r
 \r
-               /* work out the capacity of the card in bytes */\r
-               capacity_bytes = (SD_CSD_CAPACITY(csd) * block_length);\r
-\r
                if (!select_card()) {\r
                        logf("ERROR: Failed to select card!\n");\r
                        return false;\r
@@ -418,6 +471,12 @@ struct SdhostImpl : BlockDevice {
        void restart_controller() {\r
                is_sdhc = false;\r
 \r
+               logf("hcfg 0x%X, cdiv 0x%X, edm 0x%X, hsts 0x%X\n",\r
+                       SH_HCFG,\r
+                       SH_CDIV,\r
+                       SH_EDM,\r
+                       SH_HSTS);\r
+\r
                logf("Restarting the eMMC controller ...\n");\r
 \r
                configure_pinmux();\r
@@ -425,13 +484,22 @@ struct SdhostImpl : BlockDevice {
 \r
                SH_HCFG &= ~SH_HCFG_WIDE_EXT_BUS_SET;\r
                SH_HCFG = SH_HCFG_SLOW_CARD_SET | SH_HCFG_WIDE_INT_BUS_SET;\r
-               SH_CDIV = 0x96;\r
+               SH_CDIV = 0x148;\r
 \r
                udelay(300);\r
                mfence();\r
 \r
                if (init_card()) {\r
                        card_ready = true;\r
+\r
+                       /*\r
+                        * looks like a silicon bug to me or a quirk of csd2, who knows\r
+                        */\r
+                       for (int i = 0; i < 3; i++) {\r
+                               if (!read_block(0, nullptr)) {\r
+                                       panic("fifo flush cycle %d failed", i);\r
+                               }\r
+                       }\r
                }\r
                else {\r
                        panic("failed to reinitialize the eMMC controller");\r
This page took 0.040126 seconds and 4 git commands to generate.