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