ufs_pm.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-02-25 GuEe-GUI the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include <drivers/ufs.h>
  14. #define DBG_TAG "rtdm.ufs.pm"
  15. #define DBG_LVL DBG_INFO
  16. #include <rtdbg.h>
  17. #define RT_UFS_DME_ATTR_SET_NOR 0
  18. rt_inline rt_uint32_t ufs_uic_arg_attr_type(rt_uint8_t t)
  19. {
  20. return ((rt_uint32_t)(t) & 0xffu) << 16;
  21. }
  22. rt_err_t rt_ufs_dme_set(struct rt_ufs_host *ufs, rt_uint32_t attr_sel, rt_uint32_t value)
  23. {
  24. rt_err_t err;
  25. rt_uint32_t arg2 = ufs_uic_arg_attr_type(RT_UFS_DME_ATTR_SET_NOR);
  26. if ((err = rt_ufs_uic_cmd_send(ufs, RT_UFS_CMDOP_DME_SET, attr_sel, &arg2, value)))
  27. {
  28. return err;
  29. }
  30. if ((arg2 & RT_UFS_CMDRES_MASK) != RT_UFS_CMDRES_SUCCESS)
  31. {
  32. return -RT_ERROR;
  33. }
  34. return RT_EOK;
  35. }
  36. rt_err_t rt_ufs_dme_get(struct rt_ufs_host *ufs, rt_uint32_t attr_sel, rt_uint32_t *value)
  37. {
  38. rt_uint32_t arg2 = 0;
  39. rt_err_t err;
  40. if (!value)
  41. {
  42. return -RT_EINVAL;
  43. }
  44. if ((err = rt_ufs_uic_cmd_send(ufs, RT_UFS_CMDOP_DME_GET, attr_sel, &arg2, 0)))
  45. {
  46. return err;
  47. }
  48. if ((arg2 & RT_UFS_CMDRES_MASK) != RT_UFS_CMDRES_SUCCESS)
  49. {
  50. return -RT_ERROR;
  51. }
  52. *value = HWREG32(ufs->regs + RT_UFS_REG_UCMDARG3);
  53. return RT_EOK;
  54. }
  55. rt_err_t rt_ufs_uic_pa_pwrmode(struct rt_ufs_host *ufs, rt_uint8_t mode)
  56. {
  57. return rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_PWRMODE), mode);
  58. }
  59. rt_err_t rt_ufs_pa_power_mode_set(struct rt_ufs_host *ufs, const struct rt_ufs_pa_layer_attr *attr, rt_bool_t force)
  60. {
  61. rt_err_t err;
  62. rt_uint8_t mode;
  63. if (!ufs || !attr || !ufs->regs)
  64. {
  65. return -RT_EINVAL;
  66. }
  67. if (!force && ufs->pwr_active_valid &&
  68. attr->gear_rx == ufs->pwr_active.gear_rx &&
  69. attr->gear_tx == ufs->pwr_active.gear_tx &&
  70. attr->lane_rx == ufs->pwr_active.lane_rx &&
  71. attr->lane_tx == ufs->pwr_active.lane_tx &&
  72. attr->pwr_rx == ufs->pwr_active.pwr_rx &&
  73. attr->pwr_tx == ufs->pwr_active.pwr_tx &&
  74. attr->hs_rate == ufs->pwr_active.hs_rate)
  75. {
  76. return RT_EOK;
  77. }
  78. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_RXGEAR), attr->gear_rx)))
  79. {
  80. return err;
  81. }
  82. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_ACTIVERXDATALANES), attr->lane_rx)))
  83. {
  84. return err;
  85. }
  86. if (attr->pwr_rx == RT_UFS_PA_FASTAUTO_MODE || attr->pwr_rx == RT_UFS_PA_FAST_MODE)
  87. {
  88. err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_RXTERMINATION), 1);
  89. }
  90. else
  91. {
  92. err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_RXTERMINATION), 0);
  93. }
  94. if (err)
  95. {
  96. return err;
  97. }
  98. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_TXGEAR), attr->gear_tx)))
  99. {
  100. return err;
  101. }
  102. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_ACTIVETXDATALANES), attr->lane_tx)))
  103. {
  104. return err;
  105. }
  106. if (attr->pwr_tx == RT_UFS_PA_FASTAUTO_MODE || attr->pwr_tx == RT_UFS_PA_FAST_MODE)
  107. {
  108. err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_TXTERMINATION), 1);
  109. }
  110. else
  111. {
  112. err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_TXTERMINATION), 0);
  113. }
  114. if (err)
  115. {
  116. return err;
  117. }
  118. if (attr->pwr_rx == RT_UFS_PA_FASTAUTO_MODE || attr->pwr_tx == RT_UFS_PA_FASTAUTO_MODE ||
  119. attr->pwr_rx == RT_UFS_PA_FAST_MODE || attr->pwr_tx == RT_UFS_PA_FAST_MODE)
  120. {
  121. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_HSSERIES), attr->hs_rate)))
  122. {
  123. return err;
  124. }
  125. }
  126. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_PWRMODEUSERDATA0), RT_UFS_DL_FC0_PROT_TO_DEFAULT)))
  127. {
  128. return err;
  129. }
  130. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_PWRMODEUSERDATA1), RT_UFS_DL_TC0_REPLAY_TO_DEFAULT)))
  131. {
  132. return err;
  133. }
  134. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_PWRMODEUSERDATA2), RT_UFS_DL_AFC0_REQ_TO_DEFAULT)))
  135. {
  136. return err;
  137. }
  138. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_PWRMODEUSERDATA3), RT_UFS_DL_FC1_PROT_TO_DEFAULT)))
  139. {
  140. return err;
  141. }
  142. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_PWRMODEUSERDATA4), RT_UFS_DL_TC1_REPLAY_TO_DEFAULT)))
  143. {
  144. return err;
  145. }
  146. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_PA_PWRMODEUSERDATA5), RT_UFS_DL_AFC1_REQ_TO_DEFAULT)))
  147. {
  148. return err;
  149. }
  150. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_DME_LOCAL_FC0_PROT_TO), RT_UFS_DL_FC0_PROT_TO_DEFAULT)))
  151. {
  152. return err;
  153. }
  154. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_DME_LOCAL_TC0_REPLAY_TO), RT_UFS_DL_TC0_REPLAY_TO_DEFAULT)))
  155. {
  156. return err;
  157. }
  158. if ((err = rt_ufs_dme_set(ufs, RT_UFS_UIC_ARG_MIB(RT_UFS_DME_LOCAL_AFC0_REQ_TO), RT_UFS_DL_AFC0_REQ_TO_DEFAULT)))
  159. {
  160. return err;
  161. }
  162. mode = (rt_uint8_t)((attr->pwr_rx << 4) | (attr->pwr_tx & 0xfu));
  163. if ((err = rt_ufs_uic_pa_pwrmode(ufs, mode)))
  164. {
  165. LOG_E("%s: PA power mode change failed: %s", rt_dm_dev_get_name(ufs->parent.dev), rt_strerror(err));
  166. return err;
  167. }
  168. ufs->pwr_active = *attr;
  169. ufs->pwr_active_valid = 1;
  170. return RT_EOK;
  171. }
  172. rt_err_t rt_ufs_hibern8_enter(struct rt_ufs_host *ufs)
  173. {
  174. rt_uint32_t arg2 = 0;
  175. if (!ufs || !ufs->regs)
  176. {
  177. return -RT_EINVAL;
  178. }
  179. if (rt_ufs_uic_cmd_send(ufs, RT_UFS_CMDOP_DME_HIBERNATE_ENTER, 0, &arg2, 0))
  180. {
  181. return -RT_ERROR;
  182. }
  183. if ((arg2 & RT_UFS_CMDRES_MASK) != RT_UFS_CMDRES_SUCCESS)
  184. {
  185. return -RT_ERROR;
  186. }
  187. return RT_EOK;
  188. }
  189. rt_err_t rt_ufs_hibern8_exit(struct rt_ufs_host *ufs)
  190. {
  191. rt_uint32_t arg2 = 0;
  192. if (!ufs || !ufs->regs)
  193. {
  194. return -RT_EINVAL;
  195. }
  196. if (rt_ufs_uic_cmd_send(ufs, RT_UFS_CMDOP_DME_HIBERNATE_EXIT, 0, &arg2, 0))
  197. {
  198. return -RT_ERROR;
  199. }
  200. if ((arg2 & RT_UFS_CMDRES_MASK) != RT_UFS_CMDRES_SUCCESS)
  201. {
  202. return -RT_ERROR;
  203. }
  204. return RT_EOK;
  205. }
  206. rt_err_t rt_ufs_auto_hibern8_set(struct rt_ufs_host *ufs, rt_uint32_t reg_val)
  207. {
  208. if (!ufs || !ufs->regs)
  209. {
  210. return -RT_EINVAL;
  211. }
  212. if (!(ufs->cap & RT_UFS_REG_CAP_AUTOH8))
  213. {
  214. return -RT_ENOSYS;
  215. }
  216. HWREG32(ufs->regs + RT_UFS_REG_AHIT) = reg_val;
  217. ufs->ahit = reg_val;
  218. return RT_EOK;
  219. }
  220. void rt_ufs_intr_aggr_configure(struct rt_ufs_host *ufs, rt_bool_t enable, rt_uint8_t cnt, rt_uint8_t timeout)
  221. {
  222. void *regs;
  223. if (!ufs || !(regs = ufs->regs))
  224. {
  225. return;
  226. }
  227. if (!enable)
  228. {
  229. HWREG32(regs + RT_UFS_REG_UTRIACR) = 0;
  230. return;
  231. }
  232. /* Same layout as Linux ufshcd_config_intr_aggr */
  233. HWREG32(regs + RT_UFS_REG_UTRIACR) = RT_UFS_UTRIACR_ENABLE_PARAMS(cnt, timeout);
  234. }
  235. void rt_ufs_pm_post_linkup(struct rt_ufs_host *ufs)
  236. {
  237. rt_uint8_t cnt;
  238. if (!ufs || !ufs->regs)
  239. {
  240. return;
  241. }
  242. /* Linux INT_AGGR_DEF_TO = 2 (~80µs), counter = nutrs - 1 */
  243. cnt = (ufs->nutrs > 0) ? (rt_uint8_t)(ufs->nutrs - 1) : 0;
  244. if (cnt > 31)
  245. {
  246. cnt = 31;
  247. }
  248. rt_ufs_intr_aggr_configure(ufs, RT_TRUE, cnt, 2);
  249. if (ufs->cap & RT_UFS_REG_CAP_AUTOH8)
  250. {
  251. rt_uint32_t ahit = ufs->ahit ? ufs->ahit : RT_UFS_AHIT_DEFAULT;
  252. if (rt_ufs_auto_hibern8_set(ufs, ahit))
  253. {
  254. LOG_W("%s: Auto-Hibernate8 (AHIT) not applied", rt_dm_dev_get_name(ufs->parent.dev));
  255. }
  256. else
  257. {
  258. LOG_D("%s: AHIT=%#08x (auto-Hibernate8)", rt_dm_dev_get_name(ufs->parent.dev), ahit);
  259. }
  260. }
  261. }