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