[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(&regs->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