X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=hw%2Fm48t59.c;h=da61313f1e76f90b24d4ec423314f7cc84990ec3;hb=cd346349b45ef056f138a184f660b8c34c3213cc;hp=62cd301e50becd9dc9e055807c8de89b85be3547;hpb=13ab5daa86d3b802fc3a2e5959ecc8cb1aadd310;p=qemu diff --git a/hw/m48t59.c b/hw/m48t59.c index 62cd301..da61313 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -1,8 +1,8 @@ /* - * QEMU M48T59 NVRAM emulation for PPC PREP platform - * - * Copyright (c) 2003-2004 Jocelyn Mayer - * + * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms + * + * Copyright (c) 2003-2005, 2007 Jocelyn Mayer + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights @@ -32,9 +32,18 @@ #define NVRAM_PRINTF(fmt, args...) do { } while (0) #endif +/* + * The M48T08 and M48T59 chips are very similar. The newer '59 has + * alarm and a watchdog timer and related control registers. In the + * PPC platform there is also a nvram lock function. + */ struct m48t59_t { + /* Model parameters */ + int type; // 8 = m48t08, 59 = m48t59 /* Hardware parameters */ - int IRQ; + qemu_irq IRQ; + int mem_index; + target_phys_addr_t mem_base; uint32_t io_base; uint16_t size; /* RTC management */ @@ -68,13 +77,20 @@ static void get_time (m48t59_t *NVRAM, struct tm *tm) time_t t; t = time(NULL) + NVRAM->time_offset; - localtime_r(&t, tm); +#ifdef _WIN32 + memcpy(tm,localtime(&t),sizeof(*tm)); +#else + if (rtc_utc) + gmtime_r (&t, tm); + else + localtime_r (&t, tm) ; +#endif } static void set_time (m48t59_t *NVRAM, struct tm *tm) { time_t now, new_time; - + new_time = mktime(tm); now = time(NULL); NVRAM->time_offset = new_time - now; @@ -87,8 +103,8 @@ static void alarm_cb (void *opaque) uint64_t next_time; m48t59_t *NVRAM = opaque; - pic_set_irq(NVRAM->IRQ, 1); - if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && + qemu_set_irq(NVRAM->IRQ, 1); + if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && (NVRAM->buffer[0x1FF4] & 0x80) == 0 && (NVRAM->buffer[0x1FF3] & 0x80) == 0 && (NVRAM->buffer[0x1FF2] & 0x80) == 0) { @@ -124,13 +140,20 @@ static void alarm_cb (void *opaque) next_time = 1 + mktime(&tm_now); } qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000); - pic_set_irq(NVRAM->IRQ, 0); + qemu_set_irq(NVRAM->IRQ, 0); } static void get_alarm (m48t59_t *NVRAM, struct tm *tm) { - localtime_r(&NVRAM->alarm, tm); +#ifdef _WIN32 + memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm)); +#else + if (rtc_utc) + gmtime_r (&NVRAM->alarm, tm); + else + localtime_r (&NVRAM->alarm, tm); +#endif } static void set_alarm (m48t59_t *NVRAM, struct tm *tm) @@ -138,10 +161,9 @@ static void set_alarm (m48t59_t *NVRAM, struct tm *tm) NVRAM->alarm = mktime(tm); if (NVRAM->alrm_timer != NULL) { qemu_del_timer(NVRAM->alrm_timer); - NVRAM->alrm_timer = NULL; + if (NVRAM->alarm - time(NULL) > 0) + qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); } - if (NVRAM->alarm - time(NULL) > 0) - qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000); } /* Watchdog management */ @@ -154,12 +176,10 @@ static void watchdog_cb (void *opaque) NVRAM->buffer[0x1FF7] = 0x00; NVRAM->buffer[0x1FFC] &= ~0x40; /* May it be a hw CPU Reset instead ? */ - reset_requested = 1; - printf("Watchdog reset...\n"); - cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); + qemu_system_reset_request(); } else { - pic_set_irq(NVRAM->IRQ, 1); - pic_set_irq(NVRAM->IRQ, 0); + qemu_set_irq(NVRAM->IRQ, 1); + qemu_set_irq(NVRAM->IRQ, 0); } } @@ -167,27 +187,29 @@ static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value) { uint64_t interval; /* in 1/16 seconds */ + NVRAM->buffer[0x1FF0] &= ~0x80; if (NVRAM->wd_timer != NULL) { qemu_del_timer(NVRAM->wd_timer); - NVRAM->wd_timer = NULL; - } - NVRAM->buffer[0x1FF0] &= ~0x80; - if (value != 0) { - interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); - qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + - ((interval * 1000) >> 4)); + if (value != 0) { + interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F); + qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) + + ((interval * 1000) >> 4)); + } } } /* Direct access to NVRAM */ -void m48t59_write (m48t59_t *NVRAM, uint32_t val) +void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) { struct tm tm; int tmp; - if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000) - NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); - switch (NVRAM->addr) { + if (addr > 0x1FF8 && addr < 0x2000) + NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); + if (NVRAM->type == 8 && + (addr >= 0x1ff0 && addr <= 0x1ff7)) + goto do_write; + switch (addr) { case 0x1FF0: /* flags register : read-only */ break; @@ -196,52 +218,52 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val) break; case 0x1FF2: /* alarm seconds */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_sec = tmp; - NVRAM->buffer[0x1FF2] = val; - set_alarm(NVRAM, &tm); - } + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_alarm(NVRAM, &tm); + tm.tm_sec = tmp; + NVRAM->buffer[0x1FF2] = val; + set_alarm(NVRAM, &tm); + } break; case 0x1FF3: /* alarm minutes */ - tmp = fromBCD(val & 0x7F); - if (tmp >= 0 && tmp <= 59) { - get_alarm(NVRAM, &tm); - tm.tm_min = tmp; - NVRAM->buffer[0x1FF3] = val; - set_alarm(NVRAM, &tm); - } + tmp = fromBCD(val & 0x7F); + if (tmp >= 0 && tmp <= 59) { + get_alarm(NVRAM, &tm); + tm.tm_min = tmp; + NVRAM->buffer[0x1FF3] = val; + set_alarm(NVRAM, &tm); + } break; case 0x1FF4: /* alarm hours */ - tmp = fromBCD(val & 0x3F); - if (tmp >= 0 && tmp <= 23) { - get_alarm(NVRAM, &tm); - tm.tm_hour = tmp; - NVRAM->buffer[0x1FF4] = val; - set_alarm(NVRAM, &tm); - } + tmp = fromBCD(val & 0x3F); + if (tmp >= 0 && tmp <= 23) { + get_alarm(NVRAM, &tm); + tm.tm_hour = tmp; + NVRAM->buffer[0x1FF4] = val; + set_alarm(NVRAM, &tm); + } break; case 0x1FF5: /* alarm date */ - tmp = fromBCD(val & 0x1F); - if (tmp != 0) { - get_alarm(NVRAM, &tm); - tm.tm_mday = tmp; - NVRAM->buffer[0x1FF5] = val; - set_alarm(NVRAM, &tm); - } + tmp = fromBCD(val & 0x1F); + if (tmp != 0) { + get_alarm(NVRAM, &tm); + tm.tm_mday = tmp; + NVRAM->buffer[0x1FF5] = val; + set_alarm(NVRAM, &tm); + } break; case 0x1FF6: /* interrupts */ - NVRAM->buffer[0x1FF6] = val; + NVRAM->buffer[0x1FF6] = val; break; case 0x1FF7: /* watchdog */ - NVRAM->buffer[0x1FF7] = val; - set_up_watchdog(NVRAM, val); + NVRAM->buffer[0x1FF7] = val; + set_up_watchdog(NVRAM, val); break; case 0x1FF8: /* control */ @@ -314,30 +336,36 @@ void m48t59_write (m48t59_t *NVRAM, uint32_t val) tmp = fromBCD(val); if (tmp >= 0 && tmp <= 99) { get_time(NVRAM, &tm); - tm.tm_year = fromBCD(val); + if (NVRAM->type == 8) + tm.tm_year = fromBCD(val) + 68; // Base year is 1968 + else + tm.tm_year = fromBCD(val); set_time(NVRAM, &tm); } break; default: /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) + if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) + if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) break; - if (NVRAM->addr < 0x1FF0 || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - NVRAM->buffer[NVRAM->addr] = val & 0xFF; + do_write: + if (addr < NVRAM->size) { + NVRAM->buffer[addr] = val & 0xFF; } break; } } -uint32_t m48t59_read (m48t59_t *NVRAM) +uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) { struct tm tm; uint32_t retval = 0xFF; - switch (NVRAM->addr) { + if (NVRAM->type == 8 && + (addr >= 0x1ff0 && addr <= 0x1ff7)) + goto do_read; + switch (addr) { case 0x1FF0: /* flags register */ goto do_read; @@ -400,23 +428,25 @@ uint32_t m48t59_read (m48t59_t *NVRAM) case 0x1FFF: /* year */ get_time(NVRAM, &tm); - retval = toBCD(tm.tm_year); + if (NVRAM->type == 8) + retval = toBCD(tm.tm_year - 68); // Base year is 1968 + else + retval = toBCD(tm.tm_year); break; default: /* Check lock registers state */ - if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) + if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) break; - if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) + if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) break; - if (NVRAM->addr < 0x1FF0 || - (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { - do_read: - retval = NVRAM->buffer[NVRAM->addr]; + do_read: + if (addr < NVRAM->size) { + retval = NVRAM->buffer[addr]; } break; } - if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000) - NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); + if (addr > 0x1FF9 && addr < 0x2000) + NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval); return retval; } @@ -448,7 +478,7 @@ static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val) NVRAM->addr |= val << 8; break; case 3: - m48t59_write(NVRAM, val); + m48t59_write(NVRAM, val, NVRAM->addr); NVRAM->addr = 0x0000; break; default: @@ -464,7 +494,7 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) addr -= NVRAM->io_base; switch (addr) { case 3: - retval = m48t59_read(NVRAM); + retval = m48t59_read(NVRAM, NVRAM->addr); break; default: retval = -1; @@ -475,10 +505,121 @@ static uint32_t NVRAM_readb (void *opaque, uint32_t addr) return retval; } +static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t59_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + m48t59_write(NVRAM, addr, value & 0xff); +} + +static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t59_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + m48t59_write(NVRAM, addr, (value >> 8) & 0xff); + m48t59_write(NVRAM, addr + 1, value & 0xff); +} + +static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + m48t59_t *NVRAM = opaque; + + addr -= NVRAM->mem_base; + m48t59_write(NVRAM, addr, (value >> 24) & 0xff); + m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff); + m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff); + m48t59_write(NVRAM, addr + 3, value & 0xff); +} + +static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) +{ + m48t59_t *NVRAM = opaque; + uint32_t retval; + + addr -= NVRAM->mem_base; + retval = m48t59_read(NVRAM, addr); + return retval; +} + +static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) +{ + m48t59_t *NVRAM = opaque; + uint32_t retval; + + addr -= NVRAM->mem_base; + retval = m48t59_read(NVRAM, addr) << 8; + retval |= m48t59_read(NVRAM, addr + 1); + return retval; +} + +static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) +{ + m48t59_t *NVRAM = opaque; + uint32_t retval; + + addr -= NVRAM->mem_base; + retval = m48t59_read(NVRAM, addr) << 24; + retval |= m48t59_read(NVRAM, addr + 1) << 16; + retval |= m48t59_read(NVRAM, addr + 2) << 8; + retval |= m48t59_read(NVRAM, addr + 3); + return retval; +} + +static CPUWriteMemoryFunc *nvram_write[] = { + &nvram_writeb, + &nvram_writew, + &nvram_writel, +}; + +static CPUReadMemoryFunc *nvram_read[] = { + &nvram_readb, + &nvram_readw, + &nvram_readl, +}; + +static void m48t59_save(QEMUFile *f, void *opaque) +{ + m48t59_t *s = opaque; + + qemu_put_8s(f, &s->lock); + qemu_put_be16s(f, &s->addr); + qemu_put_buffer(f, s->buffer, s->size); +} + +static int m48t59_load(QEMUFile *f, void *opaque, int version_id) +{ + m48t59_t *s = opaque; + + if (version_id != 1) + return -EINVAL; + + qemu_get_8s(f, &s->lock); + qemu_get_be16s(f, &s->addr); + qemu_get_buffer(f, s->buffer, s->size); + + return 0; +} + +static void m48t59_reset(void *opaque) +{ + m48t59_t *NVRAM = opaque; + + if (NVRAM->alrm_timer != NULL) + qemu_del_timer(NVRAM->alrm_timer); + + if (NVRAM->wd_timer != NULL) + qemu_del_timer(NVRAM->wd_timer); +} + /* Initialisation routine */ -m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) +m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base, + uint32_t io_base, uint16_t size, + int type) { m48t59_t *s; + target_phys_addr_t save_base; s = qemu_mallocz(sizeof(m48t59_t)); if (!s) @@ -490,13 +631,27 @@ m48t59_t *m48t59_init (int IRQ, uint32_t io_base, uint16_t size) } s->IRQ = IRQ; s->size = size; + s->mem_base = mem_base; s->io_base = io_base; s->addr = 0; - register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); - register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); - s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); - s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); + s->type = type; + if (io_base != 0) { + register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); + register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); + } + if (mem_base != 0) { + s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); + cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); + } + if (type == 59) { + s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); + s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); + } s->lock = 0; + qemu_register_reset(m48t59_reset, s); + save_base = mem_base ? mem_base : io_base; + register_savevm("m48t59", save_base, 1, m48t59_save, m48t59_load, s); + return s; }