18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1998-2001 Russell King
68c2ecf20Sopenharmony_ci *  Copyright (C) 1998-2000 Phil Blundell
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/pci.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/mm.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/ioport.h>
158c2ecf20Sopenharmony_ci#include <linux/irq.h>
168c2ecf20Sopenharmony_ci#include <linux/io.h>
178c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <asm/irq.h>
208c2ecf20Sopenharmony_ci#include <asm/mach/pci.h>
218c2ecf20Sopenharmony_ci#include <asm/hardware/dec21285.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define MAX_SLOTS		21
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define PCICMD_ABORT		((PCI_STATUS_REC_MASTER_ABORT| \
268c2ecf20Sopenharmony_ci				  PCI_STATUS_REC_TARGET_ABORT)<<16)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define PCICMD_ERROR_BITS	((PCI_STATUS_DETECTED_PARITY | \
298c2ecf20Sopenharmony_ci				  PCI_STATUS_REC_MASTER_ABORT | \
308c2ecf20Sopenharmony_ci				  PCI_STATUS_REC_TARGET_ABORT | \
318c2ecf20Sopenharmony_ci				  PCI_STATUS_PARITY) << 16)
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciextern int setup_arm_irq(int, struct irqaction *);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic unsigned long
368c2ecf20Sopenharmony_cidc21285_base_address(struct pci_bus *bus, unsigned int devfn)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	unsigned long addr = 0;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (bus->number == 0) {
418c2ecf20Sopenharmony_ci		if (PCI_SLOT(devfn) == 0)
428c2ecf20Sopenharmony_ci			/*
438c2ecf20Sopenharmony_ci			 * For devfn 0, point at the 21285
448c2ecf20Sopenharmony_ci			 */
458c2ecf20Sopenharmony_ci			addr = ARMCSR_BASE;
468c2ecf20Sopenharmony_ci		else {
478c2ecf20Sopenharmony_ci			devfn -= 1 << 3;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci			if (devfn < PCI_DEVFN(MAX_SLOTS, 0))
508c2ecf20Sopenharmony_ci				addr = PCICFG0_BASE | 0xc00000 | (devfn << 8);
518c2ecf20Sopenharmony_ci		}
528c2ecf20Sopenharmony_ci	} else
538c2ecf20Sopenharmony_ci		addr = PCICFG1_BASE | (bus->number << 16) | (devfn << 8);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return addr;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int
598c2ecf20Sopenharmony_cidc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where,
608c2ecf20Sopenharmony_ci		    int size, u32 *value)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	unsigned long addr = dc21285_base_address(bus, devfn);
638c2ecf20Sopenharmony_ci	u32 v = 0xffffffff;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (addr)
668c2ecf20Sopenharmony_ci		switch (size) {
678c2ecf20Sopenharmony_ci		case 1:
688c2ecf20Sopenharmony_ci			asm volatile("ldrb	%0, [%1, %2]"
698c2ecf20Sopenharmony_ci				: "=r" (v) : "r" (addr), "r" (where) : "cc");
708c2ecf20Sopenharmony_ci			break;
718c2ecf20Sopenharmony_ci		case 2:
728c2ecf20Sopenharmony_ci			asm volatile("ldrh	%0, [%1, %2]"
738c2ecf20Sopenharmony_ci				: "=r" (v) : "r" (addr), "r" (where) : "cc");
748c2ecf20Sopenharmony_ci			break;
758c2ecf20Sopenharmony_ci		case 4:
768c2ecf20Sopenharmony_ci			asm volatile("ldr	%0, [%1, %2]"
778c2ecf20Sopenharmony_ci				: "=r" (v) : "r" (addr), "r" (where) : "cc");
788c2ecf20Sopenharmony_ci			break;
798c2ecf20Sopenharmony_ci		}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	*value = v;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	v = *CSR_PCICMD;
848c2ecf20Sopenharmony_ci	if (v & PCICMD_ABORT) {
858c2ecf20Sopenharmony_ci		*CSR_PCICMD = v & (0xffff|PCICMD_ABORT);
868c2ecf20Sopenharmony_ci		return -1;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int
938c2ecf20Sopenharmony_cidc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where,
948c2ecf20Sopenharmony_ci		     int size, u32 value)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	unsigned long addr = dc21285_base_address(bus, devfn);
978c2ecf20Sopenharmony_ci	u32 v;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (addr)
1008c2ecf20Sopenharmony_ci		switch (size) {
1018c2ecf20Sopenharmony_ci		case 1:
1028c2ecf20Sopenharmony_ci			asm volatile("strb	%0, [%1, %2]"
1038c2ecf20Sopenharmony_ci				: : "r" (value), "r" (addr), "r" (where)
1048c2ecf20Sopenharmony_ci				: "cc");
1058c2ecf20Sopenharmony_ci			break;
1068c2ecf20Sopenharmony_ci		case 2:
1078c2ecf20Sopenharmony_ci			asm volatile("strh	%0, [%1, %2]"
1088c2ecf20Sopenharmony_ci				: : "r" (value), "r" (addr), "r" (where)
1098c2ecf20Sopenharmony_ci				: "cc");
1108c2ecf20Sopenharmony_ci			break;
1118c2ecf20Sopenharmony_ci		case 4:
1128c2ecf20Sopenharmony_ci			asm volatile("str	%0, [%1, %2]"
1138c2ecf20Sopenharmony_ci				: : "r" (value), "r" (addr), "r" (where)
1148c2ecf20Sopenharmony_ci				: "cc");
1158c2ecf20Sopenharmony_ci			break;
1168c2ecf20Sopenharmony_ci		}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	v = *CSR_PCICMD;
1198c2ecf20Sopenharmony_ci	if (v & PCICMD_ABORT) {
1208c2ecf20Sopenharmony_ci		*CSR_PCICMD = v & (0xffff|PCICMD_ABORT);
1218c2ecf20Sopenharmony_ci		return -1;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return PCIBIOS_SUCCESSFUL;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistruct pci_ops dc21285_ops = {
1288c2ecf20Sopenharmony_ci	.read	= dc21285_read_config,
1298c2ecf20Sopenharmony_ci	.write	= dc21285_write_config,
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic struct timer_list serr_timer;
1338c2ecf20Sopenharmony_cistatic struct timer_list perr_timer;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic void dc21285_enable_error(struct timer_list *timer)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	del_timer(timer);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (timer == &serr_timer)
1408c2ecf20Sopenharmony_ci		enable_irq(IRQ_PCI_SERR);
1418c2ecf20Sopenharmony_ci	else if (timer == &perr_timer)
1428c2ecf20Sopenharmony_ci		enable_irq(IRQ_PCI_PERR);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci/*
1468c2ecf20Sopenharmony_ci * Warn on PCI errors.
1478c2ecf20Sopenharmony_ci */
1488c2ecf20Sopenharmony_cistatic irqreturn_t dc21285_abort_irq(int irq, void *dev_id)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	unsigned int cmd;
1518c2ecf20Sopenharmony_ci	unsigned int status;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	cmd = *CSR_PCICMD;
1548c2ecf20Sopenharmony_ci	status = cmd >> 16;
1558c2ecf20Sopenharmony_ci	cmd = cmd & 0xffff;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (status & PCI_STATUS_REC_MASTER_ABORT) {
1588c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n",
1598c2ecf20Sopenharmony_ci			instruction_pointer(get_irq_regs()));
1608c2ecf20Sopenharmony_ci		cmd |= PCI_STATUS_REC_MASTER_ABORT << 16;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	if (status & PCI_STATUS_REC_TARGET_ABORT) {
1648c2ecf20Sopenharmony_ci		printk(KERN_DEBUG "PCI: target abort: ");
1658c2ecf20Sopenharmony_ci		pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT |
1668c2ecf20Sopenharmony_ci				      PCI_STATUS_SIG_TARGET_ABORT |
1678c2ecf20Sopenharmony_ci				      PCI_STATUS_REC_TARGET_ABORT, 1);
1688c2ecf20Sopenharmony_ci		printk("\n");
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci		cmd |= PCI_STATUS_REC_TARGET_ABORT << 16;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	*CSR_PCICMD = cmd;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic irqreturn_t dc21285_serr_irq(int irq, void *dev_id)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct timer_list *timer = dev_id;
1818c2ecf20Sopenharmony_ci	unsigned int cntl;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "PCI: system error received: ");
1848c2ecf20Sopenharmony_ci	pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1);
1858c2ecf20Sopenharmony_ci	printk("\n");
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	cntl = *CSR_SA110_CNTL & 0xffffdf07;
1888c2ecf20Sopenharmony_ci	*CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/*
1918c2ecf20Sopenharmony_ci	 * back off this interrupt
1928c2ecf20Sopenharmony_ci	 */
1938c2ecf20Sopenharmony_ci	disable_irq(irq);
1948c2ecf20Sopenharmony_ci	timer->expires = jiffies + HZ;
1958c2ecf20Sopenharmony_ci	add_timer(timer);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic irqreturn_t dc21285_discard_irq(int irq, void *dev_id)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "PCI: discard timer expired\n");
2038c2ecf20Sopenharmony_ci	*CSR_SA110_CNTL &= 0xffffde07;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic irqreturn_t dc21285_dparity_irq(int irq, void *dev_id)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	unsigned int cmd;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "PCI: data parity error detected: ");
2138c2ecf20Sopenharmony_ci	pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1);
2148c2ecf20Sopenharmony_ci	printk("\n");
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	cmd = *CSR_PCICMD & 0xffff;
2178c2ecf20Sopenharmony_ci	*CSR_PCICMD = cmd | 1 << 24;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic irqreturn_t dc21285_parity_irq(int irq, void *dev_id)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	struct timer_list *timer = dev_id;
2258c2ecf20Sopenharmony_ci	unsigned int cmd;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "PCI: parity error detected: ");
2288c2ecf20Sopenharmony_ci	pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1);
2298c2ecf20Sopenharmony_ci	printk("\n");
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	cmd = *CSR_PCICMD & 0xffff;
2328c2ecf20Sopenharmony_ci	*CSR_PCICMD = cmd | 1 << 31;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/*
2358c2ecf20Sopenharmony_ci	 * back off this interrupt
2368c2ecf20Sopenharmony_ci	 */
2378c2ecf20Sopenharmony_ci	disable_irq(irq);
2388c2ecf20Sopenharmony_ci	timer->expires = jiffies + HZ;
2398c2ecf20Sopenharmony_ci	add_timer(timer);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ciint __init dc21285_setup(int nr, struct pci_sys_data *sys)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct resource *res;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (nr || !footbridge_cfn_mode())
2498c2ecf20Sopenharmony_ci		return 0;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
2528c2ecf20Sopenharmony_ci	if (!res) {
2538c2ecf20Sopenharmony_ci		printk("out of memory for root bus resources");
2548c2ecf20Sopenharmony_ci		return 0;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	res[0].flags = IORESOURCE_MEM;
2588c2ecf20Sopenharmony_ci	res[0].name  = "Footbridge non-prefetch";
2598c2ecf20Sopenharmony_ci	res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
2608c2ecf20Sopenharmony_ci	res[1].name  = "Footbridge prefetch";
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	allocate_resource(&iomem_resource, &res[1], 0x20000000,
2638c2ecf20Sopenharmony_ci			  0xa0000000, 0xffffffff, 0x20000000, NULL, NULL);
2648c2ecf20Sopenharmony_ci	allocate_resource(&iomem_resource, &res[0], 0x40000000,
2658c2ecf20Sopenharmony_ci			  0x80000000, 0xffffffff, 0x40000000, NULL, NULL);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	sys->mem_offset  = DC21285_PCI_MEM;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
2708c2ecf20Sopenharmony_ci	pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	return 1;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci#define dc21285_request_irq(_a, _b, _c, _d, _e) \
2768c2ecf20Sopenharmony_ci	WARN_ON(request_irq(_a, _b, _c, _d, _e) < 0)
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_civoid __init dc21285_preinit(void)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	unsigned int mem_size, mem_mask;
2818c2ecf20Sopenharmony_ci	int cfn_mode;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	pcibios_min_mem = 0x81000000;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	mem_size = (unsigned int)high_memory - PAGE_OFFSET;
2868c2ecf20Sopenharmony_ci	for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
2878c2ecf20Sopenharmony_ci		if (mem_mask >= mem_size)
2888c2ecf20Sopenharmony_ci			break;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/*
2918c2ecf20Sopenharmony_ci	 * These registers need to be set up whether we're the
2928c2ecf20Sopenharmony_ci	 * central function or not.
2938c2ecf20Sopenharmony_ci	 */
2948c2ecf20Sopenharmony_ci	*CSR_SDRAMBASEMASK    = (mem_mask - 1) & 0x0ffc0000;
2958c2ecf20Sopenharmony_ci	*CSR_SDRAMBASEOFFSET  = 0;
2968c2ecf20Sopenharmony_ci	*CSR_ROMBASEMASK      = 0x80000000;
2978c2ecf20Sopenharmony_ci	*CSR_CSRBASEMASK      = 0;
2988c2ecf20Sopenharmony_ci	*CSR_CSRBASEOFFSET    = 0;
2998c2ecf20Sopenharmony_ci	*CSR_PCIADDR_EXTN     = 0;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	cfn_mode = __footbridge_cfn_mode();
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in "
3048c2ecf20Sopenharmony_ci		"%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ?
3058c2ecf20Sopenharmony_ci		"central function" : "addin");
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	if (footbridge_cfn_mode()) {
3088c2ecf20Sopenharmony_ci		/*
3098c2ecf20Sopenharmony_ci		 * Clear any existing errors - we aren't
3108c2ecf20Sopenharmony_ci		 * interested in historical data...
3118c2ecf20Sopenharmony_ci		 */
3128c2ecf20Sopenharmony_ci		*CSR_SA110_CNTL	= (*CSR_SA110_CNTL & 0xffffde07) |
3138c2ecf20Sopenharmony_ci				  SA110_CNTL_RXSERR;
3148c2ecf20Sopenharmony_ci		*CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	timer_setup(&serr_timer, dc21285_enable_error, 0);
3188c2ecf20Sopenharmony_ci	timer_setup(&perr_timer, dc21285_enable_error, 0);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * We don't care if these fail.
3228c2ecf20Sopenharmony_ci	 */
3238c2ecf20Sopenharmony_ci	dc21285_request_irq(IRQ_PCI_SERR, dc21285_serr_irq, 0,
3248c2ecf20Sopenharmony_ci			    "PCI system error", &serr_timer);
3258c2ecf20Sopenharmony_ci	dc21285_request_irq(IRQ_PCI_PERR, dc21285_parity_irq, 0,
3268c2ecf20Sopenharmony_ci			    "PCI parity error", &perr_timer);
3278c2ecf20Sopenharmony_ci	dc21285_request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, 0,
3288c2ecf20Sopenharmony_ci			    "PCI abort", NULL);
3298c2ecf20Sopenharmony_ci	dc21285_request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, 0,
3308c2ecf20Sopenharmony_ci			    "Discard timer", NULL);
3318c2ecf20Sopenharmony_ci	dc21285_request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, 0,
3328c2ecf20Sopenharmony_ci			    "PCI data parity", NULL);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (cfn_mode) {
3358c2ecf20Sopenharmony_ci		/*
3368c2ecf20Sopenharmony_ci		 * Map our SDRAM at a known address in PCI space, just in case
3378c2ecf20Sopenharmony_ci		 * the firmware had other ideas.  Using a nonzero base is
3388c2ecf20Sopenharmony_ci		 * necessary, since some VGA cards forcefully use PCI addresses
3398c2ecf20Sopenharmony_ci		 * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
3408c2ecf20Sopenharmony_ci		 */
3418c2ecf20Sopenharmony_ci		*CSR_PCICSRBASE       = 0xf4000000;
3428c2ecf20Sopenharmony_ci		*CSR_PCICSRIOBASE     = 0;
3438c2ecf20Sopenharmony_ci		*CSR_PCISDRAMBASE     = __virt_to_bus(PAGE_OFFSET);
3448c2ecf20Sopenharmony_ci		*CSR_PCIROMBASE       = 0;
3458c2ecf20Sopenharmony_ci		*CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
3468c2ecf20Sopenharmony_ci			      PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS;
3478c2ecf20Sopenharmony_ci	} else if (footbridge_cfn_mode() != 0) {
3488c2ecf20Sopenharmony_ci		/*
3498c2ecf20Sopenharmony_ci		 * If we are not compiled to accept "add-in" mode, then
3508c2ecf20Sopenharmony_ci		 * we are using a constant virt_to_bus translation which
3518c2ecf20Sopenharmony_ci		 * can not hope to cater for the way the host BIOS  has
3528c2ecf20Sopenharmony_ci		 * set up the machine.
3538c2ecf20Sopenharmony_ci		 */
3548c2ecf20Sopenharmony_ci		panic("PCI: this kernel is compiled for central "
3558c2ecf20Sopenharmony_ci			"function mode only");
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_civoid __init dc21285_postinit(void)
3608c2ecf20Sopenharmony_ci{
3618c2ecf20Sopenharmony_ci	register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0);
3628c2ecf20Sopenharmony_ci}
363