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