kernel-fxtec-pro1x/arch/powerpc/platforms/85xx/mpc85xx_ds.c
Kumar Gala 152d018282 powerpc/85xx: Add SWIOTLB support to FSL boards
Add the platform-specific code for enabling SWIOTLB if needed on P2020DS,
MPC85xx DS, and MPC85xx MDS boards as they are capable of having >4G of
memory.

We determine if we need to enable swiotlb based on how much memory is in
the board and if it exceeds 4G or what we can map via PCI inbound
windows.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
2009-06-15 21:45:29 -05:00

313 lines
7.1 KiB
C

/*
* MPC85xx DS Board Setup
*
* Author Xianghua Xiao (x.xiao@freescale.com)
* Roy Zang <tie-fei.zang@freescale.com>
* - Add PCI/PCI Exprees support
* Copyright 2007 Freescale Semiconductor Inc.
*
* 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/stddef.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/kdev_t.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
#include <linux/lmb.h>
#include <asm/system.h>
#include <asm/time.h>
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <mm/mmu_decl.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <asm/i8259.h>
#include <asm/swiotlb.h>
#include <sysdev/fsl_soc.h>
#include <sysdev/fsl_pci.h>
#undef DEBUG
#ifdef DEBUG
#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args)
#else
#define DBG(fmt, args...)
#endif
#ifdef CONFIG_PPC_I8259
static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
unsigned int cascade_irq = i8259_irq();
if (cascade_irq != NO_IRQ) {
generic_handle_irq(cascade_irq);
}
desc->chip->eoi(irq);
}
#endif /* CONFIG_PPC_I8259 */
void __init mpc85xx_ds_pic_init(void)
{
struct mpic *mpic;
struct resource r;
struct device_node *np;
#ifdef CONFIG_PPC_I8259
struct device_node *cascade_node = NULL;
int cascade_irq;
#endif
unsigned long root = of_get_flat_dt_root();
np = of_find_node_by_type(NULL, "open-pic");
if (np == NULL) {
printk(KERN_ERR "Could not find open-pic node\n");
return;
}
if (of_address_to_resource(np, 0, &r)) {
printk(KERN_ERR "Failed to map mpic register space\n");
of_node_put(np);
return;
}
if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) {
mpic = mpic_alloc(np, r.start,
MPIC_PRIMARY |
MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS,
0, 256, " OpenPIC ");
} else {
mpic = mpic_alloc(np, r.start,
MPIC_PRIMARY | MPIC_WANTS_RESET |
MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
MPIC_SINGLE_DEST_CPU,
0, 256, " OpenPIC ");
}
BUG_ON(mpic == NULL);
of_node_put(np);
mpic_init(mpic);
#ifdef CONFIG_PPC_I8259
/* Initialize the i8259 controller */
for_each_node_by_type(np, "interrupt-controller")
if (of_device_is_compatible(np, "chrp,iic")) {
cascade_node = np;
break;
}
if (cascade_node == NULL) {
printk(KERN_DEBUG "Could not find i8259 PIC\n");
return;
}
cascade_irq = irq_of_parse_and_map(cascade_node, 0);
if (cascade_irq == NO_IRQ) {
printk(KERN_ERR "Failed to map cascade interrupt\n");
return;
}
DBG("mpc85xxds: cascade mapped to irq %d\n", cascade_irq);
i8259_init(cascade_node, 0);
of_node_put(cascade_node);
set_irq_chained_handler(cascade_irq, mpc85xx_8259_cascade);
#endif /* CONFIG_PPC_I8259 */
}
#ifdef CONFIG_PCI
static int primary_phb_addr;
extern int uli_exclude_device(struct pci_controller *hose,
u_char bus, u_char devfn);
static int mpc85xx_exclude_device(struct pci_controller *hose,
u_char bus, u_char devfn)
{
struct device_node* node;
struct resource rsrc;
node = hose->dn;
of_address_to_resource(node, 0, &rsrc);
if ((rsrc.start & 0xfffff) == primary_phb_addr) {
return uli_exclude_device(hose, bus, devfn);
}
return PCIBIOS_SUCCESSFUL;
}
#endif /* CONFIG_PCI */
/*
* Setup the architecture
*/
#ifdef CONFIG_SMP
extern void __init mpc85xx_smp_init(void);
#endif
static void __init mpc85xx_ds_setup_arch(void)
{
#ifdef CONFIG_PCI
struct device_node *np;
struct pci_controller *hose;
#endif
dma_addr_t max = 0xffffffff;
if (ppc_md.progress)
ppc_md.progress("mpc85xx_ds_setup_arch()", 0);
#ifdef CONFIG_PCI
for_each_node_by_type(np, "pci") {
if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
of_device_is_compatible(np, "fsl,mpc8548-pcie") ||
of_device_is_compatible(np, "fsl,p2020-pcie")) {
struct resource rsrc;
of_address_to_resource(np, 0, &rsrc);
if ((rsrc.start & 0xfffff) == primary_phb_addr)
fsl_add_bridge(np, 1);
else
fsl_add_bridge(np, 0);
hose = pci_find_hose_for_OF_device(np);
max = min(max, hose->dma_window_base_cur +
hose->dma_window_size);
}
}
ppc_md.pci_exclude_device = mpc85xx_exclude_device;
#endif
#ifdef CONFIG_SMP
mpc85xx_smp_init();
#endif
#ifdef CONFIG_SWIOTLB
if (lmb_end_of_DRAM() > max) {
ppc_swiotlb_enable = 1;
set_pci_dma_ops(&swiotlb_pci_dma_ops);
}
#endif
printk("MPC85xx DS board from Freescale Semiconductor\n");
}
/*
* Called very early, device-tree isn't unflattened
*/
static int __init mpc8544_ds_probe(void)
{
unsigned long root = of_get_flat_dt_root();
if (of_flat_dt_is_compatible(root, "MPC8544DS")) {
#ifdef CONFIG_PCI
primary_phb_addr = 0xb000;
#endif
return 1;
}
return 0;
}
static struct of_device_id __initdata mpc85xxds_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .compatible = "simple-bus", },
{ .compatible = "gianfar", },
{},
};
static int __init mpc85xxds_publish_devices(void)
{
return of_platform_bus_probe(NULL, mpc85xxds_ids, NULL);
}
machine_device_initcall(mpc8544_ds, mpc85xxds_publish_devices);
machine_device_initcall(mpc8572_ds, mpc85xxds_publish_devices);
machine_device_initcall(p2020_ds, mpc85xxds_publish_devices);
machine_arch_initcall(mpc8544_ds, swiotlb_setup_bus_notifier);
machine_arch_initcall(mpc8572_ds, swiotlb_setup_bus_notifier);
machine_arch_initcall(p2020_ds, swiotlb_setup_bus_notifier);
/*
* Called very early, device-tree isn't unflattened
*/
static int __init mpc8572_ds_probe(void)
{
unsigned long root = of_get_flat_dt_root();
if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS")) {
#ifdef CONFIG_PCI
primary_phb_addr = 0x8000;
#endif
return 1;
}
return 0;
}
/*
* Called very early, device-tree isn't unflattened
*/
static int __init p2020_ds_probe(void)
{
unsigned long root = of_get_flat_dt_root();
if (of_flat_dt_is_compatible(root, "fsl,P2020DS")) {
#ifdef CONFIG_PCI
primary_phb_addr = 0x9000;
#endif
return 1;
}
return 0;
}
define_machine(mpc8544_ds) {
.name = "MPC8544 DS",
.probe = mpc8544_ds_probe,
.setup_arch = mpc85xx_ds_setup_arch,
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
};
define_machine(mpc8572_ds) {
.name = "MPC8572 DS",
.probe = mpc8572_ds_probe,
.setup_arch = mpc85xx_ds_setup_arch,
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
};
define_machine(p2020_ds) {
.name = "P2020 DS",
.probe = p2020_ds_probe,
.setup_arch = mpc85xx_ds_setup_arch,
.init_IRQ = mpc85xx_ds_pic_init,
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
.get_irq = mpic_get_irq,
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
};