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