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

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) {
        !           105:         distance = qemu_get_clock(vm_clock) - timer->time;
        !           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);
        !           120:         timer->time = qemu_get_clock(vm_clock);
        !           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;
        !           166:         timer->time = qemu_get_clock(vm_clock);
        !           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 */
        !           414:         s->time = qemu_get_clock(vm_clock);
        !           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 */
        !           424:         s->time = qemu_get_clock(vm_clock);
        !           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;
        !           473:     s->timer = qemu_new_timer(vm_clock, omap_gp_timer_tick, s);
        !           474:     s->match = qemu_new_timer(vm_clock, omap_gp_timer_match, s);
        !           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.