Annotation of qemu/hw/cadence_ttc.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Xilinx Zynq cadence TTC model
                      3:  *
                      4:  * Copyright (c) 2011 Xilinx Inc.
                      5:  * Copyright (c) 2012 Peter A.G. Crosthwaite ([email protected])
                      6:  * Copyright (c) 2012 PetaLogix Pty Ltd.
                      7:  * Written By Haibing Ma
                      8:  *            M. Habib
                      9:  *
                     10:  * This program is free software; you can redistribute it and/or
                     11:  * modify it under the terms of the GNU General Public License
                     12:  * as published by the Free Software Foundation; either version
                     13:  * 2 of the License, or (at your option) any later version.
                     14:  *
                     15:  * You should have received a copy of the GNU General Public License along
                     16:  * with this program; if not, see <http://www.gnu.org/licenses/>.
                     17:  */
                     18: 
                     19: #include "sysbus.h"
                     20: #include "qemu-timer.h"
                     21: 
                     22: #ifdef CADENCE_TTC_ERR_DEBUG
                     23: #define DB_PRINT(...) do { \
                     24:     fprintf(stderr,  ": %s: ", __func__); \
                     25:     fprintf(stderr, ## __VA_ARGS__); \
                     26:     } while (0);
                     27: #else
                     28:     #define DB_PRINT(...)
                     29: #endif
                     30: 
                     31: #define COUNTER_INTR_IV     0x00000001
                     32: #define COUNTER_INTR_M1     0x00000002
                     33: #define COUNTER_INTR_M2     0x00000004
                     34: #define COUNTER_INTR_M3     0x00000008
                     35: #define COUNTER_INTR_OV     0x00000010
                     36: #define COUNTER_INTR_EV     0x00000020
                     37: 
                     38: #define COUNTER_CTRL_DIS    0x00000001
                     39: #define COUNTER_CTRL_INT    0x00000002
                     40: #define COUNTER_CTRL_DEC    0x00000004
                     41: #define COUNTER_CTRL_MATCH  0x00000008
                     42: #define COUNTER_CTRL_RST    0x00000010
                     43: 
                     44: #define CLOCK_CTRL_PS_EN    0x00000001
                     45: #define CLOCK_CTRL_PS_V     0x0000001e
                     46: 
                     47: typedef struct {
                     48:     QEMUTimer *timer;
                     49:     int freq;
                     50: 
                     51:     uint32_t reg_clock;
                     52:     uint32_t reg_count;
                     53:     uint32_t reg_value;
                     54:     uint16_t reg_interval;
                     55:     uint16_t reg_match[3];
                     56:     uint32_t reg_intr;
                     57:     uint32_t reg_intr_en;
                     58:     uint32_t reg_event_ctrl;
                     59:     uint32_t reg_event;
                     60: 
                     61:     uint64_t cpu_time;
                     62:     unsigned int cpu_time_valid;
                     63: 
                     64:     qemu_irq irq;
                     65: } CadenceTimerState;
                     66: 
                     67: typedef struct {
                     68:     SysBusDevice busdev;
                     69:     MemoryRegion iomem;
                     70:     CadenceTimerState timer[3];
                     71: } CadenceTTCState;
                     72: 
                     73: static void cadence_timer_update(CadenceTimerState *s)
                     74: {
                     75:     qemu_set_irq(s->irq, !!(s->reg_intr & s->reg_intr_en));
                     76: }
                     77: 
                     78: static CadenceTimerState *cadence_timer_from_addr(void *opaque,
                     79:                                         target_phys_addr_t offset)
                     80: {
                     81:     unsigned int index;
                     82:     CadenceTTCState *s = (CadenceTTCState *)opaque;
                     83: 
                     84:     index = (offset >> 2) % 3;
                     85: 
                     86:     return &s->timer[index];
                     87: }
                     88: 
                     89: static uint64_t cadence_timer_get_ns(CadenceTimerState *s, uint64_t timer_steps)
                     90: {
                     91:     /* timer_steps has max value of 0x100000000. double check it
                     92:      * (or overflow can happen below) */
                     93:     assert(timer_steps <= 1ULL << 32);
                     94: 
                     95:     uint64_t r = timer_steps * 1000000000ULL;
                     96:     if (s->reg_clock & CLOCK_CTRL_PS_EN) {
                     97:         r >>= 16 - (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
                     98:     } else {
                     99:         r >>= 16;
                    100:     }
                    101:     r /= (uint64_t)s->freq;
                    102:     return r;
                    103: }
                    104: 
                    105: static uint64_t cadence_timer_get_steps(CadenceTimerState *s, uint64_t ns)
                    106: {
                    107:     uint64_t to_divide = 1000000000ULL;
                    108: 
                    109:     uint64_t r = ns;
                    110:      /* for very large intervals (> 8s) do some division first to stop
                    111:       * overflow (costs some prescision) */
                    112:     while (r >= 8ULL << 30 && to_divide > 1) {
                    113:         r /= 1000;
                    114:         to_divide /= 1000;
                    115:     }
                    116:     r <<= 16;
                    117:     /* keep early-dividing as needed */
                    118:     while (r >= 8ULL << 30 && to_divide > 1) {
                    119:         r /= 1000;
                    120:         to_divide /= 1000;
                    121:     }
                    122:     r *= (uint64_t)s->freq;
                    123:     if (s->reg_clock & CLOCK_CTRL_PS_EN) {
                    124:         r /= 1 << (((s->reg_clock & CLOCK_CTRL_PS_V) >> 1) + 1);
                    125:     }
                    126: 
                    127:     r /= to_divide;
                    128:     return r;
                    129: }
                    130: 
                    131: /* determine if x is in between a and b, exclusive of a, inclusive of b */
                    132: 
                    133: static inline int64_t is_between(int64_t x, int64_t a, int64_t b)
                    134: {
                    135:     if (a < b) {
                    136:         return x > a && x <= b;
                    137:     }
                    138:     return x < a && x >= b;
                    139: }
                    140: 
                    141: static void cadence_timer_run(CadenceTimerState *s)
                    142: {
                    143:     int i;
                    144:     int64_t event_interval, next_value;
                    145: 
                    146:     assert(s->cpu_time_valid); /* cadence_timer_sync must be called first */
                    147: 
                    148:     if (s->reg_count & COUNTER_CTRL_DIS) {
                    149:         s->cpu_time_valid = 0;
                    150:         return;
                    151:     }
                    152: 
                    153:     { /* figure out what's going to happen next (rollover or match) */
                    154:         int64_t interval = (uint64_t)((s->reg_count & COUNTER_CTRL_INT) ?
                    155:                 (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
                    156:         next_value = (s->reg_count & COUNTER_CTRL_DEC) ? -1ULL : interval;
                    157:         for (i = 0; i < 3; ++i) {
                    158:             int64_t cand = (uint64_t)s->reg_match[i] << 16;
                    159:             if (is_between(cand, (uint64_t)s->reg_value, next_value)) {
                    160:                 next_value = cand;
                    161:             }
                    162:         }
                    163:     }
                    164:     DB_PRINT("next timer event value: %09llx\n",
                    165:             (unsigned long long)next_value);
                    166: 
                    167:     event_interval = next_value - (int64_t)s->reg_value;
                    168:     event_interval = (event_interval < 0) ? -event_interval : event_interval;
                    169: 
                    170:     qemu_mod_timer(s->timer, s->cpu_time +
                    171:                 cadence_timer_get_ns(s, event_interval));
                    172: }
                    173: 
                    174: static void cadence_timer_sync(CadenceTimerState *s)
                    175: {
                    176:     int i;
                    177:     int64_t r, x;
                    178:     int64_t interval = ((s->reg_count & COUNTER_CTRL_INT) ?
                    179:             (int64_t)s->reg_interval + 1 : 0x10000ULL) << 16;
                    180:     uint64_t old_time = s->cpu_time;
                    181: 
                    182:     s->cpu_time = qemu_get_clock_ns(vm_clock);
                    183:     DB_PRINT("cpu time: %lld ns\n", (long long)old_time);
                    184: 
                    185:     if (!s->cpu_time_valid || old_time == s->cpu_time) {
                    186:         s->cpu_time_valid = 1;
                    187:         return;
                    188:     }
                    189: 
                    190:     r = (int64_t)cadence_timer_get_steps(s, s->cpu_time - old_time);
                    191:     x = (int64_t)s->reg_value + ((s->reg_count & COUNTER_CTRL_DEC) ? -r : r);
                    192: 
                    193:     for (i = 0; i < 3; ++i) {
                    194:         int64_t m = (int64_t)s->reg_match[i] << 16;
                    195:         if (m > interval) {
                    196:             continue;
                    197:         }
                    198:         /* check to see if match event has occurred. check m +/- interval
                    199:          * to account for match events in wrap around cases */
                    200:         if (is_between(m, s->reg_value, x) ||
                    201:             is_between(m + interval, s->reg_value, x) ||
                    202:             is_between(m - interval, s->reg_value, x)) {
                    203:             s->reg_intr |= (2 << i);
                    204:         }
                    205:     }
                    206:     while (x < 0) {
                    207:         x += interval;
                    208:     }
                    209:     s->reg_value = (uint32_t)(x % interval);
                    210: 
                    211:     if (s->reg_value != x) {
                    212:         s->reg_intr |= (s->reg_count & COUNTER_CTRL_INT) ?
                    213:             COUNTER_INTR_IV : COUNTER_INTR_OV;
                    214:     }
                    215:     cadence_timer_update(s);
                    216: }
                    217: 
                    218: static void cadence_timer_tick(void *opaque)
                    219: {
                    220:     CadenceTimerState *s = opaque;
                    221: 
                    222:     DB_PRINT("\n");
                    223:     cadence_timer_sync(s);
                    224:     cadence_timer_run(s);
                    225: }
                    226: 
                    227: static uint32_t cadence_ttc_read_imp(void *opaque, target_phys_addr_t offset)
                    228: {
                    229:     CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
                    230:     uint32_t value;
                    231: 
                    232:     cadence_timer_sync(s);
                    233:     cadence_timer_run(s);
                    234: 
                    235:     switch (offset) {
                    236:     case 0x00: /* clock control */
                    237:     case 0x04:
                    238:     case 0x08:
                    239:         return s->reg_clock;
                    240: 
                    241:     case 0x0c: /* counter control */
                    242:     case 0x10:
                    243:     case 0x14:
                    244:         return s->reg_count;
                    245: 
                    246:     case 0x18: /* counter value */
                    247:     case 0x1c:
                    248:     case 0x20:
                    249:         return (uint16_t)(s->reg_value >> 16);
                    250: 
                    251:     case 0x24: /* reg_interval counter */
                    252:     case 0x28:
                    253:     case 0x2c:
                    254:         return s->reg_interval;
                    255: 
                    256:     case 0x30: /* match 1 counter */
                    257:     case 0x34:
                    258:     case 0x38:
                    259:         return s->reg_match[0];
                    260: 
                    261:     case 0x3c: /* match 2 counter */
                    262:     case 0x40:
                    263:     case 0x44:
                    264:         return s->reg_match[1];
                    265: 
                    266:     case 0x48: /* match 3 counter */
                    267:     case 0x4c:
                    268:     case 0x50:
                    269:         return s->reg_match[2];
                    270: 
                    271:     case 0x54: /* interrupt register */
                    272:     case 0x58:
                    273:     case 0x5c:
                    274:         /* cleared after read */
                    275:         value = s->reg_intr;
                    276:         s->reg_intr = 0;
                    277:         return value;
                    278: 
                    279:     case 0x60: /* interrupt enable */
                    280:     case 0x64:
                    281:     case 0x68:
                    282:         return s->reg_intr_en;
                    283: 
                    284:     case 0x6c:
                    285:     case 0x70:
                    286:     case 0x74:
                    287:         return s->reg_event_ctrl;
                    288: 
                    289:     case 0x78:
                    290:     case 0x7c:
                    291:     case 0x80:
                    292:         return s->reg_event;
                    293: 
                    294:     default:
                    295:         return 0;
                    296:     }
                    297: }
                    298: 
                    299: static uint64_t cadence_ttc_read(void *opaque, target_phys_addr_t offset,
                    300:     unsigned size)
                    301: {
                    302:     uint32_t ret = cadence_ttc_read_imp(opaque, offset);
                    303: 
                    304:     DB_PRINT("addr: %08x data: %08x\n", offset, ret);
                    305:     return ret;
                    306: }
                    307: 
                    308: static void cadence_ttc_write(void *opaque, target_phys_addr_t offset,
                    309:         uint64_t value, unsigned size)
                    310: {
                    311:     CadenceTimerState *s = cadence_timer_from_addr(opaque, offset);
                    312: 
                    313:     DB_PRINT("addr: %08x data %08x\n", offset, (unsigned)value);
                    314: 
                    315:     cadence_timer_sync(s);
                    316: 
                    317:     switch (offset) {
                    318:     case 0x00: /* clock control */
                    319:     case 0x04:
                    320:     case 0x08:
                    321:         s->reg_clock = value & 0x3F;
                    322:         break;
                    323: 
                    324:     case 0x0c: /* counter control */
                    325:     case 0x10:
                    326:     case 0x14:
                    327:         if (value & COUNTER_CTRL_RST) {
                    328:             s->reg_value = 0;
                    329:         }
                    330:         s->reg_count = value & 0x3f & ~COUNTER_CTRL_RST;
                    331:         break;
                    332: 
                    333:     case 0x24: /* interval register */
                    334:     case 0x28:
                    335:     case 0x2c:
                    336:         s->reg_interval = value & 0xffff;
                    337:         break;
                    338: 
                    339:     case 0x30: /* match register */
                    340:     case 0x34:
                    341:     case 0x38:
                    342:         s->reg_match[0] = value & 0xffff;
                    343: 
                    344:     case 0x3c: /* match register */
                    345:     case 0x40:
                    346:     case 0x44:
                    347:         s->reg_match[1] = value & 0xffff;
                    348: 
                    349:     case 0x48: /* match register */
                    350:     case 0x4c:
                    351:     case 0x50:
                    352:         s->reg_match[2] = value & 0xffff;
                    353:         break;
                    354: 
                    355:     case 0x54: /* interrupt register */
                    356:     case 0x58:
                    357:     case 0x5c:
                    358:         s->reg_intr &= (~value & 0xfff);
                    359:         break;
                    360: 
                    361:     case 0x60: /* interrupt enable */
                    362:     case 0x64:
                    363:     case 0x68:
                    364:         s->reg_intr_en = value & 0x3f;
                    365:         break;
                    366: 
                    367:     case 0x6c: /* event control */
                    368:     case 0x70:
                    369:     case 0x74:
                    370:         s->reg_event_ctrl = value & 0x07;
                    371:         break;
                    372: 
                    373:     default:
                    374:         return;
                    375:     }
                    376: 
                    377:     cadence_timer_run(s);
                    378:     cadence_timer_update(s);
                    379: }
                    380: 
                    381: static const MemoryRegionOps cadence_ttc_ops = {
                    382:     .read = cadence_ttc_read,
                    383:     .write = cadence_ttc_write,
                    384:     .endianness = DEVICE_NATIVE_ENDIAN,
                    385: };
                    386: 
                    387: static void cadence_timer_reset(CadenceTimerState *s)
                    388: {
                    389:    s->reg_count = 0x21;
                    390: }
                    391: 
                    392: static void cadence_timer_init(uint32_t freq, CadenceTimerState *s)
                    393: {
                    394:     memset(s, 0, sizeof(CadenceTimerState));
                    395:     s->freq = freq;
                    396: 
                    397:     cadence_timer_reset(s);
                    398: 
                    399:     s->timer = qemu_new_timer_ns(vm_clock, cadence_timer_tick, s);
                    400: }
                    401: 
                    402: static int cadence_ttc_init(SysBusDevice *dev)
                    403: {
                    404:     CadenceTTCState *s = FROM_SYSBUS(CadenceTTCState, dev);
                    405:     int i;
                    406: 
                    407:     for (i = 0; i < 3; ++i) {
                    408:         cadence_timer_init(2500000, &s->timer[i]);
                    409:         sysbus_init_irq(dev, &s->timer[i].irq);
                    410:     }
                    411: 
                    412:     memory_region_init_io(&s->iomem, &cadence_ttc_ops, s, "timer", 0x1000);
                    413:     sysbus_init_mmio(dev, &s->iomem);
                    414: 
                    415:     return 0;
                    416: }
                    417: 
                    418: static void cadence_timer_pre_save(void *opaque)
                    419: {
                    420:     cadence_timer_sync((CadenceTimerState *)opaque);
                    421: }
                    422: 
                    423: static int cadence_timer_post_load(void *opaque, int version_id)
                    424: {
                    425:     CadenceTimerState *s = opaque;
                    426: 
                    427:     s->cpu_time_valid = 0;
                    428:     cadence_timer_sync(s);
                    429:     cadence_timer_run(s);
                    430:     cadence_timer_update(s);
                    431:     return 0;
                    432: }
                    433: 
                    434: static const VMStateDescription vmstate_cadence_timer = {
                    435:     .name = "cadence_timer",
                    436:     .version_id = 1,
                    437:     .minimum_version_id = 1,
                    438:     .minimum_version_id_old = 1,
                    439:     .pre_save = cadence_timer_pre_save,
                    440:     .post_load = cadence_timer_post_load,
                    441:     .fields = (VMStateField[]) {
                    442:         VMSTATE_UINT32(reg_clock, CadenceTimerState),
                    443:         VMSTATE_UINT32(reg_count, CadenceTimerState),
                    444:         VMSTATE_UINT32(reg_value, CadenceTimerState),
                    445:         VMSTATE_UINT16(reg_interval, CadenceTimerState),
                    446:         VMSTATE_UINT16_ARRAY(reg_match, CadenceTimerState, 3),
                    447:         VMSTATE_UINT32(reg_intr, CadenceTimerState),
                    448:         VMSTATE_UINT32(reg_intr_en, CadenceTimerState),
                    449:         VMSTATE_UINT32(reg_event_ctrl, CadenceTimerState),
                    450:         VMSTATE_UINT32(reg_event, CadenceTimerState),
                    451:         VMSTATE_END_OF_LIST()
                    452:     }
                    453: };
                    454: 
                    455: static const VMStateDescription vmstate_cadence_ttc = {
                    456:     .name = "cadence_TTC",
                    457:     .version_id = 1,
                    458:     .minimum_version_id = 1,
                    459:     .minimum_version_id_old = 1,
                    460:     .fields = (VMStateField[]) {
                    461:         VMSTATE_STRUCT_ARRAY(timer, CadenceTTCState, 3, 0,
                    462:                             vmstate_cadence_timer,
                    463:                             CadenceTimerState),
                    464:         VMSTATE_END_OF_LIST()
                    465:     }
                    466: };
                    467: 
                    468: static void cadence_ttc_class_init(ObjectClass *klass, void *data)
                    469: {
                    470:     DeviceClass *dc = DEVICE_CLASS(klass);
                    471:     SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
                    472: 
                    473:     sdc->init = cadence_ttc_init;
                    474:     dc->vmsd = &vmstate_cadence_ttc;
                    475: }
                    476: 
                    477: static TypeInfo cadence_ttc_info = {
                    478:     .name  = "cadence_ttc",
                    479:     .parent = TYPE_SYS_BUS_DEVICE,
                    480:     .instance_size  = sizeof(CadenceTTCState),
                    481:     .class_init = cadence_ttc_class_init,
                    482: };
                    483: 
                    484: static void cadence_ttc_register_types(void)
                    485: {
                    486:     type_register_static(&cadence_ttc_info);
                    487: }
                    488: 
                    489: type_init(cadence_ttc_register_types)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.