aboutsummaryrefslogtreecommitdiff
path: root/drivers/ssb/driver_pcicore.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ssb/driver_pcicore.c')
-rw-r--r--drivers/ssb/driver_pcicore.c52
1 files changed, 43 insertions, 9 deletions
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 2faaa906d5d..74b9a8aea52 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -11,6 +11,7 @@
#include <linux/ssb/ssb.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/ssb/ssb_embedded.h>
#include "ssb_private.h"
@@ -27,6 +28,18 @@ void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value)
ssb_write32(pc->dev, offset, value);
}
+static inline
+u16 pcicore_read16(struct ssb_pcicore *pc, u16 offset)
+{
+ return ssb_read16(pc->dev, offset);
+}
+
+static inline
+void pcicore_write16(struct ssb_pcicore *pc, u16 offset, u16 value)
+{
+ ssb_write16(pc->dev, offset, value);
+}
+
/**************************************************
* Code for hostmode operation.
**************************************************/
@@ -66,6 +79,7 @@ int pcibios_plat_dev_init(struct pci_dev *d)
base = &ssb_pcicore_pcibus_iobase;
else
base = &ssb_pcicore_pcibus_membase;
+ res->flags |= IORESOURCE_PCI_FIXED;
if (res->end) {
size = res->end - res->start + 1;
if (*base & (size - 1))
@@ -88,20 +102,28 @@ int pcibios_plat_dev_init(struct pci_dev *d)
static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
{
+ u8 lat;
+
if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
return;
- ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
+ ssb_printk(KERN_INFO "PCI: Fixing up bridge %s\n", pci_name(dev));
/* Enable PCI bridge bus mastering and memory space */
pci_set_master(dev);
- pcibios_enable_device(dev, ~0);
+ if (pcibios_enable_device(dev, ~0) < 0) {
+ ssb_printk(KERN_ERR "PCI: SSB bridge enable failed\n");
+ return;
+ }
/* Enable PCI bridge BAR1 prefetch and burst */
pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
/* Make sure our latency is high enough to handle the devices behind us */
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
+ lat = 168;
+ ssb_printk(KERN_INFO "PCI: Fixing latency timer of device %s to %u\n",
+ pci_name(dev), lat);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
}
DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
@@ -117,8 +139,10 @@ static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
u32 addr = 0;
u32 tmp;
- if (unlikely(pc->cardbusmode && dev > 1))
+ /* We do only have one cardbus device behind the bridge. */
+ if (pc->cardbusmode && (dev >= 1))
goto out;
+
if (bus == 0) {
/* Type 0 transaction */
if (unlikely(dev >= SSB_PCI_SLOT_MAX))
@@ -279,14 +303,14 @@ static struct resource ssb_pcicore_mem_resource = {
.name = "SSB PCIcore external memory",
.start = SSB_PCI_DMA,
.end = SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
- .flags = IORESOURCE_MEM,
+ .flags = IORESOURCE_MEM | IORESOURCE_PCI_FIXED,
};
static struct resource ssb_pcicore_io_resource = {
.name = "SSB PCIcore external I/O",
.start = 0x100,
.end = 0x7FF,
- .flags = IORESOURCE_IO,
+ .flags = IORESOURCE_IO | IORESOURCE_PCI_FIXED,
};
static struct pci_controller ssb_pcicore_controller = {
@@ -318,7 +342,16 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
udelay(1); /* Assertion time demanded by the PCI standard */
- /*TODO cardbus mode */
+ if (pc->dev->bus->has_cardbus_slot) {
+ ssb_dprintk(KERN_INFO PFX "CardBus slot detected\n");
+ pc->cardbusmode = 1;
+ /* GPIO 1 resets the bridge */
+ ssb_gpio_out(pc->dev->bus, 1, 1);
+ ssb_gpio_outen(pc->dev->bus, 1, 1);
+ pcicore_write16(pc, SSB_PCICORE_SPROM(0),
+ pcicore_read16(pc, SSB_PCICORE_SPROM(0))
+ | 0x0400);
+ }
/* 64MB I/O window */
pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
@@ -344,7 +377,8 @@ static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
/* Ok, ready to run, register it to the system.
* The following needs change, if we want to port hostmode
* to non-MIPS platform. */
- set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
+ ssb_pcicore_controller.io_map_base = (unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000);
+ set_io_port_base(ssb_pcicore_controller.io_map_base);
/* Give some time to the PCI controller to configure itself with the new
* values. Not waiting at this point causes crashes of the machine. */
mdelay(10);
@@ -362,7 +396,7 @@ static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
chipid_top != 0x5300)
return 0;
- if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+ if (bus->sprom.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
return 0;
/* The 200-pin BCM4712 package does not bond out PCI. Even when