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}
270