162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Low-Level PCI Support for the SH7780 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005 - 2010 Paul Mundt 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/timer.h> 1362306a36Sopenharmony_ci#include <linux/irq.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/log2.h> 1762306a36Sopenharmony_ci#include "pci-sh4.h" 1862306a36Sopenharmony_ci#include <asm/mmu.h> 1962306a36Sopenharmony_ci#include <linux/sizes.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#if defined(CONFIG_CPU_BIG_ENDIAN) 2262306a36Sopenharmony_ci# define PCICR_ENDIANNESS SH4_PCICR_BSWP 2362306a36Sopenharmony_ci#else 2462306a36Sopenharmony_ci# define PCICR_ENDIANNESS 0 2562306a36Sopenharmony_ci#endif 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic struct resource sh7785_pci_resources[] = { 2962306a36Sopenharmony_ci { 3062306a36Sopenharmony_ci .name = "PCI IO", 3162306a36Sopenharmony_ci .start = 0x1000, 3262306a36Sopenharmony_ci .end = SZ_4M - 1, 3362306a36Sopenharmony_ci .flags = IORESOURCE_IO, 3462306a36Sopenharmony_ci }, { 3562306a36Sopenharmony_ci .name = "PCI MEM 0", 3662306a36Sopenharmony_ci .start = 0xfd000000, 3762306a36Sopenharmony_ci .end = 0xfd000000 + SZ_16M - 1, 3862306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 3962306a36Sopenharmony_ci }, { 4062306a36Sopenharmony_ci .name = "PCI MEM 1", 4162306a36Sopenharmony_ci .start = 0x10000000, 4262306a36Sopenharmony_ci .end = 0x10000000 + SZ_64M - 1, 4362306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 4462306a36Sopenharmony_ci }, { 4562306a36Sopenharmony_ci /* 4662306a36Sopenharmony_ci * 32-bit only resources must be last. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci .name = "PCI MEM 2", 4962306a36Sopenharmony_ci .start = 0xc0000000, 5062306a36Sopenharmony_ci .end = 0xc0000000 + SZ_512M - 1, 5162306a36Sopenharmony_ci .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, 5262306a36Sopenharmony_ci }, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic struct pci_channel sh7780_pci_controller = { 5662306a36Sopenharmony_ci .pci_ops = &sh4_pci_ops, 5762306a36Sopenharmony_ci .resources = sh7785_pci_resources, 5862306a36Sopenharmony_ci .nr_resources = ARRAY_SIZE(sh7785_pci_resources), 5962306a36Sopenharmony_ci .io_offset = 0, 6062306a36Sopenharmony_ci .mem_offset = 0, 6162306a36Sopenharmony_ci .io_map_base = 0xfe200000, 6262306a36Sopenharmony_ci .serr_irq = evt2irq(0xa00), 6362306a36Sopenharmony_ci .err_irq = evt2irq(0xaa0), 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistruct pci_errors { 6762306a36Sopenharmony_ci unsigned int mask; 6862306a36Sopenharmony_ci const char *str; 6962306a36Sopenharmony_ci} pci_arbiter_errors[] = { 7062306a36Sopenharmony_ci { SH4_PCIAINT_MBKN, "master broken" }, 7162306a36Sopenharmony_ci { SH4_PCIAINT_TBTO, "target bus time out" }, 7262306a36Sopenharmony_ci { SH4_PCIAINT_MBTO, "master bus time out" }, 7362306a36Sopenharmony_ci { SH4_PCIAINT_TABT, "target abort" }, 7462306a36Sopenharmony_ci { SH4_PCIAINT_MABT, "master abort" }, 7562306a36Sopenharmony_ci { SH4_PCIAINT_RDPE, "read data parity error" }, 7662306a36Sopenharmony_ci { SH4_PCIAINT_WDPE, "write data parity error" }, 7762306a36Sopenharmony_ci}, pci_interrupt_errors[] = { 7862306a36Sopenharmony_ci { SH4_PCIINT_MLCK, "master lock error" }, 7962306a36Sopenharmony_ci { SH4_PCIINT_TABT, "target-target abort" }, 8062306a36Sopenharmony_ci { SH4_PCIINT_TRET, "target retry time out" }, 8162306a36Sopenharmony_ci { SH4_PCIINT_MFDE, "master function disable error" }, 8262306a36Sopenharmony_ci { SH4_PCIINT_PRTY, "address parity error" }, 8362306a36Sopenharmony_ci { SH4_PCIINT_SERR, "SERR" }, 8462306a36Sopenharmony_ci { SH4_PCIINT_TWDP, "data parity error for target write" }, 8562306a36Sopenharmony_ci { SH4_PCIINT_TRDP, "PERR detected for target read" }, 8662306a36Sopenharmony_ci { SH4_PCIINT_MTABT, "target abort for master" }, 8762306a36Sopenharmony_ci { SH4_PCIINT_MMABT, "master abort for master" }, 8862306a36Sopenharmony_ci { SH4_PCIINT_MWPD, "master write data parity error" }, 8962306a36Sopenharmony_ci { SH4_PCIINT_MRPD, "master read data parity error" }, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic irqreturn_t sh7780_pci_err_irq(int irq, void *dev_id) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct pci_channel *hose = dev_id; 9562306a36Sopenharmony_ci unsigned long addr; 9662306a36Sopenharmony_ci unsigned int status; 9762306a36Sopenharmony_ci unsigned int cmd; 9862306a36Sopenharmony_ci int i; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci addr = __raw_readl(hose->reg_base + SH4_PCIALR); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* 10362306a36Sopenharmony_ci * Handle status errors. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci status = __raw_readw(hose->reg_base + PCI_STATUS); 10662306a36Sopenharmony_ci if (status & (PCI_STATUS_PARITY | 10762306a36Sopenharmony_ci PCI_STATUS_DETECTED_PARITY | 10862306a36Sopenharmony_ci PCI_STATUS_SIG_TARGET_ABORT | 10962306a36Sopenharmony_ci PCI_STATUS_REC_TARGET_ABORT | 11062306a36Sopenharmony_ci PCI_STATUS_REC_MASTER_ABORT)) { 11162306a36Sopenharmony_ci cmd = pcibios_handle_status_errors(addr, status, hose); 11262306a36Sopenharmony_ci if (likely(cmd)) 11362306a36Sopenharmony_ci __raw_writew(cmd, hose->reg_base + PCI_STATUS); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* 11762306a36Sopenharmony_ci * Handle arbiter errors. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci status = __raw_readl(hose->reg_base + SH4_PCIAINT); 12062306a36Sopenharmony_ci for (i = cmd = 0; i < ARRAY_SIZE(pci_arbiter_errors); i++) { 12162306a36Sopenharmony_ci if (status & pci_arbiter_errors[i].mask) { 12262306a36Sopenharmony_ci printk(KERN_DEBUG "PCI: %s, addr=%08lx\n", 12362306a36Sopenharmony_ci pci_arbiter_errors[i].str, addr); 12462306a36Sopenharmony_ci cmd |= pci_arbiter_errors[i].mask; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci __raw_writel(cmd, hose->reg_base + SH4_PCIAINT); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* 13062306a36Sopenharmony_ci * Handle the remaining PCI errors. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci status = __raw_readl(hose->reg_base + SH4_PCIINT); 13362306a36Sopenharmony_ci for (i = cmd = 0; i < ARRAY_SIZE(pci_interrupt_errors); i++) { 13462306a36Sopenharmony_ci if (status & pci_interrupt_errors[i].mask) { 13562306a36Sopenharmony_ci printk(KERN_DEBUG "PCI: %s, addr=%08lx\n", 13662306a36Sopenharmony_ci pci_interrupt_errors[i].str, addr); 13762306a36Sopenharmony_ci cmd |= pci_interrupt_errors[i].mask; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci __raw_writel(cmd, hose->reg_base + SH4_PCIINT); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return IRQ_HANDLED; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic irqreturn_t sh7780_pci_serr_irq(int irq, void *dev_id) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct pci_channel *hose = dev_id; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci printk(KERN_DEBUG "PCI: system error received: "); 15062306a36Sopenharmony_ci pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); 15162306a36Sopenharmony_ci pr_cont("\n"); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Deassert SERR */ 15462306a36Sopenharmony_ci __raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Back off the IRQ for awhile */ 15762306a36Sopenharmony_ci disable_irq_nosync(irq); 15862306a36Sopenharmony_ci hose->serr_timer.expires = jiffies + HZ; 15962306a36Sopenharmony_ci add_timer(&hose->serr_timer); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return IRQ_HANDLED; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int __init sh7780_pci_setup_irqs(struct pci_channel *hose) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci int ret; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* Clear out PCI arbiter IRQs */ 16962306a36Sopenharmony_ci __raw_writel(0, hose->reg_base + SH4_PCIAINT); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Clear all error conditions */ 17262306a36Sopenharmony_ci __raw_writew(PCI_STATUS_DETECTED_PARITY | \ 17362306a36Sopenharmony_ci PCI_STATUS_SIG_SYSTEM_ERROR | \ 17462306a36Sopenharmony_ci PCI_STATUS_REC_MASTER_ABORT | \ 17562306a36Sopenharmony_ci PCI_STATUS_REC_TARGET_ABORT | \ 17662306a36Sopenharmony_ci PCI_STATUS_SIG_TARGET_ABORT | \ 17762306a36Sopenharmony_ci PCI_STATUS_PARITY, hose->reg_base + PCI_STATUS); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci ret = request_irq(hose->serr_irq, sh7780_pci_serr_irq, 0, 18062306a36Sopenharmony_ci "PCI SERR interrupt", hose); 18162306a36Sopenharmony_ci if (unlikely(ret)) { 18262306a36Sopenharmony_ci pr_err("PCI: Failed hooking SERR IRQ\n"); 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* 18762306a36Sopenharmony_ci * The PCI ERR IRQ needs to be IRQF_SHARED since all of the power 18862306a36Sopenharmony_ci * down IRQ vectors are routed through the ERR IRQ vector. We 18962306a36Sopenharmony_ci * only request_irq() once as there is only a single masking 19062306a36Sopenharmony_ci * source for multiple events. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci ret = request_irq(hose->err_irq, sh7780_pci_err_irq, IRQF_SHARED, 19362306a36Sopenharmony_ci "PCI ERR interrupt", hose); 19462306a36Sopenharmony_ci if (unlikely(ret)) { 19562306a36Sopenharmony_ci free_irq(hose->serr_irq, hose); 19662306a36Sopenharmony_ci return ret; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Unmask all of the arbiter IRQs. */ 20062306a36Sopenharmony_ci __raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \ 20162306a36Sopenharmony_ci SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \ 20262306a36Sopenharmony_ci SH4_PCIAINT_WDPE, hose->reg_base + SH4_PCIAINTM); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Unmask all of the PCI IRQs */ 20562306a36Sopenharmony_ci __raw_writel(SH4_PCIINTM_TTADIM | SH4_PCIINTM_TMTOIM | \ 20662306a36Sopenharmony_ci SH4_PCIINTM_MDEIM | SH4_PCIINTM_APEDIM | \ 20762306a36Sopenharmony_ci SH4_PCIINTM_SDIM | SH4_PCIINTM_DPEITWM | \ 20862306a36Sopenharmony_ci SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM | \ 20962306a36Sopenharmony_ci SH4_PCIINTM_MADIMM | SH4_PCIINTM_MWPDIM | \ 21062306a36Sopenharmony_ci SH4_PCIINTM_MRDPEIM, hose->reg_base + SH4_PCIINTM); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return ret; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic inline void __init sh7780_pci_teardown_irqs(struct pci_channel *hose) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci free_irq(hose->err_irq, hose); 21862306a36Sopenharmony_ci free_irq(hose->serr_irq, hose); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void __init sh7780_pci66_init(struct pci_channel *hose) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci unsigned int tmp; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (!pci_is_66mhz_capable(hose, 0, 0)) 22662306a36Sopenharmony_ci return; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* Enable register access */ 22962306a36Sopenharmony_ci tmp = __raw_readl(hose->reg_base + SH4_PCICR); 23062306a36Sopenharmony_ci tmp |= SH4_PCICR_PREFIX; 23162306a36Sopenharmony_ci __raw_writel(tmp, hose->reg_base + SH4_PCICR); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Enable 66MHz operation */ 23462306a36Sopenharmony_ci tmp = __raw_readw(hose->reg_base + PCI_STATUS); 23562306a36Sopenharmony_ci tmp |= PCI_STATUS_66MHZ; 23662306a36Sopenharmony_ci __raw_writew(tmp, hose->reg_base + PCI_STATUS); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Done */ 23962306a36Sopenharmony_ci tmp = __raw_readl(hose->reg_base + SH4_PCICR); 24062306a36Sopenharmony_ci tmp |= SH4_PCICR_PREFIX | SH4_PCICR_CFIN; 24162306a36Sopenharmony_ci __raw_writel(tmp, hose->reg_base + SH4_PCICR); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int __init sh7780_pci_init(void) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct pci_channel *chan = &sh7780_pci_controller; 24762306a36Sopenharmony_ci phys_addr_t memphys; 24862306a36Sopenharmony_ci size_t memsize; 24962306a36Sopenharmony_ci unsigned int id; 25062306a36Sopenharmony_ci const char *type; 25162306a36Sopenharmony_ci int ret, i; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci pr_notice("PCI: Starting initialization.\n"); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci chan->reg_base = 0xfe040000; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* Enable CPU access to the PCIC registers. */ 25862306a36Sopenharmony_ci __raw_writel(PCIECR_ENBL, PCIECR); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Reset */ 26162306a36Sopenharmony_ci __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST | PCICR_ENDIANNESS, 26262306a36Sopenharmony_ci chan->reg_base + SH4_PCICR); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* 26562306a36Sopenharmony_ci * Wait for it to come back up. The spec says to allow for up to 26662306a36Sopenharmony_ci * 1 second after toggling the reset pin, but in practice 100ms 26762306a36Sopenharmony_ci * is more than enough. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci mdelay(100); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci id = __raw_readw(chan->reg_base + PCI_VENDOR_ID); 27262306a36Sopenharmony_ci if (id != PCI_VENDOR_ID_RENESAS) { 27362306a36Sopenharmony_ci pr_err("PCI: Unknown vendor ID 0x%04x.\n", id); 27462306a36Sopenharmony_ci return -ENODEV; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci id = __raw_readw(chan->reg_base + PCI_DEVICE_ID); 27862306a36Sopenharmony_ci type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" : 27962306a36Sopenharmony_ci (id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" : 28062306a36Sopenharmony_ci (id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" : 28162306a36Sopenharmony_ci (id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" : 28262306a36Sopenharmony_ci NULL; 28362306a36Sopenharmony_ci if (unlikely(!type)) { 28462306a36Sopenharmony_ci pr_err("PCI: Found an unsupported Renesas host controller, device id 0x%04x.\n", 28562306a36Sopenharmony_ci id); 28662306a36Sopenharmony_ci return -EINVAL; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci pr_notice("PCI: Found a Renesas %s host controller, revision %d.\n", 29062306a36Sopenharmony_ci type, __raw_readb(chan->reg_base + PCI_REVISION_ID)); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * Now throw it in to register initialization mode and 29462306a36Sopenharmony_ci * start the real work. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ci __raw_writel(SH4_PCICR_PREFIX | PCICR_ENDIANNESS, 29762306a36Sopenharmony_ci chan->reg_base + SH4_PCICR); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci memphys = __pa(memory_start); 30062306a36Sopenharmony_ci memsize = roundup_pow_of_two(memory_end - memory_start); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* 30362306a36Sopenharmony_ci * If there's more than 512MB of memory, we need to roll over to 30462306a36Sopenharmony_ci * LAR1/LSR1. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci if (memsize > SZ_512M) { 30762306a36Sopenharmony_ci __raw_writel(memphys + SZ_512M, chan->reg_base + SH4_PCILAR1); 30862306a36Sopenharmony_ci __raw_writel((((memsize - SZ_512M) - SZ_1M) & 0x1ff00000) | 1, 30962306a36Sopenharmony_ci chan->reg_base + SH4_PCILSR1); 31062306a36Sopenharmony_ci memsize = SZ_512M; 31162306a36Sopenharmony_ci } else { 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * Otherwise just zero it out and disable it. 31462306a36Sopenharmony_ci */ 31562306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + SH4_PCILAR1); 31662306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + SH4_PCILSR1); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * LAR0/LSR0 covers up to the first 512MB, which is enough to 32162306a36Sopenharmony_ci * cover all of lowmem on most platforms. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci __raw_writel(memphys, chan->reg_base + SH4_PCILAR0); 32462306a36Sopenharmony_ci __raw_writel(((memsize - SZ_1M) & 0x1ff00000) | 1, 32562306a36Sopenharmony_ci chan->reg_base + SH4_PCILSR0); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* 32862306a36Sopenharmony_ci * Hook up the ERR and SERR IRQs. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_ci ret = sh7780_pci_setup_irqs(chan); 33162306a36Sopenharmony_ci if (unlikely(ret)) 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* 33562306a36Sopenharmony_ci * Disable the cache snoop controller for non-coherent DMA. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCICSCR0); 33862306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCICSAR0); 33962306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCICSCR1); 34062306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCICSAR1); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* 34362306a36Sopenharmony_ci * Setup the memory BARs 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci for (i = 1; i < chan->nr_resources; i++) { 34662306a36Sopenharmony_ci struct resource *res = chan->resources + i; 34762306a36Sopenharmony_ci resource_size_t size; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (unlikely(res->flags & IORESOURCE_IO)) 35062306a36Sopenharmony_ci continue; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* 35362306a36Sopenharmony_ci * Make sure we're in the right physical addressing mode 35462306a36Sopenharmony_ci * for dealing with the resource. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_ci if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode()) { 35762306a36Sopenharmony_ci chan->nr_resources--; 35862306a36Sopenharmony_ci continue; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci size = resource_size(res); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * The MBMR mask is calculated in units of 256kB, which 36562306a36Sopenharmony_ci * keeps things pretty simple. 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18, 36862306a36Sopenharmony_ci chan->reg_base + SH7780_PCIMBMR(i - 1)); 36962306a36Sopenharmony_ci __raw_writel(res->start, chan->reg_base + SH7780_PCIMBR(i - 1)); 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* 37362306a36Sopenharmony_ci * And I/O. 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0); 37662306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCIIOBR); 37762306a36Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci __raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \ 38062306a36Sopenharmony_ci PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \ 38162306a36Sopenharmony_ci PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* 38462306a36Sopenharmony_ci * Initialization mode complete, release the control register and 38562306a36Sopenharmony_ci * enable round robin mode to stop device overruns/starvation. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ci __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO | 38862306a36Sopenharmony_ci PCICR_ENDIANNESS, 38962306a36Sopenharmony_ci chan->reg_base + SH4_PCICR); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci ret = register_pci_controller(chan); 39262306a36Sopenharmony_ci if (unlikely(ret)) 39362306a36Sopenharmony_ci goto err; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci sh7780_pci66_init(chan); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci pr_notice("PCI: Running at %dMHz.\n", 39862306a36Sopenharmony_ci (__raw_readw(chan->reg_base + PCI_STATUS) & PCI_STATUS_66MHZ) 39962306a36Sopenharmony_ci ? 66 : 33); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cierr: 40462306a36Sopenharmony_ci sh7780_pci_teardown_irqs(chan); 40562306a36Sopenharmony_ci return ret; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ciarch_initcall(sh7780_pci_init); 408