ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 801-audio-0037-MLK-16224-4-ASoC-fsl_sai-support-multi-fifo-and-DSD.patch
1 From 87f734fa8214b4ddbfdac9b7ac5dc75a3d86badb Mon Sep 17 00:00:00 2001
2 From: Shengjiu Wang <shengjiu.wang@nxp.com>
3 Date: Tue, 23 Jan 2018 13:26:37 +0800
4 Subject: [PATCH] MLK-16224-4: ASoC: fsl_sai: support multi fifo and DSD
5
6 The codec always mux the LRCLK pin to DSD data line, so when
7 we want to support DSD, the pinmux is different. For two channel
8 DSD, the DSDL is mapped to TX0, but the DSDR is mapped to TX4,
9 there is address offset for the fifo address of TX0 and TX4, TX4's
10 fifo is not adjacent to TX0's.
11
12 Usually, if mapping is TX0 and TX1, that will be easy for SAI
13 and SDMA to handle, that SAI can use the FIFO combine mode, SDMA
14 can use the normal script.
15
16 so for DSD:
17 1. The SDMA should use the multi-fifo script, and SAI can't
18 use the FIFO combine mode.
19 2. driver should to check the dts configuration(fsl,dataline) for
20 which dataline is used corrently
21 3. maxburst is the multiply of datalines
22 4. each channel of DSD occupy one data lane
23 5. according to data lane, set TRCE bits
24
25 Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
26 Reviewed-by: Viorel Suman <viorel.suman@nxp.com>
27 ---
28  sound/soc/fsl/fsl_sai.c | 162 +++++++++++++++++++++++++++++++++++++++++++++---
29  sound/soc/fsl/fsl_sai.h |  12 +++-
30  2 files changed, 164 insertions(+), 10 deletions(-)
31
32 --- a/sound/soc/fsl/fsl_sai.c
33 +++ b/sound/soc/fsl/fsl_sai.c
34 @@ -267,6 +267,7 @@ static int fsl_sai_set_dai_fmt_tr(struct
35         if (!sai->is_lsb_first)
36                 val_cr4 |= FSL_SAI_CR4_MF;
37  
38 +       sai->is_dsp_mode = false;
39         /* DAI mode */
40         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
41         case SND_SOC_DAIFMT_I2S:
42 @@ -305,6 +306,11 @@ static int fsl_sai_set_dai_fmt_tr(struct
43                 val_cr2 |= FSL_SAI_CR2_BCP;
44                 sai->is_dsp_mode = true;
45                 break;
46 +       case SND_SOC_DAIFMT_PDM:
47 +               val_cr2 |= FSL_SAI_CR2_BCP;
48 +               val_cr4 &= ~FSL_SAI_CR4_MF;
49 +               sai->is_dsp_mode = true;
50 +               break;
51         case SND_SOC_DAIFMT_RIGHT_J:
52                 /* To be done */
53         default:
54 @@ -492,12 +498,38 @@ static int fsl_sai_hw_params(struct snd_
55         u32 slot_width = word_width;
56         u32 pins;
57         int ret;
58 +       int i;
59 +       int trce_mask = 0;
60 +       snd_pcm_format_t format = params_format(params);
61  
62         if (sai->slots)
63                 slots = sai->slots;
64  
65         pins = DIV_ROUND_UP(channels, slots);
66  
67 +       if (format == SNDRV_PCM_FORMAT_DSD_U8 ||
68 +               format == SNDRV_PCM_FORMAT_DSD_U16_LE ||
69 +               format == SNDRV_PCM_FORMAT_DSD_U16_BE ||
70 +               format == SNDRV_PCM_FORMAT_DSD_U32_LE ||
71 +               format == SNDRV_PCM_FORMAT_DSD_U32_BE) {
72 +               sai->is_dsd = true;
73 +
74 +               if (!IS_ERR_OR_NULL(sai->pins_dsd)) {
75 +                       ret = pinctrl_select_state(sai->pinctrl, sai->pins_dsd);
76 +                       if (ret) {
77 +                               dev_err(cpu_dai->dev,
78 +                                       "failed to set proper pins state: %d\n", ret);
79 +                               return ret;
80 +                       }
81 +               }
82 +       } else {
83 +               pinctrl_pm_select_default_state(cpu_dai->dev);
84 +               sai->is_dsd = false;
85 +       }
86 +
87 +       if (sai->is_dsd)
88 +               pins = channels;
89 +
90         if (sai->slot_width)
91                 slot_width = sai->slot_width;
92  
93 @@ -527,7 +559,7 @@ static int fsl_sai_hw_params(struct snd_
94         val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
95         val_cr5 |= FSL_SAI_CR5_W0W(slot_width);
96  
97 -       if (sai->is_lsb_first)
98 +       if (sai->is_lsb_first || sai->is_dsd)
99                 val_cr5 |= FSL_SAI_CR5_FBT(0);
100         else
101                 val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
102 @@ -560,17 +592,71 @@ static int fsl_sai_hw_params(struct snd_
103         }
104  
105         if (sai->soc->dataline != 0x1) {
106 -               if (sai->dataline[tx] <= 1)
107 +
108 +               if (sai->dataline[tx] <= 1 || sai->is_multi_lane)
109                         regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
110                                 FSL_SAI_CR4_FCOMB_MASK, 0);
111                 else
112                         regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
113                                 FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT);
114 +
115 +               if (sai->is_multi_lane) {
116 +                       if (tx) {
117 +                               sai->dma_params_tx.maxburst =
118 +                                               FSL_SAI_MAXBURST_TX * pins;
119 +                               if (sai->is_dsd)
120 +                                       sai->dma_params_tx.fifo_num = pins +
121 +                                          (sai->dataline_off_dsd[tx] << 8);
122 +                               else
123 +                                       sai->dma_params_tx.fifo_num = pins +
124 +                                               (sai->dataline_off[tx] << 8);
125 +                       } else {
126 +                               sai->dma_params_rx.maxburst =
127 +                                       FSL_SAI_MAXBURST_RX * pins;
128 +                               if (sai->is_dsd)
129 +                                       sai->dma_params_rx.fifo_num = pins +
130 +                                         (sai->dataline_off_dsd[tx] << 8);
131 +                               else
132 +                                       sai->dma_params_rx.fifo_num = pins +
133 +                                               (sai->dataline_off[tx] << 8);
134 +                       }
135 +               }
136 +
137 +               snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx,
138 +                               &sai->dma_params_rx);
139         }
140  
141 -       regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
142 +       if (sai->is_dsd) {
143 +               if (__sw_hweight8(sai->dataline_dsd[tx] & 0xFF) < pins) {
144 +                       dev_err(cpu_dai->dev, "channel not supported\n");
145 +                       return -EINVAL;
146 +               }
147 +               /*find a proper tcre setting*/
148 +               for (i = 0; i < 8; i++) {
149 +                       trce_mask = (1 << (i + 1)) - 1;
150 +                       if (__sw_hweight8(sai->dataline_dsd[tx] & trce_mask) == pins)
151 +                               break;
152 +               }
153 +
154 +               regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
155                            FSL_SAI_CR3_TRCE_MASK,
156 -                          FSL_SAI_CR3_TRCE((sai->dataline[tx] & ((1 << pins) - 1))));
157 +                          FSL_SAI_CR3_TRCE((sai->dataline_dsd[tx] & trce_mask)));
158 +       } else {
159 +               if (__sw_hweight8(sai->dataline[tx] & 0xFF) < pins) {
160 +                       dev_err(cpu_dai->dev, "channel not supported\n");
161 +                       return -EINVAL;
162 +               }
163 +               /*find a proper tcre setting*/
164 +               for (i = 0; i < 8; i++) {
165 +                       trce_mask = (1 << (i + 1)) - 1;
166 +                       if (__sw_hweight8(sai->dataline[tx] & trce_mask) == pins)
167 +                               break;
168 +               }
169 +
170 +               regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, offset),
171 +                          FSL_SAI_CR3_TRCE_MASK,
172 +                          FSL_SAI_CR3_TRCE((sai->dataline[tx] & trce_mask)));
173 +       }
174  
175         regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, offset),
176                            FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
177 @@ -610,9 +696,18 @@ static int fsl_sai_trigger(struct snd_pc
178         unsigned char offset = sai->soc->reg_offset;
179         bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
180         u8 channels = substream->runtime->channels;
181 +       u32 slots = (channels == 1) ? 2 : channels;
182         u32 xcsr, count = 100;
183 -       int i;
184 +       u32 pins;
185 +       int i = 0, j = 0, k = 0;
186 +
187 +       if (sai->slots)
188 +               slots = sai->slots;
189 +
190 +       pins = DIV_ROUND_UP(channels, slots);
191  
192 +       if (sai->is_dsd)
193 +               pins = channels;
194         /*
195          * Asynchronous mode: Clear SYNC for both Tx and Rx.
196          * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
197 @@ -631,10 +726,19 @@ static int fsl_sai_trigger(struct snd_pc
198         case SNDRV_PCM_TRIGGER_START:
199         case SNDRV_PCM_TRIGGER_RESUME:
200         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
201 -               for (i = 0; tx && i < channels; i++)
202 -                       regmap_write(sai->regmap, FSL_SAI_TDR0, 0x0);
203 -               if (tx)
204 -                       udelay(10);
205 +
206 +               for (i = 0; tx && i < channels; i++) {
207 +               while (tx && i < channels)
208 +                       if (sai->dataline[tx] & (1 << j)) {
209 +                               regmap_write(sai->regmap, FSL_SAI_TDR0 + j * 0x4, 0x0);
210 +                               i++;
211 +                               k++;
212 +                       }
213 +                       j++;
214 +
215 +                       if (k%pins == 0)
216 +                               j = 0;
217 +               }
218  
219                 regmap_update_bits(sai->regmap, FSL_SAI_xCSR(tx, offset),
220                                    FSL_SAI_CSR_FRDE, FSL_SAI_CSR_FRDE);
221 @@ -994,6 +1098,7 @@ static int fsl_sai_probe(struct platform
222         char tmp[8];
223         int irq, ret, i;
224         int index;
225 +       int firstbitidx, nextbitidx;
226         struct regmap_config fsl_sai_regmap_config = fsl_sai_v2_regmap_config;
227         unsigned long irqflags = 0;
228  
229 @@ -1048,6 +1153,9 @@ static int fsl_sai_probe(struct platform
230                 }
231         }
232  
233 +       if (of_find_property(np, "fsl,sai-multi-lane", NULL))
234 +               sai->is_multi_lane = true;
235 +
236         /*dataline mask for rx and tx*/
237         ret = of_property_read_u32_index(np, "fsl,dataline", 0, &sai->dataline[0]);
238         if (ret)
239 @@ -1062,6 +1170,37 @@ static int fsl_sai_probe(struct platform
240                 return -EINVAL;
241         }
242  
243 +       for (i = 0; i < 2; i++) {
244 +               firstbitidx = find_first_bit((const unsigned long *)&sai->dataline[i], 8);
245 +               nextbitidx = find_next_bit((const unsigned long *)&sai->dataline[i], 8, firstbitidx+1);
246 +               sai->dataline_off[i] = nextbitidx - firstbitidx - 1;
247 +
248 +               if (sai->dataline_off[i] < 0 || sai->dataline_off[i] >= 7)
249 +                       sai->dataline_off[i] = 0;
250 +       }
251 +
252 +       ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 0, &sai->dataline_dsd[0]);
253 +       if (ret)
254 +               sai->dataline_dsd[0] = 1;
255 +
256 +       ret = of_property_read_u32_index(np, "fsl,dataline,dsd", 1, &sai->dataline_dsd[1]);
257 +       if (ret)
258 +               sai->dataline_dsd[1] = 1;
259 +
260 +       if ((sai->dataline_dsd[0] & (~sai->soc->dataline)) || sai->dataline_dsd[1] & (~sai->soc->dataline)) {
261 +               dev_err(&pdev->dev, "dataline setting error, Mask is 0x%x\n", sai->soc->dataline);
262 +               return -EINVAL;
263 +       }
264 +
265 +       for (i = 0; i < 2; i++) {
266 +               firstbitidx = find_first_bit((const unsigned long *)&sai->dataline_dsd[i], 8);
267 +               nextbitidx = find_next_bit((const unsigned long *)&sai->dataline_dsd[i], 8, firstbitidx+1);
268 +               sai->dataline_off_dsd[i] = nextbitidx - firstbitidx - 1;
269 +
270 +               if (sai->dataline_off_dsd[i] < 0 || sai->dataline_off_dsd[i] >= 7)
271 +                       sai->dataline_off_dsd[i] = 0;
272 +       }
273 +
274         if ((of_find_property(np, "fsl,i2s-xtor", NULL) != NULL) ||
275             (of_find_property(np, "fsl,txm-rxs", NULL) != NULL))
276         {
277 @@ -1143,6 +1282,11 @@ static int fsl_sai_probe(struct platform
278         sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
279         sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX;
280  
281 +       sai->pinctrl  = devm_pinctrl_get(&pdev->dev);
282 +
283 +       if (!IS_ERR_OR_NULL(sai->pinctrl))
284 +               sai->pins_dsd = pinctrl_lookup_state(sai->pinctrl, "dsd");
285 +
286         platform_set_drvdata(pdev, sai);
287  
288         pm_runtime_enable(&pdev->dev);
289 --- a/sound/soc/fsl/fsl_sai.h
290 +++ b/sound/soc/fsl/fsl_sai.h
291 @@ -11,7 +11,10 @@
292  
293  #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
294                          SNDRV_PCM_FMTBIT_S24_LE |\
295 -                        SNDRV_PCM_FMTBIT_S32_LE)
296 +                        SNDRV_PCM_FMTBIT_S32_LE |\
297 +                        SNDRV_PCM_FMTBIT_DSD_U8 |\
298 +                        SNDRV_PCM_FMTBIT_DSD_U16_LE |\
299 +                        SNDRV_PCM_FMTBIT_DSD_U32_LE)
300  
301  /* SAI Register Map Register */
302  #define FSL_SAI_TCSR(offset) (0x00 + offset) /* SAI Transmit Control */
303 @@ -172,9 +175,14 @@ struct fsl_sai {
304         bool slave_mode[2];
305         bool is_lsb_first;
306         bool is_dsp_mode;
307 +       bool is_multi_lane;
308         bool synchronous[2];
309         bool is_stream_opened[2];
310 +       bool is_dsd;
311         unsigned int dataline[2];
312 +       unsigned int dataline_dsd[2];
313 +       unsigned int dataline_off[2];
314 +       unsigned int dataline_off_dsd[2];
315         unsigned int masterflag[2];
316  
317         unsigned int mclk_id[2];
318 @@ -187,6 +195,8 @@ struct fsl_sai {
319         struct snd_dmaengine_dai_dma_data dma_params_tx;
320         const struct fsl_sai_soc_data *soc;
321         struct pm_qos_request pm_qos_req;
322 +       struct pinctrl *pinctrl;
323 +       struct pinctrl_state *pins_dsd;
324  };
325  
326  #define TX 1