Commit b9dd56e8 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull soundwire updates from Vinod Koul:

 - cleanup and conversion for soundwire sysfs groups

 - intel support for ace2x bits, auxdevice pm improvements

 - qcom multi link device support

* tag 'soundwire-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire: (33 commits)
  soundwire: intel_ace2.x: add support for DOAISE property
  soundwire: intel_ace2.x: add support for DODSE property
  soundwire: intel_ace2x: use DOAIS and DODS settings from firmware
  soundwire: intel_ace2x: cleanup DOAIS/DODS settings
  soundwire: intel_ace2x: simplify check_wake()
  soundwire: intel_ace2x: fix wakeup handling
  soundwire: intel_init: resume all devices on exit.
  soundwire: intel: export intel_resume_child_device
  soundwire: intel_auxdevice: use pm_runtime_resume() instead of pm_request_resume()
  ASoC: SOF: Intel: hda: disable SoundWire interrupt later
  soundwire: qcom: allow multi-link on newer devices
  soundwire: intel_ace2x: use legacy formula for intel_alh_id
  soundwire: reconcile dp0_prop and dpn_prop
  soundwire: intel_ace2x: set the clock source
  soundwire: intel_ace2.x: power-up first before setting SYNCPRD
  soundwire: intel_ace2x: move and extend clock selection
  soundwire: intel: add support for MeteorLake additional clocks
  soundwire: intel: add more values for SYNCPRD
  soundwire: bus: extend base clock checks to 96 MHz
  soundwire: cadence: show the bus frequency and frame shape
  ...
parents 8053d2ff a0df7e04
...@@ -17,42 +17,38 @@ ...@@ -17,42 +17,38 @@
#define ACP_PAD_PULLDOWN_CTRL 0x0001448 #define ACP_PAD_PULLDOWN_CTRL 0x0001448
#define ACP_SW_PAD_KEEPER_EN 0x0001454 #define ACP_SW_PAD_KEEPER_EN 0x0001454
#define AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9a #define AMD_SDW0_PAD_CTRL_MASK 0x60
#define AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7f9f #define AMD_SDW1_PAD_CTRL_MASK 5
#define AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK 0x7ffa #define AMD_SDW_PAD_CTRL_MASK (AMD_SDW0_PAD_CTRL_MASK | AMD_SDW1_PAD_CTRL_MASK)
#define AMD_SDW0_PAD_EN_MASK 1 #define AMD_SDW0_PAD_EN 1
#define AMD_SDW1_PAD_EN_MASK 0x10 #define AMD_SDW1_PAD_EN 0x10
#define AMD_SDW_PAD_EN_MASK (AMD_SDW0_PAD_EN_MASK | AMD_SDW1_PAD_EN_MASK) #define AMD_SDW_PAD_EN (AMD_SDW0_PAD_EN | AMD_SDW1_PAD_EN)
static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev) static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev)
{ {
u32 val; u32 pad_keeper_en, pad_pulldown_ctrl_mask;
u32 pad_keeper_en_mask, pad_pulldown_ctrl_mask;
switch (link_mask) { switch (link_mask) {
case 1: case 1:
pad_keeper_en_mask = AMD_SDW0_PAD_EN_MASK; pad_keeper_en = AMD_SDW0_PAD_EN;
pad_pulldown_ctrl_mask = AMD_SDW0_PAD_PULLDOWN_CTRL_ENABLE_MASK; pad_pulldown_ctrl_mask = AMD_SDW0_PAD_CTRL_MASK;
break; break;
case 2: case 2:
pad_keeper_en_mask = AMD_SDW1_PAD_EN_MASK; pad_keeper_en = AMD_SDW1_PAD_EN;
pad_pulldown_ctrl_mask = AMD_SDW1_PAD_PULLDOWN_CTRL_ENABLE_MASK; pad_pulldown_ctrl_mask = AMD_SDW1_PAD_CTRL_MASK;
break; break;
case 3: case 3:
pad_keeper_en_mask = AMD_SDW_PAD_EN_MASK; pad_keeper_en = AMD_SDW_PAD_EN;
pad_pulldown_ctrl_mask = AMD_SDW_PAD_PULLDOWN_CTRL_ENABLE_MASK; pad_pulldown_ctrl_mask = AMD_SDW_PAD_CTRL_MASK;
break; break;
default: default:
dev_err(dev, "No SDW Links are enabled\n"); dev_err(dev, "No SDW Links are enabled\n");
return -ENODEV; return -ENODEV;
} }
val = readl(mmio + ACP_SW_PAD_KEEPER_EN); amd_updatel(mmio, ACP_SW_PAD_KEEPER_EN, pad_keeper_en, pad_keeper_en);
val |= pad_keeper_en_mask; amd_updatel(mmio, ACP_PAD_PULLDOWN_CTRL, pad_pulldown_ctrl_mask, 0);
writel(val, mmio + ACP_SW_PAD_KEEPER_EN);
val = readl(mmio + ACP_PAD_PULLDOWN_CTRL);
val &= pad_pulldown_ctrl_mask;
writel(val, mmio + ACP_PAD_PULLDOWN_CTRL);
return 0; return 0;
} }
......
...@@ -10,4 +10,12 @@ ...@@ -10,4 +10,12 @@
int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager); int amd_sdw_manager_start(struct amd_sdw_manager *amd_manager);
static inline void amd_updatel(void __iomem *mmio, int offset, u32 mask, u32 val)
{
u32 tmp;
tmp = readl(mmio + offset);
tmp = (tmp & ~mask) | val;
writel(tmp, mmio + offset);
}
#endif #endif
...@@ -89,9 +89,8 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager) ...@@ -89,9 +89,8 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
u32 val; u32 val;
mutex_lock(amd_manager->acp_sdw_lock); mutex_lock(amd_manager->acp_sdw_lock);
val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); val = sdw_manager_reg_mask_array[amd_manager->instance];
val |= sdw_manager_reg_mask_array[amd_manager->instance]; amd_updatel(amd_manager->acp_mmio, ACP_EXTERNAL_INTR_CNTL(amd_manager->instance), val, val);
writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance));
mutex_unlock(amd_manager->acp_sdw_lock); mutex_unlock(amd_manager->acp_sdw_lock);
writel(AMD_SDW_IRQ_MASK_0TO7, amd_manager->mmio + writel(AMD_SDW_IRQ_MASK_0TO7, amd_manager->mmio +
...@@ -103,12 +102,12 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager) ...@@ -103,12 +102,12 @@ static void amd_enable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager) static void amd_disable_sdw_interrupts(struct amd_sdw_manager *amd_manager)
{ {
u32 val; u32 irq_mask;
mutex_lock(amd_manager->acp_sdw_lock); mutex_lock(amd_manager->acp_sdw_lock);
val = readl(amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); irq_mask = sdw_manager_reg_mask_array[amd_manager->instance];
val &= ~sdw_manager_reg_mask_array[amd_manager->instance]; amd_updatel(amd_manager->acp_mmio, ACP_EXTERNAL_INTR_CNTL(amd_manager->instance),
writel(val, amd_manager->acp_mmio + ACP_EXTERNAL_INTR_CNTL(amd_manager->instance)); irq_mask, 0);
mutex_unlock(amd_manager->acp_sdw_lock); mutex_unlock(amd_manager->acp_sdw_lock);
writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7); writel(0x00, amd_manager->mmio + ACP_SW_STATE_CHANGE_STATUS_MASK_0TO7);
......
...@@ -1312,18 +1312,18 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave) ...@@ -1312,18 +1312,18 @@ static int sdw_slave_set_frequency(struct sdw_slave *slave)
if (!(19200000 % mclk_freq)) { if (!(19200000 % mclk_freq)) {
mclk_freq = 19200000; mclk_freq = 19200000;
base = SDW_SCP_BASE_CLOCK_19200000_HZ; base = SDW_SCP_BASE_CLOCK_19200000_HZ;
} else if (!(24000000 % mclk_freq)) {
mclk_freq = 24000000;
base = SDW_SCP_BASE_CLOCK_24000000_HZ;
} else if (!(24576000 % mclk_freq)) {
mclk_freq = 24576000;
base = SDW_SCP_BASE_CLOCK_24576000_HZ;
} else if (!(22579200 % mclk_freq)) { } else if (!(22579200 % mclk_freq)) {
mclk_freq = 22579200; mclk_freq = 22579200;
base = SDW_SCP_BASE_CLOCK_22579200_HZ; base = SDW_SCP_BASE_CLOCK_22579200_HZ;
} else if (!(24576000 % mclk_freq)) {
mclk_freq = 24576000;
base = SDW_SCP_BASE_CLOCK_24576000_HZ;
} else if (!(32000000 % mclk_freq)) { } else if (!(32000000 % mclk_freq)) {
mclk_freq = 32000000; mclk_freq = 32000000;
base = SDW_SCP_BASE_CLOCK_32000000_HZ; base = SDW_SCP_BASE_CLOCK_32000000_HZ;
} else if (!(96000000 % mclk_freq)) {
mclk_freq = 24000000;
base = SDW_SCP_BASE_CLOCK_24000000_HZ;
} else { } else {
dev_err(&slave->dev, dev_err(&slave->dev,
"Unsupported clock base, mclk %d\n", "Unsupported clock base, mclk %d\n",
...@@ -1474,7 +1474,7 @@ static int sdw_handle_dp0_interrupt(struct sdw_slave *slave, u8 *slave_status) ...@@ -1474,7 +1474,7 @@ static int sdw_handle_dp0_interrupt(struct sdw_slave *slave, u8 *slave_status)
} }
do { do {
clear = status & ~SDW_DP0_INTERRUPTS; clear = status & ~(SDW_DP0_INTERRUPTS | SDW_DP0_SDCA_CASCADE);
if (status & SDW_DP0_INT_TEST_FAIL) { if (status & SDW_DP0_INT_TEST_FAIL) {
dev_err(&slave->dev, "Test fail for port 0\n"); dev_err(&slave->dev, "Test fail for port 0\n");
......
...@@ -126,8 +126,8 @@ static int sdw_drv_probe(struct device *dev) ...@@ -126,8 +126,8 @@ static int sdw_drv_probe(struct device *dev)
if (slave->prop.use_domain_irq) if (slave->prop.use_domain_irq)
sdw_irq_create_mapping(slave); sdw_irq_create_mapping(slave);
/* init the sysfs as we have properties now */ /* init the dynamic sysfs attributes we need */
ret = sdw_slave_sysfs_init(slave); ret = sdw_slave_sysfs_dpn_init(slave);
if (ret < 0) if (ret < 0)
dev_warn(dev, "Slave sysfs init failed:%d\n", ret); dev_warn(dev, "Slave sysfs init failed:%d\n", ret);
...@@ -221,6 +221,7 @@ int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) ...@@ -221,6 +221,7 @@ int __sdw_register_driver(struct sdw_driver *drv, struct module *owner)
drv->driver.probe = sdw_drv_probe; drv->driver.probe = sdw_drv_probe;
drv->driver.remove = sdw_drv_remove; drv->driver.remove = sdw_drv_remove;
drv->driver.shutdown = sdw_drv_shutdown; drv->driver.shutdown = sdw_drv_shutdown;
drv->driver.dev_groups = sdw_attr_groups;
return driver_register(&drv->driver); return driver_register(&drv->driver);
} }
......
...@@ -1236,7 +1236,7 @@ EXPORT_SYMBOL(sdw_cdns_enable_interrupt); ...@@ -1236,7 +1236,7 @@ EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
static int cdns_allocate_pdi(struct sdw_cdns *cdns, static int cdns_allocate_pdi(struct sdw_cdns *cdns,
struct sdw_cdns_pdi **stream, struct sdw_cdns_pdi **stream,
u32 num, u32 pdi_offset) u32 num)
{ {
struct sdw_cdns_pdi *pdi; struct sdw_cdns_pdi *pdi;
int i; int i;
...@@ -1249,7 +1249,7 @@ static int cdns_allocate_pdi(struct sdw_cdns *cdns, ...@@ -1249,7 +1249,7 @@ static int cdns_allocate_pdi(struct sdw_cdns *cdns,
return -ENOMEM; return -ENOMEM;
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
pdi[i].num = i + pdi_offset; pdi[i].num = i;
} }
*stream = pdi; *stream = pdi;
...@@ -1266,7 +1266,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, ...@@ -1266,7 +1266,6 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
struct sdw_cdns_stream_config config) struct sdw_cdns_stream_config config)
{ {
struct sdw_cdns_streams *stream; struct sdw_cdns_streams *stream;
int offset;
int ret; int ret;
cdns->pcm.num_bd = config.pcm_bd; cdns->pcm.num_bd = config.pcm_bd;
...@@ -1277,24 +1276,15 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns, ...@@ -1277,24 +1276,15 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
stream = &cdns->pcm; stream = &cdns->pcm;
/* we allocate PDI0 and PDI1 which are used for Bulk */ /* we allocate PDI0 and PDI1 which are used for Bulk */
offset = 0; ret = cdns_allocate_pdi(cdns, &stream->bd, stream->num_bd);
ret = cdns_allocate_pdi(cdns, &stream->bd,
stream->num_bd, offset);
if (ret) if (ret)
return ret; return ret;
offset += stream->num_bd; ret = cdns_allocate_pdi(cdns, &stream->in, stream->num_in);
ret = cdns_allocate_pdi(cdns, &stream->in,
stream->num_in, offset);
if (ret) if (ret)
return ret; return ret;
offset += stream->num_in; ret = cdns_allocate_pdi(cdns, &stream->out, stream->num_out);
ret = cdns_allocate_pdi(cdns, &stream->out,
stream->num_out, offset);
if (ret) if (ret)
return ret; return ret;
...@@ -1329,6 +1319,12 @@ static void cdns_init_clock_ctrl(struct sdw_cdns *cdns) ...@@ -1329,6 +1319,12 @@ static void cdns_init_clock_ctrl(struct sdw_cdns *cdns)
u32 ssp_interval; u32 ssp_interval;
int divider; int divider;
dev_dbg(cdns->dev, "mclk %d max %d row %d col %d\n",
prop->mclk_freq,
prop->max_clk_freq,
prop->default_row,
prop->default_col);
/* Set clock divider */ /* Set clock divider */
divider = (prop->mclk_freq / prop->max_clk_freq) - 1; divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
...@@ -1802,7 +1798,6 @@ EXPORT_SYMBOL(cdns_set_sdw_stream); ...@@ -1802,7 +1798,6 @@ EXPORT_SYMBOL(cdns_set_sdw_stream);
* cdns_find_pdi() - Find a free PDI * cdns_find_pdi() - Find a free PDI
* *
* @cdns: Cadence instance * @cdns: Cadence instance
* @offset: Starting offset
* @num: Number of PDIs * @num: Number of PDIs
* @pdi: PDI instances * @pdi: PDI instances
* @dai_id: DAI id * @dai_id: DAI id
...@@ -1811,14 +1806,13 @@ EXPORT_SYMBOL(cdns_set_sdw_stream); ...@@ -1811,14 +1806,13 @@ EXPORT_SYMBOL(cdns_set_sdw_stream);
* expected to match, return NULL otherwise. * expected to match, return NULL otherwise.
*/ */
static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns, static struct sdw_cdns_pdi *cdns_find_pdi(struct sdw_cdns *cdns,
unsigned int offset,
unsigned int num, unsigned int num,
struct sdw_cdns_pdi *pdi, struct sdw_cdns_pdi *pdi,
int dai_id) int dai_id)
{ {
int i; int i;
for (i = offset; i < offset + num; i++) for (i = 0; i < num; i++)
if (pdi[i].num == dai_id) if (pdi[i].num == dai_id)
return &pdi[i]; return &pdi[i];
...@@ -1872,15 +1866,15 @@ struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns, ...@@ -1872,15 +1866,15 @@ struct sdw_cdns_pdi *sdw_cdns_alloc_pdi(struct sdw_cdns *cdns,
struct sdw_cdns_pdi *pdi = NULL; struct sdw_cdns_pdi *pdi = NULL;
if (dir == SDW_DATA_DIR_RX) if (dir == SDW_DATA_DIR_RX)
pdi = cdns_find_pdi(cdns, 0, stream->num_in, stream->in, pdi = cdns_find_pdi(cdns, stream->num_in, stream->in,
dai_id); dai_id);
else else
pdi = cdns_find_pdi(cdns, 0, stream->num_out, stream->out, pdi = cdns_find_pdi(cdns, stream->num_out, stream->out,
dai_id); dai_id);
/* check if we found a PDI, else find in bi-directional */ /* check if we found a PDI, else find in bi-directional */
if (!pdi) if (!pdi)
pdi = cdns_find_pdi(cdns, 2, stream->num_bd, stream->bd, pdi = cdns_find_pdi(cdns, stream->num_bd, stream->bd,
dai_id); dai_id);
if (pdi) { if (pdi) {
......
...@@ -345,8 +345,10 @@ static int intel_link_power_up(struct sdw_intel *sdw) ...@@ -345,8 +345,10 @@ static int intel_link_power_up(struct sdw_intel *sdw)
u32 spa_mask, cpa_mask; u32 spa_mask, cpa_mask;
u32 link_control; u32 link_control;
int ret = 0; int ret = 0;
u32 clock_source;
u32 syncprd; u32 syncprd;
u32 sync_reg; u32 sync_reg;
bool lcap_mlcs;
mutex_lock(sdw->link_res->shim_lock); mutex_lock(sdw->link_res->shim_lock);
...@@ -358,12 +360,35 @@ static int intel_link_power_up(struct sdw_intel *sdw) ...@@ -358,12 +360,35 @@ static int intel_link_power_up(struct sdw_intel *sdw)
* is only dependent on the oscillator clock provided to * is only dependent on the oscillator clock provided to
* the IP, so adjust based on _DSD properties reported in DSDT * the IP, so adjust based on _DSD properties reported in DSDT
* tables. The values reported are based on either 24MHz * tables. The values reported are based on either 24MHz
* (CNL/CML) or 38.4 MHz (ICL/TGL+). * (CNL/CML) or 38.4 MHz (ICL/TGL+). On MeteorLake additional
* frequencies are available with the MLCS clock source selection.
*/ */
if (prop->mclk_freq % 6000000) lcap_mlcs = intel_readl(shim, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_MLCS_MASK;
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
else if (prop->mclk_freq % 6000000) {
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24; if (prop->mclk_freq % 2400000) {
if (lcap_mlcs) {
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24_576;
clock_source = SDW_SHIM_MLCS_CARDINAL_CLK;
} else {
dev_err(sdw->cdns.dev, "%s: invalid clock configuration, mclk %d lcap_mlcs %d\n",
__func__, prop->mclk_freq, lcap_mlcs);
ret = -EINVAL;
goto out;
}
} else {
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
clock_source = SDW_SHIM_MLCS_XTAL_CLK;
}
} else {
if (lcap_mlcs) {
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_96;
clock_source = SDW_SHIM_MLCS_AUDIO_PLL_CLK;
} else {
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
clock_source = SDW_SHIM_MLCS_XTAL_CLK;
}
}
if (!*shim_mask) { if (!*shim_mask) {
dev_dbg(sdw->cdns.dev, "powering up all links\n"); dev_dbg(sdw->cdns.dev, "powering up all links\n");
...@@ -403,6 +428,13 @@ static int intel_link_power_up(struct sdw_intel *sdw) ...@@ -403,6 +428,13 @@ static int intel_link_power_up(struct sdw_intel *sdw)
"Failed to set SHIM_SYNC: %d\n", ret); "Failed to set SHIM_SYNC: %d\n", ret);
goto out; goto out;
} }
/* update link clock if needed */
if (lcap_mlcs) {
link_control = intel_readl(shim, SDW_SHIM_LCTL);
u32p_replace_bits(&link_control, clock_source, SDW_SHIM_LCTL_MLCS_MASK);
intel_writel(shim, SDW_SHIM_LCTL, link_control);
}
} }
*shim_mask |= BIT(link_id); *shim_mask |= BIT(link_id);
...@@ -668,6 +700,24 @@ static int intel_params_stream(struct sdw_intel *sdw, ...@@ -668,6 +700,24 @@ static int intel_params_stream(struct sdw_intel *sdw,
* DAI routines * DAI routines
*/ */
static int intel_free_stream(struct sdw_intel *sdw,
struct snd_pcm_substream *substream,
struct snd_soc_dai *dai,
int link_id)
{
struct sdw_intel_link_res *res = sdw->link_res;
struct sdw_intel_stream_free_data free_data;
free_data.substream = substream;
free_data.dai = dai;
free_data.link_id = link_id;
if (res->ops && res->ops->free_stream && res->dev)
return res->ops->free_stream(res->dev, &free_data);
return 0;
}
static int intel_hw_params(struct snd_pcm_substream *substream, static int intel_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
...@@ -799,6 +849,7 @@ static int ...@@ -799,6 +849,7 @@ static int
intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
{ {
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_intel *sdw = cdns_to_intel(cdns);
struct sdw_cdns_dai_runtime *dai_runtime; struct sdw_cdns_dai_runtime *dai_runtime;
int ret; int ret;
...@@ -819,6 +870,12 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ...@@ -819,6 +870,12 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
return ret; return ret;
} }
ret = intel_free_stream(sdw, substream, dai, sdw->instance);
if (ret < 0) {
dev_err(dai->dev, "intel_free_stream: failed %d\n", ret);
return ret;
}
dai_runtime->pdi = NULL; dai_runtime->pdi = NULL;
return 0; return 0;
...@@ -1062,4 +1119,3 @@ const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = { ...@@ -1062,4 +1119,3 @@ const struct sdw_intel_hw_ops sdw_intel_cnl_hw_ops = {
.sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked, .sync_check_cmdsync_unlocked = intel_check_cmdsync_unlocked,
}; };
EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL); EXPORT_SYMBOL_NS(sdw_intel_cnl_hw_ops, SOUNDWIRE_INTEL);
...@@ -58,6 +58,13 @@ struct sdw_intel { ...@@ -58,6 +58,13 @@ struct sdw_intel {
#endif #endif
}; };
struct sdw_intel_prop {
u16 doaise;
u16 doais;
u16 dodse;
u16 dods;
};
enum intel_pdi_type { enum intel_pdi_type {
INTEL_PDI_IN = 0, INTEL_PDI_IN = 0,
INTEL_PDI_OUT = 1, INTEL_PDI_OUT = 1,
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
#include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_intel.h> #include <linux/soundwire/sdw_intel.h>
#include <sound/pcm_params.h> #include <sound/hdaudio.h>
#include <sound/hda-mlink.h> #include <sound/hda-mlink.h>
#include <sound/hda_register.h>
#include <sound/pcm_params.h>
#include "cadence_master.h" #include "cadence_master.h"
#include "bus.h" #include "bus.h"
#include "intel.h" #include "intel.h"
...@@ -23,49 +25,86 @@ ...@@ -23,49 +25,86 @@
static void intel_shim_vs_init(struct sdw_intel *sdw) static void intel_shim_vs_init(struct sdw_intel *sdw)
{ {
void __iomem *shim_vs = sdw->link_res->shim_vs; void __iomem *shim_vs = sdw->link_res->shim_vs;
struct sdw_bus *bus = &sdw->cdns.bus;
struct sdw_intel_prop *intel_prop;
u16 doaise;
u16 doais;
u16 dodse;
u16 dods;
u16 act; u16 act;
intel_prop = bus->vendor_specific_prop;
doaise = intel_prop->doaise;
doais = intel_prop->doais;
dodse = intel_prop->dodse;
dods = intel_prop->dods;
act = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL); act = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL);
u16p_replace_bits(&act, 0x1, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS); u16p_replace_bits(&act, doaise, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAISE);
u16p_replace_bits(&act, doais, SDW_SHIM2_INTEL_VS_ACTMCTL_DOAIS);
u16p_replace_bits(&act, dodse, SDW_SHIM2_INTEL_VS_ACTMCTL_DODSE);
u16p_replace_bits(&act, dods, SDW_SHIM2_INTEL_VS_ACTMCTL_DODS);
act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DACTQE; act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DACTQE;
act |= SDW_SHIM2_INTEL_VS_ACTMCTL_DODS;
intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL, act); intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_ACTMCTL, act);
usleep_range(10, 15); usleep_range(10, 15);
} }
static int intel_shim_check_wake(struct sdw_intel *sdw) static void intel_shim_vs_set_clock_source(struct sdw_intel *sdw, u32 source)
{ {
void __iomem *shim_vs; void __iomem *shim_vs = sdw->link_res->shim_vs;
u16 wake_sts; u32 val;
shim_vs = sdw->link_res->shim_vs; val = intel_readl(shim_vs, SDW_SHIM2_INTEL_VS_LVSCTL);
wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS);
return wake_sts & SDW_SHIM2_INTEL_VS_WAKEEN_PWS; u32p_replace_bits(&val, source, SDW_SHIM2_INTEL_VS_LVSCTL_MLCS);
intel_writel(shim_vs, SDW_SHIM2_INTEL_VS_LVSCTL, val);
dev_dbg(sdw->cdns.dev, "clock source %d LVSCTL %#x\n", source, val);
}
static int intel_shim_check_wake(struct sdw_intel *sdw)
{
/*
* We follow the HDaudio example and resume unconditionally
* without checking the WAKESTS bit for that specific link
*/
return 1;
} }
static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable) static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
{ {
void __iomem *shim_vs = sdw->link_res->shim_vs; u16 lsdiid = 0;
u16 wake_en; u16 wake_en;
u16 wake_sts; u16 wake_sts;
int ret;
mutex_lock(sdw->link_res->shim_lock);
ret = hdac_bus_eml_sdw_get_lsdiid_unlocked(sdw->link_res->hbus, sdw->instance, &lsdiid);
if (ret < 0)
goto unlock;
wake_en = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN); wake_en = snd_hdac_chip_readw(sdw->link_res->hbus, WAKEEN);
if (wake_enable) { if (wake_enable) {
/* Enable the wakeup */ /* Enable the wakeup */
wake_en |= SDW_SHIM2_INTEL_VS_WAKEEN_PWE; wake_en |= lsdiid;
intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en);
snd_hdac_chip_writew(sdw->link_res->hbus, WAKEEN, wake_en);
} else { } else {
/* Disable the wake up interrupt */ /* Disable the wake up interrupt */
wake_en &= ~SDW_SHIM2_INTEL_VS_WAKEEN_PWE; wake_en &= ~lsdiid;
intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKEEN, wake_en); snd_hdac_chip_writew(sdw->link_res->hbus, WAKEEN, wake_en);
/* Clear wake status (W1C) */ /* Clear wake status (W1C) */
wake_sts = intel_readw(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS); wake_sts = snd_hdac_chip_readw(sdw->link_res->hbus, STATESTS);
wake_sts |= SDW_SHIM2_INTEL_VS_WAKEEN_PWS; wake_sts |= lsdiid;
intel_writew(shim_vs, SDW_SHIM2_INTEL_VS_WAKESTS, wake_sts); snd_hdac_chip_writew(sdw->link_res->hbus, STATESTS, wake_sts);
} }
unlock:
mutex_unlock(sdw->link_res->shim_lock);
} }
static int intel_link_power_up(struct sdw_intel *sdw) static int intel_link_power_up(struct sdw_intel *sdw)
...@@ -74,36 +113,45 @@ static int intel_link_power_up(struct sdw_intel *sdw) ...@@ -74,36 +113,45 @@ static int intel_link_power_up(struct sdw_intel *sdw)
struct sdw_master_prop *prop = &bus->prop; struct sdw_master_prop *prop = &bus->prop;
u32 *shim_mask = sdw->link_res->shim_mask; u32 *shim_mask = sdw->link_res->shim_mask;
unsigned int link_id = sdw->instance; unsigned int link_id = sdw->instance;
u32 clock_source;
u32 syncprd; u32 syncprd;
int ret; int ret;
if (prop->mclk_freq % 6000000) {
if (prop->mclk_freq % 2400000) {
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24_576;
clock_source = SDW_SHIM2_MLCS_CARDINAL_CLK;
} else {
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
clock_source = SDW_SHIM2_MLCS_XTAL_CLK;
}
} else {
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_96;
clock_source = SDW_SHIM2_MLCS_AUDIO_PLL_CLK;
}
mutex_lock(sdw->link_res->shim_lock); mutex_lock(sdw->link_res->shim_lock);
ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id);
if (ret < 0) {
dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n",
__func__, ret);
goto out;
}
intel_shim_vs_set_clock_source(sdw, clock_source);
if (!*shim_mask) { if (!*shim_mask) {
/* we first need to program the SyncPRD/CPU registers */ /* we first need to program the SyncPRD/CPU registers */
dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n"); dev_dbg(sdw->cdns.dev, "first link up, programming SYNCPRD\n");
if (prop->mclk_freq % 6000000)
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
else
syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
ret = hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd); ret = hdac_bus_eml_sdw_set_syncprd_unlocked(sdw->link_res->hbus, syncprd);
if (ret < 0) { if (ret < 0) {
dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n", dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_set_syncprd failed: %d\n",
__func__, ret); __func__, ret);
goto out; goto out;
} }
}
ret = hdac_bus_eml_sdw_power_up_unlocked(sdw->link_res->hbus, link_id);
if (ret < 0) {
dev_err(sdw->cdns.dev, "%s: hdac_bus_eml_sdw_power_up failed: %d\n",
__func__, ret);
goto out;
}
if (!*shim_mask) {
/* SYNCPU will change once link is active */ /* SYNCPU will change once link is active */
ret = hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus); ret = hdac_bus_eml_sdw_wait_syncpu_unlocked(sdw->link_res->hbus);
if (ret < 0) { if (ret < 0) {
...@@ -268,6 +316,11 @@ static int intel_hw_params(struct snd_pcm_substream *substream, ...@@ -268,6 +316,11 @@ static int intel_hw_params(struct snd_pcm_substream *substream,
goto error; goto error;
} }
/* use same definitions for alh_id as previous generations */
pdi->intel_alh_id = (sdw->instance * 16) + pdi->num + 3;
if (pdi->num >= 2)
pdi->intel_alh_id += 2;
/* the SHIM will be configured in the callback functions */ /* the SHIM will be configured in the callback functions */
sdw_cdns_config_stream(cdns, ch, dir, pdi); sdw_cdns_config_stream(cdns, ch, dir, pdi);
......
...@@ -122,6 +122,7 @@ static void generic_new_peripheral_assigned(struct sdw_bus *bus, ...@@ -122,6 +122,7 @@ static void generic_new_peripheral_assigned(struct sdw_bus *bus,
static int sdw_master_read_intel_prop(struct sdw_bus *bus) static int sdw_master_read_intel_prop(struct sdw_bus *bus)
{ {
struct sdw_master_prop *prop = &bus->prop; struct sdw_master_prop *prop = &bus->prop;
struct sdw_intel_prop *intel_prop;
struct fwnode_handle *link; struct fwnode_handle *link;
char name[32]; char name[32];
u32 quirk_mask; u32 quirk_mask;
...@@ -153,6 +154,36 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus) ...@@ -153,6 +154,36 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
prop->quirks = SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH | prop->quirks = SDW_MASTER_QUIRKS_CLEAR_INITIAL_CLASH |
SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY; SDW_MASTER_QUIRKS_CLEAR_INITIAL_PARITY;
intel_prop = devm_kzalloc(bus->dev, sizeof(*intel_prop), GFP_KERNEL);
if (!intel_prop)
return -ENOMEM;
/* initialize with hardware defaults, in case the properties are not found */
intel_prop->doaise = 0x1;
intel_prop->doais = 0x3;
intel_prop->dodse = 0x0;
intel_prop->dods = 0x1;
fwnode_property_read_u16(link,
"intel-sdw-doaise",
&intel_prop->doaise);
fwnode_property_read_u16(link,
"intel-sdw-doais",
&intel_prop->doais);
fwnode_property_read_u16(link,
"intel-sdw-dodse",
&intel_prop->dodse);
fwnode_property_read_u16(link,
"intel-sdw-dods",
&intel_prop->dods);
bus->vendor_specific_prop = intel_prop;
dev_dbg(bus->dev, "doaise %#x doais %#x dodse %#x dods %#x\n",
intel_prop->doaise,
intel_prop->doais,
intel_prop->dodse,
intel_prop->dods);
return 0; return 0;
} }
...@@ -440,7 +471,7 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) ...@@ -440,7 +471,7 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev)
* PM calls * PM calls
*/ */
static int intel_resume_child_device(struct device *dev, void *data) int intel_resume_child_device(struct device *dev, void *data)
{ {
int ret; int ret;
struct sdw_slave *slave = dev_to_sdw_dev(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev);
...@@ -454,9 +485,9 @@ static int intel_resume_child_device(struct device *dev, void *data) ...@@ -454,9 +485,9 @@ static int intel_resume_child_device(struct device *dev, void *data)
return 0; return 0;
} }
ret = pm_request_resume(dev); ret = pm_runtime_resume(dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret); dev_err(dev, "%s: pm_runtime_resume failed: %d\n", __func__, ret);
return ret; return ret;
} }
...@@ -499,9 +530,9 @@ static int __maybe_unused intel_pm_prepare(struct device *dev) ...@@ -499,9 +530,9 @@ static int __maybe_unused intel_pm_prepare(struct device *dev)
* first resume the device for this link. This will also by construction * first resume the device for this link. This will also by construction
* resume the PCI parent device. * resume the PCI parent device.
*/ */
ret = pm_request_resume(dev); ret = pm_runtime_resume(dev);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret); dev_err(dev, "%s: pm_runtime_resume failed: %d\n", __func__, ret);
return 0; return 0;
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
int intel_link_startup(struct auxiliary_device *auxdev); int intel_link_startup(struct auxiliary_device *auxdev);
int intel_link_process_wakeen_event(struct auxiliary_device *auxdev); int intel_link_process_wakeen_event(struct auxiliary_device *auxdev);
int intel_resume_child_device(struct device *dev, void *data);
struct sdw_intel_link_dev { struct sdw_intel_link_dev {
struct auxiliary_device auxdev; struct auxiliary_device auxdev;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/soundwire/sdw_intel.h> #include <linux/soundwire/sdw_intel.h>
#include "cadence_master.h" #include "cadence_master.h"
#include "bus.h"
#include "intel.h" #include "intel.h"
#include "intel_auxdevice.h" #include "intel_auxdevice.h"
...@@ -356,6 +357,19 @@ EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT); ...@@ -356,6 +357,19 @@ EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT);
*/ */
void sdw_intel_exit(struct sdw_intel_ctx *ctx) void sdw_intel_exit(struct sdw_intel_ctx *ctx)
{ {
struct sdw_intel_link_res *link;
/* we first resume links and devices and wait synchronously before the cleanup */
list_for_each_entry(link, &ctx->link_list, list) {
struct sdw_bus *bus = &link->cdns->bus;
int ret;
ret = device_for_each_child(bus->dev, NULL, intel_resume_child_device);
if (ret < 0)
dev_err(bus->dev, "%s: intel_resume_child_device failed: %d\n",
__func__, ret);
}
sdw_intel_cleanup(ctx); sdw_intel_cleanup(ctx);
kfree(ctx->ids); kfree(ctx->ids);
kfree(ctx->ldev); kfree(ctx->ldev);
......
...@@ -905,6 +905,18 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl) ...@@ -905,6 +905,18 @@ static int qcom_swrm_init(struct qcom_swrm_ctrl *ctrl)
return 0; return 0;
} }
static int qcom_swrm_read_prop(struct sdw_bus *bus)
{
struct qcom_swrm_ctrl *ctrl = to_qcom_sdw(bus);
if (ctrl->version >= SWRM_VERSION_2_0_0) {
bus->multi_link = true;
bus->hw_sync_min_links = 3;
}
return 0;
}
static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus, static enum sdw_command_response qcom_swrm_xfer_msg(struct sdw_bus *bus,
struct sdw_msg *msg) struct sdw_msg *msg)
{ {
...@@ -1056,6 +1068,7 @@ static const struct sdw_master_port_ops qcom_swrm_port_ops = { ...@@ -1056,6 +1068,7 @@ static const struct sdw_master_port_ops qcom_swrm_port_ops = {
}; };
static const struct sdw_master_ops qcom_swrm_ops = { static const struct sdw_master_ops qcom_swrm_ops = {
.read_prop = qcom_swrm_read_prop,
.xfer_msg = qcom_swrm_xfer_msg, .xfer_msg = qcom_swrm_xfer_msg,
.pre_bank_switch = qcom_swrm_pre_bank_switch, .pre_bank_switch = qcom_swrm_pre_bank_switch,
}; };
...@@ -1173,6 +1186,15 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl, ...@@ -1173,6 +1186,15 @@ static int qcom_swrm_stream_alloc_ports(struct qcom_swrm_ctrl *ctrl,
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) {
/*
* For streams with multiple masters:
* Allocate ports only for devices connected to this master.
* Such devices will have ports allocated by their own master
* and its qcom_swrm_stream_alloc_ports() call.
*/
if (ctrl->bus.id != m_rt->bus->id)
continue;
if (m_rt->direction == SDW_DATA_DIR_RX) { if (m_rt->direction == SDW_DATA_DIR_RX) {
maxport = ctrl->num_dout_ports; maxport = ctrl->num_dout_ports;
port_mask = &ctrl->dout_port_mask; port_mask = &ctrl->dout_port_mask;
...@@ -1636,14 +1658,12 @@ static int qcom_swrm_probe(struct platform_device *pdev) ...@@ -1636,14 +1658,12 @@ static int qcom_swrm_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int qcom_swrm_remove(struct platform_device *pdev) static void qcom_swrm_remove(struct platform_device *pdev)
{ {
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev); struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(&pdev->dev);
sdw_bus_master_delete(&ctrl->bus); sdw_bus_master_delete(&ctrl->bus);
clk_disable_unprepare(ctrl->hclk); clk_disable_unprepare(ctrl->hclk);
return 0;
} }
static int __maybe_unused swrm_runtime_resume(struct device *dev) static int __maybe_unused swrm_runtime_resume(struct device *dev)
...@@ -1769,7 +1789,7 @@ MODULE_DEVICE_TABLE(of, qcom_swrm_of_match); ...@@ -1769,7 +1789,7 @@ MODULE_DEVICE_TABLE(of, qcom_swrm_of_match);
static struct platform_driver qcom_swrm_driver = { static struct platform_driver qcom_swrm_driver = {
.probe = &qcom_swrm_probe, .probe = &qcom_swrm_probe,
.remove = &qcom_swrm_remove, .remove_new = qcom_swrm_remove,
.driver = { .driver = {
.name = "qcom-soundwire", .name = "qcom-soundwire",
.of_match_table = qcom_swrm_of_match, .of_match_table = qcom_swrm_of_match,
......
...@@ -11,8 +11,10 @@ ...@@ -11,8 +11,10 @@
/* basic attributes to report status of Slave (attachment, dev_num) */ /* basic attributes to report status of Slave (attachment, dev_num) */
extern const struct attribute_group *sdw_slave_status_attr_groups[]; extern const struct attribute_group *sdw_slave_status_attr_groups[];
/* attributes for all soundwire devices */
extern const struct attribute_group *sdw_attr_groups[];
/* additional device-managed properties reported after driver probe */ /* additional device-managed properties reported after driver probe */
int sdw_slave_sysfs_init(struct sdw_slave *slave);
int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave); int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave);
#endif /* __SDW_SYSFS_LOCAL_H */ #endif /* __SDW_SYSFS_LOCAL_H */
...@@ -105,7 +105,10 @@ static struct attribute *slave_attrs[] = { ...@@ -105,7 +105,10 @@ static struct attribute *slave_attrs[] = {
&dev_attr_modalias.attr, &dev_attr_modalias.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(slave);
static const struct attribute_group slave_attr_group = {
.attrs = slave_attrs,
};
static struct attribute *slave_dev_attrs[] = { static struct attribute *slave_dev_attrs[] = {
&dev_attr_mipi_revision.attr, &dev_attr_mipi_revision.attr,
...@@ -126,10 +129,6 @@ static struct attribute *slave_dev_attrs[] = { ...@@ -126,10 +129,6 @@ static struct attribute *slave_dev_attrs[] = {
NULL, NULL,
}; };
/*
* we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory
* for device-level properties
*/
static const struct attribute_group sdw_slave_dev_attr_group = { static const struct attribute_group sdw_slave_dev_attr_group = {
.attrs = slave_dev_attrs, .attrs = slave_dev_attrs,
.name = "dev-properties", .name = "dev-properties",
...@@ -181,41 +180,38 @@ static struct attribute *dp0_attrs[] = { ...@@ -181,41 +180,38 @@ static struct attribute *dp0_attrs[] = {
NULL, NULL,
}; };
/* static umode_t dp0_attr_visible(struct kobject *kobj, struct attribute *attr,
* we don't use ATTRIBUTES_GROUP here since we want to add a subdirectory int n)
* for dp0-level properties
*/
static const struct attribute_group dp0_group = {
.attrs = dp0_attrs,
.name = "dp0",
};
int sdw_slave_sysfs_init(struct sdw_slave *slave)
{ {
int ret; struct sdw_slave *slave = dev_to_sdw_dev(kobj_to_dev(kobj));
ret = devm_device_add_groups(&slave->dev, slave_groups); if (slave->prop.dp0_prop)
if (ret < 0) return attr->mode;
return ret; return 0;
}
ret = devm_device_add_group(&slave->dev, &sdw_slave_dev_attr_group); static bool dp0_group_visible(struct kobject *kobj)
if (ret < 0) {
return ret; struct sdw_slave *slave = dev_to_sdw_dev(kobj_to_dev(kobj));
if (slave->prop.dp0_prop) { if (slave->prop.dp0_prop)
ret = devm_device_add_group(&slave->dev, &dp0_group); return true;
if (ret < 0) return false;
return ret; }
} DEFINE_SYSFS_GROUP_VISIBLE(dp0);
if (slave->prop.source_ports || slave->prop.sink_ports) { static const struct attribute_group dp0_group = {
ret = sdw_slave_sysfs_dpn_init(slave); .attrs = dp0_attrs,
if (ret < 0) .is_visible = SYSFS_GROUP_VISIBLE(dp0),
return ret; .name = "dp0",
} };
return 0; const struct attribute_group *sdw_attr_groups[] = {
} &slave_attr_group,
&sdw_slave_dev_attr_group,
&dp0_group,
NULL,
};
/* /*
* the status is shown in capital letters for UNATTACHED and RESERVED * the status is shown in capital letters for UNATTACHED and RESERVED
......
...@@ -283,6 +283,9 @@ int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave) ...@@ -283,6 +283,9 @@ int sdw_slave_sysfs_dpn_init(struct sdw_slave *slave)
int ret; int ret;
int i; int i;
if (!slave->prop.source_ports && !slave->prop.sink_ports)
return 0;
mask = slave->prop.source_ports; mask = slave->prop.source_ports;
for_each_set_bit(i, &mask, 32) { for_each_set_bit(i, &mask, 32) {
ret = add_all_attributes(&slave->dev, i, 1); ret = add_all_attributes(&slave->dev, i, 1);
......
...@@ -235,6 +235,7 @@ enum sdw_clk_stop_mode { ...@@ -235,6 +235,7 @@ enum sdw_clk_stop_mode {
* @BRA_flow_controlled: Slave implementation results in an OK_NotReady * @BRA_flow_controlled: Slave implementation results in an OK_NotReady
* response * response
* @simple_ch_prep_sm: If channel prepare sequence is required * @simple_ch_prep_sm: If channel prepare sequence is required
* @ch_prep_timeout: Port-specific timeout value, in milliseconds
* @imp_def_interrupts: If set, each bit corresponds to support for * @imp_def_interrupts: If set, each bit corresponds to support for
* implementation-defined interrupts * implementation-defined interrupts
* *
...@@ -249,6 +250,7 @@ struct sdw_dp0_prop { ...@@ -249,6 +250,7 @@ struct sdw_dp0_prop {
u32 *words; u32 *words;
bool BRA_flow_controlled; bool BRA_flow_controlled;
bool simple_ch_prep_sm; bool simple_ch_prep_sm;
u32 ch_prep_timeout;
bool imp_def_interrupts; bool imp_def_interrupts;
}; };
...@@ -542,21 +544,6 @@ enum sdw_reg_bank { ...@@ -542,21 +544,6 @@ enum sdw_reg_bank {
SDW_BANK1, SDW_BANK1,
}; };
/**
* struct sdw_bus_conf: Bus configuration
*
* @clk_freq: Clock frequency, in Hz
* @num_rows: Number of rows in frame
* @num_cols: Number of columns in frame
* @bank: Next register bank
*/
struct sdw_bus_conf {
unsigned int clk_freq;
unsigned int num_rows;
unsigned int num_cols;
unsigned int bank;
};
/** /**
* struct sdw_prepare_ch: Prepare/De-prepare Data Port channel * struct sdw_prepare_ch: Prepare/De-prepare Data Port channel
* *
...@@ -899,6 +886,7 @@ struct sdw_master_ops { ...@@ -899,6 +886,7 @@ struct sdw_master_ops {
* @port_ops: Master port callback ops * @port_ops: Master port callback ops
* @params: Current bus parameters * @params: Current bus parameters
* @prop: Master properties * @prop: Master properties
* @vendor_specific_prop: pointer to non-standard properties
* @m_rt_list: List of Master instance of all stream(s) running on Bus. This * @m_rt_list: List of Master instance of all stream(s) running on Bus. This
* is used to compute and program bus bandwidth, clock, frame shape, * is used to compute and program bus bandwidth, clock, frame shape,
* transport and port parameters * transport and port parameters
...@@ -933,6 +921,7 @@ struct sdw_bus { ...@@ -933,6 +921,7 @@ struct sdw_bus {
const struct sdw_master_port_ops *port_ops; const struct sdw_master_port_ops *port_ops;
struct sdw_bus_params params; struct sdw_bus_params params;
struct sdw_master_prop prop; struct sdw_master_prop prop;
void *vendor_specific_prop;
struct list_head m_rt_list; struct list_head m_rt_list;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs; struct dentry *debugfs;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
/* LCAP */ /* LCAP */
#define SDW_SHIM_LCAP 0x0 #define SDW_SHIM_LCAP 0x0
#define SDW_SHIM_LCAP_LCOUNT_MASK GENMASK(2, 0) #define SDW_SHIM_LCAP_LCOUNT_MASK GENMASK(2, 0)
#define SDW_SHIM_LCAP_MLCS_MASK BIT(8)
/* LCTL */ /* LCTL */
#define SDW_SHIM_LCTL 0x4 #define SDW_SHIM_LCTL 0x4
...@@ -30,12 +31,18 @@ ...@@ -30,12 +31,18 @@
#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)
#define SDW_SHIM_LCTL_MLCS_MASK GENMASK(29, 27)
#define SDW_SHIM_MLCS_XTAL_CLK 0x0
#define SDW_SHIM_MLCS_CARDINAL_CLK 0x1
#define SDW_SHIM_MLCS_AUDIO_PLL_CLK 0x2
/* SYNC */ /* SYNC */
#define SDW_SHIM_SYNC 0xC #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_24_576 (24576 / 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_96 (96000 / SDW_CADENCE_GSYNC_KHZ - 1)
#define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0) #define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0)
#define SDW_SHIM_SYNC_SYNCCPU BIT(15) #define SDW_SHIM_SYNC_SYNCCPU BIT(15)
#define SDW_SHIM_SYNC_CMDSYNC_MASK GENMASK(19, 16) #define SDW_SHIM_SYNC_CMDSYNC_MASK GENMASK(19, 16)
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#define SDW_REG_NO_PAGE 0x00008000 #define SDW_REG_NO_PAGE 0x00008000
#define SDW_REG_OPTIONAL_PAGE 0x00010000 #define SDW_REG_OPTIONAL_PAGE 0x00010000
#define SDW_REG_MAX 0x80000000 #define SDW_REG_MAX 0x48000000
#define SDW_DPN_SIZE 0x100 #define SDW_DPN_SIZE 0x100
#define SDW_BANK1_OFFSET 0x10 #define SDW_BANK1_OFFSET 0x10
......
...@@ -246,12 +246,12 @@ static int hda_sdw_exit(struct snd_sof_dev *sdev) ...@@ -246,12 +246,12 @@ static int hda_sdw_exit(struct snd_sof_dev *sdev)
hdev = sdev->pdata->hw_pdata; hdev = sdev->pdata->hw_pdata;
hda_sdw_int_enable(sdev, false);
if (hdev->sdw) if (hdev->sdw)
sdw_intel_exit(hdev->sdw); sdw_intel_exit(hdev->sdw);
hdev->sdw = NULL; hdev->sdw = NULL;
hda_sdw_int_enable(sdev, false);
return 0; return 0;
} }
......
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