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