~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to hw/m48t59.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "qemu-timer.h"
 
27
#include "sysemu.h"
 
28
#include "sysbus.h"
 
29
#include "isa.h"
 
30
 
 
31
//#define DEBUG_NVRAM
 
32
 
 
33
#if defined(DEBUG_NVRAM)
 
34
#define NVRAM_PRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
 
35
#else
 
36
#define NVRAM_PRINTF(fmt, ...) do { } while (0)
 
37
#endif
 
38
 
 
39
/*
 
40
 * The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
 
41
 * alarm and a watchdog timer and related control registers. In the
 
42
 * PPC platform there is also a nvram lock function.
 
43
 */
 
44
 
 
45
/*
 
46
 * Chipset docs:
 
47
 * http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
 
48
 * http://www.st.com/stonline/products/literature/ds/2411/m48t08.pdf
 
49
 * http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
 
50
 */
 
51
 
 
52
struct M48t59State {
 
53
    /* Hardware parameters */
 
54
    qemu_irq IRQ;
 
55
    uint32_t io_base;
 
56
    uint32_t size;
 
57
    /* RTC management */
 
58
    time_t   time_offset;
 
59
    time_t   stop_time;
 
60
    /* Alarm & watchdog */
 
61
    struct tm alarm;
 
62
    struct QEMUTimer *alrm_timer;
 
63
    struct QEMUTimer *wd_timer;
 
64
    /* NVRAM storage */
 
65
    uint8_t *buffer;
 
66
    /* Model parameters */
 
67
    uint32_t type; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
 
68
    /* NVRAM storage */
 
69
    uint16_t addr;
 
70
    uint8_t  lock;
 
71
};
 
72
 
 
73
typedef struct M48t59ISAState {
 
74
    ISADevice busdev;
 
75
    M48t59State state;
 
76
    MemoryRegion io;
 
77
} M48t59ISAState;
 
78
 
 
79
typedef struct M48t59SysBusState {
 
80
    SysBusDevice busdev;
 
81
    M48t59State state;
 
82
} M48t59SysBusState;
 
83
 
 
84
/* Fake timer functions */
 
85
 
 
86
/* Alarm management */
 
87
static void alarm_cb (void *opaque)
 
88
{
 
89
    struct tm tm;
 
90
    uint64_t next_time;
 
91
    M48t59State *NVRAM = opaque;
 
92
 
 
93
    qemu_set_irq(NVRAM->IRQ, 1);
 
94
    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
 
95
        (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
 
96
        (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 
97
        (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 
98
        /* Repeat once a month */
 
99
        qemu_get_timedate(&tm, NVRAM->time_offset);
 
100
        tm.tm_mon++;
 
101
        if (tm.tm_mon == 13) {
 
102
            tm.tm_mon = 1;
 
103
            tm.tm_year++;
 
104
        }
 
105
        next_time = qemu_timedate_diff(&tm) - NVRAM->time_offset;
 
106
    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 
107
               (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
 
108
               (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 
109
               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 
110
        /* Repeat once a day */
 
111
        next_time = 24 * 60 * 60;
 
112
    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 
113
               (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
 
114
               (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 
115
               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 
116
        /* Repeat once an hour */
 
117
        next_time = 60 * 60;
 
118
    } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
 
119
               (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
 
120
               (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
 
121
               (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
 
122
        /* Repeat once a minute */
 
123
        next_time = 60;
 
124
    } else {
 
125
        /* Repeat once a second */
 
126
        next_time = 1;
 
127
    }
 
128
    qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(vm_clock) +
 
129
                    next_time * 1000);
 
130
    qemu_set_irq(NVRAM->IRQ, 0);
 
131
}
 
132
 
 
133
static void set_alarm(M48t59State *NVRAM)
 
134
{
 
135
    int diff;
 
136
    if (NVRAM->alrm_timer != NULL) {
 
137
        qemu_del_timer(NVRAM->alrm_timer);
 
138
        diff = qemu_timedate_diff(&NVRAM->alarm) - NVRAM->time_offset;
 
139
        if (diff > 0)
 
140
            qemu_mod_timer(NVRAM->alrm_timer, diff * 1000);
 
141
    }
 
142
}
 
143
 
 
144
/* RTC management helpers */
 
145
static inline void get_time(M48t59State *NVRAM, struct tm *tm)
 
146
{
 
147
    qemu_get_timedate(tm, NVRAM->time_offset);
 
148
}
 
149
 
 
150
static void set_time(M48t59State *NVRAM, struct tm *tm)
 
151
{
 
152
    NVRAM->time_offset = qemu_timedate_diff(tm);
 
153
    set_alarm(NVRAM);
 
154
}
 
155
 
 
156
/* Watchdog management */
 
157
static void watchdog_cb (void *opaque)
 
158
{
 
159
    M48t59State *NVRAM = opaque;
 
160
 
 
161
    NVRAM->buffer[0x1FF0] |= 0x80;
 
162
    if (NVRAM->buffer[0x1FF7] & 0x80) {
 
163
        NVRAM->buffer[0x1FF7] = 0x00;
 
164
        NVRAM->buffer[0x1FFC] &= ~0x40;
 
165
        /* May it be a hw CPU Reset instead ? */
 
166
        qemu_system_reset_request();
 
167
    } else {
 
168
        qemu_set_irq(NVRAM->IRQ, 1);
 
169
        qemu_set_irq(NVRAM->IRQ, 0);
 
170
    }
 
171
}
 
172
 
 
173
static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
 
174
{
 
175
    uint64_t interval; /* in 1/16 seconds */
 
176
 
 
177
    NVRAM->buffer[0x1FF0] &= ~0x80;
 
178
    if (NVRAM->wd_timer != NULL) {
 
179
        qemu_del_timer(NVRAM->wd_timer);
 
180
        if (value != 0) {
 
181
            interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
 
182
            qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
 
183
                           ((interval * 1000) >> 4));
 
184
        }
 
185
    }
 
186
}
 
187
 
 
188
/* Direct access to NVRAM */
 
189
void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
 
190
{
 
191
    M48t59State *NVRAM = opaque;
 
192
    struct tm tm;
 
193
    int tmp;
 
194
 
 
195
    if (addr > 0x1FF8 && addr < 0x2000)
 
196
        NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
 
197
 
 
198
    /* check for NVRAM access */
 
199
    if ((NVRAM->type == 2 && addr < 0x7f8) ||
 
200
        (NVRAM->type == 8 && addr < 0x1ff8) ||
 
201
        (NVRAM->type == 59 && addr < 0x1ff0))
 
202
        goto do_write;
 
203
 
 
204
    /* TOD access */
 
205
    switch (addr) {
 
206
    case 0x1FF0:
 
207
        /* flags register : read-only */
 
208
        break;
 
209
    case 0x1FF1:
 
210
        /* unused */
 
211
        break;
 
212
    case 0x1FF2:
 
213
        /* alarm seconds */
 
214
        tmp = from_bcd(val & 0x7F);
 
215
        if (tmp >= 0 && tmp <= 59) {
 
216
            NVRAM->alarm.tm_sec = tmp;
 
217
            NVRAM->buffer[0x1FF2] = val;
 
218
            set_alarm(NVRAM);
 
219
        }
 
220
        break;
 
221
    case 0x1FF3:
 
222
        /* alarm minutes */
 
223
        tmp = from_bcd(val & 0x7F);
 
224
        if (tmp >= 0 && tmp <= 59) {
 
225
            NVRAM->alarm.tm_min = tmp;
 
226
            NVRAM->buffer[0x1FF3] = val;
 
227
            set_alarm(NVRAM);
 
228
        }
 
229
        break;
 
230
    case 0x1FF4:
 
231
        /* alarm hours */
 
232
        tmp = from_bcd(val & 0x3F);
 
233
        if (tmp >= 0 && tmp <= 23) {
 
234
            NVRAM->alarm.tm_hour = tmp;
 
235
            NVRAM->buffer[0x1FF4] = val;
 
236
            set_alarm(NVRAM);
 
237
        }
 
238
        break;
 
239
    case 0x1FF5:
 
240
        /* alarm date */
 
241
        tmp = from_bcd(val & 0x1F);
 
242
        if (tmp != 0) {
 
243
            NVRAM->alarm.tm_mday = tmp;
 
244
            NVRAM->buffer[0x1FF5] = val;
 
245
            set_alarm(NVRAM);
 
246
        }
 
247
        break;
 
248
    case 0x1FF6:
 
249
        /* interrupts */
 
250
        NVRAM->buffer[0x1FF6] = val;
 
251
        break;
 
252
    case 0x1FF7:
 
253
        /* watchdog */
 
254
        NVRAM->buffer[0x1FF7] = val;
 
255
        set_up_watchdog(NVRAM, val);
 
256
        break;
 
257
    case 0x1FF8:
 
258
    case 0x07F8:
 
259
        /* control */
 
260
       NVRAM->buffer[addr] = (val & ~0xA0) | 0x90;
 
261
        break;
 
262
    case 0x1FF9:
 
263
    case 0x07F9:
 
264
        /* seconds (BCD) */
 
265
        tmp = from_bcd(val & 0x7F);
 
266
        if (tmp >= 0 && tmp <= 59) {
 
267
            get_time(NVRAM, &tm);
 
268
            tm.tm_sec = tmp;
 
269
            set_time(NVRAM, &tm);
 
270
        }
 
271
        if ((val & 0x80) ^ (NVRAM->buffer[addr] & 0x80)) {
 
272
            if (val & 0x80) {
 
273
                NVRAM->stop_time = time(NULL);
 
274
            } else {
 
275
                NVRAM->time_offset += NVRAM->stop_time - time(NULL);
 
276
                NVRAM->stop_time = 0;
 
277
            }
 
278
        }
 
279
        NVRAM->buffer[addr] = val & 0x80;
 
280
        break;
 
281
    case 0x1FFA:
 
282
    case 0x07FA:
 
283
        /* minutes (BCD) */
 
284
        tmp = from_bcd(val & 0x7F);
 
285
        if (tmp >= 0 && tmp <= 59) {
 
286
            get_time(NVRAM, &tm);
 
287
            tm.tm_min = tmp;
 
288
            set_time(NVRAM, &tm);
 
289
        }
 
290
        break;
 
291
    case 0x1FFB:
 
292
    case 0x07FB:
 
293
        /* hours (BCD) */
 
294
        tmp = from_bcd(val & 0x3F);
 
295
        if (tmp >= 0 && tmp <= 23) {
 
296
            get_time(NVRAM, &tm);
 
297
            tm.tm_hour = tmp;
 
298
            set_time(NVRAM, &tm);
 
299
        }
 
300
        break;
 
301
    case 0x1FFC:
 
302
    case 0x07FC:
 
303
        /* day of the week / century */
 
304
        tmp = from_bcd(val & 0x07);
 
305
        get_time(NVRAM, &tm);
 
306
        tm.tm_wday = tmp;
 
307
        set_time(NVRAM, &tm);
 
308
        NVRAM->buffer[addr] = val & 0x40;
 
309
        break;
 
310
    case 0x1FFD:
 
311
    case 0x07FD:
 
312
        /* date */
 
313
        tmp = from_bcd(val & 0x1F);
 
314
        if (tmp != 0) {
 
315
            get_time(NVRAM, &tm);
 
316
            tm.tm_mday = tmp;
 
317
            set_time(NVRAM, &tm);
 
318
        }
 
319
        break;
 
320
    case 0x1FFE:
 
321
    case 0x07FE:
 
322
        /* month */
 
323
        tmp = from_bcd(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
    case 0x07FF:
 
332
        /* year */
 
333
        tmp = from_bcd(val);
 
334
        if (tmp >= 0 && tmp <= 99) {
 
335
            get_time(NVRAM, &tm);
 
336
            if (NVRAM->type == 8)
 
337
                tm.tm_year = from_bcd(val) + 68; // Base year is 1968
 
338
            else
 
339
                tm.tm_year = from_bcd(val);
 
340
            set_time(NVRAM, &tm);
 
341
        }
 
342
        break;
 
343
    default:
 
344
        /* Check lock registers state */
 
345
        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
 
346
            break;
 
347
        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
 
348
            break;
 
349
    do_write:
 
350
        if (addr < NVRAM->size) {
 
351
            NVRAM->buffer[addr] = val & 0xFF;
 
352
        }
 
353
        break;
 
354
    }
 
355
}
 
356
 
 
357
uint32_t m48t59_read (void *opaque, uint32_t addr)
 
358
{
 
359
    M48t59State *NVRAM = opaque;
 
360
    struct tm tm;
 
361
    uint32_t retval = 0xFF;
 
362
 
 
363
    /* check for NVRAM access */
 
364
    if ((NVRAM->type == 2 && addr < 0x078f) ||
 
365
        (NVRAM->type == 8 && addr < 0x1ff8) ||
 
366
        (NVRAM->type == 59 && addr < 0x1ff0))
 
367
        goto do_read;
 
368
 
 
369
    /* TOD access */
 
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
    case 0x07F8:
 
399
        /* control */
 
400
        goto do_read;
 
401
    case 0x1FF9:
 
402
    case 0x07F9:
 
403
        /* seconds (BCD) */
 
404
        get_time(NVRAM, &tm);
 
405
        retval = (NVRAM->buffer[addr] & 0x80) | to_bcd(tm.tm_sec);
 
406
        break;
 
407
    case 0x1FFA:
 
408
    case 0x07FA:
 
409
        /* minutes (BCD) */
 
410
        get_time(NVRAM, &tm);
 
411
        retval = to_bcd(tm.tm_min);
 
412
        break;
 
413
    case 0x1FFB:
 
414
    case 0x07FB:
 
415
        /* hours (BCD) */
 
416
        get_time(NVRAM, &tm);
 
417
        retval = to_bcd(tm.tm_hour);
 
418
        break;
 
419
    case 0x1FFC:
 
420
    case 0x07FC:
 
421
        /* day of the week / century */
 
422
        get_time(NVRAM, &tm);
 
423
        retval = NVRAM->buffer[addr] | tm.tm_wday;
 
424
        break;
 
425
    case 0x1FFD:
 
426
    case 0x07FD:
 
427
        /* date */
 
428
        get_time(NVRAM, &tm);
 
429
        retval = to_bcd(tm.tm_mday);
 
430
        break;
 
431
    case 0x1FFE:
 
432
    case 0x07FE:
 
433
        /* month */
 
434
        get_time(NVRAM, &tm);
 
435
        retval = to_bcd(tm.tm_mon + 1);
 
436
        break;
 
437
    case 0x1FFF:
 
438
    case 0x07FF:
 
439
        /* year */
 
440
        get_time(NVRAM, &tm);
 
441
        if (NVRAM->type == 8)
 
442
            retval = to_bcd(tm.tm_year - 68); // Base year is 1968
 
443
        else
 
444
            retval = to_bcd(tm.tm_year);
 
445
        break;
 
446
    default:
 
447
        /* Check lock registers state */
 
448
        if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
 
449
            break;
 
450
        if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
 
451
            break;
 
452
    do_read:
 
453
        if (addr < NVRAM->size) {
 
454
            retval = NVRAM->buffer[addr];
 
455
        }
 
456
        break;
 
457
    }
 
458
    if (addr > 0x1FF9 && addr < 0x2000)
 
459
       NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
 
460
 
 
461
    return retval;
 
462
}
 
463
 
 
464
void m48t59_set_addr (void *opaque, uint32_t addr)
 
465
{
 
466
    M48t59State *NVRAM = opaque;
 
467
 
 
468
    NVRAM->addr = addr;
 
469
}
 
470
 
 
471
void m48t59_toggle_lock (void *opaque, int lock)
 
472
{
 
473
    M48t59State *NVRAM = opaque;
 
474
 
 
475
    NVRAM->lock ^= 1 << lock;
 
476
}
 
477
 
 
478
/* IO access to NVRAM */
 
479
static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
 
480
{
 
481
    M48t59State *NVRAM = opaque;
 
482
 
 
483
    NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
 
484
    switch (addr) {
 
485
    case 0:
 
486
        NVRAM->addr &= ~0x00FF;
 
487
        NVRAM->addr |= val;
 
488
        break;
 
489
    case 1:
 
490
        NVRAM->addr &= ~0xFF00;
 
491
        NVRAM->addr |= val << 8;
 
492
        break;
 
493
    case 3:
 
494
        m48t59_write(NVRAM, NVRAM->addr, val);
 
495
        NVRAM->addr = 0x0000;
 
496
        break;
 
497
    default:
 
498
        break;
 
499
    }
 
500
}
 
501
 
 
502
static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
 
503
{
 
504
    M48t59State *NVRAM = opaque;
 
505
    uint32_t retval;
 
506
 
 
507
    switch (addr) {
 
508
    case 3:
 
509
        retval = m48t59_read(NVRAM, NVRAM->addr);
 
510
        break;
 
511
    default:
 
512
        retval = -1;
 
513
        break;
 
514
    }
 
515
    NVRAM_PRINTF("%s: 0x%08x <= 0x%08x\n", __func__, addr, retval);
 
516
 
 
517
    return retval;
 
518
}
 
519
 
 
520
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
 
521
{
 
522
    M48t59State *NVRAM = opaque;
 
523
 
 
524
    m48t59_write(NVRAM, addr, value & 0xff);
 
525
}
 
526
 
 
527
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
 
528
{
 
529
    M48t59State *NVRAM = opaque;
 
530
 
 
531
    m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
 
532
    m48t59_write(NVRAM, addr + 1, value & 0xff);
 
533
}
 
534
 
 
535
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 
536
{
 
537
    M48t59State *NVRAM = opaque;
 
538
 
 
539
    m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
 
540
    m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
 
541
    m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
 
542
    m48t59_write(NVRAM, addr + 3, value & 0xff);
 
543
}
 
544
 
 
545
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
 
546
{
 
547
    M48t59State *NVRAM = opaque;
 
548
    uint32_t retval;
 
549
 
 
550
    retval = m48t59_read(NVRAM, addr);
 
551
    return retval;
 
552
}
 
553
 
 
554
static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
 
555
{
 
556
    M48t59State *NVRAM = opaque;
 
557
    uint32_t retval;
 
558
 
 
559
    retval = m48t59_read(NVRAM, addr) << 8;
 
560
    retval |= m48t59_read(NVRAM, addr + 1);
 
561
    return retval;
 
562
}
 
563
 
 
564
static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
 
565
{
 
566
    M48t59State *NVRAM = opaque;
 
567
    uint32_t retval;
 
568
 
 
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 * const nvram_write[] = {
 
577
    &nvram_writeb,
 
578
    &nvram_writew,
 
579
    &nvram_writel,
 
580
};
 
581
 
 
582
static CPUReadMemoryFunc * const nvram_read[] = {
 
583
    &nvram_readb,
 
584
    &nvram_readw,
 
585
    &nvram_readl,
 
586
};
 
587
 
 
588
static const VMStateDescription vmstate_m48t59 = {
 
589
    .name = "m48t59",
 
590
    .version_id = 1,
 
591
    .minimum_version_id = 1,
 
592
    .minimum_version_id_old = 1,
 
593
    .fields      = (VMStateField[]) {
 
594
        VMSTATE_UINT8(lock, M48t59State),
 
595
        VMSTATE_UINT16(addr, M48t59State),
 
596
        VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size),
 
597
        VMSTATE_END_OF_LIST()
 
598
    }
 
599
};
 
600
 
 
601
static void m48t59_reset_common(M48t59State *NVRAM)
 
602
{
 
603
    NVRAM->addr = 0;
 
604
    NVRAM->lock = 0;
 
605
    if (NVRAM->alrm_timer != NULL)
 
606
        qemu_del_timer(NVRAM->alrm_timer);
 
607
 
 
608
    if (NVRAM->wd_timer != NULL)
 
609
        qemu_del_timer(NVRAM->wd_timer);
 
610
}
 
611
 
 
612
static void m48t59_reset_isa(DeviceState *d)
 
613
{
 
614
    M48t59ISAState *isa = container_of(d, M48t59ISAState, busdev.qdev);
 
615
    M48t59State *NVRAM = &isa->state;
 
616
 
 
617
    m48t59_reset_common(NVRAM);
 
618
}
 
619
 
 
620
static void m48t59_reset_sysbus(DeviceState *d)
 
621
{
 
622
    M48t59SysBusState *sys = container_of(d, M48t59SysBusState, busdev.qdev);
 
623
    M48t59State *NVRAM = &sys->state;
 
624
 
 
625
    m48t59_reset_common(NVRAM);
 
626
}
 
627
 
 
628
static const MemoryRegionPortio m48t59_portio[] = {
 
629
    {0, 4, 1, .read = NVRAM_readb, .write = NVRAM_writeb },
 
630
    PORTIO_END_OF_LIST(),
 
631
};
 
632
 
 
633
static const MemoryRegionOps m48t59_io_ops = {
 
634
    .old_portio = m48t59_portio,
 
635
};
 
636
 
 
637
/* Initialisation routine */
 
638
M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base,
 
639
                         uint32_t io_base, uint16_t size, int type)
 
640
{
 
641
    DeviceState *dev;
 
642
    SysBusDevice *s;
 
643
    M48t59SysBusState *d;
 
644
    M48t59State *state;
 
645
 
 
646
    dev = qdev_create(NULL, "m48t59");
 
647
    qdev_prop_set_uint32(dev, "type", type);
 
648
    qdev_prop_set_uint32(dev, "size", size);
 
649
    qdev_prop_set_uint32(dev, "io_base", io_base);
 
650
    qdev_init_nofail(dev);
 
651
    s = sysbus_from_qdev(dev);
 
652
    d = FROM_SYSBUS(M48t59SysBusState, s);
 
653
    state = &d->state;
 
654
    sysbus_connect_irq(s, 0, IRQ);
 
655
    if (io_base != 0) {
 
656
        register_ioport_read(io_base, 0x04, 1, NVRAM_readb, state);
 
657
        register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, state);
 
658
    }
 
659
    if (mem_base != 0) {
 
660
        sysbus_mmio_map(s, 0, mem_base);
 
661
    }
 
662
 
 
663
    return state;
 
664
}
 
665
 
 
666
M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type)
 
667
{
 
668
    M48t59ISAState *d;
 
669
    ISADevice *dev;
 
670
    M48t59State *s;
 
671
 
 
672
    dev = isa_create("m48t59_isa");
 
673
    qdev_prop_set_uint32(&dev->qdev, "type", type);
 
674
    qdev_prop_set_uint32(&dev->qdev, "size", size);
 
675
    qdev_prop_set_uint32(&dev->qdev, "io_base", io_base);
 
676
    qdev_init_nofail(&dev->qdev);
 
677
    d = DO_UPCAST(M48t59ISAState, busdev, dev);
 
678
    s = &d->state;
 
679
 
 
680
    memory_region_init_io(&d->io, &m48t59_io_ops, s, "m48t59", 4);
 
681
    if (io_base != 0) {
 
682
        isa_register_ioport(dev, &d->io, io_base);
 
683
    }
 
684
 
 
685
    return s;
 
686
}
 
687
 
 
688
static void m48t59_init_common(M48t59State *s)
 
689
{
 
690
    s->buffer = g_malloc0(s->size);
 
691
    if (s->type == 59) {
 
692
        s->alrm_timer = qemu_new_timer_ns(vm_clock, &alarm_cb, s);
 
693
        s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, s);
 
694
    }
 
695
    qemu_get_timedate(&s->alarm, 0);
 
696
 
 
697
    vmstate_register(NULL, -1, &vmstate_m48t59, s);
 
698
}
 
699
 
 
700
static int m48t59_init_isa1(ISADevice *dev)
 
701
{
 
702
    M48t59ISAState *d = DO_UPCAST(M48t59ISAState, busdev, dev);
 
703
    M48t59State *s = &d->state;
 
704
 
 
705
    isa_init_irq(dev, &s->IRQ, 8);
 
706
    m48t59_init_common(s);
 
707
 
 
708
    return 0;
 
709
}
 
710
 
 
711
static int m48t59_init1(SysBusDevice *dev)
 
712
{
 
713
    M48t59SysBusState *d = FROM_SYSBUS(M48t59SysBusState, dev);
 
714
    M48t59State *s = &d->state;
 
715
    int mem_index;
 
716
 
 
717
    sysbus_init_irq(dev, &s->IRQ);
 
718
 
 
719
    mem_index = cpu_register_io_memory(nvram_read, nvram_write, s,
 
720
                                       DEVICE_NATIVE_ENDIAN);
 
721
    sysbus_init_mmio(dev, s->size, mem_index);
 
722
    m48t59_init_common(s);
 
723
 
 
724
    return 0;
 
725
}
 
726
 
 
727
static ISADeviceInfo m48t59_isa_info = {
 
728
    .init = m48t59_init_isa1,
 
729
    .qdev.name = "m48t59_isa",
 
730
    .qdev.size = sizeof(M48t59ISAState),
 
731
    .qdev.reset = m48t59_reset_isa,
 
732
    .qdev.no_user = 1,
 
733
    .qdev.props = (Property[]) {
 
734
        DEFINE_PROP_UINT32("size",    M48t59ISAState, state.size,    -1),
 
735
        DEFINE_PROP_UINT32("type",    M48t59ISAState, state.type,    -1),
 
736
        DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base,  0),
 
737
        DEFINE_PROP_END_OF_LIST(),
 
738
    }
 
739
};
 
740
 
 
741
static SysBusDeviceInfo m48t59_info = {
 
742
    .init = m48t59_init1,
 
743
    .qdev.name  = "m48t59",
 
744
    .qdev.size = sizeof(M48t59SysBusState),
 
745
    .qdev.reset = m48t59_reset_sysbus,
 
746
    .qdev.props = (Property[]) {
 
747
        DEFINE_PROP_UINT32("size",    M48t59SysBusState, state.size,    -1),
 
748
        DEFINE_PROP_UINT32("type",    M48t59SysBusState, state.type,    -1),
 
749
        DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base,  0),
 
750
        DEFINE_PROP_END_OF_LIST(),
 
751
    }
 
752
};
 
753
 
 
754
static void m48t59_register_devices(void)
 
755
{
 
756
    sysbus_register_withprop(&m48t59_info);
 
757
    isa_qdev_register(&m48t59_isa_info);
 
758
}
 
759
 
 
760
device_init(m48t59_register_devices)