1112918Sjeff/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
2112918Sjeff   For "new style" UARTs on BF50x/BF54x parts.
3112918Sjeff
4112918Sjeff   Copyright (C) 2010-2023 Free Software Foundation, Inc.
5112918Sjeff   Contributed by Analog Devices, Inc.
6112918Sjeff
7112918Sjeff   This file is part of simulators.
8112918Sjeff
9112918Sjeff   This program is free software; you can redistribute it and/or modify
10112918Sjeff   it under the terms of the GNU General Public License as published by
11112918Sjeff   the Free Software Foundation; either version 3 of the License, or
12112918Sjeff   (at your option) any later version.
13165967Simp
14112918Sjeff   This program is distributed in the hope that it will be useful,
15112918Sjeff   but WITHOUT ANY WARRANTY; without even the implied warranty of
16112918Sjeff   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17112918Sjeff   GNU General Public License for more details.
18112918Sjeff
19112918Sjeff   You should have received a copy of the GNU General Public License
20112918Sjeff   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21112918Sjeff
22112918Sjeff/* This must come before any other includes.  */
23112918Sjeff#include "defs.h"
24112918Sjeff
25112918Sjeff#include "sim-main.h"
26112918Sjeff#include "devices.h"
27112918Sjeff#include "dv-bfin_uart2.h"
28112918Sjeff
29112918Sjeff/* XXX: Should we bother emulating the TX/RX FIFOs ?  */
30112918Sjeff
31144518Sdavidxu/* Internal state needs to be the same as bfin_uart.  */
32157457Sdavidxustruct bfin_uart
33283690Skib{
34112918Sjeff  /* This top portion matches common dv_bfin struct.  */
35112918Sjeff  bu32 base;
36112918Sjeff  struct hw *dma_master;
37112918Sjeff  bool acked;
38112918Sjeff
39157457Sdavidxu  struct hw_event *handler;
40211860Sdavidxu  char saved_byte;
41144518Sdavidxu  int saved_count;
42112918Sjeff
43112918Sjeff  /* Accessed indirectly by ier_{set,clear}.  */
44144518Sdavidxu  bu16 ier;
45112918Sjeff
46112918Sjeff  /* Order after here is important -- matches hardware MMR layout.  */
47112918Sjeff  bu16 BFIN_MMR_16(dll);
48112918Sjeff  bu16 BFIN_MMR_16(dlh);
49112918Sjeff  bu16 BFIN_MMR_16(gctl);
50112918Sjeff  bu16 BFIN_MMR_16(lcr);
51112918Sjeff  bu16 BFIN_MMR_16(mcr);
52112918Sjeff  bu16 BFIN_MMR_16(lsr);
53283690Skib  bu16 BFIN_MMR_16(msr);
54112918Sjeff  bu16 BFIN_MMR_16(scr);
55173394Smarius  bu16 BFIN_MMR_16(ier_set);
56144518Sdavidxu  bu16 BFIN_MMR_16(ier_clear);
57112918Sjeff  bu16 BFIN_MMR_16(thr);
58173394Smarius  bu16 BFIN_MMR_16(rbr);
59173394Smarius};
60173394Smarius#define mmr_base()      offsetof(struct bfin_uart, dll)
61173394Smarius#define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
62144518Sdavidxu
63144518Sdavidxustatic const char * const mmr_names[] =
64112918Sjeff{
65144518Sdavidxu  "UART_DLL", "UART_DLH", "UART_GCTL", "UART_LCR", "UART_MCR", "UART_LSR",
66144518Sdavidxu  "UART_MSR", "UART_SCR", "UART_IER_SET", "UART_IER_CLEAR", "UART_THR",
67144518Sdavidxu  "UART_RBR",
68144518Sdavidxu};
69144518Sdavidxu#define mmr_name(off) mmr_names[(off) / 4]
70144518Sdavidxu
71250691Sdavidxustatic unsigned
72112918Sjeffbfin_uart_io_write_buffer (struct hw *me, const void *source,
73112918Sjeff			   int space, address_word addr, unsigned nr_bytes)
74112918Sjeff{
75112918Sjeff  struct bfin_uart *uart = hw_data (me);
76144518Sdavidxu  bu32 mmr_off;
77112918Sjeff  bu32 value;
78112918Sjeff  bu16 *valuep;
79112918Sjeff
80112918Sjeff  /* Invalid access mode is higher priority than missing register.  */
81250691Sdavidxu  if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
82112918Sjeff    return 0;
83283690Skib
84283690Skib  value = dv_load_2 (source);
85112918Sjeff  mmr_off = addr - uart->base;
86283690Skib  valuep = (void *)((uintptr_t)uart + mmr_base() + mmr_off);
87283690Skib
88283690Skib  HW_TRACE_WRITE ();
89283690Skib
90283690Skib  /* XXX: All MMRs are "8bit" ... what happens to high 8bits ?  */
91283690Skib
92283690Skib  switch (mmr_off)
93283690Skib    {
94283690Skib    case mmr_offset(thr):
95112918Sjeff      uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
96283690Skib      if (uart->ier & ETBEI)
97283690Skib	hw_port_event (me, DV_PORT_TX, 1);
98112918Sjeff      break;
99112918Sjeff    case mmr_offset(ier_set):
100112918Sjeff      uart->ier |= value;
101112918Sjeff      break;
102112918Sjeff    case mmr_offset(ier_clear):
103112918Sjeff      dv_w1c_2 (&uart->ier, value, -1);
104283690Skib      break;
105283690Skib    case mmr_offset(lsr):
106283690Skib      dv_w1c_2 (valuep, value, TFI | BI | FE | PE | OE);
107283690Skib      break;
108112918Sjeff    case mmr_offset(rbr):
109283690Skib      /* XXX: Writes are ignored ?  */
110144518Sdavidxu      break;
111144518Sdavidxu    case mmr_offset(msr):
112144518Sdavidxu      dv_w1c_2 (valuep, value, SCTS);
113283690Skib      break;
114283690Skib    case mmr_offset(dll):
115283690Skib    case mmr_offset(dlh):
116283690Skib    case mmr_offset(gctl):
117144518Sdavidxu    case mmr_offset(lcr):
118144518Sdavidxu    case mmr_offset(mcr):
119144518Sdavidxu    case mmr_offset(scr):
120144518Sdavidxu      *valuep = value;
121144518Sdavidxu      break;
122144518Sdavidxu    default:
123157457Sdavidxu      dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
124283690Skib      return 0;
125283690Skib    }
126112918Sjeff
127144518Sdavidxu  return nr_bytes;
128144518Sdavidxu}
129283690Skib
130197477Sdavidxustatic unsigned
131283690Skibbfin_uart_io_read_buffer (struct hw *me, void *dest,
132283690Skib			  int space, address_word addr, unsigned nr_bytes)
133283690Skib{
134283690Skib  struct bfin_uart *uart = hw_data (me);
135283690Skib  bu32 mmr_off;
136283690Skib  bu16 *valuep;
137197477Sdavidxu
138197477Sdavidxu  /* Invalid access mode is higher priority than missing register.  */
139197477Sdavidxu  if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
140197477Sdavidxu    return 0;
141112918Sjeff
142144518Sdavidxu  mmr_off = addr - uart->base;
143283690Skib  valuep = (void *)((uintptr_t)uart + mmr_base() + mmr_off);
144283690Skib
145144518Sdavidxu  HW_TRACE_READ ();
146144518Sdavidxu
147144518Sdavidxu  switch (mmr_off)
148157457Sdavidxu    {
149144518Sdavidxu    case mmr_offset(rbr):
150112918Sjeff      uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
151112918Sjeff      dv_store_2 (dest, uart->rbr);
152112918Sjeff      break;
153144518Sdavidxu    case mmr_offset(ier_set):
154283690Skib    case mmr_offset(ier_clear):
155283690Skib      dv_store_2 (dest, uart->ier);
156144518Sdavidxu      bfin_uart_reschedule (me);
157283690Skib      break;
158144518Sdavidxu    case mmr_offset(lsr):
159144518Sdavidxu      uart->lsr &= ~(DR | THRE | TEMT);
160144518Sdavidxu      uart->lsr |= bfin_uart_get_status (me);
161283690Skib    case mmr_offset(thr):
162112918Sjeff    case mmr_offset(msr):
163112918Sjeff    case mmr_offset(dll):
164112918Sjeff    case mmr_offset(dlh):
165250691Sdavidxu    case mmr_offset(gctl):
166112918Sjeff    case mmr_offset(lcr):
167283690Skib    case mmr_offset(mcr):
168283690Skib    case mmr_offset(scr):
169283690Skib      dv_store_2 (dest, *valuep);
170112918Sjeff      break;
171283690Skib    default:
172283690Skib      dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
173283690Skib      return 0;
174283690Skib    }
175283690Skib
176144518Sdavidxu  return nr_bytes;
177283690Skib}
178283690Skib
179283690Skibstatic unsigned
180283690Skibbfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
181283690Skib			   unsigned_word addr, unsigned nr_bytes)
182283690Skib{
183283690Skib  HW_TRACE_DMA_READ ();
184283690Skib  return bfin_uart_read_buffer (me, dest, nr_bytes);
185283690Skib}
186283690Skib
187283690Skibstatic unsigned
188283690Skibbfin_uart_dma_write_buffer (struct hw *me, const void *source,
189283690Skib			    int space, unsigned_word addr,
190283690Skib			    unsigned nr_bytes,
191283690Skib			    int violate_read_only_section)
192283690Skib{
193112918Sjeff  struct bfin_uart *uart = hw_data (me);
194112918Sjeff  unsigned ret;
195112918Sjeff
196250691Sdavidxu  HW_TRACE_DMA_WRITE ();
197112918Sjeff
198283690Skib  ret = bfin_uart_write_buffer (me, source, nr_bytes);
199283690Skib
200283690Skib  if (ret == nr_bytes && (uart->ier & ETBEI))
201112918Sjeff    hw_port_event (me, DV_PORT_TX, 1);
202283690Skib
203283690Skib  return ret;
204283690Skib}
205283690Skib
206283690Skibstatic const struct hw_port_descriptor bfin_uart_ports[] =
207144518Sdavidxu{
208283690Skib  { "tx",   DV_PORT_TX,   0, output_port, },
209283690Skib  { "rx",   DV_PORT_RX,   0, output_port, },
210283690Skib  { "stat", DV_PORT_STAT, 0, output_port, },
211283690Skib  { NULL, 0, 0, 0, },
212283690Skib};
213283690Skib
214283690Skibstatic void
215283690Skibattach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
216283690Skib{
217283690Skib  address_word attach_address;
218112918Sjeff  int attach_space;
219283690Skib  unsigned attach_size;
220157457Sdavidxu  reg_property_spec reg;
221112918Sjeff
222211860Sdavidxu  if (hw_find_property (me, "reg") == NULL)
223211860Sdavidxu    hw_abort (me, "Missing \"reg\" property");
224211860Sdavidxu
225211860Sdavidxu  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
226283690Skib    hw_abort (me, "\"reg\" property must contain three addr/size entries");
227211860Sdavidxu
228211860Sdavidxu  hw_unit_address_to_attach_address (hw_parent (me),
229211860Sdavidxu				     &reg.address,
230283690Skib				     &attach_space, &attach_address, me);
231211860Sdavidxu  hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
232211860Sdavidxu
233283690Skib  if (attach_size != BFIN_MMR_UART2_SIZE)
234283690Skib    hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART2_SIZE);
235283690Skib
236283690Skib  hw_attach_address (hw_parent (me),
237283690Skib		     0, attach_space, attach_address, attach_size, me);
238283690Skib
239283690Skib  uart->base = attach_address;
240211860Sdavidxu}
241211860Sdavidxu
242211860Sdavidxustatic 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