• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <acpi/acpi_device.h>
4 #include <acpi/acpigen.h>
5 #include <console/console.h>
6 #include <stdio.h>
7 
8 #include "chip.h"
9 
uart_acpi_add_gpios_to_crs(struct drivers_uart_acpi_config * config)10 static bool uart_acpi_add_gpios_to_crs(struct drivers_uart_acpi_config *config)
11 {
12 	/*
13 	 * Return false if:
14 	 * 1. GPIOs are exported via a power resource, or
15 	 * 2. Both reset and enable GPIOs are not provided.
16 	 */
17 	if (config->has_power_resource ||
18 	    ((config->reset_gpio.pin_count == 0) &&
19 	     (config->enable_gpio.pin_count == 0)))
20 		return false;
21 
22 	return true;
23 }
24 
uart_acpi_write_gpio(struct acpi_gpio * gpio,int * curr_index)25 static int uart_acpi_write_gpio(struct acpi_gpio *gpio, int *curr_index)
26 {
27 	int ret = -1;
28 
29 	if (gpio->pin_count == 0)
30 		return ret;
31 
32 	acpi_device_write_gpio(gpio);
33 	ret = *curr_index;
34 	(*curr_index)++;
35 
36 	return ret;
37 }
38 
uart_acpi_fill_ssdt(const struct device * dev)39 static void uart_acpi_fill_ssdt(const struct device *dev)
40 {
41 	const char *scope = acpi_device_scope(dev);
42 	const char *path = acpi_device_path(dev);
43 	struct drivers_uart_acpi_config *config = dev->chip_info;
44 	int curr_index = 0;
45 	int irq_gpio_index = -1;
46 	int reset_gpio_index = -1;
47 	int enable_gpio_index = -1;
48 
49 	if (!scope)
50 		return;
51 
52 	if (!config->hid) {
53 		printk(BIOS_ERR, "%s: ERROR: HID required\n", dev_path(dev));
54 		return;
55 	}
56 
57 	acpigen_write_scope(scope);
58 	acpigen_write_device(acpi_device_name(dev));
59 
60 	acpigen_write_name_string("_HID", config->hid);
61 	if (config->cid)
62 		acpigen_write_name_string("_CID", config->cid);
63 	acpigen_write_name_integer("_UID", config->uid);
64 	acpigen_write_name_string("_DDN", config->desc);
65 	acpigen_write_STA(acpi_device_status(dev));
66 
67 	/* Resources */
68 	acpigen_write_name("_CRS");
69 	acpigen_write_resourcetemplate_header();
70 
71 	/* Fix up resource pointer to this scope */
72 	config->uart.resource = scope;
73 	acpi_device_write_uart(&config->uart);
74 
75 	/* Use either Interrupt() or GpioInt() */
76 	if (config->irq_gpio.pin_count)
77 		acpi_device_write_gpio(&config->irq_gpio);
78 	else
79 		acpi_device_write_interrupt(&config->irq);
80 
81 	/* Add enable/reset GPIOs if needed */
82 	if (uart_acpi_add_gpios_to_crs(config)) {
83 		reset_gpio_index = uart_acpi_write_gpio(&config->reset_gpio,
84 							&curr_index);
85 		enable_gpio_index = uart_acpi_write_gpio(&config->enable_gpio,
86 							 &curr_index);
87 	}
88 	acpigen_write_resourcetemplate_footer();
89 
90 	/* Wake capabilities */
91 	if (config->wake) {
92 		acpigen_write_name_integer("_S0W", ACPI_DEVICE_SLEEP_D3_HOT);
93 		acpigen_write_PRW(config->wake, SLP_TYP_S3);
94 	};
95 
96 	/* Write device properties if needed */
97 	if (config->compat_string || irq_gpio_index >= 0 ||
98 	    reset_gpio_index >= 0 || enable_gpio_index >= 0) {
99 		struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
100 		if (config->compat_string)
101 			acpi_dp_add_string(dsd, "compatible",
102 					   config->compat_string);
103 		if (irq_gpio_index >= 0)
104 			acpi_dp_add_gpio(dsd, "irq-gpios", path,
105 					 irq_gpio_index, 0,
106 					 config->irq_gpio.active_low);
107 		if (reset_gpio_index >= 0)
108 			acpi_dp_add_gpio(dsd, "reset-gpios", path,
109 					 reset_gpio_index, 0,
110 					 config->reset_gpio.active_low);
111 		if (enable_gpio_index >= 0)
112 			acpi_dp_add_gpio(dsd, "enable-gpios", path,
113 					 enable_gpio_index, 0,
114 					 config->enable_gpio.active_low);
115 		acpi_dp_write(dsd);
116 	}
117 
118 	/* Power Resource */
119 	if (config->has_power_resource) {
120 		const struct acpi_power_res_params power_res_params = {
121 			&config->reset_gpio,
122 			config->reset_delay_ms,
123 			config->reset_off_delay_ms,
124 			&config->enable_gpio,
125 			config->enable_delay_ms,
126 			config->enable_off_delay_ms,
127 			&config->stop_gpio,
128 			config->stop_delay_ms,
129 			config->stop_off_delay_ms
130 		};
131 		acpi_device_add_power_res(&power_res_params);
132 	}
133 
134 	acpigen_pop_len(); /* Device */
135 	acpigen_pop_len(); /* Scope */
136 
137 	printk(BIOS_INFO, "%s: %s at %s\n", path, config->desc, dev_path(dev));
138 }
139 
uart_acpi_name(const struct device * dev)140 static const char *uart_acpi_name(const struct device *dev)
141 {
142 	struct drivers_uart_acpi_config *config = dev->chip_info;
143 	static char name[5];
144 
145 	if (config->name)
146 		return config->name;
147 
148 	snprintf(name, sizeof(name), "D%03.3X", dev->path.generic.id);
149 	return name;
150 }
151 
152 static struct device_operations uart_acpi_dev_ops = {
153 	.read_resources	= noop_read_resources,
154 	.set_resources	= noop_set_resources,
155 	.acpi_fill_ssdt	= uart_acpi_fill_ssdt,
156 	.acpi_name	= uart_acpi_name,
157 };
158 
uart_acpi_enable(struct device * dev)159 static void uart_acpi_enable(struct device *dev)
160 {
161 	struct drivers_uart_acpi_config *config = dev->chip_info;
162 
163 	if (config->desc)
164 		dev->name = config->desc;
165 	else
166 		config->desc = dev->chip_ops->name;
167 
168 	dev->ops = &uart_acpi_dev_ops;
169 }
170 
171 struct chip_operations drivers_uart_acpi_ops = {
172 	.name = "ACPI UART Device",
173 	.enable_dev = uart_acpi_enable
174 };
175