xref: /openbmc/qemu/hw/ide/cmd646.c (revision 89de4b91)
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 "qemu/osdep.h"
26 #include "hw/hw.h"
27 #include "hw/i386/pc.h"
28 #include "hw/pci/pci.h"
29 #include "hw/isa/isa.h"
30 #include "sysemu/block-backend.h"
31 #include "sysemu/sysemu.h"
32 #include "sysemu/dma.h"
33 
34 #include "hw/ide/pci.h"
35 #include "trace.h"
36 
37 /* CMD646 specific */
38 #define CFR		0x50
39 #define   CFR_INTR_CH0	0x04
40 #define CNTRL		0x51
41 #define   CNTRL_EN_CH0	0x04
42 #define   CNTRL_EN_CH1	0x08
43 #define ARTTIM23	0x57
44 #define    ARTTIM23_INTR_CH1	0x10
45 #define MRDMODE		0x71
46 #define   MRDMODE_INTR_CH0	0x04
47 #define   MRDMODE_INTR_CH1	0x08
48 #define   MRDMODE_BLK_CH0	0x10
49 #define   MRDMODE_BLK_CH1	0x20
50 #define UDIDETCR0	0x73
51 #define UDIDETCR1	0x7B
52 
53 static void cmd646_update_irq(PCIDevice *pd);
54 
55 static uint64_t cmd646_cmd_read(void *opaque, hwaddr addr,
56                                 unsigned size)
57 {
58     CMD646BAR *cmd646bar = opaque;
59 
60     if (addr != 2 || size != 1) {
61         return ((uint64_t)1 << (size * 8)) - 1;
62     }
63     return ide_status_read(cmd646bar->bus, addr + 2);
64 }
65 
66 static void cmd646_cmd_write(void *opaque, hwaddr addr,
67                              uint64_t data, unsigned size)
68 {
69     CMD646BAR *cmd646bar = opaque;
70 
71     if (addr != 2 || size != 1) {
72         return;
73     }
74     ide_cmd_write(cmd646bar->bus, addr + 2, data);
75 }
76 
77 static const MemoryRegionOps cmd646_cmd_ops = {
78     .read = cmd646_cmd_read,
79     .write = cmd646_cmd_write,
80     .endianness = DEVICE_LITTLE_ENDIAN,
81 };
82 
83 static uint64_t cmd646_data_read(void *opaque, hwaddr addr,
84                                  unsigned size)
85 {
86     CMD646BAR *cmd646bar = opaque;
87 
88     if (size == 1) {
89         return ide_ioport_read(cmd646bar->bus, addr);
90     } else if (addr == 0) {
91         if (size == 2) {
92             return ide_data_readw(cmd646bar->bus, addr);
93         } else {
94             return ide_data_readl(cmd646bar->bus, addr);
95         }
96     }
97     return ((uint64_t)1 << (size * 8)) - 1;
98 }
99 
100 static void cmd646_data_write(void *opaque, hwaddr addr,
101                              uint64_t data, unsigned size)
102 {
103     CMD646BAR *cmd646bar = opaque;
104 
105     if (size == 1) {
106         ide_ioport_write(cmd646bar->bus, addr, data);
107     } else if (addr == 0) {
108         if (size == 2) {
109             ide_data_writew(cmd646bar->bus, addr, data);
110         } else {
111             ide_data_writel(cmd646bar->bus, addr, data);
112         }
113     }
114 }
115 
116 static const MemoryRegionOps cmd646_data_ops = {
117     .read = cmd646_data_read,
118     .write = cmd646_data_write,
119     .endianness = DEVICE_LITTLE_ENDIAN,
120 };
121 
122 static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
123 {
124     IDEBus *bus = &d->bus[bus_num];
125     CMD646BAR *bar = &d->cmd646_bar[bus_num];
126 
127     bar->bus = bus;
128     bar->pci_dev = d;
129     memory_region_init_io(&bar->cmd, OBJECT(d), &cmd646_cmd_ops, bar,
130                           "cmd646-cmd", 4);
131     memory_region_init_io(&bar->data, OBJECT(d), &cmd646_data_ops, bar,
132                           "cmd646-data", 8);
133 }
134 
135 static void cmd646_update_dma_interrupts(PCIDevice *pd)
136 {
137     /* Sync DMA interrupt status from UDMA interrupt status */
138     if (pd->config[MRDMODE] & MRDMODE_INTR_CH0) {
139         pd->config[CFR] |= CFR_INTR_CH0;
140     } else {
141         pd->config[CFR] &= ~CFR_INTR_CH0;
142     }
143 
144     if (pd->config[MRDMODE] & MRDMODE_INTR_CH1) {
145         pd->config[ARTTIM23] |= ARTTIM23_INTR_CH1;
146     } else {
147         pd->config[ARTTIM23] &= ~ARTTIM23_INTR_CH1;
148     }
149 }
150 
151 static void cmd646_update_udma_interrupts(PCIDevice *pd)
152 {
153     /* Sync UDMA interrupt status from DMA interrupt status */
154     if (pd->config[CFR] & CFR_INTR_CH0) {
155         pd->config[MRDMODE] |= MRDMODE_INTR_CH0;
156     } else {
157         pd->config[MRDMODE] &= ~MRDMODE_INTR_CH0;
158     }
159 
160     if (pd->config[ARTTIM23] & ARTTIM23_INTR_CH1) {
161         pd->config[MRDMODE] |= MRDMODE_INTR_CH1;
162     } else {
163         pd->config[MRDMODE] &= ~MRDMODE_INTR_CH1;
164     }
165 }
166 
167 static uint64_t bmdma_read(void *opaque, hwaddr addr,
168                            unsigned size)
169 {
170     BMDMAState *bm = opaque;
171     PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev);
172     uint32_t val;
173 
174     if (size != 1) {
175         return ((uint64_t)1 << (size * 8)) - 1;
176     }
177 
178     switch(addr & 3) {
179     case 0:
180         val = bm->cmd;
181         break;
182     case 1:
183         val = pci_dev->config[MRDMODE];
184         break;
185     case 2:
186         val = bm->status;
187         break;
188     case 3:
189         if (bm == &bm->pci_dev->bmdma[0]) {
190             val = pci_dev->config[UDIDETCR0];
191         } else {
192             val = pci_dev->config[UDIDETCR1];
193         }
194         break;
195     default:
196         val = 0xff;
197         break;
198     }
199 
200     trace_bmdma_read_cmd646(addr, val);
201     return val;
202 }
203 
204 static void bmdma_write(void *opaque, hwaddr addr,
205                         uint64_t val, unsigned size)
206 {
207     BMDMAState *bm = opaque;
208     PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev);
209 
210     if (size != 1) {
211         return;
212     }
213 
214     trace_bmdma_write_cmd646(addr, val);
215     switch(addr & 3) {
216     case 0:
217         bmdma_cmd_writeb(bm, val);
218         break;
219     case 1:
220         pci_dev->config[MRDMODE] =
221             (pci_dev->config[MRDMODE] & ~0x30) | (val & 0x30);
222         cmd646_update_dma_interrupts(pci_dev);
223         cmd646_update_irq(pci_dev);
224         break;
225     case 2:
226         bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
227         break;
228     case 3:
229         if (bm == &bm->pci_dev->bmdma[0]) {
230             pci_dev->config[UDIDETCR0] = val;
231         } else {
232             pci_dev->config[UDIDETCR1] = val;
233         }
234         break;
235     }
236 }
237 
238 static const MemoryRegionOps cmd646_bmdma_ops = {
239     .read = bmdma_read,
240     .write = bmdma_write,
241 };
242 
243 static void bmdma_setup_bar(PCIIDEState *d)
244 {
245     BMDMAState *bm;
246     int i;
247 
248     memory_region_init(&d->bmdma_bar, OBJECT(d), "cmd646-bmdma", 16);
249     for(i = 0;i < 2; i++) {
250         bm = &d->bmdma[i];
251         memory_region_init_io(&bm->extra_io, OBJECT(d), &cmd646_bmdma_ops, bm,
252                               "cmd646-bmdma-bus", 4);
253         memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
254         memory_region_init_io(&bm->addr_ioport, OBJECT(d),
255                               &bmdma_addr_ioport_ops, bm,
256                               "cmd646-bmdma-ioport", 4);
257         memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
258     }
259 }
260 
261 static void cmd646_update_irq(PCIDevice *pd)
262 {
263     int pci_level;
264 
265     pci_level = ((pd->config[MRDMODE] & MRDMODE_INTR_CH0) &&
266                  !(pd->config[MRDMODE] & MRDMODE_BLK_CH0)) ||
267         ((pd->config[MRDMODE] & MRDMODE_INTR_CH1) &&
268          !(pd->config[MRDMODE] & MRDMODE_BLK_CH1));
269     pci_set_irq(pd, pci_level);
270 }
271 
272 /* the PCI irq level is the logical OR of the two channels */
273 static void cmd646_set_irq(void *opaque, int channel, int level)
274 {
275     PCIIDEState *d = opaque;
276     PCIDevice *pd = PCI_DEVICE(d);
277     int irq_mask;
278 
279     irq_mask = MRDMODE_INTR_CH0 << channel;
280     if (level) {
281         pd->config[MRDMODE] |= irq_mask;
282     } else {
283         pd->config[MRDMODE] &= ~irq_mask;
284     }
285     cmd646_update_dma_interrupts(pd);
286     cmd646_update_irq(pd);
287 }
288 
289 static void cmd646_reset(void *opaque)
290 {
291     PCIIDEState *d = opaque;
292     unsigned int i;
293 
294     for (i = 0; i < 2; i++) {
295         ide_bus_reset(&d->bus[i]);
296     }
297 }
298 
299 static uint32_t cmd646_pci_config_read(PCIDevice *d,
300                                        uint32_t address, int len)
301 {
302     return pci_default_read_config(d, address, len);
303 }
304 
305 static void cmd646_pci_config_write(PCIDevice *d, uint32_t addr, uint32_t val,
306                                     int l)
307 {
308     uint32_t i;
309 
310     pci_default_write_config(d, addr, val, l);
311 
312     for (i = addr; i < addr + l; i++) {
313         switch (i) {
314         case CFR:
315         case ARTTIM23:
316             cmd646_update_udma_interrupts(d);
317             break;
318         case MRDMODE:
319             cmd646_update_dma_interrupts(d);
320             break;
321         }
322     }
323 
324     cmd646_update_irq(d);
325 }
326 
327 /* CMD646 PCI IDE controller */
328 static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp)
329 {
330     PCIIDEState *d = PCI_IDE(dev);
331     uint8_t *pci_conf = dev->config;
332     qemu_irq *irq;
333     int i;
334 
335     pci_conf[PCI_CLASS_PROG] = 0x8f;
336 
337     pci_conf[CNTRL] = CNTRL_EN_CH0; // enable IDE0
338     if (d->secondary) {
339         /* XXX: if not enabled, really disable the seconday IDE controller */
340         pci_conf[CNTRL] |= CNTRL_EN_CH1; /* enable IDE1 */
341     }
342 
343     /* Set write-to-clear interrupt bits */
344     dev->wmask[CFR] = 0x0;
345     dev->w1cmask[CFR] = CFR_INTR_CH0;
346     dev->wmask[ARTTIM23] = 0x0;
347     dev->w1cmask[ARTTIM23] = ARTTIM23_INTR_CH1;
348     dev->wmask[MRDMODE] = 0x0;
349     dev->w1cmask[MRDMODE] = MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1;
350 
351     setup_cmd646_bar(d, 0);
352     setup_cmd646_bar(d, 1);
353     pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].data);
354     pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].cmd);
355     pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].data);
356     pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].cmd);
357     bmdma_setup_bar(d);
358     pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
359 
360     /* TODO: RST# value should be 0 */
361     pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
362 
363     irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
364     for (i = 0; i < 2; i++) {
365         ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(dev), i, 2);
366         ide_init2(&d->bus[i], irq[i]);
367 
368         bmdma_init(&d->bus[i], &d->bmdma[i], d);
369         d->bmdma[i].bus = &d->bus[i];
370         ide_register_restart_cb(&d->bus[i]);
371     }
372 
373     vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
374     qemu_register_reset(cmd646_reset, d);
375 }
376 
377 static void pci_cmd646_ide_exitfn(PCIDevice *dev)
378 {
379     PCIIDEState *d = PCI_IDE(dev);
380     unsigned i;
381 
382     for (i = 0; i < 2; ++i) {
383         memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
384         memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
385     }
386 }
387 
388 void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
389                          int secondary_ide_enabled)
390 {
391     PCIDevice *dev;
392 
393     dev = pci_create(bus, -1, "cmd646-ide");
394     qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
395     qdev_init_nofail(&dev->qdev);
396 
397     pci_ide_create_devs(dev, hd_table);
398 }
399 
400 static Property cmd646_ide_properties[] = {
401     DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
402     DEFINE_PROP_END_OF_LIST(),
403 };
404 
405 static void cmd646_ide_class_init(ObjectClass *klass, void *data)
406 {
407     DeviceClass *dc = DEVICE_CLASS(klass);
408     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
409 
410     k->realize = pci_cmd646_ide_realize;
411     k->exit = pci_cmd646_ide_exitfn;
412     k->vendor_id = PCI_VENDOR_ID_CMD;
413     k->device_id = PCI_DEVICE_ID_CMD_646;
414     k->revision = 0x07;
415     k->class_id = PCI_CLASS_STORAGE_IDE;
416     k->config_read = cmd646_pci_config_read;
417     k->config_write = cmd646_pci_config_write;
418     dc->props = cmd646_ide_properties;
419     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
420 }
421 
422 static const TypeInfo cmd646_ide_info = {
423     .name          = "cmd646-ide",
424     .parent        = TYPE_PCI_IDE,
425     .class_init    = cmd646_ide_class_init,
426 };
427 
428 static void cmd646_ide_register_types(void)
429 {
430     type_register_static(&cmd646_ide_info);
431 }
432 
433 type_init(cmd646_ide_register_types)
434