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