sh_serial.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /*
  2. * QEMU SCI/SCIF serial port emulation
  3. *
  4. * Copyright (c) 2007 Magnus Damm
  5. *
  6. * Based on serial.c - QEMU 16450 UART emulation
  7. * Copyright (c) 2003-2004 Fabrice Bellard
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a copy
  10. * of this software and associated documentation files (the "Software"), to deal
  11. * in the Software without restriction, including without limitation the rights
  12. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. * copies of the Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice shall be included in
  17. * all copies or substantial portions of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. * THE SOFTWARE.
  26. */
  27. #include "qemu/osdep.h"
  28. #include "hw/irq.h"
  29. #include "hw/sh4/sh.h"
  30. #include "chardev/char-fe.h"
  31. #include "qapi/error.h"
  32. #include "qemu/timer.h"
  33. //#define DEBUG_SERIAL
  34. #define SH_SERIAL_FLAG_TEND (1 << 0)
  35. #define SH_SERIAL_FLAG_TDE (1 << 1)
  36. #define SH_SERIAL_FLAG_RDF (1 << 2)
  37. #define SH_SERIAL_FLAG_BRK (1 << 3)
  38. #define SH_SERIAL_FLAG_DR (1 << 4)
  39. #define SH_RX_FIFO_LENGTH (16)
  40. typedef struct {
  41. MemoryRegion iomem;
  42. MemoryRegion iomem_p4;
  43. MemoryRegion iomem_a7;
  44. uint8_t smr;
  45. uint8_t brr;
  46. uint8_t scr;
  47. uint8_t dr; /* ftdr / tdr */
  48. uint8_t sr; /* fsr / ssr */
  49. uint16_t fcr;
  50. uint8_t sptr;
  51. uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */
  52. uint8_t rx_cnt;
  53. uint8_t rx_tail;
  54. uint8_t rx_head;
  55. int freq;
  56. int feat;
  57. int flags;
  58. int rtrg;
  59. CharBackend chr;
  60. QEMUTimer *fifo_timeout_timer;
  61. uint64_t etu; /* Elementary Time Unit (ns) */
  62. qemu_irq eri;
  63. qemu_irq rxi;
  64. qemu_irq txi;
  65. qemu_irq tei;
  66. qemu_irq bri;
  67. } sh_serial_state;
  68. static void sh_serial_clear_fifo(sh_serial_state * s)
  69. {
  70. memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH);
  71. s->rx_cnt = 0;
  72. s->rx_head = 0;
  73. s->rx_tail = 0;
  74. }
  75. static void sh_serial_write(void *opaque, hwaddr offs,
  76. uint64_t val, unsigned size)
  77. {
  78. sh_serial_state *s = opaque;
  79. unsigned char ch;
  80. #ifdef DEBUG_SERIAL
  81. printf("sh_serial: write offs=0x%02x val=0x%02x\n",
  82. offs, val);
  83. #endif
  84. switch(offs) {
  85. case 0x00: /* SMR */
  86. s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
  87. return;
  88. case 0x04: /* BRR */
  89. s->brr = val;
  90. return;
  91. case 0x08: /* SCR */
  92. /* TODO : For SH7751, SCIF mask should be 0xfb. */
  93. s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff);
  94. if (!(val & (1 << 5)))
  95. s->flags |= SH_SERIAL_FLAG_TEND;
  96. if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) {
  97. qemu_set_irq(s->txi, val & (1 << 7));
  98. }
  99. if (!(val & (1 << 6))) {
  100. qemu_set_irq(s->rxi, 0);
  101. }
  102. return;
  103. case 0x0c: /* FTDR / TDR */
  104. if (qemu_chr_fe_backend_connected(&s->chr)) {
  105. ch = val;
  106. /* XXX this blocks entire thread. Rewrite to use
  107. * qemu_chr_fe_write and background I/O callbacks */
  108. qemu_chr_fe_write_all(&s->chr, &ch, 1);
  109. }
  110. s->dr = val;
  111. s->flags &= ~SH_SERIAL_FLAG_TDE;
  112. return;
  113. #if 0
  114. case 0x14: /* FRDR / RDR */
  115. ret = 0;
  116. break;
  117. #endif
  118. }
  119. if (s->feat & SH_SERIAL_FEAT_SCIF) {
  120. switch(offs) {
  121. case 0x10: /* FSR */
  122. if (!(val & (1 << 6)))
  123. s->flags &= ~SH_SERIAL_FLAG_TEND;
  124. if (!(val & (1 << 5)))
  125. s->flags &= ~SH_SERIAL_FLAG_TDE;
  126. if (!(val & (1 << 4)))
  127. s->flags &= ~SH_SERIAL_FLAG_BRK;
  128. if (!(val & (1 << 1)))
  129. s->flags &= ~SH_SERIAL_FLAG_RDF;
  130. if (!(val & (1 << 0)))
  131. s->flags &= ~SH_SERIAL_FLAG_DR;
  132. if (!(val & (1 << 1)) || !(val & (1 << 0))) {
  133. if (s->rxi) {
  134. qemu_set_irq(s->rxi, 0);
  135. }
  136. }
  137. return;
  138. case 0x18: /* FCR */
  139. s->fcr = val;
  140. switch ((val >> 6) & 3) {
  141. case 0:
  142. s->rtrg = 1;
  143. break;
  144. case 1:
  145. s->rtrg = 4;
  146. break;
  147. case 2:
  148. s->rtrg = 8;
  149. break;
  150. case 3:
  151. s->rtrg = 14;
  152. break;
  153. }
  154. if (val & (1 << 1)) {
  155. sh_serial_clear_fifo(s);
  156. s->sr &= ~(1 << 1);
  157. }
  158. return;
  159. case 0x20: /* SPTR */
  160. s->sptr = val & 0xf3;
  161. return;
  162. case 0x24: /* LSR */
  163. return;
  164. }
  165. }
  166. else {
  167. switch(offs) {
  168. #if 0
  169. case 0x0c:
  170. ret = s->dr;
  171. break;
  172. case 0x10:
  173. ret = 0;
  174. break;
  175. #endif
  176. case 0x1c:
  177. s->sptr = val & 0x8f;
  178. return;
  179. }
  180. }
  181. fprintf(stderr, "sh_serial: unsupported write to 0x%02"
  182. HWADDR_PRIx "\n", offs);
  183. abort();
  184. }
  185. static uint64_t sh_serial_read(void *opaque, hwaddr offs,
  186. unsigned size)
  187. {
  188. sh_serial_state *s = opaque;
  189. uint32_t ret = ~0;
  190. #if 0
  191. switch(offs) {
  192. case 0x00:
  193. ret = s->smr;
  194. break;
  195. case 0x04:
  196. ret = s->brr;
  197. break;
  198. case 0x08:
  199. ret = s->scr;
  200. break;
  201. case 0x14:
  202. ret = 0;
  203. break;
  204. }
  205. #endif
  206. if (s->feat & SH_SERIAL_FEAT_SCIF) {
  207. switch(offs) {
  208. case 0x00: /* SMR */
  209. ret = s->smr;
  210. break;
  211. case 0x08: /* SCR */
  212. ret = s->scr;
  213. break;
  214. case 0x10: /* FSR */
  215. ret = 0;
  216. if (s->flags & SH_SERIAL_FLAG_TEND)
  217. ret |= (1 << 6);
  218. if (s->flags & SH_SERIAL_FLAG_TDE)
  219. ret |= (1 << 5);
  220. if (s->flags & SH_SERIAL_FLAG_BRK)
  221. ret |= (1 << 4);
  222. if (s->flags & SH_SERIAL_FLAG_RDF)
  223. ret |= (1 << 1);
  224. if (s->flags & SH_SERIAL_FLAG_DR)
  225. ret |= (1 << 0);
  226. if (s->scr & (1 << 5))
  227. s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
  228. break;
  229. case 0x14:
  230. if (s->rx_cnt > 0) {
  231. ret = s->rx_fifo[s->rx_tail++];
  232. s->rx_cnt--;
  233. if (s->rx_tail == SH_RX_FIFO_LENGTH)
  234. s->rx_tail = 0;
  235. if (s->rx_cnt < s->rtrg)
  236. s->flags &= ~SH_SERIAL_FLAG_RDF;
  237. }
  238. break;
  239. case 0x18:
  240. ret = s->fcr;
  241. break;
  242. case 0x1c:
  243. ret = s->rx_cnt;
  244. break;
  245. case 0x20:
  246. ret = s->sptr;
  247. break;
  248. case 0x24:
  249. ret = 0;
  250. break;
  251. }
  252. }
  253. else {
  254. switch(offs) {
  255. #if 0
  256. case 0x0c:
  257. ret = s->dr;
  258. break;
  259. case 0x10:
  260. ret = 0;
  261. break;
  262. case 0x14:
  263. ret = s->rx_fifo[0];
  264. break;
  265. #endif
  266. case 0x1c:
  267. ret = s->sptr;
  268. break;
  269. }
  270. }
  271. #ifdef DEBUG_SERIAL
  272. printf("sh_serial: read offs=0x%02x val=0x%x\n",
  273. offs, ret);
  274. #endif
  275. if (ret & ~((1 << 16) - 1)) {
  276. fprintf(stderr, "sh_serial: unsupported read from 0x%02"
  277. HWADDR_PRIx "\n", offs);
  278. abort();
  279. }
  280. return ret;
  281. }
  282. static int sh_serial_can_receive(sh_serial_state *s)
  283. {
  284. return s->scr & (1 << 4);
  285. }
  286. static void sh_serial_receive_break(sh_serial_state *s)
  287. {
  288. if (s->feat & SH_SERIAL_FEAT_SCIF)
  289. s->sr |= (1 << 4);
  290. }
  291. static int sh_serial_can_receive1(void *opaque)
  292. {
  293. sh_serial_state *s = opaque;
  294. return sh_serial_can_receive(s);
  295. }
  296. static void sh_serial_timeout_int(void *opaque)
  297. {
  298. sh_serial_state *s = opaque;
  299. s->flags |= SH_SERIAL_FLAG_RDF;
  300. if (s->scr & (1 << 6) && s->rxi) {
  301. qemu_set_irq(s->rxi, 1);
  302. }
  303. }
  304. static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
  305. {
  306. sh_serial_state *s = opaque;
  307. if (s->feat & SH_SERIAL_FEAT_SCIF) {
  308. int i;
  309. for (i = 0; i < size; i++) {
  310. if (s->rx_cnt < SH_RX_FIFO_LENGTH) {
  311. s->rx_fifo[s->rx_head++] = buf[i];
  312. if (s->rx_head == SH_RX_FIFO_LENGTH) {
  313. s->rx_head = 0;
  314. }
  315. s->rx_cnt++;
  316. if (s->rx_cnt >= s->rtrg) {
  317. s->flags |= SH_SERIAL_FLAG_RDF;
  318. if (s->scr & (1 << 6) && s->rxi) {
  319. timer_del(s->fifo_timeout_timer);
  320. qemu_set_irq(s->rxi, 1);
  321. }
  322. } else {
  323. timer_mod(s->fifo_timeout_timer,
  324. qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 15 * s->etu);
  325. }
  326. }
  327. }
  328. } else {
  329. s->rx_fifo[0] = buf[0];
  330. }
  331. }
  332. static void sh_serial_event(void *opaque, int event)
  333. {
  334. sh_serial_state *s = opaque;
  335. if (event == CHR_EVENT_BREAK)
  336. sh_serial_receive_break(s);
  337. }
  338. static const MemoryRegionOps sh_serial_ops = {
  339. .read = sh_serial_read,
  340. .write = sh_serial_write,
  341. .endianness = DEVICE_NATIVE_ENDIAN,
  342. };
  343. void sh_serial_init(MemoryRegion *sysmem,
  344. hwaddr base, int feat,
  345. uint32_t freq, Chardev *chr,
  346. qemu_irq eri_source,
  347. qemu_irq rxi_source,
  348. qemu_irq txi_source,
  349. qemu_irq tei_source,
  350. qemu_irq bri_source)
  351. {
  352. sh_serial_state *s;
  353. s = g_malloc0(sizeof(sh_serial_state));
  354. s->feat = feat;
  355. s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
  356. s->rtrg = 1;
  357. s->smr = 0;
  358. s->brr = 0xff;
  359. s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */
  360. s->sptr = 0;
  361. if (feat & SH_SERIAL_FEAT_SCIF) {
  362. s->fcr = 0;
  363. }
  364. else {
  365. s->dr = 0xff;
  366. }
  367. sh_serial_clear_fifo(s);
  368. memory_region_init_io(&s->iomem, NULL, &sh_serial_ops, s,
  369. "serial", 0x100000000ULL);
  370. memory_region_init_alias(&s->iomem_p4, NULL, "serial-p4", &s->iomem,
  371. 0, 0x28);
  372. memory_region_add_subregion(sysmem, P4ADDR(base), &s->iomem_p4);
  373. memory_region_init_alias(&s->iomem_a7, NULL, "serial-a7", &s->iomem,
  374. 0, 0x28);
  375. memory_region_add_subregion(sysmem, A7ADDR(base), &s->iomem_a7);
  376. if (chr) {
  377. qemu_chr_fe_init(&s->chr, chr, &error_abort);
  378. qemu_chr_fe_set_handlers(&s->chr, sh_serial_can_receive1,
  379. sh_serial_receive1,
  380. sh_serial_event, NULL, s, NULL, true);
  381. }
  382. s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
  383. sh_serial_timeout_int, s);
  384. s->etu = NANOSECONDS_PER_SECOND / 9600;
  385. s->eri = eri_source;
  386. s->rxi = rxi_source;
  387. s->txi = txi_source;
  388. s->tei = tei_source;
  389. s->bri = bri_source;
  390. }