xref: /openbmc/u-boot/board/freescale/common/pixis.c (revision f1cd7aab)
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 
29 #ifdef CONFIG_FSL_PIXIS
30 #include <asm/cache.h>
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;
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;
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 set_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_px_go(void)
226 {
227 	u8 tmp;
228 
229 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
230 	tmp = tmp & 0x1E;
231 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
232 
233 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
234 	tmp = tmp | 0x01;
235 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
236 }
237 
238 
239 void set_px_go_with_watchdog(void)
240 {
241 	u8 tmp;
242 
243 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
244 	tmp = tmp & 0x1E;
245 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
246 
247 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
248 	tmp = tmp | 0x09;
249 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
250 }
251 
252 
253 int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp,
254 			       int flag, int argc, char *argv[])
255 {
256 	u8 tmp;
257 
258 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
259 	tmp = tmp & 0x1E;
260 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
261 
262 	/* setting VCTL[WDEN] to 0 to disable watch dog */
263 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
264 	tmp &= ~0x08;
265 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
266 
267 	return 0;
268 }
269 
270 U_BOOT_CMD(
271 	   diswd, 1, 0, pixis_disable_watchdog_cmd,
272 	   "diswd	- Disable watchdog timer \n",
273 	   NULL);
274 
275 /*
276  * This function takes the non-integral cpu:mpx pll ratio
277  * and converts it to an integer that can be used to assign
278  * FPGA register values.
279  * input: strptr i.e. argv[2]
280  */
281 
282 static ulong strfractoint(uchar *strptr)
283 {
284 	int i, j, retval;
285 	int mulconst;
286 	int intarr_len = 0, decarr_len = 0, no_dec = 0;
287 	ulong intval = 0, decval = 0;
288 	uchar intarr[3], decarr[3];
289 
290 	/* Assign the integer part to intarr[]
291 	 * If there is no decimal point i.e.
292 	 * if the ratio is an integral value
293 	 * simply create the intarr.
294 	 */
295 	i = 0;
296 	while (strptr[i] != 46) {
297 		if (strptr[i] == 0) {
298 			no_dec = 1;
299 			break;
300 		}
301 		intarr[i] = strptr[i];
302 		i++;
303 	}
304 
305 	/* Assign length of integer part to intarr_len. */
306 	intarr_len = i;
307 	intarr[i] = '\0';
308 
309 	if (no_dec) {
310 		/* Currently needed only for single digit corepll ratios */
311 		mulconst = 10;
312 		decval = 0;
313 	} else {
314 		j = 0;
315 		i++;		/* Skipping the decimal point */
316 		while ((strptr[i] > 47) && (strptr[i] < 58)) {
317 			decarr[j] = strptr[i];
318 			i++;
319 			j++;
320 		}
321 
322 		decarr_len = j;
323 		decarr[j] = '\0';
324 
325 		mulconst = 1;
326 		for (i = 0; i < decarr_len; i++)
327 			mulconst *= 10;
328 		decval = simple_strtoul((char *)decarr, NULL, 10);
329 	}
330 
331 	intval = simple_strtoul((char *)intarr, NULL, 10);
332 	intval = intval * mulconst;
333 
334 	retval = intval + decval;
335 
336 	return retval;
337 }
338 
339 
340 int
341 pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
342 {
343 	ulong val;
344 	ulong corepll;
345 
346 	/*
347 	 * No args is a simple reset request.
348 	 */
349 	if (argc <= 1) {
350 		pixis_reset();
351 		/* not reached */
352 	}
353 
354 	if (strcmp(argv[1], "cf") == 0) {
355 
356 		/*
357 		 * Reset with frequency changed:
358 		 *    cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>
359 		 */
360 		if (argc < 5) {
361 			puts(cmdtp->usage);
362 			return 1;
363 		}
364 
365 		read_from_px_regs(0);
366 
367 		val = set_px_sysclk(simple_strtoul(argv[2], NULL, 10));
368 
369 		corepll = strfractoint((uchar *)argv[3]);
370 		val = val + set_px_corepll(corepll);
371 		val = val + set_px_mpxpll(simple_strtoul(argv[4], NULL, 10));
372 		if (val == 3) {
373 			puts("Setting registers VCFGEN0 and VCTL\n");
374 			read_from_px_regs(1);
375 			puts("Resetting board with values from ");
376 			puts("VSPEED0, VSPEED1, VCLKH, and VCLKL \n");
377 			set_px_go();
378 		} else {
379 			puts(cmdtp->usage);
380 			return 1;
381 		}
382 
383 		while (1) ;	/* Not reached */
384 
385 	} else if (strcmp(argv[1], "altbank") == 0) {
386 
387 		/*
388 		 * Reset using alternate flash bank:
389 		 */
390 		if (argv[2] == 0) {
391 			/*
392 			 * Reset from alternate bank without changing
393 			 * frequency and without watchdog timer enabled.
394 			 *	altbank
395 			 */
396 			read_from_px_regs(0);
397 			read_from_px_regs_altbank(0);
398 			if (argc > 2) {
399 				puts(cmdtp->usage);
400 				return 1;
401 			}
402 			puts("Setting registers VCFGNE1, VBOOT, and VCTL\n");
403 			set_altbank();
404 			read_from_px_regs_altbank(1);
405 			puts("Resetting board to boot from the other bank.\n");
406 			set_px_go();
407 
408 		} else if (strcmp(argv[2], "cf") == 0) {
409 			/*
410 			 * Reset with frequency changed
411 			 *    altbank cf <SYSCLK freq> <COREPLL ratio>
412 			 *				<MPXPLL ratio>
413 			 */
414 			read_from_px_regs(0);
415 			read_from_px_regs_altbank(0);
416 			val = set_px_sysclk(simple_strtoul(argv[3], NULL, 10));
417 			corepll = strfractoint((uchar *)argv[4]);
418 			val = val + set_px_corepll(corepll);
419 			val = val + set_px_mpxpll(simple_strtoul(argv[5],
420 								 NULL, 10));
421 			if (val == 3) {
422 				puts("Setting registers VCFGEN0, VCFGEN1, VBOOT, and VCTL\n");
423 				set_altbank();
424 				read_from_px_regs(1);
425 				read_from_px_regs_altbank(1);
426 				puts("Enabling watchdog timer on the FPGA\n");
427 				puts("Resetting board with values from ");
428 				puts("VSPEED0, VSPEED1, VCLKH and VCLKL ");
429 				puts("to boot from the other bank.\n");
430 				set_px_go_with_watchdog();
431 			} else {
432 				puts(cmdtp->usage);
433 				return 1;
434 			}
435 
436 			while (1) ;	/* Not reached */
437 
438 		} else if (strcmp(argv[2], "wd") == 0) {
439 			/*
440 			 * Reset from alternate bank without changing
441 			 * frequencies but with watchdog timer enabled:
442 			 *    altbank wd
443 			 */
444 			read_from_px_regs(0);
445 			read_from_px_regs_altbank(0);
446 			puts("Setting registers VCFGEN1, VBOOT, and VCTL\n");
447 			set_altbank();
448 			read_from_px_regs_altbank(1);
449 			puts("Enabling watchdog timer on the FPGA\n");
450 			puts("Resetting board to boot from the other bank.\n");
451 			set_px_go_with_watchdog();
452 			while (1) ;	/* Not reached */
453 
454 		} else {
455 			puts(cmdtp->usage);
456 			return 1;
457 		}
458 
459 	} else {
460 		puts(cmdtp->usage);
461 		return 1;
462 	}
463 
464 	return 0;
465 }
466 
467 
468 U_BOOT_CMD(
469 	pixis_reset, CFG_MAXARGS, 1, pixis_reset_cmd,
470 	"pixis_reset - Reset the board using the FPGA sequencer\n",
471 	"    pixis_reset\n"
472 	"    pixis_reset [altbank]\n"
473 	"    pixis_reset altbank wd\n"
474 	"    pixis_reset altbank cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n"
475 	"    pixis_reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n"
476 	);
477 #endif /* CONFIG_FSL_PIXIS */
478