Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_rtc.c revision 1.8
      1  1.1  christos /* Blackfin Real Time Clock (RTC) model.
      2  1.1  christos 
      3  1.8  christos    Copyright (C) 2010-2019 Free Software Foundation, Inc.
      4  1.1  christos    Contributed by Analog Devices, Inc.
      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.1  christos #include "config.h"
     22  1.1  christos 
     23  1.1  christos #include <time.h>
     24  1.1  christos #include "sim-main.h"
     25  1.1  christos #include "dv-sockser.h"
     26  1.1  christos #include "devices.h"
     27  1.1  christos #include "dv-bfin_rtc.h"
     28  1.1  christos 
     29  1.1  christos /* XXX: This read-only stub setup is based on host system clock.  */
     30  1.1  christos 
     31  1.1  christos struct bfin_rtc
     32  1.1  christos {
     33  1.1  christos   bu32 base;
     34  1.1  christos   bu32 stat_shadow;
     35  1.1  christos 
     36  1.1  christos   /* Order after here is important -- matches hardware MMR layout.  */
     37  1.1  christos   bu32 stat;
     38  1.1  christos   bu16 BFIN_MMR_16(ictl);
     39  1.1  christos   bu16 BFIN_MMR_16(istat);
     40  1.1  christos   bu16 BFIN_MMR_16(swcnt);
     41  1.1  christos   bu32 alarm;
     42  1.1  christos   bu16 BFIN_MMR_16(pren);
     43  1.1  christos };
     44  1.1  christos #define mmr_base()      offsetof(struct bfin_rtc, stat)
     45  1.1  christos #define mmr_offset(mmr) (offsetof(struct bfin_rtc, mmr) - mmr_base())
     46  1.1  christos 
     47  1.1  christos static const char * const mmr_names[] =
     48  1.1  christos {
     49  1.1  christos   "RTC_STAT", "RTC_ICTL", "RTC_ISTAT", "RTC_SWCNT", "RTC_ALARM", "RTC_PREN",
     50  1.1  christos };
     51  1.1  christos #define mmr_name(off) mmr_names[(off) / 4]
     52  1.1  christos 
     53  1.1  christos static unsigned
     54  1.1  christos bfin_rtc_io_write_buffer (struct hw *me, const void *source,
     55  1.1  christos 			  int space, address_word addr, unsigned nr_bytes)
     56  1.1  christos {
     57  1.1  christos   struct bfin_rtc *rtc = hw_data (me);
     58  1.1  christos   bu32 mmr_off;
     59  1.1  christos   bu32 value;
     60  1.1  christos   bu16 *value16p;
     61  1.1  christos   bu32 *value32p;
     62  1.1  christos   void *valuep;
     63  1.1  christos 
     64  1.6  christos   /* Invalid access mode is higher priority than missing register.  */
     65  1.6  christos   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, true))
     66  1.6  christos     return 0;
     67  1.6  christos 
     68  1.1  christos   if (nr_bytes == 4)
     69  1.1  christos     value = dv_load_4 (source);
     70  1.1  christos   else
     71  1.1  christos     value = dv_load_2 (source);
     72  1.1  christos 
     73  1.1  christos   mmr_off = addr - rtc->base;
     74  1.1  christos   valuep = (void *)((unsigned long)rtc + mmr_base() + mmr_off);
     75  1.1  christos   value16p = valuep;
     76  1.1  christos   value32p = valuep;
     77  1.1  christos 
     78  1.1  christos   HW_TRACE_WRITE ();
     79  1.1  christos 
     80  1.1  christos   /* XXX: These probably need more work.  */
     81  1.1  christos   switch (mmr_off)
     82  1.1  christos     {
     83  1.1  christos     case mmr_offset(stat):
     84  1.1  christos       /* XXX: Ignore these since we are wired to host.  */
     85  1.1  christos       break;
     86  1.1  christos     case mmr_offset(istat):
     87  1.1  christos       dv_w1c_2 (value16p, value, ~(1 << 14));
     88  1.1  christos       break;
     89  1.1  christos     case mmr_offset(alarm):
     90  1.1  christos       break;
     91  1.1  christos     case mmr_offset(ictl):
     92  1.1  christos       /* XXX: This should schedule an event handler.  */
     93  1.1  christos     case mmr_offset(swcnt):
     94  1.1  christos     case mmr_offset(pren):
     95  1.1  christos       break;
     96  1.1  christos     }
     97  1.1  christos 
     98  1.1  christos   return nr_bytes;
     99  1.1  christos }
    100  1.1  christos 
    101  1.1  christos static unsigned
    102  1.1  christos bfin_rtc_io_read_buffer (struct hw *me, void *dest,
    103  1.1  christos 			 int space, address_word addr, unsigned nr_bytes)
    104  1.1  christos {
    105  1.1  christos   struct bfin_rtc *rtc = hw_data (me);
    106  1.1  christos   bu32 mmr_off;
    107  1.1  christos   bu16 *value16p;
    108  1.1  christos   bu32 *value32p;
    109  1.1  christos   void *valuep;
    110  1.1  christos 
    111  1.6  christos   /* Invalid access mode is higher priority than missing register.  */
    112  1.6  christos   if (!dv_bfin_mmr_require_16_32 (me, addr, nr_bytes, false))
    113  1.6  christos     return 0;
    114  1.6  christos 
    115  1.1  christos   mmr_off = addr - rtc->base;
    116  1.1  christos   valuep = (void *)((unsigned long)rtc + mmr_base() + mmr_off);
    117  1.1  christos   value16p = valuep;
    118  1.1  christos   value32p = valuep;
    119  1.1  christos 
    120  1.1  christos   HW_TRACE_READ ();
    121  1.1  christos 
    122  1.1  christos   switch (mmr_off)
    123  1.1  christos     {
    124  1.1  christos     case mmr_offset(stat):
    125  1.1  christos       {
    126  1.1  christos 	time_t t = time (NULL);
    127  1.1  christos 	struct tm *tm = localtime (&t);
    128  1.1  christos 	bu32 value =
    129  1.1  christos 	  (((tm->tm_year - 70) * 365 + tm->tm_yday) << 17) |
    130  1.1  christos 	  (tm->tm_hour << 12) |
    131  1.1  christos 	  (tm->tm_min << 6) |
    132  1.1  christos 	  (tm->tm_sec << 0);
    133  1.1  christos 	dv_store_4 (dest, value);
    134  1.1  christos 	break;
    135  1.1  christos       }
    136  1.1  christos     case mmr_offset(alarm):
    137  1.1  christos       dv_store_4 (dest, *value32p);
    138  1.1  christos       break;
    139  1.1  christos     case mmr_offset(istat):
    140  1.1  christos     case mmr_offset(ictl):
    141  1.1  christos     case mmr_offset(swcnt):
    142  1.1  christos     case mmr_offset(pren):
    143  1.1  christos       dv_store_2 (dest, *value16p);
    144  1.1  christos       break;
    145  1.1  christos     }
    146  1.1  christos 
    147  1.1  christos   return nr_bytes;
    148  1.1  christos }
    149  1.1  christos 
    150  1.1  christos static const struct hw_port_descriptor bfin_rtc_ports[] =
    151  1.1  christos {
    152  1.1  christos   { "rtc", 0, 0, output_port, },
    153  1.1  christos   { NULL, 0, 0, 0, },
    154  1.1  christos };
    155  1.1  christos 
    156  1.1  christos static void
    157  1.1  christos attach_bfin_rtc_regs (struct hw *me, struct bfin_rtc *rtc)
    158  1.1  christos {
    159  1.1  christos   address_word attach_address;
    160  1.1  christos   int attach_space;
    161  1.1  christos   unsigned attach_size;
    162  1.1  christos   reg_property_spec reg;
    163  1.1  christos 
    164  1.1  christos   if (hw_find_property (me, "reg") == NULL)
    165  1.1  christos     hw_abort (me, "Missing \"reg\" property");
    166  1.1  christos 
    167  1.1  christos   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    168  1.1  christos     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    169  1.1  christos 
    170  1.1  christos   hw_unit_address_to_attach_address (hw_parent (me),
    171  1.1  christos 				     &reg.address,
    172  1.1  christos 				     &attach_space, &attach_address, me);
    173  1.1  christos   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    174  1.1  christos 
    175  1.1  christos   if (attach_size != BFIN_MMR_RTC_SIZE)
    176  1.1  christos     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_RTC_SIZE);
    177  1.1  christos 
    178  1.1  christos   hw_attach_address (hw_parent (me),
    179  1.1  christos 		     0, attach_space, attach_address, attach_size, me);
    180  1.1  christos 
    181  1.1  christos   rtc->base = attach_address;
    182  1.1  christos }
    183  1.1  christos 
    184  1.1  christos static void
    185  1.1  christos bfin_rtc_finish (struct hw *me)
    186  1.1  christos {
    187  1.1  christos   struct bfin_rtc *rtc;
    188  1.1  christos 
    189  1.1  christos   rtc = HW_ZALLOC (me, struct bfin_rtc);
    190  1.1  christos 
    191  1.1  christos   set_hw_data (me, rtc);
    192  1.1  christos   set_hw_io_read_buffer (me, bfin_rtc_io_read_buffer);
    193  1.1  christos   set_hw_io_write_buffer (me, bfin_rtc_io_write_buffer);
    194  1.1  christos   set_hw_ports (me, bfin_rtc_ports);
    195  1.1  christos 
    196  1.1  christos   attach_bfin_rtc_regs (me, rtc);
    197  1.1  christos 
    198  1.1  christos   /* Initialize the RTC.  */
    199  1.1  christos }
    200  1.1  christos 
    201  1.1  christos const struct hw_descriptor dv_bfin_rtc_descriptor[] =
    202  1.1  christos {
    203  1.1  christos   {"bfin_rtc", bfin_rtc_finish,},
    204  1.1  christos   {NULL, NULL},
    205  1.1  christos };
    206