omap1.c

来自「xen虚拟机源代码安装包」· C语言 代码 · 共 2,284 行 · 第 1/5 页

C
2,284
字号
/* * TI OMAP processors emulation. * * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 or * (at your option) version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */#include "hw.h"#include "arm-misc.h"#include "omap.h"#include "sysemu.h"#include "qemu-timer.h"#include "qemu-char.h"/* We use pc-style serial ports.  */#include "pc.h"/* Should signal the TCMI/GPMC */uint32_t omap_badwidth_read8(void *opaque, target_phys_addr_t addr){    uint8_t ret;    OMAP_8B_REG(addr);    cpu_physical_memory_read(addr, (void *) &ret, 1);    return ret;}void omap_badwidth_write8(void *opaque, target_phys_addr_t addr,                uint32_t value){    uint8_t val8 = value;    OMAP_8B_REG(addr);    cpu_physical_memory_write(addr, (void *) &val8, 1);}uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr){    uint16_t ret;    OMAP_16B_REG(addr);    cpu_physical_memory_read(addr, (void *) &ret, 2);    return ret;}void omap_badwidth_write16(void *opaque, target_phys_addr_t addr,                uint32_t value){    uint16_t val16 = value;    OMAP_16B_REG(addr);    cpu_physical_memory_write(addr, (void *) &val16, 2);}uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr){    uint32_t ret;    OMAP_32B_REG(addr);    cpu_physical_memory_read(addr, (void *) &ret, 4);    return ret;}void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,                uint32_t value){    OMAP_32B_REG(addr);    cpu_physical_memory_write(addr, (void *) &value, 4);}/* Interrupt Handlers */struct omap_intr_handler_bank_s {    uint32_t irqs;    uint32_t inputs;    uint32_t mask;    uint32_t fiq;    uint32_t sens_edge;    uint32_t swi;    unsigned char priority[32];};struct omap_intr_handler_s {    qemu_irq *pins;    qemu_irq parent_intr[2];    target_phys_addr_t base;    unsigned char nbanks;    int level_only;    /* state */    uint32_t new_agr[2];    int sir_intr[2];    int autoidle;    uint32_t mask;    struct omap_intr_handler_bank_s bank[];};static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq){    int i, j, sir_intr, p_intr, p, f;    uint32_t level;    sir_intr = 0;    p_intr = 255;    /* Find the interrupt line with the highest dynamic priority.     * Note: 0 denotes the hightest priority.     * If all interrupts have the same priority, the default order is IRQ_N,     * IRQ_N-1,...,IRQ_0. */    for (j = 0; j < s->nbanks; ++j) {        level = s->bank[j].irqs & ~s->bank[j].mask &                (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq);        for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f,                        level >>= f) {            p = s->bank[j].priority[i];            if (p <= p_intr) {                p_intr = p;                sir_intr = 32 * j + i;            }            f = ffs(level >> 1);        }    }    s->sir_intr[is_fiq] = sir_intr;}static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq){    int i;    uint32_t has_intr = 0;    for (i = 0; i < s->nbanks; ++i)        has_intr |= s->bank[i].irqs & ~s->bank[i].mask &                (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq);    if (s->new_agr[is_fiq] & has_intr & s->mask) {        s->new_agr[is_fiq] = 0;        omap_inth_sir_update(s, is_fiq);        qemu_set_irq(s->parent_intr[is_fiq], 1);    }}#define INT_FALLING_EDGE	0#define INT_LOW_LEVEL		1static void omap_set_intr(void *opaque, int irq, int req){    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;    uint32_t rise;    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];    int n = irq & 31;    if (req) {        rise = ~bank->irqs & (1 << n);        if (~bank->sens_edge & (1 << n))            rise &= ~bank->inputs;        bank->inputs |= (1 << n);        if (rise) {            bank->irqs |= rise;            omap_inth_update(ih, 0);            omap_inth_update(ih, 1);        }    } else {        rise = bank->sens_edge & bank->irqs & (1 << n);        bank->irqs &= ~rise;        bank->inputs &= ~(1 << n);    }}/* Simplified version with no edge detection */static void omap_set_intr_noedge(void *opaque, int irq, int req){    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;    uint32_t rise;    struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5];    int n = irq & 31;    if (req) {        rise = ~bank->inputs & (1 << n);        if (rise) {            bank->irqs |= bank->inputs |= rise;            omap_inth_update(ih, 0);            omap_inth_update(ih, 1);        }    } else        bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi;}static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr){    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;    int i, offset = addr - s->base;    int bank_no = offset >> 8;    int line_no;    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];    offset &= 0xff;    switch (offset) {    case 0x00:	/* ITR */        return bank->irqs;    case 0x04:	/* MIR */        return bank->mask;    case 0x10:	/* SIR_IRQ_CODE */    case 0x14:  /* SIR_FIQ_CODE */        if (bank_no != 0)            break;        line_no = s->sir_intr[(offset - 0x10) >> 2];        bank = &s->bank[line_no >> 5];        i = line_no & 31;        if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE)            bank->irqs &= ~(1 << i);        return line_no;    case 0x18:	/* CONTROL_REG */        if (bank_no != 0)            break;        return 0;    case 0x1c:	/* ILR0 */    case 0x20:	/* ILR1 */    case 0x24:	/* ILR2 */    case 0x28:	/* ILR3 */    case 0x2c:	/* ILR4 */    case 0x30:	/* ILR5 */    case 0x34:	/* ILR6 */    case 0x38:	/* ILR7 */    case 0x3c:	/* ILR8 */    case 0x40:	/* ILR9 */    case 0x44:	/* ILR10 */    case 0x48:	/* ILR11 */    case 0x4c:	/* ILR12 */    case 0x50:	/* ILR13 */    case 0x54:	/* ILR14 */    case 0x58:	/* ILR15 */    case 0x5c:	/* ILR16 */    case 0x60:	/* ILR17 */    case 0x64:	/* ILR18 */    case 0x68:	/* ILR19 */    case 0x6c:	/* ILR20 */    case 0x70:	/* ILR21 */    case 0x74:	/* ILR22 */    case 0x78:	/* ILR23 */    case 0x7c:	/* ILR24 */    case 0x80:	/* ILR25 */    case 0x84:	/* ILR26 */    case 0x88:	/* ILR27 */    case 0x8c:	/* ILR28 */    case 0x90:	/* ILR29 */    case 0x94:	/* ILR30 */    case 0x98:	/* ILR31 */        i = (offset - 0x1c) >> 2;        return (bank->priority[i] << 2) |                (((bank->sens_edge >> i) & 1) << 1) |                ((bank->fiq >> i) & 1);    case 0x9c:	/* ISR */        return 0x00000000;    }    OMAP_BAD_REG(addr);    return 0;}static void omap_inth_write(void *opaque, target_phys_addr_t addr,                uint32_t value){    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;    int i, offset = addr - s->base;    int bank_no = offset >> 8;    struct omap_intr_handler_bank_s *bank = &s->bank[bank_no];    offset &= 0xff;    switch (offset) {    case 0x00:	/* ITR */        /* Important: ignore the clearing if the IRQ is level-triggered and           the input bit is 1 */        bank->irqs &= value | (bank->inputs & bank->sens_edge);        return;    case 0x04:	/* MIR */        bank->mask = value;        omap_inth_update(s, 0);        omap_inth_update(s, 1);        return;    case 0x10:	/* SIR_IRQ_CODE */    case 0x14:	/* SIR_FIQ_CODE */        OMAP_RO_REG(addr);        break;    case 0x18:	/* CONTROL_REG */        if (bank_no != 0)            break;        if (value & 2) {            qemu_set_irq(s->parent_intr[1], 0);            s->new_agr[1] = ~0;            omap_inth_update(s, 1);        }        if (value & 1) {            qemu_set_irq(s->parent_intr[0], 0);            s->new_agr[0] = ~0;            omap_inth_update(s, 0);        }        return;    case 0x1c:	/* ILR0 */    case 0x20:	/* ILR1 */    case 0x24:	/* ILR2 */    case 0x28:	/* ILR3 */    case 0x2c:	/* ILR4 */    case 0x30:	/* ILR5 */    case 0x34:	/* ILR6 */    case 0x38:	/* ILR7 */    case 0x3c:	/* ILR8 */    case 0x40:	/* ILR9 */    case 0x44:	/* ILR10 */    case 0x48:	/* ILR11 */    case 0x4c:	/* ILR12 */    case 0x50:	/* ILR13 */    case 0x54:	/* ILR14 */    case 0x58:	/* ILR15 */    case 0x5c:	/* ILR16 */    case 0x60:	/* ILR17 */    case 0x64:	/* ILR18 */    case 0x68:	/* ILR19 */    case 0x6c:	/* ILR20 */    case 0x70:	/* ILR21 */    case 0x74:	/* ILR22 */    case 0x78:	/* ILR23 */    case 0x7c:	/* ILR24 */    case 0x80:	/* ILR25 */    case 0x84:	/* ILR26 */    case 0x88:	/* ILR27 */    case 0x8c:	/* ILR28 */    case 0x90:	/* ILR29 */    case 0x94:	/* ILR30 */    case 0x98:	/* ILR31 */        i = (offset - 0x1c) >> 2;        bank->priority[i] = (value >> 2) & 0x1f;        bank->sens_edge &= ~(1 << i);        bank->sens_edge |= ((value >> 1) & 1) << i;        bank->fiq &= ~(1 << i);        bank->fiq |= (value & 1) << i;        return;    case 0x9c:	/* ISR */        for (i = 0; i < 32; i ++)            if (value & (1 << i)) {                omap_set_intr(s, 32 * bank_no + i, 1);                return;            }        return;    }    OMAP_BAD_REG(addr);}static CPUReadMemoryFunc *omap_inth_readfn[] = {    omap_badwidth_read32,    omap_badwidth_read32,    omap_inth_read,};static CPUWriteMemoryFunc *omap_inth_writefn[] = {    omap_inth_write,    omap_inth_write,    omap_inth_write,};void omap_inth_reset(struct omap_intr_handler_s *s){    int i;    for (i = 0; i < s->nbanks; ++i){        s->bank[i].irqs = 0x00000000;        s->bank[i].mask = 0xffffffff;        s->bank[i].sens_edge = 0x00000000;        s->bank[i].fiq = 0x00000000;        s->bank[i].inputs = 0x00000000;        s->bank[i].swi = 0x00000000;        memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority));        if (s->level_only)            s->bank[i].sens_edge = 0xffffffff;    }    s->new_agr[0] = ~0;    s->new_agr[1] = ~0;    s->sir_intr[0] = 0;    s->sir_intr[1] = 0;    s->autoidle = 0;    s->mask = ~0;    qemu_set_irq(s->parent_intr[0], 0);    qemu_set_irq(s->parent_intr[1], 0);}struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,                unsigned long size, unsigned char nbanks, qemu_irq **pins,                qemu_irq parent_irq, qemu_irq parent_fiq, omap_clk clk){    int iomemtype;    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)            qemu_mallocz(sizeof(struct omap_intr_handler_s) +                            sizeof(struct omap_intr_handler_bank_s) * nbanks);    s->parent_intr[0] = parent_irq;    s->parent_intr[1] = parent_fiq;    s->base = base;    s->nbanks = nbanks;    s->pins = qemu_allocate_irqs(omap_set_intr, s, nbanks * 32);    if (pins)        *pins = s->pins;    omap_inth_reset(s);    iomemtype = cpu_register_io_memory(0, omap_inth_readfn,                    omap_inth_writefn, s);    cpu_register_physical_memory(s->base, size, iomemtype);    return s;}static uint32_t omap2_inth_read(void *opaque, target_phys_addr_t addr){    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;    int offset = addr - s->base;    int bank_no, line_no;    struct omap_intr_handler_bank_s *bank = 0;    if ((offset & 0xf80) == 0x80) {        bank_no = (offset & 0x60) >> 5;        if (bank_no < s->nbanks) {            offset &= ~0x60;            bank = &s->bank[bank_no];        }    }    switch (offset) {    case 0x00:	/* INTC_REVISION */        return 0x21;    case 0x10:	/* INTC_SYSCONFIG */        return (s->autoidle >> 2) & 1;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?