static int intel_link_power_up(struct sdw_intel *sdw)
{
+ struct sdw_bus *bus = &sdw->cdns.bus;
+ struct sdw_master_prop *prop = &bus->prop;
+ u32 *shim_mask = sdw->link_res->shim_mask;
+ unsigned int link_id = sdw->instance;
+ u32 syncprd;
int ret;
mutex_lock(sdw->link_res->shim_lock);
- ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, sdw->instance);
+ if (!*shim_mask) {
+ /* we first need to program the SyncPRD/CPU registers */
+ dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n");
+
+ if (prop->mclk_freq % 6000000)
+ syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
+ else
+ syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
+
+ ret = hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd);
+ if (ret < 0) {
+ dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n",
+ __func__, ret);
+ goto out;
+ }
+ }
+
+ ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id);
if (ret < 0) {
dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n",
__func__, ret);
goto out;
}
+ if (!*shim_mask) {
+ /* SYNCPU will change once link is active */
+ ret = hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus);
+ if (ret < 0) {
+ dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_wait_syncpu failed: %d\n",
+ __func__, ret);
+ goto out;
+ }
+ }
+
+ *shim_mask |= BIT(link_id);
+
sdw->cdns.link_up = true;
out:
mutex_unlock(sdw->link_res->shim_lock);
static int intel_link_power_down(struct sdw_intel *sdw)
{
+ u32 *shim_mask = sdw->link_res->shim_mask;
+ unsigned int link_id = sdw->instance;
int ret;
mutex_lock(sdw->link_res->shim_lock);
sdw->cdns.link_up = false;
- ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, sdw->instance);
+ *shim_mask &= ~BIT(link_id);
+
+ ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id);
if (ret < 0) {
dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n",
__func__, ret);