Commit 825bb581b447831b6bbc21981b1eb8ad27df119d

Authored by aurel32
1 parent e976c6a1

IBM PowerPC 4xx 32-bit PCI controller emulation

This PCI controller can be found on a number of 4xx SoCs, including the 440EP.

Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Acked-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5862 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -679,7 +679,7 @@ OBJS+= heathrow_pic.o grackle_pci.o ppc_oldworld.o
679 679 # NewWorld PowerMac
680 680 OBJS+= unin_pci.o ppc_chrp.o
681 681 # PowerPC 4xx boards
682   -OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc405_uc.o ppc405_boards.o
  682 +OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
683 683 endif
684 684 ifeq ($(TARGET_BASE_ARCH), mips)
685 685 OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
... ...
hw/ppc4xx.h
... ... @@ -25,6 +25,8 @@
25 25 #if !defined(PPC_4XX_H)
26 26 #define PPC_4XX_H
27 27  
  28 +#include "pci.h"
  29 +
28 30 /* PowerPC 4xx core initialization */
29 31 CPUState *ppc4xx_init (const char *cpu_model,
30 32 clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
... ... @@ -46,4 +48,10 @@ enum {
46 48 qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
47 49 uint32_t dcr_base, int has_ssr, int has_vr);
48 50  
  51 +PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
  52 + target_phys_addr_t config_space,
  53 + target_phys_addr_t int_ack,
  54 + target_phys_addr_t special_cycle,
  55 + target_phys_addr_t registers);
  56 +
49 57 #endif /* !defined(PPC_4XX_H) */
... ...
hw/ppc4xx_pci.c 0 → 100644
  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, write to the Free Software
  13 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14 + *
  15 + * Copyright IBM Corp. 2008
  16 + *
  17 + * Authors: Hollis Blanchard <hollisb@us.ibm.com>
  18 + */
  19 +
  20 +/* This file implements emulation of the 32-bit PCI controller found in some
  21 + * 4xx SoCs, such as the 440EP. */
  22 +
  23 +#include "hw.h"
  24 +
  25 +typedef target_phys_addr_t pci_addr_t;
  26 +#include "pci.h"
  27 +#include "pci_host.h"
  28 +#include "bswap.h"
  29 +
  30 +#undef DEBUG
  31 +#ifdef DEBUG
  32 +#define DPRINTF(fmt, ...) do { printf(fmt, ## __VA_ARGS__); } while (0)
  33 +#else
  34 +#define DPRINTF(fmt, args...)
  35 +#endif /* DEBUG */
  36 +
  37 +struct PCIMasterMap {
  38 + uint32_t la;
  39 + uint32_t ma;
  40 + uint32_t pcila;
  41 + uint32_t pciha;
  42 +};
  43 +
  44 +struct PCITargetMap {
  45 + uint32_t ms;
  46 + uint32_t la;
  47 +};
  48 +
  49 +#define PPC4xx_PCI_NR_PMMS 3
  50 +#define PPC4xx_PCI_NR_PTMS 2
  51 +
  52 +struct PPC4xxPCIState {
  53 + struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
  54 + struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
  55 +
  56 + PCIHostState pci_state;
  57 + PCIDevice *pci_dev;
  58 +};
  59 +typedef struct PPC4xxPCIState PPC4xxPCIState;
  60 +
  61 +#define PCIC0_CFGADDR 0x0
  62 +#define PCIC0_CFGDATA 0x4
  63 +
  64 +/* PLB Memory Map (PMM) registers specify which PLB addresses are translated to
  65 + * PCI accesses. */
  66 +#define PCIL0_PMM0LA 0x0
  67 +#define PCIL0_PMM0MA 0x4
  68 +#define PCIL0_PMM0PCILA 0x8
  69 +#define PCIL0_PMM0PCIHA 0xc
  70 +#define PCIL0_PMM1LA 0x10
  71 +#define PCIL0_PMM1MA 0x14
  72 +#define PCIL0_PMM1PCILA 0x18
  73 +#define PCIL0_PMM1PCIHA 0x1c
  74 +#define PCIL0_PMM2LA 0x20
  75 +#define PCIL0_PMM2MA 0x24
  76 +#define PCIL0_PMM2PCILA 0x28
  77 +#define PCIL0_PMM2PCIHA 0x2c
  78 +
  79 +/* PCI Target Map (PTM) registers specify which PCI addresses are translated to
  80 + * PLB accesses. */
  81 +#define PCIL0_PTM1MS 0x30
  82 +#define PCIL0_PTM1LA 0x34
  83 +#define PCIL0_PTM2MS 0x38
  84 +#define PCIL0_PTM2LA 0x3c
  85 +#define PCI_REG_SIZE 0x40
  86 +
  87 +
  88 +static uint32_t pci4xx_cfgaddr_readl(void *opaque, target_phys_addr_t addr)
  89 +{
  90 + PPC4xxPCIState *ppc4xx_pci = opaque;
  91 +
  92 + return ppc4xx_pci->pci_state.config_reg;
  93 +}
  94 +
  95 +static CPUReadMemoryFunc *pci4xx_cfgaddr_read[] = {
  96 + &pci4xx_cfgaddr_readl,
  97 + &pci4xx_cfgaddr_readl,
  98 + &pci4xx_cfgaddr_readl,
  99 +};
  100 +
  101 +static void pci4xx_cfgaddr_writel(void *opaque, target_phys_addr_t addr,
  102 + uint32_t value)
  103 +{
  104 + PPC4xxPCIState *ppc4xx_pci = opaque;
  105 +
  106 +#ifdef TARGET_WORDS_BIGENDIAN
  107 + value = bswap32(value);
  108 +#endif
  109 +
  110 + ppc4xx_pci->pci_state.config_reg = value & ~0x3;
  111 +}
  112 +
  113 +static CPUWriteMemoryFunc *pci4xx_cfgaddr_write[] = {
  114 + &pci4xx_cfgaddr_writel,
  115 + &pci4xx_cfgaddr_writel,
  116 + &pci4xx_cfgaddr_writel,
  117 +};
  118 +
  119 +static CPUReadMemoryFunc *pci4xx_cfgdata_read[] = {
  120 + &pci_host_data_readb,
  121 + &pci_host_data_readw,
  122 + &pci_host_data_readl,
  123 +};
  124 +
  125 +static CPUWriteMemoryFunc *pci4xx_cfgdata_write[] = {
  126 + &pci_host_data_writeb,
  127 + &pci_host_data_writew,
  128 + &pci_host_data_writel,
  129 +};
  130 +
  131 +static void ppc4xx_pci_reg_write4(void *opaque, target_phys_addr_t offset,
  132 + uint32_t value)
  133 +{
  134 + struct PPC4xxPCIState *pci = opaque;
  135 +
  136 +#ifdef TARGET_WORDS_BIGENDIAN
  137 + value = bswap32(value);
  138 +#endif
  139 +
  140 + /* We ignore all target attempts at PCI configuration, effectively
  141 + * assuming a bidirectional 1:1 mapping of PLB and PCI space. */
  142 +
  143 + switch (offset) {
  144 + case PCIL0_PMM0LA:
  145 + pci->pmm[0].la = value;
  146 + break;
  147 + case PCIL0_PMM0MA:
  148 + pci->pmm[0].ma = value;
  149 + break;
  150 + case PCIL0_PMM0PCIHA:
  151 + pci->pmm[0].pciha = value;
  152 + break;
  153 + case PCIL0_PMM0PCILA:
  154 + pci->pmm[0].pcila = value;
  155 + break;
  156 +
  157 + case PCIL0_PMM1LA:
  158 + pci->pmm[1].la = value;
  159 + break;
  160 + case PCIL0_PMM1MA:
  161 + pci->pmm[1].ma = value;
  162 + break;
  163 + case PCIL0_PMM1PCIHA:
  164 + pci->pmm[1].pciha = value;
  165 + break;
  166 + case PCIL0_PMM1PCILA:
  167 + pci->pmm[1].pcila = value;
  168 + break;
  169 +
  170 + case PCIL0_PMM2LA:
  171 + pci->pmm[2].la = value;
  172 + break;
  173 + case PCIL0_PMM2MA:
  174 + pci->pmm[2].ma = value;
  175 + break;
  176 + case PCIL0_PMM2PCIHA:
  177 + pci->pmm[2].pciha = value;
  178 + break;
  179 + case PCIL0_PMM2PCILA:
  180 + pci->pmm[2].pcila = value;
  181 + break;
  182 +
  183 + case PCIL0_PTM1MS:
  184 + pci->ptm[0].ms = value;
  185 + break;
  186 + case PCIL0_PTM1LA:
  187 + pci->ptm[0].la = value;
  188 + break;
  189 + case PCIL0_PTM2MS:
  190 + pci->ptm[1].ms = value;
  191 + break;
  192 + case PCIL0_PTM2LA:
  193 + pci->ptm[1].la = value;
  194 + break;
  195 +
  196 + default:
  197 + printf("%s: unhandled PCI internal register 0x%lx\n", __func__,
  198 + (unsigned long)offset);
  199 + break;
  200 + }
  201 +}
  202 +
  203 +static uint32_t ppc4xx_pci_reg_read4(void *opaque, target_phys_addr_t offset)
  204 +{
  205 + struct PPC4xxPCIState *pci = opaque;
  206 + uint32_t value;
  207 +
  208 + switch (offset) {
  209 + case PCIL0_PMM0LA:
  210 + value = pci->pmm[0].la;
  211 + break;
  212 + case PCIL0_PMM0MA:
  213 + value = pci->pmm[0].ma;
  214 + break;
  215 + case PCIL0_PMM0PCIHA:
  216 + value = pci->pmm[0].pciha;
  217 + break;
  218 + case PCIL0_PMM0PCILA:
  219 + value = pci->pmm[0].pcila;
  220 + break;
  221 +
  222 + case PCIL0_PMM1LA:
  223 + value = pci->pmm[1].la;
  224 + break;
  225 + case PCIL0_PMM1MA:
  226 + value = pci->pmm[1].ma;
  227 + break;
  228 + case PCIL0_PMM1PCIHA:
  229 + value = pci->pmm[1].pciha;
  230 + break;
  231 + case PCIL0_PMM1PCILA:
  232 + value = pci->pmm[1].pcila;
  233 + break;
  234 +
  235 + case PCIL0_PMM2LA:
  236 + value = pci->pmm[2].la;
  237 + break;
  238 + case PCIL0_PMM2MA:
  239 + value = pci->pmm[2].ma;
  240 + break;
  241 + case PCIL0_PMM2PCIHA:
  242 + value = pci->pmm[2].pciha;
  243 + break;
  244 + case PCIL0_PMM2PCILA:
  245 + value = pci->pmm[2].pcila;
  246 + break;
  247 +
  248 + case PCIL0_PTM1MS:
  249 + value = pci->ptm[0].ms;
  250 + break;
  251 + case PCIL0_PTM1LA:
  252 + value = pci->ptm[0].la;
  253 + break;
  254 + case PCIL0_PTM2MS:
  255 + value = pci->ptm[1].ms;
  256 + break;
  257 + case PCIL0_PTM2LA:
  258 + value = pci->ptm[1].la;
  259 + break;
  260 +
  261 + default:
  262 + printf("%s: invalid PCI internal register 0x%lx\n", __func__,
  263 + (unsigned long)offset);
  264 + value = 0;
  265 + }
  266 +
  267 +#ifdef TARGET_WORDS_BIGENDIAN
  268 + value = bswap32(value);
  269 +#endif
  270 +
  271 + return value;
  272 +}
  273 +
  274 +static CPUReadMemoryFunc *pci_reg_read[] = {
  275 + &ppc4xx_pci_reg_read4,
  276 + &ppc4xx_pci_reg_read4,
  277 + &ppc4xx_pci_reg_read4,
  278 +};
  279 +
  280 +static CPUWriteMemoryFunc *pci_reg_write[] = {
  281 + &ppc4xx_pci_reg_write4,
  282 + &ppc4xx_pci_reg_write4,
  283 + &ppc4xx_pci_reg_write4,
  284 +};
  285 +
  286 +static void ppc4xx_pci_reset(void *opaque)
  287 +{
  288 + struct PPC4xxPCIState *pci = opaque;
  289 +
  290 + memset(pci->pmm, 0, sizeof(pci->pmm));
  291 + memset(pci->ptm, 0, sizeof(pci->ptm));
  292 +}
  293 +
  294 +/* On Bamboo, all pins from each slot are tied to a single board IRQ. This
  295 + * may need further refactoring for other boards. */
  296 +static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
  297 +{
  298 + int slot = pci_dev->devfn >> 3;
  299 +
  300 + DPRINTF("%s: devfn %x irq %d -> %d\n", __func__,
  301 + pci_dev->devfn, irq_num, slot);
  302 +
  303 + return slot - 1;
  304 +}
  305 +
  306 +static void ppc4xx_pci_set_irq(qemu_irq *pci_irqs, int irq_num, int level)
  307 +{
  308 + DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
  309 + qemu_set_irq(pci_irqs[irq_num], level);
  310 +}
  311 +
  312 +static void ppc4xx_pci_save(QEMUFile *f, void *opaque)
  313 +{
  314 + PPC4xxPCIState *controller = opaque;
  315 + int i;
  316 +
  317 + pci_device_save(&controller->pci_dev, f);
  318 +
  319 + for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
  320 + qemu_put_be32s(f, &controller->pmm[i].la);
  321 + qemu_put_be32s(f, &controller->pmm[i].ma);
  322 + qemu_put_be32s(f, &controller->pmm[i].pcila);
  323 + qemu_put_be32s(f, &controller->pmm[i].pciha);
  324 + }
  325 +
  326 + for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
  327 + qemu_put_be32s(f, &controller->ptm[i].ms);
  328 + qemu_put_be32s(f, &controller->ptm[i].la);
  329 + }
  330 +}
  331 +
  332 +static int ppc4xx_pci_load(QEMUFile *f, void *opaque, int version_id)
  333 +{
  334 + PPC4xxPCIState *controller = opaque;
  335 + int i;
  336 +
  337 + if (version_id != 1)
  338 + return -EINVAL;
  339 +
  340 + pci_device_load(&controller->pci_dev, f);
  341 +
  342 + for (i = 0; i < PPC4xx_PCI_NR_PMMS; i++) {
  343 + qemu_get_be32s(f, &controller->pmm[i].la);
  344 + qemu_get_be32s(f, &controller->pmm[i].ma);
  345 + qemu_get_be32s(f, &controller->pmm[i].pcila);
  346 + qemu_get_be32s(f, &controller->pmm[i].pciha);
  347 + }
  348 +
  349 + for (i = 0; i < PPC4xx_PCI_NR_PTMS; i++) {
  350 + qemu_get_be32s(f, &controller->ptm[i].ms);
  351 + qemu_get_be32s(f, &controller->ptm[i].la);
  352 + }
  353 +
  354 + return 0;
  355 +}
  356 +
  357 +/* XXX Interrupt acknowledge cycles not supported. */
  358 +PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
  359 + target_phys_addr_t config_space,
  360 + target_phys_addr_t int_ack,
  361 + target_phys_addr_t special_cycle,
  362 + target_phys_addr_t registers)
  363 +{
  364 + PPC4xxPCIState *controller;
  365 + int index;
  366 + static int ppc4xx_pci_id;
  367 +
  368 + controller = qemu_mallocz(sizeof(PPC4xxPCIState));
  369 + if (!controller)
  370 + return NULL;
  371 +
  372 + controller->pci_state.bus = pci_register_bus(ppc4xx_pci_set_irq,
  373 + ppc4xx_pci_map_irq,
  374 + pci_irqs, 0, 4);
  375 +
  376 + controller->pci_dev = pci_register_device(controller->pci_state.bus,
  377 + "host bridge", sizeof(PCIDevice),
  378 + 0, NULL, NULL);
  379 + controller->pci_dev->config[0x00] = 0x14; // vendor_id
  380 + controller->pci_dev->config[0x01] = 0x10;
  381 + controller->pci_dev->config[0x02] = 0x7f; // device_id
  382 + controller->pci_dev->config[0x03] = 0x02;
  383 + controller->pci_dev->config[0x0a] = 0x80; // class_sub = other bridge type
  384 + controller->pci_dev->config[0x0b] = 0x06; // class_base = PCI_bridge
  385 +
  386 + /* CFGADDR */
  387 + index = cpu_register_io_memory(0, pci4xx_cfgaddr_read,
  388 + pci4xx_cfgaddr_write, controller);
  389 + if (index < 0)
  390 + goto free;
  391 + cpu_register_physical_memory(config_space + PCIC0_CFGADDR, 4, index);
  392 +
  393 + /* CFGDATA */
  394 + index = cpu_register_io_memory(0, pci4xx_cfgdata_read,
  395 + pci4xx_cfgdata_write,
  396 + &controller->pci_state);
  397 + if (index < 0)
  398 + goto free;
  399 + cpu_register_physical_memory(config_space + PCIC0_CFGDATA, 4, index);
  400 +
  401 + /* Internal registers */
  402 + index = cpu_register_io_memory(0, pci_reg_read, pci_reg_write, controller);
  403 + if (index < 0)
  404 + goto free;
  405 + cpu_register_physical_memory(registers, PCI_REG_SIZE, index);
  406 +
  407 + qemu_register_reset(ppc4xx_pci_reset, controller);
  408 +
  409 + /* XXX load/save code not tested. */
  410 + register_savevm("ppc4xx_pci", ppc4xx_pci_id++, 1,
  411 + ppc4xx_pci_save, ppc4xx_pci_load, controller);
  412 +
  413 + return controller->pci_state.bus;
  414 +
  415 +free:
  416 + printf("%s error\n", __func__);
  417 + qemu_free(controller);
  418 + return NULL;
  419 +}
... ...