
2013/2/2 Gabor Juhos juhosg@openwrt.org:
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
Changes since v1:
- rebased against mips/testing
Changes since RFC:
- use a C struct to define the register layout instead of using a base address plus offset notation
- remove custom IO accessors
board/qemu-malta/Makefile | 5 +- board/qemu-malta/pci.c | 168 ++++++++++++++++++++++++++++++++++++++++++ include/configs/qemu-malta.h | 6 ++ 3 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 board/qemu-malta/pci.c
diff --git a/board/qemu-malta/Makefile b/board/qemu-malta/Makefile index 6251bb8..59c1b1d 100644 --- a/board/qemu-malta/Makefile +++ b/board/qemu-malta/Makefile @@ -25,7 +25,10 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(BOARD).o
-COBJS = $(BOARD).o +COBJS-y += $(BOARD).o +COBJS-$(CONFIG_PCI) += pci.o
+COBJS := $(COBJS-y) SOBJS = lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/board/qemu-malta/pci.c b/board/qemu-malta/pci.c new file mode 100644 index 0000000..fd9193b --- /dev/null +++ b/board/qemu-malta/pci.c @@ -0,0 +1,168 @@ +/*
- 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 <asm/addrspace.h> +#include <asm/gt64120.h> +#include <asm/malta.h> +#include <asm/io.h> +#include <pci.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;
+};
+DECLARE_GLOBAL_DATA_PTR;
+static struct gt64120_regs *gt_regs;
+/*
- PCI controller "hose" value
- */
+static struct pci_controller hose;
+#define GT_INTRCAUSE_ABORT_BITS \
(GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)
+static int gt_config_access(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 */
__raw_writel(~GT_INTRCAUSE_ABORT_BITS, >_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 */
__raw_writel(addr, >_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);
__raw_writel(val, >_regs->pci0_cfgdata);
} else {
val = __raw_readl(>_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 = __raw_readl(>_regs->intrcause);
if (intr & GT_INTRCAUSE_ABORT_BITS) {
/* Error occurred, clear abort bits */
__raw_writel(~GT_INTRCAUSE_ABORT_BITS, >_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)
+{
*value = 0xffffffff;
return gt_config_access(PCI_ACCESS_READ, dev, where, value);
+}
+static int gt_write_config_dword(struct pci_controller *hose, pci_dev_t dev,
int where, u32 value)
+{
u32 data = value;
return gt_config_access(PCI_ACCESS_WRITE, dev, where, &data);
+}
+void pci_init_board(void) +{
set_io_port_base(CKSEG1ADDR(MALTA_IO_PORT_BASE));
gt_regs = (struct gt64120_regs *) CKSEG1ADDR(MALTA_GT_BASE);
hose.first_busno = 0;
hose.last_busno = 0xff;
/* System memory space */
pci_set_region(&hose.regions[0],
0x00000000, 0x00000000,
CONFIG_SYS_MEM_SIZE,
PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
/* PCI memory space */
pci_set_region(&hose.regions[1],
0x10000000, 0x10000000,
128 * 1024 * 1024,
PCI_REGION_MEM);
/* PCI I/O space */
pci_set_region(&hose.regions[2],
0x0000000, 0x0000000,
0x20000,
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);
+}
I think this should be implemented as separate driver in drivers/pci/
diff --git a/include/configs/qemu-malta.h b/include/configs/qemu-malta.h index 881c15d..36b584a 100644 --- a/include/configs/qemu-malta.h +++ b/include/configs/qemu-malta.h @@ -17,6 +17,9 @@ */ #define CONFIG_QEMU_MALTA
+#define CONFIG_PCI +#define CONFIG_PCI_PNP
/*
- CPU Configuration
*/ @@ -30,6 +33,7 @@
#define CONFIG_SWAP_IO_SPACE
/*
- Memory map
*/ @@ -108,6 +112,8 @@ #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 */
1.7.10