actually sleep the vpu on arm init, added more stuff to sdhost, still broken though
[rpi-open-firmware.git] / arm_chainloader / drivers / sdhost.cc
index 22a2a68..1239b9e 100755 (executable)
@@ -29,9 +29,36 @@ SDHOST driver. This used to be known as ALTMMC.
 #define SAFE_READ_THRESHOLD     4\r
 #define SAFE_WRITE_THRESHOLD    4\r
 \r
+#define VOLTAGE_SUPPLY_RANGE 0x100\r
+#define CHECK_PATTERN 0x55\r
+\r
+\r
+#define SDHSTS_BUSY_IRPT                0x400\r
+#define SDHSTS_BLOCK_IRPT               0x200\r
+#define SDHSTS_SDIO_IRPT                0x100\r
+#define SDHSTS_REW_TIME_OUT             0x80\r
+#define SDHSTS_CMD_TIME_OUT             0x40\r
+#define SDHSTS_CRC16_ERROR              0x20\r
+#define SDHSTS_CRC7_ERROR               0x10\r
+#define SDHSTS_FIFO_ERROR               0x08\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
 #define logf(fmt, ...) printf("[sdhost::%s]: " fmt, __FUNCTION__, ##__VA_ARGS__);\r
 \r
 struct sdhost_t {\r
+       bool is_sdhc;\r
+       bool is_high_capacity;\r
+\r
+       uint32_t ocr;\r
+       uint32_t rca;\r
+\r
+       uint32_t cid[4];\r
+       uint32_t csd[4];\r
+\r
+       uint32_t r[4];\r
+\r
        void set_power(bool on) {\r
                SH_VDD = on ? SH_VDD_POWER_ON_SET : 0x0;\r
        }\r
@@ -51,19 +78,27 @@ struct sdhost_t {
                return true;\r
        }\r
 \r
-       bool send(uint32_t command, uint32_t arg) {\r
-               if (!wait())\r
-                       return false;\r
+       bool send_raw(uint32_t command, uint32_t arg = 0) {\r
+               uint32_t sts;\r
+\r
+               wait();\r
+\r
+               sts = SH_HSTS;\r
+               if (sts & SDHSTS_ERROR_MASK)\r
+                       SH_HSTS = sts; \r
 \r
                SH_ARG = arg;\r
-               SH_CMD = (command & SH_CMD_COMMAND_SET) | SH_CMD_NEW_FLAG_SET;\r
+               SH_CMD = command | SH_CMD_NEW_FLAG_SET;\r
 \r
-               udelay(300);\r
                mfence();\r
 \r
                return true;\r
        }\r
 \r
+       bool send(uint32_t command, uint32_t arg = 0) {\r
+               return send_raw(command & SH_CMD_COMMAND_SET, arg);\r
+       }\r
+\r
        void configure_pinmux() {\r
                GP_FSEL4 = 0x24000000;\r
                GP_FSEL5 = 0x924;\r
@@ -74,7 +109,6 @@ struct sdhost_t {
 \r
        void reset() {\r
                logf("resetting controller ...\n");\r
-\r
                set_power(false);\r
 \r
                SH_CMD = 0;\r
@@ -102,16 +136,163 @@ struct sdhost_t {
                mfence();\r
        }\r
 \r
-       void init_card() {\r
-               send(GO_IDLE_STATE, 0);\r
-               send(SEND_IF_COND, 0x155);\r
+       inline void get_response() {\r
+               r[0] = SH_RSP0;\r
+               r[1] = SH_RSP1;\r
+               r[2] = SH_RSP2;\r
+               r[3] = SH_RSP3;\r
+       }\r
+\r
+       bool wait_and_get_response() {\r
+               if (!wait())\r
+                       return false;\r
+\r
+               get_response();\r
 \r
-               wait();\r
+               logf("HSTS: 0x%x, RSP: %08x %08x %08x %08x\n", SH_HSTS, r[0], r[1], r[2], r[3]);\r
 \r
-               logf("SEND_IF_COND response is: 0x%X\n", SH_RSP0);\r
+               return true;\r
+       }\r
+\r
+       bool query_voltage_and_type() {\r
+               uint32_t t;\r
+\r
+               /* identify */\r
+               send(SD_SEND_IF_COND, 0x1AA);\r
+               wait_and_get_response();\r
+\r
+               /* set voltage */\r
+               t = MMC_OCR_3_2V_3_3V;\r
+               if (r[0] == 0x1AA) {\r
+                       t |= MMC_OCR_HCS;\r
+                       is_sdhc = true;\r
+               }\r
+\r
+               /* query voltage and type */\r
+               for (;;) {\r
+                       send(MMC_APP_CMD);\r
+                       send(SD_APP_OP_COND, t);\r
+\r
+                       if (!wait_and_get_response())\r
+                               return false;\r
+\r
+                       if (r[0] & MMC_OCR_MEM_READY)\r
+                               break;\r
+\r
+                       logf("waiting for sd card (0x%x) ...\n", r[0]);\r
+                       udelay(100);\r
+               }\r
+\r
+               logf("sd card has arrived!\n", r);\r
+\r
+               is_high_capacity = (r[0] & MMC_OCR_HCS) == MMC_OCR_HCS;\r
+\r
+               if (is_high_capacity)\r
+                       logf("this is an SDHC card!\n");\r
+\r
+               return true;\r
+\r
+       }\r
+\r
+       bool identify_card() {\r
+               logf("identifying card ...\n");\r
+               \r
+               send_raw(SH_CMD_LONG_RESPONSE_SET | MMC_ALL_SEND_CID);\r
+               if (!wait_and_get_response())\r
+                       return false;\r
+\r
+               cid[0] = r[0];\r
+               cid[1] = r[1];\r
+               cid[2] = r[2];\r
+               cid[3] = r[3];\r
+\r
+               send(MMC_SET_RELATIVE_ADDR);\r
+\r
+               if (!wait_and_get_response())\r
+                       return false;\r
+\r
+               rca = SD_R6_RCA(r);\r
+\r
+               /* get card specific data */\r
+\r
+               send_raw(SH_CMD_LONG_RESPONSE_SET | MMC_SEND_CSD, MMC_ARG_RCA(rca));\r
+               if (!wait_and_get_response())\r
+                       return false;\r
+\r
+               csd[0] = r[0];\r
+               csd[1] = r[1];\r
+               csd[2] = r[2];\r
+               csd[3] = r[3];\r
+\r
+               return true;\r
+       }\r
+\r
+       bool select_card() {\r
+               send(MMC_SELECT_CARD, MMC_ARG_RCA(rca));\r
+\r
+               if (!wait())\r
+                       return false;\r
+\r
+               return true;\r
+       }\r
+\r
+       bool init_card() {\r
+               char pnm[8];\r
+\r
+               send(MMC_GO_IDLE_STATE);\r
+\r
+               if (!query_voltage_and_type()) {\r
+                       logf("ERROR: Failed to query card voltage!\n");\r
+                       return false;\r
+               }\r
+\r
+               if (!identify_card()) {\r
+                       logf("ERROR: Failed to identify card!\n");\r
+                       return false;\r
+               }\r
+\r
+               SD_CID_PNM_CPY(cid, pnm);\r
+               logf("Product : %s\n", &pnm);\r
+               logf("MMC Ver : %d\n", SD_CSD_MMCVER(csd));\r
+\r
+               logf("MMC Size: %d\n", MMC_CSD_C_SIZE(csd));\r
+               logf("MMC Cap : %d\n", MMC_CSD_CAPACITY(csd));\r
+               \r
+               if (SD_CSD_CSDVER(csd) == SD_CSD_CSDVER_2_0) {\r
+                       logf("CSD     : version 2.0\n");\r
+                       logf("Capacity: %d\n", SD_CSD_V2_CAPACITY(csd));\r
+                       logf("Size    : %d\n", SD_CSD_V2_C_SIZE(csd));\r
+               }\r
+               else if (SD_CSD_CSDVER(csd) == SD_CSD_CSDVER_1_0) {\r
+                       logf("CSD     : version 1.0\n");\r
+                       logf("Capacity: %d\n", SD_CSD_CAPACITY(csd));\r
+                       logf("Size    : %d\n", SD_CSD_C_SIZE(csd));\r
+               }\r
+               else {\r
+                       logf("ERROR: unknown CSD version 0x%x!\n", SD_CSD_CSDVER(csd));\r
+                       return false;\r
+               }\r
+\r
+               if (!select_card()) {\r
+                       logf("ERROR: Failed to select card!\n");\r
+                       return false;\r
+               }\r
+\r
+               logf("setting block length to 512 ...\n");\r
+               send(MMC_SET_BLOCKLEN, 512);\r
+               if (!wait()) {\r
+                       logf("ERROR: Failed to set block length!\n");\r
+                       return false;\r
+               }\r
+\r
+               logf("card initialization complete!\n");\r
+\r
+               return true;\r
        }\r
 \r
        sdhost_t() {\r
+               is_sdhc = false;\r
+\r
                logf("starting up ...\n");\r
 \r
                configure_pinmux();\r
@@ -122,10 +303,34 @@ struct sdhost_t {
 \r
                udelay(300);\r
 \r
-               logf("sdhost controller ready!\n");\r
+               logf("sdhost controller ready, initializing SD card ...\n");\r
 \r
-               init_card();\r
+               if (init_card()) {\r
+                       \r
+               }\r
        }\r
 };\r
 \r
-sdhost_t STATIC_DRIVER g_SDHostDriver {};
\ No newline at end of file
+sdhost_t STATIC_DRIVER g_SDHostDriver {};\r
+\r
+/*\r
+ * abstractions for fatfs.\r
+ */\r
+\r
+#include "fatfs/diskio.h"\r
+\r
+DSTATUS disk_initialize (BYTE pdrv) {\r
+       return 0;\r
+}\r
+\r
+DSTATUS disk_status (BYTE pdrv) {\r
+       return 0;\r
+}\r
+\r
+DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {\r
+       return (DRESULT)0;\r
+}\r
+\r
+DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff) {\r
+       return (DRESULT)0;\r
+}
\ No newline at end of file
This page took 0.033582 seconds and 4 git commands to generate.