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