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