Hi Simon, On Mon, Nov 25, 2019 at 12:12 PM Simon Glass <s...@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 <s...@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), ®, > + 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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot