Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_wdog.c revision 1.1.1.1
      1 /* Blackfin Watchdog (WDOG) model.
      2 
      3    Copyright (C) 2010-2014 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   if (nr_bytes == 4)
     65     value = dv_load_4 (source);
     66   else
     67     value = dv_load_2 (source);
     68 
     69   mmr_off = addr - wdog->base;
     70   valuep = (void *)((unsigned long)wdog + mmr_base() + mmr_off);
     71   value16p = valuep;
     72   value32p = valuep;
     73 
     74   HW_TRACE_WRITE ();
     75 
     76   switch (mmr_off)
     77     {
     78     case mmr_offset(ctl):
     79       dv_w1c_2_partial (value16p, value, WDRO);
     80       /* XXX: Should enable an event here to handle timeouts.  */
     81       break;
     82 
     83     case mmr_offset(cnt):
     84       /* Writes are discarded when enabeld.  */
     85       if (!bfin_wdog_enabled (wdog))
     86 	{
     87 	  *value32p = value;
     88 	  /* Writes to CNT preloads the STAT.  */
     89 	  wdog->stat = wdog->cnt;
     90 	}
     91       break;
     92 
     93     case mmr_offset(stat):
     94       /* When enabled, writes to STAT reload the counter.  */
     95       if (bfin_wdog_enabled (wdog))
     96 	wdog->stat = wdog->cnt;
     97       /* XXX: When disabled, are writes just ignored ?  */
     98       break;
     99     }
    100 
    101   return nr_bytes;
    102 }
    103 
    104 static unsigned
    105 bfin_wdog_io_read_buffer (struct hw *me, void *dest,
    106 			  int space, address_word addr, unsigned nr_bytes)
    107 {
    108   struct bfin_wdog *wdog = hw_data (me);
    109   bu32 mmr_off;
    110   bu16 *value16p;
    111   bu32 *value32p;
    112   void *valuep;
    113 
    114   mmr_off = addr - wdog->base;
    115   valuep = (void *)((unsigned long)wdog + mmr_base() + mmr_off);
    116   value16p = valuep;
    117   value32p = valuep;
    118 
    119   HW_TRACE_READ ();
    120 
    121   switch (mmr_off)
    122     {
    123     case mmr_offset(ctl):
    124       dv_bfin_mmr_require_16 (me, addr, nr_bytes, false);
    125       dv_store_2 (dest, *value16p);
    126       break;
    127 
    128     case mmr_offset(cnt):
    129     case mmr_offset(stat):
    130       dv_store_4 (dest, *value32p);
    131       break;
    132     }
    133 
    134   return nr_bytes;
    135 }
    136 
    137 static const struct hw_port_descriptor bfin_wdog_ports[] =
    138 {
    139   { "reset", WDEV_RESET, 0, output_port, },
    140   { "nmi",   WDEV_NMI,   0, output_port, },
    141   { "gpi",   WDEV_GPI,   0, output_port, },
    142   { NULL, 0, 0, 0, },
    143 };
    144 
    145 static void
    146 bfin_wdog_port_event (struct hw *me, int my_port, struct hw *source,
    147 		      int source_port, int level)
    148 {
    149   struct bfin_wdog *wdog = hw_data (me);
    150   bu16 wdev;
    151 
    152   wdog->ctl |= WDRO;
    153   wdev = (wdog->ctl & WDEV);
    154   if (wdev != WDEV_NONE)
    155     hw_port_event (me, wdev, 1);
    156 }
    157 
    158 static void
    159 attach_bfin_wdog_regs (struct hw *me, struct bfin_wdog *wdog)
    160 {
    161   address_word attach_address;
    162   int attach_space;
    163   unsigned attach_size;
    164   reg_property_spec reg;
    165 
    166   if (hw_find_property (me, "reg") == NULL)
    167     hw_abort (me, "Missing \"reg\" property");
    168 
    169   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    170     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    171 
    172   hw_unit_address_to_attach_address (hw_parent (me),
    173 				     &reg.address,
    174 				     &attach_space, &attach_address, me);
    175   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    176 
    177   if (attach_size != BFIN_MMR_WDOG_SIZE)
    178     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_WDOG_SIZE);
    179 
    180   hw_attach_address (hw_parent (me),
    181 		     0, attach_space, attach_address, attach_size, me);
    182 
    183   wdog->base = attach_address;
    184 }
    185 
    186 static void
    187 bfin_wdog_finish (struct hw *me)
    188 {
    189   struct bfin_wdog *wdog;
    190 
    191   wdog = HW_ZALLOC (me, struct bfin_wdog);
    192 
    193   set_hw_data (me, wdog);
    194   set_hw_io_read_buffer (me, bfin_wdog_io_read_buffer);
    195   set_hw_io_write_buffer (me, bfin_wdog_io_write_buffer);
    196   set_hw_ports (me, bfin_wdog_ports);
    197   set_hw_port_event (me, bfin_wdog_port_event);
    198 
    199   attach_bfin_wdog_regs (me, wdog);
    200 
    201   /* Initialize the Watchdog.  */
    202   wdog->ctl = WDDIS;
    203 }
    204 
    205 const struct hw_descriptor dv_bfin_wdog_descriptor[] =
    206 {
    207   {"bfin_wdog", bfin_wdog_finish,},
    208   {NULL, NULL},
    209 };
    210