dmtimer.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * linux/arch/arm/plat-omap/dmtimer.c
  3. *
  4. * OMAP Dual-Mode Timers
  5. *
  6. * Copyright (C) 2005 Nokia Corporation
  7. * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify it
  10. * under the terms of the GNU General Public License as published by the
  11. * Free Software Foundation; either version 2 of the License, or (at your
  12. * option) any later version.
  13. *
  14. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  15. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  16. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  17. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  21. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. *
  23. * You should have received a copy of the GNU General Public License along
  24. * with this program; if not, write to the Free Software Foundation, Inc.,
  25. * 675 Mass Ave, Cambridge, MA 02139, USA.
  26. */
  27. #include <linux/init.h>
  28. #include <asm/hardware.h>
  29. #include <asm/arch/dmtimer.h>
  30. #include <asm/io.h>
  31. #include <asm/arch/irqs.h>
  32. #include <linux/spinlock.h>
  33. #include <linux/list.h>
  34. #define OMAP_TIMER_COUNT 8
  35. #define OMAP_TIMER_ID_REG 0x00
  36. #define OMAP_TIMER_OCP_CFG_REG 0x10
  37. #define OMAP_TIMER_SYS_STAT_REG 0x14
  38. #define OMAP_TIMER_STAT_REG 0x18
  39. #define OMAP_TIMER_INT_EN_REG 0x1c
  40. #define OMAP_TIMER_WAKEUP_EN_REG 0x20
  41. #define OMAP_TIMER_CTRL_REG 0x24
  42. #define OMAP_TIMER_COUNTER_REG 0x28
  43. #define OMAP_TIMER_LOAD_REG 0x2c
  44. #define OMAP_TIMER_TRIGGER_REG 0x30
  45. #define OMAP_TIMER_WRITE_PEND_REG 0x34
  46. #define OMAP_TIMER_MATCH_REG 0x38
  47. #define OMAP_TIMER_CAPTURE_REG 0x3c
  48. #define OMAP_TIMER_IF_CTRL_REG 0x40
  49. static struct dmtimer_info_struct {
  50. struct list_head unused_timers;
  51. struct list_head reserved_timers;
  52. } dm_timer_info;
  53. static struct omap_dm_timer dm_timers[] = {
  54. { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 },
  55. { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 },
  56. { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 },
  57. { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 },
  58. { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 },
  59. { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 },
  60. { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 },
  61. { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 },
  62. { .base=0x0 },
  63. };
  64. static spinlock_t dm_timer_lock;
  65. inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
  66. {
  67. omap_writel(value, timer->base + reg);
  68. while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
  69. ;
  70. }
  71. u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
  72. {
  73. return omap_readl(timer->base + reg);
  74. }
  75. int omap_dm_timers_active(void)
  76. {
  77. struct omap_dm_timer *timer;
  78. for (timer = &dm_timers[0]; timer->base; ++timer)
  79. if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
  80. OMAP_TIMER_CTRL_ST)
  81. return 1;
  82. return 0;
  83. }
  84. /**
  85. * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
  86. * @inputmask: current value of idlect mask
  87. */
  88. __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
  89. {
  90. int n;
  91. /* If ARMXOR cannot be idled this function call is unnecessary */
  92. if (!(inputmask & (1 << 1)))
  93. return inputmask;
  94. /* If any active timer is using ARMXOR return modified mask */
  95. for (n = 0; dm_timers[n].base; ++n)
  96. if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)&
  97. OMAP_TIMER_CTRL_ST) {
  98. if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0)
  99. inputmask &= ~(1 << 1);
  100. else
  101. inputmask &= ~(1 << 2);
  102. }
  103. return inputmask;
  104. }
  105. void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
  106. {
  107. int n = (timer - dm_timers) << 1;
  108. u32 l;
  109. l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
  110. l |= source << n;
  111. omap_writel(l, MOD_CONF_CTRL_1);
  112. }
  113. static void omap_dm_timer_reset(struct omap_dm_timer *timer)
  114. {
  115. /* Reset and set posted mode */
  116. omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
  117. omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02);
  118. omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
  119. }
  120. struct omap_dm_timer * omap_dm_timer_request(void)
  121. {
  122. struct omap_dm_timer *timer = NULL;
  123. unsigned long flags;
  124. spin_lock_irqsave(&dm_timer_lock, flags);
  125. if (!list_empty(&dm_timer_info.unused_timers)) {
  126. timer = (struct omap_dm_timer *)
  127. dm_timer_info.unused_timers.next;
  128. list_move_tail((struct list_head *)timer,
  129. &dm_timer_info.reserved_timers);
  130. }
  131. spin_unlock_irqrestore(&dm_timer_lock, flags);
  132. return timer;
  133. }
  134. void omap_dm_timer_free(struct omap_dm_timer *timer)
  135. {
  136. unsigned long flags;
  137. omap_dm_timer_reset(timer);
  138. spin_lock_irqsave(&dm_timer_lock, flags);
  139. list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
  140. spin_unlock_irqrestore(&dm_timer_lock, flags);
  141. }
  142. void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
  143. unsigned int value)
  144. {
  145. omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
  146. }
  147. unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
  148. {
  149. return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
  150. }
  151. void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
  152. {
  153. omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
  154. }
  155. void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
  156. {
  157. u32 l;
  158. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  159. l |= OMAP_TIMER_CTRL_AR;
  160. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  161. }
  162. void omap_dm_timer_trigger(struct omap_dm_timer *timer)
  163. {
  164. omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
  165. }
  166. void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
  167. {
  168. u32 l;
  169. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  170. l |= value & 0x3;
  171. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  172. }
  173. void omap_dm_timer_start(struct omap_dm_timer *timer)
  174. {
  175. u32 l;
  176. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  177. l |= OMAP_TIMER_CTRL_ST;
  178. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  179. }
  180. void omap_dm_timer_stop(struct omap_dm_timer *timer)
  181. {
  182. u32 l;
  183. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  184. l &= ~0x1;
  185. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  186. }
  187. unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
  188. {
  189. return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
  190. }
  191. void omap_dm_timer_reset_counter(struct omap_dm_timer *timer)
  192. {
  193. omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
  194. }
  195. void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
  196. {
  197. omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
  198. }
  199. void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
  200. {
  201. omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
  202. }
  203. void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
  204. {
  205. u32 l;
  206. l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
  207. l |= OMAP_TIMER_CTRL_CE;
  208. omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  209. }
  210. static inline void __dm_timer_init(void)
  211. {
  212. struct omap_dm_timer *timer;
  213. spin_lock_init(&dm_timer_lock);
  214. INIT_LIST_HEAD(&dm_timer_info.unused_timers);
  215. INIT_LIST_HEAD(&dm_timer_info.reserved_timers);
  216. timer = &dm_timers[0];
  217. while (timer->base) {
  218. list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
  219. omap_dm_timer_reset(timer);
  220. timer++;
  221. }
  222. }
  223. static int __init omap_dm_timer_init(void)
  224. {
  225. if (cpu_is_omap16xx())
  226. __dm_timer_init();
  227. return 0;
  228. }
  229. arch_initcall(omap_dm_timer_init);