blob: 72eeeec316de632939ecd7211d9f6413e7894118 [file] [log] [blame]
Simon Glassa3f29ec2011-07-17 09:36:49 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Simon Glass8bd05ec2012-03-22 11:09:04 -07005import binascii
Simon Glass3381a1a2012-03-22 11:13:19 -07006import glob
Simon Glassa3f29ec2011-07-17 09:36:49 -07007import os
8import re
Simon Glasse86f3132013-01-08 16:10:43 -08009import struct
Simon Glassa3f29ec2011-07-17 09:36:49 -070010import time
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -070011
12from exynos import ExynosBl2
Simon Glassa3f29ec2011-07-17 09:36:49 -070013from tools import CmdError
14
Simon Glassb4c14af2013-07-04 11:56:33 +090015# The numbers are the download addresses (in SRAM) for each piece
16exynos_addresses = {
17 'samsung,exynos5250': {
18 'bl1': 0x02021400,
19 'bl2': 0x02023400,
20 'u-boot': 0x43e00000,
21 },
22 'samsung,exynos5420': {
23 'bl1': 0x02022400,
24 'bl2': 0x02024400,
25 'u-boot': 0x23e00000,
26 },
27 }
28
29
Simon Glassa3f29ec2011-07-17 09:36:49 -070030def RoundUp(value, boundary):
31 """Align a value to the next power of 2 boundary.
32
33 Args:
34 value: The value to align.
35 boundary: The boundary value, e.g. 4096. Must be a power of 2.
36
37 Returns:
38 The rounded-up value.
39 """
40 return (value + boundary - 1) & ~(boundary - 1)
41
42
43class WriteFirmware:
44 """Write firmware to a Tegra 2 board using USB A-A cable.
45
46 This class handles re-reflashing a board with new firmware using the Tegra's
47 built-in boot ROM feature. This works by putting the chip into a special mode
48 where it ignores any available firmware and instead reads it from a connected
49 host machine over USB.
50
51 In our case we use that feature to send U-Boot along with a suitable payload
52 and instructions to flash it to SPI flash. The payload is itself normally a
53 full Chrome OS image consisting of U-Boot, some keys and verification
54 information, images and a map of the flash memory.
Simon Glass6a616c12012-09-24 18:13:46 -070055
56 Private attributes:
57 _servo_port: Port number to use to talk to servo with dut-control.
58 Special values are:
59 None: servo is not available.
60 0: any servo will do.
61
Simon Glassa3f29ec2011-07-17 09:36:49 -070062 """
Vadim Bendebury2b719452013-02-12 17:00:06 -080063
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080064 _DOWNLOAD_FAILURE_MESSAGE = '** Load checksum error: check download tool **'
65 _SKIP_VERIFY_MESSAGE = 'Skipping verify'
Vadim Bendebury2b719452013-02-12 17:00:06 -080066 _WRITE_FAILURE_MESSAGE = '** Readback checksum error, programming failed!! **'
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -080067 _WRITE_SUCCESS_MESSAGE = 'Image Programmed Successfully'
Vadim Bendebury2b719452013-02-12 17:00:06 -080068
69 def __init__(self, tools, fdt, output, bundle, update, verify):
Simon Glassa3f29ec2011-07-17 09:36:49 -070070 """Set up a new WriteFirmware object.
71
72 Args:
73 tools: A tools library for us to use.
74 fdt: An fdt which gives us some info that we need.
75 output: An output object to use for printing progress and messages.
Simon Glass0191a882012-05-23 13:15:06 -070076 bundle: A BundleFirmware object which created the image.
Vadim Bendebury2b719452013-02-12 17:00:06 -080077 update: Use faster update algorithm rather then full device erase.
78 verify: Verify the write by doing a readback and CRC.
Simon Glassa3f29ec2011-07-17 09:36:49 -070079 """
80 self._tools = tools
81 self._fdt = fdt
82 self._out = output
Simon Glass0191a882012-05-23 13:15:06 -070083 self._bundle = bundle
Vadim Bendebury19a77122013-01-24 17:38:00 -080084 self.text_base = self._fdt.GetInt('/chromeos-config', 'textbase', -1)
Simon Glassa3f29ec2011-07-17 09:36:49 -070085
Simon Glass5b5fd642011-08-17 12:24:01 -070086 # For speed, use the 'update' algorithm and don't verify
Vadim Bendebury2b719452013-02-12 17:00:06 -080087 self.update = update
88 self.verify = verify
Simon Glass5b5fd642011-08-17 12:24:01 -070089
Simon Glass6a616c12012-09-24 18:13:46 -070090 # Use default servo port
91 self._servo_port = 0
92
93 def SelectServo(self, servo):
94 """Select the servo to use for writing firmware.
95
96 Args:
97 servo: String containing description of servo to use:
98 'none' : Don't use servo, generate an error on any attempt.
99 'any' : Use any available servo.
100 '<port>': Use servo with that port number.
101 """
102 if servo == 'none':
103 self._servo_port = None
104 elif servo == 'any':
105 self._servo_port = 0
106 else:
107 self._servo_port = int(servo)
108 self._out.Notice('Servo port %s' % str(self._servo_port))
109
Michael Prattc610dcf2013-07-17 15:38:53 -0700110 def _GetFlashScript(self, payload_size, flash_dest, checksum, ro_size=None):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700111 """Get the U-Boot boot command needed to flash U-Boot.
112
113 We leave a marker in the string for the load address of the image,
114 since this depends on the size of this script. This can be replaced by
115 the caller provided that the marker length is unchanged.
116
117 Args:
118 payload_size: Size of payload in bytes.
Andrew Chew919858c2013-07-22 15:39:56 -0700119 flash_dest: A dictionary of strings keyed by 'type' (nand, sdmmc,
120 or spi), 'bus', and 'dev'.
Simon Glass8bd05ec2012-03-22 11:09:04 -0700121 checksum: The checksum of the payload (an integer)
Michael Prattc610dcf2013-07-17 15:38:53 -0700122 ro_size: Size of read-only partition. If set, split MMC image between
123 partition 1 (ro) and partition 2 (rw).
Simon Glassa3f29ec2011-07-17 09:36:49 -0700124
125 Returns:
126 A tuple containing:
127 The script, as a string ready to use as a U-Boot boot command, with an
128 embedded marker for the load address.
129 The marker string, which the caller should replace with the correct
130 load address as 8 hex digits, without changing its length.
Michael Prattc610dcf2013-07-17 15:38:53 -0700131 The marker RW string, which the caller should replace with the correct
132 load address for the RW section as 8 hex digits, without changing
133 its length. This is only required if ro_size is set.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700134 """
135 replace_me = 'zsHEXYla'
Michael Prattc610dcf2013-07-17 15:38:53 -0700136 replace_me_rw = 'zsHEXYrw'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800137 page_size = 4096
Andrew Chew919858c2013-07-22 15:39:56 -0700138 boot_type = flash_dest['type']
Simon Glass0dcbecb2012-03-22 21:38:55 -0700139 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800140 page_size = 512
Vadim Bendebury2b719452013-02-12 17:00:06 -0800141 update = self.update and boot_type == 'spi'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800142
Simon Glassa3f29ec2011-07-17 09:36:49 -0700143 cmds = [
144 'setenv address 0x%s' % replace_me,
145 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800146 'setenv length %#x' % RoundUp(payload_size, page_size),
147 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass5b51b472013-03-28 13:06:05 -0700148 'setenv _crc "crc32 -v ${address} ${firmware_size} %08x"' %
Simon Glass8bd05ec2012-03-22 11:09:04 -0700149 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -0700150 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -0700151 ]
Michael Prattc610dcf2013-07-17 15:38:53 -0700152
153 if ro_size:
154 rw_size = payload_size - ro_size
155
156 cmds.extend([
157 'setenv address_ro ${address}',
158 'setenv address_rw 0x%s' % replace_me_rw,
159 'setenv blocks_ro %#x' % (RoundUp(ro_size, page_size) / page_size),
160 'setenv blocks_rw %#x' % (RoundUp(rw_size, page_size) / page_size),
161 ])
162
Simon Glass0dcbecb2012-03-22 21:38:55 -0700163 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -0700164 cmds.extend([
165 'setenv _init "echo Init NAND; nand info"',
166 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
167 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
168 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
169 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700170 elif boot_type == 'sdmmc':
Michael Pratt54aaeed2013-07-12 13:42:47 -0700171 # In U-Boot, strings in double quotes have variables expanded to actual
172 # values. For reasons unclear, this expansion splits the single quoted
173 # argument into separate arguements for each word, which on exynos
174 # boards causes the command to exceed the maximum configured argument
175 # count. Passing the string in single quotes prevents this expansion,
176 # allowing variables to be expanded when run is called.
177 # crbug.com/260294
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800178 cmds.extend([
Michael Pratt54aaeed2013-07-12 13:42:47 -0700179 'setenv _init "echo Init EMMC; mmc rescan"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800180 'setenv _erase "echo Erase EMMC; "',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800181 ])
Michael Prattc610dcf2013-07-17 15:38:53 -0700182 if ro_size:
183 # Write RO section to partition 1, RW to partition 2
184 cmds.extend([
185 "setenv _write 'echo Write EMMC;" \
186 " mmc open 0 1;" \
187 " mmc write ${address_ro} 0 ${blocks_ro};" \
188 " mmc close 0 1;" \
189 " mmc open 0 2;" \
190 " mmc write ${address_rw} 0 ${blocks_rw};" \
191 " mmc close 0 2'",
192 "setenv _read 'echo Read EMMC;" \
193 " mmc open 0 1;" \
194 " mmc read ${address_ro} 0 ${blocks_ro};" \
195 " mmc close 0 1;" \
196 " mmc open 0 2;" \
197 " mmc read ${address_rw} 0 ${blocks_rw};" \
198 " mmc close 0 2'",
199 ])
200 else:
201 cmds.extend([
202 "setenv _write 'echo Write EMMC;" \
203 " mmc open 0 1;" \
204 " mmc write ${address} 0 ${blocks};" \
205 " mmc close 0 1'",
206 "setenv _read 'echo Read EMMC;" \
207 " mmc open 0 1;" \
208 " mmc read ${address} 0 ${blocks};" \
209 " mmc close 0 1'",
210 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700211 else:
Andrew Chew919858c2013-07-22 15:39:56 -0700212 if flash_dest['bus'] is None:
213 flash_dest['bus'] = '0'
214 if flash_dest['dev'] is None:
215 flash_dest['dev'] = '0'
Doug Anderson37ae2292011-09-15 17:41:57 -0700216 cmds.extend([
Andrew Chew919858c2013-07-22 15:39:56 -0700217 'setenv _init "echo Init SPI; sf probe %s:%s"' %
218 (flash_dest['bus'], flash_dest['dev']),
Doug Anderson37ae2292011-09-15 17:41:57 -0700219 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
220 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
221 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
222 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
223 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700224
Doug Anderson37ae2292011-09-15 17:41:57 -0700225 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700226 'echo Firmware loaded to ${address}, size ${firmware_size}, '
227 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700228 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700229 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700230 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700231 if update:
232 cmds += ['time run _update']
233 else:
234 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800235 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700236 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700237 'run _clear',
238 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800239 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800240 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800241 'else',
242 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800243 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800244 'echo',
245 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700246 ]
247 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800248 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700249 cmds.extend([
250 'else',
251 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800252 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700253 'fi',
254 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700255 script = '; '.join(cmds)
Michael Prattc610dcf2013-07-17 15:38:53 -0700256 return script, replace_me, replace_me_rw
Simon Glassa3f29ec2011-07-17 09:36:49 -0700257
Michael Prattc610dcf2013-07-17 15:38:53 -0700258 def _ReplaceAddr(self, data, replace_me, replacement):
259 """Replace address in FDT
260
261 Detect and replace a placeholder address in the FDT.
262
263 Args:
264 data: FDT data to do replacement on
265 replace_me: String currently in FDT to replace
266 replacement: Replacement string
267
268 Returns:
269 Updated data with replacement
270 """
271 if len(replace_me) is not len(replacement):
272 raise ValueError("Internal error: replacement string '%s' length does "
273 "not match new string '%s'" % (replace_me, replacement))
274
275 matches = len(re.findall(replace_me, data))
276 if matches != 1:
277 raise ValueError("Internal error: replacement string '%s' already "
278 "exists in the fdt (%d matches)" % (replace_me, matches))
279
280 return re.sub(replace_me, replacement, data)
281
282 def _PrepareFlasher(self, uboot, payload, flash_dest, ro_size=None):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700283 """Get a flasher ready for sending to the board.
284
285 The flasher is an executable image consisting of:
286
287 - U-Boot (u-boot.bin);
288 - a special FDT to tell it what to do in the form of a run command;
289 - (we could add some empty space here, in case U-Boot is not built to
290 be relocatable);
291 - the payload (which is a full flash image, or signed U-Boot + fdt).
292
293 Args:
294 uboot: Full path to u-boot.bin.
295 payload: Full path to payload.
Andrew Chew919858c2013-07-22 15:39:56 -0700296 flash_dest: A dictionary of strings keyed by 'type' (nand, sdmmc,
297 or spi), 'bus', and 'dev'.
Michael Prattc610dcf2013-07-17 15:38:53 -0700298 boot_type: the src for bootdevice (nand, sdmmc, or spi)
299 ro_size: Size of read-only partition on emmc. If set, indicates that
300 the image should be split, with half written to partition 1, and
301 half written to partition 2.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700302
303 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700304 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700305 """
Simon Glass951a2db2011-07-17 15:58:58 -0700306 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700307 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700308
Simon Glass8bd05ec2012-03-22 11:09:04 -0700309 # Make sure that the checksum is not negative
310 checksum = binascii.crc32(payload_data) & 0xffffffff
311
Michael Prattc610dcf2013-07-17 15:38:53 -0700312 script, replace_start, replace_rw = self._GetFlashScript(len(payload_data),
313 flash_dest, checksum, ro_size)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700314 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800315 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700316 fdt_data = self._tools.ReadFile(fdt.fname)
317
318 # Work out where to place the payload in memory. This is a chicken-and-egg
319 # problem (although in case you haven't heard, it was the chicken that
320 # came first), so we resolve it by replacing the string after
321 # fdt.PutString has done its job.
322 #
323 # Correction: Technically, the egg came first. Whatever genetic mutation
324 # created the new species would have been present in the egg, but not the
325 # parent (since if it was in the parent, it would have been present in the
326 # parent when it was an egg).
327 #
328 # Question: ok so who laid the egg then?
329 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700330
331 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
332 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700333 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700334
Simon Glass2c4b3e52011-11-15 14:45:43 -0800335 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700336 new_str = '%08x' % load_address
Michael Prattc610dcf2013-07-17 15:38:53 -0700337 fdt_data = self._ReplaceAddr(fdt_data, replace_start, new_str)
338
339 if ro_size:
340 new_str_rw = '%08x' % (load_address[0] + ro_size)
341 fdt_data = self._ReplaceAddr(fdt_data, replace_rw, new_str_rw)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700342
343 # Now put it together.
344 data += fdt_data
345 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700346 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700347 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700348 self._tools.WriteFile(flasher, data)
349
350 # Tell the user about a few things.
351 self._tools.OutputSize('U-Boot', uboot)
352 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700353 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700354 self._tools.OutputSize('Flasher', flasher)
355 return flasher
356
Vadim Bendebury19a77122013-01-24 17:38:00 -0800357 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700358 """Flash the image to SPI flash.
359
360 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000361 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700362
363 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700364 flash_dest: Destination for flasher, or None to not create a flasher.
365 This value is a dictionary of strings keyed by 'type', 'bus', and
366 'dev'.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700367 uboot: Full path to u-boot.bin.
368 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
369 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700370 bootstub: Full path to bootstub, which is the payload without the
371 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700372
373 Returns:
374 True if ok, False if failed.
375 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800376 # Use a Regex to pull Boot type from BCT file.
377 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
378 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700379
380 # TODO(sjg): The boot type is currently selected by the bct, rather than
Andrew Chew919858c2013-07-22 15:39:56 -0700381 # flash_dest['type'] selecting which bct to use. This is a bit backwards.
382 # For now we go with the bct's idea.
383 flash_dest['type'] = filter(match.match, bct_dumped)
384 flash_dest['type'] = match.match(
385 flash_dest['type'][0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700386
Simon Glass89ecf712012-06-07 12:20:15 -0700387 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700388 image = self._PrepareFlasher(uboot, payload, flash_dest)
Simon Glasse1824db2012-07-11 17:38:40 +0200389 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700390 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700391
Simon Glasse1824db2012-07-11 17:38:40 +0200392 else:
393 image = payload
394 # If we don't know the textbase, extract it from the payload.
395 if self.text_base == -1:
396 data = self._tools.ReadFile(payload)
397 # Skip the BCT which is the first 64KB
398 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
399
Simon Glass89ecf712012-06-07 12:20:15 -0700400 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700401 self._out.Progress('Uploading flasher image')
402 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700403 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000404 '--bootloader', image,
405 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700406 ]
407
408 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
409 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800410 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700411 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700412 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000413 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700414 self._out.Notice('Flasher downloaded - please see serial output '
415 'for progress.')
416 return True
417
418 except CmdError as err:
419 if not self._out.stdout_is_tty:
420 return False
421
422 # Only show the error output once unless it changes.
423 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200424 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000425 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700426
427 if err != last_err:
428 self._out.Notice(err)
429 last_err = err
430 self._out.Progress('Please connect USB A-A cable and do a '
431 'recovery-reset', True)
432 time.sleep(1)
433
434 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700435
Simon Glass27a9c142012-03-15 21:08:29 -0700436 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
437 """Wait until we see a device on the USB bus.
438
439 Args:
440 name: Board type name
441 vendor_id: USB vendor ID to look for
442 product_id: USB product ID to look for
443 timeout: Timeout to wait in seconds
444
445 Returns
446 True if the device was found, False if we timed out.
447 """
448 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700449 start_time = time.time()
450 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700451 try:
452 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
453 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700454 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700455 return True
456
Vadim Bendebury19a77122013-01-24 17:38:00 -0800457 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700458 pass
459
Simon Glass3381a1a2012-03-22 11:13:19 -0700460 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700461
Vadim Bendebury2b719452013-02-12 17:00:06 -0800462 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700463 """Run dut-control with supplied arguments.
464
Simon Glass2065a742013-02-09 13:39:26 -0800465 The correct servo will be used based on self._servo_port. If servo use is
466 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700467
468 Args:
469 args: List of arguments to dut-control.
470
Simon Glass2065a742013-02-09 13:39:26 -0800471 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800472 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700473 """
474 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800475 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800476 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700477 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800478 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700479
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800480 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800481 """Verify flash programming operation success.
482
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800483 The DUT is presumed to be programming flash with console capture mode on.
484 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800485
486 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800487 CmdError if the following cases:
488 - none of the strings show up in the allotted time (2 minutes)
489 - console goes silent for more than 10 seconds
490 - one of the error messages seen in the stream
491 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800492 """
493
494 _SOFT_DEADLINE_LIMIT = 10
495 _HARD_DEADLINE_LIMIT = 120
496 string_leftover = ''
497 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
498 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
499
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800500 if self.verify:
501 done_line = self._WRITE_SUCCESS_MESSAGE
502 else:
503 done_line = self._SKIP_VERIFY_MESSAGE
504
Vadim Bendebury2b719452013-02-12 17:00:06 -0800505 while True:
506 now = time.time()
507 if now > hard_deadline:
508 raise CmdError('Target console flooded, programming failed')
509 if now > soft_deadline:
510 raise CmdError('Target console dead, programming failed')
511 stream = self.DutControl(['cpu_uart_stream',])
512 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
513 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800514 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800515
516 text = string_leftover + match.group(1)
517 strings = text.split('\\r')
518 string_leftover = strings.pop()
519 if strings:
520 soft_deadline = now + _SOFT_DEADLINE_LIMIT
521 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800522 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800523 return True
524 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800525 raise CmdError('Readback verification failed!')
526 if self._DOWNLOAD_FAILURE_MESSAGE in string:
527 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800528
Simon Glass4c54a912013-02-18 16:56:29 -0800529 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700530 """Extract the BL1, BL2 and U-Boot parts from a payload.
531
532 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
533
534 This pulls out the various parts, puts them into files and returns
535 these files.
536
537 Args:
538 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800539 truncate_to_fdt: Truncate the U-Boot image at the start of its
540 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700541
542 Returns:
543 (bl1, bl2, image) where:
544 bl1 is the filename of the extracted BL1
545 bl2 is the filename of the extracted BL2
546 image is the filename of the extracted U-Boot image
547 """
548 # Pull out the parts from the payload
549 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
550 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
551 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
552 data = self._tools.ReadFile(payload)
553
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700554 try:
555 bl1_size = int(self._fdt.GetProps('/flash/pre-boot')['size'])
556 bl2_size = int(self._fdt.GetProps('/flash/spl')['size'])
557 uboot_offset = bl1_size + bl2_size
Simon Glass496c8302013-07-20 18:04:02 -0600558 except (CmdError, KeyError):
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700559 self._out.Warning('No component nodes in the device tree')
560 # The BL1 is always 8KB - extract that part into a new file
561 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
562 bl1_size = 0x2000
Simon Glass3c5b35b2012-05-23 13:22:23 -0700563
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700564 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
565 # which is the 'B reset' instruction at the start of U-Boot. When
566 # U-Boot is LZO compressed, we look for a LZO magic instead.
567 start_data = [struct.pack('<L', 0xea000014),
568 struct.pack('<L', 0xea000013),
569 struct.pack('>B3s', 0x89, 'LZO')]
570 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
571 uboot_offset = None
572 for start in starts:
573 if start != -1 and (not uboot_offset or start < uboot_offset):
574 uboot_offset = start
575 if not uboot_offset:
576 raise ValueError('Could not locate start of U-Boot')
577 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700578
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700579 # Sanity check: At present we only allow 14KB and 30KB for SPL
580 allowed = [14, 30]
581 if (bl2_size >> 10) not in allowed:
582 raise ValueError('BL2 size is %dK - only %s supported' %
583 (bl2_size >> 10, ', '.join(
584 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800585 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
586
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700587 self._tools.WriteFile(bl1, data[:bl1_size])
588 self._tools.WriteFile(bl2, data[bl1_size:bl1_size + bl2_size])
Simon Glasse86f3132013-01-08 16:10:43 -0800589
Simon Glassbc0d8d42013-02-09 11:59:36 -0800590 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800591 # to an assumed maximum size. As a secondary hack, locate the FDT
592 # and truncate U-Boot from that point. The correct FDT will be added
593 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800594 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
595 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800596 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
597 if truncate_to_fdt:
598 fdt_magic = struct.pack('>L', 0xd00dfeed)
599 fdt_offset = uboot_data.rfind(fdt_magic)
600 uboot_data = uboot_data[:fdt_offset]
601
602 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700603 return bl1, bl2, image
604
Vadim Bendebury19a77122013-01-24 17:38:00 -0800605 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700606 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700607 """Flash the image to SPI flash.
608
609 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000610 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700611
612 Args:
Andrew Chew919858c2013-07-22 15:39:56 -0700613 flash_dest: Destination for flasher, or None to not create a flasher.
614 This is a dictionary of strings keyed by 'type', 'bus', and 'dev'.
615 Valid options for 'type' are spi, sdmmc.
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700616 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700617 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700618 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700619 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700620 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700621
622 Returns:
623 True if ok, False if failed.
Simon Glassb4c14af2013-07-04 11:56:33 +0900624
625 Raises:
626 CmdError if a supported Exynos model is not detected in the device tree.
Simon Glass27a9c142012-03-15 21:08:29 -0700627 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800628 tools = self._tools
629 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800630 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700631 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800632 # If we don't have some bits, get them from the image
633 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
634 self._out.Warning('Extracting U-Boot from payload')
635 flash_uboot = payload_image
636 if not bl1 or not os.path.exists(tools.Filename(bl1)):
637 self._out.Warning('Extracting BL1 from payload')
638 bl1 = payload_bl1
639 if not bl2 or not os.path.exists(tools.Filename(bl2)):
640 self._out.Warning('Extracting BL2 from payload')
641 bl2 = payload_bl2
Michael Pratt24e7c162013-07-12 09:35:28 -0700642 else:
643 # Update BL2 machine parameters, as
644 # the BL2 passed in may not be updated
645 spl_load_size = os.stat(tools.Filename(bl2)).st_size
646 bl2_handler = ExynosBl2(tools, self._out)
647 bl2 = bl2_handler.Configure(self._fdt, spl_load_size,
648 bl2, 'flasher', True)
Andrew Chew919858c2013-07-22 15:39:56 -0700649 # Set default values for Exynos targets.
650 if flash_dest['bus'] is None:
651 flash_dest['bus'] = 1
652 if flash_dest['dev'] is None:
653 flash_dest['dev'] = 0
Michael Prattc610dcf2013-07-17 15:38:53 -0700654
655 # Try to determine RO section size
656 ro_size = None
657 if flash_dest['type'] == 'sdmmc':
658 try:
659 ro_size = self._fdt.GetFlashPartSize('wp', 'ro')
660 except (CmdError, ValueError):
661 self._out.Warning('Unable to detect RO section size')
662
663 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, ro_size)
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700664 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800665 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700666
667 vendor_id = 0x04e8
668 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700669
Simon Glassb4c14af2013-07-04 11:56:33 +0900670 # Work out the exynos model we are talking to,
671 compatible = self._fdt.GetString('/', 'compatible')
672
673 for model in compatible.split():
674 addresses = exynos_addresses.get(model)
675 if addresses:
676 break
677 else:
678 # TODO(sjg@chromium.org): Remove this when upstream U-Boot has the
679 # 'samsung,exynos5250' compatible string.
680 addresses = exynos_addresses.get('samsung,exynos5250')
681 self._out.Warning('No exynos compatible string, assuming Exynos 5250')
682
683 if not addresses:
684 raise CmdError("Unable to determine USB download addresses, compatible" +
685 "string is '%s'" % compatible)
686
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800687 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800688 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
689 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800690 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800691 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700692 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800693 if preserved_dut_hub_sel != required_dut_hub_sel:
694 # Need to set it to get the port properly powered up.
695 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700696 if self._servo_port is not None:
697 self._out.Progress('Reseting board via servo')
698 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700699
Simon Glassde9c8072012-07-02 22:29:02 -0700700 # If we have a kernel to write, create a new image with that added.
701 if kernel:
702 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
703 data = self._tools.ReadFile(image)
704
705 # Pad the original payload out to the original length
706 data += '\0' * (os.stat(payload).st_size - len(data))
707 data += self._tools.ReadFile(kernel)
708 self._tools.WriteFile(dl_image, data)
709 else:
710 dl_image = image
711
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700712 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700713 download_list = [
Simon Glassb4c14af2013-07-04 11:56:33 +0900714 ['bl1', bl1],
715 ['bl2', bl2],
716 ['u-boot', dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700717 ]
Simon Glassb4c14af2013-07-04 11:56:33 +0900718
Simon Glass3381a1a2012-03-22 11:13:19 -0700719 try:
Simon Glass4968a472012-05-23 13:52:19 -0700720 for upto in range(len(download_list)):
721 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700722 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700723 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700724 raise CmdError('Could not find Exynos board on USB port')
725 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glassb4c14af2013-07-04 11:56:33 +0900726 self._out.Notice(item[1])
Simon Glass27a9c142012-03-15 21:08:29 -0700727 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700728
Simon Glass4968a472012-05-23 13:52:19 -0700729 if upto == 0:
730 # The IROM needs roughly 200ms here to be ready for USB download
731 time.sleep(.5)
732
Simon Glassb4c14af2013-07-04 11:56:33 +0900733 args = ['-a', '%#x' % addresses[item[0]], '-f', item[1]]
Simon Glass79e3dd02012-08-28 20:08:50 -0700734 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700735
Simon Glass3381a1a2012-03-22 11:13:19 -0700736 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800737 # Make sure that the power button is released and dut_sel_hub state is
738 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700739 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800740 if preserved_dut_hub_sel != required_dut_hub_sel:
741 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800742 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700743
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800744 if flash_dest is None:
745 self._out.Notice('Image downloaded - please see serial output '
746 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700747 return True
748
Simon Glass0c2ba482012-03-22 21:57:51 -0700749 def _GetDiskInfo(self, disk, item):
750 """Returns information about a SCSI disk device.
751
752 Args:
753 disk: a block device name in sys/block, like '/sys/block/sdf'.
754 item: the item of disk information that is required.
755
756 Returns:
757 The information obtained, as a string, or '[Unknown]' if not found
758 """
759 dev_path = os.path.join(disk, 'device')
760
761 # Search upwards and through symlinks looking for the item.
762 while os.path.isdir(dev_path) and dev_path != '/sys':
763 fname = os.path.join(dev_path, item)
764 if os.path.exists(fname):
765 with open(fname, 'r') as fd:
766 return fd.readline().rstrip()
767
768 # Move up a level and follow any symlink.
769 new_path = os.path.join(dev_path, '..')
770 if os.path.islink(new_path):
771 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
772 dev_path = new_path
773 return '[Unknown]'
774
775 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700776 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700777
778 Args:
779 device: Device to check, like '/dev/sdf'.
780
781 Returns:
782 Capacity of device in GB, or 0 if not known.
783 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700784 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700785 args = ['-l', device]
786 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700787 for line in stdout.splitlines():
788 m = re_capacity.match(line)
789 if m:
790 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700791 return 0
792
793 def _ListUsbDisks(self):
794 """Return a list of available removable USB disks.
795
796 Returns:
797 List of USB devices, each element is itself a list containing:
798 device ('/dev/sdx')
799 manufacturer name
800 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700801 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700802 """
803 disk_list = []
804 for disk in glob.glob('/sys/block/sd*'):
805 with open(disk + '/removable', 'r') as fd:
806 if int(fd.readline()) == 1:
807 device = '/dev/%s' % disk.split('/')[-1]
808 manuf = self._GetDiskInfo(disk, 'manufacturer')
809 product = self._GetDiskInfo(disk, 'product')
810 capacity = self._GetDiskCapacity(device)
811 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700812 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700813 return disk_list
814
815 def WriteToSd(self, flash_dest, disk, uboot, payload):
816 if flash_dest:
Andrew Chew919858c2013-07-22 15:39:56 -0700817 # Set default values for sd.
818 if flash_dest['bus'] is None:
819 flash_dest['bus'] = 1
820 if flash_dest['dev'] is None:
821 flash_dest['dev'] = 0
822 raw_image = self._PrepareFlasher(uboot, payload, flash_dest)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700823 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700824 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700825
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700826 bl2_handler = ExynosBl2(self._tools, self._out)
Vadim Bendebury0c961a72013-06-11 13:35:07 -0700827 bl2_file = bl2_handler.Configure(self._fdt, spl_load_size,
Vadim Bendebury8ae67892013-06-11 17:45:15 -0700828 bl2, 'flasher', True)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700829 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700830
Vadim Bendebury22de0492013-06-17 16:11:20 -0700831 # Pad BL2 out to the required size. Its size could be either 14K or 30K
832 # bytes, but the next object in the file needs to be aligned at an 8K
833 # boundary. The BL1 size is also known to be 8K bytes, so the total BL1
834 # + BL2 size needs to be aligned to 8K (0x2000) boundary.
835 aligned_size = (len(data) + 0x1fff) & ~0x1fff
836 pad_size = aligned_size - len(data)
837 data += '\0' * pad_size
838
Simon Glass559b6612012-05-23 13:28:45 -0700839 data += self._tools.ReadFile(raw_image)
840 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
841 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700842 self._out.Progress('Writing flasher to %s' % disk)
843 else:
844 image = payload
845 self._out.Progress('Writing image to %s' % disk)
846
847 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
848 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700849 self._out.Progress('Syncing')
850 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700851
852 def SendToSdCard(self, dest, flash_dest, uboot, payload):
853 """Write a flasher to an SD card.
854
855 Args:
856 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700857 ':.' selects the only available device, fails if more than one option
858 ':<device>' select deivce
859
860 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700861 ':.'
862 ':/dev/sdd'
863
864 flash_dest: Destination for flasher, or None to not create a flasher:
865 Valid options are spi, sdmmc.
866 uboot: Full path to u-boot.bin.
867 payload: Full path to payload.
868 """
869 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700870
Vadim Bendebury223af572013-04-27 13:25:13 -0700871 # If no removable devices found - prompt user and wait for one to appear.
872 disks = self._ListUsbDisks()
873 try:
874 spinner = '|/-\\'
875 index = 0
876 while not disks:
877 self._out.ClearProgress()
878 self._out.Progress('No removable devices found, plug something in %s '
879 % spinner[index], trailer='')
880 index = (index + 1) % len(spinner)
881 disks = self._ListUsbDisks()
882 time.sleep(.2)
883 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700884 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700885
886 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700887 name = dest[1:]
888
889 # A '.' just means to use the only available disk.
890 if name == '.' and len(disks) == 1:
891 disk = disks[0][0]
892 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700893 # Use the device name.
894 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700895 disk = disk_info[0]
896
897 if disk:
898 self.WriteToSd(flash_dest, disk, uboot, payload)
899 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700900 msg = ["Please specify destination as '-w sd:<disk_description>'",]
901 msg.append(' - <disk_description> can be either . for the only disk,')
902 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700903 # List available disks as a convenience.
904 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700905 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700906 disk[0],
907 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700908 disk[3] / 10.0))
909 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700910
Vadim Bendebury19a77122013-01-24 17:38:00 -0800911 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700912 """Send an image to an attached EM100 device.
913
914 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
915 to do the SPI emulation, then write the image, then boot the board.
916 All going well, this is enough to get U-Boot running.
917
918 Args:
919 image_fname: Filename of image to send
920 """
921 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
922 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800923 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700924
925 # TODO(sjg@chromium.org): This is for link. We could make this
926 # configurable from the fdt.
927 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
928 self._out.Progress('Writing image to em100')
929 self._tools.Run('em100', args, sudo=True)
930
Simon Glass93673cf2013-04-26 17:55:55 -0700931 if self._servo_port is not None:
932 self._out.Progress('Resetting board via servo')
933 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
934 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
935 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700936
Simon Glass0c2ba482012-03-22 21:57:51 -0700937
Simon Glass27a9c142012-03-15 21:08:29 -0700938def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700939 bundle, update=True, verify=False, dest=None,
Andrew Chew919858c2013-07-22 15:39:56 -0700940 flasher_dest=None, kernel=None, bootstub=None,
941 servo='any', method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700942 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700943
944 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700945 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700946
947 Args:
948 output: cros_output object to use.
949 tools: Tools object to use.
950 fdt: Fdt object to use as our device tree.
951 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700952 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700953 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700954 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800955 update: Use faster update algorithm rather then full device erase.
956 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700957 dest: Destination device to write firmware to (usb, sd).
Andrew Chew919858c2013-07-22 15:39:56 -0700958 flasher_dest: a string, destination device for flasher to program payload
959 into. This string has the form <type>:[bus]:[dev], where
960 bus and dev are optional (and default to device and target
961 specific defaults when absent).
Simon Glassde9c8072012-07-02 22:29:02 -0700962 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800963 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700964 servo: Describes the servo unit to use: none=none; any=any; otherwise
965 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700966 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800967 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glassacf4b3e2013-07-19 16:57:43 -0600968 fdt.PutInteger('/config', 'bootsecure', 0)
Simon Glass6a616c12012-09-24 18:13:46 -0700969 write.SelectServo(servo)
Andrew Chew919858c2013-07-22 15:39:56 -0700970 flash_dest = None
971 if flasher_dest:
972 # Parse flasher_dest and store into a dictionary.
973 flash_dest_list = flasher_dest.split(":")
974 flash_dest = {'type': flash_dest_list[0], 'bus': None, 'dev': None}
975 if len(flash_dest_list) > 1:
976 flash_dest['bus'] = flash_dest_list[1]
977 if len(flash_dest_list) > 2:
978 flash_dest['dev'] = flash_dest_list[2]
Simon Glassd65f65f2013-03-28 17:03:41 -0700979 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
980 elif bootstub:
981 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700982 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800983 try:
984 write.DutControl(['cpu_uart_capture:on',])
985 method = fdt.GetString('/chromeos-config', 'flash-method', method)
986 if method == 'tegra':
987 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800988 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
989 image_fname, bootstub)
990 elif method == 'exynos':
991 tools.CheckTool('lsusb', 'usbutils')
992 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
993 ok = write.ExynosFlashImage(flash_dest, flasher,
994 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
995 kernel)
996 else:
997 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800998
Vadim Bendebury2b719452013-02-12 17:00:06 -0800999 if not ok:
1000 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -08001001 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -08001002
1003 if flash_dest is not None and servo != 'none':
1004 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -08001005 output.Progress('Done!')
1006
Vadim Bendebury2b719452013-02-12 17:00:06 -08001007 finally:
1008 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -07001009 elif dest == 'em100':
1010 # crosbug.com/31625
1011 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -08001012 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -07001013 elif dest.startswith('sd'):
1014 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -07001015 else:
Simon Glasse0b61442012-03-13 15:29:51 -07001016 raise CmdError("Unknown destination device '%s'" % dest)