xref: /openbmc/u-boot/board/freescale/common/pixis.c (revision 461fa68d)
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 
30 #include "pixis.h"
31 
32 
33 static ulong strfractoint(uchar *strptr);
34 
35 
36 /*
37  * Simple board reset.
38  */
39 void pixis_reset(void)
40 {
41     out8(PIXIS_BASE + PIXIS_RST, 0);
42 }
43 
44 
45 /*
46  * Per table 27, page 58 of MPC8641HPCN spec.
47  */
48 int set_px_sysclk(ulong sysclk)
49 {
50 	u8 sysclk_s, sysclk_r, sysclk_v, vclkh, vclkl, sysclk_aux;
51 
52 	switch (sysclk) {
53 	case 33:
54 		sysclk_s = 0x04;
55 		sysclk_r = 0x04;
56 		sysclk_v = 0x07;
57 		sysclk_aux = 0x00;
58 		break;
59 	case 40:
60 		sysclk_s = 0x01;
61 		sysclk_r = 0x1F;
62 		sysclk_v = 0x20;
63 		sysclk_aux = 0x01;
64 		break;
65 	case 50:
66 		sysclk_s = 0x01;
67 		sysclk_r = 0x1F;
68 		sysclk_v = 0x2A;
69 		sysclk_aux = 0x02;
70 		break;
71 	case 66:
72 		sysclk_s = 0x01;
73 		sysclk_r = 0x04;
74 		sysclk_v = 0x04;
75 		sysclk_aux = 0x03;
76 		break;
77 	case 83:
78 		sysclk_s = 0x01;
79 		sysclk_r = 0x1F;
80 		sysclk_v = 0x4B;
81 		sysclk_aux = 0x04;
82 		break;
83 	case 100:
84 		sysclk_s = 0x01;
85 		sysclk_r = 0x1F;
86 		sysclk_v = 0x5C;
87 		sysclk_aux = 0x05;
88 		break;
89 	case 134:
90 		sysclk_s = 0x06;
91 		sysclk_r = 0x1F;
92 		sysclk_v = 0x3B;
93 		sysclk_aux = 0x06;
94 		break;
95 	case 166:
96 		sysclk_s = 0x06;
97 		sysclk_r = 0x1F;
98 		sysclk_v = 0x4B;
99 		sysclk_aux = 0x07;
100 		break;
101 	default:
102 		printf("Unsupported SYSCLK frequency.\n");
103 		return 0;
104 	}
105 
106 	vclkh = (sysclk_s << 5) | sysclk_r;
107 	vclkl = sysclk_v;
108 
109 	out8(PIXIS_BASE + PIXIS_VCLKH, vclkh);
110 	out8(PIXIS_BASE + PIXIS_VCLKL, vclkl);
111 
112 	out8(PIXIS_BASE + PIXIS_AUX, sysclk_aux);
113 
114 	return 1;
115 }
116 
117 
118 int set_px_mpxpll(ulong mpxpll)
119 {
120 	u8 tmp;
121 	u8 val;
122 
123 	switch (mpxpll) {
124 	case 2:
125 	case 4:
126 	case 6:
127 	case 8:
128 	case 10:
129 	case 12:
130 	case 14:
131 	case 16:
132 		val = (u8) mpxpll;
133 		break;
134 	default:
135 		printf("Unsupported MPXPLL ratio.\n");
136 		return 0;
137 	}
138 
139 	tmp = in8(PIXIS_BASE + PIXIS_VSPEED1);
140 	tmp = (tmp & 0xF0) | (val & 0x0F);
141 	out8(PIXIS_BASE + PIXIS_VSPEED1, tmp);
142 
143 	return 1;
144 }
145 
146 
147 int set_px_corepll(ulong corepll)
148 {
149 	u8 tmp;
150 	u8 val;
151 
152 	switch ((int)corepll) {
153 	case 20:
154 		val = 0x08;
155 		break;
156 	case 25:
157 		val = 0x0C;
158 		break;
159 	case 30:
160 		val = 0x10;
161 		break;
162 	case 35:
163 		val = 0x1C;
164 		break;
165 	case 40:
166 		val = 0x14;
167 		break;
168 	case 45:
169 		val = 0x0E;
170 		break;
171 	default:
172 		printf("Unsupported COREPLL ratio.\n");
173 		return 0;
174 	}
175 
176 	tmp = in8(PIXIS_BASE + PIXIS_VSPEED0);
177 	tmp = (tmp & 0xE0) | (val & 0x1F);
178 	out8(PIXIS_BASE + PIXIS_VSPEED0, tmp);
179 
180 	return 1;
181 }
182 
183 
184 void read_from_px_regs(int set)
185 {
186 	u8 mask = 0x1C;	/* COREPLL, MPXPLL, SYSCLK controlled by PIXIS */
187 	u8 tmp = in8(PIXIS_BASE + PIXIS_VCFGEN0);
188 
189 	if (set)
190 		tmp = tmp | mask;
191 	else
192 		tmp = tmp & ~mask;
193 	out8(PIXIS_BASE + PIXIS_VCFGEN0, tmp);
194 }
195 
196 
197 void read_from_px_regs_altbank(int set)
198 {
199 	u8 mask = 0x04;	/* FLASHBANK and FLASHMAP controlled by PIXIS */
200 	u8 tmp = in8(PIXIS_BASE + PIXIS_VCFGEN1);
201 
202 	if (set)
203 		tmp = tmp | mask;
204 	else
205 		tmp = tmp & ~mask;
206 	out8(PIXIS_BASE + PIXIS_VCFGEN1, tmp);
207 }
208 
209 #ifndef CFG_PIXIS_VBOOT_MASK
210 #define CFG_PIXIS_VBOOT_MASK	(0x40)
211 #endif
212 
213 void clear_altbank(void)
214 {
215 	u8 tmp;
216 
217 	tmp = in8(PIXIS_BASE + PIXIS_VBOOT);
218 	tmp &= ~CFG_PIXIS_VBOOT_MASK;
219 
220 	out8(PIXIS_BASE + PIXIS_VBOOT, tmp);
221 }
222 
223 
224 void set_altbank(void)
225 {
226 	u8 tmp;
227 
228 	tmp = in8(PIXIS_BASE + PIXIS_VBOOT);
229 	tmp |= CFG_PIXIS_VBOOT_MASK;
230 
231 	out8(PIXIS_BASE + PIXIS_VBOOT, tmp);
232 }
233 
234 
235 void set_px_go(void)
236 {
237 	u8 tmp;
238 
239 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
240 	tmp = tmp & 0x1E;			/* clear GO bit */
241 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
242 
243 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
244 	tmp = tmp | 0x01;	/* set GO bit - start reset sequencer */
245 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
246 }
247 
248 
249 void set_px_go_with_watchdog(void)
250 {
251 	u8 tmp;
252 
253 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
254 	tmp = tmp & 0x1E;
255 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
256 
257 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
258 	tmp = tmp | 0x09;
259 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
260 }
261 
262 
263 int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp,
264 			       int flag, int argc, char *argv[])
265 {
266 	u8 tmp;
267 
268 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
269 	tmp = tmp & 0x1E;
270 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
271 
272 	/* setting VCTL[WDEN] to 0 to disable watch dog */
273 	tmp = in8(PIXIS_BASE + PIXIS_VCTL);
274 	tmp &= ~0x08;
275 	out8(PIXIS_BASE + PIXIS_VCTL, tmp);
276 
277 	return 0;
278 }
279 
280 U_BOOT_CMD(
281 	   diswd, 1, 0, pixis_disable_watchdog_cmd,
282 	   "diswd	- Disable watchdog timer \n",
283 	   NULL);
284 
285 /*
286  * This function takes the non-integral cpu:mpx pll ratio
287  * and converts it to an integer that can be used to assign
288  * FPGA register values.
289  * input: strptr i.e. argv[2]
290  */
291 
292 static ulong strfractoint(uchar *strptr)
293 {
294 	int i, j, retval;
295 	int mulconst;
296 	int intarr_len = 0, decarr_len = 0, no_dec = 0;
297 	ulong intval = 0, decval = 0;
298 	uchar intarr[3], decarr[3];
299 
300 	/* Assign the integer part to intarr[]
301 	 * If there is no decimal point i.e.
302 	 * if the ratio is an integral value
303 	 * simply create the intarr.
304 	 */
305 	i = 0;
306 	while (strptr[i] != '.') {
307 		if (strptr[i] == 0) {
308 			no_dec = 1;
309 			break;
310 		}
311 		intarr[i] = strptr[i];
312 		i++;
313 	}
314 
315 	/* Assign length of integer part to intarr_len. */
316 	intarr_len = i;
317 	intarr[i] = '\0';
318 
319 	if (no_dec) {
320 		/* Currently needed only for single digit corepll ratios */
321 		mulconst = 10;
322 		decval = 0;
323 	} else {
324 		j = 0;
325 		i++;		/* Skipping the decimal point */
326 		while ((strptr[i] >= '0') && (strptr[i] <= '9')) {
327 			decarr[j] = strptr[i];
328 			i++;
329 			j++;
330 		}
331 
332 		decarr_len = j;
333 		decarr[j] = '\0';
334 
335 		mulconst = 1;
336 		for (i = 0; i < decarr_len; i++)
337 			mulconst *= 10;
338 		decval = simple_strtoul((char *)decarr, NULL, 10);
339 	}
340 
341 	intval = simple_strtoul((char *)intarr, NULL, 10);
342 	intval = intval * mulconst;
343 
344 	retval = intval + decval;
345 
346 	return retval;
347 }
348 
349 
350 int
351 pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
352 {
353 	unsigned int i;
354 	char *p_cf = NULL;
355 	char *p_cf_sysclk = NULL;
356 	char *p_cf_corepll = NULL;
357 	char *p_cf_mpxpll = NULL;
358 	char *p_altbank = NULL;
359 	char *p_wd = NULL;
360 	unsigned int unknown_param = 0;
361 
362 	/*
363 	 * No args is a simple reset request.
364 	 */
365 	if (argc <= 1) {
366 		pixis_reset();
367 		/* not reached */
368 	}
369 
370 	for (i = 1; i < argc; i++) {
371 		if (strcmp(argv[i], "cf") == 0) {
372 			p_cf = argv[i];
373 			if (i + 3 >= argc) {
374 				break;
375 			}
376 			p_cf_sysclk = argv[i+1];
377 			p_cf_corepll = argv[i+2];
378 			p_cf_mpxpll = argv[i+3];
379 			i += 3;
380 			continue;
381 		}
382 
383 		if (strcmp(argv[i], "altbank") == 0) {
384 			p_altbank = argv[i];
385 			continue;
386 		}
387 
388 		if (strcmp(argv[i], "wd") == 0) {
389 			p_wd = argv[i];
390 			continue;
391 		}
392 
393 		unknown_param = 1;
394 	}
395 
396 	/*
397 	 * Check that cf has all required parms
398 	 */
399 	if ((p_cf && !(p_cf_sysclk && p_cf_corepll && p_cf_mpxpll))
400 	    ||	unknown_param) {
401 		puts(cmdtp->help);
402 		return 1;
403 	}
404 
405 	/*
406 	 * PIXIS seems to be sensitive to the ordering of
407 	 * the registers that are touched.
408 	 */
409 	read_from_px_regs(0);
410 
411 	if (p_altbank) {
412 		read_from_px_regs_altbank(0);
413 	}
414 	clear_altbank();
415 
416 	/*
417 	 * Clock configuration specified.
418 	 */
419 	if (p_cf) {
420 		unsigned long sysclk;
421 		unsigned long corepll;
422 		unsigned long mpxpll;
423 
424 		sysclk = simple_strtoul(p_cf_sysclk, NULL, 10);
425 		corepll = strfractoint((uchar *) p_cf_corepll);
426 		mpxpll = simple_strtoul(p_cf_mpxpll, NULL, 10);
427 
428 		if (!(set_px_sysclk(sysclk)
429 		      && set_px_corepll(corepll)
430 		      && set_px_mpxpll(mpxpll))) {
431 			puts(cmdtp->help);
432 			return 1;
433 		}
434 		read_from_px_regs(1);
435 	}
436 
437 	/*
438 	 * Altbank specified
439 	 *
440 	 * NOTE CHANGE IN BEHAVIOR: previous code would default
441 	 * to enabling watchdog if altbank is specified.
442 	 * Now the watchdog must be enabled explicitly using 'wd'.
443 	 */
444 	if (p_altbank) {
445 		set_altbank();
446 		read_from_px_regs_altbank(1);
447 	}
448 
449 	/*
450 	 * Reset with watchdog specified.
451 	 */
452 	if (p_wd) {
453 		set_px_go_with_watchdog();
454 	} else {
455 		set_px_go();
456 	}
457 
458 	/*
459 	 * Shouldn't be reached.
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