|
|
1.1 root 1: /*
2: * QEMU IDE Emulation: PCI cmd646 support.
3: *
4: * Copyright (c) 2003 Fabrice Bellard
5: * Copyright (c) 2006 Openedhand Ltd.
6: *
7: * Permission is hereby granted, free of charge, to any person obtaining a copy
8: * of this software and associated documentation files (the "Software"), to deal
9: * in the Software without restriction, including without limitation the rights
10: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11: * copies of the Software, and to permit persons to whom the Software is
12: * furnished to do so, subject to the following conditions:
13: *
14: * The above copyright notice and this permission notice shall be included in
15: * all copies or substantial portions of the Software.
16: *
17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23: * THE SOFTWARE.
24: */
25: #include <hw/hw.h>
26: #include <hw/pc.h>
27: #include <hw/pci.h>
28: #include <hw/isa.h>
29: #include "block.h"
30: #include "block_int.h"
31: #include "sysemu.h"
32: #include "dma.h"
33:
34: #include <hw/ide/pci.h>
35:
36: /* CMD646 specific */
37: #define MRDMODE 0x71
38: #define MRDMODE_INTR_CH0 0x04
39: #define MRDMODE_INTR_CH1 0x08
40: #define MRDMODE_BLK_CH0 0x10
41: #define MRDMODE_BLK_CH1 0x20
42: #define UDIDETCR0 0x73
43: #define UDIDETCR1 0x7B
44:
45: static void cmd646_update_irq(PCIIDEState *d);
46:
47: static void ide_map(PCIDevice *pci_dev, int region_num,
48: pcibus_t addr, pcibus_t size, int type)
49: {
50: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
51: IDEBus *bus;
52:
53: if (region_num <= 3) {
54: bus = &d->bus[(region_num >> 1)];
55: if (region_num & 1) {
56: register_ioport_read(addr + 2, 1, 1, ide_status_read, bus);
57: register_ioport_write(addr + 2, 1, 1, ide_cmd_write, bus);
58: } else {
59: register_ioport_write(addr, 8, 1, ide_ioport_write, bus);
60: register_ioport_read(addr, 8, 1, ide_ioport_read, bus);
61:
62: /* data ports */
63: register_ioport_write(addr, 2, 2, ide_data_writew, bus);
64: register_ioport_read(addr, 2, 2, ide_data_readw, bus);
65: register_ioport_write(addr, 4, 4, ide_data_writel, bus);
66: register_ioport_read(addr, 4, 4, ide_data_readl, bus);
67: }
68: }
69: }
70:
1.1.1.3 ! root 71: static uint32_t bmdma_readb_common(PCIIDEState *pci_dev, BMDMAState *bm,
! 72: uint32_t addr)
1.1 root 73: {
74: uint32_t val;
75:
76: switch(addr & 3) {
77: case 0:
78: val = bm->cmd;
79: break;
80: case 1:
81: val = pci_dev->dev.config[MRDMODE];
82: break;
83: case 2:
84: val = bm->status;
85: break;
86: case 3:
1.1.1.3 ! root 87: if (bm == &pci_dev->bmdma[0]) {
1.1 root 88: val = pci_dev->dev.config[UDIDETCR0];
89: } else {
90: val = pci_dev->dev.config[UDIDETCR1];
91: }
92: break;
93: default:
94: val = 0xff;
95: break;
96: }
97: #ifdef DEBUG_IDE
98: printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
99: #endif
100: return val;
101: }
102:
1.1.1.3 ! root 103: static uint32_t bmdma_readb_0(void *opaque, uint32_t addr)
! 104: {
! 105: PCIIDEState *pci_dev = opaque;
! 106: BMDMAState *bm = &pci_dev->bmdma[0];
! 107:
! 108: return bmdma_readb_common(pci_dev, bm, addr);
! 109: }
! 110:
! 111: static uint32_t bmdma_readb_1(void *opaque, uint32_t addr)
! 112: {
! 113: PCIIDEState *pci_dev = opaque;
! 114: BMDMAState *bm = &pci_dev->bmdma[1];
! 115:
! 116: return bmdma_readb_common(pci_dev, bm, addr);
! 117: }
! 118:
! 119: static void bmdma_writeb_common(PCIIDEState *pci_dev, BMDMAState *bm,
! 120: uint32_t addr, uint32_t val)
1.1 root 121: {
122: #ifdef DEBUG_IDE
123: printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
124: #endif
125: switch(addr & 3) {
1.1.1.3 ! root 126: case 0:
! 127: bmdma_cmd_writeb(bm, addr, val);
! 128: break;
1.1 root 129: case 1:
130: pci_dev->dev.config[MRDMODE] =
131: (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
132: cmd646_update_irq(pci_dev);
133: break;
134: case 2:
135: bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
136: break;
137: case 3:
1.1.1.3 ! root 138: if (bm == &pci_dev->bmdma[0])
1.1 root 139: pci_dev->dev.config[UDIDETCR0] = val;
140: else
141: pci_dev->dev.config[UDIDETCR1] = val;
142: break;
143: }
144: }
145:
1.1.1.3 ! root 146: static void bmdma_writeb_0(void *opaque, uint32_t addr, uint32_t val)
! 147: {
! 148: PCIIDEState *pci_dev = opaque;
! 149: BMDMAState *bm = &pci_dev->bmdma[0];
! 150:
! 151: bmdma_writeb_common(pci_dev, bm, addr, val);
! 152: }
! 153:
! 154: static void bmdma_writeb_1(void *opaque, uint32_t addr, uint32_t val)
! 155: {
! 156: PCIIDEState *pci_dev = opaque;
! 157: BMDMAState *bm = &pci_dev->bmdma[1];
! 158:
! 159: bmdma_writeb_common(pci_dev, bm, addr, val);
! 160: }
! 161:
1.1 root 162: static void bmdma_map(PCIDevice *pci_dev, int region_num,
163: pcibus_t addr, pcibus_t size, int type)
164: {
165: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev);
166: int i;
167:
168: for(i = 0;i < 2; i++) {
169: BMDMAState *bm = &d->bmdma[i];
170: d->bus[i].bmdma = bm;
171: bm->bus = d->bus+i;
172: qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm);
173:
1.1.1.3 ! root 174: if (i == 0) {
! 175: register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
! 176: register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
! 177: } else {
! 178: register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
! 179: register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
! 180: }
1.1 root 181:
182: register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm);
183: register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm);
184: register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm);
185: register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm);
186: register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
187: register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
188: addr += 8;
189: }
190: }
191:
192: /* XXX: call it also when the MRDMODE is changed from the PCI config
193: registers */
194: static void cmd646_update_irq(PCIIDEState *d)
195: {
196: int pci_level;
197: pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
198: !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
199: ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
200: !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
201: qemu_set_irq(d->dev.irq[0], pci_level);
202: }
203:
204: /* the PCI irq level is the logical OR of the two channels */
205: static void cmd646_set_irq(void *opaque, int channel, int level)
206: {
207: PCIIDEState *d = opaque;
208: int irq_mask;
209:
210: irq_mask = MRDMODE_INTR_CH0 << channel;
211: if (level)
212: d->dev.config[MRDMODE] |= irq_mask;
213: else
214: d->dev.config[MRDMODE] &= ~irq_mask;
215: cmd646_update_irq(d);
216: }
217:
218: static void cmd646_reset(void *opaque)
219: {
220: PCIIDEState *d = opaque;
221: unsigned int i;
222:
223: for (i = 0; i < 2; i++) {
224: ide_bus_reset(&d->bus[i]);
225: ide_dma_reset(&d->bmdma[i]);
226: }
227: }
228:
229: /* CMD646 PCI IDE controller */
230: static int pci_cmd646_ide_initfn(PCIDevice *dev)
231: {
232: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
233: uint8_t *pci_conf = d->dev.config;
234: qemu_irq *irq;
235:
236: pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
237: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
238:
1.1.1.3 ! root 239: pci_conf[PCI_REVISION_ID] = 0x07; // IDE controller revision
! 240: pci_conf[PCI_CLASS_PROG] = 0x8f;
1.1 root 241:
242: pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
243:
244: pci_conf[0x51] = 0x04; // enable IDE0
245: if (d->secondary) {
246: /* XXX: if not enabled, really disable the seconday IDE controller */
247: pci_conf[0x51] |= 0x08; /* enable IDE1 */
248: }
249:
250: pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
251: pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
252: pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
253: pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
254: pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
255:
1.1.1.3 ! root 256: /* TODO: RST# value should be 0 */
! 257: pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
1.1 root 258:
259: irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
260: ide_bus_new(&d->bus[0], &d->dev.qdev);
261: ide_bus_new(&d->bus[1], &d->dev.qdev);
1.1.1.3 ! root 262: ide_init2(&d->bus[0], irq[0]);
! 263: ide_init2(&d->bus[1], irq[1]);
1.1 root 264:
1.1.1.3 ! root 265: vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
1.1 root 266: qemu_register_reset(cmd646_reset, d);
267: return 0;
268: }
269:
270: void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
271: int secondary_ide_enabled)
272: {
273: PCIDevice *dev;
274:
275: dev = pci_create(bus, -1, "cmd646-ide");
276: qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
277: qdev_init_nofail(&dev->qdev);
278:
279: pci_ide_create_devs(dev, hd_table);
280: }
281:
282: static PCIDeviceInfo cmd646_ide_info[] = {
283: {
284: .qdev.name = "cmd646-ide",
285: .qdev.size = sizeof(PCIIDEState),
286: .init = pci_cmd646_ide_initfn,
287: .qdev.props = (Property[]) {
288: DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
289: DEFINE_PROP_END_OF_LIST(),
290: },
291: },{
292: /* end of list */
293: }
294: };
295:
296: static void cmd646_ide_register(void)
297: {
298: pci_qdev_register_many(cmd646_ide_info);
299: }
300: device_init(cmd646_ide_register);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.