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
27 DECLARE_GLOBAL_DATA_PTR;
28
29 struct cros_gpio_info {
30 const char *linux_name;
31 enum cros_gpio_t type;
32 int gpio_num;
33 int flags;
34 };
35
coral_check_ll_boot(void * ctx,struct event * event)36 static int coral_check_ll_boot(void *ctx, struct event *event)
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 }
60 EVENT_SPY(EVT_MISC_INIT_F, coral_check_ll_boot);
61
arch_misc_init(void)62 int arch_misc_init(void)
63 {
64 return 0;
65 }
66
get_memconfig(struct udevice * dev)67 static 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 */
get_skuconfig(struct udevice * dev)106 static 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
coral_get_str(struct udevice * dev,int id,size_t size,char * val)147 static 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
chromeos_get_gpio(const struct udevice * dev,const char * prop,enum cros_gpio_t type,struct cros_gpio_info * info)190 int 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
chromeos_acpi_gpio_generate(const struct udevice * dev,struct acpi_ctx * ctx)225 static 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
coral_write_acpi_tables(const struct udevice * dev,struct acpi_ctx * ctx)262 static 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
297 struct acpi_ops coral_acpi_ops = {
298 .write_tables = coral_write_acpi_tables,
299 .inject_dsdt = chromeos_acpi_gpio_generate,
300 };
301
302 struct sysinfo_ops coral_sysinfo_ops = {
303 .get_str = coral_get_str,
304 };
305
306 #if CONFIG_IS_ENABLED(OF_REAL)
307 static const struct udevice_id coral_ids[] = {
308 { .compatible = "google,coral" },
309 { }
310 };
311 #endif
312
313 U_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