qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Liu Yu <yu.liu@freescale.com>
To: qemu-devel@nongnu.org
Cc: Liu Yu <yu.liu@freescale.com>, kvm-ppc@vger.kernel.org
Subject: [Qemu-devel] [PATCH 5/9] powerpc/kvm: Add freescale pci controller's support
Date: Thu, 15 Jan 2009 20:34:13 +0800	[thread overview]
Message-ID: <1232022857-2315-6-git-send-email-yu.liu@freescale.com> (raw)
In-Reply-To: <1232022857-2315-5-git-send-email-yu.liu@freescale.com>

Signed-off-by: Liu Yu <yu.liu@freescale.com>
---
 Makefile.target  |    2 +
 hw/ppce500_pci.c |  369 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 371 insertions(+), 0 deletions(-)
 create mode 100644 hw/ppce500_pci.c

diff --git a/Makefile.target b/Makefile.target
index 58fe88f..2079fcb 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -649,6 +649,8 @@ OBJS+= unin_pci.o ppc_chrp.o
 # PowerPC 4xx boards
 OBJS+= pflash_cfi02.o ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 OBJS+= ppc440.o ppc440_bamboo.o
+# PowerPC E500 boards
+OBJS+= ppce500_pci.o
 ifdef FDT_LIBS
 OBJS+= device_tree.o
 LIBS+= $(FDT_LIBS)
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
new file mode 100644
index 0000000..9077591
--- /dev/null
+++ b/hw/ppce500_pci.c
@@ -0,0 +1,369 @@
+/*
+ * QEMU PowerPC E500 embedded processors pci controller emulation
+ *
+ * Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Yu Liu,     <yu.liu@freescale.com>
+ *
+ * This file is derived from hw/ppc4xx_pci.c,
+ * the copyright for that material belongs to the original owners.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of  the GNU General  Public License as published by
+ * the Free Software Foundation;  either version 2 of the  License, or
+ * (at your option) any later version.
+ */
+
+#include "hw.h"
+#include "ppc.h"
+#include "ppce500.h"
+typedef target_phys_addr_t pci_addr_t;
+#include "pci.h"
+#include "pci_host.h"
+#include "bswap.h"
+#include "qemu-log.h"
+
+#ifdef DEBUG_PCI
+#define pci_debug(fmt, arg...) fprintf(stderr, fmt, ##arg)
+#else
+#define pci_debug(fmt, arg...)
+#endif
+
+#define PCIE500_CFGADDR       0x0
+#define PCIE500_CFGDATA       0x4
+#define PCIE500_REG_BASE      0xC00
+#define PCIE500_REG_SIZE      (0x1000 - PCIE500_REG_BASE)
+
+#define PPCE500_PCI_CONFIG_ADDR		0x0
+#define PPCE500_PCI_CONFIG_DATA		0x4
+#define PPCE500_PCI_INTACK		0x8
+
+#define PPCE500_PCI_OW1			(0xC20 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW2			(0xC40 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW3			(0xC60 - PCIE500_REG_BASE)
+#define PPCE500_PCI_OW4			(0xC80 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW3			(0xDA0 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW2			(0xDC0 - PCIE500_REG_BASE)
+#define PPCE500_PCI_IW1			(0xDE0 - PCIE500_REG_BASE)
+
+#define PPCE500_PCI_GASKET_TIMR		(0xE20 - PCIE500_REG_BASE)
+
+#define PCI_POTAR		0x0
+#define PCI_POTEAR		0x4
+#define PCI_POWBAR		0x8
+#define PCI_POWAR		0x10
+
+#define PCI_PITAR		0x0
+#define PCI_PIWBAR		0x8
+#define PCI_PIWBEAR		0xC
+#define PCI_PIWAR		0x10
+
+#define PPCE500_PCI_NR_POBS 5
+#define PPCE500_PCI_NR_PIBS 3
+
+struct  pci_outbound {
+    uint32_t potar;
+    uint32_t potear;
+    uint32_t powbar;
+    uint32_t powar;
+};
+
+struct pci_inbound {
+    uint32_t pitar;
+    uint32_t piwbar;
+    uint32_t piwbear;
+    uint32_t piwar;
+};
+
+struct PPCE500PCIState {
+    struct pci_outbound pob[PPCE500_PCI_NR_POBS];
+    struct pci_inbound pib[PPCE500_PCI_NR_PIBS];
+    uint32_t gasket_time;
+    PCIHostState pci_state;
+    PCIDevice *pci_dev;
+};
+
+typedef struct PPCE500PCIState PPCE500PCIState;
+
+static uint32_t pcie500_cfgaddr_readl(void *opaque, target_phys_addr_t addr)
+{
+    PPCE500PCIState *pci = opaque;
+
+    pci_debug("%s: (addr:%Lx) -> value:%x\n", __func__, addr,
+		    pci->pci_state.config_reg);
+    return pci->pci_state.config_reg;
+}
+
+static CPUReadMemoryFunc *pcie500_cfgaddr_read[] = {
+    &pcie500_cfgaddr_readl,
+    &pcie500_cfgaddr_readl,
+    &pcie500_cfgaddr_readl,
+};
+
+static void pcie500_cfgaddr_writel(void *opaque, target_phys_addr_t addr,
+                                  uint32_t value)
+{
+    PPCE500PCIState *controller = opaque;
+
+    pci_debug("%s: value:%x -> (addr%Lx)\n", __func__, value, addr);
+    controller->pci_state.config_reg = value & ~0x3;
+}
+
+static CPUWriteMemoryFunc *pcie500_cfgaddr_write[] = {
+    pcie500_cfgaddr_writel,
+    &pcie500_cfgaddr_writel,
+    &pcie500_cfgaddr_writel,
+};
+
+static CPUReadMemoryFunc *pcie500_cfgdata_read[] = {
+    &pci_host_data_readb,
+    &pci_host_data_readw,
+    &pci_host_data_readl,
+};
+
+static CPUWriteMemoryFunc *pcie500_cfgdata_write[] = {
+    &pci_host_data_writeb,
+    &pci_host_data_writew,
+    &pci_host_data_writel,
+};
+
+static uint32_t pci_reg_read4(void *opaque, target_phys_addr_t addr)
+{
+    PPCE500PCIState *pci = opaque;
+    unsigned long win;
+    uint32_t value = 0;
+
+    win = addr & 0xfe0;
+
+    switch (win) {
+    case PPCE500_PCI_OW1:
+    case PPCE500_PCI_OW2:
+    case PPCE500_PCI_OW3:
+    case PPCE500_PCI_OW4:
+	switch (addr & 0xC) {
+	case PCI_POTAR: value = pci->pob[(addr >> 5) & 0x7].potar; break;
+	case PCI_POTEAR: value = pci->pob[(addr >> 5) & 0x7].potear; break;
+	case PCI_POWBAR: value = pci->pob[(addr >> 5) & 0x7].powbar; break;
+	case PCI_POWAR: value = pci->pob[(addr >> 5) & 0x7].powar; break;
+	default: break;
+	}
+	break;
+
+    case PPCE500_PCI_IW3:
+    case PPCE500_PCI_IW2:
+    case PPCE500_PCI_IW1:
+	switch (addr & 0xC) {
+	case PCI_PITAR: value = pci->pib[(addr >> 5) & 0x3].pitar; break;
+	case PCI_PIWBAR: value = pci->pib[(addr >> 5) & 0x3].piwbar; break;
+	case PCI_PIWBEAR: value = pci->pib[(addr >> 5) & 0x3].piwbear; break;
+	case PCI_PIWAR: value = pci->pib[(addr >> 5) & 0x3].piwar; break;
+	default: break;
+	};
+	break;
+
+    case PPCE500_PCI_GASKET_TIMR:
+	value = pci->gasket_time;
+	break;
+
+    default:
+	break;
+    }
+
+    pci_debug("%s: win:%lx(addr:%Lx) -> value:%x\n",__func__,win,addr,value);
+    return value;
+}
+
+static CPUReadMemoryFunc *e500_pci_reg_read[] = {
+    &pci_reg_read4,
+    &pci_reg_read4,
+    &pci_reg_read4,
+};
+
+static void pci_reg_write4(void *opaque, target_phys_addr_t addr,
+                               uint32_t value)
+{
+    PPCE500PCIState *pci = opaque;
+    unsigned long win;
+
+    win = addr & 0xfe0;
+
+    pci_debug("%s: value:%x -> win:%lx(addr:%Lx)\n",__func__,value,win,addr);
+
+    switch (win) {
+    case PPCE500_PCI_OW1:
+    case PPCE500_PCI_OW2:
+    case PPCE500_PCI_OW3:
+    case PPCE500_PCI_OW4:
+	switch (addr & 0xC) {
+	case PCI_POTAR: pci->pob[(addr >> 5) & 0x7].potar = value; break;
+	case PCI_POTEAR: pci->pob[(addr >> 5) & 0x7].potear = value; break;
+	case PCI_POWBAR: pci->pob[(addr >> 5) & 0x7].powbar = value; break;
+	case PCI_POWAR: pci->pob[(addr >> 5) & 0x7].powar = value; break;
+	default: break;
+	};
+	break;
+
+    case PPCE500_PCI_IW3:
+    case PPCE500_PCI_IW2:
+    case PPCE500_PCI_IW1:
+	switch (addr & 0xC) {
+	case PCI_PITAR: pci->pib[(addr >> 5) & 0x3].pitar = value; break;
+	case PCI_PIWBAR: pci->pib[(addr >> 5) & 0x3].piwbar = value; break;
+	case PCI_PIWBEAR: pci->pib[(addr >> 5) & 0x3].piwbear = value; break;
+	case PCI_PIWAR: pci->pib[(addr >> 5) & 0x3].piwar = value; break;
+	default: break;
+	};
+	break;
+
+    case PPCE500_PCI_GASKET_TIMR:
+	pci->gasket_time = value;
+	break;
+
+    default:
+	break;
+    };
+}
+
+static CPUWriteMemoryFunc *e500_pci_reg_write[] = {
+    &pci_reg_write4,
+    &pci_reg_write4,
+    &pci_reg_write4,
+};
+
+static int mpc85xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+    int devno = pci_dev->devfn >> 3, ret = 0;
+
+    switch (devno) {
+	/* Two PCI slot */
+	case 0x11:
+	case 0x12:
+	    ret = (irq_num + devno - 0x10) % 4;
+	    break;
+	default:
+	    printf("Error:%s:unknow dev number\n", __func__);
+    }
+
+    pci_debug("%s: devfn %x irq %d -> %d  devno:%x\n", __func__,
+           pci_dev->devfn, irq_num, ret, devno);
+
+    return ret;
+}
+
+static void mpc85xx_pci_set_irq(qemu_irq *pic, int irq_num, int level)
+{
+    pci_debug("%s: PCI irq %d, level:%d\n", __func__, irq_num, level);
+
+    qemu_set_irq(pic[irq_num], level);
+}
+
+static void ppce500_pci_save(QEMUFile *f, void *opaque)
+{
+    PPCE500PCIState *controller = opaque;
+    int i;
+
+    pci_device_save(controller->pci_dev, f);
+
+    for (i = 0; i < PPCE500_PCI_NR_POBS; i++) {
+        qemu_put_be32s(f, &controller->pob[i].potar);
+        qemu_put_be32s(f, &controller->pob[i].potear);
+        qemu_put_be32s(f, &controller->pob[i].powbar);
+        qemu_put_be32s(f, &controller->pob[i].powar);
+    }
+
+    for (i = 0; i < PPCE500_PCI_NR_PIBS; i++) {
+        qemu_put_be32s(f, &controller->pib[i].pitar);
+        qemu_put_be32s(f, &controller->pib[i].piwbar);
+        qemu_put_be32s(f, &controller->pib[i].piwbear);
+        qemu_put_be32s(f, &controller->pib[i].piwar);
+    }
+    qemu_put_be32s(f, &controller->gasket_time);
+}
+
+static int ppce500_pci_load(QEMUFile *f, void *opaque, int version_id)
+{
+    PPCE500PCIState *controller = opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    pci_device_load(controller->pci_dev, f);
+
+    for (i = 0; i < PPCE500_PCI_NR_POBS; i++) {
+        qemu_get_be32s(f, &controller->pob[i].potar);
+        qemu_get_be32s(f, &controller->pob[i].potear);
+        qemu_get_be32s(f, &controller->pob[i].powbar);
+        qemu_get_be32s(f, &controller->pob[i].powar);
+    }
+
+    for (i = 0; i < PPCE500_PCI_NR_PIBS; i++) {
+        qemu_get_be32s(f, &controller->pib[i].pitar);
+        qemu_get_be32s(f, &controller->pib[i].piwbar);
+        qemu_get_be32s(f, &controller->pib[i].piwbear);
+        qemu_get_be32s(f, &controller->pib[i].piwar);
+    }
+    qemu_get_be32s(f, &controller->gasket_time);
+
+    return 0;
+}
+PCIBus *ppce500_pci_init(qemu_irq pci_irqs[4], target_phys_addr_t registers)
+{
+    PPCE500PCIState *controller;
+    PCIDevice *d;
+    int index;
+    static int ppce500_pci_id;
+
+    controller = qemu_mallocz(sizeof(PPCE500PCIState));
+    if (!controller)
+	return NULL;
+
+    controller->pci_state.bus = pci_register_bus(mpc85xx_pci_set_irq,
+                                                 mpc85xx_pci_map_irq,
+                                                 pci_irqs, 0x88, 4);
+    d = pci_register_device(controller->pci_state.bus,
+                            "host bridge", sizeof(PCIDevice),
+                            0, NULL, NULL);
+
+    d->config[0x00] = 0x57; // vendor_id
+    d->config[0x01] = 0x19;
+    d->config[0x02] = 0x30; // device_id
+    d->config[0x03] = 0x00;
+    d->config[0x0a] = 0x20; // class_sub = other bridge type
+    d->config[0x0b] = 0x0B; // class_base = PCI_bridge
+
+    controller->pci_dev = d;
+
+    /* CFGADDR */
+    index = cpu_register_io_memory(0, pcie500_cfgaddr_read,
+                                   pcie500_cfgaddr_write, controller);
+    if (index < 0)
+        goto free;
+    cpu_register_physical_memory(registers + PCIE500_CFGADDR, 4, index);
+
+    /* CFGDATA */
+    index = cpu_register_io_memory(0, pcie500_cfgdata_read,
+                                   pcie500_cfgdata_write,
+                                   &controller->pci_state);
+    if (index < 0)
+        goto free;
+    cpu_register_physical_memory(registers + PCIE500_CFGDATA, 4, index);
+
+    index = cpu_register_io_memory(0, e500_pci_reg_read,
+		                   e500_pci_reg_write, controller);
+    if (index < 0)
+	goto free;
+    cpu_register_physical_memory(registers + PCIE500_REG_BASE,
+                                   PCIE500_REG_SIZE, index);
+
+    /* XXX load/save code not tested. */
+    register_savevm("ppce500_pci", ppce500_pci_id++, 1,
+                    ppce500_pci_save, ppce500_pci_load, controller);
+
+    return controller->pci_state.bus;
+
+free:
+    printf("%s error\n", __func__);
+    qemu_free(controller);
+    return NULL;
+}
-- 
1.5.4

  reply	other threads:[~2009-01-15 12:43 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-15 12:34 [Qemu-devel] [PATCH 0/9] powerpc/kvm: Add MPC85xx platform support Liu Yu
2009-01-15 12:34 ` [Qemu-devel] [PATCH 1/9] powerpc/kvm: Fix a uninitialized bug Liu Yu
2009-01-15 12:34   ` [Qemu-devel] [PATCH 2/9] powerpc/kvm: fix a openpic bug Liu Yu
2009-01-15 12:34     ` [Qemu-devel] [PATCH 3/9] powerpc/kvm: Enable mpic for E500 platform Liu Yu
2009-01-15 12:34       ` [Qemu-devel] [PATCH 4/9] powerpc/kvm: enable POWERPC_MMU_BOOKE_FSL when kvm is enabled Liu Yu
2009-01-15 12:34         ` Liu Yu [this message]
2009-01-15 12:34           ` [Qemu-devel] [PATCH 6/9] powerpc/kvm: Add E500 irq support Liu Yu
2009-01-15 12:34             ` [Qemu-devel] [PATCH 7/9] powerpc/kvm: Add E500 core emulation Liu Yu
2009-01-15 12:34               ` [Qemu-devel] [PATCH 8/9] powerpc/kvm: extern one function for E500 code use Liu Yu
     [not found]                 ` <1232022857-2315-10-git-send-email-yu.liu@freescale.com>
2009-01-16  8:22                   ` [Qemu-devel] RE: [PATCH 9/9] powerpc/kvm: Add MPC85xx board support Liu Yu
2009-01-16 18:09                     ` Hollis Blanchard
2009-01-20  3:09                       ` Liu Yu
2009-01-20 17:23                         ` Hollis Blanchard
2009-01-15 19:53               ` [Qemu-devel] Re: [PATCH 7/9] powerpc/kvm: Add E500 core emulation Hollis Blanchard
2009-01-16  7:51                 ` [Qemu-devel] " Liu Yu
2009-01-16 18:02                   ` Hollis Blanchard
2009-01-19 10:54                     ` Liu Yu
2009-01-19 10:59                       ` Liu Yu
2009-01-15 20:02           ` [Qemu-devel] Re: [PATCH 5/9] powerpc/kvm: Add freescale pci controller's support Hollis Blanchard
2009-01-16  7:37             ` [Qemu-devel] " Liu Yu
2009-01-15 21:22       ` [Qemu-devel] [PATCH 3/9] powerpc/kvm: Enable mpic for E500 platform Anthony Liguori
2009-01-16  5:34         ` Liu Yu
2009-01-16 18:17           ` Hollis Blanchard
2009-01-16 21:20             ` Aurelien Jarno
2009-01-15 20:06 ` [Qemu-devel] Re: [PATCH 0/9] powerpc/kvm: Add MPC85xx platform support Hollis Blanchard
2009-01-15 21:26 ` [Qemu-devel] " Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1232022857-2315-6-git-send-email-yu.liu@freescale.com \
    --to=yu.liu@freescale.com \
    --cc=kvm-ppc@vger.kernel.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).