Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 34 additions & 16 deletions drivers/soundwire/cadence_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,29 @@ static int cdns_config_update(struct sdw_cdns *cdns)
return ret;
}

/**
* sdw_cdns_config_update() - Update configurations
* @cdns: Cadence instance
*/
void sdw_cdns_config_update(struct sdw_cdns *cdns)
{
/* commit changes */
cdns_writel(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);
Comment thread
RanderWang marked this conversation as resolved.
}
EXPORT_SYMBOL(sdw_cdns_config_update);

/**
* sdw_cdns_config_update_set_wait() - wait until configuration update bit is self-cleared
* @cdns: Cadence instance
*/
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns)
{
/* the hardware recommendation is to wait at least 300us */
return cdns_set_wait(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT, 0);
}
EXPORT_SYMBOL(sdw_cdns_config_update_set_wait);

/*
* debugfs
*/
Expand Down Expand Up @@ -433,9 +456,9 @@ static int cdns_parity_error_injection(void *data, u64 value)
CDNS_IP_MCP_CMDCTRL_INSERT_PARITY_ERR);

/* commit changes */
cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT,
CDNS_MCP_CONFIG_UPDATE_BIT);
ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);
if (ret < 0)
goto unlock;

/* do a broadcast dummy read to avoid bus clashes */
ret = sdw_bread_no_pm_unlocked(&cdns->bus, 0xf, SDW_SCP_DEVID_0);
Expand All @@ -447,16 +470,17 @@ static int cdns_parity_error_injection(void *data, u64 value)
0);

/* commit changes */
cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT,
CDNS_MCP_CONFIG_UPDATE_BIT);

/* Continue bus operation with parity error injection disabled */
mutex_unlock(&bus->bus_lock);
ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE, CDNS_MCP_CONFIG_UPDATE_BIT);
if (ret < 0)
goto unlock;

/* Userspace changed the hardware state behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_STILL_OK);

unlock:
/* Continue bus operation with parity error injection disabled */
mutex_unlock(&bus->bus_lock);

/*
* allow Master device to enter pm_runtime suspend. This may
* also result in Slave devices suspending.
Expand Down Expand Up @@ -1116,13 +1140,7 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
CDNS_MCP_CONTROL_HW_RST);

/* commit changes */
cdns_updatel(cdns, CDNS_MCP_CONFIG_UPDATE,
CDNS_MCP_CONFIG_UPDATE_BIT,
CDNS_MCP_CONFIG_UPDATE_BIT);

/* don't wait here */
return 0;

return cdns_config_update(cdns);
}
EXPORT_SYMBOL(sdw_cdns_exit_reset);

Expand Down
3 changes: 3 additions & 0 deletions drivers/soundwire/cadence_master.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,7 @@ int cdns_set_sdw_stream(struct snd_soc_dai *dai,
void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string,
bool initial_delay, int reset_iterations);

void sdw_cdns_config_update(struct sdw_cdns *cdns);
int sdw_cdns_config_update_set_wait(struct sdw_cdns *cdns);

#endif /* __SDW_CADENCE_H */
92 changes: 51 additions & 41 deletions drivers/soundwire/intel_bus_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,6 @@ int intel_start_bus(struct sdw_intel *sdw)
struct sdw_bus *bus = &cdns->bus;
int ret;

ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
return ret;
}

/*
* follow recommended programming flows to avoid timeouts when
* gsync is enabled
Expand All @@ -32,30 +26,41 @@ int intel_start_bus(struct sdw_intel *sdw)
ret = sdw_cdns_init(cdns);
if (ret < 0) {
dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret);
goto err_interrupt;
return ret;
}

ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
goto err_interrupt;
}
sdw_cdns_config_update(cdns);

if (bus->multi_link) {
ret = sdw_intel_sync_go(sdw);
if (ret < 0) {
dev_err(dev, "%s: sync go failed: %d\n", __func__, ret);
goto err_interrupt;
return ret;
}
}

ret = sdw_cdns_config_update_set_wait(cdns);
if (ret < 0) {
dev_err(dev, "%s: CONFIG_UPDATE BIT still set\n", __func__);
return ret;
}

ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
return ret;
}

ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
return ret;
}

sdw_cdns_check_self_clearing_bits(cdns, __func__,
true, INTEL_MASTER_RESET_ITERATIONS);

return 0;

err_interrupt:
sdw_cdns_enable_interrupt(cdns, false);
return ret;
}

int intel_start_bus_after_reset(struct sdw_intel *sdw)
Expand Down Expand Up @@ -86,12 +91,6 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw)
status = SDW_UNATTACH_REQUEST_MASTER_RESET;
sdw_clear_slave_status(bus, status);

ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}

/*
* follow recommended programming flows to avoid
* timeouts when gsync is enabled
Expand All @@ -115,31 +114,44 @@ int intel_start_bus_after_reset(struct sdw_intel *sdw)
ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
if (ret < 0) {
dev_err(dev, "unable to restart clock during resume\n");
goto err_interrupt;
if (!clock_stop0)
sdw_cdns_enable_interrupt(cdns, false);
Comment thread
plbossart marked this conversation as resolved.
return ret;
}

if (!clock_stop0) {
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n");
goto err_interrupt;
}
sdw_cdns_config_update(cdns);

if (bus->multi_link) {
ret = sdw_intel_sync_go(sdw);
if (ret < 0) {
dev_err(sdw->cdns.dev, "sync go failed during resume\n");
goto err_interrupt;
return ret;
}
}

ret = sdw_cdns_config_update_set_wait(cdns);
if (ret < 0) {
dev_err(dev, "%s: CONFIG_UPDATE BIT still set\n", __func__);
return ret;
}

ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n");
return ret;
}

ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}

}
sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);

return 0;

err_interrupt:
sdw_cdns_enable_interrupt(cdns, false);
return ret;
}

void intel_check_clock_stop(struct sdw_intel *sdw)
Expand All @@ -158,21 +170,19 @@ int intel_start_bus_after_clock_stop(struct sdw_intel *sdw)
struct sdw_cdns *cdns = &sdw->cdns;
int ret;

ret = sdw_cdns_enable_interrupt(cdns, true);
ret = sdw_cdns_clock_restart(cdns, false);
if (ret < 0) {
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret);
return ret;
}

ret = sdw_cdns_clock_restart(cdns, false);
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret);
sdw_cdns_enable_interrupt(cdns, false);
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
return ret;
}

sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks",
true, INTEL_MASTER_RESET_ITERATIONS);
sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);

return 0;
}
Expand Down