qemu/hw/misc/macio/pmu.c
<<
>>
Prefs
   1/*
   2 * QEMU PowerMac PMU device support
   3 *
   4 * Copyright (c) 2016 Benjamin Herrenschmidt, IBM Corp.
   5 * Copyright (c) 2018 Mark Cave-Ayland
   6 *
   7 * Based on the CUDA device by:
   8 *
   9 * Copyright (c) 2004-2007 Fabrice Bellard
  10 * Copyright (c) 2007 Jocelyn Mayer
  11 *
  12 * Permission is hereby granted, free of charge, to any person obtaining a copy
  13 * of this software and associated documentation files (the "Software"), to deal
  14 * in the Software without restriction, including without limitation the rights
  15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  16 * copies of the Software, and to permit persons to whom the Software is
  17 * furnished to do so, subject to the following conditions:
  18 *
  19 * The above copyright notice and this permission notice shall be included in
  20 * all copies or substantial portions of the Software.
  21 *
  22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  28 * THE SOFTWARE.
  29 */
  30
  31#include "qemu/osdep.h"
  32#include "hw/hw.h"
  33#include "hw/ppc/mac.h"
  34#include "hw/input/adb.h"
  35#include "hw/misc/mos6522.h"
  36#include "hw/misc/macio/gpio.h"
  37#include "hw/misc/macio/pmu.h"
  38#include "qemu/timer.h"
  39#include "sysemu/sysemu.h"
  40#include "qemu/cutils.h"
  41#include "qemu/log.h"
  42#include "trace.h"
  43
  44
  45/* Bits in B data register: all active low */
  46#define TACK    0x08    /* Transfer request (input) */
  47#define TREQ    0x10    /* Transfer acknowledge (output) */
  48
  49/* PMU returns time_t's offset from Jan 1, 1904, not 1970 */
  50#define RTC_OFFSET                      2082844800
  51
  52#define VIA_TIMER_FREQ (4700000 / 6)
  53
  54static void via_update_irq(PMUState *s)
  55{
  56    MOS6522PMUState *mps = MOS6522_PMU(&s->mos6522_pmu);
  57    MOS6522State *ms = MOS6522(mps);
  58
  59    bool new_state = !!(ms->ifr & ms->ier & (SR_INT | T1_INT | T2_INT));
  60
  61    if (new_state != s->via_irq_state) {
  62        s->via_irq_state = new_state;
  63        qemu_set_irq(s->via_irq, new_state);
  64    }
  65}
  66
  67static void via_set_sr_int(void *opaque)
  68{
  69    PMUState *s = opaque;
  70    MOS6522PMUState *mps = MOS6522_PMU(&s->mos6522_pmu);
  71    MOS6522State *ms = MOS6522(mps);
  72    MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms);
  73
  74    mdc->set_sr_int(ms);
  75}
  76
  77static void pmu_update_extirq(PMUState *s)
  78{
  79    if ((s->intbits & s->intmask) != 0) {
  80        macio_set_gpio(s->gpio, 1, false);
  81    } else {
  82        macio_set_gpio(s->gpio, 1, true);
  83    }
  84}
  85
  86static void pmu_adb_poll(void *opaque)
  87{
  88    PMUState *s = opaque;
  89    int olen;
  90
  91    if (!(s->intbits & PMU_INT_ADB)) {
  92        olen = adb_poll(&s->adb_bus, s->adb_reply, s->adb_poll_mask);
  93        trace_pmu_adb_poll(olen);
  94
  95        if (olen > 0) {
  96            s->adb_reply_size = olen;
  97            s->intbits |= PMU_INT_ADB | PMU_INT_ADB_AUTO;
  98            pmu_update_extirq(s);
  99        }
 100    }
 101
 102    timer_mod(s->adb_poll_timer,
 103              qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30);
 104}
 105
 106static void pmu_one_sec_timer(void *opaque)
 107{
 108    PMUState *s = opaque;
 109
 110    trace_pmu_one_sec_timer();
 111
 112    s->intbits |= PMU_INT_TICK;
 113    pmu_update_extirq(s);
 114    s->one_sec_target += 1000;
 115
 116    timer_mod(s->one_sec_timer, s->one_sec_target);
 117}
 118
 119static void pmu_cmd_int_ack(PMUState *s,
 120                            const uint8_t *in_data, uint8_t in_len,
 121                            uint8_t *out_data, uint8_t *out_len)
 122{
 123    if (in_len != 0) {
 124        qemu_log_mask(LOG_GUEST_ERROR,
 125                      "PMU: INT_ACK command, invalid len: %d want: 0\n",
 126                      in_len);
 127        return;
 128    }
 129
 130    /* Make appropriate reply packet */
 131    if (s->intbits & PMU_INT_ADB) {
 132        if (!s->adb_reply_size) {
 133            qemu_log_mask(LOG_GUEST_ERROR,
 134                          "Odd, PMU_INT_ADB set with no reply in buffer\n");
 135        }
 136
 137        memcpy(out_data + 1, s->adb_reply, s->adb_reply_size);
 138        out_data[0] = s->intbits & (PMU_INT_ADB | PMU_INT_ADB_AUTO);
 139        *out_len = s->adb_reply_size + 1;
 140        s->intbits &= ~(PMU_INT_ADB | PMU_INT_ADB_AUTO);
 141        s->adb_reply_size = 0;
 142    } else {
 143        out_data[0] = s->intbits;
 144        s->intbits = 0;
 145        *out_len = 1;
 146    }
 147
 148    pmu_update_extirq(s);
 149}
 150
 151static void pmu_cmd_set_int_mask(PMUState *s,
 152                                 const uint8_t *in_data, uint8_t in_len,
 153                                 uint8_t *out_data, uint8_t *out_len)
 154{
 155    if (in_len != 1) {
 156        qemu_log_mask(LOG_GUEST_ERROR,
 157                      "PMU: SET_INT_MASK command, invalid len: %d want: 1\n",
 158                      in_len);
 159        return;
 160    }
 161
 162    trace_pmu_cmd_set_int_mask(s->intmask);
 163    s->intmask = in_data[0];
 164
 165    pmu_update_extirq(s);
 166}
 167
 168static void pmu_cmd_set_adb_autopoll(PMUState *s, uint16_t mask)
 169{
 170    trace_pmu_cmd_set_adb_autopoll(mask);
 171
 172    if (s->autopoll_mask == mask) {
 173        return;
 174    }
 175
 176    s->autopoll_mask = mask;
 177    if (mask) {
 178        timer_mod(s->adb_poll_timer,
 179                  qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 30);
 180    } else {
 181        timer_del(s->adb_poll_timer);
 182    }
 183}
 184
 185static void pmu_cmd_adb(PMUState *s,
 186                        const uint8_t *in_data, uint8_t in_len,
 187                        uint8_t *out_data, uint8_t *out_len)
 188{
 189    int len, adblen;
 190    uint8_t adb_cmd[255];
 191
 192    if (in_len < 2) {
 193        qemu_log_mask(LOG_GUEST_ERROR,
 194                      "PMU: ADB PACKET, invalid len: %d want at least 2\n",
 195                      in_len);
 196        return;
 197    }
 198
 199    *out_len = 0;
 200
 201    if (!s->has_adb) {
 202        trace_pmu_cmd_adb_nobus();
 203        return;
 204    }
 205
 206    /* Set autopoll is a special form of the command */
 207    if (in_data[0] == 0 && in_data[1] == 0x86) {
 208        uint16_t mask = in_data[2];
 209        mask = (mask << 8) | in_data[3];
 210        if (in_len != 4) {
 211            qemu_log_mask(LOG_GUEST_ERROR,
 212                          "PMU: ADB Autopoll requires 4 bytes, got %d\n",
 213                          in_len);
 214            return;
 215        }
 216
 217        pmu_cmd_set_adb_autopoll(s, mask);
 218        return;
 219    }
 220
 221    trace_pmu_cmd_adb_request(in_len, in_data[0], in_data[1], in_data[2],
 222                              in_data[3], in_data[4]);
 223
 224    *out_len = 0;
 225
 226    /* Check ADB len */
 227    adblen = in_data[2];
 228    if (adblen > (in_len - 3)) {
 229        qemu_log_mask(LOG_GUEST_ERROR,
 230                      "PMU: ADB len is %d > %d (in_len -3)...erroring\n",
 231                      adblen, in_len - 3);
 232        len = -1;
 233    } else if (adblen > 252) {
 234        qemu_log_mask(LOG_GUEST_ERROR, "PMU: ADB command too big!\n");
 235        len = -1;
 236    } else {
 237        /* Format command */
 238        adb_cmd[0] = in_data[0];
 239        memcpy(&adb_cmd[1], &in_data[3], in_len - 3);
 240        len = adb_request(&s->adb_bus, s->adb_reply + 2, adb_cmd, in_len - 2);
 241
 242        trace_pmu_cmd_adb_reply(len);
 243    }
 244
 245    if (len > 0) {
 246        /* XXX Check this */
 247        s->adb_reply_size = len + 2;
 248        s->adb_reply[0] = 0x01;
 249        s->adb_reply[1] = len;
 250    } else {
 251        /* XXX Check this */
 252        s->adb_reply_size = 1;
 253        s->adb_reply[0] = 0x00;
 254    }
 255
 256    s->intbits |= PMU_INT_ADB;
 257    pmu_update_extirq(s);
 258}
 259
 260static void pmu_cmd_adb_poll_off(PMUState *s,
 261                                 const uint8_t *in_data, uint8_t in_len,
 262                                 uint8_t *out_data, uint8_t *out_len)
 263{
 264    if (in_len != 0) {
 265        qemu_log_mask(LOG_GUEST_ERROR,
 266                      "PMU: ADB POLL OFF command, invalid len: %d want: 0\n",
 267                      in_len);
 268        return;
 269    }
 270
 271    if (s->has_adb && s->autopoll_mask) {
 272        timer_del(s->adb_poll_timer);
 273        s->autopoll_mask = false;
 274    }
 275}
 276
 277static void pmu_cmd_shutdown(PMUState *s,
 278                             const uint8_t *in_data, uint8_t in_len,
 279                             uint8_t *out_data, uint8_t *out_len)
 280{
 281    if (in_len != 4) {
 282        qemu_log_mask(LOG_GUEST_ERROR,
 283                      "PMU: SHUTDOWN command, invalid len: %d want: 4\n",
 284                      in_len);
 285        return;
 286    }
 287
 288    *out_len = 1;
 289    out_data[0] = 0;
 290
 291    if (in_data[0] != 'M' || in_data[1] != 'A' || in_data[2] != 'T' ||
 292        in_data[3] != 'T') {
 293
 294        qemu_log_mask(LOG_GUEST_ERROR,
 295                      "PMU: SHUTDOWN command, Bad MATT signature\n");
 296        return;
 297    }
 298
 299    qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
 300}
 301
 302static void pmu_cmd_reset(PMUState *s,
 303                          const uint8_t *in_data, uint8_t in_len,
 304                          uint8_t *out_data, uint8_t *out_len)
 305{
 306    if (in_len != 0) {
 307        qemu_log_mask(LOG_GUEST_ERROR,
 308                      "PMU: RESET command, invalid len: %d want: 0\n",
 309                      in_len);
 310        return;
 311    }
 312
 313    qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
 314}
 315
 316static void pmu_cmd_get_rtc(PMUState *s,
 317                            const uint8_t *in_data, uint8_t in_len,
 318                            uint8_t *out_data, uint8_t *out_len)
 319{
 320    uint32_t ti;
 321
 322    if (in_len != 0) {
 323        qemu_log_mask(LOG_GUEST_ERROR,
 324                      "PMU: GET_RTC command, invalid len: %d want: 0\n",
 325                      in_len);
 326        return;
 327    }
 328
 329    ti = s->tick_offset + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
 330                           / NANOSECONDS_PER_SECOND);
 331    out_data[0] = ti >> 24;
 332    out_data[1] = ti >> 16;
 333    out_data[2] = ti >> 8;
 334    out_data[3] = ti;
 335    *out_len = 4;
 336}
 337
 338static void pmu_cmd_set_rtc(PMUState *s,
 339                            const uint8_t *in_data, uint8_t in_len,
 340                            uint8_t *out_data, uint8_t *out_len)
 341{
 342    uint32_t ti;
 343
 344    if (in_len != 4) {
 345        qemu_log_mask(LOG_GUEST_ERROR,
 346                      "PMU: SET_RTC command, invalid len: %d want: 4\n",
 347                      in_len);
 348        return;
 349    }
 350
 351    ti = (((uint32_t)in_data[0]) << 24) + (((uint32_t)in_data[1]) << 16)
 352         + (((uint32_t)in_data[2]) << 8) + in_data[3];
 353
 354    s->tick_offset = ti - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)
 355                           / NANOSECONDS_PER_SECOND);
 356}
 357
 358static void pmu_cmd_system_ready(PMUState *s,
 359                                 const uint8_t *in_data, uint8_t in_len,
 360                                 uint8_t *out_data, uint8_t *out_len)
 361{
 362    /* Do nothing */
 363}
 364
 365static void pmu_cmd_get_version(PMUState *s,
 366                                const uint8_t *in_data, uint8_t in_len,
 367                                uint8_t *out_data, uint8_t *out_len)
 368{
 369    *out_len = 1;
 370    *out_data = 1; /* ??? Check what Apple does */
 371}
 372
 373static void pmu_cmd_power_events(PMUState *s,
 374                                 const uint8_t *in_data, uint8_t in_len,
 375                                 uint8_t *out_data, uint8_t *out_len)
 376{
 377    if (in_len < 1) {
 378        qemu_log_mask(LOG_GUEST_ERROR,
 379                      "PMU: POWER EVENTS command, invalid len %d, want at least 1\n",
 380                      in_len);
 381        return;
 382    }
 383
 384    switch (in_data[0]) {
 385    /* Dummies for now */
 386    case PMU_PWR_GET_POWERUP_EVENTS:
 387        *out_len = 2;
 388        out_data[0] = 0;
 389        out_data[1] = 0;
 390        break;
 391    case PMU_PWR_SET_POWERUP_EVENTS:
 392    case PMU_PWR_CLR_POWERUP_EVENTS:
 393        break;
 394    case PMU_PWR_GET_WAKEUP_EVENTS:
 395        *out_len = 2;
 396        out_data[0] = 0;
 397        out_data[1] = 0;
 398        break;
 399    case PMU_PWR_SET_WAKEUP_EVENTS:
 400    case PMU_PWR_CLR_WAKEUP_EVENTS:
 401        break;
 402    default:
 403        qemu_log_mask(LOG_GUEST_ERROR,
 404                      "PMU: POWER EVENTS unknown subcommand 0x%02x\n",
 405                      in_data[0]);
 406    }
 407}
 408
 409static void pmu_cmd_get_cover(PMUState *s,
 410                              const uint8_t *in_data, uint8_t in_len,
 411                              uint8_t *out_data, uint8_t *out_len)
 412{
 413    /* Not 100% sure here, will have to check what a real Mac
 414     * returns other than byte 0 bit 0 is LID closed on laptops
 415     */
 416    *out_len = 1;
 417    *out_data = 0x00;
 418}
 419
 420static void pmu_cmd_download_status(PMUState *s,
 421                                    const uint8_t *in_data, uint8_t in_len,
 422                                    uint8_t *out_data, uint8_t *out_len)
 423{
 424    /* This has to do with PMU firmware updates as far as I can tell.
 425     *
 426     * We return 0x62 which is what OpenPMU expects
 427     */
 428    *out_len = 1;
 429    *out_data = 0x62;
 430}
 431
 432static void pmu_cmd_read_pmu_ram(PMUState *s,
 433                                 const uint8_t *in_data, uint8_t in_len,
 434                                 uint8_t *out_data, uint8_t *out_len)
 435{
 436    if (in_len < 3) {
 437        qemu_log_mask(LOG_GUEST_ERROR,
 438                      "PMU: READ_PMU_RAM command, invalid len %d, expected 3\n",
 439                      in_len);
 440        return;
 441    }
 442
 443    qemu_log_mask(LOG_GUEST_ERROR,
 444                  "PMU: Unsupported READ_PMU_RAM, args: %02x %02x %02x\n",
 445                  in_data[0], in_data[1], in_data[2]);
 446
 447    *out_len = 0;
 448}
 449
 450/* description of commands */
 451typedef struct PMUCmdHandler {
 452    uint8_t command;
 453    const char *name;
 454    void (*handler)(PMUState *s,
 455                    const uint8_t *in_args, uint8_t in_len,
 456                    uint8_t *out_args, uint8_t *out_len);
 457} PMUCmdHandler;
 458
 459static const PMUCmdHandler PMUCmdHandlers[] = {
 460    { PMU_INT_ACK, "INT ACK", pmu_cmd_int_ack },
 461    { PMU_SET_INTR_MASK, "SET INT MASK", pmu_cmd_set_int_mask },
 462    { PMU_ADB_CMD, "ADB COMMAND", pmu_cmd_adb },
 463    { PMU_ADB_POLL_OFF, "ADB POLL OFF", pmu_cmd_adb_poll_off },
 464    { PMU_RESET, "REBOOT", pmu_cmd_reset },
 465    { PMU_SHUTDOWN, "SHUTDOWN", pmu_cmd_shutdown },
 466    { PMU_READ_RTC, "GET RTC", pmu_cmd_get_rtc },
 467    { PMU_SET_RTC, "SET RTC", pmu_cmd_set_rtc },
 468    { PMU_SYSTEM_READY, "SYSTEM READY", pmu_cmd_system_ready },
 469    { PMU_GET_VERSION, "GET VERSION", pmu_cmd_get_version },
 470    { PMU_POWER_EVENTS, "POWER EVENTS", pmu_cmd_power_events },
 471    { PMU_GET_COVER, "GET_COVER", pmu_cmd_get_cover },
 472    { PMU_DOWNLOAD_STATUS, "DOWNLOAD STATUS", pmu_cmd_download_status },
 473    { PMU_READ_PMU_RAM, "READ PMGR RAM", pmu_cmd_read_pmu_ram },
 474};
 475
 476static void pmu_dispatch_cmd(PMUState *s)
 477{
 478    unsigned int i;
 479
 480    /* No response by default */
 481    s->cmd_rsp_sz = 0;
 482
 483    for (i = 0; i < ARRAY_SIZE(PMUCmdHandlers); i++) {
 484        const PMUCmdHandler *desc = &PMUCmdHandlers[i];
 485
 486        if (desc->command != s->cmd) {
 487            continue;
 488        }
 489
 490        trace_pmu_dispatch_cmd(desc->name);
 491        desc->handler(s, s->cmd_buf, s->cmd_buf_pos,
 492                      s->cmd_rsp, &s->cmd_rsp_sz);
 493
 494        if (s->rsplen != -1 && s->rsplen != s->cmd_rsp_sz) {
 495            trace_pmu_debug_protocol_string("QEMU internal cmd resp mismatch!");
 496        } else {
 497            trace_pmu_debug_protocol_resp_size(s->cmd_rsp_sz);
 498        }
 499
 500        return;
 501    }
 502
 503    trace_pmu_dispatch_unknown_cmd(s->cmd);
 504
 505    /* Manufacture fake response with 0's */
 506    if (s->rsplen == -1) {
 507        s->cmd_rsp_sz = 0;
 508    } else {
 509        s->cmd_rsp_sz = s->rsplen;
 510        memset(s->cmd_rsp, 0, s->rsplen);
 511    }
 512}
 513
 514static void pmu_update(PMUState *s)
 515{
 516    MOS6522PMUState *mps = &s->mos6522_pmu;
 517    MOS6522State *ms = MOS6522(mps);
 518
 519    /* Only react to changes in reg B */
 520    if (ms->b == s->last_b) {
 521        return;
 522    }
 523    s->last_b = ms->b;
 524
 525    /* Check the TREQ / TACK state */
 526    switch (ms->b & (TREQ | TACK)) {
 527    case TREQ:
 528        /* This is an ack release, handle it and bail out */
 529        ms->b |= TACK;
 530        s->last_b = ms->b;
 531
 532        trace_pmu_debug_protocol_string("handshake: TREQ high, setting TACK");
 533        return;
 534    case TACK:
 535        /* This is a valid request, handle below */
 536        break;
 537    case TREQ | TACK:
 538        /* This is an idle state */
 539        return;
 540    default:
 541        /* Invalid state, log and ignore */
 542        trace_pmu_debug_protocol_error(ms->b);
 543        return;
 544    }
 545
 546    /* If we wanted to handle commands asynchronously, this is where
 547     * we would delay the clearing of TACK until we are ready to send
 548     * the response
 549     */
 550
 551    /* We have a request, handshake TACK so we don't stay in
 552     * an invalid state. If we were concurrent with the OS we
 553     * should only do this after we grabbed the SR but that isn't
 554     * a problem here.
 555     */
 556
 557    trace_pmu_debug_protocol_clear_treq(s->cmd_state);
 558
 559    ms->b &= ~TACK;
 560    s->last_b = ms->b;
 561
 562    /* Act according to state */
 563    switch (s->cmd_state) {
 564    case pmu_state_idle:
 565        if (!(ms->acr & SR_OUT)) {
 566            trace_pmu_debug_protocol_string("protocol error! "
 567                                            "state idle, ACR reading");
 568            break;
 569        }
 570
 571        s->cmd = ms->sr;
 572        via_set_sr_int(s);
 573        s->cmdlen = pmu_data_len[s->cmd][0];
 574        s->rsplen = pmu_data_len[s->cmd][1];
 575        s->cmd_buf_pos = 0;
 576        s->cmd_rsp_pos = 0;
 577        s->cmd_state = pmu_state_cmd;
 578
 579        trace_pmu_debug_protocol_cmd(s->cmd, s->cmdlen, s->rsplen);
 580        break;
 581
 582    case pmu_state_cmd:
 583        if (!(ms->acr & SR_OUT)) {
 584            trace_pmu_debug_protocol_string("protocol error! "
 585                                            "state cmd, ACR reading");
 586            break;
 587        }
 588
 589        if (s->cmdlen == -1) {
 590            trace_pmu_debug_protocol_cmdlen(ms->sr);
 591
 592            s->cmdlen = ms->sr;
 593            if (s->cmdlen > sizeof(s->cmd_buf)) {
 594                trace_pmu_debug_protocol_cmd_toobig(s->cmdlen);
 595            }
 596        } else if (s->cmd_buf_pos < sizeof(s->cmd_buf)) {
 597            s->cmd_buf[s->cmd_buf_pos++] = ms->sr;
 598        }
 599
 600        via_set_sr_int(s);
 601        break;
 602
 603    case pmu_state_rsp:
 604        if (ms->acr & SR_OUT) {
 605            trace_pmu_debug_protocol_string("protocol error! "
 606                                            "state resp, ACR writing");
 607            break;
 608        }
 609
 610        if (s->rsplen == -1) {
 611            trace_pmu_debug_protocol_cmd_send_resp_size(s->cmd_rsp_sz);
 612
 613            ms->sr = s->cmd_rsp_sz;
 614            s->rsplen = s->cmd_rsp_sz;
 615        } else if (s->cmd_rsp_pos < s->cmd_rsp_sz) {
 616            trace_pmu_debug_protocol_cmd_send_resp(s->cmd_rsp_pos, s->rsplen);
 617
 618            ms->sr = s->cmd_rsp[s->cmd_rsp_pos++];
 619        }
 620
 621        via_set_sr_int(s);
 622        break;
 623    }
 624
 625    /* Check for state completion */
 626    if (s->cmd_state == pmu_state_cmd && s->cmdlen == s->cmd_buf_pos) {
 627        trace_pmu_debug_protocol_string("Command reception complete, "
 628                                        "dispatching...");
 629
 630        pmu_dispatch_cmd(s);
 631        s->cmd_state = pmu_state_rsp;
 632    }
 633
 634    if (s->cmd_state == pmu_state_rsp && s->rsplen == s->cmd_rsp_pos) {
 635        trace_pmu_debug_protocol_cmd_resp_complete(ms->ier);
 636
 637        s->cmd_state = pmu_state_idle;
 638    }
 639}
 640
 641static uint64_t mos6522_pmu_read(void *opaque, hwaddr addr, unsigned size)
 642{
 643    PMUState *s = opaque;
 644    MOS6522PMUState *mps = &s->mos6522_pmu;
 645    MOS6522State *ms = MOS6522(mps);
 646
 647    addr = (addr >> 9) & 0xf;
 648    return mos6522_read(ms, addr, size);
 649}
 650
 651static void mos6522_pmu_write(void *opaque, hwaddr addr, uint64_t val,
 652                              unsigned size)
 653{
 654    PMUState *s = opaque;
 655    MOS6522PMUState *mps = &s->mos6522_pmu;
 656    MOS6522State *ms = MOS6522(mps);
 657
 658    addr = (addr >> 9) & 0xf;
 659    mos6522_write(ms, addr, val, size);
 660}
 661
 662static const MemoryRegionOps mos6522_pmu_ops = {
 663    .read = mos6522_pmu_read,
 664    .write = mos6522_pmu_write,
 665    .endianness = DEVICE_BIG_ENDIAN,
 666    .impl = {
 667        .min_access_size = 1,
 668        .max_access_size = 1,
 669    },
 670};
 671
 672static bool pmu_adb_state_needed(void *opaque)
 673{
 674    PMUState *s = opaque;
 675
 676    return s->has_adb;
 677}
 678
 679static const VMStateDescription vmstate_pmu_adb = {
 680    .name = "pmu/adb",
 681    .version_id = 0,
 682    .minimum_version_id = 0,
 683    .needed = pmu_adb_state_needed,
 684    .fields = (VMStateField[]) {
 685        VMSTATE_UINT16(adb_poll_mask, PMUState),
 686        VMSTATE_TIMER_PTR(adb_poll_timer, PMUState),
 687        VMSTATE_UINT8(adb_reply_size, PMUState),
 688        VMSTATE_BUFFER(adb_reply, PMUState),
 689    }
 690};
 691
 692static const VMStateDescription vmstate_pmu = {
 693    .name = "pmu",
 694    .version_id = 0,
 695    .minimum_version_id = 0,
 696    .fields = (VMStateField[]) {
 697        VMSTATE_STRUCT(mos6522_pmu.parent_obj, PMUState, 0, vmstate_mos6522,
 698                       MOS6522State),
 699        VMSTATE_UINT8(last_b, PMUState),
 700        VMSTATE_UINT8(cmd, PMUState),
 701        VMSTATE_UINT32(cmdlen, PMUState),
 702        VMSTATE_UINT32(rsplen, PMUState),
 703        VMSTATE_UINT8(cmd_buf_pos, PMUState),
 704        VMSTATE_BUFFER(cmd_buf, PMUState),
 705        VMSTATE_UINT8(cmd_rsp_pos, PMUState),
 706        VMSTATE_UINT8(cmd_rsp_sz, PMUState),
 707        VMSTATE_BUFFER(cmd_rsp, PMUState),
 708        VMSTATE_UINT8(intbits, PMUState),
 709        VMSTATE_UINT8(intmask, PMUState),
 710        VMSTATE_UINT8(autopoll_rate_ms, PMUState),
 711        VMSTATE_UINT8(autopoll_mask, PMUState),
 712        VMSTATE_UINT32(tick_offset, PMUState),
 713        VMSTATE_TIMER_PTR(one_sec_timer, PMUState),
 714        VMSTATE_INT64(one_sec_target, PMUState),
 715        VMSTATE_END_OF_LIST()
 716    },
 717    .subsections = (const VMStateDescription * []) {
 718        &vmstate_pmu_adb,
 719    }
 720};
 721
 722static void pmu_reset(DeviceState *dev)
 723{
 724    PMUState *s = VIA_PMU(dev);
 725
 726    /* OpenBIOS needs to do this? MacOS 9 needs it */
 727    s->intmask = PMU_INT_ADB | PMU_INT_TICK;
 728    s->intbits = 0;
 729
 730    s->cmd_state = pmu_state_idle;
 731    s->autopoll_mask = 0;
 732}
 733
 734static void pmu_realize(DeviceState *dev, Error **errp)
 735{
 736    PMUState *s = VIA_PMU(dev);
 737    SysBusDevice *sbd;
 738    MOS6522State *ms;
 739    DeviceState *d;
 740    struct tm tm;
 741
 742    /* Pass IRQ from 6522 */
 743    d = DEVICE(&s->mos6522_pmu);
 744    ms = MOS6522(d);
 745    sbd = SYS_BUS_DEVICE(s);
 746    sysbus_pass_irq(sbd, SYS_BUS_DEVICE(ms));
 747
 748    qemu_get_timedate(&tm, 0);
 749    s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET;
 750    s->one_sec_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, pmu_one_sec_timer, s);
 751    s->one_sec_target = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 1000;
 752    timer_mod(s->one_sec_timer, s->one_sec_target);
 753
 754    if (s->has_adb) {
 755        qbus_create_inplace(&s->adb_bus, sizeof(s->adb_bus), TYPE_ADB_BUS,
 756                            DEVICE(dev), "adb.0");
 757        s->adb_poll_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, pmu_adb_poll, s);
 758        s->adb_poll_mask = 0xffff;
 759        s->autopoll_rate_ms = 20;
 760    }
 761}
 762
 763static void pmu_init(Object *obj)
 764{
 765    SysBusDevice *d = SYS_BUS_DEVICE(obj);
 766    PMUState *s = VIA_PMU(obj);
 767
 768    object_property_add_link(obj, "gpio", TYPE_MACIO_GPIO,
 769                             (Object **) &s->gpio,
 770                             qdev_prop_allow_set_link_before_realize,
 771                             0, NULL);
 772
 773    sysbus_init_child_obj(obj, "mos6522-pmu", &s->mos6522_pmu,
 774                          sizeof(s->mos6522_pmu), TYPE_MOS6522_PMU);
 775
 776    memory_region_init_io(&s->mem, obj, &mos6522_pmu_ops, s, "via-pmu",
 777                          0x2000);
 778    sysbus_init_mmio(d, &s->mem);
 779}
 780
 781static Property pmu_properties[] = {
 782    DEFINE_PROP_BOOL("has-adb", PMUState, has_adb, true),
 783    DEFINE_PROP_END_OF_LIST()
 784};
 785
 786static void pmu_class_init(ObjectClass *oc, void *data)
 787{
 788    DeviceClass *dc = DEVICE_CLASS(oc);
 789
 790    dc->realize = pmu_realize;
 791    dc->reset = pmu_reset;
 792    dc->vmsd = &vmstate_pmu;
 793    dc->props = pmu_properties;
 794    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
 795}
 796
 797static const TypeInfo pmu_type_info = {
 798    .name = TYPE_VIA_PMU,
 799    .parent = TYPE_SYS_BUS_DEVICE,
 800    .instance_size = sizeof(PMUState),
 801    .instance_init = pmu_init,
 802    .class_init = pmu_class_init,
 803};
 804
 805static void mos6522_pmu_portB_write(MOS6522State *s)
 806{
 807    MOS6522PMUState *mps = container_of(s, MOS6522PMUState, parent_obj);
 808    PMUState *ps = container_of(mps, PMUState, mos6522_pmu);
 809
 810    if ((s->pcr & 0xe0) == 0x20 || (s->pcr & 0xe0) == 0x60) {
 811        s->ifr &= ~CB2_INT;
 812    }
 813    s->ifr &= ~CB1_INT;
 814
 815    via_update_irq(ps);
 816    pmu_update(ps);
 817}
 818
 819static void mos6522_pmu_portA_write(MOS6522State *s)
 820{
 821    MOS6522PMUState *mps = container_of(s, MOS6522PMUState, parent_obj);
 822    PMUState *ps = container_of(mps, PMUState, mos6522_pmu);
 823
 824    if ((s->pcr & 0x0e) == 0x02 || (s->pcr & 0x0e) == 0x06) {
 825        s->ifr &= ~CA2_INT;
 826    }
 827    s->ifr &= ~CA1_INT;
 828
 829    via_update_irq(ps);
 830}
 831
 832static void mos6522_pmu_reset(DeviceState *dev)
 833{
 834    MOS6522State *ms = MOS6522(dev);
 835    MOS6522PMUState *mps = container_of(ms, MOS6522PMUState, parent_obj);
 836    PMUState *s = container_of(mps, PMUState, mos6522_pmu);
 837    MOS6522DeviceClass *mdc = MOS6522_DEVICE_GET_CLASS(ms);
 838
 839    mdc->parent_reset(dev);
 840
 841    ms->timers[0].frequency = VIA_TIMER_FREQ;
 842    ms->timers[1].frequency = (SCALE_US * 6000) / 4700;
 843
 844    s->last_b = ms->b = TACK | TREQ;
 845}
 846
 847static void mos6522_pmu_class_init(ObjectClass *oc, void *data)
 848{
 849    DeviceClass *dc = DEVICE_CLASS(oc);
 850    MOS6522DeviceClass *mdc = MOS6522_DEVICE_CLASS(oc);
 851
 852    dc->reset = mos6522_pmu_reset;
 853    mdc->portB_write = mos6522_pmu_portB_write;
 854    mdc->portA_write = mos6522_pmu_portA_write;
 855}
 856
 857static const TypeInfo mos6522_pmu_type_info = {
 858    .name = TYPE_MOS6522_PMU,
 859    .parent = TYPE_MOS6522,
 860    .instance_size = sizeof(MOS6522PMUState),
 861    .class_init = mos6522_pmu_class_init,
 862};
 863
 864static void pmu_register_types(void)
 865{
 866    type_register_static(&pmu_type_info);
 867    type_register_static(&mos6522_pmu_type_info);
 868}
 869
 870type_init(pmu_register_types)
 871