summaryrefslogtreecommitdiff
path: root/arch/powerpc/sysdev
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c8
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c117
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h3
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c4
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c2
-rw-r--r--arch/powerpc/sysdev/micropatch.c30
-rw-r--r--arch/powerpc/sysdev/mpic.c2
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c119
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.h58
9 files changed, 299 insertions, 44 deletions
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index c8b96ed7c015..559db2b846a9 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -36,7 +36,7 @@
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <linux/suspend.h>
-#include <linux/lmb.h>
+#include <linux/memblock.h>
#include <linux/gfp.h>
#include <asm/io.h>
#include <asm/prom.h>
@@ -232,7 +232,7 @@ static int __init dart_init(struct device_node *dart_node)
* that to work around what looks like a problem with the HT bridge
* prefetching into invalid pages and corrupting data
*/
- tmp = lmb_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
+ tmp = memblock_alloc(DART_PAGE_SIZE, DART_PAGE_SIZE);
dart_emptyval = DARTMAP_VALID | ((tmp >> DART_PAGE_SHIFT) &
DARTMAP_RPNMASK);
@@ -407,7 +407,7 @@ void __init alloc_dart_table(void)
if (iommu_is_off)
return;
- if (!iommu_force_on && lmb_end_of_DRAM() <= 0x40000000ull)
+ if (!iommu_force_on && memblock_end_of_DRAM() <= 0x40000000ull)
return;
/* 512 pages (2MB) is max DART tablesize. */
@@ -416,7 +416,7 @@ void __init alloc_dart_table(void)
* will blow up an entire large page anyway in the kernel mapping
*/
dart_tablebase = (unsigned long)
- abs_to_virt(lmb_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
+ abs_to_virt(memblock_alloc_base(1UL<<24, 1UL<<24, 0x80000000L));
printk(KERN_INFO "DART table allocated at: %lx\n", dart_tablebase);
}
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index a7be144f5874..962c2d8dd8d9 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Freescale Semiconductor, Inc.
*
* Author: Tony Li <tony.li@freescale.com>
* Jason Jin <Jason.jin@freescale.com>
@@ -22,14 +22,20 @@
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
+#include <asm/mpic.h>
#include "fsl_msi.h"
+LIST_HEAD(msi_head);
+
struct fsl_msi_feature {
u32 fsl_pic_ip;
u32 msiir_offset;
};
-static struct fsl_msi *fsl_msi;
+struct fsl_msi_cascade_data {
+ struct fsl_msi *msi_data;
+ int index;
+};
static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg)
{
@@ -54,10 +60,12 @@ static struct irq_chip fsl_msi_chip = {
static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
+ struct fsl_msi *msi_data = h->host_data;
struct irq_chip *chip = &fsl_msi_chip;
irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING;
+ set_irq_chip_data(virq, msi_data);
set_irq_chip_and_handler(virq, chip, handle_edge_irq);
return 0;
@@ -96,11 +104,12 @@ static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;
- struct fsl_msi *msi_data = fsl_msi;
+ struct fsl_msi *msi_data;
list_for_each_entry(entry, &pdev->msi_list, list) {
if (entry->irq == NO_IRQ)
continue;
+ msi_data = get_irq_data(entry->irq);
set_irq_msi(entry->irq, NULL);
msi_bitmap_free_hwirqs(&msi_data->bitmap,
virq_to_hw(entry->irq), 1);
@@ -111,9 +120,10 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
}
static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
- struct msi_msg *msg)
+ struct msi_msg *msg,
+ struct fsl_msi *fsl_msi_data)
{
- struct fsl_msi *msi_data = fsl_msi;
+ struct fsl_msi *msi_data = fsl_msi_data;
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
u32 base = 0;
@@ -130,14 +140,19 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
- int rc, hwirq;
+ int rc, hwirq = -ENOMEM;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
- struct fsl_msi *msi_data = fsl_msi;
+ struct fsl_msi *msi_data;
list_for_each_entry(entry, &pdev->msi_list, list) {
- hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+ list_for_each_entry(msi_data, &msi_head, list) {
+ hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+ if (hwirq >= 0)
+ break;
+ }
+
if (hwirq < 0) {
rc = hwirq;
pr_debug("%s: fail allocating msi interrupt\n",
@@ -154,25 +169,31 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
rc = -ENOSPC;
goto out_free;
}
+ set_irq_data(virq, msi_data);
set_irq_msi(virq, entry);
- fsl_compose_msi_msg(pdev, hwirq, &msg);
+ fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
write_msi_msg(virq, &msg);
}
return 0;
out_free:
+ /* free by the caller of this function */
return rc;
}
static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
{
unsigned int cascade_irq;
- struct fsl_msi *msi_data = fsl_msi;
+ struct fsl_msi *msi_data;
int msir_index = -1;
u32 msir_value = 0;
u32 intr_index;
u32 have_shift = 0;
+ struct fsl_msi_cascade_data *cascade_data;
+
+ cascade_data = (struct fsl_msi_cascade_data *)get_irq_data(irq);
+ msi_data = cascade_data->msi_data;
raw_spin_lock(&desc->lock);
if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) {
@@ -187,13 +208,13 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
if (unlikely(desc->status & IRQ_INPROGRESS))
goto unlock;
- msir_index = (int)desc->handler_data;
+ msir_index = cascade_data->index;
if (msir_index >= NR_MSI_REG)
cascade_irq = NO_IRQ;
desc->status |= IRQ_INPROGRESS;
- switch (fsl_msi->feature & FSL_PIC_IP_MASK) {
+ switch (msi_data->feature & FSL_PIC_IP_MASK) {
case FSL_PIC_IP_MPIC:
msir_value = fsl_msi_read(msi_data->msi_regs,
msir_index * 0x10);
@@ -229,6 +250,30 @@ unlock:
raw_spin_unlock(&desc->lock);
}
+static int fsl_of_msi_remove(struct of_device *ofdev)
+{
+ struct fsl_msi *msi = ofdev->dev.platform_data;
+ int virq, i;
+ struct fsl_msi_cascade_data *cascade_data;
+
+ if (msi->list.prev != NULL)
+ list_del(&msi->list);
+ for (i = 0; i < NR_MSI_REG; i++) {
+ virq = msi->msi_virqs[i];
+ if (virq != NO_IRQ) {
+ cascade_data = get_irq_data(virq);
+ kfree(cascade_data);
+ irq_dispose_mapping(virq);
+ }
+ }
+ if (msi->bitmap.bitmap)
+ msi_bitmap_free(&msi->bitmap);
+ iounmap(msi->msi_regs);
+ kfree(msi);
+
+ return 0;
+}
+
static int __devinit fsl_of_msi_probe(struct of_device *dev,
const struct of_device_id *match)
{
@@ -239,15 +284,18 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
int virt_msir;
const u32 *p;
struct fsl_msi_feature *features = match->data;
+ struct fsl_msi_cascade_data *cascade_data = NULL;
+ int len;
+ u32 offset;
printk(KERN_DEBUG "Setting up Freescale MSI support\n");
msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL);
if (!msi) {
dev_err(&dev->dev, "No memory for MSI structure\n");
- err = -ENOMEM;
- goto error_out;
+ return -ENOMEM;
}
+ dev->dev.platform_data = msi;
msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR,
NR_MSI_IRQS, &fsl_msi_host_ops, 0);
@@ -298,27 +346,47 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
err = -EINVAL;
goto error_out;
}
+ offset = 0;
+ p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len);
+ if (p)
+ offset = *p / IRQS_PER_MSI_REG;
count /= sizeof(u32);
- for (i = 0; i < count / 2; i++) {
- if (i > NR_MSI_REG)
- break;
+ for (i = 0; i < min(count / 2, NR_MSI_REG); i++) {
virt_msir = irq_of_parse_and_map(dev->dev.of_node, i);
if (virt_msir != NO_IRQ) {
- set_irq_data(virt_msir, (void *)i);
+ cascade_data = kzalloc(
+ sizeof(struct fsl_msi_cascade_data),
+ GFP_KERNEL);
+ if (!cascade_data) {
+ dev_err(&dev->dev,
+ "No memory for MSI cascade data\n");
+ err = -ENOMEM;
+ goto error_out;
+ }
+ msi->msi_virqs[i] = virt_msir;
+ cascade_data->index = i + offset;
+ cascade_data->msi_data = msi;
+ set_irq_data(virt_msir, (void *)cascade_data);
set_irq_chained_handler(virt_msir, fsl_msi_cascade);
}
}
- fsl_msi = msi;
+ list_add_tail(&msi->list, &msi_head);
- WARN_ON(ppc_md.setup_msi_irqs);
- ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
- ppc_md.msi_check_device = fsl_msi_check_device;
+ /* The multiple setting ppc_md.setup_msi_irqs will not harm things */
+ if (!ppc_md.setup_msi_irqs) {
+ ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
+ ppc_md.msi_check_device = fsl_msi_check_device;
+ } else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) {
+ dev_err(&dev->dev, "Different MSI driver already installed!\n");
+ err = -ENODEV;
+ goto error_out;
+ }
return 0;
error_out:
- kfree(msi);
+ fsl_of_msi_remove(dev);
return err;
}
@@ -351,6 +419,7 @@ static struct of_platform_driver fsl_of_msi_driver = {
.of_match_table = fsl_of_msi_ids,
},
.probe = fsl_of_msi_probe,
+ .remove = fsl_of_msi_remove,
};
static __init int fsl_of_msi_init(void)
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index 331c7e7025b7..624580c252d7 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -32,8 +32,11 @@ struct fsl_msi {
u32 msi_addr_hi;
void __iomem *msi_regs;
u32 feature;
+ int msi_virqs[NR_MSI_REG];
struct msi_bitmap bitmap;
+
+ struct list_head list; /* support multiple MSI banks */
};
#endif /* _POWERPC_SYSDEV_FSL_MSI_H */
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index a14760fe513a..356c6a0e1b23 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -23,7 +23,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>
-#include <linux/lmb.h>
+#include <linux/memblock.h>
#include <linux/log2.h>
#include <linux/slab.h>
@@ -190,7 +190,7 @@ static void __init setup_pci_atmu(struct pci_controller *hose,
pr_info("%s: PCICSRBAR @ 0x%x\n", name, pcicsrbar);
/* Setup inbound mem window */
- mem = lmb_end_of_DRAM();
+ mem = memblock_end_of_DRAM();
sz = min(mem, paddr_lo);
mem_log = __ilog2_u64(sz);
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index cd37e49e7034..30e1626b2e85 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -1426,7 +1426,7 @@ int fsl_rio_setup(struct of_device *dev)
port->iores.flags = IORESOURCE_MEM;
port->iores.name = "rio_io_win";
- priv->pwirq = irq_of_parse_and_map(dev->node, 0);
+ priv->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0);
priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2);
priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3);
priv->rxirq = irq_of_parse_and_map(dev->dev.of_node, 4);
diff --git a/arch/powerpc/sysdev/micropatch.c b/arch/powerpc/sysdev/micropatch.c
index d8d602840757..c0bb76ef7242 100644
--- a/arch/powerpc/sysdev/micropatch.c
+++ b/arch/powerpc/sysdev/micropatch.c
@@ -4,6 +4,7 @@
* also relocates SMC2, but this would require additional changes
* to uart.c, so I am holding off on that for a moment.
*/
+#include <linux/init.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -16,6 +17,7 @@
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/8xx_immap.h>
+#include <asm/cpm.h>
#include <asm/cpm1.h>
/*
@@ -24,7 +26,7 @@
#ifdef CONFIG_I2C_SPI_UCODE_PATCH
-uint patch_2000[] = {
+static uint patch_2000[] __initdata = {
0x7FFFEFD9,
0x3FFD0000,
0x7FFB49F7,
@@ -143,7 +145,7 @@ uint patch_2000[] = {
0x5F8247F8
};
-uint patch_2f00[] = {
+static uint patch_2f00[] __initdata = {
0x3E303430,
0x34343737,
0xABF7BF9B,
@@ -182,7 +184,7 @@ uint patch_2f00[] = {
#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
-uint patch_2000[] = {
+static uint patch_2000[] __initdata = {
0x3fff0000,
0x3ffd0000,
0x3ffb0000,
@@ -505,7 +507,7 @@ uint patch_2000[] = {
0x6079e2bb
};
-uint patch_2f00[] = {
+static uint patch_2f00[] __initdata = {
0x30303030,
0x3e3e3434,
0xabbf9b99,
@@ -572,7 +574,7 @@ uint patch_2f00[] = {
0xf22f3f23
};
-uint patch_2e00[] = {
+static uint patch_2e00[] __initdata = {
0x27eeeeee,
0xeeeeeeee,
0xeeeeeeee,
@@ -598,7 +600,7 @@ uint patch_2e00[] = {
#ifdef CONFIG_USB_SOF_UCODE_PATCH
-uint patch_2000[] = {
+static uint patch_2000[] __initdata = {
0x7fff0000,
0x7ffd0000,
0x7ffb0000,
@@ -613,21 +615,25 @@ uint patch_2000[] = {
0x60750000
};
-uint patch_2f00[] = {
+static uint patch_2f00[] __initdata = {
0x3030304c,
0xcab9e441,
0xa1aaf220
};
#endif
-void
-cpm_load_patch(cpm8xx_t *cp)
+void __init cpm_load_patch(cpm8xx_t *cp)
{
volatile uint *dp; /* Dual-ported RAM. */
volatile cpm8xx_t *commproc;
+#if defined(CONFIG_I2C_SPI_UCODE_PATCH) || \
+ defined(CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
volatile iic_t *iip;
- volatile spi_t *spp;
+ volatile struct spi_pram *spp;
+#ifdef CONFIG_I2C_SPI_SMC1_UCODE_PATCH
volatile smc_uart_t *smp;
+#endif
+#endif
int i;
commproc = cp;
@@ -668,8 +674,8 @@ cpm_load_patch(cpm8xx_t *cp)
/* Put SPI above the IIC, also 32-byte aligned.
*/
i = (RPBASE + sizeof(iic_t) + 31) & ~31;
- spp = (spi_t *)&commproc->cp_dparam[PROFF_SPI];
- spp->spi_rpbase = i;
+ spp = (struct spi_pram *)&commproc->cp_dparam[PROFF_SPI];
+ spp->rpbase = i;
# if defined(CONFIG_I2C_SPI_UCODE_PATCH)
commproc->cp_cpmcr1 = 0x802a;
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 2102487612a4..20b73c025a45 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1666,7 +1666,7 @@ static int mpic_resume(struct sys_device *dev)
mpic->save_data[i].dest);
#ifdef CONFIG_MPIC_U3_HT_IRQS
- {
+ if (mpic->fixups) {
struct mpic_irq_fixup *fixup = &mpic->fixups[i];
if (fixup->base) {
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index 106d767bf65b..156aa7d36258 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -974,6 +974,123 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata =
.setup_utl = ppc460ex_pciex_init_utl,
};
+static int __init ppc460sx_pciex_core_init(struct device_node *np)
+{
+ /* HSS drive amplitude */
+ mtdcri(SDR0, PESDR0_460SX_HSSL0DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL1DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL2DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL3DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL4DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL5DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL6DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL7DAMP, 0xB9843211);
+
+ mtdcri(SDR0, PESDR1_460SX_HSSL0DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR1_460SX_HSSL1DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR1_460SX_HSSL2DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR1_460SX_HSSL3DAMP, 0xB9843211);
+
+ mtdcri(SDR0, PESDR2_460SX_HSSL0DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR2_460SX_HSSL1DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR2_460SX_HSSL2DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR2_460SX_HSSL3DAMP, 0xB9843211);
+
+ /* HSS TX pre-emphasis */
+ mtdcri(SDR0, PESDR0_460SX_HSSL0COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL1COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL2COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL3COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL4COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL5COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL6COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL7COEFA, 0xDCB98987);
+
+ mtdcri(SDR0, PESDR1_460SX_HSSL0COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR1_460SX_HSSL1COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR1_460SX_HSSL2COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR1_460SX_HSSL3COEFA, 0xDCB98987);
+
+ mtdcri(SDR0, PESDR2_460SX_HSSL0COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR2_460SX_HSSL1COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR2_460SX_HSSL2COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR2_460SX_HSSL3COEFA, 0xDCB98987);
+
+ /* HSS TX calibration control */
+ mtdcri(SDR0, PESDR0_460SX_HSSL1CALDRV, 0x22222222);
+ mtdcri(SDR0, PESDR1_460SX_HSSL1CALDRV, 0x22220000);
+ mtdcri(SDR0, PESDR2_460SX_HSSL1CALDRV, 0x22220000);
+
+ /* HSS TX slew control */
+ mtdcri(SDR0, PESDR0_460SX_HSSSLEW, 0xFFFFFFFF);
+ mtdcri(SDR0, PESDR1_460SX_HSSSLEW, 0xFFFF0000);
+ mtdcri(SDR0, PESDR2_460SX_HSSSLEW, 0xFFFF0000);
+
+ udelay(100);
+
+ /* De-assert PLLRESET */
+ dcri_clrset(SDR0, PESDR0_PLLLCT2, 0x00000100, 0);
+
+ /* Reset DL, UTL, GPL before configuration */
+ mtdcri(SDR0, PESDR0_460SX_RCSSET,
+ PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
+ mtdcri(SDR0, PESDR1_460SX_RCSSET,
+ PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
+ mtdcri(SDR0, PESDR2_460SX_RCSSET,
+ PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
+
+ udelay(100);
+
+ /*
+ * If bifurcation is not enabled, u-boot would have disabled the
+ * third PCIe port
+ */
+ if (((mfdcri(SDR0, PESDR1_460SX_HSSCTLSET) & 0x00000001) ==
+ 0x00000001)) {
+ printk(KERN_INFO "PCI: PCIE bifurcation setup successfully.\n");
+ printk(KERN_INFO "PCI: Total 3 PCIE ports are present\n");
+ return 3;
+ }
+
+ printk(KERN_INFO "PCI: Total 2 PCIE ports are present\n");
+ return 2;
+}
+
+static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
+{
+
+ if (port->endpoint)
+ dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2,
+ 0x01000000, 0);
+ else
+ dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2,
+ 0, 0x01000000);
+
+ /*Gen-1*/
+ mtdcri(SDR0, port->sdr_base + PESDRn_460SX_RCEI, 0x08000000);
+
+ dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET,
+ (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL),
+ PESDRx_RCSSET_RSTPYN);
+
+ port->has_ibpre = 1;
+
+ return 0;
+}
+
+static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port)
+{
+ /* Max 128 Bytes */
+ out_be32 (port->utl_base + PEUTL_PBBSZ, 0x00000000);
+ return 0;
+}
+
+static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = {
+ .core_init = ppc460sx_pciex_core_init,
+ .port_init_hw = ppc460sx_pciex_init_port_hw,
+ .setup_utl = ppc460sx_pciex_init_utl,
+};
+
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
@@ -1089,6 +1206,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
}
if (of_device_is_compatible(np, "ibm,plb-pciex-460ex"))
ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops;
+ if (of_device_is_compatible(np, "ibm,plb-pciex-460sx"))
+ ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops;
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h
index d04e40b306fb..56d9e5deccbf 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.h
+++ b/arch/powerpc/sysdev/ppc4xx_pci.h
@@ -324,6 +324,64 @@
#define PESDR0_460EX_IHS2 0x036D
/*
+ * 460SX addtional DCRs
+ */
+#define PESDRn_460SX_RCEI 0x02
+
+#define PESDR0_460SX_HSSL0DAMP 0x320
+#define PESDR0_460SX_HSSL1DAMP 0x321
+#define PESDR0_460SX_HSSL2DAMP 0x322
+#define PESDR0_460SX_HSSL3DAMP 0x323
+#define PESDR0_460SX_HSSL4DAMP 0x324
+#define PESDR0_460SX_HSSL5DAMP 0x325
+#define PESDR0_460SX_HSSL6DAMP 0x326
+#define PESDR0_460SX_HSSL7DAMP 0x327
+
+#define PESDR1_460SX_HSSL0DAMP 0x354
+#define PESDR1_460SX_HSSL1DAMP 0x355
+#define PESDR1_460SX_HSSL2DAMP 0x356
+#define PESDR1_460SX_HSSL3DAMP 0x357
+
+#define PESDR2_460SX_HSSL0DAMP 0x384
+#define PESDR2_460SX_HSSL1DAMP 0x385
+#define PESDR2_460SX_HSSL2DAMP 0x386
+#define PESDR2_460SX_HSSL3DAMP 0x387
+
+#define PESDR0_460SX_HSSL0COEFA 0x328
+#define PESDR0_460SX_HSSL1COEFA 0x329
+#define PESDR0_460SX_HSSL2COEFA 0x32A
+#define PESDR0_460SX_HSSL3COEFA 0x32B
+#define PESDR0_460SX_HSSL4COEFA 0x32C
+#define PESDR0_460SX_HSSL5COEFA 0x32D
+#define PESDR0_460SX_HSSL6COEFA 0x32E
+#define PESDR0_460SX_HSSL7COEFA 0x32F
+
+#define PESDR1_460SX_HSSL0COEFA 0x358
+#define PESDR1_460SX_HSSL1COEFA 0x359
+#define PESDR1_460SX_HSSL2COEFA 0x35A
+#define PESDR1_460SX_HSSL3COEFA 0x35B
+
+#define PESDR2_460SX_HSSL0COEFA 0x388
+#define PESDR2_460SX_HSSL1COEFA 0x389
+#define PESDR2_460SX_HSSL2COEFA 0x38A
+#define PESDR2_460SX_HSSL3COEFA 0x38B
+
+#define PESDR0_460SX_HSSL1CALDRV 0x339
+#define PESDR1_460SX_HSSL1CALDRV 0x361
+#define PESDR2_460SX_HSSL1CALDRV 0x391
+
+#define PESDR0_460SX_HSSSLEW 0x338
+#define PESDR1_460SX_HSSSLEW 0x360
+#define PESDR2_460SX_HSSSLEW 0x390
+
+#define PESDR0_460SX_HSSCTLSET 0x31E
+#define PESDR1_460SX_HSSCTLSET 0x352
+#define PESDR2_460SX_HSSCTLSET 0x382
+
+#define PESDR0_460SX_RCSSET 0x304
+#define PESDR1_460SX_RCSSET 0x344
+#define PESDR2_460SX_RCSSET 0x374
+/*
* Of the above, some are common offsets from the base
*/
#define PESDRn_UTLSET1 0x00