/* * the value 10 is the number of PDIs. We will need a * cleanup to remove hard-coded Intel configurations * from cadence_master.c
*/ for (j = 0; j < 10; j++) {
ret += intel_sprintf(s, false, buf, ret,
SDW_SHIM_PCMSYCHM(i, j));
ret += intel_sprintf(s, false, buf, ret,
SDW_SHIM_PCMSYCHC(i, j));
}
ret += scnprintf(buf + ret, RD_BUF - ret, "\n IOCTL, CTMCTL\n");
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
}
ret += scnprintf(buf + ret, RD_BUF - ret, "\nWake registers\n");
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);
ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);
ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH STRMzCFG\n"); for (i = 0; i < SDW_ALH_NUM_STREAMS; i++)
ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
/* at this point Master IP has full control of the I/Os */
}
/* this needs to be called with shim_lock */ staticvoid intel_shim_master_ip_to_glue(struct sdw_intel *sdw)
{ unsignedint link_id = sdw->instance; void __iomem *shim = sdw->link_res->shim;
u16 ioctl;
/* * 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+). On MeteorLake additional * frequencies are available with the MLCS clock source selection.
*/
lcap_mlcs = intel_readl(shim, SDW_SHIM_LCAP) & SDW_SHIM_LCAP_MLCS_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;
}
/* 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);
}
}
ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); if (ret < 0) {
dev_err(sdw->cdns.dev, "%s: could not power down link\n", __func__);
/* * we leave the sdw->cdns.link_up flag as false since we've disabled * the link at this point and cannot handle interrupts any longer.
*/
}
}
/* * Set SyncGO bit to synchronously trigger a bank switch for * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all * the Masters.
*/
sync_reg |= SDW_SHIM_SYNC_SYNCGO;
intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
return 0;
}
staticint intel_shim_sync_go(struct sdw_intel *sdw)
{ int ret;
/* * WORKAROUND: on all existing Intel controllers, pdi * number 2 reports channel count as 1 even though it * supports 8 channels. Performing hardcoding for pdi * number 2.
*/ if (pdi_num == 2)
count = 7;
/* zero based values for channel count in register */
count++;
return count;
}
staticint intel_pdi_get_ch_update(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi, unsignedint num_pdi, unsignedint *num_ch)
{ int i, ch_count = 0;
for (i = 0; i < num_pdi; i++) {
pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num);
ch_count += pdi->ch_count;
pdi++;
}
/* do run-time configurations for SHIM, ALH and PDI/PORT */
intel_pdi_shim_configure(sdw, pdi);
intel_pdi_alh_configure(sdw, pdi);
sdw_cdns_config_stream(cdns, ch, dir, pdi);
/* store pdi and hw_params, may be needed in prepare step */
dai_runtime->paused = false;
dai_runtime->suspended = false;
dai_runtime->pdi = pdi;
/* Inform DSP about PDI stream number */
ret = intel_params_stream(sdw, substream, dai, params,
sdw->instance,
pdi->intel_alh_id); if (ret) return ret;
/* * .prepare() is called after system resume, where we * need to reinitialize the SHIM/ALH/Cadence IP. * .prepare() is also called to deal with underflows, * but in those cases we cannot touch ALH/SHIM * registers
*/
/* configure stream */
ch = params_channels(hw_params); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
dir = SDW_DATA_DIR_RX; else
dir = SDW_DATA_DIR_TX;
dai_runtime = cdns->dai_runtime_array[dai->id]; if (!dai_runtime) return -EIO;
/* * The sdw stream state will transition to RELEASED when stream-> * master_list is empty. So the stream state will transition to * DEPREPARED for the first cpu-dai and to RELEASED for the last * cpu-dai.
*/
ret = sdw_stream_remove_master(&cdns->bus, dai_runtime->stream); if (ret < 0) {
dev_err(dai->dev, "remove master from stream %s failed: %d\n",
dai_runtime->stream->name, 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 = cdns->dai_runtime_array[dai->id]; if (!dai_runtime) return ERR_PTR(-EINVAL);
return dai_runtime->stream;
}
staticint intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{ struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); struct sdw_cdns_dai_runtime *dai_runtime; int ret = 0;
dai_runtime = cdns->dai_runtime_array[dai->id]; if (!dai_runtime) {
dev_err(dai->dev, "failed to get dai runtime in %s\n",
__func__); return -EIO;
}
switch (cmd) { case SNDRV_PCM_TRIGGER_SUSPEND:
/* * The .prepare callback is used to deal with xruns and resume operations. * In the case of xruns, the DMAs and SHIM registers cannot be touched, * but for resume operations the DMAs and SHIM registers need to be initialized. * the .trigger callback is used to track the suspend case only.
*/
dai_runtime->suspended = true;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
dai_runtime->paused = true; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
dai_runtime->paused = false; break; default: break;
}
return ret;
}
staticint intel_component_probe(struct snd_soc_component *component)
{ int ret;
/* * make sure the device is pm_runtime_active before initiating * bus transactions during the card registration. * We use pm_runtime_resume() here, without taking a reference * and releasing it immediately.
*/
ret = pm_runtime_resume(component->dev); if (ret < 0 && ret != -EACCES) return ret;
/* * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state. * Since the component suspend is called last, we can trap this corner case * and force the DAIs to release their resources.
*/
for_each_component_dais(component, dai) { struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai); struct sdw_cdns_dai_runtime *dai_runtime;
dai_runtime = cdns->dai_runtime_array[dai->id];
if (!dai_runtime) continue;
if (dai_runtime->suspended) continue;
if (dai_runtime->paused)
dai_runtime->suspended = true;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.14Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.