cros_bundle_firmware: Add configurable load address and SPI offset
At present, SPL always loads U-Boot to a fixed address (the text base) and
always from a fixed offset in SPI flash.
For early-firmware-selection, we want to allow changing these. The RO SPL
needs to read U-Boot into IRAM and the RW SPL needs to read U-Boot into
SDRAM. Each needs to reads from a different SPI flash offset.
Add support for a new U-Boot SPL machine params for SPI offset and load
address. This will allow us to support early-firmware-selection.
Use the early-firmware-selection switch to tell us whether to use IRAM for
the 'ro-boot' or not. Use a new 'payload' property in the flashmap SPL
region to tell us which section that region will be loading. This means
that SPL can now load any region in flash, not just a hard-coded offset.
U-Boot will now have two build variants. This is unavoidable for the moment
as we need the RO U-Boot to be as small as possible to fit into IRAM, but
the RW U-Boot needs to support LCD display (using 2MB of RAM) and other
features. So we define 'ro-boot' as the new RO U-Boot and keep 'boot' to
mean the normal U-Boot as now.
Add compatibility features so that the existing U-Boot flashmap is still
valid - a default payload and default addresses for IRAM, BL1, etc.
This is a rather large change. When I tried splitting it out it just added
confusion since all the pieces are related anyway.
BUG=chrome-os-partner:21115
TEST=FEATURES=test sudo -E emerge cros-devutils
With U-Boot changes, early-firmware-selection works as expected.
Change-Id: I38ad3b4b17ddf0e95e5c76cc1e42b035a8302eaa
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/63042
diff --git a/host/lib/bundle_firmware.py b/host/lib/bundle_firmware.py
index fe6ded4..aedfe17 100644
--- a/host/lib/bundle_firmware.py
+++ b/host/lib/bundle_firmware.py
@@ -105,6 +105,7 @@
'read-only' : True,
'filename' : "bl2.bin",
'type' : "blob exynos-bl2 boot,dtb",
+ 'payload' : '/flash/ro-boot',
'required' : True,
}, {
'path' : '/flash/ro-boot',
@@ -165,6 +166,7 @@
'read-only' : True,
'filename' : "bl2.bin",
'type' : "blob exynos-bl2 boot,dtb",
+ 'payload' : '/flash/ro-boot',
'required' : True,
}, {
'path' : '/flash/ro-boot',
@@ -935,6 +937,8 @@
fdt.PutInteger('/flash/rw-b-vblock', 'preamble-flags', 0)
if self._force_efs:
fdt.PutInteger('/chromeos-config', 'early-firmware-selection', 1)
+ pack.use_efs = fdt.GetInt('/chromeos-config', 'early-firmware-selection',
+ 0)
if not fdt.GetProp('/flash', 'reg', ''):
fdt.InsertNodes(default_flashmap)
diff --git a/host/lib/exynos.py b/host/lib/exynos.py
index d0b2cc7..ac5f401 100644
--- a/host/lib/exynos.py
+++ b/host/lib/exynos.py
@@ -72,7 +72,34 @@
self._spl_type = None
self.spl_source = 'straps' # SPL boot according to board settings
- def _UpdateParameters(self, fdt, spl_load_size, data, pos):
+ def GetUBootAddress(self, fdt, use_efs_memory):
+ """Work out the correct address for loading U-Boot.
+
+ This deals with EFS and the memory map automatically.
+
+ Args:
+ fdt: Device tree file containing memory map.
+ use_efs_memory: True to return the address in EFS memory (i.e. SRAM),
+ False to use SDRAM
+
+ Returns:
+ Address to load U-Boot
+ """
+ efs_suffix = ''
+ if use_efs_memory:
+ if fdt.GetInt('/chromeos-config', 'early-firmware-selection', 0):
+ efs_suffix = ',efs'
+
+ # Use the correct memory section, and then find the offset in that.
+ memory = fdt.GetString('/config', 'u-boot-memory' + efs_suffix)
+ base = fdt.GetIntList(memory, 'reg')[0]
+ offset = fdt.GetIntList('/config', 'u-boot-offset' + efs_suffix)[0]
+ addr = base + offset
+ self._out.Notice('EFS: Loading U-Boot to %x' % addr)
+ return addr
+
+ def _UpdateParameters(self, fdt, spl_load_offset, spl_load_size, data, pos,
+ use_efs_memory):
"""Update the parameters in a BL2 blob.
We look at the list in the parameter block, extract the value of each
@@ -80,9 +107,12 @@
Args:
fdt: Device tree containing the parameter values.
+ spl_load_offset: Offset in boot media that SPL must start loading (bytes)
spl_load_size: Size of U-Boot image that SPL must load
data: The BL2 data.
pos: The position of the start of the parameter block.
+ use_efs_memory: True to return the address in EFS memory (i.e. SRAM),
+ False to use SDRAM
Returns:
The new contents of the parameter block, after updating.
@@ -182,6 +212,12 @@
value = (spl_load_size + 0xfff) & ~0xfff
self._out.Info(' U-Boot size: %#0x (rounded up from %#0x)' %
(value, spl_load_size))
+ elif param == 'S':
+ value = self.GetUBootAddress(fdt, use_efs_memory)
+ self._out.Info(' U-Boot start: %#0x' % value)
+ elif param == 'o':
+ value = spl_load_offset
+ self._out.Info(' U-Boot offset: %#0x' % value)
elif param == 'l':
load_addr = fdt.GetInt('/config', 'u-boot-load-addr', -1)
if load_addr == -1:
@@ -257,7 +293,6 @@
# Put the data into our block.
data = data[:pos] + new_data + data[pos + len(new_data):]
- self._out.Info('BL2 configuration complete')
return data
def _UpdateChecksum(self, data):
@@ -375,14 +410,15 @@
pass
raise CmdError('Unrecognizable bl2 format')
- def Configure(self, fdt, spl_load_size, orig_bl2, name='',
- loose_check=False, digest=None):
+ def Configure(self, fdt, spl_load_offset, spl_load_size, orig_bl2, name='',
+ loose_check=False, digest=None, use_efs_memory=True):
"""Configure an Exynos BL2 binary for our needs.
We create a new modified BL2 and return its file name.
Args:
fdt: Device tree containing the parameter values.
+ spl_load_offset: Offset in boot media that SPL must start loading (bytes)
spl_load_size: Size of U-Boot image that SPL must load
orig_bl2: Filename of original BL2 file to modify.
name: a string, suffix to add to the generated file name
@@ -390,6 +426,8 @@
size value in the header. This is necessary for cases when
SPL is pulled out of an image (and is padded).
digest: If not None, hash digest to add to this BL2 (a string of bytes).
+ use_efs_memory: True to return the address in EFS memory (i.e. SRAM),
+ False to use SDRAM
Returns:
Filename of configured bl2.
@@ -397,7 +435,8 @@
Raises:
CmdError if machine parameter block could not be found.
"""
- self._out.Info('Configuring BL2')
+ bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
+ self._out.Info('Configuring BL2 %s' % bl2)
data = self._tools.ReadFile(orig_bl2)
self._VerifyBl2(data, loose_check)
@@ -407,12 +446,12 @@
if not pos:
raise CmdError("Could not find machine parameter block in '%s'" %
orig_bl2)
- data = self._UpdateParameters(fdt, spl_load_size, data, pos)
+ data = self._UpdateParameters(fdt, spl_load_offset, spl_load_size, data,
+ pos, use_efs_memory)
if digest:
data = self._UpdateHash(data, digest)
data = self._UpdateChecksum(data)
- bl2 = os.path.join(self._tools.outdir, 'updated-spl%s.bin' % name)
self._tools.WriteFile(bl2, data)
return bl2
@@ -462,6 +501,18 @@
compress = None
data = pack.ConcatPropContents(prop_list, compress, False)[0]
spl_load_size = len(data)
+
+ # Figure out what flash region SPL needs to load.
+ payload = fdt.GetString(blob.node, 'payload', 'none')
+ if payload == 'none':
+ payload = '/flash/ro-boot'
+ self._out.Warning("No payload boot media for '%s' - using %s" %
+ (blob.node, payload))
+ spl_load_offset = fdt.GetIntList(payload, 'reg', 2)[0]
+
+ # Tell this SPL to use EFS memory (i.e. SRAM) if we are using ro-boot
+ use_efs_memory = 'ro-boot' in prop_list
+
self._out.Info("BL2/SPL contains '%s', size is %d / %#x" %
(', '.join(prop_list), spl_load_size, spl_load_size))
if fdt.GetBool(blob.node, 'hash-target'):
@@ -470,6 +521,7 @@
digest = hasher.digest()
else:
digest = None
- bl2 = self.Configure(fdt, spl_load_size, vanilla_bl2, name=name,
- digest=digest)
+ bl2 = self.Configure(fdt, spl_load_offset, spl_load_size, vanilla_bl2,
+ name=name, digest=digest,
+ use_efs_memory=use_efs_memory)
return bl2
diff --git a/host/lib/write_firmware.py b/host/lib/write_firmware.py
index 3946f53..4f2af1d 100644
--- a/host/lib/write_firmware.py
+++ b/host/lib/write_firmware.py
@@ -75,6 +75,9 @@
# Use default servo port
self._servo_port = 0
+ # By default, no early firmware selection.
+ self.use_efs = False
+
def SelectServo(self, servo):
"""Select the servo to use for writing firmware.
@@ -525,10 +528,11 @@
embedded FDT
Returns:
- (bl1, bl2, image) where:
+ (bl1, bl2, image, uboot_offset) where:
bl1 is the filename of the extracted BL1
bl2 is the filename of the extracted BL2
image is the filename of the extracted U-Boot image
+ uboot_offset is the offset of U-Boot in the image
"""
# Pull out the parts from the payload
bl1 = os.path.join(self._tools.outdir, 'bl1.bin')
@@ -585,10 +589,10 @@
uboot_data = uboot_data[:fdt_offset]
self._tools.WriteFile(image, uboot_data)
- return bl1, bl2, image
+ return bl1, bl2, image, uboot_offset
def ExynosFlashImage(self, flash_dest, flash_uboot, bl1, bl2, payload,
- kernel):
+ kernel):
"""Flash the image to SPI flash.
This creates a special Flasher binary, with the image to be flashed as
@@ -610,9 +614,11 @@
Raises:
CmdError if a supported Exynos model is not detected in the device tree.
"""
+ use_efs_memory = False
tools = self._tools
- payload_bl1, payload_bl2, payload_image = (
+ payload_bl1, payload_bl2, payload_image, spl_load_offset = (
self._ExtractPayloadParts(payload, flash_dest is not None))
+ bl2_handler = ExynosBl2(tools, self._out)
if flash_dest:
# If we don't have some bits, get them from the image
if not flash_uboot or not os.path.exists(tools.Filename(flash_uboot)):
@@ -625,12 +631,13 @@
self._out.Warning('Extracting BL2 from payload')
bl2 = payload_bl2
else:
- # Update BL2 machine parameters, as
- # the BL2 passed in may not be updated
+ # Update BL2 machine parameters, as the BL2 passed in may not be
+ # updated. Also make sure it doesn't use early-firmware-selection
+ # since our flasher needs to run from SDRAM.
spl_load_size = os.stat(tools.Filename(bl2)).st_size
- bl2_handler = ExynosBl2(tools, self._out)
- bl2 = bl2_handler.Configure(self._fdt, spl_load_size,
- bl2, 'flasher', True)
+ bl2 = bl2_handler.Configure(self._fdt, spl_load_offset, spl_load_size,
+ bl2, 'flasher', loose_check=True,
+ use_efs_memory=False)
# Set default values for Exynos targets.
if flash_dest['bus'] is None:
flash_dest['bus'] = 1
@@ -675,7 +682,23 @@
data += self._tools.ReadFile(kernel)
self._tools.WriteFile(dl_image, data)
else:
- dl_image = image
+ # See which type of memory we should load U-Boot to
+ used_size = self._fdt.GetFlashPartUsed('ro', 'boot')
+ if self.use_efs and used_size:
+ node = self._fdt.GetFlashNode('ro', 'boot')
+ props = self._fdt.GetProp(node, 'type,efs', 'none')
+ if props != 'none' and props[0] == 'blob':
+ parts = props[1].split(',')
+ use_efs_memory = 'ro-boot' in parts
+
+ # Truncate the image to just the size actually used
+ if use_efs_memory:
+ dl_image = os.path.join(self._tools.outdir, 'image-used.bin')
+ data = self._tools.ReadFile(image)
+ self._tools.WriteFile(dl_image, data[:used_size])
+ self._out.Warning('Truncating to used size %#x' % used_size)
+ else:
+ dl_image = image
self._out.Progress('Uploading image')
@@ -700,9 +723,13 @@
# The IROM needs roughly 200ms here to be ready for USB download
time.sleep(.5)
- base = self._fdt.GetIntList(item[0], 'reg')[0]
- offset = self._fdt.GetIntList('/config', item[1])[0]
- addr = base + offset
+ # Load U-Boot either to IRAM or SDRAM depending on EFS
+ if upto == 2:
+ addr = bl2_handler.GetUBootAddress(self._fdt, use_efs_memory)
+ else:
+ base = self._fdt.GetIntList(item[0], 'reg')[0]
+ offset = self._fdt.GetIntList('/config', item[1])[0]
+ addr = base + offset
self._out.Progress("Uploading stage '%s' to %x" % (item[1], addr))
args = ['-a', '%#x' % addr, '-f', item[2]]
@@ -795,12 +822,13 @@
if flash_dest['dev'] is None:
flash_dest['dev'] = 0
raw_image = self._PrepareFlasher(uboot, payload, flash_dest)
- bl1, bl2, _ = self._ExtractPayloadParts(payload, True)
+ bl1, bl2, _, spl_load_offset = self._ExtractPayloadParts(payload, True)
spl_load_size = os.stat(raw_image).st_size
bl2_handler = ExynosBl2(self._tools, self._out)
- bl2_file = bl2_handler.Configure(self._fdt, spl_load_size,
- bl2, 'flasher', True)
+ bl2_file = bl2_handler.Configure(self._fdt, spl_load_offset,
+ spl_load_size, bl2, 'flasher', True,
+ use_efs_memory=False)
data = self._tools.ReadFile(bl1) + self._tools.ReadFile(bl2_file)
# Pad BL2 out to the required size. Its size could be either 14K or 30K