xref: /linux/drivers/soundwire/intel_bus_common.c (revision 08b7174fb8d126e607e385e34b9e1da4f3be274f)
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 
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_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 
66 int 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 
157 void 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 
167 int 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 
190 int 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 
226 int 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 
240 int 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