[U-Boot] [PATCH v3 013/108] x86: spi: Add helper functions for Intel Fast SPI
Bin Meng
bmeng.cn at gmail.com
Sat Nov 2 04:13:50 UTC 2019
On Mon, Oct 21, 2019 at 11:33 AM Simon Glass <sjg at chromium.org> wrote:
>
> Most x86 CPUs use a mechanism where the SPI flash is mapped into the very
> top of 32-bit address space, so that it can be executed in place and read
> simply by copying from memory. For an 8MB ROM the mapping starts at
> 0xff800000.
>
> However some recent Intel CPUs do not use a simple 1:1 memory map. Instead
> the map starts at a different address and not all of the SPI flash is
> accessible through the map. This 'Fast SPI' feature requires that U-Boot
> check the location of the map. It is also possible (optionally) to read
> from the SPI flash using a driver.
>
> Add support for booting from Fast SPI. The memory-mapped version is used
> by both TPL and SPL on apollolake.
>
> In respect of a SPI flash driver, the actual SPI driver is ich.c - this
> just adds a few helper functions and definitions.
>
> This is used by Apollolake.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
> Changes in v3:
> - Add support for of-platdata for TPL
> - Add the missing header file
> - Change Fast-SPI driver into a helper file used by ICH SPI
> - Don't include write() and erase() in TPL
> - Merge in patch "x86: Add support for booting from Fast SPI"
> - Reorder file so that write() and erase() are together
> - Use pci_get_devfn()
>
> Changes in v2: None
>
> arch/x86/cpu/intel_common/Makefile | 1 +
> arch/x86/cpu/intel_common/fast_spi.c | 73 ++++++++++++++++++++++++++++
> arch/x86/include/asm/fast_spi.h | 68 ++++++++++++++++++++++++++
> arch/x86/include/asm/spl.h | 1 +
> 4 files changed, 143 insertions(+)
> create mode 100644 arch/x86/cpu/intel_common/fast_spi.c
> create mode 100644 arch/x86/include/asm/fast_spi.h
>
> diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile
> index 07f27c29ec7..dfbc29f0475 100644
> --- a/arch/x86/cpu/intel_common/Makefile
> +++ b/arch/x86/cpu/intel_common/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += report_platform.o
> obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += mrc.o
> endif
> obj-y += cpu.o
> +obj-y += fast_spi.o
> obj-y += lpc.o
> ifndef CONFIG_TARGET_EFI_APP
> obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o
> diff --git a/arch/x86/cpu/intel_common/fast_spi.c b/arch/x86/cpu/intel_common/fast_spi.c
> new file mode 100644
> index 00000000000..a6e3d0a5bfc
> --- /dev/null
> +++ b/arch/x86/cpu/intel_common/fast_spi.c
> @@ -0,0 +1,73 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2019 Google LLC
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/cpu_common.h>
> +#include <asm/fast_spi.h>
> +#include <asm/pci.h>
> +
> +/*
> + * Returns bios_start and fills in size of the BIOS region.
> + */
> +static ulong fast_spi_get_bios_region(struct fast_spi_regs *regs,
> + uint *bios_size)
> +{
> + ulong bios_start, bios_end;
> +
> + /*
> + * BIOS_BFPREG provides info about BIOS-Flash Primary Region Base and
> + * Limit. Base and Limit fields are in units of 4K.
> + */
> + u32 val = readl(®s->bfp);
> +
> + bios_start = (val & SPIBAR_BFPREG_PRB_MASK) << 12;
> + bios_end = (((val & SPIBAR_BFPREG_PRL_MASK) >>
> + SPIBAR_BFPREG_PRL_SHIFT) + 1) << 12;
> + *bios_size = bios_end - bios_start;
> +
> + return bios_start;
> +}
> +
> +int fast_spi_get_bios_mmap(pci_dev_t pdev, ulong *map_basep, uint *map_sizep,
> + uint *offsetp)
> +{
> + struct fast_spi_regs *regs;
> + ulong bar, base, mmio_base;
> +
> + /* Special case to find mapping without probing the device */
> + pci_x86_read_config(pdev, 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);
> + *map_basep = (u32)-*map_sizep - base;
> + *offsetp = base;
> +
> + return 0;
> +}
> +
> +int fast_spi_early_init(pci_dev_t pdev, ulong mmio_base)
> +{
> + /* Program Temporary BAR for SPI */
> + pci_x86_write_config(pdev, PCI_BASE_ADDRESS_0,
> + mmio_base | PCI_BASE_ADDRESS_SPACE_MEMORY,
> + PCI_SIZE_32);
> +
> + /* Enable Bus Master and MMIO Space */
> + pci_x86_clrset_config(pdev, PCI_COMMAND, 0, PCI_COMMAND_MASTER |
> + PCI_COMMAND_MEMORY, PCI_SIZE_8);
> +
> + /*
> + * Disable the BIOS write protect so write commands are allowed.
> + * Enable Prefetching and caching.
> + */
> + pci_x86_clrset_config(pdev, SPIBAR_BIOS_CONTROL,
> + SPIBAR_BIOS_CONTROL_EISS |
> + SPIBAR_BIOS_CONTROL_CACHE_DISABLE,
> + SPIBAR_BIOS_CONTROL_WPD |
> + SPIBAR_BIOS_CONTROL_PREFETCH_ENABLE, PCI_SIZE_8);
> +
> + return 0;
> +}
> diff --git a/arch/x86/include/asm/fast_spi.h b/arch/x86/include/asm/fast_spi.h
> new file mode 100644
> index 00000000000..6c1bda2184f
> --- /dev/null
> +++ b/arch/x86/include/asm/fast_spi.h
> @@ -0,0 +1,68 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Copyright (C) 2017 Intel Corporation.
> + */
> +
> +#ifndef ASM_FAST_SPI_H
> +#define ASM_FAST_SPI_H
> +
> +/* Register offsets from the MMIO region base (PCI_BASE_ADDRESS_0) */
> +struct fast_spi_regs {
> + u32 bfp;
> + u32 hsfsts_ctl;
> + u32 faddr;
> + u32 dlock;
> +
> + u32 fdata[0x10];
> +
> + u32 fracc;
> + u32 freg[12];
> + u32 fpr[5];
> + u32 gpr0;
> + u32 spare2;
> + u32 sts_ctl;
> + u16 preop; /* a4 */
I assume a4 is the offset of preop? Leaving it causes confusion and it
can be dropped, I think.
> + u16 optype;
> + u8 opmenu[8];
> +
> + u32 spare3;
> + u32 fdoc;
> + u32 fdod;
> + u32 spare4;
> + u32 afc;
> + u32 vscc[2];
> + u32 ptinx;
> + u32 ptdata;
> +};
> +check_member(fast_spi_regs, ptdata, 0xd0);
> +
> +/* Bit definitions for BFPREG (0x00) register */
> +#define SPIBAR_BFPREG_PRB_MASK 0x7fff
> +#define SPIBAR_BFPREG_PRL_SHIFT 16
> +#define SPIBAR_BFPREG_PRL_MASK (0x7fff << SPIBAR_BFPREG_PRL_SHIFT)
> +
> +/* PCI configuration registers */
> +#define SPIBAR_BIOS_CONTROL 0xdc
> +#define SPIBAR_BIOS_CONTROL_WPD BIT(0)
> +#define SPIBAR_BIOS_CONTROL_LOCK_ENABLE BIT(1)
> +#define SPIBAR_BIOS_CONTROL_CACHE_DISABLE BIT(2)
> +#define SPIBAR_BIOS_CONTROL_PREFETCH_ENABLE BIT(3)
> +#define SPIBAR_BIOS_CONTROL_EISS BIT(5)
> +#define SPIBAR_BIOS_CONTROL_BILD BIT(7)
> +
> +/**
> + * fast_spi_get_bios_mmap() - Get memory map for SPI flash
> + *
> + * @pdev: PCI device to use (this is the Fast SPI device)
> + * @map_basep: Returns base memory address for mapped SPI
> + * @map_sizep: Returns size of mapped SPI
> + * @offsetp: Returns start offset of SPI flash where the map works
> + * correctly (offsets before this are not visible)
> + * @return 0 (always)
> + */
> +int fast_spi_get_bios_mmap(pci_dev_t pdev, ulong *map_basep, uint *map_sizep,
> + uint *offsetp);
> +
> +int fast_spi_early_init(pci_dev_t pdev, ulong mmio_base);
> +
> +#endif /* ASM_FAST_SPI_H */
> diff --git a/arch/x86/include/asm/spl.h b/arch/x86/include/asm/spl.h
> index 1bef4877eb3..cc6cac08f23 100644
> --- a/arch/x86/include/asm/spl.h
> +++ b/arch/x86/include/asm/spl.h
> @@ -11,6 +11,7 @@
>
> enum {
> BOOT_DEVICE_SPI_MMAP = 10,
> + BOOT_DEVICE_FAST_SPI,
> BOOT_DEVICE_CROS_VBOOT,
> };
>
> --
Regards,
Bin
More information about the U-Boot
mailing list