1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 // Copyright(c) 2023 Intel Corporation. All rights reserved.
3 
4 /*
5  * Soundwire Intel ops for LunarLake
6  */
7 
8 #include <linux/acpi.h>
9 #include <linux/device.h>
10 #include <linux/soundwire/sdw_registers.h>
11 #include <linux/soundwire/sdw.h>
12 #include <linux/soundwire/sdw_intel.h>
13 #include <sound/hda-mlink.h>
14 #include "cadence_master.h"
15 #include "bus.h"
16 #include "intel.h"
17 
18 /*
19  * shim vendor-specific (vs) ops
20  */
21 
22 static void intel_shim_vs_init(struct sdw_intel *sdw)
23 {
24 	void __iomem *shim_vs = sdw->link_res->shim_vs;
25 	u16 act = 0;
26 
27 	u16p_replace_bits(&act, 0x1, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS);
28 	act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DACTQE;
29 	act |=  SDW_SHIM2_INTEL_VS_ACTMCTL_DODS;
30 	intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL, act);
31 	usleep_range(10, 15);
32 }
33 
34 static int intel_shim_check_wake(struct sdw_intel *sdw)
35 {
36 	void __iomem *shim_vs;
37 	u16 wake_sts;
38 
39 	shim_vs = sdw->link_res->shim_vs;
40 	wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
41 
42 	return wake_sts & SDW_SHIM2_INTEL_VS_WAKEEN_PWS;
43 }
44 
45 static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
46 {
47 	void __iomem *shim_vs = sdw->link_res->shim_vs;
48 	u16 wake_en;
49 	u16 wake_sts;
50 
51 	wake_en = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN);
52 
53 	if (wake_enable) {
54 		/* Enable the wakeup */
55 		wake_en |= SDW_SHIM2_INTEL_VS_WAKEEN_PWE;
56 		intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
57 	} else {
58 		/* Disable the wake up interrupt */
59 		wake_en &= ~SDW_SHIM2_INTEL_VS_WAKEEN_PWE;
60 		intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
61 
62 		/* Clear wake status (W1C) */
63 		wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
64 		wake_sts |= SDW_SHIM2_INTEL_VS_WAKEEN_PWS;
65 		intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS, wake_sts);
66 	}
67 }
68 
69 static int intel_link_power_up(struct sdw_intel *sdw)
70 {
71 	struct sdw_bus *bus = &sdw->cdns.bus;
72 	struct sdw_master_prop *prop = &bus->prop;
73 	u32 *shim_mask = sdw->link_res->shim_mask;
74 	unsigned int link_id = sdw->instance;
75 	u32 syncprd;
76 	int ret;
77 
78 	mutex_lock(sdw->link_res->shim_lock);
79 
80 	if (!*shim_mask) {
81 		/* we first need to program the SyncPRD/CPU registers */
82 		dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n");
83 
84 		if (prop->mclk_freq % 6000000)
85 			syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
86 		else
87 			syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
88 
89 		ret =  hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd);
90 		if (ret < 0) {
91 			dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n",
92 				__func__, ret);
93 			goto out;
94 		}
95 	}
96 
97 	ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id);
98 	if (ret < 0) {
99 		dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n",
100 			__func__, ret);
101 		goto out;
102 	}
103 
104 	if (!*shim_mask) {
105 		/* SYNCPU will change once link is active */
106 		ret =  hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus);
107 		if (ret < 0) {
108 			dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_wait_syncpu failed: %d\n",
109 				__func__, ret);
110 			goto out;
111 		}
112 	}
113 
114 	*shim_mask |= BIT(link_id);
115 
116 	sdw->cdns.link_up = true;
117 
118 	intel_shim_vs_init(sdw);
119 
120 out:
121 	mutex_unlock(sdw->link_res->shim_lock);
122 
123 	return ret;
124 }
125 
126 static int intel_link_power_down(struct sdw_intel *sdw)
127 {
128 	u32 *shim_mask = sdw->link_res->shim_mask;
129 	unsigned int link_id = sdw->instance;
130 	int ret;
131 
132 	mutex_lock(sdw->link_res->shim_lock);
133 
134 	sdw->cdns.link_up = false;
135 
136 	*shim_mask &= ~BIT(link_id);
137 
138 	ret = hdac_bus_eml_sdw_power_down_unlocked(sdw->link_res->hbus, link_id);
139 	if (ret < 0) {
140 		dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_down failed: %d\n",
141 			__func__, ret);
142 
143 		/*
144 		 * we leave the sdw->cdns.link_up flag as false since we've disabled
145 		 * the link at this point and cannot handle interrupts any longer.
146 		 */
147 	}
148 
149 	mutex_unlock(sdw->link_res->shim_lock);
150 
151 	return ret;
152 }
153 
154 static void intel_sync_arm(struct sdw_intel *sdw)
155 {
156 	unsigned int link_id = sdw->instance;
157 
158 	mutex_lock(sdw->link_res->shim_lock);
159 
160 	hdac_bus_eml_sdw_sync_arm_unlocked(sdw->link_res->hbus, link_id);
161 
162 	mutex_unlock(sdw->link_res->shim_lock);
163 }
164 
165 static int intel_sync_go_unlocked(struct sdw_intel *sdw)
166 {
167 	int ret;
168 
169 	ret = hdac_bus_eml_sdw_sync_go_unlocked(sdw->link_res->hbus);
170 	if (ret < 0)
171 		dev_err(sdw->cdns.dev, "%s: SyncGO clear failed: %d\n", __func__, ret);
172 
173 	return ret;
174 }
175 
176 static int intel_sync_go(struct sdw_intel *sdw)
177 {
178 	int ret;
179 
180 	mutex_lock(sdw->link_res->shim_lock);
181 
182 	ret = intel_sync_go_unlocked(sdw);
183 
184 	mutex_unlock(sdw->link_res->shim_lock);
185 
186 	return ret;
187 }
188 
189 static bool intel_check_cmdsync_unlocked(struct sdw_intel *sdw)
190 {
191 	return hdac_bus_eml_sdw_check_cmdsync_unlocked(sdw->link_res->hbus);
192 }
193 
194 /*
195  * DAI operations
196  */
197 static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
198 };
199 
200 static const struct snd_soc_component_driver dai_component = {
201 	.name			= "soundwire",
202 };
203 
204 /*
205  * PDI routines
206  */
207 static void intel_pdi_init(struct sdw_intel *sdw,
208 			   struct sdw_cdns_stream_config *config)
209 {
210 	void __iomem *shim = sdw->link_res->shim;
211 	int pcm_cap;
212 
213 	/* PCM Stream Capability */
214 	pcm_cap = intel_readw(shim, SDW_SHIM2_PCMSCAP);
215 
216 	config->pcm_bd = FIELD_GET(SDW_SHIM2_PCMSCAP_BSS, pcm_cap);
217 	config->pcm_in = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
218 	config->pcm_out = FIELD_GET(SDW_SHIM2_PCMSCAP_ISS, pcm_cap);
219 
220 	dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
221 		config->pcm_bd, config->pcm_in, config->pcm_out);
222 }
223 
224 static int
225 intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num)
226 {
227 	void __iomem *shim = sdw->link_res->shim;
228 
229 	/* zero based values for channel count in register */
230 	return intel_readw(shim, SDW_SHIM2_PCMSYCHC(pdi_num)) + 1;
231 }
232 
233 static void intel_pdi_get_ch_update(struct sdw_intel *sdw,
234 				    struct sdw_cdns_pdi *pdi,
235 				    unsigned int num_pdi,
236 				    unsigned int *num_ch)
237 {
238 	int ch_count = 0;
239 	int i;
240 
241 	for (i = 0; i < num_pdi; i++) {
242 		pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num);
243 		ch_count += pdi->ch_count;
244 		pdi++;
245 	}
246 
247 	*num_ch = ch_count;
248 }
249 
250 static void intel_pdi_stream_ch_update(struct sdw_intel *sdw,
251 				       struct sdw_cdns_streams *stream)
252 {
253 	intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
254 				&stream->num_ch_bd);
255 
256 	intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
257 				&stream->num_ch_in);
258 
259 	intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
260 				&stream->num_ch_out);
261 }
262 
263 static int intel_create_dai(struct sdw_cdns *cdns,
264 			    struct snd_soc_dai_driver *dais,
265 			    enum intel_pdi_type type,
266 			    u32 num, u32 off, u32 max_ch)
267 {
268 	int i;
269 
270 	if (!num)
271 		return 0;
272 
273 	for (i = off; i < (off + num); i++) {
274 		dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
275 					      "SDW%d Pin%d",
276 					      cdns->instance, i);
277 		if (!dais[i].name)
278 			return -ENOMEM;
279 
280 		if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
281 			dais[i].playback.channels_min = 1;
282 			dais[i].playback.channels_max = max_ch;
283 		}
284 
285 		if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
286 			dais[i].capture.channels_min = 1;
287 			dais[i].capture.channels_max = max_ch;
288 		}
289 
290 		dais[i].ops = &intel_pcm_dai_ops;
291 	}
292 
293 	return 0;
294 }
295 
296 static int intel_register_dai(struct sdw_intel *sdw)
297 {
298 	struct sdw_cdns_dai_runtime **dai_runtime_array;
299 	struct sdw_cdns_stream_config config;
300 	struct sdw_cdns *cdns = &sdw->cdns;
301 	struct sdw_cdns_streams *stream;
302 	struct snd_soc_dai_driver *dais;
303 	int num_dai;
304 	int ret;
305 	int off = 0;
306 
307 	/* Read the PDI config and initialize cadence PDI */
308 	intel_pdi_init(sdw, &config);
309 	ret = sdw_cdns_pdi_init(cdns, config);
310 	if (ret)
311 		return ret;
312 
313 	intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm);
314 
315 	/* DAIs are created based on total number of PDIs supported */
316 	num_dai = cdns->pcm.num_pdi;
317 
318 	dai_runtime_array = devm_kcalloc(cdns->dev, num_dai,
319 					 sizeof(struct sdw_cdns_dai_runtime *),
320 					 GFP_KERNEL);
321 	if (!dai_runtime_array)
322 		return -ENOMEM;
323 	cdns->dai_runtime_array = dai_runtime_array;
324 
325 	dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
326 	if (!dais)
327 		return -ENOMEM;
328 
329 	/* Create PCM DAIs */
330 	stream = &cdns->pcm;
331 
332 	ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
333 			       off, stream->num_ch_in);
334 	if (ret)
335 		return ret;
336 
337 	off += cdns->pcm.num_in;
338 	ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
339 			       off, stream->num_ch_out);
340 	if (ret)
341 		return ret;
342 
343 	off += cdns->pcm.num_out;
344 	ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
345 			       off, stream->num_ch_bd);
346 	if (ret)
347 		return ret;
348 
349 	return devm_snd_soc_register_component(cdns->dev, &dai_component,
350 					       dais, num_dai);
351 }
352 
353 static void intel_program_sdi(struct sdw_intel *sdw, int dev_num)
354 {
355 	int ret;
356 
357 	ret = hdac_bus_eml_sdw_set_lsdiid(sdw->link_res->hbus, sdw->instance, dev_num);
358 	if (ret < 0)
359 		dev_err(sdw->cdns.dev, "%s: could not set lsdiid for link %d %d\n",
360 			__func__, sdw->instance, dev_num);
361 }
362 
363 const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = {
364 	.debugfs_init = intel_ace2x_debugfs_init,
365 	.debugfs_exit = intel_ace2x_debugfs_exit,
366 
367 	.register_dai = intel_register_dai,
368 
369 	.check_clock_stop = intel_check_clock_stop,
370 	.start_bus = intel_start_bus,
371 	.start_bus_after_reset = intel_start_bus_after_reset,
372 	.start_bus_after_clock_stop = intel_start_bus_after_clock_stop,
373 	.stop_bus = intel_stop_bus,
374 
375 	.link_power_up = intel_link_power_up,
376 	.link_power_down = intel_link_power_down,
377 
378 	.shim_check_wake = intel_shim_check_wake,
379 	.shim_wake = intel_shim_wake,
380 
381 	.pre_bank_switch = intel_pre_bank_switch,
382 	.post_bank_switch = intel_post_bank_switch,
383 
384 	.sync_arm = intel_sync_arm,
385 	.sync_go_unlocked = intel_sync_go_unlocked,
386 	.sync_go = intel_sync_go,
387 	.sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,
388 
389 	.program_sdi = intel_program_sdi,
390 };
391 EXPORT_SYMBOL_NS(sdw_intel_lnl_hw_ops, SOUNDWIRE_INTEL);
392 
393 MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
394