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