* [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup
@ 2026-09-17 9:02 Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 1/9] soundwire: amd: rename AMD_SDW_MAX_MANAGER_COUNT macro Vijendar Mukunda
` (8 more replies)
0 siblings, 9 replies; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
This series refactors the AMD SoundWire manager driver to replace
direct calls to ACP6.3-specific hardware functions with a
function-pointer dispatch table (struct amd_sdw_hw_ops). The goal is
to make adding support for new ACP revisions a matter of registering a
revision-specific ops table rather than scattering switch/case
statements across the driver.
The series also consolidates probe-time revision-specific assignments
into explicit switch blocks, replaces fixed-size arrays in
sdw_amd_ctx with dynamically-allocated ones sized from the ACP
revision, and cleans up a few stale symbols and redundant
initialisations.
Background:
The AMD SoundWire IP block was introduced on ACP6.3 and is shared
by ACP7.0, ACP7.1 and ACP7.2 with minor register-level differences.
The driver previously used a flat, hardcoded naming scheme
(amd_sdw_*) with no mechanism to swap hardware implementations per
revision. The amd_acp63_* prefix and the hw_ops dispatch table
introduced here make the per-revision nature explicit and provide a
clean extension point for future platforms.
Series overview:
Patches 1-3 are preparatory: rename the manager-count macro to carry
the ACP6.3 scope, convert the pdevinfo/sdw_pdata and pdev arrays in
sdw_amd_probe_controller() from fixed-size stack/inline arrays to
heap allocations sized by the ACP revision, ensuring the probe path
is ready for revisions with a different manager count.
Patch 4 renames the revision-specific hardware-access functions,
static op-table instances, and the manager register-offset constant
to the amd_acp63_* / ACP63_* prefix. Patch 5 removes an unused
define left over from an earlier refactor.
Patches 6-8 introduce and wire up the hw_ops dispatch framework:
patch 6 defines struct amd_sdw_hw_ops and the inline acp_*() dispatch
helpers; patch 7 converts the irq/work handlers to take
struct amd_sdw_manager * so they fit the hw_ops callback signature;
patch 8 extracts the PM callbacks into hw_ops slots, populates a
static const amd_acp63_hw_ops table covering all 19 callbacks, and
converts every remaining direct amd_acp63_*() call site to use the
corresponding acp_*() wrapper.
Patch 9 consolidates the remaining revision-specific probe assignments
(mmio offset, bus ops, port ops, compute_params, port_offset_map) into
a single acp_rev switch, and removes the redundant early
initialisation of cols_index and rows_index since
acp_sdw_clk_init_ctrl() always sets them before set_frameshape() is
called.
Dependencies:
This series applies on top of the AMD SoundWire fix series posted at:
https://lore.kernel.org/alsa-devel/20260917083732.3803526-1-Vijendar.Mukunda@amd.com/T/#t
Vijendar Mukunda (9):
soundwire: amd: rename AMD_SDW_MAX_MANAGER_COUNT macro
soundwire: amd: allocate pdevinfo and sdw_pdata by ACP revision in
probe
soundwire: amd: allocate sdw_amd_ctx pdev array dynamically
soundwire: amd: rename hardware backend functions to amd_acp63_*()
prefix
soundwire: amd: remove unused AMD_SDW_MAX_FREQ_NUM define
soundwire: amd: introduce struct amd_sdw_hw_ops dispatch framework
soundwire: amd: convert irq/work handlers to hw_ops callbacks
soundwire: amd: wire amd_acp63_*() call sites through acp_*() helpers
soundwire: amd: consolidate revision-specific probe setup
drivers/soundwire/amd_init.c | 49 +++-
drivers/soundwire/amd_manager.c | 471 ++++++++++++++++++------------
drivers/soundwire/amd_manager.h | 203 ++++++++++++-
include/linux/soundwire/sdw_amd.h | 9 +-
4 files changed, 533 insertions(+), 199 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/9] soundwire: amd: rename AMD_SDW_MAX_MANAGER_COUNT macro
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 2/9] soundwire: amd: allocate pdevinfo and sdw_pdata by ACP revision in probe Vijendar Mukunda
` (7 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Rename AMD_SDW_MAX_MANAGER_COUNT to AMD_ACP63_SDW_MAX_MANAGER_COUNT and
add a comment clarifying that ACP6.3/7.0/7.1/7.2 all expose two
SoundWire manager instances. The rename makes the platform scope
explicit and matches the acp63 prefix convention used for the shared
ACP6.3-base hardware throughout the driver.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 2 +-
drivers/soundwire/amd_manager.h | 2 +-
include/linux/soundwire/sdw_amd.h | 5 +++--
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 1a252a81269a..400fa05456a1 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -486,7 +486,7 @@ static int amd_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime
int port_bo, hstart, hstop, sample_int;
unsigned int rate, bps, channels;
unsigned int stream_slot_size, max_slots;
- static unsigned int next_offset[AMD_SDW_MAX_MANAGER_COUNT] = {1};
+ static unsigned int next_offset[AMD_ACP63_SDW_MAX_MANAGER_COUNT] = {1};
unsigned int inst_id = amd_manager->instance;
port_bo = 0;
diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h
index 88cf8a426a0c..76ecaceb3ee5 100644
--- a/drivers/soundwire/amd_manager.h
+++ b/drivers/soundwire/amd_manager.h
@@ -266,7 +266,7 @@ static struct sdw_manager_dp_reg acp70_sdw_dp_reg[AMD_ACP70_SDW_MAX_DAI] = {
ACP_SW_AUDIO2_RX_OFFSET, ACP_SW_AUDIO2_RX_CHANNEL_ENABLE_DP0},
};
-static u32 sdw_manager_reg_mask_array[AMD_SDW_MAX_MANAGER_COUNT] = {
+static u32 sdw_manager_reg_mask_array[AMD_ACP63_SDW_MAX_MANAGER_COUNT] = {
AMD_SDW0_EXT_INTR_MASK,
AMD_SDW1_EXT_INTR_MASK
};
diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
index d0e97007e3ff..40ba84c3b2cc 100644
--- a/include/linux/soundwire/sdw_amd.h
+++ b/include/linux/soundwire/sdw_amd.h
@@ -26,7 +26,8 @@
#define AMD_SDW_POWER_OFF_MODE 2
#define ACP_SDW0 0
#define ACP_SDW1 1
-#define AMD_SDW_MAX_MANAGER_COUNT 2
+/* ACP6.3/7.0/7.1/7.2 all expose two SoundWire manager instances */
+#define AMD_ACP63_SDW_MAX_MANAGER_COUNT 2
#define ACP63_PCI_REV_ID 0x63
#define ACP70_PCI_REV_ID 0x70
#define ACP71_PCI_REV_ID 0x71
@@ -138,7 +139,7 @@ struct sdw_amd_acpi_info {
struct sdw_amd_ctx {
int count;
u32 link_mask;
- struct platform_device *pdev[AMD_SDW_MAX_MANAGER_COUNT];
+ struct platform_device *pdev[AMD_ACP63_SDW_MAX_MANAGER_COUNT];
struct sdw_peripherals *peripherals;
};
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 2/9] soundwire: amd: allocate pdevinfo and sdw_pdata by ACP revision in probe
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 1/9] soundwire: amd: rename AMD_SDW_MAX_MANAGER_COUNT macro Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 3/9] soundwire: amd: allocate sdw_amd_ctx pdev array dynamically Vijendar Mukunda
` (6 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Determine the SoundWire manager count from the ACP revision and allocate
the pdevinfo and sdw_pdata arrays dynamically instead of using fixed-size
stack arrays.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_init.c | 37 ++++++++++++++++++++++++++++++++----
1 file changed, 33 insertions(+), 4 deletions(-)
diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c
index 88004d59322e..15d117172bdb 100644
--- a/drivers/soundwire/amd_init.c
+++ b/drivers/soundwire/amd_init.c
@@ -68,12 +68,12 @@ static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
{
+ struct platform_device_info *pdevinfo;
+ struct acp_sdw_pdata *sdw_pdata;
struct sdw_amd_ctx *ctx;
struct acpi_device *adev;
- struct acp_sdw_pdata sdw_pdata[2];
- struct platform_device_info pdevinfo[2];
u32 link_mask;
- int count, index;
+ int count, index, max_manager_count;
int ret;
if (!res)
@@ -88,6 +88,18 @@ 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);
+ switch (res->acp_rev) {
+ case ACP63_PCI_REV_ID:
+ case ACP70_PCI_REV_ID:
+ case ACP71_PCI_REV_ID:
+ case ACP72_PCI_REV_ID:
+ max_manager_count = AMD_ACP63_SDW_MAX_MANAGER_COUNT;
+ break;
+ default:
+ dev_err(&adev->dev, "unsupported ACP revision: 0x%x\n", res->acp_rev);
+ return NULL;
+ }
+
ret = amd_enable_sdw_pads(res->mmio_base, res->link_mask, res->parent);
if (ret)
return NULL;
@@ -112,7 +124,20 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
sdw_res->flags = IORESOURCE_MEM;
sdw_res->start = res->addr;
sdw_res->end = res->addr + res->reg_range;
- memset(&pdevinfo, 0, sizeof(pdevinfo));
+
+ sdw_pdata = kcalloc(max_manager_count, sizeof(*sdw_pdata), GFP_KERNEL);
+ if (!sdw_pdata) {
+ kfree(ctx);
+ return NULL;
+ }
+
+ pdevinfo = kcalloc(max_manager_count, sizeof(*pdevinfo), GFP_KERNEL);
+ if (!pdevinfo) {
+ kfree(sdw_pdata);
+ kfree(ctx);
+ return NULL;
+ }
+
link_mask = ctx->link_mask;
for (index = 0; index < count; index++) {
if (!(link_mask & BIT(index)))
@@ -133,6 +158,8 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
if (IS_ERR(ctx->pdev[index]))
goto err;
}
+ kfree(pdevinfo);
+ kfree(sdw_pdata);
return ctx;
err:
while (index--) {
@@ -142,6 +169,8 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
platform_device_unregister(ctx->pdev[index]);
}
+ kfree(pdevinfo);
+ kfree(sdw_pdata);
kfree(ctx);
return NULL;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 3/9] soundwire: amd: allocate sdw_amd_ctx pdev array dynamically
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 1/9] soundwire: amd: rename AMD_SDW_MAX_MANAGER_COUNT macro Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 2/9] soundwire: amd: allocate pdevinfo and sdw_pdata by ACP revision in probe Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
2026-10-03 7:52 ` Vinod Koul
2026-09-17 9:02 ` [PATCH 4/9] soundwire: amd: rename hardware backend functions to amd_acp63_*() prefix Vijendar Mukunda
` (5 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Replace the fixed-size pdev[AMD_ACP63_SDW_MAX_MANAGER_COUNT] member of
struct sdw_amd_ctx with a dynamically allocated pointer array. The array
is sized by max_manager_count via kcalloc() in sdw_amd_probe_controller()
and freed on all error paths and in sdw_amd_cleanup().
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_init.c | 12 ++++++++++++
include/linux/soundwire/sdw_amd.h | 2 +-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c
index 15d117172bdb..94d766b3f8af 100644
--- a/drivers/soundwire/amd_init.c
+++ b/drivers/soundwire/amd_init.c
@@ -62,6 +62,7 @@ static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
continue;
platform_device_unregister(ctx->pdev[i]);
}
+ kfree(ctx->pdev);
return 0;
}
@@ -116,8 +117,16 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
ctx->count = count;
ctx->link_mask = res->link_mask;
+
+ ctx->pdev = kcalloc(max_manager_count, sizeof(*ctx->pdev), GFP_KERNEL);
+ if (!ctx->pdev) {
+ kfree(ctx);
+ return NULL;
+ }
+
struct resource *sdw_res __free(kfree) = kzalloc_obj(*sdw_res);
if (!sdw_res) {
+ kfree(ctx->pdev);
kfree(ctx);
return NULL;
}
@@ -127,6 +136,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
sdw_pdata = kcalloc(max_manager_count, sizeof(*sdw_pdata), GFP_KERNEL);
if (!sdw_pdata) {
+ kfree(ctx->pdev);
kfree(ctx);
return NULL;
}
@@ -134,6 +144,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
pdevinfo = kcalloc(max_manager_count, sizeof(*pdevinfo), GFP_KERNEL);
if (!pdevinfo) {
kfree(sdw_pdata);
+ kfree(ctx->pdev);
kfree(ctx);
return NULL;
}
@@ -171,6 +182,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
kfree(pdevinfo);
kfree(sdw_pdata);
+ kfree(ctx->pdev);
kfree(ctx);
return NULL;
}
diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
index 40ba84c3b2cc..476de2c30389 100644
--- a/include/linux/soundwire/sdw_amd.h
+++ b/include/linux/soundwire/sdw_amd.h
@@ -139,7 +139,7 @@ struct sdw_amd_acpi_info {
struct sdw_amd_ctx {
int count;
u32 link_mask;
- struct platform_device *pdev[AMD_ACP63_SDW_MAX_MANAGER_COUNT];
+ struct platform_device **pdev;
struct sdw_peripherals *peripherals;
};
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 4/9] soundwire: amd: rename hardware backend functions to amd_acp63_*() prefix
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
` (2 preceding siblings ...)
2026-09-17 9:02 ` [PATCH 3/9] soundwire: amd: allocate sdw_amd_ctx pdev array dynamically Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 5/9] soundwire: amd: remove unused AMD_SDW_MAX_FREQ_NUM define Vijendar Mukunda
` (4 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
In preparation for the hw_ops dispatch framework introduced later in
this series, rename the revision-specific hardware-access functions in
amd_manager.c to the amd_acp63_*() prefix. These functions form the
ACP6.3-base-family hardware backend shared by the ACP6.3, ACP7.0,
ACP7.1 and ACP7.2 revisions and are dispatched per revision through the
amd_sdw_hw_ops table (and the sdw_master_ops structure).
The amd_acp63_ prefix denotes ACP6.3 as the base revision of this shared
IP block, not ACP6.3-only support.
Generic SoundWire protocol and bus helpers that are revision-independent
-- for example amd_sdw_xfer_msg(), amd_prop_read() and
amd_sdw_clock_stop() -- intentionally keep the amd_sdw_*() prefix, as
they are not part of the per-revision dispatch path.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 166 +++++++++++++++++---------------
drivers/soundwire/amd_manager.h | 7 +-
2 files changed, 96 insertions(+), 77 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 400fa05456a1..669044430a0b 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -27,7 +27,7 @@
#define to_amd_sdw(b) container_of(b, struct amd_sdw_manager, bus)
-static int amd_sdw_clk_init_ctrl(struct amd_sdw_manager *amd_manager)
+static int amd_acp63_sdw_clk_init_ctrl(struct amd_sdw_manager *amd_manager)
{
struct sdw_bus *bus = &amd_manager->bus;
struct sdw_master_prop *prop = &bus->prop;
@@ -57,7 +57,7 @@ static int amd_sdw_clk_init_ctrl(struct amd_sdw_manager *amd_manager)
return 0;
}
-static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager)
+static int amd_acp63_init_sdw_manager(struct amd_sdw_manager *amd_manager)
{
u32 val;
int ret;
@@ -89,7 +89,7 @@ static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager)
AMD_SDW_TIMEOUT);
}
-static int amd_enable_sdw_manager(struct amd_sdw_manager *amd_manager)
+static int amd_acp63_enable_sdw_manager(struct amd_sdw_manager *amd_manager)
{
u32 val;
@@ -98,7 +98,7 @@ static int amd_enable_sdw_manager(struct amd_sdw_manager *amd_manager)
AMD_SDW_TIMEOUT);
}
-static int amd_disable_sdw_manager(struct amd_sdw_manager *amd_manager)
+static int amd_acp63_disable_sdw_manager(struct amd_sdw_manager *amd_manager)
{
u32 val;
@@ -115,7 +115,7 @@ static int amd_disable_sdw_manager(struct amd_sdw_manager *amd_manager)
AMD_SDW_TIMEOUT);
}
-static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
+static void amd_acp63_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
{
u32 val;
@@ -131,7 +131,7 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
writel(AMD_SDW_IRQ_ERROR_MASK, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK);
}
-static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
+static void amd_acp63_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
{
u32 irq_mask;
@@ -146,7 +146,7 @@ static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
writel(0x00, amd_manager->mmio + ACP_SW_ERROR_INTR_MASK);
}
-static void amd_sdw_set_frameshape(struct amd_sdw_manager *amd_manager)
+static void amd_acp63_sdw_set_frameshape(struct amd_sdw_manager *amd_manager)
{
u32 frame_size;
@@ -154,7 +154,7 @@ static void amd_sdw_set_frameshape(struct amd_sdw_manager *amd_manager)
writel(frame_size, amd_manager->mmio + ACP_SW_FRAMESIZE);
}
-static void amd_sdw_wake_enable(struct amd_sdw_manager *amd_manager, bool enable)
+static void amd_acp63_sdw_wake_enable(struct amd_sdw_manager *amd_manager, bool enable)
{
u32 wake_ctrl;
@@ -167,7 +167,8 @@ static void amd_sdw_wake_enable(struct amd_sdw_manager *amd_manager, bool enable
writel(wake_ctrl, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11);
}
-static int amd_sdw_set_device_state(struct amd_sdw_manager *amd_manager, u32 target_device_state)
+static int amd_acp63_sdw_set_device_state(struct amd_sdw_manager *amd_manager,
+ u32 target_device_state)
{
u32 sdw_dev_state;
@@ -190,7 +191,7 @@ static int amd_sdw_set_device_state(struct amd_sdw_manager *amd_manager, u32 tar
return 0;
}
-static int amd_sdw_host_wake_enable(struct amd_sdw_manager *amd_manager, bool enable)
+static int amd_acp63_sdw_host_wake_enable(struct amd_sdw_manager *amd_manager, bool enable)
{
u32 intr_cntl1;
u32 sdw_host_wake_irq_mask;
@@ -244,8 +245,8 @@ static void amd_sdw_ctl_word_prep(u32 *lower_word, u32 *upper_word, struct sdw_m
*lower_word = lower_data;
}
-static int amd_sdw_send_cmd_get_resp(struct amd_sdw_manager *amd_manager, u32 lower_data,
- u32 upper_data, u64 *response)
+static int amd_acp63_sdw_send_cmd_get_resp(struct amd_sdw_manager *amd_manager, u32 lower_data,
+ u32 upper_data, u64 *response)
{
u32 lower_resp, upper_resp;
u32 sts;
@@ -301,7 +302,8 @@ amd_program_scp_addr(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg)
scp_msg.buf = &msg->addr_page1;
scp_msg.flags = SDW_MSG_FLAG_WRITE;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0);
- if (amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response_buf[0])) {
+ if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data,
+ &response_buf[0])) {
dev_err_ratelimited(amd_manager->dev,
"SCP_addrpage command timeout for Slave %d\n", msg->dev_num);
return SDW_CMD_TIMEOUT;
@@ -309,7 +311,8 @@ amd_program_scp_addr(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg)
scp_msg.addr = SDW_SCP_ADDRPAGE2;
scp_msg.buf = &msg->addr_page2;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0);
- if (amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response_buf[1])) {
+ if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data,
+ &response_buf[1])) {
dev_err_ratelimited(amd_manager->dev,
"SCP_addrpage command timeout for Slave %d\n", msg->dev_num);
return SDW_CMD_TIMEOUT;
@@ -374,6 +377,7 @@ static enum sdw_command_response amd_sdw_fill_msg_resp(struct amd_sdw_manager *a
return SDW_CMD_OK;
}
+/* AMD SoundWire bus helper shared across all ACP revisions. */
static unsigned int _amd_sdw_xfer_msg(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg,
int cmd_offset)
{
@@ -381,7 +385,7 @@ static unsigned int _amd_sdw_xfer_msg(struct amd_sdw_manager *amd_manager, struc
u32 upper_data = 0, lower_data = 0;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, msg, cmd_offset);
- if (amd_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response)) {
+ if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response)) {
dev_err_ratelimited(amd_manager->dev, "command timeout for Slave %d\n",
msg->dev_num);
return SDW_CMD_TIMEOUT;
@@ -389,6 +393,7 @@ static unsigned int _amd_sdw_xfer_msg(struct amd_sdw_manager *amd_manager, struc
return amd_sdw_fill_msg_resp(amd_manager, msg, response, cmd_offset);
}
+/* AMD SoundWire bus helper shared across all ACP revisions. */
static enum sdw_command_response amd_sdw_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)
{
struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
@@ -405,6 +410,7 @@ static enum sdw_command_response amd_sdw_xfer_msg(struct sdw_bus *bus, struct sd
return SDW_CMD_OK;
}
+/* AMD SoundWire bus helper shared across all ACP revisions. */
static void amd_sdw_fill_slave_status(struct amd_sdw_manager *amd_manager, u16 index, u32 status)
{
switch (status) {
@@ -419,6 +425,7 @@ static void amd_sdw_fill_slave_status(struct amd_sdw_manager *amd_manager, u16 i
}
}
+/* AMD SoundWire bus helper shared across all ACP revisions. */
static void amd_sdw_process_ping_status(u64 response, struct amd_sdw_manager *amd_manager)
{
u64 slave_stat;
@@ -436,12 +443,12 @@ static void amd_sdw_process_ping_status(u64 response, struct amd_sdw_manager *am
}
}
-static void amd_sdw_read_and_process_ping_status(struct amd_sdw_manager *amd_manager)
+static void amd_acp63_sdw_read_and_process_ping_status(struct amd_sdw_manager *amd_manager)
{
u64 response;
mutex_lock(&amd_manager->bus.msg_lock);
- if (amd_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
+ if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
mutex_unlock(&amd_manager->bus.msg_lock);
dev_err_ratelimited(amd_manager->dev, "SDW%x ping status timeout\n",
amd_manager->instance);
@@ -454,7 +461,7 @@ static void amd_sdw_read_and_process_ping_status(struct amd_sdw_manager *amd_man
mutex_unlock(&amd_manager->bus.msg_lock);
}
-static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
+static u32 amd_acp63_sdw_read_ping_status(struct sdw_bus *bus)
{
struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
u64 response;
@@ -463,7 +470,7 @@ static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
/* Called by sdw_show_ping_status() which holds msg_lock. */
lockdep_assert_held(&bus->msg_lock);
- if (amd_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
+ if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
dev_err_ratelimited(amd_manager->dev, "SDW%x ping status timeout\n",
amd_manager->instance);
return amd_manager->ping_slave_stat == U32_MAX ? 0 : amd_manager->ping_slave_stat;
@@ -476,7 +483,7 @@ static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
return slave_stat;
}
-static int amd_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
+static int amd_acp63_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime *stream)
{
struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
struct sdw_transport_data t_data = {0};
@@ -562,8 +569,8 @@ static int amd_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime
return 0;
}
-static int amd_sdw_port_params(struct sdw_bus *bus, struct sdw_port_params *p_params,
- unsigned int bank)
+static int amd_acp63_sdw_port_params(struct sdw_bus *bus, struct sdw_port_params *p_params,
+ unsigned int bank)
{
struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
u32 frame_fmt_reg, dpn_frame_fmt;
@@ -599,9 +606,9 @@ static int amd_sdw_port_params(struct sdw_bus *bus, struct sdw_port_params *p_pa
return 0;
}
-static int amd_sdw_transport_params(struct sdw_bus *bus,
- struct sdw_transport_params *params,
- enum sdw_reg_bank bank)
+static int amd_acp63_sdw_transport_params(struct sdw_bus *bus,
+ struct sdw_transport_params *params,
+ enum sdw_reg_bank bank)
{
struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
u32 dpn_frame_fmt;
@@ -676,9 +683,9 @@ static int amd_sdw_transport_params(struct sdw_bus *bus,
return 0;
}
-static int amd_sdw_port_enable(struct sdw_bus *bus,
- struct sdw_enable_ch *enable_ch,
- unsigned int bank)
+static int amd_acp63_sdw_port_enable(struct sdw_bus *bus,
+ struct sdw_enable_ch *enable_ch,
+ unsigned int bank)
{
struct amd_sdw_manager *amd_manager = to_amd_sdw(bus);
u32 dpn_ch_enable;
@@ -755,6 +762,7 @@ static int sdw_master_read_amd_prop(struct sdw_bus *bus)
return 0;
}
+/* AMD SoundWire bus helper shared across all ACP revisions. */
static int amd_prop_read(struct sdw_bus *bus)
{
sdw_master_read_prop(bus);
@@ -762,16 +770,16 @@ static int amd_prop_read(struct sdw_bus *bus)
return 0;
}
-static const struct sdw_master_port_ops amd_sdw_port_ops = {
- .dpn_set_port_params = amd_sdw_port_params,
- .dpn_set_port_transport_params = amd_sdw_transport_params,
- .dpn_port_enable_ch = amd_sdw_port_enable,
+static const struct sdw_master_port_ops amd_acp63_sdw_port_ops = {
+ .dpn_set_port_params = amd_acp63_sdw_port_params,
+ .dpn_set_port_transport_params = amd_acp63_sdw_transport_params,
+ .dpn_port_enable_ch = amd_acp63_sdw_port_enable,
};
-static const struct sdw_master_ops amd_sdw_ops = {
+static const struct sdw_master_ops amd_acp63_sdw_ops = {
.read_prop = amd_prop_read,
.xfer_msg = amd_sdw_xfer_msg,
- .read_ping_status = amd_sdw_read_ping_status,
+ .read_ping_status = amd_acp63_sdw_read_ping_status,
};
static int amd_sdw_hw_params(struct snd_pcm_substream *substream,
@@ -941,7 +949,7 @@ static int amd_sdw_register_dais(struct amd_sdw_manager *amd_manager)
dais, num_dais);
}
-static void amd_sdw_update_slave_status_work(struct work_struct *work)
+static void amd_acp63_sdw_update_slave_status_work(struct work_struct *work)
{
struct amd_sdw_manager *amd_manager =
container_of(work, struct amd_sdw_manager, amd_sdw_work);
@@ -967,7 +975,7 @@ static void amd_sdw_update_slave_status_work(struct work_struct *work)
ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7);
writel(AMD_SDW_IRQ_MASK_8TO11, amd_manager->mmio +
ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11);
- amd_sdw_read_and_process_ping_status(amd_manager);
+ amd_acp63_sdw_read_and_process_ping_status(amd_manager);
goto update_status;
} else {
dev_err_ratelimited(amd_manager->dev,
@@ -1001,7 +1009,7 @@ static void amd_sdw_update_slave_status(u32 status_change_0to7, u32 status_chang
}
}
-static void amd_sdw_process_wake_event(struct amd_sdw_manager *amd_manager)
+static void amd_acp63_sdw_process_wake_event(struct amd_sdw_manager *amd_manager)
{
dev_dbg(amd_manager->dev, "SoundWire Wake event reported\n");
pm_request_resume(amd_manager->dev);
@@ -1009,7 +1017,7 @@ static void amd_sdw_process_wake_event(struct amd_sdw_manager *amd_manager)
writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11);
}
-static void amd_sdw_irq_thread(struct work_struct *work)
+static void amd_acp63_sdw_irq_thread(struct work_struct *work)
{
struct amd_sdw_manager *amd_manager =
container_of(work, struct amd_sdw_manager, amd_sdw_irq_thread);
@@ -1024,10 +1032,10 @@ static void amd_sdw_irq_thread(struct work_struct *work)
dev_dbg(amd_manager->dev, "[SDW%d] SDW INT: 0to7=0x%x, 8to11=0x%x\n",
amd_manager->instance, status_change_0to7, status_change_8to11);
if (status_change_8to11 & AMD_SDW_WAKE_STAT_MASK)
- return amd_sdw_process_wake_event(amd_manager);
+ return amd_acp63_sdw_process_wake_event(amd_manager);
if (status_change_8to11 & AMD_SDW_PREQ_INTR_STAT) {
- amd_sdw_read_and_process_ping_status(amd_manager);
+ amd_acp63_sdw_read_and_process_ping_status(amd_manager);
} else {
/* Check for the updated status on peripheral device */
amd_sdw_update_slave_status(status_change_0to7, status_change_8to11, amd_manager);
@@ -1045,17 +1053,17 @@ int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager)
prop = &amd_manager->bus.prop;
if (!prop->hw_disabled) {
- ret = amd_sdw_clk_init_ctrl(amd_manager);
+ ret = amd_acp63_sdw_clk_init_ctrl(amd_manager);
if (ret)
return ret;
- ret = amd_init_sdw_manager(amd_manager);
+ ret = amd_acp63_init_sdw_manager(amd_manager);
if (ret)
return ret;
- amd_enable_sdw_interrupts(amd_manager);
- ret = amd_enable_sdw_manager(amd_manager);
+ amd_acp63_enable_sdw_interrupts(amd_manager);
+ ret = amd_acp63_enable_sdw_manager(amd_manager);
if (ret)
return ret;
- amd_sdw_set_frameshape(amd_manager);
+ amd_acp63_sdw_set_frameshape(amd_manager);
}
/* Enable runtime PM */
pm_runtime_set_autosuspend_delay(amd_manager->dev, AMD_SDW_MASTER_SUSPEND_DELAY_MS);
@@ -1091,15 +1099,15 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
amd_manager->ping_slave_stat = U32_MAX;
amd_manager->instance = pdata->instance;
amd_manager->mmio = amd_manager->acp_mmio +
- (amd_manager->instance * SDW_MANAGER_REG_OFFSET);
+ (amd_manager->instance * ACP63_SDW_MANAGER_REG_OFFSET);
amd_manager->acp_sdw_lock = pdata->acp_sdw_lock;
amd_manager->acp_rev = pdata->acp_rev;
amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS);
amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS);
amd_manager->dev = dev;
- amd_manager->bus.ops = &amd_sdw_ops;
- amd_manager->bus.port_ops = &amd_sdw_port_ops;
- amd_manager->bus.compute_params = &amd_sdw_compute_params;
+ amd_manager->bus.ops = &amd_acp63_sdw_ops;
+ amd_manager->bus.port_ops = &amd_acp63_sdw_port_ops;
+ amd_manager->bus.compute_params = &amd_acp63_sdw_compute_params;
amd_manager->bus.clk_stop_timeout = 200;
amd_manager->bus.link_id = amd_manager->instance;
@@ -1156,8 +1164,8 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
return ret;
}
dev_set_drvdata(dev, amd_manager);
- INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_irq_thread);
- INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work);
+ INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_acp63_sdw_irq_thread);
+ INIT_WORK(&amd_manager->amd_sdw_work, amd_acp63_sdw_update_slave_status_work);
return 0;
}
@@ -1168,15 +1176,21 @@ static void amd_sdw_manager_remove(struct platform_device *pdev)
if (pm_runtime_enabled(&pdev->dev))
pm_runtime_disable(&pdev->dev);
- amd_disable_sdw_interrupts(amd_manager);
+ amd_acp63_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
sdw_bus_master_delete(&amd_manager->bus);
- ret = amd_disable_sdw_manager(amd_manager);
+ ret = amd_acp63_disable_sdw_manager(amd_manager);
if (ret)
dev_err(&pdev->dev, "Failed to disable device (%pe)\n", ERR_PTR(ret));
}
+/*
+ * AMD SoundWire clock-stop sequence shared across all ACP revisions.
+ * Differences between revisions in this path are minimal; a switch/case
+ * on acp_rev is sufficient to accommodate any variant-specific additions
+ * needed for future platforms.
+ */
static int amd_sdw_clock_stop(struct amd_sdw_manager *amd_manager)
{
u32 val;
@@ -1208,7 +1222,7 @@ static int amd_sdw_clock_stop(struct amd_sdw_manager *amd_manager)
return 0;
}
-static int amd_sdw_clock_stop_exit(struct amd_sdw_manager *amd_manager)
+static int amd_acp63_sdw_clock_stop_exit(struct amd_sdw_manager *amd_manager)
{
int ret;
u32 val;
@@ -1300,7 +1314,7 @@ static int amd_sdw_host_wake_enable_by_rev(struct amd_sdw_manager *amd_manager,
case ACP70_PCI_REV_ID:
case ACP71_PCI_REV_ID:
case ACP72_PCI_REV_ID:
- return amd_sdw_host_wake_enable(amd_manager, enable);
+ return amd_acp63_sdw_host_wake_enable(amd_manager, enable);
default:
dev_err(amd_manager->dev, "unexpected acp_rev 0x%x\n", amd_manager->acp_rev);
return -EINVAL;
@@ -1321,22 +1335,22 @@ static int __maybe_unused amd_suspend(struct device *dev)
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
- amd_disable_sdw_interrupts(amd_manager);
+ amd_acp63_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
- amd_sdw_wake_enable(amd_manager, false);
+ amd_acp63_sdw_wake_enable(amd_manager, false);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
if (ret)
return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- amd_enable_sdw_interrupts(amd_manager);
+ amd_acp63_enable_sdw_interrupts(amd_manager);
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
- amd_disable_sdw_interrupts(amd_manager);
+ amd_acp63_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
- amd_sdw_wake_enable(amd_manager, false);
+ amd_acp63_sdw_wake_enable(amd_manager, false);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
if (ret)
return ret;
@@ -1347,7 +1361,7 @@ static int __maybe_unused amd_suspend(struct device *dev)
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- ret = amd_disable_sdw_manager(amd_manager);
+ ret = amd_acp63_disable_sdw_manager(amd_manager);
if (ret)
return ret;
}
@@ -1357,7 +1371,7 @@ static int __maybe_unused amd_suspend(struct device *dev)
case ACP70_PCI_REV_ID:
case ACP71_PCI_REV_ID:
case ACP72_PCI_REV_ID:
- ret = amd_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
+ ret = amd_acp63_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
if (ret)
return ret;
break;
@@ -1381,29 +1395,29 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
return 0;
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
- amd_disable_sdw_interrupts(amd_manager);
+ amd_acp63_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
- amd_sdw_wake_enable(amd_manager, true);
+ amd_acp63_sdw_wake_enable(amd_manager, true);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, true);
if (ret)
return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- amd_enable_sdw_interrupts(amd_manager);
+ amd_acp63_enable_sdw_interrupts(amd_manager);
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
- amd_disable_sdw_interrupts(amd_manager);
+ amd_acp63_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
- amd_sdw_wake_enable(amd_manager, true);
+ amd_acp63_sdw_wake_enable(amd_manager, true);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, true);
if (ret)
return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- ret = amd_disable_sdw_manager(amd_manager);
+ ret = amd_acp63_disable_sdw_manager(amd_manager);
if (ret)
return ret;
}
@@ -1413,7 +1427,7 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
case ACP70_PCI_REV_ID:
case ACP71_PCI_REV_ID:
case ACP72_PCI_REV_ID:
- ret = amd_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
+ ret = amd_acp63_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
if (ret)
return ret;
if (amd_manager->wake_en_mask) {
@@ -1446,7 +1460,7 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
- ret = amd_sdw_clock_stop_exit(amd_manager);
+ ret = amd_acp63_sdw_clock_stop_exit(amd_manager);
if (ret)
return ret;
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
@@ -1481,17 +1495,17 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
}
}
sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
- ret = amd_sdw_clk_init_ctrl(amd_manager);
+ ret = amd_acp63_sdw_clk_init_ctrl(amd_manager);
if (ret)
return ret;
- ret = amd_init_sdw_manager(amd_manager);
+ ret = amd_acp63_init_sdw_manager(amd_manager);
if (ret)
return ret;
- amd_enable_sdw_interrupts(amd_manager);
- ret = amd_enable_sdw_manager(amd_manager);
+ amd_acp63_enable_sdw_interrupts(amd_manager);
+ ret = amd_acp63_enable_sdw_manager(amd_manager);
if (ret)
return ret;
- amd_sdw_set_frameshape(amd_manager);
+ amd_acp63_sdw_set_frameshape(amd_manager);
}
switch (amd_manager->acp_rev) {
case ACP63_PCI_REV_ID:
@@ -1499,7 +1513,7 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
case ACP70_PCI_REV_ID:
case ACP71_PCI_REV_ID:
case ACP72_PCI_REV_ID:
- ret = amd_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D0);
+ ret = amd_acp63_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D0);
if (ret)
return ret;
break;
diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h
index 76ecaceb3ee5..adde192f61fe 100644
--- a/drivers/soundwire/amd_manager.h
+++ b/drivers/soundwire/amd_manager.h
@@ -8,7 +8,12 @@
#include <linux/soundwire/sdw_amd.h>
-#define SDW_MANAGER_REG_OFFSET 0xc00
+/*
+ * Register offset between successive SoundWire manager instances.
+ * This value applies to ACP6.3, ACP7.0, ACP7.1, and ACP7.2. A new
+ * revision with a different offset must define its own constant.
+ */
+#define ACP63_SDW_MANAGER_REG_OFFSET 0xc00
#define AMD_SDW_DEFAULT_ROWS 50
#define AMD_SDW_DEFAULT_COLUMNS 10
#define ACP_PAD_PULLDOWN_CTRL 0x0001448
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/9] soundwire: amd: remove unused AMD_SDW_MAX_FREQ_NUM define
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
` (3 preceding siblings ...)
2026-09-17 9:02 ` [PATCH 4/9] soundwire: amd: rename hardware backend functions to amd_acp63_*() prefix Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 6/9] soundwire: amd: introduce struct amd_sdw_hw_ops dispatch framework Vijendar Mukunda
` (3 subsequent siblings)
8 siblings, 0 replies; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
The AMD_SDW_MAX_FREQ_NUM macro has no users anywhere in the driver.
Remove it as a straightforward cleanup with no functional change.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h
index adde192f61fe..63fecff62079 100644
--- a/drivers/soundwire/amd_manager.h
+++ b/drivers/soundwire/amd_manager.h
@@ -159,7 +159,6 @@
#define AMD_SDW_IRQ_MASK_0TO7 0x77777777
#define AMD_SDW_IRQ_MASK_8TO11 0x000c7777
#define AMD_SDW_IRQ_ERROR_MASK 0xff
-#define AMD_SDW_MAX_FREQ_NUM 1
#define AMD_ACP63_SDW0_MAX_TX_PORTS 3
#define AMD_ACP63_SDW0_MAX_RX_PORTS 3
#define AMD_ACP63_SDW1_MAX_TX_PORTS 1
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 6/9] soundwire: amd: introduce struct amd_sdw_hw_ops dispatch framework
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
` (4 preceding siblings ...)
2026-09-17 9:02 ` [PATCH 5/9] soundwire: amd: remove unused AMD_SDW_MAX_FREQ_NUM define Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
2026-10-03 7:56 ` Vinod Koul
2026-09-17 9:02 ` [PATCH 7/9] soundwire: amd: convert irq/work handlers to hw_ops callbacks Vijendar Mukunda
` (2 subsequent siblings)
8 siblings, 1 reply; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Add struct amd_sdw_hw_ops, a function-pointer dispatch table for
hardware-revision-specific SoundWire manager operations. Add inline
dispatch helpers for each callback and a const hw_ops pointer in
struct amd_sdw_manager.
The irq_thread and update_slave_status_work slots take
struct amd_sdw_manager * so that different ACP revisions can register
different handler logic. hw_ops is populated and call sites are wired
through the dispatch helpers in subsequent patches.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.h | 193 ++++++++++++++++++++++++++++++
include/linux/soundwire/sdw_amd.h | 4 +
2 files changed, 197 insertions(+)
diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h
index 63fecff62079..2d08c6edd018 100644
--- a/drivers/soundwire/amd_manager.h
+++ b/drivers/soundwire/amd_manager.h
@@ -274,4 +274,197 @@ static u32 sdw_manager_reg_mask_array[AMD_ACP63_SDW_MAX_MANAGER_COUNT] = {
AMD_SDW0_EXT_INTR_MASK,
AMD_SDW1_EXT_INTR_MASK
};
+
+#define AMD_SDW_HW_OPS(amd_manager, cb) ((amd_manager)->hw_ops->cb)
+
+/**
+ * struct amd_sdw_hw_ops - hardware-revision-specific SoundWire manager ops
+ *
+ * @init_sdw_manager: enable the SoundWire manager hardware and perform bus reset
+ * @enable_sdw_manager: set the manager enable bit and wait for it to assert
+ * @disable_sdw_manager: clear the manager enable bit and wait for it to deassert
+ * @enable_sdw_interrupts: unmask ACP-level and per-manager interrupt bits
+ * @disable_sdw_interrupts: mask ACP-level and per-manager interrupt bits
+ * @set_frameshape: write the row/column frame-shape register
+ * @send_cmd_get_resp: issue an immediate command and return the response;
+ * returns 0 on success with the raw u64 response in @response,
+ * or negative on hardware timeout
+ * @wake_enable: enable or disable the in-band SoundWire wake interrupt
+ * @host_wake_enable: enable or disable the host-side wake interrupt
+ * @set_device_state: write the D0/D3 device power state for the manager instance
+ * @read_and_process_ping_status: issue a PING command and process the slave
+ * attach/detach status; called from the IRQ work path
+ * @process_wake_event: handle an in-band wake notification from a slave
+ * @irq_thread: hw_ops callback invoked by the thin work_struct wrapper on
+ * each interrupt; reads status registers and dispatches slave events
+ * @update_slave_status_work: hw_ops callback invoked by the status-update
+ * work item; reads slave status and updates the SoundWire core
+ * @clk_init_ctrl: set the clock divider and update the frame shape registers
+ * based on the current bus clock frequency
+ * @clock_stop_exit: restart the SoundWire bus clock after a CLK_STOP_MODE
+ * suspend; implementation differs across ACP revisions
+ * @suspend: system-suspend hook; stops the bus and powers down the manager
+ * @suspend_runtime: runtime-suspend hook; same sequence as @suspend
+ * @resume_runtime: runtime-resume hook; reinitialises the manager and restarts
+ * the bus after a POWER_OFF_MODE or CLK_STOP_MODE suspend
+ */
+struct amd_sdw_hw_ops {
+ int (*init_sdw_manager)(struct amd_sdw_manager *amd_manager);
+ int (*enable_sdw_manager)(struct amd_sdw_manager *amd_manager);
+ int (*disable_sdw_manager)(struct amd_sdw_manager *amd_manager);
+ void (*enable_sdw_interrupts)(struct amd_sdw_manager *amd_manager);
+ void (*disable_sdw_interrupts)(struct amd_sdw_manager *amd_manager);
+ void (*set_frameshape)(struct amd_sdw_manager *amd_manager);
+ int (*send_cmd_get_resp)(struct amd_sdw_manager *amd_manager, u32 lower_data,
+ u32 upper_data, u64 *response);
+ void (*wake_enable)(struct amd_sdw_manager *amd_manager, bool enable);
+ int (*host_wake_enable)(struct amd_sdw_manager *amd_manager, bool enable);
+ int (*set_device_state)(struct amd_sdw_manager *amd_manager, u32 target_device_state);
+ void (*read_and_process_ping_status)(struct amd_sdw_manager *amd_manager);
+ void (*process_wake_event)(struct amd_sdw_manager *amd_manager);
+ void (*irq_thread)(struct amd_sdw_manager *amd_manager);
+ void (*update_slave_status_work)(struct amd_sdw_manager *amd_manager);
+ int (*clk_init_ctrl)(struct amd_sdw_manager *amd_manager);
+ int (*clock_stop_exit)(struct amd_sdw_manager *amd_manager);
+ int (*suspend)(struct amd_sdw_manager *amd_manager);
+ int (*suspend_runtime)(struct amd_sdw_manager *amd_manager);
+ int (*resume_runtime)(struct amd_sdw_manager *amd_manager);
+};
+
+static inline int acp_init_sdw_manager(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->init_sdw_manager)
+ return AMD_SDW_HW_OPS(amd_manager, init_sdw_manager)(amd_manager);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_enable_sdw_manager(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->enable_sdw_manager)
+ return AMD_SDW_HW_OPS(amd_manager, enable_sdw_manager)(amd_manager);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_disable_sdw_manager(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->disable_sdw_manager)
+ return AMD_SDW_HW_OPS(amd_manager, disable_sdw_manager)(amd_manager);
+ return -EOPNOTSUPP;
+}
+
+static inline void acp_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->enable_sdw_interrupts)
+ AMD_SDW_HW_OPS(amd_manager, enable_sdw_interrupts)(amd_manager);
+}
+
+static inline void acp_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->disable_sdw_interrupts)
+ AMD_SDW_HW_OPS(amd_manager, disable_sdw_interrupts)(amd_manager);
+}
+
+static inline void acp_sdw_set_frameshape(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->set_frameshape)
+ AMD_SDW_HW_OPS(amd_manager, set_frameshape)(amd_manager);
+}
+
+static inline int acp_sdw_send_cmd_get_resp(struct amd_sdw_manager *amd_manager,
+ u32 lower_data, u32 upper_data, u64 *response)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->send_cmd_get_resp)
+ return AMD_SDW_HW_OPS(amd_manager, send_cmd_get_resp)(amd_manager,
+ lower_data, upper_data,
+ response);
+ return -EOPNOTSUPP;
+}
+
+static inline void acp_sdw_wake_enable(struct amd_sdw_manager *amd_manager, bool enable)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->wake_enable)
+ AMD_SDW_HW_OPS(amd_manager, wake_enable)(amd_manager, enable);
+}
+
+static inline int acp_sdw_host_wake_enable(struct amd_sdw_manager *amd_manager, bool enable)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->host_wake_enable)
+ return AMD_SDW_HW_OPS(amd_manager, host_wake_enable)(amd_manager, enable);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_sdw_set_device_state(struct amd_sdw_manager *amd_manager,
+ u32 target_device_state)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->set_device_state)
+ return AMD_SDW_HW_OPS(amd_manager, set_device_state)(amd_manager,
+ target_device_state);
+ return -EOPNOTSUPP;
+}
+
+static inline void acp_sdw_read_and_process_ping_status(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->read_and_process_ping_status)
+ AMD_SDW_HW_OPS(amd_manager, read_and_process_ping_status)(amd_manager);
+}
+
+static inline void acp_sdw_process_wake_event(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->process_wake_event)
+ AMD_SDW_HW_OPS(amd_manager, process_wake_event)(amd_manager);
+}
+
+static inline void acp_sdw_irq_thread(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->irq_thread)
+ AMD_SDW_HW_OPS(amd_manager, irq_thread)(amd_manager);
+}
+
+static inline void acp_sdw_update_slave_status_work(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->update_slave_status_work)
+ AMD_SDW_HW_OPS(amd_manager, update_slave_status_work)(amd_manager);
+}
+
+static inline int acp_sdw_clk_init_ctrl(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->clk_init_ctrl)
+ return AMD_SDW_HW_OPS(amd_manager, clk_init_ctrl)(amd_manager);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_sdw_clock_stop_exit(struct amd_sdw_manager *amd_manager)
+{
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->clock_stop_exit)
+ return AMD_SDW_HW_OPS(amd_manager, clock_stop_exit)(amd_manager);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_sdw_suspend(struct device *dev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
+
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->suspend)
+ return AMD_SDW_HW_OPS(amd_manager, suspend)(amd_manager);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_sdw_suspend_runtime(struct device *dev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
+
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->suspend_runtime)
+ return AMD_SDW_HW_OPS(amd_manager, suspend_runtime)(amd_manager);
+ return -EOPNOTSUPP;
+}
+
+static inline int acp_sdw_resume_runtime(struct device *dev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
+
+ if (amd_manager && amd_manager->hw_ops && amd_manager->hw_ops->resume_runtime)
+ return AMD_SDW_HW_OPS(amd_manager, resume_runtime)(amd_manager);
+ return -EOPNOTSUPP;
+}
+
#endif
diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
index 476de2c30389..cbfa3d6b3460 100644
--- a/include/linux/soundwire/sdw_amd.h
+++ b/include/linux/soundwire/sdw_amd.h
@@ -55,10 +55,13 @@ struct sdw_amd_dai_runtime {
enum sdw_stream_type stream_type;
};
+struct amd_sdw_hw_ops;
+
/**
* struct amd_sdw_manager - amd manager driver context
* @bus: bus handle
* @dev: linux device
+ * @hw_ops: pointer to hardware-revision-specific dispatch table
* @mmio: SoundWire registers mmio base
* @acp_mmio: acp registers mmio base
* @amd_sdw_irq_thread: SoundWire manager irq workqueue
@@ -85,6 +88,7 @@ struct sdw_amd_dai_runtime {
struct amd_sdw_manager {
struct sdw_bus bus;
struct device *dev;
+ const struct amd_sdw_hw_ops *hw_ops;
void __iomem *mmio;
void __iomem *acp_mmio;
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 7/9] soundwire: amd: convert irq/work handlers to hw_ops callbacks
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
` (5 preceding siblings ...)
2026-09-17 9:02 ` [PATCH 6/9] soundwire: amd: introduce struct amd_sdw_hw_ops dispatch framework Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 8/9] soundwire: amd: wire amd_acp63_*() call sites through acp_*() helpers Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 9/9] soundwire: amd: consolidate revision-specific probe setup Vijendar Mukunda
8 siblings, 0 replies; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Convert amd_acp63_sdw_irq_thread() and
amd_acp63_sdw_update_slave_status_work() from work_struct handlers
(taking struct work_struct *) to hw_ops callbacks (taking
struct amd_sdw_manager *).
Introduce thin work_struct wrappers that recover the manager pointer
via container_of and invoke the refactored functions directly. The
wrappers are wired through the acp_sdw_*() dispatch helpers in the
subsequent patch once hw_ops is populated.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 669044430a0b..87a2e779dd4e 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -17,6 +17,7 @@
#include <linux/soundwire/sdw_registers.h>
#include <linux/pm_runtime.h>
#include <linux/wait.h>
+#include <linux/workqueue.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "bus.h"
@@ -949,10 +950,8 @@ static int amd_sdw_register_dais(struct amd_sdw_manager *amd_manager)
dais, num_dais);
}
-static void amd_acp63_sdw_update_slave_status_work(struct work_struct *work)
+static void amd_acp63_sdw_update_slave_status_work(struct amd_sdw_manager *amd_manager)
{
- struct amd_sdw_manager *amd_manager =
- container_of(work, struct amd_sdw_manager, amd_sdw_work);
int retry_count = 0;
if (amd_manager->status[0] == SDW_SLAVE_ATTACHED) {
@@ -985,6 +984,14 @@ static void amd_acp63_sdw_update_slave_status_work(struct work_struct *work)
}
}
+static void amd_sdw_update_slave_status_work(struct work_struct *work)
+{
+ struct amd_sdw_manager *amd_manager =
+ container_of(work, struct amd_sdw_manager, amd_sdw_work);
+
+ amd_acp63_sdw_update_slave_status_work(amd_manager);
+}
+
static void amd_sdw_update_slave_status(u32 status_change_0to7, u32 status_change_8to11,
struct amd_sdw_manager *amd_manager)
{
@@ -1017,10 +1024,8 @@ static void amd_acp63_sdw_process_wake_event(struct amd_sdw_manager *amd_manager
writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_8TO11);
}
-static void amd_acp63_sdw_irq_thread(struct work_struct *work)
+static void amd_acp63_sdw_irq_thread(struct amd_sdw_manager *amd_manager)
{
- struct amd_sdw_manager *amd_manager =
- container_of(work, struct amd_sdw_manager, amd_sdw_irq_thread);
u32 status_change_8to11;
u32 status_change_0to7;
@@ -1046,6 +1051,14 @@ static void amd_acp63_sdw_irq_thread(struct work_struct *work)
writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_0TO7);
}
+static void amd_sdw_interrupt_thread(struct work_struct *work)
+{
+ struct amd_sdw_manager *amd_manager =
+ container_of(work, struct amd_sdw_manager, amd_sdw_irq_thread);
+
+ amd_acp63_sdw_irq_thread(amd_manager);
+}
+
int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager)
{
struct sdw_master_prop *prop;
@@ -1164,8 +1177,8 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
return ret;
}
dev_set_drvdata(dev, amd_manager);
- INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_acp63_sdw_irq_thread);
- INIT_WORK(&amd_manager->amd_sdw_work, amd_acp63_sdw_update_slave_status_work);
+ INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_interrupt_thread);
+ INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work);
return 0;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 8/9] soundwire: amd: wire amd_acp63_*() call sites through acp_*() helpers
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
` (6 preceding siblings ...)
2026-09-17 9:02 ` [PATCH 7/9] soundwire: amd: convert irq/work handlers to hw_ops callbacks Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 9/9] soundwire: amd: consolidate revision-specific probe setup Vijendar Mukunda
8 siblings, 0 replies; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Extract PM logic into amd_acp63_sdw_suspend(),
amd_acp63_sdw_suspend_runtime() and
amd_acp63_sdw_resume_runtime() hw_ops callbacks, each taking
struct amd_sdw_manager * instead of struct device *.
Replace the existing amd_suspend(), amd_suspend_runtime() and
amd_resume_runtime() static wrappers with thin one-liners that
delegate to the corresponding acp_sdw_*() dispatch helpers.
Introduce a static const struct amd_sdw_hw_ops amd_acp63_hw_ops
table that populates all 19 hw_ops slots with the amd_acp63_*()
callbacks. Introduce amd_sdw_hw_init_ops() to assign a pointer
to this table based on acp_rev, and call it from
amd_sdw_manager_probe() to wire up the dispatch table at probe
time.
Convert all remaining direct amd_acp63_*() call sites in the
start, PM, interrupt, and remove paths to use the corresponding
acp_*() wrappers.
Place amd_acp63_hw_ops and amd_sdw_hw_init_ops() after
amd_sdw_manager_remove() so all amd_acp63_*() functions they
reference are already defined. Add a forward declaration of
amd_sdw_hw_init_ops() before amd_sdw_manager_probe() to resolve
the call site ordering.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 366 ++++++++++++++++++--------------
1 file changed, 210 insertions(+), 156 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 87a2e779dd4e..834e943b040b 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -303,8 +303,7 @@ amd_program_scp_addr(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg)
scp_msg.buf = &msg->addr_page1;
scp_msg.flags = SDW_MSG_FLAG_WRITE;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0);
- if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data,
- &response_buf[0])) {
+ if (acp_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response_buf[0])) {
dev_err_ratelimited(amd_manager->dev,
"SCP_addrpage command timeout for Slave %d\n", msg->dev_num);
return SDW_CMD_TIMEOUT;
@@ -312,8 +311,7 @@ amd_program_scp_addr(struct amd_sdw_manager *amd_manager, struct sdw_msg *msg)
scp_msg.addr = SDW_SCP_ADDRPAGE2;
scp_msg.buf = &msg->addr_page2;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, &scp_msg, 0);
- if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data,
- &response_buf[1])) {
+ if (acp_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response_buf[1])) {
dev_err_ratelimited(amd_manager->dev,
"SCP_addrpage command timeout for Slave %d\n", msg->dev_num);
return SDW_CMD_TIMEOUT;
@@ -386,7 +384,7 @@ static unsigned int _amd_sdw_xfer_msg(struct amd_sdw_manager *amd_manager, struc
u32 upper_data = 0, lower_data = 0;
amd_sdw_ctl_word_prep(&lower_data, &upper_data, msg, cmd_offset);
- if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response)) {
+ if (acp_sdw_send_cmd_get_resp(amd_manager, lower_data, upper_data, &response)) {
dev_err_ratelimited(amd_manager->dev, "command timeout for Slave %d\n",
msg->dev_num);
return SDW_CMD_TIMEOUT;
@@ -449,7 +447,7 @@ static void amd_acp63_sdw_read_and_process_ping_status(struct amd_sdw_manager *a
u64 response;
mutex_lock(&amd_manager->bus.msg_lock);
- if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
+ if (acp_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
mutex_unlock(&amd_manager->bus.msg_lock);
dev_err_ratelimited(amd_manager->dev, "SDW%x ping status timeout\n",
amd_manager->instance);
@@ -471,7 +469,7 @@ static u32 amd_acp63_sdw_read_ping_status(struct sdw_bus *bus)
/* Called by sdw_show_ping_status() which holds msg_lock. */
lockdep_assert_held(&bus->msg_lock);
- if (amd_acp63_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
+ if (acp_sdw_send_cmd_get_resp(amd_manager, 0, 0, &response)) {
dev_err_ratelimited(amd_manager->dev, "SDW%x ping status timeout\n",
amd_manager->instance);
return amd_manager->ping_slave_stat == U32_MAX ? 0 : amd_manager->ping_slave_stat;
@@ -974,7 +972,7 @@ static void amd_acp63_sdw_update_slave_status_work(struct amd_sdw_manager *amd_m
ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7);
writel(AMD_SDW_IRQ_MASK_8TO11, amd_manager->mmio +
ACP_SW_STATE_CHANGE_STATUS_MASK_8TO11);
- amd_acp63_sdw_read_and_process_ping_status(amd_manager);
+ acp_sdw_read_and_process_ping_status(amd_manager);
goto update_status;
} else {
dev_err_ratelimited(amd_manager->dev,
@@ -989,7 +987,7 @@ static void amd_sdw_update_slave_status_work(struct work_struct *work)
struct amd_sdw_manager *amd_manager =
container_of(work, struct amd_sdw_manager, amd_sdw_work);
- amd_acp63_sdw_update_slave_status_work(amd_manager);
+ acp_sdw_update_slave_status_work(amd_manager);
}
static void amd_sdw_update_slave_status(u32 status_change_0to7, u32 status_change_8to11,
@@ -1037,10 +1035,10 @@ static void amd_acp63_sdw_irq_thread(struct amd_sdw_manager *amd_manager)
dev_dbg(amd_manager->dev, "[SDW%d] SDW INT: 0to7=0x%x, 8to11=0x%x\n",
amd_manager->instance, status_change_0to7, status_change_8to11);
if (status_change_8to11 & AMD_SDW_WAKE_STAT_MASK)
- return amd_acp63_sdw_process_wake_event(amd_manager);
+ return acp_sdw_process_wake_event(amd_manager);
if (status_change_8to11 & AMD_SDW_PREQ_INTR_STAT) {
- amd_acp63_sdw_read_and_process_ping_status(amd_manager);
+ acp_sdw_read_and_process_ping_status(amd_manager);
} else {
/* Check for the updated status on peripheral device */
amd_sdw_update_slave_status(status_change_0to7, status_change_8to11, amd_manager);
@@ -1056,7 +1054,7 @@ static void amd_sdw_interrupt_thread(struct work_struct *work)
struct amd_sdw_manager *amd_manager =
container_of(work, struct amd_sdw_manager, amd_sdw_irq_thread);
- amd_acp63_sdw_irq_thread(amd_manager);
+ acp_sdw_irq_thread(amd_manager);
}
int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager)
@@ -1066,17 +1064,17 @@ int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager)
prop = &amd_manager->bus.prop;
if (!prop->hw_disabled) {
- ret = amd_acp63_sdw_clk_init_ctrl(amd_manager);
+ ret = acp_sdw_clk_init_ctrl(amd_manager);
if (ret)
return ret;
- ret = amd_acp63_init_sdw_manager(amd_manager);
+ ret = acp_init_sdw_manager(amd_manager);
if (ret)
return ret;
- amd_acp63_enable_sdw_interrupts(amd_manager);
- ret = amd_acp63_enable_sdw_manager(amd_manager);
+ acp_enable_sdw_interrupts(amd_manager);
+ ret = acp_enable_sdw_manager(amd_manager);
if (ret)
return ret;
- amd_acp63_sdw_set_frameshape(amd_manager);
+ acp_sdw_set_frameshape(amd_manager);
}
/* Enable runtime PM */
pm_runtime_set_autosuspend_delay(amd_manager->dev, AMD_SDW_MASTER_SUSPEND_DELAY_MS);
@@ -1087,117 +1085,6 @@ int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager)
return 0;
}
-static int amd_sdw_manager_probe(struct platform_device *pdev)
-{
- const struct acp_sdw_pdata *pdata = pdev->dev.platform_data;
- struct resource *res;
- struct device *dev = &pdev->dev;
- struct sdw_master_prop *prop;
- struct amd_sdw_manager *amd_manager;
- int ret;
-
- amd_manager = devm_kzalloc(dev, sizeof(struct amd_sdw_manager), GFP_KERNEL);
- if (!amd_manager)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENOMEM;
-
- amd_manager->acp_mmio = devm_ioremap(dev, res->start, resource_size(res));
- if (!amd_manager->acp_mmio) {
- dev_err(dev, "mmio not found\n");
- return -ENOMEM;
- }
- amd_manager->ping_slave_stat = U32_MAX;
- amd_manager->instance = pdata->instance;
- amd_manager->mmio = amd_manager->acp_mmio +
- (amd_manager->instance * ACP63_SDW_MANAGER_REG_OFFSET);
- amd_manager->acp_sdw_lock = pdata->acp_sdw_lock;
- amd_manager->acp_rev = pdata->acp_rev;
- amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS);
- amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS);
- amd_manager->dev = dev;
- amd_manager->bus.ops = &amd_acp63_sdw_ops;
- amd_manager->bus.port_ops = &amd_acp63_sdw_port_ops;
- amd_manager->bus.compute_params = &amd_acp63_sdw_compute_params;
- amd_manager->bus.clk_stop_timeout = 200;
- amd_manager->bus.link_id = amd_manager->instance;
-
- /*
- * Due to BIOS compatibility, the two links are exposed within
- * the scope of a single controller. If this changes, the
- * controller_id will have to be updated with drv_data
- * information.
- */
- amd_manager->bus.controller_id = 0;
- dev_dbg(dev, "acp_rev:0x%x\n", amd_manager->acp_rev);
- switch (amd_manager->acp_rev) {
- case ACP63_PCI_REV_ID:
- switch (amd_manager->instance) {
- case ACP_SDW0:
- amd_manager->num_dout_ports = AMD_ACP63_SDW0_MAX_TX_PORTS;
- amd_manager->num_din_ports = AMD_ACP63_SDW0_MAX_RX_PORTS;
- break;
- case ACP_SDW1:
- amd_manager->num_dout_ports = AMD_ACP63_SDW1_MAX_TX_PORTS;
- amd_manager->num_din_ports = AMD_ACP63_SDW1_MAX_RX_PORTS;
- break;
- default:
- return -EINVAL;
- }
- break;
- case ACP70_PCI_REV_ID:
- case ACP71_PCI_REV_ID:
- case ACP72_PCI_REV_ID:
- amd_manager->num_dout_ports = AMD_ACP70_SDW_MAX_TX_PORTS;
- amd_manager->num_din_ports = AMD_ACP70_SDW_MAX_RX_PORTS;
- break;
- default:
- return -EINVAL;
- }
- amd_manager->max_ports = amd_manager->num_dout_ports + amd_manager->num_din_ports;
- amd_manager->port_offset_map = devm_kcalloc(dev, amd_manager->max_ports,
- sizeof(int), GFP_KERNEL);
- if (!amd_manager->port_offset_map)
- return -ENOMEM;
-
- prop = &amd_manager->bus.prop;
- prop->mclk_freq = AMD_SDW_BUS_BASE_FREQ;
-
- ret = sdw_bus_master_add(&amd_manager->bus, dev, dev->fwnode);
- if (ret) {
- dev_err(dev, "Failed to register SoundWire manager(%d)\n", ret);
- return ret;
- }
- ret = amd_sdw_register_dais(amd_manager);
- if (ret) {
- dev_err(dev, "CPU DAI registration failed\n");
- sdw_bus_master_delete(&amd_manager->bus);
- return ret;
- }
- dev_set_drvdata(dev, amd_manager);
- INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_interrupt_thread);
- INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work);
- return 0;
-}
-
-static void amd_sdw_manager_remove(struct platform_device *pdev)
-{
- struct amd_sdw_manager *amd_manager = dev_get_drvdata(&pdev->dev);
- int ret;
-
- if (pm_runtime_enabled(&pdev->dev))
- pm_runtime_disable(&pdev->dev);
- amd_acp63_disable_sdw_interrupts(amd_manager);
- cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
- cancel_work_sync(&amd_manager->amd_sdw_work);
- sdw_bus_master_delete(&amd_manager->bus);
- ret = amd_acp63_disable_sdw_manager(amd_manager);
- if (ret)
- dev_err(&pdev->dev, "Failed to disable device (%pe)\n", ERR_PTR(ret));
-}
-
/*
* AMD SoundWire clock-stop sequence shared across all ACP revisions.
* Differences between revisions in this path are minimal; a switch/case
@@ -1327,7 +1214,7 @@ static int amd_sdw_host_wake_enable_by_rev(struct amd_sdw_manager *amd_manager,
case ACP70_PCI_REV_ID:
case ACP71_PCI_REV_ID:
case ACP72_PCI_REV_ID:
- return amd_acp63_sdw_host_wake_enable(amd_manager, enable);
+ return acp_sdw_host_wake_enable(amd_manager, enable);
default:
dev_err(amd_manager->dev, "unexpected acp_rev 0x%x\n", amd_manager->acp_rev);
return -EINVAL;
@@ -1335,9 +1222,8 @@ static int amd_sdw_host_wake_enable_by_rev(struct amd_sdw_manager *amd_manager,
return 0;
}
-static int __maybe_unused amd_suspend(struct device *dev)
+static int amd_acp63_sdw_suspend(struct amd_sdw_manager *amd_manager)
{
- struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
struct sdw_bus *bus = &amd_manager->bus;
int ret;
@@ -1348,22 +1234,22 @@ static int __maybe_unused amd_suspend(struct device *dev)
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
- amd_acp63_disable_sdw_interrupts(amd_manager);
+ acp_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
- amd_acp63_sdw_wake_enable(amd_manager, false);
+ acp_sdw_wake_enable(amd_manager, false);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
if (ret)
return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- amd_acp63_enable_sdw_interrupts(amd_manager);
+ acp_enable_sdw_interrupts(amd_manager);
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
- amd_acp63_disable_sdw_interrupts(amd_manager);
+ acp_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
- amd_acp63_sdw_wake_enable(amd_manager, false);
+ acp_sdw_wake_enable(amd_manager, false);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
if (ret)
return ret;
@@ -1374,7 +1260,7 @@ static int __maybe_unused amd_suspend(struct device *dev)
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- ret = amd_acp63_disable_sdw_manager(amd_manager);
+ ret = acp_disable_sdw_manager(amd_manager);
if (ret)
return ret;
}
@@ -1384,7 +1270,7 @@ static int __maybe_unused amd_suspend(struct device *dev)
case ACP70_PCI_REV_ID:
case ACP71_PCI_REV_ID:
case ACP72_PCI_REV_ID:
- ret = amd_acp63_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
+ ret = acp_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
if (ret)
return ret;
break;
@@ -1395,9 +1281,8 @@ static int __maybe_unused amd_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused amd_suspend_runtime(struct device *dev)
+static int amd_acp63_sdw_suspend_runtime(struct amd_sdw_manager *amd_manager)
{
- struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
struct sdw_bus *bus = &amd_manager->bus;
int ret;
u32 val;
@@ -1408,29 +1293,29 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
return 0;
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
- amd_acp63_disable_sdw_interrupts(amd_manager);
+ acp_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
- amd_acp63_sdw_wake_enable(amd_manager, true);
+ acp_sdw_wake_enable(amd_manager, true);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, true);
if (ret)
return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- amd_acp63_enable_sdw_interrupts(amd_manager);
+ acp_enable_sdw_interrupts(amd_manager);
} else if (amd_manager->power_mode_mask & AMD_SDW_POWER_OFF_MODE) {
- amd_acp63_disable_sdw_interrupts(amd_manager);
+ acp_disable_sdw_interrupts(amd_manager);
cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
cancel_work_sync(&amd_manager->amd_sdw_work);
- amd_acp63_sdw_wake_enable(amd_manager, true);
+ acp_sdw_wake_enable(amd_manager, true);
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, true);
if (ret)
return ret;
ret = amd_sdw_clock_stop(amd_manager);
if (ret)
return ret;
- ret = amd_acp63_disable_sdw_manager(amd_manager);
+ ret = acp_disable_sdw_manager(amd_manager);
if (ret)
return ret;
}
@@ -1440,7 +1325,7 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
case ACP70_PCI_REV_ID:
case ACP71_PCI_REV_ID:
case ACP72_PCI_REV_ID:
- ret = amd_acp63_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
+ ret = acp_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D3);
if (ret)
return ret;
if (amd_manager->wake_en_mask) {
@@ -1459,9 +1344,8 @@ static int __maybe_unused amd_suspend_runtime(struct device *dev)
return 0;
}
-static int __maybe_unused amd_resume_runtime(struct device *dev)
+static int amd_acp63_sdw_resume_runtime(struct amd_sdw_manager *amd_manager)
{
- struct amd_sdw_manager *amd_manager = dev_get_drvdata(dev);
struct sdw_bus *bus = &amd_manager->bus;
int ret;
u32 val;
@@ -1473,7 +1357,7 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
}
if (amd_manager->power_mode_mask & AMD_SDW_CLK_STOP_MODE) {
- ret = amd_acp63_sdw_clock_stop_exit(amd_manager);
+ ret = acp_sdw_clock_stop_exit(amd_manager);
if (ret)
return ret;
ret = amd_sdw_host_wake_enable_by_rev(amd_manager, false);
@@ -1508,17 +1392,17 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
}
}
sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
- ret = amd_acp63_sdw_clk_init_ctrl(amd_manager);
+ ret = acp_sdw_clk_init_ctrl(amd_manager);
if (ret)
return ret;
- ret = amd_acp63_init_sdw_manager(amd_manager);
+ ret = acp_init_sdw_manager(amd_manager);
if (ret)
return ret;
- amd_acp63_enable_sdw_interrupts(amd_manager);
- ret = amd_acp63_enable_sdw_manager(amd_manager);
+ acp_enable_sdw_interrupts(amd_manager);
+ ret = acp_enable_sdw_manager(amd_manager);
if (ret)
return ret;
- amd_acp63_sdw_set_frameshape(amd_manager);
+ acp_sdw_set_frameshape(amd_manager);
}
switch (amd_manager->acp_rev) {
case ACP63_PCI_REV_ID:
@@ -1526,7 +1410,7 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
case ACP70_PCI_REV_ID:
case ACP71_PCI_REV_ID:
case ACP72_PCI_REV_ID:
- ret = amd_acp63_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D0);
+ ret = acp_sdw_set_device_state(amd_manager, AMD_SDW_DEVICE_STATE_D0);
if (ret)
return ret;
break;
@@ -1537,6 +1421,176 @@ static int __maybe_unused amd_resume_runtime(struct device *dev)
return 0;
}
+static int __maybe_unused amd_suspend(struct device *dev)
+{
+ return acp_sdw_suspend(dev);
+}
+
+static int __maybe_unused amd_suspend_runtime(struct device *dev)
+{
+ return acp_sdw_suspend_runtime(dev);
+}
+
+static int __maybe_unused amd_resume_runtime(struct device *dev)
+{
+ return acp_sdw_resume_runtime(dev);
+}
+
+static int amd_sdw_hw_init_ops(struct amd_sdw_manager *amd_manager);
+
+static int amd_sdw_manager_probe(struct platform_device *pdev)
+{
+ const struct acp_sdw_pdata *pdata = pdev->dev.platform_data;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct sdw_master_prop *prop;
+ struct amd_sdw_manager *amd_manager;
+ int ret;
+
+ amd_manager = devm_kzalloc(dev, sizeof(struct amd_sdw_manager), GFP_KERNEL);
+ if (!amd_manager)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOMEM;
+
+ amd_manager->acp_mmio = devm_ioremap(dev, res->start, resource_size(res));
+ if (!amd_manager->acp_mmio) {
+ dev_err(dev, "mmio not found\n");
+ return -ENOMEM;
+ }
+ amd_manager->ping_slave_stat = U32_MAX;
+ amd_manager->instance = pdata->instance;
+ amd_manager->mmio = amd_manager->acp_mmio +
+ (amd_manager->instance * ACP63_SDW_MANAGER_REG_OFFSET);
+ amd_manager->acp_sdw_lock = pdata->acp_sdw_lock;
+ amd_manager->acp_rev = pdata->acp_rev;
+ amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS);
+ amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS);
+ amd_manager->dev = dev;
+ amd_manager->bus.ops = &amd_acp63_sdw_ops;
+ amd_manager->bus.port_ops = &amd_acp63_sdw_port_ops;
+ amd_manager->bus.compute_params = &amd_acp63_sdw_compute_params;
+ amd_manager->bus.clk_stop_timeout = 200;
+ amd_manager->bus.link_id = amd_manager->instance;
+ ret = amd_sdw_hw_init_ops(amd_manager);
+ if (ret) {
+ dev_err(dev, "Failed to initialize hw ops (%d)\n", ret);
+ return ret;
+ }
+
+ /*
+ * Due to BIOS compatibility, the two links are exposed within
+ * the scope of a single controller. If this changes, the
+ * controller_id will have to be updated with drv_data
+ * information.
+ */
+ amd_manager->bus.controller_id = 0;
+ dev_dbg(dev, "acp_rev:0x%x\n", amd_manager->acp_rev);
+ switch (amd_manager->acp_rev) {
+ case ACP63_PCI_REV_ID:
+ switch (amd_manager->instance) {
+ case ACP_SDW0:
+ amd_manager->num_dout_ports = AMD_ACP63_SDW0_MAX_TX_PORTS;
+ amd_manager->num_din_ports = AMD_ACP63_SDW0_MAX_RX_PORTS;
+ break;
+ case ACP_SDW1:
+ amd_manager->num_dout_ports = AMD_ACP63_SDW1_MAX_TX_PORTS;
+ amd_manager->num_din_ports = AMD_ACP63_SDW1_MAX_RX_PORTS;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case ACP70_PCI_REV_ID:
+ case ACP71_PCI_REV_ID:
+ case ACP72_PCI_REV_ID:
+ amd_manager->num_dout_ports = AMD_ACP70_SDW_MAX_TX_PORTS;
+ amd_manager->num_din_ports = AMD_ACP70_SDW_MAX_RX_PORTS;
+ break;
+ default:
+ return -EINVAL;
+ }
+ amd_manager->max_ports = amd_manager->num_dout_ports + amd_manager->num_din_ports;
+ amd_manager->port_offset_map = devm_kcalloc(dev, amd_manager->max_ports,
+ sizeof(int), GFP_KERNEL);
+ if (!amd_manager->port_offset_map)
+ return -ENOMEM;
+
+ prop = &amd_manager->bus.prop;
+ prop->mclk_freq = AMD_SDW_BUS_BASE_FREQ;
+
+ ret = sdw_bus_master_add(&amd_manager->bus, dev, dev->fwnode);
+ if (ret) {
+ dev_err(dev, "Failed to register SoundWire manager(%d)\n", ret);
+ return ret;
+ }
+ ret = amd_sdw_register_dais(amd_manager);
+ if (ret) {
+ dev_err(dev, "CPU DAI registration failed\n");
+ sdw_bus_master_delete(&amd_manager->bus);
+ return ret;
+ }
+ dev_set_drvdata(dev, amd_manager);
+ INIT_WORK(&amd_manager->amd_sdw_irq_thread, amd_sdw_interrupt_thread);
+ INIT_WORK(&amd_manager->amd_sdw_work, amd_sdw_update_slave_status_work);
+ return 0;
+}
+
+static void amd_sdw_manager_remove(struct platform_device *pdev)
+{
+ struct amd_sdw_manager *amd_manager = dev_get_drvdata(&pdev->dev);
+ int ret;
+
+ if (pm_runtime_enabled(&pdev->dev))
+ pm_runtime_disable(&pdev->dev);
+ acp_disable_sdw_interrupts(amd_manager);
+ cancel_work_sync(&amd_manager->amd_sdw_irq_thread);
+ cancel_work_sync(&amd_manager->amd_sdw_work);
+ sdw_bus_master_delete(&amd_manager->bus);
+ ret = acp_disable_sdw_manager(amd_manager);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to disable device (%pe)\n", ERR_PTR(ret));
+}
+
+static const struct amd_sdw_hw_ops amd_acp63_hw_ops = {
+ .init_sdw_manager = amd_acp63_init_sdw_manager,
+ .enable_sdw_manager = amd_acp63_enable_sdw_manager,
+ .disable_sdw_manager = amd_acp63_disable_sdw_manager,
+ .enable_sdw_interrupts = amd_acp63_enable_sdw_interrupts,
+ .disable_sdw_interrupts = amd_acp63_disable_sdw_interrupts,
+ .set_frameshape = amd_acp63_sdw_set_frameshape,
+ .send_cmd_get_resp = amd_acp63_sdw_send_cmd_get_resp,
+ .wake_enable = amd_acp63_sdw_wake_enable,
+ .host_wake_enable = amd_acp63_sdw_host_wake_enable,
+ .set_device_state = amd_acp63_sdw_set_device_state,
+ .read_and_process_ping_status = amd_acp63_sdw_read_and_process_ping_status,
+ .process_wake_event = amd_acp63_sdw_process_wake_event,
+ .irq_thread = amd_acp63_sdw_irq_thread,
+ .update_slave_status_work = amd_acp63_sdw_update_slave_status_work,
+ .clk_init_ctrl = amd_acp63_sdw_clk_init_ctrl,
+ .clock_stop_exit = amd_acp63_sdw_clock_stop_exit,
+ .suspend = amd_acp63_sdw_suspend,
+ .suspend_runtime = amd_acp63_sdw_suspend_runtime,
+ .resume_runtime = amd_acp63_sdw_resume_runtime,
+};
+
+static int amd_sdw_hw_init_ops(struct amd_sdw_manager *amd_manager)
+{
+ switch (amd_manager->acp_rev) {
+ case ACP63_PCI_REV_ID:
+ case ACP70_PCI_REV_ID:
+ case ACP71_PCI_REV_ID:
+ case ACP72_PCI_REV_ID:
+ amd_manager->hw_ops = &amd_acp63_hw_ops;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static const struct dev_pm_ops amd_pm = {
.prepare = amd_pm_prepare,
SET_SYSTEM_SLEEP_PM_OPS(amd_suspend, amd_resume_runtime)
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 9/9] soundwire: amd: consolidate revision-specific probe setup
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
` (7 preceding siblings ...)
2026-09-17 9:02 ` [PATCH 8/9] soundwire: amd: wire amd_acp63_*() call sites through acp_*() helpers Vijendar Mukunda
@ 2026-09-17 9:02 ` Vijendar Mukunda
8 siblings, 0 replies; 14+ messages in thread
From: Vijendar Mukunda @ 2026-09-17 9:02 UTC (permalink / raw)
To: vkoul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel, Vijendar Mukunda
Determine port counts first via a switch on acp_rev, compute max_ports,
then consolidate all remaining revision-specific assignments
(mmio offset, bus ops, port ops, compute_params, and port_offset_map
allocation) into a single second switch. Both switches reject unknown
revisions with dev_err() and -EINVAL, keeping each switch
self-contained so an incomplete addition of a new revision is caught
at whichever switch it is missing from.
cols_index and rows_index are no longer initialised at probe time;
acp_sdw_clk_init_ctrl() sets them from the actual bus clock and frame
shape before amd_acp63_sdw_set_frameshape() is ever called, so no
early initialisation is needed.
Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
drivers/soundwire/amd_manager.c | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)
diff --git a/drivers/soundwire/amd_manager.c b/drivers/soundwire/amd_manager.c
index 834e943b040b..c660f4c8d0e6 100644
--- a/drivers/soundwire/amd_manager.c
+++ b/drivers/soundwire/amd_manager.c
@@ -1462,16 +1462,9 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
}
amd_manager->ping_slave_stat = U32_MAX;
amd_manager->instance = pdata->instance;
- amd_manager->mmio = amd_manager->acp_mmio +
- (amd_manager->instance * ACP63_SDW_MANAGER_REG_OFFSET);
amd_manager->acp_sdw_lock = pdata->acp_sdw_lock;
amd_manager->acp_rev = pdata->acp_rev;
- amd_manager->cols_index = sdw_find_col_index(AMD_SDW_DEFAULT_COLUMNS);
- amd_manager->rows_index = sdw_find_row_index(AMD_SDW_DEFAULT_ROWS);
amd_manager->dev = dev;
- amd_manager->bus.ops = &amd_acp63_sdw_ops;
- amd_manager->bus.port_ops = &amd_acp63_sdw_port_ops;
- amd_manager->bus.compute_params = &amd_acp63_sdw_compute_params;
amd_manager->bus.clk_stop_timeout = 200;
amd_manager->bus.link_id = amd_manager->instance;
ret = amd_sdw_hw_init_ops(amd_manager);
@@ -1510,13 +1503,30 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
amd_manager->num_din_ports = AMD_ACP70_SDW_MAX_RX_PORTS;
break;
default:
+ dev_err(dev, "unsupported ACP revision: 0x%x\n", amd_manager->acp_rev);
return -EINVAL;
}
amd_manager->max_ports = amd_manager->num_dout_ports + amd_manager->num_din_ports;
- amd_manager->port_offset_map = devm_kcalloc(dev, amd_manager->max_ports,
- sizeof(int), GFP_KERNEL);
- if (!amd_manager->port_offset_map)
- return -ENOMEM;
+
+ switch (amd_manager->acp_rev) {
+ case ACP63_PCI_REV_ID:
+ case ACP70_PCI_REV_ID:
+ case ACP71_PCI_REV_ID:
+ case ACP72_PCI_REV_ID:
+ amd_manager->mmio = amd_manager->acp_mmio +
+ (amd_manager->instance * ACP63_SDW_MANAGER_REG_OFFSET);
+ amd_manager->bus.ops = &amd_acp63_sdw_ops;
+ amd_manager->bus.port_ops = &amd_acp63_sdw_port_ops;
+ amd_manager->bus.compute_params = &amd_acp63_sdw_compute_params;
+ amd_manager->port_offset_map = devm_kcalloc(dev, amd_manager->max_ports,
+ sizeof(int), GFP_KERNEL);
+ if (!amd_manager->port_offset_map)
+ return -ENOMEM;
+ break;
+ default:
+ dev_err(dev, "unsupported ACP revision: 0x%x\n", amd_manager->acp_rev);
+ return -EINVAL;
+ }
prop = &amd_manager->bus.prop;
prop->mclk_freq = AMD_SDW_BUS_BASE_FREQ;
--
2.48.1
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 3/9] soundwire: amd: allocate sdw_amd_ctx pdev array dynamically
2026-09-17 9:02 ` [PATCH 3/9] soundwire: amd: allocate sdw_amd_ctx pdev array dynamically Vijendar Mukunda
@ 2026-10-03 7:52 ` Vinod Koul
2026-10-05 6:38 ` Mukunda,Vijendar
0 siblings, 1 reply; 14+ messages in thread
From: Vinod Koul @ 2026-10-03 7:52 UTC (permalink / raw)
To: Vijendar Mukunda
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel
On 17-09-26, 14:32, Vijendar Mukunda wrote:
> Replace the fixed-size pdev[AMD_ACP63_SDW_MAX_MANAGER_COUNT] member of
> struct sdw_amd_ctx with a dynamically allocated pointer array. The array
> is sized by max_manager_count via kcalloc() in sdw_amd_probe_controller()
> and freed on all error paths and in sdw_amd_cleanup().
>
> Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
> ---
> drivers/soundwire/amd_init.c | 12 ++++++++++++
> include/linux/soundwire/sdw_amd.h | 2 +-
> 2 files changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c
> index 15d117172bdb..94d766b3f8af 100644
> --- a/drivers/soundwire/amd_init.c
> +++ b/drivers/soundwire/amd_init.c
> @@ -62,6 +62,7 @@ static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
> continue;
> platform_device_unregister(ctx->pdev[i]);
> }
> + kfree(ctx->pdev);
>
> return 0;
> }
> @@ -116,8 +117,16 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
>
> ctx->count = count;
> ctx->link_mask = res->link_mask;
> +
> + ctx->pdev = kcalloc(max_manager_count, sizeof(*ctx->pdev), GFP_KERNEL);
why not use managed api for this?
> + if (!ctx->pdev) {
> + kfree(ctx);
> + return NULL;
> + }
> +
> struct resource *sdw_res __free(kfree) = kzalloc_obj(*sdw_res);
> if (!sdw_res) {
> + kfree(ctx->pdev);
> kfree(ctx);
> return NULL;
> }
> @@ -127,6 +136,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
>
> sdw_pdata = kcalloc(max_manager_count, sizeof(*sdw_pdata), GFP_KERNEL);
> if (!sdw_pdata) {
> + kfree(ctx->pdev);
> kfree(ctx);
> return NULL;
> }
> @@ -134,6 +144,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
> pdevinfo = kcalloc(max_manager_count, sizeof(*pdevinfo), GFP_KERNEL);
> if (!pdevinfo) {
> kfree(sdw_pdata);
> + kfree(ctx->pdev);
> kfree(ctx);
> return NULL;
> }
> @@ -171,6 +182,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
>
> kfree(pdevinfo);
> kfree(sdw_pdata);
> + kfree(ctx->pdev);
> kfree(ctx);
> return NULL;
> }
> diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
> index 40ba84c3b2cc..476de2c30389 100644
> --- a/include/linux/soundwire/sdw_amd.h
> +++ b/include/linux/soundwire/sdw_amd.h
> @@ -139,7 +139,7 @@ struct sdw_amd_acpi_info {
> struct sdw_amd_ctx {
> int count;
> u32 link_mask;
> - struct platform_device *pdev[AMD_ACP63_SDW_MAX_MANAGER_COUNT];
> + struct platform_device **pdev;
> struct sdw_peripherals *peripherals;
> };
>
> --
> 2.48.1
--
~Vinod
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 6/9] soundwire: amd: introduce struct amd_sdw_hw_ops dispatch framework
2026-09-17 9:02 ` [PATCH 6/9] soundwire: amd: introduce struct amd_sdw_hw_ops dispatch framework Vijendar Mukunda
@ 2026-10-03 7:56 ` Vinod Koul
2026-10-05 6:43 ` Mukunda,Vijendar
0 siblings, 1 reply; 14+ messages in thread
From: Vinod Koul @ 2026-10-03 7:56 UTC (permalink / raw)
To: Vijendar Mukunda
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel
On 17-09-26, 14:32, Vijendar Mukunda wrote:
> Add struct amd_sdw_hw_ops, a function-pointer dispatch table for
> hardware-revision-specific SoundWire manager operations. Add inline
> dispatch helpers for each callback and a const hw_ops pointer in
> struct amd_sdw_manager.
>
> The irq_thread and update_slave_status_work slots take
> struct amd_sdw_manager * so that different ACP revisions can register
> different handler logic. hw_ops is populated and call sites are wired
> through the dispatch helpers in subsequent patches.
Lets solve with one more level! Do you really need this...
>
> Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
> ---
> drivers/soundwire/amd_manager.h | 193 ++++++++++++++++++++++++++++++
> include/linux/soundwire/sdw_amd.h | 4 +
> 2 files changed, 197 insertions(+)
>
> diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h
> index 63fecff62079..2d08c6edd018 100644
> --- a/drivers/soundwire/amd_manager.h
> +++ b/drivers/soundwire/amd_manager.h
> @@ -274,4 +274,197 @@ static u32 sdw_manager_reg_mask_array[AMD_ACP63_SDW_MAX_MANAGER_COUNT] = {
> AMD_SDW0_EXT_INTR_MASK,
> AMD_SDW1_EXT_INTR_MASK
> };
> +
> +#define AMD_SDW_HW_OPS(amd_manager, cb) ((amd_manager)->hw_ops->cb)
> +
> +/**
> + * struct amd_sdw_hw_ops - hardware-revision-specific SoundWire manager ops
> + *
> + * @init_sdw_manager: enable the SoundWire manager hardware and perform bus reset
> + * @enable_sdw_manager: set the manager enable bit and wait for it to assert
> + * @disable_sdw_manager: clear the manager enable bit and wait for it to deassert
> + * @enable_sdw_interrupts: unmask ACP-level and per-manager interrupt bits
> + * @disable_sdw_interrupts: mask ACP-level and per-manager interrupt bits
> + * @set_frameshape: write the row/column frame-shape register
> + * @send_cmd_get_resp: issue an immediate command and return the response;
> + * returns 0 on success with the raw u64 response in @response,
> + * or negative on hardware timeout
> + * @wake_enable: enable or disable the in-band SoundWire wake interrupt
> + * @host_wake_enable: enable or disable the host-side wake interrupt
> + * @set_device_state: write the D0/D3 device power state for the manager instance
> + * @read_and_process_ping_status: issue a PING command and process the slave
> + * attach/detach status; called from the IRQ work path
> + * @process_wake_event: handle an in-band wake notification from a slave
> + * @irq_thread: hw_ops callback invoked by the thin work_struct wrapper on
> + * each interrupt; reads status registers and dispatches slave events
> + * @update_slave_status_work: hw_ops callback invoked by the status-update
> + * work item; reads slave status and updates the SoundWire core
> + * @clk_init_ctrl: set the clock divider and update the frame shape registers
> + * based on the current bus clock frequency
> + * @clock_stop_exit: restart the SoundWire bus clock after a CLK_STOP_MODE
> + * suspend; implementation differs across ACP revisions
> + * @suspend: system-suspend hook; stops the bus and powers down the manager
> + * @suspend_runtime: runtime-suspend hook; same sequence as @suspend
> + * @resume_runtime: runtime-resume hook; reinitialises the manager and restarts
> + * the bus after a POWER_OFF_MODE or CLK_STOP_MODE suspend
> + */
> +struct amd_sdw_hw_ops {
> + int (*init_sdw_manager)(struct amd_sdw_manager *amd_manager);
> + int (*enable_sdw_manager)(struct amd_sdw_manager *amd_manager);
> + int (*disable_sdw_manager)(struct amd_sdw_manager *amd_manager);
> + void (*enable_sdw_interrupts)(struct amd_sdw_manager *amd_manager);
> + void (*disable_sdw_interrupts)(struct amd_sdw_manager *amd_manager);
> + void (*set_frameshape)(struct amd_sdw_manager *amd_manager);
> + int (*send_cmd_get_resp)(struct amd_sdw_manager *amd_manager, u32 lower_data,
> + u32 upper_data, u64 *response);
> + void (*wake_enable)(struct amd_sdw_manager *amd_manager, bool enable);
> + int (*host_wake_enable)(struct amd_sdw_manager *amd_manager, bool enable);
> + int (*set_device_state)(struct amd_sdw_manager *amd_manager, u32 target_device_state);
> + void (*read_and_process_ping_status)(struct amd_sdw_manager *amd_manager);
> + void (*process_wake_event)(struct amd_sdw_manager *amd_manager);
> + void (*irq_thread)(struct amd_sdw_manager *amd_manager);
> + void (*update_slave_status_work)(struct amd_sdw_manager *amd_manager);
> + int (*clk_init_ctrl)(struct amd_sdw_manager *amd_manager);
> + int (*clock_stop_exit)(struct amd_sdw_manager *amd_manager);
> + int (*suspend)(struct amd_sdw_manager *amd_manager);
> + int (*suspend_runtime)(struct amd_sdw_manager *amd_manager);
> + int (*resume_runtime)(struct amd_sdw_manager *amd_manager);
I would suggest splitting the driver and add common code to a lib and
have specific drivers for older and new gen platforms...
--
~Vinod
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/9] soundwire: amd: allocate sdw_amd_ctx pdev array dynamically
2026-10-03 7:52 ` Vinod Koul
@ 2026-10-05 6:38 ` Mukunda,Vijendar
0 siblings, 0 replies; 14+ messages in thread
From: Mukunda,Vijendar @ 2026-10-05 6:38 UTC (permalink / raw)
To: Vinod Koul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel
On 03/10/26 13:22, Vinod Koul wrote:
> On 17-09-26, 14:32, Vijendar Mukunda wrote:
>> Replace the fixed-size pdev[AMD_ACP63_SDW_MAX_MANAGER_COUNT] member of
>> struct sdw_amd_ctx with a dynamically allocated pointer array. The array
>> is sized by max_manager_count via kcalloc() in sdw_amd_probe_controller()
>> and freed on all error paths and in sdw_amd_cleanup().
>>
>> Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
>> ---
>> drivers/soundwire/amd_init.c | 12 ++++++++++++
>> include/linux/soundwire/sdw_amd.h | 2 +-
>> 2 files changed, 13 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/soundwire/amd_init.c b/drivers/soundwire/amd_init.c
>> index 15d117172bdb..94d766b3f8af 100644
>> --- a/drivers/soundwire/amd_init.c
>> +++ b/drivers/soundwire/amd_init.c
>> @@ -62,6 +62,7 @@ static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
>> continue;
>> platform_device_unregister(ctx->pdev[i]);
>> }
>> + kfree(ctx->pdev);
>>
>> return 0;
>> }
>> @@ -116,8 +117,16 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
>>
>> ctx->count = count;
>> ctx->link_mask = res->link_mask;
>> +
>> + ctx->pdev = kcalloc(max_manager_count, sizeof(*ctx->pdev), GFP_KERNEL);
> why not use managed api for this?
The reason devm_kcalloc() cannot be used here is that
sdw_amd_cleanup() explicitly frees ctx->pdev using kfree().
If devm_kcalloc(res->parent, ...) were used, the allocation
would also be tracked by devres and freed automatically during
device unbind, resulting in a double-free.
Therefore, the existing manual alloc/free lifecycle is
intentional.
>> + if (!ctx->pdev) {
>> + kfree(ctx);
>> + return NULL;
>> + }
>> +
>> struct resource *sdw_res __free(kfree) = kzalloc_obj(*sdw_res);
>> if (!sdw_res) {
>> + kfree(ctx->pdev);
>> kfree(ctx);
>> return NULL;
>> }
>> @@ -127,6 +136,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
>>
>> sdw_pdata = kcalloc(max_manager_count, sizeof(*sdw_pdata), GFP_KERNEL);
>> if (!sdw_pdata) {
>> + kfree(ctx->pdev);
>> kfree(ctx);
>> return NULL;
>> }
>> @@ -134,6 +144,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
>> pdevinfo = kcalloc(max_manager_count, sizeof(*pdevinfo), GFP_KERNEL);
>> if (!pdevinfo) {
>> kfree(sdw_pdata);
>> + kfree(ctx->pdev);
>> kfree(ctx);
>> return NULL;
>> }
>> @@ -171,6 +182,7 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
>>
>> kfree(pdevinfo);
>> kfree(sdw_pdata);
>> + kfree(ctx->pdev);
>> kfree(ctx);
>> return NULL;
>> }
>> diff --git a/include/linux/soundwire/sdw_amd.h b/include/linux/soundwire/sdw_amd.h
>> index 40ba84c3b2cc..476de2c30389 100644
>> --- a/include/linux/soundwire/sdw_amd.h
>> +++ b/include/linux/soundwire/sdw_amd.h
>> @@ -139,7 +139,7 @@ struct sdw_amd_acpi_info {
>> struct sdw_amd_ctx {
>> int count;
>> u32 link_mask;
>> - struct platform_device *pdev[AMD_ACP63_SDW_MAX_MANAGER_COUNT];
>> + struct platform_device **pdev;
>> struct sdw_peripherals *peripherals;
>> };
>>
>> --
>> 2.48.1
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 6/9] soundwire: amd: introduce struct amd_sdw_hw_ops dispatch framework
2026-10-03 7:56 ` Vinod Koul
@ 2026-10-05 6:43 ` Mukunda,Vijendar
0 siblings, 0 replies; 14+ messages in thread
From: Mukunda,Vijendar @ 2026-10-05 6:43 UTC (permalink / raw)
To: Vinod Koul
Cc: broonie, alsa-devel, yung-chuan.liao, pierre-louis.bossart,
Basavaraj.Hiregoudar, Sunil-kumar.Dommati, venkataprasad.potturu,
Syed.SabaKareem, Mario.Limonciello, Richard.Gong, linux-sound,
linux-kernel
On 03/10/26 13:26, Vinod Koul wrote:
> On 17-09-26, 14:32, Vijendar Mukunda wrote:
>> Add struct amd_sdw_hw_ops, a function-pointer dispatch table for
>> hardware-revision-specific SoundWire manager operations. Add inline
>> dispatch helpers for each callback and a const hw_ops pointer in
>> struct amd_sdw_manager.
>>
>> The irq_thread and update_slave_status_work slots take
>> struct amd_sdw_manager * so that different ACP revisions can register
>> different handler logic. hw_ops is populated and call sites are wired
>> through the dispatch helpers in subsequent patches.
> Lets solve with one more level! Do you really need this...
Agreed. We can drop it. Will modify the code and respin the patch series.
>
>> Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
>> ---
>> drivers/soundwire/amd_manager.h | 193 ++++++++++++++++++++++++++++++
>> include/linux/soundwire/sdw_amd.h | 4 +
>> 2 files changed, 197 insertions(+)
>>
>> diff --git a/drivers/soundwire/amd_manager.h b/drivers/soundwire/amd_manager.h
>> index 63fecff62079..2d08c6edd018 100644
>> --- a/drivers/soundwire/amd_manager.h
>> +++ b/drivers/soundwire/amd_manager.h
>> @@ -274,4 +274,197 @@ static u32 sdw_manager_reg_mask_array[AMD_ACP63_SDW_MAX_MANAGER_COUNT] = {
>> AMD_SDW0_EXT_INTR_MASK,
>> AMD_SDW1_EXT_INTR_MASK
>> };
>> +
>> +#define AMD_SDW_HW_OPS(amd_manager, cb) ((amd_manager)->hw_ops->cb)
>> +
>> +/**
>> + * struct amd_sdw_hw_ops - hardware-revision-specific SoundWire manager ops
>> + *
>> + * @init_sdw_manager: enable the SoundWire manager hardware and perform bus reset
>> + * @enable_sdw_manager: set the manager enable bit and wait for it to assert
>> + * @disable_sdw_manager: clear the manager enable bit and wait for it to deassert
>> + * @enable_sdw_interrupts: unmask ACP-level and per-manager interrupt bits
>> + * @disable_sdw_interrupts: mask ACP-level and per-manager interrupt bits
>> + * @set_frameshape: write the row/column frame-shape register
>> + * @send_cmd_get_resp: issue an immediate command and return the response;
>> + * returns 0 on success with the raw u64 response in @response,
>> + * or negative on hardware timeout
>> + * @wake_enable: enable or disable the in-band SoundWire wake interrupt
>> + * @host_wake_enable: enable or disable the host-side wake interrupt
>> + * @set_device_state: write the D0/D3 device power state for the manager instance
>> + * @read_and_process_ping_status: issue a PING command and process the slave
>> + * attach/detach status; called from the IRQ work path
>> + * @process_wake_event: handle an in-band wake notification from a slave
>> + * @irq_thread: hw_ops callback invoked by the thin work_struct wrapper on
>> + * each interrupt; reads status registers and dispatches slave events
>> + * @update_slave_status_work: hw_ops callback invoked by the status-update
>> + * work item; reads slave status and updates the SoundWire core
>> + * @clk_init_ctrl: set the clock divider and update the frame shape registers
>> + * based on the current bus clock frequency
>> + * @clock_stop_exit: restart the SoundWire bus clock after a CLK_STOP_MODE
>> + * suspend; implementation differs across ACP revisions
>> + * @suspend: system-suspend hook; stops the bus and powers down the manager
>> + * @suspend_runtime: runtime-suspend hook; same sequence as @suspend
>> + * @resume_runtime: runtime-resume hook; reinitialises the manager and restarts
>> + * the bus after a POWER_OFF_MODE or CLK_STOP_MODE suspend
>> + */
>> +struct amd_sdw_hw_ops {
>> + int (*init_sdw_manager)(struct amd_sdw_manager *amd_manager);
>> + int (*enable_sdw_manager)(struct amd_sdw_manager *amd_manager);
>> + int (*disable_sdw_manager)(struct amd_sdw_manager *amd_manager);
>> + void (*enable_sdw_interrupts)(struct amd_sdw_manager *amd_manager);
>> + void (*disable_sdw_interrupts)(struct amd_sdw_manager *amd_manager);
>> + void (*set_frameshape)(struct amd_sdw_manager *amd_manager);
>> + int (*send_cmd_get_resp)(struct amd_sdw_manager *amd_manager, u32 lower_data,
>> + u32 upper_data, u64 *response);
>> + void (*wake_enable)(struct amd_sdw_manager *amd_manager, bool enable);
>> + int (*host_wake_enable)(struct amd_sdw_manager *amd_manager, bool enable);
>> + int (*set_device_state)(struct amd_sdw_manager *amd_manager, u32 target_device_state);
>> + void (*read_and_process_ping_status)(struct amd_sdw_manager *amd_manager);
>> + void (*process_wake_event)(struct amd_sdw_manager *amd_manager);
>> + void (*irq_thread)(struct amd_sdw_manager *amd_manager);
>> + void (*update_slave_status_work)(struct amd_sdw_manager *amd_manager);
>> + int (*clk_init_ctrl)(struct amd_sdw_manager *amd_manager);
>> + int (*clock_stop_exit)(struct amd_sdw_manager *amd_manager);
>> + int (*suspend)(struct amd_sdw_manager *amd_manager);
>> + int (*suspend_runtime)(struct amd_sdw_manager *amd_manager);
>> + int (*resume_runtime)(struct amd_sdw_manager *amd_manager);
> I would suggest splitting the driver and add common code to a lib and
> have specific drivers for older and new gen platforms...
Agreed. We will restructure the code and respin the patch series.
>
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-10-05 6:41 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-17 9:02 [PATCH 0/9] soundwire: amd: introduce hw_ops dispatch and consolidate probe setup Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 1/9] soundwire: amd: rename AMD_SDW_MAX_MANAGER_COUNT macro Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 2/9] soundwire: amd: allocate pdevinfo and sdw_pdata by ACP revision in probe Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 3/9] soundwire: amd: allocate sdw_amd_ctx pdev array dynamically Vijendar Mukunda
2026-10-03 7:52 ` Vinod Koul
2026-10-05 6:38 ` Mukunda,Vijendar
2026-09-17 9:02 ` [PATCH 4/9] soundwire: amd: rename hardware backend functions to amd_acp63_*() prefix Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 5/9] soundwire: amd: remove unused AMD_SDW_MAX_FREQ_NUM define Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 6/9] soundwire: amd: introduce struct amd_sdw_hw_ops dispatch framework Vijendar Mukunda
2026-10-03 7:56 ` Vinod Koul
2026-10-05 6:43 ` Mukunda,Vijendar
2026-09-17 9:02 ` [PATCH 7/9] soundwire: amd: convert irq/work handlers to hw_ops callbacks Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 8/9] soundwire: amd: wire amd_acp63_*() call sites through acp_*() helpers Vijendar Mukunda
2026-09-17 9:02 ` [PATCH 9/9] soundwire: amd: consolidate revision-specific probe setup Vijendar Mukunda
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.