18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/mach-ixp4xx/common-pci.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * IXP4XX PCI routines for all platforms 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Maintainer: Deepak Saxena <dsaxena@plexity.net> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (C) 2002 Intel Corporation. 108c2ecf20Sopenharmony_ci * Copyright (C) 2003 Greg Ungerer <gerg@snapgear.com> 118c2ecf20Sopenharmony_ci * Copyright (C) 2003-2004 MontaVista Software, Inc. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/sched.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/pci.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/mm.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/ioport.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci#include <linux/delay.h> 238c2ecf20Sopenharmony_ci#include <linux/device.h> 248c2ecf20Sopenharmony_ci#include <linux/io.h> 258c2ecf20Sopenharmony_ci#include <linux/export.h> 268c2ecf20Sopenharmony_ci#include <asm/dma-mapping.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <asm/cputype.h> 298c2ecf20Sopenharmony_ci#include <asm/irq.h> 308c2ecf20Sopenharmony_ci#include <linux/sizes.h> 318c2ecf20Sopenharmony_ci#include <asm/mach/pci.h> 328c2ecf20Sopenharmony_ci#include <mach/hardware.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * IXP4xx PCI read function is dependent on whether we are 378c2ecf20Sopenharmony_ci * running A0 or B0 (AppleGate) silicon. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ciint (*ixp4xx_pci_read)(u32 addr, u32 cmd, u32* data); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Base address for PCI register region 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ciunsigned long ixp4xx_pci_reg_base = 0; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * PCI cfg an I/O routines are done by programming a 488c2ecf20Sopenharmony_ci * command/byte enable register, and then read/writing 498c2ecf20Sopenharmony_ci * the data from a data register. We need to ensure 508c2ecf20Sopenharmony_ci * these transactions are atomic or we will end up 518c2ecf20Sopenharmony_ci * with corrupt data on the bus or in a driver. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(ixp4xx_pci_lock); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Read from PCI config space 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_cistatic void crp_read(u32 ad_cbe, u32 *data) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci unsigned long flags; 618c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags); 628c2ecf20Sopenharmony_ci *PCI_CRP_AD_CBE = ad_cbe; 638c2ecf20Sopenharmony_ci *data = *PCI_CRP_RDATA; 648c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* 688c2ecf20Sopenharmony_ci * Write to PCI config space 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistatic void crp_write(u32 ad_cbe, u32 data) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci unsigned long flags; 738c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags); 748c2ecf20Sopenharmony_ci *PCI_CRP_AD_CBE = CRP_AD_CBE_WRITE | ad_cbe; 758c2ecf20Sopenharmony_ci *PCI_CRP_WDATA = data; 768c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline int check_master_abort(void) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci /* check Master Abort bit after access */ 828c2ecf20Sopenharmony_ci unsigned long isr = *PCI_ISR; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (isr & PCI_ISR_PFE) { 858c2ecf20Sopenharmony_ci /* make sure the Master Abort bit is reset */ 868c2ecf20Sopenharmony_ci *PCI_ISR = PCI_ISR_PFE; 878c2ecf20Sopenharmony_ci pr_debug("%s failed\n", __func__); 888c2ecf20Sopenharmony_ci return 1; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ciint ixp4xx_pci_read_errata(u32 addr, u32 cmd, u32* data) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci unsigned long flags; 978c2ecf20Sopenharmony_ci int retval = 0; 988c2ecf20Sopenharmony_ci int i; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci *PCI_NP_AD = addr; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci /* 1058c2ecf20Sopenharmony_ci * PCI workaround - only works if NP PCI space reads have 1068c2ecf20Sopenharmony_ci * no side effects!!! Read 8 times. last one will be good. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 1098c2ecf20Sopenharmony_ci *PCI_NP_CBE = cmd; 1108c2ecf20Sopenharmony_ci *data = *PCI_NP_RDATA; 1118c2ecf20Sopenharmony_ci *data = *PCI_NP_RDATA; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if(check_master_abort()) 1158c2ecf20Sopenharmony_ci retval = 1; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); 1188c2ecf20Sopenharmony_ci return retval; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciint ixp4xx_pci_read_no_errata(u32 addr, u32 cmd, u32* data) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci unsigned long flags; 1248c2ecf20Sopenharmony_ci int retval = 0; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci *PCI_NP_AD = addr; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* set up and execute the read */ 1318c2ecf20Sopenharmony_ci *PCI_NP_CBE = cmd; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* the result of the read is now in NP_RDATA */ 1348c2ecf20Sopenharmony_ci *data = *PCI_NP_RDATA; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if(check_master_abort()) 1378c2ecf20Sopenharmony_ci retval = 1; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); 1408c2ecf20Sopenharmony_ci return retval; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciint ixp4xx_pci_write(u32 addr, u32 cmd, u32 data) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci unsigned long flags; 1468c2ecf20Sopenharmony_ci int retval = 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&ixp4xx_pci_lock, flags); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci *PCI_NP_AD = addr; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* set up the write */ 1538c2ecf20Sopenharmony_ci *PCI_NP_CBE = cmd; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* execute the write by writing to NP_WDATA */ 1568c2ecf20Sopenharmony_ci *PCI_NP_WDATA = data; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if(check_master_abort()) 1598c2ecf20Sopenharmony_ci retval = 1; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&ixp4xx_pci_lock, flags); 1628c2ecf20Sopenharmony_ci return retval; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic u32 ixp4xx_config_addr(u8 bus_num, u16 devfn, int where) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci u32 addr; 1688c2ecf20Sopenharmony_ci if (!bus_num) { 1698c2ecf20Sopenharmony_ci /* type 0 */ 1708c2ecf20Sopenharmony_ci addr = BIT(32-PCI_SLOT(devfn)) | ((PCI_FUNC(devfn)) << 8) | 1718c2ecf20Sopenharmony_ci (where & ~3); 1728c2ecf20Sopenharmony_ci } else { 1738c2ecf20Sopenharmony_ci /* type 1 */ 1748c2ecf20Sopenharmony_ci addr = (bus_num << 16) | ((PCI_SLOT(devfn)) << 11) | 1758c2ecf20Sopenharmony_ci ((PCI_FUNC(devfn)) << 8) | (where & ~3) | 1; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci return addr; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* 1818c2ecf20Sopenharmony_ci * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes. 1828c2ecf20Sopenharmony_ci * 0 and 3 are not valid indexes... 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic u32 bytemask[] = { 1858c2ecf20Sopenharmony_ci /*0*/ 0, 1868c2ecf20Sopenharmony_ci /*1*/ 0xff, 1878c2ecf20Sopenharmony_ci /*2*/ 0xffff, 1888c2ecf20Sopenharmony_ci /*3*/ 0, 1898c2ecf20Sopenharmony_ci /*4*/ 0xffffffff, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic u32 local_byte_lane_enable_bits(u32 n, int size) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci if (size == 1) 1958c2ecf20Sopenharmony_ci return (0xf & ~BIT(n)) << CRP_AD_CBE_BESL; 1968c2ecf20Sopenharmony_ci if (size == 2) 1978c2ecf20Sopenharmony_ci return (0xf & ~(BIT(n) | BIT(n+1))) << CRP_AD_CBE_BESL; 1988c2ecf20Sopenharmony_ci if (size == 4) 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci return 0xffffffff; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int local_read_config(int where, int size, u32 *value) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci u32 n, data; 2068c2ecf20Sopenharmony_ci pr_debug("local_read_config from %d size %d\n", where, size); 2078c2ecf20Sopenharmony_ci n = where % 4; 2088c2ecf20Sopenharmony_ci crp_read(where & ~3, &data); 2098c2ecf20Sopenharmony_ci *value = (data >> (8*n)) & bytemask[size]; 2108c2ecf20Sopenharmony_ci pr_debug("local_read_config read %#x\n", *value); 2118c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int local_write_config(int where, int size, u32 value) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci u32 n, byte_enables, data; 2178c2ecf20Sopenharmony_ci pr_debug("local_write_config %#x to %d size %d\n", value, where, size); 2188c2ecf20Sopenharmony_ci n = where % 4; 2198c2ecf20Sopenharmony_ci byte_enables = local_byte_lane_enable_bits(n, size); 2208c2ecf20Sopenharmony_ci if (byte_enables == 0xffffffff) 2218c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 2228c2ecf20Sopenharmony_ci data = value << (8*n); 2238c2ecf20Sopenharmony_ci crp_write((where & ~3) | byte_enables, data); 2248c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic u32 byte_lane_enable_bits(u32 n, int size) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci if (size == 1) 2308c2ecf20Sopenharmony_ci return (0xf & ~BIT(n)) << 4; 2318c2ecf20Sopenharmony_ci if (size == 2) 2328c2ecf20Sopenharmony_ci return (0xf & ~(BIT(n) | BIT(n+1))) << 4; 2338c2ecf20Sopenharmony_ci if (size == 4) 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci return 0xffffffff; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int ixp4xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci u32 n, byte_enables, addr, data; 2418c2ecf20Sopenharmony_ci u8 bus_num = bus->number; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci pr_debug("read_config from %d size %d dev %d:%d:%d\n", where, size, 2448c2ecf20Sopenharmony_ci bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn)); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci *value = 0xffffffff; 2478c2ecf20Sopenharmony_ci n = where % 4; 2488c2ecf20Sopenharmony_ci byte_enables = byte_lane_enable_bits(n, size); 2498c2ecf20Sopenharmony_ci if (byte_enables == 0xffffffff) 2508c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci addr = ixp4xx_config_addr(bus_num, devfn, where); 2538c2ecf20Sopenharmony_ci if (ixp4xx_pci_read(addr, byte_enables | NP_CMD_CONFIGREAD, &data)) 2548c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci *value = (data >> (8*n)) & bytemask[size]; 2578c2ecf20Sopenharmony_ci pr_debug("read_config_byte read %#x\n", *value); 2588c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int ixp4xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci u32 n, byte_enables, addr, data; 2648c2ecf20Sopenharmony_ci u8 bus_num = bus->number; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci pr_debug("write_config_byte %#x to %d size %d dev %d:%d:%d\n", value, where, 2678c2ecf20Sopenharmony_ci size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn)); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci n = where % 4; 2708c2ecf20Sopenharmony_ci byte_enables = byte_lane_enable_bits(n, size); 2718c2ecf20Sopenharmony_ci if (byte_enables == 0xffffffff) 2728c2ecf20Sopenharmony_ci return PCIBIOS_BAD_REGISTER_NUMBER; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci addr = ixp4xx_config_addr(bus_num, devfn, where); 2758c2ecf20Sopenharmony_ci data = value << (8*n); 2768c2ecf20Sopenharmony_ci if (ixp4xx_pci_write(addr, byte_enables | NP_CMD_CONFIGWRITE, data)) 2778c2ecf20Sopenharmony_ci return PCIBIOS_DEVICE_NOT_FOUND; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return PCIBIOS_SUCCESSFUL; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistruct pci_ops ixp4xx_ops = { 2838c2ecf20Sopenharmony_ci .read = ixp4xx_pci_read_config, 2848c2ecf20Sopenharmony_ci .write = ixp4xx_pci_write_config, 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci/* 2888c2ecf20Sopenharmony_ci * PCI abort handler 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_cistatic int abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci u32 isr, status; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci isr = *PCI_ISR; 2958c2ecf20Sopenharmony_ci local_read_config(PCI_STATUS, 2, &status); 2968c2ecf20Sopenharmony_ci pr_debug("PCI: abort_handler addr = %#lx, isr = %#x, " 2978c2ecf20Sopenharmony_ci "status = %#x\n", addr, isr, status); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* make sure the Master Abort bit is reset */ 3008c2ecf20Sopenharmony_ci *PCI_ISR = PCI_ISR_PFE; 3018c2ecf20Sopenharmony_ci status |= PCI_STATUS_REC_MASTER_ABORT; 3028c2ecf20Sopenharmony_ci local_write_config(PCI_STATUS, 2, status); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* 3058c2ecf20Sopenharmony_ci * If it was an imprecise abort, then we need to correct the 3068c2ecf20Sopenharmony_ci * return address to be _after_ the instruction. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ci if (fsr & (1 << 10)) 3098c2ecf20Sopenharmony_ci regs->ARM_pc += 4; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_civoid __init ixp4xx_pci_preinit(void) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci unsigned long cpuid = read_cpuid_id(); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci#ifdef CONFIG_IXP4XX_INDIRECT_PCI 3198c2ecf20Sopenharmony_ci pcibios_min_mem = 0x10000000; /* 1 GB of indirect PCI MMIO space */ 3208c2ecf20Sopenharmony_ci#else 3218c2ecf20Sopenharmony_ci pcibios_min_mem = 0x48000000; /* 64 MB of PCI MMIO space */ 3228c2ecf20Sopenharmony_ci#endif 3238c2ecf20Sopenharmony_ci /* 3248c2ecf20Sopenharmony_ci * Determine which PCI read method to use. 3258c2ecf20Sopenharmony_ci * Rev 0 IXP425 requires workaround. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_ci if (!(cpuid & 0xf) && cpu_is_ixp42x()) { 3288c2ecf20Sopenharmony_ci printk("PCI: IXP42x A0 silicon detected - " 3298c2ecf20Sopenharmony_ci "PCI Non-Prefetch Workaround Enabled\n"); 3308c2ecf20Sopenharmony_ci ixp4xx_pci_read = ixp4xx_pci_read_errata; 3318c2ecf20Sopenharmony_ci } else 3328c2ecf20Sopenharmony_ci ixp4xx_pci_read = ixp4xx_pci_read_no_errata; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* hook in our fault handler for PCI errors */ 3368c2ecf20Sopenharmony_ci hook_fault_code(16+6, abort_handler, SIGBUS, 0, 3378c2ecf20Sopenharmony_ci "imprecise external abort"); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci pr_debug("setup PCI-AHB(inbound) and AHB-PCI(outbound) address mappings\n"); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* 3428c2ecf20Sopenharmony_ci * We use identity AHB->PCI address translation 3438c2ecf20Sopenharmony_ci * in the 0x48000000 to 0x4bffffff address space 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci *PCI_PCIMEMBASE = 0x48494A4B; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * We also use identity PCI->AHB address translation 3498c2ecf20Sopenharmony_ci * in 4 16MB BARs that begin at the physical memory start 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci *PCI_AHBMEMBASE = (PHYS_OFFSET & 0xFF000000) + 3528c2ecf20Sopenharmony_ci ((PHYS_OFFSET & 0xFF000000) >> 8) + 3538c2ecf20Sopenharmony_ci ((PHYS_OFFSET & 0xFF000000) >> 16) + 3548c2ecf20Sopenharmony_ci ((PHYS_OFFSET & 0xFF000000) >> 24) + 3558c2ecf20Sopenharmony_ci 0x00010203; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (*PCI_CSR & PCI_CSR_HOST) { 3588c2ecf20Sopenharmony_ci printk("PCI: IXP4xx is host\n"); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci pr_debug("setup BARs in controller\n"); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* 3638c2ecf20Sopenharmony_ci * We configure the PCI inbound memory windows to be 3648c2ecf20Sopenharmony_ci * 1:1 mapped to SDRAM 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci local_write_config(PCI_BASE_ADDRESS_0, 4, PHYS_OFFSET); 3678c2ecf20Sopenharmony_ci local_write_config(PCI_BASE_ADDRESS_1, 4, PHYS_OFFSET + SZ_16M); 3688c2ecf20Sopenharmony_ci local_write_config(PCI_BASE_ADDRESS_2, 4, PHYS_OFFSET + SZ_32M); 3698c2ecf20Sopenharmony_ci local_write_config(PCI_BASE_ADDRESS_3, 4, 3708c2ecf20Sopenharmony_ci PHYS_OFFSET + SZ_32M + SZ_16M); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * Enable CSR window at 64 MiB to allow PCI masters 3748c2ecf20Sopenharmony_ci * to continue prefetching past 64 MiB boundary. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci local_write_config(PCI_BASE_ADDRESS_4, 4, PHYS_OFFSET + SZ_64M); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* 3798c2ecf20Sopenharmony_ci * Enable the IO window to be way up high, at 0xfffffc00 3808c2ecf20Sopenharmony_ci */ 3818c2ecf20Sopenharmony_ci local_write_config(PCI_BASE_ADDRESS_5, 4, 0xfffffc01); 3828c2ecf20Sopenharmony_ci local_write_config(0x40, 4, 0x000080FF); /* No TRDY time limit */ 3838c2ecf20Sopenharmony_ci } else { 3848c2ecf20Sopenharmony_ci printk("PCI: IXP4xx is target - No bus scan performed\n"); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci printk("PCI: IXP4xx Using %s access for memory space\n", 3888c2ecf20Sopenharmony_ci#ifndef CONFIG_IXP4XX_INDIRECT_PCI 3898c2ecf20Sopenharmony_ci "direct" 3908c2ecf20Sopenharmony_ci#else 3918c2ecf20Sopenharmony_ci "indirect" 3928c2ecf20Sopenharmony_ci#endif 3938c2ecf20Sopenharmony_ci ); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci pr_debug("clear error bits in ISR\n"); 3968c2ecf20Sopenharmony_ci *PCI_ISR = PCI_ISR_PSE | PCI_ISR_PFE | PCI_ISR_PPE | PCI_ISR_AHBE; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* 3998c2ecf20Sopenharmony_ci * Set Initialize Complete in PCI Control Register: allow IXP4XX to 4008c2ecf20Sopenharmony_ci * respond to PCI configuration cycles. Specify that the AHB bus is 4018c2ecf20Sopenharmony_ci * operating in big endian mode. Set up byte lane swapping between 4028c2ecf20Sopenharmony_ci * little-endian PCI and the big-endian AHB bus 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci#ifdef __ARMEB__ 4058c2ecf20Sopenharmony_ci *PCI_CSR = PCI_CSR_IC | PCI_CSR_ABE | PCI_CSR_PDS | PCI_CSR_ADS; 4068c2ecf20Sopenharmony_ci#else 4078c2ecf20Sopenharmony_ci *PCI_CSR = PCI_CSR_IC | PCI_CSR_ABE; 4088c2ecf20Sopenharmony_ci#endif 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci pr_debug("DONE\n"); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ciint ixp4xx_setup(int nr, struct pci_sys_data *sys) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct resource *res; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (nr >= 1) 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci res = kcalloc(2, sizeof(*res), GFP_KERNEL); 4218c2ecf20Sopenharmony_ci if (res == NULL) { 4228c2ecf20Sopenharmony_ci /* 4238c2ecf20Sopenharmony_ci * If we're out of memory this early, something is wrong, 4248c2ecf20Sopenharmony_ci * so we might as well catch it here. 4258c2ecf20Sopenharmony_ci */ 4268c2ecf20Sopenharmony_ci panic("PCI: unable to allocate resources?\n"); 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci local_write_config(PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci res[0].name = "PCI I/O Space"; 4328c2ecf20Sopenharmony_ci res[0].start = 0x00000000; 4338c2ecf20Sopenharmony_ci res[0].end = 0x0000ffff; 4348c2ecf20Sopenharmony_ci res[0].flags = IORESOURCE_IO; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci res[1].name = "PCI Memory Space"; 4378c2ecf20Sopenharmony_ci res[1].start = PCIBIOS_MIN_MEM; 4388c2ecf20Sopenharmony_ci res[1].end = PCIBIOS_MAX_MEM; 4398c2ecf20Sopenharmony_ci res[1].flags = IORESOURCE_MEM; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci request_resource(&ioport_resource, &res[0]); 4428c2ecf20Sopenharmony_ci request_resource(&iomem_resource, &res[1]); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset); 4458c2ecf20Sopenharmony_ci pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci return 1; 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ixp4xx_pci_read); 4518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ixp4xx_pci_write); 452