1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Generic WiFi ACPI info
4  *
5  * Copyright 2019 Google LLC
6  * Modified from coreboot src/drivers/wifi/generic.c
7  */
8 
9 #include <common.h>
10 #include <log.h>
11 #include <acpi/acpigen.h>
12 #include <acpi/acpi_device.h>
13 #include <dm.h>
14 #include <dm/acpi.h>
15 
16 /* WRDS Spec Revision */
17 #define WRDS_REVISION 0x0
18 
19 /* EWRD Spec Revision */
20 #define EWRD_REVISION 0x0
21 
22 /* WRDS Domain type */
23 #define WRDS_DOMAIN_TYPE_WIFI 0x7
24 
25 /* EWRD Domain type */
26 #define EWRD_DOMAIN_TYPE_WIFI 0x7
27 
28 /* WGDS Domain type */
29 #define WGDS_DOMAIN_TYPE_WIFI 0x7
30 
31 /*
32  * WIFI ACPI NAME = "WF" + hex value of last 8 bits of dev_path_encode + '\0'
33  * The above representation returns unique and consistent name every time
34  * generate_wifi_acpi_name is invoked. The last 8 bits of dev_path_encode is
35  * chosen since it contains the bus address of the device.
36  */
37 #define WIFI_ACPI_NAME_MAX_LEN 5
38 
39 /**
40  * struct generic_wifi_config - Data structure to contain common wifi config
41  * @wake: Wake pin for ACPI _PRW
42  * @maxsleep: Maximum sleep state to wake from
43  */
44 struct generic_wifi_config {
45 	unsigned int wake;
46 	unsigned int maxsleep;
47 };
48 
generic_wifi_fill_ssdt(struct acpi_ctx * ctx,const struct udevice * dev,const struct generic_wifi_config * config)49 static int generic_wifi_fill_ssdt(struct acpi_ctx *ctx,
50 				  const struct udevice *dev,
51 				  const struct generic_wifi_config *config)
52 {
53 	char name[ACPI_NAME_MAX];
54 	char path[ACPI_PATH_MAX];
55 	pci_dev_t bdf;
56 	u32 address;
57 	int ret;
58 
59 	ret = acpi_device_path(dev_get_parent(dev), path, sizeof(path));
60 	if (ret)
61 		return log_msg_ret("path", ret);
62 	ret = acpi_get_name(dev, name);
63 	if (ret)
64 		return log_msg_ret("name", ret);
65 
66 	/* Device */
67 	acpigen_write_scope(ctx, path);
68 	acpigen_write_device(ctx, name);
69 	acpigen_write_name_integer(ctx, "_UID", 0);
70 	acpigen_write_name_string(ctx, "_DDN",
71 				  dev_read_string(dev, "acpi,ddn"));
72 
73 	/* Address */
74 	bdf = dm_pci_get_bdf(dev);
75 	address = (PCI_DEV(bdf) << 16) | PCI_FUNC(bdf);
76 	acpigen_write_name_dword(ctx, "_ADR", address);
77 
78 	/* Wake capabilities */
79 	if (config)
80 		acpigen_write_prw(ctx, config->wake, config->maxsleep);
81 
82 	acpigen_pop_len(ctx); /* Device */
83 	acpigen_pop_len(ctx); /* Scope */
84 
85 	return 0;
86 }
87 
intel_wifi_acpi_fill_ssdt(const struct udevice * dev,struct acpi_ctx * ctx)88 static int intel_wifi_acpi_fill_ssdt(const struct udevice *dev,
89 				     struct acpi_ctx *ctx)
90 {
91 	struct generic_wifi_config config;
92 	bool have_config;
93 	int ret;
94 
95 	ret = dev_read_u32(dev, "acpi,wake", &config.wake);
96 	have_config = !ret;
97 	/* By default, all intel wifi chips wake from S3 */
98 	config.maxsleep = 3;
99 	ret = generic_wifi_fill_ssdt(ctx, dev, have_config ? &config : NULL);
100 	if (ret)
101 		return log_msg_ret("wifi", ret);
102 
103 	return 0;
104 }
105 
106 struct acpi_ops wifi_acpi_ops = {
107 	.fill_ssdt	= intel_wifi_acpi_fill_ssdt,
108 };
109 
110 static const struct udevice_id intel_wifi_ids[] = {
111 	{ .compatible = "intel,generic-wifi" },
112 	{ }
113 };
114 
115 U_BOOT_DRIVER(intel_wifi) = {
116 	.name		= "intel_wifi",
117 	.id		= UCLASS_MISC,
118 	.of_match	= intel_wifi_ids,
119 	ACPI_OPS_PTR(&wifi_acpi_ops)
120 };
121