Give an opaque to the m48t59 direct access routines to make it easier
[qemu] / hw / m48t59.c
1 /*
2  * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
3  *
4  * Copyright (c) 2003-2005, 2007 Jocelyn Mayer
5  *
6  * 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
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "vl.h"
25 #include "m48t59.h"
26
27 //#define DEBUG_NVRAM
28
29 #if defined(DEBUG_NVRAM)
30 #define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
31 #else
32 #define NVRAM_PRINTF(fmt, args...) do { } while (0)
33 #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 {
41     /* Model parameters */
42     int type; // 8 = m48t08, 59 = m48t59
43     /* Hardware parameters */
44     qemu_irq IRQ;
45     int mem_index;
46     target_phys_addr_t mem_base;
47     uint32_t io_base;
48     uint16_t size;
49     /* RTC management */
50     time_t   time_offset;
51     time_t   stop_time;
52     /* Alarm & watchdog */
53     time_t   alarm;
54     struct QEMUTimer *alrm_timer;
55     struct QEMUTimer *wd_timer;
56     /* NVRAM storage */
57     uint8_t  lock;
58     uint16_t addr;
59     uint8_t *buffer;
60 };
61
62 /* Fake timer functions */
63 /* Generic helpers for BCD */
64 static inline uint8_t toBCD (uint8_t value)
65 {
66     return (((value / 10) % 10) << 4) | (value % 10);
67 }
68
69 static inline uint8_t fromBCD (uint8_t BCD)
70 {
71     return ((BCD >> 4) * 10) + (BCD & 0x0F);
72 }
73
74 /* RTC management helpers */
75 static void get_time (m48t59_t *NVRAM, struct tm *tm)
76 {
77     time_t t;
78
79     t = time(NULL) + NVRAM->time_offset;
80 #ifdef _WIN32
81     memcpy(tm,localtime(&t),sizeof(*tm));
82 #else
83     if (rtc_utc)
84         gmtime_r (&t, tm);
85     else
86         localtime_r (&t, tm) ;
87 #endif
88 }
89
90 static void set_time (m48t59_t *NVRAM, struct tm *tm)
91 {
92     time_t now, new_time;
93
94     new_time = mktime(tm);
95     now = time(NULL);
96     NVRAM->time_offset = new_time - now;
97 }
98
99 /* Alarm management */
100 static void alarm_cb (void *opaque)
101 {
102     struct tm tm, tm_now;
103     uint64_t next_time;
104     m48t59_t *NVRAM = opaque;
105
106     qemu_set_irq(NVRAM->IRQ, 1);
107     if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
108         (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
109         (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
110         (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
111         /* Repeat once a month */
112         get_time(NVRAM, &tm_now);
113         memcpy(&tm, &tm_now, sizeof(struct tm));
114         tm.tm_mon++;
115         if (tm.tm_mon == 13) {
116             tm.tm_mon = 1;
117             tm.tm_year++;
118         }
119         next_time = mktime(&tm);
120     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
121                (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
122                (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
123                (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
124         /* Repeat once a day */
125         next_time = 24 * 60 * 60 + mktime(&tm_now);
126     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
127                (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
128                (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
129                (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
130         /* Repeat once an hour */
131         next_time = 60 * 60 + mktime(&tm_now);
132     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
133                (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
134                (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
135                (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
136         /* Repeat once a minute */
137         next_time = 60 + mktime(&tm_now);
138     } else {
139         /* Repeat once a second */
140         next_time = 1 + mktime(&tm_now);
141     }
142     qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
143     qemu_set_irq(NVRAM->IRQ, 0);
144 }
145
146
147 static void get_alarm (m48t59_t *NVRAM, struct tm *tm)
148 {
149 #ifdef _WIN32
150     memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
151 #else
152     if (rtc_utc)
153         gmtime_r (&NVRAM->alarm, tm);
154     else
155         localtime_r (&NVRAM->alarm, tm);
156 #endif
157 }
158
159 static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
160 {
161     NVRAM->alarm = mktime(tm);
162     if (NVRAM->alrm_timer != NULL) {
163         qemu_del_timer(NVRAM->alrm_timer);
164         if (NVRAM->alarm - time(NULL) > 0)
165             qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
166     }
167 }
168
169 /* Watchdog management */
170 static void watchdog_cb (void *opaque)
171 {
172     m48t59_t *NVRAM = opaque;
173
174     NVRAM->buffer[0x1FF0] |= 0x80;
175     if (NVRAM->buffer[0x1FF7] & 0x80) {
176         NVRAM->buffer[0x1FF7] = 0x00;
177         NVRAM->buffer[0x1FFC] &= ~0x40;
178         /* May it be a hw CPU Reset instead ? */
179         qemu_system_reset_request();
180     } else {
181         qemu_set_irq(NVRAM->IRQ, 1);
182         qemu_set_irq(NVRAM->IRQ, 0);
183     }
184 }
185
186 static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
187 {
188     uint64_t interval; /* in 1/16 seconds */
189
190     NVRAM->buffer[0x1FF0] &= ~0x80;
191     if (NVRAM->wd_timer != NULL) {
192         qemu_del_timer(NVRAM->wd_timer);
193         if (value != 0) {
194             interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
195             qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
196                            ((interval * 1000) >> 4));
197         }
198     }
199 }
200
201 /* Direct access to NVRAM */
202 void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
203 {
204     m48t59_t *NVRAM = opaque;
205     struct tm tm;
206     int tmp;
207
208     if (addr > 0x1FF8 && addr < 0x2000)
209         NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
210     if (NVRAM->type == 8 &&
211         (addr >= 0x1ff0 && addr <= 0x1ff7))
212         goto do_write;
213     switch (addr) {
214     case 0x1FF0:
215         /* flags register : read-only */
216         break;
217     case 0x1FF1:
218         /* unused */
219         break;
220     case 0x1FF2:
221         /* alarm seconds */
222         tmp = fromBCD(val & 0x7F);
223         if (tmp >= 0 && tmp <= 59) {
224             get_alarm(NVRAM, &tm);
225             tm.tm_sec = tmp;
226             NVRAM->buffer[0x1FF2] = val;
227             set_alarm(NVRAM, &tm);
228         }
229         break;
230     case 0x1FF3:
231         /* alarm minutes */
232         tmp = fromBCD(val & 0x7F);
233         if (tmp >= 0 && tmp <= 59) {
234             get_alarm(NVRAM, &tm);
235             tm.tm_min = tmp;
236             NVRAM->buffer[0x1FF3] = val;
237             set_alarm(NVRAM, &tm);
238         }
239         break;
240     case 0x1FF4:
241         /* alarm hours */
242         tmp = fromBCD(val & 0x3F);
243         if (tmp >= 0 && tmp <= 23) {
244             get_alarm(NVRAM, &tm);
245             tm.tm_hour = tmp;
246             NVRAM->buffer[0x1FF4] = val;
247             set_alarm(NVRAM, &tm);
248         }
249         break;
250     case 0x1FF5:
251         /* alarm date */
252         tmp = fromBCD(val & 0x1F);
253         if (tmp != 0) {
254             get_alarm(NVRAM, &tm);
255             tm.tm_mday = tmp;
256             NVRAM->buffer[0x1FF5] = val;
257             set_alarm(NVRAM, &tm);
258         }
259         break;
260     case 0x1FF6:
261         /* interrupts */
262         NVRAM->buffer[0x1FF6] = val;
263         break;
264     case 0x1FF7:
265         /* watchdog */
266         NVRAM->buffer[0x1FF7] = val;
267         set_up_watchdog(NVRAM, val);
268         break;
269     case 0x1FF8:
270         /* control */
271         NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
272         break;
273     case 0x1FF9:
274         /* seconds (BCD) */
275         tmp = fromBCD(val & 0x7F);
276         if (tmp >= 0 && tmp <= 59) {
277             get_time(NVRAM, &tm);
278             tm.tm_sec = tmp;
279             set_time(NVRAM, &tm);
280         }
281         if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
282             if (val & 0x80) {
283                 NVRAM->stop_time = time(NULL);
284             } else {
285                 NVRAM->time_offset += NVRAM->stop_time - time(NULL);
286                 NVRAM->stop_time = 0;
287             }
288         }
289         NVRAM->buffer[0x1FF9] = val & 0x80;
290         break;
291     case 0x1FFA:
292         /* minutes (BCD) */
293         tmp = fromBCD(val & 0x7F);
294         if (tmp >= 0 && tmp <= 59) {
295             get_time(NVRAM, &tm);
296             tm.tm_min = tmp;
297             set_time(NVRAM, &tm);
298         }
299         break;
300     case 0x1FFB:
301         /* hours (BCD) */
302         tmp = fromBCD(val & 0x3F);
303         if (tmp >= 0 && tmp <= 23) {
304             get_time(NVRAM, &tm);
305             tm.tm_hour = tmp;
306             set_time(NVRAM, &tm);
307         }
308         break;
309     case 0x1FFC:
310         /* day of the week / century */
311         tmp = fromBCD(val & 0x07);
312         get_time(NVRAM, &tm);
313         tm.tm_wday = tmp;
314         set_time(NVRAM, &tm);
315         NVRAM->buffer[0x1FFC] = val & 0x40;
316         break;
317     case 0x1FFD:
318         /* date */
319         tmp = fromBCD(val & 0x1F);
320         if (tmp != 0) {
321             get_time(NVRAM, &tm);
322             tm.tm_mday = tmp;
323             set_time(NVRAM, &tm);
324         }
325         break;
326     case 0x1FFE:
327         /* month */
328         tmp = fromBCD(val & 0x1F);
329         if (tmp >= 1 && tmp <= 12) {
330             get_time(NVRAM, &tm);
331             tm.tm_mon = tmp - 1;
332             set_time(NVRAM, &tm);
333         }
334         break;
335     case 0x1FFF:
336         /* year */
337         tmp = fromBCD(val);
338         if (tmp >= 0 && tmp <= 99) {
339             get_time(NVRAM, &tm);
340             if (NVRAM->type == 8)
341                 tm.tm_year = fromBCD(val) + 68; // Base year is 1968
342             else
343                 tm.tm_year = fromBCD(val);
344             set_time(NVRAM, &tm);
345         }
346         break;
347     default:
348         /* Check lock registers state */
349         if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
350             break;
351         if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
352             break;
353     do_write:
354         if (addr < NVRAM->size) {
355             NVRAM->buffer[addr] = val & 0xFF;
356         }
357         break;
358     }
359 }
360
361 uint32_t m48t59_read (void *opaque, uint32_t addr)
362 {
363     m48t59_t *NVRAM = opaque;
364     struct tm tm;
365     uint32_t retval = 0xFF;
366
367     if (NVRAM->type == 8 &&
368         (addr >= 0x1ff0 && addr <= 0x1ff7))
369         goto do_read;
370     switch (addr) {
371     case 0x1FF0:
372         /* flags register */
373         goto do_read;
374     case 0x1FF1:
375         /* unused */
376         retval = 0;
377         break;
378     case 0x1FF2:
379         /* alarm seconds */
380         goto do_read;
381     case 0x1FF3:
382         /* alarm minutes */
383         goto do_read;
384     case 0x1FF4:
385         /* alarm hours */
386         goto do_read;
387     case 0x1FF5:
388         /* alarm date */
389         goto do_read;
390     case 0x1FF6:
391         /* interrupts */
392         goto do_read;
393     case 0x1FF7:
394         /* A read resets the watchdog */
395         set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
396         goto do_read;
397     case 0x1FF8:
398         /* control */
399         goto do_read;
400     case 0x1FF9:
401         /* seconds (BCD) */
402         get_time(NVRAM, &tm);
403         retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
404         break;
405     case 0x1FFA:
406         /* minutes (BCD) */
407         get_time(NVRAM, &tm);
408         retval = toBCD(tm.tm_min);
409         break;
410     case 0x1FFB:
411         /* hours (BCD) */
412         get_time(NVRAM, &tm);
413         retval = toBCD(tm.tm_hour);
414         break;
415     case 0x1FFC:
416         /* day of the week / century */
417         get_time(NVRAM, &tm);
418         retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
419         break;
420     case 0x1FFD:
421         /* date */
422         get_time(NVRAM, &tm);
423         retval = toBCD(tm.tm_mday);
424         break;
425     case 0x1FFE:
426         /* month */
427         get_time(NVRAM, &tm);
428         retval = toBCD(tm.tm_mon + 1);
429         break;
430     case 0x1FFF:
431         /* year */
432         get_time(NVRAM, &tm);
433         if (NVRAM->type == 8)
434             retval = toBCD(tm.tm_year - 68); // Base year is 1968
435         else
436             retval = toBCD(tm.tm_year);
437         break;
438     default:
439         /* Check lock registers state */
440         if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
441             break;
442         if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
443             break;
444     do_read:
445         if (addr < NVRAM->size) {
446             retval = NVRAM->buffer[addr];
447         }
448         break;
449     }
450     if (addr > 0x1FF9 && addr < 0x2000)
451         NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
452
453     return retval;
454 }
455
456 void m48t59_set_addr (void *opaque, uint32_t addr)
457 {
458     m48t59_t *NVRAM = opaque;
459
460     NVRAM->addr = addr;
461 }
462
463 void m48t59_toggle_lock (void *opaque, int lock)
464 {
465     m48t59_t *NVRAM = opaque;
466
467     NVRAM->lock ^= 1 << lock;
468 }
469
470 /* IO access to NVRAM */
471 static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
472 {
473     m48t59_t *NVRAM = opaque;
474
475     addr -= NVRAM->io_base;
476     NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
477     switch (addr) {
478     case 0:
479         NVRAM->addr &= ~0x00FF;
480         NVRAM->addr |= val;
481         break;
482     case 1:
483         NVRAM->addr &= ~0xFF00;
484         NVRAM->addr |= val << 8;
485         break;
486     case 3:
487         m48t59_write(NVRAM, val, NVRAM->addr);
488         NVRAM->addr = 0x0000;
489         break;
490     default:
491         break;
492     }
493 }
494
495 static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
496 {
497     m48t59_t *NVRAM = opaque;
498     uint32_t retval;
499
500     addr -= NVRAM->io_base;
501     switch (addr) {
502     case 3:
503         retval = m48t59_read(NVRAM, NVRAM->addr);
504         break;
505     default:
506         retval = -1;
507         break;
508     }
509     NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
510
511     return retval;
512 }
513
514 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
515 {
516     m48t59_t *NVRAM = opaque;
517
518     addr -= NVRAM->mem_base;
519     m48t59_write(NVRAM, addr, value & 0xff);
520 }
521
522 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
523 {
524     m48t59_t *NVRAM = opaque;
525
526     addr -= NVRAM->mem_base;
527     m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
528     m48t59_write(NVRAM, addr + 1, value & 0xff);
529 }
530
531 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
532 {
533     m48t59_t *NVRAM = opaque;
534
535     addr -= NVRAM->mem_base;
536     m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
537     m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
538     m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
539     m48t59_write(NVRAM, addr + 3, value & 0xff);
540 }
541
542 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
543 {
544     m48t59_t *NVRAM = opaque;
545     uint32_t retval;
546
547     addr -= NVRAM->mem_base;
548     retval = m48t59_read(NVRAM, addr);
549     return retval;
550 }
551
552 static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
553 {
554     m48t59_t *NVRAM = opaque;
555     uint32_t retval;
556
557     addr -= NVRAM->mem_base;
558     retval = m48t59_read(NVRAM, addr) << 8;
559     retval |= m48t59_read(NVRAM, addr + 1);
560     return retval;
561 }
562
563 static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
564 {
565     m48t59_t *NVRAM = opaque;
566     uint32_t retval;
567
568     addr -= NVRAM->mem_base;
569     retval = m48t59_read(NVRAM, addr) << 24;
570     retval |= m48t59_read(NVRAM, addr + 1) << 16;
571     retval |= m48t59_read(NVRAM, addr + 2) << 8;
572     retval |= m48t59_read(NVRAM, addr + 3);
573     return retval;
574 }
575
576 static CPUWriteMemoryFunc *nvram_write[] = {
577     &nvram_writeb,
578     &nvram_writew,
579     &nvram_writel,
580 };
581
582 static CPUReadMemoryFunc *nvram_read[] = {
583     &nvram_readb,
584     &nvram_readw,
585     &nvram_readl,
586 };
587
588 static void m48t59_save(QEMUFile *f, void *opaque)
589 {
590     m48t59_t *s = opaque;
591
592     qemu_put_8s(f, &s->lock);
593     qemu_put_be16s(f, &s->addr);
594     qemu_put_buffer(f, s->buffer, s->size);
595 }
596
597 static int m48t59_load(QEMUFile *f, void *opaque, int version_id)
598 {
599     m48t59_t *s = opaque;
600
601     if (version_id != 1)
602         return -EINVAL;
603
604     qemu_get_8s(f, &s->lock);
605     qemu_get_be16s(f, &s->addr);
606     qemu_get_buffer(f, s->buffer, s->size);
607
608     return 0;
609 }
610
611 static void m48t59_reset(void *opaque)
612 {
613     m48t59_t *NVRAM = opaque;
614
615     if (NVRAM->alrm_timer != NULL)
616         qemu_del_timer(NVRAM->alrm_timer);
617
618     if (NVRAM->wd_timer != NULL)
619         qemu_del_timer(NVRAM->wd_timer);
620 }
621
622 /* Initialisation routine */
623 m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base,
624                        uint32_t io_base, uint16_t size,
625                        int type)
626 {
627     m48t59_t *s;
628     target_phys_addr_t save_base;
629
630     s = qemu_mallocz(sizeof(m48t59_t));
631     if (!s)
632         return NULL;
633     s->buffer = qemu_mallocz(size);
634     if (!s->buffer) {
635         qemu_free(s);
636         return NULL;
637     }
638     s->IRQ = IRQ;
639     s->size = size;
640     s->mem_base = mem_base;
641     s->io_base = io_base;
642     s->addr = 0;
643     s->type = type;
644     if (io_base != 0) {
645         register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
646         register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
647     }
648     if (mem_base != 0) {
649         s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
650         cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
651     }
652     if (type == 59) {
653         s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
654         s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
655     }
656     s->lock = 0;
657
658     qemu_register_reset(m48t59_reset, s);
659     save_base = mem_base ? mem_base : io_base;
660     register_savevm("m48t59", save_base, 1, m48t59_save, m48t59_load, s);
661
662     return s;
663 }