|
|
1.1 root 1: /* 1.1.1.3 ! root 2: * QEMU PowerMac CUDA device support ! 3: * ! 4: * Copyright (c) 2004-2007 Fabrice Bellard ! 5: * Copyright (c) 2007 Jocelyn Mayer ! 6: * 1.1 root 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: */ 1.1.1.3 ! root 25: #include "hw.h" ! 26: #include "ppc_mac.h" ! 27: #include "qemu-timer.h" ! 28: #include "sysemu.h" 1.1 root 29: 30: /* XXX: implement all timer modes */ 31: 32: //#define DEBUG_CUDA 33: //#define DEBUG_CUDA_PACKET 34: 35: /* Bits in B data register: all active low */ 36: #define TREQ 0x08 /* Transfer request (input) */ 37: #define TACK 0x10 /* Transfer acknowledge (output) */ 38: #define TIP 0x20 /* Transfer in progress (output) */ 39: 40: /* Bits in ACR */ 41: #define SR_CTRL 0x1c /* Shift register control bits */ 42: #define SR_EXT 0x0c /* Shift on external clock */ 43: #define SR_OUT 0x10 /* Shift out if 1 */ 44: 45: /* Bits in IFR and IER */ 46: #define IER_SET 0x80 /* set bits in IER */ 47: #define IER_CLR 0 /* clear bits in IER */ 48: #define SR_INT 0x04 /* Shift register full/empty */ 49: #define T1_INT 0x40 /* Timer 1 interrupt */ 50: #define T2_INT 0x20 /* Timer 2 interrupt */ 51: 52: /* Bits in ACR */ 53: #define T1MODE 0xc0 /* Timer 1 mode */ 54: #define T1MODE_CONT 0x40 /* continuous interrupts */ 55: 56: /* commands (1st byte) */ 57: #define ADB_PACKET 0 58: #define CUDA_PACKET 1 59: #define ERROR_PACKET 2 60: #define TIMER_PACKET 3 61: #define POWER_PACKET 4 62: #define MACIIC_PACKET 5 63: #define PMU_PACKET 6 64: 65: 66: /* CUDA commands (2nd byte) */ 67: #define CUDA_WARM_START 0x0 68: #define CUDA_AUTOPOLL 0x1 69: #define CUDA_GET_6805_ADDR 0x2 70: #define CUDA_GET_TIME 0x3 71: #define CUDA_GET_PRAM 0x7 72: #define CUDA_SET_6805_ADDR 0x8 73: #define CUDA_SET_TIME 0x9 74: #define CUDA_POWERDOWN 0xa 75: #define CUDA_POWERUP_TIME 0xb 76: #define CUDA_SET_PRAM 0xc 77: #define CUDA_MS_RESET 0xd 78: #define CUDA_SEND_DFAC 0xe 79: #define CUDA_BATTERY_SWAP_SENSE 0x10 80: #define CUDA_RESET_SYSTEM 0x11 81: #define CUDA_SET_IPL 0x12 82: #define CUDA_FILE_SERVER_FLAG 0x13 83: #define CUDA_SET_AUTO_RATE 0x14 84: #define CUDA_GET_AUTO_RATE 0x16 85: #define CUDA_SET_DEVICE_LIST 0x19 86: #define CUDA_GET_DEVICE_LIST 0x1a 87: #define CUDA_SET_ONE_SECOND_MODE 0x1b 88: #define CUDA_SET_POWER_MESSAGES 0x21 89: #define CUDA_GET_SET_IIC 0x22 90: #define CUDA_WAKEUP 0x23 91: #define CUDA_TIMER_TICKLE 0x24 92: #define CUDA_COMBINED_FORMAT_IIC 0x25 93: 94: #define CUDA_TIMER_FREQ (4700000 / 6) 95: #define CUDA_ADB_POLL_FREQ 50 96: 97: /* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */ 98: #define RTC_OFFSET 2082844800 99: 100: typedef struct CUDATimer { 1.1.1.3 ! root 101: int index; 1.1 root 102: uint16_t latch; 103: uint16_t counter_value; /* counter value at load time */ 104: int64_t load_time; 105: int64_t next_irq_time; 106: QEMUTimer *timer; 107: } CUDATimer; 108: 109: typedef struct CUDAState { 110: /* cuda registers */ 111: uint8_t b; /* B-side data */ 112: uint8_t a; /* A-side data */ 113: uint8_t dirb; /* B-side direction (1=output) */ 114: uint8_t dira; /* A-side direction (1=output) */ 115: uint8_t sr; /* Shift register */ 116: uint8_t acr; /* Auxiliary control register */ 117: uint8_t pcr; /* Peripheral control register */ 118: uint8_t ifr; /* Interrupt flag register */ 119: uint8_t ier; /* Interrupt enable register */ 120: uint8_t anh; /* A-side data, no handshake */ 121: 122: CUDATimer timers[2]; 1.1.1.3 ! root 123: 1.1 root 124: uint8_t last_b; /* last value of B register */ 125: uint8_t last_acr; /* last value of B register */ 1.1.1.3 ! root 126: 1.1 root 127: int data_in_size; 128: int data_in_index; 129: int data_out_index; 130: 1.1.1.3 ! root 131: qemu_irq irq; 1.1 root 132: uint8_t autopoll; 133: uint8_t data_in[128]; 134: uint8_t data_out[16]; 135: QEMUTimer *adb_poll_timer; 136: } CUDAState; 137: 138: static CUDAState cuda_state; 139: ADBBusState adb_bus; 140: 141: static void cuda_update(CUDAState *s); 1.1.1.3 ! root 142: static void cuda_receive_packet_from_host(CUDAState *s, 1.1 root 143: const uint8_t *data, int len); 1.1.1.3 ! root 144: static void cuda_timer_update(CUDAState *s, CUDATimer *ti, 1.1 root 145: int64_t current_time); 146: 147: static void cuda_update_irq(CUDAState *s) 148: { 149: if (s->ifr & s->ier & (SR_INT | T1_INT)) { 1.1.1.3 ! root 150: qemu_irq_raise(s->irq); 1.1 root 151: } else { 1.1.1.3 ! root 152: qemu_irq_lower(s->irq); 1.1 root 153: } 154: } 155: 156: static unsigned int get_counter(CUDATimer *s) 157: { 158: int64_t d; 159: unsigned int counter; 160: 1.1.1.3 ! root 161: d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, 1.1 root 162: CUDA_TIMER_FREQ, ticks_per_sec); 163: if (s->index == 0) { 164: /* the timer goes down from latch to -1 (period of latch + 2) */ 165: if (d <= (s->counter_value + 1)) { 166: counter = (s->counter_value - d) & 0xffff; 167: } else { 168: counter = (d - (s->counter_value + 1)) % (s->latch + 2); 1.1.1.3 ! root 169: counter = (s->latch - counter) & 0xffff; 1.1 root 170: } 171: } else { 172: counter = (s->counter_value - d) & 0xffff; 173: } 174: return counter; 175: } 176: 177: static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val) 178: { 179: #ifdef DEBUG_CUDA 180: printf("cuda: T%d.counter=%d\n", 181: 1 + (ti->timer == NULL), val); 182: #endif 183: ti->load_time = qemu_get_clock(vm_clock); 184: ti->counter_value = val; 185: cuda_timer_update(s, ti, ti->load_time); 186: } 187: 188: static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) 189: { 190: int64_t d, next_time; 191: unsigned int counter; 192: 193: /* current counter value */ 1.1.1.3 ! root 194: d = muldiv64(current_time - s->load_time, 1.1 root 195: CUDA_TIMER_FREQ, ticks_per_sec); 196: /* the timer goes down from latch to -1 (period of latch + 2) */ 197: if (d <= (s->counter_value + 1)) { 198: counter = (s->counter_value - d) & 0xffff; 199: } else { 200: counter = (d - (s->counter_value + 1)) % (s->latch + 2); 1.1.1.3 ! root 201: counter = (s->latch - counter) & 0xffff; 1.1 root 202: } 1.1.1.3 ! root 203: 1.1 root 204: /* Note: we consider the irq is raised on 0 */ 205: if (counter == 0xffff) { 206: next_time = d + s->latch + 1; 207: } else if (counter == 0) { 208: next_time = d + s->latch + 2; 209: } else { 210: next_time = d + counter; 211: } 212: #if 0 213: #ifdef DEBUG_CUDA 1.1.1.3 ! root 214: printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", 1.1 root 215: s->latch, d, next_time - d); 216: #endif 217: #endif 1.1.1.3 ! root 218: next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + 1.1 root 219: s->load_time; 220: if (next_time <= current_time) 221: next_time = current_time + 1; 222: return next_time; 223: } 224: 1.1.1.3 ! root 225: static void cuda_timer_update(CUDAState *s, CUDATimer *ti, 1.1 root 226: int64_t current_time) 227: { 228: if (!ti->timer) 229: return; 230: if ((s->acr & T1MODE) != T1MODE_CONT) { 231: qemu_del_timer(ti->timer); 232: } else { 233: ti->next_irq_time = get_next_irq_time(ti, current_time); 234: qemu_mod_timer(ti->timer, ti->next_irq_time); 235: } 236: } 237: 238: static void cuda_timer1(void *opaque) 239: { 240: CUDAState *s = opaque; 241: CUDATimer *ti = &s->timers[0]; 242: 243: cuda_timer_update(s, ti, ti->next_irq_time); 244: s->ifr |= T1_INT; 245: cuda_update_irq(s); 246: } 247: 248: static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) 249: { 250: CUDAState *s = opaque; 251: uint32_t val; 252: 253: addr = (addr >> 9) & 0xf; 254: switch(addr) { 255: case 0: 256: val = s->b; 257: break; 258: case 1: 259: val = s->a; 260: break; 261: case 2: 262: val = s->dirb; 263: break; 264: case 3: 265: val = s->dira; 266: break; 267: case 4: 268: val = get_counter(&s->timers[0]) & 0xff; 269: s->ifr &= ~T1_INT; 270: cuda_update_irq(s); 271: break; 272: case 5: 273: val = get_counter(&s->timers[0]) >> 8; 274: cuda_update_irq(s); 275: break; 276: case 6: 277: val = s->timers[0].latch & 0xff; 278: break; 279: case 7: 280: /* XXX: check this */ 281: val = (s->timers[0].latch >> 8) & 0xff; 282: break; 283: case 8: 284: val = get_counter(&s->timers[1]) & 0xff; 285: s->ifr &= ~T2_INT; 286: break; 287: case 9: 288: val = get_counter(&s->timers[1]) >> 8; 289: break; 290: case 10: 291: val = s->sr; 292: s->ifr &= ~SR_INT; 293: cuda_update_irq(s); 294: break; 295: case 11: 296: val = s->acr; 297: break; 298: case 12: 299: val = s->pcr; 300: break; 301: case 13: 302: val = s->ifr; 1.1.1.3 ! root 303: if (s->ifr & s->ier) 1.1 root 304: val |= 0x80; 305: break; 306: case 14: 307: val = s->ier | 0x80; 308: break; 309: default: 310: case 15: 311: val = s->anh; 312: break; 313: } 314: #ifdef DEBUG_CUDA 315: if (addr != 13 || val != 0) 316: printf("cuda: read: reg=0x%x val=%02x\n", addr, val); 317: #endif 318: return val; 319: } 320: 321: static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 322: { 323: CUDAState *s = opaque; 1.1.1.3 ! root 324: 1.1 root 325: addr = (addr >> 9) & 0xf; 326: #ifdef DEBUG_CUDA 327: printf("cuda: write: reg=0x%x val=%02x\n", addr, val); 328: #endif 329: 330: switch(addr) { 331: case 0: 332: s->b = val; 333: cuda_update(s); 334: break; 335: case 1: 336: s->a = val; 337: break; 338: case 2: 339: s->dirb = val; 340: break; 341: case 3: 342: s->dira = val; 343: break; 344: case 4: 345: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; 346: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); 347: break; 348: case 5: 349: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); 350: s->ifr &= ~T1_INT; 351: set_counter(s, &s->timers[0], s->timers[0].latch); 352: break; 353: case 6: 354: s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; 355: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); 356: break; 357: case 7: 358: s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); 359: s->ifr &= ~T1_INT; 360: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); 361: break; 362: case 8: 363: s->timers[1].latch = val; 364: set_counter(s, &s->timers[1], val); 365: break; 366: case 9: 367: set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch); 368: break; 369: case 10: 370: s->sr = val; 371: break; 372: case 11: 373: s->acr = val; 374: cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock)); 375: cuda_update(s); 376: break; 377: case 12: 378: s->pcr = val; 379: break; 380: case 13: 381: /* reset bits */ 382: s->ifr &= ~val; 383: cuda_update_irq(s); 384: break; 385: case 14: 386: if (val & IER_SET) { 387: /* set bits */ 388: s->ier |= val & 0x7f; 389: } else { 390: /* reset bits */ 391: s->ier &= ~val; 392: } 393: cuda_update_irq(s); 394: break; 395: default: 396: case 15: 397: s->anh = val; 398: break; 399: } 400: } 401: 402: /* NOTE: TIP and TREQ are negated */ 403: static void cuda_update(CUDAState *s) 404: { 405: int packet_received, len; 406: 407: packet_received = 0; 408: if (!(s->b & TIP)) { 409: /* transfer requested from host */ 410: 411: if (s->acr & SR_OUT) { 412: /* data output */ 413: if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { 414: if (s->data_out_index < sizeof(s->data_out)) { 415: #ifdef DEBUG_CUDA 416: printf("cuda: send: %02x\n", s->sr); 417: #endif 418: s->data_out[s->data_out_index++] = s->sr; 419: s->ifr |= SR_INT; 420: cuda_update_irq(s); 421: } 422: } 423: } else { 424: if (s->data_in_index < s->data_in_size) { 425: /* data input */ 426: if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { 427: s->sr = s->data_in[s->data_in_index++]; 428: #ifdef DEBUG_CUDA 429: printf("cuda: recv: %02x\n", s->sr); 430: #endif 431: /* indicate end of transfer */ 432: if (s->data_in_index >= s->data_in_size) { 433: s->b = (s->b | TREQ); 434: } 435: s->ifr |= SR_INT; 436: cuda_update_irq(s); 437: } 438: } 439: } 440: } else { 441: /* no transfer requested: handle sync case */ 442: if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) { 443: /* update TREQ state each time TACK change state */ 444: if (s->b & TACK) 445: s->b = (s->b | TREQ); 446: else 447: s->b = (s->b & ~TREQ); 448: s->ifr |= SR_INT; 449: cuda_update_irq(s); 450: } else { 451: if (!(s->last_b & TIP)) { 1.1.1.3 ! root 452: /* handle end of host to cuda transfer */ 1.1 root 453: packet_received = (s->data_out_index > 0); 1.1.1.3 ! root 454: /* always an IRQ at the end of transfer */ 1.1 root 455: s->ifr |= SR_INT; 456: cuda_update_irq(s); 457: } 458: /* signal if there is data to read */ 459: if (s->data_in_index < s->data_in_size) { 460: s->b = (s->b & ~TREQ); 461: } 462: } 463: } 464: 465: s->last_acr = s->acr; 466: s->last_b = s->b; 467: 468: /* NOTE: cuda_receive_packet_from_host() can call cuda_update() 469: recursively */ 470: if (packet_received) { 471: len = s->data_out_index; 472: s->data_out_index = 0; 473: cuda_receive_packet_from_host(s, s->data_out, len); 474: } 475: } 476: 1.1.1.3 ! root 477: static void cuda_send_packet_to_host(CUDAState *s, 1.1 root 478: const uint8_t *data, int len) 479: { 480: #ifdef DEBUG_CUDA_PACKET 481: { 482: int i; 483: printf("cuda_send_packet_to_host:\n"); 484: for(i = 0; i < len; i++) 485: printf(" %02x", data[i]); 486: printf("\n"); 487: } 488: #endif 489: memcpy(s->data_in, data, len); 490: s->data_in_size = len; 491: s->data_in_index = 0; 492: cuda_update(s); 493: s->ifr |= SR_INT; 494: cuda_update_irq(s); 495: } 496: 497: static void cuda_adb_poll(void *opaque) 498: { 499: CUDAState *s = opaque; 500: uint8_t obuf[ADB_MAX_OUT_LEN + 2]; 501: int olen; 502: 503: olen = adb_poll(&adb_bus, obuf + 2); 504: if (olen > 0) { 505: obuf[0] = ADB_PACKET; 506: obuf[1] = 0x40; /* polled data */ 507: cuda_send_packet_to_host(s, obuf, olen + 2); 508: } 1.1.1.3 ! root 509: qemu_mod_timer(s->adb_poll_timer, ! 510: qemu_get_clock(vm_clock) + 1.1 root 511: (ticks_per_sec / CUDA_ADB_POLL_FREQ)); 512: } 513: 1.1.1.3 ! root 514: static void cuda_receive_packet(CUDAState *s, 1.1 root 515: const uint8_t *data, int len) 516: { 517: uint8_t obuf[16]; 518: int ti, autopoll; 519: 520: switch(data[0]) { 521: case CUDA_AUTOPOLL: 522: autopoll = (data[1] != 0); 523: if (autopoll != s->autopoll) { 524: s->autopoll = autopoll; 525: if (autopoll) { 1.1.1.3 ! root 526: qemu_mod_timer(s->adb_poll_timer, ! 527: qemu_get_clock(vm_clock) + 1.1 root 528: (ticks_per_sec / CUDA_ADB_POLL_FREQ)); 529: } else { 530: qemu_del_timer(s->adb_poll_timer); 531: } 532: } 533: obuf[0] = CUDA_PACKET; 534: obuf[1] = data[1]; 535: cuda_send_packet_to_host(s, obuf, 2); 536: break; 537: case CUDA_GET_TIME: 538: case CUDA_SET_TIME: 539: /* XXX: add time support ? */ 540: ti = time(NULL) + RTC_OFFSET; 541: obuf[0] = CUDA_PACKET; 542: obuf[1] = 0; 543: obuf[2] = 0; 544: obuf[3] = ti >> 24; 545: obuf[4] = ti >> 16; 546: obuf[5] = ti >> 8; 547: obuf[6] = ti; 548: cuda_send_packet_to_host(s, obuf, 7); 549: break; 550: case CUDA_FILE_SERVER_FLAG: 551: case CUDA_SET_DEVICE_LIST: 552: case CUDA_SET_AUTO_RATE: 553: case CUDA_SET_POWER_MESSAGES: 554: obuf[0] = CUDA_PACKET; 555: obuf[1] = 0; 556: cuda_send_packet_to_host(s, obuf, 2); 557: break; 558: case CUDA_POWERDOWN: 559: obuf[0] = CUDA_PACKET; 560: obuf[1] = 0; 561: cuda_send_packet_to_host(s, obuf, 2); 562: qemu_system_shutdown_request(); 563: break; 1.1.1.3 ! root 564: case CUDA_RESET_SYSTEM: ! 565: obuf[0] = CUDA_PACKET; ! 566: obuf[1] = 0; ! 567: cuda_send_packet_to_host(s, obuf, 2); ! 568: qemu_system_reset_request(); ! 569: break; 1.1 root 570: default: 571: break; 572: } 573: } 574: 1.1.1.3 ! root 575: static void cuda_receive_packet_from_host(CUDAState *s, 1.1 root 576: const uint8_t *data, int len) 577: { 578: #ifdef DEBUG_CUDA_PACKET 579: { 580: int i; 581: printf("cuda_receive_packet_from_host:\n"); 582: for(i = 0; i < len; i++) 583: printf(" %02x", data[i]); 584: printf("\n"); 585: } 586: #endif 587: switch(data[0]) { 588: case ADB_PACKET: 589: { 590: uint8_t obuf[ADB_MAX_OUT_LEN + 2]; 591: int olen; 592: olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1); 593: if (olen > 0) { 594: obuf[0] = ADB_PACKET; 595: obuf[1] = 0x00; 596: } else { 597: /* error */ 598: obuf[0] = ADB_PACKET; 599: obuf[1] = -olen; 600: olen = 0; 601: } 602: cuda_send_packet_to_host(s, obuf, olen + 2); 603: } 604: break; 605: case CUDA_PACKET: 606: cuda_receive_packet(s, data + 1, len - 1); 607: break; 608: } 609: } 610: 611: static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value) 612: { 613: } 614: 615: static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value) 616: { 617: } 618: 619: static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr) 620: { 621: return 0; 622: } 623: 624: static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr) 625: { 626: return 0; 627: } 628: 629: static CPUWriteMemoryFunc *cuda_write[] = { 630: &cuda_writeb, 631: &cuda_writew, 632: &cuda_writel, 633: }; 634: 635: static CPUReadMemoryFunc *cuda_read[] = { 636: &cuda_readb, 637: &cuda_readw, 638: &cuda_readl, 639: }; 640: 1.1.1.3 ! root 641: void cuda_init (int *cuda_mem_index, qemu_irq irq) 1.1 root 642: { 643: CUDAState *s = &cuda_state; 644: 645: s->irq = irq; 646: 647: s->timers[0].index = 0; 648: s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); 649: s->timers[0].latch = 0xffff; 650: set_counter(s, &s->timers[0], 0xffff); 651: 652: s->timers[1].index = 1; 653: s->timers[1].latch = 0; 654: // s->ier = T1_INT | SR_INT; 655: s->ier = 0; 656: set_counter(s, &s->timers[1], 0xffff); 657: 658: s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s); 1.1.1.3 ! root 659: *cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); 1.1 root 660: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.