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