/* Returns the date/time value as a UNIX epoch time stamp */ time_t rtc_unix_secs() { uint32 rtcold, rtcnew; int i; /* Try several times to make sure we don't read one value, then the clock increments itself, then we read the second value. This algorithm is from NetBSD. */ rtcold = 0; for (;;) { for (i=0; i<3; i++) { rtcnew = ((g2_read_32(0xa0710000) & 0xffff) << 16) | (g2_read_32(0xa0710004) & 0xffff); if (rtcnew != rtcold) break; } if (i < 3) rtcold = rtcnew; else break; } /* Subtract out 20 years */ rtcnew = rtcnew - 631152000; return rtcnew; }
void rtc_gettimeofday(struct timeval *tv) { uint32 val1, val2; do { val1 = ((g2_read_32(AICA_RTC_SECS_H) & 0xffff) << 16) | (g2_read_32(AICA_RTC_SECS_L) & 0xffff); val2 = ((g2_read_32(AICA_RTC_SECS_H) & 0xffff) << 16) | (g2_read_32(AICA_RTC_SECS_L) & 0xffff); } while (val1 != val2); tv->tv_sec = val1 - TWENTY_YEARS; /* Can't get microseconds with just a seconds counter. */ tv->tv_usec = 0; }
int rtc_settimeofday(const struct timeval *tv) { uint32 val1, val2; uint32 secs = tv->tv_sec + TWENTY_YEARS; do { g2_write_32((secs & 0xffff0000) >> 16, AICA_RTC_SECS_H); g2_write_32((secs & 0xffff), AICA_RTC_SECS_L); val1 = ((g2_read_32(AICA_RTC_SECS_H) & 0xffff) << 16) | (g2_read_32(AICA_RTC_SECS_L) & 0xffff); val2 = ((g2_read_32(AICA_RTC_SECS_H) & 0xffff) << 16) | (g2_read_32(AICA_RTC_SECS_L) & 0xffff); } while (val1 != val2); return 0; }
/* Submit a request to the SH4->AICA queue; size is in uint32's */ int snd_sh4_to_aica(void *packet, uint32 size) { uint32 qa, bot, start, top, *pkt32, cnt; assert_msg( size < 256, "SH4->AICA packets may not be >256 uint32's long" ); sem_wait(sem_qram); /* Set these up for reference */ qa = SPU_RAM_BASE + AICA_MEM_CMD_QUEUE; assert_msg( g2_read_32(qa + offsetof(aica_queue_t, valid)), "Queue is not yet valid" ); bot = SPU_RAM_BASE + g2_read_32(qa + offsetof(aica_queue_t, data)); top = bot + g2_read_32(qa + offsetof(aica_queue_t, size)); start = bot + g2_read_32(qa + offsetof(aica_queue_t, head)); pkt32 = (uint32 *)packet; cnt = 0; while (size > 0) { /* Fifo wait if necessary */ if (!(cnt % 8)) g2_fifo_wait(); cnt++; /* Write the next dword */ g2_write_32(start, *pkt32++); /* Move our counters */ start += 4; if (start >= top) start = bot; size--; } /* Finally, write a new head value to signify that we've added a packet for it to process */ g2_write_32(qa + offsetof(aica_queue_t, head), start - bot); /* We could wait until head == tail here for processing, but there's not really much point; it'll just slow things down. */ sem_signal(sem_qram); return 0; }
/* Transfer one packet of data from the AICA->SH4 queue. Expects to find AICA_CMD_MAX_SIZE dwords of space available. Returns -1 if failure, 0 for no packets available, 1 otherwise. Failure might mean a permanent failure since the queue is probably out of sync. */ int snd_aica_to_sh4(void *packetout) { uint32 bot, start, stop, top, size, cnt, *pkt32; sem_wait(sem_qram); /* Set these up for reference */ bot = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE; assert_msg( g2_read_32(bot + offsetof(aica_queue_t, valid)), "Queue is not yet valid" ); top = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, size)); start = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, tail)); stop = SPU_RAM_BASE + AICA_MEM_RESP_QUEUE + g2_read_32(bot + offsetof(aica_queue_t, head)); cnt = 0; pkt32 = (uint32 *)packetout; /* Is there anything? */ if (start == stop) { sem_signal(sem_qram); return 0; } /* Check for packet size overflow */ size = g2_read_32(start + offsetof(aica_cmd_t, size)); if (cnt >= AICA_CMD_MAX_SIZE) { sem_signal(sem_qram); dbglog(DBG_ERROR, "snd_aica_to_sh4(): packet larger than %d dwords\n", AICA_CMD_MAX_SIZE); return -1; } /* Find stop point for this packet */ stop = start + size*4; if (stop > top) stop -= top - (SPU_RAM_BASE + AICA_MEM_RESP_QUEUE); while (start != stop) { /* Fifo wait if necessary */ if (!(cnt % 8)) g2_fifo_wait(); cnt++; /* Read the next dword */ *pkt32++ = g2_read_32(start); /* Move our counters */ start += 4; if (start >= top) start = bot; cnt++; } /* Finally, write a new tail value to signify that we've removed a packet */ g2_write_32(bot + offsetof(aica_queue_t, tail), start - (SPU_RAM_BASE + AICA_MEM_RESP_QUEUE)); sem_signal(sem_qram); return 1; }