mb/google/brya: Create rull variant
[coreboot2.git] / src / drivers / intel / pmc_mux / conn / conn.c
blobdda1fe0e4b00bac7616ae20f7be227f54386843d
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <acpi/acpi_pld.h>
4 #include <acpi/acpigen.h>
5 #include <boot/coreboot_tables.h>
6 #include <cbmem.h>
7 #include <console/console.h>
8 #include <drivers/usb/acpi/chip.h>
9 #include <intelblocks/acpi.h>
10 #include <stdio.h>
12 #include "chip.h"
14 /* Number of registered connectors */
15 static size_t total_conn_count;
17 static void conn_init(struct device *dev)
19 total_conn_count++;
22 static unsigned int get_usb_port_number(const struct device *usb_port)
24 return usb_port->path.usb.port_id + 1;
27 static struct type_c_info *conn_get_cbmem_buffer(void)
29 struct type_c_info *info;
30 size_t size;
32 info = cbmem_find(CBMEM_ID_TYPE_C_INFO);
33 if (info)
34 return info;
36 size = sizeof(struct type_c_info) + total_conn_count * sizeof(struct type_c_port_info);
37 info = cbmem_add(CBMEM_ID_TYPE_C_INFO, size);
39 if (!info)
40 return NULL;
42 memset(info, 0, size);
43 return info;
46 static void conn_write_cbmem_entry(struct device *dev)
48 const struct drivers_intel_pmc_mux_conn_config *config = dev->chip_info;
49 struct type_c_port_info *port_info;
50 struct type_c_info *info;
51 size_t count;
54 * Do not re-run this code on resume as the cbmem data is populated on boot-up
55 * (non-S3 path) and stays intact across S3 suspend/resume.
57 if (acpi_is_wakeup_s3())
58 return;
60 info = conn_get_cbmem_buffer();
61 if (!info || (info->port_count >= total_conn_count)) {
62 printk(BIOS_ERR, "No space for Type-C port info!\n");
63 return;
66 count = info->port_count;
67 port_info = &info->port_info[count];
68 port_info->usb2_port_number = get_usb_port_number(config->usb2_port);
69 port_info->usb3_port_number = get_usb_port_number(config->usb3_port);
70 port_info->sbu_orientation = config->sbu_orientation;
71 port_info->data_orientation = config->hsl_orientation;
73 printk(BIOS_INFO, "added type-c port%zu info to cbmem: usb2:%d usb3:%d sbu:%d data:%d\n",
74 count, port_info->usb2_port_number, port_info->usb3_port_number,
75 port_info->sbu_orientation, port_info->data_orientation);
77 info->port_count++;
80 static const char *conn_acpi_name(const struct device *dev)
82 static char name[5];
83 snprintf(name, sizeof(name), "CON%1X", dev->path.generic.id);
84 return name;
87 static const char *orientation_to_str(enum type_c_orientation ori)
89 switch (ori) {
90 case TYPEC_ORIENTATION_NORMAL:
91 return "normal";
92 case TYPEC_ORIENTATION_REVERSE:
93 return "reverse";
94 case TYPEC_ORIENTATION_NONE: /* Intentional fallthrough */
95 default:
96 return "";
100 static void get_pld_from_usb_ports(struct acpi_pld *pld,
101 struct device *usb2_port, struct device *usb3_port)
103 struct drivers_usb_acpi_config *config = NULL;
105 if (usb3_port)
106 config = usb3_port->chip_info;
107 else if (usb2_port)
108 config = usb2_port->chip_info;
110 if (config) {
111 if (config->use_custom_pld)
112 *pld = config->custom_pld;
113 else
114 acpi_pld_fill_usb(pld, config->type, &config->group);
118 static void conn_fill_ssdt(const struct device *dev)
120 struct drivers_intel_pmc_mux_conn_config *config = dev->chip_info;
121 struct acpi_dp *dsd;
122 const char *scope;
123 const char *name;
124 struct acpi_pld pld = {0};
126 /* Reference the existing scope and write CONx device */
127 scope = acpi_device_scope(dev);
128 name = acpi_device_name(dev);
129 if (!scope || !name)
130 return;
132 acpigen_write_scope(scope);
133 acpigen_write_device(name);
135 acpigen_write_name_integer("_ADR", dev->path.generic.id);
137 /* _DSD, Device-Specific Data */
138 dsd = acpi_dp_new_table("_DSD");
139 acpi_dp_add_integer(dsd, "usb2-port-number", get_usb_port_number(config->usb2_port));
140 acpi_dp_add_integer(dsd, "usb3-port-number", get_usb_port_number(config->usb3_port));
143 * The kernel assumes that these Type-C signals (SBUs and HSLs) follow the CC lines,
144 * unless they are explicitly called out otherwise.
146 if (config->sbu_orientation != TYPEC_ORIENTATION_NONE)
147 acpi_dp_add_string(dsd, "sbu-orientation",
148 orientation_to_str(config->sbu_orientation));
150 if (config->hsl_orientation != TYPEC_ORIENTATION_NONE)
151 acpi_dp_add_string(dsd, "hsl-orientation",
152 orientation_to_str(config->hsl_orientation));
154 acpi_dp_write(dsd);
156 /* Copy _PLD from USB ports */
157 get_pld_from_usb_ports(&pld, config->usb2_port, config->usb3_port);
158 acpigen_write_pld(&pld);
160 acpigen_pop_len(); /* CONx Device */
161 acpigen_pop_len(); /* Scope */
163 printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name,
164 dev_path(dev));
167 static struct device_operations conn_dev_ops = {
168 .read_resources = noop_read_resources,
169 .set_resources = noop_set_resources,
170 .acpi_name = conn_acpi_name,
171 .acpi_fill_ssdt = conn_fill_ssdt,
172 .init = conn_init,
173 .final = conn_write_cbmem_entry,
176 static void conn_enable(struct device *dev)
178 dev->ops = &conn_dev_ops;
181 struct chip_operations drivers_intel_pmc_mux_conn_ops = {
182 .name = "Intel PMC MUX CONN Driver",
183 .enable_dev = conn_enable,
186 bool intel_pmc_mux_conn_get_ports(const struct device *conn, unsigned int *usb2_port,
187 unsigned int *usb3_port)
189 const struct drivers_intel_pmc_mux_conn_config *mux_config;
191 if (!conn->chip_info || conn->chip_ops != &drivers_intel_pmc_mux_conn_ops)
192 return false;
194 mux_config = conn->chip_info;
195 *usb2_port = get_usb_port_number(mux_config->usb2_port);
196 *usb3_port = get_usb_port_number(mux_config->usb3_port);
198 return true;