exynos4210_uart.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. /*
  2. * Exynos4210 UART Emulation
  3. *
  4. * Copyright (C) 2011 Samsung Electronics Co Ltd.
  5. * Maksim Kozlov, <m.kozlov@samsung.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU General Public License as published by the
  9. * Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  15. * for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. #include "qemu/osdep.h"
  22. #include "hw/sysbus.h"
  23. #include "migration/vmstate.h"
  24. #include "qemu/error-report.h"
  25. #include "qemu/module.h"
  26. #include "chardev/char-fe.h"
  27. #include "chardev/char-serial.h"
  28. #include "hw/arm/exynos4210.h"
  29. #include "hw/irq.h"
  30. #include "hw/qdev-properties.h"
  31. #undef DEBUG_UART
  32. #undef DEBUG_UART_EXTEND
  33. #undef DEBUG_IRQ
  34. #undef DEBUG_Rx_DATA
  35. #undef DEBUG_Tx_DATA
  36. #define DEBUG_UART 0
  37. #define DEBUG_UART_EXTEND 0
  38. #define DEBUG_IRQ 0
  39. #define DEBUG_Rx_DATA 0
  40. #define DEBUG_Tx_DATA 0
  41. #if DEBUG_UART
  42. #define PRINT_DEBUG(fmt, args...) \
  43. do { \
  44. fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
  45. } while (0)
  46. #if DEBUG_UART_EXTEND
  47. #define PRINT_DEBUG_EXTEND(fmt, args...) \
  48. do { \
  49. fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
  50. } while (0)
  51. #else
  52. #define PRINT_DEBUG_EXTEND(fmt, args...) \
  53. do {} while (0)
  54. #endif /* EXTEND */
  55. #else
  56. #define PRINT_DEBUG(fmt, args...) \
  57. do {} while (0)
  58. #define PRINT_DEBUG_EXTEND(fmt, args...) \
  59. do {} while (0)
  60. #endif
  61. #define PRINT_ERROR(fmt, args...) \
  62. do { \
  63. fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
  64. } while (0)
  65. /*
  66. * Offsets for UART registers relative to SFR base address
  67. * for UARTn
  68. *
  69. */
  70. #define ULCON 0x0000 /* Line Control */
  71. #define UCON 0x0004 /* Control */
  72. #define UFCON 0x0008 /* FIFO Control */
  73. #define UMCON 0x000C /* Modem Control */
  74. #define UTRSTAT 0x0010 /* Tx/Rx Status */
  75. #define UERSTAT 0x0014 /* UART Error Status */
  76. #define UFSTAT 0x0018 /* FIFO Status */
  77. #define UMSTAT 0x001C /* Modem Status */
  78. #define UTXH 0x0020 /* Transmit Buffer */
  79. #define URXH 0x0024 /* Receive Buffer */
  80. #define UBRDIV 0x0028 /* Baud Rate Divisor */
  81. #define UFRACVAL 0x002C /* Divisor Fractional Value */
  82. #define UINTP 0x0030 /* Interrupt Pending */
  83. #define UINTSP 0x0034 /* Interrupt Source Pending */
  84. #define UINTM 0x0038 /* Interrupt Mask */
  85. /*
  86. * for indexing register in the uint32_t array
  87. *
  88. * 'reg' - register offset (see offsets definitions above)
  89. *
  90. */
  91. #define I_(reg) (reg / sizeof(uint32_t))
  92. typedef struct Exynos4210UartReg {
  93. const char *name; /* the only reason is the debug output */
  94. hwaddr offset;
  95. uint32_t reset_value;
  96. } Exynos4210UartReg;
  97. static const Exynos4210UartReg exynos4210_uart_regs[] = {
  98. {"ULCON", ULCON, 0x00000000},
  99. {"UCON", UCON, 0x00003000},
  100. {"UFCON", UFCON, 0x00000000},
  101. {"UMCON", UMCON, 0x00000000},
  102. {"UTRSTAT", UTRSTAT, 0x00000006}, /* RO */
  103. {"UERSTAT", UERSTAT, 0x00000000}, /* RO */
  104. {"UFSTAT", UFSTAT, 0x00000000}, /* RO */
  105. {"UMSTAT", UMSTAT, 0x00000000}, /* RO */
  106. {"UTXH", UTXH, 0x5c5c5c5c}, /* WO, undefined reset value*/
  107. {"URXH", URXH, 0x00000000}, /* RO */
  108. {"UBRDIV", UBRDIV, 0x00000000},
  109. {"UFRACVAL", UFRACVAL, 0x00000000},
  110. {"UINTP", UINTP, 0x00000000},
  111. {"UINTSP", UINTSP, 0x00000000},
  112. {"UINTM", UINTM, 0x00000000},
  113. };
  114. #define EXYNOS4210_UART_REGS_MEM_SIZE 0x3C
  115. /* UART FIFO Control */
  116. #define UFCON_FIFO_ENABLE 0x1
  117. #define UFCON_Rx_FIFO_RESET 0x2
  118. #define UFCON_Tx_FIFO_RESET 0x4
  119. #define UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT 8
  120. #define UFCON_Tx_FIFO_TRIGGER_LEVEL (7 << UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT)
  121. #define UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT 4
  122. #define UFCON_Rx_FIFO_TRIGGER_LEVEL (7 << UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT)
  123. /* Uart FIFO Status */
  124. #define UFSTAT_Rx_FIFO_COUNT 0xff
  125. #define UFSTAT_Rx_FIFO_FULL 0x100
  126. #define UFSTAT_Rx_FIFO_ERROR 0x200
  127. #define UFSTAT_Tx_FIFO_COUNT_SHIFT 16
  128. #define UFSTAT_Tx_FIFO_COUNT (0xff << UFSTAT_Tx_FIFO_COUNT_SHIFT)
  129. #define UFSTAT_Tx_FIFO_FULL_SHIFT 24
  130. #define UFSTAT_Tx_FIFO_FULL (1 << UFSTAT_Tx_FIFO_FULL_SHIFT)
  131. /* UART Interrupt Source Pending */
  132. #define UINTSP_RXD 0x1 /* Receive interrupt */
  133. #define UINTSP_ERROR 0x2 /* Error interrupt */
  134. #define UINTSP_TXD 0x4 /* Transmit interrupt */
  135. #define UINTSP_MODEM 0x8 /* Modem interrupt */
  136. /* UART Line Control */
  137. #define ULCON_IR_MODE_SHIFT 6
  138. #define ULCON_PARITY_SHIFT 3
  139. #define ULCON_STOP_BIT_SHIFT 1
  140. /* UART Tx/Rx Status */
  141. #define UTRSTAT_TRANSMITTER_EMPTY 0x4
  142. #define UTRSTAT_Tx_BUFFER_EMPTY 0x2
  143. #define UTRSTAT_Rx_BUFFER_DATA_READY 0x1
  144. /* UART Error Status */
  145. #define UERSTAT_OVERRUN 0x1
  146. #define UERSTAT_PARITY 0x2
  147. #define UERSTAT_FRAME 0x4
  148. #define UERSTAT_BREAK 0x8
  149. typedef struct {
  150. uint8_t *data;
  151. uint32_t sp, rp; /* store and retrieve pointers */
  152. uint32_t size;
  153. } Exynos4210UartFIFO;
  154. #define TYPE_EXYNOS4210_UART "exynos4210.uart"
  155. #define EXYNOS4210_UART(obj) \
  156. OBJECT_CHECK(Exynos4210UartState, (obj), TYPE_EXYNOS4210_UART)
  157. typedef struct Exynos4210UartState {
  158. SysBusDevice parent_obj;
  159. MemoryRegion iomem;
  160. uint32_t reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)];
  161. Exynos4210UartFIFO rx;
  162. Exynos4210UartFIFO tx;
  163. CharBackend chr;
  164. qemu_irq irq;
  165. uint32_t channel;
  166. } Exynos4210UartState;
  167. #if DEBUG_UART
  168. /* Used only for debugging inside PRINT_DEBUG_... macros */
  169. static const char *exynos4210_uart_regname(hwaddr offset)
  170. {
  171. int i;
  172. for (i = 0; i < ARRAY_SIZE(exynos4210_uart_regs); i++) {
  173. if (offset == exynos4210_uart_regs[i].offset) {
  174. return exynos4210_uart_regs[i].name;
  175. }
  176. }
  177. return NULL;
  178. }
  179. #endif
  180. static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
  181. {
  182. q->data[q->sp] = ch;
  183. q->sp = (q->sp + 1) % q->size;
  184. }
  185. static uint8_t fifo_retrieve(Exynos4210UartFIFO *q)
  186. {
  187. uint8_t ret = q->data[q->rp];
  188. q->rp = (q->rp + 1) % q->size;
  189. return ret;
  190. }
  191. static int fifo_elements_number(const Exynos4210UartFIFO *q)
  192. {
  193. if (q->sp < q->rp) {
  194. return q->size - q->rp + q->sp;
  195. }
  196. return q->sp - q->rp;
  197. }
  198. static int fifo_empty_elements_number(const Exynos4210UartFIFO *q)
  199. {
  200. return q->size - fifo_elements_number(q);
  201. }
  202. static void fifo_reset(Exynos4210UartFIFO *q)
  203. {
  204. g_free(q->data);
  205. q->data = NULL;
  206. q->data = (uint8_t *)g_malloc0(q->size);
  207. q->sp = 0;
  208. q->rp = 0;
  209. }
  210. static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(const Exynos4210UartState *s)
  211. {
  212. uint32_t level = 0;
  213. uint32_t reg;
  214. reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
  215. UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
  216. switch (s->channel) {
  217. case 0:
  218. level = reg * 32;
  219. break;
  220. case 1:
  221. case 4:
  222. level = reg * 8;
  223. break;
  224. case 2:
  225. case 3:
  226. level = reg * 2;
  227. break;
  228. default:
  229. level = 0;
  230. PRINT_ERROR("Wrong UART channel number: %d\n", s->channel);
  231. }
  232. return level;
  233. }
  234. static void exynos4210_uart_update_irq(Exynos4210UartState *s)
  235. {
  236. /*
  237. * The Tx interrupt is always requested if the number of data in the
  238. * transmit FIFO is smaller than the trigger level.
  239. */
  240. if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
  241. uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
  242. UFSTAT_Tx_FIFO_COUNT_SHIFT;
  243. if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
  244. s->reg[I_(UINTSP)] |= UINTSP_TXD;
  245. }
  246. }
  247. s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
  248. if (s->reg[I_(UINTP)]) {
  249. qemu_irq_raise(s->irq);
  250. #if DEBUG_IRQ
  251. fprintf(stderr, "UART%d: IRQ has been raised: %08x\n",
  252. s->channel, s->reg[I_(UINTP)]);
  253. #endif
  254. } else {
  255. qemu_irq_lower(s->irq);
  256. }
  257. }
  258. static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
  259. {
  260. int speed, parity, data_bits, stop_bits;
  261. QEMUSerialSetParams ssp;
  262. uint64_t uclk_rate;
  263. if (s->reg[I_(UBRDIV)] == 0) {
  264. return;
  265. }
  266. if (s->reg[I_(ULCON)] & 0x20) {
  267. if (s->reg[I_(ULCON)] & 0x28) {
  268. parity = 'E';
  269. } else {
  270. parity = 'O';
  271. }
  272. } else {
  273. parity = 'N';
  274. }
  275. if (s->reg[I_(ULCON)] & 0x4) {
  276. stop_bits = 2;
  277. } else {
  278. stop_bits = 1;
  279. }
  280. data_bits = (s->reg[I_(ULCON)] & 0x3) + 5;
  281. uclk_rate = 24000000;
  282. speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) +
  283. (s->reg[I_(UFRACVAL)] & 0x7) + 16);
  284. ssp.speed = speed;
  285. ssp.parity = parity;
  286. ssp.data_bits = data_bits;
  287. ssp.stop_bits = stop_bits;
  288. qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
  289. PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
  290. s->channel, speed, parity, data_bits, stop_bits);
  291. }
  292. static void exynos4210_uart_write(void *opaque, hwaddr offset,
  293. uint64_t val, unsigned size)
  294. {
  295. Exynos4210UartState *s = (Exynos4210UartState *)opaque;
  296. uint8_t ch;
  297. PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel,
  298. offset, exynos4210_uart_regname(offset), (long long unsigned int)val);
  299. switch (offset) {
  300. case ULCON:
  301. case UBRDIV:
  302. case UFRACVAL:
  303. s->reg[I_(offset)] = val;
  304. exynos4210_uart_update_parameters(s);
  305. break;
  306. case UFCON:
  307. s->reg[I_(UFCON)] = val;
  308. if (val & UFCON_Rx_FIFO_RESET) {
  309. fifo_reset(&s->rx);
  310. s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
  311. PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel);
  312. }
  313. if (val & UFCON_Tx_FIFO_RESET) {
  314. fifo_reset(&s->tx);
  315. s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
  316. PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel);
  317. }
  318. break;
  319. case UTXH:
  320. if (qemu_chr_fe_backend_connected(&s->chr)) {
  321. s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
  322. UTRSTAT_Tx_BUFFER_EMPTY);
  323. ch = (uint8_t)val;
  324. /* XXX this blocks entire thread. Rewrite to use
  325. * qemu_chr_fe_write and background I/O callbacks */
  326. qemu_chr_fe_write_all(&s->chr, &ch, 1);
  327. #if DEBUG_Tx_DATA
  328. fprintf(stderr, "%c", ch);
  329. #endif
  330. s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
  331. UTRSTAT_Tx_BUFFER_EMPTY;
  332. s->reg[I_(UINTSP)] |= UINTSP_TXD;
  333. exynos4210_uart_update_irq(s);
  334. }
  335. break;
  336. case UINTP:
  337. s->reg[I_(UINTP)] &= ~val;
  338. s->reg[I_(UINTSP)] &= ~val;
  339. PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n",
  340. s->channel, offset, s->reg[I_(UINTP)]);
  341. exynos4210_uart_update_irq(s);
  342. break;
  343. case UTRSTAT:
  344. case UERSTAT:
  345. case UFSTAT:
  346. case UMSTAT:
  347. case URXH:
  348. PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n",
  349. s->channel, exynos4210_uart_regname(offset), offset);
  350. break;
  351. case UINTSP:
  352. s->reg[I_(UINTSP)] &= ~val;
  353. break;
  354. case UINTM:
  355. s->reg[I_(UINTM)] = val;
  356. exynos4210_uart_update_irq(s);
  357. break;
  358. case UCON:
  359. case UMCON:
  360. default:
  361. s->reg[I_(offset)] = val;
  362. break;
  363. }
  364. }
  365. static uint64_t exynos4210_uart_read(void *opaque, hwaddr offset,
  366. unsigned size)
  367. {
  368. Exynos4210UartState *s = (Exynos4210UartState *)opaque;
  369. uint32_t res;
  370. switch (offset) {
  371. case UERSTAT: /* Read Only */
  372. res = s->reg[I_(UERSTAT)];
  373. s->reg[I_(UERSTAT)] = 0;
  374. return res;
  375. case UFSTAT: /* Read Only */
  376. s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
  377. if (fifo_empty_elements_number(&s->rx) == 0) {
  378. s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
  379. s->reg[I_(UFSTAT)] &= ~0xff;
  380. }
  381. return s->reg[I_(UFSTAT)];
  382. case URXH:
  383. if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
  384. if (fifo_elements_number(&s->rx)) {
  385. res = fifo_retrieve(&s->rx);
  386. #if DEBUG_Rx_DATA
  387. fprintf(stderr, "%c", res);
  388. #endif
  389. if (!fifo_elements_number(&s->rx)) {
  390. s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
  391. } else {
  392. s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
  393. }
  394. } else {
  395. s->reg[I_(UINTSP)] |= UINTSP_ERROR;
  396. exynos4210_uart_update_irq(s);
  397. res = 0;
  398. }
  399. } else {
  400. s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
  401. res = s->reg[I_(URXH)];
  402. }
  403. return res;
  404. case UTXH:
  405. PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n",
  406. s->channel, exynos4210_uart_regname(offset), offset);
  407. break;
  408. default:
  409. return s->reg[I_(offset)];
  410. }
  411. return 0;
  412. }
  413. static const MemoryRegionOps exynos4210_uart_ops = {
  414. .read = exynos4210_uart_read,
  415. .write = exynos4210_uart_write,
  416. .endianness = DEVICE_NATIVE_ENDIAN,
  417. .valid = {
  418. .max_access_size = 4,
  419. .unaligned = false
  420. },
  421. };
  422. static int exynos4210_uart_can_receive(void *opaque)
  423. {
  424. Exynos4210UartState *s = (Exynos4210UartState *)opaque;
  425. return fifo_empty_elements_number(&s->rx);
  426. }
  427. static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
  428. {
  429. Exynos4210UartState *s = (Exynos4210UartState *)opaque;
  430. int i;
  431. if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
  432. if (fifo_empty_elements_number(&s->rx) < size) {
  433. for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
  434. fifo_store(&s->rx, buf[i]);
  435. }
  436. s->reg[I_(UINTSP)] |= UINTSP_ERROR;
  437. s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
  438. } else {
  439. for (i = 0; i < size; i++) {
  440. fifo_store(&s->rx, buf[i]);
  441. }
  442. s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
  443. }
  444. /* XXX: Around here we maybe should check Rx trigger level */
  445. s->reg[I_(UINTSP)] |= UINTSP_RXD;
  446. } else {
  447. s->reg[I_(URXH)] = buf[0];
  448. s->reg[I_(UINTSP)] |= UINTSP_RXD;
  449. s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
  450. }
  451. exynos4210_uart_update_irq(s);
  452. }
  453. static void exynos4210_uart_event(void *opaque, int event)
  454. {
  455. Exynos4210UartState *s = (Exynos4210UartState *)opaque;
  456. if (event == CHR_EVENT_BREAK) {
  457. /* When the RxDn is held in logic 0, then a null byte is pushed into the
  458. * fifo */
  459. fifo_store(&s->rx, '\0');
  460. s->reg[I_(UERSTAT)] |= UERSTAT_BREAK;
  461. exynos4210_uart_update_irq(s);
  462. }
  463. }
  464. static void exynos4210_uart_reset(DeviceState *dev)
  465. {
  466. Exynos4210UartState *s = EXYNOS4210_UART(dev);
  467. int i;
  468. for (i = 0; i < ARRAY_SIZE(exynos4210_uart_regs); i++) {
  469. s->reg[I_(exynos4210_uart_regs[i].offset)] =
  470. exynos4210_uart_regs[i].reset_value;
  471. }
  472. fifo_reset(&s->rx);
  473. fifo_reset(&s->tx);
  474. PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size);
  475. }
  476. static const VMStateDescription vmstate_exynos4210_uart_fifo = {
  477. .name = "exynos4210.uart.fifo",
  478. .version_id = 1,
  479. .minimum_version_id = 1,
  480. .fields = (VMStateField[]) {
  481. VMSTATE_UINT32(sp, Exynos4210UartFIFO),
  482. VMSTATE_UINT32(rp, Exynos4210UartFIFO),
  483. VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, size),
  484. VMSTATE_END_OF_LIST()
  485. }
  486. };
  487. static const VMStateDescription vmstate_exynos4210_uart = {
  488. .name = "exynos4210.uart",
  489. .version_id = 1,
  490. .minimum_version_id = 1,
  491. .fields = (VMStateField[]) {
  492. VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
  493. vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
  494. VMSTATE_UINT32_ARRAY(reg, Exynos4210UartState,
  495. EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)),
  496. VMSTATE_END_OF_LIST()
  497. }
  498. };
  499. DeviceState *exynos4210_uart_create(hwaddr addr,
  500. int fifo_size,
  501. int channel,
  502. Chardev *chr,
  503. qemu_irq irq)
  504. {
  505. DeviceState *dev;
  506. SysBusDevice *bus;
  507. dev = qdev_create(NULL, TYPE_EXYNOS4210_UART);
  508. qdev_prop_set_chr(dev, "chardev", chr);
  509. qdev_prop_set_uint32(dev, "channel", channel);
  510. qdev_prop_set_uint32(dev, "rx-size", fifo_size);
  511. qdev_prop_set_uint32(dev, "tx-size", fifo_size);
  512. bus = SYS_BUS_DEVICE(dev);
  513. qdev_init_nofail(dev);
  514. if (addr != (hwaddr)-1) {
  515. sysbus_mmio_map(bus, 0, addr);
  516. }
  517. sysbus_connect_irq(bus, 0, irq);
  518. return dev;
  519. }
  520. static void exynos4210_uart_init(Object *obj)
  521. {
  522. SysBusDevice *dev = SYS_BUS_DEVICE(obj);
  523. Exynos4210UartState *s = EXYNOS4210_UART(dev);
  524. /* memory mapping */
  525. memory_region_init_io(&s->iomem, obj, &exynos4210_uart_ops, s,
  526. "exynos4210.uart", EXYNOS4210_UART_REGS_MEM_SIZE);
  527. sysbus_init_mmio(dev, &s->iomem);
  528. sysbus_init_irq(dev, &s->irq);
  529. }
  530. static void exynos4210_uart_realize(DeviceState *dev, Error **errp)
  531. {
  532. Exynos4210UartState *s = EXYNOS4210_UART(dev);
  533. qemu_chr_fe_set_handlers(&s->chr, exynos4210_uart_can_receive,
  534. exynos4210_uart_receive, exynos4210_uart_event,
  535. NULL, s, NULL, true);
  536. }
  537. static Property exynos4210_uart_properties[] = {
  538. DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
  539. DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
  540. DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16),
  541. DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16),
  542. DEFINE_PROP_END_OF_LIST(),
  543. };
  544. static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
  545. {
  546. DeviceClass *dc = DEVICE_CLASS(klass);
  547. dc->realize = exynos4210_uart_realize;
  548. dc->reset = exynos4210_uart_reset;
  549. dc->props = exynos4210_uart_properties;
  550. dc->vmsd = &vmstate_exynos4210_uart;
  551. }
  552. static const TypeInfo exynos4210_uart_info = {
  553. .name = TYPE_EXYNOS4210_UART,
  554. .parent = TYPE_SYS_BUS_DEVICE,
  555. .instance_size = sizeof(Exynos4210UartState),
  556. .instance_init = exynos4210_uart_init,
  557. .class_init = exynos4210_uart_class_init,
  558. };
  559. static void exynos4210_uart_register(void)
  560. {
  561. type_register_static(&exynos4210_uart_info);
  562. }
  563. type_init(exynos4210_uart_register)