Path: blob/master/arch/sh/drivers/pci/pci-sh7780.c
10819 views
/*1* Low-Level PCI Support for the SH77802*3* Copyright (C) 2005 - 2010 Paul Mundt4*5* This file is subject to the terms and conditions of the GNU General Public6* License. See the file "COPYING" in the main directory of this archive7* for more details.8*/9#include <linux/types.h>10#include <linux/kernel.h>11#include <linux/init.h>12#include <linux/pci.h>13#include <linux/interrupt.h>14#include <linux/timer.h>15#include <linux/irq.h>16#include <linux/errno.h>17#include <linux/delay.h>18#include <linux/log2.h>19#include "pci-sh4.h"20#include <asm/mmu.h>21#include <asm/sizes.h>2223static struct resource sh7785_pci_resources[] = {24{25.name = "PCI IO",26.start = 0x1000,27.end = SZ_4M - 1,28.flags = IORESOURCE_IO,29}, {30.name = "PCI MEM 0",31.start = 0xfd000000,32.end = 0xfd000000 + SZ_16M - 1,33.flags = IORESOURCE_MEM,34}, {35.name = "PCI MEM 1",36.start = 0x10000000,37.end = 0x10000000 + SZ_64M - 1,38.flags = IORESOURCE_MEM,39}, {40/*41* 32-bit only resources must be last.42*/43.name = "PCI MEM 2",44.start = 0xc0000000,45.end = 0xc0000000 + SZ_512M - 1,46.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,47},48};4950static struct pci_channel sh7780_pci_controller = {51.pci_ops = &sh4_pci_ops,52.resources = sh7785_pci_resources,53.nr_resources = ARRAY_SIZE(sh7785_pci_resources),54.io_offset = 0,55.mem_offset = 0,56.io_map_base = 0xfe200000,57.serr_irq = evt2irq(0xa00),58.err_irq = evt2irq(0xaa0),59};6061struct pci_errors {62unsigned int mask;63const char *str;64} pci_arbiter_errors[] = {65{ SH4_PCIAINT_MBKN, "master broken" },66{ SH4_PCIAINT_TBTO, "target bus time out" },67{ SH4_PCIAINT_MBTO, "master bus time out" },68{ SH4_PCIAINT_TABT, "target abort" },69{ SH4_PCIAINT_MABT, "master abort" },70{ SH4_PCIAINT_RDPE, "read data parity error" },71{ SH4_PCIAINT_WDPE, "write data parity error" },72}, pci_interrupt_errors[] = {73{ SH4_PCIINT_MLCK, "master lock error" },74{ SH4_PCIINT_TABT, "target-target abort" },75{ SH4_PCIINT_TRET, "target retry time out" },76{ SH4_PCIINT_MFDE, "master function disable erorr" },77{ SH4_PCIINT_PRTY, "address parity error" },78{ SH4_PCIINT_SERR, "SERR" },79{ SH4_PCIINT_TWDP, "data parity error for target write" },80{ SH4_PCIINT_TRDP, "PERR detected for target read" },81{ SH4_PCIINT_MTABT, "target abort for master" },82{ SH4_PCIINT_MMABT, "master abort for master" },83{ SH4_PCIINT_MWPD, "master write data parity error" },84{ SH4_PCIINT_MRPD, "master read data parity error" },85};8687static irqreturn_t sh7780_pci_err_irq(int irq, void *dev_id)88{89struct pci_channel *hose = dev_id;90unsigned long addr;91unsigned int status;92unsigned int cmd;93int i;9495addr = __raw_readl(hose->reg_base + SH4_PCIALR);9697/*98* Handle status errors.99*/100status = __raw_readw(hose->reg_base + PCI_STATUS);101if (status & (PCI_STATUS_PARITY |102PCI_STATUS_DETECTED_PARITY |103PCI_STATUS_SIG_TARGET_ABORT |104PCI_STATUS_REC_TARGET_ABORT |105PCI_STATUS_REC_MASTER_ABORT)) {106cmd = pcibios_handle_status_errors(addr, status, hose);107if (likely(cmd))108__raw_writew(cmd, hose->reg_base + PCI_STATUS);109}110111/*112* Handle arbiter errors.113*/114status = __raw_readl(hose->reg_base + SH4_PCIAINT);115for (i = cmd = 0; i < ARRAY_SIZE(pci_arbiter_errors); i++) {116if (status & pci_arbiter_errors[i].mask) {117printk(KERN_DEBUG "PCI: %s, addr=%08lx\n",118pci_arbiter_errors[i].str, addr);119cmd |= pci_arbiter_errors[i].mask;120}121}122__raw_writel(cmd, hose->reg_base + SH4_PCIAINT);123124/*125* Handle the remaining PCI errors.126*/127status = __raw_readl(hose->reg_base + SH4_PCIINT);128for (i = cmd = 0; i < ARRAY_SIZE(pci_interrupt_errors); i++) {129if (status & pci_interrupt_errors[i].mask) {130printk(KERN_DEBUG "PCI: %s, addr=%08lx\n",131pci_interrupt_errors[i].str, addr);132cmd |= pci_interrupt_errors[i].mask;133}134}135__raw_writel(cmd, hose->reg_base + SH4_PCIINT);136137return IRQ_HANDLED;138}139140static irqreturn_t sh7780_pci_serr_irq(int irq, void *dev_id)141{142struct pci_channel *hose = dev_id;143144printk(KERN_DEBUG "PCI: system error received: ");145pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1);146printk("\n");147148/* Deassert SERR */149__raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM);150151/* Back off the IRQ for awhile */152disable_irq_nosync(irq);153hose->serr_timer.expires = jiffies + HZ;154add_timer(&hose->serr_timer);155156return IRQ_HANDLED;157}158159static int __init sh7780_pci_setup_irqs(struct pci_channel *hose)160{161int ret;162163/* Clear out PCI arbiter IRQs */164__raw_writel(0, hose->reg_base + SH4_PCIAINT);165166/* Clear all error conditions */167__raw_writew(PCI_STATUS_DETECTED_PARITY | \168PCI_STATUS_SIG_SYSTEM_ERROR | \169PCI_STATUS_REC_MASTER_ABORT | \170PCI_STATUS_REC_TARGET_ABORT | \171PCI_STATUS_SIG_TARGET_ABORT | \172PCI_STATUS_PARITY, hose->reg_base + PCI_STATUS);173174ret = request_irq(hose->serr_irq, sh7780_pci_serr_irq, IRQF_DISABLED,175"PCI SERR interrupt", hose);176if (unlikely(ret)) {177printk(KERN_ERR "PCI: Failed hooking SERR IRQ\n");178return ret;179}180181/*182* The PCI ERR IRQ needs to be IRQF_SHARED since all of the power183* down IRQ vectors are routed through the ERR IRQ vector. We184* only request_irq() once as there is only a single masking185* source for multiple events.186*/187ret = request_irq(hose->err_irq, sh7780_pci_err_irq, IRQF_SHARED,188"PCI ERR interrupt", hose);189if (unlikely(ret)) {190free_irq(hose->serr_irq, hose);191return ret;192}193194/* Unmask all of the arbiter IRQs. */195__raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \196SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \197SH4_PCIAINT_WDPE, hose->reg_base + SH4_PCIAINTM);198199/* Unmask all of the PCI IRQs */200__raw_writel(SH4_PCIINTM_TTADIM | SH4_PCIINTM_TMTOIM | \201SH4_PCIINTM_MDEIM | SH4_PCIINTM_APEDIM | \202SH4_PCIINTM_SDIM | SH4_PCIINTM_DPEITWM | \203SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM | \204SH4_PCIINTM_MADIMM | SH4_PCIINTM_MWPDIM | \205SH4_PCIINTM_MRDPEIM, hose->reg_base + SH4_PCIINTM);206207return ret;208}209210static inline void __init sh7780_pci_teardown_irqs(struct pci_channel *hose)211{212free_irq(hose->err_irq, hose);213free_irq(hose->serr_irq, hose);214}215216static void __init sh7780_pci66_init(struct pci_channel *hose)217{218unsigned int tmp;219220if (!pci_is_66mhz_capable(hose, 0, 0))221return;222223/* Enable register access */224tmp = __raw_readl(hose->reg_base + SH4_PCICR);225tmp |= SH4_PCICR_PREFIX;226__raw_writel(tmp, hose->reg_base + SH4_PCICR);227228/* Enable 66MHz operation */229tmp = __raw_readw(hose->reg_base + PCI_STATUS);230tmp |= PCI_STATUS_66MHZ;231__raw_writew(tmp, hose->reg_base + PCI_STATUS);232233/* Done */234tmp = __raw_readl(hose->reg_base + SH4_PCICR);235tmp |= SH4_PCICR_PREFIX | SH4_PCICR_CFIN;236__raw_writel(tmp, hose->reg_base + SH4_PCICR);237}238239static int __init sh7780_pci_init(void)240{241struct pci_channel *chan = &sh7780_pci_controller;242phys_addr_t memphys;243size_t memsize;244unsigned int id;245const char *type;246int ret, i;247248printk(KERN_NOTICE "PCI: Starting initialization.\n");249250chan->reg_base = 0xfe040000;251252/* Enable CPU access to the PCIC registers. */253__raw_writel(PCIECR_ENBL, PCIECR);254255/* Reset */256__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST,257chan->reg_base + SH4_PCICR);258259/*260* Wait for it to come back up. The spec says to allow for up to261* 1 second after toggling the reset pin, but in practice 100ms262* is more than enough.263*/264mdelay(100);265266id = __raw_readw(chan->reg_base + PCI_VENDOR_ID);267if (id != PCI_VENDOR_ID_RENESAS) {268printk(KERN_ERR "PCI: Unknown vendor ID 0x%04x.\n", id);269return -ENODEV;270}271272id = __raw_readw(chan->reg_base + PCI_DEVICE_ID);273type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" :274(id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" :275(id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" :276(id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" :277NULL;278if (unlikely(!type)) {279printk(KERN_ERR "PCI: Found an unsupported Renesas host "280"controller, device id 0x%04x.\n", id);281return -EINVAL;282}283284printk(KERN_NOTICE "PCI: Found a Renesas %s host "285"controller, revision %d.\n", type,286__raw_readb(chan->reg_base + PCI_REVISION_ID));287288/*289* Now throw it in to register initialization mode and290* start the real work.291*/292__raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR);293294memphys = __pa(memory_start);295memsize = roundup_pow_of_two(memory_end - memory_start);296297/*298* If there's more than 512MB of memory, we need to roll over to299* LAR1/LSR1.300*/301if (memsize > SZ_512M) {302__raw_writel(memphys + SZ_512M, chan->reg_base + SH4_PCILAR1);303__raw_writel((((memsize - SZ_512M) - SZ_1M) & 0x1ff00000) | 1,304chan->reg_base + SH4_PCILSR1);305memsize = SZ_512M;306} else {307/*308* Otherwise just zero it out and disable it.309*/310__raw_writel(0, chan->reg_base + SH4_PCILAR1);311__raw_writel(0, chan->reg_base + SH4_PCILSR1);312}313314/*315* LAR0/LSR0 covers up to the first 512MB, which is enough to316* cover all of lowmem on most platforms.317*/318__raw_writel(memphys, chan->reg_base + SH4_PCILAR0);319__raw_writel(((memsize - SZ_1M) & 0x1ff00000) | 1,320chan->reg_base + SH4_PCILSR0);321322/*323* Hook up the ERR and SERR IRQs.324*/325ret = sh7780_pci_setup_irqs(chan);326if (unlikely(ret))327return ret;328329/*330* Disable the cache snoop controller for non-coherent DMA.331*/332__raw_writel(0, chan->reg_base + SH7780_PCICSCR0);333__raw_writel(0, chan->reg_base + SH7780_PCICSAR0);334__raw_writel(0, chan->reg_base + SH7780_PCICSCR1);335__raw_writel(0, chan->reg_base + SH7780_PCICSAR1);336337/*338* Setup the memory BARs339*/340for (i = 1; i < chan->nr_resources; i++) {341struct resource *res = chan->resources + i;342resource_size_t size;343344if (unlikely(res->flags & IORESOURCE_IO))345continue;346347/*348* Make sure we're in the right physical addressing mode349* for dealing with the resource.350*/351if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode()) {352chan->nr_resources--;353continue;354}355356size = resource_size(res);357358/*359* The MBMR mask is calculated in units of 256kB, which360* keeps things pretty simple.361*/362__raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18,363chan->reg_base + SH7780_PCIMBMR(i - 1));364__raw_writel(res->start, chan->reg_base + SH7780_PCIMBR(i - 1));365}366367/*368* And I/O.369*/370__raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0);371__raw_writel(0, chan->reg_base + SH7780_PCIIOBR);372__raw_writel(0, chan->reg_base + SH7780_PCIIOBMR);373374__raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \375PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \376PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND);377378/*379* Initialization mode complete, release the control register and380* enable round robin mode to stop device overruns/starvation.381*/382__raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO,383chan->reg_base + SH4_PCICR);384385ret = register_pci_controller(chan);386if (unlikely(ret))387goto err;388389sh7780_pci66_init(chan);390391printk(KERN_NOTICE "PCI: Running at %dMHz.\n",392(__raw_readw(chan->reg_base + PCI_STATUS) & PCI_STATUS_66MHZ) ?39366 : 33);394395return 0;396397err:398sh7780_pci_teardown_irqs(chan);399return ret;400}401arch_initcall(sh7780_pci_init);402403404