blob: a8c3182664862571b07586644c0d1f3f654c1199 [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':
Michael Pratt54aaeed2013-07-12 13:42:47 -0700153 # In U-Boot, strings in double quotes have variables expanded to actual
154 # values. For reasons unclear, this expansion splits the single quoted
155 # argument into separate arguements for each word, which on exynos
156 # boards causes the command to exceed the maximum configured argument
157 # count. Passing the string in single quotes prevents this expansion,
158 # allowing variables to be expanded when run is called.
159 # crbug.com/260294
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800160 cmds.extend([
Michael Pratt54aaeed2013-07-12 13:42:47 -0700161 'setenv _init "echo Init EMMC; mmc rescan"',
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800162 'setenv _erase "echo Erase EMMC; "',
Michael Pratt54aaeed2013-07-12 13:42:47 -0700163 "setenv _write 'echo Write EMMC; mmc open 0 1;" \
164 " mmc write ${address} 0 " \
165 "${blocks};" \
166 " mmc close 0 1'",
167 "setenv _read 'echo Read EMMC; mmc open 0 1;" \
168 " mmc read ${address} 0 " \
169 "${blocks};" \
170 " mmc close 0 1'",
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800171 ])
Doug Anderson37ae2292011-09-15 17:41:57 -0700172 else:
173 cmds.extend([
Simon Glass3d9a6c62012-03-15 20:38:04 -0700174 'setenv _init "echo Init SPI; sf probe %s"' % bus,
Doug Anderson37ae2292011-09-15 17:41:57 -0700175 'setenv _erase "echo Erase SPI; sf erase 0 ${length}"',
176 'setenv _write "echo Write SPI; sf write ${address} 0 ${length}"',
177 'setenv _read "echo Read SPI; sf read ${address} 0 ${length}"',
178 'setenv _update "echo Update SPI; sf update ${address} 0 ${length}"',
179 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700180
Doug Anderson37ae2292011-09-15 17:41:57 -0700181 cmds.extend([
Simon Glassa3f29ec2011-07-17 09:36:49 -0700182 'echo Firmware loaded to ${address}, size ${firmware_size}, '
183 'length ${length}',
Simon Glass8bd05ec2012-03-22 11:09:04 -0700184 'if run _crc; then',
Simon Glassa3f29ec2011-07-17 09:36:49 -0700185 'run _init',
Doug Anderson37ae2292011-09-15 17:41:57 -0700186 ])
Simon Glass5b5fd642011-08-17 12:24:01 -0700187 if update:
188 cmds += ['time run _update']
189 else:
190 cmds += ['run _erase', 'run _write']
Vadim Bendebury2b719452013-02-12 17:00:06 -0800191 if self.verify:
Simon Glass5b5fd642011-08-17 12:24:01 -0700192 cmds += [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700193 'run _clear',
194 'run _read',
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800195 'if run _crc; then',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800196 'echo "%s"' % self._WRITE_SUCCESS_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800197 'else',
198 'echo',
Vadim Bendebury2b719452013-02-12 17:00:06 -0800199 'echo "%s"' % self._WRITE_FAILURE_MESSAGE,
Vadim Bendeburyd6b0a372013-02-06 16:36:28 -0800200 'echo',
201 'fi',
Simon Glass5b5fd642011-08-17 12:24:01 -0700202 ]
203 else:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800204 cmds += ['echo %s' % self._SKIP_VERIFY_MESSAGE]
Simon Glass8bd05ec2012-03-22 11:09:04 -0700205 cmds.extend([
206 'else',
207 'echo',
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800208 'echo "%s"' % self._DOWNLOAD_FAILURE_MESSAGE,
Simon Glass8bd05ec2012-03-22 11:09:04 -0700209 'fi',
210 ])
Simon Glassa3f29ec2011-07-17 09:36:49 -0700211 script = '; '.join(cmds)
212 return script, replace_me
213
Vadim Bendebury2b719452013-02-12 17:00:06 -0800214 def _PrepareFlasher(self, uboot, payload, boot_type, bus):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700215 """Get a flasher ready for sending to the board.
216
217 The flasher is an executable image consisting of:
218
219 - U-Boot (u-boot.bin);
220 - a special FDT to tell it what to do in the form of a run command;
221 - (we could add some empty space here, in case U-Boot is not built to
222 be relocatable);
223 - the payload (which is a full flash image, or signed U-Boot + fdt).
224
225 Args:
226 uboot: Full path to u-boot.bin.
227 payload: Full path to payload.
Simon Glass0dcbecb2012-03-22 21:38:55 -0700228 boot_type: the src for bootdevice (nand, sdmmc, or spi)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700229
230 Returns:
Simon Glass290a1802011-07-17 13:54:32 -0700231 Filename of the flasher binary created.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700232 """
Simon Glass951a2db2011-07-17 15:58:58 -0700233 fdt = self._fdt.Copy(os.path.join(self._tools.outdir, 'flasher.dtb'))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700234 payload_data = self._tools.ReadFile(payload)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700235
Simon Glass8bd05ec2012-03-22 11:09:04 -0700236 # Make sure that the checksum is not negative
237 checksum = binascii.crc32(payload_data) & 0xffffffff
238
Vadim Bendebury2b719452013-02-12 17:00:06 -0800239 script, replace_me = self._GetFlashScript(len(payload_data), boot_type,
240 checksum, bus)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700241 data = self._tools.ReadFile(uboot)
Simon Glass02d124a2012-03-02 14:47:20 -0800242 fdt.PutString('/config', 'bootcmd', script)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700243 fdt_data = self._tools.ReadFile(fdt.fname)
244
245 # Work out where to place the payload in memory. This is a chicken-and-egg
246 # problem (although in case you haven't heard, it was the chicken that
247 # came first), so we resolve it by replacing the string after
248 # fdt.PutString has done its job.
249 #
250 # Correction: Technically, the egg came first. Whatever genetic mutation
251 # created the new species would have been present in the egg, but not the
252 # parent (since if it was in the parent, it would have been present in the
253 # parent when it was an egg).
254 #
255 # Question: ok so who laid the egg then?
256 payload_offset = len(data) + len(fdt_data)
Doug Anderson37ae2292011-09-15 17:41:57 -0700257
258 # NAND driver expects 4-byte alignment. Just go whole hog and do 4K.
259 alignment = 0x1000
Simon Glass8bd05ec2012-03-22 11:09:04 -0700260 payload_offset = (payload_offset + alignment - 1) & ~(alignment - 1)
Doug Anderson37ae2292011-09-15 17:41:57 -0700261
Simon Glass2c4b3e52011-11-15 14:45:43 -0800262 load_address = self.text_base + payload_offset,
Simon Glassa3f29ec2011-07-17 09:36:49 -0700263 new_str = '%08x' % load_address
264 if len(replace_me) is not len(new_str):
265 raise ValueError("Internal error: replacement string '%s' length does "
266 "not match new string '%s'" % (replace_me, new_str))
Vadim Bendebury19a77122013-01-24 17:38:00 -0800267 matches = len(re.findall(replace_me, fdt_data))
268 if matches != 1:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700269 raise ValueError("Internal error: replacement string '%s' already "
270 "exists in the fdt (%d matches)" % (replace_me, matches))
271 fdt_data = re.sub(replace_me, new_str, fdt_data)
272
273 # Now put it together.
274 data += fdt_data
275 data += "\0" * (payload_offset - len(data))
Simon Glass8bd05ec2012-03-22 11:09:04 -0700276 data += payload_data
Simon Glass951a2db2011-07-17 15:58:58 -0700277 flasher = os.path.join(self._tools.outdir, 'flasher-for-image.bin')
Simon Glassa3f29ec2011-07-17 09:36:49 -0700278 self._tools.WriteFile(flasher, data)
279
280 # Tell the user about a few things.
281 self._tools.OutputSize('U-Boot', uboot)
282 self._tools.OutputSize('Payload', payload)
Simon Glass8bd05ec2012-03-22 11:09:04 -0700283 self._out.Notice('Payload checksum %08x' % checksum)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700284 self._tools.OutputSize('Flasher', flasher)
285 return flasher
286
Vadim Bendebury19a77122013-01-24 17:38:00 -0800287 def NvidiaFlashImage(self, flash_dest, uboot, bct, payload, bootstub):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700288 """Flash the image to SPI flash.
289
290 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000291 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glassa3f29ec2011-07-17 09:36:49 -0700292
293 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700294 flash_dest: Destination for flasher, or None to not create a flasher
295 Valid options are spi, sdmmc
Simon Glassa3f29ec2011-07-17 09:36:49 -0700296 uboot: Full path to u-boot.bin.
297 bct: Full path to BCT file (binary chip timings file for Nvidia SOCs).
298 payload: Full path to payload.
Simon Glass89ecf712012-06-07 12:20:15 -0700299 bootstub: Full path to bootstub, which is the payload without the
300 signing information (i.e. bootstub is u-boot.bin + the FDT)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700301
302 Returns:
303 True if ok, False if failed.
304 """
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800305 # Use a Regex to pull Boot type from BCT file.
306 match = re.compile('DevType\[0\] = NvBootDevType_(?P<boot>([a-zA-Z])+);')
307 bct_dumped = self._tools.Run('bct_dump', [bct]).splitlines()
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700308
309 # TODO(sjg): The boot type is currently selected by the bct, rather than
310 # flash_dest selecting which bct to use. This is a bit backwards. For now
311 # we go with the bct's idea.
Rhyland Kleinc5c87282012-03-08 16:40:54 -0800312 boot_type = filter(match.match, bct_dumped)
Simon Glass0dcbecb2012-03-22 21:38:55 -0700313 boot_type = match.match(boot_type[0]).group('boot').lower()
Doug Anderson37ae2292011-09-15 17:41:57 -0700314
Simon Glass89ecf712012-06-07 12:20:15 -0700315 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800316 image = self._PrepareFlasher(uboot, payload, boot_type, 0)
Simon Glasse1824db2012-07-11 17:38:40 +0200317 elif bootstub:
Simon Glass89ecf712012-06-07 12:20:15 -0700318 image = bootstub
Simon Glassa3f29ec2011-07-17 09:36:49 -0700319
Simon Glasse1824db2012-07-11 17:38:40 +0200320 else:
321 image = payload
322 # If we don't know the textbase, extract it from the payload.
323 if self.text_base == -1:
324 data = self._tools.ReadFile(payload)
325 # Skip the BCT which is the first 64KB
326 self.text_base = self._bundle.DecodeTextBase(data[0x10000:])
327
Simon Glass89ecf712012-06-07 12:20:15 -0700328 self._out.Notice('TEXT_BASE is %#x' % self.text_base)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700329 self._out.Progress('Uploading flasher image')
330 args = [
Simon Glassa3f29ec2011-07-17 09:36:49 -0700331 '--bct', bct,
Allen Martinb3aa2672012-03-23 15:55:25 +0000332 '--bootloader', image,
333 '--loadaddr', "%#x" % self.text_base
Simon Glassa3f29ec2011-07-17 09:36:49 -0700334 ]
335
336 # TODO(sjg): Check for existence of board - but chroot has no lsusb!
337 last_err = None
Vadim Bendebury19a77122013-01-24 17:38:00 -0800338 for _ in range(10):
Simon Glassa3f29ec2011-07-17 09:36:49 -0700339 try:
Simon Glassa3f29ec2011-07-17 09:36:49 -0700340 # TODO(sjg): Use Chromite library so we can monitor output
Allen Martinb3aa2672012-03-23 15:55:25 +0000341 self._tools.Run('tegrarcm', args, sudo=True)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700342 self._out.Notice('Flasher downloaded - please see serial output '
343 'for progress.')
344 return True
345
346 except CmdError as err:
347 if not self._out.stdout_is_tty:
348 return False
349
350 # Only show the error output once unless it changes.
351 err = str(err)
Simon Glass22190ff2012-07-11 14:52:26 +0200352 if not 'could not open USB device' in err:
Allen Martinb3aa2672012-03-23 15:55:25 +0000353 raise CmdError('tegrarcm failed: %s' % err)
Simon Glassa3f29ec2011-07-17 09:36:49 -0700354
355 if err != last_err:
356 self._out.Notice(err)
357 last_err = err
358 self._out.Progress('Please connect USB A-A cable and do a '
359 'recovery-reset', True)
360 time.sleep(1)
361
362 return False
Simon Glass710dedc2011-08-09 14:08:52 -0700363
Simon Glass27a9c142012-03-15 21:08:29 -0700364 def _WaitForUSBDevice(self, name, vendor_id, product_id, timeout=10):
365 """Wait until we see a device on the USB bus.
366
367 Args:
368 name: Board type name
369 vendor_id: USB vendor ID to look for
370 product_id: USB product ID to look for
371 timeout: Timeout to wait in seconds
372
373 Returns
374 True if the device was found, False if we timed out.
375 """
376 self._out.Progress('Waiting for board to appear on USB bus')
Simon Glass4968a472012-05-23 13:52:19 -0700377 start_time = time.time()
378 while time.time() - start_time < timeout:
Simon Glass27a9c142012-03-15 21:08:29 -0700379 try:
380 args = ['-d', '%04x:%04x' % (vendor_id, product_id)]
381 self._tools.Run('lsusb', args, sudo=True)
Simon Glass3381a1a2012-03-22 11:13:19 -0700382 self._out.Progress('Found %s board' % name)
Simon Glass27a9c142012-03-15 21:08:29 -0700383 return True
384
Vadim Bendebury19a77122013-01-24 17:38:00 -0800385 except CmdError:
Simon Glass27a9c142012-03-15 21:08:29 -0700386 pass
387
Simon Glass3381a1a2012-03-22 11:13:19 -0700388 return False
Simon Glass27a9c142012-03-15 21:08:29 -0700389
Vadim Bendebury2b719452013-02-12 17:00:06 -0800390 def DutControl(self, args):
Simon Glass6a616c12012-09-24 18:13:46 -0700391 """Run dut-control with supplied arguments.
392
Simon Glass2065a742013-02-09 13:39:26 -0800393 The correct servo will be used based on self._servo_port. If servo use is
394 disabled, this function does nothing.
Simon Glass6a616c12012-09-24 18:13:46 -0700395
396 Args:
397 args: List of arguments to dut-control.
398
Simon Glass2065a742013-02-09 13:39:26 -0800399 Returns:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800400 a string, stdout generated by running the command
Simon Glass6a616c12012-09-24 18:13:46 -0700401 """
402 if self._servo_port is None:
Simon Glass2065a742013-02-09 13:39:26 -0800403 return '' # User has requested not to use servo
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800404 if self._servo_port:
Simon Glass6a616c12012-09-24 18:13:46 -0700405 args.extend(['-p', '%s' % self._servo_port])
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800406 return self._tools.Run('dut-control', args)
Simon Glass6a616c12012-09-24 18:13:46 -0700407
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800408 def WaitForCompletion(self):
Vadim Bendebury2b719452013-02-12 17:00:06 -0800409 """Verify flash programming operation success.
410
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800411 The DUT is presumed to be programming flash with console capture mode on.
412 This function scans console output for the success or failure strings.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800413
414 Raises:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800415 CmdError if the following cases:
416 - none of the strings show up in the allotted time (2 minutes)
417 - console goes silent for more than 10 seconds
418 - one of the error messages seen in the stream
419 - misformatted output is seen in the stream
Vadim Bendebury2b719452013-02-12 17:00:06 -0800420 """
421
422 _SOFT_DEADLINE_LIMIT = 10
423 _HARD_DEADLINE_LIMIT = 120
424 string_leftover = ''
425 soft_deadline = time.time() + _SOFT_DEADLINE_LIMIT
426 hard_deadline = soft_deadline + _HARD_DEADLINE_LIMIT - _SOFT_DEADLINE_LIMIT
427
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800428 if self.verify:
429 done_line = self._WRITE_SUCCESS_MESSAGE
430 else:
431 done_line = self._SKIP_VERIFY_MESSAGE
432
Vadim Bendebury2b719452013-02-12 17:00:06 -0800433 while True:
434 now = time.time()
435 if now > hard_deadline:
436 raise CmdError('Target console flooded, programming failed')
437 if now > soft_deadline:
438 raise CmdError('Target console dead, programming failed')
439 stream = self.DutControl(['cpu_uart_stream',])
440 match = re.search("^cpu_uart_stream:'(.*)'\n", stream)
441 if not match:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800442 raise CmdError('Misformatted console output: \n%s\n' % stream)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800443
444 text = string_leftover + match.group(1)
445 strings = text.split('\\r')
446 string_leftover = strings.pop()
447 if strings:
448 soft_deadline = now + _SOFT_DEADLINE_LIMIT
449 for string in strings:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800450 if done_line in string:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800451 return True
452 if self._WRITE_FAILURE_MESSAGE in string:
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800453 raise CmdError('Readback verification failed!')
454 if self._DOWNLOAD_FAILURE_MESSAGE in string:
455 raise CmdError('Download failed!')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800456
Simon Glass4c54a912013-02-18 16:56:29 -0800457 def _ExtractPayloadParts(self, payload, truncate_to_fdt):
Simon Glass3c5b35b2012-05-23 13:22:23 -0700458 """Extract the BL1, BL2 and U-Boot parts from a payload.
459
460 An exynos image consists of 3 parts: BL1, BL2 and U-Boot/FDT.
461
462 This pulls out the various parts, puts them into files and returns
463 these files.
464
465 Args:
466 payload: Full path to payload.
Simon Glass4c54a912013-02-18 16:56:29 -0800467 truncate_to_fdt: Truncate the U-Boot image at the start of its
468 embedded FDT
Simon Glass3c5b35b2012-05-23 13:22:23 -0700469
470 Returns:
471 (bl1, bl2, image) where:
472 bl1 is the filename of the extracted BL1
473 bl2 is the filename of the extracted BL2
474 image is the filename of the extracted U-Boot image
475 """
476 # Pull out the parts from the payload
477 bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
478 bl2 = os.path.join(self._tools.outdir, 'bl2.bin')
479 image = os.path.join(self._tools.outdir, 'u-boot-from-image.bin')
480 data = self._tools.ReadFile(payload)
481
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700482 try:
483 bl1_size = int(self._fdt.GetProps('/flash/pre-boot')['size'])
484 bl2_size = int(self._fdt.GetProps('/flash/spl')['size'])
485 uboot_offset = bl1_size + bl2_size
486 except CmdError:
487 self._out.Warning('No component nodes in the device tree')
488 # The BL1 is always 8KB - extract that part into a new file
489 # TODO(sjg@chromium.org): Perhaps pick these up from the fdt?
490 bl1_size = 0x2000
Simon Glass3c5b35b2012-05-23 13:22:23 -0700491
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700492 # Try to detect the BL2 size. We look for 0xea000014 or 0xea000013
493 # which is the 'B reset' instruction at the start of U-Boot. When
494 # U-Boot is LZO compressed, we look for a LZO magic instead.
495 start_data = [struct.pack('<L', 0xea000014),
496 struct.pack('<L', 0xea000013),
497 struct.pack('>B3s', 0x89, 'LZO')]
498 starts = [data.find(magic, bl1_size + 0x3800) for magic in start_data]
499 uboot_offset = None
500 for start in starts:
501 if start != -1 and (not uboot_offset or start < uboot_offset):
502 uboot_offset = start
503 if not uboot_offset:
504 raise ValueError('Could not locate start of U-Boot')
505 bl2_size = uboot_offset - bl1_size - 0x800 # 2KB gap after BL2
Simon Glass3c5b35b2012-05-23 13:22:23 -0700506
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700507 # Sanity check: At present we only allow 14KB and 30KB for SPL
508 allowed = [14, 30]
509 if (bl2_size >> 10) not in allowed:
510 raise ValueError('BL2 size is %dK - only %s supported' %
511 (bl2_size >> 10, ', '.join(
512 [str(size) for size in allowed])))
Simon Glasse86f3132013-01-08 16:10:43 -0800513 self._out.Notice('BL2 size is %dKB' % (bl2_size >> 10))
514
Vadim Bendeburyb397ddd2013-07-10 18:32:49 -0700515 self._tools.WriteFile(bl1, data[:bl1_size])
516 self._tools.WriteFile(bl2, data[bl1_size:bl1_size + bl2_size])
Simon Glasse86f3132013-01-08 16:10:43 -0800517
Simon Glassbc0d8d42013-02-09 11:59:36 -0800518 # U-Boot itself starts at 24KB, after the gap. As a hack, truncate it
Simon Glass4c54a912013-02-18 16:56:29 -0800519 # to an assumed maximum size. As a secondary hack, locate the FDT
520 # and truncate U-Boot from that point. The correct FDT will be added
521 # when the image is written to the board.
Simon Glassbc0d8d42013-02-09 11:59:36 -0800522 # TODO(sjg@chromium.org): Get a proper flash map here so we know how
523 # large it is
Simon Glass4c54a912013-02-18 16:56:29 -0800524 uboot_data = data[uboot_offset:uboot_offset + 0xa0000]
525 if truncate_to_fdt:
526 fdt_magic = struct.pack('>L', 0xd00dfeed)
527 fdt_offset = uboot_data.rfind(fdt_magic)
528 uboot_data = uboot_data[:fdt_offset]
529
530 self._tools.WriteFile(image, uboot_data)
Simon Glass3c5b35b2012-05-23 13:22:23 -0700531 return bl1, bl2, image
532
Vadim Bendebury19a77122013-01-24 17:38:00 -0800533 def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
Simon Glassde9c8072012-07-02 22:29:02 -0700534 kernel):
Simon Glass27a9c142012-03-15 21:08:29 -0700535 """Flash the image to SPI flash.
536
537 This creates a special Flasher binary, with the image to be flashed as
Allen Martinb3aa2672012-03-23 15:55:25 +0000538 a payload. This is then sent to the board using the tegrarcm utility.
Simon Glass27a9c142012-03-15 21:08:29 -0700539
540 Args:
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700541 flash_dest: Destination for flasher, or None to not create a flasher
542 Valid options are spi, sdmmc.
543 flash_uboot: Full path to u-boot.bin to use for flasher.
Simon Glass27a9c142012-03-15 21:08:29 -0700544 bl1: Full path to file containing BL1 (pre-boot).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700545 bl2: Full path to file containing BL2 (SPL).
Simon Glass27a9c142012-03-15 21:08:29 -0700546 payload: Full path to payload.
Simon Glassde9c8072012-07-02 22:29:02 -0700547 kernel: Kernel to send after the payload, or None.
Simon Glass27a9c142012-03-15 21:08:29 -0700548
549 Returns:
550 True if ok, False if failed.
Simon Glassb4c14af2013-07-04 11:56:33 +0900551
552 Raises:
553 CmdError if a supported Exynos model is not detected in the device tree.
Simon Glass27a9c142012-03-15 21:08:29 -0700554 """
Simon Glassbc0d8d42013-02-09 11:59:36 -0800555 tools = self._tools
556 payload_bl1, payload_bl2, payload_image = (
Simon Glass4c54a912013-02-18 16:56:29 -0800557 self._ExtractPayloadParts(payload, flash_dest is not None))
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700558 if flash_dest:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800559 # If we don't have some bits, get them from the image
560 if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
561 self._out.Warning('Extracting U-Boot from payload')
562 flash_uboot = payload_image
563 if not bl1 or not os.path.exists(tools.Filename(bl1)):
564 self._out.Warning('Extracting BL1 from payload')
565 bl1 = payload_bl1
566 if not bl2 or not os.path.exists(tools.Filename(bl2)):
567 self._out.Warning('Extracting BL2 from payload')
568 bl2 = payload_bl2
Michael Pratt24e7c162013-07-12 09:35:28 -0700569 else:
570 # Update BL2 machine parameters, as
571 # the BL2 passed in may not be updated
572 spl_load_size = os.stat(tools.Filename(bl2)).st_size
573 bl2_handler = ExynosBl2(tools, self._out)
574 bl2 = bl2_handler.Configure(self._fdt, spl_load_size,
575 bl2, 'flasher', True)
Vadim Bendebury2b719452013-02-12 17:00:06 -0800576 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, '1:0')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700577 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800578 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700579
580 vendor_id = 0x04e8
581 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700582
Simon Glassb4c14af2013-07-04 11:56:33 +0900583 # Work out the exynos model we are talking to,
584 compatible = self._fdt.GetString('/', 'compatible')
585
586 for model in compatible.split():
587 addresses = exynos_addresses.get(model)
588 if addresses:
589 break
590 else:
591 # TODO(sjg@chromium.org): Remove this when upstream U-Boot has the
592 # 'samsung,exynos5250' compatible string.
593 addresses = exynos_addresses.get('samsung,exynos5250')
594 self._out.Warning('No exynos compatible string, assuming Exynos 5250')
595
596 if not addresses:
597 raise CmdError("Unable to determine USB download addresses, compatible" +
598 "string is '%s'" % compatible)
599
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800600 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800601 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
602 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800603 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800604 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700605 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800606 if preserved_dut_hub_sel != required_dut_hub_sel:
607 # Need to set it to get the port properly powered up.
608 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700609 if self._servo_port is not None:
610 self._out.Progress('Reseting board via servo')
611 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700612
Simon Glassde9c8072012-07-02 22:29:02 -0700613 # If we have a kernel to write, create a new image with that added.
614 if kernel:
615 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
616 data = self._tools.ReadFile(image)
617
618 # Pad the original payload out to the original length
619 data += '\0' * (os.stat(payload).st_size - len(data))
620 data += self._tools.ReadFile(kernel)
621 self._tools.WriteFile(dl_image, data)
622 else:
623 dl_image = image
624
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700625 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700626 download_list = [
Simon Glassb4c14af2013-07-04 11:56:33 +0900627 ['bl1', bl1],
628 ['bl2', bl2],
629 ['u-boot', dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700630 ]
Simon Glassb4c14af2013-07-04 11:56:33 +0900631
Simon Glass3381a1a2012-03-22 11:13:19 -0700632 try:
Simon Glass4968a472012-05-23 13:52:19 -0700633 for upto in range(len(download_list)):
634 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700635 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700636 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700637 raise CmdError('Could not find Exynos board on USB port')
638 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glassb4c14af2013-07-04 11:56:33 +0900639 self._out.Notice(item[1])
Simon Glass27a9c142012-03-15 21:08:29 -0700640 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700641
Simon Glass4968a472012-05-23 13:52:19 -0700642 if upto == 0:
643 # The IROM needs roughly 200ms here to be ready for USB download
644 time.sleep(.5)
645
Simon Glassb4c14af2013-07-04 11:56:33 +0900646 args = ['-a', '%#x' % addresses[item[0]], '-f', item[1]]
Simon Glass79e3dd02012-08-28 20:08:50 -0700647 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700648
Simon Glass3381a1a2012-03-22 11:13:19 -0700649 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800650 # Make sure that the power button is released and dut_sel_hub state is
651 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700652 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800653 if preserved_dut_hub_sel != required_dut_hub_sel:
654 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800655 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700656
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800657 if flash_dest is None:
658 self._out.Notice('Image downloaded - please see serial output '
659 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700660 return True
661
Simon Glass0c2ba482012-03-22 21:57:51 -0700662 def _GetDiskInfo(self, disk, item):
663 """Returns information about a SCSI disk device.
664
665 Args:
666 disk: a block device name in sys/block, like '/sys/block/sdf'.
667 item: the item of disk information that is required.
668
669 Returns:
670 The information obtained, as a string, or '[Unknown]' if not found
671 """
672 dev_path = os.path.join(disk, 'device')
673
674 # Search upwards and through symlinks looking for the item.
675 while os.path.isdir(dev_path) and dev_path != '/sys':
676 fname = os.path.join(dev_path, item)
677 if os.path.exists(fname):
678 with open(fname, 'r') as fd:
679 return fd.readline().rstrip()
680
681 # Move up a level and follow any symlink.
682 new_path = os.path.join(dev_path, '..')
683 if os.path.islink(new_path):
684 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
685 dev_path = new_path
686 return '[Unknown]'
687
688 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700689 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700690
691 Args:
692 device: Device to check, like '/dev/sdf'.
693
694 Returns:
695 Capacity of device in GB, or 0 if not known.
696 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700697 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700698 args = ['-l', device]
699 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700700 for line in stdout.splitlines():
701 m = re_capacity.match(line)
702 if m:
703 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700704 return 0
705
706 def _ListUsbDisks(self):
707 """Return a list of available removable USB disks.
708
709 Returns:
710 List of USB devices, each element is itself a list containing:
711 device ('/dev/sdx')
712 manufacturer name
713 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700714 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700715 """
716 disk_list = []
717 for disk in glob.glob('/sys/block/sd*'):
718 with open(disk + '/removable', 'r') as fd:
719 if int(fd.readline()) == 1:
720 device = '/dev/%s' % disk.split('/')[-1]
721 manuf = self._GetDiskInfo(disk, 'manufacturer')
722 product = self._GetDiskInfo(disk, 'product')
723 capacity = self._GetDiskCapacity(device)
724 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700725 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700726 return disk_list
727
728 def WriteToSd(self, flash_dest, disk, uboot, payload):
729 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800730 raw_image = self._PrepareFlasher(uboot, payload, flash_dest, '1:0')
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700731 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700732 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700733
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700734 bl2_handler = ExynosBl2(self._tools, self._out)
Vadim Bendebury0c961a72013-06-11 13:35:07 -0700735 bl2_file = bl2_handler.Configure(self._fdt, spl_load_size,
Vadim Bendebury8ae67892013-06-11 17:45:15 -0700736 bl2, 'flasher', True)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700737 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700738
Vadim Bendebury22de0492013-06-17 16:11:20 -0700739 # Pad BL2 out to the required size. Its size could be either 14K or 30K
740 # bytes, but the next object in the file needs to be aligned at an 8K
741 # boundary. The BL1 size is also known to be 8K bytes, so the total BL1
742 # + BL2 size needs to be aligned to 8K (0x2000) boundary.
743 aligned_size = (len(data) + 0x1fff) & ~0x1fff
744 pad_size = aligned_size - len(data)
745 data += '\0' * pad_size
746
Simon Glass559b6612012-05-23 13:28:45 -0700747 data += self._tools.ReadFile(raw_image)
748 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
749 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700750 self._out.Progress('Writing flasher to %s' % disk)
751 else:
752 image = payload
753 self._out.Progress('Writing image to %s' % disk)
754
755 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
756 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700757 self._out.Progress('Syncing')
758 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700759
760 def SendToSdCard(self, dest, flash_dest, uboot, payload):
761 """Write a flasher to an SD card.
762
763 Args:
764 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700765 ':.' selects the only available device, fails if more than one option
766 ':<device>' select deivce
767
768 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700769 ':.'
770 ':/dev/sdd'
771
772 flash_dest: Destination for flasher, or None to not create a flasher:
773 Valid options are spi, sdmmc.
774 uboot: Full path to u-boot.bin.
775 payload: Full path to payload.
776 """
777 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700778
Vadim Bendebury223af572013-04-27 13:25:13 -0700779 # If no removable devices found - prompt user and wait for one to appear.
780 disks = self._ListUsbDisks()
781 try:
782 spinner = '|/-\\'
783 index = 0
784 while not disks:
785 self._out.ClearProgress()
786 self._out.Progress('No removable devices found, plug something in %s '
787 % spinner[index], trailer='')
788 index = (index + 1) % len(spinner)
789 disks = self._ListUsbDisks()
790 time.sleep(.2)
791 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700792 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700793
794 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700795 name = dest[1:]
796
797 # A '.' just means to use the only available disk.
798 if name == '.' and len(disks) == 1:
799 disk = disks[0][0]
800 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700801 # Use the device name.
802 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700803 disk = disk_info[0]
804
805 if disk:
806 self.WriteToSd(flash_dest, disk, uboot, payload)
807 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700808 msg = ["Please specify destination as '-w sd:<disk_description>'",]
809 msg.append(' - <disk_description> can be either . for the only disk,')
810 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700811 # List available disks as a convenience.
812 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700813 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700814 disk[0],
815 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700816 disk[3] / 10.0))
817 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700818
Vadim Bendebury19a77122013-01-24 17:38:00 -0800819 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700820 """Send an image to an attached EM100 device.
821
822 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
823 to do the SPI emulation, then write the image, then boot the board.
824 All going well, this is enough to get U-Boot running.
825
826 Args:
827 image_fname: Filename of image to send
828 """
829 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
830 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800831 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700832
833 # TODO(sjg@chromium.org): This is for link. We could make this
834 # configurable from the fdt.
835 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
836 self._out.Progress('Writing image to em100')
837 self._tools.Run('em100', args, sudo=True)
838
Simon Glass93673cf2013-04-26 17:55:55 -0700839 if self._servo_port is not None:
840 self._out.Progress('Resetting board via servo')
841 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
842 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
843 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700844
Simon Glass0c2ba482012-03-22 21:57:51 -0700845
Simon Glass27a9c142012-03-15 21:08:29 -0700846def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700847 bundle, update=True, verify=False, dest=None,
Vadim Bendebury19a77122013-01-24 17:38:00 -0800848 flash_dest=None, kernel=None, bootstub=None, servo='any',
Simon Glass4b8b3bd2012-11-06 12:31:01 -0800849 method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700850 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700851
852 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700853 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700854
855 Args:
856 output: cros_output object to use.
857 tools: Tools object to use.
858 fdt: Fdt object to use as our device tree.
859 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700860 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700861 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700862 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800863 update: Use faster update algorithm rather then full device erase.
864 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700865 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700866 flash_dest: Destination device for flasher to program payload into.
Simon Glassde9c8072012-07-02 22:29:02 -0700867 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800868 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700869 servo: Describes the servo unit to use: none=none; any=any; otherwise
870 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700871 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800872 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glass6a616c12012-09-24 18:13:46 -0700873 write.SelectServo(servo)
Simon Glassd65f65f2013-03-28 17:03:41 -0700874 if flash_dest:
875 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
876 elif bootstub:
877 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700878 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800879 try:
880 write.DutControl(['cpu_uart_capture:on',])
881 method = fdt.GetString('/chromeos-config', 'flash-method', method)
882 if method == 'tegra':
883 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800884 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
885 image_fname, bootstub)
886 elif method == 'exynos':
887 tools.CheckTool('lsusb', 'usbutils')
888 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
889 ok = write.ExynosFlashImage(flash_dest, flasher,
890 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
891 kernel)
892 else:
893 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800894
Vadim Bendebury2b719452013-02-12 17:00:06 -0800895 if not ok:
896 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800897 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800898
899 if flash_dest is not None and servo != 'none':
900 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800901 output.Progress('Done!')
902
Vadim Bendebury2b719452013-02-12 17:00:06 -0800903 finally:
904 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -0700905 elif dest == 'em100':
906 # crosbug.com/31625
907 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -0800908 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -0700909 elif dest.startswith('sd'):
910 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700911 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700912 raise CmdError("Unknown destination device '%s'" % dest)