cm33xx.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. * AM33XX CM functions
  3. *
  4. * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
  5. * Vaibhav Hiremath <hvaibhav@ti.com>
  6. *
  7. * Reference taken from from OMAP4 cminst44xx.c
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation version 2.
  12. *
  13. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  14. * kind, whether express or implied; without even the implied warranty
  15. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. */
  18. #include <linux/kernel.h>
  19. #include <linux/types.h>
  20. #include <linux/errno.h>
  21. #include <linux/err.h>
  22. #include <linux/io.h>
  23. #include "../plat-omap/common.h"
  24. #include "clockdomain.h"
  25. #include "cm.h"
  26. #include "cm33xx.h"
  27. #include "cm-regbits-34xx.h"
  28. #include "cm-regbits-33xx.h"
  29. #include "prm33xx.h"
  30. /*
  31. * CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
  32. *
  33. * 0x0 func: Module is fully functional, including OCP
  34. * 0x1 trans: Module is performing transition: wakeup, or sleep, or sleep
  35. * abortion
  36. * 0x2 idle: Module is in Idle mode (only OCP part). It is functional if
  37. * using separate functional clock
  38. * 0x3 disabled: Module is disabled and cannot be accessed
  39. *
  40. */
  41. #define CLKCTRL_IDLEST_FUNCTIONAL 0x0
  42. #define CLKCTRL_IDLEST_INTRANSITION 0x1
  43. #define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
  44. #define CLKCTRL_IDLEST_DISABLED 0x3
  45. /* Private functions */
  46. /* Read a register in a CM instance */
  47. static inline u32 am33xx_cm_read_reg(s16 inst, u16 idx)
  48. {
  49. return __raw_readl(cm_base + inst + idx);
  50. }
  51. /* Write into a register in a CM */
  52. static inline void am33xx_cm_write_reg(u32 val, s16 inst, u16 idx)
  53. {
  54. __raw_writel(val, cm_base + inst + idx);
  55. }
  56. /* Read-modify-write a register in CM */
  57. static inline u32 am33xx_cm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
  58. {
  59. u32 v;
  60. v = am33xx_cm_read_reg(inst, idx);
  61. v &= ~mask;
  62. v |= bits;
  63. am33xx_cm_write_reg(v, inst, idx);
  64. return v;
  65. }
  66. static inline u32 am33xx_cm_set_reg_bits(u32 bits, s16 inst, s16 idx)
  67. {
  68. return am33xx_cm_rmw_reg_bits(bits, bits, inst, idx);
  69. }
  70. static inline u32 am33xx_cm_clear_reg_bits(u32 bits, s16 inst, s16 idx)
  71. {
  72. return am33xx_cm_rmw_reg_bits(bits, 0x0, inst, idx);
  73. }
  74. static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
  75. {
  76. u32 v;
  77. v = am33xx_cm_read_reg(inst, idx);
  78. v &= mask;
  79. v >>= __ffs(mask);
  80. return v;
  81. }
  82. /**
  83. * _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
  84. * @inst: CM instance register offset (*_INST macro)
  85. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  86. * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  87. *
  88. * Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
  89. * bit 0.
  90. */
  91. static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs)
  92. {
  93. u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
  94. v &= AM33XX_IDLEST_MASK;
  95. v >>= AM33XX_IDLEST_SHIFT;
  96. return v;
  97. }
  98. /**
  99. * _is_module_ready - can module registers be accessed without causing an abort?
  100. * @inst: CM instance register offset (*_INST macro)
  101. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  102. * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  103. *
  104. * Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
  105. * *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
  106. */
  107. static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs)
  108. {
  109. u32 v;
  110. v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs);
  111. return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
  112. v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
  113. }
  114. /**
  115. * _clktrctrl_write - write @c to a CM_CLKSTCTRL.CLKTRCTRL register bitfield
  116. * @c: CLKTRCTRL register bitfield (LSB = bit 0, i.e., unshifted)
  117. * @inst: CM instance register offset (*_INST macro)
  118. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  119. *
  120. * @c must be the unshifted value for CLKTRCTRL - i.e., this function
  121. * will handle the shift itself.
  122. */
  123. static void _clktrctrl_write(u8 c, s16 inst, u16 cdoffs)
  124. {
  125. u32 v;
  126. v = am33xx_cm_read_reg(inst, cdoffs);
  127. v &= ~AM33XX_CLKTRCTRL_MASK;
  128. v |= c << AM33XX_CLKTRCTRL_SHIFT;
  129. am33xx_cm_write_reg(v, inst, cdoffs);
  130. }
  131. /* Public functions */
  132. /**
  133. * am33xx_cm_is_clkdm_in_hwsup - is a clockdomain in hwsup idle mode?
  134. * @inst: CM instance register offset (*_INST macro)
  135. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  136. *
  137. * Returns true if the clockdomain referred to by (@inst, @cdoffs)
  138. * is in hardware-supervised idle mode, or 0 otherwise.
  139. */
  140. bool am33xx_cm_is_clkdm_in_hwsup(s16 inst, u16 cdoffs)
  141. {
  142. u32 v;
  143. v = am33xx_cm_read_reg(inst, cdoffs);
  144. v &= AM33XX_CLKTRCTRL_MASK;
  145. v >>= AM33XX_CLKTRCTRL_SHIFT;
  146. return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? true : false;
  147. }
  148. /**
  149. * am33xx_cm_clkdm_enable_hwsup - put a clockdomain in hwsup-idle mode
  150. * @inst: CM instance register offset (*_INST macro)
  151. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  152. *
  153. * Put a clockdomain referred to by (@inst, @cdoffs) into
  154. * hardware-supervised idle mode. No return value.
  155. */
  156. void am33xx_cm_clkdm_enable_hwsup(s16 inst, u16 cdoffs)
  157. {
  158. _clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
  159. }
  160. /**
  161. * am33xx_cm_clkdm_disable_hwsup - put a clockdomain in swsup-idle mode
  162. * @inst: CM instance register offset (*_INST macro)
  163. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  164. *
  165. * Put a clockdomain referred to by (@inst, @cdoffs) into
  166. * software-supervised idle mode, i.e., controlled manually by the
  167. * Linux OMAP clockdomain code. No return value.
  168. */
  169. void am33xx_cm_clkdm_disable_hwsup(s16 inst, u16 cdoffs)
  170. {
  171. _clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
  172. }
  173. /**
  174. * am33xx_cm_clkdm_force_sleep - try to put a clockdomain into idle
  175. * @inst: CM instance register offset (*_INST macro)
  176. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  177. *
  178. * Put a clockdomain referred to by (@inst, @cdoffs) into idle
  179. * No return value.
  180. */
  181. void am33xx_cm_clkdm_force_sleep(s16 inst, u16 cdoffs)
  182. {
  183. _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
  184. }
  185. /**
  186. * am33xx_cm_clkdm_force_wakeup - try to take a clockdomain out of idle
  187. * @inst: CM instance register offset (*_INST macro)
  188. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  189. *
  190. * Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
  191. * waking it up. No return value.
  192. */
  193. void am33xx_cm_clkdm_force_wakeup(s16 inst, u16 cdoffs)
  194. {
  195. _clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
  196. }
  197. /*
  198. *
  199. */
  200. /**
  201. * am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
  202. * @inst: CM instance register offset (*_INST macro)
  203. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  204. * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  205. *
  206. * Wait for the module IDLEST to be functional. If the idle state is in any
  207. * the non functional state (trans, idle or disabled), module and thus the
  208. * sysconfig cannot be accessed and will probably lead to an "imprecise
  209. * external abort"
  210. */
  211. int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs)
  212. {
  213. int i = 0;
  214. if (!clkctrl_offs)
  215. return 0;
  216. omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs),
  217. MAX_MODULE_READY_TIME, i);
  218. return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
  219. }
  220. /**
  221. * am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
  222. * state
  223. * @inst: CM instance register offset (*_INST macro)
  224. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  225. * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  226. *
  227. * Wait for the module IDLEST to be disabled. Some PRCM transition,
  228. * like reset assertion or parent clock de-activation must wait the
  229. * module to be fully disabled.
  230. */
  231. int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs)
  232. {
  233. int i = 0;
  234. if (!clkctrl_offs)
  235. return 0;
  236. omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) ==
  237. CLKCTRL_IDLEST_DISABLED),
  238. MAX_MODULE_READY_TIME, i);
  239. return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
  240. }
  241. /**
  242. * am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
  243. * @mode: Module mode (SW or HW)
  244. * @inst: CM instance register offset (*_INST macro)
  245. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  246. * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  247. *
  248. * No return value.
  249. */
  250. void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs)
  251. {
  252. u32 v;
  253. v = am33xx_cm_read_reg(inst, clkctrl_offs);
  254. v &= ~AM33XX_MODULEMODE_MASK;
  255. v |= mode << AM33XX_MODULEMODE_SHIFT;
  256. am33xx_cm_write_reg(v, inst, clkctrl_offs);
  257. }
  258. /**
  259. * am33xx_cm_module_disable - Disable the module inside CLKCTRL
  260. * @inst: CM instance register offset (*_INST macro)
  261. * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
  262. * @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
  263. *
  264. * No return value.
  265. */
  266. void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs)
  267. {
  268. u32 v;
  269. v = am33xx_cm_read_reg(inst, clkctrl_offs);
  270. v &= ~AM33XX_MODULEMODE_MASK;
  271. am33xx_cm_write_reg(v, inst, clkctrl_offs);
  272. }
  273. /*
  274. * Clockdomain low-level functions
  275. */
  276. static int am33xx_clkdm_sleep(struct clockdomain *clkdm)
  277. {
  278. am33xx_cm_clkdm_force_sleep(clkdm->cm_inst, clkdm->clkdm_offs);
  279. return 0;
  280. }
  281. static int am33xx_clkdm_wakeup(struct clockdomain *clkdm)
  282. {
  283. am33xx_cm_clkdm_force_wakeup(clkdm->cm_inst, clkdm->clkdm_offs);
  284. return 0;
  285. }
  286. static void am33xx_clkdm_allow_idle(struct clockdomain *clkdm)
  287. {
  288. am33xx_cm_clkdm_enable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
  289. }
  290. static void am33xx_clkdm_deny_idle(struct clockdomain *clkdm)
  291. {
  292. am33xx_cm_clkdm_disable_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
  293. }
  294. static int am33xx_clkdm_clk_enable(struct clockdomain *clkdm)
  295. {
  296. if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
  297. return am33xx_clkdm_wakeup(clkdm);
  298. return 0;
  299. }
  300. static int am33xx_clkdm_clk_disable(struct clockdomain *clkdm)
  301. {
  302. bool hwsup = false;
  303. hwsup = am33xx_cm_is_clkdm_in_hwsup(clkdm->cm_inst, clkdm->clkdm_offs);
  304. if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
  305. am33xx_clkdm_sleep(clkdm);
  306. return 0;
  307. }
  308. struct clkdm_ops am33xx_clkdm_operations = {
  309. .clkdm_sleep = am33xx_clkdm_sleep,
  310. .clkdm_wakeup = am33xx_clkdm_wakeup,
  311. .clkdm_allow_idle = am33xx_clkdm_allow_idle,
  312. .clkdm_deny_idle = am33xx_clkdm_deny_idle,
  313. .clkdm_clk_enable = am33xx_clkdm_clk_enable,
  314. .clkdm_clk_disable = am33xx_clkdm_clk_disable,
  315. };