This hook can be implmented using events, for the three boards that actually use it. Add the event type and event handlers. Drop CONFIG_MISC_INIT_F since we can just use CONFIG_EVENT to control this. Since sandbox always enables CONFIG_EVENT, we can drop the defconfig lines there too. Signed-off-by: Simon Glass <sjg@chromium.org>
320 lines
7.1 KiB
C
320 lines
7.1 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright 2019 Google LLC
|
|
*/
|
|
|
|
#define LOG_CATEGORY UCLASS_SYSINFO
|
|
|
|
#include <common.h>
|
|
#include <bloblist.h>
|
|
#include <command.h>
|
|
#include <cros_ec.h>
|
|
#include <dm.h>
|
|
#include <event.h>
|
|
#include <init.h>
|
|
#include <log.h>
|
|
#include <sysinfo.h>
|
|
#include <acpi/acpigen.h>
|
|
#include <asm-generic/gpio.h>
|
|
#include <asm/acpi_nhlt.h>
|
|
#include <asm/cb_sysinfo.h>
|
|
#include <asm/intel_gnvs.h>
|
|
#include <asm/intel_pinctrl.h>
|
|
#include <dm/acpi.h>
|
|
#include <linux/delay.h>
|
|
#include "variant_gpio.h"
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
struct cros_gpio_info {
|
|
const char *linux_name;
|
|
enum cros_gpio_t type;
|
|
int gpio_num;
|
|
int flags;
|
|
};
|
|
|
|
static int coral_check_ll_boot(void *ctx, struct event *event)
|
|
{
|
|
if (!ll_boot_init()) {
|
|
printf("Running as secondary loader");
|
|
if (CONFIG_IS_ENABLED(COREBOOT_SYSINFO) &&
|
|
gd->arch.coreboot_table) {
|
|
int ret;
|
|
|
|
printf(" (found coreboot table at %lx)",
|
|
gd->arch.coreboot_table);
|
|
|
|
ret = get_coreboot_info(&lib_sysinfo);
|
|
if (ret) {
|
|
printf("\nFailed to parse coreboot tables (err=%d)\n",
|
|
ret);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
EVENT_SPY(EVT_MISC_INIT_F, coral_check_ll_boot);
|
|
|
|
int arch_misc_init(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int get_memconfig(struct udevice *dev)
|
|
{
|
|
struct gpio_desc gpios[4];
|
|
int cfg;
|
|
int ret;
|
|
|
|
ret = gpio_request_list_by_name(dev, "memconfig-gpios", gpios,
|
|
ARRAY_SIZE(gpios),
|
|
GPIOD_IS_IN | GPIOD_PULL_UP);
|
|
if (ret < 0) {
|
|
log_debug("Cannot get GPIO list '%s' (%d)\n", dev->name, ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Give the lines time to settle */
|
|
udelay(10);
|
|
|
|
ret = dm_gpio_get_values_as_int(gpios, ARRAY_SIZE(gpios));
|
|
if (ret < 0)
|
|
return log_msg_ret("get", ret);
|
|
cfg = ret;
|
|
|
|
ret = gpio_free_list(dev, gpios, ARRAY_SIZE(gpios));
|
|
if (ret)
|
|
return log_msg_ret("free", ret);
|
|
|
|
return cfg;
|
|
}
|
|
|
|
/**
|
|
* get_skuconfig() - Get the SKU number either from pins or the EC
|
|
*
|
|
* Two options are supported:
|
|
* skuconfig-gpios - two pins in the device tree (tried first)
|
|
* EC - reading from the EC (backup)
|
|
*
|
|
* @dev: sysinfo device to use
|
|
* Return: SKU ID, or -ve error if not found
|
|
*/
|
|
static int get_skuconfig(struct udevice *dev)
|
|
{
|
|
struct gpio_desc gpios[2];
|
|
int cfg;
|
|
int ret;
|
|
|
|
ret = gpio_request_list_by_name(dev, "skuconfig-gpios", gpios,
|
|
ARRAY_SIZE(gpios),
|
|
GPIOD_IS_IN);
|
|
if (ret != ARRAY_SIZE(gpios)) {
|
|
struct udevice *cros_ec;
|
|
|
|
log_debug("Cannot get GPIO list '%s' (%d)\n", dev->name, ret);
|
|
|
|
/* Try the EC */
|
|
ret = uclass_first_device_err(UCLASS_CROS_EC, &cros_ec);
|
|
if (ret < 0) {
|
|
log_err("Cannot find EC for SKU details\n");
|
|
return log_msg_ret("sku", ret);
|
|
}
|
|
ret = cros_ec_get_sku_id(cros_ec);
|
|
if (ret < 0) {
|
|
log_err("Cannot read SKU details\n");
|
|
return log_msg_ret("sku", ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
ret = dm_gpio_get_values_as_int_base3(gpios, ARRAY_SIZE(gpios));
|
|
if (ret < 0)
|
|
return log_msg_ret("get", ret);
|
|
cfg = ret;
|
|
|
|
ret = gpio_free_list(dev, gpios, ARRAY_SIZE(gpios));
|
|
if (ret)
|
|
return log_msg_ret("free", ret);
|
|
|
|
return cfg;
|
|
}
|
|
|
|
static int coral_get_str(struct udevice *dev, int id, size_t size, char *val)
|
|
{
|
|
int ret;
|
|
|
|
if (IS_ENABLED(CONFIG_SPL_BUILD))
|
|
return -ENOSYS;
|
|
|
|
switch (id) {
|
|
case SYSINFO_ID_SMBIOS_SYSTEM_VERSION:
|
|
case SYSINFO_ID_SMBIOS_BASEBOARD_VERSION: {
|
|
ret = get_skuconfig(dev);
|
|
|
|
if (ret < 0)
|
|
return ret;
|
|
if (size < 15)
|
|
return -ENOSPC;
|
|
sprintf(val, "rev%d", ret);
|
|
break;
|
|
}
|
|
case SYSINFO_ID_BOARD_MODEL: {
|
|
int mem_config, sku_config;
|
|
const char *model;
|
|
|
|
ret = get_memconfig(dev);
|
|
if (ret < 0)
|
|
log_warning("Unable to read memconfig (err=%d)\n", ret);
|
|
mem_config = ret;
|
|
ret = get_skuconfig(dev);
|
|
if (ret < 0)
|
|
log_warning("Unable to read skuconfig (err=%d)\n", ret);
|
|
sku_config = ret;
|
|
model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
|
|
snprintf(val, size, "%s (memconfig %d, SKU %d)", model,
|
|
mem_config, sku_config);
|
|
break;
|
|
}
|
|
default:
|
|
return -ENOENT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int chromeos_get_gpio(const struct udevice *dev, const char *prop,
|
|
enum cros_gpio_t type, struct cros_gpio_info *info)
|
|
{
|
|
struct udevice *pinctrl;
|
|
struct gpio_desc desc;
|
|
int ret;
|
|
|
|
ret = gpio_request_by_name((struct udevice *)dev, prop, 0, &desc, 0);
|
|
if (ret == -ENOTBLK) {
|
|
info->gpio_num = CROS_GPIO_VIRTUAL;
|
|
log_debug("GPIO '%s' is virtual\n", prop);
|
|
} else if (ret) {
|
|
return log_msg_ret("gpio", ret);
|
|
} else {
|
|
info->gpio_num = desc.offset;
|
|
dm_gpio_free((struct udevice *)dev, &desc);
|
|
}
|
|
info->linux_name = dev_read_string(desc.dev, "linux-name");
|
|
if (!info->linux_name)
|
|
return log_msg_ret("linux-name", -ENOENT);
|
|
info->type = type;
|
|
/* Get ACPI pin from GPIO library if available */
|
|
if (info->gpio_num != CROS_GPIO_VIRTUAL) {
|
|
pinctrl = dev_get_parent(desc.dev);
|
|
info->gpio_num = intel_pinctrl_get_acpi_pin(pinctrl,
|
|
info->gpio_num);
|
|
}
|
|
info->flags = desc.flags & GPIOD_ACTIVE_LOW ? CROS_GPIO_ACTIVE_LOW :
|
|
CROS_GPIO_ACTIVE_HIGH;
|
|
if (!ret)
|
|
dm_gpio_free(desc.dev, &desc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int chromeos_acpi_gpio_generate(const struct udevice *dev,
|
|
struct acpi_ctx *ctx)
|
|
{
|
|
struct cros_gpio_info info[3];
|
|
int count, i;
|
|
int ret;
|
|
|
|
count = 3;
|
|
ret = chromeos_get_gpio(dev, "recovery-gpios", CROS_GPIO_REC, &info[0]);
|
|
if (ret)
|
|
return log_msg_ret("rec", ret);
|
|
ret = chromeos_get_gpio(dev, "write-protect-gpios", CROS_GPIO_WP,
|
|
&info[1]);
|
|
if (ret)
|
|
return log_msg_ret("wp", ret);
|
|
ret = chromeos_get_gpio(dev, "phase-enforce-gpios", CROS_GPIO_PE,
|
|
&info[2]);
|
|
if (ret)
|
|
return log_msg_ret("phase", ret);
|
|
acpigen_write_scope(ctx, "\\");
|
|
acpigen_write_name(ctx, "OIPG");
|
|
acpigen_write_package(ctx, count);
|
|
for (i = 0; i < count; i++) {
|
|
acpigen_write_package(ctx, 4);
|
|
acpigen_write_integer(ctx, info[i].type);
|
|
acpigen_write_integer(ctx, info[i].flags);
|
|
acpigen_write_integer(ctx, info[i].gpio_num);
|
|
acpigen_write_string(ctx, info[i].linux_name);
|
|
acpigen_pop_len(ctx);
|
|
}
|
|
|
|
acpigen_pop_len(ctx);
|
|
acpigen_pop_len(ctx);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int coral_write_acpi_tables(const struct udevice *dev,
|
|
struct acpi_ctx *ctx)
|
|
{
|
|
struct acpi_global_nvs *gnvs;
|
|
struct nhlt *nhlt;
|
|
const char *oem_id = "coral";
|
|
const char *oem_table_id = "coral";
|
|
u32 oem_revision = 3;
|
|
int ret;
|
|
|
|
gnvs = bloblist_find(BLOBLISTT_ACPI_GNVS, sizeof(*gnvs));
|
|
if (!gnvs)
|
|
return log_msg_ret("bloblist", -ENOENT);
|
|
|
|
nhlt = nhlt_init();
|
|
if (!nhlt)
|
|
return -ENOMEM;
|
|
|
|
log_debug("Setting up NHLT\n");
|
|
ret = acpi_setup_nhlt(ctx, nhlt);
|
|
if (ret)
|
|
return log_msg_ret("setup", ret);
|
|
|
|
/* Update NHLT GNVS Data */
|
|
gnvs->nhla = (uintptr_t)ctx->current;
|
|
gnvs->nhll = nhlt_current_size(nhlt);
|
|
|
|
ret = nhlt_serialise_oem_overrides(ctx, nhlt, oem_id, oem_table_id,
|
|
oem_revision);
|
|
if (ret)
|
|
return log_msg_ret("serialise", ret);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct acpi_ops coral_acpi_ops = {
|
|
.write_tables = coral_write_acpi_tables,
|
|
.inject_dsdt = chromeos_acpi_gpio_generate,
|
|
};
|
|
|
|
struct sysinfo_ops coral_sysinfo_ops = {
|
|
.get_str = coral_get_str,
|
|
};
|
|
|
|
#if CONFIG_IS_ENABLED(OF_REAL)
|
|
static const struct udevice_id coral_ids[] = {
|
|
{ .compatible = "google,coral" },
|
|
{ }
|
|
};
|
|
#endif
|
|
|
|
U_BOOT_DRIVER(coral_drv) = {
|
|
.name = "coral",
|
|
.id = UCLASS_SYSINFO,
|
|
.of_match = of_match_ptr(coral_ids),
|
|
.ops = &coral_sysinfo_ops,
|
|
ACPI_OPS_PTR(&coral_acpi_ops)
|
|
};
|