soundwire updates for 7.1
- Core: DP prepare polling for avoiding interrupt deadlock - AMD clock init and bandwidth refactoring - Intel more codecs to wake list, clear message on before signaling waiting thread -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmnh3twACgkQfBQHDyUj g0eZwhAApdSFRhk43yNAMWr33Vxb+IFjRylNaJb6h5IWS7+0Z3yfq6zOuM3tW7Yh C9804L0RkncHwq6th0T5pi3neAwm/dVi1zmnzXiAe5Kgzl/Eru4ZNMh59VD8aNwQ K/emES6AJR6ulezYHNDE5Y74kjQHzMQUWiUo1DoAapoqr+WnZvfK+ZYAYh7I/ctY FxzBxx13yIHInDHsl3WQ+r1CSinDEe3RiQHW5+5DWdmmw8LfHLGUBBFIJQcVxRN/ 8NlNYr1wvRxUij11cZMPc3TetPfSsIGFpa7eOKezX1P9GxwY7qWvPvPmO0kzgLvH AsbFXOHZKYbtPy87agF1QdGq0Seym9x6OhNFucXs1yXIk1t/isv9bOrrOOmnSbR2 U3ycbMCUmJEUKhd7MWPWRaFUCEM2j/CRugFwpIbeE7AgJ5hZIUXlfWykDdlFxDTM e9IQ1jMTSnwyXs705FLLF3hxjIIAWS1kHIgEPWrxuSkAD9/Xx6sbD2fca7Ca6qrm W90TlprDAj/KiisEvje0tjEfZ8fTUanLC67d2sbxtrpzwpus4u8GzD62RAgsLlYP y9qGeAE1I5FMtJB83dewiYPCIofoez4DizM5wemojI+TtmvZwEWYfeXievD3ibad xN3uXtX6fqZ6BWUVIaxjdhSEB2FYdaZjTWPSmcUIwKlApOso0dY= =0cvn -----END PGP SIGNATURE----- Merge tag 'soundwire-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire Pull soundwire updates from Vinod Koul: - Core: DP prepare polling for avoiding interrupt deadlock - AMD clock init and bandwidth refactoring - Intel more codecs to wake list, clear message on before signaling waiting thread * tag 'soundwire-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: soundwire: intel_auxdevice: Add cs42l49 to wake_capable_list soundwire: cadence: Clear message complete before signaling waiting thread soundwire: Intel: test bus.bpt_stream before assigning it soundwire: bus: demote UNATTACHED state warnings to dev_dbg() soundwire: stream: Poll for DP prepare to avoid interrupt deadlock soundwire: amd: refactor bandwidth calculation logic soundwire: amd: add clock init control function soundwire: intel_auxdevice: Add CS47L47 to wake_capable_list soundwire: slave: Don't register devices that are disabled in ACPI soundwire: sdw.h: repair names and format of kernel-doc commentsmaster
commit
65bec0c4ea
|
|
@ -27,6 +27,36 @@
|
|||
|
||||
#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)
|
||||
{
|
||||
struct sdw_bus *bus = &amd_manager->bus;
|
||||
struct sdw_master_prop *prop = &bus->prop;
|
||||
u32 divider;
|
||||
|
||||
dev_dbg(amd_manager->dev, "mclk %d max %d row %d col %d frame_rate:%d\n",
|
||||
prop->mclk_freq, prop->max_clk_freq, prop->default_row,
|
||||
prop->default_col, prop->default_frame_rate);
|
||||
|
||||
if (!prop->default_frame_rate || !prop->default_row) {
|
||||
dev_err(amd_manager->dev, "Default frame_rate %d or row %d is invalid\n",
|
||||
prop->default_frame_rate, prop->default_row);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set clock divider */
|
||||
divider = (prop->mclk_freq / bus->params.curr_dr_freq);
|
||||
writel(divider, amd_manager->mmio + ACP_SW_CLK_FREQUENCY_CTRL);
|
||||
|
||||
/* Set frame shape base on the actual bus frequency. */
|
||||
prop->default_col = bus->params.curr_dr_freq /
|
||||
prop->default_frame_rate / prop->default_row;
|
||||
amd_manager->cols_index = sdw_find_col_index(prop->default_col);
|
||||
amd_manager->rows_index = sdw_find_row_index(prop->default_row);
|
||||
bus->params.col = prop->default_col;
|
||||
bus->params.row = prop->default_row;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amd_init_sdw_manager(struct amd_sdw_manager *amd_manager)
|
||||
{
|
||||
u32 val;
|
||||
|
|
@ -437,12 +467,16 @@ static u32 amd_sdw_read_ping_status(struct sdw_bus *bus)
|
|||
|
||||
static int amd_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};
|
||||
struct sdw_master_runtime *m_rt;
|
||||
struct sdw_port_runtime *p_rt;
|
||||
struct sdw_bus_params *b_params = &bus->params;
|
||||
int port_bo, hstart, hstop, sample_int;
|
||||
unsigned int rate, bps;
|
||||
unsigned int rate, bps, channels;
|
||||
unsigned int stream_slot_size, max_slots;
|
||||
static unsigned int next_offset[AMD_SDW_MAX_MANAGER_COUNT] = {1};
|
||||
unsigned int inst_id = amd_manager->instance;
|
||||
|
||||
port_bo = 0;
|
||||
hstart = 1;
|
||||
|
|
@ -453,11 +487,51 @@ static int amd_sdw_compute_params(struct sdw_bus *bus, struct sdw_stream_runtime
|
|||
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
|
||||
rate = m_rt->stream->params.rate;
|
||||
bps = m_rt->stream->params.bps;
|
||||
channels = m_rt->stream->params.ch_count;
|
||||
sample_int = (bus->params.curr_dr_freq / rate);
|
||||
|
||||
/* Compute slots required for this stream dynamically */
|
||||
stream_slot_size = bps * channels;
|
||||
|
||||
list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
|
||||
port_bo = (p_rt->num * 64) + 1;
|
||||
dev_dbg(bus->dev, "p_rt->num=%d hstart=%d hstop=%d port_bo=%d\n",
|
||||
p_rt->num, hstart, hstop, port_bo);
|
||||
if (p_rt->num >= amd_manager->max_ports) {
|
||||
dev_err(bus->dev, "Port %d exceeds max ports %d\n",
|
||||
p_rt->num, amd_manager->max_ports);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!amd_manager->port_offset_map[p_rt->num]) {
|
||||
/*
|
||||
* port block offset calculation for 6MHz bus clock frequency with
|
||||
* different frame sizes 50 x 10 and 125 x 2
|
||||
*/
|
||||
if (bus->params.curr_dr_freq == 12000000) {
|
||||
max_slots = bus->params.row * (bus->params.col - 1);
|
||||
if (next_offset[inst_id] + stream_slot_size <=
|
||||
(max_slots - 1)) {
|
||||
amd_manager->port_offset_map[p_rt->num] =
|
||||
next_offset[inst_id];
|
||||
next_offset[inst_id] += stream_slot_size;
|
||||
} else {
|
||||
dev_err(bus->dev,
|
||||
"No space for port %d\n", p_rt->num);
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* port block offset calculation for 12MHz bus clock
|
||||
* frequency
|
||||
*/
|
||||
amd_manager->port_offset_map[p_rt->num] =
|
||||
(p_rt->num * 64) + 1;
|
||||
}
|
||||
}
|
||||
port_bo = amd_manager->port_offset_map[p_rt->num];
|
||||
dev_dbg(bus->dev,
|
||||
"Port=%d hstart=%d hstop=%d port_bo=%d slots=%d max_ports=%d\n",
|
||||
p_rt->num, hstart, hstop, port_bo, stream_slot_size,
|
||||
amd_manager->max_ports);
|
||||
|
||||
sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
|
||||
false, SDW_BLK_GRP_CNT_1, sample_int,
|
||||
port_bo, port_bo >> 8, hstart, hstop,
|
||||
|
|
@ -960,6 +1034,9 @@ 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);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = amd_init_sdw_manager(amd_manager);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -984,7 +1061,6 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdw_master_prop *prop;
|
||||
struct sdw_bus_params *params;
|
||||
struct amd_sdw_manager *amd_manager;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1047,15 +1123,14 @@ static int amd_sdw_manager_probe(struct platform_device *pdev)
|
|||
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;
|
||||
|
||||
params = &amd_manager->bus.params;
|
||||
|
||||
params->col = AMD_SDW_DEFAULT_COLUMNS;
|
||||
params->row = AMD_SDW_DEFAULT_ROWS;
|
||||
prop = &amd_manager->bus.prop;
|
||||
prop->clk_freq = &amd_sdw_freq_tbl[0];
|
||||
prop->mclk_freq = AMD_SDW_BUS_BASE_FREQ;
|
||||
prop->max_clk_freq = AMD_SDW_DEFAULT_CLK_FREQ;
|
||||
|
||||
ret = sdw_bus_master_add(&amd_manager->bus, dev, dev->fwnode);
|
||||
if (ret) {
|
||||
|
|
@ -1347,6 +1422,9 @@ 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);
|
||||
if (ret)
|
||||
return ret;
|
||||
amd_init_sdw_manager(amd_manager);
|
||||
amd_enable_sdw_interrupts(amd_manager);
|
||||
ret = amd_enable_sdw_manager(amd_manager);
|
||||
|
|
|
|||
|
|
@ -203,10 +203,6 @@
|
|||
#define AMD_SDW_DEVICE_STATE_D3 3
|
||||
#define ACP_PME_EN 0x0001400
|
||||
|
||||
static u32 amd_sdw_freq_tbl[AMD_SDW_MAX_FREQ_NUM] = {
|
||||
AMD_SDW_DEFAULT_CLK_FREQ,
|
||||
};
|
||||
|
||||
struct sdw_manager_dp_reg {
|
||||
u32 frame_fmt_reg;
|
||||
u32 sample_int_reg;
|
||||
|
|
|
|||
|
|
@ -1899,8 +1899,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
|
|||
|
||||
if (status[i] == SDW_SLAVE_UNATTACHED &&
|
||||
slave->status != SDW_SLAVE_UNATTACHED) {
|
||||
dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n",
|
||||
i, slave->status);
|
||||
dev_dbg(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n",
|
||||
i, slave->status);
|
||||
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
|
||||
|
||||
/* Ensure driver knows that peripheral unattached */
|
||||
|
|
@ -1951,8 +1951,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
|
|||
if (slave->status == SDW_SLAVE_UNATTACHED)
|
||||
break;
|
||||
|
||||
dev_warn(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n",
|
||||
i, slave->status);
|
||||
dev_dbg(&slave->dev, "Slave %d state check2: UNATTACHED, status was %d\n",
|
||||
i, slave->status);
|
||||
|
||||
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -933,6 +933,14 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
|
|||
|
||||
cdns_read_response(cdns);
|
||||
|
||||
/*
|
||||
* Clear interrupt before signalling the completion to avoid
|
||||
* a race between this thread and the main thread starting
|
||||
* another TX.
|
||||
*/
|
||||
cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_RX_WL);
|
||||
int_status &= ~CDNS_MCP_INT_RX_WL;
|
||||
|
||||
if (defer && defer->msg) {
|
||||
cdns_fill_msg_resp(cdns, defer->msg,
|
||||
defer->length, 0);
|
||||
|
|
|
|||
|
|
@ -82,6 +82,11 @@ static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *
|
|||
int len;
|
||||
int i;
|
||||
|
||||
if (cdns->bus.bpt_stream) {
|
||||
dev_err(cdns->dev, "%s: BPT stream already exists\n", __func__);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
stream = sdw_alloc_stream("BPT", SDW_STREAM_BPT);
|
||||
if (!stream)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ struct wake_capable_part {
|
|||
static struct wake_capable_part wake_capable_list[] = {
|
||||
{0x01fa, 0x4243},
|
||||
{0x01fa, 0x4245},
|
||||
{0x01fa, 0x4249},
|
||||
{0x01fa, 0x4747},
|
||||
{0x025d, 0x5682},
|
||||
{0x025d, 0x700},
|
||||
{0x025d, 0x711},
|
||||
|
|
|
|||
|
|
@ -115,6 +115,9 @@ static bool find_slave(struct sdw_bus *bus,
|
|||
u64 addr;
|
||||
int ret;
|
||||
|
||||
if (acpi_bus_get_status(adev) || !acpi_dev_ready_for_enumeration(adev))
|
||||
return false;
|
||||
|
||||
ret = acpi_get_local_u64_address(adev->handle, &addr);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -18,6 +19,8 @@
|
|||
#include <sound/soc.h>
|
||||
#include "bus.h"
|
||||
|
||||
#define SDW_PORT_PREP_POLL_USEC 1000
|
||||
|
||||
/*
|
||||
* Array of supported rows and columns as per MIPI SoundWire Specification 1.1
|
||||
*
|
||||
|
|
@ -443,7 +446,6 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
|
|||
struct sdw_port_runtime *p_rt,
|
||||
bool prep)
|
||||
{
|
||||
struct completion *port_ready;
|
||||
struct sdw_dpn_prop *dpn_prop;
|
||||
struct sdw_prepare_ch prep_ch;
|
||||
u32 imp_def_interrupts;
|
||||
|
|
@ -518,14 +520,18 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for completion on port ready */
|
||||
port_ready = &s_rt->slave->port_ready[prep_ch.num];
|
||||
wait_for_completion_timeout(port_ready,
|
||||
msecs_to_jiffies(ch_prep_timeout));
|
||||
/*
|
||||
* Poll for NOT_PREPARED==0. Cannot use the interrupt because
|
||||
* this code holds bus_lock which blocks interrupt handling.
|
||||
*/
|
||||
ret = read_poll_timeout(sdw_read_no_pm, val,
|
||||
(val < 0) || ((val & p_rt->ch_mask) == 0),
|
||||
SDW_PORT_PREP_POLL_USEC, ch_prep_timeout * USEC_PER_MSEC,
|
||||
false, s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num));
|
||||
if (ret || (val < 0)) {
|
||||
if (val < 0)
|
||||
ret = val;
|
||||
|
||||
val = sdw_read_no_pm(s_rt->slave, SDW_DPN_PREPARESTATUS(p_rt->num));
|
||||
if ((val < 0) || (val & p_rt->ch_mask)) {
|
||||
ret = (val < 0) ? val : -ETIMEDOUT;
|
||||
dev_err(&s_rt->slave->dev,
|
||||
"Chn prep failed for port %d: %d\n", prep_ch.num, ret);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ struct sdw_slave_intr_status {
|
|||
};
|
||||
|
||||
/**
|
||||
* sdw_reg_bank - SoundWire register banks
|
||||
* enum sdw_reg_bank - SoundWire register banks
|
||||
* @SDW_BANK0: Soundwire register bank 0
|
||||
* @SDW_BANK1: Soundwire register bank 1
|
||||
*/
|
||||
|
|
@ -751,7 +751,7 @@ struct sdw_port_params {
|
|||
* struct sdw_transport_params: Data Port Transport Parameters
|
||||
*
|
||||
* @blk_grp_ctrl_valid: Port implements block group control
|
||||
* @num: Port number
|
||||
* @port_num: Port number
|
||||
* @blk_grp_ctrl: Block group control value
|
||||
* @sample_interval: Sample interval
|
||||
* @offset1: Blockoffset of the payload data
|
||||
|
|
@ -782,7 +782,7 @@ struct sdw_transport_params {
|
|||
/**
|
||||
* struct sdw_enable_ch: Enable/disable Data Port channel
|
||||
*
|
||||
* @num: Port number
|
||||
* @port_num: Port number
|
||||
* @ch_mask: Active channel mask
|
||||
* @enable: Enable (true) /disable (false) channel
|
||||
*/
|
||||
|
|
@ -885,7 +885,7 @@ void sdw_bus_master_delete(struct sdw_bus *bus);
|
|||
void sdw_show_ping_status(struct sdw_bus *bus, bool sync_delay);
|
||||
|
||||
/**
|
||||
* sdw_port_config: Master or Slave Port configuration
|
||||
* struct sdw_port_config: Master or Slave Port configuration
|
||||
*
|
||||
* @num: Port number
|
||||
* @ch_mask: channels mask for port
|
||||
|
|
@ -896,7 +896,7 @@ struct sdw_port_config {
|
|||
};
|
||||
|
||||
/**
|
||||
* sdw_stream_config: Master or Slave stream configuration
|
||||
* struct sdw_stream_config: Master or Slave stream configuration
|
||||
*
|
||||
* @frame_rate: Audio frame rate of the stream, in Hz
|
||||
* @ch_count: Channel count of the stream
|
||||
|
|
@ -913,7 +913,7 @@ struct sdw_stream_config {
|
|||
};
|
||||
|
||||
/**
|
||||
* sdw_stream_state: Stream states
|
||||
* enum sdw_stream_state: Stream states
|
||||
*
|
||||
* @SDW_STREAM_ALLOCATED: New stream allocated.
|
||||
* @SDW_STREAM_CONFIGURED: Stream configured
|
||||
|
|
@ -934,7 +934,7 @@ enum sdw_stream_state {
|
|||
};
|
||||
|
||||
/**
|
||||
* sdw_stream_params: Stream parameters
|
||||
* struct sdw_stream_params: Stream parameters
|
||||
*
|
||||
* @rate: Sampling frequency, in Hz
|
||||
* @ch_count: Number of channels
|
||||
|
|
@ -947,7 +947,7 @@ struct sdw_stream_params {
|
|||
};
|
||||
|
||||
/**
|
||||
* sdw_stream_runtime: Runtime stream parameters
|
||||
* struct sdw_stream_runtime: Runtime stream parameters
|
||||
*
|
||||
* @name: SoundWire stream name
|
||||
* @params: Stream parameters
|
||||
|
|
@ -983,7 +983,7 @@ struct sdw_stream_runtime {
|
|||
* @defer_msg: Defer message
|
||||
* @params: Current bus parameters
|
||||
* @stream_refcount: number of streams currently using this bus
|
||||
* @btp_stream_refcount: number of BTP streams currently using this bus (should
|
||||
* @bpt_stream_refcount: number of BTP streams currently using this bus (should
|
||||
* be zero or one, multiple streams per link is not supported).
|
||||
* @bpt_stream: pointer stored to handle BTP streams.
|
||||
* @ops: Master callback ops
|
||||
|
|
|
|||
|
|
@ -66,8 +66,10 @@ struct sdw_amd_dai_runtime {
|
|||
* @status: peripheral devices status array
|
||||
* @num_din_ports: number of input ports
|
||||
* @num_dout_ports: number of output ports
|
||||
* @max_ports: total number of input ports and output ports
|
||||
* @cols_index: Column index in frame shape
|
||||
* @rows_index: Rows index in frame shape
|
||||
* @port_offset_map: dynamic array to map port block offset
|
||||
* @instance: SoundWire manager instance
|
||||
* @quirks: SoundWire manager quirks
|
||||
* @wake_en_mask: wake enable mask per SoundWire manager
|
||||
|
|
@ -92,10 +94,12 @@ struct amd_sdw_manager {
|
|||
|
||||
int num_din_ports;
|
||||
int num_dout_ports;
|
||||
int max_ports;
|
||||
|
||||
int cols_index;
|
||||
int rows_index;
|
||||
|
||||
int *port_offset_map;
|
||||
u32 instance;
|
||||
u32 quirks;
|
||||
u32 wake_en_mask;
|
||||
|
|
|
|||
Loading…
Reference in New Issue