Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_pint.c revision 1.6.4.1
      1 /* Blackfin Pin Interrupt (PINT) model
      2 
      3    Copyright (C) 2010-2017 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   /* Invalid access mode is higher priority than missing register.  */
     67   /* XXX: The hardware allows 16 or 32 bit accesses ...  */
     68   if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, true))
     69     return 0;
     70 
     71   if (nr_bytes == 4)
     72     value = dv_load_4 (source);
     73   else
     74     value = dv_load_2 (source);
     75   mmr_off = addr - pint->base;
     76   valuep = (void *)((unsigned long)pint + mmr_base() + mmr_off);
     77 
     78   HW_TRACE_WRITE ();
     79 
     80   switch (mmr_off)
     81     {
     82     case mmr_offset(request):
     83     case mmr_offset(assign):
     84     case mmr_offset(pinstate):
     85     case mmr_offset(latch):
     86       *valuep = value;
     87       break;
     88     case mmr_offset(mask_set):
     89       dv_w1c_4 (&pint->mask, value, -1);
     90       break;
     91     case mmr_offset(mask_clear):
     92       pint->mask |= value;
     93       break;
     94     case mmr_offset(edge_set):
     95       dv_w1c_4 (&pint->edge, value, -1);
     96       break;
     97     case mmr_offset(edge_clear):
     98       pint->edge |= value;
     99       break;
    100     case mmr_offset(invert_set):
    101       dv_w1c_4 (&pint->invert, value, -1);
    102       break;
    103     case mmr_offset(invert_clear):
    104       pint->invert |= value;
    105       break;
    106     default:
    107       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    108       return 0;
    109     }
    110 
    111 #if 0
    112   /* If updating masks, make sure we send updated port info.  */
    113   switch (mmr_off)
    114     {
    115     case mmr_offset(dir):
    116     case mmr_offset(data) ... mmr_offset(toggle):
    117       bfin_pint_forward_ouput (me, pint, data);
    118       break;
    119     case mmr_offset(maska) ... mmr_offset(maska_toggle):
    120       bfin_pint_forward_int (me, pint, pint->maska, 0);
    121       break;
    122     case mmr_offset(maskb) ... mmr_offset(maskb_toggle):
    123       bfin_pint_forward_int (me, pint, pint->maskb, 1);
    124       break;
    125     }
    126 #endif
    127 
    128   return nr_bytes;
    129 }
    130 
    131 static unsigned
    132 bfin_pint_io_read_buffer (struct hw *me, void *dest, int space,
    133 			  address_word addr, unsigned nr_bytes)
    134 {
    135   struct bfin_pint *pint = hw_data (me);
    136   bu32 mmr_off;
    137   bu32 *valuep;
    138 
    139   /* Invalid access mode is higher priority than missing register.  */
    140   /* XXX: The hardware allows 16 or 32 bit accesses ...  */
    141   if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, false))
    142     return 0;
    143 
    144   mmr_off = addr - pint->base;
    145   valuep = (void *)((unsigned long)pint + mmr_base() + mmr_off);
    146 
    147   HW_TRACE_READ ();
    148 
    149   switch (mmr_off)
    150     {
    151     case mmr_offset(request):
    152     case mmr_offset(assign):
    153     case mmr_offset(pinstate):
    154     case mmr_offset(latch):
    155       dv_store_4 (dest, *valuep);
    156       break;
    157     case mmr_offset(mask_set):
    158     case mmr_offset(mask_clear):
    159       dv_store_4 (dest, pint->mask);
    160       break;
    161     case mmr_offset(edge_set):
    162     case mmr_offset(edge_clear):
    163       dv_store_4 (dest, pint->edge);
    164       break;
    165     case mmr_offset(invert_set):
    166     case mmr_offset(invert_clear):
    167       dv_store_4 (dest, pint->invert);
    168       break;
    169     default:
    170       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    171       return 0;
    172     }
    173 
    174   return nr_bytes;
    175 }
    176 
    177 #define ENC(bmap, piq) (((bmap) << 8) + (piq))
    178 
    179 #define PIQ_PORTS(n) \
    180   { "piq0@"#n,   ENC(n,  0), 0, input_port, }, \
    181   { "piq1@"#n,   ENC(n,  1), 0, input_port, }, \
    182   { "piq2@"#n,   ENC(n,  2), 0, input_port, }, \
    183   { "piq3@"#n,   ENC(n,  3), 0, input_port, }, \
    184   { "piq4@"#n,   ENC(n,  4), 0, input_port, }, \
    185   { "piq5@"#n,   ENC(n,  5), 0, input_port, }, \
    186   { "piq6@"#n,   ENC(n,  6), 0, input_port, }, \
    187   { "piq7@"#n,   ENC(n,  7), 0, input_port, }, \
    188   { "piq8@"#n,   ENC(n,  8), 0, input_port, }, \
    189   { "piq9@"#n,   ENC(n,  9), 0, input_port, }, \
    190   { "piq10@"#n,  ENC(n, 10), 0, input_port, }, \
    191   { "piq11@"#n,  ENC(n, 11), 0, input_port, }, \
    192   { "piq12@"#n,  ENC(n, 12), 0, input_port, }, \
    193   { "piq13@"#n,  ENC(n, 13), 0, input_port, }, \
    194   { "piq14@"#n,  ENC(n, 14), 0, input_port, }, \
    195   { "piq15@"#n,  ENC(n, 15), 0, input_port, }, \
    196   { "piq16@"#n,  ENC(n, 16), 0, input_port, }, \
    197   { "piq17@"#n,  ENC(n, 17), 0, input_port, }, \
    198   { "piq18@"#n,  ENC(n, 18), 0, input_port, }, \
    199   { "piq19@"#n,  ENC(n, 19), 0, input_port, }, \
    200   { "piq20@"#n,  ENC(n, 20), 0, input_port, }, \
    201   { "piq21@"#n,  ENC(n, 21), 0, input_port, }, \
    202   { "piq22@"#n,  ENC(n, 22), 0, input_port, }, \
    203   { "piq23@"#n,  ENC(n, 23), 0, input_port, }, \
    204   { "piq24@"#n,  ENC(n, 24), 0, input_port, }, \
    205   { "piq25@"#n,  ENC(n, 25), 0, input_port, }, \
    206   { "piq26@"#n,  ENC(n, 26), 0, input_port, }, \
    207   { "piq27@"#n,  ENC(n, 27), 0, input_port, }, \
    208   { "piq28@"#n,  ENC(n, 28), 0, input_port, }, \
    209   { "piq29@"#n,  ENC(n, 29), 0, input_port, }, \
    210   { "piq30@"#n,  ENC(n, 30), 0, input_port, }, \
    211   { "piq31@"#n,  ENC(n, 31), 0, input_port, },
    212 
    213 static const struct hw_port_descriptor bfin_pint_ports[] =
    214 {
    215   { "stat", 0, 0, output_port, },
    216   PIQ_PORTS(0)
    217   PIQ_PORTS(1)
    218   PIQ_PORTS(2)
    219   PIQ_PORTS(3)
    220   PIQ_PORTS(4)
    221   PIQ_PORTS(5)
    222   PIQ_PORTS(6)
    223   PIQ_PORTS(7)
    224   { NULL, 0, 0, 0, },
    225 };
    226 
    227 static void
    228 bfin_pint_port_event (struct hw *me, int my_port, struct hw *source,
    229 		      int source_port, int level)
    230 {
    231   /* XXX: TODO.  */
    232 }
    233 
    234 static void
    235 attach_bfin_pint_regs (struct hw *me, struct bfin_pint *pint)
    236 {
    237   address_word attach_address;
    238   int attach_space;
    239   unsigned attach_size;
    240   reg_property_spec reg;
    241 
    242   if (hw_find_property (me, "reg") == NULL)
    243     hw_abort (me, "Missing \"reg\" property");
    244 
    245   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    246     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    247 
    248   hw_unit_address_to_attach_address (hw_parent (me),
    249 				     &reg.address,
    250 				     &attach_space, &attach_address, me);
    251   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    252 
    253   if (attach_size != BFIN_MMR_PINT_SIZE)
    254     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_PINT_SIZE);
    255 
    256   hw_attach_address (hw_parent (me),
    257 		     0, attach_space, attach_address, attach_size, me);
    258 
    259   pint->base = attach_address;
    260 }
    261 
    262 static void
    263 bfin_pint_finish (struct hw *me)
    264 {
    265   struct bfin_pint *pint;
    266 
    267   pint = HW_ZALLOC (me, struct bfin_pint);
    268 
    269   set_hw_data (me, pint);
    270   set_hw_io_read_buffer (me, bfin_pint_io_read_buffer);
    271   set_hw_io_write_buffer (me, bfin_pint_io_write_buffer);
    272   set_hw_ports (me, bfin_pint_ports);
    273   set_hw_port_event (me, bfin_pint_port_event);
    274 
    275   /* Initialize the PINT.  */
    276   switch (dv_get_bus_num (me))
    277     {
    278     case 0:
    279       pint->assign = 0x00000101;
    280       break;
    281     case 1:
    282       pint->assign = 0x01010000;
    283       break;
    284     case 2:
    285       pint->assign = 0x00000101;
    286       break;
    287     case 3:
    288       pint->assign = 0x02020303;
    289       break;
    290     default:
    291       /* XXX: Should move this default into device tree.  */
    292       hw_abort (me, "no support for PINT at this address yet");
    293     }
    294 
    295   attach_bfin_pint_regs (me, pint);
    296 }
    297 
    298 const struct hw_descriptor dv_bfin_pint_descriptor[] =
    299 {
    300   {"bfin_pint", bfin_pint_finish,},
    301   {NULL, NULL},
    302 };
    303