clock year fix for sparc (Blue Swirl)
[qemu] / hw / m48t59.c
1 /*
2  * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
3  * 
4  * Copyright (c) 2003-2005 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     int      IRQ;
45     int mem_index;
46     uint32_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     localtime_r (&t, tm) ;
84 #endif
85 }
86
87 static void set_time (m48t59_t *NVRAM, struct tm *tm)
88 {
89     time_t now, new_time;
90     
91     new_time = mktime(tm);
92     now = time(NULL);
93     NVRAM->time_offset = new_time - now;
94 }
95
96 /* Alarm management */
97 static void alarm_cb (void *opaque)
98 {
99     struct tm tm, tm_now;
100     uint64_t next_time;
101     m48t59_t *NVRAM = opaque;
102
103     pic_set_irq(NVRAM->IRQ, 1);
104     if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && 
105         (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
106         (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
107         (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
108         /* Repeat once a month */
109         get_time(NVRAM, &tm_now);
110         memcpy(&tm, &tm_now, sizeof(struct tm));
111         tm.tm_mon++;
112         if (tm.tm_mon == 13) {
113             tm.tm_mon = 1;
114             tm.tm_year++;
115         }
116         next_time = mktime(&tm);
117     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
118                (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
119                (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
120                (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
121         /* Repeat once a day */
122         next_time = 24 * 60 * 60 + mktime(&tm_now);
123     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
124                (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
125                (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
126                (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
127         /* Repeat once an hour */
128         next_time = 60 * 60 + mktime(&tm_now);
129     } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
130                (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
131                (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
132                (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
133         /* Repeat once a minute */
134         next_time = 60 + mktime(&tm_now);
135     } else {
136         /* Repeat once a second */
137         next_time = 1 + mktime(&tm_now);
138     }
139     qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
140     pic_set_irq(NVRAM->IRQ, 0);
141 }
142
143
144 static void get_alarm (m48t59_t *NVRAM, struct tm *tm)
145 {
146 #ifdef _WIN32
147     memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
148 #else
149     localtime_r (&NVRAM->alarm, tm);
150 #endif
151 }
152
153 static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
154 {
155     NVRAM->alarm = mktime(tm);
156     if (NVRAM->alrm_timer != NULL) {
157         qemu_del_timer(NVRAM->alrm_timer);
158         NVRAM->alrm_timer = NULL;
159     }
160     if (NVRAM->alarm - time(NULL) > 0)
161         qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
162 }
163
164 /* Watchdog management */
165 static void watchdog_cb (void *opaque)
166 {
167     m48t59_t *NVRAM = opaque;
168
169     NVRAM->buffer[0x1FF0] |= 0x80;
170     if (NVRAM->buffer[0x1FF7] & 0x80) {
171         NVRAM->buffer[0x1FF7] = 0x00;
172         NVRAM->buffer[0x1FFC] &= ~0x40;
173         /* May it be a hw CPU Reset instead ? */
174         qemu_system_reset_request();
175     } else {
176         pic_set_irq(NVRAM->IRQ, 1);
177         pic_set_irq(NVRAM->IRQ, 0);
178     }
179 }
180
181 static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
182 {
183     uint64_t interval; /* in 1/16 seconds */
184
185     if (NVRAM->wd_timer != NULL) {
186         qemu_del_timer(NVRAM->wd_timer);
187         NVRAM->wd_timer = NULL;
188     }
189     NVRAM->buffer[0x1FF0] &= ~0x80;
190     if (value != 0) {
191         interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
192         qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
193                        ((interval * 1000) >> 4));
194     }
195 }
196
197 /* Direct access to NVRAM */
198 void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
199 {
200     struct tm tm;
201     int tmp;
202
203     if (addr > 0x1FF8 && addr < 0x2000)
204         NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
205     if (NVRAM->type == 8 && 
206         (addr >= 0x1ff0 && addr <= 0x1ff7))
207         goto do_write;
208     switch (addr) {
209     case 0x1FF0:
210         /* flags register : read-only */
211         break;
212     case 0x1FF1:
213         /* unused */
214         break;
215     case 0x1FF2:
216         /* alarm seconds */
217         tmp = fromBCD(val & 0x7F);
218         if (tmp >= 0 && tmp <= 59) {
219             get_alarm(NVRAM, &tm);
220             tm.tm_sec = tmp;
221             NVRAM->buffer[0x1FF2] = val;
222             set_alarm(NVRAM, &tm);
223         }
224         break;
225     case 0x1FF3:
226         /* alarm minutes */
227         tmp = fromBCD(val & 0x7F);
228         if (tmp >= 0 && tmp <= 59) {
229             get_alarm(NVRAM, &tm);
230             tm.tm_min = tmp;
231             NVRAM->buffer[0x1FF3] = val;
232             set_alarm(NVRAM, &tm);
233         }
234         break;
235     case 0x1FF4:
236         /* alarm hours */
237         tmp = fromBCD(val & 0x3F);
238         if (tmp >= 0 && tmp <= 23) {
239             get_alarm(NVRAM, &tm);
240             tm.tm_hour = tmp;
241             NVRAM->buffer[0x1FF4] = val;
242             set_alarm(NVRAM, &tm);
243         }
244         break;
245     case 0x1FF5:
246         /* alarm date */
247         tmp = fromBCD(val & 0x1F);
248         if (tmp != 0) {
249             get_alarm(NVRAM, &tm);
250             tm.tm_mday = tmp;
251             NVRAM->buffer[0x1FF5] = val;
252             set_alarm(NVRAM, &tm);
253         }
254         break;
255     case 0x1FF6:
256         /* interrupts */
257         NVRAM->buffer[0x1FF6] = val;
258         break;
259     case 0x1FF7:
260         /* watchdog */
261         NVRAM->buffer[0x1FF7] = val;
262         set_up_watchdog(NVRAM, val);
263         break;
264     case 0x1FF8:
265         /* control */
266         NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
267         break;
268     case 0x1FF9:
269         /* seconds (BCD) */
270         tmp = fromBCD(val & 0x7F);
271         if (tmp >= 0 && tmp <= 59) {
272             get_time(NVRAM, &tm);
273             tm.tm_sec = tmp;
274             set_time(NVRAM, &tm);
275         }
276         if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
277             if (val & 0x80) {
278                 NVRAM->stop_time = time(NULL);
279             } else {
280                 NVRAM->time_offset += NVRAM->stop_time - time(NULL);
281                 NVRAM->stop_time = 0;
282             }
283         }
284         NVRAM->buffer[0x1FF9] = val & 0x80;
285         break;
286     case 0x1FFA:
287         /* minutes (BCD) */
288         tmp = fromBCD(val & 0x7F);
289         if (tmp >= 0 && tmp <= 59) {
290             get_time(NVRAM, &tm);
291             tm.tm_min = tmp;
292             set_time(NVRAM, &tm);
293         }
294         break;
295     case 0x1FFB:
296         /* hours (BCD) */
297         tmp = fromBCD(val & 0x3F);
298         if (tmp >= 0 && tmp <= 23) {
299             get_time(NVRAM, &tm);
300             tm.tm_hour = tmp;
301             set_time(NVRAM, &tm);
302         }
303         break;
304     case 0x1FFC:
305         /* day of the week / century */
306         tmp = fromBCD(val & 0x07);
307         get_time(NVRAM, &tm);
308         tm.tm_wday = tmp;
309         set_time(NVRAM, &tm);
310         NVRAM->buffer[0x1FFC] = val & 0x40;
311         break;
312     case 0x1FFD:
313         /* date */
314         tmp = fromBCD(val & 0x1F);
315         if (tmp != 0) {
316             get_time(NVRAM, &tm);
317             tm.tm_mday = tmp;
318             set_time(NVRAM, &tm);
319         }
320         break;
321     case 0x1FFE:
322         /* month */
323         tmp = fromBCD(val & 0x1F);
324         if (tmp >= 1 && tmp <= 12) {
325             get_time(NVRAM, &tm);
326             tm.tm_mon = tmp - 1;
327             set_time(NVRAM, &tm);
328         }
329         break;
330     case 0x1FFF:
331         /* year */
332         tmp = fromBCD(val);
333         if (tmp >= 0 && tmp <= 99) {
334             get_time(NVRAM, &tm);
335             if (NVRAM->type == 8)
336                 tm.tm_year = fromBCD(val) + 68; // Base year is 1968
337             else
338                 tm.tm_year = fromBCD(val);
339             set_time(NVRAM, &tm);
340         }
341         break;
342     default:
343         /* Check lock registers state */
344         if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
345             break;
346         if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
347             break;
348     do_write:
349         if (addr < NVRAM->size) {
350             NVRAM->buffer[addr] = val & 0xFF;
351         }
352         break;
353     }
354 }
355
356 uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr)
357 {
358     struct tm tm;
359     uint32_t retval = 0xFF;
360
361     if (NVRAM->type == 8 && 
362         (addr >= 0x1ff0 && addr <= 0x1ff7))
363         goto do_read;
364     switch (addr) {
365     case 0x1FF0:
366         /* flags register */
367         goto do_read;
368     case 0x1FF1:
369         /* unused */
370         retval = 0;
371         break;
372     case 0x1FF2:
373         /* alarm seconds */
374         goto do_read;
375     case 0x1FF3:
376         /* alarm minutes */
377         goto do_read;
378     case 0x1FF4:
379         /* alarm hours */
380         goto do_read;
381     case 0x1FF5:
382         /* alarm date */
383         goto do_read;
384     case 0x1FF6:
385         /* interrupts */
386         goto do_read;
387     case 0x1FF7:
388         /* A read resets the watchdog */
389         set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
390         goto do_read;
391     case 0x1FF8:
392         /* control */
393         goto do_read;
394     case 0x1FF9:
395         /* seconds (BCD) */
396         get_time(NVRAM, &tm);
397         retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
398         break;
399     case 0x1FFA:
400         /* minutes (BCD) */
401         get_time(NVRAM, &tm);
402         retval = toBCD(tm.tm_min);
403         break;
404     case 0x1FFB:
405         /* hours (BCD) */
406         get_time(NVRAM, &tm);
407         retval = toBCD(tm.tm_hour);
408         break;
409     case 0x1FFC:
410         /* day of the week / century */
411         get_time(NVRAM, &tm);
412         retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
413         break;
414     case 0x1FFD:
415         /* date */
416         get_time(NVRAM, &tm);
417         retval = toBCD(tm.tm_mday);
418         break;
419     case 0x1FFE:
420         /* month */
421         get_time(NVRAM, &tm);
422         retval = toBCD(tm.tm_mon + 1);
423         break;
424     case 0x1FFF:
425         /* year */
426         get_time(NVRAM, &tm);
427         if (NVRAM->type == 8) 
428             retval = toBCD(tm.tm_year - 68); // Base year is 1968
429         else
430             retval = toBCD(tm.tm_year);
431         break;
432     default:
433         /* Check lock registers state */
434         if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
435             break;
436         if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
437             break;
438     do_read:
439         if (addr < NVRAM->size) {
440             retval = NVRAM->buffer[addr];
441         }
442         break;
443     }
444     if (addr > 0x1FF9 && addr < 0x2000)
445         NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
446
447     return retval;
448 }
449
450 void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr)
451 {
452     NVRAM->addr = addr;
453 }
454
455 void m48t59_toggle_lock (m48t59_t *NVRAM, int lock)
456 {
457     NVRAM->lock ^= 1 << lock;
458 }
459
460 /* IO access to NVRAM */
461 static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
462 {
463     m48t59_t *NVRAM = opaque;
464
465     addr -= NVRAM->io_base;
466     NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
467     switch (addr) {
468     case 0:
469         NVRAM->addr &= ~0x00FF;
470         NVRAM->addr |= val;
471         break;
472     case 1:
473         NVRAM->addr &= ~0xFF00;
474         NVRAM->addr |= val << 8;
475         break;
476     case 3:
477         m48t59_write(NVRAM, val, NVRAM->addr);
478         NVRAM->addr = 0x0000;
479         break;
480     default:
481         break;
482     }
483 }
484
485 static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
486 {
487     m48t59_t *NVRAM = opaque;
488     uint32_t retval;
489
490     addr -= NVRAM->io_base;
491     switch (addr) {
492     case 3:
493         retval = m48t59_read(NVRAM, NVRAM->addr);
494         break;
495     default:
496         retval = -1;
497         break;
498     }
499     NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
500
501     return retval;
502 }
503
504 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
505 {
506     m48t59_t *NVRAM = opaque;
507     
508     addr -= NVRAM->mem_base;
509     m48t59_write(NVRAM, addr, value & 0xff);
510 }
511
512 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
513 {
514     m48t59_t *NVRAM = opaque;
515     
516     addr -= NVRAM->mem_base;
517     m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
518     m48t59_write(NVRAM, addr + 1, value & 0xff);
519 }
520
521 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
522 {
523     m48t59_t *NVRAM = opaque;
524     
525     addr -= NVRAM->mem_base;
526     m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
527     m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
528     m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
529     m48t59_write(NVRAM, addr + 3, value & 0xff);
530 }
531
532 static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
533 {
534     m48t59_t *NVRAM = opaque;
535     uint32_t retval;
536     
537     addr -= NVRAM->mem_base;
538     retval = m48t59_read(NVRAM, addr);
539     return retval;
540 }
541
542 static uint32_t nvram_readw (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) << 8;
549     retval |= m48t59_read(NVRAM, addr + 1);
550     return retval;
551 }
552
553 static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
554 {
555     m48t59_t *NVRAM = opaque;
556     uint32_t retval;
557
558     addr -= NVRAM->mem_base;
559     retval = m48t59_read(NVRAM, addr) << 24;
560     retval |= m48t59_read(NVRAM, addr + 1) << 16;
561     retval |= m48t59_read(NVRAM, addr + 2) << 8;
562     retval |= m48t59_read(NVRAM, addr + 3);
563     return retval;
564 }
565
566 static CPUWriteMemoryFunc *nvram_write[] = {
567     &nvram_writeb,
568     &nvram_writew,
569     &nvram_writel,
570 };
571
572 static CPUReadMemoryFunc *nvram_read[] = {
573     &nvram_readb,
574     &nvram_readw,
575     &nvram_readl,
576 };
577
578 /* Initialisation routine */
579 m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
580                        uint32_t io_base, uint16_t size,
581                        int type)
582 {
583     m48t59_t *s;
584
585     s = qemu_mallocz(sizeof(m48t59_t));
586     if (!s)
587         return NULL;
588     s->buffer = qemu_mallocz(size);
589     if (!s->buffer) {
590         qemu_free(s);
591         return NULL;
592     }
593     s->IRQ = IRQ;
594     s->size = size;
595     s->mem_base = mem_base;
596     s->io_base = io_base;
597     s->addr = 0;
598     s->type = type;
599     if (io_base != 0) {
600         register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
601         register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
602     }
603     if (mem_base != 0) {
604         s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
605         cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
606     }
607     if (type == 59) {
608         s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
609         s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
610     }
611     s->lock = 0;
612
613     return s;
614 }