xref: /openbmc/u-boot/board/freescale/common/pixis.c (revision 29b103c7)
1 /*
2  * Copyright 2006,2010 Freescale Semiconductor
3  * Jeff Brown
4  * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
5  *
6  * SPDX-License-Identifier:	GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <command.h>
11 #include <asm/io.h>
12 
13 #define pixis_base (u8 *)PIXIS_BASE
14 
15 /*
16  * Simple board reset.
17  */
18 void pixis_reset(void)
19 {
20 	out_8(pixis_base + PIXIS_RST, 0);
21 
22 	while (1);
23 }
24 
25 /*
26  * Per table 27, page 58 of MPC8641HPCN spec.
27  */
28 static int set_px_sysclk(unsigned long sysclk)
29 {
30 	u8 sysclk_s, sysclk_r, sysclk_v, vclkh, vclkl, sysclk_aux;
31 
32 	switch (sysclk) {
33 	case 33:
34 		sysclk_s = 0x04;
35 		sysclk_r = 0x04;
36 		sysclk_v = 0x07;
37 		sysclk_aux = 0x00;
38 		break;
39 	case 40:
40 		sysclk_s = 0x01;
41 		sysclk_r = 0x1F;
42 		sysclk_v = 0x20;
43 		sysclk_aux = 0x01;
44 		break;
45 	case 50:
46 		sysclk_s = 0x01;
47 		sysclk_r = 0x1F;
48 		sysclk_v = 0x2A;
49 		sysclk_aux = 0x02;
50 		break;
51 	case 66:
52 		sysclk_s = 0x01;
53 		sysclk_r = 0x04;
54 		sysclk_v = 0x04;
55 		sysclk_aux = 0x03;
56 		break;
57 	case 83:
58 		sysclk_s = 0x01;
59 		sysclk_r = 0x1F;
60 		sysclk_v = 0x4B;
61 		sysclk_aux = 0x04;
62 		break;
63 	case 100:
64 		sysclk_s = 0x01;
65 		sysclk_r = 0x1F;
66 		sysclk_v = 0x5C;
67 		sysclk_aux = 0x05;
68 		break;
69 	case 134:
70 		sysclk_s = 0x06;
71 		sysclk_r = 0x1F;
72 		sysclk_v = 0x3B;
73 		sysclk_aux = 0x06;
74 		break;
75 	case 166:
76 		sysclk_s = 0x06;
77 		sysclk_r = 0x1F;
78 		sysclk_v = 0x4B;
79 		sysclk_aux = 0x07;
80 		break;
81 	default:
82 		printf("Unsupported SYSCLK frequency.\n");
83 		return 0;
84 	}
85 
86 	vclkh = (sysclk_s << 5) | sysclk_r;
87 	vclkl = sysclk_v;
88 
89 	out_8(pixis_base + PIXIS_VCLKH, vclkh);
90 	out_8(pixis_base + PIXIS_VCLKL, vclkl);
91 
92 	out_8(pixis_base + PIXIS_AUX, sysclk_aux);
93 
94 	return 1;
95 }
96 
97 /* Set the CFG_SYSPLL bits
98  *
99  * This only has effect if PX_VCFGEN0[SYSPLL]=1, which is true if
100  * read_from_px_regs() is called.
101  */
102 static int set_px_mpxpll(unsigned long mpxpll)
103 {
104 	switch (mpxpll) {
105 	case 2:
106 	case 4:
107 	case 6:
108 	case 8:
109 	case 10:
110 	case 12:
111 	case 14:
112 	case 16:
113 		clrsetbits_8(pixis_base + PIXIS_VSPEED1, 0x1F, mpxpll);
114 		return 1;
115 	}
116 
117 	printf("Unsupported MPXPLL ratio.\n");
118 	return 0;
119 }
120 
121 static int set_px_corepll(unsigned long corepll)
122 {
123 	u8 val;
124 
125 	switch (corepll) {
126 	case 20:
127 		val = 0x08;
128 		break;
129 	case 25:
130 		val = 0x0C;
131 		break;
132 	case 30:
133 		val = 0x10;
134 		break;
135 	case 35:
136 		val = 0x1C;
137 		break;
138 	case 40:
139 		val = 0x14;
140 		break;
141 	case 45:
142 		val = 0x0E;
143 		break;
144 	default:
145 		printf("Unsupported COREPLL ratio.\n");
146 		return 0;
147 	}
148 
149 	clrsetbits_8(pixis_base + PIXIS_VSPEED0, 0x1F, val);
150 	return 1;
151 }
152 
153 #ifndef CONFIG_SYS_PIXIS_VCFGEN0_ENABLE
154 #define CONFIG_SYS_PIXIS_VCFGEN0_ENABLE		0x1C
155 #endif
156 
157 /* Tell the PIXIS where to find the COREPLL, MPXPLL, SYSCLK values
158  *
159  * The PIXIS can be programmed to look at either the on-board dip switches
160  * or various other PIXIS registers to determine the values for COREPLL,
161  * MPXPLL, and SYSCLK.
162  *
163  * CONFIG_SYS_PIXIS_VCFGEN0_ENABLE is the value to write to the PIXIS_VCFGEN0
164  * register that tells the pixis to use the various PIXIS register.
165  */
166 static void read_from_px_regs(int set)
167 {
168 	u8 tmp = in_8(pixis_base + PIXIS_VCFGEN0);
169 
170 	if (set)
171 		tmp = tmp | CONFIG_SYS_PIXIS_VCFGEN0_ENABLE;
172 	else
173 		tmp = tmp & ~CONFIG_SYS_PIXIS_VCFGEN0_ENABLE;
174 
175 	out_8(pixis_base + PIXIS_VCFGEN0, tmp);
176 }
177 
178 /* CONFIG_SYS_PIXIS_VBOOT_ENABLE is the value to write to the PX_VCFGEN1
179  * register that tells the pixis to use the PX_VBOOT[LBMAP] register.
180  */
181 #ifndef CONFIG_SYS_PIXIS_VBOOT_ENABLE
182 #define CONFIG_SYS_PIXIS_VBOOT_ENABLE	0x04
183 #endif
184 
185 /* Configure the source of the boot location
186  *
187  * The PIXIS can be programmed to look at either the on-board dip switches
188  * or the PX_VBOOT[LBMAP] register to determine where we should boot.
189  *
190  * If we want to boot from the alternate boot bank, we need to tell the PIXIS
191  * to ignore the on-board dip switches and use the PX_VBOOT[LBMAP] instead.
192  */
193 static void read_from_px_regs_altbank(int set)
194 {
195 	u8 tmp = in_8(pixis_base + PIXIS_VCFGEN1);
196 
197 	if (set)
198 		tmp = tmp | CONFIG_SYS_PIXIS_VBOOT_ENABLE;
199 	else
200 		tmp = tmp & ~CONFIG_SYS_PIXIS_VBOOT_ENABLE;
201 
202 	out_8(pixis_base + PIXIS_VCFGEN1, tmp);
203 }
204 
205 /* CONFIG_SYS_PIXIS_VBOOT_MASK contains the bits to set in VBOOT register that
206  * tells the PIXIS what the alternate flash bank is.
207  *
208  * Note that it's not really a mask.  It contains the actual LBMAP bits that
209  * must be set to select the alternate bank.  This code assumes that the
210  * primary bank has these bits set to 0, and the alternate bank has these
211  * bits set to 1.
212  */
213 #ifndef CONFIG_SYS_PIXIS_VBOOT_MASK
214 #define CONFIG_SYS_PIXIS_VBOOT_MASK	(0x40)
215 #endif
216 
217 /* Tell the PIXIS to boot from the default flash bank
218  *
219  * Program the default flash bank into the VBOOT register.  This register is
220  * used only if PX_VCFGEN1[FLASH]=1.
221  */
222 static void clear_altbank(void)
223 {
224 	clrbits_8(pixis_base + PIXIS_VBOOT, CONFIG_SYS_PIXIS_VBOOT_MASK);
225 }
226 
227 /* Tell the PIXIS to boot from the alternate flash bank
228  *
229  * Program the alternate flash bank into the VBOOT register.  This register is
230  * used only if PX_VCFGEN1[FLASH]=1.
231  */
232 static void set_altbank(void)
233 {
234 	setbits_8(pixis_base + PIXIS_VBOOT, CONFIG_SYS_PIXIS_VBOOT_MASK);
235 }
236 
237 /* Reset the board with watchdog disabled.
238  *
239  * This respects the altbank setting.
240  */
241 static void set_px_go(void)
242 {
243 	/* Disable the VELA sequencer and watchdog */
244 	clrbits_8(pixis_base + PIXIS_VCTL, 9);
245 
246 	/* Reboot by starting the VELA sequencer */
247 	setbits_8(pixis_base + PIXIS_VCTL, 0x1);
248 
249 	while (1);
250 }
251 
252 /* Reset the board with watchdog enabled.
253  *
254  * This respects the altbank setting.
255  */
256 static void set_px_go_with_watchdog(void)
257 {
258 	/* Disable the VELA sequencer */
259 	clrbits_8(pixis_base + PIXIS_VCTL, 1);
260 
261 	/* Enable the watchdog and reboot by starting the VELA sequencer */
262 	setbits_8(pixis_base + PIXIS_VCTL, 0x9);
263 
264 	while (1);
265 }
266 
267 /* Disable the watchdog
268  *
269  */
270 static int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp, int flag, int argc,
271 				      char * const argv[])
272 {
273 	/* Disable the VELA sequencer and the watchdog */
274 	clrbits_8(pixis_base + PIXIS_VCTL, 9);
275 
276 	return 0;
277 }
278 
279 U_BOOT_CMD(
280 	diswd, 1, 0, pixis_disable_watchdog_cmd,
281 	"Disable watchdog timer",
282 	""
283 );
284 
285 #ifdef CONFIG_PIXIS_SGMII_CMD
286 
287 /* Enable or disable SGMII mode for a TSEC
288  */
289 static int pixis_set_sgmii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
290 {
291 	int which_tsec = -1;
292 	unsigned char mask;
293 	unsigned char switch_mask;
294 
295 	if ((argc > 2) && (strcmp(argv[1], "all") != 0))
296 		which_tsec = simple_strtoul(argv[1], NULL, 0);
297 
298 	switch (which_tsec) {
299 #ifdef CONFIG_TSEC1
300 	case 1:
301 		mask = PIXIS_VSPEED2_TSEC1SER;
302 		switch_mask = PIXIS_VCFGEN1_TSEC1SER;
303 		break;
304 #endif
305 #ifdef CONFIG_TSEC2
306 	case 2:
307 		mask = PIXIS_VSPEED2_TSEC2SER;
308 		switch_mask = PIXIS_VCFGEN1_TSEC2SER;
309 		break;
310 #endif
311 #ifdef CONFIG_TSEC3
312 	case 3:
313 		mask = PIXIS_VSPEED2_TSEC3SER;
314 		switch_mask = PIXIS_VCFGEN1_TSEC3SER;
315 		break;
316 #endif
317 #ifdef CONFIG_TSEC4
318 	case 4:
319 		mask = PIXIS_VSPEED2_TSEC4SER;
320 		switch_mask = PIXIS_VCFGEN1_TSEC4SER;
321 		break;
322 #endif
323 	default:
324 		mask = PIXIS_VSPEED2_MASK;
325 		switch_mask = PIXIS_VCFGEN1_MASK;
326 		break;
327 	}
328 
329 	/* Toggle whether the switches or FPGA control the settings */
330 	if (!strcmp(argv[argc - 1], "switch"))
331 		clrbits_8(pixis_base + PIXIS_VCFGEN1, switch_mask);
332 	else
333 		setbits_8(pixis_base + PIXIS_VCFGEN1, switch_mask);
334 
335 	/* If it's not the switches, enable or disable SGMII, as specified */
336 	if (!strcmp(argv[argc - 1], "on"))
337 		clrbits_8(pixis_base + PIXIS_VSPEED2, mask);
338 	else if (!strcmp(argv[argc - 1], "off"))
339 		setbits_8(pixis_base + PIXIS_VSPEED2, mask);
340 
341 	return 0;
342 }
343 
344 U_BOOT_CMD(
345 	pixis_set_sgmii, CONFIG_SYS_MAXARGS, 1, pixis_set_sgmii,
346 	"pixis_set_sgmii"
347 	" - Enable or disable SGMII mode for a given TSEC \n",
348 	"\npixis_set_sgmii [TSEC num] <on|off|switch>\n"
349 	"    TSEC num: 1,2,3,4 or 'all'.  'all' is default.\n"
350 	"    on - enables SGMII\n"
351 	"    off - disables SGMII\n"
352 	"    switch - use switch settings"
353 );
354 
355 #endif
356 
357 /*
358  * This function takes the non-integral cpu:mpx pll ratio
359  * and converts it to an integer that can be used to assign
360  * FPGA register values.
361  * input: strptr i.e. argv[2]
362  */
363 static unsigned long strfractoint(char *strptr)
364 {
365 	int i, j;
366 	int mulconst;
367 	int no_dec = 0;
368 	unsigned long intval = 0, decval = 0;
369 	char intarr[3], decarr[3];
370 
371 	/* Assign the integer part to intarr[]
372 	 * If there is no decimal point i.e.
373 	 * if the ratio is an integral value
374 	 * simply create the intarr.
375 	 */
376 	i = 0;
377 	while (strptr[i] != '.') {
378 		if (strptr[i] == 0) {
379 			no_dec = 1;
380 			break;
381 		}
382 		intarr[i] = strptr[i];
383 		i++;
384 	}
385 
386 	intarr[i] = '\0';
387 
388 	if (no_dec) {
389 		/* Currently needed only for single digit corepll ratios */
390 		mulconst = 10;
391 		decval = 0;
392 	} else {
393 		j = 0;
394 		i++;		/* Skipping the decimal point */
395 		while ((strptr[i] >= '0') && (strptr[i] <= '9')) {
396 			decarr[j] = strptr[i];
397 			i++;
398 			j++;
399 		}
400 
401 		decarr[j] = '\0';
402 
403 		mulconst = 1;
404 		for (i = 0; i < j; i++)
405 			mulconst *= 10;
406 		decval = simple_strtoul(decarr, NULL, 10);
407 	}
408 
409 	intval = simple_strtoul(intarr, NULL, 10);
410 	intval = intval * mulconst;
411 
412 	return intval + decval;
413 }
414 
415 static int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
416 {
417 	unsigned int i;
418 	char *p_cf = NULL;
419 	char *p_cf_sysclk = NULL;
420 	char *p_cf_corepll = NULL;
421 	char *p_cf_mpxpll = NULL;
422 	char *p_altbank = NULL;
423 	char *p_wd = NULL;
424 	int unknown_param = 0;
425 
426 	/*
427 	 * No args is a simple reset request.
428 	 */
429 	if (argc <= 1) {
430 		pixis_reset();
431 		/* not reached */
432 	}
433 
434 	for (i = 1; i < argc; i++) {
435 		if (strcmp(argv[i], "cf") == 0) {
436 			p_cf = argv[i];
437 			if (i + 3 >= argc) {
438 				break;
439 			}
440 			p_cf_sysclk = argv[i+1];
441 			p_cf_corepll = argv[i+2];
442 			p_cf_mpxpll = argv[i+3];
443 			i += 3;
444 			continue;
445 		}
446 
447 		if (strcmp(argv[i], "altbank") == 0) {
448 			p_altbank = argv[i];
449 			continue;
450 		}
451 
452 		if (strcmp(argv[i], "wd") == 0) {
453 			p_wd = argv[i];
454 			continue;
455 		}
456 
457 		unknown_param = 1;
458 	}
459 
460 	/*
461 	 * Check that cf has all required parms
462 	 */
463 	if ((p_cf && !(p_cf_sysclk && p_cf_corepll && p_cf_mpxpll))
464 	    ||	unknown_param) {
465 #ifdef CONFIG_SYS_LONGHELP
466 		puts(cmdtp->help);
467 		putc('\n');
468 #endif
469 		return 1;
470 	}
471 
472 	/*
473 	 * PIXIS seems to be sensitive to the ordering of
474 	 * the registers that are touched.
475 	 */
476 	read_from_px_regs(0);
477 
478 	if (p_altbank)
479 		read_from_px_regs_altbank(0);
480 
481 	clear_altbank();
482 
483 	/*
484 	 * Clock configuration specified.
485 	 */
486 	if (p_cf) {
487 		unsigned long sysclk;
488 		unsigned long corepll;
489 		unsigned long mpxpll;
490 
491 		sysclk = simple_strtoul(p_cf_sysclk, NULL, 10);
492 		corepll = strfractoint(p_cf_corepll);
493 		mpxpll = simple_strtoul(p_cf_mpxpll, NULL, 10);
494 
495 		if (!(set_px_sysclk(sysclk)
496 		      && set_px_corepll(corepll)
497 		      && set_px_mpxpll(mpxpll))) {
498 #ifdef CONFIG_SYS_LONGHELP
499 			puts(cmdtp->help);
500 			putc('\n');
501 #endif
502 			return 1;
503 		}
504 		read_from_px_regs(1);
505 	}
506 
507 	/*
508 	 * Altbank specified
509 	 *
510 	 * NOTE CHANGE IN BEHAVIOR: previous code would default
511 	 * to enabling watchdog if altbank is specified.
512 	 * Now the watchdog must be enabled explicitly using 'wd'.
513 	 */
514 	if (p_altbank) {
515 		set_altbank();
516 		read_from_px_regs_altbank(1);
517 	}
518 
519 	/*
520 	 * Reset with watchdog specified.
521 	 */
522 	if (p_wd)
523 		set_px_go_with_watchdog();
524 	else
525 		set_px_go();
526 
527 	/*
528 	 * Shouldn't be reached.
529 	 */
530 	return 0;
531 }
532 
533 
534 U_BOOT_CMD(
535 	pixis_reset, CONFIG_SYS_MAXARGS, 1, pixis_reset_cmd,
536 	"Reset the board using the FPGA sequencer",
537 	"    pixis_reset\n"
538 	"    pixis_reset [altbank]\n"
539 	"    pixis_reset altbank wd\n"
540 	"    pixis_reset altbank cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n"
541 	"    pixis_reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>"
542 );
543