18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Low-Level PCI Support for the SH7780 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005 - 2010 Paul Mundt 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/pci.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/timer.h> 138c2ecf20Sopenharmony_ci#include <linux/irq.h> 148c2ecf20Sopenharmony_ci#include <linux/errno.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/log2.h> 178c2ecf20Sopenharmony_ci#include "pci-sh4.h" 188c2ecf20Sopenharmony_ci#include <asm/mmu.h> 198c2ecf20Sopenharmony_ci#include <linux/sizes.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#if defined(CONFIG_CPU_BIG_ENDIAN) 228c2ecf20Sopenharmony_ci# define PCICR_ENDIANNESS SH4_PCICR_BSWP 238c2ecf20Sopenharmony_ci#else 248c2ecf20Sopenharmony_ci# define PCICR_ENDIANNESS 0 258c2ecf20Sopenharmony_ci#endif 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic struct resource sh7785_pci_resources[] = { 298c2ecf20Sopenharmony_ci { 308c2ecf20Sopenharmony_ci .name = "PCI IO", 318c2ecf20Sopenharmony_ci .start = 0x1000, 328c2ecf20Sopenharmony_ci .end = SZ_4M - 1, 338c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 348c2ecf20Sopenharmony_ci }, { 358c2ecf20Sopenharmony_ci .name = "PCI MEM 0", 368c2ecf20Sopenharmony_ci .start = 0xfd000000, 378c2ecf20Sopenharmony_ci .end = 0xfd000000 + SZ_16M - 1, 388c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 398c2ecf20Sopenharmony_ci }, { 408c2ecf20Sopenharmony_ci .name = "PCI MEM 1", 418c2ecf20Sopenharmony_ci .start = 0x10000000, 428c2ecf20Sopenharmony_ci .end = 0x10000000 + SZ_64M - 1, 438c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 448c2ecf20Sopenharmony_ci }, { 458c2ecf20Sopenharmony_ci /* 468c2ecf20Sopenharmony_ci * 32-bit only resources must be last. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci .name = "PCI MEM 2", 498c2ecf20Sopenharmony_ci .start = 0xc0000000, 508c2ecf20Sopenharmony_ci .end = 0xc0000000 + SZ_512M - 1, 518c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT, 528c2ecf20Sopenharmony_ci }, 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic struct pci_channel sh7780_pci_controller = { 568c2ecf20Sopenharmony_ci .pci_ops = &sh4_pci_ops, 578c2ecf20Sopenharmony_ci .resources = sh7785_pci_resources, 588c2ecf20Sopenharmony_ci .nr_resources = ARRAY_SIZE(sh7785_pci_resources), 598c2ecf20Sopenharmony_ci .io_offset = 0, 608c2ecf20Sopenharmony_ci .mem_offset = 0, 618c2ecf20Sopenharmony_ci .io_map_base = 0xfe200000, 628c2ecf20Sopenharmony_ci .serr_irq = evt2irq(0xa00), 638c2ecf20Sopenharmony_ci .err_irq = evt2irq(0xaa0), 648c2ecf20Sopenharmony_ci}; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistruct pci_errors { 678c2ecf20Sopenharmony_ci unsigned int mask; 688c2ecf20Sopenharmony_ci const char *str; 698c2ecf20Sopenharmony_ci} pci_arbiter_errors[] = { 708c2ecf20Sopenharmony_ci { SH4_PCIAINT_MBKN, "master broken" }, 718c2ecf20Sopenharmony_ci { SH4_PCIAINT_TBTO, "target bus time out" }, 728c2ecf20Sopenharmony_ci { SH4_PCIAINT_MBTO, "master bus time out" }, 738c2ecf20Sopenharmony_ci { SH4_PCIAINT_TABT, "target abort" }, 748c2ecf20Sopenharmony_ci { SH4_PCIAINT_MABT, "master abort" }, 758c2ecf20Sopenharmony_ci { SH4_PCIAINT_RDPE, "read data parity error" }, 768c2ecf20Sopenharmony_ci { SH4_PCIAINT_WDPE, "write data parity error" }, 778c2ecf20Sopenharmony_ci}, pci_interrupt_errors[] = { 788c2ecf20Sopenharmony_ci { SH4_PCIINT_MLCK, "master lock error" }, 798c2ecf20Sopenharmony_ci { SH4_PCIINT_TABT, "target-target abort" }, 808c2ecf20Sopenharmony_ci { SH4_PCIINT_TRET, "target retry time out" }, 818c2ecf20Sopenharmony_ci { SH4_PCIINT_MFDE, "master function disable error" }, 828c2ecf20Sopenharmony_ci { SH4_PCIINT_PRTY, "address parity error" }, 838c2ecf20Sopenharmony_ci { SH4_PCIINT_SERR, "SERR" }, 848c2ecf20Sopenharmony_ci { SH4_PCIINT_TWDP, "data parity error for target write" }, 858c2ecf20Sopenharmony_ci { SH4_PCIINT_TRDP, "PERR detected for target read" }, 868c2ecf20Sopenharmony_ci { SH4_PCIINT_MTABT, "target abort for master" }, 878c2ecf20Sopenharmony_ci { SH4_PCIINT_MMABT, "master abort for master" }, 888c2ecf20Sopenharmony_ci { SH4_PCIINT_MWPD, "master write data parity error" }, 898c2ecf20Sopenharmony_ci { SH4_PCIINT_MRPD, "master read data parity error" }, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic irqreturn_t sh7780_pci_err_irq(int irq, void *dev_id) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct pci_channel *hose = dev_id; 958c2ecf20Sopenharmony_ci unsigned long addr; 968c2ecf20Sopenharmony_ci unsigned int status; 978c2ecf20Sopenharmony_ci unsigned int cmd; 988c2ecf20Sopenharmony_ci int i; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci addr = __raw_readl(hose->reg_base + SH4_PCIALR); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* 1038c2ecf20Sopenharmony_ci * Handle status errors. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci status = __raw_readw(hose->reg_base + PCI_STATUS); 1068c2ecf20Sopenharmony_ci if (status & (PCI_STATUS_PARITY | 1078c2ecf20Sopenharmony_ci PCI_STATUS_DETECTED_PARITY | 1088c2ecf20Sopenharmony_ci PCI_STATUS_SIG_TARGET_ABORT | 1098c2ecf20Sopenharmony_ci PCI_STATUS_REC_TARGET_ABORT | 1108c2ecf20Sopenharmony_ci PCI_STATUS_REC_MASTER_ABORT)) { 1118c2ecf20Sopenharmony_ci cmd = pcibios_handle_status_errors(addr, status, hose); 1128c2ecf20Sopenharmony_ci if (likely(cmd)) 1138c2ecf20Sopenharmony_ci __raw_writew(cmd, hose->reg_base + PCI_STATUS); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci /* 1178c2ecf20Sopenharmony_ci * Handle arbiter errors. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci status = __raw_readl(hose->reg_base + SH4_PCIAINT); 1208c2ecf20Sopenharmony_ci for (i = cmd = 0; i < ARRAY_SIZE(pci_arbiter_errors); i++) { 1218c2ecf20Sopenharmony_ci if (status & pci_arbiter_errors[i].mask) { 1228c2ecf20Sopenharmony_ci printk(KERN_DEBUG "PCI: %s, addr=%08lx\n", 1238c2ecf20Sopenharmony_ci pci_arbiter_errors[i].str, addr); 1248c2ecf20Sopenharmony_ci cmd |= pci_arbiter_errors[i].mask; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci __raw_writel(cmd, hose->reg_base + SH4_PCIAINT); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* 1308c2ecf20Sopenharmony_ci * Handle the remaining PCI errors. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci status = __raw_readl(hose->reg_base + SH4_PCIINT); 1338c2ecf20Sopenharmony_ci for (i = cmd = 0; i < ARRAY_SIZE(pci_interrupt_errors); i++) { 1348c2ecf20Sopenharmony_ci if (status & pci_interrupt_errors[i].mask) { 1358c2ecf20Sopenharmony_ci printk(KERN_DEBUG "PCI: %s, addr=%08lx\n", 1368c2ecf20Sopenharmony_ci pci_interrupt_errors[i].str, addr); 1378c2ecf20Sopenharmony_ci cmd |= pci_interrupt_errors[i].mask; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci __raw_writel(cmd, hose->reg_base + SH4_PCIINT); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic irqreturn_t sh7780_pci_serr_irq(int irq, void *dev_id) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci struct pci_channel *hose = dev_id; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci printk(KERN_DEBUG "PCI: system error received: "); 1508c2ecf20Sopenharmony_ci pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); 1518c2ecf20Sopenharmony_ci pr_cont("\n"); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* Deassert SERR */ 1548c2ecf20Sopenharmony_ci __raw_writel(SH4_PCIINTM_SDIM, hose->reg_base + SH4_PCIINTM); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* Back off the IRQ for awhile */ 1578c2ecf20Sopenharmony_ci disable_irq_nosync(irq); 1588c2ecf20Sopenharmony_ci hose->serr_timer.expires = jiffies + HZ; 1598c2ecf20Sopenharmony_ci add_timer(&hose->serr_timer); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int __init sh7780_pci_setup_irqs(struct pci_channel *hose) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int ret; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Clear out PCI arbiter IRQs */ 1698c2ecf20Sopenharmony_ci __raw_writel(0, hose->reg_base + SH4_PCIAINT); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* Clear all error conditions */ 1728c2ecf20Sopenharmony_ci __raw_writew(PCI_STATUS_DETECTED_PARITY | \ 1738c2ecf20Sopenharmony_ci PCI_STATUS_SIG_SYSTEM_ERROR | \ 1748c2ecf20Sopenharmony_ci PCI_STATUS_REC_MASTER_ABORT | \ 1758c2ecf20Sopenharmony_ci PCI_STATUS_REC_TARGET_ABORT | \ 1768c2ecf20Sopenharmony_ci PCI_STATUS_SIG_TARGET_ABORT | \ 1778c2ecf20Sopenharmony_ci PCI_STATUS_PARITY, hose->reg_base + PCI_STATUS); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci ret = request_irq(hose->serr_irq, sh7780_pci_serr_irq, 0, 1808c2ecf20Sopenharmony_ci "PCI SERR interrupt", hose); 1818c2ecf20Sopenharmony_ci if (unlikely(ret)) { 1828c2ecf20Sopenharmony_ci pr_err("PCI: Failed hooking SERR IRQ\n"); 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* 1878c2ecf20Sopenharmony_ci * The PCI ERR IRQ needs to be IRQF_SHARED since all of the power 1888c2ecf20Sopenharmony_ci * down IRQ vectors are routed through the ERR IRQ vector. We 1898c2ecf20Sopenharmony_ci * only request_irq() once as there is only a single masking 1908c2ecf20Sopenharmony_ci * source for multiple events. 1918c2ecf20Sopenharmony_ci */ 1928c2ecf20Sopenharmony_ci ret = request_irq(hose->err_irq, sh7780_pci_err_irq, IRQF_SHARED, 1938c2ecf20Sopenharmony_ci "PCI ERR interrupt", hose); 1948c2ecf20Sopenharmony_ci if (unlikely(ret)) { 1958c2ecf20Sopenharmony_ci free_irq(hose->serr_irq, hose); 1968c2ecf20Sopenharmony_ci return ret; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Unmask all of the arbiter IRQs. */ 2008c2ecf20Sopenharmony_ci __raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \ 2018c2ecf20Sopenharmony_ci SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \ 2028c2ecf20Sopenharmony_ci SH4_PCIAINT_WDPE, hose->reg_base + SH4_PCIAINTM); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Unmask all of the PCI IRQs */ 2058c2ecf20Sopenharmony_ci __raw_writel(SH4_PCIINTM_TTADIM | SH4_PCIINTM_TMTOIM | \ 2068c2ecf20Sopenharmony_ci SH4_PCIINTM_MDEIM | SH4_PCIINTM_APEDIM | \ 2078c2ecf20Sopenharmony_ci SH4_PCIINTM_SDIM | SH4_PCIINTM_DPEITWM | \ 2088c2ecf20Sopenharmony_ci SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM | \ 2098c2ecf20Sopenharmony_ci SH4_PCIINTM_MADIMM | SH4_PCIINTM_MWPDIM | \ 2108c2ecf20Sopenharmony_ci SH4_PCIINTM_MRDPEIM, hose->reg_base + SH4_PCIINTM); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return ret; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic inline void __init sh7780_pci_teardown_irqs(struct pci_channel *hose) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci free_irq(hose->err_irq, hose); 2188c2ecf20Sopenharmony_ci free_irq(hose->serr_irq, hose); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void __init sh7780_pci66_init(struct pci_channel *hose) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci unsigned int tmp; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (!pci_is_66mhz_capable(hose, 0, 0)) 2268c2ecf20Sopenharmony_ci return; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Enable register access */ 2298c2ecf20Sopenharmony_ci tmp = __raw_readl(hose->reg_base + SH4_PCICR); 2308c2ecf20Sopenharmony_ci tmp |= SH4_PCICR_PREFIX; 2318c2ecf20Sopenharmony_ci __raw_writel(tmp, hose->reg_base + SH4_PCICR); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* Enable 66MHz operation */ 2348c2ecf20Sopenharmony_ci tmp = __raw_readw(hose->reg_base + PCI_STATUS); 2358c2ecf20Sopenharmony_ci tmp |= PCI_STATUS_66MHZ; 2368c2ecf20Sopenharmony_ci __raw_writew(tmp, hose->reg_base + PCI_STATUS); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Done */ 2398c2ecf20Sopenharmony_ci tmp = __raw_readl(hose->reg_base + SH4_PCICR); 2408c2ecf20Sopenharmony_ci tmp |= SH4_PCICR_PREFIX | SH4_PCICR_CFIN; 2418c2ecf20Sopenharmony_ci __raw_writel(tmp, hose->reg_base + SH4_PCICR); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int __init sh7780_pci_init(void) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct pci_channel *chan = &sh7780_pci_controller; 2478c2ecf20Sopenharmony_ci phys_addr_t memphys; 2488c2ecf20Sopenharmony_ci size_t memsize; 2498c2ecf20Sopenharmony_ci unsigned int id; 2508c2ecf20Sopenharmony_ci const char *type; 2518c2ecf20Sopenharmony_ci int ret, i; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci pr_notice("PCI: Starting initialization.\n"); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci chan->reg_base = 0xfe040000; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Enable CPU access to the PCIC registers. */ 2588c2ecf20Sopenharmony_ci __raw_writel(PCIECR_ENBL, PCIECR); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Reset */ 2618c2ecf20Sopenharmony_ci __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST | PCICR_ENDIANNESS, 2628c2ecf20Sopenharmony_ci chan->reg_base + SH4_PCICR); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * Wait for it to come back up. The spec says to allow for up to 2668c2ecf20Sopenharmony_ci * 1 second after toggling the reset pin, but in practice 100ms 2678c2ecf20Sopenharmony_ci * is more than enough. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ci mdelay(100); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci id = __raw_readw(chan->reg_base + PCI_VENDOR_ID); 2728c2ecf20Sopenharmony_ci if (id != PCI_VENDOR_ID_RENESAS) { 2738c2ecf20Sopenharmony_ci pr_err("PCI: Unknown vendor ID 0x%04x.\n", id); 2748c2ecf20Sopenharmony_ci return -ENODEV; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci id = __raw_readw(chan->reg_base + PCI_DEVICE_ID); 2788c2ecf20Sopenharmony_ci type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" : 2798c2ecf20Sopenharmony_ci (id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" : 2808c2ecf20Sopenharmony_ci (id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" : 2818c2ecf20Sopenharmony_ci (id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" : 2828c2ecf20Sopenharmony_ci NULL; 2838c2ecf20Sopenharmony_ci if (unlikely(!type)) { 2848c2ecf20Sopenharmony_ci pr_err("PCI: Found an unsupported Renesas host controller, device id 0x%04x.\n", 2858c2ecf20Sopenharmony_ci id); 2868c2ecf20Sopenharmony_ci return -EINVAL; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci pr_notice("PCI: Found a Renesas %s host controller, revision %d.\n", 2908c2ecf20Sopenharmony_ci type, __raw_readb(chan->reg_base + PCI_REVISION_ID)); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * Now throw it in to register initialization mode and 2948c2ecf20Sopenharmony_ci * start the real work. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ci __raw_writel(SH4_PCICR_PREFIX | PCICR_ENDIANNESS, 2978c2ecf20Sopenharmony_ci chan->reg_base + SH4_PCICR); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci memphys = __pa(memory_start); 3008c2ecf20Sopenharmony_ci memsize = roundup_pow_of_two(memory_end - memory_start); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* 3038c2ecf20Sopenharmony_ci * If there's more than 512MB of memory, we need to roll over to 3048c2ecf20Sopenharmony_ci * LAR1/LSR1. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci if (memsize > SZ_512M) { 3078c2ecf20Sopenharmony_ci __raw_writel(memphys + SZ_512M, chan->reg_base + SH4_PCILAR1); 3088c2ecf20Sopenharmony_ci __raw_writel((((memsize - SZ_512M) - SZ_1M) & 0x1ff00000) | 1, 3098c2ecf20Sopenharmony_ci chan->reg_base + SH4_PCILSR1); 3108c2ecf20Sopenharmony_ci memsize = SZ_512M; 3118c2ecf20Sopenharmony_ci } else { 3128c2ecf20Sopenharmony_ci /* 3138c2ecf20Sopenharmony_ci * Otherwise just zero it out and disable it. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + SH4_PCILAR1); 3168c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + SH4_PCILSR1); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * LAR0/LSR0 covers up to the first 512MB, which is enough to 3218c2ecf20Sopenharmony_ci * cover all of lowmem on most platforms. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci __raw_writel(memphys, chan->reg_base + SH4_PCILAR0); 3248c2ecf20Sopenharmony_ci __raw_writel(((memsize - SZ_1M) & 0x1ff00000) | 1, 3258c2ecf20Sopenharmony_ci chan->reg_base + SH4_PCILSR0); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* 3288c2ecf20Sopenharmony_ci * Hook up the ERR and SERR IRQs. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci ret = sh7780_pci_setup_irqs(chan); 3318c2ecf20Sopenharmony_ci if (unlikely(ret)) 3328c2ecf20Sopenharmony_ci return ret; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* 3358c2ecf20Sopenharmony_ci * Disable the cache snoop controller for non-coherent DMA. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCICSCR0); 3388c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCICSAR0); 3398c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCICSCR1); 3408c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCICSAR1); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * Setup the memory BARs 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci for (i = 1; i < chan->nr_resources; i++) { 3468c2ecf20Sopenharmony_ci struct resource *res = chan->resources + i; 3478c2ecf20Sopenharmony_ci resource_size_t size; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (unlikely(res->flags & IORESOURCE_IO)) 3508c2ecf20Sopenharmony_ci continue; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* 3538c2ecf20Sopenharmony_ci * Make sure we're in the right physical addressing mode 3548c2ecf20Sopenharmony_ci * for dealing with the resource. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ci if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode()) { 3578c2ecf20Sopenharmony_ci chan->nr_resources--; 3588c2ecf20Sopenharmony_ci continue; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci size = resource_size(res); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * The MBMR mask is calculated in units of 256kB, which 3658c2ecf20Sopenharmony_ci * keeps things pretty simple. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci __raw_writel(((roundup_pow_of_two(size) / SZ_256K) - 1) << 18, 3688c2ecf20Sopenharmony_ci chan->reg_base + SH7780_PCIMBMR(i - 1)); 3698c2ecf20Sopenharmony_ci __raw_writel(res->start, chan->reg_base + SH7780_PCIMBR(i - 1)); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * And I/O. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0); 3768c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCIIOBR); 3778c2ecf20Sopenharmony_ci __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci __raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \ 3808c2ecf20Sopenharmony_ci PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \ 3818c2ecf20Sopenharmony_ci PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* 3848c2ecf20Sopenharmony_ci * Initialization mode complete, release the control register and 3858c2ecf20Sopenharmony_ci * enable round robin mode to stop device overruns/starvation. 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_ci __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO | 3888c2ecf20Sopenharmony_ci PCICR_ENDIANNESS, 3898c2ecf20Sopenharmony_ci chan->reg_base + SH4_PCICR); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ret = register_pci_controller(chan); 3928c2ecf20Sopenharmony_ci if (unlikely(ret)) 3938c2ecf20Sopenharmony_ci goto err; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci sh7780_pci66_init(chan); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci pr_notice("PCI: Running at %dMHz.\n", 3988c2ecf20Sopenharmony_ci (__raw_readw(chan->reg_base + PCI_STATUS) & PCI_STATUS_66MHZ) 3998c2ecf20Sopenharmony_ci ? 66 : 33); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cierr: 4048c2ecf20Sopenharmony_ci sh7780_pci_teardown_irqs(chan); 4058c2ecf20Sopenharmony_ci return ret; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ciarch_initcall(sh7780_pci_init); 408