1*016512f3SHuacai Chen /* 2*016512f3SHuacai Chen * QEMU IDE Emulation: PCI VIA82C686B support. 3*016512f3SHuacai Chen * 4*016512f3SHuacai Chen * Copyright (c) 2003 Fabrice Bellard 5*016512f3SHuacai Chen * Copyright (c) 2006 Openedhand Ltd. 6*016512f3SHuacai Chen * Copyright (c) 2010 Huacai Chen <zltjiangshi@gmail.com> 7*016512f3SHuacai Chen * 8*016512f3SHuacai Chen * Permission is hereby granted, free of charge, to any person obtaining a copy 9*016512f3SHuacai Chen * of this software and associated documentation files (the "Software"), to deal 10*016512f3SHuacai Chen * in the Software without restriction, including without limitation the rights 11*016512f3SHuacai Chen * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12*016512f3SHuacai Chen * copies of the Software, and to permit persons to whom the Software is 13*016512f3SHuacai Chen * furnished to do so, subject to the following conditions: 14*016512f3SHuacai Chen * 15*016512f3SHuacai Chen * The above copyright notice and this permission notice shall be included in 16*016512f3SHuacai Chen * all copies or substantial portions of the Software. 17*016512f3SHuacai Chen * 18*016512f3SHuacai Chen * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19*016512f3SHuacai Chen * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20*016512f3SHuacai Chen * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21*016512f3SHuacai Chen * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22*016512f3SHuacai Chen * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23*016512f3SHuacai Chen * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24*016512f3SHuacai Chen * THE SOFTWARE. 25*016512f3SHuacai Chen */ 26*016512f3SHuacai Chen #include <hw/hw.h> 27*016512f3SHuacai Chen #include <hw/pc.h> 28*016512f3SHuacai Chen #include <hw/pci.h> 29*016512f3SHuacai Chen #include <hw/isa.h> 30*016512f3SHuacai Chen #include "block.h" 31*016512f3SHuacai Chen #include "block_int.h" 32*016512f3SHuacai Chen #include "sysemu.h" 33*016512f3SHuacai Chen #include "dma.h" 34*016512f3SHuacai Chen 35*016512f3SHuacai Chen #include <hw/ide/pci.h> 36*016512f3SHuacai Chen 37*016512f3SHuacai Chen static uint32_t bmdma_readb(void *opaque, uint32_t addr) 38*016512f3SHuacai Chen { 39*016512f3SHuacai Chen BMDMAState *bm = opaque; 40*016512f3SHuacai Chen uint32_t val; 41*016512f3SHuacai Chen 42*016512f3SHuacai Chen switch (addr & 3) { 43*016512f3SHuacai Chen case 0: 44*016512f3SHuacai Chen val = bm->cmd; 45*016512f3SHuacai Chen break; 46*016512f3SHuacai Chen case 2: 47*016512f3SHuacai Chen val = bm->status; 48*016512f3SHuacai Chen break; 49*016512f3SHuacai Chen default: 50*016512f3SHuacai Chen val = 0xff; 51*016512f3SHuacai Chen break; 52*016512f3SHuacai Chen } 53*016512f3SHuacai Chen #ifdef DEBUG_IDE 54*016512f3SHuacai Chen printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val); 55*016512f3SHuacai Chen #endif 56*016512f3SHuacai Chen return val; 57*016512f3SHuacai Chen } 58*016512f3SHuacai Chen 59*016512f3SHuacai Chen static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val) 60*016512f3SHuacai Chen { 61*016512f3SHuacai Chen BMDMAState *bm = opaque; 62*016512f3SHuacai Chen #ifdef DEBUG_IDE 63*016512f3SHuacai Chen printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val); 64*016512f3SHuacai Chen #endif 65*016512f3SHuacai Chen switch (addr & 3) { 66*016512f3SHuacai Chen case 2: 67*016512f3SHuacai Chen bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); 68*016512f3SHuacai Chen break; 69*016512f3SHuacai Chen default:; 70*016512f3SHuacai Chen } 71*016512f3SHuacai Chen } 72*016512f3SHuacai Chen 73*016512f3SHuacai Chen static void bmdma_map(PCIDevice *pci_dev, int region_num, 74*016512f3SHuacai Chen pcibus_t addr, pcibus_t size, int type) 75*016512f3SHuacai Chen { 76*016512f3SHuacai Chen PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, pci_dev); 77*016512f3SHuacai Chen int i; 78*016512f3SHuacai Chen 79*016512f3SHuacai Chen for(i = 0;i < 2; i++) { 80*016512f3SHuacai Chen BMDMAState *bm = &d->bmdma[i]; 81*016512f3SHuacai Chen d->bus[i].bmdma = bm; 82*016512f3SHuacai Chen bm->bus = d->bus+i; 83*016512f3SHuacai Chen qemu_add_vm_change_state_handler(ide_dma_restart_cb, bm); 84*016512f3SHuacai Chen 85*016512f3SHuacai Chen register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm); 86*016512f3SHuacai Chen 87*016512f3SHuacai Chen register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm); 88*016512f3SHuacai Chen register_ioport_read(addr, 4, 1, bmdma_readb, bm); 89*016512f3SHuacai Chen 90*016512f3SHuacai Chen register_ioport_write(addr + 4, 4, 1, bmdma_addr_writeb, bm); 91*016512f3SHuacai Chen register_ioport_read(addr + 4, 4, 1, bmdma_addr_readb, bm); 92*016512f3SHuacai Chen register_ioport_write(addr + 4, 4, 2, bmdma_addr_writew, bm); 93*016512f3SHuacai Chen register_ioport_read(addr + 4, 4, 2, bmdma_addr_readw, bm); 94*016512f3SHuacai Chen register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm); 95*016512f3SHuacai Chen register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm); 96*016512f3SHuacai Chen addr += 8; 97*016512f3SHuacai Chen } 98*016512f3SHuacai Chen } 99*016512f3SHuacai Chen 100*016512f3SHuacai Chen static void via_reset(void *opaque) 101*016512f3SHuacai Chen { 102*016512f3SHuacai Chen PCIIDEState *d = opaque; 103*016512f3SHuacai Chen uint8_t *pci_conf = d->dev.config; 104*016512f3SHuacai Chen int i; 105*016512f3SHuacai Chen 106*016512f3SHuacai Chen for (i = 0; i < 2; i++) { 107*016512f3SHuacai Chen ide_bus_reset(&d->bus[i]); 108*016512f3SHuacai Chen ide_dma_reset(&d->bmdma[i]); 109*016512f3SHuacai Chen } 110*016512f3SHuacai Chen 111*016512f3SHuacai Chen pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_WAIT); 112*016512f3SHuacai Chen pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK | 113*016512f3SHuacai Chen PCI_STATUS_DEVSEL_MEDIUM); 114*016512f3SHuacai Chen 115*016512f3SHuacai Chen pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, 0x000001f0); 116*016512f3SHuacai Chen pci_set_long(pci_conf + PCI_BASE_ADDRESS_1, 0x000003f4); 117*016512f3SHuacai Chen pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x00000170); 118*016512f3SHuacai Chen pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x00000374); 119*016512f3SHuacai Chen pci_set_long(pci_conf + PCI_BASE_ADDRESS_4, 0x0000cc01); /* BMIBA: 20-23h */ 120*016512f3SHuacai Chen pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000010e); 121*016512f3SHuacai Chen 122*016512f3SHuacai Chen /* IDE chip enable, IDE configuration 1/2, IDE FIFO Configuration*/ 123*016512f3SHuacai Chen pci_set_long(pci_conf + 0x40, 0x0a090600); 124*016512f3SHuacai Chen /* IDE misc configuration 1/2/3 */ 125*016512f3SHuacai Chen pci_set_long(pci_conf + 0x44, 0x00c00068); 126*016512f3SHuacai Chen /* IDE Timing control */ 127*016512f3SHuacai Chen pci_set_long(pci_conf + 0x48, 0xa8a8a8a8); 128*016512f3SHuacai Chen /* IDE Address Setup Time */ 129*016512f3SHuacai Chen pci_set_long(pci_conf + 0x4c, 0x000000ff); 130*016512f3SHuacai Chen /* UltraDMA Extended Timing Control*/ 131*016512f3SHuacai Chen pci_set_long(pci_conf + 0x50, 0x07070707); 132*016512f3SHuacai Chen /* UltraDMA FIFO Control */ 133*016512f3SHuacai Chen pci_set_long(pci_conf + 0x54, 0x00000004); 134*016512f3SHuacai Chen /* IDE primary sector size */ 135*016512f3SHuacai Chen pci_set_long(pci_conf + 0x60, 0x00000200); 136*016512f3SHuacai Chen /* IDE secondary sector size */ 137*016512f3SHuacai Chen pci_set_long(pci_conf + 0x68, 0x00000200); 138*016512f3SHuacai Chen /* PCI PM Block */ 139*016512f3SHuacai Chen pci_set_long(pci_conf + 0xc0, 0x00020001); 140*016512f3SHuacai Chen } 141*016512f3SHuacai Chen 142*016512f3SHuacai Chen /* via ide func */ 143*016512f3SHuacai Chen static int vt82c686b_ide_initfn(PCIDevice *dev) 144*016512f3SHuacai Chen { 145*016512f3SHuacai Chen PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev);; 146*016512f3SHuacai Chen uint8_t *pci_conf = d->dev.config; 147*016512f3SHuacai Chen 148*016512f3SHuacai Chen pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_VIA); 149*016512f3SHuacai Chen pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIA_IDE); 150*016512f3SHuacai Chen pci_config_set_class(pci_conf, PCI_CLASS_STORAGE_IDE); 151*016512f3SHuacai Chen pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */ 152*016512f3SHuacai Chen pci_config_set_revision(pci_conf,0x06); /* Revision 0.6 */ 153*016512f3SHuacai Chen pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; /* header_type */ 154*016512f3SHuacai Chen pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0); 155*016512f3SHuacai Chen 156*016512f3SHuacai Chen qemu_register_reset(via_reset, d); 157*016512f3SHuacai Chen pci_register_bar((PCIDevice *)d, 4, 0x10, 158*016512f3SHuacai Chen PCI_BASE_ADDRESS_SPACE_IO, bmdma_map); 159*016512f3SHuacai Chen 160*016512f3SHuacai Chen vmstate_register(0, &vmstate_ide_pci, d); 161*016512f3SHuacai Chen 162*016512f3SHuacai Chen ide_bus_new(&d->bus[0], &d->dev.qdev); 163*016512f3SHuacai Chen ide_bus_new(&d->bus[1], &d->dev.qdev); 164*016512f3SHuacai Chen ide_init2(&d->bus[0], isa_reserve_irq(14)); 165*016512f3SHuacai Chen ide_init2(&d->bus[1], isa_reserve_irq(15)); 166*016512f3SHuacai Chen ide_init_ioport(&d->bus[0], 0x1f0, 0x3f6); 167*016512f3SHuacai Chen ide_init_ioport(&d->bus[1], 0x170, 0x376); 168*016512f3SHuacai Chen 169*016512f3SHuacai Chen return 0; 170*016512f3SHuacai Chen } 171*016512f3SHuacai Chen 172*016512f3SHuacai Chen void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) 173*016512f3SHuacai Chen { 174*016512f3SHuacai Chen PCIDevice *dev; 175*016512f3SHuacai Chen 176*016512f3SHuacai Chen dev = pci_create_simple(bus, devfn, "via-ide"); 177*016512f3SHuacai Chen pci_ide_create_devs(dev, hd_table); 178*016512f3SHuacai Chen } 179*016512f3SHuacai Chen 180*016512f3SHuacai Chen static PCIDeviceInfo via_ide_info = { 181*016512f3SHuacai Chen .qdev.name = "via-ide", 182*016512f3SHuacai Chen .qdev.size = sizeof(PCIIDEState), 183*016512f3SHuacai Chen .qdev.no_user = 1, 184*016512f3SHuacai Chen .init = vt82c686b_ide_initfn, 185*016512f3SHuacai Chen }; 186*016512f3SHuacai Chen 187*016512f3SHuacai Chen static void via_ide_register(void) 188*016512f3SHuacai Chen { 189*016512f3SHuacai Chen pci_qdev_register(&via_ide_info); 190*016512f3SHuacai Chen } 191*016512f3SHuacai Chen device_init(via_ide_register); 192