sd_card_sdio.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  1. /**
  2. * ZuluSCSI™ - Copyright (c) 2022-2025 Rabbit Hole Computing™
  3. * Copyright (c) 2024 Tech by Androda, LLC
  4. *
  5. * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
  6. *
  7. * https://www.gnu.org/licenses/gpl-3.0.html
  8. * ----
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version. 
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. * GNU General Public License for more details. 
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  21. **/
  22. // Driver for accessing SD card in SDIO mode on RP2040 and RP23XX.
  23. #include "ZuluSCSI_platform.h"
  24. #ifdef SD_USE_SDIO
  25. #include "ZuluSCSI_log.h"
  26. #include "sdio.h"
  27. #include "timings_RP2MCU.h"
  28. #include <hardware/gpio.h>
  29. #include <SdFat.h>
  30. #include <SdCard/SdCardInfo.h>
  31. static uint32_t g_sdio_ocr; // Operating condition register from card
  32. static uint32_t g_sdio_rca; // Relative card address
  33. static cid_t g_sdio_cid;
  34. static csd_t g_sdio_csd;
  35. static sds_t __attribute__((aligned(4))) g_sdio_sds;
  36. static int g_sdio_error_line;
  37. static sdio_status_t g_sdio_error;
  38. static uint32_t g_sdio_dma_buf[128];
  39. static uint32_t g_sdio_sector_count;
  40. #define checkReturnOk(call) ((g_sdio_error = (call)) == SDIO_OK ? true : logSDError(__LINE__))
  41. static bool logSDError(int line)
  42. {
  43. g_sdio_error_line = line;
  44. dbgmsg("SDIO SD card error on line ", line, ", error code ", (int)g_sdio_error);
  45. return false;
  46. }
  47. // Callback used by SCSI code for simultaneous processing
  48. static sd_callback_t m_stream_callback;
  49. static const uint8_t *m_stream_buffer;
  50. static uint32_t m_stream_count;
  51. static uint32_t m_stream_count_start;
  52. void platform_set_sd_callback(sd_callback_t func, const uint8_t *buffer)
  53. {
  54. m_stream_callback = func;
  55. m_stream_buffer = buffer;
  56. m_stream_count = 0;
  57. m_stream_count_start = 0;
  58. }
  59. static sd_callback_t get_stream_callback(const uint8_t *buf, uint32_t count, const char *accesstype, uint32_t sector)
  60. {
  61. m_stream_count_start = m_stream_count;
  62. if (m_stream_callback)
  63. {
  64. if (buf == m_stream_buffer + m_stream_count)
  65. {
  66. m_stream_count += count;
  67. return m_stream_callback;
  68. }
  69. else
  70. {
  71. dbgmsg("SD card ", accesstype, "(", (int)sector,
  72. ") slow transfer, buffer", (uint32_t)buf, " vs. ", (uint32_t)(m_stream_buffer + m_stream_count));
  73. return NULL;
  74. }
  75. }
  76. return NULL;
  77. }
  78. bool SdioCard::begin(SdioConfig sdioConfig)
  79. {
  80. uint32_t reply;
  81. sdio_status_t status;
  82. // Initialize at 1 MHz clock speed
  83. rp2040_sdio_init(g_zuluscsi_timings->sdio.clk_div_1mhz);
  84. // Establish initial connection with the card
  85. for (int retries = 0; retries < 5; retries++)
  86. {
  87. // After a hard fault crash, delayMicroseconds hangs
  88. // using busy_wait_us_32 instead
  89. // delayMicroseconds(1000);
  90. busy_wait_us_32(1000);
  91. reply = 0;
  92. rp2040_sdio_command_R1(CMD0, 0, NULL); // GO_IDLE_STATE
  93. status = rp2040_sdio_command_R1(CMD8, 0x1AA, &reply); // SEND_IF_COND
  94. if (status == SDIO_OK && reply == 0x1AA)
  95. {
  96. break;
  97. }
  98. }
  99. if (reply != 0x1AA || status != SDIO_OK)
  100. {
  101. // dbgmsg("SDIO not responding to CMD8 SEND_IF_COND, status ", (int)status, " reply ", reply);
  102. return false;
  103. }
  104. // Send ACMD41 to begin card initialization and wait for it to complete
  105. uint32_t start = millis();
  106. do {
  107. if (!checkReturnOk(rp2040_sdio_command_R1(CMD55, 0, &reply)) || // APP_CMD
  108. !checkReturnOk(rp2040_sdio_command_R3(ACMD41, 0xD0040000, &g_sdio_ocr))) // 3.0V voltage
  109. // !checkReturnOk(rp2040_sdio_command_R1(ACMD41, 0xC0100000, &g_sdio_ocr)))
  110. {
  111. return false;
  112. }
  113. if ((uint32_t)(millis() - start) > 1000)
  114. {
  115. logmsg("SDIO card initialization timeout");
  116. return false;
  117. }
  118. } while (!(g_sdio_ocr & (1 << 31)));
  119. // Get CID
  120. if (!checkReturnOk(rp2040_sdio_command_R2(CMD2, 0, (uint8_t*)&g_sdio_cid)))
  121. {
  122. dbgmsg("SDIO failed to read CID");
  123. return false;
  124. }
  125. // Get relative card address
  126. if (!checkReturnOk(rp2040_sdio_command_R1(CMD3, 0, &g_sdio_rca)))
  127. {
  128. dbgmsg("SDIO failed to get RCA");
  129. return false;
  130. }
  131. // Get CSD
  132. if (!checkReturnOk(rp2040_sdio_command_R2(CMD9, g_sdio_rca, (uint8_t*)&g_sdio_csd)))
  133. {
  134. dbgmsg("SDIO failed to read CSD");
  135. return false;
  136. }
  137. g_sdio_sector_count = sectorCount();
  138. // Select card
  139. if (!checkReturnOk(rp2040_sdio_command_R1(CMD7, g_sdio_rca, &reply)))
  140. {
  141. dbgmsg("SDIO failed to select card");
  142. return false;
  143. }
  144. // Set 4-bit bus mode
  145. if (!checkReturnOk(rp2040_sdio_command_R1(CMD55, g_sdio_rca, &reply)) ||
  146. !checkReturnOk(rp2040_sdio_command_R1(ACMD6, 2, &reply)))
  147. {
  148. dbgmsg("SDIO failed to set bus width");
  149. return false;
  150. }
  151. // Read SD Status field
  152. memset(&g_sdio_sds, 0, sizeof(sds_t));
  153. uint8_t* stat_pointer = (uint8_t*) &g_sdio_sds;
  154. if (!checkReturnOk(rp2040_sdio_command_R1(CMD55, g_sdio_rca, &reply)) ||
  155. !checkReturnOk(rp2040_sdio_command_R1(ACMD13, 0, &reply)) ||
  156. !checkReturnOk(receive_status_register(stat_pointer)))
  157. {
  158. dbgmsg("SDIO failed to get SD Status");
  159. return false;
  160. }
  161. // Increase to 25 MHz clock rate
  162. rp2040_sdio_init(1);
  163. return true;
  164. }
  165. uint8_t SdioCard::errorCode() const
  166. {
  167. return g_sdio_error;
  168. }
  169. uint32_t SdioCard::errorData() const
  170. {
  171. return 0;
  172. }
  173. uint32_t SdioCard::errorLine() const
  174. {
  175. return g_sdio_error_line;
  176. }
  177. bool SdioCard::isBusy()
  178. {
  179. #if SDIO_D0 > 31
  180. return 0 == (sio_hw->gpio_hi_in & (1 << (SDIO_D0 - 32)));
  181. #else
  182. return 0 == (sio_hw->gpio_in & (1 << SDIO_D0));
  183. #endif
  184. }
  185. uint32_t SdioCard::kHzSdClk()
  186. {
  187. return 0;
  188. }
  189. bool SdioCard::readCID(cid_t* cid)
  190. {
  191. *cid = g_sdio_cid;
  192. return true;
  193. }
  194. bool SdioCard::readCSD(csd_t* csd)
  195. {
  196. *csd = g_sdio_csd;
  197. return true;
  198. }
  199. bool SdioCard::readSDS(sds_t* sds)
  200. {
  201. *sds = g_sdio_sds;
  202. return true;
  203. }
  204. bool SdioCard::readOCR(uint32_t* ocr)
  205. {
  206. // SDIO mode does not have CMD58, but main program uses this to
  207. // poll for card presence. Return status register instead.
  208. return checkReturnOk(rp2040_sdio_command_R1(CMD13, g_sdio_rca, ocr));
  209. }
  210. bool SdioCard::readData(uint8_t* dst)
  211. {
  212. logmsg("SdioCard::readData() called but not implemented!");
  213. return false;
  214. }
  215. bool SdioCard::readStart(uint32_t sector)
  216. {
  217. logmsg("SdioCard::readStart() called but not implemented!");
  218. return false;
  219. }
  220. bool SdioCard::readStop()
  221. {
  222. logmsg("SdioCard::readStop() called but not implemented!");
  223. return false;
  224. }
  225. uint32_t SdioCard::sectorCount()
  226. {
  227. return g_sdio_csd.capacity();
  228. }
  229. uint32_t SdioCard::status()
  230. {
  231. uint32_t reply;
  232. if (checkReturnOk(rp2040_sdio_command_R1(CMD13, g_sdio_rca, &reply)))
  233. return reply;
  234. else
  235. return 0;
  236. }
  237. bool SdioCard::stopTransmission(bool blocking)
  238. {
  239. uint32_t reply;
  240. if (!checkReturnOk(rp2040_sdio_command_R1(CMD12, 0, &reply)))
  241. {
  242. return false;
  243. }
  244. if (!blocking)
  245. {
  246. return true;
  247. }
  248. else
  249. {
  250. uint32_t start = millis();
  251. while ((uint32_t)(millis() - start) < 5000 && isBusy())
  252. {
  253. if (m_stream_callback)
  254. {
  255. m_stream_callback(m_stream_count);
  256. }
  257. }
  258. if (isBusy())
  259. {
  260. logmsg("SdioCard::stopTransmission() timeout");
  261. return false;
  262. }
  263. else
  264. {
  265. return true;
  266. }
  267. }
  268. }
  269. bool SdioCard::syncDevice()
  270. {
  271. return true;
  272. }
  273. uint8_t SdioCard::type() const
  274. {
  275. if (g_sdio_ocr & (1 << 30))
  276. return SD_CARD_TYPE_SDHC;
  277. else
  278. return SD_CARD_TYPE_SD2;
  279. }
  280. bool SdioCard::writeData(const uint8_t* src)
  281. {
  282. logmsg("SdioCard::writeData() called but not implemented!");
  283. return false;
  284. }
  285. bool SdioCard::writeStart(uint32_t sector)
  286. {
  287. logmsg("SdioCard::writeStart() called but not implemented!");
  288. return false;
  289. }
  290. bool SdioCard::writeStop()
  291. {
  292. logmsg("SdioCard::writeStop() called but not implemented!");
  293. return false;
  294. }
  295. bool SdioCard::erase(uint32_t firstSector, uint32_t lastSector)
  296. {
  297. logmsg("SdioCard::erase() not implemented");
  298. return false;
  299. }
  300. bool SdioCard::cardCMD6(uint32_t arg, uint8_t* status) {
  301. logmsg("SdioCard::cardCMD6() not implemented");
  302. return false;
  303. }
  304. bool SdioCard::readSCR(scr_t* scr) {
  305. logmsg("SdioCard::readSCR() not implemented");
  306. return false;
  307. }
  308. /* Writing and reading, with progress callback */
  309. bool SdioCard::writeSector(uint32_t sector, const uint8_t* src)
  310. {
  311. if (((uint32_t)src & 3) != 0)
  312. {
  313. // Buffer is not aligned, need to memcpy() the data to a temporary buffer.
  314. memcpy(g_sdio_dma_buf, src, sizeof(g_sdio_dma_buf));
  315. src = (uint8_t*)g_sdio_dma_buf;
  316. }
  317. // If possible, report transfer status to application through callback.
  318. sd_callback_t callback = get_stream_callback(src, 512, "writeSector", sector);
  319. // Cards up to 2GB use byte addressing, SDHC cards use sector addressing
  320. uint32_t address = (type() == SD_CARD_TYPE_SDHC) ? sector : (sector * 512);
  321. uint32_t reply;
  322. if (!checkReturnOk(rp2040_sdio_command_R1(16, 512, &reply)) || // SET_BLOCKLEN
  323. !checkReturnOk(rp2040_sdio_command_R1(CMD24, address, &reply)) || // WRITE_BLOCK
  324. !checkReturnOk(rp2040_sdio_tx_start(src, 1))) // Start transmission
  325. {
  326. return false;
  327. }
  328. do {
  329. uint32_t bytes_done;
  330. g_sdio_error = rp2040_sdio_tx_poll(&bytes_done);
  331. if (callback)
  332. {
  333. callback(m_stream_count_start + bytes_done);
  334. }
  335. } while (g_sdio_error == SDIO_BUSY);
  336. if (g_sdio_error != SDIO_OK)
  337. {
  338. logmsg("SdioCard::writeSector(", sector, ") failed: ", (int)g_sdio_error);
  339. }
  340. return g_sdio_error == SDIO_OK;
  341. }
  342. bool SdioCard::writeSectors(uint32_t sector, const uint8_t* src, size_t n)
  343. {
  344. if (((uint32_t)src & 3) != 0)
  345. {
  346. // Unaligned write, execute sector-by-sector
  347. for (size_t i = 0; i < n; i++)
  348. {
  349. if (!writeSector(sector + i, src + 512 * i))
  350. {
  351. return false;
  352. }
  353. }
  354. return true;
  355. }
  356. sd_callback_t callback = get_stream_callback(src, n * 512, "writeSectors", sector);
  357. // Cards up to 2GB use byte addressing, SDHC cards use sector addressing
  358. uint32_t address = (type() == SD_CARD_TYPE_SDHC) ? sector : (sector * 512);
  359. uint32_t reply;
  360. if (!checkReturnOk(rp2040_sdio_command_R1(16, 512, &reply)) || // SET_BLOCKLEN
  361. !checkReturnOk(rp2040_sdio_command_R1(CMD55, g_sdio_rca, &reply)) || // APP_CMD
  362. !checkReturnOk(rp2040_sdio_command_R1(ACMD23, n, &reply)) || // SET_WR_CLK_ERASE_COUNT
  363. !checkReturnOk(rp2040_sdio_command_R1(CMD25, address, &reply)) || // WRITE_MULTIPLE_BLOCK
  364. !checkReturnOk(rp2040_sdio_tx_start(src, n))) // Start transmission
  365. {
  366. return false;
  367. }
  368. do {
  369. uint32_t bytes_done;
  370. g_sdio_error = rp2040_sdio_tx_poll(&bytes_done);
  371. if (callback)
  372. {
  373. callback(m_stream_count_start + bytes_done);
  374. }
  375. } while (g_sdio_error == SDIO_BUSY);
  376. if (g_sdio_error != SDIO_OK)
  377. {
  378. logmsg("SdioCard::writeSectors(", sector, ",...,", (int)n, ") failed: ", (int)g_sdio_error);
  379. stopTransmission(true);
  380. return false;
  381. }
  382. else
  383. {
  384. // TODO: Instead of CMD12 stopTransmission command, according to SD spec we should send stopTran token.
  385. // stopTransmission seems to work in practice.
  386. return stopTransmission(true);
  387. }
  388. }
  389. bool SdioCard::readSector(uint32_t sector, uint8_t* dst)
  390. {
  391. uint8_t *real_dst = dst;
  392. if (((uint32_t)dst & 3) != 0)
  393. {
  394. // Buffer is not aligned, need to memcpy() the data from a temporary buffer.
  395. dst = (uint8_t*)g_sdio_dma_buf;
  396. }
  397. sd_callback_t callback = get_stream_callback(dst, 512, "readSector", sector);
  398. // Cards up to 2GB use byte addressing, SDHC cards use sector addressing
  399. uint32_t address = (type() == SD_CARD_TYPE_SDHC) ? sector : (sector * 512);
  400. uint32_t reply;
  401. if (!checkReturnOk(rp2040_sdio_command_R1(16, 512, &reply)) || // SET_BLOCKLEN
  402. !checkReturnOk(rp2040_sdio_rx_start(dst, 1)) || // Prepare for reception
  403. !checkReturnOk(rp2040_sdio_command_R1(CMD17, address, &reply))) // READ_SINGLE_BLOCK
  404. {
  405. return false;
  406. }
  407. do {
  408. uint32_t bytes_done;
  409. g_sdio_error = rp2040_sdio_rx_poll(&bytes_done);
  410. if (callback)
  411. {
  412. callback(m_stream_count_start + bytes_done);
  413. }
  414. } while (g_sdio_error == SDIO_BUSY);
  415. if (g_sdio_error != SDIO_OK)
  416. {
  417. logmsg("SdioCard::readSector(", sector, ") failed: ", (int)g_sdio_error);
  418. }
  419. if (dst != real_dst)
  420. {
  421. memcpy(real_dst, g_sdio_dma_buf, sizeof(g_sdio_dma_buf));
  422. }
  423. return g_sdio_error == SDIO_OK;
  424. }
  425. bool SdioCard::readSectors(uint32_t sector, uint8_t* dst, size_t n)
  426. {
  427. if (((uint32_t)dst & 3) != 0 || sector + n >= g_sdio_sector_count)
  428. {
  429. // Unaligned read or end-of-drive read, execute sector-by-sector
  430. for (size_t i = 0; i < n; i++)
  431. {
  432. if (!readSector(sector + i, dst + 512 * i))
  433. {
  434. return false;
  435. }
  436. }
  437. return true;
  438. }
  439. sd_callback_t callback = get_stream_callback(dst, n * 512, "readSectors", sector);
  440. // Cards up to 2GB use byte addressing, SDHC cards use sector addressing
  441. uint32_t address = (type() == SD_CARD_TYPE_SDHC) ? sector : (sector * 512);
  442. uint32_t reply;
  443. if (!checkReturnOk(rp2040_sdio_command_R1(16, 512, &reply)) || // SET_BLOCKLEN
  444. !checkReturnOk(rp2040_sdio_rx_start(dst, n)) || // Prepare for reception
  445. !checkReturnOk(rp2040_sdio_command_R1(CMD18, address, &reply))) // READ_MULTIPLE_BLOCK
  446. {
  447. return false;
  448. }
  449. do {
  450. uint32_t bytes_done;
  451. g_sdio_error = rp2040_sdio_rx_poll(&bytes_done);
  452. if (callback)
  453. {
  454. callback(m_stream_count_start + bytes_done);
  455. }
  456. } while (g_sdio_error == SDIO_BUSY);
  457. if (g_sdio_error != SDIO_OK)
  458. {
  459. logmsg("SdioCard::readSectors(", sector, ",...,", (int)n, ") failed: ", (int)g_sdio_error);
  460. stopTransmission(true);
  461. return false;
  462. }
  463. else
  464. {
  465. return stopTransmission(true);
  466. }
  467. }
  468. // These functions are not used for SDIO mode but are needed to avoid build error.
  469. void sdCsInit(SdCsPin_t pin) {}
  470. void sdCsWrite(SdCsPin_t pin, bool level) {}
  471. // SDIO configuration for main program
  472. SdioConfig g_sd_sdio_config(DMA_SDIO);
  473. #endif