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