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