| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Intel XScale PXA255/270 OS Timers. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (c) 2006 Openedhand Ltd. | 
					
						
							|  |  |  |  * Copyright (c) 2006 Thorsten Zitterell | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-06-26 12:21:35 +10:00
										 |  |  |  * This code is licensed under the GPL. | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:17:05 +00:00
										 |  |  | #include "qemu/osdep.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:42 +02:00
										 |  |  | #include "hw/irq.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:51 +02:00
										 |  |  | #include "hw/qdev-properties.h"
 | 
					
						
							| 
									
										
										
										
											2012-12-17 18:20:00 +01:00
										 |  |  | #include "qemu/timer.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:59 +02:00
										 |  |  | #include "sysemu/runstate.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-05 17:06:20 +01:00
										 |  |  | #include "hw/arm/pxa.h"
 | 
					
						
							| 
									
										
										
										
											2013-02-04 15:40:22 +01:00
										 |  |  | #include "hw/sysbus.h"
 | 
					
						
							| 
									
										
										
										
											2019-08-12 07:23:45 +02:00
										 |  |  | #include "migration/vmstate.h"
 | 
					
						
							| 
									
										
										
										
											2018-01-11 13:25:38 +00:00
										 |  |  | #include "qemu/log.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-23 16:35:07 +02:00
										 |  |  | #include "qemu/module.h"
 | 
					
						
							| 
									
										
										
										
											2020-09-03 16:43:22 -04:00
										 |  |  | #include "qom/object.h"
 | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define OSMR0	0x00
 | 
					
						
							|  |  |  | #define OSMR1	0x04
 | 
					
						
							|  |  |  | #define OSMR2	0x08
 | 
					
						
							|  |  |  | #define OSMR3	0x0c
 | 
					
						
							|  |  |  | #define OSMR4	0x80
 | 
					
						
							|  |  |  | #define OSMR5	0x84
 | 
					
						
							|  |  |  | #define OSMR6	0x88
 | 
					
						
							|  |  |  | #define OSMR7	0x8c
 | 
					
						
							|  |  |  | #define OSMR8	0x90
 | 
					
						
							|  |  |  | #define OSMR9	0x94
 | 
					
						
							|  |  |  | #define OSMR10	0x98
 | 
					
						
							|  |  |  | #define OSMR11	0x9c
 | 
					
						
							|  |  |  | #define OSCR	0x10	/* OS Timer Count */
 | 
					
						
							|  |  |  | #define OSCR4	0x40
 | 
					
						
							|  |  |  | #define OSCR5	0x44
 | 
					
						
							|  |  |  | #define OSCR6	0x48
 | 
					
						
							|  |  |  | #define OSCR7	0x4c
 | 
					
						
							|  |  |  | #define OSCR8	0x50
 | 
					
						
							|  |  |  | #define OSCR9	0x54
 | 
					
						
							|  |  |  | #define OSCR10	0x58
 | 
					
						
							|  |  |  | #define OSCR11	0x5c
 | 
					
						
							|  |  |  | #define OSSR	0x14	/* Timer status register */
 | 
					
						
							|  |  |  | #define OWER	0x18
 | 
					
						
							|  |  |  | #define OIER	0x1c	/* Interrupt enable register  3-0 to E3-E0 */
 | 
					
						
							|  |  |  | #define OMCR4	0xc0	/* OS Match Control registers */
 | 
					
						
							|  |  |  | #define OMCR5	0xc4
 | 
					
						
							|  |  |  | #define OMCR6	0xc8
 | 
					
						
							|  |  |  | #define OMCR7	0xcc
 | 
					
						
							|  |  |  | #define OMCR8	0xd0
 | 
					
						
							|  |  |  | #define OMCR9	0xd4
 | 
					
						
							|  |  |  | #define OMCR10	0xd8
 | 
					
						
							|  |  |  | #define OMCR11	0xdc
 | 
					
						
							|  |  |  | #define OSNR	0x20
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PXA25X_FREQ	3686400	/* 3.6864 MHz */
 | 
					
						
							|  |  |  | #define PXA27X_FREQ	3250000	/* 3.25 MHz */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int pxa2xx_timer4_freq[8] = { | 
					
						
							|  |  |  |     [0] = 0, | 
					
						
							|  |  |  |     [1] = 32768, | 
					
						
							|  |  |  |     [2] = 1000, | 
					
						
							|  |  |  |     [3] = 1, | 
					
						
							|  |  |  |     [4] = 1000000, | 
					
						
							|  |  |  |     /* [5] is the "Externally supplied clock".  Assign if necessary.  */ | 
					
						
							|  |  |  |     [5 ... 7] = 0, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  | #define TYPE_PXA2XX_TIMER "pxa2xx-timer"
 | 
					
						
							| 
									
										
										
										
											2020-09-16 14:25:19 -04:00
										 |  |  | OBJECT_DECLARE_SIMPLE_TYPE(PXA2xxTimerInfo, PXA2XX_TIMER) | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-10 01:44:56 +01:00
										 |  |  | typedef struct { | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     uint32_t value; | 
					
						
							| 
									
										
										
										
											2011-03-03 14:24:25 +01:00
										 |  |  |     qemu_irq irq; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     QEMUTimer *qtimer; | 
					
						
							|  |  |  |     int num; | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |     PXA2xxTimerInfo *info; | 
					
						
							| 
									
										
										
										
											2009-05-10 01:44:56 +01:00
										 |  |  | } PXA2xxTimer0; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-10 01:44:56 +01:00
										 |  |  | typedef struct { | 
					
						
							|  |  |  |     PXA2xxTimer0 tm; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     int32_t oldclock; | 
					
						
							|  |  |  |     int32_t clock; | 
					
						
							|  |  |  |     uint64_t lastload; | 
					
						
							|  |  |  |     uint32_t freq; | 
					
						
							|  |  |  |     uint32_t control; | 
					
						
							| 
									
										
										
										
											2009-05-10 01:44:56 +01:00
										 |  |  | } PXA2xxTimer4; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | struct PXA2xxTimerInfo { | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  |     SysBusDevice parent_obj; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-30 14:50:16 +01:00
										 |  |  |     MemoryRegion iomem; | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |     uint32_t flags; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     int32_t clock; | 
					
						
							|  |  |  |     int32_t oldclock; | 
					
						
							|  |  |  |     uint64_t lastload; | 
					
						
							|  |  |  |     uint32_t freq; | 
					
						
							| 
									
										
										
										
											2009-05-10 01:44:56 +01:00
										 |  |  |     PXA2xxTimer0 timer[4]; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     uint32_t events; | 
					
						
							|  |  |  |     uint32_t irq_enabled; | 
					
						
							|  |  |  |     uint32_t reset3; | 
					
						
							|  |  |  |     uint32_t snapshot; | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-04 03:40:59 +03:00
										 |  |  |     qemu_irq irq4; | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |     PXA2xxTimer4 tm4[8]; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PXA2XX_TIMER_HAVE_TM4	0
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-02-20 16:50:33 +03:00
										 |  |  |     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     int i; | 
					
						
							|  |  |  |     uint32_t now_vm; | 
					
						
							|  |  |  |     uint64_t new_qemu; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     now_vm = s->clock + | 
					
						
							| 
									
										
										
										
											2016-03-21 21:32:30 +05:30
										 |  |  |             muldiv64(now_qemu - s->lastload, s->freq, NANOSECONDS_PER_SECOND); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < 4; i ++) { | 
					
						
							|  |  |  |         new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm), | 
					
						
							| 
									
										
										
										
											2016-03-21 21:32:30 +05:30
										 |  |  |                         NANOSECONDS_PER_SECOND, s->freq); | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         timer_mod(s->timer[i].qtimer, new_qemu); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-02-20 16:50:33 +03:00
										 |  |  |     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     uint32_t now_vm; | 
					
						
							|  |  |  |     uint64_t new_qemu; | 
					
						
							|  |  |  |     static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 }; | 
					
						
							|  |  |  |     int counter; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												hw/timer/pxa2xx_timer: Add assertion to silent static analyzer warning
pxa2xx_timer_tick4() takes an opaque pointer, then calls
pxa2xx_timer_update4(), so the static analyzer can not
verify that the 'n < 8':
  425 static void pxa2xx_timer_tick4(void *opaque)
  426 {
  427     PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
  428     PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
  429
  430     pxa2xx_timer_tick(&t->tm);
  433     if (t->control & (1 << 6))
  434         pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4);
  135 static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
  136 {
  137     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
  140     static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
  142
  143     if (s->tm4[n].control & (1 << 7))
  144         counter = n;
  145     else
  146         counter = counters[n];
Add an assert() to give the static analyzer a hint, this fixes a
warning reported by Clang static code analyzer:
    CC      hw/timer/pxa2xx_timer.o
  hw/timer/pxa2xx_timer.c:146:17: warning: Assigned value is garbage or undefined
          counter = counters[n];
                  ^ ~~~~~~~~~~~
Reported-by: Clang Static Analyzer
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20200422133152.16770-10-philmd@redhat.com>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
											
										 
											2020-04-22 15:31:52 +02:00
										 |  |  |     assert(n < ARRAY_SIZE(counters)); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     if (s->tm4[n].control & (1 << 7)) | 
					
						
							|  |  |  |         counter = n; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         counter = counters[n]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!s->tm4[counter].freq) { | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         timer_del(s->tm4[n].tm.qtimer); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     now_vm = s->tm4[counter].clock + muldiv64(now_qemu - | 
					
						
							|  |  |  |                     s->tm4[counter].lastload, | 
					
						
							| 
									
										
										
										
											2016-03-21 21:32:30 +05:30
										 |  |  |                     s->tm4[counter].freq, NANOSECONDS_PER_SECOND); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-08 22:51:00 +00:00
										 |  |  |     new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm), | 
					
						
							| 
									
										
										
										
											2016-03-21 21:32:30 +05:30
										 |  |  |                     NANOSECONDS_PER_SECOND, s->tm4[counter].freq); | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |     timer_mod(s->tm4[n].tm.qtimer, new_qemu); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, | 
					
						
							| 
									
										
										
										
											2011-10-30 14:50:16 +01:00
										 |  |  |                                   unsigned size) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-02-20 16:50:33 +03:00
										 |  |  |     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     int tm = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (offset) { | 
					
						
							|  |  |  |     case OSMR3:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR2:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR1:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR0: | 
					
						
							|  |  |  |         return s->timer[tm].value; | 
					
						
							|  |  |  |     case OSMR11: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR10: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR9:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR8:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR7:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR6:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR5:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR4: | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |         if (!pxa2xx_timer_has_tm4(s)) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |             goto badreg; | 
					
						
							| 
									
										
										
										
											2007-05-08 22:51:00 +00:00
										 |  |  |         return s->tm4[tm].tm.value; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR: | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         return s->clock + muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - | 
					
						
							| 
									
										
										
										
											2016-03-21 21:32:30 +05:30
										 |  |  |                         s->lastload, s->freq, NANOSECONDS_PER_SECOND); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR11: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR10: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR9:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR8:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR7:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR6:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR5:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR4: | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |         if (!pxa2xx_timer_has_tm4(s)) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |             goto badreg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) { | 
					
						
							|  |  |  |             if (s->tm4[tm - 1].freq) | 
					
						
							|  |  |  |                 s->snapshot = s->tm4[tm - 1].clock + muldiv64( | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |                                 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |                                 s->tm4[tm - 1].lastload, | 
					
						
							| 
									
										
										
										
											2016-03-21 21:32:30 +05:30
										 |  |  |                                 s->tm4[tm - 1].freq, NANOSECONDS_PER_SECOND); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |             else | 
					
						
							|  |  |  |                 s->snapshot = s->tm4[tm - 1].clock; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!s->tm4[tm].freq) | 
					
						
							|  |  |  |             return s->tm4[tm].clock; | 
					
						
							| 
									
										
										
										
											2016-03-21 21:32:30 +05:30
										 |  |  |         return s->tm4[tm].clock + | 
					
						
							|  |  |  |             muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - | 
					
						
							|  |  |  |                      s->tm4[tm].lastload, s->tm4[tm].freq, | 
					
						
							|  |  |  |                      NANOSECONDS_PER_SECOND); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OIER: | 
					
						
							|  |  |  |         return s->irq_enabled; | 
					
						
							|  |  |  |     case OSSR:	/* Status register */ | 
					
						
							|  |  |  |         return s->events; | 
					
						
							|  |  |  |     case OWER: | 
					
						
							|  |  |  |         return s->reset3; | 
					
						
							|  |  |  |     case OMCR11: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR10: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR9:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR8:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR7:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR6:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR5:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR4: | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |         if (!pxa2xx_timer_has_tm4(s)) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |             goto badreg; | 
					
						
							|  |  |  |         return s->tm4[tm].control; | 
					
						
							|  |  |  |     case OSNR: | 
					
						
							|  |  |  |         return s->snapshot; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2018-01-11 13:25:38 +00:00
										 |  |  |         qemu_log_mask(LOG_UNIMP, | 
					
						
							|  |  |  |                       "%s: unknown register 0x%02" HWADDR_PRIx "\n", | 
					
						
							|  |  |  |                       __func__, offset); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     badreg: | 
					
						
							| 
									
										
										
										
											2018-01-11 13:25:38 +00:00
										 |  |  |         qemu_log_mask(LOG_GUEST_ERROR, | 
					
						
							|  |  |  |                       "%s: incorrect register 0x%02" HWADDR_PRIx "\n", | 
					
						
							|  |  |  |                       __func__, offset); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static void pxa2xx_timer_write(void *opaque, hwaddr offset, | 
					
						
							| 
									
										
										
										
											2011-10-30 14:50:16 +01:00
										 |  |  |                                uint64_t value, unsigned size) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int i, tm = 0; | 
					
						
							| 
									
										
										
										
											2011-02-20 16:50:33 +03:00
										 |  |  |     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     switch (offset) { | 
					
						
							|  |  |  |     case OSMR3:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR2:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR1:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR0: | 
					
						
							|  |  |  |         s->timer[tm].value = value; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         pxa2xx_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case OSMR11: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR10: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR9:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR8:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR7:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR6:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR5:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSMR4: | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |         if (!pxa2xx_timer_has_tm4(s)) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |             goto badreg; | 
					
						
							| 
									
										
										
										
											2007-05-08 22:51:00 +00:00
										 |  |  |         s->tm4[tm].tm.value = value; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case OSCR: | 
					
						
							|  |  |  |         s->oldclock = s->clock; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         s->clock = value; | 
					
						
							|  |  |  |         pxa2xx_timer_update(s, s->lastload); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case OSCR11: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR10: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR9:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR8:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR7:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR6:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR5:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OSCR4: | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |         if (!pxa2xx_timer_has_tm4(s)) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |             goto badreg; | 
					
						
							|  |  |  |         s->tm4[tm].oldclock = s->tm4[tm].clock; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         s->tm4[tm].lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         s->tm4[tm].clock = value; | 
					
						
							|  |  |  |         pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case OIER: | 
					
						
							|  |  |  |         s->irq_enabled = value & 0xfff; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case OSSR:	/* Status register */ | 
					
						
							| 
									
										
										
										
											2011-03-10 03:31:02 +01:00
										 |  |  |         value &= s->events; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         s->events &= ~value; | 
					
						
							| 
									
										
										
										
											2011-03-10 03:31:02 +01:00
										 |  |  |         for (i = 0; i < 4; i ++, value >>= 1) | 
					
						
							|  |  |  |             if (value & 1) | 
					
						
							| 
									
										
										
										
											2011-03-03 14:24:25 +01:00
										 |  |  |                 qemu_irq_lower(s->timer[i].irq); | 
					
						
							| 
									
										
										
										
											2011-03-10 03:31:02 +01:00
										 |  |  |         if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value) | 
					
						
							|  |  |  |             qemu_irq_lower(s->irq4); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case OWER:	/* XXX: Reset on OSMR3 match? */ | 
					
						
							|  |  |  |         s->reset3 = value; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case OMCR7:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR6:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR5:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR4: | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |         if (!pxa2xx_timer_has_tm4(s)) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |             goto badreg; | 
					
						
							|  |  |  |         s->tm4[tm].control = value & 0x0ff; | 
					
						
							|  |  |  |         /* XXX Stop if running (shouldn't happen) */ | 
					
						
							|  |  |  |         if ((value & (1 << 7)) || tm == 0) | 
					
						
							|  |  |  |             s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7]; | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             s->tm4[tm].freq = 0; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |             pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case OMCR11: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR10: tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR9:  tm ++; | 
					
						
							| 
									
										
										
										
											2013-01-21 12:50:56 +00:00
										 |  |  |         /* fall through */ | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     case OMCR8:  tm += 4; | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |         if (!pxa2xx_timer_has_tm4(s)) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |             goto badreg; | 
					
						
							|  |  |  |         s->tm4[tm].control = value & 0x3ff; | 
					
						
							|  |  |  |         /* XXX Stop if running (shouldn't happen) */ | 
					
						
							|  |  |  |         if ((value & (1 << 7)) || !(tm & 1)) | 
					
						
							|  |  |  |             s->tm4[tm].freq = | 
					
						
							|  |  |  |                     pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)]; | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             s->tm4[tm].freq = 0; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |             pxa2xx_timer_update4(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tm); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							| 
									
										
										
										
											2018-01-11 13:25:38 +00:00
										 |  |  |         qemu_log_mask(LOG_UNIMP, | 
					
						
							|  |  |  |                       "%s: unknown register 0x%02" HWADDR_PRIx " " | 
					
						
							|  |  |  |                       "(value 0x%08" PRIx64 ")\n",  __func__, offset, value); | 
					
						
							|  |  |  |         break; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     badreg: | 
					
						
							| 
									
										
										
										
											2018-01-11 13:25:38 +00:00
										 |  |  |         qemu_log_mask(LOG_GUEST_ERROR, | 
					
						
							|  |  |  |                       "%s: incorrect register 0x%02" HWADDR_PRIx " " | 
					
						
							|  |  |  |                       "(value 0x%08" PRIx64 ")\n", __func__, offset, value); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-30 14:50:16 +01:00
										 |  |  | static const MemoryRegionOps pxa2xx_timer_ops = { | 
					
						
							|  |  |  |     .read = pxa2xx_timer_read, | 
					
						
							|  |  |  |     .write = pxa2xx_timer_write, | 
					
						
							|  |  |  |     .endianness = DEVICE_NATIVE_ENDIAN, | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void pxa2xx_timer_tick(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-10 01:44:56 +01:00
										 |  |  |     PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque; | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |     PXA2xxTimerInfo *i = t->info; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (i->irq_enabled & (1 << t->num)) { | 
					
						
							|  |  |  |         i->events |= 1 << t->num; | 
					
						
							| 
									
										
										
										
											2011-03-03 14:24:25 +01:00
										 |  |  |         qemu_irq_raise(t->irq); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (t->num == 3) | 
					
						
							|  |  |  |         if (i->reset3 & 1) { | 
					
						
							|  |  |  |             i->reset3 = 0; | 
					
						
							| 
									
										
										
										
											2017-05-15 16:41:13 -05:00
										 |  |  |             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void pxa2xx_timer_tick4(void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-05-10 01:44:56 +01:00
										 |  |  |     PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque; | 
					
						
							| 
									
										
										
										
											2011-02-20 16:50:33 +03:00
										 |  |  |     PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info; | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-08 22:51:00 +00:00
										 |  |  |     pxa2xx_timer_tick(&t->tm); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     if (t->control & (1 << 3)) | 
					
						
							|  |  |  |         t->clock = 0; | 
					
						
							|  |  |  |     if (t->control & (1 << 6)) | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         pxa2xx_timer_update4(i, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), t->tm.num - 4); | 
					
						
							| 
									
										
										
										
											2011-03-04 03:40:59 +03:00
										 |  |  |     if (i->events & 0xff0) | 
					
						
							|  |  |  |         qemu_irq_raise(i->irq4); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | static int pxa25x_timer_post_load(void *opaque, int version_id) | 
					
						
							| 
									
										
										
										
											2007-05-24 18:50:09 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-02-20 16:50:33 +03:00
										 |  |  |     PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque; | 
					
						
							| 
									
										
										
										
											2007-05-24 18:50:09 +00:00
										 |  |  |     int64_t now; | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |     now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | 
					
						
							| 
									
										
										
										
											2007-05-24 18:50:09 +00:00
										 |  |  |     pxa2xx_timer_update(s, now); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |     if (pxa2xx_timer_has_tm4(s)) | 
					
						
							|  |  |  |         for (i = 0; i < 8; i ++) | 
					
						
							| 
									
										
										
										
											2007-05-24 18:50:09 +00:00
										 |  |  |             pxa2xx_timer_update4(s, now, i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  | static void pxa2xx_timer_init(Object *obj) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  |     PXA2xxTimerInfo *s = PXA2XX_TIMER(obj); | 
					
						
							|  |  |  |     SysBusDevice *dev = SYS_BUS_DEVICE(obj); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     s->irq_enabled = 0; | 
					
						
							|  |  |  |     s->oldclock = 0; | 
					
						
							|  |  |  |     s->clock = 0; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |     s->lastload = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     s->reset3 = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  |     memory_region_init_io(&s->iomem, obj, &pxa2xx_timer_ops, s, | 
					
						
							|  |  |  |                           "pxa2xx-timer", 0x00001000); | 
					
						
							|  |  |  |     sysbus_init_mmio(dev, &s->iomem); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void pxa2xx_timer_realize(DeviceState *dev, Error **errp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PXA2xxTimerInfo *s = PXA2XX_TIMER(dev); | 
					
						
							|  |  |  |     SysBusDevice *sbd = SYS_BUS_DEVICE(dev); | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     for (i = 0; i < 4; i ++) { | 
					
						
							|  |  |  |         s->timer[i].value = 0; | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  |         sysbus_init_irq(sbd, &s->timer[i].irq); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |         s->timer[i].info = s; | 
					
						
							|  |  |  |         s->timer[i].num = i; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |         s->timer[i].qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  |                                           pxa2xx_timer_tick, &s->timer[i]); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |     if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) { | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  |         sysbus_init_irq(sbd, &s->irq4); | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for (i = 0; i < 8; i ++) { | 
					
						
							|  |  |  |             s->tm4[i].tm.value = 0; | 
					
						
							|  |  |  |             s->tm4[i].tm.info = s; | 
					
						
							|  |  |  |             s->tm4[i].tm.num = i + 4; | 
					
						
							|  |  |  |             s->tm4[i].freq = 0; | 
					
						
							|  |  |  |             s->tm4[i].control = 0x0; | 
					
						
							| 
									
										
										
										
											2013-08-21 16:03:08 +01:00
										 |  |  |             s->tm4[i].tm.qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  |                                                pxa2xx_timer_tick4, &s->tm4[i]); | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | static const VMStateDescription vmstate_pxa2xx_timer0_regs = { | 
					
						
							|  |  |  |     .name = "pxa2xx_timer0", | 
					
						
							| 
									
										
										
										
											2011-03-10 03:31:02 +01:00
										 |  |  |     .version_id = 2, | 
					
						
							|  |  |  |     .minimum_version_id = 2, | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_UINT32(value, PXA2xxTimer0), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST(), | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const VMStateDescription vmstate_pxa2xx_timer4_regs = { | 
					
						
							|  |  |  |     .name = "pxa2xx_timer4", | 
					
						
							|  |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_STRUCT(tm, PXA2xxTimer4, 1, | 
					
						
							|  |  |  |                         vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), | 
					
						
							|  |  |  |         VMSTATE_INT32(oldclock, PXA2xxTimer4), | 
					
						
							|  |  |  |         VMSTATE_INT32(clock, PXA2xxTimer4), | 
					
						
							|  |  |  |         VMSTATE_UINT64(lastload, PXA2xxTimer4), | 
					
						
							|  |  |  |         VMSTATE_UINT32(freq, PXA2xxTimer4), | 
					
						
							|  |  |  |         VMSTATE_UINT32(control, PXA2xxTimer4), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST(), | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id) | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  |     return pxa2xx_timer_has_tm4(opaque); | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | static const VMStateDescription vmstate_pxa2xx_timer_regs = { | 
					
						
							|  |  |  |     .name = "pxa2xx_timer", | 
					
						
							|  |  |  |     .version_id = 1, | 
					
						
							|  |  |  |     .minimum_version_id = 1, | 
					
						
							|  |  |  |     .post_load = pxa25x_timer_post_load, | 
					
						
							|  |  |  |     .fields = (VMStateField[]) { | 
					
						
							|  |  |  |         VMSTATE_INT32(clock, PXA2xxTimerInfo), | 
					
						
							|  |  |  |         VMSTATE_INT32(oldclock, PXA2xxTimerInfo), | 
					
						
							|  |  |  |         VMSTATE_UINT64(lastload, PXA2xxTimerInfo), | 
					
						
							|  |  |  |         VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1, | 
					
						
							|  |  |  |                         vmstate_pxa2xx_timer0_regs, PXA2xxTimer0), | 
					
						
							|  |  |  |         VMSTATE_UINT32(events, PXA2xxTimerInfo), | 
					
						
							|  |  |  |         VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo), | 
					
						
							|  |  |  |         VMSTATE_UINT32(reset3, PXA2xxTimerInfo), | 
					
						
							|  |  |  |         VMSTATE_UINT32(snapshot, PXA2xxTimerInfo), | 
					
						
							|  |  |  |         VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8, | 
					
						
							|  |  |  |                         pxa2xx_timer_has_tm4_test, 0, | 
					
						
							|  |  |  |                         vmstate_pxa2xx_timer4_regs, PXA2xxTimer4), | 
					
						
							|  |  |  |         VMSTATE_END_OF_LIST(), | 
					
						
							| 
									
										
										
										
											2007-04-30 01:48:07 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | static Property pxa25x_timer_dev_properties[] = { | 
					
						
							|  |  |  |     DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ), | 
					
						
							|  |  |  |     DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  |                     PXA2XX_TIMER_HAVE_TM4, false), | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  |     DEFINE_PROP_END_OF_LIST(), | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     DeviceClass *dc = DEVICE_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     dc->desc = "PXA25x timer"; | 
					
						
							| 
									
										
										
										
											2020-01-10 19:30:32 +04:00
										 |  |  |     device_class_set_props(dc, pxa25x_timer_dev_properties); | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-10 16:19:07 +01:00
										 |  |  | static const TypeInfo pxa25x_timer_dev_info = { | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .name          = "pxa25x-timer", | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  |     .parent        = TYPE_PXA2XX_TIMER, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .instance_size = sizeof(PXA2xxTimerInfo), | 
					
						
							|  |  |  |     .class_init    = pxa25x_timer_dev_class_init, | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static Property pxa27x_timer_dev_properties[] = { | 
					
						
							|  |  |  |     DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ), | 
					
						
							|  |  |  |     DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags, | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  |                     PXA2XX_TIMER_HAVE_TM4, true), | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  |     DEFINE_PROP_END_OF_LIST(), | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     DeviceClass *dc = DEVICE_CLASS(klass); | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     dc->desc = "PXA27x timer"; | 
					
						
							| 
									
										
										
										
											2020-01-10 19:30:32 +04:00
										 |  |  |     device_class_set_props(dc, pxa27x_timer_dev_properties); | 
					
						
							| 
									
										
										
										
											2012-01-24 13:12:29 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-10 16:19:07 +01:00
										 |  |  | static const TypeInfo pxa27x_timer_dev_info = { | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .name          = "pxa27x-timer", | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  |     .parent        = TYPE_PXA2XX_TIMER, | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     .instance_size = sizeof(PXA2xxTimerInfo), | 
					
						
							|  |  |  |     .class_init    = pxa27x_timer_dev_class_init, | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  | static void pxa2xx_timer_class_init(ObjectClass *oc, void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     DeviceClass *dc = DEVICE_CLASS(oc); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  |     dc->realize  = pxa2xx_timer_realize; | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  |     dc->vmsd = &vmstate_pxa2xx_timer_regs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const TypeInfo pxa2xx_timer_type_info = { | 
					
						
							|  |  |  |     .name          = TYPE_PXA2XX_TIMER, | 
					
						
							|  |  |  |     .parent        = TYPE_SYS_BUS_DEVICE, | 
					
						
							|  |  |  |     .instance_size = sizeof(PXA2xxTimerInfo), | 
					
						
							| 
									
										
										
										
											2016-02-18 14:16:21 +00:00
										 |  |  |     .instance_init = pxa2xx_timer_init, | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  |     .abstract      = true, | 
					
						
							|  |  |  |     .class_init    = pxa2xx_timer_class_init, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-09 15:20:55 +01:00
										 |  |  | static void pxa2xx_timer_register_types(void) | 
					
						
							| 
									
										
										
										
											2011-03-03 14:14:44 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-07-27 15:20:20 +02:00
										 |  |  |     type_register_static(&pxa2xx_timer_type_info); | 
					
						
							| 
									
										
										
										
											2011-12-07 21:34:16 -06:00
										 |  |  |     type_register_static(&pxa25x_timer_dev_info); | 
					
						
							|  |  |  |     type_register_static(&pxa27x_timer_dev_info); | 
					
						
							| 
									
										
										
										
											2012-02-09 15:20:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type_init(pxa2xx_timer_register_types) |