drv_sd.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright (c) 2006-2024 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-10-28 zhujiale The first version
  9. */
  10. #include <sdhci.h>
  11. #include <rtdevice.h>
  12. #include "drv_sd.h"
  13. #define DBG_TAG "SDHCI"
  14. #ifdef DRV_DEBUG
  15. #define DBG_LVL DBG_LOG
  16. #else
  17. #define DBG_LVL DBG_INFO
  18. #endif /* DRV_DEBUG */
  19. #include <rtdbg.h>
  20. #define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18)
  21. struct sdhci_iproc_data {
  22. const struct sdhci_pltfm_data *pdata;
  23. rt_uint32_t caps;
  24. rt_uint32_t caps1;
  25. rt_uint32_t mmc_caps;
  26. rt_bool_t missing_caps;
  27. };
  28. struct sdhci_iproc_host {
  29. const struct sdhci_iproc_data *data;
  30. rt_uint32_t shadow_cmd;
  31. rt_uint32_t shadow_blk;
  32. rt_bool_t is_cmd_shadowed;
  33. rt_bool_t is_blk_shadowed;
  34. };
  35. static inline rt_uint32_t sdhci_iproc_readl(struct sdhci_host *host, int reg)
  36. {
  37. rt_uint32_t val = readl(host->ioaddr + reg);
  38. return val;
  39. }
  40. static rt_uint16_t sdhci_iproc_readw(struct sdhci_host *host, int reg)
  41. {
  42. struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
  43. struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host);
  44. rt_uint32_t val;
  45. rt_uint16_t word;
  46. if ((reg == SDHCI_TRANSFER_MODE) && iproc_host->is_cmd_shadowed)
  47. {
  48. /* Get the saved transfer mode */
  49. val = iproc_host->shadow_cmd;
  50. } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
  51. iproc_host->is_blk_shadowed)
  52. {
  53. /* Get the saved block info */
  54. val = iproc_host->shadow_blk;
  55. } else {
  56. val = sdhci_iproc_readl(host, (reg & ~3));
  57. }
  58. word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff;
  59. return word;
  60. }
  61. static rt_uint8_t sdhci_iproc_readb(struct sdhci_host *host, int reg)
  62. {
  63. rt_uint32_t val = sdhci_iproc_readl(host, (reg & ~3));
  64. rt_uint8_t byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff;
  65. return byte;
  66. }
  67. static inline void sdhci_iproc_writel(struct sdhci_host *host, rt_uint32_t val, int reg)
  68. {
  69. LOG_D("%s: writel [0x%02x] 0x%08x\n",
  70. mmc_hostname(host->mmc), reg, val);
  71. writel(val, host->ioaddr + reg);
  72. if (host->clock <= 400000)
  73. {
  74. /* Round up to micro-second four SD clock delay */
  75. if (host->clock)
  76. rt_hw_us_delay((4 * 1000000 + host->clock - 1) / host->clock);
  77. else
  78. rt_hw_us_delay(10);
  79. }
  80. }
  81. static void sdhci_iproc_writew(struct sdhci_host *host, rt_uint16_t val, int reg)
  82. {
  83. struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
  84. struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host);
  85. rt_uint32_t word_shift = REG_OFFSET_IN_BITS(reg);
  86. rt_uint32_t mask = 0xffff << word_shift;
  87. rt_uint32_t oldval, newval;
  88. if (reg == SDHCI_COMMAND)
  89. {
  90. /* Write the block now as we are issuing a command */
  91. if (iproc_host->is_blk_shadowed)
  92. {
  93. sdhci_iproc_writel(host, iproc_host->shadow_blk,
  94. SDHCI_BLOCK_SIZE);
  95. iproc_host->is_blk_shadowed = false;
  96. }
  97. oldval = iproc_host->shadow_cmd;
  98. iproc_host->is_cmd_shadowed = false;
  99. } else if ((reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) &&
  100. iproc_host->is_blk_shadowed)
  101. {
  102. /* Block size and count are stored in shadow reg */
  103. oldval = iproc_host->shadow_blk;
  104. } else {
  105. /* Read reg, all other registers are not shadowed */
  106. oldval = sdhci_iproc_readl(host, (reg & ~3));
  107. }
  108. newval = (oldval & ~mask) | (val << word_shift);
  109. if (reg == SDHCI_TRANSFER_MODE)
  110. {
  111. /* Save the transfer mode until the command is issued */
  112. iproc_host->shadow_cmd = newval;
  113. iproc_host->is_cmd_shadowed = true;
  114. } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT)
  115. {
  116. /* Save the block info until the command is issued */
  117. iproc_host->shadow_blk = newval;
  118. iproc_host->is_blk_shadowed = true;
  119. } else {
  120. /* Command or other regular 32-bit write */
  121. sdhci_iproc_writel(host, newval, reg & ~3);
  122. }
  123. }
  124. static void sdhci_iproc_writeb(struct sdhci_host *host, rt_uint8_t val, int reg)
  125. {
  126. rt_uint32_t oldval = sdhci_iproc_readl(host, (reg & ~3));
  127. rt_uint32_t byte_shift = REG_OFFSET_IN_BITS(reg);
  128. rt_uint32_t mask = 0xff << byte_shift;
  129. rt_uint32_t newval = (oldval & ~mask) | (val << byte_shift);
  130. sdhci_iproc_writel(host, newval, reg & ~3);
  131. }
  132. static const struct sdhci_ops sdhci_iproc_bcm2711_ops = {
  133. .read_l = sdhci_iproc_readl,
  134. .read_w = sdhci_iproc_readw,
  135. .read_b = sdhci_iproc_readb,
  136. .write_l = sdhci_iproc_writel,
  137. .write_w = sdhci_iproc_writew,
  138. .write_b = sdhci_iproc_writeb,
  139. .set_clock = sdhci_set_clock,
  140. .set_bus_width = sdhci_set_bus_width,
  141. .reset = sdhci_reset,
  142. .set_uhs_signaling = sdhci_set_uhs_signaling,
  143. };
  144. static const struct sdhci_pltfm_data sdhci_bcm2711_pltfm_data = {
  145. .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
  146. .ops = &sdhci_iproc_bcm2711_ops,
  147. };
  148. static const struct sdhci_iproc_data bcm2711_data = {
  149. .pdata = &sdhci_bcm2711_pltfm_data,
  150. .mmc_caps = MMC_CAP_3_3V_DDR,
  151. };
  152. rt_err_t bcm2835_probe(struct rt_platform_device *pdev)
  153. {
  154. struct sdhci_iproc_host *iproc_host;
  155. const struct sdhci_iproc_data *iproc_data = NULL;
  156. struct sdhci_host *host;
  157. struct sdhci_pltfm_host *pltfm_host;
  158. int ret;
  159. iproc_data = &bcm2711_data;
  160. host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host));
  161. pltfm_host = sdhci_priv(host);
  162. iproc_host = sdhci_pltfm_priv(pltfm_host);
  163. iproc_host->data = iproc_data;
  164. ret = mmc_of_parse(host->mmc);
  165. if (ret)
  166. goto err;
  167. sdhci_get_property(pdev);
  168. host->mmc->caps |= iproc_host->data->mmc_caps;
  169. ret = sdhci_add_host(host);
  170. if (ret)
  171. goto err;
  172. return 0;
  173. err:
  174. return ret;
  175. }
  176. static const struct rt_ofw_node_id bcm2835_ofw_ids[] =
  177. {
  178. /* { .compatible = "brcm,bcm2711-emmc2"},*/
  179. { .compatible = "brcm,bcm2835-mmc"},
  180. { /* sentinel */ }
  181. };
  182. static struct rt_platform_driver bcm2835_driver =
  183. {
  184. .name = "bcm2835",
  185. .ids = bcm2835_ofw_ids,
  186. .probe = bcm2835_probe,
  187. /* .remove = pl011_remove,*/
  188. };
  189. RT_PLATFORM_DRIVER_EXPORT(bcm2835_driver);