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