diff options
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r-- | arch/powerpc/sysdev/Makefile | 6 | ||||
-rw-r--r-- | arch/powerpc/sysdev/axonram.c | 2 | ||||
-rw-r--r-- | arch/powerpc/sysdev/cpm2.c | 2 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_msi.c | 9 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 138 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.h | 6 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_rio.c | 17 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.c | 14 | ||||
-rw-r--r-- | arch/powerpc/sysdev/indirect_pci.c | 4 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ipic.c | 4 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpc5xxx_clocks.c | 33 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 66 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 8 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/qe.c | 84 | ||||
-rw-r--r-- | arch/powerpc/sysdev/qe_lib/qe_ic.c | 4 | ||||
-rw-r--r-- | arch/powerpc/sysdev/tsi108_pci.c | 4 | ||||
-rw-r--r-- | arch/powerpc/sysdev/uic.c | 3 | ||||
-rw-r--r-- | arch/powerpc/sysdev/xilinx_intc.c | 81 | ||||
-rw-r--r-- | arch/powerpc/sysdev/xilinx_pci.c | 132 |
19 files changed, 500 insertions, 117 deletions
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index b33b28a..9d4b174 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -1,3 +1,5 @@ +subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror + ifeq ($(CONFIG_PPC64),y) EXTRA_CFLAGS += -mno-minimal-toc endif @@ -34,6 +36,7 @@ obj-$(CONFIG_IPIC) += ipic.o obj-$(CONFIG_4xx) += uic.o obj-$(CONFIG_4xx_SOC) += ppc4xx_soc.o obj-$(CONFIG_XILINX_VIRTEX) += xilinx_intc.o +obj-$(CONFIG_XILINX_PCI) += xilinx_pci.o obj-$(CONFIG_OF_RTC) += of_rtc.o ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_4xx) += ppc4xx_pci.o @@ -47,6 +50,9 @@ obj-$(CONFIG_PPC_DCR) += dcr.o obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o obj-$(CONFIG_UCODE_PATCH) += micropatch.o +obj-$(CONFIG_PPC_MPC512x) += mpc5xxx_clocks.o +obj-$(CONFIG_PPC_MPC52xx) += mpc5xxx_clocks.o + ifeq ($(CONFIG_SUSPEND),y) obj-$(CONFIG_6xx) += 6xx-suspend.o endif diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 9e105cb..a477991 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -250,7 +250,7 @@ axon_ram_probe(struct of_device *device, const struct of_device_id *device_id) set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT); blk_queue_make_request(bank->disk->queue, axon_ram_make_request); - blk_queue_hardsect_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE); + blk_queue_logical_block_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE); add_disk(bank->disk); bank->irq_id = irq_of_parse_and_map(device->node, 0); diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c index fd969f0..eb59272 100644 --- a/arch/powerpc/sysdev/cpm2.c +++ b/arch/powerpc/sysdev/cpm2.c @@ -61,7 +61,7 @@ EXPORT_SYMBOL(cpm2_immr); void __init cpm2_reset(void) { #ifdef CONFIG_PPC_85xx - cpm2_immr = ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE); + cpm2_immr = ioremap(get_immrbase() + 0x80000, CPM_MAP_SIZE); #else cpm2_immr = ioremap(get_immrbase(), CPM_MAP_SIZE); #endif diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index f25ce81..da38a1f 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -113,8 +113,13 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq, struct msi_msg *msg) { struct fsl_msi *msi_data = fsl_msi; + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + u32 base = 0; - msg->address_lo = msi_data->msi_addr_lo; + pci_bus_read_config_dword(hose->bus, + PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base); + + msg->address_lo = msi_data->msi_addr_lo + base; msg->address_hi = msi_data->msi_addr_hi; msg->data = hwirq; @@ -271,7 +276,7 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev, msi->irqhost->host_data = msi; msi->msi_addr_hi = 0x0; - msi->msi_addr_lo = res.start + features->msiir_offset; + msi->msi_addr_lo = features->msiir_offset + (res.start & 0xfffff); rc = fsl_msi_init_allocator(msi); if (rc) { diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 78021d8..ae88b14 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c @@ -23,6 +23,8 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/bootmem.h> +#include <linux/lmb.h> +#include <linux/log2.h> #include <asm/io.h> #include <asm/prom.h> @@ -96,7 +98,13 @@ static void __init setup_pci_atmu(struct pci_controller *hose, struct resource *rsrc) { struct ccsr_pci __iomem *pci; - int i, j, n; + int i, j, n, mem_log, win_idx = 2; + u64 mem, sz, paddr_hi = 0; + u64 paddr_lo = ULLONG_MAX; + u32 pcicsrbar = 0, pcicsrbar_sz; + u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL | + PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; + char *name = hose->dn->full_name; pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); @@ -117,6 +125,9 @@ static void __init setup_pci_atmu(struct pci_controller *hose, if (!(hose->mem_resources[i].flags & IORESOURCE_MEM)) continue; + paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start); + paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end); + n = setup_one_atmu(pci, j, &hose->mem_resources[i], hose->pci_mem_offset); @@ -147,10 +158,105 @@ static void __init setup_pci_atmu(struct pci_controller *hose, } } - /* Setup 2G inbound Memory Window @ 1 */ - out_be32(&pci->piw[2].pitar, 0x00000000); - out_be32(&pci->piw[2].piwbar,0x00000000); - out_be32(&pci->piw[2].piwar, PIWAR_2G); + /* convert to pci address space */ + paddr_hi -= hose->pci_mem_offset; + paddr_lo -= hose->pci_mem_offset; + + if (paddr_hi == paddr_lo) { + pr_err("%s: No outbound window space\n", name); + return ; + } + + if (paddr_lo == 0) { + pr_err("%s: No space for inbound window\n", name); + return ; + } + + /* setup PCSRBAR/PEXCSRBAR */ + early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff); + early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz); + pcicsrbar_sz = ~pcicsrbar_sz + 1; + + if (paddr_hi < (0x100000000ull - pcicsrbar_sz) || + (paddr_lo > 0x100000000ull)) + pcicsrbar = 0x100000000ull - pcicsrbar_sz; + else + pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz; + early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar); + + paddr_lo = min(paddr_lo, (u64)pcicsrbar); + + pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar); + + /* Setup inbound mem window */ + mem = lmb_end_of_DRAM(); + sz = min(mem, paddr_lo); + mem_log = __ilog2_u64(sz); + + /* PCIe can overmap inbound & outbound since RX & TX are separated */ + if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) { + /* Size window to exact size if power-of-two or one size up */ + if ((1ull << mem_log) != mem) { + if ((1ull << mem_log) > mem) + pr_info("%s: Setting PCI inbound window " + "greater than memory size\n", name); + mem_log++; + } + + piwar |= (mem_log - 1); + + /* Setup inbound memory window */ + out_be32(&pci->piw[win_idx].pitar, 0x00000000); + out_be32(&pci->piw[win_idx].piwbar, 0x00000000); + out_be32(&pci->piw[win_idx].piwar, piwar); + win_idx--; + + hose->dma_window_base_cur = 0x00000000; + hose->dma_window_size = (resource_size_t)sz; + } else { + u64 paddr = 0; + + /* Setup inbound memory window */ + out_be32(&pci->piw[win_idx].pitar, paddr >> 12); + out_be32(&pci->piw[win_idx].piwbar, paddr >> 12); + out_be32(&pci->piw[win_idx].piwar, (piwar | (mem_log - 1))); + win_idx--; + + paddr += 1ull << mem_log; + sz -= 1ull << mem_log; + + if (sz) { + mem_log = __ilog2_u64(sz); + piwar |= (mem_log - 1); + + out_be32(&pci->piw[win_idx].pitar, paddr >> 12); + out_be32(&pci->piw[win_idx].piwbar, paddr >> 12); + out_be32(&pci->piw[win_idx].piwar, piwar); + win_idx--; + + paddr += 1ull << mem_log; + } + + hose->dma_window_base_cur = 0x00000000; + hose->dma_window_size = (resource_size_t)paddr; + } + + if (hose->dma_window_size < mem) { +#ifndef CONFIG_SWIOTLB + pr_err("%s: ERROR: Memory size exceeds PCI ATMU ability to " + "map - enable CONFIG_SWIOTLB to avoid dma errors.\n", + name); +#endif + /* adjusting outbound windows could reclaim space in mem map */ + if (paddr_hi < 0xffffffffull) + pr_warning("%s: WARNING: Outbound window cfg leaves " + "gaps in memory map. Adjusting the memory map " + "could reduce unnecessary bounce buffering.\n", + name); + + pr_info("%s: DMA window size is 0x%llx\n", name, + (u64)hose->dma_window_size); + } iounmap(pci); } @@ -176,19 +282,9 @@ static void __init setup_pci_cmd(struct pci_controller *hose) } } -static void __init setup_pci_pcsrbar(struct pci_controller *hose) -{ -#ifdef CONFIG_PCI_MSI - phys_addr_t immr_base; - - immr_base = get_immrbase(); - early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, immr_base); -#endif -} - void fsl_pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_controller *hose = (struct pci_controller *) bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); int i; if ((bus->parent == hose->bus) && @@ -269,8 +365,6 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) /* Setup PEX window registers */ setup_pci_atmu(hose, &rsrc); - /* Setup PEXCSRBAR */ - setup_pci_pcsrbar(hose); return 0; } @@ -281,6 +375,8 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8543, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8547E, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8545E, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8545, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8569E, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8569, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8568E, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8568, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8567E, quirk_fsl_pcie_header); @@ -296,6 +392,8 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8536, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header); DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); +DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header); #endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */ #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) @@ -324,7 +422,7 @@ struct mpc83xx_pcie_priv { static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn) { - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) return PCIBIOS_DEVICE_NOT_FOUND; @@ -350,7 +448,7 @@ static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn) static void __iomem *mpc83xx_pcie_remap_cfg(struct pci_bus *bus, unsigned int devfn, int offset) { - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); struct mpc83xx_pcie_priv *pcie = hose->dn->data; u8 bus_no = bus->number - hose->first_busno; u32 dev_base = bus_no << 24 | devfn << 16; diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h index 13f30c2..a9d8bbe 100644 --- a/arch/powerpc/sysdev/fsl_pci.h +++ b/arch/powerpc/sysdev/fsl_pci.h @@ -16,7 +16,11 @@ #define PCIE_LTSSM 0x0404 /* PCIE Link Training and Status */ #define PCIE_LTSSM_L0 0x16 /* L0 state */ -#define PIWAR_2G 0xa0f5501e /* Enable, Prefetch, Local Mem, Snoop R/W, 2G */ +#define PIWAR_EN 0x80000000 /* Enable */ +#define PIWAR_PF 0x20000000 /* prefetch */ +#define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */ +#define PIWAR_READ_SNOOP 0x00050000 +#define PIWAR_WRITE_SNOOP 0x00005000 /* PCI/PCI Express outbound window reg */ struct pci_outbound_window_regs { diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index abdb124..cbb3bed 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -965,7 +965,7 @@ static inline void fsl_rio_info(struct device *dev, u32 ccsr) break; default: str = "Unknown"; - break;; + break; } dev_info(dev, "Hardware port width: %s\n", str); @@ -1026,8 +1026,7 @@ int fsl_rio_setup(struct of_device *dev) return -EFAULT; } dev_info(&dev->dev, "Of-device full name %s\n", dev->node->full_name); - dev_info(&dev->dev, "Regs start 0x%08x size 0x%08x\n", regs.start, - regs.end - regs.start + 1); + dev_info(&dev->dev, "Regs: %pR\n", ®s); dt_range = of_get_property(dev->node, "ranges", &rlen); if (!dt_range) { @@ -1077,8 +1076,9 @@ int fsl_rio_setup(struct of_device *dev) INIT_LIST_HEAD(&port->dbells); port->iores.start = law_start; - port->iores.end = law_start + law_size; + port->iores.end = law_start + law_size - 1; port->iores.flags = IORESOURCE_MEM; + port->iores.name = "rio_io_win"; priv->bellirq = irq_of_parse_and_map(dev->node, 2); priv->txirq = irq_of_parse_and_map(dev->node, 3); @@ -1156,14 +1156,15 @@ int fsl_rio_setup(struct of_device *dev) out_be32((priv->regs_win + RIO_ISR_AACR), RIO_ISR_AACR_AA); /* Configure maintenance transaction window */ - out_be32(&priv->maint_atmu_regs->rowbar, 0x000c0000); - out_be32(&priv->maint_atmu_regs->rowar, 0x80077015); + out_be32(&priv->maint_atmu_regs->rowbar, law_start >> 12); + out_be32(&priv->maint_atmu_regs->rowar, 0x80077015); /* 4M */ priv->maint_win = ioremap(law_start, RIO_MAINT_WIN_SIZE); /* Configure outbound doorbell window */ - out_be32(&priv->dbell_atmu_regs->rowbar, 0x000c0400); - out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b); + out_be32(&priv->dbell_atmu_regs->rowbar, + (law_start + RIO_MAINT_WIN_SIZE) >> 12); + out_be32(&priv->dbell_atmu_regs->rowar, 0x8004200b); /* 4k */ fsl_rio_doorbell_init(port); return 0; diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 5c64ccd..95dbc64 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -379,16 +379,10 @@ static int __init setup_rstcr(void) struct device_node *np; np = of_find_node_by_name(NULL, "global-utilities"); if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) { - const u32 *prop = of_get_property(np, "reg", NULL); - if (prop) { - /* map reset control register - * 0xE00B0 is offset of reset control register - */ - rstcr = ioremap(get_immrbase() + *prop + 0xB0, 0xff); - if (!rstcr) - printk (KERN_EMERG "Error: reset control " - "register not mapped!\n"); - } + rstcr = of_iomap(np, 0) + 0xb0; + if (!rstcr) + printk (KERN_EMERG "Error: reset control register " + "not mapped!\n"); } else printk (KERN_INFO "rstcr compatible register does not exist!\n"); if (np) diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c index 7fd49c9..7ed8096 100644 --- a/arch/powerpc/sysdev/indirect_pci.c +++ b/arch/powerpc/sysdev/indirect_pci.c @@ -24,7 +24,7 @@ static int indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); volatile void __iomem *cfg_data; u8 cfg_type = 0; u32 bus_no, reg; @@ -82,7 +82,7 @@ static int indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); volatile void __iomem *cfg_data; u8 cfg_type = 0; u32 bus_no, reg; diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index a86d3ce..69e2630 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c @@ -728,12 +728,10 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) if (ret) return NULL; - ipic = alloc_bootmem(sizeof(struct ipic)); + ipic = kzalloc(sizeof(*ipic), GFP_KERNEL); if (ipic == NULL) return NULL; - memset(ipic, 0, sizeof(struct ipic)); - ipic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, NR_IPIC_INTS, &ipic_host_ops, 0); diff --git a/arch/powerpc/sysdev/mpc5xxx_clocks.c b/arch/powerpc/sysdev/mpc5xxx_clocks.c new file mode 100644 index 0000000..34e12f9 --- /dev/null +++ b/arch/powerpc/sysdev/mpc5xxx_clocks.c @@ -0,0 +1,33 @@ +/** + * mpc5xxx_get_bus_frequency - Find the bus frequency for a device + * @node: device node + * + * Returns bus frequency (IPS on MPC512x, IPB on MPC52xx), + * or 0 if the bus frequency cannot be found. + */ + +#include <linux/kernel.h> +#include <linux/of_platform.h> + +unsigned int +mpc5xxx_get_bus_frequency(struct device_node *node) +{ + struct device_node *np; + const unsigned int *p_bus_freq = NULL; + + of_node_get(node); + while (node) { + p_bus_freq = of_get_property(node, "bus-frequency", NULL); + if (p_bus_freq) + break; + + np = of_get_parent(node); + of_node_put(node); + node = np; + } + if (node) + of_node_put(node); + + return p_bus_freq ? *p_bus_freq : 0; +} +EXPORT_SYMBOL(mpc5xxx_get_bus_frequency); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 352d8c3..3981ae4 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -279,28 +279,29 @@ static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr, } #ifdef CONFIG_PPC_DCR -static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, +static void _mpic_map_dcr(struct mpic *mpic, struct device_node *node, + struct mpic_reg_bank *rb, unsigned int offset, unsigned int size) { const u32 *dbasep; - dbasep = of_get_property(mpic->irqhost->of_node, "dcr-reg", NULL); + dbasep = of_get_property(node, "dcr-reg", NULL); - rb->dhost = dcr_map(mpic->irqhost->of_node, *dbasep + offset, size); + rb->dhost = dcr_map(node, *dbasep + offset, size); BUG_ON(!DCR_MAP_OK(rb->dhost)); } -static inline void mpic_map(struct mpic *mpic, phys_addr_t phys_addr, - struct mpic_reg_bank *rb, unsigned int offset, - unsigned int size) +static inline void mpic_map(struct mpic *mpic, struct device_node *node, + phys_addr_t phys_addr, struct mpic_reg_bank *rb, + unsigned int offset, unsigned int size) { if (mpic->flags & MPIC_USES_DCR) - _mpic_map_dcr(mpic, rb, offset, size); + _mpic_map_dcr(mpic, node, rb, offset, size); else _mpic_map_mmio(mpic, phys_addr, rb, offset, size); } #else /* CONFIG_PPC_DCR */ -#define mpic_map(m,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) +#define mpic_map(m,n,p,b,o,s) _mpic_map_mmio(m,p,b,o,s) #endif /* !CONFIG_PPC_DCR */ @@ -507,9 +508,8 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) printk(KERN_INFO "mpic: Setting up HT PICs workarounds for U3/U4\n"); /* Allocate fixups array */ - mpic->fixups = alloc_bootmem(128 * sizeof(struct mpic_irq_fixup)); + mpic->fixups = kzalloc(128 * sizeof(*mpic->fixups), GFP_KERNEL); BUG_ON(mpic->fixups == NULL); - memset(mpic->fixups, 0, 128 * sizeof(struct mpic_irq_fixup)); /* Init spinlock */ spin_lock_init(&mpic->fixup_lock); @@ -613,23 +613,23 @@ static int irq_choose_cpu(unsigned int virt_irq) #define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) /* Find an mpic associated with a given linux interrupt */ -static struct mpic *mpic_find(unsigned int irq, unsigned int *is_ipi) +static struct mpic *mpic_find(unsigned int irq) { - unsigned int src = mpic_irq_to_hw(irq); - struct mpic *mpic; - if (irq < NUM_ISA_INTERRUPTS) return NULL; - mpic = irq_desc[irq].chip_data; + return irq_desc[irq].chip_data; +} - if (is_ipi) - *is_ipi = (src >= mpic->ipi_vecs[0] && - src <= mpic->ipi_vecs[3]); +/* Determine if the linux irq is an IPI */ +static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq) +{ + unsigned int src = mpic_irq_to_hw(irq); - return mpic; + return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]); } + /* Convert a cpu mask from logical to physical cpu numbers. */ static inline u32 mpic_physmask(u32 cpumask) { @@ -1052,11 +1052,10 @@ struct mpic * __init mpic_alloc(struct device_node *node, int intvec_top; u64 paddr = phys_addr; - mpic = alloc_bootmem(sizeof(struct mpic)); + mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); if (mpic == NULL) return NULL; - - memset(mpic, 0, sizeof(struct mpic)); + mpic->name = name; mpic->hc_irq = mpic_irq_chip; @@ -1109,9 +1108,8 @@ struct mpic * __init mpic_alloc(struct device_node *node, psize /= 4; bits = intvec_top + 1; mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long); - mpic->protected = alloc_bootmem(mapsize); + mpic->protected = kzalloc(mapsize, GFP_KERNEL); BUG_ON(mpic->protected == NULL); - memset(mpic->protected, 0, mapsize); for (i = 0; i < psize; i++) { if (psrc[i] > intvec_top) continue; @@ -1152,8 +1150,8 @@ struct mpic * __init mpic_alloc(struct device_node *node, } /* Map the global registers */ - mpic_map(mpic, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); - mpic_map(mpic, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); + mpic_map(mpic, node, paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000); + mpic_map(mpic, node, paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000); /* Reset */ if (flags & MPIC_WANTS_RESET) { @@ -1194,7 +1192,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Map the per-CPU registers */ for (i = 0; i < mpic->num_cpus; i++) { - mpic_map(mpic, paddr, &mpic->cpuregs[i], + mpic_map(mpic, node, paddr, &mpic->cpuregs[i], MPIC_INFO(CPU_BASE) + i * MPIC_INFO(CPU_STRIDE), 0x1000); } @@ -1202,7 +1200,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* Initialize main ISU if none provided */ if (mpic->isu_size == 0) { mpic->isu_size = mpic->num_sources; - mpic_map(mpic, paddr, &mpic->isus[0], + mpic_map(mpic, node, paddr, &mpic->isus[0], MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); } mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); @@ -1256,8 +1254,10 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, BUG_ON(isu_num >= MPIC_MAX_ISU); - mpic_map(mpic, paddr, &mpic->isus[isu_num], 0, + mpic_map(mpic, mpic->irqhost->of_node, + paddr, &mpic->isus[isu_num], 0, MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); + if ((isu_first + mpic->isu_size) > mpic->num_sources) mpic->num_sources = isu_first + mpic->isu_size; } @@ -1351,7 +1351,8 @@ void __init mpic_init(struct mpic *mpic) #ifdef CONFIG_PM /* allocate memory to save mpic state */ - mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save)); + mpic->save_data = kmalloc(mpic->num_sources * sizeof(*mpic->save_data), + GFP_KERNEL); BUG_ON(mpic->save_data == NULL); #endif } @@ -1383,8 +1384,7 @@ void __init mpic_set_serial_int(struct mpic *mpic, int enable) void mpic_irq_set_priority(unsigned int irq, unsigned int pri) { - unsigned int is_ipi; - struct mpic *mpic = mpic_find(irq, &is_ipi); + struct mpic *mpic = mpic_find(irq); unsigned int src = mpic_irq_to_hw(irq); unsigned long flags; u32 reg; @@ -1393,7 +1393,7 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri) return; spin_lock_irqsave(&mpic_lock, flags); - if (is_ipi) { + if (mpic_is_ipi(mpic, irq)) { reg = mpic_ipi_read(src - mpic->ipi_vecs[0]) & ~MPIC_VECPRI_PRIORITY_MASK; mpic_ipi_write(src - mpic->ipi_vecs[0], diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 6a2d473..6ff9d71 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -1295,7 +1295,7 @@ static void __iomem *ppc4xx_pciex_get_config_base(struct ppc4xx_pciex_port *port static int ppc4xx_pciex_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { - struct pci_controller *hose = (struct pci_controller *) bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); struct ppc4xx_pciex_port *port = &ppc4xx_pciex_ports[hose->indirect_type]; void __iomem *addr; @@ -1352,7 +1352,7 @@ static int ppc4xx_pciex_read_config(struct pci_bus *bus, unsigned int devfn, static int ppc4xx_pciex_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { - struct pci_controller *hose = (struct pci_controller *) bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); struct ppc4xx_pciex_port *port = &ppc4xx_pciex_ports[hose->indirect_type]; void __iomem *addr; @@ -1531,7 +1531,7 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, */ /* Calculate window size */ - sa = (0xffffffffffffffffull << ilog2(ep_size));; + sa = (0xffffffffffffffffull << ilog2(ep_size)); /* Setup BAR0 */ out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); @@ -1550,7 +1550,7 @@ static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(ep_addr)); } else { /* Calculate window size */ - sa = (0xffffffffffffffffull << ilog2(size));; + sa = (0xffffffffffffffffull << ilog2(size)); if (res->flags & IORESOURCE_PREFETCH) sa |= 0x8; diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 01bce37..237e365 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c @@ -61,6 +61,7 @@ struct qe_immap __iomem *qe_immr; EXPORT_SYMBOL(qe_immr); static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */ +static unsigned int qe_num_of_snum; static phys_addr_t qebase = -1; @@ -111,6 +112,7 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) { unsigned long flags; u8 mcn_shift = 0, dev_shift = 0; + u32 ret; spin_lock_irqsave(&qe_lock, flags); if (cmd == QE_RESET) { @@ -138,11 +140,13 @@ int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) } /* wait for the QE_CR_FLG to clear */ - while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) - cpu_relax(); + ret = spin_event_timeout((in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) == 0, + 100, 0); + /* On timeout (e.g. failure), the expression will be false (ret == 0), + otherwise it will be true (ret == 1). */ spin_unlock_irqrestore(&qe_lock, flags); - return 0; + return ret == 1; } EXPORT_SYMBOL(qe_issue_cmd); @@ -264,10 +268,14 @@ static void qe_snums_init(void) 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, - 0xD8, 0xD9, 0xE8, 0xE9, + 0xD8, 0xD9, 0xE8, 0xE9, 0x08, 0x09, 0x18, 0x19, + 0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59, + 0x68, 0x69, 0x78, 0x79, 0x80, 0x81, }; - for (i = 0; i < QE_NUM_OF_SNUM; i++) { + qe_num_of_snum = qe_get_num_of_snums(); + + for (i = 0; i < qe_num_of_snum; i++) { snums[i].num = snum_init[i]; snums[i].state = QE_SNUM_STATE_FREE; } @@ -280,7 +288,7 @@ int qe_get_snum(void) int i; spin_lock_irqsave(&qe_lock, flags); - for (i = 0; i < QE_NUM_OF_SNUM; i++) { + for (i = 0; i < qe_num_of_snum; i++) { if (snums[i].state == QE_SNUM_STATE_FREE) { snums[i].state = QE_SNUM_STATE_USED; snum = snums[i].num; @@ -297,7 +305,7 @@ void qe_put_snum(u8 snum) { int i; - for (i = 0; i < QE_NUM_OF_SNUM; i++) { + for (i = 0; i < qe_num_of_snum; i++) { if (snums[i].num == snum) { snums[i].state = QE_SNUM_STATE_FREE; break; @@ -575,3 +583,65 @@ struct qe_firmware_info *qe_get_firmware_info(void) } EXPORT_SYMBOL(qe_get_firmware_info); +unsigned int qe_get_num_of_risc(void) +{ + struct device_node *qe; + int size; + unsigned int num_of_risc = 0; + const u32 *prop; + + qe = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!qe) { + /* Older devices trees did not have an "fsl,qe" + * compatible property, so we need to look for + * the QE node by name. + */ + qe = of_find_node_by_type(NULL, "qe"); + if (!qe) + return num_of_risc; + } + + prop = of_get_property(qe, "fsl,qe-num-riscs", &size); + if (prop && size == sizeof(*prop)) + num_of_risc = *prop; + + of_node_put(qe); + + return num_of_risc; +} +EXPORT_SYMBOL(qe_get_num_of_risc); + +unsigned int qe_get_num_of_snums(void) +{ + struct device_node *qe; + int size; + unsigned int num_of_snums; + const u32 *prop; + + num_of_snums = 28; /* The default number of snum for threads is 28 */ + qe = of_find_compatible_node(NULL, NULL, "fsl,qe"); + if (!qe) { + /* Older devices trees did not have an "fsl,qe" + * compatible property, so we need to look for + * the QE node by name. + */ + qe = of_find_node_by_type(NULL, "qe"); + if (!qe) + return num_of_snums; + } + + prop = of_get_property(qe, "fsl,qe-num-snums", &size); + if (prop && size == sizeof(*prop)) { + num_of_snums = *prop; + if ((num_of_snums < 28) || (num_of_snums > QE_NUM_OF_SNUM)) { + /* No QE ever has fewer than 28 SNUMs */ + pr_err("QE: number of snum is invalid\n"); + return -EINVAL; + } + } + + of_node_put(qe); + + return num_of_snums; +} +EXPORT_SYMBOL(qe_get_num_of_snums); diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 63cdf98..074905c 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c @@ -333,12 +333,10 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags, if (ret) return; - qe_ic = alloc_bootmem(sizeof(struct qe_ic)); + qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL); if (qe_ic == NULL) return; - memset(qe_ic, 0, sizeof(struct qe_ic)); - qe_ic->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, NR_QE_IC_INTS, &qe_ic_host_ops, 0); if (qe_ic->irqhost == NULL) diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 24e1f5a..cf244a4 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -63,7 +63,7 @@ tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfunc, int offset, int len, u32 val) { volatile unsigned char *cfg_addr; - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); if (ppc_md.pci_exclude_device) if (ppc_md.pci_exclude_device(hose, bus->number, devfunc)) @@ -149,7 +149,7 @@ tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 * val) { volatile unsigned char *cfg_addr; - struct pci_controller *hose = bus->sysdata; + struct pci_controller *hose = pci_bus_to_host(bus); u32 temp; if (ppc_md.pci_exclude_device) diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index d35405c..466ce9a 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c @@ -258,11 +258,10 @@ static struct uic * __init uic_init_one(struct device_node *node) BUG_ON(! of_device_is_compatible(node, "ibm,uic")); - uic = alloc_bootmem(sizeof(*uic)); + uic = kzalloc(sizeof(*uic), GFP_KERNEL); if (! uic) return NULL; /* FIXME: panic? */ - memset(uic, 0, sizeof(*uic)); spin_lock_init(&uic->lock); indexp = of_get_property(node, "cell-index", &len); if (!indexp || (len != sizeof(u32))) { diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index c658b41..3ee1fd3 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c @@ -25,6 +25,7 @@ #include <linux/of.h> #include <asm/io.h> #include <asm/processor.h> +#include <asm/i8259.h> #include <asm/irq.h> /* @@ -191,20 +192,14 @@ struct irq_host * __init xilinx_intc_init(struct device_node *np) { struct irq_host * irq; - struct resource res; void * regs; - int rc; /* Find and map the intc registers */ - rc = of_address_to_resource(np, 0, &res); - if (rc) { - printk(KERN_ERR __FILE__ ": of_address_to_resource() failed\n"); + regs = of_iomap(np, 0); + if (!regs) { + pr_err("xilinx_intc: could not map registers\n"); return NULL; } - regs = ioremap(res.start, 32); - - printk(KERN_INFO "Xilinx intc at 0x%08llx mapped to 0x%p\n", - (unsigned long long) res.start, regs); /* Setup interrupt controller */ out_be32(regs + XINTC_IER, 0); /* disable all irqs */ @@ -217,6 +212,7 @@ xilinx_intc_init(struct device_node *np) if (!irq) panic(__FILE__ ": Cannot allocate IRQ host\n"); irq->host_data = regs; + return irq; } @@ -227,23 +223,70 @@ int xilinx_intc_get_irq(void) return irq_linear_revmap(master_irqhost, in_be32(regs + XINTC_IVR)); } +#if defined(CONFIG_PPC_I8259) +/* + * Support code for cascading to 8259 interrupt controllers + */ +static void xilinx_i8259_cascade(unsigned int irq, struct irq_desc *desc) +{ + unsigned int cascade_irq = i8259_irq(); + if (cascade_irq) + generic_handle_irq(cascade_irq); + + /* Let xilinx_intc end the interrupt */ + desc->chip->ack(irq); + desc->chip->unmask(irq); +} + +static void __init xilinx_i8259_setup_cascade(void) +{ + struct device_node *cascade_node; + int cascade_irq; + + /* Initialize i8259 controller */ + cascade_node = of_find_compatible_node(NULL, NULL, "chrp,iic"); + if (!cascade_node) + return; + + cascade_irq = irq_of_parse_and_map(cascade_node, 0); + if (!cascade_irq) { + pr_err("virtex_ml510: Failed to map cascade interrupt\n"); + goto out; + } + + i8259_init(cascade_node, 0); + set_irq_chained_handler(cascade_irq, xilinx_i8259_cascade); + + /* Program irq 7 (usb/audio), 14/15 (ide) to level sensitive */ + /* This looks like a dirty hack to me --gcl */ + outb(0xc0, 0x4d0); + outb(0xc0, 0x4d1); + + out: + of_node_put(cascade_node); +} +#else +static inline void xilinx_i8259_setup_cascade(void) { return; } +#endif /* defined(CONFIG_PPC_I8259) */ + +static struct of_device_id xilinx_intc_match[] __initconst = { + { .compatible = "xlnx,opb-intc-1.00.c", }, + { .compatible = "xlnx,xps-intc-1.00.a", }, + {} +}; + +/* + * Initialize master Xilinx interrupt controller + */ void __init xilinx_intc_init_tree(void) { struct device_node *np; /* find top level interrupt controller */ - for_each_compatible_node(np, NULL, "xlnx,opb-intc-1.00.c") { + for_each_matching_node(np, xilinx_intc_match) { if (!of_get_property(np, "interrupts", NULL)) break; } - if (!np) { - for_each_compatible_node(np, NULL, "xlnx,xps-intc-1.00.a") { - if (!of_get_property(np, "interrupts", NULL)) - break; - } - } - - /* xilinx interrupt controller needs to be top level */ BUG_ON(!np); master_irqhost = xilinx_intc_init(np); @@ -251,4 +294,6 @@ void __init xilinx_intc_init_tree(void) irq_set_default_host(master_irqhost); of_node_put(np); + + xilinx_i8259_setup_cascade(); } diff --git a/arch/powerpc/sysdev/xilinx_pci.c b/arch/powerpc/sysdev/xilinx_pci.c new file mode 100644 index 0000000..1453b0e --- /dev/null +++ b/arch/powerpc/sysdev/xilinx_pci.c @@ -0,0 +1,132 @@ +/* + * PCI support for Xilinx plbv46_pci soft-core which can be used on + * Xilinx Virtex ML410 / ML510 boards. + * + * Copyright 2009 Roderick Colenbrander + * Copyright 2009 Secret Lab Technologies Ltd. + * + * The pci bridge fixup code was copied from ppc4xx_pci.c and was written + * by Benjamin Herrenschmidt. + * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/ioport.h> +#include <linux/of.h> +#include <linux/pci.h> +#include <mm/mmu_decl.h> +#include <asm/io.h> +#include <asm/xilinx_pci.h> + +#define XPLB_PCI_ADDR 0x10c +#define XPLB_PCI_DATA 0x110 +#define XPLB_PCI_BUS 0x114 + +#define PCI_HOST_ENABLE_CMD PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY + +static struct of_device_id xilinx_pci_match[] = { + { .compatible = "xlnx,plbv46-pci-1.03.a", }, + {} +}; + +/** + * xilinx_pci_fixup_bridge - Block Xilinx PHB configuration. + */ +static void xilinx_pci_fixup_bridge(struct pci_dev *dev) +{ + struct pci_controller *hose; + int i; + + if (dev->devfn || dev->bus->self) + return; + + hose = pci_bus_to_host(dev->bus); + if (!hose) + return; + + if (!of_match_node(xilinx_pci_match, hose->dn)) + return; + + /* Hide the PCI host BARs from the kernel as their content doesn't + * fit well in the resource management + */ + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + dev->resource[i].start = 0; + dev->resource[i].end = 0; + dev->resource[i].flags = 0; + } + + dev_info(&dev->dev, "Hiding Xilinx plb-pci host bridge resources %s\n", + pci_name(dev)); +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, xilinx_pci_fixup_bridge); + +/** + * xilinx_pci_exclude_device - Don't do config access for non-root bus + * + * This is a hack. Config access to any bus other than bus 0 does not + * currently work on the ML510 so we prevent it here. + */ +static int +xilinx_pci_exclude_device(struct pci_controller *hose, u_char bus, u8 devfn) +{ + return (bus != 0); +} + +/** + * xilinx_pci_init - Find and register a Xilinx PCI host bridge + */ +void __init xilinx_pci_init(void) +{ + struct pci_controller *hose; + struct resource r; + void __iomem *pci_reg; + struct device_node *pci_node; + + pci_node = of_find_matching_node(NULL, xilinx_pci_match); + if(!pci_node) + return; + + if (of_address_to_resource(pci_node, 0, &r)) { + pr_err("xilinx-pci: cannot resolve base address\n"); + return; + } + + hose = pcibios_alloc_controller(pci_node); + if (!hose) { + pr_err("xilinx-pci: pcibios_alloc_controller() failed\n"); + return; + } + + /* Setup config space */ + setup_indirect_pci(hose, r.start + XPLB_PCI_ADDR, + r.start + XPLB_PCI_DATA, + PPC_INDIRECT_TYPE_SET_CFG_TYPE); + + /* According to the xilinx plbv46_pci documentation the soft-core starts + * a self-init when the bus master enable bit is set. Without this bit + * set the pci bus can't be scanned. + */ + early_write_config_word(hose, 0, 0, PCI_COMMAND, PCI_HOST_ENABLE_CMD); + + /* Set the max latency timer to 255 */ + early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0xff); + + /* Set the max bus number to 255 */ + pci_reg = of_iomap(pci_node, 0); + out_8(pci_reg + XPLB_PCI_BUS, 0xff); + iounmap(pci_reg); + + /* Nothing past the root bridge is working right now. By default + * exclude config access to anything except bus 0 */ + if (!ppc_md.pci_exclude_device) + ppc_md.pci_exclude_device = xilinx_pci_exclude_device; + + /* Register the host bridge with the linux kernel! */ + pci_process_bridge_OF_ranges(hose, pci_node, 1); + + pr_info("xilinx-pci: Registered PCI host bridge\n"); +} |