mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-30 21:46:31 +00:00
2722090af4
Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. The advantage in doing so is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h was the source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each obj-y/bool instance for the presence of either and replace as needed. We also needed to remove the no-op MODULE_DEVICE_TABLE usage in several instances to permit removal of the module.h include. The files in these instances were all controlled by bool Kconfig. In one instance, module_param was being used so we transition the module.h include onto a moduleparam.h include. Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14035/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
597 lines
15 KiB
C
597 lines
15 KiB
C
/*
|
|
* Ralink RT3662/RT3883 SoC PCI support
|
|
*
|
|
* Copyright (C) 2011-2013 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 <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/ralink_regs.h>
|
|
|
|
#define RT3883_MEMORY_BASE 0x00000000
|
|
#define RT3883_MEMORY_SIZE 0x02000000
|
|
|
|
#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_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(_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)
|
|
|
|
#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)
|
|
|
|
#define RT3883_PCI_IRQ_COUNT 32
|
|
|
|
#define RT3883_P2P_BR_DEVNUM 1
|
|
|
|
struct rt3883_pci_controller {
|
|
void __iomem *base;
|
|
|
|
struct device_node *intc_of_node;
|
|
struct irq_domain *irq_domain;
|
|
|
|
struct pci_controller pci_controller;
|
|
struct resource io_res;
|
|
struct resource mem_res;
|
|
|
|
bool pcie_ready;
|
|
};
|
|
|
|
static inline struct rt3883_pci_controller *
|
|
pci_bus_to_rt3883_controller(struct pci_bus *bus)
|
|
{
|
|
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_w32(struct rt3883_pci_controller *rpc,
|
|
u32 val, unsigned reg)
|
|
{
|
|
iowrite32(val, rpc->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_cfg32(struct rt3883_pci_controller *rpc,
|
|
unsigned bus, unsigned slot,
|
|
unsigned func, unsigned reg)
|
|
{
|
|
unsigned long flags;
|
|
u32 address;
|
|
u32 ret;
|
|
|
|
address = rt3883_pci_get_cfgaddr(bus, slot, func, reg);
|
|
|
|
rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
|
|
ret = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc,
|
|
unsigned bus, unsigned slot,
|
|
unsigned func, unsigned reg, u32 val)
|
|
{
|
|
unsigned long flags;
|
|
u32 address;
|
|
|
|
address = rt3883_pci_get_cfgaddr(bus, slot, func, reg);
|
|
|
|
rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
|
|
rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA);
|
|
}
|
|
|
|
static void rt3883_pci_irq_handler(struct irq_desc *desc)
|
|
{
|
|
struct rt3883_pci_controller *rpc;
|
|
u32 pending;
|
|
|
|
rpc = irq_desc_get_handler_data(desc);
|
|
|
|
pending = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIINT) &
|
|
rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
|
|
|
|
if (!pending) {
|
|
spurious_interrupt();
|
|
return;
|
|
}
|
|
|
|
while (pending) {
|
|
unsigned irq, bit = __ffs(pending);
|
|
|
|
irq = irq_find_mapping(rpc->irq_domain, bit);
|
|
generic_handle_irq(irq);
|
|
|
|
pending &= ~BIT(bit);
|
|
}
|
|
}
|
|
|
|
static void rt3883_pci_irq_unmask(struct irq_data *d)
|
|
{
|
|
struct rt3883_pci_controller *rpc;
|
|
u32 t;
|
|
|
|
rpc = irq_data_get_irq_chip_data(d);
|
|
|
|
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_r32(rpc, RT3883_PCI_REG_PCIENA);
|
|
}
|
|
|
|
static void rt3883_pci_irq_mask(struct irq_data *d)
|
|
{
|
|
struct rt3883_pci_controller *rpc;
|
|
u32 t;
|
|
|
|
rpc = irq_data_get_irq_chip_data(d);
|
|
|
|
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_r32(rpc, RT3883_PCI_REG_PCIENA);
|
|
}
|
|
|
|
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 int rt3883_pci_irq_map(struct irq_domain *d, unsigned int irq,
|
|
irq_hw_number_t hw)
|
|
{
|
|
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)
|
|
{
|
|
int irq;
|
|
|
|
irq = irq_of_parse_and_map(rpc->intc_of_node, 0);
|
|
if (irq == 0) {
|
|
dev_err(dev, "%s has no IRQ",
|
|
of_node_full_name(rpc->intc_of_node));
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* disable all interrupts */
|
|
rt3883_pci_w32(rpc, 0, RT3883_PCI_REG_PCIENA);
|
|
|
|
rpc->irq_domain =
|
|
irq_domain_add_linear(rpc->intc_of_node, RT3883_PCI_IRQ_COUNT,
|
|
&rt3883_pci_irq_domain_ops,
|
|
rpc);
|
|
if (!rpc->irq_domain) {
|
|
dev_err(dev, "unable to add IRQ domain\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
irq_set_chained_handler_and_data(irq, rt3883_pci_irq_handler, rpc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
|
|
rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
|
|
data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
|
|
|
|
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)
|
|
{
|
|
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);
|
|
|
|
rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
|
|
data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
|
|
|
|
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_w32(rpc, data, RT3883_PCI_REG_CFGDATA);
|
|
|
|
return PCIBIOS_SUCCESSFUL;
|
|
}
|
|
|
|
static struct pci_ops rt3883_pci_ops = {
|
|
.read = rt3883_pci_config_read,
|
|
.write = rt3883_pci_config_write,
|
|
};
|
|
|
|
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) {
|
|
rstctrl |= RT3883_RSTCTRL_PCIE;
|
|
rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL);
|
|
|
|
/* 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_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) {
|
|
clkcfg1 |= RT3883_CLKCFG1_PCI_CLK_EN;
|
|
rstctrl &= ~RT3883_RSTCTRL_PCI;
|
|
}
|
|
|
|
if (mode & RT3883_PCI_MODE_PCIE) {
|
|
clkcfg1 |= RT3883_CLKCFG1_PCIE_CLK_EN;
|
|
rstctrl &= ~RT3883_RSTCTRL_PCIE;
|
|
}
|
|
|
|
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);
|
|
|
|
/*
|
|
* 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);
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
|
|
rpc = devm_kzalloc(dev, sizeof(*rpc), GFP_KERNEL);
|
|
if (!rpc)
|
|
return -ENOMEM;
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
rpc->base = devm_ioremap_resource(dev, res);
|
|
if (IS_ERR(rpc->base))
|
|
return PTR_ERR(rpc->base);
|
|
|
|
/* find the interrupt controller child node */
|
|
for_each_child_of_node(np, child) {
|
|
if (of_get_property(child, "interrupt-controller", NULL)) {
|
|
rpc->intc_of_node = child;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!rpc->intc_of_node) {
|
|
dev_err(dev, "%s has no %s child node",
|
|
of_node_full_name(rpc->intc_of_node),
|
|
"interrupt controller");
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* find the PCI host bridge child node */
|
|
for_each_child_of_node(np, child) {
|
|
if (child->type &&
|
|
of_node_cmp(child->type, "pci") == 0) {
|
|
rpc->pci_controller.of_node = child;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!rpc->pci_controller.of_node) {
|
|
dev_err(dev, "%s has no %s child node",
|
|
of_node_full_name(rpc->intc_of_node),
|
|
"PCI host bridge");
|
|
err = -EINVAL;
|
|
goto err_put_intc_node;
|
|
}
|
|
|
|
mode = RT3883_PCI_MODE_NONE;
|
|
for_each_available_child_of_node(rpc->pci_controller.of_node, child) {
|
|
int devfn;
|
|
|
|
if (!child->type ||
|
|
of_node_cmp(child->type, "pci") != 0)
|
|
continue;
|
|
|
|
devfn = of_pci_get_devfn(child);
|
|
if (devfn < 0)
|
|
continue;
|
|
|
|
switch (PCI_SLOT(devfn)) {
|
|
case 1:
|
|
mode |= RT3883_PCI_MODE_PCIE;
|
|
break;
|
|
|
|
case 17:
|
|
case 18:
|
|
mode |= RT3883_PCI_MODE_PCI;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (mode == RT3883_PCI_MODE_NONE) {
|
|
dev_err(dev, "unable to determine PCI mode\n");
|
|
err = -EINVAL;
|
|
goto err_put_hb_node;
|
|
}
|
|
|
|
dev_info(dev, "mode:%s%s\n",
|
|
(mode & RT3883_PCI_MODE_PCI) ? " PCI" : "",
|
|
(mode & RT3883_PCI_MODE_PCIE) ? " PCIe" : "");
|
|
|
|
rt3883_pci_preinit(rpc, mode);
|
|
|
|
rpc->pci_controller.pci_ops = &rt3883_pci_ops;
|
|
rpc->pci_controller.io_resource = &rpc->io_res;
|
|
rpc->pci_controller.mem_resource = &rpc->mem_res;
|
|
|
|
/* 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_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_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_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_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);
|
|
|
|
return 0;
|
|
|
|
err_put_hb_node:
|
|
of_node_put(rpc->pci_controller.of_node);
|
|
err_put_intc_node:
|
|
of_node_put(rpc->intc_of_node);
|
|
return err;
|
|
}
|
|
|
|
int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|
{
|
|
return of_irq_parse_and_map_pci(dev, slot, pin);
|
|
}
|
|
|
|
int pcibios_plat_dev_init(struct pci_dev *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id rt3883_pci_ids[] = {
|
|
{ .compatible = "ralink,rt3883-pci" },
|
|
{},
|
|
};
|
|
|
|
static struct platform_driver rt3883_pci_driver = {
|
|
.probe = rt3883_pci_probe,
|
|
.driver = {
|
|
.name = "rt3883-pci",
|
|
.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);
|