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