/*
* MPC83xx/85xx/86xx PCI/PCIE support routing.
*
* Copyright 2007-2012 Freescale Semiconductor, Inc.
* Copyright 2008-2009 MontaVista Software, Inc.
*
* Initial author: Xianghua Xiao <x.xiao@freescale.com>
* Recode: ZHANG WEI <wei.zhang@freescale.com>
* Rewrite the routing for Frescale PCI and PCI Express
* Roy Zang <tie-fei.zang@freescale.com>
* MPC83xx PCI-Express support:
* Tony Li <tony.li@freescale.com>
* Anton Vorontsov <avorontsov@ru.mvista.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
#include <linux/log2.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
static int fsl_pcie_bus_fixup, is_mpc83xx_pci;
static void quirk_fsl_pcie_header(struct pci_dev *dev)
{
u8 hdr_type;
/* if we aren't a PCIe don't bother */
if (!pci_find_capability(dev, PCI_CAP_ID_EXP))
return;
/* if we aren't in host mode don't bother */
pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
return;
dev->class = PCI_CLASS_BRIDGE_PCI << 8;
fsl_pcie_bus_fixup = 1;
return;
}
static int fsl_indirect_read_config(struct pci_bus *, unsigned int,
int, int, u32 *);
static int fsl_pcie_check_link(struct pci_controller *hose)
{
u32 val = 0;
if (hose->indirect_type & PPC_INDIRECT_TYPE_FSL_CFG_REG_LINK) {
if (hose->ops->read == fsl_indirect_read_config) {
struct pci_bus bus;
bus.number = 0;
bus.sysdata = hose;
bus.ops = hose->ops;
indirect_read_config(&bus, 0, PCIE_LTSSM, 4, &val);
} else
early_read_config_dword(hose, 0, 0, PCIE_LTSSM, &val);
if (val < PCIE_LTSSM_L0)
return 1;
} else {
struct ccsr_pci __iomem *pci = hose->private_data;
/* for PCIe IP rev 3.0 or greater use CSR0 for link state */
val = (in_be32(&pci->pex_csr0) & PEX_CSR0_LTSSM_MASK)
>> PEX_CSR0_LTSSM_SHIFT;
if (val != PEX_CSR0_LTSSM_L0)
return 1;
}
return 0;
}
static int fsl_indirect_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
struct pci_controller *hose = pci_bus_to_host(bus);
if (fsl_pcie_check_link(hose))
hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK;
else
hose->indirect_type &= ~PPC_INDIRECT_TYPE_NO_PCIE_LINK;
return indirect_read_config(bus, devfn, offset, len, val);
}
#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
static struct pci_ops fsl_indirect_pcie_ops =
{
.read = fsl_indirect_read_config,
.write = indirect_write_config,
};
#define MAX_PHYS_ADDR_BITS 40
static u64 pci64_dma_offset = 1ull << MAX_PHYS_ADDR_BITS;
static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
{
if (!dev->dma_mask || !dma_supported(dev, dma_mask))
return -EIO;
/*
* Fixup PCI devices that are able to DMA to above the physical
* address width of the SoC such that we can address any internal
* SoC address from across PCI if needed
*/
if ((dev->bus == &pci_bus_type) &&
dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) {
set_dma_ops(dev, &dma_direct_ops);
set_dma_offset(dev, pci64_dma_offset);
}
*dev->dma_mask = dma_mask;
return 0;
}
static int setup_one_atmu(struct ccsr_pci __iomem *pci,
unsigned int index, const struct resource *res,
resource_size_t offset)
{
resource_size_t pci_addr = res->start - offset;
resource_size_t phys_addr = res->start;
resource_size_t size = resource_size(res);
u32 flags = 0x80044000; /* enable & mem R/W */
unsigned int i;
pr_debug("PCI MEM resource start 0x%016llx, size 0x%016llx.\n",
(u64)res->start, (u64)size);
if (res->flags & IORESOURCE_PREFETCH)
flags |= 0x10000000; /* enable relaxed ordering */
for (i = 0; size > 0; i++) {
unsigned int bits