[U-Boot] [PATCH v5 091/101] x86: apl: Add LPC driver

Bin Meng bmeng.cn at gmail.com
Mon Dec 2 08:06:44 CET 2019


Hi Simon,

On Mon, Nov 25, 2019 at 12:12 PM Simon Glass <sjg at chromium.org> wrote:
>
> This driver the LPC and provides a few functions to set up LPC features.

driver models?

> These should probably use ioctls() or perhaps, better, have specific
> uclass methods.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
> Changes in v5: None
> Changes in v4:
> - Add comments for exported functions
> - Tidy up header guards
> - Use 'Apollo Lake'
> - Use BIT() macro a bit more
> - Use tabs instead of spaces
>
> Changes in v3:
> - Drop unused code in lpc_configure_pads()
> - Fix value of LPC_BC_LE
>
> Changes in v2: None
>
>  arch/x86/cpu/apollolake/Makefile           |   1 +
>  arch/x86/cpu/apollolake/lpc.c              | 141 +++++++++++++++++++++
>  arch/x86/include/asm/arch-apollolake/lpc.h |  82 ++++++++++++
>  3 files changed, 224 insertions(+)
>  create mode 100644 arch/x86/cpu/apollolake/lpc.c
>  create mode 100644 arch/x86/include/asm/arch-apollolake/lpc.h
>
> diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile
> index 2d78368150..31045a03c1 100644
> --- a/arch/x86/cpu/apollolake/Makefile
> +++ b/arch/x86/cpu/apollolake/Makefile
> @@ -6,5 +6,6 @@ obj-$(CONFIG_SPL_BUILD) += systemagent.o
>
>  obj-y += hostbridge.o
>  obj-y += itss.o
> +obj-y += lpc.o
>  obj-y += pmc.o
>  obj-y += uart.o
> diff --git a/arch/x86/cpu/apollolake/lpc.c b/arch/x86/cpu/apollolake/lpc.c
> new file mode 100644
> index 0000000000..b14eed6508
> --- /dev/null
> +++ b/arch/x86/cpu/apollolake/lpc.c
> @@ -0,0 +1,141 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2019 Google LLC
> + *
> + * From coreboot Apollo Lake support lpc.c
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <spl.h>
> +#include <asm/lpc_common.h>
> +#include <asm/pci.h>
> +#include <asm/arch/iomap.h>
> +#include <asm/arch/lpc.h>
> +#include <linux/log2.h>
> +
> +void lpc_configure_pads(void)
> +{
> +       /* All pads are configured by the hostbridge */

Useless function, remove it completely?

> +}
> +
> +void lpc_enable_fixed_io_ranges(uint io_enables)
> +{
> +       pci_x86_clrset_config(PCH_DEV_LPC, LPC_IO_ENABLES, 0, io_enables,
> +                             PCI_SIZE_16);
> +}
> +
> +/*
> + * Find the first unused IO window.
> + * Returns -1 if not found, 0 for reg 0x84, 1 for reg 0x88 ...
> + */
> +static int find_unused_pmio_window(void)
> +{
> +       int i;
> +       ulong lgir;
> +
> +       for (i = 0; i < LPC_NUM_GENERIC_IO_RANGES; i++) {
> +               pci_x86_read_config(PCH_DEV_LPC, LPC_GENERIC_IO_RANGE(i),
> +                                   &lgir, PCI_SIZE_32);
> +
> +               if (!(lgir & LPC_LGIR_EN))
> +                       return i;
> +       }
> +
> +       return -1;
> +}
> +
> +int lpc_open_pmio_window(uint base, uint size)
> +{
> +       int i, lgir_reg_num;
> +       u32 lgir_reg_offset, lgir, window_size, alignment;
> +       ulong bridged_size, bridge_base;
> +       ulong reg;
> +
> +       log_debug("LPC: Trying to open IO window from %x size %x\n", base,
> +                 size);
> +
> +       bridged_size = 0;
> +       bridge_base = base;
> +
> +       while (bridged_size < size) {
> +               /* Each IO range register can only open a 256-byte window */
> +               window_size = min(size, (uint)LPC_LGIR_MAX_WINDOW_SIZE);
> +
> +               /* Window size must be a power of two for the AMASK to work */
> +               alignment = 1UL << (order_base_2(window_size));
> +               window_size = ALIGN(window_size, alignment);
> +
> +               /* Address[15:2] in LGIR[15:12] and Mask[7:2] in LGIR[23:18] */
> +               lgir = (bridge_base & LPC_LGIR_ADDR_MASK) | LPC_LGIR_EN;
> +               lgir |= ((window_size - 1) << 16) & LPC_LGIR_AMASK_MASK;
> +
> +               /* Skip programming if same range already programmed */
> +               for (i = 0; i < LPC_NUM_GENERIC_IO_RANGES; i++) {
> +                       pci_x86_read_config(PCH_DEV_LPC,
> +                                           LPC_GENERIC_IO_RANGE(i), &reg,
> +                                           PCI_SIZE_32);
> +                       if (lgir == reg)
> +                               return -EALREADY;
> +               }
> +
> +               lgir_reg_num = find_unused_pmio_window();
> +               if (lgir_reg_num < 0) {
> +                       log_err("LPC: Cannot open IO window: %lx size %lx\n",
> +                               bridge_base, size - bridged_size);
> +                       log_err("No more IO windows\n");
> +
> +                       return -ENOSPC;
> +               }
> +               lgir_reg_offset = LPC_GENERIC_IO_RANGE(lgir_reg_num);
> +
> +               pci_x86_write_config(PCH_DEV_LPC, lgir_reg_offset, lgir,
> +                                    PCI_SIZE_32);
> +
> +               log_debug("LPC: Opened IO window LGIR%d: base %lx size %x\n",
> +                         lgir_reg_num, bridge_base, window_size);
> +
> +               bridged_size += window_size;
> +               bridge_base += window_size;
> +       }
> +
> +       return 0;
> +}
> +
> +void lpc_io_setup_comm_a_b(void)
> +{
> +       /* ComA Range 3F8h-3FFh [2:0] */
> +       u16 com_ranges = LPC_IOD_COMA_RANGE;
> +       u16 com_enable = LPC_IOE_COMA_EN;
> +
> +       /* ComB Range 2F8h-2FFh [6:4] */
> +       if (0) {

Why if (0)?

> +               com_ranges |= LPC_IOD_COMB_RANGE;
> +               com_enable |= LPC_IOE_COMB_EN;
> +       }
> +
> +       /* Setup I/O Decode Range Register for LPC */
> +       pci_write_config16(PCH_DEV_LPC, LPC_IO_DECODE, com_ranges);
> +       /* Enable ComA and ComB Port */
> +       lpc_enable_fixed_io_ranges(com_enable);
> +}
> +
> +static int apl_lpc_probe(struct udevice *dev)
> +{
> +       if (spl_phase() == PHASE_TPL)
> +               lpc_configure_pads();
> +
> +       return 0;
> +}
> +
> +static const struct udevice_id apl_lpc_ids[] = {
> +       { .compatible = "intel,apl-lpc" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(apl_lpc_drv) = {
> +       .name           = "intel_apl_lpc",
> +       .id             = UCLASS_LPC,
> +       .of_match       = apl_lpc_ids,
> +       .probe          = apl_lpc_probe,
> +};
> diff --git a/arch/x86/include/asm/arch-apollolake/lpc.h b/arch/x86/include/asm/arch-apollolake/lpc.h
> new file mode 100644
> index 0000000000..5d2adad319
> --- /dev/null
> +++ b/arch/x86/include/asm/arch-apollolake/lpc.h
> @@ -0,0 +1,82 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2017 Intel Corporation.
> + * Take from coreboot project file of the same name
> + */
> +
> +#ifndef _ASM_ARCH_LPC_H
> +#define _ASM_ARCH_LPC_H
> +
> +#define LPC_SERIRQ_CTL                 0x64
> +#define  LPC_SCNT_EN                   BIT(7)
> +#define  LPC_SCNT_MODE                 BIT(6)
> +#define LPC_IO_DECODE                  0x80
> +#define  LPC_IOD_COMA_RANGE             (0 << 0) /* 0x3F8 - 0x3FF COMA*/
> +#define  LPC_IOD_COMB_RANGE             (1 << 4) /* 0x2F8 - 0x2FF COMB*/
> +/*
> + * Use IO_<peripheral>_<IO port> style macros defined in lpc_lib.h
> + * to enable decoding of I/O locations for a peripheral
> + */
> +#define LPC_IO_ENABLES                 0x82
> +#define LPC_GENERIC_IO_RANGE(n)                ((((n) & 0x3) * 4) + 0x84)
> +#define  LPC_LGIR_AMASK_MASK           (0xfc << 16)
> +#define  LPC_LGIR_ADDR_MASK            0xfffc
> +#define  LPC_LGIR_EN                   BIT(0)
> +#define LPC_LGIR_MAX_WINDOW_SIZE       256
> +#define LPC_GENERIC_MEM_RANGE          0x98
> +#define  LPC_LGMR_ADDR_MASK            0xffff0000
> +#define  LPC_LGMR_EN                   BIT(0)
> +#define LPC_LGMR_WINDOW_SIZE           (64 * KiB)
> +#define LPC_BIOS_CNTL                  0xdc
> +#define  LPC_BC_BILD                   BIT(7)
> +#define  LPC_BC_LE                     BIT(1)
> +#define  LPC_BC_EISS                   BIT(5)
> +#define LPC_PCCTL                      0xE0    /* PCI Clock Control */
> +#define  LPC_PCCTL_CLKRUN_EN           BIT(0)
> +
> +/*
> + * IO decode enable macros are in the format IO_<peripheral>_<IO port>.
> + * For example, to open ports 0x60, 0x64 for the keyboard controller,
> + * use IOE_KBC_60_64 macro. For IOE_ macros that do not specify a port range,
> + * the port range is selectable via the IO decodes register.
> + */
> +#define LPC_IOE_EC_4E_4F               BIT(13)
> +#define LPC_IOE_SUPERIO_2E_2F          BIT(12)
> +#define LPC_IOE_EC_62_66               BIT(11)
> +#define LPC_IOE_KBC_60_64              BIT(10)
> +#define LPC_IOE_HGE_208                        BIT(9)
> +#define LPC_IOE_LGE_200                        BIT(8)
> +#define LPC_IOE_FDD_EN                 BIT(3)
> +#define LPC_IOE_LPT_EN                 BIT(2)
> +#define LPC_IOE_COMB_EN                        BIT(1)
> +#define LPC_IOE_COMA_EN                        BIT(0)
> +#define LPC_NUM_GENERIC_IO_RANGES      4
> +
> +#define LPC_IO_ENABLES                 0x82
> +
> +/**
> + * lpc_enable_fixed_io_ranges() - enable the fixed I/O ranges
> + *
> + * @io_enables: Mask of things to enable (LPC_IOE_.)
> + */
> +void lpc_enable_fixed_io_ranges(uint io_enables);
> +
> +/**
> + * lpc_open_pmio_window() - Open an IO port range
> + *
> + * @base: Base I/O address (e.g. 0x800)
> + * @size: Size of window (e.g. 0x100)
> + * @return 0 if OK, -ENOSPC if there are no more windows available, -EALREADY
> + *     if already set up
> + */
> +int lpc_open_pmio_window(uint base, uint size);
> +
> +/**
> + * lpc_io_setup_comm_a_b() - Set up basic serial UARTs
> + *
> + * Set up the LPC to handle I/O to the COMA/COMB serial UART addresses
> + * 2f8-2ff and 3f8-3ff.
> + */
> +void lpc_io_setup_comm_a_b(void);
> +
> +#endif
> --

Regards,
Bin


More information about the U-Boot mailing list