Annotation of qemu/hw/omap_gptimer.c, revision 1.1.1.4

1.1       root        1: /*
                      2:  * TI OMAP2 general purpose timers emulation.
                      3:  *
                      4:  * Copyright (C) 2007-2008 Nokia Corporation
                      5:  * Written by Andrzej Zaborowski <[email protected]>
                      6:  *
                      7:  * This program is free software; you can redistribute it and/or
                      8:  * modify it under the terms of the GNU General Public License as
                      9:  * published by the Free Software Foundation; either version 2 or
                     10:  * (at your option) any later version of the License.
                     11:  *
                     12:  * This program is distributed in the hope that it will be useful,
                     13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     15:  * GNU General Public License for more details.
                     16:  *
                     17:  * You should have received a copy of the GNU General Public License along
                     18:  * with this program; if not, see <http://www.gnu.org/licenses/>.
                     19:  */
                     20: #include "hw.h"
                     21: #include "qemu-timer.h"
                     22: #include "omap.h"
                     23: 
                     24: /* GP timers */
                     25: struct omap_gp_timer_s {
1.1.1.4 ! root       26:     MemoryRegion iomem;
1.1       root       27:     qemu_irq irq;
                     28:     qemu_irq wkup;
                     29:     qemu_irq in;
                     30:     qemu_irq out;
                     31:     omap_clk clk;
                     32:     QEMUTimer *timer;
                     33:     QEMUTimer *match;
                     34:     struct omap_target_agent_s *ta;
                     35: 
                     36:     int in_val;
                     37:     int out_val;
                     38:     int64_t time;
                     39:     int64_t rate;
                     40:     int64_t ticks_per_sec;
                     41: 
                     42:     int16_t config;
                     43:     int status;
                     44:     int it_ena;
                     45:     int wu_ena;
                     46:     int enable;
                     47:     int inout;
                     48:     int capt2;
                     49:     int pt;
                     50:     enum {
                     51:         gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
                     52:     } trigger;
                     53:     enum {
                     54:         gpt_capture_none, gpt_capture_rising,
                     55:         gpt_capture_falling, gpt_capture_both
                     56:     } capture;
                     57:     int scpwm;
                     58:     int ce;
                     59:     int pre;
                     60:     int ptv;
                     61:     int ar;
                     62:     int st;
                     63:     int posted;
                     64:     uint32_t val;
                     65:     uint32_t load_val;
                     66:     uint32_t capture_val[2];
                     67:     uint32_t match_val;
                     68:     int capt_num;
                     69: 
                     70:     uint16_t writeh;   /* LSB */
                     71:     uint16_t readh;    /* MSB */
                     72: };
                     73: 
                     74: #define GPT_TCAR_IT    (1 << 2)
                     75: #define GPT_OVF_IT     (1 << 1)
                     76: #define GPT_MAT_IT     (1 << 0)
                     77: 
                     78: static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
                     79: {
                     80:     if (timer->it_ena & it) {
                     81:         if (!timer->status)
                     82:             qemu_irq_raise(timer->irq);
                     83: 
                     84:         timer->status |= it;
                     85:         /* Or are the status bits set even when masked?
                     86:          * i.e. is masking applied before or after the status register?  */
                     87:     }
                     88: 
                     89:     if (timer->wu_ena & it)
                     90:         qemu_irq_pulse(timer->wkup);
                     91: }
                     92: 
                     93: static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
                     94: {
                     95:     if (!timer->inout && timer->out_val != level) {
                     96:         timer->out_val = level;
                     97:         qemu_set_irq(timer->out, level);
                     98:     }
                     99: }
                    100: 
                    101: static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
                    102: {
                    103:     uint64_t distance;
                    104: 
                    105:     if (timer->st && timer->rate) {
1.1.1.2   root      106:         distance = qemu_get_clock_ns(vm_clock) - timer->time;
1.1       root      107:         distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
                    108: 
                    109:         if (distance >= 0xffffffff - timer->val)
                    110:             return 0xffffffff;
                    111:         else
                    112:             return timer->val + distance;
                    113:     } else
                    114:         return timer->val;
                    115: }
                    116: 
                    117: static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
                    118: {
                    119:     if (timer->st) {
                    120:         timer->val = omap_gp_timer_read(timer);
1.1.1.2   root      121:         timer->time = qemu_get_clock_ns(vm_clock);
1.1       root      122:     }
                    123: }
                    124: 
                    125: static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
                    126: {
                    127:     int64_t expires, matches;
                    128: 
                    129:     if (timer->st && timer->rate) {
                    130:         expires = muldiv64(0x100000000ll - timer->val,
                    131:                         timer->ticks_per_sec, timer->rate);
                    132:         qemu_mod_timer(timer->timer, timer->time + expires);
                    133: 
                    134:         if (timer->ce && timer->match_val >= timer->val) {
                    135:             matches = muldiv64(timer->match_val - timer->val,
                    136:                             timer->ticks_per_sec, timer->rate);
                    137:             qemu_mod_timer(timer->match, timer->time + matches);
                    138:         } else
                    139:             qemu_del_timer(timer->match);
                    140:     } else {
                    141:         qemu_del_timer(timer->timer);
                    142:         qemu_del_timer(timer->match);
                    143:         omap_gp_timer_out(timer, timer->scpwm);
                    144:     }
                    145: }
                    146: 
                    147: static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
                    148: {
                    149:     if (timer->pt)
                    150:         /* TODO in overflow-and-match mode if the first event to
                    151:          * occur is the match, don't toggle.  */
                    152:         omap_gp_timer_out(timer, !timer->out_val);
                    153:     else
                    154:         /* TODO inverted pulse on timer->out_val == 1?  */
                    155:         qemu_irq_pulse(timer->out);
                    156: }
                    157: 
                    158: static void omap_gp_timer_tick(void *opaque)
                    159: {
                    160:     struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
                    161: 
                    162:     if (!timer->ar) {
                    163:         timer->st = 0;
                    164:         timer->val = 0;
                    165:     } else {
                    166:         timer->val = timer->load_val;
1.1.1.2   root      167:         timer->time = qemu_get_clock_ns(vm_clock);
1.1       root      168:     }
                    169: 
                    170:     if (timer->trigger == gpt_trigger_overflow ||
                    171:                     timer->trigger == gpt_trigger_both)
                    172:         omap_gp_timer_trigger(timer);
                    173: 
                    174:     omap_gp_timer_intr(timer, GPT_OVF_IT);
                    175:     omap_gp_timer_update(timer);
                    176: }
                    177: 
                    178: static void omap_gp_timer_match(void *opaque)
                    179: {
                    180:     struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
                    181: 
                    182:     if (timer->trigger == gpt_trigger_both)
                    183:         omap_gp_timer_trigger(timer);
                    184: 
                    185:     omap_gp_timer_intr(timer, GPT_MAT_IT);
                    186: }
                    187: 
                    188: static void omap_gp_timer_input(void *opaque, int line, int on)
                    189: {
                    190:     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
                    191:     int trigger;
                    192: 
                    193:     switch (s->capture) {
                    194:     default:
                    195:     case gpt_capture_none:
                    196:         trigger = 0;
                    197:         break;
                    198:     case gpt_capture_rising:
                    199:         trigger = !s->in_val && on;
                    200:         break;
                    201:     case gpt_capture_falling:
                    202:         trigger = s->in_val && !on;
                    203:         break;
                    204:     case gpt_capture_both:
                    205:         trigger = (s->in_val == !on);
                    206:         break;
                    207:     }
                    208:     s->in_val = on;
                    209: 
                    210:     if (s->inout && trigger && s->capt_num < 2) {
                    211:         s->capture_val[s->capt_num] = omap_gp_timer_read(s);
                    212: 
                    213:         if (s->capt2 == s->capt_num ++)
                    214:             omap_gp_timer_intr(s, GPT_TCAR_IT);
                    215:     }
                    216: }
                    217: 
                    218: static void omap_gp_timer_clk_update(void *opaque, int line, int on)
                    219: {
                    220:     struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
                    221: 
                    222:     omap_gp_timer_sync(timer);
                    223:     timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
                    224:     omap_gp_timer_update(timer);
                    225: }
                    226: 
                    227: static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
                    228: {
                    229:     omap_clk_adduser(timer->clk,
                    230:                     qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
                    231:     timer->rate = omap_clk_getrate(timer->clk);
                    232: }
                    233: 
                    234: void omap_gp_timer_reset(struct omap_gp_timer_s *s)
                    235: {
                    236:     s->config = 0x000;
                    237:     s->status = 0;
                    238:     s->it_ena = 0;
                    239:     s->wu_ena = 0;
                    240:     s->inout = 0;
                    241:     s->capt2 = 0;
                    242:     s->capt_num = 0;
                    243:     s->pt = 0;
                    244:     s->trigger = gpt_trigger_none;
                    245:     s->capture = gpt_capture_none;
                    246:     s->scpwm = 0;
                    247:     s->ce = 0;
                    248:     s->pre = 0;
                    249:     s->ptv = 0;
                    250:     s->ar = 0;
                    251:     s->st = 0;
                    252:     s->posted = 1;
                    253:     s->val = 0x00000000;
                    254:     s->load_val = 0x00000000;
                    255:     s->capture_val[0] = 0x00000000;
                    256:     s->capture_val[1] = 0x00000000;
                    257:     s->match_val = 0x00000000;
                    258:     omap_gp_timer_update(s);
                    259: }
                    260: 
                    261: static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr)
                    262: {
                    263:     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
                    264: 
                    265:     switch (addr) {
                    266:     case 0x00: /* TIDR */
                    267:         return 0x21;
                    268: 
                    269:     case 0x10: /* TIOCP_CFG */
                    270:         return s->config;
                    271: 
                    272:     case 0x14: /* TISTAT */
                    273:         /* ??? When's this bit reset? */
                    274:         return 1;                                              /* RESETDONE */
                    275: 
                    276:     case 0x18: /* TISR */
                    277:         return s->status;
                    278: 
                    279:     case 0x1c: /* TIER */
                    280:         return s->it_ena;
                    281: 
                    282:     case 0x20: /* TWER */
                    283:         return s->wu_ena;
                    284: 
                    285:     case 0x24: /* TCLR */
                    286:         return (s->inout << 14) |
                    287:                 (s->capt2 << 13) |
                    288:                 (s->pt << 12) |
                    289:                 (s->trigger << 10) |
                    290:                 (s->capture << 8) |
                    291:                 (s->scpwm << 7) |
                    292:                 (s->ce << 6) |
                    293:                 (s->pre << 5) |
                    294:                 (s->ptv << 2) |
                    295:                 (s->ar << 1) |
                    296:                 (s->st << 0);
                    297: 
                    298:     case 0x28: /* TCRR */
                    299:         return omap_gp_timer_read(s);
                    300: 
                    301:     case 0x2c: /* TLDR */
                    302:         return s->load_val;
                    303: 
                    304:     case 0x30: /* TTGR */
                    305:         return 0xffffffff;
                    306: 
                    307:     case 0x34: /* TWPS */
                    308:         return 0x00000000;     /* No posted writes pending.  */
                    309: 
                    310:     case 0x38: /* TMAR */
                    311:         return s->match_val;
                    312: 
                    313:     case 0x3c: /* TCAR1 */
                    314:         return s->capture_val[0];
                    315: 
                    316:     case 0x40: /* TSICR */
                    317:         return s->posted << 2;
                    318: 
                    319:     case 0x44: /* TCAR2 */
                    320:         return s->capture_val[1];
                    321:     }
                    322: 
                    323:     OMAP_BAD_REG(addr);
                    324:     return 0;
                    325: }
                    326: 
                    327: static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr)
                    328: {
                    329:     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
                    330:     uint32_t ret;
                    331: 
                    332:     if (addr & 2)
                    333:         return s->readh;
                    334:     else {
                    335:         ret = omap_gp_timer_readw(opaque, addr);
                    336:         s->readh = ret >> 16;
                    337:         return ret & 0xffff;
                    338:     }
                    339: }
                    340: 
                    341: static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr,
                    342:                 uint32_t value)
                    343: {
                    344:     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
                    345: 
                    346:     switch (addr) {
                    347:     case 0x00: /* TIDR */
                    348:     case 0x14: /* TISTAT */
                    349:     case 0x34: /* TWPS */
                    350:     case 0x3c: /* TCAR1 */
                    351:     case 0x44: /* TCAR2 */
                    352:         OMAP_RO_REG(addr);
                    353:         break;
                    354: 
                    355:     case 0x10: /* TIOCP_CFG */
                    356:         s->config = value & 0x33d;
                    357:         if (((value >> 3) & 3) == 3)                           /* IDLEMODE */
                    358:             fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
                    359:                             __FUNCTION__);
                    360:         if (value & 2)                                         /* SOFTRESET */
                    361:             omap_gp_timer_reset(s);
                    362:         break;
                    363: 
                    364:     case 0x18: /* TISR */
                    365:         if (value & GPT_TCAR_IT)
                    366:             s->capt_num = 0;
                    367:         if (s->status && !(s->status &= ~value))
                    368:             qemu_irq_lower(s->irq);
                    369:         break;
                    370: 
                    371:     case 0x1c: /* TIER */
                    372:         s->it_ena = value & 7;
                    373:         break;
                    374: 
                    375:     case 0x20: /* TWER */
                    376:         s->wu_ena = value & 7;
                    377:         break;
                    378: 
                    379:     case 0x24: /* TCLR */
                    380:         omap_gp_timer_sync(s);
                    381:         s->inout = (value >> 14) & 1;
                    382:         s->capt2 = (value >> 13) & 1;
                    383:         s->pt = (value >> 12) & 1;
                    384:         s->trigger = (value >> 10) & 3;
                    385:         if (s->capture == gpt_capture_none &&
                    386:                         ((value >> 8) & 3) != gpt_capture_none)
                    387:             s->capt_num = 0;
                    388:         s->capture = (value >> 8) & 3;
                    389:         s->scpwm = (value >> 7) & 1;
                    390:         s->ce = (value >> 6) & 1;
                    391:         s->pre = (value >> 5) & 1;
                    392:         s->ptv = (value >> 2) & 7;
                    393:         s->ar = (value >> 1) & 1;
                    394:         s->st = (value >> 0) & 1;
                    395:         if (s->inout && s->trigger != gpt_trigger_none)
                    396:             fprintf(stderr, "%s: GP timer pin must be an output "
                    397:                             "for this trigger mode\n", __FUNCTION__);
                    398:         if (!s->inout && s->capture != gpt_capture_none)
                    399:             fprintf(stderr, "%s: GP timer pin must be an input "
                    400:                             "for this capture mode\n", __FUNCTION__);
                    401:         if (s->trigger == gpt_trigger_none)
                    402:             omap_gp_timer_out(s, s->scpwm);
                    403:         /* TODO: make sure this doesn't overflow 32-bits */
                    404:         s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
                    405:         omap_gp_timer_update(s);
                    406:         break;
                    407: 
                    408:     case 0x28: /* TCRR */
1.1.1.2   root      409:         s->time = qemu_get_clock_ns(vm_clock);
1.1       root      410:         s->val = value;
                    411:         omap_gp_timer_update(s);
                    412:         break;
                    413: 
                    414:     case 0x2c: /* TLDR */
                    415:         s->load_val = value;
                    416:         break;
                    417: 
                    418:     case 0x30: /* TTGR */
1.1.1.2   root      419:         s->time = qemu_get_clock_ns(vm_clock);
1.1       root      420:         s->val = s->load_val;
                    421:         omap_gp_timer_update(s);
                    422:         break;
                    423: 
                    424:     case 0x38: /* TMAR */
                    425:         omap_gp_timer_sync(s);
                    426:         s->match_val = value;
                    427:         omap_gp_timer_update(s);
                    428:         break;
                    429: 
                    430:     case 0x40: /* TSICR */
                    431:         s->posted = (value >> 2) & 1;
                    432:         if (value & 2) /* How much exactly are we supposed to reset? */
                    433:             omap_gp_timer_reset(s);
                    434:         break;
                    435: 
                    436:     default:
                    437:         OMAP_BAD_REG(addr);
                    438:     }
                    439: }
                    440: 
                    441: static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t addr,
                    442:                 uint32_t value)
                    443: {
                    444:     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
                    445: 
                    446:     if (addr & 2)
                    447:         return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
                    448:     else
                    449:         s->writeh = (uint16_t) value;
                    450: }
                    451: 
1.1.1.4 ! root      452: static const MemoryRegionOps omap_gp_timer_ops = {
        !           453:     .old_mmio = {
        !           454:         .read = {
        !           455:             omap_badwidth_read32,
        !           456:             omap_gp_timer_readh,
        !           457:             omap_gp_timer_readw,
        !           458:         },
        !           459:         .write = {
        !           460:             omap_badwidth_write32,
        !           461:             omap_gp_timer_writeh,
        !           462:             omap_gp_timer_write,
        !           463:         },
        !           464:     },
        !           465:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      466: };
                    467: 
                    468: struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
                    469:                 qemu_irq irq, omap_clk fclk, omap_clk iclk)
                    470: {
                    471:     struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
1.1.1.3   root      472:             g_malloc0(sizeof(struct omap_gp_timer_s));
1.1       root      473: 
                    474:     s->ta = ta;
                    475:     s->irq = irq;
                    476:     s->clk = fclk;
1.1.1.2   root      477:     s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
                    478:     s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
1.1       root      479:     s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
                    480:     omap_gp_timer_reset(s);
                    481:     omap_gp_timer_clk_setup(s);
                    482: 
1.1.1.4 ! root      483:     memory_region_init_io(&s->iomem, &omap_gp_timer_ops, s, "omap.gptimer",
        !           484:                           omap_l4_region_size(ta, 0));
        !           485:     omap_l4_attach(ta, 0, &s->iomem);
1.1       root      486: 
                    487:     return s;
                    488: }

unix.superglobalmegacorp.com

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