snps_sdhci.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2021 Alibaba Group Holding Limited.
  4. */
  5. #include <common.h>
  6. #include <clk.h>
  7. #include <dm.h>
  8. #include <malloc.h>
  9. #include <sdhci.h>
  10. #include "snps_sdhci.h"
  11. #define HS400_DELAY_LANE 24
  12. volatile int DELAY_LANE = 50;
  13. static void sdhci_phy_1_8v_init_no_pull(struct sdhci_host *host)
  14. {
  15. uint32_t val;
  16. sdhci_writel(host, 1, DWC_MSHC_PTR_PHY_R);
  17. sdhci_writeb(host, 1 << 4, PHY_SDCLKDL_CNFG_R);
  18. sdhci_writeb(host, 0x40, PHY_SDCLKDL_DC_R);
  19. sdhci_writeb(host, 0xa, PHY_DLL_CNFG2_R);
  20. val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
  21. val &= ~(1 << 4);
  22. sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
  23. val = sdhci_readw(host, PHY_CMDPAD_CNFG_R);
  24. sdhci_writew(host, val | 1, PHY_CMDPAD_CNFG_R);
  25. val = sdhci_readw(host, PHY_DATAPAD_CNFG_R);
  26. sdhci_writew(host, val | 1, PHY_DATAPAD_CNFG_R);
  27. val = sdhci_readw(host, PHY_RSTNPAD_CNFG_R);
  28. sdhci_writew(host, val | 1, PHY_RSTNPAD_CNFG_R);
  29. val = sdhci_readw(host, PHY_STBPAD_CNFG_R);
  30. sdhci_writew(host, val | 1, PHY_STBPAD_CNFG_R);
  31. val = sdhci_readb(host, PHY_DLL_CTRL_R);
  32. sdhci_writeb(host, val | 1, PHY_DLL_CTRL_R);
  33. }
  34. static void sdhci_phy_3_3v_init_no_pull(struct sdhci_host *host)
  35. {
  36. uint32_t val;
  37. sdhci_writel(host, 1, DWC_MSHC_PTR_PHY_R);
  38. sdhci_writeb(host, 1 << 4, PHY_SDCLKDL_CNFG_R);
  39. sdhci_writeb(host, 0x40, PHY_SDCLKDL_DC_R);
  40. sdhci_writeb(host, 0xa, PHY_DLL_CNFG2_R);
  41. val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
  42. val &= ~(1 << 4);
  43. sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
  44. val = sdhci_readw(host, PHY_CMDPAD_CNFG_R);
  45. sdhci_writew(host, val | 2, PHY_CMDPAD_CNFG_R);
  46. val = sdhci_readw(host, PHY_DATAPAD_CNFG_R);
  47. sdhci_writew(host, val | 2, PHY_DATAPAD_CNFG_R);
  48. val = sdhci_readw(host, PHY_RSTNPAD_CNFG_R);
  49. sdhci_writew(host, val | 2, PHY_RSTNPAD_CNFG_R);
  50. val = sdhci_readw(host, PHY_STBPAD_CNFG_R);
  51. sdhci_writew(host, val | 2, PHY_STBPAD_CNFG_R);
  52. val = sdhci_readb(host, PHY_DLL_CTRL_R);
  53. sdhci_writeb(host, val | 1, PHY_DLL_CTRL_R);
  54. }
  55. static void sdhci_phy_1_8v_init(struct sdhci_host *host)
  56. {
  57. uint32_t val;
  58. struct snps_sdhci_plat *plat = dev_get_platdata(host->mmc->dev);
  59. if(plat->pull_up_en == false) {
  60. sdhci_phy_1_8v_init_no_pull(host);
  61. return;
  62. }
  63. //set driving force
  64. sdhci_writel(host, (1 << PHY_RSTN) | (0xc << PAD_SP) | (0xc << PAD_SN), PHY_CNFG_R);
  65. //disable delay lane
  66. sdhci_writeb(host, 1 << UPDATE_DC, PHY_SDCLKDL_CNFG_R);
  67. //set delay lane
  68. sdhci_writeb(host, DELAY_LANE, PHY_SDCLKDL_DC_R);
  69. sdhci_writeb(host, 0xa, PHY_DLL_CNFG2_R);
  70. //enable delay lane
  71. val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
  72. val &= ~(1 << UPDATE_DC);
  73. sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
  74. val = (1 << RXSEL) | (1 << WEAKPULL_EN) | (3 << TXSLEW_CTRL_P) | (3 << TXSLEW_CTRL_N);
  75. sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
  76. sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
  77. sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
  78. val = (3 << TXSLEW_CTRL_P) | (3 << TXSLEW_CTRL_N);
  79. sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
  80. val = (1 << RXSEL) | (2 << WEAKPULL_EN) | (3 << TXSLEW_CTRL_P) | (3 << TXSLEW_CTRL_N);
  81. sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
  82. /* enable data strobe mode */
  83. sdhci_writeb(host, 0, PHY_DLL_CTRL_R);
  84. sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
  85. sdhci_writew(host, 0x8000, PHY_DLLBT_CNFG_R);
  86. sdhci_writeb(host, 3 << SLV_INPSEL, PHY_DLLDL_CNFG_R);
  87. sdhci_writeb(host, 0x25, PHY_DLL_CNFG1_R);
  88. sdhci_writew(host, 0x7, SDHCI_CLOCK_CONTROL);
  89. sdhci_writeb(host, (1 << DLL_EN), PHY_DLL_CTRL_R);
  90. }
  91. static void sdhci_phy_3_3v_init(struct sdhci_host *host)
  92. {
  93. uint32_t val;
  94. struct snps_sdhci_plat *plat = dev_get_platdata(host->mmc->dev);
  95. if(plat->pull_up_en == false) {
  96. sdhci_phy_3_3v_init_no_pull(host);
  97. return;
  98. }
  99. //set driving force
  100. sdhci_writel(host, (1 << PHY_RSTN) | (0xc << PAD_SP) | (0xc << PAD_SN), PHY_CNFG_R);
  101. //disable delay lane
  102. sdhci_writeb(host, 1 << UPDATE_DC, PHY_SDCLKDL_CNFG_R);
  103. //set delay lane
  104. sdhci_writeb(host, DELAY_LANE, PHY_SDCLKDL_DC_R);
  105. sdhci_writeb(host, 0xa, PHY_DLL_CNFG2_R);
  106. //enable delay lane
  107. val = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
  108. val &= ~(1 << UPDATE_DC);
  109. sdhci_writeb(host, val, PHY_SDCLKDL_CNFG_R);
  110. val = (2 << RXSEL) | (1 << WEAKPULL_EN) | (3 << TXSLEW_CTRL_P) | (3 << TXSLEW_CTRL_N);
  111. sdhci_writew(host, val, PHY_CMDPAD_CNFG_R);
  112. sdhci_writew(host, val, PHY_DATAPAD_CNFG_R);
  113. sdhci_writew(host, val, PHY_RSTNPAD_CNFG_R);
  114. val = (3 << TXSLEW_CTRL_P) | (3 << TXSLEW_CTRL_N);
  115. sdhci_writew(host, val, PHY_CLKPAD_CNFG_R);
  116. val = (2 << RXSEL) | (2 << WEAKPULL_EN) | (3 << TXSLEW_CTRL_P) | (3 << TXSLEW_CTRL_N);
  117. sdhci_writew(host, val, PHY_STBPAD_CNFG_R);
  118. sdhci_writeb(host, (1 << DLL_EN), PHY_DLL_CTRL_R);
  119. /*set i wait*/
  120. sdhci_writeb(host, 0x5, PHY_DLL_CNFG1_R);
  121. }
  122. void snps_set_uhs_timing(struct sdhci_host *host)
  123. {
  124. struct mmc *mmc = (struct mmc *)host->mmc;
  125. u32 reg;
  126. reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  127. reg &= ~SDHCI_CTRL_UHS_MASK;
  128. switch (mmc->selected_mode) {
  129. case UHS_SDR50:
  130. case MMC_HS_52:
  131. sdhci_phy_1_8v_init(host);
  132. reg |= SDHCI_CTRL_UHS_SDR50;
  133. break;
  134. case UHS_DDR50:
  135. case MMC_DDR_52:
  136. sdhci_phy_1_8v_init(host);
  137. reg |= SDHCI_CTRL_UHS_DDR50;
  138. break;
  139. case UHS_SDR104:
  140. case MMC_HS_200:
  141. sdhci_phy_1_8v_init(host);
  142. reg |= SDHCI_CTRL_UHS_SDR104;
  143. break;
  144. case MMC_HS_400:
  145. DELAY_LANE = HS400_DELAY_LANE;
  146. sdhci_phy_1_8v_init(host);
  147. reg |= SNPS_SDHCI_CTRL_HS400;
  148. break;
  149. default:
  150. sdhci_phy_3_3v_init(host);
  151. reg |= SDHCI_CTRL_UHS_SDR12;
  152. }
  153. sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
  154. if (mmc->selected_mode == MMC_HS_400) {
  155. // //disable delay lane
  156. // sdhci_writeb(host, 1 << UPDATE_DC, PHY_SDCLKDL_CNFG_R);
  157. // //set delay lane
  158. // sdhci_writeb(host, DELAY_LANE, PHY_SDCLKDL_DC_R);
  159. // //enable delay lane
  160. // reg = sdhci_readb(host, PHY_SDCLKDL_CNFG_R);
  161. // reg &= ~(1 << UPDATE_DC);
  162. // sdhci_writeb(host, reg, PHY_SDCLKDL_CNFG_R);
  163. //disable auto tuning
  164. reg = sdhci_readl(host, AT_CTRL_R);
  165. reg &= ~1;
  166. sdhci_writel(host, reg, AT_CTRL_R);
  167. } else {
  168. sdhci_writeb(host, 0, PHY_DLLDL_CNFG_R);
  169. }
  170. }
  171. static void snps_sdhci_set_control_reg(struct sdhci_host *host)
  172. {
  173. struct mmc *mmc = (struct mmc *)host->mmc;
  174. struct snps_sdhci_plat *plat = dev_get_platdata(host->mmc->dev);
  175. u32 reg;
  176. reg = sdhci_readw(host, EMMC_CTRL_R);
  177. if (IS_SD(host->mmc)) {
  178. reg &=~EMMC_CARD;
  179. } else {
  180. reg |=EMMC_CARD;
  181. }
  182. sdhci_writeb(host, reg, EMMC_CTRL_R);
  183. if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
  184. reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  185. reg |= SDHCI_CTRL_VDD_180;
  186. sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
  187. sdhci_phy_1_8v_init(host);
  188. } else {
  189. reg = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  190. reg &= ~SDHCI_CTRL_VDD_180;
  191. if (plat->io_fixed_1v8)
  192. reg |= SDHCI_CTRL_VDD_180;
  193. sdhci_writew(host, reg, SDHCI_HOST_CONTROL2);
  194. sdhci_phy_3_3v_init(host);
  195. }
  196. snps_set_uhs_timing(host);
  197. }
  198. extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data);
  199. static int snps_execute_tuning(struct mmc *mmc, u8 opcode)
  200. {
  201. #define SDHCI_TUNING_LOOP_COUNT 128
  202. struct sdhci_host *host = dev_get_priv(mmc->dev);
  203. struct mmc_cmd cmd;
  204. struct mmc_data data;
  205. char tuning_loop_counter = SDHCI_TUNING_LOOP_COUNT;
  206. uint32_t val = 0;
  207. uint16_t ctrl = 0;
  208. debug("%s\n", __func__);
  209. sdhci_writeb(host, 3 << INPSEL_CNFG, PHY_ATDL_CNFG_R);
  210. val = sdhci_readl(host, AT_CTRL_R);
  211. val &= ~((1 << CI_SEL) | (1 << RPT_TUNE_ERR)\
  212. | (1 << SW_TUNE_EN) |(0xf << WIN_EDGE_SEL));
  213. val |= (1 << AT_EN) | (1 << SWIN_TH_EN) | (1 << TUNE_CLK_STOP_EN)\
  214. | (1 << PRE_CHANGE_DLY) | (3 << POST_CHANGE_DLY) | (9 << SWIN_TH_VAL);
  215. sdhci_writel(host, val, AT_CTRL_R);
  216. val = sdhci_readl(host, AT_CTRL_R);
  217. if(!(val & (1 << AT_EN))) {
  218. printf("*****Auto Tuning is NOT Enable!!!\n");
  219. return -1;
  220. }
  221. //Start Tuning
  222. ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  223. ctrl |= SDHCI_CTRL_EXEC_TUNING;
  224. sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
  225. mdelay(1);
  226. do {
  227. cmd.cmdidx = opcode;
  228. cmd.resp_type = MMC_RSP_R1;
  229. cmd.cmdarg = 0;
  230. data.blocksize = 64;
  231. data.blocks = 1;
  232. data.flags = MMC_DATA_READ;
  233. if (tuning_loop_counter-- == 0)
  234. break;
  235. if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK_HS200 &&
  236. mmc->bus_width == 8)
  237. data.blocksize = 128;
  238. sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
  239. data.blocksize),
  240. SDHCI_BLOCK_SIZE);
  241. sdhci_writew(host, data.blocks, SDHCI_BLOCK_COUNT);
  242. sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
  243. mmc_send_cmd(mmc, &cmd, NULL);
  244. ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  245. if (cmd.cmdidx == MMC_CMD_SEND_TUNING_BLOCK)
  246. udelay(1);
  247. } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
  248. if (tuning_loop_counter < 0) {
  249. ctrl &= ~SDHCI_CTRL_TUNED_CLK;
  250. sdhci_writel(host, ctrl, SDHCI_HOST_CONTROL2);
  251. }
  252. if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
  253. printf("%s:Tuning failed\n", __func__);
  254. return -1;
  255. }
  256. return 0;
  257. }
  258. const struct sdhci_ops snps_ops = {
  259. .platform_execute_tuning = &snps_execute_tuning,
  260. .set_control_reg = &snps_sdhci_set_control_reg,
  261. };
  262. static int snps_sdhci_probe(struct udevice *dev)
  263. {
  264. struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
  265. struct snps_sdhci_plat *plat = dev_get_platdata(dev);
  266. struct sdhci_host *host = dev_get_priv(dev);
  267. u32 max_clk;
  268. struct clk clk;
  269. int ret;
  270. ret = clk_get_by_index(dev, 0, &clk);
  271. if (ret)
  272. return ret;
  273. plat->pull_up_en = false;
  274. plat->io_fixed_1v8 = false;
  275. host->name = dev->name;
  276. host->ioaddr = (void *)devfdt_get_addr(dev);
  277. max_clk = clk_get_rate(&clk);
  278. if (IS_ERR_VALUE(max_clk)) {
  279. ret = max_clk;
  280. goto err;
  281. }
  282. host->mmc = &plat->mmc;
  283. host->mmc->dev = dev;
  284. host->mmc->priv = host;
  285. upriv->mmc = host->mmc;
  286. host->ops = &snps_ops;
  287. ret = mmc_of_parse(dev, &plat->cfg);
  288. if (ret)
  289. goto err;
  290. ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
  291. if (ret)
  292. goto err;
  293. host->voltages = MMC_VDD_33_34;
  294. ret = sdhci_probe(dev);
  295. if (ret)
  296. goto err;
  297. if (dev_read_bool(dev, "pull_up"))
  298. plat->pull_up_en = true;
  299. if (dev_read_bool(dev, "io_fixed_1v8"))
  300. plat->io_fixed_1v8 = true;
  301. uint16_t val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  302. if (host->voltages == MMC_VDD_165_195) {
  303. val |= SDHCI_CTRL_VDD_180;
  304. sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
  305. sdhci_phy_1_8v_init(host);
  306. } else {
  307. val &= ~SDHCI_CTRL_VDD_180;
  308. if (plat->io_fixed_1v8)
  309. val |= SDHCI_CTRL_VDD_180;
  310. sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
  311. sdhci_phy_3_3v_init(host);
  312. }
  313. host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
  314. return 0;
  315. err:
  316. clk_disable(&clk);
  317. clk_free(&clk);
  318. return ret;
  319. }
  320. int snps_sdhci_init(struct mmc *mmc)
  321. {
  322. struct sdhci_host *host = dev_get_priv(mmc->dev);
  323. struct snps_sdhci_plat *plat = dev_get_platdata(host->mmc->dev);
  324. int ret;
  325. host->voltages = MMC_VDD_33_34;
  326. ret = sdhci_probe(mmc->dev);
  327. if (ret)
  328. return -1;
  329. uint16_t val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
  330. if (host->voltages == MMC_VDD_165_195) {
  331. val |= SDHCI_CTRL_VDD_180;
  332. sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
  333. sdhci_phy_1_8v_init(host);
  334. } else {
  335. val &= ~SDHCI_CTRL_VDD_180;
  336. if (plat->io_fixed_1v8)
  337. val |= SDHCI_CTRL_VDD_180;
  338. sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
  339. sdhci_phy_3_3v_init(host);
  340. }
  341. return 0;
  342. }
  343. static int snps_sdhci_bind(struct udevice *dev)
  344. {
  345. struct snps_sdhci_plat *plat = dev_get_platdata(dev);
  346. return sdhci_bind(dev, &plat->mmc, &plat->cfg);
  347. }
  348. static const struct udevice_id snps_sdhci_ids[] = {
  349. { .compatible = "snps,dwcmshc-sdhci" },
  350. { }
  351. };
  352. U_BOOT_DRIVER(snps_sdhci_drv) = {
  353. .name = "snps_sdhci",
  354. .id = UCLASS_MMC,
  355. .of_match = snps_sdhci_ids,
  356. .ops = &sdhci_ops,
  357. .bind = snps_sdhci_bind,
  358. .probe = snps_sdhci_probe,
  359. .priv_auto_alloc_size = sizeof(struct sdhci_host),
  360. .platdata_auto_alloc_size = sizeof(struct snps_sdhci_plat),
  361. };