a7985889f87d6097a928b16d2e47cfe5a05c63f2
[deliverable/binutils-gdb.git] / sim / bfin / dv-bfin_uart2.c
1 /* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2 For "new style" UARTs on BF50x/BF54x parts.
3
4 Copyright (C) 2010-2021 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 *)((unsigned long)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 *)((unsigned long)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 case mmr_offset(thr):
162 case mmr_offset(msr):
163 case mmr_offset(dll):
164 case mmr_offset(dlh):
165 case mmr_offset(gctl):
166 case mmr_offset(lcr):
167 case mmr_offset(mcr):
168 case mmr_offset(scr):
169 dv_store_2 (dest, *valuep);
170 break;
171 default:
172 dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
173 return 0;
174 }
175
176 return nr_bytes;
177 }
178
179 static unsigned
180 bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
181 unsigned_word addr, unsigned nr_bytes)
182 {
183 HW_TRACE_DMA_READ ();
184 return bfin_uart_read_buffer (me, dest, nr_bytes);
185 }
186
187 static unsigned
188 bfin_uart_dma_write_buffer (struct hw *me, const void *source,
189 int space, unsigned_word addr,
190 unsigned nr_bytes,
191 int violate_read_only_section)
192 {
193 struct bfin_uart *uart = hw_data (me);
194 unsigned ret;
195
196 HW_TRACE_DMA_WRITE ();
197
198 ret = bfin_uart_write_buffer (me, source, nr_bytes);
199
200 if (ret == nr_bytes && (uart->ier & ETBEI))
201 hw_port_event (me, DV_PORT_TX, 1);
202
203 return ret;
204 }
205
206 static const struct hw_port_descriptor bfin_uart_ports[] =
207 {
208 { "tx", DV_PORT_TX, 0, output_port, },
209 { "rx", DV_PORT_RX, 0, output_port, },
210 { "stat", DV_PORT_STAT, 0, output_port, },
211 { NULL, 0, 0, 0, },
212 };
213
214 static void
215 attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
216 {
217 address_word attach_address;
218 int attach_space;
219 unsigned attach_size;
220 reg_property_spec reg;
221
222 if (hw_find_property (me, "reg") == NULL)
223 hw_abort (me, "Missing \"reg\" property");
224
225 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
226 hw_abort (me, "\"reg\" property must contain three addr/size entries");
227
228 hw_unit_address_to_attach_address (hw_parent (me),
229 &reg.address,
230 &attach_space, &attach_address, me);
231 hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
232
233 if (attach_size != BFIN_MMR_UART2_SIZE)
234 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART2_SIZE);
235
236 hw_attach_address (hw_parent (me),
237 0, attach_space, attach_address, attach_size, me);
238
239 uart->base = attach_address;
240 }
241
242 static void
243 bfin_uart_finish (struct hw *me)
244 {
245 struct bfin_uart *uart;
246
247 uart = HW_ZALLOC (me, struct bfin_uart);
248
249 set_hw_data (me, uart);
250 set_hw_io_read_buffer (me, bfin_uart_io_read_buffer);
251 set_hw_io_write_buffer (me, bfin_uart_io_write_buffer);
252 set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer);
253 set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer);
254 set_hw_ports (me, bfin_uart_ports);
255
256 attach_bfin_uart_regs (me, uart);
257
258 /* Initialize the UART. */
259 uart->dll = 0x0001;
260 uart->lsr = 0x0060;
261 }
262
263 const struct hw_descriptor dv_bfin_uart2_descriptor[] =
264 {
265 {"bfin_uart2", bfin_uart_finish,},
266 {NULL, NULL},
267 };
This page took 0.044265 seconds and 3 git commands to generate.