1 /* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2 For "old style" UARTs on BF53x/etc... parts.
4 Copyright (C) 2010-2024 Free Software Foundation, Inc.
5 Contributed by Analog Devices, Inc.
7 This file is part of simulators.
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.
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.
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/>. */
22 /* This must come before any other includes. */
26 #include "dv-sockser.h"
28 #include "dv-bfin_uart.h"
30 /* XXX: Should we bother emulating the TX/RX FIFOs ? */
32 /* Internal state needs to be the same as bfin_uart2. */
35 /* This top portion matches common dv_bfin struct. */
37 struct hw
*dma_master
;
40 struct hw_event
*handler
;
44 /* This is aliased to DLH. */
46 /* These are aliased to DLL. */
49 /* Order after here is important -- matches hardware MMR layout. */
50 bu16
BFIN_MMR_16(dll
);
51 bu16
BFIN_MMR_16(dlh
);
52 bu16
BFIN_MMR_16(iir
);
53 bu16
BFIN_MMR_16(lcr
);
54 bu16
BFIN_MMR_16(mcr
);
55 bu16
BFIN_MMR_16(lsr
);
56 bu16
BFIN_MMR_16(msr
);
57 bu16
BFIN_MMR_16(scr
);
59 bu16
BFIN_MMR_16(gctl
);
61 #define mmr_base() offsetof(struct bfin_uart, dll)
62 #define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
64 static const char * const mmr_names
[] =
66 "UART_RBR/UART_THR", "UART_IER", "UART_IIR", "UART_LCR", "UART_MCR",
67 "UART_LSR", "UART_MSR", "UART_SCR", "<INV>", "UART_GCTL",
69 static const char *mmr_name (struct bfin_uart
*uart
, bu32 idx
)
73 return idx
== 0 ? "UART_DLL" : "UART_DLH";
74 return mmr_names
[idx
];
76 #define mmr_name(off) mmr_name (uart, (off) / 4)
79 bfin_uart_poll (struct hw
*me
, void *data
)
81 struct bfin_uart
*uart
= data
;
86 lsr
= bfin_uart_get_status (me
);
88 hw_port_event (me
, DV_PORT_RX
, 1);
90 bfin_uart_reschedule (me
);
94 bfin_uart_reschedule (struct hw
*me
)
96 struct bfin_uart
*uart
= hw_data (me
);
98 if (uart
->ier
& ERBFI
)
101 uart
->handler
= hw_event_queue_schedule (me
, 10000,
102 bfin_uart_poll
, uart
);
108 hw_event_queue_deschedule (me
, uart
->handler
);
109 uart
->handler
= NULL
;
115 bfin_uart_write_byte (struct hw
*me
, bu16 thr
, bu16 mcr
)
117 struct bfin_uart
*uart
= hw_data (me
);
118 unsigned char ch
= thr
;
122 /* XXX: This probably doesn't work exactly right with
123 external FIFOs ... */
124 uart
->saved_byte
= thr
;
125 uart
->saved_count
= 1;
128 bfin_uart_write_buffer (me
, &ch
, 1);
134 bfin_uart_io_write_buffer (struct hw
*me
, const void *source
,
135 int space
, address_word addr
, unsigned nr_bytes
)
137 struct bfin_uart
*uart
= hw_data (me
);
142 /* Invalid access mode is higher priority than missing register. */
143 if (!dv_bfin_mmr_require_16 (me
, addr
, nr_bytes
, true))
146 value
= dv_load_2 (source
);
147 mmr_off
= addr
- uart
->base
;
148 valuep
= (void *)((uintptr_t)uart
+ mmr_base() + mmr_off
);
152 /* XXX: All MMRs are "8bit" ... what happens to high 8bits ? */
155 case mmr_offset(dll
):
156 if (uart
->lcr
& DLAB
)
160 uart
->thr
= bfin_uart_write_byte (me
, value
, uart
->mcr
);
162 if (uart
->ier
& ETBEI
)
163 hw_port_event (me
, DV_PORT_TX
, 1);
166 case mmr_offset(dlh
):
167 if (uart
->lcr
& DLAB
)
172 bfin_uart_reschedule (me
);
175 case mmr_offset(iir
):
176 case mmr_offset(lsr
):
177 /* XXX: Writes are ignored ? */
179 case mmr_offset(lcr
):
180 case mmr_offset(mcr
):
181 case mmr_offset(scr
):
182 case mmr_offset(gctl
):
186 dv_bfin_mmr_invalid (me
, addr
, nr_bytes
, true);
193 /* Switch between socket and stdin on the fly. */
195 bfin_uart_get_next_byte (struct hw
*me
, bu16 rbr
, bu16 mcr
, bool *fresh
)
197 SIM_DESC sd
= hw_system (me
);
198 struct bfin_uart
*uart
= hw_data (me
);
199 int status
= dv_sockser_status (sd
);
202 /* NB: The "uart" here may only use interal state. */
209 if (uart
->saved_count
> 0)
212 rbr
= uart
->saved_byte
;
215 else if (mcr
& LOOP_ENA
)
217 /* RX is disconnected, so only return local data. */
219 else if (status
& DV_SOCKSER_DISCONNECTED
)
222 int ret
= sim_io_poll_read (sd
, 0/*STDIN*/, &byte
, 1);
231 rbr
= dv_sockser_read (sd
);
237 bfin_uart_get_status (struct hw
*me
)
239 SIM_DESC sd
= hw_system (me
);
240 struct bfin_uart
*uart
= hw_data (me
);
241 int status
= dv_sockser_status (sd
);
244 if (status
& DV_SOCKSER_DISCONNECTED
)
246 if (uart
->saved_count
<= 0)
247 uart
->saved_count
= sim_io_poll_read (sd
, 0/*STDIN*/,
248 &uart
->saved_byte
, 1);
249 lsr
|= TEMT
| THRE
| (uart
->saved_count
> 0 ? DR
: 0);
252 lsr
|= (status
& DV_SOCKSER_INPUT_EMPTY
? 0 : DR
) |
253 (status
& DV_SOCKSER_OUTPUT_EMPTY
? TEMT
| THRE
: 0);
259 bfin_uart_io_read_buffer (struct hw
*me
, void *dest
,
260 int space
, address_word addr
, unsigned nr_bytes
)
262 struct bfin_uart
*uart
= hw_data (me
);
266 /* Invalid access mode is higher priority than missing register. */
267 if (!dv_bfin_mmr_require_16 (me
, addr
, nr_bytes
, false))
270 mmr_off
= addr
- uart
->base
;
271 valuep
= (void *)((uintptr_t)uart
+ mmr_base() + mmr_off
);
277 case mmr_offset(dll
):
278 if (uart
->lcr
& DLAB
)
279 dv_store_2 (dest
, uart
->dll
);
282 uart
->rbr
= bfin_uart_get_next_byte (me
, uart
->rbr
, uart
->mcr
, NULL
);
283 dv_store_2 (dest
, uart
->rbr
);
286 case mmr_offset(dlh
):
287 if (uart
->lcr
& DLAB
)
288 dv_store_2 (dest
, uart
->dlh
);
290 dv_store_2 (dest
, uart
->ier
);
292 case mmr_offset(lsr
):
293 /* XXX: Reads are destructive on most parts, but not all ... */
294 uart
->lsr
|= bfin_uart_get_status (me
);
295 dv_store_2 (dest
, *valuep
);
298 case mmr_offset(iir
):
299 /* XXX: Reads are destructive ... */
300 case mmr_offset(lcr
):
301 case mmr_offset(mcr
):
302 case mmr_offset(scr
):
303 case mmr_offset(gctl
):
304 dv_store_2 (dest
, *valuep
);
307 dv_bfin_mmr_invalid (me
, addr
, nr_bytes
, false);
315 bfin_uart_read_buffer (struct hw
*me
, unsigned char *buffer
, unsigned nr_bytes
)
317 SIM_DESC sd
= hw_system (me
);
318 struct bfin_uart
*uart
= hw_data (me
);
319 int status
= dv_sockser_status (sd
);
322 if (status
& DV_SOCKSER_DISCONNECTED
)
326 while (uart
->saved_count
> 0 && i
< nr_bytes
)
328 buffer
[i
++] = uart
->saved_byte
;
332 ret
= sim_io_poll_read (sd
, 0/*STDIN*/, (char *) buffer
, nr_bytes
- i
);
337 buffer
[i
++] = dv_sockser_read (sd
);
343 bfin_uart_dma_read_buffer (struct hw
*me
, void *dest
, int space
,
344 unsigned_word addr
, unsigned nr_bytes
)
346 HW_TRACE_DMA_READ ();
347 return bfin_uart_read_buffer (me
, dest
, nr_bytes
);
351 bfin_uart_write_buffer (struct hw
*me
, const unsigned char *buffer
,
354 SIM_DESC sd
= hw_system (me
);
355 int status
= dv_sockser_status (sd
);
357 if (status
& DV_SOCKSER_DISCONNECTED
)
359 sim_io_write_stdout (sd
, (const char *) buffer
, nr_bytes
);
360 sim_io_flush_stdout (sd
);
364 /* Normalize errors to a value of 0. */
365 int ret
= dv_sockser_write_buffer (sd
, buffer
, nr_bytes
);
366 nr_bytes
= CLAMP (ret
, 0, nr_bytes
);
373 bfin_uart_dma_write_buffer (struct hw
*me
, const void *source
,
374 int space
, unsigned_word addr
,
376 int violate_read_only_section
)
378 struct bfin_uart
*uart
= hw_data (me
);
381 HW_TRACE_DMA_WRITE ();
383 ret
= bfin_uart_write_buffer (me
, source
, nr_bytes
);
385 if (ret
== nr_bytes
&& (uart
->ier
& ETBEI
))
386 hw_port_event (me
, DV_PORT_TX
, 1);
391 static const struct hw_port_descriptor bfin_uart_ports
[] =
393 { "tx", DV_PORT_TX
, 0, output_port
, },
394 { "rx", DV_PORT_RX
, 0, output_port
, },
395 { "stat", DV_PORT_STAT
, 0, output_port
, },
400 attach_bfin_uart_regs (struct hw
*me
, struct bfin_uart
*uart
)
402 address_word attach_address
;
404 unsigned attach_size
;
405 reg_property_spec reg
;
407 if (hw_find_property (me
, "reg") == NULL
)
408 hw_abort (me
, "Missing \"reg\" property");
410 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
411 hw_abort (me
, "\"reg\" property must contain three addr/size entries");
413 hw_unit_address_to_attach_address (hw_parent (me
),
415 &attach_space
, &attach_address
, me
);
416 hw_unit_size_to_attach_size (hw_parent (me
), ®
.size
, &attach_size
, me
);
418 if (attach_size
!= BFIN_MMR_UART_SIZE
)
419 hw_abort (me
, "\"reg\" size must be %#x", BFIN_MMR_UART_SIZE
);
421 hw_attach_address (hw_parent (me
),
422 0, attach_space
, attach_address
, attach_size
, me
);
424 uart
->base
= attach_address
;
428 bfin_uart_finish (struct hw
*me
)
430 struct bfin_uart
*uart
;
432 uart
= HW_ZALLOC (me
, struct bfin_uart
);
434 set_hw_data (me
, uart
);
435 set_hw_io_read_buffer (me
, bfin_uart_io_read_buffer
);
436 set_hw_io_write_buffer (me
, bfin_uart_io_write_buffer
);
437 set_hw_dma_read_buffer (me
, bfin_uart_dma_read_buffer
);
438 set_hw_dma_write_buffer (me
, bfin_uart_dma_write_buffer
);
439 set_hw_ports (me
, bfin_uart_ports
);
441 attach_bfin_uart_regs (me
, uart
);
443 /* Initialize the UART. */
449 const struct hw_descriptor dv_bfin_uart_descriptor
[] =
451 {"bfin_uart", bfin_uart_finish
,},