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 100use strict; 101 102use Getopt::Std; 103use File::Basename; 104 105#****************** VARIABLE DECLARATION SECTION ***************************** 106 107use vars qw($my_name %opts); 108use vars qw($text_start $cmd); 109use vars qw($image_name $image_size); 110use vars qw($offset $source_offset $flash_size $flashing_size); 111use vars qw($sdram_timing_address $sdram_config_address); 112use 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 132getopts('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'); 138die "Could not find the image $image_name!\n" unless (-s $image_name); 139 140if ($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 207if (system('./etrax100boot --help > /dev/null') == 0) 208{ 209 $cmd = './etrax100boot'; 210} 211elsif (system('svinto_boot --help > /dev/null') == 0) 212{ 213 $cmd = 'svinto_boot'; 214} 215else 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 227if ($opts{'f'} || $opts{'F'}) 228{ 229 $cmd .= sprintf(" --flash %lx %lx %lx --jump 0", 230 hex($text_start) + $source_offset, $offset, $flashing_size); 231} 232else 233{ 234 $cmd .= " --jump $text_start"; 235} 236 237if ($opts{'p'}) 238{ 239 print "Command:\n$cmd\n"; 240} 241else 242{ 243 system($cmd); 244} 245 246exit 0; 247 248#****************** FUNCTION DEFINITION SECTION ****************************** 249 250#***************************************************************************** 251## 252## FUNCTION NAME: convert_size 253## 254##**************************************************************************** 255 256sub 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 294sub 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 363sub 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 377sub 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 449sub 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 472sub print_help 473{ 474 print "\nAXIS $my_name, ", '$Revision: 1.16 $ $Date: 2004/11/01 16:32:27 $ ', "\n"; 475 die <<EOT; 476Copyright (C) 2001-2002 Axis Communications AB 477 478DESCRIPTION: 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 482SYNTAX: 483 $my_name [options] 484 485OPTIONS: 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 508EOT 509} 510 511#****************** END OF FILE boot_linux *********************************** 512