1819ce6b2SPhilippe Mathieu-Daudé /*
2819ce6b2SPhilippe Mathieu-Daudé * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
3819ce6b2SPhilippe Mathieu-Daudé *
4819ce6b2SPhilippe Mathieu-Daudé * Copyright (c) 2003-2005, 2007, 2017 Jocelyn Mayer
5819ce6b2SPhilippe Mathieu-Daudé * Copyright (c) 2013 Hervé Poussineau
6819ce6b2SPhilippe Mathieu-Daudé *
7819ce6b2SPhilippe Mathieu-Daudé * Permission is hereby granted, free of charge, to any person obtaining a copy
8819ce6b2SPhilippe Mathieu-Daudé * of this software and associated documentation files (the "Software"), to deal
9819ce6b2SPhilippe Mathieu-Daudé * in the Software without restriction, including without limitation the rights
10819ce6b2SPhilippe Mathieu-Daudé * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11819ce6b2SPhilippe Mathieu-Daudé * copies of the Software, and to permit persons to whom the Software is
12819ce6b2SPhilippe Mathieu-Daudé * furnished to do so, subject to the following conditions:
13819ce6b2SPhilippe Mathieu-Daudé *
14819ce6b2SPhilippe Mathieu-Daudé * The above copyright notice and this permission notice shall be included in
15819ce6b2SPhilippe Mathieu-Daudé * all copies or substantial portions of the Software.
16819ce6b2SPhilippe Mathieu-Daudé *
17819ce6b2SPhilippe Mathieu-Daudé * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18819ce6b2SPhilippe Mathieu-Daudé * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19819ce6b2SPhilippe Mathieu-Daudé * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20819ce6b2SPhilippe Mathieu-Daudé * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21819ce6b2SPhilippe Mathieu-Daudé * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22819ce6b2SPhilippe Mathieu-Daudé * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23819ce6b2SPhilippe Mathieu-Daudé * THE SOFTWARE.
24819ce6b2SPhilippe Mathieu-Daudé */
25819ce6b2SPhilippe Mathieu-Daudé
26819ce6b2SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
27819ce6b2SPhilippe Mathieu-Daudé #include "hw/irq.h"
28819ce6b2SPhilippe Mathieu-Daudé #include "hw/qdev-properties.h"
29819ce6b2SPhilippe Mathieu-Daudé #include "hw/rtc/m48t59.h"
30819ce6b2SPhilippe Mathieu-Daudé #include "qemu/timer.h"
31819ce6b2SPhilippe Mathieu-Daudé #include "sysemu/runstate.h"
322f93d8b0SPeter Maydell #include "sysemu/rtc.h"
33819ce6b2SPhilippe Mathieu-Daudé #include "sysemu/sysemu.h"
34819ce6b2SPhilippe Mathieu-Daudé #include "hw/sysbus.h"
353e80f690SMarkus Armbruster #include "qapi/error.h"
36819ce6b2SPhilippe Mathieu-Daudé #include "qemu/bcd.h"
37819ce6b2SPhilippe Mathieu-Daudé #include "qemu/module.h"
38e21d73ecSPhilippe Mathieu-Daudé #include "trace.h"
399d80aa04SAbhiram Tilak #include "sysemu/watchdog.h"
40819ce6b2SPhilippe Mathieu-Daudé
41819ce6b2SPhilippe Mathieu-Daudé #include "m48t59-internal.h"
42819ce6b2SPhilippe Mathieu-Daudé #include "migration/vmstate.h"
43db1015e9SEduardo Habkost #include "qom/object.h"
44819ce6b2SPhilippe Mathieu-Daudé
45819ce6b2SPhilippe Mathieu-Daudé #define TYPE_M48TXX_SYS_BUS "sysbus-m48txx"
46db1015e9SEduardo Habkost typedef struct M48txxSysBusDeviceClass M48txxSysBusDeviceClass;
47db1015e9SEduardo Habkost typedef struct M48txxSysBusState M48txxSysBusState;
488110fa1dSEduardo Habkost DECLARE_OBJ_CHECKERS(M48txxSysBusState, M48txxSysBusDeviceClass,
498110fa1dSEduardo Habkost M48TXX_SYS_BUS, TYPE_M48TXX_SYS_BUS)
50819ce6b2SPhilippe Mathieu-Daudé
51819ce6b2SPhilippe Mathieu-Daudé /*
52819ce6b2SPhilippe Mathieu-Daudé * Chipset docs:
53819ce6b2SPhilippe Mathieu-Daudé * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
54819ce6b2SPhilippe Mathieu-Daudé * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
55819ce6b2SPhilippe Mathieu-Daudé * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
56819ce6b2SPhilippe Mathieu-Daudé */
57819ce6b2SPhilippe Mathieu-Daudé
58db1015e9SEduardo Habkost struct M48txxSysBusState {
59819ce6b2SPhilippe Mathieu-Daudé SysBusDevice parent_obj;
60819ce6b2SPhilippe Mathieu-Daudé M48t59State state;
61819ce6b2SPhilippe Mathieu-Daudé MemoryRegion io;
62db1015e9SEduardo Habkost };
63819ce6b2SPhilippe Mathieu-Daudé
64db1015e9SEduardo Habkost struct M48txxSysBusDeviceClass {
65819ce6b2SPhilippe Mathieu-Daudé SysBusDeviceClass parent_class;
66819ce6b2SPhilippe Mathieu-Daudé M48txxInfo info;
67db1015e9SEduardo Habkost };
68819ce6b2SPhilippe Mathieu-Daudé
69819ce6b2SPhilippe Mathieu-Daudé static M48txxInfo m48txx_sysbus_info[] = {
70819ce6b2SPhilippe Mathieu-Daudé {
71819ce6b2SPhilippe Mathieu-Daudé .bus_name = "sysbus-m48t02",
72819ce6b2SPhilippe Mathieu-Daudé .model = 2,
73819ce6b2SPhilippe Mathieu-Daudé .size = 0x800,
74819ce6b2SPhilippe Mathieu-Daudé },{
75819ce6b2SPhilippe Mathieu-Daudé .bus_name = "sysbus-m48t08",
76819ce6b2SPhilippe Mathieu-Daudé .model = 8,
77819ce6b2SPhilippe Mathieu-Daudé .size = 0x2000,
78819ce6b2SPhilippe Mathieu-Daudé },{
79819ce6b2SPhilippe Mathieu-Daudé .bus_name = "sysbus-m48t59",
80819ce6b2SPhilippe Mathieu-Daudé .model = 59,
81819ce6b2SPhilippe Mathieu-Daudé .size = 0x2000,
82819ce6b2SPhilippe Mathieu-Daudé }
83819ce6b2SPhilippe Mathieu-Daudé };
84819ce6b2SPhilippe Mathieu-Daudé
85819ce6b2SPhilippe Mathieu-Daudé
86819ce6b2SPhilippe Mathieu-Daudé /* Fake timer functions */
87819ce6b2SPhilippe Mathieu-Daudé
88819ce6b2SPhilippe Mathieu-Daudé /* Alarm management */
alarm_cb(void * opaque)89819ce6b2SPhilippe Mathieu-Daudé static void alarm_cb (void *opaque)
90819ce6b2SPhilippe Mathieu-Daudé {
91819ce6b2SPhilippe Mathieu-Daudé struct tm tm;
92819ce6b2SPhilippe Mathieu-Daudé uint64_t next_time;
93819ce6b2SPhilippe Mathieu-Daudé M48t59State *NVRAM = opaque;
94819ce6b2SPhilippe Mathieu-Daudé
95819ce6b2SPhilippe Mathieu-Daudé qemu_set_irq(NVRAM->IRQ, 1);
96819ce6b2SPhilippe Mathieu-Daudé if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
97819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
98819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
99819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
100819ce6b2SPhilippe Mathieu-Daudé /* Repeat once a month */
101819ce6b2SPhilippe Mathieu-Daudé qemu_get_timedate(&tm, NVRAM->time_offset);
102819ce6b2SPhilippe Mathieu-Daudé tm.tm_mon++;
103819ce6b2SPhilippe Mathieu-Daudé if (tm.tm_mon == 13) {
104819ce6b2SPhilippe Mathieu-Daudé tm.tm_mon = 1;
105819ce6b2SPhilippe Mathieu-Daudé tm.tm_year++;
106819ce6b2SPhilippe Mathieu-Daudé }
107819ce6b2SPhilippe Mathieu-Daudé next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
108819ce6b2SPhilippe Mathieu-Daudé } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
109819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
110819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
111819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
112819ce6b2SPhilippe Mathieu-Daudé /* Repeat once a day */
113819ce6b2SPhilippe Mathieu-Daudé next_time = 24 * 60 * 60;
114819ce6b2SPhilippe Mathieu-Daudé } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
115819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
116819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
117819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
118819ce6b2SPhilippe Mathieu-Daudé /* Repeat once an hour */
119819ce6b2SPhilippe Mathieu-Daudé next_time = 60 * 60;
120819ce6b2SPhilippe Mathieu-Daudé } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
121819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
122819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
123819ce6b2SPhilippe Mathieu-Daudé (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
124819ce6b2SPhilippe Mathieu-Daudé /* Repeat once a minute */
125819ce6b2SPhilippe Mathieu-Daudé next_time = 60;
126819ce6b2SPhilippe Mathieu-Daudé } else {
127819ce6b2SPhilippe Mathieu-Daudé /* Repeat once a second */
128819ce6b2SPhilippe Mathieu-Daudé next_time = 1;
129819ce6b2SPhilippe Mathieu-Daudé }
130819ce6b2SPhilippe Mathieu-Daudé timer_mod(NVRAM->alrm_timer, qemu_clock_get_ns(rtc_clock) +
131819ce6b2SPhilippe Mathieu-Daudé next_time * 1000);
132819ce6b2SPhilippe Mathieu-Daudé qemu_set_irq(NVRAM->IRQ, 0);
133819ce6b2SPhilippe Mathieu-Daudé }
134819ce6b2SPhilippe Mathieu-Daudé
set_alarm(M48t59State * NVRAM)135819ce6b2SPhilippe Mathieu-Daudé static void set_alarm(M48t59State *NVRAM)
136819ce6b2SPhilippe Mathieu-Daudé {
1377038b6e4SPeter Maydell int64_t diff;
138819ce6b2SPhilippe Mathieu-Daudé if (NVRAM->alrm_timer != NULL) {
139819ce6b2SPhilippe Mathieu-Daudé timer_del(NVRAM->alrm_timer);
140819ce6b2SPhilippe Mathieu-Daudé diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
141819ce6b2SPhilippe Mathieu-Daudé if (diff > 0)
142819ce6b2SPhilippe Mathieu-Daudé timer_mod(NVRAM->alrm_timer, diff * 1000);
143819ce6b2SPhilippe Mathieu-Daudé }
144819ce6b2SPhilippe Mathieu-Daudé }
145819ce6b2SPhilippe Mathieu-Daudé
146819ce6b2SPhilippe Mathieu-Daudé /* RTC management helpers */
get_time(M48t59State * NVRAM,struct tm * tm)147819ce6b2SPhilippe Mathieu-Daudé static inline void get_time(M48t59State *NVRAM, struct tm *tm)
148819ce6b2SPhilippe Mathieu-Daudé {
149819ce6b2SPhilippe Mathieu-Daudé qemu_get_timedate(tm, NVRAM->time_offset);
150819ce6b2SPhilippe Mathieu-Daudé }
151819ce6b2SPhilippe Mathieu-Daudé
set_time(M48t59State * NVRAM,struct tm * tm)152819ce6b2SPhilippe Mathieu-Daudé static void set_time(M48t59State *NVRAM, struct tm *tm)
153819ce6b2SPhilippe Mathieu-Daudé {
154819ce6b2SPhilippe Mathieu-Daudé NVRAM->time_offset = qemu_timedate_diff(tm);
155819ce6b2SPhilippe Mathieu-Daudé set_alarm(NVRAM);
156819ce6b2SPhilippe Mathieu-Daudé }
157819ce6b2SPhilippe Mathieu-Daudé
158819ce6b2SPhilippe Mathieu-Daudé /* Watchdog management */
watchdog_cb(void * opaque)159819ce6b2SPhilippe Mathieu-Daudé static void watchdog_cb (void *opaque)
160819ce6b2SPhilippe Mathieu-Daudé {
161819ce6b2SPhilippe Mathieu-Daudé M48t59State *NVRAM = opaque;
162819ce6b2SPhilippe Mathieu-Daudé
163819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF0] |= 0x80;
164819ce6b2SPhilippe Mathieu-Daudé if (NVRAM->buffer[0x1FF7] & 0x80) {
165819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF7] = 0x00;
166819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FFC] &= ~0x40;
1679d80aa04SAbhiram Tilak watchdog_perform_action();
168819ce6b2SPhilippe Mathieu-Daudé } else {
169819ce6b2SPhilippe Mathieu-Daudé qemu_set_irq(NVRAM->IRQ, 1);
170819ce6b2SPhilippe Mathieu-Daudé qemu_set_irq(NVRAM->IRQ, 0);
171819ce6b2SPhilippe Mathieu-Daudé }
172819ce6b2SPhilippe Mathieu-Daudé }
173819ce6b2SPhilippe Mathieu-Daudé
set_up_watchdog(M48t59State * NVRAM,uint8_t value)174819ce6b2SPhilippe Mathieu-Daudé static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
175819ce6b2SPhilippe Mathieu-Daudé {
176819ce6b2SPhilippe Mathieu-Daudé uint64_t interval; /* in 1/16 seconds */
177819ce6b2SPhilippe Mathieu-Daudé
178819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF0] &= ~0x80;
179819ce6b2SPhilippe Mathieu-Daudé if (NVRAM->wd_timer != NULL) {
180819ce6b2SPhilippe Mathieu-Daudé timer_del(NVRAM->wd_timer);
181819ce6b2SPhilippe Mathieu-Daudé if (value != 0) {
182819ce6b2SPhilippe Mathieu-Daudé interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
183819ce6b2SPhilippe Mathieu-Daudé timer_mod(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
184819ce6b2SPhilippe Mathieu-Daudé ((interval * 1000) >> 4));
185819ce6b2SPhilippe Mathieu-Daudé }
186819ce6b2SPhilippe Mathieu-Daudé }
187819ce6b2SPhilippe Mathieu-Daudé }
188819ce6b2SPhilippe Mathieu-Daudé
189819ce6b2SPhilippe Mathieu-Daudé /* Direct access to NVRAM */
m48t59_write(M48t59State * NVRAM,uint32_t addr,uint32_t val)190819ce6b2SPhilippe Mathieu-Daudé void m48t59_write(M48t59State *NVRAM, uint32_t addr, uint32_t val)
191819ce6b2SPhilippe Mathieu-Daudé {
192819ce6b2SPhilippe Mathieu-Daudé struct tm tm;
193819ce6b2SPhilippe Mathieu-Daudé int tmp;
194819ce6b2SPhilippe Mathieu-Daudé
195e21d73ecSPhilippe Mathieu-Daudé trace_m48txx_nvram_mem_write(addr, val);
196819ce6b2SPhilippe Mathieu-Daudé
197819ce6b2SPhilippe Mathieu-Daudé /* check for NVRAM access */
198819ce6b2SPhilippe Mathieu-Daudé if ((NVRAM->model == 2 && addr < 0x7f8) ||
199819ce6b2SPhilippe Mathieu-Daudé (NVRAM->model == 8 && addr < 0x1ff8) ||
200819ce6b2SPhilippe Mathieu-Daudé (NVRAM->model == 59 && addr < 0x1ff0)) {
201819ce6b2SPhilippe Mathieu-Daudé goto do_write;
202819ce6b2SPhilippe Mathieu-Daudé }
203819ce6b2SPhilippe Mathieu-Daudé
204819ce6b2SPhilippe Mathieu-Daudé /* TOD access */
205819ce6b2SPhilippe Mathieu-Daudé switch (addr) {
206819ce6b2SPhilippe Mathieu-Daudé case 0x1FF0:
207819ce6b2SPhilippe Mathieu-Daudé /* flags register : read-only */
208819ce6b2SPhilippe Mathieu-Daudé break;
209819ce6b2SPhilippe Mathieu-Daudé case 0x1FF1:
210819ce6b2SPhilippe Mathieu-Daudé /* unused */
211819ce6b2SPhilippe Mathieu-Daudé break;
212819ce6b2SPhilippe Mathieu-Daudé case 0x1FF2:
213819ce6b2SPhilippe Mathieu-Daudé /* alarm seconds */
214819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x7F);
215819ce6b2SPhilippe Mathieu-Daudé if (tmp >= 0 && tmp <= 59) {
216819ce6b2SPhilippe Mathieu-Daudé NVRAM->alarm.tm_sec = tmp;
217819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF2] = val;
218819ce6b2SPhilippe Mathieu-Daudé set_alarm(NVRAM);
219819ce6b2SPhilippe Mathieu-Daudé }
220819ce6b2SPhilippe Mathieu-Daudé break;
221819ce6b2SPhilippe Mathieu-Daudé case 0x1FF3:
222819ce6b2SPhilippe Mathieu-Daudé /* alarm minutes */
223819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x7F);
224819ce6b2SPhilippe Mathieu-Daudé if (tmp >= 0 && tmp <= 59) {
225819ce6b2SPhilippe Mathieu-Daudé NVRAM->alarm.tm_min = tmp;
226819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF3] = val;
227819ce6b2SPhilippe Mathieu-Daudé set_alarm(NVRAM);
228819ce6b2SPhilippe Mathieu-Daudé }
229819ce6b2SPhilippe Mathieu-Daudé break;
230819ce6b2SPhilippe Mathieu-Daudé case 0x1FF4:
231819ce6b2SPhilippe Mathieu-Daudé /* alarm hours */
232819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x3F);
233819ce6b2SPhilippe Mathieu-Daudé if (tmp >= 0 && tmp <= 23) {
234819ce6b2SPhilippe Mathieu-Daudé NVRAM->alarm.tm_hour = tmp;
235819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF4] = val;
236819ce6b2SPhilippe Mathieu-Daudé set_alarm(NVRAM);
237819ce6b2SPhilippe Mathieu-Daudé }
238819ce6b2SPhilippe Mathieu-Daudé break;
239819ce6b2SPhilippe Mathieu-Daudé case 0x1FF5:
240819ce6b2SPhilippe Mathieu-Daudé /* alarm date */
241819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x3F);
242819ce6b2SPhilippe Mathieu-Daudé if (tmp != 0) {
243819ce6b2SPhilippe Mathieu-Daudé NVRAM->alarm.tm_mday = tmp;
244819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF5] = val;
245819ce6b2SPhilippe Mathieu-Daudé set_alarm(NVRAM);
246819ce6b2SPhilippe Mathieu-Daudé }
247819ce6b2SPhilippe Mathieu-Daudé break;
248819ce6b2SPhilippe Mathieu-Daudé case 0x1FF6:
249819ce6b2SPhilippe Mathieu-Daudé /* interrupts */
250819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF6] = val;
251819ce6b2SPhilippe Mathieu-Daudé break;
252819ce6b2SPhilippe Mathieu-Daudé case 0x1FF7:
253819ce6b2SPhilippe Mathieu-Daudé /* watchdog */
254819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[0x1FF7] = val;
255819ce6b2SPhilippe Mathieu-Daudé set_up_watchdog(NVRAM, val);
256819ce6b2SPhilippe Mathieu-Daudé break;
257819ce6b2SPhilippe Mathieu-Daudé case 0x1FF8:
258819ce6b2SPhilippe Mathieu-Daudé case 0x07F8:
259819ce6b2SPhilippe Mathieu-Daudé /* control */
260819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
261819ce6b2SPhilippe Mathieu-Daudé break;
262819ce6b2SPhilippe Mathieu-Daudé case 0x1FF9:
263819ce6b2SPhilippe Mathieu-Daudé case 0x07F9:
264819ce6b2SPhilippe Mathieu-Daudé /* seconds (BCD) */
265819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x7F);
266819ce6b2SPhilippe Mathieu-Daudé if (tmp >= 0 && tmp <= 59) {
267819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
268819ce6b2SPhilippe Mathieu-Daudé tm.tm_sec = tmp;
269819ce6b2SPhilippe Mathieu-Daudé set_time(NVRAM, &tm);
270819ce6b2SPhilippe Mathieu-Daudé }
271819ce6b2SPhilippe Mathieu-Daudé if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
272819ce6b2SPhilippe Mathieu-Daudé if (val & 0x80) {
273819ce6b2SPhilippe Mathieu-Daudé NVRAM->stop_time = time(NULL);
274819ce6b2SPhilippe Mathieu-Daudé } else {
275819ce6b2SPhilippe Mathieu-Daudé NVRAM->time_offset += NVRAM->stop_time - time(NULL);
276819ce6b2SPhilippe Mathieu-Daudé NVRAM->stop_time = 0;
277819ce6b2SPhilippe Mathieu-Daudé }
278819ce6b2SPhilippe Mathieu-Daudé }
279819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[addr] = val & 0x80;
280819ce6b2SPhilippe Mathieu-Daudé break;
281819ce6b2SPhilippe Mathieu-Daudé case 0x1FFA:
282819ce6b2SPhilippe Mathieu-Daudé case 0x07FA:
283819ce6b2SPhilippe Mathieu-Daudé /* minutes (BCD) */
284819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x7F);
285819ce6b2SPhilippe Mathieu-Daudé if (tmp >= 0 && tmp <= 59) {
286819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
287819ce6b2SPhilippe Mathieu-Daudé tm.tm_min = tmp;
288819ce6b2SPhilippe Mathieu-Daudé set_time(NVRAM, &tm);
289819ce6b2SPhilippe Mathieu-Daudé }
290819ce6b2SPhilippe Mathieu-Daudé break;
291819ce6b2SPhilippe Mathieu-Daudé case 0x1FFB:
292819ce6b2SPhilippe Mathieu-Daudé case 0x07FB:
293819ce6b2SPhilippe Mathieu-Daudé /* hours (BCD) */
294819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x3F);
295819ce6b2SPhilippe Mathieu-Daudé if (tmp >= 0 && tmp <= 23) {
296819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
297819ce6b2SPhilippe Mathieu-Daudé tm.tm_hour = tmp;
298819ce6b2SPhilippe Mathieu-Daudé set_time(NVRAM, &tm);
299819ce6b2SPhilippe Mathieu-Daudé }
300819ce6b2SPhilippe Mathieu-Daudé break;
301819ce6b2SPhilippe Mathieu-Daudé case 0x1FFC:
302819ce6b2SPhilippe Mathieu-Daudé case 0x07FC:
303819ce6b2SPhilippe Mathieu-Daudé /* day of the week / century */
304819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x07);
305819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
306819ce6b2SPhilippe Mathieu-Daudé tm.tm_wday = tmp;
307819ce6b2SPhilippe Mathieu-Daudé set_time(NVRAM, &tm);
308819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[addr] = val & 0x40;
309819ce6b2SPhilippe Mathieu-Daudé break;
310819ce6b2SPhilippe Mathieu-Daudé case 0x1FFD:
311819ce6b2SPhilippe Mathieu-Daudé case 0x07FD:
312819ce6b2SPhilippe Mathieu-Daudé /* date (BCD) */
313819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x3F);
314819ce6b2SPhilippe Mathieu-Daudé if (tmp != 0) {
315819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
316819ce6b2SPhilippe Mathieu-Daudé tm.tm_mday = tmp;
317819ce6b2SPhilippe Mathieu-Daudé set_time(NVRAM, &tm);
318819ce6b2SPhilippe Mathieu-Daudé }
319819ce6b2SPhilippe Mathieu-Daudé break;
320819ce6b2SPhilippe Mathieu-Daudé case 0x1FFE:
321819ce6b2SPhilippe Mathieu-Daudé case 0x07FE:
322819ce6b2SPhilippe Mathieu-Daudé /* month */
323819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val & 0x1F);
324819ce6b2SPhilippe Mathieu-Daudé if (tmp >= 1 && tmp <= 12) {
325819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
326819ce6b2SPhilippe Mathieu-Daudé tm.tm_mon = tmp - 1;
327819ce6b2SPhilippe Mathieu-Daudé set_time(NVRAM, &tm);
328819ce6b2SPhilippe Mathieu-Daudé }
329819ce6b2SPhilippe Mathieu-Daudé break;
330819ce6b2SPhilippe Mathieu-Daudé case 0x1FFF:
331819ce6b2SPhilippe Mathieu-Daudé case 0x07FF:
332819ce6b2SPhilippe Mathieu-Daudé /* year */
333819ce6b2SPhilippe Mathieu-Daudé tmp = from_bcd(val);
334819ce6b2SPhilippe Mathieu-Daudé if (tmp >= 0 && tmp <= 99) {
335819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
336819ce6b2SPhilippe Mathieu-Daudé tm.tm_year = from_bcd(val) + NVRAM->base_year - 1900;
337819ce6b2SPhilippe Mathieu-Daudé set_time(NVRAM, &tm);
338819ce6b2SPhilippe Mathieu-Daudé }
339819ce6b2SPhilippe Mathieu-Daudé break;
340819ce6b2SPhilippe Mathieu-Daudé default:
341819ce6b2SPhilippe Mathieu-Daudé /* Check lock registers state */
342819ce6b2SPhilippe Mathieu-Daudé if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
343819ce6b2SPhilippe Mathieu-Daudé break;
344819ce6b2SPhilippe Mathieu-Daudé if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
345819ce6b2SPhilippe Mathieu-Daudé break;
346819ce6b2SPhilippe Mathieu-Daudé do_write:
347819ce6b2SPhilippe Mathieu-Daudé if (addr < NVRAM->size) {
348819ce6b2SPhilippe Mathieu-Daudé NVRAM->buffer[addr] = val & 0xFF;
349819ce6b2SPhilippe Mathieu-Daudé }
350819ce6b2SPhilippe Mathieu-Daudé break;
351819ce6b2SPhilippe Mathieu-Daudé }
352819ce6b2SPhilippe Mathieu-Daudé }
353819ce6b2SPhilippe Mathieu-Daudé
m48t59_read(M48t59State * NVRAM,uint32_t addr)354819ce6b2SPhilippe Mathieu-Daudé uint32_t m48t59_read(M48t59State *NVRAM, uint32_t addr)
355819ce6b2SPhilippe Mathieu-Daudé {
356819ce6b2SPhilippe Mathieu-Daudé struct tm tm;
357819ce6b2SPhilippe Mathieu-Daudé uint32_t retval = 0xFF;
358819ce6b2SPhilippe Mathieu-Daudé
359819ce6b2SPhilippe Mathieu-Daudé /* check for NVRAM access */
360819ce6b2SPhilippe Mathieu-Daudé if ((NVRAM->model == 2 && addr < 0x078f) ||
361819ce6b2SPhilippe Mathieu-Daudé (NVRAM->model == 8 && addr < 0x1ff8) ||
362819ce6b2SPhilippe Mathieu-Daudé (NVRAM->model == 59 && addr < 0x1ff0)) {
363819ce6b2SPhilippe Mathieu-Daudé goto do_read;
364819ce6b2SPhilippe Mathieu-Daudé }
365819ce6b2SPhilippe Mathieu-Daudé
366819ce6b2SPhilippe Mathieu-Daudé /* TOD access */
367819ce6b2SPhilippe Mathieu-Daudé switch (addr) {
368819ce6b2SPhilippe Mathieu-Daudé case 0x1FF0:
369819ce6b2SPhilippe Mathieu-Daudé /* flags register */
370819ce6b2SPhilippe Mathieu-Daudé goto do_read;
371819ce6b2SPhilippe Mathieu-Daudé case 0x1FF1:
372819ce6b2SPhilippe Mathieu-Daudé /* unused */
373819ce6b2SPhilippe Mathieu-Daudé retval = 0;
374819ce6b2SPhilippe Mathieu-Daudé break;
375819ce6b2SPhilippe Mathieu-Daudé case 0x1FF2:
376819ce6b2SPhilippe Mathieu-Daudé /* alarm seconds */
377819ce6b2SPhilippe Mathieu-Daudé goto do_read;
378819ce6b2SPhilippe Mathieu-Daudé case 0x1FF3:
379819ce6b2SPhilippe Mathieu-Daudé /* alarm minutes */
380819ce6b2SPhilippe Mathieu-Daudé goto do_read;
381819ce6b2SPhilippe Mathieu-Daudé case 0x1FF4:
382819ce6b2SPhilippe Mathieu-Daudé /* alarm hours */
383819ce6b2SPhilippe Mathieu-Daudé goto do_read;
384819ce6b2SPhilippe Mathieu-Daudé case 0x1FF5:
385819ce6b2SPhilippe Mathieu-Daudé /* alarm date */
386819ce6b2SPhilippe Mathieu-Daudé goto do_read;
387819ce6b2SPhilippe Mathieu-Daudé case 0x1FF6:
388819ce6b2SPhilippe Mathieu-Daudé /* interrupts */
389819ce6b2SPhilippe Mathieu-Daudé goto do_read;
390819ce6b2SPhilippe Mathieu-Daudé case 0x1FF7:
391819ce6b2SPhilippe Mathieu-Daudé /* A read resets the watchdog */
392819ce6b2SPhilippe Mathieu-Daudé set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
393819ce6b2SPhilippe Mathieu-Daudé goto do_read;
394819ce6b2SPhilippe Mathieu-Daudé case 0x1FF8:
395819ce6b2SPhilippe Mathieu-Daudé case 0x07F8:
396819ce6b2SPhilippe Mathieu-Daudé /* control */
397819ce6b2SPhilippe Mathieu-Daudé goto do_read;
398819ce6b2SPhilippe Mathieu-Daudé case 0x1FF9:
399819ce6b2SPhilippe Mathieu-Daudé case 0x07F9:
400819ce6b2SPhilippe Mathieu-Daudé /* seconds (BCD) */
401819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
402819ce6b2SPhilippe Mathieu-Daudé retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
403819ce6b2SPhilippe Mathieu-Daudé break;
404819ce6b2SPhilippe Mathieu-Daudé case 0x1FFA:
405819ce6b2SPhilippe Mathieu-Daudé case 0x07FA:
406819ce6b2SPhilippe Mathieu-Daudé /* minutes (BCD) */
407819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
408819ce6b2SPhilippe Mathieu-Daudé retval = to_bcd(tm.tm_min);
409819ce6b2SPhilippe Mathieu-Daudé break;
410819ce6b2SPhilippe Mathieu-Daudé case 0x1FFB:
411819ce6b2SPhilippe Mathieu-Daudé case 0x07FB:
412819ce6b2SPhilippe Mathieu-Daudé /* hours (BCD) */
413819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
414819ce6b2SPhilippe Mathieu-Daudé retval = to_bcd(tm.tm_hour);
415819ce6b2SPhilippe Mathieu-Daudé break;
416819ce6b2SPhilippe Mathieu-Daudé case 0x1FFC:
417819ce6b2SPhilippe Mathieu-Daudé case 0x07FC:
418819ce6b2SPhilippe Mathieu-Daudé /* day of the week / century */
419819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
420819ce6b2SPhilippe Mathieu-Daudé retval = NVRAM->buffer[addr] | tm.tm_wday;
421819ce6b2SPhilippe Mathieu-Daudé break;
422819ce6b2SPhilippe Mathieu-Daudé case 0x1FFD:
423819ce6b2SPhilippe Mathieu-Daudé case 0x07FD:
424819ce6b2SPhilippe Mathieu-Daudé /* date */
425819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
426819ce6b2SPhilippe Mathieu-Daudé retval = to_bcd(tm.tm_mday);
427819ce6b2SPhilippe Mathieu-Daudé break;
428819ce6b2SPhilippe Mathieu-Daudé case 0x1FFE:
429819ce6b2SPhilippe Mathieu-Daudé case 0x07FE:
430819ce6b2SPhilippe Mathieu-Daudé /* month */
431819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
432819ce6b2SPhilippe Mathieu-Daudé retval = to_bcd(tm.tm_mon + 1);
433819ce6b2SPhilippe Mathieu-Daudé break;
434819ce6b2SPhilippe Mathieu-Daudé case 0x1FFF:
435819ce6b2SPhilippe Mathieu-Daudé case 0x07FF:
436819ce6b2SPhilippe Mathieu-Daudé /* year */
437819ce6b2SPhilippe Mathieu-Daudé get_time(NVRAM, &tm);
438819ce6b2SPhilippe Mathieu-Daudé retval = to_bcd((tm.tm_year + 1900 - NVRAM->base_year) % 100);
439819ce6b2SPhilippe Mathieu-Daudé break;
440819ce6b2SPhilippe Mathieu-Daudé default:
441819ce6b2SPhilippe Mathieu-Daudé /* Check lock registers state */
442819ce6b2SPhilippe Mathieu-Daudé if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
443819ce6b2SPhilippe Mathieu-Daudé break;
444819ce6b2SPhilippe Mathieu-Daudé if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
445819ce6b2SPhilippe Mathieu-Daudé break;
446819ce6b2SPhilippe Mathieu-Daudé do_read:
447819ce6b2SPhilippe Mathieu-Daudé if (addr < NVRAM->size) {
448819ce6b2SPhilippe Mathieu-Daudé retval = NVRAM->buffer[addr];
449819ce6b2SPhilippe Mathieu-Daudé }
450819ce6b2SPhilippe Mathieu-Daudé break;
451819ce6b2SPhilippe Mathieu-Daudé }
452e21d73ecSPhilippe Mathieu-Daudé trace_m48txx_nvram_mem_read(addr, retval);
453819ce6b2SPhilippe Mathieu-Daudé
454819ce6b2SPhilippe Mathieu-Daudé return retval;
455819ce6b2SPhilippe Mathieu-Daudé }
456819ce6b2SPhilippe Mathieu-Daudé
457819ce6b2SPhilippe Mathieu-Daudé /* IO access to NVRAM */
NVRAM_writeb(void * opaque,hwaddr addr,uint64_t val,unsigned size)458819ce6b2SPhilippe Mathieu-Daudé static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val,
459819ce6b2SPhilippe Mathieu-Daudé unsigned size)
460819ce6b2SPhilippe Mathieu-Daudé {
461819ce6b2SPhilippe Mathieu-Daudé M48t59State *NVRAM = opaque;
462819ce6b2SPhilippe Mathieu-Daudé
463e21d73ecSPhilippe Mathieu-Daudé trace_m48txx_nvram_io_write(addr, val);
464819ce6b2SPhilippe Mathieu-Daudé switch (addr) {
465819ce6b2SPhilippe Mathieu-Daudé case 0:
466819ce6b2SPhilippe Mathieu-Daudé NVRAM->addr &= ~0x00FF;
467819ce6b2SPhilippe Mathieu-Daudé NVRAM->addr |= val;
468819ce6b2SPhilippe Mathieu-Daudé break;
469819ce6b2SPhilippe Mathieu-Daudé case 1:
470819ce6b2SPhilippe Mathieu-Daudé NVRAM->addr &= ~0xFF00;
471819ce6b2SPhilippe Mathieu-Daudé NVRAM->addr |= val << 8;
472819ce6b2SPhilippe Mathieu-Daudé break;
473819ce6b2SPhilippe Mathieu-Daudé case 3:
474819ce6b2SPhilippe Mathieu-Daudé m48t59_write(NVRAM, NVRAM->addr, val);
475819ce6b2SPhilippe Mathieu-Daudé NVRAM->addr = 0x0000;
476819ce6b2SPhilippe Mathieu-Daudé break;
477819ce6b2SPhilippe Mathieu-Daudé default:
478819ce6b2SPhilippe Mathieu-Daudé break;
479819ce6b2SPhilippe Mathieu-Daudé }
480819ce6b2SPhilippe Mathieu-Daudé }
481819ce6b2SPhilippe Mathieu-Daudé
NVRAM_readb(void * opaque,hwaddr addr,unsigned size)482819ce6b2SPhilippe Mathieu-Daudé static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size)
483819ce6b2SPhilippe Mathieu-Daudé {
484819ce6b2SPhilippe Mathieu-Daudé M48t59State *NVRAM = opaque;
485819ce6b2SPhilippe Mathieu-Daudé uint32_t retval;
486819ce6b2SPhilippe Mathieu-Daudé
487819ce6b2SPhilippe Mathieu-Daudé switch (addr) {
488819ce6b2SPhilippe Mathieu-Daudé case 3:
489819ce6b2SPhilippe Mathieu-Daudé retval = m48t59_read(NVRAM, NVRAM->addr);
490819ce6b2SPhilippe Mathieu-Daudé break;
491819ce6b2SPhilippe Mathieu-Daudé default:
492819ce6b2SPhilippe Mathieu-Daudé retval = -1;
493819ce6b2SPhilippe Mathieu-Daudé break;
494819ce6b2SPhilippe Mathieu-Daudé }
495e21d73ecSPhilippe Mathieu-Daudé trace_m48txx_nvram_io_read(addr, retval);
496819ce6b2SPhilippe Mathieu-Daudé
497819ce6b2SPhilippe Mathieu-Daudé return retval;
498819ce6b2SPhilippe Mathieu-Daudé }
499819ce6b2SPhilippe Mathieu-Daudé
nvram_read(void * opaque,hwaddr addr,unsigned size)500819ce6b2SPhilippe Mathieu-Daudé static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size)
501819ce6b2SPhilippe Mathieu-Daudé {
502819ce6b2SPhilippe Mathieu-Daudé M48t59State *NVRAM = opaque;
503819ce6b2SPhilippe Mathieu-Daudé
504819ce6b2SPhilippe Mathieu-Daudé return m48t59_read(NVRAM, addr);
505819ce6b2SPhilippe Mathieu-Daudé }
506819ce6b2SPhilippe Mathieu-Daudé
nvram_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)507819ce6b2SPhilippe Mathieu-Daudé static void nvram_write(void *opaque, hwaddr addr, uint64_t value,
508819ce6b2SPhilippe Mathieu-Daudé unsigned size)
509819ce6b2SPhilippe Mathieu-Daudé {
510819ce6b2SPhilippe Mathieu-Daudé M48t59State *NVRAM = opaque;
511819ce6b2SPhilippe Mathieu-Daudé
512819ce6b2SPhilippe Mathieu-Daudé return m48t59_write(NVRAM, addr, value);
513819ce6b2SPhilippe Mathieu-Daudé }
514819ce6b2SPhilippe Mathieu-Daudé
515819ce6b2SPhilippe Mathieu-Daudé static const MemoryRegionOps nvram_ops = {
516819ce6b2SPhilippe Mathieu-Daudé .read = nvram_read,
517819ce6b2SPhilippe Mathieu-Daudé .write = nvram_write,
518819ce6b2SPhilippe Mathieu-Daudé .impl.min_access_size = 1,
519819ce6b2SPhilippe Mathieu-Daudé .impl.max_access_size = 1,
520819ce6b2SPhilippe Mathieu-Daudé .valid.min_access_size = 1,
521819ce6b2SPhilippe Mathieu-Daudé .valid.max_access_size = 4,
522819ce6b2SPhilippe Mathieu-Daudé .endianness = DEVICE_BIG_ENDIAN,
523819ce6b2SPhilippe Mathieu-Daudé };
524819ce6b2SPhilippe Mathieu-Daudé
525819ce6b2SPhilippe Mathieu-Daudé static const VMStateDescription vmstate_m48t59 = {
526819ce6b2SPhilippe Mathieu-Daudé .name = "m48t59",
527819ce6b2SPhilippe Mathieu-Daudé .version_id = 1,
528819ce6b2SPhilippe Mathieu-Daudé .minimum_version_id = 1,
529a80cc662SRichard Henderson .fields = (const VMStateField[]) {
530819ce6b2SPhilippe Mathieu-Daudé VMSTATE_UINT8(lock, M48t59State),
531819ce6b2SPhilippe Mathieu-Daudé VMSTATE_UINT16(addr, M48t59State),
532819ce6b2SPhilippe Mathieu-Daudé VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, size),
533819ce6b2SPhilippe Mathieu-Daudé VMSTATE_END_OF_LIST()
534819ce6b2SPhilippe Mathieu-Daudé }
535819ce6b2SPhilippe Mathieu-Daudé };
536819ce6b2SPhilippe Mathieu-Daudé
m48t59_reset_common(M48t59State * NVRAM)537819ce6b2SPhilippe Mathieu-Daudé void m48t59_reset_common(M48t59State *NVRAM)
538819ce6b2SPhilippe Mathieu-Daudé {
539819ce6b2SPhilippe Mathieu-Daudé NVRAM->addr = 0;
540819ce6b2SPhilippe Mathieu-Daudé NVRAM->lock = 0;
541819ce6b2SPhilippe Mathieu-Daudé if (NVRAM->alrm_timer != NULL)
542819ce6b2SPhilippe Mathieu-Daudé timer_del(NVRAM->alrm_timer);
543819ce6b2SPhilippe Mathieu-Daudé
544819ce6b2SPhilippe Mathieu-Daudé if (NVRAM->wd_timer != NULL)
545819ce6b2SPhilippe Mathieu-Daudé timer_del(NVRAM->wd_timer);
546819ce6b2SPhilippe Mathieu-Daudé }
547819ce6b2SPhilippe Mathieu-Daudé
m48t59_reset_sysbus(DeviceState * d)548819ce6b2SPhilippe Mathieu-Daudé static void m48t59_reset_sysbus(DeviceState *d)
549819ce6b2SPhilippe Mathieu-Daudé {
550819ce6b2SPhilippe Mathieu-Daudé M48txxSysBusState *sys = M48TXX_SYS_BUS(d);
551819ce6b2SPhilippe Mathieu-Daudé M48t59State *NVRAM = &sys->state;
552819ce6b2SPhilippe Mathieu-Daudé
553819ce6b2SPhilippe Mathieu-Daudé m48t59_reset_common(NVRAM);
554819ce6b2SPhilippe Mathieu-Daudé }
555819ce6b2SPhilippe Mathieu-Daudé
556819ce6b2SPhilippe Mathieu-Daudé const MemoryRegionOps m48t59_io_ops = {
557819ce6b2SPhilippe Mathieu-Daudé .read = NVRAM_readb,
558819ce6b2SPhilippe Mathieu-Daudé .write = NVRAM_writeb,
559819ce6b2SPhilippe Mathieu-Daudé .impl = {
560819ce6b2SPhilippe Mathieu-Daudé .min_access_size = 1,
561819ce6b2SPhilippe Mathieu-Daudé .max_access_size = 1,
562819ce6b2SPhilippe Mathieu-Daudé },
563819ce6b2SPhilippe Mathieu-Daudé .endianness = DEVICE_LITTLE_ENDIAN,
564819ce6b2SPhilippe Mathieu-Daudé };
565819ce6b2SPhilippe Mathieu-Daudé
m48t59_realize_common(M48t59State * s,Error ** errp)566819ce6b2SPhilippe Mathieu-Daudé void m48t59_realize_common(M48t59State *s, Error **errp)
567819ce6b2SPhilippe Mathieu-Daudé {
568819ce6b2SPhilippe Mathieu-Daudé s->buffer = g_malloc0(s->size);
569819ce6b2SPhilippe Mathieu-Daudé if (s->model == 59) {
570819ce6b2SPhilippe Mathieu-Daudé s->alrm_timer = timer_new_ns(rtc_clock, &alarm_cb, s);
571819ce6b2SPhilippe Mathieu-Daudé s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s);
572819ce6b2SPhilippe Mathieu-Daudé }
573819ce6b2SPhilippe Mathieu-Daudé qemu_get_timedate(&s->alarm, 0);
574819ce6b2SPhilippe Mathieu-Daudé }
575819ce6b2SPhilippe Mathieu-Daudé
m48t59_init1(Object * obj)576819ce6b2SPhilippe Mathieu-Daudé static void m48t59_init1(Object *obj)
577819ce6b2SPhilippe Mathieu-Daudé {
578819ce6b2SPhilippe Mathieu-Daudé M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(obj);
579819ce6b2SPhilippe Mathieu-Daudé M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
580819ce6b2SPhilippe Mathieu-Daudé SysBusDevice *dev = SYS_BUS_DEVICE(obj);
581819ce6b2SPhilippe Mathieu-Daudé M48t59State *s = &d->state;
582819ce6b2SPhilippe Mathieu-Daudé
583819ce6b2SPhilippe Mathieu-Daudé s->model = u->info.model;
584819ce6b2SPhilippe Mathieu-Daudé s->size = u->info.size;
585819ce6b2SPhilippe Mathieu-Daudé sysbus_init_irq(dev, &s->IRQ);
586819ce6b2SPhilippe Mathieu-Daudé
587819ce6b2SPhilippe Mathieu-Daudé memory_region_init_io(&s->iomem, obj, &nvram_ops, s, "m48t59.nvram",
588819ce6b2SPhilippe Mathieu-Daudé s->size);
589819ce6b2SPhilippe Mathieu-Daudé memory_region_init_io(&d->io, obj, &m48t59_io_ops, s, "m48t59", 4);
590819ce6b2SPhilippe Mathieu-Daudé }
591819ce6b2SPhilippe Mathieu-Daudé
m48t59_realize(DeviceState * dev,Error ** errp)592819ce6b2SPhilippe Mathieu-Daudé static void m48t59_realize(DeviceState *dev, Error **errp)
593819ce6b2SPhilippe Mathieu-Daudé {
594819ce6b2SPhilippe Mathieu-Daudé M48txxSysBusState *d = M48TXX_SYS_BUS(dev);
595819ce6b2SPhilippe Mathieu-Daudé M48t59State *s = &d->state;
596819ce6b2SPhilippe Mathieu-Daudé SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
597819ce6b2SPhilippe Mathieu-Daudé
598819ce6b2SPhilippe Mathieu-Daudé sysbus_init_mmio(sbd, &s->iomem);
599819ce6b2SPhilippe Mathieu-Daudé sysbus_init_mmio(sbd, &d->io);
600819ce6b2SPhilippe Mathieu-Daudé m48t59_realize_common(s, errp);
601819ce6b2SPhilippe Mathieu-Daudé }
602819ce6b2SPhilippe Mathieu-Daudé
m48txx_sysbus_read(Nvram * obj,uint32_t addr)603819ce6b2SPhilippe Mathieu-Daudé static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr)
604819ce6b2SPhilippe Mathieu-Daudé {
605819ce6b2SPhilippe Mathieu-Daudé M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
606819ce6b2SPhilippe Mathieu-Daudé return m48t59_read(&d->state, addr);
607819ce6b2SPhilippe Mathieu-Daudé }
608819ce6b2SPhilippe Mathieu-Daudé
m48txx_sysbus_write(Nvram * obj,uint32_t addr,uint32_t val)609819ce6b2SPhilippe Mathieu-Daudé static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val)
610819ce6b2SPhilippe Mathieu-Daudé {
611819ce6b2SPhilippe Mathieu-Daudé M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
612819ce6b2SPhilippe Mathieu-Daudé m48t59_write(&d->state, addr, val);
613819ce6b2SPhilippe Mathieu-Daudé }
614819ce6b2SPhilippe Mathieu-Daudé
m48txx_sysbus_toggle_lock(Nvram * obj,int lock)615819ce6b2SPhilippe Mathieu-Daudé static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock)
616819ce6b2SPhilippe Mathieu-Daudé {
617819ce6b2SPhilippe Mathieu-Daudé M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
618819ce6b2SPhilippe Mathieu-Daudé m48t59_toggle_lock(&d->state, lock);
619819ce6b2SPhilippe Mathieu-Daudé }
620819ce6b2SPhilippe Mathieu-Daudé
621819ce6b2SPhilippe Mathieu-Daudé static Property m48t59_sysbus_properties[] = {
622819ce6b2SPhilippe Mathieu-Daudé DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
623819ce6b2SPhilippe Mathieu-Daudé DEFINE_PROP_END_OF_LIST(),
624819ce6b2SPhilippe Mathieu-Daudé };
625819ce6b2SPhilippe Mathieu-Daudé
m48txx_sysbus_class_init(ObjectClass * klass,void * data)626819ce6b2SPhilippe Mathieu-Daudé static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
627819ce6b2SPhilippe Mathieu-Daudé {
628819ce6b2SPhilippe Mathieu-Daudé DeviceClass *dc = DEVICE_CLASS(klass);
629819ce6b2SPhilippe Mathieu-Daudé NvramClass *nc = NVRAM_CLASS(klass);
630819ce6b2SPhilippe Mathieu-Daudé
631819ce6b2SPhilippe Mathieu-Daudé dc->realize = m48t59_realize;
632*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, m48t59_reset_sysbus);
6334f67d30bSMarc-André Lureau device_class_set_props(dc, m48t59_sysbus_properties);
634819ce6b2SPhilippe Mathieu-Daudé dc->vmsd = &vmstate_m48t59;
635819ce6b2SPhilippe Mathieu-Daudé nc->read = m48txx_sysbus_read;
636819ce6b2SPhilippe Mathieu-Daudé nc->write = m48txx_sysbus_write;
637819ce6b2SPhilippe Mathieu-Daudé nc->toggle_lock = m48txx_sysbus_toggle_lock;
638819ce6b2SPhilippe Mathieu-Daudé }
639819ce6b2SPhilippe Mathieu-Daudé
m48txx_sysbus_concrete_class_init(ObjectClass * klass,void * data)640819ce6b2SPhilippe Mathieu-Daudé static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
641819ce6b2SPhilippe Mathieu-Daudé {
642819ce6b2SPhilippe Mathieu-Daudé M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
643819ce6b2SPhilippe Mathieu-Daudé M48txxInfo *info = data;
644819ce6b2SPhilippe Mathieu-Daudé
645819ce6b2SPhilippe Mathieu-Daudé u->info = *info;
646819ce6b2SPhilippe Mathieu-Daudé }
647819ce6b2SPhilippe Mathieu-Daudé
648819ce6b2SPhilippe Mathieu-Daudé static const TypeInfo nvram_info = {
649819ce6b2SPhilippe Mathieu-Daudé .name = TYPE_NVRAM,
650819ce6b2SPhilippe Mathieu-Daudé .parent = TYPE_INTERFACE,
651819ce6b2SPhilippe Mathieu-Daudé .class_size = sizeof(NvramClass),
652819ce6b2SPhilippe Mathieu-Daudé };
653819ce6b2SPhilippe Mathieu-Daudé
654819ce6b2SPhilippe Mathieu-Daudé static const TypeInfo m48txx_sysbus_type_info = {
655819ce6b2SPhilippe Mathieu-Daudé .name = TYPE_M48TXX_SYS_BUS,
656819ce6b2SPhilippe Mathieu-Daudé .parent = TYPE_SYS_BUS_DEVICE,
657819ce6b2SPhilippe Mathieu-Daudé .instance_size = sizeof(M48txxSysBusState),
658819ce6b2SPhilippe Mathieu-Daudé .instance_init = m48t59_init1,
659819ce6b2SPhilippe Mathieu-Daudé .abstract = true,
660819ce6b2SPhilippe Mathieu-Daudé .class_init = m48txx_sysbus_class_init,
661819ce6b2SPhilippe Mathieu-Daudé .interfaces = (InterfaceInfo[]) {
662819ce6b2SPhilippe Mathieu-Daudé { TYPE_NVRAM },
663819ce6b2SPhilippe Mathieu-Daudé { }
664819ce6b2SPhilippe Mathieu-Daudé }
665819ce6b2SPhilippe Mathieu-Daudé };
666819ce6b2SPhilippe Mathieu-Daudé
m48t59_register_types(void)667819ce6b2SPhilippe Mathieu-Daudé static void m48t59_register_types(void)
668819ce6b2SPhilippe Mathieu-Daudé {
669819ce6b2SPhilippe Mathieu-Daudé TypeInfo sysbus_type_info = {
670819ce6b2SPhilippe Mathieu-Daudé .parent = TYPE_M48TXX_SYS_BUS,
671819ce6b2SPhilippe Mathieu-Daudé .class_size = sizeof(M48txxSysBusDeviceClass),
672819ce6b2SPhilippe Mathieu-Daudé .class_init = m48txx_sysbus_concrete_class_init,
673819ce6b2SPhilippe Mathieu-Daudé };
674819ce6b2SPhilippe Mathieu-Daudé int i;
675819ce6b2SPhilippe Mathieu-Daudé
676819ce6b2SPhilippe Mathieu-Daudé type_register_static(&nvram_info);
677819ce6b2SPhilippe Mathieu-Daudé type_register_static(&m48txx_sysbus_type_info);
678819ce6b2SPhilippe Mathieu-Daudé
679819ce6b2SPhilippe Mathieu-Daudé for (i = 0; i < ARRAY_SIZE(m48txx_sysbus_info); i++) {
680819ce6b2SPhilippe Mathieu-Daudé sysbus_type_info.name = m48txx_sysbus_info[i].bus_name;
681819ce6b2SPhilippe Mathieu-Daudé sysbus_type_info.class_data = &m48txx_sysbus_info[i];
682819ce6b2SPhilippe Mathieu-Daudé type_register(&sysbus_type_info);
683819ce6b2SPhilippe Mathieu-Daudé }
684819ce6b2SPhilippe Mathieu-Daudé }
685819ce6b2SPhilippe Mathieu-Daudé
686819ce6b2SPhilippe Mathieu-Daudé type_init(m48t59_register_types)
687