aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/boards/mach-x3proto/ilsel.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2008-07-29 08:01:19 -0400
committerPaul Mundt <lethal@linux-sh.org>2008-07-29 08:01:19 -0400
commitda2014a2b080e7f3024a4eb6917d47069ad9620b (patch)
treecfde12c6d4b5baa222966b14a676f107992cf786 /arch/sh/boards/mach-x3proto/ilsel.c
parent71b8064e7df5698520d73b4c1566a3dbc98eb9ef (diff)
sh: Shuffle the board directories in to mach groups.
This flattens out the board directories in to individual mach groups, we will use this for getting rid of unneeded directories, simplifying the build system, and becoming more coherent with the refactored arch/sh/include topology. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/boards/mach-x3proto/ilsel.c')
-rw-r--r--arch/sh/boards/mach-x3proto/ilsel.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/arch/sh/boards/mach-x3proto/ilsel.c b/arch/sh/boards/mach-x3proto/ilsel.c
new file mode 100644
index 000000000000..b5c673c39337
--- /dev/null
+++ b/arch/sh/boards/mach-x3proto/ilsel.c
@@ -0,0 +1,151 @@
1/*
2 * arch/sh/boards/renesas/x3proto/ilsel.c
3 *
4 * Helper routines for SH-X3 proto board ILSEL.
5 *
6 * Copyright (C) 2007 Paul Mundt
7 *
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
11 */
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/bitmap.h>
16#include <linux/io.h>
17#include <asm/ilsel.h>
18
19/*
20 * ILSEL is split across:
21 *
22 * ILSEL0 - 0xb8100004 [ Levels 1 - 4 ]
23 * ILSEL1 - 0xb8100006 [ Levels 5 - 8 ]
24 * ILSEL2 - 0xb8100008 [ Levels 9 - 12 ]
25 * ILSEL3 - 0xb810000a [ Levels 13 - 15 ]
26 *
27 * With each level being relative to an ilsel_source_t.
28 */
29#define ILSEL_BASE 0xb8100004
30#define ILSEL_LEVELS 15
31
32/*
33 * ILSEL level map, in descending order from the highest level down.
34 *
35 * Supported levels are 1 - 15 spread across ILSEL0 - ILSEL4, mapping
36 * directly to IRLs. As the IRQs are numbered in reverse order relative
37 * to the interrupt level, the level map is carefully managed to ensure a
38 * 1:1 mapping between the bit position and the IRQ number.
39 *
40 * This careful constructions allows ilsel_enable*() to be referenced
41 * directly for hooking up an ILSEL set and getting back an IRQ which can
42 * subsequently be used for internal accounting in the (optional) disable
43 * path.
44 */
45static unsigned long ilsel_level_map;
46
47static inline unsigned int ilsel_offset(unsigned int bit)
48{
49 return ILSEL_LEVELS - bit - 1;
50}
51
52static inline unsigned long mk_ilsel_addr(unsigned int bit)
53{
54 return ILSEL_BASE + ((ilsel_offset(bit) >> 1) & ~0x1);
55}
56
57static inline unsigned int mk_ilsel_shift(unsigned int bit)
58{
59 return (ilsel_offset(bit) & 0x3) << 2;
60}
61
62static void __ilsel_enable(ilsel_source_t set, unsigned int bit)
63{
64 unsigned int tmp, shift;
65 unsigned long addr;
66
67 addr = mk_ilsel_addr(bit);
68 shift = mk_ilsel_shift(bit);
69
70 pr_debug("%s: bit#%d: addr - 0x%08lx (shift %d, set %d)\n",
71 __func__, bit, addr, shift, set);
72
73 tmp = ctrl_inw(addr);
74 tmp &= ~(0xf << shift);
75 tmp |= set << shift;
76 ctrl_outw(tmp, addr);
77}
78
79/**
80 * ilsel_enable - Enable an ILSEL set.
81 * @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h).
82 *
83 * Enables a given non-aliased ILSEL source (<= ILSEL_KEY) at the highest
84 * available interrupt level. Callers should take care to order callsites
85 * noting descending interrupt levels. Aliasing FPGA and external board
86 * IRQs need to use ilsel_enable_fixed().
87 *
88 * The return value is an IRQ number that can later be taken down with
89 * ilsel_disable().
90 */
91int ilsel_enable(ilsel_source_t set)
92{
93 unsigned int bit;
94
95 /* Aliased sources must use ilsel_enable_fixed() */
96 BUG_ON(set > ILSEL_KEY);
97
98 do {
99 bit = find_first_zero_bit(&ilsel_level_map, ILSEL_LEVELS);
100 } while (test_and_set_bit(bit, &ilsel_level_map));
101
102 __ilsel_enable(set, bit);
103
104 return bit;
105}
106EXPORT_SYMBOL_GPL(ilsel_enable);
107
108/**
109 * ilsel_enable_fixed - Enable an ILSEL set at a fixed interrupt level
110 * @set: ILSEL source (see ilsel_source_t enum in include/asm-sh/ilsel.h).
111 * @level: Interrupt level (1 - 15)
112 *
113 * Enables a given ILSEL source at a fixed interrupt level. Necessary
114 * both for level reservation as well as for aliased sources that only
115 * exist on special ILSEL#s.
116 *
117 * Returns an IRQ number (as ilsel_enable()).
118 */
119int ilsel_enable_fixed(ilsel_source_t set, unsigned int level)
120{
121 unsigned int bit = ilsel_offset(level - 1);
122
123 if (test_and_set_bit(bit, &ilsel_level_map))
124 return -EBUSY;
125
126 __ilsel_enable(set, bit);
127
128 return bit;
129}
130EXPORT_SYMBOL_GPL(ilsel_enable_fixed);
131
132/**
133 * ilsel_disable - Disable an ILSEL set
134 * @irq: Bit position for ILSEL set value (retval from enable routines)
135 *
136 * Disable a previously enabled ILSEL set.
137 */
138void ilsel_disable(unsigned int irq)
139{
140 unsigned long addr;
141 unsigned int tmp;
142
143 addr = mk_ilsel_addr(irq);
144
145 tmp = ctrl_inw(addr);
146 tmp &= ~(0xf << mk_ilsel_shift(irq));
147 ctrl_outw(tmp, addr);
148
149 clear_bit(irq, &ilsel_level_map);
150}
151EXPORT_SYMBOL_GPL(ilsel_disable);