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, ®)) 226283690Skib hw_abort (me, "\"reg\" property must contain three addr/size entries"); 227211860Sdavidxu 228211860Sdavidxu hw_unit_address_to_attach_address (hw_parent (me), 229211860Sdavidxu ®.address, 230283690Skib &attach_space, &attach_address, me); 231211860Sdavidxu hw_unit_size_to_attach_size (hw_parent (me), ®.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