qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

omap_gptimer.c (13801B)


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