From 5b1a2927c4f63878d2c108cebad09358e69caa20 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 29 Apr 2025 11:18:07 +0100 Subject: soundwire: bus: Simplify sdw_assign_device_num() Simplify the code in sdw_assign_device_num(). Remove the new_device flag which can be simply handled inline and do a bit less shuffling of dev_num in and out of various variables. This patch should cause no functional changes. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20250429101808.348462-2-ckeepax@opensource.cirrus.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 6f8a20014e76..6cfec4a2af33 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -750,41 +750,36 @@ err: static int sdw_assign_device_num(struct sdw_slave *slave) { struct sdw_bus *bus = slave->bus; - int ret, dev_num; - bool new_device = false; + struct device *dev = bus->dev; + int ret; /* check first if device number is assigned, if so reuse that */ if (!slave->dev_num) { if (!slave->dev_num_sticky) { + int dev_num; + mutex_lock(&slave->bus->bus_lock); dev_num = sdw_get_device_num(slave); mutex_unlock(&slave->bus->bus_lock); if (dev_num < 0) { - dev_err(bus->dev, "Get dev_num failed: %d\n", - dev_num); + dev_err(dev, "Get dev_num failed: %d\n", dev_num); return dev_num; } - slave->dev_num = dev_num; + slave->dev_num_sticky = dev_num; - new_device = true; } else { - slave->dev_num = slave->dev_num_sticky; + dev_dbg(dev, "Slave already registered, reusing dev_num: %d\n", + slave->dev_num_sticky); } } - if (!new_device) - dev_dbg(bus->dev, - "Slave already registered, reusing dev_num:%d\n", - slave->dev_num); - /* Clear the slave->dev_num to transfer message on device 0 */ - dev_num = slave->dev_num; slave->dev_num = 0; - ret = sdw_write_no_pm(slave, SDW_SCP_DEVNUMBER, dev_num); + ret = sdw_write_no_pm(slave, SDW_SCP_DEVNUMBER, slave->dev_num_sticky); if (ret < 0) { - dev_err(bus->dev, "Program device_num %d failed: %d\n", - dev_num, ret); + dev_err(dev, "Program device_num %d failed: %d\n", + slave->dev_num_sticky, ret); return ret; } @@ -792,7 +787,7 @@ static int sdw_assign_device_num(struct sdw_slave *slave) slave->dev_num = slave->dev_num_sticky; if (bus->ops && bus->ops->new_peripheral_assigned) - bus->ops->new_peripheral_assigned(bus, slave, dev_num); + bus->ops->new_peripheral_assigned(bus, slave, slave->dev_num); return 0; } -- cgit v1.2.3-59-g8ed1b From aab12022b076f0b385b7a9a78e1161bd2df5d1e3 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 29 Apr 2025 11:18:08 +0100 Subject: soundwire: bus: Add internal slave ID and use for IRQs Currently the SoundWire IRQ code uses the dev_num to create an IRQ mapping for each slave. However, there is an issue there, the dev_num is only allocated when the slave enumerates on the bus and enumeration may happen before or after probe of the slave driver. In the case enumeration happens after probe of the slave driver then the IRQ mapping will use dev_num before it is set. This could cause multiple slaves to use zero as their IRQ mapping. It is very desirable to have the IRQ mapped before the slave probe is called, so drivers can do resource allocation in probe as normal. To solve these issues add an internal ID created for each slave when it is probed and use that for mapping the IRQ. Signed-off-by: Charles Keepax Reviewed-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20250429101808.348462-3-ckeepax@opensource.cirrus.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 2 ++ drivers/soundwire/bus_type.c | 10 ++++++++++ drivers/soundwire/irq.c | 6 +++--- include/linux/soundwire/sdw.h | 6 ++++++ 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 6cfec4a2af33..377ab21c9cf0 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -56,6 +56,8 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, return ret; } + ida_init(&bus->slave_ida); + ret = sdw_master_device_add(bus, parent, fwnode); if (ret < 0) { dev_err(parent, "Failed to add master device at link %d\n", diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index e98d5db81b1c..75d6f16efced 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -105,9 +105,17 @@ static int sdw_drv_probe(struct device *dev) if (ret) return ret; + ret = ida_alloc_max(&slave->bus->slave_ida, SDW_FW_MAX_DEVICES, GFP_KERNEL); + if (ret < 0) { + dev_err(dev, "Failed to allocated ID: %d\n", ret); + return ret; + } + slave->index = ret; + ret = drv->probe(slave, id); if (ret) { dev_pm_domain_detach(dev, false); + ida_free(&slave->bus->slave_ida, slave->index); return ret; } @@ -174,6 +182,8 @@ static int sdw_drv_remove(struct device *dev) dev_pm_domain_detach(dev, false); + ida_free(&slave->bus->slave_ida, slave->index); + return ret; } diff --git a/drivers/soundwire/irq.c b/drivers/soundwire/irq.c index c237e6d0766b..f18be37efef8 100644 --- a/drivers/soundwire/irq.c +++ b/drivers/soundwire/irq.c @@ -31,7 +31,7 @@ int sdw_irq_create(struct sdw_bus *bus, { bus->irq_chip.name = dev_name(bus->dev); - bus->domain = irq_domain_create_linear(fwnode, SDW_MAX_DEVICES, + bus->domain = irq_domain_create_linear(fwnode, SDW_FW_MAX_DEVICES, &sdw_domain_ops, bus); if (!bus->domain) { dev_err(bus->dev, "Failed to add IRQ domain\n"); @@ -50,12 +50,12 @@ static void sdw_irq_dispose_mapping(void *data) { struct sdw_slave *slave = data; - irq_dispose_mapping(irq_find_mapping(slave->bus->domain, slave->dev_num)); + irq_dispose_mapping(slave->irq); } void sdw_irq_create_mapping(struct sdw_slave *slave) { - slave->irq = irq_create_mapping(slave->bus->domain, slave->dev_num); + slave->irq = irq_create_mapping(slave->bus->domain, slave->index); if (!slave->irq) dev_warn(&slave->dev, "Failed to map IRQ\n"); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 2362f621d94c..0832776262ac 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,7 @@ struct sdw_slave; #define SDW_FRAME_CTRL_BITS 48 #define SDW_MAX_DEVICES 11 +#define SDW_FW_MAX_DEVICES 16 #define SDW_MAX_PORTS 15 #define SDW_VALID_PORT_RANGE(n) ((n) < SDW_MAX_PORTS && (n) >= 1) @@ -630,6 +632,7 @@ struct sdw_slave_ops { * struct sdw_slave - SoundWire Slave * @id: MIPI device ID * @dev: Linux device + * @index: internal ID for this slave * @irq: IRQ number * @status: Status reported by the Slave * @bus: Bus handle @@ -661,6 +664,7 @@ struct sdw_slave_ops { struct sdw_slave { struct sdw_slave_id id; struct device dev; + int index; int irq; enum sdw_slave_status status; struct sdw_bus *bus; @@ -968,6 +972,7 @@ struct sdw_stream_runtime { * @md: Master device * @bus_lock_key: bus lock key associated to @bus_lock * @bus_lock: bus lock + * @slave_ida: IDA for allocating internal slave IDs * @slaves: list of Slaves on this bus * @msg_lock_key: message lock key associated to @msg_lock * @msg_lock: message lock @@ -1010,6 +1015,7 @@ struct sdw_bus { struct sdw_master_device *md; struct lock_class_key bus_lock_key; struct mutex bus_lock; + struct ida slave_ida; struct list_head slaves; struct lock_class_key msg_lock_key; struct mutex msg_lock; -- cgit v1.2.3-59-g8ed1b From e1f3f5be9e8e730290ebe6d490383af4d77f0f38 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 30 Apr 2025 15:47:13 +0800 Subject: soundwire: intel: Add awareness of ACE3+ microphone privacy ACE3 introduced microphone privacy and along this feature it adds a new register in vendor specific SHIM to control and status reporting. The control of mic privacy via the SHIM register is only to enable the interrupt generation via soundwire, but not handled by the soundwire code as the mic privacy is not a feature of the soundwire IP. On the other hand, printing the register value brings value for debugging, so add a new flag to allow this conditionally. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20250430074714.94000-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.h | 2 ++ drivers/soundwire/intel_ace2x_debugfs.c | 6 ++++++ drivers/soundwire/intel_init.c | 1 + include/linux/soundwire/sdw_intel.h | 5 +++++ 4 files changed, 14 insertions(+) diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index d44e70d3c4e3..86abc465260f 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -22,6 +22,7 @@ struct hdac_bus; * @shim_lock: mutex to handle access to shared SHIM registers * @shim_mask: global pointer to check SHIM register initialization * @clock_stop_quirks: mask defining requested behavior on pm_suspend + * @mic_privacy: ACE version supports microphone privacy * @link_mask: global mask needed for power-up/down sequences * @cdns: Cadence master descriptor * @list: used to walk-through all masters exposed by the same controller @@ -42,6 +43,7 @@ struct sdw_intel_link_res { struct mutex *shim_lock; /* protect shared registers */ u32 *shim_mask; u32 clock_stop_quirks; + bool mic_privacy; u32 link_mask; struct sdw_cdns *cdns; struct list_head list; diff --git a/drivers/soundwire/intel_ace2x_debugfs.c b/drivers/soundwire/intel_ace2x_debugfs.c index 206a8d511ebd..fda8f0daaa96 100644 --- a/drivers/soundwire/intel_ace2x_debugfs.c +++ b/drivers/soundwire/intel_ace2x_debugfs.c @@ -76,6 +76,12 @@ static int intel_reg_show(struct seq_file *s_file, void *data) ret += intel_sprintf(vs_s, false, buf, ret, SDW_SHIM2_INTEL_VS_IOCTL); ret += intel_sprintf(vs_s, false, buf, ret, SDW_SHIM2_INTEL_VS_ACTMCTL); + if (sdw->link_res->mic_privacy) { + ret += scnprintf(buf + ret, RD_BUF - ret, "\nVS PVCCS\n"); + ret += intel_sprintf(vs_s, false, buf, ret, + SDW_SHIM2_INTEL_VS_PVCCS); + } + seq_printf(s_file, "%s", buf); kfree(buf); diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index 5f53666514a4..4ffdabaf9693 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -77,6 +77,7 @@ static struct sdw_intel_link_dev *intel_link_dev_register(struct sdw_intel_res * link->shim = res->mmio_base + SDW_SHIM2_GENERIC_BASE(link_id); link->shim_vs = res->mmio_base + SDW_SHIM2_VS_BASE(link_id); link->shim_lock = res->eml_lock; + link->mic_privacy = res->mic_privacy; } link->ops = res->ops; diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 493d9de4e472..2af1d8174c50 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -189,6 +189,9 @@ #define SDW_SHIM3_INTEL_VS_ACTMCTL_DOAISE2 BIT(14) #define SDW_SHIM3_INTEL_VS_ACTMCTL_CLDE BIT(15) +/* ACE3+ Mic privacy control and status register */ +#define SDW_SHIM2_INTEL_VS_PVCCS 0x10 + /** * struct sdw_intel_stream_params_data: configuration passed during * the @params_stream callback, e.g. for interaction with DSP @@ -331,6 +334,7 @@ struct sdw_intel_ctx { * @shim_base: sdw shim base. * @alh_base: sdw alh base. * @ext: extended HDaudio link support + * @mic_privacy: ACE version supports microphone privacy * @hbus: hdac_bus pointer, needed for power management * @eml_lock: mutex protecting shared registers in the HDaudio multi-link * space @@ -349,6 +353,7 @@ struct sdw_intel_res { u32 shim_base; u32 alh_base; bool ext; + bool mic_privacy; struct hdac_bus *hbus; struct mutex *eml_lock; }; -- cgit v1.2.3-59-g8ed1b From d028b57b77f91e4643abd661640f345cd34522b6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 30 Apr 2025 15:47:14 +0800 Subject: ASoC: SOF: Intel: hda: Set the mic_privacy flag for soundwire with ACE3+ The microphone privacy feature is introduced with ACE3, the soundwire driver needs to know this to be able to print the PVCCS register via register dump in sysfs. Signed-off-by: Peter Ujfalusi Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20250430074714.94000-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- sound/soc/sof/intel/hda.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index b34e5fdf10f1..510d31950587 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -192,6 +192,9 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev) res.ext = true; res.ops = &sdw_ace2x_callback; + /* ACE3+ supports microphone privacy */ + if (chip->hw_ip_version >= SOF_INTEL_ACE_3_0) + res.mic_privacy = true; } res.irq = sdev->ipc_irq; res.handle = hdev->info.handle; -- cgit v1.2.3-59-g8ed1b From 62ada17a6217a50fbd1b23f10899890f56effc97 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 8 May 2025 14:20:29 +0800 Subject: soundwire: only compute port params in specific stream states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, sdw_compute_master_ports() is blindly called for every single Manager runtime. However, we should not take into account the stream's bandwidth if the stream is just allocated or already deprepared. Fixes: 25befdf32aa4 ("soundwire: generic_bandwidth_allocation: count the bandwidth of active streams only") Link: https://github.com/thesofproject/linux/issues/5398 Signed-off-by: Bard Liao Reviewed-by: Ranjani Sridharan Reviewed-by: Péter Ujfalusi Link: https://lore.kernel.org/r/20250508062029.6596-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/generic_bandwidth_allocation.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 1cfaccf43eac..c18f0c16f929 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -204,6 +204,13 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, port_bo = 1; list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { + /* + * Only runtimes with CONFIGURED, PREPARED, ENABLED, and DISABLED + * states should be included in the bandwidth calculation. + */ + if (m_rt->stream->state > SDW_STREAM_DISABLED || + m_rt->stream->state < SDW_STREAM_CONFIGURED) + continue; sdw_compute_master_ports(m_rt, ¶ms[i], &port_bo, hstop); } -- cgit v1.2.3-59-g8ed1b