xref: /netbsd-src/external/gpl3/gdb/dist/sim/bfin/dv-bfin_uart.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
1 /* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2    For "old style" UARTs on BF53x/etc... parts.
3 
4    Copyright (C) 2010-2024 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.  */
33 struct 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 
64 static 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 };
69 static 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 
78 static void
79 bfin_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 
93 void
94 bfin_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 
114 bu16
115 bfin_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 
133 static unsigned
134 bfin_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.  */
194 bu16
195 bfin_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 
236 bu16
237 bfin_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 
258 static unsigned
259 bfin_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 
314 unsigned
315 bfin_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 
342 static unsigned
343 bfin_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 
350 unsigned
351 bfin_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 
372 static unsigned
373 bfin_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 
391 static 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 
399 static void
400 attach_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 
427 static void
428 bfin_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 
449 const struct hw_descriptor dv_bfin_uart_descriptor[] =
450 {
451   {"bfin_uart", bfin_uart_finish,},
452   {NULL, NULL},
453 };
454