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