|
|
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:
1.1.1.3 root 171: if (i == 0) {
172: register_ioport_write(addr, 4, 1, bmdma_writeb_0, d);
173: register_ioport_read(addr, 4, 1, bmdma_readb_0, d);
174: } else {
175: register_ioport_write(addr, 4, 1, bmdma_writeb_1, d);
176: register_ioport_read(addr, 4, 1, bmdma_readb_1, d);
177: }
1.1 root 178:
1.1.1.4 ! root 179: iorange_init(&bm->addr_ioport, &bmdma_addr_ioport_ops, addr + 4, 4);
! 180: ioport_register(&bm->addr_ioport);
1.1 root 181: addr += 8;
182: }
183: }
184:
185: /* XXX: call it also when the MRDMODE is changed from the PCI config
186: registers */
187: static void cmd646_update_irq(PCIIDEState *d)
188: {
189: int pci_level;
190: pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
191: !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
192: ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
193: !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
194: qemu_set_irq(d->dev.irq[0], pci_level);
195: }
196:
197: /* the PCI irq level is the logical OR of the two channels */
198: static void cmd646_set_irq(void *opaque, int channel, int level)
199: {
200: PCIIDEState *d = opaque;
201: int irq_mask;
202:
203: irq_mask = MRDMODE_INTR_CH0 << channel;
204: if (level)
205: d->dev.config[MRDMODE] |= irq_mask;
206: else
207: d->dev.config[MRDMODE] &= ~irq_mask;
208: cmd646_update_irq(d);
209: }
210:
211: static void cmd646_reset(void *opaque)
212: {
213: PCIIDEState *d = opaque;
214: unsigned int i;
215:
216: for (i = 0; i < 2; i++) {
217: ide_bus_reset(&d->bus[i]);
218: }
219: }
220:
221: /* CMD646 PCI IDE controller */
222: static int pci_cmd646_ide_initfn(PCIDevice *dev)
223: {
224: PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);
225: uint8_t *pci_conf = d->dev.config;
226: qemu_irq *irq;
1.1.1.4 ! root 227: int i;
1.1 root 228:
229: pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_CMD);
230: pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_CMD_646);
231:
1.1.1.3 root 232: pci_conf[PCI_REVISION_ID] = 0x07; // IDE controller revision
233: pci_conf[PCI_CLASS_PROG] = 0x8f;
1.1 root 234:
235: pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE);
236:
237: pci_conf[0x51] = 0x04; // enable IDE0
238: if (d->secondary) {
239: /* XXX: if not enabled, really disable the seconday IDE controller */
240: pci_conf[0x51] |= 0x08; /* enable IDE1 */
241: }
242:
243: pci_register_bar(dev, 0, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
244: pci_register_bar(dev, 1, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
245: pci_register_bar(dev, 2, 0x8, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
246: pci_register_bar(dev, 3, 0x4, PCI_BASE_ADDRESS_SPACE_IO, ide_map);
247: pci_register_bar(dev, 4, 0x10, PCI_BASE_ADDRESS_SPACE_IO, bmdma_map);
248:
1.1.1.3 root 249: /* TODO: RST# value should be 0 */
250: pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
1.1 root 251:
252: irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
1.1.1.4 ! root 253: for (i = 0; i < 2; i++) {
! 254: ide_bus_new(&d->bus[i], &d->dev.qdev, i);
! 255: ide_init2(&d->bus[i], irq[i]);
! 256:
! 257: bmdma_init(&d->bus[i], &d->bmdma[i]);
! 258: d->bmdma[i].bus = &d->bus[i];
! 259: qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
! 260: &d->bmdma[i].dma);
! 261: }
1.1 root 262:
1.1.1.3 root 263: vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
1.1 root 264: qemu_register_reset(cmd646_reset, d);
265: return 0;
266: }
267:
268: void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
269: int secondary_ide_enabled)
270: {
271: PCIDevice *dev;
272:
273: dev = pci_create(bus, -1, "cmd646-ide");
274: qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
275: qdev_init_nofail(&dev->qdev);
276:
277: pci_ide_create_devs(dev, hd_table);
278: }
279:
280: static PCIDeviceInfo cmd646_ide_info[] = {
281: {
282: .qdev.name = "cmd646-ide",
283: .qdev.size = sizeof(PCIIDEState),
284: .init = pci_cmd646_ide_initfn,
285: .qdev.props = (Property[]) {
286: DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
287: DEFINE_PROP_END_OF_LIST(),
288: },
289: },{
290: /* end of list */
291: }
292: };
293:
294: static void cmd646_ide_register(void)
295: {
296: pci_qdev_register_many(cmd646_ide_info);
297: }
298: device_init(cmd646_ide_register);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.