hpm_sdmmc_sdio.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. /*
  2. * Copyright (c) 2024 HPMicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. */
  7. #include "hpm_sdmmc_common.h"
  8. #include "hpm_sdmmc_sdio.h"
  9. #include "hpm_l1c_drv.h"
  10. static hpm_stat_t sdio_send_if_cond(sdio_card_t *card);
  11. static hpm_stat_t sdio_io_send_op_if_cond(sdio_card_t *card, uint32_t arg);
  12. static hpm_stat_t sdio_send_rca(sdio_card_t *card);
  13. static hpm_stat_t sdio_probe_sdio_card(sdio_card_t *card);
  14. static hpm_stat_t sdio_read_cccr(sdio_card_t *card);
  15. static hpm_stat_t sdio_set_timing(sdio_card_t *card);
  16. static hpm_stat_t sdio_set_bus_width(sdio_card_t *card);
  17. static void sdio_switch_to_1v8(sdio_card_t *card);
  18. static hpm_stat_t sdio_send_command(sdio_card_t *card, sdmmchost_cmd_t *cmd);
  19. static hpm_stat_t sdio_transfer(sdio_card_t *card, sdmmchost_xfer_t *xfer);
  20. static hpm_stat_t sdio_error_recovery(sdio_card_t *card);
  21. static hpm_stat_t sdio_error_recovery(sdio_card_t *card)
  22. {
  23. uint32_t cmd_arg = card->host->cmd.cmd_argument;
  24. uint32_t cmd_index = card->host->cmd.cmd_index;
  25. sdxc_command_t *cmd;
  26. if (cmd_index == sdio_cmd_io_rw_direct) {
  27. /* Abort function transfer */
  28. const sdio_cmd52_arg_t *cmd52_arg = (const sdio_cmd52_arg_t *) &cmd_arg;
  29. cmd = &card->host->cmd;
  30. cmd->cmd_index = sdio_cmd_io_rw_direct;
  31. sdio_cmd52_arg_t *abort_arg = (sdio_cmd52_arg_t *) &cmd->cmd_argument;
  32. abort_arg->func_num = 0;
  33. abort_arg->reg_addr = 6;
  34. abort_arg->wr_data = cmd52_arg->func_num;
  35. abort_arg->write = 1;
  36. cmd->cmd_type = sdxc_cmd_type_abort_cmd;
  37. } else if (cmd_index == sdio_cmd_io_rw_extend) {
  38. /* Abort function transfer */
  39. const sdio_cmd53_arg_t *cmd53_arg = (const sdio_cmd53_arg_t *) &cmd_arg;
  40. cmd = &card->host->cmd;
  41. cmd->cmd_index = sdio_cmd_io_rw_direct;
  42. sdio_cmd52_arg_t *abort_arg = (sdio_cmd52_arg_t *) &cmd->cmd_argument;
  43. abort_arg->func_num = 0;
  44. abort_arg->reg_addr = 6;
  45. abort_arg->wr_data = cmd53_arg->func_num;
  46. abort_arg->write = 1;
  47. cmd->cmd_type = sdxc_cmd_type_abort_cmd;
  48. } else {
  49. cmd = NULL;
  50. }
  51. return sdmmchost_error_recovery(card->host, cmd);
  52. }
  53. static hpm_stat_t sdio_send_command(sdio_card_t *card, sdmmchost_cmd_t *cmd)
  54. {
  55. hpm_stat_t status = sdmmchost_send_command(card->host, cmd);
  56. if (status != status_success) {
  57. hpm_stat_t recover_status = sdio_error_recovery(card);
  58. if (recover_status != status_success) {
  59. status = recover_status;
  60. }
  61. }
  62. return status;
  63. }
  64. static hpm_stat_t sdio_transfer(sdio_card_t *card, sdmmchost_xfer_t *xfer)
  65. {
  66. hpm_stat_t status = sdmmchost_transfer(card->host, xfer);
  67. if (status != status_success) {
  68. hpm_stat_t recover_status = sdio_error_recovery(card);
  69. if (recover_status != status_success) {
  70. status = recover_status;
  71. }
  72. }
  73. return status;
  74. }
  75. static hpm_stat_t sdio_send_if_cond(sdio_card_t *card)
  76. {
  77. sdmmc_host_t *host = card->host;
  78. sdmmchost_cmd_t *cmd = &host->cmd;
  79. (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
  80. cmd->cmd_index = sd_cmd_send_if_cond;
  81. cmd->cmd_argument = 0x1aa;
  82. cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r7;
  83. hpm_stat_t status = sdio_send_command(card, cmd);
  84. if (status != status_success) {
  85. return status;
  86. }
  87. if ((cmd->response[0] & 0xFFU) != 0xAAU) {
  88. return status_sdmmc_card_not_support;
  89. }
  90. return status_success;
  91. }
  92. static hpm_stat_t sdio_io_send_op_if_cond(sdio_card_t *card, uint32_t arg)
  93. {
  94. sdmmc_host_t *host = card->host;
  95. sdmmchost_cmd_t *cmd = &host->cmd;
  96. (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
  97. /* Probe the presence of SDIO */
  98. cmd->cmd_index = sdio_cmd_io_send_op_cond;
  99. cmd->cmd_argument = arg;
  100. cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r4;
  101. hpm_stat_t status = sdio_send_command(card, cmd);
  102. if (status != status_success) {
  103. return status;
  104. }
  105. return status_success;
  106. }
  107. static hpm_stat_t sdio_send_rca(sdio_card_t *card)
  108. {
  109. sdmmc_host_t *host = card->host;
  110. sdmmchost_cmd_t *cmd = &host->cmd;
  111. (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
  112. cmd->cmd_index = sd_cmd_send_relative_addr;
  113. cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r6;
  114. hpm_stat_t status = sdio_send_command(card, cmd);
  115. if (status != status_success) {
  116. return status;
  117. }
  118. card->relative_addr = cmd->response[0] >> 16;
  119. return status;
  120. }
  121. static void sdio_switch_to_1v8(sdio_card_t *card)
  122. {
  123. sdmmc_host_t *host = card->host;
  124. /* 1. Stop providing clock to the card */
  125. sdxc_enable_inverse_clock(host->host_param.base, false);
  126. sdxc_enable_sd_clock(host->host_param.base, false);
  127. /* 2. Switch signaling to 1.8v */
  128. sdmmchost_vsel_pin_control(host, hpm_sdmmc_io_voltage_1v8);
  129. sdmmchost_select_voltage(host, hpm_sdmmc_io_voltage_1v8);
  130. /* 3. Provide SD clock the card again */
  131. sdxc_enable_inverse_clock(host->host_param.base, true);
  132. sdxc_enable_sd_clock(host->host_param.base, true);
  133. /* 4. wait 1ms */
  134. sdmmchost_delay_ms(host, 1);
  135. }
  136. static hpm_stat_t sdio_probe_sdio_card(sdio_card_t *card)
  137. {
  138. sdmmc_host_t *host = card->host;
  139. sdmmchost_cmd_t *cmd = &card->host->cmd;
  140. hpm_stat_t status = sdmmc_go_idle_state(card->host, 0);
  141. if (status != status_success) {
  142. return status;
  143. }
  144. /* Probe with CMD8 first */
  145. status = sdio_send_if_cond(card);
  146. if ((status != status_sdxc_cmd_timeout_error) && (status != status_sdxc_non_recoverable_error) && (
  147. status != status_success)) {
  148. return status;
  149. }
  150. /* Probe with CMD */
  151. sdio_cmd5_resp_t cmd5_resp;
  152. status = sdio_io_send_op_if_cond(card, 0);
  153. if (status != status_success) {
  154. return status;
  155. }
  156. cmd5_resp.value = cmd->response[0];
  157. uint32_t cmd5_arg = (0x3FUL << 18); /* Voltage 3.0 - 3.6 */
  158. bool switch_voltage = false;
  159. if (sdmmchost_is_voltage_switch_supported(host) && card->operation_voltage == sdmmc_operation_voltage_3v3) {
  160. cmd5_arg |= (1UL << 24); /* S18R */
  161. switch_voltage = true;
  162. }
  163. do {
  164. sdmmchost_delay_ms(host, 1);
  165. status = sdio_io_send_op_if_cond(card, cmd5_arg);
  166. if (status != status_success) {
  167. return status;
  168. }
  169. cmd5_resp.value = cmd->response[0];
  170. } while (!cmd5_resp.ready);
  171. card->num_of_functions = cmd5_resp.num_func;
  172. if (switch_voltage && (cmd5_resp.s18r == 1)) {
  173. sdio_switch_to_1v8(card);
  174. card->operation_voltage = sdmmc_operation_voltage_1v8;
  175. }
  176. return status;
  177. }
  178. static hpm_stat_t sdio_read_cccr(sdio_card_t *card)
  179. {
  180. hpm_stat_t status;
  181. sdmmc_host_t *host = card->host;
  182. sdmmchost_cmd_t *cmd = &host->cmd;
  183. (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
  184. uint8_t *pdata = (uint8_t *) &card->cccr;
  185. for (uint32_t reg = SDIO_REG_CCCR_START; reg <= SDIO_REG_CCCR_END; reg++) {
  186. status = sdio_io_read_byte(card, 0, reg, pdata);
  187. if (status != status_success) {
  188. break;
  189. }
  190. ++pdata;
  191. }
  192. return status;
  193. }
  194. hpm_stat_t sdio_read_cis(sdio_card_t *card, uint32_t cis_ptr, sdio_cis_t *cis, bool keep_tpl_raw_data)
  195. {
  196. hpm_stat_t status = status_invalid_argument;
  197. uint8_t tpl_code;
  198. uint8_t tpl_link;
  199. struct sdio_tpl_block *tpl_blk = NULL;
  200. struct sdio_tpl_block *current_tpl = NULL;
  201. do {
  202. HPM_BREAK_IF((card == NULL) || (card->host == NULL) || (cis == NULL));
  203. do {
  204. uint8_t tmp_buf[256] = { 0 };
  205. status = sdio_io_read_byte(card, 0, cis_ptr++, &tpl_code);
  206. HPM_BREAK_IF(status != status_success);
  207. status = sdio_io_read_byte(card, 0, cis_ptr++, &tpl_link);
  208. HPM_BREAK_IF(status != status_success);
  209. if ((tpl_code == CISTPL_END) || (tpl_link == 0xFF)) {
  210. if (keep_tpl_raw_data && (tpl_blk != NULL)) {
  211. tpl_blk->next = NULL;
  212. }
  213. break;
  214. }
  215. if (tpl_code == CISTPL_NULL) {
  216. continue;
  217. }
  218. uint8_t *pdata = tmp_buf;
  219. for (uint32_t i = 0; i < tpl_link; i++) {
  220. status = sdio_io_read_byte(card, 0, cis_ptr++, pdata++);
  221. if (status != status_success) {
  222. return status;
  223. }
  224. }
  225. if (keep_tpl_raw_data) {
  226. tpl_blk = (struct sdio_tpl_block *) HPM_SDMMC_MALLOC(sizeof(struct sdio_tpl_block));
  227. if (tpl_blk == NULL) {
  228. status = status_fail;
  229. break;
  230. }
  231. tpl_blk->tpl_code = tpl_code;
  232. tpl_blk->tpl_size = tpl_link;
  233. if (tpl_link > 0) {
  234. tpl_blk->tpl_data = (uint8_t *) HPM_SDMMC_MALLOC(tpl_link);
  235. if (tpl_blk->tpl_data == NULL) {
  236. HPM_SDMMC_FREE(tpl_blk);
  237. status = status_fail;
  238. break;
  239. }
  240. (void) memcpy(tpl_blk->tpl_data, tmp_buf, tpl_link);
  241. }
  242. if (current_tpl == NULL) {
  243. cis->tpl_link = tpl_blk;
  244. current_tpl = cis->tpl_link;
  245. } else {
  246. current_tpl->next = tpl_blk;
  247. current_tpl = current_tpl->next;
  248. }
  249. }
  250. const uint8_t *tpl_data_buf = tmp_buf;
  251. sdio_cis_t *p_cis = cis;
  252. switch (tpl_code) {
  253. case CISTPL_MANFID:
  254. if (tpl_link < 4) {
  255. return status_invalid_argument;
  256. }
  257. p_cis->manufacturer = (((uint16_t) tpl_data_buf[1]) << 8) | tpl_data_buf[0];
  258. p_cis->product = (((uint16_t) tpl_data_buf[3]) << 8) | tpl_data_buf[2];
  259. break;
  260. case CISTPL_FUNCE:
  261. if (tpl_data_buf[0] == 0x00) {
  262. p_cis->func0_blk_size = (((uint16_t) tpl_data_buf[2]) << 8) | tpl_data_buf[1];
  263. p_cis->max_tran_speed = tpl_data_buf[3];
  264. } else if (tpl_data_buf[0] == 0x01) {
  265. sdio_func_funce_t *pfunce = (sdio_func_funce_t *) &tpl_data_buf[1];
  266. p_cis->std_io_rev = pfunce->std_io_rev;
  267. p_cis->support_wakeup = pfunce->support_wakeup;
  268. p_cis->max_blk_size = pfunce->max_blk_size;
  269. p_cis->csa_size = pfunce->csa_size;
  270. p_cis->serial_num = pfunce->psn;
  271. p_cis->timeout_val_in_10ms = pfunce->enable_timeout_val;
  272. p_cis->csa_wp = pfunce->csa_wp;
  273. p_cis->csa_nf = pfunce->csa_nf;
  274. p_cis->ocr = pfunce->ocr;
  275. } else {
  276. /* Skip data */
  277. }
  278. break;
  279. case CISTPL_FUNCID:
  280. /* Skip */
  281. break;
  282. case CISTPL_SDIO_STD:
  283. p_cis->std_id = tpl_data_buf[0];
  284. p_cis->std_type = tpl_data_buf[1];
  285. break;
  286. case CISTPL_SDIO_EXT:
  287. /* Skip */
  288. break;
  289. default:
  290. /* Skip */
  291. break;
  292. }
  293. } while (tpl_code != CISTPL_END);
  294. } while (false);
  295. return status;
  296. }
  297. hpm_stat_t sdio_read_fbr(sdio_card_t *card, uint32_t func_idx, sdio_fbr_t *fbr)
  298. {
  299. hpm_stat_t status = status_invalid_argument;
  300. do {
  301. HPM_BREAK_IF((card == NULL) || (card->host == NULL) || (fbr == NULL));
  302. uint32_t reg_addr = SDIO_FBR_REG_BASE(func_idx);
  303. uint8_t *pdata = (uint8_t *) fbr;
  304. for (uint32_t i = 0; i < sizeof(sdio_fbr_t); i++) {
  305. status = sdio_io_read_byte(card, 0, reg_addr++, pdata++);
  306. if (status != status_success) {
  307. return status;
  308. }
  309. }
  310. } while (false);
  311. return status;
  312. }
  313. hpm_stat_t sdio_io_rw_direct(sdio_card_t *card,
  314. bool write,
  315. uint32_t func_idx,
  316. uint32_t reg_addr,
  317. uint8_t *pdata,
  318. bool read_after_write)
  319. {
  320. hpm_stat_t status = status_invalid_argument;
  321. do {
  322. HPM_BREAK_IF(card == NULL);
  323. sdmmc_host_t *host = card->host;
  324. sdmmchost_cmd_t *cmd = &host->cmd;
  325. (void) memset(cmd, 0, sizeof(sdmmchost_cmd_t));
  326. sdio_cmd52_arg_t cmd52_arg = { .value = 0 };
  327. cmd52_arg.write = write ? 1UL : 0U;
  328. cmd52_arg.read_afer_write = read_after_write ? 1UL : 0U;
  329. cmd52_arg.func_num = func_idx;
  330. cmd52_arg.reg_addr = reg_addr;
  331. if (write) {
  332. cmd52_arg.wr_data = *pdata;
  333. }
  334. cmd->cmd_index = sdio_cmd_io_rw_direct;
  335. cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r5;
  336. cmd->cmd_argument = cmd52_arg.value;
  337. status = sdio_send_command(card, cmd);
  338. if (status != status_success) {
  339. break;
  340. }
  341. sdio_resp_r5_t cmd52_resp;
  342. cmd52_resp.value = cmd->response[0];
  343. if (!write || read_after_write) {
  344. *pdata = (uint8_t) cmd52_resp.rw_data;
  345. }
  346. } while (false);
  347. return status;
  348. }
  349. hpm_stat_t sdio_set_block_size(sdio_card_t *card, uint32_t func_idx, uint32_t block_size)
  350. {
  351. hpm_stat_t status = status_invalid_argument;
  352. do {
  353. if (card == NULL) {
  354. break;
  355. }
  356. if (block_size == 0) {
  357. block_size = MIN(SDMMC_BLOCK_SIZE_DEFAULT, block_size);
  358. }
  359. status = sdio_io_write_byte(card,
  360. 0,
  361. SDIO_FBR_REG_BASE(func_idx) + SDIO_REG_CCCR_FN0_BLK_SIZE,
  362. block_size & 0xFF);
  363. if (status != status_success) {
  364. break;
  365. }
  366. status = sdio_io_write_byte(card,
  367. 0,
  368. SDIO_FBR_REG_BASE(func_idx) + SDIO_REG_CCCR_FN0_BLK_SIZE + 1,
  369. (block_size >> 8) & 0xFF);
  370. if (status != status_success) {
  371. break;
  372. }
  373. card->sdio_func[func_idx]->current_block_size = block_size;
  374. } while (false);
  375. return status;
  376. }
  377. hpm_stat_t sdio_io_read_byte(sdio_card_t *card, uint32_t func_num, uint32_t reg, uint8_t *pdata)
  378. {
  379. return sdio_io_rw_direct(card, false, func_num, reg, pdata, false);
  380. }
  381. hpm_stat_t sdio_io_write_byte(sdio_card_t *card, uint32_t func_num, uint32_t reg, uint8_t byte_data)
  382. {
  383. return sdio_io_rw_direct(card, true, func_num, reg, &byte_data, false);
  384. }
  385. hpm_stat_t sdio_io_rw_extend(sdio_card_t *card,
  386. bool write,
  387. uint32_t func_idx,
  388. uint32_t reg_addr,
  389. uint32_t op_code,
  390. uint8_t *pbuf,
  391. uint32_t blocks,
  392. uint32_t block_size)
  393. {
  394. hpm_stat_t status = status_invalid_argument;
  395. do {
  396. HPM_BREAK_IF((card == NULL) || (card->host == NULL));
  397. if (!card->host->card_init_done) {
  398. status = status_sdmmc_device_init_required;
  399. break;
  400. }
  401. sdmmc_host_t *host = card->host;
  402. sdmmchost_cmd_t *cmd = &host->cmd;
  403. sdmmchost_data_t *data = &host->data;
  404. sdmmchost_xfer_t *content = &host->xfer;
  405. memset(cmd, 0, sizeof(*cmd));
  406. memset(data, 0, sizeof(*data));
  407. memset(content, 0, sizeof(*content));
  408. sdio_cmd53_arg_t cmd53_arg = { .value = 0 };
  409. cmd53_arg.rw_flag = write ? 1UL : 0;
  410. cmd53_arg.func_num = func_idx;
  411. cmd53_arg.reg_addr = reg_addr;
  412. cmd53_arg.block_mode = 0;
  413. cmd53_arg.op_code = op_code;
  414. if ((blocks == 1) && (block_size <= 512)) {
  415. cmd53_arg.count = (block_size == 512) ? 0 : block_size;
  416. } else {
  417. cmd53_arg.count = blocks;
  418. cmd53_arg.block_mode = 1;
  419. }
  420. cmd->cmd_index = sdio_cmd_io_rw_extend;
  421. cmd->cmd_argument = cmd53_arg.value;
  422. cmd->cmd_timeout_ms = SDIO_CMD_TIMEOUT_MS;
  423. cmd->resp_type = (sdxc_dev_resp_type_t) sdmmc_resp_r5;
  424. data->block_size = block_size;
  425. data->block_cnt = blocks;
  426. if (write) {
  427. data->tx_data = (uint32_t *) sdmmc_get_sys_addr(host, (uint32_t)pbuf);
  428. } else {
  429. data->rx_data = (uint32_t *) sdmmc_get_sys_addr(host, (uint32_t)pbuf);
  430. }
  431. content->data = data;
  432. content->command = cmd;
  433. #if !defined(HPM_SDMMC_ENABLE_CACHE_MAINTENANCE) || (HPM_SDMMC_ENABLE_CACHE_MAINTENANCE == 1)
  434. uint32_t buf_start = write ? (uint32_t) data->tx_data : (uint32_t) data->rx_data;
  435. uint32_t buf_size = blocks * block_size;
  436. uint32_t end_addr = buf_start + buf_size;
  437. uint32_t aligned_start = HPM_L1C_CACHELINE_ALIGN_DOWN(buf_start);
  438. uint32_t aligned_end = HPM_L1C_CACHELINE_ALIGN_UP(end_addr);
  439. uint32_t aligned_size = aligned_end - aligned_start;
  440. if (write) {
  441. l1c_dc_writeback(aligned_start, aligned_size);
  442. } else {
  443. /* FLUSH un-cacheline aligned memory region */
  444. if ((buf_start % HPM_L1C_CACHELINE_SIZE) != 0) {
  445. l1c_dc_writeback(aligned_start, HPM_L1C_CACHELINE_SIZE);
  446. }
  447. if ((end_addr % HPM_L1C_CACHELINE_SIZE) != 0) {
  448. uint32_t aligned_tail = HPM_L1C_CACHELINE_ALIGN_DOWN(end_addr);
  449. l1c_dc_writeback(aligned_tail, HPM_L1C_CACHELINE_SIZE);
  450. }
  451. }
  452. #endif
  453. status = sdio_transfer(card, content);
  454. HPM_BREAK_IF(status != status_success);
  455. #if !defined(HPM_SDMMC_ENABLE_CACHE_MAINTENANCE) || (HPM_SDMMC_ENABLE_CACHE_MAINTENANCE == 1)
  456. if (!write) {
  457. l1c_dc_invalidate(aligned_start, aligned_size);
  458. }
  459. #endif
  460. } while (false);
  461. return status;
  462. }
  463. hpm_stat_t sdio_io_write_multi_bytes_to_fifo(sdio_card_t *card,
  464. uint32_t func_idx,
  465. uint32_t reg_addr,
  466. uint8_t *pbuf,
  467. uint32_t length)
  468. {
  469. if ((card == NULL) || (card->host == NULL) || (length < 1U)) {
  470. return status_invalid_argument;
  471. }
  472. uint32_t block_size = MIN(card->sdio_func[func_idx]->current_block_size, length);
  473. uint32_t num_blocks = (length + block_size - 1U) / block_size;
  474. return sdio_io_rw_extend(card,
  475. true,
  476. func_idx,
  477. reg_addr,
  478. SDIO_CMD53_OP_MODE_FIXED_ADDR,
  479. pbuf,
  480. num_blocks,
  481. block_size);
  482. }
  483. hpm_stat_t sdio_io_read_multi_bytes_from_fifo(sdio_card_t *card,
  484. uint32_t func_idx,
  485. uint32_t reg_addr,
  486. uint8_t *pbuf,
  487. uint32_t length)
  488. {
  489. if ((card == NULL) || (card->host == NULL) || (length < 1U)) {
  490. return status_invalid_argument;
  491. }
  492. uint32_t block_size = MIN(card->sdio_func[func_idx]->current_block_size, length);
  493. uint32_t num_blocks = (length + block_size - 1U) / block_size;
  494. return sdio_io_rw_extend(card,
  495. false,
  496. func_idx,
  497. reg_addr,
  498. SDIO_CMD53_OP_MODE_FIXED_ADDR,
  499. pbuf,
  500. num_blocks,
  501. block_size);
  502. }
  503. hpm_stat_t sdio_io_write_incr_multi_bytes(sdio_card_t *card,
  504. uint32_t func_idx,
  505. uint32_t reg_addr,
  506. uint8_t *pbuf,
  507. uint32_t length)
  508. {
  509. if ((card == NULL) || (card->host == NULL)) {
  510. return status_invalid_argument;
  511. }
  512. uint32_t block_size = MIN(card->sdio_func[func_idx]->current_block_size, length);
  513. uint32_t num_blocks = (length + block_size - 1U) / block_size;
  514. return sdio_io_rw_extend(card,
  515. true,
  516. func_idx,
  517. reg_addr,
  518. SDIO_CMD53_OP_MODE_INCR_ADDR,
  519. pbuf,
  520. num_blocks,
  521. block_size);
  522. }
  523. hpm_stat_t sdio_io_read_incr_multi_bytes(sdio_card_t *card,
  524. uint32_t func_idx,
  525. uint32_t reg_addr,
  526. uint8_t *pbuf,
  527. uint32_t length)
  528. {
  529. if ((card == NULL) || (card->host == NULL)) {
  530. return status_invalid_argument;
  531. }
  532. uint32_t block_size = MIN(card->sdio_func[func_idx]->current_block_size, length);
  533. uint32_t num_blocks = (length + block_size - 1U) / block_size;
  534. return sdio_io_rw_extend(card,
  535. false,
  536. func_idx,
  537. reg_addr,
  538. SDIO_CMD53_OP_MODE_INCR_ADDR,
  539. pbuf,
  540. num_blocks,
  541. block_size);
  542. }
  543. hpm_stat_t sdio_init(sdio_card_t *card)
  544. {
  545. hpm_stat_t status = status_invalid_argument;
  546. do {
  547. HPM_BREAK_IF(card == NULL);
  548. status = sdio_host_init(card);
  549. HPM_BREAK_IF(status != status_success);
  550. card->host->card_init_done = false;
  551. card->relative_addr = 0;
  552. card->current_timing = sdmmc_sd_speed_normal;
  553. card->host->card_inserted = true;
  554. sdmmchost_delay_ms(card->host, 100); /* Wait a while in case the card connection is still not stable */
  555. status = sdio_card_init(card);
  556. } while (false);
  557. return status;
  558. }
  559. void sdio_deinit(sdio_card_t *card)
  560. {
  561. if ((card != NULL) && (card->host != NULL) && (card->host->card_init_done)) {
  562. card->host->card_init_done = false;
  563. sdmmchost_deinit(card->host);
  564. }
  565. }
  566. static hpm_stat_t sdio_set_bus_width(sdio_card_t *card)
  567. {
  568. hpm_stat_t status = status_success;
  569. do {
  570. /* If the card is a full-speed card, it shall support both 1-bit and 4-bit bus widths */
  571. bool support_4bit = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_4BIT);
  572. if ((card->cccr.low_speed_card == 0) && support_4bit) {
  573. uint8_t cccr_bus_if_ctrl = 0;
  574. status = sdio_io_read_byte(card, 0, SDIO_REG_CCCR_BUS_IF_CTRL, &cccr_bus_if_ctrl);
  575. HPM_BREAK_IF(status != status_success);
  576. cccr_bus_if_ctrl |= SDIO_CCCR_BUS_WIDTH_4BIT;
  577. status = sdio_io_write_byte(card, 0, SDIO_REG_CCCR_BUS_IF_CTRL, cccr_bus_if_ctrl);
  578. HPM_BREAK_IF(status != status_success);
  579. sdmmchost_set_card_bus_width(card->host, sdmmc_bus_width_4bit);
  580. }
  581. } while (false);
  582. return status;
  583. }
  584. static hpm_stat_t sdio_set_timing(sdio_card_t *card)
  585. {
  586. hpm_stat_t status = status_success;
  587. do {
  588. /* Change Speed */
  589. if (card->cccr.support_highspeed) {
  590. uint8_t bus_speed_sel = 0;
  591. bool need_reverse = true;
  592. uint32_t clock_option = SD_CLOCK_25MHZ;
  593. status = sdio_io_read_byte(card, 0, SDIO_REG_CCCR_BUS_SPEED_SEL, &bus_speed_sel);
  594. HPM_BREAK_IF(status != status_success);
  595. bool support_ddr = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_DDR);
  596. bool support_sdr104 = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_SDR104);
  597. bool support_sdr50 = IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_SDR50);
  598. sdmmc_speed_mode_t speed_mode;
  599. if (card->cccr.support_sdr104 && support_sdr104) {
  600. speed_mode = sdmmc_sd_speed_sdr104;
  601. clock_option = SD_CLOCK_208MHZ;
  602. bus_speed_sel = SDIO_CCCR_BUS_SPEED_SUPPORT_HIGHSPEED | SDIO_CCCR_BUS_SPEED_SDR104;
  603. } else if ((card->cccr.support_sdr50 || (card->max_tran_speed_in_kbps > 25000)) && support_sdr50) {
  604. speed_mode = sdmmc_sd_speed_sdr50;
  605. clock_option = SD_CLOCK_100MHZ;
  606. bus_speed_sel = SDIO_CCCR_BUS_SPEED_SUPPORT_HIGHSPEED | SDIO_CCCR_BUS_SPEED_SDR50;
  607. } else if (card->cccr.support_ddr50 && support_ddr) {
  608. speed_mode = sdmmc_sd_speed_ddr50;
  609. clock_option = SD_CLOCK_50MHZ;
  610. need_reverse = false;
  611. bus_speed_sel = SDIO_CCCR_BUS_SPEED_SUPPORT_HIGHSPEED | SDIO_CCCR_BUS_SPEED_DDR50;
  612. } else {
  613. speed_mode = sdmmc_sd_speed_high;
  614. bus_speed_sel = SDIO_CCCR_BUS_SPEED_SUPPORT_HIGHSPEED | SDIO_CCCR_BUS_SPEED_HIGH;
  615. clock_option = SD_CLOCK_50MHZ;
  616. }
  617. status = sdio_io_write_byte(card, 0, SDIO_REG_CCCR_BUS_SPEED_SEL, bus_speed_sel);
  618. HPM_BREAK_IF(status != status_success);
  619. sdmmchost_set_speed_mode(card->host, speed_mode);
  620. card->host->clock_freq = sdmmchost_set_card_clock(card->host, clock_option, need_reverse);
  621. }
  622. } while (false);
  623. return status;
  624. }
  625. hpm_stat_t sdio_card_init(sdio_card_t *card)
  626. {
  627. hpm_stat_t status = status_invalid_argument;
  628. do {
  629. HPM_BREAK_IF((card == NULL) || (card->host == NULL));
  630. sdmmchost_set_card_bus_width(card->host, sdmmc_bus_width_1bit);
  631. sdmmchost_set_card_clock(card->host, SDMMC_CLOCK_400KHZ, true);
  632. status = sdio_probe_sdio_card(card);
  633. card->host->operation_mode = hpm_sdmmc_operation_mode_identification;
  634. sdmmchost_init_io(card->host, card->host->operation_mode);
  635. HPM_BREAK_IF(status != status_success);
  636. card->host->dev_type = sdmmc_dev_type_sdio;
  637. /* Send CMD3 */
  638. status = sdio_send_rca(card);
  639. HPM_BREAK_IF(status != status_success);
  640. /* Send CMD7 */
  641. status = sdmmc_select_card(card->host, card->relative_addr, true);
  642. HPM_BREAK_IF(status != status_success);
  643. sdmmchost_set_card_clock(card->host, SD_CLOCK_25MHZ, true);
  644. card->host->operation_mode = hpm_sdmmc_operation_mode_transfer;
  645. sdmmchost_init_io(card->host, card->host->operation_mode);
  646. status = sdio_read_cccr(card);
  647. HPM_BREAK_IF(status != status_success);
  648. uint32_t common_cis_ptr = sdio_cis_csr_addr(card->cccr.common_cis_pointer);
  649. status = sdio_read_cis(card, common_cis_ptr, &card->common_cis, false);
  650. HPM_BREAK_IF(status != status_success);
  651. /* Change Bus Speed */
  652. status = sdio_set_timing(card);
  653. HPM_BREAK_IF(status != status_success);
  654. /* Change Bus width */
  655. status = sdio_set_bus_width(card);
  656. HPM_BREAK_IF(status != status_success);
  657. sdmmchost_init_io(card->host, card->host->operation_mode);
  658. sdio_get_max_transfer_speed(card);
  659. /* Update CCCR */
  660. status = sdio_read_cccr(card);
  661. } while (false);
  662. if (status == status_success) {
  663. card->host->card_init_done = true;
  664. }
  665. return status;
  666. }
  667. hpm_stat_t sdio_card_deinit(sdio_card_t *card)
  668. {
  669. hpm_stat_t status = status_invalid_argument;
  670. do {
  671. HPM_BREAK_IF((card == NULL) || (card->host == NULL));
  672. if (!card->host->card_init_done) {
  673. status = status_sdmmc_device_init_required;
  674. break;
  675. }
  676. /* De-initialize functions */
  677. status = sdio_deinit_funcs(card);
  678. } while (false);
  679. if (status == status_success) {
  680. card->host->card_init_done = false;
  681. }
  682. return status;
  683. }
  684. hpm_stat_t sdio_get_max_transfer_speed(sdio_card_t *card)
  685. {
  686. hpm_stat_t status = status_invalid_argument;
  687. do {
  688. HPM_BREAK_IF((card == NULL) || (card->host == NULL));
  689. uint32_t speed_units[8] = { 100UL, 1000UL, 10UL * 1000UL, 100UL * 1000UL, 0, 0, 0, 0 };
  690. uint32_t factor_mul10[16] = { 0, 10, 12, 13, 14, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
  691. uint32_t speed_unit_idx = card->common_cis.max_tran_speed & 0x7;
  692. uint32_t fact_idx = (card->common_cis.max_tran_speed >> 3) & 0xF;
  693. card->max_tran_speed_in_kbps = speed_units[speed_unit_idx] * factor_mul10[fact_idx] / 10;
  694. status = status_success;
  695. } while (false);
  696. return status;
  697. }
  698. hpm_stat_t sdio_init_funcs(sdio_card_t *card)
  699. {
  700. hpm_stat_t status = status_invalid_argument;
  701. do {
  702. HPM_BREAK_IF((card == NULL) || (card->host == NULL));
  703. for (uint32_t i = 0; i <= card->num_of_functions; i++) {
  704. sdio_func_t *sdio_func = (sdio_func_t *) HPM_SDMMC_MALLOC(sizeof(sdio_func_t));
  705. if (sdio_func == NULL) {
  706. return status_fail;
  707. }
  708. card->sdio_func[i] = sdio_func;
  709. }
  710. for (uint32_t i = 1; i <= card->num_of_functions; i++) {
  711. sdio_func_t *sdio_func = card->sdio_func[i];
  712. status = sdio_read_fbr(card, i, &sdio_func->fbr);
  713. HPM_BREAK_IF(status != status_success);
  714. uint32_t cis_ptr = sdio_cis_csr_addr(sdio_func->fbr.cis_ptr);
  715. status = sdio_read_cis(card, cis_ptr, &sdio_func->cis, true);
  716. HPM_BREAK_IF(status != status_success);
  717. sdio_func->func_idx = i;
  718. sdio_func->max_block_size = sdio_func->cis.max_blk_size;
  719. sdio_func->current_block_size = sdio_func->cis.max_blk_size;
  720. }
  721. if (status != status_success) {
  722. for (uint32_t i = 0; i <= card->num_of_functions; i++) {
  723. HPM_SDMMC_FREE(card->sdio_func[i]);
  724. card->sdio_func[i] = NULL;
  725. }
  726. }
  727. } while (false);
  728. return status;
  729. }
  730. hpm_stat_t sdio_deinit_funcs(sdio_card_t *card)
  731. {
  732. hpm_stat_t status = status_invalid_argument;
  733. do {
  734. HPM_BREAK_IF((card == NULL) || (card->host == NULL));
  735. /* Free all buffers */
  736. for (uint32_t i = 0; i <= card->num_of_functions; i++) {
  737. if (card->sdio_func[i] == NULL) {
  738. continue;
  739. }
  740. /* Free TPL data if necessary */
  741. if (card->sdio_func[i]->cis.tpl_link != NULL) {
  742. sdio_tpl_blk_t current_tpl = card->sdio_func[i]->cis.tpl_link;
  743. while (current_tpl != NULL) {
  744. sdio_tpl_blk_t tmp_tpl = current_tpl->next;
  745. HPM_SDMMC_FREE(current_tpl);
  746. current_tpl = tmp_tpl;
  747. }
  748. }
  749. HPM_SDMMC_FREE(card->sdio_func[i]);
  750. card->sdio_func[i] = NULL;
  751. }
  752. status = status_success;
  753. } while (false);
  754. return status;
  755. }
  756. hpm_stat_t sdio_host_init(sdio_card_t *card)
  757. {
  758. hpm_stat_t status = status_success;
  759. assert(card != NULL);
  760. status = sdmmchost_init(card->host);
  761. if (status == status_success) {
  762. card->is_host_ready = true;
  763. if (IS_HPM_BITMASK_SET(card->host->host_param.host_flags, HPM_SDMMC_HOST_SUPPORT_3V3)) {
  764. card->operation_voltage = sdmmc_operation_voltage_3v3;
  765. } else {
  766. card->operation_voltage = sdmmc_operation_voltage_1v8;
  767. }
  768. }
  769. return status_success;
  770. }
  771. hpm_stat_t sdio_host_deinit(sdio_card_t *card)
  772. {
  773. (void) card;
  774. return status_success;
  775. }
  776. const char *sdio_get_func_if_code_str(uint8_t std_func_if_code)
  777. {
  778. const char *code_str;
  779. switch (std_func_if_code) {
  780. case STD_SDIO_FUNC_IF_CODE_NON_STD:
  781. code_str = "No Standard SDIO interface";
  782. break;
  783. case STD_SDIO_FUNC_IF_CODE_UART:
  784. code_str = "SDIO Standard UART";
  785. break;
  786. case STD_SDIO_FUNC_IF_CODE_BT_TYPEA:
  787. code_str = "SDIO Bluetooth Type-A standard interface";
  788. break;
  789. case STD_SDIO_FUNC_IF_CODE_BT_TYPEB:
  790. code_str = "SDIO Bluetooth Type-B standard interface";
  791. break;
  792. case STD_SDIO_FUNC_IF_CODE_GPS:
  793. code_str = "SDIO GPS standard interface";
  794. break;
  795. case STD_SDIO_FUNC_IF_CODE_CAMERA:
  796. code_str = "SDIO Camera standard interface";
  797. break;
  798. case STD_SDIO_FUNC_IF_CODE_PHS:
  799. code_str = "SDIO PHS standard interface";
  800. break;
  801. case STD_SDIO_FUNC_IF_CODE_WLAN:
  802. code_str = "SDIO WLAN interface";
  803. break;
  804. case STD_SDIO_FUNC_IF_CODE_ATA:
  805. code_str = "Embedded SDIO-ATA standard interface";
  806. break;
  807. case STD_SDIO_FUNC_IF_CODE_BT_TYPEA_AMP:
  808. code_str = "SDIO Bluetooth Type-A AMP standard interface";
  809. break;
  810. case STD_SDIO_FUNC_IF_CODE_ISDIO:
  811. code_str = "iSDIO standard interface";
  812. break;
  813. case STD_SDIO_FUNC_IF_CODE_EXT_STD:
  814. code_str = "Extended SDIO Function Interface";
  815. break;
  816. default:
  817. code_str = "UnKnown Interface Code";
  818. break;
  819. }
  820. return code_str;
  821. }
  822. hpm_stat_t sdio_enable_interrupt(sdio_card_t *card)
  823. {
  824. hpm_stat_t status = status_invalid_argument;
  825. do {
  826. if ((card == NULL) || (card->host == NULL)) {
  827. break;
  828. }
  829. sdmmchost_enable_sdio_interrupt(card->host, true);
  830. status = status_success;
  831. } while (false);
  832. return status;
  833. }
  834. hpm_stat_t sdio_disable_interrupt(sdio_card_t *card)
  835. {
  836. hpm_stat_t status = status_invalid_argument;
  837. do {
  838. if ((card == NULL) || (card->host == NULL)) {
  839. break;
  840. }
  841. sdmmchost_enable_sdio_interrupt(card->host, false);
  842. status = status_success;
  843. } while (false);
  844. return status;
  845. }
  846. hpm_stat_t sdio_register_irq_callback(sdio_card_t *card, void (*sdio_irq_callback)(void *param), void *sdio_irq_param)
  847. {
  848. hpm_stat_t status = status_invalid_argument;
  849. do {
  850. if ((card == NULL) || (card->host == NULL)) {
  851. break;
  852. }
  853. sdmmchost_register_sdio_callback(card->host, sdio_irq_callback, sdio_irq_param);
  854. status = status_success;
  855. } while (false);
  856. return status;
  857. }