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