armadaxp.c revision 1.5 1 /* $NetBSD: armadaxp.c,v 1.5 2013/12/23 03:19:43 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.5 2013/12/23 03:19:43 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 /*
153 * armadaxp_intr_bootstrap:
154 *
155 * Initialize the rest of the interrupt subsystem, making it
156 * ready to handle interrupts from devices.
157 */
158 void
159 armadaxp_intr_bootstrap(bus_addr_t pbase)
160 {
161 int i;
162
163 /* Map MPIC base and MPIC percpu base registers */
164 if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_BASE,
165 0x500, 0, &mpic_handle) != 0)
166 panic("%s: Could not map MPIC registers", __func__);
167 if (bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_MLMB_MPIC_CPU_BASE,
168 0x800, 0, &mpic_cpu_handle) != 0)
169 panic("%s: Could not map MPIC percpu registers", __func__);
170
171 /* Disable all interrupts */
172 for (i = 0; i < 116; i++)
173 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, i);
174
175 mvsoc_intr_init = armadaxp_intr_init;
176 }
177
178 static void
179 armadaxp_intr_init(void)
180 {
181 int ctrl;
182
183 /* Get max interrupts */
184 armadaxp_pic.pic_maxsources =
185 ((MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL) >> 2) & 0x7FF);
186
187 if (!armadaxp_pic.pic_maxsources)
188 armadaxp_pic.pic_maxsources = 116;
189
190 pic_add(&armadaxp_pic, 0);
191
192 ctrl = MPIC_READ(ARMADAXP_MLMB_MPIC_CTRL);
193 /* Enable IRQ prioritization */
194 ctrl |= (1 << 0);
195 MPIC_WRITE(ARMADAXP_MLMB_MPIC_CTRL, ctrl);
196
197 find_pending_irqs = armadaxp_find_pending_irqs;
198 }
199
200 static void
201 armadaxp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
202 uint32_t irq_mask)
203 {
204 int n;
205
206 while (irq_mask != 0) {
207 n = ffs(irq_mask) - 1;
208 KASSERT(pic->pic_maxsources >= n + irqbase);
209 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISE, n + irqbase);
210 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ICM, n + irqbase);
211 if ((n + irqbase) == 0)
212 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_DOORBELL_MASK,
213 0xffffffff);
214 irq_mask &= ~__BIT(n);
215 }
216 }
217
218 static void
219 armadaxp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
220 uint32_t irq_mask)
221 {
222 int n;
223
224 while (irq_mask != 0) {
225 n = ffs(irq_mask) - 1;
226 KASSERT(pic->pic_maxsources >= n + irqbase);
227 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, n + irqbase);
228 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, n + irqbase);
229 irq_mask &= ~__BIT(n);
230 }
231 }
232
233 static void
234 armadaxp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
235 {
236 int tmp;
237 KASSERT(pic->pic_maxsources >= is->is_irq);
238 tmp = MPIC_READ(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4);
239 /* Clear previous priority */
240 tmp &= ~(0xf << MPIC_ISCR_SHIFT);
241 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ISCR_BASE + is->is_irq * 4,
242 tmp | (is->is_ipl << MPIC_ISCR_SHIFT));
243 }
244
245 static void
246 armadaxp_pic_set_priority(struct pic_softc *pic, int ipl)
247 {
248 int ctp;
249
250 ctp = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_CTP);
251 ctp &= ~(0xf << MPIC_CTP_SHIFT);
252 ctp |= (ipl << MPIC_CTP_SHIFT);
253 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_CTP, ctp);
254 }
255
256 static int
257 armadaxp_find_pending_irqs(void)
258 {
259 struct intrsource *is;
260 int irq;
261
262 irq = MPIC_CPU_READ(ARMADAXP_MLMB_MPIC_IIACK) & 0x3ff;
263
264 /* Is it a spurious interrupt ?*/
265 if (irq == 0x3ff)
266 return 0;
267 is = armadaxp_pic.pic_sources[irq];
268 if (is == NULL) {
269 printf("stray interrupt: %d\n", irq);
270 return 0;
271 }
272
273 armadaxp_pic_block_irq(&armadaxp_pic, irq);
274 pic_mark_pending(&armadaxp_pic, irq);
275
276 return is->is_ipl;
277 }
278
279 static void
280 armadaxp_pic_block_irq(struct pic_softc *pic, size_t irq)
281 {
282
283 KASSERT(pic->pic_maxsources >= irq);
284 MPIC_WRITE(ARMADAXP_MLMB_MPIC_ICE, irq);
285 MPIC_CPU_WRITE(ARMADAXP_MLMB_MPIC_ISM, irq);
286 }
287
288 /*
289 * Clock functions
290 */
291
292 void
293 armadaxp_getclks(void)
294 {
295 uint64_t sar_reg;
296 uint8_t sar_cpu_freq, sar_fab_freq, array_size;
297
298 if (cputype == CPU_ID_MV88SV584X_V7)
299 mvTclk = 250000000; /* 250 MHz */
300 else
301 mvTclk = 200000000; /* 200 MHz */
302
303 sar_reg = (read_miscreg(ARMADAXP_MISC_SAR_HI) << 31) |
304 read_miscreg(ARMADAXP_MISC_SAR_LO);
305
306 sar_cpu_freq = EXTRACT_CPU_FREQ_FIELD(sar_reg);
307 sar_fab_freq = EXTRACT_FAB_FREQ_FIELD(sar_reg);
308
309 /* Check if CPU frequency field has correct value */
310 array_size = sizeof(cpu_clock_table) / sizeof(cpu_clock_table[0]);
311 if (sar_cpu_freq >= array_size)
312 panic("Reserved value in cpu frequency configuration field: "
313 "%d", sar_cpu_freq);
314
315 /* Check if fabric frequency field has correct value */
316 array_size = sizeof(freq_conf_table) / sizeof(freq_conf_table[0]);
317 if (sar_fab_freq >= array_size)
318 panic("Reserved value in fabric frequency configuration field: "
319 "%d", sar_fab_freq);
320
321 /* Get CPU clock frequency */
322 mvPclk = cpu_clock_table[sar_cpu_freq] *
323 freq_conf_table[sar_fab_freq].vco_cpu;
324
325 /* Get L2CLK clock frequency and use as system clock (mvSysclk) */
326 mvSysclk = mvPclk / freq_conf_table[sar_fab_freq].vco_l2c;
327
328 /* Round mvSysclk value to integer MHz */
329 if (((mvPclk % freq_conf_table[sar_fab_freq].vco_l2c) * 10 /
330 freq_conf_table[sar_fab_freq].vco_l2c) >= 5)
331 mvSysclk++;
332
333 mvPclk = mvPclk * 1000000;
334 mvSysclk = mvSysclk * 1000000;
335 }
336
337 /*
338 * L2 Cache initialization
339 */
340
341 int
342 armadaxp_l2_init(bus_addr_t pbase)
343 {
344 u_int32_t reg;
345 int ret;
346
347 /* Map L2 space */
348 ret = bus_space_map(&mvsoc_bs_tag, pbase + ARMADAXP_L2_BASE,
349 0x1000, 0, &l2_handle);
350 if (ret) {
351 printf("%s: Cannot map L2 register space, ret:%d\n",
352 __func__, ret);
353 return (-1);
354 }
355
356 /* Set L2 policy */
357 reg = L2_READ(ARMADAXP_L2_AUX_CTRL);
358 reg &= ~(L2_WBWT_MODE_MASK);
359 reg &= ~(L2_REP_STRAT_MASK);
360 reg |= L2_REP_STRAT_SEMIPLRU;
361 L2_WRITE(ARMADAXP_L2_AUX_CTRL, reg);
362
363 /* Invalidate L2 cache */
364 L2_WRITE(ARMADAXP_L2_INV_WAY, L2_ALL_WAYS);
365
366 /* Clear pending L2 interrupts */
367 L2_WRITE(ARMADAXP_L2_INT_CAUSE, 0x1ff);
368
369 /* Enable Cache and TLB maintenance broadcast */
370 __asm__ __volatile__ ("mrc p15, 1, %0, c15, c2, 0" : "=r"(reg));
371 reg |= (1 << 8);
372 __asm__ __volatile__ ("mcr p15, 1, %0, c15, c2, 0" : :"r"(reg));
373
374 /*
375 * Set the Point of Coherency and Point of Unification to DRAM.
376 * This is a reset value but anyway, configure this just in case.
377 */
378 reg = read_mlmbreg(ARMADAXP_L2_CFU);
379 reg |= (1 << 17) | (1 << 18);
380 write_mlmbreg(ARMADAXP_L2_CFU, reg);
381
382 /* Enable L2 cache */
383 reg = L2_READ(ARMADAXP_L2_CTRL);
384 L2_WRITE(ARMADAXP_L2_CTRL, reg | L2_ENABLE);
385
386 /* Mark as enabled */
387 l2cache_state = 1;
388
389 #ifdef DEBUG
390 /* Configure and enable counter */
391 L2_WRITE(ARMADAXP_L2_CNTR_CONF(0), 0xf0000 | (4 << 2));
392 L2_WRITE(ARMADAXP_L2_CNTR_CONF(1), 0xf0000 | (2 << 2));
393 L2_WRITE(ARMADAXP_L2_CNTR_CTRL, 0x303);
394 #endif
395
396 return (0);
397 }
398
399 void
400 armadaxp_io_coherency_init(void)
401 {
402 uint32_t reg;
403
404 /* set CIB read snoop command to ReadUnique */
405 reg = read_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG);
406 reg &= ~(7 << 16);
407 reg |= (7 << 16);
408 write_mlmbreg(MVSOC_MLMB_CIB_CTRL_CFG, reg);
409 /* enable CPUs in SMP group on Fabric coherency */
410 reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL);
411 reg &= ~(0x3 << 24);
412 reg |= (1 << 24);
413 write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CTRL, reg);
414
415 reg = read_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG);
416 reg &= ~(0x3 << 24);
417 reg |= (1 << 24);
418 write_mlmbreg(MVSOC_MLMB_COHERENCY_FABRIC_CFG, reg);
419
420 /* Mark as enabled */
421 iocc_state = 1;
422 }
423