Skip to content

Commit b89f3e5

Browse files
committed
dai: add support for Intel UAOL DAI
This adds support for Intel USB Audio Offload Link (UAOL) DAI. Signed-off-by: Tomasz Lissowski <tomasz.lissowski@intel.com>
1 parent 1470e6c commit b89f3e5

File tree

9 files changed

+224
-3
lines changed

9 files changed

+224
-3
lines changed

src/audio/base_fw_intel.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#include <zephyr/drivers/counter.h>
2020
#endif
2121

22+
#if CONFIG_UAOL_INTEL_ADSP
23+
#include <zephyr/drivers/uaol.h>
24+
#endif
25+
2226
#include <ipc4/base_fw.h>
2327
#include <rimage/sof/user/manifest.h>
2428

@@ -27,6 +31,20 @@ struct ipc4_modules_info {
2731
struct sof_man_module modules[0];
2832
} __packed __aligned(4);
2933

34+
struct ipc4_uaol_link_capabilities {
35+
uint32_t input_streams_supported : 4;
36+
uint32_t output_streams_supported : 4;
37+
uint32_t bidirectional_streams_supported : 5;
38+
uint32_t rsvd : 19;
39+
uint32_t max_tx_fifo_size;
40+
uint32_t max_rx_fifo_size;
41+
};
42+
43+
struct ipc4_uaol_capabilities {
44+
uint32_t link_count;
45+
struct ipc4_uaol_link_capabilities link_caps[];
46+
} __packed __aligned(4);
47+
3048
LOG_MODULE_REGISTER(basefw_intel, CONFIG_SOF_LOG_LEVEL);
3149

3250
int basefw_vendor_fw_config(uint32_t *data_offset, char *data)
@@ -36,7 +54,7 @@ int basefw_vendor_fw_config(uint32_t *data_offset, char *data)
3654
tlv_value_uint32_set(tuple, IPC4_SLOW_CLOCK_FREQ_HZ_FW_CFG, IPC4_ALH_CAVS_1_8);
3755

3856
tuple = tlv_next(tuple);
39-
tlv_value_uint32_set(tuple, IPC4_UAOL_SUPPORT, 0);
57+
tlv_value_uint32_set(tuple, IPC4_UAOL_SUPPORT, 1);
4058

4159
tuple = tlv_next(tuple);
4260
tlv_value_uint32_set(tuple, IPC4_ALH_SUPPORT_LEVEL_FW_CFG, IPC4_ALH_CAVS_1_8);
@@ -47,6 +65,41 @@ int basefw_vendor_fw_config(uint32_t *data_offset, char *data)
4765
return 0;
4866
}
4967

68+
#if CONFIG_UAOL_INTEL_ADSP
69+
70+
#define UAOL_DEV(node) DEVICE_DT_GET(node),
71+
static const struct device *uaol_devs[] = {
72+
DT_FOREACH_STATUS_OKAY(intel_adsp_uaol, UAOL_DEV)
73+
};
74+
75+
static void tlv_value_set_uaol_caps(struct sof_tlv *tuple, uint32_t type)
76+
{
77+
size_t dev_count = ARRAY_SIZE(uaol_devs);
78+
struct uaol_capabilities dev_cap;
79+
struct ipc4_uaol_capabilities *caps = (struct ipc4_uaol_capabilities *)tuple->value;
80+
size_t caps_size = offsetof(struct ipc4_uaol_capabilities, link_caps[dev_count]);
81+
size_t i;
82+
int ret;
83+
84+
memset(caps, 0, caps_size);
85+
86+
caps->link_count = dev_count;
87+
for (i = 0; i < dev_count; i++) {
88+
ret = uaol_get_capabilities(uaol_devs[i], &dev_cap);
89+
if (ret)
90+
continue;
91+
92+
caps->link_caps[i].input_streams_supported = dev_cap.input_streams;
93+
caps->link_caps[i].output_streams_supported = dev_cap.output_streams;
94+
caps->link_caps[i].bidirectional_streams_supported = dev_cap.bidirectional_streams;
95+
caps->link_caps[i].max_tx_fifo_size = dev_cap.max_tx_fifo_size;
96+
caps->link_caps[i].max_rx_fifo_size = dev_cap.max_rx_fifo_size;
97+
}
98+
99+
tlv_value_set(tuple, type, caps_size, caps);
100+
}
101+
#endif
102+
50103
int basefw_vendor_hw_config(uint32_t *data_offset, char *data)
51104
{
52105
struct sof_tlv *tuple = (struct sof_tlv *)data;
@@ -63,6 +116,11 @@ int basefw_vendor_hw_config(uint32_t *data_offset, char *data)
63116
tuple = tlv_next(tuple);
64117
tlv_value_uint32_set(tuple, IPC4_LP_EBB_COUNT_HW_CFG, PLATFORM_LPSRAM_EBB_COUNT);
65118

119+
#if CONFIG_UAOL_INTEL_ADSP
120+
tuple = tlv_next(tuple);
121+
tlv_value_set_uaol_caps(tuple, IPC4_UAOL_CAPS_HW_CFG);
122+
#endif
123+
66124
tuple = tlv_next(tuple);
67125
*data_offset = (int)((char *)tuple - data);
68126

@@ -298,6 +356,27 @@ static int basefw_set_fw_config(bool first_block,
298356
return 0;
299357
}
300358

359+
static int basefw_dma_control(bool first_block, bool last_block,
360+
uint32_t data_size, const char *data)
361+
{
362+
struct ipc4_dma_control *dma_control;
363+
int ret;
364+
365+
if (!(first_block && last_block))
366+
return IPC4_INVALID_REQUEST;
367+
368+
dma_control = (struct ipc4_dma_control *)data;
369+
370+
if (data_size < offsetof(struct ipc4_dma_control, config_data[dma_control->config_length]))
371+
return IPC4_INVALID_CONFIG_DATA_STRUCT;
372+
373+
ret = dai_control(dma_control->node_id, data);
374+
if (ret)
375+
return IPC4_INVALID_REQUEST;
376+
377+
return 0;
378+
}
379+
301380
int basefw_vendor_set_large_config(struct comp_dev *dev,
302381
uint32_t param_id,
303382
bool first_block,
@@ -308,6 +387,8 @@ int basefw_vendor_set_large_config(struct comp_dev *dev,
308387
switch (param_id) {
309388
case IPC4_FW_CONFIG:
310389
return basefw_set_fw_config(first_block, last_block, data_offset, data);
390+
case IPC4_DMA_CONTROL:
391+
return basefw_dma_control(first_block, last_block, data_offset, data);
311392
default:
312393
break;
313394
}

src/audio/copier/copier.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ static int copier_init(struct processing_module *mod)
142142
case ipc4_i2s_link_input_class:
143143
case ipc4_alh_link_output_class:
144144
case ipc4_alh_link_input_class:
145+
case ipc4_alh_uaol_stream_link_output_class:
146+
case ipc4_alh_uaol_stream_link_input_class:
145147
ret = copier_dai_create(dev, cd, copier, ipc_pipe->pipeline);
146148
if (ret < 0) {
147149
comp_err(dev, "unable to create dai");

src/audio/copier/copier_dai.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,19 @@ int copier_dai_create(struct comp_dev *dev, struct copier_data *cd,
286286
if (ret)
287287
return ret;
288288
break;
289+
case ipc4_alh_uaol_stream_link_output_class:
290+
case ipc4_alh_uaol_stream_link_input_class:
291+
dai.type = SOF_DAI_INTEL_UAOL;
292+
dai.is_config_blob = true;
293+
type = ipc4_gtw_alh;
294+
ret = ipc4_find_dma_config(&dai, (uint8_t *)cd->gtw_cfg,
295+
copier->gtw_cfg.config_length * 4);
296+
if (ret != 0) {
297+
comp_err(dev, "No uaol dma_config found in blob!");
298+
return -EINVAL;
299+
}
300+
dai.out_fmt = &copier->out_fmt;
301+
break;
289302
case ipc4_dmic_link_input_class:
290303
dai.type = SOF_DAI_INTEL_DMIC;
291304
dai.is_config_blob = true;

src/audio/dai-zephyr.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
147147
cfg.format = sof_cfg->format;
148148
cfg.options = sof_cfg->flags;
149149
cfg.rate = common_config->sampling_frequency;
150+
cfg.channels = common_config->out_fmt->channels_count;
151+
cfg.word_size = common_config->out_fmt->valid_bit_depth;
150152

151153
switch (common_config->type) {
152154
case SOF_DAI_INTEL_SSP:
@@ -177,6 +179,12 @@ int dai_set_config(struct dai *dai, struct ipc_config_dai *common_config,
177179
cfg.type = DAI_IMX_ESAI;
178180
cfg_params = &sof_cfg->esai;
179181
break;
182+
case SOF_DAI_INTEL_UAOL:
183+
cfg.type = DAI_INTEL_UAOL;
184+
cfg_params = container_of(spec_config,
185+
struct ipc4_copier_gateway_cfg, config_data);
186+
dai_set_link_hda_config(&cfg.link_config, common_config, spec_config);
187+
break;
180188
default:
181189
return -EINVAL;
182190
}

src/include/ipc/dai.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ enum sof_ipc_dai_type {
9494
SOF_DAI_AMD_SP_VIRTUAL, /**<Amd SP VIRTUAL */
9595
SOF_DAI_AMD_HS_VIRTUAL, /**<Amd HS VIRTUAL */
9696
SOF_DAI_IMX_MICFIL, /**< i.MX MICFIL */
97-
SOF_DAI_AMD_SW_AUDIO /**<Amd SW AUDIO */
97+
SOF_DAI_AMD_SW_AUDIO, /**<Amd SW AUDIO */
98+
SOF_DAI_INTEL_UAOL, /**< Intel UAOL */
9899
};
99100

100101
/* general purpose DAI configuration */

src/include/sof/lib/dai-zephyr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,11 @@ void dai_dma_position_update(struct dai_data *dd, struct comp_dev *dev);
282282
* \brief release llp slot
283283
*/
284284
void dai_release_llp_slot(struct dai_data *dd);
285+
286+
/**
287+
* \brief process ioctl request
288+
*/
289+
int dai_control(uint32_t node_id, const void *data);
285290
/** @}*/
286291

287292
#endif /* __SOF_LIB_DAI_ZEPHYR_H__ */

src/ipc/ipc4/dai.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ void dai_set_link_hda_config(uint16_t *link_config,
5959
}
6060
link_cfg.part.stream = common_config->host_dma_config[0]->stream_id;
6161
break;
62+
case SOF_DAI_INTEL_UAOL:
63+
link_cfg.full = 0;
64+
link_cfg.part.hchan = out_fmt->channels_count - 1;
65+
link_cfg.part.dir = common_config->direction;
66+
link_cfg.part.stream = common_config->host_dma_config[0]->stream_id;
67+
break;
6268
default:
6369
/* other types of DAIs not need link_config */
6470
return;
@@ -115,6 +121,15 @@ int dai_config_dma_channel(struct dai_data *dd, struct comp_dev *dev, const void
115121
*/
116122
channel = 0;
117123
break;
124+
case SOF_DAI_INTEL_UAOL:
125+
#if defined(CONFIG_ACE_VERSION_2_0) || defined(CONFIG_ACE_VERSION_3_0)
126+
channel = 0;
127+
if (dai->host_dma_config[0]->pre_allocated_by_host)
128+
channel = dai->host_dma_config[0]->dma_channel_id;
129+
#else
130+
channel = copier_cfg->gtw_cfg.node_id.f.v_index;
131+
#endif
132+
break;
118133
default:
119134
/* other types of DAIs not handled for now */
120135
comp_err(dev, "dai_config_dma_channel(): Unknown dai type %d", dai->type);
@@ -177,6 +192,16 @@ int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev)
177192
dev->ipc_config.frame_fmt, dd->stream_id);
178193

179194
break;
195+
case SOF_DAI_INTEL_UAOL:
196+
#ifdef CONFIG_ZEPHYR_NATIVE_DRIVERS
197+
dd->stream_id = dai_get_stream_id(dai_p, dai->direction);
198+
dev->ipc_config.frame_fmt = SOF_IPC_FRAME_S32_LE;
199+
dd->config.burst_elems = dai_get_fifo_depth(dd->dai, dai->direction);
200+
break;
201+
#else
202+
/* only native Zephyr driver supported */
203+
return -EINVAL;
204+
#endif
180205
default:
181206
/* other types of DAIs not handled for now */
182207
comp_warn(dev, "dai_data_config(): Unknown dai type %d", dai->type);

src/ipc/ipc4/helper.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,18 @@ int ipc4_add_comp_dev(struct comp_dev *dev)
10761076
int ipc4_find_dma_config(struct ipc_config_dai *dai, uint8_t *data_buffer, uint32_t size)
10771077
{
10781078
#if defined(CONFIG_ACE_VERSION_2_0)
1079+
if (dai->type == SOF_DAI_INTEL_UAOL) {
1080+
void *value_ptr = NULL;
1081+
uint32_t value_size;
1082+
1083+
tlv_value_get(data_buffer, size, GTW_DMA_CONFIG_ID, &value_ptr, &value_size);
1084+
if (!value_ptr)
1085+
return IPC4_INVALID_REQUEST;
1086+
1087+
dai->host_dma_config[0] = (struct ipc_dma_config *)value_ptr;
1088+
return IPC4_SUCCESS;
1089+
}
1090+
10791091
uint32_t *dma_config_id = GET_IPC_DMA_CONFIG_ID(data_buffer, size);
10801092

10811093
if (*dma_config_id != GTW_DMA_CONFIG_ID)

src/lib/dai.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ const struct device *zephyr_dev[] = {
151151
#if CONFIG_DAI_NXP_ESAI
152152
DT_FOREACH_STATUS_OKAY(nxp_dai_esai, GET_DEVICE_LIST)
153153
#endif
154+
#if CONFIG_DAI_INTEL_UAOL
155+
DT_FOREACH_STATUS_OKAY(intel_uaol_dai, GET_DEVICE_LIST)
156+
#endif
154157
};
155158

156159
static const struct device *dai_get_zephyr_device(uint32_t type, uint32_t index)
@@ -202,6 +205,15 @@ static void dai_set_device_params(struct dai *d)
202205
d->dma_dev = DMA_DEV_HDA;
203206
d->dma_caps = DMA_CAP_HDA;
204207
break;
208+
case SOF_DAI_INTEL_UAOL:
209+
#ifdef CONFIG_DMA_INTEL_ADSP_GPDMA
210+
d->dma_dev = DMA_DEV_ALH;
211+
d->dma_caps = DMA_CAP_GP_LP | DMA_CAP_GP_HP;
212+
#else
213+
d->dma_dev = DMA_DEV_HDA;
214+
d->dma_caps = DMA_CAP_HDA;
215+
#endif
216+
break;
205217
default:
206218
break;
207219
}
@@ -212,8 +224,47 @@ struct dai *dai_get(uint32_t type, uint32_t index, uint32_t flags)
212224
{
213225
const struct device *dev;
214226
struct dai *d;
227+
uint32_t z_type;
215228

216-
dev = dai_get_zephyr_device(type, index);
229+
switch (type) {
230+
case SOF_DAI_INTEL_SSP:
231+
z_type = DAI_INTEL_SSP;
232+
break;
233+
case SOF_DAI_INTEL_DMIC:
234+
z_type = DAI_INTEL_DMIC;
235+
break;
236+
case SOF_DAI_INTEL_HDA:
237+
z_type = DAI_INTEL_HDA;
238+
break;
239+
case SOF_DAI_INTEL_ALH:
240+
z_type = DAI_INTEL_ALH;
241+
break;
242+
case SOF_DAI_IMX_SAI:
243+
z_type = DAI_IMX_SAI;
244+
break;
245+
case SOF_DAI_IMX_ESAI:
246+
z_type = DAI_IMX_ESAI;
247+
break;
248+
case SOF_DAI_AMD_BT:
249+
z_type = DAI_AMD_BT;
250+
break;
251+
case SOF_DAI_AMD_SP:
252+
z_type = DAI_AMD_SP;
253+
break;
254+
case SOF_DAI_AMD_DMIC:
255+
z_type = DAI_AMD_DMIC;
256+
break;
257+
case SOF_DAI_MEDIATEK_AFE:
258+
z_type = DAI_MEDIATEK_AFE;
259+
break;
260+
case SOF_DAI_INTEL_UAOL:
261+
z_type = DAI_INTEL_UAOL;
262+
break;
263+
default:
264+
return NULL;
265+
}
266+
267+
dev = dai_get_zephyr_device(z_type, index);
217268
if (!dev) {
218269
tr_err(&dai_tr, "dai_get: failed to get dai with index %d type %d",
219270
index, type);
@@ -253,6 +304,29 @@ void dai_put(struct dai *dai)
253304

254305
rfree(dai);
255306
}
307+
308+
int dai_control(uint32_t node_id, const void *data)
309+
{
310+
union ipc4_connector_node_id node = { .dw = node_id };
311+
const struct device *dev;
312+
uint32_t z_type;
313+
int ret;
314+
315+
switch (node.f.dma_type) {
316+
case ipc4_alh_uaol_stream_link_output_class:
317+
case ipc4_alh_uaol_stream_link_input_class:
318+
z_type = DAI_INTEL_UAOL;
319+
break;
320+
default:
321+
return -EINVAL;
322+
}
323+
324+
dev = dai_get_zephyr_device(z_type, node.f.v_index);
325+
if (dev == NULL)
326+
return -ENODEV;
327+
328+
return dai_config_set(dev, NULL, data);
329+
}
256330
#else
257331
static inline const struct dai_type_info *dai_find_type(uint32_t type)
258332
{

0 commit comments

Comments
 (0)