17 changes: 0 additions & 17 deletions src/drivers/intel/fsp2_0/Kconfig
Expand Up @@ -141,23 +141,6 @@ config FSP_TEMP_RAM_SIZE
own stack that will be placed in DRAM and not in CAR, this is the
amount of memory the FSP needs for its stack and heap.

config FSP2_0_USES_TPM_MRC_HASH
bool
depends on TPM1 || TPM2
depends on VBOOT && VBOOT_STARTS_IN_BOOTBLOCK
default y if HAS_RECOVERY_MRC_CACHE
default n
select VBOOT_HAS_REC_HASH_SPACE
help
Store hash of trained recovery MRC cache in NVRAM space in TPM.
Use the hash to validate recovery MRC cache before using it.
This hash needs to be updated every time recovery mode training
is recomputed, or if the hash does not match recovery MRC cache.
Selecting this option requires that TPM already be setup by this
point in time. Thus it is only compatible when the option
VBOOT_STARTS_IN_BOOTBLOCK is selected, which causes verstage and
TPM setup to occur prior to memory initialization.

config FSP_PLATFORM_MEMORY_SETTINGS_VERSIONS
bool
help
Expand Down
9 changes: 8 additions & 1 deletion src/drivers/intel/fsp2_0/cbmem.c
Expand Up @@ -6,7 +6,14 @@
void *cbmem_top_chipset(void)
{
struct range_entry tolum;
uint8_t *tolum_base;

fsp_find_bootloader_tolum(&tolum);
return (void *)(uintptr_t)range_entry_end(&tolum);
tolum_base = (uint8_t *)(uintptr_t)range_entry_base(&tolum);

/*
* The TOLUM range may have other memory regions (such as APEI
* BERT region on top of CBMEM (IMD root and IMD small) region.
*/
return tolum_base + cbmem_overhead_size();
}
9 changes: 8 additions & 1 deletion src/drivers/intel/fsp2_0/hob_verify.c
Expand Up @@ -43,9 +43,16 @@ void fsp_verify_memory_init_hobs(void)
die("Space between FSP reserved region and BIOS TOLUM!\n");
}

if (range_entry_end(&tolum) != (uintptr_t)cbmem_top()) {
if (!CONFIG(ACPI_BERT) && range_entry_end(&tolum) != (uintptr_t)cbmem_top()) {
printk(BIOS_CRIT, "TOLUM end: 0x%08llx != %p: cbmem_top\n",
range_entry_end(&tolum), cbmem_top());
die("Space between cbmem_top and BIOS TOLUM!\n");
}

if (CONFIG(ACPI_BERT) &&
range_entry_end(&tolum) != (uintptr_t)cbmem_top() + CONFIG_ACPI_BERT_SIZE) {
printk(BIOS_CRIT, "TOLUM end: 0x%08llx != %p: cbmem_top + 0x%x: BERT\n",
range_entry_end(&tolum), cbmem_top(), CONFIG_ACPI_BERT_SIZE);
die("Space between cbmem_top and APEI BERT!\n");
}
}
19 changes: 0 additions & 19 deletions src/drivers/intel/fsp2_0/include/fsp/memory_init.h

This file was deleted.

28 changes: 15 additions & 13 deletions src/drivers/intel/fsp2_0/memory_init.c
Expand Up @@ -21,16 +21,10 @@
#include <security/vboot/vboot_common.h>
#include <security/tpm/tspi.h>
#include <vb2_api.h>
#include <fsp/memory_init.h>
#include <types.h>

static uint8_t temp_ram[CONFIG_FSP_TEMP_RAM_SIZE] __aligned(sizeof(uint64_t));

/* TPM MRC hash functionality depends on vboot starting before memory init. */
_Static_assert(!CONFIG(FSP2_0_USES_TPM_MRC_HASH) ||
CONFIG(VBOOT_STARTS_IN_BOOTBLOCK),
"for TPM MRC hash functionality, vboot must start in bootblock");

static void save_memory_training_data(bool s3wake, uint32_t fsp_version)
{
size_t mrc_data_size;
Expand All @@ -54,9 +48,6 @@ static void save_memory_training_data(bool s3wake, uint32_t fsp_version)
if (mrc_cache_stash_data(MRC_TRAINING_DATA, fsp_version, mrc_data,
mrc_data_size) < 0)
printk(BIOS_ERR, "Failed to stash MRC data\n");

if (CONFIG(FSP2_0_USES_TPM_MRC_HASH))
mrc_cache_update_hash(mrc_data, mrc_data_size);
}

static void do_fsp_post_memory_init(bool s3wake, uint32_t fsp_version)
Expand Down Expand Up @@ -121,10 +112,6 @@ static void fsp_fill_mrc_cache(FSPM_ARCH_UPD *arch_upd, uint32_t fsp_version)
if (data == NULL)
return;

if (CONFIG(FSP2_0_USES_TPM_MRC_HASH) &&
!mrc_cache_verify_hash(data, mrc_size))
return;

/* MRC cache found */
arch_upd->NvsBufferPtr = data;

Expand Down Expand Up @@ -276,6 +263,21 @@ static void do_fsp_memory_init(const struct fspm_context *context, bool s3wake)
/* Reserve enough memory under TOLUD to save CBMEM header */
arch_upd->BootLoaderTolumSize = cbmem_overhead_size();

/*
* If ACPI APEI BERT region size is defined, reserve memory for it.
* +------------------------+ range_entry_top(tolum)
* | Other reserved regions |
* | APEI BERT region |
* +------------------------+ cbmem_top()
* | CBMEM IMD ROOT |
* | CBMEM IMD SMALL |
* +------------------------+ range_entry_base(tolum), TOLUM
* | CBMEM FSP MEMORY |
* | Other CBMEM regions... |
*/
if (CONFIG(ACPI_BERT))
arch_upd->BootLoaderTolumSize += CONFIG_ACPI_BERT_SIZE;

/* Fill common settings on behalf of chipset. */
if (fsp_fill_common_arch_params(arch_upd, s3wake, fsp_version,
memmap) != CB_SUCCESS)
Expand Down
2 changes: 1 addition & 1 deletion src/drivers/intel/gma/opregion.c
Expand Up @@ -19,7 +19,7 @@ const char *mainboard_vbt_filename(void)
return "vbt.bin";
}

static char vbt_data[8 * KiB];
static char vbt_data[9 * KiB];
static size_t vbt_data_sz;

void *locate_vbt(size_t *vbt_size)
Expand Down
8 changes: 8 additions & 0 deletions src/drivers/intel/usb4/retimer/Kconfig
@@ -0,0 +1,8 @@
config DRIVERS_INTEL_USB4_RETIMER
bool
depends on HAVE_ACPI_TABLES
help
A retimer is a device that retransmits a fresh copy of the signal it
receives, by doing CDR and retransmitting the data (i.e., it is
protocol-aware). If your mainboard has a USB4 retimer (usually
located close to the USB4 ports), then select this driver.
1 change: 1 addition & 0 deletions src/drivers/intel/usb4/retimer/Makefile.inc
@@ -0,0 +1 @@
ramstage-$(CONFIG_DRIVERS_INTEL_USB4_RETIMER) += retimer.c
13 changes: 13 additions & 0 deletions src/drivers/intel/usb4/retimer/chip.h
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */

#ifndef __DRIVERS_INTEL_USB4_RETIMER_H__
#define __DRIVERS_INTEL_USB4_RETIMER_H__

#include <acpi/acpi_device.h>

struct drivers_intel_usb4_retimer_config {
/* GPIO used to control power of retimer device. */
struct acpi_gpio power_gpio;
};

#endif /* __DRIVERS_INTEL_USB4_RETIMER_H__ */
136 changes: 136 additions & 0 deletions src/drivers/intel/usb4/retimer/retimer.c
@@ -0,0 +1,136 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */

#include <acpi/acpigen.h>
#include <acpi/acpi_device.h>
#include <console/console.h>
#include <device/device.h>
#include <device/path.h>
#include <gpio.h>
#include <string.h>
#include "chip.h"

/* Unique ID for the retimer _DSM. */
#define INTEL_USB4_RETIMER_DSM_UUID "61788900-C470-42BB-80F0-23A313864593"

/*
* Arg0: UUID
* Arg1: Revision ID (set to 1)
* Arg2: Function Index
* 0: Query command implemented
* 1: Query force power enable state
* 2: Set force power state
* Arg3: A package containing parameters for the function specified
* by the UUID, revision ID and function index.
*/

static void usb4_retimer_cb_standard_query(void *arg)
{
/*
* ToInteger (Arg1, Local2)
* If (Local2 == 1) {
* Return(Buffer() {0x07})
* }
* Return (Buffer() {0x01})
*/
acpigen_write_to_integer(ARG1_OP, LOCAL2_OP);

/* Revision 1 supports 2 Functions beyond the standard query */
acpigen_write_if_lequal_op_int(LOCAL2_OP, 1);
acpigen_write_return_singleton_buffer(0x07);
acpigen_pop_len(); /* If */

/* Other revisions support no additional functions */
acpigen_write_return_singleton_buffer(0);
}

static void usb4_retimer_cb_get_power_state(void *arg)
{
struct acpi_gpio *power_gpio = arg;

/*
* // Read power gpio into Local0
* Store (\_SB.PCI0.GTXS (power_gpio), Local0)
* Return (Local0)
*/
acpigen_get_tx_gpio(power_gpio);
acpigen_write_return_op(LOCAL0_OP);
}

static void usb4_retimer_cb_set_power_state(void *arg)
{
struct acpi_gpio *power_gpio = arg;

/*
* // Get argument for on/off from Arg3[0]
* Local0 = DeRefOf (Arg3[0])
*/
acpigen_get_package_op_element(ARG3_OP, 0, LOCAL0_OP);

/*
* If (Local0 == 0) {
* // Turn power off
* \_SB.PCI0.CTXS (power_gpio)
* }
*/
acpigen_write_if_lequal_op_int(LOCAL0_OP, 0);
acpigen_disable_tx_gpio(power_gpio);
acpigen_pop_len(); /* If */

/*
* Else {
* // Turn power on
* \_SB.PCI0.STXS (power_gpio)
* }
*/
acpigen_write_else();
acpigen_enable_tx_gpio(power_gpio);
acpigen_pop_len();

/* Return (Zero) */
acpigen_write_return_integer(0);
}

static void (*usb4_retimer_callbacks[3])(void *) = {
usb4_retimer_cb_standard_query, /* Function 0 */
usb4_retimer_cb_get_power_state, /* Function 1 */
usb4_retimer_cb_set_power_state, /* Function 2 */
};

static void usb4_retimer_fill_ssdt(const struct device *dev)
{
const struct drivers_intel_usb4_retimer_config *config = dev->chip_info;
const char *scope = acpi_device_scope(dev);

if (!dev->enabled || !scope || !config)
return;

if (!config->power_gpio.pin_count) {
printk(BIOS_ERR, "%s: Power GPIO required for %s\n", __func__, dev_path(dev));
return;
}

/* Write the _DSM that toggles power with provided GPIO. */
acpigen_write_scope(scope);
acpigen_write_dsm(INTEL_USB4_RETIMER_DSM_UUID, usb4_retimer_callbacks,
ARRAY_SIZE(usb4_retimer_callbacks), (void *)&config->power_gpio);
acpigen_pop_len(); /* Scope */

printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name,
dev_path(dev));
}

static struct device_operations usb4_retimer_dev_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
.acpi_fill_ssdt = usb4_retimer_fill_ssdt,
};

static void usb4_retimer_enable(struct device *dev)
{
dev->ops = &usb4_retimer_dev_ops;
}

struct chip_operations drivers_intel_usb4_retimer_ops = {
CHIP_NAME("Intel USB4 Retimer")
.enable_dev = usb4_retimer_enable
};
8 changes: 0 additions & 8 deletions src/drivers/intel/wifi/Kconfig

This file was deleted.

7 changes: 0 additions & 7 deletions src/drivers/intel/wifi/Makefile.inc

This file was deleted.

10 changes: 0 additions & 10 deletions src/drivers/intel/wifi/chip.h

This file was deleted.

157 changes: 0 additions & 157 deletions src/drivers/intel/wifi/wifi.c

This file was deleted.

2 changes: 2 additions & 0 deletions src/drivers/ipmi/ipmi_kcs.h
Expand Up @@ -33,6 +33,8 @@ extern int ipmi_kcs_message(int port, int netfn, int lun, int cmd,
* returns CB_SUCCESS on success and CB_ERR if an error occurred. */
enum cb_err ipmi_kcs_premem_init(const u16 port, const u16 device);

void ipmi_bmc_version(uint8_t *ipmi_bmc_major_revision, uint8_t *ipmi_bmc_minor_revision);

struct ipmi_rsp {
uint8_t lun;
uint8_t cmd;
Expand Down
19 changes: 19 additions & 0 deletions src/drivers/ipmi/ipmi_kcs_ops.c
Expand Up @@ -8,6 +8,7 @@
* end
*/

#include <arch/io.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pnp.h>
Expand All @@ -28,6 +29,9 @@
static u8 ipmi_revision_major = 0x1;
static u8 ipmi_revision_minor = 0x0;

static u8 bmc_revision_major = 0x0;
static u8 bmc_revision_minor = 0x0;

static int ipmi_get_device_id(struct device *dev, struct ipmi_devid_rsp *rsp)
{
int ret;
Expand Down Expand Up @@ -144,6 +148,9 @@ static void ipmi_kcs_init(struct device *dev)
ipmi_revision_minor = IPMI_IPMI_VERSION_MINOR(rsp.ipmi_version);
ipmi_revision_major = IPMI_IPMI_VERSION_MAJOR(rsp.ipmi_version);

bmc_revision_major = rsp.fw_rev1;
bmc_revision_minor = rsp.fw_rev2;

memcpy(&man_id, rsp.manufacturer_id,
sizeof(rsp.manufacturer_id));

Expand Down Expand Up @@ -272,6 +279,18 @@ static void ipmi_ssdt(const struct device *dev)
}
#endif

void ipmi_bmc_version(uint8_t *ipmi_bmc_major_revision, uint8_t *ipmi_bmc_minor_revision)
{
if (!bmc_revision_major || !bmc_revision_minor) {
printk(BIOS_ERR, "IPMI: BMC revision missing\n");
*ipmi_bmc_major_revision = 0;
*ipmi_bmc_minor_revision = 0;
} else {
*ipmi_bmc_major_revision = bmc_revision_major;
*ipmi_bmc_minor_revision = bmc_revision_minor;
}
}

#if CONFIG(GENERATE_SMBIOS_TABLES)
static int ipmi_smbios_data(struct device *dev, int *handle,
unsigned long *current)
Expand Down
1 change: 1 addition & 0 deletions src/drivers/ipmi/ipmi_kcs_ops_premem.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#include <arch/io.h>
#include <console/console.h>
#include <device/pnp.h>
#include <delay.h>
Expand Down
9 changes: 5 additions & 4 deletions src/drivers/ipmi/ocp/ipmi_ocp.c
Expand Up @@ -7,14 +7,15 @@
* end
*/

#include <arch/cpu.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pnp.h>
#include <string.h>
#include <drivers/ipmi/ipmi_kcs.h>
#include <intelblocks/cpulib.h>
#include <arch/cpu.h>
#include "chip.h"
#include "drivers/ipmi/ipmi_kcs.h"
#include <string.h>
#include <types.h>

#include "ipmi_ocp.h"

static int ipmi_set_processor_information_param1(struct device *dev)
Expand Down
22 changes: 22 additions & 0 deletions src/drivers/mrc_cache/Kconfig
Expand Up @@ -35,4 +35,26 @@ config MRC_WRITE_NV_LATE
normal, select this item. This will cause the write to occur at
BS_OS_RESUME_CHECK-ENTRY.

config MRC_STASH_TO_CBMEM
bool
default y if MRC_WRITE_NV_LATE || BOOT_DEVICE_SPI_FLASH_NO_EARLY_WRITES
default n
help
Instead of writing back MRC_CACHE training data back to the
MRC_CACHE right away, stash the data into cbmem. This data
will be written back later to MRC_CACHE. This is selected
for platforms which either do not support writes to SPI
flash in early stages
(BOOT_DEVICE_SPI_FLASH_NO_EARLY_WRITES) or the platforms
that need to write back the MRC data in late ramstage boot
states (MRC_WRITE_NV_LATE).

config MRC_SAVE_HASH_IN_TPM
bool "Save a hash of the MRC_CACHE data in TPM NVRAM"
depends on VBOOT_STARTS_IN_BOOTBLOCK && TPM2 && !TPM1
default y
help
Store a hash of the MRC_CACHE training data in a TPM NVRAM
space to ensure that it cannot be tampered with.

endif # CACHE_MRC_SETTINGS
201 changes: 143 additions & 58 deletions src/drivers/mrc_cache/mrc_cache.c
Expand Up @@ -10,6 +10,8 @@
#include <fmap.h>
#include <ip_checksum.h>
#include <region_file.h>
#include <security/vboot/antirollback.h>
#include <security/vboot/mrc_cache_hash_tpm.h>
#include <security/vboot/vboot_common.h>
#include <spi_flash.h>

Expand Down Expand Up @@ -44,6 +46,7 @@ struct cache_region {
uint32_t cbmem_id;
int type;
int elog_slot;
uint32_t tpm_hash_index;
int flags;
};

Expand All @@ -52,6 +55,7 @@ static const struct cache_region recovery_training = {
.cbmem_id = CBMEM_ID_MRCDATA,
.type = MRC_TRAINING_DATA,
.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_RECOVERY,
.tpm_hash_index = MRC_REC_HASH_NV_INDEX,
#if CONFIG(HAS_RECOVERY_MRC_CACHE)
.flags = RECOVERY_FLAG,
#else
Expand All @@ -64,6 +68,7 @@ static const struct cache_region normal_training = {
.cbmem_id = CBMEM_ID_MRCDATA,
.type = MRC_TRAINING_DATA,
.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_NORMAL,
.tpm_hash_index = MRC_RW_HASH_NV_INDEX,
.flags = NORMAL_FLAG | RECOVERY_FLAG,
};

Expand All @@ -72,6 +77,7 @@ static const struct cache_region variable_data = {
.cbmem_id = CBMEM_ID_VAR_MRCDATA,
.type = MRC_VARIABLE_DATA,
.elog_slot = ELOG_MEM_CACHE_UPDATE_SLOT_VARIABLE,
.tpm_hash_index = 0,
.flags = NORMAL_FLAG | RECOVERY_FLAG,
};

Expand All @@ -82,6 +88,11 @@ static const struct cache_region *cache_regions[] = {
&variable_data,
};

/* TPM MRC hash functionality depends on vboot starting before memory init. */
_Static_assert(!CONFIG(MRC_SAVE_HASH_IN_TPM) ||
CONFIG(VBOOT_STARTS_IN_BOOTBLOCK),
"for TPM MRC hash functionality, vboot must start in bootblock");

static int lookup_region_by_name(const char *name, struct region *r)
{
if (fmap_locate_area(name, r) == 0)
Expand Down Expand Up @@ -117,7 +128,7 @@ static const struct cache_region *lookup_region(struct region *r, int type)

if (cr == NULL) {
printk(BIOS_ERR, "MRC: failed to locate region type %d.\n",
type);
type);
return NULL;
}

Expand Down Expand Up @@ -169,20 +180,31 @@ static int mrc_header_valid(struct region_device *rdev, struct mrc_metadata *md)
return 0;
}

static int mrc_data_valid(const struct mrc_metadata *md,
static int mrc_data_valid(int type, const struct mrc_metadata *md,
void *data, size_t data_size)
{
uint16_t checksum;
const struct cache_region *cr = lookup_region_type(type);
uint32_t hash_idx;

if (cr == NULL)
return -1;

if (md->data_size != data_size)
return -1;

checksum = compute_ip_checksum(data, data_size);
hash_idx = cr->tpm_hash_index;
if (hash_idx && CONFIG(MRC_SAVE_HASH_IN_TPM)) {
if (!mrc_cache_verify_hash(hash_idx, data, data_size))
return -1;
} else {
checksum = compute_ip_checksum(data, data_size);

if (md->data_checksum != checksum) {
printk(BIOS_ERR, "MRC: data checksum mismatch: %x vs %x\n",
md->data_checksum, checksum);
return -1;
if (md->data_checksum != checksum) {
printk(BIOS_ERR, "MRC: data checksum mismatch: %x vs %x\n",
md->data_checksum, checksum);
return -1;
}
}

return 0;
Expand Down Expand Up @@ -260,12 +282,12 @@ static int mrc_cache_find_current(int type, uint32_t version,
return rdev_chain(rdev, rdev, md_size, data_size);
}

int mrc_cache_load_current(int type, uint32_t version, void *buffer,
size_t buffer_size)
ssize_t mrc_cache_load_current(int type, uint32_t version, void *buffer,
size_t buffer_size)
{
struct region_device rdev;
struct mrc_metadata md;
size_t data_size;
ssize_t data_size;

if (mrc_cache_find_current(type, version, &rdev, &md) < 0)
return -1;
Expand All @@ -277,10 +299,10 @@ int mrc_cache_load_current(int type, uint32_t version, void *buffer,
if (rdev_readat(&rdev, buffer, 0, data_size) != data_size)
return -1;

if (mrc_data_valid(&md, buffer, data_size) < 0)
if (mrc_data_valid(type, &md, buffer, data_size) < 0)
return -1;

return 0;
return data_size;
}

void *mrc_cache_current_mmap_leak(int type, uint32_t version,
Expand All @@ -304,25 +326,37 @@ void *mrc_cache_current_mmap_leak(int type, uint32_t version,
return NULL;
}

if (mrc_data_valid(&md, data, region_device_size) < 0)
if (mrc_data_valid(type, &md, data, region_device_size) < 0)
return NULL;

return data;
}

static bool mrc_cache_needs_update(const struct region_device *rdev,
const struct cbmem_entry *to_be_updated)
const struct mrc_metadata *new_md,
const void *new_data, size_t new_data_size)
{
void *mapping;
void *mapping, *data_mapping;
size_t size = region_device_sz(rdev);
bool need_update = false;

if (cbmem_entry_size(to_be_updated) != size)
if (new_data_size != size)
return true;

mapping = rdev_mmap_full(rdev);
if (mapping == NULL) {
printk(BIOS_ERR, "MRC: cannot mmap existing cache.\n");
return true;
}
data_mapping = mapping + sizeof(struct mrc_metadata);

/* we need to compare the md and the data separately */
/* check the mrc_metadata */
if (memcmp(new_md, mapping, sizeof(struct mrc_metadata)))
need_update = true;

if (memcmp(cbmem_entry_start(to_be_updated), mapping, size))
/* check the data */
if (!need_update && memcmp(new_data, data_mapping, new_data_size))
need_update = true;

rdev_munmap(rdev, mapping);
Expand Down Expand Up @@ -357,32 +391,28 @@ static void log_event_cache_update(uint8_t slot, enum result res)
* read and write. The read assumes a memory-mapped boot device that can be used
* to quickly locate and compare the up-to-date data. However, when an update
* is required it uses the writeable region access to perform the update. */
static void update_mrc_cache_by_type(int type)
static void update_mrc_cache_by_type(int type,
struct mrc_metadata *new_md,
const void *new_data,
size_t new_data_size)
{
const struct cache_region *cr;
struct region region;
struct region_device read_rdev;
struct region_device write_rdev;
struct region_file cache_file;
struct mrc_metadata md;
const struct cbmem_entry *to_be_updated;
struct incoherent_rdev backing_irdev;
const struct region_device *backing_rdev;
struct region_device latest_rdev;
const bool fail_bad_data = false;
uint32_t hash_idx;

cr = lookup_region(&region, type);

if (cr == NULL)
return;

to_be_updated = cbmem_entry_find(cr->cbmem_id);
if (to_be_updated == NULL) {
printk(BIOS_ERR, "MRC: No data in cbmem for '%s'.\n",
cr->name);
return;
}

printk(BIOS_DEBUG, "MRC: Checking cached data update for '%s'.\n",
cr->name);

Expand Down Expand Up @@ -411,22 +441,34 @@ static void update_mrc_cache_by_type(int type)

return;

if (!mrc_cache_needs_update(&latest_rdev, to_be_updated)) {
if (!mrc_cache_needs_update(&latest_rdev,
new_md, new_data, new_data_size)) {
printk(BIOS_DEBUG, "MRC: '%s' does not need update.\n", cr->name);
log_event_cache_update(cr->elog_slot, ALREADY_UPTODATE);
return;
}

printk(BIOS_DEBUG, "MRC: cache data '%s' needs update.\n", cr->name);

if (region_file_update_data(&cache_file,
cbmem_entry_start(to_be_updated),
cbmem_entry_size(to_be_updated)) < 0) {
printk(BIOS_DEBUG, "MRC: failed to update '%s'.\n", cr->name);
struct update_region_file_entry entries[] = {
[0] = {
.size = sizeof(struct mrc_metadata),
.data = new_md,
},
[1] = {
.size = new_data_size,
.data = new_data,
},
};
if (region_file_update_data_arr(&cache_file, entries, ARRAY_SIZE(entries)) < 0) {
printk(BIOS_ERR, "MRC: failed to update '%s'.\n", cr->name);
log_event_cache_update(cr->elog_slot, UPDATE_FAILURE);
} else {
printk(BIOS_DEBUG, "MRC: updated '%s'.\n", cr->name);
log_event_cache_update(cr->elog_slot, UPDATE_SUCCESS);
hash_idx = cr->tpm_hash_index;
if (hash_idx && CONFIG(MRC_SAVE_HASH_IN_TPM))
mrc_cache_update_hash(hash_idx, new_data, new_data_size);
}
}

Expand Down Expand Up @@ -548,12 +590,46 @@ static void invalidate_normal_cache(void)
printk(BIOS_ERR, "MRC: invalidation failed for '%s'.\n", name);
}

static void update_mrc_cache(void *unused)
static void update_mrc_cache_from_cbmem(int type)
{
const struct cache_region *cr;
struct region region;
const struct cbmem_entry *to_be_updated;

cr = lookup_region(&region, type);

if (cr == NULL) {
printk(BIOS_ERR, "MRC: could not find cache_region type %d\n", type);
return;
}

to_be_updated = cbmem_entry_find(cr->cbmem_id);

if (to_be_updated == NULL) {
printk(BIOS_INFO, "MRC: No data in cbmem for '%s'.\n",
cr->name);
return;
}

update_mrc_cache_by_type(type,
/* pointer to mrc_cache entry metadata header */
cbmem_entry_start(to_be_updated),
/* pointer to start of mrc_cache entry data */
cbmem_entry_start(to_be_updated) +
sizeof(struct mrc_metadata),
/* size of just data portion of the entry */
cbmem_entry_size(to_be_updated) -
sizeof(struct mrc_metadata));
}

static void finalize_mrc_cache(void *unused)
{
update_mrc_cache_by_type(MRC_TRAINING_DATA);
if (CONFIG(MRC_STASH_TO_CBMEM)) {
update_mrc_cache_from_cbmem(MRC_TRAINING_DATA);

if (CONFIG(MRC_SETTINGS_VARIABLE_DATA))
update_mrc_cache_by_type(MRC_VARIABLE_DATA);
if (CONFIG(MRC_SETTINGS_VARIABLE_DATA))
update_mrc_cache_from_cbmem(MRC_VARIABLE_DATA);
}

if (CONFIG(MRC_CLEAR_NORMAL_CACHE_ON_RECOVERY_RETRAIN))
invalidate_normal_cache();
Expand All @@ -562,11 +638,9 @@ static void update_mrc_cache(void *unused)
}

int mrc_cache_stash_data(int type, uint32_t version, const void *data,
size_t size)
size_t size)
{
const struct cache_region *cr;
size_t cbmem_size;
struct mrc_metadata *md;

cr = lookup_region_type(type);
if (cr == NULL) {
Expand All @@ -575,34 +649,45 @@ int mrc_cache_stash_data(int type, uint32_t version, const void *data,
return -1;
}

cbmem_size = sizeof(*md) + size;

md = cbmem_add(cr->cbmem_id, cbmem_size);

if (md == NULL) {
printk(BIOS_ERR, "MRC: failed to add '%s' to cbmem.\n",
cr->name);
return -1;
struct mrc_metadata md = {
.signature = MRC_DATA_SIGNATURE,
.data_size = size,
.version = version,
.data_checksum = compute_ip_checksum(data, size),
};
md.header_checksum =
compute_ip_checksum(&md, sizeof(struct mrc_metadata));

if (CONFIG(MRC_STASH_TO_CBMEM)) {
/* Store data in cbmem for use in ramstage */
struct mrc_metadata *cbmem_md;
size_t cbmem_size;
cbmem_size = sizeof(*cbmem_md) + size;

cbmem_md = cbmem_add(cr->cbmem_id, cbmem_size);

if (cbmem_md == NULL) {
printk(BIOS_ERR, "MRC: failed to add '%s' to cbmem.\n",
cr->name);
return -1;
}

memcpy(cbmem_md, &md, sizeof(*cbmem_md));
/* cbmem_md + 1 is the pointer to the mrc_cache data */
memcpy(cbmem_md + 1, data, size);
} else {
/* Otherwise store to mrc_cache right away */
update_mrc_cache_by_type(type, &md, data, size);
}

memset(md, 0, sizeof(*md));
md->signature = MRC_DATA_SIGNATURE;
md->data_size = size;
md->version = version;
md->data_checksum = compute_ip_checksum(data, size);
md->header_checksum = compute_ip_checksum(md, sizeof(*md));
memcpy(&md[1], data, size);

return 0;
}

/*
* Ensures MRC training data is stored into SPI after PCI enumeration is done.
* Some implementations may require this to be later than others.
*/

#if CONFIG(MRC_WRITE_NV_LATE)
BOOT_STATE_INIT_ENTRY(BS_OS_RESUME_CHECK, BS_ON_ENTRY, update_mrc_cache, NULL);
BOOT_STATE_INIT_ENTRY(BS_OS_RESUME_CHECK, BS_ON_ENTRY, finalize_mrc_cache, NULL);
#else
BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_EXIT, update_mrc_cache, NULL);
BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_EXIT, finalize_mrc_cache, NULL);
#endif
27 changes: 6 additions & 21 deletions src/drivers/pc80/rtc/Makefile.inc
@@ -1,29 +1,14 @@
ifeq ($(CONFIG_ARCH_X86),y)

bootblock-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_boot.c
verstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_boot.c
postcar-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_boot.c
romstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_boot.c
ramstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_boot.c
all-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_boot.c

bootblock-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c
postcar-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c
romstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c
ramstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c
smm-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c
all-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c
smm-$(CONFIG_DRIVERS_MC146818) += mc146818rtc.c

bootblock-$(CONFIG_USE_OPTION_TABLE) += option.c
verstage-$(CONFIG_USE_OPTION_TABLE) += option.c
postcar-$(CONFIG_USE_OPTION_TABLE) += option.c
romstage-$(CONFIG_USE_OPTION_TABLE) += option.c
ramstage-$(CONFIG_USE_OPTION_TABLE) += option.c
smm-$(CONFIG_USE_OPTION_TABLE) += option.c
all-$(CONFIG_USE_OPTION_TABLE) += option.c
smm-$(CONFIG_USE_OPTION_TABLE) += option.c

bootblock-$(CONFIG_CMOS_POST) += post.c
verstage-$(CONFIG_CMOS_POST) += post.c
postcar-$(CONFIG_CMOS_POST) += post.c
romstage-$(CONFIG_CMOS_POST) += post.c
ramstage-$(CONFIG_CMOS_POST) += post.c
all-$(CONFIG_CMOS_POST) += post.c

ifeq ($(CONFIG_USE_OPTION_TABLE),y)
cbfs-files-$(CONFIG_HAVE_CMOS_DEFAULT) += cmos.default
Expand Down
12 changes: 12 additions & 0 deletions src/drivers/smmstore/Kconfig
Expand Up @@ -6,6 +6,18 @@ config SMMSTORE
default y if PAYLOAD_TIANOCORE
select SPI_FLASH_SMM if BOOT_DEVICE_SPI_FLASH_RW_NOMMAP

config SMMSTORE_V2
bool "Use version 2 of SMMSTORE API"
depends on SMMSTORE
default n
help
Version 2 of SMMSTORE allows secure communication with SMM and
makes no assumptions on the structure of the data stored within.
It splits the store into chunks to allows fault tolerant writes.

By using version 2 you cannot make use of software that expects
a version 1 SMMSTORE.

config SMMSTORE_IN_CBFS
bool
default n
Expand Down
1 change: 1 addition & 0 deletions src/drivers/smmstore/Makefile.inc
@@ -1,3 +1,4 @@
ramstage-$(CONFIG_SMMSTORE) += store.c
ramstage-$(CONFIG_SMMSTORE_V2) += ramstage.c

smm-$(CONFIG_SMMSTORE) += store.c smi.c
76 changes: 76 additions & 0 deletions src/drivers/smmstore/ramstage.c
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */

#include <bootstate.h>
#include <cpu/x86/smm.h>
#include <commonlib/helpers.h>
#include <commonlib/region.h>
#include <console/console.h>
#include <smmstore.h>
#include <types.h>
#include <cbmem.h>

static struct smmstore_params_info info;

void lb_smmstorev2(struct lb_header *header)
{
struct lb_record *rec;
struct lb_smmstorev2 *store;
const struct cbmem_entry *e;

e = cbmem_entry_find(CBMEM_ID_SMM_COMBUFFER);
if (!e)
return;

rec = lb_new_record(header);
store = (struct lb_smmstorev2 *)rec;

store->tag = LB_TAG_SMMSTOREV2;
store->size = sizeof(*store);
store->com_buffer = (uintptr_t)cbmem_entry_start(e);
store->com_buffer_size = cbmem_entry_size(e);
store->mmap_addr = info.mmap_addr;
store->num_blocks = info.num_blocks;
store->block_size = info.block_size;
store->apm_cmd = APM_CNT_SMMSTORE;
}

static void init_store(void *unused)
{
struct smmstore_params_init args;
uint32_t eax = ~0;
uint32_t ebx;

if (smmstore_get_info(&info) < 0) {
printk(BIOS_INFO, "SMMSTORE: Failed to get meta data\n");
return;
}

void *ptr = cbmem_add(CBMEM_ID_SMM_COMBUFFER, info.block_size);
if (!ptr) {
printk(BIOS_ERR, "SMMSTORE: Failed to add com buffer\n");
return;
}

args.com_buffer = (uintptr_t)ptr;
args.com_buffer_size = info.block_size;
ebx = (uintptr_t)&args;

printk(BIOS_INFO, "SMMSTORE: Setting up SMI handler\n");

/* Issue SMI using APM to update the com buffer and to lock the SMMSTORE */
__asm__ __volatile__ (
"outb %%al, %%dx"
: "=a" (eax)
: "a" ((SMMSTORE_CMD_INIT << 8) | APM_CNT_SMMSTORE),
"b" (ebx),
"d" (APM_CNT)
: "memory");

if (eax != SMMSTORE_RET_SUCCESS) {
printk(BIOS_ERR, "SMMSTORE: Failed to install com buffer\n");
return;
}
}

/* The SMI APM handler is installed at DEV_INIT phase */
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT, BS_ON_EXIT, init_store, NULL);
81 changes: 78 additions & 3 deletions src/drivers/smmstore/smi.c
Expand Up @@ -23,8 +23,7 @@ static int range_check(void *start, size_t size)
return 0;
}

/* Param is usually EBX, ret in EAX */
uint32_t smmstore_exec(uint8_t command, void *param)
static uint32_t smmstorev1_exec(uint8_t command, void *param)
{
uint32_t ret = SMMSTORE_RET_FAILURE;

Expand Down Expand Up @@ -66,13 +65,89 @@ uint32_t smmstore_exec(uint8_t command, void *param)
ret = SMMSTORE_RET_SUCCESS;
break;
}
default:
printk(BIOS_DEBUG,
"Unknown SMM store v1 command: 0x%02x\n", command);
ret = SMMSTORE_RET_UNSUPPORTED;
break;
}

return ret;
}

static uint32_t smmstorev2_exec(uint8_t command, void *param)
{
uint32_t ret = SMMSTORE_RET_FAILURE;

switch (command) {
case SMMSTORE_CMD_INIT: {
printk(BIOS_DEBUG, "Init SMM store\n");
struct smmstore_params_init *params = param;

if (range_check(params, sizeof(*params)) != 0)
break;

void *buf = (void *)(uintptr_t)params->com_buffer;

if (range_check(buf, params->com_buffer_size) != 0)
break;

if (smmstore_init(buf, params->com_buffer_size) == 0)
ret = SMMSTORE_RET_SUCCESS;
break;
}
case SMMSTORE_CMD_RAW_READ: {
printk(BIOS_DEBUG, "Raw read from SMM store, param = %p\n", param);
struct smmstore_params_raw_read *params = param;

if (range_check(params, sizeof(*params)) != 0)
break;

if (smmstore_rawread_region(params->block_id, params->bufoffset,
params->bufsize) == 0)
ret = SMMSTORE_RET_SUCCESS;
break;
}
case SMMSTORE_CMD_RAW_WRITE: {
printk(BIOS_DEBUG, "Raw write to SMM store, param = %p\n", param);
struct smmstore_params_raw_write *params = param;

if (range_check(params, sizeof(*params)) != 0)
break;

if (smmstore_rawwrite_region(params->block_id, params->bufoffset,
params->bufsize) == 0)
ret = SMMSTORE_RET_SUCCESS;
break;
}
case SMMSTORE_CMD_RAW_CLEAR: {
printk(BIOS_DEBUG, "Raw clear SMM store, param = %p\n", param);
struct smmstore_params_raw_clear *params = param;

if (range_check(params, sizeof(*params)) != 0)
break;

if (smmstore_rawclear_region(params->block_id) == 0)
ret = SMMSTORE_RET_SUCCESS;
break;
}
default:
printk(BIOS_DEBUG,
"Unknown SMM store command: 0x%02x\n", command);
"Unknown SMM store v2 command: 0x%02x\n", command);
ret = SMMSTORE_RET_UNSUPPORTED;
break;
}

return ret;
}

uint32_t smmstore_exec(uint8_t command, void *param)
{
if (!param)
return SMMSTORE_RET_FAILURE;

if (CONFIG(SMMSTORE_V2))
return smmstorev2_exec(command, param);
else
return smmstorev1_exec(command, param);
}
197 changes: 197 additions & 0 deletions src/drivers/smmstore/store.c
Expand Up @@ -262,3 +262,200 @@ int smmstore_clear_region(void)

return 0;
}


/* Implementation of Version 2 */

static bool store_initialized;
static struct mem_region_device mdev_com_buf;

static int smmstore_rdev_chain(struct region_device *rdev)
{
if (!store_initialized)
return -1;

return rdev_chain_full(rdev, &mdev_com_buf.rdev);
}

/**
* Call once before using the store. In SMM this must be called through an
* APM SMI handler providing the communication buffer address and length.
*/
int smmstore_init(void *buf, size_t len)
{
if (!buf || len < SMM_BLOCK_SIZE)
return -1;

if (store_initialized)
return -1;

mem_region_device_rw_init(&mdev_com_buf, buf, len);

store_initialized = true;

return 0;
}

#if ENV_RAMSTAGE
/**
* Provide metadata for the coreboot tables.
* Must only be called in ramstage, but not in SMM.
*/
int smmstore_get_info(struct smmstore_params_info *out)
{
struct region_device store;

if (lookup_store(&store) < 0) {
printk(BIOS_ERR, "smm store: lookup of store failed\n");
return -1;
}

if (!IS_ALIGNED(region_device_offset(&store), SMM_BLOCK_SIZE)) {
printk(BIOS_ERR, "smm store: store not aligned to block size\n");
return -1;
}

out->block_size = SMM_BLOCK_SIZE;
out->num_blocks = region_device_sz(&store) / SMM_BLOCK_SIZE;

/* FIXME: Broken EDK2 always assumes memory mapped Firmware Block Volumes */
out->mmap_addr = (uintptr_t)rdev_mmap_full(&store);

printk(BIOS_DEBUG, "smm store: %d # blocks with size 0x%x\n",
out->num_blocks, out->block_size);

return 0;
}
#endif

/* Returns -1 on error, 0 on success */
static int lookup_block_in_store(struct region_device *store, uint32_t block_id)
{
if (lookup_store(store) < 0) {
printk(BIOS_ERR, "smm store: lookup of store failed\n");
return -1;
}

if ((block_id * SMM_BLOCK_SIZE) >= region_device_sz(store)) {
printk(BIOS_ERR, "smm store: block ID out of range\n");
return -1;
}

return 0;
}

/* Returns NULL on error, pointer from rdev_mmap on success */
static void *mmap_com_buf(struct region_device *com_buf, uint32_t offset, uint32_t bufsize)
{
if (smmstore_rdev_chain(com_buf) < 0) {
printk(BIOS_ERR, "smm store: lookup of com buffer failed\n");
return NULL;
}

if (offset >= region_device_sz(com_buf)) {
printk(BIOS_ERR, "smm store: offset out of range\n");
return NULL;
}

void *ptr = rdev_mmap(com_buf, offset, bufsize);
if (!ptr)
printk(BIOS_ERR, "smm store: not enough space for new data\n");

return ptr;
}

/**
* Reads the specified block of the SMMSTORE and places it in the communication
* buffer.
* @param block_id The id of the block to operate on
* @param offset Offset within the block.
* Must be smaller than the block size.
* @param bufsize Size of chunk to read within the block.
* Must be smaller than the block size.
* @return Returns -1 on error, 0 on success.
*/
int smmstore_rawread_region(uint32_t block_id, uint32_t offset, uint32_t bufsize)
{
struct region_device store;
struct region_device com_buf;

if (lookup_block_in_store(&store, block_id) < 0)
return -1;

void *ptr = mmap_com_buf(&com_buf, offset, bufsize);
if (!ptr)
return -1;

printk(BIOS_DEBUG, "smm store: reading %p block %d, offset=0x%x, size=%x\n",
ptr, block_id, offset, bufsize);

ssize_t ret = rdev_readat(&store, ptr, block_id * SMM_BLOCK_SIZE + offset, bufsize);
rdev_munmap(&com_buf, ptr);
if (ret < 0)
return -1;

return 0;
}

/**
* Writes the specified block of the SMMSTORE by reading it from the communication
* buffer.
* @param block_id The id of the block to operate on
* @param offset Offset within the block.
* Must be smaller than the block size.
* @param bufsize Size of chunk to read within the block.
* Must be smaller than the block size.
* @return Returns -1 on error, 0 on success.
*/
int smmstore_rawwrite_region(uint32_t block_id, uint32_t offset, uint32_t bufsize)
{
struct region_device store;
struct region_device com_buf;

if (lookup_block_in_store(&store, block_id) < 0)
return -1;

if (rdev_chain(&store, &store, block_id * SMM_BLOCK_SIZE + offset, bufsize)) {
printk(BIOS_ERR, "smm store: not enough space for new data\n");
return -1;
}

void *ptr = mmap_com_buf(&com_buf, offset, bufsize);
if (!ptr)
return -1;

printk(BIOS_DEBUG, "smm store: writing %p block %d, offset=0x%x, size=%x\n",
ptr, block_id, offset, bufsize);

ssize_t ret = rdev_writeat(&store, ptr, 0, bufsize);
rdev_munmap(&com_buf, ptr);
if (ret < 0)
return -1;

return 0;
}

/**
* Erases the specified block of the SMMSTORE. The communication buffer remains untouched.
*
* @param block_id The id of the block to operate on
*
* @return Returns -1 on error, 0 on success.
*/
int smmstore_rawclear_region(uint32_t block_id)
{
struct region_device store;

if (lookup_block_in_store(&store, block_id) < 0)
return -1;

ssize_t ret = rdev_eraseat(&store, block_id * SMM_BLOCK_SIZE, SMM_BLOCK_SIZE);
if (ret != SMM_BLOCK_SIZE) {
printk(BIOS_ERR, "smm store: erasing block failed\n");
return -1;
}

return 0;
}
14 changes: 13 additions & 1 deletion src/drivers/spi/Kconfig
Expand Up @@ -42,8 +42,20 @@ config BOOT_DEVICE_SPI_FLASH_RW_NOMMAP
Provide common implementation of the RW boot device that
doesn't provide mmap() operations.

config BOOT_DEVICE_SPI_FLASH_NO_EARLY_WRITES
bool
default n
depends on BOOT_DEVICE_SPI_FLASH_RW_NOMMAP
help
For platforms who do not allow writes to SPI flash in early
stages like romstage. Not selecting this config will result
in the auto-selection of
BOOT_DEVICE_SPI_FLASH_RW_NOMMAP_EARLY if
BOOT_DEVICE_SPI_FLASH_RW_NOMMAP is selected by the platform.

config BOOT_DEVICE_SPI_FLASH_RW_NOMMAP_EARLY
bool
default y if BOOT_DEVICE_SPI_FLASH_RW_NOMMAP && !BOOT_DEVICE_SPI_FLASH_NO_EARLY_WRITES
default n
depends on BOOT_DEVICE_SPI_FLASH_RW_NOMMAP
help
Expand Down Expand Up @@ -152,5 +164,5 @@ config SPI_FLASH_HAS_VOLATILE_GROUP

endif # SPI_FLASH

config HAVE_SPI_CONSOLE_SUPPORT
config HAVE_EM100PRO_SPI_CONSOLE_SUPPORT
def_bool n
2 changes: 1 addition & 1 deletion src/drivers/spi/Makefile.inc
Expand Up @@ -2,7 +2,7 @@

subdirs-y += tpm

ifeq ($(CONFIG_SPI_CONSOLE),y)
ifeq ($(CONFIG_EM100PRO_SPI_CONSOLE),y)
ramstage-y += spiconsole.c
smm-y += spiconsole.c
endif
Expand Down
4 changes: 3 additions & 1 deletion src/drivers/spi/spi_sdcard.c
Expand Up @@ -354,7 +354,9 @@ static int spi_sdcard_do_app_command(const struct spi_sdcard *card,
uint32_t *out_register)
{
/* CMD55 */
spi_sdcard_do_command(card, APP_CMD, 0, NULL);
if (spi_sdcard_do_command(card, APP_CMD, 0, NULL))
return -1;

return spi_sdcard_do_command_help(card, 1, cmd, argument, out_register);
}

Expand Down
61 changes: 18 additions & 43 deletions src/drivers/ti/sn65dsi86bridge/sn65dsi86bridge.c
Expand Up @@ -259,11 +259,11 @@ static void sn65dsi86_bridge_valid_dp_rates(uint8_t bus, uint8_t chip, bool rate
DP_BRIDGE_DPCD_REV, 1, DPCD_READ, &dpcd_val);
if (dpcd_val >= DP_BRIDGE_14) {
/* eDP 1.4 devices must provide a custom table */
uint8_t sink_rates[DP_MAX_SUPPORTED_RATES * 2];
uint16_t sink_rates[DP_MAX_SUPPORTED_RATES] = {0};

sn65dsi86_bridge_dpcd_request(bus, chip, DP_SUPPORTED_LINK_RATES,
sizeof(sink_rates),
DPCD_READ, sink_rates);
DPCD_READ, (void *)sink_rates);
for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
rate_per_200khz = le16_to_cpu(sink_rates[i]);

Expand All @@ -288,14 +288,12 @@ static void sn65dsi86_bridge_valid_dp_rates(uint8_t bus, uint8_t chip, bool rate
}

/* On older versions best we can do is use DP_MAX_LINK_RATE */
sn65dsi86_bridge_dpcd_request(bus, chip,
DP_MAX_LINK_RATE, 1, DPCD_READ, &dpcd_val);
sn65dsi86_bridge_dpcd_request(bus, chip, DP_MAX_LINK_RATE, 1, DPCD_READ, &dpcd_val);

switch (dpcd_val) {
default:
printk(BIOS_ERR,
"Unexpected max rate (%#x); assuming 5.4 GHz\n",
(int)dpcd_val);
printk(BIOS_ERR, "Unexpected max rate (%#x); assuming 5.4 GHz\n",
(int)dpcd_val);
/* fall through */
case DP_LINK_BW_5_4:
rate_valid[7] = 1;
Expand Down Expand Up @@ -415,44 +413,20 @@ static void sn65dsi86_bridge_link_training(uint8_t bus, uint8_t chip)
sn65dsi86_bridge_dpcd_request(bus, chip,
DP_BRIDGE_CONFIGURATION_SET, 1, DPCD_WRITE, &buf);

/* semi auto link training mode */
i2c_writeb(bus, chip, SN_ML_TX_MODE_REG, 0xa);
int i; /* Kernel driver suggests to retry this up to 10 times if it fails. */
for (i = 0; i < 10; i++) {
i2c_writeb(bus, chip, SN_ML_TX_MODE_REG, SEMI_AUTO_LINK_TRAINING);

if (!wait_ms(500,
!(i2c_readb(bus, chip, SN_ML_TX_MODE_REG, &buf)) &&
(buf & NORMAL_MODE))) {
printk(BIOS_ERR, "ERROR: Link training failed");
if (!wait_ms(500, !(i2c_readb(bus, chip, SN_ML_TX_MODE_REG, &buf)) &&
(buf == NORMAL_MODE || buf == MAIN_LINK_OFF))) {
printk(BIOS_ERR, "ERROR: unexpected link training state: %#x\n", buf);
return;
}
if (buf == NORMAL_MODE)
return;
}

}

static enum cb_err sn65dsi86_bridge_get_plug_in_status(uint8_t bus, uint8_t chip)
{
int val;
uint8_t buf;

val = i2c_readb(bus, chip, SN_HPD_DISABLE_REG, &buf);
if (val == 0 && (buf & HPD_DISABLE))
return CB_SUCCESS;

return CB_ERR;
}

/*
* support bridge HPD function some hardware versions do not support bridge hdp,
* we use 360ms to try to get the hpd single now, if we can not get bridge hpd single,
* it will delay 360ms, also meet the bridge power timing request, to be compatible
* all of the hardware versions
*/
static void sn65dsi86_bridge_wait_hpd(uint8_t bus, uint8_t chip)
{
if (wait_ms(400, sn65dsi86_bridge_get_plug_in_status(bus, chip)))
return;

printk(BIOS_WARNING, "HPD detection failed, force hpd\n");

/* Force HPD */
i2c_write_field(bus, chip, SN_HPD_DISABLE_REG, HPD_DISABLE, 1, 0);
printk(BIOS_ERR, "ERROR: Link training failed 10 times\n");
}

static void sn65dsi86_bridge_assr_config(uint8_t bus, uint8_t chip, int enable)
Expand All @@ -476,7 +450,8 @@ static int sn65dsi86_bridge_dp_lane_config(uint8_t bus, uint8_t chip)

void sn65dsi86_bridge_init(uint8_t bus, uint8_t chip, enum dp_pll_clk_src ref_clk)
{
sn65dsi86_bridge_wait_hpd(bus, chip);
/* disable HPD */
i2c_write_field(bus, chip, SN_HPD_DISABLE_REG, HPD_DISABLE, 1, 0);

/* set refclk to 19.2 MHZ */
i2c_write_field(bus, chip, SN_DPPLL_SRC_REG, ref_clk, 7, 1);
Expand Down
10 changes: 9 additions & 1 deletion src/drivers/wifi/generic/Kconfig
@@ -1,11 +1,19 @@
config DRIVERS_WIFI_GENERIC
bool
default n
depends on HAVE_ACPI_TABLES
help
When enabled, add identifiers in ACPI tables that are common
to WiFi chipsets from multiple vendors.

config DRIVERS_INTEL_WIFI
bool "Support Intel PCI-e WiFi adapters"
depends on PCI
default y if PCIEXP_PLUGIN_SUPPORT
select DRIVERS_WIFI_GENERIC
help
When enabled, add identifiers in ACPI and SMBIOS tables to
make OS drivers work with certain Intel PCI-e WiFi chipsets.

if DRIVERS_WIFI_GENERIC

config USE_SAR
Expand Down
4 changes: 4 additions & 0 deletions src/drivers/wifi/generic/Makefile.inc
@@ -1 +1,5 @@
ramstage-$(CONFIG_DRIVERS_WIFI_GENERIC) += generic.c

cbfs-files-$(CONFIG_WIFI_SAR_CBFS) += wifi_sar_defaults.hex
wifi_sar_defaults.hex-file := $(call strip_quotes,$(CONFIG_WIFI_SAR_CBFS_FILEPATH))
wifi_sar_defaults.hex-type := raw
24 changes: 0 additions & 24 deletions src/drivers/wifi/generic/chip.h
Expand Up @@ -6,33 +6,9 @@
/**
* struct drivers_wifi_generic_config - Data structure to contain generic wifi config
* @wake: Wake pin for ACPI _PRW
* @maxsleep: Maximum sleep state to wake from
*/
struct drivers_wifi_generic_config {
unsigned int wake;
unsigned int maxsleep;
};

/**
* wifi_generic_fill_ssdt() - Fill ACPI SSDT table for WiFi controller
* @dev: Device structure corresponding to WiFi controller.
* @config: Generic wifi config required to fill ACPI SSDT table.
*
* This function implements common device operation to help fill ACPI SSDT
* table for WiFi controller.
*/
void wifi_generic_fill_ssdt(const struct device *dev,
const struct drivers_wifi_generic_config *config);

/**
* wifi_generic_acpi_name() - Get ACPI name for WiFi controller
* @dev: Device structure corresponding to WiFi controller.
*
* This function implements common device operation to get the ACPI name for
* WiFi controller.
*
* Return: string representing the ACPI name for WiFi controller.
*/
const char *wifi_generic_acpi_name(const struct device *dev);

#endif /* _GENERIC_WIFI_H_ */
143 changes: 131 additions & 12 deletions src/drivers/wifi/generic/generic.c
Expand Up @@ -4,8 +4,12 @@
#include <acpi/acpigen.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_def.h>
#include <device/pci_ids.h>
#include <elog.h>
#include <sar.h>
#include <smbios.h>
#include <string.h>
#include <wrdd.h>
#include "chip.h"
Expand Down Expand Up @@ -33,18 +37,23 @@
*/
#define WIFI_ACPI_NAME_MAX_LEN 5

#if CONFIG(HAVE_ACPI_TABLES)
__weak
int get_wifi_sar_limits(struct wifi_sar_limits *sar_limits)
{
return -1;
}

static void emit_sar_acpi_structures(void)
static void emit_sar_acpi_structures(const struct device *dev)
{
int i, j, package_size;
struct wifi_sar_limits sar_limits;
struct wifi_sar_delta_table *wgds;

/* CBFS SAR and SAR ACPI tables are currently used only by Intel WiFi devices. */
if (dev->vendor != PCI_VENDOR_ID_INTEL)
return;

/* Retrieve the sar limits data */
if (get_wifi_sar_limits(&sar_limits) < 0) {
printk(BIOS_ERR, "Error: failed from getting SAR limits!\n");
Expand Down Expand Up @@ -158,11 +167,11 @@ static void emit_sar_acpi_structures(void)
acpigen_pop_len();
}

void wifi_generic_fill_ssdt(const struct device *dev,
const struct drivers_wifi_generic_config *config)
static void wifi_generic_fill_ssdt(const struct device *dev)
{
const char *path;
u32 address;
const struct drivers_wifi_generic_config *config = dev->chip_info;

if (!dev->enabled)
return;
Expand All @@ -187,7 +196,7 @@ void wifi_generic_fill_ssdt(const struct device *dev,

/* Wake capabilities */
if (config)
acpigen_write_PRW(config->wake, config->maxsleep);
acpigen_write_PRW(config->wake, ACPI_S3);

/* Fill regulatory domain structure */
if (CONFIG(HAVE_REGULATORY_DOMAIN)) {
Expand All @@ -212,7 +221,7 @@ void wifi_generic_fill_ssdt(const struct device *dev,

/* Fill Wifi sar related ACPI structures */
if (CONFIG(USE_SAR))
emit_sar_acpi_structures();
emit_sar_acpi_structures(dev);

acpigen_pop_len(); /* Device */
acpigen_pop_len(); /* Scope */
Expand All @@ -221,7 +230,7 @@ void wifi_generic_fill_ssdt(const struct device *dev,
dev->chip_ops ? dev->chip_ops->name : "", dev_path(dev));
}

const char *wifi_generic_acpi_name(const struct device *dev)
static const char *wifi_generic_acpi_name(const struct device *dev)
{
static char wifi_acpi_name[WIFI_ACPI_NAME_MAX_LEN];

Expand All @@ -230,17 +239,63 @@ const char *wifi_generic_acpi_name(const struct device *dev)
(dev_path_encode(dev) & 0xff));
return wifi_acpi_name;
}
#endif

static void wifi_generic_fill_ssdt_generator(const struct device *dev)
static void wifi_pci_dev_init(struct device *dev)
{
wifi_generic_fill_ssdt(dev, dev->chip_info);
if (pci_dev_is_wake_source(dev))
elog_add_event_wake(ELOG_WAKE_SOURCE_PME_WIFI, 0);
}

static struct device_operations wifi_generic_ops = {
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
#if CONFIG(GENERATE_SMBIOS_TABLES)
static int smbios_write_intel_wifi(struct device *dev, int *handle, unsigned long *current)
{
struct smbios_type_intel_wifi {
u8 type;
u8 length;
u16 handle;
u8 str;
u8 eos[2];
} __packed;

struct smbios_type_intel_wifi *t = (struct smbios_type_intel_wifi *)*current;
int len = sizeof(struct smbios_type_intel_wifi);

memset(t, 0, sizeof(struct smbios_type_intel_wifi));
t->type = 0x85;
t->length = len - 2;
t->handle = *handle;
/* Intel wifi driver expects this string to be in the table 0x85. */
t->str = smbios_add_string(t->eos, "KHOIHGIUCCHHII");

len = t->length + smbios_string_table_len(t->eos);
*current += len;
*handle += 1;
return len;
}

static int smbios_write_wifi(struct device *dev, int *handle, unsigned long *current)
{
if (dev->vendor == PCI_VENDOR_ID_INTEL)
return smbios_write_intel_wifi(dev, handle, current);

return 0;
}
#endif

struct device_operations wifi_generic_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = wifi_pci_dev_init,
.ops_pci = &pci_dev_ops_pci,
#if CONFIG(HAVE_ACPI_TABLES)
.acpi_name = wifi_generic_acpi_name,
.acpi_fill_ssdt = wifi_generic_fill_ssdt_generator,
.acpi_fill_ssdt = wifi_generic_fill_ssdt,
#endif
#if CONFIG(GENERATE_SMBIOS_TABLES)
.get_smbios_data = smbios_write_wifi,
#endif
};

static void wifi_generic_enable(struct device *dev)
Expand All @@ -257,3 +312,67 @@ struct chip_operations drivers_wifi_generic_ops = {
CHIP_NAME("WIFI Device")
.enable_dev = wifi_generic_enable
};

static const unsigned short intel_pci_device_ids[] = {
PCI_DEVICE_ID_1000_SERIES_WIFI,
PCI_DEVICE_ID_6005_SERIES_WIFI,
PCI_DEVICE_ID_6005_I_SERIES_WIFI,
PCI_DEVICE_ID_1030_SERIES_WIFI,
PCI_DEVICE_ID_6030_I_SERIES_WIFI,
PCI_DEVICE_ID_6030_SERIES_WIFI,
PCI_DEVICE_ID_6150_SERIES_WIFI,
PCI_DEVICE_ID_2030_SERIES_WIFI,
PCI_DEVICE_ID_2000_SERIES_WIFI,
PCI_DEVICE_ID_0135_SERIES_WIFI,
PCI_DEVICE_ID_0105_SERIES_WIFI,
PCI_DEVICE_ID_6035_SERIES_WIFI,
PCI_DEVICE_ID_5300_SERIES_WIFI,
PCI_DEVICE_ID_5100_SERIES_WIFI,
PCI_DEVICE_ID_6000_SERIES_WIFI,
PCI_DEVICE_ID_6000_I_SERIES_WIFI,
PCI_DEVICE_ID_5350_SERIES_WIFI,
PCI_DEVICE_ID_5150_SERIES_WIFI,
/* Wilkins Peak 2 */
PCI_DEVICE_ID_WP_7260_SERIES_1_WIFI,
PCI_DEVICE_ID_WP_7260_SERIES_2_WIFI,
/* Stone Peak 2 */
PCI_DEVICE_ID_SP_7265_SERIES_1_WIFI,
PCI_DEVICE_ID_SP_7265_SERIES_2_WIFI,
/* Stone Field Peak */
PCI_DEVICE_ID_SFP_8260_SERIES_1_WIFI,
PCI_DEVICE_ID_SFP_8260_SERIES_2_WIFI,
/* Windstorm Peak */
PCI_DEVICE_ID_WSP_8275_SERIES_1_WIFI,
/* Jefferson Peak */
PCI_DEVICE_ID_JP_9000_SERIES_1_WIFI,
PCI_DEVICE_ID_JP_9000_SERIES_2_WIFI,
PCI_DEVICE_ID_JP_9000_SERIES_3_WIFI,
/* Thunder Peak 2 */
PCI_DEVICE_ID_TP_9260_SERIES_WIFI,
/* Harrison Peak */
PCI_DEVICE_ID_HrP_9560_SERIES_1_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_2_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_3_WIFI,
PCI_DEVICE_ID_HrP_9560_SERIES_4_WIFI,
PCI_DEVICE_ID_HrP_6SERIES_WIFI,
/* Cyclone Peak */
PCI_DEVICE_ID_CyP_6SERIES_WIFI,
/* Typhoon Peak */
PCI_DEVICE_ID_TyP_6SERIES_WIFI,
/* Garfield Peak */
PCI_DEVICE_ID_GrP_6SERIES_1_WIFI,
PCI_DEVICE_ID_GrP_6SERIES_2_WIFI,
0
};

/*
* The PCI driver is retained for backward compatibility with boards that never utilized the
* chip driver to support Intel WiFi device. For these devices, the PCI driver helps perform the
* same operations as above (except exposing the wake property) by utilizing the same
* `wifi_generic_ops`.
*/
static const struct pci_driver intel_wifi_pci_driver __pci_driver = {
.ops = &wifi_generic_ops,
.vendor = PCI_VENDOR_ID_INTEL,
.devices = intel_pci_device_ids,
};
110 changes: 108 additions & 2 deletions src/ec/google/chromeec/ec.c
Expand Up @@ -1380,11 +1380,11 @@ enum ec_image google_chromeec_get_current_image(void)
return ec_image_type;
}

int google_chromeec_get_num_pd_ports(int *num_ports)
int google_chromeec_get_num_pd_ports(unsigned int *num_ports)
{
struct ec_response_charge_port_count resp = {};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_CHARGE_PORT_COUNT,
.cmd_code = EC_CMD_USB_PD_PORTS,
.cmd_version = 0,
.cmd_data_out = &resp,
.cmd_size_in = 0,
Expand Down Expand Up @@ -1441,6 +1441,65 @@ int google_ec_running_ro(void)
return (google_chromeec_get_current_image() == EC_IMAGE_RO);
}

int google_chromeec_usb_pd_control(int port, bool *ufp, bool *dbg_acc, uint8_t *dp_mode)
{
struct ec_params_usb_pd_control pd_control = {
.port = port,
.role = USB_PD_CTRL_ROLE_NO_CHANGE,
.mux = USB_PD_CTRL_ROLE_NO_CHANGE,
.swap = USB_PD_CTRL_SWAP_NONE,
};
struct ec_response_usb_pd_control_v2 resp = {};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_USB_PD_CONTROL,
.cmd_version = 2,
.cmd_data_in = &pd_control,
.cmd_size_in = sizeof(pd_control),
.cmd_data_out = &resp,
.cmd_size_out = sizeof(resp),
.cmd_dev_index = 0,
};

if (google_chromeec_command(&cmd) < 0)
return -1;

*ufp = (resp.cc_state == PD_CC_DFP_ATTACHED);
*dbg_acc = (resp.cc_state == PD_CC_DFP_DEBUG_ACC);
*dp_mode = resp.dp_mode;

return 0;
}

/**
* Check for the current mux state in EC. Flags representing the mux state found
* in ec_commands.h
*/
int google_chromeec_usb_get_pd_mux_info(int port, uint8_t *flags)
{
struct ec_params_usb_pd_mux_info req_mux = {
.port = port,
};
struct ec_response_usb_pd_mux_info resp_mux = {};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_USB_PD_MUX_INFO,
.cmd_version = 0,
.cmd_data_in = &req_mux,
.cmd_size_in = sizeof(req_mux),
.cmd_data_out = &resp_mux,
.cmd_size_out = sizeof(resp_mux),
.cmd_dev_index = 0,
};

if (port < 0)
return -1;

if (google_chromeec_command(&cmd) < 0)
return -1;

*flags = resp_mux.flags;
return 0;
}

/**
* Check if EC/TCPM is in an alternate mode or not.
*
Expand Down Expand Up @@ -1557,3 +1616,50 @@ int google_chromeec_ap_reset(void)

return 0;
}

int google_chromeec_regulator_set_voltage(uint32_t index, uint32_t min_mv,
uint32_t max_mv)
{
struct ec_params_regulator_set_voltage params = {
.index = index,
.min_mv = min_mv,
.max_mv = max_mv,
};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_REGULATOR_SET_VOLTAGE,
.cmd_version = 0,
.cmd_data_in = &params,
.cmd_size_in = sizeof(params),
.cmd_data_out = NULL,
.cmd_size_out = 0,
.cmd_dev_index = 0,
};

if (google_chromeec_command(&cmd))
return -1;

return 0;
}

int google_chromeec_regulator_get_voltage(uint32_t index, uint32_t *voltage_mv)
{
struct ec_params_regulator_get_voltage params = {
.index = index,
};
struct ec_response_regulator_get_voltage resp = {};
struct chromeec_command cmd = {
.cmd_code = EC_CMD_REGULATOR_GET_VOLTAGE,
.cmd_version = 0,
.cmd_data_in = &params,
.cmd_size_in = sizeof(params),
.cmd_data_out = &resp,
.cmd_size_out = sizeof(resp),
.cmd_dev_index = 0,
};

if (google_chromeec_command(&cmd))
return -1;

*voltage_mv = resp.voltage_mv;
return 0;
}
29 changes: 28 additions & 1 deletion src/ec/google/chromeec/ec.h
Expand Up @@ -27,6 +27,15 @@ int google_ec_running_ro(void);
enum ec_image google_chromeec_get_current_image(void);
void google_chromeec_init(void);
int google_chromeec_pd_get_amode(uint16_t svid);
/* Check for the current mux state in EC
* in: int port physical port number of the type-c port
* out: uint8_t flags flags representing the status of the mux such as
* usb capability, dp capability, cable type, etc
*/
int google_chromeec_usb_get_pd_mux_info(int port, uint8_t *flags);
/* Returns data role and type of device connected */
int google_chromeec_usb_pd_control(int port, bool *ufp, bool *dbg_acc,
uint8_t *dp_mode);
int google_chromeec_wait_for_displayport(long timeout);

/* Device events */
Expand Down Expand Up @@ -306,7 +315,7 @@ int google_chromeec_get_cmd_versions(int command, uint32_t *pmask);
* of PD-capable USB ports according to the EC.
* @return 0 on success, -1 on error
*/
int google_chromeec_get_num_pd_ports(int *num_ports);
int google_chromeec_get_num_pd_ports(unsigned int *num_ports);

/* Structure representing the capabilities of a USB-PD port */
struct usb_pd_port_caps {
Expand Down Expand Up @@ -344,6 +353,24 @@ int google_chromeec_get_keybd_config(struct ec_response_keybd_config *keybd);
*/
int google_chromeec_ap_reset(void);

/**
* Set voltage for the voltage regulator within the range specified.
* @param index Regulator ID
* @param min_mv Minimum voltage
* @param max_mv Maximum voltage
* @return 0 on success, -1 on error
*/
int google_chromeec_regulator_set_voltage(uint32_t index, uint32_t min_mv,
uint32_t max_mv);

/**
* Get the currently configured voltage for the voltage regulator.
* @param index Regulator ID
* @param *voltage_mv If successful, voltage_mv is filled with current voltage
* @return 0 on success, -1 on error
*/
int google_chromeec_regulator_get_voltage(uint32_t index, uint32_t *voltage_mv);

#if CONFIG(HAVE_ACPI_TABLES)
/**
* Writes USB Type-C PD related information to the SSDT
Expand Down
3 changes: 2 additions & 1 deletion src/ec/google/chromeec/ec_acpi.c
Expand Up @@ -144,7 +144,8 @@ static bool match_connector(DEVTREE_CONST struct device *dev)
static void fill_ssdt_typec_device(const struct device *dev)
{
int rv;
int i, num_ports;
int i;
unsigned int num_ports;
struct device *usb2_port;
struct device *usb3_port;
struct device *usb4_port;
Expand Down
400 changes: 393 additions & 7 deletions src/ec/google/chromeec/ec_commands.h

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion src/ec/hp/kbc1126/Kconfig
Expand Up @@ -5,7 +5,12 @@ config EC_HP_KBC1126
help
Interface to SMSC KBC1126 embedded controller in HP laptops.

if EC_HP_KBC1126
config EC_HP_KBC1126_ECFW_IN_CBFS
bool
depends on EC_HP_KBC1126
default y

if EC_HP_KBC1126_ECFW_IN_CBFS

comment "Please select the following otherwise your laptop cannot be powered on."

Expand Down
10 changes: 5 additions & 5 deletions src/ec/hp/kbc1126/Makefile.inc
@@ -1,6 +1,6 @@
## SPDX-License-Identifier: GPL-2.0-only

ifeq ($(CONFIG_EC_HP_KBC1126),y)
ifeq ($(CONFIG_EC_HP_KBC1126_ECFW_IN_CBFS),y)
KBC1126_EC_INSERT:=$(top)/util/kbc1126/kbc1126_ec_insert
INTERMEDIATE+=kbc1126_ec_insert

Expand Down Expand Up @@ -39,8 +39,8 @@ ifeq ($(CONFIG_KBC1126_FIRMWARE),)
printf "You can read util/kbc1126/README.md for details.\n\n"
endif

ramstage-y += ec.c
bootblock-y += early_init.c
romstage-y += early_init.c

endif

ramstage-$(CONFIG_EC_HP_KBC1126) += ec.c
bootblock-$(CONFIG_EC_HP_KBC1126) += early_init.c
romstage-$(CONFIG_EC_HP_KBC1126) += early_init.c
8 changes: 8 additions & 0 deletions src/ec/kontron/kempld/chip.h
Expand Up @@ -12,13 +12,21 @@ enum kempld_uart_io {
KEMPLD_UART_2E8 = 3,
};

enum kempld_i2c_frequency {
KEMPLD_I2C_FREQ_STANDARD_MODE_100KHZ = 100,
KEMPLD_I2C_FREQ_FAST_MODE_400KHZ = 400,
KEMPLD_I2C_FREQ_FAST_PLUS_MODE_1MHZ = 1000,
KEMPLD_I2C_FREQ_MAX = 2700,
};

struct kempld_uart {
enum kempld_uart_io io;
unsigned int irq;
};

struct ec_kontron_kempld_config {
struct kempld_uart uart[KEMPLD_NUM_UARTS];
unsigned short i2c_frequency;
};

#endif /* EC_KONTRON_KEMPLD_CHIP_H */
6 changes: 2 additions & 4 deletions src/ec/kontron/kempld/early_kempld.c
Expand Up @@ -43,13 +43,11 @@ void kempld_enable_uart_for_console(void)
switch (CONFIG_UART_FOR_CONSOLE) {
case 0:
kempld_write8(KEMPLD_UART_0,
KEMPLD_UART_ENABLE |
KEMPLD_UART_3F8 << KEMPLD_UART_IO_SHIFT);
KEMPLD_UART_ENABLE | KEMPLD_UART_3F8 << KEMPLD_UART_IO_SHIFT);
break;
case 1:
kempld_write8(KEMPLD_UART_1,
KEMPLD_UART_ENABLE |
KEMPLD_UART_2F8 << KEMPLD_UART_IO_SHIFT);
KEMPLD_UART_ENABLE | KEMPLD_UART_2F8 << KEMPLD_UART_IO_SHIFT);
break;
default:
break;
Expand Down
18 changes: 8 additions & 10 deletions src/ec/kontron/kempld/kempld.c
Expand Up @@ -16,21 +16,20 @@ static void kempld_uart_read_resources(struct device *dev)
struct resource *const res_io = new_resource(dev, 0);
struct resource *const res_irq = new_resource(dev, 1);
const unsigned int uart = dev->path.generic.subid;

if (!config || !res_io || !res_irq || uart >= KEMPLD_NUM_UARTS)
return;

const enum kempld_uart_io io = config->uart[uart].io;
if (io >= ARRAY_SIZE(io_addr)) {
printk(BIOS_ERR, "KEMPLD: Bad io value '%d' for UART#%u\n.",
io, uart);
printk(BIOS_ERR, "KEMPLD: Bad io value '%d' for UART#%u\n.", io, uart);
dev->enabled = false;
return;
}

const int irq = config->uart[uart].irq;
if (irq >= 16) {
printk(BIOS_ERR, "KEMPLD: Bad irq value '%d' for UART#%u\n.",
irq, uart);
printk(BIOS_ERR, "KEMPLD: Bad irq value '%d' for UART#%u\n.", irq, uart);
dev->enabled = false;
return;
}
Expand All @@ -49,9 +48,10 @@ static void kempld_uart_read_resources(struct device *dev)

const uint8_t reg = uart ? KEMPLD_UART_1 : KEMPLD_UART_0;
const uint8_t val = kempld_read8(reg);
kempld_write8(reg, (val & ~(KEMPLD_UART_IO_MASK | KEMPLD_UART_IRQ_MASK))
| io << KEMPLD_UART_IO_SHIFT
| irq << KEMPLD_UART_IRQ_SHIFT);
kempld_write8(reg,
(val & ~(KEMPLD_UART_IO_MASK | KEMPLD_UART_IRQ_MASK)) |
io << KEMPLD_UART_IO_SHIFT |
irq << KEMPLD_UART_IRQ_SHIFT);

kempld_release_mutex();
}
Expand Down Expand Up @@ -90,9 +90,7 @@ static void kempld_enable_dev(struct device *const dev)
}
/* Fall through. */
default:
printk(BIOS_WARNING,
"KEMPLD: Spurious device %s.\n",
dev_path(dev));
printk(BIOS_WARNING, "KEMPLD: Spurious device %s.\n", dev_path(dev));
break;
}
}
Expand Down
26 changes: 18 additions & 8 deletions src/ec/kontron/kempld/kempld_i2c.c
Expand Up @@ -13,6 +13,7 @@
#include <timer.h>
#include <delay.h>

#include "chip.h"
#include "kempld.h"
#include "kempld_internal.h"

Expand Down Expand Up @@ -40,9 +41,6 @@
#define I2C_CMD_READ_NACK 0x29
#define I2C_CMD_IACK 0x01

#define KEMPLD_I2C_FREQ_MAX 2700 /* 2.7 mHz */
#define KEMPLD_I2C_FREQ_STD 100 /* 100 kHz */

#define EIO 5
#define ENXIO 6
#define EAGAIN 11
Expand Down Expand Up @@ -153,8 +151,7 @@ static int kempld_i2c_process(struct kempld_i2c_data *const i2c)
i2c->state = STATE_ADDR;
return 0;
}
i2c->state = (msg->flags & I2C_M_RD)
? STATE_READ : STATE_WRITE;
i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
} else {
i2c->state = STATE_DONE;
kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
Expand Down Expand Up @@ -230,7 +227,8 @@ static struct device_operations kempld_i2c_dev_ops = {

void kempld_i2c_device_init(struct device *const dev)
{
u16 prescale_corr;
const struct ec_kontron_kempld_config *const config = dev->chip_info;
u16 prescale_corr, frequency;
long prescale;
u8 ctrl;
u8 stat;
Expand All @@ -244,11 +242,23 @@ void kempld_i2c_device_init(struct device *const dev)
ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN);
kempld_write8(KEMPLD_I2C_CTRL, ctrl);

frequency = KEMPLD_I2C_FREQ_STANDARD_MODE_100KHZ;
if (config && config->i2c_frequency) {
if (config->i2c_frequency <= KEMPLD_I2C_FREQ_MAX) {
frequency = config->i2c_frequency;
} else {
printk(BIOS_NOTICE,
"kempld_i2c: %d kHz is too high!\n",
config->i2c_frequency);
}
}
printk(BIOS_INFO, "kempld_i2c: Use frequency %d\n", frequency);

const u8 spec_major = KEMPLD_SPEC_GET_MAJOR(kempld_read8(KEMPLD_SPEC));
if (spec_major == 1)
prescale = KEMPLD_CLK / (KEMPLD_I2C_FREQ_STD * 5) - 1000;
prescale = KEMPLD_CLK / (frequency * 5) - 1000;
else
prescale = KEMPLD_CLK / (KEMPLD_I2C_FREQ_STD * 4) - 3000;
prescale = KEMPLD_CLK / (frequency * 4) - 3000;

if (prescale < 0)
prescale = 0;
Expand Down
2 changes: 2 additions & 0 deletions src/include/acpi/acpi.h
Expand Up @@ -41,6 +41,8 @@

#define ACPI_TABLE_CREATOR "COREBOOT" /* Must be exactly 8 bytes long! */
#define OEM_ID "COREv4" /* Must be exactly 6 bytes long! */
#define ACPI_DSDT_REV_1 0x01 /* DSDT revision: ACPI v1 */
#define ACPI_DSDT_REV_2 0x02 /* DSDT revision: ACPI v2.0 and greater */

#if !defined(__ASSEMBLER__) && !defined(__ACPI__)
#include <commonlib/helpers.h>
Expand Down
16 changes: 16 additions & 0 deletions src/include/acpi/acpi_device.h
Expand Up @@ -545,6 +545,22 @@ struct acpi_dp *acpi_dp_add_gpio(struct acpi_dp *dp, const char *name,
const char *ref, int index, int pin,
int active_low);

struct acpi_gpio_res_params {
/* Reference to the parent device. */
const char *ref;
/* Index to the GpioIo resource within the _CRS. */
int index;
/* Index to the pin within the GpioIo resource, usually 0. */
int pin;
/* Flag to indicate if pin is active low. */
int active_low;
};

/* Add a GPIO binding device property for array of GPIOs */
struct acpi_dp *acpi_dp_add_gpio_array(struct acpi_dp *dp, const char *name,
const struct acpi_gpio_res_params *params,
size_t param_count);

/* Add a child table of Device Properties */
struct acpi_dp *acpi_dp_add_child(struct acpi_dp *dp, const char *name,
struct acpi_dp *child);
Expand Down
18 changes: 13 additions & 5 deletions src/include/acpi/acpigen.h
Expand Up @@ -158,6 +158,10 @@ enum {
.name = X, \
.bits = Y, \
}
#define FIELDLIST_RESERVED(X) { .type = RESERVED, \
.name = "", \
.bits = X, \
}

#define FIELD_ANYACC 0
#define FIELD_BYTEACC 1
Expand All @@ -174,6 +178,7 @@ enum {
enum field_type {
OFFSET,
NAME_STRING,
RESERVED,
FIELD_TYPE_MAX,
};

Expand Down Expand Up @@ -356,6 +361,8 @@ void acpigen_write_power_res(const char *name, uint8_t level, uint16_t order,
const char * const dev_states[], size_t dev_states_count);
void acpigen_write_sleep(uint64_t sleep_ms);
void acpigen_write_store(void);
void acpigen_write_store_int_to_namestr(uint64_t src, const char *dst);
void acpigen_write_store_int_to_op(uint64_t src, uint8_t dst);
void acpigen_write_store_ops(uint8_t src, uint8_t dst);
void acpigen_write_store_op_to_namestr(uint8_t src, const char *dst);
void acpigen_write_or(uint8_t arg1, uint8_t arg2, uint8_t res);
Expand All @@ -371,6 +378,7 @@ void acpigen_write_if_lequal_op_op(uint8_t op, uint8_t val);
void acpigen_write_if_lequal_op_int(uint8_t op, uint64_t val);
void acpigen_write_if_lequal_namestr_int(const char *namestr, uint64_t val);
void acpigen_write_else(void);
void acpigen_write_shiftleft_op_int(uint8_t src_result, uint64_t count);
void acpigen_write_to_buffer(uint8_t src, uint8_t dst);
void acpigen_write_to_integer(uint8_t src, uint8_t dst);
void acpigen_write_to_integer_from_namestring(const char *source, uint8_t dst_op);
Expand Down Expand Up @@ -421,7 +429,7 @@ void acpigen_write_rom(void *bios, const size_t length);
* This function takes input region name, region space, region offset & region
* length.
*/
void acpigen_write_opregion(struct opregion *opreg);
void acpigen_write_opregion(const struct opregion *opreg);
/*
* Generate ACPI AML code for Mutex
* This function takes mutex name and initial value.
Expand Down Expand Up @@ -491,24 +499,24 @@ int acpigen_soc_clear_tx_gpio(unsigned int gpio_num);
*
* Returns 0 on success and -1 on error.
*/
int acpigen_enable_tx_gpio(struct acpi_gpio *gpio);
int acpigen_disable_tx_gpio(struct acpi_gpio *gpio);
int acpigen_enable_tx_gpio(const struct acpi_gpio *gpio);
int acpigen_disable_tx_gpio(const struct acpi_gpio *gpio);

/*
* Helper function for getting a RX GPIO value based on the GPIO polarity.
* The return value is stored in Local0 variable.
* This function ends up calling acpigen_soc_get_rx_gpio to make callbacks
* into SoC acpigen code
*/
void acpigen_get_rx_gpio(struct acpi_gpio *gpio);
void acpigen_get_rx_gpio(const struct acpi_gpio *gpio);

/*
* Helper function for getting a TX GPIO value based on the GPIO polarity.
* The return value is stored in Local0 variable.
* This function ends up calling acpigen_soc_get_tx_gpio to make callbacks
* into SoC acpigen code
*/
void acpigen_get_tx_gpio(struct acpi_gpio *gpio);
void acpigen_get_tx_gpio(const struct acpi_gpio *gpio);

/* refer to ACPI 6.4.3.5.3 Word Address Space Descriptor section for details */
void acpigen_resource_word(u16 res_type, u16 gen_flags, u16 type_flags, u16 gran,
Expand Down
2 changes: 1 addition & 1 deletion src/include/console/spi.h
Expand Up @@ -8,7 +8,7 @@
void spiconsole_init(void);
void spiconsole_tx_byte(unsigned char c);

#define __CONSOLE_SPI_ENABLE__ (CONFIG(SPI_CONSOLE) && \
#define __CONSOLE_SPI_ENABLE__ (CONFIG(EM100PRO_SPI_CONSOLE) && \
(ENV_RAMSTAGE || (ENV_SMM && CONFIG(DEBUG_SMI))))

#if __CONSOLE_SPI_ENABLE__
Expand Down
16 changes: 13 additions & 3 deletions src/include/cpu/amd/msr.h
Expand Up @@ -12,13 +12,16 @@

#define CPUID_EXT_PM 0x80000007
#define CPUID_MODEL 1
#define CPUID_EBX_CORE_ID 0x8000001E
#define CPUID_EBX_THREADS_SHIFT 8
#define CPUID_EBX_THREADS_MASK (0xFF << CPUID_EBX_THREADS_SHIFT)
#define MC4_MISC0 0x00000413
#define MC4_MISC1 0xC0000408
#define MC4_MISC2 0xC0000409
#define FS_Base 0xC0000100
#define HWCR_MSR 0xC0010015
#define HWCR_MSR 0xC0010015
#define SMM_LOCK (1 << 0)
#define NB_CFG_MSR 0xC001001f
#define NB_CFG_MSR 0xC001001f
#define FidVidStatus 0xC0010042
#define MC1_CTL_MASK 0xC0010045
#define MC4_CTL_MASK 0xC0010048
Expand All @@ -30,6 +33,9 @@
#define PS_LIM_REG 0xC0010061
/* P-state Maximum Value shift position */
#define PS_MAX_VAL_SHFT 4
#define PS_LIM_MAX_VAL_MASK (0x7 << PS_MAX_VAL_SHFT)
#define MAX_PSTATES 8

/* P-state Control Register */
#define PS_CTL_REG 0xC0010062
/* P-state Control Register CMD Mask OFF */
Expand All @@ -43,11 +49,15 @@
#define PSTATE_2_MSR 0xC0010066
#define PSTATE_3_MSR 0xC0010067
#define PSTATE_4_MSR 0xC0010068

/* Value defined in Serial VID Interface 2.0 spec (#48022, NDA only) */
#define SERIAL_VID_DECODE_MICROVOLTS 6250
#define SERIAL_VID_MAX_MICROVOLTS 1550000L
#define MSR_PATCH_LOADER 0xC0010020

#define MSR_COFVID_STS 0xC0010071
#define MSR_CSTATE_ADDRESS 0xC0010073
#define MSR_CSTATE_ADDRESS_MASK 0xFFFF

#define OSVW_ID_Length 0xC0010140
#define OSVW_Status 0xC0010141

Expand Down
15 changes: 15 additions & 0 deletions src/include/cpu/intel/msr.h
@@ -0,0 +1,15 @@
#ifndef CPU_INTEL_MSR_H
#define CPU_INTEL_MSR_H

/*
* Common MSRs for Intel CPUs
*/

#define MSR_FEATURE_CONFIG 0x13c
#define AESNI_DISABLE (1 << 1)
#define AESNI_LOCK (1 << 0)

#define MSR_PIC_MSG_CONTROL 0x2e
#define TPR_UPDATES_DISABLE (1 << 10)

#endif /* CPU_INTEL_MSR_H */
52 changes: 38 additions & 14 deletions src/include/cpu/x86/msr.h
Expand Up @@ -48,11 +48,12 @@
#define ENERGY_POLICY_PERFORMANCE 0
#define ENERGY_POLICY_NORMAL 6
#define ENERGY_POLICY_POWERSAVE 15
#define ENERGY_POLICY_MASK 0xf
#define IA32_PACKAGE_THERM_INTERRUPT 0x1b2
#define IA32_PLATFORM_DCA_CAP 0x1f8
#define SMRR_PHYSBASE_MSR 0x1F2
#define SMRR_PHYSMASK_MSR 0x1F3
#define IA32_PLATFORM_DCA_CAP 0x1f8
#define DCA_TYPE0_EN (1 << 0)
#define IA32_PAT 0x277
#define IA32_MC0_CTL 0x400
#define IA32_MC0_STATUS 0x401
Expand Down Expand Up @@ -299,23 +300,46 @@ static inline enum mca_err_code_types mca_err_type(msr_t reg)
return MCA_ERRTYPE_UNKNOWN;
}

/* Helper for setting single MSR bits */
static inline void msr_set_bit(unsigned int reg, unsigned int bit)
/**
* Helper for (un)setting MSR bitmasks
*
* @param[in] reg The MSR.
* @param[in] unset Bitmask with ones to the bits to unset from the MSR.
* @param[in] set Bitmask with ones to the bits to set from the MSR.
*/
static inline void msr_unset_and_set(unsigned int reg, uint64_t unset, uint64_t set)
{
msr_t msr = rdmsr(reg);

if (bit < 32) {
if (msr.lo & (1 << bit))
return;
msr.lo |= 1 << bit;
} else {
if (msr.hi & (1 << (bit - 32)))
return;
msr.hi |= 1 << (bit - 32);
}
msr_t msr;

msr = rdmsr(reg);
msr.lo &= (unsigned int)~unset;
msr.hi &= (unsigned int)~(unset >> 32);
msr.lo |= (unsigned int)set;
msr.hi |= (unsigned int)(set >> 32);
wrmsr(reg, msr);
}

/**
* Helper for setting MSR bitmasks
*
* @param[in] reg The MSR.
* @param[in] set Bitmask with ones to the bits to set from the MSR.
*/
static inline void msr_set(unsigned int reg, uint64_t set)
{
msr_unset_and_set(reg, 0, set);
}

/**
* Helper for unsetting MSR bitmasks
*
* @param[in] reg The MSR.
* @param[in] unset Bitmask with ones to the bits to unset from the MSR.
*/
static inline void msr_unset(unsigned int reg, uint64_t unset)
{
msr_unset_and_set(reg, unset, 0);
}

#endif /* __ASSEMBLER__ */
#endif /* CPU_X86_MSR_H */
2 changes: 1 addition & 1 deletion src/include/cpu/x86/smi_deprecated.h
Expand Up @@ -15,6 +15,6 @@ void smm_init_completion(void);
#endif

/* Entry from smmhandler.S. */
void smi_handler(u32 smm_revision);
void smi_handler(void);

#endif
14 changes: 4 additions & 10 deletions src/include/cpu/x86/tsc.h
Expand Up @@ -41,20 +41,14 @@ static inline void multiply_to_tsc(tsc_t *const tsc, const u32 a, const u32 b)
tsc->hi = ((a >> 16) * (b >> 16)) + (tsc->hi >> 16);
}

static inline unsigned long long rdtscll(void)
static inline uint64_t tsc_to_uint64(tsc_t tstamp)
{
unsigned long long val;
asm volatile (
TSC_SYNC
"rdtsc"
: "=A" (val)
);
return val;
return (((uint64_t)tstamp.hi) << 32) + tstamp.lo;
}

static inline uint64_t tsc_to_uint64(tsc_t tstamp)
static inline unsigned long long rdtscll(void)
{
return (((uint64_t)tstamp.hi) << 32) + tstamp.lo;
return tsc_to_uint64(rdtsc());
}

/* Provided by CPU/chipset code for the TSC rate in MHz. */
Expand Down
4 changes: 3 additions & 1 deletion src/include/device/azalia_device.h
Expand Up @@ -54,7 +54,7 @@ enum azalia_pin_type {
STEREO_MONO_1_4,
ATAPI,
RCA,
OPTIONAL,
OPTICAL,
OTHER_DIGITAL,
OTHER_ANALOG,
MULTICHANNEL_ANALOG,
Expand Down Expand Up @@ -128,6 +128,8 @@ enum azalia_pin_location_2 {
(((codec) << 28) | ((pin) << 20) | (0x71f << 8) \
| (((val) >> 24) & 0xff))

#define AZALIA_PIN_CFG_NC(n) (0x411111f0 | (n & 0xf))

#define AZALIA_RESET(pin) \
(((pin) << 20) | 0x7ff00), (((pin) << 20) | 0x7ff00), \
(((pin) << 20) | 0x7ff00), (((pin) << 20) | 0x7ff00)
Expand Down
7 changes: 7 additions & 0 deletions src/include/device/device.h
Expand Up @@ -339,6 +339,12 @@ DEVTREE_CONST struct device *pcidev_path_on_root_debug(pci_devfn_t devfn, const
void devtree_bug(const char *func, pci_devfn_t devfn);
void __noreturn devtree_die(void);

/*
* Dies if `dev` or `dev->chip_info` are NULL. Returns `dev->chip_info` otherwise.
*
* Only use if missing `chip_info` is fatal and we can't boot. If it's
* not fatal, please handle the NULL case gracefully.
*/
static inline DEVTREE_CONST void *config_of(const struct device *dev)
{
if (dev && dev->chip_info)
Expand All @@ -352,6 +358,7 @@ static inline DEVTREE_CONST void *config_of_soc(void)
return config_of(pcidev_on_root(0, 0));
}

void enable_static_device(struct device *dev);
void enable_static_devices(struct device *bus);
void scan_smbus(struct device *bus);
void scan_generic_bus(struct device *bus);
Expand Down
27 changes: 25 additions & 2 deletions src/include/device/mmio.h
Expand Up @@ -150,21 +150,44 @@ static inline void buffer_to_fifo32(void *buffer, size_t size, void *fifo,
_BF_APPLY6(op, __VA_ARGS__))
#define _BF_APPLY8(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY7(op, __VA_ARGS__))
#define _BF_APPLY9(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY8(op, __VA_ARGS__))
#define _BF_APPLY10(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY9(op, __VA_ARGS__))
#define _BF_APPLY11(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY10(op, __VA_ARGS__))
#define _BF_APPLY12(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY11(op, __VA_ARGS__))
#define _BF_APPLY13(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY12(op, __VA_ARGS__))
#define _BF_APPLY14(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY13(op, __VA_ARGS__))
#define _BF_APPLY15(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY14(op, __VA_ARGS__))
#define _BF_APPLY16(op, name, value, ...) ((op(name, value)) | \
_BF_APPLY15(op, __VA_ARGS__))
#define _BF_APPLYINVALID(...) \
_Static_assert(0, "Invalid arguments for {WRITE,SET}*_BITFIELDS")

#define _BF_IMPL2(op, addr, \
n1, v1, n2, v2, n3, v3, n4, v4, n5, v5, n6, v6, n7, v7, n8, v8, \
n9, v9, n10, v10, n11, v11, n12, v12, n13, v13, n14, v14, n15, v15, n16, v16, \
NARGS, ...) \
\
op(addr, \
_BF_APPLY##NARGS(_BF_MASK, n1, v1, n2, v2, n3, v3, n4, v4, \
n5, v5, n6, v6, n7, v7, n8, v8), \
n5, v5, n6, v6, n7, v7, n8, v8, \
n9, v9, n10, v10, n11, v11, n12, v12, \
n13, v13, n14, v14, n15, v15, n16, v16), \
_BF_APPLY##NARGS(_BF_VALUE, n1, v1, n2, v2, n3, v3, n4, v4, \
n5, v5, n6, v6, n7, v7, n8, v8))
n5, v5, n6, v6, n7, v7, n8, v8,\
n9, v9, n10, v10, n11, v11, n12, v12, \
n13, v13, n14, v14, n15, v15, n16, v16))

#define _BF_IMPL(op, addr, ...) \
_BF_IMPL2(op, addr, __VA_ARGS__, \
16, INVALID, 15, INVALID, 14, INVALID, 13, INVALID, \
12, INVALID, 11, INVALID, 10, INVALID, 9, INVALID, \
8, INVALID, 7, INVALID, 6, INVALID, 5, INVALID, \
4, INVALID, 3, INVALID, 2, INVALID, 1, INVALID)

Expand Down
8 changes: 8 additions & 0 deletions src/include/device/pci.h
Expand Up @@ -80,6 +80,14 @@ void pci_bus_reset(struct bus *bus);
struct device *pci_probe_dev(struct device *dev, struct bus *bus,
unsigned int devfn);

/*
* Determine if the given PCI device is the source of wake from sleep by checking PME_STATUS and
* PME_ENABLE bits in PM control and status register.
*
* Returns true if PCI device is wake source, false otherwise.
*/
bool pci_dev_is_wake_source(const struct device *dev);

void do_pci_scan_bridge(struct device *dev,
void (*do_scan_bus)(struct bus *bus,
unsigned int min_devfn, unsigned int max_devfn));
Expand Down
3 changes: 3 additions & 0 deletions src/include/device/pci_ids.h
Expand Up @@ -3638,6 +3638,7 @@
#define PCI_DEVICE_ID_INTEL_JSL_GT1 0x4E51
#define PCI_DEVICE_ID_INTEL_JSL_GT2 0x4E71
#define PCI_DEVICE_ID_INTEL_JSL_GT3 0x4E61
#define PCI_DEVICE_ID_INTEL_JSL_GT4 0x4E55

#define PCI_DEVICE_ID_INTEL_ADL_GT0 0x46ff
#define PCI_DEVICE_ID_INTEL_ADL_GT1 0x4600
Expand Down Expand Up @@ -3729,6 +3730,7 @@
#define PCI_DEVICE_ID_INTEL_JSL_ID_2 0x4e26
#define PCI_DEVICE_ID_INTEL_JSL_ID_3 0x4e12
#define PCI_DEVICE_ID_INTEL_JSL_ID_4 0x4e14
#define PCI_DEVICE_ID_INTEL_JSL_ID_5 0x4e24

#define PCI_DEVICE_ID_INTEL_ADL_S_ID_1 0x4660
#define PCI_DEVICE_ID_INTEL_ADL_S_ID_2 0x4664
Expand All @@ -3755,6 +3757,7 @@
#define PCI_DEVICE_ID_INTEL_ADL_P_ID_8 0x4661
#define PCI_DEVICE_ID_INTEL_ADL_P_ID_9 0x467f
/* Intel SMBUS device Ids */
#define PCI_DEVICE_ID_INTEL_APL_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_SPT_LP_SMBUS 0x9d23
#define PCI_DEVICE_ID_INTEL_SPT_H_SMBUS 0xa123
#define PCI_DEVICE_ID_INTEL_LWB_SMBUS 0xa1a3
Expand Down
1 change: 0 additions & 1 deletion src/include/device/pnp_ops.h
Expand Up @@ -4,7 +4,6 @@
#define __DEVICE_PNP_OPS_H__

#include <stdint.h>
#include <arch/io.h>
#include <device/pnp.h>

#if ENV_PNP_SIMPLE_DEVICE
Expand Down
38 changes: 38 additions & 0 deletions src/include/imd_private.h
@@ -0,0 +1,38 @@
#ifndef _IMD_PRIVATE_H_
#define _IMD_PRIVATE_H_

#include <commonlib/bsd/helpers.h>

/* In-memory data structures. */
struct imd_root_pointer {
uint32_t magic;
/* Relative to upper limit/offset. */
int32_t root_offset;
} __packed;

struct imd_entry {
uint32_t magic;
/* start is located relative to imd_root */
int32_t start_offset;
uint32_t size;
uint32_t id;
} __packed;

struct imd_root {
uint32_t max_entries;
uint32_t num_entries;
uint32_t flags;
uint32_t entry_align;
/* Used for fixing the size of an imd. Relative to the root. */
int32_t max_offset;
struct imd_entry entries[0];
} __packed;

#define IMD_ROOT_PTR_MAGIC 0xc0389481
#define IMD_ENTRY_MAGIC (~0xc0389481)
#define SMALL_REGION_ID CBMEM_ID_IMD_SMALL
#define LIMIT_ALIGN 4096

#define IMD_FLAG_LOCKED 1

#endif /* _IMD_PRIVATE_H */
7 changes: 7 additions & 0 deletions src/include/lib.h
Expand Up @@ -46,6 +46,8 @@ void hexdump32(char LEVEL, const void *d, size_t len);
*/
size_t hexstrtobin(const char *str, uint8_t *buf, size_t len);

/* Population Count: number of bits that are one */
static inline int popcnt(u32 x) { return __builtin_popcount(x); }
/* Count Leading Zeroes: clz(0) == 32, clz(0xf) == 28, clz(1 << 31) == 0 */
static inline int clz(u32 x) { return x ? __builtin_clz(x) : sizeof(x) * 8; }
/* Integer binary logarithm (rounding down): log2(0) == -1, log2(5) == 2 */
Expand All @@ -56,4 +58,9 @@ static inline int __ffs(u32 x) { return log2(x & (u32)(-(s32)x)); }
/* Integer binary logarithm (rounding up): log2_ceil(0) == -1, log2(5) == 3 */
static inline int log2_ceil(u32 x) { return (x == 0) ? -1 : log2(x * 2 - 1); }

static inline int popcnt64(u64 x) { return __builtin_popcountll(x); }
static inline int clz64(u64 x) { return x ? __builtin_clzll(x) : sizeof(x) * 8; }
static inline int log2_64(u64 x) { return sizeof(x) * 8 - clz64(x) - 1; }
static inline int __ffs64(u64 x) { return log2_64(x & (u64)(-(s64)x)); }

#endif /* __LIB_H__ */
6 changes: 6 additions & 0 deletions src/include/memory_info.h
Expand Up @@ -108,4 +108,10 @@ struct memory_info {
struct dimm_info dimm[DIMM_INFO_TOTAL];
} __packed;

/*
* mainboard_get_dram_part_num returns a DRAM part number override string
* return NULL = no part number override provided by mainboard
* return non-NULL = pointer to a string terminating in '\0'
*/
const char *mainboard_get_dram_part_num(void);
#endif
8 changes: 4 additions & 4 deletions src/include/mrc_cache.h
Expand Up @@ -27,11 +27,11 @@ enum {
* mrc_cache_load_current
*
* Fill in the buffer with the latest slot data. This will be a
* common entry point for ARM platforms. Returns < 0 on error, 0 on
* success.
* common entry point for ARM platforms. Returns < 0 on error, size
* of the returned data on success.
*/
int mrc_cache_load_current(int type, uint32_t version, void *buffer,
size_t buffer_size);
ssize_t mrc_cache_load_current(int type, uint32_t version, void *buffer,
size_t buffer_size);
/**
* mrc_cache_mmap_leak
*
Expand Down
4 changes: 4 additions & 0 deletions src/include/rules.h
Expand Up @@ -78,7 +78,11 @@
#define ENV_RMODULE 0
#define ENV_POSTCAR 0
#define ENV_LIBAGESA 0
#if CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK)
#define ENV_STRING "verstage-before-bootblock"
#else
#define ENV_STRING "verstage"
#endif

#elif defined(__RAMSTAGE__)
#define ENV_DECOMPRESSOR 0
Expand Down
13 changes: 13 additions & 0 deletions src/include/smbios.h
Expand Up @@ -54,11 +54,17 @@ const char *smbios_chassis_version(void);
const char *smbios_chassis_serial_number(void);
const char *smbios_processor_serial_number(void);

void smbios_ec_revision(uint8_t *ec_major_revision, uint8_t *ec_minor_revision);

unsigned int smbios_processor_external_clock(void);
unsigned int smbios_processor_characteristics(void);
struct cpuid_result;
unsigned int smbios_processor_family(struct cpuid_result res);

unsigned int smbios_cache_error_correction_type(u8 level);
unsigned int smbios_cache_sram_type(void);
unsigned int smbios_cache_conf_operation_mode(u8 level);

/* Used by mainboard to add port information of type 8 */
struct port_information;
int smbios_write_type8(unsigned long *current, int *handle,
Expand Down Expand Up @@ -499,6 +505,13 @@ enum smbios_cache_associativity {
#define SMBIOS_CACHE_SIZE2_UNIT_64KB (1UL << 31)
#define SMBIOS_CACHE_SIZE2_MASK 0x7fffffff

/* define for cache operation mode */

#define SMBIOS_CACHE_OP_MODE_WRITE_THROUGH 0
#define SMBIOS_CACHE_OP_MODE_WRITE_BACK 1
#define SMBIOS_CACHE_OP_MODE_VARIES_WITH_MEMORY_ADDRESS 2
#define SMBIOS_CACHE_OP_MODE_UNKNOWN 3

struct smbios_type7 {
u8 type;
u8 length;
Expand Down
94 changes: 90 additions & 4 deletions src/include/smmstore.h
Expand Up @@ -10,10 +10,18 @@
#define SMMSTORE_RET_FAILURE 1
#define SMMSTORE_RET_UNSUPPORTED 2

/* Version 1 */
#define SMMSTORE_CMD_CLEAR 1
#define SMMSTORE_CMD_READ 2
#define SMMSTORE_CMD_APPEND 3

/* Version 2 */
#define SMMSTORE_CMD_INIT 4
#define SMMSTORE_CMD_RAW_READ 5
#define SMMSTORE_CMD_RAW_WRITE 6
#define SMMSTORE_CMD_RAW_CLEAR 7

/* Version 1 */
struct smmstore_params_read {
void *buf;
ssize_t bufsize;
Expand All @@ -26,12 +34,90 @@ struct smmstore_params_append {
size_t valsize;
};

/* SMM responder */
/* Version 2 */
/*
* The Version 2 protocol separates the SMMSTORE into 64KiB blocks, each
* of which can be read/written/cleared in an independent manner. The
* data format isn't specified. See documentation page for more details.
*/

#define SMM_BLOCK_SIZE (64 * KiB)

/*
* Sets the communication buffer to use for read and write operations.
*/
struct smmstore_params_init {
uint32_t com_buffer;
uint32_t com_buffer_size;
} __packed;

/*
* Returns the number of blocks the SMMSTORE supports and their size.
* For EDK2 this should be at least two blocks with 64 KiB each.
* The mmap_addr is set the memory mapped physical address of the SMMSTORE.
*/
struct smmstore_params_info {
uint32_t num_blocks;
uint32_t block_size;
uint32_t mmap_addr;
} __packed;

/*
* Reads a chunk of raw data with size @bufsize from the block specified by
* @block_id starting at @bufoffset.
* The read data is placed in memory pointed to by @buf.
*
* @block_id must be less than num_blocks
* @bufoffset + @bufsize must be less than block_size
*/
struct smmstore_params_raw_write {
uint32_t bufsize;
uint32_t bufoffset;
uint32_t block_id;
} __packed;

/*
* Writes a chunk of raw data with size @bufsize to the block specified by
* @block_id starting at @bufoffset.
*
* @block_id must be less than num_blocks
* @bufoffset + @bufsize must be less than block_size
*/
struct smmstore_params_raw_read {
uint32_t bufsize;
uint32_t bufoffset;
uint32_t block_id;
} __packed;

/*
* Erases the specified block.
*
* @block_id must be less than num_blocks
*/
struct smmstore_params_raw_clear {
uint32_t block_id;
} __packed;


/* SMM handler */
uint32_t smmstore_exec(uint8_t command, void *param);

/* implementation */
/* Implementation of Version 1 */
int smmstore_read_region(void *buf, ssize_t *bufsize);
int smmstore_append_data(void *key, uint32_t key_sz,
void *value, uint32_t value_sz);
int smmstore_append_data(void *key, uint32_t key_sz, void *value, uint32_t value_sz);
int smmstore_clear_region(void);

/* Implementation of Version 2 */
int smmstore_init(void *buf, size_t len);
int smmstore_rawread_region(uint32_t block_id, uint32_t offset, uint32_t bufsize);
int smmstore_rawwrite_region(uint32_t block_id, uint32_t offset, uint32_t bufsize);
int smmstore_rawclear_region(uint32_t block_id);
#if ENV_RAMSTAGE
int smmstore_get_info(struct smmstore_params_info *info);
#endif

/* Advertise SMMSTORE v2 support */
struct lb_header;
void lb_smmstorev2(struct lb_header *header);

#endif
3 changes: 2 additions & 1 deletion src/lib/Makefile.inc
Expand Up @@ -100,6 +100,7 @@ ramstage-y += romstage_handoff.c
romstage-y += romstage_handoff.c
romstage-y += selfboot.c
romstage-y += stack.c
romstage-y += rtc.c
ramstage-y += rtc.c

romstage-$(CONFIG_COLLECT_TIMESTAMPS) += timestamp.c
Expand Down Expand Up @@ -359,7 +360,7 @@ LIB_SPD_DEPS = $(foreach f, $(SPD_SOURCES), src/mainboard/$(MAINBOARDDIR)/spd/$(
# Include spd ROM data
$(LIB_SPD_BIN): $(LIB_SPD_DEPS)
test -n "$(SPD_SOURCES)" || \
(echo "HAVE_SPD_BIN_IN_CBFS is set but SPD_SOURCES is empty" && exit 1)
(echo "HAVE_SPD_IN_CBFS is set but SPD_SOURCES is empty" && exit 1)
test -n "$(LIB_SPD_DEPS)" || \
(echo "SPD_SOURCES is set but no SPD file was found" && exit 1)
for f in $(LIB_SPD_DEPS); \
Expand Down
12 changes: 9 additions & 3 deletions src/lib/cbfs.c
Expand Up @@ -4,8 +4,8 @@
#include <boot_device.h>
#include <cbfs.h>
#include <commonlib/bsd/compression.h>
#include <commonlib/endian.h>
#include <console/console.h>
#include <endian.h>
#include <fmap.h>
#include <lib.h>
#include <security/tpm/tspi/crtm.h>
Expand Down Expand Up @@ -296,10 +296,16 @@ int cbfs_prog_stage_load(struct prog *pstage)
foffset = 0;
foffset += sizeof(stage);

/* cbfs_stage fields are written in little endian despite the other
cbfs data types being encoded in big endian. */
stage.compression = read_le32(&stage.compression);
stage.entry = read_le64(&stage.entry);
stage.load = read_le64(&stage.load);
stage.len = read_le32(&stage.len);
stage.memlen = read_le32(&stage.memlen);

assert(fsize == stage.len);

/* Note: cbfs_stage fields are currently in the endianness of the
* running processor. */
load = (void *)(uintptr_t)stage.load;
entry = (void *)(uintptr_t)stage.entry;

Expand Down
6 changes: 6 additions & 0 deletions src/lib/coreboot_table.c
Expand Up @@ -20,6 +20,8 @@
#include <spi_flash.h>
#include <security/vboot/misc.h>
#include <security/vboot/vbnv_layout.h>
#include <smmstore.h>

#if CONFIG(USE_OPTION_TABLE)
#include <option_table.h>
#endif
Expand Down Expand Up @@ -549,6 +551,10 @@ static uintptr_t write_coreboot_table(uintptr_t rom_table_end)

add_cbmem_pointers(head);

/* SMMSTORE v2 */
if (CONFIG(SMMSTORE_V2))
lb_smmstorev2(head);

/* Add board-specific table entries, if any. */
lb_board(head);

Expand Down
1 change: 1 addition & 0 deletions src/lib/edid.c
Expand Up @@ -261,6 +261,7 @@ detailed_block(struct edid *result_edid, unsigned char *x, int in_extension,
extract_string(x + 5,
&c->has_valid_string_termination,
EDID_ASCII_STRING_LENGTH));
c->has_name_descriptor = 1;
return 1;
case 0xFD:
{
Expand Down
2 changes: 1 addition & 1 deletion src/lib/fw_config.c
Expand Up @@ -127,5 +127,5 @@ static void fw_config_init(void *unused)
}
}
}
BOOT_STATE_INIT_ENTRY(BS_DEV_ENUMERATE, BS_ON_ENTRY, fw_config_init, NULL);
BOOT_STATE_INIT_ENTRY(BS_DEV_INIT_CHIPS, BS_ON_ENTRY, fw_config_init, NULL);
#endif