diff options
Diffstat (limited to 'arch/mips/pci/ops-tx4927.c')
-rw-r--r-- | arch/mips/pci/ops-tx4927.c | 517 |
1 files changed, 358 insertions, 159 deletions
diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c index 150419c8b414..c6b49bccd274 100644 --- a/arch/mips/pci/ops-tx4927.c +++ b/arch/mips/pci/ops-tx4927.c @@ -1,209 +1,408 @@ /* - * Copyright 2001 MontaVista Software Inc. - * Author: MontaVista Software, Inc. - * ahennessy@mvista.com + * Define the pci_ops for the PCIC on Toshiba TX4927, TX4938, etc. * - * Copyright (C) 2000-2001 Toshiba Corporation - * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) - * - * Based on arch/mips/ddb5xxx/ddb5477/pci_ops.c - * - * Define the pci_ops for the Toshiba rbtx4927 - * - * Much of the code is derived from the original DDB5074 port by - * Geert Uytterhoeven <geert@sonycom.com> - * - * Copyright 2004 MontaVista Software Inc. - * Author: Manish Lachwani (mlachwani@mvista.com) - * - * 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. + * Based on linux/arch/mips/pci/ops-tx4938.c, + * linux/arch/mips/pci/fixup-rbtx4938.c, + * linux/arch/mips/txx9/rbtx4938/setup.c, + * and RBTX49xx patch from CELF patch archive. * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * 2003-2005 (c) MontaVista Software, Inc. + * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org) + * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007 * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. + * 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/types.h> -#include <linux/pci.h> #include <linux/kernel.h> -#include <linux/init.h> - -#include <asm/addrspace.h> -#include <asm/byteorder.h> -#include <asm/tx4927/tx4927_pci.h> - -/* initialize in setup */ -struct resource pci_io_resource = { - .name = "TX4927 PCI IO SPACE", - .start = 0x1000, - .end = (0x1000 + (TX4927_PCIIO_SIZE)) - 1, - .flags = IORESOURCE_IO -}; +#include <asm/txx9/tx4927pcic.h> -/* initialize in setup */ -struct resource pci_mem_resource = { - .name = "TX4927 PCI MEM SPACE", - .start = TX4927_PCIMEM, - .end = TX4927_PCIMEM + TX4927_PCIMEM_SIZE - 1, - .flags = IORESOURCE_MEM -}; +static struct { + struct pci_controller *channel; + struct tx4927_pcic_reg __iomem *pcicptr; +} pcicptrs[2]; /* TX4938 has 2 pcic */ + +static void __init set_tx4927_pcicptr(struct pci_controller *channel, + struct tx4927_pcic_reg __iomem *pcicptr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) { + if (pcicptrs[i].channel == channel) { + pcicptrs[i].pcicptr = pcicptr; + return; + } + } + for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) { + if (!pcicptrs[i].channel) { + pcicptrs[i].channel = channel; + pcicptrs[i].pcicptr = pcicptr; + return; + } + } + BUG(); +} -static int mkaddr(int bus, int dev_fn, int where, int *flagsp) +struct tx4927_pcic_reg __iomem *get_tx4927_pcicptr( + struct pci_controller *channel) { - if (bus > 0) { - /* Type 1 configuration */ - tx4927_pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) | - ((dev_fn & 0xff) << 0x08) | (where & 0xfc) | 1; - } else { - if (dev_fn >= PCI_DEVFN(TX4927_PCIC_MAX_DEVNU, 0)) - return -1; + int i; - /* Type 0 configuration */ - tx4927_pcicptr->g2pcfgadrs = ((bus & 0xff) << 0x10) | - ((dev_fn & 0xff) << 0x08) | (where & 0xfc); + for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) { + if (pcicptrs[i].channel == channel) + return pcicptrs[i].pcicptr; } + return NULL; +} + +static int mkaddr(struct pci_bus *bus, unsigned int devfn, int where, + struct tx4927_pcic_reg __iomem *pcicptr) +{ + if (bus->parent == NULL && + devfn >= PCI_DEVFN(TX4927_PCIC_MAX_DEVNU, 0)) + return -1; + __raw_writel(((bus->number & 0xff) << 0x10) + | ((devfn & 0xff) << 0x08) | (where & 0xfc) + | (bus->parent ? 1 : 0), + &pcicptr->g2pcfgadrs); /* clear M_ABORT and Disable M_ABORT Int. */ - tx4927_pcicptr->pcistatus = - (tx4927_pcicptr->pcistatus & 0x0000ffff) | - (PCI_STATUS_REC_MASTER_ABORT << 16); - tx4927_pcicptr->pcimask &= ~PCI_STATUS_REC_MASTER_ABORT; + __raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff) + | (PCI_STATUS_REC_MASTER_ABORT << 16), + &pcicptr->pcistatus); return 0; } -static int check_abort(int flags) +static int check_abort(struct tx4927_pcic_reg __iomem *pcicptr) { int code = PCIBIOS_SUCCESSFUL; - if (tx4927_pcicptr-> - pcistatus & (PCI_STATUS_REC_MASTER_ABORT << 16)) { - tx4927_pcicptr->pcistatus = - (tx4927_pcicptr-> - pcistatus & 0x0000ffff) | (PCI_STATUS_REC_MASTER_ABORT - << 16); - tx4927_pcicptr->pcimask |= PCI_STATUS_REC_MASTER_ABORT; + + /* wait write cycle completion before checking error status */ + while (__raw_readl(&pcicptr->pcicstatus) & TX4927_PCIC_PCICSTATUS_IWB) + ; + if (__raw_readl(&pcicptr->pcistatus) + & (PCI_STATUS_REC_MASTER_ABORT << 16)) { + __raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff) + | (PCI_STATUS_REC_MASTER_ABORT << 16), + &pcicptr->pcistatus); code = PCIBIOS_DEVICE_NOT_FOUND; } return code; } -static int tx4927_pcibios_read_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 * val) +static u8 icd_readb(int offset, struct tx4927_pcic_reg __iomem *pcicptr) +{ +#ifdef __BIG_ENDIAN + offset ^= 3; +#endif + return __raw_readb((void __iomem *)&pcicptr->g2pcfgdata + offset); +} +static u16 icd_readw(int offset, struct tx4927_pcic_reg __iomem *pcicptr) +{ +#ifdef __BIG_ENDIAN + offset ^= 2; +#endif + return __raw_readw((void __iomem *)&pcicptr->g2pcfgdata + offset); +} +static u32 icd_readl(struct tx4927_pcic_reg __iomem *pcicptr) +{ + return __raw_readl(&pcicptr->g2pcfgdata); +} +static void icd_writeb(u8 val, int offset, + struct tx4927_pcic_reg __iomem *pcicptr) +{ +#ifdef __BIG_ENDIAN + offset ^= 3; +#endif + __raw_writeb(val, (void __iomem *)&pcicptr->g2pcfgdata + offset); +} +static void icd_writew(u16 val, int offset, + struct tx4927_pcic_reg __iomem *pcicptr) +{ +#ifdef __BIG_ENDIAN + offset ^= 2; +#endif + __raw_writew(val, (void __iomem *)&pcicptr->g2pcfgdata + offset); +} +static void icd_writel(u32 val, struct tx4927_pcic_reg __iomem *pcicptr) { - int flags, retval, dev, busno, func; + __raw_writel(val, &pcicptr->g2pcfgdata); +} - busno = bus->number; - dev = PCI_SLOT(devfn); - func = PCI_FUNC(devfn); +static struct tx4927_pcic_reg __iomem *pci_bus_to_pcicptr(struct pci_bus *bus) +{ + struct pci_controller *channel = bus->sysdata; + return get_tx4927_pcicptr(channel); +} - /* check if the bus is top-level */ - if (bus->parent != NULL) { - busno = bus->number; - } else { - busno = 0; - } +static int tx4927_pci_config_read(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(bus); - if (mkaddr(busno, devfn, where, &flags)) + if (mkaddr(bus, devfn, where, pcicptr)) { + *val = 0xffffffff; return -1; - + } switch (size) { case 1: - *val = *(volatile u8 *) ((unsigned long) & tx4927_pcicptr-> - g2pcfgdata | -#ifdef __LITTLE_ENDIAN - (where & 3)); -#else - ((where & 0x3) ^ 0x3)); -#endif + *val = icd_readb(where & 3, pcicptr); break; case 2: - *val = *(volatile u16 *) ((unsigned long) & tx4927_pcicptr-> - g2pcfgdata | -#ifdef __LITTLE_ENDIAN - (where & 3)); -#else - ((where & 0x3) ^ 0x2)); -#endif - break; - case 4: - *val = tx4927_pcicptr->g2pcfgdata; + *val = icd_readw(where & 3, pcicptr); break; + default: + *val = icd_readl(pcicptr); } + return check_abort(pcicptr); +} - retval = check_abort(flags); - if (retval == PCIBIOS_DEVICE_NOT_FOUND) - *val = 0xffffffff; +static int tx4927_pci_config_write(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + struct tx4927_pcic_reg __iomem *pcicptr = pci_bus_to_pcicptr(bus); - return retval; + if (mkaddr(bus, devfn, where, pcicptr)) + return -1; + switch (size) { + case 1: + icd_writeb(val, where & 3, pcicptr); + break; + case 2: + icd_writew(val, where & 3, pcicptr); + break; + default: + icd_writel(val, pcicptr); + } + return check_abort(pcicptr); } -static int tx4927_pcibios_write_config(struct pci_bus *bus, unsigned int devfn, int where, - int size, u32 val) +static struct pci_ops tx4927_pci_ops = { + .read = tx4927_pci_config_read, + .write = tx4927_pci_config_write, +}; + +static struct { + u8 trdyto; + u8 retryto; + u16 gbwc; +} tx4927_pci_opts __devinitdata = { + .trdyto = 0, + .retryto = 0, + .gbwc = 0xfe0, /* 4064 GBUSCLK for CCFG.GTOT=0b11 */ +}; + +void __init tx4927_pcic_setup(struct tx4927_pcic_reg __iomem *pcicptr, + struct pci_controller *channel, int extarb) { - int flags, dev, busno, func; - busno = bus->number; - dev = PCI_SLOT(devfn); - func = PCI_FUNC(devfn); + int i; + unsigned long flags; - /* check if the bus is top-level */ - if (bus->parent != NULL) { - busno = bus->number; - } else { - busno = 0; - } + set_tx4927_pcicptr(channel, pcicptr); - if (mkaddr(busno, devfn, where, &flags)) - return -1; + if (!channel->pci_ops) + printk(KERN_INFO + "PCIC -- DID:%04x VID:%04x RID:%02x Arbiter:%s\n", + __raw_readl(&pcicptr->pciid) >> 16, + __raw_readl(&pcicptr->pciid) & 0xffff, + __raw_readl(&pcicptr->pciccrev) & 0xff, + extarb ? "External" : "Internal"); + channel->pci_ops = &tx4927_pci_ops; - switch (size) { - case 1: - *(volatile u8 *) ((unsigned long) & tx4927_pcicptr-> - g2pcfgdata | -#ifdef __LITTLE_ENDIAN - (where & 3)) = val; + local_irq_save(flags); + + /* Disable All Initiator Space */ + __raw_writel(__raw_readl(&pcicptr->pciccfg) + & ~(TX4927_PCIC_PCICCFG_G2PMEN(0) + | TX4927_PCIC_PCICCFG_G2PMEN(1) + | TX4927_PCIC_PCICCFG_G2PMEN(2) + | TX4927_PCIC_PCICCFG_G2PIOEN), + &pcicptr->pciccfg); + + /* GB->PCI mappings */ + __raw_writel((channel->io_resource->end - channel->io_resource->start) + >> 4, + &pcicptr->g2piomask); + ____raw_writeq((channel->io_resource->start + + channel->io_map_base - IO_BASE) | +#ifdef __BIG_ENDIAN + TX4927_PCIC_G2PIOGBASE_ECHG #else - ((where & 0x3) ^ 0x3)) = val; + TX4927_PCIC_G2PIOGBASE_BSDIS #endif - break; - - case 2: - *(volatile u16 *) ((unsigned long) & tx4927_pcicptr-> - g2pcfgdata | -#ifdef __LITTLE_ENDIAN - (where & 3)) = val; + , &pcicptr->g2piogbase); + ____raw_writeq(channel->io_resource->start - channel->io_offset, + &pcicptr->g2piopbase); + for (i = 0; i < 3; i++) { + __raw_writel(0, &pcicptr->g2pmmask[i]); + ____raw_writeq(0, &pcicptr->g2pmgbase[i]); + ____raw_writeq(0, &pcicptr->g2pmpbase[i]); + } + if (channel->mem_resource->end) { + __raw_writel((channel->mem_resource->end + - channel->mem_resource->start) >> 4, + &pcicptr->g2pmmask[0]); + ____raw_writeq(channel->mem_resource->start | +#ifdef __BIG_ENDIAN + TX4927_PCIC_G2PMnGBASE_ECHG #else - ((where & 0x3) ^ 0x2)) = val; + TX4927_PCIC_G2PMnGBASE_BSDIS #endif - break; - case 4: - tx4927_pcicptr->g2pcfgdata = val; - break; + , &pcicptr->g2pmgbase[0]); + ____raw_writeq(channel->mem_resource->start - + channel->mem_offset, + &pcicptr->g2pmpbase[0]); + } + /* PCI->GB mappings (I/O 256B) */ + __raw_writel(0, &pcicptr->p2giopbase); /* 256B */ + ____raw_writeq(0, &pcicptr->p2giogbase); + /* PCI->GB mappings (MEM 512MB (64MB on R1.x)) */ + __raw_writel(0, &pcicptr->p2gm0plbase); + __raw_writel(0, &pcicptr->p2gm0pubase); + ____raw_writeq(TX4927_PCIC_P2GMnGBASE_TMEMEN | +#ifdef __BIG_ENDIAN + TX4927_PCIC_P2GMnGBASE_TECHG +#else + TX4927_PCIC_P2GMnGBASE_TBSDIS +#endif + , &pcicptr->p2gmgbase[0]); + /* PCI->GB mappings (MEM 16MB) */ + __raw_writel(0xffffffff, &pcicptr->p2gm1plbase); + __raw_writel(0xffffffff, &pcicptr->p2gm1pubase); + ____raw_writeq(0, &pcicptr->p2gmgbase[1]); + /* PCI->GB mappings (MEM 1MB) */ + __raw_writel(0xffffffff, &pcicptr->p2gm2pbase); /* 1MB */ + ____raw_writeq(0, &pcicptr->p2gmgbase[2]); + + /* Clear all (including IRBER) except for GBWC */ + __raw_writel((tx4927_pci_opts.gbwc << 16) + & TX4927_PCIC_PCICCFG_GBWC_MASK, + &pcicptr->pciccfg); + /* Enable Initiator Memory Space */ + if (channel->mem_resource->end) + __raw_writel(__raw_readl(&pcicptr->pciccfg) + | TX4927_PCIC_PCICCFG_G2PMEN(0), + &pcicptr->pciccfg); + /* Enable Initiator I/O Space */ + if (channel->io_resource->end) + __raw_writel(__raw_readl(&pcicptr->pciccfg) + | TX4927_PCIC_PCICCFG_G2PIOEN, + &pcicptr->pciccfg); + /* Enable Initiator Config */ + __raw_writel(__raw_readl(&pcicptr->pciccfg) + | TX4927_PCIC_PCICCFG_ICAEN | TX4927_PCIC_PCICCFG_TCAR, + &pcicptr->pciccfg); + + /* Do not use MEMMUL, MEMINF: YMFPCI card causes M_ABORT. */ + __raw_writel(0, &pcicptr->pcicfg1); + + __raw_writel((__raw_readl(&pcicptr->g2ptocnt) & ~0xffff) + | (tx4927_pci_opts.trdyto & 0xff) + | ((tx4927_pci_opts.retryto & 0xff) << 8), + &pcicptr->g2ptocnt); + + /* Clear All Local Bus Status */ + __raw_writel(TX4927_PCIC_PCICSTATUS_ALL, &pcicptr->pcicstatus); + /* Enable All Local Bus Interrupts */ + __raw_writel(TX4927_PCIC_PCICSTATUS_ALL, &pcicptr->pcicmask); + /* Clear All Initiator Status */ + __raw_writel(TX4927_PCIC_G2PSTATUS_ALL, &pcicptr->g2pstatus); + /* Enable All Initiator Interrupts */ + __raw_writel(TX4927_PCIC_G2PSTATUS_ALL, &pcicptr->g2pmask); + /* Clear All PCI Status Error */ + __raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff) + | (TX4927_PCIC_PCISTATUS_ALL << 16), + &pcicptr->pcistatus); + /* Enable All PCI Status Error Interrupts */ + __raw_writel(TX4927_PCIC_PCISTATUS_ALL, &pcicptr->pcimask); + + if (!extarb) { + /* Reset Bus Arbiter */ + __raw_writel(TX4927_PCIC_PBACFG_RPBA, &pcicptr->pbacfg); + __raw_writel(0, &pcicptr->pbabm); + /* Enable Bus Arbiter */ + __raw_writel(TX4927_PCIC_PBACFG_PBAEN, &pcicptr->pbacfg); } - return check_abort(flags); + __raw_writel(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY + | PCI_COMMAND_PARITY | PCI_COMMAND_SERR, + &pcicptr->pcistatus); + local_irq_restore(flags); + + printk(KERN_DEBUG + "PCI: COMMAND=%04x,PCIMASK=%04x," + "TRDYTO=%02x,RETRYTO=%02x,GBWC=%03x\n", + __raw_readl(&pcicptr->pcistatus) & 0xffff, + __raw_readl(&pcicptr->pcimask) & 0xffff, + __raw_readl(&pcicptr->g2ptocnt) & 0xff, + (__raw_readl(&pcicptr->g2ptocnt) & 0xff00) >> 8, + (__raw_readl(&pcicptr->pciccfg) >> 16) & 0xfff); } -struct pci_ops tx4927_pci_ops = { - tx4927_pcibios_read_config, - tx4927_pcibios_write_config -}; +static void tx4927_report_pcic_status1(struct tx4927_pcic_reg __iomem *pcicptr) +{ + __u16 pcistatus = (__u16)(__raw_readl(&pcicptr->pcistatus) >> 16); + __u32 g2pstatus = __raw_readl(&pcicptr->g2pstatus); + __u32 pcicstatus = __raw_readl(&pcicptr->pcicstatus); + static struct { + __u32 flag; + const char *str; + } pcistat_tbl[] = { + { PCI_STATUS_DETECTED_PARITY, "DetectedParityError" }, + { PCI_STATUS_SIG_SYSTEM_ERROR, "SignaledSystemError" }, + { PCI_STATUS_REC_MASTER_ABORT, "ReceivedMasterAbort" }, + { PCI_STATUS_REC_TARGET_ABORT, "ReceivedTargetAbort" }, + { PCI_STATUS_SIG_TARGET_ABORT, "SignaledTargetAbort" }, + { PCI_STATUS_PARITY, "MasterParityError" }, + }, g2pstat_tbl[] = { + { TX4927_PCIC_G2PSTATUS_TTOE, "TIOE" }, + { TX4927_PCIC_G2PSTATUS_RTOE, "RTOE" }, + }, pcicstat_tbl[] = { + { TX4927_PCIC_PCICSTATUS_PME, "PME" }, + { TX4927_PCIC_PCICSTATUS_TLB, "TLB" }, + { TX4927_PCIC_PCICSTATUS_NIB, "NIB" }, + { TX4927_PCIC_PCICSTATUS_ZIB, "ZIB" }, + { TX4927_PCIC_PCICSTATUS_PERR, "PERR" }, + { TX4927_PCIC_PCICSTATUS_SERR, "SERR" }, + { TX4927_PCIC_PCICSTATUS_GBE, "GBE" }, + { TX4927_PCIC_PCICSTATUS_IWB, "IWB" }, + }; + int i, cont; -/* - * h/w only supports devices 0x00 to 0x14 - */ -struct pci_controller tx4927_controller = { - .pci_ops = &tx4927_pci_ops, - .io_resource = &pci_io_resource, - .mem_resource = &pci_mem_resource, -}; + printk(KERN_ERR ""); + if (pcistatus & TX4927_PCIC_PCISTATUS_ALL) { + printk(KERN_CONT "pcistat:%04x(", pcistatus); + for (i = 0, cont = 0; i < ARRAY_SIZE(pcistat_tbl); i++) + if (pcistatus & pcistat_tbl[i].flag) + printk(KERN_CONT "%s%s", + cont++ ? " " : "", pcistat_tbl[i].str); + printk(KERN_CONT ") "); + } + if (g2pstatus & TX4927_PCIC_G2PSTATUS_ALL) { + printk(KERN_CONT "g2pstatus:%08x(", g2pstatus); + for (i = 0, cont = 0; i < ARRAY_SIZE(g2pstat_tbl); i++) + if (g2pstatus & g2pstat_tbl[i].flag) + printk(KERN_CONT "%s%s", + cont++ ? " " : "", g2pstat_tbl[i].str); + printk(KERN_CONT ") "); + } + if (pcicstatus & TX4927_PCIC_PCICSTATUS_ALL) { + printk(KERN_CONT "pcicstatus:%08x(", pcicstatus); + for (i = 0, cont = 0; i < ARRAY_SIZE(pcicstat_tbl); i++) + if (pcicstatus & pcicstat_tbl[i].flag) + printk(KERN_CONT "%s%s", + cont++ ? " " : "", pcicstat_tbl[i].str); + printk(KERN_CONT ")"); + } + printk(KERN_CONT "\n"); +} + +void tx4927_report_pcic_status(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) { + if (pcicptrs[i].pcicptr) + tx4927_report_pcic_status1(pcicptrs[i].pcicptr); + } +} |