1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <acpi/acpi_device.h>
4 #include <acpi/acpigen.h>
5 #include <console/console.h>
6 #include <device/path.h>
10 static bool uart_acpi_add_gpios_to_crs(struct drivers_uart_acpi_config
*config
)
14 * 1. GPIOs are exported via a power resource, or
15 * 2. Both reset and enable GPIOs are not provided.
17 if (config
->has_power_resource
||
18 ((config
->reset_gpio
.pin_count
== 0) &&
19 (config
->enable_gpio
.pin_count
== 0)))
25 static int uart_acpi_write_gpio(struct acpi_gpio
*gpio
, int *curr_index
)
29 if (gpio
->pin_count
== 0)
32 acpi_device_write_gpio(gpio
);
39 static void uart_acpi_fill_ssdt(const struct device
*dev
)
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
;
45 int irq_gpio_index
= -1;
46 int reset_gpio_index
= -1;
47 int enable_gpio_index
= -1;
53 printk(BIOS_ERR
, "%s: ERROR: HID required\n", dev_path(dev
));
57 acpigen_write_scope(scope
);
58 acpigen_write_device(acpi_device_name(dev
));
60 acpigen_write_name_string("_HID", config
->hid
);
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
));
68 acpigen_write_name("_CRS");
69 acpigen_write_resourcetemplate_header();
71 /* Fix up resource pointer to this scope */
72 config
->uart
.resource
= scope
;
73 acpi_device_write_uart(&config
->uart
);
75 /* Use either Interrupt() or GpioInt() */
76 if (config
->irq_gpio
.pin_count
)
77 acpi_device_write_gpio(&config
->irq_gpio
);
79 acpi_device_write_interrupt(&config
->irq
);
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
,
85 enable_gpio_index
= uart_acpi_write_gpio(&config
->enable_gpio
,
88 acpigen_write_resourcetemplate_footer();
90 /* Wake capabilities */
92 acpigen_write_name_integer("_S0W", ACPI_DEVICE_SLEEP_D3_HOT
);
93 acpigen_write_PRW(config
->wake
, SLP_TYP_S3
);
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
,
106 config
->irq_gpio
.active_low
);
107 if (reset_gpio_index
>= 0)
108 acpi_dp_add_gpio(dsd
, "reset-gpios", path
,
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
);
119 if (config
->has_power_resource
) {
120 const struct acpi_power_res_params power_res_params
= {
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
,
128 config
->stop_delay_ms
,
129 config
->stop_off_delay_ms
131 acpi_device_add_power_res(&power_res_params
);
134 acpigen_pop_len(); /* Device */
135 acpigen_pop_len(); /* Scope */
137 printk(BIOS_INFO
, "%s: %s at %s\n", path
, config
->desc
, dev_path(dev
));
140 static const char *uart_acpi_name(const struct device
*dev
)
142 struct drivers_uart_acpi_config
*config
= dev
->chip_info
;
148 snprintf(name
, sizeof(name
), "D%03.3X", dev
->path
.generic
.id
);
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
,
159 static void uart_acpi_enable(struct device
*dev
)
161 struct drivers_uart_acpi_config
*config
= dev
->chip_info
;
164 dev
->name
= config
->desc
;
166 config
->desc
= dev
->chip_ops
->name
;
168 dev
->ops
= &uart_acpi_dev_ops
;
171 struct chip_operations drivers_uart_acpi_ops
= {
172 CHIP_NAME("ACPI UART Device")
173 .enable_dev
= uart_acpi_enable