From 5203258c6e149ab865e337c00437a909abf3b5b4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:33 -0600 Subject: [PATCH 01/49] binman: Don't generate an error in 'text' entry constructor It is not good practice to raise an exception in a constructor. In this case the 'text' entry may not actually be used, if -i is used to filter out the images that get built. Move the exception to where the data is actually used. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- tools/binman/etype/text.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/binman/etype/text.py b/tools/binman/etype/text.py index 6e99819487..c4aa510a87 100644 --- a/tools/binman/etype/text.py +++ b/tools/binman/etype/text.py @@ -51,10 +51,10 @@ class Entry_text(Entry): self.text_label, = self.GetEntryArgsOrProps( [EntryArg('text-label', str)]) self.value, = self.GetEntryArgsOrProps([EntryArg(self.text_label, str)]) + + def ObtainContents(self): if not self.value: self.Raise("No value provided for text label '%s'" % self.text_label) - - def ObtainContents(self): self.SetContents(self.value) return True From eb833d871dfdb360002c02ca7e8662309828cca5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:34 -0600 Subject: [PATCH 02/49] binman: Don't show image-skip message by default This message is not very important since it is simply indicating that the user's instructions are being followed. Only show it when the verbosity level is above the default. Also drop the unnecessary extra newline on this message, which causes two line breaks. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- tools/binman/control.py | 4 ++-- tools/binman/ftest.py | 26 +++++++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/tools/binman/control.py b/tools/binman/control.py index 3446e2e79c..b32e4e1996 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -133,8 +133,8 @@ def Binman(options, args): if name not in options.image: del images[name] skip.append(name) - if skip: - print 'Skipping images: %s\n' % ', '.join(skip) + if skip and options.verbosity >= 2: + print 'Skipping images: %s' % ', '.join(skip) state.Prepare(images, dtb) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index e77fce5a26..75658c9a36 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -187,7 +187,8 @@ class TestFunctional(unittest.TestCase): return control.Binman(options, args) def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False, - entry_args=None, images=None, use_real_dtb=False): + entry_args=None, images=None, use_real_dtb=False, + verbosity=None): """Run binman with a given test file Args: @@ -210,6 +211,8 @@ class TestFunctional(unittest.TestCase): args.append('-up') if not use_real_dtb: args.append('--fake-dtb') + if verbosity is not None: + args.append('-v%d' % verbosity) if entry_args: for arg, value in entry_args.iteritems(): args.append('-a%s=%s' % (arg, value)) @@ -1459,13 +1462,22 @@ class TestFunctional(unittest.TestCase): def testSelectImage(self): """Test that we can select which images to build""" - with test_util.capture_sys_output() as (stdout, stderr): - retcode = self._DoTestFile('006_dual_image.dts', images=['image2']) - self.assertEqual(0, retcode) - self.assertIn('Skipping images: image1', stdout.getvalue()) + expected = 'Skipping images: image1' - self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin'))) - self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin'))) + # We should only get the expected message in verbose mode + for verbosity in (None, 2): + with test_util.capture_sys_output() as (stdout, stderr): + retcode = self._DoTestFile('006_dual_image.dts', + verbosity=verbosity, + images=['image2']) + self.assertEqual(0, retcode) + if verbosity: + self.assertIn(expected, stdout.getvalue()) + else: + self.assertNotIn(expected, stdout.getvalue()) + + self.assertFalse(os.path.exists(tools.GetOutputFilename('image1.bin'))) + self.assertTrue(os.path.exists(tools.GetOutputFilename('image2.bin'))) def testUpdateFdtAll(self): """Test that all device trees are updated with offset/size info""" From 0b96f6ecbe8f68232adeb4340883aaeee5d63bd5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:35 -0600 Subject: [PATCH 03/49] binman: Add a missing comment in Entry_vblock An important property is missing. Update the entry comment to include this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- tools/binman/etype/vblock.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/binman/etype/vblock.py b/tools/binman/etype/vblock.py index c4d970ed16..334ff9f966 100644 --- a/tools/binman/etype/vblock.py +++ b/tools/binman/etype/vblock.py @@ -18,6 +18,7 @@ class Entry_vblock(Entry): """An entry which contains a Chromium OS verified boot block Properties / Entry arguments: + - content: List of phandles to entries to sign - keydir: Directory containing the public keys to use - keyblock: Name of the key file to use (inside keydir) - signprivate: Name of provide key file to use (inside keydir) From 9481c80f55260fa2b2c37445fb2a30811b136ed3 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:39 -0600 Subject: [PATCH 04/49] binman: Allow sections to have an offset At present sections are always placed automatically. Even if an 'offset' property is provided it is ignored. Update the logic to support an offset for sections. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- tools/binman/README | 7 +++++ tools/binman/bsection.py | 9 +++--- tools/binman/etype/section.py | 3 +- tools/binman/ftest.py | 18 ++++++++++++ tools/binman/test/101_sections_offset.dts | 35 +++++++++++++++++++++++ 5 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 tools/binman/test/101_sections_offset.dts diff --git a/tools/binman/README b/tools/binman/README index 04ed2b799c..927fa856ac 100644 --- a/tools/binman/README +++ b/tools/binman/README @@ -342,6 +342,13 @@ size: Sets the image size in bytes, for example 'size = <0x100000>' for a 1MB image. +offset: + This is similar to 'offset' in entries, setting the offset of a section + within the image or section containing it. The first byte of the section + is normally at offset 0. If 'offset' is not provided, binman sets it to + the end of the previous region, or the start of the image's entry area + (normally 0) if there is no previous region. + align-size: This sets the alignment of the image size. For example, to ensure that the image ends on a 512-byte boundary, use 'align-size = <512>'. diff --git a/tools/binman/bsection.py b/tools/binman/bsection.py index ccf2920c5b..0ba542ee98 100644 --- a/tools/binman/bsection.py +++ b/tools/binman/bsection.py @@ -57,7 +57,7 @@ class Section(object): self._name = name self._node = node self._image = image - self._offset = 0 + self._offset = None self._size = None self._align_size = None self._pad_before = 0 @@ -75,6 +75,7 @@ class Section(object): def _ReadNode(self): """Read properties from the section node""" + self._offset = fdt_util.GetInt(self._node, 'offset') self._size = fdt_util.GetInt(self._node, 'size') self._align_size = fdt_util.GetInt(self._node, 'align-size') if tools.NotPowerOfTwo(self._align_size): @@ -130,7 +131,7 @@ class Section(object): entry.AddMissingProperties() def SetCalculatedProperties(self): - state.SetInt(self._node, 'offset', self._offset) + state.SetInt(self._node, 'offset', self._offset or 0) state.SetInt(self._node, 'size', self._size) image_pos = self._image_pos if self._parent_section: @@ -424,8 +425,8 @@ class Section(object): Args: fd: File to write the map to """ - Entry.WriteMapLine(fd, indent, self._name, self._offset, self._size, - self._image_pos) + Entry.WriteMapLine(fd, indent, self._name, self._offset or 0, + self._size, self._image_pos) for entry in self._entries.values(): entry.WriteMap(fd, indent + 1) diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index 7f1b413604..3681a48468 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -67,7 +67,8 @@ class Entry_section(Entry): def Pack(self, offset): """Pack all entries into the section""" self._section.PackEntries() - self._section.SetOffset(offset) + if self._section._offset is None: + self._section.SetOffset(offset) self.size = self._section.GetSize() return super(Entry_section, self).Pack(offset) diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 75658c9a36..daea1ea138 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -1783,6 +1783,24 @@ class TestFunctional(unittest.TestCase): data = self._DoReadFile('100_intel_refcode.dts') self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)]) + def testSectionOffset(self): + """Tests use of a section with an offset""" + data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts', + map=True) + self.assertEqual('''ImagePos Offset Size Name +00000000 00000000 00000038 main-section +00000004 00000004 00000010 section@0 +00000004 00000000 00000004 u-boot +00000018 00000018 00000010 section@1 +00000018 00000000 00000004 u-boot +0000002c 0000002c 00000004 section@2 +0000002c 00000000 00000004 u-boot +''', map_data) + self.assertEqual(data, + 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x21) + + 4 * chr(0x26) + U_BOOT_DATA + 12 * chr(0x61) + + 4 * chr(0x26) + U_BOOT_DATA + 8 * chr(0x26)) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/101_sections_offset.dts b/tools/binman/test/101_sections_offset.dts new file mode 100644 index 0000000000..46708ff9b6 --- /dev/null +++ b/tools/binman/test/101_sections_offset.dts @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + pad-byte = <0x26>; + size = <0x38>; + section@0 { + read-only; + offset = <0x4>; + size = <0x10>; + pad-byte = <0x21>; + + u-boot { + }; + }; + section@1 { + size = <0x10>; + pad-byte = <0x61>; + offset = <0x18>; + + u-boot { + }; + }; + section@2 { + offset = <0x2c>; + u-boot { + }; + }; + }; +}; From 003331827a1c7c97ea5b2e29961858e004a485e1 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:36 -0600 Subject: [PATCH 05/49] dm: core: Fix translate condition in ofnode_get_addr_size() Update the condition to translate only if this is enabled for SPL. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/core/ofnode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 785f5c3acf..cc0c031e0d 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -546,7 +546,7 @@ fdt_addr_t ofnode_get_addr_size(ofnode node, const char *property, ns = of_n_size_cells(np); *sizep = of_read_number(prop + na, ns); - if (IS_ENABLED(CONFIG_OF_TRANSLATE) && ns > 0) + if (CONFIG_IS_ENABLED(OF_TRANSLATE) && ns > 0) return of_translate_address(np, prop); else return of_read_number(prop, na); From 4fc2365ccb911a1a3401e88be702c5c42ab6386a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:38 -0600 Subject: [PATCH 06/49] spl: Allow sandbox to build a device-tree file At present only OF_SEPARATE is considered valid for building a device-tree file in SPL. However sandbox uses OF_HOSTFILE instead. Update the logic to handle this and make it easier to understand. Note that the new logic is not quite the same as the old logic. It was previously assumed that checking for: $(CONFIG_$(SPL_TPL_)OF_CONTROL) $(CONFIG_OF_SEPARATE) $(CONFIG_$(SPL_TPL_)OF_PLATDATA) producing 'yy' meant that the first two were 'y' and the last was empty. Strictly speaking it would be possible for any two of the three to be 'y' and still yield the same result. However, that was not the intention of the new logic, since OF_PLATDATA always ensures that no device-tree file is included. So in effect the new logic is the same, with the addition of OF_HOSTFILE as an option for OP_SEPARATE. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- scripts/Makefile.spl | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 56dbbe127b..8d76a2d400 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -253,8 +253,20 @@ else FINAL_DTB_CONTAINER = $(obj)/$(SPL_BIN).multidtb.fit endif +# Build the .dtb file if: +# - we are not using OF_PLATDATA +# - we are using OF_CONTROL +# - we have either OF_SEPARATE or OF_HOSTFILE +build_dtb := +ifeq ($(CONFIG_$(SPL_TPL_)OF_PLATDATA),) +ifneq ($(CONFIG_$(SPL_TPL_)OF_CONTROL),) +ifeq ($(CONFIG_OF_SEPARATE)$(CONFIG_OF_HOSTFILE),y) +build_dtb := y +endif +endif +endif -ifeq ($(CONFIG_$(SPL_TPL_)OF_CONTROL)$(CONFIG_OF_SEPARATE)$(CONFIG_$(SPL_TPL_)OF_PLATDATA),yy) +ifneq ($(build_dtb),) $(obj)/$(SPL_BIN)-dtb.bin: $(obj)/$(SPL_BIN)-nodtb.bin \ $(if $(CONFIG_SPL_SEPARATE_BSS),,$(obj)/$(SPL_BIN)-pad.bin) \ $(FINAL_DTB_CONTAINER) FORCE From 16f4d05164eb5418d4bafd5a058813c97a431273 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:11 -0600 Subject: [PATCH 07/49] cros_ec: Use a hyphen in the uclass name Device-tree rules require that aliases use a hyphen rather than a underscore. Update the uclass name to fit with this. This allows device-tree aliases to be used to refer to cros-ec devices, for example: aliases { cros-ec0 = &ec; cros-ec1 = &pd; }; Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/misc/cros_ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 565de040fe..382f826286 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1482,7 +1482,7 @@ int cros_ec_set_lid_shutdown_mask(struct udevice *dev, int enable) UCLASS_DRIVER(cros_ec) = { .id = UCLASS_CROS_EC, - .name = "cros_ec", + .name = "cros-ec", .per_device_auto_alloc_size = sizeof(struct cros_ec_dev), .post_bind = dm_scan_fdt_dev, .flags = DM_UC_FLAG_ALLOC_PRIV_DMA, From 62c72995e3cbb2aa356da7dd403d52de47a11072 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 May 2019 21:41:15 -0600 Subject: [PATCH 08/49] Revert "pci: Scale MAX_PCI_REGIONS based on CONFIG_NR_DRAM_BANKS" This reverts commit aec4298ccb337106fd0115b91d846a022fdf301d. Unfortunately this has a dramatic impact on the pre-relocation memory used on x86 platforms (increasing it by 2KB) since it increases the overhead for each PCI device from 220 bytes to 412 bytes. The offending line is in UCLASS_DRIVER(pci): .per_device_auto_alloc_size = sizeof(struct pci_controller), This means that all PCI devices have the controller struct associated with them. The solution is to move the regions[] member out of the array, makes its size dynamic, or split UCLASS_PCI into controllers and non-controllers, as the comment suggests. For now, revert the commit to get things running again. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/pci.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/pci.h b/include/pci.h index 066238a9c3..508f7bca81 100644 --- a/include/pci.h +++ b/include/pci.h @@ -546,11 +546,7 @@ extern void pci_cfgfunc_do_nothing(struct pci_controller* hose, pci_dev_t dev, extern void pci_cfgfunc_config_device(struct pci_controller* hose, pci_dev_t dev, struct pci_config_table *); -#ifdef CONFIG_NR_DRAM_BANKS -#define MAX_PCI_REGIONS (CONFIG_NR_DRAM_BANKS + 7) -#else -#define MAX_PCI_REGIONS 7 -#endif +#define MAX_PCI_REGIONS 7 #define INDIRECT_TYPE_NO_PCIE_LINK 1 From 4a5fc6a069eda83d169a8fa20168a184f3c314c5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:40 -0600 Subject: [PATCH 09/49] x86: start64: Fix copyright message There is a typo in this header. Fix it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/start64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/cpu/start64.S b/arch/x86/cpu/start64.S index a78a3316b6..7be834788b 100644 --- a/arch/x86/cpu/start64.S +++ b/arch/x86/cpu/start64.S @@ -2,7 +2,7 @@ /* * 64-bit x86 Startup Code * - * (C) Copyright 216 Google, Inc + * Copyright 2019 Google, Inc * Written by Simon Glass */ From 11b7cc37f15ae0f27987da5a037e6603e068f20c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:44 -0600 Subject: [PATCH 10/49] x86: Update a stale comment about ifdtool We use binman to build the x86 image now. Update a comment which still refers to ifdtool. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/intel_common/car.S | 2 +- arch/x86/lib/fsp/fsp_car.S | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/cpu/intel_common/car.S b/arch/x86/cpu/intel_common/car.S index 52a77bb2d1..00308dbdef 100644 --- a/arch/x86/cpu/intel_common/car.S +++ b/arch/x86/cpu/intel_common/car.S @@ -235,7 +235,7 @@ mtrr_table_end: .align 4 _dt_ucode_base_size: - /* These next two fields are filled in by ifdtool */ + /* These next two fields are filled in by binman */ .globl ucode_base ucode_base: /* Declared in microcode.h */ .long 0 /* microcode base */ diff --git a/arch/x86/lib/fsp/fsp_car.S b/arch/x86/lib/fsp/fsp_car.S index 48edc8362a..8c54cea3db 100644 --- a/arch/x86/lib/fsp/fsp_car.S +++ b/arch/x86/lib/fsp/fsp_car.S @@ -100,7 +100,7 @@ temp_ram_init_romstack: .long temp_ram_init_params temp_ram_init_params: _dt_ucode_base_size: - /* These next two fields are filled in by ifdtool */ + /* These next two fields are filled in by binman */ .globl ucode_base ucode_base: /* Declared in microcode.h */ .long 0 /* microcode base */ From 7b140238800533b334a160bf94c2901c98bc1550 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:41 -0600 Subject: [PATCH 11/49] x86: mp_init: Use proper error numbers At present many of the functions in this file return -1 as an error number. which is -EPERM. Update the code to use real error numbers. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/mp_init.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/x86/cpu/mp_init.c b/arch/x86/cpu/mp_init.c index ea64c2ee57..fefbf8f728 100644 --- a/arch/x86/cpu/mp_init.c +++ b/arch/x86/cpu/mp_init.c @@ -322,7 +322,7 @@ static int start_aps(int ap_count, atomic_t *num_aps) if (sipi_vector > max_vector_loc) { printf("SIPI vector too large! 0x%08x\n", sipi_vector); - return -1; + return -ENOSPC; } debug("Attempting to start %d APs\n", ap_count); @@ -364,7 +364,7 @@ static int start_aps(int ap_count, atomic_t *num_aps) if (wait_for_aps(num_aps, ap_count, 10000, 50)) { debug("Not all APs checked in: %d/%d\n", atomic_read(num_aps), ap_count); - return -1; + return -EIO; } return 0; @@ -387,7 +387,7 @@ static int bsp_do_flight_plan(struct udevice *cpu, struct mp_params *mp_params) if (wait_for_aps(&rec->cpus_entered, num_aps, timeout_us, step_us)) { debug("MP record %d timeout\n", i); - ret = -1; + ret = -ETIMEDOUT; } } @@ -508,7 +508,7 @@ int mp_init(struct mp_params *p) if (p == NULL || p->flight_plan == NULL || p->num_records < 1) { printf("Invalid MP parameters\n"); - return -1; + return -EINVAL; } num_cpus = cpu_get_count(cpu); @@ -531,7 +531,7 @@ int mp_init(struct mp_params *p) /* Load the SIPI vector */ ret = load_sipi_vector(&ap_count, num_cpus); if (ap_count == NULL) - return -1; + return -ENOENT; /* * Make sure SIPI data hits RAM so the APs that come up will see From c0069e9a8a033a359a202e6252da228edab9b5af Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:42 -0600 Subject: [PATCH 12/49] x86: Add a way to reinit the cpu We cannot init the CPU fully both than once during a boot. Add a new function which can be called to figure out the CPU identity, but which does not change anything. For x86_64, this is empty for now. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/i386/cpu.c | 107 ++++++++++++++++++------------ arch/x86/cpu/x86_64/cpu.c | 5 ++ arch/x86/include/asm/u-boot-x86.h | 20 ++++++ 3 files changed, 91 insertions(+), 41 deletions(-) diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index 3bde44ebf5..90b546e741 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -309,21 +309,22 @@ u32 cpu_get_stepping(void) return gd->arch.x86_mask; } -int x86_cpu_init_f(void) +/* initialise FPU, reset EM, set MP and NE */ +static void setup_cpu_features(void) { const u32 em_rst = ~X86_CR0_EM; const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE; - if (ll_boot_init()) { - /* initialize FPU, reset EM, set MP and NE */ - asm ("fninit\n" \ - "movl %%cr0, %%eax\n" \ - "andl %0, %%eax\n" \ - "orl %1, %%eax\n" \ - "movl %%eax, %%cr0\n" \ - : : "i" (em_rst), "i" (mp_ne_set) : "eax"); - } + asm ("fninit\n" \ + "movl %%cr0, %%eax\n" \ + "andl %0, %%eax\n" \ + "orl %1, %%eax\n" \ + "movl %%eax, %%cr0\n" \ + : : "i" (em_rst), "i" (mp_ne_set) : "eax"); +} +static void setup_identity(void) +{ /* identify CPU via cpuid and store the decoded info into gd->arch */ if (has_cpuid()) { struct cpu_device_id cpu; @@ -339,46 +340,70 @@ int x86_cpu_init_f(void) gd->arch.has_mtrr = has_mtrr(); } - /* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ +} + +/* Don't allow PCI region 3 to use memory in the 2-4GB memory hole */ +static void setup_pci_ram_top(void) +{ gd->pci_ram_top = 0x80000000U; +} + +static void setup_mtrr(void) +{ + u64 mtrr_cap; /* Configure fixed range MTRRs for some legacy regions */ - if (gd->arch.has_mtrr) { - u64 mtrr_cap; + if (!gd->arch.has_mtrr) + return; - mtrr_cap = native_read_msr(MTRR_CAP_MSR); - if (mtrr_cap & MTRR_CAP_FIX) { - /* Mark the VGA RAM area as uncacheable */ - native_write_msr(MTRR_FIX_16K_A0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE), - MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE)); + mtrr_cap = native_read_msr(MTRR_CAP_MSR); + if (mtrr_cap & MTRR_CAP_FIX) { + /* Mark the VGA RAM area as uncacheable */ + native_write_msr(MTRR_FIX_16K_A0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE), + MTRR_FIX_TYPE(MTRR_TYPE_UNCACHEABLE)); - /* - * Mark the PCI ROM area as cacheable to improve ROM - * execution performance. - */ - native_write_msr(MTRR_FIX_4K_C0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_C8000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_D0000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - native_write_msr(MTRR_FIX_4K_D8000_MSR, - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), - MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + /* + * Mark the PCI ROM area as cacheable to improve ROM + * execution performance. + */ + native_write_msr(MTRR_FIX_4K_C0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_C8000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_D0000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); + native_write_msr(MTRR_FIX_4K_D8000_MSR, + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK), + MTRR_FIX_TYPE(MTRR_TYPE_WRBACK)); - /* Enable the fixed range MTRRs */ - msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); - } + /* Enable the fixed range MTRRs */ + msr_setbits_64(MTRR_DEF_TYPE_MSR, MTRR_DEF_TYPE_FIX_EN); } +} + +int x86_cpu_init_f(void) +{ + if (ll_boot_init()) + setup_cpu_features(); + setup_identity(); + setup_mtrr(); + setup_pci_ram_top(); -#ifdef CONFIG_I8254_TIMER /* Set up the i8254 timer if required */ - i8254_init(); -#endif + if (IS_ENABLED(CONFIG_I8254_TIMER)) + i8254_init(); + + return 0; +} + +int x86_cpu_reinit_f(void) +{ + setup_identity(); + setup_pci_ram_top(); return 0; } diff --git a/arch/x86/cpu/x86_64/cpu.c b/arch/x86/cpu/x86_64/cpu.c index 6c063e8200..42abb23a9e 100644 --- a/arch/x86/cpu/x86_64/cpu.c +++ b/arch/x86/cpu/x86_64/cpu.c @@ -61,3 +61,8 @@ int print_cpuinfo(void) { return 0; } + +int x86_cpu_reinit_f(void) +{ + return 0; +} diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 670fcdc009..c252192bf4 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -13,7 +13,27 @@ extern char gdt_rom[]; /* cpu/.../cpu.c */ int arch_cpu_init(void); + +/** + * x86_cpu_init_f() - Set up basic features of the x86 CPU + * + * 0 on success, -ve on error + */ int x86_cpu_init_f(void); + +/** + * x86_cpu_reinit_f() - Set up the CPU a second time + * + * Once cpu_init_f() has been called (e.g. in SPL) we should not call it + * again (e.g. in U-Boot proper) since it sets up the state from scratch. + * Call this function in later phases of U-Boot instead. It reads the CPU + * identify so that CPU functions can be used correctly, but does not change + * anything. + * + * @return 0 (indicating success, to mimic cpu_init_f()) + */ +int x86_cpu_reinit_f(void); + int cpu_init_f(void); void setup_gdt(struct global_data *id, u64 *gdt_addr); /* From 20d97f33f02c4239569f61794cef4a970b2280ed Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:43 -0600 Subject: [PATCH 13/49] x86: dts: Add device-tree labels for rtc and reset Add labels for these nodes so that board DT files can reference them. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/dts/reset.dtsi | 2 +- arch/x86/dts/rtc.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/dts/reset.dtsi b/arch/x86/dts/reset.dtsi index f979d83757..555d0dd960 100644 --- a/arch/x86/dts/reset.dtsi +++ b/arch/x86/dts/reset.dtsi @@ -1,5 +1,5 @@ / { - reset { + reset: reset { compatible = "x86,reset"; u-boot,dm-pre-reloc; }; diff --git a/arch/x86/dts/rtc.dtsi b/arch/x86/dts/rtc.dtsi index 1797e042da..d0bbd84e50 100644 --- a/arch/x86/dts/rtc.dtsi +++ b/arch/x86/dts/rtc.dtsi @@ -1,5 +1,5 @@ / { - rtc { + rtc: rtc { compatible = "motorola,mc146818"; u-boot,dm-pre-reloc; reg = <0x70 2>; From 9898790247040772e068f1ef9ac8a16c01d197ac Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:45 -0600 Subject: [PATCH 14/49] x86: Support SPL and TPL At present only chromebook_link64 supports SPL. It is useful to eb able to support both TPL and SPL to implement verified boot on x86. Enable the options for both along with some suitable default options needed to boot through these phases. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/Kconfig | 31 +++++++++++++++++++++++++++++++ arch/x86/Kconfig | 1 - 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/arch/Kconfig b/arch/Kconfig index 760023b19a..2914567248 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -126,6 +126,8 @@ config SH config X86 bool "x86 architecture" + select SUPPORT_SPL + select SUPPORT_TPL select CREATE_ARCH_SYMLINK select DM select DM_PCI @@ -164,6 +166,35 @@ config X86 imply USB_HOST_ETHER imply PCH + # Thing to enable for when SPL/TPL are enabled: SPL + imply SPL_DM + imply SPL_OF_LIBFDT + imply SPL_DRIVERS_MISC_SUPPORT + imply SPL_GPIO_SUPPORT + imply SPL_LIBCOMMON_SUPPORT + imply SPL_LIBGENERIC_SUPPORT + imply SPL_SERIAL_SUPPORT + imply SPL_SPI_FLASH_SUPPORT + imply SPL_SPI_SUPPORT + imply SPL_OF_CONTROL + imply SPL_TIMER + imply SPL_REGMAP + imply SPL_SYSCON + # TPL + imply TPL_DM + imply TPL_OF_LIBFDT + imply TPL_DRIVERS_MISC_SUPPORT + imply TPL_GPIO_SUPPORT + imply TPL_LIBCOMMON_SUPPORT + imply TPL_LIBGENERIC_SUPPORT + imply TPL_SERIAL_SUPPORT + imply TPL_SPI_FLASH_SUPPORT + imply TPL_SPI_SUPPORT + imply TPL_OF_CONTROL + imply TPL_TIMER + imply TPL_REGMAP + imply TPL_SYSCON + config XTENSA bool "Xtensa architecture" select CREATE_ARCH_SYMLINK diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e052093775..185f0ef8c4 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -32,7 +32,6 @@ config X86_RUN_32BIT config X86_RUN_64BIT bool "64-bit" select X86_64 - select SUPPORT_SPL select SPL select SPL_SEPARATE_BSS help From 7c2ca877fee42085ad1b6ff24d9d10d91dcd9332 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:46 -0600 Subject: [PATCH 15/49] x86: Support booting with TPL Some boards want to use TPL as the first phase of U-Boot. This allows selection of A or B SPL phases, thus allowing the memory init to be upgraded in the field. Add a new Kconfig option for this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/Kconfig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 185f0ef8c4..45a533625a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -176,10 +176,17 @@ config X86_16BIT_INIT config SPL_X86_16BIT_INIT bool depends on X86_RESET_VECTOR - default y if X86_RESET_VECTOR && SPL + default y if X86_RESET_VECTOR && SPL && !TPL help This is enabled when 16-bit init is in SPL +config TPL_X86_16BIT_INIT + bool + depends on X86_RESET_VECTOR + default y if X86_RESET_VECTOR && TPL + help + This is enabled when 16-bit init is in TPL + config X86_32BIT_INIT bool depends on X86_RESET_VECTOR From 62be5dd8858e4b9c1aea635619be707ec45d4a88 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:47 -0600 Subject: [PATCH 16/49] x86: Add a handoff header file Add an arch-specific handoff header so that we can use the HANDOFF feature on x86 devices. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/include/asm/handoff.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 arch/x86/include/asm/handoff.h diff --git a/arch/x86/include/asm/handoff.h b/arch/x86/include/asm/handoff.h new file mode 100644 index 0000000000..4d18d59efe --- /dev/null +++ b/arch/x86/include/asm/handoff.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Architecture-specific SPL handoff information for x86 + * + * Copyright 2018 Google, Inc + * Written by Simon Glass + */ + +#ifndef __x86_asm_handoff_h +#define __x86_asm_handoff_h + +struct arch_spl_handoff { +}; + +#endif From 9f6486bff474a8c30bd257f4fcf24aa05fbae6c5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:48 -0600 Subject: [PATCH 17/49] x86: broadwell: Improve SDRAM debugging output Add debugging during SDRAM init so that problems are easier to diagnose. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/broadwell/sdram.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c index 03a35bcf73..1b9f9840c6 100644 --- a/arch/x86/cpu/broadwell/sdram.c +++ b/arch/x86/cpu/broadwell/sdram.c @@ -204,16 +204,18 @@ int dram_init(void) /* Print ME state before MRC */ ret = syscon_get_by_driver_data(X86_SYSCON_ME, &me_dev); - if (ret) + if (ret) { + debug("Cannot get ME (err=%d)\n", ret); return ret; + } intel_me_status(me_dev); /* Save ME HSIO version */ - ret = uclass_first_device(UCLASS_PCH, &pch_dev); - if (ret) + ret = uclass_first_device_err(UCLASS_PCH, &pch_dev); + if (ret) { + debug("Cannot get PCH (err=%d)\n", ret); return ret; - if (!pch_dev) - return -ENODEV; + } power_state_get(pch_dev, &ps); intel_me_hsio_version(me_dev, &ps.hsio_version, &ps.hsio_checksum); @@ -221,15 +223,17 @@ int dram_init(void) broadwell_fill_pei_data(pei_data); mainboard_fill_pei_data(pei_data); - ret = uclass_first_device(UCLASS_NORTHBRIDGE, &dev); - if (ret) + ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev); + if (ret) { + debug("Cannot get Northbridge (err=%d)\n", ret); return ret; - if (!dev) - return -ENODEV; + } size = 256; ret = mrc_locate_spd(dev, size, &spd_data); - if (ret) + if (ret) { + debug("Cannot locate SPD (err=%d)\n", ret); return ret; + } memcpy(pei_data->spd_data[0][0], spd_data, size); memcpy(pei_data->spd_data[1][0], spd_data, size); @@ -239,13 +243,17 @@ int dram_init(void) debug("PEI version %#x\n", pei_data->pei_version); ret = mrc_common_init(dev, pei_data, true); - if (ret) + if (ret) { + debug("mrc_common_init() failed(err=%d)\n", ret); return ret; + } debug("Memory init done\n"); ret = sdram_find(dev); - if (ret) + if (ret) { + debug("sdram_find() failed (err=%d)\n", ret); return ret; + } gd->ram_size = gd->arch.meminfo.total_32bit_memory; debug("RAM size %llx\n", (unsigned long long)gd->ram_size); From 4eabf1e54b7ad1d1d7511af65570743ed756f85c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:49 -0600 Subject: [PATCH 18/49] x86: broadwell: Allow SDRAM init from SPL At present, for broadwell, SDRAM is always set up in U-Boot proper since the 64-bit mode (which uses SDRAM init in SPL) is not supported. Update the code to allow SDRAM init in SPL instead so that U-Boot proper can be loaded into SDRAM and run from there. This allows U-Boot to be compressed to reduce space, since it is not necessary to run it directly from flash. It could later allow us to support 64-bit U-Boot on broadwell. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/broadwell/Makefile | 2 +- arch/x86/cpu/broadwell/northbridge.c | 100 +++++++++++++++++++++++++++ arch/x86/cpu/broadwell/sdram.c | 93 ------------------------- 3 files changed, 101 insertions(+), 94 deletions(-) diff --git a/arch/x86/cpu/broadwell/Makefile b/arch/x86/cpu/broadwell/Makefile index d3785aabdf..d464507e6c 100644 --- a/arch/x86/cpu/broadwell/Makefile +++ b/arch/x86/cpu/broadwell/Makefile @@ -13,4 +13,4 @@ obj-y += pinctrl_broadwell.o obj-y += power_state.o obj-y += refcode.o obj-y += sata.o -obj-y += sdram.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += sdram.o diff --git a/arch/x86/cpu/broadwell/northbridge.c b/arch/x86/cpu/broadwell/northbridge.c index 3055880bb7..4bcab78556 100644 --- a/arch/x86/cpu/broadwell/northbridge.c +++ b/arch/x86/cpu/broadwell/northbridge.c @@ -6,8 +6,108 @@ #include #include #include +#include #include #include +#include + +__weak asmlinkage void sdram_console_tx_byte(unsigned char byte) +{ +#ifdef DEBUG + putc(byte); +#endif +} + +void broadwell_fill_pei_data(struct pei_data *pei_data) +{ + pei_data->pei_version = PEI_VERSION; + pei_data->board_type = BOARD_TYPE_ULT; + pei_data->pciexbar = MCFG_BASE_ADDRESS; + pei_data->smbusbar = SMBUS_BASE_ADDRESS; + pei_data->ehcibar = EARLY_EHCI_BAR; + pei_data->xhcibar = EARLY_XHCI_BAR; + pei_data->gttbar = EARLY_GTT_BAR; + pei_data->pmbase = ACPI_BASE_ADDRESS; + pei_data->gpiobase = GPIO_BASE_ADDRESS; + pei_data->tseg_size = CONFIG_SMM_TSEG_SIZE; + pei_data->temp_mmio_base = EARLY_TEMP_MMIO; + pei_data->tx_byte = sdram_console_tx_byte; + pei_data->ddr_refresh_2x = 1; +} + +static void pei_data_usb2_port(struct pei_data *pei_data, int port, uint length, + uint enable, uint oc_pin, uint location) +{ + pei_data->usb2_ports[port].length = length; + pei_data->usb2_ports[port].enable = enable; + pei_data->usb2_ports[port].oc_pin = oc_pin; + pei_data->usb2_ports[port].location = location; +} + +static void pei_data_usb3_port(struct pei_data *pei_data, int port, uint enable, + uint oc_pin, uint fixed_eq) +{ + pei_data->usb3_ports[port].enable = enable; + pei_data->usb3_ports[port].oc_pin = oc_pin; + pei_data->usb3_ports[port].fixed_eq = fixed_eq; +} + +void mainboard_fill_pei_data(struct pei_data *pei_data) +{ + /* DQ byte map for Samus board */ + const u8 dq_map[2][6][2] = { + { { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 }, + { 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } }, + { { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 }, + { 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } } }; + /* DQS CPU<>DRAM map for Samus board */ + const u8 dqs_map[2][8] = { + { 2, 0, 1, 3, 6, 4, 7, 5 }, + { 2, 1, 0, 3, 6, 5, 4, 7 } }; + + pei_data->ec_present = 1; + + /* One installed DIMM per channel */ + pei_data->dimm_channel0_disabled = 2; + pei_data->dimm_channel1_disabled = 2; + + memcpy(pei_data->dq_map, dq_map, sizeof(dq_map)); + memcpy(pei_data->dqs_map, dqs_map, sizeof(dqs_map)); + + /* P0: HOST PORT */ + pei_data_usb2_port(pei_data, 0, 0x0080, 1, 0, + USB_PORT_BACK_PANEL); + /* P1: HOST PORT */ + pei_data_usb2_port(pei_data, 1, 0x0080, 1, 1, + USB_PORT_BACK_PANEL); + /* P2: RAIDEN */ + pei_data_usb2_port(pei_data, 2, 0x0080, 1, USB_OC_PIN_SKIP, + USB_PORT_BACK_PANEL); + /* P3: SD CARD */ + pei_data_usb2_port(pei_data, 3, 0x0040, 1, USB_OC_PIN_SKIP, + USB_PORT_INTERNAL); + /* P4: RAIDEN */ + pei_data_usb2_port(pei_data, 4, 0x0080, 1, USB_OC_PIN_SKIP, + USB_PORT_BACK_PANEL); + /* P5: WWAN (Disabled) */ + pei_data_usb2_port(pei_data, 5, 0x0000, 0, USB_OC_PIN_SKIP, + USB_PORT_SKIP); + /* P6: CAMERA */ + pei_data_usb2_port(pei_data, 6, 0x0040, 1, USB_OC_PIN_SKIP, + USB_PORT_INTERNAL); + /* P7: BT */ + pei_data_usb2_port(pei_data, 7, 0x0040, 1, USB_OC_PIN_SKIP, + USB_PORT_INTERNAL); + + /* P1: HOST PORT */ + pei_data_usb3_port(pei_data, 0, 1, 0, 0); + /* P2: HOST PORT */ + pei_data_usb3_port(pei_data, 1, 1, 1, 0); + /* P3: RAIDEN */ + pei_data_usb3_port(pei_data, 2, 1, USB_OC_PIN_SKIP, 0); + /* P4: RAIDEN */ + pei_data_usb3_port(pei_data, 3, 1, USB_OC_PIN_SKIP, 0); +} static int broadwell_northbridge_early_init(struct udevice *dev) { diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c index 1b9f9840c6..b8450cc9d2 100644 --- a/arch/x86/cpu/broadwell/sdram.c +++ b/arch/x86/cpu/broadwell/sdram.c @@ -34,99 +34,6 @@ int dram_init_banksize(void) return 0; } -void broadwell_fill_pei_data(struct pei_data *pei_data) -{ - pei_data->pei_version = PEI_VERSION; - pei_data->board_type = BOARD_TYPE_ULT; - pei_data->pciexbar = MCFG_BASE_ADDRESS; - pei_data->smbusbar = SMBUS_BASE_ADDRESS; - pei_data->ehcibar = EARLY_EHCI_BAR; - pei_data->xhcibar = EARLY_XHCI_BAR; - pei_data->gttbar = EARLY_GTT_BAR; - pei_data->pmbase = ACPI_BASE_ADDRESS; - pei_data->gpiobase = GPIO_BASE_ADDRESS; - pei_data->tseg_size = CONFIG_SMM_TSEG_SIZE; - pei_data->temp_mmio_base = EARLY_TEMP_MMIO; - pei_data->tx_byte = sdram_console_tx_byte; - pei_data->ddr_refresh_2x = 1; -} - -static inline void pei_data_usb2_port(struct pei_data *pei_data, int port, - uint16_t length, uint8_t enable, - uint8_t oc_pin, uint8_t location) -{ - pei_data->usb2_ports[port].length = length; - pei_data->usb2_ports[port].enable = enable; - pei_data->usb2_ports[port].oc_pin = oc_pin; - pei_data->usb2_ports[port].location = location; -} - -static inline void pei_data_usb3_port(struct pei_data *pei_data, int port, - uint8_t enable, uint8_t oc_pin, - uint8_t fixed_eq) -{ - pei_data->usb3_ports[port].enable = enable; - pei_data->usb3_ports[port].oc_pin = oc_pin; - pei_data->usb3_ports[port].fixed_eq = fixed_eq; -} - -void mainboard_fill_pei_data(struct pei_data *pei_data) -{ - /* DQ byte map for Samus board */ - const u8 dq_map[2][6][2] = { - { { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 }, - { 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } }, - { { 0x0F, 0xF0 }, { 0x00, 0xF0 }, { 0x0F, 0xF0 }, - { 0x0F, 0x00 }, { 0xFF, 0x00 }, { 0xFF, 0x00 } } }; - /* DQS CPU<>DRAM map for Samus board */ - const u8 dqs_map[2][8] = { - { 2, 0, 1, 3, 6, 4, 7, 5 }, - { 2, 1, 0, 3, 6, 5, 4, 7 } }; - - pei_data->ec_present = 1; - - /* One installed DIMM per channel */ - pei_data->dimm_channel0_disabled = 2; - pei_data->dimm_channel1_disabled = 2; - - memcpy(pei_data->dq_map, dq_map, sizeof(dq_map)); - memcpy(pei_data->dqs_map, dqs_map, sizeof(dqs_map)); - - /* P0: HOST PORT */ - pei_data_usb2_port(pei_data, 0, 0x0080, 1, 0, - USB_PORT_BACK_PANEL); - /* P1: HOST PORT */ - pei_data_usb2_port(pei_data, 1, 0x0080, 1, 1, - USB_PORT_BACK_PANEL); - /* P2: RAIDEN */ - pei_data_usb2_port(pei_data, 2, 0x0080, 1, USB_OC_PIN_SKIP, - USB_PORT_BACK_PANEL); - /* P3: SD CARD */ - pei_data_usb2_port(pei_data, 3, 0x0040, 1, USB_OC_PIN_SKIP, - USB_PORT_INTERNAL); - /* P4: RAIDEN */ - pei_data_usb2_port(pei_data, 4, 0x0080, 1, USB_OC_PIN_SKIP, - USB_PORT_BACK_PANEL); - /* P5: WWAN (Disabled) */ - pei_data_usb2_port(pei_data, 5, 0x0000, 0, USB_OC_PIN_SKIP, - USB_PORT_SKIP); - /* P6: CAMERA */ - pei_data_usb2_port(pei_data, 6, 0x0040, 1, USB_OC_PIN_SKIP, - USB_PORT_INTERNAL); - /* P7: BT */ - pei_data_usb2_port(pei_data, 7, 0x0040, 1, USB_OC_PIN_SKIP, - USB_PORT_INTERNAL); - - /* P1: HOST PORT */ - pei_data_usb3_port(pei_data, 0, 1, 0, 0); - /* P2: HOST PORT */ - pei_data_usb3_port(pei_data, 1, 1, 1, 0); - /* P3: RAIDEN */ - pei_data_usb3_port(pei_data, 2, 1, USB_OC_PIN_SKIP, 0); - /* P4: RAIDEN */ - pei_data_usb3_port(pei_data, 3, 1, USB_OC_PIN_SKIP, 0); -} - static unsigned long get_top_of_ram(struct udevice *dev) { /* From 6b83b29578907da0561b5055ad09d8d8dbcfb098 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:50 -0600 Subject: [PATCH 19/49] x86: broadwell: Move init of debug UART to cpu.c At present the debug UART is set up in sdram.c which is not the best place since it has nothing in particular to do with SDRAM. Since we want to support initing this in SPL too, move it to a common file. Signed-off-by: Simon Glass Reviewed-by: Bin Meng [bmeng: added 'broadwell' tag in the commit title] Signed-off-by: Bin Meng --- arch/x86/cpu/broadwell/cpu.c | 13 +++++++++++++ arch/x86/cpu/broadwell/sdram.c | 11 ----------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index 232fa40eb5..d53c7b863f 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -12,7 +12,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -156,6 +158,17 @@ int print_cpuinfo(void) return 0; } +void board_debug_uart_init(void) +{ + struct udevice *bus = NULL; + + /* com1 / com2 decode range */ + pci_x86_write_config(bus, PCH_DEV_LPC, LPC_IO_DEC, 1 << 4, PCI_SIZE_16); + + pci_x86_write_config(bus, PCH_DEV_LPC, LPC_EN, COMA_LPC_EN, + PCI_SIZE_16); +} + /* * The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate * the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c index b8450cc9d2..b31d78c092 100644 --- a/arch/x86/cpu/broadwell/sdram.c +++ b/arch/x86/cpu/broadwell/sdram.c @@ -194,17 +194,6 @@ int misc_init_r(void) return 0; } -void board_debug_uart_init(void) -{ - struct udevice *bus = NULL; - - /* com1 / com2 decode range */ - pci_x86_write_config(bus, PCH_DEV_LPC, LPC_IO_DEC, 1 << 4, PCI_SIZE_16); - - pci_x86_write_config(bus, PCH_DEV_LPC, LPC_EN, COMA_LPC_EN, - PCI_SIZE_16); -} - static const struct udevice_id broadwell_syscon_ids[] = { { .compatible = "intel,me", .data = X86_SYSCON_ME }, { } From 9231206b73a3eee6e68e4dd708abdb4e625eac71 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:51 -0600 Subject: [PATCH 20/49] x86: broadwell: Split CPU init Split the CPU init into two parts - the 'full' init which happens in the first U-Boot phase, and the rest of the init that happens on subsequent stages. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/broadwell/Makefile | 1 + arch/x86/cpu/broadwell/cpu.c | 673 ----------------------------- arch/x86/cpu/broadwell/cpu_full.c | 694 ++++++++++++++++++++++++++++++ 3 files changed, 695 insertions(+), 673 deletions(-) create mode 100644 arch/x86/cpu/broadwell/cpu_full.c diff --git a/arch/x86/cpu/broadwell/Makefile b/arch/x86/cpu/broadwell/Makefile index d464507e6c..8553615f67 100644 --- a/arch/x86/cpu/broadwell/Makefile +++ b/arch/x86/cpu/broadwell/Makefile @@ -4,6 +4,7 @@ obj-y += adsp.o obj-y += cpu.o +obj-y += cpu_full.o obj-y += iobp.o obj-y += lpc.o obj-y += me.o diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index d53c7b863f..bb7c361408 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -21,68 +21,6 @@ #include #include -struct cpu_broadwell_priv { - bool ht_disabled; -}; - -/* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */ -static const u8 power_limit_time_sec_to_msr[] = { - [0] = 0x00, - [1] = 0x0a, - [2] = 0x0b, - [3] = 0x4b, - [4] = 0x0c, - [5] = 0x2c, - [6] = 0x4c, - [7] = 0x6c, - [8] = 0x0d, - [10] = 0x2d, - [12] = 0x4d, - [14] = 0x6d, - [16] = 0x0e, - [20] = 0x2e, - [24] = 0x4e, - [28] = 0x6e, - [32] = 0x0f, - [40] = 0x2f, - [48] = 0x4f, - [56] = 0x6f, - [64] = 0x10, - [80] = 0x30, - [96] = 0x50, - [112] = 0x70, - [128] = 0x11, -}; - -/* Convert POWER_LIMIT_1_TIME MSR value to seconds */ -static const u8 power_limit_time_msr_to_sec[] = { - [0x00] = 0, - [0x0a] = 1, - [0x0b] = 2, - [0x4b] = 3, - [0x0c] = 4, - [0x2c] = 5, - [0x4c] = 6, - [0x6c] = 7, - [0x0d] = 8, - [0x2d] = 10, - [0x4d] = 12, - [0x6d] = 14, - [0x0e] = 16, - [0x2e] = 20, - [0x4e] = 24, - [0x6e] = 28, - [0x0f] = 32, - [0x2f] = 40, - [0x4f] = 48, - [0x6f] = 56, - [0x10] = 64, - [0x30] = 80, - [0x50] = 96, - [0x70] = 112, - [0x11] = 128, -}; - int arch_cpu_init_dm(void) { struct udevice *dev; @@ -168,614 +106,3 @@ void board_debug_uart_init(void) pci_x86_write_config(bus, PCH_DEV_LPC, LPC_EN, COMA_LPC_EN, PCI_SIZE_16); } - -/* - * The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate - * the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly - * when a core is woken up - */ -static int pcode_ready(void) -{ - int wait_count; - const int delay_step = 10; - - wait_count = 0; - do { - if (!(readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & - MAILBOX_RUN_BUSY)) - return 0; - wait_count += delay_step; - udelay(delay_step); - } while (wait_count < 1000); - - return -ETIMEDOUT; -} - -static u32 pcode_mailbox_read(u32 command) -{ - int ret; - - ret = pcode_ready(); - if (ret) { - debug("PCODE: mailbox timeout on wait ready\n"); - return ret; - } - - /* Send command and start transaction */ - writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); - - ret = pcode_ready(); - if (ret) { - debug("PCODE: mailbox timeout on completion\n"); - return ret; - } - - /* Read mailbox */ - return readl(MCHBAR_REG(BIOS_MAILBOX_DATA)); -} - -static int pcode_mailbox_write(u32 command, u32 data) -{ - int ret; - - ret = pcode_ready(); - if (ret) { - debug("PCODE: mailbox timeout on wait ready\n"); - return ret; - } - - writel(data, MCHBAR_REG(BIOS_MAILBOX_DATA)); - - /* Send command and start transaction */ - writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); - - ret = pcode_ready(); - if (ret) { - debug("PCODE: mailbox timeout on completion\n"); - return ret; - } - - return 0; -} - -/* @dev is the CPU device */ -static void initialize_vr_config(struct udevice *dev) -{ - int ramp, min_vid; - msr_t msr; - - debug("Initializing VR config\n"); - - /* Configure VR_CURRENT_CONFIG */ - msr = msr_read(MSR_VR_CURRENT_CONFIG); - /* - * Preserve bits 63 and 62. Bit 62 is PSI4 enable, but it is only valid - * on ULT systems - */ - msr.hi &= 0xc0000000; - msr.hi |= (0x01 << (52 - 32)); /* PSI3 threshold - 1A */ - msr.hi |= (0x05 << (42 - 32)); /* PSI2 threshold - 5A */ - msr.hi |= (0x14 << (32 - 32)); /* PSI1 threshold - 20A */ - msr.hi |= (1 << (62 - 32)); /* Enable PSI4 */ - /* Leave the max instantaneous current limit (12:0) to default */ - msr_write(MSR_VR_CURRENT_CONFIG, msr); - - /* Configure VR_MISC_CONFIG MSR */ - msr = msr_read(MSR_VR_MISC_CONFIG); - /* Set the IOUT_SLOPE scalar applied to dIout in U10.1.9 format */ - msr.hi &= ~(0x3ff << (40 - 32)); - msr.hi |= (0x200 << (40 - 32)); /* 1.0 */ - /* Set IOUT_OFFSET to 0 */ - msr.hi &= ~0xff; - /* Set entry ramp rate to slow */ - msr.hi &= ~(1 << (51 - 32)); - /* Enable decay mode on C-state entry */ - msr.hi |= (1 << (52 - 32)); - /* Set the slow ramp rate */ - msr.hi &= ~(0x3 << (53 - 32)); - /* Configure the C-state exit ramp rate */ - ramp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "intel,slow-ramp", -1); - if (ramp != -1) { - /* Configured slow ramp rate */ - msr.hi |= ((ramp & 0x3) << (53 - 32)); - /* Set exit ramp rate to slow */ - msr.hi &= ~(1 << (50 - 32)); - } else { - /* Fast ramp rate / 4 */ - msr.hi |= (0x01 << (53 - 32)); - /* Set exit ramp rate to fast */ - msr.hi |= (1 << (50 - 32)); - } - /* Set MIN_VID (31:24) to allow CPU to have full control */ - msr.lo &= ~0xff000000; - min_vid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "intel,min-vid", 0); - msr.lo |= (min_vid & 0xff) << 24; - msr_write(MSR_VR_MISC_CONFIG, msr); - - /* Configure VR_MISC_CONFIG2 MSR */ - msr = msr_read(MSR_VR_MISC_CONFIG2); - msr.lo &= ~0xffff; - /* - * Allow CPU to control minimum voltage completely (15:8) and - * set the fast ramp voltage in 10mV steps - */ - if (cpu_get_family_model() == BROADWELL_FAMILY_ULT) - msr.lo |= 0x006a; /* 1.56V */ - else - msr.lo |= 0x006f; /* 1.60V */ - msr_write(MSR_VR_MISC_CONFIG2, msr); - - /* Set C9/C10 VCC Min */ - pcode_mailbox_write(MAILBOX_BIOS_CMD_WRITE_C9C10_VOLTAGE, 0x1f1f); -} - -static int calibrate_24mhz_bclk(void) -{ - int err_code; - int ret; - - ret = pcode_ready(); - if (ret) - return ret; - - /* A non-zero value initiates the PCODE calibration */ - writel(~0, MCHBAR_REG(BIOS_MAILBOX_DATA)); - writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL, - MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); - - ret = pcode_ready(); - if (ret) - return ret; - - err_code = readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & 0xff; - - debug("PCODE: 24MHz BLCK calibration response: %d\n", err_code); - - /* Read the calibrated value */ - writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_READ_CALIBRATION, - MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); - - ret = pcode_ready(); - if (ret) - return ret; - - debug("PCODE: 24MHz BLCK calibration value: 0x%08x\n", - readl(MCHBAR_REG(BIOS_MAILBOX_DATA))); - - return 0; -} - -static void configure_pch_power_sharing(void) -{ - u32 pch_power, pch_power_ext, pmsync, pmsync2; - int i; - - /* Read PCH Power levels from PCODE */ - pch_power = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER); - pch_power_ext = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT); - - debug("PCH Power: PCODE Levels 0x%08x 0x%08x\n", pch_power, - pch_power_ext); - - pmsync = readl(RCB_REG(PMSYNC_CONFIG)); - pmsync2 = readl(RCB_REG(PMSYNC_CONFIG2)); - - /* - * Program PMSYNC_TPR_CONFIG PCH power limit values - * pmsync[0:4] = mailbox[0:5] - * pmsync[8:12] = mailbox[6:11] - * pmsync[16:20] = mailbox[12:17] - */ - for (i = 0; i < 3; i++) { - u32 level = pch_power & 0x3f; - pch_power >>= 6; - pmsync &= ~(0x1f << (i * 8)); - pmsync |= (level & 0x1f) << (i * 8); - } - writel(pmsync, RCB_REG(PMSYNC_CONFIG)); - - /* - * Program PMSYNC_TPR_CONFIG2 Extended PCH power limit values - * pmsync2[0:4] = mailbox[23:18] - * pmsync2[8:12] = mailbox_ext[6:11] - * pmsync2[16:20] = mailbox_ext[12:17] - * pmsync2[24:28] = mailbox_ext[18:22] - */ - pmsync2 &= ~0x1f; - pmsync2 |= pch_power & 0x1f; - - for (i = 1; i < 4; i++) { - u32 level = pch_power_ext & 0x3f; - pch_power_ext >>= 6; - pmsync2 &= ~(0x1f << (i * 8)); - pmsync2 |= (level & 0x1f) << (i * 8); - } - writel(pmsync2, RCB_REG(PMSYNC_CONFIG2)); -} - -static int bsp_init_before_ap_bringup(struct udevice *dev) -{ - int ret; - - initialize_vr_config(dev); - ret = calibrate_24mhz_bclk(); - if (ret) - return ret; - configure_pch_power_sharing(); - - return 0; -} - -int cpu_config_tdp_levels(void) -{ - msr_t platform_info; - - /* Bits 34:33 indicate how many levels supported */ - platform_info = msr_read(MSR_PLATFORM_INFO); - return (platform_info.hi >> 1) & 3; -} - -static void set_max_ratio(void) -{ - msr_t msr, perf_ctl; - - perf_ctl.hi = 0; - - /* Check for configurable TDP option */ - if (turbo_get_state() == TURBO_ENABLED) { - msr = msr_read(MSR_NHM_TURBO_RATIO_LIMIT); - perf_ctl.lo = (msr.lo & 0xff) << 8; - } else if (cpu_config_tdp_levels()) { - /* Set to nominal TDP ratio */ - msr = msr_read(MSR_CONFIG_TDP_NOMINAL); - perf_ctl.lo = (msr.lo & 0xff) << 8; - } else { - /* Platform Info bits 15:8 give max ratio */ - msr = msr_read(MSR_PLATFORM_INFO); - perf_ctl.lo = msr.lo & 0xff00; - } - msr_write(IA32_PERF_CTL, perf_ctl); - - debug("cpu: frequency set to %d\n", - ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); -} - -int broadwell_init(struct udevice *dev) -{ - struct cpu_broadwell_priv *priv = dev_get_priv(dev); - int num_threads; - int num_cores; - msr_t msr; - int ret; - - msr = msr_read(CORE_THREAD_COUNT_MSR); - num_threads = (msr.lo >> 0) & 0xffff; - num_cores = (msr.lo >> 16) & 0xffff; - debug("CPU has %u cores, %u threads enabled\n", num_cores, - num_threads); - - priv->ht_disabled = num_threads == num_cores; - - ret = bsp_init_before_ap_bringup(dev); - if (ret) - return ret; - - set_max_ratio(); - - return ret; -} - -static void configure_mca(void) -{ - msr_t msr; - const unsigned int mcg_cap_msr = 0x179; - int i; - int num_banks; - - msr = msr_read(mcg_cap_msr); - num_banks = msr.lo & 0xff; - msr.lo = 0; - msr.hi = 0; - /* - * TODO(adurbin): This should only be done on a cold boot. Also, some - * of these banks are core vs package scope. For now every CPU clears - * every bank - */ - for (i = 0; i < num_banks; i++) - msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr); -} - -static void enable_lapic_tpr(void) -{ - msr_t msr; - - msr = msr_read(MSR_PIC_MSG_CONTROL); - msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */ - msr_write(MSR_PIC_MSG_CONTROL, msr); -} - - -static void configure_c_states(void) -{ - msr_t msr; - - msr = msr_read(MSR_PMG_CST_CONFIG_CONTROL); - msr.lo |= (1 << 31); /* Timed MWAIT Enable */ - msr.lo |= (1 << 30); /* Package c-state Undemotion Enable */ - msr.lo |= (1 << 29); /* Package c-state Demotion Enable */ - msr.lo |= (1 << 28); /* C1 Auto Undemotion Enable */ - msr.lo |= (1 << 27); /* C3 Auto Undemotion Enable */ - msr.lo |= (1 << 26); /* C1 Auto Demotion Enable */ - msr.lo |= (1 << 25); /* C3 Auto Demotion Enable */ - msr.lo &= ~(1 << 10); /* Disable IO MWAIT redirection */ - /* The deepest package c-state defaults to factory-configured value */ - msr_write(MSR_PMG_CST_CONFIG_CONTROL, msr); - - msr = msr_read(MSR_MISC_PWR_MGMT); - msr.lo &= ~(1 << 0); /* Enable P-state HW_ALL coordination */ - msr_write(MSR_MISC_PWR_MGMT, msr); - - msr = msr_read(MSR_POWER_CTL); - msr.lo |= (1 << 18); /* Enable Energy Perf Bias MSR 0x1b0 */ - msr.lo |= (1 << 1); /* C1E Enable */ - msr.lo |= (1 << 0); /* Bi-directional PROCHOT# */ - msr_write(MSR_POWER_CTL, msr); - - /* C-state Interrupt Response Latency Control 0 - package C3 latency */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_0_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_0, msr); - - /* C-state Interrupt Response Latency Control 1 */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_1_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_1, msr); - - /* C-state Interrupt Response Latency Control 2 - package C6/C7 short */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_2_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_2, msr); - - /* C-state Interrupt Response Latency Control 3 - package C8 */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_3_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_3, msr); - - /* C-state Interrupt Response Latency Control 4 - package C9 */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_4_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_4, msr); - - /* C-state Interrupt Response Latency Control 5 - package C10 */ - msr.hi = 0; - msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_5_LIMIT; - msr_write(MSR_C_STATE_LATENCY_CONTROL_5, msr); -} - -static void configure_misc(void) -{ - msr_t msr; - - msr = msr_read(MSR_IA32_MISC_ENABLE); - msr.lo |= (1 << 0); /* Fast String enable */ - msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */ - msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */ - msr_write(MSR_IA32_MISC_ENABLE, msr); - - /* Disable thermal interrupts */ - msr.lo = 0; - msr.hi = 0; - msr_write(MSR_IA32_THERM_INTERRUPT, msr); - - /* Enable package critical interrupt only */ - msr.lo = 1 << 4; - msr.hi = 0; - msr_write(MSR_IA32_PACKAGE_THERM_INTERRUPT, msr); -} - -static void configure_thermal_target(struct udevice *dev) -{ - int tcc_offset; - msr_t msr; - - tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "intel,tcc-offset", 0); - - /* Set TCC activaiton offset if supported */ - msr = msr_read(MSR_PLATFORM_INFO); - if ((msr.lo & (1 << 30)) && tcc_offset) { - msr = msr_read(MSR_TEMPERATURE_TARGET); - msr.lo &= ~(0xf << 24); /* Bits 27:24 */ - msr.lo |= (tcc_offset & 0xf) << 24; - msr_write(MSR_TEMPERATURE_TARGET, msr); - } -} - -static void configure_dca_cap(void) -{ - struct cpuid_result cpuid_regs; - msr_t msr; - - /* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */ - cpuid_regs = cpuid(1); - if (cpuid_regs.ecx & (1 << 18)) { - msr = msr_read(MSR_IA32_PLATFORM_DCA_CAP); - msr.lo |= 1; - msr_write(MSR_IA32_PLATFORM_DCA_CAP, msr); - } -} - -static void set_energy_perf_bias(u8 policy) -{ - msr_t msr; - int ecx; - - /* Determine if energy efficient policy is supported */ - ecx = cpuid_ecx(0x6); - if (!(ecx & (1 << 3))) - return; - - /* Energy Policy is bits 3:0 */ - msr = msr_read(MSR_IA32_ENERGY_PERFORMANCE_BIAS); - msr.lo &= ~0xf; - msr.lo |= policy & 0xf; - msr_write(MSR_IA32_ENERGY_PERFORMANCE_BIAS, msr); - - debug("cpu: energy policy set to %u\n", policy); -} - -/* All CPUs including BSP will run the following function */ -static void cpu_core_init(struct udevice *dev) -{ - /* Clear out pending MCEs */ - configure_mca(); - - /* Enable the local cpu apics */ - enable_lapic_tpr(); - - /* Configure C States */ - configure_c_states(); - - /* Configure Enhanced SpeedStep and Thermal Sensors */ - configure_misc(); - - /* Thermal throttle activation offset */ - configure_thermal_target(dev); - - /* Enable Direct Cache Access */ - configure_dca_cap(); - - /* Set energy policy */ - set_energy_perf_bias(ENERGY_POLICY_NORMAL); - - /* Enable Turbo */ - turbo_enable(); -} - -/* - * Configure processor power limits if possible - * This must be done AFTER set of BIOS_RESET_CPL - */ -void cpu_set_power_limits(int power_limit_1_time) -{ - msr_t msr; - msr_t limit; - unsigned power_unit; - unsigned tdp, min_power, max_power, max_time; - u8 power_limit_1_val; - - msr = msr_read(MSR_PLATFORM_INFO); - if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr)) - power_limit_1_time = 28; - - if (!(msr.lo & PLATFORM_INFO_SET_TDP)) - return; - - /* Get units */ - msr = msr_read(MSR_PKG_POWER_SKU_UNIT); - power_unit = 2 << ((msr.lo & 0xf) - 1); - - /* Get power defaults for this SKU */ - msr = msr_read(MSR_PKG_POWER_SKU); - tdp = msr.lo & 0x7fff; - min_power = (msr.lo >> 16) & 0x7fff; - max_power = msr.hi & 0x7fff; - max_time = (msr.hi >> 16) & 0x7f; - - debug("CPU TDP: %u Watts\n", tdp / power_unit); - - if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time) - power_limit_1_time = power_limit_time_msr_to_sec[max_time]; - - if (min_power > 0 && tdp < min_power) - tdp = min_power; - - if (max_power > 0 && tdp > max_power) - tdp = max_power; - - power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time]; - - /* Set long term power limit to TDP */ - limit.lo = 0; - limit.lo |= tdp & PKG_POWER_LIMIT_MASK; - limit.lo |= PKG_POWER_LIMIT_EN; - limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) << - PKG_POWER_LIMIT_TIME_SHIFT; - - /* Set short term power limit to 1.25 * TDP */ - limit.hi = 0; - limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK; - limit.hi |= PKG_POWER_LIMIT_EN; - /* Power limit 2 time is only programmable on server SKU */ - - msr_write(MSR_PKG_POWER_LIMIT, limit); - - /* Set power limit values in MCHBAR as well */ - writel(limit.lo, MCHBAR_REG(MCH_PKG_POWER_LIMIT_LO)); - writel(limit.hi, MCHBAR_REG(MCH_PKG_POWER_LIMIT_HI)); - - /* Set DDR RAPL power limit by copying from MMIO to MSR */ - msr.lo = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_LO)); - msr.hi = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_HI)); - msr_write(MSR_DDR_RAPL_LIMIT, msr); - - /* Use nominal TDP values for CPUs with configurable TDP */ - if (cpu_config_tdp_levels()) { - msr = msr_read(MSR_CONFIG_TDP_NOMINAL); - limit.hi = 0; - limit.lo = msr.lo & 0xff; - msr_write(MSR_TURBO_ACTIVATION_RATIO, limit); - } -} - -static int broadwell_get_info(struct udevice *dev, struct cpu_info *info) -{ - msr_t msr; - - msr = msr_read(IA32_PERF_CTL); - info->cpu_freq = ((msr.lo >> 8) & 0xff) * BROADWELL_BCLK * 1000000; - info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | - 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; - - return 0; -} - -static int broadwell_get_count(struct udevice *dev) -{ - return 4; -} - -static int cpu_x86_broadwell_probe(struct udevice *dev) -{ - if (dev->seq == 0) { - cpu_core_init(dev); - return broadwell_init(dev); - } - - return 0; -} - -static const struct cpu_ops cpu_x86_broadwell_ops = { - .get_desc = cpu_x86_get_desc, - .get_info = broadwell_get_info, - .get_count = broadwell_get_count, - .get_vendor = cpu_x86_get_vendor, -}; - -static const struct udevice_id cpu_x86_broadwell_ids[] = { - { .compatible = "intel,core-i3-gen5" }, - { } -}; - -U_BOOT_DRIVER(cpu_x86_broadwell_drv) = { - .name = "cpu_x86_broadwell", - .id = UCLASS_CPU, - .of_match = cpu_x86_broadwell_ids, - .bind = cpu_x86_bind, - .probe = cpu_x86_broadwell_probe, - .ops = &cpu_x86_broadwell_ops, - .priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv), - .flags = DM_FLAG_PRE_RELOC, -}; diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c new file mode 100644 index 0000000000..c1db184549 --- /dev/null +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016 Google, Inc + * + * Based on code from coreboot src/soc/intel/broadwell/cpu.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct cpu_broadwell_priv { + bool ht_disabled; +}; + +/* Convert time in seconds to POWER_LIMIT_1_TIME MSR value */ +static const u8 power_limit_time_sec_to_msr[] = { + [0] = 0x00, + [1] = 0x0a, + [2] = 0x0b, + [3] = 0x4b, + [4] = 0x0c, + [5] = 0x2c, + [6] = 0x4c, + [7] = 0x6c, + [8] = 0x0d, + [10] = 0x2d, + [12] = 0x4d, + [14] = 0x6d, + [16] = 0x0e, + [20] = 0x2e, + [24] = 0x4e, + [28] = 0x6e, + [32] = 0x0f, + [40] = 0x2f, + [48] = 0x4f, + [56] = 0x6f, + [64] = 0x10, + [80] = 0x30, + [96] = 0x50, + [112] = 0x70, + [128] = 0x11, +}; + +/* Convert POWER_LIMIT_1_TIME MSR value to seconds */ +static const u8 power_limit_time_msr_to_sec[] = { + [0x00] = 0, + [0x0a] = 1, + [0x0b] = 2, + [0x4b] = 3, + [0x0c] = 4, + [0x2c] = 5, + [0x4c] = 6, + [0x6c] = 7, + [0x0d] = 8, + [0x2d] = 10, + [0x4d] = 12, + [0x6d] = 14, + [0x0e] = 16, + [0x2e] = 20, + [0x4e] = 24, + [0x6e] = 28, + [0x0f] = 32, + [0x2f] = 40, + [0x4f] = 48, + [0x6f] = 56, + [0x10] = 64, + [0x30] = 80, + [0x50] = 96, + [0x70] = 112, + [0x11] = 128, +}; + +/* + * The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate + * the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly + * when a core is woken up + */ +static int pcode_ready(void) +{ + int wait_count; + const int delay_step = 10; + + wait_count = 0; + do { + if (!(readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & + MAILBOX_RUN_BUSY)) + return 0; + wait_count += delay_step; + udelay(delay_step); + } while (wait_count < 1000); + + return -ETIMEDOUT; +} + +static u32 pcode_mailbox_read(u32 command) +{ + int ret; + + ret = pcode_ready(); + if (ret) { + debug("PCODE: mailbox timeout on wait ready\n"); + return ret; + } + + /* Send command and start transaction */ + writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); + + ret = pcode_ready(); + if (ret) { + debug("PCODE: mailbox timeout on completion\n"); + return ret; + } + + /* Read mailbox */ + return readl(MCHBAR_REG(BIOS_MAILBOX_DATA)); +} + +static int pcode_mailbox_write(u32 command, u32 data) +{ + int ret; + + ret = pcode_ready(); + if (ret) { + debug("PCODE: mailbox timeout on wait ready\n"); + return ret; + } + + writel(data, MCHBAR_REG(BIOS_MAILBOX_DATA)); + + /* Send command and start transaction */ + writel(command | MAILBOX_RUN_BUSY, MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); + + ret = pcode_ready(); + if (ret) { + debug("PCODE: mailbox timeout on completion\n"); + return ret; + } + + return 0; +} + +/* @dev is the CPU device */ +static void initialize_vr_config(struct udevice *dev) +{ + int ramp, min_vid; + msr_t msr; + + debug("Initializing VR config\n"); + + /* Configure VR_CURRENT_CONFIG */ + msr = msr_read(MSR_VR_CURRENT_CONFIG); + /* + * Preserve bits 63 and 62. Bit 62 is PSI4 enable, but it is only valid + * on ULT systems + */ + msr.hi &= 0xc0000000; + msr.hi |= (0x01 << (52 - 32)); /* PSI3 threshold - 1A */ + msr.hi |= (0x05 << (42 - 32)); /* PSI2 threshold - 5A */ + msr.hi |= (0x14 << (32 - 32)); /* PSI1 threshold - 20A */ + msr.hi |= (1 << (62 - 32)); /* Enable PSI4 */ + /* Leave the max instantaneous current limit (12:0) to default */ + msr_write(MSR_VR_CURRENT_CONFIG, msr); + + /* Configure VR_MISC_CONFIG MSR */ + msr = msr_read(MSR_VR_MISC_CONFIG); + /* Set the IOUT_SLOPE scalar applied to dIout in U10.1.9 format */ + msr.hi &= ~(0x3ff << (40 - 32)); + msr.hi |= (0x200 << (40 - 32)); /* 1.0 */ + /* Set IOUT_OFFSET to 0 */ + msr.hi &= ~0xff; + /* Set entry ramp rate to slow */ + msr.hi &= ~(1 << (51 - 32)); + /* Enable decay mode on C-state entry */ + msr.hi |= (1 << (52 - 32)); + /* Set the slow ramp rate */ + msr.hi &= ~(0x3 << (53 - 32)); + /* Configure the C-state exit ramp rate */ + ramp = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "intel,slow-ramp", -1); + if (ramp != -1) { + /* Configured slow ramp rate */ + msr.hi |= ((ramp & 0x3) << (53 - 32)); + /* Set exit ramp rate to slow */ + msr.hi &= ~(1 << (50 - 32)); + } else { + /* Fast ramp rate / 4 */ + msr.hi |= (0x01 << (53 - 32)); + /* Set exit ramp rate to fast */ + msr.hi |= (1 << (50 - 32)); + } + /* Set MIN_VID (31:24) to allow CPU to have full control */ + msr.lo &= ~0xff000000; + min_vid = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "intel,min-vid", 0); + msr.lo |= (min_vid & 0xff) << 24; + msr_write(MSR_VR_MISC_CONFIG, msr); + + /* Configure VR_MISC_CONFIG2 MSR */ + msr = msr_read(MSR_VR_MISC_CONFIG2); + msr.lo &= ~0xffff; + /* + * Allow CPU to control minimum voltage completely (15:8) and + * set the fast ramp voltage in 10mV steps + */ + if (cpu_get_family_model() == BROADWELL_FAMILY_ULT) + msr.lo |= 0x006a; /* 1.56V */ + else + msr.lo |= 0x006f; /* 1.60V */ + msr_write(MSR_VR_MISC_CONFIG2, msr); + + /* Set C9/C10 VCC Min */ + pcode_mailbox_write(MAILBOX_BIOS_CMD_WRITE_C9C10_VOLTAGE, 0x1f1f); +} + +static int calibrate_24mhz_bclk(void) +{ + int err_code; + int ret; + + ret = pcode_ready(); + if (ret) + return ret; + + /* A non-zero value initiates the PCODE calibration */ + writel(~0, MCHBAR_REG(BIOS_MAILBOX_DATA)); + writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_FSM_MEASURE_INTVL, + MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); + + ret = pcode_ready(); + if (ret) + return ret; + + err_code = readl(MCHBAR_REG(BIOS_MAILBOX_INTERFACE)) & 0xff; + + debug("PCODE: 24MHz BLCK calibration response: %d\n", err_code); + + /* Read the calibrated value */ + writel(MAILBOX_RUN_BUSY | MAILBOX_BIOS_CMD_READ_CALIBRATION, + MCHBAR_REG(BIOS_MAILBOX_INTERFACE)); + + ret = pcode_ready(); + if (ret) + return ret; + + debug("PCODE: 24MHz BLCK calibration value: 0x%08x\n", + readl(MCHBAR_REG(BIOS_MAILBOX_DATA))); + + return 0; +} + +static void configure_pch_power_sharing(void) +{ + u32 pch_power, pch_power_ext, pmsync, pmsync2; + int i; + + /* Read PCH Power levels from PCODE */ + pch_power = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER); + pch_power_ext = pcode_mailbox_read(MAILBOX_BIOS_CMD_READ_PCH_POWER_EXT); + + debug("PCH Power: PCODE Levels 0x%08x 0x%08x\n", pch_power, + pch_power_ext); + + pmsync = readl(RCB_REG(PMSYNC_CONFIG)); + pmsync2 = readl(RCB_REG(PMSYNC_CONFIG2)); + + /* + * Program PMSYNC_TPR_CONFIG PCH power limit values + * pmsync[0:4] = mailbox[0:5] + * pmsync[8:12] = mailbox[6:11] + * pmsync[16:20] = mailbox[12:17] + */ + for (i = 0; i < 3; i++) { + u32 level = pch_power & 0x3f; + + pch_power >>= 6; + pmsync &= ~(0x1f << (i * 8)); + pmsync |= (level & 0x1f) << (i * 8); + } + writel(pmsync, RCB_REG(PMSYNC_CONFIG)); + + /* + * Program PMSYNC_TPR_CONFIG2 Extended PCH power limit values + * pmsync2[0:4] = mailbox[23:18] + * pmsync2[8:12] = mailbox_ext[6:11] + * pmsync2[16:20] = mailbox_ext[12:17] + * pmsync2[24:28] = mailbox_ext[18:22] + */ + pmsync2 &= ~0x1f; + pmsync2 |= pch_power & 0x1f; + + for (i = 1; i < 4; i++) { + u32 level = pch_power_ext & 0x3f; + + pch_power_ext >>= 6; + pmsync2 &= ~(0x1f << (i * 8)); + pmsync2 |= (level & 0x1f) << (i * 8); + } + writel(pmsync2, RCB_REG(PMSYNC_CONFIG2)); +} + +static int bsp_init_before_ap_bringup(struct udevice *dev) +{ + int ret; + + initialize_vr_config(dev); + ret = calibrate_24mhz_bclk(); + if (ret) + return ret; + configure_pch_power_sharing(); + + return 0; +} + +static int cpu_config_tdp_levels(void) +{ + msr_t platform_info; + + /* Bits 34:33 indicate how many levels supported */ + platform_info = msr_read(MSR_PLATFORM_INFO); + return (platform_info.hi >> 1) & 3; +} + +static void set_max_ratio(void) +{ + msr_t msr, perf_ctl; + + perf_ctl.hi = 0; + + /* Check for configurable TDP option */ + if (turbo_get_state() == TURBO_ENABLED) { + msr = msr_read(MSR_NHM_TURBO_RATIO_LIMIT); + perf_ctl.lo = (msr.lo & 0xff) << 8; + } else if (cpu_config_tdp_levels()) { + /* Set to nominal TDP ratio */ + msr = msr_read(MSR_CONFIG_TDP_NOMINAL); + perf_ctl.lo = (msr.lo & 0xff) << 8; + } else { + /* Platform Info bits 15:8 give max ratio */ + msr = msr_read(MSR_PLATFORM_INFO); + perf_ctl.lo = msr.lo & 0xff00; + } + msr_write(IA32_PERF_CTL, perf_ctl); + + debug("cpu: frequency set to %d\n", + ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); +} + +int broadwell_init(struct udevice *dev) +{ + struct cpu_broadwell_priv *priv = dev_get_priv(dev); + int num_threads; + int num_cores; + msr_t msr; + int ret; + + msr = msr_read(CORE_THREAD_COUNT_MSR); + num_threads = (msr.lo >> 0) & 0xffff; + num_cores = (msr.lo >> 16) & 0xffff; + debug("CPU has %u cores, %u threads enabled\n", num_cores, + num_threads); + + priv->ht_disabled = num_threads == num_cores; + + ret = bsp_init_before_ap_bringup(dev); + if (ret) + return ret; + + set_max_ratio(); + + return ret; +} + +static void configure_mca(void) +{ + msr_t msr; + const unsigned int mcg_cap_msr = 0x179; + int i; + int num_banks; + + msr = msr_read(mcg_cap_msr); + num_banks = msr.lo & 0xff; + msr.lo = 0; + msr.hi = 0; + /* + * TODO(adurbin): This should only be done on a cold boot. Also, some + * of these banks are core vs package scope. For now every CPU clears + * every bank + */ + for (i = 0; i < num_banks; i++) + msr_write(MSR_IA32_MC0_STATUS + (i * 4), msr); +} + +static void enable_lapic_tpr(void) +{ + msr_t msr; + + msr = msr_read(MSR_PIC_MSG_CONTROL); + msr.lo &= ~(1 << 10); /* Enable APIC TPR updates */ + msr_write(MSR_PIC_MSG_CONTROL, msr); +} + +static void configure_c_states(void) +{ + msr_t msr; + + msr = msr_read(MSR_PMG_CST_CONFIG_CONTROL); + msr.lo |= (1 << 31); /* Timed MWAIT Enable */ + msr.lo |= (1 << 30); /* Package c-state Undemotion Enable */ + msr.lo |= (1 << 29); /* Package c-state Demotion Enable */ + msr.lo |= (1 << 28); /* C1 Auto Undemotion Enable */ + msr.lo |= (1 << 27); /* C3 Auto Undemotion Enable */ + msr.lo |= (1 << 26); /* C1 Auto Demotion Enable */ + msr.lo |= (1 << 25); /* C3 Auto Demotion Enable */ + msr.lo &= ~(1 << 10); /* Disable IO MWAIT redirection */ + /* The deepest package c-state defaults to factory-configured value */ + msr_write(MSR_PMG_CST_CONFIG_CONTROL, msr); + + msr = msr_read(MSR_MISC_PWR_MGMT); + msr.lo &= ~(1 << 0); /* Enable P-state HW_ALL coordination */ + msr_write(MSR_MISC_PWR_MGMT, msr); + + msr = msr_read(MSR_POWER_CTL); + msr.lo |= (1 << 18); /* Enable Energy Perf Bias MSR 0x1b0 */ + msr.lo |= (1 << 1); /* C1E Enable */ + msr.lo |= (1 << 0); /* Bi-directional PROCHOT# */ + msr_write(MSR_POWER_CTL, msr); + + /* C-state Interrupt Response Latency Control 0 - package C3 latency */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_0_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_0, msr); + + /* C-state Interrupt Response Latency Control 1 */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_1_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_1, msr); + + /* C-state Interrupt Response Latency Control 2 - package C6/C7 short */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_2_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_2, msr); + + /* C-state Interrupt Response Latency Control 3 - package C8 */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_3_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_3, msr); + + /* C-state Interrupt Response Latency Control 4 - package C9 */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_4_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_4, msr); + + /* C-state Interrupt Response Latency Control 5 - package C10 */ + msr.hi = 0; + msr.lo = IRTL_VALID | IRTL_1024_NS | C_STATE_LATENCY_CONTROL_5_LIMIT; + msr_write(MSR_C_STATE_LATENCY_CONTROL_5, msr); +} + +static void configure_misc(void) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_MISC_ENABLE); + msr.lo |= (1 << 0); /* Fast String enable */ + msr.lo |= (1 << 3); /* TM1/TM2/EMTTM enable */ + msr.lo |= (1 << 16); /* Enhanced SpeedStep Enable */ + msr_write(MSR_IA32_MISC_ENABLE, msr); + + /* Disable thermal interrupts */ + msr.lo = 0; + msr.hi = 0; + msr_write(MSR_IA32_THERM_INTERRUPT, msr); + + /* Enable package critical interrupt only */ + msr.lo = 1 << 4; + msr.hi = 0; + msr_write(MSR_IA32_PACKAGE_THERM_INTERRUPT, msr); +} + +static void configure_thermal_target(struct udevice *dev) +{ + int tcc_offset; + msr_t msr; + + tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "intel,tcc-offset", 0); + + /* Set TCC activaiton offset if supported */ + msr = msr_read(MSR_PLATFORM_INFO); + if ((msr.lo & (1 << 30)) && tcc_offset) { + msr = msr_read(MSR_TEMPERATURE_TARGET); + msr.lo &= ~(0xf << 24); /* Bits 27:24 */ + msr.lo |= (tcc_offset & 0xf) << 24; + msr_write(MSR_TEMPERATURE_TARGET, msr); + } +} + +static void configure_dca_cap(void) +{ + struct cpuid_result cpuid_regs; + msr_t msr; + + /* Check feature flag in CPUID.(EAX=1):ECX[18]==1 */ + cpuid_regs = cpuid(1); + if (cpuid_regs.ecx & (1 << 18)) { + msr = msr_read(MSR_IA32_PLATFORM_DCA_CAP); + msr.lo |= 1; + msr_write(MSR_IA32_PLATFORM_DCA_CAP, msr); + } +} + +static void set_energy_perf_bias(u8 policy) +{ + msr_t msr; + int ecx; + + /* Determine if energy efficient policy is supported */ + ecx = cpuid_ecx(0x6); + if (!(ecx & (1 << 3))) + return; + + /* Energy Policy is bits 3:0 */ + msr = msr_read(MSR_IA32_ENERGY_PERFORMANCE_BIAS); + msr.lo &= ~0xf; + msr.lo |= policy & 0xf; + msr_write(MSR_IA32_ENERGY_PERFORMANCE_BIAS, msr); + + debug("cpu: energy policy set to %u\n", policy); +} + +/* All CPUs including BSP will run the following function */ +static void cpu_core_init(struct udevice *dev) +{ + /* Clear out pending MCEs */ + configure_mca(); + + /* Enable the local cpu apics */ + enable_lapic_tpr(); + + /* Configure C States */ + configure_c_states(); + + /* Configure Enhanced SpeedStep and Thermal Sensors */ + configure_misc(); + + /* Thermal throttle activation offset */ + configure_thermal_target(dev); + + /* Enable Direct Cache Access */ + configure_dca_cap(); + + /* Set energy policy */ + set_energy_perf_bias(ENERGY_POLICY_NORMAL); + + /* Enable Turbo */ + turbo_enable(); +} + +/* + * Configure processor power limits if possible + * This must be done AFTER set of BIOS_RESET_CPL + */ +void cpu_set_power_limits(int power_limit_1_time) +{ + msr_t msr; + msr_t limit; + uint power_unit; + uint tdp, min_power, max_power, max_time; + u8 power_limit_1_val; + + msr = msr_read(MSR_PLATFORM_INFO); + if (power_limit_1_time > ARRAY_SIZE(power_limit_time_sec_to_msr)) + power_limit_1_time = 28; + + if (!(msr.lo & PLATFORM_INFO_SET_TDP)) + return; + + /* Get units */ + msr = msr_read(MSR_PKG_POWER_SKU_UNIT); + power_unit = 2 << ((msr.lo & 0xf) - 1); + + /* Get power defaults for this SKU */ + msr = msr_read(MSR_PKG_POWER_SKU); + tdp = msr.lo & 0x7fff; + min_power = (msr.lo >> 16) & 0x7fff; + max_power = msr.hi & 0x7fff; + max_time = (msr.hi >> 16) & 0x7f; + + debug("CPU TDP: %u Watts\n", tdp / power_unit); + + if (power_limit_time_msr_to_sec[max_time] > power_limit_1_time) + power_limit_1_time = power_limit_time_msr_to_sec[max_time]; + + if (min_power > 0 && tdp < min_power) + tdp = min_power; + + if (max_power > 0 && tdp > max_power) + tdp = max_power; + + power_limit_1_val = power_limit_time_sec_to_msr[power_limit_1_time]; + + /* Set long term power limit to TDP */ + limit.lo = 0; + limit.lo |= tdp & PKG_POWER_LIMIT_MASK; + limit.lo |= PKG_POWER_LIMIT_EN; + limit.lo |= (power_limit_1_val & PKG_POWER_LIMIT_TIME_MASK) << + PKG_POWER_LIMIT_TIME_SHIFT; + + /* Set short term power limit to 1.25 * TDP */ + limit.hi = 0; + limit.hi |= ((tdp * 125) / 100) & PKG_POWER_LIMIT_MASK; + limit.hi |= PKG_POWER_LIMIT_EN; + /* Power limit 2 time is only programmable on server SKU */ + + msr_write(MSR_PKG_POWER_LIMIT, limit); + + /* Set power limit values in MCHBAR as well */ + writel(limit.lo, MCHBAR_REG(MCH_PKG_POWER_LIMIT_LO)); + writel(limit.hi, MCHBAR_REG(MCH_PKG_POWER_LIMIT_HI)); + + /* Set DDR RAPL power limit by copying from MMIO to MSR */ + msr.lo = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_LO)); + msr.hi = readl(MCHBAR_REG(MCH_DDR_POWER_LIMIT_HI)); + msr_write(MSR_DDR_RAPL_LIMIT, msr); + + /* Use nominal TDP values for CPUs with configurable TDP */ + if (cpu_config_tdp_levels()) { + msr = msr_read(MSR_CONFIG_TDP_NOMINAL); + limit.hi = 0; + limit.lo = msr.lo & 0xff; + msr_write(MSR_TURBO_ACTIVATION_RATIO, limit); + } +} + +static int broadwell_get_info(struct udevice *dev, struct cpu_info *info) +{ + msr_t msr; + + msr = msr_read(IA32_PERF_CTL); + info->cpu_freq = ((msr.lo >> 8) & 0xff) * BROADWELL_BCLK * 1000000; + info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | + 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; + + return 0; +} + +static int broadwell_get_count(struct udevice *dev) +{ + return 4; +} + +static int cpu_x86_broadwell_probe(struct udevice *dev) +{ + if (dev->seq == 0) { + cpu_core_init(dev); + return broadwell_init(dev); + } + + return 0; +} + +static const struct cpu_ops cpu_x86_broadwell_ops = { + .get_desc = cpu_x86_get_desc, + .get_info = broadwell_get_info, + .get_count = broadwell_get_count, + .get_vendor = cpu_x86_get_vendor, +}; + +static const struct udevice_id cpu_x86_broadwell_ids[] = { + { .compatible = "intel,core-i3-gen5" }, + { } +}; + +U_BOOT_DRIVER(cpu_x86_broadwell_drv) = { + .name = "cpu_x86_broadwell", + .id = UCLASS_CPU, + .of_match = cpu_x86_broadwell_ids, + .bind = cpu_x86_bind, + .probe = cpu_x86_broadwell_probe, + .ops = &cpu_x86_broadwell_ops, + .priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv), + .flags = DM_FLAG_PRE_RELOC, +}; From 051c31b7a49933f25bcf2ffe8c7764642fcff0d4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:52 -0600 Subject: [PATCH 21/49] x86: Add support for starting from SPL/TPL When a previous phase of U-Boot has run we need to adjust the init of subsequent states to avoid messing up the CPU state. Add a new version of the start logic for SPL, when it boots from TPL (start_from tpl.c) and a new version for U-Boot when it boots from SPL. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/Makefile | 12 ++++++ arch/x86/cpu/Makefile | 15 +++++++- arch/x86/cpu/start_from_spl.S | 71 +++++++++++++++++++++++++++++++++++ arch/x86/cpu/start_from_tpl.S | 49 ++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 arch/x86/cpu/start_from_spl.S create mode 100644 arch/x86/cpu/start_from_tpl.S diff --git a/arch/x86/Makefile b/arch/x86/Makefile index fec14847cc..9fd6cf2d3b 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -4,9 +4,21 @@ ifeq ($(CONFIG_EFI_APP),) ifdef CONFIG_$(SPL_)X86_64 head-y := arch/x86/cpu/start64.o else +ifeq ($(CONFIG_$(SPL_TPL_)X86_16BIT_INIT),y) head-y := arch/x86/cpu/start.o +else +ifndef CONFIG_SPL +head-y := arch/x86/cpu/start.o +else +ifdef CONFIG_SPL_BUILD +head-y = arch/x86/cpu/start_from_tpl.o +else +head-y = arch/x86/cpu/start_from_spl.o endif endif +endif +endif +endif # EFI head-$(CONFIG_$(SPL_)X86_16BIT_INIT) += arch/x86/cpu/start16.o head-$(CONFIG_$(SPL_)X86_16BIT_INIT) += arch/x86/cpu/resetvec.o diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 54668aab24..85fd5e616e 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -9,9 +9,22 @@ ifeq ($(CONFIG_$(SPL_)X86_64),y) extra-y = start64.o else +ifeq ($(CONFIG_$(SPL_TPL_)X86_16BIT_INIT),y) extra-y = start.o +else +ifndef CONFIG_SPL +extra-y = start.o +else +ifdef CONFIG_SPL_BUILD +extra-y = start_from_tpl.o +else +extra-y = start_from_spl.o endif -extra-$(CONFIG_$(SPL_)X86_16BIT_INIT) += resetvec.o start16.o +endif +endif +endif + +extra-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += resetvec.o start16.o obj-y += cpu.o cpu_x86.o diff --git a/arch/x86/cpu/start_from_spl.S b/arch/x86/cpu/start_from_spl.S new file mode 100644 index 0000000000..4d4e5d0758 --- /dev/null +++ b/arch/x86/cpu/start_from_spl.S @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * 32-bit x86 Startup Code when running from SPL + * + * Copyright 2018 Google, Inc + * Written by Simon Glass + */ + +#include + +.section .text.start +.code32 +.globl _start +.type _start, @function +_start: + /* Set up memory using the existing stack */ + movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %eax +#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE + subl $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %eax +#endif + /* + * We don't subject CONFIG_DCACHE_RAM_MRC_VAR_SIZE since memory is + * already set up. This has the happy side-effect of putting gd in a + * new place separate from SPL, so the memset() in + * board_init_f_init_reserve() does not cause any problems (otherwise + * it would zero out the gd and crash) + */ + call board_init_f_alloc_reserve + mov %eax, %esp + + call board_init_f_init_reserve + + xorl %eax, %eax + call board_init_f + call board_init_f_r + + /* Should not return here */ + jmp . + +.globl board_init_f_r_trampoline +.type board_init_f_r_trampoline, @function +board_init_f_r_trampoline: + /* + * SPL has been executed and SDRAM has been initialised, U-Boot code + * has been copied into RAM, BSS has been cleared and relocation + * adjustments have been made. It is now time to jump into the in-RAM + * copy of U-Boot + * + * %eax = Address of top of new stack + */ + + /* Stack grows down from top of SDRAM */ + movl %eax, %esp + + /* Re-enter U-Boot by calling board_init_f_r() */ + call board_init_f_r + +die: + hlt + jmp die + hlt + + .align 4 +_dt_ucode_base_size: + /* These next two fields are filled in by binman */ +.globl ucode_base +ucode_base: /* Declared in microcode.h */ + .long 0 /* microcode base */ +.globl ucode_size +ucode_size: /* Declared in microcode.h */ + .long 0 /* microcode size */ diff --git a/arch/x86/cpu/start_from_tpl.S b/arch/x86/cpu/start_from_tpl.S new file mode 100644 index 0000000000..44b5363a68 --- /dev/null +++ b/arch/x86/cpu/start_from_tpl.S @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * 32-bit x86 Startup Code when running from TPL + * + * Copyright 2018 Google, Inc + * Written by Simon Glass + */ + +#include + +.section .text.start +.code32 +.globl _start +.type _start, @function +_start: + /* Set up memory using the existing stack */ + mov %esp, %eax + call board_init_f_alloc_reserve + mov %eax, %esp + + call board_init_f_init_reserve + + xorl %eax, %eax + call board_init_f + call board_init_f_r + + /* Should not return here */ + jmp . + +.globl board_init_f_r_trampoline +.type board_init_f_r_trampoline, @function +board_init_f_r_trampoline: + /* + * TPL has been executed: SDRAM has been initialised, BSS has been + * cleared. + * + * %eax = Address of top of new stack + */ + + /* Stack grows down from top of SDRAM */ + movl %eax, %esp + + /* Re-enter SPL by calling board_init_f_r() */ + call board_init_f_r + +die: + hlt + jmp die + hlt From d68574a72da5376784cbf3a553d82c6acfcd6824 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:53 -0600 Subject: [PATCH 22/49] x86: Allow 16-bit init to be in TPL At present we support having 16-bit init be in SPL or U-Boot proper, but not TPL. Add support for this so that TPL can boot. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- Makefile | 1 + arch/x86/Makefile | 4 ++-- arch/x86/cpu/intel_common/Makefile | 2 +- arch/x86/cpu/u-boot-spl.lds | 2 +- scripts/Makefile.spl | 10 +++++++++- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 5ae5db591f..9fb90c0779 100644 --- a/Makefile +++ b/Makefile @@ -1380,6 +1380,7 @@ cmd_ldr = $(LD) $(LDFLAGS_$(@F)) \ u-boot.rom: u-boot-x86-16bit.bin u-boot.bin \ $(if $(CONFIG_SPL_X86_16BIT_INIT),spl/u-boot-spl.bin) \ + $(if $(CONFIG_TPL_X86_16BIT_INIT),tpl/u-boot-tpl.bin) \ $(if $(CONFIG_HAVE_REFCODE),refcode.bin) FORCE $(call if_changed,binman) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 9fd6cf2d3b..f1afc74fff 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -20,8 +20,8 @@ endif endif endif # EFI -head-$(CONFIG_$(SPL_)X86_16BIT_INIT) += arch/x86/cpu/start16.o -head-$(CONFIG_$(SPL_)X86_16BIT_INIT) += arch/x86/cpu/resetvec.o +head-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += arch/x86/cpu/start16.o +head-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += arch/x86/cpu/resetvec.o libs-y += arch/x86/cpu/ libs-y += arch/x86/lib/ diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index bf798c287f..80fbc7ab66 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -3,7 +3,7 @@ # Copyright (c) 2016 Google, Inc ifdef CONFIG_HAVE_MRC -obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += car.o +obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += car.o obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += me_status.o obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += report_platform.o obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += mrc.o diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index 4e656dc4e5..f20c0b810d 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -54,7 +54,7 @@ SECTIONS /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } -#ifdef CONFIG_SPL_X86_16BIT_INIT +#if defined(CONFIG_SPL_X86_16BIT_INIT) || defined(CONFIG_TPL_X86_16BIT_INIT) /* * The following expressions place the 16-bit Real-Mode code and * Reset Vector at the end of the Flash ROM diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl index 8d76a2d400..7af6b120b6 100644 --- a/scripts/Makefile.spl +++ b/scripts/Makefile.spl @@ -228,7 +228,11 @@ ifeq ($(CONFIG_SYS_SOC),"at91") ALL-y += $(obj)/boot.bin endif +ifdef CONFIG_TPL_BUILD +ALL-$(CONFIG_TPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-16bit-tpl.bin +else ALL-$(CONFIG_SPL_X86_16BIT_INIT) += $(obj)/u-boot-x86-16bit-spl.bin +endif ALL-$(CONFIG_ARCH_ZYNQ) += $(obj)/boot.bin ALL-$(CONFIG_ARCH_ZYNQMP) += $(obj)/boot.bin @@ -328,7 +332,7 @@ quiet_cmd_objcopy = OBJCOPY $@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ OBJCOPYFLAGS_$(SPL_BIN)-nodtb.bin = $(SPL_OBJCFLAGS) -O binary \ - $(if $(CONFIG_SPL_X86_16BIT_INIT),-R .start16 -R .resetvec) + $(if $(CONFIG_$(SPL_TPL_)X86_16BIT_INIT),-R .start16 -R .resetvec) $(obj)/$(SPL_BIN)-nodtb.bin: $(obj)/$(SPL_BIN) FORCE $(call if_changed,objcopy) @@ -337,6 +341,10 @@ OBJCOPYFLAGS_u-boot-x86-16bit-spl.bin := -O binary -j .start16 -j .resetvec $(obj)/u-boot-x86-16bit-spl.bin: $(obj)/u-boot-spl FORCE $(call if_changed,objcopy) +OBJCOPYFLAGS_u-boot-x86-16bit-tpl.bin := -O binary -j .start16 -j .resetvec +$(obj)/u-boot-x86-16bit-tpl.bin: $(obj)/u-boot-tpl FORCE + $(call if_changed,objcopy) + LDFLAGS_$(SPL_BIN) += -T u-boot-spl.lds $(LDFLAGS_FINAL) # Avoid 'Not enough room for program headers' error on binutils 2.28 onwards. From 43294e67d67f2aa1309a8d6cc0e8f1605aa98734 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:54 -0600 Subject: [PATCH 23/49] x86: broadwell: Allow booting from SPL At present broadwell only supports booting straight into U-Boot proper. Add a separate init file to boot from SPL into U-Boot proper, and select it when SPL is in use. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/broadwell/Makefile | 15 +++++++ arch/x86/cpu/broadwell/cpu_from_spl.c | 63 +++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 arch/x86/cpu/broadwell/cpu_from_spl.c diff --git a/arch/x86/cpu/broadwell/Makefile b/arch/x86/cpu/broadwell/Makefile index 8553615f67..fbc778cda5 100644 --- a/arch/x86/cpu/broadwell/Makefile +++ b/arch/x86/cpu/broadwell/Makefile @@ -5,6 +5,21 @@ obj-y += adsp.o obj-y += cpu.o obj-y += cpu_full.o + +ifdef CONFIG_SPL +ifndef CONFIG_SPL_BUILD +obj-y += cpu_from_spl.o +obj-y += cpu_full.o +endif +ifndef CONFIG_SPL_BUILD +# obj-y += cpu_from_spl.o +endif +endif + +ifeq ($(CONFIG_$(SPL_TPL_)X86_32BIT_INIT),) +#obj-y += cpu_from_spl.o +endif + obj-y += iobp.o obj-y += lpc.o obj-y += me.o diff --git a/arch/x86/cpu/broadwell/cpu_from_spl.c b/arch/x86/cpu/broadwell/cpu_from_spl.c new file mode 100644 index 0000000000..c3d4a8d547 --- /dev/null +++ b/arch/x86/cpu/broadwell/cpu_from_spl.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2016 Google, Inc + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include + +int misc_init_r(void) +{ + return 0; +} + +int dram_init(void) +{ + struct spl_handoff *ho; + + ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(*ho)); + if (!ho) + return log_msg_ret("Missing SPL hand-off info", -ENOENT); + handoff_load_dram_size(ho); +#ifdef CONFIG_TPL + /* TODO(sjg@chromium.org): MTRR cannot be adjusted without a hang */ + mtrr_add_request(MTRR_TYPE_WRBACK, 0, 2ULL << 30); +#else + mtrr_add_request(MTRR_TYPE_WRBACK, 0, gd->ram_size); + mtrr_commit(true); +#endif + + return 0; +} + +int checkcpu(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + return 0; +} + +void board_debug_uart_init(void) +{ +} + +int dram_init_banksize(void) +{ +#ifdef CONFIG_NR_DRAM_BANKS + struct spl_handoff *ho; + + ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(*ho)); + if (!ho) + return log_msg_ret("Missing SPL hand-off info", -ENOENT); + handoff_load_dram_banks(ho); +#endif + + return 0; +} From c0052b6efd462ccfd43343b1cbd3460e5e3fe0dc Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:55 -0600 Subject: [PATCH 24/49] x86: broadwell: Select refcode and CPU code for SPL Allow broadwell to build for SPL and include the reference code. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/broadwell/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/cpu/broadwell/Makefile b/arch/x86/cpu/broadwell/Makefile index fbc778cda5..52d56c65be 100644 --- a/arch/x86/cpu/broadwell/Makefile +++ b/arch/x86/cpu/broadwell/Makefile @@ -3,13 +3,14 @@ # Copyright (c) 2016 Google, Inc obj-y += adsp.o -obj-y += cpu.o -obj-y += cpu_full.o +obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += cpu.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += cpu_full.o ifdef CONFIG_SPL ifndef CONFIG_SPL_BUILD obj-y += cpu_from_spl.o obj-y += cpu_full.o +obj-y += refcode.o endif ifndef CONFIG_SPL_BUILD # obj-y += cpu_from_spl.o @@ -27,6 +28,6 @@ obj-y += northbridge.o obj-y += pch.o obj-y += pinctrl_broadwell.o obj-y += power_state.o -obj-y += refcode.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += refcode.o obj-y += sata.o obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += sdram.o From 17903c06e8d4d960b6d3ae1444905e45fe99a551 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:56 -0600 Subject: [PATCH 25/49] x86: Add common Intel code for SPL Add an implementation of arch_cpu_init_f() so that the x86 SPL code builds and identifies the CPU. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/intel_common/Makefile | 6 ++++++ arch/x86/cpu/intel_common/cpu_from_spl.c | 27 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 arch/x86/cpu/intel_common/cpu_from_spl.c diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 80fbc7ab66..57cca0b930 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -14,3 +14,9 @@ ifndef CONFIG_TARGET_EFI_APP obj-y += microcode.o endif obj-y += pch.o + +ifdef CONFIG_SPL +ifndef CONFIG_SPL_BUILD +obj-y += cpu_from_spl.o +endif +endif diff --git a/arch/x86/cpu/intel_common/cpu_from_spl.c b/arch/x86/cpu/intel_common/cpu_from_spl.c new file mode 100644 index 0000000000..a6233c75ce --- /dev/null +++ b/arch/x86/cpu/intel_common/cpu_from_spl.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016 Google, Inc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int arch_cpu_init(void) +{ + int ret; + + ret = x86_cpu_reinit_f(); + + return ret; +} From 9a67994e0132f0a078de6ab7c11a049dbb5c365c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:57 -0600 Subject: [PATCH 26/49] x86: Support saving MRC data from SPL When SPL is used to set up the memory controller we want to save the MRC data in SPL to avoid needing to pass it up to U-Boot proper to save. Add a function to handle that. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/include/asm/mrccache.h | 11 ++++++++++ arch/x86/lib/mrccache.c | 36 ++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index 04783cd329..40fda856ff 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -103,4 +103,15 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry); */ int mrccache_save(void); +/** + * mrccache_spl_save() - Save to the MRC region from SPL + * + * When SPL is used to set up the memory controller we want to save the MRC + * data in SPL to avoid needing to pass it up to U-Boot proper to save. This + * function handles that. + * + * @return 0 if saved to SPI flash successfully, other error if failed + */ +int mrccache_spl_save(void); + #endif /* _ASM_MRCCACHE_H */ diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 2a8919885b..f37a732a45 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -159,18 +159,11 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry, return 0; } -int mrccache_reserve(void) +static void mrccache_setup(void *data) { - struct mrc_data_container *cache; + struct mrc_data_container *cache = data; u16 checksum; - if (!gd->arch.mrc_output_len) - return 0; - - /* adjust stack pointer to store pure cache data plus the header */ - gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE); - cache = (struct mrc_data_container *)gd->start_addr_sp; - cache->signature = MRC_DATA_SIGNATURE; cache->data_size = gd->arch.mrc_output_len; checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size); @@ -182,6 +175,16 @@ int mrccache_reserve(void) /* gd->arch.mrc_output now points to the container */ gd->arch.mrc_output = (char *)cache; +} + +int mrccache_reserve(void) +{ + if (!gd->arch.mrc_output_len) + return 0; + + /* adjust stack pointer to store pure cache data plus the header */ + gd->start_addr_sp -= (gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE); + mrccache_setup((void *)gd->start_addr_sp); gd->start_addr_sp &= ~0xf; @@ -256,3 +259,18 @@ err_entry: debug("%s: Failed: %d\n", __func__, ret); return ret; } + +int mrccache_spl_save(void) +{ + void *data; + int size; + + size = gd->arch.mrc_output_len + MRC_DATA_HEADER_SIZE; + data = malloc(size); + if (!data) + return log_msg_ret("Allocate MRC cache block", -ENOMEM); + mrccache_setup(data); + gd->arch.mrc_output = data; + + return mrccache_save(); +} From 079b38ba0485eb745cdcdac7e74986d77d2c13e2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:58:59 -0600 Subject: [PATCH 27/49] x86: mrccache: Add more debugging When the MRC cache fails to save it is useful to have some debugging info to indicate what when wrong. Add some more debug() calls. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/lib/mrccache.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index f37a732a45..be107627b8 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -113,8 +113,10 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry, ulong base_addr; int ret; - if (!is_mrc_cache(cur)) + if (!is_mrc_cache(cur)) { + debug("%s: Cache data not valid\n", __func__); return -EINVAL; + } /* Find the last used block */ base_addr = entry->base + entry->offset; @@ -205,17 +207,23 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) return -ENOENT; } - if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) + if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) { + debug("%s: Cannot find memory map\n", __func__); return -EINVAL; + } entry->base = reg[0]; /* Find the place where we put the MRC cache */ mrc_node = fdt_subnode_offset(blob, node, "rw-mrc-cache"); - if (mrc_node < 0) + if (mrc_node < 0) { + debug("%s: Cannot find node\n", __func__); return -EPERM; + } - if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) + if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) { + debug("%s: Cannot find address\n", __func__); return -EINVAL; + } entry->offset = reg[0]; entry->length = reg[1]; From b69b603bcdeb05f846f76da81e4a681aff6a1001 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:59:01 -0600 Subject: [PATCH 28/49] x86: pch: Add an ioctl to read power-management info Add a new ioctl() request to read information about the power-management system. This can be used to power off the device. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- include/pch.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/pch.h b/include/pch.h index 046a5fde3a..0b44b66df9 100644 --- a/include/pch.h +++ b/include/pch.h @@ -16,6 +16,9 @@ enum pch_req_t { /* Returns HDA config info if Azalia V1CTL enabled, -ENOENT if not */ PCH_REQ_HDA_CONFIG, + /* Fills out a struct pch_pmbase_info if available */ + PCH_REQ_PMBASE_INFO, + PCH_REQ_TEST1, /* Test requests for sandbox driver */ PCH_REQ_TEST2, PCH_REQ_TEST3, @@ -23,6 +26,21 @@ enum pch_req_t { PCH_REQ_COUNT, /* Number of ioctrls supported */ }; +/** + * struct pch_pmbase_info - Information filled in by PCH_REQ_PMBASE_INFO + * + * @pmbase: IO address of power-management controller + * @gpio0_en_ofs: Offset of GPIO0 enable register + * @pm1_sts_ofs: Offset of status register + * @pm1_cnt_ofs: Offset of control register + */ +struct pch_pmbase_info { + u16 base; + u8 gpio0_en_ofs; + u8 pm1_sts_ofs; + u8 pm1_cnt_ofs; +}; + /** * struct pch_ops - Operations for the Platform Controller Hub * From 9ffe7cd5c421e21317d56c80c1390aba636b3ffb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:59:02 -0600 Subject: [PATCH 29/49] x86: ivybridge: Implement PCH_REQ_PMBASE_INFO Implement this ioctl() to support power off. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/ivybridge/bd82x6x.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c index ed9bce6416..1cb6cecda9 100644 --- a/arch/x86/cpu/ivybridge/bd82x6x.c +++ b/arch/x86/cpu/ivybridge/bd82x6x.c @@ -229,6 +229,21 @@ static int bd82x6x_ioctl(struct udevice *dev, enum pch_req_t req, void *data, return -ENOENT; return val & RCBA_AUDIO_CONFIG_MASK; + case PCH_REQ_PMBASE_INFO: { + struct pch_pmbase_info *pm = data; + int ret; + + /* Find the base address of the powermanagement registers */ + ret = dm_pci_read_config16(dev, 0x40, &pm->base); + if (ret) + return ret; + pm->base &= 0xfffe; + pm->gpio0_en_ofs = GPE0_EN; + pm->pm1_sts_ofs = PM1_STS; + pm->pm1_cnt_ofs = PM1_CNT; + + return 0; + } default: return -ENOSYS; } From 2b36eabd8aec5107f4753715c2fb4e30cb0d6136 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:59:03 -0600 Subject: [PATCH 30/49] x86: broadwell: Implement PCH_REQ_PMBASE_INFO Implement this ioctl() to support power off. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/broadwell/pch.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/x86/cpu/broadwell/pch.c b/arch/x86/cpu/broadwell/pch.c index 73d3d3b515..e61efa7b16 100644 --- a/arch/x86/cpu/broadwell/pch.c +++ b/arch/x86/cpu/broadwell/pch.c @@ -630,10 +630,35 @@ static int broadwell_get_gpio_base(struct udevice *dev, u32 *gbasep) return 0; } +static int broadwell_ioctl(struct udevice *dev, enum pch_req_t req, void *data, + int size) +{ + switch (req) { + case PCH_REQ_PMBASE_INFO: { + struct pch_pmbase_info *pm = data; + int ret; + + /* Find the base address of the powermanagement registers */ + ret = dm_pci_read_config16(dev, 0x40, &pm->base); + if (ret) + return ret; + pm->base &= 0xfffe; + pm->gpio0_en_ofs = GPE0_EN(0); + pm->pm1_sts_ofs = PM1_STS; + pm->pm1_cnt_ofs = PM1_CNT; + + return 0; + } + default: + return -ENOSYS; + } +} + static const struct pch_ops broadwell_pch_ops = { .get_spi_base = broadwell_pch_get_spi_base, .set_spi_protect = broadwell_set_spi_protect, .get_gpio_base = broadwell_get_gpio_base, + .ioctl = broadwell_ioctl, }; static const struct udevice_id broadwell_pch_ids[] = { From 40476f4afc08ccb6f1f95d7790b6a29159e8b30a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:13 -0600 Subject: [PATCH 31/49] x86: sysreset: Separate out the EFI code The EFI implementation of reset sits inside the driver and is called directly from outside the driver, breaking the normal driver-model conventions. Worse, it passed NULL as the device pointer, hoping that the called function won't use it, which breaks as soon as code is added to use it. Separate out the implementation to improve the situation enough to allow a future patch to add new sysreset features. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/sysreset/sysreset_x86.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c index 009f376602..d484ec5de4 100644 --- a/drivers/sysreset/sysreset_x86.c +++ b/drivers/sysreset/sysreset_x86.c @@ -12,8 +12,7 @@ #include #include -static __efi_runtime int x86_sysreset_request(struct udevice *dev, - enum sysreset_t type) +static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type) { int value; @@ -39,11 +38,18 @@ void __efi_runtime EFIAPI efi_reset_system( efi_status_t reset_status, unsigned long data_size, void *reset_data) { + int value; + + /* + * inline this code since we are not caused in the context of a + * udevice and passing NULL to x86_sysreset_request() is too horrible. + */ if (reset_type == EFI_RESET_COLD || reset_type == EFI_RESET_PLATFORM_SPECIFIC) - x86_sysreset_request(NULL, SYSRESET_COLD); - else if (reset_type == EFI_RESET_WARM) - x86_sysreset_request(NULL, SYSRESET_WARM); + value = SYS_RST | RST_CPU | FULL_RST; + else /* assume EFI_RESET_WARM since we cannot return an error */ + value = SYS_RST | RST_CPU; + outb(value, IO_PORT_RESET); /* TODO EFI_RESET_SHUTDOWN */ From d6b1ba2fb99cdda35983b1e70c745728b8df9b4b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:14 -0600 Subject: [PATCH 32/49] x86: sysreset: Implement power-off if available On modern x86 devices we can power the system off using the power- management features of the PCH. Add an implementation for this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/sysreset/sysreset_x86.c | 79 ++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c index d484ec5de4..ca892b305e 100644 --- a/drivers/sysreset/sysreset_x86.c +++ b/drivers/sysreset/sysreset_x86.c @@ -7,14 +7,75 @@ #include #include +#include +#include #include +#include #include #include -#include + +struct x86_sysreset_platdata { + struct udevice *pch; +}; + +/* + * Power down the machine by using the power management sleep control + * of the chipset. This will currently only work on Intel chipsets. + * However, adapting it to new chipsets is fairly simple. You will + * have to find the IO address of the power management register block + * in your southbridge, and look up the appropriate SLP_TYP_S5 value + * from your southbridge's data sheet. + * + * This function never returns. + */ +int pch_sysreset_power_off(struct udevice *dev) +{ + struct x86_sysreset_platdata *plat = dev_get_platdata(dev); + struct pch_pmbase_info pm; + u32 reg32; + int ret; + + if (!plat->pch) + return -ENOENT; + ret = pch_ioctl(plat->pch, PCH_REQ_PMBASE_INFO, &pm, sizeof(pm)); + if (ret) + return ret; + + /* + * Mask interrupts or system might stay in a coma, not executing code + * anymore, but not powered off either. + */ + asm("cli"); + + /* + * Avoid any GPI waking the system from S5* or the system might stay in + * a coma + */ + outl(0x00000000, pm.base + pm.gpio0_en_ofs); + + /* Clear Power Button Status */ + outw(PWRBTN_STS, pm.base + pm.pm1_sts_ofs); + + /* PMBASE + 4, Bit 10-12, Sleeping Type, * set to 111 -> S5, soft_off */ + reg32 = inl(pm.base + pm.pm1_cnt_ofs); + + /* Set Sleeping Type to S5 (poweroff) */ + reg32 &= ~(SLP_EN | SLP_TYP); + reg32 |= SLP_TYP_S5; + outl(reg32, pm.base + pm.pm1_cnt_ofs); + + /* Now set the Sleep Enable bit */ + reg32 |= SLP_EN; + outl(reg32, pm.base + pm.pm1_cnt_ofs); + + for (;;) + asm("hlt"); +} static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type) { int value; + int ret; switch (type) { case SYSRESET_WARM: @@ -23,6 +84,11 @@ static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type) case SYSRESET_COLD: value = SYS_RST | RST_CPU | FULL_RST; break; + case SYSRESET_POWER_OFF: + ret = pch_sysreset_power_off(dev); + if (ret) + return ret; + return -EINPROGRESS; default: return -ENOSYS; } @@ -57,6 +123,15 @@ void __efi_runtime EFIAPI efi_reset_system( } #endif +static int x86_sysreset_probe(struct udevice *dev) +{ + struct x86_sysreset_platdata *plat = dev_get_platdata(dev); + + /* Locate the PCH if there is one. It isn't essential */ + uclass_first_device(UCLASS_PCH, &plat->pch); + + return 0; +} static const struct udevice_id x86_sysreset_ids[] = { { .compatible = "x86,reset" }, @@ -72,4 +147,6 @@ U_BOOT_DRIVER(x86_sysreset) = { .id = UCLASS_SYSRESET, .of_match = x86_sysreset_ids, .ops = &x86_sysreset_ops, + .probe = x86_sysreset_probe, + .platdata_auto_alloc_size = sizeof(struct x86_sysreset_platdata), }; From f77ab00e898bb24323d027f3f27c5661e19c8461 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:15 -0600 Subject: [PATCH 33/49] x86: sysreset: Implement the get_last() method Add a default implementation of this method which always indicates that the last reset was a power-on reset. This is the most likely type of reset and without a PCH-specific driver we cannot determine any other type. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/sysreset/sysreset_x86.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c index ca892b305e..072f7948ef 100644 --- a/drivers/sysreset/sysreset_x86.c +++ b/drivers/sysreset/sysreset_x86.c @@ -98,6 +98,11 @@ static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type) return -EINPROGRESS; } +static int x86_sysreset_get_last(struct udevice *dev) +{ + return SYSRESET_POWER; +} + #ifdef CONFIG_EFI_LOADER void __efi_runtime EFIAPI efi_reset_system( enum efi_reset_type reset_type, @@ -140,6 +145,7 @@ static const struct udevice_id x86_sysreset_ids[] = { static struct sysreset_ops x86_sysreset_ops = { .request = x86_sysreset_request, + .get_last = x86_sysreset_get_last, }; U_BOOT_DRIVER(x86_sysreset) = { From 9fa31fc51d5f06bb54c2681c91d793f82fcc537e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:59:05 -0600 Subject: [PATCH 34/49] x86: Support TPL in Intel common code Update the Makefie rules to ensure that the correct files are built when TPL is being used. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/intel_common/Makefile | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 57cca0b930..07f27c29ec 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -4,15 +4,18 @@ ifdef CONFIG_HAVE_MRC obj-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += car.o -obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += me_status.o -obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += report_platform.o -obj-$(CONFIG_$(SPL_)X86_32BIT_INIT) += mrc.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += me_status.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += report_platform.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += mrc.o endif obj-y += cpu.o obj-y += lpc.o ifndef CONFIG_TARGET_EFI_APP +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o +ifndef CONFIG_$(SPL_)X86_64 obj-y += microcode.o endif +endif obj-y += pch.o ifdef CONFIG_SPL From 665cb18ea64aabbeb03d27a4c92ddec1baccb87a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:59:06 -0600 Subject: [PATCH 35/49] x86: Don't set up MTRRs in SPL The MTRRs are normally set up in U-Boot proper, so avoid setting them up in SPL as well. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/lib/init_helpers.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c index 0481f453ca..ac85278cdf 100644 --- a/arch/x86/lib/init_helpers.c +++ b/arch/x86/lib/init_helpers.c @@ -18,7 +18,10 @@ __weak ulong board_get_usable_ram_top(ulong total_size) int init_cache_f_r(void) { -#if CONFIG_IS_ENABLED(X86_32BIT_INIT) && !defined(CONFIG_HAVE_FSP) +#if (CONFIG_IS_ENABLED(X86_32BIT_INIT) || \ + (!defined(CONFIG_SPL_BUILD) && \ + !CONFIG_IS_ENABLED(CONFIG_X86_RUN_64BIT))) && \ + !defined(CONFIG_HAVE_FSP) int ret; ret = mtrr_commit(false); From bf4d8beb126788bfd71da2645c26987516c26d10 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:59:07 -0600 Subject: [PATCH 36/49] x86: Don't generate a bootstage report in SPL This report is normally generated by U-Boot proper. Correct the condition here so that it respects the Kconfig options for bootstage. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/lib/bootm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 832b1f901c..5443a862ab 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -35,7 +35,7 @@ void bootm_announce_and_cleanup(void) timestamp_add_now(TS_U_BOOT_START_KERNEL); #endif bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); -#ifdef CONFIG_BOOTSTAGE_REPORT +#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT) bootstage_report(); #endif From 6c456516e24fb23eee01245097ef26885bc8842c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 25 Apr 2019 21:59:08 -0600 Subject: [PATCH 37/49] x86: Support PCI VGA ROM when TPL is used When TPL is in use, U-Boot proper should support initing the VGA ROM even though the 32-bit init portion is in SPL. Update the condition to handle this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- drivers/pci/pci_rom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 7d9b75c2c4..2cede1211b 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -306,7 +306,7 @@ int dm_pci_run_vga_bios(struct udevice *dev, int (*int15_handler)(void), goto err; #endif } else { -#if defined(CONFIG_X86) && CONFIG_IS_ENABLED(X86_32BIT_INIT) +#if defined(CONFIG_X86) && (CONFIG_IS_ENABLED(X86_32BIT_INIT) || CONFIG_TPL) bios_set_interrupt_handler(0x15, int15_handler); bios_run_on_x86(dev, (unsigned long)ram, vesa_mode, From d4d2521c0635fe31118b23641c06bf2387d69727 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:16 -0600 Subject: [PATCH 38/49] x86: Add documentation on the samus flashmap There are quite a few variables which control where things appear in the final ROM image. Add a flashmap in the documentation to make this easier to figure out. Signed-off-by: Simon Glass Reviewed-by: Bin Meng [bmeng: squashed "x86: Update the memory map a little" in] [bmeng: fixed typo of 'documentation' in the commit title] Signed-off-by: Bin Meng --- doc/README.x86 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/README.x86 b/doc/README.x86 index fa49cb8b8a..8e0a3f36ed 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -185,6 +185,22 @@ If you are using em100, then this command will flash write -Boot: em100 -s -d filename.rom -c W25Q64CV -r +Flash map for samus / broadwell: + + fffff800 SYS_X86_START16 + ffff0000 RESET_SEG_START + fffd8000 TPL_TEXT_BASE + fffa0000 X86_MRC_ADDR + fff90000 VGA_BIOS_ADDR + ffed0000 SYS_TEXT_BASE + ffea0000 X86_REFCODE_ADDR + ffe70000 SPL_TEXT_BASE + ffbf8000 CONFIG_ENV_OFFSET (environemnt offset) + ffbe0000 rw-mrc-cache (Memory-reference-code cache) + ffa00000 + ff801000 intel-me (address set by descriptor.bin) + ff800000 intel-descriptor + --- Intel Crown Bay specific instructions for bare mode: From 93c76075802dba9bed40d20cfe1e4351c7bed4e5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:19 -0600 Subject: [PATCH 39/49] x86: Update device tree for TPL Add TPL binaries to the device x86 binman desciption. When enabled, TPL will start first, doing the 16-bit init, then jump to SPL and finally U-Boot proper. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/dts/u-boot.dtsi | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 1050236330..9cf733806a 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -22,7 +22,21 @@ filename = CONFIG_INTEL_ME_FILE; }; #endif -#ifdef CONFIG_SPL +#ifdef CONFIG_TPL + u-boot-tpl-with-ucode-ptr { + offset = ; + }; + u-boot-tpl-dtb { + }; + u-boot-spl { + offset = ; + }; + u-boot-spl-dtb { + }; + u-boot { + offset = ; + }; +#elif defined(CONFIG_SPL) u-boot-spl-with-ucode-ptr { offset = ; }; @@ -31,7 +45,19 @@ type = "u-boot-dtb-with-ucode"; }; u-boot { + /* + * TODO(sjg@chromium.org): + * Normally we use CONFIG_SYS_TEXT_BASE as the flash offset. But + * for boards with textbase in SDRAM we cannot do this. Just use + * an assumed-valid value (1MB before the end of flash) here so + * that we can actually build an image for coreboot, etc. + * We need a better solution, perhaps a separate Kconfig. + */ +#if CONFIG_SYS_TEXT_BASE == 0x1110000 offset = <0xfff00000>; +#else + offset = ; +#endif }; #else u-boot-with-ucode-ptr { @@ -77,7 +103,11 @@ offset = ; }; #endif -#ifdef CONFIG_SPL +#ifdef CONFIG_TPL + x86-start16-tpl { + offset = ; + }; +#elif defined(CONFIG_SPL) x86-start16-spl { offset = ; }; From c5edefb7f7e555ee691b44e12e1565c5aa45dc38 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:20 -0600 Subject: [PATCH 40/49] x86: Update device tree for Chromium OS verified boot The standard image generated by U-Boot on x86 is u-boot.rom. Add a separate image called image.bin for verified boot. This supports verification in TPL of which SPL/U-Boot to start, then jumping to the correct one, with SPL setting up the SDRAM and U-Boot proper providing the user interface if needed. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/dts/u-boot.dtsi | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 9cf733806a..6b176339ae 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -6,9 +6,23 @@ #include -#ifdef CONFIG_ROM_SIZE +#ifdef CONFIG_CHROMEOS / { binman { + multiple-images; + rom: rom { + }; + }; +}; +#else +/ { + rom: binman { + }; +}; +#endif + +#ifdef CONFIG_ROM_SIZE +&rom { filename = "u-boot.rom"; end-at-4gb; sort-by-offset; @@ -116,6 +130,5 @@ offset = ; }; #endif - }; }; #endif From e766d9f1835e6ad6a2a3080c4abb2e5175b156e8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:21 -0600 Subject: [PATCH 41/49] x86: Fix device-tree indentation With the use of a phandle we can outdent the device tree nodes a little. Fix this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/dts/u-boot.dtsi | 147 +++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 74 deletions(-) diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 6b176339ae..daeb168b65 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -23,42 +23,41 @@ #ifdef CONFIG_ROM_SIZE &rom { - filename = "u-boot.rom"; - end-at-4gb; - sort-by-offset; - pad-byte = <0xff>; - size = ; + filename = "u-boot.rom"; + end-at-4gb; + sort-by-offset; + pad-byte = <0xff>; + size = ; #ifdef CONFIG_HAVE_INTEL_ME - intel-descriptor { - filename = CONFIG_FLASH_DESCRIPTOR_FILE; - }; - intel-me { - filename = CONFIG_INTEL_ME_FILE; - }; + intel-descriptor { + filename = CONFIG_FLASH_DESCRIPTOR_FILE; + }; + intel-me { + filename = CONFIG_INTEL_ME_FILE; + }; #endif #ifdef CONFIG_TPL - u-boot-tpl-with-ucode-ptr { - offset = ; - }; - u-boot-tpl-dtb { - }; - u-boot-spl { - offset = ; - }; - u-boot-spl-dtb { - }; - u-boot { - offset = ; - }; + u-boot-tpl-with-ucode-ptr { + offset = ; + }; + u-boot-tpl-dtb { + }; + u-boot-spl { + offset = ; + }; + u-boot-spl-dtb { + }; + u-boot { + offset = ; + }; #elif defined(CONFIG_SPL) - u-boot-spl-with-ucode-ptr { - offset = ; - }; - - u-boot-dtb-with-ucode2 { - type = "u-boot-dtb-with-ucode"; - }; - u-boot { + u-boot-spl-with-ucode-ptr { + offset = ; + }; + u-boot-dtb-with-ucode2 { + type = "u-boot-dtb-with-ucode"; + }; + u-boot { /* * TODO(sjg@chromium.org): * Normally we use CONFIG_SYS_TEXT_BASE as the flash offset. But @@ -68,67 +67,67 @@ * We need a better solution, perhaps a separate Kconfig. */ #if CONFIG_SYS_TEXT_BASE == 0x1110000 - offset = <0xfff00000>; + offset = <0xfff00000>; #else - offset = ; + offset = ; #endif - }; + }; #else - u-boot-with-ucode-ptr { - offset = ; - }; + u-boot-with-ucode-ptr { + offset = ; + }; #endif - u-boot-dtb-with-ucode { - }; - u-boot-ucode { - align = <16>; - }; + u-boot-dtb-with-ucode { + }; + u-boot-ucode { + align = <16>; + }; #ifdef CONFIG_HAVE_MRC - intel-mrc { - offset = ; - }; + intel-mrc { + offset = ; + }; #endif #ifdef CONFIG_HAVE_FSP - intel-fsp { - filename = CONFIG_FSP_FILE; - offset = ; - }; + intel-fsp { + filename = CONFIG_FSP_FILE; + offset = ; + }; #endif #ifdef CONFIG_HAVE_CMC - intel-cmc { - filename = CONFIG_CMC_FILE; - offset = ; - }; + intel-cmc { + filename = CONFIG_CMC_FILE; + offset = ; + }; #endif #ifdef CONFIG_HAVE_VGA_BIOS - intel-vga { - filename = CONFIG_VGA_BIOS_FILE; - offset = ; - }; + intel-vga { + filename = CONFIG_VGA_BIOS_FILE; + offset = ; + }; #endif #ifdef CONFIG_HAVE_VBT - intel-vbt { - filename = CONFIG_VBT_FILE; - offset = ; - }; + intel-vbt { + filename = CONFIG_VBT_FILE; + offset = ; + }; #endif #ifdef CONFIG_HAVE_REFCODE - intel-refcode { - offset = ; - }; + intel-refcode { + offset = ; + }; #endif #ifdef CONFIG_TPL - x86-start16-tpl { - offset = ; - }; + x86-start16-tpl { + offset = ; + }; #elif defined(CONFIG_SPL) - x86-start16-spl { - offset = ; - }; + x86-start16-spl { + offset = ; + }; #else - x86-start16 { - offset = ; - }; + x86-start16 { + offset = ; + }; #endif }; #endif From 31d5261d3599dd7e1868e93e95076ac5d7468b3c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:24 -0600 Subject: [PATCH 42/49] x86: Enable the RTC on all boards With the move to Kconfig this option should be set in Kconfig, not in the config header file. Move it. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/Kconfig | 1 + include/configs/x86-common.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/Kconfig b/arch/Kconfig index 2914567248..0ad3867cd1 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -165,6 +165,7 @@ config X86 imply USB_ETHER_SMSC95XX imply USB_HOST_ETHER imply PCH + imply RTC_MC146818 # Thing to enable for when SPL/TPL are enabled: SPL imply SPL_DM diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h index 4180b25f97..7fcf76a6bf 100644 --- a/include/configs/x86-common.h +++ b/include/configs/x86-common.h @@ -36,7 +36,6 @@ /*----------------------------------------------------------------------- * Real Time Clock Configuration */ -#define CONFIG_RTC_MC146818 #define CONFIG_SYS_ISA_IO_BASE_ADDRESS 0 #define CONFIG_SYS_ISA_IO CONFIG_SYS_ISA_IO_BASE_ADDRESS From bfeeb8d863de070b1f9a2cf17f5e491557c5ecb5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:26 -0600 Subject: [PATCH 43/49] x86: broadwell: Update PCH to work in TPL The early init should only happen once. Update the probe method to deal with TPL, SPL and U-Boot proper. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/broadwell/pch.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/x86/cpu/broadwell/pch.c b/arch/x86/cpu/broadwell/pch.c index e61efa7b16..a48945adf1 100644 --- a/arch/x86/cpu/broadwell/pch.c +++ b/arch/x86/cpu/broadwell/pch.c @@ -599,10 +599,16 @@ static int broadwell_pch_init(struct udevice *dev) static int broadwell_pch_probe(struct udevice *dev) { - if (!(gd->flags & GD_FLG_RELOC)) - return broadwell_pch_early_init(dev); - else + if (CONFIG_IS_ENABLED(X86_32BIT_INIT)) { + if (!(gd->flags & GD_FLG_RELOC)) + return broadwell_pch_early_init(dev); + else + return broadwell_pch_init(dev); + } else if (IS_ENABLED(CONFIG_SPL) && !IS_ENABLED(CONFIG_SPL_BUILD)) { return broadwell_pch_init(dev); + } else { + return 0; + } } static int broadwell_pch_get_spi_base(struct udevice *dev, ulong *sbasep) From 094ba7bb5be2a015e6227386e4380548515c3868 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:22 -0600 Subject: [PATCH 44/49] x86: samus: Increase the pre-reloc memory again This is again too small, so increase it slightly. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- configs/chromebook_samus_defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/chromebook_samus_defconfig b/configs/chromebook_samus_defconfig index d0749f14fc..91d9fdf961 100644 --- a/configs/chromebook_samus_defconfig +++ b/configs/chromebook_samus_defconfig @@ -1,6 +1,6 @@ CONFIG_X86=y CONFIG_SYS_TEXT_BASE=0xFFE00000 -CONFIG_SYS_MALLOC_F_LEN=0x1c00 +CONFIG_SYS_MALLOC_F_LEN=0x1d00 CONFIG_NR_DRAM_BANKS=8 CONFIG_DEBUG_UART_BOARD_INIT=y CONFIG_DEBUG_UART_BASE=0x3f8 From 49dffb7a074e9b9d2c27a303798c0e6bc5eea3ba Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:27 -0600 Subject: [PATCH 45/49] x86: Add a way to jump from TPL to SPL When TPL finishes it needs to jump to SPL with the stack set up correctly. Add a function to handle this. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/cpu/start.S | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 30fa7def46..4a82add76b 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -190,6 +190,19 @@ board_init_f_r_trampoline: /* Re-enter U-Boot by calling board_init_f_r() */ call board_init_f_r +#ifdef CONFIG_TPL +.globl jump_to_spl +.type jump_to_spl, @function +jump_to_spl: + /* Reset stack to the top of CAR space */ + movl $(CONFIG_SYS_CAR_ADDR + CONFIG_SYS_CAR_SIZE - 4), %esp +#ifdef CONFIG_DCACHE_RAM_MRC_VAR_SIZE + subl $CONFIG_DCACHE_RAM_MRC_VAR_SIZE, %esp +#endif + + jmp *%eax +#endif + die: hlt jmp die From 7c03caf6fac19cfef049ec84d813e87481d48d69 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 2 May 2019 10:52:12 -0600 Subject: [PATCH 46/49] x86: Add a simple TPL implementation Add the required CPU code so that TPL builds correctly. Also update the SPL code to deal with being booted from TPL. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/include/asm/spl.h | 17 ++++- arch/x86/lib/Makefile | 9 ++- arch/x86/lib/spl.c | 44 ++++++++++- arch/x86/lib/tpl.c | 118 ++++++++++++++++++++++++++++++ include/configs/chromebook_link.h | 3 - include/configs/qemu-x86.h | 5 -- 6 files changed, 183 insertions(+), 13 deletions(-) create mode 100644 arch/x86/lib/tpl.c diff --git a/arch/x86/include/asm/spl.h b/arch/x86/include/asm/spl.h index 8cf59d14e7..27432b2897 100644 --- a/arch/x86/include/asm/spl.h +++ b/arch/x86/include/asm/spl.h @@ -2,6 +2,19 @@ /* * Copyright (C) 2017 Google, Inc * Written by Simon Glass - * - * This file is required for SPL to build, but is empty. */ + +#ifndef __asm_spl_h +#define __asm_spl_h + +#define CONFIG_SPL_BOARD_LOAD_IMAGE + +enum { + BOOT_DEVICE_SPI = 10, + BOOT_DEVICE_BOARD, + BOOT_DEVICE_CROS_VBOOT, +}; + +void jump_to_spl(ulong entry); + +#endif diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 56fd680033..436252dd83 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -43,7 +43,14 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_CMD_ZBOOT) += zimage.o endif obj-$(CONFIG_HAVE_FSP) += fsp/ -obj-$(CONFIG_SPL_BUILD) += spl.o + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_TPL_BUILD +obj-y += tpl.o +else +obj-y += spl.o +endif +endif lib-$(CONFIG_USE_PRIVATE_LIBGCC) += div64.o diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index 7d290740bf..5d5d1a9ca7 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -5,8 +5,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -20,6 +22,7 @@ __weak int arch_cpu_init_dm(void) static int x86_spl_init(void) { +#ifndef CONFIG_TPL /* * TODO(sjg@chromium.org): We use this area of RAM for the stack * and global_data in SPL. Once U-Boot starts up and releocates it @@ -27,6 +30,7 @@ static int x86_spl_init(void) * place it immediately below CONFIG_SYS_TEXT_BASE. */ char *ptr = (char *)0x110000; +#endif int ret; debug("%s starting\n", __func__); @@ -35,27 +39,44 @@ static int x86_spl_init(void) debug("%s: spl_init() failed\n", __func__); return ret; } +#ifdef CONFIG_TPL + /* Do a mini-init if TPL has already done the full init */ + ret = x86_cpu_reinit_f(); +#else ret = arch_cpu_init(); +#endif if (ret) { debug("%s: arch_cpu_init() failed\n", __func__); return ret; } +#ifndef CONFIG_TPL ret = arch_cpu_init_dm(); if (ret) { debug("%s: arch_cpu_init_dm() failed\n", __func__); return ret; } +#endif preloader_console_init(); +#ifndef CONFIG_TPL ret = print_cpuinfo(); if (ret) { debug("%s: print_cpuinfo() failed\n", __func__); return ret; } +#endif ret = dram_init(); if (ret) { debug("%s: dram_init() failed\n", __func__); return ret; } + if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) { + ret = mrccache_spl_save(); + if (ret) + debug("%s: Failed to write to mrccache (err=%d)\n", + __func__, ret); + } + +#ifndef CONFIG_TPL memset(&__bss_start, 0, (ulong)&__bss_end - (ulong)&__bss_start); /* TODO(sjg@chromium.org): Consider calling cpu_init_r() here */ @@ -80,9 +101,11 @@ static int x86_spl_init(void) (1ULL << 32) - CONFIG_XIP_ROM_SIZE, CONFIG_XIP_ROM_SIZE); if (ret) { - debug("%s: SPI cache setup failed\n", __func__); + debug("%s: SPI cache setup failed (err=%d)\n", __func__, ret); return ret; } + mtrr_commit(true); +#endif return 0; } @@ -96,9 +119,17 @@ void board_init_f(ulong flags) debug("Error %d\n", ret); hang(); } - +#ifdef CONFIG_TPL + gd->bd = malloc(sizeof(*gd->bd)); + if (!gd->bd) { + printf("Out of memory for bd_info size %x\n", sizeof(*gd->bd)); + hang(); + } + board_init_r(gd, 0); +#else /* Uninit CAR and jump to board_init_f_r() */ board_init_f_r_trampoline(gd->start_addr_sp); +#endif } void board_init_f_r(void) @@ -144,6 +175,7 @@ int spl_spi_load_image(void) return -EPERM; } +#ifdef CONFIG_X86_RUN_64BIT void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) { int ret; @@ -154,3 +186,11 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) while (1) ; } +#endif + +void spl_board_init(void) +{ +#ifndef CONFIG_TPL + preloader_console_init(); +#endif +} diff --git a/arch/x86/lib/tpl.c b/arch/x86/lib/tpl.c new file mode 100644 index 0000000000..492a2d6521 --- /dev/null +++ b/arch/x86/lib/tpl.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Google, Inc + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +__weak int arch_cpu_init_dm(void) +{ + return 0; +} + +static int x86_tpl_init(void) +{ + int ret; + + debug("%s starting\n", __func__); + ret = spl_init(); + if (ret) { + debug("%s: spl_init() failed\n", __func__); + return ret; + } + ret = arch_cpu_init(); + if (ret) { + debug("%s: arch_cpu_init() failed\n", __func__); + return ret; + } + ret = arch_cpu_init_dm(); + if (ret) { + debug("%s: arch_cpu_init_dm() failed\n", __func__); + return ret; + } + preloader_console_init(); + ret = print_cpuinfo(); + if (ret) { + debug("%s: print_cpuinfo() failed\n", __func__); + return ret; + } + + return 0; +} + +void board_init_f(ulong flags) +{ + int ret; + + ret = x86_tpl_init(); + if (ret) { + debug("Error %d\n", ret); + hang(); + } + + /* Uninit CAR and jump to board_init_f_r() */ + board_init_r(gd, 0); +} + +void board_init_f_r(void) +{ + /* Not used since we never call board_init_f_r_trampoline() */ + while (1); +} + +u32 spl_boot_device(void) +{ + return IS_ENABLED(CONFIG_CHROMEOS) ? BOOT_DEVICE_CROS_VBOOT : + BOOT_DEVICE_BOARD; +} + +int spl_start_uboot(void) +{ + return 0; +} + +void spl_board_announce_boot_device(void) +{ + printf("SPI flash"); +} + +static int spl_board_load_image(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) +{ + spl_image->size = CONFIG_SYS_MONITOR_LEN; /* We don't know SPL size */ + spl_image->entry_point = CONFIG_SPL_TEXT_BASE; + spl_image->load_addr = CONFIG_SPL_TEXT_BASE; + spl_image->os = IH_OS_U_BOOT; + spl_image->name = "U-Boot"; + + debug("Loading to %lx\n", spl_image->load_addr); + + return 0; +} +SPL_LOAD_IMAGE_METHOD("SPI", 0, BOOT_DEVICE_BOARD, spl_board_load_image); + +int spl_spi_load_image(void) +{ + return -EPERM; +} + +void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{ + printf("Jumping to U-Boot SPL at %lx\n", (ulong)spl_image->entry_point); + jump_to_spl(spl_image->entry_point); + while (1) + ; +} + +void spl_board_init(void) +{ + preloader_console_init(); +} diff --git a/include/configs/chromebook_link.h b/include/configs/chromebook_link.h index ca59276892..f26e463fe5 100644 --- a/include/configs/chromebook_link.h +++ b/include/configs/chromebook_link.h @@ -18,9 +18,6 @@ #define CONFIG_ENV_SECT_SIZE 0x1000 #define CONFIG_ENV_OFFSET 0x003f8000 -#define BOOT_DEVICE_SPI 10 - #define CONFIG_SPL_BOARD_LOAD_IMAGE -#define BOOT_DEVICE_BOARD 11 #endif /* __CONFIG_H */ diff --git a/include/configs/qemu-x86.h b/include/configs/qemu-x86.h index 4cd1cac3bd..64e7a60b8a 100644 --- a/include/configs/qemu-x86.h +++ b/include/configs/qemu-x86.h @@ -33,11 +33,6 @@ #define CONFIG_SYS_ATA_IDE1_OFFSET 0x170 #define CONFIG_ATAPI -/* SPI is not supported */ - -#define BOOT_DEVICE_SPI 10 - #define CONFIG_SPL_BOARD_LOAD_IMAGE -#define BOOT_DEVICE_BOARD 11 #endif /* __CONFIG_H */ From 969ed0124289f89421b3bf36b1055ca93d900203 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 May 2019 21:41:13 -0600 Subject: [PATCH 47/49] x86: samus: Update device tree for SPL Add tags to allow required nodes to be present in SPL / TPL. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/dts/chromebook_samus.dts | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/arch/x86/dts/chromebook_samus.dts b/arch/x86/dts/chromebook_samus.dts index 35211ed81b..c4207af48a 100644 --- a/arch/x86/dts/chromebook_samus.dts +++ b/arch/x86/dts/chromebook_samus.dts @@ -17,6 +17,7 @@ spi0 = &spi; usb0 = &usb_0; usb1 = &usb_1; + cros-ec0 = &cros_ec; }; config { @@ -73,6 +74,7 @@ /* Put this first: it is the default */ gpio_unused: gpio-unused { + u-boot,dm-pre-reloc; mode-gpio; direction = ; owner = ; @@ -80,6 +82,7 @@ }; gpio_acpi_sci: acpi-sci { + u-boot,dm-pre-reloc; mode-gpio; direction = ; invert; @@ -87,6 +90,7 @@ }; gpio_acpi_smi: acpi-smi { + u-boot,dm-pre-reloc; mode-gpio; direction = ; invert; @@ -94,12 +98,14 @@ }; gpio_input: gpio-input { + u-boot,dm-pre-reloc; mode-gpio; direction = ; owner = ; }; gpio_input_invert: gpio-input-invert { + u-boot,dm-pre-reloc; mode-gpio; direction = ; owner = ; @@ -107,9 +113,11 @@ }; gpio_native: gpio-native { + u-boot,dm-pre-reloc; }; gpio_out_high: gpio-out-high { + u-boot,dm-pre-reloc; mode-gpio; direction = ; output-value = <1>; @@ -118,6 +126,7 @@ }; gpio_out_low: gpio-out-low { + u-boot,dm-pre-reloc; mode-gpio; direction = ; output-value = <0>; @@ -126,6 +135,7 @@ }; gpio_pirq: gpio-pirq { + u-boot,dm-pre-reloc; mode-gpio; direction = ; owner = ; @@ -133,6 +143,7 @@ }; soc_gpio@0 { + u-boot,dm-pre-reloc; config = <0 &gpio_unused 0>, /* unused */ <1 &gpio_unused 0>, /* unused */ @@ -250,8 +261,10 @@ spd { #address-cells = <1>; #size-cells = <0>; + u-boot,dm-pre-reloc; samsung_4 { reg = <6>; + u-boot,dm-pre-reloc; data = [91 20 f1 03 04 11 05 0b 03 11 01 08 0a 00 50 01 78 78 90 50 90 11 50 e0 @@ -291,6 +304,7 @@ * columns 10, density 4096 mb, x32 */ reg = <8>; + u-boot,dm-pre-reloc; data = [91 20 f1 03 04 11 05 0b 03 11 01 08 0a 00 50 01 78 78 90 50 90 11 50 e0 @@ -326,6 +340,7 @@ }; samsung_8 { reg = <10>; + u-boot,dm-pre-reloc; data = [91 20 f1 03 04 12 05 0a 03 11 01 08 0a 00 50 01 78 78 90 50 90 11 50 e0 @@ -365,6 +380,7 @@ * columns 11, density 4096 mb, x16 */ reg = <12>; + u-boot,dm-pre-reloc; data = [91 20 f1 03 04 12 05 0a 03 11 01 08 0a 00 50 01 78 78 90 50 90 11 50 e0 @@ -404,6 +420,7 @@ * columns 11, density 8192 mb, x16 */ reg = <13>; + u-boot,dm-pre-reloc; data = [91 20 f1 03 05 1a 05 0a 03 11 01 08 0a 00 50 01 78 78 90 50 90 11 50 e0 @@ -443,6 +460,7 @@ * columns 11, density 8192 mb, x16 */ reg = <15>; + u-boot,dm-pre-reloc; data = [91 20 f1 03 05 1a 05 0a 03 11 01 08 0a 00 50 01 78 78 90 50 90 11 50 e0 @@ -540,7 +558,7 @@ compatible = "ehci-pci"; }; - pch@1f,0 { + pch: pch@1f,0 { reg = <0x0000f800 0 0 0 0>; compatible = "intel,broadwell-pch"; u-boot,dm-pre-reloc; @@ -559,10 +577,12 @@ power-enable-gpio = <&gpio_a 23 0>; spi: spi { + u-boot,dm-pre-reloc; #address-cells = <1>; #size-cells = <0>; compatible = "intel,ich9-spi"; spi-flash@0 { + u-boot,dm-pre-reloc; #size-cells = <1>; #address-cells = <1>; reg = <0>; @@ -570,6 +590,7 @@ "jedec,spi-nor"; memory-map = <0xff800000 0x00800000>; rw-mrc-cache { + u-boot,dm-pre-reloc; label = "rw-mrc-cache"; reg = <0x003e0000 0x00010000>; }; @@ -609,7 +630,8 @@ #size-cells = <0>; u-boot,dm-pre-reloc; intel,gen-dec = <0x800 0xfc 0x900 0xfc>; - cros-ec@200 { + cros_ec: cros-ec { + u-boot,dm-pre-reloc; compatible = "google,cros-ec-lpc"; reg = <0x204 1 0x200 1 0x880 0x80>; @@ -630,7 +652,7 @@ sata@1f,2 { compatible = "intel,wildcatpoint-ahci"; reg = <0x0000fa00 0 0 0 0>; - u-boot,dm-pre-reloc; + u-boot,dm-pre-proper; intel,sata-mode = "ahci"; intel,sata-port-map = <1>; intel,sata-port0-gen3-tx = <0x72>; @@ -645,12 +667,15 @@ }; tpm { + u-boot,dm-pre-reloc; reg = <0xfed40000 0x5000>; compatible = "infineon,slb9635lpc"; }; microcode { + u-boot,dm-pre-reloc; update@0 { + u-boot,dm-pre-reloc; #include "microcode/mc0306d4_00000018.dtsi" }; }; From 3dc13cc3a05643a8764f9f455fff54f45b0fcd14 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 May 2019 21:41:14 -0600 Subject: [PATCH 48/49] x86: samus: Update device tree for verified boot Add nvdata drivers for the TPM and RTC as used on samus. These are needed for Chromium OS verified boot on samus. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- arch/x86/dts/chromebook_samus.dts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/x86/dts/chromebook_samus.dts b/arch/x86/dts/chromebook_samus.dts index c4207af48a..772ea5c91b 100644 --- a/arch/x86/dts/chromebook_samus.dts +++ b/arch/x86/dts/chromebook_samus.dts @@ -9,6 +9,12 @@ /include/ "rtc.dtsi" /include/ "tsc_timer.dtsi" +#ifdef CONFIG_CHROMEOS +#include "chromeos-x86.dtsi" +#include "flashmap-x86-ro.dtsi" +#include "flashmap-8mb-rw.dtsi" +#endif + / { model = "Google Samus"; compatible = "google,samus", "intel,broadwell"; @@ -581,7 +587,7 @@ #address-cells = <1>; #size-cells = <0>; compatible = "intel,ich9-spi"; - spi-flash@0 { + fwstore_spi: spi-flash@0 { u-boot,dm-pre-reloc; #size-cells = <1>; #address-cells = <1>; @@ -670,6 +676,10 @@ u-boot,dm-pre-reloc; reg = <0xfed40000 0x5000>; compatible = "infineon,slb9635lpc"; + secdata { + u-boot,dm-pre-reloc; + compatible = "google,tpm-secdata"; + }; }; microcode { @@ -693,3 +703,13 @@ }; }; + +&rtc { + #address-cells = <1>; + #size-cells = <0>; + nvdata { + u-boot,dm-pre-reloc; + compatible = "google,cmos-nvdata"; + reg = <0x26>; + }; +}; From ffe403762be48d475de4b2b6df87c32fd3a1e8dd Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 7 May 2019 21:41:16 -0600 Subject: [PATCH 49/49] x86: samus: Add a target to boot through TPL Add a version of samus which supports booting from TPL to SPL and then to U-Boot. This allows TPL to select from an A or B SPL to support verified boot with field upgrade. Signed-off-by: Simon Glass Reviewed-by: Bin Meng --- board/google/Kconfig | 8 +++ board/google/chromebook_samus/Kconfig | 14 +++- board/google/chromebook_samus/MAINTAINERS | 7 ++ configs/chromebook_samus_tpl_defconfig | 82 +++++++++++++++++++++++ include/configs/chromebook_samus.h | 2 + 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 configs/chromebook_samus_tpl_defconfig diff --git a/board/google/Kconfig b/board/google/Kconfig index d98a5e818f..679a0f1023 100644 --- a/board/google/Kconfig +++ b/board/google/Kconfig @@ -52,6 +52,14 @@ config TARGET_CHROMEBOOK_SAMUS Chrome OS EC connected on LPC, and it provides a 2560x1700 high resolution touch-enabled LCD display. +config TARGET_CHROMEBOOK_SAMUS_TPL + bool "Chromebook samus booting from TPL" + help + This is a version of Samus which boots into TPL, then to SPL and + U-Boot proper. This is useful where verified boot must select + between different A/B versions of SPL/U-Boot, to allow upgrading of + almost all U-Boot code in the field. + endchoice source "board/google/chromebook_link/Kconfig" diff --git a/board/google/chromebook_samus/Kconfig b/board/google/chromebook_samus/Kconfig index afbfe53deb..90c23cba1b 100644 --- a/board/google/chromebook_samus/Kconfig +++ b/board/google/chromebook_samus/Kconfig @@ -1,4 +1,4 @@ -if TARGET_CHROMEBOOK_SAMUS +if TARGET_CHROMEBOOK_SAMUS || TARGET_CHROMEBOOK_SAMUS_TPL config SYS_BOARD default "chromebook_samus" @@ -10,7 +10,8 @@ config SYS_SOC default "broadwell" config SYS_CONFIG_NAME - default "chromebook_samus" + default "chromebook_samus" if TARGET_CHROMEBOOK_SAMUS + default "chromebook_samus" if TARGET_CHROMEBOOK_SAMUS_TPL config SYS_TEXT_BASE default 0xffe00000 @@ -39,3 +40,12 @@ config SYS_CAR_SIZE default 0x40000 endif + +if TARGET_CHROMEBOOK_SAMUS_TPL + +config BOARD_SPECIFIC_OPTIONS_TPL # dummy + def_bool y + select SPL + select TPL + +endif diff --git a/board/google/chromebook_samus/MAINTAINERS b/board/google/chromebook_samus/MAINTAINERS index 5500e46b40..ca4b16500a 100644 --- a/board/google/chromebook_samus/MAINTAINERS +++ b/board/google/chromebook_samus/MAINTAINERS @@ -4,3 +4,10 @@ S: Maintained F: board/google/chromebook_samus/ F: include/configs/chromebook_samus.h F: configs/chromebook_samus_defconfig + +CHROMEBOOK SAMUS TPL BOARD +M: Simon Glass +S: Maintained +F: board/google/chromebook_samus/ +F: include/configs/chromebook_samus.h +F: configs/chromebook_samus_tpl_defconfig diff --git a/configs/chromebook_samus_tpl_defconfig b/configs/chromebook_samus_tpl_defconfig new file mode 100644 index 0000000000..6ebfaa83a1 --- /dev/null +++ b/configs/chromebook_samus_tpl_defconfig @@ -0,0 +1,82 @@ +CONFIG_X86=y +CONFIG_SYS_TEXT_BASE=0xffed0000 +CONFIG_SYS_MALLOC_F_LEN=0x1a00 +CONFIG_NR_DRAM_BANKS=8 +CONFIG_DEBUG_UART_BOARD_INIT=y +CONFIG_DEBUG_UART_BASE=0x3f8 +CONFIG_DEBUG_UART_CLOCK=1843200 +CONFIG_VENDOR_GOOGLE=y +CONFIG_TARGET_CHROMEBOOK_SAMUS_TPL=y +CONFIG_DEBUG_UART=y +CONFIG_HAVE_MRC=y +CONFIG_HAVE_REFCODE=y +CONFIG_SMP=y +CONFIG_HAVE_VGA_BIOS=y +CONFIG_BOOTSTAGE=y +CONFIG_BOOTSTAGE_REPORT=y +CONFIG_USE_BOOTARGS=y +CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" +CONFIG_SYS_CONSOLE_INFO_QUIET=y +CONFIG_MISC_INIT_R=y +CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_LAST_STAGE_INIT=y +CONFIG_BLOBLIST=y +CONFIG_BLOBLIST_SIZE=0x1000 +CONFIG_BLOBLIST_ADDR=0xff7c0000 +CONFIG_HANDOFF=y +CONFIG_SPL_TEXT_BASE=0xffe70000 +CONFIG_SPL_SEPARATE_BSS=y +CONFIG_SPL_NET_SUPPORT=y +CONFIG_SPL_PCI=y +CONFIG_SPL_PCH_SUPPORT=y +CONFIG_TPL_PCI=y +CONFIG_TPL_PCH_SUPPORT=y +CONFIG_HUSH_PARSER=y +CONFIG_CMD_CPU=y +# CONFIG_CMD_FLASH is not set +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_PART=y +CONFIG_CMD_SATA=y +CONFIG_CMD_SF=y +CONFIG_CMD_SPI=y +CONFIG_CMD_USB=y +# CONFIG_CMD_SETEXPR is not set +CONFIG_CMD_TIME=y +CONFIG_CMD_SOUND=y +CONFIG_CMD_BOOTSTAGE=y +CONFIG_CMD_TPM=y +CONFIG_CMD_TPM_TEST=y +CONFIG_CMD_EXT2=y +CONFIG_CMD_EXT4=y +CONFIG_CMD_EXT4_WRITE=y +CONFIG_CMD_FAT=y +CONFIG_CMD_FS_GENERIC=y +CONFIG_MAC_PARTITION=y +# CONFIG_SPL_MAC_PARTITION is not set +# CONFIG_SPL_DOS_PARTITION is not set +CONFIG_ISO_PARTITION=y +CONFIG_EFI_PARTITION=y +# CONFIG_SPL_EFI_PARTITION is not set +CONFIG_DEFAULT_DEVICE_TREE="chromebook_samus" +# CONFIG_NET is not set +CONFIG_REGMAP=y +CONFIG_SYSCON=y +CONFIG_CPU=y +CONFIG_DM_I2C=y +CONFIG_SYS_I2C_DW=y +CONFIG_TPL_MISC=y +CONFIG_CROS_EC=y +CONFIG_CROS_EC_LPC=y +CONFIG_SYS_NS16550=y +CONFIG_SOUND=y +CONFIG_SOUND_I8254=y +CONFIG_SOUND_RT5677=y +CONFIG_SPI=y +CONFIG_TPM_TIS_LPC=y +CONFIG_USB_STORAGE=y +CONFIG_USB_KEYBOARD=y +CONFIG_FRAMEBUFFER_SET_VESA_MODE=y +CONFIG_FRAMEBUFFER_VESA_MODE_11A=y +CONFIG_CONSOLE_SCROLL_LINES=5 +CONFIG_TPM=y diff --git a/include/configs/chromebook_samus.h b/include/configs/chromebook_samus.h index ccb2fe8caa..2f7dd69fb8 100644 --- a/include/configs/chromebook_samus.h +++ b/include/configs/chromebook_samus.h @@ -23,4 +23,6 @@ #define CONFIG_ENV_SECT_SIZE 0x1000 #define CONFIG_ENV_OFFSET 0x003f8000 +#define CONFIG_TPL_TEXT_BASE 0xfffd8000 + #endif /* __CONFIG_H */