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