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