]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
MIPS: qemu-malta: add PCI support
authorGabor Juhos <juhosg@openwrt.org>
Wed, 22 May 2013 03:57:42 +0000 (03:57 +0000)
committerTom Rini <trini@ti.com>
Wed, 24 Jul 2013 13:51:04 +0000 (09:51 -0400)
Qemu emulates the Galileo GT64120 System Controller
which provides a CPU bus to PCI bus bridge.

The patch adds driver for this bridge and enables
PCI support for the emulated Malta board.

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Cc: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
board/qemu-malta/qemu-malta.c
drivers/pci/Makefile
drivers/pci/pci_gt64120.c [new file with mode: 0644]
include/configs/qemu-malta.h
include/pci_gt64120.h [new file with mode: 0644]

index 449da9c85919bf50e5ca15f8ebac24d457f632a9..e3a733f42f486acdcff1c6a97aef4e7bb348b887 100644 (file)
@@ -8,8 +8,10 @@
 
 #include <common.h>
 
+#include <asm/addrspace.h>
 #include <asm/io.h>
 #include <asm/malta.h>
+#include <pci_gt64120.h>
 
 phys_size_t initdram(int board_type)
 {
@@ -29,3 +31,13 @@ void _machine_restart(void)
        reset_base = (void __iomem *)CKSEG1ADDR(MALTA_RESET_BASE);
        __raw_writel(GORESET, reset_base);
 }
+
+void pci_init_board(void)
+{
+       set_io_port_base(CKSEG1ADDR(MALTA_IO_PORT_BASE));
+
+       gt64120_pci_init((void *)CKSEG1ADDR(MALTA_GT_BASE),
+                        0x00000000, 0x00000000, CONFIG_SYS_MEM_SIZE,
+                        0x10000000, 0x10000000, 128 * 1024 * 1024,
+                        0x00000000, 0x00000000, 0x20000);
+}
index 5a23914ba465391f3646a5b46eb3004b0588709e..be26b60592d2e0f2a751470a91f305ee2cd76940 100644 (file)
@@ -12,6 +12,7 @@ LIB   := $(obj)libpci.o
 COBJS-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o
 COBJS-$(CONFIG_PCI) += pci.o pci_auto.o
 COBJS-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o
+COBJS-$(CONFIG_PCI_GT64120) += pci_gt64120.o
 COBJS-$(CONFIG_FTPCI100) += pci_ftpci100.o
 COBJS-$(CONFIG_IXP_PCI) += pci_ixp.o
 COBJS-$(CONFIG_SH4_PCI) += pci_sh4.o
diff --git a/drivers/pci/pci_gt64120.c b/drivers/pci/pci_gt64120.c
new file mode 100644 (file)
index 0000000..a610758
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * Based on the Linux implementation.
+ *   Copyright (C) 1999, 2000, 2004  MIPS Technologies, Inc.
+ *   Authors: Carsten Langgaard <carstenl@mips.com>
+ *            Maciej W. Rozycki <macro@mips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <gt64120.h>
+#include <pci.h>
+#include <pci_gt64120.h>
+
+#include <asm/io.h>
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+struct gt64120_regs {
+       u8      unused_000[0xc18];
+       u32     intrcause;
+       u8      unused_c1c[0x0dc];
+       u32     pci0_cfgaddr;
+       u32     pci0_cfgdata;
+};
+
+struct gt64120_pci_controller {
+       struct pci_controller hose;
+       struct gt64120_regs *regs;
+};
+
+static inline struct gt64120_pci_controller *
+hose_to_gt64120(struct pci_controller *hose)
+{
+       return container_of(hose, struct gt64120_pci_controller, hose);
+}
+
+#define GT_INTRCAUSE_ABORT_BITS        \
+               (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)
+
+static int gt_config_access(struct gt64120_pci_controller *gt,
+                           unsigned char access_type, pci_dev_t bdf,
+                           int where, u32 *data)
+{
+       unsigned int bus = PCI_BUS(bdf);
+       unsigned int dev = PCI_DEV(bdf);
+       unsigned int devfn = PCI_DEV(bdf) << 3 | PCI_FUNC(bdf);
+       u32 intr;
+       u32 addr;
+       u32 val;
+
+       if (bus == 0 && dev >= 31) {
+               /* Because of a bug in the galileo (for slot 31). */
+               return -1;
+       }
+
+       if (access_type == PCI_ACCESS_WRITE)
+               debug("PCI WR %02x:%02x.%x reg:%02d data:%08x\n",
+                     PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), where, *data);
+
+       /* Clear cause register bits */
+       writel(~GT_INTRCAUSE_ABORT_BITS, &gt->regs->intrcause);
+
+       addr = GT_PCI0_CFGADDR_CONFIGEN_BIT;
+       addr |= bus << GT_PCI0_CFGADDR_BUSNUM_SHF;
+       addr |= devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF;
+       addr |= (where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF;
+
+       /* Setup address */
+       writel(addr, &gt->regs->pci0_cfgaddr);
+
+       if (access_type == PCI_ACCESS_WRITE) {
+               if (bus == 0 && dev == 0) {
+                       /*
+                        * The Galileo system controller is acting
+                        * differently than other devices.
+                        */
+                       val = *data;
+               } else {
+                       val = cpu_to_le32(*data);
+               }
+
+               writel(val, &gt->regs->pci0_cfgdata);
+       } else {
+               val = readl(&gt->regs->pci0_cfgdata);
+
+               if (bus == 0 && dev == 0) {
+                       /*
+                        * The Galileo system controller is acting
+                        * differently than other devices.
+                        */
+                       *data = val;
+               } else {
+                       *data = le32_to_cpu(val);
+               }
+       }
+
+       /* Check for master or target abort */
+       intr = readl(&gt->regs->intrcause);
+       if (intr & GT_INTRCAUSE_ABORT_BITS) {
+               /* Error occurred, clear abort bits */
+               writel(~GT_INTRCAUSE_ABORT_BITS, &gt->regs->intrcause);
+               return -1;
+       }
+
+       if (access_type == PCI_ACCESS_READ)
+               debug("PCI RD %02x:%02x.%x reg:%02d data:%08x\n",
+                     PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf), where, *data);
+
+       return 0;
+}
+
+static int gt_read_config_dword(struct pci_controller *hose, pci_dev_t dev,
+                               int where, u32 *value)
+{
+       struct gt64120_pci_controller *gt = hose_to_gt64120(hose);
+
+       *value = 0xffffffff;
+       return gt_config_access(gt, PCI_ACCESS_READ, dev, where, value);
+}
+
+static int gt_write_config_dword(struct pci_controller *hose, pci_dev_t dev,
+                                int where, u32 value)
+{
+       struct gt64120_pci_controller *gt = hose_to_gt64120(hose);
+       u32 data = value;
+
+       return gt_config_access(gt, PCI_ACCESS_WRITE, dev, where, &data);
+}
+
+void gt64120_pci_init(void *regs, unsigned long sys_bus, unsigned long sys_phys,
+                    unsigned long sys_size, unsigned long mem_bus,
+                    unsigned long mem_phys, unsigned long mem_size,
+                    unsigned long io_bus, unsigned long io_phys,
+                    unsigned long io_size)
+{
+       static struct gt64120_pci_controller global_gt;
+       struct gt64120_pci_controller *gt;
+       struct pci_controller *hose;
+
+       gt = &global_gt;
+       gt->regs = regs;
+
+       hose = &gt->hose;
+
+       hose->first_busno = 0;
+       hose->last_busno = 0;
+
+       /* System memory space */
+       pci_set_region(&hose->regions[0], sys_bus, sys_phys, sys_size,
+                      PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+       /* PCI memory space */
+       pci_set_region(&hose->regions[1], mem_bus, mem_phys, mem_size,
+                      PCI_REGION_MEM);
+
+       /* PCI I/O space */
+       pci_set_region(&hose->regions[2], io_bus, io_phys, io_size,
+                      PCI_REGION_IO);
+
+       hose->region_count = 3;
+
+       pci_set_ops(hose,
+                   pci_hose_read_config_byte_via_dword,
+                   pci_hose_read_config_word_via_dword,
+                   gt_read_config_dword,
+                   pci_hose_write_config_byte_via_dword,
+                   pci_hose_write_config_word_via_dword,
+                   gt_write_config_dword);
+
+       pci_register_hose(hose);
+       hose->last_busno = pci_hose_scan(hose);
+}
index 436bb4973ba2538458a29f7840fb7324848e4de6..ef44d3da7231c5703fe70a63c6605765fc4e0711 100644 (file)
  */
 #define CONFIG_QEMU_MALTA
 
+#define CONFIG_PCI
+#define CONFIG_PCI_GT64120
+#define CONFIG_PCI_PNP
+
 /*
  * CPU Configuration
  */
 #undef CONFIG_CMD_NET
 #undef CONFIG_CMD_NFS
 
+#define CONFIG_CMD_PCI
+
 #define CONFIG_SYS_LONGHELP            /* verbose help, undef to save memory */
 
 #endif /* _QEMU_MALTA_CONFIG_H */
diff --git a/include/pci_gt64120.h b/include/pci_gt64120.h
new file mode 100644 (file)
index 0000000..b6d58d8
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _PCI_GT64120_H
+#define _PCI_GT64120_H
+
+void gt64120_pci_init(void *regs, unsigned long sys_bus, unsigned long sys_phys,
+                    unsigned long sys_size, unsigned long mem_bus,
+                    unsigned long mem_phys, unsigned long mem_size,
+                    unsigned long io_bus, unsigned long io_phys,
+                    unsigned long io_size);
+
+
+#endif /* _PCI_GT64120_H */