281 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)2// Copyright(c) 2015-2023 Intel Corporation3 4#include <linux/acpi.h>5#include <linux/soundwire/sdw_registers.h>6#include <linux/soundwire/sdw.h>7#include <linux/soundwire/sdw_intel.h>8#include "cadence_master.h"9#include "bus.h"10#include "intel.h"11 12int intel_start_bus(struct sdw_intel *sdw)13{14 struct device *dev = sdw->cdns.dev;15 struct sdw_cdns *cdns = &sdw->cdns;16 struct sdw_bus *bus = &cdns->bus;17 int ret;18 19 /*20 * follow recommended programming flows to avoid timeouts when21 * gsync is enabled22 */23 if (bus->multi_link)24 sdw_intel_sync_arm(sdw);25 26 ret = sdw_cdns_init(cdns);27 if (ret < 0) {28 dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret);29 return ret;30 }31 32 sdw_cdns_config_update(cdns);33 34 if (bus->multi_link) {35 ret = sdw_intel_sync_go(sdw);36 if (ret < 0) {37 dev_err(dev, "%s: sync go failed: %d\n", __func__, ret);38 return ret;39 }40 }41 42 ret = sdw_cdns_config_update_set_wait(cdns);43 if (ret < 0) {44 dev_err(dev, "%s: CONFIG_UPDATE BIT still set\n", __func__);45 return ret;46 }47 48 ret = sdw_cdns_enable_interrupt(cdns, true);49 if (ret < 0) {50 dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);51 return ret;52 }53 54 ret = sdw_cdns_exit_reset(cdns);55 if (ret < 0) {56 dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);57 return ret;58 }59 60 sdw_cdns_check_self_clearing_bits(cdns, __func__,61 true, INTEL_MASTER_RESET_ITERATIONS);62 63 schedule_delayed_work(&cdns->attach_dwork,64 msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS));65 66 return 0;67}68 69int intel_start_bus_after_reset(struct sdw_intel *sdw)70{71 struct device *dev = sdw->cdns.dev;72 struct sdw_cdns *cdns = &sdw->cdns;73 struct sdw_bus *bus = &cdns->bus;74 bool clock_stop0;75 int status;76 int ret;77 78 /*79 * An exception condition occurs for the CLK_STOP_BUS_RESET80 * case if one or more masters remain active. In this condition,81 * all the masters are powered on for they are in the same power82 * domain. Master can preserve its context for clock stop0, so83 * there is no need to clear slave status and reset bus.84 */85 clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);86 87 if (!clock_stop0) {88 89 /*90 * make sure all Slaves are tagged as UNATTACHED and91 * provide reason for reinitialization92 */93 94 status = SDW_UNATTACH_REQUEST_MASTER_RESET;95 sdw_clear_slave_status(bus, status);96 97 /*98 * follow recommended programming flows to avoid99 * timeouts when gsync is enabled100 */101 if (bus->multi_link)102 sdw_intel_sync_arm(sdw);103 104 /*105 * Re-initialize the IP since it was powered-off106 */107 sdw_cdns_init(&sdw->cdns);108 109 } else {110 ret = sdw_cdns_enable_interrupt(cdns, true);111 if (ret < 0) {112 dev_err(dev, "cannot enable interrupts during resume\n");113 return ret;114 }115 }116 117 ret = sdw_cdns_clock_restart(cdns, !clock_stop0);118 if (ret < 0) {119 dev_err(dev, "unable to restart clock during resume\n");120 if (!clock_stop0)121 sdw_cdns_enable_interrupt(cdns, false);122 return ret;123 }124 125 if (!clock_stop0) {126 sdw_cdns_config_update(cdns);127 128 if (bus->multi_link) {129 ret = sdw_intel_sync_go(sdw);130 if (ret < 0) {131 dev_err(sdw->cdns.dev, "sync go failed during resume\n");132 return ret;133 }134 }135 136 ret = sdw_cdns_config_update_set_wait(cdns);137 if (ret < 0) {138 dev_err(dev, "%s: CONFIG_UPDATE BIT still set\n", __func__);139 return ret;140 }141 142 ret = sdw_cdns_enable_interrupt(cdns, true);143 if (ret < 0) {144 dev_err(dev, "cannot enable interrupts during resume\n");145 return ret;146 }147 148 ret = sdw_cdns_exit_reset(cdns);149 if (ret < 0) {150 dev_err(dev, "unable to exit bus reset sequence during resume\n");151 return ret;152 }153 154 }155 sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);156 157 schedule_delayed_work(&cdns->attach_dwork,158 msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS));159 160 return 0;161}162 163void intel_check_clock_stop(struct sdw_intel *sdw)164{165 struct device *dev = sdw->cdns.dev;166 bool clock_stop0;167 168 clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);169 if (!clock_stop0)170 dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__);171}172 173int intel_start_bus_after_clock_stop(struct sdw_intel *sdw)174{175 struct device *dev = sdw->cdns.dev;176 struct sdw_cdns *cdns = &sdw->cdns;177 int ret;178 179 ret = sdw_cdns_clock_restart(cdns, false);180 if (ret < 0) {181 dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret);182 return ret;183 }184 185 ret = sdw_cdns_enable_interrupt(cdns, true);186 if (ret < 0) {187 dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);188 return ret;189 }190 191 sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);192 193 schedule_delayed_work(&cdns->attach_dwork,194 msecs_to_jiffies(SDW_INTEL_DELAYED_ENUMERATION_MS));195 196 return 0;197}198 199int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop)200{201 struct device *dev = sdw->cdns.dev;202 struct sdw_cdns *cdns = &sdw->cdns;203 bool wake_enable = false;204 int ret;205 206 cancel_delayed_work_sync(&cdns->attach_dwork);207 208 if (clock_stop) {209 ret = sdw_cdns_clock_stop(cdns, true);210 if (ret < 0)211 dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret);212 else213 wake_enable = true;214 }215 216 ret = sdw_cdns_enable_interrupt(cdns, false);217 if (ret < 0) {218 dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret);219 return ret;220 }221 222 ret = sdw_intel_link_power_down(sdw);223 if (ret) {224 dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret);225 return ret;226 }227 228 sdw_intel_shim_wake(sdw, wake_enable);229 230 return 0;231}232 233/*234 * bank switch routines235 */236 237int intel_pre_bank_switch(struct sdw_intel *sdw)238{239 struct sdw_cdns *cdns = &sdw->cdns;240 struct sdw_bus *bus = &cdns->bus;241 242 /* Write to register only for multi-link */243 if (!bus->multi_link)244 return 0;245 246 sdw_intel_sync_arm(sdw);247 248 return 0;249}250 251int intel_post_bank_switch(struct sdw_intel *sdw)252{253 struct sdw_cdns *cdns = &sdw->cdns;254 struct sdw_bus *bus = &cdns->bus;255 int ret = 0;256 257 /* Write to register only for multi-link */258 if (!bus->multi_link)259 return 0;260 261 mutex_lock(sdw->link_res->shim_lock);262 263 /*264 * post_bank_switch() ops is called from the bus in loop for265 * all the Masters in the steam with the expectation that266 * we trigger the bankswitch for the only first Master in the list267 * and do nothing for the other Masters268 *269 * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master.270 */271 if (sdw_intel_sync_check_cmdsync_unlocked(sdw))272 ret = sdw_intel_sync_go_unlocked(sdw);273 274 mutex_unlock(sdw->link_res->shim_lock);275 276 if (ret < 0)277 dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret);278 279 return ret;280}281