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