aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiku Voipio <riku.voipio@nokia.com>2012-07-04 11:18:34 +0000
committerPeter Maydell <peter.maydell@linaro.org>2012-07-25 13:31:58 +0100
commitf513f27f38d40914b62ca795f1168fb9bc8989c5 (patch)
treece0053dbfcddb15aa6f88135c78b6a262d0a45bf
parente6ef060372e0a71c932e025ad728bb826b7fab68 (diff)
hw/omap_dma.c: Add support for OMAP3 specific behaviour
-rw-r--r--hw/omap.h4
-rw-r--r--hw/omap_dma.c120
2 files changed, 104 insertions, 20 deletions
diff --git a/hw/omap.h b/hw/omap.h
index 06cf288e76..fd6a5b5876 100644
--- a/hw/omap.h
+++ b/hw/omap.h
@@ -549,6 +549,10 @@ struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
MemoryRegion *sysmem,
struct omap_mpu_state_s *mpu, int fifo,
int chans, omap_clk iclk, omap_clk fclk);
+struct soc_dma_s *omap3_dma4_init(struct omap_target_agent_s *ta,
+ struct omap_mpu_state_s *mpu,
+ qemu_irq *irqs, int chans,
+ omap_clk iclk, omap_clk fclk);
void omap_dma_reset(struct soc_dma_s *s);
struct dma_irq_map {
diff --git a/hw/omap_dma.c b/hw/omap_dma.c
index c38012e7d9..727ea0bafc 100644
--- a/hw/omap_dma.c
+++ b/hw/omap_dma.c
@@ -721,10 +721,17 @@ void omap_dma_reset(struct soc_dma_s *dma)
s->ch[i].repeat = 0;
s->ch[i].auto_init = 0;
s->ch[i].link_enabled = 0;
- if (s->model < omap_dma_4)
+ if (s->model < omap_dma_4) {
s->ch[i].interrupts = 0x0003;
- else
- s->ch[i].interrupts = 0x0000;
+ } else {
+ if (cpu_is_omap3630(s->mpu)) {
+ s->ch[i].interrupts = 0x2600;
+ } else if (cpu_class_omap3(s->mpu)) {
+ s->ch[i].interrupts = 0x0600;
+ } else {
+ s->ch[i].interrupts = 0x0000;
+ }
+ }
s->ch[i].status = 0;
s->ch[i].cstatus = 0;
s->ch[i].active = 0;
@@ -1586,6 +1593,9 @@ static void omap_dma_setcaps(struct omap_dma_s *s)
s->caps[0] =
(1 << 19) | /* Constant Fill Capability */
(1 << 18); /* Transparent BLT Capability */
+ if (cpu_is_omap3630(s->mpu)) {
+ s->caps[0] |= (1 << 20); /* LINK_LIST_CPBLTY_TYPE123 */
+ }
s->caps[1] =
(1 << 1); /* 1-bit palettized capability (DMA 3.2 only) */
s->caps[2] =
@@ -1616,6 +1626,15 @@ static void omap_dma_setcaps(struct omap_dma_s *s)
(1 << 2) | /* HALF_FRAME_INTERRUPT_CPBLTY */
(1 << 1) | /* EVENT_DROP_INTERRUPT_CPBLTY */
(1 << 0); /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */
+ if (cpu_is_omap3630(s->mpu)) {
+ s->caps[4] |= (1 << 14) | /* EOSB_INTERRUPT_CPBLTY */
+ (1 << 13) | /* reserved */
+ (1 << 12) | /* DRAIN_END_INTERRUPT_CPBLTY */
+ (1 << 11) | /* MISALIGNED_ADRS_ERR_INTERRUPT_CPBLTY */
+ (1 << 10) | /* SUPERVISOR_ERR_INTERRUPT_CPBLTY */
+ (1 << 9) | /* reserved */
+ (1 << 8); /* TRANS_ERR_INTERRUPT_CPBLTY */
+ }
break;
}
}
@@ -1679,7 +1698,7 @@ static void omap_dma_interrupts_4_update(struct omap_dma_s *s)
uint32_t bmp, bit;
for (bmp = 0, bit = 1; bit; ch ++, bit <<= 1)
- if (ch->status) {
+ if ((ch->status &= ch->interrupts)) {
bmp |= bit;
ch->cstatus |= ch->status;
ch->status = 0;
@@ -1707,6 +1726,9 @@ static uint64_t omap_dma4_read(void *opaque, target_phys_addr_t addr,
switch (addr) {
case 0x00: /* DMA4_REVISION */
+ if (cpu_is_omap3630(s->mpu)) {
+ return 0x50;
+ }
return 0x40;
case 0x14: /* DMA4_IRQSTATUS_L3 */
@@ -1838,8 +1860,13 @@ static uint64_t omap_dma4_read(void *opaque, target_phys_addr_t addr,
/* XXX only in sDMA */
return ch->color;
+ case 0x50: /* DMA4_CDP */
+ case 0x54: /* DMA4_CNDP */
+ case 0x58: /* DMA4_CCDN */
+ return 0;
+
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REG(0x80 + chnum * 0x60 + addr);
return 0;
}
}
@@ -1879,8 +1906,11 @@ static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
return;
case 0x2c: /* DMA4_OCP_SYSCONFIG */
- if (value & 2) /* SOFTRESET */
- omap_dma_reset(s->dma);
+ if (value & 2) { /* SOFTRESET */
+ if (!cpu_is_omap3630(s->mpu)) { /* N/A on 3630GP */
+ omap_dma_reset(s->dma);
+ }
+ }
s->ocp = value & 0x3321;
if (((s->ocp >> 12) & 3) == 3) /* MIDLEMODE */
fprintf(stderr, "%s: invalid DMA power mode\n", __FUNCTION__);
@@ -1949,7 +1979,13 @@ static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
break;
case 0x08: /* DMA4_CICR */
- ch->interrupts = value & 0x09be;
+ if (cpu_is_omap3630(s->mpu)) {
+ ch->interrupts = value & 0x5dbe;
+ } else if (cpu_class_omap3(s->mpu)) {
+ ch->interrupts = value & 0x1dbe;
+ } else {
+ ch->interrupts = value & 0x09be;
+ }
break;
case 0x0c: /* DMA4_CSR */
@@ -1979,7 +2015,7 @@ static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
printf("%s: bad data_type for DMA channel\n", __FUNCTION__);
break;
- case 0x14: /* DMA4_CEN */
+ case 0x14: /* DMA4_CCEN */
ch->set_update = 1;
ch->elements = value & 0xffffff;
break;
@@ -2028,11 +2064,32 @@ static void omap_dma4_write(void *opaque, target_phys_addr_t addr,
case 0x38: /* DMA4_CDAC */
case 0x3c: /* DMA4_CCEN */
case 0x40: /* DMA4_CCFN */
- OMAP_RO_REG(addr);
+ /* f.ex. linux kernel writes zeroes to these registers as well
+ when performing a DMA channel reset. let's just ignore the
+ writes instead of reporting "dummy" errors */
+ /*OMAP_RO_REG(0x80 + chnum * 0x60 + addr);*/
+ break;
+
+ case 0x50: /* DMA4_CDP */
+ if (cpu_is_omap3630(s->mpu)) {
+ if ((value >> 8) & 3) { /* TRANSFER_MODE */
+ hw_error("%s: linked list transfer mode not supported",
+ __FUNCTION__);
+ }
+ } else {
+ OMAP_BAD_REG(0x80 + chnum * 0x60 + addr);
+ }
+ break;
+
+ case 0x54: /* DMA4_CNDP */
+ case 0x58: /* DMA4_CCDN */
+ if (!cpu_is_omap3630(s->mpu)) {
+ OMAP_BAD_REG(0x80 + chnum * 0x60 + addr);
+ }
break;
default:
- OMAP_BAD_REG(addr);
+ OMAP_BAD_REG(0x80 + chnum * 0x60 + addr);
}
}
@@ -2042,10 +2099,10 @@ static const MemoryRegionOps omap_dma4_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
- MemoryRegion *sysmem,
- struct omap_mpu_state_s *mpu, int fifo,
- int chans, omap_clk iclk, omap_clk fclk)
+static struct omap_dma_s *omap_dma4_init_internal(struct omap_mpu_state_s *mpu,
+ qemu_irq *irqs,
+ int chans, int drq_count,
+ omap_clk iclk, omap_clk fclk)
{
int i;
struct omap_dma_s *s = (struct omap_dma_s *)
@@ -2055,31 +2112,54 @@ struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
s->chans = chans;
s->mpu = mpu;
s->clk = fclk;
-
+
s->dma = soc_dma_init(s->chans);
s->dma->freq = omap_clk_getrate(fclk);
s->dma->transfer_fn = omap_dma_transfer_generic;
s->dma->setup_fn = omap_dma_transfer_setup;
- s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, 64);
+ s->dma->drq = qemu_allocate_irqs(omap_dma_request, s, drq_count);
s->dma->opaque = s;
for (i = 0; i < s->chans; i ++) {
s->ch[i].dma = &s->dma->ch[i];
s->dma->ch[i].opaque = &s->ch[i];
}
-
+
memcpy(&s->irq, irqs, sizeof(s->irq));
s->intr_update = omap_dma_interrupts_4_update;
-
+
omap_dma_setcaps(s);
omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
omap_dma_reset(s->dma);
omap_dma_clk_update(s, 0, !!s->dma->freq);
+ mpu->drq = s->dma->drq;
+
+ return s;
+}
+
+struct soc_dma_s *omap_dma4_init(target_phys_addr_t base, qemu_irq *irqs,
+ MemoryRegion *sysmem,
+ struct omap_mpu_state_s *mpu, int fifo,
+ int chans, omap_clk iclk, omap_clk fclk)
+{
+ struct omap_dma_s *s = omap_dma4_init_internal(mpu, irqs, chans, 64,
+ iclk, fclk);
memory_region_init_io(&s->iomem, &omap_dma4_ops, s, "omap.dma4", 0x1000);
memory_region_add_subregion(sysmem, base, &s->iomem);
- mpu->drq = s->dma->drq;
+ return s->dma;
+}
+struct soc_dma_s *omap3_dma4_init(struct omap_target_agent_s *ta,
+ struct omap_mpu_state_s *mpu,
+ qemu_irq *irqs,
+ int chans,
+ omap_clk iclk, omap_clk fclk)
+{
+ struct omap_dma_s *s = omap_dma4_init_internal(mpu, irqs, chans, 96,
+ iclk, fclk);
+ memory_region_init_io(&s->iomem, &omap_dma4_ops, s, "omap.dma4", 0x1000);
+ omap_l4_attach(ta, 0, &s->iomem);
return s->dma;
}