diff options
author | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2013-04-07 20:56:18 +0000 |
---|---|---|
committer | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2013-04-07 20:56:18 +0000 |
commit | fdbab48eb7cf1263ce5df1e87371a6ba36297553 (patch) | |
tree | 440fdf5192ec887bc75f2b42a00b75e51c584c2d | |
parent | ccebd1c617423e777204f9c3f078bbc61735e0ac (diff) |
ramips: fix RT3883 PCI driver
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@36261 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r-- | target/linux/ramips/patches-3.8/0131-MIPS-pci-rt3883-rewrite.patch | 856 |
1 files changed, 856 insertions, 0 deletions
diff --git a/target/linux/ramips/patches-3.8/0131-MIPS-pci-rt3883-rewrite.patch b/target/linux/ramips/patches-3.8/0131-MIPS-pci-rt3883-rewrite.patch new file mode 100644 index 0000000000..c493049305 --- /dev/null +++ b/target/linux/ramips/patches-3.8/0131-MIPS-pci-rt3883-rewrite.patch @@ -0,0 +1,856 @@ +--- a/arch/mips/pci/pci-rt3883.c ++++ b/arch/mips/pci/pci-rt3883.c +@@ -1,7 +1,7 @@ + /* +- * Ralink RT3883 SoC PCI support ++ * Ralink RT3662/RT3883 SoC PCI support + * +- * Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org> ++ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> + * + * Parts of this file are based on Ralink's 2.6.21 BSP + * +@@ -16,52 +16,82 @@ + #include <linux/init.h> + #include <linux/delay.h> + #include <linux/interrupt.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_irq.h> ++#include <linux/of_pci.h> ++#include <linux/platform_device.h> + + #include <asm/mach-ralink/rt3883.h> +-#include <asm/mach-ralink/rt3883_regs.h> ++#include <asm/mach-ralink/ralink_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_PCICFG 0x00 ++#define RT3883_PCICFG_P2P_BR_DEVNUM_M 0xf ++#define RT3883_PCICFG_P2P_BR_DEVNUM_S 16 ++#define RT3883_PCICFG_PCIRST BIT(1) ++#define RT3883_PCI_REG_PCIRAW 0x04 ++#define RT3883_PCI_REG_PCIINT 0x08 ++#define RT3883_PCI_REG_PCIENA 0x0c + +-#define RT3883_PCI_REG_CONFIG_ADDR 0x20 +-#define RT3883_PCI_REG_CONFIG_DATA 0x24 ++#define RT3883_PCI_REG_CFGADDR 0x20 ++#define RT3883_PCI_REG_CFGDATA 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_BAR0SETUP(_x) (RT3883_PCI_REG_BASE((_x)) + 0x10) ++#define RT3883_PCI_REG_IMBASEBAR0(_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); ++#define RT3883_PCI_MODE_NONE 0 ++#define RT3883_PCI_MODE_PCI BIT(0) ++#define RT3883_PCI_MODE_PCIE BIT(1) ++#define RT3883_PCI_MODE_BOTH (RT3883_PCI_MODE_PCI | RT3883_PCI_MODE_PCIE) + +-static inline u32 rt3883_pci_rr(unsigned reg) ++#define RT3883_PCI_IRQ_COUNT 32 ++ ++#define RT3883_P2P_BR_DEVNUM 1 ++ ++struct rt3883_pci_controller { ++ void __iomem *base; ++ spinlock_t lock; ++ ++ struct irq_domain *irq_domain; ++ ++ struct pci_controller pci_controller; ++ struct resource io_res; ++ struct resource mem_res; ++ ++ bool pcie_ready; ++ unsigned char p2p_devnum; ++}; ++ ++static inline struct rt3883_pci_controller * ++pci_bus_to_rt3883_controller(struct pci_bus *bus) + { +- return readl(rt3883_pci_base + reg); ++ struct pci_controller *hose; ++ ++ hose = (struct pci_controller *) bus->sysdata; ++ return container_of(hose, struct rt3883_pci_controller, pci_controller); ++} ++ ++static inline u32 rt3883_pci_r32(struct rt3883_pci_controller *rpc, ++ unsigned reg) ++{ ++ return ioread32(rpc->base + reg); + } + +-static inline void rt3883_pci_wr(u32 val, unsigned reg) ++static inline void rt3883_pci_w32(struct rt3883_pci_controller *rpc, ++ u32 val, unsigned reg) + { +- writel(val, rt3883_pci_base + reg); ++ iowrite32(val, rpc->base + reg); + } + + static inline u32 rt3883_pci_get_cfgaddr(unsigned int bus, unsigned int slot, +@@ -71,7 +101,8 @@ static inline u32 rt3883_pci_get_cfgaddr + 0x80000000); + } + +-static u32 rt3883_pci_read_u32(unsigned bus, unsigned slot, ++static u32 rt3883_pci_read_cfg32(struct rt3883_pci_controller *rpc, ++ unsigned bus, unsigned slot, + unsigned func, unsigned reg) + { + unsigned long flags; +@@ -80,15 +111,16 @@ static u32 rt3883_pci_read_u32(unsigned + + 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); ++ spin_lock_irqsave(&rpc->lock, flags); ++ rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); ++ ret = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); ++ spin_unlock_irqrestore(&rpc->lock, flags); + + return ret; + } + +-static void rt3883_pci_write_u32(unsigned bus, unsigned slot, ++static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc, ++ unsigned bus, unsigned slot, + unsigned func, unsigned reg, u32 val) + { + unsigned long flags; +@@ -96,84 +128,61 @@ static void rt3883_pci_write_u32(unsigne + + 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); ++ spin_lock_irqsave(&rpc->lock, flags); ++ rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); ++ rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA); ++ spin_unlock_irqrestore(&rpc->lock, flags); + } + + static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) + { ++ struct rt3883_pci_controller *rpc; + u32 pending; + +- pending = rt3883_pci_rr(RT3883_PCI_REG_PCIINT_ADDR) & +- rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); ++ rpc = irq_get_handler_data(irq); ++ ++ pending = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIINT) & ++ rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); + + if (!pending) { + spurious_interrupt(); + return; + } + +- if (pending & RT3833_PCI_PCIINT_PCI0) +- generic_handle_irq(RT3883_PCI_IRQ_PCI0); ++ while (pending) { ++ unsigned bit = __ffs(pending); + +- if (pending & RT3833_PCI_PCIINT_PCI1) +- generic_handle_irq(RT3883_PCI_IRQ_PCI1); ++ irq = irq_find_mapping(rpc->irq_domain, bit); ++ generic_handle_irq(irq); + +- if (pending & RT3833_PCI_PCIINT_PCIE) +- generic_handle_irq(RT3883_PCI_IRQ_PCIE); ++ pending &= ~BIT(bit); ++ } + } + + static void rt3883_pci_irq_unmask(struct irq_data *d) + { +- int irq = d->irq; +- u32 mask; ++ struct rt3883_pci_controller *rpc; + 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(); +- } ++ rpc = irq_data_get_irq_chip_data(d); + +- t = rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); +- rt3883_pci_wr(t | mask, RT3883_PCI_REG_PCIMSK_ADDR); ++ t = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); ++ rt3883_pci_w32(rpc, t | BIT(d->hwirq), RT3883_PCI_REG_PCIENA); + /* flush write */ +- rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); ++ rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); + } + + static void rt3883_pci_irq_mask(struct irq_data *d) + { +- int irq = d->irq; +- u32 mask; ++ struct rt3883_pci_controller *rpc; + 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(); +- } ++ rpc = irq_data_get_irq_chip_data(d); + +- t = rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); +- rt3883_pci_wr(t & ~mask, RT3883_PCI_REG_PCIMSK_ADDR); ++ t = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); ++ rt3883_pci_w32(rpc, t & ~BIT(d->hwirq), RT3883_PCI_REG_PCIENA); + /* flush write */ +- rt3883_pci_rr(RT3883_PCI_REG_PCIMSK_ADDR); ++ rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA); + } + + static struct irq_chip rt3883_pci_irq_chip = { +@@ -183,36 +192,84 @@ static struct irq_chip rt3883_pci_irq_ch + .irq_mask_ack = rt3883_pci_irq_mask, + }; + +-static void __init rt3883_pci_irq_init(void) ++static int rt3883_pci_irq_map(struct irq_domain *d, unsigned int irq, ++ irq_hw_number_t hw) + { +- int i; ++ irq_set_chip_and_handler(irq, &rt3883_pci_irq_chip, handle_level_irq); ++ irq_set_chip_data(irq, d->host_data); ++ ++ return 0; ++} ++ ++static const struct irq_domain_ops rt3883_pci_irq_domain_ops = { ++ .map = rt3883_pci_irq_map, ++ .xlate = irq_domain_xlate_onecell, ++}; ++ ++static int rt3883_pci_irq_init(struct device *dev, ++ struct rt3883_pci_controller *rpc) ++{ ++ struct device_node *np = dev->of_node; ++ struct device_node *intc_np; ++ int irq; ++ int err; ++ ++ intc_np = of_get_child_by_name(np, "interrupt-controller"); ++ if (!intc_np) { ++ dev_err(dev, "no %s child node found", "interrupt-controller"); ++ return -ENODEV; ++ } ++ ++ irq = irq_of_parse_and_map(intc_np, 0); ++ if (irq == 0) { ++ dev_err(dev, "%s has no IRQ", of_node_full_name(intc_np)); ++ err = -EINVAL; ++ goto err_put_intc; ++ } + + /* disable all interrupts */ +- rt3883_pci_wr(0, RT3883_PCI_REG_PCIMSK_ADDR); ++ rt3883_pci_w32(rpc, 0, RT3883_PCI_REG_PCIENA); + +- 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); ++ rpc->irq_domain = ++ irq_domain_add_linear(intc_np, RT3883_PCI_IRQ_COUNT, ++ &rt3883_pci_irq_domain_ops, ++ rpc); ++ if (!rpc->irq_domain) { ++ dev_err(dev, "unable to add IRQ domain\n"); ++ err = -ENODEV; ++ goto err_put_intc; + } + +- irq_set_chained_handler(RT3883_CPU_IRQ_PCI, rt3883_pci_irq_handler); ++ irq_set_handler_data(irq, rpc); ++ irq_set_chained_handler(irq, rt3883_pci_irq_handler); ++ ++ return 0; ++ ++err_put_intc: ++ of_node_put(intc_np); ++ return err; + } + + static int rt3883_pci_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) + { ++ struct rt3883_pci_controller *rpc; + unsigned long flags; + u32 address; + u32 data; + ++ rpc = pci_bus_to_rt3883_controller(bus); ++ ++ if (!rpc->pcie_ready && bus->number == 1) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ + 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); ++ spin_lock_irqsave(&rpc->lock, flags); ++ rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); ++ data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); ++ spin_unlock_irqrestore(&rpc->lock, flags); + + switch (size) { + case 1: +@@ -232,16 +289,22 @@ static int rt3883_pci_config_read(struct + static int rt3883_pci_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) + { ++ struct rt3883_pci_controller *rpc; + unsigned long flags; + u32 address; + u32 data; + ++ rpc = pci_bus_to_rt3883_controller(bus); ++ ++ if (!rpc->pcie_ready && bus->number == 1) ++ return PCIBIOS_DEVICE_NOT_FOUND; ++ + 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_lock_irqsave(&rpc->lock, flags); ++ rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR); ++ data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA); + + switch (size) { + case 1: +@@ -257,8 +320,8 @@ static int rt3883_pci_config_write(struc + break; + } + +- rt3883_pci_wr(data, RT3883_PCI_REG_CONFIG_DATA); +- spin_unlock_irqrestore(&rt3883_pci_lock, flags); ++ rt3883_pci_w32(rpc, data, RT3883_PCI_REG_CFGDATA); ++ spin_unlock_irqrestore(&rpc->lock, flags); + + return PCIBIOS_SUCCESSFUL; + } +@@ -268,220 +331,310 @@ static struct pci_ops rt3883_pci_ops = { + .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) ++static void rt3883_pci_preinit(struct rt3883_pci_controller *rpc, unsigned mode) + { + u32 syscfg1; + u32 rstctrl; + u32 clkcfg1; ++ u32 t; ++ ++ rstctrl = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL); ++ syscfg1 = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1); ++ clkcfg1 = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1); + + if (mode & RT3883_PCI_MODE_PCIE) { +- u32 val; ++ rstctrl |= RT3883_RSTCTRL_PCIE; ++ rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL); + +- 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); ++ /* setup PCI PAD drive mode */ ++ syscfg1 &= ~(0x30); ++ syscfg1 |= (2 << 4); ++ rt_sysc_w32(syscfg1, RT3883_SYSC_REG_SYSCFG1); ++ ++ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ t &= ~BIT(31); ++ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ ++ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN1); ++ t &= 0x80ffffff; ++ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN1); ++ ++ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN1); ++ t |= 0xa << 24; ++ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN1); ++ ++ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ t |= BIT(31); ++ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0); + + msleep(50); ++ ++ rstctrl &= ~RT3883_RSTCTRL_PCIE; ++ rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL); + } + +- 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); ++ syscfg1 |= (RT3883_SYSCFG1_PCIE_RC_MODE | RT3883_SYSCFG1_PCI_HOST_MODE); ++ ++ 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); ++ rt_sysc_w32(syscfg1, RT3883_SYSC_REG_SYSCFG1); ++ rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL); ++ rt_sysc_w32(clkcfg1, RT3883_SYSC_REG_CLKCFG1); + + msleep(500); +-} + +-static int rt3883_pcie_ready(void) +-{ +- u32 status; ++ /* ++ * setup the device number of the P2P bridge ++ * and de-assert the reset line ++ */ ++ t = (RT3883_P2P_BR_DEVNUM << RT3883_PCICFG_P2P_BR_DEVNUM_S); ++ rt3883_pci_w32(rpc, t, RT3883_PCI_REG_PCICFG); + ++ /* flush write */ ++ rt3883_pci_r32(rpc, RT3883_PCI_REG_PCICFG); + msleep(500); + +- status = rt3883_pci_rr(RT3883_PCI_REG_STATUS(1)); +- if (status & BIT(0)) +- return 0; ++ if (mode & RT3883_PCI_MODE_PCIE) { ++ msleep(500); ++ ++ t = rt3883_pci_r32(rpc, RT3883_PCI_REG_STATUS(1)); ++ ++ rpc->pcie_ready = t & BIT(0); ++ ++ if (!rpc->pcie_ready) { ++ /* reset the PCIe block */ ++ t = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL); ++ t |= RT3883_RSTCTRL_PCIE; ++ rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL); ++ t &= ~RT3883_RSTCTRL_PCIE; ++ rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL); ++ ++ /* turn off PCIe clock */ ++ t = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1); ++ t &= ~RT3883_CLKCFG1_PCIE_CLK_EN; ++ rt_sysc_w32(t, RT3883_SYSC_REG_CLKCFG1); ++ ++ t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ t &= ~0xf000c080; ++ rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0); ++ } ++ } ++ ++ /* enable PCI arbiter */ ++ rt3883_pci_w32(rpc, 0x79, RT3883_PCI_REG_ARBCTL); ++} + +- /* TODO: reset PCIe and turn off PCIe clock */ ++static inline void ++rt3883_dump_pci_config(struct rt3883_pci_controller *rpc, ++ int bus, int slot) ++{ ++ int i; ++ ++ for (i = 0; i < 16; i++) { ++ u32 val; + +- return -ENODEV; ++ val = rt3883_pci_read_cfg32(rpc, bus, slot, 0, i << 2); ++ pr_info("pci %02x:%02x.0 0x%02x = %08x\n", ++ bus, slot, i << 2, val); ++ } + } + +-void __init rt3883_pci_init(unsigned mode) ++static int rt3883_pci_probe(struct platform_device *pdev) + { ++ struct rt3883_pci_controller *rpc; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct resource *res; ++ struct device_node *child; + u32 val; + int err; ++ int mode; + +- rt3883_pci_preinit(mode); ++ rpc = devm_kzalloc(dev, sizeof(*rpc), GFP_KERNEL); ++ if (!rpc) ++ return -ENOMEM; ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ if (!res) ++ return -EINVAL; ++ ++ rpc->base = devm_ioremap_resource(dev, res); ++ if (IS_ERR(rpc->base)) ++ return PTR_ERR(rpc->base); ++ ++ rpc->pci_controller.of_node = of_get_child_by_name(np, "host-bridge"); ++ if (!rpc->pci_controller.of_node) { ++ dev_err(dev, "no %s child node found", "host-bridge"); ++ return -ENODEV; ++ } ++ ++ mode = RT3883_PCI_MODE_NONE; ++ for_each_child_of_node(rpc->pci_controller.of_node, child) { ++ u32 slot; ++ ++ if (!of_device_is_available(child)) ++ continue; ++ ++ if (of_property_read_u32(child, "ralink,pci-slot", ++ &slot)) { ++ dev_err(dev, "no '%s' property found for %s\n", ++ "ralink,pci-slot", ++ of_node_full_name(child)); ++ continue; ++ } + +- rt3883_pci_base = ioremap(RT3883_PCI_BASE, PAGE_SIZE); +- if (rt3883_pci_base == NULL) { +- pr_err("failed to ioremap PCI registers\n"); +- return; ++ switch (slot) { ++ case 1: ++ mode |= RT3883_PCI_MODE_PCIE; ++ break; ++ ++ case 17: ++ case 18: ++ mode |= RT3883_PCI_MODE_PCI; ++ break; ++ } + } + +- 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); ++ if (mode == RT3883_PCI_MODE_NONE) { ++ dev_err(dev, "unable to determine PCI mode\n"); ++ err = -EINVAL; ++ goto err_put_hb_node; ++ } + +- msleep(500); ++ dev_info(dev, "mode:%s%s\n", ++ (mode & RT3883_PCI_MODE_PCI) ? " PCI" : "", ++ (mode & RT3883_PCI_MODE_PCIE) ? " PCIe" : ""); + +- if (mode & RT3883_PCI_MODE_PCIE) { +- err = rt3883_pcie_ready(); +- if (err) +- return; +- } ++ rt3883_pci_preinit(rpc, mode); + +- if (mode & RT3883_PCI_MODE_PCI) +- rt3883_pci_wr(0x79, RT3883_PCI_REG_ARBCTL); ++ rpc->pci_controller.pci_ops = &rt3883_pci_ops; ++ rpc->pci_controller.io_resource = &rpc->io_res; ++ rpc->pci_controller.mem_resource = &rpc->mem_res; + +- rt3883_pci_wr(RT3883_PCI_MEM_BASE, RT3883_PCI_REG_MEMBASE); +- rt3883_pci_wr(RT3883_PCI_IO_BASE, RT3883_PCI_REG_IOBASE); ++ /* Load PCI I/O and memory resources from DT */ ++ pci_load_of_ranges(&rpc->pci_controller, ++ rpc->pci_controller.of_node); ++ ++ rt3883_pci_w32(rpc, rpc->mem_res.start, RT3883_PCI_REG_MEMBASE); ++ rt3883_pci_w32(rpc, rpc->io_res.start, RT3883_PCI_REG_IOBASE); ++ ++ ioport_resource.start = rpc->io_res.start; ++ ioport_resource.end = rpc->io_res.end; + + /* 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)); ++ rt3883_pci_w32(rpc, 0x03ff0000, RT3883_PCI_REG_BAR0SETUP(0)); ++ rt3883_pci_w32(rpc, RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0(0)); ++ rt3883_pci_w32(rpc, 0x08021814, RT3883_PCI_REG_ID(0)); ++ rt3883_pci_w32(rpc, 0x00800001, RT3883_PCI_REG_CLASS(0)); ++ rt3883_pci_w32(rpc, 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(); ++ rt3883_pci_w32(rpc, 0x03ff0000, RT3883_PCI_REG_BAR0SETUP(1)); ++ rt3883_pci_w32(rpc, RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0(1)); ++ rt3883_pci_w32(rpc, 0x08021814, RT3883_PCI_REG_ID(1)); ++ rt3883_pci_w32(rpc, 0x06040001, RT3883_PCI_REG_CLASS(1)); ++ rt3883_pci_w32(rpc, 0x28801814, RT3883_PCI_REG_SUBID(1)); ++ ++ err = rt3883_pci_irq_init(dev, rpc); ++ if (err) ++ goto err_put_hb_node; + + /* PCIe */ +- val = rt3883_pci_read_u32(0, 0x01, 0, PCI_COMMAND); +- val |= 0x7; +- rt3883_pci_write_u32(0, 0x01, 0, PCI_COMMAND, val); ++ val = rt3883_pci_read_cfg32(rpc, 0, 0x01, 0, PCI_COMMAND); ++ val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; ++ rt3883_pci_write_cfg32(rpc, 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); ++ val = rt3883_pci_read_cfg32(rpc, 0, 0x00, 0, PCI_COMMAND); ++ val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; ++ rt3883_pci_write_cfg32(rpc, 0, 0x00, 0, PCI_COMMAND, val); ++ ++ if (mode == RT3883_PCI_MODE_PCIE) { ++ rt3883_pci_w32(rpc, 0x03ff0001, RT3883_PCI_REG_BAR0SETUP(0)); ++ rt3883_pci_w32(rpc, 0x03ff0001, RT3883_PCI_REG_BAR0SETUP(1)); ++ ++ rt3883_pci_write_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0, ++ PCI_BASE_ADDRESS_0, ++ RT3883_MEMORY_BASE); ++ /* flush write */ ++ rt3883_pci_read_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0, ++ PCI_BASE_ADDRESS_0); ++ } else { ++ rt3883_pci_write_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0, ++ PCI_IO_BASE, 0x00000101); ++ } ++ ++ register_pci_controller(&rpc->pci_controller); + +- ioport_resource.start = rt3883_pci_io_resource.start; +- ioport_resource.end = rt3883_pci_io_resource.end; ++ return 0; + +- register_pci_controller(&rt3883_pci_controller); ++err_put_hb_node: ++ of_node_put(rpc->pci_controller.of_node); ++ return err; + } + + 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; ++ struct rt3883_pci_controller *rpc; ++ struct of_irq dev_irq; ++ int err; ++ int irq; + +- default: +- dev_err(&dev->dev, "no IRQ specified\n"); +- return irq; ++ rpc = pci_bus_to_rt3883_controller(dev->bus); ++ err = of_irq_map_pci(dev, &dev_irq); ++ if (err) { ++ pr_err("pci %s: unable to get irq map, err=%d\n", ++ pci_name((struct pci_dev *) dev), err); ++ return 0; + } + ++ irq = irq_create_of_mapping(dev_irq.controller, ++ dev_irq.specifier, ++ dev_irq.size); ++ ++ if (irq == 0) ++ pr_crit("pci %s: no irq found for pin %u\n", ++ pci_name((struct pci_dev *) dev), pin); ++ else ++ pr_info("pci %s: using irq %d for pin %u\n", ++ pci_name((struct pci_dev *) dev), irq, pin); ++ + return irq; + } + +-void __init rt3883_pci_set_plat_dev_init(int (*f)(struct pci_dev *dev)) ++int pcibios_plat_dev_init(struct pci_dev *dev) + { +- rt3883_pci_plat_dev_init = f; ++ return 0; + } + +-int pcibios_plat_dev_init(struct pci_dev *dev) +-{ +- if (rt3883_pci_plat_dev_init) +- return rt3883_pci_plat_dev_init(dev); ++static const struct of_device_id rt3883_pci_ids[] = { ++ { .compatible = "ralink,rt3883-pci" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, rt3883_pci_ids); + +- return 0; ++static struct platform_driver rt3883_pci_driver = { ++ .probe = rt3883_pci_probe, ++ .driver = { ++ .name = "rt3883-pci", ++ .owner = THIS_MODULE, ++ .of_match_table = of_match_ptr(rt3883_pci_ids), ++ }, ++}; ++ ++static int __init rt3883_pci_init(void) ++{ ++ return platform_driver_register(&rt3883_pci_driver); + } ++ ++postcore_initcall(rt3883_pci_init); |