]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/bfin/dv-bfin_uart.c
sim: bfin: fix brace style
[thirdparty/binutils-gdb.git] / sim / bfin / dv-bfin_uart.c
1 /* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2 For "old style" UARTs on BF53x/etc... parts.
3
4 Copyright (C) 2010-2011 Free Software Foundation, Inc.
5 Contributed by Analog Devices, Inc.
6
7 This file is part of simulators.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "config.h"
23
24 #include "sim-main.h"
25 #include "dv-sockser.h"
26 #include "devices.h"
27 #include "dv-bfin_uart.h"
28
29 /* XXX: Should we bother emulating the TX/RX FIFOs ? */
30
31 /* Internal state needs to be the same as bfin_uart2. */
32 struct bfin_uart
33 {
34 /* This top portion matches common dv_bfin struct. */
35 bu32 base;
36 struct hw *dma_master;
37 bool acked;
38
39 struct hw_event *handler;
40 char saved_byte;
41 int saved_count;
42
43 /* This is aliased to DLH. */
44 bu16 ier;
45 /* These are aliased to DLL. */
46 bu16 thr, rbr;
47
48 /* Order after here is important -- matches hardware MMR layout. */
49 bu16 BFIN_MMR_16(dll);
50 bu16 BFIN_MMR_16(dlh);
51 bu16 BFIN_MMR_16(iir);
52 bu16 BFIN_MMR_16(lcr);
53 bu16 BFIN_MMR_16(mcr);
54 bu16 BFIN_MMR_16(lsr);
55 bu16 BFIN_MMR_16(msr);
56 bu16 BFIN_MMR_16(scr);
57 bu16 _pad0[2];
58 bu16 BFIN_MMR_16(gctl);
59 };
60 #define mmr_base() offsetof(struct bfin_uart, dll)
61 #define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
62
63 static const char * const mmr_names[] =
64 {
65 "UART_RBR/UART_THR", "UART_IER", "UART_IIR", "UART_LCR", "UART_MCR",
66 "UART_LSR", "UART_MSR", "UART_SCR", "<INV>", "UART_GCTL",
67 };
68 static const char *mmr_name (struct bfin_uart *uart, bu32 idx)
69 {
70 if (uart->lcr & DLAB)
71 if (idx < 2)
72 return idx == 0 ? "UART_DLL" : "UART_DLH";
73 return mmr_names[idx];
74 }
75 #define mmr_name(off) mmr_name (uart, (off) / 4)
76
77 #ifndef HAVE_DV_SOCKSER
78 # define dv_sockser_status(sd) -1
79 # define dv_sockser_write(sd, byte) do { ; } while (0)
80 # define dv_sockser_read(sd) 0xff
81 #endif
82
83 static void
84 bfin_uart_poll (struct hw *me, void *data)
85 {
86 struct bfin_uart *uart = data;
87 bu16 lsr;
88
89 uart->handler = NULL;
90
91 lsr = bfin_uart_get_status (me);
92 if (lsr & DR)
93 hw_port_event (me, DV_PORT_RX, 1);
94
95 bfin_uart_reschedule (me);
96 }
97
98 void
99 bfin_uart_reschedule (struct hw *me)
100 {
101 struct bfin_uart *uart = hw_data (me);
102
103 if (uart->ier & ERBFI)
104 {
105 if (!uart->handler)
106 uart->handler = hw_event_queue_schedule (me, 10000,
107 bfin_uart_poll, uart);
108 }
109 else
110 {
111 if (uart->handler)
112 {
113 hw_event_queue_deschedule (me, uart->handler);
114 uart->handler = NULL;
115 }
116 }
117 }
118
119 bu16
120 bfin_uart_write_byte (struct hw *me, bu16 thr)
121 {
122 unsigned char ch = thr;
123 bfin_uart_write_buffer (me, &ch, 1);
124 return thr;
125 }
126
127 static unsigned
128 bfin_uart_io_write_buffer (struct hw *me, const void *source,
129 int space, address_word addr, unsigned nr_bytes)
130 {
131 struct bfin_uart *uart = hw_data (me);
132 bu32 mmr_off;
133 bu32 value;
134 bu16 *valuep;
135
136 value = dv_load_2 (source);
137 mmr_off = addr - uart->base;
138 valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
139
140 HW_TRACE_WRITE ();
141
142 dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
143
144 /* XXX: All MMRs are "8bit" ... what happens to high 8bits ? */
145 switch (mmr_off)
146 {
147 case mmr_offset(dll):
148 if (uart->lcr & DLAB)
149 uart->dll = value;
150 else
151 {
152 uart->thr = bfin_uart_write_byte (me, value);
153
154 if (uart->ier & ETBEI)
155 hw_port_event (me, DV_PORT_TX, 1);
156 }
157 break;
158 case mmr_offset(dlh):
159 if (uart->lcr & DLAB)
160 uart->dlh = value;
161 else
162 {
163 uart->ier = value;
164 bfin_uart_reschedule (me);
165 }
166 break;
167 case mmr_offset(iir):
168 case mmr_offset(lsr):
169 /* XXX: Writes are ignored ? */
170 break;
171 case mmr_offset(lcr):
172 case mmr_offset(mcr):
173 case mmr_offset(scr):
174 case mmr_offset(gctl):
175 *valuep = value;
176 break;
177 default:
178 dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
179 break;
180 }
181
182 return nr_bytes;
183 }
184
185 /* Switch between socket and stdin on the fly. */
186 bu16
187 bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bool *fresh)
188 {
189 SIM_DESC sd = hw_system (me);
190 struct bfin_uart *uart = hw_data (me);
191 int status = dv_sockser_status (sd);
192 bool _fresh;
193
194 /* NB: The "uart" here may only use interal state. */
195
196 if (!fresh)
197 fresh = &_fresh;
198
199 *fresh = false;
200 if (status & DV_SOCKSER_DISCONNECTED)
201 {
202 if (uart->saved_count > 0)
203 {
204 *fresh = true;
205 rbr = uart->saved_byte;
206 --uart->saved_count;
207 }
208 else
209 {
210 char byte;
211 int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1);
212 if (ret > 0)
213 {
214 *fresh = true;
215 rbr = byte;
216 }
217 }
218 }
219 else
220 rbr = dv_sockser_read (sd);
221
222 return rbr;
223 }
224
225 bu16
226 bfin_uart_get_status (struct hw *me)
227 {
228 SIM_DESC sd = hw_system (me);
229 struct bfin_uart *uart = hw_data (me);
230 int status = dv_sockser_status (sd);
231 bu16 lsr = 0;
232
233 if (status & DV_SOCKSER_DISCONNECTED)
234 {
235 if (uart->saved_count <= 0)
236 uart->saved_count = sim_io_poll_read (sd, 0/*STDIN*/,
237 &uart->saved_byte, 1);
238 lsr |= TEMT | THRE | (uart->saved_count > 0 ? DR : 0);
239 }
240 else
241 lsr |= (status & DV_SOCKSER_INPUT_EMPTY ? 0 : DR) |
242 (status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0);
243
244 return lsr;
245 }
246
247 static unsigned
248 bfin_uart_io_read_buffer (struct hw *me, void *dest,
249 int space, address_word addr, unsigned nr_bytes)
250 {
251 struct bfin_uart *uart = hw_data (me);
252 bu32 mmr_off;
253 bu16 *valuep;
254
255 mmr_off = addr - uart->base;
256 valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
257
258 HW_TRACE_READ ();
259
260 dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
261
262 switch (mmr_off)
263 {
264 case mmr_offset(dll):
265 if (uart->lcr & DLAB)
266 dv_store_2 (dest, uart->dll);
267 else
268 {
269 uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, NULL);
270 dv_store_2 (dest, uart->rbr);
271 }
272 break;
273 case mmr_offset(dlh):
274 if (uart->lcr & DLAB)
275 dv_store_2 (dest, uart->dlh);
276 else
277 dv_store_2 (dest, uart->ier);
278 break;
279 case mmr_offset(lsr):
280 /* XXX: Reads are destructive on most parts, but not all ... */
281 uart->lsr |= bfin_uart_get_status (me);
282 dv_store_2 (dest, *valuep);
283 uart->lsr = 0;
284 break;
285 case mmr_offset(iir):
286 /* XXX: Reads are destructive ... */
287 case mmr_offset(lcr):
288 case mmr_offset(mcr):
289 case mmr_offset(scr):
290 case mmr_offset(gctl):
291 dv_store_2 (dest, *valuep);
292 break;
293 default:
294 dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
295 break;
296 }
297
298 return nr_bytes;
299 }
300
301 unsigned
302 bfin_uart_read_buffer (struct hw *me, unsigned char *buffer, unsigned nr_bytes)
303 {
304 SIM_DESC sd = hw_system (me);
305 struct bfin_uart *uart = hw_data (me);
306 int status = dv_sockser_status (sd);
307 unsigned i = 0;
308
309 if (status & DV_SOCKSER_DISCONNECTED)
310 {
311 int ret;
312
313 while (uart->saved_count > 0 && i < nr_bytes)
314 {
315 buffer[i++] = uart->saved_byte;
316 --uart->saved_count;
317 }
318
319 ret = sim_io_poll_read (sd, 0/*STDIN*/, (char *) buffer, nr_bytes - i);
320 if (ret > 0)
321 i += ret;
322 }
323 else
324 buffer[i++] = dv_sockser_read (sd);
325
326 return i;
327 }
328
329 static unsigned
330 bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
331 unsigned_word addr, unsigned nr_bytes)
332 {
333 HW_TRACE_DMA_READ ();
334 return bfin_uart_read_buffer (me, dest, nr_bytes);
335 }
336
337 unsigned
338 bfin_uart_write_buffer (struct hw *me, const unsigned char *buffer,
339 unsigned nr_bytes)
340 {
341 SIM_DESC sd = hw_system (me);
342 int status = dv_sockser_status (sd);
343
344 if (status & DV_SOCKSER_DISCONNECTED)
345 {
346 sim_io_write_stdout (sd, (const char *) buffer, nr_bytes);
347 sim_io_flush_stdout (sd);
348 }
349 else
350 {
351 /* Normalize errors to a value of 0. */
352 int ret = dv_sockser_write_buffer (sd, buffer, nr_bytes);
353 nr_bytes = CLAMP (ret, 0, nr_bytes);
354 }
355
356 return nr_bytes;
357 }
358
359 static unsigned
360 bfin_uart_dma_write_buffer (struct hw *me, const void *source,
361 int space, unsigned_word addr,
362 unsigned nr_bytes,
363 int violate_read_only_section)
364 {
365 struct bfin_uart *uart = hw_data (me);
366 unsigned ret;
367
368 HW_TRACE_DMA_WRITE ();
369
370 ret = bfin_uart_write_buffer (me, source, nr_bytes);
371
372 if (ret == nr_bytes && (uart->ier & ETBEI))
373 hw_port_event (me, DV_PORT_TX, 1);
374
375 return ret;
376 }
377
378 static const struct hw_port_descriptor bfin_uart_ports[] =
379 {
380 { "tx", DV_PORT_TX, 0, output_port, },
381 { "rx", DV_PORT_RX, 0, output_port, },
382 { "stat", DV_PORT_STAT, 0, output_port, },
383 { NULL, 0, 0, 0, },
384 };
385
386 static void
387 attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
388 {
389 address_word attach_address;
390 int attach_space;
391 unsigned attach_size;
392 reg_property_spec reg;
393
394 if (hw_find_property (me, "reg") == NULL)
395 hw_abort (me, "Missing \"reg\" property");
396
397 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
398 hw_abort (me, "\"reg\" property must contain three addr/size entries");
399
400 hw_unit_address_to_attach_address (hw_parent (me),
401 &reg.address,
402 &attach_space, &attach_address, me);
403 hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
404
405 if (attach_size != BFIN_MMR_UART_SIZE)
406 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART_SIZE);
407
408 hw_attach_address (hw_parent (me),
409 0, attach_space, attach_address, attach_size, me);
410
411 uart->base = attach_address;
412 }
413
414 static void
415 bfin_uart_finish (struct hw *me)
416 {
417 struct bfin_uart *uart;
418
419 uart = HW_ZALLOC (me, struct bfin_uart);
420
421 set_hw_data (me, uart);
422 set_hw_io_read_buffer (me, bfin_uart_io_read_buffer);
423 set_hw_io_write_buffer (me, bfin_uart_io_write_buffer);
424 set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer);
425 set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer);
426 set_hw_ports (me, bfin_uart_ports);
427
428 attach_bfin_uart_regs (me, uart);
429
430 /* Initialize the UART. */
431 uart->dll = 0x0001;
432 uart->iir = 0x0001;
433 uart->lsr = 0x0060;
434 }
435
436 const struct hw_descriptor dv_bfin_uart_descriptor[] = {
437 {"bfin_uart", bfin_uart_finish,},
438 {NULL, NULL},
439 };