xref: /netbsd-src/sys/arch/arm/marvell/kirkwood.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: kirkwood.c,v 1.9 2014/03/11 07:52:37 martin 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.9 2014/03/11 07:52:37 martin 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_irqs(struct pic_softc *, size_t, uint32_t);
53 static void kirkwood_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
54 static void kirkwood_pic_establish_irq(struct pic_softc *, struct intrsource *);
55 static void kirkwood_pic_source_name(struct pic_softc *, int, char *, size_t);
56 
57 static int kirkwood_find_pending_irqs(void);
58 
59 static const char * const sources[64] = {
60     "MainHighSum(0)",  "Bridge(1)",       "Host2CPU DB(2)",  "CPU2Host DB(3)",
61     "Reserved_4(4)",   "Xor0Chan0(5)",    "Xor0Chan1(6)",    "Xor1Chan0(7)",
62     "Xor1Chan1(8)",    "PEX0INT(9)",      "Reserved(10)",    "GbE0Sum(11)",
63     "GbE0Rx(12)",      "GbE0Tx(13)",      "GbE0Misc(14)",    "GbE1Sum(15)",
64     "GbE1Rx(16)",      "GbE1Tx(17)",      "GbE1Misc(18)",    "USB0Cnt(19)",
65     "Reserved(20)",    "Sata(21)",        "SecurityInt(22)", "SPIInt(23)",
66     "AudioINT(24)",    "Reserved(25)",    "TS0Int(26)",      "Reserved(27)",
67     "SDIOInt(28)",     "TWSI(29)",        "AVBInt(30)",      "TDMInt(31)",
68 
69     "Reserved(32)",    "Uart0Int(33)",    "Uart1Int(34)",    "GPIOLo7_0(35)",
70     "GPIOLo8_15(36)",  "GPIOLo16_23(37)", "GPIOLo24_31(38)", "GPIOHi7_0(39)",
71     "GPIOHi8_15(40)",  "GPIOHi16_23(41)", "XOR0Err(42)",     "XOR1Err(43)",
72     "PEX0Err(44)",     "Reserved(45)",    "GbE0Err(46)",     "GbE1Err(47)",
73     "USBErr(48)",      "SecurityErr(49)", "AudioErr(50)",    "Reserved(51)",
74     "Reserved(52)",    "RTCInt(53)",      "Reserved(54)",    "Reserved(55)",
75     "Reserved(56)",    "Reserved(57)",    "Reserved(58)",    "Reserved(59)",
76     "Reserved(60)",    "Reserved(61)",    "Reserved(62)",    "Reserved(63)"
77 };
78 
79 static struct pic_ops kirkwood_picops = {
80 	.pic_unblock_irqs = kirkwood_pic_unblock_irqs,
81 	.pic_block_irqs = kirkwood_pic_block_irqs,
82 	.pic_establish_irq = kirkwood_pic_establish_irq,
83 	.pic_source_name = kirkwood_pic_source_name,
84 };
85 static struct pic_softc kirkwood_pic = {
86 	.pic_ops = &kirkwood_picops,
87 	.pic_maxsources = 64,
88 	.pic_name = "kirkwood",
89 };
90 
91 static struct {
92 	bus_size_t offset;
93 	uint32_t bits;
94 } clkgatings[]= {
95 	{ KIRKWOOD_GBE0_BASE,	(1 << 0) },
96 	{ MVSOC_PEX_BASE,	(1 << 2) },
97 	{ KIRKWOOD_USB_BASE,	(1 << 3) },
98 	{ KIRKWOOD_SDIO_BASE,	(1 << 4) },
99 	{ KIRKWOOD_MTS_BASE,	(1 << 5) },
100 #if 0
101 	{ Dunit, (1 << 6) },	/* SDRAM Unit Clock */
102 	{ Runit, (1 << 7) },	/* Runit Clock */
103 #endif
104 	{ KIRKWOOD_IDMAC_BASE,	(1 << 8) | (1 << 16) },
105 	{ KIRKWOOD_AUDIO_BASE,	(1 << 9) },
106 	{ KIRKWOOD_SATAHC_BASE, (1 << 14) | (1 << 15) },
107 	{ KIRKWOOD_CESA_BASE,	(1 << 17) },
108 	{ KIRKWOOD_GBE1_BASE,	(1 << 19) },
109 	{ KIRKWOOD_TDM_BASE,	(1 << 20) },
110 };
111 
112 
113 /*
114  * kirkwood_intr_bootstrap:
115  *
116  *	Initialize the rest of the interrupt subsystem, making it
117  *	ready to handle interrupts from devices.
118  */
119 void
120 kirkwood_intr_bootstrap(void)
121 {
122 	extern void (*mvsoc_intr_init)(void);
123 
124 	/* disable all interrupts */
125 	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR, 0);
126 	write_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR, 0);
127 
128 	/* disable all bridge interrupts */
129 	write_mlmbreg(MVSOC_MLMB_MLMBIMR, 0);
130 
131 	mvsoc_intr_init = kirkwood_intr_init;
132 
133 #if NMVSOCGPP > 0
134 	switch (mvsoc_model()) {
135 	case MARVELL_KIRKWOOD_88F6180: gpp_npins = 30; break;
136 	case MARVELL_KIRKWOOD_88F6192: gpp_npins = 36; break;
137 	case MARVELL_KIRKWOOD_88F6281: gpp_npins = 50; break;
138 	case MARVELL_KIRKWOOD_88F6282: gpp_npins = 50; break;
139 	}
140 	gpp_irqbase = 96;	/* Main Low(32) + High(32) + Bridge(32) */
141 #endif
142 }
143 
144 static void
145 kirkwood_intr_init(void)
146 {
147 	extern struct pic_softc mvsoc_bridge_pic;
148 	void *ih __diagused;
149 
150 	pic_add(&kirkwood_pic, 0);
151 
152 	pic_add(&mvsoc_bridge_pic, 64);
153 	ih = intr_establish(KIRKWOOD_IRQ_BRIDGE, IPL_HIGH, IST_LEVEL_HIGH,
154 	    pic_handle_intr, &mvsoc_bridge_pic);
155 	KASSERT(ih != NULL);
156 
157 	find_pending_irqs = kirkwood_find_pending_irqs;
158 }
159 
160 /* ARGSUSED */
161 static void
162 kirkwood_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
163 			  uint32_t irq_mask)
164 {
165 	const size_t reg = KIRKWOOD_MLMB_MIRQIMLR
166 	   + irqbase * (KIRKWOOD_MLMB_MIRQIMHR - KIRKWOOD_MLMB_MIRQIMLR) / 32;
167 
168 	KASSERT(irqbase < 64);
169 	write_mlmbreg(reg, read_mlmbreg(reg) | irq_mask);
170 }
171 
172 /* ARGSUSED */
173 static void
174 kirkwood_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
175 			uint32_t irq_mask)
176 {
177 	const size_t reg = KIRKWOOD_MLMB_MIRQIMLR
178 	   + irqbase * (KIRKWOOD_MLMB_MIRQIMHR - KIRKWOOD_MLMB_MIRQIMLR) / 32;
179 
180 	KASSERT(irqbase < 64);
181 	write_mlmbreg(reg, read_mlmbreg(reg) & ~irq_mask);
182 }
183 
184 /* ARGSUSED */
185 static void
186 kirkwood_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
187 {
188 	/* Nothing */
189 }
190 
191 static void
192 kirkwood_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
193 {
194 
195 	strlcpy(buf, sources[pic->pic_irqbase + irq], len);
196 }
197 
198 /*
199  * Called with interrupts disabled
200  */
201 static int
202 kirkwood_find_pending_irqs(void)
203 {
204 	int ipl = 0;
205 
206 	uint32_t causelow = read_mlmbreg(KIRKWOOD_MLMB_MICLR);
207 	uint32_t pendinglow = read_mlmbreg(KIRKWOOD_MLMB_MIRQIMLR);
208 
209 	pendinglow &= causelow;
210 	if (pendinglow != 0)
211 		ipl |= pic_mark_pending_sources(&kirkwood_pic, 0, pendinglow);
212 
213 	if ((causelow & (1 << KIRKWOOD_IRQ_HIGH)) == (1 << KIRKWOOD_IRQ_HIGH)) {
214 		uint32_t causehigh = read_mlmbreg(KIRKWOOD_MLMB_MICHR);
215 		uint32_t pendinghigh = read_mlmbreg(KIRKWOOD_MLMB_MIRQIMHR);
216 		pendinghigh &= causehigh;
217 		ipl |= pic_mark_pending_sources(&kirkwood_pic, 32, pendinghigh);
218 	}
219 
220 	return ipl;
221 }
222 
223 /*
224  * Clock functions
225  */
226 
227 void
228 kirkwood_getclks(bus_addr_t iobase)
229 {
230 	uint32_t reg;
231 	uint16_t model;
232 
233 #define MHz	* 1000 * 1000
234 
235 	model = mvsoc_model();
236 	if (model == MARVELL_KIRKWOOD_88F6281 ||
237 	    model == MARVELL_KIRKWOOD_88F6282)
238 		mvTclk = 200 MHz;
239 	else		/* 166MHz */
240 		mvTclk = 166666667;
241 
242 	reg = *(volatile uint32_t *)(iobase + KIRKWOOD_MPP_BASE +
243 	    KIRKWOOD_MPP_SAMPLE_AT_RESET);
244 	if (model == MARVELL_KIRKWOOD_88F6180) {
245 		switch (reg & 0x0000001c) {
246 		case 0x00000014: mvPclk =  600 MHz; break;
247 		case 0x00000018: mvPclk =  800 MHz; break;
248 		default:
249 			panic("unknown mvPclk\n");
250 		}
251 		mvSysclk = 200 MHz;
252 	} else {
253 		switch (reg & 0x0040001a) {
254 		case 0x00000002: mvPclk =  400 MHz; break;
255 		case 0x00000008: mvPclk =  600 MHz; break;
256 		case 0x00400008: mvPclk =  800 MHz; break;
257 		case 0x0040000a: mvPclk = 1000 MHz; break;
258 		case 0x00000012: mvPclk = 1200 MHz; break;
259 		case 0x00000018: mvPclk = 1500 MHz; break;
260 		case 0x0000001a: mvPclk = 1600 MHz; break;
261 		case 0x00400018: mvPclk = 1800 MHz; break;
262 		case 0x0040001a: mvPclk = 2000 MHz; break;
263 		default:
264 			panic("unknown mvPclk\n");
265 		}
266 
267 		switch (reg & 0x000001e0) {
268 		case 0x00000000: mvSysclk = mvPclk * 1 / 1; break;
269 		case 0x00000040: mvSysclk = mvPclk * 1 / 2; break;
270 		case 0x00000060: mvSysclk = mvPclk * 2 / 5; break;
271 		case 0x00000080: mvSysclk = mvPclk * 1 / 3; break;
272 		case 0x000000c0: mvSysclk = mvPclk * 1 / 4; break;
273 		case 0x000000e0: mvSysclk = mvPclk * 2 / 9; break;
274 		case 0x00000100: mvSysclk = mvPclk * 1 / 5; break;
275 		case 0x00000120: mvSysclk = mvPclk * 1 / 6; break;
276 		default:
277 			panic("unknown mvSysclk\n");
278 		}
279 	}
280 
281 #undef MHz
282 
283 }
284 
285 int
286 kirkwood_clkgating(struct marvell_attach_args *mva)
287 {
288 	uint32_t val;
289 	int i;
290 
291 	for (i = 0; i < __arraycount(clkgatings); i++) {
292 		if (clkgatings[i].offset == mva->mva_offset) {
293 			val = read_mlmbreg(MVSOC_MLMB_CLKGATING);
294 			if ((val & clkgatings[i].bits) == clkgatings[i].bits)
295 				/* Clock enabled */
296 				return 0;
297 			return 1;
298 		}
299 	}
300 	/* Clock Gating not support */
301 	return 0;
302 }
303