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