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

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

unix.superglobalmegacorp.com

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