diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 405c24faa75b..47102f442a4f 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -103,6 +103,19 @@ struct afe_ctl { void *rx_private_data; uint32_t mmap_handle; + void (*pri_spdif_tx_cb)(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv); + void (*sec_spdif_tx_cb)(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv); + void *pri_spdif_tx_private_data; + void *sec_spdif_tx_private_data; + struct afe_port_mod_evt_rsp_hdr pri_spdif_evt_pl; + struct afe_event_fmt_update pri_spdif_fmt_event; + struct afe_port_mod_evt_rsp_hdr sec_spdif_evt_pl; + struct afe_event_fmt_update sec_spdif_fmt_event; + struct work_struct afe_pri_spdif_work; + struct work_struct afe_sec_spdif_work; + int topology[AFE_MAX_PORTS]; struct cal_type_data *cal_data[MAX_AFE_CAL_TYPES]; @@ -353,6 +366,128 @@ static void afe_notify_dc_presence_work_fn(struct work_struct *work) __func__, event, ret); } + +static const char *const afe_event_port_text[] = { + "PORT=Primary", + "PORT=Secondary", +}; + +static const char * const afe_event_state_text[] = { + "STATE=Inactive", + "STATE=Active", + "STATE=EOS", +}; + +static const char *const afe_event_rate_text[] = { + "RATE=32000", + "RATE=44100", + "RATE=48000", + "RATE=88200", + "RATE=96000", + "RATE=176400", + "RATE=192000", +}; + +static const char *const afe_event_format_text[] = { + "FORMAT=LPCM", + "FORMAT=Compr", +}; + +static void afe_notify_spdif_fmt_update_common(void *payload) +{ + int ret = 0; + char *env[6]; + struct afe_port_mod_evt_rsp_hdr *evt_pl; + struct afe_event_fmt_update *fmt_event; + + evt_pl = (struct afe_port_mod_evt_rsp_hdr *)payload; + fmt_event = (struct afe_event_fmt_update *) + (payload + sizeof(struct afe_port_mod_evt_rsp_hdr)); + + env[0] = "SPDIF_FMT_UPDATE=TRUE"; + if (evt_pl->port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) + env[1] = (char *)afe_event_port_text[0]; + else + env[1] = (char *)afe_event_port_text[1]; + + switch (fmt_event->status) { + case AFE_PORT_STATUS_AUDIO_ACTIVE: + env[2] = (char *)afe_event_state_text[1]; + break; + case AFE_PORT_STATUS_AUDIO_EOS: + env[2] = (char *)afe_event_state_text[2]; + break; + default: + env[2] = (char *)afe_event_state_text[0]; + } + + switch (fmt_event->sample_rate) { + case 32000: + env[3] = (char *)afe_event_rate_text[0]; + break; + case 44100: + env[3] = (char *)afe_event_rate_text[1]; + break; + case 48000: + env[3] = (char *)afe_event_rate_text[2]; + break; + case 88200: + env[3] = (char *)afe_event_rate_text[3]; + break; + case 96000: + env[3] = (char *)afe_event_rate_text[4]; + break; + case 176400: + env[3] = (char *)afe_event_rate_text[5]; + break; + case 192000: + env[3] = (char *)afe_event_rate_text[6]; + break; + default: + env[3] = (char *)afe_event_rate_text[2]; + } + + if (fmt_event->data_format == AFE_NON_LINEAR_DATA) + env[4] = (char *)afe_event_format_text[1]; + else + env[4] = (char *)afe_event_format_text[0]; + + env[5] = NULL; + + ret = q6core_send_uevent_env(this_afe.uevent_data, env); + if (ret) + pr_err("%s: Send UEvent %s failed: %d\n", __func__, + env[0], ret); +} + +static void afe_notify_pri_spdif_fmt_update_work_fn(struct work_struct *work) +{ + afe_notify_spdif_fmt_update_common(&this_afe.pri_spdif_evt_pl); +} + +static void afe_notify_sec_spdif_fmt_update_work_fn(struct work_struct *work) +{ + afe_notify_spdif_fmt_update_common(&this_afe.sec_spdif_evt_pl); +} + +static void afe_notify_spdif_fmt_update(void *payload) +{ + struct afe_port_mod_evt_rsp_hdr *evt_pl; + + evt_pl = (struct afe_port_mod_evt_rsp_hdr *)payload; + if (evt_pl->port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) { + memcpy(&this_afe.pri_spdif_evt_pl, payload, + sizeof(struct afe_port_mod_evt_rsp_hdr) + + sizeof(struct afe_event_fmt_update)); + schedule_work(&this_afe.afe_pri_spdif_work); + } else { + memcpy(&this_afe.sec_spdif_evt_pl, payload, + sizeof(struct afe_port_mod_evt_rsp_hdr) + + sizeof(struct afe_event_fmt_update)); + schedule_work(&this_afe.afe_sec_spdif_work); + } +} + static int32_t afe_callback(struct apr_client_data *data, void *priv) { if (!data) { @@ -549,6 +684,20 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) flag_dc_presence[1] == 1) { afe_notify_dc_presence(); } + } else if (evt_pl->port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) { + if (this_afe.pri_spdif_tx_cb) { + this_afe.pri_spdif_tx_cb(data->opcode, + data->token, data->payload, + this_afe.pri_spdif_tx_private_data); + } + afe_notify_spdif_fmt_update(data->payload); + } else if (evt_pl->port_id == AFE_PORT_ID_SECONDARY_SPDIF_TX) { + if (this_afe.sec_spdif_tx_cb) { + this_afe.sec_spdif_tx_cb(data->opcode, + data->token, data->payload, + this_afe.sec_spdif_tx_private_data); + } + afe_notify_spdif_fmt_update(data->payload); } else { pr_debug("%s: mod ID = 0x%x event_id = 0x%x\n", __func__, evt_pl->module_id, @@ -639,6 +788,13 @@ int afe_sizeof_cfg_cmd(u16 port_id) ret_size = SIZEOF_CFG_CMD(afe_param_id_hdmi_multi_chan_audio_cfg); break; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + ret_size = + SIZEOF_CFG_CMD(afe_param_id_spdif_cfg_v2); + break; case SLIMBUS_0_RX: case SLIMBUS_0_TX: case SLIMBUS_1_RX: @@ -2793,7 +2949,7 @@ int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port, param_hdr, (u8 *) spdif_port); if (ret) { pr_err("%s: AFE enable for port 0x%x failed ret = %d\n", - __func__, port_id, ret); + __func__, port_id, ret); goto fail_cmd; } @@ -2806,10 +2962,13 @@ int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port, goto fail_cmd; } - ret = afe_send_spdif_ch_status_cfg(&spdif_port->ch_status, port_id); - if (ret < 0) { - pr_err("%s: afe send failed %d\n", __func__, ret); - goto fail_cmd; + if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) { + ret = afe_send_spdif_ch_status_cfg(&spdif_port->ch_status, + port_id); + if (ret < 0) { + pr_err("%s: afe send failed %d\n", __func__, ret); + goto fail_cmd; + } } return afe_send_cmd_port_start(port_id); @@ -2819,6 +2978,105 @@ fail_cmd: } EXPORT_SYMBOL(afe_spdif_port_start); +/** + * afe_spdif_reg_event_cfg - + * register for event from AFE spdif port + * + * @port_id: Port ID to register event + * @reg_flag: register or unregister + * @cb: callback function to invoke for events from module + * @private_data: private data to sent back in callback fn + * + * Returns 0 on success or error on failure + */ +int afe_spdif_reg_event_cfg(u16 port_id, u16 reg_flag, + void (*cb)(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv), + void *private_data) +{ + struct afe_port_cmd_event_cfg *config; + struct afe_port_cmd_mod_evt_cfg_payload pl; + int index; + int ret; + int num_events = 1; + int cmd_size = sizeof(struct afe_port_cmd_event_cfg) + + (num_events * sizeof(struct afe_port_cmd_mod_evt_cfg_payload)); + + config = kzalloc(cmd_size, GFP_KERNEL); + if (!config) + return -ENOMEM; + + if (port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) { + this_afe.pri_spdif_tx_cb = cb; + this_afe.pri_spdif_tx_private_data = private_data; + } else if (port_id == AFE_PORT_ID_SECONDARY_SPDIF_TX) { + this_afe.sec_spdif_tx_cb = cb; + this_afe.sec_spdif_tx_private_data = private_data; + } else { + pr_err("%s: wrong port id 0x%x\n", __func__, port_id); + ret = -EINVAL; + goto fail_idx; + } + + index = q6audio_get_port_index(port_id); + if (index < 0) { + pr_err("%s: Invalid index number: %d\n", __func__, index); + ret = -EINVAL; + goto fail_idx; + } + + memset(&pl, 0, sizeof(pl)); + pl.module_id = AFE_MODULE_CUSTOM_EVENTS; + pl.event_id = AFE_PORT_FMT_UPDATE_EVENT; + pl.reg_flag = reg_flag; + + config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + config->hdr.pkt_size = cmd_size; + config->hdr.src_port = 1; + config->hdr.dest_port = 1; + config->hdr.token = index; + + config->hdr.opcode = AFE_PORT_CMD_MOD_EVENT_CFG; + config->port_id = q6audio_get_port_id(port_id); + config->num_events = num_events; + config->version = 1; + memcpy(config->payload, &pl, sizeof(pl)); + atomic_set(&this_afe.state, 1); + atomic_set(&this_afe.status, 0); + ret = apr_send_pkt(this_afe.apr, (uint32_t *) config); + if (ret < 0) { + pr_err("%s: port = 0x%x failed %d\n", + __func__, port_id, ret); + goto fail_cmd; + } + ret = wait_event_timeout(this_afe.wait[index], + (atomic_read(&this_afe.state) == 0), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: wait_event timeout\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + if (atomic_read(&this_afe.status) > 0) { + pr_err("%s: config cmd failed [%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&this_afe.status))); + ret = adsp_err_get_lnx_err_code( + atomic_read(&this_afe.status)); + goto fail_idx; + } + ret = 0; +fail_cmd: + pr_debug("%s: config.opcode 0x%x status %d\n", + __func__, config->hdr.opcode, ret); + +fail_idx: + kfree(config); + return ret; +} +EXPORT_SYMBOL(afe_spdif_reg_event_cfg); + int afe_send_slot_mapping_cfg( struct afe_param_id_slot_mapping_cfg *slot_mapping_cfg, u16 port_id) @@ -3880,7 +4138,10 @@ int afe_get_port_index(u16 port_id) case MI2S_TX: return IDX_MI2S_TX; case HDMI_RX: return IDX_HDMI_RX; case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX; - case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: return IDX_PRIMARY_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: return IDX_PRIMARY_SPDIF_TX; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: return IDX_SECONDARY_SPDIF_RX; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: return IDX_SECONDARY_SPDIF_TX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; case DIGI_MIC_TX: return IDX_DIGI_MIC_TX; @@ -4259,6 +4520,12 @@ int afe_open(u16 port_id, case DISPLAY_PORT_RX: cfg_type = AFE_PARAM_ID_HDMI_CONFIG; break; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + cfg_type = AFE_PARAM_ID_SPDIF_CONFIG; + break; case SLIMBUS_0_RX: case SLIMBUS_0_TX: case SLIMBUS_1_RX: @@ -6100,7 +6367,10 @@ int afe_validate_port(u16 port_id) case MI2S_TX: case HDMI_RX: case DISPLAY_PORT_RX: - case AFE_PORT_ID_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: case RSVD_2: case RSVD_3: case DIGI_MIC_TX: @@ -7695,6 +7965,10 @@ int __init afe_init(void) q6core_init_uevent_data(this_afe.uevent_data, "q6afe_uevent"); INIT_WORK(&this_afe.afe_dc_work, afe_notify_dc_presence_work_fn); + INIT_WORK(&this_afe.afe_pri_spdif_work, + afe_notify_pri_spdif_fmt_update_work_fn); + INIT_WORK(&this_afe.afe_sec_spdif_work, + afe_notify_sec_spdif_fmt_update_work_fn); return 0; } diff --git a/dsp/q6asm.c b/dsp/q6asm.c index 8deb64a723ab..059fa83567c3 100644 --- a/dsp/q6asm.c +++ b/dsp/q6asm.c @@ -1953,6 +1953,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE: case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE: case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS: + case ASM_STREAM_CMD_OPEN_READ_COMPRESSED: case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED: pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n", __func__, ac->session, @@ -2166,7 +2167,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (ac->io_mode & SYNC_IO_MODE) { if (port->buf == NULL) { - pr_err("%s: Unexpected Write Done\n", __func__); + pr_err("%s: Unexpected Read Done\n", __func__); spin_unlock_irqrestore( &(session[session_id].session_lock), flags); @@ -2833,6 +2834,85 @@ int q6asm_set_soft_volume_module_instance_ids(int instance, } EXPORT_SYMBOL(q6asm_set_soft_volume_module_instance_ids); +/** + * q6asm_open_read_compressed - + * command to open ASM in compressed read mode + * + * @ac: Audio client handle + * @format: capture format for ASM + * @passthrough_flag: flag to indicate passthrough option + * + * Returns 0 on success or error on failure + */ +int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format, + uint32_t passthrough_flag) +{ + int rc = 0; + struct asm_stream_cmd_open_read_compressed open; + + if (ac == NULL) { + pr_err("%s: ac[%pK] NULL\n", __func__, ac); + rc = -EINVAL; + goto fail_cmd; + } + + if (ac->apr == NULL) { + pr_err("%s: APR handle[%pK] NULL\n", __func__, ac->apr); + rc = -EINVAL; + goto fail_cmd; + } + pr_debug("%s: session[%d] wr_format[0x%x]\n", __func__, ac->session, + format); + + q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE); + open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_COMPRESSED; + atomic_set(&ac->cmd_state, -1); + + /* + * Below flag indicates whether DSP shall keep IEC61937 packing or + * unpack to raw compressed format + */ + if (format == FORMAT_IEC61937) { + open.mode_flags = 0x1; + pr_debug("%s: Flag 1 IEC61937 output\n", __func__); + } else { + open.mode_flags = 0; + open.frames_per_buf = 1; + pr_debug("%s: Flag 0 RAW_COMPR output\n", __func__); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &open); + if (rc < 0) { + pr_err("%s: open failed op[0x%x]rc[%d]\n", + __func__, open.hdr.opcode, rc); + rc = -EINVAL; + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 1*HZ); + if (!rc) { + pr_err("%s: timeout. waited for OPEN_READ_COMPR rc[%d]\n", + __func__, rc); + rc = -ETIMEDOUT; + goto fail_cmd; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + + return 0; + +fail_cmd: + return rc; +} +EXPORT_SYMBOL(q6asm_open_read_compressed); + static int __q6asm_open_read(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, uint32_t pcm_format_block_ver, diff --git a/dsp/q6audio-v2.c b/dsp/q6audio-v2.c index a49632700c85..b48c9b69cf55 100644 --- a/dsp/q6audio-v2.c +++ b/dsp/q6audio-v2.c @@ -50,7 +50,10 @@ int q6audio_get_port_index(u16 port_id) case MI2S_TX: return IDX_MI2S_TX; case HDMI_RX: return IDX_HDMI_RX; case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX; - case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: return IDX_PRIMARY_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: return IDX_PRIMARY_SPDIF_TX; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: return IDX_SECONDARY_SPDIF_RX; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: return IDX_SECONDARY_SPDIF_TX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; case DIGI_MIC_TX: return IDX_DIGI_MIC_TX; @@ -351,7 +354,14 @@ int q6audio_get_port_id(u16 port_id) case HDMI_RX: return AFE_PORT_ID_MULTICHAN_HDMI_RX; case DISPLAY_PORT_RX: return AFE_PORT_ID_HDMI_OVER_DP_RX; - case AFE_PORT_ID_SPDIF_RX: return AFE_PORT_ID_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + return AFE_PORT_ID_PRIMARY_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + return AFE_PORT_ID_PRIMARY_SPDIF_TX; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + return AFE_PORT_ID_SECONDARY_SPDIF_RX; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + return AFE_PORT_ID_SECONDARY_SPDIF_TX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; case DIGI_MIC_TX: return AFE_PORT_ID_DIGITAL_MIC_TX; @@ -777,6 +787,10 @@ int q6audio_is_digital_pcm_interface(u16 port_id) case AFE_PORT_ID_WSA_CODEC_DMA_TX_2: case AFE_PORT_ID_VA_CODEC_DMA_TX_0: case AFE_PORT_ID_VA_CODEC_DMA_TX_1: + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: break; default: ret = -EINVAL; @@ -854,7 +868,10 @@ int q6audio_validate_port(u16 port_id) case AFE_PORT_ID_QUATERNARY_MI2S_TX: case AFE_PORT_ID_SECONDARY_MI2S_RX: case AFE_PORT_ID_SECONDARY_MI2S_TX: - case AFE_PORT_ID_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: case AFE_PORT_ID_TERTIARY_MI2S_RX: case AFE_PORT_ID_TERTIARY_MI2S_TX: case AFE_PORT_ID_QUINARY_MI2S_RX: diff --git a/dsp/q6core.c b/dsp/q6core.c index 51b8ef0c4e9d..34f0dd091189 100644 --- a/dsp/q6core.c +++ b/dsp/q6core.c @@ -189,6 +189,23 @@ int q6core_send_uevent(struct audio_uevent_data *uevent_data, char *event) } EXPORT_SYMBOL(q6core_send_uevent); +/** + * q6core_send_uevent_env - send uevent with list of keys to userspace. + * + * @uevent_data: uevent data. + * @event: array of event keys to send. + * + * Returns 0 on success or error otherwise. + */ +int q6core_send_uevent_env(struct audio_uevent_data *uevent_data, char *env[]) +{ + if (!env || !uevent_data) + return -EINVAL; + + return kobject_uevent_env(&uevent_data->kobj, KOBJ_CHANGE, env); +} +EXPORT_SYMBOL(q6core_send_uevent_env); + static int parse_fwk_version_info(uint32_t *payload) { size_t ver_size; diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 337f66f27b25..b9ae3f55843e 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -1236,7 +1236,11 @@ struct adm_cmd_connect_afe_port_v5 { #define AFE_PORT_ID_QUINARY_PCM_RX 0x103C #define AFE_PORT_ID_QUINARY_PCM_TX 0x103D -#define AFE_PORT_ID_SPDIF_RX 0x5000 +#define AFE_PORT_ID_PRIMARY_SPDIF_RX 0x5000 +#define AFE_PORT_ID_PRIMARY_SPDIF_TX 0x5001 +#define AFE_PORT_ID_SECONDARY_SPDIF_RX 0x5002 +#define AFE_PORT_ID_SECONDARY_SPDIF_TX 0x5003 + #define AFE_PORT_ID_RT_PROXY_PORT_001_RX 0x2000 #define AFE_PORT_ID_RT_PROXY_PORT_001_TX 0x2001 #define AFE_PORT_ID_INTERNAL_BT_SCO_RX 0x3000 @@ -2270,6 +2274,7 @@ struct afe_param_id_i2s_cfg { * This param id is used to configure PCM interface */ +#define AFE_API_VERSION_SPDIF_CONFIG_V2 0x2 #define AFE_API_VERSION_SPDIF_CONFIG 0x1 #define AFE_API_VERSION_SPDIF_CH_STATUS_CONFIG 0x1 #define AFE_API_VERSION_SPDIF_CLK_CONFIG 0x1 @@ -2283,10 +2288,20 @@ struct afe_param_id_i2s_cfg { #define AFE_PORT_CLK_ROOT_LPAPLL 0x3 #define AFE_PORT_CLK_ROOT_LPAQ6PLL 0x4 -struct afe_param_id_spdif_cfg { +#define AFE_MODULE_CUSTOM_EVENTS 0x00010251 + +#define AFE_PORT_FMT_UPDATE_EVENT 0x0001010E + +#define AFE_API_VERSION_EVENT_FMT_UPDATE 0x1 +#define AFE_PORT_STATUS_NO_SIGNAL 0 +#define AFE_PORT_STATUS_AUDIO_ACTIVE 1 +#define AFE_PORT_STATUS_AUDIO_EOS 2 + +struct afe_param_id_spdif_cfg_v2 { /* Minor version used for tracking the version of the SPDIF * configuration interface. - * Supported values: #AFE_API_VERSION_SPDIF_CONFIG + * Supported values: #AFE_API_VERSION_SPDIF_CONFIG, + * #AFE_API_VERSION_SPDIF_CONFIG_V2 */ u32 spdif_cfg_minor_version; @@ -2318,6 +2333,8 @@ struct afe_param_id_spdif_cfg { u16 bit_width; /* This field must be set to zero. */ u16 reserved; +/* Input select for spdif input, must be set to 0 for spdif output. */ + u32 src_sel; } __packed; struct afe_param_id_spdif_ch_status_cfg { @@ -2344,6 +2361,7 @@ struct afe_param_id_spdif_ch_status_cfg { */ } __packed; +/* deprecated */ struct afe_param_id_spdif_clk_cfg { u32 clk_cfg_minor_version; /* Minor version used for tracking the version of SPDIF @@ -2367,8 +2385,43 @@ struct afe_param_id_spdif_clk_cfg { */ } __packed; +struct afe_event_fmt_update { + /* Tracks the configuration of this event. */ + u32 minor_version; + + /* Detected port status. + * Supported values: + * - #AFE_PORT_STATUS_NO_SIGNAL + * - #AFE_PORT_STATUS_AUDIO_ACTIVE + * - #AFE_PORT_STATUS_AUDIO_EOS + */ + u32 status; + + /* Sampling rate of the port. + * Supported values: + * - #AFE_PORT_SAMPLE_RATE_32K + * - #AFE_PORT_SAMPLE_RATE_44_1K + * - #AFE_PORT_SAMPLE_RATE_48K + * - #AFE_PORT_SAMPLE_RATE_88_2K + * - #AFE_PORT_SAMPLE_RATE_96K + * - #AFE_PORT_SAMPLE_RATE_176_4K + * - #AFE_PORT_SAMPLE_RATE_192K + */ + u32 sample_rate; + + /* Data format of the port. + * Supported values: + * - #AFE_LINEAR_PCM_DATA + * - #AFE_NON_LINEAR_DATA + */ + u16 data_format; + + /* First 6 bytes of channel status bits */ + u8 channel_status[6]; +} __packed; + struct afe_spdif_port_config { - struct afe_param_id_spdif_cfg cfg; + struct afe_param_id_spdif_cfg_v2 cfg; struct afe_param_id_spdif_ch_status_cfg ch_status; } __packed; @@ -4093,7 +4146,7 @@ union afe_port_config { struct afe_param_id_internal_bt_fm_cfg int_bt_fm; struct afe_param_id_pseudo_port_cfg pseudo_port; struct afe_param_id_device_hw_delay_cfg hw_delay; - struct afe_param_id_spdif_cfg spdif; + struct afe_param_id_spdif_cfg_v2 spdif; struct afe_param_id_set_topology_cfg topology; struct afe_param_id_tdm_cfg tdm; struct afe_param_id_usb_audio_cfg usb_audio; @@ -4793,7 +4846,7 @@ struct asm_generic_compressed_fmt_blk_t { /* Command to send sample rate & channels for IEC61937 (compressed) or IEC60958 * (pcm) streams. Both audio standards use the same format and are used for - * HDMI or SPDIF. + * HDMI or SPDIF output. */ #define ASM_DATA_CMD_IEC_60958_MEDIA_FMT 0x0001321E @@ -7669,11 +7722,23 @@ struct asm_data_cmd_remove_silence { #define ASM_STREAM_CMD_OPEN_READ_COMPRESSED 0x00010D95 +/* Bitmask for the IEC 61937 to 61937 pass-through capture. */ +#define ASM_BIT_MASK_IEC_61937_PASS_THROUGH_FLAG (0x00000001UL) + +/* Shift value for the IEC 61937 to 61937 pass-through capture. */ +#define ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG 0 + struct asm_stream_cmd_open_read_compressed { struct apr_hdr hdr; u32 mode_flags; /* Mode flags that indicate whether meta information per encoded - * frame is to be provided. + * frame is to be provided and packaging. + * Supported values for bit 0: (IEC 61937 pass-through mode) + * - 0 -- Unpack the IEC 61937 format stream to RAW compressed format + * - 1 -- Pass-through transfer of the IEC 61937 format stream + * - Use #ASM_BIT_MASK_IEC_61937_PASS_THROUGH_FLAG to set the bitmask + * and #ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG to set the shift value + * for this bit. * Supported values for bit 4: * - 0 -- Return data buffer contains all encoded frames only; it does * not contain frame metadata. @@ -7687,7 +7752,9 @@ struct asm_stream_cmd_open_read_compressed { u32 frames_per_buf; /* Indicates the number of frames that need to be returned per * read buffer - * Supported values: should be greater than 0 + * Supported values: should be greater than 0 for IEC to RAW compressed + * unpack mode. + * Value is don't care for IEC 61937 pass-through mode. */ } __packed; @@ -10321,8 +10388,18 @@ enum afe_lpass_clk_mode { /* Clock ID for AHB HDMI input */ #define Q6AFE_LPASS_CLK_ID_AHB_HDMI_INPUT 0x400 -/* Clock ID for SPDIF core */ -#define Q6AFE_LPASS_CLK_ID_SPDIF_CORE 0x500 +/* Clock ID for the primary SPDIF output core. */ +#define AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_CORE 0x500 +/* Clock ID for the secondary SPDIF output core. */ +#define AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_CORE 0x501 +/* Clock ID for the primary SPDIF input core. */ +#define AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_INPUT_CORE 0x502 +/* Clock ID for the secondary SPDIF input core. */ +#define AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_INPUT_CORE 0x503 +/* Clock ID for the secondary SPDIF output NPL clk. */ +#define AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_NPL 0x504 +/* Clock ID for the primary SPDIF output NPL clk. */ +#define AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_NPL 0x505 /* Clock attribute for invalid use (reserved for internal usage) */ diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h index e39d0b89d578..930682836f32 100644 --- a/include/dsp/q6afe-v2.h +++ b/include/dsp/q6afe-v2.h @@ -107,7 +107,7 @@ enum { /* IDX 45->49 */ IDX_SLIMBUS_6_RX, IDX_SLIMBUS_6_TX, - IDX_SPDIF_RX, + IDX_PRIMARY_SPDIF_RX, IDX_GLOBAL_CFG, IDX_AUDIO_PORT_ID_I2S_RX, /* IDX 50->53 */ @@ -229,7 +229,7 @@ enum { IDX_AFE_PORT_ID_QUINARY_TDM_TX_6, IDX_AFE_PORT_ID_QUINARY_TDM_RX_7, IDX_AFE_PORT_ID_QUINARY_TDM_TX_7, - /* IDX 161 to 166 */ + /* IDX 161 to 167 */ IDX_AFE_PORT_ID_WSA_CODEC_DMA_RX_0, IDX_AFE_PORT_ID_WSA_CODEC_DMA_TX_0, IDX_AFE_PORT_ID_WSA_CODEC_DMA_RX_1, @@ -237,6 +237,10 @@ enum { IDX_AFE_PORT_ID_WSA_CODEC_DMA_TX_2, IDX_AFE_PORT_ID_VA_CODEC_DMA_TX_0, IDX_AFE_PORT_ID_VA_CODEC_DMA_TX_1, + /* IDX 168 to 170 */ + IDX_SECONDARY_SPDIF_RX, + IDX_PRIMARY_SPDIF_TX, + IDX_SECONDARY_SPDIF_TX, AFE_MAX_PORTS }; @@ -389,6 +393,11 @@ int afe_send_spdif_ch_status_cfg(struct afe_param_id_spdif_ch_status_cfg int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port, u32 rate); +int afe_spdif_reg_event_cfg(u16 port_id, u16 reg_flag, + void (*cb)(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv), + void *private_data); + int afe_turn_onoff_hw_mad(u16 mad_type, u16 mad_enable); int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type); enum afe_mad_type afe_port_get_mad_type(u16 port_id); diff --git a/include/dsp/q6asm-v2.h b/include/dsp/q6asm-v2.h index e6f021db7e88..633e16c07e70 100644 --- a/include/dsp/q6asm-v2.h +++ b/include/dsp/q6asm-v2.h @@ -323,6 +323,9 @@ int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, int32_t stream_id, bool is_gapless_mode); +int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format, + uint32_t passthrough_flag); + int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, uint32_t passthrough_flag); diff --git a/include/dsp/q6core.h b/include/dsp/q6core.h index ac364511513a..cdee048c38bf 100644 --- a/include/dsp/q6core.h +++ b/include/dsp/q6core.h @@ -35,6 +35,7 @@ struct audio_uevent_data { int q6core_init_uevent_data(struct audio_uevent_data *uevent_data, char *name); void q6core_destroy_uevent_data(struct audio_uevent_data *uevent_data); int q6core_send_uevent(struct audio_uevent_data *uevent_data, char *name); +int q6core_send_uevent_env(struct audio_uevent_data *uevent_data, char *env[]); int q6core_get_avcs_api_version_per_service(uint32_t service_id); #define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919