soundwire: cadence: override PDI configurations to create loopback

When we set a source PDI, the target PDI parameters will be overridden
by the source register values. The loopback streams can be
independently enabled on each link.

While the loopback source and target can be configured before any
stream is active on each link, the loopback stream should only be
prepared/triggered when the playback stream is prepared. Otherwise all
registers might be programmed to their reset values and the loopback
will not succeed. The SoundWire bus driver currently does not allow
two streams to be triggered at the same time, so the playback will
have to be started first, and later the loopback.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20210714032209.11284-11-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
Pierre-Louis Bossart 2021-07-14 11:22:09 +08:00 committed by Vinod Koul
parent 8fba8acd39
commit dd81e7c3f0

View File

@ -1374,20 +1374,37 @@ static int cdns_port_params(struct sdw_bus *bus,
struct sdw_port_params *p_params, unsigned int bank)
{
struct sdw_cdns *cdns = bus_to_cdns(bus);
int dpn_config = 0, dpn_config_off;
int dpn_config_off_source;
int dpn_config_off_target;
int target_num = p_params->num;
int source_num = p_params->num;
bool override = false;
int dpn_config;
if (bank)
dpn_config_off = CDNS_DPN_B1_CONFIG(p_params->num);
else
dpn_config_off = CDNS_DPN_B0_CONFIG(p_params->num);
if (target_num == cdns->pdi_loopback_target &&
cdns->pdi_loopback_source != -1) {
source_num = cdns->pdi_loopback_source;
override = true;
}
dpn_config = cdns_readl(cdns, dpn_config_off);
if (bank) {
dpn_config_off_source = CDNS_DPN_B1_CONFIG(source_num);
dpn_config_off_target = CDNS_DPN_B1_CONFIG(target_num);
} else {
dpn_config_off_source = CDNS_DPN_B0_CONFIG(source_num);
dpn_config_off_target = CDNS_DPN_B0_CONFIG(target_num);
}
u32p_replace_bits(&dpn_config, (p_params->bps - 1), CDNS_DPN_CONFIG_WL);
u32p_replace_bits(&dpn_config, p_params->flow_mode, CDNS_DPN_CONFIG_PORT_FLOW);
u32p_replace_bits(&dpn_config, p_params->data_mode, CDNS_DPN_CONFIG_PORT_DAT);
dpn_config = cdns_readl(cdns, dpn_config_off_source);
cdns_writel(cdns, dpn_config_off, dpn_config);
/* use port params if there is no loopback, otherwise use source as is */
if (!override) {
u32p_replace_bits(&dpn_config, p_params->bps - 1, CDNS_DPN_CONFIG_WL);
u32p_replace_bits(&dpn_config, p_params->flow_mode, CDNS_DPN_CONFIG_PORT_FLOW);
u32p_replace_bits(&dpn_config, p_params->data_mode, CDNS_DPN_CONFIG_PORT_DAT);
}
cdns_writel(cdns, dpn_config_off_target, dpn_config);
return 0;
}
@ -1397,11 +1414,27 @@ static int cdns_transport_params(struct sdw_bus *bus,
enum sdw_reg_bank bank)
{
struct sdw_cdns *cdns = bus_to_cdns(bus);
int dpn_offsetctrl = 0, dpn_offsetctrl_off;
int dpn_config = 0, dpn_config_off;
int dpn_hctrl = 0, dpn_hctrl_off;
int num = t_params->port_num;
int dpn_samplectrl_off;
int dpn_config;
int dpn_config_off_source;
int dpn_config_off_target;
int dpn_hctrl;
int dpn_hctrl_off_source;
int dpn_hctrl_off_target;
int dpn_offsetctrl;
int dpn_offsetctrl_off_source;
int dpn_offsetctrl_off_target;
int dpn_samplectrl;
int dpn_samplectrl_off_source;
int dpn_samplectrl_off_target;
int source_num = t_params->port_num;
int target_num = t_params->port_num;
bool override = false;
if (target_num == cdns->pdi_loopback_target &&
cdns->pdi_loopback_source != -1) {
source_num = cdns->pdi_loopback_source;
override = true;
}
/*
* Note: Only full data port is supported on the Master side for
@ -1409,32 +1442,59 @@ static int cdns_transport_params(struct sdw_bus *bus,
*/
if (bank) {
dpn_config_off = CDNS_DPN_B1_CONFIG(num);
dpn_samplectrl_off = CDNS_DPN_B1_SAMPLE_CTRL(num);
dpn_hctrl_off = CDNS_DPN_B1_HCTRL(num);
dpn_offsetctrl_off = CDNS_DPN_B1_OFFSET_CTRL(num);
dpn_config_off_source = CDNS_DPN_B1_CONFIG(source_num);
dpn_hctrl_off_source = CDNS_DPN_B1_HCTRL(source_num);
dpn_offsetctrl_off_source = CDNS_DPN_B1_OFFSET_CTRL(source_num);
dpn_samplectrl_off_source = CDNS_DPN_B1_SAMPLE_CTRL(source_num);
dpn_config_off_target = CDNS_DPN_B1_CONFIG(target_num);
dpn_hctrl_off_target = CDNS_DPN_B1_HCTRL(target_num);
dpn_offsetctrl_off_target = CDNS_DPN_B1_OFFSET_CTRL(target_num);
dpn_samplectrl_off_target = CDNS_DPN_B1_SAMPLE_CTRL(target_num);
} else {
dpn_config_off = CDNS_DPN_B0_CONFIG(num);
dpn_samplectrl_off = CDNS_DPN_B0_SAMPLE_CTRL(num);
dpn_hctrl_off = CDNS_DPN_B0_HCTRL(num);
dpn_offsetctrl_off = CDNS_DPN_B0_OFFSET_CTRL(num);
dpn_config_off_source = CDNS_DPN_B0_CONFIG(source_num);
dpn_hctrl_off_source = CDNS_DPN_B0_HCTRL(source_num);
dpn_offsetctrl_off_source = CDNS_DPN_B0_OFFSET_CTRL(source_num);
dpn_samplectrl_off_source = CDNS_DPN_B0_SAMPLE_CTRL(source_num);
dpn_config_off_target = CDNS_DPN_B0_CONFIG(target_num);
dpn_hctrl_off_target = CDNS_DPN_B0_HCTRL(target_num);
dpn_offsetctrl_off_target = CDNS_DPN_B0_OFFSET_CTRL(target_num);
dpn_samplectrl_off_target = CDNS_DPN_B0_SAMPLE_CTRL(target_num);
}
dpn_config = cdns_readl(cdns, dpn_config_off);
u32p_replace_bits(&dpn_config, t_params->blk_grp_ctrl, CDNS_DPN_CONFIG_BGC);
u32p_replace_bits(&dpn_config, t_params->blk_pkg_mode, CDNS_DPN_CONFIG_BPM);
cdns_writel(cdns, dpn_config_off, dpn_config);
dpn_config = cdns_readl(cdns, dpn_config_off_source);
if (!override) {
u32p_replace_bits(&dpn_config, t_params->blk_grp_ctrl, CDNS_DPN_CONFIG_BGC);
u32p_replace_bits(&dpn_config, t_params->blk_pkg_mode, CDNS_DPN_CONFIG_BPM);
}
cdns_writel(cdns, dpn_config_off_target, dpn_config);
u32p_replace_bits(&dpn_offsetctrl, t_params->offset1, CDNS_DPN_OFFSET_CTRL_1);
u32p_replace_bits(&dpn_offsetctrl, t_params->offset2, CDNS_DPN_OFFSET_CTRL_2);
cdns_writel(cdns, dpn_offsetctrl_off, dpn_offsetctrl);
if (!override) {
dpn_offsetctrl = 0;
u32p_replace_bits(&dpn_offsetctrl, t_params->offset1, CDNS_DPN_OFFSET_CTRL_1);
u32p_replace_bits(&dpn_offsetctrl, t_params->offset2, CDNS_DPN_OFFSET_CTRL_2);
} else {
dpn_offsetctrl = cdns_readl(cdns, dpn_offsetctrl_off_source);
}
cdns_writel(cdns, dpn_offsetctrl_off_target, dpn_offsetctrl);
u32p_replace_bits(&dpn_hctrl, t_params->hstart, CDNS_DPN_HCTRL_HSTART);
u32p_replace_bits(&dpn_hctrl, t_params->hstop, CDNS_DPN_HCTRL_HSTOP);
u32p_replace_bits(&dpn_hctrl, t_params->lane_ctrl, CDNS_DPN_HCTRL_LCTRL);
if (!override) {
dpn_hctrl = 0;
u32p_replace_bits(&dpn_hctrl, t_params->hstart, CDNS_DPN_HCTRL_HSTART);
u32p_replace_bits(&dpn_hctrl, t_params->hstop, CDNS_DPN_HCTRL_HSTOP);
u32p_replace_bits(&dpn_hctrl, t_params->lane_ctrl, CDNS_DPN_HCTRL_LCTRL);
} else {
dpn_hctrl = cdns_readl(cdns, dpn_hctrl_off_source);
}
cdns_writel(cdns, dpn_hctrl_off_target, dpn_hctrl);
cdns_writel(cdns, dpn_hctrl_off, dpn_hctrl);
cdns_writel(cdns, dpn_samplectrl_off, (t_params->sample_interval - 1));
if (!override)
dpn_samplectrl = t_params->sample_interval - 1;
else
dpn_samplectrl = cdns_readl(cdns, dpn_samplectrl_off_source);
cdns_writel(cdns, dpn_samplectrl_off_target, dpn_samplectrl);
return 0;
}