-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds functionality for the on-board ILSEL IRQs that chain IRL mode events. Many on-board devices (ethernet, usb, etc.) rely on ILSEL IRQs directly. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
- Loading branch information
Paul Mundt
committed
Sep 21, 2007
1 parent
94807a3
commit fef9608
Showing
3 changed files
with
197 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
obj-y += setup.o | ||
obj-y += setup.o ilsel.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
/* | ||
* arch/sh/boards/renesas/x3proto/ilsel.c | ||
* | ||
* Helper routines for SH-X3 proto board ILSEL. | ||
* | ||
* Copyright (C) 2007 Paul Mundt | ||
* | ||
* This file is subject to the terms and conditions of the GNU General Public | ||
* License. See the file "COPYING" in the main directory of this archive | ||
* for more details. | ||
*/ | ||
#include <linux/init.h> | ||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/bitmap.h> | ||
#include <linux/io.h> | ||
#include <asm/ilsel.h> | ||
|
||
/* | ||
* ILSEL is split across: | ||
* | ||
* ILSEL0 - 0xb8100004 [ Levels 1 - 4 ] | ||
* ILSEL1 - 0xb8100006 [ Levels 5 - 8 ] | ||
* ILSEL2 - 0xb8100008 [ Levels 9 - 12 ] | ||
* ILSEL3 - 0xb810000a [ Levels 13 - 15 ] | ||
* | ||
* With each level being relative to an ilsel_source_t. | ||
*/ | ||
#define ILSEL_BASE 0xb8100004 | ||
#define ILSEL_LEVELS 15 | ||
|
||
/* | ||
* ILSEL level map, in descending order from the highest level down. | ||
* | ||
* Supported levels are 1 - 15 spread across ILSEL0 - ILSEL4, mapping | ||
* directly to IRLs. As the IRQs are numbered in reverse order relative | ||
* to the interrupt level, the level map is carefully managed to ensure a | ||
* 1:1 mapping between the bit position and the IRQ number. | ||
* | ||
* This careful constructions allows ilsel_enable*() to be referenced | ||
* directly for hooking up an ILSEL set and getting back an IRQ which can | ||
* subsequently be used for internal accounting in the (optional) disable | ||
* path. | ||
*/ | ||
static unsigned long ilsel_level_map; | ||
|
||
static inline unsigned int ilsel_offset(unsigned int bit) | ||
{ | ||
return ILSEL_LEVELS - bit - 1; | ||
} | ||
|
||
static inline unsigned long mk_ilsel_addr(unsigned int bit) | ||
{ | ||
return ILSEL_BASE + ((ilsel_offset(bit) >> 1) & ~0x1); | ||
} | ||
|
||
static inline unsigned int mk_ilsel_shift(unsigned int bit) | ||
{ | ||
return (ilsel_offset(bit) & 0x3) << 2; | ||
} | ||
|
||
static void __ilsel_enable(ilsel_source_t set, unsigned int bit) | ||
{ | ||
unsigned int tmp, shift; | ||
unsigned long addr; | ||
|
||
addr = mk_ilsel_addr(bit); | ||
shift = mk_ilsel_shift(bit); | ||
|
||
pr_debug("%s: bit#%d: addr - 0x%08lx (shift %d, set %d)\n", | ||
__FUNCTION__, bit, addr, shift, set); | ||
|
||
tmp = ctrl_inw(addr); | ||
tmp &= ~(0xf << shift); | ||
tmp |= set << shift; | ||
ctrl_outw(tmp, addr); | ||
} | ||
|
||
/** | ||
* ilsel_enable - Enable an ILSEL set. | ||
* @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h). | ||
* | ||
* Enables a given non-aliased ILSEL source (<= ILSEL_KEY) at the highest | ||
* available interrupt level. Callers should take care to order callsites | ||
* noting descending interrupt levels. Aliasing FPGA and external board | ||
* IRQs need to use ilsel_enable_fixed(). | ||
* | ||
* The return value is an IRQ number that can later be taken down with | ||
* ilsel_disable(). | ||
*/ | ||
int ilsel_enable(ilsel_source_t set) | ||
{ | ||
unsigned int bit; | ||
|
||
/* Aliased sources must use ilsel_enable_fixed() */ | ||
BUG_ON(set > ILSEL_KEY); | ||
|
||
do { | ||
bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS); | ||
} while (test_and_set_bit(bit, &ilsel_level_map)); | ||
|
||
__ilsel_enable(set, bit); | ||
|
||
return bit; | ||
} | ||
EXPORT_SYMBOL_GPL(ilsel_enable); | ||
|
||
/** | ||
* ilsel_enable_fixed - Enable an ILSEL set at a fixed interrupt level | ||
* @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h). | ||
* @level: Interrupt level (1 - 15) | ||
* | ||
* Enables a given ILSEL source at a fixed interrupt level. Necessary | ||
* both for level reservation as well as for aliased sources that only | ||
* exist on special ILSEL#s. | ||
* | ||
* Returns an IRQ number (as ilsel_enable()). | ||
*/ | ||
int ilsel_enable_fixed(ilsel_source_t set, unsigned int level) | ||
{ | ||
unsigned int bit = ilsel_offset(level - 1); | ||
|
||
if (test_and_set_bit(bit, &ilsel_level_map)) | ||
return -EBUSY; | ||
|
||
__ilsel_enable(set, bit); | ||
|
||
return bit; | ||
} | ||
EXPORT_SYMBOL_GPL(ilsel_enable_fixed); | ||
|
||
/** | ||
* ilsel_disable - Disable an ILSEL set | ||
* @irq: Bit position for ILSEL set value (retval from enable routines) | ||
* | ||
* Disable a previously enabled ILSEL set. | ||
*/ | ||
void ilsel_disable(unsigned int irq) | ||
{ | ||
unsigned long addr; | ||
unsigned int tmp; | ||
|
||
addr = mk_ilsel_addr(bit); | ||
|
||
tmp = ctrl_inw(addr); | ||
tmp &= ~(0xf << mk_ilsel_shift(bit)); | ||
ctrl_outw(tmp, addr); | ||
|
||
clear_bit(bit, &ilsel_level_map); | ||
} | ||
EXPORT_SYMBOL_GPL(ilsel_disable); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#ifndef __ASM_SH_ILSEL_H | ||
#define __ASM_SH_ILSEL_H | ||
|
||
typedef enum { | ||
ILSEL_NONE, | ||
ILSEL_LAN, | ||
ILSEL_USBH_I, | ||
ILSEL_USBH_S, | ||
ILSEL_USBH_V, | ||
ILSEL_RTC, | ||
ILSEL_USBP_I, | ||
ILSEL_USBP_S, | ||
ILSEL_USBP_V, | ||
ILSEL_KEY, | ||
|
||
/* | ||
* ILSEL Aliases - corner cases for interleaved level tables. | ||
* | ||
* Someone thought this was a good idea and less hassle than | ||
* demuxing a shared vector, really. | ||
*/ | ||
|
||
/* ILSEL0 and 2 */ | ||
ILSEL_FPGA0, | ||
ILSEL_FPGA1, | ||
ILSEL_EX1, | ||
ILSEL_EX2, | ||
ILSEL_EX3, | ||
ILSEL_EX4, | ||
|
||
/* ILSEL1 and 3 */ | ||
ILSEL_FPGA2 = ILSEL_FPGA0, | ||
ILSEL_FPGA3 = ILSEL_FPGA1, | ||
ILSEL_EX5 = ILSEL_EX1, | ||
ILSEL_EX6 = ILSEL_EX2, | ||
ILSEL_EX7 = ILSEL_EX3, | ||
ILSEL_EX8 = ILSEL_EX4, | ||
} ilsel_source_t; | ||
|
||
/* arch/sh/boards/renesas/x3proto/ilsel.c */ | ||
int ilsel_enable(ilsel_source_t set); | ||
int ilsel_enable_fixed(ilsel_source_t set, unsigned int level); | ||
void ilsel_disable(unsigned int irq); | ||
|
||
#endif /* __ASM_SH_ILSEL_H */ |