/* * HDMI2.1 spec defines 6- and 12-channels layout for one bit audio * stream. Todo: to check how this case can be considered below
*/ staticconst u32 fsl_xcvr_earc_channels[] = { 1, 2, 8, 16, 32, }; staticconststruct snd_pcm_hw_constraint_list fsl_xcvr_earc_channels_constr = {
.count = ARRAY_SIZE(fsl_xcvr_earc_channels),
.list = fsl_xcvr_earc_channels,
};
switch (xcvr->mode) { case FSL_XCVR_MODE_SPDIF: if (xcvr->soc_data->spdif_only && tx) {
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM,
FSL_XCVR_TX_DPTH_CTRL_BYPASS_FEM); if (ret < 0) {
dev_err(dai->dev, "Failed to set bypass fem: %d\n", ret); return ret;
}
}
fallthrough; case FSL_XCVR_MODE_ARC: if (tx) {
ret = fsl_xcvr_en_aud_pll(xcvr, fout); if (ret < 0) {
dev_err(dai->dev, "Failed to set TX freq %u: %d\n",
fout, ret); return ret;
}
ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_FRM_FMT); if (ret < 0) {
dev_err(dai->dev, "Failed to set TX_DPTH: %d\n", ret); return ret;
}
/** * set SPDIF MODE - this flag is used to gate * SPDIF output, useless for SPDIF RX
*/
m_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
v_ctl |= FSL_XCVR_EXT_CTRL_SPDIF_MODE;
} else { /** * Clear RX FIFO, flip RX FIFO bits, * disable eARC related HW mode detects
*/
ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO |
FSL_XCVR_RX_DPTH_CTRL_COMP |
FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL); if (ret < 0) {
dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret); return ret;
}
ret = fsl_xcvr_en_phy_pll(xcvr, FSL_XCVR_SPDIF_RX_FREQ, tx); if (ret < 0) {
dev_err(dai->dev, "Failed to set RX freq %u: %d\n",
FSL_XCVR_SPDIF_RX_FREQ, ret); return ret;
}
} break; case FSL_XCVR_MODE_EARC: if (!tx) { /** Clear RX FIFO, flip RX FIFO bits */
ret = regmap_set_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
FSL_XCVR_RX_DPTH_CTRL_STORE_FMT |
FSL_XCVR_RX_DPTH_CTRL_CLR_RX_FIFO); if (ret < 0) {
dev_err(dai->dev, "Failed to set RX_DPTH: %d\n", ret); return ret;
}
/** Enable eARC related HW mode detects */
ret = regmap_clear_bits(xcvr->regmap, FSL_XCVR_RX_DPTH_CTRL,
FSL_XCVR_RX_DPTH_CTRL_COMP |
FSL_XCVR_RX_DPTH_CTRL_LAYB_CTRL); if (ret < 0) {
dev_err(dai->dev, "Failed to clr TX_DPTH: %d\n", ret); return ret;
}
}
/* * EDMA controller needs period size to be a multiple of * tx/rx maxburst
*/ if (xcvr->soc_data->use_edma)
snd_pcm_hw_constraint_step(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
tx ? xcvr->dma_prms_tx.maxburst :
xcvr->dma_prms_rx.maxburst);
switch (xcvr->mode) { case FSL_XCVR_MODE_SPDIF: case FSL_XCVR_MODE_ARC: if (xcvr->soc_data->spdif_only && tx)
ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
&xcvr->spdif_constr_rates); else
ret = fsl_xcvr_constr(substream, &fsl_xcvr_spdif_channels_constr,
&fsl_xcvr_spdif_rates_constr); break; case FSL_XCVR_MODE_EARC:
ret = fsl_xcvr_constr(substream, &fsl_xcvr_earc_channels_constr,
&fsl_xcvr_earc_rates_constr); break;
} if (ret < 0) return ret;
xcvr->streams |= BIT(substream->stream);
if (!xcvr->soc_data->spdif_only) { struct snd_soc_card *card = dai->component->card;
/* Disable XCVR controls if there is stream started */
down_read(&card->snd_card->controls_rwsem);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name, false);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name, false);
up_read(&card->snd_card->controls_rwsem);
}
/* Enable XCVR controls if there is no stream started */ if (!xcvr->streams) { if (!xcvr->soc_data->spdif_only) { struct snd_soc_card *card = dai->component->card;
down_read(&card->snd_card->controls_rwsem);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_mode_kctl.name, true);
fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_ARC));
fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
(xcvr->mode == FSL_XCVR_MODE_EARC));
up_read(&card->snd_card->controls_rwsem);
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) {
dev_err(dai->dev, "Failed to set IER0: %d\n", ret); return;
}
staticint fsl_xcvr_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
{ struct fsl_xcvr *xcvr = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsignedlong lock_flags; int ret = 0;
spin_lock_irqsave(&xcvr->lock, lock_flags);
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* set DPATH RESET */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx)); if (ret < 0) {
dev_err(dai->dev, "Failed to set DPATH RESET: %d\n", ret); goto release_lock;
}
if (tx) { switch (xcvr->mode) { case FSL_XCVR_MODE_EARC: /* set isr_cmdc_tx_en, w1c */
ret = regmap_write(xcvr->regmap,
FSL_XCVR_ISR_SET,
FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) {
dev_err(dai->dev, "err updating isr %d\n", ret); goto release_lock;
}
fallthrough; case FSL_XCVR_MODE_SPDIF:
ret = regmap_set_bits(xcvr->regmap,
FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) {
dev_err(dai->dev, "Failed to start DATA_TX: %d\n", ret); goto release_lock;
} break;
}
}
/* enable DMA RD/WR */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx), 0); if (ret < 0) {
dev_err(dai->dev, "Failed to enable DMA: %d\n", ret); goto release_lock;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, FSL_XCVR_IRQ_EARC_ALL); if (ret < 0) {
dev_err(dai->dev, "Error while setting IER0: %d\n", ret); goto release_lock;
}
/* clear DPATH RESET */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DPTH_RESET(tx),
0); if (ret < 0) {
dev_err(dai->dev, "Failed to clear DPATH RESET: %d\n", ret); goto release_lock;
}
break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* disable DMA RD/WR */
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_DMA_DIS(tx),
FSL_XCVR_EXT_CTRL_DMA_DIS(tx)); if (ret < 0) {
dev_err(dai->dev, "Failed to disable DMA: %d\n", ret); goto release_lock;
}
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_IER0,
FSL_XCVR_IRQ_EARC_ALL, 0); if (ret < 0) {
dev_err(dai->dev, "Failed to clear IER0: %d\n", ret); goto release_lock;
}
if (tx) { switch (xcvr->mode) { case FSL_XCVR_MODE_SPDIF:
ret = regmap_clear_bits(xcvr->regmap,
FSL_XCVR_TX_DPTH_CTRL,
FSL_XCVR_TX_DPTH_CTRL_STRT_DATA_TX); if (ret < 0) {
dev_err(dai->dev, "Failed to stop DATA_TX: %d\n", ret); goto release_lock;
} if (xcvr->soc_data->spdif_only) break; else
fallthrough; case FSL_XCVR_MODE_EARC: /* clear ISR_CMDC_TX_EN, W1C */
ret = regmap_write(xcvr->regmap,
FSL_XCVR_ISR_CLR,
FSL_XCVR_ISR_CMDC_TX_EN); if (ret < 0) {
dev_err(dai->dev, "Err updating ISR %d\n", ret); goto release_lock;
} break;
}
} break; default:
ret = -EINVAL; break;
}
ret = request_firmware(&fw, xcvr->soc_data->fw_name, dev); if (ret) {
dev_err(dev, "failed to request firmware.\n"); return ret;
}
rem = fw->size;
/* RAM is 20KiB = 16KiB code + 4KiB data => max 10 pages 2KiB each */ if (rem > 16384) {
dev_err(dev, "FW size %d is bigger than 16KiB.\n", rem);
release_firmware(fw); return -ENOMEM;
}
for (page = 0; page < 10; page++) {
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
FSL_XCVR_EXT_CTRL_PAGE(page)); if (ret < 0) {
dev_err(dev, "FW: failed to set page %d, err=%d\n",
page, ret); goto err_firmware;
}
off = page * size;
out = min(rem, size); /* IPG clock is assumed to be running, otherwise it will hang */ if (out > 0) { /* write firmware into code memory */
memcpy_toio(xcvr->ram_addr, fw->data + off, out);
rem -= out; if (rem == 0) { /* last part of firmware written */ /* clean remaining part of code memory page */
memset_io(xcvr->ram_addr + out, 0, size - out);
}
} else { /* clean current page, including data memory */
memset_io(xcvr->ram_addr, 0, size);
}
}
err_firmware:
release_firmware(fw); if (ret < 0) return ret;
/* configure watermarks */
mask = FSL_XCVR_EXT_CTRL_RX_FWM_MASK | FSL_XCVR_EXT_CTRL_TX_FWM_MASK;
val = FSL_XCVR_EXT_CTRL_RX_FWM(FSL_XCVR_FIFO_WMK_RX);
val |= FSL_XCVR_EXT_CTRL_TX_FWM(FSL_XCVR_FIFO_WMK_TX); /* disable DMA RD/WR */
mask |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS;
val |= FSL_XCVR_EXT_CTRL_DMA_RD_DIS | FSL_XCVR_EXT_CTRL_DMA_WR_DIS; /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
mask |= FSL_XCVR_EXT_CTRL_PAGE_MASK;
val |= FSL_XCVR_EXT_CTRL_PAGE(8);
ret = regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL, mask, val); if (ret < 0) {
dev_err(dev, "Failed to set watermarks: %d\n", ret); return ret;
}
/* Store Capabilities Data Structure into Data RAM */
memcpy_toio(xcvr->ram_addr + FSL_XCVR_CAP_DATA_STR, xcvr->cap_ds,
FSL_XCVR_CAPDS_SIZE); return 0;
}
if (!xcvr->soc_data->use_phy) if ((reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) ||
reg > FSL_XCVR_TX_DPTH_BCRR) returnfalse; switch (reg) { case FSL_XCVR_VERSION: case FSL_XCVR_EXT_CTRL: case FSL_XCVR_EXT_STATUS: case FSL_XCVR_EXT_IER0: case FSL_XCVR_EXT_IER1: case FSL_XCVR_EXT_ISR: case FSL_XCVR_EXT_ISR_SET: case FSL_XCVR_EXT_ISR_CLR: case FSL_XCVR_EXT_ISR_TOG: case FSL_XCVR_IER: case FSL_XCVR_ISR: case FSL_XCVR_ISR_SET: case FSL_XCVR_ISR_CLR: case FSL_XCVR_ISR_TOG: case FSL_XCVR_PHY_AI_CTRL: case FSL_XCVR_PHY_AI_CTRL_SET: case FSL_XCVR_PHY_AI_CTRL_CLR: case FSL_XCVR_PHY_AI_CTRL_TOG: case FSL_XCVR_PHY_AI_RDATA: case FSL_XCVR_CLK_CTRL: case FSL_XCVR_RX_DPTH_CTRL: case FSL_XCVR_RX_DPTH_CTRL_SET: case FSL_XCVR_RX_DPTH_CTRL_CLR: case FSL_XCVR_RX_DPTH_CTRL_TOG: case FSL_XCVR_RX_CS_DATA_0: case FSL_XCVR_RX_CS_DATA_1: case FSL_XCVR_RX_CS_DATA_2: case FSL_XCVR_RX_CS_DATA_3: case FSL_XCVR_RX_CS_DATA_4: case FSL_XCVR_RX_CS_DATA_5: case FSL_XCVR_RX_DPTH_CNTR_CTRL: case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_RX_DPTH_TSCR: case FSL_XCVR_RX_DPTH_BCR: case FSL_XCVR_RX_DPTH_BCTR: case FSL_XCVR_RX_DPTH_BCRR: case FSL_XCVR_TX_DPTH_CTRL: case FSL_XCVR_TX_DPTH_CTRL_SET: case FSL_XCVR_TX_DPTH_CTRL_CLR: case FSL_XCVR_TX_DPTH_CTRL_TOG: case FSL_XCVR_TX_CS_DATA_0: case FSL_XCVR_TX_CS_DATA_1: case FSL_XCVR_TX_CS_DATA_2: case FSL_XCVR_TX_CS_DATA_3: case FSL_XCVR_TX_CS_DATA_4: case FSL_XCVR_TX_CS_DATA_5: case FSL_XCVR_TX_DPTH_CNTR_CTRL: case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_TX_DPTH_TSCR: case FSL_XCVR_TX_DPTH_BCR: case FSL_XCVR_TX_DPTH_BCTR: case FSL_XCVR_TX_DPTH_BCRR: case FSL_XCVR_DEBUG_REG_0: case FSL_XCVR_DEBUG_REG_1: returntrue; default: returnfalse;
}
}
if (!xcvr->soc_data->use_phy) if (reg >= FSL_XCVR_IER && reg <= FSL_XCVR_PHY_AI_RDATA) returnfalse; switch (reg) { case FSL_XCVR_EXT_CTRL: case FSL_XCVR_EXT_IER0: case FSL_XCVR_EXT_IER1: case FSL_XCVR_EXT_ISR: case FSL_XCVR_EXT_ISR_SET: case FSL_XCVR_EXT_ISR_CLR: case FSL_XCVR_EXT_ISR_TOG: case FSL_XCVR_IER: case FSL_XCVR_ISR_SET: case FSL_XCVR_ISR_CLR: case FSL_XCVR_ISR_TOG: case FSL_XCVR_PHY_AI_CTRL: case FSL_XCVR_PHY_AI_CTRL_SET: case FSL_XCVR_PHY_AI_CTRL_CLR: case FSL_XCVR_PHY_AI_CTRL_TOG: case FSL_XCVR_PHY_AI_WDATA: case FSL_XCVR_CLK_CTRL: case FSL_XCVR_RX_DPTH_CTRL: case FSL_XCVR_RX_DPTH_CTRL_SET: case FSL_XCVR_RX_DPTH_CTRL_CLR: case FSL_XCVR_RX_DPTH_CTRL_TOG: case FSL_XCVR_RX_DPTH_CNTR_CTRL: case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_TX_DPTH_CTRL: case FSL_XCVR_TX_DPTH_CTRL_SET: case FSL_XCVR_TX_DPTH_CTRL_CLR: case FSL_XCVR_TX_DPTH_CTRL_TOG: case FSL_XCVR_TX_CS_DATA_0: case FSL_XCVR_TX_CS_DATA_1: case FSL_XCVR_TX_CS_DATA_2: case FSL_XCVR_TX_CS_DATA_3: case FSL_XCVR_TX_CS_DATA_4: case FSL_XCVR_TX_CS_DATA_5: case FSL_XCVR_TX_DPTH_CNTR_CTRL: case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG: returntrue; default: returnfalse;
}
}
staticbool fsl_xcvr_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case FSL_XCVR_EXT_STATUS: case FSL_XCVR_EXT_ISR: case FSL_XCVR_EXT_ISR_SET: case FSL_XCVR_EXT_ISR_CLR: case FSL_XCVR_EXT_ISR_TOG: case FSL_XCVR_ISR: case FSL_XCVR_ISR_SET: case FSL_XCVR_ISR_CLR: case FSL_XCVR_ISR_TOG: case FSL_XCVR_PHY_AI_CTRL: case FSL_XCVR_PHY_AI_CTRL_SET: case FSL_XCVR_PHY_AI_CTRL_CLR: case FSL_XCVR_PHY_AI_CTRL_TOG: case FSL_XCVR_PHY_AI_RDATA: case FSL_XCVR_RX_CS_DATA_0: case FSL_XCVR_RX_CS_DATA_1: case FSL_XCVR_RX_CS_DATA_2: case FSL_XCVR_RX_CS_DATA_3: case FSL_XCVR_RX_CS_DATA_4: case FSL_XCVR_RX_CS_DATA_5: case FSL_XCVR_RX_DPTH_CNTR_CTRL: case FSL_XCVR_RX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_RX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_RX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_RX_DPTH_TSCR: case FSL_XCVR_RX_DPTH_BCR: case FSL_XCVR_RX_DPTH_BCTR: case FSL_XCVR_RX_DPTH_BCRR: case FSL_XCVR_TX_DPTH_CNTR_CTRL: case FSL_XCVR_TX_DPTH_CNTR_CTRL_SET: case FSL_XCVR_TX_DPTH_CNTR_CTRL_CLR: case FSL_XCVR_TX_DPTH_CNTR_CTRL_TOG: case FSL_XCVR_TX_DPTH_TSCR: case FSL_XCVR_TX_DPTH_BCR: case FSL_XCVR_TX_DPTH_BCTR: case FSL_XCVR_TX_DPTH_BCRR: case FSL_XCVR_DEBUG_REG_0: case FSL_XCVR_DEBUG_REG_1: returntrue; default: returnfalse;
}
}
if (isr & FSL_XCVR_IRQ_NEW_CS) {
dev_dbg(dev, "Received new CS block\n");
isr_clr |= FSL_XCVR_IRQ_NEW_CS; if (xcvr->soc_data->fw_name) { /* Data RAM is 4KiB, last two pages: 8 and 9. Select page 8. */
regmap_update_bits(xcvr->regmap, FSL_XCVR_EXT_CTRL,
FSL_XCVR_EXT_CTRL_PAGE_MASK,
FSL_XCVR_EXT_CTRL_PAGE(8));
/* * Register platform component before registering cpu dai for there * is not defer probe for platform component in snd_soc_add_pcm_runtime().
*/
ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); if (ret) {
pm_runtime_disable(dev);
dev_err(dev, "failed to pcm register\n"); return ret;
}
ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp,
&fsl_xcvr_dai, 1); if (ret) {
pm_runtime_disable(dev);
dev_err(dev, "failed to register component %s\n",
fsl_xcvr_comp.name);
}
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.