Refactor FLASH related code
[oweals/u-boot_mod.git] / u-boot / common / cmd_custom.c
1 /*
2  * (C) Copyright 2013
3  * Piotr Dymacz (pepe2k), Real Time Systems, piotr@realtimesystems.pl, pepe2k@gmail.com
4  * Custom commands for U-Boot 1.1.4 modification.
5  *
6  * See file CREDITS for list of people who contributed to U-Boot project.
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <common.h>
23 #include <command.h>
24 #include <asm/mipsregs.h>
25 #include <asm/addrspace.h>
26 #include <ar7240_soc.h>
27 #include "../board/ar7240/common/ar7240_flash.h"
28
29 /* TODO: remove extern and include header file*/
30 extern void qca_sys_clocks(u32 *cpu_clk, u32 *ddr_clk, u32 *ahb_clk,
31                                                    u32 *spi_clk, u32 *ref_clk);
32
33 #if defined(OFFSET_MAC_ADDRESS)
34 /*
35  * Show MAC address(es)
36  */
37 int do_print_mac(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
38         char buffer[6];
39 #if defined(OFFSET_MAC_ADDRESS2)
40         char buffer2[6];
41 #endif
42
43 #if defined(OFFSET_MAC_ADDRESS2)
44         // get MAC1 and MAC2 addresses from flash and print them
45         memcpy(buffer,  (void *)(CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_MAC_ADDRESS),  6);
46         memcpy(buffer2, (void *)(CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_MAC_ADDRESS2), 6);
47
48         puts("Current MAC addresses stored in FLASH:\n");
49         printf("MAC1 at 0x%X: %02X:%02X:%02X:%02X:%02X:%02X\n", CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_MAC_ADDRESS,
50                                                                                                                         buffer[0] & 0xFF, buffer[1] & 0xFF, buffer[2] & 0xFF, buffer[3] & 0xFF, buffer[4] & 0xFF, buffer[5] & 0xFF);
51
52         printf("MAC2 at 0x%X: %02X:%02X:%02X:%02X:%02X:%02X\n\n", CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_MAC_ADDRESS2,
53                                                                                                                           buffer2[0] & 0xFF, buffer2[1] & 0xFF, buffer2[2] & 0xFF, buffer2[3] & 0xFF, buffer2[4] & 0xFF, buffer2[5] & 0xFF);
54 #else
55         // get MAC address from flash and print it
56         memcpy(buffer, (void *)(CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_MAC_ADDRESS), 6);
57
58         printf("Current MAC address stored in FLASH at offset 0x%X: ", CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_MAC_ADDRESS);
59         printf("%02X:%02X:%02X:%02X:%02X:%02X\n\n", buffer[0] & 0xFF, buffer[1] & 0xFF, buffer[2] & 0xFF, buffer[3] & 0xFF, buffer[4] & 0xFF, buffer[5] & 0xFF);
60 #endif
61
62         return(0);
63 }
64
65 #if defined(OFFSET_MAC_ADDRESS2)
66 U_BOOT_CMD(printmac, 1, 1, do_print_mac, "print MAC addresses stored in FLASH\n", NULL);
67 #else
68 U_BOOT_CMD(printmac, 1, 1, do_print_mac, "print MAC address stored in FLASH\n", NULL);
69 #endif
70
71 /*
72  * Change MAC address(es)
73  */
74 int do_set_mac(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
75         unsigned char *data_pointer;
76         char buf[128];
77         int i = 0, j = 0;
78
79         // allow only 2 arg (command name + mac), second argument length should be 17 (xx:xx:xx:xx:xx:xx)
80         if(argc != 2 || strlen(argv[1]) != 17){
81 #if defined(CFG_LONGHELP)
82                 if(cmdtp->help != NULL){
83                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
84                 } else {
85                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
86                 }
87 #else
88                 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
89 #endif
90                 return(1);
91         }
92
93         // count ':'
94         for(i = 0; i< 17; i++){
95                 if(argv[1][i] == ':'){
96                         j++;
97                 }
98         }
99
100         if(j != 5){
101                 puts("## Error: given MAC address has wrong format (should be: xx:xx:xx:xx:xx:xx)!\n");
102                 return(1);
103         }
104
105         // backup block with MAC address from flash in RAM
106         data_pointer = (unsigned char *)WEBFAILSAFE_UPLOAD_RAM_ADDRESS;
107
108         if(!data_pointer){
109                 puts("## Error: couldn't allocate RAM for data block backup!\n");
110                 return(1);
111         }
112
113         puts("** Notice:\n   you should always make a backup of your device\n           entire FLASH content before making any changes\n\n");
114
115         memcpy((void *)data_pointer, (void *)(CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK), OFFSET_MAC_DATA_BLOCK_LENGTH);
116
117         // store new MAC address in RAM
118         for(i = 0; i < 6; i++){
119                 data_pointer[OFFSET_MAC_ADDRESS + i] = simple_strtoul((char *)(argv[1] + i*3), NULL, 16);
120         }
121
122         // now we can erase flash and write data from RAM
123         sprintf(buf,
124                         "erase 0x%lX +0x%lX; cp.b 0x%lX 0x%lX 0x%lX",
125                         CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK,
126                         OFFSET_MAC_DATA_BLOCK_LENGTH,
127                         WEBFAILSAFE_UPLOAD_RAM_ADDRESS,
128                         CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK,
129                         OFFSET_MAC_DATA_BLOCK_LENGTH);
130
131         printf("Executing: %s\n\n", buf);
132
133         return(run_command(buf, 0));
134 }
135
136 U_BOOT_CMD(setmac, 2, 0, do_set_mac, "save new MAC address in FLASH\n", "xx:xx:xx:xx:xx:xx\n\t- change MAC address stored in FLASH (xx - value in hex format)\n");
137
138 #endif /* if defined(OFFSET_MAC_ADDRESS) */
139
140 #if defined(OFFSET_ROUTER_MODEL)
141 /*
142  * Show TP-Link router model
143  */
144 int do_print_model(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
145         unsigned char buffer[8];
146
147         // get router model from flash and print it
148         memcpy(buffer, (void *)(CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_ROUTER_MODEL), 8);
149
150         printf("Router model stored in FLASH at offset 0x%X: ", CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_ROUTER_MODEL);
151         printf("%02X%02X%02X%02X%02X%02X%02X%02X\n\n", buffer[0] & 0xFF, buffer[1] & 0xFF, buffer[2] & 0xFF, buffer[3] & 0xFF, buffer[4] & 0xFF, buffer[5] & 0xFF, buffer[6] & 0xFF, buffer[7] & 0xFF);
152
153         return(0);
154 }
155
156 U_BOOT_CMD(printmodel, 1, 1, do_print_model, "print router model stored in FLASH\n", NULL);
157
158 #endif /* if defined(OFFSET_ROUTER_MODEL) */
159
160 #if defined(OFFSET_PIN_NUMBER)
161 /*
162  * Show pin number
163  */
164 int do_print_pin(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
165         unsigned char buffer[9];
166
167         // get pin number from flash and print it
168         memcpy(buffer, (void *)(CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_PIN_NUMBER), 8);
169         buffer[8] = 0;
170
171         printf("Router pin number stored in FLASH at offset 0x%X: ", CFG_FLASH_BASE + OFFSET_MAC_DATA_BLOCK + OFFSET_PIN_NUMBER);
172         printf("%s\n\n", buffer);
173
174         return(0);
175 }
176
177 U_BOOT_CMD(printpin, 1, 1, do_print_pin, "print WPS pin stored in FLASH\n", NULL);
178
179 #endif /* if defined(OFFSET_PIN_NUMBER) */
180
181 #if defined(CONFIG_NETCONSOLE)
182 /*
183  * Start NetConsole
184  */
185 int do_start_nc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
186         return(run_command("setenv stdin nc;setenv stdout nc;setenv stderr nc;version;", 0));
187 }
188
189 U_BOOT_CMD(startnc, 1, 0, do_start_nc, "start net console\n", NULL);
190
191 /*
192  * Start Serial Console
193  */
194 int do_start_sc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
195         return(run_command("setenv stdin serial;setenv stdout serial;setenv stderr serial;version;", 0));
196 }
197
198 U_BOOT_CMD(startsc, 1, 0, do_start_sc, "start serial console\n", NULL);
199
200 #endif /* if defined(CONFIG_NETCONSOLE) */
201
202 #if !defined(CONFIG_FOR_DLINK_DIR505_A1)
203 /*
204  * Erase environment sector
205  */
206 int do_default_env(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
207         int     rc, rcode = 0;
208         int len;
209         ulong end_addr, flash_sect_addr;
210 #if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
211         ulong flash_offset;
212         unsigned char env_buffer[CFG_ENV_SECT_SIZE];
213 #endif
214
215 #if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
216         flash_offset    = CFG_ENV_ADDR & (CFG_ENV_SECT_SIZE-1);
217         flash_sect_addr = CFG_ENV_ADDR & ~(CFG_ENV_SECT_SIZE-1);
218
219         /* copy whole env sector to temporary buffer */
220         memcpy(env_buffer, (void *)flash_sect_addr, CFG_ENV_SECT_SIZE);
221
222         /* clear env part */
223         memset((uchar *)((unsigned long)env_buffer + flash_offset), 0xFF, CFG_ENV_SIZE);
224
225         len      = CFG_ENV_SECT_SIZE;
226 #else
227         flash_sect_addr = CFG_ENV_ADDR;
228         len = CFG_ENV_SIZE;
229 #endif
230
231         end_addr = flash_sect_addr + len - 1;
232
233         /* erase whole env sector */
234         if(flash_sect_erase(flash_sect_addr, end_addr)){
235                 rcode = 1;
236         }
237
238 #if defined(CFG_ENV_SECT_SIZE) && (CFG_ENV_SECT_SIZE > CFG_ENV_SIZE)
239         /* restore data from buffer in FLASH */
240         rc = flash_write((char *)env_buffer, flash_sect_addr, len);
241
242         if(rc != 0){
243                 flash_perror(rc);
244                 rcode = 1;
245         }
246 #endif
247
248         return(rcode);
249 }
250
251 U_BOOT_CMD(defenv, 1, 0, do_default_env, "reset environment variables to their default values\n", NULL);
252 #endif /* if !defined(CONFIG_FOR_DLINK_DIR505_A1) */
253
254 #if defined(PLL_IN_FLASH_MAGIC_OFFSET)
255
256 typedef struct {
257         // Clocks in MHz
258         unsigned short cpu_clock;
259         unsigned short ram_clock;
260         unsigned short ahb_clock;
261         unsigned short spi_clock;
262
263         // Registers values
264         // (more info in includes/configs/ap121.h)
265         unsigned int cpu_clk_control;
266         unsigned int cpu_pll_config;
267         unsigned int spi_control;
268 } ar9331_clock_profile;
269
270 static const ar9331_clock_profile oc_profiles[] = {
271         {
272          200, 200, 100, 25,
273          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
274 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
275          MAKE_AR9331_CPU_PLL_CONFIG_VAL(20, 1, 0, 2),
276 #else
277          MAKE_AR9331_CPU_PLL_CONFIG_VAL(32, 1, 0, 2),
278 #endif
279          MAKE_AR9331_SPI_CONTROL_VAL(4)
280         },
281
282         {
283          200, 200, 200, 33,
284          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 1),
285 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
286          MAKE_AR9331_CPU_PLL_CONFIG_VAL(20, 1, 0, 2),
287 #else
288          MAKE_AR9331_CPU_PLL_CONFIG_VAL(32, 1, 0, 2),
289 #endif
290          MAKE_AR9331_SPI_CONTROL_VAL(6)
291         },
292
293 #if !defined(CONFIG_40MHZ_XTAL_SUPPORT)
294         {
295          225, 225, 112, 28,
296          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
297          MAKE_AR9331_CPU_PLL_CONFIG_VAL(36, 1, 0, 2),
298          MAKE_AR9331_SPI_CONTROL_VAL(4)
299         },
300
301         {
302          225, 225, 225, 28,
303          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 1),
304          MAKE_AR9331_CPU_PLL_CONFIG_VAL(36, 1, 0, 2),
305          MAKE_AR9331_SPI_CONTROL_VAL(8)
306         },
307 #endif
308
309         {
310          250, 250, 125, 31,
311          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
312 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
313          MAKE_AR9331_CPU_PLL_CONFIG_VAL(25, 1, 0, 2),
314 #else
315          MAKE_AR9331_CPU_PLL_CONFIG_VAL(20, 1, 0, 1),
316 #endif
317          MAKE_AR9331_SPI_CONTROL_VAL(4)
318         },
319
320         {
321          250, 250, 250, 31,
322          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 1),
323 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
324          MAKE_AR9331_CPU_PLL_CONFIG_VAL(25, 1, 0, 2),
325 #else
326          MAKE_AR9331_CPU_PLL_CONFIG_VAL(20, 1, 0, 1),
327 #endif
328          MAKE_AR9331_SPI_CONTROL_VAL(8)
329         },
330
331         {
332          300, 300, 150, 25,
333          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
334 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
335          MAKE_AR9331_CPU_PLL_CONFIG_VAL(15, 1, 0, 1),
336 #else
337          MAKE_AR9331_CPU_PLL_CONFIG_VAL(24, 1, 0, 1),
338 #endif
339          MAKE_AR9331_SPI_CONTROL_VAL(6)
340         },
341
342 #if !defined(CONFIG_40MHZ_XTAL_SUPPORT)
343         {
344          325, 325, 162, 27,
345          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
346          MAKE_AR9331_CPU_PLL_CONFIG_VAL(26, 1, 0, 1),
347          MAKE_AR9331_SPI_CONTROL_VAL(6)
348         },
349
350         {
351          350, 350, 175, 29,
352          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
353          MAKE_AR9331_CPU_PLL_CONFIG_VAL(28, 1, 0, 1),
354          MAKE_AR9331_SPI_CONTROL_VAL(6)
355         },
356 #endif
357
358         {
359          360, 360, 180, 30,
360          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
361 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
362          MAKE_AR9331_CPU_PLL_CONFIG_VAL(18, 1, 0, 1),
363 #else
364          MAKE_AR9331_CPU_PLL_CONFIG_VAL(29, 1, 0, 1),
365 #endif
366          MAKE_AR9331_SPI_CONTROL_VAL(6)
367         },
368
369 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
370         {
371          380, 380, 190, 32,
372          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
373          MAKE_AR9331_CPU_PLL_CONFIG_VAL(19, 1, 0, 1),
374          MAKE_AR9331_SPI_CONTROL_VAL(6)
375         },
376 #endif
377
378         {
379          400, 400, 200, 33,
380          CPU_CLK_CONTROL_VAL_DEFAULT,
381          CPU_PLL_CONFIG_VAL_DEFAULT,
382          AR7240_SPI_CONTROL_DEFAULT
383         },
384
385 #if !defined(CONFIG_40MHZ_XTAL_SUPPORT)
386         {
387          412, 412, 206, 34,
388          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
389          MAKE_AR9331_CPU_PLL_CONFIG_VAL(33, 1, 0, 1),
390          MAKE_AR9331_SPI_CONTROL_VAL(6)
391         },
392 #endif
393
394 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
395         {
396          420, 420, 210, 35,
397          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
398          MAKE_AR9331_CPU_PLL_CONFIG_VAL(21, 1, 0, 1),
399          MAKE_AR9331_SPI_CONTROL_VAL(6)
400         },
401 #endif
402
403 #if !defined(CONFIG_40MHZ_XTAL_SUPPORT)
404         {
405          425, 425, 212, 35,
406          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
407          MAKE_AR9331_CPU_PLL_CONFIG_VAL(34, 1, 0, 1),
408          MAKE_AR9331_SPI_CONTROL_VAL(6)
409         },
410
411         {
412          437, 437, 218, 27,
413          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
414          MAKE_AR9331_CPU_PLL_CONFIG_VAL(35, 1, 0, 1),
415          MAKE_AR9331_SPI_CONTROL_VAL(8)
416         },
417 #endif
418
419 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
420         {
421          440, 440, 220, 27,
422          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
423          MAKE_AR9331_CPU_PLL_CONFIG_VAL(22, 1, 0, 1),
424          MAKE_AR9331_SPI_CONTROL_VAL(8)
425         },
426 #endif
427
428 #if !defined(CONFIG_40MHZ_XTAL_SUPPORT)
429         {
430          450, 450, 225, 28,
431          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
432          MAKE_AR9331_CPU_PLL_CONFIG_VAL(36, 1, 0, 1),
433          MAKE_AR9331_SPI_CONTROL_VAL(8)
434         },
435 #endif
436
437         {
438          460, 460, 230, 29,
439          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
440 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
441          MAKE_AR9331_CPU_PLL_CONFIG_VAL(23, 1, 0, 1),
442 #else
443          MAKE_AR9331_CPU_PLL_CONFIG_VAL(37, 1, 0, 1),
444 #endif
445          MAKE_AR9331_SPI_CONTROL_VAL(8)
446         },
447
448 #if !defined(CONFIG_40MHZ_XTAL_SUPPORT)
449         {
450          475, 475, 237, 30,
451          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
452          MAKE_AR9331_CPU_PLL_CONFIG_VAL(38, 1, 0, 1),
453          MAKE_AR9331_SPI_CONTROL_VAL(8)
454         },
455 #endif
456
457 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
458         {
459          480, 480, 240, 30,
460          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
461          MAKE_AR9331_CPU_PLL_CONFIG_VAL(24, 1, 0, 1),
462          MAKE_AR9331_SPI_CONTROL_VAL(8)
463         },
464 #endif
465
466 #if !defined(CONFIG_40MHZ_XTAL_SUPPORT)
467         {
468          487, 487, 243, 30,
469          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
470          MAKE_AR9331_CPU_PLL_CONFIG_VAL(39, 1, 0, 1),
471          MAKE_AR9331_SPI_CONTROL_VAL(8)
472         },
473 #endif
474
475         {
476          500, 500, 250, 31,
477          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
478 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
479          MAKE_AR9331_CPU_PLL_CONFIG_VAL(25, 1, 0, 1),
480 #else
481          MAKE_AR9331_CPU_PLL_CONFIG_VAL(40, 1, 0, 1),
482 #endif
483          MAKE_AR9331_SPI_CONTROL_VAL(8)
484         },
485
486         {
487          500, 250, 250, 31,
488          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 2, 2),
489 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
490          MAKE_AR9331_CPU_PLL_CONFIG_VAL(25, 1, 0, 1),
491 #else
492          MAKE_AR9331_CPU_PLL_CONFIG_VAL(40, 1, 0, 1),
493 #endif
494          MAKE_AR9331_SPI_CONTROL_VAL(8)
495         },
496
497 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
498         {
499          520, 520, 260, 32,
500          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 1, 2),
501          MAKE_AR9331_CPU_PLL_CONFIG_VAL(26, 1, 0, 1),
502          MAKE_AR9331_SPI_CONTROL_VAL(8)
503         },
504 #endif
505
506 #if !defined(CONFIG_40MHZ_XTAL_SUPPORT)
507         {
508          525, 262, 131, 33,
509          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 2, 4),
510          MAKE_AR9331_CPU_PLL_CONFIG_VAL(42, 1, 0, 1),
511          MAKE_AR9331_SPI_CONTROL_VAL(4)
512         },
513 #endif
514
515         {
516          560, 280, 140, 35,
517          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 2, 4),
518 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
519          MAKE_AR9331_CPU_PLL_CONFIG_VAL(28, 1, 0, 1),
520 #else
521          MAKE_AR9331_CPU_PLL_CONFIG_VAL(45, 1, 0, 1),
522 #endif
523          MAKE_AR9331_SPI_CONTROL_VAL(4)
524         },
525
526 #if defined(CONFIG_40MHZ_XTAL_SUPPORT)
527         {
528          580, 290, 145, 36,
529          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 2, 4),
530          MAKE_AR9331_CPU_PLL_CONFIG_VAL(29, 1, 0, 1),
531          MAKE_AR9331_SPI_CONTROL_VAL(4)
532         },
533 #endif
534
535         {
536          600, 300, 200, 33,
537          MAKE_AR9331_CPU_CLK_CONTROL_VAL(1, 2, 3),
538 #if CONFIG_40MHZ_XTAL_SUPPORT
539          MAKE_AR9331_CPU_PLL_CONFIG_VAL(30, 1, 0, 1),
540 #else
541          MAKE_AR9331_CPU_PLL_CONFIG_VAL(48, 1, 0, 1),
542 #endif
543          MAKE_AR9331_SPI_CONTROL_VAL(6)
544         },
545 };
546
547 /*
548  * Set and store PLL configuration in FLASH
549  */
550 int do_set_clocks(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
551         unsigned int cpu_pll_config_flash, cpu_clock_control_flash, spi_control_flash, reg;
552         unsigned int ahb_freq, ddr_freq, cpu_freq, spi_freq;
553         unsigned int *data_pointer;
554         int i, index, profiles_count;
555         char buf[128];
556
557         profiles_count = sizeof(oc_profiles) / sizeof(ar9331_clock_profile);
558
559         // print all available profiles and current settings
560         if(argc == 1){
561
562                 // read clocks
563                 qca_sys_clocks(&cpu_freq, &ddr_freq, &ahb_freq, NULL, NULL);
564
565                 // calculate SPI clock (we need to set bit 0 to 1 in SPI_FUNC_SELECT to access SPI registers)
566                 ar7240_reg_wr(AR7240_SPI_FS, 0x01);
567                 spi_freq = ahb_freq / (((ar7240_reg_rd(AR7240_SPI_CLOCK) & 0x3F) + 1) * 2);
568                 ar7240_reg_wr(AR7240_SPI_FS, 0x0);
569
570                 // make MHz from Hz
571                 cpu_freq /= 1000000;
572                 ddr_freq /= 1000000;
573                 ahb_freq /= 1000000;
574                 spi_freq /= 1000000;
575
576                 printf("Current clocks (approximated):\n- CPU: %3d MHz\n", cpu_freq);
577                 printf("- RAM: %3d MHz\n", ddr_freq);
578                 printf("- AHB: %3d MHz\n", ahb_freq);
579                 printf("- SPI: %3d MHz\n", spi_freq);
580
581                 // reference clock
582                 if(ar7240_reg_rd(HORNET_BOOTSTRAP_STATUS) & HORNET_BOOTSTRAP_SEL_25M_40M_MASK){
583                         puts("- REF:  40 MHz\n\n");
584                 } else {
585                         puts("- REF:  25 MHz\n\n");
586                 }
587
588                 // do we have PLL_MAGIC in FLASH?
589                 reg = ar7240_reg_rd(CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET + PLL_IN_FLASH_MAGIC_OFFSET);
590
591                 // read all register values stored in FLASH
592                 cpu_pll_config_flash = ar7240_reg_rd(CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET + PLL_IN_FLASH_MAGIC_OFFSET + 4);
593                 cpu_clock_control_flash = ar7240_reg_rd(CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET + PLL_IN_FLASH_MAGIC_OFFSET + 8);
594                 spi_control_flash = ar7240_reg_rd(CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET + PLL_IN_FLASH_MAGIC_OFFSET + 12);
595
596                 printf("Available PLL and clocks configurations: %d\n\n", profiles_count);
597
598                 puts("      | CPU | RAM | AHB | SPI | [ ]\n  ---------------------------------\n");
599
600                 for(i = 0; i <  profiles_count; i++){
601                         printf("%4d. |%4d |%4d |%4d |%4d | ", i + 1,
602                                                                                                   oc_profiles[i].cpu_clock,
603                                                                                                   oc_profiles[i].ram_clock,
604                                                                                                   oc_profiles[i].ahb_clock,
605                                                                                                   oc_profiles[i].spi_clock);
606
607                         if(reg == PLL_IN_FLASH_MAGIC &&
608                            oc_profiles[i].cpu_pll_config == cpu_pll_config_flash &&
609                            oc_profiles[i].cpu_clk_control == cpu_clock_control_flash &&
610                            oc_profiles[i].spi_control == spi_control_flash){
611                                 puts("[*]\n");
612                         } else {
613                                 puts("[ ]\n");
614                         }
615                 }
616
617                 puts("\n[*] = currently selected profile (stored in FLASH).\nAll clocks in MHz, run 'setclk X' to choose one.\n\n");
618                 puts("** Notice:\n   you should always make a backup of your device\n   entire FLASH content before making any changes\n\n");
619
620                 return(0);
621         } else {
622                 // selected index
623                 index = simple_strtoul(argv[1], NULL, 10);
624
625                 if(index > profiles_count || index < 1){
626                         printf("## Error: selected index should be in range 1..%d!\n", profiles_count);
627                         return(1);
628                 }
629
630                 printf("You have selected profile: %d.\n\n", index);
631
632                 // array is zero-based indexing
633                 index--;
634
635                 // backup entire block in which we store PLL/CLK settings
636                 data_pointer = (unsigned int *)WEBFAILSAFE_UPLOAD_RAM_ADDRESS;
637
638                 if(!data_pointer){
639                         puts("## Error: couldn't allocate RAM for data block backup!\n");
640                         return(1);
641                 }
642
643                 memcpy((void *)data_pointer, (void *)(CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET), PLL_IN_FLASH_DATA_BLOCK_LENGTH);
644
645                 // save PLL_IN_FLASH_MAGIC and PLL/clocks registers values
646                 data_pointer = (unsigned int *)(WEBFAILSAFE_UPLOAD_RAM_ADDRESS + PLL_IN_FLASH_MAGIC_OFFSET);
647                 *data_pointer = PLL_IN_FLASH_MAGIC;
648
649                 data_pointer++;
650                 *data_pointer = oc_profiles[index].cpu_pll_config;
651
652                 data_pointer++;
653                 *data_pointer = oc_profiles[index].cpu_clk_control;
654
655                 data_pointer++;
656                 *data_pointer = oc_profiles[index].spi_control;
657
658                 // erase FLASH, copy data from RAM
659                 sprintf(buf,
660                                 "erase 0x%lX +0x%lX; cp.b 0x%lX 0x%lX 0x%lX",
661                                 CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET,
662                                 PLL_IN_FLASH_DATA_BLOCK_LENGTH,
663                                 WEBFAILSAFE_UPLOAD_RAM_ADDRESS,
664                                 CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET,
665                                 PLL_IN_FLASH_DATA_BLOCK_LENGTH);
666
667                 printf("Executing: %s\n\n", buf);
668
669                 return(run_command(buf, 0));
670         }
671 }
672
673 U_BOOT_CMD(setclk, 2, 0, do_set_clocks, "select clocks configuration from predefined list\n",
674                 "index\n"
675                 "\t- save 'index' configuration in FLASH\n"
676                 "setclk\n"
677                 "\t- prints available clocks configurations and current settings\n");
678
679 /*
680  * Remove (clear) PLL and clock settings in FLASH
681  */
682 int do_clear_clocks(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]){
683         unsigned char *data_pointer;
684         int i;
685         char buf[128];
686         unsigned int reg = 0;
687
688         // do we have PLL_MAGIC in FLASH?
689         reg = ar7240_reg_rd(CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET + PLL_IN_FLASH_MAGIC_OFFSET);
690
691         if(reg == PLL_IN_FLASH_MAGIC){
692                 // backup entire block in which we store PLL/CLK settings
693                 data_pointer = (unsigned char *)WEBFAILSAFE_UPLOAD_RAM_ADDRESS;
694
695                 if(!data_pointer){
696                         puts("## Error: couldn't allocate RAM for data block backup!\n");
697                         return(1);
698                 }
699
700                 memcpy((void *)data_pointer, (void *)(CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET), PLL_IN_FLASH_DATA_BLOCK_LENGTH);
701
702                 // 16 bytes (4x 32-bit values)
703                 for(i = 0; i < 16; i++){
704                         data_pointer[PLL_IN_FLASH_MAGIC_OFFSET + i] = 0xFF;
705                 }
706
707                 // erase FLASH, copy data from RAM
708                 sprintf(buf,
709                                 "erase 0x%lX +0x%lX; cp.b 0x%lX 0x%lX 0x%lX",
710                                 CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET,
711                                 PLL_IN_FLASH_DATA_BLOCK_LENGTH,
712                                 WEBFAILSAFE_UPLOAD_RAM_ADDRESS,
713                                 CFG_FLASH_BASE + PLL_IN_FLASH_DATA_BLOCK_OFFSET,
714                                 PLL_IN_FLASH_DATA_BLOCK_LENGTH);
715
716                 printf("Executing: %s\n\n", buf);
717
718                 return(run_command(buf, 0));
719         } else {
720                 puts("** Warning: there is no PLL and clocks configuration in FLASH!\n");
721                 return(1);
722         }
723 }
724
725 U_BOOT_CMD(clearclk, 1, 0, do_clear_clocks, "remove PLL and clocks configuration from FLASH\n", NULL);
726 #endif /* #if defined(PLL_IN_FLASH_MAGIC_OFFSET) */