xref: /netbsd-src/sys/arch/arm/marvell/armadaxp.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: armadaxp.c,v 1.8 2014/04/05 22:41:50 matt Exp $	*/
2 /*******************************************************************************
3 Copyright (C) Marvell International Ltd. and its affiliates
4 
5 Developed by Semihalf
6 
7 ********************************************************************************
8 Marvell BSD License
9 
10 If you received this File from Marvell, you may opt to use, redistribute and/or
11 modify this File under the following licensing terms.
12 Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14 
15     *   Redistributions of source code must retain the above copyright notice,
16             this list of conditions and the following disclaimer.
17 
18     *   Redistributions in binary form must reproduce the above copyright
19         notice, this list of conditions and the following disclaimer in the
20         documentation and/or other materials provided with the distribution.
21 
22     *   Neither the name of Marvell nor the names of its contributors may be
23         used to endorse or promote products derived from this software without
24         specific prior written permission.
25 
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
27 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
30 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
33 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 
37 *******************************************************************************/
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: armadaxp.c,v 1.8 2014/04/05 22:41:50 matt Exp $");
41 
42 #define _INTR_PRIVATE
43 
44 #include "opt_mvsoc.h"
45 
46 #include <sys/param.h>
47 #include <sys/bus.h>
48 
49 #include <machine/intr.h>
50 
51 #include <arm/pic/picvar.h>
52 #include <arm/pic/picvar.h>
53 
54 #include <arm/armreg.h>
55 #include <arm/cpu.h>
56 #include <arm/cpufunc.h>
57 
58 #include <arm/marvell/mvsocreg.h>
59 #include <arm/marvell/mvsocvar.h>
60 #include <arm/marvell/armadaxpreg.h>
61 
62 #include <dev/marvell/marvellreg.h>
63 
64 #define EXTRACT_XP_CPU_FREQ_FIELD(sar)	(((0x01 & (sar >> 52)) << 3) | \
65 					    (0x07 & (sar >> 21)))
66 #define EXTRACT_XP_FAB_FREQ_FIELD(sar)	(((0x01 & (sar >> 51)) << 4) | \
67 					    (0x0F & (sar >> 24)))
68 #define EXTRACT_370_CPU_FREQ_FIELD(sar)	((sar >> 11) & 0xf)
69 #define EXTRACT_370_FAB_FREQ_FIELD(sar)	((sar >> 15) & 0x1f)
70 
71 #define	MPIC_WRITE(reg, val)		(bus_space_write_4(&mvsoc_bs_tag, \
72 					    mpic_handle, reg, val))
73 #define	MPIC_CPU_WRITE(reg, val)	(bus_space_write_4(&mvsoc_bs_tag, \
74 					    mpic_cpu_handle, reg, val))
75 
76 #define	MPIC_READ(reg)			(bus_space_read_4(&mvsoc_bs_tag, \
77 					    mpic_handle, reg))
78 #define	MPIC_CPU_READ(reg)		(bus_space_read_4(&mvsoc_bs_tag, \
79 					    mpic_cpu_handle, reg))
80 
81 #define	L2_WRITE(reg, val)		(bus_space_write_4(&mvsoc_bs_tag, \
82 					    l2_handle, reg, val))
83 #define	L2_READ(reg)			(bus_space_read_4(&mvsoc_bs_tag, \
84 					    l2_handle, reg))
85 bus_space_handle_t mpic_cpu_handle;
86 static bus_space_handle_t mpic_handle, l2_handle;
87 int l2cache_state = 0;
88 int iocc_state = 0;
89 #define read_miscreg(r)		(*(volatile uint32_t *)(misc_base + (r)))
90 vaddr_t misc_base;
91 
92 extern void (*mvsoc_intr_init)(void);
93 static void armadaxp_intr_init(void);
94 
95 static void armadaxp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
96 static void armadaxp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
97 static void armadaxp_pic_establish_irq(struct pic_softc *, struct intrsource *);
98 static void armadaxp_pic_set_priority(struct pic_softc *, int);
99 
100 static int armadaxp_find_pending_irqs(void);
101 static void armadaxp_pic_block_irq(struct pic_softc *, size_t);
102 void armadaxp_io_coherency_init(void);
103 int armadaxp_l2_init(bus_addr_t);
104 
105 struct vco_freq_ratio {
106 	uint8_t	vco_cpu;	/* VCO to CLK0(CPU) clock ratio */
107 	uint8_t	vco_l2c;	/* VCO to NB(L2 cache) clock ratio */
108 	uint8_t	vco_hcl;	/* VCO to HCLK(DDR controller) clock ratio */
109 	uint8_t	vco_ddr;	/* VCO to DR(DDR memory) clock ratio */
110 };
111 
112 static struct vco_freq_ratio freq_conf_table[] = {
113 /*00*/	{ 1, 1,	 4,  2 },
114 /*01*/	{ 1, 2,	 2,  2 },
115 /*02*/	{ 2, 2,	 6,  3 },
116 /*03*/	{ 2, 2,	 3,  3 },
117 /*04*/	{ 1, 2,	 3,  3 },
118 /*05*/	{ 1, 2,	 4,  2 },
119 /*06*/	{ 1, 1,	 2,  2 },
120 /*07*/	{ 2, 3,	 6,  6 },
121 /*08*/	{ 2, 3,	 5,  5 },
122 /*09*/	{ 1, 2,	 6,  3 },
123 /*10*/	{ 2, 4,	10,  5 },
124 /*11*/	{ 1, 3,	 6,  6 },
125 /*12*/	{ 1, 2,	 5,  5 },
126 /*13*/	{ 1, 3,	 6,  3 },
127 /*14*/	{ 1, 2,	 5,  5 },
128 /*15*/	{ 2, 2,	 5,  5 },
129 /*16*/	{ 1, 1,	 3,  3 },
130 /*17*/	{ 2, 5,	10, 10 },
131 /*18*/	{ 1, 3,	 8,  4 },
132 /*19*/	{ 1, 1,	 2,  1 },
133 /*20*/	{ 2, 3,	 6,  3 },
134 /*21*/	{ 1, 2,	 8,  4 },
135 /*22*/	{ 2, 5,	10,  5 }
136 };
137 
138 static uint16_t clock_table_xp[] = {
139 	1000, 1066, 1200, 1333, 1500, 1666, 1800, 2000,
140 	 600,  667,  800, 1600, 2133, 2200, 2400
141 };
142 static uint16_t clock_table_370[] = {
143 	 400,  533,  667,  800, 1000, 1067, 1200, 1333,
144 	1500, 1600, 1667, 1800, 2000,  333,  600,  900,
145 	   0
146 };
147 
148 static struct pic_ops armadaxp_picops = {
149 	.pic_unblock_irqs = armadaxp_pic_unblock_irqs,
150 	.pic_block_irqs = armadaxp_pic_block_irqs,
151 	.pic_establish_irq = armadaxp_pic_establish_irq,
152 	.pic_set_priority = armadaxp_pic_set_priority,
153 };
154 
155 static struct pic_softc armadaxp_pic = {
156 	.pic_ops = &armadaxp_picops,
157 	.pic_name = "armadaxp",
158 };
159 
160 static struct {
161 	bus_size_t offset;
162 	uint32_t bits;
163 } clkgatings[]= {
164 	{ ARMADAXP_GBE3_BASE,	(1 << 1) },
165 	{ ARMADAXP_GBE2_BASE,	(1 << 2) },
166 	{ ARMADAXP_GBE1_BASE,	(1 << 3) },
167 	{ ARMADAXP_GBE0_BASE,	(1 << 4) },
168 	{ MVSOC_PEX_BASE,	(1 << 5) },
169 	{ ARMADAXP_PEX01_BASE,	(1 << 6) },
170 	{ ARMADAXP_PEX02_BASE,	(1 << 7) },
171 	{ ARMADAXP_PEX03_BASE,	(1 << 8) },
172 	{ ARMADAXP_PEX10_BASE,	(1 << 9) },
173 	{ ARMADAXP_PEX11_BASE,	(1 << 10) },
174 	{ ARMADAXP_PEX12_BASE,	(1 << 11) },
175 	{ ARMADAXP_PEX13_BASE,	(1 << 12) },
176 #if 0
177 	{ NetA, (1 << 13) },
178 #endif
179 	{ ARMADAXP_SATAHC_BASE,	(1 << 14) | (1 << 15) | (1 << 29) | (1 << 30) },
180 	{ ARMADAXP_LCD_BASE,	(1 << 16) },
181 	{ ARMADAXP_SDIO_BASE,	(1 << 17) },
182 	{ ARMADAXP_USB1_BASE,	(1 << 19) },
183 	{ ARMADAXP_USB2_BASE,	(1 << 20) },
184 	{ ARMADAXP_PEX2_BASE,	(1 << 26) },
185 	{ ARMADAXP_PEX3_BASE,	(1 << 27) },
186 #if 0
187 	{ DDR, (1 << 28) },
188 #endif
189 };
190 
191 /*
192  * armadaxp_intr_bootstrap:
193  *
194  *	Initialize the rest of the interrupt subsystem, making it
195  *	ready to handle interrupts from devices.
196  */
197 void
198 armadaxp_intr_bootstrap(bus_addr_t pbase)
199 {
200 	int i;
201 
202 	/* Map MPIC base and MPIC percpu base registers */
203 	if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_BASE,
204 	    0x500, 0, &mpic_handle) != 0)
205 		panic("%s: Could not map MPIC registers", __func__);
206 	if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_CPU_BASE,
207 	    0x800, 0, &mpic_cpu_handle) != 0)
208 		panic("%s: Could not map MPIC percpu registers", __func__);
209 
210 	/* Disable all interrupts */
211 	for (i = 0; i < 116; i++)
212 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, i);
213 
214 	mvsoc_intr_init = armadaxp_intr_init;
215 }
216 
217 static void
218 armadaxp_intr_init(void)
219 {
220 	int ctrl;
221 
222 	/* Get max interrupts */
223 	armadaxp_pic.pic_maxsources =
224 	    ((MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL) >> 2) & 0x7FF);
225 
226 	if (!armadaxp_pic.pic_maxsources)
227 		armadaxp_pic.pic_maxsources = 116;
228 
229 	pic_add(&armadaxp_pic, 0);
230 
231 	ctrl = MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL);
232 	/* Enable IRQ prioritization */
233 	ctrl |= (1 << 0);
234 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_CTRL, ctrl);
235 
236 	find_pending_irqs = armadaxp_find_pending_irqs;
237 }
238 
239 static void
240 armadaxp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
241     uint32_t irq_mask)
242 {
243 	int n;
244 
245 	while (irq_mask != 0) {
246 		n = ffs(irq_mask) - 1;
247 		KASSERT(pic->pic_maxsources >= n + irqbase);
248 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISE, n + irqbase);
249 		MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ICM, n + irqbase);
250 		if ((n + irqbase) == 0)
251 			MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_DOORBELL_MASK,
252 			    0xffffffff);
253 		irq_mask &= ~__BIT(n);
254 	}
255 }
256 
257 static void
258 armadaxp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
259     uint32_t irq_mask)
260 {
261 	int n;
262 
263 	while (irq_mask != 0) {
264 		n = ffs(irq_mask) - 1;
265 		KASSERT(pic->pic_maxsources >= n + irqbase);
266 		MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, n + irqbase);
267 		MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, n + irqbase);
268 		irq_mask &= ~__BIT(n);
269 	}
270 }
271 
272 static void
273 armadaxp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
274 {
275 	int tmp;
276 	KASSERT(pic->pic_maxsources >= is->is_irq);
277 	tmp = MPIC_READ(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4);
278 	/* Clear previous priority */
279 	tmp &= ~(0xf << MPIC_ISCR_SHIFT);
280 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4,
281 	    tmp | (is->is_ipl << MPIC_ISCR_SHIFT));
282 }
283 
284 static void
285 armadaxp_pic_set_priority(struct pic_softc *pic, int ipl)
286 {
287 	int ctp;
288 
289 	ctp = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_CTP);
290 	ctp &= ~(0xf << MPIC_CTP_SHIFT);
291 	ctp |= (ipl << MPIC_CTP_SHIFT);
292 	MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_CTP, ctp);
293 }
294 
295 static int
296 armadaxp_find_pending_irqs(void)
297 {
298 	struct intrsource *is;
299 	int irq;
300 
301 	irq = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_IIACK) & 0x3ff;
302 
303 	/* Is it a spurious interrupt ?*/
304 	if (irq == 0x3ff)
305 		return 0;
306 	is = armadaxp_pic.pic_sources[irq];
307 	if (is == NULL) {
308 		printf("stray interrupt: %d\n", irq);
309 		return 0;
310 	}
311 
312 	armadaxp_pic_block_irq(&armadaxp_pic, irq);
313 	pic_mark_pending(&armadaxp_pic, irq);
314 
315 	return is->is_ipl;
316 }
317 
318 static void
319 armadaxp_pic_block_irq(struct pic_softc *pic, size_t irq)
320 {
321 
322 	KASSERT(pic->pic_maxsources >= irq);
323 	MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, irq);
324 	MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, irq);
325 }
326 
327 /*
328  * Clock functions
329  */
330 
331 void
332 armadaxp_getclks(void)
333 {
334 	uint64_t sar_reg;
335 	uint8_t  sar_cpu_freq, sar_fab_freq;
336 
337 	if (cputype == CPU_ID_MV88SV584X_V7)
338 		mvTclk = 250000000; /* 250 MHz */
339 	else
340 		mvTclk = 200000000; /* 200 MHz */
341 
342 	sar_reg = (read_miscreg(ARMADAXP_MISC_SAR_HI) << 31) |
343 	    read_miscreg(ARMADAXP_MISC_SAR_LO);
344 
345 	sar_cpu_freq = EXTRACT_XP_CPU_FREQ_FIELD(sar_reg);
346 	sar_fab_freq = EXTRACT_XP_FAB_FREQ_FIELD(sar_reg);
347 
348 	/* Check if CPU frequency field has correct value */
349 	if (sar_cpu_freq >= __arraycount(clock_table_xp))
350 		panic("Reserved value in cpu frequency configuration field: "
351 		    "%d", sar_cpu_freq);
352 
353 	/* Check if fabric frequency field has correct value */
354 	if (sar_fab_freq >= __arraycount(freq_conf_table))
355 		panic("Reserved value in fabric frequency configuration field: "
356 		    "%d", sar_fab_freq);
357 
358 	/* Get CPU clock frequency */
359 	mvPclk = clock_table_xp[sar_cpu_freq] *
360 	    freq_conf_table[sar_fab_freq].vco_cpu;
361 
362 	/* Get L2CLK clock frequency and use as system clock (mvSysclk) */
363 	mvSysclk = mvPclk / freq_conf_table[sar_fab_freq].vco_l2c;
364 
365 	/* Round mvSysclk value to integer MHz */
366 	if (((mvPclk % freq_conf_table[sar_fab_freq].vco_l2c) * 10 /
367 	    freq_conf_table[sar_fab_freq].vco_l2c) >= 5)
368 		mvSysclk++;
369 
370 	mvPclk *= 1000000;
371 	mvSysclk *= 1000000;
372 
373 	curcpu()->ci_data.cpu_cc_freq = mvPclk;
374 }
375 
376 void
377 armada370_getclks(void)
378 {
379 	uint32_t sar;
380 	uint8_t  cpu_freq, fab_freq;
381 
382 	sar = read_miscreg(ARMADAXP_MISC_SAR_LO);
383 	if (sar & 0x00100000)
384 		mvTclk = 200000000; /* 200 MHz */
385 	else
386 		mvTclk = 166666667; /* 166 MHz */
387 
388 	cpu_freq = EXTRACT_370_CPU_FREQ_FIELD(sar);
389 	fab_freq = EXTRACT_370_FAB_FREQ_FIELD(sar);
390 
391 	/* Check if CPU frequency field has correct value */
392 	if (cpu_freq >= __arraycount(clock_table_370))
393 		panic("Reserved value in cpu frequency configuration field: "
394 		    "%d", cpu_freq);
395 
396 	/* Check if fabric frequency field has correct value */
397 	if (fab_freq >= __arraycount(freq_conf_table))
398 		panic("Reserved value in fabric frequency configuration field: "
399 		    "%d", fab_freq);
400 
401 	/* Get CPU clock frequency */
402 	mvPclk = clock_table_370[cpu_freq] *
403 	    freq_conf_table[fab_freq].vco_cpu;
404 
405 	/* Get L2CLK clock frequency and use as system clock (mvSysclk) */
406 	mvSysclk = mvPclk / freq_conf_table[fab_freq].vco_l2c;
407 
408 	/* Round mvSysclk value to integer MHz */
409 	if (((mvPclk % freq_conf_table[fab_freq].vco_l2c) * 10 /
410 	    freq_conf_table[fab_freq].vco_l2c) >= 5)
411 		mvSysclk++;
412 
413 	mvPclk *= 1000000;
414 	mvSysclk *= 1000000;
415 }
416 
417 /*
418  * L2 Cache initialization
419  */
420 
421 int
422 armadaxp_l2_init(bus_addr_t pbase)
423 {
424 	u_int32_t reg;
425 	int ret;
426 
427 	/* Map L2 space */
428 	ret = bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_L2_BASE,
429 	    0x1000, 0, &l2_handle);
430 	if (ret) {
431 		printf("%s: Cannot map L2 register space, ret:%d\n",
432 		    __func__, ret);
433 		return (-1);
434 	}
435 
436 	/* Set L2 policy */
437 	reg = L2_READ(ARMADAXP_L2_AUX_CTRL);
438 	reg &= ~(L2_WBWT_MODE_MASK);
439 	reg &= ~(L2_REP_STRAT_MASK);
440 	reg |= L2_REP_STRAT_SEMIPLRU;
441 	L2_WRITE(ARMADAXP_L2_AUX_CTRL, reg);
442 
443 	/* Invalidate L2 cache */
444 	L2_WRITE(ARMADAXP_L2_INV_WAY, L2_ALL_WAYS);
445 
446 	/* Clear pending L2 interrupts */
447 	L2_WRITE(ARMADAXP_L2_INT_CAUSE, 0x1ff);
448 
449 	/* Enable Cache and TLB maintenance broadcast */
450 	__asm__ __volatile__ ("mrc p15, 1, %0, c15, c2, 0" : "=r"(reg));
451 	reg |= (1 << 8);
452 	__asm__ __volatile__ ("mcr p15, 1, %0, c15, c2, 0" : :"r"(reg));
453 
454 	/*
455 	 * Set the Point of Coherency and Point of Unification to DRAM.
456 	 * This is a reset value but anyway, configure this just in case.
457 	 */
458 	reg = read_mlmbreg(ARMADAXP_L2_CFU);
459 	reg |= (1 << 17) | (1 << 18);
460 	write_mlmbreg(ARMADAXP_L2_CFU, reg);
461 
462 	/* Enable L2 cache */
463 	reg = L2_READ(ARMADAXP_L2_CTRL);
464 	L2_WRITE(ARMADAXP_L2_CTRL, reg | L2_ENABLE);
465 
466 	/* Mark as enabled */
467 	l2cache_state = 1;
468 
469 #ifdef DEBUG
470 	/* Configure and enable counter */
471 	L2_WRITE(ARMADAXP_L2_CNTR_CONF(0), 0xf0000 | (4 << 2));
472 	L2_WRITE(ARMADAXP_L2_CNTR_CONF(1), 0xf0000 | (2 << 2));
473 	L2_WRITE(ARMADAXP_L2_CNTR_CTRL, 0x303);
474 #endif
475 
476 	return (0);
477 }
478 
479 void
480 armadaxp_io_coherency_init(void)
481 {
482 	uint32_t reg;
483 
484 	/* set CIB read snoop command to ReadUnique */
485 	reg = read_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG);
486 	reg &= ~(7 << 16);
487 	reg |= (7 << 16);
488 	write_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG, reg);
489 	/* enable CPUs in SMP group on Fabric coherency */
490 	reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL);
491 	reg &= ~(0x3 << 24);
492 	reg |= (1 << 24);
493 	write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL, reg);
494 
495 	reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG);
496 	reg &= ~(0x3 << 24);
497 	reg |= (1 << 24);
498 	write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG, reg);
499 
500 	/* Mark as enabled */
501 	iocc_state = 1;
502 }
503 
504 int
505 armadaxp_clkgating(struct marvell_attach_args *mva)
506 {
507 	uint32_t val;
508 	int i;
509 
510 	for (i = 0; i < __arraycount(clkgatings); i++) {
511 		if (clkgatings[i].offset == mva->mva_offset) {
512 			val = read_miscreg(ARMADAXP_MISC_PMCGC);
513 			if ((val & clkgatings[i].bits) == clkgatings[i].bits)
514 				/* Clock enabled */
515 				return 0;
516 			return 1;
517 		}
518 	}
519 	/* Clock Gating not support */
520 	return 0;
521 }
522