1/*
2 * arch/arm/mach-ixp23xx/ixdp2351.c
3 *
4 * IXDP2351 board-specific routines
5 *
6 * Author: Deepak Saxena <dsaxena@plexity.net>
7 *
8 * Copyright 2005 (c) MontaVista Software, Inc.
9 *
10 * Based on 2.4 code Copyright 2004 (c) Intel Corporation
11 *
12 * This file is licensed under the terms of the GNU General Public
13 * License version 2. This program is licensed "as is" without any
14 * warranty of any kind, whether express or implied.
15 */
16
17#include <linux/kernel.h>
18#include <linux/init.h>
19#include <linux/spinlock.h>
20#include <linux/sched.h>
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23#include <linux/serial.h>
24#include <linux/tty.h>
25#include <linux/bitops.h>
26#include <linux/ioport.h>
27#include <linux/serial.h>
28#include <linux/serial_8250.h>
29#include <linux/serial_core.h>
30#include <linux/device.h>
31#include <linux/mm.h>
32#include <linux/pci.h>
33#include <linux/mtd/physmap.h>
34
35#include <asm/types.h>
36#include <asm/setup.h>
37#include <asm/memory.h>
38#include <asm/hardware.h>
39#include <asm/mach-types.h>
40#include <asm/system.h>
41#include <asm/tlbflush.h>
42#include <asm/pgtable.h>
43
44#include <asm/mach/map.h>
45#include <asm/mach/irq.h>
46#include <asm/mach/arch.h>
47#include <asm/mach/irq.h>
48#include <asm/mach/pci.h>
49
50/*
51 * IXDP2351 Interrupt Handling
52 */
53static void ixdp2351_inta_mask(unsigned int irq)
54{
55	*IXDP2351_CPLD_INTA_MASK_SET_REG = IXDP2351_INTA_IRQ_MASK(irq);
56}
57
58static void ixdp2351_inta_unmask(unsigned int irq)
59{
60	*IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(irq);
61}
62
63static void ixdp2351_inta_handler(unsigned int irq, struct irq_desc *desc)
64{
65	u16 ex_interrupt =
66		*IXDP2351_CPLD_INTA_STAT_REG & IXDP2351_INTA_IRQ_VALID;
67	int i;
68
69	desc->chip->mask(irq);
70
71	for (i = 0; i < IXDP2351_INTA_IRQ_NUM; i++) {
72		if (ex_interrupt & (1 << i)) {
73			struct irq_desc *cpld_desc;
74			int cpld_irq =
75				IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + i);
76			cpld_desc = irq_desc + cpld_irq;
77			desc_handle_irq(cpld_irq, cpld_desc);
78		}
79	}
80
81	desc->chip->unmask(irq);
82}
83
84static struct irq_chip ixdp2351_inta_chip = {
85	.ack	= ixdp2351_inta_mask,
86	.mask	= ixdp2351_inta_mask,
87	.unmask	= ixdp2351_inta_unmask
88};
89
90static void ixdp2351_intb_mask(unsigned int irq)
91{
92	*IXDP2351_CPLD_INTB_MASK_SET_REG = IXDP2351_INTB_IRQ_MASK(irq);
93}
94
95static void ixdp2351_intb_unmask(unsigned int irq)
96{
97	*IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(irq);
98}
99
100static void ixdp2351_intb_handler(unsigned int irq, struct irq_desc *desc)
101{
102	u16 ex_interrupt =
103		*IXDP2351_CPLD_INTB_STAT_REG & IXDP2351_INTB_IRQ_VALID;
104	int i;
105
106	desc->chip->ack(irq);
107
108	for (i = 0; i < IXDP2351_INTB_IRQ_NUM; i++) {
109		if (ex_interrupt & (1 << i)) {
110			struct irq_desc *cpld_desc;
111			int cpld_irq =
112				IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + i);
113			cpld_desc = irq_desc + cpld_irq;
114			desc_handle_irq(cpld_irq, cpld_desc);
115		}
116	}
117
118	desc->chip->unmask(irq);
119}
120
121static struct irq_chip ixdp2351_intb_chip = {
122	.ack	= ixdp2351_intb_mask,
123	.mask	= ixdp2351_intb_mask,
124	.unmask	= ixdp2351_intb_unmask
125};
126
127void __init ixdp2351_init_irq(void)
128{
129	int irq;
130
131	/* Mask all interrupts from CPLD, disable simulation */
132	*IXDP2351_CPLD_INTA_MASK_SET_REG = (u16) -1;
133	*IXDP2351_CPLD_INTB_MASK_SET_REG = (u16) -1;
134	*IXDP2351_CPLD_INTA_SIM_REG = 0;
135	*IXDP2351_CPLD_INTB_SIM_REG = 0;
136
137	ixp23xx_init_irq();
138
139	for (irq = IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE);
140	     irq <
141	     IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + IXDP2351_INTA_IRQ_NUM);
142	     irq++) {
143		if (IXDP2351_INTA_IRQ_MASK(irq) & IXDP2351_INTA_IRQ_VALID) {
144			set_irq_flags(irq, IRQF_VALID);
145			set_irq_handler(irq, handle_level_irq);
146			set_irq_chip(irq, &ixdp2351_inta_chip);
147		}
148	}
149
150	for (irq = IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE);
151	     irq <
152	     IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + IXDP2351_INTB_IRQ_NUM);
153	     irq++) {
154		if (IXDP2351_INTB_IRQ_MASK(irq) & IXDP2351_INTB_IRQ_VALID) {
155			set_irq_flags(irq, IRQF_VALID);
156			set_irq_handler(irq, handle_level_irq);
157			set_irq_chip(irq, &ixdp2351_intb_chip);
158		}
159	}
160
161	set_irq_chained_handler(IRQ_IXP23XX_INTA, ixdp2351_inta_handler);
162	set_irq_chained_handler(IRQ_IXP23XX_INTB, ixdp2351_intb_handler);
163}
164
165/*
166 * IXDP2351 PCI
167 */
168
169/*
170 * This board does not do normal PCI IRQ routing, or any
171 * sort of swizzling, so we just need to check where on the
172 * bus the device is and figure out what CPLD pin it is
173 * being routed to.
174 */
175#define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
176
177static int __init ixdp2351_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
178{
179	u8 bus = dev->bus->number;
180	u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
181	struct pci_bus *tmp_bus = dev->bus;
182
183	/* Primary bus, no interrupts here */
184	if (!bus)
185		return -1;
186
187	/* Lookup first leaf in bus tree */
188	while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL))
189		tmp_bus = tmp_bus->parent;
190
191	/* Select between known bridges */
192	switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) {
193		/* Device is located after first bridge */
194	case 0x0008:
195		if (tmp_bus == dev->bus) {
196			/* Device is located directy after first bridge */
197			switch (devpin) {
198				/* Onboard 82546 */
199			case DEVPIN(1, 1):	/* Onboard 82546 ch 0 */
200				return IRQ_IXDP2351_INTA_82546;
201			case DEVPIN(1, 2):	/* Onboard 82546 ch 1 */
202				return IRQ_IXDP2351_INTB_82546;
203				/* PMC SLOT */
204			case DEVPIN(0, 1):	/* PMCP INTA# */
205			case DEVPIN(2, 4):	/* PMCS INTD# */
206				return IRQ_IXDP2351_SPCI_PMC_INTA;
207			case DEVPIN(0, 2):	/* PMCP INTB# */
208			case DEVPIN(2, 1):	/* PMCS INTA# */
209				return IRQ_IXDP2351_SPCI_PMC_INTB;
210			case DEVPIN(0, 3):	/* PMCP INTC# */
211			case DEVPIN(2, 2):	/* PMCS INTB# */
212				return IRQ_IXDP2351_SPCI_PMC_INTC;
213			case DEVPIN(0, 4):	/* PMCP INTD# */
214			case DEVPIN(2, 3):	/* PMCS INTC# */
215				return IRQ_IXDP2351_SPCI_PMC_INTD;
216			}
217		} else {
218			/* Device is located indirectly after first bridge */
219			/* Not supported now */
220			return -1;
221		}
222		break;
223	case 0x0010:
224		if (tmp_bus == dev->bus) {
225			/* Device is located directy after second bridge */
226			/* Secondary bus of second bridge */
227			switch (devpin) {
228			case DEVPIN(0, 1):	/* DB#0 */
229			case DEVPIN(0, 2):
230			case DEVPIN(0, 3):
231			case DEVPIN(0, 4):
232				return IRQ_IXDP2351_SPCI_DB_0;
233			case DEVPIN(1, 1):	/* DB#1 */
234			case DEVPIN(1, 2):
235			case DEVPIN(1, 3):
236			case DEVPIN(1, 4):
237				return IRQ_IXDP2351_SPCI_DB_1;
238			case DEVPIN(2, 1):	/* FIC1 */
239			case DEVPIN(2, 2):
240			case DEVPIN(2, 3):
241			case DEVPIN(2, 4):
242			case DEVPIN(3, 1):	/* FIC2 */
243			case DEVPIN(3, 2):
244			case DEVPIN(3, 3):
245			case DEVPIN(3, 4):
246				return IRQ_IXDP2351_SPCI_FIC;
247			}
248		} else {
249			/* Device is located indirectly after second bridge */
250			/* Not supported now */
251			return -1;
252		}
253		break;
254	}
255
256	return -1;
257}
258
259struct hw_pci ixdp2351_pci __initdata = {
260	.nr_controllers	= 1,
261	.preinit	= ixp23xx_pci_preinit,
262	.setup		= ixp23xx_pci_setup,
263	.scan		= ixp23xx_pci_scan_bus,
264	.map_irq	= ixdp2351_map_irq,
265};
266
267int __init ixdp2351_pci_init(void)
268{
269	if (machine_is_ixdp2351())
270		pci_common_init(&ixdp2351_pci);
271
272	return 0;
273}
274
275subsys_initcall(ixdp2351_pci_init);
276
277/*
278 * IXDP2351 Static Mapped I/O
279 */
280static struct map_desc ixdp2351_io_desc[] __initdata = {
281	{
282		.virtual	= IXDP2351_NP_VIRT_BASE,
283		.pfn		= __phys_to_pfn((u64)IXDP2351_NP_PHYS_BASE),
284		.length		= IXDP2351_NP_PHYS_SIZE,
285		.type		= MT_DEVICE
286	}, {
287		.virtual	= IXDP2351_BB_BASE_VIRT,
288		.pfn		= __phys_to_pfn((u64)IXDP2351_BB_BASE_PHYS),
289		.length		= IXDP2351_BB_SIZE,
290		.type		= MT_DEVICE
291	}
292};
293
294static void __init ixdp2351_map_io(void)
295{
296	ixp23xx_map_io();
297	iotable_init(ixdp2351_io_desc, ARRAY_SIZE(ixdp2351_io_desc));
298}
299
300static struct physmap_flash_data ixdp2351_flash_data = {
301	.width		= 1,
302};
303
304static struct resource ixdp2351_flash_resource = {
305	.start		= 0x90000000,
306	.end		= 0x93ffffff,
307	.flags		= IORESOURCE_MEM,
308};
309
310static struct platform_device ixdp2351_flash = {
311	.name		= "physmap-flash",
312	.id		= 0,
313	.dev		= {
314		.platform_data	= &ixdp2351_flash_data,
315	},
316	.num_resources	= 1,
317	.resource	= &ixdp2351_flash_resource,
318};
319
320static void __init ixdp2351_init(void)
321{
322	platform_device_register(&ixdp2351_flash);
323
324	/*
325	 * Mark flash as writeable
326	 */
327	IXP23XX_EXP_CS0[0] |= IXP23XX_FLASH_WRITABLE;
328	IXP23XX_EXP_CS0[1] |= IXP23XX_FLASH_WRITABLE;
329	IXP23XX_EXP_CS0[2] |= IXP23XX_FLASH_WRITABLE;
330	IXP23XX_EXP_CS0[3] |= IXP23XX_FLASH_WRITABLE;
331
332	ixp23xx_sys_init();
333}
334
335MACHINE_START(IXDP2351, "Intel IXDP2351 Development Platform")
336	/* Maintainer: MontaVista Software, Inc. */
337	.phys_io	= IXP23XX_PERIPHERAL_PHYS,
338	.io_pg_offst	= ((IXP23XX_PERIPHERAL_VIRT >> 18)) & 0xfffc,
339	.map_io		= ixdp2351_map_io,
340	.init_irq	= ixdp2351_init_irq,
341	.timer		= &ixp23xx_timer,
342	.boot_params	= 0x00000100,
343	.init_machine	= ixdp2351_init,
344MACHINE_END
345