]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/bfin/dv-bfin_uart.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / bfin / dv-bfin_uart.c
CommitLineData
ef016f83
MF
1/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2 For "old style" UARTs on BF53x/etc... parts.
3
8acc9f48 4 Copyright (C) 2010-2013 Free Software Foundation, Inc.
ef016f83
MF
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. */
32struct 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
990d19fd
MF
63static const char * const mmr_names[] =
64{
ef016f83
MF
65 "UART_RBR/UART_THR", "UART_IER", "UART_IIR", "UART_LCR", "UART_MCR",
66 "UART_LSR", "UART_MSR", "UART_SCR", "<INV>", "UART_GCTL",
67};
68static 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
83static void
84bfin_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
98void
99bfin_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
119bu16
28fe96b7 120bfin_uart_write_byte (struct hw *me, bu16 thr, bu16 mcr)
ef016f83 121{
28fe96b7 122 struct bfin_uart *uart = hw_data (me);
ef016f83 123 unsigned char ch = thr;
28fe96b7
MF
124
125 if (mcr & LOOP_ENA)
126 {
127 /* XXX: This probably doesn't work exactly right with
128 external FIFOs ... */
129 uart->saved_byte = thr;
130 uart->saved_count = 1;
131 }
132
ef016f83 133 bfin_uart_write_buffer (me, &ch, 1);
28fe96b7 134
ef016f83
MF
135 return thr;
136}
137
138static unsigned
139bfin_uart_io_write_buffer (struct hw *me, const void *source,
140 int space, address_word addr, unsigned nr_bytes)
141{
142 struct bfin_uart *uart = hw_data (me);
143 bu32 mmr_off;
144 bu32 value;
145 bu16 *valuep;
146
147 value = dv_load_2 (source);
148 mmr_off = addr - uart->base;
149 valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
150
151 HW_TRACE_WRITE ();
152
153 dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
154
155 /* XXX: All MMRs are "8bit" ... what happens to high 8bits ? */
156 switch (mmr_off)
157 {
158 case mmr_offset(dll):
159 if (uart->lcr & DLAB)
160 uart->dll = value;
161 else
162 {
28fe96b7 163 uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
ef016f83
MF
164
165 if (uart->ier & ETBEI)
166 hw_port_event (me, DV_PORT_TX, 1);
167 }
168 break;
169 case mmr_offset(dlh):
170 if (uart->lcr & DLAB)
171 uart->dlh = value;
172 else
173 {
174 uart->ier = value;
175 bfin_uart_reschedule (me);
176 }
177 break;
178 case mmr_offset(iir):
179 case mmr_offset(lsr):
180 /* XXX: Writes are ignored ? */
181 break;
182 case mmr_offset(lcr):
183 case mmr_offset(mcr):
184 case mmr_offset(scr):
185 case mmr_offset(gctl):
186 *valuep = value;
187 break;
188 default:
189 dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
190 break;
191 }
192
193 return nr_bytes;
194}
195
196/* Switch between socket and stdin on the fly. */
197bu16
28fe96b7 198bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bu16 mcr, bool *fresh)
ef016f83
MF
199{
200 SIM_DESC sd = hw_system (me);
201 struct bfin_uart *uart = hw_data (me);
202 int status = dv_sockser_status (sd);
203 bool _fresh;
204
205 /* NB: The "uart" here may only use interal state. */
206
207 if (!fresh)
208 fresh = &_fresh;
209
210 *fresh = false;
28fe96b7
MF
211
212 if (uart->saved_count > 0)
ef016f83 213 {
28fe96b7
MF
214 *fresh = true;
215 rbr = uart->saved_byte;
216 --uart->saved_count;
217 }
218 else if (mcr & LOOP_ENA)
219 {
220 /* RX is disconnected, so only return local data. */
221 }
222 else if (status & DV_SOCKSER_DISCONNECTED)
223 {
224 char byte;
225 int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1);
226
227 if (ret > 0)
ef016f83
MF
228 {
229 *fresh = true;
28fe96b7 230 rbr = byte;
ef016f83
MF
231 }
232 }
233 else
234 rbr = dv_sockser_read (sd);
235
236 return rbr;
237}
238
239bu16
240bfin_uart_get_status (struct hw *me)
241{
242 SIM_DESC sd = hw_system (me);
243 struct bfin_uart *uart = hw_data (me);
244 int status = dv_sockser_status (sd);
245 bu16 lsr = 0;
246
247 if (status & DV_SOCKSER_DISCONNECTED)
248 {
249 if (uart->saved_count <= 0)
250 uart->saved_count = sim_io_poll_read (sd, 0/*STDIN*/,
251 &uart->saved_byte, 1);
252 lsr |= TEMT | THRE | (uart->saved_count > 0 ? DR : 0);
253 }
254 else
255 lsr |= (status & DV_SOCKSER_INPUT_EMPTY ? 0 : DR) |
28fe96b7 256 (status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0);
ef016f83
MF
257
258 return lsr;
259}
260
261static unsigned
262bfin_uart_io_read_buffer (struct hw *me, void *dest,
263 int space, address_word addr, unsigned nr_bytes)
264{
265 struct bfin_uart *uart = hw_data (me);
266 bu32 mmr_off;
267 bu16 *valuep;
268
269 mmr_off = addr - uart->base;
270 valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
271
272 HW_TRACE_READ ();
273
274 dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
275
276 switch (mmr_off)
277 {
278 case mmr_offset(dll):
279 if (uart->lcr & DLAB)
280 dv_store_2 (dest, uart->dll);
281 else
282 {
28fe96b7 283 uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
ef016f83
MF
284 dv_store_2 (dest, uart->rbr);
285 }
286 break;
287 case mmr_offset(dlh):
288 if (uart->lcr & DLAB)
289 dv_store_2 (dest, uart->dlh);
290 else
291 dv_store_2 (dest, uart->ier);
292 break;
293 case mmr_offset(lsr):
294 /* XXX: Reads are destructive on most parts, but not all ... */
295 uart->lsr |= bfin_uart_get_status (me);
296 dv_store_2 (dest, *valuep);
297 uart->lsr = 0;
298 break;
299 case mmr_offset(iir):
300 /* XXX: Reads are destructive ... */
301 case mmr_offset(lcr):
302 case mmr_offset(mcr):
303 case mmr_offset(scr):
304 case mmr_offset(gctl):
305 dv_store_2 (dest, *valuep);
306 break;
307 default:
308 dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
309 break;
310 }
311
312 return nr_bytes;
313}
314
315unsigned
316bfin_uart_read_buffer (struct hw *me, unsigned char *buffer, unsigned nr_bytes)
317{
318 SIM_DESC sd = hw_system (me);
319 struct bfin_uart *uart = hw_data (me);
320 int status = dv_sockser_status (sd);
321 unsigned i = 0;
322
323 if (status & DV_SOCKSER_DISCONNECTED)
324 {
325 int ret;
326
327 while (uart->saved_count > 0 && i < nr_bytes)
328 {
329 buffer[i++] = uart->saved_byte;
330 --uart->saved_count;
331 }
332
333 ret = sim_io_poll_read (sd, 0/*STDIN*/, (char *) buffer, nr_bytes - i);
334 if (ret > 0)
335 i += ret;
336 }
337 else
338 buffer[i++] = dv_sockser_read (sd);
339
340 return i;
341}
342
343static unsigned
344bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
345 unsigned_word addr, unsigned nr_bytes)
346{
347 HW_TRACE_DMA_READ ();
348 return bfin_uart_read_buffer (me, dest, nr_bytes);
349}
350
351unsigned
352bfin_uart_write_buffer (struct hw *me, const unsigned char *buffer,
353 unsigned nr_bytes)
354{
355 SIM_DESC sd = hw_system (me);
356 int status = dv_sockser_status (sd);
357
358 if (status & DV_SOCKSER_DISCONNECTED)
359 {
360 sim_io_write_stdout (sd, (const char *) buffer, nr_bytes);
361 sim_io_flush_stdout (sd);
362 }
363 else
364 {
365 /* Normalize errors to a value of 0. */
366 int ret = dv_sockser_write_buffer (sd, buffer, nr_bytes);
367 nr_bytes = CLAMP (ret, 0, nr_bytes);
368 }
369
370 return nr_bytes;
371}
372
373static unsigned
374bfin_uart_dma_write_buffer (struct hw *me, const void *source,
375 int space, unsigned_word addr,
376 unsigned nr_bytes,
377 int violate_read_only_section)
378{
379 struct bfin_uart *uart = hw_data (me);
380 unsigned ret;
381
382 HW_TRACE_DMA_WRITE ();
383
384 ret = bfin_uart_write_buffer (me, source, nr_bytes);
385
386 if (ret == nr_bytes && (uart->ier & ETBEI))
387 hw_port_event (me, DV_PORT_TX, 1);
388
389 return ret;
390}
391
990d19fd
MF
392static const struct hw_port_descriptor bfin_uart_ports[] =
393{
ef016f83
MF
394 { "tx", DV_PORT_TX, 0, output_port, },
395 { "rx", DV_PORT_RX, 0, output_port, },
396 { "stat", DV_PORT_STAT, 0, output_port, },
397 { NULL, 0, 0, 0, },
398};
399
400static void
401attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
402{
403 address_word attach_address;
404 int attach_space;
405 unsigned attach_size;
406 reg_property_spec reg;
407
408 if (hw_find_property (me, "reg") == NULL)
409 hw_abort (me, "Missing \"reg\" property");
410
411 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
412 hw_abort (me, "\"reg\" property must contain three addr/size entries");
413
414 hw_unit_address_to_attach_address (hw_parent (me),
415 &reg.address,
416 &attach_space, &attach_address, me);
417 hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
418
419 if (attach_size != BFIN_MMR_UART_SIZE)
420 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART_SIZE);
421
422 hw_attach_address (hw_parent (me),
423 0, attach_space, attach_address, attach_size, me);
424
425 uart->base = attach_address;
426}
427
428static void
429bfin_uart_finish (struct hw *me)
430{
431 struct bfin_uart *uart;
432
433 uart = HW_ZALLOC (me, struct bfin_uart);
434
435 set_hw_data (me, uart);
436 set_hw_io_read_buffer (me, bfin_uart_io_read_buffer);
437 set_hw_io_write_buffer (me, bfin_uart_io_write_buffer);
438 set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer);
439 set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer);
440 set_hw_ports (me, bfin_uart_ports);
441
442 attach_bfin_uart_regs (me, uart);
443
444 /* Initialize the UART. */
445 uart->dll = 0x0001;
446 uart->iir = 0x0001;
447 uart->lsr = 0x0060;
448}
449
81d126c3
MF
450const struct hw_descriptor dv_bfin_uart_descriptor[] =
451{
ef016f83
MF
452 {"bfin_uart", bfin_uart_finish,},
453 {NULL, NULL},
454};