clockdomain.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. /*
  2. * OMAP2/3/4 clockdomain framework functions
  3. *
  4. * Copyright (C) 2008-2010 Texas Instruments, Inc.
  5. * Copyright (C) 2008-2010 Nokia Corporation
  6. *
  7. * Written by Paul Walmsley and Jouni Högander
  8. * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. */
  14. #undef DEBUG
  15. #include <linux/kernel.h>
  16. #include <linux/device.h>
  17. #include <linux/list.h>
  18. #include <linux/errno.h>
  19. #include <linux/delay.h>
  20. #include <linux/clk.h>
  21. #include <linux/limits.h>
  22. #include <linux/err.h>
  23. #include <linux/io.h>
  24. #include <linux/bitops.h>
  25. #include "prm2xxx_3xxx.h"
  26. #include "prm-regbits-24xx.h"
  27. #include "cm2xxx_3xxx.h"
  28. #include "cm-regbits-24xx.h"
  29. #include "cminst44xx.h"
  30. #include "prcm44xx.h"
  31. #include <plat/clock.h>
  32. #include "powerdomain.h"
  33. #include "clockdomain.h"
  34. #include <plat/prcm.h>
  35. /* clkdm_list contains all registered struct clockdomains */
  36. static LIST_HEAD(clkdm_list);
  37. /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */
  38. static struct clkdm_autodep *autodeps;
  39. static struct clkdm_ops *arch_clkdm;
  40. /* Private functions */
  41. static struct clockdomain *_clkdm_lookup(const char *name)
  42. {
  43. struct clockdomain *clkdm, *temp_clkdm;
  44. if (!name)
  45. return NULL;
  46. clkdm = NULL;
  47. list_for_each_entry(temp_clkdm, &clkdm_list, node) {
  48. if (!strcmp(name, temp_clkdm->name)) {
  49. clkdm = temp_clkdm;
  50. break;
  51. }
  52. }
  53. return clkdm;
  54. }
  55. /**
  56. * _clkdm_register - register a clockdomain
  57. * @clkdm: struct clockdomain * to register
  58. *
  59. * Adds a clockdomain to the internal clockdomain list.
  60. * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is
  61. * already registered by the provided name, or 0 upon success.
  62. */
  63. static int _clkdm_register(struct clockdomain *clkdm)
  64. {
  65. struct powerdomain *pwrdm;
  66. if (!clkdm || !clkdm->name)
  67. return -EINVAL;
  68. if (!omap_chip_is(clkdm->omap_chip))
  69. return -EINVAL;
  70. pwrdm = pwrdm_lookup(clkdm->pwrdm.name);
  71. if (!pwrdm) {
  72. pr_err("clockdomain: %s: powerdomain %s does not exist\n",
  73. clkdm->name, clkdm->pwrdm.name);
  74. return -EINVAL;
  75. }
  76. clkdm->pwrdm.ptr = pwrdm;
  77. /* Verify that the clockdomain is not already registered */
  78. if (_clkdm_lookup(clkdm->name))
  79. return -EEXIST;
  80. list_add(&clkdm->node, &clkdm_list);
  81. pwrdm_add_clkdm(pwrdm, clkdm);
  82. pr_debug("clockdomain: registered %s\n", clkdm->name);
  83. return 0;
  84. }
  85. /* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */
  86. static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
  87. struct clkdm_dep *deps)
  88. {
  89. struct clkdm_dep *cd;
  90. if (!clkdm || !deps || !omap_chip_is(clkdm->omap_chip))
  91. return ERR_PTR(-EINVAL);
  92. for (cd = deps; cd->clkdm_name; cd++) {
  93. if (!omap_chip_is(cd->omap_chip))
  94. continue;
  95. if (!cd->clkdm && cd->clkdm_name)
  96. cd->clkdm = _clkdm_lookup(cd->clkdm_name);
  97. if (cd->clkdm == clkdm)
  98. break;
  99. }
  100. if (!cd->clkdm_name)
  101. return ERR_PTR(-ENOENT);
  102. return cd;
  103. }
  104. /*
  105. * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store
  106. * @autodep: struct clkdm_autodep * to resolve
  107. *
  108. * Resolve autodep clockdomain names to clockdomain pointers via
  109. * clkdm_lookup() and store the pointers in the autodep structure. An
  110. * "autodep" is a clockdomain sleep/wakeup dependency that is
  111. * automatically added and removed whenever clocks in the associated
  112. * clockdomain are enabled or disabled (respectively) when the
  113. * clockdomain is in hardware-supervised mode. Meant to be called
  114. * once at clockdomain layer initialization, since these should remain
  115. * fixed for a particular architecture. No return value.
  116. *
  117. * XXX autodeps are deprecated and should be removed at the earliest
  118. * opportunity
  119. */
  120. static void _autodep_lookup(struct clkdm_autodep *autodep)
  121. {
  122. struct clockdomain *clkdm;
  123. if (!autodep)
  124. return;
  125. if (!omap_chip_is(autodep->omap_chip))
  126. return;
  127. clkdm = clkdm_lookup(autodep->clkdm.name);
  128. if (!clkdm) {
  129. pr_err("clockdomain: autodeps: clockdomain %s does not exist\n",
  130. autodep->clkdm.name);
  131. clkdm = ERR_PTR(-ENOENT);
  132. }
  133. autodep->clkdm.ptr = clkdm;
  134. }
  135. /*
  136. * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
  137. * @clkdm: struct clockdomain *
  138. *
  139. * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
  140. * in hardware-supervised mode. Meant to be called from clock framework
  141. * when a clock inside clockdomain 'clkdm' is enabled. No return value.
  142. *
  143. * XXX autodeps are deprecated and should be removed at the earliest
  144. * opportunity
  145. */
  146. static void _clkdm_add_autodeps(struct clockdomain *clkdm)
  147. {
  148. struct clkdm_autodep *autodep;
  149. if (!autodeps)
  150. return;
  151. for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
  152. if (IS_ERR(autodep->clkdm.ptr))
  153. continue;
  154. if (!omap_chip_is(autodep->omap_chip))
  155. continue;
  156. pr_debug("clockdomain: adding %s sleepdep/wkdep for "
  157. "clkdm %s\n", autodep->clkdm.ptr->name,
  158. clkdm->name);
  159. clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
  160. clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
  161. }
  162. }
  163. /*
  164. * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
  165. * @clkdm: struct clockdomain *
  166. *
  167. * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
  168. * in hardware-supervised mode. Meant to be called from clock framework
  169. * when a clock inside clockdomain 'clkdm' is disabled. No return value.
  170. *
  171. * XXX autodeps are deprecated and should be removed at the earliest
  172. * opportunity
  173. */
  174. static void _clkdm_del_autodeps(struct clockdomain *clkdm)
  175. {
  176. struct clkdm_autodep *autodep;
  177. if (!autodeps)
  178. return;
  179. for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
  180. if (IS_ERR(autodep->clkdm.ptr))
  181. continue;
  182. if (!omap_chip_is(autodep->omap_chip))
  183. continue;
  184. pr_debug("clockdomain: removing %s sleepdep/wkdep for "
  185. "clkdm %s\n", autodep->clkdm.ptr->name,
  186. clkdm->name);
  187. clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
  188. clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
  189. }
  190. }
  191. /**
  192. * _enable_hwsup - place a clockdomain into hardware-supervised idle
  193. * @clkdm: struct clockdomain *
  194. *
  195. * Place the clockdomain into hardware-supervised idle mode. No return
  196. * value.
  197. *
  198. * XXX Should this return an error if the clockdomain does not support
  199. * hardware-supervised idle mode?
  200. */
  201. static void _enable_hwsup(struct clockdomain *clkdm)
  202. {
  203. if (cpu_is_omap24xx())
  204. omap2xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
  205. clkdm->clktrctrl_mask);
  206. else if (cpu_is_omap34xx())
  207. omap3xxx_cm_clkdm_enable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
  208. clkdm->clktrctrl_mask);
  209. else if (cpu_is_omap44xx())
  210. return omap4_cminst_clkdm_enable_hwsup(clkdm->prcm_partition,
  211. clkdm->cm_inst,
  212. clkdm->clkdm_offs);
  213. else
  214. BUG();
  215. }
  216. /**
  217. * _disable_hwsup - place a clockdomain into software-supervised idle
  218. * @clkdm: struct clockdomain *
  219. *
  220. * Place the clockdomain @clkdm into software-supervised idle mode.
  221. * No return value.
  222. *
  223. * XXX Should this return an error if the clockdomain does not support
  224. * software-supervised idle mode?
  225. */
  226. static void _disable_hwsup(struct clockdomain *clkdm)
  227. {
  228. if (cpu_is_omap24xx())
  229. omap2xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
  230. clkdm->clktrctrl_mask);
  231. else if (cpu_is_omap34xx())
  232. omap3xxx_cm_clkdm_disable_hwsup(clkdm->pwrdm.ptr->prcm_offs,
  233. clkdm->clktrctrl_mask);
  234. else if (cpu_is_omap44xx())
  235. return omap4_cminst_clkdm_disable_hwsup(clkdm->prcm_partition,
  236. clkdm->cm_inst,
  237. clkdm->clkdm_offs);
  238. else
  239. BUG();
  240. }
  241. /* Public functions */
  242. /**
  243. * clkdm_init - set up the clockdomain layer
  244. * @clkdms: optional pointer to an array of clockdomains to register
  245. * @init_autodeps: optional pointer to an array of autodeps to register
  246. * @custom_funcs: func pointers for arch specfic implementations
  247. *
  248. * Set up internal state. If a pointer to an array of clockdomains
  249. * @clkdms was supplied, loop through the list of clockdomains,
  250. * register all that are available on the current platform. Similarly,
  251. * if a pointer to an array of clockdomain autodependencies
  252. * @init_autodeps was provided, register those. No return value.
  253. */
  254. void clkdm_init(struct clockdomain **clkdms,
  255. struct clkdm_autodep *init_autodeps,
  256. struct clkdm_ops *custom_funcs)
  257. {
  258. struct clockdomain **c = NULL;
  259. struct clockdomain *clkdm;
  260. struct clkdm_autodep *autodep = NULL;
  261. if (!custom_funcs)
  262. WARN(1, "No custom clkdm functions registered\n");
  263. else
  264. arch_clkdm = custom_funcs;
  265. if (clkdms)
  266. for (c = clkdms; *c; c++)
  267. _clkdm_register(*c);
  268. autodeps = init_autodeps;
  269. if (autodeps)
  270. for (autodep = autodeps; autodep->clkdm.ptr; autodep++)
  271. _autodep_lookup(autodep);
  272. /*
  273. * Put all clockdomains into software-supervised mode; PM code
  274. * should later enable hardware-supervised mode as appropriate
  275. */
  276. list_for_each_entry(clkdm, &clkdm_list, node) {
  277. if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
  278. omap2_clkdm_wakeup(clkdm);
  279. else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
  280. omap2_clkdm_deny_idle(clkdm);
  281. clkdm_clear_all_wkdeps(clkdm);
  282. clkdm_clear_all_sleepdeps(clkdm);
  283. }
  284. }
  285. /**
  286. * clkdm_lookup - look up a clockdomain by name, return a pointer
  287. * @name: name of clockdomain
  288. *
  289. * Find a registered clockdomain by its name @name. Returns a pointer
  290. * to the struct clockdomain if found, or NULL otherwise.
  291. */
  292. struct clockdomain *clkdm_lookup(const char *name)
  293. {
  294. struct clockdomain *clkdm, *temp_clkdm;
  295. if (!name)
  296. return NULL;
  297. clkdm = NULL;
  298. list_for_each_entry(temp_clkdm, &clkdm_list, node) {
  299. if (!strcmp(name, temp_clkdm->name)) {
  300. clkdm = temp_clkdm;
  301. break;
  302. }
  303. }
  304. return clkdm;
  305. }
  306. /**
  307. * clkdm_for_each - call function on each registered clockdomain
  308. * @fn: callback function *
  309. *
  310. * Call the supplied function @fn for each registered clockdomain.
  311. * The callback function @fn can return anything but 0 to bail
  312. * out early from the iterator. The callback function is called with
  313. * the clkdm_mutex held, so no clockdomain structure manipulation
  314. * functions should be called from the callback, although hardware
  315. * clockdomain control functions are fine. Returns the last return
  316. * value of the callback function, which should be 0 for success or
  317. * anything else to indicate failure; or -EINVAL if the function pointer
  318. * is null.
  319. */
  320. int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user),
  321. void *user)
  322. {
  323. struct clockdomain *clkdm;
  324. int ret = 0;
  325. if (!fn)
  326. return -EINVAL;
  327. list_for_each_entry(clkdm, &clkdm_list, node) {
  328. ret = (*fn)(clkdm, user);
  329. if (ret)
  330. break;
  331. }
  332. return ret;
  333. }
  334. /**
  335. * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in
  336. * @clkdm: struct clockdomain *
  337. *
  338. * Return a pointer to the struct powerdomain that the specified clockdomain
  339. * @clkdm exists in, or returns NULL if @clkdm is NULL.
  340. */
  341. struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
  342. {
  343. if (!clkdm)
  344. return NULL;
  345. return clkdm->pwrdm.ptr;
  346. }
  347. /* Hardware clockdomain control */
  348. /**
  349. * clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1
  350. * @clkdm1: wake this struct clockdomain * up (dependent)
  351. * @clkdm2: when this struct clockdomain * wakes up (source)
  352. *
  353. * When the clockdomain represented by @clkdm2 wakes up, wake up
  354. * @clkdm1. Implemented in hardware on the OMAP, this feature is
  355. * designed to reduce wakeup latency of the dependent clockdomain @clkdm1.
  356. * Returns -EINVAL if presented with invalid clockdomain pointers,
  357. * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon
  358. * success.
  359. */
  360. int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  361. {
  362. struct clkdm_dep *cd;
  363. if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
  364. pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
  365. clkdm1->name, clkdm2->name, __func__);
  366. return -EINVAL;
  367. }
  368. if (!clkdm1 || !clkdm2)
  369. return -EINVAL;
  370. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  371. if (IS_ERR(cd)) {
  372. pr_debug("clockdomain: hardware cannot set/clear wake up of "
  373. "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
  374. return PTR_ERR(cd);
  375. }
  376. if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
  377. pr_debug("clockdomain: hardware will wake up %s when %s wakes "
  378. "up\n", clkdm1->name, clkdm2->name);
  379. omap2_prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
  380. clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
  381. }
  382. return 0;
  383. }
  384. /**
  385. * clkdm_del_wkdep - remove a wakeup dependency from clkdm2 to clkdm1
  386. * @clkdm1: wake this struct clockdomain * up (dependent)
  387. * @clkdm2: when this struct clockdomain * wakes up (source)
  388. *
  389. * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2
  390. * wakes up. Returns -EINVAL if presented with invalid clockdomain
  391. * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or
  392. * 0 upon success.
  393. */
  394. int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  395. {
  396. struct clkdm_dep *cd;
  397. if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
  398. pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
  399. clkdm1->name, clkdm2->name, __func__);
  400. return -EINVAL;
  401. }
  402. if (!clkdm1 || !clkdm2)
  403. return -EINVAL;
  404. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  405. if (IS_ERR(cd)) {
  406. pr_debug("clockdomain: hardware cannot set/clear wake up of "
  407. "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
  408. return PTR_ERR(cd);
  409. }
  410. if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
  411. pr_debug("clockdomain: hardware will no longer wake up %s "
  412. "after %s wakes up\n", clkdm1->name, clkdm2->name);
  413. omap2_prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
  414. clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
  415. }
  416. return 0;
  417. }
  418. /**
  419. * clkdm_read_wkdep - read wakeup dependency state from clkdm2 to clkdm1
  420. * @clkdm1: wake this struct clockdomain * up (dependent)
  421. * @clkdm2: when this struct clockdomain * wakes up (source)
  422. *
  423. * Return 1 if a hardware wakeup dependency exists wherein @clkdm1 will be
  424. * awoken when @clkdm2 wakes up; 0 if dependency is not set; -EINVAL
  425. * if either clockdomain pointer is invalid; or -ENOENT if the hardware
  426. * is incapable.
  427. *
  428. * REVISIT: Currently this function only represents software-controllable
  429. * wakeup dependencies. Wakeup dependencies fixed in hardware are not
  430. * yet handled here.
  431. */
  432. int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  433. {
  434. struct clkdm_dep *cd;
  435. if (!clkdm1 || !clkdm2)
  436. return -EINVAL;
  437. if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
  438. pr_err("clockdomain: %s/%s: %s: not yet implemented\n",
  439. clkdm1->name, clkdm2->name, __func__);
  440. return -EINVAL;
  441. }
  442. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  443. if (IS_ERR(cd)) {
  444. pr_debug("clockdomain: hardware cannot set/clear wake up of "
  445. "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
  446. return PTR_ERR(cd);
  447. }
  448. /* XXX It's faster to return the atomic wkdep_usecount */
  449. return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP,
  450. (1 << clkdm2->dep_bit));
  451. }
  452. /**
  453. * clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm
  454. * @clkdm: struct clockdomain * to remove all wakeup dependencies from
  455. *
  456. * Remove all inter-clockdomain wakeup dependencies that could cause
  457. * @clkdm to wake. Intended to be used during boot to initialize the
  458. * PRCM to a known state, after all clockdomains are put into swsup idle
  459. * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
  460. * 0 upon success.
  461. */
  462. int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
  463. {
  464. struct clkdm_dep *cd;
  465. u32 mask = 0;
  466. if (!cpu_is_omap24xx() && !cpu_is_omap34xx()) {
  467. pr_err("clockdomain: %s: %s: not yet implemented\n",
  468. clkdm->name, __func__);
  469. return -EINVAL;
  470. }
  471. if (!clkdm)
  472. return -EINVAL;
  473. for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
  474. if (!omap_chip_is(cd->omap_chip))
  475. continue;
  476. if (!cd->clkdm && cd->clkdm_name)
  477. cd->clkdm = _clkdm_lookup(cd->clkdm_name);
  478. /* PRM accesses are slow, so minimize them */
  479. mask |= 1 << cd->clkdm->dep_bit;
  480. atomic_set(&cd->wkdep_usecount, 0);
  481. }
  482. omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
  483. return 0;
  484. }
  485. /**
  486. * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1
  487. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  488. * @clkdm2: when this struct clockdomain * is active (source)
  489. *
  490. * Prevent @clkdm1 from automatically going inactive (and then to
  491. * retention or off) if @clkdm2 is active. Returns -EINVAL if
  492. * presented with invalid clockdomain pointers or called on a machine
  493. * that does not support software-configurable hardware sleep
  494. * dependencies, -ENOENT if the specified dependency cannot be set in
  495. * hardware, or 0 upon success.
  496. */
  497. int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  498. {
  499. struct clkdm_dep *cd;
  500. if (!cpu_is_omap34xx())
  501. return -EINVAL;
  502. if (!clkdm1 || !clkdm2)
  503. return -EINVAL;
  504. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  505. if (IS_ERR(cd)) {
  506. pr_debug("clockdomain: hardware cannot set/clear sleep "
  507. "dependency affecting %s from %s\n", clkdm1->name,
  508. clkdm2->name);
  509. return PTR_ERR(cd);
  510. }
  511. if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
  512. pr_debug("clockdomain: will prevent %s from sleeping if %s "
  513. "is active\n", clkdm1->name, clkdm2->name);
  514. omap2_cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
  515. clkdm1->pwrdm.ptr->prcm_offs,
  516. OMAP3430_CM_SLEEPDEP);
  517. }
  518. return 0;
  519. }
  520. /**
  521. * clkdm_del_sleepdep - remove a sleep dependency from clkdm2 to clkdm1
  522. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  523. * @clkdm2: when this struct clockdomain * is active (source)
  524. *
  525. * Allow @clkdm1 to automatically go inactive (and then to retention or
  526. * off), independent of the activity state of @clkdm2. Returns -EINVAL
  527. * if presented with invalid clockdomain pointers or called on a machine
  528. * that does not support software-configurable hardware sleep dependencies,
  529. * -ENOENT if the specified dependency cannot be cleared in hardware, or
  530. * 0 upon success.
  531. */
  532. int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  533. {
  534. struct clkdm_dep *cd;
  535. if (!cpu_is_omap34xx())
  536. return -EINVAL;
  537. if (!clkdm1 || !clkdm2)
  538. return -EINVAL;
  539. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  540. if (IS_ERR(cd)) {
  541. pr_debug("clockdomain: hardware cannot set/clear sleep "
  542. "dependency affecting %s from %s\n", clkdm1->name,
  543. clkdm2->name);
  544. return PTR_ERR(cd);
  545. }
  546. if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
  547. pr_debug("clockdomain: will no longer prevent %s from "
  548. "sleeping if %s is active\n", clkdm1->name,
  549. clkdm2->name);
  550. omap2_cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
  551. clkdm1->pwrdm.ptr->prcm_offs,
  552. OMAP3430_CM_SLEEPDEP);
  553. }
  554. return 0;
  555. }
  556. /**
  557. * clkdm_read_sleepdep - read sleep dependency state from clkdm2 to clkdm1
  558. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  559. * @clkdm2: when this struct clockdomain * is active (source)
  560. *
  561. * Return 1 if a hardware sleep dependency exists wherein @clkdm1 will
  562. * not be allowed to automatically go inactive if @clkdm2 is active;
  563. * 0 if @clkdm1's automatic power state inactivity transition is independent
  564. * of @clkdm2's; -EINVAL if either clockdomain pointer is invalid or called
  565. * on a machine that does not support software-configurable hardware sleep
  566. * dependencies; or -ENOENT if the hardware is incapable.
  567. *
  568. * REVISIT: Currently this function only represents software-controllable
  569. * sleep dependencies. Sleep dependencies fixed in hardware are not
  570. * yet handled here.
  571. */
  572. int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  573. {
  574. struct clkdm_dep *cd;
  575. if (!cpu_is_omap34xx())
  576. return -EINVAL;
  577. if (!clkdm1 || !clkdm2)
  578. return -EINVAL;
  579. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  580. if (IS_ERR(cd)) {
  581. pr_debug("clockdomain: hardware cannot set/clear sleep "
  582. "dependency affecting %s from %s\n", clkdm1->name,
  583. clkdm2->name);
  584. return PTR_ERR(cd);
  585. }
  586. /* XXX It's faster to return the atomic sleepdep_usecount */
  587. return omap2_prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
  588. OMAP3430_CM_SLEEPDEP,
  589. (1 << clkdm2->dep_bit));
  590. }
  591. /**
  592. * clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm
  593. * @clkdm: struct clockdomain * to remove all sleep dependencies from
  594. *
  595. * Remove all inter-clockdomain sleep dependencies that could prevent
  596. * @clkdm from idling. Intended to be used during boot to initialize the
  597. * PRCM to a known state, after all clockdomains are put into swsup idle
  598. * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
  599. * 0 upon success.
  600. */
  601. int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
  602. {
  603. struct clkdm_dep *cd;
  604. u32 mask = 0;
  605. if (!cpu_is_omap34xx())
  606. return -EINVAL;
  607. if (!clkdm)
  608. return -EINVAL;
  609. for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
  610. if (!omap_chip_is(cd->omap_chip))
  611. continue;
  612. if (!cd->clkdm && cd->clkdm_name)
  613. cd->clkdm = _clkdm_lookup(cd->clkdm_name);
  614. /* PRM accesses are slow, so minimize them */
  615. mask |= 1 << cd->clkdm->dep_bit;
  616. atomic_set(&cd->sleepdep_usecount, 0);
  617. }
  618. omap2_prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
  619. OMAP3430_CM_SLEEPDEP);
  620. return 0;
  621. }
  622. /**
  623. * omap2_clkdm_sleep - force clockdomain sleep transition
  624. * @clkdm: struct clockdomain *
  625. *
  626. * Instruct the CM to force a sleep transition on the specified
  627. * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if
  628. * clockdomain does not support software-initiated sleep; 0 upon
  629. * success.
  630. */
  631. int omap2_clkdm_sleep(struct clockdomain *clkdm)
  632. {
  633. if (!clkdm)
  634. return -EINVAL;
  635. if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
  636. pr_debug("clockdomain: %s does not support forcing "
  637. "sleep via software\n", clkdm->name);
  638. return -EINVAL;
  639. }
  640. pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
  641. if (cpu_is_omap24xx()) {
  642. omap2_cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
  643. clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
  644. } else if (cpu_is_omap34xx()) {
  645. omap3xxx_cm_clkdm_force_sleep(clkdm->pwrdm.ptr->prcm_offs,
  646. clkdm->clktrctrl_mask);
  647. } else if (cpu_is_omap44xx()) {
  648. omap4_cminst_clkdm_force_sleep(clkdm->prcm_partition,
  649. clkdm->cm_inst,
  650. clkdm->clkdm_offs);
  651. } else {
  652. BUG();
  653. };
  654. return 0;
  655. }
  656. /**
  657. * omap2_clkdm_wakeup - force clockdomain wakeup transition
  658. * @clkdm: struct clockdomain *
  659. *
  660. * Instruct the CM to force a wakeup transition on the specified
  661. * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the
  662. * clockdomain does not support software-controlled wakeup; 0 upon
  663. * success.
  664. */
  665. int omap2_clkdm_wakeup(struct clockdomain *clkdm)
  666. {
  667. if (!clkdm)
  668. return -EINVAL;
  669. if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
  670. pr_debug("clockdomain: %s does not support forcing "
  671. "wakeup via software\n", clkdm->name);
  672. return -EINVAL;
  673. }
  674. pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
  675. if (cpu_is_omap24xx()) {
  676. omap2_cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
  677. clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
  678. } else if (cpu_is_omap34xx()) {
  679. omap3xxx_cm_clkdm_force_wakeup(clkdm->pwrdm.ptr->prcm_offs,
  680. clkdm->clktrctrl_mask);
  681. } else if (cpu_is_omap44xx()) {
  682. omap4_cminst_clkdm_force_wakeup(clkdm->prcm_partition,
  683. clkdm->cm_inst,
  684. clkdm->clkdm_offs);
  685. } else {
  686. BUG();
  687. };
  688. return 0;
  689. }
  690. /**
  691. * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
  692. * @clkdm: struct clockdomain *
  693. *
  694. * Allow the hardware to automatically switch the clockdomain @clkdm into
  695. * active or idle states, as needed by downstream clocks. If the
  696. * clockdomain has any downstream clocks enabled in the clock
  697. * framework, wkdep/sleepdep autodependencies are added; this is so
  698. * device drivers can read and write to the device. No return value.
  699. */
  700. void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
  701. {
  702. if (!clkdm)
  703. return;
  704. if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
  705. pr_debug("clock: automatic idle transitions cannot be enabled "
  706. "on clockdomain %s\n", clkdm->name);
  707. return;
  708. }
  709. pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
  710. clkdm->name);
  711. /*
  712. * XXX This should be removed once TI adds wakeup/sleep
  713. * dependency code and data for OMAP4.
  714. */
  715. if (cpu_is_omap44xx()) {
  716. pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name);
  717. } else {
  718. if (atomic_read(&clkdm->usecount) > 0)
  719. _clkdm_add_autodeps(clkdm);
  720. }
  721. _enable_hwsup(clkdm);
  722. pwrdm_clkdm_state_switch(clkdm);
  723. }
  724. /**
  725. * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm
  726. * @clkdm: struct clockdomain *
  727. *
  728. * Prevent the hardware from automatically switching the clockdomain
  729. * @clkdm into inactive or idle states. If the clockdomain has
  730. * downstream clocks enabled in the clock framework, wkdep/sleepdep
  731. * autodependencies are removed. No return value.
  732. */
  733. void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
  734. {
  735. if (!clkdm)
  736. return;
  737. if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
  738. pr_debug("clockdomain: automatic idle transitions cannot be "
  739. "disabled on %s\n", clkdm->name);
  740. return;
  741. }
  742. pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
  743. clkdm->name);
  744. _disable_hwsup(clkdm);
  745. /*
  746. * XXX This should be removed once TI adds wakeup/sleep
  747. * dependency code and data for OMAP4.
  748. */
  749. if (cpu_is_omap44xx()) {
  750. pr_err("clockdomain: %s: OMAP4 wakeup/sleep dependency support: not yet implemented\n", clkdm->name);
  751. } else {
  752. if (atomic_read(&clkdm->usecount) > 0)
  753. _clkdm_del_autodeps(clkdm);
  754. }
  755. }
  756. /* Clockdomain-to-clock framework interface code */
  757. /**
  758. * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm
  759. * @clkdm: struct clockdomain *
  760. * @clk: struct clk * of the enabled downstream clock
  761. *
  762. * Increment the usecount of the clockdomain @clkdm and ensure that it
  763. * is awake before @clk is enabled. Intended to be called by
  764. * clk_enable() code. If the clockdomain is in software-supervised
  765. * idle mode, force the clockdomain to wake. If the clockdomain is in
  766. * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to
  767. * ensure that devices in the clockdomain can be read from/written to
  768. * by on-chip processors. Returns -EINVAL if passed null pointers;
  769. * returns 0 upon success or if the clockdomain is in hwsup idle mode.
  770. */
  771. int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
  772. {
  773. bool hwsup = false;
  774. /*
  775. * XXX Rewrite this code to maintain a list of enabled
  776. * downstream clocks for debugging purposes?
  777. */
  778. if (!clkdm || !clk)
  779. return -EINVAL;
  780. if (atomic_inc_return(&clkdm->usecount) > 1)
  781. return 0;
  782. /* Clockdomain now has one enabled downstream clock */
  783. pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
  784. clk->name);
  785. if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
  786. if (!clkdm->clktrctrl_mask)
  787. return 0;
  788. hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
  789. clkdm->clktrctrl_mask);
  790. } else if (cpu_is_omap44xx()) {
  791. hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
  792. clkdm->cm_inst,
  793. clkdm->clkdm_offs);
  794. }
  795. if (hwsup) {
  796. /* Disable HW transitions when we are changing deps */
  797. _disable_hwsup(clkdm);
  798. _clkdm_add_autodeps(clkdm);
  799. _enable_hwsup(clkdm);
  800. } else {
  801. omap2_clkdm_wakeup(clkdm);
  802. }
  803. pwrdm_wait_transition(clkdm->pwrdm.ptr);
  804. pwrdm_clkdm_state_switch(clkdm);
  805. return 0;
  806. }
  807. /**
  808. * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm
  809. * @clkdm: struct clockdomain *
  810. * @clk: struct clk * of the disabled downstream clock
  811. *
  812. * Decrement the usecount of this clockdomain @clkdm when @clk is
  813. * disabled. Intended to be called by clk_disable() code. If the
  814. * clockdomain usecount goes to 0, put the clockdomain to sleep
  815. * (software-supervised mode) or remove the clkdm autodependencies
  816. * (hardware-supervised mode). Returns -EINVAL if passed null
  817. * pointers; -ERANGE if the @clkdm usecount underflows and debugging
  818. * is enabled; or returns 0 upon success or if the clockdomain is in
  819. * hwsup idle mode.
  820. */
  821. int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
  822. {
  823. bool hwsup = false;
  824. /*
  825. * XXX Rewrite this code to maintain a list of enabled
  826. * downstream clocks for debugging purposes?
  827. */
  828. if (!clkdm || !clk)
  829. return -EINVAL;
  830. #ifdef DEBUG
  831. if (atomic_read(&clkdm->usecount) == 0) {
  832. WARN_ON(1); /* underflow */
  833. return -ERANGE;
  834. }
  835. #endif
  836. if (atomic_dec_return(&clkdm->usecount) > 0)
  837. return 0;
  838. /* All downstream clocks of this clockdomain are now disabled */
  839. pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
  840. clk->name);
  841. if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
  842. if (!clkdm->clktrctrl_mask)
  843. return 0;
  844. hwsup = omap2_cm_is_clkdm_in_hwsup(clkdm->pwrdm.ptr->prcm_offs,
  845. clkdm->clktrctrl_mask);
  846. } else if (cpu_is_omap44xx()) {
  847. hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
  848. clkdm->cm_inst,
  849. clkdm->clkdm_offs);
  850. }
  851. if (hwsup) {
  852. /* Disable HW transitions when we are changing deps */
  853. _disable_hwsup(clkdm);
  854. _clkdm_del_autodeps(clkdm);
  855. _enable_hwsup(clkdm);
  856. } else {
  857. omap2_clkdm_sleep(clkdm);
  858. }
  859. pwrdm_clkdm_state_switch(clkdm);
  860. return 0;
  861. }