Blame sim/bfin/dv-bfin_uart2.c

Packit Service 706eca
/* Blackfin Universal Asynchronous Receiver/Transmitter (UART) model.
Packit Service 706eca
   For "new style" UARTs on BF50x/BF54x parts.
Packit Service 706eca
Packit Service 706eca
   Copyright (C) 2010-2018 Free Software Foundation, Inc.
Packit Service 706eca
   Contributed by Analog Devices, Inc.
Packit Service 706eca
Packit Service 706eca
   This file is part of simulators.
Packit Service 706eca
Packit Service 706eca
   This program is free software; you can redistribute it and/or modify
Packit Service 706eca
   it under the terms of the GNU General Public License as published by
Packit Service 706eca
   the Free Software Foundation; either version 3 of the License, or
Packit Service 706eca
   (at your option) any later version.
Packit Service 706eca
Packit Service 706eca
   This program is distributed in the hope that it will be useful,
Packit Service 706eca
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 706eca
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 706eca
   GNU General Public License for more details.
Packit Service 706eca
Packit Service 706eca
   You should have received a copy of the GNU General Public License
Packit Service 706eca
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit Service 706eca
Packit Service 706eca
#include "config.h"
Packit Service 706eca
Packit Service 706eca
#include "sim-main.h"
Packit Service 706eca
#include "devices.h"
Packit Service 706eca
#include "dv-bfin_uart2.h"
Packit Service 706eca
Packit Service 706eca
/* XXX: Should we bother emulating the TX/RX FIFOs ?  */
Packit Service 706eca
Packit Service 706eca
/* Internal state needs to be the same as bfin_uart.  */
Packit Service 706eca
struct bfin_uart
Packit Service 706eca
{
Packit Service 706eca
  /* This top portion matches common dv_bfin struct.  */
Packit Service 706eca
  bu32 base;
Packit Service 706eca
  struct hw *dma_master;
Packit Service 706eca
  bool acked;
Packit Service 706eca
Packit Service 706eca
  struct hw_event *handler;
Packit Service 706eca
  char saved_byte;
Packit Service 706eca
  int saved_count;
Packit Service 706eca
Packit Service 706eca
  /* Accessed indirectly by ier_{set,clear}.  */
Packit Service 706eca
  bu16 ier;
Packit Service 706eca
Packit Service 706eca
  /* Order after here is important -- matches hardware MMR layout.  */
Packit Service 706eca
  bu16 BFIN_MMR_16(dll);
Packit Service 706eca
  bu16 BFIN_MMR_16(dlh);
Packit Service 706eca
  bu16 BFIN_MMR_16(gctl);
Packit Service 706eca
  bu16 BFIN_MMR_16(lcr);
Packit Service 706eca
  bu16 BFIN_MMR_16(mcr);
Packit Service 706eca
  bu16 BFIN_MMR_16(lsr);
Packit Service 706eca
  bu16 BFIN_MMR_16(msr);
Packit Service 706eca
  bu16 BFIN_MMR_16(scr);
Packit Service 706eca
  bu16 BFIN_MMR_16(ier_set);
Packit Service 706eca
  bu16 BFIN_MMR_16(ier_clear);
Packit Service 706eca
  bu16 BFIN_MMR_16(thr);
Packit Service 706eca
  bu16 BFIN_MMR_16(rbr);
Packit Service 706eca
};
Packit Service 706eca
#define mmr_base()      offsetof(struct bfin_uart, dll)
Packit Service 706eca
#define mmr_offset(mmr) (offsetof(struct bfin_uart, mmr) - mmr_base())
Packit Service 706eca
Packit Service 706eca
static const char * const mmr_names[] =
Packit Service 706eca
{
Packit Service 706eca
  "UART_DLL", "UART_DLH", "UART_GCTL", "UART_LCR", "UART_MCR", "UART_LSR",
Packit Service 706eca
  "UART_MSR", "UART_SCR", "UART_IER_SET", "UART_IER_CLEAR", "UART_THR",
Packit Service 706eca
  "UART_RBR",
Packit Service 706eca
};
Packit Service 706eca
#define mmr_name(off) mmr_names[(off) / 4]
Packit Service 706eca
Packit Service 706eca
static unsigned
Packit Service 706eca
bfin_uart_io_write_buffer (struct hw *me, const void *source,
Packit Service 706eca
			   int space, address_word addr, unsigned nr_bytes)
Packit Service 706eca
{
Packit Service 706eca
  struct bfin_uart *uart = hw_data (me);
Packit Service 706eca
  bu32 mmr_off;
Packit Service 706eca
  bu32 value;
Packit Service 706eca
  bu16 *valuep;
Packit Service 706eca
Packit Service 706eca
  /* Invalid access mode is higher priority than missing register.  */
Packit Service 706eca
  if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
Packit Service 706eca
    return 0;
Packit Service 706eca
Packit Service 706eca
  value = dv_load_2 (source);
Packit Service 706eca
  mmr_off = addr - uart->base;
Packit Service 706eca
  valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
Packit Service 706eca
Packit Service 706eca
  HW_TRACE_WRITE ();
Packit Service 706eca
Packit Service 706eca
  /* XXX: All MMRs are "8bit" ... what happens to high 8bits ?  */
Packit Service 706eca
Packit Service 706eca
  switch (mmr_off)
Packit Service 706eca
    {
Packit Service 706eca
    case mmr_offset(thr):
Packit Service 706eca
      uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
Packit Service 706eca
      if (uart->ier & ETBEI)
Packit Service 706eca
	hw_port_event (me, DV_PORT_TX, 1);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(ier_set):
Packit Service 706eca
      uart->ier |= value;
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(ier_clear):
Packit Service 706eca
      dv_w1c_2 (&uart->ier, value, -1);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(lsr):
Packit Service 706eca
      dv_w1c_2 (valuep, value, TFI | BI | FE | PE | OE);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(rbr):
Packit Service 706eca
      /* XXX: Writes are ignored ?  */
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(msr):
Packit Service 706eca
      dv_w1c_2 (valuep, value, SCTS);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(dll):
Packit Service 706eca
    case mmr_offset(dlh):
Packit Service 706eca
    case mmr_offset(gctl):
Packit Service 706eca
    case mmr_offset(lcr):
Packit Service 706eca
    case mmr_offset(mcr):
Packit Service 706eca
    case mmr_offset(scr):
Packit Service 706eca
      *valuep = value;
Packit Service 706eca
      break;
Packit Service 706eca
    default:
Packit Service 706eca
      dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
Packit Service 706eca
      return 0;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  return nr_bytes;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static unsigned
Packit Service 706eca
bfin_uart_io_read_buffer (struct hw *me, void *dest,
Packit Service 706eca
			  int space, address_word addr, unsigned nr_bytes)
Packit Service 706eca
{
Packit Service 706eca
  struct bfin_uart *uart = hw_data (me);
Packit Service 706eca
  bu32 mmr_off;
Packit Service 706eca
  bu16 *valuep;
Packit Service 706eca
Packit Service 706eca
  /* Invalid access mode is higher priority than missing register.  */
Packit Service 706eca
  if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
Packit Service 706eca
    return 0;
Packit Service 706eca
Packit Service 706eca
  mmr_off = addr - uart->base;
Packit Service 706eca
  valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);
Packit Service 706eca
Packit Service 706eca
  HW_TRACE_READ ();
Packit Service 706eca
Packit Service 706eca
  switch (mmr_off)
Packit Service 706eca
    {
Packit Service 706eca
    case mmr_offset(rbr):
Packit Service 706eca
      uart->rbr = bfin_uart_get_next_byte (me, uart->rbr, uart->mcr, NULL);
Packit Service 706eca
      dv_store_2 (dest, uart->rbr);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(ier_set):
Packit Service 706eca
    case mmr_offset(ier_clear):
Packit Service 706eca
      dv_store_2 (dest, uart->ier);
Packit Service 706eca
      bfin_uart_reschedule (me);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(lsr):
Packit Service 706eca
      uart->lsr &= ~(DR | THRE | TEMT);
Packit Service 706eca
      uart->lsr |= bfin_uart_get_status (me);
Packit Service 706eca
    case mmr_offset(thr):
Packit Service 706eca
    case mmr_offset(msr):
Packit Service 706eca
    case mmr_offset(dll):
Packit Service 706eca
    case mmr_offset(dlh):
Packit Service 706eca
    case mmr_offset(gctl):
Packit Service 706eca
    case mmr_offset(lcr):
Packit Service 706eca
    case mmr_offset(mcr):
Packit Service 706eca
    case mmr_offset(scr):
Packit Service 706eca
      dv_store_2 (dest, *valuep);
Packit Service 706eca
      break;
Packit Service 706eca
    default:
Packit Service 706eca
      dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
Packit Service 706eca
      return 0;
Packit Service 706eca
    }
Packit Service 706eca
Packit Service 706eca
  return nr_bytes;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static unsigned
Packit Service 706eca
bfin_uart_dma_read_buffer (struct hw *me, void *dest, int space,
Packit Service 706eca
			   unsigned_word addr, unsigned nr_bytes)
Packit Service 706eca
{
Packit Service 706eca
  HW_TRACE_DMA_READ ();
Packit Service 706eca
  return bfin_uart_read_buffer (me, dest, nr_bytes);
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static unsigned
Packit Service 706eca
bfin_uart_dma_write_buffer (struct hw *me, const void *source,
Packit Service 706eca
			    int space, unsigned_word addr,
Packit Service 706eca
			    unsigned nr_bytes,
Packit Service 706eca
			    int violate_read_only_section)
Packit Service 706eca
{
Packit Service 706eca
  struct bfin_uart *uart = hw_data (me);
Packit Service 706eca
  unsigned ret;
Packit Service 706eca
Packit Service 706eca
  HW_TRACE_DMA_WRITE ();
Packit Service 706eca
Packit Service 706eca
  ret = bfin_uart_write_buffer (me, source, nr_bytes);
Packit Service 706eca
Packit Service 706eca
  if (ret == nr_bytes && (uart->ier & ETBEI))
Packit Service 706eca
    hw_port_event (me, DV_PORT_TX, 1);
Packit Service 706eca
Packit Service 706eca
  return ret;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static const struct hw_port_descriptor bfin_uart_ports[] =
Packit Service 706eca
{
Packit Service 706eca
  { "tx",   DV_PORT_TX,   0, output_port, },
Packit Service 706eca
  { "rx",   DV_PORT_RX,   0, output_port, },
Packit Service 706eca
  { "stat", DV_PORT_STAT, 0, output_port, },
Packit Service 706eca
  { NULL, 0, 0, 0, },
Packit Service 706eca
};
Packit Service 706eca
Packit Service 706eca
static void
Packit Service 706eca
attach_bfin_uart_regs (struct hw *me, struct bfin_uart *uart)
Packit Service 706eca
{
Packit Service 706eca
  address_word attach_address;
Packit Service 706eca
  int attach_space;
Packit Service 706eca
  unsigned attach_size;
Packit Service 706eca
  reg_property_spec reg;
Packit Service 706eca
Packit Service 706eca
  if (hw_find_property (me, "reg") == NULL)
Packit Service 706eca
    hw_abort (me, "Missing \"reg\" property");
Packit Service 706eca
Packit Service 706eca
  if (!hw_find_reg_array_property (me, "reg", 0, &reg))
Packit Service 706eca
    hw_abort (me, "\"reg\" property must contain three addr/size entries");
Packit Service 706eca
Packit Service 706eca
  hw_unit_address_to_attach_address (hw_parent (me),
Packit Service 706eca
				     &reg.address,
Packit Service 706eca
				     &attach_space, &attach_address, me);
Packit Service 706eca
  hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
Packit Service 706eca
Packit Service 706eca
  if (attach_size != BFIN_MMR_UART2_SIZE)
Packit Service 706eca
    hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_UART2_SIZE);
Packit Service 706eca
Packit Service 706eca
  hw_attach_address (hw_parent (me),
Packit Service 706eca
		     0, attach_space, attach_address, attach_size, me);
Packit Service 706eca
Packit Service 706eca
  uart->base = attach_address;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static void
Packit Service 706eca
bfin_uart_finish (struct hw *me)
Packit Service 706eca
{
Packit Service 706eca
  struct bfin_uart *uart;
Packit Service 706eca
Packit Service 706eca
  uart = HW_ZALLOC (me, struct bfin_uart);
Packit Service 706eca
Packit Service 706eca
  set_hw_data (me, uart);
Packit Service 706eca
  set_hw_io_read_buffer (me, bfin_uart_io_read_buffer);
Packit Service 706eca
  set_hw_io_write_buffer (me, bfin_uart_io_write_buffer);
Packit Service 706eca
  set_hw_dma_read_buffer (me, bfin_uart_dma_read_buffer);
Packit Service 706eca
  set_hw_dma_write_buffer (me, bfin_uart_dma_write_buffer);
Packit Service 706eca
  set_hw_ports (me, bfin_uart_ports);
Packit Service 706eca
Packit Service 706eca
  attach_bfin_uart_regs (me, uart);
Packit Service 706eca
Packit Service 706eca
  /* Initialize the UART.  */
Packit Service 706eca
  uart->dll = 0x0001;
Packit Service 706eca
  uart->lsr = 0x0060;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
const struct hw_descriptor dv_bfin_uart2_descriptor[] =
Packit Service 706eca
{
Packit Service 706eca
  {"bfin_uart2", bfin_uart_finish,},
Packit Service 706eca
  {NULL, NULL},
Packit Service 706eca
};