- Move P2SB from Apollo Lake to a more generic location
- Add a function to find a device by drvdata in DM core
- Enhancement of DM IRQ uclass driver
- Add a clock driver for Intel devices
- Add support for ACPI general-purpose events
- Add a TPM driver for H1/Cr50
- Enable TPM on Google Chromebook Coral
This commit is contained in:
Tom Rini
2020-02-10 12:27:31 -05:00
38 changed files with 1641 additions and 95 deletions

View File

@@ -93,6 +93,7 @@
<&gpio_b 9 0xc 3 2 1>;
int-value = <1234>;
uint-value = <(-1234)>;
interrupts-extended = <&irq 3 0>;
};
junk {
@@ -357,8 +358,10 @@
vss-microvolts = <0>;
};
irq {
irq: irq {
compatible = "sandbox,irq";
interrupt-controller;
#interrupt-cells = <2>;
};
lcd {

View File

@@ -45,6 +45,10 @@
#define PCI_EA_BAR2_MAGIC 0x72727272
#define PCI_EA_BAR4_MAGIC 0x74747474
enum {
SANDBOX_IRQN_PEND = 1, /* Interrupt number for 'pending' test */
};
/* System controller driver data */
enum {
SYSCON0 = 32,

View File

@@ -715,6 +715,13 @@ config HAVE_ITSS
Select this to include the driver for the Interrupt Timer
Subsystem (ITSS) which is found on several Intel devices.
config HAVE_P2SB
bool "Enable P2SB"
help
Select this to include the driver for the Primary to
Sideband Bridge (P2SB) which is found on several Intel
devices.
menu "System tables"
depends on !EFI && !SYS_COREBOOT
@@ -916,4 +923,37 @@ config X86_OFFSET_SPL
depends on SPL && X86
default SPL_TEXT_BASE
config ACPI_GPE
bool "Support ACPI general-purpose events"
help
Enable a driver for ACPI GPEs to allow peripherals to send interrupts
via ACPI to the OS. In U-Boot this is only used when U-Boot itself
needs access to these interrupts. This can happen when it uses a
peripheral that is set up to use GPEs and so cannot use the normal
GPIO mechanism for polling an input.
See https://queue.acm.org/blogposting.cfm?id=18977 for more info
config SPL_ACPI_GPE
bool "Support ACPI general-purpose events in SPL"
help
Enable a driver for ACPI GPEs to allow peripherals to send interrupts
via ACPI to the OS. In U-Boot this is only used when U-Boot itself
needs access to these interrupts. This can happen when it uses a
peripheral that is set up to use GPEs and so cannot use the normal
GPIO mechanism for polling an input.
See https://queue.acm.org/blogposting.cfm?id=18977 for more info
config TPL_ACPI_GPE
bool "Support ACPI general-purpose events in TPL"
help
Enable a driver for ACPI GPEs to allow peripherals to send interrupts
via ACPI to the OS. In U-Boot this is only used when U-Boot itself
needs access to these interrupts. This can happen when it uses a
peripheral that is set up to use GPEs and so cannot use the normal
GPIO mechanism for polling an input.
See https://queue.acm.org/blogposting.cfm?id=18977 for more info
endmenu

View File

@@ -55,6 +55,7 @@ obj-$(CONFIG_INTEL_QUEENSBAY) += queensbay/
obj-$(CONFIG_INTEL_TANGIER) += tangier/
obj-$(CONFIG_APIC) += lapic.o ioapic.o
obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += irq.o
obj-$(CONFIG_$(SPL_TPL_)ACPI_GPE) += acpi_gpe.o
obj-$(CONFIG_QFW) += qfw_cpu.o
ifndef CONFIG_$(SPL_)X86_64
obj-$(CONFIG_SMP) += mp_init.o

85
arch/x86/cpu/acpi_gpe.c Normal file
View File

@@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2019 Google, LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <common.h>
#include <dm.h>
#include <irq.h>
#include <asm/io.h>
/**
* struct acpi_gpe_priv - private driver information
*
* @acpi_base: Base I/O address of ACPI registers
*/
struct acpi_gpe_priv {
ulong acpi_base;
};
#define GPE0_STS(x) (0x20 + ((x) * 4))
static int acpi_gpe_read_and_clear(struct irq *irq)
{
struct acpi_gpe_priv *priv = dev_get_priv(irq->dev);
u32 mask, sts;
ulong start;
int ret = 0;
int bank;
bank = irq->id / 32;
mask = 1 << (irq->id % 32);
/* Wait up to 1ms for GPE status to clear */
start = get_timer(0);
do {
if (get_timer(start) > 1)
return ret;
sts = inl(priv->acpi_base + GPE0_STS(bank));
if (sts & mask) {
outl(mask, priv->acpi_base + GPE0_STS(bank));
ret = 1;
}
} while (sts & mask);
return ret;
}
static int acpi_gpe_ofdata_to_platdata(struct udevice *dev)
{
struct acpi_gpe_priv *priv = dev_get_priv(dev);
priv->acpi_base = dev_read_addr(dev);
if (!priv->acpi_base || priv->acpi_base == FDT_ADDR_T_NONE)
return log_msg_ret("acpi_base", -EINVAL);
return 0;
}
static int acpi_gpe_of_xlate(struct irq *irq, struct ofnode_phandle_args *args)
{
irq->id = args->args[0];
return 0;
}
static const struct irq_ops acpi_gpe_ops = {
.read_and_clear = acpi_gpe_read_and_clear,
.of_xlate = acpi_gpe_of_xlate,
};
static const struct udevice_id acpi_gpe_ids[] = {
{ .compatible = "intel,acpi-gpe", .data = X86_IRQT_ACPI_GPE },
{ }
};
U_BOOT_DRIVER(acpi_gpe_drv) = {
.name = "acpi_gpe",
.id = UCLASS_IRQ,
.of_match = acpi_gpe_ids,
.ops = &acpi_gpe_ops,
.ofdata_to_platdata = acpi_gpe_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct acpi_gpe_priv),
};

View File

@@ -40,6 +40,11 @@ config INTEL_APOLLOLAKE
imply INTEL_GPIO
imply SMP
imply HAVE_ITSS
imply HAVE_P2SB
imply CLK
imply CMD_CLK
imply CLK_INTEL
imply ACPI_GPE
if INTEL_APOLLOLAKE

View File

@@ -20,7 +20,6 @@ endif
obj-y += hostbridge.o
obj-y += lpc.o
obj-y += p2sb.o
obj-y += pch.o
obj-y += pmc.o
obj-y += uart.o

View File

@@ -24,7 +24,6 @@
#define HIDE_BIT BIT(0)
#define INTEL_GSPI_MAX 3
#define INTEL_I2C_DEV_MAX 8
#define MAX_USB2_PORTS 8
enum {
@@ -32,36 +31,6 @@ enum {
CHIPSET_LOCKDOWN_COREBOOT, /* coreboot handles locking */
};
enum i2c_speed {
I2C_SPEED_STANDARD = 100000,
I2C_SPEED_FAST = 400000,
I2C_SPEED_FAST_PLUS = 1000000,
I2C_SPEED_HIGH = 3400000,
I2C_SPEED_FAST_ULTRA = 5000000,
};
/*
* Timing values are in units of clock period, with the clock speed
* provided by the SOC
*
* TODO(sjg@chromium.org): Connect this up to the I2C driver
*/
struct dw_i2c_speed_config {
enum i2c_speed speed;
/* SCL high and low period count */
u16 scl_lcnt;
u16 scl_hcnt;
/*
* SDA hold time should be 300ns in standard and fast modes
* and long enough for deterministic logic level change in
* fast-plus and high speed modes.
*
* [15:0] SDA TX Hold Time
* [23:16] SDA RX Hold Time
*/
u32 sda_hold;
};
/* Serial IRQ control. SERIRQ_QUIET is the default (0) */
enum serirq_mode {
SERIRQ_QUIET,
@@ -69,32 +38,6 @@ enum serirq_mode {
SERIRQ_OFF,
};
/*
* This I2C controller has support for 3 independent speed configs but can
* support both FAST_PLUS and HIGH speeds through the same set of speed
* config registers. These are treated separately so the speed config values
* can be provided via ACPI to the OS.
*/
#define DW_I2C_SPEED_CONFIG_COUNT 4
struct dw_i2c_bus_config {
/* Bus should be enabled in TPL with temporary base */
int early_init;
/* Bus speed in Hz, default is I2C_SPEED_FAST (400 KHz) */
enum i2c_speed speed;
/*
* If rise_time_ns is non-zero the calculations for lcnt and hcnt
* registers take into account the times of the bus. However, if
* there is a match in speed_config those register values take
* precedence
*/
int rise_time_ns;
int fall_time_ns;
int data_hold_time_ns;
/* Specific bus speed configuration */
struct dw_i2c_speed_config speed_config[DW_I2C_SPEED_CONFIG_COUNT];
};
struct gspi_cfg {
/* Bus speed in MHz */
u32 speed_mhz;
@@ -110,7 +53,6 @@ struct gspi_cfg {
struct soc_intel_common_config {
int chipset_lockdown;
struct gspi_cfg gspi[INTEL_GSPI_MAX];
struct dw_i2c_bus_config i2c[INTEL_I2C_DEV_MAX];
};
enum pnp_settings {
@@ -593,7 +535,7 @@ int arch_fsps_preinit(void)
struct udevice *itss;
int ret;
ret = uclass_first_device_err(UCLASS_IRQ, &itss);
ret = irq_first_device_type(X86_IRQT_ITSS, &itss);
if (ret)
return log_msg_ret("no itss", ret);
/*
@@ -634,7 +576,7 @@ int arch_fsp_init_r(void)
if (ret)
return ret;
ret = uclass_first_device_err(UCLASS_IRQ, &itss);
ret = irq_first_device_type(X86_IRQT_ITSS, &itss);
if (ret)
return log_msg_ret("no itss", ret);
/* Restore GPIO IRQ polarities back to previous settings */

View File

@@ -15,6 +15,7 @@
#include <efi_loader.h>
#include <hang.h>
#include <init.h>
#include <irq.h>
#include <irq_func.h>
#include <asm/control_regs.h>
#include <asm/i8259.h>
@@ -264,7 +265,7 @@ int interrupt_init(void)
int ret;
/* Try to set up the interrupt router, but don't require one */
ret = uclass_first_device_err(UCLASS_IRQ, &dev);
ret = irq_first_device_type(X86_IRQT_BASE, &dev);
if (ret && ret != -ENODEV)
return ret;

View File

@@ -28,6 +28,7 @@ endif
endif
obj-y += pch.o
obj-$(CONFIG_HAVE_ITSS) += itss.o
obj-$(CONFIG_HAVE_P2SB) += p2sb.o
ifdef CONFIG_SPL
ifndef CONFIG_SPL_BUILD

View File

@@ -146,6 +146,15 @@ static int route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
return -ENOENT;
}
static int itss_bind(struct udevice *dev)
{
/* This is not set with of-platdata, so set it manually */
if (CONFIG_IS_ENABLED(OF_PLATDATA))
dev->driver_data = X86_IRQT_ITSS;
return 0;
}
static int itss_ofdata_to_platdata(struct udevice *dev)
{
struct itss_priv *priv = dev_get_priv(dev);
@@ -199,7 +208,7 @@ static const struct irq_ops itss_ops = {
};
static const struct udevice_id itss_ids[] = {
{ .compatible = "intel,itss"},
{ .compatible = "intel,itss", .data = X86_IRQT_ITSS },
{ }
};
@@ -208,6 +217,7 @@ U_BOOT_DRIVER(itss_drv) = {
.id = UCLASS_IRQ,
.of_match = itss_ids,
.ops = &itss_ops,
.bind = itss_bind,
.ofdata_to_platdata = itss_ofdata_to_platdata,
.platdata_auto_alloc_size = sizeof(struct itss_platdata),
.priv_auto_alloc_size = sizeof(struct itss_priv),

View File

@@ -7,6 +7,7 @@
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <irq.h>
#include <malloc.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -351,7 +352,7 @@ int irq_router_probe(struct udevice *dev)
}
static const struct udevice_id irq_router_ids[] = {
{ .compatible = "intel,irq-router" },
{ .compatible = "intel,irq-router", .data = X86_IRQT_BASE },
{ }
};

View File

@@ -20,6 +20,7 @@
#include <asm/arch-apollolake/gpio.h>
#include <asm/arch-apollolake/iomap.h>
#include <asm/arch-apollolake/pm.h>
#include <dt-bindings/clock/intel-clock.h>
/ {
model = "Google Coral";
@@ -29,6 +30,14 @@
cros-ec0 = &cros_ec;
fsp = &fsp_s;
spi0 = &spi;
i2c0 = &i2c_0;
i2c1 = &i2c_1;
i2c2 = &i2c_2;
i2c3 = &i2c_3;
i2c4 = &i2c_4;
i2c5 = &i2c_5;
i2c6 = &i2c_6;
i2c7 = &i2c_7;
};
config {
@@ -39,6 +48,11 @@
stdout-path = &serial;
};
clk: clock {
compatible = "intel,apl-clk";
#clock-cells = <1>;
};
cpus {
u-boot,dm-pre-reloc;
#address-cells = <1>;
@@ -75,6 +89,13 @@
};
acpi_gpe: general-purpose-events {
reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
compatible = "intel,acpi-gpe";
interrupt-controller;
#interrupt-cells = <2>;
};
keyboard {
intel,duplicate-por;
};
@@ -243,6 +264,78 @@
};
};
i2c_0: i2c2@16,0 {
compatible = "intel,apl-i2c";
reg = <0x0200b010 0 0 0 0>;
clocks = <&clk CLK_I2C>;
i2c-scl-rising-time-ns = <104>;
i2c-scl-falling-time-ns = <52>;
};
i2c_1: i2c2@16,1 {
compatible = "intel,apl-i2c";
reg = <0x0200b110 0 0 0 0>;
clocks = <&clk CLK_I2C>;
status = "disabled";
};
i2c_2: i2c2@16,2 {
compatible = "intel,apl-i2c";
reg = <0x0200b210 0 0 0 0>;
#address-cells = <1>;
#size-cells = <0>;
clock-frequency = <400000>;
clocks = <&clk CLK_I2C>;
i2c-scl-rising-time-ns = <57>;
i2c-scl-falling-time-ns = <28>;
tpm@50 {
reg = <0x50>;
compatible = "google,cr50";
u-boot,i2c-offset-len = <0>;
ready-gpio = <&gpio_n 28 GPIO_ACTIVE_LOW>;
interrupts-extended = <&acpi_gpe 0x3c 0>;
};
};
i2c_3: i2c2@16,3 {
compatible = "intel,apl-i2c";
reg = <0x0200b110 0 0 0 0>;
clocks = <&clk CLK_I2C>;
i2c-scl-rising-time-ns = <76>;
i2c-scl-falling-time-ns = <164>;
};
i2c_4: i2c2@17,0 {
compatible = "intel,apl-i2c";
reg = <0x0200b110 0 0 0 0>;
clocks = <&clk CLK_I2C>;
i2c-sda-hold-time-ns = <350>;
i2c-scl-rising-time-ns = <114>;
i2c-scl-falling-time-ns = <164>;
};
i2c_5: i2c2@17,1 {
compatible = "intel,apl-i2c";
reg = <0x0200b110 0 0 0 0>;
clocks = <&clk CLK_I2C>;
i2c-scl-rising-time-ns = <76>;
i2c-scl-falling-time-ns = <164>;
};
i2c_6: i2c2@17,2 {
compatible = "intel,apl-i2c";
reg = <0x0200b110 0 0 0 0>;
clocks = <&clk CLK_I2C>;
status = "disabled";
};
i2c_7: i2c2@17,3 {
compatible = "intel,apl-i2c";
reg = <0x0200b110 0 0 0 0>;
clocks = <&clk CLK_I2C>;
status = "disabled";
};
serial: serial@18,2 {
reg = <0x0200c210 0 0 0 0>;
u-boot,dm-pre-reloc;