2 * QEMU JAZZ RC4030 chipset
4 * Copyright (c) 2007-2008 Hervé Poussineau
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 #include "qemu-timer.h"
29 /********************************************************/
32 //#define DEBUG_RC4030
33 //#define DEBUG_RC4030_DMA
36 #define DPRINTF(fmt, args...) \
37 do { printf("rc4030: " fmt , ##args); } while (0)
38 static const char* irq_names
[] = { "parallel", "floppy", "sound", "video",
39 "network", "scsi", "keyboard", "mouse", "serial0", "serial1" };
41 #define DPRINTF(fmt, args...)
44 #define RC4030_ERROR(fmt, args...) \
45 do { fprintf(stderr, "rc4030 ERROR: %s: " fmt, __func__ , ##args); } while (0)
47 /********************************************************/
48 /* rc4030 emulation */
50 typedef struct dma_pagetable_entry
{
53 } __attribute__((packed
)) dma_pagetable_entry
;
55 #define DMA_PAGESIZE 4096
56 #define DMA_REG_ENABLE 1
57 #define DMA_REG_COUNT 2
58 #define DMA_REG_ADDRESS 3
60 #define DMA_FLAG_ENABLE 0x0001
61 #define DMA_FLAG_MEM_TO_DEV 0x0002
62 #define DMA_FLAG_TC_INTR 0x0100
63 #define DMA_FLAG_MEM_INTR 0x0200
64 #define DMA_FLAG_ADDR_INTR 0x0400
66 typedef struct rc4030State
68 uint32_t config
; /* 0x0000: RC4030 config register */
69 uint32_t invalid_address_register
; /* 0x0010: Invalid Address register */
72 uint32_t dma_regs
[8][4];
73 uint32_t dma_tl_base
; /* 0x0018: DMA transl. table base */
74 uint32_t dma_tl_limit
; /* 0x0020: DMA transl. table limit */
77 uint32_t remote_failed_address
; /* 0x0038: Remote Failed Address */
78 uint32_t memory_failed_address
; /* 0x0040: Memory Failed Address */
79 uint32_t cache_ptag
; /* 0x0048: I/O Cache Physical Tag */
80 uint32_t cache_ltag
; /* 0x0050: I/O Cache Logical Tag */
81 uint32_t cache_bmask
; /* 0x0058: I/O Cache Byte Mask */
82 uint32_t cache_bwin
; /* 0x0060: I/O Cache Buffer Window */
85 uint32_t nvram_protect
; /* 0x0220: NV ram protect register */
87 uint32_t rem_speed
[15];
88 uint32_t imr_jazz
; /* Local bus int enable mask */
89 uint32_t isr_jazz
; /* Local bus int source */
92 QEMUTimer
*periodic_timer
;
93 uint32_t itr
; /* Interval timer reload */
96 qemu_irq jazz_bus_irq
;
99 static void set_next_tick(rc4030State
*s
)
101 qemu_irq_lower(s
->timer_irq
);
104 tm_hz
= 1000 / (s
->itr
+ 1);
106 qemu_mod_timer(s
->periodic_timer
, qemu_get_clock(vm_clock
) + ticks_per_sec
/ tm_hz
);
109 /* called for accesses to rc4030 */
110 static uint32_t rc4030_readl(void *opaque
, target_phys_addr_t addr
)
112 rc4030State
*s
= opaque
;
116 switch (addr
& ~0x3) {
117 /* Global config register */
121 /* Invalid Address register */
123 val
= s
->invalid_address_register
;
125 /* DMA transl. table base */
127 val
= s
->dma_tl_base
;
129 /* DMA transl. table limit */
131 val
= s
->dma_tl_limit
;
133 /* Remote Failed Address */
135 val
= s
->remote_failed_address
;
137 /* Memory Failed Address */
139 val
= s
->memory_failed_address
;
141 /* I/O Cache Byte Mask */
143 val
= s
->cache_bmask
;
145 if (s
->cache_bmask
== (uint32_t)-1)
148 /* Remote Speed Registers */
164 val
= s
->rem_speed
[(addr
- 0x0070) >> 3];
166 /* DMA channel base address */
200 int entry
= (addr
- 0x0100) >> 5;
201 int idx
= (addr
& 0x1f) >> 3;
202 val
= s
->dma_regs
[entry
][idx
];
213 /* NV ram protect register */
215 val
= s
->nvram_protect
;
217 /* Interval timer count */
220 qemu_irq_lower(s
->timer_irq
);
227 RC4030_ERROR("invalid read [" TARGET_FMT_plx
"]\n", addr
);
232 if ((addr
& ~3) != 0x230)
233 DPRINTF("read 0x%02x at " TARGET_FMT_plx
"\n", val
, addr
);
238 static uint32_t rc4030_readw(void *opaque
, target_phys_addr_t addr
)
240 uint32_t v
= rc4030_readl(opaque
, addr
& ~0x3);
247 static uint32_t rc4030_readb(void *opaque
, target_phys_addr_t addr
)
249 uint32_t v
= rc4030_readl(opaque
, addr
& ~0x3);
250 return (v
>> (8 * (addr
& 0x3))) & 0xff;
253 static void rc4030_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
255 rc4030State
*s
= opaque
;
258 DPRINTF("write 0x%02x at " TARGET_FMT_plx
"\n", val
, addr
);
260 switch (addr
& ~0x3) {
261 /* Global config register */
265 /* DMA transl. table base */
267 s
->dma_tl_base
= val
;
269 /* DMA transl. table limit */
271 s
->dma_tl_limit
= val
;
273 /* DMA transl. table invalidated */
276 /* Cache Maintenance */
278 RC4030_ERROR("Cache maintenance not handled yet (val 0x%02x)\n", val
);
280 /* I/O Cache Physical Tag */
284 /* I/O Cache Logical Tag */
288 /* I/O Cache Byte Mask */
290 s
->cache_bmask
|= val
; /* HACK */
292 /* I/O Cache Buffer Window */
296 if (s
->cache_ltag
== 0x80000001 && s
->cache_bmask
== 0xf0f0f0f) {
297 target_phys_addr_t dests
[] = { 4, 0, 8, 0x10 };
298 static int current
= 0;
299 target_phys_addr_t dest
= 0 + dests
[current
];
301 current
= (current
+ 1) % (ARRAY_SIZE(dests
));
302 buf
= s
->cache_bwin
- 1;
303 cpu_physical_memory_rw(dest
, &buf
, 1, 1);
306 /* Remote Speed Registers */
322 s
->rem_speed
[(addr
- 0x0070) >> 3] = val
;
324 /* DMA channel base address */
358 int entry
= (addr
- 0x0100) >> 5;
359 int idx
= (addr
& 0x1f) >> 3;
360 s
->dma_regs
[entry
][idx
] = val
;
367 /* Interval timer reload */
370 qemu_irq_lower(s
->timer_irq
);
374 RC4030_ERROR("invalid write of 0x%02x at [" TARGET_FMT_plx
"]\n", val
, addr
);
379 static void rc4030_writew(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
381 uint32_t old_val
= rc4030_readl(opaque
, addr
& ~0x3);
384 val
= (val
<< 16) | (old_val
& 0x0000ffff);
386 val
= val
| (old_val
& 0xffff0000);
387 rc4030_writel(opaque
, addr
& ~0x3, val
);
390 static void rc4030_writeb(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
392 uint32_t old_val
= rc4030_readl(opaque
, addr
& ~0x3);
396 val
= val
| (old_val
& 0xffffff00);
399 val
= (val
<< 8) | (old_val
& 0xffff00ff);
402 val
= (val
<< 16) | (old_val
& 0xff00ffff);
405 val
= (val
<< 24) | (old_val
& 0x00ffffff);
408 rc4030_writel(opaque
, addr
& ~0x3, val
);
411 static CPUReadMemoryFunc
*rc4030_read
[3] = {
417 static CPUWriteMemoryFunc
*rc4030_write
[3] = {
423 static void update_jazz_irq(rc4030State
*s
)
427 pending
= s
->isr_jazz
& s
->imr_jazz
;
430 if (s
->isr_jazz
!= 0) {
432 DPRINTF("pending irqs:");
433 for (irq
= 0; irq
< ARRAY_SIZE(irq_names
); irq
++) {
434 if (s
->isr_jazz
& (1 << irq
)) {
435 printf(" %s", irq_names
[irq
]);
436 if (!(s
->imr_jazz
& (1 << irq
))) {
446 qemu_irq_raise(s
->jazz_bus_irq
);
448 qemu_irq_lower(s
->jazz_bus_irq
);
451 static void rc4030_irq_jazz_request(void *opaque
, int irq
, int level
)
453 rc4030State
*s
= opaque
;
456 s
->isr_jazz
|= 1 << irq
;
458 s
->isr_jazz
&= ~(1 << irq
);
464 static void rc4030_periodic_timer(void *opaque
)
466 rc4030State
*s
= opaque
;
469 qemu_irq_raise(s
->timer_irq
);
472 static uint32_t jazzio_readw(void *opaque
, target_phys_addr_t addr
)
474 rc4030State
*s
= opaque
;
480 /* Local bus int source */
482 uint32_t pending
= s
->isr_jazz
& s
->imr_jazz
;
487 DPRINTF("returning irq %s\n", irq_names
[irq
]);
488 val
= (irq
+ 1) << 2;
496 /* Local bus int enable mask */
501 RC4030_ERROR("(jazz io controller) invalid read [" TARGET_FMT_plx
"]\n", addr
);
505 DPRINTF("(jazz io controller) read 0x%04x at " TARGET_FMT_plx
"\n", val
, addr
);
510 static uint32_t jazzio_readb(void *opaque
, target_phys_addr_t addr
)
513 v
= jazzio_readw(opaque
, addr
& ~0x1);
514 return (v
>> (8 * (addr
& 0x1))) & 0xff;
517 static uint32_t jazzio_readl(void *opaque
, target_phys_addr_t addr
)
520 v
= jazzio_readw(opaque
, addr
);
521 v
|= jazzio_readw(opaque
, addr
+ 2) << 16;
525 static void jazzio_writew(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
527 rc4030State
*s
= opaque
;
530 DPRINTF("(jazz io controller) write 0x%04x at " TARGET_FMT_plx
"\n", val
, addr
);
533 /* Local bus int enable mask */
539 RC4030_ERROR("(jazz io controller) invalid write of 0x%04x at [" TARGET_FMT_plx
"]\n", val
, addr
);
544 static void jazzio_writeb(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
546 uint32_t old_val
= jazzio_readw(opaque
, addr
& ~0x1);
550 val
= val
| (old_val
& 0xff00);
553 val
= (val
<< 8) | (old_val
& 0x00ff);
556 jazzio_writew(opaque
, addr
& ~0x1, val
);
559 static void jazzio_writel(void *opaque
, target_phys_addr_t addr
, uint32_t val
)
561 jazzio_writew(opaque
, addr
, val
& 0xffff);
562 jazzio_writew(opaque
, addr
+ 2, (val
>> 16) & 0xffff);
565 static CPUReadMemoryFunc
*jazzio_read
[3] = {
571 static CPUWriteMemoryFunc
*jazzio_write
[3] = {
577 static void rc4030_reset(void *opaque
)
579 rc4030State
*s
= opaque
;
582 s
->config
= 0x410; /* some boards seem to accept 0x104 too */
583 s
->invalid_address_register
= 0;
585 memset(s
->dma_regs
, 0, sizeof(s
->dma_regs
));
586 s
->dma_tl_base
= s
->dma_tl_limit
= 0;
588 s
->remote_failed_address
= s
->memory_failed_address
= 0;
589 s
->cache_ptag
= s
->cache_ltag
= 0;
590 s
->cache_bmask
= s
->cache_bwin
= 0;
592 s
->offset210
= 0x18186;
593 s
->nvram_protect
= 7;
595 for (i
= 0; i
< 15; i
++)
597 s
->imr_jazz
= s
->isr_jazz
= 0;
601 qemu_irq_lower(s
->timer_irq
);
602 qemu_irq_lower(s
->jazz_bus_irq
);
605 static void rc4030_do_dma(void *opaque
, int n
, uint8_t *buf
, int len
, int is_write
)
607 rc4030State
*s
= opaque
;
608 target_phys_addr_t entry_addr
;
609 target_phys_addr_t dma_addr
, phys_addr
;
610 dma_pagetable_entry entry
;
611 int index
, dev_to_mem
;
614 s
->dma_regs
[n
][DMA_REG_ENABLE
] &= ~(DMA_FLAG_TC_INTR
| DMA_FLAG_MEM_INTR
| DMA_FLAG_ADDR_INTR
);
616 /* Check DMA channel consistency */
617 dev_to_mem
= (s
->dma_regs
[n
][DMA_REG_ENABLE
] & DMA_FLAG_MEM_TO_DEV
) ? 0 : 1;
618 if (!(s
->dma_regs
[n
][DMA_REG_ENABLE
] & DMA_FLAG_ENABLE
) ||
619 (is_write
!= dev_to_mem
)) {
620 s
->dma_regs
[n
][DMA_REG_ENABLE
] |= DMA_FLAG_MEM_INTR
;
624 if (len
> s
->dma_regs
[n
][DMA_REG_COUNT
])
625 len
= s
->dma_regs
[n
][DMA_REG_COUNT
];
627 dma_addr
= s
->dma_regs
[n
][DMA_REG_ADDRESS
];
631 s
->dma_regs
[n
][DMA_REG_ENABLE
] |= DMA_FLAG_TC_INTR
;
635 ncpy
= DMA_PAGESIZE
- (dma_addr
& (DMA_PAGESIZE
- 1));
639 /* Get DMA translation table entry */
640 index
= dma_addr
/ DMA_PAGESIZE
;
641 if (index
>= s
->dma_tl_limit
/ sizeof(dma_pagetable_entry
)) {
642 s
->dma_regs
[n
][DMA_REG_ENABLE
] |= DMA_FLAG_MEM_INTR
;
645 entry_addr
= s
->dma_tl_base
+ index
* sizeof(dma_pagetable_entry
);
646 /* XXX: not sure. should we really use only lowest bits? */
647 entry_addr
&= 0x7fffffff;
648 cpu_physical_memory_rw(entry_addr
, (uint8_t *)&entry
, sizeof(entry
), 0);
650 /* Read/write data at right place */
651 phys_addr
= entry
.frame
+ (dma_addr
& (DMA_PAGESIZE
- 1));
652 cpu_physical_memory_rw(phys_addr
, &buf
[i
], ncpy
, is_write
);
656 s
->dma_regs
[n
][DMA_REG_COUNT
] -= ncpy
;
659 #ifdef DEBUG_RC4030_DMA
662 printf("rc4030 dma: Copying %d bytes %s host %p\n",
663 len
, is_write
? "from" : "to", buf
);
664 for (i
= 0; i
< len
; i
+= 16) {
665 int n
= min(16, len
- i
);
666 for (j
= 0; j
< n
; j
++)
667 printf("%02x ", buf
[i
+ j
]);
671 for (j
= 0; j
< n
; j
++)
672 printf("%c", isprint(buf
[i
+ j
]) ? buf
[i
+ j
] : '.');
679 struct rc4030DMAState
{
684 static void rc4030_dma_read(void *dma
, uint8_t *buf
, int len
)
687 rc4030_do_dma(s
->opaque
, s
->n
, buf
, len
, 0);
690 static void rc4030_dma_write(void *dma
, uint8_t *buf
, int len
)
693 rc4030_do_dma(s
->opaque
, s
->n
, buf
, len
, 1);
696 static rc4030_dma
*rc4030_allocate_dmas(void *opaque
, int n
)
699 struct rc4030DMAState
*p
;
702 s
= (rc4030_dma
*)qemu_mallocz(sizeof(rc4030_dma
) * n
);
703 p
= (struct rc4030DMAState
*)qemu_mallocz(sizeof(struct rc4030DMAState
) * n
);
704 for (i
= 0; i
< n
; i
++) {
713 qemu_irq
*rc4030_init(qemu_irq timer
, qemu_irq jazz_bus
,
715 rc4030_dma_function
*dma_read
, rc4030_dma_function
*dma_write
)
718 int s_chipset
, s_jazzio
;
720 s
= qemu_mallocz(sizeof(rc4030State
));
724 *dmas
= rc4030_allocate_dmas(s
, 4);
725 *dma_read
= rc4030_dma_read
;
726 *dma_write
= rc4030_dma_write
;
728 s
->periodic_timer
= qemu_new_timer(vm_clock
, rc4030_periodic_timer
, s
);
729 s
->timer_irq
= timer
;
730 s
->jazz_bus_irq
= jazz_bus
;
732 qemu_register_reset(rc4030_reset
, s
);
735 s_chipset
= cpu_register_io_memory(0, rc4030_read
, rc4030_write
, s
);
736 cpu_register_physical_memory(0x80000000, 0x300, s_chipset
);
737 s_jazzio
= cpu_register_io_memory(0, jazzio_read
, jazzio_write
, s
);
738 cpu_register_physical_memory(0xf0000000, 0x00001000, s_jazzio
);
740 return qemu_allocate_irqs(rc4030_irq_jazz_request
, s
, 16);