1/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2   For "new style" UARTs on BF50x/BF54x 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 "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.  */
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  /* 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
63static 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
71static unsigned
72bfin_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
130static unsigned
131bfin_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    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
179static unsigned
180bfin_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
187static unsigned
188bfin_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
206static 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
214static void
215attach_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
242static void
243bfin_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
263const struct hw_descriptor dv_bfin_uart2_descriptor[] =
264{
265  {"bfin_uart2", bfin_uart_finish,},
266  {NULL, NULL},
267};
268