Commit 39b53e23 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'soundwire-5.13-rc1' of...

Merge tag 'soundwire-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire into char-misc-next

Vinod writes:

soundwire updates for 5.13-rc1

Updates for v5.13-rc1 are:

Core:
 - Ability to add quirks for masters
 - static checker cleanup for bus code

Drivers:
 - DMI quirks for Intel controllers
 - static checker cleanup for drivers
 - add auto enumeration support qcom controller

* tag 'soundwire-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (45 commits)
  soundwire: intel_init: test link->cdns
  soundwire: qcom: handle return correctly in qcom_swrm_transport_params
  soundwire: qcom: cleanup internal port config indexing
  soundwire: qcom: wait for fifo space to be available before read/write
  soundwire: qcom: add static port map support
  soundwire: qcom: update port map allocation bit mask
  soundwire: add static port mapping support
  soundwire: stream: fix memory leak in stream config error path
  soundwire: qcom: use signed variable for error return
  soundwire: qcom: wait for enumeration to be complete in probe
  soundwire: qcom: add auto enumeration support
  soundwire: export sdw_compare_devid, sdw_extract_slave_id and sdw_slave_add
  soundwire: qcom: add support to new interrupts
  soundwire: qcom: update register read/write routine
  soundwire: qcom: start the clock during initialization
  soundwire: qcom: set continue execution flag for ignored commands
  soundwire: qcom: add support to missing transport params
  dt-bindings: soundwire: qcom: clarify data port bus parameters
  soundwire: cadence: only prepare attached devices on clock stop
  soundwire: generic_allocation: fix confusion between group and packing
  ...
parents 177260a7 14968dd3
...@@ -54,6 +54,8 @@ board specific bus parameters. ...@@ -54,6 +54,8 @@ board specific bus parameters.
Value type: <prop-encoded-array> Value type: <prop-encoded-array>
Definition: should specify payload transport window offset1 of each Definition: should specify payload transport window offset1 of each
data port. Out ports followed by In ports. data port. Out ports followed by In ports.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,ports-offset2: - qcom,ports-offset2:
...@@ -61,6 +63,8 @@ board specific bus parameters. ...@@ -61,6 +63,8 @@ board specific bus parameters.
Value type: <prop-encoded-array> Value type: <prop-encoded-array>
Definition: should specify payload transport window offset2 of each Definition: should specify payload transport window offset2 of each
data port. Out ports followed by In ports. data port. Out ports followed by In ports.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,ports-sinterval-low: - qcom,ports-sinterval-low:
...@@ -69,12 +73,16 @@ board specific bus parameters. ...@@ -69,12 +73,16 @@ board specific bus parameters.
Definition: should be sample interval low of each data port. Definition: should be sample interval low of each data port.
Out ports followed by In ports. Used for Sample Interval Out ports followed by In ports. Used for Sample Interval
calculation. calculation.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,ports-word-length: - qcom,ports-word-length:
Usage: optional Usage: optional
Value type: <prop-encoded-array> Value type: <prop-encoded-array>
Definition: should be size of payload channel sample. Definition: should be size of payload channel sample.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,ports-block-pack-mode: - qcom,ports-block-pack-mode:
...@@ -84,6 +92,8 @@ board specific bus parameters. ...@@ -84,6 +92,8 @@ board specific bus parameters.
0 to indicate Blocks are per Channel 0 to indicate Blocks are per Channel
1 to indicate Blocks are per Port. 1 to indicate Blocks are per Port.
Out ports followed by In ports. Out ports followed by In ports.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,ports-block-group-count: - qcom,ports-block-group-count:
...@@ -92,6 +102,8 @@ board specific bus parameters. ...@@ -92,6 +102,8 @@ board specific bus parameters.
Definition: should be in range 1 to 4 to indicate how many sample Definition: should be in range 1 to 4 to indicate how many sample
intervals are combined into a payload. intervals are combined into a payload.
Out ports followed by In ports. Out ports followed by In ports.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,ports-lane-control: - qcom,ports-lane-control:
...@@ -100,6 +112,8 @@ board specific bus parameters. ...@@ -100,6 +112,8 @@ board specific bus parameters.
Definition: should be in range 0 to 7 to identify which data lane Definition: should be in range 0 to 7 to identify which data lane
the data port uses. the data port uses.
Out ports followed by In ports. Out ports followed by In ports.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,ports-hstart: - qcom,ports-hstart:
...@@ -109,6 +123,8 @@ board specific bus parameters. ...@@ -109,6 +123,8 @@ board specific bus parameters.
SoundWire Frame, i.e. left edge of the Transport sub-frame SoundWire Frame, i.e. left edge of the Transport sub-frame
for each port. Values between 0 and 15 are valid. for each port. Values between 0 and 15 are valid.
Out ports followed by In ports. Out ports followed by In ports.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,ports-hstop: - qcom,ports-hstop:
...@@ -118,6 +134,8 @@ board specific bus parameters. ...@@ -118,6 +134,8 @@ board specific bus parameters.
SoundWire Frame, i.e. the right edge of the Transport SoundWire Frame, i.e. the right edge of the Transport
sub-frame for each port. Values between 0 and 15 are valid. sub-frame for each port. Values between 0 and 15 are valid.
Out ports followed by In ports. Out ports followed by In ports.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
- qcom,dports-type: - qcom,dports-type:
...@@ -128,6 +146,8 @@ board specific bus parameters. ...@@ -128,6 +146,8 @@ board specific bus parameters.
1 for simple ports 1 for simple ports
2 for full port 2 for full port
Out ports followed by In ports. Out ports followed by In ports.
Value of 0xFF indicates that this option is not implemented
or applicable for the respective data port.
More info in MIPI Alliance SoundWire 1.0 Specifications. More info in MIPI Alliance SoundWire 1.0 Specifications.
Note: Note:
......
...@@ -20,7 +20,7 @@ soundwire-cadence-y := cadence_master.o ...@@ -20,7 +20,7 @@ soundwire-cadence-y := cadence_master.o
obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o obj-$(CONFIG_SOUNDWIRE_CADENCE) += soundwire-cadence.o
#Intel driver #Intel driver
soundwire-intel-y := intel.o intel_init.o soundwire-intel-y := intel.o intel_init.o dmi-quirks.o
obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o obj-$(CONFIG_SOUNDWIRE_INTEL) += soundwire-intel.o
#Qualcomm driver #Qualcomm driver
......
...@@ -44,13 +44,13 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, ...@@ -44,13 +44,13 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
} }
ret = sdw_get_id(bus); ret = sdw_get_id(bus);
if (ret) { if (ret < 0) {
dev_err(parent, "Failed to get bus id\n"); dev_err(parent, "Failed to get bus id\n");
return ret; return ret;
} }
ret = sdw_master_device_add(bus, parent, fwnode); ret = sdw_master_device_add(bus, parent, fwnode);
if (ret) { if (ret < 0) {
dev_err(parent, "Failed to add master device at link %d\n", dev_err(parent, "Failed to add master device at link %d\n",
bus->link_id); bus->link_id);
return ret; return ret;
...@@ -121,7 +121,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, ...@@ -121,7 +121,7 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
else else
ret = -ENOTSUPP; /* No ACPI/DT so error out */ ret = -ENOTSUPP; /* No ACPI/DT so error out */
if (ret) { if (ret < 0) {
dev_err(bus->dev, "Finding slaves failed:%d\n", ret); dev_err(bus->dev, "Finding slaves failed:%d\n", ret);
return ret; return ret;
} }
...@@ -422,7 +422,7 @@ sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr) ...@@ -422,7 +422,7 @@ sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr)
ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num,
SDW_MSG_FLAG_READ, &buf); SDW_MSG_FLAG_READ, &buf);
if (ret) if (ret < 0)
return ret; return ret;
ret = sdw_transfer(bus, &msg); ret = sdw_transfer(bus, &msg);
...@@ -440,7 +440,7 @@ sdw_bwrite_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value) ...@@ -440,7 +440,7 @@ sdw_bwrite_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value)
ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num,
SDW_MSG_FLAG_WRITE, &value); SDW_MSG_FLAG_WRITE, &value);
if (ret) if (ret < 0)
return ret; return ret;
return sdw_transfer(bus, &msg); return sdw_transfer(bus, &msg);
...@@ -454,7 +454,7 @@ int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr) ...@@ -454,7 +454,7 @@ int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr)
ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num,
SDW_MSG_FLAG_READ, &buf); SDW_MSG_FLAG_READ, &buf);
if (ret) if (ret < 0)
return ret; return ret;
ret = sdw_transfer_unlocked(bus, &msg); ret = sdw_transfer_unlocked(bus, &msg);
...@@ -472,7 +472,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val ...@@ -472,7 +472,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val
ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num, ret = sdw_fill_msg(&msg, NULL, addr, 1, dev_num,
SDW_MSG_FLAG_WRITE, &value); SDW_MSG_FLAG_WRITE, &value);
if (ret) if (ret < 0)
return ret; return ret;
return sdw_transfer_unlocked(bus, &msg); return sdw_transfer_unlocked(bus, &msg);
...@@ -593,7 +593,7 @@ EXPORT_SYMBOL(sdw_write); ...@@ -593,7 +593,7 @@ EXPORT_SYMBOL(sdw_write);
/* called with bus_lock held */ /* called with bus_lock held */
static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i)
{ {
struct sdw_slave *slave = NULL; struct sdw_slave *slave;
list_for_each_entry(slave, &bus->slaves, node) { list_for_each_entry(slave, &bus->slaves, node) {
if (slave->dev_num == i) if (slave->dev_num == i)
...@@ -603,7 +603,7 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i) ...@@ -603,7 +603,7 @@ static struct sdw_slave *sdw_get_slave(struct sdw_bus *bus, int i)
return NULL; return NULL;
} }
static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id)
{ {
if (slave->id.mfg_id != id.mfg_id || if (slave->id.mfg_id != id.mfg_id ||
slave->id.part_id != id.part_id || slave->id.part_id != id.part_id ||
...@@ -614,6 +614,7 @@ static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id) ...@@ -614,6 +614,7 @@ static int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id)
return 0; return 0;
} }
EXPORT_SYMBOL(sdw_compare_devid);
/* called with bus_lock held */ /* called with bus_lock held */
static int sdw_get_device_num(struct sdw_slave *slave) static int sdw_get_device_num(struct sdw_slave *slave)
...@@ -698,6 +699,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus, ...@@ -698,6 +699,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus,
"SDW Slave class_id 0x%02x, mfg_id 0x%04x, part_id 0x%04x, unique_id 0x%x, version 0x%x\n", "SDW Slave class_id 0x%02x, mfg_id 0x%04x, part_id 0x%04x, unique_id 0x%x, version 0x%x\n",
id->class_id, id->mfg_id, id->part_id, id->unique_id, id->sdw_version); id->class_id, id->mfg_id, id->part_id, id->unique_id, id->sdw_version);
} }
EXPORT_SYMBOL(sdw_extract_slave_id);
static int sdw_program_device_num(struct sdw_bus *bus) static int sdw_program_device_num(struct sdw_bus *bus)
{ {
...@@ -705,7 +707,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) ...@@ -705,7 +707,7 @@ static int sdw_program_device_num(struct sdw_bus *bus)
struct sdw_slave *slave, *_s; struct sdw_slave *slave, *_s;
struct sdw_slave_id id; struct sdw_slave_id id;
struct sdw_msg msg; struct sdw_msg msg;
bool found = false; bool found;
int count = 0, ret; int count = 0, ret;
u64 addr; u64 addr;
...@@ -737,6 +739,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) ...@@ -737,6 +739,7 @@ static int sdw_program_device_num(struct sdw_bus *bus)
sdw_extract_slave_id(bus, addr, &id); sdw_extract_slave_id(bus, addr, &id);
found = false;
/* Now compare with entries */ /* Now compare with entries */
list_for_each_entry_safe(slave, _s, &bus->slaves, node) { list_for_each_entry_safe(slave, _s, &bus->slaves, node) {
if (sdw_compare_devid(slave, id) == 0) { if (sdw_compare_devid(slave, id) == 0) {
...@@ -749,7 +752,7 @@ static int sdw_program_device_num(struct sdw_bus *bus) ...@@ -749,7 +752,7 @@ static int sdw_program_device_num(struct sdw_bus *bus)
* dev_num * dev_num
*/ */
ret = sdw_assign_device_num(slave); ret = sdw_assign_device_num(slave);
if (ret) { if (ret < 0) {
dev_err(bus->dev, dev_err(bus->dev,
"Assign dev_num failed:%d\n", "Assign dev_num failed:%d\n",
ret); ret);
...@@ -875,14 +878,18 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave, ...@@ -875,14 +878,18 @@ static int sdw_slave_clk_stop_prepare(struct sdw_slave *slave,
if (wake_en) if (wake_en)
val |= SDW_SCP_SYSTEMCTRL_WAKE_UP_EN; val |= SDW_SCP_SYSTEMCTRL_WAKE_UP_EN;
} else { } else {
val = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL); ret = sdw_read_no_pm(slave, SDW_SCP_SYSTEMCTRL);
if (ret < 0) {
dev_err(&slave->dev, "SDW_SCP_SYSTEMCTRL read failed:%d\n", ret);
return ret;
}
val = ret;
val &= ~(SDW_SCP_SYSTEMCTRL_CLK_STP_PREP); val &= ~(SDW_SCP_SYSTEMCTRL_CLK_STP_PREP);
} }
ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val); ret = sdw_write_no_pm(slave, SDW_SCP_SYSTEMCTRL, val);
if (ret != 0) if (ret < 0)
dev_err(&slave->dev, dev_err(&slave->dev,
"Clock Stop prepare failed for slave: %d", ret); "Clock Stop prepare failed for slave: %d", ret);
...@@ -895,11 +902,15 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) ...@@ -895,11 +902,15 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num)
int val; int val;
do { do {
val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT) & val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT);
SDW_SCP_STAT_CLK_STP_NF; if (val < 0) {
dev_err(bus->dev, "SDW_SCP_STAT bread failed:%d\n", val);
return val;
}
val &= SDW_SCP_STAT_CLK_STP_NF;
if (!val) { if (!val) {
dev_info(bus->dev, "clock stop prep/de-prep done slave:%d", dev_dbg(bus->dev, "clock stop prep/de-prep done slave:%d",
dev_num); dev_num);
return 0; return 0;
} }
...@@ -1253,6 +1264,7 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave) ...@@ -1253,6 +1264,7 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
static int sdw_initialize_slave(struct sdw_slave *slave) static int sdw_initialize_slave(struct sdw_slave *slave)
{ {
struct sdw_slave_prop *prop = &slave->prop; struct sdw_slave_prop *prop = &slave->prop;
int status;
int ret; int ret;
u8 val; u8 val;
...@@ -1260,6 +1272,44 @@ static int sdw_initialize_slave(struct sdw_slave *slave) ...@@ -1260,6 +1272,44 @@ static int sdw_initialize_slave(struct sdw_slave *slave)
if (ret < 0) if (ret < 0)
return ret; return ret;
if (slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH) {
/* Clear bus clash interrupt before enabling interrupt mask */
status = sdw_read_no_pm(slave, SDW_SCP_INT1);
if (status < 0) {
dev_err(&slave->dev,
"SDW_SCP_INT1 (BUS_CLASH) read failed:%d\n", status);
return status;
}
if (status & SDW_SCP_INT1_BUS_CLASH) {
dev_warn(&slave->dev, "Bus clash detected before INT mask is enabled\n");
ret = sdw_write_no_pm(slave, SDW_SCP_INT1, SDW_SCP_INT1_BUS_CLASH);
if (ret < 0) {
dev_err(&slave->dev,
"SDW_SCP_INT1 (BUS_CLASH) write failed:%d\n", ret);
return ret;
}
}
}
if ((slave->bus->prop.quirks & SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY) &&
!(slave->prop.quirks & SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY)) {
/* Clear parity interrupt before enabling interrupt mask */
status = sdw_read_no_pm(slave, SDW_SCP_INT1);
if (status < 0) {
dev_err(&slave->dev,
"SDW_SCP_INT1 (PARITY) read failed:%d\n", status);
return status;
}
if (status & SDW_SCP_INT1_PARITY) {
dev_warn(&slave->dev, "PARITY error detected before INT mask is enabled\n");
ret = sdw_write_no_pm(slave, SDW_SCP_INT1, SDW_SCP_INT1_PARITY);
if (ret < 0) {
dev_err(&slave->dev,
"SDW_SCP_INT1 (PARITY) write failed:%d\n", ret);
return ret;
}
}
}
/* /*
* Set SCP_INT1_MASK register, typically bus clash and * Set SCP_INT1_MASK register, typically bus clash and
* implementation-defined interrupt mask. The Parity detection * implementation-defined interrupt mask. The Parity detection
...@@ -1589,7 +1639,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1589,7 +1639,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
ret = sdw_read_no_pm(slave, SDW_SCP_INT1); ret = sdw_read_no_pm(slave, SDW_SCP_INT1);
if (ret < 0) { if (ret < 0) {
dev_err(&slave->dev, dev_err(&slave->dev,
"SDW_SCP_INT1 read failed:%d\n", ret); "SDW_SCP_INT1 recheck read failed:%d\n", ret);
goto io_err; goto io_err;
} }
_buf = ret; _buf = ret;
...@@ -1597,7 +1647,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1597,7 +1647,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, _buf2); ret = sdw_nread_no_pm(slave, SDW_SCP_INTSTAT2, 2, _buf2);
if (ret < 0) { if (ret < 0) {
dev_err(&slave->dev, dev_err(&slave->dev,
"SDW_SCP_INT2/3 read failed:%d\n", ret); "SDW_SCP_INT2/3 recheck read failed:%d\n", ret);
goto io_err; goto io_err;
} }
...@@ -1605,7 +1655,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1605,7 +1655,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
ret = sdw_read_no_pm(slave, SDW_DP0_INT); ret = sdw_read_no_pm(slave, SDW_DP0_INT);
if (ret < 0) { if (ret < 0) {
dev_err(&slave->dev, dev_err(&slave->dev,
"SDW_DP0_INT read failed:%d\n", ret); "SDW_DP0_INT recheck read failed:%d\n", ret);
goto io_err; goto io_err;
} }
sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; sdca_cascade = ret & SDW_DP0_SDCA_CASCADE;
...@@ -1701,7 +1751,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, ...@@ -1701,7 +1751,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
if (status[0] == SDW_SLAVE_ATTACHED) { if (status[0] == SDW_SLAVE_ATTACHED) {
dev_dbg(bus->dev, "Slave attached, programming device number\n"); dev_dbg(bus->dev, "Slave attached, programming device number\n");
ret = sdw_program_device_num(bus); ret = sdw_program_device_num(bus);
if (ret) if (ret < 0)
dev_err(bus->dev, "Slave attach failed: %d\n", ret); dev_err(bus->dev, "Slave attach failed: %d\n", ret);
/* /*
* programming a device number will have side effects, * programming a device number will have side effects,
...@@ -1735,7 +1785,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, ...@@ -1735,7 +1785,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
case SDW_SLAVE_ALERT: case SDW_SLAVE_ALERT:
ret = sdw_handle_slave_alerts(slave); ret = sdw_handle_slave_alerts(slave);
if (ret) if (ret < 0)
dev_err(&slave->dev, dev_err(&slave->dev,
"Slave %d alert handling failed: %d\n", "Slave %d alert handling failed: %d\n",
i, ret); i, ret);
...@@ -1754,7 +1804,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, ...@@ -1754,7 +1804,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
attached_initializing = true; attached_initializing = true;
ret = sdw_initialize_slave(slave); ret = sdw_initialize_slave(slave);
if (ret) if (ret < 0)
dev_err(&slave->dev, dev_err(&slave->dev,
"Slave %d initialization failed: %d\n", "Slave %d initialization failed: %d\n",
i, ret); i, ret);
...@@ -1768,7 +1818,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, ...@@ -1768,7 +1818,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
} }
ret = sdw_update_slave_status(slave, status[i]); ret = sdw_update_slave_status(slave, status[i]);
if (ret) if (ret < 0)
dev_err(&slave->dev, dev_err(&slave->dev,
"Update Slave status failed:%d\n", ret); "Update Slave status failed:%d\n", ret);
if (attached_initializing) { if (attached_initializing) {
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#define DEFAULT_BANK_SWITCH_TIMEOUT 3000 #define DEFAULT_BANK_SWITCH_TIMEOUT 3000
#define DEFAULT_PROBE_TIMEOUT 2000 #define DEFAULT_PROBE_TIMEOUT 2000
u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr);
#if IS_ENABLED(CONFIG_ACPI) #if IS_ENABLED(CONFIG_ACPI)
int sdw_acpi_find_slaves(struct sdw_bus *bus); int sdw_acpi_find_slaves(struct sdw_bus *bus);
#else #else
......
...@@ -82,6 +82,7 @@ static int sdw_drv_probe(struct device *dev) ...@@ -82,6 +82,7 @@ static int sdw_drv_probe(struct device *dev)
struct sdw_slave *slave = dev_to_sdw_dev(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); struct sdw_driver *drv = drv_to_sdw_driver(dev->driver);
const struct sdw_device_id *id; const struct sdw_device_id *id;
const char *name;
int ret; int ret;
/* /*
...@@ -108,7 +109,10 @@ static int sdw_drv_probe(struct device *dev) ...@@ -108,7 +109,10 @@ static int sdw_drv_probe(struct device *dev)
ret = drv->probe(slave, id); ret = drv->probe(slave, id);
if (ret) { if (ret) {
dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); name = drv->name;
if (!name)
name = drv->driver.name;
dev_err(dev, "Probe of %s failed: %d\n", name, ret);
dev_pm_domain_detach(dev, false); dev_pm_domain_detach(dev, false);
return ret; return ret;
} }
...@@ -174,11 +178,16 @@ static void sdw_drv_shutdown(struct device *dev) ...@@ -174,11 +178,16 @@ static void sdw_drv_shutdown(struct device *dev)
*/ */
int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) int __sdw_register_driver(struct sdw_driver *drv, struct module *owner)
{ {
const char *name;
drv->driver.bus = &sdw_bus_type; drv->driver.bus = &sdw_bus_type;
if (!drv->probe) { if (!drv->probe) {
pr_err("driver %s didn't provide SDW probe routine\n", name = drv->name;
drv->name); if (!name)
name = drv->driver.name;
pr_err("driver %s didn't provide SDW probe routine\n", name);
return -EINVAL; return -EINVAL;
} }
......
...@@ -905,7 +905,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) ...@@ -905,7 +905,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
EXPORT_SYMBOL(sdw_cdns_irq); EXPORT_SYMBOL(sdw_cdns_irq);
/** /**
* To update slave status in a work since we will need to handle * cdns_update_slave_status_work - update slave status in a work since we will need to handle
* other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave * other interrupts eg. CDNS_MCP_INT_RX_WL during the update slave
* process. * process.
* @work: cdns worker thread * @work: cdns worker thread
...@@ -968,7 +968,7 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns) ...@@ -968,7 +968,7 @@ int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
EXPORT_SYMBOL(sdw_cdns_exit_reset); EXPORT_SYMBOL(sdw_cdns_exit_reset);
/** /**
* sdw_cdns_enable_slave_interrupt() - Enable SDW slave interrupts * cdns_enable_slave_interrupts() - Enable SDW slave interrupts
* @cdns: Cadence instance * @cdns: Cadence instance
* @state: boolean for true/false * @state: boolean for true/false
*/ */
...@@ -1450,10 +1450,12 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) ...@@ -1450,10 +1450,12 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)
} }
/* Prepare slaves for clock stop */ /* Prepare slaves for clock stop */
ret = sdw_bus_prep_clk_stop(&cdns->bus); if (slave_present) {
if (ret < 0) { ret = sdw_bus_prep_clk_stop(&cdns->bus);
dev_err(cdns->dev, "prepare clock stop failed %d", ret); if (ret < 0 && ret != -ENODATA) {
return ret; dev_err(cdns->dev, "prepare clock stop failed %d\n", ret);
return ret;
}
} }
/* /*
...@@ -1462,7 +1464,7 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) ...@@ -1462,7 +1464,7 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)
*/ */
ret = sdw_bus_clk_stop(&cdns->bus); ret = sdw_bus_clk_stop(&cdns->bus);
if (ret < 0 && slave_present && ret != -ENODATA) { if (ret < 0 && slave_present && ret != -ENODATA) {
dev_err(cdns->dev, "bus clock stop failed %d", ret); dev_err(cdns->dev, "bus clock stop failed %d\n", ret);
return ret; return ret;
} }
......
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
// Copyright(c) 2021 Intel Corporation.
/*
* Soundwire DMI quirks
*/
#include <linux/device.h>
#include <linux/dmi.h>
#include <linux/soundwire/sdw.h>
#include "bus.h"
struct adr_remap {
u64 adr;
u64 remapped_adr;
};
/*
* HP Spectre 360 Convertible devices do not expose the correct _ADR
* in the DSDT.
* Remap the bad _ADR values to the ones reported by hardware
*/
static const struct adr_remap hp_spectre_360[] = {
{
0x000010025D070100,
0x000020025D071100
},
{
0x000110025d070100,
0x000120025D130800
},
{}
};
/*
* The initial version of the Dell SKU 0A3E did not expose the devices
* on the correct links.
*/
static const struct adr_remap dell_sku_0A3E[] = {
/* rt715 on link0 */
{
0x00020025d071100,
0x00021025d071500
},
/* rt711 on link1 */
{
0x000120025d130800,
0x000120025d071100,
},
/* rt1308 on link2 */
{
0x000220025d071500,
0x000220025d130800
},
{}
};
static const struct dmi_system_id adr_remap_quirk_table[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"),
},
.driver_data = (void *)hp_spectre_360,
},
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A3E")
},
.driver_data = (void *)dell_sku_0A3E,
},
{}
};
u64 sdw_dmi_override_adr(struct sdw_bus *bus, u64 addr)
{
const struct dmi_system_id *dmi_id;
/* check if any address remap quirk applies */
dmi_id = dmi_first_match(adr_remap_quirk_table);
if (dmi_id) {
struct adr_remap *map = dmi_id->driver_data;
for (map = dmi_id->driver_data; map->adr; map++) {
if (map->adr == addr) {
dev_dbg(bus->dev, "remapped _ADR 0x%llx as 0x%llx\n",
addr, map->remapped_adr);
addr = map->remapped_adr;
break;
}
}
}
return addr;
}
...@@ -62,7 +62,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, ...@@ -62,7 +62,7 @@ static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
sample_int, port_bo, port_bo >> 8, sample_int, port_bo, port_bo >> 8,
t_data->hstart, t_data->hstart,
t_data->hstop, t_data->hstop,
(SDW_BLK_GRP_CNT_1 * ch), 0x0); SDW_BLK_PKG_PER_PORT, 0x0);
sdw_fill_port_params(&p_rt->port_params, sdw_fill_port_params(&p_rt->port_params,
p_rt->num, bps, p_rt->num, bps,
...@@ -95,7 +95,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, ...@@ -95,7 +95,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
struct sdw_bus *bus = m_rt->bus; struct sdw_bus *bus = m_rt->bus;
struct sdw_bus_params *b_params = &bus->params; struct sdw_bus_params *b_params = &bus->params;
int sample_int, hstart = 0; int sample_int, hstart = 0;
unsigned int rate, bps, ch, no_ch; unsigned int rate, bps, ch;
rate = m_rt->stream->params.rate; rate = m_rt->stream->params.rate;
bps = m_rt->stream->params.bps; bps = m_rt->stream->params.bps;
...@@ -110,12 +110,11 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, ...@@ -110,12 +110,11 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
t_data.hstart = hstart; t_data.hstart = hstart;
list_for_each_entry(p_rt, &m_rt->port_list, port_node) { list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
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_GRP_CNT_1 * no_ch), 0x0); SDW_BLK_PKG_PER_PORT, 0x0);
sdw_fill_port_params(&p_rt->port_params, sdw_fill_port_params(&p_rt->port_params,
p_rt->num, bps, p_rt->num, bps,
...@@ -143,7 +142,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt, ...@@ -143,7 +142,7 @@ static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
static void _sdw_compute_port_params(struct sdw_bus *bus, static void _sdw_compute_port_params(struct sdw_bus *bus,
struct sdw_group_params *params, int count) struct sdw_group_params *params, int count)
{ {
struct sdw_master_runtime *m_rt = NULL; struct sdw_master_runtime *m_rt;
int hstop = bus->params.col - 1; int hstop = bus->params.col - 1;
int block_offset, port_bo, i; int block_offset, port_bo, i;
...@@ -169,7 +168,7 @@ static int sdw_compute_group_params(struct sdw_bus *bus, ...@@ -169,7 +168,7 @@ static int sdw_compute_group_params(struct sdw_bus *bus,
struct sdw_group_params *params, struct sdw_group_params *params,
int *rates, int count) int *rates, int count)
{ {
struct sdw_master_runtime *m_rt = NULL; struct sdw_master_runtime *m_rt;
int sel_col = bus->params.col; int sel_col = bus->params.col;
unsigned int rate, bps, ch; unsigned int rate, bps, ch;
int i, column_needed = 0; int i, column_needed = 0;
...@@ -406,14 +405,14 @@ int sdw_compute_params(struct sdw_bus *bus) ...@@ -406,14 +405,14 @@ int sdw_compute_params(struct sdw_bus *bus)
/* Computes clock frequency, frame shape and frame frequency */ /* Computes clock frequency, frame shape and frame frequency */
ret = sdw_compute_bus_params(bus); ret = sdw_compute_bus_params(bus);
if (ret < 0) { if (ret < 0) {
dev_err(bus->dev, "Compute bus params failed: %d", ret); dev_err(bus->dev, "Compute bus params failed: %d\n", ret);
return ret; return ret;
} }
/* Compute transport and port params */ /* Compute transport and port params */
ret = sdw_compute_port_params(bus); ret = sdw_compute_port_params(bus);
if (ret < 0) { if (ret < 0) {
dev_err(bus->dev, "Compute transport params failed: %d", ret); dev_err(bus->dev, "Compute transport params failed: %d\n", ret);
return ret; return ret;
} }
......
...@@ -561,8 +561,6 @@ static int intel_link_power_down(struct sdw_intel *sdw) ...@@ -561,8 +561,6 @@ static int intel_link_power_down(struct sdw_intel *sdw)
ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
} }
link_control = intel_readl(shim, SDW_SHIM_LCTL);
mutex_unlock(sdw->link_res->shim_lock); mutex_unlock(sdw->link_res->shim_lock);
if (ret < 0) { if (ret < 0) {
...@@ -997,7 +995,7 @@ static int intel_prepare(struct snd_pcm_substream *substream, ...@@ -997,7 +995,7 @@ static int intel_prepare(struct snd_pcm_substream *substream,
dma = snd_soc_dai_get_dma_data(dai, substream); dma = snd_soc_dai_get_dma_data(dai, substream);
if (!dma) { if (!dma) {
dev_err(dai->dev, "failed to get dma data in %s", dev_err(dai->dev, "failed to get dma data in %s\n",
__func__); __func__);
return -EIO; return -EIO;
} }
...@@ -1061,7 +1059,7 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ...@@ -1061,7 +1059,7 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
ret = intel_free_stream(sdw, substream, dai, sdw->instance); ret = intel_free_stream(sdw, substream, dai, sdw->instance);
if (ret < 0) { if (ret < 0) {
dev_err(dai->dev, "intel_free_stream: failed %d", ret); dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);
return ret; return ret;
} }
...@@ -1286,6 +1284,9 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) ...@@ -1286,6 +1284,9 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
prop->hw_disabled = true; prop->hw_disabled = true;
prop->quirks = SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH |
SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY;
return 0; return 0;
} }
...@@ -1302,6 +1303,7 @@ static int intel_prop_read(struct sdw_bus *bus) ...@@ -1302,6 +1303,7 @@ static int intel_prop_read(struct sdw_bus *bus)
static struct sdw_master_ops sdw_intel_ops = { static struct sdw_master_ops sdw_intel_ops = {
.read_prop = sdw_master_read_prop, .read_prop = sdw_master_read_prop,
.override_adr = sdw_dmi_override_adr,
.xfer_msg = cdns_xfer_msg, .xfer_msg = cdns_xfer_msg,
.xfer_msg_defer = cdns_xfer_msg_defer, .xfer_msg_defer = cdns_xfer_msg_defer,
.reset_page_addr = cdns_reset_page_addr, .reset_page_addr = cdns_reset_page_addr,
...@@ -1630,7 +1632,7 @@ static int __maybe_unused intel_suspend(struct device *dev) ...@@ -1630,7 +1632,7 @@ static int __maybe_unused intel_suspend(struct device *dev)
ret = intel_link_power_down(sdw); ret = intel_link_power_down(sdw);
if (ret) { if (ret) {
dev_err(dev, "Link power down failed: %d", ret); dev_err(dev, "Link power down failed: %d\n", ret);
return ret; return ret;
} }
...@@ -1665,7 +1667,7 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) ...@@ -1665,7 +1667,7 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev)
ret = intel_link_power_down(sdw); ret = intel_link_power_down(sdw);
if (ret) { if (ret) {
dev_err(dev, "Link power down failed: %d", ret); dev_err(dev, "Link power down failed: %d\n", ret);
return ret; return ret;
} }
...@@ -1689,7 +1691,7 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) ...@@ -1689,7 +1691,7 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev)
ret = intel_link_power_down(sdw); ret = intel_link_power_down(sdw);
if (ret) { if (ret) {
dev_err(dev, "Link power down failed: %d", ret); dev_err(dev, "Link power down failed: %d\n", ret);
return ret; return ret;
} }
...@@ -1738,7 +1740,7 @@ static int __maybe_unused intel_resume(struct device *dev) ...@@ -1738,7 +1740,7 @@ static int __maybe_unused intel_resume(struct device *dev)
ret = intel_init(sdw); ret = intel_init(sdw);
if (ret) { if (ret) {
dev_err(dev, "%s failed: %d", __func__, ret); dev_err(dev, "%s failed: %d\n", __func__, ret);
return ret; return ret;
} }
...@@ -1822,7 +1824,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ...@@ -1822,7 +1824,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) {
ret = intel_init(sdw); ret = intel_init(sdw);
if (ret) { if (ret) {
dev_err(dev, "%s failed: %d", __func__, ret); dev_err(dev, "%s failed: %d\n", __func__, ret);
return ret; return ret;
} }
...@@ -1867,7 +1869,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ...@@ -1867,7 +1869,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) {
ret = intel_init(sdw); ret = intel_init(sdw);
if (ret) { if (ret) {
dev_err(dev, "%s failed: %d", __func__, ret); dev_err(dev, "%s failed: %d\n", __func__, ret);
return ret; return ret;
} }
...@@ -1945,7 +1947,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ...@@ -1945,7 +1947,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
ret = intel_init(sdw); ret = intel_init(sdw);
if (ret) { if (ret) {
dev_err(dev, "%s failed: %d", __func__, ret); dev_err(dev, "%s failed: %d\n", __func__, ret);
return ret; return ret;
} }
......
...@@ -178,6 +178,15 @@ static struct sdw_intel_ctx ...@@ -178,6 +178,15 @@ static struct sdw_intel_ctx
link->pdev = pdev; link->pdev = pdev;
link->cdns = platform_get_drvdata(pdev); link->cdns = platform_get_drvdata(pdev);
if (!link->cdns) {
dev_err(&adev->dev, "failed to get link->cdns\n");
/*
* 1 will be subtracted from i in the err label, but we need to call
* intel_link_dev_unregister for this ldev, so plus 1 now
*/
i++;
goto err;
}
list_add_tail(&link->list, &ctx->link_list); list_add_tail(&link->list, &ctx->link_list);
bus = &link->cdns->bus; bus = &link->cdns->bus;
/* Calculate number of slaves */ /* Calculate number of slaves */
......
This diff is collapsed.
...@@ -88,6 +88,7 @@ int sdw_slave_add(struct sdw_bus *bus, ...@@ -88,6 +88,7 @@ int sdw_slave_add(struct sdw_bus *bus,
return ret; return ret;
} }
EXPORT_SYMBOL(sdw_slave_add);
#if IS_ENABLED(CONFIG_ACPI) #if IS_ENABLED(CONFIG_ACPI)
...@@ -95,7 +96,7 @@ static bool find_slave(struct sdw_bus *bus, ...@@ -95,7 +96,7 @@ static bool find_slave(struct sdw_bus *bus,
struct acpi_device *adev, struct acpi_device *adev,
struct sdw_slave_id *id) struct sdw_slave_id *id)
{ {
unsigned long long addr; u64 addr;
unsigned int link_id; unsigned int link_id;
acpi_status status; acpi_status status;
...@@ -108,6 +109,12 @@ static bool find_slave(struct sdw_bus *bus, ...@@ -108,6 +109,12 @@ static bool find_slave(struct sdw_bus *bus,
return false; return false;
} }
if (bus->ops->override_adr)
addr = bus->ops->override_adr(bus, addr);
if (!addr)
return false;
/* Extract link id from ADR, Bit 51 to 48 (included) */ /* Extract link id from ADR, Bit 51 to 48 (included) */
link_id = SDW_DISCO_LINK_ID(addr); link_id = SDW_DISCO_LINK_ID(addr);
......
...@@ -261,7 +261,7 @@ static int sdw_program_master_port_params(struct sdw_bus *bus, ...@@ -261,7 +261,7 @@ static int sdw_program_master_port_params(struct sdw_bus *bus,
*/ */
static int sdw_program_port_params(struct sdw_master_runtime *m_rt) static int sdw_program_port_params(struct sdw_master_runtime *m_rt)
{ {
struct sdw_slave_runtime *s_rt = NULL; struct sdw_slave_runtime *s_rt;
struct sdw_bus *bus = m_rt->bus; struct sdw_bus *bus = m_rt->bus;
struct sdw_port_runtime *p_rt; struct sdw_port_runtime *p_rt;
int ret = 0; int ret = 0;
...@@ -1375,8 +1375,16 @@ int sdw_stream_add_slave(struct sdw_slave *slave, ...@@ -1375,8 +1375,16 @@ int sdw_stream_add_slave(struct sdw_slave *slave,
} }
ret = sdw_config_stream(&slave->dev, stream, stream_config, true); ret = sdw_config_stream(&slave->dev, stream, stream_config, true);
if (ret) if (ret) {
/*
* sdw_release_master_stream will release s_rt in slave_rt_list in
* stream_error case, but s_rt is only added to slave_rt_list
* when sdw_config_stream is successful, so free s_rt explicitly
* when sdw_config_stream is failed.
*/
kfree(s_rt);
goto stream_error; goto stream_error;
}
list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list); list_add_tail(&s_rt->m_rt_node, &m_rt->slave_rt_list);
...@@ -1449,7 +1457,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave, ...@@ -1449,7 +1457,7 @@ struct sdw_dpn_prop *sdw_get_slave_dpn_prop(struct sdw_slave *slave,
static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt; struct sdw_master_runtime *m_rt;
struct sdw_bus *bus = NULL; struct sdw_bus *bus;
/* Iterate for all Master(s) in Master list */ /* Iterate for all Master(s) in Master list */
list_for_each_entry(m_rt, &stream->master_list, stream_node) { list_for_each_entry(m_rt, &stream->master_list, stream_node) {
...@@ -1470,8 +1478,8 @@ static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream) ...@@ -1470,8 +1478,8 @@ static void sdw_acquire_bus_lock(struct sdw_stream_runtime *stream)
*/ */
static void sdw_release_bus_lock(struct sdw_stream_runtime *stream) static void sdw_release_bus_lock(struct sdw_stream_runtime *stream)
{ {
struct sdw_master_runtime *m_rt = NULL; struct sdw_master_runtime *m_rt;
struct sdw_bus *bus = NULL; struct sdw_bus *bus;
/* Iterate for all Master(s) in Master list */ /* Iterate for all Master(s) in Master list */
list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) { list_for_each_entry_reverse(m_rt, &stream->master_list, stream_node) {
...@@ -1513,7 +1521,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream, ...@@ -1513,7 +1521,7 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream,
if (bus->compute_params) { if (bus->compute_params) {
ret = bus->compute_params(bus); ret = bus->compute_params(bus);
if (ret < 0) { if (ret < 0) {
dev_err(bus->dev, "Compute params failed: %d", dev_err(bus->dev, "Compute params failed: %d\n",
ret); ret);
return ret; return ret;
} }
...@@ -1791,7 +1799,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream) ...@@ -1791,7 +1799,7 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
if (bus->compute_params) { if (bus->compute_params) {
ret = bus->compute_params(bus); ret = bus->compute_params(bus);
if (ret < 0) { if (ret < 0) {
dev_err(bus->dev, "Compute params failed: %d", dev_err(bus->dev, "Compute params failed: %d\n",
ret); ret);
return ret; return ret;
} }
...@@ -1855,7 +1863,7 @@ static int set_stream(struct snd_pcm_substream *substream, ...@@ -1855,7 +1863,7 @@ static int set_stream(struct snd_pcm_substream *substream,
for_each_rtd_dais(rtd, i, dai) { for_each_rtd_dais(rtd, i, dai) {
ret = snd_soc_dai_set_sdw_stream(dai, sdw_stream, substream->stream); ret = snd_soc_dai_set_sdw_stream(dai, sdw_stream, substream->stream);
if (ret < 0) { if (ret < 0) {
dev_err(rtd->dev, "failed to set stream pointer on dai %s", dai->name); dev_err(rtd->dev, "failed to set stream pointer on dai %s\n", dai->name);
break; break;
} }
} }
...@@ -1888,7 +1896,7 @@ int sdw_startup_stream(void *sdw_substream) ...@@ -1888,7 +1896,7 @@ int sdw_startup_stream(void *sdw_substream)
sdw_stream = sdw_alloc_stream(name); sdw_stream = sdw_alloc_stream(name);
if (!sdw_stream) { if (!sdw_stream) {
dev_err(rtd->dev, "alloc stream failed for substream DAI %s", substream->name); dev_err(rtd->dev, "alloc stream failed for substream DAI %s\n", substream->name);
ret = -ENOMEM; ret = -ENOMEM;
goto error; goto error;
} }
...@@ -1927,7 +1935,7 @@ void sdw_shutdown_stream(void *sdw_substream) ...@@ -1927,7 +1935,7 @@ void sdw_shutdown_stream(void *sdw_substream)
sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream); sdw_stream = snd_soc_dai_get_sdw_stream(dai, substream->stream);
if (IS_ERR(sdw_stream)) { if (IS_ERR(sdw_stream)) {
dev_err(rtd->dev, "no stream found for DAI %s", dai->name); dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
return; return;
} }
......
...@@ -125,6 +125,12 @@ enum sdw_dpn_grouping { ...@@ -125,6 +125,12 @@ enum sdw_dpn_grouping {
SDW_BLK_GRP_CNT_4 = 3, SDW_BLK_GRP_CNT_4 = 3,
}; };
/* block packing mode enum */
enum sdw_dpn_pkg_mode {
SDW_BLK_PKG_PER_PORT = 0,
SDW_BLK_PKG_PER_CHANNEL = 1
};
/** /**
* enum sdw_stream_type: data stream type * enum sdw_stream_type: data stream type
* *
...@@ -405,6 +411,7 @@ struct sdw_slave_prop { ...@@ -405,6 +411,7 @@ struct sdw_slave_prop {
* command * command
* @mclk_freq: clock reference passed to SoundWire Master, in Hz. * @mclk_freq: clock reference passed to SoundWire Master, in Hz.
* @hw_disabled: if true, the Master is not functional, typically due to pin-mux * @hw_disabled: if true, the Master is not functional, typically due to pin-mux
* @quirks: bitmask identifying optional behavior beyond the scope of the MIPI specification
*/ */
struct sdw_master_prop { struct sdw_master_prop {
u32 revision; u32 revision;
...@@ -421,8 +428,29 @@ struct sdw_master_prop { ...@@ -421,8 +428,29 @@ struct sdw_master_prop {
u32 err_threshold; u32 err_threshold;
u32 mclk_freq; u32 mclk_freq;
bool hw_disabled; bool hw_disabled;
u64 quirks;
}; };
/* Definitions for Master quirks */
/*
* In a number of platforms bus clashes are reported after a hardware
* reset but without any explanations or evidence of a real problem.
* The following quirk will discard all initial bus clash interrupts
* but will leave the detection on should real bus clashes happen
*/
#define SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH BIT(0)
/*
* Some Slave devices have known issues with incorrect parity errors
* reported after a hardware reset. However during integration unexplained
* parity errors can be reported by Slave devices, possibly due to electrical
* issues at the Master level.
* The following quirk will discard all initial parity errors but will leave
* the detection on should real parity errors happen.
*/
#define SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY BIT(1)
int sdw_master_read_prop(struct sdw_bus *bus); int sdw_master_read_prop(struct sdw_bus *bus);
int sdw_slave_read_prop(struct sdw_slave *slave); int sdw_slave_read_prop(struct sdw_slave *slave);
...@@ -614,6 +642,7 @@ struct sdw_slave_ops { ...@@ -614,6 +642,7 @@ struct sdw_slave_ops {
* @debugfs: Slave debugfs * @debugfs: Slave debugfs
* @node: node for bus list * @node: node for bus list
* @port_ready: Port ready completion flag for each Slave port * @port_ready: Port ready completion flag for each Slave port
* @m_port_map: static Master port map for each Slave port
* @dev_num: Current Device Number, values can be 0 or dev_num_sticky * @dev_num: Current Device Number, values can be 0 or dev_num_sticky
* @dev_num_sticky: one-time static Device Number assigned by Bus * @dev_num_sticky: one-time static Device Number assigned by Bus
* @probed: boolean tracking driver state * @probed: boolean tracking driver state
...@@ -645,6 +674,7 @@ struct sdw_slave { ...@@ -645,6 +674,7 @@ struct sdw_slave {
#endif #endif
struct list_head node; struct list_head node;
struct completion port_ready[SDW_MAX_PORTS]; struct completion port_ready[SDW_MAX_PORTS];
unsigned int m_port_map[SDW_MAX_PORTS];
enum sdw_clk_stop_mode curr_clk_stop_mode; enum sdw_clk_stop_mode curr_clk_stop_mode;
u16 dev_num; u16 dev_num;
u16 dev_num_sticky; u16 dev_num_sticky;
...@@ -804,6 +834,7 @@ struct sdw_defer { ...@@ -804,6 +834,7 @@ struct sdw_defer {
/** /**
* struct sdw_master_ops - Master driver ops * struct sdw_master_ops - Master driver ops
* @read_prop: Read Master properties * @read_prop: Read Master properties
* @override_adr: Override value read from firmware (quirk for buggy firmware)
* @xfer_msg: Transfer message callback * @xfer_msg: Transfer message callback
* @xfer_msg_defer: Defer version of transfer message callback * @xfer_msg_defer: Defer version of transfer message callback
* @reset_page_addr: Reset the SCP page address registers * @reset_page_addr: Reset the SCP page address registers
...@@ -813,7 +844,8 @@ struct sdw_defer { ...@@ -813,7 +844,8 @@ struct sdw_defer {
*/ */
struct sdw_master_ops { struct sdw_master_ops {
int (*read_prop)(struct sdw_bus *bus); int (*read_prop)(struct sdw_bus *bus);
u64 (*override_adr)
(struct sdw_bus *bus, u64 addr);
enum sdw_command_response (*xfer_msg) enum sdw_command_response (*xfer_msg)
(struct sdw_bus *bus, struct sdw_msg *msg); (struct sdw_bus *bus, struct sdw_msg *msg);
enum sdw_command_response (*xfer_msg_defer) enum sdw_command_response (*xfer_msg_defer)
...@@ -1009,5 +1041,7 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value); ...@@ -1009,5 +1041,7 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value);
int sdw_read_no_pm(struct sdw_slave *slave, u32 addr); int sdw_read_no_pm(struct sdw_slave *slave, u32 addr);
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id);
#endif /* __SOUNDWIRE_H */ #endif /* __SOUNDWIRE_H */
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