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