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 "hw/irq.h"
  28#include "hw/qdev-properties.h"
  29#include "hw/rtc/m48t59.h"
  30#include "qemu/timer.h"
  31#include "sysemu/runstate.h"
  32#include "sysemu/rtc.h"
  33#include "sysemu/sysemu.h"
  34#include "hw/sysbus.h"
  35#include "qapi/error.h"
  36#include "qemu/bcd.h"
  37#include "qemu/module.h"
  38#include "trace.h"
  39
  40#include "m48t59-internal.h"
  41#include "migration/vmstate.h"
  42#include "qom/object.h"
  43
  44#define TYPE_M48TXX_SYS_BUS "sysbus-m48txx"
  45typedef struct M48txxSysBusDeviceClass M48txxSysBusDeviceClass;
  46typedef struct M48txxSysBusState M48txxSysBusState;
  47DECLARE_OBJ_CHECKERS(M48txxSysBusState, M48txxSysBusDeviceClass,
  48                     M48TXX_SYS_BUS, 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
  57struct M48txxSysBusState {
  58    SysBusDevice parent_obj;
  59    M48t59State state;
  60    MemoryRegion io;
  61};
  62
  63struct M48txxSysBusDeviceClass {
  64    SysBusDeviceClass parent_class;
  65    M48txxInfo info;
  66};
  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    trace_m48txx_nvram_mem_write(addr, val);
 196
 197    /* check for NVRAM access */
 198    if ((NVRAM->model == 2 && addr < 0x7f8) ||
 199        (NVRAM->model == 8 && addr < 0x1ff8) ||
 200        (NVRAM->model == 59 && addr < 0x1ff0)) {
 201        goto do_write;
 202    }
 203
 204    /* TOD access */
 205    switch (addr) {
 206    case 0x1FF0:
 207        /* flags register : read-only */
 208        break;
 209    case 0x1FF1:
 210        /* unused */
 211        break;
 212    case 0x1FF2:
 213        /* alarm seconds */
 214        tmp = from_bcd(val & 0x7F);
 215        if (tmp >= 0 && tmp <= 59) {
 216            NVRAM->alarm.tm_sec = tmp;
 217            NVRAM->buffer[0x1FF2] = val;
 218            set_alarm(NVRAM);
 219        }
 220        break;
 221    case 0x1FF3:
 222        /* alarm minutes */
 223        tmp = from_bcd(val & 0x7F);
 224        if (tmp >= 0 && tmp <= 59) {
 225            NVRAM->alarm.tm_min = tmp;
 226            NVRAM->buffer[0x1FF3] = val;
 227            set_alarm(NVRAM);
 228        }
 229        break;
 230    case 0x1FF4:
 231        /* alarm hours */
 232        tmp = from_bcd(val & 0x3F);
 233        if (tmp >= 0 && tmp <= 23) {
 234            NVRAM->alarm.tm_hour = tmp;
 235            NVRAM->buffer[0x1FF4] = val;
 236            set_alarm(NVRAM);
 237        }
 238        break;
 239    case 0x1FF5:
 240        /* alarm date */
 241        tmp = from_bcd(val & 0x3F);
 242        if (tmp != 0) {
 243            NVRAM->alarm.tm_mday = tmp;
 244            NVRAM->buffer[0x1FF5] = val;
 245            set_alarm(NVRAM);
 246        }
 247        break;
 248    case 0x1FF6:
 249        /* interrupts */
 250        NVRAM->buffer[0x1FF6] = val;
 251        break;
 252    case 0x1FF7:
 253        /* watchdog */
 254        NVRAM->buffer[0x1FF7] = val;
 255        set_up_watchdog(NVRAM, val);
 256        break;
 257    case 0x1FF8:
 258    case 0x07F8:
 259        /* control */
 260       NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
 261        break;
 262    case 0x1FF9:
 263    case 0x07F9:
 264        /* seconds (BCD) */
 265        tmp = from_bcd(val & 0x7F);
 266        if (tmp >= 0 && tmp <= 59) {
 267            get_time(NVRAM, &tm);
 268            tm.tm_sec = tmp;
 269            set_time(NVRAM, &tm);
 270        }
 271        if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
 272            if (val & 0x80) {
 273                NVRAM->stop_time = time(NULL);
 274            } else {
 275                NVRAM->time_offset += NVRAM->stop_time - time(NULL);
 276                NVRAM->stop_time = 0;
 277            }
 278        }
 279        NVRAM->buffer[addr] = val & 0x80;
 280        break;
 281    case 0x1FFA:
 282    case 0x07FA:
 283        /* minutes (BCD) */
 284        tmp = from_bcd(val & 0x7F);
 285        if (tmp >= 0 && tmp <= 59) {
 286            get_time(NVRAM, &tm);
 287            tm.tm_min = tmp;
 288            set_time(NVRAM, &tm);
 289        }
 290        break;
 291    case 0x1FFB:
 292    case 0x07FB:
 293        /* hours (BCD) */
 294        tmp = from_bcd(val & 0x3F);
 295        if (tmp >= 0 && tmp <= 23) {
 296            get_time(NVRAM, &tm);
 297            tm.tm_hour = tmp;
 298            set_time(NVRAM, &tm);
 299        }
 300        break;
 301    case 0x1FFC:
 302    case 0x07FC:
 303        /* day of the week / century */
 304        tmp = from_bcd(val & 0x07);
 305        get_time(NVRAM, &tm);
 306        tm.tm_wday = tmp;
 307        set_time(NVRAM, &tm);
 308        NVRAM->buffer[addr] = val & 0x40;
 309        break;
 310    case 0x1FFD:
 311    case 0x07FD:
 312        /* date (BCD) */
 313       tmp = from_bcd(val & 0x3F);
 314        if (tmp != 0) {
 315            get_time(NVRAM, &tm);
 316            tm.tm_mday = tmp;
 317            set_time(NVRAM, &tm);
 318        }
 319        break;
 320    case 0x1FFE:
 321    case 0x07FE:
 322        /* month */
 323        tmp = from_bcd(val & 0x1F);
 324        if (tmp >= 1 && tmp <= 12) {
 325            get_time(NVRAM, &tm);
 326            tm.tm_mon = tmp - 1;
 327            set_time(NVRAM, &tm);
 328        }
 329        break;
 330    case 0x1FFF:
 331    case 0x07FF:
 332        /* year */
 333        tmp = from_bcd(val);
 334        if (tmp >= 0 && tmp <= 99) {
 335            get_time(NVRAM, &tm);
 336            tm.tm_year = from_bcd(val) + NVRAM->base_year - 1900;
 337            set_time(NVRAM, &tm);
 338        }
 339        break;
 340    default:
 341        /* Check lock registers state */
 342        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
 343            break;
 344        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
 345            break;
 346    do_write:
 347        if (addr < NVRAM->size) {
 348            NVRAM->buffer[addr] = val & 0xFF;
 349        }
 350        break;
 351    }
 352}
 353
 354uint32_t m48t59_read(M48t59State *NVRAM, uint32_t addr)
 355{
 356    struct tm tm;
 357    uint32_t retval = 0xFF;
 358
 359    /* check for NVRAM access */
 360    if ((NVRAM->model == 2 && addr < 0x078f) ||
 361        (NVRAM->model == 8 && addr < 0x1ff8) ||
 362        (NVRAM->model == 59 && addr < 0x1ff0)) {
 363        goto do_read;
 364    }
 365
 366    /* TOD access */
 367    switch (addr) {
 368    case 0x1FF0:
 369        /* flags register */
 370        goto do_read;
 371    case 0x1FF1:
 372        /* unused */
 373        retval = 0;
 374        break;
 375    case 0x1FF2:
 376        /* alarm seconds */
 377        goto do_read;
 378    case 0x1FF3:
 379        /* alarm minutes */
 380        goto do_read;
 381    case 0x1FF4:
 382        /* alarm hours */
 383        goto do_read;
 384    case 0x1FF5:
 385        /* alarm date */
 386        goto do_read;
 387    case 0x1FF6:
 388        /* interrupts */
 389        goto do_read;
 390    case 0x1FF7:
 391        /* A read resets the watchdog */
 392        set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
 393        goto do_read;
 394    case 0x1FF8:
 395    case 0x07F8:
 396        /* control */
 397        goto do_read;
 398    case 0x1FF9:
 399    case 0x07F9:
 400        /* seconds (BCD) */
 401        get_time(NVRAM, &tm);
 402        retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
 403        break;
 404    case 0x1FFA:
 405    case 0x07FA:
 406        /* minutes (BCD) */
 407        get_time(NVRAM, &tm);
 408        retval = to_bcd(tm.tm_min);
 409        break;
 410    case 0x1FFB:
 411    case 0x07FB:
 412        /* hours (BCD) */
 413        get_time(NVRAM, &tm);
 414        retval = to_bcd(tm.tm_hour);
 415        break;
 416    case 0x1FFC:
 417    case 0x07FC:
 418        /* day of the week / century */
 419        get_time(NVRAM, &tm);
 420        retval = NVRAM->buffer[addr] | tm.tm_wday;
 421        break;
 422    case 0x1FFD:
 423    case 0x07FD:
 424        /* date */
 425        get_time(NVRAM, &tm);
 426        retval = to_bcd(tm.tm_mday);
 427        break;
 428    case 0x1FFE:
 429    case 0x07FE:
 430        /* month */
 431        get_time(NVRAM, &tm);
 432        retval = to_bcd(tm.tm_mon + 1);
 433        break;
 434    case 0x1FFF:
 435    case 0x07FF:
 436        /* year */
 437        get_time(NVRAM, &tm);
 438        retval = to_bcd((tm.tm_year + 1900 - NVRAM->base_year) % 100);
 439        break;
 440    default:
 441        /* Check lock registers state */
 442        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
 443            break;
 444        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
 445            break;
 446    do_read:
 447        if (addr < NVRAM->size) {
 448            retval = NVRAM->buffer[addr];
 449        }
 450        break;
 451    }
 452    trace_m48txx_nvram_mem_read(addr, retval);
 453
 454    return retval;
 455}
 456
 457/* IO access to NVRAM */
 458static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val,
 459                         unsigned size)
 460{
 461    M48t59State *NVRAM = opaque;
 462
 463    trace_m48txx_nvram_io_write(addr, val);
 464    switch (addr) {
 465    case 0:
 466        NVRAM->addr &= ~0x00FF;
 467        NVRAM->addr |= val;
 468        break;
 469    case 1:
 470        NVRAM->addr &= ~0xFF00;
 471        NVRAM->addr |= val << 8;
 472        break;
 473    case 3:
 474        m48t59_write(NVRAM, NVRAM->addr, val);
 475        NVRAM->addr = 0x0000;
 476        break;
 477    default:
 478        break;
 479    }
 480}
 481
 482static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size)
 483{
 484    M48t59State *NVRAM = opaque;
 485    uint32_t retval;
 486
 487    switch (addr) {
 488    case 3:
 489        retval = m48t59_read(NVRAM, NVRAM->addr);
 490        break;
 491    default:
 492        retval = -1;
 493        break;
 494    }
 495    trace_m48txx_nvram_io_read(addr, retval);
 496
 497    return retval;
 498}
 499
 500static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size)
 501{
 502    M48t59State *NVRAM = opaque;
 503
 504    return m48t59_read(NVRAM, addr);
 505}
 506
 507static void nvram_write(void *opaque, hwaddr addr, uint64_t value,
 508                        unsigned size)
 509{
 510    M48t59State *NVRAM = opaque;
 511
 512    return m48t59_write(NVRAM, addr, value);
 513}
 514
 515static const MemoryRegionOps nvram_ops = {
 516    .read = nvram_read,
 517    .write = nvram_write,
 518    .impl.min_access_size = 1,
 519    .impl.max_access_size = 1,
 520    .valid.min_access_size = 1,
 521    .valid.max_access_size = 4,
 522    .endianness = DEVICE_BIG_ENDIAN,
 523};
 524
 525static const VMStateDescription vmstate_m48t59 = {
 526    .name = "m48t59",
 527    .version_id = 1,
 528    .minimum_version_id = 1,
 529    .fields = (VMStateField[]) {
 530        VMSTATE_UINT8(lock, M48t59State),
 531        VMSTATE_UINT16(addr, M48t59State),
 532        VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, size),
 533        VMSTATE_END_OF_LIST()
 534    }
 535};
 536
 537void m48t59_reset_common(M48t59State *NVRAM)
 538{
 539    NVRAM->addr = 0;
 540    NVRAM->lock = 0;
 541    if (NVRAM->alrm_timer != NULL)
 542        timer_del(NVRAM->alrm_timer);
 543
 544    if (NVRAM->wd_timer != NULL)
 545        timer_del(NVRAM->wd_timer);
 546}
 547
 548static void m48t59_reset_sysbus(DeviceState *d)
 549{
 550    M48txxSysBusState *sys = M48TXX_SYS_BUS(d);
 551    M48t59State *NVRAM = &sys->state;
 552
 553    m48t59_reset_common(NVRAM);
 554}
 555
 556const MemoryRegionOps m48t59_io_ops = {
 557    .read = NVRAM_readb,
 558    .write = NVRAM_writeb,
 559    .impl = {
 560        .min_access_size = 1,
 561        .max_access_size = 1,
 562    },
 563    .endianness = DEVICE_LITTLE_ENDIAN,
 564};
 565
 566void m48t59_realize_common(M48t59State *s, Error **errp)
 567{
 568    s->buffer = g_malloc0(s->size);
 569    if (s->model == 59) {
 570        s->alrm_timer = timer_new_ns(rtc_clock, &alarm_cb, s);
 571        s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s);
 572    }
 573    qemu_get_timedate(&s->alarm, 0);
 574}
 575
 576static void m48t59_init1(Object *obj)
 577{
 578    M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(obj);
 579    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 580    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 581    M48t59State *s = &d->state;
 582
 583    s->model = u->info.model;
 584    s->size = u->info.size;
 585    sysbus_init_irq(dev, &s->IRQ);
 586
 587    memory_region_init_io(&s->iomem, obj, &nvram_ops, s, "m48t59.nvram",
 588                          s->size);
 589    memory_region_init_io(&d->io, obj, &m48t59_io_ops, s, "m48t59", 4);
 590}
 591
 592static void m48t59_realize(DeviceState *dev, Error **errp)
 593{
 594    M48txxSysBusState *d = M48TXX_SYS_BUS(dev);
 595    M48t59State *s = &d->state;
 596    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 597
 598    sysbus_init_mmio(sbd, &s->iomem);
 599    sysbus_init_mmio(sbd, &d->io);
 600    m48t59_realize_common(s, errp);
 601}
 602
 603static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr)
 604{
 605    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 606    return m48t59_read(&d->state, addr);
 607}
 608
 609static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val)
 610{
 611    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 612    m48t59_write(&d->state, addr, val);
 613}
 614
 615static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock)
 616{
 617    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 618    m48t59_toggle_lock(&d->state, lock);
 619}
 620
 621static Property m48t59_sysbus_properties[] = {
 622    DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
 623    DEFINE_PROP_END_OF_LIST(),
 624};
 625
 626static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
 627{
 628    DeviceClass *dc = DEVICE_CLASS(klass);
 629    NvramClass *nc = NVRAM_CLASS(klass);
 630
 631    dc->realize = m48t59_realize;
 632    dc->reset = m48t59_reset_sysbus;
 633    device_class_set_props(dc, m48t59_sysbus_properties);
 634    dc->vmsd = &vmstate_m48t59;
 635    nc->read = m48txx_sysbus_read;
 636    nc->write = m48txx_sysbus_write;
 637    nc->toggle_lock = m48txx_sysbus_toggle_lock;
 638}
 639
 640static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
 641{
 642    M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
 643    M48txxInfo *info = data;
 644
 645    u->info = *info;
 646}
 647
 648static const TypeInfo nvram_info = {
 649    .name = TYPE_NVRAM,
 650    .parent = TYPE_INTERFACE,
 651    .class_size = sizeof(NvramClass),
 652};
 653
 654static const TypeInfo m48txx_sysbus_type_info = {
 655    .name = TYPE_M48TXX_SYS_BUS,
 656    .parent = TYPE_SYS_BUS_DEVICE,
 657    .instance_size = sizeof(M48txxSysBusState),
 658    .instance_init = m48t59_init1,
 659    .abstract = true,
 660    .class_init = m48txx_sysbus_class_init,
 661    .interfaces = (InterfaceInfo[]) {
 662        { TYPE_NVRAM },
 663        { }
 664    }
 665};
 666
 667static void m48t59_register_types(void)
 668{
 669    TypeInfo sysbus_type_info = {
 670        .parent = TYPE_M48TXX_SYS_BUS,
 671        .class_size = sizeof(M48txxSysBusDeviceClass),
 672        .class_init = m48txx_sysbus_concrete_class_init,
 673    };
 674    int i;
 675
 676    type_register_static(&nvram_info);
 677    type_register_static(&m48txx_sysbus_type_info);
 678
 679    for (i = 0; i < ARRAY_SIZE(m48txx_sysbus_info); i++) {
 680        sysbus_type_info.name = m48txx_sysbus_info[i].bus_name;
 681        sysbus_type_info.class_data = &m48txx_sysbus_info[i];
 682        type_register(&sysbus_type_info);
 683    }
 684}
 685
 686type_init(m48t59_register_types)
 687