Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Цей коміт міститься в:
8
arch/mips/vr41xx/common/Makefile
Звичайний файл
8
arch/mips/vr41xx/common/Makefile
Звичайний файл
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# Makefile for common code of the NEC VR4100 series.
|
||||
#
|
||||
|
||||
obj-y += bcu.o cmu.o giu.o icu.o init.o int-handler.o pmu.o
|
||||
obj-$(CONFIG_VRC4173) += vrc4173.o
|
||||
|
||||
EXTRA_AFLAGS := $(CFLAGS)
|
222
arch/mips/vr41xx/common/bcu.c
Звичайний файл
222
arch/mips/vr41xx/common/bcu.c
Звичайний файл
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* bcu.c, Bus Control Unit routines for the NEC VR4100 series.
|
||||
*
|
||||
* Copyright (C) 2002 MontaVista Software Inc.
|
||||
* Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com>
|
||||
* Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
* - Added support for NEC VR4133.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#define CLKSPEEDREG_TYPE1 (void __iomem *)KSEG1ADDR(0x0b000014)
|
||||
#define CLKSPEEDREG_TYPE2 (void __iomem *)KSEG1ADDR(0x0f000014)
|
||||
#define CLKSP(x) ((x) & 0x001f)
|
||||
#define CLKSP_VR4133(x) ((x) & 0x0007)
|
||||
|
||||
#define DIV2B 0x8000
|
||||
#define DIV3B 0x4000
|
||||
#define DIV4B 0x2000
|
||||
|
||||
#define DIVT(x) (((x) & 0xf000) >> 12)
|
||||
#define DIVVT(x) (((x) & 0x0f00) >> 8)
|
||||
|
||||
#define TDIVMODE(x) (2 << (((x) & 0x1000) >> 12))
|
||||
#define VTDIVMODE(x) (((x) & 0x0700) >> 8)
|
||||
|
||||
static unsigned long vr41xx_vtclock;
|
||||
static unsigned long vr41xx_tclock;
|
||||
|
||||
unsigned long vr41xx_get_vtclock_frequency(void)
|
||||
{
|
||||
return vr41xx_vtclock;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(vr41xx_get_vtclock_frequency);
|
||||
|
||||
unsigned long vr41xx_get_tclock_frequency(void)
|
||||
{
|
||||
return vr41xx_tclock;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(vr41xx_get_tclock_frequency);
|
||||
|
||||
static inline uint16_t read_clkspeed(void)
|
||||
{
|
||||
switch (current_cpu_data.cputype) {
|
||||
case CPU_VR4111:
|
||||
case CPU_VR4121: return readw(CLKSPEEDREG_TYPE1);
|
||||
case CPU_VR4122:
|
||||
case CPU_VR4131:
|
||||
case CPU_VR4133: return readw(CLKSPEEDREG_TYPE2);
|
||||
default:
|
||||
printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long calculate_pclock(uint16_t clkspeed)
|
||||
{
|
||||
unsigned long pclock = 0;
|
||||
|
||||
switch (current_cpu_data.cputype) {
|
||||
case CPU_VR4111:
|
||||
case CPU_VR4121:
|
||||
pclock = 18432000 * 64;
|
||||
pclock /= CLKSP(clkspeed);
|
||||
break;
|
||||
case CPU_VR4122:
|
||||
pclock = 18432000 * 98;
|
||||
pclock /= CLKSP(clkspeed);
|
||||
break;
|
||||
case CPU_VR4131:
|
||||
pclock = 18432000 * 108;
|
||||
pclock /= CLKSP(clkspeed);
|
||||
break;
|
||||
case CPU_VR4133:
|
||||
switch (CLKSP_VR4133(clkspeed)) {
|
||||
case 0:
|
||||
pclock = 133000000;
|
||||
break;
|
||||
case 1:
|
||||
pclock = 149000000;
|
||||
break;
|
||||
case 2:
|
||||
pclock = 165900000;
|
||||
break;
|
||||
case 3:
|
||||
pclock = 199100000;
|
||||
break;
|
||||
case 4:
|
||||
pclock = 265900000;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "Unknown PClock speed for NEC VR4133\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "PClock: %ldHz\n", pclock);
|
||||
|
||||
return pclock;
|
||||
}
|
||||
|
||||
static inline unsigned long calculate_vtclock(uint16_t clkspeed, unsigned long pclock)
|
||||
{
|
||||
unsigned long vtclock = 0;
|
||||
|
||||
switch (current_cpu_data.cputype) {
|
||||
case CPU_VR4111:
|
||||
/* The NEC VR4111 doesn't have the VTClock. */
|
||||
break;
|
||||
case CPU_VR4121:
|
||||
vtclock = pclock;
|
||||
/* DIVVT == 9 Divide by 1.5 . VTClock = (PClock * 6) / 9 */
|
||||
if (DIVVT(clkspeed) == 9)
|
||||
vtclock = pclock * 6;
|
||||
/* DIVVT == 10 Divide by 2.5 . VTClock = (PClock * 4) / 10 */
|
||||
else if (DIVVT(clkspeed) == 10)
|
||||
vtclock = pclock * 4;
|
||||
vtclock /= DIVVT(clkspeed);
|
||||
printk(KERN_INFO "VTClock: %ldHz\n", vtclock);
|
||||
break;
|
||||
case CPU_VR4122:
|
||||
if(VTDIVMODE(clkspeed) == 7)
|
||||
vtclock = pclock / 1;
|
||||
else if(VTDIVMODE(clkspeed) == 1)
|
||||
vtclock = pclock / 2;
|
||||
else
|
||||
vtclock = pclock / VTDIVMODE(clkspeed);
|
||||
printk(KERN_INFO "VTClock: %ldHz\n", vtclock);
|
||||
break;
|
||||
case CPU_VR4131:
|
||||
case CPU_VR4133:
|
||||
vtclock = pclock / VTDIVMODE(clkspeed);
|
||||
printk(KERN_INFO "VTClock: %ldHz\n", vtclock);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return vtclock;
|
||||
}
|
||||
|
||||
static inline unsigned long calculate_tclock(uint16_t clkspeed, unsigned long pclock,
|
||||
unsigned long vtclock)
|
||||
{
|
||||
unsigned long tclock = 0;
|
||||
|
||||
switch (current_cpu_data.cputype) {
|
||||
case CPU_VR4111:
|
||||
if (!(clkspeed & DIV2B))
|
||||
tclock = pclock / 2;
|
||||
else if (!(clkspeed & DIV3B))
|
||||
tclock = pclock / 3;
|
||||
else if (!(clkspeed & DIV4B))
|
||||
tclock = pclock / 4;
|
||||
break;
|
||||
case CPU_VR4121:
|
||||
tclock = pclock / DIVT(clkspeed);
|
||||
break;
|
||||
case CPU_VR4122:
|
||||
case CPU_VR4131:
|
||||
case CPU_VR4133:
|
||||
tclock = vtclock / TDIVMODE(clkspeed);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
|
||||
break;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "TClock: %ldHz\n", tclock);
|
||||
|
||||
return tclock;
|
||||
}
|
||||
|
||||
void vr41xx_calculate_clock_frequency(void)
|
||||
{
|
||||
unsigned long pclock;
|
||||
uint16_t clkspeed;
|
||||
|
||||
clkspeed = read_clkspeed();
|
||||
|
||||
pclock = calculate_pclock(clkspeed);
|
||||
vr41xx_vtclock = calculate_vtclock(clkspeed, pclock);
|
||||
vr41xx_tclock = calculate_tclock(clkspeed, pclock, vr41xx_vtclock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(vr41xx_calculate_clock_frequency);
|
257
arch/mips/vr41xx/common/cmu.c
Звичайний файл
257
arch/mips/vr41xx/common/cmu.c
Звичайний файл
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* cmu.c, Clock Mask Unit routines for the NEC VR4100 series.
|
||||
*
|
||||
* Copyright (C) 2001-2002 MontaVista Software Inc.
|
||||
* Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
|
||||
* Copuright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
* - Added support for NEC VR4133.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/vr41xx/vr41xx.h>
|
||||
|
||||
#define CMU_TYPE1_BASE 0x0b000060UL
|
||||
#define CMU_TYPE1_SIZE 0x4
|
||||
|
||||
#define CMU_TYPE2_BASE 0x0f000060UL
|
||||
#define CMU_TYPE2_SIZE 0x4
|
||||
|
||||
#define CMU_TYPE3_BASE 0x0f000060UL
|
||||
#define CMU_TYPE3_SIZE 0x8
|
||||
|
||||
#define CMUCLKMSK 0x0
|
||||
#define MSKPIU 0x0001
|
||||
#define MSKSIU 0x0002
|
||||
#define MSKAIU 0x0004
|
||||
#define MSKKIU 0x0008
|
||||
#define MSKFIR 0x0010
|
||||
#define MSKDSIU 0x0820
|
||||
#define MSKCSI 0x0040
|
||||
#define MSKPCIU 0x0080
|
||||
#define MSKSSIU 0x0100
|
||||
#define MSKSHSP 0x0200
|
||||
#define MSKFFIR 0x0400
|
||||
#define MSKSCSI 0x1000
|
||||
#define MSKPPCIU 0x2000
|
||||
#define CMUCLKMSK2 0x4
|
||||
#define MSKCEU 0x0001
|
||||
#define MSKMAC0 0x0002
|
||||
#define MSKMAC1 0x0004
|
||||
|
||||
static void __iomem *cmu_base;
|
||||
static uint16_t cmuclkmsk, cmuclkmsk2;
|
||||
static spinlock_t cmu_lock;
|
||||
|
||||
#define cmu_read(offset) readw(cmu_base + (offset))
|
||||
#define cmu_write(offset, value) writew((value), cmu_base + (offset))
|
||||
|
||||
void vr41xx_supply_clock(vr41xx_clock_t clock)
|
||||
{
|
||||
spin_lock_irq(&cmu_lock);
|
||||
|
||||
switch (clock) {
|
||||
case PIU_CLOCK:
|
||||
cmuclkmsk |= MSKPIU;
|
||||
break;
|
||||
case SIU_CLOCK:
|
||||
cmuclkmsk |= MSKSIU | MSKSSIU;
|
||||
break;
|
||||
case AIU_CLOCK:
|
||||
cmuclkmsk |= MSKAIU;
|
||||
break;
|
||||
case KIU_CLOCK:
|
||||
cmuclkmsk |= MSKKIU;
|
||||
break;
|
||||
case FIR_CLOCK:
|
||||
cmuclkmsk |= MSKFIR | MSKFFIR;
|
||||
break;
|
||||
case DSIU_CLOCK:
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121)
|
||||
cmuclkmsk |= MSKDSIU;
|
||||
else
|
||||
cmuclkmsk |= MSKSIU | MSKDSIU;
|
||||
break;
|
||||
case CSI_CLOCK:
|
||||
cmuclkmsk |= MSKCSI | MSKSCSI;
|
||||
break;
|
||||
case PCIU_CLOCK:
|
||||
cmuclkmsk |= MSKPCIU;
|
||||
break;
|
||||
case HSP_CLOCK:
|
||||
cmuclkmsk |= MSKSHSP;
|
||||
break;
|
||||
case PCI_CLOCK:
|
||||
cmuclkmsk |= MSKPPCIU;
|
||||
break;
|
||||
case CEU_CLOCK:
|
||||
cmuclkmsk2 |= MSKCEU;
|
||||
break;
|
||||
case ETHER0_CLOCK:
|
||||
cmuclkmsk2 |= MSKMAC0;
|
||||
break;
|
||||
case ETHER1_CLOCK:
|
||||
cmuclkmsk2 |= MSKMAC1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (clock == CEU_CLOCK || clock == ETHER0_CLOCK ||
|
||||
clock == ETHER1_CLOCK)
|
||||
cmu_write(CMUCLKMSK2, cmuclkmsk2);
|
||||
else
|
||||
cmu_write(CMUCLKMSK, cmuclkmsk);
|
||||
|
||||
spin_unlock_irq(&cmu_lock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(vr41xx_supply_clock);
|
||||
|
||||
void vr41xx_mask_clock(vr41xx_clock_t clock)
|
||||
{
|
||||
spin_lock_irq(&cmu_lock);
|
||||
|
||||
switch (clock) {
|
||||
case PIU_CLOCK:
|
||||
cmuclkmsk &= ~MSKPIU;
|
||||
break;
|
||||
case SIU_CLOCK:
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121) {
|
||||
cmuclkmsk &= ~(MSKSIU | MSKSSIU);
|
||||
} else {
|
||||
if (cmuclkmsk & MSKDSIU)
|
||||
cmuclkmsk &= ~MSKSSIU;
|
||||
else
|
||||
cmuclkmsk &= ~(MSKSIU | MSKSSIU);
|
||||
}
|
||||
break;
|
||||
case AIU_CLOCK:
|
||||
cmuclkmsk &= ~MSKAIU;
|
||||
break;
|
||||
case KIU_CLOCK:
|
||||
cmuclkmsk &= ~MSKKIU;
|
||||
break;
|
||||
case FIR_CLOCK:
|
||||
cmuclkmsk &= ~(MSKFIR | MSKFFIR);
|
||||
break;
|
||||
case DSIU_CLOCK:
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121) {
|
||||
cmuclkmsk &= ~MSKDSIU;
|
||||
} else {
|
||||
if (cmuclkmsk & MSKSSIU)
|
||||
cmuclkmsk &= ~MSKDSIU;
|
||||
else
|
||||
cmuclkmsk &= ~(MSKSIU | MSKDSIU);
|
||||
}
|
||||
break;
|
||||
case CSI_CLOCK:
|
||||
cmuclkmsk &= ~(MSKCSI | MSKSCSI);
|
||||
break;
|
||||
case PCIU_CLOCK:
|
||||
cmuclkmsk &= ~MSKPCIU;
|
||||
break;
|
||||
case HSP_CLOCK:
|
||||
cmuclkmsk &= ~MSKSHSP;
|
||||
break;
|
||||
case PCI_CLOCK:
|
||||
cmuclkmsk &= ~MSKPPCIU;
|
||||
break;
|
||||
case CEU_CLOCK:
|
||||
cmuclkmsk2 &= ~MSKCEU;
|
||||
break;
|
||||
case ETHER0_CLOCK:
|
||||
cmuclkmsk2 &= ~MSKMAC0;
|
||||
break;
|
||||
case ETHER1_CLOCK:
|
||||
cmuclkmsk2 &= ~MSKMAC1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (clock == CEU_CLOCK || clock == ETHER0_CLOCK ||
|
||||
clock == ETHER1_CLOCK)
|
||||
cmu_write(CMUCLKMSK2, cmuclkmsk2);
|
||||
else
|
||||
cmu_write(CMUCLKMSK, cmuclkmsk);
|
||||
|
||||
spin_unlock_irq(&cmu_lock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(vr41xx_mask_clock);
|
||||
|
||||
static int __init vr41xx_cmu_init(void)
|
||||
{
|
||||
unsigned long start, size;
|
||||
|
||||
switch (current_cpu_data.cputype) {
|
||||
case CPU_VR4111:
|
||||
case CPU_VR4121:
|
||||
start = CMU_TYPE1_BASE;
|
||||
size = CMU_TYPE1_SIZE;
|
||||
break;
|
||||
case CPU_VR4122:
|
||||
case CPU_VR4131:
|
||||
start = CMU_TYPE2_BASE;
|
||||
size = CMU_TYPE2_SIZE;
|
||||
break;
|
||||
case CPU_VR4133:
|
||||
start = CMU_TYPE3_BASE;
|
||||
size = CMU_TYPE3_SIZE;
|
||||
break;
|
||||
default:
|
||||
panic("Unexpected CPU of NEC VR4100 series");
|
||||
break;
|
||||
}
|
||||
|
||||
if (request_mem_region(start, size, "CMU") == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
cmu_base = ioremap(start, size);
|
||||
if (cmu_base == NULL) {
|
||||
release_mem_region(start, size);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmuclkmsk = cmu_read(CMUCLKMSK);
|
||||
if (current_cpu_data.cputype == CPU_VR4133)
|
||||
cmuclkmsk2 = cmu_read(CMUCLKMSK2);
|
||||
|
||||
spin_lock_init(&cmu_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
core_initcall(vr41xx_cmu_init);
|
455
arch/mips/vr41xx/common/giu.c
Звичайний файл
455
arch/mips/vr41xx/common/giu.c
Звичайний файл
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
* giu.c, General-purpose I/O Unit Interrupt routines for NEC VR4100 series.
|
||||
*
|
||||
* Copyright (C) 2002 MontaVista Software Inc.
|
||||
* Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
|
||||
* Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
* Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
|
||||
*
|
||||
* 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 VR4111, VR4121, VR4122 and VR4131 are supported.
|
||||
*
|
||||
* Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
* - Added support for NEC VR4133.
|
||||
* - Removed board_irq_init.
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/vr41xx/vr41xx.h>
|
||||
|
||||
#define GIUIOSELL_TYPE1 KSEG1ADDR(0x0b000100)
|
||||
#define GIUIOSELL_TYPE2 KSEG1ADDR(0x0f000140)
|
||||
|
||||
#define GIUIOSELL 0x00
|
||||
#define GIUIOSELH 0x02
|
||||
#define GIUINTSTATL 0x08
|
||||
#define GIUINTSTATH 0x0a
|
||||
#define GIUINTENL 0x0c
|
||||
#define GIUINTENH 0x0e
|
||||
#define GIUINTTYPL 0x10
|
||||
#define GIUINTTYPH 0x12
|
||||
#define GIUINTALSELL 0x14
|
||||
#define GIUINTALSELH 0x16
|
||||
#define GIUINTHTSELL 0x18
|
||||
#define GIUINTHTSELH 0x1a
|
||||
#define GIUFEDGEINHL 0x20
|
||||
#define GIUFEDGEINHH 0x22
|
||||
#define GIUREDGEINHL 0x24
|
||||
#define GIUREDGEINHH 0x26
|
||||
|
||||
static uint32_t giu_base;
|
||||
|
||||
static struct irqaction giu_cascade = {
|
||||
.handler = no_action,
|
||||
.mask = CPU_MASK_NONE,
|
||||
.name = "cascade",
|
||||
};
|
||||
|
||||
#define read_giuint(offset) readw(giu_base + (offset))
|
||||
#define write_giuint(val, offset) writew((val), giu_base + (offset))
|
||||
|
||||
#define GIUINT_HIGH_OFFSET 16
|
||||
|
||||
static inline uint16_t set_giuint(uint8_t offset, uint16_t set)
|
||||
{
|
||||
uint16_t res;
|
||||
|
||||
res = read_giuint(offset);
|
||||
res |= set;
|
||||
write_giuint(res, offset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint16_t clear_giuint(uint8_t offset, uint16_t clear)
|
||||
{
|
||||
uint16_t res;
|
||||
|
||||
res = read_giuint(offset);
|
||||
res &= ~clear;
|
||||
write_giuint(res, offset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static unsigned int startup_giuint_low_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int pin;
|
||||
|
||||
pin = GIU_IRQ_TO_PIN(irq);
|
||||
write_giuint((uint16_t)1 << pin, GIUINTSTATL);
|
||||
set_giuint(GIUINTENL, (uint16_t)1 << pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void shutdown_giuint_low_irq(unsigned int irq)
|
||||
{
|
||||
clear_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
static void enable_giuint_low_irq(unsigned int irq)
|
||||
{
|
||||
set_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
#define disable_giuint_low_irq shutdown_giuint_low_irq
|
||||
|
||||
static void ack_giuint_low_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int pin;
|
||||
|
||||
pin = GIU_IRQ_TO_PIN(irq);
|
||||
clear_giuint(GIUINTENL, (uint16_t)1 << pin);
|
||||
write_giuint((uint16_t)1 << pin, GIUINTSTATL);
|
||||
}
|
||||
|
||||
static void end_giuint_low_irq(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
||||
set_giuint(GIUINTENL, (uint16_t)1 << GIU_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type giuint_low_irq_type = {
|
||||
.typename = "GIUINTL",
|
||||
.startup = startup_giuint_low_irq,
|
||||
.shutdown = shutdown_giuint_low_irq,
|
||||
.enable = enable_giuint_low_irq,
|
||||
.disable = disable_giuint_low_irq,
|
||||
.ack = ack_giuint_low_irq,
|
||||
.end = end_giuint_low_irq,
|
||||
};
|
||||
|
||||
static unsigned int startup_giuint_high_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int pin;
|
||||
|
||||
pin = GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET);
|
||||
write_giuint((uint16_t)1 << pin, GIUINTSTATH);
|
||||
set_giuint(GIUINTENH, (uint16_t)1 << pin);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void shutdown_giuint_high_irq(unsigned int irq)
|
||||
{
|
||||
clear_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET));
|
||||
}
|
||||
|
||||
static void enable_giuint_high_irq(unsigned int irq)
|
||||
{
|
||||
set_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET));
|
||||
}
|
||||
|
||||
#define disable_giuint_high_irq shutdown_giuint_high_irq
|
||||
|
||||
static void ack_giuint_high_irq(unsigned int irq)
|
||||
{
|
||||
unsigned int pin;
|
||||
|
||||
pin = GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET);
|
||||
clear_giuint(GIUINTENH, (uint16_t)1 << pin);
|
||||
write_giuint((uint16_t)1 << pin, GIUINTSTATH);
|
||||
}
|
||||
|
||||
static void end_giuint_high_irq(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
||||
set_giuint(GIUINTENH, (uint16_t)1 << GIU_IRQ_TO_PIN(irq - GIUINT_HIGH_OFFSET));
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type giuint_high_irq_type = {
|
||||
.typename = "GIUINTH",
|
||||
.startup = startup_giuint_high_irq,
|
||||
.shutdown = shutdown_giuint_high_irq,
|
||||
.enable = enable_giuint_high_irq,
|
||||
.disable = disable_giuint_high_irq,
|
||||
.ack = ack_giuint_high_irq,
|
||||
.end = end_giuint_high_irq,
|
||||
};
|
||||
|
||||
void __init init_vr41xx_giuint_irq(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
|
||||
if (i < (GIU_IRQ_BASE + GIUINT_HIGH_OFFSET))
|
||||
irq_desc[i].handler = &giuint_low_irq_type;
|
||||
else
|
||||
irq_desc[i].handler = &giuint_high_irq_type;
|
||||
}
|
||||
|
||||
setup_irq(GIUINT_CASCADE_IRQ, &giu_cascade);
|
||||
}
|
||||
|
||||
void vr41xx_set_irq_trigger(int pin, int trigger, int hold)
|
||||
{
|
||||
uint16_t mask;
|
||||
|
||||
if (pin < GIUINT_HIGH_OFFSET) {
|
||||
mask = (uint16_t)1 << pin;
|
||||
if (trigger != TRIGGER_LEVEL) {
|
||||
set_giuint(GIUINTTYPL, mask);
|
||||
if (hold == SIGNAL_HOLD)
|
||||
set_giuint(GIUINTHTSELL, mask);
|
||||
else
|
||||
clear_giuint(GIUINTHTSELL, mask);
|
||||
if (current_cpu_data.cputype == CPU_VR4133) {
|
||||
switch (trigger) {
|
||||
case TRIGGER_EDGE_FALLING:
|
||||
set_giuint(GIUFEDGEINHL, mask);
|
||||
clear_giuint(GIUREDGEINHL, mask);
|
||||
break;
|
||||
case TRIGGER_EDGE_RISING:
|
||||
clear_giuint(GIUFEDGEINHL, mask);
|
||||
set_giuint(GIUREDGEINHL, mask);
|
||||
break;
|
||||
default:
|
||||
set_giuint(GIUFEDGEINHL, mask);
|
||||
set_giuint(GIUREDGEINHL, mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clear_giuint(GIUINTTYPL, mask);
|
||||
clear_giuint(GIUINTHTSELL, mask);
|
||||
}
|
||||
write_giuint(mask, GIUINTSTATL);
|
||||
} else {
|
||||
mask = (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET);
|
||||
if (trigger != TRIGGER_LEVEL) {
|
||||
set_giuint(GIUINTTYPH, mask);
|
||||
if (hold == SIGNAL_HOLD)
|
||||
set_giuint(GIUINTHTSELH, mask);
|
||||
else
|
||||
clear_giuint(GIUINTHTSELH, mask);
|
||||
if (current_cpu_data.cputype == CPU_VR4133) {
|
||||
switch (trigger) {
|
||||
case TRIGGER_EDGE_FALLING:
|
||||
set_giuint(GIUFEDGEINHH, mask);
|
||||
clear_giuint(GIUREDGEINHH, mask);
|
||||
break;
|
||||
case TRIGGER_EDGE_RISING:
|
||||
clear_giuint(GIUFEDGEINHH, mask);
|
||||
set_giuint(GIUREDGEINHH, mask);
|
||||
break;
|
||||
default:
|
||||
set_giuint(GIUFEDGEINHH, mask);
|
||||
set_giuint(GIUREDGEINHH, mask);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clear_giuint(GIUINTTYPH, mask);
|
||||
clear_giuint(GIUINTHTSELH, mask);
|
||||
}
|
||||
write_giuint(mask, GIUINTSTATH);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_set_irq_trigger);
|
||||
|
||||
void vr41xx_set_irq_level(int pin, int level)
|
||||
{
|
||||
uint16_t mask;
|
||||
|
||||
if (pin < GIUINT_HIGH_OFFSET) {
|
||||
mask = (uint16_t)1 << pin;
|
||||
if (level == LEVEL_HIGH)
|
||||
set_giuint(GIUINTALSELL, mask);
|
||||
else
|
||||
clear_giuint(GIUINTALSELL, mask);
|
||||
write_giuint(mask, GIUINTSTATL);
|
||||
} else {
|
||||
mask = (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET);
|
||||
if (level == LEVEL_HIGH)
|
||||
set_giuint(GIUINTALSELH, mask);
|
||||
else
|
||||
clear_giuint(GIUINTALSELH, mask);
|
||||
write_giuint(mask, GIUINTSTATH);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_set_irq_level);
|
||||
|
||||
#define GIUINT_NR_IRQS 32
|
||||
|
||||
enum {
|
||||
GIUINT_NO_CASCADE,
|
||||
GIUINT_CASCADE
|
||||
};
|
||||
|
||||
struct vr41xx_giuint_cascade {
|
||||
unsigned int flag;
|
||||
int (*get_irq_number)(int irq);
|
||||
};
|
||||
|
||||
static struct vr41xx_giuint_cascade giuint_cascade[GIUINT_NR_IRQS];
|
||||
|
||||
static int no_irq_number(int irq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int vr41xx_cascade_irq(unsigned int irq, int (*get_irq_number)(int irq))
|
||||
{
|
||||
unsigned int pin;
|
||||
int retval;
|
||||
|
||||
if (irq < GIU_IRQ(0) || irq > GIU_IRQ(31))
|
||||
return -EINVAL;
|
||||
|
||||
if(!get_irq_number)
|
||||
return -EINVAL;
|
||||
|
||||
pin = GIU_IRQ_TO_PIN(irq);
|
||||
giuint_cascade[pin].flag = GIUINT_CASCADE;
|
||||
giuint_cascade[pin].get_irq_number = get_irq_number;
|
||||
|
||||
retval = setup_irq(irq, &giu_cascade);
|
||||
if (retval != 0) {
|
||||
giuint_cascade[pin].flag = GIUINT_NO_CASCADE;
|
||||
giuint_cascade[pin].get_irq_number = no_irq_number;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_cascade_irq);
|
||||
|
||||
static inline int get_irq_pin_number(void)
|
||||
{
|
||||
uint16_t pendl, pendh, maskl, maskh;
|
||||
int i;
|
||||
|
||||
pendl = read_giuint(GIUINTSTATL);
|
||||
pendh = read_giuint(GIUINTSTATH);
|
||||
maskl = read_giuint(GIUINTENL);
|
||||
maskh = read_giuint(GIUINTENH);
|
||||
|
||||
maskl &= pendl;
|
||||
maskh &= pendh;
|
||||
|
||||
if (maskl) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (maskl & ((uint16_t)1 << i))
|
||||
return i;
|
||||
}
|
||||
} else if (maskh) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (maskh & ((uint16_t)1 << i))
|
||||
return i + GIUINT_HIGH_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
|
||||
maskl, pendl, maskh, pendh);
|
||||
|
||||
atomic_inc(&irq_err_count);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline void ack_giuint_irq(int pin)
|
||||
{
|
||||
if (pin < GIUINT_HIGH_OFFSET) {
|
||||
clear_giuint(GIUINTENL, (uint16_t)1 << pin);
|
||||
write_giuint((uint16_t)1 << pin, GIUINTSTATL);
|
||||
} else {
|
||||
pin -= GIUINT_HIGH_OFFSET;
|
||||
clear_giuint(GIUINTENH, (uint16_t)1 << pin);
|
||||
write_giuint((uint16_t)1 << pin, GIUINTSTATH);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void end_giuint_irq(int pin)
|
||||
{
|
||||
if (pin < GIUINT_HIGH_OFFSET)
|
||||
set_giuint(GIUINTENL, (uint16_t)1 << pin);
|
||||
else
|
||||
set_giuint(GIUINTENH, (uint16_t)1 << (pin - GIUINT_HIGH_OFFSET));
|
||||
}
|
||||
|
||||
void giuint_irq_dispatch(struct pt_regs *regs)
|
||||
{
|
||||
struct vr41xx_giuint_cascade *cascade;
|
||||
unsigned int giuint_irq;
|
||||
int pin;
|
||||
|
||||
pin = get_irq_pin_number();
|
||||
if (pin < 0)
|
||||
return;
|
||||
|
||||
disable_irq(GIUINT_CASCADE_IRQ);
|
||||
|
||||
cascade = &giuint_cascade[pin];
|
||||
giuint_irq = GIU_IRQ(pin);
|
||||
if (cascade->flag == GIUINT_CASCADE) {
|
||||
int irq = cascade->get_irq_number(giuint_irq);
|
||||
ack_giuint_irq(pin);
|
||||
if (irq >= 0)
|
||||
do_IRQ(irq, regs);
|
||||
end_giuint_irq(pin);
|
||||
} else {
|
||||
do_IRQ(giuint_irq, regs);
|
||||
}
|
||||
|
||||
enable_irq(GIUINT_CASCADE_IRQ);
|
||||
}
|
||||
|
||||
static int __init vr41xx_giu_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (current_cpu_data.cputype) {
|
||||
case CPU_VR4111:
|
||||
case CPU_VR4121:
|
||||
giu_base = GIUIOSELL_TYPE1;
|
||||
break;
|
||||
case CPU_VR4122:
|
||||
case CPU_VR4131:
|
||||
case CPU_VR4133:
|
||||
giu_base = GIUIOSELL_TYPE2;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "GIU: Unexpected CPU of NEC VR4100 series\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < GIUINT_NR_IRQS; i++) {
|
||||
if (i < GIUINT_HIGH_OFFSET)
|
||||
clear_giuint(GIUINTENL, (uint16_t)1 << i);
|
||||
else
|
||||
clear_giuint(GIUINTENH, (uint16_t)1 << (i - GIUINT_HIGH_OFFSET));
|
||||
giuint_cascade[i].flag = GIUINT_NO_CASCADE;
|
||||
giuint_cascade[i].get_irq_number = no_irq_number;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_initcall(vr41xx_giu_init);
|
757
arch/mips/vr41xx/common/icu.c
Звичайний файл
757
arch/mips/vr41xx/common/icu.c
Звичайний файл
@@ -0,0 +1,757 @@
|
||||
/*
|
||||
* 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>
|
||||
* Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
* Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
* - Coped with INTASSIGN of NEC VR4133.
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/irq_cpu.h>
|
||||
#include <asm/vr41xx/vr41xx.h>
|
||||
|
||||
extern asmlinkage void vr41xx_handle_interrupt(void);
|
||||
|
||||
extern void init_vr41xx_giuint_irq(void);
|
||||
extern void giuint_irq_dispatch(struct pt_regs *regs);
|
||||
|
||||
static uint32_t icu1_base;
|
||||
static uint32_t icu2_base;
|
||||
|
||||
static struct irqaction icu_cascade = {
|
||||
.handler = no_action,
|
||||
.mask = CPU_MASK_NONE,
|
||||
.name = "cascade",
|
||||
};
|
||||
|
||||
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] = {
|
||||
2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
#define SYSINT1REG_TYPE1 KSEG1ADDR(0x0b000080)
|
||||
#define SYSINT2REG_TYPE1 KSEG1ADDR(0x0b000200)
|
||||
|
||||
#define SYSINT1REG_TYPE2 KSEG1ADDR(0x0f000080)
|
||||
#define SYSINT2REG_TYPE2 KSEG1ADDR(0x0f0000a0)
|
||||
|
||||
#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 */
|
||||
|
||||
#define read_icu1(offset) readw(icu1_base + (offset))
|
||||
#define write_icu1(val, offset) writew((val), icu1_base + (offset))
|
||||
|
||||
#define read_icu2(offset) readw(icu2_base + (offset))
|
||||
#define write_icu2(val, offset) writew((val), icu2_base + (offset))
|
||||
|
||||
#define INTASSIGN_MAX 4
|
||||
#define INTASSIGN_MASK 0x0007
|
||||
|
||||
static inline uint16_t set_icu1(uint8_t offset, uint16_t set)
|
||||
{
|
||||
uint16_t res;
|
||||
|
||||
res = read_icu1(offset);
|
||||
res |= set;
|
||||
write_icu1(res, offset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint16_t clear_icu1(uint8_t offset, uint16_t clear)
|
||||
{
|
||||
uint16_t res;
|
||||
|
||||
res = read_icu1(offset);
|
||||
res &= ~clear;
|
||||
write_icu1(res, offset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint16_t set_icu2(uint8_t offset, uint16_t set)
|
||||
{
|
||||
uint16_t res;
|
||||
|
||||
res = read_icu2(offset);
|
||||
res |= set;
|
||||
write_icu2(res, offset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint16_t clear_icu2(uint8_t offset, uint16_t clear)
|
||||
{
|
||||
uint16_t res;
|
||||
|
||||
res = read_icu2(offset);
|
||||
res &= ~clear;
|
||||
write_icu2(res, offset);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*=======================================================================*/
|
||||
|
||||
void vr41xx_enable_piuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + PIU_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121) {
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
set_icu1(MPIUINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_piuint);
|
||||
|
||||
void vr41xx_disable_piuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + PIU_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121) {
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
clear_icu1(MPIUINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_piuint);
|
||||
|
||||
void vr41xx_enable_aiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + AIU_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121) {
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
set_icu1(MAIUINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_aiuint);
|
||||
|
||||
void vr41xx_disable_aiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + AIU_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121) {
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
clear_icu1(MAIUINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_aiuint);
|
||||
|
||||
void vr41xx_enable_kiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + KIU_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121) {
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
set_icu1(MKIUINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_kiuint);
|
||||
|
||||
void vr41xx_disable_kiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + KIU_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
if (current_cpu_data.cputype == CPU_VR4111 ||
|
||||
current_cpu_data.cputype == CPU_VR4121) {
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
clear_icu1(MKIUINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_kiuint);
|
||||
|
||||
void vr41xx_enable_dsiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + DSIU_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
set_icu1(MDSIUINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_dsiuint);
|
||||
|
||||
void vr41xx_disable_dsiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + DSIU_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
clear_icu1(MDSIUINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_dsiuint);
|
||||
|
||||
void vr41xx_enable_firint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + FIR_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
set_icu2(MFIRINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_firint);
|
||||
|
||||
void vr41xx_disable_firint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + FIR_IRQ;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
clear_icu2(MFIRINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_firint);
|
||||
|
||||
void vr41xx_enable_pciint(void)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + PCI_IRQ;
|
||||
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);
|
||||
write_icu2(PCIINT0, MPCIINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_pciint);
|
||||
|
||||
void vr41xx_disable_pciint(void)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + PCI_IRQ;
|
||||
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);
|
||||
write_icu2(0, MPCIINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_pciint);
|
||||
|
||||
void vr41xx_enable_scuint(void)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + SCU_IRQ;
|
||||
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);
|
||||
write_icu2(SCUINT0, MSCUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_scuint);
|
||||
|
||||
void vr41xx_disable_scuint(void)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + SCU_IRQ;
|
||||
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);
|
||||
write_icu2(0, MSCUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_scuint);
|
||||
|
||||
void vr41xx_enable_csiint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + CSI_IRQ;
|
||||
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);
|
||||
set_icu2(MCSIINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_csiint);
|
||||
|
||||
void vr41xx_disable_csiint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + CSI_IRQ;
|
||||
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);
|
||||
clear_icu2(MCSIINTREG, mask);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_csiint);
|
||||
|
||||
void vr41xx_enable_bcuint(void)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + BCU_IRQ;
|
||||
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);
|
||||
write_icu2(BCUINTR, MBCUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_enable_bcuint);
|
||||
|
||||
void vr41xx_disable_bcuint(void)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + BCU_IRQ;
|
||||
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);
|
||||
write_icu2(0, MBCUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vr41xx_disable_bcuint);
|
||||
|
||||
/*=======================================================================*/
|
||||
|
||||
static unsigned int startup_sysint1_irq(unsigned int irq)
|
||||
{
|
||||
set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
|
||||
|
||||
return 0; /* never anything pending */
|
||||
}
|
||||
|
||||
static void shutdown_sysint1_irq(unsigned int irq)
|
||||
{
|
||||
clear_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
static void enable_sysint1_irq(unsigned int irq)
|
||||
{
|
||||
set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
#define disable_sysint1_irq shutdown_sysint1_irq
|
||||
#define ack_sysint1_irq shutdown_sysint1_irq
|
||||
|
||||
static void end_sysint1_irq(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
||||
set_icu1(MSYSINT1REG, (uint16_t)1 << SYSINT1_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type sysint1_irq_type = {
|
||||
.typename = "SYSINT1",
|
||||
.startup = startup_sysint1_irq,
|
||||
.shutdown = shutdown_sysint1_irq,
|
||||
.enable = enable_sysint1_irq,
|
||||
.disable = disable_sysint1_irq,
|
||||
.ack = ack_sysint1_irq,
|
||||
.end = end_sysint1_irq,
|
||||
};
|
||||
|
||||
/*=======================================================================*/
|
||||
|
||||
static unsigned int startup_sysint2_irq(unsigned int irq)
|
||||
{
|
||||
set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
|
||||
|
||||
return 0; /* never anything pending */
|
||||
}
|
||||
|
||||
static void shutdown_sysint2_irq(unsigned int irq)
|
||||
{
|
||||
clear_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
static void enable_sysint2_irq(unsigned int irq)
|
||||
{
|
||||
set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
#define disable_sysint2_irq shutdown_sysint2_irq
|
||||
#define ack_sysint2_irq shutdown_sysint2_irq
|
||||
|
||||
static void end_sysint2_irq(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
||||
set_icu2(MSYSINT2REG, (uint16_t)1 << SYSINT2_IRQ_TO_PIN(irq));
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type sysint2_irq_type = {
|
||||
.typename = "SYSINT2",
|
||||
.startup = startup_sysint2_irq,
|
||||
.shutdown = shutdown_sysint2_irq,
|
||||
.enable = enable_sysint2_irq,
|
||||
.disable = disable_sysint2_irq,
|
||||
.ack = ack_sysint2_irq,
|
||||
.end = end_sysint2_irq,
|
||||
};
|
||||
|
||||
/*=======================================================================*/
|
||||
|
||||
static inline int set_sysint1_assign(unsigned int irq, unsigned char assign)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + irq;
|
||||
uint16_t intassign0, intassign1;
|
||||
unsigned int pin;
|
||||
|
||||
pin = SYSINT1_IRQ_TO_PIN(irq);
|
||||
|
||||
spin_lock_irq(&desc->lock);
|
||||
|
||||
intassign0 = read_icu1(INTASSIGN0);
|
||||
intassign1 = read_icu1(INTASSIGN1);
|
||||
|
||||
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;
|
||||
write_icu1(intassign0, INTASSIGN0);
|
||||
write_icu1(intassign1, INTASSIGN1);
|
||||
|
||||
spin_unlock_irq(&desc->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int set_sysint2_assign(unsigned int irq, unsigned char assign)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + irq;
|
||||
uint16_t intassign2, intassign3;
|
||||
unsigned int pin;
|
||||
|
||||
pin = SYSINT2_IRQ_TO_PIN(irq);
|
||||
|
||||
spin_lock_irq(&desc->lock);
|
||||
|
||||
intassign2 = read_icu1(INTASSIGN2);
|
||||
intassign3 = read_icu1(INTASSIGN3);
|
||||
|
||||
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;
|
||||
write_icu1(intassign2, INTASSIGN2);
|
||||
write_icu1(intassign3, INTASSIGN3);
|
||||
|
||||
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);
|
||||
|
||||
/*=======================================================================*/
|
||||
|
||||
asmlinkage void irq_dispatch(unsigned char intnum, struct pt_regs *regs)
|
||||
{
|
||||
uint16_t pend1, pend2;
|
||||
uint16_t mask1, mask2;
|
||||
int i;
|
||||
|
||||
pend1 = read_icu1(SYSINT1REG);
|
||||
mask1 = read_icu1(MSYSINT1REG);
|
||||
|
||||
pend2 = read_icu2(SYSINT2REG);
|
||||
mask2 = read_icu2(MSYSINT2REG);
|
||||
|
||||
mask1 &= pend1;
|
||||
mask2 &= pend2;
|
||||
|
||||
if (mask1) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (intnum == sysint1_assign[i] &&
|
||||
(mask1 & ((uint16_t)1 << i))) {
|
||||
if (i == 8)
|
||||
giuint_irq_dispatch(regs);
|
||||
else
|
||||
do_IRQ(SYSINT1_IRQ(i), regs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mask2) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (intnum == sysint2_assign[i] &&
|
||||
(mask2 & ((uint16_t)1 << i))) {
|
||||
do_IRQ(SYSINT2_IRQ(i), regs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_ERR "spurious ICU interrupt: %04x,%04x\n", pend1, pend2);
|
||||
|
||||
atomic_inc(&irq_err_count);
|
||||
}
|
||||
|
||||
/*=======================================================================*/
|
||||
|
||||
static int __init vr41xx_icu_init(void)
|
||||
{
|
||||
switch (current_cpu_data.cputype) {
|
||||
case CPU_VR4111:
|
||||
case CPU_VR4121:
|
||||
icu1_base = SYSINT1REG_TYPE1;
|
||||
icu2_base = SYSINT2REG_TYPE1;
|
||||
break;
|
||||
case CPU_VR4122:
|
||||
case CPU_VR4131:
|
||||
case CPU_VR4133:
|
||||
icu1_base = SYSINT1REG_TYPE2;
|
||||
icu2_base = SYSINT2REG_TYPE2;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "ICU: Unexpected CPU of NEC VR4100 series\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
write_icu1(0, MSYSINT1REG);
|
||||
write_icu1(0xffff, MGIUINTLREG);
|
||||
|
||||
write_icu2(0, MSYSINT2REG);
|
||||
write_icu2(0xffff, MGIUINTHREG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_initcall(vr41xx_icu_init);
|
||||
|
||||
/*=======================================================================*/
|
||||
|
||||
static inline void init_vr41xx_icu_irq(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = SYSINT1_IRQ_BASE; i <= SYSINT1_IRQ_LAST; i++)
|
||||
irq_desc[i].handler = &sysint1_irq_type;
|
||||
|
||||
for (i = SYSINT2_IRQ_BASE; i <= SYSINT2_IRQ_LAST; i++)
|
||||
irq_desc[i].handler = &sysint2_irq_type;
|
||||
|
||||
setup_irq(INT0_CASCADE_IRQ, &icu_cascade);
|
||||
setup_irq(INT1_CASCADE_IRQ, &icu_cascade);
|
||||
setup_irq(INT2_CASCADE_IRQ, &icu_cascade);
|
||||
setup_irq(INT3_CASCADE_IRQ, &icu_cascade);
|
||||
setup_irq(INT4_CASCADE_IRQ, &icu_cascade);
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
|
||||
init_vr41xx_icu_irq();
|
||||
init_vr41xx_giuint_irq();
|
||||
|
||||
set_except_vector(0, vr41xx_handle_interrupt);
|
||||
}
|
85
arch/mips/vr41xx/common/init.c
Звичайний файл
85
arch/mips/vr41xx/common/init.c
Звичайний файл
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* init.c, Common initialization routines for NEC VR4100 series.
|
||||
*
|
||||
* Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/vr41xx/vr41xx.h>
|
||||
|
||||
#define IO_MEM_RESOURCE_START 0UL
|
||||
#define IO_MEM_RESOURCE_END 0x1fffffffUL
|
||||
|
||||
static void __init iomem_resource_init(void)
|
||||
{
|
||||
iomem_resource.start = IO_MEM_RESOURCE_START;
|
||||
iomem_resource.end = IO_MEM_RESOURCE_END;
|
||||
}
|
||||
|
||||
static void __init setup_timer_frequency(void)
|
||||
{
|
||||
unsigned long tclock;
|
||||
|
||||
tclock = vr41xx_get_tclock_frequency();
|
||||
if (current_cpu_data.processor_id == PRID_VR4131_REV2_0 ||
|
||||
current_cpu_data.processor_id == PRID_VR4131_REV2_1)
|
||||
mips_hpt_frequency = tclock / 2;
|
||||
else
|
||||
mips_hpt_frequency = tclock / 4;
|
||||
}
|
||||
|
||||
static void __init setup_timer_irq(struct irqaction *irq)
|
||||
{
|
||||
setup_irq(TIMER_IRQ, irq);
|
||||
}
|
||||
|
||||
static void __init timer_init(void)
|
||||
{
|
||||
board_time_init = setup_timer_frequency;
|
||||
board_timer_setup = setup_timer_irq;
|
||||
}
|
||||
|
||||
void __init prom_init(void)
|
||||
{
|
||||
int argc, i;
|
||||
char **argv;
|
||||
|
||||
argc = fw_arg0;
|
||||
argv = (char **)fw_arg1;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
strcat(arcs_cmdline, argv[i]);
|
||||
if (i < (argc - 1))
|
||||
strcat(arcs_cmdline, " ");
|
||||
}
|
||||
|
||||
vr41xx_calculate_clock_frequency();
|
||||
|
||||
timer_init();
|
||||
|
||||
iomem_resource_init();
|
||||
}
|
||||
|
||||
unsigned long __init prom_free_prom_memory (void)
|
||||
{
|
||||
return 0UL;
|
||||
}
|
114
arch/mips/vr41xx/common/int-handler.S
Звичайний файл
114
arch/mips/vr41xx/common/int-handler.S
Звичайний файл
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* FILE NAME
|
||||
* arch/mips/vr41xx/common/int-handler.S
|
||||
*
|
||||
* BRIEF MODULE DESCRIPTION
|
||||
* Interrupt dispatcher for the NEC VR4100 series.
|
||||
*
|
||||
* Author: Yoichi Yuasa
|
||||
* yyuasa@mvista.com or source@mvista.com
|
||||
*
|
||||
* Copyright 2001 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* 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.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
/*
|
||||
* Changes:
|
||||
* MontaVista Software Inc. <yyuasa@mvista.com> or <source@mvista.com>
|
||||
* - New creation, NEC VR4100 series are supported.
|
||||
*
|
||||
* Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
* - Coped with INTASSIGN of NEC VR4133.
|
||||
*/
|
||||
#include <asm/asm.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/stackframe.h>
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
|
||||
.align 5
|
||||
NESTED(vr41xx_handle_interrupt, PT_SIZE, ra)
|
||||
.set noat
|
||||
SAVE_ALL
|
||||
CLI
|
||||
.set at
|
||||
.set noreorder
|
||||
|
||||
/*
|
||||
* Get the pending interrupts
|
||||
*/
|
||||
mfc0 t0, CP0_CAUSE
|
||||
mfc0 t1, CP0_STATUS
|
||||
andi t0, 0xff00
|
||||
and t0, t0, t1
|
||||
|
||||
andi t1, t0, CAUSEF_IP7 # MIPS timer interrupt
|
||||
bnez t1, handle_irq
|
||||
li a0, 7
|
||||
|
||||
andi t1, t0, 0x7800 # check for Int1-4
|
||||
beqz t1, 1f
|
||||
|
||||
andi t1, t0, CAUSEF_IP3 # check for Int1
|
||||
bnez t1, handle_int
|
||||
li a0, 1
|
||||
|
||||
andi t1, t0, CAUSEF_IP4 # check for Int2
|
||||
bnez t1, handle_int
|
||||
li a0, 2
|
||||
|
||||
andi t1, t0, CAUSEF_IP5 # check for Int3
|
||||
bnez t1, handle_int
|
||||
li a0, 3
|
||||
|
||||
andi t1, t0, CAUSEF_IP6 # check for Int4
|
||||
bnez t1, handle_int
|
||||
li a0, 4
|
||||
|
||||
1:
|
||||
andi t1, t0, CAUSEF_IP2 # check for Int0
|
||||
bnez t1, handle_int
|
||||
li a0, 0
|
||||
|
||||
andi t1, t0, CAUSEF_IP0 # check for IP0
|
||||
bnez t1, handle_irq
|
||||
li a0, 0
|
||||
|
||||
andi t1, t0, CAUSEF_IP1 # check for IP1
|
||||
bnez t1, handle_irq
|
||||
li a0, 1
|
||||
|
||||
j spurious_interrupt
|
||||
nop
|
||||
|
||||
handle_int:
|
||||
jal irq_dispatch
|
||||
move a1, sp
|
||||
j ret_from_irq
|
||||
nop
|
||||
|
||||
handle_irq:
|
||||
jal do_IRQ
|
||||
move a1, sp
|
||||
j ret_from_irq
|
||||
END(vr41xx_handle_interrupt)
|
81
arch/mips/vr41xx/common/pmu.c
Звичайний файл
81
arch/mips/vr41xx/common/pmu.c
Звичайний файл
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* pmu.c, Power Management Unit routines for NEC VR4100 series.
|
||||
*
|
||||
* Copyright (C) 2003-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#define PMUCNT2REG KSEG1ADDR(0x0f0000c6)
|
||||
#define SOFTRST 0x0010
|
||||
|
||||
static inline void software_reset(void)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
switch (current_cpu_data.cputype) {
|
||||
case CPU_VR4122:
|
||||
case CPU_VR4131:
|
||||
case CPU_VR4133:
|
||||
val = readw(PMUCNT2REG);
|
||||
val |= SOFTRST;
|
||||
writew(val, PMUCNT2REG);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void vr41xx_restart(char *command)
|
||||
{
|
||||
local_irq_disable();
|
||||
software_reset();
|
||||
printk(KERN_NOTICE "\nYou can reset your system\n");
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
static void vr41xx_halt(void)
|
||||
{
|
||||
local_irq_disable();
|
||||
printk(KERN_NOTICE "\nYou can turn off the power supply\n");
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
static void vr41xx_power_off(void)
|
||||
{
|
||||
local_irq_disable();
|
||||
printk(KERN_NOTICE "\nYou can turn off the power supply\n");
|
||||
while (1) ;
|
||||
}
|
||||
|
||||
static int __init vr41xx_pmu_init(void)
|
||||
{
|
||||
_machine_restart = vr41xx_restart;
|
||||
_machine_halt = vr41xx_halt;
|
||||
_machine_power_off = vr41xx_power_off;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
early_initcall(vr41xx_pmu_init);
|
581
arch/mips/vr41xx/common/vrc4173.c
Звичайний файл
581
arch/mips/vr41xx/common/vrc4173.c
Звичайний файл
@@ -0,0 +1,581 @@
|
||||
/*
|
||||
* vrc4173.c, NEC VRC4173 base driver for NEC VR4122/VR4131.
|
||||
*
|
||||
* Copyright (C) 2001-2003 MontaVista Software Inc.
|
||||
* Author: Yoichi Yuasa <yyuasa@mvista.com, or source@mvista.com>
|
||||
* Copyright (C) 2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp>
|
||||
* Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/vr41xx/vr41xx.h>
|
||||
#include <asm/vr41xx/vrc4173.h>
|
||||
|
||||
MODULE_DESCRIPTION("NEC VRC4173 base driver for NEC VR4122/4131");
|
||||
MODULE_AUTHOR("Yoichi Yuasa <yyuasa@mvista.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define VRC4173_CMUCLKMSK 0x040
|
||||
#define MSKPIU 0x0001
|
||||
#define MSKKIU 0x0002
|
||||
#define MSKAIU 0x0004
|
||||
#define MSKPS2CH1 0x0008
|
||||
#define MSKPS2CH2 0x0010
|
||||
#define MSKUSB 0x0020
|
||||
#define MSKCARD1 0x0040
|
||||
#define MSKCARD2 0x0080
|
||||
#define MSKAC97 0x0100
|
||||
#define MSK48MUSB 0x0400
|
||||
#define MSK48MPIN 0x0800
|
||||
#define MSK48MOSC 0x1000
|
||||
#define VRC4173_CMUSRST 0x042
|
||||
#define USBRST 0x0001
|
||||
#define CARD1RST 0x0002
|
||||
#define CARD2RST 0x0004
|
||||
#define AC97RST 0x0008
|
||||
|
||||
#define VRC4173_SYSINT1REG 0x060
|
||||
#define VRC4173_MSYSINT1REG 0x06c
|
||||
#define VRC4173_MPIUINTREG 0x06e
|
||||
#define VRC4173_MAIUINTREG 0x070
|
||||
#define VRC4173_MKIUINTREG 0x072
|
||||
|
||||
#define VRC4173_SELECTREG 0x09e
|
||||
#define SEL3 0x0008
|
||||
#define SEL2 0x0004
|
||||
#define SEL1 0x0002
|
||||
#define SEL0 0x0001
|
||||
|
||||
static struct pci_device_id vrc4173_id_table[] __devinitdata = {
|
||||
{ .vendor = PCI_VENDOR_ID_NEC,
|
||||
.device = PCI_DEVICE_ID_NEC_VRC4173,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID, },
|
||||
{ .vendor = 0, },
|
||||
};
|
||||
|
||||
unsigned long vrc4173_io_offset = 0;
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_io_offset);
|
||||
|
||||
static int vrc4173_initialized;
|
||||
static uint16_t vrc4173_cmuclkmsk;
|
||||
static uint16_t vrc4173_selectreg;
|
||||
static spinlock_t vrc4173_cmu_lock;
|
||||
static spinlock_t vrc4173_giu_lock;
|
||||
|
||||
static inline void set_cmusrst(uint16_t val)
|
||||
{
|
||||
uint16_t cmusrst;
|
||||
|
||||
cmusrst = vrc4173_inw(VRC4173_CMUSRST);
|
||||
cmusrst |= val;
|
||||
vrc4173_outw(cmusrst, VRC4173_CMUSRST);
|
||||
}
|
||||
|
||||
static inline void clear_cmusrst(uint16_t val)
|
||||
{
|
||||
uint16_t cmusrst;
|
||||
|
||||
cmusrst = vrc4173_inw(VRC4173_CMUSRST);
|
||||
cmusrst &= ~val;
|
||||
vrc4173_outw(cmusrst, VRC4173_CMUSRST);
|
||||
}
|
||||
|
||||
void vrc4173_supply_clock(vrc4173_clock_t clock)
|
||||
{
|
||||
if (vrc4173_initialized) {
|
||||
spin_lock_irq(&vrc4173_cmu_lock);
|
||||
|
||||
switch (clock) {
|
||||
case VRC4173_PIU_CLOCK:
|
||||
vrc4173_cmuclkmsk |= MSKPIU;
|
||||
break;
|
||||
case VRC4173_KIU_CLOCK:
|
||||
vrc4173_cmuclkmsk |= MSKKIU;
|
||||
break;
|
||||
case VRC4173_AIU_CLOCK:
|
||||
vrc4173_cmuclkmsk |= MSKAIU;
|
||||
break;
|
||||
case VRC4173_PS2_CH1_CLOCK:
|
||||
vrc4173_cmuclkmsk |= MSKPS2CH1;
|
||||
break;
|
||||
case VRC4173_PS2_CH2_CLOCK:
|
||||
vrc4173_cmuclkmsk |= MSKPS2CH2;
|
||||
break;
|
||||
case VRC4173_USBU_PCI_CLOCK:
|
||||
set_cmusrst(USBRST);
|
||||
vrc4173_cmuclkmsk |= MSKUSB;
|
||||
break;
|
||||
case VRC4173_CARDU1_PCI_CLOCK:
|
||||
set_cmusrst(CARD1RST);
|
||||
vrc4173_cmuclkmsk |= MSKCARD1;
|
||||
break;
|
||||
case VRC4173_CARDU2_PCI_CLOCK:
|
||||
set_cmusrst(CARD2RST);
|
||||
vrc4173_cmuclkmsk |= MSKCARD2;
|
||||
break;
|
||||
case VRC4173_AC97U_PCI_CLOCK:
|
||||
set_cmusrst(AC97RST);
|
||||
vrc4173_cmuclkmsk |= MSKAC97;
|
||||
break;
|
||||
case VRC4173_USBU_48MHz_CLOCK:
|
||||
set_cmusrst(USBRST);
|
||||
vrc4173_cmuclkmsk |= MSK48MUSB;
|
||||
break;
|
||||
case VRC4173_EXT_48MHz_CLOCK:
|
||||
if (vrc4173_cmuclkmsk & MSK48MOSC)
|
||||
vrc4173_cmuclkmsk |= MSK48MPIN;
|
||||
else
|
||||
printk(KERN_WARNING
|
||||
"vrc4173_supply_clock: "
|
||||
"Please supply VRC4173_48MHz_CLOCK first "
|
||||
"rather than VRC4173_EXT_48MHz_CLOCK.\n");
|
||||
break;
|
||||
case VRC4173_48MHz_CLOCK:
|
||||
vrc4173_cmuclkmsk |= MSK48MOSC;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING
|
||||
"vrc4173_supply_clock: Invalid CLOCK value %u\n", clock);
|
||||
break;
|
||||
}
|
||||
|
||||
vrc4173_outw(vrc4173_cmuclkmsk, VRC4173_CMUCLKMSK);
|
||||
|
||||
switch (clock) {
|
||||
case VRC4173_USBU_PCI_CLOCK:
|
||||
case VRC4173_USBU_48MHz_CLOCK:
|
||||
clear_cmusrst(USBRST);
|
||||
break;
|
||||
case VRC4173_CARDU1_PCI_CLOCK:
|
||||
clear_cmusrst(CARD1RST);
|
||||
break;
|
||||
case VRC4173_CARDU2_PCI_CLOCK:
|
||||
clear_cmusrst(CARD2RST);
|
||||
break;
|
||||
case VRC4173_AC97U_PCI_CLOCK:
|
||||
clear_cmusrst(AC97RST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&vrc4173_cmu_lock);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_supply_clock);
|
||||
|
||||
void vrc4173_mask_clock(vrc4173_clock_t clock)
|
||||
{
|
||||
if (vrc4173_initialized) {
|
||||
spin_lock_irq(&vrc4173_cmu_lock);
|
||||
|
||||
switch (clock) {
|
||||
case VRC4173_PIU_CLOCK:
|
||||
vrc4173_cmuclkmsk &= ~MSKPIU;
|
||||
break;
|
||||
case VRC4173_KIU_CLOCK:
|
||||
vrc4173_cmuclkmsk &= ~MSKKIU;
|
||||
break;
|
||||
case VRC4173_AIU_CLOCK:
|
||||
vrc4173_cmuclkmsk &= ~MSKAIU;
|
||||
break;
|
||||
case VRC4173_PS2_CH1_CLOCK:
|
||||
vrc4173_cmuclkmsk &= ~MSKPS2CH1;
|
||||
break;
|
||||
case VRC4173_PS2_CH2_CLOCK:
|
||||
vrc4173_cmuclkmsk &= ~MSKPS2CH2;
|
||||
break;
|
||||
case VRC4173_USBU_PCI_CLOCK:
|
||||
set_cmusrst(USBRST);
|
||||
vrc4173_cmuclkmsk &= ~MSKUSB;
|
||||
break;
|
||||
case VRC4173_CARDU1_PCI_CLOCK:
|
||||
set_cmusrst(CARD1RST);
|
||||
vrc4173_cmuclkmsk &= ~MSKCARD1;
|
||||
break;
|
||||
case VRC4173_CARDU2_PCI_CLOCK:
|
||||
set_cmusrst(CARD2RST);
|
||||
vrc4173_cmuclkmsk &= ~MSKCARD2;
|
||||
break;
|
||||
case VRC4173_AC97U_PCI_CLOCK:
|
||||
set_cmusrst(AC97RST);
|
||||
vrc4173_cmuclkmsk &= ~MSKAC97;
|
||||
break;
|
||||
case VRC4173_USBU_48MHz_CLOCK:
|
||||
set_cmusrst(USBRST);
|
||||
vrc4173_cmuclkmsk &= ~MSK48MUSB;
|
||||
break;
|
||||
case VRC4173_EXT_48MHz_CLOCK:
|
||||
vrc4173_cmuclkmsk &= ~MSK48MPIN;
|
||||
break;
|
||||
case VRC4173_48MHz_CLOCK:
|
||||
vrc4173_cmuclkmsk &= ~MSK48MOSC;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "vrc4173_mask_clock: Invalid CLOCK value %u\n", clock);
|
||||
break;
|
||||
}
|
||||
|
||||
vrc4173_outw(vrc4173_cmuclkmsk, VRC4173_CMUCLKMSK);
|
||||
|
||||
switch (clock) {
|
||||
case VRC4173_USBU_PCI_CLOCK:
|
||||
case VRC4173_USBU_48MHz_CLOCK:
|
||||
clear_cmusrst(USBRST);
|
||||
break;
|
||||
case VRC4173_CARDU1_PCI_CLOCK:
|
||||
clear_cmusrst(CARD1RST);
|
||||
break;
|
||||
case VRC4173_CARDU2_PCI_CLOCK:
|
||||
clear_cmusrst(CARD2RST);
|
||||
break;
|
||||
case VRC4173_AC97U_PCI_CLOCK:
|
||||
clear_cmusrst(AC97RST);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&vrc4173_cmu_lock);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_mask_clock);
|
||||
|
||||
static inline void vrc4173_cmu_init(void)
|
||||
{
|
||||
vrc4173_cmuclkmsk = vrc4173_inw(VRC4173_CMUCLKMSK);
|
||||
|
||||
spin_lock_init(&vrc4173_cmu_lock);
|
||||
}
|
||||
|
||||
void vrc4173_select_function(vrc4173_function_t function)
|
||||
{
|
||||
if (vrc4173_initialized) {
|
||||
spin_lock_irq(&vrc4173_giu_lock);
|
||||
|
||||
switch(function) {
|
||||
case PS2_CHANNEL1:
|
||||
vrc4173_selectreg |= SEL2;
|
||||
break;
|
||||
case PS2_CHANNEL2:
|
||||
vrc4173_selectreg |= SEL1;
|
||||
break;
|
||||
case TOUCHPANEL:
|
||||
vrc4173_selectreg &= SEL2 | SEL1 | SEL0;
|
||||
break;
|
||||
case KEYBOARD_8SCANLINES:
|
||||
vrc4173_selectreg &= SEL3 | SEL2 | SEL1;
|
||||
break;
|
||||
case KEYBOARD_10SCANLINES:
|
||||
vrc4173_selectreg &= SEL3 | SEL2;
|
||||
break;
|
||||
case KEYBOARD_12SCANLINES:
|
||||
vrc4173_selectreg &= SEL3;
|
||||
break;
|
||||
case GPIO_0_15PINS:
|
||||
vrc4173_selectreg |= SEL0;
|
||||
break;
|
||||
case GPIO_16_20PINS:
|
||||
vrc4173_selectreg |= SEL3;
|
||||
break;
|
||||
}
|
||||
|
||||
vrc4173_outw(vrc4173_selectreg, VRC4173_SELECTREG);
|
||||
|
||||
spin_unlock_irq(&vrc4173_giu_lock);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_select_function);
|
||||
|
||||
static inline void vrc4173_giu_init(void)
|
||||
{
|
||||
vrc4173_selectreg = vrc4173_inw(VRC4173_SELECTREG);
|
||||
|
||||
spin_lock_init(&vrc4173_giu_lock);
|
||||
}
|
||||
|
||||
void vrc4173_enable_piuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ;
|
||||
unsigned long flags;
|
||||
uint16_t val;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
val = vrc4173_inw(VRC4173_MPIUINTREG);
|
||||
val |= mask;
|
||||
vrc4173_outw(val, VRC4173_MPIUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_enable_piuint);
|
||||
|
||||
void vrc4173_disable_piuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + VRC4173_PIU_IRQ;
|
||||
unsigned long flags;
|
||||
uint16_t val;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
val = vrc4173_inw(VRC4173_MPIUINTREG);
|
||||
val &= ~mask;
|
||||
vrc4173_outw(val, VRC4173_MPIUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_disable_piuint);
|
||||
|
||||
void vrc4173_enable_aiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ;
|
||||
unsigned long flags;
|
||||
uint16_t val;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
val = vrc4173_inw(VRC4173_MAIUINTREG);
|
||||
val |= mask;
|
||||
vrc4173_outw(val, VRC4173_MAIUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_enable_aiuint);
|
||||
|
||||
void vrc4173_disable_aiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + VRC4173_AIU_IRQ;
|
||||
unsigned long flags;
|
||||
uint16_t val;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
val = vrc4173_inw(VRC4173_MAIUINTREG);
|
||||
val &= ~mask;
|
||||
vrc4173_outw(val, VRC4173_MAIUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_disable_aiuint);
|
||||
|
||||
void vrc4173_enable_kiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ;
|
||||
unsigned long flags;
|
||||
uint16_t val;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
val = vrc4173_inw(VRC4173_MKIUINTREG);
|
||||
val |= mask;
|
||||
vrc4173_outw(val, VRC4173_MKIUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_enable_kiuint);
|
||||
|
||||
void vrc4173_disable_kiuint(uint16_t mask)
|
||||
{
|
||||
irq_desc_t *desc = irq_desc + VRC4173_KIU_IRQ;
|
||||
unsigned long flags;
|
||||
uint16_t val;
|
||||
|
||||
spin_lock_irqsave(&desc->lock, flags);
|
||||
val = vrc4173_inw(VRC4173_MKIUINTREG);
|
||||
val &= ~mask;
|
||||
vrc4173_outw(val, VRC4173_MKIUINTREG);
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vrc4173_disable_kiuint);
|
||||
|
||||
static void enable_vrc4173_irq(unsigned int irq)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
val = vrc4173_inw(VRC4173_MSYSINT1REG);
|
||||
val |= (uint16_t)1 << (irq - VRC4173_IRQ_BASE);
|
||||
vrc4173_outw(val, VRC4173_MSYSINT1REG);
|
||||
}
|
||||
|
||||
static void disable_vrc4173_irq(unsigned int irq)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
val = vrc4173_inw(VRC4173_MSYSINT1REG);
|
||||
val &= ~((uint16_t)1 << (irq - VRC4173_IRQ_BASE));
|
||||
vrc4173_outw(val, VRC4173_MSYSINT1REG);
|
||||
}
|
||||
|
||||
static unsigned int startup_vrc4173_irq(unsigned int irq)
|
||||
{
|
||||
enable_vrc4173_irq(irq);
|
||||
return 0; /* never anything pending */
|
||||
}
|
||||
|
||||
#define shutdown_vrc4173_irq disable_vrc4173_irq
|
||||
#define ack_vrc4173_irq disable_vrc4173_irq
|
||||
|
||||
static void end_vrc4173_irq(unsigned int irq)
|
||||
{
|
||||
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
|
||||
enable_vrc4173_irq(irq);
|
||||
}
|
||||
|
||||
static struct hw_interrupt_type vrc4173_irq_type = {
|
||||
.typename = "VRC4173",
|
||||
.startup = startup_vrc4173_irq,
|
||||
.shutdown = shutdown_vrc4173_irq,
|
||||
.enable = enable_vrc4173_irq,
|
||||
.disable = disable_vrc4173_irq,
|
||||
.ack = ack_vrc4173_irq,
|
||||
.end = end_vrc4173_irq,
|
||||
};
|
||||
|
||||
static int vrc4173_get_irq_number(int irq)
|
||||
{
|
||||
uint16_t status, mask;
|
||||
int i;
|
||||
|
||||
status = vrc4173_inw(VRC4173_SYSINT1REG);
|
||||
mask = vrc4173_inw(VRC4173_MSYSINT1REG);
|
||||
|
||||
status &= mask;
|
||||
if (status) {
|
||||
for (i = 0; i < 16; i++)
|
||||
if (status & (0x0001 << i))
|
||||
return VRC4173_IRQ(i);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int vrc4173_icu_init(int cascade_irq)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cascade_irq < GIU_IRQ(0) || cascade_irq > GIU_IRQ(15))
|
||||
return -EINVAL;
|
||||
|
||||
vrc4173_outw(0, VRC4173_MSYSINT1REG);
|
||||
|
||||
vr41xx_set_irq_trigger(GIU_IRQ_TO_PIN(cascade_irq), TRIGGER_LEVEL, SIGNAL_THROUGH);
|
||||
vr41xx_set_irq_level(GIU_IRQ_TO_PIN(cascade_irq), LEVEL_LOW);
|
||||
|
||||
for (i = VRC4173_IRQ_BASE; i <= VRC4173_IRQ_LAST; i++)
|
||||
irq_desc[i].handler = &vrc4173_irq_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit vrc4173_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
unsigned long start, flags;
|
||||
int err;
|
||||
|
||||
err = pci_enable_device(dev);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "vrc4173: Failed to enable PCI device, aborting\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
pci_set_master(dev);
|
||||
|
||||
start = pci_resource_start(dev, 0);
|
||||
if (start == 0) {
|
||||
printk(KERN_ERR "vrc4173:No such PCI I/O resource, aborting\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
flags = pci_resource_flags(dev, 0);
|
||||
if ((flags & IORESOURCE_IO) == 0) {
|
||||
printk(KERN_ERR "vrc4173: No such PCI I/O resource, aborting\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
err = pci_request_regions(dev, "NEC VRC4173");
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "vrc4173: PCI resources are busy, aborting\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
set_vrc4173_io_offset(start);
|
||||
|
||||
vrc4173_cmu_init();
|
||||
vrc4173_giu_init();
|
||||
|
||||
err = vrc4173_icu_init(dev->irq);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "vrc4173: Invalid IRQ %d, aborting\n", dev->irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = vr41xx_cascade_irq(dev->irq, vrc4173_get_irq_number);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "vrc4173: IRQ resource %d is busy, aborting\n", dev->irq);
|
||||
return err;
|
||||
}
|
||||
|
||||
printk(KERN_INFO
|
||||
"NEC VRC4173 at 0x%#08lx, IRQ is cascaded to %d\n", start, dev->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vrc4173_remove(struct pci_dev *dev)
|
||||
{
|
||||
free_irq(dev->irq, NULL);
|
||||
|
||||
pci_release_regions(dev);
|
||||
}
|
||||
|
||||
static struct pci_driver vrc4173_driver = {
|
||||
.name = "NEC VRC4173",
|
||||
.probe = vrc4173_probe,
|
||||
.remove = vrc4173_remove,
|
||||
.id_table = vrc4173_id_table,
|
||||
};
|
||||
|
||||
static int __devinit vrc4173_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pci_module_init(&vrc4173_driver);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
vrc4173_initialized = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __devexit vrc4173_exit(void)
|
||||
{
|
||||
vrc4173_initialized = 0;
|
||||
|
||||
pci_unregister_driver(&vrc4173_driver);
|
||||
}
|
||||
|
||||
module_init(vrc4173_init);
|
||||
module_exit(vrc4173_exit);
|
Посилання в новій задачі
Заблокувати користувача