]> Git Repo - binutils.git/blob - sim/ppc/hw_nvram.c
Automatic date update in version.in
[binutils.git] / sim / ppc / hw_nvram.c
1 /*  This file is part of the program psim.
2
3     Copyright (C) 1994-1996, Andrew Cagney <[email protected]>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14  
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, see <http://www.gnu.org/licenses/>.
17  
18     */
19
20
21 #ifndef _HW_NVRAM_C_
22 #define _HW_NVRAM_C_
23
24 #ifndef STATIC_INLINE_HW_NVRAM
25 #define STATIC_INLINE_HW_NVRAM STATIC_INLINE
26 #endif
27
28 #include "device_table.h"
29
30 #include <time.h>
31 #include <string.h>
32
33 /* DEVICE
34
35
36    nvram - non-volatile memory with clock
37
38
39    DESCRIPTION
40
41
42    This device implements a small byte addressable non-volatile
43    memory.  The top 8 bytes of this memory include a real-time clock.
44
45
46    PROPERTIES
47
48
49    reg = <address> <size> (required)
50
51    Specify the address/size of this device within its parents address
52    space.
53
54
55    timezone = <integer> (optional)
56
57    Adjustment to the hosts current GMT (in seconds) that should be
58    applied when updating the NVRAM's clock.  If no timezone is
59    specified, zero (GMT or UCT) is assumed.
60
61
62    */
63
64 typedef struct _hw_nvram_device {
65   uint8_t *memory;
66   unsigned sizeof_memory;
67   time_t host_time;
68   unsigned timezone;
69   /* useful */
70   unsigned addr_year;
71   unsigned addr_month;
72   unsigned addr_date;
73   unsigned addr_day;
74   unsigned addr_hour;
75   unsigned addr_minutes;
76   unsigned addr_seconds;
77   unsigned addr_control;
78 } hw_nvram_device;
79
80 static void *
81 hw_nvram_create(const char *name,
82                 const device_unit *unit_address,
83                 const char *args)
84 {
85   hw_nvram_device *nvram = ZALLOC(hw_nvram_device);
86   return nvram;
87 }
88
89 typedef struct _hw_nvram_reg_spec {
90   uint32_t base;
91   uint32_t size;
92 } hw_nvram_reg_spec;
93
94 static void
95 hw_nvram_init_address(device *me)
96 {
97   hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
98   
99   /* use the generic init code to attach this device to its parent bus */
100   generic_device_init_address(me);
101
102   /* find the first non zero reg property and use that as the device
103      size */
104   if (nvram->sizeof_memory == 0) {
105     reg_property_spec reg;
106     int reg_nr;
107     for (reg_nr = 0;
108          device_find_reg_array_property(me, "reg", reg_nr, &reg);
109          reg_nr++) {
110       unsigned attach_size;
111       if (device_size_to_attach_size(device_parent(me),
112                                      &reg.size, &attach_size,
113                                      me)) {
114         nvram->sizeof_memory = attach_size;
115         break;
116       }
117     }
118     if (nvram->sizeof_memory == 0)
119       device_error(me, "reg property must contain a non-zero phys-addr:size tupple");
120     if (nvram->sizeof_memory < 8)
121       device_error(me, "NVRAM must be at least 8 bytes in size");
122   }
123
124   /* initialize the hw_nvram */
125   if (nvram->memory == NULL) {
126     nvram->memory = zalloc(nvram->sizeof_memory);
127   }
128   else
129     memset(nvram->memory, 0, nvram->sizeof_memory);
130   
131   if (device_find_property(me, "timezone") == NULL)
132     nvram->timezone = 0;
133   else
134     nvram->timezone = device_find_integer_property(me, "timezone");
135   
136   nvram->addr_year = nvram->sizeof_memory - 1;
137   nvram->addr_month = nvram->sizeof_memory - 2;
138   nvram->addr_date = nvram->sizeof_memory - 3;
139   nvram->addr_day = nvram->sizeof_memory - 4;
140   nvram->addr_hour = nvram->sizeof_memory - 5;
141   nvram->addr_minutes = nvram->sizeof_memory - 6;
142   nvram->addr_seconds = nvram->sizeof_memory - 7;
143   nvram->addr_control = nvram->sizeof_memory - 8;
144   
145 }
146
147 static int
148 hw_nvram_bcd(int val)
149 {
150   val = val % 100;
151   if (val < 0)
152     val += 100;
153   return ((val / 10) << 4) + (val % 10);
154 }
155
156
157 /* If reached an update interval and allowed, update the clock within
158    the hw_nvram.  While this function could be implemented using events
159    it isn't on the assumption that the HW_NVRAM will hardly ever be
160    referenced and hence there is little need in keeping the clock
161    continually up-to-date */
162
163 static void
164 hw_nvram_update_clock(hw_nvram_device *nvram,
165                       cpu *processor)
166 {
167   if (!(nvram->memory[nvram->addr_control] & 0xc0)) {
168     time_t host_time = time(NULL);
169     if (nvram->host_time != host_time) {
170       time_t nvtime = host_time + nvram->timezone;
171       struct tm *clock = gmtime(&nvtime);
172       nvram->host_time = host_time;
173       nvram->memory[nvram->addr_year] = hw_nvram_bcd(clock->tm_year);
174       nvram->memory[nvram->addr_month] = hw_nvram_bcd(clock->tm_mon + 1);
175       nvram->memory[nvram->addr_date] = hw_nvram_bcd(clock->tm_mday);
176       nvram->memory[nvram->addr_day] = hw_nvram_bcd(clock->tm_wday + 1);
177       nvram->memory[nvram->addr_hour] = hw_nvram_bcd(clock->tm_hour);
178       nvram->memory[nvram->addr_minutes] = hw_nvram_bcd(clock->tm_min);
179       nvram->memory[nvram->addr_seconds] = hw_nvram_bcd(clock->tm_sec);
180     }
181   }
182 }
183
184 static void
185 hw_nvram_set_clock(hw_nvram_device *nvram, cpu *processor)
186 {
187   error ("fixme - how do I set the localtime\n");
188 }
189
190 static unsigned
191 hw_nvram_io_read_buffer(device *me,
192                         void *dest,
193                         int space,
194                         unsigned_word addr,
195                         unsigned nr_bytes,
196                         cpu *processor,
197                         unsigned_word cia)
198 {
199   int i;
200   hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
201   for (i = 0; i < nr_bytes; i++) {
202     unsigned address = (addr + i) % nvram->sizeof_memory;
203     uint8_t data = nvram->memory[address];
204     hw_nvram_update_clock(nvram, processor);
205     ((uint8_t*)dest)[i] = data;
206   }
207   return nr_bytes;
208 }
209
210 static unsigned
211 hw_nvram_io_write_buffer(device *me,
212                          const void *source,
213                          int space,
214                          unsigned_word addr,
215                          unsigned nr_bytes,
216                          cpu *processor,
217                          unsigned_word cia)
218 {
219   int i;
220   hw_nvram_device *nvram = (hw_nvram_device*)device_data(me);
221   for (i = 0; i < nr_bytes; i++) {
222     unsigned address = (addr + i) % nvram->sizeof_memory;
223     uint8_t data = ((uint8_t*)source)[i];
224     if (address == nvram->addr_control
225         && (data & 0x80) == 0
226         && (nvram->memory[address] & 0x80) == 0x80)
227       hw_nvram_set_clock(nvram, processor);
228     else
229       hw_nvram_update_clock(nvram, processor);
230     nvram->memory[address] = data;
231   }
232   return nr_bytes;
233 }
234
235 static device_callbacks const hw_nvram_callbacks = {
236   { hw_nvram_init_address, },
237   { NULL, }, /* address */
238   { hw_nvram_io_read_buffer, hw_nvram_io_write_buffer }, /* IO */
239 };
240
241 const device_descriptor hw_nvram_device_descriptor[] = {
242   { "nvram", hw_nvram_create, &hw_nvram_callbacks },
243   { NULL },
244 };
245
246 #endif /* _HW_NVRAM_C_ */
This page took 0.037968 seconds and 4 git commands to generate.