bcu_vrip.c revision 1.19 1 /* $NetBSD: bcu_vrip.c,v 1.19 2002/10/02 05:26:52 thorpej 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 CFATTACH_DECL(vrbcu, sizeof(struct vrbcu_softc),
72 vrbcu_match, vrbcu_attach, NULL, NULL);
73
74 struct vrbcu_softc *the_bcu_sc = NULL;
75
76 #ifdef SINGLE_VRIP_BASE
77 #define vrbcu_addr() VRIP_BCU_ADDR
78 #else
79 static bus_addr_t vrbcu_addr(void);
80 static bus_addr_t
81 vrbcu_addr()
82 {
83 static bus_addr_t addr = NULL;
84 static struct platid_data addrs[] = {
85 { &platid_mask_CPU_MIPS_VR_4102, (void *)VR4102_BCU_ADDR },
86 { &platid_mask_CPU_MIPS_VR_4111, (void *)VR4102_BCU_ADDR },
87 { &platid_mask_CPU_MIPS_VR_4121, (void *)VR4102_BCU_ADDR },
88 { &platid_mask_CPU_MIPS_VR_4122, (void *)VR4122_BCU_ADDR },
89 { &platid_mask_CPU_MIPS_VR_4131, (void *)VR4122_BCU_ADDR },
90 { &platid_mask_CPU_MIPS_VR_4181, (void *)VR4181_BCU_ADDR },
91 { NULL, NULL } /* terminator, don't delete */
92 };
93 struct platid_data *p;
94
95 if (addr == NULL) {
96 if ((p = platid_search_data(&platid, addrs)) == NULL)
97 panic("%s: can't find VR BCU address", __FUNCTION__);
98 addr = (bus_addr_t)p->data;
99 }
100
101 return (addr);
102 }
103 #endif /* SINGLE_VRIP_BASE */
104
105 static inline void
106 vrbcu_write(struct vrbcu_softc *sc, int port, unsigned short val)
107 {
108
109 bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
110 }
111
112 static inline unsigned short
113 vrbcu_read(struct vrbcu_softc *sc, int port)
114 {
115
116 return (bus_space_read_2(sc->sc_iot, sc->sc_ioh, port));
117 }
118
119 static int
120 vrbcu_match(struct device *parent, struct cfdata *cf, void *aux)
121 {
122
123 return (2);
124 }
125
126 static void
127 vrbcu_attach(struct device *parent, struct device *self, void *aux)
128 {
129 struct vrip_attach_args *va = aux;
130 struct vrbcu_softc *sc = (struct vrbcu_softc *)self;
131
132 sc->sc_iot = va->va_iot;
133 bus_space_map(sc->sc_iot, va->va_addr, va->va_size,
134 0, /* no flags */
135 &sc->sc_ioh);
136
137 printf("\n");
138 the_bcu_sc = sc;
139 vrbcu_dump_regs();
140 }
141
142 static void
143 vrbcu_dump_regs()
144 {
145 struct vrbcu_softc *sc = the_bcu_sc;
146 int cpuclock = 0, tclock = 0, vtclock = 0, cpuid;
147 #if !defined(ONLY_VR4102)
148 int spdreg;
149 #endif
150 #ifdef VRBCUDEBUG
151 int reg;
152 #endif /* VRBCUDEBUG */
153
154 cpuid = vrbcu_vrip_getcpuid();
155 #if !defined(ONLY_VR4181) && !defined(ONLY_VR4102)
156 if (cpuid != BCUREVID_FIXRID_4181
157 && cpuid <= BCUREVID_RID_4131
158 && cpuid >= BCUREVID_RID_4111) {
159 spdreg = vrbcu_read(sc, BCUCLKSPEED_REG_W);
160 #ifdef VRBCUDEBUG
161 printf("vrbcu: CLKSPEED %x: \n", spdreg);
162 #endif /* VRBCUDEBUG */
163 }
164 #endif
165 #if defined VR4181
166 if (cpuid == BCUREVID_FIXRID_4181){
167 spdreg = vrbcu_read(sc, BCU81CLKSPEED_REG_W);
168 #ifdef VRBCUDEBUG
169 printf("vrbcu: CLKSPEED %x: \n", spdreg);
170 #endif /* VRBCUDEBUG */
171 }
172 #endif
173
174 cpuclock = vrbcu_vrip_getcpuclock();
175
176 switch (cpuid) {
177 #if defined VR4181
178 case BCUREVID_FIXRID_4181:
179 switch ((spdreg & BCU81CLKSPEED_DIVTMASK) >>
180 BCU81CLKSPEED_DIVTSHFT){
181 case BCU81CLKSPEED_DIVT1:
182 vtclock = tclock = cpuclock;
183 break;
184 case BCU81CLKSPEED_DIVT2:
185 vtclock = tclock = cpuclock/2;
186 break;
187 case BCU81CLKSPEED_DIVT3:
188 vtclock = tclock = cpuclock/3;
189 break;
190 case BCU81CLKSPEED_DIVT4:
191 vtclock = tclock = cpuclock/4;
192 break;
193 default:
194 vtclock = tclock = 0;
195 }
196 break;
197 #endif /* VR4181 */
198 case BCUREVID_RID_4101:
199 case BCUREVID_RID_4102:
200 vtclock = tclock = cpuclock/2;
201 break;
202 #if defined VR4111
203 case BCUREVID_RID_4111:
204 if ((spdreg&BCUCLKSPEED_DIVT2B) == 0)
205 vtclock = tclock = cpuclock/2;
206 else if ((spdreg&BCUCLKSPEED_DIVT3B) == 0)
207 vtclock = tclock = cpuclock/3;
208 else if ((spdreg&BCUCLKSPEED_DIVT4B) == 0)
209 vtclock = tclock = cpuclock/4;
210 else
211 vtclock = tclock = 0; /* XXX */
212 break;
213 #endif /* VR4111 */
214 #if defined VR4121
215 case BCUREVID_RID_4121:
216 {
217 int vt;
218 tclock = cpuclock / ((spdreg & BCUCLKSPEED_DIVTMASK) >>
219 BCUCLKSPEED_DIVTSHFT);
220 vt = ((spdreg & BCUCLKSPEED_DIVVTMASK) >>
221 BCUCLKSPEED_DIVVTSHFT);
222 if (vt == 0)
223 vtclock = 0; /* XXX */
224 else if (vt < 0x9)
225 vtclock = cpuclock / vt;
226 else
227 vtclock = cpuclock / ((vt - 8)*2+1) * 2;
228 }
229 break;
230 #endif /* VR4121 */
231 #if defined VR4122 || defined VR4131
232 case BCUREVID_RID_4122:
233 case BCUREVID_RID_4131:
234 {
235 int vtdiv;
236
237 vtdiv = ((spdreg & BCUCLKSPEED_VTDIVMODE) >>
238 BCUCLKSPEED_VTDIVSHFT);
239 if (vtdiv == 0 || vtdiv > BCUCLKSPEED_VTDIV6)
240 vtclock = 0; /* XXX */
241 else
242 vtclock = cpuclock / vtdiv;
243 tclock = vtclock /
244 (((spdreg & BCUCLKSPEED_TDIVMODE) >>
245 BCUCLKSPEED_TDIVSHFT) ? 4 : 2);
246 }
247 break;
248 #endif /* VR4122 || VR4131 */
249 default:
250 break;
251 }
252 if (tclock)
253 printf("%s: cpu %d.%03dMHz, bus %d.%03dMHz, ram %d.%03dMHz\n",
254 sc->sc_dev.dv_xname,
255 cpuclock/1000000, (cpuclock%1000000)/1000,
256 tclock/1000000, (tclock%1000000)/1000,
257 vtclock/1000000, (vtclock%1000000)/1000);
258 else {
259 printf("%s: cpu %d.%03dMHz\n",
260 sc->sc_dev.dv_xname,
261 cpuclock/1000000, (cpuclock%1000000)/1000);
262 printf("%s: UNKNOWN BUS CLOCK SPEED:"
263 " CPU is UNKNOWN or NOT CONFIGURED\n",
264 sc->sc_dev.dv_xname);
265 }
266 #ifdef VRBCUDEBUG
267 reg = vrbcu_read(sc, BCUCNT1_REG_W);
268 printf("vrbcu: CNT1 %x: ", reg);
269 dbg_bit_print(reg);
270 #if !defined(ONLY_VR4181)
271 if (cpuid != BCUREVID_FIXRID_4181
272 && cpuid <= BCUREVID_RID_4121
273 && cpuid >= BCUREVID_RID_4102) {
274 reg = vrbcu_read(sc, BCUCNT2_REG_W);
275 printf("vrbcu: CNT2 %x: ", reg);
276 dbg_bit_print(reg);
277 }
278 #endif /* !defined ONLY_VR4181 */
279 #if !defined(ONLY_VR4181) || !defined(ONLY_VR4122_4131)
280 if (cpuid != BCUREVID_FIXRID_4181
281 && cpuid <= BCUREVID_RID_4121
282 && cpuid >= BCUREVID_RID_4102) {
283 reg = vrbcu_read(sc, BCUSPEED_REG_W);
284 printf("vrbcu: SPEED %x: ", reg);
285 dbg_bit_print(reg);
286 reg = vrbcu_read(sc, BCUERRST_REG_W);
287 printf("vrbcu: ERRST %x: ", reg);
288 dbg_bit_print(reg);
289 reg = vrbcu_read(sc, BCURFCNT_REG_W);
290 printf("vrbcu: RFCNT %x\n", reg);
291 reg = vrbcu_read(sc, BCUREFCOUNT_REG_W);
292 printf("vrbcu: RFCOUNT %x\n", reg);
293 }
294 #endif /* !defined(ONLY_VR4181) || !defined(ONLY_VR4122_4131) */
295 #if !defined(ONLY_VR4181)
296 if (cpuid != BCUREVID_FIXRID_4181
297 && cpuid <= BCUREVID_RID_4131
298 && cpuid >= BCUREVID_RID_4111)
299 {
300 reg = vrbcu_read(sc, BCUCNT3_REG_W);
301 printf("vrbcu: CNT3 %x: ", reg);
302 dbg_bit_print(reg);
303 }
304 #endif /* !defined ONLY_VR4181 */
305 #endif /* VRBCUDEBUG */
306
307 }
308
309 static char *cpuname[] = {
310 "VR4101", /* 0 */
311 "VR4102", /* 1 */
312 "VR4111", /* 2 */
313 "VR4121", /* 3 */
314 "VR4122", /* 4 */
315 "VR4131", /* 5 */
316 "UNKNOWN",
317 "UNKNOWN",
318 "UNKNOWN",
319 "UNKNOWN",
320 "UNKNOWN",
321 "UNKNOWN",
322 "UNKNOWN",
323 "UNKNOWN",
324 "UNKNOWN",
325 "UNKNOWN",
326 "VR4181", /* 0x10 + 0 */
327 };
328
329 int
330 vrbcu_vrip_getcpuid(void)
331 {
332 volatile u_int16_t *revreg;
333
334 if (vr_cpuid != -1)
335 return (vr_cpuid);
336
337 if (vr_cpuid == -1) {
338 if (vrbcu_addr() == VR4181_BCU_ADDR)
339 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1
340 ((vrbcu_addr() + BCU81REVID_REG_W));
341 else
342 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1
343 ((vrbcu_addr() + BCUREVID_REG_W));
344
345 vr_cpuid = *revreg;
346 vr_cpuid = (vr_cpuid&BCUREVID_RIDMASK)>>BCUREVID_RIDSHFT;
347 if (vrbcu_addr() == VR4181_BCU_ADDR
348 && vr_cpuid == BCUREVID_RID_4181) /* conflict vr4101 */
349 vr_cpuid = BCUREVID_FIXRID_4181;
350 }
351 return (vr_cpuid);
352 }
353
354 char *
355 vrbcu_vrip_getcpuname(void)
356 {
357 int cpuid;
358
359 if (vr_cpuname != NULL)
360 return (vr_cpuname);
361
362 cpuid = vrbcu_vrip_getcpuid();
363 vr_cpuname = cpuname[cpuid];
364
365 return (vr_cpuname);
366 }
367
368
369 int
370 vrbcu_vrip_getcpumajor(void)
371 {
372 volatile u_int16_t *revreg;
373
374 if (vr_major != -1)
375 return (vr_major);
376
377 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1
378 ((vrbcu_addr() + BCUREVID_REG_W));
379
380 vr_major = *revreg;
381 vr_major = (vr_major&BCUREVID_MJREVMASK)>>BCUREVID_MJREVSHFT;
382
383 return (vr_major);
384 }
385
386 int
387 vrbcu_vrip_getcpuminor(void)
388 {
389 volatile u_int16_t *revreg;
390
391 if (vr_minor != -1)
392 return (vr_minor);
393
394 revreg = (u_int16_t *)MIPS_PHYS_TO_KSEG1
395 ((vrbcu_addr() + BCUREVID_REG_W));
396
397 vr_minor = *revreg;
398 vr_minor = (vr_minor&BCUREVID_MNREVMASK)>>BCUREVID_MNREVSHFT;
399
400 return (vr_minor);
401 }
402
403 #define CLKX 18432000 /* CLKX1,CLKX2: 18.432MHz */
404 #define MHZ 1000000
405
406 int
407 vrbcu_vrip_getcpuclock(void)
408 {
409 u_int16_t clksp;
410 int cpuid, cpuclock;
411
412 cpuid = vrbcu_vrip_getcpuid();
413 if (cpuid != BCUREVID_FIXRID_4181 && cpuid >= BCUREVID_RID_4111) {
414 clksp = *(u_int16_t *)MIPS_PHYS_TO_KSEG1
415 ((vrbcu_addr() + BCUCLKSPEED_REG_W)) &
416 BCUCLKSPEED_CLKSPMASK;
417 } else if (cpuid == BCUREVID_FIXRID_4181) {
418 clksp = *(u_int16_t *)MIPS_PHYS_TO_KSEG1
419 ((vrbcu_addr() + BCU81CLKSPEED_REG_W)) &
420 BCUCLKSPEED_CLKSPMASK;
421 }
422
423 switch (cpuid) {
424 case BCUREVID_FIXRID_4181:
425 cpuclock = CLKX / clksp * 64;
426 /* branch delay is 1 clock; 2 clock/loop */
427 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ;
428 break;
429 case BCUREVID_RID_4101:
430 /* assume 33MHz */
431 cpuclock = 33000000;
432 /* branch delay is 1 clock; 2 clock/loop */
433 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ;
434 break;
435 case BCUREVID_RID_4102:
436 cpuclock = CLKX / clksp * 32;
437 /* branch delay is 1 clock; 2 clock/loop */
438 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ;
439 break;
440 case BCUREVID_RID_4111:
441 cpuclock = CLKX / clksp * 64;
442 /* branch delay is 1 clock; 2 clock/loop */
443 cpuspeed = (cpuclock / 2 + MHZ / 2) / MHZ;
444 break;
445 case BCUREVID_RID_4121:
446 cpuclock = CLKX / clksp * 64;
447 /* branch delay is 2 clock; 3 clock/loop */
448 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ;
449 break;
450 case BCUREVID_RID_4122:
451 cpuclock = CLKX / clksp * 98;
452 /* branch delay is 2 clock; 3 clock/loop */
453 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ;
454 break;
455 case BCUREVID_RID_4131:
456 cpuclock = CLKX / clksp * 98;
457 /* branch delay is 2 clock; 3 clock/loop */
458 cpuspeed = (cpuclock / 3 + MHZ / 2) / MHZ;
459 break;
460 default:
461 panic("unknown CPU type %d", cpuid);
462 break;
463 }
464
465 return (cpuclock);
466 }
467