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