icu.c 16.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5
/*
 *  icu.c, Interrupt Control Unit routines for the NEC VR4100 series.
 *
 *  Copyright (C) 2001-2002  MontaVista Software Inc.
 *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
6
 *  Copyright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
L
Linus Torvalds 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
/*
 * Changes:
 *  MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
 *  - New creation, NEC VR4122 and VR4131 are supported.
 *  - Added support for NEC VR4111 and VR4121.
 *
28
 *  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
L
Linus Torvalds 已提交
29 30 31 32
 *  - Coped with INTASSIGN of NEC VR4133.
 */
#include <linux/errno.h>
#include <linux/init.h>
33
#include <linux/ioport.h>
L
Linus Torvalds 已提交
34 35 36 37 38 39 40
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/types.h>

#include <asm/cpu.h>
#include <asm/io.h>
41
#include <asm/vr41xx/irq.h>
L
Linus Torvalds 已提交
42 43
#include <asm/vr41xx/vr41xx.h>

44 45
static void __iomem *icu1_base;
static void __iomem *icu2_base;
L
Linus Torvalds 已提交
46 47 48 49

static unsigned char sysint1_assign[16] = {
	0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char sysint2_assign[16] = {
50
	2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
L
Linus Torvalds 已提交
51

52 53
#define ICU1_TYPE1_BASE	0x0b000080UL
#define ICU2_TYPE1_BASE	0x0b000200UL
L
Linus Torvalds 已提交
54

55 56 57 58 59
#define ICU1_TYPE2_BASE	0x0f000080UL
#define ICU2_TYPE2_BASE	0x0f0000a0UL

#define ICU1_SIZE	0x20
#define ICU2_SIZE	0x1c
L
Linus Torvalds 已提交
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

#define SYSINT1REG	0x00
#define PIUINTREG	0x02
#define INTASSIGN0	0x04
#define INTASSIGN1	0x06
#define GIUINTLREG	0x08
#define DSIUINTREG	0x0a
#define MSYSINT1REG	0x0c
#define MPIUINTREG	0x0e
#define MAIUINTREG	0x10
#define MKIUINTREG	0x12
#define MGIUINTLREG	0x14
#define MDSIUINTREG	0x16
#define NMIREG		0x18
#define SOFTREG		0x1a
#define INTASSIGN2	0x1c
#define INTASSIGN3	0x1e

#define SYSINT2REG	0x00
#define GIUINTHREG	0x02
#define FIRINTREG	0x04
#define MSYSINT2REG	0x06
#define MGIUINTHREG	0x08
#define MFIRINTREG	0x0a
#define PCIINTREG	0x0c
 #define PCIINT0	0x0001
#define SCUINTREG	0x0e
 #define SCUINT0	0x0001
#define CSIINTREG	0x10
#define MPCIINTREG	0x12
#define MSCUINTREG	0x14
#define MCSIINTREG	0x16
#define BCUINTREG	0x18
 #define BCUINTR	0x0001
#define MBCUINTREG	0x1a

#define SYSINT1_IRQ_TO_PIN(x)	((x) - SYSINT1_IRQ_BASE)	/* Pin 0-15 */
#define SYSINT2_IRQ_TO_PIN(x)	((x) - SYSINT2_IRQ_BASE)	/* Pin 0-15 */

99 100 101 102
#define INT_TO_IRQ(x)		((x) + 2)	/* Int0-4 -> IRQ2-6 */

#define icu1_read(offset)		readw(icu1_base + (offset))
#define icu1_write(offset, value)	writew((value), icu1_base + (offset))
L
Linus Torvalds 已提交
103

104 105
#define icu2_read(offset)		readw(icu2_base + (offset))
#define icu2_write(offset, value)	writew((value), icu2_base + (offset))
L
Linus Torvalds 已提交
106 107 108 109

#define INTASSIGN_MAX	4
#define INTASSIGN_MASK	0x0007

110
static inline uint16_t icu1_set(uint8_t offset, uint16_t set)
L
Linus Torvalds 已提交
111
{
112
	uint16_t data;
L
Linus Torvalds 已提交
113

114 115 116
	data = icu1_read(offset);
	data |= set;
	icu1_write(offset, data);
L
Linus Torvalds 已提交
117

118
	return data;
L
Linus Torvalds 已提交
119 120
}

121
static inline uint16_t icu1_clear(uint8_t offset, uint16_t clear)
L
Linus Torvalds 已提交
122
{
123
	uint16_t data;
L
Linus Torvalds 已提交
124

125 126 127
	data = icu1_read(offset);
	data &= ~clear;
	icu1_write(offset, data);
L
Linus Torvalds 已提交
128

129
	return data;
L
Linus Torvalds 已提交
130 131
}

132
static inline uint16_t icu2_set(uint8_t offset, uint16_t set)
L
Linus Torvalds 已提交
133
{
134
	uint16_t data;
L
Linus Torvalds 已提交
135

136 137 138
	data = icu2_read(offset);
	data |= set;
	icu2_write(offset, data);
L
Linus Torvalds 已提交
139

140
	return data;
L
Linus Torvalds 已提交
141 142
}

143
static inline uint16_t icu2_clear(uint8_t offset, uint16_t clear)
L
Linus Torvalds 已提交
144
{
145
	uint16_t data;
L
Linus Torvalds 已提交
146

147 148 149
	data = icu2_read(offset);
	data &= ~clear;
	icu2_write(offset, data);
L
Linus Torvalds 已提交
150

151
	return data;
L
Linus Torvalds 已提交
152 153 154 155
}

void vr41xx_enable_piuint(uint16_t mask)
{
156
	struct irq_desc *desc = irq_desc + PIU_IRQ;
L
Linus Torvalds 已提交
157 158 159 160 161
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4111 ||
	    current_cpu_data.cputype == CPU_VR4121) {
		spin_lock_irqsave(&desc->lock, flags);
162
		icu1_set(MPIUINTREG, mask);
L
Linus Torvalds 已提交
163 164 165 166 167 168 169 170
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_enable_piuint);

void vr41xx_disable_piuint(uint16_t mask)
{
171
	struct irq_desc *desc = irq_desc + PIU_IRQ;
L
Linus Torvalds 已提交
172 173 174 175 176
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4111 ||
	    current_cpu_data.cputype == CPU_VR4121) {
		spin_lock_irqsave(&desc->lock, flags);
177
		icu1_clear(MPIUINTREG, mask);
L
Linus Torvalds 已提交
178 179 180 181 182 183 184 185
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_disable_piuint);

void vr41xx_enable_aiuint(uint16_t mask)
{
186
	struct irq_desc *desc = irq_desc + AIU_IRQ;
L
Linus Torvalds 已提交
187 188 189 190 191
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4111 ||
	    current_cpu_data.cputype == CPU_VR4121) {
		spin_lock_irqsave(&desc->lock, flags);
192
		icu1_set(MAIUINTREG, mask);
L
Linus Torvalds 已提交
193 194 195 196 197 198 199 200
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_enable_aiuint);

void vr41xx_disable_aiuint(uint16_t mask)
{
201
	struct irq_desc *desc = irq_desc + AIU_IRQ;
L
Linus Torvalds 已提交
202 203 204 205 206
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4111 ||
	    current_cpu_data.cputype == CPU_VR4121) {
		spin_lock_irqsave(&desc->lock, flags);
207
		icu1_clear(MAIUINTREG, mask);
L
Linus Torvalds 已提交
208 209 210 211 212 213 214 215
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_disable_aiuint);

void vr41xx_enable_kiuint(uint16_t mask)
{
216
	struct irq_desc *desc = irq_desc + KIU_IRQ;
L
Linus Torvalds 已提交
217 218 219 220 221
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4111 ||
	    current_cpu_data.cputype == CPU_VR4121) {
		spin_lock_irqsave(&desc->lock, flags);
222
		icu1_set(MKIUINTREG, mask);
L
Linus Torvalds 已提交
223 224 225 226 227 228 229 230
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_enable_kiuint);

void vr41xx_disable_kiuint(uint16_t mask)
{
231
	struct irq_desc *desc = irq_desc + KIU_IRQ;
L
Linus Torvalds 已提交
232 233 234 235 236
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4111 ||
	    current_cpu_data.cputype == CPU_VR4121) {
		spin_lock_irqsave(&desc->lock, flags);
237
		icu1_clear(MKIUINTREG, mask);
L
Linus Torvalds 已提交
238 239 240 241 242 243 244 245
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_disable_kiuint);

void vr41xx_enable_dsiuint(uint16_t mask)
{
246
	struct irq_desc *desc = irq_desc + DSIU_IRQ;
L
Linus Torvalds 已提交
247 248 249
	unsigned long flags;

	spin_lock_irqsave(&desc->lock, flags);
250
	icu1_set(MDSIUINTREG, mask);
L
Linus Torvalds 已提交
251 252 253 254 255 256 257
	spin_unlock_irqrestore(&desc->lock, flags);
}

EXPORT_SYMBOL(vr41xx_enable_dsiuint);

void vr41xx_disable_dsiuint(uint16_t mask)
{
258
	struct irq_desc *desc = irq_desc + DSIU_IRQ;
L
Linus Torvalds 已提交
259 260 261
	unsigned long flags;

	spin_lock_irqsave(&desc->lock, flags);
262
	icu1_clear(MDSIUINTREG, mask);
L
Linus Torvalds 已提交
263 264 265 266 267 268 269
	spin_unlock_irqrestore(&desc->lock, flags);
}

EXPORT_SYMBOL(vr41xx_disable_dsiuint);

void vr41xx_enable_firint(uint16_t mask)
{
270
	struct irq_desc *desc = irq_desc + FIR_IRQ;
L
Linus Torvalds 已提交
271 272 273
	unsigned long flags;

	spin_lock_irqsave(&desc->lock, flags);
274
	icu2_set(MFIRINTREG, mask);
L
Linus Torvalds 已提交
275 276 277 278 279 280 281
	spin_unlock_irqrestore(&desc->lock, flags);
}

EXPORT_SYMBOL(vr41xx_enable_firint);

void vr41xx_disable_firint(uint16_t mask)
{
282
	struct irq_desc *desc = irq_desc + FIR_IRQ;
L
Linus Torvalds 已提交
283 284 285
	unsigned long flags;

	spin_lock_irqsave(&desc->lock, flags);
286
	icu2_clear(MFIRINTREG, mask);
L
Linus Torvalds 已提交
287 288 289 290 291 292 293
	spin_unlock_irqrestore(&desc->lock, flags);
}

EXPORT_SYMBOL(vr41xx_disable_firint);

void vr41xx_enable_pciint(void)
{
294
	struct irq_desc *desc = irq_desc + PCI_IRQ;
L
Linus Torvalds 已提交
295 296 297 298 299 300
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4122 ||
	    current_cpu_data.cputype == CPU_VR4131 ||
	    current_cpu_data.cputype == CPU_VR4133) {
		spin_lock_irqsave(&desc->lock, flags);
301
		icu2_write(MPCIINTREG, PCIINT0);
L
Linus Torvalds 已提交
302 303 304 305 306 307 308 309
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_enable_pciint);

void vr41xx_disable_pciint(void)
{
310
	struct irq_desc *desc = irq_desc + PCI_IRQ;
L
Linus Torvalds 已提交
311 312 313 314 315 316
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4122 ||
	    current_cpu_data.cputype == CPU_VR4131 ||
	    current_cpu_data.cputype == CPU_VR4133) {
		spin_lock_irqsave(&desc->lock, flags);
317
		icu2_write(MPCIINTREG, 0);
L
Linus Torvalds 已提交
318 319 320 321 322 323 324 325
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_disable_pciint);

void vr41xx_enable_scuint(void)
{
326
	struct irq_desc *desc = irq_desc + SCU_IRQ;
L
Linus Torvalds 已提交
327 328 329 330 331 332
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4122 ||
	    current_cpu_data.cputype == CPU_VR4131 ||
	    current_cpu_data.cputype == CPU_VR4133) {
		spin_lock_irqsave(&desc->lock, flags);
333
		icu2_write(MSCUINTREG, SCUINT0);
L
Linus Torvalds 已提交
334 335 336 337 338 339 340 341
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_enable_scuint);

void vr41xx_disable_scuint(void)
{
342
	struct irq_desc *desc = irq_desc + SCU_IRQ;
L
Linus Torvalds 已提交
343 344 345 346 347 348
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4122 ||
	    current_cpu_data.cputype == CPU_VR4131 ||
	    current_cpu_data.cputype == CPU_VR4133) {
		spin_lock_irqsave(&desc->lock, flags);
349
		icu2_write(MSCUINTREG, 0);
L
Linus Torvalds 已提交
350 351 352 353 354 355 356 357
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_disable_scuint);

void vr41xx_enable_csiint(uint16_t mask)
{
358
	struct irq_desc *desc = irq_desc + CSI_IRQ;
L
Linus Torvalds 已提交
359 360 361 362 363 364
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4122 ||
	    current_cpu_data.cputype == CPU_VR4131 ||
	    current_cpu_data.cputype == CPU_VR4133) {
		spin_lock_irqsave(&desc->lock, flags);
365
		icu2_set(MCSIINTREG, mask);
L
Linus Torvalds 已提交
366 367 368 369 370 371 372 373
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_enable_csiint);

void vr41xx_disable_csiint(uint16_t mask)
{
374
	struct irq_desc *desc = irq_desc + CSI_IRQ;
L
Linus Torvalds 已提交
375 376 377 378 379 380
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4122 ||
	    current_cpu_data.cputype == CPU_VR4131 ||
	    current_cpu_data.cputype == CPU_VR4133) {
		spin_lock_irqsave(&desc->lock, flags);
381
		icu2_clear(MCSIINTREG, mask);
L
Linus Torvalds 已提交
382 383 384 385 386 387 388 389
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_disable_csiint);

void vr41xx_enable_bcuint(void)
{
390
	struct irq_desc *desc = irq_desc + BCU_IRQ;
L
Linus Torvalds 已提交
391 392 393 394 395 396
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4122 ||
	    current_cpu_data.cputype == CPU_VR4131 ||
	    current_cpu_data.cputype == CPU_VR4133) {
		spin_lock_irqsave(&desc->lock, flags);
397
		icu2_write(MBCUINTREG, BCUINTR);
L
Linus Torvalds 已提交
398 399 400 401 402 403 404 405
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_enable_bcuint);

void vr41xx_disable_bcuint(void)
{
406
	struct irq_desc *desc = irq_desc + BCU_IRQ;
L
Linus Torvalds 已提交
407 408 409 410 411 412
	unsigned long flags;

	if (current_cpu_data.cputype == CPU_VR4122 ||
	    current_cpu_data.cputype == CPU_VR4131 ||
	    current_cpu_data.cputype == CPU_VR4133) {
		spin_lock_irqsave(&desc->lock, flags);
413
		icu2_write(MBCUINTREG, 0);
L
Linus Torvalds 已提交
414 415 416 417 418 419
		spin_unlock_irqrestore(&desc->lock, flags);
	}
}

EXPORT_SYMBOL(vr41xx_disable_bcuint);

A
Atsushi Nemoto 已提交
420
static void disable_sysint1_irq(unsigned int irq)
L
Linus Torvalds 已提交
421
{
422
	icu1_clear(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
L
Linus Torvalds 已提交
423 424 425 426
}

static void enable_sysint1_irq(unsigned int irq)
{
427
	icu1_set(MSYSINT1REG, 1 << SYSINT1_IRQ_TO_PIN(irq));
L
Linus Torvalds 已提交
428 429
}

430
static struct irq_chip sysint1_irq_type = {
L
Linus Torvalds 已提交
431
	.typename	= "SYSINT1",
A
Atsushi Nemoto 已提交
432 433 434 435
	.ack		= disable_sysint1_irq,
	.mask		= disable_sysint1_irq,
	.mask_ack	= disable_sysint1_irq,
	.unmask		= enable_sysint1_irq,
L
Linus Torvalds 已提交
436 437
};

A
Atsushi Nemoto 已提交
438
static void disable_sysint2_irq(unsigned int irq)
L
Linus Torvalds 已提交
439
{
440
	icu2_clear(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
L
Linus Torvalds 已提交
441 442 443 444
}

static void enable_sysint2_irq(unsigned int irq)
{
445
	icu2_set(MSYSINT2REG, 1 << SYSINT2_IRQ_TO_PIN(irq));
L
Linus Torvalds 已提交
446 447
}

448
static struct irq_chip sysint2_irq_type = {
L
Linus Torvalds 已提交
449
	.typename	= "SYSINT2",
A
Atsushi Nemoto 已提交
450 451 452 453
	.ack		= disable_sysint2_irq,
	.mask		= disable_sysint2_irq,
	.mask_ack	= disable_sysint2_irq,
	.unmask		= enable_sysint2_irq,
L
Linus Torvalds 已提交
454 455 456 457
};

static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
{
458
	struct irq_desc *desc = irq_desc + irq;
L
Linus Torvalds 已提交
459 460 461 462 463 464 465
	uint16_t intassign0, intassign1;
	unsigned int pin;

	pin = SYSINT1_IRQ_TO_PIN(irq);

	spin_lock_irq(&desc->lock);

466 467
	intassign0 = icu1_read(INTASSIGN0);
	intassign1 = icu1_read(INTASSIGN1);
L
Linus Torvalds 已提交
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506

	switch (pin) {
	case 0:
		intassign0 &= ~INTASSIGN_MASK;
		intassign0 |= (uint16_t)assign;
		break;
	case 1:
		intassign0 &= ~(INTASSIGN_MASK << 3);
		intassign0 |= (uint16_t)assign << 3;
		break;
	case 2:
		intassign0 &= ~(INTASSIGN_MASK << 6);
		intassign0 |= (uint16_t)assign << 6;
		break;
	case 3:
		intassign0 &= ~(INTASSIGN_MASK << 9);
		intassign0 |= (uint16_t)assign << 9;
		break;
	case 8:
		intassign0 &= ~(INTASSIGN_MASK << 12);
		intassign0 |= (uint16_t)assign << 12;
		break;
	case 9:
		intassign1 &= ~INTASSIGN_MASK;
		intassign1 |= (uint16_t)assign;
		break;
	case 11:
		intassign1 &= ~(INTASSIGN_MASK << 6);
		intassign1 |= (uint16_t)assign << 6;
		break;
	case 12:
		intassign1 &= ~(INTASSIGN_MASK << 9);
		intassign1 |= (uint16_t)assign << 9;
		break;
	default:
		return -EINVAL;
	}

	sysint1_assign[pin] = assign;
507 508
	icu1_write(INTASSIGN0, intassign0);
	icu1_write(INTASSIGN1, intassign1);
L
Linus Torvalds 已提交
509 510 511 512 513 514 515 516

	spin_unlock_irq(&desc->lock);

	return 0;
}

static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
{
517
	struct irq_desc *desc = irq_desc + irq;
L
Linus Torvalds 已提交
518 519 520 521 522 523 524
	uint16_t intassign2, intassign3;
	unsigned int pin;

	pin = SYSINT2_IRQ_TO_PIN(irq);

	spin_lock_irq(&desc->lock);

525 526
	intassign2 = icu1_read(INTASSIGN2);
	intassign3 = icu1_read(INTASSIGN3);
L
Linus Torvalds 已提交
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573

	switch (pin) {
	case 0:
		intassign2 &= ~INTASSIGN_MASK;
		intassign2 |= (uint16_t)assign;
		break;
	case 1:
		intassign2 &= ~(INTASSIGN_MASK << 3);
		intassign2 |= (uint16_t)assign << 3;
		break;
	case 3:
		intassign2 &= ~(INTASSIGN_MASK << 6);
		intassign2 |= (uint16_t)assign << 6;
		break;
	case 4:
		intassign2 &= ~(INTASSIGN_MASK << 9);
		intassign2 |= (uint16_t)assign << 9;
		break;
	case 5:
		intassign2 &= ~(INTASSIGN_MASK << 12);
		intassign2 |= (uint16_t)assign << 12;
		break;
	case 6:
		intassign3 &= ~INTASSIGN_MASK;
		intassign3 |= (uint16_t)assign;
		break;
	case 7:
		intassign3 &= ~(INTASSIGN_MASK << 3);
		intassign3 |= (uint16_t)assign << 3;
		break;
	case 8:
		intassign3 &= ~(INTASSIGN_MASK << 6);
		intassign3 |= (uint16_t)assign << 6;
		break;
	case 9:
		intassign3 &= ~(INTASSIGN_MASK << 9);
		intassign3 |= (uint16_t)assign << 9;
		break;
	case 10:
		intassign3 &= ~(INTASSIGN_MASK << 12);
		intassign3 |= (uint16_t)assign << 12;
		break;
	default:
		return -EINVAL;
	}

	sysint2_assign[pin] = assign;
574 575
	icu1_write(INTASSIGN2, intassign2);
	icu1_write(INTASSIGN3, intassign3);
L
Linus Torvalds 已提交
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601

	spin_unlock_irq(&desc->lock);

	return 0;
}

int vr41xx_set_intassign(unsigned int irq, unsigned char intassign)
{
	int retval = -EINVAL;

	if (current_cpu_data.cputype != CPU_VR4133)
		return -EINVAL;

	if (intassign > INTASSIGN_MAX)
		return -EINVAL;

	if (irq >= SYSINT1_IRQ_BASE && irq <= SYSINT1_IRQ_LAST)
		retval = set_sysint1_assign(irq, intassign);
	else if (irq >= SYSINT2_IRQ_BASE && irq <= SYSINT2_IRQ_LAST)
		retval = set_sysint2_assign(irq, intassign);

	return retval;
}

EXPORT_SYMBOL(vr41xx_set_intassign);

602
static int icu_get_irq(unsigned int irq)
L
Linus Torvalds 已提交
603 604 605 606 607
{
	uint16_t pend1, pend2;
	uint16_t mask1, mask2;
	int i;

608 609
	pend1 = icu1_read(SYSINT1REG);
	mask1 = icu1_read(MSYSINT1REG);
L
Linus Torvalds 已提交
610

611 612
	pend2 = icu2_read(SYSINT2REG);
	mask2 = icu2_read(MSYSINT2REG);
L
Linus Torvalds 已提交
613 614 615 616 617 618

	mask1 &= pend1;
	mask2 &= pend2;

	if (mask1) {
		for (i = 0; i < 16; i++) {
619 620
			if (irq == INT_TO_IRQ(sysint1_assign[i]) && (mask1 & (1 << i)))
				return SYSINT1_IRQ(i);
L
Linus Torvalds 已提交
621 622 623 624 625
		}
	}

	if (mask2) {
		for (i = 0; i < 16; i++) {
626 627
			if (irq == INT_TO_IRQ(sysint2_assign[i]) && (mask2 & (1 << i)))
				return SYSINT2_IRQ(i);
L
Linus Torvalds 已提交
628 629 630 631 632 633 634
		}
	}

	printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2);

	atomic_inc(&irq_err_count);

635 636
	return -1;
}
L
Linus Torvalds 已提交
637 638 639

static int __init vr41xx_icu_init(void)
{
640 641 642
	unsigned long icu1_start, icu2_start;
	int i;

L
Linus Torvalds 已提交
643 644 645
	switch (current_cpu_data.cputype) {
	case CPU_VR4111:
	case CPU_VR4121:
646 647
		icu1_start = ICU1_TYPE1_BASE;
		icu2_start = ICU2_TYPE1_BASE;
L
Linus Torvalds 已提交
648 649 650 651
		break;
	case CPU_VR4122:
	case CPU_VR4131:
	case CPU_VR4133:
652 653
		icu1_start = ICU1_TYPE2_BASE;
		icu2_start = ICU2_TYPE2_BASE;
L
Linus Torvalds 已提交
654 655 656
		break;
	default:
		printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n");
657
		return -ENODEV;
L
Linus Torvalds 已提交
658 659
	}

660 661
	if (request_mem_region(icu1_start, ICU1_SIZE, "ICU") == NULL)
		return -EBUSY;
L
Linus Torvalds 已提交
662

663 664 665 666
	if (request_mem_region(icu2_start, ICU2_SIZE, "ICU") == NULL) {
		release_mem_region(icu1_start, ICU1_SIZE);
		return -EBUSY;
	}
L
Linus Torvalds 已提交
667

668 669 670 671 672 673
	icu1_base = ioremap(icu1_start, ICU1_SIZE);
	if (icu1_base == NULL) {
		release_mem_region(icu1_start, ICU1_SIZE);
		release_mem_region(icu2_start, ICU2_SIZE);
		return -ENOMEM;
	}
L
Linus Torvalds 已提交
674

675 676 677 678 679 680 681
	icu2_base = ioremap(icu2_start, ICU2_SIZE);
	if (icu2_base == NULL) {
		iounmap(icu1_base);
		release_mem_region(icu1_start, ICU1_SIZE);
		release_mem_region(icu2_start, ICU2_SIZE);
		return -ENOMEM;
	}
L
Linus Torvalds 已提交
682

683 684
	icu1_write(MSYSINT1REG, 0);
	icu1_write(MGIUINTLREG, 0xffff);
L
Linus Torvalds 已提交
685

686 687
	icu2_write(MSYSINT2REG, 0);
	icu2_write(MGIUINTHREG, 0xffff);
L
Linus Torvalds 已提交
688 689

	for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++)
690 691
		set_irq_chip_and_handler(i, &sysint1_irq_type,
					 handle_level_irq);
L
Linus Torvalds 已提交
692 693

	for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++)
694 695
		set_irq_chip_and_handler(i, &sysint2_irq_type,
					 handle_level_irq);
L
Linus Torvalds 已提交
696

697 698 699 700 701
	cascade_irq(INT0_IRQ, icu_get_irq);
	cascade_irq(INT1_IRQ, icu_get_irq);
	cascade_irq(INT2_IRQ, icu_get_irq);
	cascade_irq(INT3_IRQ, icu_get_irq);
	cascade_irq(INT4_IRQ, icu_get_irq);
L
Linus Torvalds 已提交
702

703
	return 0;
L
Linus Torvalds 已提交
704
}
705 706

core_initcall(vr41xx_icu_init);