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 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#include "hw/hw.h"
  26#include "hw/timer/m48t59.h"
  27#include "qemu/timer.h"
  28#include "sysemu/sysemu.h"
  29#include "hw/sysbus.h"
  30#include "hw/isa/isa.h"
  31#include "exec/address-spaces.h"
  32
  33//#define DEBUG_NVRAM
  34
  35#if defined(DEBUG_NVRAM)
  36#define NVRAM_PRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
  37#else
  38#define NVRAM_PRINTF(fmt, ...) do { } while (0)
  39#endif
  40
  41#define TYPE_M48TXX_SYS_BUS "sysbus-m48txx"
  42#define M48TXX_SYS_BUS_GET_CLASS(obj) \
  43    OBJECT_GET_CLASS(M48txxSysBusDeviceClass, (obj), TYPE_M48TXX_SYS_BUS)
  44#define M48TXX_SYS_BUS_CLASS(klass) \
  45    OBJECT_CLASS_CHECK(M48txxSysBusDeviceClass, (klass), TYPE_M48TXX_SYS_BUS)
  46#define M48TXX_SYS_BUS(obj) \
  47    OBJECT_CHECK(M48txxSysBusState, (obj), TYPE_M48TXX_SYS_BUS)
  48
  49#define TYPE_M48TXX_ISA "isa-m48txx"
  50#define M48TXX_ISA_GET_CLASS(obj) \
  51    OBJECT_GET_CLASS(M48txxISADeviceClass, (obj), TYPE_M48TXX_ISA)
  52#define M48TXX_ISA_CLASS(klass) \
  53    OBJECT_CLASS_CHECK(M48txxISADeviceClass, (klass), TYPE_M48TXX_ISA)
  54#define M48TXX_ISA(obj) \
  55    OBJECT_CHECK(M48txxISAState, (obj), TYPE_M48TXX_ISA)
  56
  57/*
  58 * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
  59 * alarm and a watchdog timer and related control registers. In the
  60 * PPC platform there is also a nvram lock function.
  61 */
  62
  63typedef struct M48txxInfo {
  64    const char *isa_name;
  65    const char *sysbus_name;
  66    uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
  67    uint32_t size;
  68} M48txxInfo;
  69
  70/*
  71 * Chipset docs:
  72 * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
  73 * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
  74 * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
  75 */
  76
  77typedef struct M48t59State {
  78    /* Hardware parameters */
  79    qemu_irq IRQ;
  80    MemoryRegion iomem;
  81    uint32_t size;
  82    int32_t base_year;
  83    /* RTC management */
  84    time_t   time_offset;
  85    time_t   stop_time;
  86    /* Alarm & watchdog */
  87    struct tm alarm;
  88    QEMUTimer *alrm_timer;
  89    QEMUTimer *wd_timer;
  90    /* NVRAM storage */
  91    uint8_t *buffer;
  92    /* Model parameters */
  93    uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
  94    /* NVRAM storage */
  95    uint16_t addr;
  96    uint8_t  lock;
  97} M48t59State;
  98
  99typedef struct M48txxISAState {
 100    ISADevice parent_obj;
 101    M48t59State state;
 102    uint32_t io_base;
 103    MemoryRegion io;
 104} M48txxISAState;
 105
 106typedef struct M48txxISADeviceClass {
 107    ISADeviceClass parent_class;
 108    M48txxInfo info;
 109} M48txxISADeviceClass;
 110
 111typedef struct M48txxSysBusState {
 112    SysBusDevice parent_obj;
 113    M48t59State state;
 114    MemoryRegion io;
 115} M48txxSysBusState;
 116
 117typedef struct M48txxSysBusDeviceClass {
 118    SysBusDeviceClass parent_class;
 119    M48txxInfo info;
 120} M48txxSysBusDeviceClass;
 121
 122static M48txxInfo m48txx_info[] = {
 123    {
 124        .sysbus_name = "sysbus-m48t02",
 125        .model = 2,
 126        .size = 0x800,
 127    },{
 128        .sysbus_name = "sysbus-m48t08",
 129        .model = 8,
 130        .size = 0x2000,
 131    },{
 132        .sysbus_name = "sysbus-m48t59",
 133        .model = 59,
 134        .size = 0x2000,
 135    },{
 136        .isa_name = "isa-m48t59",
 137        .model = 59,
 138        .size = 0x2000,
 139    }
 140};
 141
 142
 143/* Fake timer functions */
 144
 145/* Alarm management */
 146static void alarm_cb (void *opaque)
 147{
 148    struct tm tm;
 149    uint64_t next_time;
 150    M48t59State *NVRAM = opaque;
 151
 152    qemu_set_irq(NVRAM->IRQ, 1);
 153    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
 154        (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
 155        (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 156        (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 157        /* Repeat once a month */
 158        qemu_get_timedate(&tm, NVRAM->time_offset);
 159        tm.tm_mon++;
 160        if (tm.tm_mon == 13) {
 161            tm.tm_mon = 1;
 162            tm.tm_year++;
 163        }
 164        next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
 165    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 166               (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
 167               (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 168               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 169        /* Repeat once a day */
 170        next_time = 24 * 60 * 60;
 171    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 172               (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
 173               (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 174               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 175        /* Repeat once an hour */
 176        next_time = 60 * 60;
 177    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 178               (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
 179               (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
 180               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 181        /* Repeat once a minute */
 182        next_time = 60;
 183    } else {
 184        /* Repeat once a second */
 185        next_time = 1;
 186    }
 187    timer_mod(NVRAM->alrm_timer, qemu_clock_get_ns(rtc_clock) +
 188                    next_time * 1000);
 189    qemu_set_irq(NVRAM->IRQ, 0);
 190}
 191
 192static void set_alarm(M48t59State *NVRAM)
 193{
 194    int diff;
 195    if (NVRAM->alrm_timer != NULL) {
 196        timer_del(NVRAM->alrm_timer);
 197        diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
 198        if (diff > 0)
 199            timer_mod(NVRAM->alrm_timer, diff * 1000);
 200    }
 201}
 202
 203/* RTC management helpers */
 204static inline void get_time(M48t59State *NVRAM, struct tm *tm)
 205{
 206    qemu_get_timedate(tm, NVRAM->time_offset);
 207}
 208
 209static void set_time(M48t59State *NVRAM, struct tm *tm)
 210{
 211    NVRAM->time_offset = qemu_timedate_diff(tm);
 212    set_alarm(NVRAM);
 213}
 214
 215/* Watchdog management */
 216static void watchdog_cb (void *opaque)
 217{
 218    M48t59State *NVRAM = opaque;
 219
 220    NVRAM->buffer[0x1FF0] |= 0x80;
 221    if (NVRAM->buffer[0x1FF7] & 0x80) {
 222        NVRAM->buffer[0x1FF7] = 0x00;
 223        NVRAM->buffer[0x1FFC] &= ~0x40;
 224        /* May it be a hw CPU Reset instead ? */
 225        qemu_system_reset_request();
 226    } else {
 227        qemu_set_irq(NVRAM->IRQ, 1);
 228        qemu_set_irq(NVRAM->IRQ, 0);
 229    }
 230}
 231
 232static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
 233{
 234    uint64_t interval; /* in 1/16 seconds */
 235
 236    NVRAM->buffer[0x1FF0] &= ~0x80;
 237    if (NVRAM->wd_timer != NULL) {
 238        timer_del(NVRAM->wd_timer);
 239        if (value != 0) {
 240            interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
 241            timer_mod(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
 242                           ((interval * 1000) >> 4));
 243        }
 244    }
 245}
 246
 247/* Direct access to NVRAM */
 248static void m48t59_write(M48t59State *NVRAM, uint32_t addr, uint32_t val)
 249{
 250    struct tm tm;
 251    int tmp;
 252
 253    if (addr > 0x1FF8 && addr < 0x2000)
 254        NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
 255
 256    /* check for NVRAM access */
 257    if ((NVRAM->model == 2 && addr < 0x7f8) ||
 258        (NVRAM->model == 8 && addr < 0x1ff8) ||
 259        (NVRAM->model == 59 && addr < 0x1ff0)) {
 260        goto do_write;
 261    }
 262
 263    /* TOD access */
 264    switch (addr) {
 265    case 0x1FF0:
 266        /* flags register : read-only */
 267        break;
 268    case 0x1FF1:
 269        /* unused */
 270        break;
 271    case 0x1FF2:
 272        /* alarm seconds */
 273        tmp = from_bcd(val & 0x7F);
 274        if (tmp >= 0 && tmp <= 59) {
 275            NVRAM->alarm.tm_sec = tmp;
 276            NVRAM->buffer[0x1FF2] = val;
 277            set_alarm(NVRAM);
 278        }
 279        break;
 280    case 0x1FF3:
 281        /* alarm minutes */
 282        tmp = from_bcd(val & 0x7F);
 283        if (tmp >= 0 && tmp <= 59) {
 284            NVRAM->alarm.tm_min = tmp;
 285            NVRAM->buffer[0x1FF3] = val;
 286            set_alarm(NVRAM);
 287        }
 288        break;
 289    case 0x1FF4:
 290        /* alarm hours */
 291        tmp = from_bcd(val & 0x3F);
 292        if (tmp >= 0 && tmp <= 23) {
 293            NVRAM->alarm.tm_hour = tmp;
 294            NVRAM->buffer[0x1FF4] = val;
 295            set_alarm(NVRAM);
 296        }
 297        break;
 298    case 0x1FF5:
 299        /* alarm date */
 300        tmp = from_bcd(val & 0x3F);
 301        if (tmp != 0) {
 302            NVRAM->alarm.tm_mday = tmp;
 303            NVRAM->buffer[0x1FF5] = val;
 304            set_alarm(NVRAM);
 305        }
 306        break;
 307    case 0x1FF6:
 308        /* interrupts */
 309        NVRAM->buffer[0x1FF6] = val;
 310        break;
 311    case 0x1FF7:
 312        /* watchdog */
 313        NVRAM->buffer[0x1FF7] = val;
 314        set_up_watchdog(NVRAM, val);
 315        break;
 316    case 0x1FF8:
 317    case 0x07F8:
 318        /* control */
 319       NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
 320        break;
 321    case 0x1FF9:
 322    case 0x07F9:
 323        /* seconds (BCD) */
 324        tmp = from_bcd(val & 0x7F);
 325        if (tmp >= 0 && tmp <= 59) {
 326            get_time(NVRAM, &tm);
 327            tm.tm_sec = tmp;
 328            set_time(NVRAM, &tm);
 329        }
 330        if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
 331            if (val & 0x80) {
 332                NVRAM->stop_time = time(NULL);
 333            } else {
 334                NVRAM->time_offset += NVRAM->stop_time - time(NULL);
 335                NVRAM->stop_time = 0;
 336            }
 337        }
 338        NVRAM->buffer[addr] = val & 0x80;
 339        break;
 340    case 0x1FFA:
 341    case 0x07FA:
 342        /* minutes (BCD) */
 343        tmp = from_bcd(val & 0x7F);
 344        if (tmp >= 0 && tmp <= 59) {
 345            get_time(NVRAM, &tm);
 346            tm.tm_min = tmp;
 347            set_time(NVRAM, &tm);
 348        }
 349        break;
 350    case 0x1FFB:
 351    case 0x07FB:
 352        /* hours (BCD) */
 353        tmp = from_bcd(val & 0x3F);
 354        if (tmp >= 0 && tmp <= 23) {
 355            get_time(NVRAM, &tm);
 356            tm.tm_hour = tmp;
 357            set_time(NVRAM, &tm);
 358        }
 359        break;
 360    case 0x1FFC:
 361    case 0x07FC:
 362        /* day of the week / century */
 363        tmp = from_bcd(val & 0x07);
 364        get_time(NVRAM, &tm);
 365        tm.tm_wday = tmp;
 366        set_time(NVRAM, &tm);
 367        NVRAM->buffer[addr] = val & 0x40;
 368        break;
 369    case 0x1FFD:
 370    case 0x07FD:
 371        /* date (BCD) */
 372       tmp = from_bcd(val & 0x3F);
 373        if (tmp != 0) {
 374            get_time(NVRAM, &tm);
 375            tm.tm_mday = tmp;
 376            set_time(NVRAM, &tm);
 377        }
 378        break;
 379    case 0x1FFE:
 380    case 0x07FE:
 381        /* month */
 382        tmp = from_bcd(val & 0x1F);
 383        if (tmp >= 1 && tmp <= 12) {
 384            get_time(NVRAM, &tm);
 385            tm.tm_mon = tmp - 1;
 386            set_time(NVRAM, &tm);
 387        }
 388        break;
 389    case 0x1FFF:
 390    case 0x07FF:
 391        /* year */
 392        tmp = from_bcd(val);
 393        if (tmp >= 0 && tmp <= 99) {
 394            get_time(NVRAM, &tm);
 395            tm.tm_year = from_bcd(val) + NVRAM->base_year - 1900;
 396            set_time(NVRAM, &tm);
 397        }
 398        break;
 399    default:
 400        /* Check lock registers state */
 401        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
 402            break;
 403        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
 404            break;
 405    do_write:
 406        if (addr < NVRAM->size) {
 407            NVRAM->buffer[addr] = val & 0xFF;
 408        }
 409        break;
 410    }
 411}
 412
 413static uint32_t m48t59_read(M48t59State *NVRAM, uint32_t addr)
 414{
 415    struct tm tm;
 416    uint32_t retval = 0xFF;
 417
 418    /* check for NVRAM access */
 419    if ((NVRAM->model == 2 && addr < 0x078f) ||
 420        (NVRAM->model == 8 && addr < 0x1ff8) ||
 421        (NVRAM->model == 59 && addr < 0x1ff0)) {
 422        goto do_read;
 423    }
 424
 425    /* TOD access */
 426    switch (addr) {
 427    case 0x1FF0:
 428        /* flags register */
 429        goto do_read;
 430    case 0x1FF1:
 431        /* unused */
 432        retval = 0;
 433        break;
 434    case 0x1FF2:
 435        /* alarm seconds */
 436        goto do_read;
 437    case 0x1FF3:
 438        /* alarm minutes */
 439        goto do_read;
 440    case 0x1FF4:
 441        /* alarm hours */
 442        goto do_read;
 443    case 0x1FF5:
 444        /* alarm date */
 445        goto do_read;
 446    case 0x1FF6:
 447        /* interrupts */
 448        goto do_read;
 449    case 0x1FF7:
 450        /* A read resets the watchdog */
 451        set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
 452        goto do_read;
 453    case 0x1FF8:
 454    case 0x07F8:
 455        /* control */
 456        goto do_read;
 457    case 0x1FF9:
 458    case 0x07F9:
 459        /* seconds (BCD) */
 460        get_time(NVRAM, &tm);
 461        retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
 462        break;
 463    case 0x1FFA:
 464    case 0x07FA:
 465        /* minutes (BCD) */
 466        get_time(NVRAM, &tm);
 467        retval = to_bcd(tm.tm_min);
 468        break;
 469    case 0x1FFB:
 470    case 0x07FB:
 471        /* hours (BCD) */
 472        get_time(NVRAM, &tm);
 473        retval = to_bcd(tm.tm_hour);
 474        break;
 475    case 0x1FFC:
 476    case 0x07FC:
 477        /* day of the week / century */
 478        get_time(NVRAM, &tm);
 479        retval = NVRAM->buffer[addr] | tm.tm_wday;
 480        break;
 481    case 0x1FFD:
 482    case 0x07FD:
 483        /* date */
 484        get_time(NVRAM, &tm);
 485        retval = to_bcd(tm.tm_mday);
 486        break;
 487    case 0x1FFE:
 488    case 0x07FE:
 489        /* month */
 490        get_time(NVRAM, &tm);
 491        retval = to_bcd(tm.tm_mon + 1);
 492        break;
 493    case 0x1FFF:
 494    case 0x07FF:
 495        /* year */
 496        get_time(NVRAM, &tm);
 497        retval = to_bcd((tm.tm_year + 1900 - NVRAM->base_year) % 100);
 498        break;
 499    default:
 500        /* Check lock registers state */
 501        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
 502            break;
 503        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
 504            break;
 505    do_read:
 506        if (addr < NVRAM->size) {
 507            retval = NVRAM->buffer[addr];
 508        }
 509        break;
 510    }
 511    if (addr > 0x1FF9 && addr < 0x2000)
 512       NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
 513
 514    return retval;
 515}
 516
 517static void m48t59_toggle_lock(M48t59State *NVRAM, int lock)
 518{
 519    NVRAM->lock ^= 1 << lock;
 520}
 521
 522/* IO access to NVRAM */
 523static void NVRAM_writeb(void *opaque, hwaddr addr, uint64_t val,
 524                         unsigned size)
 525{
 526    M48t59State *NVRAM = opaque;
 527
 528    NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
 529    switch (addr) {
 530    case 0:
 531        NVRAM->addr &= ~0x00FF;
 532        NVRAM->addr |= val;
 533        break;
 534    case 1:
 535        NVRAM->addr &= ~0xFF00;
 536        NVRAM->addr |= val << 8;
 537        break;
 538    case 3:
 539        m48t59_write(NVRAM, NVRAM->addr, val);
 540        NVRAM->addr = 0x0000;
 541        break;
 542    default:
 543        break;
 544    }
 545}
 546
 547static uint64_t NVRAM_readb(void *opaque, hwaddr addr, unsigned size)
 548{
 549    M48t59State *NVRAM = opaque;
 550    uint32_t retval;
 551
 552    switch (addr) {
 553    case 3:
 554        retval = m48t59_read(NVRAM, NVRAM->addr);
 555        break;
 556    default:
 557        retval = -1;
 558        break;
 559    }
 560    NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
 561
 562    return retval;
 563}
 564
 565static void nvram_writeb (void *opaque, hwaddr addr, uint32_t value)
 566{
 567    M48t59State *NVRAM = opaque;
 568
 569    m48t59_write(NVRAM, addr, value & 0xff);
 570}
 571
 572static void nvram_writew (void *opaque, hwaddr addr, uint32_t value)
 573{
 574    M48t59State *NVRAM = opaque;
 575
 576    m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
 577    m48t59_write(NVRAM, addr + 1, value & 0xff);
 578}
 579
 580static void nvram_writel (void *opaque, hwaddr addr, uint32_t value)
 581{
 582    M48t59State *NVRAM = opaque;
 583
 584    m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
 585    m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
 586    m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
 587    m48t59_write(NVRAM, addr + 3, value & 0xff);
 588}
 589
 590static uint32_t nvram_readb (void *opaque, hwaddr addr)
 591{
 592    M48t59State *NVRAM = opaque;
 593    uint32_t retval;
 594
 595    retval = m48t59_read(NVRAM, addr);
 596    return retval;
 597}
 598
 599static uint32_t nvram_readw (void *opaque, hwaddr addr)
 600{
 601    M48t59State *NVRAM = opaque;
 602    uint32_t retval;
 603
 604    retval = m48t59_read(NVRAM, addr) << 8;
 605    retval |= m48t59_read(NVRAM, addr + 1);
 606    return retval;
 607}
 608
 609static uint32_t nvram_readl (void *opaque, hwaddr addr)
 610{
 611    M48t59State *NVRAM = opaque;
 612    uint32_t retval;
 613
 614    retval = m48t59_read(NVRAM, addr) << 24;
 615    retval |= m48t59_read(NVRAM, addr + 1) << 16;
 616    retval |= m48t59_read(NVRAM, addr + 2) << 8;
 617    retval |= m48t59_read(NVRAM, addr + 3);
 618    return retval;
 619}
 620
 621static const MemoryRegionOps nvram_ops = {
 622    .old_mmio = {
 623        .read = { nvram_readb, nvram_readw, nvram_readl, },
 624        .write = { nvram_writeb, nvram_writew, nvram_writel, },
 625    },
 626    .endianness = DEVICE_NATIVE_ENDIAN,
 627};
 628
 629static const VMStateDescription vmstate_m48t59 = {
 630    .name = "m48t59",
 631    .version_id = 1,
 632    .minimum_version_id = 1,
 633    .fields = (VMStateField[]) {
 634        VMSTATE_UINT8(lock, M48t59State),
 635        VMSTATE_UINT16(addr, M48t59State),
 636        VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size),
 637        VMSTATE_END_OF_LIST()
 638    }
 639};
 640
 641static void m48t59_reset_common(M48t59State *NVRAM)
 642{
 643    NVRAM->addr = 0;
 644    NVRAM->lock = 0;
 645    if (NVRAM->alrm_timer != NULL)
 646        timer_del(NVRAM->alrm_timer);
 647
 648    if (NVRAM->wd_timer != NULL)
 649        timer_del(NVRAM->wd_timer);
 650}
 651
 652static void m48t59_reset_isa(DeviceState *d)
 653{
 654    M48txxISAState *isa = M48TXX_ISA(d);
 655    M48t59State *NVRAM = &isa->state;
 656
 657    m48t59_reset_common(NVRAM);
 658}
 659
 660static void m48t59_reset_sysbus(DeviceState *d)
 661{
 662    M48txxSysBusState *sys = M48TXX_SYS_BUS(d);
 663    M48t59State *NVRAM = &sys->state;
 664
 665    m48t59_reset_common(NVRAM);
 666}
 667
 668static const MemoryRegionOps m48t59_io_ops = {
 669    .read = NVRAM_readb,
 670    .write = NVRAM_writeb,
 671    .impl = {
 672        .min_access_size = 1,
 673        .max_access_size = 1,
 674    },
 675    .endianness = DEVICE_LITTLE_ENDIAN,
 676};
 677
 678/* Initialisation routine */
 679Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
 680                   uint32_t io_base, uint16_t size, int base_year,
 681                   int model)
 682{
 683    DeviceState *dev;
 684    SysBusDevice *s;
 685    int i;
 686
 687    for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
 688        if (!m48txx_info[i].sysbus_name ||
 689            m48txx_info[i].size != size ||
 690            m48txx_info[i].model != model) {
 691            continue;
 692        }
 693
 694        dev = qdev_create(NULL, m48txx_info[i].sysbus_name);
 695        qdev_prop_set_int32(dev, "base-year", base_year);
 696        qdev_init_nofail(dev);
 697        s = SYS_BUS_DEVICE(dev);
 698        sysbus_connect_irq(s, 0, IRQ);
 699        if (io_base != 0) {
 700            memory_region_add_subregion(get_system_io(), io_base,
 701                                        sysbus_mmio_get_region(s, 1));
 702        }
 703        if (mem_base != 0) {
 704            sysbus_mmio_map(s, 0, mem_base);
 705        }
 706
 707        return NVRAM(s);
 708    }
 709
 710    assert(false);
 711    return NULL;
 712}
 713
 714Nvram *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
 715                       int base_year, int model)
 716{
 717    DeviceState *dev;
 718    int i;
 719
 720    for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
 721        if (!m48txx_info[i].isa_name ||
 722            m48txx_info[i].size != size ||
 723            m48txx_info[i].model != model) {
 724            continue;
 725        }
 726
 727        dev = DEVICE(isa_create(bus, m48txx_info[i].isa_name));
 728        qdev_prop_set_uint32(dev, "iobase", io_base);
 729        qdev_prop_set_int32(dev, "base-year", base_year);
 730        qdev_init_nofail(dev);
 731        return NVRAM(dev);
 732    }
 733
 734    assert(false);
 735    return NULL;
 736}
 737
 738static void m48t59_realize_common(M48t59State *s, Error **errp)
 739{
 740    s->buffer = g_malloc0(s->size);
 741    if (s->model == 59) {
 742        s->alrm_timer = timer_new_ns(rtc_clock, &alarm_cb, s);
 743        s->wd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &watchdog_cb, s);
 744    }
 745    qemu_get_timedate(&s->alarm, 0);
 746
 747    vmstate_register(NULL, -1, &vmstate_m48t59, s);
 748}
 749
 750static void m48t59_isa_realize(DeviceState *dev, Error **errp)
 751{
 752    M48txxISADeviceClass *u = M48TXX_ISA_GET_CLASS(dev);
 753    ISADevice *isadev = ISA_DEVICE(dev);
 754    M48txxISAState *d = M48TXX_ISA(dev);
 755    M48t59State *s = &d->state;
 756
 757    s->model = u->info.model;
 758    s->size = u->info.size;
 759    isa_init_irq(isadev, &s->IRQ, 8);
 760    m48t59_realize_common(s, errp);
 761    memory_region_init_io(&d->io, OBJECT(dev), &m48t59_io_ops, s, "m48t59", 4);
 762    if (d->io_base != 0) {
 763        isa_register_ioport(isadev, &d->io, d->io_base);
 764    }
 765}
 766
 767static int m48t59_init1(SysBusDevice *dev)
 768{
 769    M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(dev);
 770    M48txxSysBusState *d = M48TXX_SYS_BUS(dev);
 771    Object *o = OBJECT(dev);
 772    M48t59State *s = &d->state;
 773    Error *err = NULL;
 774
 775    s->model = u->info.model;
 776    s->size = u->info.size;
 777    sysbus_init_irq(dev, &s->IRQ);
 778
 779    memory_region_init_io(&s->iomem, o, &nvram_ops, s, "m48t59.nvram",
 780                          s->size);
 781    memory_region_init_io(&d->io, o, &m48t59_io_ops, s, "m48t59", 4);
 782    sysbus_init_mmio(dev, &s->iomem);
 783    sysbus_init_mmio(dev, &d->io);
 784    m48t59_realize_common(s, &err);
 785    if (err != NULL) {
 786        error_free(err);
 787        return -1;
 788    }
 789
 790    return 0;
 791}
 792
 793static uint32_t m48txx_isa_read(Nvram *obj, uint32_t addr)
 794{
 795    M48txxISAState *d = M48TXX_ISA(obj);
 796    return m48t59_read(&d->state, addr);
 797}
 798
 799static void m48txx_isa_write(Nvram *obj, uint32_t addr, uint32_t val)
 800{
 801    M48txxISAState *d = M48TXX_ISA(obj);
 802    m48t59_write(&d->state, addr, val);
 803}
 804
 805static void m48txx_isa_toggle_lock(Nvram *obj, int lock)
 806{
 807    M48txxISAState *d = M48TXX_ISA(obj);
 808    m48t59_toggle_lock(&d->state, lock);
 809}
 810
 811static Property m48t59_isa_properties[] = {
 812    DEFINE_PROP_INT32("base-year", M48txxISAState, state.base_year, 0),
 813    DEFINE_PROP_UINT32("iobase", M48txxISAState, io_base, 0x74),
 814    DEFINE_PROP_END_OF_LIST(),
 815};
 816
 817static void m48txx_isa_class_init(ObjectClass *klass, void *data)
 818{
 819    DeviceClass *dc = DEVICE_CLASS(klass);
 820    NvramClass *nc = NVRAM_CLASS(klass);
 821
 822    dc->realize = m48t59_isa_realize;
 823    dc->reset = m48t59_reset_isa;
 824    dc->props = m48t59_isa_properties;
 825    nc->read = m48txx_isa_read;
 826    nc->write = m48txx_isa_write;
 827    nc->toggle_lock = m48txx_isa_toggle_lock;
 828}
 829
 830static void m48txx_isa_concrete_class_init(ObjectClass *klass, void *data)
 831{
 832    M48txxISADeviceClass *u = M48TXX_ISA_CLASS(klass);
 833    M48txxInfo *info = data;
 834
 835    u->info = *info;
 836}
 837
 838static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr)
 839{
 840    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 841    return m48t59_read(&d->state, addr);
 842}
 843
 844static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val)
 845{
 846    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 847    m48t59_write(&d->state, addr, val);
 848}
 849
 850static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock)
 851{
 852    M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
 853    m48t59_toggle_lock(&d->state, lock);
 854}
 855
 856static Property m48t59_sysbus_properties[] = {
 857    DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
 858    DEFINE_PROP_END_OF_LIST(),
 859};
 860
 861static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
 862{
 863    DeviceClass *dc = DEVICE_CLASS(klass);
 864    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 865    NvramClass *nc = NVRAM_CLASS(klass);
 866
 867    k->init = m48t59_init1;
 868    dc->reset = m48t59_reset_sysbus;
 869    dc->props = m48t59_sysbus_properties;
 870    nc->read = m48txx_sysbus_read;
 871    nc->write = m48txx_sysbus_write;
 872    nc->toggle_lock = m48txx_sysbus_toggle_lock;
 873}
 874
 875static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
 876{
 877    M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
 878    M48txxInfo *info = data;
 879
 880    u->info = *info;
 881}
 882
 883static const TypeInfo nvram_info = {
 884    .name = TYPE_NVRAM,
 885    .parent = TYPE_INTERFACE,
 886    .class_size = sizeof(NvramClass),
 887};
 888
 889static const TypeInfo m48txx_sysbus_type_info = {
 890    .name = TYPE_M48TXX_SYS_BUS,
 891    .parent = TYPE_SYS_BUS_DEVICE,
 892    .instance_size = sizeof(M48txxSysBusState),
 893    .abstract = true,
 894    .class_init = m48txx_sysbus_class_init,
 895    .interfaces = (InterfaceInfo[]) {
 896        { TYPE_NVRAM },
 897        { }
 898    }
 899};
 900
 901static const TypeInfo m48txx_isa_type_info = {
 902    .name = TYPE_M48TXX_ISA,
 903    .parent = TYPE_ISA_DEVICE,
 904    .instance_size = sizeof(M48txxISAState),
 905    .abstract = true,
 906    .class_init = m48txx_isa_class_init,
 907    .interfaces = (InterfaceInfo[]) {
 908        { TYPE_NVRAM },
 909        { }
 910    }
 911};
 912
 913static void m48t59_register_types(void)
 914{
 915    TypeInfo sysbus_type_info = {
 916        .parent = TYPE_M48TXX_SYS_BUS,
 917        .class_size = sizeof(M48txxSysBusDeviceClass),
 918        .class_init = m48txx_sysbus_concrete_class_init,
 919    };
 920    TypeInfo isa_type_info = {
 921        .parent = TYPE_M48TXX_ISA,
 922        .class_size = sizeof(M48txxISADeviceClass),
 923        .class_init = m48txx_isa_concrete_class_init,
 924    };
 925    int i;
 926
 927    type_register_static(&nvram_info);
 928    type_register_static(&m48txx_sysbus_type_info);
 929    type_register_static(&m48txx_isa_type_info);
 930
 931    for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
 932        if (m48txx_info[i].sysbus_name) {
 933            sysbus_type_info.name = m48txx_info[i].sysbus_name;
 934            sysbus_type_info.class_data = &m48txx_info[i];
 935            type_register(&sysbus_type_info);
 936        }
 937
 938        if (m48txx_info[i].isa_name) {
 939            isa_type_info.name = m48txx_info[i].isa_name;
 940            isa_type_info.class_data = &m48txx_info[i];
 941            type_register(&isa_type_info);
 942        }
 943    }
 944}
 945
 946type_init(m48t59_register_types)
 947