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,10 +902,14 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) ...@@ -895,10 +902,14 @@ 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,11 +1450,13 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) ...@@ -1450,11 +1450,13 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake)
} }
/* Prepare slaves for clock stop */ /* Prepare slaves for clock stop */
if (slave_present) {
ret = sdw_bus_prep_clk_stop(&cdns->bus); ret = sdw_bus_prep_clk_stop(&cdns->bus);
if (ret < 0) { if (ret < 0 && ret != -ENODATA) {
dev_err(cdns->dev, "prepare clock stop failed %d", ret); dev_err(cdns->dev, "prepare clock stop failed %d\n", ret);
return ret; return ret;
} }
}
/* /*
* Enter clock stop mode and only report errors if there are * Enter clock stop mode and only report errors if there are
...@@ -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 */
......
...@@ -24,28 +24,50 @@ ...@@ -24,28 +24,50 @@
#define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1) #define SWRM_COMP_CFG_IRQ_LEVEL_OR_PULSE_MSK BIT(1)
#define SWRM_COMP_CFG_ENABLE_MSK BIT(0) #define SWRM_COMP_CFG_ENABLE_MSK BIT(0)
#define SWRM_COMP_PARAMS 0x100 #define SWRM_COMP_PARAMS 0x100
#define SWRM_COMP_PARAMS_WR_FIFO_DEPTH GENMASK(14, 10)
#define SWRM_COMP_PARAMS_RD_FIFO_DEPTH GENMASK(19, 15)
#define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0) #define SWRM_COMP_PARAMS_DOUT_PORTS_MASK GENMASK(4, 0)
#define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5) #define SWRM_COMP_PARAMS_DIN_PORTS_MASK GENMASK(9, 5)
#define SWRM_INTERRUPT_STATUS 0x200 #define SWRM_INTERRUPT_STATUS 0x200
#define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0) #define SWRM_INTERRUPT_STATUS_RMSK GENMASK(16, 0)
#define SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ BIT(0)
#define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1) #define SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED BIT(1)
#define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2) #define SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS BIT(2)
#define SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET BIT(3)
#define SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW BIT(4)
#define SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW BIT(5)
#define SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW BIT(6)
#define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7) #define SWRM_INTERRUPT_STATUS_CMD_ERROR BIT(7)
#define SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION BIT(8)
#define SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH BIT(9)
#define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10) #define SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED BIT(10)
#define SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2 BIT(13)
#define SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2 BIT(14)
#define SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP BIT(16)
#define SWRM_INTERRUPT_MAX 17
#define SWRM_INTERRUPT_MASK_ADDR 0x204 #define SWRM_INTERRUPT_MASK_ADDR 0x204
#define SWRM_INTERRUPT_CLEAR 0x208 #define SWRM_INTERRUPT_CLEAR 0x208
#define SWRM_INTERRUPT_CPU_EN 0x210 #define SWRM_INTERRUPT_CPU_EN 0x210
#define SWRM_CMD_FIFO_WR_CMD 0x300 #define SWRM_CMD_FIFO_WR_CMD 0x300
#define SWRM_CMD_FIFO_RD_CMD 0x304 #define SWRM_CMD_FIFO_RD_CMD 0x304
#define SWRM_CMD_FIFO_CMD 0x308 #define SWRM_CMD_FIFO_CMD 0x308
#define SWRM_CMD_FIFO_FLUSH 0x1
#define SWRM_CMD_FIFO_STATUS 0x30C #define SWRM_CMD_FIFO_STATUS 0x30C
#define SWRM_RD_CMD_FIFO_CNT_MASK GENMASK(20, 16)
#define SWRM_WR_CMD_FIFO_CNT_MASK GENMASK(12, 8)
#define SWRM_CMD_FIFO_CFG_ADDR 0x314 #define SWRM_CMD_FIFO_CFG_ADDR 0x314
#define SWRM_CONTINUE_EXEC_ON_CMD_IGNORE BIT(31)
#define SWRM_RD_WR_CMD_RETRIES 0x7 #define SWRM_RD_WR_CMD_RETRIES 0x7
#define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318 #define SWRM_CMD_FIFO_RD_FIFO_ADDR 0x318
#define SWRM_RD_FIFO_CMD_ID_MASK GENMASK(11, 8)
#define SWRM_ENUMERATOR_CFG_ADDR 0x500 #define SWRM_ENUMERATOR_CFG_ADDR 0x500
#define SWRM_ENUMERATOR_SLAVE_DEV_ID_1(m) (0x530 + 0x8 * (m))
#define SWRM_ENUMERATOR_SLAVE_DEV_ID_2(m) (0x534 + 0x8 * (m))
#define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m)) #define SWRM_MCP_FRAME_CTRL_BANK_ADDR(m) (0x101C + 0x40 * (m))
#define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0) #define SWRM_MCP_FRAME_CTRL_BANK_COL_CTRL_BMSK GENMASK(2, 0)
#define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3) #define SWRM_MCP_FRAME_CTRL_BANK_ROW_CTRL_BMSK GENMASK(7, 3)
#define SWRM_MCP_BUS_CTRL 0x1044
#define SWRM_MCP_BUS_CLK_START BIT(1)
#define SWRM_MCP_CFG_ADDR 0x1048 #define SWRM_MCP_CFG_ADDR 0x1048
#define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17) #define SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK GENMASK(21, 17)
#define SWRM_DEF_CMD_NO_PINGS 0x1f #define SWRM_DEF_CMD_NO_PINGS 0x1f
...@@ -53,8 +75,15 @@ ...@@ -53,8 +75,15 @@
#define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0) #define SWRM_MCP_STATUS_BANK_NUM_MASK BIT(0)
#define SWRM_MCP_SLV_STATUS 0x1090 #define SWRM_MCP_SLV_STATUS 0x1090
#define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0) #define SWRM_MCP_SLV_STATUS_MASK GENMASK(1, 0)
#define SWRM_MCP_SLV_STATUS_SZ 2
#define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DP_PORT_CTRL_BANK(n, m) (0x1124 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_PORT_CTRL_2_BANK(n, m) (0x1128 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_BLOCK_CTRL_1(n) (0x112C + 0x100 * (n - 1))
#define SWRM_DP_BLOCK_CTRL2_BANK(n, m) (0x1130 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_PORT_HCTRL_BANK(n, m) (0x1134 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m) #define SWRM_DP_BLOCK_CTRL3_BANK(n, m) (0x1138 + 0x100 * (n - 1) + 0x40 * m)
#define SWRM_DIN_DPn_PCM_PORT_CTRL(n) (0x1054 + 0x100 * (n - 1))
#define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18 #define SWRM_DP_PORT_CTRL_EN_CHAN_SHFT 0x18
#define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10 #define SWRM_DP_PORT_CTRL_OFFSET2_SHFT 0x10
#define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08 #define SWRM_DP_PORT_CTRL_OFFSET1_SHFT 0x08
...@@ -69,16 +98,28 @@ ...@@ -69,16 +98,28 @@
#define SWRM_SPECIAL_CMD_ID 0xF #define SWRM_SPECIAL_CMD_ID 0xF
#define MAX_FREQ_NUM 1 #define MAX_FREQ_NUM 1
#define TIMEOUT_MS (2 * HZ) #define TIMEOUT_MS (2 * HZ)
#define QCOM_SWRM_MAX_RD_LEN 0xf #define QCOM_SWRM_MAX_RD_LEN 0x1
#define QCOM_SDW_MAX_PORTS 14 #define QCOM_SDW_MAX_PORTS 14
#define DEFAULT_CLK_FREQ 9600000 #define DEFAULT_CLK_FREQ 9600000
#define SWRM_MAX_DAIS 0xF #define SWRM_MAX_DAIS 0xF
#define SWR_INVALID_PARAM 0xFF
#define SWR_HSTOP_MAX_VAL 0xF
#define SWR_HSTART_MIN_VAL 0x0
#define SWR_BROADCAST_CMD_ID 0x0F
#define SWR_MAX_CMD_ID 14
#define MAX_FIFO_RD_RETRY 3
#define SWR_OVERFLOW_RETRY_COUNT 30
struct qcom_swrm_port_config { struct qcom_swrm_port_config {
u8 si; u8 si;
u8 off1; u8 off1;
u8 off2; u8 off2;
u8 bp_mode; u8 bp_mode;
u8 hstart;
u8 hstop;
u8 word_length;
u8 blk_group_count;
u8 lane_control;
}; };
struct qcom_swrm_ctrl { struct qcom_swrm_ctrl {
...@@ -86,10 +127,9 @@ struct qcom_swrm_ctrl { ...@@ -86,10 +127,9 @@ struct qcom_swrm_ctrl {
struct device *dev; struct device *dev;
struct regmap *regmap; struct regmap *regmap;
void __iomem *mmio; void __iomem *mmio;
struct completion *comp; struct completion broadcast;
struct completion enumeration;
struct work_struct slave_work; struct work_struct slave_work;
/* read/write lock */
spinlock_t comp_lock;
/* Port alloc/free lock */ /* Port alloc/free lock */
struct mutex port_lock; struct mutex port_lock;
struct clk *hclk; struct clk *hclk;
...@@ -103,11 +143,17 @@ struct qcom_swrm_ctrl { ...@@ -103,11 +143,17 @@ struct qcom_swrm_ctrl {
int rows_index; int rows_index;
unsigned long dout_port_mask; unsigned long dout_port_mask;
unsigned long din_port_mask; unsigned long din_port_mask;
u32 intr_mask;
u8 rcmd_id;
u8 wcmd_id;
struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS]; struct qcom_swrm_port_config pconfig[QCOM_SDW_MAX_PORTS];
struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS]; struct sdw_stream_runtime *sruntime[SWRM_MAX_DAIS];
enum sdw_slave_status status[SDW_MAX_DEVICES]; enum sdw_slave_status status[SDW_MAX_DEVICES];
int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val); int (*reg_read)(struct qcom_swrm_ctrl *ctrl, int reg, u32 *val);
int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val); int (*reg_write)(struct qcom_swrm_ctrl *ctrl, int reg, int val);
u32 slave_status;
u32 wr_fifo_depth;
u32 rd_fifo_depth;
}; };
struct qcom_swrm_data { struct qcom_swrm_data {
...@@ -181,77 +227,180 @@ static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg, ...@@ -181,77 +227,180 @@ static int qcom_swrm_cpu_reg_write(struct qcom_swrm_ctrl *ctrl, int reg,
return SDW_CMD_OK; return SDW_CMD_OK;
} }
static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *ctrl, u8 cmd_data, static u32 swrm_get_packed_reg_val(u8 *cmd_id, u8 cmd_data,
u8 dev_addr, u16 reg_addr) u8 dev_addr, u16 reg_addr)
{ {
DECLARE_COMPLETION_ONSTACK(comp);
unsigned long flags;
u32 val; u32 val;
int ret; u8 id = *cmd_id;
spin_lock_irqsave(&ctrl->comp_lock, flags); if (id != SWR_BROADCAST_CMD_ID) {
ctrl->comp = &comp; if (id < SWR_MAX_CMD_ID)
spin_unlock_irqrestore(&ctrl->comp_lock, flags); id += 1;
val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, else
SWRM_SPECIAL_CMD_ID, reg_addr); id = 0;
ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_WR_CMD, val); *cmd_id = id;
if (ret) }
goto err; val = SWRM_REG_VAL_PACK(cmd_data, dev_addr, id, reg_addr);
ret = wait_for_completion_timeout(ctrl->comp, return val;
msecs_to_jiffies(TIMEOUT_MS)); }
static int swrm_wait_for_rd_fifo_avail(struct qcom_swrm_ctrl *swrm)
{
u32 fifo_outstanding_data, value;
int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT;
do {
/* Check for fifo underflow during read */
swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
fifo_outstanding_data = FIELD_GET(SWRM_RD_CMD_FIFO_CNT_MASK, value);
/* Check if read data is available in read fifo */
if (fifo_outstanding_data > 0)
return 0;
usleep_range(500, 510);
} while (fifo_retry_count--);
if (fifo_outstanding_data == 0) {
dev_err_ratelimited(swrm->dev, "%s err read underflow\n", __func__);
return -EIO;
}
return 0;
}
static int swrm_wait_for_wr_fifo_avail(struct qcom_swrm_ctrl *swrm)
{
u32 fifo_outstanding_cmds, value;
int fifo_retry_count = SWR_OVERFLOW_RETRY_COUNT;
do {
/* Check for fifo overflow during write */
swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
fifo_outstanding_cmds = FIELD_GET(SWRM_WR_CMD_FIFO_CNT_MASK, value);
/* Check for space in write fifo before writing */
if (fifo_outstanding_cmds < swrm->wr_fifo_depth)
return 0;
usleep_range(500, 510);
} while (fifo_retry_count--);
if (fifo_outstanding_cmds == swrm->wr_fifo_depth) {
dev_err_ratelimited(swrm->dev, "%s err write overflow\n", __func__);
return -EIO;
}
return 0;
}
static int qcom_swrm_cmd_fifo_wr_cmd(struct qcom_swrm_ctrl *swrm, u8 cmd_data,
u8 dev_addr, u16 reg_addr)
{
u32 val;
int ret = 0;
u8 cmd_id = 0x0;
if (dev_addr == SDW_BROADCAST_DEV_NUM) {
cmd_id = SWR_BROADCAST_CMD_ID;
val = swrm_get_packed_reg_val(&cmd_id, cmd_data,
dev_addr, reg_addr);
} else {
val = swrm_get_packed_reg_val(&swrm->wcmd_id, cmd_data,
dev_addr, reg_addr);
}
if (swrm_wait_for_wr_fifo_avail(swrm))
return SDW_CMD_FAIL_OTHER;
/* Its assumed that write is okay as we do not get any status back */
swrm->reg_write(swrm, SWRM_CMD_FIFO_WR_CMD, val);
/* version 1.3 or less */
if (swrm->version <= 0x01030000)
usleep_range(150, 155);
if (cmd_id == SWR_BROADCAST_CMD_ID) {
/*
* sleep for 10ms for MSM soundwire variant to allow broadcast
* command to complete.
*/
ret = wait_for_completion_timeout(&swrm->broadcast,
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) if (!ret)
ret = SDW_CMD_IGNORED; ret = SDW_CMD_IGNORED;
else else
ret = SDW_CMD_OK; ret = SDW_CMD_OK;
err:
spin_lock_irqsave(&ctrl->comp_lock, flags);
ctrl->comp = NULL;
spin_unlock_irqrestore(&ctrl->comp_lock, flags);
} else {
ret = SDW_CMD_OK;
}
return ret; return ret;
} }
static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *ctrl, static int qcom_swrm_cmd_fifo_rd_cmd(struct qcom_swrm_ctrl *swrm,
u8 dev_addr, u16 reg_addr, u8 dev_addr, u16 reg_addr,
u32 len, u8 *rval) u32 len, u8 *rval)
{ {
int i, ret; u32 cmd_data, cmd_id, val, retry_attempt = 0;
u32 val;
DECLARE_COMPLETION_ONSTACK(comp); val = swrm_get_packed_reg_val(&swrm->rcmd_id, len, dev_addr, reg_addr);
unsigned long flags;
/* wait for FIFO RD to complete to avoid overflow */
usleep_range(100, 105);
swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
/* wait for FIFO RD CMD complete to avoid overflow */
usleep_range(250, 255);
if (swrm_wait_for_rd_fifo_avail(swrm))
return SDW_CMD_FAIL_OTHER;
do {
swrm->reg_read(swrm, SWRM_CMD_FIFO_RD_FIFO_ADDR, &cmd_data);
rval[0] = cmd_data & 0xFF;
cmd_id = FIELD_GET(SWRM_RD_FIFO_CMD_ID_MASK, cmd_data);
if (cmd_id != swrm->rcmd_id) {
if (retry_attempt < (MAX_FIFO_RD_RETRY - 1)) {
/* wait 500 us before retry on fifo read failure */
usleep_range(500, 505);
swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD,
SWRM_CMD_FIFO_FLUSH);
swrm->reg_write(swrm, SWRM_CMD_FIFO_RD_CMD, val);
}
retry_attempt++;
} else {
return SDW_CMD_OK;
}
spin_lock_irqsave(&ctrl->comp_lock, flags); } while (retry_attempt < MAX_FIFO_RD_RETRY);
ctrl->comp = &comp;
spin_unlock_irqrestore(&ctrl->comp_lock, flags);
val = SWRM_REG_VAL_PACK(len, dev_addr, SWRM_SPECIAL_CMD_ID, reg_addr); dev_err(swrm->dev, "failed to read fifo: reg: 0x%x, rcmd_id: 0x%x,\
ret = ctrl->reg_write(ctrl, SWRM_CMD_FIFO_RD_CMD, val); dev_num: 0x%x, cmd_data: 0x%x\n",
if (ret) reg_addr, swrm->rcmd_id, dev_addr, cmd_data);
goto err;
ret = wait_for_completion_timeout(ctrl->comp, return SDW_CMD_IGNORED;
msecs_to_jiffies(TIMEOUT_MS)); }
if (!ret) { static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl)
ret = SDW_CMD_IGNORED; {
goto err; u32 val, status;
} else { int dev_num;
ret = SDW_CMD_OK;
}
for (i = 0; i < len; i++) { ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
ctrl->reg_read(ctrl, SWRM_CMD_FIFO_RD_FIFO_ADDR, &val);
rval[i] = val & 0xFF;
}
err: for (dev_num = 0; dev_num < SDW_MAX_DEVICES; dev_num++) {
spin_lock_irqsave(&ctrl->comp_lock, flags); status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ));
ctrl->comp = NULL;
spin_unlock_irqrestore(&ctrl->comp_lock, flags);
return ret; if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) {
ctrl->status[dev_num] = status;
return dev_num;
}
}
return -EINVAL;
} }
static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
...@@ -260,6 +409,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) ...@@ -260,6 +409,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
int i; int i;
ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
ctrl->slave_status = val;
for (i = 0; i < SDW_MAX_DEVICES; i++) { for (i = 0; i < SDW_MAX_DEVICES; i++) {
u32 s; u32 s;
...@@ -270,42 +420,188 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) ...@@ -270,42 +420,188 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
} }
} }
static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) static void qcom_swrm_set_slave_dev_num(struct sdw_bus *bus,
struct sdw_slave *slave, int devnum)
{ {
struct qcom_swrm_ctrl *ctrl = dev_id; struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
u32 sts, value; u32 status;
unsigned long flags;
ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &status);
status = (status >> (devnum * SWRM_MCP_SLV_STATUS_SZ));
status &= SWRM_MCP_SLV_STATUS_MASK;
if (status == SDW_SLAVE_ATTACHED) {
if (slave)
slave->dev_num = devnum;
mutex_lock(&bus->bus_lock);
set_bit(devnum, bus->assigned);
mutex_unlock(&bus->bus_lock);
}
}
ctrl->reg_read(ctrl, SWRM_INTERRUPT_STATUS, &sts); static int qcom_swrm_enumerate(struct sdw_bus *bus)
{
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
struct sdw_slave *slave, *_s;
struct sdw_slave_id id;
u32 val1, val2;
bool found;
u64 addr;
int i;
char *buf1 = (char *)&val1, *buf2 = (char *)&val2;
for (i = 1; i <= SDW_MAX_DEVICES; i++) {
/*SCP_Devid5 - Devid 4*/
ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_1(i), &val1);
/*SCP_Devid3 - DevId 2 Devid 1 Devid 0*/
ctrl->reg_read(ctrl, SWRM_ENUMERATOR_SLAVE_DEV_ID_2(i), &val2);
if (!val1 && !val2)
break;
addr = buf2[1] | (buf2[0] << 8) | (buf1[3] << 16) |
((u64)buf1[2] << 24) | ((u64)buf1[1] << 32) |
((u64)buf1[0] << 40);
sdw_extract_slave_id(bus, addr, &id);
found = false;
/* Now compare with entries */
list_for_each_entry_safe(slave, _s, &bus->slaves, node) {
if (sdw_compare_devid(slave, id) == 0) {
qcom_swrm_set_slave_dev_num(bus, slave, i);
found = true;
break;
}
}
if (sts & SWRM_INTERRUPT_STATUS_CMD_ERROR) { if (!found) {
ctrl->reg_read(ctrl, SWRM_CMD_FIFO_STATUS, &value); qcom_swrm_set_slave_dev_num(bus, NULL, i);
dev_err_ratelimited(ctrl->dev, sdw_slave_add(bus, &id, NULL);
"CMD error, fifo status 0x%x\n", }
value);
ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CMD, 0x1);
} }
if ((sts & SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED) || complete(&ctrl->enumeration);
sts & SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS) return 0;
schedule_work(&ctrl->slave_work); }
/** static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
* clear the interrupt before complete() is called, as complete can {
* schedule new read/writes which require interrupts, clearing the struct qcom_swrm_ctrl *swrm = dev_id;
* interrupt would avoid missing interrupts in such cases. u32 value, intr_sts, intr_sts_masked, slave_status;
*/ u32 i;
ctrl->reg_write(ctrl, SWRM_INTERRUPT_CLEAR, sts); int devnum;
int ret = IRQ_HANDLED;
swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts);
intr_sts_masked = intr_sts & swrm->intr_mask;
do {
for (i = 0; i < SWRM_INTERRUPT_MAX; i++) {
value = intr_sts_masked & BIT(i);
if (!value)
continue;
switch (value) {
case SWRM_INTERRUPT_STATUS_SLAVE_PEND_IRQ:
devnum = qcom_swrm_get_alert_slave_dev_num(swrm);
if (devnum < 0) {
dev_err_ratelimited(swrm->dev,
"no slave alert found.spurious interrupt\n");
} else {
sdw_handle_slave_status(&swrm->bus, swrm->status);
}
if (sts & SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED) { break;
spin_lock_irqsave(&ctrl->comp_lock, flags); case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED:
if (ctrl->comp) case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS:
complete(ctrl->comp); dev_err_ratelimited(swrm->dev, "%s: SWR new slave attached\n",
spin_unlock_irqrestore(&ctrl->comp_lock, flags); __func__);
swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, &slave_status);
if (swrm->slave_status == slave_status) {
dev_err(swrm->dev, "Slave status not changed %x\n",
slave_status);
} else {
qcom_swrm_get_device_status(swrm);
qcom_swrm_enumerate(&swrm->bus);
sdw_handle_slave_status(&swrm->bus, swrm->status);
} }
break;
case SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET:
dev_err_ratelimited(swrm->dev,
"%s: SWR bus clsh detected\n",
__func__);
swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_MASTER_CLASH_DET;
swrm->reg_write(swrm, SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
break;
case SWRM_INTERRUPT_STATUS_RD_FIFO_OVERFLOW:
swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
dev_err_ratelimited(swrm->dev,
"%s: SWR read FIFO overflow fifo status 0x%x\n",
__func__, value);
break;
case SWRM_INTERRUPT_STATUS_RD_FIFO_UNDERFLOW:
swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
dev_err_ratelimited(swrm->dev,
"%s: SWR read FIFO underflow fifo status 0x%x\n",
__func__, value);
break;
case SWRM_INTERRUPT_STATUS_WR_CMD_FIFO_OVERFLOW:
swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
dev_err(swrm->dev,
"%s: SWR write FIFO overflow fifo status %x\n",
__func__, value);
swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
break;
case SWRM_INTERRUPT_STATUS_CMD_ERROR:
swrm->reg_read(swrm, SWRM_CMD_FIFO_STATUS, &value);
dev_err_ratelimited(swrm->dev,
"%s: SWR CMD error, fifo status 0x%x, flushing fifo\n",
__func__, value);
swrm->reg_write(swrm, SWRM_CMD_FIFO_CMD, 0x1);
break;
case SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION:
dev_err_ratelimited(swrm->dev,
"%s: SWR Port collision detected\n",
__func__);
swrm->intr_mask &= ~SWRM_INTERRUPT_STATUS_DOUT_PORT_COLLISION;
swrm->reg_write(swrm,
SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
break;
case SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH:
dev_err_ratelimited(swrm->dev,
"%s: SWR read enable valid mismatch\n",
__func__);
swrm->intr_mask &=
~SWRM_INTERRUPT_STATUS_READ_EN_RD_VALID_MISMATCH;
swrm->reg_write(swrm,
SWRM_INTERRUPT_CPU_EN, swrm->intr_mask);
break;
case SWRM_INTERRUPT_STATUS_SPECIAL_CMD_ID_FINISHED:
complete(&swrm->broadcast);
break;
case SWRM_INTERRUPT_STATUS_BUS_RESET_FINISHED_V2:
break;
case SWRM_INTERRUPT_STATUS_CLK_STOP_FINISHED_V2:
break;
case SWRM_INTERRUPT_STATUS_EXT_CLK_STOP_WAKEUP:
break;
default:
dev_err_ratelimited(swrm->dev,
"%s: SWR unknown interrupt value: %d\n",
__func__, value);
ret = IRQ_NONE;
break;
}
}
swrm->reg_write(swrm, SWRM_INTERRUPT_CLEAR, intr_sts);
swrm->reg_read(swrm, SWRM_INTERRUPT_STATUS, &intr_sts);
intr_sts_masked = intr_sts & swrm->intr_mask;
} while (intr_sts_masked);
return IRQ_HANDLED; return ret;
} }
static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
{ {
u32 val; u32 val;
...@@ -316,9 +612,10 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ...@@ -316,9 +612,10 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val); ctrl->reg_write(ctrl, SWRM_MCP_FRAME_CTRL_BANK_ADDR(0), val);
/* Disable Auto enumeration */ /* Enable Auto enumeration */
ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 0); ctrl->reg_write(ctrl, SWRM_ENUMERATOR_CFG_ADDR, 1);
ctrl->intr_mask = SWRM_INTERRUPT_STATUS_RMSK;
/* Mask soundwire interrupts */ /* Mask soundwire interrupts */
ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR, ctrl->reg_write(ctrl, SWRM_INTERRUPT_MASK_ADDR,
SWRM_INTERRUPT_STATUS_RMSK); SWRM_INTERRUPT_STATUS_RMSK);
...@@ -328,8 +625,17 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ...@@ -328,8 +625,17 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK); u32p_replace_bits(&val, SWRM_DEF_CMD_NO_PINGS, SWRM_MCP_CFG_MAX_NUM_OF_CMD_NO_PINGS_BMSK);
ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val); ctrl->reg_write(ctrl, SWRM_MCP_CFG_ADDR, val);
ctrl->reg_write(ctrl, SWRM_MCP_BUS_CTRL, SWRM_MCP_BUS_CLK_START);
/* Configure number of retries of a read/write cmd */ /* Configure number of retries of a read/write cmd */
ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR, SWRM_RD_WR_CMD_RETRIES); if (ctrl->version > 0x01050001) {
/* Only for versions >= 1.5.1 */
ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
SWRM_RD_WR_CMD_RETRIES |
SWRM_CONTINUE_EXEC_ON_CMD_IGNORE);
} else {
ctrl->reg_write(ctrl, SWRM_CMD_FIFO_CFG_ADDR,
SWRM_RD_WR_CMD_RETRIES);
}
/* Set IRQ to PULSE */ /* Set IRQ to PULSE */
ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR, ctrl->reg_write(ctrl, SWRM_COMP_CFG_ADDR,
...@@ -341,6 +647,11 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ...@@ -341,6 +647,11 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN, ctrl->reg_write(ctrl, SWRM_INTERRUPT_CPU_EN,
SWRM_INTERRUPT_STATUS_RMSK); SWRM_INTERRUPT_STATUS_RMSK);
} }
ctrl->slave_status = 0;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
ctrl->rd_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_RD_FIFO_DEPTH, val);
ctrl->wr_fifo_depth = FIELD_GET(SWRM_COMP_PARAMS_WR_FIFO_DEPTH, val);
return 0; return 0;
} }
...@@ -396,8 +707,11 @@ static int qcom_swrm_port_params(struct sdw_bus *bus, ...@@ -396,8 +707,11 @@ static int qcom_swrm_port_params(struct sdw_bus *bus,
struct sdw_port_params *p_params, struct sdw_port_params *p_params,
unsigned int bank) unsigned int bank)
{ {
/* TBD */ struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
return 0;
return ctrl->reg_write(ctrl, SWRM_DP_BLOCK_CTRL_1(p_params->num),
p_params->bps - 1);
} }
static int qcom_swrm_transport_params(struct sdw_bus *bus, static int qcom_swrm_transport_params(struct sdw_bus *bus,
...@@ -405,22 +719,57 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus, ...@@ -405,22 +719,57 @@ static int qcom_swrm_transport_params(struct sdw_bus *bus,
enum sdw_reg_bank bank) enum sdw_reg_bank bank)
{ {
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus); struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
struct qcom_swrm_port_config *pcfg;
u32 value; u32 value;
int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank); int reg = SWRM_DP_PORT_CTRL_BANK((params->port_num), bank);
int ret; int ret;
value = params->offset1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT; pcfg = &ctrl->pconfig[params->port_num];
value |= params->offset2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
value |= params->sample_interval - 1; value = pcfg->off1 << SWRM_DP_PORT_CTRL_OFFSET1_SHFT;
value |= pcfg->off2 << SWRM_DP_PORT_CTRL_OFFSET2_SHFT;
value |= pcfg->si;
ret = ctrl->reg_write(ctrl, reg, value); ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
goto err;
if (!ret && params->blk_pkg_mode) { if (pcfg->lane_control != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank); reg = SWRM_DP_PORT_CTRL_2_BANK(params->port_num, bank);
value = pcfg->lane_control;
ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
goto err;
}
if (pcfg->blk_group_count != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL2_BANK(params->port_num, bank);
value = pcfg->blk_group_count;
ret = ctrl->reg_write(ctrl, reg, value);
if (ret)
goto err;
}
ret = ctrl->reg_write(ctrl, reg, 1); if (pcfg->hstart != SWR_INVALID_PARAM
&& pcfg->hstop != SWR_INVALID_PARAM) {
reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
value = (pcfg->hstop << 4) | pcfg->hstart;
ret = ctrl->reg_write(ctrl, reg, value);
} else {
reg = SWRM_DP_PORT_HCTRL_BANK(params->port_num, bank);
value = (SWR_HSTOP_MAX_VAL << 4) | SWR_HSTART_MIN_VAL;
ret = ctrl->reg_write(ctrl, reg, value);
} }
if (ret)
goto err;
if (pcfg->bp_mode != SWR_INVALID_PARAM) {
reg = SWRM_DP_BLOCK_CTRL3_BANK(params->port_num, bank);
ret = ctrl->reg_write(ctrl, reg, pcfg->bp_mode);
}
err:
return ret; return ret;
} }
...@@ -460,20 +809,31 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) ...@@ -460,20 +809,31 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
struct sdw_slave_runtime *s_rt; struct sdw_slave_runtime *s_rt;
struct sdw_port_runtime *p_rt; struct sdw_port_runtime *p_rt;
struct qcom_swrm_port_config *pcfg; struct qcom_swrm_port_config *pcfg;
int i = 0; struct sdw_slave *slave;
unsigned int m_port;
int i = 1;
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) { list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
list_for_each_entry(p_rt, &m_rt->port_list, port_node) { list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
pcfg = &ctrl->pconfig[p_rt->num - 1]; pcfg = &ctrl->pconfig[p_rt->num];
p_rt->transport_params.port_num = p_rt->num; p_rt->transport_params.port_num = p_rt->num;
p_rt->transport_params.sample_interval = pcfg->si + 1; if (pcfg->word_length != SWR_INVALID_PARAM) {
p_rt->transport_params.offset1 = pcfg->off1; sdw_fill_port_params(&p_rt->port_params,
p_rt->transport_params.offset2 = pcfg->off2; p_rt->num, pcfg->word_length + 1,
p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; SDW_PORT_FLOW_MODE_ISOCH,
SDW_PORT_DATA_MODE_NORMAL);
}
} }
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave = s_rt->slave;
list_for_each_entry(p_rt, &s_rt->port_list, port_node) { list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
m_port = slave->m_port_map[p_rt->num];
/* port config starts at offset 0 so -1 from actual port number */
if (m_port)
pcfg = &ctrl->pconfig[m_port];
else
pcfg = &ctrl->pconfig[i]; pcfg = &ctrl->pconfig[i];
p_rt->transport_params.port_num = p_rt->num; p_rt->transport_params.port_num = p_rt->num;
p_rt->transport_params.sample_interval = p_rt->transport_params.sample_interval =
...@@ -481,6 +841,18 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus) ...@@ -481,6 +841,18 @@ static int qcom_swrm_compute_params(struct sdw_bus *bus)
p_rt->transport_params.offset1 = pcfg->off1; p_rt->transport_params.offset1 = pcfg->off1;
p_rt->transport_params.offset2 = pcfg->off2; p_rt->transport_params.offset2 = pcfg->off2;
p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode; p_rt->transport_params.blk_pkg_mode = pcfg->bp_mode;
p_rt->transport_params.blk_grp_ctrl = pcfg->blk_group_count;
p_rt->transport_params.hstart = pcfg->hstart;
p_rt->transport_params.hstop = pcfg->hstop;
p_rt->transport_params.lane_ctrl = pcfg->lane_control;
if (pcfg->word_length != SWR_INVALID_PARAM) {
sdw_fill_port_params(&p_rt->port_params,
p_rt->num,
pcfg->word_length + 1,
SDW_PORT_FLOW_MODE_ISOCH,
SDW_PORT_DATA_MODE_NORMAL);
}
i++; i++;
} }
} }
...@@ -493,16 +865,6 @@ static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = { ...@@ -493,16 +865,6 @@ static u32 qcom_swrm_freq_tbl[MAX_FREQ_NUM] = {
DEFAULT_CLK_FREQ, DEFAULT_CLK_FREQ,
}; };
static void qcom_swrm_slave_wq(struct work_struct *work)
{
struct qcom_swrm_ctrl *ctrl =
container_of(work, struct qcom_swrm_ctrl, slave_work);
qcom_swrm_get_device_status(ctrl);
sdw_handle_slave_status(&ctrl->bus, ctrl->status);
}
static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl,
struct sdw_stream_runtime *stream) struct sdw_stream_runtime *stream)
{ {
...@@ -519,7 +881,7 @@ static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl, ...@@ -519,7 +881,7 @@ static void qcom_swrm_stream_free_ports(struct qcom_swrm_ctrl *ctrl,
port_mask = &ctrl->din_port_mask; port_mask = &ctrl->din_port_mask;
list_for_each_entry(p_rt, &m_rt->port_list, port_node) list_for_each_entry(p_rt, &m_rt->port_list, port_node)
clear_bit(p_rt->num - 1, port_mask); clear_bit(p_rt->num, port_mask);
} }
mutex_unlock(&ctrl->port_lock); mutex_unlock(&ctrl->port_lock);
...@@ -535,8 +897,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, ...@@ -535,8 +897,10 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
struct sdw_master_runtime *m_rt; struct sdw_master_runtime *m_rt;
struct sdw_slave_runtime *s_rt; struct sdw_slave_runtime *s_rt;
struct sdw_port_runtime *p_rt; struct sdw_port_runtime *p_rt;
struct sdw_slave *slave;
unsigned long *port_mask; unsigned long *port_mask;
int i, maxport, pn, nports = 0, ret = 0; int i, maxport, pn, nports = 0, ret = 0;
unsigned int m_port;
mutex_lock(&ctrl->port_lock); mutex_lock(&ctrl->port_lock);
list_for_each_entry(m_rt, &stream->master_list, stream_node) { list_for_each_entry(m_rt, &stream->master_list, stream_node) {
...@@ -549,16 +913,22 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, ...@@ -549,16 +913,22 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
} }
list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) { list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
slave = s_rt->slave;
list_for_each_entry(p_rt, &s_rt->port_list, port_node) { list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
m_port = slave->m_port_map[p_rt->num];
/* Port numbers start from 1 - 14*/ /* Port numbers start from 1 - 14*/
if (m_port)
pn = m_port;
else
pn = find_first_zero_bit(port_mask, maxport); pn = find_first_zero_bit(port_mask, maxport);
if (pn > (maxport - 1)) {
if (pn > maxport) {
dev_err(ctrl->dev, "All ports busy\n"); dev_err(ctrl->dev, "All ports busy\n");
ret = -EBUSY; ret = -EBUSY;
goto err; goto err;
} }
set_bit(pn, port_mask); set_bit(pn, port_mask);
pconfig[nports].num = pn + 1; pconfig[nports].num = pn;
pconfig[nports].ch_mask = p_rt->ch_mask; pconfig[nports].ch_mask = p_rt->ch_mask;
nports++; nports++;
} }
...@@ -580,7 +950,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, ...@@ -580,7 +950,7 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
err: err:
if (ret) { if (ret) {
for (i = 0; i < nports; i++) for (i = 0; i < nports; i++)
clear_bit(pconfig[i].num - 1, port_mask); clear_bit(pconfig[i].num, port_mask);
} }
mutex_unlock(&ctrl->port_lock); mutex_unlock(&ctrl->port_lock);
...@@ -652,7 +1022,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream, ...@@ -652,7 +1022,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream,
ret = snd_soc_dai_set_sdw_stream(codec_dai, sruntime, ret = snd_soc_dai_set_sdw_stream(codec_dai, sruntime,
substream->stream); substream->stream);
if (ret < 0 && ret != -ENOTSUPP) { if (ret < 0 && ret != -ENOTSUPP) {
dev_err(dai->dev, "Failed to set sdw stream on %s", dev_err(dai->dev, "Failed to set sdw stream on %s\n",
codec_dai->name); codec_dai->name);
sdw_release_stream(sruntime); sdw_release_stream(sruntime);
return ret; return ret;
...@@ -728,6 +1098,11 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ...@@ -728,6 +1098,11 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
u8 off2[QCOM_SDW_MAX_PORTS]; u8 off2[QCOM_SDW_MAX_PORTS];
u8 si[QCOM_SDW_MAX_PORTS]; u8 si[QCOM_SDW_MAX_PORTS];
u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, }; u8 bp_mode[QCOM_SDW_MAX_PORTS] = { 0, };
u8 hstart[QCOM_SDW_MAX_PORTS];
u8 hstop[QCOM_SDW_MAX_PORTS];
u8 word_length[QCOM_SDW_MAX_PORTS];
u8 blk_group_count[QCOM_SDW_MAX_PORTS];
u8 lane_control[QCOM_SDW_MAX_PORTS];
int i, ret, nports, val; int i, ret, nports, val;
ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val); ctrl->reg_read(ctrl, SWRM_COMP_PARAMS, &val);
...@@ -754,6 +1129,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ...@@ -754,6 +1129,9 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
ctrl->num_dout_ports = val; ctrl->num_dout_ports = val;
nports = ctrl->num_dout_ports + ctrl->num_din_ports; nports = ctrl->num_dout_ports + ctrl->num_din_ports;
/* Valid port numbers are from 1-14, so mask out port 0 explicitly */
set_bit(0, &ctrl->dout_port_mask);
set_bit(0, &ctrl->din_port_mask);
ret = of_property_read_u8_array(np, "qcom,ports-offset1", ret = of_property_read_u8_array(np, "qcom,ports-offset1",
off1, nports); off1, nports);
...@@ -772,11 +1150,35 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl) ...@@ -772,11 +1150,35 @@ static int qcom_swrm_get_port_config(struct qcom_swrm_ctrl *ctrl)
ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode", ret = of_property_read_u8_array(np, "qcom,ports-block-pack-mode",
bp_mode, nports); bp_mode, nports);
if (ret)
return ret;
memset(hstart, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-hstart", hstart, nports);
memset(hstop, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-hstop", hstop, nports);
memset(word_length, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-word-length", word_length, nports);
memset(blk_group_count, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-block-group-count", blk_group_count, nports);
memset(lane_control, SWR_INVALID_PARAM, QCOM_SDW_MAX_PORTS);
of_property_read_u8_array(np, "qcom,ports-lane-control", lane_control, nports);
for (i = 0; i < nports; i++) { for (i = 0; i < nports; i++) {
ctrl->pconfig[i].si = si[i]; /* Valid port number range is from 1-14 */
ctrl->pconfig[i].off1 = off1[i]; ctrl->pconfig[i + 1].si = si[i];
ctrl->pconfig[i].off2 = off2[i]; ctrl->pconfig[i + 1].off1 = off1[i];
ctrl->pconfig[i].bp_mode = bp_mode[i]; ctrl->pconfig[i + 1].off2 = off2[i];
ctrl->pconfig[i + 1].bp_mode = bp_mode[i];
ctrl->pconfig[i + 1].hstart = hstart[i];
ctrl->pconfig[i + 1].hstop = hstop[i];
ctrl->pconfig[i + 1].word_length = word_length[i];
ctrl->pconfig[i + 1].blk_group_count = blk_group_count[i];
ctrl->pconfig[i + 1].lane_control = lane_control[i];
} }
return 0; return 0;
...@@ -833,9 +1235,9 @@ static int qcom_swrm_probe(struct platform_device *pdev) ...@@ -833,9 +1235,9 @@ static int qcom_swrm_probe(struct platform_device *pdev)
ctrl->dev = dev; ctrl->dev = dev;
dev_set_drvdata(&pdev->dev, ctrl); dev_set_drvdata(&pdev->dev, ctrl);
spin_lock_init(&ctrl->comp_lock);
mutex_init(&ctrl->port_lock); mutex_init(&ctrl->port_lock);
INIT_WORK(&ctrl->slave_work, qcom_swrm_slave_wq); init_completion(&ctrl->broadcast);
init_completion(&ctrl->enumeration);
ctrl->bus.ops = &qcom_swrm_ops; ctrl->bus.ops = &qcom_swrm_ops;
ctrl->bus.port_ops = &qcom_swrm_port_ops; ctrl->bus.port_ops = &qcom_swrm_port_ops;
...@@ -882,6 +1284,8 @@ static int qcom_swrm_probe(struct platform_device *pdev) ...@@ -882,6 +1284,8 @@ static int qcom_swrm_probe(struct platform_device *pdev)
} }
qcom_swrm_init(ctrl); qcom_swrm_init(ctrl);
wait_for_completion_timeout(&ctrl->enumeration,
msecs_to_jiffies(TIMEOUT_MS));
ret = qcom_swrm_register_dais(ctrl); ret = qcom_swrm_register_dais(ctrl);
if (ret) if (ret)
goto err_master_add; goto err_master_add;
......
...@@ -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