From d951f6ff3fff1121e8b20e7655cb88b2601b61e6 Mon Sep 17 00:00:00 2001 From: balrog Date: Mon, 29 Oct 2007 01:50:05 +0000 Subject: [PATCH] Implement OMAP MicroWire controller. Fix GPIO interrupt number. Reorder a couple of variables. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3477 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/omap.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/omap.h | 25 ++++++-- hw/palm.c | 3 +- 3 files changed, 200 insertions(+), 16 deletions(-) diff --git a/hw/omap.c b/hw/omap.c index a2a18a406c..cfb7d2bfec 100644 --- a/hw/omap.c +++ b/hw/omap.c @@ -3101,7 +3101,6 @@ static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) { struct omap_gpio_s *s = (struct omap_gpio_s *) opaque; int offset = addr - s->base; - uint16_t ret; switch (offset) { case 0x00: /* DATA_INPUT */ @@ -3238,6 +3237,175 @@ void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler) s->handler[line] = handler; } +/* MicroWire Interface */ +struct omap_uwire_s { + target_phys_addr_t base; + qemu_irq txirq; + qemu_irq rxirq; + qemu_irq txdrq; + + uint16_t txbuf; + uint16_t rxbuf; + uint16_t control; + uint16_t setup[5]; + + struct uwire_slave_s *chip[4]; +}; + +static void omap_uwire_transfer_start(struct omap_uwire_s *s) +{ + int chipselect = (s->control >> 10) & 3; /* INDEX */ + struct uwire_slave_s *slave = s->chip[chipselect]; + + if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ + if (s->control & (1 << 12)) /* CS_CMD */ + if (slave && slave->send) + slave->send(slave->opaque, + s->txbuf >> (16 - ((s->control >> 5) & 0x1f))); + s->control &= ~(1 << 14); /* CSRB */ + /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or + * a DRQ. When is the level IRQ supposed to be reset? */ + } + + if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ + if (s->control & (1 << 12)) /* CS_CMD */ + if (slave && slave->receive) + s->rxbuf = slave->receive(slave->opaque); + s->control |= 1 << 15; /* RDRB */ + /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or + * a DRQ. When is the level IRQ supposed to be reset? */ + } +} + +static uint32_t omap_uwire_read(void *opaque, target_phys_addr_t addr) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* RDR */ + s->control &= ~(1 << 15); /* RDRB */ + return s->rxbuf; + + case 0x04: /* CSR */ + return s->control; + + case 0x08: /* SR1 */ + return s->setup[0]; + case 0x0c: /* SR2 */ + return s->setup[1]; + case 0x10: /* SR3 */ + return s->setup[2]; + case 0x14: /* SR4 */ + return s->setup[3]; + case 0x18: /* SR5 */ + return s->setup[4]; + } + + OMAP_BAD_REG(addr); + return 0; +} + +static void omap_uwire_write(void *opaque, target_phys_addr_t addr, + uint32_t value) +{ + struct omap_uwire_s *s = (struct omap_uwire_s *) opaque; + int offset = addr - s->base; + + switch (offset) { + case 0x00: /* TDR */ + s->txbuf = value; /* TD */ + s->control |= 1 << 14; /* CSRB */ + if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ + ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ + (s->control & (1 << 12)))) /* CS_CMD */ + omap_uwire_transfer_start(s); + break; + + case 0x04: /* CSR */ + s->control = value & 0x1fff; + if (value & (1 << 13)) /* START */ + omap_uwire_transfer_start(s); + break; + + case 0x08: /* SR1 */ + s->setup[0] = value & 0x003f; + break; + + case 0x0c: /* SR2 */ + s->setup[1] = value & 0x0fc0; + break; + + case 0x10: /* SR3 */ + s->setup[2] = value & 0x0003; + break; + + case 0x14: /* SR4 */ + s->setup[3] = value & 0x0001; + break; + + case 0x18: /* SR5 */ + s->setup[4] = value & 0x000f; + break; + + default: + OMAP_BAD_REG(addr); + return; + } +} + +static CPUReadMemoryFunc *omap_uwire_readfn[] = { + omap_badwidth_read16, + omap_uwire_read, + omap_badwidth_read16, +}; + +static CPUWriteMemoryFunc *omap_uwire_writefn[] = { + omap_badwidth_write16, + omap_uwire_write, + omap_badwidth_write16, +}; + +void omap_uwire_reset(struct omap_uwire_s *s) +{ + s->control= 0; + s->setup[0] = 0; + s->setup[1] = 0; + s->setup[2] = 0; + s->setup[3] = 0; + s->setup[4] = 0; +} + +struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, + qemu_irq *irq, qemu_irq dma, omap_clk clk) +{ + int iomemtype; + struct omap_uwire_s *s = (struct omap_uwire_s *) + qemu_mallocz(sizeof(struct omap_uwire_s)); + + s->base = base; + s->txirq = irq[0]; + s->rxirq = irq[1]; + s->txdrq = dma; + omap_uwire_reset(s); + + iomemtype = cpu_register_io_memory(0, omap_uwire_readfn, + omap_uwire_writefn, s); + cpu_register_physical_memory(s->base, 0x800, iomemtype); + + return s; +} + +void omap_uwire_attach(struct omap_uwire_s *s, + struct uwire_slave_s *slave, int chipselect) +{ + if (chipselect < 0 || chipselect > 3) + cpu_abort(cpu_single_env, "%s: Bad chipselect %i\n", __FUNCTION__, + chipselect); + + s->chip[chipselect] = slave; +} + /* General chip reset */ static void omap_mpu_reset(void *opaque) { @@ -3261,12 +3429,13 @@ static void omap_mpu_reset(void *opaque) omap_dpll_reset(&mpu->dpll[0]); omap_dpll_reset(&mpu->dpll[1]); omap_dpll_reset(&mpu->dpll[2]); - omap_uart_reset(mpu->uart1); - omap_uart_reset(mpu->uart2); - omap_uart_reset(mpu->uart3); + omap_uart_reset(mpu->uart[0]); + omap_uart_reset(mpu->uart[1]); + omap_uart_reset(mpu->uart[2]); omap_mmc_reset(mpu->mmc); omap_mpuio_reset(mpu->mpuio); omap_gpio_reset(mpu->gpio); + omap_uwire_reset(mpu->microwire); cpu_reset(mpu->env); } @@ -3361,13 +3530,13 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, omap_tcmi_init(0xfffecc00, s); - s->uart1 = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], + s->uart[0] = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1], omap_findclk(s, "uart1_ck"), serial_hds[0]); - s->uart2 = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2], + s->uart[1] = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2], omap_findclk(s, "uart2_ck"), serial_hds[0] ? serial_hds[1] : 0); - s->uart3 = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3], + s->uart[2] = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3], omap_findclk(s, "uart3_ck"), serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0); @@ -3382,9 +3551,12 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, s->irq[1][OMAP_INT_KEYBOARD], s->irq[1][OMAP_INT_MPUIO], s->wakeup, omap_findclk(s, "clk32-kHz")); - s->gpio = omap_gpio_init(0xfffcf000, s->irq[1][OMAP_INT_KEYBOARD], + s->gpio = omap_gpio_init(0xfffcf000, s->irq[0][OMAP_INT_GPIO_BANK1], omap_findclk(s, "mpuper_ck")); + s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], + s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); + qemu_register_reset(omap_mpu_reset, s); return s; diff --git a/hw/omap.h b/hw/omap.h index caaca9e69c..e19f8ac7c0 100644 --- a/hw/omap.h +++ b/hw/omap.h @@ -464,6 +464,17 @@ struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, qemu_irq *omap_gpio_in_get(struct omap_gpio_s *s); void omap_gpio_out_set(struct omap_gpio_s *s, int line, qemu_irq handler); +struct uwire_slave_s { + uint16_t (*receive)(void *opaque); + void (*send)(void *opaque, uint16_t data); + void *opaque; +}; +struct omap_uwire_s; +struct omap_uwire_s *omap_uwire_init(target_phys_addr_t base, + qemu_irq *irq, qemu_irq dma, omap_clk clk); +void omap_uwire_attach(struct omap_uwire_s *s, + struct uwire_slave_s *slave, int chipselect); + /* omap_lcdc.c */ struct omap_lcd_panel_s; void omap_lcdc_reset(struct omap_lcd_panel_s *s); @@ -510,16 +521,19 @@ struct omap_mpu_state_s { unsigned long sram_size; /* MPUI-TIPB peripherals */ - struct omap_uart_s *uart3; + struct omap_uart_s *uart[3]; + + struct omap_gpio_s *gpio; /* MPU public TIPB peripherals */ struct omap_32khz_timer_s *os_timer; - struct omap_uart_s *uart1; - struct omap_uart_s *uart2; - struct omap_mmc_s *mmc; + struct omap_mpuio_s *mpuio; + + struct omap_uwire_s *microwire; + /* MPU private TIPB peripherals */ struct omap_intr_handler_s *ih[2]; @@ -578,9 +592,6 @@ struct omap_mpu_state_s { uint16_t dsp_idlect2; uint16_t dsp_rstct2; } clkm; - - struct omap_mpuio_s *mpuio; - struct omap_gpio_s *gpio; } *omap310_mpu_init(unsigned long sdram_size, DisplayState *ds, const char *core); diff --git a/hw/palm.c b/hw/palm.c index 1ee05b8233..794574565f 100644 --- a/hw/palm.c +++ b/hw/palm.c @@ -37,7 +37,8 @@ static uint32_t static_readw(void *opaque, target_phys_addr_t offset) { } static void static_write(void *opaque, target_phys_addr_t offset, - uint32_t value) { + uint32_t value) +{ #ifdef SPY printf("%s: value %08lx written at " PA_FMT "\n", __FUNCTION__, value, offset);