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