(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/cuda.c

    1: /*
    2:  * QEMU PowerMac CUDA device support
    3:  *
    4:  * Copyright (c) 2004-2007 Fabrice Bellard
    5:  * Copyright (c) 2007 Jocelyn Mayer
    6:  *
    7:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    8:  * of this software and associated documentation files (the "Software"), to deal
    9:  * in the Software without restriction, including without limitation the rights
   10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   11:  * copies of the Software, and to permit persons to whom the Software is
   12:  * furnished to do so, subject to the following conditions:
   13:  *
   14:  * The above copyright notice and this permission notice shall be included in
   15:  * all copies or substantial portions of the Software.
   16:  *
   17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   22:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   23:  * THE SOFTWARE.
   24:  */
   25: #include "hw.h"
   26: #include "ppc_mac.h"
   27: #include "qemu-timer.h"
   28: #include "sysemu.h"
   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 {
  101:     int index;
  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];
  123: 
  124:     uint8_t last_b; /* last value of B register */
  125:     uint8_t last_acr; /* last value of B register */
  126: 
  127:     int data_in_size;
  128:     int data_in_index;
  129:     int data_out_index;
  130: 
  131:     qemu_irq irq;
  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);
  142: static void cuda_receive_packet_from_host(CUDAState *s,
  143:                                           const uint8_t *data, int len);
  144: static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
  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)) {
  150:         qemu_irq_raise(s->irq);
  151:     } else {
  152:         qemu_irq_lower(s->irq);
  153:     }
  154: }
  155: 
  156: static unsigned int get_counter(CUDATimer *s)
  157: {
  158:     int64_t d;
  159:     unsigned int counter;
  160: 
  161:     d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
  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);
  169:             counter = (s->latch - counter) & 0xffff;
  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 */
  194:     d = muldiv64(current_time - s->load_time,
  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);
  201:         counter = (s->latch - counter) & 0xffff;
  202:     }
  203: 
  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
  214:     printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
  215:            s->latch, d, next_time - d);
  216: #endif
  217: #endif
  218:     next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
  219:         s->load_time;
  220:     if (next_time <= current_time)
  221:         next_time = current_time + 1;
  222:     return next_time;
  223: }
  224: 
  225: static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
  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;
  303:         if (s->ifr & s->ier)
  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;
  324: 
  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)) {
  452:                 /* handle end of host to cuda transfer */
  453:                 packet_received = (s->data_out_index > 0);
  454:                 /* always an IRQ at the end of transfer */
  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: 
  477: static void cuda_send_packet_to_host(CUDAState *s,
  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:     }
  509:     qemu_mod_timer(s->adb_poll_timer,
  510:                    qemu_get_clock(vm_clock) +
  511:                    (ticks_per_sec / CUDA_ADB_POLL_FREQ));
  512: }
  513: 
  514: static void cuda_receive_packet(CUDAState *s,
  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) {
  526:                 qemu_mod_timer(s->adb_poll_timer,
  527:                                qemu_get_clock(vm_clock) +
  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: