1 /* SPDX-License-Identifier: GPL-2.0-only */
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>
10 /* Specification-defined prefix for SoundWire properties. */
11 #define SDW_PFX "mipi-sdw-"
13 /* Generate SoundWire property for integer. */
14 #define SDW_INT(__key, __val) \
15 acpi_dp_add_integer(dsd, SDW_PFX __key, __val)
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)
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.
26 struct soundwire_name_map
{
27 const char *acpi_name
;
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" },
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" },
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" }
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" }
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" }
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"
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"
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"
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"
134 static void soundwire_gen_interface_revision(struct acpi_dp
*dsd
)
136 acpi_dp_add_integer(dsd
, SDW_PFX
"sw-interface-revision", SOUNDWIRE_SW_VERSION_1_0
);
139 static void soundwire_gen_slave(struct acpi_dp
*dsd
, const struct soundwire_slave
*prop
)
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
);
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
);
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
);
164 static void soundwire_gen_multilane(struct acpi_dp
*dsd
, const struct soundwire_multilane
*prop
)
168 soundwire_gen_interface_revision(dsd
);
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
];
175 /* Get the name of this connection */
176 if (map
->direction
== MASTER_LANE
)
177 name
= multilane_master_lane_names
[map
->connection
.master_lane
];
179 name
= multilane_slave_link_names
[map
->connection
.slave_link
];
181 acpi_dp_add_string(dsd
, multilane_names
[map
->lane
], name
);
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
]);
190 static void soundwire_gen_link(struct acpi_dp
*dsd
, const struct soundwire_link
*prop
)
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
);
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
);
206 static void soundwire_gen_bra_mode(struct acpi_dp
*dsd
, const struct soundwire_bra_mode
*prop
)
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
);
213 SDW_INT("bra-mode-min-bus-frequency", prop
->min_bus_frequency
);
214 SDW_INT("bra-mode-max-bus-frequency", prop
->max_bus_frequency
);
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
);
220 static void soundwire_gen_audio_mode(struct acpi_dp
*dsd
,
221 const struct soundwire_audio_mode
*prop
)
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
);
228 SDW_INT("audio-mode-min-bus-frequency", prop
->min_bus_frequency
);
229 SDW_INT("audio-mode-max-bus-frequency", prop
->max_bus_frequency
);
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
);
238 SDW_INT("audio-mode-max-sampling-frequency", prop
->max_sampling_frequency
);
239 SDW_INT("audio-mode-min-sampling-frequency", prop
->min_sampling_frequency
);
242 SDW_INT("audio-mode-prepare-channel-behavior", prop
->prepare_channel_behavior
);
243 SDW_INT("audio-mode-glitchless-transitions", prop
->glitchless_transitions
);
246 static void soundwire_gen_dp0(struct acpi_dp
*dsd
, const struct soundwire_dp0
*prop
)
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
);
255 SDW_INT("port-max-wordlength", prop
->port_max_wordlength
);
256 SDW_INT("port-min-wordlength", prop
->port_min_wordlength
);
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
);
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
);
272 static void soundwire_gen_dpn(struct acpi_dp
*dsd
, const struct soundwire_dpn
*prop
)
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
);
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
);
289 SDW_INT("port-max-wordlength", prop
->port_max_wordlength
);
290 SDW_INT("port-min-wordlength", prop
->port_min_wordlength
);
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
);
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
);
303 SDW_INT("min-channel-number", prop
->min_channel_number
);
304 SDW_INT("max-channel-number", prop
->max_channel_number
);
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
);
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
);
318 void soundwire_gen_controller(struct acpi_dp
*dsd
, const struct soundwire_controller
*prop
,
319 soundwire_link_prop_cb link_prop_cb
)
323 soundwire_gen_interface_revision(dsd
);
324 SDW_INT("master-count", prop
->master_list_count
);
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
]);
331 /* Callback for custom link properties from the controller. */
333 link_prop_cb(link
, i
, prop
);
334 acpi_dp_add_child(dsd
, link_names
[i
].sdw_name
, link
);
338 void soundwire_gen_codec(struct acpi_dp
*dsd
, const struct soundwire_codec
*codec
,
339 soundwire_dp_prop_cb dp_prop_cb
)
341 const struct soundwire_dpn_entry
*entry
;
342 const struct soundwire_name_map
*name
;
345 /* Generate slave properties for this codec. */
346 soundwire_gen_slave(dsd
, codec
->slave
);
348 /* Generate properties for multilane config, if provided. */
349 if (codec
->multilane
)
350 soundwire_gen_multilane(dsd
, codec
->multilane
);
352 /* Generate properties for data port 0, if provided. */
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
];
361 /* Stop processing at the first undefined BRA mode. */
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
);
370 name
= &dpn_source_names
[0];
371 dp0
= acpi_dp_new_table(name
->acpi_name
);
372 soundwire_gen_dp0(dp0
, codec
->dp0
);
374 /* Callback for custom properties from the codec. */
376 dp_prop_cb(dp0
, 0, codec
);
377 acpi_dp_add_child(dsd
, name
->sdw_name
, dp0
);
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.
385 for (i
= 0; i
< SOUNDWIRE_MAX_MODE
; i
++) {
386 const struct soundwire_audio_mode
*prop
= codec
->audio_mode
[i
];
389 /* Stop processing at the first undefined audio mode. */
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
);
398 /* Now generate properties for source/slave on each defined data port. */
399 for (entry
= codec
->dpn
; entry
; entry
++) {
402 /* Stop processing at the first invalid data port. */
403 if (entry
->port
< SOUNDWIRE_MIN_DPN
|| entry
->port
>= SOUNDWIRE_MAX_DPN
)
407 name
= &dpn_source_names
[entry
->port
];
408 dpn
= acpi_dp_new_table(name
->acpi_name
);
409 soundwire_gen_dpn(dpn
, entry
->source
);
411 /* Callback for custom properties from the codec. */
413 dp_prop_cb(dpn
, entry
->port
, codec
);
414 acpi_dp_add_child(dsd
, name
->sdw_name
, dpn
);
417 name
= &dpn_sink_names
[entry
->port
];
418 dpn
= acpi_dp_new_table(name
->acpi_name
);
419 soundwire_gen_dpn(dpn
, entry
->sink
);
421 /* Callback for custom properties from the codec. */
423 dp_prop_cb(dpn
, entry
->port
, codec
);
424 acpi_dp_add_child(dsd
, name
->sdw_name
, dpn
);