qemu/hw/ide/via.c
<<
>>
Prefs
   1/*
   2 * QEMU IDE Emulation: PCI VIA82C686B support.
   3 *
   4 * Copyright (c) 2003 Fabrice Bellard
   5 * Copyright (c) 2006 Openedhand Ltd.
   6 * Copyright (c) 2010 Huacai Chen <zltjiangshi@gmail.com>
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 * copies of the Software, and to permit persons to whom the Software is
  13 * furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 * THE SOFTWARE.
  25 */
  26
  27#include "qemu/osdep.h"
  28#include "hw/hw.h"
  29#include "hw/pci/pci.h"
  30#include "qemu/module.h"
  31#include "sysemu/sysemu.h"
  32#include "sysemu/dma.h"
  33
  34#include "hw/ide/pci.h"
  35#include "trace.h"
  36
  37static uint64_t bmdma_read(void *opaque, hwaddr addr,
  38                           unsigned size)
  39{
  40    BMDMAState *bm = opaque;
  41    uint32_t val;
  42
  43    if (size != 1) {
  44        return ((uint64_t)1 << (size * 8)) - 1;
  45    }
  46
  47    switch (addr & 3) {
  48    case 0:
  49        val = bm->cmd;
  50        break;
  51    case 2:
  52        val = bm->status;
  53        break;
  54    default:
  55        val = 0xff;
  56        break;
  57    }
  58
  59    trace_bmdma_read_via(addr, val);
  60    return val;
  61}
  62
  63static void bmdma_write(void *opaque, hwaddr addr,
  64                        uint64_t val, unsigned size)
  65{
  66    BMDMAState *bm = opaque;
  67
  68    if (size != 1) {
  69        return;
  70    }
  71
  72    trace_bmdma_write_via(addr, val);
  73    switch (addr & 3) {
  74    case 0:
  75        bmdma_cmd_writeb(bm, val);
  76        break;
  77    case 2:
  78        bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
  79        break;
  80    default:;
  81    }
  82}
  83
  84static const MemoryRegionOps via_bmdma_ops = {
  85    .read = bmdma_read,
  86    .write = bmdma_write,
  87};
  88
  89static void bmdma_setup_bar(PCIIDEState *d)
  90{
  91    int i;
  92
  93    memory_region_init(&d->bmdma_bar, OBJECT(d), "via-bmdma-container", 16);
  94    for(i = 0;i < 2; i++) {
  95        BMDMAState *bm = &d->bmdma[i];
  96
  97        memory_region_init_io(&bm->extra_io, OBJECT(d), &via_bmdma_ops, bm,
  98                              "via-bmdma", 4);
  99        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
 100        memory_region_init_io(&bm->addr_ioport, OBJECT(d),
 101                              &bmdma_addr_ioport_ops, bm, "bmdma", 4);
 102        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
 103    }
 104}
 105
 106static void via_ide_set_irq(void *opaque, int n, int level)
 107{
 108    PCIDevice *d = PCI_DEVICE(opaque);
 109
 110    if (level) {
 111        d->config[0x70 + n * 8] |= 0x80;
 112    } else {
 113        d->config[0x70 + n * 8] &= ~0x80;
 114    }
 115
 116    level = (d->config[0x70] & 0x80) || (d->config[0x78] & 0x80);
 117    n = pci_get_byte(d->config + PCI_INTERRUPT_LINE);
 118    if (n) {
 119        qemu_set_irq(isa_get_irq(NULL, n), level);
 120    }
 121}
 122
 123static void via_ide_reset(void *opaque)
 124{
 125    PCIIDEState *d = opaque;
 126    PCIDevice *pd = PCI_DEVICE(d);
 127    uint8_t *pci_conf = pd->config;
 128    int i;
 129
 130    for (i = 0; i < 2; i++) {
 131        ide_bus_reset(&d->bus[i]);
 132    }
 133
 134    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_WAIT);
 135    pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK |
 136                 PCI_STATUS_DEVSEL_MEDIUM);
 137
 138    pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, 0x000001f0);
 139    pci_set_long(pci_conf + PCI_BASE_ADDRESS_1, 0x000003f4);
 140    pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x00000170);
 141    pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x00000374);
 142    pci_set_long(pci_conf + PCI_BASE_ADDRESS_4, 0x0000cc01); /* BMIBA: 20-23h */
 143    pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000010e);
 144
 145    /* IDE chip enable, IDE configuration 1/2, IDE FIFO Configuration*/
 146    pci_set_long(pci_conf + 0x40, 0x0a090600);
 147    /* IDE misc configuration 1/2/3 */
 148    pci_set_long(pci_conf + 0x44, 0x00c00068);
 149    /* IDE Timing control */
 150    pci_set_long(pci_conf + 0x48, 0xa8a8a8a8);
 151    /* IDE Address Setup Time */
 152    pci_set_long(pci_conf + 0x4c, 0x000000ff);
 153    /* UltraDMA Extended Timing Control*/
 154    pci_set_long(pci_conf + 0x50, 0x07070707);
 155    /* UltraDMA FIFO Control */
 156    pci_set_long(pci_conf + 0x54, 0x00000004);
 157    /* IDE primary sector size */
 158    pci_set_long(pci_conf + 0x60, 0x00000200);
 159    /* IDE secondary sector size */
 160    pci_set_long(pci_conf + 0x68, 0x00000200);
 161    /* PCI PM Block */
 162    pci_set_long(pci_conf + 0xc0, 0x00020001);
 163}
 164
 165static void via_ide_realize(PCIDevice *dev, Error **errp)
 166{
 167    PCIIDEState *d = PCI_IDE(dev);
 168    uint8_t *pci_conf = dev->config;
 169    int i;
 170
 171    pci_config_set_prog_interface(pci_conf, 0x8f); /* native PCI ATA mode */
 172    pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
 173    dev->wmask[PCI_INTERRUPT_LINE] = 0xf;
 174
 175    qemu_register_reset(via_ide_reset, d);
 176
 177    memory_region_init_io(&d->data_bar[0], OBJECT(d), &pci_ide_data_le_ops,
 178                          &d->bus[0], "via-ide0-data", 8);
 179    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->data_bar[0]);
 180
 181    memory_region_init_io(&d->cmd_bar[0], OBJECT(d), &pci_ide_cmd_le_ops,
 182                          &d->bus[0], "via-ide0-cmd", 4);
 183    pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd_bar[0]);
 184
 185    memory_region_init_io(&d->data_bar[1], OBJECT(d), &pci_ide_data_le_ops,
 186                          &d->bus[1], "via-ide1-data", 8);
 187    pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->data_bar[1]);
 188
 189    memory_region_init_io(&d->cmd_bar[1], OBJECT(d), &pci_ide_cmd_le_ops,
 190                          &d->bus[1], "via-ide1-cmd", 4);
 191    pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd_bar[1]);
 192
 193    bmdma_setup_bar(d);
 194    pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
 195
 196    vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
 197
 198    for (i = 0; i < 2; i++) {
 199        ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2);
 200        ide_init2(&d->bus[i], qemu_allocate_irq(via_ide_set_irq, d, i));
 201
 202        bmdma_init(&d->bus[i], &d->bmdma[i], d);
 203        d->bmdma[i].bus = &d->bus[i];
 204        ide_register_restart_cb(&d->bus[i]);
 205    }
 206}
 207
 208static void via_ide_exitfn(PCIDevice *dev)
 209{
 210    PCIIDEState *d = PCI_IDE(dev);
 211    unsigned i;
 212
 213    for (i = 0; i < 2; ++i) {
 214        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
 215        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
 216    }
 217}
 218
 219void via_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
 220{
 221    PCIDevice *dev;
 222
 223    dev = pci_create_simple(bus, devfn, "via-ide");
 224    pci_ide_create_devs(dev, hd_table);
 225}
 226
 227static void via_ide_class_init(ObjectClass *klass, void *data)
 228{
 229    DeviceClass *dc = DEVICE_CLASS(klass);
 230    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 231
 232    k->realize = via_ide_realize;
 233    k->exit = via_ide_exitfn;
 234    k->vendor_id = PCI_VENDOR_ID_VIA;
 235    k->device_id = PCI_DEVICE_ID_VIA_IDE;
 236    k->revision = 0x06;
 237    k->class_id = PCI_CLASS_STORAGE_IDE;
 238    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
 239}
 240
 241static const TypeInfo via_ide_info = {
 242    .name          = "via-ide",
 243    .parent        = TYPE_PCI_IDE,
 244    .class_init    = via_ide_class_init,
 245};
 246
 247static void via_ide_register_types(void)
 248{
 249    type_register_static(&via_ide_info);
 250}
 251
 252type_init(via_ide_register_types)
 253