]> git.ipfire.org Git - thirdparty/qemu.git/blame - hw/rtc/m48t59.c
Move QOM typedefs and add missing includes
[thirdparty/qemu.git] / hw / rtc / m48t59.c
CommitLineData
a541f297 1/*
819385c5 2 * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
5fafdf24 3 *
cf83f140 4 * Copyright (c) 2003-2005, 2007, 2017 Jocelyn Mayer
051ddccd 5 * Copyright (c) 2013 Hervé Poussineau
5fafdf24 6 *
a541f297
FB
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
0b8fa32f 25
282bc81e 26#include "qemu/osdep.h"
a8d25326 27#include "qemu-common.h"
64552b6b 28#include "hw/irq.h"
a27bd6c7 29#include "hw/qdev-properties.h"
819ce6b2 30#include "hw/rtc/m48t59.h"
1de7afc9 31#include "qemu/timer.h"
54d31236 32#include "sysemu/runstate.h"
9c17d615 33#include "sysemu/sysemu.h"
83c9f4ca 34#include "hw/sysbus.h"
022c62cb 35#include "exec/address-spaces.h"
3e80f690 36#include "qapi/error.h"
f348b6d1 37#include "qemu/bcd.h"
0b8fa32f 38#include "qemu/module.h"
e21d73ec 39#include "trace.h"
a541f297 40
c124c4d1 41#include "m48t59-internal.h"
d6454270 42#include "migration/vmstate.h"
db1015e9 43#include "qom/object.h"
a541f297 44
051ddccd 45#define TYPE_M48TXX_SYS_BUS "sysbus-m48txx"
db1015e9
EH
46typedef struct M48txxSysBusDeviceClass M48txxSysBusDeviceClass;
47typedef struct M48txxSysBusState M48txxSysBusState;
051ddccd
HP
48#define M48TXX_SYS_BUS_GET_CLASS(obj) \
49 OBJECT_GET_CLASS(M48txxSysBusDeviceClass, (obj), TYPE_M48TXX_SYS_BUS)
50#define M48TXX_SYS_BUS_CLASS(klass) \
51 OBJECT_CLASS_CHECK(M48txxSysBusDeviceClass, (klass), TYPE_M48TXX_SYS_BUS)
52#define M48TXX_SYS_BUS(obj) \
53 OBJECT_CHECK(M48txxSysBusState, (obj), TYPE_M48TXX_SYS_BUS)
54
930f3fe1
BS
55/*
56 * Chipset docs:
57 * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
58 * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
59 * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
60 */
61
db1015e9 62struct M48txxSysBusState {
29d1ffc3 63 SysBusDevice parent_obj;
43a34704 64 M48t59State state;
087bd055 65 MemoryRegion io;
db1015e9 66};
051ddccd 67
db1015e9 68struct M48txxSysBusDeviceClass {
051ddccd
HP
69 SysBusDeviceClass parent_class;
70 M48txxInfo info;
db1015e9 71};
051ddccd 72
c124c4d1 73static M48txxInfo m48txx_sysbus_info[] = {
051ddccd 74 {
c124c4d1 75 .bus_name = "sysbus-m48t02",
051ddccd
HP
76 .model = 2,
77 .size = 0x800,
78 },{
c124c4d1 79 .bus_name = "sysbus-m48t08",
051ddccd
HP
80 .model = 8,
81 .size = 0x2000,
0278377d 82 },{
c124c4d1 83 .bus_name = "sysbus-m48t59",
051ddccd
HP
84 .model = 59,
85 .size = 0x2000,
86 }
87};
88
f80237d4 89
a541f297 90/* Fake timer functions */
a541f297 91
a541f297
FB
92/* Alarm management */
93static void alarm_cb (void *opaque)
94{
f6503059 95 struct tm tm;
a541f297 96 uint64_t next_time;
43a34704 97 M48t59State *NVRAM = opaque;
a541f297 98
d537cf6c 99 qemu_set_irq(NVRAM->IRQ, 1);
5fafdf24 100 if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
a541f297
FB
101 (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
102 (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
103 (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
f6503059
AZ
104 /* Repeat once a month */
105 qemu_get_timedate(&tm, NVRAM->time_offset);
106 tm.tm_mon++;
107 if (tm.tm_mon == 13) {
108 tm.tm_mon = 1;
109 tm.tm_year++;
110 }
111 next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
a541f297
FB
112 } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
113 (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
114 (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
115 (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
f6503059
AZ
116 /* Repeat once a day */
117 next_time = 24 * 60 * 60;
a541f297
FB
118 } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
119 (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
120 (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
121 (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
f6503059
AZ
122 /* Repeat once an hour */
123 next_time = 60 * 60;
a541f297
FB
124 } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
125 (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
126 (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
127 (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
f6503059
AZ
128 /* Repeat once a minute */
129 next_time = 60;
a541f297 130 } else {
f6503059
AZ
131 /* Repeat once a second */
132 next_time = 1;
a541f297 133 }
bc72ad67 134 timer_mod(NVRAM->alrm_timer, qemu_clock_get_ns(rtc_clock) +
f6503059 135 next_time * 1000);
d537cf6c 136 qemu_set_irq(NVRAM->IRQ, 0);
a541f297
FB
137}
138
43a34704 139static void set_alarm(M48t59State *NVRAM)
f6503059
AZ
140{
141 int diff;
142 if (NVRAM->alrm_timer != NULL) {
bc72ad67 143 timer_del(NVRAM->alrm_timer);
f6503059
AZ
144 diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
145 if (diff > 0)
bc72ad67 146 timer_mod(NVRAM->alrm_timer, diff * 1000);
f6503059
AZ
147 }
148}
a541f297 149
f6503059 150/* RTC management helpers */
43a34704 151static inline void get_time(M48t59State *NVRAM, struct tm *tm)
a541f297 152{
f6503059 153 qemu_get_timedate(tm, NVRAM->time_offset);
a541f297
FB
154}
155
43a34704 156static void set_time(M48t59State *NVRAM, struct tm *tm)
a541f297 157{
f6503059
AZ
158 NVRAM->time_offset = qemu_timedate_diff(tm);
159 set_alarm(NVRAM);
a541f297
FB
160}
161
162/* Watchdog management */
163static void watchdog_cb (void *opaque)
164{
43a34704 165 M48t59State *NVRAM = opaque;
a541f297
FB
166
167 NVRAM->buffer[0x1FF0] |= 0x80;
168 if (NVRAM->buffer[0x1FF7] & 0x80) {
169 NVRAM->buffer[0x1FF7] = 0x00;
170 NVRAM->buffer[0x1FFC] &= ~0x40;
13ab5daa 171 /* May it be a hw CPU Reset instead ? */
cf83f140 172 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
a541f297 173 } else {
d537cf6c
PB
174 qemu_set_irq(NVRAM->IRQ, 1);
175 qemu_set_irq(NVRAM->IRQ, 0);
a541f297
FB
176 }
177}
178
43a34704 179static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
a541f297
FB
180{
181 uint64_t interval; /* in 1/16 seconds */
182
868d585a 183 NVRAM->buffer[0x1FF0] &= ~0x80;
a541f297 184 if (NVRAM->wd_timer != NULL) {
bc72ad67 185 timer_del(NVRAM->wd_timer);
868d585a
JM
186 if (value != 0) {
187 interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
bc72ad67 188 timer_mod(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
868d585a
JM
189 ((interval * 1000) >> 4));
190 }
a541f297
FB
191 }
192}
193
194/* Direct access to NVRAM */
c124c4d1 195void m48t59_write(M48t59State *NVRAM, uint32_t addr, uint32_t val)
a541f297 196{
a541f297
FB
197 struct tm tm;
198 int tmp;
199
e21d73ec 200 trace_m48txx_nvram_mem_write(addr, val);
4aed2c33
BS
201
202 /* check for NVRAM access */
7bc3018b
PB
203 if ((NVRAM->model == 2 && addr < 0x7f8) ||
204 (NVRAM->model == 8 && addr < 0x1ff8) ||
205 (NVRAM->model == 59 && addr < 0x1ff0)) {
819385c5 206 goto do_write;
7bc3018b 207 }
4aed2c33
BS
208
209 /* TOD access */
819385c5 210 switch (addr) {
a541f297
FB
211 case 0x1FF0:
212 /* flags register : read-only */
213 break;
214 case 0x1FF1:
215 /* unused */
216 break;
217 case 0x1FF2:
218 /* alarm seconds */
abd0c6bd 219 tmp = from_bcd(val & 0x7F);
819385c5 220 if (tmp >= 0 && tmp <= 59) {
f6503059 221 NVRAM->alarm.tm_sec = tmp;
819385c5 222 NVRAM->buffer[0x1FF2] = val;
f6503059 223 set_alarm(NVRAM);
819385c5 224 }
a541f297
FB
225 break;
226 case 0x1FF3:
227 /* alarm minutes */
abd0c6bd 228 tmp = from_bcd(val & 0x7F);
819385c5 229 if (tmp >= 0 && tmp <= 59) {
f6503059 230 NVRAM->alarm.tm_min = tmp;
819385c5 231 NVRAM->buffer[0x1FF3] = val;
f6503059 232 set_alarm(NVRAM);
819385c5 233 }
a541f297
FB
234 break;
235 case 0x1FF4:
236 /* alarm hours */
abd0c6bd 237 tmp = from_bcd(val & 0x3F);
819385c5 238 if (tmp >= 0 && tmp <= 23) {
f6503059 239 NVRAM->alarm.tm_hour = tmp;
819385c5 240 NVRAM->buffer[0x1FF4] = val;
f6503059 241 set_alarm(NVRAM);
819385c5 242 }
a541f297
FB
243 break;
244 case 0x1FF5:
245 /* alarm date */
02f5da11 246 tmp = from_bcd(val & 0x3F);
819385c5 247 if (tmp != 0) {
f6503059 248 NVRAM->alarm.tm_mday = tmp;
819385c5 249 NVRAM->buffer[0x1FF5] = val;
f6503059 250 set_alarm(NVRAM);
819385c5 251 }
a541f297
FB
252 break;
253 case 0x1FF6:
254 /* interrupts */
819385c5 255 NVRAM->buffer[0x1FF6] = val;
a541f297
FB
256 break;
257 case 0x1FF7:
258 /* watchdog */
819385c5
FB
259 NVRAM->buffer[0x1FF7] = val;
260 set_up_watchdog(NVRAM, val);
a541f297
FB
261 break;
262 case 0x1FF8:
4aed2c33 263 case 0x07F8:
a541f297 264 /* control */
4aed2c33 265 NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
a541f297
FB
266 break;
267 case 0x1FF9:
4aed2c33 268 case 0x07F9:
a541f297 269 /* seconds (BCD) */
abd0c6bd 270 tmp = from_bcd(val & 0x7F);
a541f297
FB
271 if (tmp >= 0 && tmp <= 59) {
272 get_time(NVRAM, &tm);
273 tm.tm_sec = tmp;
274 set_time(NVRAM, &tm);
275 }
f6503059 276 if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
a541f297
FB
277 if (val & 0x80) {
278 NVRAM->stop_time = time(NULL);
279 } else {
280 NVRAM->time_offset += NVRAM->stop_time - time(NULL);
281 NVRAM->stop_time = 0;
282 }
283 }
f6503059 284 NVRAM->buffer[addr] = val & 0x80;
a541f297
FB
285 break;
286 case 0x1FFA:
4aed2c33 287 case 0x07FA:
a541f297 288 /* minutes (BCD) */
abd0c6bd 289 tmp = from_bcd(val & 0x7F);
a541f297
FB
290 if (tmp >= 0 && tmp <= 59) {
291 get_time(NVRAM, &tm);
292 tm.tm_min = tmp;
293 set_time(NVRAM, &tm);
294 }
295 break;
296 case 0x1FFB:
4aed2c33 297 case 0x07FB:
a541f297 298 /* hours (BCD) */
abd0c6bd 299 tmp = from_bcd(val & 0x3F);
a541f297
FB
300 if (tmp >= 0 && tmp <= 23) {
301 get_time(NVRAM, &tm);
302 tm.tm_hour = tmp;
303 set_time(NVRAM, &tm);
304 }
305 break;
306 case 0x1FFC:
4aed2c33 307 case 0x07FC:
a541f297 308 /* day of the week / century */
abd0c6bd 309 tmp = from_bcd(val & 0x07);
a541f297
FB
310 get_time(NVRAM, &tm);
311 tm.tm_wday = tmp;
312 set_time(NVRAM, &tm);
4aed2c33 313 NVRAM->buffer[addr] = val & 0x40;
a541f297
FB
314 break;
315 case 0x1FFD:
4aed2c33 316 case 0x07FD:
02f5da11
AT
317 /* date (BCD) */
318 tmp = from_bcd(val & 0x3F);
a541f297
FB
319 if (tmp != 0) {
320 get_time(NVRAM, &tm);
321 tm.tm_mday = tmp;
322 set_time(NVRAM, &tm);
323 }
324 break;
325 case 0x1FFE:
4aed2c33 326 case 0x07FE:
a541f297 327 /* month */
abd0c6bd 328 tmp = from_bcd(val & 0x1F);
a541f297
FB
329 if (tmp >= 1 && tmp <= 12) {
330 get_time(NVRAM, &tm);
331 tm.tm_mon = tmp - 1;
332 set_time(NVRAM, &tm);
333 }
334 break;
335 case 0x1FFF:
4aed2c33 336 case 0x07FF:
a541f297 337 /* year */
abd0c6bd 338 tmp = from_bcd(val);
a541f297
FB
339 if (tmp >= 0 && tmp <= 99) {
340 get_time(NVRAM, &tm);
6de04973 341 tm.tm_year = from_bcd(val) + NVRAM->base_year - 1900;
a541f297
FB
342 set_time(NVRAM, &tm);
343 }
344 break;
345 default:
13ab5daa 346 /* Check lock registers state */
819385c5 347 if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
13ab5daa 348 break;
819385c5 349 if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
13ab5daa 350 break;
819385c5
FB
351 do_write:
352 if (addr < NVRAM->size) {
353 NVRAM->buffer[addr] = val & 0xFF;
a541f297
FB
354 }
355 break;
356 }
357}
358
c124c4d1 359uint32_t m48t59_read(M48t59State *NVRAM, uint32_t addr)
a541f297 360{
a541f297
FB
361 struct tm tm;
362 uint32_t retval = 0xFF;
363
4aed2c33 364 /* check for NVRAM access */
7bc3018b
PB
365 if ((NVRAM->model == 2 && addr < 0x078f) ||
366 (NVRAM->model == 8 && addr < 0x1ff8) ||
367 (NVRAM->model == 59 && addr < 0x1ff0)) {
819385c5 368 goto do_read;
7bc3018b 369 }
4aed2c33
BS
370
371 /* TOD access */
819385c5 372 switch (addr) {
a541f297
FB
373 case 0x1FF0:
374 /* flags register */
375 goto do_read;
376 case 0x1FF1:
377 /* unused */
378 retval = 0;
379 break;
380 case 0x1FF2:
381 /* alarm seconds */
382 goto do_read;
383 case 0x1FF3:
384 /* alarm minutes */
385 goto do_read;
386 case 0x1FF4:
387 /* alarm hours */
388 goto do_read;
389 case 0x1FF5:
390 /* alarm date */
391 goto do_read;
392 case 0x1FF6:
393 /* interrupts */
394 goto do_read;
395 case 0x1FF7:
396 /* A read resets the watchdog */
397 set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
398 goto do_read;
399 case 0x1FF8:
4aed2c33 400 case 0x07F8:
a541f297
FB
401 /* control */
402 goto do_read;
403 case 0x1FF9:
4aed2c33 404 case 0x07F9:
a541f297
FB
405 /* seconds (BCD) */
406 get_time(NVRAM, &tm);
abd0c6bd 407 retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
a541f297
FB
408 break;
409 case 0x1FFA:
4aed2c33 410 case 0x07FA:
a541f297
FB
411 /* minutes (BCD) */
412 get_time(NVRAM, &tm);
abd0c6bd 413 retval = to_bcd(tm.tm_min);
a541f297
FB
414 break;
415 case 0x1FFB:
4aed2c33 416 case 0x07FB:
a541f297
FB
417 /* hours (BCD) */
418 get_time(NVRAM, &tm);
abd0c6bd 419 retval = to_bcd(tm.tm_hour);
a541f297
FB
420 break;
421 case 0x1FFC:
4aed2c33 422 case 0x07FC:
a541f297
FB
423 /* day of the week / century */
424 get_time(NVRAM, &tm);
4aed2c33 425 retval = NVRAM->buffer[addr] | tm.tm_wday;
a541f297
FB
426 break;
427 case 0x1FFD:
4aed2c33 428 case 0x07FD:
a541f297
FB
429 /* date */
430 get_time(NVRAM, &tm);
abd0c6bd 431 retval = to_bcd(tm.tm_mday);
a541f297
FB
432 break;
433 case 0x1FFE:
4aed2c33 434 case 0x07FE:
a541f297
FB
435 /* month */
436 get_time(NVRAM, &tm);
abd0c6bd 437 retval = to_bcd(tm.tm_mon + 1);
a541f297
FB
438 break;
439 case 0x1FFF:
4aed2c33 440 case 0x07FF:
a541f297
FB
441 /* year */
442 get_time(NVRAM, &tm);
6de04973 443 retval = to_bcd((tm.tm_year + 1900 - NVRAM->base_year) % 100);
a541f297
FB
444 break;
445 default:
13ab5daa 446 /* Check lock registers state */
819385c5 447 if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
13ab5daa 448 break;
819385c5 449 if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
13ab5daa 450 break;
819385c5
FB
451 do_read:
452 if (addr < NVRAM->size) {
453 retval = NVRAM->buffer[addr];
a541f297
FB
454 }
455 break;
456 }
e21d73ec 457 trace_m48txx_nvram_mem_read(addr, retval);
a541f297
FB
458
459 return retval;
460}
461
a541f297 462/* IO access to NVRAM */
087bd055
AG
463static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val,
464 unsigned size)
a541f297 465{
43a34704 466 M48t59State *NVRAM = opaque;
a541f297 467
e21d73ec 468 trace_m48txx_nvram_io_write(addr, val);
a541f297
FB
469 switch (addr) {
470 case 0:
471 NVRAM->addr &= ~0x00FF;
472 NVRAM->addr |= val;
473 break;
474 case 1:
475 NVRAM->addr &= ~0xFF00;
476 NVRAM->addr |= val << 8;
477 break;
478 case 3:
b1f88301 479 m48t59_write(NVRAM, NVRAM->addr, val);
a541f297
FB
480 NVRAM->addr = 0x0000;
481 break;
482 default:
483 break;
484 }
485}
486
087bd055 487static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size)
a541f297 488{
43a34704 489 M48t59State *NVRAM = opaque;
13ab5daa 490 uint32_t retval;
a541f297 491
13ab5daa
FB
492 switch (addr) {
493 case 3:
819385c5 494 retval = m48t59_read(NVRAM, NVRAM->addr);
13ab5daa
FB
495 break;
496 default:
497 retval = -1;
498 break;
499 }
e21d73ec 500 trace_m48txx_nvram_io_read(addr, retval);
a541f297 501
13ab5daa 502 return retval;
a541f297
FB
503}
504
62b9cf0a 505static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size)
e1bb04f7 506{
43a34704 507 M48t59State *NVRAM = opaque;
3b46e624 508
bf5f78ef 509 return m48t59_read(NVRAM, addr);
e1bb04f7
FB
510}
511
62b9cf0a
PM
512static void nvram_write(void *opaque, hwaddr addr, uint64_t value,
513 unsigned size)
e1bb04f7 514{
43a34704 515 M48t59State *NVRAM = opaque;
e1bb04f7 516
62b9cf0a 517 return m48t59_write(NVRAM, addr, value);
e1bb04f7
FB
518}
519
5a31cd68 520static const MemoryRegionOps nvram_ops = {
62b9cf0a
PM
521 .read = nvram_read,
522 .write = nvram_write,
523 .impl.min_access_size = 1,
524 .impl.max_access_size = 1,
525 .valid.min_access_size = 1,
526 .valid.max_access_size = 4,
527 .endianness = DEVICE_BIG_ENDIAN,
e1bb04f7 528};
819385c5 529
fd484ae4
JQ
530static const VMStateDescription vmstate_m48t59 = {
531 .name = "m48t59",
532 .version_id = 1,
533 .minimum_version_id = 1,
3aff6c2f 534 .fields = (VMStateField[]) {
fd484ae4
JQ
535 VMSTATE_UINT8(lock, M48t59State),
536 VMSTATE_UINT16(addr, M48t59State),
59046ec2 537 VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, size),
fd484ae4
JQ
538 VMSTATE_END_OF_LIST()
539 }
540};
3ccacc4a 541
c124c4d1 542void m48t59_reset_common(M48t59State *NVRAM)
3ccacc4a 543{
6e6b7363
BS
544 NVRAM->addr = 0;
545 NVRAM->lock = 0;
3ccacc4a 546 if (NVRAM->alrm_timer != NULL)
bc72ad67 547 timer_del(NVRAM->alrm_timer);
3ccacc4a
BS
548
549 if (NVRAM->wd_timer != NULL)
bc72ad67 550 timer_del(NVRAM->wd_timer);
3ccacc4a
BS
551}
552
285e468d
BS
553static void m48t59_reset_sysbus(DeviceState *d)
554{
051ddccd 555 M48txxSysBusState *sys = M48TXX_SYS_BUS(d);
43a34704 556 M48t59State *NVRAM = &sys->state;
285e468d
BS
557
558 m48t59_reset_common(NVRAM);
559}
560
c124c4d1 561const MemoryRegionOps m48t59_io_ops = {
087bd055
AG
562 .read = NVRAM_readb,
563 .write = NVRAM_writeb,
564 .impl = {
565 .min_access_size = 1,
566 .max_access_size = 1,
567 },
568 .endianness = DEVICE_LITTLE_ENDIAN,
9936d6e4
RH
569};
570
a541f297 571/* Initialisation routine */
31688246 572Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
6de04973
MCA
573 uint32_t io_base, uint16_t size, int base_year,
574 int model)
a541f297 575{
d27cf0ae
BS
576 DeviceState *dev;
577 SysBusDevice *s;
051ddccd 578 int i;
d27cf0ae 579
c124c4d1
DG
580 for (i = 0; i < ARRAY_SIZE(m48txx_sysbus_info); i++) {
581 if (m48txx_sysbus_info[i].size != size ||
582 m48txx_sysbus_info[i].model != model) {
051ddccd
HP
583 continue;
584 }
585
3e80f690 586 dev = qdev_new(m48txx_sysbus_info[i].bus_name);
6de04973 587 qdev_prop_set_int32(dev, "base-year", base_year);
051ddccd 588 s = SYS_BUS_DEVICE(dev);
3c6ef471 589 sysbus_realize_and_unref(s, &error_fatal);
051ddccd
HP
590 sysbus_connect_irq(s, 0, IRQ);
591 if (io_base != 0) {
592 memory_region_add_subregion(get_system_io(), io_base,
593 sysbus_mmio_get_region(s, 1));
594 }
595 if (mem_base != 0) {
596 sysbus_mmio_map(s, 0, mem_base);
597 }
598
31688246 599 return NVRAM(s);
e1bb04f7 600 }
d27cf0ae 601
051ddccd
HP
602 assert(false);
603 return NULL;
d27cf0ae
BS
604}
605
c124c4d1 606void m48t59_realize_common(M48t59State *s, Error **errp)
f80237d4 607{
7267c094 608 s->buffer = g_malloc0(s->size);
7bc3018b 609 if (s->model == 59) {
884f17c2 610 s->alrm_timer = timer_new_ns(rtc_clock, &alarm_cb, s);
bc72ad67 611 s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s);
819385c5 612 }
f6503059 613 qemu_get_timedate(&s->alarm, 0);
f80237d4
BS
614}
615
c04e34a9 616static void m48t59_init1(Object *obj)
f80237d4 617{
c04e34a9
XZ
618 M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(obj);
619 M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
620 SysBusDevice *dev = SYS_BUS_DEVICE(obj);
43a34704 621 M48t59State *s = &d->state;
f80237d4 622
051ddccd
HP
623 s->model = u->info.model;
624 s->size = u->info.size;
f80237d4
BS
625 sysbus_init_irq(dev, &s->IRQ);
626
c04e34a9 627 memory_region_init_io(&s->iomem, obj, &nvram_ops, s, "m48t59.nvram",
72cd63f8 628 s->size);
c04e34a9
XZ
629 memory_region_init_io(&d->io, obj, &m48t59_io_ops, s, "m48t59", 4);
630}
631
632static void m48t59_realize(DeviceState *dev, Error **errp)
633{
634 M48txxSysBusState *d = M48TXX_SYS_BUS(dev);
635 M48t59State *s = &d->state;
636 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
f80237d4 637
c04e34a9
XZ
638 sysbus_init_mmio(sbd, &s->iomem);
639 sysbus_init_mmio(sbd, &d->io);
640 m48t59_realize_common(s, errp);
f80237d4
BS
641}
642
43745328
HP
643static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr)
644{
645 M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
646 return m48t59_read(&d->state, addr);
647}
648
649static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val)
650{
651 M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
652 m48t59_write(&d->state, addr, val);
653}
654
655static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock)
656{
657 M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
658 m48t59_toggle_lock(&d->state, lock);
659}
660
6de04973
MCA
661static Property m48t59_sysbus_properties[] = {
662 DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
663 DEFINE_PROP_END_OF_LIST(),
664};
665
051ddccd 666static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
999e12bb 667{
39bffca2 668 DeviceClass *dc = DEVICE_CLASS(klass);
43745328 669 NvramClass *nc = NVRAM_CLASS(klass);
999e12bb 670
c04e34a9 671 dc->realize = m48t59_realize;
39bffca2 672 dc->reset = m48t59_reset_sysbus;
4f67d30b 673 device_class_set_props(dc, m48t59_sysbus_properties);
c04e34a9 674 dc->vmsd = &vmstate_m48t59;
43745328
HP
675 nc->read = m48txx_sysbus_read;
676 nc->write = m48txx_sysbus_write;
677 nc->toggle_lock = m48txx_sysbus_toggle_lock;
999e12bb
AL
678}
679
051ddccd
HP
680static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
681{
682 M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
683 M48txxInfo *info = data;
684
685 u->info = *info;
686}
687
43745328
HP
688static const TypeInfo nvram_info = {
689 .name = TYPE_NVRAM,
690 .parent = TYPE_INTERFACE,
691 .class_size = sizeof(NvramClass),
692};
693
051ddccd
HP
694static const TypeInfo m48txx_sysbus_type_info = {
695 .name = TYPE_M48TXX_SYS_BUS,
696 .parent = TYPE_SYS_BUS_DEVICE,
697 .instance_size = sizeof(M48txxSysBusState),
c04e34a9 698 .instance_init = m48t59_init1,
051ddccd
HP
699 .abstract = true,
700 .class_init = m48txx_sysbus_class_init,
43745328
HP
701 .interfaces = (InterfaceInfo[]) {
702 { TYPE_NVRAM },
703 { }
704 }
051ddccd
HP
705};
706
83f7d43a 707static void m48t59_register_types(void)
d27cf0ae 708{
051ddccd
HP
709 TypeInfo sysbus_type_info = {
710 .parent = TYPE_M48TXX_SYS_BUS,
711 .class_size = sizeof(M48txxSysBusDeviceClass),
712 .class_init = m48txx_sysbus_concrete_class_init,
713 };
051ddccd
HP
714 int i;
715
43745328 716 type_register_static(&nvram_info);
051ddccd 717 type_register_static(&m48txx_sysbus_type_info);
051ddccd 718
c124c4d1
DG
719 for (i = 0; i < ARRAY_SIZE(m48txx_sysbus_info); i++) {
720 sysbus_type_info.name = m48txx_sysbus_info[i].bus_name;
721 sysbus_type_info.class_data = &m48txx_sysbus_info[i];
722 type_register(&sysbus_type_info);
051ddccd 723 }
a541f297 724}
d27cf0ae 725
83f7d43a 726type_init(m48t59_register_types)