1 |
/* |
/* |
2 |
* QEMU M48T59 NVRAM emulation for PPC PREP platform |
* QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms |
3 |
* |
* |
4 |
* Copyright (c) 2003-2004 Jocelyn Mayer |
* Copyright (c) 2003-2005 Jocelyn Mayer |
5 |
* |
* |
6 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
7 |
* of this software and associated documentation files (the "Software"), to deal |
* of this software and associated documentation files (the "Software"), to deal |
32 |
#define NVRAM_PRINTF(fmt, args...) do { } while (0) |
#define NVRAM_PRINTF(fmt, args...) do { } while (0) |
33 |
#endif |
#endif |
34 |
|
|
35 |
|
/* |
36 |
|
* The M48T08 and M48T59 chips are very similar. The newer '59 has |
37 |
|
* alarm and a watchdog timer and related control registers. In the |
38 |
|
* PPC platform there is also a nvram lock function. |
39 |
|
*/ |
40 |
struct m48t59_t { |
struct m48t59_t { |
41 |
|
/* Model parameters */ |
42 |
|
int type; // 8 = m48t08, 59 = m48t59 |
43 |
/* Hardware parameters */ |
/* Hardware parameters */ |
44 |
int IRQ; |
int IRQ; |
45 |
int mem_index; |
int mem_index; |
195 |
} |
} |
196 |
|
|
197 |
/* Direct access to NVRAM */ |
/* Direct access to NVRAM */ |
198 |
void m48t59_write (m48t59_t *NVRAM, uint32_t val) |
void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val) |
199 |
{ |
{ |
200 |
struct tm tm; |
struct tm tm; |
201 |
int tmp; |
int tmp; |
202 |
|
|
203 |
if (NVRAM->addr > 0x1FF8 && NVRAM->addr < 0x2000) |
if (addr > 0x1FF8 && addr < 0x2000) |
204 |
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val); |
NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val); |
205 |
switch (NVRAM->addr) { |
if (NVRAM->type == 8 && |
206 |
|
(addr >= 0x1ff0 && addr <= 0x1ff7)) |
207 |
|
goto do_write; |
208 |
|
switch (addr) { |
209 |
case 0x1FF0: |
case 0x1FF0: |
210 |
/* flags register : read-only */ |
/* flags register : read-only */ |
211 |
break; |
break; |
214 |
break; |
break; |
215 |
case 0x1FF2: |
case 0x1FF2: |
216 |
/* alarm seconds */ |
/* alarm seconds */ |
217 |
tmp = fromBCD(val & 0x7F); |
tmp = fromBCD(val & 0x7F); |
218 |
if (tmp >= 0 && tmp <= 59) { |
if (tmp >= 0 && tmp <= 59) { |
219 |
get_alarm(NVRAM, &tm); |
get_alarm(NVRAM, &tm); |
220 |
tm.tm_sec = tmp; |
tm.tm_sec = tmp; |
221 |
NVRAM->buffer[0x1FF2] = val; |
NVRAM->buffer[0x1FF2] = val; |
222 |
set_alarm(NVRAM, &tm); |
set_alarm(NVRAM, &tm); |
223 |
} |
} |
224 |
break; |
break; |
225 |
case 0x1FF3: |
case 0x1FF3: |
226 |
/* alarm minutes */ |
/* alarm minutes */ |
227 |
tmp = fromBCD(val & 0x7F); |
tmp = fromBCD(val & 0x7F); |
228 |
if (tmp >= 0 && tmp <= 59) { |
if (tmp >= 0 && tmp <= 59) { |
229 |
get_alarm(NVRAM, &tm); |
get_alarm(NVRAM, &tm); |
230 |
tm.tm_min = tmp; |
tm.tm_min = tmp; |
231 |
NVRAM->buffer[0x1FF3] = val; |
NVRAM->buffer[0x1FF3] = val; |
232 |
set_alarm(NVRAM, &tm); |
set_alarm(NVRAM, &tm); |
233 |
} |
} |
234 |
break; |
break; |
235 |
case 0x1FF4: |
case 0x1FF4: |
236 |
/* alarm hours */ |
/* alarm hours */ |
237 |
tmp = fromBCD(val & 0x3F); |
tmp = fromBCD(val & 0x3F); |
238 |
if (tmp >= 0 && tmp <= 23) { |
if (tmp >= 0 && tmp <= 23) { |
239 |
get_alarm(NVRAM, &tm); |
get_alarm(NVRAM, &tm); |
240 |
tm.tm_hour = tmp; |
tm.tm_hour = tmp; |
241 |
NVRAM->buffer[0x1FF4] = val; |
NVRAM->buffer[0x1FF4] = val; |
242 |
set_alarm(NVRAM, &tm); |
set_alarm(NVRAM, &tm); |
243 |
} |
} |
244 |
break; |
break; |
245 |
case 0x1FF5: |
case 0x1FF5: |
246 |
/* alarm date */ |
/* alarm date */ |
247 |
tmp = fromBCD(val & 0x1F); |
tmp = fromBCD(val & 0x1F); |
248 |
if (tmp != 0) { |
if (tmp != 0) { |
249 |
get_alarm(NVRAM, &tm); |
get_alarm(NVRAM, &tm); |
250 |
tm.tm_mday = tmp; |
tm.tm_mday = tmp; |
251 |
NVRAM->buffer[0x1FF5] = val; |
NVRAM->buffer[0x1FF5] = val; |
252 |
set_alarm(NVRAM, &tm); |
set_alarm(NVRAM, &tm); |
253 |
} |
} |
254 |
break; |
break; |
255 |
case 0x1FF6: |
case 0x1FF6: |
256 |
/* interrupts */ |
/* interrupts */ |
257 |
NVRAM->buffer[0x1FF6] = val; |
NVRAM->buffer[0x1FF6] = val; |
258 |
break; |
break; |
259 |
case 0x1FF7: |
case 0x1FF7: |
260 |
/* watchdog */ |
/* watchdog */ |
261 |
NVRAM->buffer[0x1FF7] = val; |
NVRAM->buffer[0x1FF7] = val; |
262 |
set_up_watchdog(NVRAM, val); |
set_up_watchdog(NVRAM, val); |
263 |
break; |
break; |
264 |
case 0x1FF8: |
case 0x1FF8: |
265 |
/* control */ |
/* control */ |
338 |
break; |
break; |
339 |
default: |
default: |
340 |
/* Check lock registers state */ |
/* Check lock registers state */ |
341 |
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) |
if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) |
342 |
break; |
break; |
343 |
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) |
if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) |
344 |
break; |
break; |
345 |
if (NVRAM->addr < 0x1FF0 || |
do_write: |
346 |
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { |
if (addr < NVRAM->size) { |
347 |
NVRAM->buffer[NVRAM->addr] = val & 0xFF; |
NVRAM->buffer[addr] = val & 0xFF; |
348 |
} |
} |
349 |
break; |
break; |
350 |
} |
} |
351 |
} |
} |
352 |
|
|
353 |
uint32_t m48t59_read (m48t59_t *NVRAM) |
uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr) |
354 |
{ |
{ |
355 |
struct tm tm; |
struct tm tm; |
356 |
uint32_t retval = 0xFF; |
uint32_t retval = 0xFF; |
357 |
|
|
358 |
switch (NVRAM->addr) { |
if (NVRAM->type == 8 && |
359 |
|
(addr >= 0x1ff0 && addr <= 0x1ff7)) |
360 |
|
goto do_read; |
361 |
|
switch (addr) { |
362 |
case 0x1FF0: |
case 0x1FF0: |
363 |
/* flags register */ |
/* flags register */ |
364 |
goto do_read; |
goto do_read; |
425 |
break; |
break; |
426 |
default: |
default: |
427 |
/* Check lock registers state */ |
/* Check lock registers state */ |
428 |
if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1)) |
if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1)) |
429 |
break; |
break; |
430 |
if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2)) |
if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2)) |
431 |
break; |
break; |
432 |
if (NVRAM->addr < 0x1FF0 || |
do_read: |
433 |
(NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) { |
if (addr < NVRAM->size) { |
434 |
do_read: |
retval = NVRAM->buffer[addr]; |
|
retval = NVRAM->buffer[NVRAM->addr]; |
|
435 |
} |
} |
436 |
break; |
break; |
437 |
} |
} |
438 |
if (NVRAM->addr > 0x1FF9 && NVRAM->addr < 0x2000) |
if (addr > 0x1FF9 && addr < 0x2000) |
439 |
NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval); |
NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval); |
440 |
|
|
441 |
return retval; |
return retval; |
442 |
} |
} |
468 |
NVRAM->addr |= val << 8; |
NVRAM->addr |= val << 8; |
469 |
break; |
break; |
470 |
case 3: |
case 3: |
471 |
m48t59_write(NVRAM, val); |
m48t59_write(NVRAM, val, NVRAM->addr); |
472 |
NVRAM->addr = 0x0000; |
NVRAM->addr = 0x0000; |
473 |
break; |
break; |
474 |
default: |
default: |
484 |
addr -= NVRAM->io_base; |
addr -= NVRAM->io_base; |
485 |
switch (addr) { |
switch (addr) { |
486 |
case 3: |
case 3: |
487 |
retval = m48t59_read(NVRAM); |
retval = m48t59_read(NVRAM, NVRAM->addr); |
488 |
break; |
break; |
489 |
default: |
default: |
490 |
retval = -1; |
retval = -1; |
500 |
m48t59_t *NVRAM = opaque; |
m48t59_t *NVRAM = opaque; |
501 |
|
|
502 |
addr -= NVRAM->mem_base; |
addr -= NVRAM->mem_base; |
503 |
if (addr < 0x1FF0) |
m48t59_write(NVRAM, addr, value & 0xff); |
|
NVRAM->buffer[addr] = value; |
|
504 |
} |
} |
505 |
|
|
506 |
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) |
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value) |
508 |
m48t59_t *NVRAM = opaque; |
m48t59_t *NVRAM = opaque; |
509 |
|
|
510 |
addr -= NVRAM->mem_base; |
addr -= NVRAM->mem_base; |
511 |
if (addr < 0x1FF0) { |
m48t59_write(NVRAM, addr, (value >> 8) & 0xff); |
512 |
NVRAM->buffer[addr] = value >> 8; |
m48t59_write(NVRAM, addr + 1, value & 0xff); |
|
NVRAM->buffer[addr + 1] = value; |
|
|
} |
|
513 |
} |
} |
514 |
|
|
515 |
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
517 |
m48t59_t *NVRAM = opaque; |
m48t59_t *NVRAM = opaque; |
518 |
|
|
519 |
addr -= NVRAM->mem_base; |
addr -= NVRAM->mem_base; |
520 |
if (addr < 0x1FF0) { |
m48t59_write(NVRAM, addr, (value >> 24) & 0xff); |
521 |
NVRAM->buffer[addr] = value >> 24; |
m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff); |
522 |
NVRAM->buffer[addr + 1] = value >> 16; |
m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff); |
523 |
NVRAM->buffer[addr + 2] = value >> 8; |
m48t59_write(NVRAM, addr + 3, value & 0xff); |
|
NVRAM->buffer[addr + 3] = value; |
|
|
} |
|
524 |
} |
} |
525 |
|
|
526 |
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) |
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr) |
527 |
{ |
{ |
528 |
m48t59_t *NVRAM = opaque; |
m48t59_t *NVRAM = opaque; |
529 |
uint32_t retval = 0; |
uint32_t retval; |
530 |
|
|
531 |
addr -= NVRAM->mem_base; |
addr -= NVRAM->mem_base; |
532 |
if (addr < 0x1FF0) |
retval = m48t59_read(NVRAM, addr); |
|
retval = NVRAM->buffer[addr]; |
|
|
|
|
533 |
return retval; |
return retval; |
534 |
} |
} |
535 |
|
|
536 |
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) |
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr) |
537 |
{ |
{ |
538 |
m48t59_t *NVRAM = opaque; |
m48t59_t *NVRAM = opaque; |
539 |
uint32_t retval = 0; |
uint32_t retval; |
540 |
|
|
541 |
addr -= NVRAM->mem_base; |
addr -= NVRAM->mem_base; |
542 |
if (addr < 0x1FF0) { |
retval = m48t59_read(NVRAM, addr) << 8; |
543 |
retval = NVRAM->buffer[addr] << 8; |
retval |= m48t59_read(NVRAM, addr + 1); |
|
retval |= NVRAM->buffer[addr + 1]; |
|
|
} |
|
|
|
|
544 |
return retval; |
return retval; |
545 |
} |
} |
546 |
|
|
547 |
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) |
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr) |
548 |
{ |
{ |
549 |
m48t59_t *NVRAM = opaque; |
m48t59_t *NVRAM = opaque; |
550 |
uint32_t retval = 0; |
uint32_t retval; |
|
|
|
|
addr -= NVRAM->mem_base; |
|
|
if (addr < 0x1FF0) { |
|
|
retval = NVRAM->buffer[addr] << 24; |
|
|
retval |= NVRAM->buffer[addr + 1] << 16; |
|
|
retval |= NVRAM->buffer[addr + 2] << 8; |
|
|
retval |= NVRAM->buffer[addr + 3]; |
|
|
} |
|
551 |
|
|
552 |
|
addr -= NVRAM->mem_base; |
553 |
|
retval = m48t59_read(NVRAM, addr) << 24; |
554 |
|
retval |= m48t59_read(NVRAM, addr + 1) << 16; |
555 |
|
retval |= m48t59_read(NVRAM, addr + 2) << 8; |
556 |
|
retval |= m48t59_read(NVRAM, addr + 3); |
557 |
return retval; |
return retval; |
558 |
} |
} |
559 |
|
|
568 |
&nvram_readw, |
&nvram_readw, |
569 |
&nvram_readl, |
&nvram_readl, |
570 |
}; |
}; |
571 |
|
|
572 |
/* Initialisation routine */ |
/* Initialisation routine */ |
573 |
m48t59_t *m48t59_init (int IRQ, uint32_t mem_base, |
m48t59_t *m48t59_init (int IRQ, target_ulong mem_base, |
574 |
uint32_t io_base, uint16_t size) |
uint32_t io_base, uint16_t size, |
575 |
|
int type) |
576 |
{ |
{ |
577 |
m48t59_t *s; |
m48t59_t *s; |
578 |
|
|
589 |
s->mem_base = mem_base; |
s->mem_base = mem_base; |
590 |
s->io_base = io_base; |
s->io_base = io_base; |
591 |
s->addr = 0; |
s->addr = 0; |
592 |
register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); |
s->type = type; |
593 |
register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); |
if (io_base != 0) { |
594 |
|
register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s); |
595 |
|
register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s); |
596 |
|
} |
597 |
if (mem_base != 0) { |
if (mem_base != 0) { |
598 |
s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); |
s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s); |
599 |
cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); |
cpu_register_physical_memory(mem_base, 0x4000, s->mem_index); |
600 |
} |
} |
601 |
s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); |
if (type == 59) { |
602 |
s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); |
s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s); |
603 |
|
s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s); |
604 |
|
} |
605 |
s->lock = 0; |
s->lock = 0; |
606 |
|
|
607 |
return s; |
return s; |