xref: /netbsd/sys/arch/hpcmips/vr/bcu_vrip.c (revision bf9ec67e)
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