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