From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from mail-fx0-f49.google.com ([209.85.161.49]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QrcrF-0006fS-Te for barebox@lists.infradead.org; Thu, 11 Aug 2011 21:32:07 +0000 Received: by mail-fx0-f49.google.com with SMTP id 20so2558706fxd.36 for ; Thu, 11 Aug 2011 14:32:05 -0700 (PDT) From: Antony Pavlov Date: Fri, 12 Aug 2011 01:31:51 +0400 Message-Id: <1313098311-5752-1-git-send-email-antonynpavlov@gmail.com> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: barebox-bounces@lists.infradead.org Errors-To: barebox-bounces+u.kleine-koenig=pengutronix.de@lists.infradead.org Subject: [RFC 3/5] MIPS: add PCI support for GT64120-based malta To: barebox@lists.infradead.org Signed-off-by: Antony Pavlov --- arch/mips/Kconfig | 22 ++++ arch/mips/mach-malta/Makefile | 1 + arch/mips/mach-malta/pci.c | 241 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+), 0 deletions(-) create mode 100644 arch/mips/mach-malta/pci.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8970470..9c599e4 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -36,6 +36,7 @@ config MACH_MIPS_MALTA select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN select HAS_DEBUG_LL + select HW_HAS_PCI config MACH_MIPS_BCM47XX bool "Broadcom BCM47xx-based boards" @@ -219,6 +220,27 @@ config CMD_MIPS_CPUINFO endmenu +menu "Bus options (PCI)" + +config HW_HAS_PCI + bool + +config PCI + bool "Support for PCI controller" + depends on HW_HAS_PCI + select PCI_DOMAINS + help + Find out whether you have a PCI motherboard. PCI is the name of a + bus system, i.e. the way the CPU talks to the other stuff inside + your box. If you have PCI, say Y, otherwise N. + +config PCI_DOMAINS + bool + +source "drivers/pci/Kconfig" + +endmenu + source common/Kconfig source commands/Kconfig source net/Kconfig diff --git a/arch/mips/mach-malta/Makefile b/arch/mips/mach-malta/Makefile index f3cc668..0c5a701 100644 --- a/arch/mips/mach-malta/Makefile +++ b/arch/mips/mach-malta/Makefile @@ -1 +1,2 @@ obj-y += reset.o +obj-$(CONFIG_PCI) += pci.o diff --git a/arch/mips/mach-malta/pci.c b/arch/mips/mach-malta/pci.c new file mode 100644 index 0000000..8f87c70 --- /dev/null +++ b/arch/mips/mach-malta/pci.c @@ -0,0 +1,241 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#define GT64120_BASE 0xb4000000 + +#define PCI_ACCESS_READ 0 +#define PCI_ACCESS_WRITE 1 + +static struct resource gt64120_mem_resource = { + .name = "GT-64120 PCI MEM", + .flags = IORESOURCE_MEM, +}; + +static struct resource gt64120_io_resource = { + .name = "GT-64120 PCI I/O", + .flags = IORESOURCE_IO, +}; + +static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type, + struct pci_bus *bus, unsigned int devfn, int where, u32 * data) +{ + unsigned char busnum = bus->number; + u32 intr; + + if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0))) + return -1; /* Because of a bug in the galileo (for slot 31). */ + + /* Clear cause register bits */ + GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT)); + + /* Setup address */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) | + (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | + ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) | + GT_PCI0_CFGADDR_CONFIGEN_BIT); + + if (access_type == PCI_ACCESS_WRITE) { + if (busnum == 0 && PCI_SLOT(devfn) == 0) { + /* + * The Galileo system controller is acting + * differently than other devices. + */ + GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); + } else + __GT_WRITE(GT_PCI0_CFGDATA_OFS, *data); + } else { + if (busnum == 0 && PCI_SLOT(devfn) == 0) { + /* + * The Galileo system controller is acting + * differently than other devices. + */ + *data = GT_READ(GT_PCI0_CFGDATA_OFS); + } else + *data = __GT_READ(GT_PCI0_CFGDATA_OFS); + } + + /* Check for master or target abort */ + intr = GT_READ(GT_INTRCAUSE_OFS); + + if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) { + /* Error occurred */ + + /* Clear bits */ + GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT | + GT_INTRCAUSE_TARABORT0_BIT)); + + return -1; + } + + return 0; +} + +/* + * We can't address 8 and 16 bit words directly. Instead we have to + * read/write a 32bit word and mask/modify the data we actually want. + */ +static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 * val) +{ + u32 data = 0; + + if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn, + where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + *val = (data >> ((where & 3) << 3)) & 0xff; + else if (size == 2) + *val = (data >> ((where & 3) << 3)) & 0xffff; + else + *val = data; + + return PCIBIOS_SUCCESSFUL; +} + +static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 data = 0; + + if (size == 4) + data = val; + else { + if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, + devfn, where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (size == 1) + data = (data & ~(0xff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + else if (size == 2) + data = (data & ~(0xffff << ((where & 3) << 3))) | + (val << ((where & 3) << 3)); + } + + if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn, + where, &data)) + return PCIBIOS_DEVICE_NOT_FOUND; + + return PCIBIOS_SUCCESSFUL; +} + +/* FIXME: it's HACK */ +/* function returns memory address for begin of pci resource */ +static int gt64xxx_res_start(struct pci_bus *bus, resource_size_t res_addr) +{ + return res_addr | 0xa0000000; +} + +struct pci_ops gt64xxx_pci0_ops = { + .read = gt64xxx_pci0_pcibios_read, + .write = gt64xxx_pci0_pcibios_write, + + .res_start = gt64xxx_res_start, +}; + +static struct pci_controller gt64120_controller = { + .pci_ops = >64xxx_pci0_ops, + .io_resource = >64120_io_resource, + .mem_resource = >64120_mem_resource, +}; + +int pcibios_init() +{ + resource_size_t start, end, map, start1, end1, map1, mask, res_end; + + /* + * Due to a bug in the Galileo system controller, we need + * to setup the PCI BAR for the Galileo internal registers. + * This should be done in the bios/bootprom and will be + * fixed in a later revision of YAMON (the MIPS boards + * boot prom). + */ + GT_WRITE(GT_PCI0_CFGADDR_OFS, + (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */ + (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */ + (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/ + ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/ + GT_PCI0_CFGADDR_CONFIGEN_BIT); + + /* Perform the write */ + //GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); + //GT_WRITE(GT_PCI0_CFGDATA_OFS, GT64120_BASE); + GT_WRITE(GT_PCI0_CFGDATA_OFS, 0x14000000); + +#define PCI0_IO_SPACE_BASE 0x10000000 +#define PCI0_IO_SPACE_SIZE 0x01000000 +#define PCI0_MEM_SPACE_BASE 0x11000000 +#define PCI0_MEM_SPACE_SIZE 0x01000000 + +#if 1 + GT_WRITE(GT_PCI0IOLD_OFS, (PCI0_IO_SPACE_BASE >> 21) & 0x7ff); + GT_WRITE(GT_PCI0IOHD_OFS, ((PCI0_IO_SPACE_BASE + PCI0_IO_SPACE_SIZE - 1) >> 21) & 0x7f); + GT_WRITE(GT_PCI0M0LD_OFS, (PCI0_MEM_SPACE_BASE >> 21) & 0x7ff); + GT_WRITE(GT_PCI0M0HD_OFS, ((PCI0_MEM_SPACE_BASE + PCI0_MEM_SPACE_SIZE - 1) >> 21) & 0x7f); +#endif + + /* Here is linux code. It assumes, that firmware made the work... */ + + /* Set up resource ranges from the controller's registers. */ + start = GT_READ(GT_PCI0M0LD_OFS); + end = GT_READ(GT_PCI0M0HD_OFS); + map = GT_READ(GT_PCI0M0REMAP_OFS); + end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); + start1 = GT_READ(GT_PCI0M1LD_OFS); + end1 = GT_READ(GT_PCI0M1HD_OFS); + map1 = GT_READ(GT_PCI0M1REMAP_OFS); + end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK); +#if 0 + /* Cannot support multiple windows, use the wider. */ + if (end1 - start1 > end - start) { + start = start1; + end = end1; + map = map1; + } +#endif + mask = ~(start ^ end); + /* We don't support remapping with a discontiguous mask. */ + BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && + mask != ~((mask & -mask) - 1)); + gt64120_mem_resource.start = start; + res_end = end; + gt64120_controller.mem_offset = (start & mask) - (map & mask); + /* Addresses are 36-bit, so do shifts in the destinations. */ + gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF; + res_end <<= GT_PCI_DCRM_SHF; + res_end |= (1 << GT_PCI_DCRM_SHF) - 1; + gt64120_mem_resource.size = res_end - gt64120_mem_resource.start + 1; + gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF; + + start = GT_READ(GT_PCI0IOLD_OFS); + end = GT_READ(GT_PCI0IOHD_OFS); + map = GT_READ(GT_PCI0IOREMAP_OFS); + end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK); + mask = ~(start ^ end); + /* We don't support remapping with a discontiguous mask. */ + BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) && + mask != ~((mask & -mask) - 1)); + gt64120_io_resource.start = map & mask; + res_end = (map & mask) | ~mask; + gt64120_controller.io_offset = 0; + /* Addresses are 36-bit, so do shifts in the destinations. */ + gt64120_io_resource.start <<= GT_PCI_DCRM_SHF; + res_end <<= GT_PCI_DCRM_SHF; + res_end |= (1 << GT_PCI_DCRM_SHF) - 1; + gt64120_io_resource.size = res_end - gt64120_io_resource.start + 1; + + register_pci_controller(>64120_controller); + + return 0; +} +EXPORT_SYMBOL(pcibios_init); -- 1.7.5.4 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox