xref: /linux/drivers/soundwire/intel_init.c (revision ebf878eddbb449091078d2ed282aed42a4fcef34)
1d62a7d41SVinod Koul // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2d62a7d41SVinod Koul // Copyright(c) 2015-17 Intel Corporation.
3d62a7d41SVinod Koul 
4d62a7d41SVinod Koul /*
5d62a7d41SVinod Koul  * SDW Intel Init Routines
6d62a7d41SVinod Koul  *
7d62a7d41SVinod Koul  * Initializes and creates SDW devices based on ACPI and Hardware values
8d62a7d41SVinod Koul  */
9d62a7d41SVinod Koul 
10d62a7d41SVinod Koul #include <linux/acpi.h>
114abbd783SPaul Gortmaker #include <linux/export.h>
124a98a6b2SBard Liao #include <linux/interrupt.h>
133fc40449SVinod Koul #include <linux/io.h>
144abbd783SPaul Gortmaker #include <linux/module.h>
15d62a7d41SVinod Koul #include <linux/platform_device.h>
16*ebf878edSPierre-Louis Bossart #include <linux/pm_runtime.h>
17d62a7d41SVinod Koul #include <linux/soundwire/sdw_intel.h>
18b6109dd6SPierre-Louis Bossart #include "cadence_master.h"
19d62a7d41SVinod Koul #include "intel.h"
20d62a7d41SVinod Koul 
216f11586fSPierre-Louis Bossart #define SDW_LINK_TYPE		4 /* from Intel ACPI documentation */
22d62a7d41SVinod Koul #define SDW_MAX_LINKS		4
23d62a7d41SVinod Koul #define SDW_SHIM_LCAP		0x0
24d62a7d41SVinod Koul #define SDW_SHIM_BASE		0x2C000
25d62a7d41SVinod Koul #define SDW_ALH_BASE		0x2C800
26d62a7d41SVinod Koul #define SDW_LINK_BASE		0x30000
27d62a7d41SVinod Koul #define SDW_LINK_SIZE		0x10000
28d62a7d41SVinod Koul 
296d2c6669SPierre-Louis Bossart static int ctrl_link_mask;
306d2c6669SPierre-Louis Bossart module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444);
3150302fc7SPierre-Louis Bossart MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
3250302fc7SPierre-Louis Bossart 
336d2c6669SPierre-Louis Bossart static bool is_link_enabled(struct fwnode_handle *fw_node, int i)
346d2c6669SPierre-Louis Bossart {
356d2c6669SPierre-Louis Bossart 	struct fwnode_handle *link;
366d2c6669SPierre-Louis Bossart 	char name[32];
376d2c6669SPierre-Louis Bossart 	u32 quirk_mask = 0;
386d2c6669SPierre-Louis Bossart 
396d2c6669SPierre-Louis Bossart 	/* Find master handle */
406d2c6669SPierre-Louis Bossart 	snprintf(name, sizeof(name),
416d2c6669SPierre-Louis Bossart 		 "mipi-sdw-link-%d-subproperties", i);
426d2c6669SPierre-Louis Bossart 
436d2c6669SPierre-Louis Bossart 	link = fwnode_get_named_child_node(fw_node, name);
446d2c6669SPierre-Louis Bossart 	if (!link)
456d2c6669SPierre-Louis Bossart 		return false;
466d2c6669SPierre-Louis Bossart 
476d2c6669SPierre-Louis Bossart 	fwnode_property_read_u32(link,
486d2c6669SPierre-Louis Bossart 				 "intel-quirk-mask",
496d2c6669SPierre-Louis Bossart 				 &quirk_mask);
506d2c6669SPierre-Louis Bossart 
516d2c6669SPierre-Louis Bossart 	if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
526d2c6669SPierre-Louis Bossart 		return false;
536d2c6669SPierre-Louis Bossart 
546d2c6669SPierre-Louis Bossart 	return true;
556d2c6669SPierre-Louis Bossart }
566d2c6669SPierre-Louis Bossart 
576d2c6669SPierre-Louis Bossart static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx)
58d62a7d41SVinod Koul {
59f98f690fSPierre-Louis Bossart 	struct sdw_intel_link_res *link = ctx->links;
606d2c6669SPierre-Louis Bossart 	u32 link_mask;
61d62a7d41SVinod Koul 	int i;
62d62a7d41SVinod Koul 
63d62a7d41SVinod Koul 	if (!link)
64d62a7d41SVinod Koul 		return 0;
65d62a7d41SVinod Koul 
666d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
676d2c6669SPierre-Louis Bossart 
686d2c6669SPierre-Louis Bossart 	for (i = 0; i < ctx->count; i++, link++) {
696d2c6669SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
706d2c6669SPierre-Louis Bossart 			continue;
716d2c6669SPierre-Louis Bossart 
72*ebf878edSPierre-Louis Bossart 		if (link->pdev) {
73*ebf878edSPierre-Louis Bossart 			pm_runtime_disable(&link->pdev->dev);
74d62a7d41SVinod Koul 			platform_device_unregister(link->pdev);
75d62a7d41SVinod Koul 		}
76*ebf878edSPierre-Louis Bossart 	}
77d62a7d41SVinod Koul 
78d62a7d41SVinod Koul 	return 0;
79d62a7d41SVinod Koul }
80d62a7d41SVinod Koul 
816d2c6669SPierre-Louis Bossart static int
826d2c6669SPierre-Louis Bossart sdw_intel_scan_controller(struct sdw_intel_acpi_info *info)
83d62a7d41SVinod Koul {
84d62a7d41SVinod Koul 	struct acpi_device *adev;
85d62a7d41SVinod Koul 	int ret, i;
86d62a7d41SVinod Koul 	u8 count;
87d62a7d41SVinod Koul 
886d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(info->handle, &adev))
896d2c6669SPierre-Louis Bossart 		return -EINVAL;
90d62a7d41SVinod Koul 
91d62a7d41SVinod Koul 	/* Found controller, find links supported */
92d62a7d41SVinod Koul 	count = 0;
93d62a7d41SVinod Koul 	ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev),
94d62a7d41SVinod Koul 					    "mipi-sdw-master-count", &count, 1);
95d62a7d41SVinod Koul 
966d2c6669SPierre-Louis Bossart 	/*
976d2c6669SPierre-Louis Bossart 	 * In theory we could check the number of links supported in
986d2c6669SPierre-Louis Bossart 	 * hardware, but in that step we cannot assume SoundWire IP is
996d2c6669SPierre-Louis Bossart 	 * powered.
1006d2c6669SPierre-Louis Bossart 	 *
1016d2c6669SPierre-Louis Bossart 	 * In addition, if the BIOS doesn't even provide this
1026d2c6669SPierre-Louis Bossart 	 * 'master-count' property then all the inits based on link
1036d2c6669SPierre-Louis Bossart 	 * masks will fail as well.
1046d2c6669SPierre-Louis Bossart 	 *
1056d2c6669SPierre-Louis Bossart 	 * We will check the hardware capabilities in the startup() step
1066d2c6669SPierre-Louis Bossart 	 */
1076d2c6669SPierre-Louis Bossart 
108d62a7d41SVinod Koul 	if (ret) {
109d62a7d41SVinod Koul 		dev_err(&adev->dev,
110d62a7d41SVinod Koul 			"Failed to read mipi-sdw-master-count: %d\n", ret);
1116d2c6669SPierre-Louis Bossart 		return -EINVAL;
112d62a7d41SVinod Koul 	}
113d62a7d41SVinod Koul 
114d62a7d41SVinod Koul 	/* Check count is within bounds */
115d62a7d41SVinod Koul 	if (count > SDW_MAX_LINKS) {
116d62a7d41SVinod Koul 		dev_err(&adev->dev, "Link count %d exceeds max %d\n",
117d62a7d41SVinod Koul 			count, SDW_MAX_LINKS);
1186d2c6669SPierre-Louis Bossart 		return -EINVAL;
1196f7219feSGuennadi Liakhovetski 	}
1206f7219feSGuennadi Liakhovetski 
1216f7219feSGuennadi Liakhovetski 	if (!count) {
122432732b8SPierre-Louis Bossart 		dev_warn(&adev->dev, "No SoundWire links detected\n");
1236d2c6669SPierre-Louis Bossart 		return -EINVAL;
1246d2c6669SPierre-Louis Bossart 	}
1256d2c6669SPierre-Louis Bossart 	dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count);
1266d2c6669SPierre-Louis Bossart 
1276d2c6669SPierre-Louis Bossart 	info->count = count;
1286d2c6669SPierre-Louis Bossart 	info->link_mask = 0;
1296d2c6669SPierre-Louis Bossart 
1306d2c6669SPierre-Louis Bossart 	for (i = 0; i < count; i++) {
1316d2c6669SPierre-Louis Bossart 		if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) {
1326d2c6669SPierre-Louis Bossart 			dev_dbg(&adev->dev,
1336d2c6669SPierre-Louis Bossart 				"Link %d masked, will not be enabled\n", i);
1346d2c6669SPierre-Louis Bossart 			continue;
135d62a7d41SVinod Koul 		}
136d62a7d41SVinod Koul 
1376d2c6669SPierre-Louis Bossart 		if (!is_link_enabled(acpi_fwnode_handle(adev), i)) {
1386d2c6669SPierre-Louis Bossart 			dev_dbg(&adev->dev,
1396d2c6669SPierre-Louis Bossart 				"Link %d not selected in firmware\n", i);
1406d2c6669SPierre-Louis Bossart 			continue;
1416d2c6669SPierre-Louis Bossart 		}
1426d2c6669SPierre-Louis Bossart 
1436d2c6669SPierre-Louis Bossart 		info->link_mask |= BIT(i);
1446d2c6669SPierre-Louis Bossart 	}
1456d2c6669SPierre-Louis Bossart 
1466d2c6669SPierre-Louis Bossart 	return 0;
1476d2c6669SPierre-Louis Bossart }
1486d2c6669SPierre-Louis Bossart 
14912b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIC2             (0x10)
15012b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIS2             (0x14)
15112b16146SPierre-Louis Bossart #define HDA_DSP_REG_ADSPIC2_SNDW        BIT(5)
15212b16146SPierre-Louis Bossart 
15312b16146SPierre-Louis Bossart /**
15412b16146SPierre-Louis Bossart  * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ
15512b16146SPierre-Louis Bossart  * @mmio_base: The mmio base of the control register
15612b16146SPierre-Louis Bossart  * @enable: true if enable
15712b16146SPierre-Louis Bossart  */
15812b16146SPierre-Louis Bossart void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable)
15912b16146SPierre-Louis Bossart {
16012b16146SPierre-Louis Bossart 	u32 val;
16112b16146SPierre-Louis Bossart 
16212b16146SPierre-Louis Bossart 	val = readl(mmio_base + HDA_DSP_REG_ADSPIC2);
16312b16146SPierre-Louis Bossart 
16412b16146SPierre-Louis Bossart 	if (enable)
16512b16146SPierre-Louis Bossart 		val |= HDA_DSP_REG_ADSPIC2_SNDW;
16612b16146SPierre-Louis Bossart 	else
16712b16146SPierre-Louis Bossart 		val &= ~HDA_DSP_REG_ADSPIC2_SNDW;
16812b16146SPierre-Louis Bossart 
16912b16146SPierre-Louis Bossart 	writel(val, mmio_base + HDA_DSP_REG_ADSPIC2);
17012b16146SPierre-Louis Bossart }
1718459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT);
17212b16146SPierre-Louis Bossart 
1734a98a6b2SBard Liao irqreturn_t sdw_intel_thread(int irq, void *dev_id)
1744a98a6b2SBard Liao {
1754a98a6b2SBard Liao 	struct sdw_intel_ctx *ctx = dev_id;
1764a98a6b2SBard Liao 	struct sdw_intel_link_res *link;
1774a98a6b2SBard Liao 
1784a98a6b2SBard Liao 	list_for_each_entry(link, &ctx->link_list, list)
1794a98a6b2SBard Liao 		sdw_cdns_irq(irq, link->cdns);
1804a98a6b2SBard Liao 
1814a98a6b2SBard Liao 	sdw_intel_enable_irq(ctx->mmio_base, true);
1824a98a6b2SBard Liao 	return IRQ_HANDLED;
1834a98a6b2SBard Liao }
1844a98a6b2SBard Liao EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT);
1854a98a6b2SBard Liao 
1866d2c6669SPierre-Louis Bossart static struct sdw_intel_ctx
1876d2c6669SPierre-Louis Bossart *sdw_intel_probe_controller(struct sdw_intel_res *res)
1886d2c6669SPierre-Louis Bossart {
1896d2c6669SPierre-Louis Bossart 	struct platform_device_info pdevinfo;
1906d2c6669SPierre-Louis Bossart 	struct platform_device *pdev;
1916d2c6669SPierre-Louis Bossart 	struct sdw_intel_link_res *link;
1926d2c6669SPierre-Louis Bossart 	struct sdw_intel_ctx *ctx;
1936d2c6669SPierre-Louis Bossart 	struct acpi_device *adev;
194a8184403SBard Liao 	struct sdw_slave *slave;
195a8184403SBard Liao 	struct list_head *node;
196a8184403SBard Liao 	struct sdw_bus *bus;
1976d2c6669SPierre-Louis Bossart 	u32 link_mask;
198a8184403SBard Liao 	int num_slaves = 0;
1996d2c6669SPierre-Louis Bossart 	int count;
2006d2c6669SPierre-Louis Bossart 	int i;
2016d2c6669SPierre-Louis Bossart 
2026d2c6669SPierre-Louis Bossart 	if (!res)
2036d2c6669SPierre-Louis Bossart 		return NULL;
2046d2c6669SPierre-Louis Bossart 
2056d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(res->handle, &adev))
2066d2c6669SPierre-Louis Bossart 		return NULL;
2076d2c6669SPierre-Louis Bossart 
2086d2c6669SPierre-Louis Bossart 	if (!res->count)
2096d2c6669SPierre-Louis Bossart 		return NULL;
2106d2c6669SPierre-Louis Bossart 
2116d2c6669SPierre-Louis Bossart 	count = res->count;
212d62a7d41SVinod Koul 	dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
213d62a7d41SVinod Koul 
214dd906cc6SPierre-Louis Bossart 	ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL);
215d62a7d41SVinod Koul 	if (!ctx)
216d62a7d41SVinod Koul 		return NULL;
217d62a7d41SVinod Koul 
218d62a7d41SVinod Koul 	ctx->count = count;
219dd906cc6SPierre-Louis Bossart 	ctx->links = devm_kcalloc(&adev->dev, ctx->count,
220dd906cc6SPierre-Louis Bossart 				  sizeof(*ctx->links), GFP_KERNEL);
221d62a7d41SVinod Koul 	if (!ctx->links)
222dd906cc6SPierre-Louis Bossart 		return NULL;
223d62a7d41SVinod Koul 
2246d2c6669SPierre-Louis Bossart 	ctx->count = count;
2256d2c6669SPierre-Louis Bossart 	ctx->mmio_base = res->mmio_base;
2266d2c6669SPierre-Louis Bossart 	ctx->link_mask = res->link_mask;
2276d2c6669SPierre-Louis Bossart 	ctx->handle = res->handle;
2284a17c441SPierre-Louis Bossart 	mutex_init(&ctx->shim_lock);
2296d2c6669SPierre-Louis Bossart 
230d62a7d41SVinod Koul 	link = ctx->links;
2316d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
232d62a7d41SVinod Koul 
2334a98a6b2SBard Liao 	INIT_LIST_HEAD(&ctx->link_list);
2344a98a6b2SBard Liao 
235d62a7d41SVinod Koul 	/* Create SDW Master devices */
2366d2c6669SPierre-Louis Bossart 	for (i = 0; i < count; i++, link++) {
2379cd1c5a7SPierre-Louis Bossart 		if (!(link_mask & BIT(i))) {
23850302fc7SPierre-Louis Bossart 			dev_dbg(&adev->dev,
23950302fc7SPierre-Louis Bossart 				"Link %d masked, will not be enabled\n", i);
24050302fc7SPierre-Louis Bossart 			continue;
24150302fc7SPierre-Louis Bossart 		}
24250302fc7SPierre-Louis Bossart 
2436d2c6669SPierre-Louis Bossart 		link->mmio_base = res->mmio_base;
244f98f690fSPierre-Louis Bossart 		link->registers = res->mmio_base + SDW_LINK_BASE
245d62a7d41SVinod Koul 			+ (SDW_LINK_SIZE * i);
246f98f690fSPierre-Louis Bossart 		link->shim = res->mmio_base + SDW_SHIM_BASE;
247f98f690fSPierre-Louis Bossart 		link->alh = res->mmio_base + SDW_ALH_BASE;
248d62a7d41SVinod Koul 
249f98f690fSPierre-Louis Bossart 		link->ops = res->ops;
2504b206d34SRander Wang 		link->dev = res->dev;
251c46302ecSVinod Koul 
2524a17c441SPierre-Louis Bossart 		link->shim_lock = &ctx->shim_lock;
2534a17c441SPierre-Louis Bossart 		link->shim_mask = &ctx->shim_mask;
2544a17c441SPierre-Louis Bossart 
255d62a7d41SVinod Koul 		memset(&pdevinfo, 0, sizeof(pdevinfo));
256d62a7d41SVinod Koul 
257d62a7d41SVinod Koul 		pdevinfo.parent = res->parent;
2586d2c6669SPierre-Louis Bossart 		pdevinfo.name = "intel-sdw";
259d62a7d41SVinod Koul 		pdevinfo.id = i;
260d62a7d41SVinod Koul 		pdevinfo.fwnode = acpi_fwnode_handle(adev);
2614ab34412SPierre-Louis Bossart 		pdevinfo.data = link;
2624ab34412SPierre-Louis Bossart 		pdevinfo.size_data = sizeof(*link);
263d62a7d41SVinod Koul 
264d62a7d41SVinod Koul 		pdev = platform_device_register_full(&pdevinfo);
265d62a7d41SVinod Koul 		if (IS_ERR(pdev)) {
266d62a7d41SVinod Koul 			dev_err(&adev->dev,
267d62a7d41SVinod Koul 				"platform device creation failed: %ld\n",
268d62a7d41SVinod Koul 				PTR_ERR(pdev));
2696d2c6669SPierre-Louis Bossart 			goto err;
270d62a7d41SVinod Koul 		}
271d62a7d41SVinod Koul 		link->pdev = pdev;
2724a98a6b2SBard Liao 		link->cdns = platform_get_drvdata(pdev);
2734a98a6b2SBard Liao 
2744a98a6b2SBard Liao 		list_add_tail(&link->list, &ctx->link_list);
275a8184403SBard Liao 		bus = &link->cdns->bus;
276a8184403SBard Liao 		/* Calculate number of slaves */
277a8184403SBard Liao 		list_for_each(node, &bus->slaves)
278a8184403SBard Liao 			num_slaves++;
279a8184403SBard Liao 	}
280a8184403SBard Liao 
281a8184403SBard Liao 	ctx->ids = devm_kcalloc(&adev->dev, num_slaves,
282a8184403SBard Liao 				sizeof(*ctx->ids), GFP_KERNEL);
283a8184403SBard Liao 	if (!ctx->ids)
284a8184403SBard Liao 		goto err;
285a8184403SBard Liao 
286a8184403SBard Liao 	ctx->num_slaves = num_slaves;
287a8184403SBard Liao 	i = 0;
288a8184403SBard Liao 	list_for_each_entry(link, &ctx->link_list, list) {
289a8184403SBard Liao 		bus = &link->cdns->bus;
290a8184403SBard Liao 		list_for_each_entry(slave, &bus->slaves, node) {
291a8184403SBard Liao 			ctx->ids[i].id = slave->id;
292a8184403SBard Liao 			ctx->ids[i].link_id = bus->link_id;
293a8184403SBard Liao 			i++;
294a8184403SBard Liao 		}
295d62a7d41SVinod Koul 	}
296d62a7d41SVinod Koul 
297d62a7d41SVinod Koul 	return ctx;
298d62a7d41SVinod Koul 
2996d2c6669SPierre-Louis Bossart err:
300dd906cc6SPierre-Louis Bossart 	ctx->count = i;
3016d2c6669SPierre-Louis Bossart 	sdw_intel_cleanup(ctx);
302d62a7d41SVinod Koul 	return NULL;
303d62a7d41SVinod Koul }
304d62a7d41SVinod Koul 
3056d2c6669SPierre-Louis Bossart static int
3066d2c6669SPierre-Louis Bossart sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
3076d2c6669SPierre-Louis Bossart {
3086d2c6669SPierre-Louis Bossart 	struct acpi_device *adev;
3096d2c6669SPierre-Louis Bossart 	struct sdw_intel_link_res *link;
3106d2c6669SPierre-Louis Bossart 	u32 caps;
3116d2c6669SPierre-Louis Bossart 	u32 link_mask;
3126d2c6669SPierre-Louis Bossart 	int i;
3136d2c6669SPierre-Louis Bossart 
3146d2c6669SPierre-Louis Bossart 	if (acpi_bus_get_device(ctx->handle, &adev))
3156d2c6669SPierre-Louis Bossart 		return -EINVAL;
3166d2c6669SPierre-Louis Bossart 
3176d2c6669SPierre-Louis Bossart 	/* Check SNDWLCAP.LCOUNT */
3186d2c6669SPierre-Louis Bossart 	caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
3196d2c6669SPierre-Louis Bossart 	caps &= GENMASK(2, 0);
3206d2c6669SPierre-Louis Bossart 
3216d2c6669SPierre-Louis Bossart 	/* Check HW supported vs property value */
3226d2c6669SPierre-Louis Bossart 	if (caps < ctx->count) {
3236d2c6669SPierre-Louis Bossart 		dev_err(&adev->dev,
3246d2c6669SPierre-Louis Bossart 			"BIOS master count is larger than hardware capabilities\n");
3256d2c6669SPierre-Louis Bossart 		return -EINVAL;
3266d2c6669SPierre-Louis Bossart 	}
3276d2c6669SPierre-Louis Bossart 
3286d2c6669SPierre-Louis Bossart 	if (!ctx->links)
3296d2c6669SPierre-Louis Bossart 		return -EINVAL;
3306d2c6669SPierre-Louis Bossart 
3316d2c6669SPierre-Louis Bossart 	link = ctx->links;
3326d2c6669SPierre-Louis Bossart 	link_mask = ctx->link_mask;
3336d2c6669SPierre-Louis Bossart 
3346d2c6669SPierre-Louis Bossart 	/* Startup SDW Master devices */
3356d2c6669SPierre-Louis Bossart 	for (i = 0; i < ctx->count; i++, link++) {
3366d2c6669SPierre-Louis Bossart 		if (!(link_mask & BIT(i)))
3376d2c6669SPierre-Louis Bossart 			continue;
3386d2c6669SPierre-Louis Bossart 
3396d2c6669SPierre-Louis Bossart 		intel_master_startup(link->pdev);
3406d2c6669SPierre-Louis Bossart 	}
3416d2c6669SPierre-Louis Bossart 
3426d2c6669SPierre-Louis Bossart 	return 0;
3436d2c6669SPierre-Louis Bossart }
3446d2c6669SPierre-Louis Bossart 
345d62a7d41SVinod Koul static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
346d62a7d41SVinod Koul 				     void *cdata, void **return_value)
347d62a7d41SVinod Koul {
3486d2c6669SPierre-Louis Bossart 	struct sdw_intel_acpi_info *info = cdata;
349d62a7d41SVinod Koul 	struct acpi_device *adev;
3506f11586fSPierre-Louis Bossart 	acpi_status status;
3516f11586fSPierre-Louis Bossart 	u64 adr;
3526f11586fSPierre-Louis Bossart 
3536f11586fSPierre-Louis Bossart 	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
3546f11586fSPierre-Louis Bossart 	if (ACPI_FAILURE(status))
3556f11586fSPierre-Louis Bossart 		return AE_OK; /* keep going */
356d62a7d41SVinod Koul 
357d62a7d41SVinod Koul 	if (acpi_bus_get_device(handle, &adev)) {
358e1c815f4SVinod Koul 		pr_err("%s: Couldn't find ACPI handle\n", __func__);
359d62a7d41SVinod Koul 		return AE_NOT_FOUND;
360d62a7d41SVinod Koul 	}
361d62a7d41SVinod Koul 
3626d2c6669SPierre-Louis Bossart 	info->handle = handle;
3636f11586fSPierre-Louis Bossart 
3646f11586fSPierre-Louis Bossart 	/*
3656f11586fSPierre-Louis Bossart 	 * On some Intel platforms, multiple children of the HDAS
3666f11586fSPierre-Louis Bossart 	 * device can be found, but only one of them is the SoundWire
3676f11586fSPierre-Louis Bossart 	 * controller. The SNDW device is always exposed with
3686f11586fSPierre-Louis Bossart 	 * Name(_ADR, 0x40000000), with bits 31..28 representing the
3696f11586fSPierre-Louis Bossart 	 * SoundWire link so filter accordingly
3706f11586fSPierre-Louis Bossart 	 */
3716f11586fSPierre-Louis Bossart 	if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
3726f11586fSPierre-Louis Bossart 		return AE_OK; /* keep going */
3736f11586fSPierre-Louis Bossart 
3746f11586fSPierre-Louis Bossart 	/* device found, stop namespace walk */
3756f11586fSPierre-Louis Bossart 	return AE_CTRL_TERMINATE;
376d62a7d41SVinod Koul }
377d62a7d41SVinod Koul 
378d62a7d41SVinod Koul /**
3796d2c6669SPierre-Louis Bossart  * sdw_intel_acpi_scan() - SoundWire Intel init routine
380d62a7d41SVinod Koul  * @parent_handle: ACPI parent handle
3816d2c6669SPierre-Louis Bossart  * @info: description of what firmware/DSDT tables expose
382d62a7d41SVinod Koul  *
3836d2c6669SPierre-Louis Bossart  * This scans the namespace and queries firmware to figure out which
3846d2c6669SPierre-Louis Bossart  * links to enable. A follow-up use of sdw_intel_probe() and
3856d2c6669SPierre-Louis Bossart  * sdw_intel_startup() is required for creation of devices and bus
3866d2c6669SPierre-Louis Bossart  * startup
387d62a7d41SVinod Koul  */
3886d2c6669SPierre-Louis Bossart int sdw_intel_acpi_scan(acpi_handle *parent_handle,
3896d2c6669SPierre-Louis Bossart 			struct sdw_intel_acpi_info *info)
390d62a7d41SVinod Koul {
391d62a7d41SVinod Koul 	acpi_status status;
392d62a7d41SVinod Koul 
393d62a7d41SVinod Koul 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
394d62a7d41SVinod Koul 				     parent_handle, 1,
395d62a7d41SVinod Koul 				     sdw_intel_acpi_cb,
3966d2c6669SPierre-Louis Bossart 				     NULL, info, NULL);
397d62a7d41SVinod Koul 	if (ACPI_FAILURE(status))
3986d2c6669SPierre-Louis Bossart 		return -ENODEV;
399d62a7d41SVinod Koul 
4006d2c6669SPierre-Louis Bossart 	return sdw_intel_scan_controller(info);
401d62a7d41SVinod Koul }
4028459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SOUNDWIRE_INTEL_INIT);
403d62a7d41SVinod Koul 
404d62a7d41SVinod Koul /**
4056d2c6669SPierre-Louis Bossart  * sdw_intel_probe() - SoundWire Intel probe routine
4066d2c6669SPierre-Louis Bossart  * @res: resource data
4076d2c6669SPierre-Louis Bossart  *
4086d2c6669SPierre-Louis Bossart  * This registers a platform device for each Master handled by the controller,
4096d2c6669SPierre-Louis Bossart  * and SoundWire Master and Slave devices will be created by the platform
4106d2c6669SPierre-Louis Bossart  * device probe. All the information necessary is stored in the context, and
4116d2c6669SPierre-Louis Bossart  * the res argument pointer can be freed after this step.
4126d2c6669SPierre-Louis Bossart  * This function will be called after sdw_intel_acpi_scan() by SOF probe.
4136d2c6669SPierre-Louis Bossart  */
4146d2c6669SPierre-Louis Bossart struct sdw_intel_ctx
4156d2c6669SPierre-Louis Bossart *sdw_intel_probe(struct sdw_intel_res *res)
4166d2c6669SPierre-Louis Bossart {
4176d2c6669SPierre-Louis Bossart 	return sdw_intel_probe_controller(res);
4186d2c6669SPierre-Louis Bossart }
4198459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT);
4206d2c6669SPierre-Louis Bossart 
4216d2c6669SPierre-Louis Bossart /**
4226d2c6669SPierre-Louis Bossart  * sdw_intel_startup() - SoundWire Intel startup
4236d2c6669SPierre-Louis Bossart  * @ctx: SoundWire context allocated in the probe
4246d2c6669SPierre-Louis Bossart  *
4256d2c6669SPierre-Louis Bossart  * Startup Intel SoundWire controller. This function will be called after
4266d2c6669SPierre-Louis Bossart  * Intel Audio DSP is powered up.
4276d2c6669SPierre-Louis Bossart  */
4286d2c6669SPierre-Louis Bossart int sdw_intel_startup(struct sdw_intel_ctx *ctx)
4296d2c6669SPierre-Louis Bossart {
4306d2c6669SPierre-Louis Bossart 	return sdw_intel_startup_controller(ctx);
4316d2c6669SPierre-Louis Bossart }
4328459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
4336d2c6669SPierre-Louis Bossart /**
434d62a7d41SVinod Koul  * sdw_intel_exit() - SoundWire Intel exit
4356d2c6669SPierre-Louis Bossart  * @ctx: SoundWire context allocated in the probe
436d62a7d41SVinod Koul  *
437d62a7d41SVinod Koul  * Delete the controller instances created and cleanup
438d62a7d41SVinod Koul  */
439f98f690fSPierre-Louis Bossart void sdw_intel_exit(struct sdw_intel_ctx *ctx)
440d62a7d41SVinod Koul {
4416d2c6669SPierre-Louis Bossart 	sdw_intel_cleanup(ctx);
442d62a7d41SVinod Koul }
4438459cea7SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT);
444d62a7d41SVinod Koul 
445ab2c9132SRander Wang void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx)
446ab2c9132SRander Wang {
447ab2c9132SRander Wang 	struct sdw_intel_link_res *link;
448ab2c9132SRander Wang 	u32 link_mask;
449ab2c9132SRander Wang 	int i;
450ab2c9132SRander Wang 
451ab2c9132SRander Wang 	if (!ctx->links)
452ab2c9132SRander Wang 		return;
453ab2c9132SRander Wang 
454ab2c9132SRander Wang 	link = ctx->links;
455ab2c9132SRander Wang 	link_mask = ctx->link_mask;
456ab2c9132SRander Wang 
457ab2c9132SRander Wang 	/* Startup SDW Master devices */
458ab2c9132SRander Wang 	for (i = 0; i < ctx->count; i++, link++) {
459ab2c9132SRander Wang 		if (!(link_mask & BIT(i)))
460ab2c9132SRander Wang 			continue;
461ab2c9132SRander Wang 
462ab2c9132SRander Wang 		intel_master_process_wakeen_event(link->pdev);
463ab2c9132SRander Wang 	}
464ab2c9132SRander Wang }
465ab2c9132SRander Wang EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT);
466ab2c9132SRander Wang 
467d62a7d41SVinod Koul MODULE_LICENSE("Dual BSD/GPL");
468d62a7d41SVinod Koul MODULE_DESCRIPTION("Intel Soundwire Init Library");
469