root / hw / ide / via.c @ 34b5d2c6
History | View | Annotate | Download (7.2 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 | 0d09e41a | Paolo Bonzini | #include <hw/i386/pc.h> |
28 | a2cb15b0 | Michael S. Tsirkin | #include <hw/pci/pci.h> |
29 | 0d09e41a | Paolo Bonzini | #include <hw/isa/isa.h> |
30 | 737e150e | Paolo Bonzini | #include "block/block.h" |
31 | 9c17d615 | Paolo Bonzini | #include "sysemu/sysemu.h" |
32 | 9c17d615 | Paolo Bonzini | #include "sysemu/dma.h" |
33 | 016512f3 | Huacai Chen | |
34 | 016512f3 | Huacai Chen | #include <hw/ide/pci.h> |
35 | 016512f3 | Huacai Chen | |
36 | a8170e5e | Avi Kivity | static uint64_t bmdma_read(void *opaque, hwaddr 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 | 08406b03 | malc | 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 | a8170e5e | Avi Kivity | static void bmdma_write(void *opaque, hwaddr 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 | 08406b03 | malc | 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 | 0ed8b6f6 | Blue Swirl | bmdma_cmd_writeb(bm, val); |
78 | 0ed8b6f6 | Blue Swirl | break;
|
79 | 016512f3 | Huacai Chen | case 2: |
80 | 016512f3 | Huacai Chen | bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06); |
81 | 016512f3 | Huacai Chen | break;
|
82 | 016512f3 | Huacai Chen | default:;
|
83 | 016512f3 | Huacai Chen | } |
84 | 016512f3 | Huacai Chen | } |
85 | 016512f3 | Huacai Chen | |
86 | a348f108 | Stefan Weil | static const MemoryRegionOps via_bmdma_ops = { |
87 | a9deb8c6 | Avi Kivity | .read = bmdma_read, |
88 | a9deb8c6 | Avi Kivity | .write = bmdma_write, |
89 | a9deb8c6 | Avi Kivity | }; |
90 | a9deb8c6 | Avi Kivity | |
91 | a9deb8c6 | Avi Kivity | static void bmdma_setup_bar(PCIIDEState *d) |
92 | 016512f3 | Huacai Chen | { |
93 | 016512f3 | Huacai Chen | int i;
|
94 | 016512f3 | Huacai Chen | |
95 | 1437c94b | Paolo Bonzini | memory_region_init(&d->bmdma_bar, OBJECT(d), "via-bmdma-container", 16); |
96 | 016512f3 | Huacai Chen | for(i = 0;i < 2; i++) { |
97 | 016512f3 | Huacai Chen | BMDMAState *bm = &d->bmdma[i]; |
98 | 016512f3 | Huacai Chen | |
99 | 1437c94b | Paolo Bonzini | memory_region_init_io(&bm->extra_io, OBJECT(d), &via_bmdma_ops, bm, |
100 | a9deb8c6 | Avi Kivity | "via-bmdma", 4); |
101 | a9deb8c6 | Avi Kivity | memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
|
102 | 1437c94b | Paolo Bonzini | memory_region_init_io(&bm->addr_ioport, OBJECT(d), |
103 | 1437c94b | Paolo Bonzini | &bmdma_addr_ioport_ops, bm, "bmdma", 4); |
104 | a9deb8c6 | Avi Kivity | memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport); |
105 | 016512f3 | Huacai Chen | } |
106 | 016512f3 | Huacai Chen | } |
107 | 016512f3 | Huacai Chen | |
108 | 016512f3 | Huacai Chen | static void via_reset(void *opaque) |
109 | 016512f3 | Huacai Chen | { |
110 | 016512f3 | Huacai Chen | PCIIDEState *d = opaque; |
111 | f6c11d56 | Andreas Färber | PCIDevice *pd = PCI_DEVICE(d); |
112 | f6c11d56 | Andreas Färber | uint8_t *pci_conf = pd->config; |
113 | 016512f3 | Huacai Chen | int i;
|
114 | 016512f3 | Huacai Chen | |
115 | 016512f3 | Huacai Chen | for (i = 0; i < 2; i++) { |
116 | 016512f3 | Huacai Chen | ide_bus_reset(&d->bus[i]); |
117 | 016512f3 | Huacai Chen | } |
118 | 016512f3 | Huacai Chen | |
119 | 016512f3 | Huacai Chen | pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_WAIT); |
120 | 016512f3 | Huacai Chen | pci_set_word(pci_conf + PCI_STATUS, PCI_STATUS_FAST_BACK | |
121 | 016512f3 | Huacai Chen | PCI_STATUS_DEVSEL_MEDIUM); |
122 | 016512f3 | Huacai Chen | |
123 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, 0x000001f0);
|
124 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_1, 0x000003f4);
|
125 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_2, 0x00000170);
|
126 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_3, 0x00000374);
|
127 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_BASE_ADDRESS_4, 0x0000cc01); /* BMIBA: 20-23h */ |
128 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_INTERRUPT_LINE, 0x0000010e);
|
129 | 016512f3 | Huacai Chen | |
130 | 016512f3 | Huacai Chen | /* IDE chip enable, IDE configuration 1/2, IDE FIFO Configuration*/
|
131 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x40, 0x0a090600); |
132 | 016512f3 | Huacai Chen | /* IDE misc configuration 1/2/3 */
|
133 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x44, 0x00c00068); |
134 | 016512f3 | Huacai Chen | /* IDE Timing control */
|
135 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x48, 0xa8a8a8a8); |
136 | 016512f3 | Huacai Chen | /* IDE Address Setup Time */
|
137 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x4c, 0x000000ff); |
138 | 016512f3 | Huacai Chen | /* UltraDMA Extended Timing Control*/
|
139 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x50, 0x07070707); |
140 | 016512f3 | Huacai Chen | /* UltraDMA FIFO Control */
|
141 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x54, 0x00000004); |
142 | 016512f3 | Huacai Chen | /* IDE primary sector size */
|
143 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x60, 0x00000200); |
144 | 016512f3 | Huacai Chen | /* IDE secondary sector size */
|
145 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0x68, 0x00000200); |
146 | 016512f3 | Huacai Chen | /* PCI PM Block */
|
147 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + 0xc0, 0x00020001); |
148 | 016512f3 | Huacai Chen | } |
149 | 016512f3 | Huacai Chen | |
150 | 61d9d6b0 | Stefan Hajnoczi | static void vt82c686b_init_ports(PCIIDEState *d) { |
151 | 4a91d3b3 | Richard Henderson | static const struct { |
152 | 61d9d6b0 | Stefan Hajnoczi | int iobase;
|
153 | 61d9d6b0 | Stefan Hajnoczi | int iobase2;
|
154 | 61d9d6b0 | Stefan Hajnoczi | int isairq;
|
155 | 61d9d6b0 | Stefan Hajnoczi | } port_info[] = { |
156 | 61d9d6b0 | Stefan Hajnoczi | {0x1f0, 0x3f6, 14}, |
157 | 61d9d6b0 | Stefan Hajnoczi | {0x170, 0x376, 15}, |
158 | 61d9d6b0 | Stefan Hajnoczi | }; |
159 | 4a91d3b3 | Richard Henderson | int i;
|
160 | 61d9d6b0 | Stefan Hajnoczi | |
161 | 61d9d6b0 | Stefan Hajnoczi | for (i = 0; i < 2; i++) { |
162 | c6baf942 | Andreas Färber | ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(d), i, 2); |
163 | 4a91d3b3 | Richard Henderson | ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase,
|
164 | 4a91d3b3 | Richard Henderson | port_info[i].iobase2); |
165 | 48a18b3c | Hervé Poussineau | ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq));
|
166 | 61d9d6b0 | Stefan Hajnoczi | |
167 | a9deb8c6 | Avi Kivity | bmdma_init(&d->bus[i], &d->bmdma[i], d); |
168 | 61d9d6b0 | Stefan Hajnoczi | d->bmdma[i].bus = &d->bus[i]; |
169 | 61d9d6b0 | Stefan Hajnoczi | qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb, |
170 | 653af235 | Kevin Wolf | &d->bmdma[i].dma); |
171 | 61d9d6b0 | Stefan Hajnoczi | } |
172 | 61d9d6b0 | Stefan Hajnoczi | } |
173 | 61d9d6b0 | Stefan Hajnoczi | |
174 | 016512f3 | Huacai Chen | /* via ide func */
|
175 | 016512f3 | Huacai Chen | static int vt82c686b_ide_initfn(PCIDevice *dev) |
176 | 016512f3 | Huacai Chen | { |
177 | f6c11d56 | Andreas Färber | PCIIDEState *d = PCI_IDE(dev); |
178 | f6c11d56 | Andreas Färber | uint8_t *pci_conf = dev->config; |
179 | 016512f3 | Huacai Chen | |
180 | 016512f3 | Huacai Chen | pci_config_set_prog_interface(pci_conf, 0x8a); /* legacy ATA mode */ |
181 | 016512f3 | Huacai Chen | pci_set_long(pci_conf + PCI_CAPABILITY_LIST, 0x000000c0);
|
182 | 016512f3 | Huacai Chen | |
183 | 016512f3 | Huacai Chen | qemu_register_reset(via_reset, d); |
184 | a9deb8c6 | Avi Kivity | bmdma_setup_bar(d); |
185 | f6c11d56 | Andreas Färber | pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
|
186 | 016512f3 | Huacai Chen | |
187 | f6c11d56 | Andreas Färber | vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
|
188 | 016512f3 | Huacai Chen | |
189 | 61d9d6b0 | Stefan Hajnoczi | vt82c686b_init_ports(d); |
190 | 016512f3 | Huacai Chen | |
191 | 016512f3 | Huacai Chen | return 0; |
192 | 016512f3 | Huacai Chen | } |
193 | 016512f3 | Huacai Chen | |
194 | f90c2bcd | Alex Williamson | static void vt82c686b_ide_exitfn(PCIDevice *dev) |
195 | a9deb8c6 | Avi Kivity | { |
196 | f6c11d56 | Andreas Färber | PCIIDEState *d = PCI_IDE(dev); |
197 | a9deb8c6 | Avi Kivity | unsigned i;
|
198 | a9deb8c6 | Avi Kivity | |
199 | a9deb8c6 | Avi Kivity | for (i = 0; i < 2; ++i) { |
200 | a9deb8c6 | Avi Kivity | memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io); |
201 | a9deb8c6 | Avi Kivity | memory_region_destroy(&d->bmdma[i].extra_io); |
202 | a9deb8c6 | Avi Kivity | memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport); |
203 | a9deb8c6 | Avi Kivity | memory_region_destroy(&d->bmdma[i].addr_ioport); |
204 | a9deb8c6 | Avi Kivity | } |
205 | a9deb8c6 | Avi Kivity | memory_region_destroy(&d->bmdma_bar); |
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 | 125ee0ed | Marcel Apfelbaum | set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); |
228 | 39bffca2 | Anthony Liguori | dc->no_user = 1;
|
229 | 40021f08 | Anthony Liguori | } |
230 | 40021f08 | Anthony Liguori | |
231 | 8c43a6f0 | Andreas Färber | static const TypeInfo via_ide_info = { |
232 | 39bffca2 | Anthony Liguori | .name = "via-ide",
|
233 | f6c11d56 | Andreas Färber | .parent = TYPE_PCI_IDE, |
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) |