2 * QEMU SiI3112A PCI to Serial ATA Controller Emulation
4 * Copyright (C) 2017 BALATON Zoltan <balaton@eik.bme.hu>
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
11 /* For documentation on this and similar cards see:
12 * http://wiki.osdev.org/User:Quok/Silicon_Image_Datasheets
15 #include "qemu/osdep.h"
16 #include "hw/ide/pci.h"
19 #define TYPE_SII3112_PCI "sii3112"
20 #define SII3112_PCI(obj) OBJECT_CHECK(SiI3112PCIState, (obj), \
23 typedef struct SiI3112Regs
{
30 typedef struct SiI3112PCIState
{
36 /* The sii3112_reg_read and sii3112_reg_write functions implement the
37 * Internal Register Space - BAR5 (section 6.7 of the data sheet).
40 static uint64_t sii3112_reg_read(void *opaque
, hwaddr addr
,
43 SiI3112PCIState
*d
= opaque
;
48 val
= d
->i
.bmdma
[0].cmd
;
51 val
= d
->regs
[0].swdata
;
54 val
= d
->i
.bmdma
[0].status
;
60 val
= bmdma_addr_ioport_ops
.read(&d
->i
.bmdma
[0], addr
- 4, size
);
63 val
= d
->i
.bmdma
[1].cmd
;
66 val
= d
->regs
[1].swdata
;
69 val
= d
->i
.bmdma
[1].status
;
75 val
= bmdma_addr_ioport_ops
.read(&d
->i
.bmdma
[1], addr
- 12, size
);
78 val
= d
->i
.bmdma
[0].cmd
;
79 val
|= (d
->regs
[0].confstat
& (1UL << 11) ? (1 << 4) : 0); /*SATAINT0*/
80 val
|= (d
->regs
[1].confstat
& (1UL << 11) ? (1 << 6) : 0); /*SATAINT1*/
81 val
|= (d
->i
.bmdma
[1].status
& BM_STATUS_INT
? (1 << 14) : 0);
82 val
|= (uint32_t)d
->i
.bmdma
[0].status
<< 16;
83 val
|= (uint32_t)d
->i
.bmdma
[1].status
<< 24;
86 val
= d
->i
.bmdma
[1].cmd
;
87 val
|= (d
->regs
[1].confstat
& (1UL << 11) ? (1 << 4) : 0);
88 val
|= (uint32_t)d
->i
.bmdma
[1].status
<< 16;
92 val
= ide_ioport_read(&d
->i
.bus
[0], addr
- 0x80);
93 } else if (addr
== 0x80) {
94 val
= (size
== 2) ? ide_data_readw(&d
->i
.bus
[0], 0) :
95 ide_data_readl(&d
->i
.bus
[0], 0);
97 val
= (1ULL << (size
* 8)) - 1;
101 val
= (size
== 1) ? ide_status_read(&d
->i
.bus
[0], 4) :
102 (1ULL << (size
* 8)) - 1;
105 val
= d
->regs
[0].confstat
;
109 val
= ide_ioport_read(&d
->i
.bus
[1], addr
- 0xc0);
110 } else if (addr
== 0xc0) {
111 val
= (size
== 2) ? ide_data_readw(&d
->i
.bus
[1], 0) :
112 ide_data_readl(&d
->i
.bus
[1], 0);
114 val
= (1ULL << (size
* 8)) - 1;
118 val
= (size
== 1) ? ide_status_read(&d
->i
.bus
[0], 4) :
119 (1ULL << (size
* 8)) - 1;
122 val
= d
->regs
[1].confstat
;
125 val
= d
->regs
[0].scontrol
;
128 val
= (d
->i
.bus
[0].ifs
[0].blk
) ? 0x113 : 0;
131 val
= (uint32_t)d
->regs
[0].sien
<< 16;
134 val
= d
->regs
[1].scontrol
;
137 val
= (d
->i
.bus
[1].ifs
[0].blk
) ? 0x113 : 0;
140 val
= (uint32_t)d
->regs
[1].sien
<< 16;
145 trace_sii3112_read(size
, addr
, val
);
149 static void sii3112_reg_write(void *opaque
, hwaddr addr
,
150 uint64_t val
, unsigned int size
)
152 SiI3112PCIState
*d
= opaque
;
154 trace_sii3112_write(size
, addr
, val
);
158 bmdma_cmd_writeb(&d
->i
.bmdma
[0], val
);
162 d
->regs
[0].swdata
= val
& 0x3f;
166 d
->i
.bmdma
[0].status
= (val
& 0x60) | (d
->i
.bmdma
[0].status
& 1) |
167 (d
->i
.bmdma
[0].status
& ~val
& 6);
170 bmdma_addr_ioport_ops
.write(&d
->i
.bmdma
[0], addr
- 4, val
, size
);
174 bmdma_cmd_writeb(&d
->i
.bmdma
[1], val
);
178 d
->regs
[1].swdata
= val
& 0x3f;
182 d
->i
.bmdma
[1].status
= (val
& 0x60) | (d
->i
.bmdma
[1].status
& 1) |
183 (d
->i
.bmdma
[1].status
& ~val
& 6);
186 bmdma_addr_ioport_ops
.write(&d
->i
.bmdma
[1], addr
- 12, val
, size
);
190 ide_ioport_write(&d
->i
.bus
[0], addr
- 0x80, val
);
191 } else if (addr
== 0x80) {
193 ide_data_writew(&d
->i
.bus
[0], 0, val
);
195 ide_data_writel(&d
->i
.bus
[0], 0, val
);
201 ide_cmd_write(&d
->i
.bus
[0], 4, val
);
206 ide_ioport_write(&d
->i
.bus
[1], addr
- 0xc0, val
);
207 } else if (addr
== 0xc0) {
209 ide_data_writew(&d
->i
.bus
[1], 0, val
);
211 ide_data_writel(&d
->i
.bus
[1], 0, val
);
217 ide_cmd_write(&d
->i
.bus
[1], 4, val
);
221 d
->regs
[0].scontrol
= val
& 0xfff;
223 ide_bus_reset(&d
->i
.bus
[0]);
227 d
->regs
[0].sien
= (val
>> 16) & 0x3eed;
230 d
->regs
[1].scontrol
= val
& 0xfff;
232 ide_bus_reset(&d
->i
.bus
[1]);
236 d
->regs
[1].sien
= (val
>> 16) & 0x3eed;
243 static const MemoryRegionOps sii3112_reg_ops
= {
244 .read
= sii3112_reg_read
,
245 .write
= sii3112_reg_write
,
246 .endianness
= DEVICE_LITTLE_ENDIAN
,
249 /* the PCI irq level is the logical OR of the two channels */
250 static void sii3112_update_irq(SiI3112PCIState
*s
)
254 for (i
= 0; i
< 2; i
++) {
255 set
|= s
->regs
[i
].confstat
& (1UL << 11);
257 pci_set_irq(PCI_DEVICE(s
), (set
? 1 : 0));
260 static void sii3112_set_irq(void *opaque
, int channel
, int level
)
262 SiI3112PCIState
*s
= opaque
;
264 trace_sii3112_set_irq(channel
, level
);
266 s
->regs
[channel
].confstat
|= (1UL << 11);
268 s
->regs
[channel
].confstat
&= ~(1UL << 11);
271 sii3112_update_irq(s
);
274 static void sii3112_reset(void *opaque
)
276 SiI3112PCIState
*s
= opaque
;
279 for (i
= 0; i
< 2; i
++) {
280 s
->regs
[i
].confstat
= 0x6515 << 16;
281 ide_bus_reset(&s
->i
.bus
[i
]);
285 static void sii3112_pci_realize(PCIDevice
*dev
, Error
**errp
)
287 SiI3112PCIState
*d
= SII3112_PCI(dev
);
288 PCIIDEState
*s
= PCI_IDE(dev
);
293 pci_config_set_interrupt_pin(dev
->config
, 1);
294 pci_set_byte(dev
->config
+ PCI_CACHE_LINE_SIZE
, 8);
296 /* BAR5 is in PCI memory space */
297 memory_region_init_io(&d
->mmio
, OBJECT(d
), &sii3112_reg_ops
, d
,
298 "sii3112.bar5", 0x200);
299 pci_register_bar(dev
, 5, PCI_BASE_ADDRESS_SPACE_MEMORY
, &d
->mmio
);
301 /* BAR0-BAR4 are PCI I/O space aliases into BAR5 */
302 mr
= g_new(MemoryRegion
, 1);
303 memory_region_init_alias(mr
, OBJECT(d
), "sii3112.bar0", &d
->mmio
, 0x80, 8);
304 pci_register_bar(dev
, 0, PCI_BASE_ADDRESS_SPACE_IO
, mr
);
305 mr
= g_new(MemoryRegion
, 1);
306 memory_region_init_alias(mr
, OBJECT(d
), "sii3112.bar1", &d
->mmio
, 0x88, 4);
307 pci_register_bar(dev
, 1, PCI_BASE_ADDRESS_SPACE_IO
, mr
);
308 mr
= g_new(MemoryRegion
, 1);
309 memory_region_init_alias(mr
, OBJECT(d
), "sii3112.bar2", &d
->mmio
, 0xc0, 8);
310 pci_register_bar(dev
, 2, PCI_BASE_ADDRESS_SPACE_IO
, mr
);
311 mr
= g_new(MemoryRegion
, 1);
312 memory_region_init_alias(mr
, OBJECT(d
), "sii3112.bar3", &d
->mmio
, 0xc8, 4);
313 pci_register_bar(dev
, 3, PCI_BASE_ADDRESS_SPACE_IO
, mr
);
314 mr
= g_new(MemoryRegion
, 1);
315 memory_region_init_alias(mr
, OBJECT(d
), "sii3112.bar4", &d
->mmio
, 0, 16);
316 pci_register_bar(dev
, 4, PCI_BASE_ADDRESS_SPACE_IO
, mr
);
318 irq
= qemu_allocate_irqs(sii3112_set_irq
, d
, 2);
319 for (i
= 0; i
< 2; i
++) {
320 ide_bus_new(&s
->bus
[i
], sizeof(s
->bus
[i
]), DEVICE(dev
), i
, 1);
321 ide_init2(&s
->bus
[i
], irq
[i
]);
323 bmdma_init(&s
->bus
[i
], &s
->bmdma
[i
], s
);
324 s
->bmdma
[i
].bus
= &s
->bus
[i
];
325 ide_register_restart_cb(&s
->bus
[i
]);
327 qemu_register_reset(sii3112_reset
, s
);
330 static void sii3112_pci_exitfn(PCIDevice
*dev
)
332 PCIIDEState
*d
= PCI_IDE(dev
);
335 for (i
= 0; i
< 2; ++i
) {
336 memory_region_del_subregion(&d
->bmdma_bar
, &d
->bmdma
[i
].extra_io
);
337 memory_region_del_subregion(&d
->bmdma_bar
, &d
->bmdma
[i
].addr_ioport
);
341 static void sii3112_pci_class_init(ObjectClass
*klass
, void *data
)
343 DeviceClass
*dc
= DEVICE_CLASS(klass
);
344 PCIDeviceClass
*pd
= PCI_DEVICE_CLASS(klass
);
346 pd
->vendor_id
= 0x1095;
347 pd
->device_id
= 0x3112;
348 pd
->class_id
= PCI_CLASS_STORAGE_RAID
;
350 pd
->realize
= sii3112_pci_realize
;
351 pd
->exit
= sii3112_pci_exitfn
;
352 dc
->desc
= "SiI3112A SATA controller";
353 set_bit(DEVICE_CATEGORY_STORAGE
, dc
->categories
);
356 static const TypeInfo sii3112_pci_info
= {
357 .name
= TYPE_SII3112_PCI
,
358 .parent
= TYPE_PCI_IDE
,
359 .instance_size
= sizeof(SiI3112PCIState
),
360 .class_init
= sii3112_pci_class_init
,
363 static void sii3112_register_types(void)
365 type_register_static(&sii3112_pci_info
);
368 type_init(sii3112_register_types
)