Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soundwire: amd: refactor amd soundwire manager device node creation

Refactor amd SoundWire manager device node creation logic and implement
generic functions to have a common functionality for SoundWire manager
platform device creation, start and exit sequence for both legacy(NO DSP)
and SOF stack for AMD platforms. These functions will be invoked from
legacy and SOF stack.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Acked-by: Vinod Koul <vkoul@kernel.org>
Link: https://msgid.link/r/20240129055147.1493853-4-Vijendar.Mukunda@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Vijendar Mukunda and committed by
Mark Brown
ed5e8741 a4774642

+220 -16
+1 -1
drivers/soundwire/Makefile
··· 20 20 endif 21 21 22 22 #AMD driver 23 - soundwire-amd-y := amd_manager.o 23 + soundwire-amd-y := amd_init.o amd_manager.o 24 24 obj-$(CONFIG_SOUNDWIRE_AMD) += soundwire-amd.o 25 25 26 26 #Cadence Objs
+147
drivers/soundwire/amd_init.c
··· 1 + // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 + /* 3 + * SoundWire AMD Manager Initialize routines 4 + * 5 + * Initializes and creates SDW devices based on ACPI and Hardware values 6 + * 7 + * Copyright 2024 Advanced Micro Devices, Inc. 8 + */ 9 + 10 + #include <linux/acpi.h> 11 + #include <linux/export.h> 12 + #include <linux/io.h> 13 + #include <linux/module.h> 14 + #include <linux/platform_device.h> 15 + 16 + #include "amd_init.h" 17 + 18 + static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx) 19 + { 20 + int i; 21 + 22 + for (i = 0; i < ctx->count; i++) { 23 + if (!(ctx->link_mask & BIT(i))) 24 + continue; 25 + platform_device_unregister(ctx->pdev[i]); 26 + } 27 + 28 + return 0; 29 + } 30 + 31 + static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) 32 + { 33 + struct sdw_amd_ctx *ctx; 34 + struct acpi_device *adev; 35 + struct resource *sdw_res; 36 + struct acp_sdw_pdata sdw_pdata[2]; 37 + struct platform_device_info pdevinfo[2]; 38 + u32 link_mask; 39 + int count, index; 40 + 41 + if (!res) 42 + return NULL; 43 + 44 + adev = acpi_fetch_acpi_dev(res->handle); 45 + if (!adev) 46 + return NULL; 47 + 48 + if (!res->count) 49 + return NULL; 50 + 51 + count = res->count; 52 + dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count); 53 + 54 + /* 55 + * we need to alloc/free memory manually and can't use devm: 56 + * this routine may be called from a workqueue, and not from 57 + * the parent .probe. 58 + * If devm_ was used, the memory might never be freed on errors. 59 + */ 60 + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 61 + if (!ctx) 62 + return NULL; 63 + 64 + ctx->count = count; 65 + ctx->link_mask = res->link_mask; 66 + sdw_res = kzalloc(sizeof(*sdw_res), GFP_KERNEL); 67 + if (!sdw_res) { 68 + kfree(ctx); 69 + return NULL; 70 + } 71 + sdw_res->flags = IORESOURCE_MEM; 72 + sdw_res->start = res->addr; 73 + sdw_res->end = res->addr + res->reg_range; 74 + memset(&pdevinfo, 0, sizeof(pdevinfo)); 75 + link_mask = ctx->link_mask; 76 + for (index = 0; index < count; index++) { 77 + if (!(link_mask & BIT(index))) 78 + continue; 79 + 80 + sdw_pdata[index].instance = index; 81 + sdw_pdata[index].acp_sdw_lock = res->acp_lock; 82 + pdevinfo[index].name = "amd_sdw_manager"; 83 + pdevinfo[index].id = index; 84 + pdevinfo[index].parent = res->parent; 85 + pdevinfo[index].num_res = 1; 86 + pdevinfo[index].res = sdw_res; 87 + pdevinfo[index].data = &sdw_pdata[index]; 88 + pdevinfo[index].size_data = sizeof(struct acp_sdw_pdata); 89 + pdevinfo[index].fwnode = acpi_fwnode_handle(adev); 90 + ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]); 91 + if (IS_ERR(ctx->pdev[index])) 92 + goto err; 93 + } 94 + kfree(sdw_res); 95 + return ctx; 96 + err: 97 + while (index--) { 98 + if (!(link_mask & BIT(index))) 99 + continue; 100 + 101 + platform_device_unregister(ctx->pdev[index]); 102 + } 103 + 104 + kfree(sdw_res); 105 + kfree(ctx); 106 + return NULL; 107 + } 108 + 109 + static int sdw_amd_startup(struct sdw_amd_ctx *ctx) 110 + { 111 + struct amd_sdw_manager *amd_manager; 112 + int i, ret; 113 + 114 + /* Startup SDW Manager devices */ 115 + for (i = 0; i < ctx->count; i++) { 116 + if (!(ctx->link_mask & BIT(i))) 117 + continue; 118 + amd_manager = dev_get_drvdata(&ctx->pdev[i]->dev); 119 + ret = amd_sdw_manager_start(amd_manager); 120 + if (ret) 121 + return ret; 122 + } 123 + 124 + return 0; 125 + } 126 + 127 + int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx) 128 + { 129 + *sdw_ctx = sdw_amd_probe_controller(res); 130 + if (!*sdw_ctx) 131 + return -ENODEV; 132 + 133 + return sdw_amd_startup(*sdw_ctx); 134 + } 135 + EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT); 136 + 137 + void sdw_amd_exit(struct sdw_amd_ctx *ctx) 138 + { 139 + sdw_amd_cleanup(ctx); 140 + kfree(ctx->ids); 141 + kfree(ctx); 142 + } 143 + EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT); 144 + 145 + MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); 146 + MODULE_DESCRIPTION("AMD SoundWire Init Library"); 147 + MODULE_LICENSE("Dual BSD/GPL");
+13
drivers/soundwire/amd_init.h
··· 1 + /* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ 2 + /* 3 + * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. 4 + */ 5 + 6 + #ifndef __AMD_INIT_H 7 + #define __AMD_INIT_H 8 + 9 + #include <linux/soundwire/sdw_amd.h> 10 + 11 + int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager); 12 + 13 + #endif
+6 -12
drivers/soundwire/amd_manager.c
··· 2 2 /* 3 3 * SoundWire AMD Manager driver 4 4 * 5 - * Copyright 2023 Advanced Micro Devices, Inc. 5 + * Copyright 2023-24 Advanced Micro Devices, Inc. 6 6 */ 7 7 8 8 #include <linux/completion.h> ··· 19 19 #include <sound/pcm_params.h> 20 20 #include <sound/soc.h> 21 21 #include "bus.h" 22 + #include "amd_init.h" 22 23 #include "amd_manager.h" 23 24 24 25 #define DRV_NAME "amd_sdw_manager" ··· 865 864 writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7); 866 865 } 867 866 868 - static void amd_sdw_probe_work(struct work_struct *work) 867 + int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager) 869 868 { 870 - struct amd_sdw_manager *amd_manager = container_of(work, struct amd_sdw_manager, 871 - probe_work); 872 869 struct sdw_master_prop *prop; 873 870 int ret; 874 871 ··· 875 876 amd_enable_sdw_pads(amd_manager); 876 877 ret = amd_init_sdw_manager(amd_manager); 877 878 if (ret) 878 - return; 879 + return ret; 879 880 amd_enable_sdw_interrupts(amd_manager); 880 881 ret = amd_enable_sdw_manager(amd_manager); 881 882 if (ret) 882 - return; 883 + return ret; 883 884 amd_sdw_set_frameshape(amd_manager); 884 885 } 885 886 /* Enable runtime PM */ ··· 888 889 pm_runtime_mark_last_busy(amd_manager->dev); 889 890 pm_runtime_set_active(amd_manager->dev); 890 891 pm_runtime_enable(amd_manager->dev); 892 + return 0; 891 893 } 892 894 893 895 static int amd_sdw_manager_probe(struct platform_device *pdev) ··· 972 972 dev_set_drvdata(dev, amd_manager); 973 973 INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_irq_thread); 974 974 INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work); 975 - INIT_WORK(&amd_manager->probe_work, amd_sdw_probe_work); 976 - /* 977 - * Instead of having lengthy probe sequence, use deferred probe. 978 - */ 979 - schedule_work(&amd_manager->probe_work); 980 975 return 0; 981 976 } 982 977 ··· 981 986 int ret; 982 987 983 988 pm_runtime_disable(&pdev->dev); 984 - cancel_work_sync(&amd_manager->probe_work); 985 989 amd_disable_sdw_interrupts(amd_manager); 986 990 sdw_bus_master_delete(&amd_manager->bus); 987 991 ret = amd_disable_sdw_manager(amd_manager);
+53 -3
include/linux/soundwire/sdw_amd.h
··· 1 1 /* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ 2 2 /* 3 - * Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved. 3 + * Copyright (C) 2023-24 Advanced Micro Devices, Inc. All rights reserved. 4 4 */ 5 5 6 6 #ifndef __SDW_AMD_H ··· 26 26 #define AMD_SDW_POWER_OFF_MODE 2 27 27 #define ACP_SDW0 0 28 28 #define ACP_SDW1 1 29 + #define AMD_SDW_MAX_MANAGER_COUNT 2 29 30 30 31 struct acp_sdw_pdata { 31 32 u16 instance; ··· 64 63 * @reg_mask: register mask structure per manager instance 65 64 * @amd_sdw_irq_thread: SoundWire manager irq workqueue 66 65 * @amd_sdw_work: peripheral status work queue 67 - * @probe_work: SoundWire manager probe workqueue 68 66 * @acp_sdw_lock: mutex to protect acp share register access 69 67 * @status: peripheral devices status array 70 68 * @num_din_ports: number of input ports ··· 87 87 struct sdw_manager_reg_mask *reg_mask; 88 88 struct work_struct amd_sdw_irq_thread; 89 89 struct work_struct amd_sdw_work; 90 - struct work_struct probe_work; 91 90 /* mutex to protect acp common register access */ 92 91 struct mutex *acp_sdw_lock; 93 92 ··· 118 119 int count; 119 120 u32 link_mask; 120 121 }; 122 + 123 + /** 124 + * struct sdw_amd_ctx - context allocated by the controller driver probe 125 + * 126 + * @count: link count 127 + * @num_slaves: total number of devices exposed across all enabled links 128 + * @link_mask: bit-wise mask listing SoundWire links reported by the 129 + * Controller 130 + * @ids: array of slave_id, representing Slaves exposed across all enabled 131 + * links 132 + * @pdev: platform device structure 133 + */ 134 + struct sdw_amd_ctx { 135 + int count; 136 + int num_slaves; 137 + u32 link_mask; 138 + struct sdw_extended_slave_id *ids; 139 + struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT]; 140 + }; 141 + 142 + /** 143 + * struct sdw_amd_res - Soundwire AMD global resource structure, 144 + * typically populated by the DSP driver/Legacy driver 145 + * 146 + * @addr: acp pci device resource start address 147 + * @reg_range: ACP register range 148 + * @link_mask: bit-wise mask listing links selected by the DSP driver/ 149 + * legacy driver 150 + * @count: link count 151 + * @mmio_base: mmio base of SoundWire registers 152 + * @handle: ACPI parent handle 153 + * @parent: parent device 154 + * @dev: device implementing hwparams and free callbacks 155 + * @acp_lock: mutex protecting acp common registers access 156 + */ 157 + struct sdw_amd_res { 158 + u32 addr; 159 + u32 reg_range; 160 + u32 link_mask; 161 + int count; 162 + void __iomem *mmio_base; 163 + acpi_handle handle; 164 + struct device *parent; 165 + struct device *dev; 166 + /* use to protect acp common registers access */ 167 + struct mutex *acp_lock; 168 + }; 169 + 170 + int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **ctx); 171 + 172 + void sdw_amd_exit(struct sdw_amd_ctx *ctx); 121 173 122 174 int amd_sdw_scan_controller(struct sdw_amd_acpi_info *info); 123 175 #endif