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.  */
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
63static 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};
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
120bfin_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
127static unsigned
128bfin_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.  */
186bu16
187bfin_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
225bu16
226bfin_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
247static unsigned
248bfin_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
301unsigned
302bfin_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
329static unsigned
330bfin_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
337unsigned
338bfin_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
359static unsigned
360bfin_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
378static 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
386static void
387attach_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
414static void
415bfin_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
436const struct hw_descriptor dv_bfin_uart_descriptor[] =
437{
438  {"bfin_uart", bfin_uart_finish,},
439  {NULL, NULL},
440};
441