Statistics
| Branch: | Revision:

root / hw / ide / cmd646.c @ 216db403

History | View | Annotate | Download (10.4 kB)

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 <hw/hw.h>
26
#include <hw/i386/pc.h>
27
#include <hw/pci/pci.h>
28
#include <hw/isa/isa.h>
29
#include "block/block.h"
30
#include "sysemu/sysemu.h"
31
#include "sysemu/dma.h"
32

    
33
#include <hw/ide/pci.h>
34

    
35
/* CMD646 specific */
36
#define MRDMODE                0x71
37
#define   MRDMODE_INTR_CH0        0x04
38
#define   MRDMODE_INTR_CH1        0x08
39
#define   MRDMODE_BLK_CH0        0x10
40
#define   MRDMODE_BLK_CH1        0x20
41
#define UDIDETCR0        0x73
42
#define UDIDETCR1        0x7B
43

    
44
static void cmd646_update_irq(PCIIDEState *d);
45

    
46
static uint64_t cmd646_cmd_read(void *opaque, hwaddr addr,
47
                                unsigned size)
48
{
49
    CMD646BAR *cmd646bar = opaque;
50

    
51
    if (addr != 2 || size != 1) {
52
        return ((uint64_t)1 << (size * 8)) - 1;
53
    }
54
    return ide_status_read(cmd646bar->bus, addr + 2);
55
}
56

    
57
static void cmd646_cmd_write(void *opaque, hwaddr addr,
58
                             uint64_t data, unsigned size)
59
{
60
    CMD646BAR *cmd646bar = opaque;
61

    
62
    if (addr != 2 || size != 1) {
63
        return;
64
    }
65
    ide_cmd_write(cmd646bar->bus, addr + 2, data);
66
}
67

    
68
static const MemoryRegionOps cmd646_cmd_ops = {
69
    .read = cmd646_cmd_read,
70
    .write = cmd646_cmd_write,
71
    .endianness = DEVICE_LITTLE_ENDIAN,
72
};
73

    
74
static uint64_t cmd646_data_read(void *opaque, hwaddr addr,
75
                                 unsigned size)
76
{
77
    CMD646BAR *cmd646bar = opaque;
78

    
79
    if (size == 1) {
80
        return ide_ioport_read(cmd646bar->bus, addr);
81
    } else if (addr == 0) {
82
        if (size == 2) {
83
            return ide_data_readw(cmd646bar->bus, addr);
84
        } else {
85
            return ide_data_readl(cmd646bar->bus, addr);
86
        }
87
    }
88
    return ((uint64_t)1 << (size * 8)) - 1;
89
}
90

    
91
static void cmd646_data_write(void *opaque, hwaddr addr,
92
                             uint64_t data, unsigned size)
93
{
94
    CMD646BAR *cmd646bar = opaque;
95

    
96
    if (size == 1) {
97
        ide_ioport_write(cmd646bar->bus, addr, data);
98
    } else if (addr == 0) {
99
        if (size == 2) {
100
            ide_data_writew(cmd646bar->bus, addr, data);
101
        } else {
102
            ide_data_writel(cmd646bar->bus, addr, data);
103
        }
104
    }
105
}
106

    
107
static const MemoryRegionOps cmd646_data_ops = {
108
    .read = cmd646_data_read,
109
    .write = cmd646_data_write,
110
    .endianness = DEVICE_LITTLE_ENDIAN,
111
};
112

    
113
static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
114
{
115
    IDEBus *bus = &d->bus[bus_num];
116
    CMD646BAR *bar = &d->cmd646_bar[bus_num];
117

    
118
    bar->bus = bus;
119
    bar->pci_dev = d;
120
    memory_region_init_io(&bar->cmd, OBJECT(d), &cmd646_cmd_ops, bar,
121
                          "cmd646-cmd", 4);
122
    memory_region_init_io(&bar->data, OBJECT(d), &cmd646_data_ops, bar,
123
                          "cmd646-data", 8);
124
}
125

    
126
static uint64_t bmdma_read(void *opaque, hwaddr addr,
127
                           unsigned size)
128
{
129
    BMDMAState *bm = opaque;
130
    PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev);
131
    uint32_t val;
132

    
133
    if (size != 1) {
134
        return ((uint64_t)1 << (size * 8)) - 1;
135
    }
136

    
137
    switch(addr & 3) {
138
    case 0:
139
        val = bm->cmd;
140
        break;
141
    case 1:
142
        val = pci_dev->config[MRDMODE];
143
        break;
144
    case 2:
145
        val = bm->status;
146
        break;
147
    case 3:
148
        if (bm == &bm->pci_dev->bmdma[0]) {
149
            val = pci_dev->config[UDIDETCR0];
150
        } else {
151
            val = pci_dev->config[UDIDETCR1];
152
        }
153
        break;
154
    default:
155
        val = 0xff;
156
        break;
157
    }
158
#ifdef DEBUG_IDE
159
    printf("bmdma: readb " TARGET_FMT_plx " : 0x%02x\n", addr, val);
160
#endif
161
    return val;
162
}
163

    
164
static void bmdma_write(void *opaque, hwaddr addr,
165
                        uint64_t val, unsigned size)
166
{
167
    BMDMAState *bm = opaque;
168
    PCIDevice *pci_dev = PCI_DEVICE(bm->pci_dev);
169

    
170
    if (size != 1) {
171
        return;
172
    }
173

    
174
#ifdef DEBUG_IDE
175
    printf("bmdma: writeb " TARGET_FMT_plx " : 0x%" PRIx64 "\n", addr, val);
176
#endif
177
    switch(addr & 3) {
178
    case 0:
179
        bmdma_cmd_writeb(bm, val);
180
        break;
181
    case 1:
182
        pci_dev->config[MRDMODE] =
183
            (pci_dev->config[MRDMODE] & ~0x30) | (val & 0x30);
184
        cmd646_update_irq(bm->pci_dev);
185
        break;
186
    case 2:
187
        bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
188
        break;
189
    case 3:
190
        if (bm == &bm->pci_dev->bmdma[0]) {
191
            pci_dev->config[UDIDETCR0] = val;
192
        } else {
193
            pci_dev->config[UDIDETCR1] = val;
194
        }
195
        break;
196
    }
197
}
198

    
199
static const MemoryRegionOps cmd646_bmdma_ops = {
200
    .read = bmdma_read,
201
    .write = bmdma_write,
202
};
203

    
204
static void bmdma_setup_bar(PCIIDEState *d)
205
{
206
    BMDMAState *bm;
207
    int i;
208

    
209
    memory_region_init(&d->bmdma_bar, OBJECT(d), "cmd646-bmdma", 16);
210
    for(i = 0;i < 2; i++) {
211
        bm = &d->bmdma[i];
212
        memory_region_init_io(&bm->extra_io, OBJECT(d), &cmd646_bmdma_ops, bm,
213
                              "cmd646-bmdma-bus", 4);
214
        memory_region_add_subregion(&d->bmdma_bar, i * 8, &bm->extra_io);
215
        memory_region_init_io(&bm->addr_ioport, OBJECT(d),
216
                              &bmdma_addr_ioport_ops, bm,
217
                              "cmd646-bmdma-ioport", 4);
218
        memory_region_add_subregion(&d->bmdma_bar, i * 8 + 4, &bm->addr_ioport);
219
    }
220
}
221

    
222
/* XXX: call it also when the MRDMODE is changed from the PCI config
223
   registers */
224
static void cmd646_update_irq(PCIIDEState *d)
225
{
226
    PCIDevice *pd = PCI_DEVICE(d);
227
    int pci_level;
228

    
229
    pci_level = ((pd->config[MRDMODE] & MRDMODE_INTR_CH0) &&
230
                 !(pd->config[MRDMODE] & MRDMODE_BLK_CH0)) ||
231
        ((pd->config[MRDMODE] & MRDMODE_INTR_CH1) &&
232
         !(pd->config[MRDMODE] & MRDMODE_BLK_CH1));
233
    pci_set_irq(pd, pci_level);
234
}
235

    
236
/* the PCI irq level is the logical OR of the two channels */
237
static void cmd646_set_irq(void *opaque, int channel, int level)
238
{
239
    PCIIDEState *d = opaque;
240
    PCIDevice *pd = PCI_DEVICE(d);
241
    int irq_mask;
242

    
243
    irq_mask = MRDMODE_INTR_CH0 << channel;
244
    if (level) {
245
        pd->config[MRDMODE] |= irq_mask;
246
    } else {
247
        pd->config[MRDMODE] &= ~irq_mask;
248
    }
249
    cmd646_update_irq(d);
250
}
251

    
252
static void cmd646_reset(void *opaque)
253
{
254
    PCIIDEState *d = opaque;
255
    unsigned int i;
256

    
257
    for (i = 0; i < 2; i++) {
258
        ide_bus_reset(&d->bus[i]);
259
    }
260
}
261

    
262
/* CMD646 PCI IDE controller */
263
static int pci_cmd646_ide_initfn(PCIDevice *dev)
264
{
265
    PCIIDEState *d = PCI_IDE(dev);
266
    uint8_t *pci_conf = dev->config;
267
    qemu_irq *irq;
268
    int i;
269

    
270
    pci_conf[PCI_CLASS_PROG] = 0x8f;
271

    
272
    pci_conf[0x51] = 0x04; // enable IDE0
273
    if (d->secondary) {
274
        /* XXX: if not enabled, really disable the seconday IDE controller */
275
        pci_conf[0x51] |= 0x08; /* enable IDE1 */
276
    }
277

    
278
    setup_cmd646_bar(d, 0);
279
    setup_cmd646_bar(d, 1);
280
    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].data);
281
    pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].cmd);
282
    pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].data);
283
    pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[1].cmd);
284
    bmdma_setup_bar(d);
285
    pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, &d->bmdma_bar);
286

    
287
    /* TODO: RST# value should be 0 */
288
    pci_conf[PCI_INTERRUPT_PIN] = 0x01; // interrupt on pin 1
289

    
290
    irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
291
    for (i = 0; i < 2; i++) {
292
        ide_bus_new(&d->bus[i], sizeof(d->bus[i]), DEVICE(dev), i, 2);
293
        ide_init2(&d->bus[i], irq[i]);
294

    
295
        bmdma_init(&d->bus[i], &d->bmdma[i], d);
296
        d->bmdma[i].bus = &d->bus[i];
297
        qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
298
                                         &d->bmdma[i].dma);
299
    }
300

    
301
    vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
302
    qemu_register_reset(cmd646_reset, d);
303
    return 0;
304
}
305

    
306
static void pci_cmd646_ide_exitfn(PCIDevice *dev)
307
{
308
    PCIIDEState *d = PCI_IDE(dev);
309
    unsigned i;
310

    
311
    for (i = 0; i < 2; ++i) {
312
        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].extra_io);
313
        memory_region_destroy(&d->bmdma[i].extra_io);
314
        memory_region_del_subregion(&d->bmdma_bar, &d->bmdma[i].addr_ioport);
315
        memory_region_destroy(&d->bmdma[i].addr_ioport);
316
        memory_region_destroy(&d->cmd646_bar[i].cmd);
317
        memory_region_destroy(&d->cmd646_bar[i].data);
318
    }
319
    memory_region_destroy(&d->bmdma_bar);
320
}
321

    
322
void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
323
                         int secondary_ide_enabled)
324
{
325
    PCIDevice *dev;
326

    
327
    dev = pci_create(bus, -1, "cmd646-ide");
328
    qdev_prop_set_uint32(&dev->qdev, "secondary", secondary_ide_enabled);
329
    qdev_init_nofail(&dev->qdev);
330

    
331
    pci_ide_create_devs(dev, hd_table);
332
}
333

    
334
static Property cmd646_ide_properties[] = {
335
    DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
336
    DEFINE_PROP_END_OF_LIST(),
337
};
338

    
339
static void cmd646_ide_class_init(ObjectClass *klass, void *data)
340
{
341
    DeviceClass *dc = DEVICE_CLASS(klass);
342
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
343

    
344
    k->init = pci_cmd646_ide_initfn;
345
    k->exit = pci_cmd646_ide_exitfn;
346
    k->vendor_id = PCI_VENDOR_ID_CMD;
347
    k->device_id = PCI_DEVICE_ID_CMD_646;
348
    k->revision = 0x07;
349
    k->class_id = PCI_CLASS_STORAGE_IDE;
350
    dc->props = cmd646_ide_properties;
351
}
352

    
353
static const TypeInfo cmd646_ide_info = {
354
    .name          = "cmd646-ide",
355
    .parent        = TYPE_PCI_IDE,
356
    .class_init    = cmd646_ide_class_init,
357
};
358

    
359
static void cmd646_ide_register_types(void)
360
{
361
    type_register_static(&cmd646_ide_info);
362
}
363

    
364
type_init(cmd646_ide_register_types)