Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_pint.c revision 1.1.1.2
      1 /* Blackfin Pin Interrupt (PINT) model
      2 
      3    Copyright (C) 2010-2015 Free Software Foundation, Inc.
      4    Contributed by Analog Devices, Inc. and Mike Frysinger.
      5 
      6    This file is part of simulators.
      7 
      8    This program is free software; you can redistribute it and/or modify
      9    it under the terms of the GNU General Public License as published by
     10    the Free Software Foundation; either version 3 of the License, or
     11    (at your option) any later version.
     12 
     13    This program is distributed in the hope that it will be useful,
     14    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16    GNU General Public License for more details.
     17 
     18    You should have received a copy of the GNU General Public License
     19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     20 
     21 #include "config.h"
     22 
     23 #include "sim-main.h"
     24 #include "devices.h"
     25 #include "dv-bfin_pint.h"
     26 
     27 struct bfin_pint
     28 {
     29   bu32 base;
     30 
     31   /* Only accessed indirectly via the associated set/clear MMRs.  */
     32   bu32 mask, edge, invert;
     33 
     34   /* Order after here is important -- matches hardware MMR layout.  */
     35   bu32 mask_set;
     36   bu32 mask_clear;
     37   bu32 request;
     38   bu32 assign;
     39   bu32 edge_set;
     40   bu32 edge_clear;
     41   bu32 invert_set;
     42   bu32 invert_clear;
     43   bu32 pinstate;
     44   bu32 latch;
     45 };
     46 #define mmr_base()      offsetof(struct bfin_pint, mask_set)
     47 #define mmr_offset(mmr) (offsetof(struct bfin_pint, mmr) - mmr_base())
     48 
     49 static const char * const mmr_names[] =
     50 {
     51   "PINT_MASK_SET", "PINT_MASK_CLEAR", "PINT_REQUEST", "PINT_ASSIGN",
     52   "PINT_EDGE_SET", "PINT_EDGE_CLEAR", "PINT_INVERT_SET",
     53   "PINT_INVERT_CLEAR", "PINT_PINSTATE", "PINT_LATCH",
     54 };
     55 #define mmr_name(off) mmr_names[(off) / 4]
     56 
     57 static unsigned
     58 bfin_pint_io_write_buffer (struct hw *me, const void *source, int space,
     59 			   address_word addr, unsigned nr_bytes)
     60 {
     61   struct bfin_pint *pint = hw_data (me);
     62   bu32 mmr_off;
     63   bu32 value;
     64   bu32 *valuep;
     65 
     66   if (nr_bytes == 4)
     67     value = dv_load_4 (source);
     68   else
     69     value = dv_load_2 (source);
     70   mmr_off = addr - pint->base;
     71   valuep = (void *)((unsigned long)pint + mmr_base() + mmr_off);
     72 
     73   HW_TRACE_WRITE ();
     74 
     75   /* XXX: The hardware allows 16 or 32 bit accesses ...  */
     76   dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
     77 
     78   switch (mmr_off)
     79     {
     80     case mmr_offset(request):
     81     case mmr_offset(assign):
     82     case mmr_offset(pinstate):
     83     case mmr_offset(latch):
     84       *valuep = value;
     85       break;
     86     case mmr_offset(mask_set):
     87       dv_w1c_4 (&pint->mask, value, -1);
     88       break;
     89     case mmr_offset(mask_clear):
     90       pint->mask |= value;
     91       break;
     92     case mmr_offset(edge_set):
     93       dv_w1c_4 (&pint->edge, value, -1);
     94       break;
     95     case mmr_offset(edge_clear):
     96       pint->edge |= value;
     97       break;
     98     case mmr_offset(invert_set):
     99       dv_w1c_4 (&pint->invert, value, -1);
    100       break;
    101     case mmr_offset(invert_clear):
    102       pint->invert |= value;
    103       break;
    104     default:
    105       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    106       break;
    107     }
    108 
    109 #if 0
    110   /* If updating masks, make sure we send updated port info.  */
    111   switch (mmr_off)
    112     {
    113     case mmr_offset(dir):
    114     case mmr_offset(data) ... mmr_offset(toggle):
    115       bfin_pint_forward_ouput (me, pint, data);
    116       break;
    117     case mmr_offset(maska) ... mmr_offset(maska_toggle):
    118       bfin_pint_forward_int (me, pint, pint->maska, 0);
    119       break;
    120     case mmr_offset(maskb) ... mmr_offset(maskb_toggle):
    121       bfin_pint_forward_int (me, pint, pint->maskb, 1);
    122       break;
    123     }
    124 #endif
    125 
    126   return nr_bytes;
    127 }
    128 
    129 static unsigned
    130 bfin_pint_io_read_buffer (struct hw *me, void *dest, int space,
    131 			  address_word addr, unsigned nr_bytes)
    132 {
    133   struct bfin_pint *pint = hw_data (me);
    134   bu32 mmr_off;
    135   bu32 *valuep;
    136 
    137   mmr_off = addr - pint->base;
    138   valuep = (void *)((unsigned long)pint + mmr_base() + mmr_off);
    139 
    140   HW_TRACE_READ ();
    141 
    142   /* XXX: The hardware allows 16 or 32 bit accesses ...  */
    143   dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
    144 
    145   switch (mmr_off)
    146     {
    147     case mmr_offset(request):
    148     case mmr_offset(assign):
    149     case mmr_offset(pinstate):
    150     case mmr_offset(latch):
    151       dv_store_4 (dest, *valuep);
    152       break;
    153     case mmr_offset(mask_set):
    154     case mmr_offset(mask_clear):
    155       dv_store_4 (dest, pint->mask);
    156       break;
    157     case mmr_offset(edge_set):
    158     case mmr_offset(edge_clear):
    159       dv_store_4 (dest, pint->edge);
    160       break;
    161     case mmr_offset(invert_set):
    162     case mmr_offset(invert_clear):
    163       dv_store_4 (dest, pint->invert);
    164       break;
    165     default:
    166       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    167       break;
    168     }
    169 
    170   return nr_bytes;
    171 }
    172 
    173 #define ENC(bmap, piq) (((bmap) << 8) + (piq))
    174 
    175 #define PIQ_PORTS(n) \
    176   { "piq0@"#n,   ENC(n,  0), 0, input_port, }, \
    177   { "piq1@"#n,   ENC(n,  1), 0, input_port, }, \
    178   { "piq2@"#n,   ENC(n,  2), 0, input_port, }, \
    179   { "piq3@"#n,   ENC(n,  3), 0, input_port, }, \
    180   { "piq4@"#n,   ENC(n,  4), 0, input_port, }, \
    181   { "piq5@"#n,   ENC(n,  5), 0, input_port, }, \
    182   { "piq6@"#n,   ENC(n,  6), 0, input_port, }, \
    183   { "piq7@"#n,   ENC(n,  7), 0, input_port, }, \
    184   { "piq8@"#n,   ENC(n,  8), 0, input_port, }, \
    185   { "piq9@"#n,   ENC(n,  9), 0, input_port, }, \
    186   { "piq10@"#n,  ENC(n, 10), 0, input_port, }, \
    187   { "piq11@"#n,  ENC(n, 11), 0, input_port, }, \
    188   { "piq12@"#n,  ENC(n, 12), 0, input_port, }, \
    189   { "piq13@"#n,  ENC(n, 13), 0, input_port, }, \
    190   { "piq14@"#n,  ENC(n, 14), 0, input_port, }, \
    191   { "piq15@"#n,  ENC(n, 15), 0, input_port, }, \
    192   { "piq16@"#n,  ENC(n, 16), 0, input_port, }, \
    193   { "piq17@"#n,  ENC(n, 17), 0, input_port, }, \
    194   { "piq18@"#n,  ENC(n, 18), 0, input_port, }, \
    195   { "piq19@"#n,  ENC(n, 19), 0, input_port, }, \
    196   { "piq20@"#n,  ENC(n, 20), 0, input_port, }, \
    197   { "piq21@"#n,  ENC(n, 21), 0, input_port, }, \
    198   { "piq22@"#n,  ENC(n, 22), 0, input_port, }, \
    199   { "piq23@"#n,  ENC(n, 23), 0, input_port, }, \
    200   { "piq24@"#n,  ENC(n, 24), 0, input_port, }, \
    201   { "piq25@"#n,  ENC(n, 25), 0, input_port, }, \
    202   { "piq26@"#n,  ENC(n, 26), 0, input_port, }, \
    203   { "piq27@"#n,  ENC(n, 27), 0, input_port, }, \
    204   { "piq28@"#n,  ENC(n, 28), 0, input_port, }, \
    205   { "piq29@"#n,  ENC(n, 29), 0, input_port, }, \
    206   { "piq30@"#n,  ENC(n, 30), 0, input_port, }, \
    207   { "piq31@"#n,  ENC(n, 31), 0, input_port, },
    208 
    209 static const struct hw_port_descriptor bfin_pint_ports[] =
    210 {
    211   { "stat", 0, 0, output_port, },
    212   PIQ_PORTS(0)
    213   PIQ_PORTS(1)
    214   PIQ_PORTS(2)
    215   PIQ_PORTS(3)
    216   PIQ_PORTS(4)
    217   PIQ_PORTS(5)
    218   PIQ_PORTS(6)
    219   PIQ_PORTS(7)
    220   { NULL, 0, 0, 0, },
    221 };
    222 
    223 static void
    224 bfin_pint_port_event (struct hw *me, int my_port, struct hw *source,
    225 		      int source_port, int level)
    226 {
    227   /* XXX: TODO.  */
    228 }
    229 
    230 static void
    231 attach_bfin_pint_regs (struct hw *me, struct bfin_pint *pint)
    232 {
    233   address_word attach_address;
    234   int attach_space;
    235   unsigned attach_size;
    236   reg_property_spec reg;
    237 
    238   if (hw_find_property (me, "reg") == NULL)
    239     hw_abort (me, "Missing \"reg\" property");
    240 
    241   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    242     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    243 
    244   hw_unit_address_to_attach_address (hw_parent (me),
    245 				     &reg.address,
    246 				     &attach_space, &attach_address, me);
    247   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    248 
    249   if (attach_size != BFIN_MMR_PINT_SIZE)
    250     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PINT_SIZE);
    251 
    252   hw_attach_address (hw_parent (me),
    253 		     0, attach_space, attach_address, attach_size, me);
    254 
    255   pint->base = attach_address;
    256 }
    257 
    258 static void
    259 bfin_pint_finish (struct hw *me)
    260 {
    261   struct bfin_pint *pint;
    262 
    263   pint = HW_ZALLOC (me, struct bfin_pint);
    264 
    265   set_hw_data (me, pint);
    266   set_hw_io_read_buffer (me, bfin_pint_io_read_buffer);
    267   set_hw_io_write_buffer (me, bfin_pint_io_write_buffer);
    268   set_hw_ports (me, bfin_pint_ports);
    269   set_hw_port_event (me, bfin_pint_port_event);
    270 
    271   /* Initialize the PINT.  */
    272   switch (dv_get_bus_num (me))
    273     {
    274     case 0:
    275       pint->assign = 0x00000101;
    276       break;
    277     case 1:
    278       pint->assign = 0x01010000;
    279       break;
    280     case 2:
    281       pint->assign = 0x00000101;
    282       break;
    283     case 3:
    284       pint->assign = 0x02020303;
    285       break;
    286     default:
    287       /* XXX: Should move this default into device tree.  */
    288       hw_abort (me, "no support for PINT at this address yet");
    289     }
    290 
    291   attach_bfin_pint_regs (me, pint);
    292 }
    293 
    294 const struct hw_descriptor dv_bfin_pint_descriptor[] =
    295 {
    296   {"bfin_pint", bfin_pint_finish,},
    297   {NULL, NULL},
    298 };
    299