blob: d2d1b7d21e3d688d75ae16889b1e005bf98f98c2 [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
Vadim Bendebury2b719452013-02-12 17:00:06 -0800110 def _GetFlashScript(self, payload_size, boot_type, checksum, bus='0'):
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.
Simon Glass0dcbecb2012-03-22 21:38:55 -0700119 boot_type: The source for bootdevice (nand, sdmmc, or spi)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700120 checksum: The checksum of the payload (an integer)
121 bus: The bus number
Simon Glassa3f29ec2011-07-17 09:36:49 -0700122
123 Returns:
124 A tuple containing:
125 The script, as a string ready to use as a U-Boot boot command, with an
126 embedded marker for the load address.
127 The marker string, which the caller should replace with the correct
128 load address as 8 hex digits, without changing its length.
129 """
130 replace_me = 'zsHEXYla'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800131 page_size = 4096
Simon Glass0dcbecb2012-03-22 21:38:55 -0700132 if boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800133 page_size = 512
Vadim Bendebury2b719452013-02-12 17:00:06 -0800134 update = self.update and boot_type == 'spi'
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800135
Simon Glassa3f29ec2011-07-17 09:36:49 -0700136 cmds = [
137 'setenv address 0x%s' % replace_me,
138 'setenv firmware_size %#x' % payload_size,
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800139 'setenv length %#x' % RoundUp(payload_size, page_size),
140 'setenv blocks %#x' % (RoundUp(payload_size, page_size) / page_size),
Simon Glass5b51b472013-03-28 13:06:05 -0700141 'setenv _crc "crc32 -v ${address} ${firmware_size} %08x"' %
Simon Glass8bd05ec2012-03-22 11:09:04 -0700142 checksum,
Simon Glass5b5fd642011-08-17 12:24:01 -0700143 'setenv _clear "echo Clearing RAM; mw.b ${address} 0 ${length}"',
Doug Anderson37ae2292011-09-15 17:41:57 -0700144 ]
Simon Glass0dcbecb2012-03-22 21:38:55 -0700145 if boot_type == 'nand':
Doug Anderson37ae2292011-09-15 17:41:57 -0700146 cmds.extend([
147 'setenv _init "echo Init NAND; nand info"',
148 'setenv _erase "echo Erase NAND; nand erase 0 ${length}"',
149 'setenv _write "echo Write NAND; nand write ${address} 0 ${length}"',
150 'setenv _read "echo Read NAND; nand read ${address} 0 ${length}"',
151 ])
Simon Glass0dcbecb2012-03-22 21:38:55 -0700152 elif boot_type == 'sdmmc':
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800153 cmds.extend([
Allen Martinc4e25b42013-04-05 17:05:39 -0700154 'setenv _init "echo Init EMMC; mmc rescan 0"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800155 'setenv _erase "echo Erase EMMC; "',
Allen Martinc4e25b42013-04-05 17:05:39 -0700156 'setenv _write "echo Write EMMC; mmc open 0 1;' \
157 ' mmc write ${address} 0 ' \
158 '${blocks};' \
159 ' mmc close 0 1"',
160 'setenv _read "echo Read EMMC; mmc open 0 1;' \
161 ' mmc read ${address} 0 ' \
162 '${blocks};' \
163 ' mmc close 0 1"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800164 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700165 else:
166 cmds.extend([
Simon Glass3d9a6c62012-03-15 20:38:04 -0700167 'setenv _init "echo Init SPI; sf probe %s"' % bus,
Doug Anderson37ae2292011-09-15 17:41:57 -0700168 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
169 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
170 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
171 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
172 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700173
Doug Anderson37ae2292011-09-15 17:41:57 -0700174 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700175 'echo Firmware loaded to ${address}, size ${firmware_size}, '
176 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700177 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700178 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700179 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700180 if update:
181 cmds += ['time run _update']
182 else:
183 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800184 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700185 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700186 'run _clear',
187 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800188 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800189 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800190 'else',
191 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800192 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800193 'echo',
194 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700195 ]
196 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800197 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700198 cmds.extend([
199 'else',
200 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800201 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700202 'fi',
203 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700204 script = '; '.join(cmds)
205 return script, replace_me
206
Vadim Bendebury2b719452013-02-12 17:00:06 -0800207 def _PrepareFlasher(self, uboot, payload, boot_type, bus):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700208 """Get a flasher ready for sending to the board.
209
210 The flasher is an executable image consisting of:
211
212 - U-Boot (u-boot.bin);
213 - a special FDT to tell it what to do in the form of a run command;
214 - (we could add some empty space here, in case U-Boot is not built to
215 be relocatable);
216 - the payload (which is a full flash image, or signed U-Boot + fdt).
217
218 Args:
219 uboot: Full path to u-boot.bin.
220 payload: Full path to payload.
Simon Glass0dcbecb2012-03-22 21:38:55 -0700221 boot_type: the src for bootdevice (nand, sdmmc, or spi)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700222
223 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700224 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700225 """
Simon Glass951a2db2011-07-17 15:58:58 -0700226 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700227 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700228
Simon Glass8bd05ec2012-03-22 11:09:04 -0700229 # Make sure that the checksum is not negative
230 checksum = binascii.crc32(payload_data) & 0xffffffff
231
Vadim Bendebury2b719452013-02-12 17:00:06 -0800232 script, replace_me = self._GetFlashScript(len(payload_data), boot_type,
233 checksum, bus)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700234 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800235 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700236 fdt_data = self._tools.ReadFile(fdt.fname)
237
238 # Work out where to place the payload in memory. This is a chicken-and-egg
239 # problem (although in case you haven't heard, it was the chicken that
240 # came first), so we resolve it by replacing the string after
241 # fdt.PutString has done its job.
242 #
243 # Correction: Technically, the egg came first. Whatever genetic mutation
244 # created the new species would have been present in the egg, but not the
245 # parent (since if it was in the parent, it would have been present in the
246 # parent when it was an egg).
247 #
248 # Question: ok so who laid the egg then?
249 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700250
251 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
252 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700253 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700254
Simon Glass2c4b3e52011-11-15 14:45:43 -0800255 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700256 new_str = '%08x' % load_address
257 if len(replace_me) is not len(new_str):
258 raise ValueError("Internal error: replacement string '%s' length does "
259 "not match new string '%s'" % (replace_me, new_str))
Vadim Bendebury19a77122013-01-24 17:38:00 -0800260 matches = len(re.findall(replace_me, fdt_data))
261 if matches != 1:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700262 raise ValueError("Internal error: replacement string '%s' already "
263 "exists in the fdt (%d matches)" % (replace_me, matches))
264 fdt_data = re.sub(replace_me, new_str, fdt_data)
265
266 # Now put it together.
267 data += fdt_data
268 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700269 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700270 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700271 self._tools.WriteFile(flasher, data)
272
273 # Tell the user about a few things.
274 self._tools.OutputSize('U-Boot', uboot)
275 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700276 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700277 self._tools.OutputSize('Flasher', flasher)
278 return flasher
279
Vadim Bendebury19a77122013-01-24 17:38:00 -0800280 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700281 """Flash the image to SPI flash.
282
283 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000284 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700285
286 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700287 flash_dest: Destination for flasher, or None to not create a flasher
288 Valid options are spi, sdmmc
Simon Glassa3f29ec2011-07-17 09:36:49 -0700289 uboot: Full path to u-boot.bin.
290 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
291 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700292 bootstub: Full path to bootstub, which is the payload without the
293 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700294
295 Returns:
296 True if ok, False if failed.
297 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800298 # Use a Regex to pull Boot type from BCT file.
299 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
300 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700301
302 # TODO(sjg): The boot type is currently selected by the bct, rather than
303 # flash_dest selecting which bct to use. This is a bit backwards. For now
304 # we go with the bct's idea.
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800305 boot_type = filter(match.match, bct_dumped)
Simon Glass0dcbecb2012-03-22 21:38:55 -0700306 boot_type = match.match(boot_type[0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700307
Simon Glass89ecf712012-06-07 12:20:15 -0700308 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800309 image = self._PrepareFlasher(uboot, payload, boot_type, 0)
Simon Glasse1824db2012-07-11 17:38:40 +0200310 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700311 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700312
Simon Glasse1824db2012-07-11 17:38:40 +0200313 else:
314 image = payload
315 # If we don't know the textbase, extract it from the payload.
316 if self.text_base == -1:
317 data = self._tools.ReadFile(payload)
318 # Skip the BCT which is the first 64KB
319 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
320
Simon Glass89ecf712012-06-07 12:20:15 -0700321 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700322 self._out.Progress('Uploading flasher image')
323 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700324 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000325 '--bootloader', image,
326 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700327 ]
328
329 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
330 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800331 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700332 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700333 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000334 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700335 self._out.Notice('Flasher downloaded - please see serial output '
336 'for progress.')
337 return True
338
339 except CmdError as err:
340 if not self._out.stdout_is_tty:
341 return False
342
343 # Only show the error output once unless it changes.
344 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200345 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000346 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700347
348 if err != last_err:
349 self._out.Notice(err)
350 last_err = err
351 self._out.Progress('Please connect USB A-A cable and do a '
352 'recovery-reset', True)
353 time.sleep(1)
354
355 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700356
Simon Glass27a9c142012-03-15 21:08:29 -0700357 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
358 """Wait until we see a device on the USB bus.
359
360 Args:
361 name: Board type name
362 vendor_id: USB vendor ID to look for
363 product_id: USB product ID to look for
364 timeout: Timeout to wait in seconds
365
366 Returns
367 True if the device was found, False if we timed out.
368 """
369 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700370 start_time = time.time()
371 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700372 try:
373 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
374 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700375 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700376 return True
377
Vadim Bendebury19a77122013-01-24 17:38:00 -0800378 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700379 pass
380
Simon Glass3381a1a2012-03-22 11:13:19 -0700381 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700382
Vadim Bendebury2b719452013-02-12 17:00:06 -0800383 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700384 """Run dut-control with supplied arguments.
385
Simon Glass2065a742013-02-09 13:39:26 -0800386 The correct servo will be used based on self._servo_port. If servo use is
387 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700388
389 Args:
390 args: List of arguments to dut-control.
391
Simon Glass2065a742013-02-09 13:39:26 -0800392 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800393 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700394 """
395 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800396 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800397 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700398 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800399 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700400
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800401 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800402 """Verify flash programming operation success.
403
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800404 The DUT is presumed to be programming flash with console capture mode on.
405 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800406
407 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800408 CmdError if the following cases:
409 - none of the strings show up in the allotted time (2 minutes)
410 - console goes silent for more than 10 seconds
411 - one of the error messages seen in the stream
412 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800413 """
414
415 _SOFT_DEADLINE_LIMIT = 10
416 _HARD_DEADLINE_LIMIT = 120
417 string_leftover = ''
418 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
419 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
420
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800421 if self.verify:
422 done_line = self._WRITE_SUCCESS_MESSAGE
423 else:
424 done_line = self._SKIP_VERIFY_MESSAGE
425
Vadim Bendebury2b719452013-02-12 17:00:06 -0800426 while True:
427 now = time.time()
428 if now > hard_deadline:
429 raise CmdError('Target console flooded, programming failed')
430 if now > soft_deadline:
431 raise CmdError('Target console dead, programming failed')
432 stream = self.DutControl(['cpu_uart_stream',])
433 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
434 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800435 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800436
437 text = string_leftover + match.group(1)
438 strings = text.split('\\r')
439 string_leftover = strings.pop()
440 if strings:
441 soft_deadline = now + _SOFT_DEADLINE_LIMIT
442 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800443 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800444 return True
445 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800446 raise CmdError('Readback verification failed!')
447 if self._DOWNLOAD_FAILURE_MESSAGE in string:
448 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800449
Simon Glass4c54a912013-02-18 16:56:29 -0800450 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700451 """Extract the BL1, BL2 and U-Boot parts from a payload.
452
453 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
454
455 This pulls out the various parts, puts them into files and returns
456 these files.
457
458 Args:
459 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800460 truncate_to_fdt: Truncate the U-Boot image at the start of its
461 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700462
463 Returns:
464 (bl1, bl2, image) where:
465 bl1 is the filename of the extracted BL1
466 bl2 is the filename of the extracted BL2
467 image is the filename of the extracted U-Boot image
468 """
469 # Pull out the parts from the payload
470 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
471 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
472 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
473 data = self._tools.ReadFile(payload)
474
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700475 try:
476 bl1_size = int(self._fdt.GetProps('/flash/pre-boot')['size'])
477 bl2_size = int(self._fdt.GetProps('/flash/spl')['size'])
478 uboot_offset = bl1_size + bl2_size
479 except CmdError:
480 self._out.Warning('No component nodes in the device tree')
481 # The BL1 is always 8KB - extract that part into a new file
482 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
483 bl1_size = 0x2000
Simon Glass3c5b35b2012-05-23 13:22:23 -0700484
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700485 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
486 # which is the 'B reset' instruction at the start of U-Boot. When
487 # U-Boot is LZO compressed, we look for a LZO magic instead.
488 start_data = [struct.pack('<L', 0xea000014),
489 struct.pack('<L', 0xea000013),
490 struct.pack('>B3s', 0x89, 'LZO')]
491 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
492 uboot_offset = None
493 for start in starts:
494 if start != -1 and (not uboot_offset or start < uboot_offset):
495 uboot_offset = start
496 if not uboot_offset:
497 raise ValueError('Could not locate start of U-Boot')
498 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700499
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700500 # Sanity check: At present we only allow 14KB and 30KB for SPL
501 allowed = [14, 30]
502 if (bl2_size >> 10) not in allowed:
503 raise ValueError('BL2 size is %dK - only %s supported' %
504 (bl2_size >> 10, ', '.join(
505 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800506 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
507
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700508 self._tools.WriteFile(bl1, data[:bl1_size])
509 self._tools.WriteFile(bl2, data[bl1_size:bl1_size + bl2_size])
Simon Glasse86f3132013-01-08 16:10:43 -0800510
Simon Glassbc0d8d42013-02-09 11:59:36 -0800511 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800512 # to an assumed maximum size. As a secondary hack, locate the FDT
513 # and truncate U-Boot from that point. The correct FDT will be added
514 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800515 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
516 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800517 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
518 if truncate_to_fdt:
519 fdt_magic = struct.pack('>L', 0xd00dfeed)
520 fdt_offset = uboot_data.rfind(fdt_magic)
521 uboot_data = uboot_data[:fdt_offset]
522
523 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700524 return bl1, bl2, image
525
Vadim Bendebury19a77122013-01-24 17:38:00 -0800526 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700527 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700528 """Flash the image to SPI flash.
529
530 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000531 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700532
533 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700534 flash_dest: Destination for flasher, or None to not create a flasher
535 Valid options are spi, sdmmc.
536 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700537 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700538 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700539 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700540 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700541
542 Returns:
543 True if ok, False if failed.
Simon Glassb4c14af2013-07-04 11:56:33 +0900544
545 Raises:
546 CmdError if a supported Exynos model is not detected in the device tree.
Simon Glass27a9c142012-03-15 21:08:29 -0700547 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800548 tools = self._tools
549 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800550 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700551 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800552 # If we don't have some bits, get them from the image
553 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
554 self._out.Warning('Extracting U-Boot from payload')
555 flash_uboot = payload_image
556 if not bl1 or not os.path.exists(tools.Filename(bl1)):
557 self._out.Warning('Extracting BL1 from payload')
558 bl1 = payload_bl1
559 if not bl2 or not os.path.exists(tools.Filename(bl2)):
560 self._out.Warning('Extracting BL2 from payload')
561 bl2 = payload_bl2
Michael Pratt24e7c162013-07-12 09:35:28 -0700562 else:
563 # Update BL2 machine parameters, as
564 # the BL2 passed in may not be updated
565 spl_load_size = os.stat(tools.Filename(bl2)).st_size
566 bl2_handler = ExynosBl2(tools, self._out)
567 bl2 = bl2_handler.Configure(self._fdt, spl_load_size,
568 bl2, 'flasher', True)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800569 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, '1:0')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700570 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800571 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700572
573 vendor_id = 0x04e8
574 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700575
Simon Glassb4c14af2013-07-04 11:56:33 +0900576 # Work out the exynos model we are talking to,
577 compatible = self._fdt.GetString('/', 'compatible')
578
579 for model in compatible.split():
580 addresses = exynos_addresses.get(model)
581 if addresses:
582 break
583 else:
584 # TODO(sjg@chromium.org): Remove this when upstream U-Boot has the
585 # 'samsung,exynos5250' compatible string.
586 addresses = exynos_addresses.get('samsung,exynos5250')
587 self._out.Warning('No exynos compatible string, assuming Exynos 5250')
588
589 if not addresses:
590 raise CmdError("Unable to determine USB download addresses, compatible" +
591 "string is '%s'" % compatible)
592
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800593 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800594 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
595 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800596 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800597 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700598 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800599 if preserved_dut_hub_sel != required_dut_hub_sel:
600 # Need to set it to get the port properly powered up.
601 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700602 if self._servo_port is not None:
603 self._out.Progress('Reseting board via servo')
604 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700605
Simon Glassde9c8072012-07-02 22:29:02 -0700606 # If we have a kernel to write, create a new image with that added.
607 if kernel:
608 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
609 data = self._tools.ReadFile(image)
610
611 # Pad the original payload out to the original length
612 data += '\0' * (os.stat(payload).st_size - len(data))
613 data += self._tools.ReadFile(kernel)
614 self._tools.WriteFile(dl_image, data)
615 else:
616 dl_image = image
617
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700618 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700619 download_list = [
Simon Glassb4c14af2013-07-04 11:56:33 +0900620 ['bl1', bl1],
621 ['bl2', bl2],
622 ['u-boot', dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700623 ]
Simon Glassb4c14af2013-07-04 11:56:33 +0900624
Simon Glass3381a1a2012-03-22 11:13:19 -0700625 try:
Simon Glass4968a472012-05-23 13:52:19 -0700626 for upto in range(len(download_list)):
627 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700628 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700629 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700630 raise CmdError('Could not find Exynos board on USB port')
631 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glassb4c14af2013-07-04 11:56:33 +0900632 self._out.Notice(item[1])
Simon Glass27a9c142012-03-15 21:08:29 -0700633 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700634
Simon Glass4968a472012-05-23 13:52:19 -0700635 if upto == 0:
636 # The IROM needs roughly 200ms here to be ready for USB download
637 time.sleep(.5)
638
Simon Glassb4c14af2013-07-04 11:56:33 +0900639 args = ['-a', '%#x' % addresses[item[0]], '-f', item[1]]
Simon Glass79e3dd02012-08-28 20:08:50 -0700640 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700641
Simon Glass3381a1a2012-03-22 11:13:19 -0700642 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800643 # Make sure that the power button is released and dut_sel_hub state is
644 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700645 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800646 if preserved_dut_hub_sel != required_dut_hub_sel:
647 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800648 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700649
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800650 if flash_dest is None:
651 self._out.Notice('Image downloaded - please see serial output '
652 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700653 return True
654
Simon Glass0c2ba482012-03-22 21:57:51 -0700655 def _GetDiskInfo(self, disk, item):
656 """Returns information about a SCSI disk device.
657
658 Args:
659 disk: a block device name in sys/block, like '/sys/block/sdf'.
660 item: the item of disk information that is required.
661
662 Returns:
663 The information obtained, as a string, or '[Unknown]' if not found
664 """
665 dev_path = os.path.join(disk, 'device')
666
667 # Search upwards and through symlinks looking for the item.
668 while os.path.isdir(dev_path) and dev_path != '/sys':
669 fname = os.path.join(dev_path, item)
670 if os.path.exists(fname):
671 with open(fname, 'r') as fd:
672 return fd.readline().rstrip()
673
674 # Move up a level and follow any symlink.
675 new_path = os.path.join(dev_path, '..')
676 if os.path.islink(new_path):
677 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
678 dev_path = new_path
679 return '[Unknown]'
680
681 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700682 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700683
684 Args:
685 device: Device to check, like '/dev/sdf'.
686
687 Returns:
688 Capacity of device in GB, or 0 if not known.
689 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700690 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700691 args = ['-l', device]
692 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700693 for line in stdout.splitlines():
694 m = re_capacity.match(line)
695 if m:
696 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700697 return 0
698
699 def _ListUsbDisks(self):
700 """Return a list of available removable USB disks.
701
702 Returns:
703 List of USB devices, each element is itself a list containing:
704 device ('/dev/sdx')
705 manufacturer name
706 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700707 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700708 """
709 disk_list = []
710 for disk in glob.glob('/sys/block/sd*'):
711 with open(disk + '/removable', 'r') as fd:
712 if int(fd.readline()) == 1:
713 device = '/dev/%s' % disk.split('/')[-1]
714 manuf = self._GetDiskInfo(disk, 'manufacturer')
715 product = self._GetDiskInfo(disk, 'product')
716 capacity = self._GetDiskCapacity(device)
717 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700718 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700719 return disk_list
720
721 def WriteToSd(self, flash_dest, disk, uboot, payload):
722 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800723 raw_image = self._PrepareFlasher(uboot, payload, flash_dest, '1:0')
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700724 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700725 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700726
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700727 bl2_handler = ExynosBl2(self._tools, self._out)
Vadim Bendebury0c961a72013-06-11 13:35:07 -0700728 bl2_file = bl2_handler.Configure(self._fdt, spl_load_size,
Vadim Bendebury8ae67892013-06-11 17:45:15 -0700729 bl2, 'flasher', True)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700730 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700731
Vadim Bendebury22de0492013-06-17 16:11:20 -0700732 # Pad BL2 out to the required size. Its size could be either 14K or 30K
733 # bytes, but the next object in the file needs to be aligned at an 8K
734 # boundary. The BL1 size is also known to be 8K bytes, so the total BL1
735 # + BL2 size needs to be aligned to 8K (0x2000) boundary.
736 aligned_size = (len(data) + 0x1fff) & ~0x1fff
737 pad_size = aligned_size - len(data)
738 data += '\0' * pad_size
739
Simon Glass559b6612012-05-23 13:28:45 -0700740 data += self._tools.ReadFile(raw_image)
741 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
742 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700743 self._out.Progress('Writing flasher to %s' % disk)
744 else:
745 image = payload
746 self._out.Progress('Writing image to %s' % disk)
747
748 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
749 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700750 self._out.Progress('Syncing')
751 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700752
753 def SendToSdCard(self, dest, flash_dest, uboot, payload):
754 """Write a flasher to an SD card.
755
756 Args:
757 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700758 ':.' selects the only available device, fails if more than one option
759 ':<device>' select deivce
760
761 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700762 ':.'
763 ':/dev/sdd'
764
765 flash_dest: Destination for flasher, or None to not create a flasher:
766 Valid options are spi, sdmmc.
767 uboot: Full path to u-boot.bin.
768 payload: Full path to payload.
769 """
770 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700771
Vadim Bendebury223af572013-04-27 13:25:13 -0700772 # If no removable devices found - prompt user and wait for one to appear.
773 disks = self._ListUsbDisks()
774 try:
775 spinner = '|/-\\'
776 index = 0
777 while not disks:
778 self._out.ClearProgress()
779 self._out.Progress('No removable devices found, plug something in %s '
780 % spinner[index], trailer='')
781 index = (index + 1) % len(spinner)
782 disks = self._ListUsbDisks()
783 time.sleep(.2)
784 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700785 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700786
787 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700788 name = dest[1:]
789
790 # A '.' just means to use the only available disk.
791 if name == '.' and len(disks) == 1:
792 disk = disks[0][0]
793 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700794 # Use the device name.
795 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700796 disk = disk_info[0]
797
798 if disk:
799 self.WriteToSd(flash_dest, disk, uboot, payload)
800 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700801 msg = ["Please specify destination as '-w sd:<disk_description>'",]
802 msg.append(' - <disk_description> can be either . for the only disk,')
803 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700804 # List available disks as a convenience.
805 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700806 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700807 disk[0],
808 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700809 disk[3] / 10.0))
810 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700811
Vadim Bendebury19a77122013-01-24 17:38:00 -0800812 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700813 """Send an image to an attached EM100 device.
814
815 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
816 to do the SPI emulation, then write the image, then boot the board.
817 All going well, this is enough to get U-Boot running.
818
819 Args:
820 image_fname: Filename of image to send
821 """
822 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
823 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800824 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700825
826 # TODO(sjg@chromium.org): This is for link. We could make this
827 # configurable from the fdt.
828 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
829 self._out.Progress('Writing image to em100')
830 self._tools.Run('em100', args, sudo=True)
831
Simon Glass93673cf2013-04-26 17:55:55 -0700832 if self._servo_port is not None:
833 self._out.Progress('Resetting board via servo')
834 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
835 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
836 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700837
Simon Glass0c2ba482012-03-22 21:57:51 -0700838
Simon Glass27a9c142012-03-15 21:08:29 -0700839def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700840 bundle, update=True, verify=False, dest=None,
Vadim Bendebury19a77122013-01-24 17:38:00 -0800841 flash_dest=None, kernel=None, bootstub=None, servo='any',
Simon Glass4b8b3bd2012-11-06 12:31:01 -0800842 method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700843 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700844
845 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700846 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700847
848 Args:
849 output: cros_output object to use.
850 tools: Tools object to use.
851 fdt: Fdt object to use as our device tree.
852 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700853 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700854 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700855 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800856 update: Use faster update algorithm rather then full device erase.
857 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700858 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700859 flash_dest: Destination device for flasher to program payload into.
Simon Glassde9c8072012-07-02 22:29:02 -0700860 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800861 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700862 servo: Describes the servo unit to use: none=none; any=any; otherwise
863 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700864 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800865 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glass6a616c12012-09-24 18:13:46 -0700866 write.SelectServo(servo)
Simon Glassd65f65f2013-03-28 17:03:41 -0700867 if flash_dest:
868 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
869 elif bootstub:
870 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700871 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800872 try:
873 write.DutControl(['cpu_uart_capture:on',])
874 method = fdt.GetString('/chromeos-config', 'flash-method', method)
875 if method == 'tegra':
876 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800877 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
878 image_fname, bootstub)
879 elif method == 'exynos':
880 tools.CheckTool('lsusb', 'usbutils')
881 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
882 ok = write.ExynosFlashImage(flash_dest, flasher,
883 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
884 kernel)
885 else:
886 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800887
Vadim Bendebury2b719452013-02-12 17:00:06 -0800888 if not ok:
889 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800890 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800891
892 if flash_dest is not None and servo != 'none':
893 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800894 output.Progress('Done!')
895
Vadim Bendebury2b719452013-02-12 17:00:06 -0800896 finally:
897 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -0700898 elif dest == 'em100':
899 # crosbug.com/31625
900 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -0800901 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -0700902 elif dest.startswith('sd'):
903 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700904 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700905 raise CmdError("Unknown destination device '%s'" % dest)