Blame sim/bfin/dv-bfin_twi.c

Packit Service 706eca
/* Blackfin Two Wire Interface (TWI) model
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_twi.h"
Packit Service 706eca
Packit Service 706eca
/* XXX: This is merely a stub.  */
Packit Service 706eca
Packit Service 706eca
struct bfin_twi
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
  bu16 xmt_fifo, rcv_fifo;
Packit Service 706eca
Packit Service 706eca
  /* Order after here is important -- matches hardware MMR layout.  */
Packit Service 706eca
  bu16 BFIN_MMR_16(clkdiv);
Packit Service 706eca
  bu16 BFIN_MMR_16(control);
Packit Service 706eca
  bu16 BFIN_MMR_16(slave_ctl);
Packit Service 706eca
  bu16 BFIN_MMR_16(slave_stat);
Packit Service 706eca
  bu16 BFIN_MMR_16(slave_addr);
Packit Service 706eca
  bu16 BFIN_MMR_16(master_ctl);
Packit Service 706eca
  bu16 BFIN_MMR_16(master_stat);
Packit Service 706eca
  bu16 BFIN_MMR_16(master_addr);
Packit Service 706eca
  bu16 BFIN_MMR_16(int_stat);
Packit Service 706eca
  bu16 BFIN_MMR_16(int_mask);
Packit Service 706eca
  bu16 BFIN_MMR_16(fifo_ctl);
Packit Service 706eca
  bu16 BFIN_MMR_16(fifo_stat);
Packit Service 706eca
  bu32 _pad0[20];
Packit Service 706eca
  bu16 BFIN_MMR_16(xmt_data8);
Packit Service 706eca
  bu16 BFIN_MMR_16(xmt_data16);
Packit Service 706eca
  bu16 BFIN_MMR_16(rcv_data8);
Packit Service 706eca
  bu16 BFIN_MMR_16(rcv_data16);
Packit Service 706eca
};
Packit Service 706eca
#define mmr_base()      offsetof(struct bfin_twi, clkdiv)
Packit Service 706eca
#define mmr_offset(mmr) (offsetof(struct bfin_twi, mmr) - mmr_base())
Packit Service 706eca
#define mmr_idx(mmr)    (mmr_offset (mmr) / 4)
Packit Service 706eca
Packit Service 706eca
static const char * const mmr_names[] =
Packit Service 706eca
{
Packit Service 706eca
  "TWI_CLKDIV", "TWI_CONTROL", "TWI_SLAVE_CTL", "TWI_SLAVE_STAT",
Packit Service 706eca
  "TWI_SLAVE_ADDR", "TWI_MASTER_CTL", "TWI_MASTER_STAT", "TWI_MASTER_ADDR",
Packit Service 706eca
  "TWI_INT_STAT", "TWI_INT_MASK", "TWI_FIFO_CTL", "TWI_FIFO_STAT",
Packit Service 706eca
  [mmr_idx (xmt_data8)] = "TWI_XMT_DATA8", "TWI_XMT_DATA16", "TWI_RCV_DATA8",
Packit Service 706eca
  "TWI_RCV_DATA16",
Packit Service 706eca
};
Packit Service 706eca
#define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
Packit Service 706eca
Packit Service 706eca
static unsigned
Packit Service 706eca
bfin_twi_io_write_buffer (struct hw *me, const void *source, int space,
Packit Service 706eca
			  address_word addr, unsigned nr_bytes)
Packit Service 706eca
{
Packit Service 706eca
  struct bfin_twi *twi = 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 - twi->base;
Packit Service 706eca
  valuep = (void *)((unsigned long)twi + mmr_base() + mmr_off);
Packit Service 706eca
Packit Service 706eca
  HW_TRACE_WRITE ();
Packit Service 706eca
Packit Service 706eca
  switch (mmr_off)
Packit Service 706eca
    {
Packit Service 706eca
    case mmr_offset(clkdiv):
Packit Service 706eca
    case mmr_offset(control):
Packit Service 706eca
    case mmr_offset(slave_ctl):
Packit Service 706eca
    case mmr_offset(slave_addr):
Packit Service 706eca
    case mmr_offset(master_ctl):
Packit Service 706eca
    case mmr_offset(master_addr):
Packit Service 706eca
    case mmr_offset(int_mask):
Packit Service 706eca
    case mmr_offset(fifo_ctl):
Packit Service 706eca
      *valuep = value;
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(int_stat):
Packit Service 706eca
      dv_w1c_2 (valuep, value, -1);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(master_stat):
Packit Service 706eca
      dv_w1c_2 (valuep, value, BUFWRERR | BUFRDERR | DNAK | ANAK | LOSTARB);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(slave_stat):
Packit Service 706eca
    case mmr_offset(fifo_stat):
Packit Service 706eca
    case mmr_offset(rcv_data8):
Packit Service 706eca
    case mmr_offset(rcv_data16):
Packit Service 706eca
      /* These are all RO.  XXX: Does these throw error ?  */
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(xmt_data8):
Packit Service 706eca
      value &= 0xff;
Packit Service 706eca
    case mmr_offset(xmt_data16):
Packit Service 706eca
      twi->xmt_fifo = 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_twi_io_read_buffer (struct hw *me, void *dest, int space,
Packit Service 706eca
			 address_word addr, unsigned nr_bytes)
Packit Service 706eca
{
Packit Service 706eca
  struct bfin_twi *twi = 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 - twi->base;
Packit Service 706eca
  valuep = (void *)((unsigned long)twi + 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(clkdiv):
Packit Service 706eca
    case mmr_offset(control):
Packit Service 706eca
    case mmr_offset(slave_ctl):
Packit Service 706eca
    case mmr_offset(slave_stat):
Packit Service 706eca
    case mmr_offset(slave_addr):
Packit Service 706eca
    case mmr_offset(master_ctl):
Packit Service 706eca
    case mmr_offset(master_stat):
Packit Service 706eca
    case mmr_offset(master_addr):
Packit Service 706eca
    case mmr_offset(int_stat):
Packit Service 706eca
    case mmr_offset(int_mask):
Packit Service 706eca
    case mmr_offset(fifo_ctl):
Packit Service 706eca
    case mmr_offset(fifo_stat):
Packit Service 706eca
      dv_store_2 (dest, *valuep);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(rcv_data8):
Packit Service 706eca
    case mmr_offset(rcv_data16):
Packit Service 706eca
      dv_store_2 (dest, twi->rcv_fifo);
Packit Service 706eca
      break;
Packit Service 706eca
    case mmr_offset(xmt_data8):
Packit Service 706eca
    case mmr_offset(xmt_data16):
Packit Service 706eca
      /* These always read as 0.  */
Packit Service 706eca
      dv_store_2 (dest, 0);
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 const struct hw_port_descriptor bfin_twi_ports[] =
Packit Service 706eca
{
Packit Service 706eca
  { "stat", 0, 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_twi_regs (struct hw *me, struct bfin_twi *twi)
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_TWI_SIZE)
Packit Service 706eca
    hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_TWI_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
  twi->base = attach_address;
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
static void
Packit Service 706eca
bfin_twi_finish (struct hw *me)
Packit Service 706eca
{
Packit Service 706eca
  struct bfin_twi *twi;
Packit Service 706eca
Packit Service 706eca
  twi = HW_ZALLOC (me, struct bfin_twi);
Packit Service 706eca
Packit Service 706eca
  set_hw_data (me, twi);
Packit Service 706eca
  set_hw_io_read_buffer (me, bfin_twi_io_read_buffer);
Packit Service 706eca
  set_hw_io_write_buffer (me, bfin_twi_io_write_buffer);
Packit Service 706eca
  set_hw_ports (me, bfin_twi_ports);
Packit Service 706eca
Packit Service 706eca
  attach_bfin_twi_regs (me, twi);
Packit Service 706eca
}
Packit Service 706eca
Packit Service 706eca
const struct hw_descriptor dv_bfin_twi_descriptor[] =
Packit Service 706eca
{
Packit Service 706eca
  {"bfin_twi", bfin_twi_finish,},
Packit Service 706eca
  {NULL, NULL},
Packit Service 706eca
};