Commit 881eccbe authored by Linus Torvalds's avatar Linus Torvalds

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

Pull soundwire updates from Vinod Koul:
 "Updates for Intel, Cadence and Qualcomm drivers:

   - another round of Intel driver cleanup to prepare for future code
     reorg which is expected in next cycle (Pierre-Louis Bossart)

   - bus unattach notifications processing during re-enumeration along
     with Cadence driver updates for this (Richard Fitzgerald)

   - Qualcomm driver updates to handle device0 status (Srinivas
     Kandagatla)"

* tag 'soundwire-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (42 commits)
  soundwire: intel: add helper to stop bus
  soundwire: intel: introduce helpers to start bus
  soundwire: intel: introduce intel_shim_check_wake() helper
  soundwire: intel: simplify read ops assignment
  soundwire: intel: remove intel_init() wrapper
  soundwire: intel: move shim initialization before power up/down
  soundwire: intel: remove clock_stop parameter in intel_shim_init()
  soundwire: intel: move all PDI initialization under intel_register_dai()
  soundwire: intel: move DAI registration and debugfs init earlier
  soundwire: intel: simplify flow and use devm_ for DAI registration
  soundwire: intel: fix error handling on dai registration issues
  soundwire: cadence: Simplify error paths in cdns_xfer_msg()
  soundwire: cadence: Fix error check in cdns_xfer_msg()
  soundwire: cadence: Write to correct address for each FIFO chunk
  soundwire: bus: Fix wrong port number in sdw_handle_slave_alerts()
  soundwire: qcom: do not send status of device 0 during alert
  soundwire: qcom: update status from device id 1
  soundwire: cadence: Don't overwrite msg->buf during write commands
  soundwire: bus: Don't exit early if no device IDs were programmed
  soundwire: cadence: Fix lost ATTACHED interrupts when enumerating
  ...
parents 33e591de 503ae285
...@@ -11,11 +11,12 @@ ...@@ -11,11 +11,12 @@
#include "bus.h" #include "bus.h"
#include "sysfs_local.h" #include "sysfs_local.h"
static DEFINE_IDA(sdw_ida); static DEFINE_IDA(sdw_bus_ida);
static DEFINE_IDA(sdw_peripheral_ida);
static int sdw_get_id(struct sdw_bus *bus) static int sdw_get_id(struct sdw_bus *bus)
{ {
int rc = ida_alloc(&sdw_ida, GFP_KERNEL); int rc = ida_alloc(&sdw_bus_ida, GFP_KERNEL);
if (rc < 0) if (rc < 0)
return rc; return rc;
...@@ -75,7 +76,6 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, ...@@ -75,7 +76,6 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
/* /*
* Initialize multi_link flag * Initialize multi_link flag
* TODO: populate this flag by reading property from FW node
*/ */
bus->multi_link = false; bus->multi_link = false;
if (bus->ops->read_prop) { if (bus->ops->read_prop) {
...@@ -157,9 +157,11 @@ static int sdw_delete_slave(struct device *dev, void *data) ...@@ -157,9 +157,11 @@ static int sdw_delete_slave(struct device *dev, void *data)
mutex_lock(&bus->bus_lock); mutex_lock(&bus->bus_lock);
if (slave->dev_num) /* clear dev_num if assigned */ if (slave->dev_num) { /* clear dev_num if assigned */
clear_bit(slave->dev_num, bus->assigned); clear_bit(slave->dev_num, bus->assigned);
if (bus->dev_num_ida_min)
ida_free(&sdw_peripheral_ida, slave->dev_num);
}
list_del_init(&slave->node); list_del_init(&slave->node);
mutex_unlock(&bus->bus_lock); mutex_unlock(&bus->bus_lock);
...@@ -179,7 +181,7 @@ void sdw_bus_master_delete(struct sdw_bus *bus) ...@@ -179,7 +181,7 @@ void sdw_bus_master_delete(struct sdw_bus *bus)
sdw_master_device_del(bus); sdw_master_device_del(bus);
sdw_bus_debugfs_exit(bus); sdw_bus_debugfs_exit(bus);
ida_free(&sdw_ida, bus->id); ida_free(&sdw_bus_ida, bus->id);
} }
EXPORT_SYMBOL(sdw_bus_master_delete); EXPORT_SYMBOL(sdw_bus_master_delete);
...@@ -671,10 +673,18 @@ static int sdw_get_device_num(struct sdw_slave *slave) ...@@ -671,10 +673,18 @@ static int sdw_get_device_num(struct sdw_slave *slave)
{ {
int bit; int bit;
bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES); if (slave->bus->dev_num_ida_min) {
if (bit == SDW_MAX_DEVICES) { bit = ida_alloc_range(&sdw_peripheral_ida,
bit = -ENODEV; slave->bus->dev_num_ida_min, SDW_MAX_DEVICES,
goto err; GFP_KERNEL);
if (bit < 0)
goto err;
} else {
bit = find_first_zero_bit(slave->bus->assigned, SDW_MAX_DEVICES);
if (bit == SDW_MAX_DEVICES) {
bit = -ENODEV;
goto err;
}
} }
/* /*
...@@ -751,7 +761,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus, ...@@ -751,7 +761,7 @@ void sdw_extract_slave_id(struct sdw_bus *bus,
} }
EXPORT_SYMBOL(sdw_extract_slave_id); 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, bool *programmed)
{ {
u8 buf[SDW_NUM_DEV_ID_REGISTERS] = {0}; u8 buf[SDW_NUM_DEV_ID_REGISTERS] = {0};
struct sdw_slave *slave, *_s; struct sdw_slave *slave, *_s;
...@@ -761,6 +771,8 @@ static int sdw_program_device_num(struct sdw_bus *bus) ...@@ -761,6 +771,8 @@ static int sdw_program_device_num(struct sdw_bus *bus)
int count = 0, ret; int count = 0, ret;
u64 addr; u64 addr;
*programmed = false;
/* No Slave, so use raw xfer api */ /* No Slave, so use raw xfer api */
ret = sdw_fill_msg(&msg, NULL, SDW_SCP_DEVID_0, ret = sdw_fill_msg(&msg, NULL, SDW_SCP_DEVID_0,
SDW_NUM_DEV_ID_REGISTERS, 0, SDW_MSG_FLAG_READ, buf); SDW_NUM_DEV_ID_REGISTERS, 0, SDW_MSG_FLAG_READ, buf);
...@@ -795,6 +807,16 @@ static int sdw_program_device_num(struct sdw_bus *bus) ...@@ -795,6 +807,16 @@ static int sdw_program_device_num(struct sdw_bus *bus)
if (sdw_compare_devid(slave, id) == 0) { if (sdw_compare_devid(slave, id) == 0) {
found = true; found = true;
/*
* To prevent skipping state-machine stages don't
* program a device until we've seen it UNATTACH.
* Must return here because no other device on #0
* can be detected until this one has been
* assigned a device ID.
*/
if (slave->status != SDW_SLAVE_UNATTACHED)
return 0;
/* /*
* Assign a new dev_num to this Slave and * Assign a new dev_num to this Slave and
* not mark it present. It will be marked * not mark it present. It will be marked
...@@ -809,6 +831,8 @@ static int sdw_program_device_num(struct sdw_bus *bus) ...@@ -809,6 +831,8 @@ static int sdw_program_device_num(struct sdw_bus *bus)
return ret; return ret;
} }
*programmed = true;
break; break;
} }
} }
...@@ -848,13 +872,13 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, ...@@ -848,13 +872,13 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
mutex_lock(&bus->bus_lock); mutex_lock(&bus->bus_lock);
dev_vdbg(bus->dev, dev_vdbg(bus->dev,
"%s: changing status slave %d status %d new status %d\n", "changing status slave %d status %d new status %d\n",
__func__, slave->dev_num, slave->status, status); slave->dev_num, slave->status, status);
if (status == SDW_SLAVE_UNATTACHED) { if (status == SDW_SLAVE_UNATTACHED) {
dev_dbg(&slave->dev, dev_dbg(&slave->dev,
"%s: initializing enumeration and init completion for Slave %d\n", "initializing enumeration and init completion for Slave %d\n",
__func__, slave->dev_num); slave->dev_num);
init_completion(&slave->enumeration_complete); init_completion(&slave->enumeration_complete);
init_completion(&slave->initialization_complete); init_completion(&slave->initialization_complete);
...@@ -862,8 +886,8 @@ static void sdw_modify_slave_status(struct sdw_slave *slave, ...@@ -862,8 +886,8 @@ static void sdw_modify_slave_status(struct sdw_slave *slave,
} else if ((status == SDW_SLAVE_ATTACHED) && } else if ((status == SDW_SLAVE_ATTACHED) &&
(slave->status == SDW_SLAVE_UNATTACHED)) { (slave->status == SDW_SLAVE_UNATTACHED)) {
dev_dbg(&slave->dev, dev_dbg(&slave->dev,
"%s: signaling enumeration completion for Slave %d\n", "signaling enumeration completion for Slave %d\n",
__func__, slave->dev_num); slave->dev_num);
complete(&slave->enumeration_complete); complete(&slave->enumeration_complete);
} }
...@@ -1630,7 +1654,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1630,7 +1654,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
port = buf2[0] & SDW_SCP_INTSTAT2_PORT4_10; port = buf2[0] & SDW_SCP_INTSTAT2_PORT4_10;
for_each_set_bit(bit, &port, 8) { for_each_set_bit(bit, &port, 8) {
/* scp2 ports start from 4 */ /* scp2 ports start from 4 */
port_num = bit + 3; port_num = bit + 4;
sdw_handle_port_interrupt(slave, sdw_handle_port_interrupt(slave,
port_num, port_num,
&port_status[port_num]); &port_status[port_num]);
...@@ -1642,7 +1666,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) ...@@ -1642,7 +1666,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave)
port = buf2[1] & SDW_SCP_INTSTAT3_PORT11_14; port = buf2[1] & SDW_SCP_INTSTAT3_PORT11_14;
for_each_set_bit(bit, &port, 8) { for_each_set_bit(bit, &port, 8) {
/* scp3 ports start from 11 */ /* scp3 ports start from 11 */
port_num = bit + 10; port_num = bit + 11;
sdw_handle_port_interrupt(slave, sdw_handle_port_interrupt(slave,
port_num, port_num,
&port_status[port_num]); &port_status[port_num]);
...@@ -1768,7 +1792,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus, ...@@ -1768,7 +1792,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
{ {
enum sdw_slave_status prev_status; enum sdw_slave_status prev_status;
struct sdw_slave *slave; struct sdw_slave *slave;
bool attached_initializing; bool attached_initializing, id_programmed;
int i, ret = 0; int i, ret = 0;
/* first check if any Slaves fell off the bus */ /* first check if any Slaves fell off the bus */
...@@ -1789,19 +1813,33 @@ int sdw_handle_slave_status(struct sdw_bus *bus, ...@@ -1789,19 +1813,33 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n", dev_warn(&slave->dev, "Slave %d state check1: UNATTACHED, status was %d\n",
i, slave->status); i, slave->status);
sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED);
/* Ensure driver knows that peripheral unattached */
ret = sdw_update_slave_status(slave, status[i]);
if (ret < 0)
dev_warn(&slave->dev, "Update Slave status failed:%d\n", ret);
} }
} }
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);
if (ret < 0)
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,
* so we deal with other devices at a later time * so we deal with other devices at a later time.
* This relies on those devices reporting ATTACHED, which will
* trigger another call to this function. This will only
* happen if at least one device ID was programmed.
* Error returns from sdw_program_device_num() are currently
* ignored because there's no useful recovery that can be done.
* Returning the error here could result in the current status
* of other devices not being handled, because if no device IDs
* were programmed there's nothing to guarantee a status change
* to trigger another call to this function.
*/ */
return ret; sdw_program_device_num(bus, &id_programmed);
if (id_programmed)
return 0;
} }
/* Continue to check other slave statuses */ /* Continue to check other slave statuses */
...@@ -1870,8 +1908,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus, ...@@ -1870,8 +1908,8 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
"Update Slave status failed:%d\n", ret); "Update Slave status failed:%d\n", ret);
if (attached_initializing) { if (attached_initializing) {
dev_dbg(&slave->dev, dev_dbg(&slave->dev,
"%s: signaling initialization completion for Slave %d\n", "signaling initialization completion for Slave %d\n",
__func__, slave->dev_num); slave->dev_num);
complete(&slave->initialization_complete); complete(&slave->initialization_complete);
......
...@@ -544,9 +544,12 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns, ...@@ -544,9 +544,12 @@ cdns_fill_msg_resp(struct sdw_cdns *cdns,
return SDW_CMD_IGNORED; return SDW_CMD_IGNORED;
} }
/* fill response */ if (msg->flags == SDW_MSG_FLAG_READ) {
for (i = 0; i < count; i++) /* fill response */
msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA, cdns->response_buf[i]); for (i = 0; i < count; i++)
msg->buf[i + offset] = FIELD_GET(CDNS_MCP_RESP_RDATA,
cdns->response_buf[i]);
}
return SDW_CMD_OK; return SDW_CMD_OK;
} }
...@@ -566,7 +569,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd, ...@@ -566,7 +569,7 @@ _cdns_xfer_msg(struct sdw_cdns *cdns, struct sdw_msg *msg, int cmd,
} }
base = CDNS_MCP_CMD_BASE; base = CDNS_MCP_CMD_BASE;
addr = msg->addr; addr = msg->addr + offset;
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
data = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num); data = FIELD_PREP(CDNS_MCP_CMD_DEV_ADDR, msg->dev_num);
...@@ -705,18 +708,15 @@ cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg) ...@@ -705,18 +708,15 @@ cdns_xfer_msg(struct sdw_bus *bus, struct sdw_msg *msg)
for (i = 0; i < msg->len / CDNS_MCP_CMD_LEN; i++) { for (i = 0; i < msg->len / CDNS_MCP_CMD_LEN; i++) {
ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN, ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
CDNS_MCP_CMD_LEN, false); CDNS_MCP_CMD_LEN, false);
if (ret < 0) if (ret != SDW_CMD_OK)
goto exit; return ret;
} }
if (!(msg->len % CDNS_MCP_CMD_LEN)) if (!(msg->len % CDNS_MCP_CMD_LEN))
goto exit; return SDW_CMD_OK;
ret = _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
msg->len % CDNS_MCP_CMD_LEN, false);
exit: return _cdns_xfer_msg(cdns, msg, cmd, i * CDNS_MCP_CMD_LEN,
return ret; msg->len % CDNS_MCP_CMD_LEN, false);
} }
EXPORT_SYMBOL(cdns_xfer_msg); EXPORT_SYMBOL(cdns_xfer_msg);
...@@ -790,6 +790,7 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, ...@@ -790,6 +790,7 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
enum sdw_slave_status status[SDW_MAX_DEVICES + 1]; enum sdw_slave_status status[SDW_MAX_DEVICES + 1];
bool is_slave = false; bool is_slave = false;
u32 mask; u32 mask;
u32 val;
int i, set_status; int i, set_status;
memset(status, 0, sizeof(status)); memset(status, 0, sizeof(status));
...@@ -797,41 +798,38 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, ...@@ -797,41 +798,38 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
for (i = 0; i <= SDW_MAX_DEVICES; i++) { for (i = 0; i <= SDW_MAX_DEVICES; i++) {
mask = (slave_intstat >> (i * CDNS_MCP_SLAVE_STATUS_NUM)) & mask = (slave_intstat >> (i * CDNS_MCP_SLAVE_STATUS_NUM)) &
CDNS_MCP_SLAVE_STATUS_BITS; CDNS_MCP_SLAVE_STATUS_BITS;
if (!mask)
continue;
is_slave = true;
set_status = 0; set_status = 0;
if (mask & CDNS_MCP_SLAVE_INTSTAT_RESERVED) { if (mask) {
status[i] = SDW_SLAVE_RESERVED; is_slave = true;
set_status++;
}
if (mask & CDNS_MCP_SLAVE_INTSTAT_ATTACHED) {
status[i] = SDW_SLAVE_ATTACHED;
set_status++;
}
if (mask & CDNS_MCP_SLAVE_INTSTAT_ALERT) { if (mask & CDNS_MCP_SLAVE_INTSTAT_RESERVED) {
status[i] = SDW_SLAVE_ALERT; status[i] = SDW_SLAVE_RESERVED;
set_status++; set_status++;
} }
if (mask & CDNS_MCP_SLAVE_INTSTAT_NPRESENT) { if (mask & CDNS_MCP_SLAVE_INTSTAT_ATTACHED) {
status[i] = SDW_SLAVE_UNATTACHED; status[i] = SDW_SLAVE_ATTACHED;
set_status++; set_status++;
} }
/* first check if Slave reported multiple status */ if (mask & CDNS_MCP_SLAVE_INTSTAT_ALERT) {
if (set_status > 1) { status[i] = SDW_SLAVE_ALERT;
u32 val; set_status++;
}
dev_warn_ratelimited(cdns->dev, if (mask & CDNS_MCP_SLAVE_INTSTAT_NPRESENT) {
"Slave %d reported multiple Status: %d\n", status[i] = SDW_SLAVE_UNATTACHED;
i, mask); set_status++;
}
}
/* check latest status extracted from PING commands */ /*
* check that there was a single reported Slave status and when
* there is not use the latest status extracted from PING commands
*/
if (set_status != 1) {
val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT); val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
val >>= (i * 2); val >>= (i * 2);
...@@ -850,11 +848,6 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns, ...@@ -850,11 +848,6 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
status[i] = SDW_SLAVE_RESERVED; status[i] = SDW_SLAVE_RESERVED;
break; break;
} }
dev_warn_ratelimited(cdns->dev,
"Slave %d status updated to %d\n",
i, status[i]);
} }
} }
...@@ -969,9 +962,22 @@ static void cdns_update_slave_status_work(struct work_struct *work) ...@@ -969,9 +962,22 @@ static void cdns_update_slave_status_work(struct work_struct *work)
u32 device0_status; u32 device0_status;
int retry_count = 0; int retry_count = 0;
/*
* Clear main interrupt first so we don't lose any assertions
* that happen during this function.
*/
cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK);
slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0); slave0 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT0);
slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1); slave1 = cdns_readl(cdns, CDNS_MCP_SLAVE_INTSTAT1);
/*
* Clear the bits before handling so we don't lose any
* bits that re-assert.
*/
cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0);
cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1);
/* combine the two status */ /* combine the two status */
slave_intstat = ((u64)slave1 << 32) | slave0; slave_intstat = ((u64)slave1 << 32) | slave0;
...@@ -979,8 +985,6 @@ static void cdns_update_slave_status_work(struct work_struct *work) ...@@ -979,8 +985,6 @@ static void cdns_update_slave_status_work(struct work_struct *work)
update_status: update_status:
cdns_update_slave_status(cdns, slave_intstat); cdns_update_slave_status(cdns, slave_intstat);
cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT0, slave0);
cdns_writel(cdns, CDNS_MCP_SLAVE_INTSTAT1, slave1);
/* /*
* When there is more than one peripheral per link, it's * When there is more than one peripheral per link, it's
...@@ -997,6 +1001,11 @@ static void cdns_update_slave_status_work(struct work_struct *work) ...@@ -997,6 +1001,11 @@ static void cdns_update_slave_status_work(struct work_struct *work)
* attention with PING commands. There is no need to check for * attention with PING commands. There is no need to check for
* ALERTS since they are not allowed until a non-zero * ALERTS since they are not allowed until a non-zero
* device_number is assigned. * device_number is assigned.
*
* Do not clear the INTSTAT0/1. While looping to enumerate devices on
* #0 there could be status changes on other devices - these must
* be kept in the INTSTAT so they can be handled when all #0 devices
* have been handled.
*/ */
device0_status = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT); device0_status = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
...@@ -1016,8 +1025,7 @@ static void cdns_update_slave_status_work(struct work_struct *work) ...@@ -1016,8 +1025,7 @@ static void cdns_update_slave_status_work(struct work_struct *work)
} }
} }
/* clear and unmask Slave interrupt now */ /* unmask Slave interrupt now */
cdns_writel(cdns, CDNS_MCP_INTSTAT, CDNS_MCP_INT_SLAVE_MASK);
cdns_updatel(cdns, CDNS_MCP_INTMASK, cdns_updatel(cdns, CDNS_MCP_INTMASK,
CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK); CDNS_MCP_INT_SLAVE_MASK, CDNS_MCP_INT_SLAVE_MASK);
......
...@@ -55,7 +55,26 @@ static const struct adr_remap dell_sku_0A3E[] = { ...@@ -55,7 +55,26 @@ static const struct adr_remap dell_sku_0A3E[] = {
{} {}
}; };
/*
* The HP Omen 16-k0005TX does not expose the correct version of RT711 on link0
* and does not expose a RT1316 on link3
*/
static const struct adr_remap hp_omen_16[] = {
/* rt711-sdca on link0 */
{
0x000020025d071100ull,
0x000030025d071101ull
},
/* rt1316-sdca on link3 */
{
0x000120025d071100ull,
0x000330025d131601ull
},
{}
};
static const struct dmi_system_id adr_remap_quirk_table[] = { static const struct dmi_system_id adr_remap_quirk_table[] = {
/* TGL devices */
{ {
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"), DMI_MATCH(DMI_SYS_VENDOR, "HP"),
...@@ -78,6 +97,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = { ...@@ -78,6 +97,14 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
}, },
.driver_data = (void *)dell_sku_0A3E, .driver_data = (void *)dell_sku_0A3E,
}, },
/* ADL devices */
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-k0xxx"),
},
.driver_data = (void *)hp_omen_16,
},
{} {}
}; };
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
#include "bus.h" #include "bus.h"
#include "intel.h" #include "intel.h"
/* IDA min selected to avoid conflicts with HDaudio/iDISP SDI values */
#define INTEL_DEV_NUM_IDA_MIN 4
#define INTEL_MASTER_SUSPEND_DELAY_MS 3000 #define INTEL_MASTER_SUSPEND_DELAY_MS 3000
#define INTEL_MASTER_RESET_ITERATIONS 10 #define INTEL_MASTER_RESET_ITERATIONS 10
...@@ -135,7 +138,7 @@ static int intel_reg_show(struct seq_file *s_file, void *data) ...@@ -135,7 +138,7 @@ static int intel_reg_show(struct seq_file *s_file, void *data)
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0); links = intel_readl(s, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_LCOUNT_MASK;
ret = scnprintf(buf, RD_BUF, "Register Value\n"); ret = scnprintf(buf, RD_BUF, "Register Value\n");
ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n"); ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");
...@@ -167,9 +170,8 @@ static int intel_reg_show(struct seq_file *s_file, void *data) ...@@ -167,9 +170,8 @@ static int intel_reg_show(struct seq_file *s_file, void *data)
ret += intel_sprintf(s, false, buf, ret, ret += intel_sprintf(s, false, buf, ret,
SDW_SHIM_PCMSYCHC(i, j)); SDW_SHIM_PCMSYCHC(i, j));
} }
ret += scnprintf(buf + ret, RD_BUF - ret, "\n PDMSCAP, IOCTL, CTMCTL\n"); ret += scnprintf(buf + ret, RD_BUF - ret, "\n IOCTL, CTMCTL\n");
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i));
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i)); ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i)); ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
} }
...@@ -258,86 +260,6 @@ static void intel_debugfs_exit(struct sdw_intel *sdw) {} ...@@ -258,86 +260,6 @@ static void intel_debugfs_exit(struct sdw_intel *sdw) {}
/* /*
* shim ops * shim ops
*/ */
static int intel_link_power_up(struct sdw_intel *sdw)
{
unsigned int link_id = sdw->instance;
void __iomem *shim = sdw->link_res->shim;
u32 *shim_mask = sdw->link_res->shim_mask;
struct sdw_bus *bus = &sdw->cdns.bus;
struct sdw_master_prop *prop = &bus->prop;
u32 spa_mask, cpa_mask;
u32 link_control;
int ret = 0;
u32 syncprd;
u32 sync_reg;
mutex_lock(sdw->link_res->shim_lock);
/*
* The hardware relies on an internal counter, typically 4kHz,
* to generate the SoundWire SSP - which defines a 'safe'
* synchronization point between commands and audio transport
* and allows for multi link synchronization. The SYNCPRD value
* is only dependent on the oscillator clock provided to
* the IP, so adjust based on _DSD properties reported in DSDT
* tables. The values reported are based on either 24MHz
* (CNL/CML) or 38.4 MHz (ICL/TGL+).
*/
if (prop->mclk_freq % 6000000)
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
else
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
if (!*shim_mask) {
dev_dbg(sdw->cdns.dev, "%s: powering up all links\n", __func__);
/* we first need to program the SyncPRD/CPU registers */
dev_dbg(sdw->cdns.dev,
"%s: first link up, programming SYNCPRD\n", __func__);
/* set SyncPRD period */
sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
u32p_replace_bits(&sync_reg, syncprd, SDW_SHIM_SYNC_SYNCPRD);
/* Set SyncCPU bit */
sync_reg |= SDW_SHIM_SYNC_SYNCCPU;
intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
/* Link power up sequence */
link_control = intel_readl(shim, SDW_SHIM_LCTL);
/* only power-up enabled links */
spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, sdw->link_res->link_mask);
cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);
link_control |= spa_mask;
ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
if (ret < 0) {
dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret);
goto out;
}
/* SyncCPU will change once link is active */
ret = intel_wait_bit(shim, SDW_SHIM_SYNC,
SDW_SHIM_SYNC_SYNCCPU, 0);
if (ret < 0) {
dev_err(sdw->cdns.dev,
"Failed to set SHIM_SYNC: %d\n", ret);
goto out;
}
}
*shim_mask |= BIT(link_id);
sdw->cdns.link_up = true;
out:
mutex_unlock(sdw->link_res->shim_lock);
return ret;
}
/* this needs to be called with shim_lock */ /* this needs to be called with shim_lock */
static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw) static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw)
{ {
...@@ -389,15 +311,13 @@ static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw) ...@@ -389,15 +311,13 @@ static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw)
/* at this point Integration Glue has full control of the I/Os */ /* at this point Integration Glue has full control of the I/Os */
} }
static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop) /* this needs to be called with shim_lock */
static void intel_shim_init(struct sdw_intel *sdw)
{ {
void __iomem *shim = sdw->link_res->shim; void __iomem *shim = sdw->link_res->shim;
unsigned int link_id = sdw->instance; unsigned int link_id = sdw->instance;
int ret = 0;
u16 ioctl = 0, act = 0; u16 ioctl = 0, act = 0;
mutex_lock(sdw->link_res->shim_lock);
/* Initialize Shim */ /* Initialize Shim */
ioctl |= SDW_SHIM_IOCTL_BKE; ioctl |= SDW_SHIM_IOCTL_BKE;
intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl); intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
...@@ -422,10 +342,17 @@ static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop) ...@@ -422,10 +342,17 @@ static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop)
act |= SDW_SHIM_CTMCTL_DODS; act |= SDW_SHIM_CTMCTL_DODS;
intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act); intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act);
usleep_range(10, 15); usleep_range(10, 15);
}
mutex_unlock(sdw->link_res->shim_lock); static int intel_shim_check_wake(struct sdw_intel *sdw)
{
void __iomem *shim;
u16 wake_sts;
return ret; shim = sdw->link_res->shim;
wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
return wake_sts & BIT(sdw->instance);
} }
static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
...@@ -454,6 +381,88 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) ...@@ -454,6 +381,88 @@ static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
mutex_unlock(sdw->link_res->shim_lock); mutex_unlock(sdw->link_res->shim_lock);
} }
static int intel_link_power_up(struct sdw_intel *sdw)
{
unsigned int link_id = sdw->instance;
void __iomem *shim = sdw->link_res->shim;
u32 *shim_mask = sdw->link_res->shim_mask;
struct sdw_bus *bus = &sdw->cdns.bus;
struct sdw_master_prop *prop = &bus->prop;
u32 spa_mask, cpa_mask;
u32 link_control;
int ret = 0;
u32 syncprd;
u32 sync_reg;
mutex_lock(sdw->link_res->shim_lock);
/*
* The hardware relies on an internal counter, typically 4kHz,
* to generate the SoundWire SSP - which defines a 'safe'
* synchronization point between commands and audio transport
* and allows for multi link synchronization. The SYNCPRD value
* is only dependent on the oscillator clock provided to
* the IP, so adjust based on _DSD properties reported in DSDT
* tables. The values reported are based on either 24MHz
* (CNL/CML) or 38.4 MHz (ICL/TGL+).
*/
if (prop->mclk_freq % 6000000)
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
else
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
if (!*shim_mask) {
dev_dbg(sdw->cdns.dev, "powering up all links\n");
/* we first need to program the SyncPRD/CPU registers */
dev_dbg(sdw->cdns.dev,
"first link up, programming SYNCPRD\n");
/* set SyncPRD period */
sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
u32p_replace_bits(&sync_reg, syncprd, SDW_SHIM_SYNC_SYNCPRD);
/* Set SyncCPU bit */
sync_reg |= SDW_SHIM_SYNC_SYNCCPU;
intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
/* Link power up sequence */
link_control = intel_readl(shim, SDW_SHIM_LCTL);
/* only power-up enabled links */
spa_mask = FIELD_PREP(SDW_SHIM_LCTL_SPA_MASK, sdw->link_res->link_mask);
cpa_mask = FIELD_PREP(SDW_SHIM_LCTL_CPA_MASK, sdw->link_res->link_mask);
link_control |= spa_mask;
ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
if (ret < 0) {
dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret);
goto out;
}
/* SyncCPU will change once link is active */
ret = intel_wait_bit(shim, SDW_SHIM_SYNC,
SDW_SHIM_SYNC_SYNCCPU, 0);
if (ret < 0) {
dev_err(sdw->cdns.dev,
"Failed to set SHIM_SYNC: %d\n", ret);
goto out;
}
}
*shim_mask |= BIT(link_id);
sdw->cdns.link_up = true;
intel_shim_init(sdw);
out:
mutex_unlock(sdw->link_res->shim_lock);
return ret;
}
static int intel_link_power_down(struct sdw_intel *sdw) static int intel_link_power_down(struct sdw_intel *sdw)
{ {
u32 link_control, spa_mask, cpa_mask; u32 link_control, spa_mask, cpa_mask;
...@@ -476,7 +485,7 @@ static int intel_link_power_down(struct sdw_intel *sdw) ...@@ -476,7 +485,7 @@ static int intel_link_power_down(struct sdw_intel *sdw)
if (!*shim_mask) { if (!*shim_mask) {
dev_dbg(sdw->cdns.dev, "%s: powering down all links\n", __func__); dev_dbg(sdw->cdns.dev, "powering down all links\n");
/* Link power down sequence */ /* Link power down sequence */
link_control = intel_readl(shim, SDW_SHIM_LCTL); link_control = intel_readl(shim, SDW_SHIM_LCTL);
...@@ -1169,11 +1178,20 @@ static int intel_create_dai(struct sdw_cdns *cdns, ...@@ -1169,11 +1178,20 @@ static int intel_create_dai(struct sdw_cdns *cdns,
static int intel_register_dai(struct sdw_intel *sdw) static int intel_register_dai(struct sdw_intel *sdw)
{ {
struct sdw_cdns_stream_config config;
struct sdw_cdns *cdns = &sdw->cdns; struct sdw_cdns *cdns = &sdw->cdns;
struct sdw_cdns_streams *stream; struct sdw_cdns_streams *stream;
struct snd_soc_dai_driver *dais; struct snd_soc_dai_driver *dais;
int num_dai, ret, off = 0; int num_dai, ret, off = 0;
/* Read the PDI config and initialize cadence PDI */
intel_pdi_init(sdw, &config);
ret = sdw_cdns_pdi_init(cdns, config);
if (ret)
return ret;
intel_pdi_ch_update(sdw);
/* DAIs are created based on total number of PDIs supported */ /* DAIs are created based on total number of PDIs supported */
num_dai = cdns->pcm.num_pdi; num_dai = cdns->pcm.num_pdi;
...@@ -1201,8 +1219,208 @@ static int intel_register_dai(struct sdw_intel *sdw) ...@@ -1201,8 +1219,208 @@ static int intel_register_dai(struct sdw_intel *sdw)
if (ret) if (ret)
return ret; return ret;
return snd_soc_register_component(cdns->dev, &dai_component, return devm_snd_soc_register_component(cdns->dev, &dai_component,
dais, num_dai); dais, num_dai);
}
static int intel_start_bus(struct sdw_intel *sdw)
{
struct device *dev = sdw->cdns.dev;
struct sdw_cdns *cdns = &sdw->cdns;
struct sdw_bus *bus = &cdns->bus;
int ret;
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
return ret;
}
/*
* follow recommended programming flows to avoid timeouts when
* gsync is enabled
*/
if (bus->multi_link)
intel_shim_sync_arm(sdw);
ret = sdw_cdns_init(cdns);
if (ret < 0) {
dev_err(dev, "%s: unable to initialize Cadence IP: %d\n", __func__, ret);
goto err_interrupt;
}
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "%s: unable to exit bus reset sequence: %d\n", __func__, ret);
goto err_interrupt;
}
if (bus->multi_link) {
ret = intel_shim_sync_go(sdw);
if (ret < 0) {
dev_err(dev, "%s: sync go failed: %d\n", __func__, ret);
goto err_interrupt;
}
}
sdw_cdns_check_self_clearing_bits(cdns, __func__,
true, INTEL_MASTER_RESET_ITERATIONS);
return 0;
err_interrupt:
sdw_cdns_enable_interrupt(cdns, false);
return ret;
}
static int intel_start_bus_after_reset(struct sdw_intel *sdw)
{
struct device *dev = sdw->cdns.dev;
struct sdw_cdns *cdns = &sdw->cdns;
struct sdw_bus *bus = &cdns->bus;
bool clock_stop0;
int status;
int ret;
/*
* An exception condition occurs for the CLK_STOP_BUS_RESET
* case if one or more masters remain active. In this condition,
* all the masters are powered on for they are in the same power
* domain. Master can preserve its context for clock stop0, so
* there is no need to clear slave status and reset bus.
*/
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
if (!clock_stop0) {
/*
* make sure all Slaves are tagged as UNATTACHED and
* provide reason for reinitialization
*/
status = SDW_UNATTACH_REQUEST_MASTER_RESET;
sdw_clear_slave_status(bus, status);
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
/*
* follow recommended programming flows to avoid
* timeouts when gsync is enabled
*/
if (bus->multi_link)
intel_shim_sync_arm(sdw);
/*
* Re-initialize the IP since it was powered-off
*/
sdw_cdns_init(&sdw->cdns);
} else {
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
}
ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
if (ret < 0) {
dev_err(dev, "unable to restart clock during resume\n");
goto err_interrupt;
}
if (!clock_stop0) {
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n");
goto err_interrupt;
}
if (bus->multi_link) {
ret = intel_shim_sync_go(sdw);
if (ret < 0) {
dev_err(sdw->cdns.dev, "sync go failed during resume\n");
goto err_interrupt;
}
}
}
sdw_cdns_check_self_clearing_bits(cdns, __func__, true, INTEL_MASTER_RESET_ITERATIONS);
return 0;
err_interrupt:
sdw_cdns_enable_interrupt(cdns, false);
return ret;
}
static void intel_check_clock_stop(struct sdw_intel *sdw)
{
struct device *dev = sdw->cdns.dev;
bool clock_stop0;
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
if (!clock_stop0)
dev_err(dev, "%s: invalid configuration, clock was not stopped\n", __func__);
}
static int intel_start_bus_after_clock_stop(struct sdw_intel *sdw)
{
struct device *dev = sdw->cdns.dev;
struct sdw_cdns *cdns = &sdw->cdns;
int ret;
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "%s: cannot enable interrupts: %d\n", __func__, ret);
return ret;
}
ret = sdw_cdns_clock_restart(cdns, false);
if (ret < 0) {
dev_err(dev, "%s: unable to restart clock: %d\n", __func__, ret);
sdw_cdns_enable_interrupt(cdns, false);
return ret;
}
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks",
true, INTEL_MASTER_RESET_ITERATIONS);
return 0;
}
static int intel_stop_bus(struct sdw_intel *sdw, bool clock_stop)
{
struct device *dev = sdw->cdns.dev;
struct sdw_cdns *cdns = &sdw->cdns;
bool wake_enable = false;
int ret;
if (clock_stop) {
ret = sdw_cdns_clock_stop(cdns, true);
if (ret < 0)
dev_err(dev, "%s: cannot stop clock: %d\n", __func__, ret);
else
wake_enable = true;
}
ret = sdw_cdns_enable_interrupt(cdns, false);
if (ret < 0) {
dev_err(dev, "%s: cannot disable interrupts: %d\n", __func__, ret);
return ret;
}
ret = intel_link_power_down(sdw);
if (ret) {
dev_err(dev, "%s: Link power down failed: %d\n", __func__, ret);
return ret;
}
intel_shim_wake(sdw, wake_enable);
return 0;
} }
static int sdw_master_read_intel_prop(struct sdw_bus *bus) static int sdw_master_read_intel_prop(struct sdw_bus *bus)
...@@ -1254,7 +1472,7 @@ static int intel_prop_read(struct sdw_bus *bus) ...@@ -1254,7 +1472,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 = intel_prop_read,
.override_adr = sdw_dmi_override_adr, .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,
...@@ -1265,20 +1483,6 @@ static struct sdw_master_ops sdw_intel_ops = { ...@@ -1265,20 +1483,6 @@ static struct sdw_master_ops sdw_intel_ops = {
.read_ping_status = cdns_read_ping_status, .read_ping_status = cdns_read_ping_status,
}; };
static int intel_init(struct sdw_intel *sdw)
{
bool clock_stop;
/* Initialize shim and controller */
intel_link_power_up(sdw);
clock_stop = sdw_cdns_is_clock_stop(&sdw->cdns);
intel_shim_init(sdw, clock_stop);
return 0;
}
/* /*
* probe and init (aux_dev_id argument is required by function prototype but not used) * probe and init (aux_dev_id argument is required by function prototype but not used)
*/ */
...@@ -1308,11 +1512,11 @@ static int intel_link_probe(struct auxiliary_device *auxdev, ...@@ -1308,11 +1512,11 @@ static int intel_link_probe(struct auxiliary_device *auxdev,
cdns->msg_count = 0; cdns->msg_count = 0;
bus->link_id = auxdev->id; bus->link_id = auxdev->id;
bus->dev_num_ida_min = INTEL_DEV_NUM_IDA_MIN;
sdw_cdns_probe(cdns); sdw_cdns_probe(cdns);
/* Set property read ops */ /* Set ops */
sdw_intel_ops.read_prop = intel_prop_read;
bus->ops = &sdw_intel_ops; bus->ops = &sdw_intel_ops;
/* set driver data, accessed by snd_soc_dai_get_drvdata() */ /* set driver data, accessed by snd_soc_dai_get_drvdata() */
...@@ -1345,7 +1549,6 @@ static int intel_link_probe(struct auxiliary_device *auxdev, ...@@ -1345,7 +1549,6 @@ static int intel_link_probe(struct auxiliary_device *auxdev,
int intel_link_startup(struct auxiliary_device *auxdev) int intel_link_startup(struct auxiliary_device *auxdev)
{ {
struct sdw_cdns_stream_config config;
struct device *dev = &auxdev->dev; struct device *dev = &auxdev->dev;
struct sdw_cdns *cdns = auxiliary_get_drvdata(auxdev); struct sdw_cdns *cdns = auxiliary_get_drvdata(auxdev);
struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_intel *sdw = cdns_to_intel(cdns);
...@@ -1366,7 +1569,6 @@ int intel_link_startup(struct auxiliary_device *auxdev) ...@@ -1366,7 +1569,6 @@ int intel_link_startup(struct auxiliary_device *auxdev)
multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK); multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
if (!multi_link) { if (!multi_link) {
dev_dbg(dev, "Multi-link is disabled\n"); dev_dbg(dev, "Multi-link is disabled\n");
bus->multi_link = false;
} else { } else {
/* /*
* hardware-based synchronization is required regardless * hardware-based synchronization is required regardless
...@@ -1374,68 +1576,31 @@ int intel_link_startup(struct auxiliary_device *auxdev) ...@@ -1374,68 +1576,31 @@ int intel_link_startup(struct auxiliary_device *auxdev)
* synchronization is gated by gsync when the multi-master * synchronization is gated by gsync when the multi-master
* mode is set. * mode is set.
*/ */
bus->multi_link = true;
bus->hw_sync_min_links = 1; bus->hw_sync_min_links = 1;
} }
bus->multi_link = multi_link;
/* Initialize shim, controller */ /* Initialize shim, controller */
ret = intel_init(sdw); ret = intel_link_power_up(sdw);
if (ret)
goto err_init;
/* Read the PDI config and initialize cadence PDI */
intel_pdi_init(sdw, &config);
ret = sdw_cdns_pdi_init(cdns, config);
if (ret) if (ret)
goto err_init; goto err_init;
intel_pdi_ch_update(sdw);
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts\n");
goto err_init;
}
/*
* follow recommended programming flows to avoid timeouts when
* gsync is enabled
*/
if (multi_link)
intel_shim_sync_arm(sdw);
ret = sdw_cdns_init(cdns);
if (ret < 0) {
dev_err(dev, "unable to initialize Cadence IP\n");
goto err_interrupt;
}
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence\n");
goto err_interrupt;
}
if (multi_link) {
ret = intel_shim_sync_go(sdw);
if (ret < 0) {
dev_err(dev, "sync go failed: %d\n", ret);
goto err_interrupt;
}
}
sdw_cdns_check_self_clearing_bits(cdns, __func__,
true, INTEL_MASTER_RESET_ITERATIONS);
/* Register DAIs */ /* Register DAIs */
ret = intel_register_dai(sdw); ret = intel_register_dai(sdw);
if (ret) { if (ret) {
dev_err(dev, "DAI registration failed: %d\n", ret); dev_err(dev, "DAI registration failed: %d\n", ret);
snd_soc_unregister_component(dev); goto err_power_up;
goto err_interrupt;
} }
intel_debugfs_init(sdw); intel_debugfs_init(sdw);
/* start bus */
ret = intel_start_bus(sdw);
if (ret) {
dev_err(dev, "bus start failed: %d\n", ret);
goto err_power_up;
}
/* Enable runtime PM */ /* Enable runtime PM */
if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) { if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) {
pm_runtime_set_autosuspend_delay(dev, pm_runtime_set_autosuspend_delay(dev,
...@@ -1480,15 +1645,14 @@ int intel_link_startup(struct auxiliary_device *auxdev) ...@@ -1480,15 +1645,14 @@ int intel_link_startup(struct auxiliary_device *auxdev)
sdw->startup_done = true; sdw->startup_done = true;
return 0; return 0;
err_interrupt: err_power_up:
sdw_cdns_enable_interrupt(cdns, false); intel_link_power_down(sdw);
err_init: err_init:
return ret; return ret;
} }
static void intel_link_remove(struct auxiliary_device *auxdev) static void intel_link_remove(struct auxiliary_device *auxdev)
{ {
struct device *dev = &auxdev->dev;
struct sdw_cdns *cdns = auxiliary_get_drvdata(auxdev); struct sdw_cdns *cdns = auxiliary_get_drvdata(auxdev);
struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_bus *bus = &cdns->bus; struct sdw_bus *bus = &cdns->bus;
...@@ -1501,7 +1665,6 @@ static void intel_link_remove(struct auxiliary_device *auxdev) ...@@ -1501,7 +1665,6 @@ static void intel_link_remove(struct auxiliary_device *auxdev)
if (!bus->prop.hw_disabled) { if (!bus->prop.hw_disabled) {
intel_debugfs_exit(sdw); intel_debugfs_exit(sdw);
sdw_cdns_enable_interrupt(cdns, false); sdw_cdns_enable_interrupt(cdns, false);
snd_soc_unregister_component(dev);
} }
sdw_bus_master_delete(bus); sdw_bus_master_delete(bus);
} }
...@@ -1511,8 +1674,6 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) ...@@ -1511,8 +1674,6 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev)
struct device *dev = &auxdev->dev; struct device *dev = &auxdev->dev;
struct sdw_intel *sdw; struct sdw_intel *sdw;
struct sdw_bus *bus; struct sdw_bus *bus;
void __iomem *shim;
u16 wake_sts;
sdw = auxiliary_get_drvdata(auxdev); sdw = auxiliary_get_drvdata(auxdev);
bus = &sdw->cdns.bus; bus = &sdw->cdns.bus;
...@@ -1523,10 +1684,7 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) ...@@ -1523,10 +1684,7 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev)
return 0; return 0;
} }
shim = sdw->link_res->shim; if (!intel_shim_check_wake(sdw))
wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
if (!(wake_sts & BIT(sdw->instance)))
return 0; return 0;
/* disable WAKEEN interrupt ASAP to prevent interrupt flood */ /* disable WAKEEN interrupt ASAP to prevent interrupt flood */
...@@ -1554,11 +1712,11 @@ static int intel_resume_child_device(struct device *dev, void *data) ...@@ -1554,11 +1712,11 @@ static int intel_resume_child_device(struct device *dev, void *data)
struct sdw_slave *slave = dev_to_sdw_dev(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev);
if (!slave->probed) { if (!slave->probed) {
dev_dbg(dev, "%s: skipping device, no probed driver\n", __func__); dev_dbg(dev, "skipping device, no probed driver\n");
return 0; return 0;
} }
if (!slave->dev_num_sticky) { if (!slave->dev_num_sticky) {
dev_dbg(dev, "%s: skipping device, never detected on bus\n", __func__); dev_dbg(dev, "skipping device, never detected on bus\n");
return 0; return 0;
} }
...@@ -1644,7 +1802,7 @@ static int __maybe_unused intel_suspend(struct device *dev) ...@@ -1644,7 +1802,7 @@ static int __maybe_unused intel_suspend(struct device *dev)
} }
if (pm_runtime_suspended(dev)) { if (pm_runtime_suspended(dev)) {
dev_dbg(dev, "%s: pm_runtime status: suspended\n", __func__); dev_dbg(dev, "pm_runtime status: suspended\n");
clock_stop_quirks = sdw->link_res->clock_stop_quirks; clock_stop_quirks = sdw->link_res->clock_stop_quirks;
...@@ -1665,20 +1823,12 @@ static int __maybe_unused intel_suspend(struct device *dev) ...@@ -1665,20 +1823,12 @@ static int __maybe_unused intel_suspend(struct device *dev)
return 0; return 0;
} }
ret = sdw_cdns_enable_interrupt(cdns, false); ret = intel_stop_bus(sdw, false);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "cannot disable interrupts on suspend\n"); dev_err(dev, "%s: cannot stop bus: %d\n", __func__, ret);
return ret;
}
ret = intel_link_power_down(sdw);
if (ret) {
dev_err(dev, "Link power down failed: %d\n", ret);
return ret; return ret;
} }
intel_shim_wake(sdw, false);
return 0; return 0;
} }
...@@ -1699,44 +1849,19 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) ...@@ -1699,44 +1849,19 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev)
clock_stop_quirks = sdw->link_res->clock_stop_quirks; clock_stop_quirks = sdw->link_res->clock_stop_quirks;
if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) {
ret = intel_stop_bus(sdw, false);
ret = sdw_cdns_enable_interrupt(cdns, false);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "cannot disable interrupts on suspend\n"); dev_err(dev, "%s: cannot stop bus during teardown: %d\n",
return ret; __func__, ret);
}
ret = intel_link_power_down(sdw);
if (ret) {
dev_err(dev, "Link power down failed: %d\n", ret);
return ret; return ret;
} }
} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET || !clock_stop_quirks) {
intel_shim_wake(sdw, false); ret = intel_stop_bus(sdw, true);
} else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET ||
!clock_stop_quirks) {
bool wake_enable = true;
ret = sdw_cdns_clock_stop(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable clock stop on suspend\n");
wake_enable = false;
}
ret = sdw_cdns_enable_interrupt(cdns, false);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "cannot disable interrupts on suspend\n"); dev_err(dev, "%s: cannot stop bus during clock_stop: %d\n",
return ret; __func__, ret);
}
ret = intel_link_power_down(sdw);
if (ret) {
dev_err(dev, "Link power down failed: %d\n", ret);
return ret; return ret;
} }
intel_shim_wake(sdw, wake_enable);
} else { } else {
dev_err(dev, "%s clock_stop_quirks %x unsupported\n", dev_err(dev, "%s clock_stop_quirks %x unsupported\n",
__func__, clock_stop_quirks); __func__, clock_stop_quirks);
...@@ -1752,7 +1877,6 @@ static int __maybe_unused intel_resume(struct device *dev) ...@@ -1752,7 +1877,6 @@ static int __maybe_unused intel_resume(struct device *dev)
struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_bus *bus = &cdns->bus; struct sdw_bus *bus = &cdns->bus;
int link_flags; int link_flags;
bool multi_link;
int ret; int ret;
if (bus->prop.hw_disabled || !sdw->startup_done) { if (bus->prop.hw_disabled || !sdw->startup_done) {
...@@ -1762,10 +1886,9 @@ static int __maybe_unused intel_resume(struct device *dev) ...@@ -1762,10 +1886,9 @@ static int __maybe_unused intel_resume(struct device *dev)
} }
link_flags = md_flags >> (bus->link_id * 8); link_flags = md_flags >> (bus->link_id * 8);
multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
if (pm_runtime_suspended(dev)) { if (pm_runtime_suspended(dev)) {
dev_dbg(dev, "%s: pm_runtime status was suspended, forcing active\n", __func__); dev_dbg(dev, "pm_runtime status was suspended, forcing active\n");
/* follow required sequence from runtime_pm.rst */ /* follow required sequence from runtime_pm.rst */
pm_runtime_disable(dev); pm_runtime_disable(dev);
...@@ -1779,7 +1902,7 @@ static int __maybe_unused intel_resume(struct device *dev) ...@@ -1779,7 +1902,7 @@ static int __maybe_unused intel_resume(struct device *dev)
pm_runtime_idle(dev); pm_runtime_idle(dev);
} }
ret = intel_init(sdw); ret = intel_link_power_up(sdw);
if (ret) { if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret); dev_err(dev, "%s failed: %d\n", __func__, ret);
return ret; return ret;
...@@ -1791,41 +1914,13 @@ static int __maybe_unused intel_resume(struct device *dev) ...@@ -1791,41 +1914,13 @@ static int __maybe_unused intel_resume(struct device *dev)
*/ */
sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET); sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
ret = sdw_cdns_enable_interrupt(cdns, true); ret = intel_start_bus(sdw);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
/*
* follow recommended programming flows to avoid timeouts when
* gsync is enabled
*/
if (multi_link)
intel_shim_sync_arm(sdw);
ret = sdw_cdns_init(&sdw->cdns);
if (ret < 0) {
dev_err(dev, "unable to initialize Cadence IP during resume\n");
return ret;
}
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n"); dev_err(dev, "cannot start bus during resume\n");
intel_link_power_down(sdw);
return ret; return ret;
} }
if (multi_link) {
ret = intel_shim_sync_go(sdw);
if (ret < 0) {
dev_err(dev, "sync go failed during resume\n");
return ret;
}
}
sdw_cdns_check_self_clearing_bits(cdns, __func__,
true, INTEL_MASTER_RESET_ITERATIONS);
/* /*
* after system resume, the pm_runtime suspend() may kick in * after system resume, the pm_runtime suspend() may kick in
* during the enumeration, before any children device force the * during the enumeration, before any children device force the
...@@ -1838,7 +1933,7 @@ static int __maybe_unused intel_resume(struct device *dev) ...@@ -1838,7 +1933,7 @@ static int __maybe_unused intel_resume(struct device *dev)
*/ */
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
return ret; return 0;
} }
static int __maybe_unused intel_resume_runtime(struct device *dev) static int __maybe_unused intel_resume_runtime(struct device *dev)
...@@ -1847,10 +1942,6 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ...@@ -1847,10 +1942,6 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
struct sdw_intel *sdw = cdns_to_intel(cdns); struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_bus *bus = &cdns->bus; struct sdw_bus *bus = &cdns->bus;
u32 clock_stop_quirks; u32 clock_stop_quirks;
bool clock_stop0;
int link_flags;
bool multi_link;
int status;
int ret; int ret;
if (bus->prop.hw_disabled || !sdw->startup_done) { if (bus->prop.hw_disabled || !sdw->startup_done) {
...@@ -1862,15 +1953,12 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ...@@ -1862,15 +1953,12 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
/* unconditionally disable WAKEEN interrupt */ /* unconditionally disable WAKEEN interrupt */
intel_shim_wake(sdw, false); intel_shim_wake(sdw, false);
link_flags = md_flags >> (bus->link_id * 8);
multi_link = !(link_flags & SDW_INTEL_MASTER_DISABLE_MULTI_LINK);
clock_stop_quirks = sdw->link_res->clock_stop_quirks; clock_stop_quirks = sdw->link_res->clock_stop_quirks;
if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) { if (clock_stop_quirks & SDW_INTEL_CLK_STOP_TEARDOWN) {
ret = intel_init(sdw); ret = intel_link_power_up(sdw);
if (ret) { if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret); dev_err(dev, "%s: power_up failed after teardown: %d\n", __func__, ret);
return ret; return ret;
} }
...@@ -1880,145 +1968,45 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) ...@@ -1880,145 +1968,45 @@ static int __maybe_unused intel_resume_runtime(struct device *dev)
*/ */
sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET); sdw_clear_slave_status(bus, SDW_UNATTACH_REQUEST_MASTER_RESET);
ret = sdw_cdns_enable_interrupt(cdns, true); ret = intel_start_bus(sdw);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
/*
* follow recommended programming flows to avoid
* timeouts when gsync is enabled
*/
if (multi_link)
intel_shim_sync_arm(sdw);
ret = sdw_cdns_init(&sdw->cdns);
if (ret < 0) {
dev_err(dev, "unable to initialize Cadence IP during resume\n");
return ret;
}
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n"); dev_err(dev, "%s: cannot start bus after teardown: %d\n", __func__, ret);
intel_link_power_down(sdw);
return ret; return ret;
} }
if (multi_link) {
ret = intel_shim_sync_go(sdw);
if (ret < 0) {
dev_err(dev, "sync go failed during resume\n");
return ret;
}
}
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime TEARDOWN",
true, INTEL_MASTER_RESET_ITERATIONS);
} 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_link_power_up(sdw);
if (ret) { if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret); dev_err(dev, "%s: power_up failed after bus reset: %d\n", __func__, ret);
return ret; return ret;
} }
/* ret = intel_start_bus_after_reset(sdw);
* An exception condition occurs for the CLK_STOP_BUS_RESET
* case if one or more masters remain active. In this condition,
* all the masters are powered on for they are in the same power
* domain. Master can preserve its context for clock stop0, so
* there is no need to clear slave status and reset bus.
*/
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns);
if (!clock_stop0) {
/*
* make sure all Slaves are tagged as UNATTACHED and
* provide reason for reinitialization
*/
status = SDW_UNATTACH_REQUEST_MASTER_RESET;
sdw_clear_slave_status(bus, status);
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
/*
* follow recommended programming flows to avoid
* timeouts when gsync is enabled
*/
if (multi_link)
intel_shim_sync_arm(sdw);
/*
* Re-initialize the IP since it was powered-off
*/
sdw_cdns_init(&sdw->cdns);
} else {
ret = sdw_cdns_enable_interrupt(cdns, true);
if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n");
return ret;
}
}
ret = sdw_cdns_clock_restart(cdns, !clock_stop0);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "unable to restart clock during resume\n"); dev_err(dev, "%s: cannot start bus after reset: %d\n", __func__, ret);
intel_link_power_down(sdw);
return ret; return ret;
} }
if (!clock_stop0) {
ret = sdw_cdns_exit_reset(cdns);
if (ret < 0) {
dev_err(dev, "unable to exit bus reset sequence during resume\n");
return ret;
}
if (multi_link) {
ret = intel_shim_sync_go(sdw);
if (ret < 0) {
dev_err(sdw->cdns.dev, "sync go failed during resume\n");
return ret;
}
}
}
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime BUS_RESET",
true, INTEL_MASTER_RESET_ITERATIONS);
} else if (!clock_stop_quirks) { } else if (!clock_stop_quirks) {
clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); intel_check_clock_stop(sdw);
if (!clock_stop0)
dev_err(dev, "%s invalid configuration, clock was not stopped", __func__);
ret = intel_init(sdw); ret = intel_link_power_up(sdw);
if (ret) { if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret); dev_err(dev, "%s: power_up failed: %d\n", __func__, ret);
return ret; return ret;
} }
ret = sdw_cdns_enable_interrupt(cdns, true); ret = intel_start_bus_after_clock_stop(sdw);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "cannot enable interrupts during resume\n"); dev_err(dev, "%s: cannot start bus after clock stop: %d\n", __func__, ret);
intel_link_power_down(sdw);
return ret; return ret;
} }
ret = sdw_cdns_clock_restart(cdns, false);
if (ret < 0) {
dev_err(dev, "unable to resume master during resume\n");
return ret;
}
sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks",
true, INTEL_MASTER_RESET_ITERATIONS);
} else { } else {
dev_err(dev, "%s clock_stop_quirks %x unsupported\n", dev_err(dev, "%s: clock_stop_quirks %x unsupported\n",
__func__, clock_stop_quirks); __func__, clock_stop_quirks);
ret = -EINVAL; ret = -EINVAL;
} }
......
...@@ -306,7 +306,7 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx) ...@@ -306,7 +306,7 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx)
/* Check SNDWLCAP.LCOUNT */ /* Check SNDWLCAP.LCOUNT */
caps = ioread32(ctx->mmio_base + ctx->shim_base + SDW_SHIM_LCAP); caps = ioread32(ctx->mmio_base + ctx->shim_base + SDW_SHIM_LCAP);
caps &= GENMASK(2, 0); caps &= SDW_SHIM_LCAP_LCOUNT_MASK;
/* Check HW supported vs property value */ /* Check HW supported vs property value */
if (caps < ctx->count) { if (caps < ctx->count) {
......
...@@ -420,7 +420,7 @@ static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl) ...@@ -420,7 +420,7 @@ static int qcom_swrm_get_alert_slave_dev_num(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
for (dev_num = 0; dev_num <= SDW_MAX_DEVICES; dev_num++) { for (dev_num = 1; dev_num <= SDW_MAX_DEVICES; dev_num++) {
status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ)); status = (val >> (dev_num * SWRM_MCP_SLV_STATUS_SZ));
if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) { if ((status & SWRM_MCP_SLV_STATUS_MASK) == SDW_SLAVE_ALERT) {
...@@ -440,7 +440,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl) ...@@ -440,7 +440,7 @@ static void qcom_swrm_get_device_status(struct qcom_swrm_ctrl *ctrl)
ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val); ctrl->reg_read(ctrl, SWRM_MCP_SLV_STATUS, &val);
ctrl->slave_status = val; ctrl->slave_status = val;
for (i = 0; i <= SDW_MAX_DEVICES; i++) { for (i = 1; i <= SDW_MAX_DEVICES; i++) {
u32 s; u32 s;
s = (val >> (i * 2)); s = (val >> (i * 2));
...@@ -573,11 +573,10 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id) ...@@ -573,11 +573,10 @@ static irqreturn_t qcom_swrm_irq_handler(int irq, void *dev_id)
break; break;
case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED: case SWRM_INTERRUPT_STATUS_NEW_SLAVE_ATTACHED:
case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS: case SWRM_INTERRUPT_STATUS_CHANGE_ENUM_SLAVE_STATUS:
dev_err_ratelimited(swrm->dev, "%s: SWR new slave attached\n", dev_dbg_ratelimited(swrm->dev, "SWR new slave attached\n");
__func__);
swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, &slave_status); swrm->reg_read(swrm, SWRM_MCP_SLV_STATUS, &slave_status);
if (swrm->slave_status == slave_status) { if (swrm->slave_status == slave_status) {
dev_err(swrm->dev, "Slave status not changed %x\n", dev_dbg(swrm->dev, "Slave status not changed %x\n",
slave_status); slave_status);
} else { } else {
qcom_swrm_get_device_status(swrm); qcom_swrm_get_device_status(swrm);
......
...@@ -892,6 +892,9 @@ struct sdw_master_ops { ...@@ -892,6 +892,9 @@ struct sdw_master_ops {
* meaningful if multi_link is set. If set to 1, hardware-based * meaningful if multi_link is set. If set to 1, hardware-based
* synchronization will be used even if a stream only uses a single * synchronization will be used even if a stream only uses a single
* SoundWire segment. * SoundWire segment.
* @dev_num_ida_min: if set, defines the minimum values for the IDA
* used to allocate system-unique device numbers. This value needs to be
* identical across all SoundWire bus in the system.
*/ */
struct sdw_bus { struct sdw_bus {
struct device *dev; struct device *dev;
...@@ -916,6 +919,7 @@ struct sdw_bus { ...@@ -916,6 +919,7 @@ struct sdw_bus {
u32 bank_switch_timeout; u32 bank_switch_timeout;
bool multi_link; bool multi_link;
int hw_sync_min_links; int hw_sync_min_links;
int dev_num_ida_min;
}; };
int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent,
......
...@@ -15,32 +15,21 @@ ...@@ -15,32 +15,21 @@
#define SDW_LINK_SIZE 0x10000 #define SDW_LINK_SIZE 0x10000
/* Intel SHIM Registers Definition */ /* Intel SHIM Registers Definition */
/* LCAP */
#define SDW_SHIM_LCAP 0x0 #define SDW_SHIM_LCAP 0x0
#define SDW_SHIM_LCTL 0x4 #define SDW_SHIM_LCAP_LCOUNT_MASK GENMASK(2, 0)
#define SDW_SHIM_IPPTR 0x8
#define SDW_SHIM_SYNC 0xC
#define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * (x))
#define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * (x))
#define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * (x))
#define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * (x))
#define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * (x))
#define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * (x))
#define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * (x)) + (0x2 * (y))) /* LCTL */
#define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * (x)) + (0x2 * (y))) #define SDW_SHIM_LCTL 0x4
#define SDW_SHIM_PDMSCAP(x) (0x062 + 0x60 * (x))
#define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * (x))
#define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * (x))
#define SDW_SHIM_WAKEEN 0x190
#define SDW_SHIM_WAKESTS 0x192
#define SDW_SHIM_LCTL_SPA BIT(0) #define SDW_SHIM_LCTL_SPA BIT(0)
#define SDW_SHIM_LCTL_SPA_MASK GENMASK(3, 0) #define SDW_SHIM_LCTL_SPA_MASK GENMASK(3, 0)
#define SDW_SHIM_LCTL_CPA BIT(8) #define SDW_SHIM_LCTL_CPA BIT(8)
#define SDW_SHIM_LCTL_CPA_MASK GENMASK(11, 8) #define SDW_SHIM_LCTL_CPA_MASK GENMASK(11, 8)
/* SYNC */
#define SDW_SHIM_SYNC 0xC
#define SDW_SHIM_SYNC_SYNCPRD_VAL_24 (24000 / SDW_CADENCE_GSYNC_KHZ - 1) #define SDW_SHIM_SYNC_SYNCPRD_VAL_24 (24000 / SDW_CADENCE_GSYNC_KHZ - 1)
#define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4 (38400 / SDW_CADENCE_GSYNC_KHZ - 1) #define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4 (38400 / SDW_CADENCE_GSYNC_KHZ - 1)
#define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0) #define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0)
...@@ -49,19 +38,33 @@ ...@@ -49,19 +38,33 @@
#define SDW_SHIM_SYNC_CMDSYNC BIT(16) #define SDW_SHIM_SYNC_CMDSYNC BIT(16)
#define SDW_SHIM_SYNC_SYNCGO BIT(24) #define SDW_SHIM_SYNC_SYNCGO BIT(24)
/* Control stream capabililities and channel mask */
#define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * (x))
#define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * (x))
#define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * (x))
#define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * (x))
#define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * (x))
/* PCM Stream capabilities */
#define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * (x))
#define SDW_SHIM_PCMSCAP_ISS GENMASK(3, 0) #define SDW_SHIM_PCMSCAP_ISS GENMASK(3, 0)
#define SDW_SHIM_PCMSCAP_OSS GENMASK(7, 4) #define SDW_SHIM_PCMSCAP_OSS GENMASK(7, 4)
#define SDW_SHIM_PCMSCAP_BSS GENMASK(12, 8) #define SDW_SHIM_PCMSCAP_BSS GENMASK(12, 8)
/* PCM Stream Channel Map */
#define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * (x)) + (0x2 * (y)))
/* PCM Stream Channel Count */
#define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * (x)) + (0x2 * (y)))
#define SDW_SHIM_PCMSYCM_LCHN GENMASK(3, 0) #define SDW_SHIM_PCMSYCM_LCHN GENMASK(3, 0)
#define SDW_SHIM_PCMSYCM_HCHN GENMASK(7, 4) #define SDW_SHIM_PCMSYCM_HCHN GENMASK(7, 4)
#define SDW_SHIM_PCMSYCM_STREAM GENMASK(13, 8) #define SDW_SHIM_PCMSYCM_STREAM GENMASK(13, 8)
#define SDW_SHIM_PCMSYCM_DIR BIT(15) #define SDW_SHIM_PCMSYCM_DIR BIT(15)
#define SDW_SHIM_PDMSCAP_ISS GENMASK(3, 0) /* IO control */
#define SDW_SHIM_PDMSCAP_OSS GENMASK(7, 4) #define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * (x))
#define SDW_SHIM_PDMSCAP_BSS GENMASK(12, 8)
#define SDW_SHIM_PDMSCAP_CPSS GENMASK(15, 13)
#define SDW_SHIM_IOCTL_MIF BIT(0) #define SDW_SHIM_IOCTL_MIF BIT(0)
#define SDW_SHIM_IOCTL_CO BIT(1) #define SDW_SHIM_IOCTL_CO BIT(1)
...@@ -73,13 +76,23 @@ ...@@ -73,13 +76,23 @@
#define SDW_SHIM_IOCTL_CIBD BIT(8) #define SDW_SHIM_IOCTL_CIBD BIT(8)
#define SDW_SHIM_IOCTL_DIBD BIT(9) #define SDW_SHIM_IOCTL_DIBD BIT(9)
#define SDW_SHIM_CTMCTL_DACTQE BIT(0) /* Wake Enable*/
#define SDW_SHIM_CTMCTL_DODS BIT(1) #define SDW_SHIM_WAKEEN 0x190
#define SDW_SHIM_CTMCTL_DOAIS GENMASK(4, 3)
#define SDW_SHIM_WAKEEN_ENABLE BIT(0) #define SDW_SHIM_WAKEEN_ENABLE BIT(0)
/* Wake Status */
#define SDW_SHIM_WAKESTS 0x192
#define SDW_SHIM_WAKESTS_STATUS BIT(0) #define SDW_SHIM_WAKESTS_STATUS BIT(0)
/* AC Timing control */
#define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * (x))
#define SDW_SHIM_CTMCTL_DACTQE BIT(0)
#define SDW_SHIM_CTMCTL_DODS BIT(1)
#define SDW_SHIM_CTMCTL_DOAIS GENMASK(4, 3)
/* Intel ALH Register definitions */ /* Intel ALH Register definitions */
#define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x))) #define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x)))
#define SDW_ALH_NUM_STREAMS 64 #define SDW_ALH_NUM_STREAMS 64
......
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