summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-iop3xx/iq31244-pci.c
blob: c6a973ba8fc6f9aff7af143be17f4fdd95427720 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * arch/arm/mach-iop3xx/iq80321-pci.c
 *
 * PCI support for the Intel IQ80321 reference board
 *
 * Author: Rory Bolt <rorybolt@pacbell.net>
 * Copyright (C) 2002 Rory Bolt
 * Copyright (C) 2004 Intel Corp.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>

#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/mach/pci.h>
#include <asm/mach-types.h>

/*
 * The following macro is used to lookup irqs in a standard table
 * format for those systems that do not already have PCI
 * interrupts properly routed.  We assume 1 <= pin <= 4
 */
#define PCI_IRQ_TABLE_LOOKUP(minid,maxid)	\
({ int _ctl_ = -1;				\
   unsigned int _idsel = idsel - minid;		\
   if (_idsel <= maxid)				\
      _ctl_ = pci_irq_table[_idsel][pin-1];	\
   _ctl_; })

#define INTA	IRQ_IQ31244_INTA
#define INTB	IRQ_IQ31244_INTB
#define INTC	IRQ_IQ31244_INTC
#define INTD	IRQ_IQ31244_INTD

#define INTE	IRQ_IQ31244_I82546

static inline int __init
iq31244_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
{
	static int pci_irq_table[][4] = {
		/*
		 * PCI IDSEL/INTPIN->INTLINE
		 * A       B       C       D
		 */
#ifdef CONFIG_ARCH_EP80219
		{INTB, INTB, INTB, INTB}, /* CFlash */
		{INTE, INTE, INTE, INTE}, /* 82551 Pro 100 */
		{INTD, INTD, INTD, INTD}, /* PCI-X Slot */
		{INTC, INTC, INTC, INTC}, /* SATA   */
#else
		{INTB, INTB, INTB, INTB}, /* CFlash */
		{INTC, INTC, INTC, INTC}, /* SATA   */
		{INTD, INTD, INTD, INTD}, /* PCI-X Slot */
		{INTE, INTE, INTE, INTE}, /* 82546 GigE */
#endif // CONFIG_ARCH_EP80219
	};

	BUG_ON(pin < 1 || pin > 4);

	return PCI_IRQ_TABLE_LOOKUP(0, 7);
}

static int iq31244_setup(int nr, struct pci_sys_data *sys)
{
	struct resource *res;

	if(nr != 0)
		return 0;

	res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
	if (!res)
		panic("PCI: unable to alloc resources");

	memset(res, 0, sizeof(struct resource) * 2);

	res[0].start = IOP321_PCI_LOWER_IO_VA;
	res[0].end   = IOP321_PCI_UPPER_IO_VA;
	res[0].name  = "IQ31244 PCI I/O Space";
	res[0].flags = IORESOURCE_IO;

	res[1].start = IOP321_PCI_LOWER_MEM_PA;
	res[1].end   = IOP321_PCI_UPPER_MEM_PA;
	res[1].name  = "IQ31244 PCI Memory Space";
	res[1].flags = IORESOURCE_MEM;

	request_resource(&ioport_resource, &res[0]);
	request_resource(&iomem_resource, &res[1]);

	sys->mem_offset = IOP321_PCI_MEM_OFFSET;
	sys->io_offset  = IOP321_PCI_IO_OFFSET;

	sys->resource[0] = &res[0];
	sys->resource[1] = &res[1];
	sys->resource[2] = NULL;

	return 1;
}

static void iq31244_preinit(void)
{
	iop321_init();
}

static struct hw_pci iq31244_pci __initdata = {
	.swizzle	= pci_std_swizzle,
	.nr_controllers = 1,
	.setup		= iq31244_setup,
	.scan		= iop321_scan_bus,
	.preinit	= iq31244_preinit,
	.map_irq	= iq31244_map_irq
};

static int __init iq31244_pci_init(void)
{
	if (machine_is_iq31244())
		pci_common_init(&iq31244_pci);
	return 0;
}

subsys_initcall(iq31244_pci_init);