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