cadence_ttc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * Xilinx Zynq cadence TTC model
  3. *
  4. * Copyright (c) 2011 Xilinx Inc.
  5. * Copyright (c) 2012 Peter A.G. Crosthwaite (peter.crosthwaite@petalogix.com)
  6. * Copyright (c) 2012 PetaLogix Pty Ltd.
  7. * Written By Haibing Ma
  8. * M. Habib
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version
  13. * 2 of the License, or (at your option) any later version.
  14. *
  15. * You should have received a copy of the GNU General Public License along
  16. * with this program; if not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "qemu/osdep.h"
  19. #include "hw/irq.h"
  20. #include "hw/sysbus.h"
  21. #include "migration/vmstate.h"
  22. #include "qemu/module.h"
  23. #include "qemu/timer.h"
  24. #include "qom/object.h"
  25. #include "hw/timer/cadence_ttc.h"
  26. #ifdef CADENCE_TTC_ERR_DEBUG
  27. #define DB_PRINT(...) do { \
  28. fprintf(stderr, ": %s: ", __func__); \
  29. fprintf(stderr, ## __VA_ARGS__); \
  30. } while (0)
  31. #else
  32. #define DB_PRINT(...)
  33. #endif
  34. #define COUNTER_INTR_IV 0x00000001
  35. #define COUNTER_INTR_M1 0x00000002
  36. #define COUNTER_INTR_M2 0x00000004
  37. #define COUNTER_INTR_M3 0x00000008
  38. #define COUNTER_INTR_OV 0x00000010
  39. #define COUNTER_INTR_EV 0x00000020
  40. #define COUNTER_CTRL_DIS 0x00000001
  41. #define COUNTER_CTRL_INT 0x00000002
  42. #define COUNTER_CTRL_DEC 0x00000004
  43. #define COUNTER_CTRL_MATCH 0x00000008
  44. #define COUNTER_CTRL_RST 0x00000010
  45. #define CLOCK_CTRL_PS_EN 0x00000001
  46. #define CLOCK_CTRL_PS_V 0x0000001e
  47. static void cadence_timer_update(CadenceTimerState *s)
  48. {
  49. qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en));
  50. }
  51. static CadenceTimerState *cadence_timer_from_addr(void *opaque,
  52. hwaddr offset)
  53. {
  54. unsigned int index;
  55. CadenceTTCState *s = (CadenceTTCState *)opaque;
  56. index = (offset >> 2) % 3;
  57. return &s->timer[index];
  58. }
  59. static uint64_t cadence_timer_get_ns(CadenceTimerState *s, uint64_t timer_steps)
  60. {
  61. /* timer_steps has max value of 0x100000000. double check it
  62. * (or overflow can happen below) */
  63. assert(timer_steps <= 1ULL << 32);
  64. uint64_t r = timer_steps * 1000000000ULL;
  65. if (s->reg_clock & CLOCK_CTRL_PS_EN) {
  66. r >>= 16 - (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
  67. } else {
  68. r >>= 16;
  69. }
  70. r /= (uint64_t)s->freq;
  71. return r;
  72. }
  73. static uint64_t cadence_timer_get_steps(CadenceTimerState *s, uint64_t ns)
  74. {
  75. uint64_t to_divide = 1000000000ULL;
  76. uint64_t r = ns;
  77. /* for very large intervals (> 8s) do some division first to stop
  78. * overflow (costs some prescision) */
  79. while (r >= 8ULL << 30 && to_divide > 1) {
  80. r /= 1000;
  81. to_divide /= 1000;
  82. }
  83. r <<= 16;
  84. /* keep early-dividing as needed */
  85. while (r >= 8ULL << 30 && to_divide > 1) {
  86. r /= 1000;
  87. to_divide /= 1000;
  88. }
  89. r *= (uint64_t)s->freq;
  90. if (s->reg_clock & CLOCK_CTRL_PS_EN) {
  91. r /= 1 << (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
  92. }
  93. r /= to_divide;
  94. return r;
  95. }
  96. /* determine if x is in between a and b, exclusive of a, inclusive of b */
  97. static inline int64_t is_between(int64_t x, int64_t a, int64_t b)
  98. {
  99. if (a < b) {
  100. return x > a && x <= b;
  101. }
  102. return x < a && x >= b;
  103. }
  104. static void cadence_timer_run(CadenceTimerState *s)
  105. {
  106. int i;
  107. int64_t event_interval, next_value;
  108. assert(s->cpu_time_valid); /* cadence_timer_sync must be called first */
  109. if (s->reg_count & COUNTER_CTRL_DIS) {
  110. s->cpu_time_valid = 0;
  111. return;
  112. }
  113. { /* figure out what's going to happen next (rollover or match) */
  114. int64_t interval = (uint64_t)((s->reg_count & COUNTER_CTRL_INT) ?
  115. (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
  116. next_value = (s->reg_count & COUNTER_CTRL_DEC) ? -1ULL : interval;
  117. for (i = 0; i < 3; ++i) {
  118. int64_t cand = (uint64_t)s->reg_match[i] << 16;
  119. if (is_between(cand, (uint64_t)s->reg_value, next_value)) {
  120. next_value = cand;
  121. }
  122. }
  123. }
  124. DB_PRINT("next timer event value: %09llx\n",
  125. (unsigned long long)next_value);
  126. event_interval = next_value - (int64_t)s->reg_value;
  127. event_interval = (event_interval < 0) ? -event_interval : event_interval;
  128. timer_mod(s->timer, s->cpu_time +
  129. cadence_timer_get_ns(s, event_interval));
  130. }
  131. static void cadence_timer_sync(CadenceTimerState *s)
  132. {
  133. int i;
  134. int64_t r, x;
  135. int64_t interval = ((s->reg_count & COUNTER_CTRL_INT) ?
  136. (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
  137. uint64_t old_time = s->cpu_time;
  138. s->cpu_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
  139. DB_PRINT("cpu time: %lld ns\n", (long long)old_time);
  140. if (!s->cpu_time_valid || old_time == s->cpu_time) {
  141. s->cpu_time_valid = 1;
  142. return;
  143. }
  144. r = (int64_t)cadence_timer_get_steps(s, s->cpu_time - old_time);
  145. x = (int64_t)s->reg_value + ((s->reg_count & COUNTER_CTRL_DEC) ? -r : r);
  146. for (i = 0; i < 3; ++i) {
  147. int64_t m = (int64_t)s->reg_match[i] << 16;
  148. if (m > interval) {
  149. continue;
  150. }
  151. /* check to see if match event has occurred. check m +/- interval
  152. * to account for match events in wrap around cases */
  153. if (is_between(m, s->reg_value, x) ||
  154. is_between(m + interval, s->reg_value, x) ||
  155. is_between(m - interval, s->reg_value, x)) {
  156. s->reg_intr |= (2 << i);
  157. }
  158. }
  159. if ((x < 0) || (x >= interval)) {
  160. s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ?
  161. COUNTER_INTR_IV : COUNTER_INTR_OV;
  162. }
  163. while (x < 0) {
  164. x += interval;
  165. }
  166. s->reg_value = (uint32_t)(x % interval);
  167. cadence_timer_update(s);
  168. }
  169. static void cadence_timer_tick(void *opaque)
  170. {
  171. CadenceTimerState *s = opaque;
  172. DB_PRINT("\n");
  173. cadence_timer_sync(s);
  174. cadence_timer_run(s);
  175. }
  176. static uint32_t cadence_ttc_read_imp(void *opaque, hwaddr offset)
  177. {
  178. CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
  179. uint32_t value;
  180. cadence_timer_sync(s);
  181. cadence_timer_run(s);
  182. switch (offset) {
  183. case 0x00: /* clock control */
  184. case 0x04:
  185. case 0x08:
  186. return s->reg_clock;
  187. case 0x0c: /* counter control */
  188. case 0x10:
  189. case 0x14:
  190. return s->reg_count;
  191. case 0x18: /* counter value */
  192. case 0x1c:
  193. case 0x20:
  194. return (uint16_t)(s->reg_value >> 16);
  195. case 0x24: /* reg_interval counter */
  196. case 0x28:
  197. case 0x2c:
  198. return s->reg_interval;
  199. case 0x30: /* match 1 counter */
  200. case 0x34:
  201. case 0x38:
  202. return s->reg_match[0];
  203. case 0x3c: /* match 2 counter */
  204. case 0x40:
  205. case 0x44:
  206. return s->reg_match[1];
  207. case 0x48: /* match 3 counter */
  208. case 0x4c:
  209. case 0x50:
  210. return s->reg_match[2];
  211. case 0x54: /* interrupt register */
  212. case 0x58:
  213. case 0x5c:
  214. /* cleared after read */
  215. value = s->reg_intr;
  216. s->reg_intr = 0;
  217. cadence_timer_update(s);
  218. return value;
  219. case 0x60: /* interrupt enable */
  220. case 0x64:
  221. case 0x68:
  222. return s->reg_intr_en;
  223. case 0x6c:
  224. case 0x70:
  225. case 0x74:
  226. return s->reg_event_ctrl;
  227. case 0x78:
  228. case 0x7c:
  229. case 0x80:
  230. return s->reg_event;
  231. default:
  232. return 0;
  233. }
  234. }
  235. static uint64_t cadence_ttc_read(void *opaque, hwaddr offset,
  236. unsigned size)
  237. {
  238. uint32_t ret = cadence_ttc_read_imp(opaque, offset);
  239. DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)ret);
  240. return ret;
  241. }
  242. static void cadence_ttc_write(void *opaque, hwaddr offset,
  243. uint64_t value, unsigned size)
  244. {
  245. CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
  246. DB_PRINT("addr: %08x data %08x\n", (unsigned)offset, (unsigned)value);
  247. cadence_timer_sync(s);
  248. switch (offset) {
  249. case 0x00: /* clock control */
  250. case 0x04:
  251. case 0x08:
  252. s->reg_clock = value & 0x3F;
  253. break;
  254. case 0x0c: /* counter control */
  255. case 0x10:
  256. case 0x14:
  257. if (value & COUNTER_CTRL_RST) {
  258. s->reg_value = 0;
  259. }
  260. s->reg_count = value & 0x3f & ~COUNTER_CTRL_RST;
  261. break;
  262. case 0x24: /* interval register */
  263. case 0x28:
  264. case 0x2c:
  265. s->reg_interval = value & 0xffff;
  266. break;
  267. case 0x30: /* match register */
  268. case 0x34:
  269. case 0x38:
  270. s->reg_match[0] = value & 0xffff;
  271. break;
  272. case 0x3c: /* match register */
  273. case 0x40:
  274. case 0x44:
  275. s->reg_match[1] = value & 0xffff;
  276. break;
  277. case 0x48: /* match register */
  278. case 0x4c:
  279. case 0x50:
  280. s->reg_match[2] = value & 0xffff;
  281. break;
  282. case 0x54: /* interrupt register */
  283. case 0x58:
  284. case 0x5c:
  285. break;
  286. case 0x60: /* interrupt enable */
  287. case 0x64:
  288. case 0x68:
  289. s->reg_intr_en = value & 0x3f;
  290. break;
  291. case 0x6c: /* event control */
  292. case 0x70:
  293. case 0x74:
  294. s->reg_event_ctrl = value & 0x07;
  295. break;
  296. default:
  297. return;
  298. }
  299. cadence_timer_run(s);
  300. cadence_timer_update(s);
  301. }
  302. static const MemoryRegionOps cadence_ttc_ops = {
  303. .read = cadence_ttc_read,
  304. .write = cadence_ttc_write,
  305. .endianness = DEVICE_NATIVE_ENDIAN,
  306. };
  307. static void cadence_timer_reset(CadenceTimerState *s)
  308. {
  309. s->reg_count = 0x21;
  310. }
  311. static void cadence_timer_init(uint32_t freq, CadenceTimerState *s)
  312. {
  313. memset(s, 0, sizeof(CadenceTimerState));
  314. s->freq = freq;
  315. cadence_timer_reset(s);
  316. s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, cadence_timer_tick, s);
  317. }
  318. static void cadence_ttc_init(Object *obj)
  319. {
  320. CadenceTTCState *s = CADENCE_TTC(obj);
  321. memory_region_init_io(&s->iomem, obj, &cadence_ttc_ops, s,
  322. "timer", 0x1000);
  323. sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
  324. }
  325. static void cadence_ttc_realize(DeviceState *dev, Error **errp)
  326. {
  327. CadenceTTCState *s = CADENCE_TTC(dev);
  328. int i;
  329. for (i = 0; i < 3; ++i) {
  330. cadence_timer_init(133000000, &s->timer[i]);
  331. sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->timer[i].irq);
  332. }
  333. }
  334. static int cadence_timer_pre_save(void *opaque)
  335. {
  336. cadence_timer_sync((CadenceTimerState *)opaque);
  337. return 0;
  338. }
  339. static int cadence_timer_post_load(void *opaque, int version_id)
  340. {
  341. CadenceTimerState *s = opaque;
  342. s->cpu_time_valid = 0;
  343. cadence_timer_sync(s);
  344. cadence_timer_run(s);
  345. cadence_timer_update(s);
  346. return 0;
  347. }
  348. static const VMStateDescription vmstate_cadence_timer = {
  349. .name = "cadence_timer",
  350. .version_id = 1,
  351. .minimum_version_id = 1,
  352. .pre_save = cadence_timer_pre_save,
  353. .post_load = cadence_timer_post_load,
  354. .fields = (const VMStateField[]) {
  355. VMSTATE_UINT32(reg_clock, CadenceTimerState),
  356. VMSTATE_UINT32(reg_count, CadenceTimerState),
  357. VMSTATE_UINT32(reg_value, CadenceTimerState),
  358. VMSTATE_UINT16(reg_interval, CadenceTimerState),
  359. VMSTATE_UINT16_ARRAY(reg_match, CadenceTimerState, 3),
  360. VMSTATE_UINT32(reg_intr, CadenceTimerState),
  361. VMSTATE_UINT32(reg_intr_en, CadenceTimerState),
  362. VMSTATE_UINT32(reg_event_ctrl, CadenceTimerState),
  363. VMSTATE_UINT32(reg_event, CadenceTimerState),
  364. VMSTATE_END_OF_LIST()
  365. }
  366. };
  367. static const VMStateDescription vmstate_cadence_ttc = {
  368. .name = "cadence_TTC",
  369. .version_id = 1,
  370. .minimum_version_id = 1,
  371. .fields = (const VMStateField[]) {
  372. VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0,
  373. vmstate_cadence_timer,
  374. CadenceTimerState),
  375. VMSTATE_END_OF_LIST()
  376. }
  377. };
  378. static void cadence_ttc_class_init(ObjectClass *klass, void *data)
  379. {
  380. DeviceClass *dc = DEVICE_CLASS(klass);
  381. dc->vmsd = &vmstate_cadence_ttc;
  382. dc->realize = cadence_ttc_realize;
  383. }
  384. static const TypeInfo cadence_ttc_info = {
  385. .name = TYPE_CADENCE_TTC,
  386. .parent = TYPE_SYS_BUS_DEVICE,
  387. .instance_size = sizeof(CadenceTTCState),
  388. .instance_init = cadence_ttc_init,
  389. .class_init = cadence_ttc_class_init,
  390. };
  391. static void cadence_ttc_register_types(void)
  392. {
  393. type_register_static(&cadence_ttc_info);
  394. }
  395. type_init(cadence_ttc_register_types)