Linux Audio

Check our new training course

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