brintos

brintos / linux-shallow public Read only

0
0
Text · 6.4 KiB · d3ff6c6 Raw
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