Statistics
| Branch: | Revision:

root / hw / char / exynos4210_uart.c @ 9944d320

History | View | Annotate | Download (19.2 kB)

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