2
0

pl080.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * Arm PrimeCell PL080/PL081 DMA controller
  3. *
  4. * Copyright (c) 2006 CodeSourcery.
  5. * Written by Paul Brook
  6. *
  7. * This code is licensed under the GPL.
  8. */
  9. #include "sysbus.h"
  10. #define PL080_MAX_CHANNELS 8
  11. #define PL080_CONF_E 0x1
  12. #define PL080_CONF_M1 0x2
  13. #define PL080_CONF_M2 0x4
  14. #define PL080_CCONF_H 0x40000
  15. #define PL080_CCONF_A 0x20000
  16. #define PL080_CCONF_L 0x10000
  17. #define PL080_CCONF_ITC 0x08000
  18. #define PL080_CCONF_IE 0x04000
  19. #define PL080_CCONF_E 0x00001
  20. #define PL080_CCTRL_I 0x80000000
  21. #define PL080_CCTRL_DI 0x08000000
  22. #define PL080_CCTRL_SI 0x04000000
  23. #define PL080_CCTRL_D 0x02000000
  24. #define PL080_CCTRL_S 0x01000000
  25. typedef struct {
  26. uint32_t src;
  27. uint32_t dest;
  28. uint32_t lli;
  29. uint32_t ctrl;
  30. uint32_t conf;
  31. } pl080_channel;
  32. typedef struct {
  33. SysBusDevice busdev;
  34. uint8_t tc_int;
  35. uint8_t tc_mask;
  36. uint8_t err_int;
  37. uint8_t err_mask;
  38. uint32_t conf;
  39. uint32_t sync;
  40. uint32_t req_single;
  41. uint32_t req_burst;
  42. pl080_channel chan[PL080_MAX_CHANNELS];
  43. int nchannels;
  44. /* Flag to avoid recursive DMA invocations. */
  45. int running;
  46. qemu_irq irq;
  47. } pl080_state;
  48. static const VMStateDescription vmstate_pl080_channel = {
  49. .name = "pl080_channel",
  50. .version_id = 1,
  51. .minimum_version_id = 1,
  52. .fields = (VMStateField[]) {
  53. VMSTATE_UINT32(src, pl080_channel),
  54. VMSTATE_UINT32(dest, pl080_channel),
  55. VMSTATE_UINT32(lli, pl080_channel),
  56. VMSTATE_UINT32(ctrl, pl080_channel),
  57. VMSTATE_UINT32(conf, pl080_channel),
  58. VMSTATE_END_OF_LIST()
  59. }
  60. };
  61. static const VMStateDescription vmstate_pl080 = {
  62. .name = "pl080",
  63. .version_id = 1,
  64. .minimum_version_id = 1,
  65. .fields = (VMStateField[]) {
  66. VMSTATE_UINT8(tc_int, pl080_state),
  67. VMSTATE_UINT8(tc_mask, pl080_state),
  68. VMSTATE_UINT8(err_int, pl080_state),
  69. VMSTATE_UINT8(err_mask, pl080_state),
  70. VMSTATE_UINT32(conf, pl080_state),
  71. VMSTATE_UINT32(sync, pl080_state),
  72. VMSTATE_UINT32(req_single, pl080_state),
  73. VMSTATE_UINT32(req_burst, pl080_state),
  74. VMSTATE_UINT8(tc_int, pl080_state),
  75. VMSTATE_UINT8(tc_int, pl080_state),
  76. VMSTATE_UINT8(tc_int, pl080_state),
  77. VMSTATE_STRUCT_ARRAY(chan, pl080_state, PL080_MAX_CHANNELS,
  78. 1, vmstate_pl080_channel, pl080_channel),
  79. VMSTATE_INT32(running, pl080_state),
  80. VMSTATE_END_OF_LIST()
  81. }
  82. };
  83. static const unsigned char pl080_id[] =
  84. { 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
  85. static const unsigned char pl081_id[] =
  86. { 0x81, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
  87. static void pl080_update(pl080_state *s)
  88. {
  89. if ((s->tc_int & s->tc_mask)
  90. || (s->err_int & s->err_mask))
  91. qemu_irq_raise(s->irq);
  92. else
  93. qemu_irq_lower(s->irq);
  94. }
  95. static void pl080_run(pl080_state *s)
  96. {
  97. int c;
  98. int flow;
  99. pl080_channel *ch;
  100. int swidth;
  101. int dwidth;
  102. int xsize;
  103. int n;
  104. int src_id;
  105. int dest_id;
  106. int size;
  107. uint8_t buff[4];
  108. uint32_t req;
  109. s->tc_mask = 0;
  110. for (c = 0; c < s->nchannels; c++) {
  111. if (s->chan[c].conf & PL080_CCONF_ITC)
  112. s->tc_mask |= 1 << c;
  113. if (s->chan[c].conf & PL080_CCONF_IE)
  114. s->err_mask |= 1 << c;
  115. }
  116. if ((s->conf & PL080_CONF_E) == 0)
  117. return;
  118. hw_error("DMA active\n");
  119. /* If we are already in the middle of a DMA operation then indicate that
  120. there may be new DMA requests and return immediately. */
  121. if (s->running) {
  122. s->running++;
  123. return;
  124. }
  125. s->running = 1;
  126. while (s->running) {
  127. for (c = 0; c < s->nchannels; c++) {
  128. ch = &s->chan[c];
  129. again:
  130. /* Test if thiws channel has any pending DMA requests. */
  131. if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
  132. != PL080_CCONF_E)
  133. continue;
  134. flow = (ch->conf >> 11) & 7;
  135. if (flow >= 4) {
  136. hw_error(
  137. "pl080_run: Peripheral flow control not implemented\n");
  138. }
  139. src_id = (ch->conf >> 1) & 0x1f;
  140. dest_id = (ch->conf >> 6) & 0x1f;
  141. size = ch->ctrl & 0xfff;
  142. req = s->req_single | s->req_burst;
  143. switch (flow) {
  144. case 0:
  145. break;
  146. case 1:
  147. if ((req & (1u << dest_id)) == 0)
  148. size = 0;
  149. break;
  150. case 2:
  151. if ((req & (1u << src_id)) == 0)
  152. size = 0;
  153. break;
  154. case 3:
  155. if ((req & (1u << src_id)) == 0
  156. || (req & (1u << dest_id)) == 0)
  157. size = 0;
  158. break;
  159. }
  160. if (!size)
  161. continue;
  162. /* Transfer one element. */
  163. /* ??? Should transfer multiple elements for a burst request. */
  164. /* ??? Unclear what the proper behavior is when source and
  165. destination widths are different. */
  166. swidth = 1 << ((ch->ctrl >> 18) & 7);
  167. dwidth = 1 << ((ch->ctrl >> 21) & 7);
  168. for (n = 0; n < dwidth; n+= swidth) {
  169. cpu_physical_memory_read(ch->src, buff + n, swidth);
  170. if (ch->ctrl & PL080_CCTRL_SI)
  171. ch->src += swidth;
  172. }
  173. xsize = (dwidth < swidth) ? swidth : dwidth;
  174. /* ??? This may pad the value incorrectly for dwidth < 32. */
  175. for (n = 0; n < xsize; n += dwidth) {
  176. cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
  177. if (ch->ctrl & PL080_CCTRL_DI)
  178. ch->dest += swidth;
  179. }
  180. size--;
  181. ch->ctrl = (ch->ctrl & 0xfffff000) | size;
  182. if (size == 0) {
  183. /* Transfer complete. */
  184. if (ch->lli) {
  185. ch->src = ldl_le_phys(ch->lli);
  186. ch->dest = ldl_le_phys(ch->lli + 4);
  187. ch->ctrl = ldl_le_phys(ch->lli + 12);
  188. ch->lli = ldl_le_phys(ch->lli + 8);
  189. } else {
  190. ch->conf &= ~PL080_CCONF_E;
  191. }
  192. if (ch->ctrl & PL080_CCTRL_I) {
  193. s->tc_int |= 1 << c;
  194. }
  195. }
  196. goto again;
  197. }
  198. if (--s->running)
  199. s->running = 1;
  200. }
  201. }
  202. static uint32_t pl080_read(void *opaque, target_phys_addr_t offset)
  203. {
  204. pl080_state *s = (pl080_state *)opaque;
  205. uint32_t i;
  206. uint32_t mask;
  207. if (offset >= 0xfe0 && offset < 0x1000) {
  208. if (s->nchannels == 8) {
  209. return pl080_id[(offset - 0xfe0) >> 2];
  210. } else {
  211. return pl081_id[(offset - 0xfe0) >> 2];
  212. }
  213. }
  214. if (offset >= 0x100 && offset < 0x200) {
  215. i = (offset & 0xe0) >> 5;
  216. if (i >= s->nchannels)
  217. goto bad_offset;
  218. switch (offset >> 2) {
  219. case 0: /* SrcAddr */
  220. return s->chan[i].src;
  221. case 1: /* DestAddr */
  222. return s->chan[i].dest;
  223. case 2: /* LLI */
  224. return s->chan[i].lli;
  225. case 3: /* Control */
  226. return s->chan[i].ctrl;
  227. case 4: /* Configuration */
  228. return s->chan[i].conf;
  229. default:
  230. goto bad_offset;
  231. }
  232. }
  233. switch (offset >> 2) {
  234. case 0: /* IntStatus */
  235. return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
  236. case 1: /* IntTCStatus */
  237. return (s->tc_int & s->tc_mask);
  238. case 3: /* IntErrorStatus */
  239. return (s->err_int & s->err_mask);
  240. case 5: /* RawIntTCStatus */
  241. return s->tc_int;
  242. case 6: /* RawIntErrorStatus */
  243. return s->err_int;
  244. case 7: /* EnbldChns */
  245. mask = 0;
  246. for (i = 0; i < s->nchannels; i++) {
  247. if (s->chan[i].conf & PL080_CCONF_E)
  248. mask |= 1 << i;
  249. }
  250. return mask;
  251. case 8: /* SoftBReq */
  252. case 9: /* SoftSReq */
  253. case 10: /* SoftLBReq */
  254. case 11: /* SoftLSReq */
  255. /* ??? Implement these. */
  256. return 0;
  257. case 12: /* Configuration */
  258. return s->conf;
  259. case 13: /* Sync */
  260. return s->sync;
  261. default:
  262. bad_offset:
  263. hw_error("pl080_read: Bad offset %x\n", (int)offset);
  264. return 0;
  265. }
  266. }
  267. static void pl080_write(void *opaque, target_phys_addr_t offset,
  268. uint32_t value)
  269. {
  270. pl080_state *s = (pl080_state *)opaque;
  271. int i;
  272. if (offset >= 0x100 && offset < 0x200) {
  273. i = (offset & 0xe0) >> 5;
  274. if (i >= s->nchannels)
  275. goto bad_offset;
  276. switch (offset >> 2) {
  277. case 0: /* SrcAddr */
  278. s->chan[i].src = value;
  279. break;
  280. case 1: /* DestAddr */
  281. s->chan[i].dest = value;
  282. break;
  283. case 2: /* LLI */
  284. s->chan[i].lli = value;
  285. break;
  286. case 3: /* Control */
  287. s->chan[i].ctrl = value;
  288. break;
  289. case 4: /* Configuration */
  290. s->chan[i].conf = value;
  291. pl080_run(s);
  292. break;
  293. }
  294. }
  295. switch (offset >> 2) {
  296. case 2: /* IntTCClear */
  297. s->tc_int &= ~value;
  298. break;
  299. case 4: /* IntErrorClear */
  300. s->err_int &= ~value;
  301. break;
  302. case 8: /* SoftBReq */
  303. case 9: /* SoftSReq */
  304. case 10: /* SoftLBReq */
  305. case 11: /* SoftLSReq */
  306. /* ??? Implement these. */
  307. hw_error("pl080_write: Soft DMA not implemented\n");
  308. break;
  309. case 12: /* Configuration */
  310. s->conf = value;
  311. if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
  312. hw_error("pl080_write: Big-endian DMA not implemented\n");
  313. }
  314. pl080_run(s);
  315. break;
  316. case 13: /* Sync */
  317. s->sync = value;
  318. break;
  319. default:
  320. bad_offset:
  321. hw_error("pl080_write: Bad offset %x\n", (int)offset);
  322. }
  323. pl080_update(s);
  324. }
  325. static CPUReadMemoryFunc * const pl080_readfn[] = {
  326. pl080_read,
  327. pl080_read,
  328. pl080_read
  329. };
  330. static CPUWriteMemoryFunc * const pl080_writefn[] = {
  331. pl080_write,
  332. pl080_write,
  333. pl080_write
  334. };
  335. static int pl08x_init(SysBusDevice *dev, int nchannels)
  336. {
  337. int iomemtype;
  338. pl080_state *s = FROM_SYSBUS(pl080_state, dev);
  339. iomemtype = cpu_register_io_memory(pl080_readfn,
  340. pl080_writefn, s,
  341. DEVICE_NATIVE_ENDIAN);
  342. sysbus_init_mmio(dev, 0x1000, iomemtype);
  343. sysbus_init_irq(dev, &s->irq);
  344. s->nchannels = nchannels;
  345. return 0;
  346. }
  347. static int pl080_init(SysBusDevice *dev)
  348. {
  349. return pl08x_init(dev, 8);
  350. }
  351. static int pl081_init(SysBusDevice *dev)
  352. {
  353. return pl08x_init(dev, 2);
  354. }
  355. static SysBusDeviceInfo pl080_info = {
  356. .init = pl080_init,
  357. .qdev.name = "pl080",
  358. .qdev.size = sizeof(pl080_state),
  359. .qdev.vmsd = &vmstate_pl080,
  360. .qdev.no_user = 1,
  361. };
  362. static SysBusDeviceInfo pl081_info = {
  363. .init = pl081_init,
  364. .qdev.name = "pl081",
  365. .qdev.size = sizeof(pl080_state),
  366. .qdev.vmsd = &vmstate_pl080,
  367. .qdev.no_user = 1,
  368. };
  369. /* The PL080 and PL081 are the same except for the number of channels
  370. they implement (8 and 2 respectively). */
  371. static void pl080_register_devices(void)
  372. {
  373. sysbus_register_withprop(&pl080_info);
  374. sysbus_register_withprop(&pl081_info);
  375. }
  376. device_init(pl080_register_devices)