1/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2   For "old style" UARTs on BF53x/etc... parts.
3
4   Copyright (C) 2010-2023 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/* This must come before any other includes.  */
23#include "defs.h"
24
25#include "sim-main.h"
26#include "dv-sockser.h"
27#include "devices.h"
28#include "dv-bfin_uart.h"
29
30/* XXX: Should we bother emulating the TX/RX FIFOs ?  */
31
32/* Internal state needs to be the same as bfin_uart2.  */
33struct bfin_uart
34{
35  /* This top portion matches common dv_bfin struct.  */
36  bu32 base;
37  struct hw *dma_master;
38  bool acked;
39
40  struct hw_event *handler;
41  char saved_byte;
42  int saved_count;
43
44  /* This is aliased to DLH.  */
45  bu16 ier;
46  /* These are aliased to DLL.  */
47  bu16 thr, rbr;
48
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);
58  bu16 _pad0[2];
59  bu16 BFIN_MMR_16(gctl);
60};
61#define mmr_base()      offsetof(struct bfin_uart, dll)
62#define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
63
64static const char * const mmr_names[] =
65{
66  "UART_RBR/UART_THR", "UART_IER", "UART_IIR", "UART_LCR", "UART_MCR",
67  "UART_LSR", "UART_MSR", "UART_SCR", "<INV>", "UART_GCTL",
68};
69static const char *mmr_name (struct bfin_uart *uart, bu32 idx)
70{
71  if (uart->lcr & DLAB)
72    if (idx < 2)
73      return idx == 0 ? "UART_DLL" : "UART_DLH";
74  return mmr_names[idx];
75}
76#define mmr_name(off) mmr_name (uart, (off) / 4)
77
78static void
79bfin_uart_poll (struct hw *me, void *data)
80{
81  struct bfin_uart *uart = data;
82  bu16 lsr;
83
84  uart->handler = NULL;
85
86  lsr = bfin_uart_get_status (me);
87  if (lsr & DR)
88    hw_port_event (me, DV_PORT_RX, 1);
89
90  bfin_uart_reschedule (me);
91}
92
93void
94bfin_uart_reschedule (struct hw *me)
95{
96  struct bfin_uart *uart = hw_data (me);
97
98  if (uart->ier & ERBFI)
99    {
100      if (!uart->handler)
101	uart->handler = hw_event_queue_schedule (me, 10000,
102						 bfin_uart_poll, uart);
103    }
104  else
105    {
106      if (uart->handler)
107	{
108	  hw_event_queue_deschedule (me, uart->handler);
109	  uart->handler = NULL;
110	}
111    }
112}
113
114bu16
115bfin_uart_write_byte (struct hw *me, bu16 thr, bu16 mcr)
116{
117  struct bfin_uart *uart = hw_data (me);
118  unsigned char ch = thr;
119
120  if (mcr & LOOP_ENA)
121    {
122      /* XXX: This probably doesn't work exactly right with
123              external FIFOs ...  */
124      uart->saved_byte = thr;
125      uart->saved_count = 1;
126    }
127
128  bfin_uart_write_buffer (me, &ch, 1);
129
130  return thr;
131}
132
133static unsigned
134bfin_uart_io_write_buffer (struct hw *me, const void *source,
135			   int space, address_word addr, unsigned nr_bytes)
136{
137  struct bfin_uart *uart = hw_data (me);
138  bu32 mmr_off;
139  bu32 value;
140  bu16 *valuep;
141
142  /* Invalid access mode is higher priority than missing register.  */
143  if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
144    return 0;
145
146  value = dv_load_2 (source);
147  mmr_off = addr - uart->base;
148  valuep = (void *)((uintptr_t)uart + mmr_base() + mmr_off);
149
150  HW_TRACE_WRITE ();
151
152  /* XXX: All MMRs are "8bit" ... what happens to high 8bits ?  */
153  switch (mmr_off)
154    {
155    case mmr_offset(dll):
156      if (uart->lcr & DLAB)
157	uart->dll = value;
158      else
159	{
160	  uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
161
162	  if (uart->ier & ETBEI)
163	    hw_port_event (me, DV_PORT_TX, 1);
164	}
165      break;
166    case mmr_offset(dlh):
167      if (uart->lcr & DLAB)
168	uart->dlh = value;
169      else
170	{
171	  uart->ier = value;
172	  bfin_uart_reschedule (me);
173	}
174      break;
175    case mmr_offset(iir):
176    case mmr_offset(lsr):
177      /* XXX: Writes are ignored ?  */
178      break;
179    case mmr_offset(lcr):
180    case mmr_offset(mcr):
181    case mmr_offset(scr):
182    case mmr_offset(gctl):
183      *valuep = value;
184      break;
185    default:
186      dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
187      return 0;
188    }
189
190  return nr_bytes;
191}
192
193/* Switch between socket and stdin on the fly.  */
194bu16
195bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bu16 mcr, bool *fresh)
196{
197  SIM_DESC sd = hw_system (me);
198  struct bfin_uart *uart = hw_data (me);
199  int status = dv_sockser_status (sd);
200  bool _fresh;
201
202  /* NB: The "uart" here may only use interal state.  */
203
204  if (!fresh)
205    fresh = &_fresh;
206
207  *fresh = false;
208
209  if (uart->saved_count > 0)
210    {
211      *fresh = true;
212      rbr = uart->saved_byte;
213      --uart->saved_count;
214    }
215  else if (mcr & LOOP_ENA)
216    {
217      /* RX is disconnected, so only return local data.  */
218    }
219  else if (status & DV_SOCKSER_DISCONNECTED)
220    {
221      char byte;
222      int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1);
223
224      if (ret > 0)
225	{
226	  *fresh = true;
227	  rbr = byte;
228	}
229    }
230  else
231    rbr = dv_sockser_read (sd);
232
233  return rbr;
234}
235
236bu16
237bfin_uart_get_status (struct hw *me)
238{
239  SIM_DESC sd = hw_system (me);
240  struct bfin_uart *uart = hw_data (me);
241  int status = dv_sockser_status (sd);
242  bu16 lsr = 0;
243
244  if (status & DV_SOCKSER_DISCONNECTED)
245    {
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);
250    }
251  else
252    lsr |= (status & DV_SOCKSER_INPUT_EMPTY ? 0 : DR) |
253	   (status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0);
254
255  return lsr;
256}
257
258static unsigned
259bfin_uart_io_read_buffer (struct hw *me, void *dest,
260			  int space, address_word addr, unsigned nr_bytes)
261{
262  struct bfin_uart *uart = hw_data (me);
263  bu32 mmr_off;
264  bu16 *valuep;
265
266  /* Invalid access mode is higher priority than missing register.  */
267  if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
268    return 0;
269
270  mmr_off = addr - uart->base;
271  valuep = (void *)((uintptr_t)uart + mmr_base() + mmr_off);
272
273  HW_TRACE_READ ();
274
275  switch (mmr_off)
276    {
277    case mmr_offset(dll):
278      if (uart->lcr & DLAB)
279	dv_store_2 (dest, uart->dll);
280      else
281	{
282	  uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
283	  dv_store_2 (dest, uart->rbr);
284	}
285      break;
286    case mmr_offset(dlh):
287      if (uart->lcr & DLAB)
288	dv_store_2 (dest, uart->dlh);
289      else
290	dv_store_2 (dest, uart->ier);
291      break;
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);
296      uart->lsr = 0;
297      break;
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);
305      break;
306    default:
307      dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
308      return 0;
309    }
310
311  return nr_bytes;
312}
313
314unsigned
315bfin_uart_read_buffer (struct hw *me, unsigned char *buffer, unsigned nr_bytes)
316{
317  SIM_DESC sd = hw_system (me);
318  struct bfin_uart *uart = hw_data (me);
319  int status = dv_sockser_status (sd);
320  unsigned i = 0;
321
322  if (status & DV_SOCKSER_DISCONNECTED)
323    {
324      int ret;
325
326      while (uart->saved_count > 0 && i < nr_bytes)
327	{
328	  buffer[i++] = uart->saved_byte;
329	  --uart->saved_count;
330	}
331
332      ret = sim_io_poll_read (sd, 0/*STDIN*/, (char *) buffer, nr_bytes - i);
333      if (ret > 0)
334	i += ret;
335    }
336  else
337    buffer[i++] = dv_sockser_read (sd);
338
339  return i;
340}
341
342static unsigned
343bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
344			   unsigned_word addr, unsigned nr_bytes)
345{
346  HW_TRACE_DMA_READ ();
347  return bfin_uart_read_buffer (me, dest, nr_bytes);
348}
349
350unsigned
351bfin_uart_write_buffer (struct hw *me, const unsigned char *buffer,
352			unsigned nr_bytes)
353{
354  SIM_DESC sd = hw_system (me);
355  int status = dv_sockser_status (sd);
356
357  if (status & DV_SOCKSER_DISCONNECTED)
358    {
359      sim_io_write_stdout (sd, (const char *) buffer, nr_bytes);
360      sim_io_flush_stdout (sd);
361    }
362  else
363    {
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);
367    }
368
369  return nr_bytes;
370}
371
372static unsigned
373bfin_uart_dma_write_buffer (struct hw *me, const void *source,
374			    int space, unsigned_word addr,
375			    unsigned nr_bytes,
376			    int violate_read_only_section)
377{
378  struct bfin_uart *uart = hw_data (me);
379  unsigned ret;
380
381  HW_TRACE_DMA_WRITE ();
382
383  ret = bfin_uart_write_buffer (me, source, nr_bytes);
384
385  if (ret == nr_bytes && (uart->ier & ETBEI))
386    hw_port_event (me, DV_PORT_TX, 1);
387
388  return ret;
389}
390
391static const struct hw_port_descriptor bfin_uart_ports[] =
392{
393  { "tx",   DV_PORT_TX,   0, output_port, },
394  { "rx",   DV_PORT_RX,   0, output_port, },
395  { "stat", DV_PORT_STAT, 0, output_port, },
396  { NULL, 0, 0, 0, },
397};
398
399static void
400attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
401{
402  address_word attach_address;
403  int attach_space;
404  unsigned attach_size;
405  reg_property_spec reg;
406
407  if (hw_find_property (me, "reg") == NULL)
408    hw_abort (me, "Missing \"reg\" property");
409
410  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
411    hw_abort (me, "\"reg\" property must contain three addr/size entries");
412
413  hw_unit_address_to_attach_address (hw_parent (me),
414				     &reg.address,
415				     &attach_space, &attach_address, me);
416  hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
417
418  if (attach_size != BFIN_MMR_UART_SIZE)
419    hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART_SIZE);
420
421  hw_attach_address (hw_parent (me),
422		     0, attach_space, attach_address, attach_size, me);
423
424  uart->base = attach_address;
425}
426
427static void
428bfin_uart_finish (struct hw *me)
429{
430  struct bfin_uart *uart;
431
432  uart = HW_ZALLOC (me, struct bfin_uart);
433
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);
440
441  attach_bfin_uart_regs (me, uart);
442
443  /* Initialize the UART.  */
444  uart->dll = 0x0001;
445  uart->iir = 0x0001;
446  uart->lsr = 0x0060;
447}
448
449const struct hw_descriptor dv_bfin_uart_descriptor[] =
450{
451  {"bfin_uart", bfin_uart_finish,},
452  {NULL, NULL},
453};
454