• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
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>
11 
12 #include "chip.h"
13 
14 /* Number of registered connectors */
15 static size_t total_conn_count;
16 
conn_init(struct device * dev)17 static void conn_init(struct device *dev)
18 {
19 	total_conn_count++;
20 }
21 
get_usb_port_number(const struct device * usb_port)22 static unsigned int get_usb_port_number(const struct device *usb_port)
23 {
24 	return usb_port->path.usb.port_id + 1;
25 }
26 
conn_get_cbmem_buffer(void)27 static struct type_c_info *conn_get_cbmem_buffer(void)
28 {
29 	struct type_c_info *info;
30 	size_t size;
31 
32 	info = cbmem_find(CBMEM_ID_TYPE_C_INFO);
33 	if (info)
34 		return info;
35 
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);
38 
39 	if (!info)
40 		return NULL;
41 
42 	memset(info, 0, size);
43 	return info;
44 }
45 
conn_write_cbmem_entry(struct device * dev)46 static void conn_write_cbmem_entry(struct device *dev)
47 {
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;
52 
53 	/*
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.
56 	 */
57 	if (acpi_is_wakeup_s3())
58 		return;
59 
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;
64 	}
65 
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;
72 
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);
76 
77 	info->port_count++;
78 }
79 
conn_acpi_name(const struct device * dev)80 static const char *conn_acpi_name(const struct device *dev)
81 {
82 	static char name[5];
83 	snprintf(name, sizeof(name), "CON%1X", dev->path.generic.id);
84 	return name;
85 }
86 
orientation_to_str(enum type_c_orientation ori)87 static const char *orientation_to_str(enum type_c_orientation ori)
88 {
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 "";
97 	}
98 }
99 
get_pld_from_usb_ports(struct acpi_pld * pld,struct device * usb2_port,struct device * usb3_port)100 static void get_pld_from_usb_ports(struct acpi_pld *pld,
101 	struct device *usb2_port, struct device *usb3_port)
102 {
103 	struct drivers_usb_acpi_config *config = NULL;
104 
105 	if (usb3_port)
106 		config = usb3_port->chip_info;
107 	else if (usb2_port)
108 		config = usb2_port->chip_info;
109 
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);
115 	}
116 }
117 
conn_fill_ssdt(const struct device * dev)118 static void conn_fill_ssdt(const struct device *dev)
119 {
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};
125 
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;
131 
132 	acpigen_write_scope(scope);
133 	acpigen_write_device(name);
134 
135 	acpigen_write_name_integer("_ADR", dev->path.generic.id);
136 
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));
141 
142 	/*
143 	 * The kernel assumes that these Type-C signals (SBUs and HSLs) follow the CC lines,
144 	 * unless they are explicitly called out otherwise.
145 	 */
146 	if (config->sbu_orientation != TYPEC_ORIENTATION_NONE)
147 		acpi_dp_add_string(dsd, "sbu-orientation",
148 				   orientation_to_str(config->sbu_orientation));
149 
150 	if (config->hsl_orientation != TYPEC_ORIENTATION_NONE)
151 		acpi_dp_add_string(dsd, "hsl-orientation",
152 				   orientation_to_str(config->hsl_orientation));
153 
154 	acpi_dp_write(dsd);
155 
156 	/* Copy _PLD from USB ports */
157 	get_pld_from_usb_ports(&pld, config->usb2_port, config->usb3_port);
158 	acpigen_write_pld(&pld);
159 
160 	acpigen_pop_len(); /* CONx Device */
161 	acpigen_pop_len(); /* Scope */
162 
163 	printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), dev->chip_ops->name,
164 	       dev_path(dev));
165 }
166 
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,
174 };
175 
conn_enable(struct device * dev)176 static void conn_enable(struct device *dev)
177 {
178 	dev->ops = &conn_dev_ops;
179 }
180 
181 struct chip_operations drivers_intel_pmc_mux_conn_ops = {
182 	.name = "Intel PMC MUX CONN Driver",
183 	.enable_dev	= conn_enable,
184 };
185 
intel_pmc_mux_conn_get_ports(const struct device * conn,unsigned int * usb2_port,unsigned int * usb3_port)186 bool intel_pmc_mux_conn_get_ports(const struct device *conn, unsigned int *usb2_port,
187 					unsigned int *usb3_port)
188 {
189 	const struct drivers_intel_pmc_mux_conn_config *mux_config;
190 
191 	if (!conn->chip_info || conn->chip_ops != &drivers_intel_pmc_mux_conn_ops)
192 		return false;
193 
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);
197 
198 	return true;
199 };
200