blob: 5ed00df15f4859a0dfc10550292ae7ad66ef4d19 [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
Vadim Bendebury2b719452013-02-12 17:00:06 -0800562 image = self._PrepareFlasher(flash_uboot, payload, flash_dest, '1:0')
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700563 else:
Simon Glassbc0d8d42013-02-09 11:59:36 -0800564 bl1, bl2, image = payload_bl1, payload_bl2, payload_image
Simon Glass27a9c142012-03-15 21:08:29 -0700565
566 vendor_id = 0x04e8
567 product_id = 0x1234
Simon Glass3381a1a2012-03-22 11:13:19 -0700568
Simon Glassb4c14af2013-07-04 11:56:33 +0900569 # Work out the exynos model we are talking to,
570 compatible = self._fdt.GetString('/', 'compatible')
571
572 for model in compatible.split():
573 addresses = exynos_addresses.get(model)
574 if addresses:
575 break
576 else:
577 # TODO(sjg@chromium.org): Remove this when upstream U-Boot has the
578 # 'samsung,exynos5250' compatible string.
579 addresses = exynos_addresses.get('samsung,exynos5250')
580 self._out.Warning('No exynos compatible string, assuming Exynos 5250')
581
582 if not addresses:
583 raise CmdError("Unable to determine USB download addresses, compatible" +
584 "string is '%s'" % compatible)
585
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800586 # Preserve dut_hub_sel state.
Vadim Bendebury2b719452013-02-12 17:00:06 -0800587 preserved_dut_hub_sel = self.DutControl(['dut_hub_sel',]
588 ).strip().split(':')[-1]
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800589 required_dut_hub_sel = 'dut_sees_servo'
Simon Glass68e6c6c2013-02-14 09:35:54 -0800590 args = ['warm_reset:on', 'fw_up:on', 'pwr_button:press', 'sleep:.2',
Simon Glass3381a1a2012-03-22 11:13:19 -0700591 'warm_reset:off']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800592 if preserved_dut_hub_sel != required_dut_hub_sel:
593 # Need to set it to get the port properly powered up.
594 args += ['dut_hub_sel:%s' % required_dut_hub_sel]
Simon Glass93673cf2013-04-26 17:55:55 -0700595 if self._servo_port is not None:
596 self._out.Progress('Reseting board via servo')
597 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700598
Simon Glassde9c8072012-07-02 22:29:02 -0700599 # If we have a kernel to write, create a new image with that added.
600 if kernel:
601 dl_image = os.path.join(self._tools.outdir, 'image-plus-kernel.bin')
602 data = self._tools.ReadFile(image)
603
604 # Pad the original payload out to the original length
605 data += '\0' * (os.stat(payload).st_size - len(data))
606 data += self._tools.ReadFile(kernel)
607 self._tools.WriteFile(dl_image, data)
608 else:
609 dl_image = image
610
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700611 self._out.Progress('Uploading image')
Simon Glass27a9c142012-03-15 21:08:29 -0700612 download_list = [
Simon Glassb4c14af2013-07-04 11:56:33 +0900613 ['bl1', bl1],
614 ['bl2', bl2],
615 ['u-boot', dl_image]
Simon Glass27a9c142012-03-15 21:08:29 -0700616 ]
Simon Glassb4c14af2013-07-04 11:56:33 +0900617
Simon Glass3381a1a2012-03-22 11:13:19 -0700618 try:
Simon Glass4968a472012-05-23 13:52:19 -0700619 for upto in range(len(download_list)):
620 item = download_list[upto]
Simon Glass3381a1a2012-03-22 11:13:19 -0700621 if not self._WaitForUSBDevice('exynos', vendor_id, product_id, 4):
Simon Glass4968a472012-05-23 13:52:19 -0700622 if upto == 0:
Simon Glass3381a1a2012-03-22 11:13:19 -0700623 raise CmdError('Could not find Exynos board on USB port')
624 raise CmdError("Stage '%s' did not complete" % item[0])
Simon Glassb4c14af2013-07-04 11:56:33 +0900625 self._out.Notice(item[1])
Simon Glass27a9c142012-03-15 21:08:29 -0700626 self._out.Progress("Uploading stage '%s'" % item[0])
Simon Glass3381a1a2012-03-22 11:13:19 -0700627
Simon Glass4968a472012-05-23 13:52:19 -0700628 if upto == 0:
629 # The IROM needs roughly 200ms here to be ready for USB download
630 time.sleep(.5)
631
Simon Glassb4c14af2013-07-04 11:56:33 +0900632 args = ['-a', '%#x' % addresses[item[0]], '-f', item[1]]
Simon Glass79e3dd02012-08-28 20:08:50 -0700633 self._tools.Run('smdk-usbdl', args, sudo=True)
Simon Glass4968a472012-05-23 13:52:19 -0700634
Simon Glass3381a1a2012-03-22 11:13:19 -0700635 finally:
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800636 # Make sure that the power button is released and dut_sel_hub state is
637 # restored, whatever happens
Simon Glass3381a1a2012-03-22 11:13:19 -0700638 args = ['fw_up:off', 'pwr_button:release']
Vadim Bendeburybfaf0552013-01-24 17:38:00 -0800639 if preserved_dut_hub_sel != required_dut_hub_sel:
640 args += ['dut_hub_sel:%s' % preserved_dut_hub_sel]
Vadim Bendebury2b719452013-02-12 17:00:06 -0800641 self.DutControl(args)
Simon Glass27a9c142012-03-15 21:08:29 -0700642
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800643 if flash_dest is None:
644 self._out.Notice('Image downloaded - please see serial output '
645 'for progress.')
Simon Glass27a9c142012-03-15 21:08:29 -0700646 return True
647
Simon Glass0c2ba482012-03-22 21:57:51 -0700648 def _GetDiskInfo(self, disk, item):
649 """Returns information about a SCSI disk device.
650
651 Args:
652 disk: a block device name in sys/block, like '/sys/block/sdf'.
653 item: the item of disk information that is required.
654
655 Returns:
656 The information obtained, as a string, or '[Unknown]' if not found
657 """
658 dev_path = os.path.join(disk, 'device')
659
660 # Search upwards and through symlinks looking for the item.
661 while os.path.isdir(dev_path) and dev_path != '/sys':
662 fname = os.path.join(dev_path, item)
663 if os.path.exists(fname):
664 with open(fname, 'r') as fd:
665 return fd.readline().rstrip()
666
667 # Move up a level and follow any symlink.
668 new_path = os.path.join(dev_path, '..')
669 if os.path.islink(new_path):
670 new_path = os.path.abspath(os.readlink(os.path.dirname(dev_path)))
671 dev_path = new_path
672 return '[Unknown]'
673
674 def _GetDiskCapacity(self, device):
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700675 """Returns the disk capacity in tenth of GB, or 0 if not known.
Simon Glass0c2ba482012-03-22 21:57:51 -0700676
677 Args:
678 device: Device to check, like '/dev/sdf'.
679
680 Returns:
681 Capacity of device in GB, or 0 if not known.
682 """
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700683 re_capacity = re.compile('Disk %s: .* (\d+) bytes' % device)
Simon Glass0c2ba482012-03-22 21:57:51 -0700684 args = ['-l', device]
685 stdout = self._tools.Run('fdisk', args, sudo=True)
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700686 for line in stdout.splitlines():
687 m = re_capacity.match(line)
688 if m:
689 return int(int(m.group(1)) / 1e8)
Simon Glass0c2ba482012-03-22 21:57:51 -0700690 return 0
691
692 def _ListUsbDisks(self):
693 """Return a list of available removable USB disks.
694
695 Returns:
696 List of USB devices, each element is itself a list containing:
697 device ('/dev/sdx')
698 manufacturer name
699 product name
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700700 capacity in tenth of GB (an integer)
Simon Glass0c2ba482012-03-22 21:57:51 -0700701 """
702 disk_list = []
703 for disk in glob.glob('/sys/block/sd*'):
704 with open(disk + '/removable', 'r') as fd:
705 if int(fd.readline()) == 1:
706 device = '/dev/%s' % disk.split('/')[-1]
707 manuf = self._GetDiskInfo(disk, 'manufacturer')
708 product = self._GetDiskInfo(disk, 'product')
709 capacity = self._GetDiskCapacity(device)
710 if capacity:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700711 disk_list.append([device, manuf, product, capacity])
Simon Glass0c2ba482012-03-22 21:57:51 -0700712 return disk_list
713
714 def WriteToSd(self, flash_dest, disk, uboot, payload):
715 if flash_dest:
Vadim Bendebury2b719452013-02-12 17:00:06 -0800716 raw_image = self._PrepareFlasher(uboot, payload, flash_dest, '1:0')
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700717 bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
Simon Glass559b6612012-05-23 13:28:45 -0700718 spl_load_size = os.stat(raw_image).st_size
Simon Glass559b6612012-05-23 13:28:45 -0700719
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700720 bl2_handler = ExynosBl2(self._tools, self._out)
Vadim Bendebury0c961a72013-06-11 13:35:07 -0700721 bl2_file = bl2_handler.Configure(self._fdt, spl_load_size,
Vadim Bendebury8ae67892013-06-11 17:45:15 -0700722 bl2, 'flasher', True)
Vadim Bendeburydcc5a5c2013-06-10 13:45:36 -0700723 data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
Simon Glass559b6612012-05-23 13:28:45 -0700724
Vadim Bendebury22de0492013-06-17 16:11:20 -0700725 # Pad BL2 out to the required size. Its size could be either 14K or 30K
726 # bytes, but the next object in the file needs to be aligned at an 8K
727 # boundary. The BL1 size is also known to be 8K bytes, so the total BL1
728 # + BL2 size needs to be aligned to 8K (0x2000) boundary.
729 aligned_size = (len(data) + 0x1fff) & ~0x1fff
730 pad_size = aligned_size - len(data)
731 data += '\0' * pad_size
732
Simon Glass559b6612012-05-23 13:28:45 -0700733 data += self._tools.ReadFile(raw_image)
734 image = os.path.join(self._tools.outdir, 'flasher-with-bl.bin')
735 self._tools.WriteFile(image, data)
Simon Glass0c2ba482012-03-22 21:57:51 -0700736 self._out.Progress('Writing flasher to %s' % disk)
737 else:
738 image = payload
739 self._out.Progress('Writing image to %s' % disk)
740
741 args = ['if=%s' % image, 'of=%s' % disk, 'bs=512', 'seek=1']
742 self._tools.Run('dd', args, sudo=True)
Vadim Bendebury7706c4c2013-03-28 09:50:00 -0700743 self._out.Progress('Syncing')
744 self._tools.Run('sync', [], sudo=True)
Simon Glass0c2ba482012-03-22 21:57:51 -0700745
746 def SendToSdCard(self, dest, flash_dest, uboot, payload):
747 """Write a flasher to an SD card.
748
749 Args:
750 dest: Destination in one of these forms:
Simon Glass0c2ba482012-03-22 21:57:51 -0700751 ':.' selects the only available device, fails if more than one option
752 ':<device>' select deivce
753
754 Examples:
Simon Glass0c2ba482012-03-22 21:57:51 -0700755 ':.'
756 ':/dev/sdd'
757
758 flash_dest: Destination for flasher, or None to not create a flasher:
759 Valid options are spi, sdmmc.
760 uboot: Full path to u-boot.bin.
761 payload: Full path to payload.
762 """
763 disk = None
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700764
Vadim Bendebury223af572013-04-27 13:25:13 -0700765 # If no removable devices found - prompt user and wait for one to appear.
766 disks = self._ListUsbDisks()
767 try:
768 spinner = '|/-\\'
769 index = 0
770 while not disks:
771 self._out.ClearProgress()
772 self._out.Progress('No removable devices found, plug something in %s '
773 % spinner[index], trailer='')
774 index = (index + 1) % len(spinner)
775 disks = self._ListUsbDisks()
776 time.sleep(.2)
777 except KeyboardInterrupt:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700778 raise CmdError("No removable device found, interrupted")
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700779
780 if dest.startswith(':'):
Simon Glass0c2ba482012-03-22 21:57:51 -0700781 name = dest[1:]
782
783 # A '.' just means to use the only available disk.
784 if name == '.' and len(disks) == 1:
785 disk = disks[0][0]
786 for disk_info in disks:
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700787 # Use the device name.
788 if disk_info[0] == name:
Simon Glass0c2ba482012-03-22 21:57:51 -0700789 disk = disk_info[0]
790
791 if disk:
792 self.WriteToSd(flash_dest, disk, uboot, payload)
793 else:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700794 msg = ["Please specify destination as '-w sd:<disk_description>'",]
795 msg.append(' - <disk_description> can be either . for the only disk,')
796 msg.append(' or the full device name, one of listed below:')
Simon Glass0c2ba482012-03-22 21:57:51 -0700797 # List available disks as a convenience.
798 for disk in disks:
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700799 msg.append(' %s - %s %.1f GB' % (
Vadim Bendebury856d63c2013-03-21 19:09:35 -0700800 disk[0],
801 ' '.join(str(x) for x in disk[1:3]),
Vadim Bendeburyf4374c42013-04-27 13:59:28 -0700802 disk[3] / 10.0))
803 raise CmdError('\n'.join(msg))
Simon Glass0c2ba482012-03-22 21:57:51 -0700804
Vadim Bendebury19a77122013-01-24 17:38:00 -0800805 def Em100FlashImage(self, image_fname):
Simon Glass9eb8c722012-06-07 13:34:31 -0700806 """Send an image to an attached EM100 device.
807
808 This is a Dediprog EM100 SPI flash emulation device. We set up servo2
809 to do the SPI emulation, then write the image, then boot the board.
810 All going well, this is enough to get U-Boot running.
811
812 Args:
813 image_fname: Filename of image to send
814 """
815 args = ['spi2_vref:off', 'spi2_buf_en:off', 'spi2_buf_on_flex_en:off']
816 args.append('spi_hold:on')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800817 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700818
819 # TODO(sjg@chromium.org): This is for link. We could make this
820 # configurable from the fdt.
821 args = ['-c', 'W25Q64CV', '-d', self._tools.Filename(image_fname), '-r']
822 self._out.Progress('Writing image to em100')
823 self._tools.Run('em100', args, sudo=True)
824
Simon Glass93673cf2013-04-26 17:55:55 -0700825 if self._servo_port is not None:
826 self._out.Progress('Resetting board via servo')
827 args = ['cold_reset:on', 'sleep:.2', 'cold_reset:off', 'sleep:.5']
828 args.extend(['pwr_button:press', 'sleep:.2', 'pwr_button:release'])
829 self.DutControl(args)
Simon Glass9eb8c722012-06-07 13:34:31 -0700830
Simon Glass0c2ba482012-03-22 21:57:51 -0700831
Simon Glass27a9c142012-03-15 21:08:29 -0700832def DoWriteFirmware(output, tools, fdt, flasher, file_list, image_fname,
Simon Glass60a40af2012-06-07 11:54:17 -0700833 bundle, update=True, verify=False, dest=None,
Vadim Bendebury19a77122013-01-24 17:38:00 -0800834 flash_dest=None, kernel=None, bootstub=None, servo='any',
Simon Glass4b8b3bd2012-11-06 12:31:01 -0800835 method='tegra'):
Simon Glasse0b61442012-03-13 15:29:51 -0700836 """A simple function to write firmware to a device.
Simon Glass710dedc2011-08-09 14:08:52 -0700837
838 This creates a WriteFirmware object and uses it to write the firmware image
Simon Glasse0b61442012-03-13 15:29:51 -0700839 to the given destination device.
Simon Glass710dedc2011-08-09 14:08:52 -0700840
841 Args:
842 output: cros_output object to use.
843 tools: Tools object to use.
844 fdt: Fdt object to use as our device tree.
845 flasher: U-Boot binary to use as the flasher.
Simon Glass75759302012-03-15 20:26:53 -0700846 file_list: Dictionary containing files that we might need.
Simon Glass710dedc2011-08-09 14:08:52 -0700847 image_fname: Filename of image to write.
Simon Glass0191a882012-05-23 13:15:06 -0700848 bundle: The bundle object which created the image.
Simon Glass2c4b3e52011-11-15 14:45:43 -0800849 update: Use faster update algorithm rather then full device erase.
850 verify: Verify the write by doing a readback and CRC.
Simon Glasse0b61442012-03-13 15:29:51 -0700851 dest: Destination device to write firmware to (usb, sd).
Simon Glass2d1fc8b2012-03-22 21:44:50 -0700852 flash_dest: Destination device for flasher to program payload into.
Simon Glassde9c8072012-07-02 22:29:02 -0700853 kernel: Kernel file to write after U-Boot
Vadim Bendebury19a77122013-01-24 17:38:00 -0800854 bootstub: string, file name of the boot stub, if present
Simon Glass6a616c12012-09-24 18:13:46 -0700855 servo: Describes the servo unit to use: none=none; any=any; otherwise
856 port number of servo to use.
Simon Glass710dedc2011-08-09 14:08:52 -0700857 """
Vadim Bendebury2b719452013-02-12 17:00:06 -0800858 write = WriteFirmware(tools, fdt, output, bundle, update, verify)
Simon Glass6a616c12012-09-24 18:13:46 -0700859 write.SelectServo(servo)
Simon Glassd65f65f2013-03-28 17:03:41 -0700860 if flash_dest:
861 write.text_base = bundle.CalcTextBase('flasher ', fdt, flasher)
862 elif bootstub:
863 write.text_base = bundle.CalcTextBase('bootstub ', fdt, bootstub)
Simon Glasse0b61442012-03-13 15:29:51 -0700864 if dest == 'usb':
Vadim Bendebury2b719452013-02-12 17:00:06 -0800865 try:
866 write.DutControl(['cpu_uart_capture:on',])
867 method = fdt.GetString('/chromeos-config', 'flash-method', method)
868 if method == 'tegra':
869 tools.CheckTool('tegrarcm')
Vadim Bendebury2b719452013-02-12 17:00:06 -0800870 ok = write.NvidiaFlashImage(flash_dest, flasher, file_list['bct'],
871 image_fname, bootstub)
872 elif method == 'exynos':
873 tools.CheckTool('lsusb', 'usbutils')
874 tools.CheckTool('smdk-usbdl', 'smdk-dltool')
875 ok = write.ExynosFlashImage(flash_dest, flasher,
876 file_list['exynos-bl1'], file_list['exynos-bl2'], image_fname,
877 kernel)
878 else:
879 raise CmdError("Unknown flash method '%s'" % method)
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800880
Vadim Bendebury2b719452013-02-12 17:00:06 -0800881 if not ok:
882 raise CmdError('Image upload failed - please check board connection')
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800883 output.Progress('Image uploaded, waiting for completion')
Vadim Bendebury3b4ae2c2013-02-19 17:37:18 -0800884
885 if flash_dest is not None and servo != 'none':
886 write.WaitForCompletion()
Vadim Bendeburyeabc2cd2013-02-13 19:25:22 -0800887 output.Progress('Done!')
888
Vadim Bendebury2b719452013-02-12 17:00:06 -0800889 finally:
890 write.DutControl(['cpu_uart_capture:off',])
Simon Glass9eb8c722012-06-07 13:34:31 -0700891 elif dest == 'em100':
892 # crosbug.com/31625
893 tools.CheckTool('em100')
Vadim Bendebury19a77122013-01-24 17:38:00 -0800894 write.Em100FlashImage(image_fname)
Simon Glass0c2ba482012-03-22 21:57:51 -0700895 elif dest.startswith('sd'):
896 write.SendToSdCard(dest[2:], flash_dest, flasher, image_fname)
Simon Glass710dedc2011-08-09 14:08:52 -0700897 else:
Simon Glasse0b61442012-03-13 15:29:51 -0700898 raise CmdError("Unknown destination device '%s'" % dest)