Less magic constants, by Filip Navara.
[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         NVRAM->alrm_timer = NULL;
165     }
166     if (NVRAM->alarm - time(NULL) > 0)
167         qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
168 }
169
170 /* Watchdog management */
171 static void watchdog_cb (void *opaque)
172 {
173     m48t59_t *NVRAM = opaque;
174
175     NVRAM->buffer[0x1FF0] |= 0x80;
176     if (NVRAM->buffer[0x1FF7] & 0x80) {
177         NVRAM->buffer[0x1FF7] = 0x00;
178         NVRAM->buffer[0x1FFC] &= ~0x40;
179         /* May it be a hw CPU Reset instead ? */
180         qemu_system_reset_request();
181     } else {
182         qemu_set_irq(NVRAM->IRQ, 1);
183         qemu_set_irq(NVRAM->IRQ, 0);
184     }
185 }
186
187 static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
188 {
189     uint64_t interval; /* in 1/16 seconds */
190
191     if (NVRAM->wd_timer != NULL) {
192         qemu_del_timer(NVRAM->wd_timer);
193         NVRAM->wd_timer = NULL;
194     }
195     NVRAM->buffer[0x1FF0] &= ~0x80;
196     if (value != 0) {
197         interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
198         qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
199                        ((interval * 1000) >> 4));
200     }
201 }
202
203 /* Direct access to NVRAM */
204 void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
205 {
206     struct tm tm;
207     int tmp;
208
209     if (addr > 0x1FF8 && addr < 0x2000)
210         NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
211     if (NVRAM->type == 8 && 
212         (addr >= 0x1ff0 && addr <= 0x1ff7))
213         goto do_write;
214     switch (addr) {
215     case 0x1FF0:
216         /* flags register : read-only */
217         break;
218     case 0x1FF1:
219         /* unused */
220         break;
221     case 0x1FF2:
222         /* alarm seconds */
223         tmp = fromBCD(val & 0x7F);
224         if (tmp >= 0 && tmp <= 59) {
225             get_alarm(NVRAM, &tm);
226             tm.tm_sec = tmp;
227             NVRAM->buffer[0x1FF2] = val;
228             set_alarm(NVRAM, &tm);
229         }
230         break;
231     case 0x1FF3:
232         /* alarm minutes */
233         tmp = fromBCD(val & 0x7F);
234         if (tmp >= 0 && tmp <= 59) {
235             get_alarm(NVRAM, &tm);
236             tm.tm_min = tmp;
237             NVRAM->buffer[0x1FF3] = val;
238             set_alarm(NVRAM, &tm);
239         }
240         break;
241     case 0x1FF4:
242         /* alarm hours */
243         tmp = fromBCD(val & 0x3F);
244         if (tmp >= 0 && tmp <= 23) {
245             get_alarm(NVRAM, &tm);
246             tm.tm_hour = tmp;
247             NVRAM->buffer[0x1FF4] = val;
248             set_alarm(NVRAM, &tm);
249         }
250         break;
251     case 0x1FF5:
252         /* alarm date */
253         tmp = fromBCD(val & 0x1F);
254         if (tmp != 0) {
255             get_alarm(NVRAM, &tm);
256             tm.tm_mday = tmp;
257             NVRAM->buffer[0x1FF5] = val;
258             set_alarm(NVRAM, &tm);
259         }
260         break;
261     case 0x1FF6:
262         /* interrupts */
263         NVRAM->buffer[0x1FF6] = val;
264         break;
265     case 0x1FF7:
266         /* watchdog */
267         NVRAM->buffer[0x1FF7] = val;
268         set_up_watchdog(NVRAM, val);
269         break;
270     case 0x1FF8:
271         /* control */
272         NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
273         break;
274     case 0x1FF9:
275         /* seconds (BCD) */
276         tmp = fromBCD(val & 0x7F);
277         if (tmp >= 0 && tmp <= 59) {
278             get_time(NVRAM, &tm);
279             tm.tm_sec = tmp;
280             set_time(NVRAM, &tm);
281         }
282         if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
283             if (val & 0x80) {
284                 NVRAM->stop_time = time(NULL);
285             } else {
286                 NVRAM->time_offset += NVRAM->stop_time - time(NULL);
287                 NVRAM->stop_time = 0;
288             }
289         }
290         NVRAM->buffer[0x1FF9] = val & 0x80;
291         break;
292     case 0x1FFA:
293         /* minutes (BCD) */
294         tmp = fromBCD(val & 0x7F);
295         if (tmp >= 0 && tmp <= 59) {
296             get_time(NVRAM, &tm);
297             tm.tm_min = tmp;
298             set_time(NVRAM, &tm);
299         }
300         break;
301     case 0x1FFB:
302         /* hours (BCD) */
303         tmp = fromBCD(val & 0x3F);
304         if (tmp >= 0 && tmp <= 23) {
305             get_time(NVRAM, &tm);
306             tm.tm_hour = tmp;
307             set_time(NVRAM, &tm);
308         }
309         break;
310     case 0x1FFC:
311         /* day of the week / century */
312         tmp = fromBCD(val & 0x07);
313         get_time(NVRAM, &tm);
314         tm.tm_wday = tmp;
315         set_time(NVRAM, &tm);
316         NVRAM->buffer[0x1FFC] = val & 0x40;
317         break;
318     case 0x1FFD:
319         /* date */
320         tmp = fromBCD(val & 0x1F);
321         if (tmp != 0) {
322             get_time(NVRAM, &tm);
323             tm.tm_mday = tmp;
324             set_time(NVRAM, &tm);
325         }
326         break;
327     case 0x1FFE:
328         /* month */
329         tmp = fromBCD(val & 0x1F);
330         if (tmp >= 1 && tmp <= 12) {
331             get_time(NVRAM, &tm);
332             tm.tm_mon = tmp - 1;
333             set_time(NVRAM, &tm);
334         }
335         break;
336     case 0x1FFF:
337         /* year */
338         tmp = fromBCD(val);
339         if (tmp >= 0 && tmp <= 99) {
340             get_time(NVRAM, &tm);
341             if (NVRAM->type == 8)
342                 tm.tm_year = fromBCD(val) + 68; // Base year is 1968
343             else
344                 tm.tm_year = fromBCD(val);
345             set_time(NVRAM, &tm);
346         }
347         break;
348     default:
349         /* Check lock registers state */
350         if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
351             break;
352         if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
353             break;
354     do_write:
355         if (addr < NVRAM->size) {
356             NVRAM->buffer[addr] = val & 0xFF;
357         }
358         break;
359     }
360 }
361
362 uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr)
363 {
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 (m48t59_t *NVRAM, uint32_t addr)
457 {
458     NVRAM->addr = addr;
459 }
460
461 void m48t59_toggle_lock (m48t59_t *NVRAM, int lock)
462 {
463     NVRAM->lock ^= 1 << lock;
464 }
465
466 /* IO access to NVRAM */
467 static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
468 {
469     m48t59_t *NVRAM = opaque;
470
471     addr -= NVRAM->io_base;
472     NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
473     switch (addr) {
474     case 0:
475         NVRAM->addr &= ~0x00FF;
476         NVRAM->addr |= val;
477         break;
478     case 1:
479         NVRAM->addr &= ~0xFF00;
480         NVRAM->addr |= val << 8;
481         break;
482     case 3:
483         m48t59_write(NVRAM, val, NVRAM->addr);
484         NVRAM->addr = 0x0000;
485         break;
486     default:
487         break;
488     }
489 }
490
491 static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
492 {
493     m48t59_t *NVRAM = opaque;
494     uint32_t retval;
495
496     addr -= NVRAM->io_base;
497     switch (addr) {
498     case 3:
499         retval = m48t59_read(NVRAM, NVRAM->addr);
500         break;
501     default:
502         retval = -1;
503         break;
504     }
505     NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
506
507     return retval;
508 }
509
510 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
511 {
512     m48t59_t *NVRAM = opaque;
513     
514     addr -= NVRAM->mem_base;
515     m48t59_write(NVRAM, addr, value & 0xff);
516 }
517
518 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
519 {
520     m48t59_t *NVRAM = opaque;
521     
522     addr -= NVRAM->mem_base;
523     m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
524     m48t59_write(NVRAM, addr + 1, value & 0xff);
525 }
526
527 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
528 {
529     m48t59_t *NVRAM = opaque;
530     
531     addr -= NVRAM->mem_base;
532     m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
533     m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
534     m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
535     m48t59_write(NVRAM, addr + 3, value & 0xff);
536 }
537
538 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
539 {
540     m48t59_t *NVRAM = opaque;
541     uint32_t retval;
542     
543     addr -= NVRAM->mem_base;
544     retval = m48t59_read(NVRAM, addr);
545     return retval;
546 }
547
548 static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
549 {
550     m48t59_t *NVRAM = opaque;
551     uint32_t retval;
552     
553     addr -= NVRAM->mem_base;
554     retval = m48t59_read(NVRAM, addr) << 8;
555     retval |= m48t59_read(NVRAM, addr + 1);
556     return retval;
557 }
558
559 static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
560 {
561     m48t59_t *NVRAM = opaque;
562     uint32_t retval;
563
564     addr -= NVRAM->mem_base;
565     retval = m48t59_read(NVRAM, addr) << 24;
566     retval |= m48t59_read(NVRAM, addr + 1) << 16;
567     retval |= m48t59_read(NVRAM, addr + 2) << 8;
568     retval |= m48t59_read(NVRAM, addr + 3);
569     return retval;
570 }
571
572 static CPUWriteMemoryFunc *nvram_write[] = {
573     &nvram_writeb,
574     &nvram_writew,
575     &nvram_writel,
576 };
577
578 static CPUReadMemoryFunc *nvram_read[] = {
579     &nvram_readb,
580     &nvram_readw,
581     &nvram_readl,
582 };
583
584 static void m48t59_save(QEMUFile *f, void *opaque)
585 {
586     m48t59_t *s = opaque;
587
588     qemu_put_8s(f, &s->lock);
589     qemu_put_be16s(f, &s->addr);
590     qemu_put_buffer(f, s->buffer, s->size);
591 }
592
593 static int m48t59_load(QEMUFile *f, void *opaque, int version_id)
594 {
595     m48t59_t *s = opaque;
596
597     if (version_id != 1)
598         return -EINVAL;
599
600     qemu_get_8s(f, &s->lock);
601     qemu_get_be16s(f, &s->addr);
602     qemu_get_buffer(f, s->buffer, s->size);
603
604     return 0;
605 }
606
607 static void m48t59_reset(void *opaque)
608 {
609     m48t59_t *NVRAM = opaque;
610
611     if (NVRAM->alrm_timer != NULL)
612         qemu_del_timer(NVRAM->alrm_timer);
613
614     if (NVRAM->wd_timer != NULL)
615         qemu_del_timer(NVRAM->wd_timer);
616 }
617
618 /* Initialisation routine */
619 m48t59_t *m48t59_init (qemu_irq IRQ, target_phys_addr_t mem_base,
620                        uint32_t io_base, uint16_t size,
621                        int type)
622 {
623     m48t59_t *s;
624     target_phys_addr_t save_base;
625
626     s = qemu_mallocz(sizeof(m48t59_t));
627     if (!s)
628         return NULL;
629     s->buffer = qemu_mallocz(size);
630     if (!s->buffer) {
631         qemu_free(s);
632         return NULL;
633     }
634     s->IRQ = IRQ;
635     s->size = size;
636     s->mem_base = mem_base;
637     s->io_base = io_base;
638     s->addr = 0;
639     s->type = type;
640     if (io_base != 0) {
641         register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
642         register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
643     }
644     if (mem_base != 0) {
645         s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
646         cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
647     }
648     if (type == 59) {
649         s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
650         s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
651     }
652     s->lock = 0;
653
654     qemu_register_reset(m48t59_reset, s);
655     save_base = mem_base ? mem_base : io_base;
656     register_savevm("m48t59", save_base, 1, m48t59_save, m48t59_load, s);
657
658     return s;
659 }