1/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model. 2 For "old style" UARTs on BF53x/etc... parts. 3 4 Copyright (C) 2010-2020 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 "dv-sockser.h" 26#include "devices.h" 27#include "dv-bfin_uart.h" 28 29/* XXX: Should we bother emulating the TX/RX FIFOs ? */ 30 31/* Internal state needs to be the same as bfin_uart2. */ 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 /* This is aliased to DLH. */ 44 bu16 ier; 45 /* These are aliased to DLL. */ 46 bu16 thr, rbr; 47 48 /* Order after here is important -- matches hardware MMR layout. */ 49 bu16 BFIN_MMR_16(dll); 50 bu16 BFIN_MMR_16(dlh); 51 bu16 BFIN_MMR_16(iir); 52 bu16 BFIN_MMR_16(lcr); 53 bu16 BFIN_MMR_16(mcr); 54 bu16 BFIN_MMR_16(lsr); 55 bu16 BFIN_MMR_16(msr); 56 bu16 BFIN_MMR_16(scr); 57 bu16 _pad0[2]; 58 bu16 BFIN_MMR_16(gctl); 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_RBR/UART_THR", "UART_IER", "UART_IIR", "UART_LCR", "UART_MCR", 66 "UART_LSR", "UART_MSR", "UART_SCR", "<INV>", "UART_GCTL", 67}; 68static const char *mmr_name (struct bfin_uart *uart, bu32 idx) 69{ 70 if (uart->lcr & DLAB) 71 if (idx < 2) 72 return idx == 0 ? "UART_DLL" : "UART_DLH"; 73 return mmr_names[idx]; 74} 75#define mmr_name(off) mmr_name (uart, (off) / 4) 76 77static void 78bfin_uart_poll (struct hw *me, void *data) 79{ 80 struct bfin_uart *uart = data; 81 bu16 lsr; 82 83 uart->handler = NULL; 84 85 lsr = bfin_uart_get_status (me); 86 if (lsr & DR) 87 hw_port_event (me, DV_PORT_RX, 1); 88 89 bfin_uart_reschedule (me); 90} 91 92void 93bfin_uart_reschedule (struct hw *me) 94{ 95 struct bfin_uart *uart = hw_data (me); 96 97 if (uart->ier & ERBFI) 98 { 99 if (!uart->handler) 100 uart->handler = hw_event_queue_schedule (me, 10000, 101 bfin_uart_poll, uart); 102 } 103 else 104 { 105 if (uart->handler) 106 { 107 hw_event_queue_deschedule (me, uart->handler); 108 uart->handler = NULL; 109 } 110 } 111} 112 113bu16 114bfin_uart_write_byte (struct hw *me, bu16 thr, bu16 mcr) 115{ 116 struct bfin_uart *uart = hw_data (me); 117 unsigned char ch = thr; 118 119 if (mcr & LOOP_ENA) 120 { 121 /* XXX: This probably doesn't work exactly right with 122 external FIFOs ... */ 123 uart->saved_byte = thr; 124 uart->saved_count = 1; 125 } 126 127 bfin_uart_write_buffer (me, &ch, 1); 128 129 return thr; 130} 131 132static unsigned 133bfin_uart_io_write_buffer (struct hw *me, const void *source, 134 int space, address_word addr, unsigned nr_bytes) 135{ 136 struct bfin_uart *uart = hw_data (me); 137 bu32 mmr_off; 138 bu32 value; 139 bu16 *valuep; 140 141 /* Invalid access mode is higher priority than missing register. */ 142 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true)) 143 return 0; 144 145 value = dv_load_2 (source); 146 mmr_off = addr - uart->base; 147 valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off); 148 149 HW_TRACE_WRITE (); 150 151 /* XXX: All MMRs are "8bit" ... what happens to high 8bits ? */ 152 switch (mmr_off) 153 { 154 case mmr_offset(dll): 155 if (uart->lcr & DLAB) 156 uart->dll = value; 157 else 158 { 159 uart->thr = bfin_uart_write_byte (me, value, uart->mcr); 160 161 if (uart->ier & ETBEI) 162 hw_port_event (me, DV_PORT_TX, 1); 163 } 164 break; 165 case mmr_offset(dlh): 166 if (uart->lcr & DLAB) 167 uart->dlh = value; 168 else 169 { 170 uart->ier = value; 171 bfin_uart_reschedule (me); 172 } 173 break; 174 case mmr_offset(iir): 175 case mmr_offset(lsr): 176 /* XXX: Writes are ignored ? */ 177 break; 178 case mmr_offset(lcr): 179 case mmr_offset(mcr): 180 case mmr_offset(scr): 181 case mmr_offset(gctl): 182 *valuep = value; 183 break; 184 default: 185 dv_bfin_mmr_invalid (me, addr, nr_bytes, true); 186 return 0; 187 } 188 189 return nr_bytes; 190} 191 192/* Switch between socket and stdin on the fly. */ 193bu16 194bfin_uart_get_next_byte (struct hw *me, bu16 rbr, bu16 mcr, bool *fresh) 195{ 196 SIM_DESC sd = hw_system (me); 197 struct bfin_uart *uart = hw_data (me); 198 int status = dv_sockser_status (sd); 199 bool _fresh; 200 201 /* NB: The "uart" here may only use interal state. */ 202 203 if (!fresh) 204 fresh = &_fresh; 205 206 *fresh = false; 207 208 if (uart->saved_count > 0) 209 { 210 *fresh = true; 211 rbr = uart->saved_byte; 212 --uart->saved_count; 213 } 214 else if (mcr & LOOP_ENA) 215 { 216 /* RX is disconnected, so only return local data. */ 217 } 218 else if (status & DV_SOCKSER_DISCONNECTED) 219 { 220 char byte; 221 int ret = sim_io_poll_read (sd, 0/*STDIN*/, &byte, 1); 222 223 if (ret > 0) 224 { 225 *fresh = true; 226 rbr = byte; 227 } 228 } 229 else 230 rbr = dv_sockser_read (sd); 231 232 return rbr; 233} 234 235bu16 236bfin_uart_get_status (struct hw *me) 237{ 238 SIM_DESC sd = hw_system (me); 239 struct bfin_uart *uart = hw_data (me); 240 int status = dv_sockser_status (sd); 241 bu16 lsr = 0; 242 243 if (status & DV_SOCKSER_DISCONNECTED) 244 { 245 if (uart->saved_count <= 0) 246 uart->saved_count = sim_io_poll_read (sd, 0/*STDIN*/, 247 &uart->saved_byte, 1); 248 lsr |= TEMT | THRE | (uart->saved_count > 0 ? DR : 0); 249 } 250 else 251 lsr |= (status & DV_SOCKSER_INPUT_EMPTY ? 0 : DR) | 252 (status & DV_SOCKSER_OUTPUT_EMPTY ? TEMT | THRE : 0); 253 254 return lsr; 255} 256 257static unsigned 258bfin_uart_io_read_buffer (struct hw *me, void *dest, 259 int space, address_word addr, unsigned nr_bytes) 260{ 261 struct bfin_uart *uart = hw_data (me); 262 bu32 mmr_off; 263 bu16 *valuep; 264 265 /* Invalid access mode is higher priority than missing register. */ 266 if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false)) 267 return 0; 268 269 mmr_off = addr - uart->base; 270 valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off); 271 272 HW_TRACE_READ (); 273 274 switch (mmr_off) 275 { 276 case mmr_offset(dll): 277 if (uart->lcr & DLAB) 278 dv_store_2 (dest, uart->dll); 279 else 280 { 281 uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL); 282 dv_store_2 (dest, uart->rbr); 283 } 284 break; 285 case mmr_offset(dlh): 286 if (uart->lcr & DLAB) 287 dv_store_2 (dest, uart->dlh); 288 else 289 dv_store_2 (dest, uart->ier); 290 break; 291 case mmr_offset(lsr): 292 /* XXX: Reads are destructive on most parts, but not all ... */ 293 uart->lsr |= bfin_uart_get_status (me); 294 dv_store_2 (dest, *valuep); 295 uart->lsr = 0; 296 break; 297 case mmr_offset(iir): 298 /* XXX: Reads are destructive ... */ 299 case mmr_offset(lcr): 300 case mmr_offset(mcr): 301 case mmr_offset(scr): 302 case mmr_offset(gctl): 303 dv_store_2 (dest, *valuep); 304 break; 305 default: 306 dv_bfin_mmr_invalid (me, addr, nr_bytes, false); 307 return 0; 308 } 309 310 return nr_bytes; 311} 312 313unsigned 314bfin_uart_read_buffer (struct hw *me, unsigned char *buffer, unsigned nr_bytes) 315{ 316 SIM_DESC sd = hw_system (me); 317 struct bfin_uart *uart = hw_data (me); 318 int status = dv_sockser_status (sd); 319 unsigned i = 0; 320 321 if (status & DV_SOCKSER_DISCONNECTED) 322 { 323 int ret; 324 325 while (uart->saved_count > 0 && i < nr_bytes) 326 { 327 buffer[i++] = uart->saved_byte; 328 --uart->saved_count; 329 } 330 331 ret = sim_io_poll_read (sd, 0/*STDIN*/, (char *) buffer, nr_bytes - i); 332 if (ret > 0) 333 i += ret; 334 } 335 else 336 buffer[i++] = dv_sockser_read (sd); 337 338 return i; 339} 340 341static unsigned 342bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space, 343 unsigned_word addr, unsigned nr_bytes) 344{ 345 HW_TRACE_DMA_READ (); 346 return bfin_uart_read_buffer (me, dest, nr_bytes); 347} 348 349unsigned 350bfin_uart_write_buffer (struct hw *me, const unsigned char *buffer, 351 unsigned nr_bytes) 352{ 353 SIM_DESC sd = hw_system (me); 354 int status = dv_sockser_status (sd); 355 356 if (status & DV_SOCKSER_DISCONNECTED) 357 { 358 sim_io_write_stdout (sd, (const char *) buffer, nr_bytes); 359 sim_io_flush_stdout (sd); 360 } 361 else 362 { 363 /* Normalize errors to a value of 0. */ 364 int ret = dv_sockser_write_buffer (sd, buffer, nr_bytes); 365 nr_bytes = CLAMP (ret, 0, nr_bytes); 366 } 367 368 return nr_bytes; 369} 370 371static unsigned 372bfin_uart_dma_write_buffer (struct hw *me, const void *source, 373 int space, unsigned_word addr, 374 unsigned nr_bytes, 375 int violate_read_only_section) 376{ 377 struct bfin_uart *uart = hw_data (me); 378 unsigned ret; 379 380 HW_TRACE_DMA_WRITE (); 381 382 ret = bfin_uart_write_buffer (me, source, nr_bytes); 383 384 if (ret == nr_bytes && (uart->ier & ETBEI)) 385 hw_port_event (me, DV_PORT_TX, 1); 386 387 return ret; 388} 389 390static const struct hw_port_descriptor bfin_uart_ports[] = 391{ 392 { "tx", DV_PORT_TX, 0, output_port, }, 393 { "rx", DV_PORT_RX, 0, output_port, }, 394 { "stat", DV_PORT_STAT, 0, output_port, }, 395 { NULL, 0, 0, 0, }, 396}; 397 398static void 399attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart) 400{ 401 address_word attach_address; 402 int attach_space; 403 unsigned attach_size; 404 reg_property_spec reg; 405 406 if (hw_find_property (me, "reg") == NULL) 407 hw_abort (me, "Missing \"reg\" property"); 408 409 if (!hw_find_reg_array_property (me, "reg", 0, ®)) 410 hw_abort (me, "\"reg\" property must contain three addr/size entries"); 411 412 hw_unit_address_to_attach_address (hw_parent (me), 413 ®.address, 414 &attach_space, &attach_address, me); 415 hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me); 416 417 if (attach_size != BFIN_MMR_UART_SIZE) 418 hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART_SIZE); 419 420 hw_attach_address (hw_parent (me), 421 0, attach_space, attach_address, attach_size, me); 422 423 uart->base = attach_address; 424} 425 426static void 427bfin_uart_finish (struct hw *me) 428{ 429 struct bfin_uart *uart; 430 431 uart = HW_ZALLOC (me, struct bfin_uart); 432 433 set_hw_data (me, uart); 434 set_hw_io_read_buffer (me, bfin_uart_io_read_buffer); 435 set_hw_io_write_buffer (me, bfin_uart_io_write_buffer); 436 set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer); 437 set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer); 438 set_hw_ports (me, bfin_uart_ports); 439 440 attach_bfin_uart_regs (me, uart); 441 442 /* Initialize the UART. */ 443 uart->dll = 0x0001; 444 uart->iir = 0x0001; 445 uart->lsr = 0x0060; 446} 447 448const struct hw_descriptor dv_bfin_uart_descriptor[] = 449{ 450 {"bfin_uart", bfin_uart_finish,}, 451 {NULL, NULL}, 452}; 453