aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch')
-rw-r--r--target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch326
1 files changed, 326 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch b/target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch
new file mode 100644
index 0000000000..033ab0d06b
--- /dev/null
+++ b/target/linux/layerscape/patches-5.4/801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch
@@ -0,0 +1,326 @@
+From 87f734fa8214b4ddbfdac9b7ac5dc75a3d86badb Mon Sep 17 00:00:00 2001
+From: Shengjiu Wang <shengjiu.wang@nxp.com>
+Date: Tue, 23 Jan 2018 13:26:37 +0800
+Subject: [PATCH] MLK-16224-4: ASoC: fsl_sai: support multi fifo and DSD
+
+The codec always mux the LRCLK pin to DSD data line, so when
+we want to support DSD, the pinmux is different. For two channel
+DSD, the DSDL is mapped to TX0, but the DSDR is mapped to TX4,
+there is address offset for the fifo address of TX0 and TX4, TX4's
+fifo is not adjacent to TX0's.
+
+Usually, if mapping is TX0 and TX1, that will be easy for SAI
+and SDMA to handle, that SAI can use the FIFO combine mode, SDMA
+can use the normal script.
+
+so for DSD:
+1. The SDMA should use the multi-fifo script, and SAI can't
+use the FIFO combine mode.
+2. driver should to check the dts configuration(fsl,dataline) for
+which dataline is used corrently
+3. maxburst is the multiply of datalines
+4. each channel of DSD occupy one data lane
+5. according to data lane, set TRCE bits
+
+Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
+Reviewed-by: Viorel Suman <viorel.suman@nxp.com>
+---
+ sound/soc/fsl/fsl_sai.c | 162 +++++++++++++++++++++++++++++++++++++++++++++---
+ sound/soc/fsl/fsl_sai.h | 12 +++-
+ 2 files changed, 164 insertions(+), 10 deletions(-)
+
+--- a/sound/soc/fsl/fsl_sai.c
++++ b/sound/soc/fsl/fsl_sai.c
+@@ -267,6 +267,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
+ if (!sai->is_lsb_first)
+ val_cr4 |= FSL_SAI_CR4_MF;
+
++ sai->is_dsp_mode = false;
+ /* DAI mode */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+@@ -305,6 +306,11 @@ static int fsl_sai_set_dai_fmt_tr(struct
+ val_cr2 |= FSL_SAI_CR2_BCP;
+ sai->is_dsp_mode = true;
+ break;
++ case SND_SOC_DAIFMT_PDM:
++ val_cr2 |= FSL_SAI_CR2_BCP;
++ val_cr4 &= ~FSL_SAI_CR4_MF;
++ sai->is_dsp_mode = true;
++ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ /* To be done */
+ default:
+@@ -492,12 +498,38 @@ static int fsl_sai_hw_params(struct snd_
+ u32 slot_width = word_width;
+ u32 pins;
+ int ret;
++ int i;
++ int trce_mask = 0;
++ snd_pcm_format_t format = params_format(params);
+
+ if (sai->slots)
+ slots = sai->slots;
+
+ pins = DIV_ROUND_UP(channels, slots);
+
++ if (format == SNDRV_PCM_FORMAT_DSD_U8 ||
++ format == SNDRV_PCM_FORMAT_DSD_U16_LE ||
++ format == SNDRV_PCM_FORMAT_DSD_U16_BE ||
++ format == SNDRV_PCM_FORMAT_DSD_U32_LE ||
++ format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
++ sai->is_dsd = true;
++
++ if (!IS_ERR_OR_NULL(sai->pins_dsd)) {
++ ret = pinctrl_select_state(sai->pinctrl, sai->pins_dsd);
++ if (ret) {
++ dev_err(cpu_dai->dev,
++ "failed to set proper pins state: %d\n", ret);
++ return ret;
++ }
++ }
++ } else {
++ pinctrl_pm_select_default_state(cpu_dai->dev);
++ sai->is_dsd = false;
++ }
++
++ if (sai->is_dsd)
++ pins = channels;
++
+ if (sai->slot_width)
+ slot_width = sai->slot_width;
+
+@@ -527,7 +559,7 @@ static int fsl_sai_hw_params(struct snd_
+ val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
+ val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
+
+- if (sai->is_lsb_first)
++ if (sai->is_lsb_first || sai->is_dsd)
+ val_cr5 |= FSL_SAI_CR5_FBT(0);
+ else
+ val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
+@@ -560,17 +592,71 @@ static int fsl_sai_hw_params(struct snd_
+ }
+
+ if (sai->soc->dataline != 0x1) {
+- if (sai->dataline[tx] <= 1)
++
++ if (sai->dataline[tx] <= 1 || sai->is_multi_lane)
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+ FSL_SAI_CR4_FCOMB_MASK, 0);
+ else
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+ FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
++
++ if (sai->is_multi_lane) {
++ if (tx) {
++ sai->dma_params_tx.maxburst =
++ FSL_SAI_MAXBURST_TX * pins;
++ if (sai->is_dsd)
++ sai->dma_params_tx.fifo_num = pins +
++ (sai->dataline_off_dsd[tx] << 8);
++ else
++ sai->dma_params_tx.fifo_num = pins +
++ (sai->dataline_off[tx] << 8);
++ } else {
++ sai->dma_params_rx.maxburst =
++ FSL_SAI_MAXBURST_RX * pins;
++ if (sai->is_dsd)
++ sai->dma_params_rx.fifo_num = pins +
++ (sai->dataline_off_dsd[tx] << 8);
++ else
++ sai->dma_params_rx.fifo_num = pins +
++ (sai->dataline_off[tx] << 8);
++ }
++ }
++
++ snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
++ &sai->dma_params_rx);
+ }
+
+- regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++ if (sai->is_dsd) {
++ if (__sw_hweight8(sai->dataline_dsd[tx] & 0xFF) < pins) {
++ dev_err(cpu_dai->dev, "channel not supported\n");
++ return -EINVAL;
++ }
++ /*find a proper tcre setting*/
++ for (i = 0; i < 8; i++) {
++ trce_mask = (1 << (i + 1)) - 1;
++ if (__sw_hweight8(sai->dataline_dsd[tx] & trce_mask) == pins)
++ break;
++ }
++
++ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
+ FSL_SAI_CR3_TRCE_MASK,
+- FSL_SAI_CR3_TRCE((sai->dataline[tx] & ((1 << pins) - 1))));
++ FSL_SAI_CR3_TRCE((sai->dataline_dsd[tx] & trce_mask)));
++ } else {
++ if (__sw_hweight8(sai->dataline[tx] & 0xFF) < pins) {
++ dev_err(cpu_dai->dev, "channel not supported\n");
++ return -EINVAL;
++ }
++ /*find a proper tcre setting*/
++ for (i = 0; i < 8; i++) {
++ trce_mask = (1 << (i + 1)) - 1;
++ if (__sw_hweight8(sai->dataline[tx] & trce_mask) == pins)
++ break;
++ }
++
++ regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
++ FSL_SAI_CR3_TRCE_MASK,
++ FSL_SAI_CR3_TRCE((sai->dataline[tx] & trce_mask)));
++ }
+
+ regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
+ FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
+@@ -610,9 +696,18 @@ static int fsl_sai_trigger(struct snd_pc
+ unsigned char offset = sai->soc->reg_offset;
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ u8 channels = substream->runtime->channels;
++ u32 slots = (channels == 1) ? 2 : channels;
+ u32 xcsr, count = 100;
+- int i;
++ u32 pins;
++ int i = 0, j = 0, k = 0;
++
++ if (sai->slots)
++ slots = sai->slots;
++
++ pins = DIV_ROUND_UP(channels, slots);
+
++ if (sai->is_dsd)
++ pins = channels;
+ /*
+ * Asynchronous mode: Clear SYNC for both Tx and Rx.
+ * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
+@@ -631,10 +726,19 @@ static int fsl_sai_trigger(struct snd_pc
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+- for (i = 0; tx && i < channels; i++)
+- regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0);
+- if (tx)
+- udelay(10);
++
++ for (i = 0; tx && i < channels; i++) {
++ while (tx && i < channels)
++ if (sai->dataline[tx] & (1 << j)) {
++ regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
++ i++;
++ k++;
++ }
++ j++;
++
++ if (k%pins == 0)
++ j = 0;
++ }
+
+ regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
+ FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
+@@ -994,6 +1098,7 @@ static int fsl_sai_probe(struct platform
+ char tmp[8];
+ int irq, ret, i;
+ int index;
++ int firstbitidx, nextbitidx;
+ struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
+ unsigned long irqflags = 0;
+
+@@ -1048,6 +1153,9 @@ static int fsl_sai_probe(struct platform
+ }
+ }
+
++ if (of_find_property(np, "fsl,sai-multi-lane", NULL))
++ sai->is_multi_lane = true;
++
+ /*dataline mask for rx and tx*/
+ ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
+ if (ret)
+@@ -1062,6 +1170,37 @@ static int fsl_sai_probe(struct platform
+ return -EINVAL;
+ }
+
++ for (i = 0; i < 2; i++) {
++ firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8);
++ nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1);
++ sai->dataline_off[i] = nextbitidx - firstbitidx - 1;
++
++ if (sai->dataline_off[i] < 0 || sai->dataline_off[i] >= 7)
++ sai->dataline_off[i] = 0;
++ }
++
++ ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]);
++ if (ret)
++ sai->dataline_dsd[0] = 1;
++
++ ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 1, &sai->dataline_dsd[1]);
++ if (ret)
++ sai->dataline_dsd[1] = 1;
++
++ if ((sai->dataline_dsd[0] & (~sai->soc->dataline)) || sai->dataline_dsd[1] & (~sai->soc->dataline)) {
++ dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < 2; i++) {
++ firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8);
++ nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1);
++ sai->dataline_off_dsd[i] = nextbitidx - firstbitidx - 1;
++
++ if (sai->dataline_off_dsd[i] < 0 || sai->dataline_off_dsd[i] >= 7)
++ sai->dataline_off_dsd[i] = 0;
++ }
++
+ if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
+ (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
+ {
+@@ -1143,6 +1282,11 @@ static int fsl_sai_probe(struct platform
+ sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
+ sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
+
++ sai->pinctrl = devm_pinctrl_get(&pdev->dev);
++
++ if (!IS_ERR_OR_NULL(sai->pinctrl))
++ sai->pins_dsd = pinctrl_lookup_state(sai->pinctrl, "dsd");
++
+ platform_set_drvdata(pdev, sai);
+
+ pm_runtime_enable(&pdev->dev);
+--- a/sound/soc/fsl/fsl_sai.h
++++ b/sound/soc/fsl/fsl_sai.h
+@@ -11,7 +11,10 @@
+
+ #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S24_LE |\
+- SNDRV_PCM_FMTBIT_S32_LE)
++ SNDRV_PCM_FMTBIT_S32_LE |\
++ SNDRV_PCM_FMTBIT_DSD_U8 |\
++ SNDRV_PCM_FMTBIT_DSD_U16_LE |\
++ SNDRV_PCM_FMTBIT_DSD_U32_LE)
+
+ /* SAI Register Map Register */
+ #define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
+@@ -172,9 +175,14 @@ struct fsl_sai {
+ bool slave_mode[2];
+ bool is_lsb_first;
+ bool is_dsp_mode;
++ bool is_multi_lane;
+ bool synchronous[2];
+ bool is_stream_opened[2];
++ bool is_dsd;
+ unsigned int dataline[2];
++ unsigned int dataline_dsd[2];
++ unsigned int dataline_off[2];
++ unsigned int dataline_off_dsd[2];
+ unsigned int masterflag[2];
+
+ unsigned int mclk_id[2];
+@@ -187,6 +195,8 @@ struct fsl_sai {
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
+ const struct fsl_sai_soc_data *soc;
+ struct pm_qos_request pm_qos_req;
++ struct pinctrl *pinctrl;
++ struct pinctrl_state *pins_dsd;
+ };
+
+ #define TX 1