From ac53688a654a43e25b7b01c9a120dfb952ee2942 Mon Sep 17 00:00:00 2001 From: Andrew Baumann Date: Mon, 29 Feb 2016 14:35:17 -0800 Subject: [PATCH] bcm2835_dma: cleanup prior to upstreaming --- hw/dma/bcm2835_dma.c | 227 +++++++++++++++++++++-------------- include/hw/arm/bcm2835_peripherals.h | 2 +- include/hw/dma/bcm2835_dma.h | 16 ++- 3 files changed, 147 insertions(+), 98 deletions(-) diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c index 76754f8ea0..1b3cdcf504 100644 --- a/hw/dma/bcm2835_dma.c +++ b/hw/dma/bcm2835_dma.c @@ -8,6 +8,7 @@ /* DMA CS Control and Status bits */ #define BCM2708_DMA_ACTIVE (1 << 0) +#define BCM2708_DMA_END (1 << 1) /* GE */ #define BCM2708_DMA_INT (1 << 2) #define BCM2708_DMA_ISPAUSED (1 << 4) /* Pause requested or not active */ #define BCM2708_DMA_ISHELD (1 << 5) /* Is held by DREQ flow control */ @@ -15,8 +16,6 @@ #define BCM2708_DMA_ABORT (1 << 30) /* stop current CB, go to next, WO */ #define BCM2708_DMA_RESET (1 << 31) /* WO, self clearing */ -#define BCM2708_DMA_END (1 << 1) /* GE */ - /* DMA control block "info" field bits */ #define BCM2708_DMA_INT_EN (1 << 0) #define BCM2708_DMA_TDMODE (1 << 1) @@ -30,28 +29,26 @@ #define BCM2708_DMA_S_DREQ (1 << 10) #define BCM2708_DMA_S_IGNORE (1 << 11) -#define BCM2708_DMA_BURST(x) (((x)&0xf) << 12) -#define BCM2708_DMA_PER_MAP(x) ((x) << 16) -#define BCM2708_DMA_WAITS(x) (((x)&0x1f) << 21) - -#define BCM2708_DMA_DREQ_EMMC 11 -#define BCM2708_DMA_DREQ_SDHOST 13 - +/* Register offsets */ #define BCM2708_DMA_CS 0x00 /* Control and Status */ -#define BCM2708_DMA_ADDR 0x04 +#define BCM2708_DMA_ADDR 0x04 /* Control block address */ /* the current control block appears in the following registers - read only */ #define BCM2708_DMA_INFO 0x08 +#define BCM2708_DMA_SOURCE_AD 0x0c +#define BCM2708_DMA_DEST_AD 0x10 +#define BCM2708_DMA_TXFR_LEN 0x14 +#define BCM2708_DMA_STRIDE 0x18 #define BCM2708_DMA_NEXTCB 0x1C #define BCM2708_DMA_DEBUG 0x20 -#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4)+BCM2708_DMA_CS) -#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4)+BCM2708_DMA_ADDR) +#define BCM2708_DMA_INT_STATUS 0xfe0 /* Interrupt status of each channel */ +#define BCM2708_DMA_ENABLE 0xff0 /* Global enable bits for each channel */ -#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w)) +#define BCM2708_DMA_CS_RW_MASK 0x30ff0001 /* All RW bits in DMA_CS */ -static void bcm2835_dma_update(BCM2835DmaState *s, int c) +static void bcm2835_dma_update(BCM2835DMAState *s, unsigned c) { - BCM2835DmaChan *ch = &s->chan[c]; + BCM2835DMAChan *ch = &s->chan[c]; uint32_t data, xlen, ylen; int16_t dst_stride, src_stride; @@ -130,60 +127,63 @@ static void bcm2835_dma_update(BCM2835DmaState *s, int c) ch->cs &= ~BCM2708_DMA_ACTIVE; } -static uint64_t bcm2835_dma_read(BCM2835DmaState *s, hwaddr offset, - unsigned size, int c) +static uint64_t bcm2835_dma_read(BCM2835DMAState *s, hwaddr offset, + unsigned size, unsigned c) { - BCM2835DmaChan *ch = &s->chan[c]; + BCM2835DMAChan *ch = &s->chan[c]; uint32_t res = 0; assert(size == 4); + assert(c < BCM2835_DMA_NCHANS); switch (offset) { - case 0x0: + case BCM2708_DMA_CS: res = ch->cs; break; - case 0x4: + case BCM2708_DMA_ADDR: res = ch->conblk_ad; break; - case 0x8: + case BCM2708_DMA_INFO: res = ch->ti; break; - case 0xc: + case BCM2708_DMA_SOURCE_AD: res = ch->source_ad; break; - case 0x10: + case BCM2708_DMA_DEST_AD: res = ch->dest_ad; break; - case 0x14: + case BCM2708_DMA_TXFR_LEN: res = ch->txfr_len; break; - case 0x18: + case BCM2708_DMA_STRIDE: res = ch->stride; break; - case 0x1c: + case BCM2708_DMA_NEXTCB: res = ch->nextconbk; break; - case 0x20: + case BCM2708_DMA_DEBUG: res = ch->debug; break; default: - qemu_log_mask(LOG_GUEST_ERROR, - "bcm2835_dma_read: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); break; } return res; } -static void bcm2835_dma_write(BCM2835DmaState *s, hwaddr offset, - uint64_t value, unsigned size, int c) +static void bcm2835_dma_write(BCM2835DMAState *s, hwaddr offset, + uint64_t value, unsigned size, unsigned c) { - BCM2835DmaChan *ch = &s->chan[c]; - uint32_t oldcs = ch->cs; + BCM2835DMAChan *ch = &s->chan[c]; + uint32_t oldcs; assert(size == 4); + assert(c < BCM2835_DMA_NCHANS); switch (offset) { - case 0x0: + case BCM2708_DMA_CS: + oldcs = ch->cs; if (value & BCM2708_DMA_RESET) { ch->cs |= BCM2708_DMA_RESET; } @@ -198,104 +198,141 @@ static void bcm2835_dma_write(BCM2835DmaState *s, hwaddr offset, s->int_status &= ~(1 << c); qemu_set_irq(ch->irq, 0); } - ch->cs &= ~0x30ff0001; - ch->cs |= (value & 0x30ff0001); + ch->cs &= ~BCM2708_DMA_CS_RW_MASK; + ch->cs |= (value & BCM2708_DMA_CS_RW_MASK); if (!(oldcs & BCM2708_DMA_ACTIVE) && (ch->cs & BCM2708_DMA_ACTIVE)) { bcm2835_dma_update(s, c); } break; - case 0x4: + case BCM2708_DMA_ADDR: ch->conblk_ad = value; break; - case 0x20: + case BCM2708_DMA_DEBUG: ch->debug = value; break; default: - qemu_log_mask(LOG_GUEST_ERROR, - "bcm2835_dma_write: Bad offset %x\n", (int)offset); + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); break; } } -/* ==================================================================== */ - -static uint64_t bcm2835_dma0_14_read(void *opaque, hwaddr offset, - unsigned size) +static uint64_t bcm2835_dma0_read(void *opaque, hwaddr offset, unsigned size) { - BCM2835DmaState *s = (BCM2835DmaState *)opaque; - if (offset == 0xfe0) { - return s->int_status; - } - if (offset == 0xff0) { - return s->enable; + BCM2835DMAState *s = opaque; + + if (offset < 0xf00) { + return bcm2835_dma_read(s, (offset & 0xff), size, (offset >> 8) & 0xf); + } else { + switch (offset) { + case BCM2708_DMA_INT_STATUS: + return s->int_status; + case BCM2708_DMA_ENABLE: + return s->enable; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); + return 0; + } } - return bcm2835_dma_read(s, (offset & 0xff), - size, (offset >> 8) & 0xf); } -static uint64_t bcm2835_dma15_read(void *opaque, hwaddr offset, - unsigned size) +static uint64_t bcm2835_dma15_read(void *opaque, hwaddr offset, unsigned size) { - return bcm2835_dma_read((BCM2835DmaState *)opaque, (offset & 0xff), - size, 15); + return bcm2835_dma_read(opaque, (offset & 0xff), size, 15); } -static void bcm2835_dma0_14_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) +static void bcm2835_dma0_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) { - BCM2835DmaState *s = (BCM2835DmaState *)opaque; - if (offset == 0xfe0) { - return; - } - if (offset == 0xff0) { - s->enable = (value & 0xffff); - return; + BCM2835DMAState *s = opaque; + + if (offset < 0xf00) { + bcm2835_dma_write(s, (offset & 0xff), value, size, (offset >> 8) & 0xf); + } else { + switch (offset) { + case BCM2708_DMA_INT_STATUS: + break; + case BCM2708_DMA_ENABLE: + s->enable = (value & 0xffff); + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n", + __func__, offset); + } } - bcm2835_dma_write(s, (offset & 0xff), - value, size, (offset >> 8) & 0xf); + } -static void bcm2835_dma15_write(void *opaque, hwaddr offset, - uint64_t value, unsigned size) +static void bcm2835_dma15_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) { - bcm2835_dma_write((BCM2835DmaState *)opaque, (offset & 0xff), - value, size, 15); + bcm2835_dma_write(opaque, (offset & 0xff), value, size, 15); } - -static const MemoryRegionOps bcm2835_dma0_14_ops = { - .read = bcm2835_dma0_14_read, - .write = bcm2835_dma0_14_write, +static const MemoryRegionOps bcm2835_dma0_ops = { + .read = bcm2835_dma0_read, + .write = bcm2835_dma0_write, .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, }; static const MemoryRegionOps bcm2835_dma15_ops = { .read = bcm2835_dma15_read, .write = bcm2835_dma15_write, .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 4, + .valid.max_access_size = 4, +}; + +static const VMStateDescription vmstate_bcm2835_dma_chan = { + .name = TYPE_BCM2835_DMA "-chan", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(cs, BCM2835DMAChan), + VMSTATE_UINT32(conblk_ad, BCM2835DMAChan), + VMSTATE_UINT32(ti, BCM2835DMAChan), + VMSTATE_UINT32(source_ad, BCM2835DMAChan), + VMSTATE_UINT32(dest_ad, BCM2835DMAChan), + VMSTATE_UINT32(txfr_len, BCM2835DMAChan), + VMSTATE_UINT32(stride, BCM2835DMAChan), + VMSTATE_UINT32(nextconbk, BCM2835DMAChan), + VMSTATE_UINT32(debug, BCM2835DMAChan), + VMSTATE_END_OF_LIST() + } }; static const VMStateDescription vmstate_bcm2835_dma = { .name = TYPE_BCM2835_DMA, .version_id = 1, .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField[]) { + .fields = (VMStateField[]) { + VMSTATE_STRUCT_ARRAY(chan, BCM2835DMAState, BCM2835_DMA_NCHANS, 1, + vmstate_bcm2835_dma_chan, BCM2835DMAChan), + VMSTATE_UINT32(int_status, BCM2835DMAState), + VMSTATE_UINT32(enable, BCM2835DMAState), VMSTATE_END_OF_LIST() } }; static void bcm2835_dma_init(Object *obj) { - BCM2835DmaState *s = BCM2835_DMA(obj); + BCM2835DMAState *s = BCM2835_DMA(obj); int n; - memory_region_init_io(&s->iomem0_14, OBJECT(s), &bcm2835_dma0_14_ops, s, - "bcm2835_dma0_14", 0xf00); - sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem0_14); + /* DMA channels 0-14 occupy a contiguous block of IO memory, along + * with the global enable and interrupt status bits. Channel 15 + * has the same register map, but is mapped at a discontiguous + * address in a separate IO block. + */ + memory_region_init_io(&s->iomem0, OBJECT(s), &bcm2835_dma0_ops, s, + TYPE_BCM2835_DMA, 0x1000); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem0); memory_region_init_io(&s->iomem15, OBJECT(s), &bcm2835_dma15_ops, s, - "bcm2835_dma15", 0x100); + TYPE_BCM2835_DMA "-chan15", 0x100); sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem15); for (n = 0; n < 16; n++) { @@ -303,10 +340,22 @@ static void bcm2835_dma_init(Object *obj) } } -static void bcm2835_dma_realize(DeviceState *dev, Error **errp) +static void bcm2835_dma_reset(DeviceState *dev) { + BCM2835DMAState *s = BCM2835_DMA(dev); int n; - BCM2835DmaState *s = BCM2835_DMA(dev); + + s->enable = 0xffff; + s->int_status = 0; + for (n = 0; n < BCM2835_DMA_NCHANS; n++) { + s->chan[n].cs = 0; + s->chan[n].conblk_ad = 0; + } +} + +static void bcm2835_dma_realize(DeviceState *dev, Error **errp) +{ + BCM2835DMAState *s = BCM2835_DMA(dev); Error *err = NULL; Object *obj; @@ -320,12 +369,7 @@ static void bcm2835_dma_realize(DeviceState *dev, Error **errp) s->dma_mr = MEMORY_REGION(obj); address_space_init(&s->dma_as, s->dma_mr, NULL); - s->enable = 0xffff; - s->int_status = 0; - for (n = 0; n < 16; n++) { - s->chan[n].cs = 0; - s->chan[n].conblk_ad = 0; - } + bcm2835_dma_reset(dev); } static void bcm2835_dma_class_init(ObjectClass *klass, void *data) @@ -333,13 +377,14 @@ static void bcm2835_dma_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = bcm2835_dma_realize; + dc->reset = bcm2835_dma_reset; dc->vmsd = &vmstate_bcm2835_dma; } static TypeInfo bcm2835_dma_info = { .name = TYPE_BCM2835_DMA, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(BCM2835DmaState), + .instance_size = sizeof(BCM2835DMAState), .class_init = bcm2835_dma_class_init, .instance_init = bcm2835_dma_init, }; diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index 36ea6996c9..d84b056724 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -43,7 +43,7 @@ typedef struct BCM2835PeripheralState { SysBusDevice *uart0; BCM2835AuxState aux; BCM2835FBState fb; - BCM2835DmaState dma; + BCM2835DMAState dma; BCM2835ICState ic; BCM2835MphiState mphi; BCM2835PowerState power; diff --git a/include/hw/dma/bcm2835_dma.h b/include/hw/dma/bcm2835_dma.h index 6508da18bd..75312e2e17 100644 --- a/include/hw/dma/bcm2835_dma.h +++ b/include/hw/dma/bcm2835_dma.h @@ -22,22 +22,26 @@ typedef struct { uint32_t debug; qemu_irq irq; -} BCM2835DmaChan; +} BCM2835DMAChan; #define TYPE_BCM2835_DMA "bcm2835-dma" #define BCM2835_DMA(obj) \ - OBJECT_CHECK(BCM2835DmaState, (obj), TYPE_BCM2835_DMA) + OBJECT_CHECK(BCM2835DMAState, (obj), TYPE_BCM2835_DMA) + +#define BCM2835_DMA_NCHANS 16 typedef struct { + /*< private >*/ SysBusDevice busdev; - MemoryRegion iomem0_14; - MemoryRegion iomem15; + /*< public >*/ + + MemoryRegion iomem0, iomem15; MemoryRegion *dma_mr; AddressSpace dma_as; - BCM2835DmaChan chan[16]; + BCM2835DMAChan chan[BCM2835_DMA_NCHANS]; uint32_t int_status; uint32_t enable; -} BCM2835DmaState; +} BCM2835DMAState; #endif -- 2.11.4.GIT