root / hw / xilinx_uartlite.c @ 8b92e298
History | View | Annotate | Download (5.5 kB)
1 | ee118d95 | Edgar E. Iglesias | /*
|
---|---|---|---|
2 | ee118d95 | Edgar E. Iglesias | * QEMU model of Xilinx uartlite.
|
3 | ee118d95 | Edgar E. Iglesias | *
|
4 | ee118d95 | Edgar E. Iglesias | * Copyright (c) 2009 Edgar E. Iglesias.
|
5 | ee118d95 | Edgar E. Iglesias | *
|
6 | ee118d95 | Edgar E. Iglesias | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
7 | ee118d95 | Edgar E. Iglesias | * of this software and associated documentation files (the "Software"), to deal
|
8 | ee118d95 | Edgar E. Iglesias | * in the Software without restriction, including without limitation the rights
|
9 | ee118d95 | Edgar E. Iglesias | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10 | ee118d95 | Edgar E. Iglesias | * copies of the Software, and to permit persons to whom the Software is
|
11 | ee118d95 | Edgar E. Iglesias | * furnished to do so, subject to the following conditions:
|
12 | ee118d95 | Edgar E. Iglesias | *
|
13 | ee118d95 | Edgar E. Iglesias | * The above copyright notice and this permission notice shall be included in
|
14 | ee118d95 | Edgar E. Iglesias | * all copies or substantial portions of the Software.
|
15 | ee118d95 | Edgar E. Iglesias | *
|
16 | ee118d95 | Edgar E. Iglesias | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17 | ee118d95 | Edgar E. Iglesias | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18 | ee118d95 | Edgar E. Iglesias | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19 | ee118d95 | Edgar E. Iglesias | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20 | ee118d95 | Edgar E. Iglesias | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21 | ee118d95 | Edgar E. Iglesias | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22 | ee118d95 | Edgar E. Iglesias | * THE SOFTWARE.
|
23 | ee118d95 | Edgar E. Iglesias | */
|
24 | ee118d95 | Edgar E. Iglesias | |
25 | ee118d95 | Edgar E. Iglesias | #include "sysbus.h" |
26 | ee118d95 | Edgar E. Iglesias | #include "qemu-char.h" |
27 | ee118d95 | Edgar E. Iglesias | |
28 | ee118d95 | Edgar E. Iglesias | #define DUART(x)
|
29 | ee118d95 | Edgar E. Iglesias | |
30 | ee118d95 | Edgar E. Iglesias | #define R_RX 0 |
31 | ee118d95 | Edgar E. Iglesias | #define R_TX 1 |
32 | ee118d95 | Edgar E. Iglesias | #define R_STATUS 2 |
33 | ee118d95 | Edgar E. Iglesias | #define R_CTRL 3 |
34 | ee118d95 | Edgar E. Iglesias | #define R_MAX 4 |
35 | ee118d95 | Edgar E. Iglesias | |
36 | ee118d95 | Edgar E. Iglesias | #define STATUS_RXVALID 0x01 |
37 | ee118d95 | Edgar E. Iglesias | #define STATUS_RXFULL 0x02 |
38 | ee118d95 | Edgar E. Iglesias | #define STATUS_TXEMPTY 0x04 |
39 | ee118d95 | Edgar E. Iglesias | #define STATUS_TXFULL 0x08 |
40 | ee118d95 | Edgar E. Iglesias | #define STATUS_IE 0x10 |
41 | ee118d95 | Edgar E. Iglesias | #define STATUS_OVERRUN 0x20 |
42 | ee118d95 | Edgar E. Iglesias | #define STATUS_FRAME 0x40 |
43 | ee118d95 | Edgar E. Iglesias | #define STATUS_PARITY 0x80 |
44 | ee118d95 | Edgar E. Iglesias | |
45 | ee118d95 | Edgar E. Iglesias | #define CONTROL_RST_TX 0x01 |
46 | ee118d95 | Edgar E. Iglesias | #define CONTROL_RST_RX 0x02 |
47 | ee118d95 | Edgar E. Iglesias | #define CONTROL_IE 0x10 |
48 | ee118d95 | Edgar E. Iglesias | |
49 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite
|
50 | ee118d95 | Edgar E. Iglesias | { |
51 | ee118d95 | Edgar E. Iglesias | SysBusDevice busdev; |
52 | ee118d95 | Edgar E. Iglesias | CharDriverState *chr; |
53 | ee118d95 | Edgar E. Iglesias | qemu_irq irq; |
54 | ee118d95 | Edgar E. Iglesias | |
55 | ee118d95 | Edgar E. Iglesias | uint8_t rx_fifo[8];
|
56 | ee118d95 | Edgar E. Iglesias | unsigned int rx_fifo_pos; |
57 | ee118d95 | Edgar E. Iglesias | unsigned int rx_fifo_len; |
58 | ee118d95 | Edgar E. Iglesias | |
59 | ee118d95 | Edgar E. Iglesias | uint32_t regs[R_MAX]; |
60 | ee118d95 | Edgar E. Iglesias | }; |
61 | ee118d95 | Edgar E. Iglesias | |
62 | ee118d95 | Edgar E. Iglesias | static void uart_update_irq(struct xlx_uartlite *s) |
63 | ee118d95 | Edgar E. Iglesias | { |
64 | ee118d95 | Edgar E. Iglesias | unsigned int irq; |
65 | ee118d95 | Edgar E. Iglesias | |
66 | ee118d95 | Edgar E. Iglesias | if (s->rx_fifo_len)
|
67 | ee118d95 | Edgar E. Iglesias | s->regs[R_STATUS] |= STATUS_IE; |
68 | ee118d95 | Edgar E. Iglesias | |
69 | ee118d95 | Edgar E. Iglesias | irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE); |
70 | ee118d95 | Edgar E. Iglesias | qemu_set_irq(s->irq, irq); |
71 | ee118d95 | Edgar E. Iglesias | } |
72 | ee118d95 | Edgar E. Iglesias | |
73 | ee118d95 | Edgar E. Iglesias | static void uart_update_status(struct xlx_uartlite *s) |
74 | ee118d95 | Edgar E. Iglesias | { |
75 | ee118d95 | Edgar E. Iglesias | uint32_t r; |
76 | ee118d95 | Edgar E. Iglesias | |
77 | ee118d95 | Edgar E. Iglesias | r = s->regs[R_STATUS]; |
78 | ee118d95 | Edgar E. Iglesias | r &= ~7;
|
79 | ee118d95 | Edgar E. Iglesias | r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */ |
80 | ee118d95 | Edgar E. Iglesias | r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1; |
81 | ee118d95 | Edgar E. Iglesias | r |= (!!s->rx_fifo_len); |
82 | ee118d95 | Edgar E. Iglesias | s->regs[R_STATUS] = r; |
83 | ee118d95 | Edgar E. Iglesias | } |
84 | ee118d95 | Edgar E. Iglesias | |
85 | c227f099 | Anthony Liguori | static uint32_t uart_readl (void *opaque, target_phys_addr_t addr) |
86 | ee118d95 | Edgar E. Iglesias | { |
87 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = opaque;
|
88 | ee118d95 | Edgar E. Iglesias | uint32_t r = 0;
|
89 | ee118d95 | Edgar E. Iglesias | addr >>= 2;
|
90 | ee118d95 | Edgar E. Iglesias | switch (addr)
|
91 | ee118d95 | Edgar E. Iglesias | { |
92 | ee118d95 | Edgar E. Iglesias | case R_RX:
|
93 | ee118d95 | Edgar E. Iglesias | r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7];
|
94 | ee118d95 | Edgar E. Iglesias | if (s->rx_fifo_len)
|
95 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_len--; |
96 | ee118d95 | Edgar E. Iglesias | uart_update_status(s); |
97 | ee118d95 | Edgar E. Iglesias | uart_update_irq(s); |
98 | ee118d95 | Edgar E. Iglesias | break;
|
99 | ee118d95 | Edgar E. Iglesias | |
100 | ee118d95 | Edgar E. Iglesias | default:
|
101 | ee118d95 | Edgar E. Iglesias | if (addr < ARRAY_SIZE(s->regs))
|
102 | ee118d95 | Edgar E. Iglesias | r = s->regs[addr]; |
103 | ee118d95 | Edgar E. Iglesias | DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r));
|
104 | ee118d95 | Edgar E. Iglesias | break;
|
105 | ee118d95 | Edgar E. Iglesias | } |
106 | ee118d95 | Edgar E. Iglesias | return r;
|
107 | ee118d95 | Edgar E. Iglesias | } |
108 | ee118d95 | Edgar E. Iglesias | |
109 | ee118d95 | Edgar E. Iglesias | static void |
110 | c227f099 | Anthony Liguori | uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
|
111 | ee118d95 | Edgar E. Iglesias | { |
112 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = opaque;
|
113 | ee118d95 | Edgar E. Iglesias | unsigned char ch = value; |
114 | ee118d95 | Edgar E. Iglesias | |
115 | ee118d95 | Edgar E. Iglesias | addr >>= 2;
|
116 | ee118d95 | Edgar E. Iglesias | switch (addr)
|
117 | ee118d95 | Edgar E. Iglesias | { |
118 | ee118d95 | Edgar E. Iglesias | case R_STATUS:
|
119 | ee118d95 | Edgar E. Iglesias | hw_error("write to UART STATUS?\n");
|
120 | ee118d95 | Edgar E. Iglesias | break;
|
121 | ee118d95 | Edgar E. Iglesias | |
122 | ee118d95 | Edgar E. Iglesias | case R_CTRL:
|
123 | ee118d95 | Edgar E. Iglesias | if (value & CONTROL_RST_RX) {
|
124 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_pos = 0;
|
125 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_len = 0;
|
126 | ee118d95 | Edgar E. Iglesias | } |
127 | ee118d95 | Edgar E. Iglesias | s->regs[addr] = value; |
128 | ee118d95 | Edgar E. Iglesias | break;
|
129 | ee118d95 | Edgar E. Iglesias | |
130 | ee118d95 | Edgar E. Iglesias | case R_TX:
|
131 | ee118d95 | Edgar E. Iglesias | if (s->chr)
|
132 | ee118d95 | Edgar E. Iglesias | qemu_chr_write(s->chr, &ch, 1);
|
133 | ee118d95 | Edgar E. Iglesias | |
134 | ee118d95 | Edgar E. Iglesias | s->regs[addr] = value; |
135 | ee118d95 | Edgar E. Iglesias | |
136 | ee118d95 | Edgar E. Iglesias | /* hax. */
|
137 | ee118d95 | Edgar E. Iglesias | s->regs[R_STATUS] |= STATUS_IE; |
138 | ee118d95 | Edgar E. Iglesias | break;
|
139 | ee118d95 | Edgar E. Iglesias | |
140 | ee118d95 | Edgar E. Iglesias | default:
|
141 | ee118d95 | Edgar E. Iglesias | DUART(printf("%s addr=%x v=%x\n", __func__, addr, value));
|
142 | ee118d95 | Edgar E. Iglesias | if (addr < ARRAY_SIZE(s->regs))
|
143 | ee118d95 | Edgar E. Iglesias | s->regs[addr] = value; |
144 | ee118d95 | Edgar E. Iglesias | break;
|
145 | ee118d95 | Edgar E. Iglesias | } |
146 | ee118d95 | Edgar E. Iglesias | uart_update_status(s); |
147 | ee118d95 | Edgar E. Iglesias | uart_update_irq(s); |
148 | ee118d95 | Edgar E. Iglesias | } |
149 | ee118d95 | Edgar E. Iglesias | |
150 | d60efc6b | Blue Swirl | static CPUReadMemoryFunc * const uart_read[] = { |
151 | ee118d95 | Edgar E. Iglesias | &uart_readl, |
152 | ee118d95 | Edgar E. Iglesias | &uart_readl, |
153 | ee118d95 | Edgar E. Iglesias | &uart_readl, |
154 | ee118d95 | Edgar E. Iglesias | }; |
155 | ee118d95 | Edgar E. Iglesias | |
156 | d60efc6b | Blue Swirl | static CPUWriteMemoryFunc * const uart_write[] = { |
157 | ee118d95 | Edgar E. Iglesias | &uart_writel, |
158 | ee118d95 | Edgar E. Iglesias | &uart_writel, |
159 | ee118d95 | Edgar E. Iglesias | &uart_writel, |
160 | ee118d95 | Edgar E. Iglesias | }; |
161 | ee118d95 | Edgar E. Iglesias | |
162 | ee118d95 | Edgar E. Iglesias | static void uart_rx(void *opaque, const uint8_t *buf, int size) |
163 | ee118d95 | Edgar E. Iglesias | { |
164 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = opaque;
|
165 | ee118d95 | Edgar E. Iglesias | |
166 | ee118d95 | Edgar E. Iglesias | /* Got a byte. */
|
167 | ee118d95 | Edgar E. Iglesias | if (s->rx_fifo_len >= 8) { |
168 | ee118d95 | Edgar E. Iglesias | printf("WARNING: UART dropped char.\n");
|
169 | ee118d95 | Edgar E. Iglesias | return;
|
170 | ee118d95 | Edgar E. Iglesias | } |
171 | ee118d95 | Edgar E. Iglesias | s->rx_fifo[s->rx_fifo_pos] = *buf; |
172 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_pos++; |
173 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_pos &= 0x7;
|
174 | ee118d95 | Edgar E. Iglesias | s->rx_fifo_len++; |
175 | ee118d95 | Edgar E. Iglesias | |
176 | ee118d95 | Edgar E. Iglesias | uart_update_status(s); |
177 | ee118d95 | Edgar E. Iglesias | uart_update_irq(s); |
178 | ee118d95 | Edgar E. Iglesias | } |
179 | ee118d95 | Edgar E. Iglesias | |
180 | ee118d95 | Edgar E. Iglesias | static int uart_can_rx(void *opaque) |
181 | ee118d95 | Edgar E. Iglesias | { |
182 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = opaque;
|
183 | ee118d95 | Edgar E. Iglesias | int r;
|
184 | ee118d95 | Edgar E. Iglesias | |
185 | ee118d95 | Edgar E. Iglesias | r = s->rx_fifo_len < sizeof(s->rx_fifo);
|
186 | ee118d95 | Edgar E. Iglesias | if (!r)
|
187 | ee118d95 | Edgar E. Iglesias | printf("cannot receive!\n");
|
188 | ee118d95 | Edgar E. Iglesias | return r;
|
189 | ee118d95 | Edgar E. Iglesias | } |
190 | ee118d95 | Edgar E. Iglesias | |
191 | ee118d95 | Edgar E. Iglesias | static void uart_event(void *opaque, int event) |
192 | ee118d95 | Edgar E. Iglesias | { |
193 | ee118d95 | Edgar E. Iglesias | |
194 | ee118d95 | Edgar E. Iglesias | } |
195 | ee118d95 | Edgar E. Iglesias | |
196 | 81a322d4 | Gerd Hoffmann | static int xilinx_uartlite_init(SysBusDevice *dev) |
197 | ee118d95 | Edgar E. Iglesias | { |
198 | ee118d95 | Edgar E. Iglesias | struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev);
|
199 | ee118d95 | Edgar E. Iglesias | int uart_regs;
|
200 | ee118d95 | Edgar E. Iglesias | |
201 | ee118d95 | Edgar E. Iglesias | sysbus_init_irq(dev, &s->irq); |
202 | ee118d95 | Edgar E. Iglesias | |
203 | ee118d95 | Edgar E. Iglesias | uart_update_status(s); |
204 | 2507c12a | Alexander Graf | uart_regs = cpu_register_io_memory(uart_read, uart_write, s, |
205 | 2507c12a | Alexander Graf | DEVICE_NATIVE_ENDIAN); |
206 | ee118d95 | Edgar E. Iglesias | sysbus_init_mmio(dev, R_MAX * 4, uart_regs);
|
207 | ee118d95 | Edgar E. Iglesias | |
208 | ee118d95 | Edgar E. Iglesias | s->chr = qdev_init_chardev(&dev->qdev); |
209 | ee118d95 | Edgar E. Iglesias | if (s->chr)
|
210 | ee118d95 | Edgar E. Iglesias | qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); |
211 | 81a322d4 | Gerd Hoffmann | return 0; |
212 | ee118d95 | Edgar E. Iglesias | } |
213 | ee118d95 | Edgar E. Iglesias | |
214 | ee118d95 | Edgar E. Iglesias | static void xilinx_uart_register(void) |
215 | ee118d95 | Edgar E. Iglesias | { |
216 | ee118d95 | Edgar E. Iglesias | sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite), |
217 | ee118d95 | Edgar E. Iglesias | xilinx_uartlite_init); |
218 | ee118d95 | Edgar E. Iglesias | } |
219 | ee118d95 | Edgar E. Iglesias | |
220 | ee118d95 | Edgar E. Iglesias | device_init(xilinx_uart_register) |