Commit ad7b0b7b authored by Linus Torvalds's avatar Linus Torvalds

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

Pull soundwire updates from Vinod Koul:

 - Simplification across subsystem using cleanup.h

 - Support for debugfs to read/write commands

 - Few Intel and Qualcomm driver updates

* tag 'soundwire-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire:
  soundwire: debugfs: simplify with cleanup.h
  soundwire: cadence: simplify with cleanup.h
  soundwire: intel_ace2x: simplify with cleanup.h
  soundwire: intel_ace2x: simplify return path in hw_params
  soundwire: intel: simplify with cleanup.h
  soundwire: intel: simplify return path in hw_params
  soundwire: amd_init: simplify with cleanup.h
  soundwire: amd: simplify with cleanup.h
  soundwire: amd: simplify return path in hw_params
  soundwire: intel_auxdevice: start the bus at default frequency
  soundwire: intel_auxdevice: add cs42l43 codec to wake_capable_list
  drivers:soundwire: qcom: cleanup port maask calculations
  soundwire: bus: simplify by using local slave->prop
  soundwire: generic_bandwidth_allocation: change port_bo parameter to pointer
  soundwire: Intel: clarify Copyright information
  soundwire: intel_ace2.x: add AC timing extensions for PantherLake
  soundwire: bus: add stream refcount
  soundwire: debugfs: add interface to read/write commands
parents 7a46b17d fdd3d14c
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/cleanup.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -69,7 +70,6 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) ...@@ -69,7 +70,6 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
{ {
struct sdw_amd_ctx *ctx; struct sdw_amd_ctx *ctx;
struct acpi_device *adev; struct acpi_device *adev;
struct resource *sdw_res;
struct acp_sdw_pdata sdw_pdata[2]; struct acp_sdw_pdata sdw_pdata[2];
struct platform_device_info pdevinfo[2]; struct platform_device_info pdevinfo[2];
u32 link_mask; u32 link_mask;
...@@ -104,7 +104,8 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) ...@@ -104,7 +104,8 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
ctx->count = count; ctx->count = count;
ctx->link_mask = res->link_mask; ctx->link_mask = res->link_mask;
sdw_res = kzalloc(sizeof(*sdw_res), GFP_KERNEL); struct resource *sdw_res __free(kfree) = kzalloc(sizeof(*sdw_res),
GFP_KERNEL);
if (!sdw_res) { if (!sdw_res) {
kfree(ctx); kfree(ctx);
return NULL; return NULL;
...@@ -132,7 +133,6 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) ...@@ -132,7 +133,6 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
if (IS_ERR(ctx->pdev[index])) if (IS_ERR(ctx->pdev[index]))
goto err; goto err;
} }
kfree(sdw_res);
return ctx; return ctx;
err: err:
while (index--) { while (index--) {
...@@ -142,7 +142,6 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res) ...@@ -142,7 +142,6 @@ static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
platform_device_unregister(ctx->pdev[index]); platform_device_unregister(ctx->pdev[index]);
} }
kfree(sdw_res);
kfree(ctx); kfree(ctx);
return NULL; return NULL;
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/cleanup.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
...@@ -603,7 +604,6 @@ static int amd_sdw_hw_params(struct snd_pcm_substream *substream, ...@@ -603,7 +604,6 @@ static int amd_sdw_hw_params(struct snd_pcm_substream *substream,
struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai); struct amd_sdw_manager *amd_manager = snd_soc_dai_get_drvdata(dai);
struct sdw_amd_dai_runtime *dai_runtime; struct sdw_amd_dai_runtime *dai_runtime;
struct sdw_stream_config sconfig; struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig;
int ch, dir; int ch, dir;
int ret; int ret;
...@@ -626,11 +626,10 @@ static int amd_sdw_hw_params(struct snd_pcm_substream *substream, ...@@ -626,11 +626,10 @@ static int amd_sdw_hw_params(struct snd_pcm_substream *substream,
sconfig.bps = snd_pcm_format_width(params_format(params)); sconfig.bps = snd_pcm_format_width(params_format(params));
/* Port configuration */ /* Port configuration */
pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL); struct sdw_port_config *pconfig __free(kfree) = kzalloc(sizeof(*pconfig),
if (!pconfig) { GFP_KERNEL);
ret = -ENOMEM; if (!pconfig)
goto error; return -ENOMEM;
}
pconfig->num = dai->id; pconfig->num = dai->id;
pconfig->ch_mask = (1 << ch) - 1; pconfig->ch_mask = (1 << ch) - 1;
...@@ -639,8 +638,6 @@ static int amd_sdw_hw_params(struct snd_pcm_substream *substream, ...@@ -639,8 +638,6 @@ static int amd_sdw_hw_params(struct snd_pcm_substream *substream,
if (ret) if (ret)
dev_err(amd_manager->dev, "add manager to stream failed:%d\n", ret); dev_err(amd_manager->dev, "add manager to stream failed:%d\n", ret);
kfree(pconfig);
error:
return ret; return ret;
} }
......
...@@ -1410,7 +1410,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave) ...@@ -1410,7 +1410,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
} }
} }
if ((slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY) && if ((slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY) &&
!(slave->prop.quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY)) { !(prop->quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY)) {
/* Clear parity interrupt before enabling interrupt mask */ /* Clear parity interrupt before enabling interrupt mask */
status = sdw_read_no_pm(slave, SDW_SCP_INT1); status = sdw_read_no_pm(slave, SDW_SCP_INT1);
if (status < 0) { if (status < 0) {
...@@ -1436,7 +1436,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave) ...@@ -1436,7 +1436,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
* device-dependent, it might e.g. only be enabled in * device-dependent, it might e.g. only be enabled in
* steady-state after a couple of frames. * steady-state after a couple of frames.
*/ */
val = slave->prop.scp_int1_mask; val = prop->scp_int1_mask;
/* Enable SCP interrupts */ /* Enable SCP interrupts */
ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, val, val); ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, val, val);
...@@ -1447,7 +1447,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave) ...@@ -1447,7 +1447,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
} }
/* No need to continue if DP0 is not present */ /* No need to continue if DP0 is not present */
if (!slave->prop.dp0_prop) if (!prop->dp0_prop)
return 0; return 0;
/* Enable DP0 interrupts */ /* Enable DP0 interrupts */
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Used by Master driver * Used by Master driver
*/ */
#include <linux/cleanup.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -323,12 +324,11 @@ static ssize_t cdns_sprintf(struct sdw_cdns *cdns, ...@@ -323,12 +324,11 @@ static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
static int cdns_reg_show(struct seq_file *s, void *data) static int cdns_reg_show(struct seq_file *s, void *data)
{ {
struct sdw_cdns *cdns = s->private; struct sdw_cdns *cdns = s->private;
char *buf;
ssize_t ret; ssize_t ret;
int num_ports; int num_ports;
int i, j; int i, j;
buf = kzalloc(RD_BUF, GFP_KERNEL); char *buf __free(kfree) = kzalloc(RD_BUF, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
...@@ -389,7 +389,6 @@ static int cdns_reg_show(struct seq_file *s, void *data) ...@@ -389,7 +389,6 @@ static int cdns_reg_show(struct seq_file *s, void *data)
ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i)); ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i));
seq_printf(s, "%s", buf); seq_printf(s, "%s", buf);
kfree(buf);
return 0; return 0;
} }
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2017-2019 Intel Corporation. // Copyright(c) 2017-2019 Intel Corporation.
#include <linux/cleanup.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/firmware.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -48,18 +50,16 @@ static ssize_t sdw_sprintf(struct sdw_slave *slave, ...@@ -48,18 +50,16 @@ static ssize_t sdw_sprintf(struct sdw_slave *slave,
static int sdw_slave_reg_show(struct seq_file *s_file, void *data) static int sdw_slave_reg_show(struct seq_file *s_file, void *data)
{ {
struct sdw_slave *slave = s_file->private; struct sdw_slave *slave = s_file->private;
char *buf;
ssize_t ret; ssize_t ret;
int i, j; int i, j;
buf = kzalloc(RD_BUF, GFP_KERNEL); char *buf __free(kfree) = kzalloc(RD_BUF, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
ret = pm_runtime_get_sync(&slave->dev); ret = pm_runtime_get_sync(&slave->dev);
if (ret < 0 && ret != -EACCES) { if (ret < 0 && ret != -EACCES) {
pm_runtime_put_noidle(&slave->dev); pm_runtime_put_noidle(&slave->dev);
kfree(buf);
return ret; return ret;
} }
...@@ -131,12 +131,149 @@ static int sdw_slave_reg_show(struct seq_file *s_file, void *data) ...@@ -131,12 +131,149 @@ static int sdw_slave_reg_show(struct seq_file *s_file, void *data)
pm_runtime_mark_last_busy(&slave->dev); pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put(&slave->dev); pm_runtime_put(&slave->dev);
kfree(buf);
return 0; return 0;
} }
DEFINE_SHOW_ATTRIBUTE(sdw_slave_reg); DEFINE_SHOW_ATTRIBUTE(sdw_slave_reg);
#define MAX_CMD_BYTES 256
static int cmd;
static u32 start_addr;
static size_t num_bytes;
static u8 read_buffer[MAX_CMD_BYTES];
static char *firmware_file;
static int set_command(void *data, u64 value)
{
struct sdw_slave *slave = data;
if (value > 1)
return -EINVAL;
/* Userspace changed the hardware state behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
dev_dbg(&slave->dev, "command: %s\n", value ? "read" : "write");
cmd = value;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(set_command_fops, NULL,
set_command, "%llu\n");
static int set_start_address(void *data, u64 value)
{
struct sdw_slave *slave = data;
/* Userspace changed the hardware state behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
dev_dbg(&slave->dev, "start address %#llx\n", value);
start_addr = value;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(set_start_address_fops, NULL,
set_start_address, "%llu\n");
static int set_num_bytes(void *data, u64 value)
{
struct sdw_slave *slave = data;
if (value == 0 || value > MAX_CMD_BYTES)
return -EINVAL;
/* Userspace changed the hardware state behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
dev_dbg(&slave->dev, "number of bytes %lld\n", value);
num_bytes = value;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(set_num_bytes_fops, NULL,
set_num_bytes, "%llu\n");
static int cmd_go(void *data, u64 value)
{
struct sdw_slave *slave = data;
int ret;
if (value != 1)
return -EINVAL;
/* one last check */
if (start_addr > SDW_REG_MAX ||
num_bytes == 0 || num_bytes > MAX_CMD_BYTES)
return -EINVAL;
ret = pm_runtime_get_sync(&slave->dev);
if (ret < 0 && ret != -EACCES) {
pm_runtime_put_noidle(&slave->dev);
return ret;
}
/* Userspace changed the hardware state behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
dev_dbg(&slave->dev, "starting command\n");
if (cmd == 0) {
const struct firmware *fw;
ret = request_firmware(&fw, firmware_file, &slave->dev);
if (ret < 0) {
dev_err(&slave->dev, "firmware %s not found\n", firmware_file);
goto out;
}
if (fw->size != num_bytes) {
dev_err(&slave->dev,
"firmware %s: unexpected size %zd, desired %zd\n",
firmware_file, fw->size, num_bytes);
release_firmware(fw);
goto out;
}
ret = sdw_nwrite_no_pm(slave, start_addr, num_bytes, fw->data);
release_firmware(fw);
} else {
ret = sdw_nread_no_pm(slave, start_addr, num_bytes, read_buffer);
}
dev_dbg(&slave->dev, "command completed %d\n", ret);
out:
pm_runtime_mark_last_busy(&slave->dev);
pm_runtime_put(&slave->dev);
return ret;
}
DEFINE_DEBUGFS_ATTRIBUTE(cmd_go_fops, NULL,
cmd_go, "%llu\n");
#define MAX_LINE_LEN 128
static int read_buffer_show(struct seq_file *s_file, void *data)
{
char buf[MAX_LINE_LEN];
int i;
if (num_bytes == 0 || num_bytes > MAX_CMD_BYTES)
return -EINVAL;
for (i = 0; i < num_bytes; i++) {
scnprintf(buf, MAX_LINE_LEN, "address %#x val 0x%02x\n",
start_addr + i, read_buffer[i]);
seq_printf(s_file, "%s", buf);
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(read_buffer);
void sdw_slave_debugfs_init(struct sdw_slave *slave) void sdw_slave_debugfs_init(struct sdw_slave *slave)
{ {
struct dentry *master; struct dentry *master;
...@@ -151,6 +288,16 @@ void sdw_slave_debugfs_init(struct sdw_slave *slave) ...@@ -151,6 +288,16 @@ void sdw_slave_debugfs_init(struct sdw_slave *slave)
debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops); debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops);
/* interface to send arbitrary commands */
debugfs_create_file("command", 0200, d, slave, &set_command_fops);
debugfs_create_file("start_address", 0200, d, slave, &set_start_address_fops);
debugfs_create_file("num_bytes", 0200, d, slave, &set_num_bytes_fops);
debugfs_create_file("go", 0200, d, slave, &cmd_go_fops);
debugfs_create_file("read_buffer", 0400, d, slave, &read_buffer_fops);
firmware_file = NULL;
debugfs_create_str("firmware_file", 0200, d, &firmware_file);
slave->debugfs = d; slave->debugfs = d;
} }
......
...@@ -83,7 +83,7 @@ EXPORT_SYMBOL(sdw_compute_slave_ports); ...@@ -83,7 +83,7 @@ EXPORT_SYMBOL(sdw_compute_slave_ports);
static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
struct sdw_group_params *params, struct sdw_group_params *params,
int port_bo, int hstop) int *port_bo, int hstop)
{ {
struct sdw_transport_data t_data = {0}; struct sdw_transport_data t_data = {0};
struct sdw_port_runtime *p_rt; struct sdw_port_runtime *p_rt;
...@@ -108,7 +108,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, ...@@ -108,7 +108,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
sdw_fill_xport_params(&p_rt->transport_params, p_rt->num, sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
false, SDW_BLK_GRP_CNT_1, sample_int, false, SDW_BLK_GRP_CNT_1, sample_int,
port_bo, port_bo >> 8, hstart, hstop, *port_bo, (*port_bo) >> 8, hstart, hstop,
SDW_BLK_PKG_PER_PORT, 0x0); SDW_BLK_PKG_PER_PORT, 0x0);
sdw_fill_port_params(&p_rt->port_params, sdw_fill_port_params(&p_rt->port_params,
...@@ -120,15 +120,15 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, ...@@ -120,15 +120,15 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
if (!(p_rt == list_first_entry(&m_rt->port_list, if (!(p_rt == list_first_entry(&m_rt->port_list,
struct sdw_port_runtime, struct sdw_port_runtime,
port_node))) { port_node))) {
port_bo += bps * ch; (*port_bo) += bps * ch;
continue; continue;
} }
t_data.hstart = hstart; t_data.hstart = hstart;
t_data.hstop = hstop; t_data.hstop = hstop;
t_data.block_offset = port_bo; t_data.block_offset = *port_bo;
t_data.sub_block_offset = 0; t_data.sub_block_offset = 0;
port_bo += bps * ch; (*port_bo) += bps * ch;
} }
sdw_compute_slave_ports(m_rt, &t_data); sdw_compute_slave_ports(m_rt, &t_data);
...@@ -146,9 +146,7 @@ static void _sdw_compute_port_params(struct sdw_bus *bus, ...@@ -146,9 +146,7 @@ static void _sdw_compute_port_params(struct sdw_bus *bus,
port_bo = 1; port_bo = 1;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
sdw_compute_master_ports(m_rt, &params[i], port_bo, hstop); sdw_compute_master_ports(m_rt, &params[i], &port_bo, hstop);
port_bo += m_rt->ch_count * m_rt->stream->params.bps;
} }
hstop = hstop - params[i].hwidth; hstop = hstop - params[i].hwidth;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/cleanup.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -73,12 +74,11 @@ static int intel_reg_show(struct seq_file *s_file, void *data) ...@@ -73,12 +74,11 @@ static int intel_reg_show(struct seq_file *s_file, void *data)
struct sdw_intel *sdw = s_file->private; struct sdw_intel *sdw = s_file->private;
void __iomem *s = sdw->link_res->shim; void __iomem *s = sdw->link_res->shim;
void __iomem *a = sdw->link_res->alh; void __iomem *a = sdw->link_res->alh;
char *buf;
ssize_t ret; ssize_t ret;
int i, j; int i, j;
unsigned int links, reg; unsigned int links, reg;
buf = kzalloc(RD_BUF, GFP_KERNEL); char *buf __free(kfree) = kzalloc(RD_BUF, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
...@@ -129,7 +129,6 @@ static int intel_reg_show(struct seq_file *s_file, void *data) ...@@ -129,7 +129,6 @@ static int intel_reg_show(struct seq_file *s_file, void *data)
ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i)); ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
seq_printf(s_file, "%s", buf); seq_printf(s_file, "%s", buf);
kfree(buf);
return 0; return 0;
} }
...@@ -727,7 +726,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -727,7 +726,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
struct sdw_cdns_dai_runtime *dai_runtime; struct sdw_cdns_dai_runtime *dai_runtime;
struct sdw_cdns_pdi *pdi; struct sdw_cdns_pdi *pdi;
struct sdw_stream_config sconfig; struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig;
int ch, dir; int ch, dir;
int ret; int ret;
...@@ -743,10 +741,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -743,10 +741,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id); pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
if (!pdi) { if (!pdi)
ret = -EINVAL; return -EINVAL;
goto error;
}
/* do run-time configurations for SHIM, ALH and PDI/PORT */ /* do run-time configurations for SHIM, ALH and PDI/PORT */
intel_pdi_shim_configure(sdw, pdi); intel_pdi_shim_configure(sdw, pdi);
...@@ -763,7 +759,7 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -763,7 +759,7 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
sdw->instance, sdw->instance,
pdi->intel_alh_id); pdi->intel_alh_id);
if (ret) if (ret)
goto error; return ret;
sconfig.direction = dir; sconfig.direction = dir;
sconfig.ch_count = ch; sconfig.ch_count = ch;
...@@ -773,11 +769,10 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -773,11 +769,10 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
sconfig.bps = snd_pcm_format_width(params_format(params)); sconfig.bps = snd_pcm_format_width(params_format(params));
/* Port configuration */ /* Port configuration */
pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL); struct sdw_port_config *pconfig __free(kfree) = kzalloc(sizeof(*pconfig),
if (!pconfig) { GFP_KERNEL);
ret = -ENOMEM; if (!pconfig)
goto error; return -ENOMEM;
}
pconfig->num = pdi->num; pconfig->num = pdi->num;
pconfig->ch_mask = (1 << ch) - 1; pconfig->ch_mask = (1 << ch) - 1;
...@@ -787,8 +782,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -787,8 +782,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
if (ret) if (ret)
dev_err(cdns->dev, "add master to stream failed:%d\n", ret); dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
kfree(pconfig);
error:
return ret; return ret;
} }
......
...@@ -59,6 +59,11 @@ struct sdw_intel { ...@@ -59,6 +59,11 @@ struct sdw_intel {
}; };
struct sdw_intel_prop { struct sdw_intel_prop {
u16 clde;
u16 doaise2;
u16 dodse2;
u16 clds;
u16 clss;
u16 doaise; u16 doaise;
u16 doais; u16 doais;
u16 dodse; u16 dodse;
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
// Copyright(c) 2023 Intel Corporation. All rights reserved. // Copyright(c) 2023 Intel Corporation
/* /*
* Soundwire Intel ops for LunarLake * Soundwire Intel ops for LunarLake
*/ */
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/cleanup.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw.h>
...@@ -27,6 +28,11 @@ static void intel_shim_vs_init(struct sdw_intel *sdw) ...@@ -27,6 +28,11 @@ static void intel_shim_vs_init(struct sdw_intel *sdw)
void __iomem *shim_vs = sdw->link_res->shim_vs; void __iomem *shim_vs = sdw->link_res->shim_vs;
struct sdw_bus *bus = &sdw->cdns.bus; struct sdw_bus *bus = &sdw->cdns.bus;
struct sdw_intel_prop *intel_prop; struct sdw_intel_prop *intel_prop;
u16 clde;
u16 doaise2;
u16 dodse2;
u16 clds;
u16 clss;
u16 doaise; u16 doaise;
u16 doais; u16 doais;
u16 dodse; u16 dodse;
...@@ -34,12 +40,22 @@ static void intel_shim_vs_init(struct sdw_intel *sdw) ...@@ -34,12 +40,22 @@ static void intel_shim_vs_init(struct sdw_intel *sdw)
u16 act; u16 act;
intel_prop = bus->vendor_specific_prop; intel_prop = bus->vendor_specific_prop;
clde = intel_prop->clde;
doaise2 = intel_prop->doaise2;
dodse2 = intel_prop->dodse2;
clds = intel_prop->clds;
clss = intel_prop->clss;
doaise = intel_prop->doaise; doaise = intel_prop->doaise;
doais = intel_prop->doais; doais = intel_prop->doais;
dodse = intel_prop->dodse; dodse = intel_prop->dodse;
dods = intel_prop->dods; dods = intel_prop->dods;
act = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL); act = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL);
u16p_replace_bits(&act, clde, SDW_SHIM3_INTEL_VS_ACTMCTL_CLDE);
u16p_replace_bits(&act, doaise2, SDW_SHIM3_INTEL_VS_ACTMCTL_DOAISE2);
u16p_replace_bits(&act, dodse2, SDW_SHIM3_INTEL_VS_ACTMCTL_DODSE2);
u16p_replace_bits(&act, clds, SDW_SHIM3_INTEL_VS_ACTMCTL_CLDS);
u16p_replace_bits(&act, clss, SDW_SHIM3_INTEL_VS_ACTMCTL_CLSS);
u16p_replace_bits(&act, doaise, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAISE); u16p_replace_bits(&act, doaise, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAISE);
u16p_replace_bits(&act, doais, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS); u16p_replace_bits(&act, doais, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS);
u16p_replace_bits(&act, dodse, SDW_SHIM2_INTEL_VS_ACTMCTL_DODSE); u16p_replace_bits(&act, dodse, SDW_SHIM2_INTEL_VS_ACTMCTL_DODSE);
...@@ -295,7 +311,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -295,7 +311,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
struct sdw_cdns_dai_runtime *dai_runtime; struct sdw_cdns_dai_runtime *dai_runtime;
struct sdw_cdns_pdi *pdi; struct sdw_cdns_pdi *pdi;
struct sdw_stream_config sconfig; struct sdw_stream_config sconfig;
struct sdw_port_config *pconfig;
int ch, dir; int ch, dir;
int ret; int ret;
...@@ -310,11 +325,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -310,11 +325,8 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
dir = SDW_DATA_DIR_TX; dir = SDW_DATA_DIR_TX;
pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id); pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
if (!pdi)
if (!pdi) { return -EINVAL;
ret = -EINVAL;
goto error;
}
/* use same definitions for alh_id as previous generations */ /* use same definitions for alh_id as previous generations */
pdi->intel_alh_id = (sdw->instance * 16) + pdi->num + 3; pdi->intel_alh_id = (sdw->instance * 16) + pdi->num + 3;
...@@ -335,7 +347,7 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -335,7 +347,7 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
sdw->instance, sdw->instance,
pdi->intel_alh_id); pdi->intel_alh_id);
if (ret) if (ret)
goto error; return ret;
sconfig.direction = dir; sconfig.direction = dir;
sconfig.ch_count = ch; sconfig.ch_count = ch;
...@@ -345,11 +357,10 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -345,11 +357,10 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
sconfig.bps = snd_pcm_format_width(params_format(params)); sconfig.bps = snd_pcm_format_width(params_format(params));
/* Port configuration */ /* Port configuration */
pconfig = kzalloc(sizeof(*pconfig), GFP_KERNEL); struct sdw_port_config *pconfig __free(kfree) = kzalloc(sizeof(*pconfig),
if (!pconfig) { GFP_KERNEL);
ret = -ENOMEM; if (!pconfig)
goto error; return -ENOMEM;
}
pconfig->num = pdi->num; pconfig->num = pdi->num;
pconfig->ch_mask = (1 << ch) - 1; pconfig->ch_mask = (1 << ch) - 1;
...@@ -359,8 +370,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -359,8 +370,6 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
if (ret) if (ret)
dev_err(cdns->dev, "add master to stream failed:%d\n", ret); dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
kfree(pconfig);
error:
return ret; return ret;
} }
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
// Copyright(c) 2023 Intel Corporation. All rights reserved. // Copyright(c) 2023 Intel Corporation
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
......
...@@ -47,6 +47,7 @@ struct wake_capable_part { ...@@ -47,6 +47,7 @@ struct wake_capable_part {
}; };
static struct wake_capable_part wake_capable_list[] = { static struct wake_capable_part wake_capable_list[] = {
{0x01fa, 0x4243},
{0x025d, 0x5682}, {0x025d, 0x5682},
{0x025d, 0x700}, {0x025d, 0x700},
{0x025d, 0x711}, {0x025d, 0x711},
...@@ -161,11 +162,31 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) ...@@ -161,11 +162,31 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
} }
/* initialize with hardware defaults, in case the properties are not found */ /* initialize with hardware defaults, in case the properties are not found */
intel_prop->clde = 0x0;
intel_prop->doaise2 = 0x0;
intel_prop->dodse2 = 0x0;
intel_prop->clds = 0x0;
intel_prop->clss = 0x0;
intel_prop->doaise = 0x1; intel_prop->doaise = 0x1;
intel_prop->doais = 0x3; intel_prop->doais = 0x3;
intel_prop->dodse = 0x0; intel_prop->dodse = 0x0;
intel_prop->dods = 0x1; intel_prop->dods = 0x1;
fwnode_property_read_u16(link,
"intel-sdw-clde",
&intel_prop->clde);
fwnode_property_read_u16(link,
"intel-sdw-doaise2",
&intel_prop->doaise2);
fwnode_property_read_u16(link,
"intel-sdw-dodse2",
&intel_prop->dodse2);
fwnode_property_read_u16(link,
"intel-sdw-clds",
&intel_prop->clds);
fwnode_property_read_u16(link,
"intel-sdw-clss",
&intel_prop->clss);
fwnode_property_read_u16(link, fwnode_property_read_u16(link,
"intel-sdw-doaise", "intel-sdw-doaise",
&intel_prop->doaise); &intel_prop->doaise);
...@@ -193,9 +214,30 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) ...@@ -193,9 +214,30 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
static int intel_prop_read(struct sdw_bus *bus) static int intel_prop_read(struct sdw_bus *bus)
{ {
struct sdw_master_prop *prop;
/* Initialize with default handler to read all DisCo properties */ /* Initialize with default handler to read all DisCo properties */
sdw_master_read_prop(bus); sdw_master_read_prop(bus);
/*
* Only one bus frequency is supported so far, filter
* frequencies reported in the DSDT
*/
prop = &bus->prop;
if (prop->clk_freq && prop->num_clk_freq > 1) {
unsigned int default_bus_frequency;
default_bus_frequency =
prop->default_frame_rate *
prop->default_row *
prop->default_col /
SDW_DOUBLE_RATE_FACTOR;
prop->num_clk_freq = 1;
prop->clk_freq[0] = default_bus_frequency;
prop->max_clk_freq = default_bus_frequency;
}
/* read Intel-specific properties */ /* read Intel-specific properties */
sdw_master_read_intel_prop(bus); sdw_master_read_intel_prop(bus);
......
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
// Copyright(c) 2015-2023 Intel Corporation. All rights reserved. // Copyright(c) 2015-2023 Intel Corporation
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw_registers.h>
......
...@@ -197,8 +197,7 @@ struct qcom_swrm_ctrl { ...@@ -197,8 +197,7 @@ struct qcom_swrm_ctrl {
int num_dout_ports; int num_dout_ports;
int cols_index; int cols_index;
int rows_index; int rows_index;
unsigned long dout_port_mask; unsigned long port_mask;
unsigned long din_port_mask;
u32 intr_mask; u32 intr_mask;
u8 rcmd_id; u8 rcmd_id;
u8 wcmd_id; u8 wcmd_id;
...@@ -1146,11 +1145,7 @@ static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, ...@@ -1146,11 +1145,7 @@ static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl,
mutex_lock(&ctrl->port_lock); mutex_lock(&ctrl->port_lock);
list_for_each_entry(m_rt, &stream->master_list, stream_node) { list_for_each_entry(m_rt, &stream->master_list, stream_node) {
if (m_rt->direction == SDW_DATA_DIR_RX) port_mask = &ctrl->port_mask;
port_mask = &ctrl->dout_port_mask;
else
port_mask = &ctrl->din_port_mask;
list_for_each_entry(p_rt, &m_rt->port_list, port_node) list_for_each_entry(p_rt, &m_rt->port_list, port_node)
clear_bit(p_rt->num, port_mask); clear_bit(p_rt->num, port_mask);
} }
...@@ -1195,13 +1190,9 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, ...@@ -1195,13 +1190,9 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
if (ctrl->bus.id != m_rt->bus->id) if (ctrl->bus.id != m_rt->bus->id)
continue; continue;
if (m_rt->direction == SDW_DATA_DIR_RX) { port_mask = &ctrl->port_mask;
maxport = ctrl->num_dout_ports; maxport = ctrl->num_dout_ports + ctrl->num_din_ports;
port_mask = &ctrl->dout_port_mask;
} else {
maxport = ctrl->num_din_ports;
port_mask = &ctrl->din_port_mask;
}
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave = s_rt->slave; slave = s_rt->slave;
...@@ -1401,8 +1392,7 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ...@@ -1401,8 +1392,7 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
return -EINVAL; return -EINVAL;
/* Valid port numbers are from 1-14, so mask out port 0 explicitly */ /* Valid port numbers are from 1-14, so mask out port 0 explicitly */
set_bit(0, &ctrl->dout_port_mask); set_bit(0, &ctrl->port_mask);
set_bit(0, &ctrl->din_port_mask);
ret = of_property_read_u8_array(np, "qcom,ports-offset1", ret = of_property_read_u8_array(np, "qcom,ports-offset1",
off1, nports); off1, nports);
......
...@@ -1181,6 +1181,8 @@ static struct sdw_master_runtime ...@@ -1181,6 +1181,8 @@ static struct sdw_master_runtime
m_rt->bus = bus; m_rt->bus = bus;
m_rt->stream = stream; m_rt->stream = stream;
bus->stream_refcount++;
return m_rt; return m_rt;
} }
...@@ -1217,6 +1219,7 @@ static void sdw_master_rt_free(struct sdw_master_runtime *m_rt, ...@@ -1217,6 +1219,7 @@ static void sdw_master_rt_free(struct sdw_master_runtime *m_rt,
struct sdw_stream_runtime *stream) struct sdw_stream_runtime *stream)
{ {
struct sdw_slave_runtime *s_rt, *_s_rt; struct sdw_slave_runtime *s_rt, *_s_rt;
struct sdw_bus *bus = m_rt->bus;
list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) { list_for_each_entry_safe(s_rt, _s_rt, &m_rt->slave_rt_list, m_rt_node) {
sdw_slave_port_free(s_rt->slave, stream); sdw_slave_port_free(s_rt->slave, stream);
...@@ -1226,6 +1229,8 @@ static void sdw_master_rt_free(struct sdw_master_runtime *m_rt, ...@@ -1226,6 +1229,8 @@ static void sdw_master_rt_free(struct sdw_master_runtime *m_rt,
list_del(&m_rt->stream_node); list_del(&m_rt->stream_node);
list_del(&m_rt->bus_node); list_del(&m_rt->bus_node);
kfree(m_rt); kfree(m_rt);
bus->stream_refcount--;
} }
/** /**
......
...@@ -903,6 +903,7 @@ struct sdw_master_ops { ...@@ -903,6 +903,7 @@ struct sdw_master_ops {
* meaningful if multi_link is set. If set to 1, hardware-based * meaningful if multi_link is set. If set to 1, hardware-based
* synchronization will be used even if a stream only uses a single * synchronization will be used even if a stream only uses a single
* SoundWire segment. * SoundWire segment.
* @stream_refcount: number of streams currently using this bus
*/ */
struct sdw_bus { struct sdw_bus {
struct device *dev; struct device *dev;
...@@ -933,6 +934,7 @@ struct sdw_bus { ...@@ -933,6 +934,7 @@ struct sdw_bus {
u32 bank_switch_timeout; u32 bank_switch_timeout;
bool multi_link; bool multi_link;
int hw_sync_min_links; int hw_sync_min_links;
int stream_refcount;
}; };
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
......
...@@ -182,6 +182,11 @@ ...@@ -182,6 +182,11 @@
#define SDW_SHIM2_INTEL_VS_ACTMCTL_DODSE BIT(2) #define SDW_SHIM2_INTEL_VS_ACTMCTL_DODSE BIT(2)
#define SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS GENMASK(4, 3) #define SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS GENMASK(4, 3)
#define SDW_SHIM2_INTEL_VS_ACTMCTL_DOAISE BIT(5) #define SDW_SHIM2_INTEL_VS_ACTMCTL_DOAISE BIT(5)
#define SDW_SHIM3_INTEL_VS_ACTMCTL_CLSS BIT(6)
#define SDW_SHIM3_INTEL_VS_ACTMCTL_CLDS GENMASK(11, 7)
#define SDW_SHIM3_INTEL_VS_ACTMCTL_DODSE2 GENMASK(13, 12)
#define SDW_SHIM3_INTEL_VS_ACTMCTL_DOAISE2 BIT(14)
#define SDW_SHIM3_INTEL_VS_ACTMCTL_CLDE BIT(15)
/** /**
* struct sdw_intel_stream_params_data: configuration passed during * struct sdw_intel_stream_params_data: configuration passed during
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment