Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_wdog.c revision 1.1.1.6.4.1
      1 /* Blackfin Watchdog (WDOG) model.
      2 
      3    Copyright (C) 2010-2019 Free Software Foundation, Inc.
      4    Contributed by Analog Devices, Inc.
      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 "dv-sockser.h"
     25 #include "devices.h"
     26 #include "dv-bfin_wdog.h"
     27 
     28 /* XXX: Should we bother emulating the TX/RX FIFOs ?  */
     29 
     30 struct bfin_wdog
     31 {
     32   bu32 base;
     33 
     34   /* Order after here is important -- matches hardware MMR layout.  */
     35   bu16 BFIN_MMR_16(ctl);
     36   bu32 cnt, stat;
     37 };
     38 #define mmr_base()      offsetof(struct bfin_wdog, ctl)
     39 #define mmr_offset(mmr) (offsetof(struct bfin_wdog, mmr) - mmr_base())
     40 
     41 static const char * const mmr_names[] =
     42 {
     43   "WDOG_CTL", "WDOG_CNT", "WDOG_STAT",
     44 };
     45 #define mmr_name(off) mmr_names[(off) / 4]
     46 
     47 static bool
     48 bfin_wdog_enabled (struct bfin_wdog *wdog)
     49 {
     50   return ((wdog->ctl & WDEN) != WDDIS);
     51 }
     52 
     53 static unsigned
     54 bfin_wdog_io_write_buffer (struct hw *me, const void *source,
     55 			   int space, address_word addr, unsigned nr_bytes)
     56 {
     57   struct bfin_wdog *wdog = hw_data (me);
     58   bu32 mmr_off;
     59   bu32 value;
     60   bu16 *value16p;
     61   bu32 *value32p;
     62   void *valuep;
     63 
     64   /* Invalid access mode is higher priority than missing register.  */
     65   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, true))
     66     return 0;
     67 
     68   if (nr_bytes == 4)
     69     value = dv_load_4 (source);
     70   else
     71     value = dv_load_2 (source);
     72 
     73   mmr_off = addr - wdog->base;
     74   valuep = (void *)((unsigned long)wdog + mmr_base() + mmr_off);
     75   value16p = valuep;
     76   value32p = valuep;
     77 
     78   HW_TRACE_WRITE ();
     79 
     80   switch (mmr_off)
     81     {
     82     case mmr_offset(ctl):
     83       dv_w1c_2_partial (value16p, value, WDRO);
     84       /* XXX: Should enable an event here to handle timeouts.  */
     85       break;
     86 
     87     case mmr_offset(cnt):
     88       /* Writes are discarded when enabeld.  */
     89       if (!bfin_wdog_enabled (wdog))
     90 	{
     91 	  *value32p = value;
     92 	  /* Writes to CNT preloads the STAT.  */
     93 	  wdog->stat = wdog->cnt;
     94 	}
     95       break;
     96 
     97     case mmr_offset(stat):
     98       /* When enabled, writes to STAT reload the counter.  */
     99       if (bfin_wdog_enabled (wdog))
    100 	wdog->stat = wdog->cnt;
    101       /* XXX: When disabled, are writes just ignored ?  */
    102       break;
    103     }
    104 
    105   return nr_bytes;
    106 }
    107 
    108 static unsigned
    109 bfin_wdog_io_read_buffer (struct hw *me, void *dest,
    110 			  int space, address_word addr, unsigned nr_bytes)
    111 {
    112   struct bfin_wdog *wdog = hw_data (me);
    113   bu32 mmr_off;
    114   bu16 *value16p;
    115   bu32 *value32p;
    116   void *valuep;
    117 
    118   /* Invalid access mode is higher priority than missing register.  */
    119   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, false))
    120     return 0;
    121 
    122   mmr_off = addr - wdog->base;
    123   valuep = (void *)((unsigned long)wdog + mmr_base() + mmr_off);
    124   value16p = valuep;
    125   value32p = valuep;
    126 
    127   HW_TRACE_READ ();
    128 
    129   switch (mmr_off)
    130     {
    131     case mmr_offset(ctl):
    132       if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, false))
    133 	return 0;
    134       dv_store_2 (dest, *value16p);
    135       break;
    136 
    137     case mmr_offset(cnt):
    138     case mmr_offset(stat):
    139       dv_store_4 (dest, *value32p);
    140       break;
    141     }
    142 
    143   return nr_bytes;
    144 }
    145 
    146 static const struct hw_port_descriptor bfin_wdog_ports[] =
    147 {
    148   { "reset", WDEV_RESET, 0, output_port, },
    149   { "nmi",   WDEV_NMI,   0, output_port, },
    150   { "gpi",   WDEV_GPI,   0, output_port, },
    151   { NULL, 0, 0, 0, },
    152 };
    153 
    154 static void
    155 bfin_wdog_port_event (struct hw *me, int my_port, struct hw *source,
    156 		      int source_port, int level)
    157 {
    158   struct bfin_wdog *wdog = hw_data (me);
    159   bu16 wdev;
    160 
    161   wdog->ctl |= WDRO;
    162   wdev = (wdog->ctl & WDEV);
    163   if (wdev != WDEV_NONE)
    164     hw_port_event (me, wdev, 1);
    165 }
    166 
    167 static void
    168 attach_bfin_wdog_regs (struct hw *me, struct bfin_wdog *wdog)
    169 {
    170   address_word attach_address;
    171   int attach_space;
    172   unsigned attach_size;
    173   reg_property_spec reg;
    174 
    175   if (hw_find_property (me, "reg") == NULL)
    176     hw_abort (me, "Missing \"reg\" property");
    177 
    178   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    179     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    180 
    181   hw_unit_address_to_attach_address (hw_parent (me),
    182 				     &reg.address,
    183 				     &attach_space, &attach_address, me);
    184   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    185 
    186   if (attach_size != BFIN_MMR_WDOG_SIZE)
    187     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_WDOG_SIZE);
    188 
    189   hw_attach_address (hw_parent (me),
    190 		     0, attach_space, attach_address, attach_size, me);
    191 
    192   wdog->base = attach_address;
    193 }
    194 
    195 static void
    196 bfin_wdog_finish (struct hw *me)
    197 {
    198   struct bfin_wdog *wdog;
    199 
    200   wdog = HW_ZALLOC (me, struct bfin_wdog);
    201 
    202   set_hw_data (me, wdog);
    203   set_hw_io_read_buffer (me, bfin_wdog_io_read_buffer);
    204   set_hw_io_write_buffer (me, bfin_wdog_io_write_buffer);
    205   set_hw_ports (me, bfin_wdog_ports);
    206   set_hw_port_event (me, bfin_wdog_port_event);
    207 
    208   attach_bfin_wdog_regs (me, wdog);
    209 
    210   /* Initialize the Watchdog.  */
    211   wdog->ctl = WDDIS;
    212 }
    213 
    214 const struct hw_descriptor dv_bfin_wdog_descriptor[] =
    215 {
    216   {"bfin_wdog", bfin_wdog_finish,},
    217   {NULL, NULL},
    218 };
    219