exynos_dw_mmc.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * (C) Copyright 2012 SAMSUNG Electronics
  3. * Jaehoon Chung <jh80.chung@samsung.com>
  4. *
  5. * SPDX-License-Identifier: GPL-2.0+
  6. */
  7. #include <common.h>
  8. #include <dwmmc.h>
  9. #include <fdtdec.h>
  10. #include <libfdt.h>
  11. #include <malloc.h>
  12. #include <asm/arch/dwmmc.h>
  13. #include <asm/arch/clk.h>
  14. #include <asm/arch/pinmux.h>
  15. #include <asm/arch/power.h>
  16. #include <asm/gpio.h>
  17. #include <asm-generic/errno.h>
  18. #define DWMMC_MAX_CH_NUM 4
  19. #define DWMMC_MAX_FREQ 52000000
  20. #define DWMMC_MIN_FREQ 400000
  21. #define DWMMC_MMC0_SDR_TIMING_VAL 0x03030001
  22. #define DWMMC_MMC2_SDR_TIMING_VAL 0x03020001
  23. /* Exynos implmentation specific drver private data */
  24. struct dwmci_exynos_priv_data {
  25. u32 sdr_timing;
  26. };
  27. /*
  28. * Function used as callback function to initialise the
  29. * CLKSEL register for every mmc channel.
  30. */
  31. static void exynos_dwmci_clksel(struct dwmci_host *host)
  32. {
  33. struct dwmci_exynos_priv_data *priv = host->priv;
  34. dwmci_writel(host, DWMCI_CLKSEL, priv->sdr_timing);
  35. }
  36. unsigned int exynos_dwmci_get_clk(struct dwmci_host *host, uint freq)
  37. {
  38. unsigned long sclk;
  39. int8_t clk_div;
  40. /*
  41. * Since SDCLKIN is divided inside controller by the DIVRATIO
  42. * value set in the CLKSEL register, we need to use the same output
  43. * clock value to calculate the CLKDIV value.
  44. * as per user manual:cclk_in = SDCLKIN / (DIVRATIO + 1)
  45. */
  46. clk_div = ((dwmci_readl(host, DWMCI_CLKSEL) >> DWMCI_DIVRATIO_BIT)
  47. & DWMCI_DIVRATIO_MASK) + 1;
  48. sclk = get_mmc_clk(host->dev_index);
  49. /*
  50. * Assume to know divider value.
  51. * When clock unit is broken, need to set "host->div"
  52. */
  53. return sclk / clk_div / (host->div + 1);
  54. }
  55. static void exynos_dwmci_board_init(struct dwmci_host *host)
  56. {
  57. struct dwmci_exynos_priv_data *priv = host->priv;
  58. if (host->quirks & DWMCI_QUIRK_DISABLE_SMU) {
  59. dwmci_writel(host, EMMCP_MPSBEGIN0, 0);
  60. dwmci_writel(host, EMMCP_SEND0, 0);
  61. dwmci_writel(host, EMMCP_CTRL0,
  62. MPSCTRL_SECURE_READ_BIT |
  63. MPSCTRL_SECURE_WRITE_BIT |
  64. MPSCTRL_NON_SECURE_READ_BIT |
  65. MPSCTRL_NON_SECURE_WRITE_BIT | MPSCTRL_VALID);
  66. }
  67. /* Set to timing value at initial time */
  68. if (priv->sdr_timing)
  69. exynos_dwmci_clksel(host);
  70. }
  71. static int exynos_dwmci_core_init(struct dwmci_host *host, int index)
  72. {
  73. unsigned int div;
  74. unsigned long freq, sclk;
  75. struct dwmci_exynos_priv_data *priv = host->priv;
  76. if (host->bus_hz)
  77. freq = host->bus_hz;
  78. else
  79. freq = DWMMC_MAX_FREQ;
  80. /* request mmc clock vlaue of 52MHz. */
  81. sclk = get_mmc_clk(index);
  82. div = DIV_ROUND_UP(sclk, freq);
  83. /* set the clock divisor for mmc */
  84. set_mmc_clk(index, div);
  85. host->name = "EXYNOS DWMMC";
  86. #ifdef CONFIG_EXYNOS5420
  87. host->quirks = DWMCI_QUIRK_DISABLE_SMU;
  88. #endif
  89. host->board_init = exynos_dwmci_board_init;
  90. if (!priv->sdr_timing) {
  91. if (index == 0)
  92. priv->sdr_timing = DWMMC_MMC0_SDR_TIMING_VAL;
  93. else if (index == 2)
  94. priv->sdr_timing = DWMMC_MMC2_SDR_TIMING_VAL;
  95. }
  96. host->caps = MMC_MODE_DDR_52MHz;
  97. host->clksel = exynos_dwmci_clksel;
  98. host->dev_index = index;
  99. host->get_mmc_clk = exynos_dwmci_get_clk;
  100. /* Add the mmc channel to be registered with mmc core */
  101. if (add_dwmci(host, DWMMC_MAX_FREQ, DWMMC_MIN_FREQ)) {
  102. printf("DWMMC%d registration failed\n", index);
  103. return -1;
  104. }
  105. return 0;
  106. }
  107. /*
  108. * This function adds the mmc channel to be registered with mmc core.
  109. * index - mmc channel number.
  110. * regbase - register base address of mmc channel specified in 'index'.
  111. * bus_width - operating bus width of mmc channel specified in 'index'.
  112. * clksel - value to be written into CLKSEL register in case of FDT.
  113. * NULL in case od non-FDT.
  114. */
  115. int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel)
  116. {
  117. struct dwmci_host *host = NULL;
  118. struct dwmci_exynos_priv_data *priv;
  119. host = malloc(sizeof(struct dwmci_host));
  120. if (!host) {
  121. error("dwmci_host malloc fail!\n");
  122. return -ENOMEM;
  123. }
  124. priv = malloc(sizeof(struct dwmci_exynos_priv_data));
  125. if (!priv) {
  126. error("dwmci_exynos_priv_data malloc fail!\n");
  127. return -ENOMEM;
  128. }
  129. host->ioaddr = (void *)regbase;
  130. host->buswidth = bus_width;
  131. if (clksel)
  132. priv->sdr_timing = clksel;
  133. host->priv = priv;
  134. return exynos_dwmci_core_init(host, index);
  135. }
  136. #if CONFIG_IS_ENABLED(OF_CONTROL)
  137. static struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM];
  138. static int do_dwmci_init(struct dwmci_host *host)
  139. {
  140. int index, flag, err;
  141. index = host->dev_index;
  142. flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
  143. err = exynos_pinmux_config(host->dev_id, flag);
  144. if (err) {
  145. printf("DWMMC%d not configure\n", index);
  146. return err;
  147. }
  148. return exynos_dwmci_core_init(host, index);
  149. }
  150. static int exynos_dwmci_get_config(const void *blob, int node,
  151. struct dwmci_host *host)
  152. {
  153. int err = 0;
  154. u32 base, timing[3];
  155. struct dwmci_exynos_priv_data *priv;
  156. priv = malloc(sizeof(struct dwmci_exynos_priv_data));
  157. if (!priv) {
  158. error("dwmci_exynos_priv_data malloc fail!\n");
  159. return -ENOMEM;
  160. }
  161. /* Extract device id for each mmc channel */
  162. host->dev_id = pinmux_decode_periph_id(blob, node);
  163. host->dev_index = fdtdec_get_int(blob, node, "index", host->dev_id);
  164. if (host->dev_index == host->dev_id)
  165. host->dev_index = host->dev_id - PERIPH_ID_SDMMC0;
  166. /* Get the bus width from the device node */
  167. host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0);
  168. if (host->buswidth <= 0) {
  169. printf("DWMMC%d: Can't get bus-width\n", host->dev_index);
  170. return -EINVAL;
  171. }
  172. /* Set the base address from the device node */
  173. base = fdtdec_get_addr(blob, node, "reg");
  174. if (!base) {
  175. printf("DWMMC%d: Can't get base address\n", host->dev_index);
  176. return -EINVAL;
  177. }
  178. host->ioaddr = (void *)base;
  179. /* Extract the timing info from the node */
  180. err = fdtdec_get_int_array(blob, node, "samsung,timing", timing, 3);
  181. if (err) {
  182. printf("DWMMC%d: Can't get sdr-timings for devider\n",
  183. host->dev_index);
  184. return -EINVAL;
  185. }
  186. priv->sdr_timing = (DWMCI_SET_SAMPLE_CLK(timing[0]) |
  187. DWMCI_SET_DRV_CLK(timing[1]) |
  188. DWMCI_SET_DIV_RATIO(timing[2]));
  189. /* sdr_timing didn't assigned anything, use the default value */
  190. if (!priv->sdr_timing) {
  191. if (host->dev_index == 0)
  192. priv->sdr_timing = DWMMC_MMC0_SDR_TIMING_VAL;
  193. else if (host->dev_index == 2)
  194. priv->sdr_timing = DWMMC_MMC2_SDR_TIMING_VAL;
  195. }
  196. host->fifoth_val = fdtdec_get_int(blob, node, "fifoth_val", 0);
  197. host->bus_hz = fdtdec_get_int(blob, node, "bus_hz", 0);
  198. host->div = fdtdec_get_int(blob, node, "div", 0);
  199. host->priv = priv;
  200. return 0;
  201. }
  202. static int exynos_dwmci_process_node(const void *blob,
  203. int node_list[], int count)
  204. {
  205. struct dwmci_host *host;
  206. int i, node, err;
  207. for (i = 0; i < count; i++) {
  208. node = node_list[i];
  209. if (node <= 0)
  210. continue;
  211. host = &dwmci_host[i];
  212. err = exynos_dwmci_get_config(blob, node, host);
  213. if (err) {
  214. printf("%s: failed to decode dev %d\n", __func__, i);
  215. return err;
  216. }
  217. do_dwmci_init(host);
  218. }
  219. return 0;
  220. }
  221. int exynos_dwmmc_init(const void *blob)
  222. {
  223. int compat_id;
  224. int node_list[DWMMC_MAX_CH_NUM];
  225. int boot_dev_node;
  226. int err = 0, count;
  227. compat_id = COMPAT_SAMSUNG_EXYNOS_DWMMC;
  228. count = fdtdec_find_aliases_for_id(blob, "mmc",
  229. compat_id, node_list, DWMMC_MAX_CH_NUM);
  230. /* For DWMMC always set boot device as mmc 0 */
  231. if (count >= 3 && get_boot_mode() == BOOT_MODE_SD) {
  232. boot_dev_node = node_list[2];
  233. node_list[2] = node_list[0];
  234. node_list[0] = boot_dev_node;
  235. }
  236. err = exynos_dwmci_process_node(blob, node_list, count);
  237. return err;
  238. }
  239. #endif