Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_ppi.c revision 1.11
      1 /* Blackfin Parallel Port Interface (PPI) model
      2    For "old style" PPIs on BF53x/etc... 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_ppi.h"
     28 #include "gui.h"
     29 
     30 /* XXX: TX is merely a stub.  */
     31 
     32 struct bfin_ppi
     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   /* GUI state.  */
     44   void *gui_state;
     45   int color;
     46 
     47   /* Order after here is important -- matches hardware MMR layout.  */
     48   bu16 BFIN_MMR_16(control);
     49   bu16 BFIN_MMR_16(status);
     50   bu16 BFIN_MMR_16(count);
     51   bu16 BFIN_MMR_16(delay);
     52   bu16 BFIN_MMR_16(frame);
     53 };
     54 #define mmr_base()      offsetof(struct bfin_ppi, control)
     55 #define mmr_offset(mmr) (offsetof(struct bfin_ppi, mmr) - mmr_base())
     56 
     57 static const char * const mmr_names[] =
     58 {
     59   "PPI_CONTROL", "PPI_STATUS", "PPI_COUNT", "PPI_DELAY", "PPI_FRAME",
     60 };
     61 #define mmr_name(off) mmr_names[(off) / 4]
     62 
     63 static void
     64 bfin_ppi_gui_setup (struct bfin_ppi *ppi)
     65 {
     66   int bpp;
     67 
     68   /* If we are in RX mode, nothing to do.  */
     69   if (!(ppi->control & PORT_DIR))
     70     return;
     71 
     72   bpp = bfin_gui_color_depth (ppi->color);
     73   ppi->gui_state = bfin_gui_setup (ppi->gui_state,
     74 				   ppi->control & PORT_EN,
     75 				   (ppi->count + 1) / (bpp / 8),
     76 				   ppi->frame,
     77 				   ppi->color);
     78 }
     79 
     80 static unsigned
     81 bfin_ppi_io_write_buffer (struct hw *me, const void *source, int space,
     82 			  address_word addr, unsigned nr_bytes)
     83 {
     84   struct bfin_ppi *ppi = hw_data (me);
     85   bu32 mmr_off;
     86   bu32 value;
     87   bu16 *valuep;
     88 
     89   /* Invalid access mode is higher priority than missing register.  */
     90   if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
     91     return 0;
     92 
     93   value = dv_load_2 (source);
     94   mmr_off = addr - ppi->base;
     95   valuep = (void *)((uintptr_t)ppi + mmr_base() + mmr_off);
     96 
     97   HW_TRACE_WRITE ();
     98 
     99   switch (mmr_off)
    100     {
    101     case mmr_offset(control):
    102       *valuep = value;
    103       bfin_ppi_gui_setup (ppi);
    104       break;
    105     case mmr_offset(count):
    106     case mmr_offset(delay):
    107     case mmr_offset(frame):
    108       *valuep = value;
    109       break;
    110     case mmr_offset(status):
    111       dv_w1c_2 (valuep, value, ~(1 << 10));
    112       break;
    113     default:
    114       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    115       return 0;
    116     }
    117 
    118   return nr_bytes;
    119 }
    120 
    121 static unsigned
    122 bfin_ppi_io_read_buffer (struct hw *me, void *dest, int space,
    123 			 address_word addr, unsigned nr_bytes)
    124 {
    125   struct bfin_ppi *ppi = hw_data (me);
    126   bu32 mmr_off;
    127   bu16 *valuep;
    128 
    129   /* Invalid access mode is higher priority than missing register.  */
    130   if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
    131     return 0;
    132 
    133   mmr_off = addr - ppi->base;
    134   valuep = (void *)((uintptr_t)ppi + mmr_base() + mmr_off);
    135 
    136   HW_TRACE_READ ();
    137 
    138   switch (mmr_off)
    139     {
    140     case mmr_offset(control):
    141     case mmr_offset(count):
    142     case mmr_offset(delay):
    143     case mmr_offset(frame):
    144     case mmr_offset(status):
    145       dv_store_2 (dest, *valuep);
    146       break;
    147     default:
    148       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    149       return 0;
    150     }
    151 
    152   return nr_bytes;
    153 }
    154 
    155 static unsigned
    156 bfin_ppi_dma_read_buffer (struct hw *me, void *dest, int space,
    157 			  unsigned_word addr, unsigned nr_bytes)
    158 {
    159   HW_TRACE_DMA_READ ();
    160   return 0;
    161 }
    162 
    163 static unsigned
    164 bfin_ppi_dma_write_buffer (struct hw *me, const void *source,
    165 			   int space, unsigned_word addr,
    166 			   unsigned nr_bytes,
    167 			   int violate_read_only_section)
    168 {
    169   struct bfin_ppi *ppi = hw_data (me);
    170 
    171   HW_TRACE_DMA_WRITE ();
    172 
    173   return bfin_gui_update (ppi->gui_state, source, nr_bytes);
    174 }
    175 
    176 static const struct hw_port_descriptor bfin_ppi_ports[] =
    177 {
    178   { "stat", 0, 0, output_port, },
    179   { NULL, 0, 0, 0, },
    180 };
    181 
    182 static void
    183 attach_bfin_ppi_regs (struct hw *me, struct bfin_ppi *ppi)
    184 {
    185   address_word attach_address;
    186   int attach_space;
    187   unsigned attach_size;
    188   reg_property_spec reg;
    189 
    190   if (hw_find_property (me, "reg") == NULL)
    191     hw_abort (me, "Missing \"reg\" property");
    192 
    193   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    194     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    195 
    196   hw_unit_address_to_attach_address (hw_parent (me),
    197 				     &reg.address,
    198 				     &attach_space, &attach_address, me);
    199   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    200 
    201   if (attach_size != BFIN_MMR_PPI_SIZE)
    202     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PPI_SIZE);
    203 
    204   hw_attach_address (hw_parent (me),
    205 		     0, attach_space, attach_address, attach_size, me);
    206 
    207   ppi->base = attach_address;
    208 }
    209 
    210 static void
    211 bfin_ppi_finish (struct hw *me)
    212 {
    213   struct bfin_ppi *ppi;
    214   const char *color;
    215 
    216   ppi = HW_ZALLOC (me, struct bfin_ppi);
    217 
    218   set_hw_data (me, ppi);
    219   set_hw_io_read_buffer (me, bfin_ppi_io_read_buffer);
    220   set_hw_io_write_buffer (me, bfin_ppi_io_write_buffer);
    221   set_hw_dma_read_buffer (me, bfin_ppi_dma_read_buffer);
    222   set_hw_dma_write_buffer (me, bfin_ppi_dma_write_buffer);
    223   set_hw_ports (me, bfin_ppi_ports);
    224 
    225   attach_bfin_ppi_regs (me, ppi);
    226 
    227   /* Initialize the PPI.  */
    228   if (hw_find_property (me, "color"))
    229     color = hw_find_string_property (me, "color");
    230   else
    231     color = NULL;
    232   ppi->color = bfin_gui_color (color);
    233 }
    234 
    235 const struct hw_descriptor dv_bfin_ppi_descriptor[] =
    236 {
    237   {"bfin_ppi", bfin_ppi_finish,},
    238   {NULL, NULL},
    239 };
    240