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 "qapi/error.h"
  37#include "qemu/bcd.h"
  38#include "qemu/module.h"
  39#include "trace.h"
  40
  41#include "m48t59-internal.h"
  42#include "migration/vmstate.h"
  43#include "qom/object.h"
  44
  45#define TYPE_M48TXX_SYS_BUS "sysbus-m48txx"
  46typedef struct M48txxSysBusDeviceClass M48txxSysBusDeviceClass;
  47typedef struct M48txxSysBusState M48txxSysBusState;
  48DECLARE_OBJ_CHECKERS(M48txxSysBusState, M48txxSysBusDeviceClass,
  49                     M48TXX_SYS_BUS, TYPE_M48TXX_SYS_BUS)
  50
  51/*
  52 * Chipset docs:
  53 * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
  54 * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
  55 * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
  56 */
  57
  58struct M48txxSysBusState {
  59    SysBusDevice parent_obj;
  60    M48t59State state;
  61    MemoryRegion io;
  62};
  63
  64struct M48txxSysBusDeviceClass {
  65    SysBusDeviceClass parent_class;
  66    M48txxInfo info;
  67};
  68
  69static M48txxInfo m48txx_sysbus_info[] = {
  70    {
  71        .bus_name = "sysbus-m48t02",
  72        .model = 2,
  73        .size = 0x800,
  74    },{
  75        .bus_name = "sysbus-m48t08",
  76        .model = 8,
  77        .size = 0x2000,
  78    },{
  79        .bus_name = "sysbus-m48t59",
  80        .model = 59,
  81        .size = 0x2000,
  82    }
  83};
  84
  85
  86/* Fake timer functions */
  87
  88/* Alarm management */
  89static void alarm_cb (void *opaque)
  90{
  91    struct tm tm;
  92    uint64_t next_time;
  93    M48t59State *NVRAM = opaque;
  94
  95    qemu_set_irq(NVRAM->IRQ, 1);
  96    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
  97        (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
  98        (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
  99        (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 100        /* Repeat once a month */
 101        qemu_get_timedate(&tm, NVRAM->time_offset);
 102        tm.tm_mon++;
 103        if (tm.tm_mon == 13) {
 104            tm.tm_mon = 1;
 105            tm.tm_year++;
 106        }
 107        next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
 108    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 109               (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
 110               (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 111               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 112        /* Repeat once a day */
 113        next_time = 24 * 60 * 60;
 114    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 115               (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
 116               (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 117               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 118        /* Repeat once an hour */
 119        next_time = 60 * 60;
 120    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 121               (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
 122               (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
 123               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 124        /* Repeat once a minute */
 125        next_time = 60;
 126    } else {
 127        /* Repeat once a second */
 128        next_time = 1;
 129    }
 130    timer_mod(NVRAM->alrm_timer, qemu_clock_get_ns(rtc_clock) +
 131                    next_time * 1000);
 132    qemu_set_irq(NVRAM->IRQ, 0);
 133}
 134
 135static void set_alarm(M48t59State *NVRAM)
 136{
 137    int diff;
 138    if (NVRAM->alrm_timer != NULL) {
 139        timer_del(NVRAM->alrm_timer);
 140        diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
 141        if (diff > 0)
 142            timer_mod(NVRAM->alrm_timer, diff * 1000);
 143    }
 144}
 145
 146/* RTC management helpers */
 147static inline void get_time(M48t59State *NVRAM, struct tm *tm)
 148{
 149    qemu_get_timedate(tm, NVRAM->time_offset);
 150}
 151
 152static void set_time(M48t59State *NVRAM, struct tm *tm)
 153{
 154    NVRAM->time_offset = qemu_timedate_diff(tm);
 155    set_alarm(NVRAM);
 156}
 157
 158/* Watchdog management */
 159static void watchdog_cb (void *opaque)
 160{
 161    M48t59State *NVRAM = opaque;
 162
 163    NVRAM->buffer[0x1FF0] |= 0x80;
 164    if (NVRAM->buffer[0x1FF7] & 0x80) {
 165        NVRAM->buffer[0x1FF7] = 0x00;
 166        NVRAM->buffer[0x1FFC] &= ~0x40;
 167        /* May it be a hw CPU Reset instead ? */
 168        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 169    } else {
 170        qemu_set_irq(NVRAM->IRQ, 1);
 171        qemu_set_irq(NVRAM->IRQ, 0);
 172    }
 173}
 174
 175static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
 176{
 177    uint64_t interval; /* in 1/16 seconds */
 178
 179    NVRAM->buffer[0x1FF0] &= ~0x80;
 180    if (NVRAM->wd_timer != NULL) {
 181        timer_del(NVRAM->wd_timer);
 182        if (value != 0) {
 183            interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
 184            timer_mod(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
 185                           ((interval * 1000) >> 4));
 186        }
 187    }
 188}
 189
 190/* Direct access to NVRAM */
 191void m48t59_write(M48t59State *NVRAM, uint32_t addr, uint32_t val)
 192{
 193    struct tm tm;
 194    int tmp;
 195
 196    trace_m48txx_nvram_mem_write(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    trace_m48txx_nvram_mem_read(addr, retval);
 454
 455    return retval;
 456}
 457
 458/* IO access to NVRAM */
 459static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val,
 460                         unsigned size)
 461{
 462    M48t59State *NVRAM = opaque;
 463
 464    trace_m48txx_nvram_io_write(addr, val);
 465    switch (addr) {
 466    case 0:
 467        NVRAM->addr &= ~0x00FF;
 468        NVRAM->addr |= val;
 469        break;
 470    case 1:
 471        NVRAM->addr &= ~0xFF00;
 472        NVRAM->addr |= val << 8;
 473        break;
 474    case 3:
 475        m48t59_write(NVRAM, NVRAM->addr, val);
 476        NVRAM->addr = 0x0000;
 477        break;
 478    default:
 479        break;
 480    }
 481}
 482
 483static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size)
 484{
 485    M48t59State *NVRAM = opaque;
 486    uint32_t retval;
 487
 488    switch (addr) {
 489    case 3:
 490        retval = m48t59_read(NVRAM, NVRAM->addr);
 491        break;
 492    default:
 493        retval = -1;
 494        break;
 495    }
 496    trace_m48txx_nvram_io_read(addr, retval);
 497
 498    return retval;
 499}
 500
 501static uint64_t nvram_read(void *opaque, hwaddr addr, unsigned size)
 502{
 503    M48t59State *NVRAM = opaque;
 504
 505    return m48t59_read(NVRAM, addr);
 506}
 507
 508static void nvram_write(void *opaque, hwaddr addr, uint64_t value,
 509                        unsigned size)
 510{
 511    M48t59State *NVRAM = opaque;
 512
 513    return m48t59_write(NVRAM, addr, value);
 514}
 515
 516static const MemoryRegionOps nvram_ops = {
 517    .read = nvram_read,
 518    .write = nvram_write,
 519    .impl.min_access_size = 1,
 520    .impl.max_access_size = 1,
 521    .valid.min_access_size = 1,
 522    .valid.max_access_size = 4,
 523    .endianness = DEVICE_BIG_ENDIAN,
 524};
 525
 526static const VMStateDescription vmstate_m48t59 = {
 527    .name = "m48t59",
 528    .version_id = 1,
 529    .minimum_version_id = 1,
 530    .fields = (VMStateField[]) {
 531        VMSTATE_UINT8(lock, M48t59State),
 532        VMSTATE_UINT16(addr, M48t59State),
 533        VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, size),
 534        VMSTATE_END_OF_LIST()
 535    }
 536};
 537
 538void m48t59_reset_common(M48t59State *NVRAM)
 539{
 540    NVRAM->addr = 0;
 541    NVRAM->lock = 0;
 542    if (NVRAM->alrm_timer != NULL)
 543        timer_del(NVRAM->alrm_timer);
 544
 545    if (NVRAM->wd_timer != NULL)
 546        timer_del(NVRAM->wd_timer);
 547}
 548
 549static void m48t59_reset_sysbus(DeviceState *d)
 550{
 551    M48txxSysBusState *sys = M48TXX_SYS_BUS(d);
 552    M48t59State *NVRAM = &sys->state;
 553
 554    m48t59_reset_common(NVRAM);
 555}
 556
 557const MemoryRegionOps m48t59_io_ops = {
 558    .read = NVRAM_readb,
 559    .write = NVRAM_writeb,
 560    .impl = {
 561        .min_access_size = 1,
 562        .max_access_size = 1,
 563    },
 564    .endianness = DEVICE_LITTLE_ENDIAN,
 565};
 566
 567void m48t59_realize_common(M48t59State *s, Error **errp)
 568{
 569    s->buffer = g_malloc0(s->size);
 570    if (s->model == 59) {
 571        s->alrm_timer = timer_new_ns(rtc_clock, &alarm_cb, s);
 572        s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s);
 573    }
 574    qemu_get_timedate(&s->alarm, 0);
 575}
 576
 577static void m48t59_init1(Object *obj)
 578{
 579    M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(obj);
 580    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 581    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 582    M48t59State *s = &d->state;
 583
 584    s->model = u->info.model;
 585    s->size = u->info.size;
 586    sysbus_init_irq(dev, &s->IRQ);
 587
 588    memory_region_init_io(&s->iomem, obj, &nvram_ops, s, "m48t59.nvram",
 589                          s->size);
 590    memory_region_init_io(&d->io, obj, &m48t59_io_ops, s, "m48t59", 4);
 591}
 592
 593static void m48t59_realize(DeviceState *dev, Error **errp)
 594{
 595    M48txxSysBusState *d = M48TXX_SYS_BUS(dev);
 596    M48t59State *s = &d->state;
 597    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
 598
 599    sysbus_init_mmio(sbd, &s->iomem);
 600    sysbus_init_mmio(sbd, &d->io);
 601    m48t59_realize_common(s, errp);
 602}
 603
 604static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr)
 605{
 606    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 607    return m48t59_read(&d->state, addr);
 608}
 609
 610static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val)
 611{
 612    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 613    m48t59_write(&d->state, addr, val);
 614}
 615
 616static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock)
 617{
 618    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 619    m48t59_toggle_lock(&d->state, lock);
 620}
 621
 622static Property m48t59_sysbus_properties[] = {
 623    DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
 624    DEFINE_PROP_END_OF_LIST(),
 625};
 626
 627static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
 628{
 629    DeviceClass *dc = DEVICE_CLASS(klass);
 630    NvramClass *nc = NVRAM_CLASS(klass);
 631
 632    dc->realize = m48t59_realize;
 633    dc->reset = m48t59_reset_sysbus;
 634    device_class_set_props(dc, m48t59_sysbus_properties);
 635    dc->vmsd = &vmstate_m48t59;
 636    nc->read = m48txx_sysbus_read;
 637    nc->write = m48txx_sysbus_write;
 638    nc->toggle_lock = m48txx_sysbus_toggle_lock;
 639}
 640
 641static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
 642{
 643    M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
 644    M48txxInfo *info = data;
 645
 646    u->info = *info;
 647}
 648
 649static const TypeInfo nvram_info = {
 650    .name = TYPE_NVRAM,
 651    .parent = TYPE_INTERFACE,
 652    .class_size = sizeof(NvramClass),
 653};
 654
 655static const TypeInfo m48txx_sysbus_type_info = {
 656    .name = TYPE_M48TXX_SYS_BUS,
 657    .parent = TYPE_SYS_BUS_DEVICE,
 658    .instance_size = sizeof(M48txxSysBusState),
 659    .instance_init = m48t59_init1,
 660    .abstract = true,
 661    .class_init = m48txx_sysbus_class_init,
 662    .interfaces = (InterfaceInfo[]) {
 663        { TYPE_NVRAM },
 664        { }
 665    }
 666};
 667
 668static void m48t59_register_types(void)
 669{
 670    TypeInfo sysbus_type_info = {
 671        .parent = TYPE_M48TXX_SYS_BUS,
 672        .class_size = sizeof(M48txxSysBusDeviceClass),
 673        .class_init = m48txx_sysbus_concrete_class_init,
 674    };
 675    int i;
 676
 677    type_register_static(&nvram_info);
 678    type_register_static(&m48txx_sysbus_type_info);
 679
 680    for (i = 0; i < ARRAY_SIZE(m48txx_sysbus_info); i++) {
 681        sysbus_type_info.name = m48txx_sysbus_info[i].bus_name;
 682        sysbus_type_info.class_data = &m48txx_sysbus_info[i];
 683        type_register(&sysbus_type_info);
 684    }
 685}
 686
 687type_init(m48t59_register_types)
 688