xref: /openbmc/qemu/hw/arm/omap1.c (revision dd285b06)
1*dd285b06SPaolo Bonzini /*
2*dd285b06SPaolo Bonzini  * TI OMAP processors emulation.
3*dd285b06SPaolo Bonzini  *
4*dd285b06SPaolo Bonzini  * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
5*dd285b06SPaolo Bonzini  *
6*dd285b06SPaolo Bonzini  * This program is free software; you can redistribute it and/or
7*dd285b06SPaolo Bonzini  * modify it under the terms of the GNU General Public License as
8*dd285b06SPaolo Bonzini  * published by the Free Software Foundation; either version 2 or
9*dd285b06SPaolo Bonzini  * (at your option) version 3 of the License.
10*dd285b06SPaolo Bonzini  *
11*dd285b06SPaolo Bonzini  * This program is distributed in the hope that it will be useful,
12*dd285b06SPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*dd285b06SPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*dd285b06SPaolo Bonzini  * GNU General Public License for more details.
15*dd285b06SPaolo Bonzini  *
16*dd285b06SPaolo Bonzini  * You should have received a copy of the GNU General Public License along
17*dd285b06SPaolo Bonzini  * with this program; if not, see <http://www.gnu.org/licenses/>.
18*dd285b06SPaolo Bonzini  */
19*dd285b06SPaolo Bonzini #include "hw/hw.h"
20*dd285b06SPaolo Bonzini #include "hw/arm-misc.h"
21*dd285b06SPaolo Bonzini #include "hw/omap.h"
22*dd285b06SPaolo Bonzini #include "sysemu/sysemu.h"
23*dd285b06SPaolo Bonzini #include "hw/soc_dma.h"
24*dd285b06SPaolo Bonzini #include "sysemu/blockdev.h"
25*dd285b06SPaolo Bonzini #include "qemu/range.h"
26*dd285b06SPaolo Bonzini #include "hw/sysbus.h"
27*dd285b06SPaolo Bonzini 
28*dd285b06SPaolo Bonzini /* Should signal the TCMI/GPMC */
29*dd285b06SPaolo Bonzini uint32_t omap_badwidth_read8(void *opaque, hwaddr addr)
30*dd285b06SPaolo Bonzini {
31*dd285b06SPaolo Bonzini     uint8_t ret;
32*dd285b06SPaolo Bonzini 
33*dd285b06SPaolo Bonzini     OMAP_8B_REG(addr);
34*dd285b06SPaolo Bonzini     cpu_physical_memory_read(addr, (void *) &ret, 1);
35*dd285b06SPaolo Bonzini     return ret;
36*dd285b06SPaolo Bonzini }
37*dd285b06SPaolo Bonzini 
38*dd285b06SPaolo Bonzini void omap_badwidth_write8(void *opaque, hwaddr addr,
39*dd285b06SPaolo Bonzini                 uint32_t value)
40*dd285b06SPaolo Bonzini {
41*dd285b06SPaolo Bonzini     uint8_t val8 = value;
42*dd285b06SPaolo Bonzini 
43*dd285b06SPaolo Bonzini     OMAP_8B_REG(addr);
44*dd285b06SPaolo Bonzini     cpu_physical_memory_write(addr, (void *) &val8, 1);
45*dd285b06SPaolo Bonzini }
46*dd285b06SPaolo Bonzini 
47*dd285b06SPaolo Bonzini uint32_t omap_badwidth_read16(void *opaque, hwaddr addr)
48*dd285b06SPaolo Bonzini {
49*dd285b06SPaolo Bonzini     uint16_t ret;
50*dd285b06SPaolo Bonzini 
51*dd285b06SPaolo Bonzini     OMAP_16B_REG(addr);
52*dd285b06SPaolo Bonzini     cpu_physical_memory_read(addr, (void *) &ret, 2);
53*dd285b06SPaolo Bonzini     return ret;
54*dd285b06SPaolo Bonzini }
55*dd285b06SPaolo Bonzini 
56*dd285b06SPaolo Bonzini void omap_badwidth_write16(void *opaque, hwaddr addr,
57*dd285b06SPaolo Bonzini                 uint32_t value)
58*dd285b06SPaolo Bonzini {
59*dd285b06SPaolo Bonzini     uint16_t val16 = value;
60*dd285b06SPaolo Bonzini 
61*dd285b06SPaolo Bonzini     OMAP_16B_REG(addr);
62*dd285b06SPaolo Bonzini     cpu_physical_memory_write(addr, (void *) &val16, 2);
63*dd285b06SPaolo Bonzini }
64*dd285b06SPaolo Bonzini 
65*dd285b06SPaolo Bonzini uint32_t omap_badwidth_read32(void *opaque, hwaddr addr)
66*dd285b06SPaolo Bonzini {
67*dd285b06SPaolo Bonzini     uint32_t ret;
68*dd285b06SPaolo Bonzini 
69*dd285b06SPaolo Bonzini     OMAP_32B_REG(addr);
70*dd285b06SPaolo Bonzini     cpu_physical_memory_read(addr, (void *) &ret, 4);
71*dd285b06SPaolo Bonzini     return ret;
72*dd285b06SPaolo Bonzini }
73*dd285b06SPaolo Bonzini 
74*dd285b06SPaolo Bonzini void omap_badwidth_write32(void *opaque, hwaddr addr,
75*dd285b06SPaolo Bonzini                 uint32_t value)
76*dd285b06SPaolo Bonzini {
77*dd285b06SPaolo Bonzini     OMAP_32B_REG(addr);
78*dd285b06SPaolo Bonzini     cpu_physical_memory_write(addr, (void *) &value, 4);
79*dd285b06SPaolo Bonzini }
80*dd285b06SPaolo Bonzini 
81*dd285b06SPaolo Bonzini /* MPU OS timers */
82*dd285b06SPaolo Bonzini struct omap_mpu_timer_s {
83*dd285b06SPaolo Bonzini     MemoryRegion iomem;
84*dd285b06SPaolo Bonzini     qemu_irq irq;
85*dd285b06SPaolo Bonzini     omap_clk clk;
86*dd285b06SPaolo Bonzini     uint32_t val;
87*dd285b06SPaolo Bonzini     int64_t time;
88*dd285b06SPaolo Bonzini     QEMUTimer *timer;
89*dd285b06SPaolo Bonzini     QEMUBH *tick;
90*dd285b06SPaolo Bonzini     int64_t rate;
91*dd285b06SPaolo Bonzini     int it_ena;
92*dd285b06SPaolo Bonzini 
93*dd285b06SPaolo Bonzini     int enable;
94*dd285b06SPaolo Bonzini     int ptv;
95*dd285b06SPaolo Bonzini     int ar;
96*dd285b06SPaolo Bonzini     int st;
97*dd285b06SPaolo Bonzini     uint32_t reset_val;
98*dd285b06SPaolo Bonzini };
99*dd285b06SPaolo Bonzini 
100*dd285b06SPaolo Bonzini static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer)
101*dd285b06SPaolo Bonzini {
102*dd285b06SPaolo Bonzini     uint64_t distance = qemu_get_clock_ns(vm_clock) - timer->time;
103*dd285b06SPaolo Bonzini 
104*dd285b06SPaolo Bonzini     if (timer->st && timer->enable && timer->rate)
105*dd285b06SPaolo Bonzini         return timer->val - muldiv64(distance >> (timer->ptv + 1),
106*dd285b06SPaolo Bonzini                                      timer->rate, get_ticks_per_sec());
107*dd285b06SPaolo Bonzini     else
108*dd285b06SPaolo Bonzini         return timer->val;
109*dd285b06SPaolo Bonzini }
110*dd285b06SPaolo Bonzini 
111*dd285b06SPaolo Bonzini static inline void omap_timer_sync(struct omap_mpu_timer_s *timer)
112*dd285b06SPaolo Bonzini {
113*dd285b06SPaolo Bonzini     timer->val = omap_timer_read(timer);
114*dd285b06SPaolo Bonzini     timer->time = qemu_get_clock_ns(vm_clock);
115*dd285b06SPaolo Bonzini }
116*dd285b06SPaolo Bonzini 
117*dd285b06SPaolo Bonzini static inline void omap_timer_update(struct omap_mpu_timer_s *timer)
118*dd285b06SPaolo Bonzini {
119*dd285b06SPaolo Bonzini     int64_t expires;
120*dd285b06SPaolo Bonzini 
121*dd285b06SPaolo Bonzini     if (timer->enable && timer->st && timer->rate) {
122*dd285b06SPaolo Bonzini         timer->val = timer->reset_val;	/* Should skip this on clk enable */
123*dd285b06SPaolo Bonzini         expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1),
124*dd285b06SPaolo Bonzini                            get_ticks_per_sec(), timer->rate);
125*dd285b06SPaolo Bonzini 
126*dd285b06SPaolo Bonzini         /* If timer expiry would be sooner than in about 1 ms and
127*dd285b06SPaolo Bonzini          * auto-reload isn't set, then fire immediately.  This is a hack
128*dd285b06SPaolo Bonzini          * to make systems like PalmOS run in acceptable time.  PalmOS
129*dd285b06SPaolo Bonzini          * sets the interval to a very low value and polls the status bit
130*dd285b06SPaolo Bonzini          * in a busy loop when it wants to sleep just a couple of CPU
131*dd285b06SPaolo Bonzini          * ticks.  */
132*dd285b06SPaolo Bonzini         if (expires > (get_ticks_per_sec() >> 10) || timer->ar)
133*dd285b06SPaolo Bonzini             qemu_mod_timer(timer->timer, timer->time + expires);
134*dd285b06SPaolo Bonzini         else
135*dd285b06SPaolo Bonzini             qemu_bh_schedule(timer->tick);
136*dd285b06SPaolo Bonzini     } else
137*dd285b06SPaolo Bonzini         qemu_del_timer(timer->timer);
138*dd285b06SPaolo Bonzini }
139*dd285b06SPaolo Bonzini 
140*dd285b06SPaolo Bonzini static void omap_timer_fire(void *opaque)
141*dd285b06SPaolo Bonzini {
142*dd285b06SPaolo Bonzini     struct omap_mpu_timer_s *timer = opaque;
143*dd285b06SPaolo Bonzini 
144*dd285b06SPaolo Bonzini     if (!timer->ar) {
145*dd285b06SPaolo Bonzini         timer->val = 0;
146*dd285b06SPaolo Bonzini         timer->st = 0;
147*dd285b06SPaolo Bonzini     }
148*dd285b06SPaolo Bonzini 
149*dd285b06SPaolo Bonzini     if (timer->it_ena)
150*dd285b06SPaolo Bonzini         /* Edge-triggered irq */
151*dd285b06SPaolo Bonzini         qemu_irq_pulse(timer->irq);
152*dd285b06SPaolo Bonzini }
153*dd285b06SPaolo Bonzini 
154*dd285b06SPaolo Bonzini static void omap_timer_tick(void *opaque)
155*dd285b06SPaolo Bonzini {
156*dd285b06SPaolo Bonzini     struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque;
157*dd285b06SPaolo Bonzini 
158*dd285b06SPaolo Bonzini     omap_timer_sync(timer);
159*dd285b06SPaolo Bonzini     omap_timer_fire(timer);
160*dd285b06SPaolo Bonzini     omap_timer_update(timer);
161*dd285b06SPaolo Bonzini }
162*dd285b06SPaolo Bonzini 
163*dd285b06SPaolo Bonzini static void omap_timer_clk_update(void *opaque, int line, int on)
164*dd285b06SPaolo Bonzini {
165*dd285b06SPaolo Bonzini     struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque;
166*dd285b06SPaolo Bonzini 
167*dd285b06SPaolo Bonzini     omap_timer_sync(timer);
168*dd285b06SPaolo Bonzini     timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
169*dd285b06SPaolo Bonzini     omap_timer_update(timer);
170*dd285b06SPaolo Bonzini }
171*dd285b06SPaolo Bonzini 
172*dd285b06SPaolo Bonzini static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer)
173*dd285b06SPaolo Bonzini {
174*dd285b06SPaolo Bonzini     omap_clk_adduser(timer->clk,
175*dd285b06SPaolo Bonzini                     qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]);
176*dd285b06SPaolo Bonzini     timer->rate = omap_clk_getrate(timer->clk);
177*dd285b06SPaolo Bonzini }
178*dd285b06SPaolo Bonzini 
179*dd285b06SPaolo Bonzini static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr,
180*dd285b06SPaolo Bonzini                                     unsigned size)
181*dd285b06SPaolo Bonzini {
182*dd285b06SPaolo Bonzini     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
183*dd285b06SPaolo Bonzini 
184*dd285b06SPaolo Bonzini     if (size != 4) {
185*dd285b06SPaolo Bonzini         return omap_badwidth_read32(opaque, addr);
186*dd285b06SPaolo Bonzini     }
187*dd285b06SPaolo Bonzini 
188*dd285b06SPaolo Bonzini     switch (addr) {
189*dd285b06SPaolo Bonzini     case 0x00:	/* CNTL_TIMER */
190*dd285b06SPaolo Bonzini         return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st;
191*dd285b06SPaolo Bonzini 
192*dd285b06SPaolo Bonzini     case 0x04:	/* LOAD_TIM */
193*dd285b06SPaolo Bonzini         break;
194*dd285b06SPaolo Bonzini 
195*dd285b06SPaolo Bonzini     case 0x08:	/* READ_TIM */
196*dd285b06SPaolo Bonzini         return omap_timer_read(s);
197*dd285b06SPaolo Bonzini     }
198*dd285b06SPaolo Bonzini 
199*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
200*dd285b06SPaolo Bonzini     return 0;
201*dd285b06SPaolo Bonzini }
202*dd285b06SPaolo Bonzini 
203*dd285b06SPaolo Bonzini static void omap_mpu_timer_write(void *opaque, hwaddr addr,
204*dd285b06SPaolo Bonzini                                  uint64_t value, unsigned size)
205*dd285b06SPaolo Bonzini {
206*dd285b06SPaolo Bonzini     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
207*dd285b06SPaolo Bonzini 
208*dd285b06SPaolo Bonzini     if (size != 4) {
209*dd285b06SPaolo Bonzini         return omap_badwidth_write32(opaque, addr, value);
210*dd285b06SPaolo Bonzini     }
211*dd285b06SPaolo Bonzini 
212*dd285b06SPaolo Bonzini     switch (addr) {
213*dd285b06SPaolo Bonzini     case 0x00:	/* CNTL_TIMER */
214*dd285b06SPaolo Bonzini         omap_timer_sync(s);
215*dd285b06SPaolo Bonzini         s->enable = (value >> 5) & 1;
216*dd285b06SPaolo Bonzini         s->ptv = (value >> 2) & 7;
217*dd285b06SPaolo Bonzini         s->ar = (value >> 1) & 1;
218*dd285b06SPaolo Bonzini         s->st = value & 1;
219*dd285b06SPaolo Bonzini         omap_timer_update(s);
220*dd285b06SPaolo Bonzini         return;
221*dd285b06SPaolo Bonzini 
222*dd285b06SPaolo Bonzini     case 0x04:	/* LOAD_TIM */
223*dd285b06SPaolo Bonzini         s->reset_val = value;
224*dd285b06SPaolo Bonzini         return;
225*dd285b06SPaolo Bonzini 
226*dd285b06SPaolo Bonzini     case 0x08:	/* READ_TIM */
227*dd285b06SPaolo Bonzini         OMAP_RO_REG(addr);
228*dd285b06SPaolo Bonzini         break;
229*dd285b06SPaolo Bonzini 
230*dd285b06SPaolo Bonzini     default:
231*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
232*dd285b06SPaolo Bonzini     }
233*dd285b06SPaolo Bonzini }
234*dd285b06SPaolo Bonzini 
235*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_mpu_timer_ops = {
236*dd285b06SPaolo Bonzini     .read = omap_mpu_timer_read,
237*dd285b06SPaolo Bonzini     .write = omap_mpu_timer_write,
238*dd285b06SPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
239*dd285b06SPaolo Bonzini };
240*dd285b06SPaolo Bonzini 
241*dd285b06SPaolo Bonzini static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s)
242*dd285b06SPaolo Bonzini {
243*dd285b06SPaolo Bonzini     qemu_del_timer(s->timer);
244*dd285b06SPaolo Bonzini     s->enable = 0;
245*dd285b06SPaolo Bonzini     s->reset_val = 31337;
246*dd285b06SPaolo Bonzini     s->val = 0;
247*dd285b06SPaolo Bonzini     s->ptv = 0;
248*dd285b06SPaolo Bonzini     s->ar = 0;
249*dd285b06SPaolo Bonzini     s->st = 0;
250*dd285b06SPaolo Bonzini     s->it_ena = 1;
251*dd285b06SPaolo Bonzini }
252*dd285b06SPaolo Bonzini 
253*dd285b06SPaolo Bonzini static struct omap_mpu_timer_s *omap_mpu_timer_init(MemoryRegion *system_memory,
254*dd285b06SPaolo Bonzini                 hwaddr base,
255*dd285b06SPaolo Bonzini                 qemu_irq irq, omap_clk clk)
256*dd285b06SPaolo Bonzini {
257*dd285b06SPaolo Bonzini     struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *)
258*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_mpu_timer_s));
259*dd285b06SPaolo Bonzini 
260*dd285b06SPaolo Bonzini     s->irq = irq;
261*dd285b06SPaolo Bonzini     s->clk = clk;
262*dd285b06SPaolo Bonzini     s->timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, s);
263*dd285b06SPaolo Bonzini     s->tick = qemu_bh_new(omap_timer_fire, s);
264*dd285b06SPaolo Bonzini     omap_mpu_timer_reset(s);
265*dd285b06SPaolo Bonzini     omap_timer_clk_setup(s);
266*dd285b06SPaolo Bonzini 
267*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_mpu_timer_ops, s,
268*dd285b06SPaolo Bonzini                           "omap-mpu-timer", 0x100);
269*dd285b06SPaolo Bonzini 
270*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &s->iomem);
271*dd285b06SPaolo Bonzini 
272*dd285b06SPaolo Bonzini     return s;
273*dd285b06SPaolo Bonzini }
274*dd285b06SPaolo Bonzini 
275*dd285b06SPaolo Bonzini /* Watchdog timer */
276*dd285b06SPaolo Bonzini struct omap_watchdog_timer_s {
277*dd285b06SPaolo Bonzini     struct omap_mpu_timer_s timer;
278*dd285b06SPaolo Bonzini     MemoryRegion iomem;
279*dd285b06SPaolo Bonzini     uint8_t last_wr;
280*dd285b06SPaolo Bonzini     int mode;
281*dd285b06SPaolo Bonzini     int free;
282*dd285b06SPaolo Bonzini     int reset;
283*dd285b06SPaolo Bonzini };
284*dd285b06SPaolo Bonzini 
285*dd285b06SPaolo Bonzini static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr,
286*dd285b06SPaolo Bonzini                                    unsigned size)
287*dd285b06SPaolo Bonzini {
288*dd285b06SPaolo Bonzini     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
289*dd285b06SPaolo Bonzini 
290*dd285b06SPaolo Bonzini     if (size != 2) {
291*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
292*dd285b06SPaolo Bonzini     }
293*dd285b06SPaolo Bonzini 
294*dd285b06SPaolo Bonzini     switch (addr) {
295*dd285b06SPaolo Bonzini     case 0x00:	/* CNTL_TIMER */
296*dd285b06SPaolo Bonzini         return (s->timer.ptv << 9) | (s->timer.ar << 8) |
297*dd285b06SPaolo Bonzini                 (s->timer.st << 7) | (s->free << 1);
298*dd285b06SPaolo Bonzini 
299*dd285b06SPaolo Bonzini     case 0x04:	/* READ_TIMER */
300*dd285b06SPaolo Bonzini         return omap_timer_read(&s->timer);
301*dd285b06SPaolo Bonzini 
302*dd285b06SPaolo Bonzini     case 0x08:	/* TIMER_MODE */
303*dd285b06SPaolo Bonzini         return s->mode << 15;
304*dd285b06SPaolo Bonzini     }
305*dd285b06SPaolo Bonzini 
306*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
307*dd285b06SPaolo Bonzini     return 0;
308*dd285b06SPaolo Bonzini }
309*dd285b06SPaolo Bonzini 
310*dd285b06SPaolo Bonzini static void omap_wd_timer_write(void *opaque, hwaddr addr,
311*dd285b06SPaolo Bonzini                                 uint64_t value, unsigned size)
312*dd285b06SPaolo Bonzini {
313*dd285b06SPaolo Bonzini     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
314*dd285b06SPaolo Bonzini 
315*dd285b06SPaolo Bonzini     if (size != 2) {
316*dd285b06SPaolo Bonzini         return omap_badwidth_write16(opaque, addr, value);
317*dd285b06SPaolo Bonzini     }
318*dd285b06SPaolo Bonzini 
319*dd285b06SPaolo Bonzini     switch (addr) {
320*dd285b06SPaolo Bonzini     case 0x00:	/* CNTL_TIMER */
321*dd285b06SPaolo Bonzini         omap_timer_sync(&s->timer);
322*dd285b06SPaolo Bonzini         s->timer.ptv = (value >> 9) & 7;
323*dd285b06SPaolo Bonzini         s->timer.ar = (value >> 8) & 1;
324*dd285b06SPaolo Bonzini         s->timer.st = (value >> 7) & 1;
325*dd285b06SPaolo Bonzini         s->free = (value >> 1) & 1;
326*dd285b06SPaolo Bonzini         omap_timer_update(&s->timer);
327*dd285b06SPaolo Bonzini         break;
328*dd285b06SPaolo Bonzini 
329*dd285b06SPaolo Bonzini     case 0x04:	/* LOAD_TIMER */
330*dd285b06SPaolo Bonzini         s->timer.reset_val = value & 0xffff;
331*dd285b06SPaolo Bonzini         break;
332*dd285b06SPaolo Bonzini 
333*dd285b06SPaolo Bonzini     case 0x08:	/* TIMER_MODE */
334*dd285b06SPaolo Bonzini         if (!s->mode && ((value >> 15) & 1))
335*dd285b06SPaolo Bonzini             omap_clk_get(s->timer.clk);
336*dd285b06SPaolo Bonzini         s->mode |= (value >> 15) & 1;
337*dd285b06SPaolo Bonzini         if (s->last_wr == 0xf5) {
338*dd285b06SPaolo Bonzini             if ((value & 0xff) == 0xa0) {
339*dd285b06SPaolo Bonzini                 if (s->mode) {
340*dd285b06SPaolo Bonzini                     s->mode = 0;
341*dd285b06SPaolo Bonzini                     omap_clk_put(s->timer.clk);
342*dd285b06SPaolo Bonzini                 }
343*dd285b06SPaolo Bonzini             } else {
344*dd285b06SPaolo Bonzini                 /* XXX: on T|E hardware somehow this has no effect,
345*dd285b06SPaolo Bonzini                  * on Zire 71 it works as specified.  */
346*dd285b06SPaolo Bonzini                 s->reset = 1;
347*dd285b06SPaolo Bonzini                 qemu_system_reset_request();
348*dd285b06SPaolo Bonzini             }
349*dd285b06SPaolo Bonzini         }
350*dd285b06SPaolo Bonzini         s->last_wr = value & 0xff;
351*dd285b06SPaolo Bonzini         break;
352*dd285b06SPaolo Bonzini 
353*dd285b06SPaolo Bonzini     default:
354*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
355*dd285b06SPaolo Bonzini     }
356*dd285b06SPaolo Bonzini }
357*dd285b06SPaolo Bonzini 
358*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_wd_timer_ops = {
359*dd285b06SPaolo Bonzini     .read = omap_wd_timer_read,
360*dd285b06SPaolo Bonzini     .write = omap_wd_timer_write,
361*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
362*dd285b06SPaolo Bonzini };
363*dd285b06SPaolo Bonzini 
364*dd285b06SPaolo Bonzini static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s)
365*dd285b06SPaolo Bonzini {
366*dd285b06SPaolo Bonzini     qemu_del_timer(s->timer.timer);
367*dd285b06SPaolo Bonzini     if (!s->mode)
368*dd285b06SPaolo Bonzini         omap_clk_get(s->timer.clk);
369*dd285b06SPaolo Bonzini     s->mode = 1;
370*dd285b06SPaolo Bonzini     s->free = 1;
371*dd285b06SPaolo Bonzini     s->reset = 0;
372*dd285b06SPaolo Bonzini     s->timer.enable = 1;
373*dd285b06SPaolo Bonzini     s->timer.it_ena = 1;
374*dd285b06SPaolo Bonzini     s->timer.reset_val = 0xffff;
375*dd285b06SPaolo Bonzini     s->timer.val = 0;
376*dd285b06SPaolo Bonzini     s->timer.st = 0;
377*dd285b06SPaolo Bonzini     s->timer.ptv = 0;
378*dd285b06SPaolo Bonzini     s->timer.ar = 0;
379*dd285b06SPaolo Bonzini     omap_timer_update(&s->timer);
380*dd285b06SPaolo Bonzini }
381*dd285b06SPaolo Bonzini 
382*dd285b06SPaolo Bonzini static struct omap_watchdog_timer_s *omap_wd_timer_init(MemoryRegion *memory,
383*dd285b06SPaolo Bonzini                 hwaddr base,
384*dd285b06SPaolo Bonzini                 qemu_irq irq, omap_clk clk)
385*dd285b06SPaolo Bonzini {
386*dd285b06SPaolo Bonzini     struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *)
387*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_watchdog_timer_s));
388*dd285b06SPaolo Bonzini 
389*dd285b06SPaolo Bonzini     s->timer.irq = irq;
390*dd285b06SPaolo Bonzini     s->timer.clk = clk;
391*dd285b06SPaolo Bonzini     s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer);
392*dd285b06SPaolo Bonzini     omap_wd_timer_reset(s);
393*dd285b06SPaolo Bonzini     omap_timer_clk_setup(&s->timer);
394*dd285b06SPaolo Bonzini 
395*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_wd_timer_ops, s,
396*dd285b06SPaolo Bonzini                           "omap-wd-timer", 0x100);
397*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, base, &s->iomem);
398*dd285b06SPaolo Bonzini 
399*dd285b06SPaolo Bonzini     return s;
400*dd285b06SPaolo Bonzini }
401*dd285b06SPaolo Bonzini 
402*dd285b06SPaolo Bonzini /* 32-kHz timer */
403*dd285b06SPaolo Bonzini struct omap_32khz_timer_s {
404*dd285b06SPaolo Bonzini     struct omap_mpu_timer_s timer;
405*dd285b06SPaolo Bonzini     MemoryRegion iomem;
406*dd285b06SPaolo Bonzini };
407*dd285b06SPaolo Bonzini 
408*dd285b06SPaolo Bonzini static uint64_t omap_os_timer_read(void *opaque, hwaddr addr,
409*dd285b06SPaolo Bonzini                                    unsigned size)
410*dd285b06SPaolo Bonzini {
411*dd285b06SPaolo Bonzini     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
412*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
413*dd285b06SPaolo Bonzini 
414*dd285b06SPaolo Bonzini     if (size != 4) {
415*dd285b06SPaolo Bonzini         return omap_badwidth_read32(opaque, addr);
416*dd285b06SPaolo Bonzini     }
417*dd285b06SPaolo Bonzini 
418*dd285b06SPaolo Bonzini     switch (offset) {
419*dd285b06SPaolo Bonzini     case 0x00:	/* TVR */
420*dd285b06SPaolo Bonzini         return s->timer.reset_val;
421*dd285b06SPaolo Bonzini 
422*dd285b06SPaolo Bonzini     case 0x04:	/* TCR */
423*dd285b06SPaolo Bonzini         return omap_timer_read(&s->timer);
424*dd285b06SPaolo Bonzini 
425*dd285b06SPaolo Bonzini     case 0x08:	/* CR */
426*dd285b06SPaolo Bonzini         return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st;
427*dd285b06SPaolo Bonzini 
428*dd285b06SPaolo Bonzini     default:
429*dd285b06SPaolo Bonzini         break;
430*dd285b06SPaolo Bonzini     }
431*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
432*dd285b06SPaolo Bonzini     return 0;
433*dd285b06SPaolo Bonzini }
434*dd285b06SPaolo Bonzini 
435*dd285b06SPaolo Bonzini static void omap_os_timer_write(void *opaque, hwaddr addr,
436*dd285b06SPaolo Bonzini                                 uint64_t value, unsigned size)
437*dd285b06SPaolo Bonzini {
438*dd285b06SPaolo Bonzini     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
439*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
440*dd285b06SPaolo Bonzini 
441*dd285b06SPaolo Bonzini     if (size != 4) {
442*dd285b06SPaolo Bonzini         return omap_badwidth_write32(opaque, addr, value);
443*dd285b06SPaolo Bonzini     }
444*dd285b06SPaolo Bonzini 
445*dd285b06SPaolo Bonzini     switch (offset) {
446*dd285b06SPaolo Bonzini     case 0x00:	/* TVR */
447*dd285b06SPaolo Bonzini         s->timer.reset_val = value & 0x00ffffff;
448*dd285b06SPaolo Bonzini         break;
449*dd285b06SPaolo Bonzini 
450*dd285b06SPaolo Bonzini     case 0x04:	/* TCR */
451*dd285b06SPaolo Bonzini         OMAP_RO_REG(addr);
452*dd285b06SPaolo Bonzini         break;
453*dd285b06SPaolo Bonzini 
454*dd285b06SPaolo Bonzini     case 0x08:	/* CR */
455*dd285b06SPaolo Bonzini         s->timer.ar = (value >> 3) & 1;
456*dd285b06SPaolo Bonzini         s->timer.it_ena = (value >> 2) & 1;
457*dd285b06SPaolo Bonzini         if (s->timer.st != (value & 1) || (value & 2)) {
458*dd285b06SPaolo Bonzini             omap_timer_sync(&s->timer);
459*dd285b06SPaolo Bonzini             s->timer.enable = value & 1;
460*dd285b06SPaolo Bonzini             s->timer.st = value & 1;
461*dd285b06SPaolo Bonzini             omap_timer_update(&s->timer);
462*dd285b06SPaolo Bonzini         }
463*dd285b06SPaolo Bonzini         break;
464*dd285b06SPaolo Bonzini 
465*dd285b06SPaolo Bonzini     default:
466*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
467*dd285b06SPaolo Bonzini     }
468*dd285b06SPaolo Bonzini }
469*dd285b06SPaolo Bonzini 
470*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_os_timer_ops = {
471*dd285b06SPaolo Bonzini     .read = omap_os_timer_read,
472*dd285b06SPaolo Bonzini     .write = omap_os_timer_write,
473*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
474*dd285b06SPaolo Bonzini };
475*dd285b06SPaolo Bonzini 
476*dd285b06SPaolo Bonzini static void omap_os_timer_reset(struct omap_32khz_timer_s *s)
477*dd285b06SPaolo Bonzini {
478*dd285b06SPaolo Bonzini     qemu_del_timer(s->timer.timer);
479*dd285b06SPaolo Bonzini     s->timer.enable = 0;
480*dd285b06SPaolo Bonzini     s->timer.it_ena = 0;
481*dd285b06SPaolo Bonzini     s->timer.reset_val = 0x00ffffff;
482*dd285b06SPaolo Bonzini     s->timer.val = 0;
483*dd285b06SPaolo Bonzini     s->timer.st = 0;
484*dd285b06SPaolo Bonzini     s->timer.ptv = 0;
485*dd285b06SPaolo Bonzini     s->timer.ar = 1;
486*dd285b06SPaolo Bonzini }
487*dd285b06SPaolo Bonzini 
488*dd285b06SPaolo Bonzini static struct omap_32khz_timer_s *omap_os_timer_init(MemoryRegion *memory,
489*dd285b06SPaolo Bonzini                 hwaddr base,
490*dd285b06SPaolo Bonzini                 qemu_irq irq, omap_clk clk)
491*dd285b06SPaolo Bonzini {
492*dd285b06SPaolo Bonzini     struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *)
493*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_32khz_timer_s));
494*dd285b06SPaolo Bonzini 
495*dd285b06SPaolo Bonzini     s->timer.irq = irq;
496*dd285b06SPaolo Bonzini     s->timer.clk = clk;
497*dd285b06SPaolo Bonzini     s->timer.timer = qemu_new_timer_ns(vm_clock, omap_timer_tick, &s->timer);
498*dd285b06SPaolo Bonzini     omap_os_timer_reset(s);
499*dd285b06SPaolo Bonzini     omap_timer_clk_setup(&s->timer);
500*dd285b06SPaolo Bonzini 
501*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_os_timer_ops, s,
502*dd285b06SPaolo Bonzini                           "omap-os-timer", 0x800);
503*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, base, &s->iomem);
504*dd285b06SPaolo Bonzini 
505*dd285b06SPaolo Bonzini     return s;
506*dd285b06SPaolo Bonzini }
507*dd285b06SPaolo Bonzini 
508*dd285b06SPaolo Bonzini /* Ultra Low-Power Device Module */
509*dd285b06SPaolo Bonzini static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr,
510*dd285b06SPaolo Bonzini                                   unsigned size)
511*dd285b06SPaolo Bonzini {
512*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
513*dd285b06SPaolo Bonzini     uint16_t ret;
514*dd285b06SPaolo Bonzini 
515*dd285b06SPaolo Bonzini     if (size != 2) {
516*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
517*dd285b06SPaolo Bonzini     }
518*dd285b06SPaolo Bonzini 
519*dd285b06SPaolo Bonzini     switch (addr) {
520*dd285b06SPaolo Bonzini     case 0x14:	/* IT_STATUS */
521*dd285b06SPaolo Bonzini         ret = s->ulpd_pm_regs[addr >> 2];
522*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] = 0;
523*dd285b06SPaolo Bonzini         qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
524*dd285b06SPaolo Bonzini         return ret;
525*dd285b06SPaolo Bonzini 
526*dd285b06SPaolo Bonzini     case 0x18:	/* Reserved */
527*dd285b06SPaolo Bonzini     case 0x1c:	/* Reserved */
528*dd285b06SPaolo Bonzini     case 0x20:	/* Reserved */
529*dd285b06SPaolo Bonzini     case 0x28:	/* Reserved */
530*dd285b06SPaolo Bonzini     case 0x2c:	/* Reserved */
531*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
532*dd285b06SPaolo Bonzini         /* fall through */
533*dd285b06SPaolo Bonzini     case 0x00:	/* COUNTER_32_LSB */
534*dd285b06SPaolo Bonzini     case 0x04:	/* COUNTER_32_MSB */
535*dd285b06SPaolo Bonzini     case 0x08:	/* COUNTER_HIGH_FREQ_LSB */
536*dd285b06SPaolo Bonzini     case 0x0c:	/* COUNTER_HIGH_FREQ_MSB */
537*dd285b06SPaolo Bonzini     case 0x10:	/* GAUGING_CTRL */
538*dd285b06SPaolo Bonzini     case 0x24:	/* SETUP_ANALOG_CELL3_ULPD1 */
539*dd285b06SPaolo Bonzini     case 0x30:	/* CLOCK_CTRL */
540*dd285b06SPaolo Bonzini     case 0x34:	/* SOFT_REQ */
541*dd285b06SPaolo Bonzini     case 0x38:	/* COUNTER_32_FIQ */
542*dd285b06SPaolo Bonzini     case 0x3c:	/* DPLL_CTRL */
543*dd285b06SPaolo Bonzini     case 0x40:	/* STATUS_REQ */
544*dd285b06SPaolo Bonzini         /* XXX: check clk::usecount state for every clock */
545*dd285b06SPaolo Bonzini     case 0x48:	/* LOCL_TIME */
546*dd285b06SPaolo Bonzini     case 0x4c:	/* APLL_CTRL */
547*dd285b06SPaolo Bonzini     case 0x50:	/* POWER_CTRL */
548*dd285b06SPaolo Bonzini         return s->ulpd_pm_regs[addr >> 2];
549*dd285b06SPaolo Bonzini     }
550*dd285b06SPaolo Bonzini 
551*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
552*dd285b06SPaolo Bonzini     return 0;
553*dd285b06SPaolo Bonzini }
554*dd285b06SPaolo Bonzini 
555*dd285b06SPaolo Bonzini static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s,
556*dd285b06SPaolo Bonzini                 uint16_t diff, uint16_t value)
557*dd285b06SPaolo Bonzini {
558*dd285b06SPaolo Bonzini     if (diff & (1 << 4))				/* USB_MCLK_EN */
559*dd285b06SPaolo Bonzini         omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1);
560*dd285b06SPaolo Bonzini     if (diff & (1 << 5))				/* DIS_USB_PVCI_CLK */
561*dd285b06SPaolo Bonzini         omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1);
562*dd285b06SPaolo Bonzini }
563*dd285b06SPaolo Bonzini 
564*dd285b06SPaolo Bonzini static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s,
565*dd285b06SPaolo Bonzini                 uint16_t diff, uint16_t value)
566*dd285b06SPaolo Bonzini {
567*dd285b06SPaolo Bonzini     if (diff & (1 << 0))				/* SOFT_DPLL_REQ */
568*dd285b06SPaolo Bonzini         omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1);
569*dd285b06SPaolo Bonzini     if (diff & (1 << 1))				/* SOFT_COM_REQ */
570*dd285b06SPaolo Bonzini         omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1);
571*dd285b06SPaolo Bonzini     if (diff & (1 << 2))				/* SOFT_SDW_REQ */
572*dd285b06SPaolo Bonzini         omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1);
573*dd285b06SPaolo Bonzini     if (diff & (1 << 3))				/* SOFT_USB_REQ */
574*dd285b06SPaolo Bonzini         omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1);
575*dd285b06SPaolo Bonzini }
576*dd285b06SPaolo Bonzini 
577*dd285b06SPaolo Bonzini static void omap_ulpd_pm_write(void *opaque, hwaddr addr,
578*dd285b06SPaolo Bonzini                                uint64_t value, unsigned size)
579*dd285b06SPaolo Bonzini {
580*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
581*dd285b06SPaolo Bonzini     int64_t now, ticks;
582*dd285b06SPaolo Bonzini     int div, mult;
583*dd285b06SPaolo Bonzini     static const int bypass_div[4] = { 1, 2, 4, 4 };
584*dd285b06SPaolo Bonzini     uint16_t diff;
585*dd285b06SPaolo Bonzini 
586*dd285b06SPaolo Bonzini     if (size != 2) {
587*dd285b06SPaolo Bonzini         return omap_badwidth_write16(opaque, addr, value);
588*dd285b06SPaolo Bonzini     }
589*dd285b06SPaolo Bonzini 
590*dd285b06SPaolo Bonzini     switch (addr) {
591*dd285b06SPaolo Bonzini     case 0x00:	/* COUNTER_32_LSB */
592*dd285b06SPaolo Bonzini     case 0x04:	/* COUNTER_32_MSB */
593*dd285b06SPaolo Bonzini     case 0x08:	/* COUNTER_HIGH_FREQ_LSB */
594*dd285b06SPaolo Bonzini     case 0x0c:	/* COUNTER_HIGH_FREQ_MSB */
595*dd285b06SPaolo Bonzini     case 0x14:	/* IT_STATUS */
596*dd285b06SPaolo Bonzini     case 0x40:	/* STATUS_REQ */
597*dd285b06SPaolo Bonzini         OMAP_RO_REG(addr);
598*dd285b06SPaolo Bonzini         break;
599*dd285b06SPaolo Bonzini 
600*dd285b06SPaolo Bonzini     case 0x10:	/* GAUGING_CTRL */
601*dd285b06SPaolo Bonzini         /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */
602*dd285b06SPaolo Bonzini         if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) {
603*dd285b06SPaolo Bonzini             now = qemu_get_clock_ns(vm_clock);
604*dd285b06SPaolo Bonzini 
605*dd285b06SPaolo Bonzini             if (value & 1)
606*dd285b06SPaolo Bonzini                 s->ulpd_gauge_start = now;
607*dd285b06SPaolo Bonzini             else {
608*dd285b06SPaolo Bonzini                 now -= s->ulpd_gauge_start;
609*dd285b06SPaolo Bonzini 
610*dd285b06SPaolo Bonzini                 /* 32-kHz ticks */
611*dd285b06SPaolo Bonzini                 ticks = muldiv64(now, 32768, get_ticks_per_sec());
612*dd285b06SPaolo Bonzini                 s->ulpd_pm_regs[0x00 >> 2] = (ticks >>  0) & 0xffff;
613*dd285b06SPaolo Bonzini                 s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff;
614*dd285b06SPaolo Bonzini                 if (ticks >> 32)	/* OVERFLOW_32K */
615*dd285b06SPaolo Bonzini                     s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2;
616*dd285b06SPaolo Bonzini 
617*dd285b06SPaolo Bonzini                 /* High frequency ticks */
618*dd285b06SPaolo Bonzini                 ticks = muldiv64(now, 12000000, get_ticks_per_sec());
619*dd285b06SPaolo Bonzini                 s->ulpd_pm_regs[0x08 >> 2] = (ticks >>  0) & 0xffff;
620*dd285b06SPaolo Bonzini                 s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff;
621*dd285b06SPaolo Bonzini                 if (ticks >> 32)	/* OVERFLOW_HI_FREQ */
622*dd285b06SPaolo Bonzini                     s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1;
623*dd285b06SPaolo Bonzini 
624*dd285b06SPaolo Bonzini                 s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0;	/* IT_GAUGING */
625*dd285b06SPaolo Bonzini                 qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K));
626*dd285b06SPaolo Bonzini             }
627*dd285b06SPaolo Bonzini         }
628*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] = value;
629*dd285b06SPaolo Bonzini         break;
630*dd285b06SPaolo Bonzini 
631*dd285b06SPaolo Bonzini     case 0x18:	/* Reserved */
632*dd285b06SPaolo Bonzini     case 0x1c:	/* Reserved */
633*dd285b06SPaolo Bonzini     case 0x20:	/* Reserved */
634*dd285b06SPaolo Bonzini     case 0x28:	/* Reserved */
635*dd285b06SPaolo Bonzini     case 0x2c:	/* Reserved */
636*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
637*dd285b06SPaolo Bonzini         /* fall through */
638*dd285b06SPaolo Bonzini     case 0x24:	/* SETUP_ANALOG_CELL3_ULPD1 */
639*dd285b06SPaolo Bonzini     case 0x38:	/* COUNTER_32_FIQ */
640*dd285b06SPaolo Bonzini     case 0x48:	/* LOCL_TIME */
641*dd285b06SPaolo Bonzini     case 0x50:	/* POWER_CTRL */
642*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] = value;
643*dd285b06SPaolo Bonzini         break;
644*dd285b06SPaolo Bonzini 
645*dd285b06SPaolo Bonzini     case 0x30:	/* CLOCK_CTRL */
646*dd285b06SPaolo Bonzini         diff = s->ulpd_pm_regs[addr >> 2] ^ value;
647*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] = value & 0x3f;
648*dd285b06SPaolo Bonzini         omap_ulpd_clk_update(s, diff, value);
649*dd285b06SPaolo Bonzini         break;
650*dd285b06SPaolo Bonzini 
651*dd285b06SPaolo Bonzini     case 0x34:	/* SOFT_REQ */
652*dd285b06SPaolo Bonzini         diff = s->ulpd_pm_regs[addr >> 2] ^ value;
653*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] = value & 0x1f;
654*dd285b06SPaolo Bonzini         omap_ulpd_req_update(s, diff, value);
655*dd285b06SPaolo Bonzini         break;
656*dd285b06SPaolo Bonzini 
657*dd285b06SPaolo Bonzini     case 0x3c:	/* DPLL_CTRL */
658*dd285b06SPaolo Bonzini         /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is
659*dd285b06SPaolo Bonzini          * omitted altogether, probably a typo.  */
660*dd285b06SPaolo Bonzini         /* This register has identical semantics with DPLL(1:3) control
661*dd285b06SPaolo Bonzini          * registers, see omap_dpll_write() */
662*dd285b06SPaolo Bonzini         diff = s->ulpd_pm_regs[addr >> 2] & value;
663*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] = value & 0x2fff;
664*dd285b06SPaolo Bonzini         if (diff & (0x3ff << 2)) {
665*dd285b06SPaolo Bonzini             if (value & (1 << 4)) {			/* PLL_ENABLE */
666*dd285b06SPaolo Bonzini                 div = ((value >> 5) & 3) + 1;		/* PLL_DIV */
667*dd285b06SPaolo Bonzini                 mult = MIN((value >> 7) & 0x1f, 1);	/* PLL_MULT */
668*dd285b06SPaolo Bonzini             } else {
669*dd285b06SPaolo Bonzini                 div = bypass_div[((value >> 2) & 3)];	/* BYPASS_DIV */
670*dd285b06SPaolo Bonzini                 mult = 1;
671*dd285b06SPaolo Bonzini             }
672*dd285b06SPaolo Bonzini             omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult);
673*dd285b06SPaolo Bonzini         }
674*dd285b06SPaolo Bonzini 
675*dd285b06SPaolo Bonzini         /* Enter the desired mode.  */
676*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] =
677*dd285b06SPaolo Bonzini                 (s->ulpd_pm_regs[addr >> 2] & 0xfffe) |
678*dd285b06SPaolo Bonzini                 ((s->ulpd_pm_regs[addr >> 2] >> 4) & 1);
679*dd285b06SPaolo Bonzini 
680*dd285b06SPaolo Bonzini         /* Act as if the lock is restored.  */
681*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] |= 2;
682*dd285b06SPaolo Bonzini         break;
683*dd285b06SPaolo Bonzini 
684*dd285b06SPaolo Bonzini     case 0x4c:	/* APLL_CTRL */
685*dd285b06SPaolo Bonzini         diff = s->ulpd_pm_regs[addr >> 2] & value;
686*dd285b06SPaolo Bonzini         s->ulpd_pm_regs[addr >> 2] = value & 0xf;
687*dd285b06SPaolo Bonzini         if (diff & (1 << 0))				/* APLL_NDPLL_SWITCH */
688*dd285b06SPaolo Bonzini             omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s,
689*dd285b06SPaolo Bonzini                                     (value & (1 << 0)) ? "apll" : "dpll4"));
690*dd285b06SPaolo Bonzini         break;
691*dd285b06SPaolo Bonzini 
692*dd285b06SPaolo Bonzini     default:
693*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
694*dd285b06SPaolo Bonzini     }
695*dd285b06SPaolo Bonzini }
696*dd285b06SPaolo Bonzini 
697*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_ulpd_pm_ops = {
698*dd285b06SPaolo Bonzini     .read = omap_ulpd_pm_read,
699*dd285b06SPaolo Bonzini     .write = omap_ulpd_pm_write,
700*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
701*dd285b06SPaolo Bonzini };
702*dd285b06SPaolo Bonzini 
703*dd285b06SPaolo Bonzini static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu)
704*dd285b06SPaolo Bonzini {
705*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001;
706*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000;
707*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001;
708*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000;
709*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000;
710*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x18 >> 2] = 0x01;
711*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x1c >> 2] = 0x01;
712*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x20 >> 2] = 0x01;
713*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff;
714*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x28 >> 2] = 0x01;
715*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x2c >> 2] = 0x01;
716*dd285b06SPaolo Bonzini     omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000);
717*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000;
718*dd285b06SPaolo Bonzini     omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000);
719*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000;
720*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001;
721*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211;
722*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */
723*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x48 >> 2] = 0x960;
724*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x4c >> 2] = 0x08;
725*dd285b06SPaolo Bonzini     mpu->ulpd_pm_regs[0x50 >> 2] = 0x08;
726*dd285b06SPaolo Bonzini     omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4);
727*dd285b06SPaolo Bonzini     omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4"));
728*dd285b06SPaolo Bonzini }
729*dd285b06SPaolo Bonzini 
730*dd285b06SPaolo Bonzini static void omap_ulpd_pm_init(MemoryRegion *system_memory,
731*dd285b06SPaolo Bonzini                 hwaddr base,
732*dd285b06SPaolo Bonzini                 struct omap_mpu_state_s *mpu)
733*dd285b06SPaolo Bonzini {
734*dd285b06SPaolo Bonzini     memory_region_init_io(&mpu->ulpd_pm_iomem, &omap_ulpd_pm_ops, mpu,
735*dd285b06SPaolo Bonzini                           "omap-ulpd-pm", 0x800);
736*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &mpu->ulpd_pm_iomem);
737*dd285b06SPaolo Bonzini     omap_ulpd_pm_reset(mpu);
738*dd285b06SPaolo Bonzini }
739*dd285b06SPaolo Bonzini 
740*dd285b06SPaolo Bonzini /* OMAP Pin Configuration */
741*dd285b06SPaolo Bonzini static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr,
742*dd285b06SPaolo Bonzini                                   unsigned size)
743*dd285b06SPaolo Bonzini {
744*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
745*dd285b06SPaolo Bonzini 
746*dd285b06SPaolo Bonzini     if (size != 4) {
747*dd285b06SPaolo Bonzini         return omap_badwidth_read32(opaque, addr);
748*dd285b06SPaolo Bonzini     }
749*dd285b06SPaolo Bonzini 
750*dd285b06SPaolo Bonzini     switch (addr) {
751*dd285b06SPaolo Bonzini     case 0x00:	/* FUNC_MUX_CTRL_0 */
752*dd285b06SPaolo Bonzini     case 0x04:	/* FUNC_MUX_CTRL_1 */
753*dd285b06SPaolo Bonzini     case 0x08:	/* FUNC_MUX_CTRL_2 */
754*dd285b06SPaolo Bonzini         return s->func_mux_ctrl[addr >> 2];
755*dd285b06SPaolo Bonzini 
756*dd285b06SPaolo Bonzini     case 0x0c:	/* COMP_MODE_CTRL_0 */
757*dd285b06SPaolo Bonzini         return s->comp_mode_ctrl[0];
758*dd285b06SPaolo Bonzini 
759*dd285b06SPaolo Bonzini     case 0x10:	/* FUNC_MUX_CTRL_3 */
760*dd285b06SPaolo Bonzini     case 0x14:	/* FUNC_MUX_CTRL_4 */
761*dd285b06SPaolo Bonzini     case 0x18:	/* FUNC_MUX_CTRL_5 */
762*dd285b06SPaolo Bonzini     case 0x1c:	/* FUNC_MUX_CTRL_6 */
763*dd285b06SPaolo Bonzini     case 0x20:	/* FUNC_MUX_CTRL_7 */
764*dd285b06SPaolo Bonzini     case 0x24:	/* FUNC_MUX_CTRL_8 */
765*dd285b06SPaolo Bonzini     case 0x28:	/* FUNC_MUX_CTRL_9 */
766*dd285b06SPaolo Bonzini     case 0x2c:	/* FUNC_MUX_CTRL_A */
767*dd285b06SPaolo Bonzini     case 0x30:	/* FUNC_MUX_CTRL_B */
768*dd285b06SPaolo Bonzini     case 0x34:	/* FUNC_MUX_CTRL_C */
769*dd285b06SPaolo Bonzini     case 0x38:	/* FUNC_MUX_CTRL_D */
770*dd285b06SPaolo Bonzini         return s->func_mux_ctrl[(addr >> 2) - 1];
771*dd285b06SPaolo Bonzini 
772*dd285b06SPaolo Bonzini     case 0x40:	/* PULL_DWN_CTRL_0 */
773*dd285b06SPaolo Bonzini     case 0x44:	/* PULL_DWN_CTRL_1 */
774*dd285b06SPaolo Bonzini     case 0x48:	/* PULL_DWN_CTRL_2 */
775*dd285b06SPaolo Bonzini     case 0x4c:	/* PULL_DWN_CTRL_3 */
776*dd285b06SPaolo Bonzini         return s->pull_dwn_ctrl[(addr & 0xf) >> 2];
777*dd285b06SPaolo Bonzini 
778*dd285b06SPaolo Bonzini     case 0x50:	/* GATE_INH_CTRL_0 */
779*dd285b06SPaolo Bonzini         return s->gate_inh_ctrl[0];
780*dd285b06SPaolo Bonzini 
781*dd285b06SPaolo Bonzini     case 0x60:	/* VOLTAGE_CTRL_0 */
782*dd285b06SPaolo Bonzini         return s->voltage_ctrl[0];
783*dd285b06SPaolo Bonzini 
784*dd285b06SPaolo Bonzini     case 0x70:	/* TEST_DBG_CTRL_0 */
785*dd285b06SPaolo Bonzini         return s->test_dbg_ctrl[0];
786*dd285b06SPaolo Bonzini 
787*dd285b06SPaolo Bonzini     case 0x80:	/* MOD_CONF_CTRL_0 */
788*dd285b06SPaolo Bonzini         return s->mod_conf_ctrl[0];
789*dd285b06SPaolo Bonzini     }
790*dd285b06SPaolo Bonzini 
791*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
792*dd285b06SPaolo Bonzini     return 0;
793*dd285b06SPaolo Bonzini }
794*dd285b06SPaolo Bonzini 
795*dd285b06SPaolo Bonzini static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s,
796*dd285b06SPaolo Bonzini                 uint32_t diff, uint32_t value)
797*dd285b06SPaolo Bonzini {
798*dd285b06SPaolo Bonzini     if (s->compat1509) {
799*dd285b06SPaolo Bonzini         if (diff & (1 << 9))			/* BLUETOOTH */
800*dd285b06SPaolo Bonzini             omap_clk_onoff(omap_findclk(s, "bt_mclk_out"),
801*dd285b06SPaolo Bonzini                             (~value >> 9) & 1);
802*dd285b06SPaolo Bonzini         if (diff & (1 << 7))			/* USB.CLKO */
803*dd285b06SPaolo Bonzini             omap_clk_onoff(omap_findclk(s, "usb.clko"),
804*dd285b06SPaolo Bonzini                             (value >> 7) & 1);
805*dd285b06SPaolo Bonzini     }
806*dd285b06SPaolo Bonzini }
807*dd285b06SPaolo Bonzini 
808*dd285b06SPaolo Bonzini static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s,
809*dd285b06SPaolo Bonzini                 uint32_t diff, uint32_t value)
810*dd285b06SPaolo Bonzini {
811*dd285b06SPaolo Bonzini     if (s->compat1509) {
812*dd285b06SPaolo Bonzini         if (diff & (1 << 31))			/* MCBSP3_CLK_HIZ_DI */
813*dd285b06SPaolo Bonzini             omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"),
814*dd285b06SPaolo Bonzini                             (value >> 31) & 1);
815*dd285b06SPaolo Bonzini         if (diff & (1 << 1))			/* CLK32K */
816*dd285b06SPaolo Bonzini             omap_clk_onoff(omap_findclk(s, "clk32k_out"),
817*dd285b06SPaolo Bonzini                             (~value >> 1) & 1);
818*dd285b06SPaolo Bonzini     }
819*dd285b06SPaolo Bonzini }
820*dd285b06SPaolo Bonzini 
821*dd285b06SPaolo Bonzini static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
822*dd285b06SPaolo Bonzini                 uint32_t diff, uint32_t value)
823*dd285b06SPaolo Bonzini {
824*dd285b06SPaolo Bonzini     if (diff & (1 << 31))			/* CONF_MOD_UART3_CLK_MODE_R */
825*dd285b06SPaolo Bonzini          omap_clk_reparent(omap_findclk(s, "uart3_ck"),
826*dd285b06SPaolo Bonzini                          omap_findclk(s, ((value >> 31) & 1) ?
827*dd285b06SPaolo Bonzini                                  "ck_48m" : "armper_ck"));
828*dd285b06SPaolo Bonzini     if (diff & (1 << 30))			/* CONF_MOD_UART2_CLK_MODE_R */
829*dd285b06SPaolo Bonzini          omap_clk_reparent(omap_findclk(s, "uart2_ck"),
830*dd285b06SPaolo Bonzini                          omap_findclk(s, ((value >> 30) & 1) ?
831*dd285b06SPaolo Bonzini                                  "ck_48m" : "armper_ck"));
832*dd285b06SPaolo Bonzini     if (diff & (1 << 29))			/* CONF_MOD_UART1_CLK_MODE_R */
833*dd285b06SPaolo Bonzini          omap_clk_reparent(omap_findclk(s, "uart1_ck"),
834*dd285b06SPaolo Bonzini                          omap_findclk(s, ((value >> 29) & 1) ?
835*dd285b06SPaolo Bonzini                                  "ck_48m" : "armper_ck"));
836*dd285b06SPaolo Bonzini     if (diff & (1 << 23))			/* CONF_MOD_MMC_SD_CLK_REQ_R */
837*dd285b06SPaolo Bonzini          omap_clk_reparent(omap_findclk(s, "mmc_ck"),
838*dd285b06SPaolo Bonzini                          omap_findclk(s, ((value >> 23) & 1) ?
839*dd285b06SPaolo Bonzini                                  "ck_48m" : "armper_ck"));
840*dd285b06SPaolo Bonzini     if (diff & (1 << 12))			/* CONF_MOD_COM_MCLK_12_48_S */
841*dd285b06SPaolo Bonzini          omap_clk_reparent(omap_findclk(s, "com_mclk_out"),
842*dd285b06SPaolo Bonzini                          omap_findclk(s, ((value >> 12) & 1) ?
843*dd285b06SPaolo Bonzini                                  "ck_48m" : "armper_ck"));
844*dd285b06SPaolo Bonzini     if (diff & (1 << 9))			/* CONF_MOD_USB_HOST_HHC_UHO */
845*dd285b06SPaolo Bonzini          omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1);
846*dd285b06SPaolo Bonzini }
847*dd285b06SPaolo Bonzini 
848*dd285b06SPaolo Bonzini static void omap_pin_cfg_write(void *opaque, hwaddr addr,
849*dd285b06SPaolo Bonzini                                uint64_t value, unsigned size)
850*dd285b06SPaolo Bonzini {
851*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
852*dd285b06SPaolo Bonzini     uint32_t diff;
853*dd285b06SPaolo Bonzini 
854*dd285b06SPaolo Bonzini     if (size != 4) {
855*dd285b06SPaolo Bonzini         return omap_badwidth_write32(opaque, addr, value);
856*dd285b06SPaolo Bonzini     }
857*dd285b06SPaolo Bonzini 
858*dd285b06SPaolo Bonzini     switch (addr) {
859*dd285b06SPaolo Bonzini     case 0x00:	/* FUNC_MUX_CTRL_0 */
860*dd285b06SPaolo Bonzini         diff = s->func_mux_ctrl[addr >> 2] ^ value;
861*dd285b06SPaolo Bonzini         s->func_mux_ctrl[addr >> 2] = value;
862*dd285b06SPaolo Bonzini         omap_pin_funcmux0_update(s, diff, value);
863*dd285b06SPaolo Bonzini         return;
864*dd285b06SPaolo Bonzini 
865*dd285b06SPaolo Bonzini     case 0x04:	/* FUNC_MUX_CTRL_1 */
866*dd285b06SPaolo Bonzini         diff = s->func_mux_ctrl[addr >> 2] ^ value;
867*dd285b06SPaolo Bonzini         s->func_mux_ctrl[addr >> 2] = value;
868*dd285b06SPaolo Bonzini         omap_pin_funcmux1_update(s, diff, value);
869*dd285b06SPaolo Bonzini         return;
870*dd285b06SPaolo Bonzini 
871*dd285b06SPaolo Bonzini     case 0x08:	/* FUNC_MUX_CTRL_2 */
872*dd285b06SPaolo Bonzini         s->func_mux_ctrl[addr >> 2] = value;
873*dd285b06SPaolo Bonzini         return;
874*dd285b06SPaolo Bonzini 
875*dd285b06SPaolo Bonzini     case 0x0c:	/* COMP_MODE_CTRL_0 */
876*dd285b06SPaolo Bonzini         s->comp_mode_ctrl[0] = value;
877*dd285b06SPaolo Bonzini         s->compat1509 = (value != 0x0000eaef);
878*dd285b06SPaolo Bonzini         omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]);
879*dd285b06SPaolo Bonzini         omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]);
880*dd285b06SPaolo Bonzini         return;
881*dd285b06SPaolo Bonzini 
882*dd285b06SPaolo Bonzini     case 0x10:	/* FUNC_MUX_CTRL_3 */
883*dd285b06SPaolo Bonzini     case 0x14:	/* FUNC_MUX_CTRL_4 */
884*dd285b06SPaolo Bonzini     case 0x18:	/* FUNC_MUX_CTRL_5 */
885*dd285b06SPaolo Bonzini     case 0x1c:	/* FUNC_MUX_CTRL_6 */
886*dd285b06SPaolo Bonzini     case 0x20:	/* FUNC_MUX_CTRL_7 */
887*dd285b06SPaolo Bonzini     case 0x24:	/* FUNC_MUX_CTRL_8 */
888*dd285b06SPaolo Bonzini     case 0x28:	/* FUNC_MUX_CTRL_9 */
889*dd285b06SPaolo Bonzini     case 0x2c:	/* FUNC_MUX_CTRL_A */
890*dd285b06SPaolo Bonzini     case 0x30:	/* FUNC_MUX_CTRL_B */
891*dd285b06SPaolo Bonzini     case 0x34:	/* FUNC_MUX_CTRL_C */
892*dd285b06SPaolo Bonzini     case 0x38:	/* FUNC_MUX_CTRL_D */
893*dd285b06SPaolo Bonzini         s->func_mux_ctrl[(addr >> 2) - 1] = value;
894*dd285b06SPaolo Bonzini         return;
895*dd285b06SPaolo Bonzini 
896*dd285b06SPaolo Bonzini     case 0x40:	/* PULL_DWN_CTRL_0 */
897*dd285b06SPaolo Bonzini     case 0x44:	/* PULL_DWN_CTRL_1 */
898*dd285b06SPaolo Bonzini     case 0x48:	/* PULL_DWN_CTRL_2 */
899*dd285b06SPaolo Bonzini     case 0x4c:	/* PULL_DWN_CTRL_3 */
900*dd285b06SPaolo Bonzini         s->pull_dwn_ctrl[(addr & 0xf) >> 2] = value;
901*dd285b06SPaolo Bonzini         return;
902*dd285b06SPaolo Bonzini 
903*dd285b06SPaolo Bonzini     case 0x50:	/* GATE_INH_CTRL_0 */
904*dd285b06SPaolo Bonzini         s->gate_inh_ctrl[0] = value;
905*dd285b06SPaolo Bonzini         return;
906*dd285b06SPaolo Bonzini 
907*dd285b06SPaolo Bonzini     case 0x60:	/* VOLTAGE_CTRL_0 */
908*dd285b06SPaolo Bonzini         s->voltage_ctrl[0] = value;
909*dd285b06SPaolo Bonzini         return;
910*dd285b06SPaolo Bonzini 
911*dd285b06SPaolo Bonzini     case 0x70:	/* TEST_DBG_CTRL_0 */
912*dd285b06SPaolo Bonzini         s->test_dbg_ctrl[0] = value;
913*dd285b06SPaolo Bonzini         return;
914*dd285b06SPaolo Bonzini 
915*dd285b06SPaolo Bonzini     case 0x80:	/* MOD_CONF_CTRL_0 */
916*dd285b06SPaolo Bonzini         diff = s->mod_conf_ctrl[0] ^ value;
917*dd285b06SPaolo Bonzini         s->mod_conf_ctrl[0] = value;
918*dd285b06SPaolo Bonzini         omap_pin_modconf1_update(s, diff, value);
919*dd285b06SPaolo Bonzini         return;
920*dd285b06SPaolo Bonzini 
921*dd285b06SPaolo Bonzini     default:
922*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
923*dd285b06SPaolo Bonzini     }
924*dd285b06SPaolo Bonzini }
925*dd285b06SPaolo Bonzini 
926*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_pin_cfg_ops = {
927*dd285b06SPaolo Bonzini     .read = omap_pin_cfg_read,
928*dd285b06SPaolo Bonzini     .write = omap_pin_cfg_write,
929*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
930*dd285b06SPaolo Bonzini };
931*dd285b06SPaolo Bonzini 
932*dd285b06SPaolo Bonzini static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu)
933*dd285b06SPaolo Bonzini {
934*dd285b06SPaolo Bonzini     /* Start in Compatibility Mode.  */
935*dd285b06SPaolo Bonzini     mpu->compat1509 = 1;
936*dd285b06SPaolo Bonzini     omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0);
937*dd285b06SPaolo Bonzini     omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0);
938*dd285b06SPaolo Bonzini     omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0);
939*dd285b06SPaolo Bonzini     memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl));
940*dd285b06SPaolo Bonzini     memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl));
941*dd285b06SPaolo Bonzini     memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl));
942*dd285b06SPaolo Bonzini     memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl));
943*dd285b06SPaolo Bonzini     memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl));
944*dd285b06SPaolo Bonzini     memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl));
945*dd285b06SPaolo Bonzini     memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl));
946*dd285b06SPaolo Bonzini }
947*dd285b06SPaolo Bonzini 
948*dd285b06SPaolo Bonzini static void omap_pin_cfg_init(MemoryRegion *system_memory,
949*dd285b06SPaolo Bonzini                 hwaddr base,
950*dd285b06SPaolo Bonzini                 struct omap_mpu_state_s *mpu)
951*dd285b06SPaolo Bonzini {
952*dd285b06SPaolo Bonzini     memory_region_init_io(&mpu->pin_cfg_iomem, &omap_pin_cfg_ops, mpu,
953*dd285b06SPaolo Bonzini                           "omap-pin-cfg", 0x800);
954*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &mpu->pin_cfg_iomem);
955*dd285b06SPaolo Bonzini     omap_pin_cfg_reset(mpu);
956*dd285b06SPaolo Bonzini }
957*dd285b06SPaolo Bonzini 
958*dd285b06SPaolo Bonzini /* Device Identification, Die Identification */
959*dd285b06SPaolo Bonzini static uint64_t omap_id_read(void *opaque, hwaddr addr,
960*dd285b06SPaolo Bonzini                              unsigned size)
961*dd285b06SPaolo Bonzini {
962*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
963*dd285b06SPaolo Bonzini 
964*dd285b06SPaolo Bonzini     if (size != 4) {
965*dd285b06SPaolo Bonzini         return omap_badwidth_read32(opaque, addr);
966*dd285b06SPaolo Bonzini     }
967*dd285b06SPaolo Bonzini 
968*dd285b06SPaolo Bonzini     switch (addr) {
969*dd285b06SPaolo Bonzini     case 0xfffe1800:	/* DIE_ID_LSB */
970*dd285b06SPaolo Bonzini         return 0xc9581f0e;
971*dd285b06SPaolo Bonzini     case 0xfffe1804:	/* DIE_ID_MSB */
972*dd285b06SPaolo Bonzini         return 0xa8858bfa;
973*dd285b06SPaolo Bonzini 
974*dd285b06SPaolo Bonzini     case 0xfffe2000:	/* PRODUCT_ID_LSB */
975*dd285b06SPaolo Bonzini         return 0x00aaaafc;
976*dd285b06SPaolo Bonzini     case 0xfffe2004:	/* PRODUCT_ID_MSB */
977*dd285b06SPaolo Bonzini         return 0xcafeb574;
978*dd285b06SPaolo Bonzini 
979*dd285b06SPaolo Bonzini     case 0xfffed400:	/* JTAG_ID_LSB */
980*dd285b06SPaolo Bonzini         switch (s->mpu_model) {
981*dd285b06SPaolo Bonzini         case omap310:
982*dd285b06SPaolo Bonzini             return 0x03310315;
983*dd285b06SPaolo Bonzini         case omap1510:
984*dd285b06SPaolo Bonzini             return 0x03310115;
985*dd285b06SPaolo Bonzini         default:
986*dd285b06SPaolo Bonzini             hw_error("%s: bad mpu model\n", __FUNCTION__);
987*dd285b06SPaolo Bonzini         }
988*dd285b06SPaolo Bonzini         break;
989*dd285b06SPaolo Bonzini 
990*dd285b06SPaolo Bonzini     case 0xfffed404:	/* JTAG_ID_MSB */
991*dd285b06SPaolo Bonzini         switch (s->mpu_model) {
992*dd285b06SPaolo Bonzini         case omap310:
993*dd285b06SPaolo Bonzini             return 0xfb57402f;
994*dd285b06SPaolo Bonzini         case omap1510:
995*dd285b06SPaolo Bonzini             return 0xfb47002f;
996*dd285b06SPaolo Bonzini         default:
997*dd285b06SPaolo Bonzini             hw_error("%s: bad mpu model\n", __FUNCTION__);
998*dd285b06SPaolo Bonzini         }
999*dd285b06SPaolo Bonzini         break;
1000*dd285b06SPaolo Bonzini     }
1001*dd285b06SPaolo Bonzini 
1002*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1003*dd285b06SPaolo Bonzini     return 0;
1004*dd285b06SPaolo Bonzini }
1005*dd285b06SPaolo Bonzini 
1006*dd285b06SPaolo Bonzini static void omap_id_write(void *opaque, hwaddr addr,
1007*dd285b06SPaolo Bonzini                           uint64_t value, unsigned size)
1008*dd285b06SPaolo Bonzini {
1009*dd285b06SPaolo Bonzini     if (size != 4) {
1010*dd285b06SPaolo Bonzini         return omap_badwidth_write32(opaque, addr, value);
1011*dd285b06SPaolo Bonzini     }
1012*dd285b06SPaolo Bonzini 
1013*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1014*dd285b06SPaolo Bonzini }
1015*dd285b06SPaolo Bonzini 
1016*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_id_ops = {
1017*dd285b06SPaolo Bonzini     .read = omap_id_read,
1018*dd285b06SPaolo Bonzini     .write = omap_id_write,
1019*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1020*dd285b06SPaolo Bonzini };
1021*dd285b06SPaolo Bonzini 
1022*dd285b06SPaolo Bonzini static void omap_id_init(MemoryRegion *memory, struct omap_mpu_state_s *mpu)
1023*dd285b06SPaolo Bonzini {
1024*dd285b06SPaolo Bonzini     memory_region_init_io(&mpu->id_iomem, &omap_id_ops, mpu,
1025*dd285b06SPaolo Bonzini                           "omap-id", 0x100000000ULL);
1026*dd285b06SPaolo Bonzini     memory_region_init_alias(&mpu->id_iomem_e18, "omap-id-e18", &mpu->id_iomem,
1027*dd285b06SPaolo Bonzini                              0xfffe1800, 0x800);
1028*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, 0xfffe1800, &mpu->id_iomem_e18);
1029*dd285b06SPaolo Bonzini     memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-ed4", &mpu->id_iomem,
1030*dd285b06SPaolo Bonzini                              0xfffed400, 0x100);
1031*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, 0xfffed400, &mpu->id_iomem_ed4);
1032*dd285b06SPaolo Bonzini     if (!cpu_is_omap15xx(mpu)) {
1033*dd285b06SPaolo Bonzini         memory_region_init_alias(&mpu->id_iomem_ed4, "omap-id-e20",
1034*dd285b06SPaolo Bonzini                                  &mpu->id_iomem, 0xfffe2000, 0x800);
1035*dd285b06SPaolo Bonzini         memory_region_add_subregion(memory, 0xfffe2000, &mpu->id_iomem_e20);
1036*dd285b06SPaolo Bonzini     }
1037*dd285b06SPaolo Bonzini }
1038*dd285b06SPaolo Bonzini 
1039*dd285b06SPaolo Bonzini /* MPUI Control (Dummy) */
1040*dd285b06SPaolo Bonzini static uint64_t omap_mpui_read(void *opaque, hwaddr addr,
1041*dd285b06SPaolo Bonzini                                unsigned size)
1042*dd285b06SPaolo Bonzini {
1043*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
1044*dd285b06SPaolo Bonzini 
1045*dd285b06SPaolo Bonzini     if (size != 4) {
1046*dd285b06SPaolo Bonzini         return omap_badwidth_read32(opaque, addr);
1047*dd285b06SPaolo Bonzini     }
1048*dd285b06SPaolo Bonzini 
1049*dd285b06SPaolo Bonzini     switch (addr) {
1050*dd285b06SPaolo Bonzini     case 0x00:	/* CTRL */
1051*dd285b06SPaolo Bonzini         return s->mpui_ctrl;
1052*dd285b06SPaolo Bonzini     case 0x04:	/* DEBUG_ADDR */
1053*dd285b06SPaolo Bonzini         return 0x01ffffff;
1054*dd285b06SPaolo Bonzini     case 0x08:	/* DEBUG_DATA */
1055*dd285b06SPaolo Bonzini         return 0xffffffff;
1056*dd285b06SPaolo Bonzini     case 0x0c:	/* DEBUG_FLAG */
1057*dd285b06SPaolo Bonzini         return 0x00000800;
1058*dd285b06SPaolo Bonzini     case 0x10:	/* STATUS */
1059*dd285b06SPaolo Bonzini         return 0x00000000;
1060*dd285b06SPaolo Bonzini 
1061*dd285b06SPaolo Bonzini     /* Not in OMAP310 */
1062*dd285b06SPaolo Bonzini     case 0x14:	/* DSP_STATUS */
1063*dd285b06SPaolo Bonzini     case 0x18:	/* DSP_BOOT_CONFIG */
1064*dd285b06SPaolo Bonzini         return 0x00000000;
1065*dd285b06SPaolo Bonzini     case 0x1c:	/* DSP_MPUI_CONFIG */
1066*dd285b06SPaolo Bonzini         return 0x0000ffff;
1067*dd285b06SPaolo Bonzini     }
1068*dd285b06SPaolo Bonzini 
1069*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1070*dd285b06SPaolo Bonzini     return 0;
1071*dd285b06SPaolo Bonzini }
1072*dd285b06SPaolo Bonzini 
1073*dd285b06SPaolo Bonzini static void omap_mpui_write(void *opaque, hwaddr addr,
1074*dd285b06SPaolo Bonzini                             uint64_t value, unsigned size)
1075*dd285b06SPaolo Bonzini {
1076*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
1077*dd285b06SPaolo Bonzini 
1078*dd285b06SPaolo Bonzini     if (size != 4) {
1079*dd285b06SPaolo Bonzini         return omap_badwidth_write32(opaque, addr, value);
1080*dd285b06SPaolo Bonzini     }
1081*dd285b06SPaolo Bonzini 
1082*dd285b06SPaolo Bonzini     switch (addr) {
1083*dd285b06SPaolo Bonzini     case 0x00:	/* CTRL */
1084*dd285b06SPaolo Bonzini         s->mpui_ctrl = value & 0x007fffff;
1085*dd285b06SPaolo Bonzini         break;
1086*dd285b06SPaolo Bonzini 
1087*dd285b06SPaolo Bonzini     case 0x04:	/* DEBUG_ADDR */
1088*dd285b06SPaolo Bonzini     case 0x08:	/* DEBUG_DATA */
1089*dd285b06SPaolo Bonzini     case 0x0c:	/* DEBUG_FLAG */
1090*dd285b06SPaolo Bonzini     case 0x10:	/* STATUS */
1091*dd285b06SPaolo Bonzini     /* Not in OMAP310 */
1092*dd285b06SPaolo Bonzini     case 0x14:	/* DSP_STATUS */
1093*dd285b06SPaolo Bonzini         OMAP_RO_REG(addr);
1094*dd285b06SPaolo Bonzini         break;
1095*dd285b06SPaolo Bonzini     case 0x18:	/* DSP_BOOT_CONFIG */
1096*dd285b06SPaolo Bonzini     case 0x1c:	/* DSP_MPUI_CONFIG */
1097*dd285b06SPaolo Bonzini         break;
1098*dd285b06SPaolo Bonzini 
1099*dd285b06SPaolo Bonzini     default:
1100*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
1101*dd285b06SPaolo Bonzini     }
1102*dd285b06SPaolo Bonzini }
1103*dd285b06SPaolo Bonzini 
1104*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_mpui_ops = {
1105*dd285b06SPaolo Bonzini     .read = omap_mpui_read,
1106*dd285b06SPaolo Bonzini     .write = omap_mpui_write,
1107*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1108*dd285b06SPaolo Bonzini };
1109*dd285b06SPaolo Bonzini 
1110*dd285b06SPaolo Bonzini static void omap_mpui_reset(struct omap_mpu_state_s *s)
1111*dd285b06SPaolo Bonzini {
1112*dd285b06SPaolo Bonzini     s->mpui_ctrl = 0x0003ff1b;
1113*dd285b06SPaolo Bonzini }
1114*dd285b06SPaolo Bonzini 
1115*dd285b06SPaolo Bonzini static void omap_mpui_init(MemoryRegion *memory, hwaddr base,
1116*dd285b06SPaolo Bonzini                 struct omap_mpu_state_s *mpu)
1117*dd285b06SPaolo Bonzini {
1118*dd285b06SPaolo Bonzini     memory_region_init_io(&mpu->mpui_iomem, &omap_mpui_ops, mpu,
1119*dd285b06SPaolo Bonzini                           "omap-mpui", 0x100);
1120*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, base, &mpu->mpui_iomem);
1121*dd285b06SPaolo Bonzini 
1122*dd285b06SPaolo Bonzini     omap_mpui_reset(mpu);
1123*dd285b06SPaolo Bonzini }
1124*dd285b06SPaolo Bonzini 
1125*dd285b06SPaolo Bonzini /* TIPB Bridges */
1126*dd285b06SPaolo Bonzini struct omap_tipb_bridge_s {
1127*dd285b06SPaolo Bonzini     qemu_irq abort;
1128*dd285b06SPaolo Bonzini     MemoryRegion iomem;
1129*dd285b06SPaolo Bonzini 
1130*dd285b06SPaolo Bonzini     int width_intr;
1131*dd285b06SPaolo Bonzini     uint16_t control;
1132*dd285b06SPaolo Bonzini     uint16_t alloc;
1133*dd285b06SPaolo Bonzini     uint16_t buffer;
1134*dd285b06SPaolo Bonzini     uint16_t enh_control;
1135*dd285b06SPaolo Bonzini };
1136*dd285b06SPaolo Bonzini 
1137*dd285b06SPaolo Bonzini static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr,
1138*dd285b06SPaolo Bonzini                                       unsigned size)
1139*dd285b06SPaolo Bonzini {
1140*dd285b06SPaolo Bonzini     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
1141*dd285b06SPaolo Bonzini 
1142*dd285b06SPaolo Bonzini     if (size < 2) {
1143*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
1144*dd285b06SPaolo Bonzini     }
1145*dd285b06SPaolo Bonzini 
1146*dd285b06SPaolo Bonzini     switch (addr) {
1147*dd285b06SPaolo Bonzini     case 0x00:	/* TIPB_CNTL */
1148*dd285b06SPaolo Bonzini         return s->control;
1149*dd285b06SPaolo Bonzini     case 0x04:	/* TIPB_BUS_ALLOC */
1150*dd285b06SPaolo Bonzini         return s->alloc;
1151*dd285b06SPaolo Bonzini     case 0x08:	/* MPU_TIPB_CNTL */
1152*dd285b06SPaolo Bonzini         return s->buffer;
1153*dd285b06SPaolo Bonzini     case 0x0c:	/* ENHANCED_TIPB_CNTL */
1154*dd285b06SPaolo Bonzini         return s->enh_control;
1155*dd285b06SPaolo Bonzini     case 0x10:	/* ADDRESS_DBG */
1156*dd285b06SPaolo Bonzini     case 0x14:	/* DATA_DEBUG_LOW */
1157*dd285b06SPaolo Bonzini     case 0x18:	/* DATA_DEBUG_HIGH */
1158*dd285b06SPaolo Bonzini         return 0xffff;
1159*dd285b06SPaolo Bonzini     case 0x1c:	/* DEBUG_CNTR_SIG */
1160*dd285b06SPaolo Bonzini         return 0x00f8;
1161*dd285b06SPaolo Bonzini     }
1162*dd285b06SPaolo Bonzini 
1163*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1164*dd285b06SPaolo Bonzini     return 0;
1165*dd285b06SPaolo Bonzini }
1166*dd285b06SPaolo Bonzini 
1167*dd285b06SPaolo Bonzini static void omap_tipb_bridge_write(void *opaque, hwaddr addr,
1168*dd285b06SPaolo Bonzini                                    uint64_t value, unsigned size)
1169*dd285b06SPaolo Bonzini {
1170*dd285b06SPaolo Bonzini     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
1171*dd285b06SPaolo Bonzini 
1172*dd285b06SPaolo Bonzini     if (size < 2) {
1173*dd285b06SPaolo Bonzini         return omap_badwidth_write16(opaque, addr, value);
1174*dd285b06SPaolo Bonzini     }
1175*dd285b06SPaolo Bonzini 
1176*dd285b06SPaolo Bonzini     switch (addr) {
1177*dd285b06SPaolo Bonzini     case 0x00:	/* TIPB_CNTL */
1178*dd285b06SPaolo Bonzini         s->control = value & 0xffff;
1179*dd285b06SPaolo Bonzini         break;
1180*dd285b06SPaolo Bonzini 
1181*dd285b06SPaolo Bonzini     case 0x04:	/* TIPB_BUS_ALLOC */
1182*dd285b06SPaolo Bonzini         s->alloc = value & 0x003f;
1183*dd285b06SPaolo Bonzini         break;
1184*dd285b06SPaolo Bonzini 
1185*dd285b06SPaolo Bonzini     case 0x08:	/* MPU_TIPB_CNTL */
1186*dd285b06SPaolo Bonzini         s->buffer = value & 0x0003;
1187*dd285b06SPaolo Bonzini         break;
1188*dd285b06SPaolo Bonzini 
1189*dd285b06SPaolo Bonzini     case 0x0c:	/* ENHANCED_TIPB_CNTL */
1190*dd285b06SPaolo Bonzini         s->width_intr = !(value & 2);
1191*dd285b06SPaolo Bonzini         s->enh_control = value & 0x000f;
1192*dd285b06SPaolo Bonzini         break;
1193*dd285b06SPaolo Bonzini 
1194*dd285b06SPaolo Bonzini     case 0x10:	/* ADDRESS_DBG */
1195*dd285b06SPaolo Bonzini     case 0x14:	/* DATA_DEBUG_LOW */
1196*dd285b06SPaolo Bonzini     case 0x18:	/* DATA_DEBUG_HIGH */
1197*dd285b06SPaolo Bonzini     case 0x1c:	/* DEBUG_CNTR_SIG */
1198*dd285b06SPaolo Bonzini         OMAP_RO_REG(addr);
1199*dd285b06SPaolo Bonzini         break;
1200*dd285b06SPaolo Bonzini 
1201*dd285b06SPaolo Bonzini     default:
1202*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
1203*dd285b06SPaolo Bonzini     }
1204*dd285b06SPaolo Bonzini }
1205*dd285b06SPaolo Bonzini 
1206*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_tipb_bridge_ops = {
1207*dd285b06SPaolo Bonzini     .read = omap_tipb_bridge_read,
1208*dd285b06SPaolo Bonzini     .write = omap_tipb_bridge_write,
1209*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1210*dd285b06SPaolo Bonzini };
1211*dd285b06SPaolo Bonzini 
1212*dd285b06SPaolo Bonzini static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s)
1213*dd285b06SPaolo Bonzini {
1214*dd285b06SPaolo Bonzini     s->control = 0xffff;
1215*dd285b06SPaolo Bonzini     s->alloc = 0x0009;
1216*dd285b06SPaolo Bonzini     s->buffer = 0x0000;
1217*dd285b06SPaolo Bonzini     s->enh_control = 0x000f;
1218*dd285b06SPaolo Bonzini }
1219*dd285b06SPaolo Bonzini 
1220*dd285b06SPaolo Bonzini static struct omap_tipb_bridge_s *omap_tipb_bridge_init(
1221*dd285b06SPaolo Bonzini     MemoryRegion *memory, hwaddr base,
1222*dd285b06SPaolo Bonzini     qemu_irq abort_irq, omap_clk clk)
1223*dd285b06SPaolo Bonzini {
1224*dd285b06SPaolo Bonzini     struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *)
1225*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_tipb_bridge_s));
1226*dd285b06SPaolo Bonzini 
1227*dd285b06SPaolo Bonzini     s->abort = abort_irq;
1228*dd285b06SPaolo Bonzini     omap_tipb_bridge_reset(s);
1229*dd285b06SPaolo Bonzini 
1230*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_tipb_bridge_ops, s,
1231*dd285b06SPaolo Bonzini                           "omap-tipb-bridge", 0x100);
1232*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, base, &s->iomem);
1233*dd285b06SPaolo Bonzini 
1234*dd285b06SPaolo Bonzini     return s;
1235*dd285b06SPaolo Bonzini }
1236*dd285b06SPaolo Bonzini 
1237*dd285b06SPaolo Bonzini /* Dummy Traffic Controller's Memory Interface */
1238*dd285b06SPaolo Bonzini static uint64_t omap_tcmi_read(void *opaque, hwaddr addr,
1239*dd285b06SPaolo Bonzini                                unsigned size)
1240*dd285b06SPaolo Bonzini {
1241*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
1242*dd285b06SPaolo Bonzini     uint32_t ret;
1243*dd285b06SPaolo Bonzini 
1244*dd285b06SPaolo Bonzini     if (size != 4) {
1245*dd285b06SPaolo Bonzini         return omap_badwidth_read32(opaque, addr);
1246*dd285b06SPaolo Bonzini     }
1247*dd285b06SPaolo Bonzini 
1248*dd285b06SPaolo Bonzini     switch (addr) {
1249*dd285b06SPaolo Bonzini     case 0x00:	/* IMIF_PRIO */
1250*dd285b06SPaolo Bonzini     case 0x04:	/* EMIFS_PRIO */
1251*dd285b06SPaolo Bonzini     case 0x08:	/* EMIFF_PRIO */
1252*dd285b06SPaolo Bonzini     case 0x0c:	/* EMIFS_CONFIG */
1253*dd285b06SPaolo Bonzini     case 0x10:	/* EMIFS_CS0_CONFIG */
1254*dd285b06SPaolo Bonzini     case 0x14:	/* EMIFS_CS1_CONFIG */
1255*dd285b06SPaolo Bonzini     case 0x18:	/* EMIFS_CS2_CONFIG */
1256*dd285b06SPaolo Bonzini     case 0x1c:	/* EMIFS_CS3_CONFIG */
1257*dd285b06SPaolo Bonzini     case 0x24:	/* EMIFF_MRS */
1258*dd285b06SPaolo Bonzini     case 0x28:	/* TIMEOUT1 */
1259*dd285b06SPaolo Bonzini     case 0x2c:	/* TIMEOUT2 */
1260*dd285b06SPaolo Bonzini     case 0x30:	/* TIMEOUT3 */
1261*dd285b06SPaolo Bonzini     case 0x3c:	/* EMIFF_SDRAM_CONFIG_2 */
1262*dd285b06SPaolo Bonzini     case 0x40:	/* EMIFS_CFG_DYN_WAIT */
1263*dd285b06SPaolo Bonzini         return s->tcmi_regs[addr >> 2];
1264*dd285b06SPaolo Bonzini 
1265*dd285b06SPaolo Bonzini     case 0x20:	/* EMIFF_SDRAM_CONFIG */
1266*dd285b06SPaolo Bonzini         ret = s->tcmi_regs[addr >> 2];
1267*dd285b06SPaolo Bonzini         s->tcmi_regs[addr >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */
1268*dd285b06SPaolo Bonzini         /* XXX: We can try using the VGA_DIRTY flag for this */
1269*dd285b06SPaolo Bonzini         return ret;
1270*dd285b06SPaolo Bonzini     }
1271*dd285b06SPaolo Bonzini 
1272*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1273*dd285b06SPaolo Bonzini     return 0;
1274*dd285b06SPaolo Bonzini }
1275*dd285b06SPaolo Bonzini 
1276*dd285b06SPaolo Bonzini static void omap_tcmi_write(void *opaque, hwaddr addr,
1277*dd285b06SPaolo Bonzini                             uint64_t value, unsigned size)
1278*dd285b06SPaolo Bonzini {
1279*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
1280*dd285b06SPaolo Bonzini 
1281*dd285b06SPaolo Bonzini     if (size != 4) {
1282*dd285b06SPaolo Bonzini         return omap_badwidth_write32(opaque, addr, value);
1283*dd285b06SPaolo Bonzini     }
1284*dd285b06SPaolo Bonzini 
1285*dd285b06SPaolo Bonzini     switch (addr) {
1286*dd285b06SPaolo Bonzini     case 0x00:	/* IMIF_PRIO */
1287*dd285b06SPaolo Bonzini     case 0x04:	/* EMIFS_PRIO */
1288*dd285b06SPaolo Bonzini     case 0x08:	/* EMIFF_PRIO */
1289*dd285b06SPaolo Bonzini     case 0x10:	/* EMIFS_CS0_CONFIG */
1290*dd285b06SPaolo Bonzini     case 0x14:	/* EMIFS_CS1_CONFIG */
1291*dd285b06SPaolo Bonzini     case 0x18:	/* EMIFS_CS2_CONFIG */
1292*dd285b06SPaolo Bonzini     case 0x1c:	/* EMIFS_CS3_CONFIG */
1293*dd285b06SPaolo Bonzini     case 0x20:	/* EMIFF_SDRAM_CONFIG */
1294*dd285b06SPaolo Bonzini     case 0x24:	/* EMIFF_MRS */
1295*dd285b06SPaolo Bonzini     case 0x28:	/* TIMEOUT1 */
1296*dd285b06SPaolo Bonzini     case 0x2c:	/* TIMEOUT2 */
1297*dd285b06SPaolo Bonzini     case 0x30:	/* TIMEOUT3 */
1298*dd285b06SPaolo Bonzini     case 0x3c:	/* EMIFF_SDRAM_CONFIG_2 */
1299*dd285b06SPaolo Bonzini     case 0x40:	/* EMIFS_CFG_DYN_WAIT */
1300*dd285b06SPaolo Bonzini         s->tcmi_regs[addr >> 2] = value;
1301*dd285b06SPaolo Bonzini         break;
1302*dd285b06SPaolo Bonzini     case 0x0c:	/* EMIFS_CONFIG */
1303*dd285b06SPaolo Bonzini         s->tcmi_regs[addr >> 2] = (value & 0xf) | (1 << 4);
1304*dd285b06SPaolo Bonzini         break;
1305*dd285b06SPaolo Bonzini 
1306*dd285b06SPaolo Bonzini     default:
1307*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
1308*dd285b06SPaolo Bonzini     }
1309*dd285b06SPaolo Bonzini }
1310*dd285b06SPaolo Bonzini 
1311*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_tcmi_ops = {
1312*dd285b06SPaolo Bonzini     .read = omap_tcmi_read,
1313*dd285b06SPaolo Bonzini     .write = omap_tcmi_write,
1314*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1315*dd285b06SPaolo Bonzini };
1316*dd285b06SPaolo Bonzini 
1317*dd285b06SPaolo Bonzini static void omap_tcmi_reset(struct omap_mpu_state_s *mpu)
1318*dd285b06SPaolo Bonzini {
1319*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x00 >> 2] = 0x00000000;
1320*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x04 >> 2] = 0x00000000;
1321*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x08 >> 2] = 0x00000000;
1322*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x0c >> 2] = 0x00000010;
1323*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb;
1324*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb;
1325*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb;
1326*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb;
1327*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x20 >> 2] = 0x00618800;
1328*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x24 >> 2] = 0x00000037;
1329*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x28 >> 2] = 0x00000000;
1330*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x2c >> 2] = 0x00000000;
1331*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x30 >> 2] = 0x00000000;
1332*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x3c >> 2] = 0x00000003;
1333*dd285b06SPaolo Bonzini     mpu->tcmi_regs[0x40 >> 2] = 0x00000000;
1334*dd285b06SPaolo Bonzini }
1335*dd285b06SPaolo Bonzini 
1336*dd285b06SPaolo Bonzini static void omap_tcmi_init(MemoryRegion *memory, hwaddr base,
1337*dd285b06SPaolo Bonzini                 struct omap_mpu_state_s *mpu)
1338*dd285b06SPaolo Bonzini {
1339*dd285b06SPaolo Bonzini     memory_region_init_io(&mpu->tcmi_iomem, &omap_tcmi_ops, mpu,
1340*dd285b06SPaolo Bonzini                           "omap-tcmi", 0x100);
1341*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, base, &mpu->tcmi_iomem);
1342*dd285b06SPaolo Bonzini     omap_tcmi_reset(mpu);
1343*dd285b06SPaolo Bonzini }
1344*dd285b06SPaolo Bonzini 
1345*dd285b06SPaolo Bonzini /* Digital phase-locked loops control */
1346*dd285b06SPaolo Bonzini struct dpll_ctl_s {
1347*dd285b06SPaolo Bonzini     MemoryRegion iomem;
1348*dd285b06SPaolo Bonzini     uint16_t mode;
1349*dd285b06SPaolo Bonzini     omap_clk dpll;
1350*dd285b06SPaolo Bonzini };
1351*dd285b06SPaolo Bonzini 
1352*dd285b06SPaolo Bonzini static uint64_t omap_dpll_read(void *opaque, hwaddr addr,
1353*dd285b06SPaolo Bonzini                                unsigned size)
1354*dd285b06SPaolo Bonzini {
1355*dd285b06SPaolo Bonzini     struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
1356*dd285b06SPaolo Bonzini 
1357*dd285b06SPaolo Bonzini     if (size != 2) {
1358*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
1359*dd285b06SPaolo Bonzini     }
1360*dd285b06SPaolo Bonzini 
1361*dd285b06SPaolo Bonzini     if (addr == 0x00)	/* CTL_REG */
1362*dd285b06SPaolo Bonzini         return s->mode;
1363*dd285b06SPaolo Bonzini 
1364*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1365*dd285b06SPaolo Bonzini     return 0;
1366*dd285b06SPaolo Bonzini }
1367*dd285b06SPaolo Bonzini 
1368*dd285b06SPaolo Bonzini static void omap_dpll_write(void *opaque, hwaddr addr,
1369*dd285b06SPaolo Bonzini                             uint64_t value, unsigned size)
1370*dd285b06SPaolo Bonzini {
1371*dd285b06SPaolo Bonzini     struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
1372*dd285b06SPaolo Bonzini     uint16_t diff;
1373*dd285b06SPaolo Bonzini     static const int bypass_div[4] = { 1, 2, 4, 4 };
1374*dd285b06SPaolo Bonzini     int div, mult;
1375*dd285b06SPaolo Bonzini 
1376*dd285b06SPaolo Bonzini     if (size != 2) {
1377*dd285b06SPaolo Bonzini         return omap_badwidth_write16(opaque, addr, value);
1378*dd285b06SPaolo Bonzini     }
1379*dd285b06SPaolo Bonzini 
1380*dd285b06SPaolo Bonzini     if (addr == 0x00) {	/* CTL_REG */
1381*dd285b06SPaolo Bonzini         /* See omap_ulpd_pm_write() too */
1382*dd285b06SPaolo Bonzini         diff = s->mode & value;
1383*dd285b06SPaolo Bonzini         s->mode = value & 0x2fff;
1384*dd285b06SPaolo Bonzini         if (diff & (0x3ff << 2)) {
1385*dd285b06SPaolo Bonzini             if (value & (1 << 4)) {			/* PLL_ENABLE */
1386*dd285b06SPaolo Bonzini                 div = ((value >> 5) & 3) + 1;		/* PLL_DIV */
1387*dd285b06SPaolo Bonzini                 mult = MIN((value >> 7) & 0x1f, 1);	/* PLL_MULT */
1388*dd285b06SPaolo Bonzini             } else {
1389*dd285b06SPaolo Bonzini                 div = bypass_div[((value >> 2) & 3)];	/* BYPASS_DIV */
1390*dd285b06SPaolo Bonzini                 mult = 1;
1391*dd285b06SPaolo Bonzini             }
1392*dd285b06SPaolo Bonzini             omap_clk_setrate(s->dpll, div, mult);
1393*dd285b06SPaolo Bonzini         }
1394*dd285b06SPaolo Bonzini 
1395*dd285b06SPaolo Bonzini         /* Enter the desired mode.  */
1396*dd285b06SPaolo Bonzini         s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1);
1397*dd285b06SPaolo Bonzini 
1398*dd285b06SPaolo Bonzini         /* Act as if the lock is restored.  */
1399*dd285b06SPaolo Bonzini         s->mode |= 2;
1400*dd285b06SPaolo Bonzini     } else {
1401*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
1402*dd285b06SPaolo Bonzini     }
1403*dd285b06SPaolo Bonzini }
1404*dd285b06SPaolo Bonzini 
1405*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_dpll_ops = {
1406*dd285b06SPaolo Bonzini     .read = omap_dpll_read,
1407*dd285b06SPaolo Bonzini     .write = omap_dpll_write,
1408*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1409*dd285b06SPaolo Bonzini };
1410*dd285b06SPaolo Bonzini 
1411*dd285b06SPaolo Bonzini static void omap_dpll_reset(struct dpll_ctl_s *s)
1412*dd285b06SPaolo Bonzini {
1413*dd285b06SPaolo Bonzini     s->mode = 0x2002;
1414*dd285b06SPaolo Bonzini     omap_clk_setrate(s->dpll, 1, 1);
1415*dd285b06SPaolo Bonzini }
1416*dd285b06SPaolo Bonzini 
1417*dd285b06SPaolo Bonzini static struct dpll_ctl_s  *omap_dpll_init(MemoryRegion *memory,
1418*dd285b06SPaolo Bonzini                            hwaddr base, omap_clk clk)
1419*dd285b06SPaolo Bonzini {
1420*dd285b06SPaolo Bonzini     struct dpll_ctl_s *s = g_malloc0(sizeof(*s));
1421*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_dpll_ops, s, "omap-dpll", 0x100);
1422*dd285b06SPaolo Bonzini 
1423*dd285b06SPaolo Bonzini     s->dpll = clk;
1424*dd285b06SPaolo Bonzini     omap_dpll_reset(s);
1425*dd285b06SPaolo Bonzini 
1426*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, base, &s->iomem);
1427*dd285b06SPaolo Bonzini     return s;
1428*dd285b06SPaolo Bonzini }
1429*dd285b06SPaolo Bonzini 
1430*dd285b06SPaolo Bonzini /* MPU Clock/Reset/Power Mode Control */
1431*dd285b06SPaolo Bonzini static uint64_t omap_clkm_read(void *opaque, hwaddr addr,
1432*dd285b06SPaolo Bonzini                                unsigned size)
1433*dd285b06SPaolo Bonzini {
1434*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
1435*dd285b06SPaolo Bonzini 
1436*dd285b06SPaolo Bonzini     if (size != 2) {
1437*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
1438*dd285b06SPaolo Bonzini     }
1439*dd285b06SPaolo Bonzini 
1440*dd285b06SPaolo Bonzini     switch (addr) {
1441*dd285b06SPaolo Bonzini     case 0x00:	/* ARM_CKCTL */
1442*dd285b06SPaolo Bonzini         return s->clkm.arm_ckctl;
1443*dd285b06SPaolo Bonzini 
1444*dd285b06SPaolo Bonzini     case 0x04:	/* ARM_IDLECT1 */
1445*dd285b06SPaolo Bonzini         return s->clkm.arm_idlect1;
1446*dd285b06SPaolo Bonzini 
1447*dd285b06SPaolo Bonzini     case 0x08:	/* ARM_IDLECT2 */
1448*dd285b06SPaolo Bonzini         return s->clkm.arm_idlect2;
1449*dd285b06SPaolo Bonzini 
1450*dd285b06SPaolo Bonzini     case 0x0c:	/* ARM_EWUPCT */
1451*dd285b06SPaolo Bonzini         return s->clkm.arm_ewupct;
1452*dd285b06SPaolo Bonzini 
1453*dd285b06SPaolo Bonzini     case 0x10:	/* ARM_RSTCT1 */
1454*dd285b06SPaolo Bonzini         return s->clkm.arm_rstct1;
1455*dd285b06SPaolo Bonzini 
1456*dd285b06SPaolo Bonzini     case 0x14:	/* ARM_RSTCT2 */
1457*dd285b06SPaolo Bonzini         return s->clkm.arm_rstct2;
1458*dd285b06SPaolo Bonzini 
1459*dd285b06SPaolo Bonzini     case 0x18:	/* ARM_SYSST */
1460*dd285b06SPaolo Bonzini         return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start;
1461*dd285b06SPaolo Bonzini 
1462*dd285b06SPaolo Bonzini     case 0x1c:	/* ARM_CKOUT1 */
1463*dd285b06SPaolo Bonzini         return s->clkm.arm_ckout1;
1464*dd285b06SPaolo Bonzini 
1465*dd285b06SPaolo Bonzini     case 0x20:	/* ARM_CKOUT2 */
1466*dd285b06SPaolo Bonzini         break;
1467*dd285b06SPaolo Bonzini     }
1468*dd285b06SPaolo Bonzini 
1469*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1470*dd285b06SPaolo Bonzini     return 0;
1471*dd285b06SPaolo Bonzini }
1472*dd285b06SPaolo Bonzini 
1473*dd285b06SPaolo Bonzini static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s,
1474*dd285b06SPaolo Bonzini                 uint16_t diff, uint16_t value)
1475*dd285b06SPaolo Bonzini {
1476*dd285b06SPaolo Bonzini     omap_clk clk;
1477*dd285b06SPaolo Bonzini 
1478*dd285b06SPaolo Bonzini     if (diff & (1 << 14)) {				/* ARM_INTHCK_SEL */
1479*dd285b06SPaolo Bonzini         if (value & (1 << 14))
1480*dd285b06SPaolo Bonzini             /* Reserved */;
1481*dd285b06SPaolo Bonzini         else {
1482*dd285b06SPaolo Bonzini             clk = omap_findclk(s, "arminth_ck");
1483*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
1484*dd285b06SPaolo Bonzini         }
1485*dd285b06SPaolo Bonzini     }
1486*dd285b06SPaolo Bonzini     if (diff & (1 << 12)) {				/* ARM_TIMXO */
1487*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "armtim_ck");
1488*dd285b06SPaolo Bonzini         if (value & (1 << 12))
1489*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "clkin"));
1490*dd285b06SPaolo Bonzini         else
1491*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
1492*dd285b06SPaolo Bonzini     }
1493*dd285b06SPaolo Bonzini     /* XXX: en_dspck */
1494*dd285b06SPaolo Bonzini     if (diff & (3 << 10)) {				/* DSPMMUDIV */
1495*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "dspmmu_ck");
1496*dd285b06SPaolo Bonzini         omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1);
1497*dd285b06SPaolo Bonzini     }
1498*dd285b06SPaolo Bonzini     if (diff & (3 << 8)) {				/* TCDIV */
1499*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "tc_ck");
1500*dd285b06SPaolo Bonzini         omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1);
1501*dd285b06SPaolo Bonzini     }
1502*dd285b06SPaolo Bonzini     if (diff & (3 << 6)) {				/* DSPDIV */
1503*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "dsp_ck");
1504*dd285b06SPaolo Bonzini         omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1);
1505*dd285b06SPaolo Bonzini     }
1506*dd285b06SPaolo Bonzini     if (diff & (3 << 4)) {				/* ARMDIV */
1507*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "arm_ck");
1508*dd285b06SPaolo Bonzini         omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1);
1509*dd285b06SPaolo Bonzini     }
1510*dd285b06SPaolo Bonzini     if (diff & (3 << 2)) {				/* LCDDIV */
1511*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "lcd_ck");
1512*dd285b06SPaolo Bonzini         omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1);
1513*dd285b06SPaolo Bonzini     }
1514*dd285b06SPaolo Bonzini     if (diff & (3 << 0)) {				/* PERDIV */
1515*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "armper_ck");
1516*dd285b06SPaolo Bonzini         omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1);
1517*dd285b06SPaolo Bonzini     }
1518*dd285b06SPaolo Bonzini }
1519*dd285b06SPaolo Bonzini 
1520*dd285b06SPaolo Bonzini static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s,
1521*dd285b06SPaolo Bonzini                 uint16_t diff, uint16_t value)
1522*dd285b06SPaolo Bonzini {
1523*dd285b06SPaolo Bonzini     omap_clk clk;
1524*dd285b06SPaolo Bonzini 
1525*dd285b06SPaolo Bonzini     if (value & (1 << 11)) {                            /* SETARM_IDLE */
1526*dd285b06SPaolo Bonzini         cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT);
1527*dd285b06SPaolo Bonzini     }
1528*dd285b06SPaolo Bonzini     if (!(value & (1 << 10)))				/* WKUP_MODE */
1529*dd285b06SPaolo Bonzini         qemu_system_shutdown_request();	/* XXX: disable wakeup from IRQ */
1530*dd285b06SPaolo Bonzini 
1531*dd285b06SPaolo Bonzini #define SET_CANIDLE(clock, bit)				\
1532*dd285b06SPaolo Bonzini     if (diff & (1 << bit)) {				\
1533*dd285b06SPaolo Bonzini         clk = omap_findclk(s, clock);			\
1534*dd285b06SPaolo Bonzini         omap_clk_canidle(clk, (value >> bit) & 1);	\
1535*dd285b06SPaolo Bonzini     }
1536*dd285b06SPaolo Bonzini     SET_CANIDLE("mpuwd_ck", 0)				/* IDLWDT_ARM */
1537*dd285b06SPaolo Bonzini     SET_CANIDLE("armxor_ck", 1)				/* IDLXORP_ARM */
1538*dd285b06SPaolo Bonzini     SET_CANIDLE("mpuper_ck", 2)				/* IDLPER_ARM */
1539*dd285b06SPaolo Bonzini     SET_CANIDLE("lcd_ck", 3)				/* IDLLCD_ARM */
1540*dd285b06SPaolo Bonzini     SET_CANIDLE("lb_ck", 4)				/* IDLLB_ARM */
1541*dd285b06SPaolo Bonzini     SET_CANIDLE("hsab_ck", 5)				/* IDLHSAB_ARM */
1542*dd285b06SPaolo Bonzini     SET_CANIDLE("tipb_ck", 6)				/* IDLIF_ARM */
1543*dd285b06SPaolo Bonzini     SET_CANIDLE("dma_ck", 6)				/* IDLIF_ARM */
1544*dd285b06SPaolo Bonzini     SET_CANIDLE("tc_ck", 6)				/* IDLIF_ARM */
1545*dd285b06SPaolo Bonzini     SET_CANIDLE("dpll1", 7)				/* IDLDPLL_ARM */
1546*dd285b06SPaolo Bonzini     SET_CANIDLE("dpll2", 7)				/* IDLDPLL_ARM */
1547*dd285b06SPaolo Bonzini     SET_CANIDLE("dpll3", 7)				/* IDLDPLL_ARM */
1548*dd285b06SPaolo Bonzini     SET_CANIDLE("mpui_ck", 8)				/* IDLAPI_ARM */
1549*dd285b06SPaolo Bonzini     SET_CANIDLE("armtim_ck", 9)				/* IDLTIM_ARM */
1550*dd285b06SPaolo Bonzini }
1551*dd285b06SPaolo Bonzini 
1552*dd285b06SPaolo Bonzini static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s,
1553*dd285b06SPaolo Bonzini                 uint16_t diff, uint16_t value)
1554*dd285b06SPaolo Bonzini {
1555*dd285b06SPaolo Bonzini     omap_clk clk;
1556*dd285b06SPaolo Bonzini 
1557*dd285b06SPaolo Bonzini #define SET_ONOFF(clock, bit)				\
1558*dd285b06SPaolo Bonzini     if (diff & (1 << bit)) {				\
1559*dd285b06SPaolo Bonzini         clk = omap_findclk(s, clock);			\
1560*dd285b06SPaolo Bonzini         omap_clk_onoff(clk, (value >> bit) & 1);	\
1561*dd285b06SPaolo Bonzini     }
1562*dd285b06SPaolo Bonzini     SET_ONOFF("mpuwd_ck", 0)				/* EN_WDTCK */
1563*dd285b06SPaolo Bonzini     SET_ONOFF("armxor_ck", 1)				/* EN_XORPCK */
1564*dd285b06SPaolo Bonzini     SET_ONOFF("mpuper_ck", 2)				/* EN_PERCK */
1565*dd285b06SPaolo Bonzini     SET_ONOFF("lcd_ck", 3)				/* EN_LCDCK */
1566*dd285b06SPaolo Bonzini     SET_ONOFF("lb_ck", 4)				/* EN_LBCK */
1567*dd285b06SPaolo Bonzini     SET_ONOFF("hsab_ck", 5)				/* EN_HSABCK */
1568*dd285b06SPaolo Bonzini     SET_ONOFF("mpui_ck", 6)				/* EN_APICK */
1569*dd285b06SPaolo Bonzini     SET_ONOFF("armtim_ck", 7)				/* EN_TIMCK */
1570*dd285b06SPaolo Bonzini     SET_CANIDLE("dma_ck", 8)				/* DMACK_REQ */
1571*dd285b06SPaolo Bonzini     SET_ONOFF("arm_gpio_ck", 9)				/* EN_GPIOCK */
1572*dd285b06SPaolo Bonzini     SET_ONOFF("lbfree_ck", 10)				/* EN_LBFREECK */
1573*dd285b06SPaolo Bonzini }
1574*dd285b06SPaolo Bonzini 
1575*dd285b06SPaolo Bonzini static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
1576*dd285b06SPaolo Bonzini                 uint16_t diff, uint16_t value)
1577*dd285b06SPaolo Bonzini {
1578*dd285b06SPaolo Bonzini     omap_clk clk;
1579*dd285b06SPaolo Bonzini 
1580*dd285b06SPaolo Bonzini     if (diff & (3 << 4)) {				/* TCLKOUT */
1581*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "tclk_out");
1582*dd285b06SPaolo Bonzini         switch ((value >> 4) & 3) {
1583*dd285b06SPaolo Bonzini         case 1:
1584*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "ck_gen3"));
1585*dd285b06SPaolo Bonzini             omap_clk_onoff(clk, 1);
1586*dd285b06SPaolo Bonzini             break;
1587*dd285b06SPaolo Bonzini         case 2:
1588*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
1589*dd285b06SPaolo Bonzini             omap_clk_onoff(clk, 1);
1590*dd285b06SPaolo Bonzini             break;
1591*dd285b06SPaolo Bonzini         default:
1592*dd285b06SPaolo Bonzini             omap_clk_onoff(clk, 0);
1593*dd285b06SPaolo Bonzini         }
1594*dd285b06SPaolo Bonzini     }
1595*dd285b06SPaolo Bonzini     if (diff & (3 << 2)) {				/* DCLKOUT */
1596*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "dclk_out");
1597*dd285b06SPaolo Bonzini         switch ((value >> 2) & 3) {
1598*dd285b06SPaolo Bonzini         case 0:
1599*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck"));
1600*dd285b06SPaolo Bonzini             break;
1601*dd285b06SPaolo Bonzini         case 1:
1602*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "ck_gen2"));
1603*dd285b06SPaolo Bonzini             break;
1604*dd285b06SPaolo Bonzini         case 2:
1605*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "dsp_ck"));
1606*dd285b06SPaolo Bonzini             break;
1607*dd285b06SPaolo Bonzini         case 3:
1608*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "ck_ref14"));
1609*dd285b06SPaolo Bonzini             break;
1610*dd285b06SPaolo Bonzini         }
1611*dd285b06SPaolo Bonzini     }
1612*dd285b06SPaolo Bonzini     if (diff & (3 << 0)) {				/* ACLKOUT */
1613*dd285b06SPaolo Bonzini         clk = omap_findclk(s, "aclk_out");
1614*dd285b06SPaolo Bonzini         switch ((value >> 0) & 3) {
1615*dd285b06SPaolo Bonzini         case 1:
1616*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
1617*dd285b06SPaolo Bonzini             omap_clk_onoff(clk, 1);
1618*dd285b06SPaolo Bonzini             break;
1619*dd285b06SPaolo Bonzini         case 2:
1620*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "arm_ck"));
1621*dd285b06SPaolo Bonzini             omap_clk_onoff(clk, 1);
1622*dd285b06SPaolo Bonzini             break;
1623*dd285b06SPaolo Bonzini         case 3:
1624*dd285b06SPaolo Bonzini             omap_clk_reparent(clk, omap_findclk(s, "ck_ref14"));
1625*dd285b06SPaolo Bonzini             omap_clk_onoff(clk, 1);
1626*dd285b06SPaolo Bonzini             break;
1627*dd285b06SPaolo Bonzini         default:
1628*dd285b06SPaolo Bonzini             omap_clk_onoff(clk, 0);
1629*dd285b06SPaolo Bonzini         }
1630*dd285b06SPaolo Bonzini     }
1631*dd285b06SPaolo Bonzini }
1632*dd285b06SPaolo Bonzini 
1633*dd285b06SPaolo Bonzini static void omap_clkm_write(void *opaque, hwaddr addr,
1634*dd285b06SPaolo Bonzini                             uint64_t value, unsigned size)
1635*dd285b06SPaolo Bonzini {
1636*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
1637*dd285b06SPaolo Bonzini     uint16_t diff;
1638*dd285b06SPaolo Bonzini     omap_clk clk;
1639*dd285b06SPaolo Bonzini     static const char *clkschemename[8] = {
1640*dd285b06SPaolo Bonzini         "fully synchronous", "fully asynchronous", "synchronous scalable",
1641*dd285b06SPaolo Bonzini         "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4",
1642*dd285b06SPaolo Bonzini     };
1643*dd285b06SPaolo Bonzini 
1644*dd285b06SPaolo Bonzini     if (size != 2) {
1645*dd285b06SPaolo Bonzini         return omap_badwidth_write16(opaque, addr, value);
1646*dd285b06SPaolo Bonzini     }
1647*dd285b06SPaolo Bonzini 
1648*dd285b06SPaolo Bonzini     switch (addr) {
1649*dd285b06SPaolo Bonzini     case 0x00:	/* ARM_CKCTL */
1650*dd285b06SPaolo Bonzini         diff = s->clkm.arm_ckctl ^ value;
1651*dd285b06SPaolo Bonzini         s->clkm.arm_ckctl = value & 0x7fff;
1652*dd285b06SPaolo Bonzini         omap_clkm_ckctl_update(s, diff, value);
1653*dd285b06SPaolo Bonzini         return;
1654*dd285b06SPaolo Bonzini 
1655*dd285b06SPaolo Bonzini     case 0x04:	/* ARM_IDLECT1 */
1656*dd285b06SPaolo Bonzini         diff = s->clkm.arm_idlect1 ^ value;
1657*dd285b06SPaolo Bonzini         s->clkm.arm_idlect1 = value & 0x0fff;
1658*dd285b06SPaolo Bonzini         omap_clkm_idlect1_update(s, diff, value);
1659*dd285b06SPaolo Bonzini         return;
1660*dd285b06SPaolo Bonzini 
1661*dd285b06SPaolo Bonzini     case 0x08:	/* ARM_IDLECT2 */
1662*dd285b06SPaolo Bonzini         diff = s->clkm.arm_idlect2 ^ value;
1663*dd285b06SPaolo Bonzini         s->clkm.arm_idlect2 = value & 0x07ff;
1664*dd285b06SPaolo Bonzini         omap_clkm_idlect2_update(s, diff, value);
1665*dd285b06SPaolo Bonzini         return;
1666*dd285b06SPaolo Bonzini 
1667*dd285b06SPaolo Bonzini     case 0x0c:	/* ARM_EWUPCT */
1668*dd285b06SPaolo Bonzini         s->clkm.arm_ewupct = value & 0x003f;
1669*dd285b06SPaolo Bonzini         return;
1670*dd285b06SPaolo Bonzini 
1671*dd285b06SPaolo Bonzini     case 0x10:	/* ARM_RSTCT1 */
1672*dd285b06SPaolo Bonzini         diff = s->clkm.arm_rstct1 ^ value;
1673*dd285b06SPaolo Bonzini         s->clkm.arm_rstct1 = value & 0x0007;
1674*dd285b06SPaolo Bonzini         if (value & 9) {
1675*dd285b06SPaolo Bonzini             qemu_system_reset_request();
1676*dd285b06SPaolo Bonzini             s->clkm.cold_start = 0xa;
1677*dd285b06SPaolo Bonzini         }
1678*dd285b06SPaolo Bonzini         if (diff & ~value & 4) {				/* DSP_RST */
1679*dd285b06SPaolo Bonzini             omap_mpui_reset(s);
1680*dd285b06SPaolo Bonzini             omap_tipb_bridge_reset(s->private_tipb);
1681*dd285b06SPaolo Bonzini             omap_tipb_bridge_reset(s->public_tipb);
1682*dd285b06SPaolo Bonzini         }
1683*dd285b06SPaolo Bonzini         if (diff & 2) {						/* DSP_EN */
1684*dd285b06SPaolo Bonzini             clk = omap_findclk(s, "dsp_ck");
1685*dd285b06SPaolo Bonzini             omap_clk_canidle(clk, (~value >> 1) & 1);
1686*dd285b06SPaolo Bonzini         }
1687*dd285b06SPaolo Bonzini         return;
1688*dd285b06SPaolo Bonzini 
1689*dd285b06SPaolo Bonzini     case 0x14:	/* ARM_RSTCT2 */
1690*dd285b06SPaolo Bonzini         s->clkm.arm_rstct2 = value & 0x0001;
1691*dd285b06SPaolo Bonzini         return;
1692*dd285b06SPaolo Bonzini 
1693*dd285b06SPaolo Bonzini     case 0x18:	/* ARM_SYSST */
1694*dd285b06SPaolo Bonzini         if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) {
1695*dd285b06SPaolo Bonzini             s->clkm.clocking_scheme = (value >> 11) & 7;
1696*dd285b06SPaolo Bonzini             printf("%s: clocking scheme set to %s\n", __FUNCTION__,
1697*dd285b06SPaolo Bonzini                             clkschemename[s->clkm.clocking_scheme]);
1698*dd285b06SPaolo Bonzini         }
1699*dd285b06SPaolo Bonzini         s->clkm.cold_start &= value & 0x3f;
1700*dd285b06SPaolo Bonzini         return;
1701*dd285b06SPaolo Bonzini 
1702*dd285b06SPaolo Bonzini     case 0x1c:	/* ARM_CKOUT1 */
1703*dd285b06SPaolo Bonzini         diff = s->clkm.arm_ckout1 ^ value;
1704*dd285b06SPaolo Bonzini         s->clkm.arm_ckout1 = value & 0x003f;
1705*dd285b06SPaolo Bonzini         omap_clkm_ckout1_update(s, diff, value);
1706*dd285b06SPaolo Bonzini         return;
1707*dd285b06SPaolo Bonzini 
1708*dd285b06SPaolo Bonzini     case 0x20:	/* ARM_CKOUT2 */
1709*dd285b06SPaolo Bonzini     default:
1710*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
1711*dd285b06SPaolo Bonzini     }
1712*dd285b06SPaolo Bonzini }
1713*dd285b06SPaolo Bonzini 
1714*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_clkm_ops = {
1715*dd285b06SPaolo Bonzini     .read = omap_clkm_read,
1716*dd285b06SPaolo Bonzini     .write = omap_clkm_write,
1717*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1718*dd285b06SPaolo Bonzini };
1719*dd285b06SPaolo Bonzini 
1720*dd285b06SPaolo Bonzini static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr,
1721*dd285b06SPaolo Bonzini                                  unsigned size)
1722*dd285b06SPaolo Bonzini {
1723*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
1724*dd285b06SPaolo Bonzini 
1725*dd285b06SPaolo Bonzini     if (size != 2) {
1726*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
1727*dd285b06SPaolo Bonzini     }
1728*dd285b06SPaolo Bonzini 
1729*dd285b06SPaolo Bonzini     switch (addr) {
1730*dd285b06SPaolo Bonzini     case 0x04:	/* DSP_IDLECT1 */
1731*dd285b06SPaolo Bonzini         return s->clkm.dsp_idlect1;
1732*dd285b06SPaolo Bonzini 
1733*dd285b06SPaolo Bonzini     case 0x08:	/* DSP_IDLECT2 */
1734*dd285b06SPaolo Bonzini         return s->clkm.dsp_idlect2;
1735*dd285b06SPaolo Bonzini 
1736*dd285b06SPaolo Bonzini     case 0x14:	/* DSP_RSTCT2 */
1737*dd285b06SPaolo Bonzini         return s->clkm.dsp_rstct2;
1738*dd285b06SPaolo Bonzini 
1739*dd285b06SPaolo Bonzini     case 0x18:	/* DSP_SYSST */
1740*dd285b06SPaolo Bonzini         return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start |
1741*dd285b06SPaolo Bonzini                 (s->cpu->env.halted << 6);      /* Quite useless... */
1742*dd285b06SPaolo Bonzini     }
1743*dd285b06SPaolo Bonzini 
1744*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1745*dd285b06SPaolo Bonzini     return 0;
1746*dd285b06SPaolo Bonzini }
1747*dd285b06SPaolo Bonzini 
1748*dd285b06SPaolo Bonzini static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s,
1749*dd285b06SPaolo Bonzini                 uint16_t diff, uint16_t value)
1750*dd285b06SPaolo Bonzini {
1751*dd285b06SPaolo Bonzini     omap_clk clk;
1752*dd285b06SPaolo Bonzini 
1753*dd285b06SPaolo Bonzini     SET_CANIDLE("dspxor_ck", 1);			/* IDLXORP_DSP */
1754*dd285b06SPaolo Bonzini }
1755*dd285b06SPaolo Bonzini 
1756*dd285b06SPaolo Bonzini static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s,
1757*dd285b06SPaolo Bonzini                 uint16_t diff, uint16_t value)
1758*dd285b06SPaolo Bonzini {
1759*dd285b06SPaolo Bonzini     omap_clk clk;
1760*dd285b06SPaolo Bonzini 
1761*dd285b06SPaolo Bonzini     SET_ONOFF("dspxor_ck", 1);				/* EN_XORPCK */
1762*dd285b06SPaolo Bonzini }
1763*dd285b06SPaolo Bonzini 
1764*dd285b06SPaolo Bonzini static void omap_clkdsp_write(void *opaque, hwaddr addr,
1765*dd285b06SPaolo Bonzini                               uint64_t value, unsigned size)
1766*dd285b06SPaolo Bonzini {
1767*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
1768*dd285b06SPaolo Bonzini     uint16_t diff;
1769*dd285b06SPaolo Bonzini 
1770*dd285b06SPaolo Bonzini     if (size != 2) {
1771*dd285b06SPaolo Bonzini         return omap_badwidth_write16(opaque, addr, value);
1772*dd285b06SPaolo Bonzini     }
1773*dd285b06SPaolo Bonzini 
1774*dd285b06SPaolo Bonzini     switch (addr) {
1775*dd285b06SPaolo Bonzini     case 0x04:	/* DSP_IDLECT1 */
1776*dd285b06SPaolo Bonzini         diff = s->clkm.dsp_idlect1 ^ value;
1777*dd285b06SPaolo Bonzini         s->clkm.dsp_idlect1 = value & 0x01f7;
1778*dd285b06SPaolo Bonzini         omap_clkdsp_idlect1_update(s, diff, value);
1779*dd285b06SPaolo Bonzini         break;
1780*dd285b06SPaolo Bonzini 
1781*dd285b06SPaolo Bonzini     case 0x08:	/* DSP_IDLECT2 */
1782*dd285b06SPaolo Bonzini         s->clkm.dsp_idlect2 = value & 0x0037;
1783*dd285b06SPaolo Bonzini         diff = s->clkm.dsp_idlect1 ^ value;
1784*dd285b06SPaolo Bonzini         omap_clkdsp_idlect2_update(s, diff, value);
1785*dd285b06SPaolo Bonzini         break;
1786*dd285b06SPaolo Bonzini 
1787*dd285b06SPaolo Bonzini     case 0x14:	/* DSP_RSTCT2 */
1788*dd285b06SPaolo Bonzini         s->clkm.dsp_rstct2 = value & 0x0001;
1789*dd285b06SPaolo Bonzini         break;
1790*dd285b06SPaolo Bonzini 
1791*dd285b06SPaolo Bonzini     case 0x18:	/* DSP_SYSST */
1792*dd285b06SPaolo Bonzini         s->clkm.cold_start &= value & 0x3f;
1793*dd285b06SPaolo Bonzini         break;
1794*dd285b06SPaolo Bonzini 
1795*dd285b06SPaolo Bonzini     default:
1796*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
1797*dd285b06SPaolo Bonzini     }
1798*dd285b06SPaolo Bonzini }
1799*dd285b06SPaolo Bonzini 
1800*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_clkdsp_ops = {
1801*dd285b06SPaolo Bonzini     .read = omap_clkdsp_read,
1802*dd285b06SPaolo Bonzini     .write = omap_clkdsp_write,
1803*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
1804*dd285b06SPaolo Bonzini };
1805*dd285b06SPaolo Bonzini 
1806*dd285b06SPaolo Bonzini static void omap_clkm_reset(struct omap_mpu_state_s *s)
1807*dd285b06SPaolo Bonzini {
1808*dd285b06SPaolo Bonzini     if (s->wdt && s->wdt->reset)
1809*dd285b06SPaolo Bonzini         s->clkm.cold_start = 0x6;
1810*dd285b06SPaolo Bonzini     s->clkm.clocking_scheme = 0;
1811*dd285b06SPaolo Bonzini     omap_clkm_ckctl_update(s, ~0, 0x3000);
1812*dd285b06SPaolo Bonzini     s->clkm.arm_ckctl = 0x3000;
1813*dd285b06SPaolo Bonzini     omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400);
1814*dd285b06SPaolo Bonzini     s->clkm.arm_idlect1 = 0x0400;
1815*dd285b06SPaolo Bonzini     omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100);
1816*dd285b06SPaolo Bonzini     s->clkm.arm_idlect2 = 0x0100;
1817*dd285b06SPaolo Bonzini     s->clkm.arm_ewupct = 0x003f;
1818*dd285b06SPaolo Bonzini     s->clkm.arm_rstct1 = 0x0000;
1819*dd285b06SPaolo Bonzini     s->clkm.arm_rstct2 = 0x0000;
1820*dd285b06SPaolo Bonzini     s->clkm.arm_ckout1 = 0x0015;
1821*dd285b06SPaolo Bonzini     s->clkm.dpll1_mode = 0x2002;
1822*dd285b06SPaolo Bonzini     omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040);
1823*dd285b06SPaolo Bonzini     s->clkm.dsp_idlect1 = 0x0040;
1824*dd285b06SPaolo Bonzini     omap_clkdsp_idlect2_update(s, ~0, 0x0000);
1825*dd285b06SPaolo Bonzini     s->clkm.dsp_idlect2 = 0x0000;
1826*dd285b06SPaolo Bonzini     s->clkm.dsp_rstct2 = 0x0000;
1827*dd285b06SPaolo Bonzini }
1828*dd285b06SPaolo Bonzini 
1829*dd285b06SPaolo Bonzini static void omap_clkm_init(MemoryRegion *memory, hwaddr mpu_base,
1830*dd285b06SPaolo Bonzini                 hwaddr dsp_base, struct omap_mpu_state_s *s)
1831*dd285b06SPaolo Bonzini {
1832*dd285b06SPaolo Bonzini     memory_region_init_io(&s->clkm_iomem, &omap_clkm_ops, s,
1833*dd285b06SPaolo Bonzini                           "omap-clkm", 0x100);
1834*dd285b06SPaolo Bonzini     memory_region_init_io(&s->clkdsp_iomem, &omap_clkdsp_ops, s,
1835*dd285b06SPaolo Bonzini                           "omap-clkdsp", 0x1000);
1836*dd285b06SPaolo Bonzini 
1837*dd285b06SPaolo Bonzini     s->clkm.arm_idlect1 = 0x03ff;
1838*dd285b06SPaolo Bonzini     s->clkm.arm_idlect2 = 0x0100;
1839*dd285b06SPaolo Bonzini     s->clkm.dsp_idlect1 = 0x0002;
1840*dd285b06SPaolo Bonzini     omap_clkm_reset(s);
1841*dd285b06SPaolo Bonzini     s->clkm.cold_start = 0x3a;
1842*dd285b06SPaolo Bonzini 
1843*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, mpu_base, &s->clkm_iomem);
1844*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, dsp_base, &s->clkdsp_iomem);
1845*dd285b06SPaolo Bonzini }
1846*dd285b06SPaolo Bonzini 
1847*dd285b06SPaolo Bonzini /* MPU I/O */
1848*dd285b06SPaolo Bonzini struct omap_mpuio_s {
1849*dd285b06SPaolo Bonzini     qemu_irq irq;
1850*dd285b06SPaolo Bonzini     qemu_irq kbd_irq;
1851*dd285b06SPaolo Bonzini     qemu_irq *in;
1852*dd285b06SPaolo Bonzini     qemu_irq handler[16];
1853*dd285b06SPaolo Bonzini     qemu_irq wakeup;
1854*dd285b06SPaolo Bonzini     MemoryRegion iomem;
1855*dd285b06SPaolo Bonzini 
1856*dd285b06SPaolo Bonzini     uint16_t inputs;
1857*dd285b06SPaolo Bonzini     uint16_t outputs;
1858*dd285b06SPaolo Bonzini     uint16_t dir;
1859*dd285b06SPaolo Bonzini     uint16_t edge;
1860*dd285b06SPaolo Bonzini     uint16_t mask;
1861*dd285b06SPaolo Bonzini     uint16_t ints;
1862*dd285b06SPaolo Bonzini 
1863*dd285b06SPaolo Bonzini     uint16_t debounce;
1864*dd285b06SPaolo Bonzini     uint16_t latch;
1865*dd285b06SPaolo Bonzini     uint8_t event;
1866*dd285b06SPaolo Bonzini 
1867*dd285b06SPaolo Bonzini     uint8_t buttons[5];
1868*dd285b06SPaolo Bonzini     uint8_t row_latch;
1869*dd285b06SPaolo Bonzini     uint8_t cols;
1870*dd285b06SPaolo Bonzini     int kbd_mask;
1871*dd285b06SPaolo Bonzini     int clk;
1872*dd285b06SPaolo Bonzini };
1873*dd285b06SPaolo Bonzini 
1874*dd285b06SPaolo Bonzini static void omap_mpuio_set(void *opaque, int line, int level)
1875*dd285b06SPaolo Bonzini {
1876*dd285b06SPaolo Bonzini     struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
1877*dd285b06SPaolo Bonzini     uint16_t prev = s->inputs;
1878*dd285b06SPaolo Bonzini 
1879*dd285b06SPaolo Bonzini     if (level)
1880*dd285b06SPaolo Bonzini         s->inputs |= 1 << line;
1881*dd285b06SPaolo Bonzini     else
1882*dd285b06SPaolo Bonzini         s->inputs &= ~(1 << line);
1883*dd285b06SPaolo Bonzini 
1884*dd285b06SPaolo Bonzini     if (((1 << line) & s->dir & ~s->mask) && s->clk) {
1885*dd285b06SPaolo Bonzini         if ((s->edge & s->inputs & ~prev) | (~s->edge & ~s->inputs & prev)) {
1886*dd285b06SPaolo Bonzini             s->ints |= 1 << line;
1887*dd285b06SPaolo Bonzini             qemu_irq_raise(s->irq);
1888*dd285b06SPaolo Bonzini             /* TODO: wakeup */
1889*dd285b06SPaolo Bonzini         }
1890*dd285b06SPaolo Bonzini         if ((s->event & (1 << 0)) &&		/* SET_GPIO_EVENT_MODE */
1891*dd285b06SPaolo Bonzini                 (s->event >> 1) == line)	/* PIN_SELECT */
1892*dd285b06SPaolo Bonzini             s->latch = s->inputs;
1893*dd285b06SPaolo Bonzini     }
1894*dd285b06SPaolo Bonzini }
1895*dd285b06SPaolo Bonzini 
1896*dd285b06SPaolo Bonzini static void omap_mpuio_kbd_update(struct omap_mpuio_s *s)
1897*dd285b06SPaolo Bonzini {
1898*dd285b06SPaolo Bonzini     int i;
1899*dd285b06SPaolo Bonzini     uint8_t *row, rows = 0, cols = ~s->cols;
1900*dd285b06SPaolo Bonzini 
1901*dd285b06SPaolo Bonzini     for (row = s->buttons + 4, i = 1 << 4; i; row --, i >>= 1)
1902*dd285b06SPaolo Bonzini         if (*row & cols)
1903*dd285b06SPaolo Bonzini             rows |= i;
1904*dd285b06SPaolo Bonzini 
1905*dd285b06SPaolo Bonzini     qemu_set_irq(s->kbd_irq, rows && !s->kbd_mask && s->clk);
1906*dd285b06SPaolo Bonzini     s->row_latch = ~rows;
1907*dd285b06SPaolo Bonzini }
1908*dd285b06SPaolo Bonzini 
1909*dd285b06SPaolo Bonzini static uint64_t omap_mpuio_read(void *opaque, hwaddr addr,
1910*dd285b06SPaolo Bonzini                                 unsigned size)
1911*dd285b06SPaolo Bonzini {
1912*dd285b06SPaolo Bonzini     struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
1913*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
1914*dd285b06SPaolo Bonzini     uint16_t ret;
1915*dd285b06SPaolo Bonzini 
1916*dd285b06SPaolo Bonzini     if (size != 2) {
1917*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
1918*dd285b06SPaolo Bonzini     }
1919*dd285b06SPaolo Bonzini 
1920*dd285b06SPaolo Bonzini     switch (offset) {
1921*dd285b06SPaolo Bonzini     case 0x00:	/* INPUT_LATCH */
1922*dd285b06SPaolo Bonzini         return s->inputs;
1923*dd285b06SPaolo Bonzini 
1924*dd285b06SPaolo Bonzini     case 0x04:	/* OUTPUT_REG */
1925*dd285b06SPaolo Bonzini         return s->outputs;
1926*dd285b06SPaolo Bonzini 
1927*dd285b06SPaolo Bonzini     case 0x08:	/* IO_CNTL */
1928*dd285b06SPaolo Bonzini         return s->dir;
1929*dd285b06SPaolo Bonzini 
1930*dd285b06SPaolo Bonzini     case 0x10:	/* KBR_LATCH */
1931*dd285b06SPaolo Bonzini         return s->row_latch;
1932*dd285b06SPaolo Bonzini 
1933*dd285b06SPaolo Bonzini     case 0x14:	/* KBC_REG */
1934*dd285b06SPaolo Bonzini         return s->cols;
1935*dd285b06SPaolo Bonzini 
1936*dd285b06SPaolo Bonzini     case 0x18:	/* GPIO_EVENT_MODE_REG */
1937*dd285b06SPaolo Bonzini         return s->event;
1938*dd285b06SPaolo Bonzini 
1939*dd285b06SPaolo Bonzini     case 0x1c:	/* GPIO_INT_EDGE_REG */
1940*dd285b06SPaolo Bonzini         return s->edge;
1941*dd285b06SPaolo Bonzini 
1942*dd285b06SPaolo Bonzini     case 0x20:	/* KBD_INT */
1943*dd285b06SPaolo Bonzini         return (~s->row_latch & 0x1f) && !s->kbd_mask;
1944*dd285b06SPaolo Bonzini 
1945*dd285b06SPaolo Bonzini     case 0x24:	/* GPIO_INT */
1946*dd285b06SPaolo Bonzini         ret = s->ints;
1947*dd285b06SPaolo Bonzini         s->ints &= s->mask;
1948*dd285b06SPaolo Bonzini         if (ret)
1949*dd285b06SPaolo Bonzini             qemu_irq_lower(s->irq);
1950*dd285b06SPaolo Bonzini         return ret;
1951*dd285b06SPaolo Bonzini 
1952*dd285b06SPaolo Bonzini     case 0x28:	/* KBD_MASKIT */
1953*dd285b06SPaolo Bonzini         return s->kbd_mask;
1954*dd285b06SPaolo Bonzini 
1955*dd285b06SPaolo Bonzini     case 0x2c:	/* GPIO_MASKIT */
1956*dd285b06SPaolo Bonzini         return s->mask;
1957*dd285b06SPaolo Bonzini 
1958*dd285b06SPaolo Bonzini     case 0x30:	/* GPIO_DEBOUNCING_REG */
1959*dd285b06SPaolo Bonzini         return s->debounce;
1960*dd285b06SPaolo Bonzini 
1961*dd285b06SPaolo Bonzini     case 0x34:	/* GPIO_LATCH_REG */
1962*dd285b06SPaolo Bonzini         return s->latch;
1963*dd285b06SPaolo Bonzini     }
1964*dd285b06SPaolo Bonzini 
1965*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
1966*dd285b06SPaolo Bonzini     return 0;
1967*dd285b06SPaolo Bonzini }
1968*dd285b06SPaolo Bonzini 
1969*dd285b06SPaolo Bonzini static void omap_mpuio_write(void *opaque, hwaddr addr,
1970*dd285b06SPaolo Bonzini                              uint64_t value, unsigned size)
1971*dd285b06SPaolo Bonzini {
1972*dd285b06SPaolo Bonzini     struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
1973*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
1974*dd285b06SPaolo Bonzini     uint16_t diff;
1975*dd285b06SPaolo Bonzini     int ln;
1976*dd285b06SPaolo Bonzini 
1977*dd285b06SPaolo Bonzini     if (size != 2) {
1978*dd285b06SPaolo Bonzini         return omap_badwidth_write16(opaque, addr, value);
1979*dd285b06SPaolo Bonzini     }
1980*dd285b06SPaolo Bonzini 
1981*dd285b06SPaolo Bonzini     switch (offset) {
1982*dd285b06SPaolo Bonzini     case 0x04:	/* OUTPUT_REG */
1983*dd285b06SPaolo Bonzini         diff = (s->outputs ^ value) & ~s->dir;
1984*dd285b06SPaolo Bonzini         s->outputs = value;
1985*dd285b06SPaolo Bonzini         while ((ln = ffs(diff))) {
1986*dd285b06SPaolo Bonzini             ln --;
1987*dd285b06SPaolo Bonzini             if (s->handler[ln])
1988*dd285b06SPaolo Bonzini                 qemu_set_irq(s->handler[ln], (value >> ln) & 1);
1989*dd285b06SPaolo Bonzini             diff &= ~(1 << ln);
1990*dd285b06SPaolo Bonzini         }
1991*dd285b06SPaolo Bonzini         break;
1992*dd285b06SPaolo Bonzini 
1993*dd285b06SPaolo Bonzini     case 0x08:	/* IO_CNTL */
1994*dd285b06SPaolo Bonzini         diff = s->outputs & (s->dir ^ value);
1995*dd285b06SPaolo Bonzini         s->dir = value;
1996*dd285b06SPaolo Bonzini 
1997*dd285b06SPaolo Bonzini         value = s->outputs & ~s->dir;
1998*dd285b06SPaolo Bonzini         while ((ln = ffs(diff))) {
1999*dd285b06SPaolo Bonzini             ln --;
2000*dd285b06SPaolo Bonzini             if (s->handler[ln])
2001*dd285b06SPaolo Bonzini                 qemu_set_irq(s->handler[ln], (value >> ln) & 1);
2002*dd285b06SPaolo Bonzini             diff &= ~(1 << ln);
2003*dd285b06SPaolo Bonzini         }
2004*dd285b06SPaolo Bonzini         break;
2005*dd285b06SPaolo Bonzini 
2006*dd285b06SPaolo Bonzini     case 0x14:	/* KBC_REG */
2007*dd285b06SPaolo Bonzini         s->cols = value;
2008*dd285b06SPaolo Bonzini         omap_mpuio_kbd_update(s);
2009*dd285b06SPaolo Bonzini         break;
2010*dd285b06SPaolo Bonzini 
2011*dd285b06SPaolo Bonzini     case 0x18:	/* GPIO_EVENT_MODE_REG */
2012*dd285b06SPaolo Bonzini         s->event = value & 0x1f;
2013*dd285b06SPaolo Bonzini         break;
2014*dd285b06SPaolo Bonzini 
2015*dd285b06SPaolo Bonzini     case 0x1c:	/* GPIO_INT_EDGE_REG */
2016*dd285b06SPaolo Bonzini         s->edge = value;
2017*dd285b06SPaolo Bonzini         break;
2018*dd285b06SPaolo Bonzini 
2019*dd285b06SPaolo Bonzini     case 0x28:	/* KBD_MASKIT */
2020*dd285b06SPaolo Bonzini         s->kbd_mask = value & 1;
2021*dd285b06SPaolo Bonzini         omap_mpuio_kbd_update(s);
2022*dd285b06SPaolo Bonzini         break;
2023*dd285b06SPaolo Bonzini 
2024*dd285b06SPaolo Bonzini     case 0x2c:	/* GPIO_MASKIT */
2025*dd285b06SPaolo Bonzini         s->mask = value;
2026*dd285b06SPaolo Bonzini         break;
2027*dd285b06SPaolo Bonzini 
2028*dd285b06SPaolo Bonzini     case 0x30:	/* GPIO_DEBOUNCING_REG */
2029*dd285b06SPaolo Bonzini         s->debounce = value & 0x1ff;
2030*dd285b06SPaolo Bonzini         break;
2031*dd285b06SPaolo Bonzini 
2032*dd285b06SPaolo Bonzini     case 0x00:	/* INPUT_LATCH */
2033*dd285b06SPaolo Bonzini     case 0x10:	/* KBR_LATCH */
2034*dd285b06SPaolo Bonzini     case 0x20:	/* KBD_INT */
2035*dd285b06SPaolo Bonzini     case 0x24:	/* GPIO_INT */
2036*dd285b06SPaolo Bonzini     case 0x34:	/* GPIO_LATCH_REG */
2037*dd285b06SPaolo Bonzini         OMAP_RO_REG(addr);
2038*dd285b06SPaolo Bonzini         return;
2039*dd285b06SPaolo Bonzini 
2040*dd285b06SPaolo Bonzini     default:
2041*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
2042*dd285b06SPaolo Bonzini         return;
2043*dd285b06SPaolo Bonzini     }
2044*dd285b06SPaolo Bonzini }
2045*dd285b06SPaolo Bonzini 
2046*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_mpuio_ops  = {
2047*dd285b06SPaolo Bonzini     .read = omap_mpuio_read,
2048*dd285b06SPaolo Bonzini     .write = omap_mpuio_write,
2049*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
2050*dd285b06SPaolo Bonzini };
2051*dd285b06SPaolo Bonzini 
2052*dd285b06SPaolo Bonzini static void omap_mpuio_reset(struct omap_mpuio_s *s)
2053*dd285b06SPaolo Bonzini {
2054*dd285b06SPaolo Bonzini     s->inputs = 0;
2055*dd285b06SPaolo Bonzini     s->outputs = 0;
2056*dd285b06SPaolo Bonzini     s->dir = ~0;
2057*dd285b06SPaolo Bonzini     s->event = 0;
2058*dd285b06SPaolo Bonzini     s->edge = 0;
2059*dd285b06SPaolo Bonzini     s->kbd_mask = 0;
2060*dd285b06SPaolo Bonzini     s->mask = 0;
2061*dd285b06SPaolo Bonzini     s->debounce = 0;
2062*dd285b06SPaolo Bonzini     s->latch = 0;
2063*dd285b06SPaolo Bonzini     s->ints = 0;
2064*dd285b06SPaolo Bonzini     s->row_latch = 0x1f;
2065*dd285b06SPaolo Bonzini     s->clk = 1;
2066*dd285b06SPaolo Bonzini }
2067*dd285b06SPaolo Bonzini 
2068*dd285b06SPaolo Bonzini static void omap_mpuio_onoff(void *opaque, int line, int on)
2069*dd285b06SPaolo Bonzini {
2070*dd285b06SPaolo Bonzini     struct omap_mpuio_s *s = (struct omap_mpuio_s *) opaque;
2071*dd285b06SPaolo Bonzini 
2072*dd285b06SPaolo Bonzini     s->clk = on;
2073*dd285b06SPaolo Bonzini     if (on)
2074*dd285b06SPaolo Bonzini         omap_mpuio_kbd_update(s);
2075*dd285b06SPaolo Bonzini }
2076*dd285b06SPaolo Bonzini 
2077*dd285b06SPaolo Bonzini static struct omap_mpuio_s *omap_mpuio_init(MemoryRegion *memory,
2078*dd285b06SPaolo Bonzini                 hwaddr base,
2079*dd285b06SPaolo Bonzini                 qemu_irq kbd_int, qemu_irq gpio_int, qemu_irq wakeup,
2080*dd285b06SPaolo Bonzini                 omap_clk clk)
2081*dd285b06SPaolo Bonzini {
2082*dd285b06SPaolo Bonzini     struct omap_mpuio_s *s = (struct omap_mpuio_s *)
2083*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_mpuio_s));
2084*dd285b06SPaolo Bonzini 
2085*dd285b06SPaolo Bonzini     s->irq = gpio_int;
2086*dd285b06SPaolo Bonzini     s->kbd_irq = kbd_int;
2087*dd285b06SPaolo Bonzini     s->wakeup = wakeup;
2088*dd285b06SPaolo Bonzini     s->in = qemu_allocate_irqs(omap_mpuio_set, s, 16);
2089*dd285b06SPaolo Bonzini     omap_mpuio_reset(s);
2090*dd285b06SPaolo Bonzini 
2091*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_mpuio_ops, s,
2092*dd285b06SPaolo Bonzini                           "omap-mpuio", 0x800);
2093*dd285b06SPaolo Bonzini     memory_region_add_subregion(memory, base, &s->iomem);
2094*dd285b06SPaolo Bonzini 
2095*dd285b06SPaolo Bonzini     omap_clk_adduser(clk, qemu_allocate_irqs(omap_mpuio_onoff, s, 1)[0]);
2096*dd285b06SPaolo Bonzini 
2097*dd285b06SPaolo Bonzini     return s;
2098*dd285b06SPaolo Bonzini }
2099*dd285b06SPaolo Bonzini 
2100*dd285b06SPaolo Bonzini qemu_irq *omap_mpuio_in_get(struct omap_mpuio_s *s)
2101*dd285b06SPaolo Bonzini {
2102*dd285b06SPaolo Bonzini     return s->in;
2103*dd285b06SPaolo Bonzini }
2104*dd285b06SPaolo Bonzini 
2105*dd285b06SPaolo Bonzini void omap_mpuio_out_set(struct omap_mpuio_s *s, int line, qemu_irq handler)
2106*dd285b06SPaolo Bonzini {
2107*dd285b06SPaolo Bonzini     if (line >= 16 || line < 0)
2108*dd285b06SPaolo Bonzini         hw_error("%s: No GPIO line %i\n", __FUNCTION__, line);
2109*dd285b06SPaolo Bonzini     s->handler[line] = handler;
2110*dd285b06SPaolo Bonzini }
2111*dd285b06SPaolo Bonzini 
2112*dd285b06SPaolo Bonzini void omap_mpuio_key(struct omap_mpuio_s *s, int row, int col, int down)
2113*dd285b06SPaolo Bonzini {
2114*dd285b06SPaolo Bonzini     if (row >= 5 || row < 0)
2115*dd285b06SPaolo Bonzini         hw_error("%s: No key %i-%i\n", __FUNCTION__, col, row);
2116*dd285b06SPaolo Bonzini 
2117*dd285b06SPaolo Bonzini     if (down)
2118*dd285b06SPaolo Bonzini         s->buttons[row] |= 1 << col;
2119*dd285b06SPaolo Bonzini     else
2120*dd285b06SPaolo Bonzini         s->buttons[row] &= ~(1 << col);
2121*dd285b06SPaolo Bonzini 
2122*dd285b06SPaolo Bonzini     omap_mpuio_kbd_update(s);
2123*dd285b06SPaolo Bonzini }
2124*dd285b06SPaolo Bonzini 
2125*dd285b06SPaolo Bonzini /* MicroWire Interface */
2126*dd285b06SPaolo Bonzini struct omap_uwire_s {
2127*dd285b06SPaolo Bonzini     MemoryRegion iomem;
2128*dd285b06SPaolo Bonzini     qemu_irq txirq;
2129*dd285b06SPaolo Bonzini     qemu_irq rxirq;
2130*dd285b06SPaolo Bonzini     qemu_irq txdrq;
2131*dd285b06SPaolo Bonzini 
2132*dd285b06SPaolo Bonzini     uint16_t txbuf;
2133*dd285b06SPaolo Bonzini     uint16_t rxbuf;
2134*dd285b06SPaolo Bonzini     uint16_t control;
2135*dd285b06SPaolo Bonzini     uint16_t setup[5];
2136*dd285b06SPaolo Bonzini 
2137*dd285b06SPaolo Bonzini     uWireSlave *chip[4];
2138*dd285b06SPaolo Bonzini };
2139*dd285b06SPaolo Bonzini 
2140*dd285b06SPaolo Bonzini static void omap_uwire_transfer_start(struct omap_uwire_s *s)
2141*dd285b06SPaolo Bonzini {
2142*dd285b06SPaolo Bonzini     int chipselect = (s->control >> 10) & 3;		/* INDEX */
2143*dd285b06SPaolo Bonzini     uWireSlave *slave = s->chip[chipselect];
2144*dd285b06SPaolo Bonzini 
2145*dd285b06SPaolo Bonzini     if ((s->control >> 5) & 0x1f) {			/* NB_BITS_WR */
2146*dd285b06SPaolo Bonzini         if (s->control & (1 << 12))			/* CS_CMD */
2147*dd285b06SPaolo Bonzini             if (slave && slave->send)
2148*dd285b06SPaolo Bonzini                 slave->send(slave->opaque,
2149*dd285b06SPaolo Bonzini                                 s->txbuf >> (16 - ((s->control >> 5) & 0x1f)));
2150*dd285b06SPaolo Bonzini         s->control &= ~(1 << 14);			/* CSRB */
2151*dd285b06SPaolo Bonzini         /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
2152*dd285b06SPaolo Bonzini          * a DRQ.  When is the level IRQ supposed to be reset?  */
2153*dd285b06SPaolo Bonzini     }
2154*dd285b06SPaolo Bonzini 
2155*dd285b06SPaolo Bonzini     if ((s->control >> 0) & 0x1f) {			/* NB_BITS_RD */
2156*dd285b06SPaolo Bonzini         if (s->control & (1 << 12))			/* CS_CMD */
2157*dd285b06SPaolo Bonzini             if (slave && slave->receive)
2158*dd285b06SPaolo Bonzini                 s->rxbuf = slave->receive(slave->opaque);
2159*dd285b06SPaolo Bonzini         s->control |= 1 << 15;				/* RDRB */
2160*dd285b06SPaolo Bonzini         /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or
2161*dd285b06SPaolo Bonzini          * a DRQ.  When is the level IRQ supposed to be reset?  */
2162*dd285b06SPaolo Bonzini     }
2163*dd285b06SPaolo Bonzini }
2164*dd285b06SPaolo Bonzini 
2165*dd285b06SPaolo Bonzini static uint64_t omap_uwire_read(void *opaque, hwaddr addr,
2166*dd285b06SPaolo Bonzini                                 unsigned size)
2167*dd285b06SPaolo Bonzini {
2168*dd285b06SPaolo Bonzini     struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
2169*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
2170*dd285b06SPaolo Bonzini 
2171*dd285b06SPaolo Bonzini     if (size != 2) {
2172*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
2173*dd285b06SPaolo Bonzini     }
2174*dd285b06SPaolo Bonzini 
2175*dd285b06SPaolo Bonzini     switch (offset) {
2176*dd285b06SPaolo Bonzini     case 0x00:	/* RDR */
2177*dd285b06SPaolo Bonzini         s->control &= ~(1 << 15);			/* RDRB */
2178*dd285b06SPaolo Bonzini         return s->rxbuf;
2179*dd285b06SPaolo Bonzini 
2180*dd285b06SPaolo Bonzini     case 0x04:	/* CSR */
2181*dd285b06SPaolo Bonzini         return s->control;
2182*dd285b06SPaolo Bonzini 
2183*dd285b06SPaolo Bonzini     case 0x08:	/* SR1 */
2184*dd285b06SPaolo Bonzini         return s->setup[0];
2185*dd285b06SPaolo Bonzini     case 0x0c:	/* SR2 */
2186*dd285b06SPaolo Bonzini         return s->setup[1];
2187*dd285b06SPaolo Bonzini     case 0x10:	/* SR3 */
2188*dd285b06SPaolo Bonzini         return s->setup[2];
2189*dd285b06SPaolo Bonzini     case 0x14:	/* SR4 */
2190*dd285b06SPaolo Bonzini         return s->setup[3];
2191*dd285b06SPaolo Bonzini     case 0x18:	/* SR5 */
2192*dd285b06SPaolo Bonzini         return s->setup[4];
2193*dd285b06SPaolo Bonzini     }
2194*dd285b06SPaolo Bonzini 
2195*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
2196*dd285b06SPaolo Bonzini     return 0;
2197*dd285b06SPaolo Bonzini }
2198*dd285b06SPaolo Bonzini 
2199*dd285b06SPaolo Bonzini static void omap_uwire_write(void *opaque, hwaddr addr,
2200*dd285b06SPaolo Bonzini                              uint64_t value, unsigned size)
2201*dd285b06SPaolo Bonzini {
2202*dd285b06SPaolo Bonzini     struct omap_uwire_s *s = (struct omap_uwire_s *) opaque;
2203*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
2204*dd285b06SPaolo Bonzini 
2205*dd285b06SPaolo Bonzini     if (size != 2) {
2206*dd285b06SPaolo Bonzini         return omap_badwidth_write16(opaque, addr, value);
2207*dd285b06SPaolo Bonzini     }
2208*dd285b06SPaolo Bonzini 
2209*dd285b06SPaolo Bonzini     switch (offset) {
2210*dd285b06SPaolo Bonzini     case 0x00:	/* TDR */
2211*dd285b06SPaolo Bonzini         s->txbuf = value;				/* TD */
2212*dd285b06SPaolo Bonzini         if ((s->setup[4] & (1 << 2)) &&			/* AUTO_TX_EN */
2213*dd285b06SPaolo Bonzini                         ((s->setup[4] & (1 << 3)) ||	/* CS_TOGGLE_TX_EN */
2214*dd285b06SPaolo Bonzini                          (s->control & (1 << 12)))) {	/* CS_CMD */
2215*dd285b06SPaolo Bonzini             s->control |= 1 << 14;			/* CSRB */
2216*dd285b06SPaolo Bonzini             omap_uwire_transfer_start(s);
2217*dd285b06SPaolo Bonzini         }
2218*dd285b06SPaolo Bonzini         break;
2219*dd285b06SPaolo Bonzini 
2220*dd285b06SPaolo Bonzini     case 0x04:	/* CSR */
2221*dd285b06SPaolo Bonzini         s->control = value & 0x1fff;
2222*dd285b06SPaolo Bonzini         if (value & (1 << 13))				/* START */
2223*dd285b06SPaolo Bonzini             omap_uwire_transfer_start(s);
2224*dd285b06SPaolo Bonzini         break;
2225*dd285b06SPaolo Bonzini 
2226*dd285b06SPaolo Bonzini     case 0x08:	/* SR1 */
2227*dd285b06SPaolo Bonzini         s->setup[0] = value & 0x003f;
2228*dd285b06SPaolo Bonzini         break;
2229*dd285b06SPaolo Bonzini 
2230*dd285b06SPaolo Bonzini     case 0x0c:	/* SR2 */
2231*dd285b06SPaolo Bonzini         s->setup[1] = value & 0x0fc0;
2232*dd285b06SPaolo Bonzini         break;
2233*dd285b06SPaolo Bonzini 
2234*dd285b06SPaolo Bonzini     case 0x10:	/* SR3 */
2235*dd285b06SPaolo Bonzini         s->setup[2] = value & 0x0003;
2236*dd285b06SPaolo Bonzini         break;
2237*dd285b06SPaolo Bonzini 
2238*dd285b06SPaolo Bonzini     case 0x14:	/* SR4 */
2239*dd285b06SPaolo Bonzini         s->setup[3] = value & 0x0001;
2240*dd285b06SPaolo Bonzini         break;
2241*dd285b06SPaolo Bonzini 
2242*dd285b06SPaolo Bonzini     case 0x18:	/* SR5 */
2243*dd285b06SPaolo Bonzini         s->setup[4] = value & 0x000f;
2244*dd285b06SPaolo Bonzini         break;
2245*dd285b06SPaolo Bonzini 
2246*dd285b06SPaolo Bonzini     default:
2247*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
2248*dd285b06SPaolo Bonzini         return;
2249*dd285b06SPaolo Bonzini     }
2250*dd285b06SPaolo Bonzini }
2251*dd285b06SPaolo Bonzini 
2252*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_uwire_ops = {
2253*dd285b06SPaolo Bonzini     .read = omap_uwire_read,
2254*dd285b06SPaolo Bonzini     .write = omap_uwire_write,
2255*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
2256*dd285b06SPaolo Bonzini };
2257*dd285b06SPaolo Bonzini 
2258*dd285b06SPaolo Bonzini static void omap_uwire_reset(struct omap_uwire_s *s)
2259*dd285b06SPaolo Bonzini {
2260*dd285b06SPaolo Bonzini     s->control = 0;
2261*dd285b06SPaolo Bonzini     s->setup[0] = 0;
2262*dd285b06SPaolo Bonzini     s->setup[1] = 0;
2263*dd285b06SPaolo Bonzini     s->setup[2] = 0;
2264*dd285b06SPaolo Bonzini     s->setup[3] = 0;
2265*dd285b06SPaolo Bonzini     s->setup[4] = 0;
2266*dd285b06SPaolo Bonzini }
2267*dd285b06SPaolo Bonzini 
2268*dd285b06SPaolo Bonzini static struct omap_uwire_s *omap_uwire_init(MemoryRegion *system_memory,
2269*dd285b06SPaolo Bonzini                                             hwaddr base,
2270*dd285b06SPaolo Bonzini                                             qemu_irq txirq, qemu_irq rxirq,
2271*dd285b06SPaolo Bonzini                                             qemu_irq dma,
2272*dd285b06SPaolo Bonzini                                             omap_clk clk)
2273*dd285b06SPaolo Bonzini {
2274*dd285b06SPaolo Bonzini     struct omap_uwire_s *s = (struct omap_uwire_s *)
2275*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_uwire_s));
2276*dd285b06SPaolo Bonzini 
2277*dd285b06SPaolo Bonzini     s->txirq = txirq;
2278*dd285b06SPaolo Bonzini     s->rxirq = rxirq;
2279*dd285b06SPaolo Bonzini     s->txdrq = dma;
2280*dd285b06SPaolo Bonzini     omap_uwire_reset(s);
2281*dd285b06SPaolo Bonzini 
2282*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_uwire_ops, s, "omap-uwire", 0x800);
2283*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &s->iomem);
2284*dd285b06SPaolo Bonzini 
2285*dd285b06SPaolo Bonzini     return s;
2286*dd285b06SPaolo Bonzini }
2287*dd285b06SPaolo Bonzini 
2288*dd285b06SPaolo Bonzini void omap_uwire_attach(struct omap_uwire_s *s,
2289*dd285b06SPaolo Bonzini                 uWireSlave *slave, int chipselect)
2290*dd285b06SPaolo Bonzini {
2291*dd285b06SPaolo Bonzini     if (chipselect < 0 || chipselect > 3) {
2292*dd285b06SPaolo Bonzini         fprintf(stderr, "%s: Bad chipselect %i\n", __FUNCTION__, chipselect);
2293*dd285b06SPaolo Bonzini         exit(-1);
2294*dd285b06SPaolo Bonzini     }
2295*dd285b06SPaolo Bonzini 
2296*dd285b06SPaolo Bonzini     s->chip[chipselect] = slave;
2297*dd285b06SPaolo Bonzini }
2298*dd285b06SPaolo Bonzini 
2299*dd285b06SPaolo Bonzini /* Pseudonoise Pulse-Width Light Modulator */
2300*dd285b06SPaolo Bonzini struct omap_pwl_s {
2301*dd285b06SPaolo Bonzini     MemoryRegion iomem;
2302*dd285b06SPaolo Bonzini     uint8_t output;
2303*dd285b06SPaolo Bonzini     uint8_t level;
2304*dd285b06SPaolo Bonzini     uint8_t enable;
2305*dd285b06SPaolo Bonzini     int clk;
2306*dd285b06SPaolo Bonzini };
2307*dd285b06SPaolo Bonzini 
2308*dd285b06SPaolo Bonzini static void omap_pwl_update(struct omap_pwl_s *s)
2309*dd285b06SPaolo Bonzini {
2310*dd285b06SPaolo Bonzini     int output = (s->clk && s->enable) ? s->level : 0;
2311*dd285b06SPaolo Bonzini 
2312*dd285b06SPaolo Bonzini     if (output != s->output) {
2313*dd285b06SPaolo Bonzini         s->output = output;
2314*dd285b06SPaolo Bonzini         printf("%s: Backlight now at %i/256\n", __FUNCTION__, output);
2315*dd285b06SPaolo Bonzini     }
2316*dd285b06SPaolo Bonzini }
2317*dd285b06SPaolo Bonzini 
2318*dd285b06SPaolo Bonzini static uint64_t omap_pwl_read(void *opaque, hwaddr addr,
2319*dd285b06SPaolo Bonzini                               unsigned size)
2320*dd285b06SPaolo Bonzini {
2321*dd285b06SPaolo Bonzini     struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
2322*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
2323*dd285b06SPaolo Bonzini 
2324*dd285b06SPaolo Bonzini     if (size != 1) {
2325*dd285b06SPaolo Bonzini         return omap_badwidth_read8(opaque, addr);
2326*dd285b06SPaolo Bonzini     }
2327*dd285b06SPaolo Bonzini 
2328*dd285b06SPaolo Bonzini     switch (offset) {
2329*dd285b06SPaolo Bonzini     case 0x00:	/* PWL_LEVEL */
2330*dd285b06SPaolo Bonzini         return s->level;
2331*dd285b06SPaolo Bonzini     case 0x04:	/* PWL_CTRL */
2332*dd285b06SPaolo Bonzini         return s->enable;
2333*dd285b06SPaolo Bonzini     }
2334*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
2335*dd285b06SPaolo Bonzini     return 0;
2336*dd285b06SPaolo Bonzini }
2337*dd285b06SPaolo Bonzini 
2338*dd285b06SPaolo Bonzini static void omap_pwl_write(void *opaque, hwaddr addr,
2339*dd285b06SPaolo Bonzini                            uint64_t value, unsigned size)
2340*dd285b06SPaolo Bonzini {
2341*dd285b06SPaolo Bonzini     struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
2342*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
2343*dd285b06SPaolo Bonzini 
2344*dd285b06SPaolo Bonzini     if (size != 1) {
2345*dd285b06SPaolo Bonzini         return omap_badwidth_write8(opaque, addr, value);
2346*dd285b06SPaolo Bonzini     }
2347*dd285b06SPaolo Bonzini 
2348*dd285b06SPaolo Bonzini     switch (offset) {
2349*dd285b06SPaolo Bonzini     case 0x00:	/* PWL_LEVEL */
2350*dd285b06SPaolo Bonzini         s->level = value;
2351*dd285b06SPaolo Bonzini         omap_pwl_update(s);
2352*dd285b06SPaolo Bonzini         break;
2353*dd285b06SPaolo Bonzini     case 0x04:	/* PWL_CTRL */
2354*dd285b06SPaolo Bonzini         s->enable = value & 1;
2355*dd285b06SPaolo Bonzini         omap_pwl_update(s);
2356*dd285b06SPaolo Bonzini         break;
2357*dd285b06SPaolo Bonzini     default:
2358*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
2359*dd285b06SPaolo Bonzini         return;
2360*dd285b06SPaolo Bonzini     }
2361*dd285b06SPaolo Bonzini }
2362*dd285b06SPaolo Bonzini 
2363*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_pwl_ops = {
2364*dd285b06SPaolo Bonzini     .read = omap_pwl_read,
2365*dd285b06SPaolo Bonzini     .write = omap_pwl_write,
2366*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
2367*dd285b06SPaolo Bonzini };
2368*dd285b06SPaolo Bonzini 
2369*dd285b06SPaolo Bonzini static void omap_pwl_reset(struct omap_pwl_s *s)
2370*dd285b06SPaolo Bonzini {
2371*dd285b06SPaolo Bonzini     s->output = 0;
2372*dd285b06SPaolo Bonzini     s->level = 0;
2373*dd285b06SPaolo Bonzini     s->enable = 0;
2374*dd285b06SPaolo Bonzini     s->clk = 1;
2375*dd285b06SPaolo Bonzini     omap_pwl_update(s);
2376*dd285b06SPaolo Bonzini }
2377*dd285b06SPaolo Bonzini 
2378*dd285b06SPaolo Bonzini static void omap_pwl_clk_update(void *opaque, int line, int on)
2379*dd285b06SPaolo Bonzini {
2380*dd285b06SPaolo Bonzini     struct omap_pwl_s *s = (struct omap_pwl_s *) opaque;
2381*dd285b06SPaolo Bonzini 
2382*dd285b06SPaolo Bonzini     s->clk = on;
2383*dd285b06SPaolo Bonzini     omap_pwl_update(s);
2384*dd285b06SPaolo Bonzini }
2385*dd285b06SPaolo Bonzini 
2386*dd285b06SPaolo Bonzini static struct omap_pwl_s *omap_pwl_init(MemoryRegion *system_memory,
2387*dd285b06SPaolo Bonzini                                         hwaddr base,
2388*dd285b06SPaolo Bonzini                                         omap_clk clk)
2389*dd285b06SPaolo Bonzini {
2390*dd285b06SPaolo Bonzini     struct omap_pwl_s *s = g_malloc0(sizeof(*s));
2391*dd285b06SPaolo Bonzini 
2392*dd285b06SPaolo Bonzini     omap_pwl_reset(s);
2393*dd285b06SPaolo Bonzini 
2394*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_pwl_ops, s,
2395*dd285b06SPaolo Bonzini                           "omap-pwl", 0x800);
2396*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &s->iomem);
2397*dd285b06SPaolo Bonzini 
2398*dd285b06SPaolo Bonzini     omap_clk_adduser(clk, qemu_allocate_irqs(omap_pwl_clk_update, s, 1)[0]);
2399*dd285b06SPaolo Bonzini     return s;
2400*dd285b06SPaolo Bonzini }
2401*dd285b06SPaolo Bonzini 
2402*dd285b06SPaolo Bonzini /* Pulse-Width Tone module */
2403*dd285b06SPaolo Bonzini struct omap_pwt_s {
2404*dd285b06SPaolo Bonzini     MemoryRegion iomem;
2405*dd285b06SPaolo Bonzini     uint8_t frc;
2406*dd285b06SPaolo Bonzini     uint8_t vrc;
2407*dd285b06SPaolo Bonzini     uint8_t gcr;
2408*dd285b06SPaolo Bonzini     omap_clk clk;
2409*dd285b06SPaolo Bonzini };
2410*dd285b06SPaolo Bonzini 
2411*dd285b06SPaolo Bonzini static uint64_t omap_pwt_read(void *opaque, hwaddr addr,
2412*dd285b06SPaolo Bonzini                               unsigned size)
2413*dd285b06SPaolo Bonzini {
2414*dd285b06SPaolo Bonzini     struct omap_pwt_s *s = (struct omap_pwt_s *) opaque;
2415*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
2416*dd285b06SPaolo Bonzini 
2417*dd285b06SPaolo Bonzini     if (size != 1) {
2418*dd285b06SPaolo Bonzini         return omap_badwidth_read8(opaque, addr);
2419*dd285b06SPaolo Bonzini     }
2420*dd285b06SPaolo Bonzini 
2421*dd285b06SPaolo Bonzini     switch (offset) {
2422*dd285b06SPaolo Bonzini     case 0x00:	/* FRC */
2423*dd285b06SPaolo Bonzini         return s->frc;
2424*dd285b06SPaolo Bonzini     case 0x04:	/* VCR */
2425*dd285b06SPaolo Bonzini         return s->vrc;
2426*dd285b06SPaolo Bonzini     case 0x08:	/* GCR */
2427*dd285b06SPaolo Bonzini         return s->gcr;
2428*dd285b06SPaolo Bonzini     }
2429*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
2430*dd285b06SPaolo Bonzini     return 0;
2431*dd285b06SPaolo Bonzini }
2432*dd285b06SPaolo Bonzini 
2433*dd285b06SPaolo Bonzini static void omap_pwt_write(void *opaque, hwaddr addr,
2434*dd285b06SPaolo Bonzini                            uint64_t value, unsigned size)
2435*dd285b06SPaolo Bonzini {
2436*dd285b06SPaolo Bonzini     struct omap_pwt_s *s = (struct omap_pwt_s *) opaque;
2437*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
2438*dd285b06SPaolo Bonzini 
2439*dd285b06SPaolo Bonzini     if (size != 1) {
2440*dd285b06SPaolo Bonzini         return omap_badwidth_write8(opaque, addr, value);
2441*dd285b06SPaolo Bonzini     }
2442*dd285b06SPaolo Bonzini 
2443*dd285b06SPaolo Bonzini     switch (offset) {
2444*dd285b06SPaolo Bonzini     case 0x00:	/* FRC */
2445*dd285b06SPaolo Bonzini         s->frc = value & 0x3f;
2446*dd285b06SPaolo Bonzini         break;
2447*dd285b06SPaolo Bonzini     case 0x04:	/* VRC */
2448*dd285b06SPaolo Bonzini         if ((value ^ s->vrc) & 1) {
2449*dd285b06SPaolo Bonzini             if (value & 1)
2450*dd285b06SPaolo Bonzini                 printf("%s: %iHz buzz on\n", __FUNCTION__, (int)
2451*dd285b06SPaolo Bonzini                                 /* 1.5 MHz from a 12-MHz or 13-MHz PWT_CLK */
2452*dd285b06SPaolo Bonzini                                 ((omap_clk_getrate(s->clk) >> 3) /
2453*dd285b06SPaolo Bonzini                                  /* Pre-multiplexer divider */
2454*dd285b06SPaolo Bonzini                                  ((s->gcr & 2) ? 1 : 154) /
2455*dd285b06SPaolo Bonzini                                  /* Octave multiplexer */
2456*dd285b06SPaolo Bonzini                                  (2 << (value & 3)) *
2457*dd285b06SPaolo Bonzini                                  /* 101/107 divider */
2458*dd285b06SPaolo Bonzini                                  ((value & (1 << 2)) ? 101 : 107) *
2459*dd285b06SPaolo Bonzini                                  /*  49/55 divider */
2460*dd285b06SPaolo Bonzini                                  ((value & (1 << 3)) ?  49 : 55) *
2461*dd285b06SPaolo Bonzini                                  /*  50/63 divider */
2462*dd285b06SPaolo Bonzini                                  ((value & (1 << 4)) ?  50 : 63) *
2463*dd285b06SPaolo Bonzini                                  /*  80/127 divider */
2464*dd285b06SPaolo Bonzini                                  ((value & (1 << 5)) ?  80 : 127) /
2465*dd285b06SPaolo Bonzini                                  (107 * 55 * 63 * 127)));
2466*dd285b06SPaolo Bonzini             else
2467*dd285b06SPaolo Bonzini                 printf("%s: silence!\n", __FUNCTION__);
2468*dd285b06SPaolo Bonzini         }
2469*dd285b06SPaolo Bonzini         s->vrc = value & 0x7f;
2470*dd285b06SPaolo Bonzini         break;
2471*dd285b06SPaolo Bonzini     case 0x08:	/* GCR */
2472*dd285b06SPaolo Bonzini         s->gcr = value & 3;
2473*dd285b06SPaolo Bonzini         break;
2474*dd285b06SPaolo Bonzini     default:
2475*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
2476*dd285b06SPaolo Bonzini         return;
2477*dd285b06SPaolo Bonzini     }
2478*dd285b06SPaolo Bonzini }
2479*dd285b06SPaolo Bonzini 
2480*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_pwt_ops = {
2481*dd285b06SPaolo Bonzini     .read =omap_pwt_read,
2482*dd285b06SPaolo Bonzini     .write = omap_pwt_write,
2483*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
2484*dd285b06SPaolo Bonzini };
2485*dd285b06SPaolo Bonzini 
2486*dd285b06SPaolo Bonzini static void omap_pwt_reset(struct omap_pwt_s *s)
2487*dd285b06SPaolo Bonzini {
2488*dd285b06SPaolo Bonzini     s->frc = 0;
2489*dd285b06SPaolo Bonzini     s->vrc = 0;
2490*dd285b06SPaolo Bonzini     s->gcr = 0;
2491*dd285b06SPaolo Bonzini }
2492*dd285b06SPaolo Bonzini 
2493*dd285b06SPaolo Bonzini static struct omap_pwt_s *omap_pwt_init(MemoryRegion *system_memory,
2494*dd285b06SPaolo Bonzini                                         hwaddr base,
2495*dd285b06SPaolo Bonzini                                         omap_clk clk)
2496*dd285b06SPaolo Bonzini {
2497*dd285b06SPaolo Bonzini     struct omap_pwt_s *s = g_malloc0(sizeof(*s));
2498*dd285b06SPaolo Bonzini     s->clk = clk;
2499*dd285b06SPaolo Bonzini     omap_pwt_reset(s);
2500*dd285b06SPaolo Bonzini 
2501*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_pwt_ops, s,
2502*dd285b06SPaolo Bonzini                           "omap-pwt", 0x800);
2503*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &s->iomem);
2504*dd285b06SPaolo Bonzini     return s;
2505*dd285b06SPaolo Bonzini }
2506*dd285b06SPaolo Bonzini 
2507*dd285b06SPaolo Bonzini /* Real-time Clock module */
2508*dd285b06SPaolo Bonzini struct omap_rtc_s {
2509*dd285b06SPaolo Bonzini     MemoryRegion iomem;
2510*dd285b06SPaolo Bonzini     qemu_irq irq;
2511*dd285b06SPaolo Bonzini     qemu_irq alarm;
2512*dd285b06SPaolo Bonzini     QEMUTimer *clk;
2513*dd285b06SPaolo Bonzini 
2514*dd285b06SPaolo Bonzini     uint8_t interrupts;
2515*dd285b06SPaolo Bonzini     uint8_t status;
2516*dd285b06SPaolo Bonzini     int16_t comp_reg;
2517*dd285b06SPaolo Bonzini     int running;
2518*dd285b06SPaolo Bonzini     int pm_am;
2519*dd285b06SPaolo Bonzini     int auto_comp;
2520*dd285b06SPaolo Bonzini     int round;
2521*dd285b06SPaolo Bonzini     struct tm alarm_tm;
2522*dd285b06SPaolo Bonzini     time_t alarm_ti;
2523*dd285b06SPaolo Bonzini 
2524*dd285b06SPaolo Bonzini     struct tm current_tm;
2525*dd285b06SPaolo Bonzini     time_t ti;
2526*dd285b06SPaolo Bonzini     uint64_t tick;
2527*dd285b06SPaolo Bonzini };
2528*dd285b06SPaolo Bonzini 
2529*dd285b06SPaolo Bonzini static void omap_rtc_interrupts_update(struct omap_rtc_s *s)
2530*dd285b06SPaolo Bonzini {
2531*dd285b06SPaolo Bonzini     /* s->alarm is level-triggered */
2532*dd285b06SPaolo Bonzini     qemu_set_irq(s->alarm, (s->status >> 6) & 1);
2533*dd285b06SPaolo Bonzini }
2534*dd285b06SPaolo Bonzini 
2535*dd285b06SPaolo Bonzini static void omap_rtc_alarm_update(struct omap_rtc_s *s)
2536*dd285b06SPaolo Bonzini {
2537*dd285b06SPaolo Bonzini     s->alarm_ti = mktimegm(&s->alarm_tm);
2538*dd285b06SPaolo Bonzini     if (s->alarm_ti == -1)
2539*dd285b06SPaolo Bonzini         printf("%s: conversion failed\n", __FUNCTION__);
2540*dd285b06SPaolo Bonzini }
2541*dd285b06SPaolo Bonzini 
2542*dd285b06SPaolo Bonzini static uint64_t omap_rtc_read(void *opaque, hwaddr addr,
2543*dd285b06SPaolo Bonzini                               unsigned size)
2544*dd285b06SPaolo Bonzini {
2545*dd285b06SPaolo Bonzini     struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
2546*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
2547*dd285b06SPaolo Bonzini     uint8_t i;
2548*dd285b06SPaolo Bonzini 
2549*dd285b06SPaolo Bonzini     if (size != 1) {
2550*dd285b06SPaolo Bonzini         return omap_badwidth_read8(opaque, addr);
2551*dd285b06SPaolo Bonzini     }
2552*dd285b06SPaolo Bonzini 
2553*dd285b06SPaolo Bonzini     switch (offset) {
2554*dd285b06SPaolo Bonzini     case 0x00:	/* SECONDS_REG */
2555*dd285b06SPaolo Bonzini         return to_bcd(s->current_tm.tm_sec);
2556*dd285b06SPaolo Bonzini 
2557*dd285b06SPaolo Bonzini     case 0x04:	/* MINUTES_REG */
2558*dd285b06SPaolo Bonzini         return to_bcd(s->current_tm.tm_min);
2559*dd285b06SPaolo Bonzini 
2560*dd285b06SPaolo Bonzini     case 0x08:	/* HOURS_REG */
2561*dd285b06SPaolo Bonzini         if (s->pm_am)
2562*dd285b06SPaolo Bonzini             return ((s->current_tm.tm_hour > 11) << 7) |
2563*dd285b06SPaolo Bonzini                     to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1);
2564*dd285b06SPaolo Bonzini         else
2565*dd285b06SPaolo Bonzini             return to_bcd(s->current_tm.tm_hour);
2566*dd285b06SPaolo Bonzini 
2567*dd285b06SPaolo Bonzini     case 0x0c:	/* DAYS_REG */
2568*dd285b06SPaolo Bonzini         return to_bcd(s->current_tm.tm_mday);
2569*dd285b06SPaolo Bonzini 
2570*dd285b06SPaolo Bonzini     case 0x10:	/* MONTHS_REG */
2571*dd285b06SPaolo Bonzini         return to_bcd(s->current_tm.tm_mon + 1);
2572*dd285b06SPaolo Bonzini 
2573*dd285b06SPaolo Bonzini     case 0x14:	/* YEARS_REG */
2574*dd285b06SPaolo Bonzini         return to_bcd(s->current_tm.tm_year % 100);
2575*dd285b06SPaolo Bonzini 
2576*dd285b06SPaolo Bonzini     case 0x18:	/* WEEK_REG */
2577*dd285b06SPaolo Bonzini         return s->current_tm.tm_wday;
2578*dd285b06SPaolo Bonzini 
2579*dd285b06SPaolo Bonzini     case 0x20:	/* ALARM_SECONDS_REG */
2580*dd285b06SPaolo Bonzini         return to_bcd(s->alarm_tm.tm_sec);
2581*dd285b06SPaolo Bonzini 
2582*dd285b06SPaolo Bonzini     case 0x24:	/* ALARM_MINUTES_REG */
2583*dd285b06SPaolo Bonzini         return to_bcd(s->alarm_tm.tm_min);
2584*dd285b06SPaolo Bonzini 
2585*dd285b06SPaolo Bonzini     case 0x28:	/* ALARM_HOURS_REG */
2586*dd285b06SPaolo Bonzini         if (s->pm_am)
2587*dd285b06SPaolo Bonzini             return ((s->alarm_tm.tm_hour > 11) << 7) |
2588*dd285b06SPaolo Bonzini                     to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1);
2589*dd285b06SPaolo Bonzini         else
2590*dd285b06SPaolo Bonzini             return to_bcd(s->alarm_tm.tm_hour);
2591*dd285b06SPaolo Bonzini 
2592*dd285b06SPaolo Bonzini     case 0x2c:	/* ALARM_DAYS_REG */
2593*dd285b06SPaolo Bonzini         return to_bcd(s->alarm_tm.tm_mday);
2594*dd285b06SPaolo Bonzini 
2595*dd285b06SPaolo Bonzini     case 0x30:	/* ALARM_MONTHS_REG */
2596*dd285b06SPaolo Bonzini         return to_bcd(s->alarm_tm.tm_mon + 1);
2597*dd285b06SPaolo Bonzini 
2598*dd285b06SPaolo Bonzini     case 0x34:	/* ALARM_YEARS_REG */
2599*dd285b06SPaolo Bonzini         return to_bcd(s->alarm_tm.tm_year % 100);
2600*dd285b06SPaolo Bonzini 
2601*dd285b06SPaolo Bonzini     case 0x40:	/* RTC_CTRL_REG */
2602*dd285b06SPaolo Bonzini         return (s->pm_am << 3) | (s->auto_comp << 2) |
2603*dd285b06SPaolo Bonzini                 (s->round << 1) | s->running;
2604*dd285b06SPaolo Bonzini 
2605*dd285b06SPaolo Bonzini     case 0x44:	/* RTC_STATUS_REG */
2606*dd285b06SPaolo Bonzini         i = s->status;
2607*dd285b06SPaolo Bonzini         s->status &= ~0x3d;
2608*dd285b06SPaolo Bonzini         return i;
2609*dd285b06SPaolo Bonzini 
2610*dd285b06SPaolo Bonzini     case 0x48:	/* RTC_INTERRUPTS_REG */
2611*dd285b06SPaolo Bonzini         return s->interrupts;
2612*dd285b06SPaolo Bonzini 
2613*dd285b06SPaolo Bonzini     case 0x4c:	/* RTC_COMP_LSB_REG */
2614*dd285b06SPaolo Bonzini         return ((uint16_t) s->comp_reg) & 0xff;
2615*dd285b06SPaolo Bonzini 
2616*dd285b06SPaolo Bonzini     case 0x50:	/* RTC_COMP_MSB_REG */
2617*dd285b06SPaolo Bonzini         return ((uint16_t) s->comp_reg) >> 8;
2618*dd285b06SPaolo Bonzini     }
2619*dd285b06SPaolo Bonzini 
2620*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
2621*dd285b06SPaolo Bonzini     return 0;
2622*dd285b06SPaolo Bonzini }
2623*dd285b06SPaolo Bonzini 
2624*dd285b06SPaolo Bonzini static void omap_rtc_write(void *opaque, hwaddr addr,
2625*dd285b06SPaolo Bonzini                            uint64_t value, unsigned size)
2626*dd285b06SPaolo Bonzini {
2627*dd285b06SPaolo Bonzini     struct omap_rtc_s *s = (struct omap_rtc_s *) opaque;
2628*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
2629*dd285b06SPaolo Bonzini     struct tm new_tm;
2630*dd285b06SPaolo Bonzini     time_t ti[2];
2631*dd285b06SPaolo Bonzini 
2632*dd285b06SPaolo Bonzini     if (size != 1) {
2633*dd285b06SPaolo Bonzini         return omap_badwidth_write8(opaque, addr, value);
2634*dd285b06SPaolo Bonzini     }
2635*dd285b06SPaolo Bonzini 
2636*dd285b06SPaolo Bonzini     switch (offset) {
2637*dd285b06SPaolo Bonzini     case 0x00:	/* SECONDS_REG */
2638*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2639*dd285b06SPaolo Bonzini         printf("RTC SEC_REG <-- %02x\n", value);
2640*dd285b06SPaolo Bonzini #endif
2641*dd285b06SPaolo Bonzini         s->ti -= s->current_tm.tm_sec;
2642*dd285b06SPaolo Bonzini         s->ti += from_bcd(value);
2643*dd285b06SPaolo Bonzini         return;
2644*dd285b06SPaolo Bonzini 
2645*dd285b06SPaolo Bonzini     case 0x04:	/* MINUTES_REG */
2646*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2647*dd285b06SPaolo Bonzini         printf("RTC MIN_REG <-- %02x\n", value);
2648*dd285b06SPaolo Bonzini #endif
2649*dd285b06SPaolo Bonzini         s->ti -= s->current_tm.tm_min * 60;
2650*dd285b06SPaolo Bonzini         s->ti += from_bcd(value) * 60;
2651*dd285b06SPaolo Bonzini         return;
2652*dd285b06SPaolo Bonzini 
2653*dd285b06SPaolo Bonzini     case 0x08:	/* HOURS_REG */
2654*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2655*dd285b06SPaolo Bonzini         printf("RTC HRS_REG <-- %02x\n", value);
2656*dd285b06SPaolo Bonzini #endif
2657*dd285b06SPaolo Bonzini         s->ti -= s->current_tm.tm_hour * 3600;
2658*dd285b06SPaolo Bonzini         if (s->pm_am) {
2659*dd285b06SPaolo Bonzini             s->ti += (from_bcd(value & 0x3f) & 12) * 3600;
2660*dd285b06SPaolo Bonzini             s->ti += ((value >> 7) & 1) * 43200;
2661*dd285b06SPaolo Bonzini         } else
2662*dd285b06SPaolo Bonzini             s->ti += from_bcd(value & 0x3f) * 3600;
2663*dd285b06SPaolo Bonzini         return;
2664*dd285b06SPaolo Bonzini 
2665*dd285b06SPaolo Bonzini     case 0x0c:	/* DAYS_REG */
2666*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2667*dd285b06SPaolo Bonzini         printf("RTC DAY_REG <-- %02x\n", value);
2668*dd285b06SPaolo Bonzini #endif
2669*dd285b06SPaolo Bonzini         s->ti -= s->current_tm.tm_mday * 86400;
2670*dd285b06SPaolo Bonzini         s->ti += from_bcd(value) * 86400;
2671*dd285b06SPaolo Bonzini         return;
2672*dd285b06SPaolo Bonzini 
2673*dd285b06SPaolo Bonzini     case 0x10:	/* MONTHS_REG */
2674*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2675*dd285b06SPaolo Bonzini         printf("RTC MTH_REG <-- %02x\n", value);
2676*dd285b06SPaolo Bonzini #endif
2677*dd285b06SPaolo Bonzini         memcpy(&new_tm, &s->current_tm, sizeof(new_tm));
2678*dd285b06SPaolo Bonzini         new_tm.tm_mon = from_bcd(value);
2679*dd285b06SPaolo Bonzini         ti[0] = mktimegm(&s->current_tm);
2680*dd285b06SPaolo Bonzini         ti[1] = mktimegm(&new_tm);
2681*dd285b06SPaolo Bonzini 
2682*dd285b06SPaolo Bonzini         if (ti[0] != -1 && ti[1] != -1) {
2683*dd285b06SPaolo Bonzini             s->ti -= ti[0];
2684*dd285b06SPaolo Bonzini             s->ti += ti[1];
2685*dd285b06SPaolo Bonzini         } else {
2686*dd285b06SPaolo Bonzini             /* A less accurate version */
2687*dd285b06SPaolo Bonzini             s->ti -= s->current_tm.tm_mon * 2592000;
2688*dd285b06SPaolo Bonzini             s->ti += from_bcd(value) * 2592000;
2689*dd285b06SPaolo Bonzini         }
2690*dd285b06SPaolo Bonzini         return;
2691*dd285b06SPaolo Bonzini 
2692*dd285b06SPaolo Bonzini     case 0x14:	/* YEARS_REG */
2693*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2694*dd285b06SPaolo Bonzini         printf("RTC YRS_REG <-- %02x\n", value);
2695*dd285b06SPaolo Bonzini #endif
2696*dd285b06SPaolo Bonzini         memcpy(&new_tm, &s->current_tm, sizeof(new_tm));
2697*dd285b06SPaolo Bonzini         new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100);
2698*dd285b06SPaolo Bonzini         ti[0] = mktimegm(&s->current_tm);
2699*dd285b06SPaolo Bonzini         ti[1] = mktimegm(&new_tm);
2700*dd285b06SPaolo Bonzini 
2701*dd285b06SPaolo Bonzini         if (ti[0] != -1 && ti[1] != -1) {
2702*dd285b06SPaolo Bonzini             s->ti -= ti[0];
2703*dd285b06SPaolo Bonzini             s->ti += ti[1];
2704*dd285b06SPaolo Bonzini         } else {
2705*dd285b06SPaolo Bonzini             /* A less accurate version */
2706*dd285b06SPaolo Bonzini             s->ti -= (s->current_tm.tm_year % 100) * 31536000;
2707*dd285b06SPaolo Bonzini             s->ti += from_bcd(value) * 31536000;
2708*dd285b06SPaolo Bonzini         }
2709*dd285b06SPaolo Bonzini         return;
2710*dd285b06SPaolo Bonzini 
2711*dd285b06SPaolo Bonzini     case 0x18:	/* WEEK_REG */
2712*dd285b06SPaolo Bonzini         return;	/* Ignored */
2713*dd285b06SPaolo Bonzini 
2714*dd285b06SPaolo Bonzini     case 0x20:	/* ALARM_SECONDS_REG */
2715*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2716*dd285b06SPaolo Bonzini         printf("ALM SEC_REG <-- %02x\n", value);
2717*dd285b06SPaolo Bonzini #endif
2718*dd285b06SPaolo Bonzini         s->alarm_tm.tm_sec = from_bcd(value);
2719*dd285b06SPaolo Bonzini         omap_rtc_alarm_update(s);
2720*dd285b06SPaolo Bonzini         return;
2721*dd285b06SPaolo Bonzini 
2722*dd285b06SPaolo Bonzini     case 0x24:	/* ALARM_MINUTES_REG */
2723*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2724*dd285b06SPaolo Bonzini         printf("ALM MIN_REG <-- %02x\n", value);
2725*dd285b06SPaolo Bonzini #endif
2726*dd285b06SPaolo Bonzini         s->alarm_tm.tm_min = from_bcd(value);
2727*dd285b06SPaolo Bonzini         omap_rtc_alarm_update(s);
2728*dd285b06SPaolo Bonzini         return;
2729*dd285b06SPaolo Bonzini 
2730*dd285b06SPaolo Bonzini     case 0x28:	/* ALARM_HOURS_REG */
2731*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2732*dd285b06SPaolo Bonzini         printf("ALM HRS_REG <-- %02x\n", value);
2733*dd285b06SPaolo Bonzini #endif
2734*dd285b06SPaolo Bonzini         if (s->pm_am)
2735*dd285b06SPaolo Bonzini             s->alarm_tm.tm_hour =
2736*dd285b06SPaolo Bonzini                     ((from_bcd(value & 0x3f)) % 12) +
2737*dd285b06SPaolo Bonzini                     ((value >> 7) & 1) * 12;
2738*dd285b06SPaolo Bonzini         else
2739*dd285b06SPaolo Bonzini             s->alarm_tm.tm_hour = from_bcd(value);
2740*dd285b06SPaolo Bonzini         omap_rtc_alarm_update(s);
2741*dd285b06SPaolo Bonzini         return;
2742*dd285b06SPaolo Bonzini 
2743*dd285b06SPaolo Bonzini     case 0x2c:	/* ALARM_DAYS_REG */
2744*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2745*dd285b06SPaolo Bonzini         printf("ALM DAY_REG <-- %02x\n", value);
2746*dd285b06SPaolo Bonzini #endif
2747*dd285b06SPaolo Bonzini         s->alarm_tm.tm_mday = from_bcd(value);
2748*dd285b06SPaolo Bonzini         omap_rtc_alarm_update(s);
2749*dd285b06SPaolo Bonzini         return;
2750*dd285b06SPaolo Bonzini 
2751*dd285b06SPaolo Bonzini     case 0x30:	/* ALARM_MONTHS_REG */
2752*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2753*dd285b06SPaolo Bonzini         printf("ALM MON_REG <-- %02x\n", value);
2754*dd285b06SPaolo Bonzini #endif
2755*dd285b06SPaolo Bonzini         s->alarm_tm.tm_mon = from_bcd(value);
2756*dd285b06SPaolo Bonzini         omap_rtc_alarm_update(s);
2757*dd285b06SPaolo Bonzini         return;
2758*dd285b06SPaolo Bonzini 
2759*dd285b06SPaolo Bonzini     case 0x34:	/* ALARM_YEARS_REG */
2760*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2761*dd285b06SPaolo Bonzini         printf("ALM YRS_REG <-- %02x\n", value);
2762*dd285b06SPaolo Bonzini #endif
2763*dd285b06SPaolo Bonzini         s->alarm_tm.tm_year = from_bcd(value);
2764*dd285b06SPaolo Bonzini         omap_rtc_alarm_update(s);
2765*dd285b06SPaolo Bonzini         return;
2766*dd285b06SPaolo Bonzini 
2767*dd285b06SPaolo Bonzini     case 0x40:	/* RTC_CTRL_REG */
2768*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2769*dd285b06SPaolo Bonzini         printf("RTC CONTROL <-- %02x\n", value);
2770*dd285b06SPaolo Bonzini #endif
2771*dd285b06SPaolo Bonzini         s->pm_am = (value >> 3) & 1;
2772*dd285b06SPaolo Bonzini         s->auto_comp = (value >> 2) & 1;
2773*dd285b06SPaolo Bonzini         s->round = (value >> 1) & 1;
2774*dd285b06SPaolo Bonzini         s->running = value & 1;
2775*dd285b06SPaolo Bonzini         s->status &= 0xfd;
2776*dd285b06SPaolo Bonzini         s->status |= s->running << 1;
2777*dd285b06SPaolo Bonzini         return;
2778*dd285b06SPaolo Bonzini 
2779*dd285b06SPaolo Bonzini     case 0x44:	/* RTC_STATUS_REG */
2780*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2781*dd285b06SPaolo Bonzini         printf("RTC STATUSL <-- %02x\n", value);
2782*dd285b06SPaolo Bonzini #endif
2783*dd285b06SPaolo Bonzini         s->status &= ~((value & 0xc0) ^ 0x80);
2784*dd285b06SPaolo Bonzini         omap_rtc_interrupts_update(s);
2785*dd285b06SPaolo Bonzini         return;
2786*dd285b06SPaolo Bonzini 
2787*dd285b06SPaolo Bonzini     case 0x48:	/* RTC_INTERRUPTS_REG */
2788*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2789*dd285b06SPaolo Bonzini         printf("RTC INTRS <-- %02x\n", value);
2790*dd285b06SPaolo Bonzini #endif
2791*dd285b06SPaolo Bonzini         s->interrupts = value;
2792*dd285b06SPaolo Bonzini         return;
2793*dd285b06SPaolo Bonzini 
2794*dd285b06SPaolo Bonzini     case 0x4c:	/* RTC_COMP_LSB_REG */
2795*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2796*dd285b06SPaolo Bonzini         printf("RTC COMPLSB <-- %02x\n", value);
2797*dd285b06SPaolo Bonzini #endif
2798*dd285b06SPaolo Bonzini         s->comp_reg &= 0xff00;
2799*dd285b06SPaolo Bonzini         s->comp_reg |= 0x00ff & value;
2800*dd285b06SPaolo Bonzini         return;
2801*dd285b06SPaolo Bonzini 
2802*dd285b06SPaolo Bonzini     case 0x50:	/* RTC_COMP_MSB_REG */
2803*dd285b06SPaolo Bonzini #ifdef ALMDEBUG
2804*dd285b06SPaolo Bonzini         printf("RTC COMPMSB <-- %02x\n", value);
2805*dd285b06SPaolo Bonzini #endif
2806*dd285b06SPaolo Bonzini         s->comp_reg &= 0x00ff;
2807*dd285b06SPaolo Bonzini         s->comp_reg |= 0xff00 & (value << 8);
2808*dd285b06SPaolo Bonzini         return;
2809*dd285b06SPaolo Bonzini 
2810*dd285b06SPaolo Bonzini     default:
2811*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
2812*dd285b06SPaolo Bonzini         return;
2813*dd285b06SPaolo Bonzini     }
2814*dd285b06SPaolo Bonzini }
2815*dd285b06SPaolo Bonzini 
2816*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_rtc_ops = {
2817*dd285b06SPaolo Bonzini     .read = omap_rtc_read,
2818*dd285b06SPaolo Bonzini     .write = omap_rtc_write,
2819*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
2820*dd285b06SPaolo Bonzini };
2821*dd285b06SPaolo Bonzini 
2822*dd285b06SPaolo Bonzini static void omap_rtc_tick(void *opaque)
2823*dd285b06SPaolo Bonzini {
2824*dd285b06SPaolo Bonzini     struct omap_rtc_s *s = opaque;
2825*dd285b06SPaolo Bonzini 
2826*dd285b06SPaolo Bonzini     if (s->round) {
2827*dd285b06SPaolo Bonzini         /* Round to nearest full minute.  */
2828*dd285b06SPaolo Bonzini         if (s->current_tm.tm_sec < 30)
2829*dd285b06SPaolo Bonzini             s->ti -= s->current_tm.tm_sec;
2830*dd285b06SPaolo Bonzini         else
2831*dd285b06SPaolo Bonzini             s->ti += 60 - s->current_tm.tm_sec;
2832*dd285b06SPaolo Bonzini 
2833*dd285b06SPaolo Bonzini         s->round = 0;
2834*dd285b06SPaolo Bonzini     }
2835*dd285b06SPaolo Bonzini 
2836*dd285b06SPaolo Bonzini     localtime_r(&s->ti, &s->current_tm);
2837*dd285b06SPaolo Bonzini 
2838*dd285b06SPaolo Bonzini     if ((s->interrupts & 0x08) && s->ti == s->alarm_ti) {
2839*dd285b06SPaolo Bonzini         s->status |= 0x40;
2840*dd285b06SPaolo Bonzini         omap_rtc_interrupts_update(s);
2841*dd285b06SPaolo Bonzini     }
2842*dd285b06SPaolo Bonzini 
2843*dd285b06SPaolo Bonzini     if (s->interrupts & 0x04)
2844*dd285b06SPaolo Bonzini         switch (s->interrupts & 3) {
2845*dd285b06SPaolo Bonzini         case 0:
2846*dd285b06SPaolo Bonzini             s->status |= 0x04;
2847*dd285b06SPaolo Bonzini             qemu_irq_pulse(s->irq);
2848*dd285b06SPaolo Bonzini             break;
2849*dd285b06SPaolo Bonzini         case 1:
2850*dd285b06SPaolo Bonzini             if (s->current_tm.tm_sec)
2851*dd285b06SPaolo Bonzini                 break;
2852*dd285b06SPaolo Bonzini             s->status |= 0x08;
2853*dd285b06SPaolo Bonzini             qemu_irq_pulse(s->irq);
2854*dd285b06SPaolo Bonzini             break;
2855*dd285b06SPaolo Bonzini         case 2:
2856*dd285b06SPaolo Bonzini             if (s->current_tm.tm_sec || s->current_tm.tm_min)
2857*dd285b06SPaolo Bonzini                 break;
2858*dd285b06SPaolo Bonzini             s->status |= 0x10;
2859*dd285b06SPaolo Bonzini             qemu_irq_pulse(s->irq);
2860*dd285b06SPaolo Bonzini             break;
2861*dd285b06SPaolo Bonzini         case 3:
2862*dd285b06SPaolo Bonzini             if (s->current_tm.tm_sec ||
2863*dd285b06SPaolo Bonzini                             s->current_tm.tm_min || s->current_tm.tm_hour)
2864*dd285b06SPaolo Bonzini                 break;
2865*dd285b06SPaolo Bonzini             s->status |= 0x20;
2866*dd285b06SPaolo Bonzini             qemu_irq_pulse(s->irq);
2867*dd285b06SPaolo Bonzini             break;
2868*dd285b06SPaolo Bonzini         }
2869*dd285b06SPaolo Bonzini 
2870*dd285b06SPaolo Bonzini     /* Move on */
2871*dd285b06SPaolo Bonzini     if (s->running)
2872*dd285b06SPaolo Bonzini         s->ti ++;
2873*dd285b06SPaolo Bonzini     s->tick += 1000;
2874*dd285b06SPaolo Bonzini 
2875*dd285b06SPaolo Bonzini     /*
2876*dd285b06SPaolo Bonzini      * Every full hour add a rough approximation of the compensation
2877*dd285b06SPaolo Bonzini      * register to the 32kHz Timer (which drives the RTC) value.
2878*dd285b06SPaolo Bonzini      */
2879*dd285b06SPaolo Bonzini     if (s->auto_comp && !s->current_tm.tm_sec && !s->current_tm.tm_min)
2880*dd285b06SPaolo Bonzini         s->tick += s->comp_reg * 1000 / 32768;
2881*dd285b06SPaolo Bonzini 
2882*dd285b06SPaolo Bonzini     qemu_mod_timer(s->clk, s->tick);
2883*dd285b06SPaolo Bonzini }
2884*dd285b06SPaolo Bonzini 
2885*dd285b06SPaolo Bonzini static void omap_rtc_reset(struct omap_rtc_s *s)
2886*dd285b06SPaolo Bonzini {
2887*dd285b06SPaolo Bonzini     struct tm tm;
2888*dd285b06SPaolo Bonzini 
2889*dd285b06SPaolo Bonzini     s->interrupts = 0;
2890*dd285b06SPaolo Bonzini     s->comp_reg = 0;
2891*dd285b06SPaolo Bonzini     s->running = 0;
2892*dd285b06SPaolo Bonzini     s->pm_am = 0;
2893*dd285b06SPaolo Bonzini     s->auto_comp = 0;
2894*dd285b06SPaolo Bonzini     s->round = 0;
2895*dd285b06SPaolo Bonzini     s->tick = qemu_get_clock_ms(rtc_clock);
2896*dd285b06SPaolo Bonzini     memset(&s->alarm_tm, 0, sizeof(s->alarm_tm));
2897*dd285b06SPaolo Bonzini     s->alarm_tm.tm_mday = 0x01;
2898*dd285b06SPaolo Bonzini     s->status = 1 << 7;
2899*dd285b06SPaolo Bonzini     qemu_get_timedate(&tm, 0);
2900*dd285b06SPaolo Bonzini     s->ti = mktimegm(&tm);
2901*dd285b06SPaolo Bonzini 
2902*dd285b06SPaolo Bonzini     omap_rtc_alarm_update(s);
2903*dd285b06SPaolo Bonzini     omap_rtc_tick(s);
2904*dd285b06SPaolo Bonzini }
2905*dd285b06SPaolo Bonzini 
2906*dd285b06SPaolo Bonzini static struct omap_rtc_s *omap_rtc_init(MemoryRegion *system_memory,
2907*dd285b06SPaolo Bonzini                                         hwaddr base,
2908*dd285b06SPaolo Bonzini                                         qemu_irq timerirq, qemu_irq alarmirq,
2909*dd285b06SPaolo Bonzini                                         omap_clk clk)
2910*dd285b06SPaolo Bonzini {
2911*dd285b06SPaolo Bonzini     struct omap_rtc_s *s = (struct omap_rtc_s *)
2912*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_rtc_s));
2913*dd285b06SPaolo Bonzini 
2914*dd285b06SPaolo Bonzini     s->irq = timerirq;
2915*dd285b06SPaolo Bonzini     s->alarm = alarmirq;
2916*dd285b06SPaolo Bonzini     s->clk = qemu_new_timer_ms(rtc_clock, omap_rtc_tick, s);
2917*dd285b06SPaolo Bonzini 
2918*dd285b06SPaolo Bonzini     omap_rtc_reset(s);
2919*dd285b06SPaolo Bonzini 
2920*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_rtc_ops, s,
2921*dd285b06SPaolo Bonzini                           "omap-rtc", 0x800);
2922*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &s->iomem);
2923*dd285b06SPaolo Bonzini 
2924*dd285b06SPaolo Bonzini     return s;
2925*dd285b06SPaolo Bonzini }
2926*dd285b06SPaolo Bonzini 
2927*dd285b06SPaolo Bonzini /* Multi-channel Buffered Serial Port interfaces */
2928*dd285b06SPaolo Bonzini struct omap_mcbsp_s {
2929*dd285b06SPaolo Bonzini     MemoryRegion iomem;
2930*dd285b06SPaolo Bonzini     qemu_irq txirq;
2931*dd285b06SPaolo Bonzini     qemu_irq rxirq;
2932*dd285b06SPaolo Bonzini     qemu_irq txdrq;
2933*dd285b06SPaolo Bonzini     qemu_irq rxdrq;
2934*dd285b06SPaolo Bonzini 
2935*dd285b06SPaolo Bonzini     uint16_t spcr[2];
2936*dd285b06SPaolo Bonzini     uint16_t rcr[2];
2937*dd285b06SPaolo Bonzini     uint16_t xcr[2];
2938*dd285b06SPaolo Bonzini     uint16_t srgr[2];
2939*dd285b06SPaolo Bonzini     uint16_t mcr[2];
2940*dd285b06SPaolo Bonzini     uint16_t pcr;
2941*dd285b06SPaolo Bonzini     uint16_t rcer[8];
2942*dd285b06SPaolo Bonzini     uint16_t xcer[8];
2943*dd285b06SPaolo Bonzini     int tx_rate;
2944*dd285b06SPaolo Bonzini     int rx_rate;
2945*dd285b06SPaolo Bonzini     int tx_req;
2946*dd285b06SPaolo Bonzini     int rx_req;
2947*dd285b06SPaolo Bonzini 
2948*dd285b06SPaolo Bonzini     I2SCodec *codec;
2949*dd285b06SPaolo Bonzini     QEMUTimer *source_timer;
2950*dd285b06SPaolo Bonzini     QEMUTimer *sink_timer;
2951*dd285b06SPaolo Bonzini };
2952*dd285b06SPaolo Bonzini 
2953*dd285b06SPaolo Bonzini static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
2954*dd285b06SPaolo Bonzini {
2955*dd285b06SPaolo Bonzini     int irq;
2956*dd285b06SPaolo Bonzini 
2957*dd285b06SPaolo Bonzini     switch ((s->spcr[0] >> 4) & 3) {			/* RINTM */
2958*dd285b06SPaolo Bonzini     case 0:
2959*dd285b06SPaolo Bonzini         irq = (s->spcr[0] >> 1) & 1;			/* RRDY */
2960*dd285b06SPaolo Bonzini         break;
2961*dd285b06SPaolo Bonzini     case 3:
2962*dd285b06SPaolo Bonzini         irq = (s->spcr[0] >> 3) & 1;			/* RSYNCERR */
2963*dd285b06SPaolo Bonzini         break;
2964*dd285b06SPaolo Bonzini     default:
2965*dd285b06SPaolo Bonzini         irq = 0;
2966*dd285b06SPaolo Bonzini         break;
2967*dd285b06SPaolo Bonzini     }
2968*dd285b06SPaolo Bonzini 
2969*dd285b06SPaolo Bonzini     if (irq)
2970*dd285b06SPaolo Bonzini         qemu_irq_pulse(s->rxirq);
2971*dd285b06SPaolo Bonzini 
2972*dd285b06SPaolo Bonzini     switch ((s->spcr[1] >> 4) & 3) {			/* XINTM */
2973*dd285b06SPaolo Bonzini     case 0:
2974*dd285b06SPaolo Bonzini         irq = (s->spcr[1] >> 1) & 1;			/* XRDY */
2975*dd285b06SPaolo Bonzini         break;
2976*dd285b06SPaolo Bonzini     case 3:
2977*dd285b06SPaolo Bonzini         irq = (s->spcr[1] >> 3) & 1;			/* XSYNCERR */
2978*dd285b06SPaolo Bonzini         break;
2979*dd285b06SPaolo Bonzini     default:
2980*dd285b06SPaolo Bonzini         irq = 0;
2981*dd285b06SPaolo Bonzini         break;
2982*dd285b06SPaolo Bonzini     }
2983*dd285b06SPaolo Bonzini 
2984*dd285b06SPaolo Bonzini     if (irq)
2985*dd285b06SPaolo Bonzini         qemu_irq_pulse(s->txirq);
2986*dd285b06SPaolo Bonzini }
2987*dd285b06SPaolo Bonzini 
2988*dd285b06SPaolo Bonzini static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s)
2989*dd285b06SPaolo Bonzini {
2990*dd285b06SPaolo Bonzini     if ((s->spcr[0] >> 1) & 1)				/* RRDY */
2991*dd285b06SPaolo Bonzini         s->spcr[0] |= 1 << 2;				/* RFULL */
2992*dd285b06SPaolo Bonzini     s->spcr[0] |= 1 << 1;				/* RRDY */
2993*dd285b06SPaolo Bonzini     qemu_irq_raise(s->rxdrq);
2994*dd285b06SPaolo Bonzini     omap_mcbsp_intr_update(s);
2995*dd285b06SPaolo Bonzini }
2996*dd285b06SPaolo Bonzini 
2997*dd285b06SPaolo Bonzini static void omap_mcbsp_source_tick(void *opaque)
2998*dd285b06SPaolo Bonzini {
2999*dd285b06SPaolo Bonzini     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
3000*dd285b06SPaolo Bonzini     static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 };
3001*dd285b06SPaolo Bonzini 
3002*dd285b06SPaolo Bonzini     if (!s->rx_rate)
3003*dd285b06SPaolo Bonzini         return;
3004*dd285b06SPaolo Bonzini     if (s->rx_req)
3005*dd285b06SPaolo Bonzini         printf("%s: Rx FIFO overrun\n", __FUNCTION__);
3006*dd285b06SPaolo Bonzini 
3007*dd285b06SPaolo Bonzini     s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7];
3008*dd285b06SPaolo Bonzini 
3009*dd285b06SPaolo Bonzini     omap_mcbsp_rx_newdata(s);
3010*dd285b06SPaolo Bonzini     qemu_mod_timer(s->source_timer, qemu_get_clock_ns(vm_clock) +
3011*dd285b06SPaolo Bonzini                    get_ticks_per_sec());
3012*dd285b06SPaolo Bonzini }
3013*dd285b06SPaolo Bonzini 
3014*dd285b06SPaolo Bonzini static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s)
3015*dd285b06SPaolo Bonzini {
3016*dd285b06SPaolo Bonzini     if (!s->codec || !s->codec->rts)
3017*dd285b06SPaolo Bonzini         omap_mcbsp_source_tick(s);
3018*dd285b06SPaolo Bonzini     else if (s->codec->in.len) {
3019*dd285b06SPaolo Bonzini         s->rx_req = s->codec->in.len;
3020*dd285b06SPaolo Bonzini         omap_mcbsp_rx_newdata(s);
3021*dd285b06SPaolo Bonzini     }
3022*dd285b06SPaolo Bonzini }
3023*dd285b06SPaolo Bonzini 
3024*dd285b06SPaolo Bonzini static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s)
3025*dd285b06SPaolo Bonzini {
3026*dd285b06SPaolo Bonzini     qemu_del_timer(s->source_timer);
3027*dd285b06SPaolo Bonzini }
3028*dd285b06SPaolo Bonzini 
3029*dd285b06SPaolo Bonzini static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s)
3030*dd285b06SPaolo Bonzini {
3031*dd285b06SPaolo Bonzini     s->spcr[0] &= ~(1 << 1);				/* RRDY */
3032*dd285b06SPaolo Bonzini     qemu_irq_lower(s->rxdrq);
3033*dd285b06SPaolo Bonzini     omap_mcbsp_intr_update(s);
3034*dd285b06SPaolo Bonzini }
3035*dd285b06SPaolo Bonzini 
3036*dd285b06SPaolo Bonzini static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s)
3037*dd285b06SPaolo Bonzini {
3038*dd285b06SPaolo Bonzini     s->spcr[1] |= 1 << 1;				/* XRDY */
3039*dd285b06SPaolo Bonzini     qemu_irq_raise(s->txdrq);
3040*dd285b06SPaolo Bonzini     omap_mcbsp_intr_update(s);
3041*dd285b06SPaolo Bonzini }
3042*dd285b06SPaolo Bonzini 
3043*dd285b06SPaolo Bonzini static void omap_mcbsp_sink_tick(void *opaque)
3044*dd285b06SPaolo Bonzini {
3045*dd285b06SPaolo Bonzini     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
3046*dd285b06SPaolo Bonzini     static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 };
3047*dd285b06SPaolo Bonzini 
3048*dd285b06SPaolo Bonzini     if (!s->tx_rate)
3049*dd285b06SPaolo Bonzini         return;
3050*dd285b06SPaolo Bonzini     if (s->tx_req)
3051*dd285b06SPaolo Bonzini         printf("%s: Tx FIFO underrun\n", __FUNCTION__);
3052*dd285b06SPaolo Bonzini 
3053*dd285b06SPaolo Bonzini     s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7];
3054*dd285b06SPaolo Bonzini 
3055*dd285b06SPaolo Bonzini     omap_mcbsp_tx_newdata(s);
3056*dd285b06SPaolo Bonzini     qemu_mod_timer(s->sink_timer, qemu_get_clock_ns(vm_clock) +
3057*dd285b06SPaolo Bonzini                    get_ticks_per_sec());
3058*dd285b06SPaolo Bonzini }
3059*dd285b06SPaolo Bonzini 
3060*dd285b06SPaolo Bonzini static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s)
3061*dd285b06SPaolo Bonzini {
3062*dd285b06SPaolo Bonzini     if (!s->codec || !s->codec->cts)
3063*dd285b06SPaolo Bonzini         omap_mcbsp_sink_tick(s);
3064*dd285b06SPaolo Bonzini     else if (s->codec->out.size) {
3065*dd285b06SPaolo Bonzini         s->tx_req = s->codec->out.size;
3066*dd285b06SPaolo Bonzini         omap_mcbsp_tx_newdata(s);
3067*dd285b06SPaolo Bonzini     }
3068*dd285b06SPaolo Bonzini }
3069*dd285b06SPaolo Bonzini 
3070*dd285b06SPaolo Bonzini static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s)
3071*dd285b06SPaolo Bonzini {
3072*dd285b06SPaolo Bonzini     s->spcr[1] &= ~(1 << 1);				/* XRDY */
3073*dd285b06SPaolo Bonzini     qemu_irq_lower(s->txdrq);
3074*dd285b06SPaolo Bonzini     omap_mcbsp_intr_update(s);
3075*dd285b06SPaolo Bonzini     if (s->codec && s->codec->cts)
3076*dd285b06SPaolo Bonzini         s->codec->tx_swallow(s->codec->opaque);
3077*dd285b06SPaolo Bonzini }
3078*dd285b06SPaolo Bonzini 
3079*dd285b06SPaolo Bonzini static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s)
3080*dd285b06SPaolo Bonzini {
3081*dd285b06SPaolo Bonzini     s->tx_req = 0;
3082*dd285b06SPaolo Bonzini     omap_mcbsp_tx_done(s);
3083*dd285b06SPaolo Bonzini     qemu_del_timer(s->sink_timer);
3084*dd285b06SPaolo Bonzini }
3085*dd285b06SPaolo Bonzini 
3086*dd285b06SPaolo Bonzini static void omap_mcbsp_req_update(struct omap_mcbsp_s *s)
3087*dd285b06SPaolo Bonzini {
3088*dd285b06SPaolo Bonzini     int prev_rx_rate, prev_tx_rate;
3089*dd285b06SPaolo Bonzini     int rx_rate = 0, tx_rate = 0;
3090*dd285b06SPaolo Bonzini     int cpu_rate = 1500000;	/* XXX */
3091*dd285b06SPaolo Bonzini 
3092*dd285b06SPaolo Bonzini     /* TODO: check CLKSTP bit */
3093*dd285b06SPaolo Bonzini     if (s->spcr[1] & (1 << 6)) {			/* GRST */
3094*dd285b06SPaolo Bonzini         if (s->spcr[0] & (1 << 0)) {			/* RRST */
3095*dd285b06SPaolo Bonzini             if ((s->srgr[1] & (1 << 13)) &&		/* CLKSM */
3096*dd285b06SPaolo Bonzini                             (s->pcr & (1 << 8))) {	/* CLKRM */
3097*dd285b06SPaolo Bonzini                 if (~s->pcr & (1 << 7))			/* SCLKME */
3098*dd285b06SPaolo Bonzini                     rx_rate = cpu_rate /
3099*dd285b06SPaolo Bonzini                             ((s->srgr[0] & 0xff) + 1);	/* CLKGDV */
3100*dd285b06SPaolo Bonzini             } else
3101*dd285b06SPaolo Bonzini                 if (s->codec)
3102*dd285b06SPaolo Bonzini                     rx_rate = s->codec->rx_rate;
3103*dd285b06SPaolo Bonzini         }
3104*dd285b06SPaolo Bonzini 
3105*dd285b06SPaolo Bonzini         if (s->spcr[1] & (1 << 0)) {			/* XRST */
3106*dd285b06SPaolo Bonzini             if ((s->srgr[1] & (1 << 13)) &&		/* CLKSM */
3107*dd285b06SPaolo Bonzini                             (s->pcr & (1 << 9))) {	/* CLKXM */
3108*dd285b06SPaolo Bonzini                 if (~s->pcr & (1 << 7))			/* SCLKME */
3109*dd285b06SPaolo Bonzini                     tx_rate = cpu_rate /
3110*dd285b06SPaolo Bonzini                             ((s->srgr[0] & 0xff) + 1);	/* CLKGDV */
3111*dd285b06SPaolo Bonzini             } else
3112*dd285b06SPaolo Bonzini                 if (s->codec)
3113*dd285b06SPaolo Bonzini                     tx_rate = s->codec->tx_rate;
3114*dd285b06SPaolo Bonzini         }
3115*dd285b06SPaolo Bonzini     }
3116*dd285b06SPaolo Bonzini     prev_tx_rate = s->tx_rate;
3117*dd285b06SPaolo Bonzini     prev_rx_rate = s->rx_rate;
3118*dd285b06SPaolo Bonzini     s->tx_rate = tx_rate;
3119*dd285b06SPaolo Bonzini     s->rx_rate = rx_rate;
3120*dd285b06SPaolo Bonzini 
3121*dd285b06SPaolo Bonzini     if (s->codec)
3122*dd285b06SPaolo Bonzini         s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate);
3123*dd285b06SPaolo Bonzini 
3124*dd285b06SPaolo Bonzini     if (!prev_tx_rate && tx_rate)
3125*dd285b06SPaolo Bonzini         omap_mcbsp_tx_start(s);
3126*dd285b06SPaolo Bonzini     else if (s->tx_rate && !tx_rate)
3127*dd285b06SPaolo Bonzini         omap_mcbsp_tx_stop(s);
3128*dd285b06SPaolo Bonzini 
3129*dd285b06SPaolo Bonzini     if (!prev_rx_rate && rx_rate)
3130*dd285b06SPaolo Bonzini         omap_mcbsp_rx_start(s);
3131*dd285b06SPaolo Bonzini     else if (prev_tx_rate && !tx_rate)
3132*dd285b06SPaolo Bonzini         omap_mcbsp_rx_stop(s);
3133*dd285b06SPaolo Bonzini }
3134*dd285b06SPaolo Bonzini 
3135*dd285b06SPaolo Bonzini static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr,
3136*dd285b06SPaolo Bonzini                                 unsigned size)
3137*dd285b06SPaolo Bonzini {
3138*dd285b06SPaolo Bonzini     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
3139*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
3140*dd285b06SPaolo Bonzini     uint16_t ret;
3141*dd285b06SPaolo Bonzini 
3142*dd285b06SPaolo Bonzini     if (size != 2) {
3143*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
3144*dd285b06SPaolo Bonzini     }
3145*dd285b06SPaolo Bonzini 
3146*dd285b06SPaolo Bonzini     switch (offset) {
3147*dd285b06SPaolo Bonzini     case 0x00:	/* DRR2 */
3148*dd285b06SPaolo Bonzini         if (((s->rcr[0] >> 5) & 7) < 3)			/* RWDLEN1 */
3149*dd285b06SPaolo Bonzini             return 0x0000;
3150*dd285b06SPaolo Bonzini         /* Fall through.  */
3151*dd285b06SPaolo Bonzini     case 0x02:	/* DRR1 */
3152*dd285b06SPaolo Bonzini         if (s->rx_req < 2) {
3153*dd285b06SPaolo Bonzini             printf("%s: Rx FIFO underrun\n", __FUNCTION__);
3154*dd285b06SPaolo Bonzini             omap_mcbsp_rx_done(s);
3155*dd285b06SPaolo Bonzini         } else {
3156*dd285b06SPaolo Bonzini             s->tx_req -= 2;
3157*dd285b06SPaolo Bonzini             if (s->codec && s->codec->in.len >= 2) {
3158*dd285b06SPaolo Bonzini                 ret = s->codec->in.fifo[s->codec->in.start ++] << 8;
3159*dd285b06SPaolo Bonzini                 ret |= s->codec->in.fifo[s->codec->in.start ++];
3160*dd285b06SPaolo Bonzini                 s->codec->in.len -= 2;
3161*dd285b06SPaolo Bonzini             } else
3162*dd285b06SPaolo Bonzini                 ret = 0x0000;
3163*dd285b06SPaolo Bonzini             if (!s->tx_req)
3164*dd285b06SPaolo Bonzini                 omap_mcbsp_rx_done(s);
3165*dd285b06SPaolo Bonzini             return ret;
3166*dd285b06SPaolo Bonzini         }
3167*dd285b06SPaolo Bonzini         return 0x0000;
3168*dd285b06SPaolo Bonzini 
3169*dd285b06SPaolo Bonzini     case 0x04:	/* DXR2 */
3170*dd285b06SPaolo Bonzini     case 0x06:	/* DXR1 */
3171*dd285b06SPaolo Bonzini         return 0x0000;
3172*dd285b06SPaolo Bonzini 
3173*dd285b06SPaolo Bonzini     case 0x08:	/* SPCR2 */
3174*dd285b06SPaolo Bonzini         return s->spcr[1];
3175*dd285b06SPaolo Bonzini     case 0x0a:	/* SPCR1 */
3176*dd285b06SPaolo Bonzini         return s->spcr[0];
3177*dd285b06SPaolo Bonzini     case 0x0c:	/* RCR2 */
3178*dd285b06SPaolo Bonzini         return s->rcr[1];
3179*dd285b06SPaolo Bonzini     case 0x0e:	/* RCR1 */
3180*dd285b06SPaolo Bonzini         return s->rcr[0];
3181*dd285b06SPaolo Bonzini     case 0x10:	/* XCR2 */
3182*dd285b06SPaolo Bonzini         return s->xcr[1];
3183*dd285b06SPaolo Bonzini     case 0x12:	/* XCR1 */
3184*dd285b06SPaolo Bonzini         return s->xcr[0];
3185*dd285b06SPaolo Bonzini     case 0x14:	/* SRGR2 */
3186*dd285b06SPaolo Bonzini         return s->srgr[1];
3187*dd285b06SPaolo Bonzini     case 0x16:	/* SRGR1 */
3188*dd285b06SPaolo Bonzini         return s->srgr[0];
3189*dd285b06SPaolo Bonzini     case 0x18:	/* MCR2 */
3190*dd285b06SPaolo Bonzini         return s->mcr[1];
3191*dd285b06SPaolo Bonzini     case 0x1a:	/* MCR1 */
3192*dd285b06SPaolo Bonzini         return s->mcr[0];
3193*dd285b06SPaolo Bonzini     case 0x1c:	/* RCERA */
3194*dd285b06SPaolo Bonzini         return s->rcer[0];
3195*dd285b06SPaolo Bonzini     case 0x1e:	/* RCERB */
3196*dd285b06SPaolo Bonzini         return s->rcer[1];
3197*dd285b06SPaolo Bonzini     case 0x20:	/* XCERA */
3198*dd285b06SPaolo Bonzini         return s->xcer[0];
3199*dd285b06SPaolo Bonzini     case 0x22:	/* XCERB */
3200*dd285b06SPaolo Bonzini         return s->xcer[1];
3201*dd285b06SPaolo Bonzini     case 0x24:	/* PCR0 */
3202*dd285b06SPaolo Bonzini         return s->pcr;
3203*dd285b06SPaolo Bonzini     case 0x26:	/* RCERC */
3204*dd285b06SPaolo Bonzini         return s->rcer[2];
3205*dd285b06SPaolo Bonzini     case 0x28:	/* RCERD */
3206*dd285b06SPaolo Bonzini         return s->rcer[3];
3207*dd285b06SPaolo Bonzini     case 0x2a:	/* XCERC */
3208*dd285b06SPaolo Bonzini         return s->xcer[2];
3209*dd285b06SPaolo Bonzini     case 0x2c:	/* XCERD */
3210*dd285b06SPaolo Bonzini         return s->xcer[3];
3211*dd285b06SPaolo Bonzini     case 0x2e:	/* RCERE */
3212*dd285b06SPaolo Bonzini         return s->rcer[4];
3213*dd285b06SPaolo Bonzini     case 0x30:	/* RCERF */
3214*dd285b06SPaolo Bonzini         return s->rcer[5];
3215*dd285b06SPaolo Bonzini     case 0x32:	/* XCERE */
3216*dd285b06SPaolo Bonzini         return s->xcer[4];
3217*dd285b06SPaolo Bonzini     case 0x34:	/* XCERF */
3218*dd285b06SPaolo Bonzini         return s->xcer[5];
3219*dd285b06SPaolo Bonzini     case 0x36:	/* RCERG */
3220*dd285b06SPaolo Bonzini         return s->rcer[6];
3221*dd285b06SPaolo Bonzini     case 0x38:	/* RCERH */
3222*dd285b06SPaolo Bonzini         return s->rcer[7];
3223*dd285b06SPaolo Bonzini     case 0x3a:	/* XCERG */
3224*dd285b06SPaolo Bonzini         return s->xcer[6];
3225*dd285b06SPaolo Bonzini     case 0x3c:	/* XCERH */
3226*dd285b06SPaolo Bonzini         return s->xcer[7];
3227*dd285b06SPaolo Bonzini     }
3228*dd285b06SPaolo Bonzini 
3229*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
3230*dd285b06SPaolo Bonzini     return 0;
3231*dd285b06SPaolo Bonzini }
3232*dd285b06SPaolo Bonzini 
3233*dd285b06SPaolo Bonzini static void omap_mcbsp_writeh(void *opaque, hwaddr addr,
3234*dd285b06SPaolo Bonzini                 uint32_t value)
3235*dd285b06SPaolo Bonzini {
3236*dd285b06SPaolo Bonzini     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
3237*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
3238*dd285b06SPaolo Bonzini 
3239*dd285b06SPaolo Bonzini     switch (offset) {
3240*dd285b06SPaolo Bonzini     case 0x00:	/* DRR2 */
3241*dd285b06SPaolo Bonzini     case 0x02:	/* DRR1 */
3242*dd285b06SPaolo Bonzini         OMAP_RO_REG(addr);
3243*dd285b06SPaolo Bonzini         return;
3244*dd285b06SPaolo Bonzini 
3245*dd285b06SPaolo Bonzini     case 0x04:	/* DXR2 */
3246*dd285b06SPaolo Bonzini         if (((s->xcr[0] >> 5) & 7) < 3)			/* XWDLEN1 */
3247*dd285b06SPaolo Bonzini             return;
3248*dd285b06SPaolo Bonzini         /* Fall through.  */
3249*dd285b06SPaolo Bonzini     case 0x06:	/* DXR1 */
3250*dd285b06SPaolo Bonzini         if (s->tx_req > 1) {
3251*dd285b06SPaolo Bonzini             s->tx_req -= 2;
3252*dd285b06SPaolo Bonzini             if (s->codec && s->codec->cts) {
3253*dd285b06SPaolo Bonzini                 s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff;
3254*dd285b06SPaolo Bonzini                 s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff;
3255*dd285b06SPaolo Bonzini             }
3256*dd285b06SPaolo Bonzini             if (s->tx_req < 2)
3257*dd285b06SPaolo Bonzini                 omap_mcbsp_tx_done(s);
3258*dd285b06SPaolo Bonzini         } else
3259*dd285b06SPaolo Bonzini             printf("%s: Tx FIFO overrun\n", __FUNCTION__);
3260*dd285b06SPaolo Bonzini         return;
3261*dd285b06SPaolo Bonzini 
3262*dd285b06SPaolo Bonzini     case 0x08:	/* SPCR2 */
3263*dd285b06SPaolo Bonzini         s->spcr[1] &= 0x0002;
3264*dd285b06SPaolo Bonzini         s->spcr[1] |= 0x03f9 & value;
3265*dd285b06SPaolo Bonzini         s->spcr[1] |= 0x0004 & (value << 2);		/* XEMPTY := XRST */
3266*dd285b06SPaolo Bonzini         if (~value & 1)					/* XRST */
3267*dd285b06SPaolo Bonzini             s->spcr[1] &= ~6;
3268*dd285b06SPaolo Bonzini         omap_mcbsp_req_update(s);
3269*dd285b06SPaolo Bonzini         return;
3270*dd285b06SPaolo Bonzini     case 0x0a:	/* SPCR1 */
3271*dd285b06SPaolo Bonzini         s->spcr[0] &= 0x0006;
3272*dd285b06SPaolo Bonzini         s->spcr[0] |= 0xf8f9 & value;
3273*dd285b06SPaolo Bonzini         if (value & (1 << 15))				/* DLB */
3274*dd285b06SPaolo Bonzini             printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__);
3275*dd285b06SPaolo Bonzini         if (~value & 1) {				/* RRST */
3276*dd285b06SPaolo Bonzini             s->spcr[0] &= ~6;
3277*dd285b06SPaolo Bonzini             s->rx_req = 0;
3278*dd285b06SPaolo Bonzini             omap_mcbsp_rx_done(s);
3279*dd285b06SPaolo Bonzini         }
3280*dd285b06SPaolo Bonzini         omap_mcbsp_req_update(s);
3281*dd285b06SPaolo Bonzini         return;
3282*dd285b06SPaolo Bonzini 
3283*dd285b06SPaolo Bonzini     case 0x0c:	/* RCR2 */
3284*dd285b06SPaolo Bonzini         s->rcr[1] = value & 0xffff;
3285*dd285b06SPaolo Bonzini         return;
3286*dd285b06SPaolo Bonzini     case 0x0e:	/* RCR1 */
3287*dd285b06SPaolo Bonzini         s->rcr[0] = value & 0x7fe0;
3288*dd285b06SPaolo Bonzini         return;
3289*dd285b06SPaolo Bonzini     case 0x10:	/* XCR2 */
3290*dd285b06SPaolo Bonzini         s->xcr[1] = value & 0xffff;
3291*dd285b06SPaolo Bonzini         return;
3292*dd285b06SPaolo Bonzini     case 0x12:	/* XCR1 */
3293*dd285b06SPaolo Bonzini         s->xcr[0] = value & 0x7fe0;
3294*dd285b06SPaolo Bonzini         return;
3295*dd285b06SPaolo Bonzini     case 0x14:	/* SRGR2 */
3296*dd285b06SPaolo Bonzini         s->srgr[1] = value & 0xffff;
3297*dd285b06SPaolo Bonzini         omap_mcbsp_req_update(s);
3298*dd285b06SPaolo Bonzini         return;
3299*dd285b06SPaolo Bonzini     case 0x16:	/* SRGR1 */
3300*dd285b06SPaolo Bonzini         s->srgr[0] = value & 0xffff;
3301*dd285b06SPaolo Bonzini         omap_mcbsp_req_update(s);
3302*dd285b06SPaolo Bonzini         return;
3303*dd285b06SPaolo Bonzini     case 0x18:	/* MCR2 */
3304*dd285b06SPaolo Bonzini         s->mcr[1] = value & 0x03e3;
3305*dd285b06SPaolo Bonzini         if (value & 3)					/* XMCM */
3306*dd285b06SPaolo Bonzini             printf("%s: Tx channel selection mode enable attempt\n",
3307*dd285b06SPaolo Bonzini                             __FUNCTION__);
3308*dd285b06SPaolo Bonzini         return;
3309*dd285b06SPaolo Bonzini     case 0x1a:	/* MCR1 */
3310*dd285b06SPaolo Bonzini         s->mcr[0] = value & 0x03e1;
3311*dd285b06SPaolo Bonzini         if (value & 1)					/* RMCM */
3312*dd285b06SPaolo Bonzini             printf("%s: Rx channel selection mode enable attempt\n",
3313*dd285b06SPaolo Bonzini                             __FUNCTION__);
3314*dd285b06SPaolo Bonzini         return;
3315*dd285b06SPaolo Bonzini     case 0x1c:	/* RCERA */
3316*dd285b06SPaolo Bonzini         s->rcer[0] = value & 0xffff;
3317*dd285b06SPaolo Bonzini         return;
3318*dd285b06SPaolo Bonzini     case 0x1e:	/* RCERB */
3319*dd285b06SPaolo Bonzini         s->rcer[1] = value & 0xffff;
3320*dd285b06SPaolo Bonzini         return;
3321*dd285b06SPaolo Bonzini     case 0x20:	/* XCERA */
3322*dd285b06SPaolo Bonzini         s->xcer[0] = value & 0xffff;
3323*dd285b06SPaolo Bonzini         return;
3324*dd285b06SPaolo Bonzini     case 0x22:	/* XCERB */
3325*dd285b06SPaolo Bonzini         s->xcer[1] = value & 0xffff;
3326*dd285b06SPaolo Bonzini         return;
3327*dd285b06SPaolo Bonzini     case 0x24:	/* PCR0 */
3328*dd285b06SPaolo Bonzini         s->pcr = value & 0x7faf;
3329*dd285b06SPaolo Bonzini         return;
3330*dd285b06SPaolo Bonzini     case 0x26:	/* RCERC */
3331*dd285b06SPaolo Bonzini         s->rcer[2] = value & 0xffff;
3332*dd285b06SPaolo Bonzini         return;
3333*dd285b06SPaolo Bonzini     case 0x28:	/* RCERD */
3334*dd285b06SPaolo Bonzini         s->rcer[3] = value & 0xffff;
3335*dd285b06SPaolo Bonzini         return;
3336*dd285b06SPaolo Bonzini     case 0x2a:	/* XCERC */
3337*dd285b06SPaolo Bonzini         s->xcer[2] = value & 0xffff;
3338*dd285b06SPaolo Bonzini         return;
3339*dd285b06SPaolo Bonzini     case 0x2c:	/* XCERD */
3340*dd285b06SPaolo Bonzini         s->xcer[3] = value & 0xffff;
3341*dd285b06SPaolo Bonzini         return;
3342*dd285b06SPaolo Bonzini     case 0x2e:	/* RCERE */
3343*dd285b06SPaolo Bonzini         s->rcer[4] = value & 0xffff;
3344*dd285b06SPaolo Bonzini         return;
3345*dd285b06SPaolo Bonzini     case 0x30:	/* RCERF */
3346*dd285b06SPaolo Bonzini         s->rcer[5] = value & 0xffff;
3347*dd285b06SPaolo Bonzini         return;
3348*dd285b06SPaolo Bonzini     case 0x32:	/* XCERE */
3349*dd285b06SPaolo Bonzini         s->xcer[4] = value & 0xffff;
3350*dd285b06SPaolo Bonzini         return;
3351*dd285b06SPaolo Bonzini     case 0x34:	/* XCERF */
3352*dd285b06SPaolo Bonzini         s->xcer[5] = value & 0xffff;
3353*dd285b06SPaolo Bonzini         return;
3354*dd285b06SPaolo Bonzini     case 0x36:	/* RCERG */
3355*dd285b06SPaolo Bonzini         s->rcer[6] = value & 0xffff;
3356*dd285b06SPaolo Bonzini         return;
3357*dd285b06SPaolo Bonzini     case 0x38:	/* RCERH */
3358*dd285b06SPaolo Bonzini         s->rcer[7] = value & 0xffff;
3359*dd285b06SPaolo Bonzini         return;
3360*dd285b06SPaolo Bonzini     case 0x3a:	/* XCERG */
3361*dd285b06SPaolo Bonzini         s->xcer[6] = value & 0xffff;
3362*dd285b06SPaolo Bonzini         return;
3363*dd285b06SPaolo Bonzini     case 0x3c:	/* XCERH */
3364*dd285b06SPaolo Bonzini         s->xcer[7] = value & 0xffff;
3365*dd285b06SPaolo Bonzini         return;
3366*dd285b06SPaolo Bonzini     }
3367*dd285b06SPaolo Bonzini 
3368*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
3369*dd285b06SPaolo Bonzini }
3370*dd285b06SPaolo Bonzini 
3371*dd285b06SPaolo Bonzini static void omap_mcbsp_writew(void *opaque, hwaddr addr,
3372*dd285b06SPaolo Bonzini                 uint32_t value)
3373*dd285b06SPaolo Bonzini {
3374*dd285b06SPaolo Bonzini     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
3375*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
3376*dd285b06SPaolo Bonzini 
3377*dd285b06SPaolo Bonzini     if (offset == 0x04) {				/* DXR */
3378*dd285b06SPaolo Bonzini         if (((s->xcr[0] >> 5) & 7) < 3)			/* XWDLEN1 */
3379*dd285b06SPaolo Bonzini             return;
3380*dd285b06SPaolo Bonzini         if (s->tx_req > 3) {
3381*dd285b06SPaolo Bonzini             s->tx_req -= 4;
3382*dd285b06SPaolo Bonzini             if (s->codec && s->codec->cts) {
3383*dd285b06SPaolo Bonzini                 s->codec->out.fifo[s->codec->out.len ++] =
3384*dd285b06SPaolo Bonzini                         (value >> 24) & 0xff;
3385*dd285b06SPaolo Bonzini                 s->codec->out.fifo[s->codec->out.len ++] =
3386*dd285b06SPaolo Bonzini                         (value >> 16) & 0xff;
3387*dd285b06SPaolo Bonzini                 s->codec->out.fifo[s->codec->out.len ++] =
3388*dd285b06SPaolo Bonzini                         (value >> 8) & 0xff;
3389*dd285b06SPaolo Bonzini                 s->codec->out.fifo[s->codec->out.len ++] =
3390*dd285b06SPaolo Bonzini                         (value >> 0) & 0xff;
3391*dd285b06SPaolo Bonzini             }
3392*dd285b06SPaolo Bonzini             if (s->tx_req < 4)
3393*dd285b06SPaolo Bonzini                 omap_mcbsp_tx_done(s);
3394*dd285b06SPaolo Bonzini         } else
3395*dd285b06SPaolo Bonzini             printf("%s: Tx FIFO overrun\n", __FUNCTION__);
3396*dd285b06SPaolo Bonzini         return;
3397*dd285b06SPaolo Bonzini     }
3398*dd285b06SPaolo Bonzini 
3399*dd285b06SPaolo Bonzini     omap_badwidth_write16(opaque, addr, value);
3400*dd285b06SPaolo Bonzini }
3401*dd285b06SPaolo Bonzini 
3402*dd285b06SPaolo Bonzini static void omap_mcbsp_write(void *opaque, hwaddr addr,
3403*dd285b06SPaolo Bonzini                              uint64_t value, unsigned size)
3404*dd285b06SPaolo Bonzini {
3405*dd285b06SPaolo Bonzini     switch (size) {
3406*dd285b06SPaolo Bonzini     case 2: return omap_mcbsp_writeh(opaque, addr, value);
3407*dd285b06SPaolo Bonzini     case 4: return omap_mcbsp_writew(opaque, addr, value);
3408*dd285b06SPaolo Bonzini     default: return omap_badwidth_write16(opaque, addr, value);
3409*dd285b06SPaolo Bonzini     }
3410*dd285b06SPaolo Bonzini }
3411*dd285b06SPaolo Bonzini 
3412*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_mcbsp_ops = {
3413*dd285b06SPaolo Bonzini     .read = omap_mcbsp_read,
3414*dd285b06SPaolo Bonzini     .write = omap_mcbsp_write,
3415*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
3416*dd285b06SPaolo Bonzini };
3417*dd285b06SPaolo Bonzini 
3418*dd285b06SPaolo Bonzini static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
3419*dd285b06SPaolo Bonzini {
3420*dd285b06SPaolo Bonzini     memset(&s->spcr, 0, sizeof(s->spcr));
3421*dd285b06SPaolo Bonzini     memset(&s->rcr, 0, sizeof(s->rcr));
3422*dd285b06SPaolo Bonzini     memset(&s->xcr, 0, sizeof(s->xcr));
3423*dd285b06SPaolo Bonzini     s->srgr[0] = 0x0001;
3424*dd285b06SPaolo Bonzini     s->srgr[1] = 0x2000;
3425*dd285b06SPaolo Bonzini     memset(&s->mcr, 0, sizeof(s->mcr));
3426*dd285b06SPaolo Bonzini     memset(&s->pcr, 0, sizeof(s->pcr));
3427*dd285b06SPaolo Bonzini     memset(&s->rcer, 0, sizeof(s->rcer));
3428*dd285b06SPaolo Bonzini     memset(&s->xcer, 0, sizeof(s->xcer));
3429*dd285b06SPaolo Bonzini     s->tx_req = 0;
3430*dd285b06SPaolo Bonzini     s->rx_req = 0;
3431*dd285b06SPaolo Bonzini     s->tx_rate = 0;
3432*dd285b06SPaolo Bonzini     s->rx_rate = 0;
3433*dd285b06SPaolo Bonzini     qemu_del_timer(s->source_timer);
3434*dd285b06SPaolo Bonzini     qemu_del_timer(s->sink_timer);
3435*dd285b06SPaolo Bonzini }
3436*dd285b06SPaolo Bonzini 
3437*dd285b06SPaolo Bonzini static struct omap_mcbsp_s *omap_mcbsp_init(MemoryRegion *system_memory,
3438*dd285b06SPaolo Bonzini                                             hwaddr base,
3439*dd285b06SPaolo Bonzini                                             qemu_irq txirq, qemu_irq rxirq,
3440*dd285b06SPaolo Bonzini                                             qemu_irq *dma, omap_clk clk)
3441*dd285b06SPaolo Bonzini {
3442*dd285b06SPaolo Bonzini     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *)
3443*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_mcbsp_s));
3444*dd285b06SPaolo Bonzini 
3445*dd285b06SPaolo Bonzini     s->txirq = txirq;
3446*dd285b06SPaolo Bonzini     s->rxirq = rxirq;
3447*dd285b06SPaolo Bonzini     s->txdrq = dma[0];
3448*dd285b06SPaolo Bonzini     s->rxdrq = dma[1];
3449*dd285b06SPaolo Bonzini     s->sink_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_sink_tick, s);
3450*dd285b06SPaolo Bonzini     s->source_timer = qemu_new_timer_ns(vm_clock, omap_mcbsp_source_tick, s);
3451*dd285b06SPaolo Bonzini     omap_mcbsp_reset(s);
3452*dd285b06SPaolo Bonzini 
3453*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_mcbsp_ops, s, "omap-mcbsp", 0x800);
3454*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &s->iomem);
3455*dd285b06SPaolo Bonzini 
3456*dd285b06SPaolo Bonzini     return s;
3457*dd285b06SPaolo Bonzini }
3458*dd285b06SPaolo Bonzini 
3459*dd285b06SPaolo Bonzini static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level)
3460*dd285b06SPaolo Bonzini {
3461*dd285b06SPaolo Bonzini     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
3462*dd285b06SPaolo Bonzini 
3463*dd285b06SPaolo Bonzini     if (s->rx_rate) {
3464*dd285b06SPaolo Bonzini         s->rx_req = s->codec->in.len;
3465*dd285b06SPaolo Bonzini         omap_mcbsp_rx_newdata(s);
3466*dd285b06SPaolo Bonzini     }
3467*dd285b06SPaolo Bonzini }
3468*dd285b06SPaolo Bonzini 
3469*dd285b06SPaolo Bonzini static void omap_mcbsp_i2s_start(void *opaque, int line, int level)
3470*dd285b06SPaolo Bonzini {
3471*dd285b06SPaolo Bonzini     struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
3472*dd285b06SPaolo Bonzini 
3473*dd285b06SPaolo Bonzini     if (s->tx_rate) {
3474*dd285b06SPaolo Bonzini         s->tx_req = s->codec->out.size;
3475*dd285b06SPaolo Bonzini         omap_mcbsp_tx_newdata(s);
3476*dd285b06SPaolo Bonzini     }
3477*dd285b06SPaolo Bonzini }
3478*dd285b06SPaolo Bonzini 
3479*dd285b06SPaolo Bonzini void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, I2SCodec *slave)
3480*dd285b06SPaolo Bonzini {
3481*dd285b06SPaolo Bonzini     s->codec = slave;
3482*dd285b06SPaolo Bonzini     slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0];
3483*dd285b06SPaolo Bonzini     slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0];
3484*dd285b06SPaolo Bonzini }
3485*dd285b06SPaolo Bonzini 
3486*dd285b06SPaolo Bonzini /* LED Pulse Generators */
3487*dd285b06SPaolo Bonzini struct omap_lpg_s {
3488*dd285b06SPaolo Bonzini     MemoryRegion iomem;
3489*dd285b06SPaolo Bonzini     QEMUTimer *tm;
3490*dd285b06SPaolo Bonzini 
3491*dd285b06SPaolo Bonzini     uint8_t control;
3492*dd285b06SPaolo Bonzini     uint8_t power;
3493*dd285b06SPaolo Bonzini     int64_t on;
3494*dd285b06SPaolo Bonzini     int64_t period;
3495*dd285b06SPaolo Bonzini     int clk;
3496*dd285b06SPaolo Bonzini     int cycle;
3497*dd285b06SPaolo Bonzini };
3498*dd285b06SPaolo Bonzini 
3499*dd285b06SPaolo Bonzini static void omap_lpg_tick(void *opaque)
3500*dd285b06SPaolo Bonzini {
3501*dd285b06SPaolo Bonzini     struct omap_lpg_s *s = opaque;
3502*dd285b06SPaolo Bonzini 
3503*dd285b06SPaolo Bonzini     if (s->cycle)
3504*dd285b06SPaolo Bonzini         qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->period - s->on);
3505*dd285b06SPaolo Bonzini     else
3506*dd285b06SPaolo Bonzini         qemu_mod_timer(s->tm, qemu_get_clock_ms(vm_clock) + s->on);
3507*dd285b06SPaolo Bonzini 
3508*dd285b06SPaolo Bonzini     s->cycle = !s->cycle;
3509*dd285b06SPaolo Bonzini     printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off");
3510*dd285b06SPaolo Bonzini }
3511*dd285b06SPaolo Bonzini 
3512*dd285b06SPaolo Bonzini static void omap_lpg_update(struct omap_lpg_s *s)
3513*dd285b06SPaolo Bonzini {
3514*dd285b06SPaolo Bonzini     int64_t on, period = 1, ticks = 1000;
3515*dd285b06SPaolo Bonzini     static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 };
3516*dd285b06SPaolo Bonzini 
3517*dd285b06SPaolo Bonzini     if (~s->control & (1 << 6))					/* LPGRES */
3518*dd285b06SPaolo Bonzini         on = 0;
3519*dd285b06SPaolo Bonzini     else if (s->control & (1 << 7))				/* PERM_ON */
3520*dd285b06SPaolo Bonzini         on = period;
3521*dd285b06SPaolo Bonzini     else {
3522*dd285b06SPaolo Bonzini         period = muldiv64(ticks, per[s->control & 7],		/* PERCTRL */
3523*dd285b06SPaolo Bonzini                         256 / 32);
3524*dd285b06SPaolo Bonzini         on = (s->clk && s->power) ? muldiv64(ticks,
3525*dd285b06SPaolo Bonzini                         per[(s->control >> 3) & 7], 256) : 0;	/* ONCTRL */
3526*dd285b06SPaolo Bonzini     }
3527*dd285b06SPaolo Bonzini 
3528*dd285b06SPaolo Bonzini     qemu_del_timer(s->tm);
3529*dd285b06SPaolo Bonzini     if (on == period && s->on < s->period)
3530*dd285b06SPaolo Bonzini         printf("%s: LED is on\n", __FUNCTION__);
3531*dd285b06SPaolo Bonzini     else if (on == 0 && s->on)
3532*dd285b06SPaolo Bonzini         printf("%s: LED is off\n", __FUNCTION__);
3533*dd285b06SPaolo Bonzini     else if (on && (on != s->on || period != s->period)) {
3534*dd285b06SPaolo Bonzini         s->cycle = 0;
3535*dd285b06SPaolo Bonzini         s->on = on;
3536*dd285b06SPaolo Bonzini         s->period = period;
3537*dd285b06SPaolo Bonzini         omap_lpg_tick(s);
3538*dd285b06SPaolo Bonzini         return;
3539*dd285b06SPaolo Bonzini     }
3540*dd285b06SPaolo Bonzini 
3541*dd285b06SPaolo Bonzini     s->on = on;
3542*dd285b06SPaolo Bonzini     s->period = period;
3543*dd285b06SPaolo Bonzini }
3544*dd285b06SPaolo Bonzini 
3545*dd285b06SPaolo Bonzini static void omap_lpg_reset(struct omap_lpg_s *s)
3546*dd285b06SPaolo Bonzini {
3547*dd285b06SPaolo Bonzini     s->control = 0x00;
3548*dd285b06SPaolo Bonzini     s->power = 0x00;
3549*dd285b06SPaolo Bonzini     s->clk = 1;
3550*dd285b06SPaolo Bonzini     omap_lpg_update(s);
3551*dd285b06SPaolo Bonzini }
3552*dd285b06SPaolo Bonzini 
3553*dd285b06SPaolo Bonzini static uint64_t omap_lpg_read(void *opaque, hwaddr addr,
3554*dd285b06SPaolo Bonzini                               unsigned size)
3555*dd285b06SPaolo Bonzini {
3556*dd285b06SPaolo Bonzini     struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
3557*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
3558*dd285b06SPaolo Bonzini 
3559*dd285b06SPaolo Bonzini     if (size != 1) {
3560*dd285b06SPaolo Bonzini         return omap_badwidth_read8(opaque, addr);
3561*dd285b06SPaolo Bonzini     }
3562*dd285b06SPaolo Bonzini 
3563*dd285b06SPaolo Bonzini     switch (offset) {
3564*dd285b06SPaolo Bonzini     case 0x00:	/* LCR */
3565*dd285b06SPaolo Bonzini         return s->control;
3566*dd285b06SPaolo Bonzini 
3567*dd285b06SPaolo Bonzini     case 0x04:	/* PMR */
3568*dd285b06SPaolo Bonzini         return s->power;
3569*dd285b06SPaolo Bonzini     }
3570*dd285b06SPaolo Bonzini 
3571*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
3572*dd285b06SPaolo Bonzini     return 0;
3573*dd285b06SPaolo Bonzini }
3574*dd285b06SPaolo Bonzini 
3575*dd285b06SPaolo Bonzini static void omap_lpg_write(void *opaque, hwaddr addr,
3576*dd285b06SPaolo Bonzini                            uint64_t value, unsigned size)
3577*dd285b06SPaolo Bonzini {
3578*dd285b06SPaolo Bonzini     struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
3579*dd285b06SPaolo Bonzini     int offset = addr & OMAP_MPUI_REG_MASK;
3580*dd285b06SPaolo Bonzini 
3581*dd285b06SPaolo Bonzini     if (size != 1) {
3582*dd285b06SPaolo Bonzini         return omap_badwidth_write8(opaque, addr, value);
3583*dd285b06SPaolo Bonzini     }
3584*dd285b06SPaolo Bonzini 
3585*dd285b06SPaolo Bonzini     switch (offset) {
3586*dd285b06SPaolo Bonzini     case 0x00:	/* LCR */
3587*dd285b06SPaolo Bonzini         if (~value & (1 << 6))					/* LPGRES */
3588*dd285b06SPaolo Bonzini             omap_lpg_reset(s);
3589*dd285b06SPaolo Bonzini         s->control = value & 0xff;
3590*dd285b06SPaolo Bonzini         omap_lpg_update(s);
3591*dd285b06SPaolo Bonzini         return;
3592*dd285b06SPaolo Bonzini 
3593*dd285b06SPaolo Bonzini     case 0x04:	/* PMR */
3594*dd285b06SPaolo Bonzini         s->power = value & 0x01;
3595*dd285b06SPaolo Bonzini         omap_lpg_update(s);
3596*dd285b06SPaolo Bonzini         return;
3597*dd285b06SPaolo Bonzini 
3598*dd285b06SPaolo Bonzini     default:
3599*dd285b06SPaolo Bonzini         OMAP_BAD_REG(addr);
3600*dd285b06SPaolo Bonzini         return;
3601*dd285b06SPaolo Bonzini     }
3602*dd285b06SPaolo Bonzini }
3603*dd285b06SPaolo Bonzini 
3604*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_lpg_ops = {
3605*dd285b06SPaolo Bonzini     .read = omap_lpg_read,
3606*dd285b06SPaolo Bonzini     .write = omap_lpg_write,
3607*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
3608*dd285b06SPaolo Bonzini };
3609*dd285b06SPaolo Bonzini 
3610*dd285b06SPaolo Bonzini static void omap_lpg_clk_update(void *opaque, int line, int on)
3611*dd285b06SPaolo Bonzini {
3612*dd285b06SPaolo Bonzini     struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
3613*dd285b06SPaolo Bonzini 
3614*dd285b06SPaolo Bonzini     s->clk = on;
3615*dd285b06SPaolo Bonzini     omap_lpg_update(s);
3616*dd285b06SPaolo Bonzini }
3617*dd285b06SPaolo Bonzini 
3618*dd285b06SPaolo Bonzini static struct omap_lpg_s *omap_lpg_init(MemoryRegion *system_memory,
3619*dd285b06SPaolo Bonzini                                         hwaddr base, omap_clk clk)
3620*dd285b06SPaolo Bonzini {
3621*dd285b06SPaolo Bonzini     struct omap_lpg_s *s = (struct omap_lpg_s *)
3622*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_lpg_s));
3623*dd285b06SPaolo Bonzini 
3624*dd285b06SPaolo Bonzini     s->tm = qemu_new_timer_ms(vm_clock, omap_lpg_tick, s);
3625*dd285b06SPaolo Bonzini 
3626*dd285b06SPaolo Bonzini     omap_lpg_reset(s);
3627*dd285b06SPaolo Bonzini 
3628*dd285b06SPaolo Bonzini     memory_region_init_io(&s->iomem, &omap_lpg_ops, s, "omap-lpg", 0x800);
3629*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, base, &s->iomem);
3630*dd285b06SPaolo Bonzini 
3631*dd285b06SPaolo Bonzini     omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]);
3632*dd285b06SPaolo Bonzini 
3633*dd285b06SPaolo Bonzini     return s;
3634*dd285b06SPaolo Bonzini }
3635*dd285b06SPaolo Bonzini 
3636*dd285b06SPaolo Bonzini /* MPUI Peripheral Bridge configuration */
3637*dd285b06SPaolo Bonzini static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr,
3638*dd285b06SPaolo Bonzini                                   unsigned size)
3639*dd285b06SPaolo Bonzini {
3640*dd285b06SPaolo Bonzini     if (size != 2) {
3641*dd285b06SPaolo Bonzini         return omap_badwidth_read16(opaque, addr);
3642*dd285b06SPaolo Bonzini     }
3643*dd285b06SPaolo Bonzini 
3644*dd285b06SPaolo Bonzini     if (addr == OMAP_MPUI_BASE)	/* CMR */
3645*dd285b06SPaolo Bonzini         return 0xfe4d;
3646*dd285b06SPaolo Bonzini 
3647*dd285b06SPaolo Bonzini     OMAP_BAD_REG(addr);
3648*dd285b06SPaolo Bonzini     return 0;
3649*dd285b06SPaolo Bonzini }
3650*dd285b06SPaolo Bonzini 
3651*dd285b06SPaolo Bonzini static void omap_mpui_io_write(void *opaque, hwaddr addr,
3652*dd285b06SPaolo Bonzini                                uint64_t value, unsigned size)
3653*dd285b06SPaolo Bonzini {
3654*dd285b06SPaolo Bonzini     /* FIXME: infinite loop */
3655*dd285b06SPaolo Bonzini     omap_badwidth_write16(opaque, addr, value);
3656*dd285b06SPaolo Bonzini }
3657*dd285b06SPaolo Bonzini 
3658*dd285b06SPaolo Bonzini static const MemoryRegionOps omap_mpui_io_ops = {
3659*dd285b06SPaolo Bonzini     .read = omap_mpui_io_read,
3660*dd285b06SPaolo Bonzini     .write = omap_mpui_io_write,
3661*dd285b06SPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
3662*dd285b06SPaolo Bonzini };
3663*dd285b06SPaolo Bonzini 
3664*dd285b06SPaolo Bonzini static void omap_setup_mpui_io(MemoryRegion *system_memory,
3665*dd285b06SPaolo Bonzini                                struct omap_mpu_state_s *mpu)
3666*dd285b06SPaolo Bonzini {
3667*dd285b06SPaolo Bonzini     memory_region_init_io(&mpu->mpui_io_iomem, &omap_mpui_io_ops, mpu,
3668*dd285b06SPaolo Bonzini                           "omap-mpui-io", 0x7fff);
3669*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, OMAP_MPUI_BASE,
3670*dd285b06SPaolo Bonzini                                 &mpu->mpui_io_iomem);
3671*dd285b06SPaolo Bonzini }
3672*dd285b06SPaolo Bonzini 
3673*dd285b06SPaolo Bonzini /* General chip reset */
3674*dd285b06SPaolo Bonzini static void omap1_mpu_reset(void *opaque)
3675*dd285b06SPaolo Bonzini {
3676*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
3677*dd285b06SPaolo Bonzini 
3678*dd285b06SPaolo Bonzini     omap_dma_reset(mpu->dma);
3679*dd285b06SPaolo Bonzini     omap_mpu_timer_reset(mpu->timer[0]);
3680*dd285b06SPaolo Bonzini     omap_mpu_timer_reset(mpu->timer[1]);
3681*dd285b06SPaolo Bonzini     omap_mpu_timer_reset(mpu->timer[2]);
3682*dd285b06SPaolo Bonzini     omap_wd_timer_reset(mpu->wdt);
3683*dd285b06SPaolo Bonzini     omap_os_timer_reset(mpu->os_timer);
3684*dd285b06SPaolo Bonzini     omap_lcdc_reset(mpu->lcd);
3685*dd285b06SPaolo Bonzini     omap_ulpd_pm_reset(mpu);
3686*dd285b06SPaolo Bonzini     omap_pin_cfg_reset(mpu);
3687*dd285b06SPaolo Bonzini     omap_mpui_reset(mpu);
3688*dd285b06SPaolo Bonzini     omap_tipb_bridge_reset(mpu->private_tipb);
3689*dd285b06SPaolo Bonzini     omap_tipb_bridge_reset(mpu->public_tipb);
3690*dd285b06SPaolo Bonzini     omap_dpll_reset(mpu->dpll[0]);
3691*dd285b06SPaolo Bonzini     omap_dpll_reset(mpu->dpll[1]);
3692*dd285b06SPaolo Bonzini     omap_dpll_reset(mpu->dpll[2]);
3693*dd285b06SPaolo Bonzini     omap_uart_reset(mpu->uart[0]);
3694*dd285b06SPaolo Bonzini     omap_uart_reset(mpu->uart[1]);
3695*dd285b06SPaolo Bonzini     omap_uart_reset(mpu->uart[2]);
3696*dd285b06SPaolo Bonzini     omap_mmc_reset(mpu->mmc);
3697*dd285b06SPaolo Bonzini     omap_mpuio_reset(mpu->mpuio);
3698*dd285b06SPaolo Bonzini     omap_uwire_reset(mpu->microwire);
3699*dd285b06SPaolo Bonzini     omap_pwl_reset(mpu->pwl);
3700*dd285b06SPaolo Bonzini     omap_pwt_reset(mpu->pwt);
3701*dd285b06SPaolo Bonzini     omap_rtc_reset(mpu->rtc);
3702*dd285b06SPaolo Bonzini     omap_mcbsp_reset(mpu->mcbsp1);
3703*dd285b06SPaolo Bonzini     omap_mcbsp_reset(mpu->mcbsp2);
3704*dd285b06SPaolo Bonzini     omap_mcbsp_reset(mpu->mcbsp3);
3705*dd285b06SPaolo Bonzini     omap_lpg_reset(mpu->led[0]);
3706*dd285b06SPaolo Bonzini     omap_lpg_reset(mpu->led[1]);
3707*dd285b06SPaolo Bonzini     omap_clkm_reset(mpu);
3708*dd285b06SPaolo Bonzini     cpu_reset(CPU(mpu->cpu));
3709*dd285b06SPaolo Bonzini }
3710*dd285b06SPaolo Bonzini 
3711*dd285b06SPaolo Bonzini static const struct omap_map_s {
3712*dd285b06SPaolo Bonzini     hwaddr phys_dsp;
3713*dd285b06SPaolo Bonzini     hwaddr phys_mpu;
3714*dd285b06SPaolo Bonzini     uint32_t size;
3715*dd285b06SPaolo Bonzini     const char *name;
3716*dd285b06SPaolo Bonzini } omap15xx_dsp_mm[] = {
3717*dd285b06SPaolo Bonzini     /* Strobe 0 */
3718*dd285b06SPaolo Bonzini     { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" },		/* CS0 */
3719*dd285b06SPaolo Bonzini     { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" },		/* CS1 */
3720*dd285b06SPaolo Bonzini     { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" },		/* CS3 */
3721*dd285b06SPaolo Bonzini     { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" },	/* CS4 */
3722*dd285b06SPaolo Bonzini     { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" },	/* CS5 */
3723*dd285b06SPaolo Bonzini     { 0xe1013000, 0xfffb3000, 0x800, "uWire" },			/* CS6 */
3724*dd285b06SPaolo Bonzini     { 0xe1013800, 0xfffb3800, 0x800, "I^2C" },			/* CS7 */
3725*dd285b06SPaolo Bonzini     { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" },		/* CS8 */
3726*dd285b06SPaolo Bonzini     { 0xe1014800, 0xfffb4800, 0x800, "RTC" },			/* CS9 */
3727*dd285b06SPaolo Bonzini     { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" },			/* CS10 */
3728*dd285b06SPaolo Bonzini     { 0xe1015800, 0xfffb5800, 0x800, "PWL" },			/* CS11 */
3729*dd285b06SPaolo Bonzini     { 0xe1016000, 0xfffb6000, 0x800, "PWT" },			/* CS12 */
3730*dd285b06SPaolo Bonzini     { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" },		/* CS14 */
3731*dd285b06SPaolo Bonzini     { 0xe1017800, 0xfffb7800, 0x800, "MMC" },			/* CS15 */
3732*dd285b06SPaolo Bonzini     { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" },		/* CS18 */
3733*dd285b06SPaolo Bonzini     { 0xe1019800, 0xfffb9800, 0x800, "UART3" },			/* CS19 */
3734*dd285b06SPaolo Bonzini     { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" },		/* CS25 */
3735*dd285b06SPaolo Bonzini     /* Strobe 1 */
3736*dd285b06SPaolo Bonzini     { 0xe101e000, 0xfffce000, 0x800, "GPIOs" },			/* CS28 */
3737*dd285b06SPaolo Bonzini 
3738*dd285b06SPaolo Bonzini     { 0 }
3739*dd285b06SPaolo Bonzini };
3740*dd285b06SPaolo Bonzini 
3741*dd285b06SPaolo Bonzini static void omap_setup_dsp_mapping(MemoryRegion *system_memory,
3742*dd285b06SPaolo Bonzini                                    const struct omap_map_s *map)
3743*dd285b06SPaolo Bonzini {
3744*dd285b06SPaolo Bonzini     MemoryRegion *io;
3745*dd285b06SPaolo Bonzini 
3746*dd285b06SPaolo Bonzini     for (; map->phys_dsp; map ++) {
3747*dd285b06SPaolo Bonzini         io = g_new(MemoryRegion, 1);
3748*dd285b06SPaolo Bonzini         memory_region_init_alias(io, map->name,
3749*dd285b06SPaolo Bonzini                                  system_memory, map->phys_mpu, map->size);
3750*dd285b06SPaolo Bonzini         memory_region_add_subregion(system_memory, map->phys_dsp, io);
3751*dd285b06SPaolo Bonzini     }
3752*dd285b06SPaolo Bonzini }
3753*dd285b06SPaolo Bonzini 
3754*dd285b06SPaolo Bonzini void omap_mpu_wakeup(void *opaque, int irq, int req)
3755*dd285b06SPaolo Bonzini {
3756*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
3757*dd285b06SPaolo Bonzini 
3758*dd285b06SPaolo Bonzini     if (mpu->cpu->env.halted) {
3759*dd285b06SPaolo Bonzini         cpu_interrupt(&mpu->cpu->env, CPU_INTERRUPT_EXITTB);
3760*dd285b06SPaolo Bonzini     }
3761*dd285b06SPaolo Bonzini }
3762*dd285b06SPaolo Bonzini 
3763*dd285b06SPaolo Bonzini static const struct dma_irq_map omap1_dma_irq_map[] = {
3764*dd285b06SPaolo Bonzini     { 0, OMAP_INT_DMA_CH0_6 },
3765*dd285b06SPaolo Bonzini     { 0, OMAP_INT_DMA_CH1_7 },
3766*dd285b06SPaolo Bonzini     { 0, OMAP_INT_DMA_CH2_8 },
3767*dd285b06SPaolo Bonzini     { 0, OMAP_INT_DMA_CH3 },
3768*dd285b06SPaolo Bonzini     { 0, OMAP_INT_DMA_CH4 },
3769*dd285b06SPaolo Bonzini     { 0, OMAP_INT_DMA_CH5 },
3770*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH6 },
3771*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH7 },
3772*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH8 },
3773*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH9 },
3774*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH10 },
3775*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH11 },
3776*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH12 },
3777*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH13 },
3778*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH14 },
3779*dd285b06SPaolo Bonzini     { 1, OMAP_INT_1610_DMA_CH15 }
3780*dd285b06SPaolo Bonzini };
3781*dd285b06SPaolo Bonzini 
3782*dd285b06SPaolo Bonzini /* DMA ports for OMAP1 */
3783*dd285b06SPaolo Bonzini static int omap_validate_emiff_addr(struct omap_mpu_state_s *s,
3784*dd285b06SPaolo Bonzini                 hwaddr addr)
3785*dd285b06SPaolo Bonzini {
3786*dd285b06SPaolo Bonzini     return range_covers_byte(OMAP_EMIFF_BASE, s->sdram_size, addr);
3787*dd285b06SPaolo Bonzini }
3788*dd285b06SPaolo Bonzini 
3789*dd285b06SPaolo Bonzini static int omap_validate_emifs_addr(struct omap_mpu_state_s *s,
3790*dd285b06SPaolo Bonzini                 hwaddr addr)
3791*dd285b06SPaolo Bonzini {
3792*dd285b06SPaolo Bonzini     return range_covers_byte(OMAP_EMIFS_BASE, OMAP_EMIFF_BASE - OMAP_EMIFS_BASE,
3793*dd285b06SPaolo Bonzini                              addr);
3794*dd285b06SPaolo Bonzini }
3795*dd285b06SPaolo Bonzini 
3796*dd285b06SPaolo Bonzini static int omap_validate_imif_addr(struct omap_mpu_state_s *s,
3797*dd285b06SPaolo Bonzini                 hwaddr addr)
3798*dd285b06SPaolo Bonzini {
3799*dd285b06SPaolo Bonzini     return range_covers_byte(OMAP_IMIF_BASE, s->sram_size, addr);
3800*dd285b06SPaolo Bonzini }
3801*dd285b06SPaolo Bonzini 
3802*dd285b06SPaolo Bonzini static int omap_validate_tipb_addr(struct omap_mpu_state_s *s,
3803*dd285b06SPaolo Bonzini                 hwaddr addr)
3804*dd285b06SPaolo Bonzini {
3805*dd285b06SPaolo Bonzini     return range_covers_byte(0xfffb0000, 0xffff0000 - 0xfffb0000, addr);
3806*dd285b06SPaolo Bonzini }
3807*dd285b06SPaolo Bonzini 
3808*dd285b06SPaolo Bonzini static int omap_validate_local_addr(struct omap_mpu_state_s *s,
3809*dd285b06SPaolo Bonzini                 hwaddr addr)
3810*dd285b06SPaolo Bonzini {
3811*dd285b06SPaolo Bonzini     return range_covers_byte(OMAP_LOCALBUS_BASE, 0x1000000, addr);
3812*dd285b06SPaolo Bonzini }
3813*dd285b06SPaolo Bonzini 
3814*dd285b06SPaolo Bonzini static int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s,
3815*dd285b06SPaolo Bonzini                 hwaddr addr)
3816*dd285b06SPaolo Bonzini {
3817*dd285b06SPaolo Bonzini     return range_covers_byte(0xe1010000, 0xe1020004 - 0xe1010000, addr);
3818*dd285b06SPaolo Bonzini }
3819*dd285b06SPaolo Bonzini 
3820*dd285b06SPaolo Bonzini struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
3821*dd285b06SPaolo Bonzini                 unsigned long sdram_size,
3822*dd285b06SPaolo Bonzini                 const char *core)
3823*dd285b06SPaolo Bonzini {
3824*dd285b06SPaolo Bonzini     int i;
3825*dd285b06SPaolo Bonzini     struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
3826*dd285b06SPaolo Bonzini             g_malloc0(sizeof(struct omap_mpu_state_s));
3827*dd285b06SPaolo Bonzini     qemu_irq *cpu_irq;
3828*dd285b06SPaolo Bonzini     qemu_irq dma_irqs[6];
3829*dd285b06SPaolo Bonzini     DriveInfo *dinfo;
3830*dd285b06SPaolo Bonzini     SysBusDevice *busdev;
3831*dd285b06SPaolo Bonzini 
3832*dd285b06SPaolo Bonzini     if (!core)
3833*dd285b06SPaolo Bonzini         core = "ti925t";
3834*dd285b06SPaolo Bonzini 
3835*dd285b06SPaolo Bonzini     /* Core */
3836*dd285b06SPaolo Bonzini     s->mpu_model = omap310;
3837*dd285b06SPaolo Bonzini     s->cpu = cpu_arm_init(core);
3838*dd285b06SPaolo Bonzini     if (s->cpu == NULL) {
3839*dd285b06SPaolo Bonzini         fprintf(stderr, "Unable to find CPU definition\n");
3840*dd285b06SPaolo Bonzini         exit(1);
3841*dd285b06SPaolo Bonzini     }
3842*dd285b06SPaolo Bonzini     s->sdram_size = sdram_size;
3843*dd285b06SPaolo Bonzini     s->sram_size = OMAP15XX_SRAM_SIZE;
3844*dd285b06SPaolo Bonzini 
3845*dd285b06SPaolo Bonzini     s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0];
3846*dd285b06SPaolo Bonzini 
3847*dd285b06SPaolo Bonzini     /* Clocks */
3848*dd285b06SPaolo Bonzini     omap_clk_init(s);
3849*dd285b06SPaolo Bonzini 
3850*dd285b06SPaolo Bonzini     /* Memory-mapped stuff */
3851*dd285b06SPaolo Bonzini     memory_region_init_ram(&s->emiff_ram, "omap1.dram", s->sdram_size);
3852*dd285b06SPaolo Bonzini     vmstate_register_ram_global(&s->emiff_ram);
3853*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, OMAP_EMIFF_BASE, &s->emiff_ram);
3854*dd285b06SPaolo Bonzini     memory_region_init_ram(&s->imif_ram, "omap1.sram", s->sram_size);
3855*dd285b06SPaolo Bonzini     vmstate_register_ram_global(&s->imif_ram);
3856*dd285b06SPaolo Bonzini     memory_region_add_subregion(system_memory, OMAP_IMIF_BASE, &s->imif_ram);
3857*dd285b06SPaolo Bonzini 
3858*dd285b06SPaolo Bonzini     omap_clkm_init(system_memory, 0xfffece00, 0xe1008000, s);
3859*dd285b06SPaolo Bonzini 
3860*dd285b06SPaolo Bonzini     cpu_irq = arm_pic_init_cpu(s->cpu);
3861*dd285b06SPaolo Bonzini     s->ih[0] = qdev_create(NULL, "omap-intc");
3862*dd285b06SPaolo Bonzini     qdev_prop_set_uint32(s->ih[0], "size", 0x100);
3863*dd285b06SPaolo Bonzini     qdev_prop_set_ptr(s->ih[0], "clk", omap_findclk(s, "arminth_ck"));
3864*dd285b06SPaolo Bonzini     qdev_init_nofail(s->ih[0]);
3865*dd285b06SPaolo Bonzini     busdev = SYS_BUS_DEVICE(s->ih[0]);
3866*dd285b06SPaolo Bonzini     sysbus_connect_irq(busdev, 0, cpu_irq[ARM_PIC_CPU_IRQ]);
3867*dd285b06SPaolo Bonzini     sysbus_connect_irq(busdev, 1, cpu_irq[ARM_PIC_CPU_FIQ]);
3868*dd285b06SPaolo Bonzini     sysbus_mmio_map(busdev, 0, 0xfffecb00);
3869*dd285b06SPaolo Bonzini     s->ih[1] = qdev_create(NULL, "omap-intc");
3870*dd285b06SPaolo Bonzini     qdev_prop_set_uint32(s->ih[1], "size", 0x800);
3871*dd285b06SPaolo Bonzini     qdev_prop_set_ptr(s->ih[1], "clk", omap_findclk(s, "arminth_ck"));
3872*dd285b06SPaolo Bonzini     qdev_init_nofail(s->ih[1]);
3873*dd285b06SPaolo Bonzini     busdev = SYS_BUS_DEVICE(s->ih[1]);
3874*dd285b06SPaolo Bonzini     sysbus_connect_irq(busdev, 0,
3875*dd285b06SPaolo Bonzini                        qdev_get_gpio_in(s->ih[0], OMAP_INT_15XX_IH2_IRQ));
3876*dd285b06SPaolo Bonzini     /* The second interrupt controller's FIQ output is not wired up */
3877*dd285b06SPaolo Bonzini     sysbus_mmio_map(busdev, 0, 0xfffe0000);
3878*dd285b06SPaolo Bonzini 
3879*dd285b06SPaolo Bonzini     for (i = 0; i < 6; i++) {
3880*dd285b06SPaolo Bonzini         dma_irqs[i] = qdev_get_gpio_in(s->ih[omap1_dma_irq_map[i].ih],
3881*dd285b06SPaolo Bonzini                                        omap1_dma_irq_map[i].intr);
3882*dd285b06SPaolo Bonzini     }
3883*dd285b06SPaolo Bonzini     s->dma = omap_dma_init(0xfffed800, dma_irqs, system_memory,
3884*dd285b06SPaolo Bonzini                            qdev_get_gpio_in(s->ih[0], OMAP_INT_DMA_LCD),
3885*dd285b06SPaolo Bonzini                            s, omap_findclk(s, "dma_ck"), omap_dma_3_1);
3886*dd285b06SPaolo Bonzini 
3887*dd285b06SPaolo Bonzini     s->port[emiff    ].addr_valid = omap_validate_emiff_addr;
3888*dd285b06SPaolo Bonzini     s->port[emifs    ].addr_valid = omap_validate_emifs_addr;
3889*dd285b06SPaolo Bonzini     s->port[imif     ].addr_valid = omap_validate_imif_addr;
3890*dd285b06SPaolo Bonzini     s->port[tipb     ].addr_valid = omap_validate_tipb_addr;
3891*dd285b06SPaolo Bonzini     s->port[local    ].addr_valid = omap_validate_local_addr;
3892*dd285b06SPaolo Bonzini     s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr;
3893*dd285b06SPaolo Bonzini 
3894*dd285b06SPaolo Bonzini     /* Register SDRAM and SRAM DMA ports for fast transfers.  */
3895*dd285b06SPaolo Bonzini     soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->emiff_ram),
3896*dd285b06SPaolo Bonzini                          OMAP_EMIFF_BASE, s->sdram_size);
3897*dd285b06SPaolo Bonzini     soc_dma_port_add_mem(s->dma, memory_region_get_ram_ptr(&s->imif_ram),
3898*dd285b06SPaolo Bonzini                          OMAP_IMIF_BASE, s->sram_size);
3899*dd285b06SPaolo Bonzini 
3900*dd285b06SPaolo Bonzini     s->timer[0] = omap_mpu_timer_init(system_memory, 0xfffec500,
3901*dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER1),
3902*dd285b06SPaolo Bonzini                     omap_findclk(s, "mputim_ck"));
3903*dd285b06SPaolo Bonzini     s->timer[1] = omap_mpu_timer_init(system_memory, 0xfffec600,
3904*dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER2),
3905*dd285b06SPaolo Bonzini                     omap_findclk(s, "mputim_ck"));
3906*dd285b06SPaolo Bonzini     s->timer[2] = omap_mpu_timer_init(system_memory, 0xfffec700,
3907*dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->ih[0], OMAP_INT_TIMER3),
3908*dd285b06SPaolo Bonzini                     omap_findclk(s, "mputim_ck"));
3909*dd285b06SPaolo Bonzini 
3910*dd285b06SPaolo Bonzini     s->wdt = omap_wd_timer_init(system_memory, 0xfffec800,
3911*dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->ih[0], OMAP_INT_WD_TIMER),
3912*dd285b06SPaolo Bonzini                     omap_findclk(s, "armwdt_ck"));
3913*dd285b06SPaolo Bonzini 
3914*dd285b06SPaolo Bonzini     s->os_timer = omap_os_timer_init(system_memory, 0xfffb9000,
3915*dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->ih[1], OMAP_INT_OS_TIMER),
3916*dd285b06SPaolo Bonzini                     omap_findclk(s, "clk32-kHz"));
3917*dd285b06SPaolo Bonzini 
3918*dd285b06SPaolo Bonzini     s->lcd = omap_lcdc_init(system_memory, 0xfffec000,
3919*dd285b06SPaolo Bonzini                             qdev_get_gpio_in(s->ih[0], OMAP_INT_LCD_CTRL),
3920*dd285b06SPaolo Bonzini                             omap_dma_get_lcdch(s->dma),
3921*dd285b06SPaolo Bonzini                             omap_findclk(s, "lcd_ck"));
3922*dd285b06SPaolo Bonzini 
3923*dd285b06SPaolo Bonzini     omap_ulpd_pm_init(system_memory, 0xfffe0800, s);
3924*dd285b06SPaolo Bonzini     omap_pin_cfg_init(system_memory, 0xfffe1000, s);
3925*dd285b06SPaolo Bonzini     omap_id_init(system_memory, s);
3926*dd285b06SPaolo Bonzini 
3927*dd285b06SPaolo Bonzini     omap_mpui_init(system_memory, 0xfffec900, s);
3928*dd285b06SPaolo Bonzini 
3929*dd285b06SPaolo Bonzini     s->private_tipb = omap_tipb_bridge_init(system_memory, 0xfffeca00,
3930*dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PRIV),
3931*dd285b06SPaolo Bonzini                     omap_findclk(s, "tipb_ck"));
3932*dd285b06SPaolo Bonzini     s->public_tipb = omap_tipb_bridge_init(system_memory, 0xfffed300,
3933*dd285b06SPaolo Bonzini                     qdev_get_gpio_in(s->ih[0], OMAP_INT_BRIDGE_PUB),
3934*dd285b06SPaolo Bonzini                     omap_findclk(s, "tipb_ck"));
3935*dd285b06SPaolo Bonzini 
3936*dd285b06SPaolo Bonzini     omap_tcmi_init(system_memory, 0xfffecc00, s);
3937*dd285b06SPaolo Bonzini 
3938*dd285b06SPaolo Bonzini     s->uart[0] = omap_uart_init(0xfffb0000,
3939*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[1], OMAP_INT_UART1),
3940*dd285b06SPaolo Bonzini                     omap_findclk(s, "uart1_ck"),
3941*dd285b06SPaolo Bonzini                     omap_findclk(s, "uart1_ck"),
3942*dd285b06SPaolo Bonzini                     s->drq[OMAP_DMA_UART1_TX], s->drq[OMAP_DMA_UART1_RX],
3943*dd285b06SPaolo Bonzini                     "uart1",
3944*dd285b06SPaolo Bonzini                     serial_hds[0]);
3945*dd285b06SPaolo Bonzini     s->uart[1] = omap_uart_init(0xfffb0800,
3946*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[1], OMAP_INT_UART2),
3947*dd285b06SPaolo Bonzini                     omap_findclk(s, "uart2_ck"),
3948*dd285b06SPaolo Bonzini                     omap_findclk(s, "uart2_ck"),
3949*dd285b06SPaolo Bonzini                     s->drq[OMAP_DMA_UART2_TX], s->drq[OMAP_DMA_UART2_RX],
3950*dd285b06SPaolo Bonzini                     "uart2",
3951*dd285b06SPaolo Bonzini                     serial_hds[0] ? serial_hds[1] : NULL);
3952*dd285b06SPaolo Bonzini     s->uart[2] = omap_uart_init(0xfffb9800,
3953*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[0], OMAP_INT_UART3),
3954*dd285b06SPaolo Bonzini                     omap_findclk(s, "uart3_ck"),
3955*dd285b06SPaolo Bonzini                     omap_findclk(s, "uart3_ck"),
3956*dd285b06SPaolo Bonzini                     s->drq[OMAP_DMA_UART3_TX], s->drq[OMAP_DMA_UART3_RX],
3957*dd285b06SPaolo Bonzini                     "uart3",
3958*dd285b06SPaolo Bonzini                     serial_hds[0] && serial_hds[1] ? serial_hds[2] : NULL);
3959*dd285b06SPaolo Bonzini 
3960*dd285b06SPaolo Bonzini     s->dpll[0] = omap_dpll_init(system_memory, 0xfffecf00,
3961*dd285b06SPaolo Bonzini                                 omap_findclk(s, "dpll1"));
3962*dd285b06SPaolo Bonzini     s->dpll[1] = omap_dpll_init(system_memory, 0xfffed000,
3963*dd285b06SPaolo Bonzini                                 omap_findclk(s, "dpll2"));
3964*dd285b06SPaolo Bonzini     s->dpll[2] = omap_dpll_init(system_memory, 0xfffed100,
3965*dd285b06SPaolo Bonzini                                 omap_findclk(s, "dpll3"));
3966*dd285b06SPaolo Bonzini 
3967*dd285b06SPaolo Bonzini     dinfo = drive_get(IF_SD, 0, 0);
3968*dd285b06SPaolo Bonzini     if (!dinfo) {
3969*dd285b06SPaolo Bonzini         fprintf(stderr, "qemu: missing SecureDigital device\n");
3970*dd285b06SPaolo Bonzini         exit(1);
3971*dd285b06SPaolo Bonzini     }
3972*dd285b06SPaolo Bonzini     s->mmc = omap_mmc_init(0xfffb7800, system_memory, dinfo->bdrv,
3973*dd285b06SPaolo Bonzini                            qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN),
3974*dd285b06SPaolo Bonzini                            &s->drq[OMAP_DMA_MMC_TX],
3975*dd285b06SPaolo Bonzini                     omap_findclk(s, "mmc_ck"));
3976*dd285b06SPaolo Bonzini 
3977*dd285b06SPaolo Bonzini     s->mpuio = omap_mpuio_init(system_memory, 0xfffb5000,
3978*dd285b06SPaolo Bonzini                                qdev_get_gpio_in(s->ih[1], OMAP_INT_KEYBOARD),
3979*dd285b06SPaolo Bonzini                                qdev_get_gpio_in(s->ih[1], OMAP_INT_MPUIO),
3980*dd285b06SPaolo Bonzini                                s->wakeup, omap_findclk(s, "clk32-kHz"));
3981*dd285b06SPaolo Bonzini 
3982*dd285b06SPaolo Bonzini     s->gpio = qdev_create(NULL, "omap-gpio");
3983*dd285b06SPaolo Bonzini     qdev_prop_set_int32(s->gpio, "mpu_model", s->mpu_model);
3984*dd285b06SPaolo Bonzini     qdev_prop_set_ptr(s->gpio, "clk", omap_findclk(s, "arm_gpio_ck"));
3985*dd285b06SPaolo Bonzini     qdev_init_nofail(s->gpio);
3986*dd285b06SPaolo Bonzini     sysbus_connect_irq(SYS_BUS_DEVICE(s->gpio), 0,
3987*dd285b06SPaolo Bonzini                        qdev_get_gpio_in(s->ih[0], OMAP_INT_GPIO_BANK1));
3988*dd285b06SPaolo Bonzini     sysbus_mmio_map(SYS_BUS_DEVICE(s->gpio), 0, 0xfffce000);
3989*dd285b06SPaolo Bonzini 
3990*dd285b06SPaolo Bonzini     s->microwire = omap_uwire_init(system_memory, 0xfffb3000,
3991*dd285b06SPaolo Bonzini                                    qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireTX),
3992*dd285b06SPaolo Bonzini                                    qdev_get_gpio_in(s->ih[1], OMAP_INT_uWireRX),
3993*dd285b06SPaolo Bonzini                     s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck"));
3994*dd285b06SPaolo Bonzini 
3995*dd285b06SPaolo Bonzini     s->pwl = omap_pwl_init(system_memory, 0xfffb5800,
3996*dd285b06SPaolo Bonzini                            omap_findclk(s, "armxor_ck"));
3997*dd285b06SPaolo Bonzini     s->pwt = omap_pwt_init(system_memory, 0xfffb6000,
3998*dd285b06SPaolo Bonzini                            omap_findclk(s, "armxor_ck"));
3999*dd285b06SPaolo Bonzini 
4000*dd285b06SPaolo Bonzini     s->i2c[0] = qdev_create(NULL, "omap_i2c");
4001*dd285b06SPaolo Bonzini     qdev_prop_set_uint8(s->i2c[0], "revision", 0x11);
4002*dd285b06SPaolo Bonzini     qdev_prop_set_ptr(s->i2c[0], "fclk", omap_findclk(s, "mpuper_ck"));
4003*dd285b06SPaolo Bonzini     qdev_init_nofail(s->i2c[0]);
4004*dd285b06SPaolo Bonzini     busdev = SYS_BUS_DEVICE(s->i2c[0]);
4005*dd285b06SPaolo Bonzini     sysbus_connect_irq(busdev, 0, qdev_get_gpio_in(s->ih[1], OMAP_INT_I2C));
4006*dd285b06SPaolo Bonzini     sysbus_connect_irq(busdev, 1, s->drq[OMAP_DMA_I2C_TX]);
4007*dd285b06SPaolo Bonzini     sysbus_connect_irq(busdev, 2, s->drq[OMAP_DMA_I2C_RX]);
4008*dd285b06SPaolo Bonzini     sysbus_mmio_map(busdev, 0, 0xfffb3800);
4009*dd285b06SPaolo Bonzini 
4010*dd285b06SPaolo Bonzini     s->rtc = omap_rtc_init(system_memory, 0xfffb4800,
4011*dd285b06SPaolo Bonzini                            qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_TIMER),
4012*dd285b06SPaolo Bonzini                            qdev_get_gpio_in(s->ih[1], OMAP_INT_RTC_ALARM),
4013*dd285b06SPaolo Bonzini                     omap_findclk(s, "clk32-kHz"));
4014*dd285b06SPaolo Bonzini 
4015*dd285b06SPaolo Bonzini     s->mcbsp1 = omap_mcbsp_init(system_memory, 0xfffb1800,
4016*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1TX),
4017*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP1RX),
4018*dd285b06SPaolo Bonzini                     &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck"));
4019*dd285b06SPaolo Bonzini     s->mcbsp2 = omap_mcbsp_init(system_memory, 0xfffb1000,
4020*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[0],
4021*dd285b06SPaolo Bonzini                                                  OMAP_INT_310_McBSP2_TX),
4022*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[0],
4023*dd285b06SPaolo Bonzini                                                  OMAP_INT_310_McBSP2_RX),
4024*dd285b06SPaolo Bonzini                     &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck"));
4025*dd285b06SPaolo Bonzini     s->mcbsp3 = omap_mcbsp_init(system_memory, 0xfffb7000,
4026*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3TX),
4027*dd285b06SPaolo Bonzini                                 qdev_get_gpio_in(s->ih[1], OMAP_INT_McBSP3RX),
4028*dd285b06SPaolo Bonzini                     &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
4029*dd285b06SPaolo Bonzini 
4030*dd285b06SPaolo Bonzini     s->led[0] = omap_lpg_init(system_memory,
4031*dd285b06SPaolo Bonzini                               0xfffbd000, omap_findclk(s, "clk32-kHz"));
4032*dd285b06SPaolo Bonzini     s->led[1] = omap_lpg_init(system_memory,
4033*dd285b06SPaolo Bonzini                               0xfffbd800, omap_findclk(s, "clk32-kHz"));
4034*dd285b06SPaolo Bonzini 
4035*dd285b06SPaolo Bonzini     /* Register mappings not currenlty implemented:
4036*dd285b06SPaolo Bonzini      * MCSI2 Comm	fffb2000 - fffb27ff (not mapped on OMAP310)
4037*dd285b06SPaolo Bonzini      * MCSI1 Bluetooth	fffb2800 - fffb2fff (not mapped on OMAP310)
4038*dd285b06SPaolo Bonzini      * USB W2FC		fffb4000 - fffb47ff
4039*dd285b06SPaolo Bonzini      * Camera Interface	fffb6800 - fffb6fff
4040*dd285b06SPaolo Bonzini      * USB Host		fffba000 - fffba7ff
4041*dd285b06SPaolo Bonzini      * FAC		fffba800 - fffbafff
4042*dd285b06SPaolo Bonzini      * HDQ/1-Wire	fffbc000 - fffbc7ff
4043*dd285b06SPaolo Bonzini      * TIPB switches	fffbc800 - fffbcfff
4044*dd285b06SPaolo Bonzini      * Mailbox		fffcf000 - fffcf7ff
4045*dd285b06SPaolo Bonzini      * Local bus IF	fffec100 - fffec1ff
4046*dd285b06SPaolo Bonzini      * Local bus MMU	fffec200 - fffec2ff
4047*dd285b06SPaolo Bonzini      * DSP MMU		fffed200 - fffed2ff
4048*dd285b06SPaolo Bonzini      */
4049*dd285b06SPaolo Bonzini 
4050*dd285b06SPaolo Bonzini     omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm);
4051*dd285b06SPaolo Bonzini     omap_setup_mpui_io(system_memory, s);
4052*dd285b06SPaolo Bonzini 
4053*dd285b06SPaolo Bonzini     qemu_register_reset(omap1_mpu_reset, s);
4054*dd285b06SPaolo Bonzini 
4055*dd285b06SPaolo Bonzini     return s;
4056*dd285b06SPaolo Bonzini }
4057