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

1.1       root        1: /*
                      2:  * QEMU GRLIB GPTimer Emulator
                      3:  *
                      4:  * Copyright (c) 2010-2011 AdaCore
                      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: 
                     25: #include "sysbus.h"
                     26: #include "qemu-timer.h"
                     27: 
                     28: #include "trace.h"
                     29: 
                     30: #define UNIT_REG_SIZE    16     /* Size of memory mapped regs for the unit */
                     31: #define GPTIMER_REG_SIZE 16     /* Size of memory mapped regs for a GPTimer */
                     32: 
                     33: #define GPTIMER_MAX_TIMERS 8
                     34: 
                     35: /* GPTimer Config register fields */
                     36: #define GPTIMER_ENABLE      (1 << 0)
                     37: #define GPTIMER_RESTART     (1 << 1)
                     38: #define GPTIMER_LOAD        (1 << 2)
                     39: #define GPTIMER_INT_ENABLE  (1 << 3)
                     40: #define GPTIMER_INT_PENDING (1 << 4)
                     41: #define GPTIMER_CHAIN       (1 << 5) /* Not supported */
                     42: #define GPTIMER_DEBUG_HALT  (1 << 6) /* Not supported */
                     43: 
                     44: /* Memory mapped register offsets */
                     45: #define SCALER_OFFSET         0x00
                     46: #define SCALER_RELOAD_OFFSET  0x04
                     47: #define CONFIG_OFFSET         0x08
                     48: #define COUNTER_OFFSET        0x00
                     49: #define COUNTER_RELOAD_OFFSET 0x04
                     50: #define TIMER_BASE            0x10
                     51: 
                     52: typedef struct GPTimer     GPTimer;
                     53: typedef struct GPTimerUnit GPTimerUnit;
                     54: 
                     55: struct GPTimer {
                     56:     QEMUBH *bh;
                     57:     struct ptimer_state *ptimer;
                     58: 
                     59:     qemu_irq     irq;
                     60:     int          id;
                     61:     GPTimerUnit *unit;
                     62: 
                     63:     /* registers */
                     64:     uint32_t counter;
                     65:     uint32_t reload;
                     66:     uint32_t config;
                     67: };
                     68: 
                     69: struct GPTimerUnit {
                     70:     SysBusDevice  busdev;
                     71: 
                     72:     uint32_t nr_timers;         /* Number of timers available */
                     73:     uint32_t freq_hz;           /* System frequency */
                     74:     uint32_t irq_line;          /* Base irq line */
                     75: 
                     76:     GPTimer *timers;
                     77: 
                     78:     /* registers */
                     79:     uint32_t scaler;
                     80:     uint32_t reload;
                     81:     uint32_t config;
                     82: };
                     83: 
                     84: static void grlib_gptimer_enable(GPTimer *timer)
                     85: {
                     86:     assert(timer != NULL);
                     87: 
                     88: 
                     89:     ptimer_stop(timer->ptimer);
                     90: 
                     91:     if (!(timer->config & GPTIMER_ENABLE)) {
                     92:         /* Timer disabled */
                     93:         trace_grlib_gptimer_disabled(timer->id, timer->config);
                     94:         return;
                     95:     }
                     96: 
                     97:     /* ptimer is triggered when the counter reach 0 but GPTimer is triggered at
                     98:        underflow. Set count + 1 to simulate the GPTimer behavior. */
                     99: 
                    100:     trace_grlib_gptimer_enable(timer->id, timer->counter + 1);
                    101: 
                    102:     ptimer_set_count(timer->ptimer, timer->counter + 1);
                    103:     ptimer_run(timer->ptimer, 1);
                    104: }
                    105: 
                    106: static void grlib_gptimer_restart(GPTimer *timer)
                    107: {
                    108:     assert(timer != NULL);
                    109: 
                    110:     trace_grlib_gptimer_restart(timer->id, timer->reload);
                    111: 
                    112:     timer->counter = timer->reload;
                    113:     grlib_gptimer_enable(timer);
                    114: }
                    115: 
                    116: static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
                    117: {
                    118:     int i = 0;
                    119:     uint32_t value = 0;
                    120: 
                    121:     assert(unit != NULL);
                    122: 
                    123:     if (scaler > 0) {
                    124:         value = unit->freq_hz / (scaler + 1);
                    125:     } else {
                    126:         value = unit->freq_hz;
                    127:     }
                    128: 
                    129:     trace_grlib_gptimer_set_scaler(scaler, value);
                    130: 
                    131:     for (i = 0; i < unit->nr_timers; i++) {
                    132:         ptimer_set_freq(unit->timers[i].ptimer, value);
                    133:     }
                    134: }
                    135: 
                    136: static void grlib_gptimer_hit(void *opaque)
                    137: {
                    138:     GPTimer *timer = opaque;
                    139:     assert(timer != NULL);
                    140: 
                    141:     trace_grlib_gptimer_hit(timer->id);
                    142: 
                    143:     /* Timer expired */
                    144: 
                    145:     if (timer->config & GPTIMER_INT_ENABLE) {
                    146:         /* Set the pending bit (only unset by write in the config register) */
                    147:         timer->config |= GPTIMER_INT_PENDING;
                    148:         qemu_irq_pulse(timer->irq);
                    149:     }
                    150: 
                    151:     if (timer->config & GPTIMER_RESTART) {
                    152:         grlib_gptimer_restart(timer);
                    153:     }
                    154: }
                    155: 
                    156: static uint32_t grlib_gptimer_readl(void *opaque, target_phys_addr_t addr)
                    157: {
                    158:     GPTimerUnit        *unit  = opaque;
                    159:     target_phys_addr_t  timer_addr;
                    160:     int                 id;
                    161:     uint32_t            value = 0;
                    162: 
                    163:     addr &= 0xff;
                    164: 
                    165:     /* Unit registers */
                    166:     switch (addr) {
                    167:     case SCALER_OFFSET:
                    168:         trace_grlib_gptimer_readl(-1, "scaler:", unit->scaler);
                    169:         return unit->scaler;
                    170: 
                    171:     case SCALER_RELOAD_OFFSET:
                    172:         trace_grlib_gptimer_readl(-1, "reload:", unit->reload);
                    173:         return unit->reload;
                    174: 
                    175:     case CONFIG_OFFSET:
                    176:         trace_grlib_gptimer_readl(-1, "config:", unit->config);
                    177:         return unit->config;
                    178: 
                    179:     default:
                    180:         break;
                    181:     }
                    182: 
                    183:     timer_addr = (addr % TIMER_BASE);
                    184:     id         = (addr - TIMER_BASE) / TIMER_BASE;
                    185: 
                    186:     if (id >= 0 && id < unit->nr_timers) {
                    187: 
                    188:         /* GPTimer registers */
                    189:         switch (timer_addr) {
                    190:         case COUNTER_OFFSET:
                    191:             value = ptimer_get_count(unit->timers[id].ptimer);
                    192:             trace_grlib_gptimer_readl(id, "counter value:", value);
                    193:             return value;
                    194: 
                    195:         case COUNTER_RELOAD_OFFSET:
                    196:             value = unit->timers[id].reload;
                    197:             trace_grlib_gptimer_readl(id, "reload value:", value);
                    198:             return value;
                    199: 
                    200:         case CONFIG_OFFSET:
                    201:             trace_grlib_gptimer_readl(id, "scaler value:",
                    202:                                       unit->timers[id].config);
                    203:             return unit->timers[id].config;
                    204: 
                    205:         default:
                    206:             break;
                    207:         }
                    208: 
                    209:     }
                    210: 
                    211:     trace_grlib_gptimer_unknown_register("read", addr);
                    212:     return 0;
                    213: }
                    214: 
                    215: static void
                    216: grlib_gptimer_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
                    217: {
                    218:     GPTimerUnit        *unit = opaque;
                    219:     target_phys_addr_t  timer_addr;
                    220:     int                 id;
                    221: 
                    222:     addr &= 0xff;
                    223: 
                    224:     /* Unit registers */
                    225:     switch (addr) {
                    226:     case SCALER_OFFSET:
                    227:         value &= 0xFFFF; /* clean up the value */
                    228:         unit->scaler = value;
                    229:         trace_grlib_gptimer_writel(-1, "scaler:", unit->scaler);
                    230:         return;
                    231: 
                    232:     case SCALER_RELOAD_OFFSET:
                    233:         value &= 0xFFFF; /* clean up the value */
                    234:         unit->reload = value;
                    235:         trace_grlib_gptimer_writel(-1, "reload:", unit->reload);
                    236:         grlib_gptimer_set_scaler(unit, value);
                    237:         return;
                    238: 
                    239:     case CONFIG_OFFSET:
                    240:         /* Read Only (disable timer freeze not supported) */
                    241:         trace_grlib_gptimer_writel(-1, "config (Read Only):", 0);
                    242:         return;
                    243: 
                    244:     default:
                    245:         break;
                    246:     }
                    247: 
                    248:     timer_addr = (addr % TIMER_BASE);
                    249:     id         = (addr - TIMER_BASE) / TIMER_BASE;
                    250: 
                    251:     if (id >= 0 && id < unit->nr_timers) {
                    252: 
                    253:         /* GPTimer registers */
                    254:         switch (timer_addr) {
                    255:         case COUNTER_OFFSET:
                    256:             trace_grlib_gptimer_writel(id, "counter:", value);
                    257:             unit->timers[id].counter = value;
                    258:             grlib_gptimer_enable(&unit->timers[id]);
                    259:             return;
                    260: 
                    261:         case COUNTER_RELOAD_OFFSET:
                    262:             trace_grlib_gptimer_writel(id, "reload:", value);
                    263:             unit->timers[id].reload = value;
                    264:             return;
                    265: 
                    266:         case CONFIG_OFFSET:
                    267:             trace_grlib_gptimer_writel(id, "config:", value);
                    268: 
                    269:             if (value & GPTIMER_INT_PENDING) {
                    270:                 /* clear pending bit */
                    271:                 value &= ~GPTIMER_INT_PENDING;
                    272:             } else {
                    273:                 /* keep pending bit */
                    274:                 value |= unit->timers[id].config & GPTIMER_INT_PENDING;
                    275:             }
                    276: 
                    277:             unit->timers[id].config = value;
                    278: 
                    279:             /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
                    280:                bits are present, we just have to call restart. */
                    281: 
                    282:             if (value & GPTIMER_LOAD) {
                    283:                 grlib_gptimer_restart(&unit->timers[id]);
                    284:             } else if (value & GPTIMER_ENABLE) {
                    285:                 grlib_gptimer_enable(&unit->timers[id]);
                    286:             }
                    287: 
                    288:             /* These fields must always be read as 0 */
                    289:             value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
                    290: 
                    291:             unit->timers[id].config = value;
                    292:             return;
                    293: 
                    294:         default:
                    295:             break;
                    296:         }
                    297: 
                    298:     }
                    299: 
                    300:     trace_grlib_gptimer_unknown_register("write", addr);
                    301: }
                    302: 
                    303: static CPUReadMemoryFunc * const grlib_gptimer_read[] = {
                    304:     NULL, NULL, grlib_gptimer_readl,
                    305: };
                    306: 
                    307: static CPUWriteMemoryFunc * const grlib_gptimer_write[] = {
                    308:     NULL, NULL, grlib_gptimer_writel,
                    309: };
                    310: 
                    311: static void grlib_gptimer_reset(DeviceState *d)
                    312: {
                    313:     GPTimerUnit *unit = container_of(d, GPTimerUnit, busdev.qdev);
                    314:     int          i    = 0;
                    315: 
                    316:     assert(unit != NULL);
                    317: 
                    318:     unit->scaler = 0;
                    319:     unit->reload = 0;
                    320:     unit->config = 0;
                    321: 
                    322:     unit->config  = unit->nr_timers;
                    323:     unit->config |= unit->irq_line << 3;
                    324:     unit->config |= 1 << 8;     /* separate interrupt */
                    325:     unit->config |= 1 << 9;     /* Disable timer freeze */
                    326: 
                    327: 
                    328:     for (i = 0; i < unit->nr_timers; i++) {
                    329:         GPTimer *timer = &unit->timers[i];
                    330: 
                    331:         timer->counter = 0;
                    332:         timer->reload = 0;
                    333:         timer->config = 0;
                    334:         ptimer_stop(timer->ptimer);
                    335:         ptimer_set_count(timer->ptimer, 0);
                    336:         ptimer_set_freq(timer->ptimer, unit->freq_hz);
                    337:     }
                    338: }
                    339: 
                    340: static int grlib_gptimer_init(SysBusDevice *dev)
                    341: {
                    342:     GPTimerUnit  *unit = FROM_SYSBUS(typeof(*unit), dev);
                    343:     unsigned int  i;
                    344:     int           timer_regs;
                    345: 
                    346:     assert(unit->nr_timers > 0);
                    347:     assert(unit->nr_timers <= GPTIMER_MAX_TIMERS);
                    348: 
                    349:     unit->timers = qemu_mallocz(sizeof unit->timers[0] * unit->nr_timers);
                    350: 
                    351:     for (i = 0; i < unit->nr_timers; i++) {
                    352:         GPTimer *timer = &unit->timers[i];
                    353: 
                    354:         timer->unit   = unit;
                    355:         timer->bh     = qemu_bh_new(grlib_gptimer_hit, timer);
                    356:         timer->ptimer = ptimer_init(timer->bh);
                    357:         timer->id     = i;
                    358: 
                    359:         /* One IRQ line for each timer */
                    360:         sysbus_init_irq(dev, &timer->irq);
                    361: 
                    362:         ptimer_set_freq(timer->ptimer, unit->freq_hz);
                    363:     }
                    364: 
                    365:     timer_regs = cpu_register_io_memory(grlib_gptimer_read,
                    366:                                         grlib_gptimer_write,
                    367:                                         unit, DEVICE_NATIVE_ENDIAN);
                    368:     if (timer_regs < 0) {
                    369:         return -1;
                    370:     }
                    371: 
                    372:     sysbus_init_mmio(dev, UNIT_REG_SIZE + GPTIMER_REG_SIZE * unit->nr_timers,
                    373:                      timer_regs);
                    374:     return 0;
                    375: }
                    376: 
                    377: static SysBusDeviceInfo grlib_gptimer_info = {
                    378:     .init       = grlib_gptimer_init,
                    379:     .qdev.name  = "grlib,gptimer",
                    380:     .qdev.reset = grlib_gptimer_reset,
                    381:     .qdev.size  = sizeof(GPTimerUnit),
                    382:     .qdev.props = (Property[]) {
                    383:         DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz,   40000000),
                    384:         DEFINE_PROP_UINT32("irq-line",  GPTimerUnit, irq_line,  8),
                    385:         DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
                    386:         DEFINE_PROP_END_OF_LIST()
                    387:     }
                    388: };
                    389: 
                    390: static void grlib_gptimer_register(void)
                    391: {
                    392:     sysbus_register_withprop(&grlib_gptimer_info);
                    393: }
                    394: 
                    395: device_init(grlib_gptimer_register)

unix.superglobalmegacorp.com

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