diff options
Diffstat (limited to 'arch/mips/pci')
-rw-r--r-- | arch/mips/pci/fixup-cobalt.c | 8 | ||||
-rw-r--r-- | arch/mips/pci/fixup-malta.c | 14 | ||||
-rw-r--r-- | arch/mips/pci/fixup-rc32434.c | 2 | ||||
-rw-r--r-- | arch/mips/pci/ops-bcm63xx.c | 63 | ||||
-rw-r--r-- | arch/mips/pci/pci-bcm63xx.c | 133 | ||||
-rw-r--r-- | arch/mips/pci/pci-bcm63xx.h | 5 |
6 files changed, 213 insertions, 12 deletions
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c index 9553b14002dd..3e7ce65d776c 100644 --- a/arch/mips/pci/fixup-cobalt.c +++ b/arch/mips/pci/fixup-cobalt.c @@ -37,7 +37,7 @@ #define VIA_COBALT_BRD_ID_REG 0x94 #define VIA_COBALT_BRD_REG_to_ID(reg) ((unsigned char)(reg) >> 4) -static void qube_raq_galileo_early_fixup(struct pci_dev *dev) +static void __devinit qube_raq_galileo_early_fixup(struct pci_dev *dev) { if (dev->devfn == PCI_DEVFN(0, 0) && (dev->class >> 8) == PCI_CLASS_MEMORY_OTHER) { @@ -51,7 +51,7 @@ static void qube_raq_galileo_early_fixup(struct pci_dev *dev) DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111, qube_raq_galileo_early_fixup); -static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev) +static void __devinit qube_raq_via_bmIDE_fixup(struct pci_dev *dev) { unsigned short cfgword; unsigned char lt; @@ -74,7 +74,7 @@ static void qube_raq_via_bmIDE_fixup(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, qube_raq_via_bmIDE_fixup); -static void qube_raq_galileo_fixup(struct pci_dev *dev) +static void __devinit qube_raq_galileo_fixup(struct pci_dev *dev) { if (dev->devfn != PCI_DEVFN(0, 0)) return; @@ -129,7 +129,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111, int cobalt_board_id; -static void qube_raq_via_board_id_fixup(struct pci_dev *dev) +static void __devinit qube_raq_via_board_id_fixup(struct pci_dev *dev) { u8 id; int retval; diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c index 70073c98ed32..819622f93e9c 100644 --- a/arch/mips/pci/fixup-malta.c +++ b/arch/mips/pci/fixup-malta.c @@ -101,3 +101,17 @@ static void __devinit malta_piix_func1_fixup(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, malta_piix_func1_fixup); + +/* Enable PCI 2.1 compatibility in PIIX4 */ +static void __devinit quirk_dlcsetup(struct pci_dev *dev) +{ + u8 odlc, ndlc; + + (void) pci_read_config_byte(dev, 0x82, &odlc); + /* Enable passive releases and delayed transaction */ + ndlc = odlc | 7; + (void) pci_write_config_byte(dev, 0x82, ndlc); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, + quirk_dlcsetup); diff --git a/arch/mips/pci/fixup-rc32434.c b/arch/mips/pci/fixup-rc32434.c index 3d86823d03a0..76bb1be99d43 100644 --- a/arch/mips/pci/fixup-rc32434.c +++ b/arch/mips/pci/fixup-rc32434.c @@ -47,7 +47,7 @@ int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) return irq + GROUP4_IRQ_BASE + 4; } -static void rc32434_pci_early_fixup(struct pci_dev *dev) +static void __devinit rc32434_pci_early_fixup(struct pci_dev *dev) { if (PCI_SLOT(dev->devfn) == 6 && dev->bus->number == 0) { /* disable prefetched memory range */ diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index 822ae179bc56..65c7bd100486 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c @@ -411,7 +411,7 @@ struct pci_ops bcm63xx_cb_ops = { * only one IO window, so it cannot be shared by PCI and cardbus, use * fixup to choose and detect unhandled configuration */ -static void bcm63xx_fixup(struct pci_dev *dev) +static void __devinit bcm63xx_fixup(struct pci_dev *dev) { static int io_window = -1; int i, found, new_io_window; @@ -465,3 +465,64 @@ static void bcm63xx_fixup(struct pci_dev *dev) DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, bcm63xx_fixup); #endif + +static int bcm63xx_pcie_can_access(struct pci_bus *bus, int devfn) +{ + switch (bus->number) { + case PCIE_BUS_BRIDGE: + return (PCI_SLOT(devfn) == 0); + case PCIE_BUS_DEVICE: + if (PCI_SLOT(devfn) == 0) + return bcm_pcie_readl(PCIE_DLSTATUS_REG) + & DLSTATUS_PHYLINKUP; + default: + return false; + } +} + +static int bcm63xx_pcie_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + u32 data; + u32 reg = where & ~3; + + if (!bcm63xx_pcie_can_access(bus, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (bus->number == PCIE_BUS_DEVICE) + reg += PCIE_DEVICE_OFFSET; + + data = bcm_pcie_readl(reg); + + *val = postprocess_read(data, where, size); + + return PCIBIOS_SUCCESSFUL; + +} + +static int bcm63xx_pcie_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + u32 data; + u32 reg = where & ~3; + + if (!bcm63xx_pcie_can_access(bus, devfn)) + return PCIBIOS_DEVICE_NOT_FOUND; + + if (bus->number == PCIE_BUS_DEVICE) + reg += PCIE_DEVICE_OFFSET; + + + data = bcm_pcie_readl(reg); + + data = preprocess_write(data, val, where, size); + bcm_pcie_writel(data, reg); + + return PCIBIOS_SUCCESSFUL; +} + + +struct pci_ops bcm63xx_pcie_ops = { + .read = bcm63xx_pcie_read, + .write = bcm63xx_pcie_write +}; diff --git a/arch/mips/pci/pci-bcm63xx.c b/arch/mips/pci/pci-bcm63xx.c index 39eb7c417e2f..8a48139d219c 100644 --- a/arch/mips/pci/pci-bcm63xx.c +++ b/arch/mips/pci/pci-bcm63xx.c @@ -10,6 +10,7 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/init.h> +#include <linux/delay.h> #include <asm/bootinfo.h> #include "pci-bcm63xx.h" @@ -71,6 +72,26 @@ struct pci_controller bcm63xx_cb_controller = { }; #endif +static struct resource bcm_pcie_mem_resource = { + .name = "bcm63xx PCIe memory space", + .start = BCM_PCIE_MEM_BASE_PA, + .end = BCM_PCIE_MEM_END_PA, + .flags = IORESOURCE_MEM, +}; + +static struct resource bcm_pcie_io_resource = { + .name = "bcm63xx PCIe IO space", + .start = 0, + .end = 0, + .flags = 0, +}; + +struct pci_controller bcm63xx_pcie_controller = { + .pci_ops = &bcm63xx_pcie_ops, + .io_resource = &bcm_pcie_io_resource, + .mem_resource = &bcm_pcie_mem_resource, +}; + static u32 bcm63xx_int_cfg_readl(u32 reg) { u32 tmp; @@ -94,17 +115,99 @@ static void bcm63xx_int_cfg_writel(u32 val, u32 reg) void __iomem *pci_iospace_start; -static int __init bcm63xx_pci_init(void) +static void __init bcm63xx_reset_pcie(void) { - unsigned int mem_size; u32 val; - if (!BCMCPU_IS_6348() && !BCMCPU_IS_6358() && !BCMCPU_IS_6368()) - return -ENODEV; + /* enable clock */ + val = bcm_perf_readl(PERF_CKCTL_REG); + val |= CKCTL_6328_PCIE_EN; + bcm_perf_writel(val, PERF_CKCTL_REG); + + /* enable SERDES */ + val = bcm_misc_readl(MISC_SERDES_CTRL_REG); + val |= SERDES_PCIE_EN | SERDES_PCIE_EXD_EN; + bcm_misc_writel(val, MISC_SERDES_CTRL_REG); + + /* reset the PCIe core */ + val = bcm_perf_readl(PERF_SOFTRESET_6328_REG); + + val &= ~SOFTRESET_6328_PCIE_MASK; + val &= ~SOFTRESET_6328_PCIE_CORE_MASK; + val &= ~SOFTRESET_6328_PCIE_HARD_MASK; + val &= ~SOFTRESET_6328_PCIE_EXT_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(10); + + val |= SOFTRESET_6328_PCIE_MASK; + val |= SOFTRESET_6328_PCIE_CORE_MASK; + val |= SOFTRESET_6328_PCIE_HARD_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(10); + + val |= SOFTRESET_6328_PCIE_EXT_MASK; + bcm_perf_writel(val, PERF_SOFTRESET_6328_REG); + mdelay(200); +} - if (!bcm63xx_pci_enabled) - return -ENODEV; +static int __init bcm63xx_register_pcie(void) +{ + u32 val; + bcm63xx_reset_pcie(); + + /* configure the PCIe bridge */ + val = bcm_pcie_readl(PCIE_BRIDGE_OPT1_REG); + val |= OPT1_RD_BE_OPT_EN; + val |= OPT1_RD_REPLY_BE_FIX_EN; + val |= OPT1_PCIE_BRIDGE_HOLE_DET_EN; + val |= OPT1_L1_INT_STATUS_MASK_POL; + bcm_pcie_writel(val, PCIE_BRIDGE_OPT1_REG); + + /* setup the interrupts */ + val = bcm_pcie_readl(PCIE_BRIDGE_RC_INT_MASK_REG); + val |= PCIE_RC_INT_A | PCIE_RC_INT_B | PCIE_RC_INT_C | PCIE_RC_INT_D; + bcm_pcie_writel(val, PCIE_BRIDGE_RC_INT_MASK_REG); + + val = bcm_pcie_readl(PCIE_BRIDGE_OPT2_REG); + /* enable credit checking and error checking */ + val |= OPT2_TX_CREDIT_CHK_EN; + val |= OPT2_UBUS_UR_DECODE_DIS; + + /* set device bus/func for the pcie device */ + val |= (PCIE_BUS_DEVICE << OPT2_CFG_TYPE1_BUS_NO_SHIFT); + val |= OPT2_CFG_TYPE1_BD_SEL; + bcm_pcie_writel(val, PCIE_BRIDGE_OPT2_REG); + + /* setup class code as bridge */ + val = bcm_pcie_readl(PCIE_IDVAL3_REG); + val &= ~IDVAL3_CLASS_CODE_MASK; + val |= (PCI_CLASS_BRIDGE_PCI << IDVAL3_SUBCLASS_SHIFT); + bcm_pcie_writel(val, PCIE_IDVAL3_REG); + + /* disable bar1 size */ + val = bcm_pcie_readl(PCIE_CONFIG2_REG); + val &= ~CONFIG2_BAR1_SIZE_MASK; + bcm_pcie_writel(val, PCIE_CONFIG2_REG); + + /* set bar0 to little endian */ + val = (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_BASE_SHIFT; + val |= (BCM_PCIE_MEM_BASE_PA >> 20) << BASEMASK_MASK_SHIFT; + val |= BASEMASK_REMAP_EN; + bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_BASEMASK_REG); + + val = (BCM_PCIE_MEM_BASE_PA >> 20) << REBASE_ADDR_BASE_SHIFT; + bcm_pcie_writel(val, PCIE_BRIDGE_BAR0_REBASE_ADDR_REG); + + register_pci_controller(&bcm63xx_pcie_controller); + + return 0; +} + +static int __init bcm63xx_register_pci(void) +{ + unsigned int mem_size; + u32 val; /* * configuration access are done through IO space, remap 4 * first bytes to access it from CPU. @@ -221,4 +324,22 @@ static int __init bcm63xx_pci_init(void) return 0; } + +static int __init bcm63xx_pci_init(void) +{ + if (!bcm63xx_pci_enabled) + return -ENODEV; + + switch (bcm63xx_get_cpu_id()) { + case BCM6328_CPU_ID: + return bcm63xx_register_pcie(); + case BCM6348_CPU_ID: + case BCM6358_CPU_ID: + case BCM6368_CPU_ID: + return bcm63xx_register_pci(); + default: + return -ENODEV; + } +} + arch_initcall(bcm63xx_pci_init); diff --git a/arch/mips/pci/pci-bcm63xx.h b/arch/mips/pci/pci-bcm63xx.h index a6e594ef3d6a..e6736d558ac7 100644 --- a/arch/mips/pci/pci-bcm63xx.h +++ b/arch/mips/pci/pci-bcm63xx.h @@ -13,11 +13,16 @@ */ #define CARDBUS_PCI_IDSEL 0x8 + +#define PCIE_BUS_BRIDGE 0 +#define PCIE_BUS_DEVICE 1 + /* * defined in ops-bcm63xx.c */ extern struct pci_ops bcm63xx_pci_ops; extern struct pci_ops bcm63xx_cb_ops; +extern struct pci_ops bcm63xx_pcie_ops; /* * defined in pci-bcm63xx.c |