[ARM] Kirkwood: add support for PCIe1

This patch extends the kirkwood's PCIe support up to 2 controllers as in the 6282 devices.

Signed-off-by: Saeed Bishara <saeed@marvell.com>
Signed-off-by: Nicolas Pitre <nico@fluxnic.net>
This commit is contained in:
Saeed Bishara 2010-06-08 14:21:34 +03:00 committed by Nicolas Pitre
parent 35fe2fc44a
commit ffd58bd2e4
15 changed files with 226 additions and 79 deletions

View file

@ -31,6 +31,8 @@
#define ATTR_DEV_CS0 0x3e
#define ATTR_PCIE_IO 0xe0
#define ATTR_PCIE_MEM 0xe8
#define ATTR_PCIE1_IO 0xd0
#define ATTR_PCIE1_MEM 0xd8
#define ATTR_SRAM 0x01
/*
@ -106,17 +108,21 @@ void __init kirkwood_setup_cpu_mbus(void)
TARGET_PCIE, ATTR_PCIE_IO, KIRKWOOD_PCIE_IO_BUS_BASE);
setup_cpu_win(1, KIRKWOOD_PCIE_MEM_PHYS_BASE, KIRKWOOD_PCIE_MEM_SIZE,
TARGET_PCIE, ATTR_PCIE_MEM, KIRKWOOD_PCIE_MEM_BUS_BASE);
setup_cpu_win(2, KIRKWOOD_PCIE1_IO_PHYS_BASE, KIRKWOOD_PCIE1_IO_SIZE,
TARGET_PCIE, ATTR_PCIE1_IO, KIRKWOOD_PCIE1_IO_BUS_BASE);
setup_cpu_win(3, KIRKWOOD_PCIE1_MEM_PHYS_BASE, KIRKWOOD_PCIE1_MEM_SIZE,
TARGET_PCIE, ATTR_PCIE1_MEM, KIRKWOOD_PCIE1_MEM_BUS_BASE);
/*
* Setup window for NAND controller.
*/
setup_cpu_win(2, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE,
setup_cpu_win(4, KIRKWOOD_NAND_MEM_PHYS_BASE, KIRKWOOD_NAND_MEM_SIZE,
TARGET_DEV_BUS, ATTR_DEV_NAND, -1);
/*
* Setup window for SRAM.
*/
setup_cpu_win(3, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE,
setup_cpu_win(5, KIRKWOOD_SRAM_PHYS_BASE, KIRKWOOD_SRAM_SIZE,
TARGET_SRAM, ATTR_SRAM, -1);
/*

View file

@ -43,6 +43,11 @@ static struct map_desc kirkwood_io_desc[] __initdata = {
.pfn = __phys_to_pfn(KIRKWOOD_PCIE_IO_PHYS_BASE),
.length = KIRKWOOD_PCIE_IO_SIZE,
.type = MT_DEVICE,
}, {
.virtual = KIRKWOOD_PCIE1_IO_VIRT_BASE,
.pfn = __phys_to_pfn(KIRKWOOD_PCIE1_IO_PHYS_BASE),
.length = KIRKWOOD_PCIE1_IO_SIZE,
.type = MT_DEVICE,
}, {
.virtual = KIRKWOOD_REGS_VIRT_BASE,
.pfn = __phys_to_pfn(KIRKWOOD_REGS_PHYS_BASE),
@ -960,12 +965,14 @@ void __init kirkwood_init(void)
static int __init kirkwood_clock_gate(void)
{
unsigned int curr = readl(CLOCK_GATING_CTRL);
u32 dev, rev;
kirkwood_pcie_id(&dev, &rev);
printk(KERN_DEBUG "Gating clock of unused units\n");
printk(KERN_DEBUG "before: 0x%08x\n", curr);
/* Make sure those units are accessible */
writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0, CLOCK_GATING_CTRL);
writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0 | CGC_PEX1, CLOCK_GATING_CTRL);
/* For SATA: first shutdown the phy */
if (!(kirkwood_clk_ctrl & CGC_SATA0)) {
@ -990,6 +997,18 @@ static int __init kirkwood_clock_gate(void)
writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL);
}
/* For PCIe 1: first shutdown the phy */
if (dev == MV88F6282_DEV_ID) {
if (!(kirkwood_clk_ctrl & CGC_PEX1)) {
writel(readl(PCIE1_LINK_CTRL) | 0x10, PCIE1_LINK_CTRL);
while (1)
if (readl(PCIE1_STATUS) & 0x1)
break;
writel(readl(PCIE1_LINK_CTRL) & ~0x10, PCIE1_LINK_CTRL);
}
} else /* keep this bit set for devices that don't have PCIe1 */
kirkwood_clk_ctrl |= CGC_PEX1;
/* Now gate clock the required units */
writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL);
printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL));

View file

@ -18,6 +18,9 @@ struct mvsdio_platform_data;
struct mtd_partition;
struct mtd_info;
#define KW_PCIE0 (1 << 0)
#define KW_PCIE1 (1 << 1)
/*
* Basic Kirkwood init functions used early by machine-setup.
*/
@ -34,7 +37,7 @@ void kirkwood_ehci_init(void);
void kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data);
void kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data);
void kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq);
void kirkwood_pcie_init(void);
void kirkwood_pcie_init(unsigned int portmask);
void kirkwood_sata_init(struct mv_sata_platform_data *sata_data);
void kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data);
void kirkwood_spi_init(void);

View file

@ -82,9 +82,15 @@ static void __init db88f6281_init(void)
static int __init db88f6281_pci_init(void)
{
if (machine_is_db88f6281_bp())
kirkwood_pcie_init();
if (machine_is_db88f6281_bp()) {
u32 dev, rev;
kirkwood_pcie_id(&dev, &rev);
if (dev == MV88F6282_DEV_ID)
kirkwood_pcie_init(KW_PCIE1 | KW_PCIE0);
else
kirkwood_pcie_init(KW_PCIE0);
}
return 0;
}
subsys_initcall(db88f6281_pci_init);

View file

@ -59,8 +59,9 @@
#define CGC_SATA1 (1 << 15)
#define CGC_XOR1 (1 << 16)
#define CGC_CRYPTO (1 << 17)
#define CGC_PEX1 (1 << 18)
#define CGC_GE1 (1 << 19)
#define CGC_TDM (1 << 20)
#define CGC_RESERVED ((1 << 18) | (0x6 << 21))
#define CGC_RESERVED (0x6 << 21)
#endif

View file

@ -23,6 +23,7 @@
#define IRQ_KIRKWOOD_XOR_10 7
#define IRQ_KIRKWOOD_XOR_11 8
#define IRQ_KIRKWOOD_PCIE 9
#define IRQ_KIRKWOOD_PCIE1 10
#define IRQ_KIRKWOOD_GE00_SUM 11
#define IRQ_KIRKWOOD_GE01_SUM 15
#define IRQ_KIRKWOOD_USB 19

View file

@ -16,36 +16,48 @@
* Marvell Kirkwood address maps.
*
* phys
* e0000000 PCIe Memory space
* e0000000 PCIe #0 Memory space
* e8000000 PCIe #1 Memory space
* f1000000 on-chip peripheral registers
* f2000000 PCIe I/O space
* f3000000 NAND controller address window
* f4000000 Security Accelerator SRAM
* f2000000 PCIe #0 I/O space
* f3000000 PCIe #1 I/O space
* f4000000 NAND controller address window
* f5000000 Security Accelerator SRAM
*
* virt phys size
* fee00000 f1000000 1M on-chip peripheral registers
* fef00000 f2000000 1M PCIe I/O space
* fed00000 f1000000 1M on-chip peripheral registers
* fee00000 f2000000 1M PCIe #0 I/O space
* fef00000 f3000000 1M PCIe #1 I/O space
*/
#define KIRKWOOD_SRAM_PHYS_BASE 0xf4000000
#define KIRKWOOD_SRAM_PHYS_BASE 0xf5000000
#define KIRKWOOD_SRAM_SIZE SZ_2K
#define KIRKWOOD_NAND_MEM_PHYS_BASE 0xf3000000
#define KIRKWOOD_NAND_MEM_PHYS_BASE 0xf4000000
#define KIRKWOOD_NAND_MEM_SIZE SZ_1K
#define KIRKWOOD_PCIE1_IO_PHYS_BASE 0xf3000000
#define KIRKWOOD_PCIE1_IO_VIRT_BASE 0xfef00000
#define KIRKWOOD_PCIE1_IO_BUS_BASE 0x00000000
#define KIRKWOOD_PCIE1_IO_SIZE SZ_1M
#define KIRKWOOD_PCIE_IO_PHYS_BASE 0xf2000000
#define KIRKWOOD_PCIE_IO_VIRT_BASE 0xfef00000
#define KIRKWOOD_PCIE_IO_VIRT_BASE 0xfee00000
#define KIRKWOOD_PCIE_IO_BUS_BASE 0x00000000
#define KIRKWOOD_PCIE_IO_SIZE SZ_1M
#define KIRKWOOD_REGS_PHYS_BASE 0xf1000000
#define KIRKWOOD_REGS_VIRT_BASE 0xfee00000
#define KIRKWOOD_REGS_VIRT_BASE 0xfed00000
#define KIRKWOOD_REGS_SIZE SZ_1M
#define KIRKWOOD_PCIE_MEM_PHYS_BASE 0xe0000000
#define KIRKWOOD_PCIE_MEM_BUS_BASE 0xe0000000
#define KIRKWOOD_PCIE_MEM_SIZE SZ_128M
#define KIRKWOOD_PCIE1_MEM_PHYS_BASE 0xe8000000
#define KIRKWOOD_PCIE1_MEM_BUS_BASE 0xe8000000
#define KIRKWOOD_PCIE1_MEM_SIZE SZ_128M
/*
* Register Map
*/
@ -72,6 +84,9 @@
#define PCIE_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x40000)
#define PCIE_LINK_CTRL (PCIE_VIRT_BASE | 0x70)
#define PCIE_STATUS (PCIE_VIRT_BASE | 0x1a04)
#define PCIE1_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0x44000)
#define PCIE1_LINK_CTRL (PCIE1_VIRT_BASE | 0x70)
#define PCIE1_STATUS (PCIE1_VIRT_BASE | 0x1a04)
#define USB_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x50000)

View file

@ -155,7 +155,7 @@ static void __init mv88f6281gtw_ge_init(void)
static int __init mv88f6281gtw_ge_pci_init(void)
{
if (machine_is_mv88f6281gtw_ge())
kirkwood_pcie_init();
kirkwood_pcie_init(KW_PCIE0);
return 0;
}

View file

@ -93,7 +93,7 @@ static int __init openrd_pci_init(void)
if (machine_is_openrd_base() ||
machine_is_openrd_client() ||
machine_is_openrd_ultimate())
kirkwood_pcie_init();
kirkwood_pcie_init(KW_PCIE0);
return 0;
}

View file

@ -18,29 +18,43 @@
#include <mach/bridge-regs.h>
#include "common.h"
#define PCIE_BASE ((void __iomem *)PCIE_VIRT_BASE)
void __init kirkwood_pcie_id(u32 *dev, u32 *rev)
{
*dev = orion_pcie_dev_id(PCIE_BASE);
*rev = orion_pcie_rev(PCIE_BASE);
*dev = orion_pcie_dev_id((void __iomem *)PCIE_VIRT_BASE);
*rev = orion_pcie_rev((void __iomem *)PCIE_VIRT_BASE);
}
static int pcie_valid_config(int bus, int dev)
struct pcie_port {
u8 root_bus_nr;
void __iomem *base;
spinlock_t conf_lock;
int irq;
struct resource res[2];
};
static int pcie_port_map[2];
static int num_pcie_ports;
static inline struct pcie_port *bus_to_port(struct pci_bus *bus)
{
struct pci_sys_data *sys = bus->sysdata;
return sys->private_data;
}
static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
{
/*
* Don't go out when trying to access --
* 1. nonexisting device on local bus
* 2. where there's no device connected (no link)
*/
if (bus == 0 && dev == 0)
if (bus == pp->root_bus_nr && dev == 0)
return 1;
if (!orion_pcie_link_up(PCIE_BASE))
if (!orion_pcie_link_up(pp->base))
return 0;
if (bus == 0 && dev != 1)
if (bus == pp->root_bus_nr && dev != 1)
return 0;
return 1;
@ -52,22 +66,22 @@ static int pcie_valid_config(int bus, int dev)
* and then reading the PCIE_CONF_DATA register. Need to make sure these
* transactions are atomic.
*/
static DEFINE_SPINLOCK(kirkwood_pcie_lock);
static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
int size, u32 *val)
{
struct pcie_port *pp = bus_to_port(bus);
unsigned long flags;
int ret;
if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) {
if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
*val = 0xffffffff;
return PCIBIOS_DEVICE_NOT_FOUND;
}
spin_lock_irqsave(&kirkwood_pcie_lock, flags);
ret = orion_pcie_rd_conf(PCIE_BASE, bus, devfn, where, size, val);
spin_unlock_irqrestore(&kirkwood_pcie_lock, flags);
spin_lock_irqsave(&pp->conf_lock, flags);
ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
spin_unlock_irqrestore(&pp->conf_lock, flags);
return ret;
}
@ -75,15 +89,16 @@ static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
int where, int size, u32 val)
{
struct pcie_port *pp = bus_to_port(bus);
unsigned long flags;
int ret;
if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0)
if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
spin_lock_irqsave(&kirkwood_pcie_lock, flags);
ret = orion_pcie_wr_conf(PCIE_BASE, bus, devfn, where, size, val);
spin_unlock_irqrestore(&kirkwood_pcie_lock, flags);
spin_lock_irqsave(&pp->conf_lock, flags);
ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
spin_unlock_irqrestore(&pp->conf_lock, flags);
return ret;
}
@ -93,50 +108,112 @@ static struct pci_ops pcie_ops = {
.write = pcie_wr_conf,
};
static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
static int __init pcie0_ioresources_setup(struct pci_sys_data *sys)
{
struct resource *res;
extern unsigned int kirkwood_clk_ctrl;
/*
* Generic PCIe unit setup.
*/
orion_pcie_setup(PCIE_BASE, &kirkwood_mbus_dram_info);
/*
* Request resources.
*/
res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
if (!res)
panic("pcie_setup unable to alloc resources");
struct pcie_port *pp = (struct pcie_port *)sys->private_data;
/*
* IORESOURCE_IO
*/
res[0].name = "PCIe I/O Space";
res[0].flags = IORESOURCE_IO;
res[0].start = KIRKWOOD_PCIE_IO_BUS_BASE;
res[0].end = res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
if (request_resource(&ioport_resource, &res[0]))
panic("Request PCIe IO resource failed\n");
sys->resource[0] = &res[0];
pp->res[0].name = "PCIe 0 I/O Space";
pp->res[0].start = KIRKWOOD_PCIE_IO_PHYS_BASE;
pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
pp->res[0].flags = IORESOURCE_IO;
if (request_resource(&ioport_resource, &pp->res[0]))
panic("Request PCIe 0 IO resource failed\n");
sys->resource[0] = &pp->res[0];
/*
* IORESOURCE_MEM
*/
res[1].name = "PCIe Memory Space";
res[1].flags = IORESOURCE_MEM;
res[1].start = KIRKWOOD_PCIE_MEM_BUS_BASE;
res[1].end = res[1].start + KIRKWOOD_PCIE_MEM_SIZE - 1;
if (request_resource(&iomem_resource, &res[1]))
panic("Request PCIe Memory resource failed\n");
sys->resource[1] = &res[1];
pp->res[1].name = "PCIe 0 MEM";
pp->res[1].start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE_MEM_SIZE - 1;
pp->res[1].flags = IORESOURCE_MEM;
if (request_resource(&iomem_resource, &pp->res[1]))
panic("Request PCIe 0 Memory resource failed\n");
sys->resource[1] = &pp->res[1];
sys->resource[2] = NULL;
sys->io_offset = 0;
kirkwood_clk_ctrl |= CGC_PEX0;
return 1;
}
static int __init pcie1_ioresources_setup(struct pci_sys_data *sys)
{
struct pcie_port *pp = (struct pcie_port *)sys->private_data;
/*
* IORESOURCE_IO
*/
pp->res[0].name = "PCIe 1 I/O Space";
pp->res[0].start = KIRKWOOD_PCIE1_IO_PHYS_BASE;
pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE1_IO_SIZE - 1;
pp->res[0].flags = IORESOURCE_IO;
if (request_resource(&ioport_resource, &pp->res[0]))
panic("Request PCIe 1 IO resource failed\n");
sys->resource[0] = &pp->res[0];
/*
* IORESOURCE_MEM
*/
pp->res[1].name = "PCIe 1 MEM";
pp->res[1].start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
pp->res[1].flags = IORESOURCE_MEM;
if (request_resource(&iomem_resource, &pp->res[1]))
panic("Request PCIe 1 Memory resource failed\n");
sys->resource[1] = &pp->res[1];
sys->resource[2] = NULL;
sys->io_offset = 0;
return 1;
}
static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
{
extern unsigned int kirkwood_clk_ctrl;
struct pcie_port *pp;
int index;
if (nr >= num_pcie_ports)
return 0;
index = pcie_port_map[nr];
printk(KERN_INFO "PCI: bus%d uses PCIe port %d\n", sys->busnr, index);
pp = kzalloc(sizeof(*pp), GFP_KERNEL);
if (!pp)
panic("PCIe: failed to allocate pcie_port data");
sys->private_data = pp;
pp->root_bus_nr = sys->busnr;
spin_lock_init(&pp->conf_lock);
switch (index) {
case 0:
pp->base = (void __iomem *)PCIE_VIRT_BASE;
pp->irq = IRQ_KIRKWOOD_PCIE;
kirkwood_clk_ctrl |= CGC_PEX0;
pcie0_ioresources_setup(sys);
break;
case 1:
pp->base = (void __iomem *)PCIE1_VIRT_BASE;
pp->irq = IRQ_KIRKWOOD_PCIE1;
kirkwood_clk_ctrl |= CGC_PEX1;
pcie1_ioresources_setup(sys);
break;
default:
panic("PCIe setup: invalid controller");
}
/*
* Generic PCIe unit setup.
*/
orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
orion_pcie_setup(pp->base, &kirkwood_mbus_dram_info);
return 1;
}
@ -163,7 +240,7 @@ kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys)
{
struct pci_bus *bus;
if (nr == 0) {
if (nr < num_pcie_ports) {
bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
} else {
bus = NULL;
@ -175,18 +252,37 @@ kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys)
static int __init kirkwood_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
return IRQ_KIRKWOOD_PCIE;
struct pcie_port *pp = bus_to_port(dev->bus);
return pp->irq;
}
static struct hw_pci kirkwood_pci __initdata = {
.nr_controllers = 1,
.swizzle = pci_std_swizzle,
.setup = kirkwood_pcie_setup,
.scan = kirkwood_pcie_scan_bus,
.map_irq = kirkwood_pcie_map_irq,
};
void __init kirkwood_pcie_init(void)
static void __init add_pcie_port(int index, unsigned long base)
{
printk(KERN_INFO "Kirkwood PCIe port %d: ", index);
if (orion_pcie_link_up((void __iomem *)base)) {
printk(KERN_INFO "link up\n");
pcie_port_map[num_pcie_ports++] = index;
} else
printk(KERN_INFO "link down, ignoring\n");
}
void __init kirkwood_pcie_init(unsigned int portmask)
{
if (portmask & KW_PCIE0)
add_pcie_port(0, PCIE_VIRT_BASE);
if (portmask & KW_PCIE1)
add_pcie_port(1, PCIE1_VIRT_BASE);
kirkwood_pci.nr_controllers = num_pcie_ports;
pci_common_init(&kirkwood_pci);
}

View file

@ -71,7 +71,7 @@ static void __init rd88f6192_init(void)
static int __init rd88f6192_pci_init(void)
{
if (machine_is_rd88f6192_nas())
kirkwood_pcie_init();
kirkwood_pcie_init(KW_PCIE0);
return 0;
}

View file

@ -107,7 +107,7 @@ static void __init rd88f6281_init(void)
static int __init rd88f6281_pci_init(void)
{
if (machine_is_rd88f6281())
kirkwood_pcie_init();
kirkwood_pcie_init(KW_PCIE0);
return 0;
}

View file

@ -176,7 +176,7 @@ static void __init hp_t5325_init(void)
static int __init hp_t5325_pci_init(void)
{
if (machine_is_t5325())
kirkwood_pcie_init();
kirkwood_pcie_init(KW_PCIE0);
return 0;
}

View file

@ -111,10 +111,10 @@ static void __init qnap_ts219_init(void)
static int __init ts219_pci_init(void)
{
if (machine_is_ts219())
kirkwood_pcie_init();
if (machine_is_ts219())
kirkwood_pcie_init(KW_PCIE0);
return 0;
return 0;
}
subsys_initcall(ts219_pci_init);

View file

@ -141,7 +141,7 @@ static void __init qnap_ts41x_init(void)
static int __init ts41x_pci_init(void)
{
if (machine_is_ts41x())
kirkwood_pcie_init();
kirkwood_pcie_init(KW_PCIE0);
return 0;
}