s3c2442: R.I.P.
[openwrt.git] / target / linux / etrax / image / boot_linux
1 #!/usr/bin/perl -w
2
3 #*****************************************************************************
4 #!
5 #! FILE NAME  : boot_linux
6 #!
7 #! PARAMETERS : -b <bootimage>     the name of the boot image to use
8 #!              -d <device>        the interface to use, e.g., eth1
9 #!                                 (defaults is eth0)
10 #!              -f                 save it in flash memory at address 0x10000
11 #!              -F                 save it in flash memory at address 0
12 #!              -h                 show some help
13 #!              -i <image>         name of the image to use (default is fimage)
14 #!              -o <offset>        the offset in the flash where the flashing
15 #!                                 starts
16 #!              -O <offset>        the offset in the image file where the
17 #!                                 flashing starts from
18 #!              -p                 print the resulting etrax100boot command
19 #!                                 instead of executing it
20 #!              -s <size>          how much to flash (default is the size of
21 #!                                 the flash minus the offset specified using
22 #!                                 -o or -f)
23 #!              -S <size>          the size of the flash
24 #!
25 #!              All sizes and offsets above can be specified as decimal
26 #!              numbers, or as hexadecimal numbers by prefixing them with 0x.
27 #!              It is also possible to use the suffixes k and M to specify
28 #!              kilo (1024) or mega (1048576).
29 #!
30 #! DESCRIPTION: Extract the start of the image and any registers that should
31 #!              be set from the kimage or fimage file, and then boot it.
32 #!
33 #! FUNCTIONS  : convert_size
34 #!              extract_hw_settings
35 #!              get_dword
36 #!              calculate_sdram_init
37 #!              sdram_command
38 #!              print_help
39 #!
40 #!----------------------------------------------------------------------------
41 #! HISTORY
42 #!
43 #! $Log: boot_linux,v $
44 #! Revision 1.16  2004/11/01 16:32:27  starvik
45 #! Corrected help text to avoid confusion
46 #!
47 #! Revision 1.15  2003/01/29 11:48:57  pkj
48 #! Calculate a flash size large enough for the given image if the
49 #! -S option is not specified.
50 #!
51 #! Revision 1.14  2002/11/18 14:40:09  pkj
52 #! Make use of the --loop option to etrax100boot when initialising
53 #! SDRAM memories. This requires a lot fewer options to be passed
54 #! to the boot loader.
55 #!
56 #! Revision 1.13  2002/08/15 16:29:02  pkj
57 #! * The -S option now accepts the size in bytes (just like the -s option).
58 #!   For backwards compatibility it still assumes sizes of 16 and less to
59 #!   be specified in MB.
60 #! * The suffixes k and M can now be used with all sizes and offsets to
61 #!   specify them in kilo or mega.
62 #!
63 #! Revision 1.12  2002/08/15 15:27:34  pkj
64 #! Use $opts{'x'} instead of $opt_x.
65 #!
66 #! Revision 1.11  2002/07/04 17:06:39  pkj
67 #! * No longer specifies a bootfile by default (not needed any longer).
68 #! * Implemented option -b to specify a bootfile.
69 #! * Removed references to option -l (it was never implemented).
70 #!
71 #! Revision 1.10  2002/06/04 11:50:23  starvik
72 #! Check if mrs_data is specified in kernelconfig (necessary for MCM)
73 #!
74 #! Revision 1.9  2002/01/29 10:38:26  pkj
75 #! Change illegal to invalid.
76 #!
77 #! Revision 1.8  2001/09/13 12:32:10  pkj
78 #! * Added option -S to specify the size of the flash (in MB),  as -s
79 #!   is used to specify how much to flash nowadays.
80 #! * Made the default size of the flash depend on the size of the image
81 #!   file. If it is bigger than 0x200100 then the flash is assumed to
82 #!   be 4 MB, otherwise it is assumed to be 2 MB.
83 #! * Added verification of various options.
84 #!
85 #! Revision 1.7  2001/09/13 10:25:11  pkj
86 #! Minor clean-up.
87 #!
88 #! Revision 1.6  2001/06/29 10:05:16  pkj
89 #! Corrected check for SDRAM.
90 #!
91 #! Revision 1.5  2001/06/29 09:11:55  pkj
92 #! Synchronised boot_elinux and boot_linux.
93 #!
94 #!----------------------------------------------------------------------------
95 #! (C) Copyright 2001, Axis Communications AB, LUND, SWEDEN
96 #!****************************************************************************
97
98 #****************** INCLUDE FILES SECTION ************************************
99
100 use strict;
101
102 use Getopt::Std;
103 use File::Basename;
104
105 #****************** VARIABLE DECLARATION SECTION *****************************
106
107 use vars qw($my_name %opts);
108 use vars qw($text_start $cmd);
109 use vars qw($image_name $image_size);
110 use vars qw($offset $source_offset $flash_size $flashing_size);
111 use vars qw($sdram_timing_address $sdram_config_address);
112 use vars qw($sdram_precharge $sdram_nop $sdram_refresh $sdram_mrs);
113
114 #****************** CONSTANT SECTION *****************************************
115
116 # Register addresses
117 $sdram_timing_address = "b0000008";
118 $sdram_config_address = "b000000c";
119
120 # SDRAM commands
121 $sdram_precharge = 3;
122 $sdram_nop = 0;
123 $sdram_refresh = 2;
124 $sdram_mrs = 1;
125
126 #****************** MAIN PROGRAM SECTION *************************************
127
128 # The name of this program.
129 $my_name = basename($0);
130
131 # Get options
132 getopts('b:d:fFhi:o:O:ps:S:', \%opts);
133
134 &print_help if ($opts{'h'});
135
136 # Name and existance of the image
137 $image_name = ($opts{'i'} ? $opts{'i'} : 'fimage');
138 die "Could not find the image $image_name!\n" unless (-s $image_name);
139
140 if ($opts{'f'} || $opts{'F'})
141 {
142   $image_size = -s $image_name;
143
144   $offset = ($opts{'f'} ? 0x10000 : 0);
145
146   $offset = &convert_size($opts{'o'}) if (defined($opts{'o'}));
147
148   die("$my_name: Invalid destination offset\n") if ($offset !~ /^\d+$/);
149
150   my $base_name = basename($image_name);
151   if ($base_name eq 'timage' || $base_name eq 'flash1.img')
152   {
153     $source_offset = 0;
154   }
155   else
156   {
157     $source_offset = $offset;
158   }
159
160   $source_offset = &convert_size($opts{'O'}) if (defined($opts{'O'}));
161
162   die("$my_name: Invalid source offset\n") if ($source_offset !~ /^\d+$/);
163   die("$my_name: Source offset > image size\n") if ($source_offset > $image_size);
164
165   if (defined($opts{'S'}))
166   {
167     # Backwards compatibility to allow specifying the flash size in MB
168     # without using an M suffix
169     $opts{'S'} .= 'M' if ($opts{'S'} =~ /^\d+$/ && $opts{'S'} <= 16);
170
171     $flash_size = &convert_size($opts{'S'});
172   }
173   else
174   {
175     # Calculate a flash size large enough for the image without the checksum
176     # and HWID.
177     $flash_size = ($image_size - $source_offset + $offset) & 0xFFFF0000;
178   }
179
180   die("$my_name: Invalid flash size\n") if ($flash_size !~ /^\d+$/);
181   die("$my_name: Destination offset > flash size\n") if ($offset > $flash_size);
182   if (defined($opts{'s'}))
183   {
184     $flashing_size = &convert_size($opts{'s'});
185   }
186   else
187   {
188     $flashing_size = $flash_size - $offset;
189   }
190
191   die("$my_name: Invalid size to flash\n") if ($flashing_size !~ /^\d+$/);
192
193   if ($flashing_size > $flash_size - $offset)
194   {
195     $flashing_size = $flash_size - $offset;
196     printf("Warning: Flashing size limited to 0x%lx due to the offset (0x%lx) and flash size (0x%lx).\n", $flashing_size, $offset, $flash_size);
197   }
198
199   if ($flashing_size > $image_size - $source_offset)
200   {
201     $flashing_size = $image_size - $source_offset;
202     printf("Warning: Flashing size limited to 0x%lx due to the offset (0x%lx) and image size (0x%lx).\n", $flashing_size, $source_offset, $image_size);
203   }
204 }
205
206 # Create the command line to boot the image
207 if (system('./etrax100boot --help > /dev/null') == 0)
208 {
209   $cmd = './etrax100boot';
210 }
211 elsif (system('svinto_boot --help > /dev/null') == 0)
212 {
213   $cmd = 'svinto_boot';
214 }
215 else
216 {
217   die("Cannot find e100boot program in your PATH!\n");
218 }
219
220 $cmd .= " --device $opts{'d'}" if ($opts{'d'});
221
222 $cmd .= &extract_hw_settings;
223
224 $cmd .= " --bootfile $opts{'b'}" if ($opts{'b'});
225 $cmd .= " --file $image_name $text_start";
226
227 if ($opts{'f'} || $opts{'F'})
228 {
229   $cmd .= sprintf(" --flash %lx %lx %lx --jump 0",
230                   hex($text_start) + $source_offset, $offset, $flashing_size);
231 }
232 else
233 {
234   $cmd .= " --jump $text_start";
235 }
236
237 if ($opts{'p'})
238 {
239   print "Command:\n$cmd\n";
240 }
241 else
242 {
243   system($cmd);
244 }
245
246 exit 0;
247
248 #****************** FUNCTION DEFINITION SECTION ******************************
249
250 #*****************************************************************************
251 ##
252 ## FUNCTION NAME: convert_size
253 ##
254 ##****************************************************************************
255
256 sub convert_size
257 {
258   my($arg) = @_;
259   my $size;
260
261   if ($arg =~ /^0x([\da-fA-F]+)([kM])?$/)
262   {
263     $size = hex($1);
264   }
265   elsif ($arg =~ /^(\d+)([kM])?$/)
266   {
267     $size = $1;
268   }
269   else
270   {
271     return -1;
272   }
273
274   if (!defined($2))
275   {
276     return $size;
277   }
278   elsif ($2 eq 'k')
279   {
280     return $size * 1024;
281   }
282   elsif ($2 eq 'M')
283   {
284     return $size * 1048576;
285   }
286 }
287
288 #*****************************************************************************
289 ##
290 ## FUNCTION NAME: extract_hw_settings
291 ##
292 ##****************************************************************************
293
294 sub extract_hw_settings
295 {
296   my $data;
297   my $dbg_port;
298   my $sdram_enabled;
299   my $return_value = "";
300   my $sdram_config;
301
302   # The hw information table has the following format
303   #
304   # "HW_PARAM_MAGIC"
305   # text_start (dword)
306   # serial debg port (dword)
307   # sdram enabled (dword)
308   # register address (dword)
309   # register value (dword)
310   # ...
311   # 0
312
313   open(FILE, "$image_name") || die("Could not open '$image_name'");
314
315   while (<FILE>)
316   {
317     if (m/HW_PARAM_MAGIC/g)
318     {
319       # Seek to first byte after magic
320       seek(FILE, -length($_) + pos($_), 1);
321       last;
322     }
323   }
324
325   $text_start = &get_dword;
326   $dbg_port = &get_dword;
327   $sdram_enabled = int(&get_dword);
328
329   while (1)
330   {
331     my $register = &get_dword;
332     my $value = &get_dword;
333
334     last if ($register eq "00000000");
335
336     if ($sdram_enabled)
337     {
338       if ($register eq $sdram_config_address)
339       {
340         $sdram_config = $value;
341       }
342       elsif ($register eq $sdram_timing_address)
343       {
344         $return_value .= &calculate_sdram_init($value, $sdram_config);
345         next;
346       }
347     }
348
349     $return_value .= " --setreg $register $value";
350   }
351
352   close(FILE);
353
354   return $return_value;
355 }
356
357 #*****************************************************************************
358 ##
359 ## FUNCTION NAME: get_dword
360 ##
361 ##****************************************************************************
362
363 sub get_dword
364 {
365   my $data;
366
367   read(FILE, $data, 4);
368   return unpack("H8", pack("V", unpack("N", $data)));
369 }
370
371 #*****************************************************************************
372 ##
373 ## FUNCTION NAME: calculate_sdram_init
374 ##
375 ##****************************************************************************
376
377 sub calculate_sdram_init
378 {
379   # Refer to ETRAX 100LX Designers Reference for a description of SDRAM
380   # initialization
381   my $sdram_init_val = hex($_[0]);
382   my $sdram_config_val = hex($_[1]);
383   my $bus_width = $sdram_config_val & 0x00800000;
384   my $speed;
385   my $cas_latency;
386   my $mrs_data;
387   my $temp;
388   my $return_value;
389   my $value;
390
391   $mrs_data = ($sdram_init_val & 0x00ff0000) >> 16;
392   $sdram_init_val &= 0x8000ffff; # Make sure mrs data is 0
393   $sdram_init_val |= 0x80000000; # Make sure sdram is enabled
394   $speed = $sdram_init_val & 0x1000;
395   $cas_latency = $sdram_init_val & 0x3;
396   if ($speed) # 100 MHz
397   {
398     $cas_latency += 2;
399   }
400   else # 50 MHz
401   {
402     $cas_latency += 1;
403   }
404
405   # Calculate value of mrs_data
406   # CAS latency = 2 && bus_width = 32 => 0x40
407   # CAS latency = 3 && bus_width = 32 => 0x60
408   # CAS latency = 2 && bus_width = 16 => 0x20
409   # CAS latency = 3 && bus_width = 16 => 0x30
410   if ($mrs_data == 0)
411   {
412     if ($bus_width == 0) # 16 bits
413     {
414       $mrs_data = $cas_latency == 2 ? 0x20 : 0x30;
415     }
416     else # 32 bits
417     {
418       $mrs_data = $cas_latency == 2 ? 0x40 : 0x60;
419     }
420   }
421
422   $temp = $sdram_init_val | 0x0000c000; # Disable refresh
423   $return_value .= &sdram_command($temp);
424   $return_value .= " --pause 20000";
425
426   $return_value .= &sdram_command($temp, $sdram_precharge);
427   $return_value .= &sdram_command($temp, $sdram_nop);
428
429   $return_value .= " --setreg +0 7";
430   $return_value .= " --label label1";
431   $return_value .= &sdram_command($temp, $sdram_refresh);
432   $return_value .= &sdram_command($temp, $sdram_nop);
433   $return_value .= " --loop +0 label1";
434
435   $return_value .= &sdram_command($temp, $sdram_mrs, $mrs_data);
436   $return_value .= &sdram_command($temp, $sdram_nop);
437
438   $return_value .= &sdram_command($sdram_init_val);
439
440   return $return_value;
441 }
442
443 #*****************************************************************************
444 ##
445 ## FUNCTION NAME: sdram_command
446 ##
447 ##****************************************************************************
448
449 sub sdram_command
450 {
451   my($temp, $value, $mrs_data) = @_;
452
453   $value ||= 0;
454   if ($value == $sdram_mrs)
455   {
456     $value = sprintf("%lx", $temp | ($value << 9) | ($mrs_data << 16));
457   }
458   else
459   {
460     $value = sprintf("%lx", $temp | ($value << 9));
461   }
462
463   return " --setreg $sdram_timing_address $value";
464 }
465
466 #*****************************************************************************
467 ##
468 ## FUNCTION NAME: print_help
469 ##
470 ##****************************************************************************
471
472 sub print_help
473 {
474   print "\nAXIS $my_name, ", '$Revision: 1.16 $ $Date: 2004/11/01 16:32:27 $ ', "\n";
475   die <<EOT;
476 Copyright (C) 2001-2002 Axis Communications AB
477
478 DESCRIPTION:
479   This program is used to boot (and flash) a linux image to a box.
480   It tries to extract the required ETRAX 100 settings from the image file.
481
482 SYNTAX:
483   $my_name [options]
484
485 OPTIONS:
486   -b <bootfile>           : The boot image to use.
487   -d <device>             : The network interface to use, default is eth0.
488   -f                      : Save the image in the flash memory starting at
489                             address 0x10000.
490   -F                      : Save the image in the flash memory starting at
491                             address 0.
492   -h                      : Print this help text.
493   -i <image>              : The path and name of the image to use, default
494                             is fimage.
495   -o <offset>             : The offset in the flash where the flashing starts.
496   -O <offset>             : The offset in the image file where the flashing
497                             starts from.
498   -p                      : Print the resulting etrax100boot command instead
499                             of executing it.
500   -s <size>               : How much to flash (default is the size of the
501                             flash minus the offset specified using -o or -f).
502   -S <size>               : The size of the flash.
503
504   All sizes and offsets above can be specified as decimal numbers, or as
505   hexadecimal numbers by prefixing them with 0x. It is also possible to use
506   the suffixes k and M to specify kilo (1024) or mega (1048576).
507
508 EOT
509 }
510
511 #****************** END OF FILE boot_linux ***********************************