xref: /netbsd-src/external/gpl3/gdb/dist/sim/bfin/dv-bfin_uart2.c (revision 1f4e7eb9e5e045e008f1894823a8e4e6c9f46890)
1 /* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2    For "new style" UARTs on BF50x/BF54x 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 "devices.h"
27 #include "dv-bfin_uart2.h"
28 
29 /* XXX: Should we bother emulating the TX/RX FIFOs ?  */
30 
31 /* Internal state needs to be the same as bfin_uart.  */
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   /* Accessed indirectly by ier_{set,clear}.  */
44   bu16 ier;
45 
46   /* Order after here is important -- matches hardware MMR layout.  */
47   bu16 BFIN_MMR_16(dll);
48   bu16 BFIN_MMR_16(dlh);
49   bu16 BFIN_MMR_16(gctl);
50   bu16 BFIN_MMR_16(lcr);
51   bu16 BFIN_MMR_16(mcr);
52   bu16 BFIN_MMR_16(lsr);
53   bu16 BFIN_MMR_16(msr);
54   bu16 BFIN_MMR_16(scr);
55   bu16 BFIN_MMR_16(ier_set);
56   bu16 BFIN_MMR_16(ier_clear);
57   bu16 BFIN_MMR_16(thr);
58   bu16 BFIN_MMR_16(rbr);
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 {
65   "UART_DLL", "UART_DLH", "UART_GCTL", "UART_LCR", "UART_MCR", "UART_LSR",
66   "UART_MSR", "UART_SCR", "UART_IER_SET", "UART_IER_CLEAR", "UART_THR",
67   "UART_RBR",
68 };
69 #define mmr_name(off) mmr_names[(off) / 4]
70 
71 static unsigned
72 bfin_uart_io_write_buffer (struct hw *me, const void *source,
73 			   int space, address_word addr, unsigned nr_bytes)
74 {
75   struct bfin_uart *uart = hw_data (me);
76   bu32 mmr_off;
77   bu32 value;
78   bu16 *valuep;
79 
80   /* Invalid access mode is higher priority than missing register.  */
81   if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
82     return 0;
83 
84   value = dv_load_2 (source);
85   mmr_off = addr - uart->base;
86   valuep = (void *)((uintptr_t)uart + mmr_base() + mmr_off);
87 
88   HW_TRACE_WRITE ();
89 
90   /* XXX: All MMRs are "8bit" ... what happens to high 8bits ?  */
91 
92   switch (mmr_off)
93     {
94     case mmr_offset(thr):
95       uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
96       if (uart->ier & ETBEI)
97 	hw_port_event (me, DV_PORT_TX, 1);
98       break;
99     case mmr_offset(ier_set):
100       uart->ier |= value;
101       break;
102     case mmr_offset(ier_clear):
103       dv_w1c_2 (&uart->ier, value, -1);
104       break;
105     case mmr_offset(lsr):
106       dv_w1c_2 (valuep, value, TFI | BI | FE | PE | OE);
107       break;
108     case mmr_offset(rbr):
109       /* XXX: Writes are ignored ?  */
110       break;
111     case mmr_offset(msr):
112       dv_w1c_2 (valuep, value, SCTS);
113       break;
114     case mmr_offset(dll):
115     case mmr_offset(dlh):
116     case mmr_offset(gctl):
117     case mmr_offset(lcr):
118     case mmr_offset(mcr):
119     case mmr_offset(scr):
120       *valuep = value;
121       break;
122     default:
123       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
124       return 0;
125     }
126 
127   return nr_bytes;
128 }
129 
130 static unsigned
131 bfin_uart_io_read_buffer (struct hw *me, void *dest,
132 			  int space, address_word addr, unsigned nr_bytes)
133 {
134   struct bfin_uart *uart = hw_data (me);
135   bu32 mmr_off;
136   bu16 *valuep;
137 
138   /* Invalid access mode is higher priority than missing register.  */
139   if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
140     return 0;
141 
142   mmr_off = addr - uart->base;
143   valuep = (void *)((uintptr_t)uart + mmr_base() + mmr_off);
144 
145   HW_TRACE_READ ();
146 
147   switch (mmr_off)
148     {
149     case mmr_offset(rbr):
150       uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
151       dv_store_2 (dest, uart->rbr);
152       break;
153     case mmr_offset(ier_set):
154     case mmr_offset(ier_clear):
155       dv_store_2 (dest, uart->ier);
156       bfin_uart_reschedule (me);
157       break;
158     case mmr_offset(lsr):
159       uart->lsr &= ~(DR | THRE | TEMT);
160       uart->lsr |= bfin_uart_get_status (me);
161       ATTRIBUTE_FALLTHROUGH;
162     case mmr_offset(thr):
163     case mmr_offset(msr):
164     case mmr_offset(dll):
165     case mmr_offset(dlh):
166     case mmr_offset(gctl):
167     case mmr_offset(lcr):
168     case mmr_offset(mcr):
169     case mmr_offset(scr):
170       dv_store_2 (dest, *valuep);
171       break;
172     default:
173       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
174       return 0;
175     }
176 
177   return nr_bytes;
178 }
179 
180 static unsigned
181 bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
182 			   unsigned_word addr, unsigned nr_bytes)
183 {
184   HW_TRACE_DMA_READ ();
185   return bfin_uart_read_buffer (me, dest, nr_bytes);
186 }
187 
188 static unsigned
189 bfin_uart_dma_write_buffer (struct hw *me, const void *source,
190 			    int space, unsigned_word addr,
191 			    unsigned nr_bytes,
192 			    int violate_read_only_section)
193 {
194   struct bfin_uart *uart = hw_data (me);
195   unsigned ret;
196 
197   HW_TRACE_DMA_WRITE ();
198 
199   ret = bfin_uart_write_buffer (me, source, nr_bytes);
200 
201   if (ret == nr_bytes && (uart->ier & ETBEI))
202     hw_port_event (me, DV_PORT_TX, 1);
203 
204   return ret;
205 }
206 
207 static const struct hw_port_descriptor bfin_uart_ports[] =
208 {
209   { "tx",   DV_PORT_TX,   0, output_port, },
210   { "rx",   DV_PORT_RX,   0, output_port, },
211   { "stat", DV_PORT_STAT, 0, output_port, },
212   { NULL, 0, 0, 0, },
213 };
214 
215 static void
216 attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
217 {
218   address_word attach_address;
219   int attach_space;
220   unsigned attach_size;
221   reg_property_spec reg;
222 
223   if (hw_find_property (me, "reg") == NULL)
224     hw_abort (me, "Missing \"reg\" property");
225 
226   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
227     hw_abort (me, "\"reg\" property must contain three addr/size entries");
228 
229   hw_unit_address_to_attach_address (hw_parent (me),
230 				     &reg.address,
231 				     &attach_space, &attach_address, me);
232   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
233 
234   if (attach_size != BFIN_MMR_UART2_SIZE)
235     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART2_SIZE);
236 
237   hw_attach_address (hw_parent (me),
238 		     0, attach_space, attach_address, attach_size, me);
239 
240   uart->base = attach_address;
241 }
242 
243 static void
244 bfin_uart_finish (struct hw *me)
245 {
246   struct bfin_uart *uart;
247 
248   uart = HW_ZALLOC (me, struct bfin_uart);
249 
250   set_hw_data (me, uart);
251   set_hw_io_read_buffer (me, bfin_uart_io_read_buffer);
252   set_hw_io_write_buffer (me, bfin_uart_io_write_buffer);
253   set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer);
254   set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer);
255   set_hw_ports (me, bfin_uart_ports);
256 
257   attach_bfin_uart_regs (me, uart);
258 
259   /* Initialize the UART.  */
260   uart->dll = 0x0001;
261   uart->lsr = 0x0060;
262 }
263 
264 const struct hw_descriptor dv_bfin_uart2_descriptor[] =
265 {
266   {"bfin_uart2", bfin_uart_finish,},
267   {NULL, NULL},
268 };
269