1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
3 * SoundWire AMD Manager Initialize routines
5 * Initializes and creates SDW devices based on ACPI and Hardware values
7 * Copyright 2024 Advanced Micro Devices, Inc.
10 #include <linux/acpi.h>
11 #include <linux/export.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
18 #define ACP_PAD_PULLDOWN_CTRL 0x0001448
19 #define ACP_SW_PAD_KEEPER_EN 0x0001454
20 #define AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9a
21 #define AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9f
22 #define AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7ffa
23 #define AMD_SDW0_PAD_EN_MASK 1
24 #define AMD_SDW1_PAD_EN_MASK 0x10
25 #define AMD_SDW_PAD_EN_MASK (AMD_SDW0_PAD_EN_MASK | AMD_SDW1_PAD_EN_MASK)
27 static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev)
30 u32 pad_keeper_en_mask, pad_pulldown_ctrl_mask;
34 pad_keeper_en_mask = AMD_SDW0_PAD_EN_MASK;
35 pad_pulldown_ctrl_mask = AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK;
38 pad_keeper_en_mask = AMD_SDW1_PAD_EN_MASK;
39 pad_pulldown_ctrl_mask = AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK;
42 pad_keeper_en_mask = AMD_SDW_PAD_EN_MASK;
43 pad_pulldown_ctrl_mask = AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK;
46 dev_err(dev, "No SDW Links are enabled\n");
50 val = readl(mmio + ACP_SW_PAD_KEEPER_EN);
51 val |= pad_keeper_en_mask;
52 writel(val, mmio + ACP_SW_PAD_KEEPER_EN);
53 val = readl(mmio + ACP_PAD_PULLDOWN_CTRL);
54 val &= pad_pulldown_ctrl_mask;
55 writel(val, mmio + ACP_PAD_PULLDOWN_CTRL);
59 static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
63 for (i = 0; i < ctx->count; i++) {
64 if (!(ctx->link_mask & BIT(i)))
66 platform_device_unregister(ctx->pdev[i]);
72 static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
74 struct sdw_amd_ctx *ctx;
75 struct acpi_device *adev;
76 struct resource *sdw_res;
77 struct acp_sdw_pdata sdw_pdata[2];
78 struct platform_device_info pdevinfo[2];
86 adev = acpi_fetch_acpi_dev(res->handle);
94 dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
95 ret = amd_enable_sdw_pads(res->mmio_base, res->link_mask, res->parent);
100 * we need to alloc/free memory manually and can't use devm:
101 * this routine may be called from a workqueue, and not from
103 * If devm_ was used, the memory might never be freed on errors.
105 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
110 ctx->link_mask = res->link_mask;
111 sdw_res = kzalloc(sizeof(*sdw_res), GFP_KERNEL);
116 sdw_res->flags = IORESOURCE_MEM;
117 sdw_res->start = res->addr;
118 sdw_res->end = res->addr + res->reg_range;
119 memset(&pdevinfo, 0, sizeof(pdevinfo));
120 link_mask = ctx->link_mask;
121 for (index = 0; index < count; index++) {
122 if (!(link_mask & BIT(index)))
125 sdw_pdata[index].instance = index;
126 sdw_pdata[index].acp_sdw_lock = res->acp_lock;
127 pdevinfo[index].name = "amd_sdw_manager";
128 pdevinfo[index].id = index;
129 pdevinfo[index].parent = res->parent;
130 pdevinfo[index].num_res = 1;
131 pdevinfo[index].res = sdw_res;
132 pdevinfo[index].data = &sdw_pdata[index];
133 pdevinfo[index].size_data = sizeof(struct acp_sdw_pdata);
134 pdevinfo[index].fwnode = acpi_fwnode_handle(adev);
135 ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]);
136 if (IS_ERR(ctx->pdev[index]))
143 if (!(link_mask & BIT(index)))
146 platform_device_unregister(ctx->pdev[index]);
154 static int sdw_amd_startup(struct sdw_amd_ctx *ctx)
156 struct amd_sdw_manager *amd_manager;
159 /* Startup SDW Manager devices */
160 for (i = 0; i < ctx->count; i++) {
161 if (!(ctx->link_mask & BIT(i)))
163 amd_manager = dev_get_drvdata(&ctx->pdev[i]->dev);
164 ret = amd_sdw_manager_start(amd_manager);
172 int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx)
174 *sdw_ctx = sdw_amd_probe_controller(res);
178 return sdw_amd_startup(*sdw_ctx);
180 EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT);
182 void sdw_amd_exit(struct sdw_amd_ctx *ctx)
184 sdw_amd_cleanup(ctx);
188 EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT);
190 int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
192 struct amd_sdw_manager *amd_manager;
194 struct sdw_slave *slave;
195 struct list_head *node;
200 for (index = 0; index < ctx->count; index++) {
201 if (!(ctx->link_mask & BIT(index)))
203 amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
206 bus = &amd_manager->bus;
207 /* Calculate number of slaves */
208 list_for_each(node, &bus->slaves)
212 ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL);
215 ctx->num_slaves = num_slaves;
216 for (index = 0; index < ctx->count; index++) {
217 if (!(ctx->link_mask & BIT(index)))
219 amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
221 bus = &amd_manager->bus;
222 list_for_each_entry(slave, &bus->slaves, node) {
223 ctx->ids[i].id = slave->id;
224 ctx->ids[i].link_id = bus->link_id;
231 EXPORT_SYMBOL_NS(sdw_amd_get_slave_info, SOUNDWIRE_AMD_INIT);
233 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
234 MODULE_DESCRIPTION("AMD SoundWire Init Library");
235 MODULE_LICENSE("Dual BSD/GPL");