1 /* This file is part of the program psim.
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
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 2 of the License, or
8 (at your option) any later version.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #ifndef STATIC_INLINE_HW_NVRAM
26 #define STATIC_INLINE_HW_NVRAM STATIC_INLINE
29 #include "device_table.h"
46 nvram - non-volatile memory with clock
52 This device implements a small byte addressable non-volatile
53 memory. The top 8 bytes of this memory include a real-time clock.
59 reg = <address> <size> (required)
61 Specify the address/size of this device within its parents address
65 timezone = <integer> (optional)
67 Adjustment to the hosts current GMT (in seconds) that should be
68 applied when updating the NVRAM's clock. If no timezone is
69 specified, zero (GMT or UCT) is assumed.
74 typedef struct _hw_nvram_device
{
76 unsigned sizeof_memory
;
89 unsigned addr_minutes
;
90 unsigned addr_seconds
;
91 unsigned addr_control
;
95 hw_nvram_create(const char *name
,
96 const device_unit
*unit_address
,
99 hw_nvram_device
*nvram
= ZALLOC(hw_nvram_device
);
103 typedef struct _hw_nvram_reg_spec
{
109 hw_nvram_init_address(device
*me
)
111 hw_nvram_device
*nvram
= (hw_nvram_device
*)device_data(me
);
113 /* use the generic init code to attach this device to its parent bus */
114 generic_device_init_address(me
);
116 /* find the first non zero reg property and use that as the device
118 if (nvram
->sizeof_memory
== 0) {
119 reg_property_spec reg
;
122 device_find_reg_array_property(me
, "reg", reg_nr
, ®
);
124 unsigned attach_size
;
125 if (device_size_to_attach_size(device_parent(me
),
126 ®
.size
, &attach_size
,
128 nvram
->sizeof_memory
= attach_size
;
132 if (nvram
->sizeof_memory
== 0)
133 device_error(me
, "reg property must contain a non-zero phys-addr:size tupple");
134 if (nvram
->sizeof_memory
< 8)
135 device_error(me
, "NVRAM must be at least 8 bytes in size");
138 /* initialize the hw_nvram */
139 if (nvram
->memory
== NULL
) {
140 nvram
->memory
= zalloc(nvram
->sizeof_memory
);
143 memset(nvram
->memory
, 0, nvram
->sizeof_memory
);
145 if (device_find_property(me
, "timezone") == NULL
)
148 nvram
->timezone
= device_find_integer_property(me
, "timezone");
150 nvram
->addr_year
= nvram
->sizeof_memory
- 1;
151 nvram
->addr_month
= nvram
->sizeof_memory
- 2;
152 nvram
->addr_date
= nvram
->sizeof_memory
- 3;
153 nvram
->addr_day
= nvram
->sizeof_memory
- 4;
154 nvram
->addr_hour
= nvram
->sizeof_memory
- 5;
155 nvram
->addr_minutes
= nvram
->sizeof_memory
- 6;
156 nvram
->addr_seconds
= nvram
->sizeof_memory
- 7;
157 nvram
->addr_control
= nvram
->sizeof_memory
- 8;
162 hw_nvram_bcd(int val
)
167 return ((val
/ 10) << 4) + (val
% 10);
171 /* If reached an update interval and allowed, update the clock within
172 the hw_nvram. While this function could be implemented using events
173 it isn't on the assumption that the HW_NVRAM will hardly ever be
174 referenced and hence there is little need in keeping the clock
175 continually up-to-date */
178 hw_nvram_update_clock(hw_nvram_device
*nvram
,
182 if (!(nvram
->memory
[nvram
->addr_control
] & 0xc0)) {
183 time_t host_time
= time(NULL
);
184 if (nvram
->host_time
!= host_time
) {
185 time_t nvtime
= host_time
+ nvram
->timezone
;
186 struct tm
*clock
= gmtime(&nvtime
);
187 nvram
->host_time
= host_time
;
188 nvram
->memory
[nvram
->addr_year
] = hw_nvram_bcd(clock
->tm_year
);
189 nvram
->memory
[nvram
->addr_month
] = hw_nvram_bcd(clock
->tm_mon
+ 1);
190 nvram
->memory
[nvram
->addr_date
] = hw_nvram_bcd(clock
->tm_mday
);
191 nvram
->memory
[nvram
->addr_day
] = hw_nvram_bcd(clock
->tm_wday
+ 1);
192 nvram
->memory
[nvram
->addr_hour
] = hw_nvram_bcd(clock
->tm_hour
);
193 nvram
->memory
[nvram
->addr_minutes
] = hw_nvram_bcd(clock
->tm_min
);
194 nvram
->memory
[nvram
->addr_seconds
] = hw_nvram_bcd(clock
->tm_sec
);
198 error("fixme - where do I find out GMT\n");
203 hw_nvram_set_clock(hw_nvram_device
*nvram
, cpu
*processor
)
205 error ("fixme - how do I set the localtime\n");
209 hw_nvram_io_read_buffer(device
*me
,
218 hw_nvram_device
*nvram
= (hw_nvram_device
*)device_data(me
);
219 for (i
= 0; i
< nr_bytes
; i
++) {
220 unsigned address
= (addr
+ i
) % nvram
->sizeof_memory
;
221 unsigned8 data
= nvram
->memory
[address
];
222 hw_nvram_update_clock(nvram
, processor
);
223 ((unsigned8
*)dest
)[i
] = data
;
229 hw_nvram_io_write_buffer(device
*me
,
238 hw_nvram_device
*nvram
= (hw_nvram_device
*)device_data(me
);
239 for (i
= 0; i
< nr_bytes
; i
++) {
240 unsigned address
= (addr
+ i
) % nvram
->sizeof_memory
;
241 unsigned8 data
= ((unsigned8
*)source
)[i
];
242 if (address
== nvram
->addr_control
243 && (data
& 0x80) == 0
244 && (nvram
->memory
[address
] & 0x80) == 0x80)
245 hw_nvram_set_clock(nvram
, processor
);
247 hw_nvram_update_clock(nvram
, processor
);
248 nvram
->memory
[address
] = data
;
253 static device_callbacks
const hw_nvram_callbacks
= {
254 { hw_nvram_init_address
, },
255 { NULL
, }, /* address */
256 { hw_nvram_io_read_buffer
, hw_nvram_io_write_buffer
}, /* IO */
259 const device_descriptor hw_nvram_device_descriptor
[] = {
260 { "nvram", hw_nvram_create
, &hw_nvram_callbacks
},
264 #endif /* _HW_NVRAM_C_ */