149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini * QEMU JAZZ RC4030 chipset
349ab747fSPaolo Bonzini *
4d791d60fSHervé Poussineau * Copyright (c) 2007-2013 Hervé Poussineau
549ab747fSPaolo Bonzini *
649ab747fSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini *
1349ab747fSPaolo Bonzini * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini *
1649ab747fSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini * THE SOFTWARE.
2349ab747fSPaolo Bonzini */
2449ab747fSPaolo Bonzini
250430891cSPeter Maydell #include "qemu/osdep.h"
26d37eae6cSAleksandar Markovic #include "qemu/units.h"
2764552b6bSMarkus Armbruster #include "hw/irq.h"
2849ab747fSPaolo Bonzini #include "hw/mips/mips.h"
29d791d60fSHervé Poussineau #include "hw/sysbus.h"
30d6454270SMarkus Armbruster #include "migration/vmstate.h"
313e80f690SMarkus Armbruster #include "qapi/error.h"
3249ab747fSPaolo Bonzini #include "qemu/timer.h"
3303dd024fSPaolo Bonzini #include "qemu/log.h"
340b8fa32fSMarkus Armbruster #include "qemu/module.h"
35a3d586f7SHervé Poussineau #include "exec/address-spaces.h"
3695c357bcSHervé Poussineau #include "trace.h"
37db1015e9SEduardo Habkost #include "qom/object.h"
3849ab747fSPaolo Bonzini
3949ab747fSPaolo Bonzini /********************************************************/
4049ab747fSPaolo Bonzini /* rc4030 emulation */
4149ab747fSPaolo Bonzini
4249ab747fSPaolo Bonzini typedef struct dma_pagetable_entry {
4349ab747fSPaolo Bonzini int32_t frame;
4449ab747fSPaolo Bonzini int32_t owner;
4549ab747fSPaolo Bonzini } QEMU_PACKED dma_pagetable_entry;
4649ab747fSPaolo Bonzini
4749ab747fSPaolo Bonzini #define DMA_PAGESIZE 4096
4849ab747fSPaolo Bonzini #define DMA_REG_ENABLE 1
4949ab747fSPaolo Bonzini #define DMA_REG_COUNT 2
5049ab747fSPaolo Bonzini #define DMA_REG_ADDRESS 3
5149ab747fSPaolo Bonzini
5249ab747fSPaolo Bonzini #define DMA_FLAG_ENABLE 0x0001
5349ab747fSPaolo Bonzini #define DMA_FLAG_MEM_TO_DEV 0x0002
5449ab747fSPaolo Bonzini #define DMA_FLAG_TC_INTR 0x0100
5549ab747fSPaolo Bonzini #define DMA_FLAG_MEM_INTR 0x0200
5649ab747fSPaolo Bonzini #define DMA_FLAG_ADDR_INTR 0x0400
5749ab747fSPaolo Bonzini
58d791d60fSHervé Poussineau #define TYPE_RC4030 "rc4030"
598063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(rc4030State, RC4030)
60d791d60fSHervé Poussineau
611221a474SAlexey Kardashevskiy #define TYPE_RC4030_IOMMU_MEMORY_REGION "rc4030-iommu-memory-region"
621221a474SAlexey Kardashevskiy
63db1015e9SEduardo Habkost struct rc4030State {
64a9e2d149SAleksandar Markovic
65d791d60fSHervé Poussineau SysBusDevice parent;
66d791d60fSHervé Poussineau
6749ab747fSPaolo Bonzini uint32_t config; /* 0x0000: RC4030 config register */
6849ab747fSPaolo Bonzini uint32_t revision; /* 0x0008: RC4030 Revision register */
6949ab747fSPaolo Bonzini uint32_t invalid_address_register; /* 0x0010: Invalid Address register */
7049ab747fSPaolo Bonzini
7149ab747fSPaolo Bonzini /* DMA */
7249ab747fSPaolo Bonzini uint32_t dma_regs[8][4];
7349ab747fSPaolo Bonzini uint32_t dma_tl_base; /* 0x0018: DMA transl. table base */
7449ab747fSPaolo Bonzini uint32_t dma_tl_limit; /* 0x0020: DMA transl. table limit */
7549ab747fSPaolo Bonzini
7649ab747fSPaolo Bonzini /* cache */
7749ab747fSPaolo Bonzini uint32_t cache_maint; /* 0x0030: Cache Maintenance */
7849ab747fSPaolo Bonzini uint32_t remote_failed_address; /* 0x0038: Remote Failed Address */
7949ab747fSPaolo Bonzini uint32_t memory_failed_address; /* 0x0040: Memory Failed Address */
8049ab747fSPaolo Bonzini uint32_t cache_ptag; /* 0x0048: I/O Cache Physical Tag */
8149ab747fSPaolo Bonzini uint32_t cache_ltag; /* 0x0050: I/O Cache Logical Tag */
8249ab747fSPaolo Bonzini uint32_t cache_bmask; /* 0x0058: I/O Cache Byte Mask */
8349ab747fSPaolo Bonzini
8449ab747fSPaolo Bonzini uint32_t nmi_interrupt; /* 0x0200: interrupt source */
85dc6e3e1eSHervé Poussineau uint32_t memory_refresh_rate; /* 0x0210: memory refresh rate */
8649ab747fSPaolo Bonzini uint32_t nvram_protect; /* 0x0220: NV ram protect register */
8749ab747fSPaolo Bonzini uint32_t rem_speed[16];
8849ab747fSPaolo Bonzini uint32_t imr_jazz; /* Local bus int enable mask */
8949ab747fSPaolo Bonzini uint32_t isr_jazz; /* Local bus int source */
9049ab747fSPaolo Bonzini
9149ab747fSPaolo Bonzini /* timer */
9249ab747fSPaolo Bonzini QEMUTimer *periodic_timer;
9349ab747fSPaolo Bonzini uint32_t itr; /* Interval timer reload */
9449ab747fSPaolo Bonzini
9549ab747fSPaolo Bonzini qemu_irq timer_irq;
9649ab747fSPaolo Bonzini qemu_irq jazz_bus_irq;
9749ab747fSPaolo Bonzini
98a3d586f7SHervé Poussineau /* whole DMA memory region, root of DMA address space */
993df9d748SAlexey Kardashevskiy IOMMUMemoryRegion dma_mr;
100a3d586f7SHervé Poussineau AddressSpace dma_as;
101a3d586f7SHervé Poussineau
10249ab747fSPaolo Bonzini MemoryRegion iomem_chipset;
10349ab747fSPaolo Bonzini MemoryRegion iomem_jazzio;
104db1015e9SEduardo Habkost };
10549ab747fSPaolo Bonzini
set_next_tick(rc4030State * s)10649ab747fSPaolo Bonzini static void set_next_tick(rc4030State *s)
10749ab747fSPaolo Bonzini {
10849ab747fSPaolo Bonzini uint32_t tm_hz;
1091b393b31SYongbok Kim qemu_irq_lower(s->timer_irq);
11049ab747fSPaolo Bonzini
11149ab747fSPaolo Bonzini tm_hz = 1000 / (s->itr + 1);
11249ab747fSPaolo Bonzini
113bc72ad67SAlex Bligh timer_mod(s->periodic_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
11473bcb24dSRutuja Shah NANOSECONDS_PER_SECOND / tm_hz);
11549ab747fSPaolo Bonzini }
11649ab747fSPaolo Bonzini
11749ab747fSPaolo Bonzini /* called for accesses to rc4030 */
rc4030_read(void * opaque,hwaddr addr,unsigned int size)118b421f3f5SHervé Poussineau static uint64_t rc4030_read(void *opaque, hwaddr addr, unsigned int size)
11949ab747fSPaolo Bonzini {
12049ab747fSPaolo Bonzini rc4030State *s = opaque;
12149ab747fSPaolo Bonzini uint32_t val;
12249ab747fSPaolo Bonzini
12349ab747fSPaolo Bonzini addr &= 0x3fff;
12449ab747fSPaolo Bonzini switch (addr & ~0x3) {
12549ab747fSPaolo Bonzini /* Global config register */
12649ab747fSPaolo Bonzini case 0x0000:
12749ab747fSPaolo Bonzini val = s->config;
12849ab747fSPaolo Bonzini break;
12949ab747fSPaolo Bonzini /* Revision register */
13049ab747fSPaolo Bonzini case 0x0008:
13149ab747fSPaolo Bonzini val = s->revision;
13249ab747fSPaolo Bonzini break;
13349ab747fSPaolo Bonzini /* Invalid Address register */
13449ab747fSPaolo Bonzini case 0x0010:
13549ab747fSPaolo Bonzini val = s->invalid_address_register;
13649ab747fSPaolo Bonzini break;
13749ab747fSPaolo Bonzini /* DMA transl. table base */
13849ab747fSPaolo Bonzini case 0x0018:
13949ab747fSPaolo Bonzini val = s->dma_tl_base;
14049ab747fSPaolo Bonzini break;
14149ab747fSPaolo Bonzini /* DMA transl. table limit */
14249ab747fSPaolo Bonzini case 0x0020:
14349ab747fSPaolo Bonzini val = s->dma_tl_limit;
14449ab747fSPaolo Bonzini break;
14549ab747fSPaolo Bonzini /* Remote Failed Address */
14649ab747fSPaolo Bonzini case 0x0038:
14749ab747fSPaolo Bonzini val = s->remote_failed_address;
14849ab747fSPaolo Bonzini break;
14949ab747fSPaolo Bonzini /* Memory Failed Address */
15049ab747fSPaolo Bonzini case 0x0040:
15149ab747fSPaolo Bonzini val = s->memory_failed_address;
15249ab747fSPaolo Bonzini break;
15349ab747fSPaolo Bonzini /* I/O Cache Byte Mask */
15449ab747fSPaolo Bonzini case 0x0058:
15549ab747fSPaolo Bonzini val = s->cache_bmask;
15649ab747fSPaolo Bonzini /* HACK */
157a9e2d149SAleksandar Markovic if (s->cache_bmask == (uint32_t)-1) {
15849ab747fSPaolo Bonzini s->cache_bmask = 0;
159a9e2d149SAleksandar Markovic }
16049ab747fSPaolo Bonzini break;
16149ab747fSPaolo Bonzini /* Remote Speed Registers */
16249ab747fSPaolo Bonzini case 0x0070:
16349ab747fSPaolo Bonzini case 0x0078:
16449ab747fSPaolo Bonzini case 0x0080:
16549ab747fSPaolo Bonzini case 0x0088:
16649ab747fSPaolo Bonzini case 0x0090:
16749ab747fSPaolo Bonzini case 0x0098:
16849ab747fSPaolo Bonzini case 0x00a0:
16949ab747fSPaolo Bonzini case 0x00a8:
17049ab747fSPaolo Bonzini case 0x00b0:
17149ab747fSPaolo Bonzini case 0x00b8:
17249ab747fSPaolo Bonzini case 0x00c0:
17349ab747fSPaolo Bonzini case 0x00c8:
17449ab747fSPaolo Bonzini case 0x00d0:
17549ab747fSPaolo Bonzini case 0x00d8:
17649ab747fSPaolo Bonzini case 0x00e0:
17749ab747fSPaolo Bonzini case 0x00e8:
17849ab747fSPaolo Bonzini val = s->rem_speed[(addr - 0x0070) >> 3];
17949ab747fSPaolo Bonzini break;
18049ab747fSPaolo Bonzini /* DMA channel base address */
18149ab747fSPaolo Bonzini case 0x0100:
18249ab747fSPaolo Bonzini case 0x0108:
18349ab747fSPaolo Bonzini case 0x0110:
18449ab747fSPaolo Bonzini case 0x0118:
18549ab747fSPaolo Bonzini case 0x0120:
18649ab747fSPaolo Bonzini case 0x0128:
18749ab747fSPaolo Bonzini case 0x0130:
18849ab747fSPaolo Bonzini case 0x0138:
18949ab747fSPaolo Bonzini case 0x0140:
19049ab747fSPaolo Bonzini case 0x0148:
19149ab747fSPaolo Bonzini case 0x0150:
19249ab747fSPaolo Bonzini case 0x0158:
19349ab747fSPaolo Bonzini case 0x0160:
19449ab747fSPaolo Bonzini case 0x0168:
19549ab747fSPaolo Bonzini case 0x0170:
19649ab747fSPaolo Bonzini case 0x0178:
19749ab747fSPaolo Bonzini case 0x0180:
19849ab747fSPaolo Bonzini case 0x0188:
19949ab747fSPaolo Bonzini case 0x0190:
20049ab747fSPaolo Bonzini case 0x0198:
20149ab747fSPaolo Bonzini case 0x01a0:
20249ab747fSPaolo Bonzini case 0x01a8:
20349ab747fSPaolo Bonzini case 0x01b0:
20449ab747fSPaolo Bonzini case 0x01b8:
20549ab747fSPaolo Bonzini case 0x01c0:
20649ab747fSPaolo Bonzini case 0x01c8:
20749ab747fSPaolo Bonzini case 0x01d0:
20849ab747fSPaolo Bonzini case 0x01d8:
20949ab747fSPaolo Bonzini case 0x01e0:
21049ab747fSPaolo Bonzini case 0x01e8:
21149ab747fSPaolo Bonzini case 0x01f0:
21249ab747fSPaolo Bonzini case 0x01f8:
21349ab747fSPaolo Bonzini {
21449ab747fSPaolo Bonzini int entry = (addr - 0x0100) >> 5;
21549ab747fSPaolo Bonzini int idx = (addr & 0x1f) >> 3;
21649ab747fSPaolo Bonzini val = s->dma_regs[entry][idx];
21749ab747fSPaolo Bonzini }
21849ab747fSPaolo Bonzini break;
21949ab747fSPaolo Bonzini /* Interrupt source */
22049ab747fSPaolo Bonzini case 0x0200:
22149ab747fSPaolo Bonzini val = s->nmi_interrupt;
22249ab747fSPaolo Bonzini break;
22349ab747fSPaolo Bonzini /* Error type */
22449ab747fSPaolo Bonzini case 0x0208:
22549ab747fSPaolo Bonzini val = 0;
22649ab747fSPaolo Bonzini break;
227dc6e3e1eSHervé Poussineau /* Memory refresh rate */
22849ab747fSPaolo Bonzini case 0x0210:
229dc6e3e1eSHervé Poussineau val = s->memory_refresh_rate;
23049ab747fSPaolo Bonzini break;
23149ab747fSPaolo Bonzini /* NV ram protect register */
23249ab747fSPaolo Bonzini case 0x0220:
23349ab747fSPaolo Bonzini val = s->nvram_protect;
23449ab747fSPaolo Bonzini break;
23549ab747fSPaolo Bonzini /* Interval timer count */
23649ab747fSPaolo Bonzini case 0x0230:
23749ab747fSPaolo Bonzini val = 0;
23849ab747fSPaolo Bonzini qemu_irq_lower(s->timer_irq);
23949ab747fSPaolo Bonzini break;
24049ab747fSPaolo Bonzini /* EISA interrupt */
24149ab747fSPaolo Bonzini case 0x0238:
24249ab747fSPaolo Bonzini val = 7; /* FIXME: should be read from EISA controller */
24349ab747fSPaolo Bonzini break;
24449ab747fSPaolo Bonzini default:
24595c357bcSHervé Poussineau qemu_log_mask(LOG_GUEST_ERROR,
24695c357bcSHervé Poussineau "rc4030: invalid read at 0x%x", (int)addr);
24749ab747fSPaolo Bonzini val = 0;
24849ab747fSPaolo Bonzini break;
24949ab747fSPaolo Bonzini }
25049ab747fSPaolo Bonzini
25149ab747fSPaolo Bonzini if ((addr & ~3) != 0x230) {
25295c357bcSHervé Poussineau trace_rc4030_read(addr, val);
25349ab747fSPaolo Bonzini }
25449ab747fSPaolo Bonzini
25549ab747fSPaolo Bonzini return val;
25649ab747fSPaolo Bonzini }
25749ab747fSPaolo Bonzini
rc4030_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)258b421f3f5SHervé Poussineau static void rc4030_write(void *opaque, hwaddr addr, uint64_t data,
259b421f3f5SHervé Poussineau unsigned int size)
26049ab747fSPaolo Bonzini {
26149ab747fSPaolo Bonzini rc4030State *s = opaque;
262b421f3f5SHervé Poussineau uint32_t val = data;
26349ab747fSPaolo Bonzini addr &= 0x3fff;
26449ab747fSPaolo Bonzini
26595c357bcSHervé Poussineau trace_rc4030_write(addr, val);
26649ab747fSPaolo Bonzini
26749ab747fSPaolo Bonzini switch (addr & ~0x3) {
26849ab747fSPaolo Bonzini /* Global config register */
26949ab747fSPaolo Bonzini case 0x0000:
27049ab747fSPaolo Bonzini s->config = val;
27149ab747fSPaolo Bonzini break;
27249ab747fSPaolo Bonzini /* DMA transl. table base */
27349ab747fSPaolo Bonzini case 0x0018:
274c627e752SHervé Poussineau s->dma_tl_base = val;
27549ab747fSPaolo Bonzini break;
27649ab747fSPaolo Bonzini /* DMA transl. table limit */
27749ab747fSPaolo Bonzini case 0x0020:
278c627e752SHervé Poussineau s->dma_tl_limit = val;
27949ab747fSPaolo Bonzini break;
28049ab747fSPaolo Bonzini /* DMA transl. table invalidated */
28149ab747fSPaolo Bonzini case 0x0028:
28249ab747fSPaolo Bonzini break;
28349ab747fSPaolo Bonzini /* Cache Maintenance */
28449ab747fSPaolo Bonzini case 0x0030:
28549ab747fSPaolo Bonzini s->cache_maint = val;
28649ab747fSPaolo Bonzini break;
28749ab747fSPaolo Bonzini /* I/O Cache Physical Tag */
28849ab747fSPaolo Bonzini case 0x0048:
28949ab747fSPaolo Bonzini s->cache_ptag = val;
29049ab747fSPaolo Bonzini break;
29149ab747fSPaolo Bonzini /* I/O Cache Logical Tag */
29249ab747fSPaolo Bonzini case 0x0050:
29349ab747fSPaolo Bonzini s->cache_ltag = val;
29449ab747fSPaolo Bonzini break;
29549ab747fSPaolo Bonzini /* I/O Cache Byte Mask */
29649ab747fSPaolo Bonzini case 0x0058:
29749ab747fSPaolo Bonzini s->cache_bmask |= val; /* HACK */
29849ab747fSPaolo Bonzini break;
29949ab747fSPaolo Bonzini /* I/O Cache Buffer Window */
30049ab747fSPaolo Bonzini case 0x0060:
30149ab747fSPaolo Bonzini /* HACK */
30249ab747fSPaolo Bonzini if (s->cache_ltag == 0x80000001 && s->cache_bmask == 0xf0f0f0f) {
30349ab747fSPaolo Bonzini hwaddr dest = s->cache_ptag & ~0x1;
30449ab747fSPaolo Bonzini dest += (s->cache_maint & 0x3) << 3;
30549ab747fSPaolo Bonzini cpu_physical_memory_write(dest, &val, 4);
30649ab747fSPaolo Bonzini }
30749ab747fSPaolo Bonzini break;
30849ab747fSPaolo Bonzini /* Remote Speed Registers */
30949ab747fSPaolo Bonzini case 0x0070:
31049ab747fSPaolo Bonzini case 0x0078:
31149ab747fSPaolo Bonzini case 0x0080:
31249ab747fSPaolo Bonzini case 0x0088:
31349ab747fSPaolo Bonzini case 0x0090:
31449ab747fSPaolo Bonzini case 0x0098:
31549ab747fSPaolo Bonzini case 0x00a0:
31649ab747fSPaolo Bonzini case 0x00a8:
31749ab747fSPaolo Bonzini case 0x00b0:
31849ab747fSPaolo Bonzini case 0x00b8:
31949ab747fSPaolo Bonzini case 0x00c0:
32049ab747fSPaolo Bonzini case 0x00c8:
32149ab747fSPaolo Bonzini case 0x00d0:
32249ab747fSPaolo Bonzini case 0x00d8:
32349ab747fSPaolo Bonzini case 0x00e0:
32449ab747fSPaolo Bonzini case 0x00e8:
32549ab747fSPaolo Bonzini s->rem_speed[(addr - 0x0070) >> 3] = val;
32649ab747fSPaolo Bonzini break;
32749ab747fSPaolo Bonzini /* DMA channel base address */
32849ab747fSPaolo Bonzini case 0x0100:
32949ab747fSPaolo Bonzini case 0x0108:
33049ab747fSPaolo Bonzini case 0x0110:
33149ab747fSPaolo Bonzini case 0x0118:
33249ab747fSPaolo Bonzini case 0x0120:
33349ab747fSPaolo Bonzini case 0x0128:
33449ab747fSPaolo Bonzini case 0x0130:
33549ab747fSPaolo Bonzini case 0x0138:
33649ab747fSPaolo Bonzini case 0x0140:
33749ab747fSPaolo Bonzini case 0x0148:
33849ab747fSPaolo Bonzini case 0x0150:
33949ab747fSPaolo Bonzini case 0x0158:
34049ab747fSPaolo Bonzini case 0x0160:
34149ab747fSPaolo Bonzini case 0x0168:
34249ab747fSPaolo Bonzini case 0x0170:
34349ab747fSPaolo Bonzini case 0x0178:
34449ab747fSPaolo Bonzini case 0x0180:
34549ab747fSPaolo Bonzini case 0x0188:
34649ab747fSPaolo Bonzini case 0x0190:
34749ab747fSPaolo Bonzini case 0x0198:
34849ab747fSPaolo Bonzini case 0x01a0:
34949ab747fSPaolo Bonzini case 0x01a8:
35049ab747fSPaolo Bonzini case 0x01b0:
35149ab747fSPaolo Bonzini case 0x01b8:
35249ab747fSPaolo Bonzini case 0x01c0:
35349ab747fSPaolo Bonzini case 0x01c8:
35449ab747fSPaolo Bonzini case 0x01d0:
35549ab747fSPaolo Bonzini case 0x01d8:
35649ab747fSPaolo Bonzini case 0x01e0:
35749ab747fSPaolo Bonzini case 0x01e8:
35849ab747fSPaolo Bonzini case 0x01f0:
35949ab747fSPaolo Bonzini case 0x01f8:
36049ab747fSPaolo Bonzini {
36149ab747fSPaolo Bonzini int entry = (addr - 0x0100) >> 5;
36249ab747fSPaolo Bonzini int idx = (addr & 0x1f) >> 3;
36349ab747fSPaolo Bonzini s->dma_regs[entry][idx] = val;
36449ab747fSPaolo Bonzini }
36549ab747fSPaolo Bonzini break;
366dc6e3e1eSHervé Poussineau /* Memory refresh rate */
36749ab747fSPaolo Bonzini case 0x0210:
368dc6e3e1eSHervé Poussineau s->memory_refresh_rate = val;
36949ab747fSPaolo Bonzini break;
37049ab747fSPaolo Bonzini /* Interval timer reload */
37149ab747fSPaolo Bonzini case 0x0228:
372c0a3172fSPrasad J Pandit s->itr = val & 0x01FF;
37349ab747fSPaolo Bonzini qemu_irq_lower(s->timer_irq);
37449ab747fSPaolo Bonzini set_next_tick(s);
37549ab747fSPaolo Bonzini break;
37649ab747fSPaolo Bonzini /* EISA interrupt */
37749ab747fSPaolo Bonzini case 0x0238:
37849ab747fSPaolo Bonzini break;
37949ab747fSPaolo Bonzini default:
38095c357bcSHervé Poussineau qemu_log_mask(LOG_GUEST_ERROR,
38195c357bcSHervé Poussineau "rc4030: invalid write of 0x%02x at 0x%x",
38295c357bcSHervé Poussineau val, (int)addr);
38349ab747fSPaolo Bonzini break;
38449ab747fSPaolo Bonzini }
38549ab747fSPaolo Bonzini }
38649ab747fSPaolo Bonzini
38749ab747fSPaolo Bonzini static const MemoryRegionOps rc4030_ops = {
388b421f3f5SHervé Poussineau .read = rc4030_read,
389b421f3f5SHervé Poussineau .write = rc4030_write,
390b421f3f5SHervé Poussineau .impl.min_access_size = 4,
391b421f3f5SHervé Poussineau .impl.max_access_size = 4,
39249ab747fSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
39349ab747fSPaolo Bonzini };
39449ab747fSPaolo Bonzini
update_jazz_irq(rc4030State * s)39549ab747fSPaolo Bonzini static void update_jazz_irq(rc4030State *s)
39649ab747fSPaolo Bonzini {
39749ab747fSPaolo Bonzini uint16_t pending;
39849ab747fSPaolo Bonzini
39949ab747fSPaolo Bonzini pending = s->isr_jazz & s->imr_jazz;
40049ab747fSPaolo Bonzini
40168fa5f55SFilip Bozuta if (pending != 0) {
40249ab747fSPaolo Bonzini qemu_irq_raise(s->jazz_bus_irq);
40368fa5f55SFilip Bozuta } else {
40449ab747fSPaolo Bonzini qemu_irq_lower(s->jazz_bus_irq);
40549ab747fSPaolo Bonzini }
40668fa5f55SFilip Bozuta }
40749ab747fSPaolo Bonzini
rc4030_irq_jazz_request(void * opaque,int irq,int level)40849ab747fSPaolo Bonzini static void rc4030_irq_jazz_request(void *opaque, int irq, int level)
40949ab747fSPaolo Bonzini {
41049ab747fSPaolo Bonzini rc4030State *s = opaque;
41149ab747fSPaolo Bonzini
41249ab747fSPaolo Bonzini if (level) {
41349ab747fSPaolo Bonzini s->isr_jazz |= 1 << irq;
41449ab747fSPaolo Bonzini } else {
41549ab747fSPaolo Bonzini s->isr_jazz &= ~(1 << irq);
41649ab747fSPaolo Bonzini }
41749ab747fSPaolo Bonzini
41849ab747fSPaolo Bonzini update_jazz_irq(s);
41949ab747fSPaolo Bonzini }
42049ab747fSPaolo Bonzini
rc4030_periodic_timer(void * opaque)42149ab747fSPaolo Bonzini static void rc4030_periodic_timer(void *opaque)
42249ab747fSPaolo Bonzini {
42349ab747fSPaolo Bonzini rc4030State *s = opaque;
42449ab747fSPaolo Bonzini
42549ab747fSPaolo Bonzini set_next_tick(s);
42649ab747fSPaolo Bonzini qemu_irq_raise(s->timer_irq);
42749ab747fSPaolo Bonzini }
42849ab747fSPaolo Bonzini
jazzio_read(void * opaque,hwaddr addr,unsigned int size)429b421f3f5SHervé Poussineau static uint64_t jazzio_read(void *opaque, hwaddr addr, unsigned int size)
43049ab747fSPaolo Bonzini {
43149ab747fSPaolo Bonzini rc4030State *s = opaque;
43249ab747fSPaolo Bonzini uint32_t val;
43349ab747fSPaolo Bonzini uint32_t irq;
43449ab747fSPaolo Bonzini addr &= 0xfff;
43549ab747fSPaolo Bonzini
43649ab747fSPaolo Bonzini switch (addr) {
43749ab747fSPaolo Bonzini /* Local bus int source */
43849ab747fSPaolo Bonzini case 0x00: {
43949ab747fSPaolo Bonzini uint32_t pending = s->isr_jazz & s->imr_jazz;
44049ab747fSPaolo Bonzini val = 0;
44149ab747fSPaolo Bonzini irq = 0;
44249ab747fSPaolo Bonzini while (pending) {
44349ab747fSPaolo Bonzini if (pending & 1) {
44449ab747fSPaolo Bonzini val = (irq + 1) << 2;
44549ab747fSPaolo Bonzini break;
44649ab747fSPaolo Bonzini }
44749ab747fSPaolo Bonzini irq++;
44849ab747fSPaolo Bonzini pending >>= 1;
44949ab747fSPaolo Bonzini }
45049ab747fSPaolo Bonzini break;
45149ab747fSPaolo Bonzini }
45249ab747fSPaolo Bonzini /* Local bus int enable mask */
45349ab747fSPaolo Bonzini case 0x02:
45449ab747fSPaolo Bonzini val = s->imr_jazz;
45549ab747fSPaolo Bonzini break;
45649ab747fSPaolo Bonzini default:
45795c357bcSHervé Poussineau qemu_log_mask(LOG_GUEST_ERROR,
45895c357bcSHervé Poussineau "rc4030/jazzio: invalid read at 0x%x", (int)addr);
45949ab747fSPaolo Bonzini val = 0;
46095c357bcSHervé Poussineau break;
46149ab747fSPaolo Bonzini }
46249ab747fSPaolo Bonzini
46395c357bcSHervé Poussineau trace_jazzio_read(addr, val);
46449ab747fSPaolo Bonzini
46549ab747fSPaolo Bonzini return val;
46649ab747fSPaolo Bonzini }
46749ab747fSPaolo Bonzini
jazzio_write(void * opaque,hwaddr addr,uint64_t data,unsigned int size)468b421f3f5SHervé Poussineau static void jazzio_write(void *opaque, hwaddr addr, uint64_t data,
469b421f3f5SHervé Poussineau unsigned int size)
47049ab747fSPaolo Bonzini {
47149ab747fSPaolo Bonzini rc4030State *s = opaque;
472b421f3f5SHervé Poussineau uint32_t val = data;
47349ab747fSPaolo Bonzini addr &= 0xfff;
47449ab747fSPaolo Bonzini
47595c357bcSHervé Poussineau trace_jazzio_write(addr, val);
47649ab747fSPaolo Bonzini
47749ab747fSPaolo Bonzini switch (addr) {
47849ab747fSPaolo Bonzini /* Local bus int enable mask */
47949ab747fSPaolo Bonzini case 0x02:
48049ab747fSPaolo Bonzini s->imr_jazz = val;
48149ab747fSPaolo Bonzini update_jazz_irq(s);
48249ab747fSPaolo Bonzini break;
48349ab747fSPaolo Bonzini default:
48495c357bcSHervé Poussineau qemu_log_mask(LOG_GUEST_ERROR,
48595c357bcSHervé Poussineau "rc4030/jazzio: invalid write of 0x%02x at 0x%x",
48695c357bcSHervé Poussineau val, (int)addr);
48749ab747fSPaolo Bonzini break;
48849ab747fSPaolo Bonzini }
48949ab747fSPaolo Bonzini }
49049ab747fSPaolo Bonzini
49149ab747fSPaolo Bonzini static const MemoryRegionOps jazzio_ops = {
492b421f3f5SHervé Poussineau .read = jazzio_read,
493b421f3f5SHervé Poussineau .write = jazzio_write,
494b421f3f5SHervé Poussineau .impl.min_access_size = 2,
495b421f3f5SHervé Poussineau .impl.max_access_size = 2,
49649ab747fSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
49749ab747fSPaolo Bonzini };
49849ab747fSPaolo Bonzini
rc4030_dma_translate(IOMMUMemoryRegion * iommu,hwaddr addr,IOMMUAccessFlags flag,int iommu_idx)4993df9d748SAlexey Kardashevskiy static IOMMUTLBEntry rc4030_dma_translate(IOMMUMemoryRegion *iommu, hwaddr addr,
5002c91bcf2SPeter Maydell IOMMUAccessFlags flag, int iommu_idx)
501c627e752SHervé Poussineau {
502c627e752SHervé Poussineau rc4030State *s = container_of(iommu, rc4030State, dma_mr);
503c627e752SHervé Poussineau IOMMUTLBEntry ret = {
504c627e752SHervé Poussineau .target_as = &address_space_memory,
505c627e752SHervé Poussineau .iova = addr & ~(DMA_PAGESIZE - 1),
506c627e752SHervé Poussineau .translated_addr = 0,
507c627e752SHervé Poussineau .addr_mask = DMA_PAGESIZE - 1,
508c627e752SHervé Poussineau .perm = IOMMU_NONE,
509c627e752SHervé Poussineau };
510c627e752SHervé Poussineau uint64_t i, entry_address;
511c627e752SHervé Poussineau dma_pagetable_entry entry;
512c627e752SHervé Poussineau
513c627e752SHervé Poussineau i = addr / DMA_PAGESIZE;
514c627e752SHervé Poussineau if (i < s->dma_tl_limit / sizeof(entry)) {
515c627e752SHervé Poussineau entry_address = (s->dma_tl_base & 0x7fffffff) + i * sizeof(entry);
516c627e752SHervé Poussineau if (address_space_read(ret.target_as, entry_address,
517b7cbebf2SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED, &entry, sizeof(entry))
518b7cbebf2SPhilippe Mathieu-Daudé == MEMTX_OK) {
519c627e752SHervé Poussineau ret.translated_addr = entry.frame & ~(DMA_PAGESIZE - 1);
520c627e752SHervé Poussineau ret.perm = IOMMU_RW;
521c627e752SHervé Poussineau }
522c627e752SHervé Poussineau }
523c627e752SHervé Poussineau
524c627e752SHervé Poussineau return ret;
525c627e752SHervé Poussineau }
526c627e752SHervé Poussineau
rc4030_reset(DeviceState * dev)527d791d60fSHervé Poussineau static void rc4030_reset(DeviceState *dev)
52849ab747fSPaolo Bonzini {
529d791d60fSHervé Poussineau rc4030State *s = RC4030(dev);
53049ab747fSPaolo Bonzini int i;
53149ab747fSPaolo Bonzini
53249ab747fSPaolo Bonzini s->config = 0x410; /* some boards seem to accept 0x104 too */
53349ab747fSPaolo Bonzini s->revision = 1;
53449ab747fSPaolo Bonzini s->invalid_address_register = 0;
53549ab747fSPaolo Bonzini
53649ab747fSPaolo Bonzini memset(s->dma_regs, 0, sizeof(s->dma_regs));
53749ab747fSPaolo Bonzini
53849ab747fSPaolo Bonzini s->remote_failed_address = s->memory_failed_address = 0;
53949ab747fSPaolo Bonzini s->cache_maint = 0;
54049ab747fSPaolo Bonzini s->cache_ptag = s->cache_ltag = 0;
54149ab747fSPaolo Bonzini s->cache_bmask = 0;
54249ab747fSPaolo Bonzini
543dc6e3e1eSHervé Poussineau s->memory_refresh_rate = 0x18186;
54449ab747fSPaolo Bonzini s->nvram_protect = 7;
545a9e2d149SAleksandar Markovic for (i = 0; i < 15; i++) {
54649ab747fSPaolo Bonzini s->rem_speed[i] = 7;
547a9e2d149SAleksandar Markovic }
54849ab747fSPaolo Bonzini s->imr_jazz = 0x10; /* XXX: required by firmware, but why? */
54949ab747fSPaolo Bonzini s->isr_jazz = 0;
55049ab747fSPaolo Bonzini
55149ab747fSPaolo Bonzini s->itr = 0;
55249ab747fSPaolo Bonzini
55349ab747fSPaolo Bonzini qemu_irq_lower(s->timer_irq);
55449ab747fSPaolo Bonzini qemu_irq_lower(s->jazz_bus_irq);
55549ab747fSPaolo Bonzini }
55649ab747fSPaolo Bonzini
rc4030_post_load(void * opaque,int version_id)55773bfa8c0SDr. David Alan Gilbert static int rc4030_post_load(void *opaque, int version_id)
55849ab747fSPaolo Bonzini {
55949ab747fSPaolo Bonzini rc4030State *s = opaque;
56049ab747fSPaolo Bonzini
56149ab747fSPaolo Bonzini set_next_tick(s);
56249ab747fSPaolo Bonzini update_jazz_irq(s);
56349ab747fSPaolo Bonzini
56449ab747fSPaolo Bonzini return 0;
56549ab747fSPaolo Bonzini }
56649ab747fSPaolo Bonzini
56773bfa8c0SDr. David Alan Gilbert static const VMStateDescription vmstate_rc4030 = {
56873bfa8c0SDr. David Alan Gilbert .name = "rc4030",
56973bfa8c0SDr. David Alan Gilbert .version_id = 3,
57073bfa8c0SDr. David Alan Gilbert .post_load = rc4030_post_load,
57163e6b564SRichard Henderson .fields = (const VMStateField []) {
57273bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(config, rc4030State),
57373bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(invalid_address_register, rc4030State),
57473bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32_2DARRAY(dma_regs, rc4030State, 8, 4),
57573bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(dma_tl_base, rc4030State),
57673bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(dma_tl_limit, rc4030State),
57773bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(cache_maint, rc4030State),
57873bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(remote_failed_address, rc4030State),
57973bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(memory_failed_address, rc4030State),
58073bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(cache_ptag, rc4030State),
58173bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(cache_ltag, rc4030State),
58273bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(cache_bmask, rc4030State),
58373bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(memory_refresh_rate, rc4030State),
58473bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(nvram_protect, rc4030State),
58573bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32_ARRAY(rem_speed, rc4030State, 16),
58673bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(imr_jazz, rc4030State),
58773bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(isr_jazz, rc4030State),
58873bfa8c0SDr. David Alan Gilbert VMSTATE_UINT32(itr, rc4030State),
58973bfa8c0SDr. David Alan Gilbert VMSTATE_END_OF_LIST()
59049ab747fSPaolo Bonzini }
59173bfa8c0SDr. David Alan Gilbert };
59249ab747fSPaolo Bonzini
rc4030_do_dma(void * opaque,int n,uint8_t * buf,int len,bool is_write)59368fa5f55SFilip Bozuta static void rc4030_do_dma(void *opaque, int n, uint8_t *buf,
5949842a9cfSPhilippe Mathieu-Daudé int len, bool is_write)
59549ab747fSPaolo Bonzini {
59649ab747fSPaolo Bonzini rc4030State *s = opaque;
59749ab747fSPaolo Bonzini hwaddr dma_addr;
59849ab747fSPaolo Bonzini int dev_to_mem;
59949ab747fSPaolo Bonzini
600a9e2d149SAleksandar Markovic s->dma_regs[n][DMA_REG_ENABLE] &=
601a9e2d149SAleksandar Markovic ~(DMA_FLAG_TC_INTR | DMA_FLAG_MEM_INTR | DMA_FLAG_ADDR_INTR);
60249ab747fSPaolo Bonzini
60349ab747fSPaolo Bonzini /* Check DMA channel consistency */
60449ab747fSPaolo Bonzini dev_to_mem = (s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_MEM_TO_DEV) ? 0 : 1;
60549ab747fSPaolo Bonzini if (!(s->dma_regs[n][DMA_REG_ENABLE] & DMA_FLAG_ENABLE) ||
60649ab747fSPaolo Bonzini (is_write != dev_to_mem)) {
60749ab747fSPaolo Bonzini s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_MEM_INTR;
60849ab747fSPaolo Bonzini s->nmi_interrupt |= 1 << n;
60949ab747fSPaolo Bonzini return;
61049ab747fSPaolo Bonzini }
61149ab747fSPaolo Bonzini
61249ab747fSPaolo Bonzini /* Get start address and len */
613a9e2d149SAleksandar Markovic if (len > s->dma_regs[n][DMA_REG_COUNT]) {
61449ab747fSPaolo Bonzini len = s->dma_regs[n][DMA_REG_COUNT];
615a9e2d149SAleksandar Markovic }
61649ab747fSPaolo Bonzini dma_addr = s->dma_regs[n][DMA_REG_ADDRESS];
61749ab747fSPaolo Bonzini
61849ab747fSPaolo Bonzini /* Read/write data at right place */
619a3d586f7SHervé Poussineau address_space_rw(&s->dma_as, dma_addr, MEMTXATTRS_UNSPECIFIED,
620a3d586f7SHervé Poussineau buf, len, is_write);
62149ab747fSPaolo Bonzini
62249ab747fSPaolo Bonzini s->dma_regs[n][DMA_REG_ENABLE] |= DMA_FLAG_TC_INTR;
62349ab747fSPaolo Bonzini s->dma_regs[n][DMA_REG_COUNT] -= len;
62449ab747fSPaolo Bonzini }
62549ab747fSPaolo Bonzini
62649ab747fSPaolo Bonzini struct rc4030DMAState {
62749ab747fSPaolo Bonzini void *opaque;
62849ab747fSPaolo Bonzini int n;
62949ab747fSPaolo Bonzini };
63049ab747fSPaolo Bonzini
rc4030_dma_read(void * dma,uint8_t * buf,int len)63149ab747fSPaolo Bonzini void rc4030_dma_read(void *dma, uint8_t *buf, int len)
63249ab747fSPaolo Bonzini {
63349ab747fSPaolo Bonzini rc4030_dma s = dma;
6349842a9cfSPhilippe Mathieu-Daudé rc4030_do_dma(s->opaque, s->n, buf, len, false);
63549ab747fSPaolo Bonzini }
63649ab747fSPaolo Bonzini
rc4030_dma_write(void * dma,uint8_t * buf,int len)63749ab747fSPaolo Bonzini void rc4030_dma_write(void *dma, uint8_t *buf, int len)
63849ab747fSPaolo Bonzini {
63949ab747fSPaolo Bonzini rc4030_dma s = dma;
6409842a9cfSPhilippe Mathieu-Daudé rc4030_do_dma(s->opaque, s->n, buf, len, true);
64149ab747fSPaolo Bonzini }
64249ab747fSPaolo Bonzini
rc4030_allocate_dmas(void * opaque,int n)64349ab747fSPaolo Bonzini static rc4030_dma *rc4030_allocate_dmas(void *opaque, int n)
64449ab747fSPaolo Bonzini {
64549ab747fSPaolo Bonzini rc4030_dma *s;
64649ab747fSPaolo Bonzini struct rc4030DMAState *p;
64749ab747fSPaolo Bonzini int i;
64849ab747fSPaolo Bonzini
649b21e2380SMarkus Armbruster s = g_new0(rc4030_dma, n);
650b21e2380SMarkus Armbruster p = g_new0(struct rc4030DMAState, n);
65149ab747fSPaolo Bonzini for (i = 0; i < n; i++) {
65249ab747fSPaolo Bonzini p->opaque = opaque;
65349ab747fSPaolo Bonzini p->n = i;
65449ab747fSPaolo Bonzini s[i] = p;
65549ab747fSPaolo Bonzini p++;
65649ab747fSPaolo Bonzini }
65749ab747fSPaolo Bonzini return s;
65849ab747fSPaolo Bonzini }
65949ab747fSPaolo Bonzini
rc4030_initfn(Object * obj)660d791d60fSHervé Poussineau static void rc4030_initfn(Object *obj)
66149ab747fSPaolo Bonzini {
662d791d60fSHervé Poussineau DeviceState *dev = DEVICE(obj);
663d791d60fSHervé Poussineau rc4030State *s = RC4030(obj);
664d791d60fSHervé Poussineau SysBusDevice *sysbus = SYS_BUS_DEVICE(obj);
665d791d60fSHervé Poussineau
666d791d60fSHervé Poussineau qdev_init_gpio_in(dev, rc4030_irq_jazz_request, 16);
667d791d60fSHervé Poussineau
668d791d60fSHervé Poussineau sysbus_init_irq(sysbus, &s->timer_irq);
669d791d60fSHervé Poussineau sysbus_init_irq(sysbus, &s->jazz_bus_irq);
670d791d60fSHervé Poussineau
671d791d60fSHervé Poussineau sysbus_init_mmio(sysbus, &s->iomem_chipset);
672d791d60fSHervé Poussineau sysbus_init_mmio(sysbus, &s->iomem_jazzio);
673d791d60fSHervé Poussineau }
674d791d60fSHervé Poussineau
rc4030_realize(DeviceState * dev,Error ** errp)675d791d60fSHervé Poussineau static void rc4030_realize(DeviceState *dev, Error **errp)
676d791d60fSHervé Poussineau {
677d791d60fSHervé Poussineau rc4030State *s = RC4030(dev);
678d791d60fSHervé Poussineau Object *o = OBJECT(dev);
67949ab747fSPaolo Bonzini
680d791d60fSHervé Poussineau s->periodic_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
681d791d60fSHervé Poussineau rc4030_periodic_timer, s);
68249ab747fSPaolo Bonzini
683a8457764SPhilippe Mathieu-Daudé memory_region_init_io(&s->iomem_chipset, o, &rc4030_ops, s,
68449ab747fSPaolo Bonzini "rc4030.chipset", 0x300);
685a8457764SPhilippe Mathieu-Daudé memory_region_init_io(&s->iomem_jazzio, o, &jazzio_ops, s,
68649ab747fSPaolo Bonzini "rc4030.jazzio", 0x00001000);
68749ab747fSPaolo Bonzini
6881221a474SAlexey Kardashevskiy memory_region_init_iommu(&s->dma_mr, sizeof(s->dma_mr),
6891221a474SAlexey Kardashevskiy TYPE_RC4030_IOMMU_MEMORY_REGION,
690d37eae6cSAleksandar Markovic o, "rc4030.dma", 4 * GiB);
6913df9d748SAlexey Kardashevskiy address_space_init(&s->dma_as, MEMORY_REGION(&s->dma_mr), "rc4030-dma");
692d791d60fSHervé Poussineau }
693d791d60fSHervé Poussineau
rc4030_unrealize(DeviceState * dev)694b69c3c21SMarkus Armbruster static void rc4030_unrealize(DeviceState *dev)
695d791d60fSHervé Poussineau {
696d791d60fSHervé Poussineau rc4030State *s = RC4030(dev);
697d791d60fSHervé Poussineau
698d791d60fSHervé Poussineau timer_free(s->periodic_timer);
699d791d60fSHervé Poussineau
700d791d60fSHervé Poussineau address_space_destroy(&s->dma_as);
701d791d60fSHervé Poussineau object_unparent(OBJECT(&s->dma_mr));
702d791d60fSHervé Poussineau }
703d791d60fSHervé Poussineau
rc4030_class_init(ObjectClass * klass,void * class_data)704d791d60fSHervé Poussineau static void rc4030_class_init(ObjectClass *klass, void *class_data)
705d791d60fSHervé Poussineau {
706d791d60fSHervé Poussineau DeviceClass *dc = DEVICE_CLASS(klass);
707d791d60fSHervé Poussineau
708d791d60fSHervé Poussineau dc->realize = rc4030_realize;
709d791d60fSHervé Poussineau dc->unrealize = rc4030_unrealize;
710*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, rc4030_reset);
71173bfa8c0SDr. David Alan Gilbert dc->vmsd = &vmstate_rc4030;
712d791d60fSHervé Poussineau }
713d791d60fSHervé Poussineau
714d791d60fSHervé Poussineau static const TypeInfo rc4030_info = {
715d791d60fSHervé Poussineau .name = TYPE_RC4030,
716d791d60fSHervé Poussineau .parent = TYPE_SYS_BUS_DEVICE,
717d791d60fSHervé Poussineau .instance_size = sizeof(rc4030State),
718d791d60fSHervé Poussineau .instance_init = rc4030_initfn,
719d791d60fSHervé Poussineau .class_init = rc4030_class_init,
720d791d60fSHervé Poussineau };
721d791d60fSHervé Poussineau
rc4030_iommu_memory_region_class_init(ObjectClass * klass,void * data)7221221a474SAlexey Kardashevskiy static void rc4030_iommu_memory_region_class_init(ObjectClass *klass,
7231221a474SAlexey Kardashevskiy void *data)
7241221a474SAlexey Kardashevskiy {
7251221a474SAlexey Kardashevskiy IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
7261221a474SAlexey Kardashevskiy
7271221a474SAlexey Kardashevskiy imrc->translate = rc4030_dma_translate;
7281221a474SAlexey Kardashevskiy }
7291221a474SAlexey Kardashevskiy
7301221a474SAlexey Kardashevskiy static const TypeInfo rc4030_iommu_memory_region_info = {
7311221a474SAlexey Kardashevskiy .parent = TYPE_IOMMU_MEMORY_REGION,
7321221a474SAlexey Kardashevskiy .name = TYPE_RC4030_IOMMU_MEMORY_REGION,
7331221a474SAlexey Kardashevskiy .class_init = rc4030_iommu_memory_region_class_init,
7341221a474SAlexey Kardashevskiy };
7351221a474SAlexey Kardashevskiy
rc4030_register_types(void)736d791d60fSHervé Poussineau static void rc4030_register_types(void)
737d791d60fSHervé Poussineau {
738d791d60fSHervé Poussineau type_register_static(&rc4030_info);
7391221a474SAlexey Kardashevskiy type_register_static(&rc4030_iommu_memory_region_info);
740d791d60fSHervé Poussineau }
741d791d60fSHervé Poussineau
type_init(rc4030_register_types)742d791d60fSHervé Poussineau type_init(rc4030_register_types)
743d791d60fSHervé Poussineau
7443df9d748SAlexey Kardashevskiy DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr)
745d791d60fSHervé Poussineau {
746d791d60fSHervé Poussineau DeviceState *dev;
747d791d60fSHervé Poussineau
7483e80f690SMarkus Armbruster dev = qdev_new(TYPE_RC4030);
7493c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
750d791d60fSHervé Poussineau
751d791d60fSHervé Poussineau *dmas = rc4030_allocate_dmas(dev, 4);
752d791d60fSHervé Poussineau *dma_mr = &RC4030(dev)->dma_mr;
753d791d60fSHervé Poussineau return dev;
75449ab747fSPaolo Bonzini }
755