File Index
Files and directories
Sign in
FILE

intel_init.c

File preview with syntax highlighting.

linux-6.19.14/drivers/soundwire/intel_init.c C
  1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
  2// Copyright(c) 2015-17 Intel Corporation.
  3
  4/*
  5 * SDW Intel Init Routines
  6 *
  7 * Initializes and creates SDW devices based on ACPI and Hardware values
  8 */
  9
 10#include <linux/acpi.h>
 11#include <linux/export.h>
 12#include <linux/interrupt.h>
 13#include <linux/io.h>
 14#include <linux/module.h>
 15#include <linux/auxiliary_bus.h>
 16#include <linux/pm_runtime.h>
 17#include <linux/soundwire/sdw_intel.h>
 18#include "cadence_master.h"
 19#include "bus.h"
 20#include "intel.h"
 21#include "intel_auxdevice.h"
 22
 23static void intel_link_dev_release(struct device *dev)
 24{
 25	struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
 26	struct sdw_intel_link_dev *ldev = auxiliary_dev_to_sdw_intel_link_dev(auxdev);
 27
 28	kfree(ldev);
 29}
 30
 31/* alloc, init and add link devices */
 32static struct sdw_intel_link_dev *intel_link_dev_register(struct sdw_intel_res *res,
 33							  struct sdw_intel_ctx *ctx,
 34							  struct fwnode_handle *fwnode,
 35							  const char *name,
 36							  int link_id)
 37{
 38	struct sdw_intel_link_dev *ldev;
 39	struct sdw_intel_link_res *link;
 40	struct auxiliary_device *auxdev;
 41	int ret;
 42
 43	ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
 44	if (!ldev)
 45		return ERR_PTR(-ENOMEM);
 46
 47	auxdev = &ldev->auxdev;
 48	auxdev->name = name;
 49	auxdev->dev.parent = res->parent;
 50	auxdev->dev.fwnode = fwnode;
 51	auxdev->dev.release = intel_link_dev_release;
 52
 53	/* we don't use an IDA since we already have a link ID */
 54	auxdev->id = link_id;
 55
 56	/*
 57	 * keep a handle on the allocated memory, to be used in all other functions.
 58	 * Since the same pattern is used to skip links that are not enabled, there is
 59	 * no need to check if ctx->ldev[i] is NULL later on.
 60	 */
 61	ctx->ldev[link_id] = ldev;
 62
 63	/* Add link information used in the driver probe */
 64	link = &ldev->link_res;
 65	link->hw_ops = res->hw_ops;
 66	link->mmio_base = res->mmio_base;
 67	if (!res->ext) {
 68		link->registers = res->mmio_base + SDW_LINK_BASE
 69			+ (SDW_LINK_SIZE * link_id);
 70		link->ip_offset = 0;
 71		link->shim = res->mmio_base + res->shim_base;
 72		link->alh = res->mmio_base + res->alh_base;
 73		link->shim_lock = &ctx->shim_lock;
 74	} else {
 75		link->registers = res->mmio_base + SDW_IP_BASE(link_id);
 76		link->ip_offset = SDW_CADENCE_MCP_IP_OFFSET;
 77		link->shim = res->mmio_base +  SDW_SHIM2_GENERIC_BASE(link_id);
 78		link->shim_vs = res->mmio_base + SDW_SHIM2_VS_BASE(link_id);
 79		link->shim_lock = res->eml_lock;
 80		link->mic_privacy = res->mic_privacy;
 81	}
 82
 83	link->ops = res->ops;
 84	link->dev = res->dev;
 85
 86	link->clock_stop_quirks = res->clock_stop_quirks;
 87	link->shim_mask = &ctx->shim_mask;
 88	link->link_mask = ctx->link_mask;
 89
 90	link->hbus = res->hbus;
 91
 92	/* now follow the two-step init/add sequence */
 93	ret = auxiliary_device_init(auxdev);
 94	if (ret < 0) {
 95		dev_err(res->parent, "failed to initialize link dev %s link_id %d\n",
 96			name, link_id);
 97		kfree(ldev);
 98		return ERR_PTR(ret);
 99	}
100
101	ret = auxiliary_device_add(&ldev->auxdev);
102	if (ret < 0) {
103		dev_err(res->parent, "failed to add link dev %s link_id %d\n",
104			ldev->auxdev.name, link_id);
105		/* ldev will be freed with the put_device() and .release sequence */
106		auxiliary_device_uninit(&ldev->auxdev);
107		return ERR_PTR(ret);
108	}
109
110	return ldev;
111}
112
113static void intel_link_dev_unregister(struct sdw_intel_link_dev *ldev)
114{
115	auxiliary_device_delete(&ldev->auxdev);
116	auxiliary_device_uninit(&ldev->auxdev);
117}
118
119static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
120{
121	struct sdw_intel_link_dev *ldev;
122	u32 link_mask;
123	int i;
124
125	link_mask = ctx->link_mask;
126
127	for (i = 0; i < ctx->count; i++) {
128		if (!(link_mask & BIT(i)))
129			continue;
130
131		ldev = ctx->ldev[i];
132
133		pm_runtime_disable(&ldev->auxdev.dev);
134		if (!ldev->link_res.clock_stop_quirks)
135			pm_runtime_put_noidle(ldev->link_res.dev);
136
137		intel_link_dev_unregister(ldev);
138	}
139
140	return 0;
141}
142
143irqreturn_t sdw_intel_thread(int irq, void *dev_id)
144{
145	struct sdw_intel_ctx *ctx = dev_id;
146	struct sdw_intel_link_res *link;
147
148	list_for_each_entry(link, &ctx->link_list, list)
149		sdw_cdns_irq(irq, link->cdns);
150
151	return IRQ_HANDLED;
152}
153EXPORT_SYMBOL_NS(sdw_intel_thread, "SOUNDWIRE_INTEL_INIT");
154
155static struct sdw_intel_ctx
156*sdw_intel_probe_controller(struct sdw_intel_res *res)
157{
158	struct sdw_intel_link_res *link;
159	struct sdw_intel_link_dev *ldev;
160	struct sdw_intel_ctx *ctx;
161	struct acpi_device *adev;
162	struct sdw_slave *slave;
163	struct list_head *node;
164	struct sdw_bus *bus;
165	u32 link_mask;
166	int num_slaves = 0;
167	int count;
168	int i;
169
170	if (!res)
171		return NULL;
172
173	adev = acpi_fetch_acpi_dev(res->handle);
174	if (!adev)
175		return NULL;
176
177	if (!res->count)
178		return NULL;
179
180	count = res->count;
181	dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
182
183	/*
184	 * we need to alloc/free memory manually and can't use devm:
185	 * this routine may be called from a workqueue, and not from
186	 * the parent .probe.
187	 * If devm_ was used, the memory might never be freed on errors.
188	 */
189	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
190	if (!ctx)
191		return NULL;
192
193	ctx->count = count;
194
195	/*
196	 * allocate the array of pointers. The link-specific data is allocated
197	 * as part of the first loop below and released with the auxiliary_device_uninit().
198	 * If some links are disabled, the link pointer will remain NULL. Given that the
199	 * number of links is small, this is simpler than using a list to keep track of links.
200	 */
201	ctx->ldev = kcalloc(ctx->count, sizeof(*ctx->ldev), GFP_KERNEL);
202	if (!ctx->ldev) {
203		kfree(ctx);
204		return NULL;
205	}
206
207	ctx->mmio_base = res->mmio_base;
208	ctx->shim_base = res->shim_base;
209	ctx->alh_base = res->alh_base;
210	ctx->link_mask = res->link_mask;
211	ctx->handle = res->handle;
212	mutex_init(&ctx->shim_lock);
213
214	link_mask = ctx->link_mask;
215
216	INIT_LIST_HEAD(&ctx->link_list);
217
218	for (i = 0; i < count; i++) {
219		if (!(link_mask & BIT(i)))
220			continue;
221
222		/*
223		 * init and add a device for each link
224		 *
225		 * The name of the device will be soundwire_intel.link.[i],
226		 * with the "soundwire_intel" module prefix automatically added
227		 * by the auxiliary bus core.
228		 */
229		ldev = intel_link_dev_register(res,
230					       ctx,
231					       acpi_fwnode_handle(adev),
232					       "link",
233					       i);
234		if (IS_ERR(ldev))
235			goto err;
236
237		link = &ldev->link_res;
238		link->cdns = auxiliary_get_drvdata(&ldev->auxdev);
239
240		if (!link->cdns) {
241			dev_err(&adev->dev, "failed to get link->cdns\n");
242			/*
243			 * 1 will be subtracted from i in the err label, but we need to call
244			 * intel_link_dev_unregister for this ldev, so plus 1 now
245			 */
246			i++;
247			goto err;
248		}
249		list_add_tail(&link->list, &ctx->link_list);
250		bus = &link->cdns->bus;
251		/* Calculate number of slaves */
252		list_for_each(node, &bus->slaves)
253			num_slaves++;
254	}
255
256	ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
257				   GFP_KERNEL);
258	if (!ctx->peripherals)
259		goto err;
260	ctx->peripherals->num_peripherals = num_slaves;
261	i = 0;
262	list_for_each_entry(link, &ctx->link_list, list) {
263		bus = &link->cdns->bus;
264		list_for_each_entry(slave, &bus->slaves, node) {
265			ctx->peripherals->array[i] = slave;
266			i++;
267		}
268	}
269
270	return ctx;
271
272err:
273	while (i--) {
274		if (!(link_mask & BIT(i)))
275			continue;
276		ldev = ctx->ldev[i];
277		intel_link_dev_unregister(ldev);
278	}
279	kfree(ctx->ldev);
280	kfree(ctx);
281	return NULL;
282}
283
284static int
285sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
286{
287	struct acpi_device *adev = acpi_fetch_acpi_dev(ctx->handle);
288	struct sdw_intel_link_dev *ldev;
289	u32 link_mask;
290	int i;
291
292	if (!adev)
293		return -EINVAL;
294
295	if (!ctx->ldev)
296		return -EINVAL;
297
298	link_mask = ctx->link_mask;
299
300	/* Startup SDW Master devices */
301	for (i = 0; i < ctx->count; i++) {
302		if (!(link_mask & BIT(i)))
303			continue;
304
305		ldev = ctx->ldev[i];
306
307		intel_link_startup(&ldev->auxdev);
308
309		if (!ldev->link_res.clock_stop_quirks) {
310			/*
311			 * we need to prevent the parent PCI device
312			 * from entering pm_runtime suspend, so that
313			 * power rails to the SoundWire IP are not
314			 * turned off.
315			 */
316			pm_runtime_get_noresume(ldev->link_res.dev);
317		}
318	}
319
320	return 0;
321}
322
323/**
324 * sdw_intel_probe() - SoundWire Intel probe routine
325 * @res: resource data
326 *
327 * This registers an auxiliary device for each Master handled by the controller,
328 * and SoundWire Master and Slave devices will be created by the auxiliary
329 * device probe. All the information necessary is stored in the context, and
330 * the res argument pointer can be freed after this step.
331 * This function will be called after sdw_intel_acpi_scan() by SOF probe.
332 */
333struct sdw_intel_ctx
334*sdw_intel_probe(struct sdw_intel_res *res)
335{
336	return sdw_intel_probe_controller(res);
337}
338EXPORT_SYMBOL_NS(sdw_intel_probe, "SOUNDWIRE_INTEL_INIT");
339
340/**
341 * sdw_intel_startup() - SoundWire Intel startup
342 * @ctx: SoundWire context allocated in the probe
343 *
344 * Startup Intel SoundWire controller. This function will be called after
345 * Intel Audio DSP is powered up.
346 */
347int sdw_intel_startup(struct sdw_intel_ctx *ctx)
348{
349	return sdw_intel_startup_controller(ctx);
350}
351EXPORT_SYMBOL_NS(sdw_intel_startup, "SOUNDWIRE_INTEL_INIT");
352/**
353 * sdw_intel_exit() - SoundWire Intel exit
354 * @ctx: SoundWire context allocated in the probe
355 *
356 * Delete the controller instances created and cleanup
357 */
358void sdw_intel_exit(struct sdw_intel_ctx *ctx)
359{
360	struct sdw_intel_link_res *link;
361
362	/* we first resume links and devices and wait synchronously before the cleanup */
363	list_for_each_entry(link, &ctx->link_list, list) {
364		struct sdw_bus *bus = &link->cdns->bus;
365		int ret;
366
367		ret = device_for_each_child(bus->dev, NULL, intel_resume_child_device);
368		if (ret < 0)
369			dev_err(bus->dev, "%s: intel_resume_child_device failed: %d\n",
370				__func__, ret);
371	}
372
373	sdw_intel_cleanup(ctx);
374	kfree(ctx->peripherals);
375	kfree(ctx->ldev);
376	kfree(ctx);
377}
378EXPORT_SYMBOL_NS(sdw_intel_exit, "SOUNDWIRE_INTEL_INIT");
379
380void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx)
381{
382	struct sdw_intel_link_dev *ldev;
383	u32 link_mask;
384	int i;
385
386	if (!ctx->ldev)
387		return;
388
389	link_mask = ctx->link_mask;
390
391	/* Startup SDW Master devices */
392	for (i = 0; i < ctx->count; i++) {
393		if (!(link_mask & BIT(i)))
394			continue;
395
396		ldev = ctx->ldev[i];
397
398		intel_link_process_wakeen_event(&ldev->auxdev);
399	}
400}
401EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, "SOUNDWIRE_INTEL_INIT");
402
403MODULE_LICENSE("Dual BSD/GPL");
404MODULE_DESCRIPTION("Intel Soundwire Init Library");
~/ Read-only file preview.