xref: /openbmc/u-boot/board/freescale/common/pixis.c (revision 62c3ae7c)
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 	   "diswd	- Disable watchdog timer \n",
284 	   NULL);
285 
286 #ifdef CONFIG_PIXIS_SGMII_CMD
287 int pixis_set_sgmii(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
288 {
289 	int which_tsec = -1;
290 	uchar mask;
291 	uchar switch_mask;
292 
293 	if (argc > 2)
294 		if (strcmp(argv[1], "all") != 0)
295 			which_tsec = simple_strtoul(argv[1], NULL, 0);
296 
297 	switch (which_tsec) {
298 #ifdef CONFIG_TSEC1
299 	case 1:
300 		mask = PIXIS_VSPEED2_TSEC1SER;
301 		switch_mask = PIXIS_VCFGEN1_TSEC1SER;
302 		break;
303 #endif
304 #ifdef CONFIG_TSEC2
305 	case 2:
306 		mask = PIXIS_VSPEED2_TSEC2SER;
307 		switch_mask = PIXIS_VCFGEN1_TSEC2SER;
308 		break;
309 #endif
310 #ifdef CONFIG_TSEC3
311 	case 3:
312 		mask = PIXIS_VSPEED2_TSEC3SER;
313 		switch_mask = PIXIS_VCFGEN1_TSEC3SER;
314 		break;
315 #endif
316 #ifdef CONFIG_TSEC4
317 	case 4:
318 		mask = PIXIS_VSPEED2_TSEC4SER;
319 		switch_mask = PIXIS_VCFGEN1_TSEC4SER;
320 		break;
321 #endif
322 	default:
323 		mask = PIXIS_VSPEED2_MASK;
324 		switch_mask = PIXIS_VCFGEN1_MASK;
325 		break;
326 	}
327 
328 	/* Toggle whether the switches or FPGA control the settings */
329 	if (!strcmp(argv[argc - 1], "switch"))
330 		clrbits_8((unsigned char *)PIXIS_BASE + PIXIS_VCFGEN1,
331 			switch_mask);
332 	else
333 		setbits_8((unsigned char *)PIXIS_BASE + PIXIS_VCFGEN1,
334 			switch_mask);
335 
336 	/* If it's not the switches, enable or disable SGMII, as specified */
337 	if (!strcmp(argv[argc - 1], "on"))
338 		clrbits_8((unsigned char *)PIXIS_BASE + PIXIS_VSPEED2, mask);
339 	else if (!strcmp(argv[argc - 1], "off"))
340 		setbits_8((unsigned char *)PIXIS_BASE + PIXIS_VSPEED2, mask);
341 
342 	return 0;
343 }
344 
345 U_BOOT_CMD(
346 		pixis_set_sgmii, CONFIG_SYS_MAXARGS, 1, pixis_set_sgmii,
347 		"pixis_set_sgmii"
348 		" - Enable or disable SGMII mode for a given TSEC \n",
349 		"\npixis_set_sgmii [TSEC num] <on|off|switch>\n"
350 		"    TSEC num: 1,2,3,4 or 'all'.  'all' is default.\n"
351 		"    on - enables SGMII\n"
352 		"    off - disables SGMII\n"
353 		"    switch - use switch settings\n");
354 #endif
355 
356 /*
357  * This function takes the non-integral cpu:mpx pll ratio
358  * and converts it to an integer that can be used to assign
359  * FPGA register values.
360  * input: strptr i.e. argv[2]
361  */
362 
363 static ulong strfractoint(uchar *strptr)
364 {
365 	int i, j, retval;
366 	int mulconst;
367 	int intarr_len = 0, decarr_len = 0, no_dec = 0;
368 	ulong intval = 0, decval = 0;
369 	uchar 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 	/* Assign length of integer part to intarr_len. */
387 	intarr_len = i;
388 	intarr[i] = '\0';
389 
390 	if (no_dec) {
391 		/* Currently needed only for single digit corepll ratios */
392 		mulconst = 10;
393 		decval = 0;
394 	} else {
395 		j = 0;
396 		i++;		/* Skipping the decimal point */
397 		while ((strptr[i] >= '0') && (strptr[i] <= '9')) {
398 			decarr[j] = strptr[i];
399 			i++;
400 			j++;
401 		}
402 
403 		decarr_len = j;
404 		decarr[j] = '\0';
405 
406 		mulconst = 1;
407 		for (i = 0; i < decarr_len; i++)
408 			mulconst *= 10;
409 		decval = simple_strtoul((char *)decarr, NULL, 10);
410 	}
411 
412 	intval = simple_strtoul((char *)intarr, NULL, 10);
413 	intval = intval * mulconst;
414 
415 	retval = intval + decval;
416 
417 	return retval;
418 }
419 
420 
421 int
422 pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
423 {
424 	unsigned int i;
425 	char *p_cf = NULL;
426 	char *p_cf_sysclk = NULL;
427 	char *p_cf_corepll = NULL;
428 	char *p_cf_mpxpll = NULL;
429 	char *p_altbank = NULL;
430 	char *p_wd = NULL;
431 	unsigned int unknown_param = 0;
432 
433 	/*
434 	 * No args is a simple reset request.
435 	 */
436 	if (argc <= 1) {
437 		pixis_reset();
438 		/* not reached */
439 	}
440 
441 	for (i = 1; i < argc; i++) {
442 		if (strcmp(argv[i], "cf") == 0) {
443 			p_cf = argv[i];
444 			if (i + 3 >= argc) {
445 				break;
446 			}
447 			p_cf_sysclk = argv[i+1];
448 			p_cf_corepll = argv[i+2];
449 			p_cf_mpxpll = argv[i+3];
450 			i += 3;
451 			continue;
452 		}
453 
454 		if (strcmp(argv[i], "altbank") == 0) {
455 			p_altbank = argv[i];
456 			continue;
457 		}
458 
459 		if (strcmp(argv[i], "wd") == 0) {
460 			p_wd = argv[i];
461 			continue;
462 		}
463 
464 		unknown_param = 1;
465 	}
466 
467 	/*
468 	 * Check that cf has all required parms
469 	 */
470 	if ((p_cf && !(p_cf_sysclk && p_cf_corepll && p_cf_mpxpll))
471 	    ||	unknown_param) {
472 #ifdef CONFIG_SYS_LONGHELP
473 		puts(cmdtp->help);
474 #endif
475 		return 1;
476 	}
477 
478 	/*
479 	 * PIXIS seems to be sensitive to the ordering of
480 	 * the registers that are touched.
481 	 */
482 	read_from_px_regs(0);
483 
484 	if (p_altbank) {
485 		read_from_px_regs_altbank(0);
486 	}
487 	clear_altbank();
488 
489 	/*
490 	 * Clock configuration specified.
491 	 */
492 	if (p_cf) {
493 		unsigned long sysclk;
494 		unsigned long corepll;
495 		unsigned long mpxpll;
496 
497 		sysclk = simple_strtoul(p_cf_sysclk, NULL, 10);
498 		corepll = strfractoint((uchar *) p_cf_corepll);
499 		mpxpll = simple_strtoul(p_cf_mpxpll, NULL, 10);
500 
501 		if (!(set_px_sysclk(sysclk)
502 		      && set_px_corepll(corepll)
503 		      && set_px_mpxpll(mpxpll))) {
504 #ifdef CONFIG_SYS_LONGHELP
505 			puts(cmdtp->help);
506 #endif
507 			return 1;
508 		}
509 		read_from_px_regs(1);
510 	}
511 
512 	/*
513 	 * Altbank specified
514 	 *
515 	 * NOTE CHANGE IN BEHAVIOR: previous code would default
516 	 * to enabling watchdog if altbank is specified.
517 	 * Now the watchdog must be enabled explicitly using 'wd'.
518 	 */
519 	if (p_altbank) {
520 		set_altbank();
521 		read_from_px_regs_altbank(1);
522 	}
523 
524 	/*
525 	 * Reset with watchdog specified.
526 	 */
527 	if (p_wd) {
528 		set_px_go_with_watchdog();
529 	} else {
530 		set_px_go();
531 	}
532 
533 	/*
534 	 * Shouldn't be reached.
535 	 */
536 	return 0;
537 }
538 
539 
540 U_BOOT_CMD(
541 	pixis_reset, CONFIG_SYS_MAXARGS, 1, pixis_reset_cmd,
542 	"pixis_reset - Reset the board using the FPGA sequencer\n",
543 	"    pixis_reset\n"
544 	"    pixis_reset [altbank]\n"
545 	"    pixis_reset altbank wd\n"
546 	"    pixis_reset altbank cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n"
547 	"    pixis_reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n"
548 	);
549