armadaxp.c revision 1.7.2.1 1 /* $NetBSD: armadaxp.c,v 1.7.2.1 2014/08/10 06:53:52 tls 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.7.2.1 2014/08/10 06:53:52 tls 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