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