From ed5e8741b8db908d51a26e368c18573ee1b9e208 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 29 Jan 2024 11:21:37 +0530 Subject: 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 Acked-by: Vinod Koul Link: https://msgid.link/r/20240129055147.1493853-4-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- drivers/soundwire/amd_init.c | 147 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 drivers/soundwire/amd_init.c (limited to 'drivers/soundwire/amd_init.c') diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c new file mode 100644 index 000000000000..699391d9acba --- /dev/null +++ b/drivers/soundwire/amd_init.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +/* + * SoundWire AMD Manager Initialize routines + * + * Initializes and creates SDW devices based on ACPI and Hardware values + * + * Copyright 2024 Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include + +#include "amd_init.h" + +static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx) +{ + int i; + + for (i = 0; i < ctx->count; i++) { + if (!(ctx->link_mask & BIT(i))) + continue; + platform_device_unregister(ctx->pdev[i]); + } + + return 0; +} + +static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) +{ + struct sdw_amd_ctx *ctx; + struct acpi_device *adev; + struct resource *sdw_res; + struct acp_sdw_pdata sdw_pdata[2]; + struct platform_device_info pdevinfo[2]; + u32 link_mask; + int count, index; + + if (!res) + return NULL; + + adev = acpi_fetch_acpi_dev(res->handle); + if (!adev) + return NULL; + + if (!res->count) + return NULL; + + count = res->count; + dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count); + + /* + * we need to alloc/free memory manually and can't use devm: + * this routine may be called from a workqueue, and not from + * the parent .probe. + * If devm_ was used, the memory might never be freed on errors. + */ + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->count = count; + ctx->link_mask = res->link_mask; + sdw_res = kzalloc(sizeof(*sdw_res), GFP_KERNEL); + if (!sdw_res) { + kfree(ctx); + return NULL; + } + sdw_res->flags = IORESOURCE_MEM; + sdw_res->start = res->addr; + sdw_res->end = res->addr + res->reg_range; + memset(&pdevinfo, 0, sizeof(pdevinfo)); + link_mask = ctx->link_mask; + for (index = 0; index < count; index++) { + if (!(link_mask & BIT(index))) + continue; + + sdw_pdata[index].instance = index; + sdw_pdata[index].acp_sdw_lock = res->acp_lock; + pdevinfo[index].name = "amd_sdw_manager"; + pdevinfo[index].id = index; + pdevinfo[index].parent = res->parent; + pdevinfo[index].num_res = 1; + pdevinfo[index].res = sdw_res; + pdevinfo[index].data = &sdw_pdata[index]; + pdevinfo[index].size_data = sizeof(struct acp_sdw_pdata); + pdevinfo[index].fwnode = acpi_fwnode_handle(adev); + ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]); + if (IS_ERR(ctx->pdev[index])) + goto err; + } + kfree(sdw_res); + return ctx; +err: + while (index--) { + if (!(link_mask & BIT(index))) + continue; + + platform_device_unregister(ctx->pdev[index]); + } + + kfree(sdw_res); + kfree(ctx); + return NULL; +} + +static int sdw_amd_startup(struct sdw_amd_ctx *ctx) +{ + struct amd_sdw_manager *amd_manager; + int i, ret; + + /* Startup SDW Manager devices */ + for (i = 0; i < ctx->count; i++) { + if (!(ctx->link_mask & BIT(i))) + continue; + amd_manager = dev_get_drvdata(&ctx->pdev[i]->dev); + ret = amd_sdw_manager_start(amd_manager); + if (ret) + return ret; + } + + return 0; +} + +int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx) +{ + *sdw_ctx = sdw_amd_probe_controller(res); + if (!*sdw_ctx) + return -ENODEV; + + return sdw_amd_startup(*sdw_ctx); +} +EXPORT_SYMBOL_NS(sdw_amd_probe, SOUNDWIRE_AMD_INIT); + +void sdw_amd_exit(struct sdw_amd_ctx *ctx) +{ + sdw_amd_cleanup(ctx); + kfree(ctx->ids); + kfree(ctx); +} +EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT); + +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); +MODULE_DESCRIPTION("AMD SoundWire Init Library"); +MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From aff9d088a306541117e420d96ed6b6f1215a7e2d Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 29 Jan 2024 11:21:38 +0530 Subject: soundwire: amd: implement function to extract slave information Implement function to extract slaves information connected on the bus. This information is required during machine select logic. This function will be called from machine select logic code. Signed-off-by: Vijendar Mukunda Acked-by: Vinod Koul Link: https://msgid.link/r/20240129055147.1493853-5-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- drivers/soundwire/amd_init.c | 43 +++++++++++++++++++++++++++++++++++++++ include/linux/soundwire/sdw_amd.h | 2 ++ 2 files changed, 45 insertions(+) (limited to 'drivers/soundwire/amd_init.c') diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c index 699391d9acba..46a0538d7fc7 100644 --- a/drivers/soundwire/amd_init.c +++ b/drivers/soundwire/amd_init.c @@ -142,6 +142,49 @@ void sdw_amd_exit(struct sdw_amd_ctx *ctx) } EXPORT_SYMBOL_NS(sdw_amd_exit, SOUNDWIRE_AMD_INIT); +int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx) +{ + struct amd_sdw_manager *amd_manager; + struct sdw_bus *bus; + struct sdw_slave *slave; + struct list_head *node; + int index; + int i = 0; + int num_slaves = 0; + + for (index = 0; index < ctx->count; index++) { + if (!(ctx->link_mask & BIT(index))) + continue; + amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev); + if (!amd_manager) + return -ENODEV; + bus = &amd_manager->bus; + /* Calculate number of slaves */ + list_for_each(node, &bus->slaves) + num_slaves++; + } + + ctx->ids = kcalloc(num_slaves, sizeof(*ctx->ids), GFP_KERNEL); + if (!ctx->ids) + return -ENOMEM; + ctx->num_slaves = num_slaves; + for (index = 0; index < ctx->count; index++) { + if (!(ctx->link_mask & BIT(index))) + continue; + amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev); + if (amd_manager) { + bus = &amd_manager->bus; + list_for_each_entry(slave, &bus->slaves, node) { + ctx->ids[i].id = slave->id; + ctx->ids[i].link_id = bus->link_id; + i++; + } + } + } + return 0; +} +EXPORT_SYMBOL_NS(sdw_amd_get_slave_info, SOUNDWIRE_AMD_INIT); + MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); MODULE_DESCRIPTION("AMD SoundWire Init Library"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h index 54735fa49759..9103772c2497 100644 --- a/include/linux/soundwire/sdw_amd.h +++ b/include/linux/soundwire/sdw_amd.h @@ -170,5 +170,7 @@ int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **ctx); void sdw_amd_exit(struct sdw_amd_ctx *ctx); +int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx); + int amd_sdw_scan_controller(struct sdw_amd_acpi_info *info); #endif -- cgit v1.2.3 From cf0ddbc29dfaacb26d58a594619e42ced286ff29 Mon Sep 17 00:00:00 2001 From: Vijendar Mukunda Date: Mon, 29 Jan 2024 11:21:39 +0530 Subject: soundwire: amd: refactor soundwire pads enable As sdw pads enable sequence is executed only once, invoke it from probe sequence. Program required pads for both manager instances based on link_mask during probe sequence. This will avoid acquiring mutex lock. Remove unnecessary delay after programming ACP_SW_PAD_KEEPER_EN register. Signed-off-by: Vijendar Mukunda Acked-by: Vinod Koul Link: https://msgid.link/r/20240129055147.1493853-6-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown --- drivers/soundwire/amd_init.c | 45 +++++++++++++++++++++++++++++++++++++++++ drivers/soundwire/amd_manager.c | 18 ----------------- 2 files changed, 45 insertions(+), 18 deletions(-) (limited to 'drivers/soundwire/amd_init.c') diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c index 46a0538d7fc7..e45dc8261ab1 100644 --- a/drivers/soundwire/amd_init.c +++ b/drivers/soundwire/amd_init.c @@ -15,6 +15,47 @@ #include "amd_init.h" +#define ACP_PAD_PULLDOWN_CTRL 0x0001448 +#define ACP_SW_PAD_KEEPER_EN 0x0001454 +#define AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9a +#define AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9f +#define AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7ffa +#define AMD_SDW0_PAD_EN_MASK 1 +#define AMD_SDW1_PAD_EN_MASK 0x10 +#define AMD_SDW_PAD_EN_MASK (AMD_SDW0_PAD_EN_MASK | AMD_SDW1_PAD_EN_MASK) + +static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev) +{ + u32 val; + u32 pad_keeper_en_mask, pad_pulldown_ctrl_mask; + + switch (link_mask) { + case 1: + pad_keeper_en_mask = AMD_SDW0_PAD_EN_MASK; + pad_pulldown_ctrl_mask = AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK; + break; + case 2: + pad_keeper_en_mask = AMD_SDW1_PAD_EN_MASK; + pad_pulldown_ctrl_mask = AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK; + break; + case 3: + pad_keeper_en_mask = AMD_SDW_PAD_EN_MASK; + pad_pulldown_ctrl_mask = AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK; + break; + default: + dev_err(dev, "No SDW Links are enabled\n"); + return -ENODEV; + } + + val = readl(mmio + ACP_SW_PAD_KEEPER_EN); + val |= pad_keeper_en_mask; + writel(val, mmio + ACP_SW_PAD_KEEPER_EN); + val = readl(mmio + ACP_PAD_PULLDOWN_CTRL); + val &= pad_pulldown_ctrl_mask; + writel(val, mmio + ACP_PAD_PULLDOWN_CTRL); + return 0; +} + static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx) { int i; @@ -37,6 +78,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) struct platform_device_info pdevinfo[2]; u32 link_mask; int count, index; + int ret; if (!res) return NULL; @@ -50,6 +92,9 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) count = res->count; dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count); + ret = amd_enable_sdw_pads(res->mmio_base, res->link_mask, res->parent); + if (ret) + return NULL; /* * we need to alloc/free memory manually and can't use devm: diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c index efc000334aa0..44d682a83e23 100644 --- a/drivers/soundwire/amd_manager.c +++ b/drivers/soundwire/amd_manager.c @@ -26,23 +26,6 @@ #define to_amd_sdw(b) container_of(b, struct amd_sdw_manager, bus) -static void amd_enable_sdw_pads(struct amd_sdw_manager *amd_manager) -{ - u32 sw_pad_pulldown_val; - u32 val; - - mutex_lock(amd_manager->acp_sdw_lock); - val = readl(amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN); - val |= amd_manager->reg_mask->sw_pad_enable_mask; - writel(val, amd_manager->acp_mmio + ACP_SW_PAD_KEEPER_EN); - usleep_range(1000, 1500); - - sw_pad_pulldown_val = readl(amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL); - sw_pad_pulldown_val &= amd_manager->reg_mask->sw_pad_pulldown_mask; - writel(sw_pad_pulldown_val, amd_manager->acp_mmio + ACP_PAD_PULLDOWN_CTRL); - mutex_unlock(amd_manager->acp_sdw_lock); -} - static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager) { u32 val; @@ -872,7 +855,6 @@ int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager) prop = &amd_manager->bus.prop; if (!prop->hw_disabled) { - amd_enable_sdw_pads(amd_manager); ret = amd_init_sdw_manager(amd_manager); if (ret) return ret; -- cgit v1.2.3