soundwire updates for 6.16

Couple of small core changes for
  - sdw_assign_device_num() logic simplification, using internal slave id
    for irqs and optimizing computing of port params in specific stream
    states
  - Intel driver updates for ACE3+ microphone privacy status reporting
    and enabling the status in HDA Intel driver
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmhBMgcACgkQfBQHDyUj
 g0elyQ/8CqVJ4y6M1i2MgV+efGewspmvzt2WM9a82LA1wzSz668YxEaa50aplWwh
 c2jqqL702zOsbH5gX+H31tDM0wuder9zn5qxQML4JCUbw/Ec7cQSUOeVse+v9Rbg
 Fnb5MdxGXShSnOMjXA+H6JZ4Kt2TF759Q3wd4dmba0VBTIasVtyxW/qhFT997bJp
 SziLBT38dEG3WOBf8I+4qPsDg6NfJtUsn8H3oMJBD4ng8/uTD1BR5GZp3YsyH5X8
 2najQHVUFfGhWM8jLAniBZUBjeAMpGcKHjZxbKiizO3gGrCmetVao3PD1L0WYJP7
 macqODWQ+C3JGuk8aEvrgQ5YZpls/DF1BJDxABmq9u+8IYPFYTKzQdA+YKOmQPGB
 zli+F/GgBT5fCBIDb1UzZxGf5NC/mRN50eTPkd8ZnN2lA+OAsJs6Bnzh8c9BdMqY
 9haG0kY6sgDQVy1f3SSDI+JwAOEecVi6x6jhXKWdc++JyXEL57L3njHeXNA7kd+K
 esDQREVYXZ9Te17g1CL2/uQSWi/nMbPGQ0bPr0Y6CMzbMom1EguUE1FzPpIgct9K
 +3qPs9h6g2zUaUW0CtY1e0WGWUEG/XzBw8OHvTem4320yiSVSnhgF7QTtA4N+nIz
 cH870V3S8enqKU0V6HqDA5kwvfhh1SS8K1wnkRhFGDC3m/nhlRA=
 =izGg
 -----END PGP SIGNATURE-----

Merge tag 'soundwire-6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire

Pull soundwire updates from Vinod Koul:
 "A couple of small core changes and an Intel driver change:

   - sdw_assign_device_num() logic simplification, using internal slave
     id for irqs and optimizing computing of port params in specific
     stream states

   - Intel driver updates for ACE3+ microphone privacy status reporting
     and enabling the status in HDA Intel driver"

* tag 'soundwire-6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: only compute port params in specific stream states
  ASoC: SOF: Intel: hda: Set the mic_privacy flag for soundwire with ACE3+
  soundwire: intel: Add awareness of ACE3+ microphone privacy
  soundwire: bus: Add internal slave ID and use for IRQs
  soundwire: bus: Simplify sdw_assign_device_num()
This commit is contained in:
Linus Torvalds 2025-06-05 08:07:24 -07:00
commit a479ebb269
10 changed files with 57 additions and 20 deletions

View File

@ -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",
@ -751,41 +753,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;
}
@ -793,7 +790,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;
}

View File

@ -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;
}

View File

@ -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, &params[i], &port_bo, hstop);
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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");

View File

@ -8,6 +8,7 @@
#include <linux/bug.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/lockdep_types.h>
@ -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;

View File

@ -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;
};

View File

@ -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;