aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/pci/ops-tx3927.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/pci/ops-tx3927.c')
-rw-r--r--arch/mips/pci/ops-tx3927.c418
1 files changed, 129 insertions, 289 deletions
diff --git a/arch/mips/pci/ops-tx3927.c b/arch/mips/pci/ops-tx3927.c
index 0e0daadc303..d35dc9c9ab9 100644
--- a/arch/mips/pci/ops-tx3927.c
+++ b/arch/mips/pci/ops-tx3927.c
@@ -8,10 +8,10 @@
*
* Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c
*
- * Define the pci_ops for JMR3927.
+ * Define the pci_ops for TX3927.
*
* Much of the code is derived from the original DDB5074 port by
- * Geert Uytterhoeven <geert@sonycom.com>
+ * Geert Uytterhoeven <geert@linux-m68k.org>
*
* 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
@@ -37,50 +37,49 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/addrspace.h>
-#include <asm/jmr3927/jmr3927.h>
-#include <asm/debug.h>
+#include <asm/txx9irq.h>
+#include <asm/txx9/pci.h>
+#include <asm/txx9/tx3927.h>
-static inline int mkaddr(unsigned char bus, unsigned char dev_fn,
- unsigned char where)
+static int mkaddr(struct pci_bus *bus, unsigned char devfn, unsigned char where)
{
- if (bus == 0 && dev_fn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- tx3927_pcicptr->ica = ((bus & 0xff) << 0x10) |
- ((dev_fn & 0xff) << 0x08) |
- (where & 0xfc);
+ if (bus->parent == NULL &&
+ devfn >= PCI_DEVFN(TX3927_PCIC_MAX_DEVNU, 0))
+ return -1;
+ tx3927_pcicptr->ica =
+ ((bus->number & 0xff) << 0x10) |
+ ((devfn & 0xff) << 0x08) |
+ (where & 0xfc) | (bus->parent ? 1 : 0);
/* clear M_ABORT and Disable M_ABORT Int. */
tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
tx3927_pcicptr->pcistatim &= ~PCI_STATUS_REC_MASTER_ABORT;
-
- return PCIBIOS_SUCCESSFUL;
+ return 0;
}
static inline int check_abort(void)
{
- if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT)
+ if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT) {
tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT;
+ /* flush write buffer */
+ iob();
return PCIBIOS_DEVICE_NOT_FOUND;
-
+ }
return PCIBIOS_SUCCESSFUL;
}
-static int jmr3927_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+static int tx3927_pci_read_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 * val)
{
- int ret, busno;
-
- /* check if the bus is top-level */
- if (bus->parent != NULL)
- busno = bus->number;
-
- ret = mkaddr(busno, devfn, where);
- if (ret)
- return ret;
+ if (mkaddr(bus, devfn, where)) {
+ *val = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
switch (size) {
case 1:
@@ -99,20 +98,11 @@ static int jmr3927_pci_read_config(struct pci_bus *bus, unsigned int devfn,
return check_abort();
}
-static int jmr3927_pci_write_config(struct pci_bus *bus, unsigned int devfn,
+static int tx3927_pci_write_config(struct pci_bus *bus, unsigned int devfn,
int where, int size, u32 val)
{
- int ret, busno;
-
- /* check if the bus is top-level */
- if (bus->parent != NULL)
- bus = bus->number;
- else
- bus = 0;
-
- ret = mkaddr(busno, devfn, where);
- if (ret)
- return ret;
+ if (mkaddr(bus, devfn, where))
+ return PCIBIOS_DEVICE_NOT_FOUND;
switch (size) {
case 1:
@@ -120,7 +110,7 @@ static int jmr3927_pci_write_config(struct pci_bus *bus, unsigned int devfn,
break;
case 2:
- *(volatile u16 *) (unsigned longulong) & tx3927_pcicptr->icd | (where & 2)) =
+ *(volatile u16 *) ((unsigned long) & tx3927_pcicptr->icd | (where & 2)) =
cpu_to_le16(val);
break;
@@ -128,264 +118,114 @@ static int jmr3927_pci_write_config(struct pci_bus *bus, unsigned int devfn,
tx3927_pcicptr->icd = cpu_to_le32(val);
}
- if (tx3927_pcicptr->pcistat & PCI_STATUS_REC_MASTER_ABORT)
- tx3927_pcicptr->pcistat |= PCI_STATUS_REC_MASTER_ABORT;
- tx3927_pcicptr->pcistatim |= PCI_STATUS_REC_MASTER_ABORT;
- return PCIBIOS_DEVICE_NOT_FOUND;
-
return check_abort();
}
-struct pci_ops jmr3927_pci_ops = {
- jmr3927_pcibios_read_config,
- jmr3927_pcibios_write_config,
+static struct pci_ops tx3927_pci_ops = {
+ .read = tx3927_pci_read_config,
+ .write = tx3927_pci_write_config,
};
-
-#ifndef JMR3927_INIT_INDIRECT_PCI
-
-inline unsigned long tc_readl(volatile __u32 * addr)
-{
- return readl(addr);
-}
-
-inline void tc_writel(unsigned long data, volatile __u32 * addr)
-{
- writel(data, addr);
-}
-#else
-
-unsigned long tc_readl(volatile __u32 * addr)
-{
- unsigned long val;
-
- addr = PHYSADDR(addr);
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
- (unsigned long) addr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
- (PCI_IPCIBE_ICMD_MEMREAD << PCI_IPCIBE_ICMD_SHIFT) |
- PCI_IPCIBE_IBE_LONG;
- while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
- val =
- le32_to_cpu(*(volatile u32 *) (ulong) & tx3927_pcicptr->
- ipcidata);
- /* clear by setting */
- tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
- return val;
-}
-
-void tc_writel(unsigned long data, volatile __u32 * addr)
-{
- addr = PHYSADDR(addr);
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcidata =
- cpu_to_le32(data);
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
- (unsigned long) addr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
- (PCI_IPCIBE_ICMD_MEMWRITE << PCI_IPCIBE_ICMD_SHIFT) |
- PCI_IPCIBE_IBE_LONG;
- while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
- /* clear by setting */
- tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-}
-
-unsigned char tx_ioinb(unsigned char *addr)
-{
- unsigned long val;
- __u32 ioaddr;
- int offset;
- int byte;
-
- ioaddr = (unsigned long) addr;
- offset = ioaddr & 0x3;
- if (offset == 0)
- byte = 0x7;
- else if (offset == 1)
- byte = 0xb;
- else if (offset == 2)
- byte = 0xd;
- else if (offset == 3)
- byte = 0xe;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
- (unsigned long) ioaddr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
- (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte;
- while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
- val =
- le32_to_cpu(*(volatile u32 *) (ulong) & tx3927_pcicptr->
- ipcidata);
- val = val & 0xff;
- /* clear by setting */
- tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
- return val;
-}
-
-void tx_iooutb(unsigned long data, unsigned char *addr)
-{
- __u32 ioaddr;
- int offset;
- int byte;
-
- data = data | (data << 8) | (data << 16) | (data << 24);
- ioaddr = (unsigned long) addr;
- offset = ioaddr & 0x3;
- if (offset == 0)
- byte = 0x7;
- else if (offset == 1)
- byte = 0xb;
- else if (offset == 2)
- byte = 0xd;
- else if (offset == 3)
- byte = 0xe;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcidata = data;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
- (unsigned long) ioaddr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
- (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte;
- while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
- /* clear by setting */
- tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-}
-
-unsigned short tx_ioinw(unsigned short *addr)
-{
- unsigned long val;
- __u32 ioaddr;
- int offset;
- int byte;
-
- ioaddr = (unsigned long) addr;
- offset = ioaddr & 0x3;
- if (offset == 0)
- byte = 0x3;
- else if (offset == 2)
- byte = 0xc;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
- (unsigned long) ioaddr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
- (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) | byte;
- while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
- val =
- le32_to_cpu(*(volatile u32 *) (ulong) & tx3927_pcicptr->
- ipcidata);
- val = val & 0xffff;
- /* clear by setting */
- tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
- return val;
-
-}
-
-void tx_iooutw(unsigned long data, unsigned short *addr)
-{
- __u32 ioaddr;
- int offset;
- int byte;
-
- data = data | (data << 16);
- ioaddr = (unsigned long) addr;
- offset = ioaddr & 0x3;
- if (offset == 0)
- byte = 0x3;
- else if (offset == 2)
- byte = 0xc;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcidata = data;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
- (unsigned long) ioaddr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
- (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) | byte;
- while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
- /* clear by setting */
- tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-}
-
-unsigned long tx_ioinl(unsigned int *addr)
-{
- unsigned long val;
- __u32 ioaddr;
-
- ioaddr = (unsigned long) addr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
- (unsigned long) ioaddr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
- (PCI_IPCIBE_ICMD_IOREAD << PCI_IPCIBE_ICMD_SHIFT) |
- PCI_IPCIBE_IBE_LONG;
- while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
- val =
- le32_to_cpu(*(volatile u32 *) (ulong) & tx3927_pcicptr->
- ipcidata);
- /* clear by setting */
- tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
- return val;
-}
-
-void tx_iooutl(unsigned long data, unsigned int *addr)
-{
- __u32 ioaddr;
-
- ioaddr = (unsigned long) addr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcidata =
- cpu_to_le32(data);
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipciaddr =
- (unsigned long) ioaddr;
- *(volatile u32 *) (ulong) & tx3927_pcicptr->ipcibe =
- (PCI_IPCIBE_ICMD_IOWRITE << PCI_IPCIBE_ICMD_SHIFT) |
- PCI_IPCIBE_IBE_LONG;
- while (!(tx3927_pcicptr->istat & PCI_ISTAT_IDICC));
- /* clear by setting */
- tx3927_pcicptr->istat |= PCI_ISTAT_IDICC;
-}
-
-void tx_insbyte(unsigned char *addr, void *buffer, unsigned int count)
-{
- unsigned char *ptr = (unsigned char *) buffer;
-
- while (count--) {
- *ptr++ = tx_ioinb(addr);
- }
-}
-
-void tx_insword(unsigned short *addr, void *buffer, unsigned int count)
-{
- unsigned short *ptr = (unsigned short *) buffer;
-
- while (count--) {
- *ptr++ = tx_ioinw(addr);
- }
-}
-
-void tx_inslong(unsigned int *addr, void *buffer, unsigned int count)
-{
- unsigned long *ptr = (unsigned long *) buffer;
-
- while (count--) {
- *ptr++ = tx_ioinl(addr);
- }
-}
-
-void tx_outsbyte(unsigned char *addr, void *buffer, unsigned int count)
-{
- unsigned char *ptr = (unsigned char *) buffer;
-
- while (count--) {
- tx_iooutb(*ptr++, addr);
+void __init tx3927_pcic_setup(struct pci_controller *channel,
+ unsigned long sdram_size, int extarb)
+{
+ unsigned long flags;
+ unsigned long io_base =
+ channel->io_resource->start + mips_io_port_base - IO_BASE;
+ unsigned long io_size =
+ channel->io_resource->end - channel->io_resource->start;
+ unsigned long io_pciaddr =
+ channel->io_resource->start - channel->io_offset;
+ unsigned long mem_base =
+ channel->mem_resource->start;
+ unsigned long mem_size =
+ channel->mem_resource->end - channel->mem_resource->start;
+ unsigned long mem_pciaddr =
+ channel->mem_resource->start - channel->mem_offset;
+
+ printk(KERN_INFO "TX3927 PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:%s",
+ tx3927_pcicptr->did, tx3927_pcicptr->vid,
+ tx3927_pcicptr->rid,
+ extarb ? "External" : "Internal");
+ channel->pci_ops = &tx3927_pci_ops;
+
+ local_irq_save(flags);
+ /* Disable External PCI Config. Access */
+ tx3927_pcicptr->lbc = TX3927_PCIC_LBC_EPCAD;
+#ifdef __BIG_ENDIAN
+ tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_IBSE |
+ TX3927_PCIC_LBC_TIBSE |
+ TX3927_PCIC_LBC_TMFBSE | TX3927_PCIC_LBC_MSDSE;
+#endif
+ /* LB->PCI mappings */
+ tx3927_pcicptr->iomas = ~(io_size - 1);
+ tx3927_pcicptr->ilbioma = io_base;
+ tx3927_pcicptr->ipbioma = io_pciaddr;
+ tx3927_pcicptr->mmas = ~(mem_size - 1);
+ tx3927_pcicptr->ilbmma = mem_base;
+ tx3927_pcicptr->ipbmma = mem_pciaddr;
+ /* PCI->LB mappings */
+ tx3927_pcicptr->iobas = 0xffffffff;
+ tx3927_pcicptr->ioba = 0;
+ tx3927_pcicptr->tlbioma = 0;
+ tx3927_pcicptr->mbas = ~(sdram_size - 1);
+ tx3927_pcicptr->mba = 0;
+ tx3927_pcicptr->tlbmma = 0;
+ /* Enable Direct mapping Address Space Decoder */
+ tx3927_pcicptr->lbc |= TX3927_PCIC_LBC_ILMDE | TX3927_PCIC_LBC_ILIDE;
+
+ /* Clear All Local Bus Status */
+ tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL;
+ /* Enable All Local Bus Interrupts */
+ tx3927_pcicptr->lbim = TX3927_PCIC_LBIM_ALL;
+ /* Clear All PCI Status Error */
+ tx3927_pcicptr->pcistat = TX3927_PCIC_PCISTATIM_ALL;
+ /* Enable All PCI Status Error Interrupts */
+ tx3927_pcicptr->pcistatim = TX3927_PCIC_PCISTATIM_ALL;
+
+ /* PCIC Int => IRC IRQ10 */
+ tx3927_pcicptr->il = TX3927_IR_PCI;
+ /* Target Control (per errata) */
+ tx3927_pcicptr->tc = TX3927_PCIC_TC_OF8E | TX3927_PCIC_TC_IF8E;
+
+ /* Enable Bus Arbiter */
+ if (!extarb)
+ tx3927_pcicptr->pbapmc = TX3927_PCIC_PBAPMC_PBAEN;
+
+ tx3927_pcicptr->pcicmd = PCI_COMMAND_MASTER |
+ PCI_COMMAND_MEMORY |
+ PCI_COMMAND_IO |
+ PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+ local_irq_restore(flags);
+}
+
+static irqreturn_t tx3927_pcierr_interrupt(int irq, void *dev_id)
+{
+ struct pt_regs *regs = get_irq_regs();
+
+ if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) {
+ printk(KERN_WARNING "PCI error interrupt at 0x%08lx.\n",
+ regs->cp0_epc);
+ printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n",
+ tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat);
}
-}
-
-void tx_outsword(unsigned short *addr, void *buffer, unsigned int count)
-{
- unsigned short *ptr = (unsigned short *) buffer;
-
- while (count--) {
- tx_iooutw(*ptr++, addr);
+ if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) {
+ /* clear all pci errors */
+ tx3927_pcicptr->pcistat |= TX3927_PCIC_PCISTATIM_ALL;
+ tx3927_pcicptr->istat = TX3927_PCIC_IIM_ALL;
+ tx3927_pcicptr->tstat = TX3927_PCIC_TIM_ALL;
+ tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL;
+ return IRQ_HANDLED;
}
+ console_verbose();
+ panic("PCI error.");
}
-void tx_outslong(unsigned int *addr, void *buffer, unsigned int count)
+void __init tx3927_setup_pcierr_irq(void)
{
- unsigned long *ptr = (unsigned long *) buffer;
-
- while (count--) {
- tx_iooutl(*ptr++, addr);
- }
+ if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI,
+ tx3927_pcierr_interrupt,
+ 0, "PCI error",
+ (void *)TX3927_PCIC_REG))
+ printk(KERN_WARNING "Failed to request irq for PCIERR\n");
}
-#endif