diff options
Diffstat (limited to 'target/linux/gemini/patches-3.18/140-arm-gemini-add-pci-support.patch')
-rw-r--r-- | target/linux/gemini/patches-3.18/140-arm-gemini-add-pci-support.patch | 389 |
1 files changed, 0 insertions, 389 deletions
diff --git a/target/linux/gemini/patches-3.18/140-arm-gemini-add-pci-support.patch b/target/linux/gemini/patches-3.18/140-arm-gemini-add-pci-support.patch deleted file mode 100644 index f662a295f9..0000000000 --- a/target/linux/gemini/patches-3.18/140-arm-gemini-add-pci-support.patch +++ /dev/null @@ -1,389 +0,0 @@ ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -400,6 +400,7 @@ config ARCH_GEMINI - select CLKSRC_MMIO - select CPU_FA526 - select GENERIC_CLOCKEVENTS -+ select MIGHT_HAVE_PCI - help - Support for the Cortina Systems Gemini family SoCs - ---- a/arch/arm/mach-gemini/include/mach/hardware.h -+++ b/arch/arm/mach-gemini/include/mach/hardware.h -@@ -71,4 +71,9 @@ - */ - #define IO_ADDRESS(x) IOMEM((((x) & 0xFFF00000) >> 4) | ((x) & 0x000FFFFF) | 0xF0000000) - -+/* -+ * PCI subsystem macros -+ */ -+#define pcibios_assign_all_busses() 1 -+ - #endif ---- a/arch/arm/mach-gemini/include/mach/irqs.h -+++ b/arch/arm/mach-gemini/include/mach/irqs.h -@@ -43,11 +43,14 @@ - - #define NORMAL_IRQ_NUM 32 - --#define GPIO_IRQ_BASE NORMAL_IRQ_NUM -+#define PCI_IRQ_BASE NORMAL_IRQ_NUM -+#define PCI_IRQ_NUM 4 -+ -+#define GPIO_IRQ_BASE (NORMAL_IRQ_NUM + PCI_IRQ_NUM) - #define GPIO_IRQ_NUM (3 * 32) - - #define ARCH_TIMER_IRQ IRQ_TIMER2 - --#define NR_IRQS (NORMAL_IRQ_NUM + GPIO_IRQ_NUM) -+#define NR_IRQS (NORMAL_IRQ_NUM + PCI_IRQ_NUM + GPIO_IRQ_NUM) - - #endif /* __MACH_IRQS_H__ */ ---- a/arch/arm/mach-gemini/Makefile -+++ b/arch/arm/mach-gemini/Makefile -@@ -6,6 +6,8 @@ - - obj-y := irq.o mm.o time.o devices.o gpio.o idle.o reset.o - -+obj-$(CONFIG_PCI) += pci.o -+ - # Board-specific support - obj-$(CONFIG_MACH_NAS4220B) += board-nas4220b.o - obj-$(CONFIG_MACH_RUT100) += board-rut1xx.o ---- a/arch/arm/mach-gemini/mm.c -+++ b/arch/arm/mach-gemini/mm.c -@@ -59,6 +59,11 @@ static struct map_desc gemini_io_desc[] - .length = SZ_512K, - .type = MT_DEVICE, - }, { -+ .virtual = (unsigned long)IO_ADDRESS(GEMINI_PCI_IO_BASE), -+ .pfn = __phys_to_pfn(GEMINI_PCI_IO_BASE), -+ .length = SZ_512K, -+ .type = MT_DEVICE, -+ }, { - .virtual = (unsigned long)IO_ADDRESS(GEMINI_FLASH_CTRL_BASE), - .pfn = __phys_to_pfn(GEMINI_FLASH_CTRL_BASE), - .length = SZ_512K, ---- /dev/null -+++ b/arch/arm/mach-gemini/pci.c -@@ -0,0 +1,320 @@ -+/* -+ * Support for Gemini PCI Controller -+ * -+ * Copyright (C) 2009 Janos Laube <janos.dev@gmail.com> -+ * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> -+ * -+ * based on SL2312 PCI controller code -+ * Storlink (C) 2003 -+ * -+ * This program 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 <linux/kernel.h> -+#include <linux/pci.h> -+#include <linux/irq.h> -+#include <linux/gpio.h> -+ -+#include <asm/mach/pci.h> -+ -+#include <mach/irqs.h> -+#include <mach/hardware.h> -+ -+#define GEMINI_PCI_IOSIZE_1M 0x0000 -+ -+#define GEMINI_PCI_PMC 0x40 -+#define GEMINI_PCI_PMCSR 0x44 -+#define GEMINI_PCI_CTRL1 0x48 -+#define GEMINI_PCI_CTRL2 0x4C -+#define GEMINI_PCI_MEM1_BASE_SIZE 0x50 -+#define GEMINI_PCI_MEM2_BASE_SIZE 0x54 -+#define GEMINI_PCI_MEM3_BASE_SIZE 0x58 -+ -+#define PCI_CTRL2_INTSTS_OFFSET 28 -+#define PCI_CTRL2_INTMASK_OFFSET 22 -+ -+#define GEMINI_PCI_DMA_MASK 0xFFF00000 -+#define GEMINI_PCI_DMA_MEM1_BASE 0x00000000 -+#define GEMINI_PCI_DMA_MEM2_BASE 0x00000000 -+#define GEMINI_PCI_DMA_MEM3_BASE 0x00000000 -+#define GEMINI_PCI_DMA_MEM1_SIZE 7 -+#define GEMINI_PCI_DMA_MEM2_SIZE 6 -+#define GEMINI_PCI_DMA_MEM3_SIZE 6 -+ -+#define PCI_CONF_ENABLE (1 << 31) -+#define PCI_CONF_WHERE(r) ((r) & 0xFC) -+#define PCI_CONF_BUS(b) (((b) & 0xFF) << 16) -+#define PCI_CONF_DEVICE(d) (((d) & 0x1F) << 11) -+#define PCI_CONF_FUNCTION(f) (((f) & 0x07) << 8) -+ -+#define PCI_IOSIZE_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE)) -+#define PCI_PROT_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x04) -+#define PCI_CTRL_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x08) -+#define PCI_SOFTRST_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x10) -+#define PCI_CONFIG_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x28) -+#define PCI_DATA_REG (IO_ADDRESS(GEMINI_PCI_IO_BASE) + 0x2C) -+ -+ -+static DEFINE_SPINLOCK(gemini_pci_lock); -+ -+static int gemini_pci_read_config(struct pci_bus* bus, unsigned int fn, -+ int config, int size, u32* value) -+{ -+ unsigned long irq_flags; -+ -+ spin_lock_irqsave(&gemini_pci_lock, irq_flags); -+ -+ __raw_writel(PCI_CONF_BUS(bus->number) | -+ PCI_CONF_DEVICE(PCI_SLOT(fn)) | -+ PCI_CONF_FUNCTION(PCI_FUNC(fn)) | -+ PCI_CONF_WHERE(config) | -+ PCI_CONF_ENABLE, -+ PCI_CONFIG_REG); -+ -+ *value = __raw_readl(PCI_DATA_REG); -+ -+ if (size == 1) -+ *value = (*value >> (8 * (config & 3))) & 0xFF; -+ else if (size == 2) -+ *value = (*value >> (8 * (config & 3))) & 0xFFFF; -+ -+ spin_unlock_irqrestore(&gemini_pci_lock, irq_flags); -+ -+ dev_dbg(&bus->dev, -+ "[read] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", -+ PCI_SLOT(fn), PCI_FUNC(fn), config, size, *value); -+ -+ return PCIBIOS_SUCCESSFUL; -+} -+ -+static int gemini_pci_write_config(struct pci_bus* bus, unsigned int fn, -+ int config, int size, u32 value) -+{ -+ unsigned long irq_flags = 0; -+ int ret = PCIBIOS_SUCCESSFUL; -+ -+ dev_dbg(&bus->dev, -+ "[write] slt: %.2d, fnc: %d, cnf: 0x%.2X, val (%d bytes): 0x%.8X\n", -+ PCI_SLOT(fn), PCI_FUNC(fn), config, size, value); -+ -+ spin_lock_irqsave(&gemini_pci_lock, irq_flags); -+ -+ __raw_writel(PCI_CONF_BUS(bus->number) | -+ PCI_CONF_DEVICE(PCI_SLOT(fn)) | -+ PCI_CONF_FUNCTION(PCI_FUNC(fn)) | -+ PCI_CONF_WHERE(config) | -+ PCI_CONF_ENABLE, -+ PCI_CONFIG_REG); -+ -+ switch(size) { -+ case 4: -+ __raw_writel(value, PCI_DATA_REG); -+ break; -+ case 2: -+ __raw_writew(value, PCI_DATA_REG + (config & 3)); -+ break; -+ case 1: -+ __raw_writeb(value, PCI_DATA_REG + (config & 3)); -+ break; -+ default: -+ ret = PCIBIOS_BAD_REGISTER_NUMBER; -+ } -+ -+ spin_unlock_irqrestore(&gemini_pci_lock, irq_flags); -+ -+ return ret; -+} -+ -+static struct pci_ops gemini_pci_ops = { -+ .read = gemini_pci_read_config, -+ .write = gemini_pci_write_config, -+}; -+ -+static struct resource gemini_pci_resource_io = { -+ .name = "PCI I/O Space", -+ .start = GEMINI_PCI_IO_BASE, -+ .end = GEMINI_PCI_IO_BASE + SZ_1M - 1, -+ .flags = IORESOURCE_IO, -+}; -+ -+static struct resource gemini_pci_resource_mem = { -+ .name = "PCI Memory Space", -+ .start = GEMINI_PCI_MEM_BASE, -+ .end = GEMINI_PCI_MEM_BASE + SZ_128M - 1, -+ .flags = IORESOURCE_MEM, -+}; -+ -+static int __init gemini_pci_request_resources(struct pci_sys_data *sys) -+{ -+ if (request_resource(&ioport_resource, &gemini_pci_resource_io)) -+ goto bad_resources; -+ if (request_resource(&iomem_resource, &gemini_pci_resource_mem)) -+ goto bad_resources; -+ -+ pci_add_resource(&sys->resources, &gemini_pci_resource_io); -+ pci_add_resource(&sys->resources, &gemini_pci_resource_mem); -+ -+ return 0; -+ -+bad_resources: -+ pr_err("Gemini PCI: request_resource() failed. " -+ "Abort PCI bus enumeration.\n"); -+ return -1; -+} -+ -+static int __init gemini_pci_setup(int nr, struct pci_sys_data *sys) -+{ -+ unsigned int cmd; -+ -+ pcibios_min_io = 0x100; -+ pcibios_min_mem = 0; -+ -+ if ((nr > 0) || gemini_pci_request_resources(sys)) -+ return 0; -+ -+ /* setup I/O space to 1MB size */ -+ __raw_writel(GEMINI_PCI_IOSIZE_1M, PCI_IOSIZE_REG); -+ -+ /* setup hostbridge */ -+ cmd = __raw_readl(PCI_CTRL_REG); -+ cmd |= PCI_COMMAND_IO; -+ cmd |= PCI_COMMAND_MEMORY; -+ cmd |= PCI_COMMAND_MASTER; -+ __raw_writel(cmd, PCI_CTRL_REG); -+ -+ return 1; -+} -+ -+static struct pci_bus* __init gemini_pci_scan_bus(int nr, struct pci_sys_data* sys) -+{ -+ unsigned int reg = 0; -+ struct pci_bus* bus = 0; -+ -+ bus = pci_scan_bus(nr, &gemini_pci_ops, sys); -+ if (bus) { -+ dev_dbg(&bus->dev, "setting up PCI DMA\n"); -+ reg = (GEMINI_PCI_DMA_MEM1_BASE & GEMINI_PCI_DMA_MASK) -+ | (GEMINI_PCI_DMA_MEM1_SIZE << 16); -+ gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM1_BASE_SIZE, 4, reg); -+ reg = (GEMINI_PCI_DMA_MEM2_BASE & GEMINI_PCI_DMA_MASK) -+ | (GEMINI_PCI_DMA_MEM2_SIZE << 16); -+ gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM2_BASE_SIZE, 4, reg); -+ reg = (GEMINI_PCI_DMA_MEM3_BASE & GEMINI_PCI_DMA_MASK) -+ | (GEMINI_PCI_DMA_MEM3_SIZE << 16); -+ gemini_pci_write_config(bus, 0, GEMINI_PCI_MEM3_BASE_SIZE, 4, reg); -+ } -+ -+ return bus; -+} -+ -+/* Should work with all boards based on original Storlink EVB */ -+static int __init gemini_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -+{ -+ if (slot < 9 || slot > 12) -+ return -1; -+ -+ return PCI_IRQ_BASE + (((slot - 9) + (pin - 1)) & 0x3); -+} -+ -+static struct hw_pci gemini_hw_pci __initdata = { -+ .nr_controllers = 1, -+ .setup = gemini_pci_setup, -+ .scan = gemini_pci_scan_bus, -+ .map_irq = gemini_pci_map_irq, -+}; -+ -+/* we need this for muxed PCI interrupts handling */ -+static struct pci_bus bogus_pci_bus; -+ -+static void gemini_pci_ack_irq(struct irq_data *d) -+{ -+ unsigned int irq = d->irq; -+ unsigned int reg; -+ -+ gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, ®); -+ reg &= ~(0xF << PCI_CTRL2_INTSTS_OFFSET); -+ reg |= 1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTSTS_OFFSET); -+ gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg); -+} -+ -+static void gemini_pci_mask_irq(struct irq_data *d) -+{ -+ unsigned int irq = d->irq; -+ unsigned int reg; -+ -+ gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, ®); -+ reg &= ~((0xF << PCI_CTRL2_INTSTS_OFFSET) -+ | (1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTMASK_OFFSET))); -+ gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg); -+} -+ -+static void gemini_pci_unmask_irq(struct irq_data *d) -+{ -+ unsigned int irq = d->irq; -+ unsigned int reg; -+ -+ gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, ®); -+ reg &= ~(0xF << PCI_CTRL2_INTSTS_OFFSET); -+ reg |= 1 << (irq - PCI_IRQ_BASE + PCI_CTRL2_INTMASK_OFFSET); -+ gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, reg); -+} -+ -+static void gemini_pci_irq_handler(unsigned int irq, struct irq_desc *desc) -+{ -+ unsigned int pci_irq_no, irq_stat, reg, i; -+ -+ gemini_pci_read_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2, 4, ®); -+ irq_stat = reg >> PCI_CTRL2_INTSTS_OFFSET; -+ -+ for (i = 0; i < 4; i++) { -+ -+ if ((irq_stat & (1 << i)) == 0) -+ continue; -+ -+ pci_irq_no = PCI_IRQ_BASE + i; -+ -+ BUG_ON(!(irq_desc[pci_irq_no].handle_irq)); -+ irq_desc[pci_irq_no].handle_irq(pci_irq_no, -+ &irq_desc[pci_irq_no]); -+ } -+} -+ -+static struct irq_chip gemini_pci_irq_chip = { -+ .name = "PCI", -+ .irq_ack = gemini_pci_ack_irq, -+ .irq_mask = gemini_pci_mask_irq, -+ .irq_unmask = gemini_pci_unmask_irq, -+}; -+ -+static int __init gemini_pci_init(void) -+{ -+ int i; -+ -+ for (i = 72; i <= 95; i++) -+ gpio_request(i, "PCI"); -+ -+ /* initialize our bogus bus */ -+ dev_set_name(&bogus_pci_bus.dev, "PCI IRQ handler"); -+ bogus_pci_bus.number = 0; -+ -+ /* mask and clear all interrupts */ -+ gemini_pci_write_config(&bogus_pci_bus, 0, GEMINI_PCI_CTRL2 + 2, 2, -+ 0xF000); -+ -+ for (i = PCI_IRQ_BASE; i < PCI_IRQ_BASE + 4; i++) { -+ irq_set_chip_and_handler(i, &gemini_pci_irq_chip, -+ handle_level_irq); -+ set_irq_flags(i, IRQF_VALID); -+ } -+ -+ irq_set_chained_handler(IRQ_PCI, gemini_pci_irq_handler); -+ -+ pci_common_init(&gemini_hw_pci); -+ -+ return 0; -+} -+ -+subsys_initcall(gemini_pci_init); |