xref: /linux/drivers/soundwire/intel_bus_common.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
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 
12 int 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_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 
69 int 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_RESET
80 	 * case if one or more masters remain active. In this condition,
81 	 * all the masters are powered on for they are in the same power
82 	 * domain. Master can preserve its context for clock stop0, so
83 	 * 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 and
91 		 * provide reason for reinitialization
92 		 */
93 
94 		status = SDW_UNATTACH_REQUEST_MASTER_RESET;
95 		sdw_clear_slave_status(bus, status);
96 
97 		/*
98 		 * follow recommended programming flows to avoid
99 		 * timeouts when gsync is enabled
100 		 */
101 		if (bus->multi_link)
102 			sdw_intel_sync_arm(sdw);
103 
104 		/*
105 		 * Re-initialize the IP since it was powered-off
106 		 */
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 
163 void 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 
173 int 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 
199 int 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 		else
213 			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 routines
235  */
236 
237 int 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 
251 int 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 for
265 	 * all the Masters in the steam with the expectation that
266 	 * we trigger the bankswitch for the only first Master in the list
267 	 * and do nothing for the other Masters
268 	 *
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