diff options
Diffstat (limited to 'target/linux/ramips/patches-3.8/0119-PCI-MIPS-adds-rt3883-pci-support.patch')
-rw-r--r-- | target/linux/ramips/patches-3.8/0119-PCI-MIPS-adds-rt3883-pci-support.patch | 535 |
1 files changed, 535 insertions, 0 deletions
diff --git a/target/linux/ramips/patches-3.8/0119-PCI-MIPS-adds-rt3883-pci-support.patch b/target/linux/ramips/patches-3.8/0119-PCI-MIPS-adds-rt3883-pci-support.patch new file mode 100644 index 000000000..d34656555 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0119-PCI-MIPS-adds-rt3883-pci-support.patch @@ -0,0 +1,535 @@ +From f01830fcc57273bd9ec5f6733ab3d28adeb71955 Mon Sep 17 00:00:00 2001 +From: John Crispin <blogic@openwrt.org> +Date: Thu, 21 Mar 2013 17:34:08 +0100 +Subject: [PATCH 119/121] PCI: MIPS: adds rt3883 pci support + +Add support for the pcie found on the rt3883 SoC. + +Signed-off-by: John Crispin <blogic@openwrt.org> +--- + arch/mips/pci/Makefile | 1 + + arch/mips/pci/pci-rt3883.c | 487 ++++++++++++++++++++++++++++++++++++++++++++ + arch/mips/ralink/Kconfig | 1 + + 3 files changed, 489 insertions(+) + create mode 100644 arch/mips/pci/pci-rt3883.c + +diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile +index 77974ba..3cbfd9b 100644 +--- a/arch/mips/pci/Makefile ++++ b/arch/mips/pci/Makefile +@@ -42,6 +42,7 @@ obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o + obj-$(CONFIG_LANTIQ) += fixup-lantiq.o + obj-$(CONFIG_PCI_LANTIQ) += pci-lantiq.o ops-lantiq.o + obj-$(CONFIG_SOC_RT2880) += pci-rt2880.o ++obj-$(CONFIG_SOC_RT3883) += pci-rt3883.o + obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o + obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o + obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o +diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c +new file mode 100644 +index 0000000..8a4c8ce +--- /dev/null ++++ b/arch/mips/pci/pci-rt3883.c +@@ -0,0 +1,487 @@ ++/* ++ * Ralink RT3883 SoC PCI support ++ * ++ * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> ++ * ++ * Parts of this file are based on Ralink's 2.6.21 BSP ++ * ++ * 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 <linux/types.h> ++#include <linux/pci.h> ++#include <linux/io.h> ++#include <linux/init.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++ ++#include <asm/mach-ralink/rt3883.h> ++#include <asm/mach-ralink/rt3883_regs.h> ++ ++#define RT3883_MEMORY_BASE 0x00000000 ++#define RT3883_MEMORY_SIZE 0x02000000 ++ ++#define RT3883_PCI_MEM_BASE 0x20000000 ++#define RT3883_PCI_MEM_SIZE 0x10000000 ++#define RT3883_PCI_IO_BASE 0x10160000 ++#define RT3883_PCI_IO_SIZE 0x00010000 ++ ++#define RT3883_PCI_REG_PCICFG_ADDR 0x00 ++#define RT3883_PCI_REG_PCIRAW_ADDR 0x04 ++#define RT3883_PCI_REG_PCIINT_ADDR 0x08 ++#define RT3883_PCI_REG_PCIMSK_ADDR 0x0c ++#define RT3833_PCI_PCIINT_PCIE BIT(20) ++#define RT3833_PCI_PCIINT_PCI1 BIT(19) ++#define RT3833_PCI_PCIINT_PCI0 BIT(18) ++ ++#define RT3883_PCI_REG_CONFIG_ADDR 0x20 ++#define RT3883_PCI_REG_CONFIG_DATA 0x24 ++#define RT3883_PCI_REG_MEMBASE 0x28 ++#define RT3883_PCI_REG_IOBASE 0x2c ++#define RT3883_PCI_REG_ARBCTL 0x80 ++ ++#define RT3883_PCI_REG_BASE(_x) (0x1000 + (_x) * 0x1000) ++#define RT3883_PCI_REG_BAR0SETUP_ADDR(_x) (RT3883_PCI_REG_BASE((_x)) + 0x10) ++#define RT3883_PCI_REG_IMBASEBAR0_ADDR(_x) (RT3883_PCI_REG_BASE((_x)) + 0x18) ++#define RT3883_PCI_REG_ID(_x) (RT3883_PCI_REG_BASE((_x)) + 0x30) ++#define RT3883_PCI_REG_CLASS(_x) (RT3883_PCI_REG_BASE((_x)) + 0x34) ++#define RT3883_PCI_REG_SUBID(_x) (RT3883_PCI_REG_BASE((_x)) + 0x38) ++#define RT3883_PCI_REG_STATUS(_x) (RT3883_PCI_REG_BASE((_x)) + 0x50) ++ ++static int (*rt3883_pci_plat_dev_init)(struct pci_dev *dev); ++static void __iomem *rt3883_pci_base; ++static DEFINE_SPINLOCK(rt3883_pci_lock); ++ ++static inline u32 rt3883_pci_rr(unsigned reg) ++{ ++ return readl(rt3883_pci_base + reg); ++} ++ ++static inline void rt3883_pci_wr(u32 val, unsigned reg) ++{ ++ writel(val, rt3883_pci_base + reg); ++} ++ ++static inline u32 rt3883_pci_get_cfgaddr(unsigned int bus, unsigned int slot, ++ unsigned int func, unsigned int where) ++{ ++ return ((bus << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | ++ 0x80000000); ++} ++ ++static u32 rt3883_pci_read_u32(unsigned bus, unsigned slot, ++ unsigned func, unsigned reg) ++{ ++ unsigned long flags; ++ u32 address; ++ u32 ret; ++ ++ address = rt3883_pci_get_cfgaddr(bus, slot, func, reg); ++ ++ spin_lock_irqsave(&rt3883_pci_lock, flags); ++ rt3883_pci_wr(address, RT3883_PCI_REG_CONFIG_ADDR); ++ ret = rt3883_pci_rr(RT3883_PCI_REG_CONFIG_DATA); ++ spin_unlock_irqrestore(&rt3883_pci_lock, flags); ++ ++ return ret; ++} ++ ++static void rt3883_pci_write_u32(unsigned bus, unsigned slot, ++ unsigned func, unsigned reg, u32 val) ++{ ++ unsigned long flags; ++ u32 address; ++ ++ address = rt3883_pci_get_cfgaddr(bus, slot, func, reg); ++ ++ spin_lock_irqsave(&rt3883_pci_lock, flags); ++ rt3883_pci_wr(address, RT3883_PCI_REG_CONFIG_ADDR); ++ rt3883_pci_wr(val, RT3883_PCI_REG_CONFIG_DATA); ++ spin_unlock_irqrestore(&rt3883_pci_lock, flags); ++} ++ ++static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ u32 pending; ++ ++ pending = rt3883_pci_rr(RT3883_PCI_REG_PCIINT_ADDR) & ++ rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); ++ ++ if (!pending) { ++ spurious_interrupt(); ++ return; ++ } ++ ++ if (pending & RT3833_PCI_PCIINT_PCI0) ++ generic_handle_irq(RT3883_PCI_IRQ_PCI0); ++ ++ if (pending & RT3833_PCI_PCIINT_PCI1) ++ generic_handle_irq(RT3883_PCI_IRQ_PCI1); ++ ++ if (pending & RT3833_PCI_PCIINT_PCIE) ++ generic_handle_irq(RT3883_PCI_IRQ_PCIE); ++} ++ ++static void rt3883_pci_irq_unmask(struct irq_data *d) ++{ ++ int irq = d->irq; ++ u32 mask; ++ u32 t; ++ ++ switch (irq) { ++ case RT3883_PCI_IRQ_PCI0: ++ mask = RT3833_PCI_PCIINT_PCI0; ++ break; ++ case RT3883_PCI_IRQ_PCI1: ++ mask = RT3833_PCI_PCIINT_PCI1; ++ break; ++ case RT3883_PCI_IRQ_PCIE: ++ mask = RT3833_PCI_PCIINT_PCIE; ++ break; ++ default: ++ BUG(); ++ } ++ ++ t = rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); ++ rt3883_pci_wr(t | mask, RT3883_PCI_REG_PCIMSK_ADDR); ++ /* flush write */ ++ rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); ++} ++ ++static void rt3883_pci_irq_mask(struct irq_data *d) ++{ ++ int irq = d->irq; ++ u32 mask; ++ u32 t; ++ ++ switch (irq) { ++ case RT3883_PCI_IRQ_PCI0: ++ mask = RT3833_PCI_PCIINT_PCI0; ++ break; ++ case RT3883_PCI_IRQ_PCI1: ++ mask = RT3833_PCI_PCIINT_PCI1; ++ break; ++ case RT3883_PCI_IRQ_PCIE: ++ mask = RT3833_PCI_PCIINT_PCIE; ++ break; ++ default: ++ BUG(); ++ } ++ ++ t = rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); ++ rt3883_pci_wr(t & ~mask, RT3883_PCI_REG_PCIMSK_ADDR); ++ /* flush write */ ++ rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); ++} ++ ++static struct irq_chip rt3883_pci_irq_chip = { ++ .name = "RT3883 PCI", ++ .irq_mask = rt3883_pci_irq_mask, ++ .irq_unmask = rt3883_pci_irq_unmask, ++ .irq_mask_ack = rt3883_pci_irq_mask, ++}; ++ ++static void __init rt3883_pci_irq_init(void) ++{ ++ int i; ++ ++ /* disable all interrupts */ ++ rt3883_pci_wr(0, RT3883_PCI_REG_PCIMSK_ADDR); ++ ++ for (i = RT3883_PCI_IRQ_BASE; ++ i < RT3883_PCI_IRQ_BASE + RT3883_PCI_IRQ_COUNT; i++) { ++ irq_set_chip_and_handler(i, &rt3883_pci_irq_chip, ++ handle_level_irq); ++ } ++ ++ irq_set_chained_handler(RT3883_CPU_IRQ_PCI, rt3883_pci_irq_handler); ++} ++ ++static int rt3883_pci_config_read(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 *val) ++{ ++ unsigned long flags; ++ u32 address; ++ u32 data; ++ ++ address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), where); ++ ++ spin_lock_irqsave(&rt3883_pci_lock, flags); ++ rt3883_pci_wr(address, RT3883_PCI_REG_CONFIG_ADDR); ++ data = rt3883_pci_rr(RT3883_PCI_REG_CONFIG_DATA); ++ spin_unlock_irqrestore(&rt3883_pci_lock, flags); ++ ++ switch (size) { ++ case 1: ++ *val = (data >> ((where & 3) << 3)) & 0xff; ++ break; ++ case 2: ++ *val = (data >> ((where & 3) << 3)) & 0xffff; ++ break; ++ case 4: ++ *val = data; ++ break; ++ } ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static int rt3883_pci_config_write(struct pci_bus *bus, unsigned int devfn, ++ int where, int size, u32 val) ++{ ++ unsigned long flags; ++ u32 address; ++ u32 data; ++ ++ address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn), ++ PCI_FUNC(devfn), where); ++ ++ spin_lock_irqsave(&rt3883_pci_lock, flags); ++ rt3883_pci_wr(address, RT3883_PCI_REG_CONFIG_ADDR); ++ data = rt3883_pci_rr(RT3883_PCI_REG_CONFIG_DATA); ++ ++ switch (size) { ++ case 1: ++ data = (data & ~(0xff << ((where & 3) << 3))) | ++ (val << ((where & 3) << 3)); ++ break; ++ case 2: ++ data = (data & ~(0xffff << ((where & 3) << 3))) | ++ (val << ((where & 3) << 3)); ++ break; ++ case 4: ++ data = val; ++ break; ++ } ++ ++ rt3883_pci_wr(data, RT3883_PCI_REG_CONFIG_DATA); ++ spin_unlock_irqrestore(&rt3883_pci_lock, flags); ++ ++ return PCIBIOS_SUCCESSFUL; ++} ++ ++static struct pci_ops rt3883_pci_ops = { ++ .read = rt3883_pci_config_read, ++ .write = rt3883_pci_config_write, ++}; ++ ++static struct resource rt3883_pci_mem_resource = { ++ .name = "PCI MEM space", ++ .start = RT3883_PCI_MEM_BASE, ++ .end = RT3883_PCI_MEM_BASE + RT3883_PCI_MEM_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++}; ++ ++static struct resource rt3883_pci_io_resource = { ++ .name = "PCI IO space", ++ .start = RT3883_PCI_IO_BASE, ++ .end = RT3883_PCI_IO_BASE + RT3883_PCI_IO_SIZE - 1, ++ .flags = IORESOURCE_IO, ++}; ++ ++static struct pci_controller rt3883_pci_controller = { ++ .pci_ops = &rt3883_pci_ops, ++ .mem_resource = &rt3883_pci_mem_resource, ++ .io_resource = &rt3883_pci_io_resource, ++}; ++ ++static void rt3883_pci_preinit(unsigned mode) ++{ ++ u32 syscfg1; ++ u32 rstctrl; ++ u32 clkcfg1; ++ ++ if (mode & RT3883_PCI_MODE_PCIE) { ++ u32 val; ++ ++ val = rt3883_sysc_rr(RT3883_SYSC_REG_SYSCFG1); ++ val &= ~(0x30); ++ val |= (2 << 4); ++ rt3883_sysc_wr(val, RT3883_SYSC_REG_SYSCFG1); ++ ++ val = rt3883_sysc_rr(RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ val &= ~BIT(31); ++ rt3883_sysc_wr(val, RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ ++ val = rt3883_sysc_rr(RT3883_SYSC_REG_PCIE_CLK_GEN1); ++ val &= 0x80ffffff; ++ rt3883_sysc_wr(val, RT3883_SYSC_REG_PCIE_CLK_GEN1); ++ ++ val = rt3883_sysc_rr(RT3883_SYSC_REG_PCIE_CLK_GEN1); ++ val |= 0xa << 24; ++ rt3883_sysc_wr(val, RT3883_SYSC_REG_PCIE_CLK_GEN1); ++ ++ val = rt3883_sysc_rr(RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ val |= BIT(31); ++ rt3883_sysc_wr(val, RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ ++ msleep(50); ++ } ++ ++ syscfg1 = rt3883_sysc_rr(RT3883_SYSC_REG_SYSCFG1); ++ syscfg1 &= ~(RT3883_SYSCFG1_PCIE_RC_MODE | ++ RT3883_SYSCFG1_PCI_HOST_MODE); ++ ++ rstctrl = rt3883_sysc_rr(RT3883_SYSC_REG_RSTCTRL); ++ rstctrl |= (RT3883_RSTCTRL_PCI | RT3883_RSTCTRL_PCIE); ++ ++ clkcfg1 = rt3883_sysc_rr(RT3883_SYSC_REG_CLKCFG1); ++ clkcfg1 &= ~(RT3883_CLKCFG1_PCI_CLK_EN | ++ RT3883_CLKCFG1_PCIE_CLK_EN); ++ ++ if (mode & RT3883_PCI_MODE_PCI) { ++ syscfg1 |= RT3883_SYSCFG1_PCI_HOST_MODE; ++ clkcfg1 |= RT3883_CLKCFG1_PCI_CLK_EN; ++ rstctrl &= ~RT3883_RSTCTRL_PCI; ++ } ++ if (mode & RT3883_PCI_MODE_PCIE) { ++ syscfg1 |= RT3883_SYSCFG1_PCI_HOST_MODE | ++ RT3883_SYSCFG1_PCIE_RC_MODE; ++ clkcfg1 |= RT3883_CLKCFG1_PCIE_CLK_EN; ++ rstctrl &= ~RT3883_RSTCTRL_PCIE; ++ } ++ ++ rt3883_sysc_wr(syscfg1, RT3883_SYSC_REG_SYSCFG1); ++ rt3883_sysc_wr(rstctrl, RT3883_SYSC_REG_RSTCTRL); ++ rt3883_sysc_wr(clkcfg1, RT3883_SYSC_REG_CLKCFG1); ++ ++ msleep(500); ++} ++ ++static int rt3883_pcie_ready(void) ++{ ++ u32 status; ++ ++ msleep(500); ++ ++ status = rt3883_pci_rr(RT3883_PCI_REG_STATUS(1)); ++ if (status & BIT(0)) ++ return 0; ++ ++ /* TODO: reset PCIe and turn off PCIe clock */ ++ ++ return -ENODEV; ++} ++ ++void __init rt3883_pci_init(unsigned mode) ++{ ++ u32 val; ++ int err; ++ ++ rt3883_pci_preinit(mode); ++ ++ rt3883_pci_base = ioremap(RT3883_PCI_BASE, PAGE_SIZE); ++ if (rt3883_pci_base == NULL) { ++ pr_err("failed to ioremap PCI registers\n"); ++ return; ++ } ++ ++ rt3883_pci_wr(0, RT3883_PCI_REG_PCICFG_ADDR); ++ if (mode & RT3883_PCI_MODE_PCI) ++ rt3883_pci_wr(BIT(16), RT3883_PCI_REG_PCICFG_ADDR); ++ ++ msleep(500); ++ ++ if (mode & RT3883_PCI_MODE_PCIE) { ++ err = rt3883_pcie_ready(); ++ if (err) ++ return; ++ } ++ ++ if (mode & RT3883_PCI_MODE_PCI) ++ rt3883_pci_wr(0x79, RT3883_PCI_REG_ARBCTL); ++ ++ rt3883_pci_wr(RT3883_PCI_MEM_BASE, RT3883_PCI_REG_MEMBASE); ++ rt3883_pci_wr(RT3883_PCI_IO_BASE, RT3883_PCI_REG_IOBASE); ++ ++ /* PCI */ ++ rt3883_pci_wr(0x03ff0000, RT3883_PCI_REG_BAR0SETUP_ADDR(0)); ++ rt3883_pci_wr(RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0_ADDR(0)); ++ rt3883_pci_wr(0x08021814, RT3883_PCI_REG_ID(0)); ++ rt3883_pci_wr(0x00800001, RT3883_PCI_REG_CLASS(0)); ++ rt3883_pci_wr(0x28801814, RT3883_PCI_REG_SUBID(0)); ++ ++ /* PCIe */ ++ rt3883_pci_wr(0x01ff0000, RT3883_PCI_REG_BAR0SETUP_ADDR(1)); ++ rt3883_pci_wr(RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0_ADDR(1)); ++ rt3883_pci_wr(0x08021814, RT3883_PCI_REG_ID(1)); ++ rt3883_pci_wr(0x06040001, RT3883_PCI_REG_CLASS(1)); ++ rt3883_pci_wr(0x28801814, RT3883_PCI_REG_SUBID(1)); ++ ++ rt3883_pci_irq_init(); ++ ++ /* PCIe */ ++ val = rt3883_pci_read_u32(0, 0x01, 0, PCI_COMMAND); ++ val |= 0x7; ++ rt3883_pci_write_u32(0, 0x01, 0, PCI_COMMAND, val); ++ ++ /* PCI */ ++ val = rt3883_pci_read_u32(0, 0x00, 0, PCI_COMMAND); ++ val |= 0x7; ++ rt3883_pci_write_u32(0, 0x00, 0, PCI_COMMAND, val); ++ ++ ioport_resource.start = rt3883_pci_io_resource.start; ++ ioport_resource.end = rt3883_pci_io_resource.end; ++ ++ register_pci_controller(&rt3883_pci_controller); ++} ++ ++int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ++{ ++ int irq = -1; ++ ++ switch (dev->bus->number) { ++ case 0: ++ switch (PCI_SLOT(dev->devfn)) { ++ case 0x00: ++ rt3883_pci_wr(0x03ff0001, ++ RT3883_PCI_REG_BAR0SETUP_ADDR(0)); ++ rt3883_pci_wr(0x03ff0001, ++ RT3883_PCI_REG_BAR0SETUP_ADDR(1)); ++ ++ rt3883_pci_write_u32(0, 0x00, 0, PCI_BASE_ADDRESS_0, ++ RT3883_MEMORY_BASE); ++ rt3883_pci_read_u32(0, 0x00, 0, PCI_BASE_ADDRESS_0); ++ ++ irq = RT3883_CPU_IRQ_PCI; ++ break; ++ case 0x01: ++ rt3883_pci_write_u32(0, 0x01, 0, PCI_IO_BASE, ++ 0x00000101); ++ break; ++ case 0x11: ++ irq = RT3883_PCI_IRQ_PCI0; ++ break; ++ case 0x12: ++ irq = RT3883_PCI_IRQ_PCI1; ++ break; ++ } ++ break; ++ ++ case 1: ++ irq = RT3883_PCI_IRQ_PCIE; ++ break; ++ ++ default: ++ dev_err(&dev->dev, "no IRQ specified\n"); ++ return irq; ++ } ++ ++ return irq; ++} ++ ++void __init rt3883_pci_set_plat_dev_init(int (*f)(struct pci_dev *dev)) ++{ ++ rt3883_pci_plat_dev_init = f; ++} ++ ++int pcibios_plat_dev_init(struct pci_dev *dev) ++{ ++ if (rt3883_pci_plat_dev_init) ++ return rt3883_pci_plat_dev_init(dev); ++ ++ return 0; ++} +diff --git a/arch/mips/ralink/Kconfig b/arch/mips/ralink/Kconfig +index a3eec2a..2b7b70a 100644 +--- a/arch/mips/ralink/Kconfig ++++ b/arch/mips/ralink/Kconfig +@@ -20,6 +20,7 @@ choice + bool "RT3883" + select USB_ARCH_HAS_OHCI + select USB_ARCH_HAS_EHCI ++ select HW_HAS_PCI + + config SOC_MT7620 + bool "MT7620" +-- +1.7.10.4 + |