hpm_sdmmc_common.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * Copyright (c) 2021-2024 HPMicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. */
  7. #include "hpm_sdmmc_common.h"
  8. #include "hpm_sdmmc_card.h"
  9. #include <string.h>
  10. hpm_stat_t sdmmc_go_idle_state(sdmmc_host_t *host, uint32_t argument)
  11. {
  12. hpm_stat_t status = status_invalid_argument;
  13. do {
  14. HPM_BREAK_IF(host == NULL);
  15. sdmmchost_cmd_t *host_cmd = &host->cmd;
  16. (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
  17. host_cmd->cmd_index = sdmmc_cmd_go_idle_state;
  18. host_cmd->cmd_argument = argument;
  19. host_cmd->resp_type = sdxc_dev_resp_none;
  20. status = sdmmchost_send_command(host, host_cmd);
  21. } while (false);
  22. return status;
  23. }
  24. hpm_stat_t sdmmc_go_inactive_state(sdmmc_host_t *host, uint16_t relative_addr)
  25. {
  26. hpm_stat_t status = status_invalid_argument;
  27. do {
  28. HPM_BREAK_IF(host == NULL);
  29. sdmmchost_cmd_t *host_cmd = &host->cmd;
  30. (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
  31. host_cmd->cmd_index = sdmmc_cmd_go_inactive_state;
  32. host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
  33. host_cmd->resp_type = sdxc_dev_resp_none;
  34. status = sdmmchost_send_command(host, host_cmd);
  35. } while (false);
  36. return status;
  37. }
  38. hpm_stat_t sdmmc_select_card(sdmmc_host_t *host, uint16_t relative_addr, bool is_selected)
  39. {
  40. hpm_stat_t status = status_invalid_argument;
  41. do {
  42. HPM_BREAK_IF(host == NULL);
  43. sdmmchost_cmd_t *host_cmd = &host->cmd;
  44. (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
  45. host_cmd->cmd_index = sdmmc_cmd_select_card;
  46. host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
  47. if (is_selected) {
  48. host_cmd->resp_type = sdxc_dev_resp_r1b;
  49. } else {
  50. host_cmd->resp_type = sdxc_dev_resp_none;
  51. }
  52. status = sdmmchost_send_command(host, host_cmd);
  53. } while (false);
  54. return status;
  55. }
  56. hpm_stat_t sdmmc_send_application_command(sdmmc_host_t *host, uint16_t relative_addr)
  57. {
  58. hpm_stat_t status = status_invalid_argument;
  59. do {
  60. HPM_BREAK_IF(host == NULL);
  61. sdmmchost_cmd_t *host_cmd = &host->cmd;
  62. (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
  63. host_cmd->cmd_index = sdmmc_cmd_app_cmd;
  64. host_cmd->cmd_argument = ((uint32_t) relative_addr) << 16;
  65. host_cmd->resp_type = sdxc_dev_resp_r1;
  66. status = sdmmchost_send_command(host, host_cmd);
  67. } while (false);
  68. return status;
  69. }
  70. hpm_stat_t sdmmc_set_block_count(sdmmc_host_t *host, uint32_t block_count)
  71. {
  72. hpm_stat_t status = status_invalid_argument;
  73. do {
  74. HPM_BREAK_IF(host == NULL);
  75. sdmmchost_cmd_t *host_cmd = &host->cmd;
  76. (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
  77. host_cmd->cmd_index = sdmmc_cmd_set_block_count;
  78. host_cmd->cmd_argument = block_count;
  79. host_cmd->resp_type = sdxc_dev_resp_r1;
  80. status = sdmmchost_send_command(host, host_cmd);
  81. } while (false);
  82. return status;
  83. }
  84. hpm_stat_t sdmmc_set_block_size(sdmmc_host_t *host, uint32_t block_size)
  85. {
  86. hpm_stat_t status = status_invalid_argument;
  87. do {
  88. HPM_BREAK_IF(host == NULL);
  89. sdmmchost_cmd_t *host_cmd = &host->cmd;
  90. (void) memset(host_cmd, 0, sizeof(sdmmchost_cmd_t));
  91. host_cmd->cmd_index = sdmmc_cmd_set_block_length;
  92. host_cmd->cmd_argument = block_size;
  93. host_cmd->resp_type = sdxc_dev_resp_r1;
  94. status = sdmmchost_send_command(host, host_cmd);
  95. } while (false);
  96. return status;
  97. }
  98. hpm_stat_t sdmmc_enable_auto_tuning(const sdmmc_host_t *host)
  99. {
  100. hpm_stat_t status = status_invalid_argument;
  101. do {
  102. HPM_BREAK_IF((host == NULL) || (host->host_param.base == NULL));
  103. SDXC_Type *base = host->host_param.base;
  104. /* Prepare the Auto tuning environment */
  105. sdxc_stop_clock_during_phase_code_change(base, true);
  106. sdxc_set_post_change_delay(base, 3U);
  107. sdxc_select_cardclk_delay_source(base, false);
  108. sdxc_enable_power(base, true);
  109. /* Start Auto tuning */
  110. uint8_t tuning_cmd = (host->dev_type == sdmmc_dev_type_sd) ? 19U : 21U;
  111. status = sdxc_perform_auto_tuning(host->host_param.base, tuning_cmd);
  112. HPM_BREAK_IF(status != status_success);
  113. } while (false);
  114. return status;
  115. }
  116. uint32_t extract_csd_field(const uint32_t *raw_csd, uint8_t end_offset, uint8_t start_offset)
  117. {
  118. uint32_t result = 0;
  119. uint32_t start_word_index = start_offset / 32;
  120. uint32_t end_word_index = end_offset / 32;
  121. uint32_t end_offset_in_word = end_offset % 32;
  122. uint32_t start_offset_in_word = start_offset % 32;
  123. /* If all bits of the field are in the same raw_csd word */
  124. if (start_word_index == end_word_index) {
  125. uint32_t field_width = end_offset - start_offset + 1U;
  126. uint32_t field_mask = ((1UL << field_width) - 1U) << start_offset;
  127. result = (raw_csd[start_word_index] & field_mask) >> start_offset_in_word;
  128. } else {
  129. /* If the bits of the field crosses two raw_csd words */
  130. uint32_t lsb_width = 32U - start_offset_in_word;
  131. uint32_t result_lsb = raw_csd[start_word_index] >> start_offset_in_word;
  132. uint32_t msb_width = end_offset_in_word + 1UL;
  133. uint32_t result_msb = raw_csd[end_word_index] & ((1UL << msb_width) - 1U);
  134. result = (result_msb << lsb_width) | result_lsb;
  135. }
  136. return result;
  137. }