From b84eea37684d5cd7c1dbc29fa0f47c2148d7d09b Mon Sep 17 00:00:00 2001 From: Cong Tang Date: Tue, 26 Feb 2019 15:14:28 +0800 Subject: [PATCH] audio-driver: support tdm multi lane for sa8155 Support group tdm multi lane configuration for TDM interface. With valid lane mask tdm interface support delivery audio channels through different data lines. Change-Id: I63e8ba1106b89c6bcaca0a8359a1def696c334ad Signed-off-by: Cong Tang --- asoc/msm-dai-q6-v2.c | 51 +++++++++++++++++++++++++++++---- dsp/q6afe.c | 58 ++++++++++++++++++++++++++++++++++++-- include/dsp/apr_audio-v2.h | 33 ++++++++++++++++++++++ include/dsp/q6afe-v2.h | 3 +- 4 files changed, 136 insertions(+), 9 deletions(-) diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c index 580335691b1a..336f9744aba8 100644 --- a/asoc/msm-dai-q6-v2.c +++ b/asoc/msm-dai-q6-v2.c @@ -272,6 +272,7 @@ struct msm_dai_q6_tdm_dai_data { struct afe_clk_set clk_set; /* hold LPASS clock config. */ union afe_port_group_config group_cfg; /* hold tdm group config */ struct afe_tdm_port_config port_cfg; /* hold tdm config */ + struct afe_param_id_tdm_lane_cfg lane_cfg; /* hold tdm lane config */ }; /* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command @@ -337,6 +338,11 @@ static DEFINE_MUTEX(tdm_mutex); static atomic_t tdm_group_ref[IDX_GROUP_TDM_MAX]; +static struct afe_param_id_tdm_lane_cfg tdm_lane_cfg = { + AFE_GROUP_DEVICE_ID_QUINARY_TDM_RX, + 0x0, +}; + /* cache of group cfg per parent node */ static struct afe_param_id_group_device_tdm_cfg tdm_group_cfg = { AFE_API_VERSION_GROUP_DEVICE_TDM_CONFIG, @@ -6590,6 +6596,24 @@ static int msm_dai_tdm_q6_probe(struct platform_device *pdev) } else dev_dbg(&pdev->dev, "%s: clk attribute not found\n", __func__); + /* extract tdm lane cfg to static */ + tdm_lane_cfg.port_id = tdm_group_cfg.group_id; + tdm_lane_cfg.lane_mask = AFE_LANE_MASK_INVALID; + if (of_find_property(pdev->dev.of_node, + "qcom,msm-cpudai-tdm-lane-mask", NULL)) { + rc = of_property_read_u16(pdev->dev.of_node, + "qcom,msm-cpudai-tdm-lane-mask", + &tdm_lane_cfg.lane_mask); + if (rc) { + dev_err(&pdev->dev, "%s: value for tdm lane mask not found %s\n", + __func__, "qcom,msm-cpudai-tdm-lane-mask"); + goto rtn; + } + dev_dbg(&pdev->dev, "%s: tdm lane mask from DT file %d\n", + __func__, tdm_lane_cfg.lane_mask); + } else + dev_dbg(&pdev->dev, "%s: tdm lane mask not found\n", __func__); + /* extract tdm clk src master/slave info into static */ rc = of_property_read_u32(pdev->dev.of_node, "qcom,msm-cpudai-tdm-clk-internal", @@ -7696,7 +7720,7 @@ static int msm_dai_q6_dai_tdm_remove(struct snd_soc_dai *dai) if (atomic_read(group_ref) == 0) { rc = afe_port_group_enable(group_id, - NULL, false); + NULL, false, NULL); if (rc < 0) { dev_err(dai->dev, "fail to disable AFE group 0x%x\n", group_id); @@ -8066,7 +8090,17 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream, * NOTE: group config is set to the same as slot config. */ tdm_group->bit_width = tdm_group->slot_width; - tdm_group->num_channels = tdm_group->nslots_per_frame; + + /* + * for multi lane scenario + * Total number of active channels = number of active lanes * number of active slots. + */ + if (dai_data->lane_cfg.lane_mask != AFE_LANE_MASK_INVALID) + tdm_group->num_channels = tdm_group->nslots_per_frame + * num_of_bits_set(dai_data->lane_cfg.lane_mask); + else + tdm_group->num_channels = tdm_group->nslots_per_frame; + tdm_group->sample_rate = dai_data->rate; pr_debug("%s: TDM GROUP:\n" @@ -8091,6 +8125,10 @@ static int msm_dai_q6_tdm_hw_params(struct snd_pcm_substream *substream, tdm_group->port_id[5], tdm_group->port_id[6], tdm_group->port_id[7]); + pr_debug("%s: TDM GROUP ID 0x%x lane mask 0x%x:\n", + __func__, + tdm_group->group_id, + dai_data->lane_cfg.lane_mask); /* * update tdm config param @@ -8246,7 +8284,8 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, */ if (dai_data->num_group_ports > 1) { rc = afe_port_group_enable(group_id, - &dai_data->group_cfg, true); + &dai_data->group_cfg, true, + &dai_data->lane_cfg); if (rc < 0) { dev_err(dai->dev, "%s: fail to enable AFE group 0x%x\n", @@ -8261,7 +8300,7 @@ static int msm_dai_q6_tdm_prepare(struct snd_pcm_substream *substream, if (rc < 0) { if (atomic_read(group_ref) == 0) { afe_port_group_enable(group_id, - NULL, false); + NULL, false, NULL); } if (msm_dai_q6_get_tdm_clk_ref(group_idx) == 0) { msm_dai_q6_tdm_set_clk(dai_data, @@ -8318,7 +8357,7 @@ static void msm_dai_q6_tdm_shutdown(struct snd_pcm_substream *substream, if (atomic_read(group_ref) == 0) { rc = afe_port_group_enable(group_id, - NULL, false); + NULL, false, NULL); if (rc < 0) { dev_err(dai->dev, "%s: fail to disable AFE group 0x%x\n", __func__, group_id); @@ -10223,7 +10262,7 @@ static int msm_dai_q6_tdm_dev_probe(struct platform_device *pdev) dai_data->group_cfg.tdm_cfg = tdm_group_cfg; /* copy static num group ports per parent node */ dai_data->num_group_ports = num_tdm_group_ports; - + dai_data->lane_cfg = tdm_lane_cfg; dev_set_drvdata(&pdev->dev, dai_data); diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 0002d82a125c..9f398bcc0f27 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -5422,6 +5422,53 @@ int afe_port_group_set_param(u16 group_id, return ret; } +/** + * afe_port_tdm_lane_config - + * to configure group TDM lane mask with specified configuration + * + * @group_id: AFE group id number + * @lane_cfg: TDM lane mask configutation + * + * Returns 0 on success or error value on failure. + */ +static int afe_port_tdm_lane_config(u16 group_id, + struct afe_param_id_tdm_lane_cfg *lane_cfg) +{ + struct param_hdr_v3 param_hdr; + int ret = 0; + + if (lane_cfg == NULL || + lane_cfg->lane_mask == AFE_LANE_MASK_INVALID) { + pr_debug("%s: lane cfg not supported for group id: 0x%x\n", + __func__, group_id); + return ret; + } + + pr_debug("%s: group id: 0x%x lane mask 0x%x\n", __func__, + group_id, lane_cfg->lane_mask); + + memset(¶m_hdr, 0, sizeof(param_hdr)); + + ret = afe_q6_interface_prepare(); + if (ret != 0) { + pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret); + return ret; + } + + param_hdr.module_id = AFE_MODULE_GROUP_DEVICE; + param_hdr.instance_id = INSTANCE_ID_0; + param_hdr.param_id = AFE_PARAM_ID_TDM_LANE_CONFIG; + param_hdr.param_size = sizeof(struct afe_param_id_tdm_lane_cfg); + + ret = q6afe_svc_pack_and_set_param_in_band(IDX_GLOBAL_CFG, param_hdr, + (u8 *)lane_cfg); + if (ret) + pr_err("%s: AFE_PARAM_ID_TDM_LANE_CONFIG failed %d\n", + __func__, ret); + + return ret; +} + /** * afe_port_group_enable - * command to enable AFE port group @@ -5429,12 +5476,14 @@ int afe_port_group_set_param(u16 group_id, * @group_id: group ID for AFE port group * @afe_group_config: config for AFE group * @enable: flag to indicate enable or disable + * @lane_cfg: TDM lane mask configutation * * Returns 0 on success or error on failure */ int afe_port_group_enable(u16 group_id, union afe_port_group_config *afe_group_config, - u16 enable) + u16 enable, + struct afe_param_id_tdm_lane_cfg *lane_cfg) { struct afe_group_device_enable group_enable; struct param_hdr_v3 param_hdr; @@ -5458,6 +5507,12 @@ int afe_port_group_enable(u16 group_id, pr_err("%s: afe send failed %d\n", __func__, ret); return ret; } + ret = afe_port_tdm_lane_config(group_id, lane_cfg); + if (ret < 0) { + pr_err("%s: afe send lane config failed %d\n", + __func__, ret); + return ret; + } } param_hdr.module_id = AFE_MODULE_GROUP_DEVICE; @@ -8998,4 +9053,3 @@ done: return ret; } EXPORT_SYMBOL(afe_unvote_lpass_core_hw); - diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 62ff28b17ed0..01174925da9c 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -1354,6 +1354,8 @@ struct adm_cmd_connect_afe_port_v5 { #define AFE_LOOPBACK_TX 0x6001 #define DISPLAY_PORT_RX 0x6020 +#define AFE_LANE_MASK_INVALID 0 + #define AFE_PORT_INVALID 0xFFFF #define SLIMBUS_INVALID AFE_PORT_INVALID @@ -12430,4 +12432,35 @@ struct afe_param_id_vad_cfg_t { #define AFE_PARAM_ID_VAD_CORE_CFG 0x000102BB +/** + * This parameter is should be used to configure the AFE TDM + * interface lane configuration. + * Regular TDM interface ports: + * This parameter ID must be used with module ID + * AFE_MODULE_AUDIO_DEV_INTERFACE and set using the AFE_PORT_CMD_SET_PARAM_V3 + * command for the AFE TDM interface port IDs. + * Group device TDM interface ports: + * This parameter ID must be used with module ID AFE_MODULE_GROUP_DEVICE + * and set using the AFE_SVC_CMD_SET_PARAM_V2 command for the AFE TDM group IDs. + */ +#define AFE_PARAM_ID_TDM_LANE_CONFIG 0x000102C1 + +/* Payload of the AFE_PARAM_ID_TDM_LANE_CONFIG parameter used by + * AFE_MODULE_AUDIO_DEV_INTERFACE. + */ +struct afe_param_id_tdm_lane_cfg { + uint16_t port_id; + /** ID of the TDM interface. + * For regular TDM interfaces value corresponds to valid port ID. + * For group devices TDM interface value corresponds to valid group device ID. + */ + + uint16_t lane_mask; + /** Position of the active lanes. Bits 0 to N correspond to lanes 0 to N. + * 1 to 2^N-1 When a bit is set, the corresponding lane is active. + * The number of active lanes can be inferred from the number of bits + * set in the mask. + */ +}; + #endif /*_APR_AUDIO_V2_H_ */ diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h index c5b7e3e65292..1efcb50b5669 100644 --- a/include/dsp/q6afe-v2.h +++ b/include/dsp/q6afe-v2.h @@ -432,7 +432,8 @@ int afe_set_aanc_noise_level(int val); int afe_port_group_set_param(u16 group_id, union afe_port_group_config *afe_group_config); int afe_port_group_enable(u16 group_id, - union afe_port_group_config *afe_group_config, u16 enable); + union afe_port_group_config *afe_group_config, u16 enable, + struct afe_param_id_tdm_lane_cfg *lane_cfg); int afe_unmap_rtac_block(uint32_t *mem_map_handle); int afe_map_rtac_block(struct rtac_cal_block_data *cal_block); int afe_send_slot_mapping_cfg(