Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_ppi.c revision 1.1
      1 /* Blackfin Parallel Port Interface (PPI) model
      2    For "old style" PPIs on BF53x/etc... parts.
      3 
      4    Copyright (C) 2010-2014 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   value = dv_load_2 (source);
     89   mmr_off = addr - ppi->base;
     90   valuep = (void *)((unsigned long)ppi + mmr_base() + mmr_off);
     91 
     92   HW_TRACE_WRITE ();
     93 
     94   dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);
     95 
     96   switch (mmr_off)
     97     {
     98     case mmr_offset(control):
     99       *valuep = value;
    100       bfin_ppi_gui_setup (ppi);
    101       break;
    102     case mmr_offset(count):
    103     case mmr_offset(delay):
    104     case mmr_offset(frame):
    105       *valuep = value;
    106       break;
    107     case mmr_offset(status):
    108       dv_w1c_2 (valuep, value, ~(1 << 10));
    109       break;
    110     default:
    111       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    112       break;
    113     }
    114 
    115   return nr_bytes;
    116 }
    117 
    118 static unsigned
    119 bfin_ppi_io_read_buffer (struct hw *me, void *dest, int space,
    120 			 address_word addr, unsigned nr_bytes)
    121 {
    122   struct bfin_ppi *ppi = hw_data (me);
    123   bu32 mmr_off;
    124   bu16 *valuep;
    125 
    126   mmr_off = addr - ppi->base;
    127   valuep = (void *)((unsigned long)ppi + mmr_base() + mmr_off);
    128 
    129   HW_TRACE_READ ();
    130 
    131   dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
    132 
    133   switch (mmr_off)
    134     {
    135     case mmr_offset(control):
    136     case mmr_offset(count):
    137     case mmr_offset(delay):
    138     case mmr_offset(frame):
    139     case mmr_offset(status):
    140       dv_store_2 (dest, *valuep);
    141       break;
    142     default:
    143       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    144       break;
    145     }
    146 
    147   return nr_bytes;
    148 }
    149 
    150 static unsigned
    151 bfin_ppi_dma_read_buffer (struct hw *me, void *dest, int space,
    152 			  unsigned_word addr, unsigned nr_bytes)
    153 {
    154   HW_TRACE_DMA_READ ();
    155   return 0;
    156 }
    157 
    158 static unsigned
    159 bfin_ppi_dma_write_buffer (struct hw *me, const void *source,
    160 			   int space, unsigned_word addr,
    161 			   unsigned nr_bytes,
    162 			   int violate_read_only_section)
    163 {
    164   struct bfin_ppi *ppi = hw_data (me);
    165 
    166   HW_TRACE_DMA_WRITE ();
    167 
    168   return bfin_gui_update (ppi->gui_state, source, nr_bytes);
    169 }
    170 
    171 static const struct hw_port_descriptor bfin_ppi_ports[] =
    172 {
    173   { "stat", 0, 0, output_port, },
    174   { NULL, 0, 0, 0, },
    175 };
    176 
    177 static void
    178 attach_bfin_ppi_regs (struct hw *me, struct bfin_ppi *ppi)
    179 {
    180   address_word attach_address;
    181   int attach_space;
    182   unsigned attach_size;
    183   reg_property_spec reg;
    184 
    185   if (hw_find_property (me, "reg") == NULL)
    186     hw_abort (me, "Missing \"reg\" property");
    187 
    188   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    189     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    190 
    191   hw_unit_address_to_attach_address (hw_parent (me),
    192 				     &reg.address,
    193 				     &attach_space, &attach_address, me);
    194   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    195 
    196   if (attach_size != BFIN_MMR_PPI_SIZE)
    197     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PPI_SIZE);
    198 
    199   hw_attach_address (hw_parent (me),
    200 		     0, attach_space, attach_address, attach_size, me);
    201 
    202   ppi->base = attach_address;
    203 }
    204 
    205 static void
    206 bfin_ppi_finish (struct hw *me)
    207 {
    208   struct bfin_ppi *ppi;
    209   const char *color;
    210 
    211   ppi = HW_ZALLOC (me, struct bfin_ppi);
    212 
    213   set_hw_data (me, ppi);
    214   set_hw_io_read_buffer (me, bfin_ppi_io_read_buffer);
    215   set_hw_io_write_buffer (me, bfin_ppi_io_write_buffer);
    216   set_hw_dma_read_buffer (me, bfin_ppi_dma_read_buffer);
    217   set_hw_dma_write_buffer (me, bfin_ppi_dma_write_buffer);
    218   set_hw_ports (me, bfin_ppi_ports);
    219 
    220   attach_bfin_ppi_regs (me, ppi);
    221 
    222   /* Initialize the PPI.  */
    223   if (hw_find_property (me, "color"))
    224     color = hw_find_string_property (me, "color");
    225   else
    226     color = NULL;
    227   ppi->color = bfin_gui_color (color);
    228 }
    229 
    230 const struct hw_descriptor dv_bfin_ppi_descriptor[] =
    231 {
    232   {"bfin_ppi", bfin_ppi_finish,},
    233   {NULL, NULL},
    234 };
    235