kirkwood.c revision 1.1 1 /* $NetBSD: kirkwood.c,v 1.1 2010/10/03 05:49:24 kiyohara Exp $ */
2 /*
3 * Copyright (c) 2010 KIYOHARA Takashi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: kirkwood.c,v 1.1 2010/10/03 05:49:24 kiyohara Exp $");
30
31 #define _INTR_PRIVATE
32
33 #include "mvsocgpp.h"
34
35 #include <sys/param.h>
36 #include <sys/bus.h>
37
38 #include <machine/intr.h>
39
40 #include <arm/pic/picvar.h>
41 #include <arm/pic/picvar.h>
42
43 #include <arm/marvell/mvsocreg.h>
44 #include <arm/marvell/mvsocvar.h>
45 #include <arm/marvell/kirkwoodreg.h>
46
47 #include <dev/marvell/marvellreg.h>
48
49
50 static void kirkwood_intr_init(void);
51
52 static void kirkwood_pic_unblock_low_irqs(struct pic_softc *, size_t, uint32_t);
53 static void kirkwood_pic_unblock_high_irqs(struct pic_softc *, size_t,
54 uint32_t);
55 static void kirkwood_pic_block_low_irqs(struct pic_softc *, size_t, uint32_t);
56 static void kirkwood_pic_block_high_irqs(struct pic_softc *, size_t, uint32_t);
57 static int kirkwood_pic_find_pending_high_irqs(struct pic_softc *);
58 static void kirkwood_pic_establish_irq(struct pic_softc *, struct intrsource *);
59 static void kirkwood_pic_source_name(struct pic_softc *, int, char *, size_t);
60
61 static int kirkwood_find_pending_irqs(void);
62
63 static const char * const sources[64] = {
64 "MainHighSum(0)", "Bridge(1)", "Host2CPU DB(2)", "CPU2Host DB(3)",
65 "Reserved_4(4)", "Xor0Chan0(5)", "Xor0Chan1(6)", "Xor1Chan0(7)",
66 "Xor1Chan1(8)", "PEX0INT(9)", "Reserved(10)", "GbE0Sum(11)",
67 "GbE0Rx(12)", "GbE0Tx(13)", "GbE0Misc(14)", "GbE1Sum(15)",
68 "GbE1Rx(16)", "GbE1Tx(17)", "GbE1Misc(18)", "USB0Cnt(19)",
69 "Reserved(20)", "Sata(21)", "SecurityInt(22)", "SPIInt(23)",
70 "AudioINT(24)", "Reserved(25)", "TS0Int(26)", "Reserved(27)",
71 "SDIOInt(28)", "TWSI(29)", "AVBInt(30)", "TDMInt(31)"
72
73 "Reserved(32)", "Uart0Int(33)", "Uart1Int(34)", "GPIOLo7_0(35)"
74 "GPIOLo8_15(36)", "GPIOLo16_23(37)", "GPIOLo24_31(38)", "GPIOHi7_0(39)"
75 "GPIOHi8_15(40)", "GPIOHi16_23(41)", "XOR0Err(42)", "XOR1Err(43)"
76 "PEX0Err(44)", "Reserved(45)", "GbE0Err(46)", "GbE1Err(47)"
77 "USBErr(48)", "SecurityErr(49)", "AudioErr(50)", "Reserved(51)"
78 "Reserved(52)", "RTCInt(53)", "Reserved(54)", "Reserved(55)"
79 "Reserved(56)", "Reserved(57)", "Reserved(58)", "Reserved(59)"
80 "Reserved(60)", "Reserved(61)", "Reserved(62)", "Reserved(63)"
81 };
82
83 static struct pic_ops kirkwood_picops_low = {
84 .pic_unblock_irqs = kirkwood_pic_unblock_low_irqs,
85 .pic_block_irqs = kirkwood_pic_block_low_irqs,
86 .pic_establish_irq = kirkwood_pic_establish_irq,
87 .pic_source_name = kirkwood_pic_source_name,
88 };
89 static struct pic_ops kirkwood_picops_high = {
90 .pic_unblock_irqs = kirkwood_pic_unblock_high_irqs,
91 .pic_block_irqs = kirkwood_pic_block_high_irqs,
92 .pic_find_pending_irqs = kirkwood_pic_find_pending_high_irqs,
93 .pic_establish_irq = kirkwood_pic_establish_irq,
94 .pic_source_name = kirkwood_pic_source_name,
95 };
96 static struct pic_softc kirkwood_pic_low = {
97 .pic_ops = &kirkwood_picops_low,
98 .pic_maxsources = 32,
99 .pic_name = "kirkwood_low",
100 };
101 static struct pic_softc kirkwood_pic_high = {
102 .pic_ops = &kirkwood_picops_high,
103 .pic_maxsources = 32,
104 .pic_name = "kirkwood_high",
105 };
106
107
108 /*
109 * kirkwood_intr_bootstrap:
110 *
111 * Initialize the rest of the interrupt subsystem, making it
112 * ready to handle interrupts from devices.
113 */
114 void
115 kirkwood_intr_bootstrap(void)
116 {
117 extern void (*mvsoc_intr_init)(void);
118
119 /* disable all interrupts */
120 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR, 0);
121 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR, 0);
122
123 /* disable all bridge interrupts */
124 write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
125
126 mvsoc_intr_init = kirkwood_intr_init;
127
128 #if NMVSOCGPP > 0
129 switch (mvsoc_model()) {
130 case MARVELL_KIRKWOOD_88F6180: gpp_npins = 30; break;
131 case MARVELL_KIRKWOOD_88F6192: gpp_npins = 36; break;
132 case MARVELL_KIRKWOOD_88F6281: gpp_npins = 50; break;
133 }
134 gpp_irqbase = 96; /* Main Low(32) + High(32) + Bridge(32) */
135 #endif
136 }
137
138 static void
139 kirkwood_intr_init(void)
140 {
141 extern struct pic_softc mvsoc_bridge_pic;
142 void *ih;
143
144 pic_add(&kirkwood_pic_low, 0);
145
146 pic_add(&kirkwood_pic_high, 32);
147 ih = intr_establish(KIRKWOOD_IRQ_HIGH, IPL_HIGH, IST_LEVEL_HIGH,
148 pic_handle_intr, &kirkwood_pic_high);
149 KASSERT(ih != NULL);
150
151 pic_add(&mvsoc_bridge_pic, 64);
152 ih = intr_establish(KIRKWOOD_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH,
153 pic_handle_intr, &mvsoc_bridge_pic);
154 KASSERT(ih != NULL);
155
156 find_pending_irqs = kirkwood_find_pending_irqs;
157 }
158
159 /* ARGSUSED */
160 static void
161 kirkwood_pic_unblock_low_irqs(struct pic_softc *pic, size_t irqbase,
162 uint32_t irq_mask)
163 {
164
165 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR,
166 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR) | irq_mask);
167 }
168
169 /* ARGSUSED */
170 static void
171 kirkwood_pic_unblock_high_irqs(struct pic_softc *pic, size_t irqbase,
172 uint32_t irq_mask)
173 {
174
175 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR,
176 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR) | irq_mask);
177 }
178
179 /* ARGSUSED */
180 static void
181 kirkwood_pic_block_low_irqs(struct pic_softc *pic, size_t irqbase,
182 uint32_t irq_mask)
183 {
184
185 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR,
186 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR) & ~irq_mask);
187 }
188
189 /* ARGSUSED */
190 static void
191 kirkwood_pic_block_high_irqs(struct pic_softc *pic, size_t irqbase,
192 uint32_t irq_mask)
193 {
194
195 write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR,
196 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR) & ~irq_mask);
197 }
198
199 static int
200 kirkwood_pic_find_pending_high_irqs(struct pic_softc *pic)
201 {
202 uint32_t pending;
203
204 pending = read_mlmbreg(KIRKWOOD_MLMB_MICHR) &
205 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR);
206 if (pending == 0)
207 return 0;
208 pic_mark_pending_sources(pic, 0, pending);
209 return 1;
210 }
211
212 /* ARGSUSED */
213 static void
214 kirkwood_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
215 {
216 /* Nothing */
217 }
218
219 static void
220 kirkwood_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
221 {
222
223 strlcpy(buf, sources[pic->pic_irqbase + irq], len);
224 }
225
226 /*
227 * Called with interrupts disabled
228 */
229 static int
230 kirkwood_find_pending_irqs(void)
231 {
232 uint32_t pending;
233
234 pending = read_mlmbreg(KIRKWOOD_MLMB_MICLR) &
235 read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR);
236 if (pending == 0)
237 return 0;
238
239 return pic_mark_pending_sources(&kirkwood_pic_low, 0, pending);
240 }
241
242 /*
243 * Clock functions
244 */
245
246 void
247 kirkwood_getclks(bus_addr_t iobase)
248 {
249 uint32_t reg;
250 uint16_t model;
251
252 #define MHz * 1000 * 1000
253
254 model = mvsoc_model();
255 if (model == MARVELL_KIRKWOOD_88F6281)
256 mvTclk = 200 MHz;
257 else /* 166MHz */
258 mvTclk = 166666667;
259
260 reg = *(volatile uint32_t *)(iobase + KIRKWOOD_MPP_BASE +
261 KIRKWOOD_MPP_SAMPLE_AT_RESET);
262 if (model == MARVELL_KIRKWOOD_88F6180) {
263 switch (reg & 0x0000001c) {
264 case 0x00000014: mvPclk = 600 MHz;
265 case 0x00000018: mvPclk = 800 MHz;
266 default:
267 panic("unknown mvPclk\n");
268 }
269 mvSysclk = 200 MHz;
270 } else {
271 switch (reg & 0x0040001a) {
272 case 0x00000008: mvPclk = 600 MHz; break;
273 case 0x00400008: mvPclk = 800 MHz; break;
274 case 0x0040000a: mvPclk = 1000 MHz; break;
275 case 0x00000012: mvPclk = 1200 MHz; break;
276 case 0x00000018: mvPclk = 1200 MHz; break;
277 default:
278 panic("unknown mvPclk\n");
279 }
280
281 switch (reg & 0x000001e0) {
282 case 0x00000060: mvSysclk = mvPclk * 2 / 5; break;
283 case 0x00000080: mvSysclk = mvPclk * 1 / 3; break;
284 case 0x000000c0: mvSysclk = mvPclk * 1 / 4; break;
285 default:
286 panic("unknown mvSysclk\n");
287 }
288 }
289
290 #undef MHz
291
292 }
293