bcu_vrip.c revision 1.16 1 /* $NetBSD: bcu_vrip.c,v 1.16 2002/02/10 13:23:55 takemura Exp $ */
2
3 /*-
4 * Copyright (c) 1999-2001 SATO Kazumi. All rights reserved.
5 * Copyright (c) 1999, 2002 PocketBSD Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the PocketBSD project
18 * and its contributors.
19 * 4. Neither the name of the project nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/reboot.h>
41
42 #include <machine/bus.h>
43 #include <machine/debug.h>
44 #include <machine/platid.h>
45 #include <machine/platid_mask.h>
46
47 #include <mips/cpuregs.h>
48
49 #include "opt_vr41xx.h"
50 #include <hpcmips/vr/vr.h>
51 #include <hpcmips/vr/vrcpudef.h>
52 #include <hpcmips/vr/vripif.h>
53 #include <hpcmips/vr/vripvar.h>
54 #include <hpcmips/vr/vripreg.h>
55 #include <hpcmips/vr/bcureg.h>
56 #include <hpcmips/vr/bcuvar.h>
57
58 static int vrbcu_match(struct device *, struct cfdata *, void *);
59 static void vrbcu_attach(struct device *, struct device *, void *);
60
61 static void vrbcu_write(struct vrbcu_softc *, int, unsigned short);
62 static unsigned short vrbcu_read(struct vrbcu_softc *, int);
63
64 static void vrbcu_dump_regs(void);
65
66 char *vr_cpuname=NULL;
67 int vr_major=-1;
68 int vr_minor=-1;
69 int vr_cpuid=-1;
70
71 struct cfattach vrbcu_ca = {
72 sizeof(struct vrbcu_softc), vrbcu_match, vrbcu_attach
73 };
74
75 struct vrbcu_softc *the_bcu_sc = NULL;
76
77 #ifdef SINGLE_VRIP_BASE
78 #define vrbcu_addr() VRIP_BCU_ADDR
79 #else
80 static bus_addr_t vrbcu_addr(void);
81 static bus_addr_t
82 vrbcu_addr()
83 {
84 static bus_addr_t addr = NULL;
85 static struct platid_data addrs[] = {
86 { &platid_mask_CPU_MIPS_VR_4102, (void *)VR4102_BCU_ADDR },
87 { &platid_mask_CPU_MIPS_VR_4111, (void *)VR4102_BCU_ADDR },
88 { &platid_mask_CPU_MIPS_VR_4121, (void *)VR4102_BCU_ADDR },
89 { &platid_mask_CPU_MIPS_VR_4122, (void *)VR4122_BCU_ADDR },
90 { &platid_mask_CPU_MIPS_VR_4131, (void *)VR4122_BCU_ADDR },
91 { &platid_mask_CPU_MIPS_VR_4181, (void *)VR4181_BCU_ADDR },
92 { NULL, NULL } /* terminator, don't delete */
93 };
94 struct platid_data *p;
95
96 if (addr == NULL) {
97 if ((p = platid_search_data(&platid, addrs)) == NULL)
98 panic("%s: can't find VR BCU address\n", __FUNCTION__);
99 addr = (bus_addr_t)p->data;
100 }
101
102 return (addr);
103 }
104 #endif /* SINGLE_VRIP_BASE */
105
106 static inline void
107 vrbcu_write(struct vrbcu_softc *sc, int port, unsigned short val)
108 {
109
110 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
111 }
112
113 static inline unsigned short
114 vrbcu_read(struct vrbcu_softc *sc, int port)
115 {
116
117 return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port));
118 }
119
120 static int
121 vrbcu_match(struct device *parent, struct cfdata *cf, void *aux)
122 {
123
124 return (2);
125 }
126
127 static void
128 vrbcu_attach(struct device *parent, struct device *self, void *aux)
129 {
130 struct vrip_attach_args *va = aux;
131 struct vrbcu_softc *sc = (struct vrbcu_softc *)self;
132
133 sc->sc_iot = va->va_iot;
134 bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
135 0, /* no flags */
136 &sc->sc_ioh);
137
138 printf("\n");
139 the_bcu_sc = sc;
140 vrbcu_dump_regs();
141 }
142
143 static void
144 vrbcu_dump_regs()
145 {
146 struct vrbcu_softc *sc = the_bcu_sc;
147 int cpuclock = 0, tclock = 0, vtclock = 0, cpuid;
148 #if !defined(ONLY_VR4102)
149 int spdreg;
150 #endif
151 #ifdef VRBCUDEBUG
152 int reg;
153 #endif /* VRBCUDEBUG */
154
155 cpuid = vrbcu_vrip_getcpuid();
156 #if !defined(ONLY_VR4181) && !defined(ONLY_VR4102)
157 if (cpuid != BCUREVID_FIXRID_4181
158 && cpuid <= BCUREVID_RID_4131
159 && cpuid >= BCUREVID_RID_4111) {
160 spdreg = vrbcu_read(sc, BCUCLKSPEED_REG_W);
161 #ifdef VRBCUDEBUG
162 printf("vrbcu: CLKSPEED %x: \n", spdreg);
163 #endif /* VRBCUDEBUG */
164 }
165 #endif
166 #if defined VR4181
167 if (cpuid == BCUREVID_FIXRID_4181){
168 spdreg = vrbcu_read(sc, BCU81CLKSPEED_REG_W);
169 #ifdef VRBCUDEBUG
170 printf("vrbcu: CLKSPEED %x: \n", spdreg);
171 #endif /* VRBCUDEBUG */
172 }
173 #endif
174
175 cpuclock = vrbcu_vrip_getcpuclock();
176
177 switch (cpuid) {
178 #if defined VR4181
179 case BCUREVID_FIXRID_4181:
180 switch ((spdreg & BCU81CLKSPEED_DIVTMASK) >>
181 BCU81CLKSPEED_DIVTSHFT){
182 case BCU81CLKSPEED_DIVT1:
183 vtclock = tclock = cpuclock;
184 break;
185 case BCU81CLKSPEED_DIVT2:
186 vtclock = tclock = cpuclock/2;
187 break;
188 case BCU81CLKSPEED_DIVT3:
189 vtclock = tclock = cpuclock/3;
190 break;
191 case BCU81CLKSPEED_DIVT4:
192 vtclock = tclock = cpuclock/4;
193 break;
194 default:
195 vtclock = tclock = 0;
196 }
197 break;
198 #endif /* VR4181 */
199 case BCUREVID_RID_4101:
200 case BCUREVID_RID_4102:
201 vtclock = tclock = cpuclock/2;
202 break;
203 #if defined VR4111
204 case BCUREVID_RID_4111:
205 if ((spdreg&BCUCLKSPEED_DIVT2B) == 0)
206 vtclock = tclock = cpuclock/2;
207 else if ((spdreg&BCUCLKSPEED_DIVT3B) == 0)
208 vtclock = tclock = cpuclock/3;
209 else if ((spdreg&BCUCLKSPEED_DIVT4B) == 0)
210 vtclock = tclock = cpuclock/4;
211 else
212 vtclock = tclock = 0; /* XXX */
213 break;
214 #endif /* VR4111 */
215 #if defined VR4121
216 case BCUREVID_RID_4121:
217 {
218 int vt;
219 tclock = cpuclock / ((spdreg & BCUCLKSPEED_DIVTMASK) >>
220 BCUCLKSPEED_DIVTSHFT);
221 vt = ((spdreg & BCUCLKSPEED_DIVVTMASK) >>
222 BCUCLKSPEED_DIVVTSHFT);
223 if (vt == 0)
224 vtclock = 0; /* XXX */
225 else if (vt < 0x9)
226 vtclock = cpuclock / vt;
227 else
228 vtclock = cpuclock / ((vt - 8)*2+1) * 2;
229 }
230 break;
231 #endif /* VR4121 */
232 #if defined VR4122 || defined VR4131
233 case BCUREVID_RID_4122:
234 case BCUREVID_RID_4131:
235 {
236 int vtdiv;
237
238 vtdiv = ((spdreg & BCUCLKSPEED_VTDIVMODE) >>
239 BCUCLKSPEED_VTDIVSHFT);
240 if (vtdiv == 0 || vtdiv > BCUCLKSPEED_VTDIV6)
241 vtclock = 0; /* XXX */
242 else
243 vtclock = cpuclock / vtdiv;
244 tclock = vtclock /
245 (((spdreg & BCUCLKSPEED_TDIVMODE) >>
246 BCUCLKSPEED_TDIVSHFT) ? 4 : 2);
247 }
248 break;
249 #endif /* VR4122 || VR4131 */
250 default:
251 break;
252 }
253 if (tclock)
254 printf("%s: cpu %d.%03dMHz, bus %d.%03dMHz, ram %d.%03dMHz\n",
255 sc->sc_dev.dv_xname,
256 cpuclock/1000000, (cpuclock%1000000)/1000,
257 tclock/1000000, (tclock%1000000)/1000,
258 vtclock/1000000, (vtclock%1000000)/1000);
259 else {
260 printf("%s: cpu %d.%03dMHz\n",
261 sc->sc_dev.dv_xname,
262 cpuclock/1000000, (cpuclock%1000000)/1000);
263 printf("%s: UNKNOWN BUS CLOCK SPEED:"
264 " CPU is UNKNOWN or NOT CONFIGURED\n",
265 sc->sc_dev.dv_xname);
266 }
267 #ifdef VRBCUDEBUG
268 reg = vrbcu_read(sc, BCUCNT1_REG_W);
269 printf("vrbcu: CNT1 %x: ", reg);
270 dbg_bit_print(reg);
271 #if !defined(ONLY_VR4181)
272 if (cpuid != BCUREVID_FIXRID_4181
273 && cpuid <= BCUREVID_RID_4121
274 && cpuid >= BCUREVID_RID_4102) {
275 reg = vrbcu_read(sc, BCUCNT2_REG_W);
276 printf("vrbcu: CNT2 %x: ", reg);
277 dbg_bit_print(reg);
278 }
279 #endif /* !defined ONLY_VR4181 */
280 #if !defined(ONLY_VR4181) || !defined(ONLY_VR4122_4131)
281 if (cpuid != BCUREVID_FIXRID_4181
282 && cpuid <= BCUREVID_RID_4121
283 && cpuid >= BCUREVID_RID_4102) {
284 reg = vrbcu_read(sc, BCUSPEED_REG_W);
285 printf("vrbcu: SPEED %x: ", reg);
286 dbg_bit_print(reg);
287 reg = vrbcu_read(sc, BCUERRST_REG_W);
288 printf("vrbcu: ERRST %x: ", reg);
289 dbg_bit_print(reg);
290 reg = vrbcu_read(sc, BCURFCNT_REG_W);
291 printf("vrbcu: RFCNT %x\n", reg);
292 reg = vrbcu_read(sc, BCUREFCOUNT_REG_W);
293 printf("vrbcu: RFCOUNT %x\n", reg);
294 }
295 #endif /* !defined(ONLY_VR4181) || !defined(ONLY_VR4122_4131) */
296 #if !defined(ONLY_VR4181)
297 if (cpuid != BCUREVID_FIXRID_4181
298 && cpuid <= BCUREVID_RID_4131
299 && cpuid >= BCUREVID_RID_4111)
300 {
301 reg = vrbcu_read(sc, BCUCNT3_REG_W);
302 printf("vrbcu: CNT3 %x: ", reg);
303 dbg_bit_print(reg);
304 }
305 #endif /* !defined ONLY_VR4181 */
306 #endif /* VRBCUDEBUG */
307
308 }
309
310 static char *cpuname[] = {
311 "VR4101", /* 0 */
312 "VR4102", /* 1 */
313 "VR4111", /* 2 */
314 "VR4121", /* 3 */
315 "VR4122", /* 4 */
316 "VR4131", /* 5 */
317 "UNKNOWN",
318 "UNKNOWN",
319 "UNKNOWN",
320 "UNKNOWN",
321 "UNKNOWN",
322 "UNKNOWN",
323 "UNKNOWN",
324 "UNKNOWN",
325 "UNKNOWN",
326 "UNKNOWN",
327 "VR4181", /* 0x10 + 0 */
328 };
329
330 int
331 vrbcu_vrip_getcpuid(void)
332 {
333 volatile u_int16_t *revreg;
334
335 if (vr_cpuid != -1)
336 return (vr_cpuid);
337
338 if (vr_cpuid == -1) {
339 if (vrbcu_addr() == VR4181_BCU_ADDR)
340 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1
341 ((vrbcu_addr() + BCU81REVID_REG_W));
342 else
343 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1
344 ((vrbcu_addr() + BCUREVID_REG_W));
345
346 vr_cpuid = *revreg;
347 vr_cpuid = (vr_cpuid&BCUREVID_RIDMASK)>>BCUREVID_RIDSHFT;
348 if (vrbcu_addr() == VR4181_BCU_ADDR
349 && vr_cpuid == BCUREVID_RID_4181) /* conflict vr4101 */
350 vr_cpuid = BCUREVID_FIXRID_4181;
351 }
352 return (vr_cpuid);
353 }
354
355 char *
356 vrbcu_vrip_getcpuname(void)
357 {
358 int cpuid;
359
360 if (vr_cpuname != NULL)
361 return (vr_cpuname);
362
363 cpuid = vrbcu_vrip_getcpuid();
364 vr_cpuname = cpuname[cpuid];
365
366 return (vr_cpuname);
367 }
368
369
370 int
371 vrbcu_vrip_getcpumajor(void)
372 {
373 volatile u_int16_t *revreg;
374
375 if (vr_major != -1)
376 return (vr_major);
377
378 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1
379 ((vrbcu_addr() + BCUREVID_REG_W));
380
381 vr_major = *revreg;
382 vr_major = (vr_major&BCUREVID_MJREVMASK)>>BCUREVID_MJREVSHFT;
383
384 return (vr_major);
385 }
386
387 int
388 vrbcu_vrip_getcpuminor(void)
389 {
390 volatile u_int16_t *revreg;
391
392 if (vr_minor != -1)
393 return (vr_minor);
394
395 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1
396 ((vrbcu_addr() + BCUREVID_REG_W));
397
398 vr_minor = *revreg;
399 vr_minor = (vr_minor&BCUREVID_MNREVMASK)>>BCUREVID_MNREVSHFT;
400
401 return (vr_minor);
402 }
403
404 #define CLKX 18432000 /* CLKX1,CLKX2: 18.432MHz */
405 #define MHZ 1000000
406
407 int
408 vrbcu_vrip_getcpuclock(void)
409 {
410 u_int16_t clksp;
411 int cpuid, cpuclock;
412
413 cpuid = vrbcu_vrip_getcpuid();
414 if (cpuid != BCUREVID_FIXRID_4181 && cpuid >= BCUREVID_RID_4111) {
415 clksp = *(u_int16_t *)MIPS_PHYS_TO_KSEG1
416 ((vrbcu_addr() + BCUCLKSPEED_REG_W)) &
417 BCUCLKSPEED_CLKSPMASK;
418 } else if (cpuid == BCUREVID_FIXRID_4181) {
419 clksp = *(u_int16_t *)MIPS_PHYS_TO_KSEG1
420 ((vrbcu_addr() + BCU81CLKSPEED_REG_W)) &
421 BCUCLKSPEED_CLKSPMASK;
422 }
423
424 switch (cpuid) {
425 case BCUREVID_FIXRID_4181:
426 cpuclock = CLKX / clksp * 64;
427 /* branch delay is 1 clock; 2 clock/loop */
428 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ;
429 break;
430 case BCUREVID_RID_4101:
431 /* assume 33MHz */
432 cpuclock = 33000000;
433 /* branch delay is 1 clock; 2 clock/loop */
434 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ;
435 break;
436 case BCUREVID_RID_4102:
437 cpuclock = CLKX / clksp * 32;
438 /* branch delay is 1 clock; 2 clock/loop */
439 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ;
440 break;
441 case BCUREVID_RID_4111:
442 cpuclock = CLKX / clksp * 64;
443 /* branch delay is 1 clock; 2 clock/loop */
444 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ;
445 break;
446 case BCUREVID_RID_4121:
447 cpuclock = CLKX / clksp * 64;
448 /* branch delay is 2 clock; 3 clock/loop */
449 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ;
450 break;
451 case BCUREVID_RID_4122:
452 cpuclock = CLKX / clksp * 98;
453 /* branch delay is 2 clock; 3 clock/loop */
454 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ;
455 break;
456 case BCUREVID_RID_4131:
457 cpuclock = CLKX / clksp * 98;
458 /* branch delay is 2 clock; 3 clock/loop */
459 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ;
460 break;
461 default:
462 panic("unknown CPU type %d\n", cpuid);
463 break;
464 }
465
466 return (cpuclock);
467 }
468