13bd88451SPaolo Bonzini /* 23bd88451SPaolo Bonzini * TI OMAP2 general purpose timers emulation. 33bd88451SPaolo Bonzini * 43bd88451SPaolo Bonzini * Copyright (C) 2007-2008 Nokia Corporation 53bd88451SPaolo Bonzini * Written by Andrzej Zaborowski <andrew@openedhand.com> 63bd88451SPaolo Bonzini * 73bd88451SPaolo Bonzini * This program is free software; you can redistribute it and/or 83bd88451SPaolo Bonzini * modify it under the terms of the GNU General Public License as 93bd88451SPaolo Bonzini * published by the Free Software Foundation; either version 2 or 103bd88451SPaolo Bonzini * (at your option) any later version of the License. 113bd88451SPaolo Bonzini * 123bd88451SPaolo Bonzini * This program is distributed in the hope that it will be useful, 133bd88451SPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of 143bd88451SPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 153bd88451SPaolo Bonzini * GNU General Public License for more details. 163bd88451SPaolo Bonzini * 173bd88451SPaolo Bonzini * You should have received a copy of the GNU General Public License along 183bd88451SPaolo Bonzini * with this program; if not, see <http://www.gnu.org/licenses/>. 193bd88451SPaolo Bonzini */ 203bd88451SPaolo Bonzini #include "hw/hw.h" 213bd88451SPaolo Bonzini #include "qemu/timer.h" 223bd88451SPaolo Bonzini #include "hw/arm/omap.h" 233bd88451SPaolo Bonzini 243bd88451SPaolo Bonzini /* GP timers */ 253bd88451SPaolo Bonzini struct omap_gp_timer_s { 263bd88451SPaolo Bonzini MemoryRegion iomem; 273bd88451SPaolo Bonzini qemu_irq irq; 283bd88451SPaolo Bonzini qemu_irq wkup; 293bd88451SPaolo Bonzini qemu_irq in; 303bd88451SPaolo Bonzini qemu_irq out; 313bd88451SPaolo Bonzini omap_clk clk; 323bd88451SPaolo Bonzini QEMUTimer *timer; 333bd88451SPaolo Bonzini QEMUTimer *match; 343bd88451SPaolo Bonzini struct omap_target_agent_s *ta; 353bd88451SPaolo Bonzini 363bd88451SPaolo Bonzini int in_val; 373bd88451SPaolo Bonzini int out_val; 383bd88451SPaolo Bonzini int64_t time; 393bd88451SPaolo Bonzini int64_t rate; 403bd88451SPaolo Bonzini int64_t ticks_per_sec; 413bd88451SPaolo Bonzini 423bd88451SPaolo Bonzini int16_t config; 433bd88451SPaolo Bonzini int status; 443bd88451SPaolo Bonzini int it_ena; 453bd88451SPaolo Bonzini int wu_ena; 463bd88451SPaolo Bonzini int enable; 473bd88451SPaolo Bonzini int inout; 483bd88451SPaolo Bonzini int capt2; 493bd88451SPaolo Bonzini int pt; 503bd88451SPaolo Bonzini enum { 513bd88451SPaolo Bonzini gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both 523bd88451SPaolo Bonzini } trigger; 533bd88451SPaolo Bonzini enum { 543bd88451SPaolo Bonzini gpt_capture_none, gpt_capture_rising, 553bd88451SPaolo Bonzini gpt_capture_falling, gpt_capture_both 563bd88451SPaolo Bonzini } capture; 573bd88451SPaolo Bonzini int scpwm; 583bd88451SPaolo Bonzini int ce; 593bd88451SPaolo Bonzini int pre; 603bd88451SPaolo Bonzini int ptv; 613bd88451SPaolo Bonzini int ar; 623bd88451SPaolo Bonzini int st; 633bd88451SPaolo Bonzini int posted; 643bd88451SPaolo Bonzini uint32_t val; 653bd88451SPaolo Bonzini uint32_t load_val; 663bd88451SPaolo Bonzini uint32_t capture_val[2]; 673bd88451SPaolo Bonzini uint32_t match_val; 683bd88451SPaolo Bonzini int capt_num; 693bd88451SPaolo Bonzini 703bd88451SPaolo Bonzini uint16_t writeh; /* LSB */ 713bd88451SPaolo Bonzini uint16_t readh; /* MSB */ 723bd88451SPaolo Bonzini }; 733bd88451SPaolo Bonzini 743bd88451SPaolo Bonzini #define GPT_TCAR_IT (1 << 2) 753bd88451SPaolo Bonzini #define GPT_OVF_IT (1 << 1) 763bd88451SPaolo Bonzini #define GPT_MAT_IT (1 << 0) 773bd88451SPaolo Bonzini 783bd88451SPaolo Bonzini static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it) 793bd88451SPaolo Bonzini { 803bd88451SPaolo Bonzini if (timer->it_ena & it) { 813bd88451SPaolo Bonzini if (!timer->status) 823bd88451SPaolo Bonzini qemu_irq_raise(timer->irq); 833bd88451SPaolo Bonzini 843bd88451SPaolo Bonzini timer->status |= it; 853bd88451SPaolo Bonzini /* Or are the status bits set even when masked? 863bd88451SPaolo Bonzini * i.e. is masking applied before or after the status register? */ 873bd88451SPaolo Bonzini } 883bd88451SPaolo Bonzini 893bd88451SPaolo Bonzini if (timer->wu_ena & it) 903bd88451SPaolo Bonzini qemu_irq_pulse(timer->wkup); 913bd88451SPaolo Bonzini } 923bd88451SPaolo Bonzini 933bd88451SPaolo Bonzini static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level) 943bd88451SPaolo Bonzini { 953bd88451SPaolo Bonzini if (!timer->inout && timer->out_val != level) { 963bd88451SPaolo Bonzini timer->out_val = level; 973bd88451SPaolo Bonzini qemu_set_irq(timer->out, level); 983bd88451SPaolo Bonzini } 993bd88451SPaolo Bonzini } 1003bd88451SPaolo Bonzini 1013bd88451SPaolo Bonzini static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer) 1023bd88451SPaolo Bonzini { 1033bd88451SPaolo Bonzini uint64_t distance; 1043bd88451SPaolo Bonzini 1053bd88451SPaolo Bonzini if (timer->st && timer->rate) { 106bc72ad67SAlex Bligh distance = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - timer->time; 1073bd88451SPaolo Bonzini distance = muldiv64(distance, timer->rate, timer->ticks_per_sec); 1083bd88451SPaolo Bonzini 1093bd88451SPaolo Bonzini if (distance >= 0xffffffff - timer->val) 1103bd88451SPaolo Bonzini return 0xffffffff; 1113bd88451SPaolo Bonzini else 1123bd88451SPaolo Bonzini return timer->val + distance; 1133bd88451SPaolo Bonzini } else 1143bd88451SPaolo Bonzini return timer->val; 1153bd88451SPaolo Bonzini } 1163bd88451SPaolo Bonzini 1173bd88451SPaolo Bonzini static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer) 1183bd88451SPaolo Bonzini { 1193bd88451SPaolo Bonzini if (timer->st) { 1203bd88451SPaolo Bonzini timer->val = omap_gp_timer_read(timer); 121bc72ad67SAlex Bligh timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1223bd88451SPaolo Bonzini } 1233bd88451SPaolo Bonzini } 1243bd88451SPaolo Bonzini 1253bd88451SPaolo Bonzini static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer) 1263bd88451SPaolo Bonzini { 1273bd88451SPaolo Bonzini int64_t expires, matches; 1283bd88451SPaolo Bonzini 1293bd88451SPaolo Bonzini if (timer->st && timer->rate) { 1303bd88451SPaolo Bonzini expires = muldiv64(0x100000000ll - timer->val, 1313bd88451SPaolo Bonzini timer->ticks_per_sec, timer->rate); 132bc72ad67SAlex Bligh timer_mod(timer->timer, timer->time + expires); 1333bd88451SPaolo Bonzini 1343bd88451SPaolo Bonzini if (timer->ce && timer->match_val >= timer->val) { 1353bd88451SPaolo Bonzini matches = muldiv64(timer->match_val - timer->val, 1363bd88451SPaolo Bonzini timer->ticks_per_sec, timer->rate); 137bc72ad67SAlex Bligh timer_mod(timer->match, timer->time + matches); 1383bd88451SPaolo Bonzini } else 139bc72ad67SAlex Bligh timer_del(timer->match); 1403bd88451SPaolo Bonzini } else { 141bc72ad67SAlex Bligh timer_del(timer->timer); 142bc72ad67SAlex Bligh timer_del(timer->match); 1433bd88451SPaolo Bonzini omap_gp_timer_out(timer, timer->scpwm); 1443bd88451SPaolo Bonzini } 1453bd88451SPaolo Bonzini } 1463bd88451SPaolo Bonzini 1473bd88451SPaolo Bonzini static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer) 1483bd88451SPaolo Bonzini { 1493bd88451SPaolo Bonzini if (timer->pt) 1503bd88451SPaolo Bonzini /* TODO in overflow-and-match mode if the first event to 1513bd88451SPaolo Bonzini * occur is the match, don't toggle. */ 1523bd88451SPaolo Bonzini omap_gp_timer_out(timer, !timer->out_val); 1533bd88451SPaolo Bonzini else 1543bd88451SPaolo Bonzini /* TODO inverted pulse on timer->out_val == 1? */ 1553bd88451SPaolo Bonzini qemu_irq_pulse(timer->out); 1563bd88451SPaolo Bonzini } 1573bd88451SPaolo Bonzini 1583bd88451SPaolo Bonzini static void omap_gp_timer_tick(void *opaque) 1593bd88451SPaolo Bonzini { 1603bd88451SPaolo Bonzini struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 1613bd88451SPaolo Bonzini 1623bd88451SPaolo Bonzini if (!timer->ar) { 1633bd88451SPaolo Bonzini timer->st = 0; 1643bd88451SPaolo Bonzini timer->val = 0; 1653bd88451SPaolo Bonzini } else { 1663bd88451SPaolo Bonzini timer->val = timer->load_val; 167bc72ad67SAlex Bligh timer->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1683bd88451SPaolo Bonzini } 1693bd88451SPaolo Bonzini 1703bd88451SPaolo Bonzini if (timer->trigger == gpt_trigger_overflow || 1713bd88451SPaolo Bonzini timer->trigger == gpt_trigger_both) 1723bd88451SPaolo Bonzini omap_gp_timer_trigger(timer); 1733bd88451SPaolo Bonzini 1743bd88451SPaolo Bonzini omap_gp_timer_intr(timer, GPT_OVF_IT); 1753bd88451SPaolo Bonzini omap_gp_timer_update(timer); 1763bd88451SPaolo Bonzini } 1773bd88451SPaolo Bonzini 1783bd88451SPaolo Bonzini static void omap_gp_timer_match(void *opaque) 1793bd88451SPaolo Bonzini { 1803bd88451SPaolo Bonzini struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 1813bd88451SPaolo Bonzini 1823bd88451SPaolo Bonzini if (timer->trigger == gpt_trigger_both) 1833bd88451SPaolo Bonzini omap_gp_timer_trigger(timer); 1843bd88451SPaolo Bonzini 1853bd88451SPaolo Bonzini omap_gp_timer_intr(timer, GPT_MAT_IT); 1863bd88451SPaolo Bonzini } 1873bd88451SPaolo Bonzini 1883bd88451SPaolo Bonzini static void omap_gp_timer_input(void *opaque, int line, int on) 1893bd88451SPaolo Bonzini { 1903bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 1913bd88451SPaolo Bonzini int trigger; 1923bd88451SPaolo Bonzini 1933bd88451SPaolo Bonzini switch (s->capture) { 1943bd88451SPaolo Bonzini default: 1953bd88451SPaolo Bonzini case gpt_capture_none: 1963bd88451SPaolo Bonzini trigger = 0; 1973bd88451SPaolo Bonzini break; 1983bd88451SPaolo Bonzini case gpt_capture_rising: 1993bd88451SPaolo Bonzini trigger = !s->in_val && on; 2003bd88451SPaolo Bonzini break; 2013bd88451SPaolo Bonzini case gpt_capture_falling: 2023bd88451SPaolo Bonzini trigger = s->in_val && !on; 2033bd88451SPaolo Bonzini break; 2043bd88451SPaolo Bonzini case gpt_capture_both: 2053bd88451SPaolo Bonzini trigger = (s->in_val == !on); 2063bd88451SPaolo Bonzini break; 2073bd88451SPaolo Bonzini } 2083bd88451SPaolo Bonzini s->in_val = on; 2093bd88451SPaolo Bonzini 2103bd88451SPaolo Bonzini if (s->inout && trigger && s->capt_num < 2) { 2113bd88451SPaolo Bonzini s->capture_val[s->capt_num] = omap_gp_timer_read(s); 2123bd88451SPaolo Bonzini 2133bd88451SPaolo Bonzini if (s->capt2 == s->capt_num ++) 2143bd88451SPaolo Bonzini omap_gp_timer_intr(s, GPT_TCAR_IT); 2153bd88451SPaolo Bonzini } 2163bd88451SPaolo Bonzini } 2173bd88451SPaolo Bonzini 2183bd88451SPaolo Bonzini static void omap_gp_timer_clk_update(void *opaque, int line, int on) 2193bd88451SPaolo Bonzini { 2203bd88451SPaolo Bonzini struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque; 2213bd88451SPaolo Bonzini 2223bd88451SPaolo Bonzini omap_gp_timer_sync(timer); 2233bd88451SPaolo Bonzini timer->rate = on ? omap_clk_getrate(timer->clk) : 0; 2243bd88451SPaolo Bonzini omap_gp_timer_update(timer); 2253bd88451SPaolo Bonzini } 2263bd88451SPaolo Bonzini 2273bd88451SPaolo Bonzini static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer) 2283bd88451SPaolo Bonzini { 2293bd88451SPaolo Bonzini omap_clk_adduser(timer->clk, 230f3c7d038SAndreas Färber qemu_allocate_irq(omap_gp_timer_clk_update, timer, 0)); 2313bd88451SPaolo Bonzini timer->rate = omap_clk_getrate(timer->clk); 2323bd88451SPaolo Bonzini } 2333bd88451SPaolo Bonzini 2343bd88451SPaolo Bonzini void omap_gp_timer_reset(struct omap_gp_timer_s *s) 2353bd88451SPaolo Bonzini { 2363bd88451SPaolo Bonzini s->config = 0x000; 2373bd88451SPaolo Bonzini s->status = 0; 2383bd88451SPaolo Bonzini s->it_ena = 0; 2393bd88451SPaolo Bonzini s->wu_ena = 0; 2403bd88451SPaolo Bonzini s->inout = 0; 2413bd88451SPaolo Bonzini s->capt2 = 0; 2423bd88451SPaolo Bonzini s->capt_num = 0; 2433bd88451SPaolo Bonzini s->pt = 0; 2443bd88451SPaolo Bonzini s->trigger = gpt_trigger_none; 2453bd88451SPaolo Bonzini s->capture = gpt_capture_none; 2463bd88451SPaolo Bonzini s->scpwm = 0; 2473bd88451SPaolo Bonzini s->ce = 0; 2483bd88451SPaolo Bonzini s->pre = 0; 2493bd88451SPaolo Bonzini s->ptv = 0; 2503bd88451SPaolo Bonzini s->ar = 0; 2513bd88451SPaolo Bonzini s->st = 0; 2523bd88451SPaolo Bonzini s->posted = 1; 2533bd88451SPaolo Bonzini s->val = 0x00000000; 2543bd88451SPaolo Bonzini s->load_val = 0x00000000; 2553bd88451SPaolo Bonzini s->capture_val[0] = 0x00000000; 2563bd88451SPaolo Bonzini s->capture_val[1] = 0x00000000; 2573bd88451SPaolo Bonzini s->match_val = 0x00000000; 2583bd88451SPaolo Bonzini omap_gp_timer_update(s); 2593bd88451SPaolo Bonzini } 2603bd88451SPaolo Bonzini 2613bd88451SPaolo Bonzini static uint32_t omap_gp_timer_readw(void *opaque, hwaddr addr) 2623bd88451SPaolo Bonzini { 2633bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 2643bd88451SPaolo Bonzini 2653bd88451SPaolo Bonzini switch (addr) { 2663bd88451SPaolo Bonzini case 0x00: /* TIDR */ 2673bd88451SPaolo Bonzini return 0x21; 2683bd88451SPaolo Bonzini 2693bd88451SPaolo Bonzini case 0x10: /* TIOCP_CFG */ 2703bd88451SPaolo Bonzini return s->config; 2713bd88451SPaolo Bonzini 2723bd88451SPaolo Bonzini case 0x14: /* TISTAT */ 2733bd88451SPaolo Bonzini /* ??? When's this bit reset? */ 2743bd88451SPaolo Bonzini return 1; /* RESETDONE */ 2753bd88451SPaolo Bonzini 2763bd88451SPaolo Bonzini case 0x18: /* TISR */ 2773bd88451SPaolo Bonzini return s->status; 2783bd88451SPaolo Bonzini 2793bd88451SPaolo Bonzini case 0x1c: /* TIER */ 2803bd88451SPaolo Bonzini return s->it_ena; 2813bd88451SPaolo Bonzini 2823bd88451SPaolo Bonzini case 0x20: /* TWER */ 2833bd88451SPaolo Bonzini return s->wu_ena; 2843bd88451SPaolo Bonzini 2853bd88451SPaolo Bonzini case 0x24: /* TCLR */ 2863bd88451SPaolo Bonzini return (s->inout << 14) | 2873bd88451SPaolo Bonzini (s->capt2 << 13) | 2883bd88451SPaolo Bonzini (s->pt << 12) | 2893bd88451SPaolo Bonzini (s->trigger << 10) | 2903bd88451SPaolo Bonzini (s->capture << 8) | 2913bd88451SPaolo Bonzini (s->scpwm << 7) | 2923bd88451SPaolo Bonzini (s->ce << 6) | 2933bd88451SPaolo Bonzini (s->pre << 5) | 2943bd88451SPaolo Bonzini (s->ptv << 2) | 2953bd88451SPaolo Bonzini (s->ar << 1) | 2963bd88451SPaolo Bonzini (s->st << 0); 2973bd88451SPaolo Bonzini 2983bd88451SPaolo Bonzini case 0x28: /* TCRR */ 2993bd88451SPaolo Bonzini return omap_gp_timer_read(s); 3003bd88451SPaolo Bonzini 3013bd88451SPaolo Bonzini case 0x2c: /* TLDR */ 3023bd88451SPaolo Bonzini return s->load_val; 3033bd88451SPaolo Bonzini 3043bd88451SPaolo Bonzini case 0x30: /* TTGR */ 3053bd88451SPaolo Bonzini return 0xffffffff; 3063bd88451SPaolo Bonzini 3073bd88451SPaolo Bonzini case 0x34: /* TWPS */ 3083bd88451SPaolo Bonzini return 0x00000000; /* No posted writes pending. */ 3093bd88451SPaolo Bonzini 3103bd88451SPaolo Bonzini case 0x38: /* TMAR */ 3113bd88451SPaolo Bonzini return s->match_val; 3123bd88451SPaolo Bonzini 3133bd88451SPaolo Bonzini case 0x3c: /* TCAR1 */ 3143bd88451SPaolo Bonzini return s->capture_val[0]; 3153bd88451SPaolo Bonzini 3163bd88451SPaolo Bonzini case 0x40: /* TSICR */ 3173bd88451SPaolo Bonzini return s->posted << 2; 3183bd88451SPaolo Bonzini 3193bd88451SPaolo Bonzini case 0x44: /* TCAR2 */ 3203bd88451SPaolo Bonzini return s->capture_val[1]; 3213bd88451SPaolo Bonzini } 3223bd88451SPaolo Bonzini 3233bd88451SPaolo Bonzini OMAP_BAD_REG(addr); 3243bd88451SPaolo Bonzini return 0; 3253bd88451SPaolo Bonzini } 3263bd88451SPaolo Bonzini 3273bd88451SPaolo Bonzini static uint32_t omap_gp_timer_readh(void *opaque, hwaddr addr) 3283bd88451SPaolo Bonzini { 3293bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 3303bd88451SPaolo Bonzini uint32_t ret; 3313bd88451SPaolo Bonzini 3323bd88451SPaolo Bonzini if (addr & 2) 3333bd88451SPaolo Bonzini return s->readh; 3343bd88451SPaolo Bonzini else { 3353bd88451SPaolo Bonzini ret = omap_gp_timer_readw(opaque, addr); 3363bd88451SPaolo Bonzini s->readh = ret >> 16; 3373bd88451SPaolo Bonzini return ret & 0xffff; 3383bd88451SPaolo Bonzini } 3393bd88451SPaolo Bonzini } 3403bd88451SPaolo Bonzini 3413bd88451SPaolo Bonzini static void omap_gp_timer_write(void *opaque, hwaddr addr, 3423bd88451SPaolo Bonzini uint32_t value) 3433bd88451SPaolo Bonzini { 3443bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 3453bd88451SPaolo Bonzini 3463bd88451SPaolo Bonzini switch (addr) { 3473bd88451SPaolo Bonzini case 0x00: /* TIDR */ 3483bd88451SPaolo Bonzini case 0x14: /* TISTAT */ 3493bd88451SPaolo Bonzini case 0x34: /* TWPS */ 3503bd88451SPaolo Bonzini case 0x3c: /* TCAR1 */ 3513bd88451SPaolo Bonzini case 0x44: /* TCAR2 */ 3523bd88451SPaolo Bonzini OMAP_RO_REG(addr); 3533bd88451SPaolo Bonzini break; 3543bd88451SPaolo Bonzini 3553bd88451SPaolo Bonzini case 0x10: /* TIOCP_CFG */ 3563bd88451SPaolo Bonzini s->config = value & 0x33d; 3573bd88451SPaolo Bonzini if (((value >> 3) & 3) == 3) /* IDLEMODE */ 3583bd88451SPaolo Bonzini fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n", 3593bd88451SPaolo Bonzini __FUNCTION__); 3603bd88451SPaolo Bonzini if (value & 2) /* SOFTRESET */ 3613bd88451SPaolo Bonzini omap_gp_timer_reset(s); 3623bd88451SPaolo Bonzini break; 3633bd88451SPaolo Bonzini 3643bd88451SPaolo Bonzini case 0x18: /* TISR */ 3653bd88451SPaolo Bonzini if (value & GPT_TCAR_IT) 3663bd88451SPaolo Bonzini s->capt_num = 0; 3673bd88451SPaolo Bonzini if (s->status && !(s->status &= ~value)) 3683bd88451SPaolo Bonzini qemu_irq_lower(s->irq); 3693bd88451SPaolo Bonzini break; 3703bd88451SPaolo Bonzini 3713bd88451SPaolo Bonzini case 0x1c: /* TIER */ 3723bd88451SPaolo Bonzini s->it_ena = value & 7; 3733bd88451SPaolo Bonzini break; 3743bd88451SPaolo Bonzini 3753bd88451SPaolo Bonzini case 0x20: /* TWER */ 3763bd88451SPaolo Bonzini s->wu_ena = value & 7; 3773bd88451SPaolo Bonzini break; 3783bd88451SPaolo Bonzini 3793bd88451SPaolo Bonzini case 0x24: /* TCLR */ 3803bd88451SPaolo Bonzini omap_gp_timer_sync(s); 3813bd88451SPaolo Bonzini s->inout = (value >> 14) & 1; 3823bd88451SPaolo Bonzini s->capt2 = (value >> 13) & 1; 3833bd88451SPaolo Bonzini s->pt = (value >> 12) & 1; 3843bd88451SPaolo Bonzini s->trigger = (value >> 10) & 3; 3853bd88451SPaolo Bonzini if (s->capture == gpt_capture_none && 3863bd88451SPaolo Bonzini ((value >> 8) & 3) != gpt_capture_none) 3873bd88451SPaolo Bonzini s->capt_num = 0; 3883bd88451SPaolo Bonzini s->capture = (value >> 8) & 3; 3893bd88451SPaolo Bonzini s->scpwm = (value >> 7) & 1; 3903bd88451SPaolo Bonzini s->ce = (value >> 6) & 1; 3913bd88451SPaolo Bonzini s->pre = (value >> 5) & 1; 3923bd88451SPaolo Bonzini s->ptv = (value >> 2) & 7; 3933bd88451SPaolo Bonzini s->ar = (value >> 1) & 1; 3943bd88451SPaolo Bonzini s->st = (value >> 0) & 1; 3953bd88451SPaolo Bonzini if (s->inout && s->trigger != gpt_trigger_none) 3963bd88451SPaolo Bonzini fprintf(stderr, "%s: GP timer pin must be an output " 3973bd88451SPaolo Bonzini "for this trigger mode\n", __FUNCTION__); 3983bd88451SPaolo Bonzini if (!s->inout && s->capture != gpt_capture_none) 3993bd88451SPaolo Bonzini fprintf(stderr, "%s: GP timer pin must be an input " 4003bd88451SPaolo Bonzini "for this capture mode\n", __FUNCTION__); 4013bd88451SPaolo Bonzini if (s->trigger == gpt_trigger_none) 4023bd88451SPaolo Bonzini omap_gp_timer_out(s, s->scpwm); 4033bd88451SPaolo Bonzini /* TODO: make sure this doesn't overflow 32-bits */ 4043bd88451SPaolo Bonzini s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0); 4053bd88451SPaolo Bonzini omap_gp_timer_update(s); 4063bd88451SPaolo Bonzini break; 4073bd88451SPaolo Bonzini 4083bd88451SPaolo Bonzini case 0x28: /* TCRR */ 409bc72ad67SAlex Bligh s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 4103bd88451SPaolo Bonzini s->val = value; 4113bd88451SPaolo Bonzini omap_gp_timer_update(s); 4123bd88451SPaolo Bonzini break; 4133bd88451SPaolo Bonzini 4143bd88451SPaolo Bonzini case 0x2c: /* TLDR */ 4153bd88451SPaolo Bonzini s->load_val = value; 4163bd88451SPaolo Bonzini break; 4173bd88451SPaolo Bonzini 4183bd88451SPaolo Bonzini case 0x30: /* TTGR */ 419bc72ad67SAlex Bligh s->time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 4203bd88451SPaolo Bonzini s->val = s->load_val; 4213bd88451SPaolo Bonzini omap_gp_timer_update(s); 4223bd88451SPaolo Bonzini break; 4233bd88451SPaolo Bonzini 4243bd88451SPaolo Bonzini case 0x38: /* TMAR */ 4253bd88451SPaolo Bonzini omap_gp_timer_sync(s); 4263bd88451SPaolo Bonzini s->match_val = value; 4273bd88451SPaolo Bonzini omap_gp_timer_update(s); 4283bd88451SPaolo Bonzini break; 4293bd88451SPaolo Bonzini 4303bd88451SPaolo Bonzini case 0x40: /* TSICR */ 4313bd88451SPaolo Bonzini s->posted = (value >> 2) & 1; 4323bd88451SPaolo Bonzini if (value & 2) /* How much exactly are we supposed to reset? */ 4333bd88451SPaolo Bonzini omap_gp_timer_reset(s); 4343bd88451SPaolo Bonzini break; 4353bd88451SPaolo Bonzini 4363bd88451SPaolo Bonzini default: 4373bd88451SPaolo Bonzini OMAP_BAD_REG(addr); 4383bd88451SPaolo Bonzini } 4393bd88451SPaolo Bonzini } 4403bd88451SPaolo Bonzini 4413bd88451SPaolo Bonzini static void omap_gp_timer_writeh(void *opaque, hwaddr addr, 4423bd88451SPaolo Bonzini uint32_t value) 4433bd88451SPaolo Bonzini { 4443bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque; 4453bd88451SPaolo Bonzini 4463bd88451SPaolo Bonzini if (addr & 2) 447*77a8257eSStefan Weil omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh); 4483bd88451SPaolo Bonzini else 4493bd88451SPaolo Bonzini s->writeh = (uint16_t) value; 4503bd88451SPaolo Bonzini } 4513bd88451SPaolo Bonzini 4523bd88451SPaolo Bonzini static const MemoryRegionOps omap_gp_timer_ops = { 4533bd88451SPaolo Bonzini .old_mmio = { 4543bd88451SPaolo Bonzini .read = { 4553bd88451SPaolo Bonzini omap_badwidth_read32, 4563bd88451SPaolo Bonzini omap_gp_timer_readh, 4573bd88451SPaolo Bonzini omap_gp_timer_readw, 4583bd88451SPaolo Bonzini }, 4593bd88451SPaolo Bonzini .write = { 4603bd88451SPaolo Bonzini omap_badwidth_write32, 4613bd88451SPaolo Bonzini omap_gp_timer_writeh, 4623bd88451SPaolo Bonzini omap_gp_timer_write, 4633bd88451SPaolo Bonzini }, 4643bd88451SPaolo Bonzini }, 4653bd88451SPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN, 4663bd88451SPaolo Bonzini }; 4673bd88451SPaolo Bonzini 4683bd88451SPaolo Bonzini struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta, 4693bd88451SPaolo Bonzini qemu_irq irq, omap_clk fclk, omap_clk iclk) 4703bd88451SPaolo Bonzini { 4713bd88451SPaolo Bonzini struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) 4723bd88451SPaolo Bonzini g_malloc0(sizeof(struct omap_gp_timer_s)); 4733bd88451SPaolo Bonzini 4743bd88451SPaolo Bonzini s->ta = ta; 4753bd88451SPaolo Bonzini s->irq = irq; 4763bd88451SPaolo Bonzini s->clk = fclk; 477bc72ad67SAlex Bligh s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_tick, s); 478bc72ad67SAlex Bligh s->match = timer_new_ns(QEMU_CLOCK_VIRTUAL, omap_gp_timer_match, s); 479f3c7d038SAndreas Färber s->in = qemu_allocate_irq(omap_gp_timer_input, s, 0); 4803bd88451SPaolo Bonzini omap_gp_timer_reset(s); 4813bd88451SPaolo Bonzini omap_gp_timer_clk_setup(s); 4823bd88451SPaolo Bonzini 4832c9b15caSPaolo Bonzini memory_region_init_io(&s->iomem, NULL, &omap_gp_timer_ops, s, "omap.gptimer", 4843bd88451SPaolo Bonzini omap_l4_region_size(ta, 0)); 4853bd88451SPaolo Bonzini omap_l4_attach(ta, 0, &s->iomem); 4863bd88451SPaolo Bonzini 4873bd88451SPaolo Bonzini return s; 4883bd88451SPaolo Bonzini } 489