amptimer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. /* $OpenBSD: amptimer.c,v 1.4 2013/08/08 10:07:22 rapha Exp $ */
  2. /*
  3. * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/systm.h>
  19. #include <sys/queue.h>
  20. #include <sys/malloc.h>
  21. #include <sys/device.h>
  22. #include <sys/kernel.h>
  23. #include <sys/timetc.h>
  24. #include <sys/evcount.h>
  25. #include <arm/cpufunc.h>
  26. #include <machine/bus.h>
  27. #include <machine/intr.h>
  28. #include <arm/cortex/cortex.h>
  29. /* offset from periphbase */
  30. #define GTIMER_ADDR 0x200
  31. #define GTIMER_SIZE 0x100
  32. /* registers */
  33. #define GTIMER_CNT_LOW 0x00
  34. #define GTIMER_CNT_HIGH 0x04
  35. #define GTIMER_CTRL 0x08
  36. #define GTIMER_CTRL_AA (1 << 3)
  37. #define GTIMER_CTRL_IRQ (1 << 2)
  38. #define GTIMER_CTRL_COMP (1 << 1)
  39. #define GTIMER_CTRL_TIMER (1 << 0)
  40. #define GTIMER_STATUS 0x0c
  41. #define GTIMER_STATUS_EVENT (1 << 0)
  42. #define GTIMER_CMP_LOW 0x10
  43. #define GTIMER_CMP_HIGH 0x14
  44. #define GTIMER_AUTOINC 0x18
  45. /* offset from periphbase */
  46. #define PTIMER_ADDR 0x600
  47. #define PTIMER_SIZE 0x100
  48. /* registers */
  49. #define PTIMER_LOAD 0x0
  50. #define PTIMER_CNT 0x4
  51. #define PTIMER_CTRL 0x8
  52. #define PTIMER_CTRL_ENABLE (1<<0)
  53. #define PTIMER_CTRL_AUTORELOAD (1<<1)
  54. #define PTIMER_CTRL_IRQEN (1<<2)
  55. #define PTIMER_STATUS 0xC
  56. #define PTIMER_STATUS_EVENT (1<<0)
  57. #define TIMER_FREQUENCY 396 * 1000 * 1000 /* ARM core clock */
  58. int32_t amptimer_frequency = TIMER_FREQUENCY;
  59. u_int amptimer_get_timecount(struct timecounter *);
  60. static struct timecounter amptimer_timecounter = {
  61. amptimer_get_timecount, NULL, 0x7fffffff, 0, "amptimer", 0, NULL
  62. };
  63. #define MAX_ARM_CPUS 8
  64. struct amptimer_pcpu_softc {
  65. uint64_t pc_nexttickevent;
  66. uint64_t pc_nextstatevent;
  67. u_int32_t pc_ticks_err_sum;
  68. };
  69. struct amptimer_softc {
  70. struct device sc_dev;
  71. bus_space_tag_t sc_iot;
  72. bus_space_handle_t sc_ioh;
  73. bus_space_handle_t sc_pioh;
  74. struct amptimer_pcpu_softc sc_pstat[MAX_ARM_CPUS];
  75. u_int32_t sc_ticks_err_cnt;
  76. u_int32_t sc_ticks_per_second;
  77. u_int32_t sc_ticks_per_intr;
  78. u_int32_t sc_statvar;
  79. u_int32_t sc_statmin;
  80. #ifdef AMPTIMER_DEBUG
  81. struct evcount sc_clk_count;
  82. struct evcount sc_stat_count;
  83. #endif
  84. };
  85. int amptimer_match(struct device *, void *, void *);
  86. void amptimer_attach(struct device *, struct device *, void *);
  87. uint64_t amptimer_readcnt64(struct amptimer_softc *sc);
  88. int amptimer_intr(void *);
  89. void amptimer_cpu_initclocks(void);
  90. void amptimer_delay(u_int);
  91. void amptimer_setstatclockrate(int stathz);
  92. void amptimer_set_clockrate(int32_t new_frequency);
  93. void amptimer_startclock(void);
  94. /* hack - XXXX
  95. * gptimer connects directly to ampintc, not thru the generic
  96. * inteface because it uses an 'internal' interupt
  97. * not a peripheral interrupt.
  98. */
  99. void *ampintc_intr_establish(int, int, int (*)(void *), void *, char *);
  100. struct cfattach amptimer_ca = {
  101. sizeof (struct amptimer_softc), amptimer_match, amptimer_attach
  102. };
  103. struct cfdriver amptimer_cd = {
  104. NULL, "amptimer", DV_DULL
  105. };
  106. uint64_t
  107. amptimer_readcnt64(struct amptimer_softc *sc)
  108. {
  109. uint32_t high0, high1, low;
  110. bus_space_tag_t iot = sc->sc_iot;
  111. bus_space_handle_t ioh = sc->sc_ioh;
  112. do {
  113. high0 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH);
  114. low = bus_space_read_4(iot, ioh, GTIMER_CNT_LOW);
  115. high1 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH);
  116. } while (high0 != high1);
  117. return ((((uint64_t)high1) << 32) | low);
  118. }
  119. int
  120. amptimer_match(struct device *parent, void *cfdata, void *aux)
  121. {
  122. if ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9)
  123. return (1);
  124. return 0;
  125. }
  126. void
  127. amptimer_attach(struct device *parent, struct device *self, void *args)
  128. {
  129. struct amptimer_softc *sc = (struct amptimer_softc *)self;
  130. struct cortex_attach_args *ia = args;
  131. bus_space_handle_t ioh, pioh;
  132. sc->sc_iot = ia->ca_iot;
  133. if (bus_space_map(sc->sc_iot, ia->ca_periphbase + GTIMER_ADDR,
  134. GTIMER_SIZE, 0, &ioh))
  135. panic("amptimer_attach: bus_space_map global timer failed!");
  136. if (bus_space_map(sc->sc_iot, ia->ca_periphbase + PTIMER_ADDR,
  137. PTIMER_SIZE, 0, &pioh))
  138. panic("amptimer_attach: bus_space_map priv timer failed!");
  139. sc->sc_ticks_per_second = amptimer_frequency;
  140. printf(": tick rate %d KHz\n", sc->sc_ticks_per_second /1000);
  141. sc->sc_ioh = ioh;
  142. sc->sc_pioh = pioh;
  143. /* disable global timer */
  144. bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, 0);
  145. /* XXX ??? reset counters to 0 - gives us uptime in the counter */
  146. bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_LOW, 0);
  147. bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_HIGH, 0);
  148. /* enable global timer */
  149. bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, GTIMER_CTRL_TIMER);
  150. #if defined(USE_GTIMER_CMP)
  151. /* clear event */
  152. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_STATUS, 1);
  153. #else
  154. bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 0);
  155. bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS,
  156. PTIMER_STATUS_EVENT);
  157. #endif
  158. #ifdef AMPTIMER_DEBUG
  159. evcount_attach(&sc->sc_clk_count, "clock", NULL);
  160. evcount_attach(&sc->sc_stat_count, "stat", NULL);
  161. #endif
  162. /*
  163. * private timer and interrupts not enabled until
  164. * timer configures
  165. */
  166. arm_clock_register(amptimer_cpu_initclocks, amptimer_delay,
  167. amptimer_setstatclockrate, amptimer_startclock);
  168. amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
  169. amptimer_timecounter.tc_priv = sc;
  170. tc_init(&amptimer_timecounter);
  171. }
  172. u_int
  173. amptimer_get_timecount(struct timecounter *tc)
  174. {
  175. struct amptimer_softc *sc = amptimer_timecounter.tc_priv;
  176. return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW);
  177. }
  178. int
  179. amptimer_intr(void *frame)
  180. {
  181. struct amptimer_softc *sc = amptimer_cd.cd_devs[0];
  182. struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
  183. uint64_t now;
  184. uint64_t nextevent;
  185. uint32_t r, reg;
  186. #if defined(USE_GTIMER_CMP)
  187. int skip = 1;
  188. #else
  189. int64_t delay;
  190. #endif
  191. int rc = 0;
  192. /*
  193. * DSR - I know that the tick timer is 64 bits, but the following
  194. * code deals with rollover, so there is no point in dealing
  195. * with the 64 bit math, just let the 32 bit rollover
  196. * do the right thing
  197. */
  198. now = amptimer_readcnt64(sc);
  199. while (pc->pc_nexttickevent <= now) {
  200. pc->pc_nexttickevent += sc->sc_ticks_per_intr;
  201. pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt;
  202. /* looping a few times is faster than divide */
  203. while (pc->pc_ticks_err_sum > hz) {
  204. pc->pc_nexttickevent += 1;
  205. pc->pc_ticks_err_sum -= hz;
  206. }
  207. #ifdef AMPTIMER_DEBUG
  208. sc->sc_clk_count.ec_count++;
  209. #endif
  210. rc = 1;
  211. hardclock(frame);
  212. }
  213. while (pc->pc_nextstatevent <= now) {
  214. do {
  215. r = random() & (sc->sc_statvar -1);
  216. } while (r == 0); /* random == 0 not allowed */
  217. pc->pc_nextstatevent += sc->sc_statmin + r;
  218. /* XXX - correct nextstatevent? */
  219. #ifdef AMPTIMER_DEBUG
  220. sc->sc_stat_count.ec_count++;
  221. #endif
  222. rc = 1;
  223. statclock(frame);
  224. }
  225. if (pc->pc_nexttickevent < pc->pc_nextstatevent)
  226. nextevent = pc->pc_nexttickevent;
  227. else
  228. nextevent = pc->pc_nextstatevent;
  229. #if defined(USE_GTIMER_CMP)
  230. again:
  231. reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL);
  232. reg &= ~GTIMER_CTRL_COMP;
  233. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg);
  234. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_LOW,
  235. nextevent & 0xffffffff);
  236. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_HIGH,
  237. nextevent >> 32);
  238. reg |= GTIMER_CTRL_COMP;
  239. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg);
  240. now = amptimer_readcnt64(sc);
  241. if (now >= nextevent) {
  242. nextevent = now + skip;
  243. skip += 1;
  244. goto again;
  245. }
  246. #else
  247. /* clear old status */
  248. bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS,
  249. PTIMER_STATUS_EVENT);
  250. delay = nextevent - now;
  251. if (delay < 0)
  252. delay = 1;
  253. reg = bus_space_read_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL);
  254. if ((reg & (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) !=
  255. (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN))
  256. bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL,
  257. (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN));
  258. bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, delay);
  259. #endif
  260. return (rc);
  261. }
  262. void
  263. amptimer_set_clockrate(int32_t new_frequency)
  264. {
  265. struct amptimer_softc *sc = amptimer_cd.cd_devs[0];
  266. amptimer_frequency = new_frequency;
  267. if (sc == NULL)
  268. return;
  269. sc->sc_ticks_per_second = amptimer_frequency;
  270. amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
  271. printf("amptimer0: adjusting clock: new tick rate %d KHz\n",
  272. sc->sc_ticks_per_second /1000);
  273. }
  274. void
  275. amptimer_cpu_initclocks()
  276. {
  277. struct amptimer_softc *sc = amptimer_cd.cd_devs[0];
  278. struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
  279. uint64_t next;
  280. #if defined(USE_GTIMER_CMP)
  281. uint32_t reg;
  282. #endif
  283. stathz = hz;
  284. profhz = hz * 10;
  285. if (sc->sc_ticks_per_second != amptimer_frequency) {
  286. amptimer_set_clockrate(amptimer_frequency);
  287. }
  288. amptimer_setstatclockrate(stathz);
  289. sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz;
  290. sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
  291. pc->pc_ticks_err_sum = 0;
  292. /* establish interrupts */
  293. /* XXX - irq */
  294. #if defined(USE_GTIMER_CMP)
  295. ampintc_intr_establish(27, IPL_CLOCK, amptimer_intr,
  296. NULL, "tick");
  297. #else
  298. ampintc_intr_establish(29, IPL_CLOCK, amptimer_intr,
  299. NULL, "tick");
  300. #endif
  301. next = amptimer_readcnt64(sc) + sc->sc_ticks_per_intr;
  302. pc->pc_nexttickevent = pc->pc_nextstatevent = next;
  303. #if defined(USE_GTIMER_CMP)
  304. reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL);
  305. reg &= ~GTIMER_CTRL_COMP;
  306. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg);
  307. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_LOW,
  308. next & 0xffffffff);
  309. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_HIGH,
  310. next >> 32);
  311. reg |= GTIMER_CTRL_COMP | GTIMER_CTRL_IRQ;
  312. bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg);
  313. #else
  314. bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL,
  315. (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN));
  316. bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD,
  317. sc->sc_ticks_per_intr);
  318. #endif
  319. }
  320. void
  321. amptimer_delay(u_int usecs)
  322. {
  323. struct amptimer_softc *sc = amptimer_cd.cd_devs[0];
  324. u_int32_t clock, oclock, delta, delaycnt;
  325. volatile int j;
  326. int csec, usec;
  327. if (usecs > (0x80000000 / (sc->sc_ticks_per_second))) {
  328. csec = usecs / 10000;
  329. usec = usecs % 10000;
  330. delaycnt = (sc->sc_ticks_per_second / 100) * csec +
  331. (sc->sc_ticks_per_second / 100) * usec / 10000;
  332. } else {
  333. delaycnt = sc->sc_ticks_per_second * usecs / 1000000;
  334. }
  335. if (delaycnt <= 1)
  336. for (j = 100; j > 0; j--)
  337. ;
  338. oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW);
  339. while (1) {
  340. for (j = 100; j > 0; j--)
  341. ;
  342. clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
  343. GTIMER_CNT_LOW);
  344. delta = clock - oclock;
  345. if (delta > delaycnt)
  346. break;
  347. }
  348. }
  349. void
  350. amptimer_setstatclockrate(int newhz)
  351. {
  352. struct amptimer_softc *sc = amptimer_cd.cd_devs[0];
  353. int minint, statint;
  354. int s;
  355. s = splclock();
  356. statint = sc->sc_ticks_per_second / newhz;
  357. /* calculate largest 2^n which is smaller that just over half statint */
  358. sc->sc_statvar = 0x40000000; /* really big power of two */
  359. minint = statint / 2 + 100;
  360. while (sc->sc_statvar > minint)
  361. sc->sc_statvar >>= 1;
  362. sc->sc_statmin = statint - (sc->sc_statvar >> 1);
  363. splx(s);
  364. /*
  365. * XXX this allows the next stat timer to occur then it switches
  366. * to the new frequency. Rather than switching instantly.
  367. */
  368. }
  369. void
  370. amptimer_startclock(void)
  371. {
  372. struct amptimer_softc *sc = amptimer_cd.cd_devs[0];
  373. struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
  374. uint64_t nextevent;
  375. nextevent = amptimer_readcnt64(sc) + sc->sc_ticks_per_intr;
  376. pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent;
  377. bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD,
  378. sc->sc_ticks_per_intr);
  379. }