exynos4210_uart.c 19 KB

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