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"
43 /* NVRAM - non-volatile memory with optional clock.
47 This device implements a small byte addressable non-volatile memory
48 component. The component may include an optional real-time clock
49 at its upper addresses.
53 reg = <address> <size>. Determine where the device lives in the
54 parents address space.
56 timezone = <integer>. Adjustment to current host's GMT (in secons)
57 that should be applied when updating the NVRAM's clock. */
59 typedef struct _hw_nvram_device
{
61 unsigned sizeof_memory
;
74 unsigned addr_minutes
;
75 unsigned addr_seconds
;
76 unsigned addr_control
;
80 hw_nvram_create(const char *name
,
81 const device_unit
*unit_address
,
85 hw_nvram_device
*hw_nvram
= ZALLOC(hw_nvram_device
);
89 typedef struct _hw_nvram_reg_spec
{
95 hw_nvram_init_address(device
*me
)
97 hw_nvram_device
*hw_nvram
= (hw_nvram_device
*)device_data(me
);
98 const device_property
*reg
= device_find_array_property(me
, "reg");
99 const hw_nvram_reg_spec
*spec
= reg
->array
;
100 int nr_entries
= reg
->sizeof_array
/ sizeof(*spec
);
102 if ((reg
->sizeof_array
% sizeof(*spec
)) != 0)
103 error("devices/%s reg property of incorrect size\n", device_name(me
));
105 error("devices/%s reg property contains multiple specs\n",
108 /* initialize the hw_nvram */
109 if (hw_nvram
->memory
== NULL
) {
110 hw_nvram
->sizeof_memory
= BE2H_4(spec
->size
);
111 hw_nvram
->memory
= zalloc(hw_nvram
->sizeof_memory
);
114 memset(hw_nvram
->memory
, hw_nvram
->sizeof_memory
, 0);
116 hw_nvram
->timezone
= device_find_integer_property(me
, "timezone");
118 hw_nvram
->addr_year
= hw_nvram
->sizeof_memory
- 1;
119 hw_nvram
->addr_month
= hw_nvram
->sizeof_memory
- 2;
120 hw_nvram
->addr_date
= hw_nvram
->sizeof_memory
- 3;
121 hw_nvram
->addr_day
= hw_nvram
->sizeof_memory
- 4;
122 hw_nvram
->addr_hour
= hw_nvram
->sizeof_memory
- 5;
123 hw_nvram
->addr_minutes
= hw_nvram
->sizeof_memory
- 6;
124 hw_nvram
->addr_seconds
= hw_nvram
->sizeof_memory
- 7;
125 hw_nvram
->addr_control
= hw_nvram
->sizeof_memory
- 8;
127 device_attach_address(device_parent(me
),
132 hw_nvram
->sizeof_memory
,
133 access_read_write_exec
,
138 hw_nvram_bcd(int val
)
140 return ((val
/ 10) << 4) + (val
% 10);
143 /* If reached an update interval and allowed, update the clock within
144 the hw_nvram. While this function could be implemented using events
145 it isn't on the assumption that the HW_NVRAM will hardly ever be
146 referenced and hence there is little need in keeping the clock
147 continually up-to-date */
149 hw_nvram_update_clock(hw_nvram_device
*hw_nvram
, cpu
*processor
)
152 if (!(hw_nvram
->memory
[hw_nvram
->addr_control
] & 0xc0)) {
153 time_t host_time
= time(NULL
);
154 if (hw_nvram
->host_time
!= host_time
) {
155 time_t nvtime
= hw_nvram
->host_time
+ hw_nvram
->timezone
;
156 struct tm
*clock
= gmtime(&nvtime
);
157 hw_nvram
->host_time
= host_time
;
158 hw_nvram
->memory
[hw_nvram
->addr_year
] = hw_nvram_bcd(clock
->tm_year
);
159 hw_nvram
->memory
[hw_nvram
->addr_month
] = hw_nvram_bcd(clock
->tm_mon
+ 1);
160 hw_nvram
->memory
[hw_nvram
->addr_date
] = hw_nvram_bcd(clock
->tm_mday
);
161 hw_nvram
->memory
[hw_nvram
->addr_day
] = hw_nvram_bcd(clock
->tm_wday
+ 1);
162 hw_nvram
->memory
[hw_nvram
->addr_hour
] = hw_nvram_bcd(clock
->tm_hour
);
163 hw_nvram
->memory
[hw_nvram
->addr_minutes
] = hw_nvram_bcd(clock
->tm_min
);
164 hw_nvram
->memory
[hw_nvram
->addr_seconds
] = hw_nvram_bcd(clock
->tm_sec
);
168 error("fixme - where do I find out GMT\n");
173 hw_nvram_set_clock(hw_nvram_device
*hw_nvram
, cpu
*processor
)
175 error ("fixme - how do I set the localtime\n");
179 hw_nvram_io_read_buffer(device
*me
,
188 hw_nvram_device
*hw_nvram
= (hw_nvram_device
*)device_data(me
);
189 for (i
= 0; i
< nr_bytes
; i
++) {
190 unsigned address
= (addr
+ i
) % hw_nvram
->sizeof_memory
;
191 unsigned8 data
= hw_nvram
->memory
[address
];
192 hw_nvram_update_clock(hw_nvram
, processor
);
193 ((unsigned8
*)dest
)[i
] = data
;
199 hw_nvram_io_write_buffer(device
*me
,
208 hw_nvram_device
*hw_nvram
= (hw_nvram_device
*)device_data(me
);
209 for (i
= 0; i
< nr_bytes
; i
++) {
210 unsigned address
= (addr
+ i
) % hw_nvram
->sizeof_memory
;
211 unsigned8 data
= ((unsigned8
*)source
)[i
];
212 if (address
== hw_nvram
->addr_control
213 && (data
& 0x80) == 0
214 && (hw_nvram
->memory
[address
] & 0x80) == 0x80)
215 hw_nvram_set_clock(hw_nvram
, processor
);
217 hw_nvram_update_clock(hw_nvram
, processor
);
218 hw_nvram
->memory
[address
] = data
;
223 static device_callbacks
const hw_nvram_callbacks
= {
224 { hw_nvram_init_address
, },
225 { NULL
, }, /* address */
226 { hw_nvram_io_read_buffer
, hw_nvram_io_write_buffer
}, /* IO */
229 const device_descriptor hw_nvram_device_descriptor
[] = {
230 { "nvram", hw_nvram_create
, &hw_nvram_callbacks
},
234 #endif /* _HW_NVRAM_C_ */