mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-02-18 06:58:54 +00:00
x86: apl: Add LPC driver
This driver the LPC and provides a few functions to set up LPC features. These should probably use ioctls() or perhaps, better, have specific uclass methods. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
parent
3a02f699fa
commit
8bd5dcd895
3 changed files with 205 additions and 0 deletions
|
@ -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
|
||||
|
|
122
arch/x86/cpu/apollolake/lpc.c
Normal file
122
arch/x86/cpu/apollolake/lpc.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
// 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_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;
|
||||
|
||||
/* 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 const struct udevice_id apl_lpc_ids[] = {
|
||||
{ .compatible = "intel,apl-lpc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* All pads are LPC already configured by the hostbridge, so no probing here */
|
||||
U_BOOT_DRIVER(apl_lpc_drv) = {
|
||||
.name = "intel_apl_lpc",
|
||||
.id = UCLASS_LPC,
|
||||
.of_match = apl_lpc_ids,
|
||||
};
|
82
arch/x86/include/asm/arch-apollolake/lpc.h
Normal file
82
arch/x86/include/asm/arch-apollolake/lpc.h
Normal file
|
@ -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
|
Loading…
Add table
Reference in a new issue