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