cadence_ttc.c 12 KB

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