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