xref: /openbmc/u-boot/board/freescale/common/pixis.c (revision 236aad87)
1 /*
2  * Copyright 2006 Freescale Semiconductor
3  * Jeff Brown
4  * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
5  *
6  * See file CREDITS for list of people who contributed to this
7  * project.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22  * MA 02111-1307 USA
23  */
24 
25 #include <common.h>
26 #include <command.h>
27 #include <watchdog.h>
28 #include <asm/cache.h>
29 #include <asm/io.h>
30 
31 #include "pixis.h"
32 
33 
34 static ulong strfractoint(uchar *strptr);
35 
36 
37 /*
38  * Simple board reset.
39  */
40 void pixis_reset(void)
41 {
42     out8(PIXIS_BASE + PIXIS_RST, 0);
43 }
44 
45 
46 /*
47  * Per table 27, page 58 of MPC8641HPCN spec.
48  */
49 int set_px_sysclk(ulong sysclk)
50 {
51 	u8 sysclk_s, sysclk_r, sysclk_v, vclkh, vclkl, sysclk_aux;
52 
53 	switch (sysclk) {
54 	case 33:
55 		sysclk_s = 0x04;
56 		sysclk_r = 0x04;
57 		sysclk_v = 0x07;
58 		sysclk_aux = 0x00;
59 		break;
60 	case 40:
61 		sysclk_s = 0x01;
62 		sysclk_r = 0x1F;
63 		sysclk_v = 0x20;
64 		sysclk_aux = 0x01;
65 		break;
66 	case 50:
67 		sysclk_s = 0x01;
68 		sysclk_r = 0x1F;
69 		sysclk_v = 0x2A;
70 		sysclk_aux = 0x02;
71 		break;
72 	case 66:
73 		sysclk_s = 0x01;
74 		sysclk_r = 0x04;
75 		sysclk_v = 0x04;
76 		sysclk_aux = 0x03;
77 		break;
78 	case 83:
79 		sysclk_s = 0x01;
80 		sysclk_r = 0x1F;
81 		sysclk_v = 0x4B;
82 		sysclk_aux = 0x04;
83 		break;
84 	case 100:
85 		sysclk_s = 0x01;
86 		sysclk_r = 0x1F;
87 		sysclk_v = 0x5C;
88 		sysclk_aux = 0x05;
89 		break;
90 	case 134:
91 		sysclk_s = 0x06;
92 		sysclk_r = 0x1F;
93 		sysclk_v = 0x3B;
94 		sysclk_aux = 0x06;
95 		break;
96 	case 166:
97 		sysclk_s = 0x06;
98 		sysclk_r = 0x1F;
99 		sysclk_v = 0x4B;
100 		sysclk_aux = 0x07;
101 		break;
102 	default:
103 		printf("Unsupported SYSCLK frequency.\n");
104 		return 0;
105 	}
106 
107 	vclkh = (sysclk_s << 5) | sysclk_r;
108 	vclkl = sysclk_v;
109 
110 	out8(PIXIS_BASE + PIXIS_VCLKH, vclkh);
111 	out8(PIXIS_BASE + PIXIS_VCLKL, vclkl);
112 
113 	out8(PIXIS_BASE + PIXIS_AUX, sysclk_aux);
114 
115 	return 1;
116 }
117 
118 
119 int set_px_mpxpll(ulong mpxpll)
120 {
121 	u8 tmp;
122 	u8 val;
123 
124 	switch (mpxpll) {
125 	case 2:
126 	case 4:
127 	case 6:
128 	case 8:
129 	case 10:
130 	case 12:
131 	case 14:
132 	case 16:
133 		val = (u8) mpxpll;
134 		break;
135 	default:
136 		printf("Unsupported MPXPLL ratio.\n");
137 		return 0;
138 	}
139 
140 	tmp = in8(PIXIS_BASE + PIXIS_VSPEED1);
141 	tmp = (tmp & 0xF0) | (val & 0x0F);
142 	out8(PIXIS_BASE + PIXIS_VSPEED1, tmp);
143 
144 	return 1;
145 }
146 
147 
148 int set_px_corepll(ulong corepll)
149 {
150 	u8 tmp;
151 	u8 val;
152 
153 	switch ((int)corepll) {
154 	case 20:
155 		val = 0x08;
156 		break;
157 	case 25:
158 		val = 0x0C;
159 		break;
160 	case 30:
161 		val = 0x10;
162 		break;
163 	case 35:
164 		val = 0x1C;
165 		break;
166 	case 40:
167 		val = 0x14;
168 		break;
169 	case 45:
170 		val = 0x0E;
171 		break;
172 	default:
173 		printf("Unsupported COREPLL ratio.\n");
174 		return 0;
175 	}
176 
177 	tmp = in8(PIXIS_BASE + PIXIS_VSPEED0);
178 	tmp = (tmp & 0xE0) | (val & 0x1F);
179 	out8(PIXIS_BASE + PIXIS_VSPEED0, tmp);
180 
181 	return 1;
182 }
183 
184 
185 void read_from_px_regs(int set)
186 {
187 	u8 mask = 0x1C;	/* COREPLL, MPXPLL, SYSCLK controlled by PIXIS */
188 	u8 tmp = in8(PIXIS_BASE + PIXIS_VCFGEN0);
189 
190 	if (set)
191 		tmp = tmp | mask;
192 	else
193 		tmp = tmp & ~mask;
194 	out8(PIXIS_BASE + PIXIS_VCFGEN0, tmp);
195 }
196 
197 
198 void read_from_px_regs_altbank(int set)
199 {
200 	u8 mask = 0x04;	/* FLASHBANK and FLASHMAP controlled by PIXIS */
201 	u8 tmp = in8(PIXIS_BASE + PIXIS_VCFGEN1);
202 
203 	if (set)
204 		tmp = tmp | mask;
205 	else
206 		tmp = tmp & ~mask;
207 	out8(PIXIS_BASE + PIXIS_VCFGEN1, tmp);
208 }
209 
210 #ifndef CONFIG_SYS_PIXIS_VBOOT_MASK
211 #define CONFIG_SYS_PIXIS_VBOOT_MASK	(0x40)
212 #endif
213 
214 void clear_altbank(void)
215 {
216 	u8 tmp;
217 
218 	tmp = in8(PIXIS_BASE + PIXIS_VBOOT);
219 	tmp &= ~CONFIG_SYS_PIXIS_VBOOT_MASK;
220 
221 	out8(PIXIS_BASE + PIXIS_VBOOT, tmp);
222 }
223 
224 
225 void set_altbank(void)
226 {
227 	u8 tmp;
228 
229 	tmp = in8(PIXIS_BASE + PIXIS_VBOOT);
230 	tmp |= CONFIG_SYS_PIXIS_VBOOT_MASK;
231 
232 	out8(PIXIS_BASE + PIXIS_VBOOT, tmp);
233 }
234 
235 
236 void set_px_go(void)
237 {
238 	u8 tmp;
239 
240 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
241 	tmp = tmp & 0x1E;			/* clear GO bit */
242 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
243 
244 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
245 	tmp = tmp | 0x01;	/* set GO bit - start reset sequencer */
246 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
247 }
248 
249 
250 void set_px_go_with_watchdog(void)
251 {
252 	u8 tmp;
253 
254 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
255 	tmp = tmp & 0x1E;
256 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
257 
258 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
259 	tmp = tmp | 0x09;
260 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
261 }
262 
263 
264 int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp,
265 			       int flag, int argc, char *argv[])
266 {
267 	u8 tmp;
268 
269 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
270 	tmp = tmp & 0x1E;
271 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
272 
273 	/* setting VCTL[WDEN] to 0 to disable watch dog */
274 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
275 	tmp &= ~0x08;
276 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
277 
278 	return 0;
279 }
280 
281 U_BOOT_CMD(
282 	diswd, 1, 0, pixis_disable_watchdog_cmd,
283 	"Disable watchdog timer",
284 	""
285 );
286 
287 #ifdef CONFIG_PIXIS_SGMII_CMD
288 int pixis_set_sgmii(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
289 {
290 	int which_tsec = -1;
291 	uchar mask;
292 	uchar switch_mask;
293 
294 	if (argc > 2)
295 		if (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((unsigned char *)PIXIS_BASE + PIXIS_VCFGEN1,
332 			switch_mask);
333 	else
334 		setbits_8((unsigned char *)PIXIS_BASE + PIXIS_VCFGEN1,
335 			switch_mask);
336 
337 	/* If it's not the switches, enable or disable SGMII, as specified */
338 	if (!strcmp(argv[argc - 1], "on"))
339 		clrbits_8((unsigned char *)PIXIS_BASE + PIXIS_VSPEED2, mask);
340 	else if (!strcmp(argv[argc - 1], "off"))
341 		setbits_8((unsigned char *)PIXIS_BASE + PIXIS_VSPEED2, mask);
342 
343 	return 0;
344 }
345 
346 U_BOOT_CMD(
347 	pixis_set_sgmii, CONFIG_SYS_MAXARGS, 1, pixis_set_sgmii,
348 	"pixis_set_sgmii"
349 	" - Enable or disable SGMII mode for a given TSEC \n",
350 	"\npixis_set_sgmii [TSEC num] <on|off|switch>\n"
351 	"    TSEC num: 1,2,3,4 or 'all'.  'all' is default.\n"
352 	"    on - enables SGMII\n"
353 	"    off - disables SGMII\n"
354 	"    switch - use switch settings"
355 );
356 #endif
357 
358 /*
359  * This function takes the non-integral cpu:mpx pll ratio
360  * and converts it to an integer that can be used to assign
361  * FPGA register values.
362  * input: strptr i.e. argv[2]
363  */
364 
365 static ulong strfractoint(uchar *strptr)
366 {
367 	int i, j, retval;
368 	int mulconst;
369 	int intarr_len = 0, decarr_len = 0, no_dec = 0;
370 	ulong intval = 0, decval = 0;
371 	uchar intarr[3], decarr[3];
372 
373 	/* Assign the integer part to intarr[]
374 	 * If there is no decimal point i.e.
375 	 * if the ratio is an integral value
376 	 * simply create the intarr.
377 	 */
378 	i = 0;
379 	while (strptr[i] != '.') {
380 		if (strptr[i] == 0) {
381 			no_dec = 1;
382 			break;
383 		}
384 		intarr[i] = strptr[i];
385 		i++;
386 	}
387 
388 	/* Assign length of integer part to intarr_len. */
389 	intarr_len = i;
390 	intarr[i] = '\0';
391 
392 	if (no_dec) {
393 		/* Currently needed only for single digit corepll ratios */
394 		mulconst = 10;
395 		decval = 0;
396 	} else {
397 		j = 0;
398 		i++;		/* Skipping the decimal point */
399 		while ((strptr[i] >= '0') && (strptr[i] <= '9')) {
400 			decarr[j] = strptr[i];
401 			i++;
402 			j++;
403 		}
404 
405 		decarr_len = j;
406 		decarr[j] = '\0';
407 
408 		mulconst = 1;
409 		for (i = 0; i < decarr_len; i++)
410 			mulconst *= 10;
411 		decval = simple_strtoul((char *)decarr, NULL, 10);
412 	}
413 
414 	intval = simple_strtoul((char *)intarr, NULL, 10);
415 	intval = intval * mulconst;
416 
417 	retval = intval + decval;
418 
419 	return retval;
420 }
421 
422 
423 int
424 pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
425 {
426 	unsigned int i;
427 	char *p_cf = NULL;
428 	char *p_cf_sysclk = NULL;
429 	char *p_cf_corepll = NULL;
430 	char *p_cf_mpxpll = NULL;
431 	char *p_altbank = NULL;
432 	char *p_wd = NULL;
433 	unsigned int unknown_param = 0;
434 
435 	/*
436 	 * No args is a simple reset request.
437 	 */
438 	if (argc <= 1) {
439 		pixis_reset();
440 		/* not reached */
441 	}
442 
443 	for (i = 1; i < argc; i++) {
444 		if (strcmp(argv[i], "cf") == 0) {
445 			p_cf = argv[i];
446 			if (i + 3 >= argc) {
447 				break;
448 			}
449 			p_cf_sysclk = argv[i+1];
450 			p_cf_corepll = argv[i+2];
451 			p_cf_mpxpll = argv[i+3];
452 			i += 3;
453 			continue;
454 		}
455 
456 		if (strcmp(argv[i], "altbank") == 0) {
457 			p_altbank = argv[i];
458 			continue;
459 		}
460 
461 		if (strcmp(argv[i], "wd") == 0) {
462 			p_wd = argv[i];
463 			continue;
464 		}
465 
466 		unknown_param = 1;
467 	}
468 
469 	/*
470 	 * Check that cf has all required parms
471 	 */
472 	if ((p_cf && !(p_cf_sysclk && p_cf_corepll && p_cf_mpxpll))
473 	    ||	unknown_param) {
474 #ifdef CONFIG_SYS_LONGHELP
475 		puts(cmdtp->help);
476 #endif
477 		return 1;
478 	}
479 
480 	/*
481 	 * PIXIS seems to be sensitive to the ordering of
482 	 * the registers that are touched.
483 	 */
484 	read_from_px_regs(0);
485 
486 	if (p_altbank) {
487 		read_from_px_regs_altbank(0);
488 	}
489 	clear_altbank();
490 
491 	/*
492 	 * Clock configuration specified.
493 	 */
494 	if (p_cf) {
495 		unsigned long sysclk;
496 		unsigned long corepll;
497 		unsigned long mpxpll;
498 
499 		sysclk = simple_strtoul(p_cf_sysclk, NULL, 10);
500 		corepll = strfractoint((uchar *) p_cf_corepll);
501 		mpxpll = simple_strtoul(p_cf_mpxpll, NULL, 10);
502 
503 		if (!(set_px_sysclk(sysclk)
504 		      && set_px_corepll(corepll)
505 		      && set_px_mpxpll(mpxpll))) {
506 #ifdef CONFIG_SYS_LONGHELP
507 			puts(cmdtp->help);
508 #endif
509 			return 1;
510 		}
511 		read_from_px_regs(1);
512 	}
513 
514 	/*
515 	 * Altbank specified
516 	 *
517 	 * NOTE CHANGE IN BEHAVIOR: previous code would default
518 	 * to enabling watchdog if altbank is specified.
519 	 * Now the watchdog must be enabled explicitly using 'wd'.
520 	 */
521 	if (p_altbank) {
522 		set_altbank();
523 		read_from_px_regs_altbank(1);
524 	}
525 
526 	/*
527 	 * Reset with watchdog specified.
528 	 */
529 	if (p_wd) {
530 		set_px_go_with_watchdog();
531 	} else {
532 		set_px_go();
533 	}
534 
535 	/*
536 	 * Shouldn't be reached.
537 	 */
538 	return 0;
539 }
540 
541 
542 U_BOOT_CMD(
543 	pixis_reset, CONFIG_SYS_MAXARGS, 1, pixis_reset_cmd,
544 	"Reset the board using the FPGA sequencer",
545 	"    pixis_reset\n"
546 	"    pixis_reset [altbank]\n"
547 	"    pixis_reset altbank wd\n"
548 	"    pixis_reset altbank cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n"
549 	"    pixis_reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>"
550 );
551