From 6208975e237c9549cab50756c6291d3ecde953b7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 31 Dec 2020 09:52:12 -0700 Subject: [PATCH 01/44] tpm: cr50: Check for valid locality When the Cr50 starts up it doesn't have a valid locality. The driver sets it to -1 to indicate that. Tracking this allows cr50_i2c_cleanup() to avoid releasing a locality that was not claimed. However the helper functions that generate the flags use a u8 type which cannot support -1, so they return a locality of 0xff. Fix this by updating the type. With this, 'tpm startup TPM2_SU_CLEAR' works as expected. Signed-off-by: Simon Glass --- drivers/tpm/cr50_i2c.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index ce61b72d22..f53924a8fc 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -183,23 +183,31 @@ static int cr50_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer, return cr50_i2c_wait_tpm_ready(dev); } -static inline u8 tpm_access(u8 locality) +static inline u8 tpm_access(int locality) { + if (locality == -1) + locality = 0; return 0x0 | (locality << 4); } -static inline u8 tpm_sts(u8 locality) +static inline u8 tpm_sts(int locality) { + if (locality == -1) + locality = 0; return 0x1 | (locality << 4); } -static inline u8 tpm_data_fifo(u8 locality) +static inline u8 tpm_data_fifo(int locality) { + if (locality == -1) + locality = 0; return 0x5 | (locality << 4); } -static inline u8 tpm_did_vid(u8 locality) +static inline u8 tpm_did_vid(int locality) { + if (locality == -1) + locality = 0; return 0x6 | (locality << 4); } From 5372fc772ec0004297c080a0bd53f1871bd6b93a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 31 Dec 2020 09:52:13 -0700 Subject: [PATCH 02/44] tpm: cr50: Add a better description and more debug Update the TPM description to include the interrupt mechanicm since this is useful to know. Also add a warning if the TPM cannot be found and a debug line if it succeeds. Signed-off-by: Simon Glass --- drivers/tpm/cr50_i2c.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index f53924a8fc..8b79240963 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -380,7 +380,6 @@ out_err: static int cr50_i2c_send(struct udevice *dev, const u8 *buf, size_t len) { struct cr50_priv *priv = dev_get_priv(dev); - int status; size_t burstcnt, limit, sent = 0; u8 tpm_go[4] = { TPM_STS_GO }; @@ -557,9 +556,23 @@ static int cr50_i2c_get_desc(struct udevice *dev, char *buf, int size) { struct dm_i2c_chip *chip = dev_get_parent_plat(dev); struct cr50_priv *priv = dev_get_priv(dev); + int len; - return snprintf(buf, size, "cr50 TPM 2.0 (i2c %02x id %x) irq=%d", - chip->chip_addr, priv->vendor >> 16, priv->use_irq); + len = snprintf(buf, size, "cr50 TPM 2.0 (i2c %02x id %x), ", + chip->chip_addr, priv->vendor >> 16); + if (priv->use_irq) { + len += snprintf(buf + len, size - len, "irq=%s/%ld", + priv->irq.dev->name, priv->irq.id); + } else if (dm_gpio_is_valid(&priv->ready_gpio)) { + len += snprintf(buf + len, size - len, "gpio=%s/%u", + priv->ready_gpio.dev->name, + priv->ready_gpio.offset); + } else { + len += snprintf(buf + len, size - len, "delay=%d", + TIMEOUT_NO_IRQ_US); + } + + return len; } static int cr50_i2c_open(struct udevice *dev) @@ -702,11 +715,12 @@ static int cr50_i2c_probe(struct udevice *dev) mdelay(10); } if (vendor != CR50_DID_VID) { - log_debug("DID_VID %08x not recognised\n", vendor); + log_warning("DID_VID %08x not recognised\n", vendor); return log_msg_ret("vendor-id", -EXDEV); } priv->vendor = vendor; priv->locality = -1; + log_debug("Cr50 ready\n"); return 0; } From 3039fc7e964c75aba700538881b8b107c6e8792b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 31 Dec 2020 09:52:14 -0700 Subject: [PATCH 03/44] tpm: cr50: Rename driver to work with of-platdata Update the driver name to match the compatible string, so it can work with of-platdata. Signed-off-by: Simon Glass --- drivers/tpm/cr50_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tpm/cr50_i2c.c b/drivers/tpm/cr50_i2c.c index 8b79240963..b103a6fdc3 100644 --- a/drivers/tpm/cr50_i2c.c +++ b/drivers/tpm/cr50_i2c.c @@ -742,8 +742,8 @@ static const struct udevice_id cr50_i2c_ids[] = { { } }; -U_BOOT_DRIVER(cr50_i2c) = { - .name = "cr50_i2c", +U_BOOT_DRIVER(google_cr50) = { + .name = "google_cr50", .id = UCLASS_TPM, .of_match = cr50_i2c_ids, .ops = &cr50_i2c_ops, From 30e486f3a501cbfdce178433fa66bdc001ab7e05 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 31 Dec 2020 09:52:15 -0700 Subject: [PATCH 04/44] x86: coral: Update an unused pin to reduce power GPIO_25 is not used on coral, so set it up in deep sleep. Signed-off-by: Simon Glass --- arch/x86/dts/chromebook_coral.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts index a846022095..965f59276a 100644 --- a/arch/x86/dts/chromebook_coral.dts +++ b/arch/x86/dts/chromebook_coral.dts @@ -637,6 +637,7 @@ PAD_CFG0_TX_DISABLE | PAD_CFG0_ROUTE_IOAPIC | PAD_CFG0_TRIG_LEVEL | PAD_CFG0_RX_POL_INVERT) (PAD_CFG1_PULL_NONE | PAD_CFG1_IOSSTATE_TXD_RXE) + PAD_CFG_GPI(GPIO_25, UP_20K, DEEP) /* unused */ /* * WLAN_PE_RST - default to deasserted just in case FSP From 5c53da2b30819514bc309888ad71890494e32295 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 31 Dec 2020 09:52:16 -0700 Subject: [PATCH 05/44] x86: coral: Enable CONFIG_BOOTARGS_SUBST Enable this option so that the boot-script substitutions of %U works as expected. With this, it can boot into Chrome OS. Signed-off-by: Simon Glass --- configs/chromebook_coral_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/chromebook_coral_defconfig b/configs/chromebook_coral_defconfig index 05e6ce6493..ab73a0a88c 100644 --- a/configs/chromebook_coral_defconfig +++ b/configs/chromebook_coral_defconfig @@ -29,6 +29,7 @@ CONFIG_BOOTSTAGE_REPORT=y CONFIG_SPL_BOOTSTAGE_RECORD_COUNT=10 CONFIG_BOOTSTAGE_STASH=y CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS_SUBST=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_LOGF_FUNC=y CONFIG_SPL_LOG=y From 9fc6ebd8feb4654483b544d12587857cf8938796 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:10 -0700 Subject: [PATCH 06/44] dtoc: binman: Drop Python 2 code Drop a few more Python 2 relics that are no-longer needed. Signed-off-by: Simon Glass --- tools/binman/fmap_util.py | 4 ++-- tools/dtoc/fdt.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/binman/fmap_util.py b/tools/binman/fmap_util.py index b03fc28fbb..8277619768 100644 --- a/tools/binman/fmap_util.py +++ b/tools/binman/fmap_util.py @@ -53,8 +53,8 @@ FmapArea = collections.namedtuple('FmapArea', FMAP_AREA_NAMES) def NameToFmap(name): - if type(name) == bytes and sys.version_info[0] >= 3: - name = name.decode('utf-8') # pragma: no cover (for Python 2) + if type(name) == bytes: + name = name.decode('utf-8') return name.replace('\0', '').replace('-', '_').upper() def ConvertName(field_names, fields): diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index 4a78c73725..965106a3b2 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -460,8 +460,7 @@ class Node: prop_name: Name of property to add val: String value of property """ - if sys.version_info[0] >= 3: # pragma: no cover - val = bytes(val, 'utf-8') + val = bytes(val, 'utf-8') self.AddData(prop_name, val + b'\0') def AddSubnode(self, name): From 6deff872cf7ac25bf3d67066b57e7831cd560e5b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:11 -0700 Subject: [PATCH 07/44] patman: Correct lz4 compression parameters At present on large files, lz4 uses a larger block size (e.g. 256KB) than the 64KB supported by the U-Boot decompression implementation. Also it is optimised for maximum compression speed, producing larger output than we would like. Update the parameters to correct these problems. Signed-off-by: Simon Glass --- tools/patman/tools.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/patman/tools.py b/tools/patman/tools.py index d8e01a3e60..10997e4386 100644 --- a/tools/patman/tools.py +++ b/tools/patman/tools.py @@ -476,7 +476,8 @@ def Compress(indata, algo, with_header=True): fname = GetOutputFilename('%s.comp.tmp' % algo) WriteFile(fname, indata) if algo == 'lz4': - data = Run('lz4', '--no-frame-crc', '-c', fname, binary=True) + data = Run('lz4', '--no-frame-crc', '-B4', '-5', '-c', fname, + binary=True) # cbfstool uses a very old version of lzma elif algo == 'lzma': outfname = GetOutputFilename('%s.comp.otmp' % algo) From 397a770254781d1bc59b0f8730aec4b7f52d750d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:12 -0700 Subject: [PATCH 08/44] binman: Update the TODO list Two of the items have been completed and I thought of another one. Update the list. Signed-off-by: Simon Glass --- tools/binman/README | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/binman/README b/tools/binman/README index de1eedfc3f..a00c902616 100644 --- a/tools/binman/README +++ b/tools/binman/README @@ -1050,10 +1050,9 @@ Some ideas: - Allow easy building of images by specifying just the board name - Support building an image for a board (-b) more completely, with a configurable build directory -- Support adding FITs to an image -- Support for ARM Trusted Firmware (ATF) - Detect invalid properties in nodes - Sort the fdtmap by offset +- Output temporary files to a different directory -- Simon Glass From 5b378e4d0b88502faac50180d4be10d60a3f49a8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:13 -0700 Subject: [PATCH 09/44] binman: Show the size when writing entries Update the log output to show the size, since this is useful information. Signed-off-by: Simon Glass --- tools/binman/control.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/binman/control.py b/tools/binman/control.py index 072417f364..1952b2abf4 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -244,7 +244,8 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths, if not os.path.exists(fname): os.makedirs(fname) fname = os.path.join(fname, 'root') - tout.Notice("Write entry '%s' to '%s'" % (entry.GetPath(), fname)) + tout.Notice("Write entry '%s' size %x to '%s'" % + (entry.GetPath(), len(data), fname)) tools.WriteFile(fname, data) return einfos From 1ecf3b8f274f2fc66317d73532c82639f661f3ef Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:14 -0700 Subject: [PATCH 10/44] binman: Fix a few file comments Two files have the wrong comment at the top of them. Fix this. Signed-off-by: Simon Glass --- tools/binman/etype/u_boot_spl_bss_pad.py | 1 - tools/binman/etype/u_boot_spl_nodtb.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/binman/etype/u_boot_spl_bss_pad.py b/tools/binman/etype/u_boot_spl_bss_pad.py index 596b2bed97..df15cd24ce 100644 --- a/tools/binman/etype/u_boot_spl_bss_pad.py +++ b/tools/binman/etype/u_boot_spl_bss_pad.py @@ -9,7 +9,6 @@ from binman import elf from binman.entry import Entry -from patman import command from binman.etype.blob import Entry_blob from patman import tools diff --git a/tools/binman/etype/u_boot_spl_nodtb.py b/tools/binman/etype/u_boot_spl_nodtb.py index 6f4529396d..c154cfde57 100644 --- a/tools/binman/etype/u_boot_spl_nodtb.py +++ b/tools/binman/etype/u_boot_spl_nodtb.py @@ -2,7 +2,7 @@ # Copyright (c) 2016 Google, Inc # Written by Simon Glass # -# Entry-type module for 'u-boot-nodtb.bin' +# Entry-type module for 'u-boot-spl-nodtb.bin' # from binman.entry import Entry From 870a9ead569ce8ee1f9fc03d178b56e012465582 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:15 -0700 Subject: [PATCH 11/44] binman: Support finding symbols in sub-sections At present binman only supports resolving symbols in the same section as the binary that uses it. This is quite limited because we often need to group entries into different sections. Enhance the algorithm to search the entire image for symbols. Signed-off-by: Simon Glass --- tools/binman/elf.py | 3 +- tools/binman/elf_test.py | 4 ++- tools/binman/etype/section.py | 41 +++++++++++++++++++++--- tools/binman/ftest.py | 15 +++++++++ tools/binman/image.py | 45 +++++++++++++++++++++++++++ tools/binman/test/187_symbols_sub.dts | 22 +++++++++++++ 6 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 tools/binman/test/187_symbols_sub.dts diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 249074a334..03b49d7163 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -132,7 +132,8 @@ def LookupAndWriteSymbols(elf_fname, entry, section): (msg, sym.size)) # Look up the symbol in our entry tables. - value = section.LookupSymbol(name, sym.weak, msg, base.address) + value = section.GetImage().LookupImageSymbol(name, sym.weak, msg, + base.address) if value is None: value = -1 pack_string = pack_string.lower() diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index e3d218a89e..7a128018d9 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -45,10 +45,12 @@ class FakeSection: def GetPath(self): return 'section_path' - def LookupSymbol(self, name, weak, msg, base_addr): + def LookupImageSymbol(self, name, weak, msg, base_addr): """Fake implementation which returns the same value for all symbols""" return self.sym_value + def GetImage(self): + return self def BuildElfTestFiles(target_dir): """Build ELF files used for testing in binman diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index 3dd5f58c4c..9c6334c450 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -385,7 +385,7 @@ class Entry_section(Entry): return entry.GetData() source_entry.Raise("Cannot find entry for node '%s'" % node.name) - def LookupSymbol(self, sym_name, optional, msg, base_addr): + def LookupSymbol(self, sym_name, optional, msg, base_addr, entries=None): """Look up a symbol in an ELF file Looks up a symbol in an ELF file. Only entry types which come from an @@ -428,18 +428,20 @@ class Entry_section(Entry): (msg, sym_name)) entry_name, prop_name = m.groups() entry_name = entry_name.replace('_', '-') - entry = self._entries.get(entry_name) + if not entries: + entries = self._entries + entry = entries.get(entry_name) if not entry: if entry_name.endswith('-any'): root = entry_name[:-4] - for name in self._entries: + for name in entries: if name.startswith(root): rest = name[len(root):] if rest in ['', '-img', '-nodtb']: - entry = self._entries[name] + entry = entries[name] if not entry: err = ("%s: Entry '%s' not found in list (%s)" % - (msg, entry_name, ','.join(self._entries.keys()))) + (msg, entry_name, ','.join(entries.keys()))) if optional: print('Warning: %s' % err, file=sys.stderr) return None @@ -648,3 +650,32 @@ class Entry_section(Entry): """ for entry in self._entries.values(): entry.CheckMissing(missing_list) + + def _CollectEntries(self, entries, entries_by_name, add_entry): + """Collect all the entries in an section + + This builds up a dict of entries in this section and all subsections. + Entries are indexed by path and by name. + + Since all paths are unique, entries will not have any conflicts. However + entries_by_name make have conflicts if two entries have the same name + (e.g. with different parent sections). In this case, an entry at a + higher level in the hierarchy will win over a lower-level entry. + + Args: + entries: dict to put entries: + key: entry path + value: Entry object + entries_by_name: dict to put entries + key: entry name + value: Entry object + add_entry: Entry to add + """ + entries[add_entry.GetPath()] = add_entry + to_add = add_entry.GetEntries() + if to_add: + for entry in to_add.values(): + entries[entry.GetPath()] = entry + for entry in to_add.values(): + self._CollectEntries(entries, entries_by_name, entry) + entries_by_name[add_entry.name] = add_entry diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index e753a342c8..5016060ea6 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -4139,6 +4139,21 @@ class TestFunctional(unittest.TestCase): } self.assertEqual(expected, props) + def testSymbolsSubsection(self): + """Test binman can assign symbols from a subsection""" + elf_fname = self.ElfTestFile('u_boot_binman_syms') + syms = elf.GetSymbols(elf_fname, ['binman', 'image']) + addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start') + self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr) + + self._SetupSplElf('u_boot_binman_syms') + data = self._DoReadFile('187_symbols_sub.dts') + sym_values = struct.pack('_prop_ where is the name of + the entry and is the property to find (e.g. + _binman_u_boot_prop_offset). As a special case, you can append + _any to to have it search for any matching entry. E.g. + _binman_u_boot_any_prop_offset will match entries called u-boot, + u-boot-img and u-boot-nodtb) + optional: True if the symbol is optional. If False this function + will raise if the symbol is not found + msg: Message to display if an error occurs + base_addr: Base address of image. This is added to the returned + image_pos in most cases so that the returned position indicates + where the targeted entry/binary has actually been loaded. But + if end-at-4gb is used, this is not done, since the binary is + already assumed to be linked to the ROM position and using + execute-in-place (XIP). + + Returns: + Value that should be assigned to that symbol, or None if it was + optional and not found + + Raises: + ValueError if the symbol is invalid or not found, or references a + property which is not supported + """ + entries = OrderedDict() + entries_by_name = {} + self._CollectEntries(entries, entries_by_name, self) + return self.LookupSymbol(sym_name, optional, msg, base_addr, + entries_by_name) diff --git a/tools/binman/test/187_symbols_sub.dts b/tools/binman/test/187_symbols_sub.dts new file mode 100644 index 0000000000..54511a7371 --- /dev/null +++ b/tools/binman/test/187_symbols_sub.dts @@ -0,0 +1,22 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + section { + pad-byte = <0xff>; + u-boot-spl { + }; + + u-boot { + offset = <24>; + }; + }; + + u-boot-spl2 { + type = "u-boot-spl"; + }; + }; +}; From 939d1062d05fb4990ca7898613bcc753574f7c56 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:16 -0700 Subject: [PATCH 12/44] binman: Support reading an image with entry args Normally when an entry is created, any entry arguments it has are required to be provided, so it can actually generate its contents correctly. However when an existing image is read, Entry objects are created for each of the entries in the image. This happens as part of the process of reading the image into binman. In this case we don't need the entry arguments, since we do not intend to regenerate the entries, or at least not unless requested. So there is no sense in reporting an error for missing entry arguments. Add a new property for the Image to handle this case. Update the error reporting to be conditional on this property. Signed-off-by: Simon Glass --- tools/binman/entry.py | 3 +-- tools/binman/etype/section.py | 15 +++++++++++++++ tools/binman/ftest.py | 19 +++++++++++++++++++ tools/binman/image.py | 10 ++++++++-- tools/binman/test/188_image_entryarg.dts | 21 +++++++++++++++++++++ 5 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 tools/binman/test/188_image_entryarg.dts diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 2be0d8e053..d58a730f3d 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -434,8 +434,7 @@ class Entry(object): missing.append(prop.name) values.append(value) if missing: - self.Raise('Missing required properties/entry args: %s' % - (', '.join(missing))) + self.GetImage().MissingArgs(self, missing) return values def GetPath(self): diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index 9c6334c450..28a888776a 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -679,3 +679,18 @@ class Entry_section(Entry): for entry in to_add.values(): self._CollectEntries(entries, entries_by_name, entry) entries_by_name[add_entry.name] = add_entry + + def MissingArgs(self, entry, missing): + """Report a missing argument, if enabled + + For entries which require arguments, this reports an error if some are + missing. If missing entries are being ignored (e.g. because we read the + entry from an image rather than creating it), this function does + nothing. + + Args: + missing: List of missing properties / entry args, each a string + """ + if not self._ignore_missing: + entry.Raise('Missing required properties/entry args: %s' % + (', '.join(missing))) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 5016060ea6..8b928eb406 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -4154,6 +4154,25 @@ class TestFunctional(unittest.TestCase): U_BOOT_SPL_DATA[20:]) self.assertEqual(expected, data) + def testReadImageEntryArg(self): + """Test reading an image that would need an entry arg to generate""" + entry_args = { + 'cros-ec-rw-path': 'ecrw.bin', + } + data = self.data = self._DoReadFileDtb( + '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True, + entry_args=entry_args) + + image_fname = tools.GetOutputFilename('image.bin') + orig_image = control.images['image'] + + # This should not generate an error about the missing 'cros-ec-rw-path' + # since we are reading the image from a file. Compare with + # testEntryArgsRequired() + image = Image.FromFile(image_fname) + self.assertEqual(orig_image.GetEntries().keys(), + image.GetEntries().keys()) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/image.py b/tools/binman/image.py index 3622efc686..3c2fe5ea62 100644 --- a/tools/binman/image.py +++ b/tools/binman/image.py @@ -43,8 +43,13 @@ class Image(section.Entry_section): test: True if this is being called from a test of Images. This this case there is no device tree defining the structure of the section, so we create a section manually. + ignore_missing: Ignore any missing entry arguments (i.e. don't raise an + exception). This should be used if the Image is being loaded from + a file rather than generated. In that case we obviously don't need + the entry arguments since the contents already exists. """ - def __init__(self, name, node, copy_to_orig=True, test=False): + def __init__(self, name, node, copy_to_orig=True, test=False, + ignore_missing=False): super().__init__(None, 'section', node, test=test) self.copy_to_orig = copy_to_orig self.name = 'main-section' @@ -53,6 +58,7 @@ class Image(section.Entry_section): self.fdtmap_dtb = None self.fdtmap_data = None self.allow_repack = False + self._ignore_missing = ignore_missing if not test: self.ReadNode() @@ -100,7 +106,7 @@ class Image(section.Entry_section): # Return an Image with the associated nodes root = dtb.GetRoot() - image = Image('image', root, copy_to_orig=False) + image = Image('image', root, copy_to_orig=False, ignore_missing=True) image.image_node = fdt_util.GetString(root, 'image-node', 'image') image.fdtmap_dtb = dtb diff --git a/tools/binman/test/188_image_entryarg.dts b/tools/binman/test/188_image_entryarg.dts new file mode 100644 index 0000000000..29d8149162 --- /dev/null +++ b/tools/binman/test/188_image_entryarg.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <0xc00>; + u-boot { + }; + cros-ec-rw { + }; + fdtmap { + }; + image-header { + location = "end"; + }; + }; +}; From 5af9ebc4bcbcca91b21257c18cb94c78e7356980 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:17 -0700 Subject: [PATCH 13/44] binman: Allow vblock to include devicetree blobs At present if a devicetree blob is included in a vblock it does not deal with updates. This is because the vblock is created once at the start and does not have a method to update itself later, after all the entry contents are finalised. Fix this by adjusting how the vblock is created. Also simplify Image.ProcessEntryContents() since it effectively duplicates the code in Section.ProcessContents(). Signed-off-by: Simon Glass --- tools/binman/etype/blob.py | 4 ++ tools/binman/etype/vblock.py | 15 +++++++- tools/binman/ftest.py | 49 +++++++++++++++++++++++- tools/binman/image.py | 7 +--- tools/binman/test/189_vblock_content.dts | 31 +++++++++++++++ 5 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 tools/binman/test/189_vblock_content.dts diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py index 301ac55e3b..81756c326d 100644 --- a/tools/binman/etype/blob.py +++ b/tools/binman/etype/blob.py @@ -66,3 +66,7 @@ class Entry_blob(Entry): def GetDefaultFilename(self): return self._filename + + def ProcessContents(self): + # The blob may have changed due to WriteSymbols() + return self.ProcessContentsUpdate(self.data) diff --git a/tools/binman/etype/vblock.py b/tools/binman/etype/vblock.py index f734fbaec4..eba5351dd5 100644 --- a/tools/binman/etype/vblock.py +++ b/tools/binman/etype/vblock.py @@ -49,7 +49,7 @@ class Entry_vblock(Entry): EntryArg('kernelkey', str), EntryArg('preamble-flags', int)]) - def ObtainContents(self): + def GetVblock(self): # Join up the data files to be signed input_data = b'' for entry_phandle in self.content: @@ -76,5 +76,16 @@ class Entry_vblock(Entry): ] #out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label)) stdout = tools.Run('futility', *args) - self.SetContents(tools.ReadFile(output_fname)) + return tools.ReadFile(output_fname) + + def ObtainContents(self): + data = self.GetVblock() + if data is False: + return False + self.SetContents(data) return True + + def ProcessContents(self): + # The blob may have changed due to WriteSymbols() + data = self.GetVblock() + return self.ProcessContentsUpdate(data) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 8b928eb406..7f7827b6a7 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -1638,15 +1638,37 @@ class TestFunctional(unittest.TestCase): str(e.exception)) def _HandleVblockCommand(self, pipe_list): - """Fake calls to the futility utility""" + """Fake calls to the futility utility + + The expected pipe is: + + [('futility', 'vbutil_firmware', '--vblock', + 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock', + '--signprivate', 'devkeys/firmware_data_key.vbprivk', + '--version', '1', '--fv', 'input.vblock', '--kernelkey', + 'devkeys/kernel_subkey.vbpubk', '--flags', '1')] + + This writes to the output file (here, 'vblock.vblock'). If + self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash + of the input data (here, 'input.vblock'). + """ if pipe_list[0][0] == 'futility': fname = pipe_list[0][3] with open(fname, 'wb') as fd: - fd.write(VBLOCK_DATA) + if self._hash_data: + infile = pipe_list[0][11] + m = hashlib.sha256() + data = tools.ReadFile(infile) + m.update(data) + fd.write(m.digest()) + else: + fd.write(VBLOCK_DATA) + return command.CommandResult() def testVblock(self): """Test for the Chromium OS Verified Boot Block""" + self._hash_data = False command.test_result = self._HandleVblockCommand entry_args = { 'keydir': 'devkeys', @@ -1677,6 +1699,29 @@ class TestFunctional(unittest.TestCase): self.assertIn("Node '/binman/vblock': Cannot find entry for node " "'other'", str(e.exception)) + def testVblockContent(self): + """Test that the vblock signs the right data""" + self._hash_data = True + command.test_result = self._HandleVblockCommand + entry_args = { + 'keydir': 'devkeys', + } + data = self._DoReadFileDtb( + '189_vblock_content.dts', use_real_dtb=True, update_dtb=True, + entry_args=entry_args)[0] + hashlen = 32 # SHA256 hash is 32 bytes + self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)]) + hashval = data[-hashlen:] + dtb = data[len(U_BOOT_DATA):-hashlen] + + expected_data = U_BOOT_DATA + dtb + + # The hashval should be a hash of the dtb + m = hashlib.sha256() + m.update(expected_data) + expected_hashval = m.digest() + self.assertEqual(expected_hashval, hashval) + def testTpl(self): """Test that an image with TPL and its device tree can be created""" # ELF file with a '__bss_size' symbol diff --git a/tools/binman/image.py b/tools/binman/image.py index 3c2fe5ea62..e949435241 100644 --- a/tools/binman/image.py +++ b/tools/binman/image.py @@ -136,12 +136,7 @@ class Image(section.Entry_section): Returns: True if the new data size is OK, False if expansion is needed """ - sizes_ok = True - for entry in self._entries.values(): - if not entry.ProcessContents(): - sizes_ok = False - tout.Debug("Entry '%s' size change" % self._node.path) - return sizes_ok + return super().ProcessContents() def WriteSymbols(self): """Write symbol values into binary files for access at run time""" diff --git a/tools/binman/test/189_vblock_content.dts b/tools/binman/test/189_vblock_content.dts new file mode 100644 index 0000000000..dcc74449c1 --- /dev/null +++ b/tools/binman/test/189_vblock_content.dts @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u_boot: u-boot { + }; + + dtb: u-boot-dtb { + }; + + /* + * Put the vblock after the dtb so that the dtb is updated + * before the vblock reads its data. At present binman does not + * understand dependencies between entries, but simply + * iterates again when it thinks something needs to be + * recalculated. + */ + vblock { + content = <&u_boot &dtb>; + keyblock = "firmware.keyblock"; + signprivate = "firmware_data_key.vbprivk"; + version = <1>; + kernelkey = "kernel_subkey.vbpubk"; + preamble-flags = <1>; + }; + }; +}; From 6eb9932668fa6bd8c659484b2d18d8a73713208c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:18 -0700 Subject: [PATCH 14/44] binman: Support alignment of files When packing files it is sometimes useful to align the start of each file, e.g. if the flash driver can only access 32-bit-aligned data. Provides a new property to support this. Signed-off-by: Simon Glass --- tools/binman/etype/files.py | 4 ++++ tools/binman/ftest.py | 8 ++++++++ tools/binman/state.py | 10 ++++++++++ tools/binman/test/084_files.dts | 2 +- tools/binman/test/190_files_align.dts | 12 ++++++++++++ tools/dtoc/fdt.py | 12 ++++++++++++ tools/dtoc/test_fdt.py | 6 ++++++ 7 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 tools/binman/test/190_files_align.dts diff --git a/tools/binman/etype/files.py b/tools/binman/etype/files.py index ce3832e3cd..1feebd0510 100644 --- a/tools/binman/etype/files.py +++ b/tools/binman/etype/files.py @@ -22,6 +22,7 @@ class Entry_files(Entry_section): - files-compress: Compression algorithm to use: none: No compression lz4: Use lz4 compression (via 'lz4' command-line utility) + - files-align: Align each file to the given alignment This entry reads a number of files and places each in a separate sub-entry within this entry. To access these you need to enable device-tree updates @@ -38,6 +39,7 @@ class Entry_files(Entry_section): self.Raise("Missing 'pattern' property") self._files_compress = fdt_util.GetString(self._node, 'files-compress', 'none') + self._files_align = fdt_util.GetInt(self._node, 'files-align'); self._require_matches = fdt_util.GetBool(self._node, 'require-matches') @@ -55,6 +57,8 @@ class Entry_files(Entry_section): state.AddString(subnode, 'type', 'blob') state.AddString(subnode, 'filename', fname) state.AddString(subnode, 'compress', self._files_compress) + if self._files_align: + state.AddInt(subnode, 'align', self._files_align) # Read entries again, now that we have some self._ReadEntries() diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 7f7827b6a7..b31a7305a3 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -4218,6 +4218,14 @@ class TestFunctional(unittest.TestCase): self.assertEqual(orig_image.GetEntries().keys(), image.GetEntries().keys()) + def testFilesAlign(self): + """Test alignment with files""" + data = self._DoReadFile('190_files_align.dts') + + # The first string is 15 bytes so will align to 16 + expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:] + self.assertEqual(expect, data) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/state.py b/tools/binman/state.py index 36bc513535..bb3e36ea7a 100644 --- a/tools/binman/state.py +++ b/tools/binman/state.py @@ -314,6 +314,16 @@ def AddString(node, prop, value): for n in GetUpdateNodes(node): n.AddString(prop, value) +def AddInt(node, prop, value): + """Add a new string property to affected device trees + + Args: + prop_name: Name of property + val: Integer value of property + """ + for n in GetUpdateNodes(node): + n.AddInt(prop, value) + def SetInt(node, prop, value, for_repack=False): """Update an integer property in affected device trees with an integer value diff --git a/tools/binman/test/084_files.dts b/tools/binman/test/084_files.dts index 83ddb78f8e..8f09afd24e 100644 --- a/tools/binman/test/084_files.dts +++ b/tools/binman/test/084_files.dts @@ -5,7 +5,7 @@ binman { files { pattern = "files/*.dat"; - compress = "none"; + files-compress = "none"; }; }; }; diff --git a/tools/binman/test/190_files_align.dts b/tools/binman/test/190_files_align.dts new file mode 100644 index 0000000000..213ba966d3 --- /dev/null +++ b/tools/binman/test/190_files_align.dts @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0+ +/dts-v1/; + +/ { + binman { + files { + pattern = "files/*.dat"; + files-compress = "none"; + files-align = <4>; + }; + }; +}; diff --git a/tools/dtoc/fdt.py b/tools/dtoc/fdt.py index 965106a3b2..25ce5136eb 100644 --- a/tools/dtoc/fdt.py +++ b/tools/dtoc/fdt.py @@ -463,6 +463,18 @@ class Node: val = bytes(val, 'utf-8') self.AddData(prop_name, val + b'\0') + def AddInt(self, prop_name, val): + """Add a new integer property to a node + + The device tree is marked dirty so that the value will be written to + the blob on the next sync. + + Args: + prop_name: Name of property to add + val: Integer value of property + """ + self.AddData(prop_name, struct.pack('>I', val)) + def AddSubnode(self, name): """Add a new subnode to the node diff --git a/tools/dtoc/test_fdt.py b/tools/dtoc/test_fdt.py index dc6943f733..e8fbbd5d10 100755 --- a/tools/dtoc/test_fdt.py +++ b/tools/dtoc/test_fdt.py @@ -397,6 +397,12 @@ class TestProp(unittest.TestCase): data = self.fdt.getprop(self.node.Offset(), 'one') self.assertEqual(1, fdt32_to_cpu(data)) + val = 1234 + self.node.AddInt('integer', val) + self.dtb.Sync(auto_resize=True) + data = self.fdt.getprop(self.node.Offset(), 'integer') + self.assertEqual(val, fdt32_to_cpu(data)) + val = '123' + chr(0) + '456' self.node.AddString('string', val) self.dtb.Sync(auto_resize=True) From 5c6ba71bbe1285cfd323574dca88b8484a38aecd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 6 Jan 2021 21:35:19 -0700 Subject: [PATCH 15/44] binman: Allow for skip_at_start when reading entries The offset of an entry needs to be adjusted by its skip-at-start value. This is currently missing when reading entry data. Fix it. Signed-off-by: Simon Glass --- tools/binman/etype/section.py | 10 ++++++---- tools/binman/ftest.py | 19 +++++++++++++++++++ tools/binman/test/191_read_image_skip.dts | 23 +++++++++++++++++++++++ 3 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 tools/binman/test/191_read_image_skip.dts diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index 28a888776a..1ceadef13f 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -605,10 +605,12 @@ class Entry_section(Entry): def ReadData(self, decomp=True): tout.Info("ReadData path='%s'" % self.GetPath()) parent_data = self.section.ReadData(True) - tout.Info('%s: Reading data from offset %#x-%#x, size %#x' % - (self.GetPath(), self.offset, self.offset + self.size, - self.size)) - data = parent_data[self.offset:self.offset + self.size] + offset = self.offset - self.section._skip_at_start + data = parent_data[offset:offset + self.size] + tout.Info( + '%s: Reading data from offset %#x-%#x (real %#x), size %#x, got %#x' % + (self.GetPath(), self.offset, self.offset + self.size, offset, + self.size, len(data))) return data def ReadChildData(self, child, decomp=True): diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index b31a7305a3..814e91d42e 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -4226,6 +4226,25 @@ class TestFunctional(unittest.TestCase): expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:] self.assertEqual(expect, data) + def testReadImageSkip(self): + """Test reading an image and accessing its FDT map""" + data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts') + image_fname = tools.GetOutputFilename('image.bin') + orig_image = control.images['image'] + image = Image.FromFile(image_fname) + self.assertEqual(orig_image.GetEntries().keys(), + image.GetEntries().keys()) + + orig_entry = orig_image.GetEntries()['fdtmap'] + entry = image.GetEntries()['fdtmap'] + self.assertEqual(orig_entry.offset, entry.offset) + self.assertEqual(orig_entry.size, entry.size) + self.assertEqual(16, entry.image_pos) + + u_boot = image.GetEntries()['section'].GetEntries()['u-boot'] + + self.assertEquals(U_BOOT_DATA, u_boot.ReadData()) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/191_read_image_skip.dts b/tools/binman/test/191_read_image_skip.dts new file mode 100644 index 0000000000..31df518fae --- /dev/null +++ b/tools/binman/test/191_read_image_skip.dts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + end-at-4gb; + size = <0x400>; + section { + size = <0x10>; + u-boot { + }; + }; + fdtmap { + }; + image-header { + location = "end"; + }; + }; +}; From a0df924928906b9da095dcbfa63dd5503e3ac3df Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 22 Dec 2020 07:53:03 +0100 Subject: [PATCH 16/44] x86: typo segement %s/segement/segment/ Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng --- arch/x86/cpu/i386/cpu.c | 2 +- arch/x86/cpu/start.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index 7517b756f4..6fa0f4d32b 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -175,7 +175,7 @@ void arch_setup_gd(gd_t *new_gd) * Per Intel FSP external architecture specification, before calling any FSP * APIs, we need make sure the system is in flat 32-bit mode and both the code * and data selectors should have full 4GB access range. Here we reuse the one - * we used in arch/x86/cpu/start16.S, and reload the segement registers. + * we used in arch/x86/cpu/start16.S, and reload the segment registers. */ void setup_fsp_gdt(void) { diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 3b6ed37bc0..3d0d95295f 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -77,7 +77,7 @@ _start: lgdt gdt_ptr2 #endif - /* Load the segement registers to match the GDT loaded in start16.S */ + /* Load the segment registers to match the GDT loaded in start16.S */ movl $(X86_GDT_ENTRY_32BIT_DS * X86_GDT_ENTRY_SIZE), %eax movw %ax, %fs movw %ax, %ds From b680c5539a4b29889a2d248aaa2c14e2669046fd Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 25 Dec 2020 16:04:26 +0100 Subject: [PATCH 17/44] sandbox: fix sandbox_cmdline_cb_test_fdt() fmt does not foresee any parameter. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- arch/sandbox/cpu/start.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 2d18d9debc..2542580974 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -215,7 +215,7 @@ static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state, if (!p) p = fname + strlen(fname); len -= p - fname; - snprintf(p, len, fmt, p); + snprintf(p, len, fmt); state->fdt_fname = fname; return 0; From 3096ee866e7388277ad3968d9c7ea704589dedea Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 30 Dec 2020 18:10:24 +0100 Subject: [PATCH 18/44] doc/sandbox: improve formatting of command line options Show the command line options in bold. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- doc/arch/sandbox.rst | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst index 4674c420ac..1a7801af02 100644 --- a/doc/arch/sandbox.rst +++ b/doc/arch/sandbox.rst @@ -99,37 +99,37 @@ Command-line Options Various options are available, mostly for test purposes. Use -h to see available options. Some of these are described below: -* -t, --terminal - - The terminal is normally in what is called 'raw-with-sigs' mode. This means +-t, --terminal + The terminal is normally in what is called 'raw-with-sigs' mode. This means that you can use arrow keys for command editing and history, but if you press Ctrl-C, U-Boot will exit instead of handling this as a keypress. Other options are 'raw' (so Ctrl-C is handled within U-Boot) and 'cooked' (where the terminal is in cooked mode and cursor keys will not work, Ctrl-C will exit). -* -l - - Show the LCD emulation window. +-l + Show the LCD emulation window. -* -d - - A device tree binary file can be provided with -d. If you edit the source +-d + A device tree binary file can be provided with -d. If you edit the source (it is stored at arch/sandbox/dts/sandbox.dts) you must rebuild U-Boot to recreate the binary file. -* -D - - To use the default device tree, use -D. +-D + To use the default device tree, use -D. -* -T - - To use the test device tree, use -T. +-T + To use the test device tree, use -T. -* -c [;] - - To execute commands directly, use the -c option. You can specify a single +-c [;] + To execute commands directly, use the -c option. You can specify a single command, or multiple commands separated by a semicolon, as is normal in U-Boot. Be careful with quoting as the shell will normally process and swallow quotes. When -c is used, U-Boot exits after the command is complete, but you can force it to go to interactive mode instead with -i. -* -i - - Go to interactive mode after executing the commands specified by -c. +-i + Go to interactive mode after executing the commands specified by -c. Memory Emulation ---------------- From d8e9a93895fb3ad710963ddef6a4cc7c43bd65f6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:22 -0700 Subject: [PATCH 19/44] cros_ec: Add a function for the hello message This is used several times in this file. Put it in a function to avoid code duplication. Also add a test for this function. There are no cros_ec tests at present, so it is time to update the code. Signed-off-by: Simon Glass --- arch/sandbox/include/asm/test.h | 14 ++++++++++ drivers/misc/cros_ec.c | 46 ++++++++++++++++++++++----------- drivers/misc/cros_ec_sandbox.c | 12 +++++++++ include/cros_ec.h | 11 ++++++++ test/dm/Makefile | 1 + test/dm/cros_ec.c | 32 +++++++++++++++++++++++ 6 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 test/dm/cros_ec.c diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 05f66f700c..8363ca7319 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -57,6 +57,12 @@ enum { SYSCON_COUNT }; +/** + */ +enum cros_ec_test_t { + CROSECT_BREAK_HELLO = BIT(1), +}; + /** * sandbox_i2c_set_test_mode() - set test mode for running unit tests * @@ -260,4 +266,12 @@ uint sandbox_pci_read_bar(u32 barval, int type, uint size); */ void sandbox_set_enable_memio(bool enable); +/** + * sandbox_cros_ec_set_test_flags() - Set behaviour for testing purposes + * + * @dev: Device to check + * @flags: Flags to control behaviour (CROSECT_...) + */ +void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags); + #endif diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index f03b7d55d6..013c67e046 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -591,6 +591,25 @@ static int cros_ec_invalidate_hash(struct udevice *dev) return 0; } +int cros_ec_hello(struct udevice *dev, uint *handshakep) +{ + struct ec_params_hello req; + struct ec_response_hello *resp; + + req.in_data = 0x12345678; + if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), + (uint8_t **)&resp, sizeof(*resp)) < 0) + return -EIO; + if (resp->out_data != req.in_data + 0x01020304) { + printf("Received invalid handshake %x\n", resp->out_data); + if (handshakep) + *handshakep = req.in_data; + return -ENOTSYNC; + } + + return 0; +} + int cros_ec_reboot(struct udevice *dev, enum ec_reboot_cmd cmd, uint8_t flags) { struct ec_params_reboot_ec p; @@ -738,7 +757,6 @@ static int cros_ec_check_version(struct udevice *dev) { struct cros_ec_dev *cdev = dev_get_uclass_priv(dev); struct ec_params_hello req; - struct ec_response_hello *resp; struct dm_cros_ec_ops *ops; int ret; @@ -767,14 +785,14 @@ static int cros_ec_check_version(struct udevice *dev) /* Try sending a version 3 packet */ cdev->protocol_version = 3; req.in_data = 0; - if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), - (uint8_t **)&resp, sizeof(*resp)) > 0) + ret = cros_ec_hello(dev, NULL); + if (!ret || ret == -ENOTSYNC) return 0; /* Try sending a version 2 packet */ cdev->protocol_version = 2; - if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), - (uint8_t **)&resp, sizeof(*resp)) > 0) + ret = cros_ec_hello(dev, NULL); + if (!ret || ret == -ENOTSYNC) return 0; /* @@ -790,18 +808,16 @@ static int cros_ec_check_version(struct udevice *dev) int cros_ec_test(struct udevice *dev) { - struct ec_params_hello req; - struct ec_response_hello *resp; + uint out_data; + int ret; - req.in_data = 0x12345678; - if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), - (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) { + ret = cros_ec_hello(dev, &out_data); + if (ret == -ENOTSYNC) { + printf("Received invalid handshake %x\n", out_data); + return ret; + } else if (ret) { printf("ec_command_inptr() returned error\n"); - return -1; - } - if (resp->out_data != req.in_data + 0x01020304) { - printf("Received invalid handshake %x\n", resp->out_data); - return -1; + return ret; } return 0; diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 9fd6cc2086..1922a9c1b9 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /* @@ -73,6 +74,7 @@ struct ec_keymatrix_entry { * @matrix: Information about keyboard matrix * @keyscan: Current keyscan information (bit set for each row/column pressed) * @recovery_req: Keyboard recovery requested + * @test_flags: Flags that control behaviour for tests */ struct ec_state { u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2]; @@ -84,6 +86,7 @@ struct ec_state { struct ec_keymatrix_entry *matrix; /* the key matrix info */ uint8_t keyscan[KEYBOARD_COLS]; bool recovery_req; + uint test_flags; } s_state, *g_state; /** @@ -295,6 +298,8 @@ static int process_cmd(struct ec_state *ec, struct ec_response_hello *resp = resp_data; resp->out_data = req->in_data + 0x01020304; + if (ec->test_flags & CROSECT_BREAK_HELLO) + resp->out_data++; len = sizeof(*resp); break; } @@ -518,6 +523,13 @@ void cros_ec_check_keyboard(struct udevice *dev) } } +void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags) +{ + struct ec_state *ec = dev_get_priv(dev); + + ec->test_flags = flags; +} + int cros_ec_probe(struct udevice *dev) { struct ec_state *ec = dev_get_priv(dev); diff --git a/include/cros_ec.h b/include/cros_ec.h index f187bd0d4b..f57e0cc450 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -497,4 +497,15 @@ int cros_ec_get_lid_shutdown_mask(struct udevice *dev); */ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable); +/** + * cros_ec_hello() - Send a hello message + * + * Sends a message with a fixed input value and checks that the expected output + * value is received + * + * @dev: CROS-EC device + * @handshakep: If non-NULL, returns received handshake value on error + * @return 0 if OK, -ve on error + */ +int cros_ec_hello(struct udevice *dev, uint *handshakep); #endif diff --git a/test/dm/Makefile b/test/dm/Makefile index 46e076ed09..afcabfacc1 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_BLK) += blk.o obj-$(CONFIG_BUTTON) += button.o obj-$(CONFIG_DM_BOOTCOUNT) += bootcount.o obj-$(CONFIG_CLK) += clk.o clk_ccf.o +obj-$(CONFIG_CROS_EC) += cros_ec.o obj-$(CONFIG_DEVRES) += devres.o obj-$(CONFIG_VIDEO_MIPI_DSI) += dsi_host.o obj-$(CONFIG_DM_ETH) += eth.o diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c new file mode 100644 index 0000000000..823245ca70 --- /dev/null +++ b/test/dm/cros_ec.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright 2021 Google LLC + */ + +#include +#include +#include +#include +#include +#include + +static int dm_test_cros_ec_hello(struct unit_test_state *uts) +{ + struct udevice *dev; + uint val; + + ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev)); + + ut_assertok(cros_ec_hello(dev, NULL)); + + val = 0xdead1357; + ut_assertok(cros_ec_hello(dev, &val)); + ut_asserteq(0xdead1357, val); + + sandbox_cros_ec_set_test_flags(dev, CROSECT_BREAK_HELLO); + ut_asserteq(-ENOTSYNC, cros_ec_hello(dev, &val)); + ut_asserteq(0x12345678, val); + + return 0; +} +DM_TEST(dm_test_cros_ec_hello, UT_TESTF_SCAN_FDT); From 2525e53c2766a8731ebee9d13dd491a8ba0db2cb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:23 -0700 Subject: [PATCH 20/44] cros_ec: Tidy up a few delays Allow a longer time for the EC to reboot. Also use a constant for the hash delay time, so it is clear what it is for. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 013c67e046..ce5fa5bee3 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -44,6 +44,10 @@ enum { CROS_EC_CMD_TIMEOUT_MS = 5000, /* Timeout waiting for a synchronous hash to be recomputed */ CROS_EC_CMD_HASH_TIMEOUT_MS = 2000, + + /* Wait 10 ms between attempts to check if EC's hash is ready */ + CROS_EC_HASH_CHECK_DELAY_MS = 10, + }; #define INVALID_HCMD 0xFF @@ -502,9 +506,10 @@ static int cros_ec_wait_on_hash_done(struct udevice *dev, start = get_timer(0); while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) { - mdelay(50); /* Insert some reasonable delay */ + mdelay(CROS_EC_HASH_CHECK_DELAY_MS); p->cmd = EC_VBOOT_HASH_GET; + if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, p, sizeof(*p), hash, sizeof(*hash)) < 0) return -1; @@ -622,18 +627,23 @@ int cros_ec_reboot(struct udevice *dev, enum ec_reboot_cmd cmd, uint8_t flags) return -1; if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) { + ulong start; + /* * EC reboot will take place immediately so delay to allow it * to complete. Note that some reboot types (EC_REBOOT_COLD) * will reboot the AP as well, in which case we won't actually * get to this point. */ - /* - * TODO(rspangler@chromium.org): Would be nice if we had a - * better way to determine when the reboot is complete. Could - * we poll a memory-mapped LPC value? - */ - udelay(50000); + mdelay(50); + start = get_timer(0); + while (cros_ec_hello(dev, NULL)) { + if (get_timer(start) > 3000) { + log_err("EC did not return from reboot\n"); + return -ETIMEDOUT; + } + mdelay(5); + } } return 0; From 698e30f7a862ae6eb4754ef0d42b8dc8cf416edd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:24 -0700 Subject: [PATCH 21/44] cros_ec: Add run-time check for input buffer overflow This should not happen in normal operation, but the EC might have a bug, so add a run-time check just in case. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index ce5fa5bee3..e51ac87409 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -404,6 +404,8 @@ static int ec_command(struct udevice *dev, uint cmd, int cmd_version, */ if (din && in_buffer) { assert(len <= din_len); + if (len > din_len) + return -ENOSPC; memmove(din, in_buffer, len); } } From 7791df576c4e0bcb0529850e14173d028ec37275 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:25 -0700 Subject: [PATCH 22/44] cros_ec: Add support for reading the SKU ID This allows reading strapping pins attached to the EC. Add an implementation for this. Signed-off-by: Simon Glass --- cmd/cros_ec.c | 10 ++++++++++ drivers/misc/cros_ec.c | 13 +++++++++++++ drivers/misc/cros_ec_sandbox.c | 7 +++++++ include/cros_ec.h | 8 ++++++++ test/dm/cros_ec.c | 17 +++++++++++++++++ 5 files changed, 55 insertions(+) diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index ce1f59a740..4e85e184fe 100644 --- a/cmd/cros_ec.c +++ b/cmd/cros_ec.c @@ -352,6 +352,15 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, debug("%s: Could not access LDO%d\n", __func__, index); return ret; } + } else if (!strcmp("sku", cmd)) { + ret = cros_ec_get_sku_id(dev); + + if (ret >= 0) { + printf("%d\n", ret); + ret = 0; + } else { + printf("Error: %d\n", ret); + } } else { return CMD_RET_USAGE; } @@ -382,6 +391,7 @@ U_BOOT_CMD( "crosec write [] Write EC image\n" "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n" "crosec ldo [] Switch/Read LDO state\n" + "crosec sku Read board SKU ID\n" "crosec test run tests on cros_ec\n" "crosec version Read CROS-EC version" ); diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index e51ac87409..80709be2f1 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1105,6 +1105,19 @@ int cros_ec_flash_update_rw(struct udevice *dev, const uint8_t *image, return 0; } +int cros_ec_get_sku_id(struct udevice *dev) +{ + struct ec_sku_id_info *r; + int ret; + + ret = ec_command_inptr(dev, EC_CMD_GET_SKU_ID, 0, NULL, 0, + (uint8_t **)&r, sizeof(*r)); + if (ret != sizeof(*r)) + return -ret; + + return r->sku_id; +} + int cros_ec_read_nvdata(struct udevice *dev, uint8_t *block, int size) { struct ec_params_vbnvcontext p; diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 1922a9c1b9..9324384704 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -473,6 +473,13 @@ static int process_cmd(struct ec_state *ec, len = sizeof(*resp); break; } + case EC_CMD_GET_SKU_ID: { + struct ec_sku_id_info *resp = resp_data; + + resp->sku_id = 1234; + len = sizeof(*resp); + break; + } default: printf(" ** Unknown EC command %#02x\n", req_hdr->command); return -1; diff --git a/include/cros_ec.h b/include/cros_ec.h index f57e0cc450..1154cdc52b 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -329,6 +329,14 @@ int cros_ec_flash_write(struct udevice *dev, const uint8_t *data, int cros_ec_flash_offset(struct udevice *dev, enum ec_flash_region region, uint32_t *offset, uint32_t *size); +/** + * cros_ec_get_sku_id() - Read the SKU ID + * + * @dev: CROS-EC device + * return SKU ID, or -ve on error + */ +int cros_ec_get_sku_id(struct udevice *dev); + /** * Read/write non-volatile data from/to a CROS-EC device. * diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c index 823245ca70..3d0e5dc08d 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -30,3 +30,20 @@ static int dm_test_cros_ec_hello(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_cros_ec_hello, UT_TESTF_SCAN_FDT); + +static int dm_test_cros_ec_sku_id(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev)); + ut_asserteq(1234, cros_ec_get_sku_id(dev)); + + /* try the command */ + console_record_reset(); + ut_assertok(run_command("crosec sku", 0)); + ut_assert_nextline("1234"); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_cros_ec_sku_id, UT_TESTF_SCAN_FDT); From 8aec32f6abd722b141d96bc095999efa76bd0327 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:26 -0700 Subject: [PATCH 23/44] cros_ec: Support reading EC features The EC can support a variety of features and provides a way to find out what is available. Add support for this. Also update the feature list to the lastest available while we are here. This is at: https://chromium.googlesource.com/chromiumos/platform/ec/+/refs/heads/master/include/ec_commands.h Signed-off-by: Simon Glass --- cmd/cros_ec.c | 74 ++++++++++++++++++++++++++++++++++ drivers/misc/cros_ec.c | 26 +++++++++--- drivers/misc/cros_ec_sandbox.c | 11 +++++ include/cros_ec.h | 21 ++++++++++ include/ec_commands.h | 45 +++++++++++++++++++-- test/dm/cros_ec.c | 28 +++++++++++++ 6 files changed, 195 insertions(+), 10 deletions(-) diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index 4e85e184fe..77656a2308 100644 --- a/cmd/cros_ec.c +++ b/cmd/cros_ec.c @@ -94,6 +94,74 @@ static int do_read_write(struct udevice *dev, int is_write, int argc, return 0; } +static const char *const feat_name[64] = { + "limited", + "flash", + "pwm_fan", + "pwm_keyb", + "lightbar", + "led", + "motion_sense", + "keyb", + "pstore", + "port80", + "thermal", + "bklight_switch", + "wifi_switch", + "host_events", + "gpio", + "i2c", + "charger", + "battery", + "smart_battery", + "hang_detect", + "pmu", + "sub_mcu", + "usb_pd", + "usb_mux", + "motion_sense_fifo", + "vstore", + "usbc_ss_mux_virtual", + "rtc", + "fingerprint", + "touchpad", + "rwsig", + "device_event", + "unified_wake_masks", + "host_event64", + "exec_in_ram", + "cec", + "motion_sense_tight_timestamps", + "refined_tablet_mode_hysteresis", + "efs2", + "scp", + "ish", + "typec_cmd", + "typec_require_ap_mode_entry", + "typec_mux_require_ap_ack", +}; + +static int do_show_features(struct udevice *dev) +{ + u64 feat; + int ret; + uint i; + + ret = cros_ec_get_features(dev, &feat); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(feat_name); i++) { + if (feat & (1ULL << i)) { + if (feat_name[i]) + printf("%s\n", feat_name[i]); + else + printf("unknown %d\n", i); + } + } + + return 0; +} + static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -140,6 +208,11 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, } printf("rows = %u\n", info.rows); printf("cols = %u\n", info.cols); + } else if (!strcmp("features", cmd)) { + ret = do_show_features(dev); + + if (ret) + printf("Error: %d\n", ret); } else if (0 == strcmp("curimage", cmd)) { enum ec_current_image image; @@ -379,6 +452,7 @@ U_BOOT_CMD( "init Re-init CROS-EC (done on startup automatically)\n" "crosec id Read CROS-EC ID\n" "crosec info Read CROS-EC info\n" + "crosec features Read CROS-EC features\n" "crosec curimage Read CROS-EC current image\n" "crosec hash Read CROS-EC hash\n" "crosec reboot [rw | ro | cold] Reboot CROS-EC\n" diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 80709be2f1..fd2f2abd7e 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1344,19 +1344,33 @@ int cros_ec_i2c_tunnel(struct udevice *dev, int port, struct i2c_msg *in, return 0; } -int cros_ec_check_feature(struct udevice *dev, int feature) +int cros_ec_get_features(struct udevice *dev, u64 *featuresp) { struct ec_response_get_features r; int rv; - rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, &r, sizeof(r), NULL, 0); - if (rv) - return rv; + rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, NULL, 0, &r, sizeof(r)); + if (rv != sizeof(r)) + return -EIO; + *featuresp = r.flags[0] | (u64)r.flags[1] << 32; + + return 0; +} + +int cros_ec_check_feature(struct udevice *dev, uint feature) +{ + struct ec_response_get_features r; + int rv; + + rv = ec_command(dev, EC_CMD_GET_FEATURES, 0, NULL, 0, &r, sizeof(r)); + if (rv != sizeof(r)) + return -EIO; if (feature >= 8 * sizeof(r.flags)) - return -1; + return -EINVAL; - return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature); + return r.flags[feature / 32] & EC_FEATURE_MASK_0(feature) ? true : + false; } /* diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 9324384704..7213313c1a 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -480,6 +480,17 @@ static int process_cmd(struct ec_state *ec, len = sizeof(*resp); break; } + case EC_CMD_GET_FEATURES: { + struct ec_response_get_features *resp = resp_data; + + resp->flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FLASH) | + EC_FEATURE_MASK_0(EC_FEATURE_I2C); + resp->flags[1] = + EC_FEATURE_MASK_1(EC_FEATURE_UNIFIED_WAKE_MASKS) | + EC_FEATURE_MASK_1(EC_FEATURE_ISH); + len = sizeof(*resp); + break; + } default: printf(" ** Unknown EC command %#02x\n", req_hdr->command); return -1; diff --git a/include/cros_ec.h b/include/cros_ec.h index 1154cdc52b..338878c3be 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -516,4 +516,25 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable); * @return 0 if OK, -ve on error */ int cros_ec_hello(struct udevice *dev, uint *handshakep); + +/** + * cros_ec_get_features() - Get the set of features provided by the EC + * + * See enum ec_feature_code for the list of available features + * + * @dev: CROS-EC device + * @featuresp: Returns a bitmask of supported features + * @return 0 if OK, -ve on error + */ +int cros_ec_get_features(struct udevice *dev, u64 *featuresp); + +/** + * cros_ec_check_feature() - Check if a feature is supported + * + * @dev: CROS-EC device + * @feature: Feature number to check (enum ec_feature_code) + * @return true if supported, false if not, -ve on error + */ +int cros_ec_check_feature(struct udevice *dev, uint feature); + #endif diff --git a/include/ec_commands.h b/include/ec_commands.h index 444ba61e59..36f4a02f93 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -1101,13 +1101,50 @@ enum ec_feature_code { EC_FEATURE_DEVICE_EVENT = 31, /* EC supports the unified wake masks for LPC/eSPI systems */ EC_FEATURE_UNIFIED_WAKE_MASKS = 32, + /* EC supports 64-bit host events */ + EC_FEATURE_HOST_EVENT64 = 33, + /* EC runs code in RAM (not in place, a.k.a. XIP) */ + EC_FEATURE_EXEC_IN_RAM = 34, + /* EC supports CEC commands */ + EC_FEATURE_CEC = 35, + /* EC supports tight sensor timestamping. */ + EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36, + /* + * EC supports tablet mode detection aligned to Chrome and allows + * setting of threshold by host command using + * MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE. + */ + EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37, + /* + * Early Firmware Selection ver.2. Enabled by CONFIG_VBOOT_EFS2. + * Note this is a RO feature. So, a query (EC_CMD_GET_FEATURES) should + * be sent to RO to be precise. + */ + EC_FEATURE_EFS2 = 38, + /* The MCU is a System Companion Processor (SCP). */ + EC_FEATURE_SCP = 39, + /* The MCU is an Integrated Sensor Hub */ + EC_FEATURE_ISH = 40, + /* New TCPMv2 TYPEC_ prefaced commands supported */ + EC_FEATURE_TYPEC_CMD = 41, + /* + * The EC will wait for direction from the AP to enter Type-C alternate + * modes or USB4. + */ + EC_FEATURE_TYPEC_REQUIRE_AP_MODE_ENTRY = 42, + /* + * The EC will wait for an acknowledge from the AP after setting the + * mux. + */ + EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK = 43, }; -#define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32)) -#define EC_FEATURE_MASK_1(event_code) (1UL << (event_code - 32)) -struct __ec_align4 ec_response_get_features { +#define EC_FEATURE_MASK_0(event_code) BIT(event_code % 32) +#define EC_FEATURE_MASK_1(event_code) BIT(event_code - 32) + +struct ec_response_get_features { uint32_t flags[2]; -}; +} __ec_align4; /*****************************************************************************/ /* Get the board's SKU ID from EC */ diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c index 3d0e5dc08d..a1ec9fccf3 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -47,3 +47,31 @@ static int dm_test_cros_ec_sku_id(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_cros_ec_sku_id, UT_TESTF_SCAN_FDT); + +static int dm_test_cros_ec_features(struct unit_test_state *uts) +{ + struct udevice *dev; + u64 feat; + + ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev)); + ut_assertok(cros_ec_get_features(dev, &feat)); + ut_asserteq_64(1U << EC_FEATURE_FLASH | 1U << EC_FEATURE_I2C | + 1ULL << EC_FEATURE_UNIFIED_WAKE_MASKS | 1ULL << EC_FEATURE_ISH, + feat); + + ut_asserteq(true, cros_ec_check_feature(dev, EC_FEATURE_I2C)); + ut_asserteq(false, cros_ec_check_feature(dev, EC_FEATURE_MOTION_SENSE)); + ut_asserteq(true, cros_ec_check_feature(dev, EC_FEATURE_ISH)); + + /* try the command */ + console_record_reset(); + ut_assertok(run_command("crosec features", 0)); + ut_assert_nextline("flash"); + ut_assert_nextline("i2c"); + ut_assert_nextline("unified_wake_masks"); + ut_assert_nextline("ish"); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_cros_ec_features, UT_TESTF_SCAN_FDT); From 2b4b65339110e11b4a859fceeb1eec82b2ebb5f1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:27 -0700 Subject: [PATCH 24/44] cros_ec: Add documentation for cros_ec driver operations Add comments to these methods so it is documented in this central place, not just in each driver. Signed-off-by: Simon Glass --- include/cros_ec.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/cros_ec.h b/include/cros_ec.h index 338878c3be..26e3f3ba0c 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -234,10 +234,50 @@ int cros_ec_flash_update_rw(struct udevice *dev, const uint8_t *image, struct udevice *board_get_cros_ec_dev(void); struct dm_cros_ec_ops { + /** + * check_version() - Check the protocol version being used (optional) + * + * If provided, this function should check that the EC can be supported + * by the driver. If not provided, HELLO messages will be sent to try + * to determine the protocol version. + * + * @dev: Device to check + * @return 0 if the protocol is valid, -ve if not supported + */ int (*check_version)(struct udevice *dev); + + /** + * command() - Old-style command interface + * + * This sends a command and receives a response (deprecated, use + * packet()) + * + * @dev: Device to use + * @cmd: Command to send (only supports 0-0xff) + * @cmd_version: Version of command to send (often 0) + * @dout: Output data (may be NULL If dout_len=0) + * @dout_len: Length of output data excluding 4-byte header + * @dinp: On input, set to point to input data, often struct + * cros_ec_dev->din - typically this is left alone but may be + * updated by the driver + * @din_len: Maximum length of response + * @return number of bytes in response, or -ve on error + */ int (*command)(struct udevice *dev, uint8_t cmd, int cmd_version, const uint8_t *dout, int dout_len, uint8_t **dinp, int din_len); + + /** + * packet() - New-style command interface + * + * This interface is preferred over command(), since it is typically + * easier to implement. + * + * @dev: Device to use + * @out_bytes: Number of bytes to send (from struct cros_ec_dev->dout) + * @in_bytes: Maximum number of bytes to expect in response + * @return number of bytes in response, or -ve on error + */ int (*packet)(struct udevice *dev, int out_bytes, int in_bytes); }; From 3a6c994f3896d66e617acdf9bb58ffc4def08b71 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:28 -0700 Subject: [PATCH 25/44] cros_ec: Add support for switches On x86 platforms the EC provides a way to read 'switches', which are on/off values determined by the EC. Add a new driver method for this and implement it for LPC. Signed-off-by: Simon Glass --- arch/sandbox/include/asm/test.h | 1 + cmd/cros_ec.c | 41 +++++++++++++++++++++++++++++++++ drivers/misc/cros_ec.c | 16 +++++++++++++ drivers/misc/cros_ec_lpc.c | 7 ++++++ drivers/misc/cros_ec_sandbox.c | 10 ++++++++ include/cros_ec.h | 19 +++++++++++++++ test/dm/cros_ec.c | 26 +++++++++++++++++++++ 7 files changed, 120 insertions(+) diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 8363ca7319..1cb960ac24 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -61,6 +61,7 @@ enum { */ enum cros_ec_test_t { CROSECT_BREAK_HELLO = BIT(1), + CROSECT_LID_OPEN = BIT(2), }; /** diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index 77656a2308..a222c75c17 100644 --- a/cmd/cros_ec.c +++ b/cmd/cros_ec.c @@ -162,6 +162,41 @@ static int do_show_features(struct udevice *dev) return 0; } +static const char *const switch_name[8] = { + "lid open", + "power button pressed", + "write-protect disabled", + NULL, + "dedicated recovery", + NULL, + NULL, + NULL, +}; + +static int do_show_switches(struct udevice *dev) +{ + uint switches; + int ret; + uint i; + + ret = cros_ec_get_switches(dev); + if (ret < 0) + return log_msg_ret("get", ret); + switches = ret; + for (i = 0; i < ARRAY_SIZE(switch_name); i++) { + uint mask = 1 << i; + + if (switches & mask) { + if (switch_name[i]) + printf("%s\n", switch_name[i]); + else + printf("unknown %02x\n", mask); + } + } + + return 0; +} + static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -211,6 +246,11 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, } else if (!strcmp("features", cmd)) { ret = do_show_features(dev); + if (ret) + printf("Error: %d\n", ret); + } else if (!strcmp("switches", cmd)) { + ret = do_show_switches(dev); + if (ret) printf("Error: %d\n", ret); } else if (0 == strcmp("curimage", cmd)) { @@ -453,6 +493,7 @@ U_BOOT_CMD( "crosec id Read CROS-EC ID\n" "crosec info Read CROS-EC info\n" "crosec features Read CROS-EC features\n" + "crosec switches Read CROS-EC switches\n" "crosec curimage Read CROS-EC current image\n" "crosec hash Read CROS-EC hash\n" "crosec reboot [rw | ro | cold] Reboot CROS-EC\n" diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index fd2f2abd7e..0bc28e882c 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1557,6 +1557,22 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable) return 0; } +int cros_ec_get_switches(struct udevice *dev) +{ + struct dm_cros_ec_ops *ops; + int ret; + + ops = dm_cros_ec_get_ops(dev); + if (!ops->get_switches) + return -ENOSYS; + + ret = ops->get_switches(dev); + if (ret < 0) + return log_msg_ret("get", ret); + + return ret; +} + UCLASS_DRIVER(cros_ec) = { .id = UCLASS_CROS_EC, .name = "cros-ec", diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c index e0002b9753..f40375978d 100644 --- a/drivers/misc/cros_ec_lpc.c +++ b/drivers/misc/cros_ec_lpc.c @@ -207,6 +207,12 @@ int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob) return 0; } +/* Return the byte of EC switch states */ +static int cros_ec_lpc_get_switches(struct udevice *dev) +{ + return inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_SWITCHES); +} + /* * Test if LPC command args are supported. * @@ -239,6 +245,7 @@ static struct dm_cros_ec_ops cros_ec_ops = { .packet = cros_ec_lpc_packet, .command = cros_ec_lpc_command, .check_version = cros_ec_lpc_check_version, + .get_switches = cros_ec_lpc_get_switches, }; static const struct udevice_id cros_ec_ids[] = { diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 7213313c1a..38a2614a99 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -75,6 +75,7 @@ struct ec_keymatrix_entry { * @keyscan: Current keyscan information (bit set for each row/column pressed) * @recovery_req: Keyboard recovery requested * @test_flags: Flags that control behaviour for tests + * @switches: Current switches value (EC_SWITCH_) */ struct ec_state { u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2]; @@ -541,6 +542,14 @@ void cros_ec_check_keyboard(struct udevice *dev) } } +/* Return the byte of EC switch states */ +static int cros_ec_sandbox_get_switches(struct udevice *dev) +{ + struct ec_state *ec = dev_get_priv(dev); + + return ec->test_flags & CROSECT_LID_OPEN ? EC_SWITCH_LID_OPEN : 0; +} + void sandbox_cros_ec_set_test_flags(struct udevice *dev, uint flags) { struct ec_state *ec = dev_get_priv(dev); @@ -603,6 +612,7 @@ int cros_ec_probe(struct udevice *dev) struct dm_cros_ec_ops cros_ec_ops = { .packet = cros_ec_sandbox_packet, + .get_switches = cros_ec_sandbox_get_switches, }; static const struct udevice_id cros_ec_ids[] = { diff --git a/include/cros_ec.h b/include/cros_ec.h index 26e3f3ba0c..cb91343e3d 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -279,6 +279,16 @@ struct dm_cros_ec_ops { * @return number of bytes in response, or -ve on error */ int (*packet)(struct udevice *dev, int out_bytes, int in_bytes); + + /** + * get_switches() - Get value of EC switches + * + * This is currently supported on the LPC EC. + * + * @dev: Device to use + * @return current switches value, or -ENOSYS if not supported + */ + int (*get_switches)(struct udevice *dev); }; #define dm_cros_ec_get_ops(dev) \ @@ -577,4 +587,13 @@ int cros_ec_get_features(struct udevice *dev, u64 *featuresp); */ int cros_ec_check_feature(struct udevice *dev, uint feature); +/** + * cros_ec_get_switches() - Get switches value + * + * @dev: CROS-EC device + * @return switches value, or -ENOSYS if not supported, or other -ve value on + * other error + */ +int cros_ec_get_switches(struct udevice *dev); + #endif diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c index a1ec9fccf3..43774400a1 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -75,3 +75,29 @@ static int dm_test_cros_ec_features(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_cros_ec_features, UT_TESTF_SCAN_FDT); + +static int dm_test_cros_ec_switches(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev)); + ut_asserteq(0, cros_ec_get_switches(dev)); + + /* try the command */ + console_record_reset(); + ut_assertok(run_command("crosec switches", 0)); + ut_assert_console_end(); + + /* Open the lid and check the switch changes */ + sandbox_cros_ec_set_test_flags(dev, CROSECT_LID_OPEN); + ut_asserteq(EC_SWITCH_LID_OPEN, cros_ec_get_switches(dev)); + + /* try the command */ + console_record_reset(); + ut_assertok(run_command("crosec switches", 0)); + ut_assert_nextline("lid open"); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_cros_ec_switches, UT_TESTF_SCAN_FDT); From 3ae338299e1649ef9a38c45fcde864022c448a9e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:29 -0700 Subject: [PATCH 26/44] cros_ec: Show events in human-readable form Add a command to show the current events as a list of names. This is easier to decipher than a bit mask. Signed-off-by: Simon Glass --- cmd/cros_ec.c | 70 +++++++++++++++++++++++++++++++--- drivers/misc/cros_ec_sandbox.c | 12 +++++- test/dm/cros_ec.c | 37 ++++++++++++++++++ 3 files changed, 112 insertions(+), 7 deletions(-) diff --git a/cmd/cros_ec.c b/cmd/cros_ec.c index a222c75c17..eb5053d642 100644 --- a/cmd/cros_ec.c +++ b/cmd/cros_ec.c @@ -197,6 +197,66 @@ static int do_show_switches(struct udevice *dev) return 0; } +static const char *const event_name[] = { + "lid_closed", + "lid_open", + "power_button", + "ac_connected", + "ac_disconnected", + "battery_low", + "battery_critical", + "battery", + "thermal_threshold", + "device", + "thermal", + "usb_charger", + "key_pressed", + "interface_ready", + "keyboard_recovery", + "thermal_shutdown", + "battery_shutdown", + "throttle_start", + "throttle_stop", + "hang_detect", + "hang_reboot", + "pd_mcu", + "battery_status", + "panic", + "keyboard_fastboot", + "rtc", + "mkbp", + "usb_mux", + "mode_change", + "keyboard_recovery_hw_reinit", + "extended", + "invalid", +}; + +static int do_show_events(struct udevice *dev) +{ + u32 events; + int ret; + uint i; + + ret = cros_ec_get_host_events(dev, &events); + if (ret) + return ret; + printf("%08x\n", events); + for (i = 0; i < ARRAY_SIZE(event_name); i++) { + enum host_event_code code = i + 1; + u64 mask = EC_HOST_EVENT_MASK(code); + + if (events & mask) { + if (event_name[i]) + printf("%s\n", event_name[i]); + else + printf("unknown code %#x\n", code); + } + } + + return 0; +} + static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -303,13 +363,10 @@ static int do_cros_ec(struct cmd_tbl *cmdtp, int flag, int argc, return 1; } } else if (0 == strcmp("events", cmd)) { - uint32_t events; + ret = do_show_events(dev); - if (cros_ec_get_host_events(dev, &events)) { - debug("%s: Could not read host events\n", __func__); - return 1; - } - printf("0x%08x\n", events); + if (ret) + printf("Error: %d\n", ret); } else if (0 == strcmp("clrevents", cmd)) { uint32_t events = 0x7fffffff; @@ -498,6 +555,7 @@ U_BOOT_CMD( "crosec hash Read CROS-EC hash\n" "crosec reboot [rw | ro | cold] Reboot CROS-EC\n" "crosec events Read CROS-EC host events\n" + "crosec eventsb Read CROS-EC host events_b\n" "crosec clrevents [mask] Clear CROS-EC host events\n" "crosec regioninfo Read image info\n" "crosec flashinfo Read flash info\n" diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 38a2614a99..845876cfb0 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -364,10 +364,20 @@ static int process_cmd(struct ec_state *ec, resp->mask |= EC_HOST_EVENT_MASK( EC_HOST_EVENT_KEYBOARD_RECOVERY); } - + if (ec->test_flags & CROSECT_LID_OPEN) + resp->mask |= + EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN); len = sizeof(*resp); break; } + case EC_CMD_HOST_EVENT_CLEAR_B: { + const struct ec_params_host_event_mask *req = req_data; + + if (req->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN)) + ec->test_flags &= ~CROSECT_LID_OPEN; + len = 0; + break; + } case EC_CMD_VBOOT_HASH: { const struct ec_params_vboot_hash *req = req_data; struct ec_response_vboot_hash *resp = resp_data; diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c index 43774400a1..0da7548fd2 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -101,3 +101,40 @@ static int dm_test_cros_ec_switches(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_cros_ec_switches, UT_TESTF_SCAN_FDT); + +static int dm_test_cros_ec_events(struct unit_test_state *uts) +{ + struct udevice *dev; + u32 events; + + ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev)); + ut_assertok(cros_ec_get_host_events(dev, &events)); + ut_asserteq(0, events); + + /* try the command */ + console_record_reset(); + ut_assertok(run_command("crosec events", 0)); + ut_assert_nextline("00000000"); + ut_assert_console_end(); + + /* Open the lid and check the event appears */ + sandbox_cros_ec_set_test_flags(dev, CROSECT_LID_OPEN); + ut_assertok(cros_ec_get_host_events(dev, &events)); + ut_asserteq(EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN), events); + + /* try the command */ + console_record_reset(); + ut_assertok(run_command("crosec events", 0)); + ut_assert_nextline("00000002"); + ut_assert_nextline("lid_open"); + ut_assert_console_end(); + + /* Clear the event */ + ut_assertok(cros_ec_clear_host_events(dev, + EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN))); + ut_assertok(cros_ec_get_host_events(dev, &events)); + ut_asserteq(0, events); + + return 0; +} +DM_TEST(dm_test_cros_ec_events, UT_TESTF_SCAN_FDT); From d9ffaef6fe25e7a29e63911fe1af5d18c9d77a45 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:30 -0700 Subject: [PATCH 27/44] cros_ec: Allow use with of-platdata Avoid reading the device tree when of-platdata is in use. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 0bc28e882c..c22bb4b5b5 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1577,6 +1577,8 @@ UCLASS_DRIVER(cros_ec) = { .id = UCLASS_CROS_EC, .name = "cros-ec", .per_device_auto = sizeof(struct cros_ec_dev), +#if !CONFIG_IS_ENABLED(OF_PLATDATA) .post_bind = dm_scan_fdt_dev, +#endif .flags = DM_UC_FLAG_ALLOC_PRIV_DMA, }; From 10f746591fba16a48f0e3d14641be09f01982807 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 16 Jan 2021 14:52:31 -0700 Subject: [PATCH 28/44] cros_ec: Add vstore support The EC can store small amounts of data for the benefit of the verified boot process. Since the EC is seldom reset, this can allow the AP to store data that survives a reboot or a suspend/resume cycle. Add support for this. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 71 ++++++++++++++++++++++++++++++++++ drivers/misc/cros_ec_sandbox.c | 52 ++++++++++++++++++++++++- include/cros_ec.h | 43 ++++++++++++++++++++ test/dm/cros_ec.c | 38 ++++++++++++++++++ 4 files changed, 202 insertions(+), 2 deletions(-) diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index c22bb4b5b5..ebfa7c41c2 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1557,6 +1557,77 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable) return 0; } +int cros_ec_vstore_supported(struct udevice *dev) +{ + return cros_ec_check_feature(dev, EC_FEATURE_VSTORE); +} + +int cros_ec_vstore_info(struct udevice *dev, u32 *lockedp) +{ + struct ec_response_vstore_info *resp; + + if (ec_command_inptr(dev, EC_CMD_VSTORE_INFO, 0, NULL, 0, + (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp)) + return -EIO; + + if (lockedp) + *lockedp = resp->slot_locked; + + return resp->slot_count; +} + +/* + * cros_ec_vstore_read - Read data from EC vstore slot + * + * @slot: vstore slot to read from + * @data: buffer to store read data, must be EC_VSTORE_SLOT_SIZE bytes + */ +int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data) +{ + struct ec_params_vstore_read req; + struct ec_response_vstore_read *resp; + + req.slot = slot; + if (ec_command_inptr(dev, EC_CMD_VSTORE_READ, 0, &req, sizeof(req), + (uint8_t **)&resp, sizeof(*resp)) != sizeof(*resp)) + return -EIO; + + if (!data || req.slot >= EC_VSTORE_SLOT_MAX) + return -EINVAL; + + memcpy(data, resp->data, sizeof(resp->data)); + + return 0; +} + +/* + * cros_ec_vstore_write - Save data into EC vstore slot + * + * @slot: vstore slot to write into + * @data: data to write + * @size: size of data in bytes + * + * Maximum size of data is EC_VSTORE_SLOT_SIZE. It is the callers + * responsibility to check the number of implemented slots by + * querying the vstore info. + */ +int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data, + size_t size) +{ + struct ec_params_vstore_write req; + + if (slot >= EC_VSTORE_SLOT_MAX || size > EC_VSTORE_SLOT_SIZE) + return -EINVAL; + + req.slot = slot; + memcpy(req.data, data, size); + + if (ec_command(dev, EC_CMD_VSTORE_WRITE, 0, &req, sizeof(req), NULL, 0)) + return -EIO; + + return 0; +} + int cros_ec_get_switches(struct udevice *dev) { struct dm_cros_ec_ops *ops; diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index 845876cfb0..cb8adc4495 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -62,6 +62,15 @@ struct ec_keymatrix_entry { int keycode; /* corresponding linux key code */ }; +enum { + VSTORE_SLOT_COUNT = 4, +}; + +struct vstore_slot { + bool locked; + u8 data[EC_VSTORE_SLOT_SIZE]; +}; + /** * struct ec_state - Information about the EC state * @@ -75,7 +84,7 @@ struct ec_keymatrix_entry { * @keyscan: Current keyscan information (bit set for each row/column pressed) * @recovery_req: Keyboard recovery requested * @test_flags: Flags that control behaviour for tests - * @switches: Current switches value (EC_SWITCH_) + * @slot_locked: Locked vstore slots (mask) */ struct ec_state { u8 vbnv_context[EC_VBNV_BLOCK_SIZE_V2]; @@ -88,6 +97,7 @@ struct ec_state { uint8_t keyscan[KEYBOARD_COLS]; bool recovery_req; uint test_flags; + struct vstore_slot slot[VSTORE_SLOT_COUNT]; } s_state, *g_state; /** @@ -495,13 +505,51 @@ static int process_cmd(struct ec_state *ec, struct ec_response_get_features *resp = resp_data; resp->flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FLASH) | - EC_FEATURE_MASK_0(EC_FEATURE_I2C); + EC_FEATURE_MASK_0(EC_FEATURE_I2C) | + EC_FEATURE_MASK_0(EC_FEATURE_VSTORE); resp->flags[1] = EC_FEATURE_MASK_1(EC_FEATURE_UNIFIED_WAKE_MASKS) | EC_FEATURE_MASK_1(EC_FEATURE_ISH); len = sizeof(*resp); break; } + case EC_CMD_VSTORE_INFO: { + struct ec_response_vstore_info *resp = resp_data; + int i; + + resp->slot_count = VSTORE_SLOT_COUNT; + resp->slot_locked = 0; + for (i = 0; i < VSTORE_SLOT_COUNT; i++) { + if (ec->slot[i].locked) + resp->slot_locked |= 1 << i; + } + len = sizeof(*resp); + break; + }; + case EC_CMD_VSTORE_WRITE: { + const struct ec_params_vstore_write *req = req_data; + struct vstore_slot *slot; + + if (req->slot >= EC_VSTORE_SLOT_MAX) + return -EINVAL; + slot = &ec->slot[req->slot]; + slot->locked = true; + memcpy(slot->data, req->data, EC_VSTORE_SLOT_SIZE); + len = 0; + break; + } + case EC_CMD_VSTORE_READ: { + const struct ec_params_vstore_read *req = req_data; + struct ec_response_vstore_read *resp = resp_data; + struct vstore_slot *slot; + + if (req->slot >= EC_VSTORE_SLOT_MAX) + return -EINVAL; + slot = &ec->slot[req->slot]; + memcpy(resp->data, slot->data, EC_VSTORE_SLOT_SIZE); + len = sizeof(*resp); + break; + } default: printf(" ** Unknown EC command %#02x\n", req_hdr->command); return -1; diff --git a/include/cros_ec.h b/include/cros_ec.h index cb91343e3d..eddc23d48f 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -596,4 +596,47 @@ int cros_ec_check_feature(struct udevice *dev, uint feature); */ int cros_ec_get_switches(struct udevice *dev); +/** + * cros_ec_vstore_supported() - Check if vstore is supported + * + * @dev: CROS-EC device + * @return false if not supported, true if supported, -ve on error + */ +int cros_ec_vstore_supported(struct udevice *dev); + +/** + * cros_ec_vstore_info() - Get vstore information + * + * @dev: CROS-EC device + * @lockedp: mask of locked slots + * @return number of vstore slots supported by the EC,, -ve on error + */ +int cros_ec_vstore_info(struct udevice *dev, u32 *lockedp); + +/** + * cros_ec_vstore_read() - Read data from EC vstore slot + * + * @dev: CROS-EC device + * @slot: vstore slot to read from + * @data: buffer to store read data, must be EC_VSTORE_SLOT_SIZE bytes + * @return 0 if OK, -ve on error + */ +int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data); + +/** + * cros_ec_vstore_write() - Save data into EC vstore slot + * + * The maximum size of data is EC_VSTORE_SLOT_SIZE. It is the caller's + * responsibility to check the number of implemented slots by querying the + * vstore info. + * + * @dev: CROS-EC device + * @slot: vstore slot to write into + * @data: data to write + * @size: size of data in bytes + * @return 0 if OK, -ve on error + */ +int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data, + size_t size); + #endif diff --git a/test/dm/cros_ec.c b/test/dm/cros_ec.c index 0da7548fd2..30cb70e088 100644 --- a/test/dm/cros_ec.c +++ b/test/dm/cros_ec.c @@ -56,6 +56,7 @@ static int dm_test_cros_ec_features(struct unit_test_state *uts) ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev)); ut_assertok(cros_ec_get_features(dev, &feat)); ut_asserteq_64(1U << EC_FEATURE_FLASH | 1U << EC_FEATURE_I2C | + 1u << EC_FEATURE_VSTORE | 1ULL << EC_FEATURE_UNIFIED_WAKE_MASKS | 1ULL << EC_FEATURE_ISH, feat); @@ -68,6 +69,7 @@ static int dm_test_cros_ec_features(struct unit_test_state *uts) ut_assertok(run_command("crosec features", 0)); ut_assert_nextline("flash"); ut_assert_nextline("i2c"); + ut_assert_nextline("vstore"); ut_assert_nextline("unified_wake_masks"); ut_assert_nextline("ish"); ut_assert_console_end(); @@ -138,3 +140,39 @@ static int dm_test_cros_ec_events(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_cros_ec_events, UT_TESTF_SCAN_FDT); + +static int dm_test_cros_ec_vstore(struct unit_test_state *uts) +{ + const int size = EC_VSTORE_SLOT_SIZE; + u8 test_data[size], data[size]; + struct udevice *dev; + u32 locked; + int i; + + ut_assertok(uclass_first_device_err(UCLASS_CROS_EC, &dev)); + ut_asserteq(true, cros_ec_vstore_supported(dev)); + + ut_asserteq(4, cros_ec_vstore_info(dev, &locked)); + ut_asserteq(0, locked); + + /* Write some data */ + for (i = 0; i < size; i++) + test_data[i] = ' ' + i; + ut_assertok(cros_ec_vstore_write(dev, 2, test_data, size)); + + /* Check it is locked */ + ut_asserteq(4, cros_ec_vstore_info(dev, &locked)); + ut_asserteq(1 << 2, locked); + + /* Read it back and compare */ + ut_assertok(cros_ec_vstore_read(dev, 2, data)); + ut_asserteq_mem(test_data, data, size); + + /* Try another slot to make sure it is empty */ + ut_assertok(cros_ec_vstore_read(dev, 0, data)); + for (i = 0; i < size; i++) + ut_asserteq(0, data[i]); + + return 0; +} +DM_TEST(dm_test_cros_ec_vstore, UT_TESTF_SCAN_FDT); From 1426174f3fb0727321531504afbde110ef716573 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:06 -0700 Subject: [PATCH 29/44] spl: Tidy up SPL/TPL malloc sizes The current help talks about relocation which doesn't apply to SPL and TPL. Update it to avoid confusion. Also make the TPL size default to the same as the SPL size, since this is more likely to be a useful value than the one used by U-Boot proper, which may be quite a bit larger. Signed-off-by: Simon Glass --- Kconfig | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Kconfig b/Kconfig index 6dc20ed25b..86f0a39bb0 100644 --- a/Kconfig +++ b/Kconfig @@ -217,22 +217,25 @@ config SYS_MALLOC_LEN TODO: Use for other architectures config SPL_SYS_MALLOC_F_LEN - hex "Size of malloc() pool in SPL before relocation" + hex "Size of malloc() pool in SPL" depends on SYS_MALLOC_F && SPL default 0x2800 if RCAR_GEN3 default SYS_MALLOC_F_LEN help - Before relocation, memory is very limited on many platforms. Still, + In SPL memory is very limited on many platforms. Still, we can provide a small malloc() pool if needed. Driver model in particular needs this to operate, so that it can allocate the initial serial device and any others that are needed. + It is possible to enable CONFIG_SYS_SPL_MALLOC_START to start a new + malloc() region in SDRAM once it is inited. + config TPL_SYS_MALLOC_F_LEN - hex "Size of malloc() pool in TPL before relocation" + hex "Size of malloc() pool in TPL" depends on SYS_MALLOC_F && TPL - default SYS_MALLOC_F_LEN + default SPL_SYS_MALLOC_F_LEN help - Before relocation, memory is very limited on many platforms. Still, + In TPL memory is very limited on many platforms. Still, we can provide a small malloc() pool if needed. Driver model in particular needs this to operate, so that it can allocate the initial serial device and any others that are needed. From 442e6305b5b02d689774a0bf73311643ffa0df6f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:07 -0700 Subject: [PATCH 30/44] x86: coral: Support TPM and RTC in SPL Update the devicetree so that the TPM and RTC can be used in SPL. Also enable the pins used for getting the memory configuration settings while we are here. Signed-off-by: Simon Glass --- arch/x86/dts/chromebook_coral.dts | 20 +++++++++++++++++++- arch/x86/include/asm/arch-apollolake/iomap.h | 3 +++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/x86/dts/chromebook_coral.dts b/arch/x86/dts/chromebook_coral.dts index 965f59276a..9319123c0c 100644 --- a/arch/x86/dts/chromebook_coral.dts +++ b/arch/x86/dts/chromebook_coral.dts @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /dts-v1/; +#include #include /include/ "skeleton.dtsi" @@ -99,6 +100,7 @@ clk: clock { compatible = "intel,apl-clk"; #clock-cells = <1>; + u-boot,dm-pre-reloc; }; cpus { @@ -139,6 +141,7 @@ }; acpi_gpe: general-purpose-events { + u-boot,dm-pre-reloc; reg = ; compatible = "intel,acpi-gpe"; interrupt-controller; @@ -417,8 +420,10 @@ }; i2c_2: i2c2@16,2 { - compatible = "intel,apl-i2c"; + compatible = "intel,apl-i2c", "snps,designware-i2c-pci"; reg = <0x0200b210 0 0 0 0>; + early-regs = ; + u-boot,dm-pre-reloc; #address-cells = <1>; #size-cells = <0>; clock-frequency = <400000>; @@ -429,6 +434,7 @@ tpm: tpm@50 { reg = <0x50>; compatible = "google,cr50"; + u-boot,dm-pre-reloc; u-boot,i2c-offset-len = <0>; ready-gpios = <&gpio_n 28 GPIO_ACTIVE_LOW>; interrupts-extended = <&acpi_gpe GPIO_28_IRQ @@ -583,6 +589,7 @@ u-boot,dm-pre-reloc; cros_ec: cros-ec { u-boot,dm-pre-proper; + u-boot,dm-vpl; compatible = "google,cros-ec-lpc"; reg = <0x204 1 0x200 1 0x880 0x80>; @@ -658,6 +665,11 @@ PAD_CFG_NF(LPC_AD3, UP_20K, DEEP, NF1) /* LPC_AD3 */ PAD_CFG_NF(LPC_CLKRUNB, UP_20K, DEEP, NF1) /* LPC_CLKRUN_N */ PAD_CFG_NF(LPC_FRAMEB, NATIVE, DEEP, NF1) /* LPC_FRAME_N */ + + PAD_CFG_GPI(GPIO_101, NONE, DEEP) /* FST_IO2 -- MEM_CONFIG0 */ + PAD_CFG_GPI(GPIO_102, NONE, DEEP) /* FST_IO3 -- MEM_CONFIG1 */ + PAD_CFG_GPI(GPIO_38, NONE, DEEP) /* LPSS_UART0_RXD - MEM_CONFIG2*/ + PAD_CFG_GPI(GPIO_45, NONE, DEEP) /* LPSS_UART1_CTS - MEM_CONFIG3 */ >; }; @@ -1211,3 +1223,9 @@ PAD_CFG_GPI(GPIO_73, UP_20K, DEEP) /* GP_CAMERASB11 */ >; }; + +&rtc { + #address-cells = <1>; + #size-cells = <0>; + u-boot,dm-pre-reloc; +}; diff --git a/arch/x86/include/asm/arch-apollolake/iomap.h b/arch/x86/include/asm/arch-apollolake/iomap.h index 21c5f33021..a4ea150707 100644 --- a/arch/x86/include/asm/arch-apollolake/iomap.h +++ b/arch/x86/include/asm/arch-apollolake/iomap.h @@ -33,6 +33,9 @@ #define SRAM_SIZE_2 (4 * KiB) #endif +/* Early address for I2C port 2 */ +#define IOMAP_I2C2_BASE (0xfe020000 + 2 * 0x1000) + /* * Use UART2. To use UART1 you need to set '2' to '1', change device tree serial * node name and 'reg' property, and update CONFIG_DEBUG_UART_BASE. From dfb5bfbc208699ae1b5fc8e17f65d862be3b4612 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:08 -0700 Subject: [PATCH 31/44] i2c: desigware: Add an alias for Intel Apollo Lake Add an alias so that this driver can be used in TPL on coral. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- drivers/i2c/designware_i2c_pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/i2c/designware_i2c_pci.c b/drivers/i2c/designware_i2c_pci.c index ec0cdf6220..9e387737b6 100644 --- a/drivers/i2c/designware_i2c_pci.c +++ b/drivers/i2c/designware_i2c_pci.c @@ -192,6 +192,8 @@ static const struct udevice_id designware_i2c_pci_ids[] = { { } }; +DM_DRIVER_ALIAS(i2c_designware_pci, intel_apl_i2c) + U_BOOT_DRIVER(i2c_designware_pci) = { .name = "i2c_designware_pci", .id = UCLASS_I2C, From d85f2c4f2970d0ec2f5f075de734afd11200d153 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:09 -0700 Subject: [PATCH 32/44] sandbox: Disable I2C emulators in SPL These cannot work with of-platdata since they currently need the devicetree at runtime. Disable the emulators and the sandbox I2C driver that needs them. We can enable these later, if needed for testing. Switch the of_plat_parent test over to use a simple bus instead. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- arch/sandbox/dts/sandbox.dtsi | 10 +++++++--- configs/sandbox_spl_defconfig | 1 - drivers/i2c/Makefile | 2 ++ test/dm/of_platdata.c | 8 ++++---- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index d842f02176..dc933f3bfc 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -260,10 +260,14 @@ stringarray = "pre-proper"; }; - spl-test7 { + test-bus { + compatible = "simple-bus"; u-boot,dm-spl; - compatible = "sandbox,spl-test"; - stringarray = "spl"; + spl-test7 { + u-boot,dm-spl; + compatible = "sandbox,spl-test"; + stringarray = "spl"; + }; }; square { diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index d193b18f47..61dae34a6a 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -101,7 +101,6 @@ CONFIG_SYSCON=y CONFIG_SPL_SYSCON=y CONFIG_DEVRES=y CONFIG_DEBUG_DEVRES=y -# CONFIG_SPL_SIMPLE_BUS is not set CONFIG_ADC=y CONFIG_ADC_SANDBOX=y CONFIG_AXI=y diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 1aac5c481e..29aab0f9e3 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -39,7 +39,9 @@ obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o +ifndef CONFIG_SPL_BUILD obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o +endif obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c index cfc43a5b03..26c50922c5 100644 --- a/test/dm/of_platdata.c +++ b/test/dm/of_platdata.c @@ -210,11 +210,11 @@ DM_TEST(dm_test_of_plat_phandle, UT_TESTF_SCAN_PDATA); /* Test that device parents are correctly set up */ static int dm_test_of_plat_parent(struct unit_test_state *uts) { - struct udevice *rtc, *i2c; + struct udevice *dev, *bus; - ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc)); - ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c)); - ut_asserteq_ptr(i2c, dev_get_parent(rtc)); + ut_assertok(uclass_first_device_err(UCLASS_SIMPLE_BUS, &bus)); + ut_assertok(device_first_child_err(bus, &dev)); + ut_asserteq_ptr(bus, dev_get_parent(dev)); return 0; } From ef79ef21a85272f52be58089a96bc1299aa04458 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:10 -0700 Subject: [PATCH 33/44] dm: core: Don't inline dev_read...() calls with of-platdata At present if these calls are used with of-platdata, a confusing error is produced, referring to a function not actually called by the code causing the problem. Fix this by not inlining, so that the error mentions the dev_read_...() function and it is more obvious what is going on. Signed-off-by: Simon Glass --- include/dm/read.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/dm/read.h b/include/dm/read.h index c875e11a13..f6f8b875d1 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -30,8 +30,7 @@ static inline const struct device_node *dev_np(const struct udevice *dev) } #endif -#ifndef CONFIG_DM_DEV_READ_INLINE - +#if !defined(CONFIG_DM_DEV_READ_INLINE) || CONFIG_IS_ENABLED(OF_PLATDATA) /** * dev_read_u32() - read a 32-bit integer from a device's DT property * From 5c5992cb90cf9ca4d51e38d9a95a13c293904df5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:11 -0700 Subject: [PATCH 34/44] clk: Add debugging for return values Use the log_msg_ret() mechanism to get error-return information when clocks fail to probe, etc. Signed-off-by: Simon Glass --- drivers/clk/clk-uclass.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c index b75056718b..d5c4e3cbe5 100644 --- a/drivers/clk/clk-uclass.c +++ b/drivers/clk/clk-uclass.c @@ -83,7 +83,7 @@ static int clk_get_by_index_tail(int ret, ofnode node, if (ret) { debug("%s: uclass_get_device_by_of_offset failed: err=%d\n", __func__, ret); - return ret; + return log_msg_ret("get", ret); } clk->dev = dev_clk; @@ -96,14 +96,15 @@ static int clk_get_by_index_tail(int ret, ofnode node, ret = clk_of_xlate_default(clk, args); if (ret) { debug("of_xlate() failed: %d\n", ret); - return ret; + return log_msg_ret("xlate", ret); } return clk_request(dev_clk, clk); err: debug("%s: Node '%s', property '%s', failed to request CLK index %d: %d\n", __func__, ofnode_get_name(node), list_name, index, ret); - return ret; + + return log_msg_ret("prop", ret); } static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name, @@ -122,7 +123,7 @@ static int clk_get_by_indexed_prop(struct udevice *dev, const char *prop_name, if (ret) { debug("%s: fdtdec_parse_phandle_with_args failed: err=%d\n", __func__, ret); - return ret; + return log_ret(ret); } @@ -470,6 +471,7 @@ int clk_free(struct clk *clk) ulong clk_get_rate(struct clk *clk) { const struct clk_ops *ops; + int ret; debug("%s(clk=%p)\n", __func__, clk); if (!clk_valid(clk)) @@ -479,7 +481,11 @@ ulong clk_get_rate(struct clk *clk) if (!ops->get_rate) return -ENOSYS; - return ops->get_rate(clk); + ret = ops->get_rate(clk); + if (ret) + return log_ret(ret); + + return 0; } struct clk *clk_get_parent(struct clk *clk) From 0dc2bf2b6e6e7581e3307f3aa65d0ce310375511 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:12 -0700 Subject: [PATCH 35/44] clk: x86: Correct the driver name The current driver name does not match its compatible string, so of-platdata does not work correctly. Fix it. Signed-off-by: Simon Glass --- drivers/clk/intel/clk_intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/intel/clk_intel.c b/drivers/clk/intel/clk_intel.c index b633934d90..46ccbb1d83 100644 --- a/drivers/clk/intel/clk_intel.c +++ b/drivers/clk/intel/clk_intel.c @@ -29,8 +29,8 @@ static const struct udevice_id intel_clk_ids[] = { { } }; -U_BOOT_DRIVER(clk_intel) = { - .name = "clk_intel", +U_BOOT_DRIVER(intel_apl_clk) = { + .name = "intel_apl_clk", .id = UCLASS_CLK, .of_match = intel_clk_ids, .ops = &intel_clk_ops, From 017d421828971f6adbfa6a1305b80da7d620c596 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:13 -0700 Subject: [PATCH 36/44] dm: core: Add a comment about pinctrl_select_state() The use of pinctrl in the core of driver model is useful but can provoke some strange behaviour. Add a comment to aid debugging. Signed-off-by: Simon Glass --- drivers/core/device.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/core/device.c b/drivers/core/device.c index aeab3836ed..8629df8def 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -462,6 +462,15 @@ int device_probe(struct udevice *dev) * continue regardless of the result of pinctrl. Don't process pinctrl * settings for pinctrl devices since the device may not yet be * probed. + * + * This call can produce some non-intuitive results. For example, on an + * x86 device where dev is the main PCI bus, the pinctrl device may be + * child or grandchild of that bus, meaning that the child will be + * probed here. If the child happens to be the P2SB and the pinctrl + * device is a child of that, then both the pinctrl and P2SB will be + * probed by this call. This works because the DM_FLAG_ACTIVATED flag + * is set just above. However, the PCI bus' probe() method and + * associated uclass methods have not yet been called. */ if (dev->parent && device_get_uclass_id(dev) != UCLASS_PINCTRL) pinctrl_select_state(dev, "default"); From ff5fa7d62655ae6c1873e17057c057566c81df0d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:14 -0700 Subject: [PATCH 37/44] dm: core: Update ofnode_read_fmap_entry() to read hashes At present this function uses the old format for reading hashes. Add support for the current format. Add a test while we are here. Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 10 ++++++++++ drivers/core/of_extra.c | 21 ++++++++++++--------- test/dm/Makefile | 1 + test/dm/of_extra.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 test/dm/of_extra.c diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index f86cd0d3b2..e95f4631bf 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -90,6 +90,16 @@ wp-ro { image-pos = <0xf000>; size = <0x1000>; + used = <0x884>; + compress = "lz4"; + uncomp-size = <0xcf8>; + hash { + algo = "sha256"; + value = [00 01 02 03 04 05 06 07 + 08 09 0a 0b 0c 0d 0e 0f + 10 11 12 13 14 15 16 17 + 18 19 1a 1b 1c 1d 1e 1f]; + }; }; rw { image-pos = <0x10000>; diff --git a/drivers/core/of_extra.c b/drivers/core/of_extra.c index 6420e6ec44..653344529e 100644 --- a/drivers/core/of_extra.c +++ b/drivers/core/of_extra.c @@ -14,16 +14,17 @@ int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry) { const char *prop; + ofnode subnode; if (ofnode_read_u32(node, "image-pos", &entry->offset)) { debug("Node '%s' has bad/missing 'image-pos' property\n", ofnode_get_name(node)); - return log_ret(-ENOENT); + return log_msg_ret("image-pos", -ENOENT); } if (ofnode_read_u32(node, "size", &entry->length)) { debug("Node '%s' has bad/missing 'size' property\n", ofnode_get_name(node)); - return log_ret(-ENOENT); + return log_msg_ret("size", -ENOENT); } entry->used = ofnode_read_s32_default(node, "used", entry->length); prop = ofnode_read_string(node, "compress"); @@ -31,18 +32,20 @@ int ofnode_read_fmap_entry(ofnode node, struct fmap_entry *entry) if (!strcmp(prop, "lz4")) entry->compress_algo = FMAP_COMPRESS_LZ4; else - return log_msg_ret("Unknown compression algo", - -EINVAL); + return log_msg_ret("compression algo", -EINVAL); } else { entry->compress_algo = FMAP_COMPRESS_NONE; } entry->unc_length = ofnode_read_s32_default(node, "uncomp-size", entry->length); - prop = ofnode_read_string(node, "hash"); - if (prop) - entry->hash_size = strlen(prop); - entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE; - entry->hash = (uint8_t *)prop; + subnode = ofnode_find_subnode(node, "hash"); + if (ofnode_valid(subnode)) { + prop = ofnode_read_prop(subnode, "value", &entry->hash_size); + + /* Assume it is sha256 */ + entry->hash_algo = prop ? FMAP_HASH_SHA256 : FMAP_HASH_NONE; + entry->hash = (uint8_t *)prop; + } return 0; } diff --git a/test/dm/Makefile b/test/dm/Makefile index afcabfacc1..e70e50f402 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -42,6 +42,7 @@ obj-y += fdtdec.o obj-$(CONFIG_UT_DM) += nop.o obj-y += ofnode.o obj-y += ofread.o +obj-y += of_extra.o obj-$(CONFIG_OSD) += osd.o obj-$(CONFIG_DM_VIDEO) += panel.o obj-$(CONFIG_DM_PCI) += pci.o diff --git a/test/dm/of_extra.c b/test/dm/of_extra.c new file mode 100644 index 0000000000..b19cd3787d --- /dev/null +++ b/test/dm/of_extra.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include + +static int dm_test_ofnode_read_fmap_entry(struct unit_test_state *uts) +{ + const char hash_expect[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + }; + struct fmap_entry entry; + ofnode node; + + node = ofnode_path("/cros-ec/flash/wp-ro"); + ut_assertok(ofnode_read_fmap_entry(node, &entry)); + ut_asserteq(0xf000, entry.offset); + ut_asserteq(0x1000, entry.length); + ut_asserteq(0x884, entry.used); + ut_asserteq(FMAP_COMPRESS_LZ4, entry.compress_algo); + ut_asserteq(0xcf8, entry.unc_length); + ut_asserteq(FMAP_HASH_SHA256, entry.hash_algo); + ut_asserteq(SHA256_SUM_LEN, entry.hash_size); + ut_asserteq_mem(hash_expect, entry.hash, SHA256_SUM_LEN); + + return 0; +} +DM_TEST(dm_test_ofnode_read_fmap_entry, 0); From 3306eeca892fe90f55a229526cb966b0ecfc189b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:15 -0700 Subject: [PATCH 38/44] Add a symlink for ctype.h Libraries that link with U-Boot typically may expect to be able to include ctype.h but this file is in a different place in U-Boot. Add a symlink to make this work. Signed-off-by: Simon Glass --- include/ctype.h | 1 + 1 file changed, 1 insertion(+) create mode 120000 include/ctype.h diff --git a/include/ctype.h b/include/ctype.h new file mode 120000 index 0000000000..9e43f9c6c6 --- /dev/null +++ b/include/ctype.h @@ -0,0 +1 @@ +linux/ctype.h \ No newline at end of file From 5e6c9029cdeae72eeeb4e05caa4ce3d48e2e86fb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 21 Jan 2021 13:57:16 -0700 Subject: [PATCH 39/44] binman: Print a debug message when binman selects a node Add some debugging to indicate which node the binman library is looking at. Signed-off-by: Simon Glass --- lib/binman.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/binman.c b/lib/binman.c index f415df3054..6040ec8924 100644 --- a/lib/binman.c +++ b/lib/binman.c @@ -145,6 +145,8 @@ int binman_init(void) if (ret) return log_msg_ret("node", -ENOENT); binman_set_rom_offset(ROM_OFFSET_NONE); + log_debug("binman: Selected image node '%s'\n", + ofnode_get_name(binman->image)); return 0; } From 43db07507abdb54b6575345300c171b0486e46be Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 30 Dec 2020 18:07:48 +0100 Subject: [PATCH 40/44] sandbox: keep time offset when resetting The UEFI Self Certification Test (SCT) checks the SetTime() service with the following steps: * set date * reset * check date matches To be compliant the sandbox should keep the offset to the host RTC during resets. The implementation uses the environment variable UBOOT_SB_TIME_OFFSET to persist the offset. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- arch/sandbox/cpu/os.c | 25 +++++++++++++++++++++++++ doc/arch/sandbox.rst | 7 +++++++ drivers/rtc/i2c_rtc_emul.c | 4 +++- include/os.h | 18 ++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 80996a91ce..3d8af0a52b 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -32,6 +32,9 @@ #include #include +/* Environment variable for time offset */ +#define ENV_TIME_OFFSET "UBOOT_SB_TIME_OFFSET" + /* Operating System Interface */ struct os_mem_hdr { @@ -798,6 +801,28 @@ int os_spl_to_uboot(const char *fname) return os_jump_to_file(fname); } +long os_get_time_offset(void) +{ + const char *offset; + + offset = getenv(ENV_TIME_OFFSET); + if (offset) + return strtol(offset, NULL, 0); + return 0; +} + +void os_set_time_offset(long offset) +{ + char buf[21]; + int ret; + + snprintf(buf, sizeof(buf), "%ld", offset); + ret = setenv(ENV_TIME_OFFSET, buf, true); + if (ret) + printf("Could not set environment variable %s\n", + ENV_TIME_OFFSET); +} + void os_localtime(struct rtc_time *rt) { time_t t = time(NULL); diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst index 1a7801af02..60ee1e0741 100644 --- a/doc/arch/sandbox.rst +++ b/doc/arch/sandbox.rst @@ -131,6 +131,13 @@ available options. Some of these are described below: -i Go to interactive mode after executing the commands specified by -c. +Environment Variables +--------------------- + +UBOOT_SB_TIME_OFFSET + This environment variable stores the offset of the emulated real time clock + to the host's real time clock in seconds. The offset defaults to zero. + Memory Emulation ---------------- diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c index 5a2a154e65..f25b976e54 100644 --- a/drivers/rtc/i2c_rtc_emul.c +++ b/drivers/rtc/i2c_rtc_emul.c @@ -57,6 +57,7 @@ long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time, plat->use_system_time = use_system_time; if (offset != -1) plat->offset = offset; + os_set_time_offset(plat->offset); return old_offset; } @@ -80,7 +81,7 @@ static void reset_time(struct udevice *dev) os_localtime(&now); plat->base_time = rtc_mktime(&now); - plat->offset = 0; + plat->offset = os_get_time_offset(); plat->use_system_time = true; } @@ -115,6 +116,7 @@ static int sandbox_i2c_rtc_set(struct udevice *dev, const struct rtc_time *time) now = plat->base_time; } plat->offset = rtc_mktime(time) - now; + os_set_time_offset(plat->offset); return 0; } diff --git a/include/os.h b/include/os.h index 0913b47b3a..e192e32d59 100644 --- a/include/os.h +++ b/include/os.h @@ -424,4 +424,22 @@ int os_setup_signal_handlers(void); */ void os_signal_action(int sig, unsigned long pc); +/** + * os_get_time_offset() - get time offset + * + * Get the time offset from environment variable UBOOT_SB_TIME_OFFSET. + * + * Return: offset in seconds + */ +long os_get_time_offset(void); + +/** + * os_set_time_offset() - set time offset + * + * Save the time offset in environment variable UBOOT_SB_TIME_OFFSET. + * + * @offset: offset in seconds + */ +void os_set_time_offset(long offset); + #endif From a00e0f7ae5a3058dc8dd520d1d449d4c8806e5f8 Mon Sep 17 00:00:00 2001 From: Stanislav Pinchuk Date: Wed, 20 Jan 2021 21:52:23 +0300 Subject: [PATCH 41/44] do not pass NULL pointer to libfdt Re-send because of line-wraps. Without this patch, u-boot just hangs if the fdt pointer is not initialized. The diagnostic subsystems are not yet initialized, so all you get is a blind hang. Signed-off-by: Stanislav.Pinchuk@kaspersky.com --- include/dm/read.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dm/read.h b/include/dm/read.h index f6f8b875d1..03ba98232a 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -1006,7 +1006,7 @@ static inline u64 dev_translate_dma_address(const struct udevice *dev, static inline int dev_read_alias_highest_id(const char *stem) { - if (!CONFIG_IS_ENABLED(OF_LIBFDT)) + if (!CONFIG_IS_ENABLED(OF_LIBFDT) || !gd->fdt_blob) return -1; return fdtdec_get_alias_highest_id(gd->fdt_blob, stem); } From fabae8711fd74c0b803f62fd24d28d6712042c2f Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sat, 23 Jan 2021 19:48:57 +0100 Subject: [PATCH 42/44] dm: replace auto_alloc_size with auto The auto_alloc_size members of struct driver has been renamed auto. Signed-off-by: Dario Binacchi Reviewed-by: Simon Glass --- include/dm/device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/dm/device.h b/include/dm/device.h index f5b4cd6876..e665558444 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -111,7 +111,7 @@ enum { * probe method if the device has a device tree node. * * All three of plat, priv and uclass_priv can be allocated by the - * driver, or you can use the auto_alloc_size members of struct driver and + * driver, or you can use the auto members of struct driver and * struct uclass_driver to have driver model do this automatically. * * @driver: The driver used by this device From 168e313b5b128a0a2e55010875c1636dead38527 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 25 Jan 2021 12:57:14 +0100 Subject: [PATCH 43/44] sandbox: fill block device meta information Provide information about host backed block device. Mark the device created by 'host bind' as removable. Signed-off-by: Heinrich Schuchardt --- drivers/block/sandbox.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c index 34c26cda47..f57f690d3c 100644 --- a/drivers/block/sandbox.c +++ b/drivers/block/sandbox.c @@ -92,6 +92,7 @@ int host_dev_bind(int devnum, char *filename) { struct host_block_dev *host_dev; struct udevice *dev; + struct blk_desc *desc; char dev_name[20], *str, *fname; int ret, fd; @@ -143,6 +144,12 @@ int host_dev_bind(int devnum, char *filename) goto err_file; } + desc = blk_get_devnum_by_type(IF_TYPE_HOST, devnum); + desc->removable = 1; + snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot"); + snprintf(desc->product, BLK_PRD_SIZE, "hostfile"); + snprintf(desc->revision, BLK_REV_SIZE, "1.0"); + return 0; err_file: os_close(fd); @@ -187,6 +194,10 @@ int host_dev_bind(int dev, char *filename) blk_dev->block_write = host_block_write; blk_dev->devnum = dev; blk_dev->part_type = PART_TYPE_UNKNOWN; + blk_dev->removable = 1; + snprintf(blk_dev->vendor, BLK_VEN_SIZE, "U-Boot"); + snprintf(blk_dev->product, BLK_PRD_SIZE, "hostfile"); + snprintf(blk_dev->revision, BLK_REV_SIZE, "1.0"); part_init(blk_dev); return 0; From f84eda89e5970ef513fe64ba8e8d977788c44dca Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 25 Jan 2021 12:57:15 +0100 Subject: [PATCH 44/44] disk: part: sandbox support in dev_print() Commands like 'fatinfo' call dev_print() to print device information. If the block device is created via 'host bind', we should print accurate information. Signed-off-by: Heinrich Schuchardt --- disk/part.c | 1 + 1 file changed, 1 insertion(+) diff --git a/disk/part.c b/disk/part.c index b69fd345f3..85b1af55e2 100644 --- a/disk/part.c +++ b/disk/part.c @@ -150,6 +150,7 @@ void dev_print (struct blk_desc *dev_desc) case IF_TYPE_USB: case IF_TYPE_NVME: case IF_TYPE_PVBLOCK: + case IF_TYPE_HOST: printf ("Vendor: %s Rev: %s Prod: %s\n", dev_desc->vendor, dev_desc->revision,