root / hw / ide / via.c @ bc4caf49
History | View | Annotate | Download (7.1 kB)
1 | 016512f3 | Huacai Chen | /*
|
---|---|---|---|
2 | 016512f3 | Huacai Chen | * QEMU IDE Emulation: PCI VIA82C686B support.
|
3 | 016512f3 | Huacai Chen | *
|
4 | 016512f3 | Huacai Chen | * Copyright (c) 2003 Fabrice Bellard
|
5 | 016512f3 | Huacai Chen | * Copyright (c) 2006 Openedhand Ltd.
|
6 | 016512f3 | Huacai Chen | * Copyright (c) 2010 Huacai Chen <zltjiangshi@gmail.com>
|
7 | 016512f3 | Huacai Chen | *
|
8 | 016512f3 | Huacai Chen | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
9 | 016512f3 | Huacai Chen | * of this software and associated documentation files (the "Software"), to deal
|
10 | 016512f3 | Huacai Chen | * in the Software without restriction, including without limitation the rights
|
11 | 016512f3 | Huacai Chen | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
12 | 016512f3 | Huacai Chen | * copies of the Software, and to permit persons to whom the Software is
|
13 | 016512f3 | Huacai Chen | * furnished to do so, subject to the following conditions:
|
14 | 016512f3 | Huacai Chen | *
|
15 | 016512f3 | Huacai Chen | * The above copyright notice and this permission notice shall be included in
|
16 | 016512f3 | Huacai Chen | * all copies or substantial portions of the Software.
|
17 | 016512f3 | Huacai Chen | *
|
18 | 016512f3 | Huacai Chen | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
19 | 016512f3 | Huacai Chen | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
20 | 016512f3 | Huacai Chen | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
21 | 016512f3 | Huacai Chen | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
22 | 016512f3 | Huacai Chen | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
23 | 016512f3 | Huacai Chen | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
24 | 016512f3 | Huacai Chen | * THE SOFTWARE.
|
25 | 016512f3 | Huacai Chen | */
|
26 | 016512f3 | Huacai Chen | #include <hw/hw.h> |
27 | 016512f3 | Huacai Chen | #include <hw/pc.h> |
28 | 016512f3 | Huacai Chen | #include <hw/pci.h> |
29 | 016512f3 | Huacai Chen | #include <hw/isa.h> |
30 | 016512f3 | Huacai Chen | #include "block.h" |
31 | 016512f3 | Huacai Chen | #include "sysemu.h" |
32 | 016512f3 | Huacai Chen | #include "dma.h" |
33 | 016512f3 | Huacai Chen | |
34 | 016512f3 | Huacai Chen | #include <hw/ide/pci.h> |
35 | 016512f3 | Huacai Chen | |
36 | a9deb8c6 | Avi Kivity | static uint64_t bmdma_read(void *opaque, target_phys_addr_t addr, |
37 | a9deb8c6 | Avi Kivity | unsigned size)
|
38 | 016512f3 | Huacai Chen | { |
39 | 016512f3 | Huacai Chen | BMDMAState *bm = opaque; |
40 | 016512f3 | Huacai Chen | uint32_t val; |
41 | 016512f3 | Huacai Chen | |
42 | a9deb8c6 | Avi Kivity | if (size != 1) { |
43 | a9deb8c6 | Avi Kivity | return ((uint64_t)1 << (size * 8)) - 1; |
44 | a9deb8c6 | Avi Kivity | } |
45 | a9deb8c6 | Avi Kivity | |
46 | 016512f3 | Huacai Chen | switch (addr & 3) { |
47 | 016512f3 | Huacai Chen | case 0: |
48 | 016512f3 | Huacai Chen | val = bm->cmd; |
49 | 016512f3 | Huacai Chen | break;
|
50 | 016512f3 | Huacai Chen | case 2: |
51 | 016512f3 | Huacai Chen | val = bm->status; |
52 | 016512f3 | Huacai Chen | break;
|
53 | 016512f3 | Huacai Chen | default:
|
54 | 016512f3 | Huacai Chen | val = 0xff;
|
55 | 016512f3 | Huacai Chen | break;
|
56 | 016512f3 | Huacai Chen | } |
57 | 016512f3 | Huacai Chen | #ifdef DEBUG_IDE
|
58 | 016512f3 | Huacai Chen | printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
|
59 | 016512f3 | Huacai Chen | #endif
|
60 | 016512f3 | Huacai Chen | return val;
|
61 | 016512f3 | Huacai Chen | } |
62 | 016512f3 | Huacai Chen | |
63 | a9deb8c6 | Avi Kivity | static void bmdma_write(void *opaque, target_phys_addr_t addr, |
64 | a9deb8c6 | Avi Kivity | uint64_t val, unsigned size)
|
65 | 016512f3 | Huacai Chen | { |
66 | 016512f3 | Huacai Chen | BMDMAState *bm = opaque; |
67 | a9deb8c6 | Avi Kivity | |
68 | a9deb8c6 | Avi Kivity | if (size != 1) { |
69 | a9deb8c6 | Avi Kivity | return;
|
70 | a9deb8c6 | Avi Kivity | } |
71 | a9deb8c6 | Avi Kivity | |
72 | 016512f3 | Huacai Chen | #ifdef DEBUG_IDE
|
73 | 016512f3 | Huacai Chen | printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
|
74 | 016512f3 | Huacai Chen | #endif
|
75 | 016512f3 | Huacai Chen | switch (addr & 3) { |
76 | a9deb8c6 | Avi Kivity | case 0: |
77 | a9deb8c6 | Avi Kivity | return bmdma_cmd_writeb(bm, val);
|
78 | 016512f3 | Huacai Chen | case 2: |
79 | 016512f3 | Huacai Chen | bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); |
80 | 016512f3 | Huacai Chen | break;
|
81 | 016512f3 | Huacai Chen | default:;
|
82 | 016512f3 | Huacai Chen | } |
83 | 016512f3 | Huacai Chen | } |
84 | 016512f3 | Huacai Chen | |
85 | a348f108 | Stefan Weil | static const MemoryRegionOps via_bmdma_ops = { |
86 | a9deb8c6 | Avi Kivity | .read = bmdma_read, |
87 | a9deb8c6 | Avi Kivity | .write = bmdma_write, |
88 | a9deb8c6 | Avi Kivity | }; |
89 | a9deb8c6 | Avi Kivity | |
90 | a9deb8c6 | Avi Kivity | static void bmdma_setup_bar(PCIIDEState *d) |
91 | 016512f3 | Huacai Chen | { |
92 | 016512f3 | Huacai Chen | int i;
|
93 | 016512f3 | Huacai Chen | |
94 | a9deb8c6 | Avi Kivity | memory_region_init(&d->bmdma_bar, "via-bmdma-container", 16); |
95 | 016512f3 | Huacai Chen | for(i = 0;i < 2; i++) { |
96 | 016512f3 | Huacai Chen | BMDMAState *bm = &d->bmdma[i]; |
97 | 016512f3 | Huacai Chen | |
98 | a9deb8c6 | Avi Kivity | memory_region_init_io(&bm->extra_io, &via_bmdma_ops, bm, |
99 | a9deb8c6 | Avi Kivity | "via-bmdma", 4); |
100 | a9deb8c6 | Avi Kivity | memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
|
101 | a9deb8c6 | Avi Kivity | memory_region_init_io(&bm->addr_ioport, &bmdma_addr_ioport_ops, bm, |
102 | a9deb8c6 | Avi Kivity | "bmdma", 4); |
103 | a9deb8c6 | Avi Kivity | memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport); |
104 | 016512f3 | Huacai Chen | } |
105 | 016512f3 | Huacai Chen | } |
106 | 016512f3 | Huacai Chen | |
107 | 016512f3 | Huacai Chen | static void via_reset(void *opaque) |
108 | 016512f3 | Huacai Chen | { |
109 | 016512f3 | Huacai Chen | PCIIDEState *d = opaque; |
110 | 016512f3 | Huacai Chen | uint8_t *pci_conf = d->dev.config; |
111 | 016512f3 | Huacai Chen | int i;
|
112 | 016512f3 | Huacai Chen | |
113 | 016512f3 | Huacai Chen | for (i = 0; i < 2; i++) { |
114 | 016512f3 | Huacai Chen | ide_bus_reset(&d->bus[i]); |
115 | 016512f3 | Huacai Chen | } |
116 | 016512f3 | Huacai Chen | |
117 | 016512f3 | Huacai Chen | pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_WAIT); |
118 | 016512f3 | Huacai Chen | pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK | |
119 | 016512f3 | Huacai Chen | PCI_STATUS_DEVSEL_MEDIUM); |
120 | 016512f3 | Huacai Chen | |
121 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, 0x000001f0);
|
122 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_1, 0x000003f4);
|
123 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x00000170);
|
124 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x00000374);
|
125 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_4, 0x0000cc01); /* BMIBA: 20-23h */ |
126 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000010e);
|
127 | 016512f3 | Huacai Chen | |
128 | 016512f3 | Huacai Chen | /* IDE chip enable, IDE configuration 1/2, IDE FIFO Configuration*/
|
129 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x40, 0x0a090600); |
130 | 016512f3 | Huacai Chen | /* IDE misc configuration 1/2/3 */
|
131 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x44, 0x00c00068); |
132 | 016512f3 | Huacai Chen | /* IDE Timing control */
|
133 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x48, 0xa8a8a8a8); |
134 | 016512f3 | Huacai Chen | /* IDE Address Setup Time */
|
135 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x4c, 0x000000ff); |
136 | 016512f3 | Huacai Chen | /* UltraDMA Extended Timing Control*/
|
137 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x50, 0x07070707); |
138 | 016512f3 | Huacai Chen | /* UltraDMA FIFO Control */
|
139 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x54, 0x00000004); |
140 | 016512f3 | Huacai Chen | /* IDE primary sector size */
|
141 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x60, 0x00000200); |
142 | 016512f3 | Huacai Chen | /* IDE secondary sector size */
|
143 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x68, 0x00000200); |
144 | 016512f3 | Huacai Chen | /* PCI PM Block */
|
145 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0xc0, 0x00020001); |
146 | 016512f3 | Huacai Chen | } |
147 | 016512f3 | Huacai Chen | |
148 | 61d9d6b0 | Stefan Hajnoczi | static void vt82c686b_init_ports(PCIIDEState *d) { |
149 | 4a91d3b3 | Richard Henderson | static const struct { |
150 | 61d9d6b0 | Stefan Hajnoczi | int iobase;
|
151 | 61d9d6b0 | Stefan Hajnoczi | int iobase2;
|
152 | 61d9d6b0 | Stefan Hajnoczi | int isairq;
|
153 | 61d9d6b0 | Stefan Hajnoczi | } port_info[] = { |
154 | 61d9d6b0 | Stefan Hajnoczi | {0x1f0, 0x3f6, 14}, |
155 | 61d9d6b0 | Stefan Hajnoczi | {0x170, 0x376, 15}, |
156 | 61d9d6b0 | Stefan Hajnoczi | }; |
157 | 4a91d3b3 | Richard Henderson | int i;
|
158 | 61d9d6b0 | Stefan Hajnoczi | |
159 | 61d9d6b0 | Stefan Hajnoczi | for (i = 0; i < 2; i++) { |
160 | 61d9d6b0 | Stefan Hajnoczi | ide_bus_new(&d->bus[i], &d->dev.qdev, i); |
161 | 4a91d3b3 | Richard Henderson | ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
|
162 | 4a91d3b3 | Richard Henderson | port_info[i].iobase2); |
163 | 48a18b3c | Hervé Poussineau | ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq));
|
164 | 61d9d6b0 | Stefan Hajnoczi | |
165 | a9deb8c6 | Avi Kivity | bmdma_init(&d->bus[i], &d->bmdma[i], d); |
166 | 61d9d6b0 | Stefan Hajnoczi | d->bmdma[i].bus = &d->bus[i]; |
167 | 61d9d6b0 | Stefan Hajnoczi | qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb, |
168 | 653af235 | Kevin Wolf | &d->bmdma[i].dma); |
169 | 61d9d6b0 | Stefan Hajnoczi | } |
170 | 61d9d6b0 | Stefan Hajnoczi | } |
171 | 61d9d6b0 | Stefan Hajnoczi | |
172 | 016512f3 | Huacai Chen | /* via ide func */
|
173 | 016512f3 | Huacai Chen | static int vt82c686b_ide_initfn(PCIDevice *dev) |
174 | 016512f3 | Huacai Chen | { |
175 | 3a93113a | Dong Xu Wang | PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); |
176 | 016512f3 | Huacai Chen | uint8_t *pci_conf = d->dev.config; |
177 | 016512f3 | Huacai Chen | |
178 | 016512f3 | Huacai Chen | pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */ |
179 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
|
180 | 016512f3 | Huacai Chen | |
181 | 016512f3 | Huacai Chen | qemu_register_reset(via_reset, d); |
182 | a9deb8c6 | Avi Kivity | bmdma_setup_bar(d); |
183 | e824b2cc | Avi Kivity | pci_register_bar(&d->dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
|
184 | 016512f3 | Huacai Chen | |
185 | 1724f049 | Alex Williamson | vmstate_register(&dev->qdev, 0, &vmstate_ide_pci, d);
|
186 | 016512f3 | Huacai Chen | |
187 | 61d9d6b0 | Stefan Hajnoczi | vt82c686b_init_ports(d); |
188 | 016512f3 | Huacai Chen | |
189 | 016512f3 | Huacai Chen | return 0; |
190 | 016512f3 | Huacai Chen | } |
191 | 016512f3 | Huacai Chen | |
192 | a9deb8c6 | Avi Kivity | static int vt82c686b_ide_exitfn(PCIDevice *dev) |
193 | a9deb8c6 | Avi Kivity | { |
194 | a9deb8c6 | Avi Kivity | PCIIDEState *d = DO_UPCAST(PCIIDEState, dev, dev); |
195 | a9deb8c6 | Avi Kivity | unsigned i;
|
196 | a9deb8c6 | Avi Kivity | |
197 | a9deb8c6 | Avi Kivity | for (i = 0; i < 2; ++i) { |
198 | a9deb8c6 | Avi Kivity | memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io); |
199 | a9deb8c6 | Avi Kivity | memory_region_destroy(&d->bmdma[i].extra_io); |
200 | a9deb8c6 | Avi Kivity | memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport); |
201 | a9deb8c6 | Avi Kivity | memory_region_destroy(&d->bmdma[i].addr_ioport); |
202 | a9deb8c6 | Avi Kivity | } |
203 | a9deb8c6 | Avi Kivity | memory_region_destroy(&d->bmdma_bar); |
204 | a9deb8c6 | Avi Kivity | |
205 | a9deb8c6 | Avi Kivity | return 0; |
206 | a9deb8c6 | Avi Kivity | } |
207 | a9deb8c6 | Avi Kivity | |
208 | 016512f3 | Huacai Chen | void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn) |
209 | 016512f3 | Huacai Chen | { |
210 | 016512f3 | Huacai Chen | PCIDevice *dev; |
211 | 016512f3 | Huacai Chen | |
212 | 016512f3 | Huacai Chen | dev = pci_create_simple(bus, devfn, "via-ide");
|
213 | 016512f3 | Huacai Chen | pci_ide_create_devs(dev, hd_table); |
214 | 016512f3 | Huacai Chen | } |
215 | 016512f3 | Huacai Chen | |
216 | 40021f08 | Anthony Liguori | static void via_ide_class_init(ObjectClass *klass, void *data) |
217 | 40021f08 | Anthony Liguori | { |
218 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
219 | 40021f08 | Anthony Liguori | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
220 | 40021f08 | Anthony Liguori | |
221 | 40021f08 | Anthony Liguori | k->init = vt82c686b_ide_initfn; |
222 | 40021f08 | Anthony Liguori | k->exit = vt82c686b_ide_exitfn; |
223 | 40021f08 | Anthony Liguori | k->vendor_id = PCI_VENDOR_ID_VIA; |
224 | 40021f08 | Anthony Liguori | k->device_id = PCI_DEVICE_ID_VIA_IDE; |
225 | 40021f08 | Anthony Liguori | k->revision = 0x06;
|
226 | 40021f08 | Anthony Liguori | k->class_id = PCI_CLASS_STORAGE_IDE; |
227 | 39bffca2 | Anthony Liguori | dc->no_user = 1;
|
228 | 40021f08 | Anthony Liguori | } |
229 | 40021f08 | Anthony Liguori | |
230 | 39bffca2 | Anthony Liguori | static TypeInfo via_ide_info = {
|
231 | 39bffca2 | Anthony Liguori | .name = "via-ide",
|
232 | 39bffca2 | Anthony Liguori | .parent = TYPE_PCI_DEVICE, |
233 | 39bffca2 | Anthony Liguori | .instance_size = sizeof(PCIIDEState),
|
234 | 39bffca2 | Anthony Liguori | .class_init = via_ide_class_init, |
235 | 016512f3 | Huacai Chen | }; |
236 | 016512f3 | Huacai Chen | |
237 | 83f7d43a | Andreas Färber | static void via_ide_register_types(void) |
238 | 016512f3 | Huacai Chen | { |
239 | 39bffca2 | Anthony Liguori | type_register_static(&via_ide_info); |
240 | 016512f3 | Huacai Chen | } |
241 | 83f7d43a | Andreas Färber | |
242 | 83f7d43a | Andreas Färber | type_init(via_ide_register_types) |