Statistics
| Branch: | Revision:

root / hw / ppc4xx_pci.c @ 0be71e32

History | View | Annotate | Download (10.6 kB)

1
/*
2
 * This program is free software; you can redistribute it and/or modify
3
 * it under the terms of the GNU General Public License, version 2, as
4
 * published by the Free Software Foundation.
5
 *
6
 * This program is distributed in the hope that it will be useful,
7
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9
 * GNU General Public License for more details.
10
 *
11
 * You should have received a copy of the GNU General Public License
12
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
13
 *
14
 * Copyright IBM Corp. 2008
15
 *
16
 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
17
 */
18

    
19
/* This file implements emulation of the 32-bit PCI controller found in some
20
 * 4xx SoCs, such as the 440EP. */
21

    
22
#include "hw.h"
23
#include "ppc.h"
24
#include "ppc4xx.h"
25
#include "pci.h"
26
#include "pci_host.h"
27
#include "bswap.h"
28

    
29
#undef DEBUG
30
#ifdef DEBUG
31
#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
32
#else
33
#define DPRINTF(fmt, ...)
34
#endif /* DEBUG */
35

    
36
struct PCIMasterMap {
37
    uint32_t la;
38
    uint32_t ma;
39
    uint32_t pcila;
40
    uint32_t pciha;
41
};
42

    
43
struct PCITargetMap {
44
    uint32_t ms;
45
    uint32_t la;
46
};
47

    
48
#define PPC4xx_PCI_NR_PMMS 3
49
#define PPC4xx_PCI_NR_PTMS 2
50

    
51
struct PPC4xxPCIState {
52
    struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
53
    struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
54

    
55
    PCIHostState pci_state;
56
    PCIDevice *pci_dev;
57
};
58
typedef struct PPC4xxPCIState PPC4xxPCIState;
59

    
60
#define PCIC0_CFGADDR       0x0
61
#define PCIC0_CFGDATA       0x4
62

    
63
/* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
64
 * PCI accesses. */
65
#define PCIL0_PMM0LA        0x0
66
#define PCIL0_PMM0MA        0x4
67
#define PCIL0_PMM0PCILA     0x8
68
#define PCIL0_PMM0PCIHA     0xc
69
#define PCIL0_PMM1LA        0x10
70
#define PCIL0_PMM1MA        0x14
71
#define PCIL0_PMM1PCILA     0x18
72
#define PCIL0_PMM1PCIHA     0x1c
73
#define PCIL0_PMM2LA        0x20
74
#define PCIL0_PMM2MA        0x24
75
#define PCIL0_PMM2PCILA     0x28
76
#define PCIL0_PMM2PCIHA     0x2c
77

    
78
/* PCI Target Map (PTM) registers specify which PCI addresses are translated to
79
 * PLB accesses. */
80
#define PCIL0_PTM1MS        0x30
81
#define PCIL0_PTM1LA        0x34
82
#define PCIL0_PTM2MS        0x38
83
#define PCIL0_PTM2LA        0x3c
84
#define PCI_REG_SIZE        0x40
85

    
86

    
87
static uint32_t pci4xx_cfgaddr_readl(void *opaque, target_phys_addr_t addr)
88
{
89
    PPC4xxPCIState *ppc4xx_pci = opaque;
90

    
91
    return ppc4xx_pci->pci_state.config_reg;
92
}
93

    
94
static CPUReadMemoryFunc * const pci4xx_cfgaddr_read[] = {
95
    &pci4xx_cfgaddr_readl,
96
    &pci4xx_cfgaddr_readl,
97
    &pci4xx_cfgaddr_readl,
98
};
99

    
100
static void pci4xx_cfgaddr_writel(void *opaque, target_phys_addr_t addr,
101
                                  uint32_t value)
102
{
103
    PPC4xxPCIState *ppc4xx_pci = opaque;
104

    
105
#ifdef TARGET_WORDS_BIGENDIAN
106
    value = bswap32(value);
107
#endif
108

    
109
    ppc4xx_pci->pci_state.config_reg = value & ~0x3;
110
}
111

    
112
static CPUWriteMemoryFunc * const pci4xx_cfgaddr_write[] = {
113
    &pci4xx_cfgaddr_writel,
114
    &pci4xx_cfgaddr_writel,
115
    &pci4xx_cfgaddr_writel,
116
};
117

    
118
static void ppc4xx_pci_reg_write4(void *opaque, target_phys_addr_t offset,
119
                                  uint32_t value)
120
{
121
    struct PPC4xxPCIState *pci = opaque;
122

    
123
#ifdef TARGET_WORDS_BIGENDIAN
124
    value = bswap32(value);
125
#endif
126

    
127
    /* We ignore all target attempts at PCI configuration, effectively
128
     * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
129

    
130
    switch (offset) {
131
    case PCIL0_PMM0LA:
132
        pci->pmm[0].la = value;
133
        break;
134
    case PCIL0_PMM0MA:
135
        pci->pmm[0].ma = value;
136
        break;
137
    case PCIL0_PMM0PCIHA:
138
        pci->pmm[0].pciha = value;
139
        break;
140
    case PCIL0_PMM0PCILA:
141
        pci->pmm[0].pcila = value;
142
        break;
143

    
144
    case PCIL0_PMM1LA:
145
        pci->pmm[1].la = value;
146
        break;
147
    case PCIL0_PMM1MA:
148
        pci->pmm[1].ma = value;
149
        break;
150
    case PCIL0_PMM1PCIHA:
151
        pci->pmm[1].pciha = value;
152
        break;
153
    case PCIL0_PMM1PCILA:
154
        pci->pmm[1].pcila = value;
155
        break;
156

    
157
    case PCIL0_PMM2LA:
158
        pci->pmm[2].la = value;
159
        break;
160
    case PCIL0_PMM2MA:
161
        pci->pmm[2].ma = value;
162
        break;
163
    case PCIL0_PMM2PCIHA:
164
        pci->pmm[2].pciha = value;
165
        break;
166
    case PCIL0_PMM2PCILA:
167
        pci->pmm[2].pcila = value;
168
        break;
169

    
170
    case PCIL0_PTM1MS:
171
        pci->ptm[0].ms = value;
172
        break;
173
    case PCIL0_PTM1LA:
174
        pci->ptm[0].la = value;
175
        break;
176
    case PCIL0_PTM2MS:
177
        pci->ptm[1].ms = value;
178
        break;
179
    case PCIL0_PTM2LA:
180
        pci->ptm[1].la = value;
181
        break;
182

    
183
    default:
184
        printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
185
               (unsigned long)offset);
186
        break;
187
    }
188
}
189

    
190
static uint32_t ppc4xx_pci_reg_read4(void *opaque, target_phys_addr_t offset)
191
{
192
    struct PPC4xxPCIState *pci = opaque;
193
    uint32_t value;
194

    
195
    switch (offset) {
196
    case PCIL0_PMM0LA:
197
        value = pci->pmm[0].la;
198
        break;
199
    case PCIL0_PMM0MA:
200
        value = pci->pmm[0].ma;
201
        break;
202
    case PCIL0_PMM0PCIHA:
203
        value = pci->pmm[0].pciha;
204
        break;
205
    case PCIL0_PMM0PCILA:
206
        value = pci->pmm[0].pcila;
207
        break;
208

    
209
    case PCIL0_PMM1LA:
210
        value = pci->pmm[1].la;
211
        break;
212
    case PCIL0_PMM1MA:
213
        value = pci->pmm[1].ma;
214
        break;
215
    case PCIL0_PMM1PCIHA:
216
        value = pci->pmm[1].pciha;
217
        break;
218
    case PCIL0_PMM1PCILA:
219
        value = pci->pmm[1].pcila;
220
        break;
221

    
222
    case PCIL0_PMM2LA:
223
        value = pci->pmm[2].la;
224
        break;
225
    case PCIL0_PMM2MA:
226
        value = pci->pmm[2].ma;
227
        break;
228
    case PCIL0_PMM2PCIHA:
229
        value = pci->pmm[2].pciha;
230
        break;
231
    case PCIL0_PMM2PCILA:
232
        value = pci->pmm[2].pcila;
233
        break;
234

    
235
    case PCIL0_PTM1MS:
236
        value = pci->ptm[0].ms;
237
        break;
238
    case PCIL0_PTM1LA:
239
        value = pci->ptm[0].la;
240
        break;
241
    case PCIL0_PTM2MS:
242
        value = pci->ptm[1].ms;
243
        break;
244
    case PCIL0_PTM2LA:
245
        value = pci->ptm[1].la;
246
        break;
247

    
248
    default:
249
        printf("%s: invalid PCI internal register 0x%lx\n", __func__,
250
               (unsigned long)offset);
251
        value = 0;
252
    }
253

    
254
#ifdef TARGET_WORDS_BIGENDIAN
255
    value = bswap32(value);
256
#endif
257

    
258
    return value;
259
}
260

    
261
static CPUReadMemoryFunc * const pci_reg_read[] = {
262
    &ppc4xx_pci_reg_read4,
263
    &ppc4xx_pci_reg_read4,
264
    &ppc4xx_pci_reg_read4,
265
};
266

    
267
static CPUWriteMemoryFunc * const pci_reg_write[] = {
268
    &ppc4xx_pci_reg_write4,
269
    &ppc4xx_pci_reg_write4,
270
    &ppc4xx_pci_reg_write4,
271
};
272

    
273
static void ppc4xx_pci_reset(void *opaque)
274
{
275
    struct PPC4xxPCIState *pci = opaque;
276

    
277
    memset(pci->pmm, 0, sizeof(pci->pmm));
278
    memset(pci->ptm, 0, sizeof(pci->ptm));
279
}
280

    
281
/* On Bamboo, all pins from each slot are tied to a single board IRQ. This
282
 * may need further refactoring for other boards. */
283
static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
284
{
285
    int slot = pci_dev->devfn >> 3;
286

    
287
    DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
288
            pci_dev->devfn, irq_num, slot);
289

    
290
    return slot - 1;
291
}
292

    
293
static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
294
{
295
    qemu_irq *pci_irqs = opaque;
296

    
297
    DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
298
    qemu_set_irq(pci_irqs[irq_num], level);
299
}
300

    
301
static void ppc4xx_pci_save(QEMUFile *f, void *opaque)
302
{
303
    PPC4xxPCIState *controller = opaque;
304
    int i;
305

    
306
    pci_device_save(controller->pci_dev, f);
307

    
308
    for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
309
        qemu_put_be32s(f, &controller->pmm[i].la);
310
        qemu_put_be32s(f, &controller->pmm[i].ma);
311
        qemu_put_be32s(f, &controller->pmm[i].pcila);
312
        qemu_put_be32s(f, &controller->pmm[i].pciha);
313
    }
314

    
315
    for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
316
        qemu_put_be32s(f, &controller->ptm[i].ms);
317
        qemu_put_be32s(f, &controller->ptm[i].la);
318
    }
319
}
320

    
321
static int ppc4xx_pci_load(QEMUFile *f, void *opaque, int version_id)
322
{
323
    PPC4xxPCIState *controller = opaque;
324
    int i;
325

    
326
    if (version_id != 1)
327
        return -EINVAL;
328

    
329
    pci_device_load(controller->pci_dev, f);
330

    
331
    for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
332
        qemu_get_be32s(f, &controller->pmm[i].la);
333
        qemu_get_be32s(f, &controller->pmm[i].ma);
334
        qemu_get_be32s(f, &controller->pmm[i].pcila);
335
        qemu_get_be32s(f, &controller->pmm[i].pciha);
336
    }
337

    
338
    for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
339
        qemu_get_be32s(f, &controller->ptm[i].ms);
340
        qemu_get_be32s(f, &controller->ptm[i].la);
341
    }
342

    
343
    return 0;
344
}
345

    
346
/* XXX Interrupt acknowledge cycles not supported. */
347
PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
348
                        target_phys_addr_t config_space,
349
                        target_phys_addr_t int_ack,
350
                        target_phys_addr_t special_cycle,
351
                        target_phys_addr_t registers)
352
{
353
    PPC4xxPCIState *controller;
354
    int index;
355
    static int ppc4xx_pci_id;
356
    uint8_t *pci_conf;
357

    
358
    controller = qemu_mallocz(sizeof(PPC4xxPCIState));
359

    
360
    controller->pci_state.bus = pci_register_bus(NULL, "pci",
361
                                                 ppc4xx_pci_set_irq,
362
                                                 ppc4xx_pci_map_irq,
363
                                                 pci_irqs, 0, 4);
364

    
365
    controller->pci_dev = pci_register_device(controller->pci_state.bus,
366
                                              "host bridge", sizeof(PCIDevice),
367
                                              0, NULL, NULL);
368
    pci_conf = controller->pci_dev->config;
369
    pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
370
    pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_440GX);
371
    pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
372

    
373
    /* CFGADDR */
374
    index = cpu_register_io_memory(pci4xx_cfgaddr_read,
375
                                   pci4xx_cfgaddr_write, controller);
376
    if (index < 0)
377
        goto free;
378
    cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
379

    
380
    /* CFGDATA */
381
    index = pci_host_data_register_mmio(&controller->pci_state, 1);
382
    if (index < 0)
383
        goto free;
384
    cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index);
385

    
386
    /* Internal registers */
387
    index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller);
388
    if (index < 0)
389
        goto free;
390
    cpu_register_physical_memory(registers, PCI_REG_SIZE, index);
391

    
392
    qemu_register_reset(ppc4xx_pci_reset, controller);
393

    
394
    /* XXX load/save code not tested. */
395
    register_savevm(&controller->pci_dev->qdev, "ppc4xx_pci", ppc4xx_pci_id++,
396
                    1, ppc4xx_pci_save, ppc4xx_pci_load, controller);
397

    
398
    return controller->pci_state.bus;
399

    
400
free:
401
    printf("%s error\n", __func__);
402
    qemu_free(controller);
403
    return NULL;
404
}