]> Git Repo - qemu.git/blob - hw/ppc4xx_pci.c
ppc4xx_pci: Declare as little endian
[qemu.git] / hw / ppc4xx_pci.c
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 <[email protected]>
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
28 #undef DEBUG
29 #ifdef DEBUG
30 #define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
31 #else
32 #define DPRINTF(fmt, ...)
33 #endif /* DEBUG */
34
35 struct PCIMasterMap {
36     uint32_t la;
37     uint32_t ma;
38     uint32_t pcila;
39     uint32_t pciha;
40 };
41
42 struct PCITargetMap {
43     uint32_t ms;
44     uint32_t la;
45 };
46
47 #define PPC4xx_PCI_NR_PMMS 3
48 #define PPC4xx_PCI_NR_PTMS 2
49
50 struct PPC4xxPCIState {
51     struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
52     struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
53
54     PCIHostState pci_state;
55     PCIDevice *pci_dev;
56 };
57 typedef struct PPC4xxPCIState PPC4xxPCIState;
58
59 #define PCIC0_CFGADDR       0x0
60 #define PCIC0_CFGDATA       0x4
61
62 /* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
63  * PCI accesses. */
64 #define PCIL0_PMM0LA        0x0
65 #define PCIL0_PMM0MA        0x4
66 #define PCIL0_PMM0PCILA     0x8
67 #define PCIL0_PMM0PCIHA     0xc
68 #define PCIL0_PMM1LA        0x10
69 #define PCIL0_PMM1MA        0x14
70 #define PCIL0_PMM1PCILA     0x18
71 #define PCIL0_PMM1PCIHA     0x1c
72 #define PCIL0_PMM2LA        0x20
73 #define PCIL0_PMM2MA        0x24
74 #define PCIL0_PMM2PCILA     0x28
75 #define PCIL0_PMM2PCIHA     0x2c
76
77 /* PCI Target Map (PTM) registers specify which PCI addresses are translated to
78  * PLB accesses. */
79 #define PCIL0_PTM1MS        0x30
80 #define PCIL0_PTM1LA        0x34
81 #define PCIL0_PTM2MS        0x38
82 #define PCIL0_PTM2LA        0x3c
83 #define PCI_REG_SIZE        0x40
84
85
86 static uint32_t pci4xx_cfgaddr_readl(void *opaque, target_phys_addr_t addr)
87 {
88     PPC4xxPCIState *ppc4xx_pci = opaque;
89
90     return ppc4xx_pci->pci_state.config_reg;
91 }
92
93 static CPUReadMemoryFunc * const pci4xx_cfgaddr_read[] = {
94     &pci4xx_cfgaddr_readl,
95     &pci4xx_cfgaddr_readl,
96     &pci4xx_cfgaddr_readl,
97 };
98
99 static void pci4xx_cfgaddr_writel(void *opaque, target_phys_addr_t addr,
100                                   uint32_t value)
101 {
102     PPC4xxPCIState *ppc4xx_pci = opaque;
103
104     ppc4xx_pci->pci_state.config_reg = value & ~0x3;
105 }
106
107 static CPUWriteMemoryFunc * const pci4xx_cfgaddr_write[] = {
108     &pci4xx_cfgaddr_writel,
109     &pci4xx_cfgaddr_writel,
110     &pci4xx_cfgaddr_writel,
111 };
112
113 static void ppc4xx_pci_reg_write4(void *opaque, target_phys_addr_t offset,
114                                   uint32_t value)
115 {
116     struct PPC4xxPCIState *pci = opaque;
117
118     /* We ignore all target attempts at PCI configuration, effectively
119      * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
120
121     switch (offset) {
122     case PCIL0_PMM0LA:
123         pci->pmm[0].la = value;
124         break;
125     case PCIL0_PMM0MA:
126         pci->pmm[0].ma = value;
127         break;
128     case PCIL0_PMM0PCIHA:
129         pci->pmm[0].pciha = value;
130         break;
131     case PCIL0_PMM0PCILA:
132         pci->pmm[0].pcila = value;
133         break;
134
135     case PCIL0_PMM1LA:
136         pci->pmm[1].la = value;
137         break;
138     case PCIL0_PMM1MA:
139         pci->pmm[1].ma = value;
140         break;
141     case PCIL0_PMM1PCIHA:
142         pci->pmm[1].pciha = value;
143         break;
144     case PCIL0_PMM1PCILA:
145         pci->pmm[1].pcila = value;
146         break;
147
148     case PCIL0_PMM2LA:
149         pci->pmm[2].la = value;
150         break;
151     case PCIL0_PMM2MA:
152         pci->pmm[2].ma = value;
153         break;
154     case PCIL0_PMM2PCIHA:
155         pci->pmm[2].pciha = value;
156         break;
157     case PCIL0_PMM2PCILA:
158         pci->pmm[2].pcila = value;
159         break;
160
161     case PCIL0_PTM1MS:
162         pci->ptm[0].ms = value;
163         break;
164     case PCIL0_PTM1LA:
165         pci->ptm[0].la = value;
166         break;
167     case PCIL0_PTM2MS:
168         pci->ptm[1].ms = value;
169         break;
170     case PCIL0_PTM2LA:
171         pci->ptm[1].la = value;
172         break;
173
174     default:
175         printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
176                (unsigned long)offset);
177         break;
178     }
179 }
180
181 static uint32_t ppc4xx_pci_reg_read4(void *opaque, target_phys_addr_t offset)
182 {
183     struct PPC4xxPCIState *pci = opaque;
184     uint32_t value;
185
186     switch (offset) {
187     case PCIL0_PMM0LA:
188         value = pci->pmm[0].la;
189         break;
190     case PCIL0_PMM0MA:
191         value = pci->pmm[0].ma;
192         break;
193     case PCIL0_PMM0PCIHA:
194         value = pci->pmm[0].pciha;
195         break;
196     case PCIL0_PMM0PCILA:
197         value = pci->pmm[0].pcila;
198         break;
199
200     case PCIL0_PMM1LA:
201         value = pci->pmm[1].la;
202         break;
203     case PCIL0_PMM1MA:
204         value = pci->pmm[1].ma;
205         break;
206     case PCIL0_PMM1PCIHA:
207         value = pci->pmm[1].pciha;
208         break;
209     case PCIL0_PMM1PCILA:
210         value = pci->pmm[1].pcila;
211         break;
212
213     case PCIL0_PMM2LA:
214         value = pci->pmm[2].la;
215         break;
216     case PCIL0_PMM2MA:
217         value = pci->pmm[2].ma;
218         break;
219     case PCIL0_PMM2PCIHA:
220         value = pci->pmm[2].pciha;
221         break;
222     case PCIL0_PMM2PCILA:
223         value = pci->pmm[2].pcila;
224         break;
225
226     case PCIL0_PTM1MS:
227         value = pci->ptm[0].ms;
228         break;
229     case PCIL0_PTM1LA:
230         value = pci->ptm[0].la;
231         break;
232     case PCIL0_PTM2MS:
233         value = pci->ptm[1].ms;
234         break;
235     case PCIL0_PTM2LA:
236         value = pci->ptm[1].la;
237         break;
238
239     default:
240         printf("%s: invalid PCI internal register 0x%lx\n", __func__,
241                (unsigned long)offset);
242         value = 0;
243     }
244
245     return value;
246 }
247
248 static CPUReadMemoryFunc * const pci_reg_read[] = {
249     &ppc4xx_pci_reg_read4,
250     &ppc4xx_pci_reg_read4,
251     &ppc4xx_pci_reg_read4,
252 };
253
254 static CPUWriteMemoryFunc * const pci_reg_write[] = {
255     &ppc4xx_pci_reg_write4,
256     &ppc4xx_pci_reg_write4,
257     &ppc4xx_pci_reg_write4,
258 };
259
260 static void ppc4xx_pci_reset(void *opaque)
261 {
262     struct PPC4xxPCIState *pci = opaque;
263
264     memset(pci->pmm, 0, sizeof(pci->pmm));
265     memset(pci->ptm, 0, sizeof(pci->ptm));
266 }
267
268 /* On Bamboo, all pins from each slot are tied to a single board IRQ. This
269  * may need further refactoring for other boards. */
270 static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
271 {
272     int slot = pci_dev->devfn >> 3;
273
274     DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
275             pci_dev->devfn, irq_num, slot);
276
277     return slot - 1;
278 }
279
280 static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
281 {
282     qemu_irq *pci_irqs = opaque;
283
284     DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
285     qemu_set_irq(pci_irqs[irq_num], level);
286 }
287
288 static void ppc4xx_pci_save(QEMUFile *f, void *opaque)
289 {
290     PPC4xxPCIState *controller = opaque;
291     int i;
292
293     pci_device_save(controller->pci_dev, f);
294
295     for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
296         qemu_put_be32s(f, &controller->pmm[i].la);
297         qemu_put_be32s(f, &controller->pmm[i].ma);
298         qemu_put_be32s(f, &controller->pmm[i].pcila);
299         qemu_put_be32s(f, &controller->pmm[i].pciha);
300     }
301
302     for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
303         qemu_put_be32s(f, &controller->ptm[i].ms);
304         qemu_put_be32s(f, &controller->ptm[i].la);
305     }
306 }
307
308 static int ppc4xx_pci_load(QEMUFile *f, void *opaque, int version_id)
309 {
310     PPC4xxPCIState *controller = opaque;
311     int i;
312
313     if (version_id != 1)
314         return -EINVAL;
315
316     pci_device_load(controller->pci_dev, f);
317
318     for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
319         qemu_get_be32s(f, &controller->pmm[i].la);
320         qemu_get_be32s(f, &controller->pmm[i].ma);
321         qemu_get_be32s(f, &controller->pmm[i].pcila);
322         qemu_get_be32s(f, &controller->pmm[i].pciha);
323     }
324
325     for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
326         qemu_get_be32s(f, &controller->ptm[i].ms);
327         qemu_get_be32s(f, &controller->ptm[i].la);
328     }
329
330     return 0;
331 }
332
333 /* XXX Interrupt acknowledge cycles not supported. */
334 PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
335                         target_phys_addr_t config_space,
336                         target_phys_addr_t int_ack,
337                         target_phys_addr_t special_cycle,
338                         target_phys_addr_t registers)
339 {
340     PPC4xxPCIState *controller;
341     int index;
342     static int ppc4xx_pci_id;
343     uint8_t *pci_conf;
344
345     controller = qemu_mallocz(sizeof(PPC4xxPCIState));
346
347     controller->pci_state.bus = pci_register_bus(NULL, "pci",
348                                                  ppc4xx_pci_set_irq,
349                                                  ppc4xx_pci_map_irq,
350                                                  pci_irqs, 0, 4);
351
352     controller->pci_dev = pci_register_device(controller->pci_state.bus,
353                                               "host bridge", sizeof(PCIDevice),
354                                               0, NULL, NULL);
355     pci_conf = controller->pci_dev->config;
356     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
357     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_440GX);
358     pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
359
360     /* CFGADDR */
361     index = cpu_register_io_memory(pci4xx_cfgaddr_read,
362                                    pci4xx_cfgaddr_write, controller,
363                                    DEVICE_LITTLE_ENDIAN);
364     if (index < 0)
365         goto free;
366     cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
367
368     /* CFGDATA */
369     index = pci_host_data_register_mmio(&controller->pci_state, 1);
370     if (index < 0)
371         goto free;
372     cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index);
373
374     /* Internal registers */
375     index = cpu_register_io_memory(pci_reg_read, pci_reg_write, controller,
376                                    DEVICE_LITTLE_ENDIAN);
377     if (index < 0)
378         goto free;
379     cpu_register_physical_memory(registers, PCI_REG_SIZE, index);
380
381     qemu_register_reset(ppc4xx_pci_reset, controller);
382
383     /* XXX load/save code not tested. */
384     register_savevm(&controller->pci_dev->qdev, "ppc4xx_pci", ppc4xx_pci_id++,
385                     1, ppc4xx_pci_save, ppc4xx_pci_load, controller);
386
387     return controller->pci_state.bus;
388
389 free:
390     printf("%s error\n", __func__);
391     qemu_free(controller);
392     return NULL;
393 }
This page took 0.046507 seconds and 4 git commands to generate.