armadaxp.c revision 1.6 1 /* $NetBSD: armadaxp.c,v 1.6 2013/12/23 04:12:09 kiyohara 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.6 2013/12/23 04:12:09 kiyohara 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_CPU_FREQ_FIELD(sar) (((0x01 & (sar >> 52)) << 3) | \
65 (0x07 & (sar >> 21)))
66 #define EXTRACT_FAB_FREQ_FIELD(sar) (((0x01 & (sar >> 51)) << 4) | \
67 (0x0F & (sar >> 24)))
68
69 #define MPIC_WRITE(reg, val) (bus_space_write_4(&mvsoc_bs_tag, \
70 mpic_handle, reg, val))
71 #define MPIC_CPU_WRITE(reg, val) (bus_space_write_4(&mvsoc_bs_tag, \
72 mpic_cpu_handle, reg, val))
73
74 #define MPIC_READ(reg) (bus_space_read_4(&mvsoc_bs_tag, \
75 mpic_handle, reg))
76 #define MPIC_CPU_READ(reg) (bus_space_read_4(&mvsoc_bs_tag, \
77 mpic_cpu_handle, reg))
78
79 #define L2_WRITE(reg, val) (bus_space_write_4(&mvsoc_bs_tag, \
80 l2_handle, reg, val))
81 #define L2_READ(reg) (bus_space_read_4(&mvsoc_bs_tag, \
82 l2_handle, reg))
83 bus_space_handle_t mpic_cpu_handle;
84 static bus_space_handle_t mpic_handle, l2_handle;
85 int l2cache_state = 0;
86 int iocc_state = 0;
87 #define read_miscreg(r) (*(volatile uint32_t *)(misc_base + (r)))
88 vaddr_t misc_base;
89
90 extern void (*mvsoc_intr_init)(void);
91 static void armadaxp_intr_init(void);
92
93 static void armadaxp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
94 static void armadaxp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
95 static void armadaxp_pic_establish_irq(struct pic_softc *, struct intrsource *);
96 static void armadaxp_pic_set_priority(struct pic_softc *, int);
97
98 static int armadaxp_find_pending_irqs(void);
99 static void armadaxp_pic_block_irq(struct pic_softc *, size_t);
100 void armadaxp_io_coherency_init(void);
101 int armadaxp_l2_init(bus_addr_t);
102
103 struct vco_freq_ratio {
104 uint8_t vco_cpu; /* VCO to CLK0(CPU) clock ratio */
105 uint8_t vco_l2c; /* VCO to NB(L2 cache) clock ratio */
106 uint8_t vco_hcl; /* VCO to HCLK(DDR controller) clock ratio */
107 uint8_t vco_ddr; /* VCO to DR(DDR memory) clock ratio */
108 };
109
110 static struct vco_freq_ratio freq_conf_table[] = {
111 /*00*/ { 1, 1, 4, 2 },
112 /*01*/ { 1, 2, 2, 2 },
113 /*02*/ { 2, 2, 6, 3 },
114 /*03*/ { 2, 2, 3, 3 },
115 /*04*/ { 1, 2, 3, 3 },
116 /*05*/ { 1, 2, 4, 2 },
117 /*06*/ { 1, 1, 2, 2 },
118 /*07*/ { 2, 3, 6, 6 },
119 /*08*/ { 2, 3, 5, 5 },
120 /*09*/ { 1, 2, 6, 3 },
121 /*10*/ { 2, 4, 10, 5 },
122 /*11*/ { 1, 3, 6, 6 },
123 /*12*/ { 1, 2, 5, 5 },
124 /*13*/ { 1, 3, 6, 3 },
125 /*14*/ { 1, 2, 5, 5 },
126 /*15*/ { 2, 2, 5, 5 },
127 /*16*/ { 1, 1, 3, 3 },
128 /*17*/ { 2, 5, 10, 10 },
129 /*18*/ { 1, 3, 8, 4 },
130 /*19*/ { 1, 1, 2, 1 },
131 /*20*/ { 2, 3, 6, 3 },
132 /*21*/ { 1, 2, 8, 4 },
133 /*22*/ { 2, 5, 10, 5 }
134 };
135
136 static uint16_t cpu_clock_table[] = {
137 1000, 1066, 1200, 1333, 1500, 1666, 1800, 2000, 600, 667, 800, 1600,
138 2133, 2200, 2400 };
139
140 static struct pic_ops armadaxp_picops = {
141 .pic_unblock_irqs = armadaxp_pic_unblock_irqs,
142 .pic_block_irqs = armadaxp_pic_block_irqs,
143 .pic_establish_irq = armadaxp_pic_establish_irq,
144 .pic_set_priority = armadaxp_pic_set_priority,
145 };
146
147 static struct pic_softc armadaxp_pic = {
148 .pic_ops = &armadaxp_picops,
149 .pic_name = "armadaxp",
150 };
151
152 static struct {
153 bus_size_t offset;
154 uint32_t bits;
155 } clkgatings[]= {
156 { ARMADAXP_GBE3_BASE, (1 << 1) },
157 { ARMADAXP_GBE2_BASE, (1 << 2) },
158 { ARMADAXP_GBE1_BASE, (1 << 3) },
159 { ARMADAXP_GBE0_BASE, (1 << 4) },
160 { MVSOC_PEX_BASE, (1 << 5) },
161 { ARMADAXP_PEX01_BASE, (1 << 6) },
162 { ARMADAXP_PEX02_BASE, (1 << 7) },
163 { ARMADAXP_PEX03_BASE, (1 << 8) },
164 { ARMADAXP_PEX10_BASE, (1 << 9) },
165 { ARMADAXP_PEX11_BASE, (1 << 10) },
166 { ARMADAXP_PEX12_BASE, (1 << 11) },
167 { ARMADAXP_PEX13_BASE, (1 << 12) },
168 #if 0
169 { NetA, (1 << 13) },
170 #endif
171 { ARMADAXP_SATAHC_BASE, (1 << 14) | (1 << 15) | (1 << 29) | (1 << 30) },
172 { ARMADAXP_LCD_BASE, (1 << 16) },
173 { ARMADAXP_SDIO_BASE, (1 << 17) },
174 { ARMADAXP_USB1_BASE, (1 << 19) },
175 { ARMADAXP_USB2_BASE, (1 << 20) },
176 { ARMADAXP_PEX2_BASE, (1 << 26) },
177 { ARMADAXP_PEX3_BASE, (1 << 27) },
178 #if 0
179 { DDR, (1 << 28) },
180 #endif
181 };
182
183 /*
184 * armadaxp_intr_bootstrap:
185 *
186 * Initialize the rest of the interrupt subsystem, making it
187 * ready to handle interrupts from devices.
188 */
189 void
190 armadaxp_intr_bootstrap(bus_addr_t pbase)
191 {
192 int i;
193
194 /* Map MPIC base and MPIC percpu base registers */
195 if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_BASE,
196 0x500, 0, &mpic_handle) != 0)
197 panic("%s: Could not map MPIC registers", __func__);
198 if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_CPU_BASE,
199 0x800, 0, &mpic_cpu_handle) != 0)
200 panic("%s: Could not map MPIC percpu registers", __func__);
201
202 /* Disable all interrupts */
203 for (i = 0; i < 116; i++)
204 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, i);
205
206 mvsoc_intr_init = armadaxp_intr_init;
207 }
208
209 static void
210 armadaxp_intr_init(void)
211 {
212 int ctrl;
213
214 /* Get max interrupts */
215 armadaxp_pic.pic_maxsources =
216 ((MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL) >> 2) & 0x7FF);
217
218 if (!armadaxp_pic.pic_maxsources)
219 armadaxp_pic.pic_maxsources = 116;
220
221 pic_add(&armadaxp_pic, 0);
222
223 ctrl = MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL);
224 /* Enable IRQ prioritization */
225 ctrl |= (1 << 0);
226 MPIC_WRITE(ARMADAXP_MLMB_MPIC_CTRL, ctrl);
227
228 find_pending_irqs = armadaxp_find_pending_irqs;
229 }
230
231 static void
232 armadaxp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
233 uint32_t irq_mask)
234 {
235 int n;
236
237 while (irq_mask != 0) {
238 n = ffs(irq_mask) - 1;
239 KASSERT(pic->pic_maxsources >= n + irqbase);
240 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISE, n + irqbase);
241 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ICM, n + irqbase);
242 if ((n + irqbase) == 0)
243 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_DOORBELL_MASK,
244 0xffffffff);
245 irq_mask &= ~__BIT(n);
246 }
247 }
248
249 static void
250 armadaxp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
251 uint32_t irq_mask)
252 {
253 int n;
254
255 while (irq_mask != 0) {
256 n = ffs(irq_mask) - 1;
257 KASSERT(pic->pic_maxsources >= n + irqbase);
258 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, n + irqbase);
259 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, n + irqbase);
260 irq_mask &= ~__BIT(n);
261 }
262 }
263
264 static void
265 armadaxp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
266 {
267 int tmp;
268 KASSERT(pic->pic_maxsources >= is->is_irq);
269 tmp = MPIC_READ(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4);
270 /* Clear previous priority */
271 tmp &= ~(0xf << MPIC_ISCR_SHIFT);
272 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4,
273 tmp | (is->is_ipl << MPIC_ISCR_SHIFT));
274 }
275
276 static void
277 armadaxp_pic_set_priority(struct pic_softc *pic, int ipl)
278 {
279 int ctp;
280
281 ctp = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_CTP);
282 ctp &= ~(0xf << MPIC_CTP_SHIFT);
283 ctp |= (ipl << MPIC_CTP_SHIFT);
284 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_CTP, ctp);
285 }
286
287 static int
288 armadaxp_find_pending_irqs(void)
289 {
290 struct intrsource *is;
291 int irq;
292
293 irq = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_IIACK) & 0x3ff;
294
295 /* Is it a spurious interrupt ?*/
296 if (irq == 0x3ff)
297 return 0;
298 is = armadaxp_pic.pic_sources[irq];
299 if (is == NULL) {
300 printf("stray interrupt: %d\n", irq);
301 return 0;
302 }
303
304 armadaxp_pic_block_irq(&armadaxp_pic, irq);
305 pic_mark_pending(&armadaxp_pic, irq);
306
307 return is->is_ipl;
308 }
309
310 static void
311 armadaxp_pic_block_irq(struct pic_softc *pic, size_t irq)
312 {
313
314 KASSERT(pic->pic_maxsources >= irq);
315 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, irq);
316 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, irq);
317 }
318
319 /*
320 * Clock functions
321 */
322
323 void
324 armadaxp_getclks(void)
325 {
326 uint64_t sar_reg;
327 uint8_t sar_cpu_freq, sar_fab_freq, array_size;
328
329 if (cputype == CPU_ID_MV88SV584X_V7)
330 mvTclk = 250000000; /* 250 MHz */
331 else
332 mvTclk = 200000000; /* 200 MHz */
333
334 sar_reg = (read_miscreg(ARMADAXP_MISC_SAR_HI) << 31) |
335 read_miscreg(ARMADAXP_MISC_SAR_LO);
336
337 sar_cpu_freq = EXTRACT_CPU_FREQ_FIELD(sar_reg);
338 sar_fab_freq = EXTRACT_FAB_FREQ_FIELD(sar_reg);
339
340 /* Check if CPU frequency field has correct value */
341 array_size = sizeof(cpu_clock_table) / sizeof(cpu_clock_table[0]);
342 if (sar_cpu_freq >= array_size)
343 panic("Reserved value in cpu frequency configuration field: "
344 "%d", sar_cpu_freq);
345
346 /* Check if fabric frequency field has correct value */
347 array_size = sizeof(freq_conf_table) / sizeof(freq_conf_table[0]);
348 if (sar_fab_freq >= array_size)
349 panic("Reserved value in fabric frequency configuration field: "
350 "%d", sar_fab_freq);
351
352 /* Get CPU clock frequency */
353 mvPclk = cpu_clock_table[sar_cpu_freq] *
354 freq_conf_table[sar_fab_freq].vco_cpu;
355
356 /* Get L2CLK clock frequency and use as system clock (mvSysclk) */
357 mvSysclk = mvPclk / freq_conf_table[sar_fab_freq].vco_l2c;
358
359 /* Round mvSysclk value to integer MHz */
360 if (((mvPclk % freq_conf_table[sar_fab_freq].vco_l2c) * 10 /
361 freq_conf_table[sar_fab_freq].vco_l2c) >= 5)
362 mvSysclk++;
363
364 mvPclk = mvPclk * 1000000;
365 mvSysclk = mvSysclk * 1000000;
366 }
367
368 /*
369 * L2 Cache initialization
370 */
371
372 int
373 armadaxp_l2_init(bus_addr_t pbase)
374 {
375 u_int32_t reg;
376 int ret;
377
378 /* Map L2 space */
379 ret = bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_L2_BASE,
380 0x1000, 0, &l2_handle);
381 if (ret) {
382 printf("%s: Cannot map L2 register space, ret:%d\n",
383 __func__, ret);
384 return (-1);
385 }
386
387 /* Set L2 policy */
388 reg = L2_READ(ARMADAXP_L2_AUX_CTRL);
389 reg &= ~(L2_WBWT_MODE_MASK);
390 reg &= ~(L2_REP_STRAT_MASK);
391 reg |= L2_REP_STRAT_SEMIPLRU;
392 L2_WRITE(ARMADAXP_L2_AUX_CTRL, reg);
393
394 /* Invalidate L2 cache */
395 L2_WRITE(ARMADAXP_L2_INV_WAY, L2_ALL_WAYS);
396
397 /* Clear pending L2 interrupts */
398 L2_WRITE(ARMADAXP_L2_INT_CAUSE, 0x1ff);
399
400 /* Enable Cache and TLB maintenance broadcast */
401 __asm__ __volatile__ ("mrc p15, 1, %0, c15, c2, 0" : "=r"(reg));
402 reg |= (1 << 8);
403 __asm__ __volatile__ ("mcr p15, 1, %0, c15, c2, 0" : :"r"(reg));
404
405 /*
406 * Set the Point of Coherency and Point of Unification to DRAM.
407 * This is a reset value but anyway, configure this just in case.
408 */
409 reg = read_mlmbreg(ARMADAXP_L2_CFU);
410 reg |= (1 << 17) | (1 << 18);
411 write_mlmbreg(ARMADAXP_L2_CFU, reg);
412
413 /* Enable L2 cache */
414 reg = L2_READ(ARMADAXP_L2_CTRL);
415 L2_WRITE(ARMADAXP_L2_CTRL, reg | L2_ENABLE);
416
417 /* Mark as enabled */
418 l2cache_state = 1;
419
420 #ifdef DEBUG
421 /* Configure and enable counter */
422 L2_WRITE(ARMADAXP_L2_CNTR_CONF(0), 0xf0000 | (4 << 2));
423 L2_WRITE(ARMADAXP_L2_CNTR_CONF(1), 0xf0000 | (2 << 2));
424 L2_WRITE(ARMADAXP_L2_CNTR_CTRL, 0x303);
425 #endif
426
427 return (0);
428 }
429
430 void
431 armadaxp_io_coherency_init(void)
432 {
433 uint32_t reg;
434
435 /* set CIB read snoop command to ReadUnique */
436 reg = read_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG);
437 reg &= ~(7 << 16);
438 reg |= (7 << 16);
439 write_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG, reg);
440 /* enable CPUs in SMP group on Fabric coherency */
441 reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL);
442 reg &= ~(0x3 << 24);
443 reg |= (1 << 24);
444 write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL, reg);
445
446 reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG);
447 reg &= ~(0x3 << 24);
448 reg |= (1 << 24);
449 write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG, reg);
450
451 /* Mark as enabled */
452 iocc_state = 1;
453 }
454
455 int
456 armadaxp_clkgating(struct marvell_attach_args *mva)
457 {
458 uint32_t val;
459 int i;
460
461 for (i = 0; i < __arraycount(clkgatings); i++) {
462 if (clkgatings[i].offset == mva->mva_offset) {
463 val = read_miscreg(ARMADAXP_MISC_PMCGC);
464 if ((val & clkgatings[i].bits) == clkgatings[i].bits)
465 /* Clock enabled */
466 return 0;
467 return 1;
468 }
469 }
470 /* Clock Gating not support */
471 return 0;
472 }
473