1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright 2019 Google LLC 4 */ 5 6#define LOG_CATEGORY UCLASS_SYSINFO 7 8#include <common.h> 9#include <bloblist.h> 10#include <command.h> 11#include <cros_ec.h> 12#include <dm.h> 13#include <event.h> 14#include <init.h> 15#include <log.h> 16#include <sysinfo.h> 17#include <acpi/acpigen.h> 18#include <asm-generic/gpio.h> 19#include <asm/acpi_nhlt.h> 20#include <asm/cb_sysinfo.h> 21#include <asm/intel_gnvs.h> 22#include <asm/intel_pinctrl.h> 23#include <dm/acpi.h> 24#include <linux/delay.h> 25#include "variant_gpio.h" 26 27DECLARE_GLOBAL_DATA_PTR; 28 29struct cros_gpio_info { 30 const char *linux_name; 31 enum cros_gpio_t type; 32 int gpio_num; 33 int flags; 34}; 35 36static int coral_check_ll_boot(void) 37{ 38 if (!ll_boot_init()) { 39 printf("Running as secondary loader"); 40 if (CONFIG_IS_ENABLED(COREBOOT_SYSINFO) && 41 gd->arch.coreboot_table) { 42 int ret; 43 44 printf(" (found coreboot table at %lx)", 45 gd->arch.coreboot_table); 46 47 ret = get_coreboot_info(&lib_sysinfo); 48 if (ret) { 49 printf("\nFailed to parse coreboot tables (err=%d)\n", 50 ret); 51 return ret; 52 } 53 } 54 55 printf("\n"); 56 } 57 58 return 0; 59} 60EVENT_SPY_SIMPLE(EVT_MISC_INIT_F, coral_check_ll_boot); 61 62int arch_misc_init(void) 63{ 64 return 0; 65} 66 67static int get_memconfig(struct udevice *dev) 68{ 69 struct gpio_desc gpios[4]; 70 int cfg; 71 int ret; 72 73 ret = gpio_request_list_by_name(dev, "memconfig-gpios", gpios, 74 ARRAY_SIZE(gpios), 75 GPIOD_IS_IN | GPIOD_PULL_UP); 76 if (ret < 0) { 77 log_debug("Cannot get GPIO list '%s' (%d)\n", dev->name, ret); 78 return ret; 79 } 80 81 /* Give the lines time to settle */ 82 udelay(10); 83 84 ret = dm_gpio_get_values_as_int(gpios, ARRAY_SIZE(gpios)); 85 if (ret < 0) 86 return log_msg_ret("get", ret); 87 cfg = ret; 88 89 ret = gpio_free_list(dev, gpios, ARRAY_SIZE(gpios)); 90 if (ret) 91 return log_msg_ret("free", ret); 92 93 return cfg; 94} 95 96/** 97 * get_skuconfig() - Get the SKU number either from pins or the EC 98 * 99 * Two options are supported: 100 * skuconfig-gpios - two pins in the device tree (tried first) 101 * EC - reading from the EC (backup) 102 * 103 * @dev: sysinfo device to use 104 * Return: SKU ID, or -ve error if not found 105 */ 106static int get_skuconfig(struct udevice *dev) 107{ 108 struct gpio_desc gpios[2]; 109 int cfg; 110 int ret; 111 112 ret = gpio_request_list_by_name(dev, "skuconfig-gpios", gpios, 113 ARRAY_SIZE(gpios), 114 GPIOD_IS_IN); 115 if (ret != ARRAY_SIZE(gpios)) { 116 struct udevice *cros_ec; 117 118 log_debug("Cannot get GPIO list '%s' (%d)\n", dev->name, ret); 119 120 /* Try the EC */ 121 ret = uclass_first_device_err(UCLASS_CROS_EC, &cros_ec); 122 if (ret < 0) { 123 log_err("Cannot find EC for SKU details\n"); 124 return log_msg_ret("sku", ret); 125 } 126 ret = cros_ec_get_sku_id(cros_ec); 127 if (ret < 0) { 128 log_err("Cannot read SKU details\n"); 129 return log_msg_ret("sku", ret); 130 } 131 132 return ret; 133 } 134 135 ret = dm_gpio_get_values_as_int_base3(gpios, ARRAY_SIZE(gpios)); 136 if (ret < 0) 137 return log_msg_ret("get", ret); 138 cfg = ret; 139 140 ret = gpio_free_list(dev, gpios, ARRAY_SIZE(gpios)); 141 if (ret) 142 return log_msg_ret("free", ret); 143 144 return cfg; 145} 146 147static int coral_get_str(struct udevice *dev, int id, size_t size, char *val) 148{ 149 int ret; 150 151 if (IS_ENABLED(CONFIG_SPL_BUILD)) 152 return -ENOSYS; 153 154 switch (id) { 155 case SYSINFO_ID_SMBIOS_SYSTEM_VERSION: 156 case SYSINFO_ID_SMBIOS_BASEBOARD_VERSION: { 157 ret = get_skuconfig(dev); 158 159 if (ret < 0) 160 return ret; 161 if (size < 15) 162 return -ENOSPC; 163 sprintf(val, "rev%d", ret); 164 break; 165 } 166 case SYSINFO_ID_BOARD_MODEL: { 167 int mem_config, sku_config; 168 const char *model; 169 170 ret = get_memconfig(dev); 171 if (ret < 0) 172 log_warning("Unable to read memconfig (err=%d)\n", ret); 173 mem_config = ret; 174 ret = get_skuconfig(dev); 175 if (ret < 0) 176 log_warning("Unable to read skuconfig (err=%d)\n", ret); 177 sku_config = ret; 178 model = fdt_getprop(gd->fdt_blob, 0, "model", NULL); 179 snprintf(val, size, "%s (memconfig %d, SKU %d)", model, 180 mem_config, sku_config); 181 break; 182 } 183 default: 184 return -ENOENT; 185 } 186 187 return 0; 188} 189 190int chromeos_get_gpio(const struct udevice *dev, const char *prop, 191 enum cros_gpio_t type, struct cros_gpio_info *info) 192{ 193 struct udevice *pinctrl; 194 struct gpio_desc desc; 195 int ret; 196 197 ret = gpio_request_by_name((struct udevice *)dev, prop, 0, &desc, 0); 198 if (ret == -ENOTBLK) { 199 info->gpio_num = CROS_GPIO_VIRTUAL; 200 log_debug("GPIO '%s' is virtual\n", prop); 201 } else if (ret) { 202 return log_msg_ret("gpio", ret); 203 } else { 204 info->gpio_num = desc.offset; 205 dm_gpio_free((struct udevice *)dev, &desc); 206 } 207 info->linux_name = dev_read_string(desc.dev, "linux-name"); 208 if (!info->linux_name) 209 return log_msg_ret("linux-name", -ENOENT); 210 info->type = type; 211 /* Get ACPI pin from GPIO library if available */ 212 if (info->gpio_num != CROS_GPIO_VIRTUAL) { 213 pinctrl = dev_get_parent(desc.dev); 214 info->gpio_num = intel_pinctrl_get_acpi_pin(pinctrl, 215 info->gpio_num); 216 } 217 info->flags = desc.flags & GPIOD_ACTIVE_LOW ? CROS_GPIO_ACTIVE_LOW : 218 CROS_GPIO_ACTIVE_HIGH; 219 if (!ret) 220 dm_gpio_free(desc.dev, &desc); 221 222 return 0; 223} 224 225static int chromeos_acpi_gpio_generate(const struct udevice *dev, 226 struct acpi_ctx *ctx) 227{ 228 struct cros_gpio_info info[3]; 229 int count, i; 230 int ret; 231 232 count = 3; 233 ret = chromeos_get_gpio(dev, "recovery-gpios", CROS_GPIO_REC, &info[0]); 234 if (ret) 235 return log_msg_ret("rec", ret); 236 ret = chromeos_get_gpio(dev, "write-protect-gpios", CROS_GPIO_WP, 237 &info[1]); 238 if (ret) 239 return log_msg_ret("wp", ret); 240 ret = chromeos_get_gpio(dev, "phase-enforce-gpios", CROS_GPIO_PE, 241 &info[2]); 242 if (ret) 243 return log_msg_ret("phase", ret); 244 acpigen_write_scope(ctx, "\\"); 245 acpigen_write_name(ctx, "OIPG"); 246 acpigen_write_package(ctx, count); 247 for (i = 0; i < count; i++) { 248 acpigen_write_package(ctx, 4); 249 acpigen_write_integer(ctx, info[i].type); 250 acpigen_write_integer(ctx, info[i].flags); 251 acpigen_write_integer(ctx, info[i].gpio_num); 252 acpigen_write_string(ctx, info[i].linux_name); 253 acpigen_pop_len(ctx); 254 } 255 256 acpigen_pop_len(ctx); 257 acpigen_pop_len(ctx); 258 259 return 0; 260} 261 262static int coral_write_acpi_tables(const struct udevice *dev, 263 struct acpi_ctx *ctx) 264{ 265 struct acpi_global_nvs *gnvs; 266 struct nhlt *nhlt; 267 const char *oem_id = "coral"; 268 const char *oem_table_id = "coral"; 269 u32 oem_revision = 3; 270 int ret; 271 272 gnvs = bloblist_find(BLOBLISTT_ACPI_GNVS, sizeof(*gnvs)); 273 if (!gnvs) 274 return log_msg_ret("bloblist", -ENOENT); 275 276 nhlt = nhlt_init(); 277 if (!nhlt) 278 return -ENOMEM; 279 280 log_debug("Setting up NHLT\n"); 281 ret = acpi_setup_nhlt(ctx, nhlt); 282 if (ret) 283 return log_msg_ret("setup", ret); 284 285 /* Update NHLT GNVS Data */ 286 gnvs->nhla = (uintptr_t)ctx->current; 287 gnvs->nhll = nhlt_current_size(nhlt); 288 289 ret = nhlt_serialise_oem_overrides(ctx, nhlt, oem_id, oem_table_id, 290 oem_revision); 291 if (ret) 292 return log_msg_ret("serialise", ret); 293 294 return 0; 295} 296 297struct acpi_ops coral_acpi_ops = { 298 .write_tables = coral_write_acpi_tables, 299 .inject_dsdt = chromeos_acpi_gpio_generate, 300}; 301 302struct sysinfo_ops coral_sysinfo_ops = { 303 .get_str = coral_get_str, 304}; 305 306#if CONFIG_IS_ENABLED(OF_REAL) 307static const struct udevice_id coral_ids[] = { 308 { .compatible = "google,coral" }, 309 { } 310}; 311#endif 312 313U_BOOT_DRIVER(coral_drv) = { 314 .name = "coral", 315 .id = UCLASS_SYSINFO, 316 .of_match = of_match_ptr(coral_ids), 317 .ops = &coral_sysinfo_ops, 318 ACPI_OPS_PTR(&coral_acpi_ops) 319}; 320