e7d5807f5331c0567ae9d6970172d0d39e9ebe64
[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 # $Id: boot_linux,v 1.16 2004/11/01 16:32:27 starvik Exp $
98
99 #****************** INCLUDE FILES SECTION ************************************
100
101 use strict;
102
103 use Getopt::Std;
104 use File::Basename;
105
106 #****************** VARIABLE DECLARATION SECTION *****************************
107
108 use vars qw($my_name %opts);
109 use vars qw($text_start $cmd);
110 use vars qw($image_name $image_size);
111 use vars qw($offset $source_offset $flash_size $flashing_size);
112 use vars qw($sdram_timing_address $sdram_config_address);
113 use vars qw($sdram_precharge $sdram_nop $sdram_refresh $sdram_mrs);
114
115 #****************** CONSTANT SECTION *****************************************
116
117 # Register addresses
118 $sdram_timing_address = "b0000008";
119 $sdram_config_address = "b000000c";
120
121 # SDRAM commands
122 $sdram_precharge = 3;
123 $sdram_nop = 0;
124 $sdram_refresh = 2;
125 $sdram_mrs = 1;
126
127 #****************** MAIN PROGRAM SECTION *************************************
128
129 # The name of this program.
130 $my_name = basename($0);
131
132 # Get options
133 getopts('b:d:fFhi:o:O:ps:S:', \%opts);
134
135 &print_help if ($opts{'h'});
136
137 # Name and existance of the image
138 $image_name = ($opts{'i'} ? $opts{'i'} : 'fimage');
139 die "Could not find the image $image_name!\n" unless (-s $image_name);
140
141 if ($opts{'f'} || $opts{'F'})
142 {
143   $image_size = -s $image_name;
144
145   $offset = ($opts{'f'} ? 0x10000 : 0);
146
147   $offset = &convert_size($opts{'o'}) if (defined($opts{'o'}));
148
149   die("$my_name: Invalid destination offset\n") if ($offset !~ /^\d+$/);
150
151   my $base_name = basename($image_name);
152   if ($base_name eq 'timage' || $base_name eq 'flash1.img')
153   {
154     $source_offset = 0;
155   }
156   else
157   {
158     $source_offset = $offset;
159   }
160
161   $source_offset = &convert_size($opts{'O'}) if (defined($opts{'O'}));
162
163   die("$my_name: Invalid source offset\n") if ($source_offset !~ /^\d+$/);
164   die("$my_name: Source offset > image size\n") if ($source_offset > $image_size);
165
166   if (defined($opts{'S'}))
167   {
168     # Backwards compatibility to allow specifying the flash size in MB
169     # without using an M suffix
170     $opts{'S'} .= 'M' if ($opts{'S'} =~ /^\d+$/ && $opts{'S'} <= 16);
171
172     $flash_size = &convert_size($opts{'S'});
173   }
174   else
175   {
176     # Calculate a flash size large enough for the image without the checksum
177     # and HWID.
178     $flash_size = ($image_size - $source_offset + $offset) & 0xFFFF0000;
179   }
180
181   die("$my_name: Invalid flash size\n") if ($flash_size !~ /^\d+$/);
182   die("$my_name: Destination offset > flash size\n") if ($offset > $flash_size);
183   if (defined($opts{'s'}))
184   {
185     $flashing_size = &convert_size($opts{'s'});
186   }
187   else
188   {
189     $flashing_size = $flash_size - $offset;
190   }
191
192   die("$my_name: Invalid size to flash\n") if ($flashing_size !~ /^\d+$/);
193
194   if ($flashing_size > $flash_size - $offset)
195   {
196     $flashing_size = $flash_size - $offset;
197     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);
198   }
199
200   if ($flashing_size > $image_size - $source_offset)
201   {
202     $flashing_size = $image_size - $source_offset;
203     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);
204   }
205 }
206
207 # Create the command line to boot the image
208 if (system('./etrax100boot --help > /dev/null') == 0)
209 {
210   $cmd = './etrax100boot';
211 }
212 elsif (system('svinto_boot --help > /dev/null') == 0)
213 {
214   $cmd = 'svinto_boot';
215 }
216 else
217 {
218   die("Cannot find e100boot program in your PATH!\n");
219 }
220
221 $cmd .= " --device $opts{'d'}" if ($opts{'d'});
222
223 $cmd .= &extract_hw_settings;
224
225 $cmd .= " --bootfile $opts{'b'}" if ($opts{'b'});
226 $cmd .= " --file $image_name $text_start";
227
228 if ($opts{'f'} || $opts{'F'})
229 {
230   $cmd .= sprintf(" --flash %lx %lx %lx --jump 0",
231                   hex($text_start) + $source_offset, $offset, $flashing_size);
232 }
233 else
234 {
235   $cmd .= " --jump $text_start";
236 }
237
238 if ($opts{'p'})
239 {
240   print "Command:\n$cmd\n";
241 }
242 else
243 {
244   system($cmd);
245 }
246
247 exit 0;
248
249 #****************** FUNCTION DEFINITION SECTION ******************************
250
251 #*****************************************************************************
252 ##
253 ## FUNCTION NAME: convert_size
254 ##
255 ##****************************************************************************
256
257 sub convert_size
258 {
259   my($arg) = @_;
260   my $size;
261
262   if ($arg =~ /^0x([\da-fA-F]+)([kM])?$/)
263   {
264     $size = hex($1);
265   }
266   elsif ($arg =~ /^(\d+)([kM])?$/)
267   {
268     $size = $1;
269   }
270   else
271   {
272     return -1;
273   }
274
275   if (!defined($2))
276   {
277     return $size;
278   }
279   elsif ($2 eq 'k')
280   {
281     return $size * 1024;
282   }
283   elsif ($2 eq 'M')
284   {
285     return $size * 1048576;
286   }
287 }
288
289 #*****************************************************************************
290 ##
291 ## FUNCTION NAME: extract_hw_settings
292 ##
293 ##****************************************************************************
294
295 sub extract_hw_settings
296 {
297   my $data;
298   my $dbg_port;
299   my $sdram_enabled;
300   my $return_value = "";
301   my $sdram_config;
302
303   # The hw information table has the following format
304   #
305   # "HW_PARAM_MAGIC"
306   # text_start (dword)
307   # serial debg port (dword)
308   # sdram enabled (dword)
309   # register address (dword)
310   # register value (dword)
311   # ...
312   # 0
313
314   open(FILE, "$image_name") || die("Could not open '$image_name'");
315
316   while (<FILE>)
317   {
318     if (m/HW_PARAM_MAGIC/g)
319     {
320       # Seek to first byte after magic
321       seek(FILE, -length($_) + pos($_), 1);
322       last;
323     }
324   }
325
326   $text_start = &get_dword;
327   $dbg_port = &get_dword;
328   $sdram_enabled = int(&get_dword);
329
330   while (1)
331   {
332     my $register = &get_dword;
333     my $value = &get_dword;
334
335     last if ($register eq "00000000");
336
337     if ($sdram_enabled)
338     {
339       if ($register eq $sdram_config_address)
340       {
341         $sdram_config = $value;
342       }
343       elsif ($register eq $sdram_timing_address)
344       {
345         $return_value .= &calculate_sdram_init($value, $sdram_config);
346         next;
347       }
348     }
349
350     $return_value .= " --setreg $register $value";
351   }
352
353   close(FILE);
354
355   return $return_value;
356 }
357
358 #*****************************************************************************
359 ##
360 ## FUNCTION NAME: get_dword
361 ##
362 ##****************************************************************************
363
364 sub get_dword
365 {
366   my $data;
367
368   read(FILE, $data, 4);
369   return unpack("H8", pack("V", unpack("N", $data)));
370 }
371
372 #*****************************************************************************
373 ##
374 ## FUNCTION NAME: calculate_sdram_init
375 ##
376 ##****************************************************************************
377
378 sub calculate_sdram_init
379 {
380   # Refer to ETRAX 100LX Designers Reference for a description of SDRAM
381   # initialization
382   my $sdram_init_val = hex($_[0]);
383   my $sdram_config_val = hex($_[1]);
384   my $bus_width = $sdram_config_val & 0x00800000;
385   my $speed;
386   my $cas_latency;
387   my $mrs_data;
388   my $temp;
389   my $return_value;
390   my $value;
391
392   $mrs_data = ($sdram_init_val & 0x00ff0000) >> 16;
393   $sdram_init_val &= 0x8000ffff; # Make sure mrs data is 0
394   $sdram_init_val |= 0x80000000; # Make sure sdram is enabled
395   $speed = $sdram_init_val & 0x1000;
396   $cas_latency = $sdram_init_val & 0x3;
397   if ($speed) # 100 MHz
398   {
399     $cas_latency += 2;
400   }
401   else # 50 MHz
402   {
403     $cas_latency += 1;
404   }
405
406   # Calculate value of mrs_data
407   # CAS latency = 2 && bus_width = 32 => 0x40
408   # CAS latency = 3 && bus_width = 32 => 0x60
409   # CAS latency = 2 && bus_width = 16 => 0x20
410   # CAS latency = 3 && bus_width = 16 => 0x30
411   if ($mrs_data == 0)
412   {
413     if ($bus_width == 0) # 16 bits
414     {
415       $mrs_data = $cas_latency == 2 ? 0x20 : 0x30;
416     }
417     else # 32 bits
418     {
419       $mrs_data = $cas_latency == 2 ? 0x40 : 0x60;
420     }
421   }
422
423   $temp = $sdram_init_val | 0x0000c000; # Disable refresh
424   $return_value .= &sdram_command($temp);
425   $return_value .= " --pause 20000";
426
427   $return_value .= &sdram_command($temp, $sdram_precharge);
428   $return_value .= &sdram_command($temp, $sdram_nop);
429
430   $return_value .= " --setreg +0 7";
431   $return_value .= " --label label1";
432   $return_value .= &sdram_command($temp, $sdram_refresh);
433   $return_value .= &sdram_command($temp, $sdram_nop);
434   $return_value .= " --loop +0 label1";
435
436   $return_value .= &sdram_command($temp, $sdram_mrs, $mrs_data);
437   $return_value .= &sdram_command($temp, $sdram_nop);
438
439   $return_value .= &sdram_command($sdram_init_val);
440
441   return $return_value;
442 }
443
444 #*****************************************************************************
445 ##
446 ## FUNCTION NAME: sdram_command
447 ##
448 ##****************************************************************************
449
450 sub sdram_command
451 {
452   my($temp, $value, $mrs_data) = @_;
453
454   $value ||= 0;
455   if ($value == $sdram_mrs)
456   {
457     $value = sprintf("%lx", $temp | ($value << 9) | ($mrs_data << 16));
458   }
459   else
460   {
461     $value = sprintf("%lx", $temp | ($value << 9));
462   }
463
464   return " --setreg $sdram_timing_address $value";
465 }
466
467 #*****************************************************************************
468 ##
469 ## FUNCTION NAME: print_help
470 ##
471 ##****************************************************************************
472
473 sub print_help
474 {
475   print "\nAXIS $my_name, ", '$Revision: 1.16 $ $Date: 2004/11/01 16:32:27 $ ', "\n";
476   die <<EOT;
477 Copyright (C) 2001-2002 Axis Communications AB
478
479 DESCRIPTION:
480   This program is used to boot (and flash) a linux image to a box.
481   It tries to extract the required ETRAX 100 settings from the image file.
482
483 SYNTAX:
484   $my_name [options]
485
486 OPTIONS:
487   -b <bootfile>           : The boot image to use.
488   -d <device>             : The network interface to use, default is eth0.
489   -f                      : Save the image in the flash memory starting at
490                             address 0x10000.
491   -F                      : Save the image in the flash memory starting at
492                             address 0.
493   -h                      : Print this help text.
494   -i <image>              : The path and name of the image to use, default
495                             is fimage.
496   -o <offset>             : The offset in the flash where the flashing starts.
497   -O <offset>             : The offset in the image file where the flashing
498                             starts from.
499   -p                      : Print the resulting etrax100boot command instead
500                             of executing it.
501   -s <size>               : How much to flash (default is the size of the
502                             flash minus the offset specified using -o or -f).
503   -S <size>               : The size of the flash.
504
505   All sizes and offsets above can be specified as decimal numbers, or as
506   hexadecimal numbers by prefixing them with 0x. It is also possible to use
507   the suffixes k and M to specify kilo (1024) or mega (1048576).
508
509 EOT
510 }
511
512 #****************** END OF FILE boot_linux ***********************************