soundwire updates for v5.3-rc1
Updates for 5.3 include: - module_sdw_driver macro for drivers - Documentation updates for code-blocks - Improvement from Pierre on intel and cadence driver - Clarification of DisCo properties and updates -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJdHtldAAoJEHwUBw8lI4NHf6AP/2glTkehAHh0C/zW7pgTk8na 7bHvEfp0kopdH+qcxyUwa7kBmI1x1ODBtrPIU++ZU7pPC1gXw0RUlOeOTa5HIw9/ uFQKRjbNUJ7/cVuvJZ16WEp3q2Uv5UG5OXlnT/kBFE87T2Zwov5/LKSUQMiHstgn Ix6aS0GgmHY9/4iFlxafR6SDhZ7Y1wN2gqKAM09K5QguFgGbG/6r+ioEOHEfkCSn tMiMXy2Koazrq1dRqdWL9PscVe0Yz3JxUDv9lED4OkyIY4zGHM5/LgfLuxzdhqmF vn9ZorS1AxOt7u5ewxuY8BLc//vqol1bbGzHFNfaOZ6/lmEsIBdXYKTQl8iyTZJP p/tdp2t9vWs+dDJ9BYXQpIEI/72Gcuu7g2kcwutLaWymp/OdTAjPhQGPc3NPUXgV aJv1D0Xwktdo/9jMBMpP4e8paM4KcGFeL1QkD545nVhVmCxt8Myf6RgktFEFtgS4 qLt6sl6ahea/0aAtOrQ9Uej3/dOG3S5dYpyXouyJ6mOkSNNAp3FSeNkQI1OayPBV owFqdnFeAJ9CR/Ae/Ua0yDMSeRIdk+a4WVS3vH9sxWJZtyIPfxQcoWamIMmzxrg7 g9+HorQjz6uOX+o1MzwD70RR6Hosc+sZaNiUsq/yyNbiJ7Ol/to2REMWgT+3XoLE X9Eio/OZ0sF9fZvCp8cI =ZOYI -----END PGP SIGNATURE----- Merge tag 'soundwire-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next Vinod writes: soundwire updates for v5.3-rc1 Updates for 5.3 include: - module_sdw_driver macro for drivers - Documentation updates for code-blocks - Improvement from Pierre on intel and cadence driver - Clarification of DisCo properties and updates * tag 'soundwire-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: soundwire: add module_sdw_driver helper macro docs: soundwire: locking: fix tags for a code-block soundwire: intel_init: add checks on link numbers soundwire: fix typo in comments soundwire: Intel: add log for number of PCM and PDM PDIs soundwire: cadence_master: check the number of bidir PDIs soundwire: cadence_master: log Slave status mask on errors soundwire: cadence_master: use rate_limited dynamic debug soundwire: rename/clarify MIPI DisCo properties soundwire: clarify comment soundwire: mipi-disco: fix clock stop modes soundwire: rename 'freq' fields soundwire: mipi-disco: remove master_count property for masters soundwire: remove master data port properties soundwire: add port-related definitions soundwire: mipi_disco: fix master/link error soundwire: intel: filter SoundWire controller device search soundwire: cdns: Fix compilation error on arm64alistair/sunxi64-5.4-dsi
commit
2f4281f4dc
|
@ -44,7 +44,9 @@ Message transfer.
|
||||||
b. Transfer message (Read/Write) to Slave1 or broadcast message on
|
b. Transfer message (Read/Write) to Slave1 or broadcast message on
|
||||||
Bus in case of bank switch.
|
Bus in case of bank switch.
|
||||||
|
|
||||||
c. Release Message lock ::
|
c. Release Message lock
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
+----------+ +---------+
|
+----------+ +---------+
|
||||||
| | | |
|
| | | |
|
||||||
|
|
|
@ -87,7 +87,7 @@ int sdw_add_bus_master(struct sdw_bus *bus)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize clock values based on Master properties. The max
|
* Initialize clock values based on Master properties. The max
|
||||||
* frequency is read from max_freq property. Current assumption
|
* frequency is read from max_clk_freq property. Current assumption
|
||||||
* is that the bus will start at highest clock frequency when
|
* is that the bus will start at highest clock frequency when
|
||||||
* powered on.
|
* powered on.
|
||||||
*
|
*
|
||||||
|
@ -95,7 +95,7 @@ int sdw_add_bus_master(struct sdw_bus *bus)
|
||||||
* to start with bank 0 (Table 40 of Spec)
|
* to start with bank 0 (Table 40 of Spec)
|
||||||
*/
|
*/
|
||||||
prop = &bus->prop;
|
prop = &bus->prop;
|
||||||
bus->params.max_dr_freq = prop->max_freq * SDW_DOUBLE_RATE_FACTOR;
|
bus->params.max_dr_freq = prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;
|
||||||
bus->params.curr_dr_freq = bus->params.max_dr_freq;
|
bus->params.curr_dr_freq = bus->params.max_dr_freq;
|
||||||
bus->params.curr_bank = SDW_BANK0;
|
bus->params.curr_bank = SDW_BANK0;
|
||||||
bus->params.next_bank = SDW_BANK1;
|
bus->params.next_bank = SDW_BANK1;
|
||||||
|
@ -648,7 +648,7 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Enable DP0 interrupts */
|
/* Enable DP0 interrupts */
|
||||||
val = prop->dp0_prop->device_interrupts;
|
val = prop->dp0_prop->imp_def_interrupts;
|
||||||
val |= SDW_DP0_INT_PORT_READY | SDW_DP0_INT_BRA_FAILURE;
|
val |= SDW_DP0_INT_PORT_READY | SDW_DP0_INT_BRA_FAILURE;
|
||||||
|
|
||||||
ret = sdw_update(slave, SDW_DP0_INTMASK, val, val);
|
ret = sdw_update(slave, SDW_DP0_INTMASK, val, val);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mod_devicetable.h>
|
#include <linux/mod_devicetable.h>
|
||||||
#include <linux/soundwire/sdw_registers.h>
|
#include <linux/soundwire/sdw_registers.h>
|
||||||
|
@ -236,19 +237,19 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns,
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
|
if (!(cdns->response_buf[i] & CDNS_MCP_RESP_ACK)) {
|
||||||
no_ack = 1;
|
no_ack = 1;
|
||||||
dev_dbg(cdns->dev, "Msg Ack not received\n");
|
dev_dbg_ratelimited(cdns->dev, "Msg Ack not received\n");
|
||||||
if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
|
if (cdns->response_buf[i] & CDNS_MCP_RESP_NACK) {
|
||||||
nack = 1;
|
nack = 1;
|
||||||
dev_err(cdns->dev, "Msg NACK received\n");
|
dev_err_ratelimited(cdns->dev, "Msg NACK received\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nack) {
|
if (nack) {
|
||||||
dev_err(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
|
dev_err_ratelimited(cdns->dev, "Msg NACKed for Slave %d\n", msg->dev_num);
|
||||||
return SDW_CMD_FAIL;
|
return SDW_CMD_FAIL;
|
||||||
} else if (no_ack) {
|
} else if (no_ack) {
|
||||||
dev_dbg(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
|
dev_dbg_ratelimited(cdns->dev, "Msg ignored for Slave %d\n", msg->dev_num);
|
||||||
return SDW_CMD_IGNORED;
|
return SDW_CMD_IGNORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,12 +357,12 @@ cdns_program_scp_addr(struct sdw_cdns *cdns, struct sdw_msg *msg)
|
||||||
|
|
||||||
/* For NACK, NO ack, don't return err if we are in Broadcast mode */
|
/* For NACK, NO ack, don't return err if we are in Broadcast mode */
|
||||||
if (nack) {
|
if (nack) {
|
||||||
dev_err(cdns->dev,
|
dev_err_ratelimited(cdns->dev,
|
||||||
"SCP_addrpage NACKed for Slave %d\n", msg->dev_num);
|
"SCP_addrpage NACKed for Slave %d\n", msg->dev_num);
|
||||||
return SDW_CMD_FAIL;
|
return SDW_CMD_FAIL;
|
||||||
} else if (no_ack) {
|
} else if (no_ack) {
|
||||||
dev_dbg(cdns->dev,
|
dev_dbg_ratelimited(cdns->dev,
|
||||||
"SCP_addrpage ignored for Slave %d\n", msg->dev_num);
|
"SCP_addrpage ignored for Slave %d\n", msg->dev_num);
|
||||||
return SDW_CMD_IGNORED;
|
return SDW_CMD_IGNORED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +487,8 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
|
||||||
{
|
{
|
||||||
enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
|
enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
|
||||||
bool is_slave = false;
|
bool is_slave = false;
|
||||||
u64 slave, mask;
|
u64 slave;
|
||||||
|
u32 mask;
|
||||||
int i, set_status;
|
int i, set_status;
|
||||||
|
|
||||||
/* combine the two status */
|
/* combine the two status */
|
||||||
|
@ -524,9 +526,9 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
|
||||||
|
|
||||||
/* first check if Slave reported multiple status */
|
/* first check if Slave reported multiple status */
|
||||||
if (set_status > 1) {
|
if (set_status > 1) {
|
||||||
dev_warn(cdns->dev,
|
dev_warn_ratelimited(cdns->dev,
|
||||||
"Slave reported multiple Status: %d\n",
|
"Slave reported multiple Status: %d\n",
|
||||||
status[i]);
|
mask);
|
||||||
/*
|
/*
|
||||||
* TODO: we need to reread the status here by
|
* TODO: we need to reread the status here by
|
||||||
* issuing a PING cmd
|
* issuing a PING cmd
|
||||||
|
@ -612,7 +614,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id)
|
||||||
struct sdw_cdns *cdns = dev_id;
|
struct sdw_cdns *cdns = dev_id;
|
||||||
u32 slave0, slave1;
|
u32 slave0, slave1;
|
||||||
|
|
||||||
dev_dbg(cdns->dev, "Slave status change\n");
|
dev_dbg_ratelimited(cdns->dev, "Slave status change\n");
|
||||||
|
|
||||||
slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
|
slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
|
||||||
slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
|
slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
|
||||||
|
@ -716,6 +718,8 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
|
||||||
stream = &cdns->pcm;
|
stream = &cdns->pcm;
|
||||||
|
|
||||||
/* First two PDIs are reserved for bulk transfers */
|
/* First two PDIs are reserved for bulk transfers */
|
||||||
|
if (stream->num_bd < CDNS_PCM_PDI_OFFSET)
|
||||||
|
return -EINVAL;
|
||||||
stream->num_bd -= CDNS_PCM_PDI_OFFSET;
|
stream->num_bd -= CDNS_PCM_PDI_OFFSET;
|
||||||
offset = CDNS_PCM_PDI_OFFSET;
|
offset = CDNS_PCM_PDI_OFFSET;
|
||||||
|
|
||||||
|
|
|
@ -263,6 +263,9 @@ static void intel_pdi_init(struct sdw_intel *sdw,
|
||||||
config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >>
|
config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >>
|
||||||
SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS);
|
SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS);
|
||||||
|
|
||||||
|
dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
|
||||||
|
config->pcm_bd, config->pcm_in, config->pcm_out);
|
||||||
|
|
||||||
/* PDM Stream Capability */
|
/* PDM Stream Capability */
|
||||||
pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
|
pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
|
||||||
|
|
||||||
|
@ -272,6 +275,9 @@ static void intel_pdi_init(struct sdw_intel *sdw,
|
||||||
SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS);
|
SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS);
|
||||||
config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >>
|
config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >>
|
||||||
SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS);
|
SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS);
|
||||||
|
|
||||||
|
dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n",
|
||||||
|
config->pdm_bd, config->pdm_in, config->pdm_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -796,13 +802,14 @@ static int intel_prop_read(struct sdw_bus *bus)
|
||||||
sdw_master_read_prop(bus);
|
sdw_master_read_prop(bus);
|
||||||
|
|
||||||
/* BIOS is not giving some values correctly. So, lets override them */
|
/* BIOS is not giving some values correctly. So, lets override them */
|
||||||
bus->prop.num_freq = 1;
|
bus->prop.num_clk_freq = 1;
|
||||||
bus->prop.freq = devm_kcalloc(bus->dev, bus->prop.num_freq,
|
bus->prop.clk_freq = devm_kcalloc(bus->dev, bus->prop.num_clk_freq,
|
||||||
sizeof(*bus->prop.freq), GFP_KERNEL);
|
sizeof(*bus->prop.clk_freq),
|
||||||
if (!bus->prop.freq)
|
GFP_KERNEL);
|
||||||
|
if (!bus->prop.clk_freq)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
bus->prop.freq[0] = bus->prop.max_freq;
|
bus->prop.clk_freq[0] = bus->prop.max_clk_freq;
|
||||||
bus->prop.err_threshold = 5;
|
bus->prop.err_threshold = 5;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#define __SDW_INTEL_LOCAL_H
|
#define __SDW_INTEL_LOCAL_H
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct sdw_intel_res - Soundwire link resources
|
* struct sdw_intel_link_res - Soundwire link resources
|
||||||
* @registers: Link IO registers base
|
* @registers: Link IO registers base
|
||||||
* @shim: Audio shim pointer
|
* @shim: Audio shim pointer
|
||||||
* @alh: ALH (Audio Link Hub) pointer
|
* @alh: ALH (Audio Link Hub) pointer
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/soundwire/sdw_intel.h>
|
#include <linux/soundwire/sdw_intel.h>
|
||||||
#include "intel.h"
|
#include "intel.h"
|
||||||
|
|
||||||
|
#define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */
|
||||||
#define SDW_MAX_LINKS 4
|
#define SDW_MAX_LINKS 4
|
||||||
#define SDW_SHIM_LCAP 0x0
|
#define SDW_SHIM_LCAP 0x0
|
||||||
#define SDW_SHIM_BASE 0x2C000
|
#define SDW_SHIM_BASE 0x2C000
|
||||||
|
@ -80,6 +81,7 @@ static struct sdw_intel_ctx
|
||||||
|
|
||||||
/* Check SNDWLCAP.LCOUNT */
|
/* Check SNDWLCAP.LCOUNT */
|
||||||
caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
|
caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
|
||||||
|
caps &= GENMASK(2, 0);
|
||||||
|
|
||||||
/* Check HW supported vs property value and use min of two */
|
/* Check HW supported vs property value and use min of two */
|
||||||
count = min_t(u8, caps, count);
|
count = min_t(u8, caps, count);
|
||||||
|
@ -89,6 +91,9 @@ static struct sdw_intel_ctx
|
||||||
dev_err(&adev->dev, "Link count %d exceeds max %d\n",
|
dev_err(&adev->dev, "Link count %d exceeds max %d\n",
|
||||||
count, SDW_MAX_LINKS);
|
count, SDW_MAX_LINKS);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
} else if (!count) {
|
||||||
|
dev_warn(&adev->dev, "No SoundWire links detected\n");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
|
dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
|
||||||
|
@ -150,6 +155,12 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
|
||||||
{
|
{
|
||||||
struct sdw_intel_res *res = cdata;
|
struct sdw_intel_res *res = cdata;
|
||||||
struct acpi_device *adev;
|
struct acpi_device *adev;
|
||||||
|
acpi_status status;
|
||||||
|
u64 adr;
|
||||||
|
|
||||||
|
status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return AE_OK; /* keep going */
|
||||||
|
|
||||||
if (acpi_bus_get_device(handle, &adev)) {
|
if (acpi_bus_get_device(handle, &adev)) {
|
||||||
pr_err("%s: Couldn't find ACPI handle\n", __func__);
|
pr_err("%s: Couldn't find ACPI handle\n", __func__);
|
||||||
|
@ -157,7 +168,19 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
|
||||||
}
|
}
|
||||||
|
|
||||||
res->handle = handle;
|
res->handle = handle;
|
||||||
return AE_OK;
|
|
||||||
|
/*
|
||||||
|
* On some Intel platforms, multiple children of the HDAS
|
||||||
|
* device can be found, but only one of them is the SoundWire
|
||||||
|
* controller. The SNDW device is always exposed with
|
||||||
|
* Name(_ADR, 0x40000000), with bits 31..28 representing the
|
||||||
|
* SoundWire link so filter accordingly
|
||||||
|
*/
|
||||||
|
if ((adr & GENMASK(31, 28)) >> 28 != SDW_LINK_TYPE)
|
||||||
|
return AE_OK; /* keep going */
|
||||||
|
|
||||||
|
/* device found, stop namespace walk */
|
||||||
|
return AE_CTRL_TERMINATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -40,7 +40,7 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
||||||
|
|
||||||
/* Find master handle */
|
/* Find master handle */
|
||||||
snprintf(name, sizeof(name),
|
snprintf(name, sizeof(name),
|
||||||
"mipi-sdw-master-%d-subproperties", bus->link_id);
|
"mipi-sdw-link-%d-subproperties", bus->link_id);
|
||||||
|
|
||||||
link = device_get_named_child_node(bus->dev, name);
|
link = device_get_named_child_node(bus->dev, name);
|
||||||
if (!link) {
|
if (!link) {
|
||||||
|
@ -50,39 +50,40 @@ int sdw_master_read_prop(struct sdw_bus *bus)
|
||||||
|
|
||||||
if (fwnode_property_read_bool(link,
|
if (fwnode_property_read_bool(link,
|
||||||
"mipi-sdw-clock-stop-mode0-supported"))
|
"mipi-sdw-clock-stop-mode0-supported"))
|
||||||
prop->clk_stop_mode = SDW_CLK_STOP_MODE0;
|
prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE0);
|
||||||
|
|
||||||
if (fwnode_property_read_bool(link,
|
if (fwnode_property_read_bool(link,
|
||||||
"mipi-sdw-clock-stop-mode1-supported"))
|
"mipi-sdw-clock-stop-mode1-supported"))
|
||||||
prop->clk_stop_mode |= SDW_CLK_STOP_MODE1;
|
prop->clk_stop_modes |= BIT(SDW_CLK_STOP_MODE1);
|
||||||
|
|
||||||
fwnode_property_read_u32(link,
|
fwnode_property_read_u32(link,
|
||||||
"mipi-sdw-max-clock-frequency",
|
"mipi-sdw-max-clock-frequency",
|
||||||
&prop->max_freq);
|
&prop->max_clk_freq);
|
||||||
|
|
||||||
nval = fwnode_property_read_u32_array(link,
|
nval = fwnode_property_read_u32_array(link,
|
||||||
"mipi-sdw-clock-frequencies-supported", NULL, 0);
|
"mipi-sdw-clock-frequencies-supported", NULL, 0);
|
||||||
if (nval > 0) {
|
if (nval > 0) {
|
||||||
prop->num_freq = nval;
|
prop->num_clk_freq = nval;
|
||||||
prop->freq = devm_kcalloc(bus->dev, prop->num_freq,
|
prop->clk_freq = devm_kcalloc(bus->dev, prop->num_clk_freq,
|
||||||
sizeof(*prop->freq), GFP_KERNEL);
|
sizeof(*prop->clk_freq),
|
||||||
if (!prop->freq)
|
GFP_KERNEL);
|
||||||
|
if (!prop->clk_freq)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
fwnode_property_read_u32_array(link,
|
fwnode_property_read_u32_array(link,
|
||||||
"mipi-sdw-clock-frequencies-supported",
|
"mipi-sdw-clock-frequencies-supported",
|
||||||
prop->freq, prop->num_freq);
|
prop->clk_freq, prop->num_clk_freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the frequencies supported. If FW doesn't provide max
|
* Check the frequencies supported. If FW doesn't provide max
|
||||||
* freq, then populate here by checking values.
|
* freq, then populate here by checking values.
|
||||||
*/
|
*/
|
||||||
if (!prop->max_freq && prop->freq) {
|
if (!prop->max_clk_freq && prop->clk_freq) {
|
||||||
prop->max_freq = prop->freq[0];
|
prop->max_clk_freq = prop->clk_freq[0];
|
||||||
for (i = 1; i < prop->num_freq; i++) {
|
for (i = 1; i < prop->num_clk_freq; i++) {
|
||||||
if (prop->freq[i] > prop->max_freq)
|
if (prop->clk_freq[i] > prop->max_clk_freq)
|
||||||
prop->max_freq = prop->freq[i];
|
prop->max_clk_freq = prop->clk_freq[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,13 +150,13 @@ static int sdw_slave_read_dp0(struct sdw_slave *slave,
|
||||||
dp0->words, dp0->num_words);
|
dp0->words, dp0->num_words);
|
||||||
}
|
}
|
||||||
|
|
||||||
dp0->flow_controlled = fwnode_property_read_bool(port,
|
dp0->BRA_flow_controlled = fwnode_property_read_bool(port,
|
||||||
"mipi-sdw-bra-flow-controlled");
|
"mipi-sdw-bra-flow-controlled");
|
||||||
|
|
||||||
dp0->simple_ch_prep_sm = fwnode_property_read_bool(port,
|
dp0->simple_ch_prep_sm = fwnode_property_read_bool(port,
|
||||||
"mipi-sdw-simplified-channel-prepare-sm");
|
"mipi-sdw-simplified-channel-prepare-sm");
|
||||||
|
|
||||||
dp0->device_interrupts = fwnode_property_read_bool(port,
|
dp0->imp_def_interrupts = fwnode_property_read_bool(port,
|
||||||
"mipi-sdw-imp-def-dp0-interrupts-supported");
|
"mipi-sdw-imp-def-dp0-interrupts-supported");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -224,7 +225,7 @@ static int sdw_slave_read_dpn(struct sdw_slave *slave,
|
||||||
|
|
||||||
fwnode_property_read_u32(node,
|
fwnode_property_read_u32(node,
|
||||||
"mipi-sdw-imp-def-dpn-interrupts-supported",
|
"mipi-sdw-imp-def-dpn-interrupts-supported",
|
||||||
&dpn[i].device_interrupts);
|
&dpn[i].imp_def_interrupts);
|
||||||
|
|
||||||
fwnode_property_read_u32(node, "mipi-sdw-min-channel-number",
|
fwnode_property_read_u32(node, "mipi-sdw-min-channel-number",
|
||||||
&dpn[i].min_ch);
|
&dpn[i].min_ch);
|
||||||
|
|
|
@ -439,7 +439,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
|
||||||
|
|
||||||
prep_ch.bank = bus->params.next_bank;
|
prep_ch.bank = bus->params.next_bank;
|
||||||
|
|
||||||
if (dpn_prop->device_interrupts || !dpn_prop->simple_ch_prep_sm)
|
if (dpn_prop->imp_def_interrupts || !dpn_prop->simple_ch_prep_sm)
|
||||||
intr = true;
|
intr = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -449,7 +449,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
|
||||||
*/
|
*/
|
||||||
if (prep && intr) {
|
if (prep && intr) {
|
||||||
ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
|
ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
|
||||||
dpn_prop->device_interrupts);
|
dpn_prop->imp_def_interrupts);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -493,7 +493,7 @@ static int sdw_prep_deprep_slave_ports(struct sdw_bus *bus,
|
||||||
/* Disable interrupt after Port de-prepare */
|
/* Disable interrupt after Port de-prepare */
|
||||||
if (!prep && intr)
|
if (!prep && intr)
|
||||||
ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
|
ret = sdw_configure_dpn_intr(s_rt->slave, p_rt->num, prep,
|
||||||
dpn_prop->device_interrupts);
|
dpn_prop->imp_def_interrupts);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1473,7 +1473,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
|
||||||
memcpy(¶ms, &bus->params, sizeof(params));
|
memcpy(¶ms, &bus->params, sizeof(params));
|
||||||
|
|
||||||
/* TODO: Support Asynchronous mode */
|
/* TODO: Support Asynchronous mode */
|
||||||
if ((prop->max_freq % stream->params.rate) != 0) {
|
if ((prop->max_clk_freq % stream->params.rate) != 0) {
|
||||||
dev_err(bus->dev, "Async mode not supported\n");
|
dev_err(bus->dev, "Async mode not supported\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,31 @@ struct sdw_slave;
|
||||||
#define SDW_DAI_ID_RANGE_START 100
|
#define SDW_DAI_ID_RANGE_START 100
|
||||||
#define SDW_DAI_ID_RANGE_END 200
|
#define SDW_DAI_ID_RANGE_END 200
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SDW_PORT_DIRN_SINK = 0,
|
||||||
|
SDW_PORT_DIRN_SOURCE,
|
||||||
|
SDW_PORT_DIRN_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* constants for flow control, ports and transport
|
||||||
|
*
|
||||||
|
* these are bit masks as devices can have multiple capabilities
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flow modes for SDW port. These can be isochronous, tx controlled,
|
||||||
|
* rx controlled or async
|
||||||
|
*/
|
||||||
|
#define SDW_PORT_FLOW_MODE_ISOCH 0
|
||||||
|
#define SDW_PORT_FLOW_MODE_TX_CNTRL BIT(0)
|
||||||
|
#define SDW_PORT_FLOW_MODE_RX_CNTRL BIT(1)
|
||||||
|
#define SDW_PORT_FLOW_MODE_ASYNC GENMASK(1, 0)
|
||||||
|
|
||||||
|
/* sample packaging for block. It can be per port or per channel */
|
||||||
|
#define SDW_BLOCK_PACKG_PER_PORT BIT(0)
|
||||||
|
#define SDW_BLOCK_PACKG_PER_CH BIT(1)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum sdw_slave_status - Slave status
|
* enum sdw_slave_status - Slave status
|
||||||
* @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus.
|
* @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus.
|
||||||
|
@ -76,6 +101,14 @@ enum sdw_command_response {
|
||||||
SDW_CMD_FAIL_OTHER = 4,
|
SDW_CMD_FAIL_OTHER = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* block group count enum */
|
||||||
|
enum sdw_dpn_grouping {
|
||||||
|
SDW_BLK_GRP_CNT_1 = 0,
|
||||||
|
SDW_BLK_GRP_CNT_2 = 1,
|
||||||
|
SDW_BLK_GRP_CNT_3 = 2,
|
||||||
|
SDW_BLK_GRP_CNT_4 = 3,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum sdw_stream_type: data stream type
|
* enum sdw_stream_type: data stream type
|
||||||
*
|
*
|
||||||
|
@ -100,6 +133,26 @@ enum sdw_data_direction {
|
||||||
SDW_DATA_DIR_TX = 1,
|
SDW_DATA_DIR_TX = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum sdw_port_data_mode: Data Port mode
|
||||||
|
*
|
||||||
|
* @SDW_PORT_DATA_MODE_NORMAL: Normal data mode where audio data is received
|
||||||
|
* and transmitted.
|
||||||
|
* @SDW_PORT_DATA_MODE_STATIC_1: Simple test mode which uses static value of
|
||||||
|
* logic 1. The encoding will result in signal transitions at every bitslot
|
||||||
|
* owned by this Port
|
||||||
|
* @SDW_PORT_DATA_MODE_STATIC_0: Simple test mode which uses static value of
|
||||||
|
* logic 0. The encoding will result in no signal transitions
|
||||||
|
* @SDW_PORT_DATA_MODE_PRBS: Test mode which uses a PRBS generator to produce
|
||||||
|
* a pseudo random data pattern that is transferred
|
||||||
|
*/
|
||||||
|
enum sdw_port_data_mode {
|
||||||
|
SDW_PORT_DATA_MODE_NORMAL = 0,
|
||||||
|
SDW_PORT_DATA_MODE_STATIC_1 = 1,
|
||||||
|
SDW_PORT_DATA_MODE_STATIC_0 = 2,
|
||||||
|
SDW_PORT_DATA_MODE_PRBS = 3,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SDW properties, defined in MIPI DisCo spec v1.0
|
* SDW properties, defined in MIPI DisCo spec v1.0
|
||||||
*/
|
*/
|
||||||
|
@ -153,10 +206,11 @@ enum sdw_clk_stop_mode {
|
||||||
* (inclusive)
|
* (inclusive)
|
||||||
* @num_words: number of wordlengths supported
|
* @num_words: number of wordlengths supported
|
||||||
* @words: wordlengths supported
|
* @words: wordlengths supported
|
||||||
* @flow_controlled: Slave implementation results in an OK_NotReady
|
* @BRA_flow_controlled: Slave implementation results in an OK_NotReady
|
||||||
* response
|
* response
|
||||||
* @simple_ch_prep_sm: If channel prepare sequence is required
|
* @simple_ch_prep_sm: If channel prepare sequence is required
|
||||||
* @device_interrupts: If implementation-defined interrupts are supported
|
* @imp_def_interrupts: If set, each bit corresponds to support for
|
||||||
|
* implementation-defined interrupts
|
||||||
*
|
*
|
||||||
* The wordlengths are specified by Spec as max, min AND number of
|
* The wordlengths are specified by Spec as max, min AND number of
|
||||||
* discrete values, implementation can define based on the wordlengths they
|
* discrete values, implementation can define based on the wordlengths they
|
||||||
|
@ -167,9 +221,9 @@ struct sdw_dp0_prop {
|
||||||
u32 min_word;
|
u32 min_word;
|
||||||
u32 num_words;
|
u32 num_words;
|
||||||
u32 *words;
|
u32 *words;
|
||||||
bool flow_controlled;
|
bool BRA_flow_controlled;
|
||||||
bool simple_ch_prep_sm;
|
bool simple_ch_prep_sm;
|
||||||
bool device_interrupts;
|
bool imp_def_interrupts;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -219,7 +273,7 @@ struct sdw_dpn_audio_mode {
|
||||||
* @simple_ch_prep_sm: If the port supports simplified channel prepare state
|
* @simple_ch_prep_sm: If the port supports simplified channel prepare state
|
||||||
* machine
|
* machine
|
||||||
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
|
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
|
||||||
* @device_interrupts: If set, each bit corresponds to support for
|
* @imp_def_interrupts: If set, each bit corresponds to support for
|
||||||
* implementation-defined interrupts
|
* implementation-defined interrupts
|
||||||
* @max_ch: Maximum channels supported
|
* @max_ch: Maximum channels supported
|
||||||
* @min_ch: Minimum channels supported
|
* @min_ch: Minimum channels supported
|
||||||
|
@ -244,7 +298,7 @@ struct sdw_dpn_prop {
|
||||||
u32 max_grouping;
|
u32 max_grouping;
|
||||||
bool simple_ch_prep_sm;
|
bool simple_ch_prep_sm;
|
||||||
u32 ch_prep_timeout;
|
u32 ch_prep_timeout;
|
||||||
u32 device_interrupts;
|
u32 imp_def_interrupts;
|
||||||
u32 max_ch;
|
u32 max_ch;
|
||||||
u32 min_ch;
|
u32 min_ch;
|
||||||
u32 num_ch;
|
u32 num_ch;
|
||||||
|
@ -311,36 +365,32 @@ struct sdw_slave_prop {
|
||||||
/**
|
/**
|
||||||
* struct sdw_master_prop - Master properties
|
* struct sdw_master_prop - Master properties
|
||||||
* @revision: MIPI spec version of the implementation
|
* @revision: MIPI spec version of the implementation
|
||||||
* @master_count: Number of masters
|
* @clk_stop_modes: Bitmap, bit N set when clock-stop-modeN supported
|
||||||
* @clk_stop_mode: Bitmap for Clock Stop modes supported
|
* @max_clk_freq: Maximum Bus clock frequency, in Hz
|
||||||
* @max_freq: Maximum Bus clock frequency, in Hz
|
|
||||||
* @num_clk_gears: Number of clock gears supported
|
* @num_clk_gears: Number of clock gears supported
|
||||||
* @clk_gears: Clock gears supported
|
* @clk_gears: Clock gears supported
|
||||||
* @num_freq: Number of clock frequencies supported, in Hz
|
* @num_clk_freq: Number of clock frequencies supported, in Hz
|
||||||
* @freq: Clock frequencies supported, in Hz
|
* @clk_freq: Clock frequencies supported, in Hz
|
||||||
* @default_frame_rate: Controller default Frame rate, in Hz
|
* @default_frame_rate: Controller default Frame rate, in Hz
|
||||||
* @default_row: Number of rows
|
* @default_row: Number of rows
|
||||||
* @default_col: Number of columns
|
* @default_col: Number of columns
|
||||||
* @dynamic_frame: Dynamic frame supported
|
* @dynamic_frame: Dynamic frame shape supported
|
||||||
* @err_threshold: Number of times that software may retry sending a single
|
* @err_threshold: Number of times that software may retry sending a single
|
||||||
* command
|
* command
|
||||||
* @dpn_prop: Data Port N properties
|
|
||||||
*/
|
*/
|
||||||
struct sdw_master_prop {
|
struct sdw_master_prop {
|
||||||
u32 revision;
|
u32 revision;
|
||||||
u32 master_count;
|
u32 clk_stop_modes;
|
||||||
enum sdw_clk_stop_mode clk_stop_mode;
|
u32 max_clk_freq;
|
||||||
u32 max_freq;
|
|
||||||
u32 num_clk_gears;
|
u32 num_clk_gears;
|
||||||
u32 *clk_gears;
|
u32 *clk_gears;
|
||||||
u32 num_freq;
|
u32 num_clk_freq;
|
||||||
u32 *freq;
|
u32 *clk_freq;
|
||||||
u32 default_frame_rate;
|
u32 default_frame_rate;
|
||||||
u32 default_row;
|
u32 default_row;
|
||||||
u32 default_col;
|
u32 default_col;
|
||||||
bool dynamic_frame;
|
bool dynamic_frame;
|
||||||
u32 err_threshold;
|
u32 err_threshold;
|
||||||
struct sdw_dpn_prop *dpn_prop;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int sdw_master_read_prop(struct sdw_bus *bus);
|
int sdw_master_read_prop(struct sdw_bus *bus);
|
||||||
|
|
|
@ -16,4 +16,15 @@ void sdw_unregister_driver(struct sdw_driver *drv);
|
||||||
|
|
||||||
int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size);
|
int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* module_sdw_driver() - Helper macro for registering a Soundwire driver
|
||||||
|
* @__sdw_driver: soundwire slave driver struct
|
||||||
|
*
|
||||||
|
* Helper macro for Soundwire drivers which do not do anything special in
|
||||||
|
* module init/exit. This eliminates a lot of boilerplate. Each module may only
|
||||||
|
* use this macro once, and calling it replaces module_init() and module_exit()
|
||||||
|
*/
|
||||||
|
#define module_sdw_driver(__sdw_driver) \
|
||||||
|
module_driver(__sdw_driver, sdw_register_driver, \
|
||||||
|
sdw_unregister_driver)
|
||||||
#endif /* __SOUNDWIRE_TYPES_H */
|
#endif /* __SOUNDWIRE_TYPES_H */
|
||||||
|
|
Loading…
Reference in New Issue