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>
7 #include <console/console.h>
8 #include <drivers/usb/acpi/chip.h>
9 #include <intelblocks/acpi.h>
14 /* Number of registered connectors */
15 static size_t total_conn_count
;
17 static void conn_init(struct device
*dev
)
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
;
32 info
= cbmem_find(CBMEM_ID_TYPE_C_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
);
42 memset(info
, 0, size
);
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
;
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())
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");
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
);
80 static const char *conn_acpi_name(const struct device
*dev
)
83 snprintf(name
, sizeof(name
), "CON%1X", dev
->path
.generic
.id
);
87 static const char *orientation_to_str(enum type_c_orientation ori
)
90 case TYPEC_ORIENTATION_NORMAL
:
92 case TYPEC_ORIENTATION_REVERSE
:
94 case TYPEC_ORIENTATION_NONE
: /* Intentional fallthrough */
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
;
106 config
= usb3_port
->chip_info
;
108 config
= usb2_port
->chip_info
;
111 if (config
->use_custom_pld
)
112 *pld
= config
->custom_pld
;
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
;
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
);
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
));
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
,
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
,
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
)
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
);