[U-Boot] [PATCH 000/126] x86: Add initial support for apollolake

Apollolake is an Intel SoC generation aimed at relatively low-end embedded systems. It was released in 2016 but has become more popular recently with some embedded boards using it.
This series adds support for apollolake. As an example it adds an implementation of chromebook_coral (a large range of Chromebooks released in 2017).
The series provides only enough to boot to a prompt. It does not include display, storage, USB, etc. But it does include the major part of the plumbing.
Since this is the first time U-Boot has used FSP2 there is quite a bit of refactoring needed. Some of this is in previous series, but much of it is here.
Some further clean-up is needed with this series and it needs more documentation, but it is ready for review.
This series is available at u-boot-dm/coral-working
Simon Glass (126): dm: core: Use U-Boot logging instead of pr_debug() dm: core: Correct low cell in ofnode_read_pci_addr() dm: core: Drop a few early returns dm: core: Add documentation on how to debug driver model dm: core: Don't include ofnode functions with of-platdata dm: core: Correct bad cast in ofnode_get_addr_size_index() dm: test: Fix running of multiple test from command line dm: test: Don't fail when tests are skipped due to build dm: core: Call ofdata_to_platdata() with of-platdata dm: doc: Correct of-platdata CONFIG_IS_ENABLED() condition dm: core: Correct the return value for uclass_find_first_device() dm: core: Add device_foreach_child() dm: test: Correct a stray backslash in dm_test_destroy() fdt: Show the preprocessed .dts file on error sandbox: spmi: Add ranges property for address translation sandbox: mmc: Fix up MMC emulator for valgrind sandbox: Rename PCI ID for swap_case to be more specific sandbox: Add support for clrsetio_32() and friends sandbox: swap_case: Use statics where possible sandbox: pci: Drop the get_devfn() method sandbox: net: Suppress the MAC-address warnings sandbox: pci: Move pci_offset_to_barnum() to pci.h sandbox: Add a -T flag to use the test device tree sandbox: pci: Increase the memory space sandbox: Allow use of real I/O with readl(), etc. pci: sandbox: Move the emulators into their own node pci: sandbox: Probe PCI emulation devices when used pci: Show the result of binding a device pci: Disable autoconfig in SPL pci: Correct 'specifified' and 'Plese' typos pci: Add more debug detail when resources are exhausted pci: Show a message if PCI autoconfig fails dm: pci: Add a function to read a PCI BAR serial: ns16550: Add a PCI device/function field binman: Allow verbose output with all commands binman: Add a base implementation of Entry.ReadChildData() binman: Handle reading data for end-at-4gb sections binman: Take account of skip-at-start with image-header log: Add log_nop() to avoid unused-variable warnings cros_ec: Add MEC_EMI_BASE and size to the header file iod: Enhance to support display of multiple values arm: mxs: Correct CONFIG_SPL_NO_CPU_SUPPORT option spl: Allow tiny printf() to be controlled in SPL and TPL spl: Convert CONFIG_SPL_LIMIT to hex spl: Add a size check for TPL spl: Allow distinguishing between two phases in U-Boot spl: Allow SPL/TPL to use of-platdata without libfdt x86: Move acpi_s3.h to a common location x86: pci: Drop the first parameter in pci_x86_r/w_config() x86: timer: Reduce timer code size in TPL on Intel CPUs x86: Use a common definition of MSR_IA32_PERF_CTL x86: Add a common function to set CPU thermal target x86: Use a common bus clock for Intel CPUs x86: Add common functions for TDP and perf control x86: Tidy up some duplicate MSR defines x86: Add new common CPU functions for turbo/burst mode dm: core: Drop fdtdec_get_pci_addr() sandbox: pci: Create a new sandbox_pci_read_bar() function x86: Allow the PCH and LPC uclasses to work with of-platdata x86: timer: Set up the timer in timer_early_get_count() x86: Refactor mtrr_commit() to allow for shared code x86: Add a function to set variable MTRRs x86: pci: Add a function to decode a PCI BDF x86: cpu: Don't include the cpu driver in TPL x86: Use mtrr_commit() with FSP2 x86: spl: Support init of a PUNIT x86: Panic when SPL or TPL fail x86: tpl: Add a fake PCI bus sandbox: pci: Remember the device being emulated x86: power: Add a PMC uclass x86: sandbox: Add a PMC emulator and test x86: power: Add a 'pmc' command trace: Remove the const from write functions pci: Add support for p2sb uclass sandbox: Add PCI driver and test for p2sb x86: Add a uclass for ITSS sandbox: Add a test for ITSS x86: Define the SPL image start x86: Reduce mrccache record alignment size x86: Add a function to find the size of an mrccache record x86: Correct mrccache find_next_mrc_cache() calculation x86: Adjust mrccache_get_region() to use livetree x86: Add a new global_data member for the cache record x86: Tidy up error handling in mrccache_save() x86: Update mrccache to support multiple caches x86: Add mrccache support for a 'variable' cache x86: Move fsp_prepare_mrc_cache() to fsp1 directory x86: Set the DRAM banks to reflect real location x86: Set up the MTRR for SDRAM x86: Update Kconfig options for FSP1 x86: Don't imply TPL_OF_LIBFDT x86: Allow removal of standard PCH drivers x86: Allow interrupt to happen once x86: Add FSP2 base support x86: Don't include the BIOS emulator in TPL x86: Add an option to include a FIT x86: Add support for newer CAR schemes x86: Drop RESET_BASE x86: Drop RESET_SEG_SIZE x86: Disable microcode section for FSP2 x86: Use fsp command with FSP1 x86: Update .dtsi file for FSP2 x86: Add an option to control the position of U-Boot x86: Add an option to control the position of SPL x86: Reduce resetvec size x86: Add an fdtmap and image-header x86: Don't repeat microcode in U-Boot if not needed x86: apollolake: Add basic IO addresses x86: apollolake: Add PMC driver x86: apollolake: Add UART driver x86: apollolake: Add GPIO driver x86: apollolake: Add defintions for the Intel Fast SPI interface x86: apollolake: Add systemagent driver x86: apollolake: Add hostbridge driver x86: apollolake: Add ITSS driver x86: apollolake: Add LPC driver x86: apollolake: Add PCH driver x86: apollolake: Add PUNIT driver x86: apollolake: Add SPL loaders x86: apollolake: Add a CPU driver x86: apollolake: Add SPL/TPL init x86: apollolake: Add P2SB driver x86: apollolake: Add Kconfig and Makefile x86: apollolake: Add FSP structures x86: Add chromebook_coral RFC: x86: coral: Add binary MRC data
Kconfig | 9 +- Makefile | 20 +- arch/Kconfig | 4 +- arch/arm/Kconfig | 2 +- arch/arm/cpu/arm926ejs/Makefile | 2 +- arch/arm/mach-omap2/Kconfig | 6 +- arch/arm/mach-rmobile/Kconfig | 2 +- arch/arm/mach-rmobile/Kconfig.32 | 14 +- arch/arm/mach-socfpga/Kconfig | 6 +- arch/arm/mach-uniphier/pinctrl-glue.c | 4 +- arch/sandbox/cpu/cpu.c | 51 ++ arch/sandbox/cpu/start.c | 25 + arch/sandbox/cpu/state.c | 1 + arch/sandbox/dts/sandbox.dtsi | 25 +- arch/sandbox/dts/test.dts | 78 +- arch/sandbox/include/asm/io.h | 69 +- arch/sandbox/include/asm/state.h | 1 + arch/sandbox/include/asm/test.h | 28 +- arch/sandbox/lib/pci_io.c | 12 +- arch/x86/Kconfig | 100 ++- arch/x86/cpu/Makefile | 8 +- arch/x86/cpu/apollolake/Kconfig | 68 ++ arch/x86/cpu/apollolake/Makefile | 21 + arch/x86/cpu/apollolake/cpu.c | 51 ++ arch/x86/cpu/apollolake/cpu_spl.c | 272 +++++++ arch/x86/cpu/apollolake/gpio.c | 742 ++++++++++++++++++ arch/x86/cpu/apollolake/hostbridge.c | 127 +++ arch/x86/cpu/apollolake/itss.c | 129 +++ arch/x86/cpu/apollolake/lpc.c | 155 ++++ arch/x86/cpu/apollolake/p2sb.c | 167 ++++ arch/x86/cpu/apollolake/pch.c | 29 + arch/x86/cpu/apollolake/pmc.c | 216 +++++ arch/x86/cpu/apollolake/punit.c | 121 +++ arch/x86/cpu/apollolake/spl.c | 122 +++ arch/x86/cpu/apollolake/systemagent.c | 19 + arch/x86/cpu/apollolake/uart.c | 157 ++++ arch/x86/cpu/baytrail/acpi.c | 2 +- arch/x86/cpu/baytrail/cpu.c | 6 +- arch/x86/cpu/broadwell/cpu.c | 18 +- arch/x86/cpu/broadwell/cpu_full.c | 41 +- arch/x86/cpu/broadwell/sdram.c | 8 +- arch/x86/cpu/config.mk | 2 - arch/x86/cpu/cpu.c | 2 +- arch/x86/cpu/intel_common/Kconfig | 18 + arch/x86/cpu/intel_common/Makefile | 8 + arch/x86/cpu/intel_common/car2.S | 490 ++++++++++++ arch/x86/cpu/intel_common/car2_uninit.S | 87 ++ arch/x86/cpu/intel_common/cpu.c | 104 ++- arch/x86/cpu/intel_common/fast_spi.c | 3 +- arch/x86/cpu/ivybridge/cpu.c | 3 +- arch/x86/cpu/ivybridge/model_206ax.c | 52 +- arch/x86/cpu/ivybridge/northbridge.c | 2 +- arch/x86/cpu/ivybridge/sdram.c | 8 +- arch/x86/cpu/mtrr.c | 57 +- arch/x86/cpu/pci.c | 38 +- arch/x86/cpu/quark/dram.c | 8 +- arch/x86/cpu/resetvec.S | 3 - arch/x86/cpu/turbo.c | 10 +- arch/x86/cpu/u-boot-spl.lds | 5 +- arch/x86/cpu/wakeup.S | 2 +- arch/x86/dts/Makefile | 1 + arch/x86/dts/chromebook_coral.dts | 298 +++++++ arch/x86/dts/u-boot.dtsi | 89 ++- arch/x86/include/asm/arch-apollolake/cpu.h | 21 + .../include/asm/arch-apollolake/fast_spi.h | 176 +++++ .../asm/arch-apollolake/fsp/fsp_configs.h | 13 + .../asm/arch-apollolake/fsp/fsp_m_upd.h | 127 +++ .../include/asm/arch-apollolake/fsp/fsp_vpd.h | 11 + arch/x86/include/asm/arch-apollolake/gpio.h | 156 ++++ .../include/asm/arch-apollolake/gpio_apl.h | 491 ++++++++++++ .../include/asm/arch-apollolake/gpio_defs.h | 398 ++++++++++ arch/x86/include/asm/arch-apollolake/iomap.h | 28 + arch/x86/include/asm/arch-apollolake/itss.h | 43 + arch/x86/include/asm/arch-apollolake/lpc.h | 61 ++ arch/x86/include/asm/arch-apollolake/pch.h | 9 + arch/x86/include/asm/arch-apollolake/pm.h | 19 + .../include/asm/arch-apollolake/systemagent.h | 31 + arch/x86/include/asm/arch-apollolake/uart.h | 17 + arch/x86/include/asm/arch-broadwell/cpu.h | 3 - arch/x86/include/asm/arch-broadwell/pch.h | 3 - .../include/asm/arch-ivybridge/model_206ax.h | 5 +- arch/x86/include/asm/cpu.h | 1 + arch/x86/include/asm/cpu_common.h | 83 +- arch/x86/include/asm/fsp/fsp_support.h | 7 - arch/x86/include/asm/fsp2/fsp_api.h | 38 + arch/x86/include/asm/fsp2/fsp_internal.h | 16 + arch/x86/include/asm/global_data.h | 21 +- arch/x86/include/asm/mrccache.h | 14 +- arch/x86/include/asm/msr-index.h | 106 +-- arch/x86/include/asm/mtrr.h | 12 + arch/x86/include/asm/pci.h | 37 +- arch/x86/lib/Makefile | 2 + arch/x86/lib/acpi_s3.c | 2 +- arch/x86/lib/coreboot_table.c | 2 +- arch/x86/lib/fsp/fsp_common.c | 22 +- arch/x86/lib/fsp/fsp_dram.c | 35 +- arch/x86/lib/fsp1/fsp_common.c | 22 +- arch/x86/lib/fsp1/fsp_dram.c | 8 +- arch/x86/lib/fsp2/Makefile | 7 + arch/x86/lib/fsp2/fsp_dram.c | 73 ++ arch/x86/lib/fsp2/fsp_meminit.c | 344 ++++++++ arch/x86/lib/fsp2/fsp_support.c | 109 +++ arch/x86/lib/init_helpers.c | 22 +- arch/x86/lib/lpc-uclass.c | 2 + arch/x86/lib/mrccache.c | 186 +++-- arch/x86/lib/spl.c | 42 +- arch/x86/lib/tpl.c | 27 +- board/google/Kconfig | 15 + board/google/chromebook_coral/Kconfig | 43 + board/google/chromebook_coral/MAINTAINERS | 6 + board/google/chromebook_coral/Makefile | 5 + board/google/chromebook_coral/coral.c | 18 + board/google/chromebook_coral/rw-mrc-cache | Bin 0 -> 65536 bytes .../google/chromebook_coral/rw-var-mrc-cache | Bin 0 -> 4096 bytes cmd/Kconfig | 8 + cmd/Makefile | 1 + cmd/io.c | 84 +- cmd/pmc.c | 81 ++ cmd/x86/Makefile | 2 +- common/iotrace.c | 6 +- common/spl/Kconfig | 12 +- common/xyzModem.c | 2 +- configs/am335x_pdu001_defconfig | 2 +- configs/chromebook_coral_defconfig | 95 +++ configs/chromebook_samus_tpl_defconfig | 1 + configs/evb-rk3288_defconfig | 2 +- configs/ls1043ardb_nand_SECURE_BOOT_defconfig | 2 +- configs/ls1043ardb_nand_defconfig | 2 +- .../ls1043ardb_sdcard_SECURE_BOOT_defconfig | 2 +- configs/ls1043ardb_sdcard_defconfig | 2 +- configs/sandbox_defconfig | 2 + configs/sandbox_spl_defconfig | 3 +- configs/tinker-rk3288_defconfig | 2 +- doc/arch/sandbox.rst | 9 + doc/board/google/chromebook_coral.rst | 25 + doc/driver-model/debugging.rst | 62 ++ doc/driver-model/of-plat.rst | 2 +- doc/driver-model/pci-info.rst | 25 +- drivers/Makefile | 2 + drivers/block/blk-uclass.c | 4 +- drivers/core/Makefile | 4 +- drivers/core/device.c | 3 +- drivers/core/fdtaddr.c | 30 + drivers/core/lists.c | 20 +- drivers/core/ofnode.c | 9 +- drivers/core/read.c | 11 + drivers/core/uclass.c | 16 +- drivers/gpio/gpio-uclass.c | 4 +- drivers/gpio/pm8916_gpio.c | 12 +- drivers/misc/Kconfig | 42 + drivers/misc/Makefile | 7 +- drivers/misc/itss-uclass.c | 34 + drivers/misc/itss_sandbox.c | 44 ++ drivers/misc/p2sb-uclass.c | 199 +++++ drivers/misc/p2sb_emul.c | 272 +++++++ drivers/misc/p2sb_sandbox.c | 44 ++ drivers/misc/sandbox_adder.c | 60 ++ drivers/misc/swap_case.c | 48 +- drivers/mmc/mmc.c | 2 +- drivers/mmc/sandbox_mmc.c | 4 + drivers/mtd/spi/sf-uclass.c | 2 +- drivers/nvme/nvme.h | 4 +- drivers/pch/Kconfig | 18 + drivers/pch/Makefile | 4 +- drivers/pch/pch-uclass.c | 2 + drivers/pci/pci-emul-uclass.c | 74 +- drivers/pci/pci-uclass.c | 5 +- drivers/pci/pci_auto.c | 12 +- drivers/pci/pci_auto_common.c | 3 +- drivers/pci/pci_rom.c | 2 +- drivers/pci/pci_sandbox.c | 1 + drivers/pci/pci_x86.c | 16 +- drivers/power/Kconfig | 2 + drivers/power/power_mgr/Kconfig | 34 + drivers/power/power_mgr/Makefile | 6 + drivers/power/power_mgr/pmc_emul.c | 246 ++++++ drivers/power/power_mgr/power-mgr-uclass.c | 242 ++++++ drivers/power/power_mgr/sandbox.c | 97 +++ drivers/serial/ns16550.c | 31 +- drivers/serial/sandbox.c | 2 + drivers/sysreset/sysreset_x86.c | 2 +- drivers/timer/Kconfig | 29 +- drivers/timer/tsc_timer.c | 9 +- {arch/x86/include/asm => include}/acpi_s3.h | 0 include/configs/chromebook_coral.h | 29 + include/configs/mxs.h | 2 +- include/dm/device.h | 9 + include/dm/fdtaddr.h | 8 + include/dm/read.h | 28 +- include/dm/uclass-id.h | 4 + include/dm/uclass-internal.h | 4 +- include/ec_commands.h | 4 + include/fdtdec.h | 17 - include/iotrace.h | 13 +- include/itss.h | 56 ++ include/log.h | 33 +- include/ns16550.h | 4 + include/p2sb.h | 127 +++ include/pci.h | 33 +- include/power/power_mgr.h | 177 +++++ include/spl.h | 16 +- lib/Kconfig | 24 +- lib/Makefile | 2 +- lib/fdtdec.c | 54 -- net/eth-uclass.c | 34 +- scripts/Makefile.lib | 4 +- scripts/config_whitelist.txt | 1 - test/dm/Makefile | 3 + test/dm/core.c | 3 +- test/dm/itss.c | 29 + test/dm/p2sb.c | 28 + test/dm/pci.c | 51 +- test/dm/pmc.c | 33 + test/dm/test-main.c | 16 +- tools/binman/control.py | 36 +- tools/binman/entry.py | 18 + tools/binman/etype/image_header.py | 1 + tools/binman/etype/section.py | 16 +- tools/binman/image.py | 2 + 219 files changed, 9447 insertions(+), 787 deletions(-) create mode 100644 arch/x86/cpu/apollolake/Kconfig create mode 100644 arch/x86/cpu/apollolake/Makefile create mode 100644 arch/x86/cpu/apollolake/cpu.c create mode 100644 arch/x86/cpu/apollolake/cpu_spl.c create mode 100644 arch/x86/cpu/apollolake/gpio.c create mode 100644 arch/x86/cpu/apollolake/hostbridge.c create mode 100644 arch/x86/cpu/apollolake/itss.c create mode 100644 arch/x86/cpu/apollolake/lpc.c create mode 100644 arch/x86/cpu/apollolake/p2sb.c create mode 100644 arch/x86/cpu/apollolake/pch.c create mode 100644 arch/x86/cpu/apollolake/pmc.c create mode 100644 arch/x86/cpu/apollolake/punit.c create mode 100644 arch/x86/cpu/apollolake/spl.c create mode 100644 arch/x86/cpu/apollolake/systemagent.c create mode 100644 arch/x86/cpu/apollolake/uart.c create mode 100644 arch/x86/cpu/intel_common/Kconfig create mode 100644 arch/x86/cpu/intel_common/car2.S create mode 100644 arch/x86/cpu/intel_common/car2_uninit.S create mode 100644 arch/x86/dts/chromebook_coral.dts create mode 100644 arch/x86/include/asm/arch-apollolake/cpu.h create mode 100644 arch/x86/include/asm/arch-apollolake/fast_spi.h create mode 100644 arch/x86/include/asm/arch-apollolake/fsp/fsp_configs.h create mode 100644 arch/x86/include/asm/arch-apollolake/fsp/fsp_m_upd.h create mode 100644 arch/x86/include/asm/arch-apollolake/fsp/fsp_vpd.h create mode 100644 arch/x86/include/asm/arch-apollolake/gpio.h create mode 100644 arch/x86/include/asm/arch-apollolake/gpio_apl.h create mode 100644 arch/x86/include/asm/arch-apollolake/gpio_defs.h create mode 100644 arch/x86/include/asm/arch-apollolake/iomap.h create mode 100644 arch/x86/include/asm/arch-apollolake/itss.h create mode 100644 arch/x86/include/asm/arch-apollolake/lpc.h create mode 100644 arch/x86/include/asm/arch-apollolake/pch.h create mode 100644 arch/x86/include/asm/arch-apollolake/pm.h create mode 100644 arch/x86/include/asm/arch-apollolake/systemagent.h create mode 100644 arch/x86/include/asm/arch-apollolake/uart.h create mode 100644 arch/x86/include/asm/fsp2/fsp_api.h create mode 100644 arch/x86/include/asm/fsp2/fsp_internal.h create mode 100644 arch/x86/lib/fsp2/Makefile create mode 100644 arch/x86/lib/fsp2/fsp_dram.c create mode 100644 arch/x86/lib/fsp2/fsp_meminit.c create mode 100644 arch/x86/lib/fsp2/fsp_support.c create mode 100644 board/google/chromebook_coral/Kconfig create mode 100644 board/google/chromebook_coral/MAINTAINERS create mode 100644 board/google/chromebook_coral/Makefile create mode 100644 board/google/chromebook_coral/coral.c create mode 100644 board/google/chromebook_coral/rw-mrc-cache create mode 100644 board/google/chromebook_coral/rw-var-mrc-cache create mode 100644 cmd/pmc.c create mode 100644 configs/chromebook_coral_defconfig create mode 100644 doc/board/google/chromebook_coral.rst create mode 100644 doc/driver-model/debugging.rst create mode 100644 drivers/misc/itss-uclass.c create mode 100644 drivers/misc/itss_sandbox.c create mode 100644 drivers/misc/p2sb-uclass.c create mode 100644 drivers/misc/p2sb_emul.c create mode 100644 drivers/misc/p2sb_sandbox.c create mode 100644 drivers/misc/sandbox_adder.c create mode 100644 drivers/power/power_mgr/Kconfig create mode 100644 drivers/power/power_mgr/Makefile create mode 100644 drivers/power/power_mgr/pmc_emul.c create mode 100644 drivers/power/power_mgr/power-mgr-uclass.c create mode 100644 drivers/power/power_mgr/sandbox.c rename {arch/x86/include/asm => include}/acpi_s3.h (100%) create mode 100644 include/configs/chromebook_coral.h create mode 100644 include/itss.h create mode 100644 include/p2sb.h create mode 100644 include/power/power_mgr.h create mode 100644 test/dm/itss.c create mode 100644 test/dm/p2sb.c create mode 100644 test/dm/pmc.c

The pr_debug() functions do not response to setting the log level and in fact have their own separate log level. Use U-Boot logging instead.
Perhaps we should make these options redirect to log_debug(), etc.?
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/lists.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/core/lists.c b/drivers/core/lists.c index a1f828463ec..4681b3e5dd1 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -6,6 +6,8 @@ * Marek Vasut marex@denx.de */
+#define LOG_CATEGORY LOGC_DM + #include <common.h> #include <errno.h> #include <dm/device.h> @@ -139,13 +141,13 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, if (devp) *devp = NULL; name = ofnode_get_name(node); - pr_debug("bind node %s\n", name); + log_debug("bind node %s\n", name);
compat_list = ofnode_get_property(node, "compatible", &compat_length); if (!compat_list) { if (compat_length == -FDT_ERR_NOTFOUND) { - pr_debug("Device '%s' has no compatible string\n", - name); + log_debug("Device '%s' has no compatible string\n", + name); return 0; }
@@ -160,8 +162,8 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, */ for (i = 0; i < compat_length; i += strlen(compat) + 1) { compat = compat_list + i; - pr_debug(" - attempt to match compatible string '%s'\n", - compat); + log_debug(" - attempt to match compatible string '%s'\n", + compat);
for (entry = driver; entry != driver + n_ents; entry++) { ret = driver_check_compatible(entry->of_match, &id, @@ -178,11 +180,13 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, return 0; }
- pr_debug(" - found match at '%s'\n", entry->name); + log_debug(" - found match at '%s': '%s' matches '%s'\n", + entry->name, entry->of_match->compatible, + id->compatible); ret = device_bind_with_driver_data(parent, entry, name, id->data, node, &dev); if (ret == -ENODEV) { - pr_debug("Driver '%s' refuses to bind\n", entry->name); + log_debug("Driver '%s' refuses to bind\n", entry->name); continue; } if (ret) { @@ -198,7 +202,7 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, }
if (!found && !result && ret != -ENODEV) - pr_debug("No match for node '%s'\n", name); + log_debug("No match for node '%s'\n", name);
return result; }

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The pr_debug() functions do not response to setting the log level and in fact have their own separate log level. Use U-Boot logging instead.
Perhaps we should make these options redirect to log_debug(), etc.?
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/lists.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 3, 2019 at 8:47 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The pr_debug() functions do not response to setting the log level and in fact have their own separate log level. Use U-Boot logging instead.
Perhaps we should make these options redirect to log_debug(), etc.?
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/lists.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

This reads the low cell of the PCI address from the wrong cell. Fix it. Also fix the function that this code came from.
Fixes: 9e51204527 (dm: core: Add operations on device tree references) Fixes: 4ea5243a3a (fdt: fix fdtdec_get_pci_addr() for CONFIG_PHYS_64BIT) Signed-off-by: Simon Glass sjg@chromium.org --- I can't work out why the existing code is correct, but I suppose it might be for some obscure reason that needs a comment.
The original patch is here: http://patchwork.ozlabs.org/patch/525853/
drivers/core/ofnode.c | 2 +- lib/fdtdec.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 7eca00cd661..5d47eccf1d1 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -617,7 +617,7 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type, if ((fdt32_to_cpu(*cell) & type) == type) { addr->phys_hi = fdt32_to_cpu(cell[0]); addr->phys_mid = fdt32_to_cpu(cell[1]); - addr->phys_lo = fdt32_to_cpu(cell[1]); + addr->phys_lo = fdt32_to_cpu(cell[2]); break; }
diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 74525c84e7b..74430c8b2ff 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -217,7 +217,7 @@ int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, if ((fdt32_to_cpu(*cell) & type) == type) { addr->phys_hi = fdt32_to_cpu(cell[0]); addr->phys_mid = fdt32_to_cpu(cell[1]); - addr->phys_lo = fdt32_to_cpu(cell[1]); + addr->phys_lo = fdt32_to_cpu(cell[2]); break; }

On 9/25/19 8:55 AM, Simon Glass wrote:
This reads the low cell of the PCI address from the wrong cell. Fix it. Also fix the function that this code came from.
Fixes: 9e51204527 (dm: core: Add operations on device tree references) Fixes: 4ea5243a3a (fdt: fix fdtdec_get_pci_addr() for CONFIG_PHYS_64BIT) Signed-off-by: Simon Glass sjg@chromium.org
I can't work out why the existing code is correct, but I suppose it might be for some obscure reason that needs a comment.
The original patch is here: http://patchwork.ozlabs.org/patch/525853/
This makes sense. I am not sure how the original code worked; I can only assume the mid/low values were always both set to 0, or unused, or something?
Tested-by: Stephen Warren swarren@nvidia.com

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This reads the low cell of the PCI address from the wrong cell. Fix it. Also fix the function that this code came from.
Fixes: 9e51204527 (dm: core: Add operations on device tree references) Fixes: 4ea5243a3a (fdt: fix fdtdec_get_pci_addr() for CONFIG_PHYS_64BIT) Signed-off-by: Simon Glass sjg@chromium.org
I can't work out why the existing code is correct, but I suppose it might be for some obscure reason that needs a comment.
The original patch is here: http://patchwork.ozlabs.org/patch/525853/
drivers/core/ofnode.c | 2 +- lib/fdtdec.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
I think this should go in v2019.10.
Tom, I will prepare a PR soon.
Regards, Bin

On Thu, Oct 3, 2019 at 8:47 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This reads the low cell of the PCI address from the wrong cell. Fix it. Also fix the function that this code came from.
Fixes: 9e51204527 (dm: core: Add operations on device tree references) Fixes: 4ea5243a3a (fdt: fix fdtdec_get_pci_addr() for CONFIG_PHYS_64BIT) Signed-off-by: Simon Glass sjg@chromium.org
I can't work out why the existing code is correct, but I suppose it might be for some obscure reason that needs a comment.
The original patch is here: http://patchwork.ozlabs.org/patch/525853/
drivers/core/ofnode.c | 2 +- lib/fdtdec.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
I think this should go in v2019.10.
Tom, I will prepare a PR soon.
applied to u-boot-x86, thanks!

Two functions in this file return early for no good reason. Adjust the code to match the standard DM style of returning 0 at the end of the function on success.
Oddly enough this save 12 bytes of code size on ARM.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/uclass.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index b33296542f6..af575bbeb72 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -714,8 +714,11 @@ int uclass_pre_probe_device(struct udevice *dev) if (!dev->parent) return 0; uc_drv = dev->parent->uclass->uc_drv; - if (uc_drv->child_pre_probe) - return uc_drv->child_pre_probe(dev); + if (uc_drv->child_pre_probe) { + ret = uc_drv->child_pre_probe(dev); + if (ret) + return ret; + }
return 0; } @@ -735,8 +738,11 @@ int uclass_post_probe_device(struct udevice *dev) }
uc_drv = dev->uclass->uc_drv; - if (uc_drv->post_probe) - return uc_drv->post_probe(dev); + if (uc_drv->post_probe) { + ret = uc_drv->post_probe(dev); + if (ret) + return ret; + }
return 0; }

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Two functions in this file return early for no good reason. Adjust the code to match the standard DM style of returning 0 at the end of the function on success.
Oddly enough this save 12 bytes of code size on ARM.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/uclass.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 3, 2019 at 8:47 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Two functions in this file return early for no good reason. Adjust the code to match the standard DM style of returning 0 at the end of the function on success.
Oddly enough this save 12 bytes of code size on ARM.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/uclass.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Sometimes devices don't appear and it can be confusing. Add a few notes to help with this situation.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/driver-model/debugging.rst | 62 ++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 doc/driver-model/debugging.rst
diff --git a/doc/driver-model/debugging.rst b/doc/driver-model/debugging.rst new file mode 100644 index 00000000000..9711dd6d653 --- /dev/null +++ b/doc/driver-model/debugging.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. sectionauthor:: Simon Glass sjg@chromium.org + +Debugging driver model +====================== + +This document aims to provide help when you cannot work out why driver model is +not doing what you expect. + + +Useful techniques in general +---------------------------- + +Here are some useful debugging features generally. + + - If you are writing a new feature, consider doing it in sandbox instead of + on your board. Sandbox has no limits, allows each debugging (e.g. gdb) and + you can writing emulators for most common devices. + - Put '#define DEBUG' at the top of a file, to activate all the debug() and + log_debug() statements in that file. + - Where logging is used, change the logging level, e.g. in SPL with + CONFIG_SPL_LOG_MAX_LEVEL=7 (which is LOGL_DEBUG) and + CONFIG_LOG_DEFAULT_LEVEL=7 + - Where logging of return values is implemented with log_msg_ret(), set + CONFIG_LOG_ERROR_RETURN=y to see exactly where the error is happening + - Make sure you have a debug UART enabled - see CONFIG_DEBUG_UART. With this + you can get serial output (printf(), etc.) before the serial driver is + running. + - Use a JTAG emulator to set breakpoints and single-step through code + +Not that most of these increase code/data size somewhat when enabled. + + +Failure to locate a device +-------------------------- + +Let's say you have uclass_first_device_err() and it is not finding anything. + +If it is returning an error, then that gives you a clue. Look up linux/errno.h +to see errors. Common ones are: + + - -ENOMEM which indicates that memory is short. If it happens in SPL or + before relocation in U-Boot, check CONFIG_SPL_SYS_MALLOC_F_LEN and + CONFIG_SYS_MALLOC_F_LEN as they may need to be larger. Add '#define DEBUG' + at the very top of malloc_simple.c to get an idea of where your memory is + going. + - -EINVAL which typically indicates that something was missing or wrong in + the device tree node. Check that everything is correct and look at the + ofdata_to_platdata() method in the driver. + +If there is no error, you should check if the device is actually bound. Call +dm_dump_all() just before you locate the device to make sure it exists. + +If it does not exist, check your device tree compatible strings match up with +what the driver expects (in the struct udevice_id array). + +If you are using of-platdata (e.g. CONFIG_SPL_OF_PLATDATA), check that the +driver name is the same as the first compatible string in the device tree (with +invalid-variable characters converted to underscore). + +If you are really stuck, #define DEBUG at the top of lists.c should show you +what is going on.

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Sometimes devices don't appear and it can be confusing. Add a few notes to help with this situation.
Signed-off-by: Simon Glass sjg@chromium.org
doc/driver-model/debugging.rst | 62 ++++++++++++++++++++++++++++++++++
missed updating index.rst to include this doc.
I can fix this when applying.
1 file changed, 62 insertions(+) create mode 100644 doc/driver-model/debugging.rst
diff --git a/doc/driver-model/debugging.rst b/doc/driver-model/debugging.rst new file mode 100644 index 00000000000..9711dd6d653 --- /dev/null +++ b/doc/driver-model/debugging.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. sectionauthor:: Simon Glass sjg@chromium.org
+Debugging driver model +======================
+This document aims to provide help when you cannot work out why driver model is +not doing what you expect.
+Useful techniques in general +----------------------------
+Here are some useful debugging features generally.
- If you are writing a new feature, consider doing it in sandbox instead of
on your board. Sandbox has no limits, allows each debugging (e.g. gdb) and
easy debugging
you can writing emulators for most common devices.
write
- Put '#define DEBUG' at the top of a file, to activate all the debug() and
log_debug() statements in that file.
- Where logging is used, change the logging level, e.g. in SPL with
CONFIG_SPL_LOG_MAX_LEVEL=7 (which is LOGL_DEBUG) and
CONFIG_LOG_DEFAULT_LEVEL=7
- Where logging of return values is implemented with log_msg_ret(), set
CONFIG_LOG_ERROR_RETURN=y to see exactly where the error is happening
- Make sure you have a debug UART enabled - see CONFIG_DEBUG_UART. With this
you can get serial output (printf(), etc.) before the serial driver is
running.
- Use a JTAG emulator to set breakpoints and single-step through code
+Not that most of these increase code/data size somewhat when enabled.
+Failure to locate a device +--------------------------
+Let's say you have uclass_first_device_err() and it is not finding anything.
+If it is returning an error, then that gives you a clue. Look up linux/errno.h +to see errors. Common ones are:
- -ENOMEM which indicates that memory is short. If it happens in SPL or
before relocation in U-Boot, check CONFIG_SPL_SYS_MALLOC_F_LEN and
CONFIG_SYS_MALLOC_F_LEN as they may need to be larger. Add '#define DEBUG'
at the very top of malloc_simple.c to get an idea of where your memory is
going.
- -EINVAL which typically indicates that something was missing or wrong in
the device tree node. Check that everything is correct and look at the
ofdata_to_platdata() method in the driver.
+If there is no error, you should check if the device is actually bound. Call +dm_dump_all() just before you locate the device to make sure it exists.
+If it does not exist, check your device tree compatible strings match up with +what the driver expects (in the struct udevice_id array).
+If you are using of-platdata (e.g. CONFIG_SPL_OF_PLATDATA), check that the +driver name is the same as the first compatible string in the device tree (with +invalid-variable characters converted to underscore).
+If you are really stuck, #define DEBUG at the top of lists.c should show you
+what is going on.
Other than that,
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 3, 2019 at 8:47 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Sometimes devices don't appear and it can be confusing. Add a few notes to help with this situation.
Signed-off-by: Simon Glass sjg@chromium.org
doc/driver-model/debugging.rst | 62 ++++++++++++++++++++++++++++++++++
missed updating index.rst to include this doc.
I can fix this when applying.
1 file changed, 62 insertions(+) create mode 100644 doc/driver-model/debugging.rst
diff --git a/doc/driver-model/debugging.rst b/doc/driver-model/debugging.rst new file mode 100644 index 00000000000..9711dd6d653 --- /dev/null +++ b/doc/driver-model/debugging.rst @@ -0,0 +1,62 @@ +.. SPDX-License-Identifier: GPL-2.0+ +.. sectionauthor:: Simon Glass sjg@chromium.org
+Debugging driver model +======================
+This document aims to provide help when you cannot work out why driver model is +not doing what you expect.
+Useful techniques in general +----------------------------
+Here are some useful debugging features generally.
- If you are writing a new feature, consider doing it in sandbox instead of
on your board. Sandbox has no limits, allows each debugging (e.g. gdb) and
easy debugging
you can writing emulators for most common devices.
write
Fixed these issues, and
- Put '#define DEBUG' at the top of a file, to activate all the debug() and
log_debug() statements in that file.
- Where logging is used, change the logging level, e.g. in SPL with
CONFIG_SPL_LOG_MAX_LEVEL=7 (which is LOGL_DEBUG) and
CONFIG_LOG_DEFAULT_LEVEL=7
- Where logging of return values is implemented with log_msg_ret(), set
CONFIG_LOG_ERROR_RETURN=y to see exactly where the error is happening
- Make sure you have a debug UART enabled - see CONFIG_DEBUG_UART. With this
you can get serial output (printf(), etc.) before the serial driver is
running.
- Use a JTAG emulator to set breakpoints and single-step through code
+Not that most of these increase code/data size somewhat when enabled.
+Failure to locate a device +--------------------------
+Let's say you have uclass_first_device_err() and it is not finding anything.
+If it is returning an error, then that gives you a clue. Look up linux/errno.h +to see errors. Common ones are:
- -ENOMEM which indicates that memory is short. If it happens in SPL or
before relocation in U-Boot, check CONFIG_SPL_SYS_MALLOC_F_LEN and
CONFIG_SYS_MALLOC_F_LEN as they may need to be larger. Add '#define DEBUG'
at the very top of malloc_simple.c to get an idea of where your memory is
going.
- -EINVAL which typically indicates that something was missing or wrong in
the device tree node. Check that everything is correct and look at the
ofdata_to_platdata() method in the driver.
+If there is no error, you should check if the device is actually bound. Call +dm_dump_all() just before you locate the device to make sure it exists.
+If it does not exist, check your device tree compatible strings match up with +what the driver expects (in the struct udevice_id array).
+If you are using of-platdata (e.g. CONFIG_SPL_OF_PLATDATA), check that the +driver name is the same as the first compatible string in the device tree (with +invalid-variable characters converted to underscore).
+If you are really stuck, #define DEBUG at the top of lists.c should show you
+what is going on.
Other than that,
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

These functions cannot work with of-platdata since libfdt is not available. At present when dev_read_...() functions are used it produces error messages about ofnode which is confusing.
Adjust the Makefile and header to produce an error message for the actual dev_read...() function which is called. This makes it easier to see what code needs to be converted for use with of-platdata.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/Makefile | 4 +++- include/dm/read.h | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index bce7467da1d..b9e4a2aab1a 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -13,6 +13,8 @@ obj-$(CONFIG_OF_LIVE) += of_access.o of_addr.o ifndef CONFIG_DM_DEV_READ_INLINE obj-$(CONFIG_OF_CONTROL) += read.o endif -obj-$(CONFIG_OF_CONTROL) += of_extra.o ofnode.o read_extra.o +ifdef CONFIG_$(SPL_TPL_)OF_LIBFDT +obj-$(CONFIG_$(SPL_TPL_)OF_CONTROL) += of_extra.o ofnode.o read_extra.o +endif
ccflags-$(CONFIG_DM_DEBUG) += -DDEBUG diff --git a/include/dm/read.h b/include/dm/read.h index 803daf7620c..03189838ff7 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -43,8 +43,7 @@ static inline bool dev_of_valid(struct udevice *dev) return ofnode_valid(dev_ofnode(dev)); }
-#ifndef CONFIG_DM_DEV_READ_INLINE - +#if !defined(CONFIG_DM_DEV_READ_INLINE) || CONFIG_IS_ENABLED(OF_PLATDATA) /** * dev_read_u32() - read a 32-bit integer from a device's DT property *

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions cannot work with of-platdata since libfdt is not available. At present when dev_read_...() functions are used it produces error messages about ofnode which is confusing.
Adjust the Makefile and header to produce an error message for the actual dev_read...() function which is called. This makes it easier to see what code needs to be converted for use with of-platdata.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/Makefile | 4 +++- include/dm/read.h | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 3, 2019 at 8:48 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions cannot work with of-platdata since libfdt is not available. At present when dev_read_...() functions are used it produces error messages about ofnode which is confusing.
Adjust the Makefile and header to produce an error message for the actual dev_read...() function which is called. This makes it easier to see what code needs to be converted for use with of-platdata.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/Makefile | 4 +++- include/dm/read.h | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Hi Simon,
On Sun, Oct 6, 2019 at 5:15 PM Bin Meng bmeng.cn@gmail.com wrote:
On Thu, Oct 3, 2019 at 8:48 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions cannot work with of-platdata since libfdt is not available. At present when dev_read_...() functions are used it produces error messages about ofnode which is confusing.
Adjust the Makefile and header to produce an error message for the actual dev_read...() function which is called. This makes it easier to see what code needs to be converted for use with of-platdata.
As this commit message says, with this patch now it causes a large number of ARM boards build break. See: https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/16696 https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/16697
So this is intentional, but I think we should provide the build fix at the same time to make gitlab-CI happy.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/Makefile | 4 +++- include/dm/read.h | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!
I will have to drop this patch from the queue.
Regards, Bin

Hi Bin,
On Sun, 6 Oct 2019 at 19:40, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sun, Oct 6, 2019 at 5:15 PM Bin Meng bmeng.cn@gmail.com wrote:
On Thu, Oct 3, 2019 at 8:48 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions cannot work with of-platdata since libfdt is not available. At present when dev_read_...() functions are used it produces error messages about ofnode which is confusing.
Adjust the Makefile and header to produce an error message for the actual dev_read...() function which is called. This makes it easier to see what code needs to be converted for use with of-platdata.
As this commit message says, with this patch now it causes a large number of ARM boards build break. See: https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/16696 https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/16697
So this is intentional, but I think we should provide the build fix at the same time to make gitlab-CI happy.
Yes that makes sense. In fact I think I'll pull this out into a separate series since it is better done with multiple patches.
Regards, Simon

At present this code passes an fdt_addr_t pointer as a u64 pointer which is not save, since sizeof(fdt_addr_t) may be 4, e.g. with sandbox. Correct this to avoid a stack corruption problem.
Fixes: e679d03b08 (core: ofnode: Add ofnode_get_addr_size_index) Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/ofnode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 5d47eccf1d1..297f0a0c7cc 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -261,12 +261,15 @@ fdt_addr_t ofnode_get_addr_size_index(ofnode node, int index, fdt_size_t *size)
if (ofnode_is_np(node)) { const __be32 *prop_val; + u64 size64; uint flags;
- prop_val = of_get_address(ofnode_to_np(node), index, - (u64 *)size, &flags); + prop_val = of_get_address(ofnode_to_np(node), index, &size64, + &flags); if (!prop_val) return FDT_ADDR_T_NONE; + if (size) + *size = size64;
ns = of_n_size_cells(ofnode_to_np(node));

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this code passes an fdt_addr_t pointer as a u64 pointer which is not save, since sizeof(fdt_addr_t) may be 4, e.g. with sandbox. Correct
not safe
this to avoid a stack corruption problem.
Fixes: e679d03b08 (core: ofnode: Add ofnode_get_addr_size_index) Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/ofnode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
I think this should go in v2019.10.
Tom, I will prepare a PR soon.
Regards, Bin

On Thu, Oct 3, 2019 at 8:48 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this code passes an fdt_addr_t pointer as a u64 pointer which is not save, since sizeof(fdt_addr_t) may be 4, e.g. with sandbox. Correct
not safe
Fixed this typo, and
this to avoid a stack corruption problem.
Fixes: e679d03b08 (core: ofnode: Add ofnode_get_addr_size_index) Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/ofnode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
I think this should go in v2019.10.
Tom, I will prepare a PR soon.
applied to u-boot-x86, thanks!

At present when multiple 'ut dm' commands are executed, all but the first is run with a flat tree, even if live tree is enabled. This is because the live tree node pointer is set to NULL and never restored.
This does not affect normal test running, which just runs all the test in one go, but can be confusing when several individual tests are run during the same U-Boot run.
Correct this by restoring the pointer.
Fixes: c166c47ba3 (dm: test: Add support for running tests with livetree) Signed-off-by: Simon Glass sjg@chromium.org ---
test/dm/test-main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 5d79ce641d7..487d8b96275 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -188,8 +188,12 @@ static int dm_test_main(const char *test_name) else printf("Failures: %d\n", uts->fail_count);
+ /* Put everything back to normal so that sandbox works as expected */ +#ifdef CONFIG_OF_LIVE + gd->of_root = uts->of_root; +#endif gd->dm_root = NULL; - ut_assertok(dm_init(false)); + ut_assertok(dm_init(IS_ENABLED(CONFIG_OF_LIVE))); dm_scan_platdata(false); dm_scan_fdt(gd->fdt_blob, false);

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present when multiple 'ut dm' commands are executed, all but the first is run with a flat tree, even if live tree is enabled. This is because the live tree node pointer is set to NULL and never restored.
This does not affect normal test running, which just runs all the test in one go, but can be confusing when several individual tests are run during the same U-Boot run.
Correct this by restoring the pointer.
Fixes: c166c47ba3 (dm: test: Add support for running tests with livetree) Signed-off-by: Simon Glass sjg@chromium.org
test/dm/test-main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Fri, Oct 4, 2019 at 5:44 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present when multiple 'ut dm' commands are executed, all but the first is run with a flat tree, even if live tree is enabled. This is because the live tree node pointer is set to NULL and never restored.
This does not affect normal test running, which just runs all the test in one go, but can be confusing when several individual tests are run during the same U-Boot run.
Correct this by restoring the pointer.
Fixes: c166c47ba3 (dm: test: Add support for running tests with livetree) Signed-off-by: Simon Glass sjg@chromium.org
test/dm/test-main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present tests that are marked as only for livetree fail when executed on sandbox_flattree. They cannot actually be executed, but we should not resport them as 'not found', since this causes errors. Instead, they should be silently skipped.
Signed-off-by: Simon Glass sjg@chromium.org ---
test/dm/test-main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 487d8b96275..74f77ccc849 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -130,7 +130,7 @@ static int dm_test_main(const char *test_name) const int n_ents = ll_entry_count(struct unit_test, dm_test); struct unit_test_state *uts = &global_dm_test_state; struct unit_test *test; - int run_count; + int found;
uts->priv = &_global_priv_dm_test_state; uts->fail_count = 0; @@ -148,7 +148,7 @@ static int dm_test_main(const char *test_name) if (!test_name) printf("Running %d driver model tests\n", n_ents);
- run_count = 0; + found = 0; #ifdef CONFIG_OF_LIVE uts->of_root = gd->of_root; #endif @@ -180,10 +180,10 @@ static int dm_test_main(const char *test_name) ut_assertok(dm_do_test(uts, test, false)); runs++; } - run_count += runs; + found++; }
- if (test_name && !run_count) + if (test_name && !found) printf("Test '%s' not found\n", test_name); else printf("Failures: %d\n", uts->fail_count);

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present tests that are marked as only for livetree fail when executed on sandbox_flattree. They cannot actually be executed, but we should not resport them as 'not found', since this causes errors. Instead, they should be silently skipped.
Signed-off-by: Simon Glass sjg@chromium.org
test/dm/test-main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Fri, Oct 4, 2019 at 5:44 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present tests that are marked as only for livetree fail when executed on sandbox_flattree. They cannot actually be executed, but we should not resport them as 'not found', since this causes errors. Instead, they should be silently skipped.
Signed-off-by: Simon Glass sjg@chromium.org
test/dm/test-main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present this function is never called when of-platdata is enabled since we never have a device tree. However, this function is responsible for copying over the of-platdata, so we must call it. Otherwise the probe() method would have to be used.
Correct this and fix the sandbox serial driver to not read from the device tree and try to write to what is read-only platdata on some platforms.
Fixes: 396e343b3d (dm: core: Allow binding a device from a live tree) Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/device.c | 3 ++- drivers/serial/sandbox.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/core/device.c b/drivers/core/device.c index 05dadf98f95..84f0f0fbf0e 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -404,7 +404,8 @@ int device_probe(struct udevice *dev) goto fail; }
- if (drv->ofdata_to_platdata && dev_has_of_node(dev)) { + if (drv->ofdata_to_platdata && + (CONFIG_IS_ENABLED(OF_PLATDATA) || dev_has_of_node(dev))) { ret = drv->ofdata_to_platdata(dev); if (ret) goto fail; diff --git a/drivers/serial/sandbox.c b/drivers/serial/sandbox.c index 33102fc872f..2f7bc248871 100644 --- a/drivers/serial/sandbox.c +++ b/drivers/serial/sandbox.c @@ -220,6 +220,8 @@ static int sandbox_serial_ofdata_to_platdata(struct udevice *dev) const char *colour; int i;
+ if (CONFIG_IS_ENABLED(OF_PLATDATA)) + return 0; plat->colour = -1; colour = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "sandbox,text-colour", NULL);

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this function is never called when of-platdata is enabled since we never have a device tree. However, this function is responsible for copying over the of-platdata, so we must call it. Otherwise the probe() method would have to be used.
Correct this and fix the sandbox serial driver to not read from the device tree and try to write to what is read-only platdata on some platforms.
Fixes: 396e343b3d (dm: core: Allow binding a device from a live tree) Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/device.c | 3 ++- drivers/serial/sandbox.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Fri, Oct 4, 2019 at 5:44 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this function is never called when of-platdata is enabled since we never have a device tree. However, this function is responsible for copying over the of-platdata, so we must call it. Otherwise the probe() method would have to be used.
Correct this and fix the sandbox serial driver to not read from the device tree and try to write to what is read-only platdata on some platforms.
Fixes: 396e343b3d (dm: core: Allow binding a device from a live tree) Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/device.c | 3 ++- drivers/serial/sandbox.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

This condition is not correct since it should not include an SPL_ prefix. Fix it and also add a note about the driver name in the same file.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/driver-model/of-plat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/driver-model/of-plat.rst b/doc/driver-model/of-plat.rst index a38e58e4d29..557957d2a16 100644 --- a/doc/driver-model/of-plat.rst +++ b/doc/driver-model/of-plat.rst @@ -269,7 +269,7 @@ For example: };
U_BOOT_DRIVER(mmc_drv) = { - .name = "mmc", + .name = "vendor_mmc", /* matches compatible string */ .id = UCLASS_MMC, .of_match = mmc_ids, .ofdata_to_platdata = mmc_ofdata_to_platdata,

Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This condition is not correct since it should not include an SPL_ prefix. Fix it and also add a note about the driver name in the same file.
Signed-off-by: Simon Glass sjg@chromium.org
doc/driver-model/of-plat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/driver-model/of-plat.rst b/doc/driver-model/of-plat.rst index a38e58e4d29..557957d2a16 100644 --- a/doc/driver-model/of-plat.rst +++ b/doc/driver-model/of-plat.rst @@ -269,7 +269,7 @@ For example: };
U_BOOT_DRIVER(mmc_drv) = {
.name = "mmc",
.name = "vendor_mmc", /* matches compatible string */
This single line change only does half of what the commit message says. Where is the other half?
.id = UCLASS_MMC, .of_match = mmc_ids, .ofdata_to_platdata = mmc_ofdata_to_platdata,
--
Regards, Bin

Hi Bin,
On Fri, 4 Oct 2019 at 03:44, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This condition is not correct since it should not include an SPL_ prefix. Fix it and also add a note about the driver name in the same file.
Signed-off-by: Simon Glass sjg@chromium.org
doc/driver-model/of-plat.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/driver-model/of-plat.rst b/doc/driver-model/of-plat.rst index a38e58e4d29..557957d2a16 100644 --- a/doc/driver-model/of-plat.rst +++ b/doc/driver-model/of-plat.rst @@ -269,7 +269,7 @@ For example: };
U_BOOT_DRIVER(mmc_drv) = {
.name = "mmc",
.name = "vendor_mmc", /* matches compatible string */
This single line change only does half of what the commit message says. Where is the other half?
Yes this part was fixed by someone else's patch and I forgot about it. I'll update the patch.
.id = UCLASS_MMC, .of_match = mmc_ids, .ofdata_to_platdata = mmc_ofdata_to_platdata,
--
Regards, Simon

This function returns -ENODEV when there is no device. This is inconsistent with other functions, such as uclass_find_next_device(), which returns 0.
Update it and tidy up the incorrect '-1' values in the comments.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/uclass.c | 2 +- include/dm/uclass-internal.h | 4 ++-- test/dm/core.c | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index af575bbeb72..f217876cd2c 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -225,7 +225,7 @@ int uclass_find_first_device(enum uclass_id id, struct udevice **devp) if (ret) return ret; if (list_empty(&uc->dev_head)) - return -ENODEV; + return 0;
*devp = list_first_entry(&uc->dev_head, struct udevice, uclass_node);
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index 6977995246d..6e3f15c2b08 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -69,7 +69,7 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp); * The device is not prepared for use - this is an internal function. * The function uclass_get_device_tail() can be used to probe the device. * - * @return 0 if OK (found or not found), -1 on error + * @return 0 if OK (found or not found), -ve on error */ int uclass_find_first_device(enum uclass_id id, struct udevice **devp);
@@ -81,7 +81,7 @@ int uclass_find_first_device(enum uclass_id id, struct udevice **devp); * The device is not prepared for use - this is an internal function. * The function uclass_get_device_tail() can be used to probe the device. * - * @return 0 if OK (found or not found), -1 on error + * @return 0 if OK (found or not found), -ve on error */ int uclass_find_next_device(struct udevice **devp);
diff --git a/test/dm/core.c b/test/dm/core.c index edd55b05d6e..f74c4308439 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -749,8 +749,7 @@ static int dm_test_uclass_devices_find(struct unit_test_state *uts) ut_assert(dev); }
- ret = uclass_find_first_device(UCLASS_TEST_DUMMY, &dev); - ut_assert(ret == -ENODEV); + ut_assertok(uclass_find_first_device(UCLASS_TEST_DUMMY, &dev)); ut_assert(!dev);
return 0;

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This function returns -ENODEV when there is no device. This is inconsistent with other functions, such as uclass_find_next_device(), which returns 0.
Update it and tidy up the incorrect '-1' values in the comments.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/uclass.c | 2 +- include/dm/uclass-internal.h | 4 ++-- test/dm/core.c | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Fri, Oct 4, 2019 at 5:44 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This function returns -ENODEV when there is no device. This is inconsistent with other functions, such as uclass_find_next_device(), which returns 0.
Update it and tidy up the incorrect '-1' values in the comments.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/uclass.c | 2 +- include/dm/uclass-internal.h | 4 ++-- test/dm/core.c | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

We have a 'safe' version of this function but sometimes it is not needed. Add a normal version too and update a few places that can use it.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/mach-uniphier/pinctrl-glue.c | 4 ++-- drivers/block/blk-uclass.c | 4 ++-- include/dm/device.h | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-uniphier/pinctrl-glue.c b/arch/arm/mach-uniphier/pinctrl-glue.c index c4d3b17c39d..b45f72f59a7 100644 --- a/arch/arm/mach-uniphier/pinctrl-glue.c +++ b/arch/arm/mach-uniphier/pinctrl-glue.c @@ -13,14 +13,14 @@
int uniphier_pin_init(const char *pinconfig_name) { - struct udevice *pctldev, *config, *next; + struct udevice *pctldev, *config; int ret;
ret = uclass_first_device(UCLASS_PINCTRL, &pctldev); if (ret) return ret;
- device_foreach_child_safe(config, next, pctldev) { + device_foreach_child(config, pctldev) { if (strcmp(config->name, pinconfig_name)) continue;
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index baaf431e5e0..e8f58b3f5e4 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -142,9 +142,9 @@ struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) */ struct blk_desc *blk_get_by_device(struct udevice *dev) { - struct udevice *child_dev, *next; + struct udevice *child_dev;
- device_foreach_child_safe(child_dev, next, dev) { + device_foreach_child(child_dev, dev) { if (device_get_uclass_id(child_dev) != UCLASS_BLK) continue;
diff --git a/include/dm/device.h b/include/dm/device.h index 27a6d7b9fdb..d1210429e92 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -679,6 +679,15 @@ static inline bool device_is_on_pci_bus(struct udevice *dev) #define device_foreach_child_safe(pos, next, parent) \ list_for_each_entry_safe(pos, next, &parent->child_head, sibling_node)
+/** + * device_foreach_child() - iterate through child devices + * + * @pos: struct udevice * for the current device + * @parent: parent device to scan + */ +#define device_foreach_child(pos, parent) \ + list_for_each_entry(pos, &parent->child_head, sibling_node) + /** * dm_scan_fdt_dev() - Bind child device in a the device tree *

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
We have a 'safe' version of this function but sometimes it is not needed. Add a normal version too and update a few places that can use it.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/mach-uniphier/pinctrl-glue.c | 4 ++-- drivers/block/blk-uclass.c | 4 ++-- include/dm/device.h | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Fri, Oct 4, 2019 at 5:44 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
We have a 'safe' version of this function but sometimes it is not needed. Add a normal version too and update a few places that can use it.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/mach-uniphier/pinctrl-glue.c | 4 ++-- drivers/block/blk-uclass.c | 4 ++-- include/dm/device.h | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

This should perhaps be a period but it is not necessary. Remove it.
Signed-off-by: Simon Glass sjg@chromium.org ---
test/dm/test-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 74f77ccc849..c944ab9c5f2 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -64,7 +64,7 @@ static int dm_test_destroy(struct unit_test_state *uts)
/* * If the uclass doesn't exist we don't want to create it. So - * check that here before we call uclass_find_device()/ + * check that here before we call uclass_find_device() */ uc = uclass_find(id); if (!uc)

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This should perhaps be a period but it is not necessary. Remove it.
Signed-off-by: Simon Glass sjg@chromium.org
test/dm/test-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 74f77ccc849..c944ab9c5f2 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -64,7 +64,7 @@ static int dm_test_destroy(struct unit_test_state *uts)
/* * If the uclass doesn't exist we don't want to create it. So
* check that here before we call uclass_find_device()/
* check that here before we call uclass_find_device()
I tend to use a period since it's a complete sentence.
*/ uc = uclass_find(id); if (!uc)
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Fri, Oct 4, 2019 at 5:44 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This should perhaps be a period but it is not necessary. Remove it.
Signed-off-by: Simon Glass sjg@chromium.org
test/dm/test-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/test/dm/test-main.c b/test/dm/test-main.c index 74f77ccc849..c944ab9c5f2 100644 --- a/test/dm/test-main.c +++ b/test/dm/test-main.c @@ -64,7 +64,7 @@ static int dm_test_destroy(struct unit_test_state *uts)
/* * If the uclass doesn't exist we don't want to create it. So
* check that here before we call uclass_find_device()/
* check that here before we call uclass_find_device()
I tend to use a period since it's a complete sentence.
Added the ending period, reworded the commit message, and
*/ uc = uclass_find(id); if (!uc)
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

When device-tree compilation fails it is sometimes tricky to see which line is broken, since the input file to dtc is a pre-processed version of the device tree.
Add a line that points to the file that needs to be checked:
Output is something like this:
Error: arch/x86/dts/.chromebook_coral.dtb.pre.tmp:170.15-16 syntax error FATAL ERROR: Unable to parse input tree Check /tmp/b/chromebook_coral/arch/x86/dts/.chromebook_coral.dtb.pre.tmp for errors
Signed-off-by: Simon Glass sjg@chromium.org ---
scripts/Makefile.lib | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index ef116e0e0ae..c10cd83a0a3 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -300,7 +300,9 @@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $(pre-tmp) ; \ $(DTC) -O dtb -o $@ -b 0 \ -i $(dir $<) $(DTC_FLAGS) \ - -d $(depfile).dtc.tmp $(dtc-tmp) ; \ + -d $(depfile).dtc.tmp $(dtc-tmp) || \ + (echo "Check $(shell pwd)/$(pre-tmp) for errors" && false) \ + ; \ cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) ; \ sed -i "s:$(pre-tmp):$(<):" $(depfile)

Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
When device-tree compilation fails it is sometimes tricky to see which line is broken, since the input file to dtc is a pre-processed version of the device tree.
Add a line that points to the file that needs to be checked:
Output is something like this:
Error: arch/x86/dts/.chromebook_coral.dtb.pre.tmp:170.15-16 syntax error
This line already provides information that you need.
FATAL ERROR: Unable to parse input tree Check /tmp/b/chromebook_coral/arch/x86/dts/.chromebook_coral.dtb.pre.tmp
I don't understand why we need another line that provides the same information.
for errors
Signed-off-by: Simon Glass sjg@chromium.org
scripts/Makefile.lib | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Regards, Bin

Hi Bin,
On Fri, 4 Oct 2019 at 03:45, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
When device-tree compilation fails it is sometimes tricky to see which line is broken, since the input file to dtc is a pre-processed version of the device tree.
Add a line that points to the file that needs to be checked:
Output is something like this:
Error: arch/x86/dts/.chromebook_coral.dtb.pre.tmp:170.15-16 syntax error
This line already provides information that you need.
FATAL ERROR: Unable to parse input tree Check /tmp/b/chromebook_coral/arch/x86/dts/.chromebook_coral.dtb.pre.tmp
I don't understand why we need another line that provides the same information.
Yes that is a bad example, I will update it. If a .dtsi has a CONFIG it is not possible from the source file to work one what when wrong.
for errors
Signed-off-by: Simon Glass sjg@chromium.org
scripts/Makefile.lib | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Regards, Simon

At present address translation does not work since there is no ranges property in the spmi nodes. Add empty ranges properties and a little more logging so that this shows the error:
/tmp/b/sandbox/u-boot -d /tmp/b/sandbox/arch/sandbox/dts/test.dtb \ -c "ut dm spmi_access_peripheral" -L7 -v ... pm8916_gpio_probe() bad address: returning err=-22
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/test.dts | 2 ++ drivers/gpio/pm8916_gpio.c | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 208551d7c19..f664b65b72d 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -717,11 +717,13 @@ compatible = "sandbox,spmi"; #address-cells = <0x1>; #size-cells = <0x1>; + ranges; pm8916@0 { compatible = "qcom,spmi-pmic"; reg = <0x0 0x1>; #address-cells = <0x1>; #size-cells = <0x1>; + ranges;
spmi_gpios: gpios@c000 { compatible = "qcom,pm8916-gpio"; diff --git a/drivers/gpio/pm8916_gpio.c b/drivers/gpio/pm8916_gpio.c index bbe214d5eea..74a773c099b 100644 --- a/drivers/gpio/pm8916_gpio.c +++ b/drivers/gpio/pm8916_gpio.c @@ -172,16 +172,16 @@ static int pm8916_gpio_probe(struct udevice *dev)
priv->pid = dev_read_addr(dev); if (priv->pid == FDT_ADDR_T_NONE) - return -EINVAL; + return log_msg_ret("bad address", -EINVAL);
/* Do a sanity check */ reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE); if (reg != 0x10) - return -ENODEV; + return log_msg_ret("bad type", -ENXIO);
reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE); if (reg != 0x5 && reg != 0x1) - return -ENODEV; + return log_msg_ret("bad subtype", -ENXIO);
return 0; } @@ -257,16 +257,16 @@ static int pm8941_pwrkey_probe(struct udevice *dev)
priv->pid = devfdt_get_addr(dev); if (priv->pid == FDT_ADDR_T_NONE) - return -EINVAL; + return log_msg_ret("bad address", -EINVAL);
/* Do a sanity check */ reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE); if (reg != 0x1) - return -ENODEV; + return log_msg_ret("bad type", -ENXIO);
reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE); if (reg != 0x1) - return -ENODEV; + return log_msg_ret("bad subtype", -ENXIO);
return 0; }

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present address translation does not work since there is no ranges property in the spmi nodes. Add empty ranges properties and a little more logging so that this shows the error:
/tmp/b/sandbox/u-boot -d /tmp/b/sandbox/arch/sandbox/dts/test.dtb \ -c "ut dm spmi_access_peripheral" -L7 -v ... pm8916_gpio_probe() bad address: returning err=-22
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/test.dts | 2 ++ drivers/gpio/pm8916_gpio.c | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 9:58 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present address translation does not work since there is no ranges property in the spmi nodes. Add empty ranges properties and a little more logging so that this shows the error:
/tmp/b/sandbox/u-boot -d /tmp/b/sandbox/arch/sandbox/dts/test.dtb \ -c "ut dm spmi_access_peripheral" -L7 -v ... pm8916_gpio_probe() bad address: returning err=-22
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/test.dts | 2 ++ drivers/gpio/pm8916_gpio.c | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present running sandbox with valgrind produces some warnings due to the MMC emulator not filling in all the expected fields. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mmc/sandbox_mmc.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c index 2fa7d8c3dcd..7ca8da0946c 100644 --- a/drivers/mmc/sandbox_mmc.c +++ b/drivers/mmc/sandbox_mmc.c @@ -27,6 +27,7 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, { switch (cmd->cmdidx) { case MMC_CMD_ALL_SEND_CID: + memset(cmd->response, '\0', 16); break; case SD_CMD_SEND_RELATIVE_ADDR: cmd->response[0] = 0 << 16; /* mmc->rca */ @@ -43,11 +44,14 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, case MMC_CMD_SEND_CSD: cmd->response[0] = 0; cmd->response[1] = 10 << 16; /* 1 << block_len */ + cmd->response[2] = 0; + cmd->response[3] = 0; break; case SD_CMD_SWITCH_FUNC: { if (!data) break; u32 *resp = (u32 *)data->dest; + resp[3] = 0; resp[7] = cpu_to_be32(SD_HIGHSPEED_BUSY); if ((cmd->cmdarg & 0xF) == UHS_SDR12_BUS_SPEED) resp[4] = (cmd->cmdarg & 0xF) << 24;

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present running sandbox with valgrind produces some warnings due to the MMC emulator not filling in all the expected fields. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/mmc/sandbox_mmc.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c index 2fa7d8c3dcd..7ca8da0946c 100644 --- a/drivers/mmc/sandbox_mmc.c +++ b/drivers/mmc/sandbox_mmc.c @@ -27,6 +27,7 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, { switch (cmd->cmdidx) { case MMC_CMD_ALL_SEND_CID:
memset(cmd->response, '\0', 16);
sizeof(cmd->response)
break; case SD_CMD_SEND_RELATIVE_ADDR: cmd->response[0] = 0 << 16; /* mmc->rca */
@@ -43,11 +44,14 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, case MMC_CMD_SEND_CSD: cmd->response[0] = 0; cmd->response[1] = 10 << 16; /* 1 << block_len */
cmd->response[2] = 0;
cmd->response[3] = 0; break; case SD_CMD_SWITCH_FUNC: { if (!data) break; u32 *resp = (u32 *)data->dest;
resp[3] = 0; resp[7] = cpu_to_be32(SD_HIGHSPEED_BUSY); if ((cmd->cmdarg & 0xF) == UHS_SDR12_BUS_SPEED) resp[4] = (cmd->cmdarg & 0xF) << 24;
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 9:58 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present running sandbox with valgrind produces some warnings due to the MMC emulator not filling in all the expected fields. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/mmc/sandbox_mmc.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c index 2fa7d8c3dcd..7ca8da0946c 100644 --- a/drivers/mmc/sandbox_mmc.c +++ b/drivers/mmc/sandbox_mmc.c @@ -27,6 +27,7 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, { switch (cmd->cmdidx) { case MMC_CMD_ALL_SEND_CID:
memset(cmd->response, '\0', 16);
sizeof(cmd->response)
Changed to use sizeof(), and
break; case SD_CMD_SEND_RELATIVE_ADDR: cmd->response[0] = 0 << 16; /* mmc->rca */
@@ -43,11 +44,14 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, case MMC_CMD_SEND_CSD: cmd->response[0] = 0; cmd->response[1] = 10 << 16; /* 1 << block_len */
cmd->response[2] = 0;
cmd->response[3] = 0; break; case SD_CMD_SWITCH_FUNC: { if (!data) break; u32 *resp = (u32 *)data->dest;
resp[3] = 0; resp[7] = cpu_to_be32(SD_HIGHSPEED_BUSY); if ((cmd->cmdarg & 0xF) == UHS_SDR12_BUS_SPEED) resp[4] = (cmd->cmdarg & 0xF) << 24;
--
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Rename this ID to SANDBOX_PCI_SWAP_CASE_EMUL_ID since it is more descriptive and allows us to add new PCI emulators without any conflict or confusion.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/include/asm/test.h | 2 +- drivers/misc/swap_case.c | 5 +++-- test/dm/pci.c | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index cbf209693da..1b21af6bed7 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -12,7 +12,7 @@ #define SANDBOX_I2C_TEST_ADDR 0x59
#define SANDBOX_PCI_VENDOR_ID 0x1234 -#define SANDBOX_PCI_DEVICE_ID 0x5678 +#define SANDBOX_PCI_SWAP_CASE_EMUL_ID 0x5678 #define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM #define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL
diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 6afc6d9466b..eb32d101f96 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -129,7 +129,7 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset, *valuep = SANDBOX_PCI_VENDOR_ID; break; case PCI_DEVICE_ID: - *valuep = SANDBOX_PCI_DEVICE_ID; + *valuep = SANDBOX_PCI_SWAP_CASE_EMUL_ID; break; case PCI_CLASS_DEVICE: if (size == PCI_SIZE_8) { @@ -417,7 +417,8 @@ U_BOOT_DRIVER(sandbox_swap_case_emul) = { };
static struct pci_device_id sandbox_swap_case_supported[] = { - { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_DEVICE_ID), SWAP_CASE_DRV_DATA }, + { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_SWAP_CASE_EMUL_ID), + SWAP_CASE_DRV_DATA }, {}, };
diff --git a/test/dm/pci.c b/test/dm/pci.c index c325f6600e7..e70b65aea4a 100644 --- a/test/dm/pci.c +++ b/test/dm/pci.c @@ -38,7 +38,7 @@ static int dm_test_pci_busdev(struct unit_test_state *uts) ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap)); device = 0; ut_assertok(dm_pci_read_config16(swap, PCI_DEVICE_ID, &device)); - ut_asserteq(SANDBOX_PCI_DEVICE_ID, device); + ut_asserteq(SANDBOX_PCI_SWAP_CASE_EMUL_ID, device);
/* Test bus#1 and its devices */ ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 1, &bus)); @@ -50,7 +50,7 @@ static int dm_test_pci_busdev(struct unit_test_state *uts) ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x0c, 0), &swap)); device = 0; ut_assertok(dm_pci_read_config16(swap, PCI_DEVICE_ID, &device)); - ut_asserteq(SANDBOX_PCI_DEVICE_ID, device); + ut_asserteq(SANDBOX_PCI_SWAP_CASE_EMUL_ID, device);
return 0; } @@ -170,7 +170,7 @@ static int dm_test_pci_mixed(struct unit_test_state *uts) ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(2, 0x1f, 0), &swap)); device = 0; ut_assertok(dm_pci_read_config16(swap, PCI_DEVICE_ID, &device)); - ut_asserteq(SANDBOX_PCI_DEVICE_ID, device); + ut_asserteq(SANDBOX_PCI_SWAP_CASE_EMUL_ID, device);
/* First test I/O */ io_addr = dm_pci_read_bar32(swap, 0);

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Rename this ID to SANDBOX_PCI_SWAP_CASE_EMUL_ID since it is more descriptive and allows us to add new PCI emulators without any conflict or confusion.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/include/asm/test.h | 2 +- drivers/misc/swap_case.c | 5 +++-- test/dm/pci.c | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 9:58 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Rename this ID to SANDBOX_PCI_SWAP_CASE_EMUL_ID since it is more descriptive and allows us to add new PCI emulators without any conflict or confusion.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/include/asm/test.h | 2 +- drivers/misc/swap_case.c | 5 +++-- test/dm/pci.c | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

These functions are available on x86 but not sandbox. They are useful shortcuts and clarify the code, so add them to sandbox.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/include/asm/io.h | 42 ++++++++++++++++++++++++++++++----- arch/sandbox/lib/pci_io.c | 12 +++++----- 2 files changed, 42 insertions(+), 12 deletions(-)
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index 2a350a826c4..481787b516b 100644 --- a/arch/sandbox/include/asm/io.h +++ b/arch/sandbox/include/asm/io.h @@ -110,13 +110,21 @@ phys_addr_t map_to_sysmem(const void *ptr); #define clrsetbits_8(addr, clear, set) clrsetbits(8, addr, clear, set)
/* I/O access functions */ -int inl(unsigned int addr); -int inw(unsigned int addr); -int inb(unsigned int addr); +int _inl(unsigned int addr); +int _inw(unsigned int addr); +int _inb(unsigned int addr);
-void outl(unsigned int value, unsigned int addr); -void outw(unsigned int value, unsigned int addr); -void outb(unsigned int value, unsigned int addr); +void _outl(unsigned int value, unsigned int addr); +void _outw(unsigned int value, unsigned int addr); +void _outb(unsigned int value, unsigned int addr); + +#define inb(port) _inb((uintptr_t)(port)) +#define inw(port) _inw((uintptr_t)(port)) +#define inl(port) _inl((uintptr_t)(port)) + +#define outb(val, port) _outb(val, (uintptr_t)(port)) +#define outw(val, port) _outw(val, (uintptr_t)(port)) +#define outl(val, port) _outl(val, (uintptr_t)(port))
#define out_arch(type,endian,a,v) write##type(cpu_to_##endian(v),a) #define in_arch(type,endian,a) endian##_to_cpu(read##type(a)) @@ -188,6 +196,28 @@ static inline void memcpy_toio(volatile void *dst, const void *src, int count) #define insw(port, buf, ns) _insw((u16 *)port, buf, ns) #define outsw(port, buf, ns) _outsw((u16 *)port, buf, ns)
+/* IO space accessors */ +#define clrio(type, addr, clear) \ + out##type(in##type(addr) & ~(clear), (addr)) + +#define setio(type, addr, set) \ + out##type(in##type(addr) | (set), (addr)) + +#define clrsetio(type, addr, clear, set) \ + out##type((in##type(addr) & ~(clear)) | (set), (addr)) + +#define clrio_32(addr, clear) clrio(l, addr, clear) +#define clrio_16(addr, clear) clrio(w, addr, clear) +#define clrio_8(addr, clear) clrio(b, addr, clear) + +#define setio_32(addr, set) setio(l, addr, set) +#define setio_16(addr, set) setio(w, addr, set) +#define setio_8(addr, set) setio(b, addr, set) + +#define clrsetio_32(addr, clear, set) clrsetio(l, addr, clear, set) +#define clrsetio_16(addr, clear, set) clrsetio(w, addr, clear, set) +#define clrsetio_8(addr, clear, set) clrsetio(b, addr, clear, set) + #include <iotrace.h> #include <asm/types.h>
diff --git a/arch/sandbox/lib/pci_io.c b/arch/sandbox/lib/pci_io.c index 01822c60695..f22e47c7f6d 100644 --- a/arch/sandbox/lib/pci_io.c +++ b/arch/sandbox/lib/pci_io.c @@ -91,7 +91,7 @@ static int pci_io_write(unsigned int addr, ulong value, pci_size_t size) return -ENOSYS; }
-int inl(unsigned int addr) +int _inl(unsigned int addr) { unsigned long value; int ret; @@ -101,7 +101,7 @@ int inl(unsigned int addr) return ret ? 0 : value; }
-int inw(unsigned int addr) +int _inw(unsigned int addr) { unsigned long value; int ret; @@ -111,7 +111,7 @@ int inw(unsigned int addr) return ret ? 0 : value; }
-int inb(unsigned int addr) +int _inb(unsigned int addr) { unsigned long value; int ret; @@ -121,17 +121,17 @@ int inb(unsigned int addr) return ret ? 0 : value; }
-void outl(unsigned int value, unsigned int addr) +void _outl(unsigned int value, unsigned int addr) { pci_io_write(addr, value, PCI_SIZE_32); }
-void outw(unsigned int value, unsigned int addr) +void _outw(unsigned int value, unsigned int addr) { pci_io_write(addr, value, PCI_SIZE_16); }
-void outb(unsigned int value, unsigned int addr) +void _outb(unsigned int value, unsigned int addr) { pci_io_write(addr, value, PCI_SIZE_8); }

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions are available on x86 but not sandbox. They are useful shortcuts and clarify the code, so add them to sandbox.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/include/asm/io.h | 42 ++++++++++++++++++++++++++++++----- arch/sandbox/lib/pci_io.c | 12 +++++----- 2 files changed, 42 insertions(+), 12 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:01 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions are available on x86 but not sandbox. They are useful shortcuts and clarify the code, so add them to sandbox.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/include/asm/io.h | 42 ++++++++++++++++++++++++++++++----- arch/sandbox/lib/pci_io.c | 12 +++++----- 2 files changed, 42 insertions(+), 12 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Some functions and a struct should be marked static since they are not used outside this file. Update them.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/misc/swap_case.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index eb32d101f96..8abf88a8fff 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -286,8 +286,8 @@ static void sandbox_swap_case_do_op(enum swap_case_op op, char *str, int len) } }
-int sandbox_swap_case_read_io(struct udevice *dev, unsigned int addr, - ulong *valuep, enum pci_size_t size) +static int sandbox_swap_case_read_io(struct udevice *dev, unsigned int addr, + ulong *valuep, enum pci_size_t size) { struct swap_case_priv *priv = dev_get_priv(dev); unsigned int offset; @@ -304,8 +304,8 @@ int sandbox_swap_case_read_io(struct udevice *dev, unsigned int addr, return 0; }
-int sandbox_swap_case_write_io(struct udevice *dev, unsigned int addr, - ulong value, enum pci_size_t size) +static int sandbox_swap_case_write_io(struct udevice *dev, unsigned int addr, + ulong value, enum pci_size_t size) { struct swap_case_priv *priv = dev_get_priv(dev); unsigned int offset; @@ -392,7 +392,7 @@ static int sandbox_swap_case_unmap_physmem(struct udevice *dev, return 0; }
-struct dm_pci_emul_ops sandbox_swap_case_emul_ops = { +static struct dm_pci_emul_ops sandbox_swap_case_emul_ops = { .get_devfn = sandbox_swap_case_get_devfn, .read_config = sandbox_swap_case_read_config, .write_config = sandbox_swap_case_write_config,

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Some functions and a struct should be marked static since they are not used outside this file. Update them.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/misc/swap_case.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:01 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Some functions and a struct should be marked static since they are not used outside this file. Update them.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/misc/swap_case.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

This method is not used anymore since the bus/device/function of PCI devices can be obtained from their (parent's per-child) platform data. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/misc/swap_case.c | 8 -------- include/pci.h | 7 ------- 2 files changed, 15 deletions(-)
diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 8abf88a8fff..18d756e9cd5 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -54,13 +54,6 @@ struct swap_case_priv { char mem_text[MEM_TEXT_SIZE]; };
-static int sandbox_swap_case_get_devfn(struct udevice *dev) -{ - struct pci_child_platdata *plat = dev_get_parent_platdata(dev); - - return plat->devfn; -} - static int sandbox_swap_case_use_ea(struct udevice *dev) { return !!ofnode_get_property(dev->node, "use-ea", NULL); @@ -393,7 +386,6 @@ static int sandbox_swap_case_unmap_physmem(struct udevice *dev, }
static struct dm_pci_emul_ops sandbox_swap_case_emul_ops = { - .get_devfn = sandbox_swap_case_get_devfn, .read_config = sandbox_swap_case_read_config, .write_config = sandbox_swap_case_write_config, .read_io = sandbox_swap_case_read_io, diff --git a/include/pci.h b/include/pci.h index 298d0d43559..999a594cddf 100644 --- a/include/pci.h +++ b/include/pci.h @@ -1490,13 +1490,6 @@ int dm_pci_find_class(uint find_class, int index, struct udevice **devp); * struct dm_pci_emul_ops - PCI device emulator operations */ struct dm_pci_emul_ops { - /** - * get_devfn(): Check which device and function this emulators - * - * @dev: device to check - * @return the device and function this emulates, or -ve on error - */ - int (*get_devfn)(struct udevice *dev); /** * read_config() - Read a PCI configuration value *

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This method is not used anymore since the bus/device/function of PCI devices can be obtained from their (parent's per-child) platform data. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/misc/swap_case.c | 8 -------- include/pci.h | 7 ------- 2 files changed, 15 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:01 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This method is not used anymore since the bus/device/function of PCI devices can be obtained from their (parent's per-child) platform data. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/misc/swap_case.c | 8 -------- include/pci.h | 7 ------- 2 files changed, 15 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

These warnings appear every thing sandbox is run (see below) and dwarf the actual useful output. Suppress them.
Hopefully at some point a way can be found to fix the root cause.
U-Boot 2019.10-rc2
Model: sandbox DRAM: 128 MiB
Warning: host_lo MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:44
Warning: host_enp5s0 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:45
Warning: host_eth6 using MAC address from ROM
Warning: host_docker0 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:46
Warning: host_docker_gwbridge using MAC address from ROM
Warning: host_veth1118e68 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:47 WDT: Not found! MMC: In: cros-ec-keyb Out: vidconsole Err: vidconsole Model: sandbox SCSI: Net: eth0: host_lo, eth1: host_enp5s0, eth2: host_eth6, eth3: host_docker0, eth4: host_docker_gwbridge, eth5: host_veth1118e68 Error: eth@10002000 address not set. , eth-1: eth@10002000 Test 'pmc_base' not found
Warning: host_lo MAC addresses don't match: Address in ROM is 2a:24:9a:31:90:f8 Address in environment is 00:00:11:22:33:44
Warning: host_enp5s0 MAC addresses don't match: Address in ROM is ce:23:d9:74:6f:6c Address in environment is 00:00:11:22:33:45
Warning: host_eth6 using MAC address from ROM
Warning: host_docker0 MAC addresses don't match: Address in ROM is ee:22:1c:3b:be:bc Address in environment is 00:00:11:22:33:46
Warning: host_docker_gwbridge using MAC address from ROM
Warning: host_veth1118e68 MAC addresses don't match: Address in ROM is ae:20:9e:3d:a4:9f Address in environment is 00:00:11:22:33:47
Signed-off-by: Simon Glass sjg@chromium.org ---
net/eth-uclass.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/net/eth-uclass.c b/net/eth-uclass.c index 3bd98b01ad3..67a7062e9d8 100644 --- a/net/eth-uclass.c +++ b/net/eth-uclass.c @@ -485,6 +485,12 @@ static int eth_post_probe(struct udevice *dev) struct eth_device_priv *priv = dev->uclass_priv; struct eth_pdata *pdata = dev->platdata; unsigned char env_enetaddr[ARP_HLEN]; + /* + * These warnings always appear on sandbox and are not useful. They have + * been here for some time and the issue has not been resolved. So for + * now, disable them. + */ + bool show_warnings = !IS_ENABLED(CONFIG_SANDBOX);
#if defined(CONFIG_NEEDS_MANUAL_RELOC) struct eth_ops *ops = eth_get_ops(dev); @@ -526,29 +532,33 @@ static int eth_post_probe(struct udevice *dev) if (!is_zero_ethaddr(env_enetaddr)) { if (!is_zero_ethaddr(pdata->enetaddr) && memcmp(pdata->enetaddr, env_enetaddr, ARP_HLEN)) { - printf("\nWarning: %s MAC addresses don't match:\n", - dev->name); - printf("Address in ROM is %pM\n", - pdata->enetaddr); - printf("Address in environment is %pM\n", - env_enetaddr); + if (show_warnings) { + printf("\nWarning: %s MAC addresses don't match:\n", + dev->name); + printf("Address in ROM is %pM\n", + pdata->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } }
/* Override the ROM MAC address */ memcpy(pdata->enetaddr, env_enetaddr, ARP_HLEN); } else if (is_valid_ethaddr(pdata->enetaddr)) { eth_env_set_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); - printf("\nWarning: %s using MAC address from ROM\n", - dev->name); + if (show_warnings) + printf("\nWarning: %s using MAC address from ROM\n", + dev->name); } else if (is_zero_ethaddr(pdata->enetaddr) || !is_valid_ethaddr(pdata->enetaddr)) { #ifdef CONFIG_NET_RANDOM_ETHADDR net_random_ethaddr(pdata->enetaddr); - printf("\nWarning: %s (eth%d) using random MAC address - %pM\n", - dev->name, dev->seq, pdata->enetaddr); + if (show_warnings) + printf("\nWarning: %s (eth%d) using random MAC address - %pM\n", + dev->name, dev->seq, pdata->enetaddr); #else - printf("\nError: %s address not set.\n", - dev->name); + if (show_warnings) + printf("\nError: %s address not set.\n", dev->name); return -EINVAL; #endif }

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These warnings appear every thing sandbox is run (see below) and dwarf the actual useful output. Suppress them.
Hopefully at some point a way can be found to fix the root cause.
U-Boot 2019.10-rc2
Model: sandbox DRAM: 128 MiB
Warning: host_lo MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:44
Warning: host_enp5s0 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:45
Warning: host_eth6 using MAC address from ROM
Warning: host_docker0 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:46
Warning: host_docker_gwbridge using MAC address from ROM
I am not sure how to reproduce this. Joe, do you know anything?
Warning: host_veth1118e68 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:47 WDT: Not found! MMC: In: cros-ec-keyb Out: vidconsole Err: vidconsole Model: sandbox SCSI: Net: eth0: host_lo, eth1: host_enp5s0, eth2: host_eth6, eth3: host_docker0, eth4: host_docker_gwbridge, eth5: host_veth1118e68 Error: eth@10002000 address not set. , eth-1: eth@10002000 Test 'pmc_base' not found
Warning: host_lo MAC addresses don't match: Address in ROM is 2a:24:9a:31:90:f8 Address in environment is 00:00:11:22:33:44
Warning: host_enp5s0 MAC addresses don't match: Address in ROM is ce:23:d9:74:6f:6c Address in environment is 00:00:11:22:33:45
Warning: host_eth6 using MAC address from ROM
Warning: host_docker0 MAC addresses don't match: Address in ROM is ee:22:1c:3b:be:bc Address in environment is 00:00:11:22:33:46
Warning: host_docker_gwbridge using MAC address from ROM
Warning: host_veth1118e68 MAC addresses don't match: Address in ROM is ae:20:9e:3d:a4:9f Address in environment is 00:00:11:22:33:47
Signed-off-by: Simon Glass sjg@chromium.org
net/eth-uclass.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-)
Regards, Bin

Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These warnings appear every thing sandbox is run (see below) and dwarf the actual useful output. Suppress them.
Hopefully at some point a way can be found to fix the root cause.
Does removing ethaddr env from SANDBOX_ETH_SETTINGS in sandbox.h fix this problem?
U-Boot 2019.10-rc2
Model: sandbox DRAM: 128 MiB
Warning: host_lo MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:44
Warning: host_enp5s0 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:45
Warning: host_eth6 using MAC address from ROM
Warning: host_docker0 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:46
Warning: host_docker_gwbridge using MAC address from ROM
Warning: host_veth1118e68 MAC addresses don't match: Address in ROM is a6:28:b7:47:28:93 Address in environment is 00:00:11:22:33:47 WDT: Not found! MMC: In: cros-ec-keyb Out: vidconsole Err: vidconsole Model: sandbox SCSI: Net: eth0: host_lo, eth1: host_enp5s0, eth2: host_eth6, eth3: host_docker0, eth4: host_docker_gwbridge, eth5: host_veth1118e68 Error: eth@10002000 address not set. , eth-1: eth@10002000 Test 'pmc_base' not found
Warning: host_lo MAC addresses don't match: Address in ROM is 2a:24:9a:31:90:f8 Address in environment is 00:00:11:22:33:44
Warning: host_enp5s0 MAC addresses don't match: Address in ROM is ce:23:d9:74:6f:6c Address in environment is 00:00:11:22:33:45
Warning: host_eth6 using MAC address from ROM
Warning: host_docker0 MAC addresses don't match: Address in ROM is ee:22:1c:3b:be:bc Address in environment is 00:00:11:22:33:46
Warning: host_docker_gwbridge using MAC address from ROM
Warning: host_veth1118e68 MAC addresses don't match: Address in ROM is ae:20:9e:3d:a4:9f Address in environment is 00:00:11:22:33:47
Signed-off-by: Simon Glass sjg@chromium.org
net/eth-uclass.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-)
Regards, Bin

Hi Simon,
On Sat, Oct 5, 2019 at 10:16 AM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These warnings appear every thing sandbox is run (see below) and dwarf the actual useful output. Suppress them.
Hopefully at some point a way can be found to fix the root cause.
Does removing ethaddr env from SANDBOX_ETH_SETTINGS in sandbox.h fix this problem?
I was able to reproduce this, and confirmed that removing ethaddr* envs from SANDBOX_ETH_SETTINGS in sandbox.h could fix the issue you were seeing.
Regards, Bin

Hi Bin,
On Fri, Oct 4, 2019 at 9:27 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 5, 2019 at 10:16 AM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These warnings appear every thing sandbox is run (see below) and dwarf the actual useful output. Suppress them.
Hopefully at some point a way can be found to fix the root cause.
Does removing ethaddr env from SANDBOX_ETH_SETTINGS in sandbox.h fix this problem?
I was able to reproduce this, and confirmed that removing ethaddr* envs from SANDBOX_ETH_SETTINGS in sandbox.h could fix the issue you were seeing.
While that fixes the issue, it also breaks the unit tests.
Regards, Bin _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

Hi Joe,
On Sun, Oct 6, 2019 at 9:05 AM Joe Hershberger joe.hershberger@ni.com wrote:
Hi Bin,
On Fri, Oct 4, 2019 at 9:27 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 5, 2019 at 10:16 AM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These warnings appear every thing sandbox is run (see below) and dwarf the actual useful output. Suppress them.
Hopefully at some point a way can be found to fix the root cause.
Does removing ethaddr env from SANDBOX_ETH_SETTINGS in sandbox.h fix this problem?
I was able to reproduce this, and confirmed that removing ethaddr* envs from SANDBOX_ETH_SETTINGS in sandbox.h could fix the issue you were seeing.
While that fixes the issue, it also breaks the unit tests.
Yes, it fixes sandbox with "-D" but fails with "-T".
Regards, Bin

Hi Bin,
On Sat, Oct 5, 2019 at 9:13 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Joe,
On Sun, Oct 6, 2019 at 9:05 AM Joe Hershberger joe.hershberger@ni.com wrote:
Hi Bin,
On Fri, Oct 4, 2019 at 9:27 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 5, 2019 at 10:16 AM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These warnings appear every thing sandbox is run (see below) and dwarf the actual useful output. Suppress them.
Hopefully at some point a way can be found to fix the root cause.
Does removing ethaddr env from SANDBOX_ETH_SETTINGS in sandbox.h fix this problem?
I was able to reproduce this, and confirmed that removing ethaddr* envs from SANDBOX_ETH_SETTINGS in sandbox.h could fix the issue you were seeing.
While that fixes the issue, it also breaks the unit tests.
Yes, it fixes sandbox with "-D" but fails with "-T".
Maybe we can make it work for both by removing them from the header, but then setting the needed ethaddr's in the unit tests.
-Joe
Regards, Bin _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

Hi,
On Sat, 5 Oct 2019 at 20:42, Joe Hershberger joe.hershberger@ni.com wrote:
Hi Bin,
On Sat, Oct 5, 2019 at 9:13 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Joe,
On Sun, Oct 6, 2019 at 9:05 AM Joe Hershberger joe.hershberger@ni.com wrote:
Hi Bin,
On Fri, Oct 4, 2019 at 9:27 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 5, 2019 at 10:16 AM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These warnings appear every thing sandbox is run (see below) and dwarf the actual useful output. Suppress them.
Hopefully at some point a way can be found to fix the root cause.
Does removing ethaddr env from SANDBOX_ETH_SETTINGS in sandbox.h fix this problem?
I was able to reproduce this, and confirmed that removing ethaddr* envs from SANDBOX_ETH_SETTINGS in sandbox.h could fix the issue you were seeing.
While that fixes the issue, it also breaks the unit tests.
Yes, it fixes sandbox with "-D" but fails with "-T".
Maybe we can make it work for both by removing them from the header, but then setting the needed ethaddr's in the unit tests.
It looks like I can get most of the way there with this change, but I still need to supress one warning.
Plus it breaks the tests, perhaps because the env vars are set after net is inited.
WIll send an updated patch.
Regards, Simon

This function is useful in PCI emulators. More it into the header file to avoid duplicating it in other drivers.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/misc/swap_case.c | 7 ++----- include/pci.h | 4 ++++ 2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 18d756e9cd5..75fe6416707 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -24,9 +24,6 @@ struct swap_case_platdata { u32 bar[6]; };
-#define offset_to_barnum(offset) \ - (((offset) - PCI_BASE_ADDRESS_0) / sizeof(u32)) - enum { MEM_TEXT_SIZE = 0x100, }; @@ -144,7 +141,7 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset, int barnum; u32 *bar, result;
- barnum = offset_to_barnum(offset); + barnum = pci_offset_to_barnum(offset); bar = &plat->bar[barnum];
result = *bar; @@ -224,7 +221,7 @@ static int sandbox_swap_case_write_config(struct udevice *emul, uint offset, int barnum; u32 *bar;
- barnum = offset_to_barnum(offset); + barnum = pci_offset_to_barnum(offset); bar = &plat->bar[barnum];
debug("w bar %d=%lx\n", barnum, value); diff --git a/include/pci.h b/include/pci.h index 999a594cddf..2b82b2c5a3e 100644 --- a/include/pci.h +++ b/include/pci.h @@ -215,6 +215,10 @@ #define PCI_BASE_ADDRESS_IO_MASK (~0x03ULL) /* bit 1 is reserved if address_space = 1 */
+/* Convert a regsister address (e.g. PCI_BASE_ADDRESS_1) to a bar # (e.g. 1) */ +#define pci_offset_to_barnum(offset) \ + (((offset) - PCI_BASE_ADDRESS_0) / sizeof(u32)) + /* Header type 0 (normal devices) */ #define PCI_CARDBUS_CIS 0x28 #define PCI_SUBSYSTEM_VENDOR_ID 0x2c

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This function is useful in PCI emulators. More it into the header file to avoid duplicating it in other drivers.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/misc/swap_case.c | 7 ++----- include/pci.h | 4 ++++ 2 files changed, 6 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:17 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This function is useful in PCI emulators. More it into the header file to avoid duplicating it in other drivers.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/misc/swap_case.c | 7 ++----- include/pci.h | 4 ++++ 2 files changed, 6 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

U-Boot already supports using -D to indicate that it should use the normal device tree. It is sometimes useful to run with the test device tree, e.g. when running a test. Add a -T option for this along with some documentation.
It can be used like this:
/tmp/b/sandbox/u-boot -T -c "ut dm pci_busdev"
(this will use /tmp/b/sandbox/arch/sandbox/dts/test.dtb as the DT)
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/start.c | 25 +++++++++++++++++++++++++ doc/arch/sandbox.rst | 9 +++++++++ 2 files changed, 34 insertions(+)
diff --git a/arch/sandbox/cpu/start.c b/arch/sandbox/cpu/start.c index 82828f0c1d4..cfc542c8066 100644 --- a/arch/sandbox/cpu/start.c +++ b/arch/sandbox/cpu/start.c @@ -147,6 +147,31 @@ static int sandbox_cmdline_cb_default_fdt(struct sandbox_state *state, SANDBOX_CMDLINE_OPT_SHORT(default_fdt, 'D', 0, "Use the default u-boot.dtb control FDT in U-Boot directory");
+static int sandbox_cmdline_cb_test_fdt(struct sandbox_state *state, + const char *arg) +{ + const char *fmt = "/arch/sandbox/dts/test.dtb"; + char *p; + char *fname; + int len; + + len = strlen(state->argv[0]) + strlen(fmt) + 1; + fname = os_malloc(len); + if (!fname) + return -ENOMEM; + strcpy(fname, state->argv[0]); + p = strrchr(fname, '/'); + if (!p) + p = fname + strlen(fname); + len -= p - fname; + snprintf(p, len, fmt, p); + state->fdt_fname = fname; + + return 0; +} +SANDBOX_CMDLINE_OPT_SHORT(test_fdt, 'T', 0, + "Use the test.dtb control FDT in U-Boot directory"); + static int sandbox_cmdline_cb_interactive(struct sandbox_state *state, const char *arg) { diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst index 5c0caebcbf0..54933b56759 100644 --- a/doc/arch/sandbox.rst +++ b/doc/arch/sandbox.rst @@ -103,6 +103,8 @@ A device tree binary file can be provided with -d. If you edit the source (it is stored at arch/sandbox/dts/sandbox.dts) you must rebuild U-Boot to recreate the binary file.
+To use the default device tree, use -D. To use the test device tree, use -T. + To execute commands directly, use the -c option. You can specify a single command, or multiple commands separated by a semicolon, as is normal in U-Boot. Be careful with quoting as the shell will normally process and @@ -499,6 +501,13 @@ run natively on your board if desired (and enabled).
To run all tests use "make check".
+To run a single test in an existing sandbox build, you can use -T to use the +test device tree, and -c to select the test: + + /tmp/b/sandbox/u-boot -T -c "ut dm pci_busdev" + +This runs dm_test_pci_busdev() which is in test/dm/pci.c +
Memory Map ----------

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
U-Boot already supports using -D to indicate that it should use the normal device tree. It is sometimes useful to run with the test device tree, e.g. when running a test. Add a -T option for this along with some documentation.
It can be used like this:
/tmp/b/sandbox/u-boot -T -c "ut dm pci_busdev"
(this will use /tmp/b/sandbox/arch/sandbox/dts/test.dtb as the DT)
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/cpu/start.c | 25 +++++++++++++++++++++++++ doc/arch/sandbox.rst | 9 +++++++++ 2 files changed, 34 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:13 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
U-Boot already supports using -D to indicate that it should use the normal device tree. It is sometimes useful to run with the test device tree, e.g. when running a test. Add a -T option for this along with some documentation.
It can be used like this:
/tmp/b/sandbox/u-boot -T -c "ut dm pci_busdev"
(this will use /tmp/b/sandbox/arch/sandbox/dts/test.dtb as the DT)
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/cpu/start.c | 25 +++++++++++++++++++++++++ doc/arch/sandbox.rst | 9 +++++++++ 2 files changed, 34 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Increase the memory space so we can support the p2sb bus which needs multiples of 1MB.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/test.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index f664b65b72d..5669ede7051 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -447,7 +447,7 @@ device_type = "pci"; #address-cells = <3>; #size-cells = <2>; - ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000 + ranges = <0x02000000 0 0x10000000 0x10000000 0 0x2000000 0x01000000 0 0x20000000 0x20000000 0 0x2000>; pci@0,0 { compatible = "pci-generic";

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Increase the memory space so we can support the p2sb bus which needs multiples of 1MB.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/test.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:14 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Increase the memory space so we can support the p2sb bus which needs multiples of 1MB.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/test.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present these functions are stubbed out. For more comprehensive testing with PCI devices it is useful to be able to fully emulate I/O access. Add simple implementations for these.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/cpu.c | 51 ++++++++++++++++++++++++++++++++ arch/sandbox/include/asm/io.h | 27 +++++++++++------ arch/sandbox/include/asm/state.h | 1 + drivers/nvme/nvme.h | 4 +-- 4 files changed, 72 insertions(+), 11 deletions(-)
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index fdfb209f77d..f3af88d79e9 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -225,6 +225,57 @@ phys_addr_t map_to_sysmem(const void *ptr) return mentry->tag; }
+unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size) +{ + struct sandbox_state *state = state_get_current(); + + if (!state->allow_memio) + return 0; + + switch (size) { + case SB_SIZE_8: + return *(u8 *)addr; + case SB_SIZE_16: + return *(u16 *)addr; + case SB_SIZE_32: + return *(u32 *)addr; + case SB_SIZE_64: + return *(u64 *)addr; + } + + return 0; +} + +void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size) +{ + struct sandbox_state *state = state_get_current(); + + if (!state->allow_memio) + return; + + switch (size) { + case SB_SIZE_8: + *(u8 *)addr = val; + break; + case SB_SIZE_16: + *(u16 *)addr = val; + break; + case SB_SIZE_32: + *(u32 *)addr = val; + break; + case SB_SIZE_64: + *(u64 *)addr = val; + break; + } +} + +void sandbox_set_enable_memio(bool enable) +{ + struct sandbox_state *state = state_get_current(); + + state->allow_memio = enable; +} + void sandbox_set_enable_pci_map(int enable) { enable_pci_map = enable; diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index 481787b516b..2bbaff26a61 100644 --- a/arch/sandbox/include/asm/io.h +++ b/arch/sandbox/include/asm/io.h @@ -6,6 +6,13 @@ #ifndef __SANDBOX_ASM_IO_H #define __SANDBOX_ASM_IO_H
+enum sandboxio_size_t { + SB_SIZE_8, + SB_SIZE_16, + SB_SIZE_32, + SB_SIZE_64, +}; + void *phys_to_virt(phys_addr_t paddr); #define phys_to_virt phys_to_virt
@@ -38,18 +45,20 @@ static inline void unmap_sysmem(const void *vaddr) /* Map from a pointer to our RAM buffer */ phys_addr_t map_to_sysmem(const void *ptr);
-/* Define nops for sandbox I/O access */ -#define readb(addr) ((void)addr, 0) -#define readw(addr) ((void)addr, 0) -#define readl(addr) ((void)addr, 0) +unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size); +void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size); + +#define readb(addr) sandbox_read(addr, SB_SIZE_8) +#define readw(addr) sandbox_read(addr, SB_SIZE_16) +#define readl(addr) sandbox_read(addr, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define readq(addr) ((void)addr, 0) +#define readq(addr) sandbox_read(addr, SB_SIZE_64) #endif -#define writeb(v, addr) ((void)addr) -#define writew(v, addr) ((void)addr) -#define writel(v, addr) ((void)addr) +#define writeb(v, addr) sandbox_write(addr, v, SB_SIZE_8) +#define writew(v, addr) sandbox_write(addr, v, SB_SIZE_16) +#define writel(v, addr) sandbox_write(addr, v, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define writeq(v, addr) ((void)addr) +#define writeq(v, addr) sandbox_write(addr, v, SB_SIZE_64) #endif
/* diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 2d773d3fa6b..ad3e94beb9a 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -102,6 +102,7 @@ struct sandbox_state { ulong next_tag; /* Next address tag to allocate */ struct list_head mapmem_head; /* struct sandbox_mapmem_entry */ bool hwspinlock; /* Hardware Spinlock status */ + bool allow_memio; /* Allow readl() etc. to work */
/* * This struct is getting large. diff --git a/drivers/nvme/nvme.h b/drivers/nvme/nvme.h index 922f7abfe85..c56ea7e58e6 100644 --- a/drivers/nvme/nvme.h +++ b/drivers/nvme/nvme.h @@ -536,7 +536,7 @@ struct nvme_completion { static inline u64 nvme_readq(__le64 volatile *regs) { #if BITS_PER_LONG == 64 - return readq(regs); + return readq((__le64 *)regs); #else __u32 *ptr = (__u32 *)regs; u64 val_lo = readl(ptr); @@ -549,7 +549,7 @@ static inline u64 nvme_readq(__le64 volatile *regs) static inline void nvme_writeq(const u64 val, __le64 volatile *regs) { #if BITS_PER_LONG == 64 - writeq(val, regs); + writeq(val, (__le64 *)regs); #else __u32 *ptr = (__u32 *)regs; u32 val_lo = lower_32_bits(val);

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present these functions are stubbed out. For more comprehensive testing with PCI devices it is useful to be able to fully emulate I/O access. Add simple implementations for these.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/cpu/cpu.c | 51 ++++++++++++++++++++++++++++++++ arch/sandbox/include/asm/io.h | 27 +++++++++++------ arch/sandbox/include/asm/state.h | 1 + drivers/nvme/nvme.h | 4 +-- 4 files changed, 72 insertions(+), 11 deletions(-)
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index fdfb209f77d..f3af88d79e9 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -225,6 +225,57 @@ phys_addr_t map_to_sysmem(const void *ptr) return mentry->tag; }
+unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size) +{
struct sandbox_state *state = state_get_current();
if (!state->allow_memio)
return 0;
switch (size) {
case SB_SIZE_8:
return *(u8 *)addr;
case SB_SIZE_16:
return *(u16 *)addr;
case SB_SIZE_32:
return *(u32 *)addr;
case SB_SIZE_64:
return *(u64 *)addr;
}
return 0;
+}
+void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size)
const void *addr
+{
struct sandbox_state *state = state_get_current();
if (!state->allow_memio)
return;
switch (size) {
case SB_SIZE_8:
*(u8 *)addr = val;
break;
case SB_SIZE_16:
*(u16 *)addr = val;
break;
case SB_SIZE_32:
*(u32 *)addr = val;
break;
case SB_SIZE_64:
*(u64 *)addr = val;
break;
}
+}
+void sandbox_set_enable_memio(bool enable) +{
struct sandbox_state *state = state_get_current();
state->allow_memio = enable;
+}
void sandbox_set_enable_pci_map(int enable) { enable_pci_map = enable; diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index 481787b516b..2bbaff26a61 100644 --- a/arch/sandbox/include/asm/io.h +++ b/arch/sandbox/include/asm/io.h @@ -6,6 +6,13 @@ #ifndef __SANDBOX_ASM_IO_H #define __SANDBOX_ASM_IO_H
+enum sandboxio_size_t {
SB_SIZE_8,
SB_SIZE_16,
SB_SIZE_32,
SB_SIZE_64,
+};
void *phys_to_virt(phys_addr_t paddr); #define phys_to_virt phys_to_virt
@@ -38,18 +45,20 @@ static inline void unmap_sysmem(const void *vaddr) /* Map from a pointer to our RAM buffer */ phys_addr_t map_to_sysmem(const void *ptr);
-/* Define nops for sandbox I/O access */ -#define readb(addr) ((void)addr, 0) -#define readw(addr) ((void)addr, 0) -#define readl(addr) ((void)addr, 0) +unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size); +void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size);
+#define readb(addr) sandbox_read(addr, SB_SIZE_8) +#define readw(addr) sandbox_read(addr, SB_SIZE_16) +#define readl(addr) sandbox_read(addr, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define readq(addr) ((void)addr, 0) +#define readq(addr) sandbox_read(addr, SB_SIZE_64) #endif -#define writeb(v, addr) ((void)addr) -#define writew(v, addr) ((void)addr) -#define writel(v, addr) ((void)addr) +#define writeb(v, addr) sandbox_write(addr, v, SB_SIZE_8) +#define writew(v, addr) sandbox_write(addr, v, SB_SIZE_16) +#define writel(v, addr) sandbox_write(addr, v, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define writeq(v, addr) ((void)addr) +#define writeq(v, addr) sandbox_write(addr, v, SB_SIZE_64) #endif
/* diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 2d773d3fa6b..ad3e94beb9a 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -102,6 +102,7 @@ struct sandbox_state { ulong next_tag; /* Next address tag to allocate */ struct list_head mapmem_head; /* struct sandbox_mapmem_entry */ bool hwspinlock; /* Hardware Spinlock status */
bool allow_memio; /* Allow readl() etc. to work */ /* * This struct is getting large.
diff --git a/drivers/nvme/nvme.h b/drivers/nvme/nvme.h index 922f7abfe85..c56ea7e58e6 100644 --- a/drivers/nvme/nvme.h +++ b/drivers/nvme/nvme.h @@ -536,7 +536,7 @@ struct nvme_completion { static inline u64 nvme_readq(__le64 volatile *regs) { #if BITS_PER_LONG == 64
return readq(regs);
return readq((__le64 *)regs);
This cast is not needed
#else __u32 *ptr = (__u32 *)regs; u64 val_lo = readl(ptr); @@ -549,7 +549,7 @@ static inline u64 nvme_readq(__le64 volatile *regs) static inline void nvme_writeq(const u64 val, __le64 volatile *regs) { #if BITS_PER_LONG == 64
writeq(val, regs);
writeq(val, (__le64 *)regs);
Ditto
#else __u32 *ptr = (__u32 *)regs; u32 val_lo = lower_32_bits(val); --
Other than above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:30 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present these functions are stubbed out. For more comprehensive testing with PCI devices it is useful to be able to fully emulate I/O access. Add simple implementations for these.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/cpu/cpu.c | 51 ++++++++++++++++++++++++++++++++ arch/sandbox/include/asm/io.h | 27 +++++++++++------ arch/sandbox/include/asm/state.h | 1 + drivers/nvme/nvme.h | 4 +-- 4 files changed, 72 insertions(+), 11 deletions(-)
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index fdfb209f77d..f3af88d79e9 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -225,6 +225,57 @@ phys_addr_t map_to_sysmem(const void *ptr) return mentry->tag; }
+unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size) +{
struct sandbox_state *state = state_get_current();
if (!state->allow_memio)
return 0;
switch (size) {
case SB_SIZE_8:
return *(u8 *)addr;
case SB_SIZE_16:
return *(u16 *)addr;
case SB_SIZE_32:
return *(u32 *)addr;
case SB_SIZE_64:
return *(u64 *)addr;
}
return 0;
+}
+void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size)
const void *addr
Fixed this, and
+{
struct sandbox_state *state = state_get_current();
if (!state->allow_memio)
return;
switch (size) {
case SB_SIZE_8:
*(u8 *)addr = val;
break;
case SB_SIZE_16:
*(u16 *)addr = val;
break;
case SB_SIZE_32:
*(u32 *)addr = val;
break;
case SB_SIZE_64:
*(u64 *)addr = val;
break;
}
+}
+void sandbox_set_enable_memio(bool enable) +{
struct sandbox_state *state = state_get_current();
state->allow_memio = enable;
+}
void sandbox_set_enable_pci_map(int enable) { enable_pci_map = enable; diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index 481787b516b..2bbaff26a61 100644 --- a/arch/sandbox/include/asm/io.h +++ b/arch/sandbox/include/asm/io.h @@ -6,6 +6,13 @@ #ifndef __SANDBOX_ASM_IO_H #define __SANDBOX_ASM_IO_H
+enum sandboxio_size_t {
SB_SIZE_8,
SB_SIZE_16,
SB_SIZE_32,
SB_SIZE_64,
+};
void *phys_to_virt(phys_addr_t paddr); #define phys_to_virt phys_to_virt
@@ -38,18 +45,20 @@ static inline void unmap_sysmem(const void *vaddr) /* Map from a pointer to our RAM buffer */ phys_addr_t map_to_sysmem(const void *ptr);
-/* Define nops for sandbox I/O access */ -#define readb(addr) ((void)addr, 0) -#define readw(addr) ((void)addr, 0) -#define readl(addr) ((void)addr, 0) +unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size); +void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size);
+#define readb(addr) sandbox_read(addr, SB_SIZE_8) +#define readw(addr) sandbox_read(addr, SB_SIZE_16) +#define readl(addr) sandbox_read(addr, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define readq(addr) ((void)addr, 0) +#define readq(addr) sandbox_read(addr, SB_SIZE_64) #endif -#define writeb(v, addr) ((void)addr) -#define writew(v, addr) ((void)addr) -#define writel(v, addr) ((void)addr) +#define writeb(v, addr) sandbox_write(addr, v, SB_SIZE_8) +#define writew(v, addr) sandbox_write(addr, v, SB_SIZE_16) +#define writel(v, addr) sandbox_write(addr, v, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define writeq(v, addr) ((void)addr) +#define writeq(v, addr) sandbox_write(addr, v, SB_SIZE_64) #endif
/* diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 2d773d3fa6b..ad3e94beb9a 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -102,6 +102,7 @@ struct sandbox_state { ulong next_tag; /* Next address tag to allocate */ struct list_head mapmem_head; /* struct sandbox_mapmem_entry */ bool hwspinlock; /* Hardware Spinlock status */
bool allow_memio; /* Allow readl() etc. to work */ /* * This struct is getting large.
diff --git a/drivers/nvme/nvme.h b/drivers/nvme/nvme.h index 922f7abfe85..c56ea7e58e6 100644 --- a/drivers/nvme/nvme.h +++ b/drivers/nvme/nvme.h @@ -536,7 +536,7 @@ struct nvme_completion { static inline u64 nvme_readq(__le64 volatile *regs) { #if BITS_PER_LONG == 64
return readq(regs);
return readq((__le64 *)regs);
This cast is not needed
Removed the cast, and
#else __u32 *ptr = (__u32 *)regs; u64 val_lo = readl(ptr); @@ -549,7 +549,7 @@ static inline u64 nvme_readq(__le64 volatile *regs) static inline void nvme_writeq(const u64 val, __le64 volatile *regs) { #if BITS_PER_LONG == 64
writeq(val, regs);
writeq(val, (__le64 *)regs);
Ditto
#else __u32 *ptr = (__u32 *)regs; u32 val_lo = lower_32_bits(val); --
Other than above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

On Sun, Oct 6, 2019 at 6:04 PM Bin Meng bmeng.cn@gmail.com wrote:
On Sat, Oct 5, 2019 at 11:30 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present these functions are stubbed out. For more comprehensive testing with PCI devices it is useful to be able to fully emulate I/O access. Add simple implementations for these.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/cpu/cpu.c | 51 ++++++++++++++++++++++++++++++++ arch/sandbox/include/asm/io.h | 27 +++++++++++------ arch/sandbox/include/asm/state.h | 1 + drivers/nvme/nvme.h | 4 +-- 4 files changed, 72 insertions(+), 11 deletions(-)
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index fdfb209f77d..f3af88d79e9 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -225,6 +225,57 @@ phys_addr_t map_to_sysmem(const void *ptr) return mentry->tag; }
+unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size) +{
struct sandbox_state *state = state_get_current();
if (!state->allow_memio)
return 0;
switch (size) {
case SB_SIZE_8:
return *(u8 *)addr;
case SB_SIZE_16:
return *(u16 *)addr;
case SB_SIZE_32:
return *(u32 *)addr;
case SB_SIZE_64:
return *(u64 *)addr;
}
return 0;
+}
+void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size)
const void *addr
Fixed this, and
+{
struct sandbox_state *state = state_get_current();
if (!state->allow_memio)
return;
switch (size) {
case SB_SIZE_8:
*(u8 *)addr = val;
break;
case SB_SIZE_16:
*(u16 *)addr = val;
break;
case SB_SIZE_32:
*(u32 *)addr = val;
break;
case SB_SIZE_64:
*(u64 *)addr = val;
break;
}
+}
+void sandbox_set_enable_memio(bool enable) +{
struct sandbox_state *state = state_get_current();
state->allow_memio = enable;
+}
void sandbox_set_enable_pci_map(int enable) { enable_pci_map = enable; diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index 481787b516b..2bbaff26a61 100644 --- a/arch/sandbox/include/asm/io.h +++ b/arch/sandbox/include/asm/io.h @@ -6,6 +6,13 @@ #ifndef __SANDBOX_ASM_IO_H #define __SANDBOX_ASM_IO_H
+enum sandboxio_size_t {
SB_SIZE_8,
SB_SIZE_16,
SB_SIZE_32,
SB_SIZE_64,
+};
void *phys_to_virt(phys_addr_t paddr); #define phys_to_virt phys_to_virt
@@ -38,18 +45,20 @@ static inline void unmap_sysmem(const void *vaddr) /* Map from a pointer to our RAM buffer */ phys_addr_t map_to_sysmem(const void *ptr);
-/* Define nops for sandbox I/O access */ -#define readb(addr) ((void)addr, 0) -#define readw(addr) ((void)addr, 0) -#define readl(addr) ((void)addr, 0) +unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size); +void sandbox_write(void *addr, unsigned int val, enum sandboxio_size_t size);
+#define readb(addr) sandbox_read(addr, SB_SIZE_8) +#define readw(addr) sandbox_read(addr, SB_SIZE_16) +#define readl(addr) sandbox_read(addr, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define readq(addr) ((void)addr, 0) +#define readq(addr) sandbox_read(addr, SB_SIZE_64) #endif -#define writeb(v, addr) ((void)addr) -#define writew(v, addr) ((void)addr) -#define writel(v, addr) ((void)addr) +#define writeb(v, addr) sandbox_write(addr, v, SB_SIZE_8) +#define writew(v, addr) sandbox_write(addr, v, SB_SIZE_16) +#define writel(v, addr) sandbox_write(addr, v, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define writeq(v, addr) ((void)addr) +#define writeq(v, addr) sandbox_write(addr, v, SB_SIZE_64) #endif
/* diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h index 2d773d3fa6b..ad3e94beb9a 100644 --- a/arch/sandbox/include/asm/state.h +++ b/arch/sandbox/include/asm/state.h @@ -102,6 +102,7 @@ struct sandbox_state { ulong next_tag; /* Next address tag to allocate */ struct list_head mapmem_head; /* struct sandbox_mapmem_entry */ bool hwspinlock; /* Hardware Spinlock status */
bool allow_memio; /* Allow readl() etc. to work */ /* * This struct is getting large.
diff --git a/drivers/nvme/nvme.h b/drivers/nvme/nvme.h index 922f7abfe85..c56ea7e58e6 100644 --- a/drivers/nvme/nvme.h +++ b/drivers/nvme/nvme.h @@ -536,7 +536,7 @@ struct nvme_completion { static inline u64 nvme_readq(__le64 volatile *regs) { #if BITS_PER_LONG == 64
return readq(regs);
return readq((__le64 *)regs);
This cast is not needed
Removed the cast, and
So it turns out the cast here was to eliminate the build warnings for sandbox64_defconfig. However, we really should fix the build warning by do the cast in the arch/sandbox/include/asm/io.h below, instead of touching nvme.h:
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index c4897b8..4a35c41 100644 --- a/arch/sandbox/include/asm/io.h +++ b/arch/sandbox/include/asm/io.h @@ -49,17 +49,17 @@ unsigned int sandbox_read(const void *addr, enum sandboxio_size_t size); void sandbox_write(const void *addr, unsigned int val, enum sandboxio_size_t size);
-#define readb(addr) sandbox_read(addr, SB_SIZE_8) -#define readw(addr) sandbox_read(addr, SB_SIZE_16) -#define readl(addr) sandbox_read(addr, SB_SIZE_32) +#define readb(addr) sandbox_read((const void *)addr, SB_SIZE_8) +#define readw(addr) sandbox_read((const void *)addr, SB_SIZE_16) +#define readl(addr) sandbox_read((const void *)addr, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define readq(addr) sandbox_read(addr, SB_SIZE_64) +#define readq(addr) sandbox_read((const void *)addr, SB_SIZE_64) #endif -#define writeb(v, addr) sandbox_write(addr, v, SB_SIZE_8) -#define writew(v, addr) sandbox_write(addr, v, SB_SIZE_16) -#define writel(v, addr) sandbox_write(addr, v, SB_SIZE_32) +#define writeb(v, addr) sandbox_write((const void *)addr, v, SB_SIZE_8) +#define writew(v, addr) sandbox_write((const void *)addr, v, SB_SIZE_16) +#define writel(v, addr) sandbox_write((const void *)addr, v, SB_SIZE_32) #ifdef CONFIG_SANDBOX64 -#define writeq(v, addr) sandbox_write(addr, v, SB_SIZE_64) +#define writeq(v, addr) sandbox_write((const void *)addr, v, SB_SIZE_64) #endif
Applied the above fix to the same commit, and now in u-boot-x86/next.
Regards, Bin

Sandbox i2c works using emulation drivers which are currently children of the i2c device:
pci-controller { pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; emul@1f,0 { compatible = "sandbox,swap-case"; }; }; };
In this case the emulation device is attached to pci device on address f800 (device 1f, function 0) and provides the swap-case functionality.
However this is not ideal, since every device on a PCI bus has a child device. This is only really the case for sandbox, but we want to avoid special-case code for sandbox.
Worse, child devices cannot be probed before their parents. This forces us to use 'find' rather than 'get' to obtain the emulator device. In fact the emulator devices are never probed. There is code in sandbox_pci_emul_post_probe() which tries to track when emulators are active, but at present this does not work.
A better approach seems to be to add a separate node elsewhere in the device tree, an 'emulation parent'. This could be given a bogus address (such as -1) to hide the emulators away from the 'pci' command, but it seems better to keep it at the root node to avoid such hacks.
Then we can use a phandle to point from the evice to the correct emulator, and only on sandbox. The code to find an emulator does not interfere with normal pci operation.
Add a new UCLASS_PCI_EMUL_PARENT uclass which allows finding an emulator given a bus, and finding a bus given an emulator. Update the existing device trees and the code for finding an emulator.
This brings PCI emulators more into line with I2C.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/sandbox.dtsi | 11 +++++++--- arch/sandbox/dts/test.dts | 38 +++++++++++++++++++++++------------ doc/driver-model/pci-info.rst | 23 +++++++++++---------- drivers/pci/pci-emul-uclass.c | 37 ++++++++++++++++++++++++++++------ include/dm/uclass-id.h | 1 + 5 files changed, 77 insertions(+), 33 deletions(-)
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index c6d5650c20b..f09bc70b0da 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -103,9 +103,14 @@ pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; - emul@1f,0 { - compatible = "sandbox,swap-case"; - }; + sandbox,emul = <&swap_case_emul>; + }; + }; + + emul { + compatible = "sandbox,pci-emul-parent"; + swap_case_emul: emul@1f,0 { + compatible = "sandbox,swap-case"; }; };
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5669ede7051..a2e75981f0b 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -452,24 +452,31 @@ pci@0,0 { compatible = "pci-generic"; reg = <0x0000 0 0 0 0>; - emul@0,0 { - compatible = "sandbox,swap-case"; - }; + sandbox,emul = <&swap_case_emul0>; }; pci@1,0 { compatible = "pci-generic"; reg = <0x0800 0 0 0 0>; - emul@0,0 { - compatible = "sandbox,swap-case"; - use-ea; - }; + sandbox,emul = <&swap_case_emul1>; }; pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; - emul@1f,0 { - compatible = "sandbox,swap-case"; - }; + sandbox,emul = <&swap_case_emul1f>; + }; + }; + + pci-emul0 { + compatible = "sandbox,pci-emul-parent"; + swap_case_emul0: emul@0,0 { + compatible = "sandbox,swap-case"; + }; + swap_case_emul1: emul@1,0 { + compatible = "sandbox,swap-case"; + use-ea; + }; + swap_case_emul1f: emul@1f,0 { + compatible = "sandbox,swap-case"; }; };
@@ -499,9 +506,14 @@ pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; - emul@1f,0 { - compatible = "sandbox,swap-case"; - }; + sandbox,emul = <&swap_case_emul2_1f>; + }; + }; + + pci-emul2 { + compatible = "sandbox,pci-emul-parent"; + swap_case_emul2_1f: emul2@1f,0 { + compatible = "sandbox,swap-case"; }; };
diff --git a/doc/driver-model/pci-info.rst b/doc/driver-model/pci-info.rst index d93ab8b61d5..f39ff990a67 100644 --- a/doc/driver-model/pci-info.rst +++ b/doc/driver-model/pci-info.rst @@ -113,14 +113,17 @@ Sandbox -------
With sandbox we need a device emulator for each device on the bus since there -is no real PCI bus. This works by looking in the device tree node for a -driver. For example:: - +is no real PCI bus. This works by looking in the device tree node for an +emulator driver. For example::
pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; - emul@1f,0 { + sandbox,emul = <&emul_1f>; + }; + pci-emul { + compatible = "sandbox,pci-emul-parent"; + emul_1f: emul@1f,0 { compatible = "sandbox,swap-case"; }; }; @@ -130,14 +133,16 @@ Note that the first cell in the 'reg' value is the bus/device/function. See PCI_BDF() for the encoding (it is also specified in the IEEE Std 1275-1994 PCI bus binding document, v2.1)
+The pci-emul node should go outside the pci bus node, since otherwise it will +be scanned as a PCI device, causing confusion. + When this bus is scanned we will end up with something like this::
`- * pci-controller @ 05c660c8, 0 `- pci@1f,0 @ 05c661c8, 63488 - `- emul@1f,0 @ 05c662c8 + `- emul@1f,0 @ 05c662c8
-When accesses go to the pci@1f,0 device they are forwarded to its child, the -emulator. +When accesses go to the pci@1f,0 device they are forwarded to its emulator.
The sandbox PCI drivers also support dynamic driver binding, allowing device driver to declare the driver binding information via U_BOOT_PCI_DEVICE(), @@ -164,7 +169,3 @@ When this bus is scanned we will end up with something like this:: pci [ + ] pci_sandbo |-- pci-controller1 pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul pci_emul [ ] sandbox_sw | `-- sandbox_swap_case_emul - -Note the difference from the statically declared device nodes is that the -device is directly attached to the host controller, instead of via a container -device like pci@1f,0. diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 38227583547..f918e9a52fd 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -10,6 +10,7 @@ #include <linux/libfdt.h> #include <pci.h> #include <dm/lists.h> +#include <dm/uclass-internal.h>
struct sandbox_pci_emul_priv { int dev_count; @@ -30,13 +31,15 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, } *containerp = dev;
- if (device_get_uclass_id(dev) == UCLASS_PCI_GENERIC) { - ret = device_find_first_child(dev, emulp); - if (ret) - return ret; - } else { + /* + * TODO(sjg@chromium.org): This code needs a comment as I'm not sure + * why UCLASS_PCI_GENERIC devices end up being their own emulators. I + * left this code as is. + */ + ret = uclass_find_device_by_phandle(UCLASS_PCI_EMUL, dev, + "sandbox,emul", emulp); + if (ret && device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) *emulp = dev; - }
return *emulp ? 0 : -ENODEV; } @@ -68,3 +71,25 @@ UCLASS_DRIVER(pci_emul) = { .pre_remove = sandbox_pci_emul_pre_remove, .priv_auto_alloc_size = sizeof(struct sandbox_pci_emul_priv), }; + +/* + * This uclass is a child of the pci bus. Its platdata is not defined here so + * is defined by its parent, UCLASS_PCI, which uses struct pci_child_platdata. + * See per_child_platdata_auto_alloc_size in UCLASS_DRIVER(pci). + */ +UCLASS_DRIVER(pci_emul_parent) = { + .id = UCLASS_PCI_EMUL_PARENT, + .name = "pci_emul_parent", + .post_bind = dm_scan_fdt_dev, +}; + +static const struct udevice_id pci_emul_parent_ids[] = { + { .compatible = "sandbox,pci-emul-parent" }, + { } +}; + +U_BOOT_DRIVER(pci_emul_parent_drv) = { + .name = "pci_emul_parent_drv", + .id = UCLASS_PCI_EMUL_PARENT, + .of_match = pci_emul_parent_ids, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index d4d96106b37..f431f3bf294 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -23,6 +23,7 @@ enum uclass_id { UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ UCLASS_I2C_EMUL_PARENT, /* parent for I2C device emulators */ UCLASS_PCI_EMUL, /* sandbox PCI device emulator */ + UCLASS_PCI_EMUL_PARENT, /* parent for PCI device emulators */ UCLASS_USB_EMUL, /* sandbox USB bus device emulator */ UCLASS_AXI_EMUL, /* sandbox AXI bus device emulator */

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Sandbox i2c works using emulation drivers which are currently children of
pci
the i2c device:
pci
pci-controller { pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; emul@1f,0 { compatible = "sandbox,swap-case"; }; }; };
In this case the emulation device is attached to pci device on address f800 (device 1f, function 0) and provides the swap-case functionality.
However this is not ideal, since every device on a PCI bus has a child device. This is only really the case for sandbox, but we want to avoid special-case code for sandbox.
Worse, child devices cannot be probed before their parents. This forces us to use 'find' rather than 'get' to obtain the emulator device. In fact the emulator devices are never probed. There is code in sandbox_pci_emul_post_probe() which tries to track when emulators are active, but at present this does not work.
A better approach seems to be to add a separate node elsewhere in the device tree, an 'emulation parent'. This could be given a bogus address (such as -1) to hide the emulators away from the 'pci' command, but it seems better to keep it at the root node to avoid such hacks.
Then we can use a phandle to point from the evice to the correct
typo: device
emulator, and only on sandbox. The code to find an emulator does not interfere with normal pci operation.
Add a new UCLASS_PCI_EMUL_PARENT uclass which allows finding an emulator given a bus, and finding a bus given an emulator. Update the existing device trees and the code for finding an emulator.
This brings PCI emulators more into line with I2C.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/sandbox.dtsi | 11 +++++++--- arch/sandbox/dts/test.dts | 38 +++++++++++++++++++++++------------ doc/driver-model/pci-info.rst | 23 +++++++++++---------- drivers/pci/pci-emul-uclass.c | 37 ++++++++++++++++++++++++++++------ include/dm/uclass-id.h | 1 + 5 files changed, 77 insertions(+), 33 deletions(-)
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index c6d5650c20b..f09bc70b0da 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -103,9 +103,14 @@ pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
sandbox,emul = <&swap_case_emul>;
};
};
emul {
compatible = "sandbox,pci-emul-parent";
swap_case_emul: emul@1f,0 {
compatible = "sandbox,swap-case"; }; };
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5669ede7051..a2e75981f0b 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -452,24 +452,31 @@ pci@0,0 { compatible = "pci-generic"; reg = <0x0000 0 0 0 0>;
emul@0,0 {
compatible = "sandbox,swap-case";
};
sandbox,emul = <&swap_case_emul0>;
&swap_case_emul0_0
}; pci@1,0 { compatible = "pci-generic"; reg = <0x0800 0 0 0 0>;
emul@0,0 {
compatible = "sandbox,swap-case";
use-ea;
};
sandbox,emul = <&swap_case_emul1>;
&swap_case_emul0_1
}; pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
sandbox,emul = <&swap_case_emul1f>;
&swap_case_emul0_1f
};
};
pci-emul0 {
compatible = "sandbox,pci-emul-parent";
swap_case_emul0: emul@0,0 {
compatible = "sandbox,swap-case";
};
swap_case_emul1: emul@1,0 {
compatible = "sandbox,swap-case";
use-ea;
};
swap_case_emul1f: emul@1f,0 {
compatible = "sandbox,swap-case"; }; };
@@ -499,9 +506,14 @@ pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
sandbox,emul = <&swap_case_emul2_1f>;
};
};
pci-emul2 {
compatible = "sandbox,pci-emul-parent";
swap_case_emul2_1f: emul2@1f,0 {
compatible = "sandbox,swap-case"; }; };
diff --git a/doc/driver-model/pci-info.rst b/doc/driver-model/pci-info.rst index d93ab8b61d5..f39ff990a67 100644 --- a/doc/driver-model/pci-info.rst +++ b/doc/driver-model/pci-info.rst @@ -113,14 +113,17 @@ Sandbox
With sandbox we need a device emulator for each device on the bus since there -is no real PCI bus. This works by looking in the device tree node for a -driver. For example::
+is no real PCI bus. This works by looking in the device tree node for an +emulator driver. For example::
pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>;
emul@1f,0 {
sandbox,emul = <&emul_1f>;
};
pci-emul {
compatible = "sandbox,pci-emul-parent";
emul_1f: emul@1f,0 { compatible = "sandbox,swap-case"; }; };
@@ -130,14 +133,16 @@ Note that the first cell in the 'reg' value is the bus/device/function. See PCI_BDF() for the encoding (it is also specified in the IEEE Std 1275-1994 PCI bus binding document, v2.1)
+The pci-emul node should go outside the pci bus node, since otherwise it will +be scanned as a PCI device, causing confusion.
When this bus is scanned we will end up with something like this::
`- * pci-controller @ 05c660c8, 0 `- pci@1f,0 @ 05c661c8, 63488
`- emul@1f,0 @ 05c662c8
- `- emul@1f,0 @ 05c662c8
-When accesses go to the pci@1f,0 device they are forwarded to its child, the -emulator. +When accesses go to the pci@1f,0 device they are forwarded to its emulator.
The sandbox PCI drivers also support dynamic driver binding, allowing device driver to declare the driver binding information via U_BOOT_PCI_DEVICE(), @@ -164,7 +169,3 @@ When this bus is scanned we will end up with something like this:: pci [ + ] pci_sandbo |-- pci-controller1 pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul pci_emul [ ] sandbox_sw | `-- sandbox_swap_case_emul
-Note the difference from the statically declared device nodes is that the -device is directly attached to the host controller, instead of via a container -device like pci@1f,0. diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 38227583547..f918e9a52fd 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -10,6 +10,7 @@ #include <linux/libfdt.h> #include <pci.h> #include <dm/lists.h> +#include <dm/uclass-internal.h>
struct sandbox_pci_emul_priv { int dev_count; @@ -30,13 +31,15 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, } *containerp = dev;
if (device_get_uclass_id(dev) == UCLASS_PCI_GENERIC) {
ret = device_find_first_child(dev, emulp);
if (ret)
return ret;
} else {
/*
* TODO(sjg@chromium.org): This code needs a comment as I'm not sure
* why UCLASS_PCI_GENERIC devices end up being their own emulators. I
* left this code as is.
*/
This code comes from:
commit 4345998ae9dfad7ba0beb54ad4322134557504a9 Author: Bin Meng bmeng.cn@gmail.com Date: Fri Aug 3 01:14:45 2018 -0700
pci: sandbox: Support dynamically binding device driver
I think the comments can be removed :)
ret = uclass_find_device_by_phandle(UCLASS_PCI_EMUL, dev,
"sandbox,emul", emulp);
if (ret && device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) *emulp = dev;
} return *emulp ? 0 : -ENODEV;
} @@ -68,3 +71,25 @@ UCLASS_DRIVER(pci_emul) = { .pre_remove = sandbox_pci_emul_pre_remove, .priv_auto_alloc_size = sizeof(struct sandbox_pci_emul_priv), };
+/*
- This uclass is a child of the pci bus. Its platdata is not defined here so
- is defined by its parent, UCLASS_PCI, which uses struct pci_child_platdata.
- See per_child_platdata_auto_alloc_size in UCLASS_DRIVER(pci).
- */
+UCLASS_DRIVER(pci_emul_parent) = {
.id = UCLASS_PCI_EMUL_PARENT,
.name = "pci_emul_parent",
.post_bind = dm_scan_fdt_dev,
+};
+static const struct udevice_id pci_emul_parent_ids[] = {
{ .compatible = "sandbox,pci-emul-parent" },
{ }
+};
+U_BOOT_DRIVER(pci_emul_parent_drv) = {
.name = "pci_emul_parent_drv",
.id = UCLASS_PCI_EMUL_PARENT,
.of_match = pci_emul_parent_ids,
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index d4d96106b37..f431f3bf294 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -23,6 +23,7 @@ enum uclass_id { UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ UCLASS_I2C_EMUL_PARENT, /* parent for I2C device emulators */ UCLASS_PCI_EMUL, /* sandbox PCI device emulator */
UCLASS_PCI_EMUL_PARENT, /* parent for PCI device emulators */ UCLASS_USB_EMUL, /* sandbox USB bus device emulator */ UCLASS_AXI_EMUL, /* sandbox AXI bus device emulator */
--
Other than the issues above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 1:03 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Sandbox i2c works using emulation drivers which are currently children of
pci
the i2c device:
pci
Fixed these, and
pci-controller { pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; emul@1f,0 { compatible = "sandbox,swap-case"; }; }; };
In this case the emulation device is attached to pci device on address f800 (device 1f, function 0) and provides the swap-case functionality.
However this is not ideal, since every device on a PCI bus has a child device. This is only really the case for sandbox, but we want to avoid special-case code for sandbox.
Worse, child devices cannot be probed before their parents. This forces us to use 'find' rather than 'get' to obtain the emulator device. In fact the emulator devices are never probed. There is code in sandbox_pci_emul_post_probe() which tries to track when emulators are active, but at present this does not work.
A better approach seems to be to add a separate node elsewhere in the device tree, an 'emulation parent'. This could be given a bogus address (such as -1) to hide the emulators away from the 'pci' command, but it seems better to keep it at the root node to avoid such hacks.
Then we can use a phandle to point from the evice to the correct
typo: device
Fixed this, and
emulator, and only on sandbox. The code to find an emulator does not interfere with normal pci operation.
Add a new UCLASS_PCI_EMUL_PARENT uclass which allows finding an emulator given a bus, and finding a bus given an emulator. Update the existing device trees and the code for finding an emulator.
This brings PCI emulators more into line with I2C.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/sandbox.dtsi | 11 +++++++--- arch/sandbox/dts/test.dts | 38 +++++++++++++++++++++++------------ doc/driver-model/pci-info.rst | 23 +++++++++++---------- drivers/pci/pci-emul-uclass.c | 37 ++++++++++++++++++++++++++++------ include/dm/uclass-id.h | 1 + 5 files changed, 77 insertions(+), 33 deletions(-)
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index c6d5650c20b..f09bc70b0da 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -103,9 +103,14 @@ pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
sandbox,emul = <&swap_case_emul>;
};
};
emul {
compatible = "sandbox,pci-emul-parent";
swap_case_emul: emul@1f,0 {
compatible = "sandbox,swap-case"; }; };
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5669ede7051..a2e75981f0b 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -452,24 +452,31 @@ pci@0,0 { compatible = "pci-generic"; reg = <0x0000 0 0 0 0>;
emul@0,0 {
compatible = "sandbox,swap-case";
};
sandbox,emul = <&swap_case_emul0>;
&swap_case_emul0_0
}; pci@1,0 { compatible = "pci-generic"; reg = <0x0800 0 0 0 0>;
emul@0,0 {
compatible = "sandbox,swap-case";
use-ea;
};
sandbox,emul = <&swap_case_emul1>;
&swap_case_emul0_1
}; pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
sandbox,emul = <&swap_case_emul1f>;
&swap_case_emul0_1f
Fixed the label names, and
};
};
pci-emul0 {
compatible = "sandbox,pci-emul-parent";
swap_case_emul0: emul@0,0 {
compatible = "sandbox,swap-case";
};
swap_case_emul1: emul@1,0 {
compatible = "sandbox,swap-case";
use-ea;
};
swap_case_emul1f: emul@1f,0 {
compatible = "sandbox,swap-case"; }; };
@@ -499,9 +506,14 @@ pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>;
emul@1f,0 {
compatible = "sandbox,swap-case";
};
sandbox,emul = <&swap_case_emul2_1f>;
};
};
pci-emul2 {
compatible = "sandbox,pci-emul-parent";
swap_case_emul2_1f: emul2@1f,0 {
compatible = "sandbox,swap-case"; }; };
diff --git a/doc/driver-model/pci-info.rst b/doc/driver-model/pci-info.rst index d93ab8b61d5..f39ff990a67 100644 --- a/doc/driver-model/pci-info.rst +++ b/doc/driver-model/pci-info.rst @@ -113,14 +113,17 @@ Sandbox
With sandbox we need a device emulator for each device on the bus since there -is no real PCI bus. This works by looking in the device tree node for a -driver. For example::
+is no real PCI bus. This works by looking in the device tree node for an +emulator driver. For example::
pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>;
emul@1f,0 {
sandbox,emul = <&emul_1f>;
};
pci-emul {
compatible = "sandbox,pci-emul-parent";
emul_1f: emul@1f,0 { compatible = "sandbox,swap-case"; }; };
@@ -130,14 +133,16 @@ Note that the first cell in the 'reg' value is the bus/device/function. See PCI_BDF() for the encoding (it is also specified in the IEEE Std 1275-1994 PCI bus binding document, v2.1)
+The pci-emul node should go outside the pci bus node, since otherwise it will +be scanned as a PCI device, causing confusion.
When this bus is scanned we will end up with something like this::
`- * pci-controller @ 05c660c8, 0 `- pci@1f,0 @ 05c661c8, 63488
`- emul@1f,0 @ 05c662c8
- `- emul@1f,0 @ 05c662c8
-When accesses go to the pci@1f,0 device they are forwarded to its child, the -emulator. +When accesses go to the pci@1f,0 device they are forwarded to its emulator.
The sandbox PCI drivers also support dynamic driver binding, allowing device driver to declare the driver binding information via U_BOOT_PCI_DEVICE(), @@ -164,7 +169,3 @@ When this bus is scanned we will end up with something like this:: pci [ + ] pci_sandbo |-- pci-controller1 pci_emul [ ] sandbox_sw | |-- sandbox_swap_case_emul pci_emul [ ] sandbox_sw | `-- sandbox_swap_case_emul
-Note the difference from the statically declared device nodes is that the -device is directly attached to the host controller, instead of via a container -device like pci@1f,0. diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 38227583547..f918e9a52fd 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -10,6 +10,7 @@ #include <linux/libfdt.h> #include <pci.h> #include <dm/lists.h> +#include <dm/uclass-internal.h>
struct sandbox_pci_emul_priv { int dev_count; @@ -30,13 +31,15 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, } *containerp = dev;
if (device_get_uclass_id(dev) == UCLASS_PCI_GENERIC) {
ret = device_find_first_child(dev, emulp);
if (ret)
return ret;
} else {
/*
* TODO(sjg@chromium.org): This code needs a comment as I'm not sure
* why UCLASS_PCI_GENERIC devices end up being their own emulators. I
* left this code as is.
*/
This code comes from:
commit 4345998ae9dfad7ba0beb54ad4322134557504a9 Author: Bin Meng bmeng.cn@gmail.com Date: Fri Aug 3 01:14:45 2018 -0700
pci: sandbox: Support dynamically binding device driver
I think the comments can be removed :)
Updated the comment to mention commit 4345998ae9dfad7ba0beb54ad4322134557504a9, and
ret = uclass_find_device_by_phandle(UCLASS_PCI_EMUL, dev,
"sandbox,emul", emulp);
if (ret && device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) *emulp = dev;
} return *emulp ? 0 : -ENODEV;
} @@ -68,3 +71,25 @@ UCLASS_DRIVER(pci_emul) = { .pre_remove = sandbox_pci_emul_pre_remove, .priv_auto_alloc_size = sizeof(struct sandbox_pci_emul_priv), };
+/*
- This uclass is a child of the pci bus. Its platdata is not defined here so
- is defined by its parent, UCLASS_PCI, which uses struct pci_child_platdata.
- See per_child_platdata_auto_alloc_size in UCLASS_DRIVER(pci).
- */
+UCLASS_DRIVER(pci_emul_parent) = {
.id = UCLASS_PCI_EMUL_PARENT,
.name = "pci_emul_parent",
.post_bind = dm_scan_fdt_dev,
+};
+static const struct udevice_id pci_emul_parent_ids[] = {
{ .compatible = "sandbox,pci-emul-parent" },
{ }
+};
+U_BOOT_DRIVER(pci_emul_parent_drv) = {
.name = "pci_emul_parent_drv",
.id = UCLASS_PCI_EMUL_PARENT,
.of_match = pci_emul_parent_ids,
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index d4d96106b37..f431f3bf294 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -23,6 +23,7 @@ enum uclass_id { UCLASS_I2C_EMUL, /* sandbox I2C device emulator */ UCLASS_I2C_EMUL_PARENT, /* parent for I2C device emulators */ UCLASS_PCI_EMUL, /* sandbox PCI device emulator */
UCLASS_PCI_EMUL_PARENT, /* parent for PCI device emulators */ UCLASS_USB_EMUL, /* sandbox USB bus device emulator */ UCLASS_AXI_EMUL, /* sandbox AXI bus device emulator */
--
Other than the issues above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present PCI emulation devices are not probed before use, since they used to be children of the device that used them, and children cannot be probed before their parents.
Now that PCI emulation devices are attached to the root node, we can simply probe them, and avoid using the internal function.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pci/pci-emul-uclass.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index f918e9a52fd..a70c5e7633d 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -10,7 +10,6 @@ #include <linux/libfdt.h> #include <pci.h> #include <dm/lists.h> -#include <dm/uclass-internal.h>
struct sandbox_pci_emul_priv { int dev_count; @@ -36,8 +35,8 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, * why UCLASS_PCI_GENERIC devices end up being their own emulators. I * left this code as is. */ - ret = uclass_find_device_by_phandle(UCLASS_PCI_EMUL, dev, - "sandbox,emul", emulp); + ret = uclass_get_device_by_phandle(UCLASS_PCI_EMUL, dev, "sandbox,emul", + emulp); if (ret && device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) *emulp = dev;

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present PCI emulation devices are not probed before use, since they used to be children of the device that used them, and children cannot be probed before their parents.
Now that PCI emulation devices are attached to the root node, we can simply probe them, and avoid using the internal function.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci-emul-uclass.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 1:03 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present PCI emulation devices are not probed before use, since they used to be children of the device that used them, and children cannot be probed before their parents.
Now that PCI emulation devices are attached to the root node, we can simply probe them, and avoid using the internal function.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci-emul-uclass.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
Rebased the patch against u-boot-x86/next to get it applied cleanly, and
applied to u-boot-x86/next, thanks!

Update the debugging info a little to show the result of trying to bind a PCI device.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pci/pci-uclass.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index ab3e1310eb5..4c84c656856 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -790,7 +790,7 @@ int pci_bind_bus_devices(struct udevice *bus) if (!PCI_FUNC(bdf)) found_multi = header_type & 0x80;
- debug("%s: bus %d/%s: found device %x, function %d\n", __func__, + debug("%s: bus %d/%s: found device %x, function %d", __func__, bus->seq, bus->name, PCI_DEV(bdf), PCI_FUNC(bdf)); pci_bus_read_config(bus, bdf, PCI_DEVICE_ID, &device, PCI_SIZE_16); @@ -800,6 +800,7 @@ int pci_bind_bus_devices(struct udevice *bus)
/* Find this device in the device tree */ ret = pci_bus_find_devfn(bus, PCI_MASK_BUS(bdf), &dev); + debug(": find ret=%d\n", ret);
/* If nothing in the device tree, bind a device */ if (ret == -ENODEV) {

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Update the debugging info a little to show the result of trying to bind a PCI device.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci-uclass.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 1:03 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Update the debugging info a little to show the result of trying to bind a PCI device.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci-uclass.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present U-Boot runs autoconfig in SPL but this is best left to U-Boot proper. For TPL and SPL we can normally used fixed BARs and save code size and time.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pci/pci-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 4c84c656856..896cb6b23a1 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -983,7 +983,7 @@ static int pci_uclass_post_probe(struct udevice *bus) if (ret) return ret;
-#ifdef CONFIG_PCI_PNP +#if CONFIG_IS_ENABLED(PCI_PNP) ret = pci_auto_config_devices(bus); if (ret < 0) return ret;

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present U-Boot runs autoconfig in SPL but this is best left to U-Boot proper. For TPL and SPL we can normally used fixed BARs and save code size and time.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 1:03 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present U-Boot runs autoconfig in SPL but this is best left to U-Boot proper. For TPL and SPL we can normally used fixed BARs and save code size and time.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci-uclass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Fix these spelling errors the header file and documentation.
Fix a small typo in the PCI documentation.
Signed-off-by: Simon Glass sjg@chromium.org ---
doc/driver-model/pci-info.rst | 2 +- include/pci.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/doc/driver-model/pci-info.rst b/doc/driver-model/pci-info.rst index f39ff990a67..3c1b1adf077 100644 --- a/doc/driver-model/pci-info.rst +++ b/doc/driver-model/pci-info.rst @@ -103,7 +103,7 @@ in each of these nodes.
If PCI devices are not listed in the device tree, U_BOOT_PCI_DEVICE can be used to specify the driver to use for the device. The device tree takes precedence -over U_BOOT_PCI_DEVICE. Plese note with U_BOOT_PCI_DEVICE, only drivers with +over U_BOOT_PCI_DEVICE. Please note with U_BOOT_PCI_DEVICE, only drivers with DM_FLAG_PRE_RELOC will be bound before relocation. If neither device tree nor U_BOOT_PCI_DEVICE is provided, the built-in driver (either pci_bridge_drv or pci_generic_drv) will be used. diff --git a/include/pci.h b/include/pci.h index 2b82b2c5a3e..8aa6636cfbf 100644 --- a/include/pci.h +++ b/include/pci.h @@ -1595,7 +1595,7 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, /** * pci_get_devfn() - Extract the devfn from fdt_pci_addr of the device * - * Get devfn from fdt_pci_addr of the specifified device + * Get devfn from fdt_pci_addr of the specified device * * @dev: PCI device * @return devfn in bits 15...8 if found, -ENODEV if not found

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Fix these spelling errors the header file and documentation.
in the header
Fix a small typo in the PCI documentation.
Signed-off-by: Simon Glass sjg@chromium.org
doc/driver-model/pci-info.rst | 2 +- include/pci.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 1:03 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Fix these spelling errors the header file and documentation.
in the header
Fix a small typo in the PCI documentation.
Signed-off-by: Simon Glass sjg@chromium.org
doc/driver-model/pci-info.rst | 2 +- include/pci.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

If PCI auto-config runs out of memory, show a few more details to help diagnose the problem.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pci/pci_auto_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci_auto_common.c b/drivers/pci/pci_auto_common.c index 84908e6154c..bb56a3d3fea 100644 --- a/drivers/pci/pci_auto_common.c +++ b/drivers/pci/pci_auto_common.c @@ -45,7 +45,8 @@ int pciauto_region_allocate(struct pci_region *res, pci_size_t size, addr = ((res->bus_lower - 1) | (size - 1)) + 1;
if (addr - res->bus_start + size > res->size) { - debug("No room in resource"); + debug("No room in resource, avail start=%x / size=%x, need=%x\n", + res->bus_lower, res->size, size); goto error; }

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
If PCI auto-config runs out of memory, show a few more details to help diagnose the problem.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci_auto_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 9:12 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
If PCI auto-config runs out of memory, show a few more details to help diagnose the problem.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci_auto_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

On Sun, Oct 6, 2019 at 7:19 PM Bin Meng bmeng.cn@gmail.com wrote:
On Sat, Oct 5, 2019 at 9:12 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
If PCI auto-config runs out of memory, show a few more details to help diagnose the problem.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci_auto_common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!
It turns out we need do the following to eliminate build warnings on some boards:
diff --git a/drivers/pci/pci_auto_common.c b/drivers/pci/pci_auto_common.c index bb56a3d..8690316 100644 --- a/drivers/pci/pci_auto_common.c +++ b/drivers/pci/pci_auto_common.c @@ -45,8 +45,9 @@ int pciauto_region_allocate(struct pci_region *res, pci_size_t size, addr = ((res->bus_lower - 1) | (size - 1)) + 1;
if (addr - res->bus_start + size > res->size) { - debug("No room in resource, avail start=%x / size=%x, need=%x\n", - res->bus_lower, res->size, size); + debug("No room in resource, avail start=%llx / size=%llx, " + "need=%llx\n", (unsigned long long)res->bus_lower, + (unsigned long long)res->size, (unsigned long long)size); goto error; }
Applied the above fix in the same commit, and now in u-boot-x86/next.
Regards, Bin

At present this fails silently which can be confusing since some devices on the PCI bus may not work correctly. Show a message in this case
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pci/pci_auto.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 1a3bf708347..7755ffb6fa2 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -39,6 +39,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) { + int ret = 0; + /* Tickle the BAR and get the response */ if (!enum_only) dm_pci_write_config32(dev, bar, 0xffffffff); @@ -97,9 +99,13 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, (unsigned long long)bar_size); }
- if (!enum_only && pciauto_region_allocate(bar_res, bar_size, - &bar_value, - found_mem64) == 0) { + if (!enum_only) { + ret = pciauto_region_allocate(bar_res, bar_size, + &bar_value, found_mem64); + if (ret) + printf("PCI: Failed autoconfig bar %x", bar); + } + if (!enum_only && !ret) { /* Write it out and update our limit */ dm_pci_write_config32(dev, bar, (u32)bar_value);

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this fails silently which can be confusing since some devices on the PCI bus may not work correctly. Show a message in this case
nits: missing . after case
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci_auto.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 1a3bf708347..7755ffb6fa2 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -39,6 +39,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) {
int ret = 0;
/* Tickle the BAR and get the response */ if (!enum_only) dm_pci_write_config32(dev, bar, 0xffffffff);
@@ -97,9 +99,13 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, (unsigned long long)bar_size); }
if (!enum_only && pciauto_region_allocate(bar_res, bar_size,
&bar_value,
found_mem64) == 0) {
if (!enum_only) {
ret = pciauto_region_allocate(bar_res, bar_size,
&bar_value, found_mem64);
if (ret)
printf("PCI: Failed autoconfig bar %x", bar);
nits: should have a '\n'
}
if (!enum_only && !ret) { /* Write it out and update our limit */ dm_pci_write_config32(dev, bar, (u32)bar_value);
--
Other than above, Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 9:12 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this fails silently which can be confusing since some devices on the PCI bus may not work correctly. Show a message in this case
nits: missing . after case
Fixed, and
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci_auto.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 1a3bf708347..7755ffb6fa2 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -39,6 +39,8 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num,
for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) {
int ret = 0;
/* Tickle the BAR and get the response */ if (!enum_only) dm_pci_write_config32(dev, bar, 0xffffffff);
@@ -97,9 +99,13 @@ void dm_pciauto_setup_device(struct udevice *dev, int bars_num, (unsigned long long)bar_size); }
if (!enum_only && pciauto_region_allocate(bar_res, bar_size,
&bar_value,
found_mem64) == 0) {
if (!enum_only) {
ret = pciauto_region_allocate(bar_res, bar_size,
&bar_value, found_mem64);
if (ret)
printf("PCI: Failed autoconfig bar %x", bar);
nits: should have a '\n'
Added a '\n', and
}
if (!enum_only && !ret) { /* Write it out and update our limit */ dm_pci_write_config32(dev, bar, (u32)bar_value);
--
Other than above, Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present PCI address transaction is not supported so drivers must manually read the correct BAR after reading the device tree info. The ns16550 has a suitable implementation, so move this code into the core DM support.
Note that there is no live-tree equivalent at present.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/test.dts | 7 ++++-- drivers/core/fdtaddr.c | 33 ++++++++++++++++++++++++++++ drivers/core/read.c | 11 ++++++++++ drivers/serial/ns16550.c | 31 +-------------------------- include/dm/fdtaddr.h | 8 +++++++ include/dm/read.h | 25 ++++++++++++++++++++++ test/dm/pci.c | 45 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 32 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index a2e75981f0b..8733e0d7e19 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -456,12 +456,15 @@ }; pci@1,0 { compatible = "pci-generic"; - reg = <0x0800 0 0 0 0>; + /* BAR0 is at 0x14, using FDT_PCI_SPACE_MEM32 */ + reg = <0x02000814 0 0 0 0 + 0x0100f810 0 0 0 0>; sandbox,emul = <&swap_case_emul1>; }; pci@1f,0 { compatible = "pci-generic"; - reg = <0xf800 0 0 0 0>; + /* BAR1 is at 0x10, using FDT_PCI_SPACE_IO */ + reg = <0x0100f810 0 0 0 0>; sandbox,emul = <&swap_case_emul1f>; }; }; diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c index 6850003a287..c9a941116a3 100644 --- a/drivers/core/fdtaddr.c +++ b/drivers/core/fdtaddr.c @@ -190,3 +190,36 @@ void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
return map_physmem(addr, size, MAP_NOCACHE); } + +fdt_addr_t devfdt_get_addr_pci(struct udevice *dev) +{ + ulong addr; + + addr = devfdt_get_addr(dev); + if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) && + addr == FDT_ADDR_T_NONE) { + struct fdt_pci_addr pci_addr; + u32 bar; + int ret; + + ret = fdtdec_get_pci_addr(gd->fdt_blob, + dev_of_offset(dev), + FDT_PCI_SPACE_MEM32, "reg", + &pci_addr); + if (ret) { + /* try if there is any i/o-mapped register */ + ret = fdtdec_get_pci_addr(gd->fdt_blob, + dev_of_offset(dev), + FDT_PCI_SPACE_IO, "reg", + &pci_addr); + if (ret) + return FDT_ADDR_T_NONE; + } + ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar); + if (ret) + return FDT_ADDR_T_NONE; + addr = bar; + } + + return addr; +} diff --git a/drivers/core/read.c b/drivers/core/read.c index fb3dcd9a790..9602e52d1b1 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -307,3 +307,14 @@ int dev_read_alias_highest_id(const char *stem)
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem); } + +fdt_addr_t dev_read_addr_pci(struct udevice *dev) +{ + ulong addr; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE && !of_live_active()) + addr = devfdt_get_addr_pci(dev); + + return addr; +} diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 01f334938ea..754b6e99215 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -440,36 +440,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) int err;
/* try Processor Local Bus device first */ - addr = dev_read_addr(dev); -#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI) - if (addr == FDT_ADDR_T_NONE) { - /* then try pci device */ - struct fdt_pci_addr pci_addr; - u32 bar; - int ret; - - /* we prefer to use a memory-mapped register */ - ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev), - FDT_PCI_SPACE_MEM32, "reg", - &pci_addr); - if (ret) { - /* try if there is any i/o-mapped register */ - ret = fdtdec_get_pci_addr(gd->fdt_blob, - dev_of_offset(dev), - FDT_PCI_SPACE_IO, - "reg", &pci_addr); - if (ret) - return ret; - } - - ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar); - if (ret) - return ret; - - addr = bar; - } -#endif - + addr = dev_read_addr_pci(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL;
diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h index 57b326cb336..959d3bc2d69 100644 --- a/include/dm/fdtaddr.h +++ b/include/dm/fdtaddr.h @@ -138,4 +138,12 @@ fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name); fdt_addr_t devfdt_get_addr_size_name(struct udevice *dev, const char *name, fdt_size_t *size);
+/** + * devfdt_get_addr_pci() - Read an address and handle PCI address translation + * + * @dev: Device to read from + * @return address or FDT_ADDR_T_NONE if not found + */ +fdt_addr_t devfdt_get_addr_pci(struct udevice *dev); + #endif diff --git a/include/dm/read.h b/include/dm/read.h index 03189838ff7..4f02d07d001 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -247,6 +247,26 @@ fdt_addr_t dev_read_addr(struct udevice *dev); */ void *dev_read_addr_ptr(struct udevice *dev);
+/** + * dev_read_addr_pci() - Read an address and handle PCI address translation + * + * At present U-Boot does not have address translation logic for PCI in the + * livetree implementation (of_addr.c). This special function supports this for + * the flat tree implementation. + * + * This function should be removed (and code should use dev_read() instead) + * once: + * + * 1. PCI address translation is added; and either + * 2. everything uses livetree where PCI translation is used (which is feasible + * in SPL and U-Boot proper) or PCI address translation is added to + * fdtdec_get_addr() and friends. + * + * @dev: Device to read from + * @return address or FDT_ADDR_T_NONE if not found + */ +fdt_addr_t dev_read_addr_pci(struct udevice *dev); + /** * dev_remap_addr() - Get the reg property of a device as a * memory-mapped I/O pointer @@ -690,6 +710,11 @@ static inline void *dev_read_addr_ptr(struct udevice *dev) return devfdt_get_addr_ptr(dev); }
+static inline fdt_addr_t dev_read_addr_pci(struct udevice *dev) +{ + return devfdt_get_addr_pci(dev); +} + static inline void *dev_remap_addr(struct udevice *dev) { return devfdt_remap_addr(dev); diff --git a/test/dm/pci.c b/test/dm/pci.c index e70b65aea4a..fb93e4c78ae 100644 --- a/test/dm/pci.c +++ b/test/dm/pci.c @@ -294,3 +294,48 @@ static int dm_test_pci_ea(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_pci_ea, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test the dev_read_addr_pci() function */ +static int dm_test_pci_addr_flat(struct unit_test_state *uts) +{ + struct udevice *swap1f, *swap1; + ulong io_addr, mem_addr; + + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f)); + io_addr = dm_pci_read_bar32(swap1f, 0); + ut_asserteq(io_addr, dev_read_addr_pci(swap1f)); + + /* + * This device has both I/O and MEM spaces but the MEM space appears + * first + */ + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1)); + mem_addr = dm_pci_read_bar32(swap1, 1); + ut_asserteq(mem_addr, dev_read_addr_pci(swap1)); + + return 0; +} +DM_TEST(dm_test_pci_addr_flat, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | + DM_TESTF_FLAT_TREE); + +/* + * Test the dev_read_addr_pci() function with livetree. That function is + * not currently fully implemented, in that it fails to return the BAR address. + * Once that is implemented this test can be removed and dm_test_pci_addr_flat() + * can be used for both flattree and livetree by removing the DM_TESTF_FLAT_TREE + * flag above. + */ +static int dm_test_pci_addr_live(struct unit_test_state *uts) +{ + struct udevice *swap1f, *swap1; + + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f)); + ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f)); + + ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1)); + ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1)); + + return 0; +} +DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT | + DM_TESTF_LIVE_TREE);

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present PCI address transaction is not supported so drivers must manually read the correct BAR after reading the device tree info. The ns16550 has a suitable implementation, so move this code into the core DM support.
Note that there is no live-tree equivalent at present.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/test.dts | 7 ++++-- drivers/core/fdtaddr.c | 33 ++++++++++++++++++++++++++++ drivers/core/read.c | 11 ++++++++++ drivers/serial/ns16550.c | 31 +-------------------------- include/dm/fdtaddr.h | 8 +++++++ include/dm/read.h | 25 ++++++++++++++++++++++ test/dm/pci.c | 45 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 32 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index a2e75981f0b..8733e0d7e19 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -456,12 +456,15 @@ }; pci@1,0 { compatible = "pci-generic";
reg = <0x0800 0 0 0 0>;
/* BAR0 is at 0x14, using FDT_PCI_SPACE_MEM32 */
reg 0
reg = <0x02000814 0 0 0 0
0x0100f810 0 0 0 0>;
it should be 0x01000810, and should have a similar comment like reg 0
sandbox,emul = <&swap_case_emul1>; }; pci@1f,0 { compatible = "pci-generic";
reg = <0xf800 0 0 0 0>;
/* BAR1 is at 0x10, using FDT_PCI_SPACE_IO */
reg 0
reg = <0x0100f810 0 0 0 0>; sandbox,emul = <&swap_case_emul1f>; }; };
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c index 6850003a287..c9a941116a3 100644 --- a/drivers/core/fdtaddr.c +++ b/drivers/core/fdtaddr.c @@ -190,3 +190,36 @@ void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
return map_physmem(addr, size, MAP_NOCACHE);
}
+fdt_addr_t devfdt_get_addr_pci(struct udevice *dev) +{
ulong addr;
addr = devfdt_get_addr(dev);
if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) &&
addr == FDT_ADDR_T_NONE) {
struct fdt_pci_addr pci_addr;
u32 bar;
int ret;
ret = fdtdec_get_pci_addr(gd->fdt_blob,
dev_of_offset(dev),
FDT_PCI_SPACE_MEM32, "reg",
&pci_addr);
if (ret) {
/* try if there is any i/o-mapped register */
ret = fdtdec_get_pci_addr(gd->fdt_blob,
dev_of_offset(dev),
FDT_PCI_SPACE_IO, "reg",
&pci_addr);
if (ret)
return FDT_ADDR_T_NONE;
}
ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
if (ret)
return FDT_ADDR_T_NONE;
addr = bar;
}
return addr;
+} diff --git a/drivers/core/read.c b/drivers/core/read.c index fb3dcd9a790..9602e52d1b1 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -307,3 +307,14 @@ int dev_read_alias_highest_id(const char *stem)
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
}
+fdt_addr_t dev_read_addr_pci(struct udevice *dev) +{
ulong addr;
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE && !of_live_active())
addr = devfdt_get_addr_pci(dev);
return addr;
+} diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 01f334938ea..754b6e99215 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -440,36 +440,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) int err;
/* try Processor Local Bus device first */
addr = dev_read_addr(dev);
-#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI)
if (addr == FDT_ADDR_T_NONE) {
/* then try pci device */
struct fdt_pci_addr pci_addr;
u32 bar;
int ret;
/* we prefer to use a memory-mapped register */
ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev),
FDT_PCI_SPACE_MEM32, "reg",
&pci_addr);
if (ret) {
/* try if there is any i/o-mapped register */
ret = fdtdec_get_pci_addr(gd->fdt_blob,
dev_of_offset(dev),
FDT_PCI_SPACE_IO,
"reg", &pci_addr);
if (ret)
return ret;
}
ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
if (ret)
return ret;
addr = bar;
}
-#endif
addr = dev_read_addr_pci(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL;
diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h index 57b326cb336..959d3bc2d69 100644 --- a/include/dm/fdtaddr.h +++ b/include/dm/fdtaddr.h @@ -138,4 +138,12 @@ fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name); fdt_addr_t devfdt_get_addr_size_name(struct udevice *dev, const char *name, fdt_size_t *size);
+/**
- devfdt_get_addr_pci() - Read an address and handle PCI address translation
- @dev: Device to read from
- @return address or FDT_ADDR_T_NONE if not found
- */
+fdt_addr_t devfdt_get_addr_pci(struct udevice *dev);
#endif diff --git a/include/dm/read.h b/include/dm/read.h index 03189838ff7..4f02d07d001 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -247,6 +247,26 @@ fdt_addr_t dev_read_addr(struct udevice *dev); */ void *dev_read_addr_ptr(struct udevice *dev);
+/**
- dev_read_addr_pci() - Read an address and handle PCI address translation
- At present U-Boot does not have address translation logic for PCI in the
- livetree implementation (of_addr.c). This special function supports this for
- the flat tree implementation.
- This function should be removed (and code should use dev_read() instead)
- once:
- PCI address translation is added; and either
- everything uses livetree where PCI translation is used (which is feasible
- in SPL and U-Boot proper) or PCI address translation is added to
- fdtdec_get_addr() and friends.
- @dev: Device to read from
- @return address or FDT_ADDR_T_NONE if not found
- */
+fdt_addr_t dev_read_addr_pci(struct udevice *dev);
/**
- dev_remap_addr() - Get the reg property of a device as a
memory-mapped I/O pointer
@@ -690,6 +710,11 @@ static inline void *dev_read_addr_ptr(struct udevice *dev) return devfdt_get_addr_ptr(dev); }
+static inline fdt_addr_t dev_read_addr_pci(struct udevice *dev) +{
return devfdt_get_addr_pci(dev);
+}
static inline void *dev_remap_addr(struct udevice *dev) { return devfdt_remap_addr(dev); diff --git a/test/dm/pci.c b/test/dm/pci.c index e70b65aea4a..fb93e4c78ae 100644 --- a/test/dm/pci.c +++ b/test/dm/pci.c @@ -294,3 +294,48 @@ static int dm_test_pci_ea(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_pci_ea, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/* Test the dev_read_addr_pci() function */ +static int dm_test_pci_addr_flat(struct unit_test_state *uts) +{
struct udevice *swap1f, *swap1;
ulong io_addr, mem_addr;
ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
io_addr = dm_pci_read_bar32(swap1f, 0);
ut_asserteq(io_addr, dev_read_addr_pci(swap1f));
/*
* This device has both I/O and MEM spaces but the MEM space appears
* first
*/
ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
mem_addr = dm_pci_read_bar32(swap1, 1);
ut_asserteq(mem_addr, dev_read_addr_pci(swap1));
return 0;
+} +DM_TEST(dm_test_pci_addr_flat, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
DM_TESTF_FLAT_TREE);
+/*
- Test the dev_read_addr_pci() function with livetree. That function is
- not currently fully implemented, in that it fails to return the BAR address.
- Once that is implemented this test can be removed and dm_test_pci_addr_flat()
- can be used for both flattree and livetree by removing the DM_TESTF_FLAT_TREE
- flag above.
- */
+static int dm_test_pci_addr_live(struct unit_test_state *uts) +{
struct udevice *swap1f, *swap1;
ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f));
ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1));
return 0;
+} +DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
DM_TESTF_LIVE_TREE);
--
Other than above, Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 9:12 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present PCI address transaction is not supported so drivers must manually read the correct BAR after reading the device tree info. The ns16550 has a suitable implementation, so move this code into the core DM support.
Note that there is no live-tree equivalent at present.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/dts/test.dts | 7 ++++-- drivers/core/fdtaddr.c | 33 ++++++++++++++++++++++++++++ drivers/core/read.c | 11 ++++++++++ drivers/serial/ns16550.c | 31 +-------------------------- include/dm/fdtaddr.h | 8 +++++++ include/dm/read.h | 25 ++++++++++++++++++++++ test/dm/pci.c | 45 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 32 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index a2e75981f0b..8733e0d7e19 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -456,12 +456,15 @@ }; pci@1,0 { compatible = "pci-generic";
reg = <0x0800 0 0 0 0>;
/* BAR0 is at 0x14, using FDT_PCI_SPACE_MEM32 */
reg 0
reg = <0x02000814 0 0 0 0
0x0100f810 0 0 0 0>;
it should be 0x01000810, and should have a similar comment like reg 0
sandbox,emul = <&swap_case_emul1>; }; pci@1f,0 { compatible = "pci-generic";
reg = <0xf800 0 0 0 0>;
/* BAR1 is at 0x10, using FDT_PCI_SPACE_IO */
reg 0
Corrected the above comments, and
reg = <0x0100f810 0 0 0 0>; sandbox,emul = <&swap_case_emul1f>; }; };
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c index 6850003a287..c9a941116a3 100644 --- a/drivers/core/fdtaddr.c +++ b/drivers/core/fdtaddr.c @@ -190,3 +190,36 @@ void *devfdt_map_physmem(struct udevice *dev, unsigned long size)
return map_physmem(addr, size, MAP_NOCACHE);
}
+fdt_addr_t devfdt_get_addr_pci(struct udevice *dev) +{
ulong addr;
addr = devfdt_get_addr(dev);
if (CONFIG_IS_ENABLED(PCI) && IS_ENABLED(CONFIG_DM_PCI) &&
addr == FDT_ADDR_T_NONE) {
struct fdt_pci_addr pci_addr;
u32 bar;
int ret;
ret = fdtdec_get_pci_addr(gd->fdt_blob,
dev_of_offset(dev),
FDT_PCI_SPACE_MEM32, "reg",
&pci_addr);
if (ret) {
/* try if there is any i/o-mapped register */
ret = fdtdec_get_pci_addr(gd->fdt_blob,
dev_of_offset(dev),
FDT_PCI_SPACE_IO, "reg",
&pci_addr);
if (ret)
return FDT_ADDR_T_NONE;
}
ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
if (ret)
return FDT_ADDR_T_NONE;
addr = bar;
}
return addr;
+} diff --git a/drivers/core/read.c b/drivers/core/read.c index fb3dcd9a790..9602e52d1b1 100644 --- a/drivers/core/read.c +++ b/drivers/core/read.c @@ -307,3 +307,14 @@ int dev_read_alias_highest_id(const char *stem)
return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
}
+fdt_addr_t dev_read_addr_pci(struct udevice *dev) +{
ulong addr;
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE && !of_live_active())
addr = devfdt_get_addr_pci(dev);
return addr;
+} diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 01f334938ea..754b6e99215 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -440,36 +440,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) int err;
/* try Processor Local Bus device first */
addr = dev_read_addr(dev);
-#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI)
if (addr == FDT_ADDR_T_NONE) {
/* then try pci device */
struct fdt_pci_addr pci_addr;
u32 bar;
int ret;
/* we prefer to use a memory-mapped register */
ret = fdtdec_get_pci_addr(gd->fdt_blob, dev_of_offset(dev),
FDT_PCI_SPACE_MEM32, "reg",
&pci_addr);
if (ret) {
/* try if there is any i/o-mapped register */
ret = fdtdec_get_pci_addr(gd->fdt_blob,
dev_of_offset(dev),
FDT_PCI_SPACE_IO,
"reg", &pci_addr);
if (ret)
return ret;
}
ret = fdtdec_get_pci_bar32(dev, &pci_addr, &bar);
if (ret)
return ret;
addr = bar;
}
-#endif
addr = dev_read_addr_pci(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL;
diff --git a/include/dm/fdtaddr.h b/include/dm/fdtaddr.h index 57b326cb336..959d3bc2d69 100644 --- a/include/dm/fdtaddr.h +++ b/include/dm/fdtaddr.h @@ -138,4 +138,12 @@ fdt_addr_t devfdt_get_addr_name(struct udevice *dev, const char *name); fdt_addr_t devfdt_get_addr_size_name(struct udevice *dev, const char *name, fdt_size_t *size);
+/**
- devfdt_get_addr_pci() - Read an address and handle PCI address translation
- @dev: Device to read from
- @return address or FDT_ADDR_T_NONE if not found
- */
+fdt_addr_t devfdt_get_addr_pci(struct udevice *dev);
#endif diff --git a/include/dm/read.h b/include/dm/read.h index 03189838ff7..4f02d07d001 100644 --- a/include/dm/read.h +++ b/include/dm/read.h @@ -247,6 +247,26 @@ fdt_addr_t dev_read_addr(struct udevice *dev); */ void *dev_read_addr_ptr(struct udevice *dev);
+/**
- dev_read_addr_pci() - Read an address and handle PCI address translation
- At present U-Boot does not have address translation logic for PCI in the
- livetree implementation (of_addr.c). This special function supports this for
- the flat tree implementation.
- This function should be removed (and code should use dev_read() instead)
- once:
- PCI address translation is added; and either
- everything uses livetree where PCI translation is used (which is feasible
- in SPL and U-Boot proper) or PCI address translation is added to
- fdtdec_get_addr() and friends.
- @dev: Device to read from
- @return address or FDT_ADDR_T_NONE if not found
- */
+fdt_addr_t dev_read_addr_pci(struct udevice *dev);
/**
- dev_remap_addr() - Get the reg property of a device as a
memory-mapped I/O pointer
@@ -690,6 +710,11 @@ static inline void *dev_read_addr_ptr(struct udevice *dev) return devfdt_get_addr_ptr(dev); }
+static inline fdt_addr_t dev_read_addr_pci(struct udevice *dev) +{
return devfdt_get_addr_pci(dev);
+}
static inline void *dev_remap_addr(struct udevice *dev) { return devfdt_remap_addr(dev); diff --git a/test/dm/pci.c b/test/dm/pci.c index e70b65aea4a..fb93e4c78ae 100644 --- a/test/dm/pci.c +++ b/test/dm/pci.c @@ -294,3 +294,48 @@ static int dm_test_pci_ea(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_pci_ea, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/* Test the dev_read_addr_pci() function */ +static int dm_test_pci_addr_flat(struct unit_test_state *uts) +{
struct udevice *swap1f, *swap1;
ulong io_addr, mem_addr;
ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
io_addr = dm_pci_read_bar32(swap1f, 0);
ut_asserteq(io_addr, dev_read_addr_pci(swap1f));
/*
* This device has both I/O and MEM spaces but the MEM space appears
* first
*/
ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
mem_addr = dm_pci_read_bar32(swap1, 1);
ut_asserteq(mem_addr, dev_read_addr_pci(swap1));
return 0;
+} +DM_TEST(dm_test_pci_addr_flat, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
DM_TESTF_FLAT_TREE);
+/*
- Test the dev_read_addr_pci() function with livetree. That function is
- not currently fully implemented, in that it fails to return the BAR address.
- Once that is implemented this test can be removed and dm_test_pci_addr_flat()
- can be used for both flattree and livetree by removing the DM_TESTF_FLAT_TREE
- flag above.
- */
+static int dm_test_pci_addr_live(struct unit_test_state *uts) +{
struct udevice *swap1f, *swap1;
ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f));
ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
ut_asserteq(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1));
return 0;
+} +DM_TEST(dm_test_pci_addr_live, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT |
DM_TESTF_LIVE_TREE);
--
Other than above, Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

When this UART is used early in boot (before PCI is set up) it is convenient to store the PCI BDF of the UART so that it can be manually configured. This is useful when it is used as a debug UART, for example.
Add a new field to hold this information, so that drivers can simply use the existing platform data.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/ns16550.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/ns16550.h b/include/ns16550.h index 22b89e4d6d1..701efeea855 100644 --- a/include/ns16550.h +++ b/include/ns16550.h @@ -52,6 +52,7 @@ * @reg_width: IO accesses size of registers (in bytes) * @reg_shift: Shift size of registers (0=byte, 1=16bit, 2=32bit...) * @clock: UART base clock speed in Hz + * @bdf: PCI slot/function (pci_dev_t) */ struct ns16550_platdata { unsigned long base; @@ -60,6 +61,9 @@ struct ns16550_platdata { int reg_offset; int clock; u32 fcr; +#if defined(CONFIG_PCI) && defined(CONFIG_SPL) + int bdf; +#endif };
struct udevice;

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
When this UART is used early in boot (before PCI is set up) it is convenient to store the PCI BDF of the UART so that it can be manually configured. This is useful when it is used as a debug UART, for example.
Add a new field to hold this information, so that drivers can simply use the existing platform data.
Signed-off-by: Simon Glass sjg@chromium.org
include/ns16550.h | 4 ++++ 1 file changed, 4 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 9:12 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
When this UART is used early in boot (before PCI is set up) it is convenient to store the PCI BDF of the UART so that it can be manually configured. This is useful when it is used as a debug UART, for example.
Add a new field to hold this information, so that drivers can simply use the existing platform data.
Signed-off-by: Simon Glass sjg@chromium.org
include/ns16550.h | 4 ++++ 1 file changed, 4 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present the verbose flag only works for the 'build' command. This is not intended, nor is it useful. Update the code to support the verbose flag and make use of a command exception handler.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/control.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-)
diff --git a/tools/binman/control.py b/tools/binman/control.py index d1ca798cfb9..1d05bbb87ac 100644 --- a/tools/binman/control.py +++ b/tools/binman/control.py @@ -475,29 +475,23 @@ def Binman(args): from image import Image import state
- if args.cmd == 'ls': + if args.cmd in ['ls', 'extract', 'replace']: try: + tout.Init(args.verbosity) tools.PrepareOutputDir(None) - ListEntries(args.image, args.paths) - finally: - tools.FinaliseOutputDir() - return 0 - - if args.cmd == 'extract': - try: - tools.PrepareOutputDir(None) - ExtractEntries(args.image, args.filename, args.outdir, args.paths, - not args.uncompressed) - finally: - tools.FinaliseOutputDir() - return 0 - - if args.cmd == 'replace': - try: - tools.PrepareOutputDir(None) - ReplaceEntries(args.image, args.filename, args.indir, args.paths, - do_compress=not args.compressed, - allow_resize=not args.fix_size, write_map=args.map) + if args.cmd == 'ls': + ListEntries(args.image, args.paths) + + if args.cmd == 'extract': + ExtractEntries(args.image, args.filename, args.outdir, args.paths, + not args.uncompressed) + + if args.cmd == 'replace': + ReplaceEntries(args.image, args.filename, args.indir, args.paths, + do_compress=not args.compressed, + allow_resize=not args.fix_size, write_map=args.map) + except: + raise finally: tools.FinaliseOutputDir() return 0

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present the verbose flag only works for the 'build' command. This is not intended, nor is it useful. Update the code to support the verbose flag and make use of a command exception handler.
Signed-off-by: Simon Glass sjg@chromium.org
tools/binman/control.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 9:12 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present the verbose flag only works for the 'build' command. This is not intended, nor is it useful. Update the code to support the verbose flag and make use of a command exception handler.
Signed-off-by: Simon Glass sjg@chromium.org
tools/binman/control.py | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Rebased the patch against u-boot-x86/next to get it applied cleanly, and
applied to u-boot-x86/next, thanks!

At present this function is not present in the Entry base class so it is hard to find the documentation for it. Move the docs from the section class and expand it a little.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/entry.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 04c26f9e505..0e82065c291 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -720,6 +720,22 @@ features to produce new behaviours. data = self.section.ReadChildData(self, decomp) return data
+ def ReadChildData(self, child, decomp=True): + """Read the data for a particular child + + This reads data from the parent and extracts the piece that relates to + the given child. + + Args: + child: Child to read (must be valid) + decomp: True to decompress any compressed data before returning it; + False to return the raw, uncompressed data + + Returns: + Data for the child (bytes) + """ + pass + def LoadData(self, decomp=True): data = self.ReadData(decomp) self.contents_size = len(data)

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this function is not present in the Entry base class so it is hard to find the documentation for it. Move the docs from the section class and expand it a little.
Signed-off-by: Simon Glass sjg@chromium.org
tools/binman/entry.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:41 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this function is not present in the Entry base class so it is hard to find the documentation for it. Move the docs from the section class and expand it a little.
Signed-off-by: Simon Glass sjg@chromium.org
tools/binman/entry.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Some x86 sections have special offsets which currently result in empty data being returned from the 'extract' command. Fix this by taking account of the skip-at-start property.
Add a little more debugging while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/entry.py | 6 ++++-- tools/binman/etype/section.py | 16 +++++----------- tools/binman/image.py | 2 ++ 3 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 0e82065c291..409c0dca934 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -717,17 +717,19 @@ features to produce new behaviours. """ # Use True here so that we get an uncompressed section to work from, # although compressed sections are currently not supported + tout.Debug("ReadChildData section '%s', entry '%s'" % + (self.section.GetPath(), self.GetPath())) data = self.section.ReadChildData(self, decomp) return data
def ReadChildData(self, child, decomp=True): - """Read the data for a particular child + """Read the data for a particular child entry
This reads data from the parent and extracts the piece that relates to the given child.
Args: - child: Child to read (must be valid) + child: Child entry to read data for (must be valid) decomp: True to decompress any compressed data before returning it; False to return the raw, uncompressed data
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index d39c6ad81ea..ab0c42cee04 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -508,18 +508,12 @@ class Entry_section(Entry): return data
def ReadChildData(self, child, decomp=True): - """Read the data for a particular child entry - - Args: - child: Child entry to read data for - decomp: True to return uncompressed data, False to leave the data - compressed if it is compressed - - Returns: - Data contents of entry - """ + tout.Debug("ReadChildData for child '%s'" % child.GetPath()) parent_data = self.ReadData(True) - data = parent_data[child.offset:child.offset + child.size] + offset = child.offset - self._skip_at_start + tout.Debug("Extract for child '%s': offset %#x, skip_at_start %#x, result %#x" % + (child.GetPath(), child.offset, self._skip_at_start, offset)) + data = parent_data[offset:offset + child.size] if decomp: indata = data data = tools.Decompress(indata, child.compress) diff --git a/tools/binman/image.py b/tools/binman/image.py index 7b39a1ddcec..2beab7fd4d2 100644 --- a/tools/binman/image.py +++ b/tools/binman/image.py @@ -201,6 +201,8 @@ class Image(section.Entry_section): return entry
def ReadData(self, decomp=True): + tout.Debug("Image '%s' ReadData(), size=%#x" % + (self.GetPath(), len(self._data))) return self._data
def GetListEntries(self, entry_paths):

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Some x86 sections have special offsets which currently result in empty data being returned from the 'extract' command. Fix this by taking account of the skip-at-start property.
Add a little more debugging while we are here.
Signed-off-by: Simon Glass sjg@chromium.org
tools/binman/entry.py | 6 ++++-- tools/binman/etype/section.py | 16 +++++----------- tools/binman/image.py | 2 ++ 3 files changed, 11 insertions(+), 13 deletions(-)
Acked-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:42 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Some x86 sections have special offsets which currently result in empty data being returned from the 'extract' command. Fix this by taking account of the skip-at-start property.
Add a little more debugging while we are here.
Signed-off-by: Simon Glass sjg@chromium.org
tools/binman/entry.py | 6 ++++-- tools/binman/etype/section.py | 16 +++++----------- tools/binman/image.py | 2 ++ 3 files changed, 11 insertions(+), 13 deletions(-)
Acked-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

The image-header currently sets it offset assuming that skip-at-start is zero. This does not work on x86 where offsets end at 4GB. Add in this value so that the offset is correct.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/binman/etype/image_header.py | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/binman/etype/image_header.py b/tools/binman/etype/image_header.py index 4b69eda1a22..b9327dd799b 100644 --- a/tools/binman/etype/image_header.py +++ b/tools/binman/etype/image_header.py @@ -100,6 +100,7 @@ class Entry_image_header(Entry): offset = offset else: offset = image_size - IMAGE_HEADER_LEN + offset += self.section.GetStartOffset() return Entry.Pack(self, offset)
def ProcessContents(self):

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The image-header currently sets it offset assuming that skip-at-start is zero. This does not work on x86 where offsets end at 4GB. Add in this value so that the offset is correct.
Signed-off-by: Simon Glass sjg@chromium.org
tools/binman/etype/image_header.py | 1 + 1 file changed, 1 insertion(+)
Acked-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:42 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The image-header currently sets it offset assuming that skip-at-start is zero. This does not work on x86 where offsets end at 4GB. Add in this value so that the offset is correct.
Signed-off-by: Simon Glass sjg@chromium.org
tools/binman/etype/image_header.py | 1 + 1 file changed, 1 insertion(+)
Acked-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

If a log statement includes a variable and logging is disabled, this can generate warnings about unused variables. Add a bit more complexity to the macros to avoid this for the common case.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/log.h | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-)
diff --git a/include/log.h b/include/log.h index 6d15e955d7e..d8f18a6afdf 100644 --- a/include/log.h +++ b/include/log.h @@ -76,6 +76,18 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, int line, const char *func, const char *fmt, ...) __attribute__ ((format (__printf__, 6, 7)));
+static inline int _log_nop(enum log_category_t cat, enum log_level_t level, + const char *file, int line, const char *func, + const char *fmt, ...) + __attribute__ ((format (__printf__, 6, 7))); + +static inline int _log_nop(enum log_category_t cat, enum log_level_t level, + const char *file, int line, const char *func, + const char *fmt, ...) +{ + return 0; +} + /* Define this at the top of a file to add a prefix to debug messages */ #ifndef pr_fmt #define pr_fmt(fmt) fmt @@ -101,13 +113,14 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, #define log_io(_fmt...) log(LOG_CATEGORY, LOGL_DEBUG_IO, ##_fmt) #else #define _LOG_MAX_LEVEL LOGL_INFO -#define log_err(_fmt...) -#define log_warning(_fmt...) -#define log_notice(_fmt...) -#define log_info(_fmt...) -#define log_debug(_fmt...) -#define log_content(_fmt...) -#define log_io(_fmt...) +#define log_err(_fmt...) log_nop(LOG_CATEGORY, LOGL_ERR, ##_fmt) +#define log_warning(_fmt...) log_nop(LOG_CATEGORY, LOGL_WARNING, ##_fmt) +#define log_notice(_fmt...) log_nop(LOG_CATEGORY, LOGL_NOTICE, ##_fmt) +#define log_info(_fmt...) log_nop(LOG_CATEGORY, LOGL_INFO, ##_fmt) +#define log_debug(_fmt...) log_nop(LOG_CATEGORY, LOGL_DEBUG, ##_fmt) +#define log_content(_fmt...) log_nop(LOG_CATEGORY, \ + LOGL_DEBUG_CONTENT, ##_fmt) +#define log_io(_fmt...) log_nop(LOG_CATEGORY, LOGL_DEBUG_IO, ##_fmt) #endif
#if CONFIG_IS_ENABLED(LOG) @@ -129,6 +142,12 @@ int _log(enum log_category_t cat, enum log_level_t level, const char *file, #define log(_cat, _level, _fmt, _args...) #endif
+#define log_nop(_cat, _level, _fmt, _args...) ({ \ + int _l = _level; \ + _log_nop((enum log_category_t)(_cat), _l, __FILE__, __LINE__, \ + __func__, pr_fmt(_fmt), ##_args); \ +}) + #ifdef DEBUG #define _DEBUG 1 #else

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
If a log statement includes a variable and logging is disabled, this can generate warnings about unused variables. Add a bit more complexity to the macros to avoid this for the common case.
Signed-off-by: Simon Glass sjg@chromium.org
include/log.h | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:42 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
If a log statement includes a variable and logging is disabled, this can generate warnings about unused variables. Add a bit more complexity to the macros to avoid this for the common case.
Signed-off-by: Simon Glass sjg@chromium.org
include/log.h | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Provide these values which are part of the EC interface now.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/ec_commands.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/include/ec_commands.h b/include/ec_commands.h index 392c1f1a43a..444ba61e591 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -71,6 +71,10 @@ #define EC_LPC_CMDR_SCI (1 << 5) /* SCI event is pending */ #define EC_LPC_CMDR_SMI (1 << 6) /* SMI event is pending */
+/* MEC uses 0x800/0x804 as register/index pair, thus an 8-byte resource */ +#define MEC_EMI_BASE 0x800 +#define MEC_EMI_SIZE 8 + #define EC_LPC_ADDR_MEMMAP 0x900 #define EC_MEMMAP_SIZE 255 /* ACPI IO buffer max is 255 bytes */ #define EC_MEMMAP_TEXT_MAX 8 /* Size of a string in the memory map */

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Provide these values which are part of the EC interface now.
Signed-off-by: Simon Glass sjg@chromium.org
include/ec_commands.h | 4 ++++ 1 file changed, 4 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 10:42 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Provide these values which are part of the EC interface now.
Signed-off-by: Simon Glass sjg@chromium.org
include/ec_commands.h | 4 ++++ 1 file changed, 4 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present the 'iod' command differs from 'md' in that it only shows a single value. It is useful to see a dump of multiple values, particularly when x86 peripherals contain register sets accessible via I/O ports.
Enhance the command to match md.
Signed-off-by: Simon Glass sjg@chromium.org ---
cmd/io.c | 84 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 19 deletions(-)
diff --git a/cmd/io.c b/cmd/io.c index 79faf814ff7..2021a44b10f 100644 --- a/cmd/io.c +++ b/cmd/io.c @@ -11,6 +11,15 @@ #include <command.h> #include <asm/io.h>
+/* Display values from last command. + * Memory modify remembered values are different from display memory. + */ +static ulong last_addr, last_size; +static ulong last_length = 0x40; +static ulong base_address; + +#define DISP_LINE_LEN 16 + /* * IO Display * @@ -19,26 +28,63 @@ */ int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { - ulong addr; - int size; - - if (argc != 2) + ulong addr, length, bytes; + u8 buf[DISP_LINE_LEN]; + int size, todo; + + /* We use the last specified parameters, unless new ones are + * entered. + */ + addr = last_addr; + size = last_size; + length = last_length; + + if (argc < 2) return CMD_RET_USAGE;
- size = cmd_get_data_size(argv[0], 4); - if (size < 0) - return 1; - - addr = simple_strtoul(argv[1], NULL, 16); - - printf("%04x: ", (u16) addr); - - if (size == 4) - printf("%08x\n", inl(addr)); - else if (size == 2) - printf("%04x\n", inw(addr)); - else - printf("%02x\n", inb(addr)); + if ((flag & CMD_FLAG_REPEAT) == 0) { + /* New command specified. Check for a size specification. + * Defaults to long if no or incorrect specification. + */ + size = cmd_get_data_size(argv[0], 4); + if (size < 0) + return 1; + + /* Address is specified since argc > 1 */ + addr = simple_strtoul(argv[1], NULL, 16); + addr += base_address; + + /* If another parameter, it is the length to display. + * Length is the number of objects, not number of bytes. + */ + if (argc > 2) + length = simple_strtoul(argv[2], NULL, 16); + } + + bytes = size * length; + + /* Print the lines */ + for (; bytes > 0; addr += todo) { + u8 *ptr = buf; + int i; + + todo = min(bytes, (ulong)DISP_LINE_LEN); + for (i = 0; i < todo; i += size, ptr += size) { + if (size == 4) + *(u32 *)ptr = inl(addr + i); + else if (size == 2) + *(u16 *)ptr = inw(addr + i); + else + *ptr = inb(addr + i); + } + print_buffer(addr, buf, size, todo / size, + DISP_LINE_LEN / size); + bytes -= todo; + } + + last_addr = addr; + last_length = length; + last_size = size;
return 0; } @@ -69,7 +115,7 @@ int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) }
/**************************************************/ -U_BOOT_CMD(iod, 2, 0, do_io_iod, +U_BOOT_CMD(iod, 3, 1, do_io_iod, "IO space display", "[.b, .w, .l] address");
U_BOOT_CMD(iow, 3, 0, do_io_iow,

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present the 'iod' command differs from 'md' in that it only shows a single value. It is useful to see a dump of multiple values, particularly when x86 peripherals contain register sets accessible via I/O ports.
Enhance the command to match md.
Signed-off-by: Simon Glass sjg@chromium.org
cmd/io.c | 84 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 19 deletions(-)
diff --git a/cmd/io.c b/cmd/io.c index 79faf814ff7..2021a44b10f 100644 --- a/cmd/io.c +++ b/cmd/io.c @@ -11,6 +11,15 @@ #include <command.h> #include <asm/io.h>
+/* Display values from last command.
nits: wrong multi-line comment format
- Memory modify remembered values are different from display memory.
This comment does not apply as there is no "memory modify" in this context.
- */
+static ulong last_addr, last_size; +static ulong last_length = 0x40; +static ulong base_address;
+#define DISP_LINE_LEN 16
/*
- IO Display
@@ -19,26 +28,63 @@ */ int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) {
ulong addr;
int size;
if (argc != 2)
ulong addr, length, bytes;
u8 buf[DISP_LINE_LEN];
int size, todo;
/* We use the last specified parameters, unless new ones are
nits: wrong multi-line comment format
* entered.
*/
addr = last_addr;
size = last_size;
length = last_length;
if (argc < 2) return CMD_RET_USAGE;
size = cmd_get_data_size(argv[0], 4);
if (size < 0)
return 1;
addr = simple_strtoul(argv[1], NULL, 16);
printf("%04x: ", (u16) addr);
if (size == 4)
printf("%08x\n", inl(addr));
else if (size == 2)
printf("%04x\n", inw(addr));
else
printf("%02x\n", inb(addr));
if ((flag & CMD_FLAG_REPEAT) == 0) {
/* New command specified. Check for a size specification.
nits: wrong multi-line comment format
* Defaults to long if no or incorrect specification.
*/
size = cmd_get_data_size(argv[0], 4);
if (size < 0)
return 1;
/* Address is specified since argc > 1 */
addr = simple_strtoul(argv[1], NULL, 16);
addr += base_address;
/* If another parameter, it is the length to display.
nits: wrong multi-line comment format
* Length is the number of objects, not number of bytes.
*/
if (argc > 2)
length = simple_strtoul(argv[2], NULL, 16);
}
bytes = size * length;
/* Print the lines */
for (; bytes > 0; addr += todo) {
u8 *ptr = buf;
int i;
todo = min(bytes, (ulong)DISP_LINE_LEN);
for (i = 0; i < todo; i += size, ptr += size) {
if (size == 4)
*(u32 *)ptr = inl(addr + i);
else if (size == 2)
*(u16 *)ptr = inw(addr + i);
else
*ptr = inb(addr + i);
}
print_buffer(addr, buf, size, todo / size,
DISP_LINE_LEN / size);
bytes -= todo;
}
last_addr = addr;
last_length = length;
last_size = size; return 0;
} @@ -69,7 +115,7 @@ int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) }
/**************************************************/ -U_BOOT_CMD(iod, 2, 0, do_io_iod, +U_BOOT_CMD(iod, 3, 1, do_io_iod, "IO space display", "[.b, .w, .l] address");
U_BOOT_CMD(iow, 3, 0, do_io_iow,
Other than above issues,
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:18 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present the 'iod' command differs from 'md' in that it only shows a single value. It is useful to see a dump of multiple values, particularly when x86 peripherals contain register sets accessible via I/O ports.
Enhance the command to match md.
Signed-off-by: Simon Glass sjg@chromium.org
cmd/io.c | 84 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 19 deletions(-)
diff --git a/cmd/io.c b/cmd/io.c index 79faf814ff7..2021a44b10f 100644 --- a/cmd/io.c +++ b/cmd/io.c @@ -11,6 +11,15 @@ #include <command.h> #include <asm/io.h>
+/* Display values from last command.
nits: wrong multi-line comment format
- Memory modify remembered values are different from display memory.
This comment does not apply as there is no "memory modify" in this context.
- */
+static ulong last_addr, last_size; +static ulong last_length = 0x40; +static ulong base_address;
+#define DISP_LINE_LEN 16
/*
- IO Display
@@ -19,26 +28,63 @@ */ int do_io_iod(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) {
ulong addr;
int size;
if (argc != 2)
ulong addr, length, bytes;
u8 buf[DISP_LINE_LEN];
int size, todo;
/* We use the last specified parameters, unless new ones are
nits: wrong multi-line comment format
* entered.
*/
addr = last_addr;
size = last_size;
length = last_length;
if (argc < 2) return CMD_RET_USAGE;
size = cmd_get_data_size(argv[0], 4);
if (size < 0)
return 1;
addr = simple_strtoul(argv[1], NULL, 16);
printf("%04x: ", (u16) addr);
if (size == 4)
printf("%08x\n", inl(addr));
else if (size == 2)
printf("%04x\n", inw(addr));
else
printf("%02x\n", inb(addr));
if ((flag & CMD_FLAG_REPEAT) == 0) {
/* New command specified. Check for a size specification.
nits: wrong multi-line comment format
* Defaults to long if no or incorrect specification.
*/
size = cmd_get_data_size(argv[0], 4);
if (size < 0)
return 1;
/* Address is specified since argc > 1 */
addr = simple_strtoul(argv[1], NULL, 16);
addr += base_address;
/* If another parameter, it is the length to display.
nits: wrong multi-line comment format
Corrected these wrong multi-line comment format, and
* Length is the number of objects, not number of bytes.
*/
if (argc > 2)
length = simple_strtoul(argv[2], NULL, 16);
}
bytes = size * length;
/* Print the lines */
for (; bytes > 0; addr += todo) {
u8 *ptr = buf;
int i;
todo = min(bytes, (ulong)DISP_LINE_LEN);
for (i = 0; i < todo; i += size, ptr += size) {
if (size == 4)
*(u32 *)ptr = inl(addr + i);
else if (size == 2)
*(u16 *)ptr = inw(addr + i);
else
*ptr = inb(addr + i);
}
print_buffer(addr, buf, size, todo / size,
DISP_LINE_LEN / size);
bytes -= todo;
}
last_addr = addr;
last_length = length;
last_size = size; return 0;
} @@ -69,7 +115,7 @@ int do_io_iow(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) }
/**************************************************/ -U_BOOT_CMD(iod, 2, 0, do_io_iod, +U_BOOT_CMD(iod, 3, 1, do_io_iod, "IO space display", "[.b, .w, .l] address");
U_BOOT_CMD(iow, 3, 0, do_io_iow,
Other than above issues,
Reviewed-by: Bin Meng bmeng.cn@gmail.com Tested-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present this is defined in Kconfig but there is a separate one in the CONFIG whitelist. It looks like these are duplicates.
Rename the non-Kconfig one and remove it from the whitelist.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/arm926ejs/Makefile | 2 +- include/configs/mxs.h | 2 +- scripts/config_whitelist.txt | 1 - 3 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/arch/arm/cpu/arm926ejs/Makefile b/arch/arm/cpu/arm926ejs/Makefile index fdb0c926fb2..b051025bb0a 100644 --- a/arch/arm/cpu/arm926ejs/Makefile +++ b/arch/arm/cpu/arm926ejs/Makefile @@ -7,7 +7,7 @@ extra-y = start.o obj-y = cpu.o cache.o
ifdef CONFIG_SPL_BUILD -ifdef CONFIG_SPL_NO_CPU_SUPPORT_CODE +ifdef CONFIG_SPL_NO_CPU_SUPPORT extra-y := endif endif diff --git a/include/configs/mxs.h b/include/configs/mxs.h index 6cadd720d2b..e079f8035b8 100644 --- a/include/configs/mxs.h +++ b/include/configs/mxs.h @@ -45,7 +45,7 @@
/* SPL */ #ifndef CONFIG_SPL_FRAMEWORK -#define CONFIG_SPL_NO_CPU_SUPPORT_CODE +#define CONFIG_SPL_NO_CPU_SUPPORT #define CONFIG_SPL_START_S_PATH "arch/arm/cpu/arm926ejs/mxs" #endif
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index b06a77ebd66..169f98752be 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1728,7 +1728,6 @@ CONFIG_SPL_NAND_MINIMAL CONFIG_SPL_NAND_RAW_ONLY CONFIG_SPL_NAND_SOFTECC CONFIG_SPL_NAND_WORKSPACE -CONFIG_SPL_NO_CPU_SUPPORT_CODE CONFIG_SPL_PAD_TO CONFIG_SPL_PANIC_ON_RAW_IMAGE CONFIG_SPL_PBL_PAD

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this is defined in Kconfig but there is a separate one in the CONFIG whitelist. It looks like these are duplicates.
Rename the non-Kconfig one and remove it from the whitelist.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/cpu/arm926ejs/Makefile | 2 +- include/configs/mxs.h | 2 +- scripts/config_whitelist.txt | 1 - 3 files changed, 2 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:18 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this is defined in Kconfig but there is a separate one in the CONFIG whitelist. It looks like these are duplicates.
Rename the non-Kconfig one and remove it from the whitelist.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/cpu/arm926ejs/Makefile | 2 +- include/configs/mxs.h | 2 +- scripts/config_whitelist.txt | 1 - 3 files changed, 2 insertions(+), 3 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present there is only one control for this and it is used for both SPL and TPL. But SPL might have a lot more space than TPL so the extra cost of a full printf() might be acceptable.
Split the option into two, providing separate SPL and TPL controls. The TPL setting defaults to the same as SPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/Kconfig | 2 +- arch/arm/mach-omap2/Kconfig | 6 +++--- arch/arm/mach-rmobile/Kconfig | 2 +- arch/arm/mach-rmobile/Kconfig.32 | 14 ++++++------- arch/arm/mach-socfpga/Kconfig | 4 ++-- common/spl/Kconfig | 2 +- common/xyzModem.c | 2 +- configs/am335x_pdu001_defconfig | 2 +- configs/ls1043ardb_nand_SECURE_BOOT_defconfig | 2 +- configs/ls1043ardb_nand_defconfig | 2 +- .../ls1043ardb_sdcard_SECURE_BOOT_defconfig | 2 +- configs/ls1043ardb_sdcard_defconfig | 2 +- configs/sandbox_spl_defconfig | 2 +- drivers/gpio/gpio-uclass.c | 4 ++-- drivers/mmc/mmc.c | 2 +- drivers/mtd/spi/sf-uclass.c | 2 +- lib/Kconfig | 20 +++++++++++++++---- lib/Makefile | 2 +- 18 files changed, 43 insertions(+), 31 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3b0e315061a..7086db368fb 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -954,7 +954,7 @@ config ARCH_SUNXI select USB if DISTRO_DEFAULTS select USB_KEYBOARD if DISTRO_DEFAULTS select USB_STORAGE if DISTRO_DEFAULTS - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply CMD_DM imply CMD_GPT imply CMD_UBI if NAND diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index ed8056e8718..4c87cbc00f7 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -11,7 +11,7 @@ config OMAP34XX select ARM_ERRATA_454179 select ARM_ERRATA_621766 select ARM_ERRATA_725233 - select USE_TINY_PRINTF if SPL + select SPL_USE_TINY_PRINTF if SPL imply NAND_OMAP_GPMC imply SPL_FS_EXT4 imply SPL_FS_FAT @@ -31,7 +31,7 @@ config OMAP34XX
config OMAP44XX bool "OMAP44XX SoC" - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply NAND_OMAP_ELM imply NAND_OMAP_GPMC imply SPL_DISPLAY_PRINT @@ -124,7 +124,7 @@ config AM33XX imply SPL_NAND_SUPPORT imply SYS_I2C_OMAP24XX imply SYS_THUMB_BUILD - imply USE_TINY_PRINTF + imply SPL_USE_TINY_PRINTF help Support for AM335x SOC from Texas Instruments. The AM335x high performance SOC features a Cortex-A8 diff --git a/arch/arm/mach-rmobile/Kconfig b/arch/arm/mach-rmobile/Kconfig index 52ab8914257..8343000c8fa 100644 --- a/arch/arm/mach-rmobile/Kconfig +++ b/arch/arm/mach-rmobile/Kconfig @@ -32,7 +32,7 @@ config RCAR_GEN3 imply SPL_SYS_MALLOC_SIMPLE imply SPL_TINY_MEMSET imply SPL_YMODEM_SUPPORT - imply USE_TINY_PRINTF + imply SPL_USE_TINY_PRINTF
config RZA1 prompt "Renesas ARM SoCs RZ/A1 (32bit)" diff --git a/arch/arm/mach-rmobile/Kconfig.32 b/arch/arm/mach-rmobile/Kconfig.32 index 1441c806920..d5e437f0d2e 100644 --- a/arch/arm/mach-rmobile/Kconfig.32 +++ b/arch/arm/mach-rmobile/Kconfig.32 @@ -65,7 +65,7 @@ config TARGET_GOSE select DM_SERIAL select SPL_TINY_MEMSET select SUPPORT_SPL - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply CMD_DM
config TARGET_KOELSCH @@ -74,7 +74,7 @@ config TARGET_KOELSCH select DM_SERIAL select SPL_TINY_MEMSET select SUPPORT_SPL - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply CMD_DM
config TARGET_LAGER @@ -83,7 +83,7 @@ config TARGET_LAGER select DM_SERIAL select SPL_TINY_MEMSET select SUPPORT_SPL - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply CMD_DM
config TARGET_KZM9G @@ -95,7 +95,7 @@ config TARGET_ALT select DM_SERIAL select SPL_TINY_MEMSET select SUPPORT_SPL - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply CMD_DM
config TARGET_SILK @@ -104,7 +104,7 @@ config TARGET_SILK select DM_SERIAL select SPL_TINY_MEMSET select SUPPORT_SPL - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply CMD_DM
config TARGET_PORTER @@ -113,7 +113,7 @@ config TARGET_PORTER select DM_SERIAL select SPL_TINY_MEMSET select SUPPORT_SPL - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply CMD_DM
config TARGET_STOUT @@ -122,7 +122,7 @@ config TARGET_STOUT select DM_SERIAL select SPL_TINY_MEMSET select SUPPORT_SPL - select USE_TINY_PRINTF + select SPL_USE_TINY_PRINTF imply CMD_DM
endchoice diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index 1d914648e31..ee79953fcc2 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -45,7 +45,7 @@ config TARGET_SOCFPGA_ARRIA10 select SPL_SYSCON if SPL select ETH_DESIGNWARE_SOCFPGA imply FPGA_SOCFPGA - imply USE_TINY_PRINTF + imply SPL_USE_TINY_PRINTF
config TARGET_SOCFPGA_CYCLONE5 bool @@ -59,7 +59,7 @@ config TARGET_SOCFPGA_GEN5 imply SPL_SIZE_LIMIT_SUBTRACT_MALLOC imply SPL_STACK_R imply SPL_SYS_MALLOC_SIMPLE - imply USE_TINY_PRINTF + imply SPL_USE_TINY_PRINTF
config TARGET_SOCFPGA_STRATIX10 bool diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 62b93c112b1..048b85ba7a2 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -963,7 +963,7 @@ config SPL_SERIAL_SUPPORT for displaying messages while SPL is running. It also brings in printf() and panic() functions. This should normally be enabled unless there are space reasons not to. Even then, consider - enabling USE_TINY_PRINTF which is a small printf() version. + enabling SPL_USE_TINY_PRINTF which is a small printf() version.
config SPL_SPI_FLASH_SUPPORT bool "Support SPI flash drivers" diff --git a/common/xyzModem.c b/common/xyzModem.c index e85da74a698..6bf2375671d 100644 --- a/common/xyzModem.c +++ b/common/xyzModem.c @@ -173,7 +173,7 @@ parse_num (char *s, unsigned long *val, char **es, char *delim) }
-#if defined(DEBUG) && !defined(CONFIG_USE_TINY_PRINTF) +#if defined(DEBUG) && !CONFIG_IS_ENABLED(USE_TINY_PRINTF) /* * Note: this debug setup works by storing the strings in a fixed buffer */ diff --git a/configs/am335x_pdu001_defconfig b/configs/am335x_pdu001_defconfig index e69f81b6e54..1a1d58d3cc8 100644 --- a/configs/am335x_pdu001_defconfig +++ b/configs/am335x_pdu001_defconfig @@ -51,5 +51,5 @@ CONFIG_SPL_DM_REGULATOR=y CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_TPS65910=y CONFIG_CONS_INDEX=4 -# CONFIG_USE_TINY_PRINTF is not set +# CONFIG_SPL_USE_TINY_PRINTF is not set # CONFIG_EFI_LOADER is not set diff --git a/configs/ls1043ardb_nand_SECURE_BOOT_defconfig b/configs/ls1043ardb_nand_SECURE_BOOT_defconfig index 7aa8c54a128..c45fc68ac3f 100644 --- a/configs/ls1043ardb_nand_SECURE_BOOT_defconfig +++ b/configs/ls1043ardb_nand_SECURE_BOOT_defconfig @@ -67,7 +67,7 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -# CONFIG_USE_TINY_PRINTF is not set +# CONFIG_SPL_USE_TINY_PRINTF is not set CONFIG_RSA=y CONFIG_SPL_RSA=y CONFIG_EFI_LOADER_BOUNCE_BUFFER=y diff --git a/configs/ls1043ardb_nand_defconfig b/configs/ls1043ardb_nand_defconfig index 22ccf526f69..a9e58047acc 100644 --- a/configs/ls1043ardb_nand_defconfig +++ b/configs/ls1043ardb_nand_defconfig @@ -67,5 +67,5 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -# CONFIG_USE_TINY_PRINTF is not set +# CONFIG_SPL_USE_TINY_PRINTF is not set CONFIG_EFI_LOADER_BOUNCE_BUFFER=y diff --git a/configs/ls1043ardb_sdcard_SECURE_BOOT_defconfig b/configs/ls1043ardb_sdcard_SECURE_BOOT_defconfig index 486a2e089b7..bdfa13a0a71 100644 --- a/configs/ls1043ardb_sdcard_SECURE_BOOT_defconfig +++ b/configs/ls1043ardb_sdcard_SECURE_BOOT_defconfig @@ -65,7 +65,7 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -# CONFIG_USE_TINY_PRINTF is not set +# CONFIG_SPL_USE_TINY_PRINTF is not set CONFIG_RSA=y CONFIG_SPL_RSA=y CONFIG_EFI_LOADER_BOUNCE_BUFFER=y diff --git a/configs/ls1043ardb_sdcard_defconfig b/configs/ls1043ardb_sdcard_defconfig index b3c2970207c..01adbf0b192 100644 --- a/configs/ls1043ardb_sdcard_defconfig +++ b/configs/ls1043ardb_sdcard_defconfig @@ -65,5 +65,5 @@ CONFIG_USB=y CONFIG_DM_USB=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_DWC3=y -# CONFIG_USE_TINY_PRINTF is not set +# CONFIG_SPL_USE_TINY_PRINTF is not set CONFIG_EFI_LOADER_BOUNCE_BUFFER=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 0b3391a2a6b..409b8a38d5e 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -191,7 +191,7 @@ CONFIG_OSD=y CONFIG_SANDBOX_OSD=y CONFIG_FS_CBFS=y CONFIG_FS_CRAMFS=y -# CONFIG_USE_TINY_PRINTF is not set +# CONFIG_SPL_USE_TINY_PRINTF is not set CONFIG_CMD_DHRYSTONE=y CONFIG_TPM=y CONFIG_LZ4=y diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 01cfa2f7884..90fbed455b8 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -294,7 +294,7 @@ int dm_gpio_request(struct gpio_desc *desc, const char *label)
static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...) { -#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_USE_TINY_PRINTF) +#if !defined(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(USE_TINY_PRINTF) va_list args; char buf[40];
@@ -343,7 +343,7 @@ int gpio_request(unsigned gpio, const char *label) */ int gpio_requestf(unsigned gpio, const char *fmt, ...) { -#if !defined(CONFIG_SPL_BUILD) || !defined(CONFIG_USE_TINY_PRINTF) +#if !defined(CONFIG_SPL_BUILD) || !CONFIG_IS_ENABLED(USE_TINY_PRINTF) va_list args; char buf[40];
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index c8f71cd0c1b..6bece7f3073 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -2577,7 +2577,7 @@ static int mmc_startup(struct mmc *mmc) bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); #if !defined(CONFIG_SPL_BUILD) || \ (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ - !defined(CONFIG_USE_TINY_PRINTF)) + !CONFIG_IS_ENABLED(USE_TINY_PRINTF)) sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), (mmc->cid[3] >> 16) & 0xffff); diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index 127ec7e7aa6..1751eccd99a 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -77,7 +77,7 @@ int spi_flash_probe_bus_cs(unsigned int busnum, unsigned int cs, char *str; int ret;
-#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_TINY_PRINTF) +#if defined(CONFIG_SPL_BUILD) && CONFIG_IS_ENABLED(USE_TINY_PRINTF) str = "spi_flash"; #else char name[30]; diff --git a/lib/Kconfig b/lib/Kconfig index 3da45a5ec32..135f0b372b0 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -40,12 +40,12 @@ config PRINTF config SPL_PRINTF bool select SPL_SPRINTF - select SPL_STRTO if !USE_TINY_PRINTF + select SPL_STRTO if !SPL_USE_TINY_PRINTF
config TPL_PRINTF bool select TPL_SPRINTF - select TPL_STRTO if !USE_TINY_PRINTF + select TPL_STRTO if !TPL_USE_TINY_PRINTF
config SPRINTF bool @@ -95,9 +95,9 @@ config SYS_HZ get_timer() must operate in milliseconds and this option must be set to 1000.
-config USE_TINY_PRINTF +config SPL_USE_TINY_PRINTF bool "Enable tiny printf() version" - depends on SPL || TPL + depends on SPL default y help This option enables a tiny, stripped down printf version. @@ -107,6 +107,18 @@ config USE_TINY_PRINTF
The supported format specifiers are %c, %s, %u/%d and %x.
+config TPL_USE_TINY_PRINTF + bool "Enable tiny printf() version" + depends on TPL + default y if SPL_USE_TINY_PRINTF + help + This option enables a tiny, stripped down printf version. + This should only be used in space limited environments, + like SPL versions with hard memory limits. This version + reduces the code size by about 2.5KiB on armv7. + + The supported format specifiers are %c, %s, %u/%d and %x. + config PANIC_HANG bool "Do not reset the system on fatal error" help diff --git a/lib/Makefile b/lib/Makefile index 2fffd68f943..d248d8626ce 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -106,7 +106,7 @@ obj-y += panic.o
ifeq ($(CONFIG_$(SPL_TPL_)BUILD),y) # SPL U-Boot may use full-printf, tiny-printf or none at all -ifdef CONFIG_USE_TINY_PRINTF +ifdef CONFIG_$(SPL_TPL_)USE_TINY_PRINTF obj-$(CONFIG_$(SPL_TPL_)SPRINTF) += tiny-printf.o else obj-$(CONFIG_$(SPL_TPL_)SPRINTF) += vsprintf.o strmhz.o

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present there is only one control for this and it is used for both SPL and TPL. But SPL might have a lot more space than TPL so the extra cost of a full printf() might be acceptable.
Split the option into two, providing separate SPL and TPL controls. The TPL setting defaults to the same as SPL.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/Kconfig | 2 +- arch/arm/mach-omap2/Kconfig | 6 +++--- arch/arm/mach-rmobile/Kconfig | 2 +- arch/arm/mach-rmobile/Kconfig.32 | 14 ++++++------- arch/arm/mach-socfpga/Kconfig | 4 ++-- common/spl/Kconfig | 2 +- common/xyzModem.c | 2 +- configs/am335x_pdu001_defconfig | 2 +- configs/ls1043ardb_nand_SECURE_BOOT_defconfig | 2 +- configs/ls1043ardb_nand_defconfig | 2 +- .../ls1043ardb_sdcard_SECURE_BOOT_defconfig | 2 +- configs/ls1043ardb_sdcard_defconfig | 2 +- configs/sandbox_spl_defconfig | 2 +- drivers/gpio/gpio-uclass.c | 4 ++-- drivers/mmc/mmc.c | 2 +- drivers/mtd/spi/sf-uclass.c | 2 +- lib/Kconfig | 20 +++++++++++++++---- lib/Makefile | 2 +- 18 files changed, 43 insertions(+), 31 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:18 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present there is only one control for this and it is used for both SPL and TPL. But SPL might have a lot more space than TPL so the extra cost of a full printf() might be acceptable.
Split the option into two, providing separate SPL and TPL controls. The TPL setting defaults to the same as SPL.
Signed-off-by: Simon Glass sjg@chromium.org
arch/arm/Kconfig | 2 +- arch/arm/mach-omap2/Kconfig | 6 +++--- arch/arm/mach-rmobile/Kconfig | 2 +- arch/arm/mach-rmobile/Kconfig.32 | 14 ++++++------- arch/arm/mach-socfpga/Kconfig | 4 ++-- common/spl/Kconfig | 2 +- common/xyzModem.c | 2 +- configs/am335x_pdu001_defconfig | 2 +- configs/ls1043ardb_nand_SECURE_BOOT_defconfig | 2 +- configs/ls1043ardb_nand_defconfig | 2 +- .../ls1043ardb_sdcard_SECURE_BOOT_defconfig | 2 +- configs/ls1043ardb_sdcard_defconfig | 2 +- configs/sandbox_spl_defconfig | 2 +- drivers/gpio/gpio-uclass.c | 4 ++-- drivers/mmc/mmc.c | 2 +- drivers/mtd/spi/sf-uclass.c | 2 +- lib/Kconfig | 20 +++++++++++++++---- lib/Makefile | 2 +- 18 files changed, 43 insertions(+), 31 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

This is currently a decimal value which is not as convenient or meaningful. Also U-Boot tends to use hex everywhere.
Convert this option to hex and add a comment for the size_check macro.
Signed-off-by: Simon Glass sjg@chromium.org ---
Makefile | 10 +++++++--- arch/arm/mach-socfpga/Kconfig | 2 +- common/spl/Kconfig | 2 +- configs/evb-rk3288_defconfig | 2 +- configs/tinker-rk3288_defconfig | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile index fd390e19458..a7a48b6aef3 100644 --- a/Makefile +++ b/Makefile @@ -337,14 +337,18 @@ endif # KBUILD_MODULES := 1 #endif
+# Check ths size of a binary: +# Args: +# $1: File to check +# #2: Size limit in bytes (decimal or 0xhex) define size_check actual=$$( wc -c $1 | awk '{print $$1}'); \ limit=$$( printf "%d" $2 ); \ if test $$actual -gt $$limit; then \ echo "$1 exceeds file size limit:" >&2; \ - echo " limit: $$limit bytes" >&2; \ - echo " actual: $$actual bytes" >&2; \ - echo " excess: $$((actual - limit)) bytes" >&2; \ + echo " limit: $$(printf %#x bytes $$limit) bytes" >&2; \ + echo " actual: $$(printf %#x $$actual) bytes" >&2; \ + echo " excess: $$(printf %#x $$((actual - limit))) bytes" >&2;\ exit 1; \ fi endef diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index ee79953fcc2..45de153aa5a 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -4,7 +4,7 @@ config NR_DRAM_BANKS default 1
config SPL_SIZE_LIMIT - default 65536 if TARGET_SOCFPGA_GEN5 + default 0x10000 if TARGET_SOCFPGA_GEN5
config SPL_SIZE_LIMIT_PROVIDE_STACK default 0x200 if TARGET_SOCFPGA_GEN5 diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 048b85ba7a2..ef4fb19e52c 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -26,7 +26,7 @@ config SPL_FRAMEWORK and the Linux Kernel. If unsure, say Y.
config SPL_SIZE_LIMIT - int "Maximum size of SPL image" + hex "Maximum size of SPL image" depends on SPL default 69632 if ARCH_MX6 default 0 diff --git a/configs/evb-rk3288_defconfig b/configs/evb-rk3288_defconfig index 7b0e908f715..043ee32bb44 100644 --- a/configs/evb-rk3288_defconfig +++ b/configs/evb-rk3288_defconfig @@ -4,7 +4,7 @@ CONFIG_SYS_TEXT_BASE=0x01000000 CONFIG_ROCKCHIP_RK3288=y CONFIG_TARGET_EVB_RK3288=y CONFIG_NR_DRAM_BANKS=1 -CONFIG_SPL_SIZE_LIMIT=307200 +CONFIG_SPL_SIZE_LIMIT=0x4b000 CONFIG_SPL_STACK_R_ADDR=0x80000 CONFIG_DEBUG_UART_BASE=0xff690000 CONFIG_DEBUG_UART_CLOCK=24000000 diff --git a/configs/tinker-rk3288_defconfig b/configs/tinker-rk3288_defconfig index 93286084525..eff3b06b5ce 100644 --- a/configs/tinker-rk3288_defconfig +++ b/configs/tinker-rk3288_defconfig @@ -5,7 +5,7 @@ CONFIG_SPL_GPIO_SUPPORT=y CONFIG_ROCKCHIP_RK3288=y CONFIG_TARGET_TINKER_RK3288=y CONFIG_NR_DRAM_BANKS=1 -CONFIG_SPL_SIZE_LIMIT=307200 +CONFIG_SPL_SIZE_LIMIT=0x4b000 CONFIG_SPL_STACK_R_ADDR=0x80000 CONFIG_DEBUG_UART_BASE=0xff690000 CONFIG_DEBUG_UART_CLOCK=24000000

You've got the config name wrong in the summary (forgot '_SIZE' in the middle).
On Wed, Sep 25, 2019 at 5:24 PM Simon Glass sjg@chromium.org wrote:
This is currently a decimal value which is not as convenient or meaningful. Also U-Boot tends to use hex everywhere.
Convert this option to hex and add a comment for the size_check macro.
Signed-off-by: Simon Glass sjg@chromium.org
Makefile | 10 +++++++--- arch/arm/mach-socfpga/Kconfig | 2 +-
I would have expected to be on CC for this file?
Otherwise: Reviewed-by: Simon Goldschmidt simon.k.r.goldschmidt@gmail.com
Regards, Simon
common/spl/Kconfig | 2 +- configs/evb-rk3288_defconfig | 2 +- configs/tinker-rk3288_defconfig | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile index fd390e19458..a7a48b6aef3 100644 --- a/Makefile +++ b/Makefile @@ -337,14 +337,18 @@ endif # KBUILD_MODULES := 1 #endif
+# Check ths size of a binary: +# Args: +# $1: File to check +# #2: Size limit in bytes (decimal or 0xhex) define size_check actual=$$( wc -c $1 | awk '{print $$1}'); \ limit=$$( printf "%d" $2 ); \ if test $$actual -gt $$limit; then \ echo "$1 exceeds file size limit:" >&2; \
echo " limit: $$limit bytes" >&2; \
echo " actual: $$actual bytes" >&2; \
echo " excess: $$((actual - limit)) bytes" >&2; \
echo " limit: $$(printf %#x bytes $$limit) bytes" >&2; \
echo " actual: $$(printf %#x $$actual) bytes" >&2; \
echo " excess: $$(printf %#x $$((actual - limit))) bytes" >&2;\ exit 1; \ fi
endef diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index ee79953fcc2..45de153aa5a 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -4,7 +4,7 @@ config NR_DRAM_BANKS default 1
config SPL_SIZE_LIMIT
default 65536 if TARGET_SOCFPGA_GEN5
default 0x10000 if TARGET_SOCFPGA_GEN5
config SPL_SIZE_LIMIT_PROVIDE_STACK default 0x200 if TARGET_SOCFPGA_GEN5 diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 048b85ba7a2..ef4fb19e52c 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -26,7 +26,7 @@ config SPL_FRAMEWORK and the Linux Kernel. If unsure, say Y.
config SPL_SIZE_LIMIT
int "Maximum size of SPL image"
hex "Maximum size of SPL image" depends on SPL default 69632 if ARCH_MX6 default 0
diff --git a/configs/evb-rk3288_defconfig b/configs/evb-rk3288_defconfig index 7b0e908f715..043ee32bb44 100644 --- a/configs/evb-rk3288_defconfig +++ b/configs/evb-rk3288_defconfig @@ -4,7 +4,7 @@ CONFIG_SYS_TEXT_BASE=0x01000000 CONFIG_ROCKCHIP_RK3288=y CONFIG_TARGET_EVB_RK3288=y CONFIG_NR_DRAM_BANKS=1 -CONFIG_SPL_SIZE_LIMIT=307200 +CONFIG_SPL_SIZE_LIMIT=0x4b000 CONFIG_SPL_STACK_R_ADDR=0x80000 CONFIG_DEBUG_UART_BASE=0xff690000 CONFIG_DEBUG_UART_CLOCK=24000000 diff --git a/configs/tinker-rk3288_defconfig b/configs/tinker-rk3288_defconfig index 93286084525..eff3b06b5ce 100644 --- a/configs/tinker-rk3288_defconfig +++ b/configs/tinker-rk3288_defconfig @@ -5,7 +5,7 @@ CONFIG_SPL_GPIO_SUPPORT=y CONFIG_ROCKCHIP_RK3288=y CONFIG_TARGET_TINKER_RK3288=y CONFIG_NR_DRAM_BANKS=1 -CONFIG_SPL_SIZE_LIMIT=307200 +CONFIG_SPL_SIZE_LIMIT=0x4b000 CONFIG_SPL_STACK_R_ADDR=0x80000 CONFIG_DEBUG_UART_BASE=0xff690000 CONFIG_DEBUG_UART_CLOCK=24000000 -- 2.23.0.444.g18eeb5a265-goog
U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This is currently a decimal value which is not as convenient or meaningful. Also U-Boot tends to use hex everywhere.
Convert this option to hex and add a comment for the size_check macro.
Signed-off-by: Simon Glass sjg@chromium.org
Makefile | 10 +++++++--- arch/arm/mach-socfpga/Kconfig | 2 +- common/spl/Kconfig | 2 +- configs/evb-rk3288_defconfig | 2 +- configs/tinker-rk3288_defconfig | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-)
Acked-by: Bin Meng bmeng.cn@gmail.com
I can fix the commit summary issue (missing _SIZE, as pointed out by Simon Goldschmidt) when applying.

On Sat, Oct 5, 2019 at 11:18 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This is currently a decimal value which is not as convenient or meaningful. Also U-Boot tends to use hex everywhere.
Convert this option to hex and add a comment for the size_check macro.
Signed-off-by: Simon Glass sjg@chromium.org
Makefile | 10 +++++++--- arch/arm/mach-socfpga/Kconfig | 2 +- common/spl/Kconfig | 2 +- configs/evb-rk3288_defconfig | 2 +- configs/tinker-rk3288_defconfig | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-)
Acked-by: Bin Meng bmeng.cn@gmail.com
I can fix the commit summary issue (missing _SIZE, as pointed out by Simon Goldschmidt) when applying.
Fixed the typo in the commit title, and
applied to u-boot-x86/next, thanks!

We have the ability to enforce a maximum size for SPL but not yet for TPL. Add a new option for this.
Document the size check macro while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
Makefile | 7 +++++++ common/spl/Kconfig | 8 ++++++++ 2 files changed, 15 insertions(+)
diff --git a/Makefile b/Makefile index a7a48b6aef3..43961af590f 100644 --- a/Makefile +++ b/Makefile @@ -806,6 +806,12 @@ else SPL_SIZE_CHECK = endif
+ifneq ($(CONFIG_TPL_SIZE_LIMIT),0) +TPL_SIZE_CHECK = @$(call size_check,$@,$(CONFIG_TPL_SIZE_LIMIT)) +else +TPL_SIZE_CHECK = +endif + # Statically apply RELA-style relocations (currently arm64 only) # This is useful for arm64 where static relocation needs to be performed on # the raw binary, but certain simulators only accept an ELF file (but don't @@ -1786,6 +1792,7 @@ spl/boot.bin: spl/u-boot-spl tpl/u-boot-tpl.bin: tools prepare \ $(if $(CONFIG_OF_SEPARATE)$(CONFIG_OF_EMBED)$(CONFIG_SPL_OF_PLATDATA),dts/dt.dtb) $(Q)$(MAKE) obj=tpl -f $(srctree)/scripts/Makefile.spl all + $(TPL_SIZE_CHECK)
TAG_SUBDIRS := $(patsubst %,$(srctree)/%,$(u-boot-dirs) include)
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index ef4fb19e52c..b6d7bc81802 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1183,6 +1183,14 @@ config TPL
if TPL
+config TPL_SIZE_LIMIT + hex "Maximum size of TPL image" + depends on TPL + default 0 + help + Specifies the maximum length of the U-Boot TPL image. + If this value is zero, it is ignored. + config TPL_HANDOFF bool "Pass hand-off information from TPL to SPL and U-Boot proper" depends on HANDOFF && TPL_BLOBLIST

Hi Simon,
On Wed, Sep 25, 2019 at 5:36 PM Simon Glass sjg@chromium.org wrote:
We have the ability to enforce a maximum size for SPL but not yet for TPL. Add a new option for this.
Document the size check macro while we are here.
Signed-off-by: Simon Glass sjg@chromium.org
Makefile | 7 +++++++ common/spl/Kconfig | 8 ++++++++ 2 files changed, 15 insertions(+)
diff --git a/Makefile b/Makefile index a7a48b6aef3..43961af590f 100644 --- a/Makefile +++ b/Makefile @@ -806,6 +806,12 @@ else SPL_SIZE_CHECK = endif
+ifneq ($(CONFIG_TPL_SIZE_LIMIT),0) +TPL_SIZE_CHECK = @$(call size_check,$@,$(CONFIG_TPL_SIZE_LIMIT))
Using a constant here is not what SPL does by now: some months ago, I implemented a more sophisticated size check for SPL that also integrates 'gd', stack and heap usage into the size check. Wouldn't that be required for TPL as well (at least on platforms where everything must fit into SRAM)?
Regards, Simon
+else +TPL_SIZE_CHECK = +endif
# Statically apply RELA-style relocations (currently arm64 only) # This is useful for arm64 where static relocation needs to be performed on # the raw binary, but certain simulators only accept an ELF file (but don't @@ -1786,6 +1792,7 @@ spl/boot.bin: spl/u-boot-spl tpl/u-boot-tpl.bin: tools prepare \ $(if $(CONFIG_OF_SEPARATE)$(CONFIG_OF_EMBED)$(CONFIG_SPL_OF_PLATDATA),dts/dt.dtb) $(Q)$(MAKE) obj=tpl -f $(srctree)/scripts/Makefile.spl all
$(TPL_SIZE_CHECK)
TAG_SUBDIRS := $(patsubst %,$(srctree)/%,$(u-boot-dirs) include)
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index ef4fb19e52c..b6d7bc81802 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -1183,6 +1183,14 @@ config TPL
if TPL
+config TPL_SIZE_LIMIT
hex "Maximum size of TPL image"
depends on TPL
default 0
help
Specifies the maximum length of the U-Boot TPL image.
If this value is zero, it is ignored.
config TPL_HANDOFF bool "Pass hand-off information from TPL to SPL and U-Boot proper" depends on HANDOFF && TPL_BLOBLIST -- 2.23.0.444.g18eeb5a265-goog

Hi Simon,
On Thu, 26 Sep 2019 at 06:23, Simon Goldschmidt simon.k.r.goldschmidt@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 5:36 PM Simon Glass sjg@chromium.org wrote:
We have the ability to enforce a maximum size for SPL but not yet for TPL. Add a new option for this.
Document the size check macro while we are here.
Signed-off-by: Simon Glass sjg@chromium.org
Makefile | 7 +++++++ common/spl/Kconfig | 8 ++++++++ 2 files changed, 15 insertions(+)
diff --git a/Makefile b/Makefile index a7a48b6aef3..43961af590f 100644 --- a/Makefile +++ b/Makefile @@ -806,6 +806,12 @@ else SPL_SIZE_CHECK = endif
+ifneq ($(CONFIG_TPL_SIZE_LIMIT),0) +TPL_SIZE_CHECK = @$(call size_check,$@,$(CONFIG_TPL_SIZE_LIMIT))
Using a constant here is not what SPL does by now: some months ago, I implemented a more sophisticated size check for SPL that also integrates 'gd', stack and heap usage into the size check. Wouldn't that be required for TPL as well (at least on platforms where everything must fit into SRAM)?
Yes I see, but in this case we just need the image to be below a certain size. The actual memory used is somewhere else.
Regards, SImon

U-Boot has two distinct phases: before and after relocation. These are commonly referred to as F (running from Flash) and R (Relocated and running from RAM). Some drivers want to do different things in these phases so update the SPL phase function to return a different value for each.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/spl.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/include/spl.h b/include/spl.h index 2869c9dc702..1ba90c36def 100644 --- a/include/spl.h +++ b/include/spl.h @@ -50,9 +50,10 @@ static inline bool u_boot_first_phase(void) }
enum u_boot_phase { - PHASE_TPL, - PHASE_SPL, - PHASE_U_BOOT, + PHASE_TPL, /* Running in TPL */ + PHASE_SPL, /* Running in SPL */ + PHASE_BOARD_F, /* Running in U-Boot before relocation */ + PHASE_BOARD_R, /* Running in U-Boot after relocation */ };
/** @@ -92,7 +93,7 @@ enum u_boot_phase { * * but with this you can use: * - * if (spl_phase() == PHASE_U_BOOT) { + * if (spl_phase() == PHASE_BOARD_F) { * ... * } * @@ -105,7 +106,12 @@ static inline enum u_boot_phase spl_phase(void) #elif CONFIG_SPL_BUILD return PHASE_SPL; #else - return PHASE_U_BOOT; + DECLARE_GLOBAL_DATA_PTR; + + if (!(gd->flags & GD_FLG_RELOC)) + return PHASE_BOARD_F; + else + return PHASE_BOARD_R; #endif }

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
U-Boot has two distinct phases: before and after relocation. These are commonly referred to as F (running from Flash) and R (Relocated and running from RAM). Some drivers want to do different things in these phases so update the SPL phase function to return a different value for each.
Signed-off-by: Simon Glass sjg@chromium.org
include/spl.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:30 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
U-Boot has two distinct phases: before and after relocation. These are commonly referred to as F (running from Flash) and R (Relocated and running from RAM). Some drivers want to do different things in these phases so update the SPL phase function to return a different value for each.
Signed-off-by: Simon Glass sjg@chromium.org
include/spl.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

At present libfdt is included in SPL/TPL if SPL/TPL_OF_CONTROL is enabled. But if of-platdata is in use this is not required. Update the condition to avoid building this extra code. This ensures that if a libfdt function is used it will produce a link error rather than silently increasing the build size.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/Kconfig b/lib/Kconfig index 135f0b372b0..bab57eb3059 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -473,7 +473,7 @@ config OF_LIBFDT_OVERLAY
config SPL_OF_LIBFDT bool "Enable the FDT library for SPL" - default y if SPL_OF_CONTROL + default y if SPL_OF_CONTROL && !SPL_OF_PLATDATA help This enables the FDT library (libfdt). It provides functions for accessing binary device tree images in memory, such as adding and @@ -483,7 +483,7 @@ config SPL_OF_LIBFDT
config TPL_OF_LIBFDT bool "Enable the FDT library for TPL" - default y if TPL_OF_CONTROL + default y if TPL_OF_CONTROL && !TPL_OF_PLATDATA help This enables the FDT library (libfdt). It provides functions for accessing binary device tree images in memory, such as adding and

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present libfdt is included in SPL/TPL if SPL/TPL_OF_CONTROL is enabled. But if of-platdata is in use this is not required. Update the condition to avoid building this extra code. This ensures that if a libfdt function is used it will produce a link error rather than silently increasing the build size.
Signed-off-by: Simon Glass sjg@chromium.org
lib/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:30 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present libfdt is included in SPL/TPL if SPL/TPL_OF_CONTROL is enabled. But if of-platdata is in use this is not required. Update the condition to avoid building this extra code. This ensures that if a libfdt function is used it will produce a link error rather than silently increasing the build size.
Signed-off-by: Simon Glass sjg@chromium.org
lib/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

On Mon, Oct 7, 2019 at 9:55 AM Bin Meng bmeng.cn@gmail.com wrote:
On Sat, Oct 5, 2019 at 11:30 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present libfdt is included in SPL/TPL if SPL/TPL_OF_CONTROL is enabled. But if of-platdata is in use this is not required. Update the condition to avoid building this extra code. This ensures that if a libfdt function is used it will produce a link error rather than silently increasing the build size.
Signed-off-by: Simon Glass sjg@chromium.org
lib/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!
This patch unfortunately breaks some ARM boards build, eg: chromebook_jerry
See https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/17131 https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/17132
I will have to drop this patch from my queue.
Regards, Bin

Hi Bin,
On Mon, 7 Oct 2019 at 23:46, Bin Meng bmeng.cn@gmail.com wrote:
On Mon, Oct 7, 2019 at 9:55 AM Bin Meng bmeng.cn@gmail.com wrote:
On Sat, Oct 5, 2019 at 11:30 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present libfdt is included in SPL/TPL if SPL/TPL_OF_CONTROL is enabled. But if of-platdata is in use this is not required. Update the condition to avoid building this extra code. This ensures that if a libfdt function is used it will produce a link error rather than silently increasing the build size.
Signed-off-by: Simon Glass sjg@chromium.org
lib/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!
This patch unfortunately breaks some ARM boards build, eg: chromebook_jerry
See https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/17131 https://gitlab.denx.de/u-boot/custodians/u-boot-x86/-/jobs/17132
I will have to drop this patch from my queue.
I'll put this one in a separate series.
Regards, SImon

At present this hedaer is only available on x86. To allow sandbox to use it for testing, move it to a common location.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/baytrail/acpi.c | 2 +- arch/x86/cpu/cpu.c | 2 +- arch/x86/cpu/wakeup.S | 2 +- arch/x86/lib/acpi_s3.c | 2 +- arch/x86/lib/coreboot_table.c | 2 +- arch/x86/lib/fsp/fsp_common.c | 2 +- arch/x86/lib/fsp1/fsp_common.c | 2 +- drivers/pci/pci_rom.c | 2 +- drivers/sysreset/sysreset_x86.c | 2 +- {arch/x86/include/asm => include}/acpi_s3.h | 0 10 files changed, 9 insertions(+), 9 deletions(-) rename {arch/x86/include/asm => include}/acpi_s3.h (100%)
diff --git a/arch/x86/cpu/baytrail/acpi.c b/arch/x86/cpu/baytrail/acpi.c index 1e3829a433c..f44228e6939 100644 --- a/arch/x86/cpu/baytrail/acpi.c +++ b/arch/x86/cpu/baytrail/acpi.c @@ -4,10 +4,10 @@ */
#include <common.h> +#include <acpi_s3.h> #include <cpu.h> #include <dm.h> #include <dm/uclass-internal.h> -#include <asm/acpi_s3.h> #include <asm/acpi_table.h> #include <asm/io.h> #include <asm/tables.h> diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index e0b24c8df29..9cafd39ec91 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -19,13 +19,13 @@ */
#include <common.h> +#include <acpi_s3.h> #include <command.h> #include <dm.h> #include <errno.h> #include <malloc.h> #include <syscon.h> #include <asm/acpi.h> -#include <asm/acpi_s3.h> #include <asm/acpi_table.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> diff --git a/arch/x86/cpu/wakeup.S b/arch/x86/cpu/wakeup.S index 663b02f27d8..244ca1276af 100644 --- a/arch/x86/cpu/wakeup.S +++ b/arch/x86/cpu/wakeup.S @@ -5,7 +5,7 @@ * From coreboot src/arch/x86/wakeup.S */
-#include <asm/acpi_s3.h> +#include <acpi_s3.h> #include <asm/processor.h> #include <asm/processor-flags.h>
diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c index 03917188a9b..197636c4b50 100644 --- a/arch/x86/lib/acpi_s3.c +++ b/arch/x86/lib/acpi_s3.c @@ -4,8 +4,8 @@ */
#include <common.h> +#include <acpi_s3.h> #include <asm/acpi.h> -#include <asm/acpi_s3.h> #include <asm/acpi_table.h> #include <asm/post.h> #include <linux/linkage.h> diff --git a/arch/x86/lib/coreboot_table.c b/arch/x86/lib/coreboot_table.c index 2d08a2db0db..8685aa30467 100644 --- a/arch/x86/lib/coreboot_table.c +++ b/arch/x86/lib/coreboot_table.c @@ -4,8 +4,8 @@ */
#include <common.h> +#include <acpi_s3.h> #include <vbe.h> -#include <asm/acpi_s3.h> #include <asm/coreboot_tables.h> #include <asm/e820.h>
diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 6678d75ffd5..40ba866d77c 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -4,10 +4,10 @@ */
#include <common.h> +#include <acpi_s3.h> #include <dm.h> #include <errno.h> #include <rtc.h> -#include <asm/acpi_s3.h> #include <asm/cmos_layout.h> #include <asm/early_cmos.h> #include <asm/io.h> diff --git a/arch/x86/lib/fsp1/fsp_common.c b/arch/x86/lib/fsp1/fsp_common.c index 285ef72ebf8..e8066d8de39 100644 --- a/arch/x86/lib/fsp1/fsp_common.c +++ b/arch/x86/lib/fsp1/fsp_common.c @@ -4,10 +4,10 @@ */
#include <common.h> +#include <acpi_s3.h> #include <dm.h> #include <errno.h> #include <rtc.h> -#include <asm/acpi_s3.h> #include <asm/cmos_layout.h> #include <asm/early_cmos.h> #include <asm/io.h> diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 2cede1211bb..1d4064e3769 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -35,7 +35,7 @@ #include <linux/screen_info.h>
#ifdef CONFIG_X86 -#include <asm/acpi_s3.h> +#include <acpi_s3.h> DECLARE_GLOBAL_DATA_PTR; #endif
diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c index 072f7948efa..8e2d1eaa7a1 100644 --- a/drivers/sysreset/sysreset_x86.c +++ b/drivers/sysreset/sysreset_x86.c @@ -6,11 +6,11 @@ */
#include <common.h> +#include <acpi_s3.h> #include <dm.h> #include <efi_loader.h> #include <pch.h> #include <sysreset.h> -#include <asm/acpi_s3.h> #include <asm/io.h> #include <asm/processor.h>
diff --git a/arch/x86/include/asm/acpi_s3.h b/include/acpi_s3.h similarity index 100% rename from arch/x86/include/asm/acpi_s3.h rename to include/acpi_s3.h

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this hedaer is only available on x86. To allow sandbox to use it for testing, move it to a common location.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/baytrail/acpi.c | 2 +- arch/x86/cpu/cpu.c | 2 +- arch/x86/cpu/wakeup.S | 2 +- arch/x86/lib/acpi_s3.c | 2 +- arch/x86/lib/coreboot_table.c | 2 +- arch/x86/lib/fsp/fsp_common.c | 2 +- arch/x86/lib/fsp1/fsp_common.c | 2 +- drivers/pci/pci_rom.c | 2 +- drivers/sysreset/sysreset_x86.c | 2 +- {arch/x86/include/asm => include}/acpi_s3.h | 0 10 files changed, 9 insertions(+), 9 deletions(-) rename {arch/x86/include/asm => include}/acpi_s3.h (100%)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Sat, Oct 5, 2019 at 11:33 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present this hedaer is only available on x86. To allow sandbox to use it for testing, move it to a common location.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/baytrail/acpi.c | 2 +- arch/x86/cpu/cpu.c | 2 +- arch/x86/cpu/wakeup.S | 2 +- arch/x86/lib/acpi_s3.c | 2 +- arch/x86/lib/coreboot_table.c | 2 +- arch/x86/lib/fsp/fsp_common.c | 2 +- arch/x86/lib/fsp1/fsp_common.c | 2 +- drivers/pci/pci_rom.c | 2 +- drivers/sysreset/sysreset_x86.c | 2 +- {arch/x86/include/asm => include}/acpi_s3.h | 0 10 files changed, 9 insertions(+), 9 deletions(-) rename {arch/x86/include/asm => include}/acpi_s3.h (100%)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

This parameter is needed by the PCI driver-mode interface but is always NULL on x86. There are a number of calls to this function so it makes sense to minimise the parameters.
Adjust the x86 function to omit the first parameter, and introduce stub functions to handle the conversion.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/cpu.c | 7 ++----- arch/x86/cpu/intel_common/fast_spi.c | 3 +-- arch/x86/cpu/ivybridge/cpu.c | 3 +-- arch/x86/cpu/pci.c | 20 ++++++++------------ arch/x86/include/asm/pci.h | 15 ++++++--------- drivers/pci/pci_x86.c | 16 ++++++++++++++-- 6 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index bba8cd1e942..297f1e0b682 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -103,11 +103,8 @@ int print_cpuinfo(void)
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(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); + pci_x86_write_config(PCH_DEV_LPC, LPC_EN, COMA_LPC_EN, PCI_SIZE_16); } diff --git a/arch/x86/cpu/intel_common/fast_spi.c b/arch/x86/cpu/intel_common/fast_spi.c index a7334ecf1a3..e22d7853040 100644 --- a/arch/x86/cpu/intel_common/fast_spi.c +++ b/arch/x86/cpu/intel_common/fast_spi.c @@ -36,8 +36,7 @@ int fast_spi_get_bios_mmap(ulong *map_basep, size_t *map_sizep, uint *offsetp) ulong bar, base, mmio_base;
/* Special case to find mapping without probing the device */ - pci_x86_read_config(NULL, PCH_DEV_SPI, PCI_BASE_ADDRESS_0, &bar, - PCI_SIZE_32); + pci_x86_read_config(PCH_DEV_SPI, PCI_BASE_ADDRESS_0, &bar, PCI_SIZE_32); mmio_base = bar & PCI_BASE_ADDRESS_MEM_MASK; regs = (struct fast_spi_regs *)mmio_base; base = fast_spi_get_bios_region(regs, map_sizep); diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c index c8b16e32c03..6db9da81b71 100644 --- a/arch/x86/cpu/ivybridge/cpu.c +++ b/arch/x86/cpu/ivybridge/cpu.c @@ -199,6 +199,5 @@ int print_cpuinfo(void) void board_debug_uart_init(void) { /* This enables the debug UART */ - pci_x86_write_config(NULL, PCH_LPC_DEV, LPC_EN, COMA_LPC_EN, - PCI_SIZE_16); + pci_x86_write_config(PCH_LPC_DEV, LPC_EN, COMA_LPC_EN, PCI_SIZE_16); } diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c index 0ccde194d9a..e1aae158ce5 100644 --- a/arch/x86/cpu/pci.c +++ b/arch/x86/cpu/pci.c @@ -16,12 +16,8 @@ #include <asm/io.h> #include <asm/pci.h>
-/* - * TODO(sjg@chromium.org): Drop the first parameter from each of these - * functions since it is not used. - */ -int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, - ulong *valuep, enum pci_size_t size) +int pci_x86_read_config(pci_dev_t bdf, uint offset, ulong *valuep, + enum pci_size_t size) { outl(bdf | (offset & 0xfc) | PCI_CFG_EN, PCI_REG_ADDR); switch (size) { @@ -39,8 +35,8 @@ int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, return 0; }
-int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, - ulong value, enum pci_size_t size) +int pci_x86_write_config(pci_dev_t bdf, uint offset, ulong value, + enum pci_size_t size) { outl(bdf | (offset & 0xfc) | PCI_CFG_EN, PCI_REG_ADDR); switch (size) { @@ -58,19 +54,19 @@ int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, return 0; }
-int pci_x86_clrset_config(struct udevice *bus, pci_dev_t bdf, uint offset, - ulong clr, ulong set, enum pci_size_t size) +int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, + enum pci_size_t size) { ulong value; int ret;
- ret = pci_x86_read_config(bus, bdf, offset, &value, size); + ret = pci_x86_read_config(bdf, offset, &value, size); if (ret) return ret; value &= ~clr; value |= set;
- return pci_x86_write_config(bus, bdf, offset, value, size); + return pci_x86_write_config(bdf, offset, value, size); }
void pci_assign_irqs(int bus, int device, u8 irq[4]) diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index fb1edf3df76..2a720735728 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -22,30 +22,28 @@ * * This function can be called before PCI is set up in driver model. * - * @bus: Bus to read from (ignored, can be NULL) * @bdf: PCI device address: bus, device and function -see PCI_BDF() * @offset: Register offset to read * @valuep: Place to put the returned value * @size: Access size * @return 0 if OK, -ve on error */ -int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, - ulong *valuep, enum pci_size_t size); +int pci_x86_read_config(pci_dev_t bdf, uint offset, ulong *valuep, + enum pci_size_t size);
/** * pci_bus_write_config() - Write a configuration value to a device * * This function can be called before PCI is set up in driver model. * - * @bus: Bus to read from (ignored, can be NULL) * @bdf: PCI device address: bus, device and function -see PCI_BDF() * @offset: Register offset to write * @value: Value to write * @size: Access size * @return 0 if OK, -ve on error */ -int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, - ulong value, enum pci_size_t size); +int pci_x86_write_config(pci_dev_t bdf, uint offset, ulong value, + enum pci_size_t size);
/** * pci_bus_clrset_config32() - Update a configuration value for a device @@ -53,15 +51,14 @@ int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, * The register at @offset is updated to (oldvalue & ~clr) | set. This function * can be called before PCI is set up in driver model. * - * @bus: Bus to read from (ignored, can be NULL) * @bdf: PCI device address: bus, device and function -see PCI_BDF() * @offset: Register offset to update * @clr: Bits to clear * @set: Bits to set * @return 0 if OK, -ve on error */ -int pci_x86_clrset_config(struct udevice *bus, pci_dev_t bdf, uint offset, - ulong clr, ulong set, enum pci_size_t size); +int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, + enum pci_size_t size);
/** * Assign IRQ number to a PCI device diff --git a/drivers/pci/pci_x86.c b/drivers/pci/pci_x86.c index 520ea4649e1..e76a9c6e44f 100644 --- a/drivers/pci/pci_x86.c +++ b/drivers/pci/pci_x86.c @@ -8,9 +8,21 @@ #include <pci.h> #include <asm/pci.h>
+static int _pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, + ulong *valuep, enum pci_size_t size) +{ + return pci_x86_read_config(bdf, offset, valuep, size); +} + +static int _pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, + uint offset, ulong value, enum pci_size_t size) +{ + return pci_x86_write_config(bdf, offset, value, size); +} + static const struct dm_pci_ops pci_x86_ops = { - .read_config = pci_x86_read_config, - .write_config = pci_x86_write_config, + .read_config = _pci_x86_read_config, + .write_config = _pci_x86_write_config, };
static const struct udevice_id pci_x86_ids[] = {

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This parameter is needed by the PCI driver-mode interface but is always NULL on x86. There are a number of calls to this function so it makes sense to minimise the parameters.
Adjust the x86 function to omit the first parameter, and introduce stub functions to handle the conversion.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 7 ++----- arch/x86/cpu/intel_common/fast_spi.c | 3 +-- arch/x86/cpu/ivybridge/cpu.c | 3 +-- arch/x86/cpu/pci.c | 20 ++++++++------------ arch/x86/include/asm/pci.h | 15 ++++++--------- drivers/pci/pci_x86.c | 16 ++++++++++++++-- 6 files changed, 32 insertions(+), 32 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 8:24 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This parameter is needed by the PCI driver-mode interface but is always NULL on x86. There are a number of calls to this function so it makes sense to minimise the parameters.
Adjust the x86 function to omit the first parameter, and introduce stub functions to handle the conversion.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 7 ++----- arch/x86/cpu/intel_common/fast_spi.c | 3 +-- arch/x86/cpu/ivybridge/cpu.c | 3 +-- arch/x86/cpu/pci.c | 20 ++++++++------------ arch/x86/include/asm/pci.h | 15 ++++++--------- drivers/pci/pci_x86.c | 16 ++++++++++++++-- 6 files changed, 32 insertions(+), 32 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Rebased the patch against u-boot-x86/next to get it applied cleanly, and
applied to u-boot-x86/next, thanks!

Most of the timer-calibration methods are not needed on recent Intel CPUs and just increase code size. Add an option to use the known-good way to get the clock frequency in TPL. Size reduction is about 700 bytes.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/timer/Kconfig | 29 +++++++++++++++++++---------- drivers/timer/tsc_timer.c | 7 +++++-- 2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 5f4bc6edb67..90bc8ec7c53 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER Enables support for the Renesas OSTM Timer driver. This timer is present on Renesas RZ/A1 R7S72100 SoCs.
-config X86_TSC_TIMER_EARLY_FREQ - int "x86 TSC timer frequency in MHz when used as the early timer" - depends on X86_TSC_TIMER - default 1000 - help - Sets the estimated CPU frequency in MHz when TSC is used as the - early timer and the frequency can neither be calibrated via some - hardware ways, nor got from device tree at the time when device - tree is not available yet. - config OMAP_TIMER bool "Omap timer support" depends on TIMER @@ -174,6 +164,25 @@ config X86_TSC_TIMER help Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config X86_TSC_TIMER_EARLY_FREQ + int "x86 TSC timer frequency in MHz when used as the early timer" + depends on X86_TSC_TIMER + default 1000 + help + Sets the estimated CPU frequency in MHz when TSC is used as the + early timer and the frequency can neither be calibrated via some + hardware ways, nor got from device tree at the time when device + tree is not available yet. + +config TPL_X86_TSC_TIMER_NATIVE + bool "x86 TSC timer uses native calibration" + depends on TPL && X86_TSC_TIMER + help + Selects native timer calibration for TPL and don't include the other + methods in the code. This helps to reduce code size in TPL and works + on fairly modern Intel chips. Code-size reductions is about 700 + bytes. + config MTK_TIMER bool "MediaTek timer support" depends on TIMER diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 919caba8a14..9630036bc7f 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) return 0;
crystal_freq = tsc_info.ecx / 1000; - - if (!crystal_freq) { + if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { switch (gd->arch.x86_model) { case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP: @@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) if (fast_calibrate) goto done;
+ /* Reduce code size by dropping other methods */ + if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE)) + panic("no timer"); + fast_calibrate = cpu_mhz_from_cpuid(); if (fast_calibrate) goto done;

Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Most of the timer-calibration methods are not needed on recent Intel CPUs and just increase code size. Add an option to use the known-good way to get the clock frequency in TPL. Size reduction is about 700 bytes.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/timer/Kconfig | 29 +++++++++++++++++++---------- drivers/timer/tsc_timer.c | 7 +++++-- 2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 5f4bc6edb67..90bc8ec7c53 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER Enables support for the Renesas OSTM Timer driver. This timer is present on Renesas RZ/A1 R7S72100 SoCs.
-config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
config OMAP_TIMER bool "Omap timer support" depends on TIMER @@ -174,6 +164,25 @@ config X86_TSC_TIMER help Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
+config TPL_X86_TSC_TIMER_NATIVE
bool "x86 TSC timer uses native calibration"
depends on TPL && X86_TSC_TIMER
help
Selects native timer calibration for TPL and don't include the other
methods in the code. This helps to reduce code size in TPL and works
on fairly modern Intel chips. Code-size reductions is about 700
bytes.
config MTK_TIMER bool "MediaTek timer support" depends on TIMER diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 919caba8a14..9630036bc7f 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) return 0;
crystal_freq = tsc_info.ecx / 1000;
if (!crystal_freq) {
if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { switch (gd->arch.x86_model) { case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) if (fast_calibrate) goto done;
/* Reduce code size by dropping other methods */
if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
panic("no timer");
I don't get it. How could this reduce the code size? I don't see any #ifdefs around the other methods we want to drop?
fast_calibrate = cpu_mhz_from_cpuid(); if (fast_calibrate) goto done;
--
Regards, Bin

Hi Bin,
On Sat, 5 Oct 2019 at 08:36, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Most of the timer-calibration methods are not needed on recent Intel CPUs and just increase code size. Add an option to use the known-good way to get the clock frequency in TPL. Size reduction is about 700 bytes.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/timer/Kconfig | 29 +++++++++++++++++++---------- drivers/timer/tsc_timer.c | 7 +++++-- 2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 5f4bc6edb67..90bc8ec7c53 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER Enables support for the Renesas OSTM Timer driver. This timer is present on Renesas RZ/A1 R7S72100 SoCs.
-config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
config OMAP_TIMER bool "Omap timer support" depends on TIMER @@ -174,6 +164,25 @@ config X86_TSC_TIMER help Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
+config TPL_X86_TSC_TIMER_NATIVE
bool "x86 TSC timer uses native calibration"
depends on TPL && X86_TSC_TIMER
help
Selects native timer calibration for TPL and don't include the other
methods in the code. This helps to reduce code size in TPL and works
on fairly modern Intel chips. Code-size reductions is about 700
bytes.
config MTK_TIMER bool "MediaTek timer support" depends on TIMER diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 919caba8a14..9630036bc7f 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) return 0;
crystal_freq = tsc_info.ecx / 1000;
if (!crystal_freq) {
if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { switch (gd->arch.x86_model) { case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) if (fast_calibrate) goto done;
/* Reduce code size by dropping other methods */
if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
panic("no timer");
I don't get it. How could this reduce the code size? I don't see any #ifdefs around the other methods we want to drop?
The compiler sees that CONFIG_IS_ENABLED(..) is 1, and leaves out the code that follows it.
fast_calibrate = cpu_mhz_from_cpuid(); if (fast_calibrate) goto done;
--
Regards, Bin
Regards, Simon

Hi Simon,
On Fri, Oct 11, 2019 at 1:06 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Sat, 5 Oct 2019 at 08:36, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Most of the timer-calibration methods are not needed on recent Intel CPUs and just increase code size. Add an option to use the known-good way to get the clock frequency in TPL. Size reduction is about 700 bytes.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/timer/Kconfig | 29 +++++++++++++++++++---------- drivers/timer/tsc_timer.c | 7 +++++-- 2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 5f4bc6edb67..90bc8ec7c53 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER Enables support for the Renesas OSTM Timer driver. This timer is present on Renesas RZ/A1 R7S72100 SoCs.
-config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
config OMAP_TIMER bool "Omap timer support" depends on TIMER @@ -174,6 +164,25 @@ config X86_TSC_TIMER help Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
+config TPL_X86_TSC_TIMER_NATIVE
bool "x86 TSC timer uses native calibration"
depends on TPL && X86_TSC_TIMER
help
Selects native timer calibration for TPL and don't include the other
methods in the code. This helps to reduce code size in TPL and works
on fairly modern Intel chips. Code-size reductions is about 700
bytes.
config MTK_TIMER bool "MediaTek timer support" depends on TIMER diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 919caba8a14..9630036bc7f 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) return 0;
crystal_freq = tsc_info.ecx / 1000;
if (!crystal_freq) {
if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { switch (gd->arch.x86_model) { case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) if (fast_calibrate) goto done;
/* Reduce code size by dropping other methods */
if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
panic("no timer");
I don't get it. How could this reduce the code size? I don't see any #ifdefs around the other methods we want to drop?
The compiler sees that CONFIG_IS_ENABLED(..) is 1, and leaves out the code that follows it.
Why?
if (1) panic("no timer");
then compiler does not generate any codes of the following?
fast_calibrate = cpu_mhz_from_cpuid();
I don't understand.
Besides, I think adding some random Kconfig options to exclude some specific parts in one C file is a bad idea. It's unclear to me why we should exclude one part versus another part. I'm OK to exclude the whole C file for TPL/SPL though, but not part of it for size limitation purpose.
fast_calibrate = cpu_mhz_from_cpuid(); if (fast_calibrate) goto done;
--
Regards, Bin

Hi Bin,
On Fri, 11 Oct 2019 at 07:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Oct 11, 2019 at 1:06 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Sat, 5 Oct 2019 at 08:36, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Most of the timer-calibration methods are not needed on recent Intel CPUs and just increase code size. Add an option to use the known-good way to get the clock frequency in TPL. Size reduction is about 700 bytes.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/timer/Kconfig | 29 +++++++++++++++++++---------- drivers/timer/tsc_timer.c | 7 +++++-- 2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 5f4bc6edb67..90bc8ec7c53 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER Enables support for the Renesas OSTM Timer driver. This timer is present on Renesas RZ/A1 R7S72100 SoCs.
-config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
config OMAP_TIMER bool "Omap timer support" depends on TIMER @@ -174,6 +164,25 @@ config X86_TSC_TIMER help Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
+config TPL_X86_TSC_TIMER_NATIVE
bool "x86 TSC timer uses native calibration"
depends on TPL && X86_TSC_TIMER
help
Selects native timer calibration for TPL and don't include the other
methods in the code. This helps to reduce code size in TPL and works
on fairly modern Intel chips. Code-size reductions is about 700
bytes.
config MTK_TIMER bool "MediaTek timer support" depends on TIMER diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 919caba8a14..9630036bc7f 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) return 0;
crystal_freq = tsc_info.ecx / 1000;
if (!crystal_freq) {
if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { switch (gd->arch.x86_model) { case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) if (fast_calibrate) goto done;
/* Reduce code size by dropping other methods */
if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
panic("no timer");
I don't get it. How could this reduce the code size? I don't see any #ifdefs around the other methods we want to drop?
The compiler sees that CONFIG_IS_ENABLED(..) is 1, and leaves out the code that follows it.
Why?
if (1) panic("no timer");
then compiler does not generate any codes of the following?
fast_calibrate = cpu_mhz_from_cpuid();
I don't understand.
The panic() function is marked as noreturn, so the compiler assume it doesn't return. You can try this if you like. It reduces the size by 700 bytes which on a 22KB image is a lot.
Besides, I think adding some random Kconfig options to exclude some specific parts in one C file is a bad idea. It's unclear to me why we should exclude one part versus another part. I'm OK to exclude the whole C file for TPL/SPL though, but not part of it for size limitation purpose.
My understanding is the most of the code in this function is a fallback in case an earlier method doesn't work. But on modern CPUs the first method always works, so this is a waste of time?
Regards, Simon

Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, 11 Oct 2019 at 07:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Oct 11, 2019 at 1:06 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Sat, 5 Oct 2019 at 08:36, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Most of the timer-calibration methods are not needed on recent Intel CPUs and just increase code size. Add an option to use the known-good way to get the clock frequency in TPL. Size reduction is about 700 bytes.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/timer/Kconfig | 29 +++++++++++++++++++---------- drivers/timer/tsc_timer.c | 7 +++++-- 2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 5f4bc6edb67..90bc8ec7c53 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER Enables support for the Renesas OSTM Timer driver. This timer is present on Renesas RZ/A1 R7S72100 SoCs.
-config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
config OMAP_TIMER bool "Omap timer support" depends on TIMER @@ -174,6 +164,25 @@ config X86_TSC_TIMER help Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
+config TPL_X86_TSC_TIMER_NATIVE
bool "x86 TSC timer uses native calibration"
depends on TPL && X86_TSC_TIMER
help
Selects native timer calibration for TPL and don't include the other
methods in the code. This helps to reduce code size in TPL and works
on fairly modern Intel chips. Code-size reductions is about 700
bytes.
config MTK_TIMER bool "MediaTek timer support" depends on TIMER diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 919caba8a14..9630036bc7f 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) return 0;
crystal_freq = tsc_info.ecx / 1000;
if (!crystal_freq) {
if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { switch (gd->arch.x86_model) { case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) if (fast_calibrate) goto done;
/* Reduce code size by dropping other methods */
if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
panic("no timer");
I don't get it. How could this reduce the code size? I don't see any #ifdefs around the other methods we want to drop?
The compiler sees that CONFIG_IS_ENABLED(..) is 1, and leaves out the code that follows it.
Why?
if (1) panic("no timer");
then compiler does not generate any codes of the following?
fast_calibrate = cpu_mhz_from_cpuid();
I don't understand.
The panic() function is marked as noreturn, so the compiler assume it doesn't return. You can try this if you like. It reduces the size by 700 bytes which on a 22KB image is a lot.
OK, compiler is smart to generate less codes :)
But the way you added the CONFIG_IS_ENABLED(..) logic check here is obscure if one does not dig into that deep ..
Besides, I think adding some random Kconfig options to exclude some specific parts in one C file is a bad idea. It's unclear to me why we should exclude one part versus another part. I'm OK to exclude the whole C file for TPL/SPL though, but not part of it for size limitation purpose.
My understanding is the most of the code in this function is a fallback in case an earlier method doesn't work. But on modern CPUs
Yes, correct.
the first method always works, so this is a waste of time?
It's not a wast of time, but a bloat of the code size. As you said, these are fallbacks, and methods are prioritized based on the age of the processors, so that native method is tried first, followed by cpuid, MSR, and finally PIT.
You also mentioned that "on modern CPUs the first method always works", so today the first method is native_calibrate_tsc(), but say 3 years later, this might not be true, and chances are that we may add another method before native_calibrate_tsc() for whatever mechanism is used on the latest processors, and the insertion of the TPL Kconfig option (TPL_X86_TSC_TIMER_NATIVE) check today is not future proof.
Regards, Bin

Hi Bin,
On Fri, 11 Oct 2019 at 23:18, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, 11 Oct 2019 at 07:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Oct 11, 2019 at 1:06 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Sat, 5 Oct 2019 at 08:36, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Most of the timer-calibration methods are not needed on recent Intel CPUs and just increase code size. Add an option to use the known-good way to get the clock frequency in TPL. Size reduction is about 700 bytes.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/timer/Kconfig | 29 +++++++++++++++++++---------- drivers/timer/tsc_timer.c | 7 +++++-- 2 files changed, 24 insertions(+), 12 deletions(-)
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 5f4bc6edb67..90bc8ec7c53 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER Enables support for the Renesas OSTM Timer driver. This timer is present on Renesas RZ/A1 R7S72100 SoCs.
-config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
config OMAP_TIMER bool "Omap timer support" depends on TIMER @@ -174,6 +164,25 @@ config X86_TSC_TIMER help Select this to enable Time-Stamp Counter (TSC) timer for x86.
+config X86_TSC_TIMER_EARLY_FREQ
int "x86 TSC timer frequency in MHz when used as the early timer"
depends on X86_TSC_TIMER
default 1000
help
Sets the estimated CPU frequency in MHz when TSC is used as the
early timer and the frequency can neither be calibrated via some
hardware ways, nor got from device tree at the time when device
tree is not available yet.
+config TPL_X86_TSC_TIMER_NATIVE
bool "x86 TSC timer uses native calibration"
depends on TPL && X86_TSC_TIMER
help
Selects native timer calibration for TPL and don't include the other
methods in the code. This helps to reduce code size in TPL and works
on fairly modern Intel chips. Code-size reductions is about 700
bytes.
config MTK_TIMER bool "MediaTek timer support" depends on TIMER diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 919caba8a14..9630036bc7f 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) return 0;
crystal_freq = tsc_info.ecx / 1000;
if (!crystal_freq) {
if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { switch (gd->arch.x86_model) { case INTEL_FAM6_SKYLAKE_MOBILE: case INTEL_FAM6_SKYLAKE_DESKTOP:
@@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) if (fast_calibrate) goto done;
/* Reduce code size by dropping other methods */
if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE))
panic("no timer");
I don't get it. How could this reduce the code size? I don't see any #ifdefs around the other methods we want to drop?
The compiler sees that CONFIG_IS_ENABLED(..) is 1, and leaves out the code that follows it.
Why?
if (1) panic("no timer");
then compiler does not generate any codes of the following?
fast_calibrate = cpu_mhz_from_cpuid();
I don't understand.
The panic() function is marked as noreturn, so the compiler assume it doesn't return. You can try this if you like. It reduces the size by 700 bytes which on a 22KB image is a lot.
OK, compiler is smart to generate less codes :)
But the way you added the CONFIG_IS_ENABLED(..) logic check here is obscure if one does not dig into that deep ..
Besides, I think adding some random Kconfig options to exclude some specific parts in one C file is a bad idea. It's unclear to me why we should exclude one part versus another part. I'm OK to exclude the whole C file for TPL/SPL though, but not part of it for size limitation purpose.
My understanding is the most of the code in this function is a fallback in case an earlier method doesn't work. But on modern CPUs
Yes, correct.
the first method always works, so this is a waste of time?
It's not a wast of time, but a bloat of the code size. As you said, these are fallbacks, and methods are prioritized based on the age of the processors, so that native method is tried first, followed by cpuid, MSR, and finally PIT.
You also mentioned that "on modern CPUs the first method always works", so today the first method is native_calibrate_tsc(), but say 3 years later, this might not be true, and chances are that we may add another method before native_calibrate_tsc() for whatever mechanism is used on the latest processors, and the insertion of the TPL Kconfig option (TPL_X86_TSC_TIMER_NATIVE) check today is not future proof.
That's right, it is not. Perhaps we need to have separate timer drivers for different generations? But if not, I am loath to have 700 bytes of dead code in TPL, which I why I added the option.
If we later need to adjust it, we can do so, but this cuts off the worst of the bloat.
Regards, Simon

Hi Simon,
On Sun, Oct 13, 2019 at 1:55 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, 11 Oct 2019 at 23:18, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, 11 Oct 2019 at 07:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Oct 11, 2019 at 1:06 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Sat, 5 Oct 2019 at 08:36, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote: > > Most of the timer-calibration methods are not needed on recent Intel CPUs > and just increase code size. Add an option to use the known-good way to > get the clock frequency in TPL. Size reduction is about 700 bytes. > > Signed-off-by: Simon Glass sjg@chromium.org > --- > > drivers/timer/Kconfig | 29 +++++++++++++++++++---------- > drivers/timer/tsc_timer.c | 7 +++++-- > 2 files changed, 24 insertions(+), 12 deletions(-) > > diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig > index 5f4bc6edb67..90bc8ec7c53 100644 > --- a/drivers/timer/Kconfig > +++ b/drivers/timer/Kconfig > @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER > Enables support for the Renesas OSTM Timer driver. > This timer is present on Renesas RZ/A1 R7S72100 SoCs. > > -config X86_TSC_TIMER_EARLY_FREQ > - int "x86 TSC timer frequency in MHz when used as the early timer" > - depends on X86_TSC_TIMER > - default 1000 > - help > - Sets the estimated CPU frequency in MHz when TSC is used as the > - early timer and the frequency can neither be calibrated via some > - hardware ways, nor got from device tree at the time when device > - tree is not available yet. > - > config OMAP_TIMER > bool "Omap timer support" > depends on TIMER > @@ -174,6 +164,25 @@ config X86_TSC_TIMER > help > Select this to enable Time-Stamp Counter (TSC) timer for x86. > > +config X86_TSC_TIMER_EARLY_FREQ > + int "x86 TSC timer frequency in MHz when used as the early timer" > + depends on X86_TSC_TIMER > + default 1000 > + help > + Sets the estimated CPU frequency in MHz when TSC is used as the > + early timer and the frequency can neither be calibrated via some > + hardware ways, nor got from device tree at the time when device > + tree is not available yet. > + > +config TPL_X86_TSC_TIMER_NATIVE > + bool "x86 TSC timer uses native calibration" > + depends on TPL && X86_TSC_TIMER > + help > + Selects native timer calibration for TPL and don't include the other > + methods in the code. This helps to reduce code size in TPL and works > + on fairly modern Intel chips. Code-size reductions is about 700 > + bytes. > + > config MTK_TIMER > bool "MediaTek timer support" > depends on TIMER > diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c > index 919caba8a14..9630036bc7f 100644 > --- a/drivers/timer/tsc_timer.c > +++ b/drivers/timer/tsc_timer.c > @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) > return 0; > > crystal_freq = tsc_info.ecx / 1000; > - > - if (!crystal_freq) { > + if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { > switch (gd->arch.x86_model) { > case INTEL_FAM6_SKYLAKE_MOBILE: > case INTEL_FAM6_SKYLAKE_DESKTOP: > @@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) > if (fast_calibrate) > goto done; > > + /* Reduce code size by dropping other methods */ > + if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE)) > + panic("no timer"); > +
I don't get it. How could this reduce the code size? I don't see any #ifdefs around the other methods we want to drop?
The compiler sees that CONFIG_IS_ENABLED(..) is 1, and leaves out the code that follows it.
Why?
if (1) panic("no timer");
then compiler does not generate any codes of the following?
fast_calibrate = cpu_mhz_from_cpuid();
I don't understand.
The panic() function is marked as noreturn, so the compiler assume it doesn't return. You can try this if you like. It reduces the size by 700 bytes which on a 22KB image is a lot.
OK, compiler is smart to generate less codes :)
But the way you added the CONFIG_IS_ENABLED(..) logic check here is obscure if one does not dig into that deep ..
Besides, I think adding some random Kconfig options to exclude some specific parts in one C file is a bad idea. It's unclear to me why we should exclude one part versus another part. I'm OK to exclude the whole C file for TPL/SPL though, but not part of it for size limitation purpose.
My understanding is the most of the code in this function is a fallback in case an earlier method doesn't work. But on modern CPUs
Yes, correct.
the first method always works, so this is a waste of time?
It's not a wast of time, but a bloat of the code size. As you said, these are fallbacks, and methods are prioritized based on the age of the processors, so that native method is tried first, followed by cpuid, MSR, and finally PIT.
You also mentioned that "on modern CPUs the first method always works", so today the first method is native_calibrate_tsc(), but say 3 years later, this might not be true, and chances are that we may add another method before native_calibrate_tsc() for whatever mechanism is used on the latest processors, and the insertion of the TPL Kconfig option (TPL_X86_TSC_TIMER_NATIVE) check today is not future proof.
That's right, it is not. Perhaps we need to have separate timer drivers for different generations? But if not, I am loath to have 700 bytes of dead code in TPL, which I why I added the option.
I asked the TPL question in another thread. I think I will need understand why size is a problem for latest x86 processors to have just a single U-Boot booting from reset vector to the shell.
If we later need to adjust it, we can do so, but this cuts off the worst of the bloat.
Regards, Bin

Hi Bin,
On Sun, 13 Oct 2019 at 20:00, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sun, Oct 13, 2019 at 1:55 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, 11 Oct 2019 at 23:18, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, 11 Oct 2019 at 07:19, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Fri, Oct 11, 2019 at 1:06 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Sat, 5 Oct 2019 at 08:36, Bin Meng bmeng.cn@gmail.com wrote: > > Hi Simon, > > On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote: > > > > Most of the timer-calibration methods are not needed on recent Intel CPUs > > and just increase code size. Add an option to use the known-good way to > > get the clock frequency in TPL. Size reduction is about 700 bytes. > > > > Signed-off-by: Simon Glass sjg@chromium.org > > --- > > > > drivers/timer/Kconfig | 29 +++++++++++++++++++---------- > > drivers/timer/tsc_timer.c | 7 +++++-- > > 2 files changed, 24 insertions(+), 12 deletions(-) > > > > diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig > > index 5f4bc6edb67..90bc8ec7c53 100644 > > --- a/drivers/timer/Kconfig > > +++ b/drivers/timer/Kconfig > > @@ -117,16 +117,6 @@ config RENESAS_OSTM_TIMER > > Enables support for the Renesas OSTM Timer driver. > > This timer is present on Renesas RZ/A1 R7S72100 SoCs. > > > > -config X86_TSC_TIMER_EARLY_FREQ > > - int "x86 TSC timer frequency in MHz when used as the early timer" > > - depends on X86_TSC_TIMER > > - default 1000 > > - help > > - Sets the estimated CPU frequency in MHz when TSC is used as the > > - early timer and the frequency can neither be calibrated via some > > - hardware ways, nor got from device tree at the time when device > > - tree is not available yet. > > - > > config OMAP_TIMER > > bool "Omap timer support" > > depends on TIMER > > @@ -174,6 +164,25 @@ config X86_TSC_TIMER > > help > > Select this to enable Time-Stamp Counter (TSC) timer for x86. > > > > +config X86_TSC_TIMER_EARLY_FREQ > > + int "x86 TSC timer frequency in MHz when used as the early timer" > > + depends on X86_TSC_TIMER > > + default 1000 > > + help > > + Sets the estimated CPU frequency in MHz when TSC is used as the > > + early timer and the frequency can neither be calibrated via some > > + hardware ways, nor got from device tree at the time when device > > + tree is not available yet. > > + > > +config TPL_X86_TSC_TIMER_NATIVE > > + bool "x86 TSC timer uses native calibration" > > + depends on TPL && X86_TSC_TIMER > > + help > > + Selects native timer calibration for TPL and don't include the other > > + methods in the code. This helps to reduce code size in TPL and works > > + on fairly modern Intel chips. Code-size reductions is about 700 > > + bytes. > > + > > config MTK_TIMER > > bool "MediaTek timer support" > > depends on TIMER > > diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c > > index 919caba8a14..9630036bc7f 100644 > > --- a/drivers/timer/tsc_timer.c > > +++ b/drivers/timer/tsc_timer.c > > @@ -49,8 +49,7 @@ static unsigned long native_calibrate_tsc(void) > > return 0; > > > > crystal_freq = tsc_info.ecx / 1000; > > - > > - if (!crystal_freq) { > > + if (!CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE) && !crystal_freq) { > > switch (gd->arch.x86_model) { > > case INTEL_FAM6_SKYLAKE_MOBILE: > > case INTEL_FAM6_SKYLAKE_DESKTOP: > > @@ -405,6 +404,10 @@ static void tsc_timer_ensure_setup(bool early) > > if (fast_calibrate) > > goto done; > > > > + /* Reduce code size by dropping other methods */ > > + if (CONFIG_IS_ENABLED(X86_TSC_TIMER_NATIVE)) > > + panic("no timer"); > > + > > I don't get it. How could this reduce the code size? I don't see any > #ifdefs around the other methods we want to drop?
The compiler sees that CONFIG_IS_ENABLED(..) is 1, and leaves out the code that follows it.
Why?
if (1) panic("no timer");
then compiler does not generate any codes of the following?
fast_calibrate = cpu_mhz_from_cpuid();
I don't understand.
The panic() function is marked as noreturn, so the compiler assume it doesn't return. You can try this if you like. It reduces the size by 700 bytes which on a 22KB image is a lot.
OK, compiler is smart to generate less codes :)
But the way you added the CONFIG_IS_ENABLED(..) logic check here is obscure if one does not dig into that deep ..
Besides, I think adding some random Kconfig options to exclude some specific parts in one C file is a bad idea. It's unclear to me why we should exclude one part versus another part. I'm OK to exclude the whole C file for TPL/SPL though, but not part of it for size limitation purpose.
My understanding is the most of the code in this function is a fallback in case an earlier method doesn't work. But on modern CPUs
Yes, correct.
the first method always works, so this is a waste of time?
It's not a wast of time, but a bloat of the code size. As you said, these are fallbacks, and methods are prioritized based on the age of the processors, so that native method is tried first, followed by cpuid, MSR, and finally PIT.
You also mentioned that "on modern CPUs the first method always works", so today the first method is native_calibrate_tsc(), but say 3 years later, this might not be true, and chances are that we may add another method before native_calibrate_tsc() for whatever mechanism is used on the latest processors, and the insertion of the TPL Kconfig option (TPL_X86_TSC_TIMER_NATIVE) check today is not future proof.
That's right, it is not. Perhaps we need to have separate timer drivers for different generations? But if not, I am loath to have 700 bytes of dead code in TPL, which I why I added the option.
I asked the TPL question in another thread. I think I will need understand why size is a problem for latest x86 processors to have just a single U-Boot booting from reset vector to the shell.
OK I replied on that thread.
I'm going to drop this patch for now as it is not necessary and breaks bootstage in TPL anyway.
Regards, Simon

Remove the duplicate definition as it is not needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/cpu.c | 2 +- arch/x86/cpu/broadwell/cpu_full.c | 2 +- arch/x86/cpu/intel_common/cpu.c | 2 +- arch/x86/include/asm/cpu_common.h | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index 297f1e0b682..61003a6d68f 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -57,7 +57,7 @@ void set_max_freq(void) }
perf_ctl.hi = 0; - msr_write(IA32_PERF_CTL, perf_ctl); + msr_write(MSR_IA32_PERF_CTL, perf_ctl);
debug("CPU: frequency set to %d MHz\n", ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index 9686cf5e0e7..0e3d8781392 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -357,7 +357,7 @@ static void set_max_ratio(void) msr = msr_read(MSR_PLATFORM_INFO); perf_ctl.lo = msr.lo & 0xff00; } - msr_write(IA32_PERF_CTL, perf_ctl); + msr_write(MSR_IA32_PERF_CTL, perf_ctl);
debug("cpu: frequency set to %d\n", ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 9357626b5a6..3a0d505a321 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -116,7 +116,7 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk) { msr_t msr;
- msr = msr_read(IA32_PERF_CTL); + msr = msr_read(MSR_IA32_PERF_CTL); info->cpu_freq = ((msr.lo >> 8) & 0xff) * bclk * 1000000; info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index 0d560262d5a..eb922da2ab8 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -6,8 +6,6 @@ #ifndef __ASM_CPU_COMMON_H #define __ASM_CPU_COMMON_H
-#define IA32_PERF_CTL 0x199 - struct cpu_info;
/**

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Remove the duplicate definition as it is not needed.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 2 +- arch/x86/cpu/broadwell/cpu_full.c | 2 +- arch/x86/cpu/intel_common/cpu.c | 2 +- arch/x86/include/asm/cpu_common.h | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 12:08 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Remove the duplicate definition as it is not needed.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 2 +- arch/x86/cpu/broadwell/cpu_full.c | 2 +- arch/x86/cpu/intel_common/cpu.c | 2 +- arch/x86/include/asm/cpu_common.h | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

This code appears in a few places, so move it to a common file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/cpu_full.c | 20 +------------------- arch/x86/cpu/intel_common/cpu.c | 22 ++++++++++++++++++++++ arch/x86/cpu/ivybridge/model_206ax.c | 25 +++---------------------- arch/x86/include/asm/cpu_common.h | 11 +++++++++++ 4 files changed, 37 insertions(+), 41 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index 0e3d8781392..d1f3c07109f 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -495,24 +495,6 @@ static void configure_misc(void) 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; @@ -562,7 +544,7 @@ static void cpu_core_init(struct udevice *dev) configure_misc();
/* Thermal throttle activation offset */ - configure_thermal_target(dev); + cpu_configure_thermal_target(dev);
/* Enable Direct Cache Access */ configure_dca_cap(); diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 3a0d505a321..7d0ed73b4b6 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -123,3 +123,25 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk)
return 0; } + +int cpu_configure_thermal_target(struct udevice *dev) +{ + u32 tcc_offset; + msr_t msr; + int ret; + + ret = dev_read_u32(dev, "tcc-offset", &tcc_offset); + if (!ret) + return -ENOENT; + + /* Set TCC activaiton offset if supported */ + msr = msr_read(MSR_PLATFORM_INFO); + if (msr.lo & (1 << 30)) { + 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); + } + + return 0; +} diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 68e78e9478b..ed66d2dd8d7 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -283,26 +283,6 @@ static void configure_c_states(void) msr_write(MSR_PP1_CURRENT_CONFIG, msr); }
-static int configure_thermal_target(struct udevice *dev) -{ - int tcc_offset; - msr_t msr; - - tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), - "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); - } - - return 0; -} - static void configure_misc(void) { msr_t msr; @@ -414,10 +394,11 @@ static int model_206ax_init(struct udevice *dev) configure_misc();
/* Thermal throttle activation offset */ - ret = configure_thermal_target(dev); + ret = cpu_configure_thermal_target(dev); if (ret) { debug("Cannot set thermal target\n"); - return ret; + if (ret != -ENOENT) + return ret; }
/* Enable Direct Cache Access */ diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index eb922da2ab8..a1fd7498741 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -40,4 +40,15 @@ int cpu_set_flex_ratio_to_tdp_nominal(void); */ int cpu_intel_get_info(struct cpu_info *info, int bclk_mz);
+/** + * cpu_configure_thermal_target() - Set the thermal target for a CPU + * + * This looks up the tcc-offset property and uses it to set the + * MSR_TEMPERATURE_TARGET value. + * + * @dev: CPU device + * @return 0 if OK, -ENOENT if no target is given in device tree + */ +int cpu_configure_thermal_target(struct udevice *dev); + #endif

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This code appears in a few places, so move it to a common file.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu_full.c | 20 +------------------- arch/x86/cpu/intel_common/cpu.c | 22 ++++++++++++++++++++++ arch/x86/cpu/ivybridge/model_206ax.c | 25 +++---------------------- arch/x86/include/asm/cpu_common.h | 11 +++++++++++ 4 files changed, 37 insertions(+), 41 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index 0e3d8781392..d1f3c07109f 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -495,24 +495,6 @@ static void configure_misc(void) 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);
"intel,tcc-offset" removed
/* 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; @@ -562,7 +544,7 @@ static void cpu_core_init(struct udevice *dev) configure_misc();
/* Thermal throttle activation offset */
configure_thermal_target(dev);
cpu_configure_thermal_target(dev); /* Enable Direct Cache Access */ configure_dca_cap();
diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 3a0d505a321..7d0ed73b4b6 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -123,3 +123,25 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk)
return 0;
}
+int cpu_configure_thermal_target(struct udevice *dev) +{
u32 tcc_offset;
msr_t msr;
int ret;
ret = dev_read_u32(dev, "tcc-offset", &tcc_offset);
"tcc-offset" added, so I wonder how this commit could avoid breaking broadwell? But I see no dts file provides "tcc-offset", or "intel,tcc-offset" neither. Probably not a problem.
if (!ret)
return -ENOENT;
/* Set TCC activaiton offset if supported */
msr = msr_read(MSR_PLATFORM_INFO);
if (msr.lo & (1 << 30)) {
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);
}
return 0;
+} diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 68e78e9478b..ed66d2dd8d7 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -283,26 +283,6 @@ static void configure_c_states(void) msr_write(MSR_PP1_CURRENT_CONFIG, msr); }
-static int configure_thermal_target(struct udevice *dev) -{
int tcc_offset;
msr_t msr;
tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"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);
}
return 0;
-}
static void configure_misc(void) { msr_t msr; @@ -414,10 +394,11 @@ static int model_206ax_init(struct udevice *dev) configure_misc();
/* Thermal throttle activation offset */
ret = configure_thermal_target(dev);
ret = cpu_configure_thermal_target(dev); if (ret) { debug("Cannot set thermal target\n");
return ret;
if (ret != -ENOENT)
return ret; } /* Enable Direct Cache Access */
diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index eb922da2ab8..a1fd7498741 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -40,4 +40,15 @@ int cpu_set_flex_ratio_to_tdp_nominal(void); */ int cpu_intel_get_info(struct cpu_info *info, int bclk_mz);
+/**
- cpu_configure_thermal_target() - Set the thermal target for a CPU
- This looks up the tcc-offset property and uses it to set the
- MSR_TEMPERATURE_TARGET value.
- @dev: CPU device
- @return 0 if OK, -ENOENT if no target is given in device tree
- */
+int cpu_configure_thermal_target(struct udevice *dev);
#endif
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 12:08 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This code appears in a few places, so move it to a common file.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu_full.c | 20 +------------------- arch/x86/cpu/intel_common/cpu.c | 22 ++++++++++++++++++++++ arch/x86/cpu/ivybridge/model_206ax.c | 25 +++---------------------- arch/x86/include/asm/cpu_common.h | 11 +++++++++++ 4 files changed, 37 insertions(+), 41 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index 0e3d8781392..d1f3c07109f 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -495,24 +495,6 @@ static void configure_misc(void) 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);
"intel,tcc-offset" removed
/* 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; @@ -562,7 +544,7 @@ static void cpu_core_init(struct udevice *dev) configure_misc();
/* Thermal throttle activation offset */
configure_thermal_target(dev);
cpu_configure_thermal_target(dev); /* Enable Direct Cache Access */ configure_dca_cap();
diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 3a0d505a321..7d0ed73b4b6 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -123,3 +123,25 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk)
return 0;
}
+int cpu_configure_thermal_target(struct udevice *dev) +{
u32 tcc_offset;
msr_t msr;
int ret;
ret = dev_read_u32(dev, "tcc-offset", &tcc_offset);
"tcc-offset" added, so I wonder how this commit could avoid breaking broadwell? But I see no dts file provides "tcc-offset", or "intel,tcc-offset" neither. Probably not a problem.
if (!ret)
return -ENOENT;
/* Set TCC activaiton offset if supported */
msr = msr_read(MSR_PLATFORM_INFO);
if (msr.lo & (1 << 30)) {
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);
}
return 0;
+} diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 68e78e9478b..ed66d2dd8d7 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -283,26 +283,6 @@ static void configure_c_states(void) msr_write(MSR_PP1_CURRENT_CONFIG, msr); }
-static int configure_thermal_target(struct udevice *dev) -{
int tcc_offset;
msr_t msr;
tcc_offset = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
"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);
}
return 0;
-}
static void configure_misc(void) { msr_t msr; @@ -414,10 +394,11 @@ static int model_206ax_init(struct udevice *dev) configure_misc();
/* Thermal throttle activation offset */
ret = configure_thermal_target(dev);
ret = cpu_configure_thermal_target(dev); if (ret) { debug("Cannot set thermal target\n");
return ret;
if (ret != -ENOENT)
return ret; } /* Enable Direct Cache Access */
diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index eb922da2ab8..a1fd7498741 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -40,4 +40,15 @@ int cpu_set_flex_ratio_to_tdp_nominal(void); */ int cpu_intel_get_info(struct cpu_info *info, int bclk_mz);
+/**
- cpu_configure_thermal_target() - Set the thermal target for a CPU
- This looks up the tcc-offset property and uses it to set the
- MSR_TEMPERATURE_TARGET value.
- @dev: CPU device
- @return 0 if OK, -ENOENT if no target is given in device tree
- */
+int cpu_configure_thermal_target(struct udevice *dev);
#endif
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Modern Intel CPUs use a standard bus clock value of 100MHz, so put this in a common file and tidy up the copies.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/cpu.c | 2 +- arch/x86/cpu/broadwell/cpu_full.c | 4 ++-- arch/x86/cpu/ivybridge/model_206ax.c | 4 ++-- arch/x86/include/asm/arch-broadwell/cpu.h | 3 --- arch/x86/include/asm/arch-broadwell/pch.h | 3 --- arch/x86/include/asm/arch-ivybridge/model_206ax.h | 3 --- arch/x86/include/asm/cpu_common.h | 5 +++++ 7 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index 61003a6d68f..586a2e8f05a 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -60,7 +60,7 @@ void set_max_freq(void) msr_write(MSR_IA32_PERF_CTL, perf_ctl);
debug("CPU: frequency set to %d MHz\n", - ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); + ((perf_ctl.lo >> 8) & 0xff) * INTEL_BCLK_MHZ); }
int arch_cpu_init(void) diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index d1f3c07109f..58cc2f362cc 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -360,7 +360,7 @@ static void set_max_ratio(void) msr_write(MSR_IA32_PERF_CTL, perf_ctl);
debug("cpu: frequency set to %d\n", - ((perf_ctl.lo >> 8) & 0xff) * CPU_BCLK); + ((perf_ctl.lo >> 8) & 0xff) * INTEL_BCLK_MHZ); }
int broadwell_init(struct udevice *dev) @@ -634,7 +634,7 @@ void cpu_set_power_limits(int power_limit_1_time)
static int broadwell_get_info(struct udevice *dev, struct cpu_info *info) { - return cpu_intel_get_info(info, BROADWELL_BCLK); + return cpu_intel_get_info(info, INTEL_BCLK_MHZ); }
static int broadwell_get_count(struct udevice *dev) diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index ed66d2dd8d7..3177ba3297f 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -346,7 +346,7 @@ static void set_max_ratio(void) msr_write(MSR_IA32_PERF_CTL, perf_ctl);
debug("model_x06ax: frequency set to %d\n", - ((perf_ctl.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK); + ((perf_ctl.lo >> 8) & 0xff) * INTEL_BCLK_MHZ); }
static void set_energy_perf_bias(u8 policy) @@ -418,7 +418,7 @@ static int model_206ax_init(struct udevice *dev)
static int model_206ax_get_info(struct udevice *dev, struct cpu_info *info) { - return cpu_intel_get_info(info, SANDYBRIDGE_BCLK); + return cpu_intel_get_info(info, INTEL_BCLK_MHZ);
return 0; } diff --git a/arch/x86/include/asm/arch-broadwell/cpu.h b/arch/x86/include/asm/arch-broadwell/cpu.h index ca22a799968..3bc3bd6609e 100644 --- a/arch/x86/include/asm/arch-broadwell/cpu.h +++ b/arch/x86/include/asm/arch-broadwell/cpu.h @@ -21,9 +21,6 @@ #define CPUID_BROADWELL_D0 0x306d3 #define CPUID_BROADWELL_E0 0x306d4
-/* Broadwell bus clock is fixed at 100MHz */ -#define BROADWELL_BCLK 100 - #define BROADWELL_FAMILY_ULT 0x306d0
#define CORE_THREAD_COUNT_MSR 0x35 diff --git a/arch/x86/include/asm/arch-broadwell/pch.h b/arch/x86/include/asm/arch-broadwell/pch.h index 23153a040fa..ecdf6d16f94 100644 --- a/arch/x86/include/asm/arch-broadwell/pch.h +++ b/arch/x86/include/asm/arch-broadwell/pch.h @@ -6,9 +6,6 @@ #ifndef __ASM_ARCH_PCH_H #define __ASM_ARCH_PCH_H
-/* CPU bus clock is fixed at 100MHz */ -#define CPU_BCLK 100 - #define PMBASE 0x40 #define ACPI_CNTL 0x44 #define ACPI_EN (1 << 7) diff --git a/arch/x86/include/asm/arch-ivybridge/model_206ax.h b/arch/x86/include/asm/arch-ivybridge/model_206ax.h index 850d96bdd9a..10caaa24226 100644 --- a/arch/x86/include/asm/arch-ivybridge/model_206ax.h +++ b/arch/x86/include/asm/arch-ivybridge/model_206ax.h @@ -8,9 +8,6 @@ #ifndef _ASM_ARCH_MODEL_206AX_H #define _ASM_ARCH_MODEL_206AX_H
-/* SandyBridge/IvyBridge bus clock is fixed at 100MHz */ -#define SANDYBRIDGE_BCLK 100 - #define CPUID_VMX (1 << 5) #define CPUID_SMX (1 << 6) #define MSR_FEATURE_CONFIG 0x13c diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index a1fd7498741..3d093021ae6 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -6,6 +6,11 @@ #ifndef __ASM_CPU_COMMON_H #define __ASM_CPU_COMMON_H
+/* Standard Intel bus clock is fixed at 100MHz */ +enum { + INTEL_BCLK_MHZ = 100 +}; + struct cpu_info;
/**

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Modern Intel CPUs use a standard bus clock value of 100MHz, so put this in a common file and tidy up the copies.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 2 +- arch/x86/cpu/broadwell/cpu_full.c | 4 ++-- arch/x86/cpu/ivybridge/model_206ax.c | 4 ++-- arch/x86/include/asm/arch-broadwell/cpu.h | 3 --- arch/x86/include/asm/arch-broadwell/pch.h | 3 --- arch/x86/include/asm/arch-ivybridge/model_206ax.h | 3 --- arch/x86/include/asm/cpu_common.h | 5 +++++ 7 files changed, 10 insertions(+), 14 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 12:09 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Modern Intel CPUs use a standard bus clock value of 100MHz, so put this in a common file and tidy up the copies.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 2 +- arch/x86/cpu/broadwell/cpu_full.c | 4 ++-- arch/x86/cpu/ivybridge/model_206ax.c | 4 ++-- arch/x86/include/asm/arch-broadwell/cpu.h | 3 --- arch/x86/include/asm/arch-broadwell/pch.h | 3 --- arch/x86/include/asm/arch-ivybridge/model_206ax.h | 3 --- arch/x86/include/asm/cpu_common.h | 5 +++++ 7 files changed, 10 insertions(+), 14 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

These functions are the same on modern Intel CPUs, so use common code to set them.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/cpu.c | 7 ++---- arch/x86/cpu/broadwell/cpu_full.c | 9 ------- arch/x86/cpu/intel_common/cpu.c | 20 +++++++++++++++ arch/x86/cpu/ivybridge/model_206ax.c | 25 +++++++------------ arch/x86/cpu/ivybridge/northbridge.c | 2 +- .../include/asm/arch-ivybridge/model_206ax.h | 2 +- arch/x86/include/asm/cpu_common.h | 18 +++++++++++++ 7 files changed, 51 insertions(+), 32 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index 586a2e8f05a..55a7439f1c1 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -41,12 +41,9 @@ int arch_cpu_init_dm(void)
void set_max_freq(void) { - msr_t msr, perf_ctl, platform_info; + msr_t msr, perf_ctl;
- /* Check for configurable TDP option */ - platform_info = msr_read(MSR_PLATFORM_INFO); - - if ((platform_info.hi >> 1) & 3) { + if (cpu_config_tdp_levels()) { /* Set to nominal TDP ratio */ msr = msr_read(MSR_CONFIG_TDP_NOMINAL); perf_ctl.lo = (msr.lo & 0xff) << 8; diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index 58cc2f362cc..169b5b02a6a 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -329,15 +329,6 @@ static int bsp_init_before_ap_bringup(struct udevice *dev) 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; diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 7d0ed73b4b6..1898903853f 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -145,3 +145,23 @@ int cpu_configure_thermal_target(struct udevice *dev)
return 0; } + +void cpu_set_perf_control(uint clk_ratio) +{ + msr_t perf_ctl; + + perf_ctl.lo = (clk_ratio & 0xff) << 8; + perf_ctl.hi = 0; + msr_write(MSR_IA32_PERF_CTL, perf_ctl); + debug("CPU: frequency set to %d MHz\n", clk_ratio * INTEL_BCLK_MHZ); +} + +bool 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) != 0; +} diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 3177ba3297f..2c8cedbaea2 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -140,19 +140,16 @@ static const u8 power_limit_time_msr_to_sec[] = { [0x11] = 128, };
-int cpu_config_tdp_levels(void) +bool cpu_ivybridge_config_tdp_levels(void) { struct cpuid_result result; - msr_t platform_info;
/* Minimum CPU revision */ result = cpuid(1); if (result.eax < IVB_CONFIG_TDP_MIN_CPUID) return 0;
- /* Bits 34:33 indicate how many levels supported */ - platform_info = msr_read(MSR_PLATFORM_INFO); - return (platform_info.hi >> 1) & 3; + return cpu_config_tdp_levels(); }
/* @@ -213,7 +210,7 @@ void set_power_limits(u8 power_limit_1_time) msr_write(MSR_PKG_POWER_LIMIT, limit);
/* Use nominal TDP values for CPUs with configurable TDP */ - if (cpu_config_tdp_levels()) { + if (cpu_ivybridge_config_tdp_levels()) { msr = msr_read(MSR_CONFIG_TDP_NOMINAL); limit.hi = 0; limit.lo = msr.lo & 0xff; @@ -329,24 +326,20 @@ static void configure_dca_cap(void)
static void set_max_ratio(void) { - msr_t msr, perf_ctl; - - perf_ctl.hi = 0; + msr_t msr; + uint ratio;
/* Check for configurable TDP option */ - if (cpu_config_tdp_levels()) { + if (cpu_ivybridge_config_tdp_levels()) { /* Set to nominal TDP ratio */ msr = msr_read(MSR_CONFIG_TDP_NOMINAL); - perf_ctl.lo = (msr.lo & 0xff) << 8; + ratio = msr.lo & 0xff; } else { /* Platform Info bits 15:8 give max ratio */ msr = msr_read(MSR_PLATFORM_INFO); - perf_ctl.lo = msr.lo & 0xff00; + ratio = (msr.lo & 0xff00) >> 8; } - msr_write(MSR_IA32_PERF_CTL, perf_ctl); - - debug("model_x06ax: frequency set to %d\n", - ((perf_ctl.lo >> 8) & 0xff) * INTEL_BCLK_MHZ); + cpu_set_perf_control(ratio); }
static void set_energy_perf_bias(u8 policy) diff --git a/arch/x86/cpu/ivybridge/northbridge.c b/arch/x86/cpu/ivybridge/northbridge.c index a809b823b3b..0f427afcb82 100644 --- a/arch/x86/cpu/ivybridge/northbridge.c +++ b/arch/x86/cpu/ivybridge/northbridge.c @@ -141,7 +141,7 @@ static void northbridge_init(struct udevice *dev, int rev) * CPUs with configurable TDP also need power limits set * in MCHBAR. Use same values from MSR_PKG_POWER_LIMIT. */ - if (cpu_config_tdp_levels()) { + if (cpu_ivybridge_config_tdp_levels()) { msr_t msr = msr_read(MSR_PKG_POWER_LIMIT);
writel(msr.lo, MCHBAR_REG(0x59A0)); diff --git a/arch/x86/include/asm/arch-ivybridge/model_206ax.h b/arch/x86/include/asm/arch-ivybridge/model_206ax.h index 10caaa24226..4839ebc3124 100644 --- a/arch/x86/include/asm/arch-ivybridge/model_206ax.h +++ b/arch/x86/include/asm/arch-ivybridge/model_206ax.h @@ -58,6 +58,6 @@
/* Configure power limits for turbo mode */ void set_power_limits(u8 power_limit_1_time); -int cpu_config_tdp_levels(void); +bool cpu_ivybridge_config_tdp_levels(void);
#endif diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index 3d093021ae6..e6a2a0eb3e5 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* + * Common code for Intel CPUs + * * Copyright (c) 2016 Google, Inc */
@@ -56,4 +58,20 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk_mz); */ int cpu_configure_thermal_target(struct udevice *dev);
+/** + * cpu_set_perf_control() - Set the nominal CPU clock speed + * + * This sets the clock speed as a muiltiplier of BCLK + * + * @clk_ratio: Ratio to use + */ +void cpu_set_perf_control(uint clk_ratio); + +/** + * cpu_config_tdp_levels() - Check for configurable TDP option + * + * @return true if the CPU has configurable TDP (Thermal-desgn power) + */ +bool cpu_config_tdp_levels(void); + #endif

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions are the same on modern Intel CPUs, so use common code to set them.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 7 ++---- arch/x86/cpu/broadwell/cpu_full.c | 9 ------- arch/x86/cpu/intel_common/cpu.c | 20 +++++++++++++++ arch/x86/cpu/ivybridge/model_206ax.c | 25 +++++++------------ arch/x86/cpu/ivybridge/northbridge.c | 2 +- .../include/asm/arch-ivybridge/model_206ax.h | 2 +- arch/x86/include/asm/cpu_common.h | 18 +++++++++++++ 7 files changed, 51 insertions(+), 32 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index 586a2e8f05a..55a7439f1c1 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -41,12 +41,9 @@ int arch_cpu_init_dm(void)
void set_max_freq(void) {
msr_t msr, perf_ctl, platform_info;
msr_t msr, perf_ctl;
/* Check for configurable TDP option */
platform_info = msr_read(MSR_PLATFORM_INFO);
if ((platform_info.hi >> 1) & 3) {
if (cpu_config_tdp_levels()) { /* Set to nominal TDP ratio */ msr = msr_read(MSR_CONFIG_TDP_NOMINAL); perf_ctl.lo = (msr.lo & 0xff) << 8;
diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index 58cc2f362cc..169b5b02a6a 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -329,15 +329,6 @@ static int bsp_init_before_ap_bringup(struct udevice *dev) 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; diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 7d0ed73b4b6..1898903853f 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -145,3 +145,23 @@ int cpu_configure_thermal_target(struct udevice *dev)
return 0;
}
+void cpu_set_perf_control(uint clk_ratio) +{
msr_t perf_ctl;
perf_ctl.lo = (clk_ratio & 0xff) << 8;
perf_ctl.hi = 0;
msr_write(MSR_IA32_PERF_CTL, perf_ctl);
debug("CPU: frequency set to %d MHz\n", clk_ratio * INTEL_BCLK_MHZ);
+}
+bool 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) != 0;
+} diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 3177ba3297f..2c8cedbaea2 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -140,19 +140,16 @@ static const u8 power_limit_time_msr_to_sec[] = { [0x11] = 128, };
-int cpu_config_tdp_levels(void) +bool cpu_ivybridge_config_tdp_levels(void) { struct cpuid_result result;
msr_t platform_info; /* Minimum CPU revision */ result = cpuid(1); if (result.eax < IVB_CONFIG_TDP_MIN_CPUID) return 0;
We should return false here, since the return value type is now changed to bool.
/* Bits 34:33 indicate how many levels supported */
platform_info = msr_read(MSR_PLATFORM_INFO);
return (platform_info.hi >> 1) & 3;
return cpu_config_tdp_levels();
}
/* @@ -213,7 +210,7 @@ void set_power_limits(u8 power_limit_1_time) msr_write(MSR_PKG_POWER_LIMIT, limit);
/* Use nominal TDP values for CPUs with configurable TDP */
if (cpu_config_tdp_levels()) {
if (cpu_ivybridge_config_tdp_levels()) { msr = msr_read(MSR_CONFIG_TDP_NOMINAL); limit.hi = 0; limit.lo = msr.lo & 0xff;
@@ -329,24 +326,20 @@ static void configure_dca_cap(void)
static void set_max_ratio(void) {
msr_t msr, perf_ctl;
perf_ctl.hi = 0;
msr_t msr;
uint ratio; /* Check for configurable TDP option */
if (cpu_config_tdp_levels()) {
if (cpu_ivybridge_config_tdp_levels()) { /* Set to nominal TDP ratio */ msr = msr_read(MSR_CONFIG_TDP_NOMINAL);
perf_ctl.lo = (msr.lo & 0xff) << 8;
ratio = msr.lo & 0xff; } else { /* Platform Info bits 15:8 give max ratio */ msr = msr_read(MSR_PLATFORM_INFO);
perf_ctl.lo = msr.lo & 0xff00;
ratio = (msr.lo & 0xff00) >> 8; }
msr_write(MSR_IA32_PERF_CTL, perf_ctl);
debug("model_x06ax: frequency set to %d\n",
((perf_ctl.lo >> 8) & 0xff) * INTEL_BCLK_MHZ);
cpu_set_perf_control(ratio);
}
static void set_energy_perf_bias(u8 policy) diff --git a/arch/x86/cpu/ivybridge/northbridge.c b/arch/x86/cpu/ivybridge/northbridge.c index a809b823b3b..0f427afcb82 100644 --- a/arch/x86/cpu/ivybridge/northbridge.c +++ b/arch/x86/cpu/ivybridge/northbridge.c @@ -141,7 +141,7 @@ static void northbridge_init(struct udevice *dev, int rev) * CPUs with configurable TDP also need power limits set * in MCHBAR. Use same values from MSR_PKG_POWER_LIMIT. */
if (cpu_config_tdp_levels()) {
if (cpu_ivybridge_config_tdp_levels()) { msr_t msr = msr_read(MSR_PKG_POWER_LIMIT); writel(msr.lo, MCHBAR_REG(0x59A0));
diff --git a/arch/x86/include/asm/arch-ivybridge/model_206ax.h b/arch/x86/include/asm/arch-ivybridge/model_206ax.h index 10caaa24226..4839ebc3124 100644 --- a/arch/x86/include/asm/arch-ivybridge/model_206ax.h +++ b/arch/x86/include/asm/arch-ivybridge/model_206ax.h @@ -58,6 +58,6 @@
/* Configure power limits for turbo mode */ void set_power_limits(u8 power_limit_1_time); -int cpu_config_tdp_levels(void); +bool cpu_ivybridge_config_tdp_levels(void);
#endif diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index 3d093021ae6..e6a2a0eb3e5 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /*
- Common code for Intel CPUs
*/
- Copyright (c) 2016 Google, Inc
@@ -56,4 +58,20 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk_mz); */ int cpu_configure_thermal_target(struct udevice *dev);
+/**
- cpu_set_perf_control() - Set the nominal CPU clock speed
- This sets the clock speed as a muiltiplier of BCLK
- @clk_ratio: Ratio to use
- */
+void cpu_set_perf_control(uint clk_ratio);
+/**
- cpu_config_tdp_levels() - Check for configurable TDP option
- @return true if the CPU has configurable TDP (Thermal-desgn power)
- */
+bool cpu_config_tdp_levels(void);
#endif
Other than above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 12:09 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions are the same on modern Intel CPUs, so use common code to set them.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 7 ++---- arch/x86/cpu/broadwell/cpu_full.c | 9 ------- arch/x86/cpu/intel_common/cpu.c | 20 +++++++++++++++ arch/x86/cpu/ivybridge/model_206ax.c | 25 +++++++------------ arch/x86/cpu/ivybridge/northbridge.c | 2 +- .../include/asm/arch-ivybridge/model_206ax.h | 2 +- arch/x86/include/asm/cpu_common.h | 18 +++++++++++++ 7 files changed, 51 insertions(+), 32 deletions(-)
[snip]
diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index 3d093021ae6..e6a2a0eb3e5 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /*
- Common code for Intel CPUs
*/
- Copyright (c) 2016 Google, Inc
@@ -56,4 +58,20 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk_mz); */ int cpu_configure_thermal_target(struct udevice *dev);
+/**
- cpu_set_perf_control() - Set the nominal CPU clock speed
- This sets the clock speed as a muiltiplier of BCLK
typo: multiplier
- @clk_ratio: Ratio to use
- */
+void cpu_set_perf_control(uint clk_ratio);
+/**
- cpu_config_tdp_levels() - Check for configurable TDP option
- @return true if the CPU has configurable TDP (Thermal-desgn power)
typo: design
- */
+bool cpu_config_tdp_levels(void);
#endif
Will fix these typos when applying.

On Mon, Oct 7, 2019 at 12:15 AM Bin Meng bmeng.cn@gmail.com wrote:
On Mon, Oct 7, 2019 at 12:09 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
These functions are the same on modern Intel CPUs, so use common code to set them.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/cpu.c | 7 ++---- arch/x86/cpu/broadwell/cpu_full.c | 9 ------- arch/x86/cpu/intel_common/cpu.c | 20 +++++++++++++++ arch/x86/cpu/ivybridge/model_206ax.c | 25 +++++++------------ arch/x86/cpu/ivybridge/northbridge.c | 2 +- .../include/asm/arch-ivybridge/model_206ax.h | 2 +- arch/x86/include/asm/cpu_common.h | 18 +++++++++++++ 7 files changed, 51 insertions(+), 32 deletions(-)
[snip]
diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index 3d093021ae6..e6a2a0eb3e5 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -1,5 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /*
- Common code for Intel CPUs
*/
- Copyright (c) 2016 Google, Inc
@@ -56,4 +58,20 @@ int cpu_intel_get_info(struct cpu_info *info, int bclk_mz); */ int cpu_configure_thermal_target(struct udevice *dev);
+/**
- cpu_set_perf_control() - Set the nominal CPU clock speed
- This sets the clock speed as a muiltiplier of BCLK
typo: multiplier
- @clk_ratio: Ratio to use
- */
+void cpu_set_perf_control(uint clk_ratio);
+/**
- cpu_config_tdp_levels() - Check for configurable TDP option
- @return true if the CPU has configurable TDP (Thermal-desgn power)
typo: design
- */
+bool cpu_config_tdp_levels(void);
#endif
Will fix these typos when applying.
Fixed return value as false, and these typos, and,
applied to u-boot-x86/next, thanks!

Some MSR registers are defined twice in different parts of the file. Move them together and remove the duplicates. Also drop some thermal defines which are not used.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/baytrail/cpu.c | 6 +- arch/x86/cpu/broadwell/cpu_full.c | 6 +- arch/x86/cpu/turbo.c | 10 +-- arch/x86/include/asm/msr-index.h | 106 ++++++++++++------------------ 4 files changed, 54 insertions(+), 74 deletions(-)
diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c index 2eb917283bc..9394eab956b 100644 --- a/arch/x86/cpu/baytrail/cpu.c +++ b/arch/x86/cpu/baytrail/cpu.c @@ -68,9 +68,9 @@ static void set_max_freq(void) msr_t msr;
/* Enable speed step */ - msr = msr_read(MSR_IA32_MISC_ENABLES); - msr.lo |= (1 << 16); - msr_write(MSR_IA32_MISC_ENABLES, msr); + msr = msr_read(MSR_IA32_MISC_ENABLE); + msr.lo |= MISC_ENABLE_ENHANCED_SPEEDSTEP; + msr_write(MSR_IA32_MISC_ENABLE, msr);
/* * Set guaranteed ratio [21:16] from IACORE_RATIOS to bits [15:8] of diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index 169b5b02a6a..895edeb4bc4 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -470,9 +470,9 @@ 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.lo |= MISC_ENABLE_FAST_STRING; + msr.lo |= MISC_ENABLE_TM1; + msr.lo |= MISC_ENABLE_ENHANCED_SPEEDSTEP; msr_write(MSR_IA32_MISC_ENABLE, msr);
/* Disable thermal interrupts */ diff --git a/arch/x86/cpu/turbo.c b/arch/x86/cpu/turbo.c index a41d511238d..be468d2b2ca 100644 --- a/arch/x86/cpu/turbo.c +++ b/arch/x86/cpu/turbo.c @@ -60,8 +60,8 @@ int turbo_get_state(void) cpuid_regs = cpuid(CPUID_LEAF_PM); turbo_cap = !!(cpuid_regs.eax & PM_CAP_TURBO_MODE);
- msr = msr_read(MSR_IA32_MISC_ENABLES); - turbo_en = !(msr.hi & H_MISC_DISABLE_TURBO); + msr = msr_read(MSR_IA32_MISC_ENABLE); + turbo_en = !(msr.hi & MISC_DISABLE_TURBO);
if (!turbo_cap && turbo_en) { /* Unavailable */ @@ -86,9 +86,9 @@ void turbo_enable(void) /* Only possible if turbo is available but hidden */ if (turbo_get_state() == TURBO_DISABLED) { /* Clear Turbo Disable bit in Misc Enables */ - msr = msr_read(MSR_IA32_MISC_ENABLES); - msr.hi &= ~H_MISC_DISABLE_TURBO; - msr_write(MSR_IA32_MISC_ENABLES, msr); + msr = msr_read(MSR_IA32_MISC_ENABLE); + msr.hi &= ~MISC_DISABLE_TURBO; + msr_write(MSR_IA32_MISC_ENABLE, msr);
/* Update cached turbo state */ set_global_turbo_state(TURBO_ENABLED); diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 7cb78beafa1..74c436072f6 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -92,7 +92,38 @@ /* This is burst mode BIT 38 in IA32_MISC_ENABLE MSR at offset 1A0h */ #define BURST_MODE_DISABLE (1 << 6)
-#define MSR_IA32_MISC_ENABLES 0x000001a0 +#define MSR_IA32_MISC_ENABLE 0x000001a0 + +/* MISC_ENABLE bits: architectural */ +#define MISC_ENABLE_FAST_STRING BIT_ULL(0) +#define MISC_ENABLE_TCC BIT_ULL(1) +#define MISC_DISABLE_TURBO BIT_ULL(6) +#define MISC_ENABLE_EMON BIT_ULL(7) +#define MISC_ENABLE_BTS_UNAVAIL BIT_ULL(11) +#define MISC_ENABLE_PEBS_UNAVAIL BIT_ULL(12) +#define MISC_ENABLE_ENHANCED_SPEEDSTEP BIT_ULL(16) +#define MISC_ENABLE_MWAIT BIT_ULL(18) +#define MISC_ENABLE_LIMIT_CPUID BIT_ULL(22) +#define MISC_ENABLE_XTPR_DISABLE BIT_ULL(23) +#define MISC_ENABLE_XD_DISABLE BIT_ULL(34) + +/* MISC_ENABLE bits: model-specific, meaning may vary from core to core */ +#define MISC_ENABLE_X87_COMPAT BIT_ULL(2) +#define MISC_ENABLE_TM1 BIT_ULL(3) +#define MISC_ENABLE_SPLIT_LOCK_DISABLE BIT_ULL(4) +#define MISC_ENABLE_L3CACHE_DISABLE BIT_ULL(6) +#define MISC_ENABLE_SUPPRESS_LOCK BIT_ULL(8) +#define MISC_ENABLE_PREFETCH_DISABLE BIT_ULL(9) +#define MISC_ENABLE_FERR BIT_ULL(10) +#define MISC_ENABLE_FERR_MULTIPLEX BIT_ULL(10) +#define MISC_ENABLE_TM2 BIT_ULL(13) +#define MISC_ENABLE_ADJ_PREF_DISABLE BIT_ULL(19) +#define MISC_ENABLE_SPEEDSTEP_LOCK BIT_ULL(20) +#define MISC_ENABLE_L1D_CONTEXT BIT_ULL(24) +#define MISC_ENABLE_DCU_PREF_DISABLE BIT_ULL(37) +#define MISC_ENABLE_TURBO_DISABLE BIT_ULL(38) +#define MISC_ENABLE_IP_PREF_DISABLE BIT_ULL(39) + #define MSR_TEMPERATURE_TARGET 0x1a2 #define MSR_PREFETCH_CTL 0x1a4 #define PREFETCH_L1_DISABLE (1 << 0) @@ -109,6 +140,17 @@ #define ENERGY_POLICY_NORMAL 6 #define ENERGY_POLICY_POWERSAVE 15
+#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 + +#define PACKAGE_THERM_STATUS_PROCHOT BIT(0) +#define PACKAGE_THERM_STATUS_POWER_LIMIT BIT(10) + +#define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2 + +#define PACKAGE_THERM_INT_HIGH_ENABLE BIT(0) +#define PACKAGE_THERM_INT_LOW_ENABLE BIT(1) +#define PACKAGE_THERM_INT_PLN_ENABLE BIT(24) + #define MSR_LBR_SELECT 0x000001c8 #define MSR_LBR_TOS 0x000001c9 #define MSR_IA32_PLATFORM_DCA_CAP 0x1f8 @@ -420,68 +462,6 @@
#define MSR_THERM2_CTL_TM_SELECT (1ULL << 16)
-#define MSR_IA32_MISC_ENABLE 0x000001a0 -#define H_MISC_DISABLE_TURBO (1 << 6) - -#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2 - -#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 -#define ENERGY_PERF_BIAS_PERFORMANCE 0 -#define ENERGY_PERF_BIAS_NORMAL 6 -#define ENERGY_PERF_BIAS_POWERSAVE 15 - -#define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 - -#define PACKAGE_THERM_STATUS_PROCHOT (1 << 0) -#define PACKAGE_THERM_STATUS_POWER_LIMIT (1 << 10) - -#define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2 - -#define PACKAGE_THERM_INT_HIGH_ENABLE (1 << 0) -#define PACKAGE_THERM_INT_LOW_ENABLE (1 << 1) -#define PACKAGE_THERM_INT_PLN_ENABLE (1 << 24) - -/* Thermal Thresholds Support */ -#define THERM_INT_THRESHOLD0_ENABLE (1 << 15) -#define THERM_SHIFT_THRESHOLD0 8 -#define THERM_MASK_THRESHOLD0 (0x7f << THERM_SHIFT_THRESHOLD0) -#define THERM_INT_THRESHOLD1_ENABLE (1 << 23) -#define THERM_SHIFT_THRESHOLD1 16 -#define THERM_MASK_THRESHOLD1 (0x7f << THERM_SHIFT_THRESHOLD1) -#define THERM_STATUS_THRESHOLD0 (1 << 6) -#define THERM_LOG_THRESHOLD0 (1 << 7) -#define THERM_STATUS_THRESHOLD1 (1 << 8) -#define THERM_LOG_THRESHOLD1 (1 << 9) - -/* MISC_ENABLE bits: architectural */ -#define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0) -#define MSR_IA32_MISC_ENABLE_TCC (1ULL << 1) -#define MSR_IA32_MISC_ENABLE_EMON (1ULL << 7) -#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1ULL << 11) -#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1ULL << 12) -#define MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP (1ULL << 16) -#define MSR_IA32_MISC_ENABLE_MWAIT (1ULL << 18) -#define MSR_IA32_MISC_ENABLE_LIMIT_CPUID (1ULL << 22) -#define MSR_IA32_MISC_ENABLE_XTPR_DISABLE (1ULL << 23) -#define MSR_IA32_MISC_ENABLE_XD_DISABLE (1ULL << 34) - -/* MISC_ENABLE bits: model-specific, meaning may vary from core to core */ -#define MSR_IA32_MISC_ENABLE_X87_COMPAT (1ULL << 2) -#define MSR_IA32_MISC_ENABLE_TM1 (1ULL << 3) -#define MSR_IA32_MISC_ENABLE_SPLIT_LOCK_DISABLE (1ULL << 4) -#define MSR_IA32_MISC_ENABLE_L3CACHE_DISABLE (1ULL << 6) -#define MSR_IA32_MISC_ENABLE_SUPPRESS_LOCK (1ULL << 8) -#define MSR_IA32_MISC_ENABLE_PREFETCH_DISABLE (1ULL << 9) -#define MSR_IA32_MISC_ENABLE_FERR (1ULL << 10) -#define MSR_IA32_MISC_ENABLE_FERR_MULTIPLEX (1ULL << 10) -#define MSR_IA32_MISC_ENABLE_TM2 (1ULL << 13) -#define MSR_IA32_MISC_ENABLE_ADJ_PREF_DISABLE (1ULL << 19) -#define MSR_IA32_MISC_ENABLE_SPEEDSTEP_LOCK (1ULL << 20) -#define MSR_IA32_MISC_ENABLE_L1D_CONTEXT (1ULL << 24) -#define MSR_IA32_MISC_ENABLE_DCU_PREF_DISABLE (1ULL << 37) -#define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38) -#define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39) - #define MSR_IA32_TSC_DEADLINE 0x000006E0
/* P4/Xeon+ specific */

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Some MSR registers are defined twice in different parts of the file. Move them together and remove the duplicates. Also drop some thermal defines which are not used.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/baytrail/cpu.c | 6 +- arch/x86/cpu/broadwell/cpu_full.c | 6 +- arch/x86/cpu/turbo.c | 10 +-- arch/x86/include/asm/msr-index.h | 106 ++++++++++++------------------ 4 files changed, 54 insertions(+), 74 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 12:09 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Some MSR registers are defined twice in different parts of the file. Move them together and remove the duplicates. Also drop some thermal defines which are not used.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/baytrail/cpu.c | 6 +- arch/x86/cpu/broadwell/cpu_full.c | 6 +- arch/x86/cpu/turbo.c | 10 +-- arch/x86/include/asm/msr-index.h | 106 ++++++++++++------------------ 4 files changed, 54 insertions(+), 74 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Add a few more CPU functions that are common on Intel CPUs. Also add attribution for the code source.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/intel_common/cpu.c | 60 +++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu_common.h | 49 +++++++++++++++++++++++++ 2 files changed, 109 insertions(+)
diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 1898903853f..e4ce1b0703e 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -1,12 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2016 Google, Inc + * Copyright (C) 2014 Google Inc. + * Copyright (C) 2015-2018 Intel Corporation. + * Copyright (C) 2018 Siemens AG + * Some code taken from coreboot cpulib.c */
#include <common.h> #include <cpu.h> #include <dm.h> #include <errno.h> +#include <asm/cpu.h> #include <asm/cpu_common.h> #include <asm/intel_regs.h> #include <asm/lapic.h> @@ -165,3 +170,58 @@ bool cpu_config_tdp_levels(void)
return ((platform_info.hi >> 1) & 3) != 0; } + +void cpu_set_p_state_to_turbo_ratio(void) +{ + msr_t msr; + + msr = msr_read(MSR_TURBO_RATIO_LIMIT); + cpu_set_perf_control(msr.lo); +} + +enum burst_mode_t cpu_get_burst_mode_state(void) +{ + enum burst_mode_t state; + int burst_en, burst_cap; + msr_t msr; + uint eax; + + eax = cpuid_eax(0x6); + burst_cap = eax & 0x2; + msr = msr_read(MSR_IA32_MISC_ENABLE); + burst_en = !(msr.hi & BURST_MODE_DISABLE); + + if (!burst_cap && burst_en) + state = BURST_MODE_UNAVAILABLE; + else if (burst_cap && !burst_en) + state = BURST_MODE_DISABLED; + else if (burst_cap && burst_en) + state = BURST_MODE_ENABLED; + else + state = BURST_MODE_UNKNOWN; + + return state; +} + +void cpu_set_burst_mode(bool burst_mode) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_MISC_ENABLE); + if (burst_mode) + msr.hi &= ~BURST_MODE_DISABLE; + else + msr.hi |= BURST_MODE_DISABLE; + msr_write(MSR_IA32_MISC_ENABLE, msr); +} + +void cpu_set_eist(bool eist_status) +{ + msr_t msr; + + msr = msr_read(MSR_IA32_MISC_ENABLE); + if (eist_status) + msr.lo |= MISC_ENABLE_ENHANCED_SPEEDSTEP; + else + msr.lo &= ~MISC_ENABLE_ENHANCED_SPEEDSTEP; +} diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index e6a2a0eb3e5..d5c09dccae0 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -74,4 +74,53 @@ void cpu_set_perf_control(uint clk_ratio); */ bool cpu_config_tdp_levels(void);
+/** enum burst_mode_t - Burst-mode states */ +enum burst_mode_t { + BURST_MODE_UNKNOWN, + BURST_MODE_UNAVAILABLE, + BURST_MODE_DISABLED, + BURST_MODE_ENABLED +}; + +/* + * cpu_get_burst_mode_state() - Get the Burst/Turbo Mode State + * + * This reads MSR IA32_MISC_ENABLE 0x1A0 + * Bit 38 - TURBO_MODE_DISABLE Bit to get state ENABLED / DISABLED. + * Also checks cpuid 0x6 to see whether Burst mode us supported. + * + * @return current burst mode status + */ +enum burst_mode_t cpu_get_burst_mode_state(void); + +/** + * cpu_set_burst_mode() - Set CPU burst mode + * + * @burst_mode: true to enable burst mode, false to disable + */ +void cpu_set_burst_mode(bool burst_mode); + +/** + * cpu_set_eist() - Enable Enhanced Intel Speed Step Technology + * + * @eist_status: true to enable EIST, false to disable + */ +void cpu_set_eist(bool eist_status); + +/** + * cpu_set_p_state_to_turbo_ratio() - Set turbo ratio + * + * TURBO_RATIO_LIMIT MSR (0x1AD) Bits 31:0 indicates the + * factory configured values for of 1-core, 2-core, 3-core + * and 4-core turbo ratio limits for all processors. + * + * 7:0 - MAX_TURBO_1_CORE + * 15:8 - MAX_TURBO_2_CORES + * 23:16 - MAX_TURBO_3_CORES + * 31:24 - MAX_TURBO_4_CORES + * + * Set PERF_CTL MSR (0x199) P_Req with that value. + */ +void cpu_set_p_state_to_turbo_ratio(void); + #endif

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Add a few more CPU functions that are common on Intel CPUs. Also add attribution for the code source.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/intel_common/cpu.c | 60 +++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu_common.h | 49 +++++++++++++++++++++++++ 2 files changed, 109 insertions(+)
diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 1898903853f..e4ce1b0703e 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -1,12 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 /*
- Copyright (c) 2016 Google, Inc
nits: put this line after 2014 below?
- Copyright (C) 2014 Google Inc.
- Copyright (C) 2015-2018 Intel Corporation.
- Copyright (C) 2018 Siemens AG
*/
- Some code taken from coreboot cpulib.c
#include <common.h> #include <cpu.h> #include <dm.h> #include <errno.h> +#include <asm/cpu.h> #include <asm/cpu_common.h> #include <asm/intel_regs.h> #include <asm/lapic.h> @@ -165,3 +170,58 @@ bool cpu_config_tdp_levels(void)
return ((platform_info.hi >> 1) & 3) != 0;
}
+void cpu_set_p_state_to_turbo_ratio(void) +{
msr_t msr;
msr = msr_read(MSR_TURBO_RATIO_LIMIT);
cpu_set_perf_control(msr.lo);
+}
+enum burst_mode_t cpu_get_burst_mode_state(void) +{
enum burst_mode_t state;
int burst_en, burst_cap;
msr_t msr;
uint eax;
eax = cpuid_eax(0x6);
burst_cap = eax & 0x2;
msr = msr_read(MSR_IA32_MISC_ENABLE);
burst_en = !(msr.hi & BURST_MODE_DISABLE);
if (!burst_cap && burst_en)
state = BURST_MODE_UNAVAILABLE;
else if (burst_cap && !burst_en)
state = BURST_MODE_DISABLED;
else if (burst_cap && burst_en)
state = BURST_MODE_ENABLED;
else
state = BURST_MODE_UNKNOWN;
return state;
+}
+void cpu_set_burst_mode(bool burst_mode) +{
msr_t msr;
msr = msr_read(MSR_IA32_MISC_ENABLE);
if (burst_mode)
msr.hi &= ~BURST_MODE_DISABLE;
else
msr.hi |= BURST_MODE_DISABLE;
msr_write(MSR_IA32_MISC_ENABLE, msr);
+}
+void cpu_set_eist(bool eist_status) +{
msr_t msr;
msr = msr_read(MSR_IA32_MISC_ENABLE);
if (eist_status)
msr.lo |= MISC_ENABLE_ENHANCED_SPEEDSTEP;
else
msr.lo &= ~MISC_ENABLE_ENHANCED_SPEEDSTEP;
There is no write back to the MSR_IA32_MISC_ENABLE.
+} diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index e6a2a0eb3e5..d5c09dccae0 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -74,4 +74,53 @@ void cpu_set_perf_control(uint clk_ratio); */ bool cpu_config_tdp_levels(void);
+/** enum burst_mode_t - Burst-mode states */ +enum burst_mode_t {
BURST_MODE_UNKNOWN,
BURST_MODE_UNAVAILABLE,
BURST_MODE_DISABLED,
BURST_MODE_ENABLED
+};
+/*
- cpu_get_burst_mode_state() - Get the Burst/Turbo Mode State
- This reads MSR IA32_MISC_ENABLE 0x1A0
- Bit 38 - TURBO_MODE_DISABLE Bit to get state ENABLED / DISABLED.
- Also checks cpuid 0x6 to see whether Burst mode us supported.
nits: Burst -> burst, us -> is
- @return current burst mode status
- */
+enum burst_mode_t cpu_get_burst_mode_state(void);
+/**
- cpu_set_burst_mode() - Set CPU burst mode
- @burst_mode: true to enable burst mode, false to disable
- */
+void cpu_set_burst_mode(bool burst_mode);
+/**
- cpu_set_eist() - Enable Enhanced Intel Speed Step Technology
- @eist_status: true to enable EIST, false to disable
- */
+void cpu_set_eist(bool eist_status);
+/**
- cpu_set_p_state_to_turbo_ratio() - Set turbo ratio
- TURBO_RATIO_LIMIT MSR (0x1AD) Bits 31:0 indicates the
- factory configured values for of 1-core, 2-core, 3-core
- and 4-core turbo ratio limits for all processors.
- 7:0 - MAX_TURBO_1_CORE
- 15:8 - MAX_TURBO_2_CORES
- 23:16 - MAX_TURBO_3_CORES
- 31:24 - MAX_TURBO_4_CORES
- Set PERF_CTL MSR (0x199) P_Req with that value.
- */
+void cpu_set_p_state_to_turbo_ratio(void);
#endif
Other than above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 8:32 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Add a few more CPU functions that are common on Intel CPUs. Also add attribution for the code source.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/intel_common/cpu.c | 60 +++++++++++++++++++++++++++++++ arch/x86/include/asm/cpu_common.h | 49 +++++++++++++++++++++++++ 2 files changed, 109 insertions(+)
diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index 1898903853f..e4ce1b0703e 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -1,12 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 /*
- Copyright (c) 2016 Google, Inc
nits: put this line after 2014 below?
- Copyright (C) 2014 Google Inc.
- Copyright (C) 2015-2018 Intel Corporation.
- Copyright (C) 2018 Siemens AG
*/
- Some code taken from coreboot cpulib.c
#include <common.h> #include <cpu.h> #include <dm.h> #include <errno.h> +#include <asm/cpu.h> #include <asm/cpu_common.h> #include <asm/intel_regs.h> #include <asm/lapic.h> @@ -165,3 +170,58 @@ bool cpu_config_tdp_levels(void)
return ((platform_info.hi >> 1) & 3) != 0;
}
+void cpu_set_p_state_to_turbo_ratio(void) +{
msr_t msr;
msr = msr_read(MSR_TURBO_RATIO_LIMIT);
cpu_set_perf_control(msr.lo);
+}
+enum burst_mode_t cpu_get_burst_mode_state(void) +{
enum burst_mode_t state;
int burst_en, burst_cap;
msr_t msr;
uint eax;
eax = cpuid_eax(0x6);
burst_cap = eax & 0x2;
msr = msr_read(MSR_IA32_MISC_ENABLE);
burst_en = !(msr.hi & BURST_MODE_DISABLE);
if (!burst_cap && burst_en)
state = BURST_MODE_UNAVAILABLE;
else if (burst_cap && !burst_en)
state = BURST_MODE_DISABLED;
else if (burst_cap && burst_en)
state = BURST_MODE_ENABLED;
else
state = BURST_MODE_UNKNOWN;
return state;
+}
+void cpu_set_burst_mode(bool burst_mode) +{
msr_t msr;
msr = msr_read(MSR_IA32_MISC_ENABLE);
if (burst_mode)
msr.hi &= ~BURST_MODE_DISABLE;
else
msr.hi |= BURST_MODE_DISABLE;
msr_write(MSR_IA32_MISC_ENABLE, msr);
+}
+void cpu_set_eist(bool eist_status) +{
msr_t msr;
msr = msr_read(MSR_IA32_MISC_ENABLE);
if (eist_status)
msr.lo |= MISC_ENABLE_ENHANCED_SPEEDSTEP;
else
msr.lo &= ~MISC_ENABLE_ENHANCED_SPEEDSTEP;
There is no write back to the MSR_IA32_MISC_ENABLE.
+} diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index e6a2a0eb3e5..d5c09dccae0 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -74,4 +74,53 @@ void cpu_set_perf_control(uint clk_ratio); */ bool cpu_config_tdp_levels(void);
+/** enum burst_mode_t - Burst-mode states */ +enum burst_mode_t {
BURST_MODE_UNKNOWN,
BURST_MODE_UNAVAILABLE,
BURST_MODE_DISABLED,
BURST_MODE_ENABLED
+};
+/*
- cpu_get_burst_mode_state() - Get the Burst/Turbo Mode State
- This reads MSR IA32_MISC_ENABLE 0x1A0
- Bit 38 - TURBO_MODE_DISABLE Bit to get state ENABLED / DISABLED.
- Also checks cpuid 0x6 to see whether Burst mode us supported.
nits: Burst -> burst, us -> is
- @return current burst mode status
- */
+enum burst_mode_t cpu_get_burst_mode_state(void);
+/**
- cpu_set_burst_mode() - Set CPU burst mode
- @burst_mode: true to enable burst mode, false to disable
- */
+void cpu_set_burst_mode(bool burst_mode);
+/**
- cpu_set_eist() - Enable Enhanced Intel Speed Step Technology
- @eist_status: true to enable EIST, false to disable
- */
+void cpu_set_eist(bool eist_status);
+/**
- cpu_set_p_state_to_turbo_ratio() - Set turbo ratio
- TURBO_RATIO_LIMIT MSR (0x1AD) Bits 31:0 indicates the
- factory configured values for of 1-core, 2-core, 3-core
- and 4-core turbo ratio limits for all processors.
- 7:0 - MAX_TURBO_1_CORE
- 15:8 - MAX_TURBO_2_CORES
- 23:16 - MAX_TURBO_3_CORES
- 31:24 - MAX_TURBO_4_CORES
- Set PERF_CTL MSR (0x199) P_Req with that value.
- */
+void cpu_set_p_state_to_turbo_ratio(void);
#endif
Other than above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Fixed all the issues above, and
applied to u-boot-x86/next, thanks!

This function ise effectively replaced by ofnode_read_pci_addr() which works with flat tree. Delete it to avoid code duplication.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/core/fdtaddr.c | 13 ++++------ include/fdtdec.h | 17 ------------- lib/fdtdec.c | 54 ------------------------------------------ 3 files changed, 5 insertions(+), 79 deletions(-)
diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c index c9a941116a3..575798fae93 100644 --- a/drivers/core/fdtaddr.c +++ b/drivers/core/fdtaddr.c @@ -202,16 +202,13 @@ fdt_addr_t devfdt_get_addr_pci(struct udevice *dev) u32 bar; int ret;
- ret = fdtdec_get_pci_addr(gd->fdt_blob, - dev_of_offset(dev), - FDT_PCI_SPACE_MEM32, "reg", - &pci_addr); + ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32, + "reg", &pci_addr); if (ret) { /* try if there is any i/o-mapped register */ - ret = fdtdec_get_pci_addr(gd->fdt_blob, - dev_of_offset(dev), - FDT_PCI_SPACE_IO, "reg", - &pci_addr); + ret = ofnode_read_pci_addr(dev_ofnode(dev), + FDT_PCI_SPACE_IO, "reg", + &pci_addr); if (ret) return FDT_ADDR_T_NONE; } diff --git a/include/fdtdec.h b/include/fdtdec.h index 635f53083b7..f1e58f9732d 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -416,23 +416,6 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node, fdt_addr_t fdtdec_get_addr_size(const void *blob, int node, const char *prop_name, fdt_size_t *sizep);
-/** - * Look at an address property in a node and return the pci address which - * corresponds to the given type in the form of fdt_pci_addr. - * The property must hold one fdt_pci_addr with a lengh. - * - * @param blob FDT blob - * @param node node to examine - * @param type pci address type (FDT_PCI_SPACE_xxx) - * @param prop_name name of property to find - * @param addr returns pci address in the form of fdt_pci_addr - * @return 0 if ok, -ENOENT if the property did not exist, -EINVAL if the - * format of the property was invalid, -ENXIO if the requested - * address type was not found - */ -int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, - const char *prop_name, struct fdt_pci_addr *addr); - /** * Look at the compatible property of a device node that represents a PCI * device and extract pci vendor id and device id from it. diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 74430c8b2ff..17736ce6655 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -186,60 +186,6 @@ fdt_addr_t fdtdec_get_addr(const void *blob, int node, const char *prop_name) }
#if CONFIG_IS_ENABLED(PCI) && defined(CONFIG_DM_PCI) -int fdtdec_get_pci_addr(const void *blob, int node, enum fdt_pci_space type, - const char *prop_name, struct fdt_pci_addr *addr) -{ - const u32 *cell; - int len; - int ret = -ENOENT; - - debug("%s: %s: ", __func__, prop_name); - - /* - * If we follow the pci bus bindings strictly, we should check - * the value of the node's parent node's #address-cells and - * #size-cells. They need to be 3 and 2 accordingly. However, - * for simplicity we skip the check here. - */ - cell = fdt_getprop(blob, node, prop_name, &len); - if (!cell) - goto fail; - - if ((len % FDT_PCI_REG_SIZE) == 0) { - int num = len / FDT_PCI_REG_SIZE; - int i; - - for (i = 0; i < num; i++) { - debug("pci address #%d: %08lx %08lx %08lx\n", i, - (ulong)fdt32_to_cpu(cell[0]), - (ulong)fdt32_to_cpu(cell[1]), - (ulong)fdt32_to_cpu(cell[2])); - if ((fdt32_to_cpu(*cell) & type) == type) { - addr->phys_hi = fdt32_to_cpu(cell[0]); - addr->phys_mid = fdt32_to_cpu(cell[1]); - addr->phys_lo = fdt32_to_cpu(cell[2]); - break; - } - - cell += (FDT_PCI_ADDR_CELLS + - FDT_PCI_SIZE_CELLS); - } - - if (i == num) { - ret = -ENXIO; - goto fail; - } - - return 0; - } - - ret = -EINVAL; - -fail: - debug("(not found)\n"); - return ret; -} - int fdtdec_get_pci_vendev(const void *blob, int node, u16 *vendor, u16 *device) { const char *list, *end;

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This function ise effectively replaced by ofnode_read_pci_addr() which works with flat tree. Delete it to avoid code duplication.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/fdtaddr.c | 13 ++++------ include/fdtdec.h | 17 ------------- lib/fdtdec.c | 54 ------------------------------------------ 3 files changed, 5 insertions(+), 79 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 8:32 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This function ise effectively replaced by ofnode_read_pci_addr() which works with flat tree. Delete it to avoid code duplication.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/core/fdtaddr.c | 13 ++++------ include/fdtdec.h | 17 ------------- lib/fdtdec.c | 54 ------------------------------------------ 3 files changed, 5 insertions(+), 79 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

The code in swapcase can be used by other sandbox drivers. Move it into a common place to allow this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/include/asm/test.h | 15 +++++++++++++++ drivers/misc/Makefile | 2 +- drivers/misc/swap_case.c | 18 +++--------------- drivers/pci/pci-emul-uclass.c | 20 ++++++++++++++++++++ drivers/pci/pci_sandbox.c | 1 + 5 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 1b21af6bed7..cd2b9e3155d 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -198,4 +198,19 @@ int sandbox_get_pch_spi_protect(struct udevice *dev); */ int sandbox_get_pci_ep_irq_count(struct udevice *dev);
+/** + * sandbox_pci_read_bar() - Read the BAR value for a read_config operation + * + * This is used in PCI emulators to read a base address reset. This has special + * rules because when the register is set to 0xffffffff it can be used to + * discover the type and size of the BAR. + * + * @barval: Current value of the BAR + * @type: Type of BAR (PCI_BASE_ADDRESS_SPACE_IO or + * PCI_BASE_ADDRESS_MEM_TYPE_32) + * @size: Size of BAR in bytes + * @return BAR value to return from emulator + */ +uint sandbox_pci_read_bar(u32 barval, int type, uint size); + #endif diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 509c588582d..0001d105bae 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_TPL_)CROS_EC_LPC) += cros_ec_lpc.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o +obj-$(CONFIG_SANDBOX) += swap_case.o endif
ifdef CONFIG_DM_I2C @@ -52,7 +53,6 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o -obj-$(CONFIG_SANDBOX) += swap_case.o obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 75fe6416707..11189d16c83 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -139,25 +139,13 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset, case PCI_BASE_ADDRESS_4: case PCI_BASE_ADDRESS_5: { int barnum; - u32 *bar, result; + u32 *bar;
barnum = pci_offset_to_barnum(offset); bar = &plat->bar[barnum];
- result = *bar; - if (*bar == 0xffffffff) { - if (barinfo[barnum].type) { - result = (~(barinfo[barnum].size - 1) & - PCI_BASE_ADDRESS_IO_MASK) | - PCI_BASE_ADDRESS_SPACE_IO; - } else { - result = (~(barinfo[barnum].size - 1) & - PCI_BASE_ADDRESS_MEM_MASK) | - PCI_BASE_ADDRESS_MEM_TYPE_32; - } - } - debug("r bar %d=%x\n", barnum, result); - *valuep = result; + *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type, + barinfo[barnum].size); break; } case PCI_CAPABILITY_LIST: diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index a70c5e7633d..6e6172836a4 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -43,6 +43,26 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, return *emulp ? 0 : -ENODEV; }
+uint sandbox_pci_read_bar(u32 barval, int type, uint size) +{ + u32 result; + + result = barval; + if (result == 0xffffffff) { + if (type == PCI_BASE_ADDRESS_SPACE_IO) { + result = (~(size - 1) & + PCI_BASE_ADDRESS_IO_MASK) | + PCI_BASE_ADDRESS_SPACE_IO; + } else { + result = (~(size - 1) & + PCI_BASE_ADDRESS_MEM_MASK) | + PCI_BASE_ADDRESS_MEM_TYPE_32; + } + } + + return result; +} + static int sandbox_pci_emul_post_probe(struct udevice *dev) { struct sandbox_pci_emul_priv *priv = dev->uclass->priv; diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c index 2af2b79c05d..2a38d104a09 100644 --- a/drivers/pci/pci_sandbox.c +++ b/drivers/pci/pci_sandbox.c @@ -8,6 +8,7 @@ #include <dm.h> #include <fdtdec.h> #include <pci.h> +#include <asm/test.h>
#define FDT_DEV_INFO_CELLS 4 #define FDT_DEV_INFO_SIZE (FDT_DEV_INFO_CELLS * sizeof(u32))

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The code in swapcase can be used by other sandbox drivers. Move it into a common place to allow this.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/include/asm/test.h | 15 +++++++++++++++ drivers/misc/Makefile | 2 +- drivers/misc/swap_case.c | 18 +++--------------- drivers/pci/pci-emul-uclass.c | 20 ++++++++++++++++++++ drivers/pci/pci_sandbox.c | 1 + 5 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 1b21af6bed7..cd2b9e3155d 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -198,4 +198,19 @@ int sandbox_get_pch_spi_protect(struct udevice *dev); */ int sandbox_get_pci_ep_irq_count(struct udevice *dev);
+/**
- sandbox_pci_read_bar() - Read the BAR value for a read_config operation
- This is used in PCI emulators to read a base address reset. This has special
- rules because when the register is set to 0xffffffff it can be used to
- discover the type and size of the BAR.
- @barval: Current value of the BAR
- @type: Type of BAR (PCI_BASE_ADDRESS_SPACE_IO or
PCI_BASE_ADDRESS_MEM_TYPE_32)
- @size: Size of BAR in bytes
- @return BAR value to return from emulator
- */
+uint sandbox_pci_read_bar(u32 barval, int type, uint size);
#endif diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 509c588582d..0001d105bae 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_TPL_)CROS_EC_LPC) += cros_ec_lpc.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o +obj-$(CONFIG_SANDBOX) += swap_case.o endif
ifdef CONFIG_DM_I2C @@ -52,7 +53,6 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o -obj-$(CONFIG_SANDBOX) += swap_case.o obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 75fe6416707..11189d16c83 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -139,25 +139,13 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset, case PCI_BASE_ADDRESS_4: case PCI_BASE_ADDRESS_5: { int barnum;
u32 *bar, result;
u32 *bar; barnum = pci_offset_to_barnum(offset); bar = &plat->bar[barnum];
result = *bar;
if (*bar == 0xffffffff) {
if (barinfo[barnum].type) {
result = (~(barinfo[barnum].size - 1) &
PCI_BASE_ADDRESS_IO_MASK) |
PCI_BASE_ADDRESS_SPACE_IO;
} else {
result = (~(barinfo[barnum].size - 1) &
PCI_BASE_ADDRESS_MEM_MASK) |
PCI_BASE_ADDRESS_MEM_TYPE_32;
}
}
debug("r bar %d=%x\n", barnum, result);
*valuep = result;
*valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
barinfo[barnum].size); break; } case PCI_CAPABILITY_LIST:
diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index a70c5e7633d..6e6172836a4 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -43,6 +43,26 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, return *emulp ? 0 : -ENODEV; }
+uint sandbox_pci_read_bar(u32 barval, int type, uint size) +{
u32 result;
result = barval;
if (result == 0xffffffff) {
if (type == PCI_BASE_ADDRESS_SPACE_IO) {
result = (~(size - 1) &
PCI_BASE_ADDRESS_IO_MASK) |
PCI_BASE_ADDRESS_SPACE_IO;
} else {
result = (~(size - 1) &
PCI_BASE_ADDRESS_MEM_MASK) |
PCI_BASE_ADDRESS_MEM_TYPE_32;
}
}
return result;
+}
static int sandbox_pci_emul_post_probe(struct udevice *dev) { struct sandbox_pci_emul_priv *priv = dev->uclass->priv; diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c index 2af2b79c05d..2a38d104a09 100644 --- a/drivers/pci/pci_sandbox.c +++ b/drivers/pci/pci_sandbox.c @@ -8,6 +8,7 @@ #include <dm.h> #include <fdtdec.h> #include <pci.h> +#include <asm/test.h>
This change is not needed.
#define FDT_DEV_INFO_CELLS 4
#define FDT_DEV_INFO_SIZE (FDT_DEV_INFO_CELLS * sizeof(u32))
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Regards, Bin

On Mon, Oct 7, 2019 at 8:32 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The code in swapcase can be used by other sandbox drivers. Move it into a common place to allow this.
Signed-off-by: Simon Glass sjg@chromium.org
arch/sandbox/include/asm/test.h | 15 +++++++++++++++ drivers/misc/Makefile | 2 +- drivers/misc/swap_case.c | 18 +++--------------- drivers/pci/pci-emul-uclass.c | 20 ++++++++++++++++++++ drivers/pci/pci_sandbox.c | 1 + 5 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 1b21af6bed7..cd2b9e3155d 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -198,4 +198,19 @@ int sandbox_get_pch_spi_protect(struct udevice *dev); */ int sandbox_get_pci_ep_irq_count(struct udevice *dev);
+/**
- sandbox_pci_read_bar() - Read the BAR value for a read_config operation
- This is used in PCI emulators to read a base address reset. This has special
- rules because when the register is set to 0xffffffff it can be used to
- discover the type and size of the BAR.
- @barval: Current value of the BAR
- @type: Type of BAR (PCI_BASE_ADDRESS_SPACE_IO or
PCI_BASE_ADDRESS_MEM_TYPE_32)
- @size: Size of BAR in bytes
- @return BAR value to return from emulator
- */
+uint sandbox_pci_read_bar(u32 barval, int type, uint size);
#endif diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 509c588582d..0001d105bae 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_$(SPL_TPL_)CROS_EC_LPC) += cros_ec_lpc.o ifndef CONFIG_SPL_BUILD obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o +obj-$(CONFIG_SANDBOX) += swap_case.o endif
ifdef CONFIG_DM_I2C @@ -52,7 +53,6 @@ obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o -obj-$(CONFIG_SANDBOX) += swap_case.o obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index 75fe6416707..11189d16c83 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -139,25 +139,13 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset, case PCI_BASE_ADDRESS_4: case PCI_BASE_ADDRESS_5: { int barnum;
u32 *bar, result;
u32 *bar; barnum = pci_offset_to_barnum(offset); bar = &plat->bar[barnum];
result = *bar;
if (*bar == 0xffffffff) {
if (barinfo[barnum].type) {
result = (~(barinfo[barnum].size - 1) &
PCI_BASE_ADDRESS_IO_MASK) |
PCI_BASE_ADDRESS_SPACE_IO;
} else {
result = (~(barinfo[barnum].size - 1) &
PCI_BASE_ADDRESS_MEM_MASK) |
PCI_BASE_ADDRESS_MEM_TYPE_32;
}
}
debug("r bar %d=%x\n", barnum, result);
*valuep = result;
*valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type,
barinfo[barnum].size); break; } case PCI_CAPABILITY_LIST:
diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index a70c5e7633d..6e6172836a4 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -43,6 +43,26 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, return *emulp ? 0 : -ENODEV; }
+uint sandbox_pci_read_bar(u32 barval, int type, uint size) +{
u32 result;
result = barval;
if (result == 0xffffffff) {
if (type == PCI_BASE_ADDRESS_SPACE_IO) {
result = (~(size - 1) &
PCI_BASE_ADDRESS_IO_MASK) |
PCI_BASE_ADDRESS_SPACE_IO;
} else {
result = (~(size - 1) &
PCI_BASE_ADDRESS_MEM_MASK) |
PCI_BASE_ADDRESS_MEM_TYPE_32;
}
}
return result;
+}
static int sandbox_pci_emul_post_probe(struct udevice *dev) { struct sandbox_pci_emul_priv *priv = dev->uclass->priv; diff --git a/drivers/pci/pci_sandbox.c b/drivers/pci/pci_sandbox.c index 2af2b79c05d..2a38d104a09 100644 --- a/drivers/pci/pci_sandbox.c +++ b/drivers/pci/pci_sandbox.c @@ -8,6 +8,7 @@ #include <dm.h> #include <fdtdec.h> #include <pci.h> +#include <asm/test.h>
This change is not needed.
Removed this, and
#define FDT_DEV_INFO_CELLS 4
#define FDT_DEV_INFO_SIZE (FDT_DEV_INFO_CELLS * sizeof(u32))
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Tested-by: Bin Meng bmeng.cn@gmail.com
and applied to u-boot-x86/next, thanks!

At present these uclasses assumes that they are used with a device tree. Update them to support of-platdata as well.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/lpc-uclass.c | 2 ++ drivers/pch/pch-uclass.c | 2 ++ 2 files changed, 4 insertions(+)
diff --git a/arch/x86/lib/lpc-uclass.c b/arch/x86/lib/lpc-uclass.c index 505d7a943d2..1302a6e34a1 100644 --- a/arch/x86/lib/lpc-uclass.c +++ b/arch/x86/lib/lpc-uclass.c @@ -10,5 +10,7 @@ UCLASS_DRIVER(lpc) = { .id = UCLASS_LPC, .name = "lpc", +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) .post_bind = dm_scan_fdt_dev, +#endif }; diff --git a/drivers/pch/pch-uclass.c b/drivers/pch/pch-uclass.c index caf8b72803c..ad4906aa58b 100644 --- a/drivers/pch/pch-uclass.c +++ b/drivers/pch/pch-uclass.c @@ -64,5 +64,7 @@ int pch_ioctl(struct udevice *dev, ulong req, void *data, int size) UCLASS_DRIVER(pch) = { .id = UCLASS_PCH, .name = "pch", +#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA) .post_bind = dm_scan_fdt_dev, +#endif };

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present these uclasses assumes that they are used with a device tree. Update them to support of-platdata as well.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/lpc-uclass.c | 2 ++ drivers/pch/pch-uclass.c | 2 ++ 2 files changed, 4 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 8:32 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present these uclasses assumes that they are used with a device tree. Update them to support of-platdata as well.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/lpc-uclass.c | 2 ++ drivers/pch/pch-uclass.c | 2 ++ 2 files changed, 4 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

This function can be called before the timer is set up. Make sure that the init function is called so that it works correctly.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/timer/tsc_timer.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 9630036bc7f..85bdd95a819 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -464,6 +464,8 @@ unsigned long notrace timer_early_get_rate(void)
u64 notrace timer_early_get_count(void) { + tsc_timer_ensure_setup(true); + return rdtsc() - gd->arch.tsc_base; }

Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This function can be called before the timer is set up. Make sure that the init function is called so that it works correctly.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/timer/tsc_timer.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 9630036bc7f..85bdd95a819 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -464,6 +464,8 @@ unsigned long notrace timer_early_get_rate(void)
u64 notrace timer_early_get_count(void) {
tsc_timer_ensure_setup(true);
Could you please specify why this is needed? I remember we had done quite some fixes to the tsc_timer to support the early timer.
return rdtsc() - gd->arch.tsc_base;
}
Regards, Bin

Hi Bin,
On Sun, 6 Oct 2019 at 18:32, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
This function can be called before the timer is set up. Make sure that the init function is called so that it works correctly.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/timer/tsc_timer.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c index 9630036bc7f..85bdd95a819 100644 --- a/drivers/timer/tsc_timer.c +++ b/drivers/timer/tsc_timer.c @@ -464,6 +464,8 @@ unsigned long notrace timer_early_get_rate(void)
u64 notrace timer_early_get_count(void) {
tsc_timer_ensure_setup(true);
Could you please specify why this is needed? I remember we had done quite some fixes to the tsc_timer to support the early timer.
It doesn't seem to be needed actually. Will drop.
Regards, Simon

Move the code that actually sets up the MTRR into another function so it can be used elsewhere in the file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/mtrr.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index 0939736164d..6218d149e30 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -50,11 +50,20 @@ void mtrr_close(struct mtrr_state *state, bool do_caches) enable_caches(); }
+static void set_var_mtrr(uint reg, uint type, uint64_t start, uint64_t size) +{ + u64 mask; + + wrmsrl(MTRR_PHYS_BASE_MSR(reg), start | type); + mask = ~(size - 1); + mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; + wrmsrl(MTRR_PHYS_MASK_MSR(reg), mask | MTRR_PHYS_MASK_VALID); +} + int mtrr_commit(bool do_caches) { struct mtrr_request *req = gd->arch.mtrr_req; struct mtrr_state state; - uint64_t mask; int i;
debug("%s: enabled=%d, count=%d\n", __func__, gd->arch.has_mtrr, @@ -65,12 +74,8 @@ int mtrr_commit(bool do_caches) debug("open\n"); mtrr_open(&state, do_caches); debug("open done\n"); - for (i = 0; i < gd->arch.mtrr_req_count; i++, req++) { - mask = ~(req->size - 1); - mask &= (1ULL << CONFIG_CPU_ADDR_BITS) - 1; - wrmsrl(MTRR_PHYS_BASE_MSR(i), req->start | req->type); - wrmsrl(MTRR_PHYS_MASK_MSR(i), mask | MTRR_PHYS_MASK_VALID); - } + for (i = 0; i < gd->arch.mtrr_req_count; i++, req++) + set_var_mtrr(i, req->type, req->start, req->size);
/* Clear the ones that are unused */ debug("clear\n");

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Move the code that actually sets up the MTRR into another function so it can be used elsewhere in the file.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/mtrr.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 9:53 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Move the code that actually sets up the MTRR into another function so it can be used elsewhere in the file.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/mtrr.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Normally U-Boot handles MTRRs through an add/commit process which overwrites all MTRRs. But in very early boot it is not desirable to clear the existing MTRRs since they may be in use and it can cause a hang.
Add a new mtrr_set_next_var() function which sets up the next available MTRR to the required region.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/mtrr.c | 38 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mtrr.h | 12 ++++++++++++ 2 files changed, 50 insertions(+)
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index 6218d149e30..1a7c292fa8b 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -112,3 +112,41 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size)
return 0; } + +static int get_var_mtrr_count(void) +{ + return msr_read(MSR_MTRR_CAP_MSR).lo & MSR_MTRR_CAP_VCNT; +} + +static int get_free_var_mtrr(void) +{ + struct msr_t maskm; + int vcnt; + int i; + + vcnt = get_var_mtrr_count(); + + /* Identify the first var mtrr which is not valid */ + for (i = 0; i < vcnt; i++) { + maskm = msr_read(MTRR_PHYS_MASK_MSR(i)); + if ((maskm.lo & MTRR_PHYS_MASK_VALID) == 0) + return i; + } + + /* No free var mtrr */ + return -ENOSPC; +} + +int mtrr_set_next_var(uint type, uint64_t start, uint64_t size) +{ + int mtrr; + + mtrr = get_free_var_mtrr(); + if (mtrr < 0) + return mtrr; + + set_var_mtrr(mtrr, MTRR_TYPE_WRPROT, start, size); + debug("MTRR %x: start=%x, size=%x\n", mtrr, (uint)start, (uint)size); + + return 0; +} diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 6f29e75ce65..672617256e9 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -117,6 +117,18 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size); */ int mtrr_commit(bool do_caches);
+/** + * mtrr_set_next_var() - set up a variable MTRR + * + * This finds the first free variable MTRR and sets to the given area + * + * @type: Requested type (MTRR_TYPE_) + * @start: Start address + * @size: Size + * @return 0 on success, -ENOSPC if there are no more MTRRs + */ +int mtrr_set_next_var(uint type, uint64_t base, uint64_t size); + #endif
#if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0)

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Normally U-Boot handles MTRRs through an add/commit process which overwrites all MTRRs. But in very early boot it is not desirable to clear the existing MTRRs since they may be in use and it can cause a hang.
Add a new mtrr_set_next_var() function which sets up the next available MTRR to the required region.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/mtrr.c | 38 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mtrr.h | 12 ++++++++++++ 2 files changed, 50 insertions(+)
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index 6218d149e30..1a7c292fa8b 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -112,3 +112,41 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size)
return 0;
}
+static int get_var_mtrr_count(void) +{
return msr_read(MSR_MTRR_CAP_MSR).lo & MSR_MTRR_CAP_VCNT;
+}
+static int get_free_var_mtrr(void) +{
struct msr_t maskm;
int vcnt;
int i;
vcnt = get_var_mtrr_count();
/* Identify the first var mtrr which is not valid */
for (i = 0; i < vcnt; i++) {
maskm = msr_read(MTRR_PHYS_MASK_MSR(i));
if ((maskm.lo & MTRR_PHYS_MASK_VALID) == 0)
return i;
}
/* No free var mtrr */
return -ENOSPC;
+}
+int mtrr_set_next_var(uint type, uint64_t start, uint64_t size) +{
int mtrr;
mtrr = get_free_var_mtrr();
if (mtrr < 0)
return mtrr;
set_var_mtrr(mtrr, MTRR_TYPE_WRPROT, start, size);
I think MTRR_TYPE_WRPROT should be parameter 'type'
debug("MTRR %x: start=%x, size=%x\n", mtrr, (uint)start, (uint)size);
return 0;
+} diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 6f29e75ce65..672617256e9 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -117,6 +117,18 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size); */ int mtrr_commit(bool do_caches);
+/**
- mtrr_set_next_var() - set up a variable MTRR
- This finds the first free variable MTRR and sets to the given area
- @type: Requested type (MTRR_TYPE_)
- @start: Start address
- @size: Size
- @return 0 on success, -ENOSPC if there are no more MTRRs
- */
+int mtrr_set_next_var(uint type, uint64_t base, uint64_t size);
#endif
#if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0)
Other than above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 9:53 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Normally U-Boot handles MTRRs through an add/commit process which overwrites all MTRRs. But in very early boot it is not desirable to clear the existing MTRRs since they may be in use and it can cause a hang.
Add a new mtrr_set_next_var() function which sets up the next available MTRR to the required region.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/mtrr.c | 38 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mtrr.h | 12 ++++++++++++ 2 files changed, 50 insertions(+)
diff --git a/arch/x86/cpu/mtrr.c b/arch/x86/cpu/mtrr.c index 6218d149e30..1a7c292fa8b 100644 --- a/arch/x86/cpu/mtrr.c +++ b/arch/x86/cpu/mtrr.c @@ -112,3 +112,41 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size)
return 0;
}
+static int get_var_mtrr_count(void) +{
return msr_read(MSR_MTRR_CAP_MSR).lo & MSR_MTRR_CAP_VCNT;
+}
+static int get_free_var_mtrr(void) +{
struct msr_t maskm;
int vcnt;
int i;
vcnt = get_var_mtrr_count();
/* Identify the first var mtrr which is not valid */
for (i = 0; i < vcnt; i++) {
maskm = msr_read(MTRR_PHYS_MASK_MSR(i));
if ((maskm.lo & MTRR_PHYS_MASK_VALID) == 0)
return i;
}
/* No free var mtrr */
return -ENOSPC;
+}
+int mtrr_set_next_var(uint type, uint64_t start, uint64_t size) +{
int mtrr;
mtrr = get_free_var_mtrr();
if (mtrr < 0)
return mtrr;
set_var_mtrr(mtrr, MTRR_TYPE_WRPROT, start, size);
I think MTRR_TYPE_WRPROT should be parameter 'type'
Fixed this, and
debug("MTRR %x: start=%x, size=%x\n", mtrr, (uint)start, (uint)size);
return 0;
+} diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 6f29e75ce65..672617256e9 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -117,6 +117,18 @@ int mtrr_add_request(int type, uint64_t start, uint64_t size); */ int mtrr_commit(bool do_caches);
+/**
- mtrr_set_next_var() - set up a variable MTRR
- This finds the first free variable MTRR and sets to the given area
- @type: Requested type (MTRR_TYPE_)
- @start: Start address
- @size: Size
- @return 0 on success, -ENOSPC if there are no more MTRRs
- */
+int mtrr_set_next_var(uint type, uint64_t base, uint64_t size);
#endif
#if ((CONFIG_XIP_ROM_SIZE & (CONFIG_XIP_ROM_SIZE - 1)) != 0)
Other than above,
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

Early in boot it is necessary to decode the PCI device/function values for particular peripherals in the device tree or of-platdata. Add functions to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/pci.c | 18 ++++++++++++++++++ arch/x86/include/asm/pci.h | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+)
diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c index e1aae158ce5..f551fef5bbb 100644 --- a/arch/x86/cpu/pci.c +++ b/arch/x86/cpu/pci.c @@ -69,6 +69,24 @@ int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, return pci_x86_write_config(bdf, offset, value, size); }
+#if !CONFIG_IS_ENABLED(OF_PLATDATA) +int pci_x86_get_devfn(struct udevice *dev) +{ + struct fdt_pci_addr addr; + int ret; + + /* Extract the devfn from fdt_pci_addr */ + ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG, + "reg", &addr); + if (ret) { + if (ret != -ENOENT) + return -EINVAL; + } + + return addr.phys_hi & 0xff00; +} +#endif + void pci_assign_irqs(int bus, int device, u8 irq[4]) { pci_dev_t bdf; diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 2a720735728..abb770760f5 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -60,6 +60,28 @@ int pci_x86_write_config(pci_dev_t bdf, uint offset, ulong value, int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, enum pci_size_t size);
+/** + * pci_x86_get_devfn() - Extract the devfn from fdt_pci_addr of the device + * + * Get devfn from fdt_pci_addr of the specified device. This is a copy of + * pci_get_devfn() for use in TPL on x86, since PCI may not be available. + * + * @dev: PCI device + * @return devfn in bits 15...8 if found, -ENODEV if not found + */ +int pci_x86_get_devfn(struct udevice *dev); + +/** + * pci_x86_ofplat_get_devfn() - Get the PCI dev/fn from ofplat reg data + * + * @reg: reg value from dt-platdata.c array (first member) + * @return device/function for that device + */ +static inline pci_dev_t pci_x86_ofplat_get_devfn(u32 reg) +{ + return reg & 0xff00; +} + /** * Assign IRQ number to a PCI device *

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Early in boot it is necessary to decode the PCI device/function values for particular peripherals in the device tree or of-platdata. Add functions to handle this.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/pci.c | 18 ++++++++++++++++++ arch/x86/include/asm/pci.h | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+)
diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c index e1aae158ce5..f551fef5bbb 100644 --- a/arch/x86/cpu/pci.c +++ b/arch/x86/cpu/pci.c @@ -69,6 +69,24 @@ int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, return pci_x86_write_config(bdf, offset, value, size); }
+#if !CONFIG_IS_ENABLED(OF_PLATDATA) +int pci_x86_get_devfn(struct udevice *dev) +{
struct fdt_pci_addr addr;
int ret;
/* Extract the devfn from fdt_pci_addr */
ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
"reg", &addr);
if (ret) {
if (ret != -ENOENT)
return -EINVAL;
}
return addr.phys_hi & 0xff00;
+} +#endif
This function is a duplicates of pci_get_devfn() in pci-uclass driver.
void pci_assign_irqs(int bus, int device, u8 irq[4]) { pci_dev_t bdf; diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 2a720735728..abb770760f5 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -60,6 +60,28 @@ int pci_x86_write_config(pci_dev_t bdf, uint offset, ulong value, int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, enum pci_size_t size);
+/**
- pci_x86_get_devfn() - Extract the devfn from fdt_pci_addr of the device
- Get devfn from fdt_pci_addr of the specified device. This is a copy of
- pci_get_devfn() for use in TPL on x86, since PCI may not be available.
- @dev: PCI device
- @return devfn in bits 15...8 if found, -ENODEV if not found
- */
+int pci_x86_get_devfn(struct udevice *dev);
+/**
- pci_x86_ofplat_get_devfn() - Get the PCI dev/fn from ofplat reg data
- @reg: reg value from dt-platdata.c array (first member)
- @return device/function for that device
- */
+static inline pci_dev_t pci_x86_ofplat_get_devfn(u32 reg)
Why returns pci_dev_t instead of int? This is inconsistent with the pci_x86_get_devfn() above.
+{
return reg & 0xff00;
+}
/**
- Assign IRQ number to a PCI device
--
Regards, Bin

Hi Bin,
On Mon, 7 Oct 2019 at 07:53, Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Early in boot it is necessary to decode the PCI device/function values for particular peripherals in the device tree or of-platdata. Add functions to handle this.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/pci.c | 18 ++++++++++++++++++ arch/x86/include/asm/pci.h | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+)
diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c index e1aae158ce5..f551fef5bbb 100644 --- a/arch/x86/cpu/pci.c +++ b/arch/x86/cpu/pci.c @@ -69,6 +69,24 @@ int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, return pci_x86_write_config(bdf, offset, value, size); }
+#if !CONFIG_IS_ENABLED(OF_PLATDATA) +int pci_x86_get_devfn(struct udevice *dev) +{
struct fdt_pci_addr addr;
int ret;
/* Extract the devfn from fdt_pci_addr */
ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
"reg", &addr);
if (ret) {
if (ret != -ENOENT)
return -EINVAL;
}
return addr.phys_hi & 0xff00;
+} +#endif
This function is a duplicates of pci_get_devfn() in pci-uclass driver.
Yes that's right. But with TPL we don't enable UCLASS_PCI to save code size, so we need it somewhere else.
void pci_assign_irqs(int bus, int device, u8 irq[4]) { pci_dev_t bdf; diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 2a720735728..abb770760f5 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -60,6 +60,28 @@ int pci_x86_write_config(pci_dev_t bdf, uint offset, ulong value, int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, enum pci_size_t size);
+/**
- pci_x86_get_devfn() - Extract the devfn from fdt_pci_addr of the device
- Get devfn from fdt_pci_addr of the specified device. This is a copy of
- pci_get_devfn() for use in TPL on x86, since PCI may not be available.
- @dev: PCI device
- @return devfn in bits 15...8 if found, -ENODEV if not found
- */
+int pci_x86_get_devfn(struct udevice *dev);
+/**
- pci_x86_ofplat_get_devfn() - Get the PCI dev/fn from ofplat reg data
- @reg: reg value from dt-platdata.c array (first member)
- @return device/function for that device
- */
+static inline pci_dev_t pci_x86_ofplat_get_devfn(u32 reg)
Why returns pci_dev_t instead of int? This is inconsistent with the pci_x86_get_devfn() above.
Will fix.
Regards, Simon

Hi Simon,
On Sun, Oct 13, 2019 at 11:03 PM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Mon, 7 Oct 2019 at 07:53, Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Early in boot it is necessary to decode the PCI device/function values for particular peripherals in the device tree or of-platdata. Add functions to handle this.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/pci.c | 18 ++++++++++++++++++ arch/x86/include/asm/pci.h | 22 ++++++++++++++++++++++ 2 files changed, 40 insertions(+)
diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c index e1aae158ce5..f551fef5bbb 100644 --- a/arch/x86/cpu/pci.c +++ b/arch/x86/cpu/pci.c @@ -69,6 +69,24 @@ int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, return pci_x86_write_config(bdf, offset, value, size); }
+#if !CONFIG_IS_ENABLED(OF_PLATDATA) +int pci_x86_get_devfn(struct udevice *dev) +{
struct fdt_pci_addr addr;
int ret;
/* Extract the devfn from fdt_pci_addr */
ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
"reg", &addr);
if (ret) {
if (ret != -ENOENT)
return -EINVAL;
}
return addr.phys_hi & 0xff00;
+} +#endif
This function is a duplicates of pci_get_devfn() in pci-uclass driver.
Yes that's right. But with TPL we don't enable UCLASS_PCI to save code size, so we need it somewhere else.
How about we exact the pci_get_devfn() from pci-uclass driver and put it somewhere else public for both w/ and w/o UCLASS_PCI case?
void pci_assign_irqs(int bus, int device, u8 irq[4]) { pci_dev_t bdf; diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 2a720735728..abb770760f5 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -60,6 +60,28 @@ int pci_x86_write_config(pci_dev_t bdf, uint offset, ulong value, int pci_x86_clrset_config(pci_dev_t bdf, uint offset, ulong clr, ulong set, enum pci_size_t size);
+/**
- pci_x86_get_devfn() - Extract the devfn from fdt_pci_addr of the device
- Get devfn from fdt_pci_addr of the specified device. This is a copy of
- pci_get_devfn() for use in TPL on x86, since PCI may not be available.
- @dev: PCI device
- @return devfn in bits 15...8 if found, -ENODEV if not found
- */
+int pci_x86_get_devfn(struct udevice *dev);
+/**
- pci_x86_ofplat_get_devfn() - Get the PCI dev/fn from ofplat reg data
- @reg: reg value from dt-platdata.c array (first member)
- @return device/function for that device
- */
+static inline pci_dev_t pci_x86_ofplat_get_devfn(u32 reg)
Why returns pci_dev_t instead of int? This is inconsistent with the pci_x86_get_devfn() above.
Will fix.
Regards, Bin

We don't need this driver very early in boot and it adds code size. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 3f1f62da2b1..6296b55ff8a 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -26,7 +26,10 @@ endif
extra-$(CONFIG_$(SPL_TPL_)X86_16BIT_INIT) += resetvec.o start16.o
-obj-y += cpu.o cpu_x86.o +obj-y += cpu.o +ifndef CONFIG_TPL_BUILD +obj-y += cpu_x86.o +endif
ifndef CONFIG_$(SPL_)X86_64 AFLAGS_REMOVE_call32.o := -mregparm=3 \

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
We don't need this driver very early in boot and it adds code size. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 9:53 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
We don't need this driver very early in boot and it adds code size. Drop it.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

With FSP2 we use MTRRs in U-Boot proper even though the 32-bit init happens in TPL. Enable this, using a variable to try to make the conditions more palatable.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/init_helpers.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c index 4774a9bdb78..3e3a11ac2fa 100644 --- a/arch/x86/lib/init_helpers.c +++ b/arch/x86/lib/init_helpers.c @@ -12,15 +12,23 @@ DECLARE_GLOBAL_DATA_PTR;
int init_cache_f_r(void) { -#if CONFIG_IS_ENABLED(X86_32BIT_INIT) && !defined(CONFIG_HAVE_FSP) && \ - !defined(CONFIG_SYS_SLIMBOOTLOADER) + bool do_mtrr = CONFIG_IS_ENABLED(X86_32BIT_INIT) || + IS_ENABLED(CONFIG_FSP_VERSION2); int ret;
- ret = mtrr_commit(false); - /* If MTRR MSR is not implemented by the processor, just ignore it */ - if (ret && ret != -ENOSYS) - return ret; -#endif + do_mtrr &= !IS_ENABLED(CONFIG_FSP_VERSION1) && + !IS_ENABLED(CONFIG_SYS_SLIMBOOTLOADER); + + if (do_mtrr) { + ret = mtrr_commit(false); + /* + * If MTRR MSR is not implemented by the processor, just ignore + * it + */ + if (ret && ret != -ENOSYS) + return ret; + } + /* Initialise the CPU cache(s) */ return init_cache(); }

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
With FSP2 we use MTRRs in U-Boot proper even though the 32-bit init happens in TPL. Enable this, using a variable to try to make the conditions more palatable.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/init_helpers.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Mon, Oct 7, 2019 at 9:53 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
With FSP2 we use MTRRs in U-Boot proper even though the 32-bit init happens in TPL. Enable this, using a variable to try to make the conditions more palatable.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/init_helpers.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86/next, thanks!

The x86 power unit handles power management. Support initing this device which is modelled as a new type of system controller since there are no operations needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/cpu.h | 1 + arch/x86/lib/spl.c | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index feee0f915f6..21a05dab7de 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -55,6 +55,7 @@ enum { X86_SYSCON_PINCONF, /* Intel x86 pin configuration */ X86_SYSCON_PMU, /* Power Management Unit */ X86_SYSCON_SCU, /* System Controller Unit */ + X86_SYSCON_PUNIT, /* Power unit */ };
struct cpuid_result { diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index 2baac913837..db1ce67a590 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -5,11 +5,15 @@
#include <common.h> #include <debug_uart.h> +#include <dm.h> #include <malloc.h> #include <spl.h> +#include <syscon.h> #include <asm/cpu.h> +#include <asm/cpu_common.h> #include <asm/mrccache.h> #include <asm/mtrr.h> +#include <asm/pci.h> #include <asm/processor.h> #include <asm/spl.h> #include <asm-generic/sections.h> @@ -21,6 +25,32 @@ __weak int arch_cpu_init_dm(void) return 0; }
+#ifdef CONFIG_TPL + +static int set_max_freq(void) +{ + if (cpu_get_burst_mode_state() == BURST_MODE_UNAVAILABLE) { + /* + * Burst Mode has been factory-configured as disabled and is not + * available in this physical processor package + */ + debug("Burst Mode is factory-disabled\n"); + return -ENOENT; + } + + /* Enable burst mode */ + cpu_set_burst_mode(true); + + /* Enable speed step */ + cpu_set_eist(true); + + /* Set P-State ratio */ + cpu_set_p_state_to_turbo_ratio(); + + return 0; +} +#endif + static int x86_spl_init(void) { #ifndef CONFIG_TPL @@ -31,6 +61,8 @@ static int x86_spl_init(void) * place it immediately below CONFIG_SYS_TEXT_BASE. */ char *ptr = (char *)0x110000; +#else + struct udevice *punit; #endif int ret;
@@ -101,6 +133,14 @@ static int x86_spl_init(void) return ret; } mtrr_commit(true); +#else + ret = syscon_get_by_driver_data(X86_SYSCON_PUNIT, &punit); + if (ret) + debug("Could not find PUNIT (err-%d)\n", ret); + + ret = set_max_freq(); + if (ret) + debug("Failed to set CPU frequency (err=%d)\n", ret); #endif
return 0;

Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The x86 power unit handles power management. Support initing this device which is modelled as a new type of system controller since there are no operations needed.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/cpu.h | 1 + arch/x86/lib/spl.c | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index feee0f915f6..21a05dab7de 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -55,6 +55,7 @@ enum { X86_SYSCON_PINCONF, /* Intel x86 pin configuration */ X86_SYSCON_PMU, /* Power Management Unit */ X86_SYSCON_SCU, /* System Controller Unit */
X86_SYSCON_PUNIT, /* Power unit */
};
struct cpuid_result { diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index 2baac913837..db1ce67a590 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -5,11 +5,15 @@
#include <common.h> #include <debug_uart.h> +#include <dm.h> #include <malloc.h> #include <spl.h> +#include <syscon.h> #include <asm/cpu.h> +#include <asm/cpu_common.h> #include <asm/mrccache.h> #include <asm/mtrr.h> +#include <asm/pci.h> #include <asm/processor.h> #include <asm/spl.h> #include <asm-generic/sections.h> @@ -21,6 +25,32 @@ __weak int arch_cpu_init_dm(void) return 0; }
+#ifdef CONFIG_TPL
+static int set_max_freq(void) +{
if (cpu_get_burst_mode_state() == BURST_MODE_UNAVAILABLE) {
/*
* Burst Mode has been factory-configured as disabled and is not
* available in this physical processor package
*/
debug("Burst Mode is factory-disabled\n");
return -ENOENT;
}
/* Enable burst mode */
cpu_set_burst_mode(true);
/* Enable speed step */
cpu_set_eist(true);
/* Set P-State ratio */
cpu_set_p_state_to_turbo_ratio();
return 0;
+} +#endif
static int x86_spl_init(void) { #ifndef CONFIG_TPL @@ -31,6 +61,8 @@ static int x86_spl_init(void) * place it immediately below CONFIG_SYS_TEXT_BASE. */ char *ptr = (char *)0x110000; +#else
struct udevice *punit;
#endif int ret;
@@ -101,6 +133,14 @@ static int x86_spl_init(void) return ret; } mtrr_commit(true); +#else
ret = syscon_get_by_driver_data(X86_SYSCON_PUNIT, &punit);
if (ret)
debug("Could not find PUNIT (err-%d)\n", ret);
err=%d
But I wonder what's the purpose of init punit at this point?
ret = set_max_freq();
Can we delay this to U-Boot proper? I don't see a need to bring the core up to speed at this early stage.
if (ret)
debug("Failed to set CPU frequency (err=%d)\n", ret);
#endif
return 0;
--
Regards, Bin

Hi Bin,
On Wed, 9 Oct 2019 at 08:02, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The x86 power unit handles power management. Support initing this device which is modelled as a new type of system controller since there are no operations needed.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/cpu.h | 1 + arch/x86/lib/spl.c | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+)
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index feee0f915f6..21a05dab7de 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -55,6 +55,7 @@ enum { X86_SYSCON_PINCONF, /* Intel x86 pin configuration */ X86_SYSCON_PMU, /* Power Management Unit */ X86_SYSCON_SCU, /* System Controller Unit */
X86_SYSCON_PUNIT, /* Power unit */
};
struct cpuid_result { diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index 2baac913837..db1ce67a590 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -5,11 +5,15 @@
#include <common.h> #include <debug_uart.h> +#include <dm.h> #include <malloc.h> #include <spl.h> +#include <syscon.h> #include <asm/cpu.h> +#include <asm/cpu_common.h> #include <asm/mrccache.h> #include <asm/mtrr.h> +#include <asm/pci.h> #include <asm/processor.h> #include <asm/spl.h> #include <asm-generic/sections.h> @@ -21,6 +25,32 @@ __weak int arch_cpu_init_dm(void) return 0; }
+#ifdef CONFIG_TPL
+static int set_max_freq(void) +{
if (cpu_get_burst_mode_state() == BURST_MODE_UNAVAILABLE) {
/*
* Burst Mode has been factory-configured as disabled and is not
* available in this physical processor package
*/
debug("Burst Mode is factory-disabled\n");
return -ENOENT;
}
/* Enable burst mode */
cpu_set_burst_mode(true);
/* Enable speed step */
cpu_set_eist(true);
/* Set P-State ratio */
cpu_set_p_state_to_turbo_ratio();
return 0;
+} +#endif
static int x86_spl_init(void) { #ifndef CONFIG_TPL @@ -31,6 +61,8 @@ static int x86_spl_init(void) * place it immediately below CONFIG_SYS_TEXT_BASE. */ char *ptr = (char *)0x110000; +#else
struct udevice *punit;
#endif int ret;
@@ -101,6 +133,14 @@ static int x86_spl_init(void) return ret; } mtrr_commit(true); +#else
ret = syscon_get_by_driver_data(X86_SYSCON_PUNIT, &punit);
if (ret)
debug("Could not find PUNIT (err-%d)\n", ret);
err=%d
But I wonder what's the purpose of init punit at this point?
See punit_init() - among other things it tells the systemagent that U-Boot is running and sets the thermal target for the device.
ret = set_max_freq();
Can we delay this to U-Boot proper? I don't see a need to bring the core up to speed at this early stage.
Yes, but it does add time. SPL is 8ms slower without this, and getting to board_init_r() in U-Boot is 50ms slower.
if (ret)
debug("Failed to set CPU frequency (err=%d)\n", ret);
#endif
return 0;
--
Regards, Bin

At present when these fail to boot there is no message, just a hang. Add a panic so it is obvious that something when wrong.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/spl.c | 2 +- arch/x86/lib/tpl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index db1ce67a590..e1e2d4fa0d5 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -153,7 +153,7 @@ void board_init_f(ulong flags) ret = x86_spl_init(); if (ret) { debug("Error %d\n", ret); - hang(); + panic("x86_spl_init fail"); } #ifdef CONFIG_TPL gd->bd = malloc(sizeof(*gd->bd)); diff --git a/arch/x86/lib/tpl.c b/arch/x86/lib/tpl.c index cfefa78045e..d70f590541c 100644 --- a/arch/x86/lib/tpl.c +++ b/arch/x86/lib/tpl.c @@ -55,7 +55,7 @@ void board_init_f(ulong flags) ret = x86_tpl_init(); if (ret) { debug("Error %d\n", ret); - hang(); + panic("x86_tpl_init fail"); }
/* Uninit CAR and jump to board_init_f_r() */

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present when these fail to boot there is no message, just a hang. Add a panic so it is obvious that something when wrong.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/spl.c | 2 +- arch/x86/lib/tpl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Wed, Oct 9, 2019 at 10:02 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
At present when these fail to boot there is no message, just a hang. Add a panic so it is obvious that something when wrong.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/spl.c | 2 +- arch/x86/lib/tpl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!

In TPL we try to minimise code size so do not include the PCI subsystem. We can use fixed BARs and drivers can directly program the devices that they need.
However we do need to bind the devices on the PCI bus and without PCI this does not ordinarily happen. As a work-around, define a fake PCI bus which does this binding, but no other PCI operations. This is a convenient way to ensure that we can use the same device tree for TPL, SPL and U-Boot proper:
TPL - CONFIG_TPL_PCI is not set (manual mode, fake PCI bus) SPL - CONFIG_SPL_PCI is set (manual mode but with real PCI bus) U-Boot - CONFIG_PCI is set (full auto-config after relocation)
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/tpl.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/x86/lib/tpl.c b/arch/x86/lib/tpl.c index d70f590541c..f8075568a2c 100644 --- a/arch/x86/lib/tpl.c +++ b/arch/x86/lib/tpl.c @@ -5,6 +5,7 @@
#include <common.h> #include <debug_uart.h> +#include <dm.h> #include <spl.h> #include <asm/cpu.h> #include <asm/mtrr.h> @@ -115,3 +116,27 @@ void spl_board_init(void) { preloader_console_init(); } + +#if !CONFIG_IS_ENABLED(PCI) +/* + * This is a fake PCI bus for TPL when it doesn't have proper PCI. It is enough + * to bind the devices on the PCI bus, some of which have early-regs properties + * providing fixed BARs. Individual drivers program these BARs themselves so + * that they can access the devices. The BARs are allocated statically in the + * device tree. + * + * Once SPL is running it enables PCI properly, but does not auto-assign BARs + * for devices, so the TPL BARs continue to be used. Once U-Boot starts it does + * the autoallocation (after relocation). + */ +static const struct udevice_id tpl_fake_pci_ids[] = { + { .compatible = "pci-x86" }, + { } +}; + +U_BOOT_DRIVER(pci_x86) = { + .name = "pci_x86", + .id = UCLASS_SIMPLE_BUS, + .of_match = tpl_fake_pci_ids, +}; +#endif

Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
In TPL we try to minimise code size so do not include the PCI subsystem. We can use fixed BARs and drivers can directly program the devices that they need.
However we do need to bind the devices on the PCI bus and without PCI this does not ordinarily happen. As a work-around, define a fake PCI bus which does this binding, but no other PCI operations. This is a convenient way to ensure that we can use the same device tree for TPL, SPL and U-Boot proper:
TPL - CONFIG_TPL_PCI is not set (manual mode, fake PCI bus) SPL - CONFIG_SPL_PCI is set (manual mode but with real PCI bus)
manual mode is confusing. Maybe (no auto-config, real PCI bus)?
U-Boot - CONFIG_PCI is set (full auto-config after relocation)
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/tpl.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/arch/x86/lib/tpl.c b/arch/x86/lib/tpl.c index d70f590541c..f8075568a2c 100644 --- a/arch/x86/lib/tpl.c +++ b/arch/x86/lib/tpl.c @@ -5,6 +5,7 @@
#include <common.h> #include <debug_uart.h> +#include <dm.h> #include <spl.h> #include <asm/cpu.h> #include <asm/mtrr.h> @@ -115,3 +116,27 @@ void spl_board_init(void) { preloader_console_init(); }
+#if !CONFIG_IS_ENABLED(PCI) +/*
- This is a fake PCI bus for TPL when it doesn't have proper PCI. It is enough
- to bind the devices on the PCI bus, some of which have early-regs properties
- providing fixed BARs. Individual drivers program these BARs themselves so
- that they can access the devices. The BARs are allocated statically in the
- device tree.
- Once SPL is running it enables PCI properly, but does not auto-assign BARs
- for devices, so the TPL BARs continue to be used. Once U-Boot starts it does
- the autoallocation (after relocation).
missing space between "auto" and "allocation"
- */
+static const struct udevice_id tpl_fake_pci_ids[] = {
{ .compatible = "pci-x86" },
{ }
+};
+U_BOOT_DRIVER(pci_x86) = {
.name = "pci_x86",
.id = UCLASS_SIMPLE_BUS,
.of_match = tpl_fake_pci_ids,
+};
+#endif
Regards, Bin

Add a field to the PCI emulator per-device data which records which device is being emulated. This is useful when the emulator needs to check the device for something.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pci/pci-emul-uclass.c | 32 +++++++++++++++++++++++++------- include/pci.h | 20 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 6e6172836a4..589fb539031 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -18,6 +18,7 @@ struct sandbox_pci_emul_priv { int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, struct udevice **containerp, struct udevice **emulp) { + struct pci_emul_uc_priv *upriv; struct udevice *dev; int ret;
@@ -30,17 +31,33 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, } *containerp = dev;
- /* - * TODO(sjg@chromium.org): This code needs a comment as I'm not sure - * why UCLASS_PCI_GENERIC devices end up being their own emulators. I - * left this code as is. - */ ret = uclass_get_device_by_phandle(UCLASS_PCI_EMUL, dev, "sandbox,emul", emulp); - if (ret && device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) + if (!ret) { + upriv = dev_get_uclass_priv(*emulp); + + upriv->client = dev; + } else if (device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) { + /* + * TODO(sjg@chromium.org): This code needs a comment as I'm not + * sure why non-UCLASS_PCI_GENERIC devices end up being their + * own emulators. I left this code as is. + */ *emulp = dev; + } + + return 0; +}
- return *emulp ? 0 : -ENODEV; +int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp) +{ + struct pci_emul_uc_priv *upriv = dev_get_uclass_priv(emul); + + if (!upriv->client) + return -ENOENT; + *devp = upriv->client; + + return 0; }
uint sandbox_pci_read_bar(u32 barval, int type, uint size) @@ -89,6 +106,7 @@ UCLASS_DRIVER(pci_emul) = { .post_probe = sandbox_pci_emul_post_probe, .pre_remove = sandbox_pci_emul_pre_remove, .priv_auto_alloc_size = sizeof(struct sandbox_pci_emul_priv), + .per_device_auto_alloc_size = sizeof(struct pci_emul_uc_priv), };
/* diff --git a/include/pci.h b/include/pci.h index 8aa6636cfbf..ff59ac0e695 100644 --- a/include/pci.h +++ b/include/pci.h @@ -1490,6 +1490,17 @@ int dm_pci_find_device(unsigned int vendor, unsigned int device, int index, */ int dm_pci_find_class(uint find_class, int index, struct udevice **devp);
+/** + * struct pci_emul_uc_priv - holds info about an emulator device + * + * There is always at most one emulator per client + * + * @client: Client device if any, else NULL + */ +struct pci_emul_uc_priv { + struct udevice *client; +}; + /** * struct dm_pci_emul_ops - PCI device emulator operations */ @@ -1592,6 +1603,15 @@ struct dm_pci_emul_ops { int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, struct udevice **containerp, struct udevice **emulp);
+/** + * sandbox_pci_get_client() - Find the client for an emulation device + * + * @emul: Emulation device to check + * @devp: Returns the client device emulated by this device + * @return 0 if OK, -ENOENT if the device has no client yet + */ +int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp); + /** * pci_get_devfn() - Extract the devfn from fdt_pci_addr of the device *

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Add a field to the PCI emulator per-device data which records which device is being emulated. This is useful when the emulator needs to check the device for something.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci-emul-uclass.c | 32 +++++++++++++++++++++++++------- include/pci.h | 20 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 6e6172836a4..589fb539031 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -18,6 +18,7 @@ struct sandbox_pci_emul_priv { int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, struct udevice **containerp, struct udevice **emulp) {
struct pci_emul_uc_priv *upriv; struct udevice *dev; int ret;
@@ -30,17 +31,33 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, } *containerp = dev;
/*
* TODO(sjg@chromium.org): This code needs a comment as I'm not sure
* why UCLASS_PCI_GENERIC devices end up being their own emulators. I
* left this code as is.
*/ ret = uclass_get_device_by_phandle(UCLASS_PCI_EMUL, dev, "sandbox,emul", emulp);
if (ret && device_get_uclass_id(dev) != UCLASS_PCI_GENERIC)
if (!ret) {
upriv = dev_get_uclass_priv(*emulp);
upriv->client = dev;
} else if (device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) {
/*
* TODO(sjg@chromium.org): This code needs a comment as I'm not
* sure why non-UCLASS_PCI_GENERIC devices end up being their
* own emulators. I left this code as is.
*/
This part will not apply to current u-boot/master. Need rebase.
*emulp = dev;
}
return 0;
+}
return *emulp ? 0 : -ENODEV;
+int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp) +{
struct pci_emul_uc_priv *upriv = dev_get_uclass_priv(emul);
if (!upriv->client)
return -ENOENT;
*devp = upriv->client;
return 0;
}
uint sandbox_pci_read_bar(u32 barval, int type, uint size) @@ -89,6 +106,7 @@ UCLASS_DRIVER(pci_emul) = { .post_probe = sandbox_pci_emul_post_probe, .pre_remove = sandbox_pci_emul_pre_remove, .priv_auto_alloc_size = sizeof(struct sandbox_pci_emul_priv),
.per_device_auto_alloc_size = sizeof(struct pci_emul_uc_priv),
};
/* diff --git a/include/pci.h b/include/pci.h index 8aa6636cfbf..ff59ac0e695 100644 --- a/include/pci.h +++ b/include/pci.h @@ -1490,6 +1490,17 @@ int dm_pci_find_device(unsigned int vendor, unsigned int device, int index, */ int dm_pci_find_class(uint find_class, int index, struct udevice **devp);
+/**
- struct pci_emul_uc_priv - holds info about an emulator device
- There is always at most one emulator per client
- @client: Client device if any, else NULL
- */
+struct pci_emul_uc_priv {
struct udevice *client;
+};
/**
- struct dm_pci_emul_ops - PCI device emulator operations
*/ @@ -1592,6 +1603,15 @@ struct dm_pci_emul_ops { int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, struct udevice **containerp, struct udevice **emulp);
+/**
- sandbox_pci_get_client() - Find the client for an emulation device
- @emul: Emulation device to check
- @devp: Returns the client device emulated by this device
- @return 0 if OK, -ENOENT if the device has no client yet
- */
+int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp);
/**
- pci_get_devfn() - Extract the devfn from fdt_pci_addr of the device
--
The changes look good to me. Reviewed-by: Bin Meng bmeng.cn@gmail.com
Regards, Bin

On Wed, Oct 9, 2019 at 10:27 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Add a field to the PCI emulator per-device data which records which device is being emulated. This is useful when the emulator needs to check the device for something.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pci/pci-emul-uclass.c | 32 +++++++++++++++++++++++++------- include/pci.h | 20 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/drivers/pci/pci-emul-uclass.c b/drivers/pci/pci-emul-uclass.c index 6e6172836a4..589fb539031 100644 --- a/drivers/pci/pci-emul-uclass.c +++ b/drivers/pci/pci-emul-uclass.c @@ -18,6 +18,7 @@ struct sandbox_pci_emul_priv { int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, struct udevice **containerp, struct udevice **emulp) {
struct pci_emul_uc_priv *upriv; struct udevice *dev; int ret;
@@ -30,17 +31,33 @@ int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, } *containerp = dev;
/*
* TODO(sjg@chromium.org): This code needs a comment as I'm not sure
* why UCLASS_PCI_GENERIC devices end up being their own emulators. I
* left this code as is.
*/ ret = uclass_get_device_by_phandle(UCLASS_PCI_EMUL, dev, "sandbox,emul", emulp);
if (ret && device_get_uclass_id(dev) != UCLASS_PCI_GENERIC)
if (!ret) {
upriv = dev_get_uclass_priv(*emulp);
upriv->client = dev;
} else if (device_get_uclass_id(dev) != UCLASS_PCI_GENERIC) {
/*
* TODO(sjg@chromium.org): This code needs a comment as I'm not
* sure why non-UCLASS_PCI_GENERIC devices end up being their
* own emulators. I left this code as is.
*/
This part will not apply to current u-boot/master. Need rebase.
Rebased the patch against u-boot-x86/master to get it applied cleanly, and
*emulp = dev;
}
return 0;
+}
return *emulp ? 0 : -ENODEV;
+int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp) +{
struct pci_emul_uc_priv *upriv = dev_get_uclass_priv(emul);
if (!upriv->client)
return -ENOENT;
*devp = upriv->client;
return 0;
}
uint sandbox_pci_read_bar(u32 barval, int type, uint size) @@ -89,6 +106,7 @@ UCLASS_DRIVER(pci_emul) = { .post_probe = sandbox_pci_emul_post_probe, .pre_remove = sandbox_pci_emul_pre_remove, .priv_auto_alloc_size = sizeof(struct sandbox_pci_emul_priv),
.per_device_auto_alloc_size = sizeof(struct pci_emul_uc_priv),
};
/* diff --git a/include/pci.h b/include/pci.h index 8aa6636cfbf..ff59ac0e695 100644 --- a/include/pci.h +++ b/include/pci.h @@ -1490,6 +1490,17 @@ int dm_pci_find_device(unsigned int vendor, unsigned int device, int index, */ int dm_pci_find_class(uint find_class, int index, struct udevice **devp);
+/**
- struct pci_emul_uc_priv - holds info about an emulator device
- There is always at most one emulator per client
- @client: Client device if any, else NULL
- */
+struct pci_emul_uc_priv {
struct udevice *client;
+};
/**
- struct dm_pci_emul_ops - PCI device emulator operations
*/ @@ -1592,6 +1603,15 @@ struct dm_pci_emul_ops { int sandbox_pci_get_emul(struct udevice *bus, pci_dev_t find_devfn, struct udevice **containerp, struct udevice **emulp);
+/**
- sandbox_pci_get_client() - Find the client for an emulation device
- @emul: Emulation device to check
- @devp: Returns the client device emulated by this device
- @return 0 if OK, -ENOENT if the device has no client yet
- */
+int sandbox_pci_get_client(struct udevice *emul, struct udevice **devp);
/**
- pci_get_devfn() - Extract the devfn from fdt_pci_addr of the device
--
The changes look good to me. Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!

Intel x86 SoCs have a power manager/controller which handles several power-related aspects of the platform. Add a uclass for this, with a few useful operations.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/power/Kconfig | 2 + drivers/power/power_mgr/Kconfig | 25 +++ drivers/power/power_mgr/Makefile | 6 + drivers/power/power_mgr/power-mgr-uclass.c | 191 +++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/power_mgr.h | 177 +++++++++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 drivers/power/power_mgr/Kconfig create mode 100644 drivers/power/power_mgr/Makefile create mode 100644 drivers/power/power_mgr/power-mgr-uclass.c create mode 100644 include/power/power_mgr.h
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 9495dca33b9..1cb3f6d5e25 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -4,6 +4,8 @@ source "drivers/power/domain/Kconfig"
source "drivers/power/pmic/Kconfig"
+source "drivers/power/power_mgr/Kconfig" + source "drivers/power/regulator/Kconfig"
choice diff --git a/drivers/power/power_mgr/Kconfig b/drivers/power/power_mgr/Kconfig new file mode 100644 index 00000000000..2731518462f --- /dev/null +++ b/drivers/power/power_mgr/Kconfig @@ -0,0 +1,25 @@ +config POWER_MGR + bool "Power Manager (x86 PMC) support" + help + Enable support for an x86-style power-management controller which + provides features including checking whether the system started from + resume, powering off the system and enabling/disabling the reset + mechanism. + +config SPL_POWER_MGR + bool "Power Manager (x86 PMC) support in SPL" + default y if POWER_MGR + help + Enable support for an x86-style power-management controller which + provides features including checking whether the system started from + resume, powering off the system and enabling/disabling the reset + mechanism. + +config TPL_POWER_MGR + bool "Power Manager (x86 PMC) support in TPL" + default y if POWER_MGR + help + Enable support for an x86-style power-management controller which + provides features including checking whether the system started from + resume, powering off the system and enabling/disabling the reset + mechanism. diff --git a/drivers/power/power_mgr/Makefile b/drivers/power/power_mgr/Makefile new file mode 100644 index 00000000000..87542f5248a --- /dev/null +++ b/drivers/power/power_mgr/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2019 Google LLC + +obj-$(CONFIG_$(SPL_TPL_)POWER_MGR) += power-mgr-uclass.o + diff --git a/drivers/power/power_mgr/power-mgr-uclass.c b/drivers/power/power_mgr/power-mgr-uclass.c new file mode 100644 index 00000000000..0d73caf8cf6 --- /dev/null +++ b/drivers/power/power_mgr/power-mgr-uclass.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#define LOG_CATEGORY UCLASS_POWER_MGR + +#include <common.h> +#include <acpi_s3.h> +#include <dm.h> +#include <log.h> +#include <asm/io.h> +#ifdef CONFIG_CREATE_ARCH_SYMLINK +#include <asm/arch/gpio.h> +#endif +#include <power/power_mgr.h> + +enum { + PM1_STS = 0x00, + PM1_EN = 0x02, + PM1_CNT = 0x04, + + GPE0_STS = 0x20, + GPE0_EN = 0x30, +}; + +struct tco_regs { + u32 tco_rld; + u32 tco_sts; + u32 tco1_cnt; + u32 tco_tmr; +}; + +enum { + TCO_STS_TIMEOUT = 1 << 3, + TCO_STS_SECOND_TO_STS = 1 << 17, + TCO1_CNT_HLT = 1 << 11, +}; + +static void pmc_fill_pm_reg_info(struct udevice *dev) +{ + struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev); + int i; + + upriv->pm1_sts = inw(upriv->acpi_base + PM1_STS); + upriv->pm1_en = inw(upriv->acpi_base + PM1_EN); + upriv->pm1_cnt = inw(upriv->acpi_base + PM1_CNT); + + log_debug("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n", + upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt); + + for (i = 0; i < GPE0_REG_MAX; i++) { + upriv->gpe0_sts[i] = inl(upriv->acpi_base + GPE0_STS + i * 4); + upriv->gpe0_en[i] = inl(upriv->acpi_base + GPE0_EN + i * 4); + log_debug("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i, + upriv->gpe0_sts[i], i, upriv->gpe0_en[i]); + } +} + +int pmc_disable_tco_base(ulong tco_base) +{ + struct tco_regs *regs = (struct tco_regs *)tco_base; + + debug("tco_base %lx = %x\n", (ulong)®s->tco1_cnt, TCO1_CNT_HLT); + setio_32(®s->tco1_cnt, TCO1_CNT_HLT); + + return 0; +} + +int pmc_init(struct udevice *dev) +{ + const struct power_mgr_ops *ops = power_mgr_get_ops(dev); + int ret; + + pmc_fill_pm_reg_info(dev); + if (!ops->init) + return -ENOSYS; + + ret = ops->init(dev); + if (ret) + return log_msg_ret("Failed to init pmc", ret); + +#ifdef DEBUG + pmc_dump_info(dev); +#endif + + return 0; +} + +int pmc_prev_sleep_state(struct udevice *dev) +{ + struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev); + const struct power_mgr_ops *ops = power_mgr_get_ops(dev); + int prev_sleep_state = ACPI_S0; /* Default to S0 */ + + if (upriv->pm1_sts & WAK_STS) { + switch (acpi_sleep_from_pm1(upriv->pm1_cnt)) { + case ACPI_S3: + if (IS_ENABLED(HAVE_ACPI_RESUME)) + prev_sleep_state = ACPI_S3; + break; + case ACPI_S5: + prev_sleep_state = ACPI_S5; + break; + default: + break; + } + + /* Clear SLP_TYP */ + outl(upriv->pm1_cnt & ~SLP_TYP, upriv->acpi_base + PM1_CNT); + } + + if (!ops->prev_sleep_state) + return prev_sleep_state; + + return ops->prev_sleep_state(dev, prev_sleep_state); +} + +int pmc_disable_tco(struct udevice *dev) +{ + const struct power_mgr_ops *ops = power_mgr_get_ops(dev); + + pmc_fill_pm_reg_info(dev); + if (!ops->disable_tco) + return -ENOSYS; + + return ops->disable_tco(dev); +} + +int pmc_global_reset_set_enable(struct udevice *dev, bool enable) +{ + const struct power_mgr_ops *ops = power_mgr_get_ops(dev); + + if (!ops->global_reset_set_enable) + return -ENOSYS; + + return ops->global_reset_set_enable(dev, enable); +} + +void pmc_dump_info(struct udevice *dev) +{ + struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev); + int i; + + printf("Device: %s\n", dev->name); + printf("ACPI base %x, pmc_bar0 %p, pmc_bar2 %p, gpe_cfg %p\n", + upriv->acpi_base, upriv->pmc_bar0, upriv->pmc_bar2, + upriv->gpe_cfg); + printf("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n", + upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt); + + for (i = 0; i < GPE0_REG_MAX; i++) { + printf("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i, + upriv->gpe0_sts[i], i, upriv->gpe0_en[i]); + } + + printf("prsts: %08x\n", upriv->prsts); + printf("tco_sts: %04x %04x\n", upriv->tco1_sts, upriv->tco2_sts); + printf("gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n", + upriv->gen_pmcon1, upriv->gen_pmcon2, upriv->gen_pmcon3); +} + +int pmc_ofdata_to_uc_platdata(struct udevice *dev) +{ + struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev); + int ret; + + ret = dev_read_u32(dev, "gpe0-dwx-mask", &upriv->gpe0_dwx_mask); + if (ret) + return log_msg_ret("no gpe0-dwx-mask", ret); + ret = dev_read_u32(dev, "gpe0-dwx-shift-base", + &upriv->gpe0_dwx_shift_base); + if (ret) + return log_msg_ret("no gpe0-dwx-shift-base", ret); + ret = dev_read_u32(dev, "gpe0-sts", &upriv->gpe0_sts_reg); + if (ret) + return log_msg_ret("no gpe0-sts", ret); + upriv->gpe0_sts_reg += upriv->acpi_base; + ret = dev_read_u32(dev, "gpe0-en", &upriv->gpe0_en_reg); + if (ret) + return log_msg_ret("no gpe0-en", ret); + upriv->gpe0_en_reg += upriv->acpi_base; + + return 0; +} + +UCLASS_DRIVER(power_mgr) = { + .id = UCLASS_POWER_MGR, + .name = "power-mgr", + .per_device_auto_alloc_size = sizeof(struct power_mgr_upriv), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f431f3bf294..907fe257ad1 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -79,6 +79,7 @@ enum uclass_id { UCLASS_PINCTRL, /* Pinctrl (pin muxing/configuration) device */ UCLASS_PMIC, /* PMIC I/O device */ UCLASS_POWER_DOMAIN, /* (SoC) Power domains */ + UCLASS_POWER_MGR, /* (x86) Power managerment controller (PMC) */ UCLASS_PWM, /* Pulse-width modulator */ UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_RAM, /* RAM controller */ diff --git a/include/power/power_mgr.h b/include/power/power_mgr.h new file mode 100644 index 00000000000..7f6cdc5cd62 --- /dev/null +++ b/include/power/power_mgr.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2019 Google LLC + */ + +#ifndef __POWER_MGR_H +#define __POWER_MGR_H + +enum { + GPE0_REG_MAX = 4, +}; + +/** + * struct power_mgr_upriv - holds common data for the x86 PMC + * + * @pmc_bar0: Base address 0 of PMC + * @pmc_bar1: Base address 2 of PMC + * @acpi_base: Base address of ACPI block + * @pm1_sts: PM1 status + * @pm1_en: PM1 enable + * @pm1_cnt: PM1 control + * @gpe_cfg: Address of GPE_CFG register + * @gpe0_dwx_mask: Mask to use for each GPE0 (typically 7 or 0xf) + * @gpe0_dwx_shift_base: Base shift value to use for GPE0 (0 or 4) + * @gpe0_sts_req: GPE0 status register offset + * @gpe0_en_req: GPE0 enable register offset + * @gpe0_sts: GPE0 status values + * @gpe0_en: GPE0 enable values + * @gpe0_dw: GPE0 DW values + * @gpe0_count: Number of GPE0 registers + * @tco1_sts: TCO1 status + * @tco2_sts: TCO2 status + * @prsts: Power and reset status + * @gen_pmcon1: General power mgmt configuration 1 + * @gen_pmcon2: General power mgmt configuration 2 + * @gen_pmcon3: General power mgmt configuration 3 + */ +struct power_mgr_upriv { + void *pmc_bar0; + void *pmc_bar2; + u32 acpi_base; + u16 pm1_sts; + u16 pm1_en; + u32 pm1_cnt; + u32 *gpe_cfg; + u32 gpe0_dwx_mask; + u32 gpe0_dwx_shift_base; + u32 gpe0_sts_reg; + u32 gpe0_en_reg; + u32 gpe0_sts[GPE0_REG_MAX]; + u32 gpe0_en[GPE0_REG_MAX]; + u32 gpe0_dw[GPE0_REG_MAX]; + int gpe0_count; + u16 tco1_sts; + u16 tco2_sts; + u32 prsts; + u32 gen_pmcon1; + u32 gen_pmcon2; + u32 gen_pmcon3; +}; + +struct power_mgr_ops { + /** + * init() - Set up the PMC for use + * + * This reads the current state of the PMC. Most of the state is read + * automatically by the uclass since it is common. + * + * @dev: PMC device to use + * @return 0 if OK, -ve on error + */ + int (*init)(struct udevice *dev); + + /** + * prev_sleep_state() - Get the previous sleep state (optional) + * + * This reads various state registers and returns the sleep state from + * which the system woke. If this method is not provided, the uclass + * will return a calculated value. + * + * @dev: PMC device to use + * @prev_sleep_state: Previous sleep state as calculated by the uclass. + * The method can use this as the return value or calculate its + * own. + * + * @return enum acpi_sleep_state indicating the previous sleep state + * (ACPI_S0, ACPI_S3 or ACPI_S5), or -ve on error + */ + int (*prev_sleep_state)(struct udevice *dev, int prev_sleep_state); + + /** + * disable_tco() - Disable the timer/counter + * + * Disables the timer/counter in the PMC + * + * @dev: PMC device to use + * @return 0 + */ + int (*disable_tco)(struct udevice *dev); + + /** + * global_reset_set_enable() - Enable/Disable global reset + * + * Enable or disable global reset. If global reset is enabled, both hard + * reset and soft reset will trigger global reset, where both host and + * TXE are reset. This is cleared on cold boot, hard reset, soft reset + * and Sx. + * + * @dev: PMC device to use + * @enable: true to enable global reset, false to disable + * @return 0 + */ + int (*global_reset_set_enable)(struct udevice *dev, bool enable); +}; + +#define power_mgr_get_ops(dev) ((struct power_mgr_ops *)(dev)->driver->ops) + +/** + * init() - Set up the PMC for use + * + * This reads the current state of the PMC. This reads in the common registers, + * then calls the device's init() method to read the SoC-specific registers. + * + * @return 0 if OK, -ve on error + */ +int pmc_init(struct udevice *dev); + +/** + * pmc_prev_sleep_state() - Get the previous sleep state + * + * This reads various state registers and returns the sleep state from + * which the system woke. + * + * @return enum acpi_sleep_state indicating the previous sleep state + * (ACPI_S0, ACPI_S3 or ACPI_S5), or -ve on error + */ +int pmc_prev_sleep_state(struct udevice *dev); + +/** + * pmc_disable_tco() - Disable the timer/counter + * + * Disables the timer/counter in the PMC + * + * @dev: PMC device to use + * @return 0 + */ +int pmc_disable_tco(struct udevice *dev); + +/** + * pmc_global_reset_set_enable() - Enable/Disable global reset + * + * Enable or disable global reset. If global reset is enabled, both hard + * reset and soft reset will trigger global reset, where both host and + * TXE are reset. This is cleared on cold boot, hard reset, soft reset + * and Sx. + * + * @dev: PMC device to use + * @enable: true to enable global reset, false to disable + * @return 0 + */ +int pmc_global_reset_set_enable(struct udevice *dev, bool enable); + +int pmc_ofdata_to_uc_platdata(struct udevice *dev); + +int pmc_disable_tco_base(ulong tco_base); + +void pmc_dump_info(struct udevice *dev); + +/** + * pmc_gpe_init() - Set up general-purpose events + * + * @dev: PMC device + * @return 0 if OK, -ve on error + */ +int pmc_gpe_init(struct udevice *dev); + +#endif

Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Intel x86 SoCs have a power manager/controller which handles several power-related aspects of the platform. Add a uclass for this, with a few useful operations.
I don't like to create another x86 specific uclass for this power management controller.
I see two options:
- Create a standard acpi-pmc uclass instead. Almost all registers in the PMC module follow the ACPI spec, except a few - Do not abstract this to a uclass level. Use platform codes to do such. x86 SoC varies from one to another, and it's very hard to do a one-size-fit-all job.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/power/Kconfig | 2 + drivers/power/power_mgr/Kconfig | 25 +++ drivers/power/power_mgr/Makefile | 6 + drivers/power/power_mgr/power-mgr-uclass.c | 191 +++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/power_mgr.h | 177 +++++++++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 drivers/power/power_mgr/Kconfig create mode 100644 drivers/power/power_mgr/Makefile create mode 100644 drivers/power/power_mgr/power-mgr-uclass.c create mode 100644 include/power/power_mgr.h
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 9495dca33b9..1cb3f6d5e25 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -4,6 +4,8 @@ source "drivers/power/domain/Kconfig"
source "drivers/power/pmic/Kconfig"
+source "drivers/power/power_mgr/Kconfig"
source "drivers/power/regulator/Kconfig"
choice diff --git a/drivers/power/power_mgr/Kconfig b/drivers/power/power_mgr/Kconfig new file mode 100644 index 00000000000..2731518462f --- /dev/null +++ b/drivers/power/power_mgr/Kconfig @@ -0,0 +1,25 @@ +config POWER_MGR
bool "Power Manager (x86 PMC) support"
help
Enable support for an x86-style power-management controller which
provides features including checking whether the system started from
resume, powering off the system and enabling/disabling the reset
mechanism.
+config SPL_POWER_MGR
bool "Power Manager (x86 PMC) support in SPL"
default y if POWER_MGR
help
Enable support for an x86-style power-management controller which
provides features including checking whether the system started from
resume, powering off the system and enabling/disabling the reset
mechanism.
+config TPL_POWER_MGR
bool "Power Manager (x86 PMC) support in TPL"
Why would we need access PMC in both SPL and TPL?
default y if POWER_MGR
help
Enable support for an x86-style power-management controller which
provides features including checking whether the system started from
resume, powering off the system and enabling/disabling the reset
mechanism.
diff --git a/drivers/power/power_mgr/Makefile b/drivers/power/power_mgr/Makefile new file mode 100644 index 00000000000..87542f5248a --- /dev/null +++ b/drivers/power/power_mgr/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2019 Google LLC
+obj-$(CONFIG_$(SPL_TPL_)POWER_MGR) += power-mgr-uclass.o
diff --git a/drivers/power/power_mgr/power-mgr-uclass.c b/drivers/power/power_mgr/power-mgr-uclass.c new file mode 100644 index 00000000000..0d73caf8cf6 --- /dev/null +++ b/drivers/power/power_mgr/power-mgr-uclass.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright 2019 Google LLC
- */
+#define LOG_CATEGORY UCLASS_POWER_MGR
+#include <common.h> +#include <acpi_s3.h> +#include <dm.h> +#include <log.h> +#include <asm/io.h> +#ifdef CONFIG_CREATE_ARCH_SYMLINK +#include <asm/arch/gpio.h> +#endif +#include <power/power_mgr.h>
+enum {
PM1_STS = 0x00,
PM1_EN = 0x02,
PM1_CNT = 0x04,
GPE0_STS = 0x20,
GPE0_EN = 0x30,
+};
+struct tco_regs {
u32 tco_rld;
u32 tco_sts;
u32 tco1_cnt;
u32 tco_tmr;
+};
+enum {
TCO_STS_TIMEOUT = 1 << 3,
TCO_STS_SECOND_TO_STS = 1 << 17,
TCO1_CNT_HLT = 1 << 11,
+};
+static void pmc_fill_pm_reg_info(struct udevice *dev) +{
struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev);
int i;
upriv->pm1_sts = inw(upriv->acpi_base + PM1_STS);
upriv->pm1_en = inw(upriv->acpi_base + PM1_EN);
upriv->pm1_cnt = inw(upriv->acpi_base + PM1_CNT);
log_debug("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
for (i = 0; i < GPE0_REG_MAX; i++) {
upriv->gpe0_sts[i] = inl(upriv->acpi_base + GPE0_STS + i * 4);
upriv->gpe0_en[i] = inl(upriv->acpi_base + GPE0_EN + i * 4);
log_debug("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
}
+}
+int pmc_disable_tco_base(ulong tco_base) +{
TCO is not defined in the ACPI spec. This is APL specific. It looks this has something to do with the hardware watchdog?
Anyway, if we want to put such in an acpi-pmc uclass driver, we should mark such op as optional.
struct tco_regs *regs = (struct tco_regs *)tco_base;
debug("tco_base %lx = %x\n", (ulong)®s->tco1_cnt, TCO1_CNT_HLT);
setio_32(®s->tco1_cnt, TCO1_CNT_HLT);
return 0;
+}
+int pmc_init(struct udevice *dev) +{
const struct power_mgr_ops *ops = power_mgr_get_ops(dev);
int ret;
pmc_fill_pm_reg_info(dev);
if (!ops->init)
return -ENOSYS;
ret = ops->init(dev);
if (ret)
return log_msg_ret("Failed to init pmc", ret);
+#ifdef DEBUG
pmc_dump_info(dev);
+#endif
return 0;
+}
+int pmc_prev_sleep_state(struct udevice *dev) +{
struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev);
const struct power_mgr_ops *ops = power_mgr_get_ops(dev);
int prev_sleep_state = ACPI_S0; /* Default to S0 */
if (upriv->pm1_sts & WAK_STS) {
switch (acpi_sleep_from_pm1(upriv->pm1_cnt)) {
case ACPI_S3:
if (IS_ENABLED(HAVE_ACPI_RESUME))
prev_sleep_state = ACPI_S3;
break;
case ACPI_S5:
prev_sleep_state = ACPI_S5;
break;
default:
break;
}
/* Clear SLP_TYP */
outl(upriv->pm1_cnt & ~SLP_TYP, upriv->acpi_base + PM1_CNT);
}
if (!ops->prev_sleep_state)
return prev_sleep_state;
return ops->prev_sleep_state(dev, prev_sleep_state);
+}
+int pmc_disable_tco(struct udevice *dev) +{
const struct power_mgr_ops *ops = power_mgr_get_ops(dev);
pmc_fill_pm_reg_info(dev);
if (!ops->disable_tco)
return -ENOSYS;
return ops->disable_tco(dev);
+}
+int pmc_global_reset_set_enable(struct udevice *dev, bool enable) +{
const struct power_mgr_ops *ops = power_mgr_get_ops(dev);
if (!ops->global_reset_set_enable)
return -ENOSYS;
return ops->global_reset_set_enable(dev, enable);
+}
+void pmc_dump_info(struct udevice *dev) +{
struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev);
int i;
printf("Device: %s\n", dev->name);
printf("ACPI base %x, pmc_bar0 %p, pmc_bar2 %p, gpe_cfg %p\n",
upriv->acpi_base, upriv->pmc_bar0, upriv->pmc_bar2,
upriv->gpe_cfg);
printf("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
for (i = 0; i < GPE0_REG_MAX; i++) {
printf("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
}
printf("prsts: %08x\n", upriv->prsts);
printf("tco_sts: %04x %04x\n", upriv->tco1_sts, upriv->tco2_sts);
printf("gen_pmcon1: %08x gen_pmcon2: %08x gen_pmcon3: %08x\n",
upriv->gen_pmcon1, upriv->gen_pmcon2, upriv->gen_pmcon3);
+}
+int pmc_ofdata_to_uc_platdata(struct udevice *dev) +{
struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev);
int ret;
ret = dev_read_u32(dev, "gpe0-dwx-mask", &upriv->gpe0_dwx_mask);
if (ret)
return log_msg_ret("no gpe0-dwx-mask", ret);
ret = dev_read_u32(dev, "gpe0-dwx-shift-base",
&upriv->gpe0_dwx_shift_base);
if (ret)
return log_msg_ret("no gpe0-dwx-shift-base", ret);
ret = dev_read_u32(dev, "gpe0-sts", &upriv->gpe0_sts_reg);
if (ret)
return log_msg_ret("no gpe0-sts", ret);
upriv->gpe0_sts_reg += upriv->acpi_base;
ret = dev_read_u32(dev, "gpe0-en", &upriv->gpe0_en_reg);
if (ret)
return log_msg_ret("no gpe0-en", ret);
upriv->gpe0_en_reg += upriv->acpi_base;
return 0;
+}
+UCLASS_DRIVER(power_mgr) = {
.id = UCLASS_POWER_MGR,
.name = "power-mgr",
.per_device_auto_alloc_size = sizeof(struct power_mgr_upriv),
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index f431f3bf294..907fe257ad1 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -79,6 +79,7 @@ enum uclass_id { UCLASS_PINCTRL, /* Pinctrl (pin muxing/configuration) device */ UCLASS_PMIC, /* PMIC I/O device */ UCLASS_POWER_DOMAIN, /* (SoC) Power domains */
UCLASS_POWER_MGR, /* (x86) Power managerment controller (PMC) */ UCLASS_PWM, /* Pulse-width modulator */ UCLASS_PWRSEQ, /* Power sequence device */ UCLASS_RAM, /* RAM controller */
diff --git a/include/power/power_mgr.h b/include/power/power_mgr.h new file mode 100644 index 00000000000..7f6cdc5cd62 --- /dev/null +++ b/include/power/power_mgr.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright 2019 Google LLC
- */
+#ifndef __POWER_MGR_H +#define __POWER_MGR_H
+enum {
GPE0_REG_MAX = 4,
+};
+/**
- struct power_mgr_upriv - holds common data for the x86 PMC
- @pmc_bar0: Base address 0 of PMC
- @pmc_bar1: Base address 2 of PMC
- @acpi_base: Base address of ACPI block
- @pm1_sts: PM1 status
- @pm1_en: PM1 enable
- @pm1_cnt: PM1 control
- @gpe_cfg: Address of GPE_CFG register
- @gpe0_dwx_mask: Mask to use for each GPE0 (typically 7 or 0xf)
- @gpe0_dwx_shift_base: Base shift value to use for GPE0 (0 or 4)
- @gpe0_sts_req: GPE0 status register offset
- @gpe0_en_req: GPE0 enable register offset
- @gpe0_sts: GPE0 status values
- @gpe0_en: GPE0 enable values
- @gpe0_dw: GPE0 DW values
- @gpe0_count: Number of GPE0 registers
- @tco1_sts: TCO1 status
- @tco2_sts: TCO2 status
- @prsts: Power and reset status
- @gen_pmcon1: General power mgmt configuration 1
- @gen_pmcon2: General power mgmt configuration 2
- @gen_pmcon3: General power mgmt configuration 3
- */
+struct power_mgr_upriv {
void *pmc_bar0;
void *pmc_bar2;
u32 acpi_base;
u16 pm1_sts;
u16 pm1_en;
u32 pm1_cnt;
u32 *gpe_cfg;
u32 gpe0_dwx_mask;
u32 gpe0_dwx_shift_base;
u32 gpe0_sts_reg;
u32 gpe0_en_reg;
u32 gpe0_sts[GPE0_REG_MAX];
u32 gpe0_en[GPE0_REG_MAX];
u32 gpe0_dw[GPE0_REG_MAX];
int gpe0_count;
u16 tco1_sts;
u16 tco2_sts;
u32 prsts;
u32 gen_pmcon1;
u32 gen_pmcon2;
u32 gen_pmcon3;
+};
+struct power_mgr_ops {
/**
* init() - Set up the PMC for use
*
* This reads the current state of the PMC. Most of the state is read
* automatically by the uclass since it is common.
*
* @dev: PMC device to use
* @return 0 if OK, -ve on error
*/
int (*init)(struct udevice *dev);
/**
* prev_sleep_state() - Get the previous sleep state (optional)
*
* This reads various state registers and returns the sleep state from
* which the system woke. If this method is not provided, the uclass
* will return a calculated value.
*
* @dev: PMC device to use
* @prev_sleep_state: Previous sleep state as calculated by the uclass.
* The method can use this as the return value or calculate its
* own.
*
* @return enum acpi_sleep_state indicating the previous sleep state
* (ACPI_S0, ACPI_S3 or ACPI_S5), or -ve on error
*/
int (*prev_sleep_state)(struct udevice *dev, int prev_sleep_state);
/**
* disable_tco() - Disable the timer/counter
*
* Disables the timer/counter in the PMC
*
* @dev: PMC device to use
* @return 0
*/
int (*disable_tco)(struct udevice *dev);
/**
* global_reset_set_enable() - Enable/Disable global reset
*
* Enable or disable global reset. If global reset is enabled, both hard
* reset and soft reset will trigger global reset, where both host and
* TXE are reset. This is cleared on cold boot, hard reset, soft reset
* and Sx.
*
* @dev: PMC device to use
* @enable: true to enable global reset, false to disable
* @return 0
*/
int (*global_reset_set_enable)(struct udevice *dev, bool enable);
+};
+#define power_mgr_get_ops(dev) ((struct power_mgr_ops *)(dev)->driver->ops)
+/**
- init() - Set up the PMC for use
- This reads the current state of the PMC. This reads in the common registers,
- then calls the device's init() method to read the SoC-specific registers.
- @return 0 if OK, -ve on error
- */
+int pmc_init(struct udevice *dev);
+/**
- pmc_prev_sleep_state() - Get the previous sleep state
- This reads various state registers and returns the sleep state from
- which the system woke.
- @return enum acpi_sleep_state indicating the previous sleep state
(ACPI_S0, ACPI_S3 or ACPI_S5), or -ve on error
- */
+int pmc_prev_sleep_state(struct udevice *dev);
+/**
- pmc_disable_tco() - Disable the timer/counter
- Disables the timer/counter in the PMC
- @dev: PMC device to use
- @return 0
- */
+int pmc_disable_tco(struct udevice *dev);
+/**
- pmc_global_reset_set_enable() - Enable/Disable global reset
- Enable or disable global reset. If global reset is enabled, both hard
- reset and soft reset will trigger global reset, where both host and
- TXE are reset. This is cleared on cold boot, hard reset, soft reset
- and Sx.
- @dev: PMC device to use
- @enable: true to enable global reset, false to disable
- @return 0
- */
+int pmc_global_reset_set_enable(struct udevice *dev, bool enable);
+int pmc_ofdata_to_uc_platdata(struct udevice *dev);
+int pmc_disable_tco_base(ulong tco_base);
+void pmc_dump_info(struct udevice *dev);
+/**
- pmc_gpe_init() - Set up general-purpose events
- @dev: PMC device
- @return 0 if OK, -ve on error
- */
+int pmc_gpe_init(struct udevice *dev);
+#endif
Regards, Bin

Hi Bin,
On Wed, 9 Oct 2019 at 21:11, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
Intel x86 SoCs have a power manager/controller which handles several power-related aspects of the platform. Add a uclass for this, with a few useful operations.
I don't like to create another x86 specific uclass for this power management controller.
I see two options:
- Create a standard acpi-pmc uclass instead. Almost all registers in
the PMC module follow the ACPI spec, except a few
- Do not abstract this to a uclass level. Use platform codes to do
such. x86 SoC varies from one to another, and it's very hard to do a one-size-fit-all job.
I like the first option, at least for now. I suppose as we see more SoCs added it might get tricky, but quite a few seem to use this common approach.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/power/Kconfig | 2 + drivers/power/power_mgr/Kconfig | 25 +++ drivers/power/power_mgr/Makefile | 6 + drivers/power/power_mgr/power-mgr-uclass.c | 191 +++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/power/power_mgr.h | 177 +++++++++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 drivers/power/power_mgr/Kconfig create mode 100644 drivers/power/power_mgr/Makefile create mode 100644 drivers/power/power_mgr/power-mgr-uclass.c create mode 100644 include/power/power_mgr.h
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 9495dca33b9..1cb3f6d5e25 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -4,6 +4,8 @@ source "drivers/power/domain/Kconfig"
source "drivers/power/pmic/Kconfig"
+source "drivers/power/power_mgr/Kconfig"
source "drivers/power/regulator/Kconfig"
choice diff --git a/drivers/power/power_mgr/Kconfig b/drivers/power/power_mgr/Kconfig new file mode 100644 index 00000000000..2731518462f --- /dev/null +++ b/drivers/power/power_mgr/Kconfig @@ -0,0 +1,25 @@ +config POWER_MGR
bool "Power Manager (x86 PMC) support"
help
Enable support for an x86-style power-management controller which
provides features including checking whether the system started from
resume, powering off the system and enabling/disabling the reset
mechanism.
+config SPL_POWER_MGR
bool "Power Manager (x86 PMC) support in SPL"
default y if POWER_MGR
help
Enable support for an x86-style power-management controller which
provides features including checking whether the system started from
resume, powering off the system and enabling/disabling the reset
mechanism.
+config TPL_POWER_MGR
bool "Power Manager (x86 PMC) support in TPL"
Why would we need access PMC in both SPL and TPL?
The code used in TPL is in arch_cpu_init_tpm():
- enable the fixed BAR - clear global reset promotion - disable TCO
default y if POWER_MGR
help
Enable support for an x86-style power-management controller which
provides features including checking whether the system started from
resume, powering off the system and enabling/disabling the reset
mechanism.
diff --git a/drivers/power/power_mgr/Makefile b/drivers/power/power_mgr/Makefile new file mode 100644 index 00000000000..87542f5248a --- /dev/null +++ b/drivers/power/power_mgr/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2019 Google LLC
+obj-$(CONFIG_$(SPL_TPL_)POWER_MGR) += power-mgr-uclass.o
diff --git a/drivers/power/power_mgr/power-mgr-uclass.c b/drivers/power/power_mgr/power-mgr-uclass.c new file mode 100644 index 00000000000..0d73caf8cf6 --- /dev/null +++ b/drivers/power/power_mgr/power-mgr-uclass.c @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: GPL-2.0 +/*
- Copyright 2019 Google LLC
- */
+#define LOG_CATEGORY UCLASS_POWER_MGR
+#include <common.h> +#include <acpi_s3.h> +#include <dm.h> +#include <log.h> +#include <asm/io.h> +#ifdef CONFIG_CREATE_ARCH_SYMLINK +#include <asm/arch/gpio.h> +#endif +#include <power/power_mgr.h>
+enum {
PM1_STS = 0x00,
PM1_EN = 0x02,
PM1_CNT = 0x04,
GPE0_STS = 0x20,
GPE0_EN = 0x30,
+};
+struct tco_regs {
u32 tco_rld;
u32 tco_sts;
u32 tco1_cnt;
u32 tco_tmr;
+};
+enum {
TCO_STS_TIMEOUT = 1 << 3,
TCO_STS_SECOND_TO_STS = 1 << 17,
TCO1_CNT_HLT = 1 << 11,
+};
+static void pmc_fill_pm_reg_info(struct udevice *dev) +{
struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev);
int i;
upriv->pm1_sts = inw(upriv->acpi_base + PM1_STS);
upriv->pm1_en = inw(upriv->acpi_base + PM1_EN);
upriv->pm1_cnt = inw(upriv->acpi_base + PM1_CNT);
log_debug("pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
upriv->pm1_sts, upriv->pm1_en, upriv->pm1_cnt);
for (i = 0; i < GPE0_REG_MAX; i++) {
upriv->gpe0_sts[i] = inl(upriv->acpi_base + GPE0_STS + i * 4);
upriv->gpe0_en[i] = inl(upriv->acpi_base + GPE0_EN + i * 4);
log_debug("gpe0_sts[%d]: %08x gpe0_en[%d]: %08x\n", i,
upriv->gpe0_sts[i], i, upriv->gpe0_en[i]);
}
+}
+int pmc_disable_tco_base(ulong tco_base) +{
TCO is not defined in the ACPI spec. This is APL specific. It looks this has something to do with the hardware watchdog?
Anyway, if we want to put such in an acpi-pmc uclass driver, we should mark such op as optional.
OK.
Regards, SImon

Add a simple PMC for sandbox to permit tests to run.
Signed-off-by: Simon Glass sjg@chromium.org ---
Makefile | 3 +- arch/Kconfig | 2 + arch/sandbox/dts/sandbox.dtsi | 14 ++ arch/sandbox/dts/test.dts | 14 ++ arch/sandbox/include/asm/test.h | 1 + drivers/Makefile | 2 + drivers/power/power_mgr/Kconfig | 9 ++ drivers/power/power_mgr/Makefile | 2 +- drivers/power/power_mgr/pmc_emul.c | 246 +++++++++++++++++++++++++++++ drivers/power/power_mgr/sandbox.c | 97 ++++++++++++ test/dm/Makefile | 1 + test/dm/pmc.c | 33 ++++ 12 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 drivers/power/power_mgr/pmc_emul.c create mode 100644 drivers/power/power_mgr/sandbox.c create mode 100644 test/dm/pmc.c
diff --git a/Makefile b/Makefile index 43961af590f..f008d13d02a 100644 --- a/Makefile +++ b/Makefile @@ -725,7 +725,8 @@ libs-y += drivers/power/ \ drivers/power/mfd/ \ drivers/power/pmic/ \ drivers/power/battery/ \ - drivers/power/regulator/ + drivers/power/regulator/ \ + drivers/power/power_mgr/ libs-y += drivers/spi/ libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/ libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/ diff --git a/arch/Kconfig b/arch/Kconfig index 141e48bc439..e22d62f9290 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -133,6 +133,8 @@ config SANDBOX imply PHYLIB imply DM_MDIO imply DM_MDIO_MUX + imply POWER_MGR + imply POWER_MGR_SANDBOX
config SH bool "SuperH architecture" diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index f09bc70b0da..7bf144f5326 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -100,6 +100,17 @@ };
pci-controller { + pci@1e,0 { + compatible = "sandbox,pmc"; + reg = <0xf000 0 0 0 0>; + sandbox,emul = <&pmc_emul>; + gpe0-dwx-mask = <0xf>; + gpe0-dwx-shift-base = <4>; + gpe0-dw = <6 7 9>; + gpe0-sts = <0x20>; + gpe0-en = <0x30>; + }; + pci@1f,0 { compatible = "pci-generic"; reg = <0xf800 0 0 0 0>; @@ -109,6 +120,9 @@
emul { compatible = "sandbox,pci-emul-parent"; + pmc_emul: emul@1e,0 { + compatible = "sandbox,pmc-emul"; + }; swap_case_emul: emul@1f,0 { compatible = "sandbox,swap-case"; }; diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 8733e0d7e19..9b72c2f279c 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -461,6 +461,17 @@ 0x0100f810 0 0 0 0>; sandbox,emul = <&swap_case_emul1>; }; + pci@1e,0 { + compatible = "sandbox,pmc"; + reg = <0xf000 0 0 0 0>; + sandbox,emul = <&pmc_emul1e>; + acpi-base = <0x400>; + gpe0-dwx-mask = <0xf>; + gpe0-dwx-shift-base = <4>; + gpe0-dw = <6 7 9>; + gpe0-sts = <0x20>; + gpe0-en = <0x30>; + }; pci@1f,0 { compatible = "pci-generic"; /* BAR1 is at 0x10, using FDT_PCI_SPACE_IO */ @@ -478,6 +489,9 @@ compatible = "sandbox,swap-case"; use-ea; }; + pmc_emul1e: emul@1e,0 { + compatible = "sandbox,pmc-emul"; + }; swap_case_emul1f: emul@1f,0 { compatible = "sandbox,swap-case"; }; diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index cd2b9e3155d..7f9e7fc26f5 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -13,6 +13,7 @@
#define SANDBOX_PCI_VENDOR_ID 0x1234 #define SANDBOX_PCI_SWAP_CASE_EMUL_ID 0x5678 +#define SANDBOX_PCI_PMC_EMUL_ID 0x5677 #define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM #define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL
diff --git a/drivers/Makefile b/drivers/Makefile index a4bb5e4975c..b2e081e6cc8 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_$(SPL_)ALTERA_SDRAM) += ddr/altera/ obj-$(CONFIG_ARCH_IMX8M) += ddr/imx/imx8m/ obj-$(CONFIG_SPL_POWER_SUPPORT) += power/ power/pmic/ obj-$(CONFIG_SPL_POWER_SUPPORT) += power/regulator/ +obj-$(CONFIG_SPL_POWER_MGR) += power/power_mgr/ obj-$(CONFIG_SPL_POWER_DOMAIN) += power/domain/ obj-$(CONFIG_SPL_DM_RESET) += reset/ obj-$(CONFIG_SPL_MTD_SUPPORT) += mtd/ @@ -67,6 +68,7 @@ endif ifdef CONFIG_TPL_BUILD
obj-$(CONFIG_TPL_MPC8XXX_INIT_DDR_SUPPORT) += ddr/fsl/ +obj-$(CONFIG_TPL_POWER_MGR) += power/power_mgr/
endif
diff --git a/drivers/power/power_mgr/Kconfig b/drivers/power/power_mgr/Kconfig index 2731518462f..8047ecf3a80 100644 --- a/drivers/power/power_mgr/Kconfig +++ b/drivers/power/power_mgr/Kconfig @@ -23,3 +23,12 @@ config TPL_POWER_MGR provides features including checking whether the system started from resume, powering off the system and enabling/disabling the reset mechanism. + +config POWER_MGR_SANDBOX + bool "Test power manager (PMC) for sandbox" + depends on POWER_MGR && SANDBOX + help + This driver emulates a PMC (Power-Management Controller) so that + the uclass logic can be tested. You can use the 'pmc' command to + access information from the driver. It uses I/O access to read + from the PMC. diff --git a/drivers/power/power_mgr/Makefile b/drivers/power/power_mgr/Makefile index 87542f5248a..a5bf131ad92 100644 --- a/drivers/power/power_mgr/Makefile +++ b/drivers/power/power_mgr/Makefile @@ -3,4 +3,4 @@ # Copyright 2019 Google LLC
obj-$(CONFIG_$(SPL_TPL_)POWER_MGR) += power-mgr-uclass.o - +obj-$(CONFIG_$(SPL_TPL_)POWER_MGR_SANDBOX) += sandbox.o pmc_emul.o diff --git a/drivers/power/power_mgr/pmc_emul.c b/drivers/power/power_mgr/pmc_emul.c new file mode 100644 index 00000000000..6fce245d7d9 --- /dev/null +++ b/drivers/power/power_mgr/pmc_emul.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PCI emulation device for an x86 Power-Management Controller (PMC) + * + * Copyright 2019 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <dm.h> +#include <pci.h> +#include <asm/test.h> +#include <power/power_mgr.h> + +/** + * struct pmc_emul_platdata - platform data for this device + * + * @command: Current PCI command value + * @bar: Current base address values + */ +struct pmc_emul_platdata { + u16 command; + u32 bar[6]; +}; + +enum { + MEMMAP_SIZE = 0x80, +}; + +static struct pci_bar { + int type; + u32 size; +} barinfo[] = { + { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { PCI_BASE_ADDRESS_SPACE_IO, 256 }, +}; + +struct pmc_emul_priv { + u8 regs[MEMMAP_SIZE]; +}; + +static int sandbox_pmc_emul_read_config(struct udevice *emul, uint offset, + ulong *valuep, enum pci_size_t size) +{ + struct pmc_emul_platdata *plat = dev_get_platdata(emul); + + switch (offset) { + case PCI_COMMAND: + *valuep = plat->command; + break; + case PCI_HEADER_TYPE: + *valuep = 0; + break; + case PCI_VENDOR_ID: + *valuep = SANDBOX_PCI_VENDOR_ID; + break; + case PCI_DEVICE_ID: + *valuep = SANDBOX_PCI_PMC_EMUL_ID; + break; + case PCI_CLASS_DEVICE: + if (size == PCI_SIZE_8) { + *valuep = SANDBOX_PCI_CLASS_SUB_CODE; + } else { + *valuep = (SANDBOX_PCI_CLASS_CODE << 8) | + SANDBOX_PCI_CLASS_SUB_CODE; + } + break; + case PCI_CLASS_CODE: + *valuep = SANDBOX_PCI_CLASS_CODE; + break; + case PCI_BASE_ADDRESS_0: + case PCI_BASE_ADDRESS_1: + case PCI_BASE_ADDRESS_2: + case PCI_BASE_ADDRESS_3: + case PCI_BASE_ADDRESS_4: + case PCI_BASE_ADDRESS_5: { + int barnum; + u32 *bar; + + barnum = pci_offset_to_barnum(offset); + bar = &plat->bar[barnum]; + + *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type, + barinfo[barnum].size); + break; + } + case PCI_CAPABILITY_LIST: + *valuep = PCI_CAP_ID_PM_OFFSET; + break; + } + + return 0; +} + +static int sandbox_pmc_emul_write_config(struct udevice *emul, uint offset, + ulong value, enum pci_size_t size) +{ + struct pmc_emul_platdata *plat = dev_get_platdata(emul); + + switch (offset) { + case PCI_COMMAND: + plat->command = value; + break; + case PCI_BASE_ADDRESS_0: + case PCI_BASE_ADDRESS_1: { + int barnum; + u32 *bar; + + barnum = pci_offset_to_barnum(offset); + bar = &plat->bar[barnum]; + + debug("w bar %d=%lx\n", barnum, value); + *bar = value; + /* space indicator (bit#0) is read-only */ + *bar |= barinfo[barnum].type; + break; + } + } + + return 0; +} + +static int sandbox_pmc_emul_find_bar(struct udevice *emul, unsigned int addr, + int *barnump, unsigned int *offsetp) +{ + struct pmc_emul_platdata *plat = dev_get_platdata(emul); + int barnum; + + for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) { + unsigned int size = barinfo[barnum].size; + u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE; + + if (addr >= base && addr < base + size) { + *barnump = barnum; + *offsetp = addr - base; + return 0; + } + } + *barnump = -1; + + return -ENOENT; +} + +static int sandbox_pmc_emul_read_io(struct udevice *dev, unsigned int addr, + ulong *valuep, enum pci_size_t size) +{ + unsigned int offset; + int barnum; + int ret; + + ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset); + if (ret) + return ret; + + if (barnum == 4) + *valuep = offset; + else if (barnum == 0) + *valuep = offset; + + return 0; +} + +static int sandbox_pmc_emul_write_io(struct udevice *dev, unsigned int addr, + ulong value, enum pci_size_t size) +{ + unsigned int offset; + int barnum; + int ret; + + ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset); + if (ret) + return ret; + + return 0; +} + +static int sandbox_pmc_emul_map_physmem(struct udevice *dev, + phys_addr_t addr, unsigned long *lenp, + void **ptrp) +{ + struct pmc_emul_priv *priv = dev_get_priv(dev); + unsigned int offset, avail; + int barnum; + int ret; + + ret = sandbox_pmc_emul_find_bar(dev, addr, &barnum, &offset); + if (ret) + return ret; + + if (barnum == 0) { + *ptrp = priv->regs + offset; + avail = barinfo[0].size - offset; + if (avail > barinfo[0].size) + *lenp = 0; + else + *lenp = min(*lenp, (ulong)avail); + + return 0; + } + + return -ENOENT; +} + +static int sandbox_pmc_probe(struct udevice *dev) +{ + struct pmc_emul_priv *priv = dev_get_priv(dev); + int i; + + for (i = 0; i < MEMMAP_SIZE; i++) + priv->regs[i] = i; + + return 0; +} + +static struct dm_pci_emul_ops sandbox_pmc_emul_emul_ops = { + .read_config = sandbox_pmc_emul_read_config, + .write_config = sandbox_pmc_emul_write_config, + .read_io = sandbox_pmc_emul_read_io, + .write_io = sandbox_pmc_emul_write_io, + .map_physmem = sandbox_pmc_emul_map_physmem, +}; + +static const struct udevice_id sandbox_pmc_emul_ids[] = { + { .compatible = "sandbox,pmc-emul" }, + { } +}; + +U_BOOT_DRIVER(sandbox_pmc_emul_emul) = { + .name = "sandbox_pmc_emul_emul", + .id = UCLASS_PCI_EMUL, + .of_match = sandbox_pmc_emul_ids, + .ops = &sandbox_pmc_emul_emul_ops, + .probe = sandbox_pmc_probe, + .priv_auto_alloc_size = sizeof(struct pmc_emul_priv), + .platdata_auto_alloc_size = sizeof(struct pmc_emul_platdata), +}; + +static struct pci_device_id sandbox_pmc_emul_supported[] = { + { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) }, + {}, +}; + +U_BOOT_PCI_DEVICE(sandbox_pmc_emul_emul, sandbox_pmc_emul_supported); diff --git a/drivers/power/power_mgr/sandbox.c b/drivers/power/power_mgr/sandbox.c new file mode 100644 index 00000000000..85683b296a0 --- /dev/null +++ b/drivers/power/power_mgr/sandbox.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sandbox PMC for testing + * + * Copyright 2019 Google LLC + */ + +#define LOG_CATEGORY UCLASS_POWER_MGR + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <power/power_mgr.h> + +#define GPIO_GPE_CFG 0x1050 + +/* Memory mapped IO registers behind PMC_BASE_ADDRESS */ +#define PRSTS 0x1000 +#define GEN_PMCON1 0x1020 +#define GEN_PMCON2 0x1024 +#define GEN_PMCON3 0x1028 + +/* Offset of TCO registers from ACPI base I/O address */ +#define TCO_REG_OFFSET 0x60 +#define TCO1_STS 0x64 +#define TCO2_STS 0x66 +#define TCO1_CNT 0x68 +#define TCO2_CNT 0x6a + +struct sandbox_pmc_priv { + ulong base; +}; + +static int sandbox_pmc_fill_power_state(struct udevice *dev) +{ + struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev); + + upriv->tco1_sts = inw(upriv->acpi_base + TCO1_STS); + upriv->tco2_sts = inw(upriv->acpi_base + TCO2_STS); + + upriv->prsts = readl(upriv->pmc_bar0 + PRSTS); + upriv->gen_pmcon1 = readl(upriv->pmc_bar0 + GEN_PMCON1); + upriv->gen_pmcon2 = readl(upriv->pmc_bar0 + GEN_PMCON2); + upriv->gen_pmcon3 = readl(upriv->pmc_bar0 + GEN_PMCON3); + + return 0; +} + +static int sandbox_prev_sleep_state(struct udevice *dev, int prev_sleep_state) +{ + return prev_sleep_state; +} + +static int sandbox_disable_tco(struct udevice *dev) +{ + struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev); + + pmc_disable_tco_base(upriv->acpi_base + TCO_REG_OFFSET); + + return 0; +} + +static int sandbox_pmc_probe(struct udevice *dev) +{ + struct power_mgr_upriv *upriv = dev_get_uclass_priv(dev); + struct udevice *bus; + ulong base; + + uclass_first_device(UCLASS_PCI, &bus); + base = dm_pci_read_bar32(dev, 0); + if (base == FDT_ADDR_T_NONE) + return log_msg_ret("No base address", -EINVAL); + upriv->pmc_bar0 = map_sysmem(base, 0x2000); + upriv->gpe_cfg = (u32 *)(upriv->pmc_bar0 + GPIO_GPE_CFG); + + return pmc_ofdata_to_uc_platdata(dev); +} + +static struct power_mgr_ops sandbox_pmc_ops = { + .init = sandbox_pmc_fill_power_state, + .prev_sleep_state = sandbox_prev_sleep_state, + .disable_tco = sandbox_disable_tco, +}; + +static const struct udevice_id sandbox_pmc_ids[] = { + { .compatible = "sandbox,pmc" }, + { } +}; + +U_BOOT_DRIVER(pmc_sandbox) = { + .name = "pmc_sandbox", + .id = UCLASS_POWER_MGR, + .of_match = sandbox_pmc_ids, + .probe = sandbox_pmc_probe, + .ops = &sandbox_pmc_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_pmc_priv), +}; diff --git a/test/dm/Makefile b/test/dm/Makefile index 55a7940053e..c1d34bfbbe7 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_PCI_ENDPOINT) += pci_ep.o obj-$(CONFIG_PCH) += pch.o obj-$(CONFIG_PHY) += phy.o obj-$(CONFIG_POWER_DOMAIN) += power-domain.o +obj-$(CONFIG_POWER_MGR) += pmc.o obj-$(CONFIG_DM_PWM) += pwm.o obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o diff --git a/test/dm/pmc.c b/test/dm/pmc.c new file mode 100644 index 00000000000..6967e82dc2e --- /dev/null +++ b/test/dm/pmc.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for power-management controller uclass (PMC) + * + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <power/power_mgr.h> +#include <dm/test.h> +#include <test/ut.h> + +/* Base test of the PMC uclass */ +static int dm_test_pmc_base(struct unit_test_state *uts) +{ + struct power_mgr_upriv *upriv; + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_POWER_MGR, &dev)); + + ut_assertok(pmc_disable_tco(dev)); + ut_assertok(pmc_init(dev)); + ut_assertok(pmc_prev_sleep_state(dev)); + + /* Check some values to see that I/O works */ + upriv = dev_get_uclass_priv(dev); + ut_asserteq(0x24, upriv->gpe0_sts[1]); + ut_asserteq(0x64, upriv->tco1_sts); + + return 0; +} +DM_TEST(dm_test_pmc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

Add a simple command to show information about the PMC.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/Kconfig | 1 + cmd/Kconfig | 8 ++++++ cmd/Makefile | 1 + cmd/pmc.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 cmd/pmc.c
diff --git a/arch/Kconfig b/arch/Kconfig index e22d62f9290..0374139fa89 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -134,6 +134,7 @@ config SANDBOX imply DM_MDIO imply DM_MDIO_MUX imply POWER_MGR + imply CMD_PMC imply POWER_MGR_SANDBOX
config SH diff --git a/cmd/Kconfig b/cmd/Kconfig index 98647f58b7a..eaad9e52578 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -225,6 +225,14 @@ config CMD_LICENSE help Print GPL license text
+config CMD_PMC + bool "pmc" + help + Provides access to the Intel Power-Management Controller (PMC) so + that its state can be examined. This does not currently support + changing the state but it is still useful for debugging and seeing + what is going on. + config CMD_REGINFO bool "reginfo" depends on PPC diff --git a/cmd/Makefile b/cmd/Makefile index ac843b4b16a..8151ba8741f 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -108,6 +108,7 @@ ifdef CONFIG_PCI obj-$(CONFIG_CMD_PCI) += pci.o endif obj-$(CONFIG_CMD_PINMUX) += pinmux.o +obj-$(CONFIG_CMD_PMC) += pmc.o obj-$(CONFIG_CMD_PXE) += pxe.o obj-$(CONFIG_CMD_WOL) += wol.o obj-$(CONFIG_CMD_QFW) += qfw.o diff --git a/cmd/pmc.c b/cmd/pmc.c new file mode 100644 index 00000000000..704e8e86534 --- /dev/null +++ b/cmd/pmc.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel PMC command + * + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <command.h> +#include <dm.h> +#include <power/power_mgr.h> + +static int get_pmc_dev(struct udevice **devp) +{ + struct udevice *dev; + int ret; + + ret = uclass_first_device_err(UCLASS_POWER_MGR, &dev); + if (ret) { + printf("Could not find device (err=%d)\n", ret); + return ret; + } + ret = pmc_init(dev); + if (ret) { + printf("Could not init device (err=%d)\n", ret); + return ret; + } + *devp = dev; + + return 0; +} + +static int do_pcm_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *dev; + int ret; + + ret = get_pmc_dev(&dev); + if (ret) + return CMD_RET_FAILURE; + + return 0; +} + +static int do_pcm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *dev; + int ret; + + ret = get_pmc_dev(&dev); + if (ret) + return CMD_RET_FAILURE; + pmc_dump_info(dev); + + return 0; +} + +static cmd_tbl_t cmd_pmc_sub[] = { + U_BOOT_CMD_MKENT(init, 0, 1, do_pcm_init, "", ""), + U_BOOT_CMD_MKENT(info, 0, 1, do_pcm_info, "", ""), +}; + +static int do_pmc(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + const cmd_tbl_t *cp; + + if (argc < 2) /* no subcommand */ + return cmd_usage(cmdtp); + + cp = find_cmd_tbl(argv[1], &cmd_pmc_sub[0], ARRAY_SIZE(cmd_pmc_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +U_BOOT_CMD( + pmc, 2, 1, do_pmc, "Power-management controller info", + "info - read state and show info about the PMC\n" + "pcm init - read state from the PMC\n" + );

The write functions do actually change the contents of memory so it is not correct to use 'const'. Remove it.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/iotrace.c | 6 +++--- include/iotrace.h | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/common/iotrace.c b/common/iotrace.c index 49bee3c92a0..5b92fabc76e 100644 --- a/common/iotrace.c +++ b/common/iotrace.c @@ -86,7 +86,7 @@ u32 iotrace_readl(const void *ptr) return v; }
-void iotrace_writel(ulong value, const void *ptr) +void iotrace_writel(ulong value, void *ptr) { add_record(IOT_32 | IOT_WRITE, ptr, value); writel(value, ptr); @@ -102,7 +102,7 @@ u16 iotrace_readw(const void *ptr) return v; }
-void iotrace_writew(ulong value, const void *ptr) +void iotrace_writew(ulong value, void *ptr) { add_record(IOT_16 | IOT_WRITE, ptr, value); writew(value, ptr); @@ -118,7 +118,7 @@ u8 iotrace_readb(const void *ptr) return v; }
-void iotrace_writeb(ulong value, const void *ptr) +void iotrace_writeb(ulong value, void *ptr) { add_record(IOT_8 | IOT_WRITE, ptr, value); writeb(value, ptr); diff --git a/include/iotrace.h b/include/iotrace.h index be1d2753e19..380da1fbc2c 100644 --- a/include/iotrace.h +++ b/include/iotrace.h @@ -49,30 +49,29 @@ struct iotrace_record { #define readl(addr) iotrace_readl((const void *)(addr))
#undef writel -#define writel(val, addr) iotrace_writel(val, (const void *)(addr)) +#define writel(val, addr) iotrace_writel(val, (void *)(addr))
#undef readw #define readw(addr) iotrace_readw((const void *)(addr))
#undef writew -#define writew(val, addr) iotrace_writew(val, (const void *)(addr)) +#define writew(val, addr) iotrace_writew(val, (void *)(addr))
#undef readb #define readb(addr) iotrace_readb((const void *)(uintptr_t)addr)
#undef writeb -#define writeb(val, addr) \ - iotrace_writeb(val, (const void *)(uintptr_t)addr) +#define writeb(val, addr) iotrace_writeb(val, (void *)(uintptr_t)addr)
#endif
/* Tracing functions which mirror their io.h counterparts */ u32 iotrace_readl(const void *ptr); -void iotrace_writel(ulong value, const void *ptr); +void iotrace_writel(ulong value, void *ptr); u16 iotrace_readw(const void *ptr); -void iotrace_writew(ulong value, const void *ptr); +void iotrace_writew(ulong value, void *ptr); u8 iotrace_readb(const void *ptr); -void iotrace_writeb(ulong value, const void *ptr); +void iotrace_writeb(ulong value, void *ptr);
/** * iotrace_reset_checksum() - Reset the iotrace checksum

On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The write functions do actually change the contents of memory so it is not correct to use 'const'. Remove it.
Signed-off-by: Simon Glass sjg@chromium.org
common/iotrace.c | 6 +++--- include/iotrace.h | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 10, 2019 at 11:20 AM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:58 PM Simon Glass sjg@chromium.org wrote:
The write functions do actually change the contents of memory so it is not correct to use 'const'. Remove it.
Signed-off-by: Simon Glass sjg@chromium.org
common/iotrace.c | 6 +++--- include/iotrace.h | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!

The Primary-to-Sideband bus (P2SB) is used to access various peripherals through memory-mapped I/O in a large chunk of PCI space. The space is segmented into different channels and peripherals are accessed by device-specific means within those channels. Devices should be added in the device tree as subnodes of the p2sb.
This adds a uclass and enables it for sandbox.
Signed-off-by: Simon Glass sjg@chromium.org ---
configs/sandbox_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + drivers/misc/Kconfig | 33 ++++++ drivers/misc/Makefile | 1 + drivers/misc/p2sb-uclass.c | 199 ++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/p2sb.h | 127 ++++++++++++++++++++++ 7 files changed, 363 insertions(+) create mode 100644 drivers/misc/p2sb-uclass.c create mode 100644 include/p2sb.h
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index f77b9e8a7d1..6f4d8449290 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -149,6 +149,7 @@ CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_DM_PCI_COMPAT=y CONFIG_PCI_SANDBOX=y +CONFIG_P2SB=y CONFIG_PHY=y CONFIG_PHY_SANDBOX=y CONFIG_PINCTRL=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 409b8a38d5e..c49e05ec319 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -135,6 +135,7 @@ CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_DM_PCI_COMPAT=y CONFIG_PCI_SANDBOX=y +CONFIG_P2SB=y CONFIG_PHY=y CONFIG_PHY_SANDBOX=y CONFIG_PINCTRL=y diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 8037b6ee2d7..74055a35516 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -217,6 +217,39 @@ config NUVOTON_NCT6102D disable the legacy UART, the watchdog or other devices in the Nuvoton Super IO chips on X86 platforms.
+config P2SB + bool "Intel Primary-to-Sideband Bus" + depends on X86 || SANDBOX + help + This enables support for the Intel Primary-to-Sideband bus, + abbreviated to P2SB. The P2SB is used to access various peripherals + such as eSPI, GPIO, through memory-mapped I/O in a large chunk of PCI + space. The space is segmented into different channels and peripherals + are accessed by device-specific means within those channels. Devices + should be added in the device tree as subnodes of the P2SB. A + Peripheral Channel Register? (PCR) API is provided to access those + devices - see pcr_readl(), etc. + +config SPL_P2SB + bool "Intel Primary-to-Sideband Bus in SPL" + depends on SPL && (X86 || SANDBOX) + help + The Primary-to-Sideband bus is used to access various peripherals + through memory-mapped I/O in a large chunk of PCI space. The space is + segmented into different channels and peripherals are accessed by + device-specific means within those channels. Devices should be added + in the device tree as subnodes of the p2sb. + +config TPL_P2SB + bool "Intel Primary-to-Sideband Bus in TPL" + depends on TPL && (X86 || SANDBOX) + help + The Primary-to-Sideband bus is used to access various peripherals + through memory-mapped I/O in a large chunk of PCI space. The space is + segmented into different channels and peripherals are accessed by + device-specific means within those channels. Devices should be added + in the device tree as subnodes of the p2sb. + config PWRSEQ bool "Enable power-sequencing drivers" depends on DM diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 0001d105bae..840d9fa5e39 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o +obj-$(CONFIG_P2SB) += p2sb-uclass.o obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_QFW) += qfw.o diff --git a/drivers/misc/p2sb-uclass.c b/drivers/misc/p2sb-uclass.c new file mode 100644 index 00000000000..7915eb5c3ed --- /dev/null +++ b/drivers/misc/p2sb-uclass.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Uclass for Primary-to-sideband bus, used to access various peripherals + * + * Copyright 2019 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <dm.h> +#include <mapmem.h> +#include <p2sb.h> +#include <asm/io.h> +#include <dm/uclass-internal.h> + +#define PCR_COMMON_IOSF_1_0 1 + +static void *_pcr_reg_address(struct udevice *dev, uint offset) +{ + struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev); + struct udevice *p2sb = dev_get_parent(dev); + struct p2sb_uc_priv *upriv = dev_get_uclass_priv(p2sb); + uintptr_t reg_addr; + + /* Create an address based off of port id and offset */ + reg_addr = upriv->mmio_base; + reg_addr += pplat->pid << PCR_PORTID_SHIFT; + reg_addr += offset; + + return map_sysmem(reg_addr, 4); +} + +/* + * The mapping of addresses via the SBREG_BAR assumes the IOSF-SB + * agents are using 32-bit aligned accesses for their configuration + * registers. For IOSF versions greater than 1_0, IOSF-SB + * agents can use any access (8/16/32 bit aligned) for their + * configuration registers + */ +static inline void check_pcr_offset_align(uint offset, uint size) +{ + const size_t align = PCR_COMMON_IOSF_1_0 ? sizeof(uint32_t) : size; + + assert(IS_ALIGNED(offset, align)); +} + +uint pcr_read32(struct udevice *dev, uint offset) +{ + void *ptr; + uint val; + + /* Ensure the PCR offset is correctly aligned */ + assert(IS_ALIGNED(offset, sizeof(uint32_t))); + + ptr = _pcr_reg_address(dev, offset); + val = readl(ptr); + unmap_sysmem(ptr); + + return val; +} + +uint pcr_read16(struct udevice *dev, uint offset) +{ + /* Ensure the PCR offset is correctly aligned */ + check_pcr_offset_align(offset, sizeof(uint16_t)); + + return readw(_pcr_reg_address(dev, offset)); +} + +uint pcr_read8(struct udevice *dev, uint offset) +{ + /* Ensure the PCR offset is correctly aligned */ + check_pcr_offset_align(offset, sizeof(uint8_t)); + + return readb(_pcr_reg_address(dev, offset)); +} + +/* + * After every write one needs to perform a read an innocuous register to + * ensure the writes are completed for certain ports. This is done for + * all ports so that the callers don't need the per-port knowledge for + * each transaction. + */ +static void write_completion(struct udevice *dev, uint offset) +{ + readl(_pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t)))); +} + +void pcr_write32(struct udevice *dev, uint offset, uint indata) +{ + /* Ensure the PCR offset is correctly aligned */ + assert(IS_ALIGNED(offset, sizeof(indata))); + + writel(indata, _pcr_reg_address(dev, offset)); + /* Ensure the writes complete */ + write_completion(dev, offset); +} + +void pcr_write16(struct udevice *dev, uint offset, uint indata) +{ + /* Ensure the PCR offset is correctly aligned */ + check_pcr_offset_align(offset, sizeof(uint16_t)); + + writew(indata, _pcr_reg_address(dev, offset)); + /* Ensure the writes complete */ + write_completion(dev, offset); +} + +void pcr_write8(struct udevice *dev, uint offset, uint indata) +{ + /* Ensure the PCR offset is correctly aligned */ + check_pcr_offset_align(offset, sizeof(uint8_t)); + + writeb(indata, _pcr_reg_address(dev, offset)); + /* Ensure the writes complete */ + write_completion(dev, offset); +} + +void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set) +{ + uint data32; + + data32 = pcr_read32(dev, offset); + data32 &= ~clr; + data32 |= set; + pcr_write32(dev, offset, data32); +} + +void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set) +{ + uint data16; + + data16 = pcr_read16(dev, offset); + data16 &= ~clr; + data16 |= set; + pcr_write16(dev, offset, data16); +} + +void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set) +{ + uint data8; + + data8 = pcr_read8(dev, offset); + data8 &= ~clr; + data8 |= set; + pcr_write8(dev, offset, data8); +} + +int p2sb_set_port_id(struct udevice *dev, int portid) +{ + struct udevice *ps2b; + struct p2sb_child_platdata *pplat; + + if (!CONFIG_IS_ENABLED(OF_PLATDATA)) + return -ENOSYS; + + uclass_find_first_device(UCLASS_P2SB, &ps2b); + if (!ps2b) + return -EDEADLK; + dev->parent = ps2b; + + /* + * We must allocate this, since when the device was bound it did not + * have a parent. + * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc + */ + dev->parent_platdata = malloc(sizeof(*pplat)); + if (!dev->parent_platdata) + return -ENOMEM; + pplat = dev_get_parent_platdata(dev); + pplat->pid = portid; + + return 0; +} + +static int p2sb_child_post_bind(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA) + struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev); + int ret; + u32 pid; + + ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid); + if (ret) + return ret; + pplat->pid = pid; +#endif + + return 0; +} + +UCLASS_DRIVER(p2sb) = { + .id = UCLASS_P2SB, + .name = "p2sb", + .per_device_auto_alloc_size = sizeof(struct p2sb_uc_priv), + .child_post_bind = p2sb_child_post_bind, + .per_child_platdata_auto_alloc_size = + sizeof(struct p2sb_child_platdata), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 907fe257ad1..496570ff47d 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -68,6 +68,7 @@ enum uclass_id { UCLASS_NOP, /* No-op devices */ UCLASS_NORTHBRIDGE, /* Intel Northbridge / SDRAM controller */ UCLASS_NVME, /* NVM Express device */ + UCLASS_P2SB, /* (x86) Primary-to-Sideband Bus */ UCLASS_PANEL, /* Display panel, such as an LCD */ UCLASS_PANEL_BACKLIGHT, /* Backlight controller for panel */ UCLASS_PCH, /* x86 platform controller hub */ diff --git a/include/p2sb.h b/include/p2sb.h new file mode 100644 index 00000000000..370f127058c --- /dev/null +++ b/include/p2sb.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#ifndef __p2sb_h +#define __p2sb_h + +/* Port Id lives in bits 23:16 and register offset lives in 15:0 of address */ +#define PCR_PORTID_SHIFT 16 + +/** + * struct p2sb_child_platdata - Information about each child of a p2sb device + * + * @pid: Port ID for this child + */ +struct p2sb_child_platdata { + uint pid; +}; + +/** + * struct p2sb_uc_priv - information for the uclass about each device + * + * This must be set up by the driver when it is probed + * + * @mmio_base: Base address of P2SB region + */ +struct p2sb_uc_priv { + uint mmio_base; +}; + +/** + * struct p2sb_ops - Operations for the P2SB (none at present) + */ +struct p2sb_ops { +}; + +#define p2sb_get_ops(dev) ((struct p2sb_ops *)(dev)->driver->ops) + +/** + * pcr_read32/16/8() - Read from a PCR device + * + * Reads data from a PCR device within the P2SB + * + * @dev: Device to read from + * @offset: Offset within device to read + * @return value read + */ +uint pcr_read32(struct udevice *dev, uint offset); +uint pcr_read16(struct udevice *dev, uint offset); +uint pcr_read8(struct udevice *dev, uint offset); + +/** + * pcr_read32/16/8() - Write to a PCR device + * + * Writes data to a PCR device within the P2SB + * + * @dev: Device to write to + * @offset: Offset within device to write + * @data: Data to write + */ +void pcr_write32(struct udevice *dev, uint offset, uint data); +void pcr_write16(struct udevice *dev, uint offset, uint data); +void pcr_write8(struct udevice *dev, uint offset, uint data); + +/** + * pcr_clrsetbits32/16/8() - Update a PCR device + * + * Updates dat in a PCR device within the P2SB + * + * This reads from the device, clears and set bits, then writes back. + * + * new_data = (old_data & ~clr) | set + * + * @dev: Device to update + * @offset: Offset within device to update + * @clr: Bits to clear after reading + * @set: Bits to set before writing + */ +void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set); +void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set); +void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set); + +static inline void pcr_setbits32(struct udevice *dev, uint offset, uint set) +{ + return pcr_clrsetbits32(dev, offset, 0, set); +} + +static inline void pcr_setbits16(struct udevice *dev, uint offset, uint set) +{ + return pcr_clrsetbits16(dev, offset, 0, set); +} + +static inline void pcr_setbits8(struct udevice *dev, uint offset, uint set) +{ + return pcr_clrsetbits8(dev, offset, 0, set); +} + +static inline void pcr_clrbits32(struct udevice *dev, uint offset, uint clr) +{ + return pcr_clrsetbits32(dev, offset, clr, 0); +} + +static inline void pcr_clrbits16(struct udevice *dev, uint offset, uint clr) +{ + return pcr_clrsetbits16(dev, offset, clr, 0); +} + +static inline void pcr_clrbits8(struct udevice *dev, uint offset, uint clr) +{ + return pcr_clrsetbits8(dev, offset, clr, 0); +} + +/** + * p2sb_set_port_id() - Set the port ID for a p2sb child device + * + * This must be called in a device's bind() method when OF_PLATDATA is used + * since the uclass cannot access the device's of-platdata. + * + * @dev: Child device (whose parent is UCLASS_P2SB) + * @portid: Port ID of child device + * @return 0 if OK, -ENODEV is the p2sb device could not be found + */ +int p2sb_set_port_id(struct udevice *dev, int portid); + +#endif

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
The Primary-to-Sideband bus (P2SB) is used to access various peripherals through memory-mapped I/O in a large chunk of PCI space. The space is segmented into different channels and peripherals are accessed by device-specific means within those channels. Devices should be added in the device tree as subnodes of the p2sb.
Again, I see no value of bringing P2SB to the uclass driver level, given as of today it is only seen in ApolloLake. Similar mechanism was seen in old x86 SoCs, and at the old time, it was called "Message Port", that existed in old Atom SoCs.
This adds a uclass and enables it for sandbox.
Signed-off-by: Simon Glass sjg@chromium.org
configs/sandbox_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + drivers/misc/Kconfig | 33 ++++++ drivers/misc/Makefile | 1 + drivers/misc/p2sb-uclass.c | 199 ++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/p2sb.h | 127 ++++++++++++++++++++++ 7 files changed, 363 insertions(+) create mode 100644 drivers/misc/p2sb-uclass.c create mode 100644 include/p2sb.h
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index f77b9e8a7d1..6f4d8449290 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -149,6 +149,7 @@ CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_DM_PCI_COMPAT=y CONFIG_PCI_SANDBOX=y +CONFIG_P2SB=y CONFIG_PHY=y CONFIG_PHY_SANDBOX=y CONFIG_PINCTRL=y diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 409b8a38d5e..c49e05ec319 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -135,6 +135,7 @@ CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_DM_PCI_COMPAT=y CONFIG_PCI_SANDBOX=y +CONFIG_P2SB=y CONFIG_PHY=y CONFIG_PHY_SANDBOX=y CONFIG_PINCTRL=y diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 8037b6ee2d7..74055a35516 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -217,6 +217,39 @@ config NUVOTON_NCT6102D disable the legacy UART, the watchdog or other devices in the Nuvoton Super IO chips on X86 platforms.
+config P2SB
bool "Intel Primary-to-Sideband Bus"
depends on X86 || SANDBOX
help
This enables support for the Intel Primary-to-Sideband bus,
abbreviated to P2SB. The P2SB is used to access various peripherals
such as eSPI, GPIO, through memory-mapped I/O in a large chunk of PCI
space. The space is segmented into different channels and peripherals
are accessed by device-specific means within those channels. Devices
should be added in the device tree as subnodes of the P2SB. A
Peripheral Channel Register? (PCR) API is provided to access those
devices - see pcr_readl(), etc.
+config SPL_P2SB
bool "Intel Primary-to-Sideband Bus in SPL"
depends on SPL && (X86 || SANDBOX)
help
The Primary-to-Sideband bus is used to access various peripherals
through memory-mapped I/O in a large chunk of PCI space. The space is
segmented into different channels and peripherals are accessed by
device-specific means within those channels. Devices should be added
in the device tree as subnodes of the p2sb.
+config TPL_P2SB
bool "Intel Primary-to-Sideband Bus in TPL"
depends on TPL && (X86 || SANDBOX)
help
The Primary-to-Sideband bus is used to access various peripherals
through memory-mapped I/O in a large chunk of PCI space. The space is
segmented into different channels and peripherals are accessed by
device-specific means within those channels. Devices should be added
in the device tree as subnodes of the p2sb.
config PWRSEQ bool "Enable power-sequencing drivers" depends on DM diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 0001d105bae..840d9fa5e39 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o +obj-$(CONFIG_P2SB) += p2sb-uclass.o obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_QFW) += qfw.o diff --git a/drivers/misc/p2sb-uclass.c b/drivers/misc/p2sb-uclass.c new file mode 100644 index 00000000000..7915eb5c3ed --- /dev/null +++ b/drivers/misc/p2sb-uclass.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Uclass for Primary-to-sideband bus, used to access various peripherals
- Copyright 2019 Google LLC
- Written by Simon Glass sjg@chromium.org
- */
+#include <common.h> +#include <dm.h> +#include <mapmem.h> +#include <p2sb.h> +#include <asm/io.h> +#include <dm/uclass-internal.h>
+#define PCR_COMMON_IOSF_1_0 1
+static void *_pcr_reg_address(struct udevice *dev, uint offset) +{
struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
struct udevice *p2sb = dev_get_parent(dev);
struct p2sb_uc_priv *upriv = dev_get_uclass_priv(p2sb);
uintptr_t reg_addr;
/* Create an address based off of port id and offset */
reg_addr = upriv->mmio_base;
reg_addr += pplat->pid << PCR_PORTID_SHIFT;
Having PCR_PORTID_SHIFT defined in the p2sb.h is not appropriate. A different SoC may have a different value, or even choose a completely different register layout, that makes the function here useless.
reg_addr += offset;
return map_sysmem(reg_addr, 4);
+}
+/*
- The mapping of addresses via the SBREG_BAR assumes the IOSF-SB
- agents are using 32-bit aligned accesses for their configuration
- registers. For IOSF versions greater than 1_0, IOSF-SB
- agents can use any access (8/16/32 bit aligned) for their
- configuration registers
- */
+static inline void check_pcr_offset_align(uint offset, uint size) +{
const size_t align = PCR_COMMON_IOSF_1_0 ? sizeof(uint32_t) : size;
assert(IS_ALIGNED(offset, align));
+}
+uint pcr_read32(struct udevice *dev, uint offset) +{
void *ptr;
uint val;
/* Ensure the PCR offset is correctly aligned */
assert(IS_ALIGNED(offset, sizeof(uint32_t)));
ptr = _pcr_reg_address(dev, offset);
val = readl(ptr);
unmap_sysmem(ptr);
return val;
+}
+uint pcr_read16(struct udevice *dev, uint offset) +{
/* Ensure the PCR offset is correctly aligned */
check_pcr_offset_align(offset, sizeof(uint16_t));
return readw(_pcr_reg_address(dev, offset));
+}
+uint pcr_read8(struct udevice *dev, uint offset) +{
/* Ensure the PCR offset is correctly aligned */
check_pcr_offset_align(offset, sizeof(uint8_t));
return readb(_pcr_reg_address(dev, offset));
+}
+/*
- After every write one needs to perform a read an innocuous register to
- ensure the writes are completed for certain ports. This is done for
- all ports so that the callers don't need the per-port knowledge for
- each transaction.
- */
+static void write_completion(struct udevice *dev, uint offset) +{
readl(_pcr_reg_address(dev, ALIGN_DOWN(offset, sizeof(uint32_t))));
+}
+void pcr_write32(struct udevice *dev, uint offset, uint indata) +{
/* Ensure the PCR offset is correctly aligned */
assert(IS_ALIGNED(offset, sizeof(indata)));
writel(indata, _pcr_reg_address(dev, offset));
/* Ensure the writes complete */
write_completion(dev, offset);
+}
+void pcr_write16(struct udevice *dev, uint offset, uint indata) +{
/* Ensure the PCR offset is correctly aligned */
check_pcr_offset_align(offset, sizeof(uint16_t));
writew(indata, _pcr_reg_address(dev, offset));
/* Ensure the writes complete */
write_completion(dev, offset);
+}
+void pcr_write8(struct udevice *dev, uint offset, uint indata) +{
/* Ensure the PCR offset is correctly aligned */
check_pcr_offset_align(offset, sizeof(uint8_t));
writeb(indata, _pcr_reg_address(dev, offset));
/* Ensure the writes complete */
write_completion(dev, offset);
+}
+void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set) +{
uint data32;
data32 = pcr_read32(dev, offset);
data32 &= ~clr;
data32 |= set;
pcr_write32(dev, offset, data32);
+}
+void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set) +{
uint data16;
data16 = pcr_read16(dev, offset);
data16 &= ~clr;
data16 |= set;
pcr_write16(dev, offset, data16);
+}
+void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set) +{
uint data8;
data8 = pcr_read8(dev, offset);
data8 &= ~clr;
data8 |= set;
pcr_write8(dev, offset, data8);
+}
+int p2sb_set_port_id(struct udevice *dev, int portid) +{
struct udevice *ps2b;
struct p2sb_child_platdata *pplat;
if (!CONFIG_IS_ENABLED(OF_PLATDATA))
return -ENOSYS;
uclass_find_first_device(UCLASS_P2SB, &ps2b);
if (!ps2b)
return -EDEADLK;
dev->parent = ps2b;
/*
* We must allocate this, since when the device was bound it did not
* have a parent.
* TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
*/
dev->parent_platdata = malloc(sizeof(*pplat));
if (!dev->parent_platdata)
return -ENOMEM;
pplat = dev_get_parent_platdata(dev);
pplat->pid = portid;
return 0;
+}
+static int p2sb_child_post_bind(struct udevice *dev) +{ +#if !CONFIG_IS_ENABLED(OF_PLATDATA)
struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev);
int ret;
u32 pid;
ret = dev_read_u32(dev, "intel,p2sb-port-id", &pid);
if (ret)
return ret;
pplat->pid = pid;
+#endif
return 0;
+}
+UCLASS_DRIVER(p2sb) = {
.id = UCLASS_P2SB,
.name = "p2sb",
.per_device_auto_alloc_size = sizeof(struct p2sb_uc_priv),
.child_post_bind = p2sb_child_post_bind,
.per_child_platdata_auto_alloc_size =
sizeof(struct p2sb_child_platdata),
+}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 907fe257ad1..496570ff47d 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -68,6 +68,7 @@ enum uclass_id { UCLASS_NOP, /* No-op devices */ UCLASS_NORTHBRIDGE, /* Intel Northbridge / SDRAM controller */ UCLASS_NVME, /* NVM Express device */
UCLASS_P2SB, /* (x86) Primary-to-Sideband Bus */ UCLASS_PANEL, /* Display panel, such as an LCD */ UCLASS_PANEL_BACKLIGHT, /* Backlight controller for panel */ UCLASS_PCH, /* x86 platform controller hub */
diff --git a/include/p2sb.h b/include/p2sb.h new file mode 100644 index 00000000000..370f127058c --- /dev/null +++ b/include/p2sb.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright 2019 Google LLC
- Written by Simon Glass sjg@chromium.org
- */
+#ifndef __p2sb_h +#define __p2sb_h
+/* Port Id lives in bits 23:16 and register offset lives in 15:0 of address */ +#define PCR_PORTID_SHIFT 16
+/**
- struct p2sb_child_platdata - Information about each child of a p2sb device
- @pid: Port ID for this child
- */
+struct p2sb_child_platdata {
uint pid;
+};
+/**
- struct p2sb_uc_priv - information for the uclass about each device
- This must be set up by the driver when it is probed
- @mmio_base: Base address of P2SB region
- */
+struct p2sb_uc_priv {
uint mmio_base;
+};
+/**
- struct p2sb_ops - Operations for the P2SB (none at present)
- */
+struct p2sb_ops { +};
+#define p2sb_get_ops(dev) ((struct p2sb_ops *)(dev)->driver->ops)
+/**
- pcr_read32/16/8() - Read from a PCR device
- Reads data from a PCR device within the P2SB
- @dev: Device to read from
- @offset: Offset within device to read
- @return value read
- */
+uint pcr_read32(struct udevice *dev, uint offset); +uint pcr_read16(struct udevice *dev, uint offset); +uint pcr_read8(struct udevice *dev, uint offset);
+/**
- pcr_read32/16/8() - Write to a PCR device
- Writes data to a PCR device within the P2SB
- @dev: Device to write to
- @offset: Offset within device to write
- @data: Data to write
- */
+void pcr_write32(struct udevice *dev, uint offset, uint data); +void pcr_write16(struct udevice *dev, uint offset, uint data); +void pcr_write8(struct udevice *dev, uint offset, uint data);
+/**
- pcr_clrsetbits32/16/8() - Update a PCR device
- Updates dat in a PCR device within the P2SB
- This reads from the device, clears and set bits, then writes back.
- new_data = (old_data & ~clr) | set
- @dev: Device to update
- @offset: Offset within device to update
- @clr: Bits to clear after reading
- @set: Bits to set before writing
- */
+void pcr_clrsetbits32(struct udevice *dev, uint offset, uint clr, uint set); +void pcr_clrsetbits16(struct udevice *dev, uint offset, uint clr, uint set); +void pcr_clrsetbits8(struct udevice *dev, uint offset, uint clr, uint set);
+static inline void pcr_setbits32(struct udevice *dev, uint offset, uint set) +{
return pcr_clrsetbits32(dev, offset, 0, set);
+}
+static inline void pcr_setbits16(struct udevice *dev, uint offset, uint set) +{
return pcr_clrsetbits16(dev, offset, 0, set);
+}
+static inline void pcr_setbits8(struct udevice *dev, uint offset, uint set) +{
return pcr_clrsetbits8(dev, offset, 0, set);
+}
+static inline void pcr_clrbits32(struct udevice *dev, uint offset, uint clr) +{
return pcr_clrsetbits32(dev, offset, clr, 0);
+}
+static inline void pcr_clrbits16(struct udevice *dev, uint offset, uint clr) +{
return pcr_clrsetbits16(dev, offset, clr, 0);
+}
+static inline void pcr_clrbits8(struct udevice *dev, uint offset, uint clr) +{
return pcr_clrsetbits8(dev, offset, clr, 0);
+}
+/**
- p2sb_set_port_id() - Set the port ID for a p2sb child device
- This must be called in a device's bind() method when OF_PLATDATA is used
- since the uclass cannot access the device's of-platdata.
- @dev: Child device (whose parent is UCLASS_P2SB)
- @portid: Port ID of child device
- @return 0 if OK, -ENODEV is the p2sb device could not be found
- */
+int p2sb_set_port_id(struct udevice *dev, int portid);
+#endif
Regards, Bin

Hi Bin,
On Wed, 9 Oct 2019 at 22:57, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
The Primary-to-Sideband bus (P2SB) is used to access various peripherals through memory-mapped I/O in a large chunk of PCI space. The space is segmented into different channels and peripherals are accessed by device-specific means within those channels. Devices should be added in the device tree as subnodes of the p2sb.
Again, I see no value of bringing P2SB to the uclass driver level, given as of today it is only seen in ApolloLake. Similar mechanism was seen in old x86 SoCs, and at the old time, it was called "Message Port", that existed in old Atom SoCs.
OK, I'll make it a SYSCON I suppose.
Regards, Simon

Hi Bin,
On Fri, 11 Oct 2019 at 21:37, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Wed, 9 Oct 2019 at 22:57, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
The Primary-to-Sideband bus (P2SB) is used to access various peripherals through memory-mapped I/O in a large chunk of PCI space. The space is segmented into different channels and peripherals are accessed by device-specific means within those channels. Devices should be added in the device tree as subnodes of the p2sb.
Again, I see no value of bringing P2SB to the uclass driver level, given as of today it is only seen in ApolloLake. Similar mechanism was seen in old x86 SoCs, and at the old time, it was called "Message Port", that existed in old Atom SoCs.
OK, I'll make it a SYSCON I suppose.
I dug into this a bit and I think it is better as a separate uclass.
The reason is that it has child devices which access their resources through the uclass. Currently we have GPIO and ITSS that do this. But from the datasheet the RTC is there alsol. The p2sb has child platdata which supports mmio access. Take a look at p2sb-uclass.c for this.
If it is a syscon: 1. We can't really have child devices with properties known to the uclass - syscon is for simple devices 2. The devices themselves would have to set the port ID, when really this is a shared/uclass thing 3. We end up with an odd syscon device in the PCI bus in the device tree, with children and no indication of why they are there
So I think a uclass is the right thing. I don't think it matters that we end up with a few more uclasses than we would like. There is no particular limit unless we want to have a tiny driver model with a byte for the uclass ID.
Regards, Simon

Add a sandbox driver and PCI-device emulator for p2sb. Also add a test which uses a simple 'adder' driver to test the p2sb functionality.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/state.c | 1 + arch/sandbox/dts/test.dts | 13 ++ arch/sandbox/include/asm/test.h | 10 ++ drivers/misc/Makefile | 2 + drivers/misc/p2sb_emul.c | 272 ++++++++++++++++++++++++++++++++ drivers/misc/p2sb_sandbox.c | 44 ++++++ drivers/misc/sandbox_adder.c | 60 +++++++ test/dm/Makefile | 1 + test/dm/p2sb.c | 28 ++++ 9 files changed, 431 insertions(+) create mode 100644 drivers/misc/p2sb_emul.c create mode 100644 drivers/misc/p2sb_sandbox.c create mode 100644 drivers/misc/sandbox_adder.c create mode 100644 test/dm/p2sb.c
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c index dee5fde4f73..cd46e000f5e 100644 --- a/arch/sandbox/cpu/state.c +++ b/arch/sandbox/cpu/state.c @@ -356,6 +356,7 @@ void state_reset_for_test(struct sandbox_state *state) /* No reset yet, so mark it as such. Always allow power reset */ state->last_sysreset = SYSRESET_COUNT; state->sysreset_allowed[SYSRESET_POWER_OFF] = true; + state->allow_memio = false;
memset(&state->wdt, '\0', sizeof(state->wdt)); memset(state->spi, '\0', sizeof(state->spi)); diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 9b72c2f279c..cd4409b7aea 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -461,6 +461,16 @@ 0x0100f810 0 0 0 0>; sandbox,emul = <&swap_case_emul1>; }; + p2sb-pci@2,0 { + compatible = "sandbox,p2sb"; + reg = <0x02001010 0 0 0 0>; + sandbox,emul = <&p2sb_emul>; + + adder { + intel,p2sb-port-id = <3>; + compatible = "sandbox,adder"; + }; + }; pci@1e,0 { compatible = "sandbox,pmc"; reg = <0xf000 0 0 0 0>; @@ -489,6 +499,9 @@ compatible = "sandbox,swap-case"; use-ea; }; + p2sb_emul: emul@2,0 { + compatible = "sandbox,p2sb-emul"; + }; pmc_emul1e: emul@1e,0 { compatible = "sandbox,pmc-emul"; }; diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h index 7f9e7fc26f5..77fff529e19 100644 --- a/arch/sandbox/include/asm/test.h +++ b/arch/sandbox/include/asm/test.h @@ -14,6 +14,7 @@ #define SANDBOX_PCI_VENDOR_ID 0x1234 #define SANDBOX_PCI_SWAP_CASE_EMUL_ID 0x5678 #define SANDBOX_PCI_PMC_EMUL_ID 0x5677 +#define SANDBOX_PCI_P2SB_EMUL_ID 0x5676 #define SANDBOX_PCI_CLASS_CODE PCI_CLASS_CODE_COMM #define SANDBOX_PCI_CLASS_SUB_CODE PCI_CLASS_SUB_CODE_COMM_SERIAL
@@ -214,4 +215,13 @@ int sandbox_get_pci_ep_irq_count(struct udevice *dev); */ uint sandbox_pci_read_bar(u32 barval, int type, uint size);
+/** + * sandbox_set_enable_memio() - Enable memory-mapped I/O read/write + * + * Normally readl(), writel() and the like are nops on sandbox. If this function + * is called with true, those function do real memory accesses. This is useful + * for certain tests. + */ +void sandbox_set_enable_memio(bool enable); + #endif diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 840d9fa5e39..90ef92806b9 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_$(SPL_TPL_)CROS_EC_SANDBOX) += cros_ec_sandbox.o obj-$(CONFIG_$(SPL_TPL_)CROS_EC_LPC) += cros_ec_lpc.o
ifndef CONFIG_SPL_BUILD +obj-$(CONFIG_SANDBOX) += sandbox_adder.o obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o obj-$(CONFIG_SANDBOX) += swap_case.o @@ -50,6 +51,7 @@ obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o obj-$(CONFIG_NS87308) += ns87308.o obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o obj-$(CONFIG_P2SB) += p2sb-uclass.o +obj-$(CONFIG_SANDBOX) += p2sb_sandbox.o p2sb_emul.o obj-$(CONFIG_PCA9551_LED) += pca9551_led.o obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_QFW) += qfw.o diff --git a/drivers/misc/p2sb_emul.c b/drivers/misc/p2sb_emul.c new file mode 100644 index 00000000000..c51db143495 --- /dev/null +++ b/drivers/misc/p2sb_emul.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PCI emulation device for an x86 Primary-to-Sideband bus + * + * Copyright 2019 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#define LOG_CATEGORY UCLASS_MISC +#define LOG_DEBUG + +#include <common.h> +#include <axi.h> +#include <dm.h> +#include <pci.h> +#include <asm/test.h> +#include <p2sb.h> + +/** + * struct p2sb_emul_platdata - platform data for this device + * + * @command: Current PCI command value + * @bar: Current base address values + */ +struct p2sb_emul_platdata { + u16 command; + u32 bar[6]; +}; + +enum { + /* This emulator supports 16 different devices */ + MEMMAP_SIZE = 16 << PCR_PORTID_SHIFT, +}; + +static struct pci_bar { + int type; + u32 size; +} barinfo[] = { + { PCI_BASE_ADDRESS_MEM_TYPE_32, MEMMAP_SIZE }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, +}; + +struct p2sb_emul_priv { + u8 regs[16]; +}; + +static int sandbox_p2sb_emul_read_config(struct udevice *emul, uint offset, + ulong *valuep, enum pci_size_t size) +{ + struct p2sb_emul_platdata *plat = dev_get_platdata(emul); + + switch (offset) { + case PCI_COMMAND: + *valuep = plat->command; + break; + case PCI_HEADER_TYPE: + *valuep = PCI_HEADER_TYPE_NORMAL; + break; + case PCI_VENDOR_ID: + *valuep = SANDBOX_PCI_VENDOR_ID; + break; + case PCI_DEVICE_ID: + *valuep = SANDBOX_PCI_P2SB_EMUL_ID; + break; + case PCI_CLASS_DEVICE: + if (size == PCI_SIZE_8) { + *valuep = SANDBOX_PCI_CLASS_SUB_CODE; + } else { + *valuep = (SANDBOX_PCI_CLASS_CODE << 8) | + SANDBOX_PCI_CLASS_SUB_CODE; + } + break; + case PCI_CLASS_CODE: + *valuep = SANDBOX_PCI_CLASS_CODE; + break; + case PCI_BASE_ADDRESS_0: + case PCI_BASE_ADDRESS_1: + case PCI_BASE_ADDRESS_2: + case PCI_BASE_ADDRESS_3: + case PCI_BASE_ADDRESS_4: + case PCI_BASE_ADDRESS_5: { + int barnum; + u32 *bar; + + barnum = pci_offset_to_barnum(offset); + bar = &plat->bar[barnum]; + + *valuep = sandbox_pci_read_bar(*bar, barinfo[barnum].type, + barinfo[barnum].size); + break; + } + case PCI_CAPABILITY_LIST: + *valuep = PCI_CAP_ID_PM_OFFSET; + break; + } + + return 0; +} + +static int sandbox_p2sb_emul_write_config(struct udevice *emul, uint offset, + ulong value, enum pci_size_t size) +{ + struct p2sb_emul_platdata *plat = dev_get_platdata(emul); + + switch (offset) { + case PCI_COMMAND: + plat->command = value; + break; + case PCI_BASE_ADDRESS_0: + case PCI_BASE_ADDRESS_1: { + int barnum; + u32 *bar; + + barnum = pci_offset_to_barnum(offset); + bar = &plat->bar[barnum]; + + log_debug("w bar %d=%lx\n", barnum, value); + *bar = value; + /* space indicator (bit#0) is read-only */ + *bar |= barinfo[barnum].type; + break; + } + } + + return 0; +} + +static int sandbox_p2sb_emul_find_bar(struct udevice *emul, unsigned int addr, + int *barnump, unsigned int *offsetp) +{ + struct p2sb_emul_platdata *plat = dev_get_platdata(emul); + int barnum; + + for (barnum = 0; barnum < ARRAY_SIZE(barinfo); barnum++) { + unsigned int size = barinfo[barnum].size; + u32 base = plat->bar[barnum] & ~PCI_BASE_ADDRESS_SPACE; + + if (addr >= base && addr < base + size) { + *barnump = barnum; + *offsetp = addr - base; + return 0; + } + } + *barnump = -1; + + return -ENOENT; +} + +static int sandbox_p2sb_emul_read_io(struct udevice *dev, unsigned int addr, + ulong *valuep, enum pci_size_t size) +{ + unsigned int offset; + int barnum; + int ret; + + ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset); + if (ret) + return ret; + + if (barnum == 4) + *valuep = offset; + else if (barnum == 0) + *valuep = offset; + + return 0; +} + +static int sandbox_p2sb_emul_write_io(struct udevice *dev, unsigned int addr, + ulong value, enum pci_size_t size) +{ + unsigned int offset; + int barnum; + int ret; + + ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset); + if (ret) + return ret; + + return 0; +} + +static int find_p2sb_channel(struct udevice *emul, uint offset, + struct udevice **devp) +{ + uint pid = offset >> PCR_PORTID_SHIFT; + struct udevice *p2sb, *dev; + int ret; + + ret = sandbox_pci_get_client(emul, &p2sb); + if (ret) + return log_msg_ret("No client", ret); + + device_foreach_child(dev, p2sb) { + struct p2sb_child_platdata *pplat = + dev_get_parent_platdata(dev); + + log_debug(" - child %s, pid %d, want %d\n", dev->name, + pplat->pid, pid); + if (pid == pplat->pid) { + *devp = dev; + return 0; + } + } + + return -ENOENT; +} + +static int sandbox_p2sb_emul_map_physmem(struct udevice *dev, + phys_addr_t addr, unsigned long *lenp, + void **ptrp) +{ + struct p2sb_emul_priv *priv = dev_get_priv(dev); + struct udevice *child; + unsigned int offset; + int barnum; + int ret; + + log_debug("map %x: ", addr); + ret = sandbox_p2sb_emul_find_bar(dev, addr, &barnum, &offset); + if (ret) + return log_msg_ret("Cannot find bar", ret); + log_debug("bar %d, offset %x\n", barnum, offset); + + if (barnum != 0) + return log_msg_ret("Unknown BAR", -EINVAL); + + ret = find_p2sb_channel(dev, offset, &child); + if (ret) + return log_msg_ret("Cannot find channel", ret); + + offset &= ((1 << PCR_PORTID_SHIFT) - 1); + ret = axi_read(child, offset, priv->regs, AXI_SIZE_32); + if (ret) + return log_msg_ret("Child read failed", ret); + *ptrp = priv->regs + (offset & 3); + *lenp = 4; + + return 0; +} + +static struct dm_pci_emul_ops sandbox_p2sb_emul_emul_ops = { + .read_config = sandbox_p2sb_emul_read_config, + .write_config = sandbox_p2sb_emul_write_config, + .read_io = sandbox_p2sb_emul_read_io, + .write_io = sandbox_p2sb_emul_write_io, + .map_physmem = sandbox_p2sb_emul_map_physmem, +}; + +static const struct udevice_id sandbox_p2sb_emul_ids[] = { + { .compatible = "sandbox,p2sb-emul" }, + { } +}; + +U_BOOT_DRIVER(sandbox_p2sb_emul_emul) = { + .name = "sandbox_p2sb_emul_emul", + .id = UCLASS_PCI_EMUL, + .of_match = sandbox_p2sb_emul_ids, + .ops = &sandbox_p2sb_emul_emul_ops, + .priv_auto_alloc_size = sizeof(struct p2sb_emul_priv), + .platdata_auto_alloc_size = sizeof(struct p2sb_emul_platdata), +}; + +static struct pci_device_id sandbox_p2sb_emul_supported[] = { + { PCI_VDEVICE(SANDBOX, SANDBOX_PCI_PMC_EMUL_ID) }, + {}, +}; + +U_BOOT_PCI_DEVICE(sandbox_p2sb_emul_emul, sandbox_p2sb_emul_supported); diff --git a/drivers/misc/p2sb_sandbox.c b/drivers/misc/p2sb_sandbox.c new file mode 100644 index 00000000000..2337df9951d --- /dev/null +++ b/drivers/misc/p2sb_sandbox.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sandbox P2SB for testing + * + * Copyright 2019 Google LLC + */ + +#define LOG_CATEGORY UCLASS_P2SB + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <p2sb.h> + +struct sandbox_p2sb_priv { + ulong base; +}; + +static int sandbox_p2sb_probe(struct udevice *dev) +{ + struct p2sb_uc_priv *upriv = dev_get_uclass_priv(dev); + + upriv->mmio_base = dm_pci_read_bar32(dev, 0); + printf("mmio base %x\n", upriv->mmio_base); + + return 0; +} + +static struct p2sb_ops sandbox_p2sb_ops = { +}; + +static const struct udevice_id sandbox_p2sb_ids[] = { + { .compatible = "sandbox,p2sb" }, + { } +}; + +U_BOOT_DRIVER(p2sb_sandbox) = { + .name = "pmic_pm8916", + .id = UCLASS_P2SB, + .of_match = sandbox_p2sb_ids, + .probe = sandbox_p2sb_probe, + .ops = &sandbox_p2sb_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_p2sb_priv), +}; diff --git a/drivers/misc/sandbox_adder.c b/drivers/misc/sandbox_adder.c new file mode 100644 index 00000000000..df262e62555 --- /dev/null +++ b/drivers/misc/sandbox_adder.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sandbox adder for p2sb testing + * + * Copyright 2019 Google LLC + */ + +#define LOG_CATEGORY UCLASS_MISC + +#include <common.h> +#include <axi.h> +#include <dm.h> +#include <misc.h> +#include <p2sb.h> +#include <asm/io.h> + +struct sandbox_adder_priv { + ulong base; +}; + +int sandbox_adder_read(struct udevice *dev, ulong address, void *data, + enum axi_size_t size) +{ + struct p2sb_child_platdata *pplat = dev_get_parent_platdata(dev); + u32 *val = data; + + *val = pplat->pid << 24 | address; + + return 0; +} + +int sandbox_adder_write(struct udevice *dev, ulong address, void *data, + enum axi_size_t size) +{ + return 0; +} + +static int sandbox_adder_probe(struct udevice *dev) +{ + return 0; +} + +static struct axi_ops sandbox_adder_ops = { + .read = sandbox_adder_read, + .write = sandbox_adder_write, +}; + +static const struct udevice_id sandbox_adder_ids[] = { + { .compatible = "sandbox,adder" }, + { } +}; + +U_BOOT_DRIVER(adder_sandbox) = { + .name = "sandbox_adder", + .id = UCLASS_AXI, + .of_match = sandbox_adder_ids, + .probe = sandbox_adder_probe, + .ops = &sandbox_adder_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_adder_priv), +}; diff --git a/test/dm/Makefile b/test/dm/Makefile index c1d34bfbbe7..52a2392a8e9 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -31,6 +31,7 @@ obj-y += ofnode.o obj-$(CONFIG_OSD) += osd.o obj-$(CONFIG_DM_VIDEO) += panel.o obj-$(CONFIG_DM_PCI) += pci.o +obj-$(CONFIG_P2SB) += p2sb.o obj-$(CONFIG_PCI_ENDPOINT) += pci_ep.o obj-$(CONFIG_PCH) += pch.o obj-$(CONFIG_PHY) += phy.o diff --git a/test/dm/p2sb.c b/test/dm/p2sb.c new file mode 100644 index 00000000000..ccb75cf3753 --- /dev/null +++ b/test/dm/p2sb.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for Primary-to-Sideband bus (P2SB) + * + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <p2sb.h> +#include <asm/test.h> +#include <dm/test.h> +#include <test/ut.h> + +/* Base test of the PMC uclass */ +static int dm_test_p2sb_base(struct unit_test_state *uts) +{ + struct udevice *dev; + + sandbox_set_enable_memio(true); + ut_assertok(uclass_get_device_by_name(UCLASS_AXI, "adder", &dev)); + ut_asserteq(0x03000004, pcr_read32(dev, 4)); + ut_asserteq(0x300, pcr_read16(dev, 6)); + ut_asserteq(4, pcr_read8(dev, 4)); + + return 0; +} +DM_TEST(dm_test_p2sb_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

This models some sort of interrupt thingy but there are so many abreviations that I cannot find out what it stands for. It is something to do with interrupts.
It supports two operations.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/misc/Kconfig | 9 ++++++ drivers/misc/Makefile | 1 + drivers/misc/itss-uclass.c | 34 +++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/itss.h | 56 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 drivers/misc/itss-uclass.c create mode 100644 include/itss.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 74055a35516..62c9e1089db 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -194,6 +194,15 @@ config FSL_SEC_MON Security Monitor can be transitioned on any security failures, like software violations or hardware security violations.
+config ITSS + bool "Intel ITSS Interrupt controller" + depends on X86 || SANDBOX + help + This enabled support for the Intel ITSS, a type of interrupt + controller. It is present on apollolake and some other SoCs. The + device has its own uclass since there are several operations + involved. + config JZ4780_EFUSE bool "Ingenic JZ4780 eFUSE support" depends on ARCH_JZ47XX diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 90ef92806b9..f715d6d6df5 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o obj-$(CONFIG_IMX8) += imx8/ +obj-$(CONFIG_ITSS) += itss-uclass.o obj-$(CONFIG_LED_STATUS) += status_led.o obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o diff --git a/drivers/misc/itss-uclass.c b/drivers/misc/itss-uclass.c new file mode 100644 index 00000000000..664865cec3f --- /dev/null +++ b/drivers/misc/itss-uclass.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ITSS is a type of interrupt controller used on recent Intel SoC. + * + * Copyright 2019 Google LLC + */ + +#include <dm.h> +#include <itss.h> + +int itss_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) +{ + const struct itss_ops *ops = itss_get_ops(dev); + + if (!ops->route_pmc_gpio_gpe) + return -ENOSYS; + + return ops->route_pmc_gpio_gpe(dev, pmc_gpe_num); +} + +int itss_set_irq_polarity(struct udevice *dev, uint irq, bool active_low) +{ + const struct itss_ops *ops = itss_get_ops(dev); + + if (!ops->set_irq_polarity) + return -ENOSYS; + + return ops->set_irq_polarity(dev, irq, active_low); +} + +UCLASS_DRIVER(itss) = { + .id = UCLASS_ITSS, + .name = "itss", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 496570ff47d..892c746940d 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -54,6 +54,7 @@ enum uclass_id { UCLASS_I2S, /* I2S bus */ UCLASS_IDE, /* IDE device */ UCLASS_IRQ, /* Interrupt controller */ + UCLASS_ITSS, /* Intel interrupt thingy */ UCLASS_KEYBOARD, /* Keyboard input device */ UCLASS_LED, /* Light-emitting diode (LED) */ UCLASS_LPC, /* x86 'low pin count' interface */ diff --git a/include/itss.h b/include/itss.h new file mode 100644 index 00000000000..1a282cbac56 --- /dev/null +++ b/include/itss.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ITSS is a type of interrupt controller used on recent Intel SoC. + * + * Copyright 2019 Google LLC + */ + +#ifndef __ITSS_H +#define __ITSS_H + +/** + * struct itss_ops - Operations for the ITSS + */ +struct itss_ops { + /** + * route_pmc_gpio_gpe() - Get the GPIO for an event + * + * @dev: ITSS device + * @pmc_gpe_num: Event number to check + * @returns GPIO for the event, or -ENOENT if none + */ + int (*route_pmc_gpio_gpe)(struct udevice *dev, uint pmc_gpe_num); + + /** + * set_irq_polarity() - Set the IRQ polarity + * + * @dev: ITSS device + * @irq: Interrupt number to set + * @active_low: true if active low, false for active high + * @return 0 if OK, -EINVAL if @irq is invalid + */ + int (*set_irq_polarity)(struct udevice *dev, uint irq, bool active_low); +}; + +#define itss_get_ops(dev) ((struct itss_ops *)(dev)->driver->ops) + +/** + * itss_route_pmc_gpio_gpe() - Get the GPIO for an event + * + * @dev: ITSS device + * @pmc_gpe_num: Event number to check + * @returns GPIO for the event, or -ENOENT if none + */ +int itss_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num); + +/** + * set_irq_polarity() - Set the IRQ polarity + * + * @dev: ITSS device + * @irq: Interrupt number to set + * @active_low: true if active low, false for active high + * @return 0 if OK, -EINVAL if @irq is invalid + */ +int itss_set_irq_polarity(struct udevice *dev, uint irq, bool active_low); + +#endif

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This models some sort of interrupt thingy but there are so many abreviations that I cannot find out what it stands for. It is something to do with interrupts.
After I read the ApolloLake datasheet, the ITSS contains the following parts:
- A register block that is compatible with current "intel,irq-router" driver in U-Boot, plus two more - IOAPIC - Legacy 8254 - Legacy 8259 - Legacy I/O ports like NMI and reset control (0xcf9) - HPET
So it seems to me that the best option for us is to extend current "intel,irq-router" driver to support new capabilities, instead of creating a new "ITSS" uclass driver, which we both don't know that ITSS stands for ...
It supports two operations.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/misc/Kconfig | 9 ++++++ drivers/misc/Makefile | 1 + drivers/misc/itss-uclass.c | 34 +++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/itss.h | 56 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 drivers/misc/itss-uclass.c create mode 100644 include/itss.h
Regards, Bin

Add a simple sandbox test for this uclass.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/test.dts | 4 ++++ configs/sandbox_defconfig | 3 ++- drivers/misc/Makefile | 1 + drivers/misc/itss_sandbox.c | 44 +++++++++++++++++++++++++++++++++++++ test/dm/Makefile | 1 + test/dm/itss.c | 29 ++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 drivers/misc/itss_sandbox.c create mode 100644 test/dm/itss.c
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index cd4409b7aea..ea435f16247 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -345,6 +345,10 @@ vss-microvolts = <0>; };
+ itss { + compatible = "sandbox,itss"; + }; + lcd { u-boot,dm-pre-reloc; compatible = "sandbox,lcd-sdl"; diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 6f4d8449290..a1104b03433 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -129,6 +129,8 @@ CONFIG_CROS_EC_I2C=y CONFIG_CROS_EC_LPC=y CONFIG_CROS_EC_SANDBOX=y CONFIG_CROS_EC_SPI=y +CONFIG_ITSS=y +CONFIG_P2SB=y CONFIG_PWRSEQ=y CONFIG_SPL_PWRSEQ=y CONFIG_I2C_EEPROM=y @@ -149,7 +151,6 @@ CONFIG_PCI=y CONFIG_DM_PCI=y CONFIG_DM_PCI_COMPAT=y CONFIG_PCI_SANDBOX=y -CONFIG_P2SB=y CONFIG_PHY=y CONFIG_PHY_SANDBOX=y CONFIG_PINCTRL=y diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index f715d6d6df5..83fbd193657 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o obj-$(CONFIG_IMX8) += imx8/ obj-$(CONFIG_ITSS) += itss-uclass.o +obj-$(CONFIG_SANDBOX) += itss_sandbox.o obj-$(CONFIG_LED_STATUS) += status_led.o obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o diff --git a/drivers/misc/itss_sandbox.c b/drivers/misc/itss_sandbox.c new file mode 100644 index 00000000000..993106ffdc2 --- /dev/null +++ b/drivers/misc/itss_sandbox.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sandbox driver for itss + * + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <itss.h> + +static int sandbox_set_irq_polarity(struct udevice *dev, uint irq, + bool active_low) +{ + if (irq > 10) + return -EINVAL; + + return 0; +} + +static int sandbox_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num) +{ + if (pmc_gpe_num > 10) + return -ENOENT; + + return pmc_gpe_num + 1; +} + +static const struct itss_ops sandbox_itss_ops = { + .route_pmc_gpio_gpe = sandbox_route_pmc_gpio_gpe, + .set_irq_polarity = sandbox_set_irq_polarity, +}; + +static const struct udevice_id sandbox_itss_ids[] = { + { .compatible = "sandbox,itss"}, + { } +}; + +U_BOOT_DRIVER(sandbox_itss_drv) = { + .name = "sandbox_itss", + .id = UCLASS_ITSS, + .of_match = sandbox_itss_ids, + .ops = &sandbox_itss_ops, +}; diff --git a/test/dm/Makefile b/test/dm/Makefile index 52a2392a8e9..3868b5d4aa9 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_DM_GPIO) += gpio.o obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o obj-$(CONFIG_DM_I2C) += i2c.o obj-$(CONFIG_SOUND) += i2s.o +obj-$(CONFIG_ITSS) += itss.o obj-$(CONFIG_LED) += led.o obj-$(CONFIG_DM_MAILBOX) += mailbox.o obj-$(CONFIG_DM_MMC) += mmc.o diff --git a/test/dm/itss.c b/test/dm/itss.c new file mode 100644 index 00000000000..1ca1aeba9f4 --- /dev/null +++ b/test/dm/itss.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for ITSS uclass + * + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <itss.h> +#include <dm/test.h> +#include <test/ut.h> + +/* Base test of the ITSS uclass */ +static int dm_test_itss_base(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_ITSS, &dev)); + + ut_asserteq(5, itss_route_pmc_gpio_gpe(dev, 4)); + ut_asserteq(-ENOENT, itss_route_pmc_gpio_gpe(dev, 14)); + + ut_assertok(itss_set_irq_polarity(dev, 4, true)); + ut_asserteq(-EINVAL, itss_set_irq_polarity(dev, 14, true)); + + return 0; +} +DM_TEST(dm_test_itss_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

Define this symbol so that we can use binman symbols correctly.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/u-boot-spl.lds | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index c1e9bfbf66f..e6c22895b35 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -17,7 +17,10 @@ SECTIONS
. = IMAGE_TEXT_BASE; /* Location of bootcode in flash */ __text_start = .; - .text : { *(.text*); } + .text : { + __image_copy_start = .; + *(.text*); + }
. = ALIGN(4);

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Define this symbol so that we can use binman symbols correctly.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/u-boot-spl.lds | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index c1e9bfbf66f..e6c22895b35 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -17,7 +17,10 @@ SECTIONS
. = IMAGE_TEXT_BASE; /* Location of bootcode in flash */ __text_start = .;
.text : { *(.text*); }
.text : {
__image_copy_start = .;
I see this symbol is currently used in ARM. What's the purpose for x86?
*(.text*);
} . = ALIGN(4);
--
Regards, Bin

Hi Bin,
On Thu, 10 Oct 2019 at 01:09, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Define this symbol so that we can use binman symbols correctly.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/u-boot-spl.lds | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index c1e9bfbf66f..e6c22895b35 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -17,7 +17,10 @@ SECTIONS
. = IMAGE_TEXT_BASE; /* Location of bootcode in flash */ __text_start = .;
.text : { *(.text*); }
.text : {
__image_copy_start = .;
I see this symbol is currently used in ARM. What's the purpose for x86?
It defines the start address of the image. This is needed by binman since it needs to be able to find symbols mentioned in the elf file.
Regards, Simon

At present the records are 4KB in size. This is unnecessarily large when the SPI-flash erase size is 256 bytes. Reduce it so it will be more efficient with Apollolake's 24-byte variable-data record.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/mrccache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index 40fda856ff4..abf58182237 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -7,7 +7,7 @@ #ifndef _ASM_MRCCACHE_H #define _ASM_MRCCACHE_H
-#define MRC_DATA_ALIGN 0x1000 +#define MRC_DATA_ALIGN 0x100 #define MRC_DATA_SIGNATURE (('M' << 0) | ('R' << 8) | \ ('C' << 16) | ('D'<<24))

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
At present the records are 4KB in size. This is unnecessarily large when the SPI-flash erase size is 256 bytes. Reduce it so it will be more
But this will break for SPI-flash erase size that is not 256 bytes?
efficient with Apollolake's 24-byte variable-data record.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/mrccache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Regards, Bin

Hi Bin,
On Wed, 9 Oct 2019 at 23:09, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
At present the records are 4KB in size. This is unnecessarily large when the SPI-flash erase size is 256 bytes. Reduce it so it will be more
But this will break for SPI-flash erase size that is not 256 bytes?
The way it works is that it erases the whole region, then fills it up record by record, then when it gets full, erases it all again. So I think it is OK.
Regards, Simon

Move the code to determine the size of a cache record into a function so we can use it elsewhere in this file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/mrccache.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index be107627b80..33bb52039bd 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -17,19 +17,20 @@
DECLARE_GLOBAL_DATA_PTR;
+static uint mrc_block_size(uint data_size) +{ + uint mrc_size = sizeof(struct mrc_data_container) + data_size; + + return ALIGN(mrc_size, MRC_DATA_ALIGN); +} + static struct mrc_data_container *next_mrc_block( struct mrc_data_container *cache) { /* MRC data blocks are aligned within the region */ - u32 mrc_size = sizeof(*cache) + cache->data_size; u8 *region_ptr = (u8 *)cache;
- if (mrc_size & (MRC_DATA_ALIGN - 1UL)) { - mrc_size &= ~(MRC_DATA_ALIGN - 1UL); - mrc_size += MRC_DATA_ALIGN; - } - - region_ptr += mrc_size; + region_ptr += mrc_block_size(cache->data_size);
return (struct mrc_data_container *)region_ptr; }

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Move the code to determine the size of a cache record into a function so we can use it elsewhere in this file.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/mrccache.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 10, 2019 at 1:09 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Move the code to determine the size of a cache record into a function so we can use it elsewhere in this file.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/mrccache.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!

This should take account of the end of the new cache record since a record cannot extend beyond the end of the flash region. This problem was not seen before due to the alignment of the relatively small amount of MRC data.
But with apollolake the MRC data is about 45KB, even if most of it is zeroes.
Fix this bug and update the parameter name to be less confusing.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/mrccache.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 33bb52039bd..e286bdf1b30 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -86,15 +86,16 @@ struct mrc_data_container *mrccache_find_current(struct mrc_region *entry) * @return next cache entry if found, NULL if we got to the end */ static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry, - struct mrc_data_container *cache) + struct mrc_data_container *prev) { + struct mrc_data_container *cache; ulong base_addr, end_addr;
base_addr = entry->base + entry->offset; end_addr = base_addr + entry->length;
- cache = next_mrc_block(cache); - if ((ulong)cache >= end_addr) { + cache = next_mrc_block(prev); + if ((ulong)cache + mrc_block_size(prev->data_size) > end_addr) { /* Crossed the boundary */ cache = NULL; debug("%s: no available entries found\n", __func__);

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This should take account of the end of the new cache record since a record cannot extend beyond the end of the flash region. This problem was not seen before due to the alignment of the relatively small amount of MRC data.
But with apollolake the MRC data is about 45KB, even if most of it is zeroes.
Fix this bug and update the parameter name to be less confusing.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/mrccache.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 33bb52039bd..e286bdf1b30 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -86,15 +86,16 @@ struct mrc_data_container *mrccache_find_current(struct mrc_region *entry)
- @return next cache entry if found, NULL if we got to the end
*/ static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry,
struct mrc_data_container *cache)
struct mrc_data_container *prev)
{
struct mrc_data_container *cache; ulong base_addr, end_addr; base_addr = entry->base + entry->offset; end_addr = base_addr + entry->length;
cache = next_mrc_block(cache);
if ((ulong)cache >= end_addr) {
cache = next_mrc_block(prev);
if ((ulong)cache + mrc_block_size(prev->data_size) > end_addr) {
This does not look good to me. Why adding the "next" cache position to "prev" cache size? It should add the "next" cache size.
I agree there is an issue in missing check of boundary, but the check should not happen here, but mrccache_update(), before writing to SPI flash.
/* Crossed the boundary */ cache = NULL; debug("%s: no available entries found\n", __func__);
--
Regards, Bin

Hi Bin,
On Thu, 10 Oct 2019 at 00:23, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This should take account of the end of the new cache record since a record cannot extend beyond the end of the flash region. This problem was not seen before due to the alignment of the relatively small amount of MRC data.
But with apollolake the MRC data is about 45KB, even if most of it is zeroes.
Fix this bug and update the parameter name to be less confusing.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/mrccache.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 33bb52039bd..e286bdf1b30 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -86,15 +86,16 @@ struct mrc_data_container *mrccache_find_current(struct mrc_region *entry)
- @return next cache entry if found, NULL if we got to the end
*/ static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry,
struct mrc_data_container *cache)
struct mrc_data_container *prev)
{
struct mrc_data_container *cache; ulong base_addr, end_addr; base_addr = entry->base + entry->offset; end_addr = base_addr + entry->length;
cache = next_mrc_block(cache);
if ((ulong)cache >= end_addr) {
cache = next_mrc_block(prev);
if ((ulong)cache + mrc_block_size(prev->data_size) > end_addr) {
This does not look good to me. Why adding the "next" cache position to "prev" cache size? It should add the "next" cache size.
Yes, although here we assume they are the same. Should I add a comment?
Alternatively I could pass in the size that the caller wants for the new item?
I agree there is an issue in missing check of boundary, but the check should not happen here, but mrccache_update(), before writing to SPI flash.
OK, so passing in the size would be best, I suspect.
Perhaps rename the function to find_next_mrc_cache_pos()?
/* Crossed the boundary */ cache = NULL; debug("%s: no available entries found\n", __func__);
--
Regards, SImon

Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Thu, 10 Oct 2019 at 00:23, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This should take account of the end of the new cache record since a record cannot extend beyond the end of the flash region. This problem was not seen before due to the alignment of the relatively small amount of MRC data.
But with apollolake the MRC data is about 45KB, even if most of it is zeroes.
Fix this bug and update the parameter name to be less confusing.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/mrccache.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 33bb52039bd..e286bdf1b30 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -86,15 +86,16 @@ struct mrc_data_container *mrccache_find_current(struct mrc_region *entry)
- @return next cache entry if found, NULL if we got to the end
*/ static struct mrc_data_container *find_next_mrc_cache(struct mrc_region *entry,
struct mrc_data_container *cache)
struct mrc_data_container *prev)
{
struct mrc_data_container *cache; ulong base_addr, end_addr; base_addr = entry->base + entry->offset; end_addr = base_addr + entry->length;
cache = next_mrc_block(cache);
if ((ulong)cache >= end_addr) {
cache = next_mrc_block(prev);
if ((ulong)cache + mrc_block_size(prev->data_size) > end_addr) {
This does not look good to me. Why adding the "next" cache position to "prev" cache size? It should add the "next" cache size.
Yes, although here we assume they are the same. Should I add a comment?
Alternatively I could pass in the size that the caller wants for the new item?
I agree there is an issue in missing check of boundary, but the check should not happen here, but mrccache_update(), before writing to SPI flash.
OK, so passing in the size would be best, I suspect.
Yep, that would be better.
Perhaps rename the function to find_next_mrc_cache_pos()?
Sounds good.
/* Crossed the boundary */ cache = NULL; debug("%s: no available entries found\n", __func__);
--
Regards, Bin

Change the algorithm to first find the flash device then read the properties using the livetree API. With this change the device is not probed so this needs to be done in mrccache_save().
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/mrccache.c | 59 ++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 28 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index e286bdf1b30..296dd5e54f7 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -14,6 +14,8 @@ #include <spi.h> #include <spi_flash.h> #include <asm/mrccache.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -197,45 +199,43 @@ int mrccache_reserve(void)
int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) { - const void *blob = gd->fdt_blob; - int node, mrc_node; + struct udevice *dev; + ofnode mrc_node; + ulong map_base; + size_t map_size; + u32 offset; u32 reg[2]; int ret;
/* Find the flash chip within the SPI controller node */ - node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH); - if (node < 0) { - debug("%s: Cannot find SPI flash\n", __func__); - return -ENOENT; - } - - if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) { - debug("%s: Cannot find memory map\n", __func__); - return -EINVAL; + ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev); + if (ret) + return log_msg_ret("Cannot find SPI flash\n", ret); + ret = spi_flash_get_mmap(dev, &map_base, &map_size, &offset); + if (!ret) { + entry->base = map_base; + } else { + ret = dev_read_u32_array(dev, "memory-map", reg, 2); + if (ret) + return log_msg_ret("Cannot find memory map\n", ret); + entry->base = reg[0]; } - 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) { - debug("%s: Cannot find node\n", __func__); - return -EPERM; - } + mrc_node = dev_read_subnode(dev, "rw-mrc-cache"); + if (!ofnode_valid(mrc_node)) + return log_msg_ret("Cannot find node", -EPERM);
- if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) { - debug("%s: Cannot find address\n", __func__); - return -EINVAL; - } + ret = ofnode_read_u32_array(mrc_node, "reg", reg, 2); + if (ret) + return log_msg_ret("Cannot find address", ret); entry->offset = reg[0]; entry->length = reg[1];
- if (devp) { - ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node, - devp); - debug("ret = %d\n", ret); - if (ret) - return ret; - } + if (devp) + *devp = dev; + debug("MRC cache in '%s', offset %x, len %x, base %x\n", + dev->name, entry->offset, entry->length, entry->base);
return 0; } @@ -253,6 +253,9 @@ int mrccache_save(void) gd->arch.mrc_output_len);
ret = mrccache_get_region(&sf, &entry); + if (ret) + goto err_entry; + ret = device_probe(sf); if (ret) goto err_entry; data = (struct mrc_data_container *)gd->arch.mrc_output;

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Change the algorithm to first find the flash device then read the properties using the livetree API. With this change the device is not probed so this needs to be done in mrccache_save().
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/mrccache.c | 59 ++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 28 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index e286bdf1b30..296dd5e54f7 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -14,6 +14,8 @@ #include <spi.h> #include <spi_flash.h> #include <asm/mrccache.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -197,45 +199,43 @@ int mrccache_reserve(void)
int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) {
const void *blob = gd->fdt_blob;
int node, mrc_node;
struct udevice *dev;
ofnode mrc_node;
ulong map_base;
size_t map_size;
u32 offset; u32 reg[2]; int ret; /* Find the flash chip within the SPI controller node */
node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
if (node < 0) {
debug("%s: Cannot find SPI flash\n", __func__);
return -ENOENT;
}
if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) {
debug("%s: Cannot find memory map\n", __func__);
return -EINVAL;
ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev);
if (ret)
return log_msg_ret("Cannot find SPI flash\n", ret);
ret = spi_flash_get_mmap(dev, &map_base, &map_size, &offset);
This looks a separate patch, not related to livetree conversion.
if (!ret) {
entry->base = map_base;
} else {
ret = dev_read_u32_array(dev, "memory-map", reg, 2);
if (ret)
return log_msg_ret("Cannot find memory map\n", ret);
entry->base = reg[0]; }
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) {
debug("%s: Cannot find node\n", __func__);
return -EPERM;
}
mrc_node = dev_read_subnode(dev, "rw-mrc-cache");
if (!ofnode_valid(mrc_node))
return log_msg_ret("Cannot find node", -EPERM);
if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) {
debug("%s: Cannot find address\n", __func__);
return -EINVAL;
}
ret = ofnode_read_u32_array(mrc_node, "reg", reg, 2);
if (ret)
return log_msg_ret("Cannot find address", ret); entry->offset = reg[0]; entry->length = reg[1];
if (devp) {
ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node,
devp);
debug("ret = %d\n", ret);
if (ret)
return ret;
}
if (devp)
*devp = dev;
debug("MRC cache in '%s', offset %x, len %x, base %x\n",
dev->name, entry->offset, entry->length, entry->base); return 0;
} @@ -253,6 +253,9 @@ int mrccache_save(void) gd->arch.mrc_output_len);
ret = mrccache_get_region(&sf, &entry);
if (ret)
goto err_entry;
ret = device_probe(sf);
Why we need manually probe spi flash here?
if (ret) goto err_entry; data = (struct mrc_data_container *)gd->arch.mrc_output;
--
Regards, Bin

Hi Bin,
On Thu, 10 Oct 2019 at 00:45, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Change the algorithm to first find the flash device then read the properties using the livetree API. With this change the device is not probed so this needs to be done in mrccache_save().
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/mrccache.c | 59 ++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 28 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index e286bdf1b30..296dd5e54f7 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -14,6 +14,8 @@ #include <spi.h> #include <spi_flash.h> #include <asm/mrccache.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -197,45 +199,43 @@ int mrccache_reserve(void)
int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) {
const void *blob = gd->fdt_blob;
int node, mrc_node;
struct udevice *dev;
ofnode mrc_node;
ulong map_base;
size_t map_size;
u32 offset; u32 reg[2]; int ret; /* Find the flash chip within the SPI controller node */
node = fdtdec_next_compatible(blob, 0, COMPAT_GENERIC_SPI_FLASH);
if (node < 0) {
debug("%s: Cannot find SPI flash\n", __func__);
return -ENOENT;
}
if (fdtdec_get_int_array(blob, node, "memory-map", reg, 2)) {
debug("%s: Cannot find memory map\n", __func__);
return -EINVAL;
ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev);
if (ret)
return log_msg_ret("Cannot find SPI flash\n", ret);
ret = spi_flash_get_mmap(dev, &map_base, &map_size, &offset);
This looks a separate patch, not related to livetree conversion.
Yes, will split this out.
if (!ret) {
entry->base = map_base;
} else {
ret = dev_read_u32_array(dev, "memory-map", reg, 2);
if (ret)
return log_msg_ret("Cannot find memory map\n", ret);
entry->base = reg[0]; }
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) {
debug("%s: Cannot find node\n", __func__);
return -EPERM;
}
mrc_node = dev_read_subnode(dev, "rw-mrc-cache");
if (!ofnode_valid(mrc_node))
return log_msg_ret("Cannot find node", -EPERM);
if (fdtdec_get_int_array(blob, mrc_node, "reg", reg, 2)) {
debug("%s: Cannot find address\n", __func__);
return -EINVAL;
}
ret = ofnode_read_u32_array(mrc_node, "reg", reg, 2);
if (ret)
return log_msg_ret("Cannot find address", ret); entry->offset = reg[0]; entry->length = reg[1];
if (devp) {
ret = uclass_get_device_by_of_offset(UCLASS_SPI_FLASH, node,
devp);
debug("ret = %d\n", ret);
if (ret)
return ret;
}
if (devp)
*devp = dev;
debug("MRC cache in '%s', offset %x, len %x, base %x\n",
dev->name, entry->offset, entry->length, entry->base); return 0;
} @@ -253,6 +253,9 @@ int mrccache_save(void) gd->arch.mrc_output_len);
ret = mrccache_get_region(&sf, &entry);
if (ret)
goto err_entry;
ret = device_probe(sf);
Why we need manually probe spi flash here?
Probing it before calling the get_mmap() function seems to break it and then causes the SPI flash to stop working. I'll add a larger comment. Hopefully we can correct this.
if (ret) goto err_entry; data = (struct mrc_data_container *)gd->arch.mrc_output;
--
Regards, Bin
Regards, Simon

At present we reuse the mrc_output char * to also point to the cache record after it has been set up. This is confusing and doesn't save much data space.
Add a new mrc_cache member instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/global_data.h | 2 ++ arch/x86/lib/mrccache.c | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 17a4d344913..c5faac5c901 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -10,6 +10,7 @@ #ifndef __ASSEMBLY__
#include <asm/processor.h> +#include <asm/mrccache.h>
enum pei_boot_mode_t { PEI_BOOT_NONE = 0, @@ -92,6 +93,7 @@ struct arch_global_data { /* MRC training data to save for the next boot */ char *mrc_output; unsigned int mrc_output_len; + struct mrc_data_container *mrc_cache; ulong table; /* Table pointer from previous loader */ int turbo_state; /* Current turbo state */ struct irq_routing_table *pirq_routing_table; diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 296dd5e54f7..9a3e5fffa45 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -179,8 +179,7 @@ static void mrccache_setup(void *data) cache->reserved = 0; memcpy(cache->data, gd->arch.mrc_output, cache->data_size);
- /* gd->arch.mrc_output now points to the container */ - gd->arch.mrc_output = (char *)cache; + gd->arch.mrc_cache = cache; }
int mrccache_reserve(void) @@ -242,7 +241,7 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
int mrccache_save(void) { - struct mrc_data_container *data; + struct mrc_data_container *cache; struct mrc_region entry; struct udevice *sf; int ret; @@ -258,10 +257,10 @@ int mrccache_save(void) ret = device_probe(sf); if (ret) goto err_entry; - data = (struct mrc_data_container *)gd->arch.mrc_output; - ret = mrccache_update(sf, &entry, data); + cache = gd->arch.mrc_cache; + ret = mrccache_update(sf, &entry, cache); if (!ret) { - debug("Saved MRC data with checksum %04x\n", data->checksum); + debug("Saved MRC data with checksum %04x\n", cache->checksum); } else if (ret == -EEXIST) { debug("MRC data is the same as last time, skipping save\n"); ret = 0;

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
At present we reuse the mrc_output char * to also point to the cache record after it has been set up. This is confusing and doesn't save much data space.
Add a new mrc_cache member instead.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/global_data.h | 2 ++ arch/x86/lib/mrccache.c | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

This function is a bit confusing at present due to the error handling. Update it to remove the goto, returning errors as they happen.
While we are here, use hex for the data size since this is the norm in U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/mrccache.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 9a3e5fffa45..0208696c834 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -248,28 +248,23 @@ int mrccache_save(void)
if (!gd->arch.mrc_output_len) return 0; - debug("Saving %d bytes of MRC output data to SPI flash\n", + debug("Saving %#x bytes of MRC output data to SPI flash\n", gd->arch.mrc_output_len);
ret = mrccache_get_region(&sf, &entry); if (ret) - goto err_entry; + return log_msg_ret("Cannot get region", ret); ret = device_probe(sf); if (ret) - goto err_entry; + return log_msg_ret("Cannot probe device", ret); cache = gd->arch.mrc_cache; ret = mrccache_update(sf, &entry, cache); - if (!ret) { + if (!ret) debug("Saved MRC data with checksum %04x\n", cache->checksum); - } else if (ret == -EEXIST) { + else if (ret == -EEXIST) debug("MRC data is the same as last time, skipping save\n"); - ret = 0; - }
-err_entry: - if (ret) - debug("%s: Failed: %d\n", __func__, ret); - return ret; + return 0; }
int mrccache_spl_save(void)

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This function is a bit confusing at present due to the error handling. Update it to remove the goto, returning errors as they happen.
While we are here, use hex for the data size since this is the norm in U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/mrccache.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

With apollolake we need to support a normal cache, which almost never changes and a much smaller 'variable' cache which changes every time.
Update the code to add a cache type, use an array for the caches and use a for loop to iterate over the caches.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/sdram.c | 8 ++- arch/x86/cpu/ivybridge/sdram.c | 8 ++- arch/x86/cpu/quark/dram.c | 8 ++- arch/x86/include/asm/global_data.h | 21 +++++-- arch/x86/include/asm/mrccache.h | 11 +++- arch/x86/lib/fsp/fsp_common.c | 2 +- arch/x86/lib/fsp1/fsp_dram.c | 8 ++- arch/x86/lib/mrccache.c | 93 ++++++++++++++++++++---------- 8 files changed, 109 insertions(+), 50 deletions(-)
diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c index b31d78c092a..107c04691b0 100644 --- a/arch/x86/cpu/broadwell/sdram.c +++ b/arch/x86/cpu/broadwell/sdram.c @@ -82,7 +82,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data) struct mrc_region entry; int ret;
- ret = mrccache_get_region(NULL, &entry); + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret; mrc_cache = mrccache_find_current(&entry); @@ -168,12 +168,14 @@ int dram_init(void) pei_data->data_to_save); /* S3 resume: don't save scrambler seed or MRC data */ if (pei_data->boot_mode != SLEEP_STATE_S3) { + struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL]; + /* * This will be copied to SDRAM in reserve_arch(), then written * to SPI flash in mrccache_save() */ - gd->arch.mrc_output = (char *)pei_data->data_to_save; - gd->arch.mrc_output_len = pei_data->data_to_save_size; + mrc->buf = (char *)pei_data->data_to_save; + mrc->len = pei_data->data_to_save_size; } gd->arch.pei_meminfo = pei_data->meminfo;
diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c index 8a58d0383d5..8b03406666e 100644 --- a/arch/x86/cpu/ivybridge/sdram.c +++ b/arch/x86/cpu/ivybridge/sdram.c @@ -115,7 +115,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data) ret = read_seed_from_cmos(pei_data); if (ret) return ret; - ret = mrccache_get_region(NULL, &entry); + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret; mrc_cache = mrccache_find_current(&entry); @@ -537,12 +537,14 @@ int dram_init(void)
/* S3 resume: don't save scrambler seed or MRC data */ if (pei_data->boot_mode != PEI_BOOT_RESUME) { + struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL]; + /* * This will be copied to SDRAM in reserve_arch(), then written * to SPI flash in mrccache_save() */ - gd->arch.mrc_output = (char *)pei_data->mrc_output; - gd->arch.mrc_output_len = pei_data->mrc_output_len; + mrc->buf = (char *)pei_data->mrc_output; + mrc->len = pei_data->mrc_output_len; ret = write_seeds_to_cmos(pei_data); if (ret) debug("Failed to write seeds to CMOS: %d\n", ret); diff --git a/arch/x86/cpu/quark/dram.c b/arch/x86/cpu/quark/dram.c index 51f9659ab15..3994355112b 100644 --- a/arch/x86/cpu/quark/dram.c +++ b/arch/x86/cpu/quark/dram.c @@ -22,7 +22,7 @@ static __maybe_unused int prepare_mrc_cache(struct mrc_params *mrc_params) struct mrc_region entry; int ret;
- ret = mrccache_get_region(NULL, &entry); + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret;
@@ -152,9 +152,11 @@ int dram_init(void) #ifdef CONFIG_ENABLE_MRC_CACHE cache = malloc(sizeof(struct mrc_timings)); if (cache) { + struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL]; + memcpy(cache, &mrc_params.timings, sizeof(struct mrc_timings)); - gd->arch.mrc_output = cache; - gd->arch.mrc_output_len = sizeof(struct mrc_timings); + mrc->buf = cache; + mrc->len = sizeof(struct mrc_timings); } #endif
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index c5faac5c901..2475b3427e1 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -67,6 +67,21 @@ struct mtrr_request { uint64_t size; };
+/** + * struct mrc_output - holds the MRC data + * + * @buf: MRC training data to save for the next boot. This is set to point to + * the raw data after SDRAM init is complete. Then mrccache_setup() + * turns it into a proper cache record with a checksum + * @len: Length of @buf + * @cache: Resulting cache record + */ +struct mrc_output { + char *buf; + uint len; + struct mrc_data_container *cache; +}; + /* Architecture-specific global data */ struct arch_global_data { u64 gdt[X86_GDT_NUM_ENTRIES] __aligned(16); @@ -90,10 +105,8 @@ struct arch_global_data { struct mtrr_request mtrr_req[MAX_MTRR_REQUESTS]; int mtrr_req_count; int has_mtrr; - /* MRC training data to save for the next boot */ - char *mrc_output; - unsigned int mrc_output_len; - struct mrc_data_container *mrc_cache; + /* MRC training data */ + struct mrc_output mrc[MRC_TYPE_COUNT]; ulong table; /* Table pointer from previous loader */ int turbo_state; /* Current turbo state */ struct irq_routing_table *pirq_routing_table; diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index abf58182237..b81e2b2fb6a 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -27,6 +27,13 @@ struct mrc_region { u32 length; };
+/* Types of MRC data */ +enum mrc_type_t { + MRC_TYPE_NORMAL, + + MRC_TYPE_COUNT, +}; + struct udevice;
/** @@ -84,6 +91,7 @@ int mrccache_reserve(void); * triggers PCI bus enumeration during which insufficient memory issue * might be exposed and it causes subsequent SPI flash probe fails). * + * @type: Type of MRC data to use * @devp: Returns pointer to the SPI flash device * @entry: Position and size of MRC cache in SPI flash * @return 0 if success, -ENOENT if SPI flash node does not exist in the @@ -91,7 +99,8 @@ int mrccache_reserve(void); * tree, -EINVAL if MRC region properties format is incorrect, other error * if SPI flash probe failed. */ -int mrccache_get_region(struct udevice **devp, struct mrc_region *entry); +int mrccache_get_region(enum mrc_type_t type, struct udevice **devp, + struct mrc_region *entry);
/** * mrccache_save() - save MRC data to the SPI flash diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 40ba866d77c..c1c30ce0eb6 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -63,7 +63,7 @@ void *fsp_prepare_mrc_cache(void) struct mrc_region entry; int ret;
- ret = mrccache_get_region(NULL, &entry); + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return NULL;
diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c index 6a3349b42af..5ef89744b94 100644 --- a/arch/x86/lib/fsp1/fsp_dram.c +++ b/arch/x86/lib/fsp1/fsp_dram.c @@ -15,9 +15,11 @@ int dram_init(void) if (ret) return ret;
- if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) - gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list, - &gd->arch.mrc_output_len); + if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) { + struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL]; + + mrc->buf = fsp_get_nvs_data(gd->arch.hob_list, &mrc->len); + }
return 0; } diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 0208696c834..8de7dc48f44 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -159,44 +159,51 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry, cur); if (ret) { debug("Failed to write to SPI flash\n"); - return ret; + return log_msg_ret("Cannot update mrccache", ret); }
return 0; }
-static void mrccache_setup(void *data) +static void mrccache_setup(struct mrc_output *mrc, void *data) { struct mrc_data_container *cache = data; u16 checksum;
cache->signature = MRC_DATA_SIGNATURE; - cache->data_size = gd->arch.mrc_output_len; - checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size); + cache->data_size = mrc->len; + checksum = compute_ip_checksum(mrc->buf, cache->data_size); debug("Saving %d bytes for MRC output data, checksum %04x\n", cache->data_size, checksum); cache->checksum = checksum; cache->reserved = 0; - memcpy(cache->data, gd->arch.mrc_output, cache->data_size); + memcpy(cache->data, mrc->buf, cache->data_size);
- gd->arch.mrc_cache = cache; + mrc->cache = cache; }
int mrccache_reserve(void) { - if (!gd->arch.mrc_output_len) - return 0; + int i; + + for (i = 0; i < MRC_TYPE_COUNT; i++) { + struct mrc_output *mrc = &gd->arch.mrc[i];
- /* 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); + if (!mrc->len) + continue;
- gd->start_addr_sp &= ~0xf; + /* adjust stack pointer to store pure cache data plus header */ + gd->start_addr_sp -= (mrc->len + MRC_DATA_HEADER_SIZE); + mrccache_setup(mrc, (void *)gd->start_addr_sp); + + gd->start_addr_sp &= ~0xf; + }
return 0; }
-int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) +int mrccache_get_region(enum mrc_type_t type, struct udevice **devp, + struct mrc_region *entry) { struct udevice *dev; ofnode mrc_node; @@ -221,7 +228,8 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) }
/* Find the place where we put the MRC cache */ - mrc_node = dev_read_subnode(dev, "rw-mrc-cache"); + mrc_node = dev_read_subnode(dev, type == MRC_TYPE_NORMAL ? + "rw-mrc-cache" : "rw-var-mrc-cache"); if (!ofnode_valid(mrc_node)) return log_msg_ret("Cannot find node", -EPERM);
@@ -233,31 +241,33 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
if (devp) *devp = dev; - debug("MRC cache in '%s', offset %x, len %x, base %x\n", - dev->name, entry->offset, entry->length, entry->base); + debug("MRC cache type %d in '%s', offset %x, len %x, base %x\n", + type, dev->name, entry->offset, entry->length, entry->base);
return 0; }
-int mrccache_save(void) +static int mrccache_save_type(enum mrc_type_t type) { struct mrc_data_container *cache; + struct mrc_output *mrc; struct mrc_region entry; struct udevice *sf; int ret;
- if (!gd->arch.mrc_output_len) + mrc = &gd->arch.mrc[type]; + if (!mrc->len) return 0; - debug("Saving %#x bytes of MRC output data to SPI flash\n", - gd->arch.mrc_output_len); - - ret = mrccache_get_region(&sf, &entry); + log_debug("Saving %#x bytes of MRC output data type %d to SPI flash\n", + mrc->len, type); + ret = mrccache_get_region(type, &sf, &entry); if (ret) return log_msg_ret("Cannot get region", ret); ret = device_probe(sf); if (ret) return log_msg_ret("Cannot probe device", ret); - cache = gd->arch.mrc_cache; + cache = mrc->cache; + ret = mrccache_update(sf, &entry, cache); if (!ret) debug("Saved MRC data with checksum %04x\n", cache->checksum); @@ -267,17 +277,36 @@ int mrccache_save(void) return 0; }
+int mrccache_save(void) +{ + int i; + + for (i = 0; i < MRC_TYPE_COUNT; i++) { + int ret; + + ret = mrccache_save_type(i); + if (ret) + return ret; + } + + return 0; +} + 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; + int i; + + for (i = 0; i < MRC_TYPE_COUNT; i++) { + struct mrc_output *mrc = &gd->arch.mrc[i]; + void *data; + int size; + + size = mrc->len + MRC_DATA_HEADER_SIZE; + data = malloc(size); + if (!data) + return log_msg_ret("Allocate MRC cache block", -ENOMEM); + mrccache_setup(mrc, data); + }
return mrccache_save(); }

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
With apollolake we need to support a normal cache, which almost never changes and a much smaller 'variable' cache which changes every time.
Update the code to add a cache type, use an array for the caches and use a for loop to iterate over the caches.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/broadwell/sdram.c | 8 ++- arch/x86/cpu/ivybridge/sdram.c | 8 ++- arch/x86/cpu/quark/dram.c | 8 ++- arch/x86/include/asm/global_data.h | 21 +++++-- arch/x86/include/asm/mrccache.h | 11 +++- arch/x86/lib/fsp/fsp_common.c | 2 +- arch/x86/lib/fsp1/fsp_dram.c | 8 ++- arch/x86/lib/mrccache.c | 93 ++++++++++++++++++++---------- 8 files changed, 109 insertions(+), 50 deletions(-)
diff --git a/arch/x86/cpu/broadwell/sdram.c b/arch/x86/cpu/broadwell/sdram.c index b31d78c092a..107c04691b0 100644 --- a/arch/x86/cpu/broadwell/sdram.c +++ b/arch/x86/cpu/broadwell/sdram.c @@ -82,7 +82,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data) struct mrc_region entry; int ret;
ret = mrccache_get_region(NULL, &entry);
ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret; mrc_cache = mrccache_find_current(&entry);
@@ -168,12 +168,14 @@ int dram_init(void) pei_data->data_to_save); /* S3 resume: don't save scrambler seed or MRC data */ if (pei_data->boot_mode != SLEEP_STATE_S3) {
struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
/* * This will be copied to SDRAM in reserve_arch(), then written * to SPI flash in mrccache_save() */
gd->arch.mrc_output = (char *)pei_data->data_to_save;
gd->arch.mrc_output_len = pei_data->data_to_save_size;
mrc->buf = (char *)pei_data->data_to_save;
mrc->len = pei_data->data_to_save_size; } gd->arch.pei_meminfo = pei_data->meminfo;
diff --git a/arch/x86/cpu/ivybridge/sdram.c b/arch/x86/cpu/ivybridge/sdram.c index 8a58d0383d5..8b03406666e 100644 --- a/arch/x86/cpu/ivybridge/sdram.c +++ b/arch/x86/cpu/ivybridge/sdram.c @@ -115,7 +115,7 @@ static int prepare_mrc_cache(struct pei_data *pei_data) ret = read_seed_from_cmos(pei_data); if (ret) return ret;
ret = mrccache_get_region(NULL, &entry);
ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret; mrc_cache = mrccache_find_current(&entry);
@@ -537,12 +537,14 @@ int dram_init(void)
/* S3 resume: don't save scrambler seed or MRC data */ if (pei_data->boot_mode != PEI_BOOT_RESUME) {
struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
/* * This will be copied to SDRAM in reserve_arch(), then written * to SPI flash in mrccache_save() */
gd->arch.mrc_output = (char *)pei_data->mrc_output;
gd->arch.mrc_output_len = pei_data->mrc_output_len;
mrc->buf = (char *)pei_data->mrc_output;
mrc->len = pei_data->mrc_output_len; ret = write_seeds_to_cmos(pei_data); if (ret) debug("Failed to write seeds to CMOS: %d\n", ret);
diff --git a/arch/x86/cpu/quark/dram.c b/arch/x86/cpu/quark/dram.c index 51f9659ab15..3994355112b 100644 --- a/arch/x86/cpu/quark/dram.c +++ b/arch/x86/cpu/quark/dram.c @@ -22,7 +22,7 @@ static __maybe_unused int prepare_mrc_cache(struct mrc_params *mrc_params) struct mrc_region entry; int ret;
ret = mrccache_get_region(NULL, &entry);
ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return ret;
@@ -152,9 +152,11 @@ int dram_init(void) #ifdef CONFIG_ENABLE_MRC_CACHE cache = malloc(sizeof(struct mrc_timings)); if (cache) {
struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
memcpy(cache, &mrc_params.timings, sizeof(struct mrc_timings));
gd->arch.mrc_output = cache;
gd->arch.mrc_output_len = sizeof(struct mrc_timings);
mrc->buf = cache;
mrc->len = sizeof(struct mrc_timings); }
#endif
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index c5faac5c901..2475b3427e1 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -67,6 +67,21 @@ struct mtrr_request { uint64_t size; };
+/**
- struct mrc_output - holds the MRC data
- @buf: MRC training data to save for the next boot. This is set to point to
the raw data after SDRAM init is complete. Then mrccache_setup()
turns it into a proper cache record with a checksum
- @len: Length of @buf
- @cache: Resulting cache record
- */
+struct mrc_output {
char *buf;
uint len;
struct mrc_data_container *cache;
+};
/* Architecture-specific global data */ struct arch_global_data { u64 gdt[X86_GDT_NUM_ENTRIES] __aligned(16); @@ -90,10 +105,8 @@ struct arch_global_data { struct mtrr_request mtrr_req[MAX_MTRR_REQUESTS]; int mtrr_req_count; int has_mtrr;
/* MRC training data to save for the next boot */
char *mrc_output;
unsigned int mrc_output_len;
struct mrc_data_container *mrc_cache;
/* MRC training data */
struct mrc_output mrc[MRC_TYPE_COUNT]; ulong table; /* Table pointer from previous loader */ int turbo_state; /* Current turbo state */ struct irq_routing_table *pirq_routing_table;
diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index abf58182237..b81e2b2fb6a 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -27,6 +27,13 @@ struct mrc_region { u32 length; };
+/* Types of MRC data */ +enum mrc_type_t {
MRC_TYPE_NORMAL,
MRC_TYPE_COUNT,
+};
struct udevice;
/** @@ -84,6 +91,7 @@ int mrccache_reserve(void);
- triggers PCI bus enumeration during which insufficient memory issue
- might be exposed and it causes subsequent SPI flash probe fails).
- @type: Type of MRC data to use
- @devp: Returns pointer to the SPI flash device
- @entry: Position and size of MRC cache in SPI flash
- @return 0 if success, -ENOENT if SPI flash node does not exist in the
@@ -91,7 +99,8 @@ int mrccache_reserve(void);
- tree, -EINVAL if MRC region properties format is incorrect, other error
- if SPI flash probe failed.
*/ -int mrccache_get_region(struct udevice **devp, struct mrc_region *entry); +int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
struct mrc_region *entry);
/**
- mrccache_save() - save MRC data to the SPI flash
diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 40ba866d77c..c1c30ce0eb6 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -63,7 +63,7 @@ void *fsp_prepare_mrc_cache(void) struct mrc_region entry; int ret;
ret = mrccache_get_region(NULL, &entry);
ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); if (ret) return NULL;
diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c index 6a3349b42af..5ef89744b94 100644 --- a/arch/x86/lib/fsp1/fsp_dram.c +++ b/arch/x86/lib/fsp1/fsp_dram.c @@ -15,9 +15,11 @@ int dram_init(void) if (ret) return ret;
if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE))
gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list,
&gd->arch.mrc_output_len);
if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) {
struct mrc_output *mrc = &gd->arch.mrc[MRC_TYPE_NORMAL];
mrc->buf = fsp_get_nvs_data(gd->arch.hob_list, &mrc->len);
} return 0;
} diff --git a/arch/x86/lib/mrccache.c b/arch/x86/lib/mrccache.c index 0208696c834..8de7dc48f44 100644 --- a/arch/x86/lib/mrccache.c +++ b/arch/x86/lib/mrccache.c @@ -159,44 +159,51 @@ int mrccache_update(struct udevice *sf, struct mrc_region *entry, cur); if (ret) { debug("Failed to write to SPI flash\n");
return ret;
return log_msg_ret("Cannot update mrccache", ret);
This line change should be in patch [84/126] "x86: Tidy up error handling in mrccache_save()"
} return 0;
}
-static void mrccache_setup(void *data) +static void mrccache_setup(struct mrc_output *mrc, void *data) { struct mrc_data_container *cache = data; u16 checksum;
cache->signature = MRC_DATA_SIGNATURE;
cache->data_size = gd->arch.mrc_output_len;
checksum = compute_ip_checksum(gd->arch.mrc_output, cache->data_size);
cache->data_size = mrc->len;
checksum = compute_ip_checksum(mrc->buf, cache->data_size); debug("Saving %d bytes for MRC output data, checksum %04x\n", cache->data_size, checksum); cache->checksum = checksum; cache->reserved = 0;
memcpy(cache->data, gd->arch.mrc_output, cache->data_size);
memcpy(cache->data, mrc->buf, cache->data_size);
gd->arch.mrc_cache = cache;
mrc->cache = cache;
}
int mrccache_reserve(void) {
if (!gd->arch.mrc_output_len)
return 0;
int i;
for (i = 0; i < MRC_TYPE_COUNT; i++) {
struct mrc_output *mrc = &gd->arch.mrc[i];
/* 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);
if (!mrc->len)
continue;
gd->start_addr_sp &= ~0xf;
/* adjust stack pointer to store pure cache data plus header */
gd->start_addr_sp -= (mrc->len + MRC_DATA_HEADER_SIZE);
mrccache_setup(mrc, (void *)gd->start_addr_sp);
gd->start_addr_sp &= ~0xf;
} return 0;
}
-int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) +int mrccache_get_region(enum mrc_type_t type, struct udevice **devp,
struct mrc_region *entry)
{ struct udevice *dev; ofnode mrc_node; @@ -221,7 +228,8 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry) }
/* Find the place where we put the MRC cache */
mrc_node = dev_read_subnode(dev, "rw-mrc-cache");
mrc_node = dev_read_subnode(dev, type == MRC_TYPE_NORMAL ?
"rw-mrc-cache" : "rw-var-mrc-cache");
This change should either be put in next patch [86/126] "x86: Add mrccache support for a 'variable' cache", or squash the [86/126] patch into this patch.
if (!ofnode_valid(mrc_node)) return log_msg_ret("Cannot find node", -EPERM);
@@ -233,31 +241,33 @@ int mrccache_get_region(struct udevice **devp, struct mrc_region *entry)
if (devp) *devp = dev;
debug("MRC cache in '%s', offset %x, len %x, base %x\n",
dev->name, entry->offset, entry->length, entry->base);
debug("MRC cache type %d in '%s', offset %x, len %x, base %x\n",
type, dev->name, entry->offset, entry->length, entry->base); return 0;
}
-int mrccache_save(void) +static int mrccache_save_type(enum mrc_type_t type) { struct mrc_data_container *cache;
struct mrc_output *mrc; struct mrc_region entry; struct udevice *sf; int ret;
if (!gd->arch.mrc_output_len)
mrc = &gd->arch.mrc[type];
if (!mrc->len) return 0;
debug("Saving %#x bytes of MRC output data to SPI flash\n",
gd->arch.mrc_output_len);
ret = mrccache_get_region(&sf, &entry);
log_debug("Saving %#x bytes of MRC output data type %d to SPI flash\n",
mrc->len, type);
ret = mrccache_get_region(type, &sf, &entry); if (ret) return log_msg_ret("Cannot get region", ret); ret = device_probe(sf); if (ret) return log_msg_ret("Cannot probe device", ret);
cache = gd->arch.mrc_cache;
cache = mrc->cache;
ret = mrccache_update(sf, &entry, cache); if (!ret) debug("Saved MRC data with checksum %04x\n", cache->checksum);
@@ -267,17 +277,36 @@ int mrccache_save(void) return 0; }
+int mrccache_save(void) +{
int i;
for (i = 0; i < MRC_TYPE_COUNT; i++) {
int ret;
ret = mrccache_save_type(i);
if (ret)
return ret;
}
return 0;
+}
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;
int i;
for (i = 0; i < MRC_TYPE_COUNT; i++) {
struct mrc_output *mrc = &gd->arch.mrc[i];
void *data;
int size;
size = mrc->len + MRC_DATA_HEADER_SIZE;
data = malloc(size);
if (!data)
return log_msg_ret("Allocate MRC cache block", -ENOMEM);
mrccache_setup(mrc, data);
} return mrccache_save();
}
Regards, Bin

Add support for a second cache type, for apollolake.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/mrccache.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index b81e2b2fb6a..0917cf24704 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -30,6 +30,7 @@ struct mrc_region { /* Types of MRC data */ enum mrc_type_t { MRC_TYPE_NORMAL, + MRC_TYPE_VAR,
MRC_TYPE_COUNT, };

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Add support for a second cache type, for apollolake.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/mrccache.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/arch/x86/include/asm/mrccache.h b/arch/x86/include/asm/mrccache.h index b81e2b2fb6a..0917cf24704 100644 --- a/arch/x86/include/asm/mrccache.h +++ b/arch/x86/include/asm/mrccache.h @@ -30,6 +30,7 @@ struct mrc_region { /* Types of MRC data */ enum mrc_type_t { MRC_TYPE_NORMAL,
MRC_TYPE_VAR,
Please see my comments to previous patch. Either squash this patch to previous one, or move the MRC_TYPE_VAR related changes to this patch.
MRC_TYPE_COUNT,
};
Regards, Bin

This function needs to be different for FSP2, so move the existing function into the fsp1 directory. Since it is only called from one file, drop it from the header file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/fsp/fsp_support.h | 7 ------- arch/x86/lib/fsp/fsp_common.c | 20 -------------------- arch/x86/lib/fsp1/fsp_common.c | 20 ++++++++++++++++++++ 3 files changed, 20 insertions(+), 27 deletions(-)
diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h index 2424bc1f5f9..d3eee6c0c11 100644 --- a/arch/x86/include/asm/fsp/fsp_support.h +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -146,13 +146,6 @@ int fsp_init_phase_pci(void); */ int fsp_scan_for_ram_size(void);
-/** - * fsp_prepare_mrc_cache() - Find the DRAM training data from the MRC cache - * - * @return pointer to data, or NULL if no cache or no data found in the cache - */ -void *fsp_prepare_mrc_cache(void); - /** * fsp_notify() - FSP notification wrapper function * diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index c1c30ce0eb6..6b7a614e929 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -57,26 +57,6 @@ void board_final_cleanup(void) debug("OK\n"); }
-void *fsp_prepare_mrc_cache(void) -{ - struct mrc_data_container *cache; - struct mrc_region entry; - int ret; - - ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); - if (ret) - return NULL; - - cache = mrccache_find_current(&entry); - if (!cache) - return NULL; - - debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__, - cache->data, cache->data_size, cache->checksum); - - return cache->data; -} - #ifdef CONFIG_HAVE_ACPI_RESUME int fsp_save_s3_stack(void) { diff --git a/arch/x86/lib/fsp1/fsp_common.c b/arch/x86/lib/fsp1/fsp_common.c index e8066d8de39..ec9c218778d 100644 --- a/arch/x86/lib/fsp1/fsp_common.c +++ b/arch/x86/lib/fsp1/fsp_common.c @@ -18,6 +18,26 @@
DECLARE_GLOBAL_DATA_PTR;
+static void *fsp_prepare_mrc_cache(void) +{ + struct mrc_data_container *cache; + struct mrc_region entry; + int ret; + + ret = mrccache_get_region(MRC_TYPE_NORMAL, NULL, &entry); + if (ret) + return NULL; + + cache = mrccache_find_current(&entry); + if (!cache) + return NULL; + + debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__, + cache->data, cache->data_size, cache->checksum); + + return cache->data; +} + int arch_fsp_init(void) { void *nvs;

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This function needs to be different for FSP2, so move the existing function into the fsp1 directory. Since it is only called from one file, drop it from the header file.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/include/asm/fsp/fsp_support.h | 7 ------- arch/x86/lib/fsp/fsp_common.c | 20 -------------------- arch/x86/lib/fsp1/fsp_common.c | 20 ++++++++++++++++++++ 3 files changed, 20 insertions(+), 27 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

At present with fsp a single DRAM bank is added which extends to the whole size of memory. However there is typically only 2GB of memory available below the 4GB boundary, and this is what is used by U-Boot while running in 32-bit mode.
Scan the tables to set the banks correct. The first bank is set to memory below 4GB, and the rest of memory is put into subsequent banks.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/fsp/fsp_dram.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)
diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index 38cc25839ec..9161af65b98 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -37,8 +37,38 @@ int fsp_scan_for_ram_size(void)
int dram_init_banksize(void) { + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + phys_addr_t low_end; + uint bank; + + low_end = 0; + for (bank = 1, hdr = gd->arch.hob_list; + bank < CONFIG_NR_DRAM_BANKS && !end_of_hob(hdr); + hdr = get_next_hob(hdr)) { + if (hdr->type != HOB_TYPE_RES_DESC) + continue; + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type != RES_SYS_MEM && + res_desc->type != RES_MEM_RESERVED) + continue; + if (res_desc->phys_start < (1ULL << 32)) { + low_end = max(low_end, + res_desc->phys_start + res_desc->len); + continue; + } + + gd->bd->bi_dram[bank].start = res_desc->phys_start; + gd->bd->bi_dram[bank].size = res_desc->len; + mtrr_add_request(MTRR_TYPE_WRBACK, res_desc->phys_start, + res_desc->len); + log_debug("ram %llx %llx\n", gd->bd->bi_dram[bank].start, + gd->bd->bi_dram[bank].size); + } + + /* Add the memory below 4GB */ gd->bd->bi_dram[0].start = 0; - gd->bd->bi_dram[0].size = gd->ram_size; + gd->bd->bi_dram[0].size = low_end;
return 0; }

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
At present with fsp a single DRAM bank is added which extends to the whole size of memory. However there is typically only 2GB of memory available below the 4GB boundary, and this is what is used by U-Boot while running in 32-bit mode.
Scan the tables to set the banks correct. The first bank is set to memory below 4GB, and the rest of memory is put into subsequent banks.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/fsp/fsp_dram.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

Set up MTRRs for the FST SDRAM regions to improve performance.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/fsp/fsp_dram.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index 9161af65b98..4a87516f422 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -8,6 +8,7 @@ #include <asm/fsp/fsp_support.h> #include <asm/e820.h> #include <asm/mrccache.h> +#include <asm/mtrr.h> #include <asm/post.h>
DECLARE_GLOBAL_DATA_PTR; @@ -70,6 +71,8 @@ int dram_init_banksize(void) gd->bd->bi_dram[0].start = 0; gd->bd->bi_dram[0].size = low_end;
+ mtrr_add_request(MTRR_TYPE_WRBACK, 0, low_end); + return 0; }

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Set up MTRRs for the FST SDRAM regions to improve performance.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/fsp/fsp_dram.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index 9161af65b98..4a87516f422 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -8,6 +8,7 @@ #include <asm/fsp/fsp_support.h> #include <asm/e820.h> #include <asm/mrccache.h> +#include <asm/mtrr.h> #include <asm/post.h>
DECLARE_GLOBAL_DATA_PTR; @@ -70,6 +71,8 @@ int dram_init_banksize(void) gd->bd->bi_dram[0].start = 0; gd->bd->bi_dram[0].size = low_end;
mtrr_add_request(MTRR_TYPE_WRBACK, 0, low_end);
I suspect we don't need explicit MTRR configuration. I see on the FSP 1.0 boards, MTRR is already programmed by FSP.
But I am fine adding this. So if we are adding this MTRR, please also move MTRR programming from previous patch ([088/126] x86: Set the DRAM banks to reflect real location) to this patch.
return 0;
Regards, Bin

Hi Bin,
On Thu, 10 Oct 2019 at 03:19, Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Set up MTRRs for the FST SDRAM regions to improve performance.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/fsp/fsp_dram.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index 9161af65b98..4a87516f422 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -8,6 +8,7 @@ #include <asm/fsp/fsp_support.h> #include <asm/e820.h> #include <asm/mrccache.h> +#include <asm/mtrr.h> #include <asm/post.h>
DECLARE_GLOBAL_DATA_PTR; @@ -70,6 +71,8 @@ int dram_init_banksize(void) gd->bd->bi_dram[0].start = 0; gd->bd->bi_dram[0].size = low_end;
mtrr_add_request(MTRR_TYPE_WRBACK, 0, low_end);
I suspect we don't need explicit MTRR configuration. I see on the FSP 1.0 boards, MTRR is already programmed by FSP.
But I am fine adding this. So if we are adding this MTRR, please also move MTRR programming from previous patch ([088/126] x86: Set the DRAM banks to reflect real location) to this patch.
The FSP does not seem to do this. However I wonder if I need to check the version of my FSP.
Regards, Simon

Many of the Kconfig options do not apply to FSP2. Update them to use the FSP_VERSION1 condition instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 47bf28c434f..0de3f6ed7da 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -397,7 +397,7 @@ endchoice
config FSP_FILE string "Firmware Support Package binary filename" - depends on HAVE_FSP + depends on FSP_VERSION1 default "fsp.bin" help The filename of the file to use as Firmware Support Package binary @@ -405,7 +405,7 @@ config FSP_FILE
config FSP_ADDR hex "Firmware Support Package binary location" - depends on HAVE_FSP + depends on FSP_VERSION1 default 0xfffc0000 help FSP is not Position Independent Code (PIC) and the whole FSP has to @@ -418,7 +418,7 @@ config FSP_ADDR
config FSP_TEMP_RAM_ADDR hex - depends on HAVE_FSP + depends on FSP_VERSION1 default 0x2000000 help Stack top address which is used in fsp_init() after DRAM is ready and @@ -426,14 +426,14 @@ config FSP_TEMP_RAM_ADDR
config FSP_SYS_MALLOC_F_LEN hex - depends on HAVE_FSP + depends on FSP_VERSION1 default 0x100000 help Additional size of malloc() pool before relocation.
config FSP_USE_UPD bool - depends on HAVE_FSP + depends on FSP_VERSION1 default y help Most FSPs use UPD data region for some FSP customization. But there @@ -442,7 +442,7 @@ config FSP_USE_UPD
config FSP_BROKEN_HOB bool - depends on HAVE_FSP + depends on FSP_VERSION1 help Indicate some buggy FSPs that does not report memory used by FSP itself as reserved in the resource descriptor HOB. Select this to @@ -600,7 +600,7 @@ config VGA_BIOS_ADDR
config HAVE_VBT bool "Add a Video BIOS Table (VBT) image" - depends on HAVE_FSP + depends on FSP_VERSION1 help Select this option if you have a Video BIOS Table (VBT) image that you would like to add to your ROM. This is normally required if you

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Many of the Kconfig options do not apply to FSP2. Update them to use the FSP_VERSION1 condition instead.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 10, 2019 at 5:19 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Many of the Kconfig options do not apply to FSP2. Update them to use the FSP_VERSION1 condition instead.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!

This option pulls in libfdt and therefore precludes getting the full code-size savings of op-platdata. Drop it since it will be enabled anyway if needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/Kconfig | 1 - 1 file changed, 1 deletion(-)
diff --git a/arch/Kconfig b/arch/Kconfig index 0374139fa89..b6f244d7c1b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -203,7 +203,6 @@ config X86 imply SPL_SYSCON # TPL imply TPL_DM - imply TPL_OF_LIBFDT imply TPL_DRIVERS_MISC_SUPPORT imply TPL_GPIO_SUPPORT imply TPL_LIBCOMMON_SUPPORT

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This option pulls in libfdt and therefore precludes getting the full code-size savings of op-platdata. Drop it since it will be enabled anyway if needed.
Signed-off-by: Simon Glass sjg@chromium.org
arch/Kconfig | 1 - 1 file changed, 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
But let's wait for custodians to reach an agreement of SPL / TPL boot order.
Regards, Bin

These drivers are not needed on all platforms. While they are small, it is useful in TPL to drop then. Add Kconfig control to allow this.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/pch/Kconfig | 18 ++++++++++++++++++ drivers/pch/Makefile | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/pch/Kconfig b/drivers/pch/Kconfig index 18f006de24c..a02a1b857cc 100644 --- a/drivers/pch/Kconfig +++ b/drivers/pch/Kconfig @@ -7,3 +7,21 @@ config PCH northbridge / southbridge architecture that was previously used. The PCH allows for higher performance since the memory functions are handled in the CPU. + +config X86_PCH7 + bool "Add support for Intel PCH7" + default y if X86 + help + Enable this if your SoC uses Platform Controller Hub 7 (PCH7). This + dates from about 2011 and is used on queensbay, for example. The + PCH proides access to the GPIO and SPI base addresses, among other + functions. + +config X86_PCH9 + bool "Add support for Intel PCH9" + default y if X86 + help + Enable this if your SoC uses Platform Controller Hub 9 (PCH9). This + dates from about 2015 and is used on queensbay, for example. The + PCH proides access to the GPIO and SPI base addresses, among other + functions. diff --git a/drivers/pch/Makefile b/drivers/pch/Makefile index 8ea6b7852ac..d5de3e48be1 100644 --- a/drivers/pch/Makefile +++ b/drivers/pch/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+
obj-y += pch-uclass.o -obj-y += pch7.o -obj-y += pch9.o +obj-$(CONFIG_X86_PCH7) += pch7.o +obj-$(CONFIG_X86_PCH9) += pch9.o obj-$(CONFIG_SANDBOX) += sandbox_pch.o

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
These drivers are not needed on all platforms. While they are small, it is useful in TPL to drop then. Add Kconfig control to allow this.
Signed-off-by: Simon Glass sjg@chromium.org
drivers/pch/Kconfig | 18 ++++++++++++++++++ drivers/pch/Makefile | 4 ++-- 2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/drivers/pch/Kconfig b/drivers/pch/Kconfig index 18f006de24c..a02a1b857cc 100644 --- a/drivers/pch/Kconfig +++ b/drivers/pch/Kconfig @@ -7,3 +7,21 @@ config PCH northbridge / southbridge architecture that was previously used. The PCH allows for higher performance since the memory functions are handled in the CPU.
+config X86_PCH7
bool "Add support for Intel PCH7"
default y if X86
help
Enable this if your SoC uses Platform Controller Hub 7 (PCH7). This
dates from about 2011 and is used on queensbay, for example. The
PCH proides access to the GPIO and SPI base addresses, among other
typo: provides
functions.
+config X86_PCH9
bool "Add support for Intel PCH9"
default y if X86
help
Enable this if your SoC uses Platform Controller Hub 9 (PCH9). This
dates from about 2015 and is used on queensbay, for example. The
used on baytrail, I think
PCH proides access to the GPIO and SPI base addresses, among other
typo: provides
functions.
diff --git a/drivers/pch/Makefile b/drivers/pch/Makefile index 8ea6b7852ac..d5de3e48be1 100644 --- a/drivers/pch/Makefile +++ b/drivers/pch/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0+
obj-y += pch-uclass.o -obj-y += pch7.o -obj-y += pch9.o +obj-$(CONFIG_X86_PCH7) += pch7.o +obj-$(CONFIG_X86_PCH9) += pch9.o obj-$(CONFIG_SANDBOX) += sandbox_pch.o --
Other than above, Reviewed-by: Bin Meng bmeng.cn@gmail.com

At present the interrupt table is included in all phases of U-Boot. Allow it to be omitted, e.g. in TPL, to reduce size.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 6296b55ff8a..b6a010ea320 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -53,7 +53,7 @@ obj-$(CONFIG_INTEL_QUARK) += quark/ obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/ obj-$(CONFIG_INTEL_TANGIER) += tangier/ obj-$(CONFIG_APIC) += lapic.o ioapic.o -obj-y += irq.o +obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += irq.o ifndef CONFIG_$(SPL_)X86_64 obj-$(CONFIG_SMP) += mp_init.o endif

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
At present the interrupt table is included in all phases of U-Boot. Allow it to be omitted, e.g. in TPL, to reduce size.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 10, 2019 at 5:26 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
At present the interrupt table is included in all phases of U-Boot. Allow it to be omitted, e.g. in TPL, to reduce size.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!

Hi Simon,
On Fri, Oct 11, 2019 at 4:35 PM Bin Meng bmeng.cn@gmail.com wrote:
On Thu, Oct 10, 2019 at 5:26 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
At present the interrupt table is included in all phases of U-Boot. Allow it to be omitted, e.g. in TPL, to reduce size.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!
This unfortunately breaks qemu-x86_64_defconfig.
06: x86: Allow interrupt to happen once x86: + qemu-x86_64 +arch/x86/lib/built-in.o:build/../arch/x86/lib/tables.c:22: undefined reference to `write_pirq_routing_table' +make[1]: *** [u-boot] Error 1 +make: *** [sub-make] Error 2
I will have to drop this patch from my queue.
Regards, Bin

Add support for some important configuration options and FSP memory init. The memory init uses swizzle tables from the device tree.
Note that support for the FSP_S binary is not yet included.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/Kconfig | 41 ++- arch/x86/include/asm/fsp2/fsp_api.h | 38 +++ arch/x86/include/asm/fsp2/fsp_internal.h | 16 ++ arch/x86/lib/fsp2/Makefile | 7 + arch/x86/lib/fsp2/fsp_dram.c | 73 +++++ arch/x86/lib/fsp2/fsp_meminit.c | 344 +++++++++++++++++++++++ arch/x86/lib/fsp2/fsp_support.c | 109 +++++++ 7 files changed, 627 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/fsp2/fsp_api.h create mode 100644 arch/x86/include/asm/fsp2/fsp_internal.h create mode 100644 arch/x86/lib/fsp2/Makefile create mode 100644 arch/x86/lib/fsp2/fsp_dram.c create mode 100644 arch/x86/lib/fsp2/fsp_meminit.c create mode 100644 arch/x86/lib/fsp2/fsp_support.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 0de3f6ed7da..49b5f0f4ebd 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -331,7 +331,7 @@ config X86_RAMTEST
config FLASH_DESCRIPTOR_FILE string "Flash descriptor binary filename" - depends on HAVE_INTEL_ME + depends on HAVE_INTEL_ME || FSP_VERSION2 default "descriptor.bin" help The filename of the file to use as flash descriptor in the @@ -416,6 +416,45 @@ config FSP_ADDR The default base address of 0xfffc0000 indicates that the binary must be located at offset 0xc0000 from the beginning of a 1MB flash device.
+if FSP_VERSION2 + +config FSP_FILE_T + string "Firmware-Support-Package binary filename (Temp RAM)" + default "fsp_t.bin" + help + The filename of the file to use for the temporary-RAM init phase from + the Firmware-Support-Package binary. Put this in the board directory. + It is used to set up an initial area of RAM which can be used for the + stack and other purposes, while bringing up the main system DRAM. + +config FSP_ADDR_T + hex "Firmware-Support-Package binary location (Temp RAM)" + default 0xffff8000 + help + FSP is not Position-Independent Code (PIC) and FSP components have to + be rebased if placed at a location which is different from the + perferred base address specified during the FSP build. Use Intel's + Binary Configuration Tool (BCT) to do the rebase. + +config FSP_FILE_M + string "Firmware-Support-Package binary filename (Memory Init)" + default "fsp_m.bin" + help + The filename of the file to use for the RAM init phase from the + Firmware Support Package binary. Put this in the board directory. + It is used to set up an initial area of RAM which can be used for the + stack and other purposes, while bringing up the main system DRAM. + +config IFWI_INPUT_FILE + string "Filename containing FIT (Firmware Interface Table) with IFWI" + default "fitimage.bin" + help + The IFWI is obtained by running a tool on this file to extract the + IFWI. Put this in the board directory. The IFWI contains U-Boot TPL, + microcode and other internal items. + +endif + config FSP_TEMP_RAM_ADDR hex depends on FSP_VERSION1 diff --git a/arch/x86/include/asm/fsp2/fsp_api.h b/arch/x86/include/asm/fsp2/fsp_api.h new file mode 100644 index 00000000000..3e41ecbede8 --- /dev/null +++ b/arch/x86/include/asm/fsp2/fsp_api.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@intel.com for Intel Corp.) + * (Written by Alexandru Gagniuc alexandrux.gagniuc@intel.com for Intel Corp.) + * Mostly taken from coreboot fsp2_0/memory_init.c + */ + +#ifndef __ASM_FSP_API_H +#define __ASM_FSP_API_H + +struct fspm_upd; +struct hob_header; + +enum fsp_boot_mode { + FSP_BOOT_WITH_FULL_CONFIGURATION = 0x00, + FSP_BOOT_WITH_MINIMAL_CONFIGURATION = 0x01, + FSP_BOOT_ASSUMING_NO_CONFIGURATION_CHANGES = 0x02, + FSP_BOOT_ON_S4_RESUME = 0x05, + FSP_BOOT_ON_S3_RESUME = 0x11, + FSP_BOOT_ON_FLASH_UPDATE = 0x12, + FSP_BOOT_IN_RECOVERY_MODE = 0x20 +}; + +/** + * fsp_memory_init() - Init the SDRAM + * + * @s3wake: true if we are booting from resume, so cannot reinit the mememory + * from scatch since we will lose its contents + * @use_spi_flash: true to use the fast SPI driver to read FSP, otherwise use + * mapped SPI + */ +int fsp_memory_init(bool s3wake, bool use_spi_flash); + +typedef asmlinkage int (*fsp_memory_init_func)(struct fspm_upd *params, + struct hob_header **hobp); + +#endif diff --git a/arch/x86/include/asm/fsp2/fsp_internal.h b/arch/x86/include/asm/fsp2/fsp_internal.h new file mode 100644 index 00000000000..c69c90a931d --- /dev/null +++ b/arch/x86/include/asm/fsp2/fsp_internal.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Alexandru Gagniuc alexandrux.gagniuc@intel.com for Intel Corp.) + * Mostly taken from coreboot + */ + +#ifndef __ASM_FSP_INTERNAL_H +#define __ASM_FSP_INTERNAL_H + +struct fsp_header; + +int fsp_get_header(ulong offset, ulong size, bool use_spi_flash, + struct fsp_header **fspp, ulong *basep); + +#endif diff --git a/arch/x86/lib/fsp2/Makefile b/arch/x86/lib/fsp2/Makefile new file mode 100644 index 00000000000..e56e63a1094 --- /dev/null +++ b/arch/x86/lib/fsp2/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2019 Google LLC + +obj-y += fsp_dram.o +obj-y += fsp_meminit.o +obj-y += fsp_support.o diff --git a/arch/x86/lib/fsp2/fsp_dram.c b/arch/x86/lib/fsp2/fsp_dram.c new file mode 100644 index 00000000000..7f74cfa63fd --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_dram.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <acpi_s3.h> +#include <handoff.h> +#include <spl.h> +#include <asm/arch/cpu.h> +#include <asm/fsp/fsp_support.h> +#include <asm/fsp2/fsp_api.h> + +int dram_init(void) +{ + int ret; + + if (spl_phase() == PHASE_SPL) { +#ifdef CONFIG_HAVE_ACPI_RESUME + bool s3wake = gd->arch.prev_sleep_state == ACPI_S3; +#else + bool s3wake = false; +#endif + + ret = fsp_memory_init(s3wake, BOOT_FROM_FAST_SPI_FLASH); + if (ret) { + debug("Memory init failed (err=%x)\n", ret); + return ret; + } + + /* The FSP has already set up DRAM, so grab the info we need */ + ret = fsp_scan_for_ram_size(); + if (ret) + return ret; + +#ifdef CONFIG_ENABLE_MRC_CACHE + gd->arch.mrc[MRC_TYPE_NORMAL].buf = + fsp_get_nvs_data(gd->arch.hob_list, + &gd->arch.mrc[MRC_TYPE_NORMAL].len); + gd->arch.mrc[MRC_TYPE_VAR].buf = + fsp_get_var_nvs_data(gd->arch.hob_list, + &gd->arch.mrc[MRC_TYPE_VAR].len); + log_debug("normal %x, var %x\n", + gd->arch.mrc[MRC_TYPE_NORMAL].len, + gd->arch.mrc[MRC_TYPE_VAR].len); +#endif + } else { +#if CONFIG_IS_ENABLED(HANDOFF) + struct spl_handoff *ho = gd->spl_handoff; + + if (!ho) { + debug("No SPL handoff found\n"); + return -ESTRPIPE; + } + gd->ram_size = ho->ram_size; + handoff_load_dram_banks(ho); +#endif + } + + return 0; +} + +ulong board_get_usable_ram_top(ulong total_size) +{ +#if CONFIG_IS_ENABLED(HANDOFF) + struct spl_handoff *ho = gd->spl_handoff; + + return ho->arch.usable_ram_top; +#endif + + return gd->ram_top; +} diff --git a/arch/x86/lib/fsp2/fsp_meminit.c b/arch/x86/lib/fsp2/fsp_meminit.c new file mode 100644 index 00000000000..9eaa565c4a0 --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_meminit.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: Intel +/* + * Copyright (C) 2015-2016 Intel Corp. + * (Written by Andrey Petrov andrey.petrov@intel.com for Intel Corp.) + * (Written by Alexandru Gagniuc alexandrux.gagniuc@intel.com for Intel Corp.) + * Mostly taken from coreboot fsp2_0/memory_init.c + */ + +#include <common.h> +#include <binman_sym.h> +#include <cbfs.h> +#include <dm.h> +#include <spi_flash.h> +#include <asm/mrccache.h> +#include <asm/hob.h> +#include <asm/fsp/fsp_infoheader.h> +#include <asm/fsp2/fsp_api.h> +#include <asm/fsp2/fsp_internal.h> +#include <asm/arch/fsp/fsp_configs.h> +#include <asm/arch/fsp/fsp_m_upd.h> + +binman_sym_declare(ulong, intel_fsp_m, image_pos); +binman_sym_declare(ulong, intel_fsp_m, size); + +/* + * ODT settings: + * If ODT PIN to LP4 DRAM is pulled HIGH for ODT_A and HIGH for ODT_B, + * choose ODT_A_B_HIGH_HIGH. If ODT PIN to LP4 DRAM is pulled HIGH for ODT_A + * and LOW for ODT_B, choose ODT_A_B_HIGH_LOW. + * + * Note that the enum values correspond to the interpreted UPD fields + * within Ch[3:0]_OdtConfig parameters. + */ +enum { + ODT_A_B_HIGH_LOW = 0 << 1, + ODT_A_B_HIGH_HIGH = 1 << 1, + N_WR_24 = 1 << 5, +}; + +/* + * LPDDR4 helper routines for configuring the memory UPD for LPDDR4 operation. + * There are four physical LPDDR4 channels, each 32-bits wide. There are two + * logical channels using two physical channels together to form a 64-bit + * interface to memory for each logical channel. + */ + +enum { + LP4_PHYS_CH0A, + LP4_PHYS_CH0B, + LP4_PHYS_CH1A, + LP4_PHYS_CH1B, + + LP4_NUM_PHYS_CHANNELS, +}; + +/* + * The DQs within a physical channel can be bit-swizzled within each byte. + * Within a channel the bytes can be swapped, but the DQs need to be routed + * with the corresponding DQS (strobe). + */ +enum { + LP4_DQS0, + LP4_DQS1, + LP4_DQS2, + LP4_DQS3, + + LP4_NUM_BYTE_LANES, + DQ_BITS_PER_DQS = 8, +}; + +/* Provide bit swizzling per DQS and byte swapping within a channel. */ +struct lpddr4_chan_swizzle_cfg { + u8 dqs[LP4_NUM_BYTE_LANES][DQ_BITS_PER_DQS]; +}; + +struct lpddr4_swizzle_cfg { + struct lpddr4_chan_swizzle_cfg phys[LP4_NUM_PHYS_CHANNELS]; +}; + +static int prepare_mrc_cache_type(enum mrc_type_t type, + struct mrc_data_container **cachep) +{ + struct mrc_data_container *cache; + struct mrc_region entry; + int ret; + + ret = mrccache_get_region(type, NULL, &entry); + if (ret) + return ret; + cache = mrccache_find_current(&entry); + if (!cache) + return -ENOENT; + + log_debug("MRC at %x, size %x\n", (uint)cache->data, cache->data_size); + *cachep = cache; + + return 0; +} + +static int prepare_mrc_cache(struct fspm_upd *upd) +{ + struct mrc_data_container *cache; + int ret; + + ret = prepare_mrc_cache_type(MRC_TYPE_NORMAL, &cache); + if (ret) + return log_msg_ret("Cannot get normal cache", ret); + upd->arch.nvs_buffer_ptr = cache->data; + + ret = prepare_mrc_cache_type(MRC_TYPE_VAR, &cache); + if (ret) + return log_msg_ret("Cannot get var cache", ret); + upd->config.variable_nvs_buffer_ptr = cache->data; + + return 0; +} + +static int get_coreboot_fsp(ulong map_base, ulong *fsp_m_posp, + ulong *fsp_m_sizep) +{ + /* Hard-coded position of CBFS in ROM */ + ulong cbfs_base = 0x205000; + ulong cbfs_size = 0x1bb000; + struct cbfs_priv *cbfs; + int ret; + + ret = cbfs_init_mem(map_base + cbfs_base, cbfs_size, &cbfs); + if (ret) + return ret; + if (!ret) { + const struct cbfs_cachenode *node; + + node = cbfs_find_file(cbfs, "fspm.bin"); + if (!node) { + printf("no node\n"); + return -ENOENT; + } + + *fsp_m_posp = (ulong)node->data; + *fsp_m_sizep = node->data_length; + } + + return 0; +} + +static void setup_sdram(struct fsp_m_config *cfg, + const struct lpddr4_swizzle_cfg *swizzle_cfg) +{ + const struct lpddr4_chan_swizzle_cfg *sch; + /* Number of bytes to copy per DQS. */ + const size_t sz = DQ_BITS_PER_DQS; + int chan; + + cfg->memory_down = 1; + cfg->scrambler_support = 1; + cfg->channel_hash_mask = 0x36; + cfg->slice_hash_mask = 9; + cfg->interleaved_mode = 2; + cfg->channels_slices_enable = 0; + cfg->min_ref_rate2x_enable = 0; + cfg->dual_rank_support_enable = 1; + + /* LPDDR4 is memory down so no SPD addresses. */ + cfg->dimm0_spd_address = 0; + cfg->dimm1_spd_address = 0; + + for (chan = 0; chan < 4; chan++) { + struct fsp_ram_channel *ch = &cfg->chan[chan]; + + ch->rank_enable = 1; + ch->device_width = 1; + ch->dram_density = 2; + ch->option = 3; + ch->odt_config = ODT_A_B_HIGH_HIGH; + } + + /* + * CH0_DQB byte lanes in the bit swizzle configuration field are + * not 1:1. The mapping within the swizzling field is: + * indices [0:7] - byte lane 1 (DQS1) DQ[8:15] + * indices [8:15] - byte lane 0 (DQS0) DQ[0:7] + * indices [16:23] - byte lane 3 (DQS3) DQ[24:31] + * indices [24:31] - byte lane 2 (DQS2) DQ[16:23] + */ + sch = &swizzle_cfg->phys[LP4_PHYS_CH0B]; + memcpy(&cfg->ch_bit_swizzling[0][0], &sch->dqs[LP4_DQS1], sz); + memcpy(&cfg->ch_bit_swizzling[0][8], &sch->dqs[LP4_DQS0], sz); + memcpy(&cfg->ch_bit_swizzling[0][16], &sch->dqs[LP4_DQS3], sz); + memcpy(&cfg->ch_bit_swizzling[0][24], &sch->dqs[LP4_DQS2], sz); + + /* + * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1. + */ + sch = &swizzle_cfg->phys[LP4_PHYS_CH0A]; + memcpy(&cfg->ch_bit_swizzling[1][0], &sch->dqs[LP4_DQS0], sz); + memcpy(&cfg->ch_bit_swizzling[1][8], &sch->dqs[LP4_DQS1], sz); + memcpy(&cfg->ch_bit_swizzling[1][16], &sch->dqs[LP4_DQS2], sz); + memcpy(&cfg->ch_bit_swizzling[1][24], &sch->dqs[LP4_DQS3], sz); + + sch = &swizzle_cfg->phys[LP4_PHYS_CH1B]; + memcpy(&cfg->ch_bit_swizzling[2][0], &sch->dqs[LP4_DQS1], sz); + memcpy(&cfg->ch_bit_swizzling[2][8], &sch->dqs[LP4_DQS0], sz); + memcpy(&cfg->ch_bit_swizzling[2][16], &sch->dqs[LP4_DQS3], sz); + memcpy(&cfg->ch_bit_swizzling[2][24], &sch->dqs[LP4_DQS2], sz); + + /* + * CH0_DQA byte lanes in the bit swizzle configuration field are 1:1. + */ + sch = &swizzle_cfg->phys[LP4_PHYS_CH1A]; + memcpy(&cfg->ch_bit_swizzling[3][0], &sch->dqs[LP4_DQS0], sz); + memcpy(&cfg->ch_bit_swizzling[3][8], &sch->dqs[LP4_DQS1], sz); + memcpy(&cfg->ch_bit_swizzling[3][16], &sch->dqs[LP4_DQS2], sz); + memcpy(&cfg->ch_bit_swizzling[3][24], &sch->dqs[LP4_DQS3], sz); +} + +/** + * setup_config() - Set up the config structure for FSP-M + * + * @dev: Hostbridge device containing config + * @upd: Config data to fill in + * @return 0 if OK, -ve on error + */ +static int setup_config(struct udevice *dev, struct fspm_upd *upd) +{ + struct fsp_m_config *cfg = &upd->config; + struct fspm_arch_upd *arch = &upd->arch; + + arch->nvs_buffer_ptr = NULL; + prepare_mrc_cache(upd); + arch->stack_base = (void *)0xfef96000; + arch->boot_loader_tolum_size = 0x2000; + + arch->boot_mode = FSP_BOOT_WITH_FULL_CONFIGURATION; + cfg->serial_debug_port_type = 2; + cfg->serial_debug_port_device = 2; + cfg->serial_debug_port_stride_size = 2; + cfg->serial_debug_port_address = 0; + + cfg->package = 1; + /* Don't enforce a memory size limit. */ + cfg->memory_size_limit = 0; + cfg->low_memory_max_value = 2048; /* 2 GB */ + /* No restrictions on memory above 4GiB */ + cfg->high_memory_max_value = 0; + + /* Always default to attempt to use saved training data. */ + cfg->disable_fast_boot = 0; + + const u8 *swizzle_data; + + swizzle_data = dev_read_u8_array_ptr(dev, "lpddr4-swizzle", + LP4_NUM_BYTE_LANES * + DQ_BITS_PER_DQS * + LP4_NUM_PHYS_CHANNELS); + if (!swizzle_data) + return log_msg_ret("Cannot read swizzel data", -EINVAL); + + setup_sdram(cfg, (struct lpddr4_swizzle_cfg *)swizzle_data); + + cfg->pre_mem_gpio_table_ptr = 0; + + cfg->profile = 0xb; + cfg->msg_level_mask = 0; + + /* other */ + cfg->skip_cse_rbp = 1; + cfg->periodic_retraining_disable = 0; + cfg->enable_s3_heci2 = 0; + + return 0; +} + +int fsp_memory_init(bool s3wake, bool use_spi_flash) +{ + struct fspm_upd upd, *fsp_upd; + fsp_memory_init_func func; + struct fsp_header *hdr; + struct hob_header *hob; + struct udevice *dev, *sf; + ulong fsp_m_pos = 0; + ulong fsp_m_size = 0; + size_t map_size; + ulong map_base; + ulong base; + u32 offset; + int ret; + + ret = uclass_first_device_err(UCLASS_NORTHBRIDGE, &dev); + if (ret) + return log_msg_ret("Cannot get northbridge", ret); + ret = uclass_first_device_err(UCLASS_SPI_FLASH, &sf); + if (ret) + return log_msg_ret("Cannot get SPI flash", ret); + ret = spi_flash_get_mmap(sf, &map_base, &map_size, &offset); + if (ret) + return log_msg_ret("Could not get flash mmap", ret); + + ret = -ENOENT; + if (false) + /* Support using a hybrid image build by coreboot */ + ret = get_coreboot_fsp(map_base, &fsp_m_pos, &fsp_m_size); + if (ret) { + ulong mask = CONFIG_ROM_SIZE - 1; + + fsp_m_pos = binman_sym(ulong, intel_fsp_m, image_pos); + fsp_m_size = binman_sym(ulong, intel_fsp_m, size); + if (fsp_m_pos != BINMAN_SYM_MISSING) { + ret = 0; + if (use_spi_flash) + fsp_m_pos &= mask; + else + fsp_m_pos += (map_base & mask); + } else { + ret = -ENOENT; + } + } + if (ret) + return log_msg_ret("Cannot find FSP_M", ret); + + /* Use memory-mapped SPI flash by default as it is simpler */ + ret = fsp_get_header(fsp_m_pos, fsp_m_size, use_spi_flash, &hdr, &base); + if (ret) + return log_msg_ret("fsp_get_header", ret); + + /* Copy over the default config */ + fsp_upd = (struct fspm_upd *)(base + hdr->cfg_region_off); + if (fsp_upd->header.signature != FSPM_UPD_SIGNATURE) + return log_msg_ret("Bad UPD signature", -EPERM); + memcpy(&upd, fsp_upd, sizeof(upd)); + + ret = setup_config(dev, &upd); + if (ret) + return log_msg_ret("Could not setup config", ret); + debug("SDRAM init..."); + func = (fsp_memory_init_func)(base + hdr->fsp_mem_init); + ret = func(&upd, &hob); + if (ret) + return log_msg_ret("SDRAM init fail\n", ret); + + gd->arch.hob_list = hob; + debug("done\n"); + + return 0; +} diff --git a/arch/x86/lib/fsp2/fsp_support.c b/arch/x86/lib/fsp2/fsp_support.c new file mode 100644 index 00000000000..b5e75aaf6d4 --- /dev/null +++ b/arch/x86/lib/fsp2/fsp_support.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: Intel +/* + * Copyright 2019 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <common.h> +#include <dm.h> +#include <spi_flash.h> +#include <asm/fsp/fsp_support.h> +#include <asm/fsp2/fsp_internal.h> + +/* The amount of the FSP header to probe to obtain what we need */ +#define PROBE_BUF_SIZE 0x180 + +/* Not needed in SPL apparently */ +#define SAFETY_MARGIN 0 + +int fsp_get_header(ulong offset, ulong size, bool use_spi_flash, + struct fsp_header **fspp, ulong *basep) +{ + static efi_guid_t guid = FSP_HEADER_GUID; + struct fv_ext_header *exhdr; + struct fsp_header *fsp; + struct ffs_file_header *file_hdr; + struct fv_header *fv; + struct raw_section *raw; + void *ptr, *base; + u8 buf[PROBE_BUF_SIZE]; + struct udevice *dev; + int ret; + + /* You are in a maze of twisty headers all alike */ + debug("offset=%x buf=%x\n", (uint)offset, (uint)buf); + if (use_spi_flash) { + ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev); + if (ret) + return log_msg_ret("Cannot find flash device", ret); + ret = spi_flash_read_dm(dev, offset, PROBE_BUF_SIZE, buf); + if (ret) + return log_msg_ret("Cannot read flash", ret); + } else { + memcpy(buf, (void *)offset, PROBE_BUF_SIZE); + } + + /* Initalise the FSP base */ + ptr = buf; + fv = ptr; + + /* Check the FV signature, _FVH */ + debug("offset=%x sign=%x\n", (uint)offset, (uint)fv->sign); + if (fv->sign != EFI_FVH_SIGNATURE) + return log_msg_ret("Base FV signature", -EINVAL); + + /* Go to the end of the FV header and align the address */ + debug("fv->ext_hdr_off = %x\n", fv->ext_hdr_off); + ptr += fv->ext_hdr_off; + exhdr = ptr; + ptr += ALIGN(exhdr->ext_hdr_size, 8); + debug("ptr=%x\n", ptr - (void *)buf); + + /* Check the FFS GUID */ + file_hdr = ptr; + if (memcmp(&file_hdr->name, &guid, sizeof(guid))) + return log_msg_ret("Base FFS GUID", -ENXIO); + /* Add the FFS header size to find the raw section header */ + ptr = file_hdr + 1; + + raw = ptr; + debug("raw->type = %x\n", raw->type); + if (raw->type != EFI_SECTION_RAW) + return log_msg_ret("Section type not RAW", -ENOEXEC); + + /* Add the raw section header size to find the FSP header */ + ptr = raw + 1; + fsp = ptr; + + /* Check the FSPH header */ + debug("fsp %x\n", (uint)fsp); + if (fsp->sign != EFI_FSPH_SIGNATURE) + return log_msg_ret("Base FSPH signature", -EACCES); + + base = (void *)fsp->img_base; + debug("Image base %x\n", (uint)base); + debug("Image addr %x\n", (uint)fsp->fsp_mem_init); + if (use_spi_flash) { + ret = spi_flash_read_dm(dev, offset, size + SAFETY_MARGIN, + base); + if (ret) + return log_msg_ret("Could not read FPS-M", ret); + } else { + memcpy(base, (void *)offset, size + SAFETY_MARGIN); + } + ptr = base + (ptr - (void *)buf); + *fspp = ptr; + *basep = fsp->img_base; + + return 0; +} + +int arch_fsp_init(void) +{ + return 0; +} + +u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase) +{ + return 0; +}

We don't generally have enough space to run this, so don't build it into TPL. This helps reduce the size of TPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/Makefile | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index ca0ca1066b0..5cd45874803 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -4,9 +4,11 @@ # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
ifndef CONFIG_X86_64 +ifndef CONFIG_TPL_BUILD obj-y += bios.o obj-y += bios_asm.o obj-y += bios_interrupts.o +endif obj-y += string.o endif ifndef CONFIG_SPL_BUILD

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
We don't generally have enough space to run this, so don't build it into TPL. This helps reduce the size of TPL.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/Makefile | 2 ++ 1 file changed, 2 insertions(+)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
Again, we will need clarify the ordering issue before applying.

Many Intel SoCs require a FIT in order to boot properly. Add an option to include this and enable it by default.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/Kconfig | 9 +++++++++ arch/x86/dts/u-boot.dtsi | 6 ++++++ 2 files changed, 15 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 49b5f0f4ebd..556e26080de 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -222,6 +222,15 @@ config SYS_X86_START16 depends on X86_RESET_VECTOR default 0xfffff800
+config X86_HAS_FIT + bool + default y + help + Enable inclusion of an Intel Firmware Interface Table (FIT) into the + image. This table is supposed to point to microcode and the like. So + far it is just a fixed table with the minimum set of headers, so that + it is actually present. + config X86_LOAD_FROM_32_BIT bool "Boot from a 32-bit program" help diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 0e87b88e105..049f47c9ffd 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -82,6 +82,12 @@ u-boot-ucode { align = <16>; }; +#ifdef CONFIG_X86_HAS_FIT + intel-fit { + }; + intel-fit-ptr { + }; +#endif #ifdef CONFIG_HAVE_MRC intel-mrc { offset = <CONFIG_X86_MRC_ADDR>;

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Many Intel SoCs require a FIT in order to boot properly. Add an option to include this and enable it by default.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/Kconfig | 9 +++++++++ arch/x86/dts/u-boot.dtsi | 6 ++++++ 2 files changed, 15 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 49b5f0f4ebd..556e26080de 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -222,6 +222,15 @@ config SYS_X86_START16 depends on X86_RESET_VECTOR default 0xfffff800
+config X86_HAS_FIT
bool
Please include a string to describe the option.
default y
This should not be y. Instead let's imply it in the SoC Kconfig file.
help
Enable inclusion of an Intel Firmware Interface Table (FIT) into the
image. This table is supposed to point to microcode and the like. So
far it is just a fixed table with the minimum set of headers, so that
it is actually present.
config X86_LOAD_FROM_32_BIT bool "Boot from a 32-bit program" help diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 0e87b88e105..049f47c9ffd 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -82,6 +82,12 @@ u-boot-ucode { align = <16>; }; +#ifdef CONFIG_X86_HAS_FIT
intel-fit {
};
intel-fit-ptr {
};
+#endif #ifdef CONFIG_HAVE_MRC intel-mrc { offset = <CONFIG_X86_MRC_ADDR>; --
Regards, Bin

Newer Intel SoCs have different ways of setting up cache-as-ram (CAR). Add support for these along with suitable configuration options.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/Kconfig | 16 + arch/x86/cpu/intel_common/Kconfig | 18 + arch/x86/cpu/intel_common/Makefile | 8 + arch/x86/cpu/intel_common/car2.S | 490 ++++++++++++++++++++++++ arch/x86/cpu/intel_common/car2_uninit.S | 87 +++++ 5 files changed, 619 insertions(+) create mode 100644 arch/x86/cpu/intel_common/Kconfig create mode 100644 arch/x86/cpu/intel_common/car2.S create mode 100644 arch/x86/cpu/intel_common/car2_uninit.S
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 556e26080de..e34c71ec4cb 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -876,4 +876,20 @@ config HIGH_TABLE_SIZE Increse it if the default size does not fit the board's needs. This is most likely due to a large ACPI DSDT table is used.
+config INTEL_CAR_CQOS + bool "Support Intel Cache Quality of Service" + help + Cache Quality of Service allows more fine-grained control of cache + usage. As result, it is possible to set up a portion of L2 cache for + CAR and use the remainder for actual caching. + +# +# Each bit in QOS mask controls this many bytes. This is calculated as: +# (CACHE_WAYS / CACHE_BITS_PER_MASK) * CACHE_LINE_SIZE * CACHE_SETS +# +config CACHE_QOS_SIZE_PER_BIT + hex + depends on INTEL_CAR_CQOS + default 0x20000 # 128 KB + endmenu diff --git a/arch/x86/cpu/intel_common/Kconfig b/arch/x86/cpu/intel_common/Kconfig new file mode 100644 index 00000000000..a4f46b1108b --- /dev/null +++ b/arch/x86/cpu/intel_common/Kconfig @@ -0,0 +1,18 @@ +config INTEL_PMC + bool "Intel Power-management Controller" + select POWER_MGR + help + Enable support for the common Intel power-management controller which + provides features including checking whether the system started from + resume, powering off the system and enabling/disabling the reset + mechanism. + +config SPL_INTEL_PMC + bool "Intel Power-management Controller in SPL" + default y if SPL && INTEL_PMC + select SPL_POWER_MGR + help + Enable support for the common Intel power-management controller which + provides features including checking whether the system started from + resume, powering off the system and enabling/disabling the reset + mechanism. diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 2de567dd9fe..f620747a7d2 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -8,6 +8,14 @@ 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 + +ifdef CONFIG_FSP_VERSION2 +obj-$(CONFIG_TPL_BUILD) += car2.o +ifndef CONFIG_SPL_BUILD +obj-y += car2_uninit.o +endif +endif + obj-y += cpu.o obj-$(CONFIG_SPI_FLASH_INTEL_FAST) += fast_spi.o obj-y += lpc.o diff --git a/arch/x86/cpu/intel_common/car2.S b/arch/x86/cpu/intel_common/car2.S new file mode 100644 index 00000000000..ac07fe5ea6a --- /dev/null +++ b/arch/x86/cpu/intel_common/car2.S @@ -0,0 +1,490 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015-2016 Intel Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <config.h> +#include <asm/msr-index.h> +#include <asm/mtrr.h> +#include <asm/post.h> +#include <asm/processor-flags.h> + +#define KiB 1024 + +.global car_init +car_init: + post_code(0x20) + + /* + * Use the MTRR default type MSR as a proxy for detecting INIT#. + * Reset the system if any known bits are set in that MSR. That is + * an indication of the CPU not being properly reset. + */ +check_for_clean_reset: + mov $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + and $(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN), %eax + cmp $0, %eax + jz no_reset + /* perform warm reset */ + movw $0xcf9, %dx + movb $0x06, %al + outb %al, %dx + +no_reset: + post_code(0x21) + + /* Clear/disable fixed MTRRs */ + mov $fixed_mtrr_list_size, %ebx + xor %eax, %eax + xor %edx, %edx + +clear_fixed_mtrr: + add $-2, %ebx + movzwl fixed_mtrr_list(%ebx), %ecx + wrmsr + jnz clear_fixed_mtrr + + post_code(0x22) + + /* Figure put how many MTRRs we have, and clear them out */ + mov $MTRR_CAP_MSR, %ecx + rdmsr + movzb %al, %ebx /* Number of variable MTRRs */ + mov $MTRR_PHYS_BASE_MSR(0), %ecx + xor %eax, %eax + xor %edx, %edx + +clear_var_mtrr: + wrmsr + inc %ecx + wrmsr + inc %ecx + dec %ebx + jnz clear_var_mtrr + + post_code(0x23) + + /* Configure default memory type to uncacheable (UC) */ + mov $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + /* Clear enable bits and set default type to UC. */ + and $~(MTRR_DEF_TYPE_MASK | MTRR_DEF_TYPE_EN | \ + MTRR_DEF_TYPE_FIX_EN), %eax + wrmsr + + /* Configure MTRR_PHYS_MASK_HIGH for proper addressing above 4GB + * based on the physical address size supported for this processor + * This is based on read from CPUID EAX = 080000008h, EAX bits [7:0] + * + * Examples: + * MTRR_PHYS_MASK_HIGH = 00000000Fh For 36 bit addressing + * MTRR_PHYS_MASK_HIGH = 0000000FFh For 40 bit addressing + */ + + movl $0x80000008, %eax /* Address sizes leaf */ + cpuid + sub $32, %al + movzx %al, %eax + xorl %esi, %esi + bts %eax, %esi + dec %esi /* esi <- MTRR_PHYS_MASK_HIGH */ + + post_code(0x24) + +#if ((CONFIG_DCACHE_RAM_SIZE & (CONFIG_DCACHE_RAM_SIZE - 1)) == 0) + /* Configure CAR region as write-back (WB) */ + mov $MTRR_PHYS_BASE_MSR(0), %ecx + mov $CONFIG_DCACHE_RAM_BASE, %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + /* Configure the MTRR mask for the size region */ + mov $MTRR_PHYS_MASK(0), %ecx + mov $CONFIG_DCACHE_RAM_SIZE, %eax /* size mask */ + dec %eax + not %eax + or $MTRR_PHYS_MASK_VALID, %eax + movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */ + wrmsr +#elif (CONFIG_DCACHE_RAM_SIZE == 768 * KiB) /* 768 KiB */ + /* Configure CAR region as write-back (WB) */ + mov $MTRR_PHYS_BASE_MSR(0), %ecx + mov $CONFIG_DCACHE_RAM_BASE, %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + mov $MTRR_PHYS_MASK_MSR(0), %ecx + mov $(512 * KiB), %eax /* size mask */ + dec %eax + not %eax + or $MTRR_PHYS_MASK_VALID, %eax + movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */ + wrmsr + + mov $MTRR_PHYS_BASE_MSR(1), %ecx + mov $(CONFIG_DCACHE_RAM_BASE + 512 * KiB), %eax + or $MTRR_TYPE_WRBACK, %eax + xor %edx,%edx + wrmsr + + mov $MTRR_PHYS_MASK_MSR(1), %ecx + mov $(256 * KiB), %eax /* size mask */ + dec %eax + not %eax + or $MTRR_PHYS_MASK_VALID, %eax + movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */ + wrmsr +#else +#error "DCACHE_RAM_SIZE is not a power of 2 and setup code is missing" +#endif + post_code(0x25) + + /* start */ +/* mov $0xffff80a8, %ebx */ +/* jmp *%ebx */ +.globl _from_bb +_from_bb: +/* jmp car_init_ret */ + /* end */ + + /* Enable variable MTRRs */ + mov $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + or $MTRR_DEF_TYPE_EN, %eax + wrmsr + + /* Enable caching */ + mov %cr0, %eax + and $~(X86_CR0_CD | X86_CR0_NW), %eax + invd + mov %eax, %cr0 + +#if IS_ENABLED(CONFIG_INTEL_CAR_NEM) + jmp car_nem +#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS) + jmp car_cqos +#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED) + jmp car_nem_enhanced +#else +#error "No CAR mechanism selected: +#endif + jmp car_init_ret + +#if 0 +.global car_init_done +car_init_done: + + post_code(0x29) + + /* Setup bootblock stack */ + mov $_car_stack_end, %esp + + /* Need to align stack to 16 bytes at call instruction. Account for + the two pushes below. */ + andl $0xfffffff0, %esp + sub $8, %esp + + /*push TSC value to stack*/ + movd %mm2, %eax + pushl %eax /* tsc[63:32] */ + movd %mm1, %eax + pushl %eax /* tsc[31:0] */ + +before_carstage: + post_code(0x2A) + + call bootblock_c_entry + /* Never reached */ +#endif + +fixed_mtrr_list: + .word MTRR_FIX_64K_00000_MSR + .word MTRR_FIX_16K_80000_MSR + .word MTRR_FIX_16K_A0000_MSR + .word MTRR_FIX_4K_C0000_MSR + .word MTRR_FIX_4K_C8000_MSR + .word MTRR_FIX_4K_D0000_MSR + .word MTRR_FIX_4K_D8000_MSR + .word MTRR_FIX_4K_E0000_MSR + .word MTRR_FIX_4K_E8000_MSR + .word MTRR_FIX_4K_F0000_MSR + .word MTRR_FIX_4K_F8000_MSR +fixed_mtrr_list_size = . - fixed_mtrr_list + +#if IS_ENABLED(CONFIG_INTEL_CAR_NEM) +.global car_nem +car_nem: + /* Disable cache eviction (setup stage) */ + mov $MSR_EVICT_CTL, %ecx + rdmsr + or $0x1, %eax + wrmsr + + post_code(0x26) + + /* Clear the cache memory region. This will also fill up the cache */ + movl $CONFIG_DCACHE_RAM_BASE, %edi + movl $CONFIG_DCACHE_RAM_SIZE, %ecx + shr $0x02, %ecx + xor %eax, %eax + cld + rep stosl + + post_code(0x27) + + /* Disable cache eviction (run stage) */ + mov $MSR_EVICT_CTL, %ecx + rdmsr + or $0x2, %eax + wrmsr + + post_code(0x28) + + jmp car_init_done + +#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS) +.global car_cqos +car_cqos: + /* + * Create CBM_LEN_MASK based on CBM_LEN + * Get CPUID.(EAX=10H, ECX=2H):EAX.CBM_LEN[bits 4:0] + */ + mov $0x10, %eax + mov $0x2, %ecx + cpuid + and $0x1F, %eax + add $1, %al + + mov $1, %ebx + mov %al, %cl + shl %cl, %ebx + sub $1, %ebx + + /* Store the CBM_LEN_MASK in mm3 for later use. */ + movd %ebx, %mm3 + + /* + * Disable both L1 and L2 prefetcher. For yet-to-understood reason, + * prefetchers slow down filling cache with rep stos in CQOS mode. + */ + mov $MSR_PREFETCH_CTL, %ecx + rdmsr + or $(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax + wrmsr + +#if (CONFIG_DCACHE_RAM_SIZE == CONFIG_L2_CACHE_SIZE) +/* + * If CAR size is set to full L2 size, mask is calculated as all-zeros. + * This is not supported by the CPU/uCode. + */ +#error "CQOS CAR may not use whole L2 cache area" +#endif + + /* Calculate how many bits to be used for CAR */ + xor %edx, %edx + mov $CONFIG_DCACHE_RAM_SIZE, %eax /* dividend */ + mov $CONFIG_CACHE_QOS_SIZE_PER_BIT, %ecx /* divisor */ + div %ecx /* result is in eax */ + mov %eax, %ecx /* save to ecx */ + mov $1, %ebx + shl %cl, %ebx + sub $1, %ebx /* resulting mask is is in ebx */ + + /* Set this mask for initial cache fill */ + mov $MSR_L2_QOS_MASK(0), %ecx + rdmsr + mov %ebx, %eax + wrmsr + + /* Set CLOS selector to 0 */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~MSR_IA32_PQR_ASSOC_MASK, %edx /* select mask 0 */ + wrmsr + + /* We will need to block CAR region from evicts */ + mov $MSR_L2_QOS_MASK(1), %ecx + rdmsr + /* Invert bits that are to be used for cache */ + mov %ebx, %eax + xor $~0, %eax /* invert 32 bits */ + + /* + * Use CBM_LEN_MASK stored in mm3 to set bits based on Capacity Bit + * Mask Length. + */ + movd %mm3, %ebx + and %ebx, %eax + wrmsr + + post_code(0x26) + + /* Clear the cache memory region. This will also fill up the cache */ + movl $CONFIG_DCACHE_RAM_BASE, %edi + movl $CONFIG_DCACHE_RAM_SIZE, %ecx + shr $0x02, %ecx + xor %eax, %eax + cld + rep stosl + + post_code(0x27) + + /* Cache is populated. Use mask 1 that will block evicts */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~MSR_IA32_PQR_ASSOC_MASK, %edx /* clear index bits first */ + or $1, %edx /* select mask 1 */ + wrmsr + + /* Enable prefetchers */ + mov $MSR_PREFETCH_CTL, %ecx + rdmsr + and $~(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax + wrmsr + + post_code(0x28) + +/* jmp car_init_done */ + jmp car_init_ret + +#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED) +.global car_nem_enhanced +car_nem_enhanced: + /* Disable cache eviction (setup stage) */ + mov $MSR_EVICT_CTL, %ecx + rdmsr + or $0x1, %eax + wrmsr + post_code(0x26) + + /* Create n-way set associativity of cache */ + xorl %edi, %edi +find_llc_subleaf: + movl %edi, %ecx + movl $0x04, %eax + cpuid + inc %edi + and $0xe0, %al /* EAX[7:5] = Cache Level */ + cmp $0x60, %al /* Check to see if it is LLC */ + jnz find_llc_subleaf + + /* + * Set MSR 0xC91 IA32_L3_MASK_! = 0xE/0xFE/0xFFE/0xFFFE + * for 4/8/16 way of LLC + */ + shr $22, %ebx + inc %ebx + /* Calculate n-way associativity of LLC */ + mov %bl, %cl + + /* + * Maximizing RO cacheability while locking in the CAR to a + * single way since that particular way won't be victim candidate + * for evictions. + * This has been done after programing LLC_WAY_MASK_1 MSR + * with desired LLC way as mentioned below. + * + * Hence create Code and Data Size as per request + * Code Size (RO) : Up to 16M + * Data Size (RW) : Up to 256K + */ + movl $0x01, %eax + /* + * LLC Ways -> LLC_WAY_MASK_1: + * 4: 0x000E + * 8: 0x00FE + * 12: 0x0FFE + * 16: 0xFFFE + * + * These MSRs contain one bit per each way of LLC + * - If this bit is '0' - the way is protected from eviction + * - If this bit is '1' - the way is not protected from eviction + */ + shl %cl, %eax + subl $0x02, %eax + movl $MSR_IA32_L3_MASK_1, %ecx + xorl %edx, %edx + wrmsr + /* + * Set MSR 0xC92 IA32_L3_MASK_2 = 0x1 + * + * For SKL SOC, data size remains 256K consistently. + * Hence, creating 1-way associative cache for Data + */ + mov $MSR_IA32_L3_MASK_2, %ecx + mov $0x01, %eax + xorl %edx, %edx + wrmsr + /* + * Set MSR_IA32_PQR_ASSOC = 0x02 + * + * Possible values: + * 0: Default value, no way mask should be applied + * 1: Apply way mask 1 to LLC + * 2: Apply way mask 2 to LLC + * 3: Shouldn't be use in NEM Mode + */ + movl $MSR_IA32_PQR_ASSOC, %ecx + movl $0x02, %eax + xorl %edx, %edx + wrmsr + + movl $CONFIG_DCACHE_RAM_BASE, %edi + movl $CONFIG_DCACHE_RAM_SIZE, %ecx + shr $0x02, %ecx + xor %eax, %eax + cld + rep stosl + /* + * Set MSR_IA32_PQR_ASSOC = 0x01 + * At this stage we apply LLC_WAY_MASK_1 to the cache. + * i.e. way 0 is protected from eviction. + */ + movl $MSR_IA32_PQR_ASSOC, %ecx + movl $0x01, %eax + xorl %edx, %edx + wrmsr + + post_code(0x27) + /* + * Enable No-Eviction Mode Run State by setting + * NO_EVICT_MODE MSR 2E0h bit [1] = '1'. + */ + + movl $MSR_EVICT_CTL, %ecx + rdmsr + orl $0x02, %eax + wrmsr + + post_code(0x28) + + jmp car_init_done +#endif + +#if CONFIG_IS_ENABLED(X86_16BIT_INIT) +_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 */ + .long CONFIG_SYS_MONITOR_BASE /* code region base */ + .long CONFIG_SYS_MONITOR_LEN /* code region size */ +#endif diff --git a/arch/x86/cpu/intel_common/car2_uninit.S b/arch/x86/cpu/intel_common/car2_uninit.S new file mode 100644 index 00000000000..4797ac04279 --- /dev/null +++ b/arch/x86/cpu/intel_common/car2_uninit.S @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017 Intel Corp. + * Copyright 2019 Google LLC + * Taken from coreboot file exit_car.S + */ + +#include <config.h> +#include <asm/msr-index.h> +#include <asm/mtrr.h> + +.text +.global car_uninit +car_uninit: + + /* + * Retrieve return address from stack as it will get trashed below if + * execution is utilizing the cache-as-ram stack. + */ + pop %ebx + + /* Disable MTRRs. */ + mov $(MTRR_DEF_TYPE_MSR), %ecx + rdmsr + and $(~(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN)), %eax + wrmsr + +#ifdef CONFIG_INTEL_CAR_NEM +.global car_nem_teardown +car_nem_teardown: + + /* invalidate cache contents. */ + invd + + /* Knock down bit 1 then bit 0 of NEM control not combining steps. */ + mov $(MSR_EVICT_CTL), %ecx + rdmsr + and $(~(1 << 1)), %eax + wrmsr + and $(~(1 << 0)), %eax + wrmsr + +#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS) +.global car_cqos_teardown +car_cqos_teardown: + + /* Go back to all-evicting mode, set both masks to all-1s */ + mov $MSR_L2_QOS_MASK(0), %ecx + rdmsr + mov $~0, %al + wrmsr + + mov $MSR_L2_QOS_MASK(1), %ecx + rdmsr + mov $~0, %al + wrmsr + + /* Reset CLOS selector to 0 */ + mov $MSR_IA32_PQR_ASSOC, %ecx + rdmsr + and $~MSR_IA32_PQR_ASSOC_MASK, %edx + wrmsr + +#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED) +.global car_nem_enhanced_teardown +car_nem_enhanced_teardown: + + /* invalidate cache contents. */ + invd + + /* Knock down bit 1 then bit 0 of NEM control not combining steps. */ + mov $(MSR_EVICT_CTL), %ecx + rdmsr + and $(~(1 << 1)), %eax + wrmsr + and $(~(1 << 0)), %eax + wrmsr + + /* Reset CLOS selector to 0 */ + mov $IA32_PQR_ASSOC, %ecx + rdmsr + and $~IA32_PQR_ASSOC_MASK, %edx + wrmsr +#endif + + /* Return to caller. */ + jmp *%ebx

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Newer Intel SoCs have different ways of setting up cache-as-ram (CAR). Add support for these along with suitable configuration options.
I wonder why do we need do this in U-Boot. Isn't FSP-T doing the CAR for us?
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/Kconfig | 16 + arch/x86/cpu/intel_common/Kconfig | 18 + arch/x86/cpu/intel_common/Makefile | 8 + arch/x86/cpu/intel_common/car2.S | 490 ++++++++++++++++++++++++ arch/x86/cpu/intel_common/car2_uninit.S | 87 +++++ 5 files changed, 619 insertions(+) create mode 100644 arch/x86/cpu/intel_common/Kconfig create mode 100644 arch/x86/cpu/intel_common/car2.S create mode 100644 arch/x86/cpu/intel_common/car2_uninit.S
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 556e26080de..e34c71ec4cb 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -876,4 +876,20 @@ config HIGH_TABLE_SIZE Increse it if the default size does not fit the board's needs. This is most likely due to a large ACPI DSDT table is used.
+config INTEL_CAR_CQOS
bool "Support Intel Cache Quality of Service"
help
Cache Quality of Service allows more fine-grained control of cache
usage. As result, it is possible to set up a portion of L2 cache for
CAR and use the remainder for actual caching.
+# +# Each bit in QOS mask controls this many bytes. This is calculated as: +# (CACHE_WAYS / CACHE_BITS_PER_MASK) * CACHE_LINE_SIZE * CACHE_SETS +# +config CACHE_QOS_SIZE_PER_BIT
hex
depends on INTEL_CAR_CQOS
default 0x20000 # 128 KB
endmenu diff --git a/arch/x86/cpu/intel_common/Kconfig b/arch/x86/cpu/intel_common/Kconfig new file mode 100644 index 00000000000..a4f46b1108b --- /dev/null +++ b/arch/x86/cpu/intel_common/Kconfig @@ -0,0 +1,18 @@ +config INTEL_PMC
bool "Intel Power-management Controller"
select POWER_MGR
help
Enable support for the common Intel power-management controller which
provides features including checking whether the system started from
resume, powering off the system and enabling/disabling the reset
mechanism.
+config SPL_INTEL_PMC
bool "Intel Power-management Controller in SPL"
default y if SPL && INTEL_PMC
select SPL_POWER_MGR
help
Enable support for the common Intel power-management controller which
provides features including checking whether the system started from
resume, powering off the system and enabling/disabling the reset
mechanism.
I think the above 2 should not be in this patch
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 2de567dd9fe..f620747a7d2 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -8,6 +8,14 @@ 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
+ifdef CONFIG_FSP_VERSION2 +obj-$(CONFIG_TPL_BUILD) += car2.o +ifndef CONFIG_SPL_BUILD +obj-y += car2_uninit.o +endif +endif
obj-y += cpu.o obj-$(CONFIG_SPI_FLASH_INTEL_FAST) += fast_spi.o obj-y += lpc.o diff --git a/arch/x86/cpu/intel_common/car2.S b/arch/x86/cpu/intel_common/car2.S new file mode 100644 index 00000000000..ac07fe5ea6a --- /dev/null +++ b/arch/x86/cpu/intel_common/car2.S @@ -0,0 +1,490 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- This file is part of the coreboot project.
- Copyright (C) 2015-2016 Intel Corp.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
nits: there is already SPDX license
- */
+#include <config.h> +#include <asm/msr-index.h> +#include <asm/mtrr.h> +#include <asm/post.h> +#include <asm/processor-flags.h>
+#define KiB 1024
+.global car_init +car_init:
post_code(0x20)
/*
* Use the MTRR default type MSR as a proxy for detecting INIT#.
* Reset the system if any known bits are set in that MSR. That is
* an indication of the CPU not being properly reset.
*/
+check_for_clean_reset:
mov $MTRR_DEF_TYPE_MSR, %ecx
rdmsr
and $(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN), %eax
cmp $0, %eax
jz no_reset
/* perform warm reset */
movw $0xcf9, %dx
movb $0x06, %al
outb %al, %dx
+no_reset:
post_code(0x21)
Can we use values from post.h?
/* Clear/disable fixed MTRRs */
mov $fixed_mtrr_list_size, %ebx
xor %eax, %eax
xor %edx, %edx
+clear_fixed_mtrr:
add $-2, %ebx
movzwl fixed_mtrr_list(%ebx), %ecx
wrmsr
jnz clear_fixed_mtrr
post_code(0x22)
/* Figure put how many MTRRs we have, and clear them out */
mov $MTRR_CAP_MSR, %ecx
rdmsr
movzb %al, %ebx /* Number of variable MTRRs */
mov $MTRR_PHYS_BASE_MSR(0), %ecx
xor %eax, %eax
xor %edx, %edx
+clear_var_mtrr:
wrmsr
inc %ecx
wrmsr
inc %ecx
dec %ebx
jnz clear_var_mtrr
post_code(0x23)
/* Configure default memory type to uncacheable (UC) */
mov $MTRR_DEF_TYPE_MSR, %ecx
rdmsr
/* Clear enable bits and set default type to UC. */
and $~(MTRR_DEF_TYPE_MASK | MTRR_DEF_TYPE_EN | \
MTRR_DEF_TYPE_FIX_EN), %eax
wrmsr
/* Configure MTRR_PHYS_MASK_HIGH for proper addressing above 4GB
nits: wrong multi-line comment format
* based on the physical address size supported for this processor
* This is based on read from CPUID EAX = 080000008h, EAX bits [7:0]
*
* Examples:
* MTRR_PHYS_MASK_HIGH = 00000000Fh For 36 bit addressing
* MTRR_PHYS_MASK_HIGH = 0000000FFh For 40 bit addressing
*/
movl $0x80000008, %eax /* Address sizes leaf */
cpuid
sub $32, %al
movzx %al, %eax
xorl %esi, %esi
bts %eax, %esi
dec %esi /* esi <- MTRR_PHYS_MASK_HIGH */
post_code(0x24)
+#if ((CONFIG_DCACHE_RAM_SIZE & (CONFIG_DCACHE_RAM_SIZE - 1)) == 0)
/* Configure CAR region as write-back (WB) */
mov $MTRR_PHYS_BASE_MSR(0), %ecx
mov $CONFIG_DCACHE_RAM_BASE, %eax
or $MTRR_TYPE_WRBACK, %eax
xor %edx,%edx
wrmsr
/* Configure the MTRR mask for the size region */
mov $MTRR_PHYS_MASK(0), %ecx
mov $CONFIG_DCACHE_RAM_SIZE, %eax /* size mask */
dec %eax
not %eax
or $MTRR_PHYS_MASK_VALID, %eax
movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */
wrmsr
+#elif (CONFIG_DCACHE_RAM_SIZE == 768 * KiB) /* 768 KiB */
/* Configure CAR region as write-back (WB) */
mov $MTRR_PHYS_BASE_MSR(0), %ecx
mov $CONFIG_DCACHE_RAM_BASE, %eax
or $MTRR_TYPE_WRBACK, %eax
xor %edx,%edx
wrmsr
mov $MTRR_PHYS_MASK_MSR(0), %ecx
mov $(512 * KiB), %eax /* size mask */
dec %eax
not %eax
or $MTRR_PHYS_MASK_VALID, %eax
movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */
wrmsr
mov $MTRR_PHYS_BASE_MSR(1), %ecx
mov $(CONFIG_DCACHE_RAM_BASE + 512 * KiB), %eax
or $MTRR_TYPE_WRBACK, %eax
xor %edx,%edx
wrmsr
mov $MTRR_PHYS_MASK_MSR(1), %ecx
mov $(256 * KiB), %eax /* size mask */
dec %eax
not %eax
or $MTRR_PHYS_MASK_VALID, %eax
movl %esi, %edx /* edx <- MTRR_PHYS_MASK_HIGH */
wrmsr
+#else +#error "DCACHE_RAM_SIZE is not a power of 2 and setup code is missing" +#endif
post_code(0x25)
/* start */
+/* mov $0xffff80a8, %ebx */ +/* jmp *%ebx */ +.globl _from_bb +_from_bb: +/* jmp car_init_ret */
/* end */
/* Enable variable MTRRs */
mov $MTRR_DEF_TYPE_MSR, %ecx
rdmsr
or $MTRR_DEF_TYPE_EN, %eax
wrmsr
/* Enable caching */
mov %cr0, %eax
and $~(X86_CR0_CD | X86_CR0_NW), %eax
invd
mov %eax, %cr0
+#if IS_ENABLED(CONFIG_INTEL_CAR_NEM)
jmp car_nem
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS)
jmp car_cqos
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED)
jmp car_nem_enhanced
+#else +#error "No CAR mechanism selected: +#endif
jmp car_init_ret
+#if 0 +.global car_init_done +car_init_done:
post_code(0x29)
/* Setup bootblock stack */
mov $_car_stack_end, %esp
/* Need to align stack to 16 bytes at call instruction. Account for
the two pushes below. */
andl $0xfffffff0, %esp
sub $8, %esp
/*push TSC value to stack*/
movd %mm2, %eax
pushl %eax /* tsc[63:32] */
movd %mm1, %eax
pushl %eax /* tsc[31:0] */
+before_carstage:
post_code(0x2A)
call bootblock_c_entry
where is this function?
/* Never reached */
+#endif
+fixed_mtrr_list:
.word MTRR_FIX_64K_00000_MSR
.word MTRR_FIX_16K_80000_MSR
.word MTRR_FIX_16K_A0000_MSR
.word MTRR_FIX_4K_C0000_MSR
.word MTRR_FIX_4K_C8000_MSR
.word MTRR_FIX_4K_D0000_MSR
.word MTRR_FIX_4K_D8000_MSR
.word MTRR_FIX_4K_E0000_MSR
.word MTRR_FIX_4K_E8000_MSR
.word MTRR_FIX_4K_F0000_MSR
.word MTRR_FIX_4K_F8000_MSR
+fixed_mtrr_list_size = . - fixed_mtrr_list
+#if IS_ENABLED(CONFIG_INTEL_CAR_NEM) +.global car_nem +car_nem:
/* Disable cache eviction (setup stage) */
mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x1, %eax
wrmsr
post_code(0x26)
/* Clear the cache memory region. This will also fill up the cache */
movl $CONFIG_DCACHE_RAM_BASE, %edi
movl $CONFIG_DCACHE_RAM_SIZE, %ecx
shr $0x02, %ecx
xor %eax, %eax
cld
rep stosl
post_code(0x27)
/* Disable cache eviction (run stage) */
mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x2, %eax
wrmsr
post_code(0x28)
jmp car_init_done
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS) +.global car_cqos +car_cqos:
/*
* Create CBM_LEN_MASK based on CBM_LEN
* Get CPUID.(EAX=10H, ECX=2H):EAX.CBM_LEN[bits 4:0]
*/
mov $0x10, %eax
mov $0x2, %ecx
cpuid
and $0x1F, %eax
add $1, %al
mov $1, %ebx
mov %al, %cl
shl %cl, %ebx
sub $1, %ebx
/* Store the CBM_LEN_MASK in mm3 for later use. */
movd %ebx, %mm3
/*
* Disable both L1 and L2 prefetcher. For yet-to-understood reason,
* prefetchers slow down filling cache with rep stos in CQOS mode.
*/
mov $MSR_PREFETCH_CTL, %ecx
rdmsr
or $(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax
wrmsr
+#if (CONFIG_DCACHE_RAM_SIZE == CONFIG_L2_CACHE_SIZE) +/*
- If CAR size is set to full L2 size, mask is calculated as all-zeros.
- This is not supported by the CPU/uCode.
- */
+#error "CQOS CAR may not use whole L2 cache area" +#endif
/* Calculate how many bits to be used for CAR */
xor %edx, %edx
mov $CONFIG_DCACHE_RAM_SIZE, %eax /* dividend */
mov $CONFIG_CACHE_QOS_SIZE_PER_BIT, %ecx /* divisor */
div %ecx /* result is in eax */
mov %eax, %ecx /* save to ecx */
mov $1, %ebx
shl %cl, %ebx
sub $1, %ebx /* resulting mask is is in ebx */
/* Set this mask for initial cache fill */
mov $MSR_L2_QOS_MASK(0), %ecx
rdmsr
mov %ebx, %eax
wrmsr
/* Set CLOS selector to 0 */
mov $MSR_IA32_PQR_ASSOC, %ecx
rdmsr
and $~MSR_IA32_PQR_ASSOC_MASK, %edx /* select mask 0 */
wrmsr
/* We will need to block CAR region from evicts */
mov $MSR_L2_QOS_MASK(1), %ecx
rdmsr
/* Invert bits that are to be used for cache */
mov %ebx, %eax
xor $~0, %eax /* invert 32 bits */
/*
* Use CBM_LEN_MASK stored in mm3 to set bits based on Capacity Bit
* Mask Length.
*/
movd %mm3, %ebx
and %ebx, %eax
wrmsr
post_code(0x26)
/* Clear the cache memory region. This will also fill up the cache */
movl $CONFIG_DCACHE_RAM_BASE, %edi
movl $CONFIG_DCACHE_RAM_SIZE, %ecx
shr $0x02, %ecx
xor %eax, %eax
cld
rep stosl
post_code(0x27)
/* Cache is populated. Use mask 1 that will block evicts */
mov $MSR_IA32_PQR_ASSOC, %ecx
rdmsr
and $~MSR_IA32_PQR_ASSOC_MASK, %edx /* clear index bits first */
or $1, %edx /* select mask 1 */
wrmsr
/* Enable prefetchers */
mov $MSR_PREFETCH_CTL, %ecx
rdmsr
and $~(PREFETCH_L1_DISABLE | PREFETCH_L2_DISABLE), %eax
wrmsr
post_code(0x28)
+/* jmp car_init_done */
jmp car_init_ret
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED) +.global car_nem_enhanced +car_nem_enhanced:
/* Disable cache eviction (setup stage) */
mov $MSR_EVICT_CTL, %ecx
rdmsr
or $0x1, %eax
wrmsr
post_code(0x26)
/* Create n-way set associativity of cache */
xorl %edi, %edi
+find_llc_subleaf:
movl %edi, %ecx
movl $0x04, %eax
cpuid
inc %edi
and $0xe0, %al /* EAX[7:5] = Cache Level */
cmp $0x60, %al /* Check to see if it is LLC */
jnz find_llc_subleaf
/*
* Set MSR 0xC91 IA32_L3_MASK_! = 0xE/0xFE/0xFFE/0xFFFE
* for 4/8/16 way of LLC
*/
shr $22, %ebx
inc %ebx
/* Calculate n-way associativity of LLC */
mov %bl, %cl
/*
* Maximizing RO cacheability while locking in the CAR to a
* single way since that particular way won't be victim candidate
* for evictions.
* This has been done after programing LLC_WAY_MASK_1 MSR
* with desired LLC way as mentioned below.
*
* Hence create Code and Data Size as per request
* Code Size (RO) : Up to 16M
* Data Size (RW) : Up to 256K
*/
movl $0x01, %eax
/*
* LLC Ways -> LLC_WAY_MASK_1:
* 4: 0x000E
* 8: 0x00FE
* 12: 0x0FFE
* 16: 0xFFFE
*
* These MSRs contain one bit per each way of LLC
* - If this bit is '0' - the way is protected from eviction
* - If this bit is '1' - the way is not protected from eviction
*/
shl %cl, %eax
subl $0x02, %eax
movl $MSR_IA32_L3_MASK_1, %ecx
xorl %edx, %edx
wrmsr
/*
* Set MSR 0xC92 IA32_L3_MASK_2 = 0x1
*
* For SKL SOC, data size remains 256K consistently.
* Hence, creating 1-way associative cache for Data
*/
mov $MSR_IA32_L3_MASK_2, %ecx
mov $0x01, %eax
xorl %edx, %edx
wrmsr
/*
* Set MSR_IA32_PQR_ASSOC = 0x02
*
* Possible values:
* 0: Default value, no way mask should be applied
* 1: Apply way mask 1 to LLC
* 2: Apply way mask 2 to LLC
* 3: Shouldn't be use in NEM Mode
*/
movl $MSR_IA32_PQR_ASSOC, %ecx
movl $0x02, %eax
xorl %edx, %edx
wrmsr
movl $CONFIG_DCACHE_RAM_BASE, %edi
movl $CONFIG_DCACHE_RAM_SIZE, %ecx
shr $0x02, %ecx
xor %eax, %eax
cld
rep stosl
/*
* Set MSR_IA32_PQR_ASSOC = 0x01
* At this stage we apply LLC_WAY_MASK_1 to the cache.
* i.e. way 0 is protected from eviction.
*/
movl $MSR_IA32_PQR_ASSOC, %ecx
movl $0x01, %eax
xorl %edx, %edx
wrmsr
post_code(0x27)
/*
* Enable No-Eviction Mode Run State by setting
* NO_EVICT_MODE MSR 2E0h bit [1] = '1'.
*/
movl $MSR_EVICT_CTL, %ecx
rdmsr
orl $0x02, %eax
wrmsr
post_code(0x28)
jmp car_init_done
+#endif
+#if CONFIG_IS_ENABLED(X86_16BIT_INIT) +_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 */
.long CONFIG_SYS_MONITOR_BASE /* code region base */
.long CONFIG_SYS_MONITOR_LEN /* code region size */
+#endif diff --git a/arch/x86/cpu/intel_common/car2_uninit.S b/arch/x86/cpu/intel_common/car2_uninit.S new file mode 100644 index 00000000000..4797ac04279 --- /dev/null +++ b/arch/x86/cpu/intel_common/car2_uninit.S @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/*
- Copyright 2017 Intel Corp.
- Copyright 2019 Google LLC
- Taken from coreboot file exit_car.S
- */
+#include <config.h> +#include <asm/msr-index.h> +#include <asm/mtrr.h>
+.text +.global car_uninit +car_uninit:
/*
* Retrieve return address from stack as it will get trashed below if
* execution is utilizing the cache-as-ram stack.
*/
pop %ebx
/* Disable MTRRs. */
mov $(MTRR_DEF_TYPE_MSR), %ecx
rdmsr
and $(~(MTRR_DEF_TYPE_EN | MTRR_DEF_TYPE_FIX_EN)), %eax
wrmsr
+#ifdef CONFIG_INTEL_CAR_NEM +.global car_nem_teardown +car_nem_teardown:
/* invalidate cache contents. */
invd
/* Knock down bit 1 then bit 0 of NEM control not combining steps. */
mov $(MSR_EVICT_CTL), %ecx
rdmsr
and $(~(1 << 1)), %eax
wrmsr
and $(~(1 << 0)), %eax
wrmsr
+#elif IS_ENABLED(CONFIG_INTEL_CAR_CQOS) +.global car_cqos_teardown +car_cqos_teardown:
/* Go back to all-evicting mode, set both masks to all-1s */
mov $MSR_L2_QOS_MASK(0), %ecx
rdmsr
mov $~0, %al
wrmsr
mov $MSR_L2_QOS_MASK(1), %ecx
rdmsr
mov $~0, %al
wrmsr
/* Reset CLOS selector to 0 */
mov $MSR_IA32_PQR_ASSOC, %ecx
rdmsr
and $~MSR_IA32_PQR_ASSOC_MASK, %edx
wrmsr
+#elif IS_ENABLED(CONFIG_INTEL_CAR_NEM_ENHANCED) +.global car_nem_enhanced_teardown +car_nem_enhanced_teardown:
/* invalidate cache contents. */
invd
/* Knock down bit 1 then bit 0 of NEM control not combining steps. */
mov $(MSR_EVICT_CTL), %ecx
rdmsr
and $(~(1 << 1)), %eax
wrmsr
and $(~(1 << 0)), %eax
wrmsr
/* Reset CLOS selector to 0 */
mov $IA32_PQR_ASSOC, %ecx
rdmsr
and $~IA32_PQR_ASSOC_MASK, %edx
wrmsr
+#endif
/* Return to caller. */
jmp *%ebx
--
I was not fully convinced we need this in U-Boot if we are using FSP.
Regards, Bin

Hi Bin,
On Thu, 10 Oct 2019 at 03:50, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Newer Intel SoCs have different ways of setting up cache-as-ram (CAR). Add support for these along with suitable configuration options.
I wonder why do we need do this in U-Boot. Isn't FSP-T doing the CAR for us?
Well actually I have not tried using FSP-T yet on apollolake. I'll see how it looks.
Regards, Simon

Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Thu, 10 Oct 2019 at 03:50, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Newer Intel SoCs have different ways of setting up cache-as-ram (CAR). Add support for these along with suitable configuration options.
I wonder why do we need do this in U-Boot. Isn't FSP-T doing the CAR for us?
Well actually I have not tried using FSP-T yet on apollolake. I'll see how it looks.
It looks so far only FSP-M is used on your apollolake port.
What I'd like to see is a complete FSP 2.0 support in U-Boot, which means we need FSP-T for the CAR and FSP-S for the silicon-specific initialization. With FSP-S, I believe most of your platform support codes in this patch series are no longer needed.
Regards, Bin

Hi Bin,
On Fri, 11 Oct 2019 at 22:48, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Thu, 10 Oct 2019 at 03:50, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Newer Intel SoCs have different ways of setting up cache-as-ram (CAR). Add support for these along with suitable configuration options.
I wonder why do we need do this in U-Boot. Isn't FSP-T doing the CAR for us?
Well actually I have not tried using FSP-T yet on apollolake. I'll see how it looks.
It looks so far only FSP-M is used on your apollolake port.
What I'd like to see is a complete FSP 2.0 support in U-Boot, which means we need FSP-T for the CAR and FSP-S for the silicon-specific initialization. With FSP-S, I believe most of your platform support codes in this patch series are no longer needed.
I have actually got FSP-S running - see u-boot-dm/coral2-working, along with display, MMC, etc. There is very little init in U-Boot itself and my feeling is that most of the TPL/SPL init is actually needed. We cannot run FSP-S until the CAR is turned off, so it has to run in U-Boot.
I also just got an Up board so can give that a try one day assuming I have the SPI adaptor. But I think you might have some apollolake boards too?
Regards, Simon

Hi Simon,
On Sun, Oct 13, 2019 at 1:53 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, 11 Oct 2019 at 22:48, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Thu, 10 Oct 2019 at 03:50, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Newer Intel SoCs have different ways of setting up cache-as-ram (CAR). Add support for these along with suitable configuration options.
I wonder why do we need do this in U-Boot. Isn't FSP-T doing the CAR for us?
Well actually I have not tried using FSP-T yet on apollolake. I'll see how it looks.
It looks so far only FSP-M is used on your apollolake port.
What I'd like to see is a complete FSP 2.0 support in U-Boot, which means we need FSP-T for the CAR and FSP-S for the silicon-specific initialization. With FSP-S, I believe most of your platform support codes in this patch series are no longer needed.
I have actually got FSP-S running - see u-boot-dm/coral2-working, along with display, MMC, etc. There is very little init in U-Boot itself and my feeling is that most of the TPL/SPL init is actually needed. We cannot run FSP-S until the CAR is turned off, so it has to run in U-Boot.
OK, so why do we want to introduce TPL on ApolloLake? I think there is no size limitation that you can just run U-Boot directly on ApolloLake, no?
I also just got an Up board so can give that a try one day assuming I have the SPI adaptor. But I think you might have some apollolake boards too?
Yes, I have one of the ApolloLake CRB from Intel and planned to try at some point but some other stuff has been occupying my time :)
Regards, Bin

Hi Bin,
On Sun, 13 Oct 2019 at 19:58, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sun, Oct 13, 2019 at 1:53 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Fri, 11 Oct 2019 at 22:48, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Sat, Oct 12, 2019 at 11:38 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Thu, 10 Oct 2019 at 03:50, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Newer Intel SoCs have different ways of setting up cache-as-ram (CAR). Add support for these along with suitable configuration options.
I wonder why do we need do this in U-Boot. Isn't FSP-T doing the CAR for us?
Well actually I have not tried using FSP-T yet on apollolake. I'll see how it looks.
It looks so far only FSP-M is used on your apollolake port.
What I'd like to see is a complete FSP 2.0 support in U-Boot, which means we need FSP-T for the CAR and FSP-S for the silicon-specific initialization. With FSP-S, I believe most of your platform support codes in this patch series are no longer needed.
I have actually got FSP-S running - see u-boot-dm/coral2-working, along with display, MMC, etc. There is very little init in U-Boot itself and my feeling is that most of the TPL/SPL init is actually needed. We cannot run FSP-S until the CAR is turned off, so it has to run in U-Boot.
OK, so why do we want to introduce TPL on ApolloLake? I think there is no size limitation that you can just run U-Boot directly on ApolloLake, no?
More details here:
https://gitlab.denx.de/u-boot/custodians/u-boot-dm/blob/coral2-working/doc/b...
In short, APL only supports booting a 30KB image to start. Then we need to load something else that can set up DRAM, which is SPL. After that we can load U-Boot. So we have to have TPL on APL (and perhaps later) CPUs.
I also just got an Up board so can give that a try one day assuming I have the SPI adaptor. But I think you might have some apollolake boards too?
Yes, I have one of the ApolloLake CRB from Intel and planned to try at some point but some other stuff has been occupying my time :)
Sounds good! I am not sure I will be able to get FSP-T going so may ask for help on that.
- Simon

Since x86 users binman now, we don't need this compile-time define.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/config.mk | 1 - 1 file changed, 1 deletion(-)
diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk index 22416f39b6e..e5a393a1c81 100644 --- a/arch/x86/cpu/config.mk +++ b/arch/x86/cpu/config.mk @@ -10,7 +10,6 @@ LDPPFLAGS += -DRESET_SEG_START=$(CONFIG_RESET_SEG_START) LDPPFLAGS += -DRESET_SEG_SIZE=$(CONFIG_RESET_SEG_SIZE) LDPPFLAGS += -DRESET_VEC_LOC=$(CONFIG_RESET_VEC_LOC) LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16) -LDPPFLAGS += -DRESET_BASE="CONFIG_SYS_TEXT_BASE + (CONFIG_SYS_MONITOR_LEN - RESET_SEG_SIZE)"
ifdef CONFIG_X86_64 ifndef CONFIG_SPL_BUILD

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Since x86 users binman now, we don't need this compile-time define.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/config.mk | 1 - 1 file changed, 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 10, 2019 at 5:56 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
Since x86 users binman now, we don't need this compile-time define.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/cpu/config.mk | 1 - 1 file changed, 1 deletion(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!

This is not used anywhere now, so drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/Kconfig | 5 ----- arch/x86/cpu/config.mk | 1 - 2 files changed, 6 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e34c71ec4cb..e797612e30e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -207,11 +207,6 @@ config RESET_SEG_START depends on X86_RESET_VECTOR default 0xffff0000
-config RESET_SEG_SIZE - hex - depends on X86_RESET_VECTOR - default 0x10000 - config RESET_VEC_LOC hex depends on X86_RESET_VECTOR diff --git a/arch/x86/cpu/config.mk b/arch/x86/cpu/config.mk index e5a393a1c81..8f9814c0ae7 100644 --- a/arch/x86/cpu/config.mk +++ b/arch/x86/cpu/config.mk @@ -7,7 +7,6 @@ CROSS_COMPILE ?= i386-linux-
# DO NOT MODIFY THE FOLLOWING UNLESS YOU REALLY KNOW WHAT YOU ARE DOING! LDPPFLAGS += -DRESET_SEG_START=$(CONFIG_RESET_SEG_START) -LDPPFLAGS += -DRESET_SEG_SIZE=$(CONFIG_RESET_SEG_SIZE) LDPPFLAGS += -DRESET_VEC_LOC=$(CONFIG_RESET_VEC_LOC) LDPPFLAGS += -DSTART_16=$(CONFIG_SYS_X86_START16)

On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This is not used anywhere now, so drop it.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/Kconfig | 5 ----- arch/x86/cpu/config.mk | 1 - 2 files changed, 6 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com

On Thu, Oct 10, 2019 at 5:57 PM Bin Meng bmeng.cn@gmail.com wrote:
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
This is not used anywhere now, so drop it.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/Kconfig | 5 ----- arch/x86/cpu/config.mk | 1 - 2 files changed, 6 deletions(-)
Reviewed-by: Bin Meng bmeng.cn@gmail.com
applied to u-boot-x86, thanks!

At present we don't support loading microcode with FSP2. The correct way to do this is by adding it to the FIT. For now, disable including microcode in the image.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/Kconfig | 4 ++++ arch/x86/dts/u-boot.dtsi | 11 +++++++++++ 2 files changed, 15 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e797612e30e..fce3c1d92a3 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -580,6 +580,10 @@ config HAVE_REFCODE broadwell) U-Boot will be missing some critical setup steps. Various peripherals may fail to work.
+config HAVE_MICROCODE + bool + default y if !FSP_VERSION2 + config SMP bool "Enable Symmetric Multiprocessing" default n diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 049f47c9ffd..35129d0510b 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -37,9 +37,15 @@ }; #endif #ifdef CONFIG_TPL +#ifdef CONFIG_HAVE_MICROCODE u-boot-tpl-with-ucode-ptr { offset = <CONFIG_TPL_TEXT_BASE>; }; +#else + u-boot-tpl { + offset = <0xffff0000>; + }; +#endif u-boot-tpl-dtb { }; u-boot-spl { @@ -77,11 +83,16 @@ offset = <CONFIG_SYS_TEXT_BASE>; }; #endif +#ifdef CONFIG_HAVE_MICROCODE u-boot-dtb-with-ucode { }; u-boot-ucode { align = <16>; }; +#else + u-boot-dtb { + }; +#endif #ifdef CONFIG_X86_HAS_FIT intel-fit { };

Hi Simon,
On Wed, Sep 25, 2019 at 10:59 PM Simon Glass sjg@chromium.org wrote:
At present we don't support loading microcode with FSP2. The correct way to do this is by adding it to the FIT. For now, disable including microcode in the image.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/Kconfig | 4 ++++ arch/x86/dts/u-boot.dtsi | 11 +++++++++++ 2 files changed, 15 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e797612e30e..fce3c1d92a3 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -580,6 +580,10 @@ config HAVE_REFCODE broadwell) U-Boot will be missing some critical setup steps. Various peripherals may fail to work.
+config HAVE_MICROCODE
bool
default y if !FSP_VERSION2
config SMP bool "Enable Symmetric Multiprocessing" default n diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi index 049f47c9ffd..35129d0510b 100644 --- a/arch/x86/dts/u-boot.dtsi +++ b/arch/x86/dts/u-boot.dtsi @@ -37,9 +37,15 @@ }; #endif #ifdef CONFIG_TPL +#ifdef CONFIG_HAVE_MICROCODE u-boot-tpl-with-ucode-ptr { offset = <CONFIG_TPL_TEXT_BASE>; }; +#else
u-boot-tpl {
offset = <0xffff0000>;
Why hardcode?
};
+#endif u-boot-tpl-dtb { }; u-boot-spl { @@ -77,11 +83,16 @@ offset = <CONFIG_SYS_TEXT_BASE>; }; #endif +#ifdef CONFIG_HAVE_MICROCODE u-boot-dtb-with-ucode { }; u-boot-ucode { align = <16>; }; +#else
u-boot-dtb {
};
+#endif #ifdef CONFIG_X86_HAS_FIT intel-fit { }; --
Regards, Bin

Hi Bin,
On Wed, 25 Sep 2019 at 08:58, Simon Glass sjg@chromium.org wrote:
Apollolake is an Intel SoC generation aimed at relatively low-end embedded systems. It was released in 2016 but has become more popular recently with some embedded boards using it.
This series adds support for apollolake. As an example it adds an implementation of chromebook_coral (a large range of Chromebooks released in 2017).
The series provides only enough to boot to a prompt. It does not include display, storage, USB, etc. But it does include the major part of the plumbing.
Since this is the first time U-Boot has used FSP2 there is quite a bit of refactoring needed. Some of this is in previous series, but much of it is here.
Some further clean-up is needed with this series and it needs more documentation, but it is ready for review.
This series is available at u-boot-dm/coral-working
Just a note on this series. I sent it out as it was already getting huge and I don't like sitting on so many patches.
I have since done a little more work and have more peripherals running as well as FSP-S. In doing so I've found some clean-ups in the FSP parts, moving apollolake-specific code out of the fsp/ directory where it ended up, for example.
This results in another 20 patches or so :-(
The first 45 patches in *this* are not specific to x86 so I am thinking of dealing with them separately.
So my plan is:
1. Get the sandbox/dm patches reviewed and applied 2. Tidy up the remaining series 3. Add the new patches 4. Resend
I am on holiday for a week so will get to this on the 12th or so.
Regards, Simon

Hi Simon,
On Wed, Oct 2, 2019 at 10:15 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Wed, 25 Sep 2019 at 08:58, Simon Glass sjg@chromium.org wrote:
Apollolake is an Intel SoC generation aimed at relatively low-end embedded systems. It was released in 2016 but has become more popular recently with some embedded boards using it.
This series adds support for apollolake. As an example it adds an implementation of chromebook_coral (a large range of Chromebooks released in 2017).
The series provides only enough to boot to a prompt. It does not include display, storage, USB, etc. But it does include the major part of the plumbing.
Since this is the first time U-Boot has used FSP2 there is quite a bit of refactoring needed. Some of this is in previous series, but much of it is here.
Some further clean-up is needed with this series and it needs more documentation, but it is ready for review.
This series is available at u-boot-dm/coral-working
Just a note on this series. I sent it out as it was already getting huge and I don't like sitting on so many patches.
I have since done a little more work and have more peripherals running as well as FSP-S. In doing so I've found some clean-ups in the FSP parts, moving apollolake-specific code out of the fsp/ directory where it ended up, for example.
This results in another 20 patches or so :-(
The first 45 patches in *this* are not specific to x86 so I am thinking of dealing with them separately.
So my plan is:
- Get the sandbox/dm patches reviewed and applied
- Tidy up the remaining series
- Add the new patches
- Resend
Sounds like a good plan.
I will start reviewing the patches, and apply the patches as many as possible, to save some efforts of resending such a huge patch series.
I am on holiday for a week so will get to this on the 12th or so.
Regards, Bin

Hi Simon,
On Wed, Oct 2, 2019 at 8:34 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Oct 2, 2019 at 10:15 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Wed, 25 Sep 2019 at 08:58, Simon Glass sjg@chromium.org wrote:
Apollolake is an Intel SoC generation aimed at relatively low-end embedded systems. It was released in 2016 but has become more popular recently with some embedded boards using it.
This series adds support for apollolake. As an example it adds an implementation of chromebook_coral (a large range of Chromebooks released in 2017).
The series provides only enough to boot to a prompt. It does not include display, storage, USB, etc. But it does include the major part of the plumbing.
Since this is the first time U-Boot has used FSP2 there is quite a bit of refactoring needed. Some of this is in previous series, but much of it is here.
Some further clean-up is needed with this series and it needs more documentation, but it is ready for review.
This series is available at u-boot-dm/coral-working
Just a note on this series. I sent it out as it was already getting huge and I don't like sitting on so many patches.
I have since done a little more work and have more peripherals running as well as FSP-S. In doing so I've found some clean-ups in the FSP parts, moving apollolake-specific code out of the fsp/ directory where it ended up, for example.
This results in another 20 patches or so :-(
The first 45 patches in *this* are not specific to x86 so I am thinking of dealing with them separately.
So my plan is:
- Get the sandbox/dm patches reviewed and applied
- Tidy up the remaining series
- Add the new patches
- Resend
Sounds like a good plan.
I will start reviewing the patches, and apply the patches as many as possible, to save some efforts of resending such a huge patch series.
I've applied about half of current patches to u-boot-x86/next. I see most of them are clean-ups, and preparation for FSP2, and suspect some patches may have broader impacts other than sandbox or x86. Hence I am going to send a PR soon for what I have for now once the new release merge window is open, to leave more time for wider testing. I will continue reviewing the remaining patches.
I am on holiday for a week so will get to this on the 12th or so.
Regards, Bin

Hi Bin,
On Mon, 7 Oct 2019 at 08:31, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Oct 2, 2019 at 8:34 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Oct 2, 2019 at 10:15 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Wed, 25 Sep 2019 at 08:58, Simon Glass sjg@chromium.org wrote:
Apollolake is an Intel SoC generation aimed at relatively low-end embedded systems. It was released in 2016 but has become more popular recently with some embedded boards using it.
This series adds support for apollolake. As an example it adds an implementation of chromebook_coral (a large range of Chromebooks released in 2017).
The series provides only enough to boot to a prompt. It does not include display, storage, USB, etc. But it does include the major part of the plumbing.
Since this is the first time U-Boot has used FSP2 there is quite a bit of refactoring needed. Some of this is in previous series, but much of it is here.
Some further clean-up is needed with this series and it needs more documentation, but it is ready for review.
This series is available at u-boot-dm/coral-working
Just a note on this series. I sent it out as it was already getting huge and I don't like sitting on so many patches.
I have since done a little more work and have more peripherals running as well as FSP-S. In doing so I've found some clean-ups in the FSP parts, moving apollolake-specific code out of the fsp/ directory where it ended up, for example.
This results in another 20 patches or so :-(
The first 45 patches in *this* are not specific to x86 so I am thinking of dealing with them separately.
So my plan is:
- Get the sandbox/dm patches reviewed and applied
- Tidy up the remaining series
- Add the new patches
- Resend
Sounds like a good plan.
I will start reviewing the patches, and apply the patches as many as possible, to save some efforts of resending such a huge patch series.
I've applied about half of current patches to u-boot-x86/next. I see most of them are clean-ups, and preparation for FSP2, and suspect some patches may have broader impacts other than sandbox or x86. Hence I am going to send a PR soon for what I have for now once the new release merge window is open, to leave more time for wider testing. I will continue reviewing the remaining patches.
I am on holiday for a week so will get to this on the 12th or so.
Thanks for your effort on this. I really appreciate your clean-ups too and I'm sorry I wasn't able to get things into a better state in time.
I'll take a look through the comments and do a respin. I suspect it will take me until the 21st but we will see.
Regards, SImon

Hi Bin,
On Thu, 10 Oct 2019 at 11:06, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Mon, 7 Oct 2019 at 08:31, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Oct 2, 2019 at 8:34 PM Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Oct 2, 2019 at 10:15 AM Simon Glass sjg@chromium.org wrote:
Hi Bin,
On Wed, 25 Sep 2019 at 08:58, Simon Glass sjg@chromium.org wrote:
Apollolake is an Intel SoC generation aimed at relatively low-end embedded systems. It was released in 2016 but has become more popular recently with some embedded boards using it.
This series adds support for apollolake. As an example it adds an implementation of chromebook_coral (a large range of Chromebooks released in 2017).
The series provides only enough to boot to a prompt. It does not include display, storage, USB, etc. But it does include the major part of the plumbing.
Since this is the first time U-Boot has used FSP2 there is quite a bit of refactoring needed. Some of this is in previous series, but much of it is here.
Some further clean-up is needed with this series and it needs more documentation, but it is ready for review.
This series is available at u-boot-dm/coral-working
Just a note on this series. I sent it out as it was already getting huge and I don't like sitting on so many patches.
I have since done a little more work and have more peripherals running as well as FSP-S. In doing so I've found some clean-ups in the FSP parts, moving apollolake-specific code out of the fsp/ directory where it ended up, for example.
This results in another 20 patches or so :-(
The first 45 patches in *this* are not specific to x86 so I am thinking of dealing with them separately.
So my plan is:
- Get the sandbox/dm patches reviewed and applied
- Tidy up the remaining series
- Add the new patches
- Resend
Sounds like a good plan.
I will start reviewing the patches, and apply the patches as many as possible, to save some efforts of resending such a huge patch series.
I've applied about half of current patches to u-boot-x86/next. I see most of them are clean-ups, and preparation for FSP2, and suspect some patches may have broader impacts other than sandbox or x86. Hence I am going to send a PR soon for what I have for now once the new release merge window is open, to leave more time for wider testing. I will continue reviewing the remaining patches.
I am on holiday for a week so will get to this on the 12th or so.
Thanks for your effort on this. I really appreciate your clean-ups too and I'm sorry I wasn't able to get things into a better state in time.
I'll take a look through the comments and do a respin. I suspect it will take me until the 21st but we will see.
Still on track for the 21st. I just need to sort out the SPI driver.
The WIP is at u-boot-dm/coral-working
Regards, Simon
participants (5)
-
Bin Meng
-
Joe Hershberger
-
Simon Glass
-
Simon Goldschmidt
-
Stephen Warren