xref: /aosp_15_r20/external/coreboot/src/acpi/soundwire.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpigen.h>
4 #include <acpi/acpi_device.h>
5 #include <acpi/acpi_soundwire.h>
6 #include <commonlib/helpers.h>
7 #include <device/soundwire.h>
8 #include <stddef.h>
9 
10 /* Specification-defined prefix for SoundWire properties. */
11 #define SDW_PFX "mipi-sdw-"
12 
13 /* Generate SoundWire property for integer. */
14 #define SDW_INT(__key, __val) \
15 	acpi_dp_add_integer(dsd, SDW_PFX __key, __val)
16 
17 /* Generate SoundWire property for integer array. */
18 #define SDW_INT_ARRAY(__key, __val) \
19 	acpi_dp_add_integer_array(dsd, SDW_PFX __key, __val, __val##_count)
20 
21 /**
22  * struct soundwire_name_map - Map ACPI name to SoundWire property name.
23  * @acpi_name: ACPI compatible name string.
24  * @sdw_name: MIPI SoundWire property name string.
25  */
26 struct soundwire_name_map {
27 	const char *acpi_name;
28 	const char *sdw_name;
29 };
30 
31 static const struct soundwire_name_map bra_mode_names[] = {
32 	{ "BRA0", SDW_PFX "port-bra-mode-0" },
33 	{ "BRA1", SDW_PFX "port-bra-mode-1" },
34 	{ "BRA2", SDW_PFX "port-bra-mode-2" },
35 	{ "BRA3", SDW_PFX "port-bra-mode-3" },
36 };
37 
38 static const struct soundwire_name_map audio_mode_names[] = {
39 	{ "MOD0", SDW_PFX "port-audio-mode-0" },
40 	{ "MOD1", SDW_PFX "port-audio-mode-1" },
41 	{ "MOD2", SDW_PFX "port-audio-mode-2" },
42 	{ "MOD3", SDW_PFX "port-audio-mode-3" },
43 };
44 
45 static const struct soundwire_name_map dpn_source_names[] = {
46 	{ "DP0",  SDW_PFX "dp-0-subproperties" },
47 	{ "SRC1", SDW_PFX "dp-1-source-subproperties" },
48 	{ "SRC2", SDW_PFX "dp-2-source-subproperties" },
49 	{ "SRC3", SDW_PFX "dp-3-source-subproperties" },
50 	{ "SRC4", SDW_PFX "dp-4-source-subproperties" },
51 	{ "SRC5", SDW_PFX "dp-5-source-subproperties" },
52 	{ "SRC6", SDW_PFX "dp-6-source-subproperties" },
53 	{ "SRC7", SDW_PFX "dp-7-source-subproperties" },
54 	{ "SRC8", SDW_PFX "dp-8-source-subproperties" },
55 	{ "SRC9", SDW_PFX "dp-9-source-subproperties" },
56 	{ "SRCA", SDW_PFX "dp-10-source-subproperties" },
57 	{ "SRCB", SDW_PFX "dp-11-source-subproperties" },
58 	{ "SRCC", SDW_PFX "dp-12-source-subproperties" },
59 	{ "SRCD", SDW_PFX "dp-13-source-subproperties" }
60 };
61 
62 static const struct soundwire_name_map dpn_sink_names[] = {
63 	{ "DP0",  SDW_PFX "dp-0-subproperties" },
64 	{ "SNK1", SDW_PFX "dp-1-sink-subproperties" },
65 	{ "SNK2", SDW_PFX "dp-2-sink-subproperties" },
66 	{ "SNK3", SDW_PFX "dp-3-sink-subproperties" },
67 	{ "SNK4", SDW_PFX "dp-4-sink-subproperties" },
68 	{ "SNK5", SDW_PFX "dp-5-sink-subproperties" },
69 	{ "SNK6", SDW_PFX "dp-6-sink-subproperties" },
70 	{ "SNK7", SDW_PFX "dp-7-sink-subproperties" },
71 	{ "SNK8", SDW_PFX "dp-8-sink-subproperties" },
72 	{ "SNK9", SDW_PFX "dp-9-sink-subproperties" },
73 	{ "SNKA", SDW_PFX "dp-10-sink-subproperties" },
74 	{ "SNKB", SDW_PFX "dp-11-sink-subproperties" },
75 	{ "SNKC", SDW_PFX "dp-12-sink-subproperties" },
76 	{ "SNKD", SDW_PFX "dp-13-sink-subproperties" }
77 };
78 
79 static const struct soundwire_name_map link_names[] = {
80 	{ "LNK0", SDW_PFX "link-0-subproperties" },
81 	{ "LNK1", SDW_PFX "link-1-subproperties" },
82 	{ "LNK2", SDW_PFX "link-2-subproperties" },
83 	{ "LNK3", SDW_PFX "link-3-subproperties" },
84 	{ "LNK4", SDW_PFX "link-4-subproperties" },
85 	{ "LNK5", SDW_PFX "link-5-subproperties" },
86 	{ "LNK6", SDW_PFX "link-6-subproperties" },
87 	{ "LNK7", SDW_PFX "link-7-subproperties" }
88 };
89 
90 static const char * const multilane_names[] = {
91 	SDW_PFX "lane-1-mapping",
92 	SDW_PFX "lane-2-mapping",
93 	SDW_PFX "lane-3-mapping",
94 	SDW_PFX "lane-4-mapping",
95 	SDW_PFX "lane-5-mapping",
96 	SDW_PFX "lane-6-mapping",
97 	SDW_PFX "lane-7-mapping",
98 	SDW_PFX "lane-8-mapping"
99 };
100 
101 static const char * const multilane_master_lane_names[] = {
102 	SDW_PFX "master-lane-1",
103 	SDW_PFX "master-lane-2",
104 	SDW_PFX "master-lane-3",
105 	SDW_PFX "master-lane-4",
106 	SDW_PFX "master-lane-5",
107 	SDW_PFX "master-lane-6",
108 	SDW_PFX "master-lane-7",
109 	SDW_PFX "master-lane-8"
110 };
111 
112 static const char * const multilane_slave_link_names[] = {
113 	SDW_PFX "slave-link-A",
114 	SDW_PFX "slave-link-B",
115 	SDW_PFX "slave-link-C",
116 	SDW_PFX "slave-link-D",
117 	SDW_PFX "slave-link-E",
118 	SDW_PFX "slave-link-F",
119 	SDW_PFX "slave-link-G",
120 	SDW_PFX "slave-link-I"
121 };
122 
123 static const char * const multilane_bus_holder_names[] = {
124 	SDW_PFX "lane-1-bus-holder",
125 	SDW_PFX "lane-2-bus-holder",
126 	SDW_PFX "lane-3-bus-holder",
127 	SDW_PFX "lane-4-bus-holder",
128 	SDW_PFX "lane-5-bus-holder",
129 	SDW_PFX "lane-6-bus-holder",
130 	SDW_PFX "lane-7-bus-holder",
131 	SDW_PFX "lane-8-bus-holder"
132 };
133 
soundwire_gen_interface_revision(struct acpi_dp * dsd)134 static void soundwire_gen_interface_revision(struct acpi_dp *dsd)
135 {
136 	acpi_dp_add_integer(dsd, SDW_PFX "sw-interface-revision", SOUNDWIRE_SW_VERSION_1_0);
137 }
138 
soundwire_gen_slave(struct acpi_dp * dsd,const struct soundwire_slave * prop)139 static void soundwire_gen_slave(struct acpi_dp *dsd, const struct soundwire_slave *prop)
140 {
141 	soundwire_gen_interface_revision(dsd);
142 	SDW_INT("wake-up-unavailable", prop->wake_up_unavailable);
143 	SDW_INT("test-mode-supported", prop->test_mode_supported);
144 	SDW_INT("clock-stop-mode1-supported", prop->clock_stop_mode1_supported);
145 
146 	/* Clock Stop Prepare Timeout only used without simplified Clock Stop Prepare. */
147 	SDW_INT("simplified-clockstopprepare-sm-supported",
148 		prop->simplified_clockstopprepare_sm_supported);
149 	if (!prop->simplified_clockstopprepare_sm_supported)
150 		SDW_INT("clockstopprepare-timeout", prop->clockstopprepare_timeout);
151 
152 	SDW_INT("clockstopprepare-hard-reset-behavior",
153 		prop->clockstopprepare_hard_reset_behavior);
154 	SDW_INT("slave-channelprepare-timeout", prop->slave_channelprepare_timeout);
155 	SDW_INT("highPHY-capable", prop->highPHY_capable);
156 	SDW_INT("paging-supported", prop->paging_supported);
157 	SDW_INT("bank-delay-supported", prop->bank_delay_supported);
158 	SDW_INT("port15-read-behavior", prop->port15_read_behavior);
159 	SDW_INT("master-count", prop->master_count);
160 	SDW_INT("source-port-list", prop->source_port_list);
161 	SDW_INT("sink-port-list", prop->sink_port_list);
162 }
163 
soundwire_gen_multilane(struct acpi_dp * dsd,const struct soundwire_multilane * prop)164 static void soundwire_gen_multilane(struct acpi_dp *dsd, const struct soundwire_multilane *prop)
165 {
166 	size_t i;
167 
168 	soundwire_gen_interface_revision(dsd);
169 
170 	/* Fill out multilane map based on master/slave links. */
171 	for (i = 0; i < prop->lane_mapping_count && i < SOUNDWIRE_MAX_LANE; i++) {
172 		const struct soundwire_multilane_map *map = &prop->lane_mapping[i];
173 		const char *name;
174 
175 		/* Get the name of this connection */
176 		if (map->direction == MASTER_LANE)
177 			name = multilane_master_lane_names[map->connection.master_lane];
178 		else
179 			name = multilane_slave_link_names[map->connection.slave_link];
180 
181 		acpi_dp_add_string(dsd, multilane_names[map->lane], name);
182 	}
183 
184 	/* Add bus holder properties. */
185 	for (i = 0; i < prop->lane_bus_holder_count; i++)
186 		acpi_dp_add_integer(dsd, multilane_bus_holder_names[i],
187 				    prop->lane_bus_holder[i]);
188 }
189 
soundwire_gen_link(struct acpi_dp * dsd,const struct soundwire_link * prop)190 static void soundwire_gen_link(struct acpi_dp *dsd, const struct soundwire_link *prop)
191 {
192 	SDW_INT("clock-stop-mode0-supported", prop->clock_stop_mode0_supported);
193 	SDW_INT("clock-stop-mode1-supported", prop->clock_stop_mode1_supported);
194 	if (prop->clock_frequencies_supported_count > 0 &&
195 	    prop->clock_frequencies_supported_count < SOUNDWIRE_MAX) {
196 		SDW_INT_ARRAY("clock-frequencies-supported",
197 			      prop->clock_frequencies_supported);
198 	}
199 	SDW_INT("default-frame-rate", prop->default_frame_rate);
200 	SDW_INT("default-frame-row-size", prop->default_frame_row_size);
201 	SDW_INT("default-frame-col-size", prop->default_frame_col_size);
202 	SDW_INT("dynamic-frame-shape", prop->dynamic_frame_shape);
203 	SDW_INT("command-error-threshold", prop->command_error_threshold);
204 }
205 
soundwire_gen_bra_mode(struct acpi_dp * dsd,const struct soundwire_bra_mode * prop)206 static void soundwire_gen_bra_mode(struct acpi_dp *dsd, const struct soundwire_bra_mode *prop)
207 {
208 	/* Bus frequency configs used if min/max not supported. */
209 	if (prop->bus_frequency_configs_count > 0 &&
210 	    prop->bus_frequency_configs_count < SOUNDWIRE_MAX) {
211 		SDW_INT_ARRAY("bra-mode-bus-frequency-configs", prop->bus_frequency_configs);
212 	} else {
213 		SDW_INT("bra-mode-min-bus-frequency", prop->min_bus_frequency);
214 		SDW_INT("bra-mode-max-bus-frequency", prop->max_bus_frequency);
215 	}
216 	SDW_INT("bra-mode-max-data-per-frame", prop->max_data_per_frame);
217 	SDW_INT("bra-mode-min-us-between-transactions", prop->min_us_between_transactions);
218 }
219 
soundwire_gen_audio_mode(struct acpi_dp * dsd,const struct soundwire_audio_mode * prop)220 static void soundwire_gen_audio_mode(struct acpi_dp *dsd,
221 				     const struct soundwire_audio_mode *prop)
222 {
223 	/* Bus frequency configs used if min/max not supported. */
224 	if (prop->bus_frequency_configs_count > 0 &&
225 	    prop->bus_frequency_configs_count < SOUNDWIRE_MAX) {
226 		SDW_INT_ARRAY("audio-mode-bus-frequency-configs", prop->bus_frequency_configs);
227 	} else {
228 		SDW_INT("audio-mode-min-bus-frequency", prop->min_bus_frequency);
229 		SDW_INT("audio-mode-max-bus-frequency", prop->max_bus_frequency);
230 	}
231 
232 	/* Sampling frequency configs used if min/max not supported. */
233 	if (prop->sampling_frequency_configs_count > 0 &&
234 	    prop->sampling_frequency_configs_count < SOUNDWIRE_MAX) {
235 		SDW_INT_ARRAY("audio-mode-sampling-frequency-configs",
236 			      prop->sampling_frequency_configs);
237 	} else {
238 		SDW_INT("audio-mode-max-sampling-frequency", prop->max_sampling_frequency);
239 		SDW_INT("audio-mode-min-sampling-frequency", prop->min_sampling_frequency);
240 	}
241 
242 	SDW_INT("audio-mode-prepare-channel-behavior", prop->prepare_channel_behavior);
243 	SDW_INT("audio-mode-glitchless-transitions", prop->glitchless_transitions);
244 }
245 
soundwire_gen_dp0(struct acpi_dp * dsd,const struct soundwire_dp0 * prop)246 static void soundwire_gen_dp0(struct acpi_dp *dsd, const struct soundwire_dp0 *prop)
247 {
248 	size_t i;
249 
250 	/* Max wordlength configs used if min/max not supported. */
251 	if (prop->port_wordlength_configs_count > 0 &&
252 	    prop->port_wordlength_configs_count < SOUNDWIRE_MAX) {
253 		SDW_INT_ARRAY("port-wordlength-configs", prop->port_wordlength_configs);
254 	} else {
255 		SDW_INT("port-max-wordlength", prop->port_max_wordlength);
256 		SDW_INT("port-min-wordlength", prop->port_min_wordlength);
257 	}
258 	SDW_INT("bra-flow-controlled", prop->bra_flow_controlled);
259 	SDW_INT("bra-imp-def-response-supported", prop->bra_imp_def_response_supported);
260 	SDW_INT("bra-role-supported", prop->bra_role_supported);
261 	SDW_INT("simplified-channel-prepare-sm", prop->simplified_channel_prepare_sm);
262 	SDW_INT("imp-def-dp0-interrupts-supported", prop->imp_def_dp0_interrupts_supported);
263 	SDW_INT("imp-def-bpt-supported", prop->imp_def_bpt_supported);
264 
265 	/* Add bulk register access mode property pointers. */
266 	for (i = 0; i < prop->bra_mode_count && i < SOUNDWIRE_MAX_MODE; i++) {
267 		struct acpi_dp *bra = acpi_dp_new_table(bra_mode_names[i].acpi_name);
268 		acpi_dp_add_child(dsd, bra_mode_names[i].sdw_name, bra);
269 	}
270 }
271 
soundwire_gen_dpn(struct acpi_dp * dsd,const struct soundwire_dpn * prop)272 static void soundwire_gen_dpn(struct acpi_dp *dsd, const struct soundwire_dpn *prop)
273 {
274 	size_t i;
275 
276 	SDW_INT("data-port-type", prop->data_port_type);
277 	SDW_INT("max-grouping-supported", prop->max_grouping_supported);
278 	SDW_INT("imp-def-dpn-interrupts-supported", prop->imp_def_dpn_interrupts_supported);
279 	SDW_INT("modes-supported", prop->modes_supported);
280 	SDW_INT("max-async-buffer", prop->max_async_buffer);
281 	SDW_INT("block-packing-mode", prop->block_packing_mode);
282 	SDW_INT("port-encoding-type", prop->port_encoding_type);
283 
284 	/* Max wordlength configs used if min/max not supported. */
285 	if (prop->port_wordlength_configs_count > 0 &&
286 	    prop->port_wordlength_configs_count < SOUNDWIRE_MAX) {
287 		SDW_INT_ARRAY("port-wordlength-configs", prop->port_wordlength_configs);
288 	} else {
289 		SDW_INT("port-max-wordlength", prop->port_max_wordlength);
290 		SDW_INT("port-min-wordlength", prop->port_min_wordlength);
291 	}
292 
293 	/* Channel Prepare Timeout only used without simplified Channel Prepare. */
294 	SDW_INT("simplified-channelprepare-sm", prop->simplified_channelprepare_sm);
295 	if (!prop->simplified_channelprepare_sm)
296 		SDW_INT("port-channelprepare-timeout", prop->port_channelprepare_timeout);
297 
298 	/* Channel number list used if min/max not supported. */
299 	if (prop->channel_number_list_count > 0 &&
300 	    prop->channel_number_list_count < SOUNDWIRE_MAX) {
301 		SDW_INT_ARRAY("channel-number-list", prop->channel_number_list);
302 	} else {
303 		SDW_INT("min-channel-number", prop->min_channel_number);
304 		SDW_INT("max-channel-number", prop->max_channel_number);
305 	}
306 	if (prop->channel_combination_list_count > 0 &&
307 	    prop->channel_combination_list_count < SOUNDWIRE_MAX) {
308 		SDW_INT_ARRAY("channel-combination-list", prop->channel_combination_list);
309 	}
310 
311 	/* Add reference to Audio Mode properties. */
312 	for (i = 0; i < prop->port_audio_mode_count && i < SOUNDWIRE_MAX_MODE; i++) {
313 		struct acpi_dp *am = acpi_dp_new_table(audio_mode_names[i].acpi_name);
314 		acpi_dp_add_child(dsd, audio_mode_names[i].sdw_name, am);
315 	}
316 }
317 
soundwire_gen_controller(struct acpi_dp * dsd,const struct soundwire_controller * prop,soundwire_link_prop_cb link_prop_cb)318 void soundwire_gen_controller(struct acpi_dp *dsd, const struct soundwire_controller *prop,
319 			      soundwire_link_prop_cb link_prop_cb)
320 {
321 	size_t i;
322 
323 	soundwire_gen_interface_revision(dsd);
324 	SDW_INT("master-count", prop->master_list_count);
325 
326 	/* Generate properties for each master link on the controller. */
327 	for (i = 0; i < prop->master_list_count && i < SOUNDWIRE_MAX_LINK; i++) {
328 		struct acpi_dp *link = acpi_dp_new_table(link_names[i].acpi_name);
329 		soundwire_gen_link(link, &prop->master_list[i]);
330 
331 		/* Callback for custom link properties from the controller. */
332 		if (link_prop_cb)
333 			link_prop_cb(link, i, prop);
334 		acpi_dp_add_child(dsd, link_names[i].sdw_name, link);
335 	}
336 }
337 
soundwire_gen_codec(struct acpi_dp * dsd,const struct soundwire_codec * codec,soundwire_dp_prop_cb dp_prop_cb)338 void soundwire_gen_codec(struct acpi_dp *dsd, const struct soundwire_codec *codec,
339 			 soundwire_dp_prop_cb dp_prop_cb)
340 {
341 	const struct soundwire_dpn_entry *entry;
342 	const struct soundwire_name_map *name;
343 	size_t i;
344 
345 	/* Generate slave properties for this codec. */
346 	soundwire_gen_slave(dsd, codec->slave);
347 
348 	/* Generate properties for multilane config, if provided. */
349 	if (codec->multilane)
350 		soundwire_gen_multilane(dsd, codec->multilane);
351 
352 	/* Generate properties for data port 0, if provided. */
353 	if (codec->dp0) {
354 		struct acpi_dp *dp0;
355 
356 		/* First generate any Bulk Register Access mode properties. */
357 		for (i = 0; i < SOUNDWIRE_MAX_MODE; i++) {
358 			const struct soundwire_bra_mode *prop = codec->dp0_bra_mode[i];
359 			struct acpi_dp *bra;
360 
361 			/* Stop processing at the first undefined BRA mode. */
362 			if (!prop)
363 				break;
364 			name = &bra_mode_names[i];
365 			bra = acpi_dp_new_table(name->acpi_name);
366 			soundwire_gen_bra_mode(bra, prop);
367 			acpi_dp_add_child(dsd, name->sdw_name, bra);
368 		}
369 
370 		name = &dpn_source_names[0];
371 		dp0 = acpi_dp_new_table(name->acpi_name);
372 		soundwire_gen_dp0(dp0, codec->dp0);
373 
374 		/* Callback for custom properties from the codec. */
375 		if (dp_prop_cb)
376 			dp_prop_cb(dp0, 0, codec);
377 		acpi_dp_add_child(dsd, name->sdw_name, dp0);
378 	}
379 
380 	/*
381 	 * First generate audio modes for the data ports.  This results in unnecessary
382 	 * (but harmless) references to the audio modes at the codec level, but it allows
383 	 * the data ports to use these objects without duplication.
384 	 */
385 	for (i = 0; i < SOUNDWIRE_MAX_MODE; i++) {
386 		const struct soundwire_audio_mode *prop = codec->audio_mode[i];
387 		struct acpi_dp *am;
388 
389 		/* Stop processing at the first undefined audio mode. */
390 		if (!prop)
391 			break;
392 		name = &audio_mode_names[i];
393 		am = acpi_dp_new_table(name->acpi_name);
394 		soundwire_gen_audio_mode(am, prop);
395 		acpi_dp_add_child(dsd, name->sdw_name, am);
396 	}
397 
398 	/* Now generate properties for source/slave on each defined data port. */
399 	for (entry = codec->dpn; entry; entry++) {
400 		struct acpi_dp *dpn;
401 
402 		/* Stop processing at the first invalid data port. */
403 		if (entry->port < SOUNDWIRE_MIN_DPN || entry->port >= SOUNDWIRE_MAX_DPN)
404 			break;
405 
406 		if (entry->source) {
407 			name = &dpn_source_names[entry->port];
408 			dpn = acpi_dp_new_table(name->acpi_name);
409 			soundwire_gen_dpn(dpn, entry->source);
410 
411 			/* Callback for custom properties from the codec. */
412 			if (dp_prop_cb)
413 				dp_prop_cb(dpn, entry->port, codec);
414 			acpi_dp_add_child(dsd, name->sdw_name, dpn);
415 		}
416 		if (entry->sink) {
417 			name = &dpn_sink_names[entry->port];
418 			dpn = acpi_dp_new_table(name->acpi_name);
419 			soundwire_gen_dpn(dpn, entry->sink);
420 
421 			/* Callback for custom properties from the codec. */
422 			if (dp_prop_cb)
423 				dp_prop_cb(dpn, entry->port, codec);
424 			acpi_dp_add_child(dsd, name->sdw_name, dpn);
425 		}
426 	}
427 }
428