?? omap.c
字號:
case 0x08: /* READ_TIM */ return omap_timer_read(s); } OMAP_BAD_REG(addr); return 0;}static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr, uint32_t value){ struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque; int offset = addr - s->base; switch (offset) { case 0x00: /* CNTL_TIMER */ omap_timer_sync(s); s->enable = (value >> 5) & 1; s->ptv = (value >> 2) & 7; s->ar = (value >> 1) & 1; s->st = value & 1; omap_timer_update(s); return; case 0x04: /* LOAD_TIM */ s->reset_val = value; return; case 0x08: /* READ_TIM */ OMAP_RO_REG(addr); break; default: OMAP_BAD_REG(addr); }}static CPUReadMemoryFunc *omap_mpu_timer_readfn[] = { omap_badwidth_read32, omap_badwidth_read32, omap_mpu_timer_read,};static CPUWriteMemoryFunc *omap_mpu_timer_writefn[] = { omap_badwidth_write32, omap_badwidth_write32, omap_mpu_timer_write,};static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s){ qemu_del_timer(s->timer); s->enable = 0; s->reset_val = 31337; s->val = 0; s->ptv = 0; s->ar = 0; s->st = 0; s->it_ena = 1;}struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base, qemu_irq irq, omap_clk clk){ int iomemtype; struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) qemu_mallocz(sizeof(struct omap_mpu_timer_s)); s->irq = irq; s->clk = clk; s->base = base; s->timer = qemu_new_timer(vm_clock, omap_timer_tick, s); omap_mpu_timer_reset(s); omap_timer_clk_setup(s); iomemtype = cpu_register_io_memory(0, omap_mpu_timer_readfn, omap_mpu_timer_writefn, s); cpu_register_physical_memory(s->base, 0x100, iomemtype); return s;}/* Watchdog timer */struct omap_watchdog_timer_s { struct omap_mpu_timer_s timer; uint8_t last_wr; int mode; int free; int reset;};static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr){ struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; int offset = addr - s->timer.base; switch (offset) { case 0x00: /* CNTL_TIMER */ return (s->timer.ptv << 9) | (s->timer.ar << 8) | (s->timer.st << 7) | (s->free << 1); case 0x04: /* READ_TIMER */ return omap_timer_read(&s->timer); case 0x08: /* TIMER_MODE */ return s->mode << 15; } OMAP_BAD_REG(addr); return 0;}static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, uint32_t value){ struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque; int offset = addr - s->timer.base; switch (offset) { case 0x00: /* CNTL_TIMER */ omap_timer_sync(&s->timer); s->timer.ptv = (value >> 9) & 7; s->timer.ar = (value >> 8) & 1; s->timer.st = (value >> 7) & 1; s->free = (value >> 1) & 1; omap_timer_update(&s->timer); break; case 0x04: /* LOAD_TIMER */ s->timer.reset_val = value & 0xffff; break; case 0x08: /* TIMER_MODE */ if (!s->mode && ((value >> 15) & 1)) omap_clk_get(s->timer.clk); s->mode |= (value >> 15) & 1; if (s->last_wr == 0xf5) { if ((value & 0xff) == 0xa0) { if (s->mode) { s->mode = 0; omap_clk_put(s->timer.clk); } } else { /* XXX: on T|E hardware somehow this has no effect, * on Zire 71 it works as specified. */ s->reset = 1; qemu_system_reset_request(); } } s->last_wr = value & 0xff; break; default: OMAP_BAD_REG(addr); }}static CPUReadMemoryFunc *omap_wd_timer_readfn[] = { omap_badwidth_read16, omap_wd_timer_read, omap_badwidth_read16,};static CPUWriteMemoryFunc *omap_wd_timer_writefn[] = { omap_badwidth_write16, omap_wd_timer_write, omap_badwidth_write16,};static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s){ qemu_del_timer(s->timer.timer); if (!s->mode) omap_clk_get(s->timer.clk); s->mode = 1; s->free = 1; s->reset = 0; s->timer.enable = 1; s->timer.it_ena = 1; s->timer.reset_val = 0xffff; s->timer.val = 0; s->timer.st = 0; s->timer.ptv = 0; s->timer.ar = 0; omap_timer_update(&s->timer);}struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base, qemu_irq irq, omap_clk clk){ int iomemtype; struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) qemu_mallocz(sizeof(struct omap_watchdog_timer_s)); s->timer.irq = irq; s->timer.clk = clk; s->timer.base = base; s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer); omap_wd_timer_reset(s); omap_timer_clk_setup(&s->timer); iomemtype = cpu_register_io_memory(0, omap_wd_timer_readfn, omap_wd_timer_writefn, s); cpu_register_physical_memory(s->timer.base, 0x100, iomemtype); return s;}/* 32-kHz timer */struct omap_32khz_timer_s { struct omap_mpu_timer_s timer;};static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr){ struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* TVR */ return s->timer.reset_val; case 0x04: /* TCR */ return omap_timer_read(&s->timer); case 0x08: /* CR */ return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st; default: break; } OMAP_BAD_REG(addr); return 0;}static void omap_os_timer_write(void *opaque, target_phys_addr_t addr, uint32_t value){ struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque; int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { case 0x00: /* TVR */ s->timer.reset_val = value & 0x00ffffff; break; case 0x04: /* TCR */ OMAP_RO_REG(addr); break; case 0x08: /* CR */ s->timer.ar = (value >> 3) & 1; s->timer.it_ena = (value >> 2) & 1; if (s->timer.st != (value & 1) || (value & 2)) { omap_timer_sync(&s->timer); s->timer.enable = value & 1; s->timer.st = value & 1; omap_timer_update(&s->timer); } break; default: OMAP_BAD_REG(addr); }}static CPUReadMemoryFunc *omap_os_timer_readfn[] = { omap_badwidth_read32, omap_badwidth_read32, omap_os_timer_read,};static CPUWriteMemoryFunc *omap_os_timer_writefn[] = { omap_badwidth_write32, omap_badwidth_write32, omap_os_timer_write,};static void omap_os_timer_reset(struct omap_32khz_timer_s *s){ qemu_del_timer(s->timer.timer); s->timer.enable = 0; s->timer.it_ena = 0; s->timer.reset_val = 0x00ffffff; s->timer.val = 0; s->timer.st = 0; s->timer.ptv = 0; s->timer.ar = 1;}struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base, qemu_irq irq, omap_clk clk){ int iomemtype; struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) qemu_mallocz(sizeof(struct omap_32khz_timer_s)); s->timer.irq = irq; s->timer.clk = clk; s->timer.base = base; s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer); omap_os_timer_reset(s); omap_timer_clk_setup(&s->timer); iomemtype = cpu_register_io_memory(0, omap_os_timer_readfn, omap_os_timer_writefn, s); cpu_register_physical_memory(s->timer.base, 0x800, iomemtype); return s;}/* Ultra Low-Power Device Module */static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr){ struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; int offset = addr - s->ulpd_pm_base; uint16_t ret; switch (offset) { case 0x14: /* IT_STATUS */ ret = s->ulpd_pm_regs[offset >> 2]; s->ulpd_pm_regs[offset >> 2] = 0; qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]); return ret; case 0x18: /* Reserved */ case 0x1c: /* Reserved */ case 0x20: /* Reserved */ case 0x28: /* Reserved */ case 0x2c: /* Reserved */ OMAP_BAD_REG(addr); case 0x00: /* COUNTER_32_LSB */ case 0x04: /* COUNTER_32_MSB */ case 0x08: /* COUNTER_HIGH_FREQ_LSB */ case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ case 0x10: /* GAUGING_CTRL */ case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ case 0x30: /* CLOCK_CTRL */ case 0x34: /* SOFT_REQ */ case 0x38: /* COUNTER_32_FIQ */ case 0x3c: /* DPLL_CTRL */ case 0x40: /* STATUS_REQ */ /* XXX: check clk::usecount state for every clock */ case 0x48: /* LOCL_TIME */ case 0x4c: /* APLL_CTRL */ case 0x50: /* POWER_CTRL */ return s->ulpd_pm_regs[offset >> 2]; } OMAP_BAD_REG(addr); return 0;}static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s, uint16_t diff, uint16_t value){ if (diff & (1 << 4)) /* USB_MCLK_EN */ omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1); if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1);}static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, uint16_t diff, uint16_t value){ if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1); if (diff & (1 << 1)) /* SOFT_COM_REQ */ omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1); if (diff & (1 << 2)) /* SOFT_SDW_REQ */ omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1); if (diff & (1 << 3)) /* SOFT_USB_REQ */ omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1);}static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr, uint32_t value){ struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque; int offset = addr - s->ulpd_pm_base; int64_t now, ticks; int div, mult; static const int bypass_div[4] = { 1, 2, 4, 4 }; uint16_t diff; switch (offset) { case 0x00: /* COUNTER_32_LSB */ case 0x04: /* COUNTER_32_MSB */ case 0x08: /* COUNTER_HIGH_FREQ_LSB */ case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ case 0x14: /* IT_STATUS */ case 0x40: /* STATUS_REQ */ OMAP_RO_REG(addr); break; case 0x10: /* GAUGING_CTRL */ /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ if ((s->ulpd_pm_regs[offset >> 2] ^ value) & 1) { now = qemu_get_clock(vm_clock); if (value & 1) s->ulpd_gauge_start = now; else { now -= s->ulpd_gauge_start; /* 32-kHz ticks */ ticks = muldiv64(now, 32768, ticks_per_sec); s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; if (ticks >> 32) /* OVERFLOW_32K */ s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; /* High frequency ticks */ ticks = muldiv64(now, 12000000, ticks_per_sec); s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; if (ticks >> 32) /* OVERFLOW_HI_FREQ */ s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1; s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]); } } s->ulpd_pm_regs[offset >> 2] = value; break; case 0x18: /* Reserved */ case 0x1c: /* Reserved */ case 0x20: /* Reserved */ case 0x28: /* Reserved */ case 0x2c: /* Reserved */ OMAP_BAD_REG(addr); case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ case 0x38: /* COUNTER_32_FIQ */ case 0x48: /* LOCL_TIME */ case 0x50: /* POWER_CTRL */ s->ulpd_pm_regs[offset >> 2] = value; break; case 0x30: /* CLOCK_CTRL */ diff = s->ulpd_pm_regs[offset >> 2] ^ value; s->ulpd_pm_regs[offset >> 2] = value & 0x3f; omap_ulpd_clk_update(s, diff, value); break; case 0x34: /* SOFT_REQ */ diff = s->ulpd_pm_regs[offset >> 2] ^ value; s->ulpd_pm_regs[offset >> 2] = value & 0x1f; omap_ulpd_req_update(s, diff, value); break; case 0x3c: /* DPLL_CTRL */ /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is * omitted altogether, probably a typo. */ /* This register has identical semantics with DPLL(1:3) control * registers, see omap_dpll_write() */ diff = s->ulpd_pm_regs[offset >> 2] & value; s->ulpd_pm_regs[offset >> 2] = value & 0x2fff; if (diff & (0x3ff << 2)) { if (value & (1 << 4)) { /* PLL_ENABLE */ div = ((value >> 5) & 3) + 1; /* PLL_DIV */ mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -