(linenum→info "unix/slp.c:2238")

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