@@ -87,6 +87,10 @@ static int _sdw_program_slave_port_params(struct sdw_bus *bus,
return ret;
}
+ /* DP0 does not implement BlockCtrl3 */
+ if (!t_params->port_num)
+ goto skip_block_ctrl3;
+
/* Program DPN_BlockCtrl3 register */
ret = sdw_write_no_pm(slave, addr2, t_params->blk_pkg_mode);
if (ret < 0) {
@@ -94,6 +98,7 @@ static int _sdw_program_slave_port_params(struct sdw_bus *bus,
return ret;
}
+skip_block_ctrl3:
/*
* Data ports are FULL, SIMPLE and REDUCED. This function handles
* FULL and REDUCED only and beyond this point only FULL is
@@ -130,18 +135,29 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
struct sdw_port_params *p_params = &p_rt->port_params;
struct sdw_slave_prop *slave_prop = &s_rt->slave->prop;
u32 addr1, addr2, addr3, addr4, addr5, addr6;
- struct sdw_dpn_prop *dpn_prop;
+ enum sdw_dpn_type port_type;
+ bool read_only_wordlength;
int ret;
u8 wbuf;
if (s_rt->slave->is_mockup_device)
return 0;
- dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave,
- s_rt->direction,
- t_params->port_num);
- if (!dpn_prop)
- return -EINVAL;
+ if (t_params->port_num) {
+ struct sdw_dpn_prop *dpn_prop;
+
+ dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave,
+ s_rt->direction,
+ t_params->port_num);
+ if (!dpn_prop)
+ return -EINVAL;
+
+ read_only_wordlength = dpn_prop->read_only_wordlength;
+ port_type = dpn_prop->type;
+ } else {
+ read_only_wordlength = false;
+ port_type = SDW_DPN_FULL;
+ }
addr1 = SDW_DPN_PORTCTRL(t_params->port_num);
addr2 = SDW_DPN_BLOCKCTRL1(t_params->port_num);
@@ -171,7 +187,7 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
return ret;
}
- if (!dpn_prop->read_only_wordlength) {
+ if (!read_only_wordlength) {
/* Program DPN_BlockCtrl1 register */
ret = sdw_write_no_pm(s_rt->slave, addr2, (p_params->bps - 1));
if (ret < 0) {
@@ -223,9 +239,9 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus,
}
}
- if (dpn_prop->type != SDW_DPN_SIMPLE) {
+ if (port_type != SDW_DPN_SIMPLE) {
ret = _sdw_program_slave_port_params(bus, s_rt->slave,
- t_params, dpn_prop->type);
+ t_params, port_type);
if (ret < 0)
dev_err(&s_rt->slave->dev,
"Transport reg write failed for port: %d\n",
@@ -432,6 +448,9 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
struct completion *port_ready;
struct sdw_dpn_prop *dpn_prop;
struct sdw_prepare_ch prep_ch;
+ u32 imp_def_interrupts;
+ bool simple_ch_prep_sm;
+ u32 ch_prep_timeout;
bool intr = false;
int ret = 0, val;
u32 addr;
@@ -439,20 +458,31 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
prep_ch.num = p_rt->num;
prep_ch.ch_mask = p_rt->ch_mask;
- dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave,
- s_rt->direction,
- prep_ch.num);
- if (!dpn_prop) {
- dev_err(bus->dev,
- "Slave Port:%d properties not found\n", prep_ch.num);
- return -EINVAL;
+ if (p_rt->num) {
+ dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave,
+ s_rt->direction,
+ prep_ch.num);
+ if (!dpn_prop) {
+ dev_err(bus->dev,
+ "Slave Port:%d properties not found\n", prep_ch.num);
+ return -EINVAL;
+ }
+
+ imp_def_interrupts = dpn_prop->imp_def_interrupts;
+ simple_ch_prep_sm = dpn_prop->simple_ch_prep_sm;
+ } else {
+ struct sdw_dp0_prop *dp0_prop = s_rt->slave->prop.dp0_prop;
+
+ imp_def_interrupts = dp0_prop->imp_def_interrupts;
+ simple_ch_prep_sm = dp0_prop->simple_ch_prep_sm;
+ ch_prep_timeout = dp0_prop->ch_prep_timeout;
}
prep_ch.prepare = prep;
prep_ch.bank = bus->params.next_bank;
- if (dpn_prop->imp_def_interrupts || !dpn_prop->simple_ch_prep_sm ||
+ if (imp_def_interrupts || !simple_ch_prep_sm ||
bus->params.s_data_mode != SDW_PORT_DATA_MODE_NORMAL)
intr = true;
@@ -463,7 +493,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
*/
if (prep && intr) {
ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
- dpn_prop->imp_def_interrupts);
+ imp_def_interrupts);
if (ret < 0)
return ret;
}
@@ -472,7 +502,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
sdw_do_port_prep(s_rt, prep_ch, prep ? SDW_OPS_PORT_PRE_PREP : SDW_OPS_PORT_PRE_DEPREP);
/* Prepare Slave port implementing CP_SM */
- if (!dpn_prop->simple_ch_prep_sm) {
+ if (!simple_ch_prep_sm) {
addr = SDW_DPN_PREPARECTRL(p_rt->num);
if (prep)
@@ -489,7 +519,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
/* Wait for completion on port ready */
port_ready = &s_rt->slave->port_ready[prep_ch.num];
wait_for_completion_timeout(port_ready,
- msecs_to_jiffies(dpn_prop->ch_prep_timeout));
+ msecs_to_jiffies(ch_prep_timeout));
val = sdw_read_no_pm(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num));
if ((val < 0) || (val & p_rt->ch_mask)) {
@@ -506,7 +536,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
/* Disable interrupt after Port de-prepare */
if (!prep && intr)
ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
- dpn_prop->imp_def_interrupts);
+ imp_def_interrupts);
return ret;
}
@@ -970,7 +1000,8 @@ static int sdw_slave_port_is_valid_range(struct device *dev, int num)
static int sdw_slave_port_config(struct sdw_slave *slave,
struct sdw_slave_runtime *s_rt,
- const struct sdw_port_config *port_config)
+ const struct sdw_port_config *port_config,
+ bool is_bpt_stream)
{
struct sdw_port_runtime *p_rt;
int ret;
@@ -982,9 +1013,14 @@ static int sdw_slave_port_config(struct sdw_slave *slave,
* TODO: Check valid port range as defined by DisCo/
* slave
*/
- ret = sdw_slave_port_is_valid_range(&slave->dev, port_config[i].num);
- if (ret < 0)
- return ret;
+ if (!is_bpt_stream) {
+ ret = sdw_slave_port_is_valid_range(&slave->dev, port_config[i].num);
+ if (ret < 0)
+ return ret;
+ } else {
+ if (port_config[i].num)
+ return -EINVAL;
+ }
ret = sdw_port_config(p_rt, port_config, i);
if (ret < 0)
@@ -1293,6 +1329,11 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
u8 num_ports;
int i;
+ if (!port_num) {
+ dev_err(&slave->dev, "%s: port_num is zero\n", __func__);
+ return NULL;
+ }
+
if (direction == SDW_DATA_DIR_TX) {
num_ports = hweight32(slave->prop.source_ports);
dpn_prop = slave->prop.src_dpn_prop;
@@ -2056,7 +2097,8 @@ int sdw_stream_add_slave(struct sdw_slave *slave,
if (ret)
goto unlock;
- ret = sdw_slave_port_config(slave, s_rt, port_config);
+ ret = sdw_slave_port_config(slave, s_rt, port_config,
+ stream->type == SDW_STREAM_BPT ? true : false);
if (ret)
goto unlock;
DP0 (Data Port 0) is very similar to regular data ports, with minor tweaks we can reuse the same code. Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> --- drivers/soundwire/stream.c | 94 +++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 26 deletions(-)