DMAENGINE: ste_dma40: code clean-up
[firefly-linux-kernel-4.4.55.git] / drivers / dma / ste_dma40_ll.c
1 /*
2  * Copyright (C) ST-Ericsson SA 2007-2010
3  * Author: Per Friden <per.friden@stericsson.com> for ST-Ericsson
4  * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
5  * License terms: GNU General Public License (GPL) version 2
6  */
7
8 #include <linux/kernel.h>
9 #include <plat/ste_dma40.h>
10
11 #include "ste_dma40_ll.h"
12
13 /* Sets up proper LCSP1 and LCSP3 register for a logical channel */
14 void d40_log_cfg(struct stedma40_chan_cfg *cfg,
15                  u32 *lcsp1, u32 *lcsp3)
16 {
17         u32 l3 = 0; /* dst */
18         u32 l1 = 0; /* src */
19
20         /* src is mem? -> increase address pos */
21         if (cfg->dir ==  STEDMA40_MEM_TO_PERIPH ||
22             cfg->dir ==  STEDMA40_MEM_TO_MEM)
23                 l1 |= 1 << D40_MEM_LCSP1_SCFG_INCR_POS;
24
25         /* dst is mem? -> increase address pos */
26         if (cfg->dir ==  STEDMA40_PERIPH_TO_MEM ||
27             cfg->dir ==  STEDMA40_MEM_TO_MEM)
28                 l3 |= 1 << D40_MEM_LCSP3_DCFG_INCR_POS;
29
30         /* src is hw? -> master port 1 */
31         if (cfg->dir ==  STEDMA40_PERIPH_TO_MEM ||
32             cfg->dir ==  STEDMA40_PERIPH_TO_PERIPH)
33                 l1 |= 1 << D40_MEM_LCSP1_SCFG_MST_POS;
34
35         /* dst is hw? -> master port 1 */
36         if (cfg->dir ==  STEDMA40_MEM_TO_PERIPH ||
37             cfg->dir ==  STEDMA40_PERIPH_TO_PERIPH)
38                 l3 |= 1 << D40_MEM_LCSP3_DCFG_MST_POS;
39
40         l3 |= 1 << D40_MEM_LCSP3_DCFG_TIM_POS;
41         l3 |= 1 << D40_MEM_LCSP3_DCFG_EIM_POS;
42         l3 |= cfg->dst_info.psize << D40_MEM_LCSP3_DCFG_PSIZE_POS;
43         l3 |= cfg->dst_info.data_width << D40_MEM_LCSP3_DCFG_ESIZE_POS;
44         l3 |= 1 << D40_MEM_LCSP3_DTCP_POS;
45
46         l1 |= 1 << D40_MEM_LCSP1_SCFG_EIM_POS;
47         l1 |= cfg->src_info.psize << D40_MEM_LCSP1_SCFG_PSIZE_POS;
48         l1 |= cfg->src_info.data_width << D40_MEM_LCSP1_SCFG_ESIZE_POS;
49         l1 |= 1 << D40_MEM_LCSP1_STCP_POS;
50
51         *lcsp1 = l1;
52         *lcsp3 = l3;
53
54 }
55
56 /* Sets up SRC and DST CFG register for both logical and physical channels */
57 void d40_phy_cfg(struct stedma40_chan_cfg *cfg,
58                  u32 *src_cfg, u32 *dst_cfg, bool is_log)
59 {
60         u32 src = 0;
61         u32 dst = 0;
62
63         if (!is_log) {
64                 /* Physical channel */
65                 if ((cfg->dir ==  STEDMA40_PERIPH_TO_MEM) ||
66                     (cfg->dir == STEDMA40_PERIPH_TO_PERIPH)) {
67                         /* Set master port to 1 */
68                         src |= 1 << D40_SREG_CFG_MST_POS;
69                         src |= D40_TYPE_TO_EVENT(cfg->src_dev_type);
70
71                         if (cfg->src_info.flow_ctrl == STEDMA40_NO_FLOW_CTRL)
72                                 src |= 1 << D40_SREG_CFG_PHY_TM_POS;
73                         else
74                                 src |= 3 << D40_SREG_CFG_PHY_TM_POS;
75                 }
76                 if ((cfg->dir ==  STEDMA40_MEM_TO_PERIPH) ||
77                     (cfg->dir == STEDMA40_PERIPH_TO_PERIPH)) {
78                         /* Set master port to 1 */
79                         dst |= 1 << D40_SREG_CFG_MST_POS;
80                         dst |= D40_TYPE_TO_EVENT(cfg->dst_dev_type);
81
82                         if (cfg->dst_info.flow_ctrl == STEDMA40_NO_FLOW_CTRL)
83                                 dst |= 1 << D40_SREG_CFG_PHY_TM_POS;
84                         else
85                                 dst |= 3 << D40_SREG_CFG_PHY_TM_POS;
86                 }
87                 /* Interrupt on end of transfer for destination */
88                 dst |= 1 << D40_SREG_CFG_TIM_POS;
89
90                 /* Generate interrupt on error */
91                 src |= 1 << D40_SREG_CFG_EIM_POS;
92                 dst |= 1 << D40_SREG_CFG_EIM_POS;
93
94                 /* PSIZE */
95                 if (cfg->src_info.psize != STEDMA40_PSIZE_PHY_1) {
96                         src |= 1 << D40_SREG_CFG_PHY_PEN_POS;
97                         src |= cfg->src_info.psize << D40_SREG_CFG_PSIZE_POS;
98                 }
99                 if (cfg->dst_info.psize != STEDMA40_PSIZE_PHY_1) {
100                         dst |= 1 << D40_SREG_CFG_PHY_PEN_POS;
101                         dst |= cfg->dst_info.psize << D40_SREG_CFG_PSIZE_POS;
102                 }
103
104                 /* Element size */
105                 src |= cfg->src_info.data_width << D40_SREG_CFG_ESIZE_POS;
106                 dst |= cfg->dst_info.data_width << D40_SREG_CFG_ESIZE_POS;
107
108         } else {
109                 /* Logical channel */
110                 dst |= 1 << D40_SREG_CFG_LOG_GIM_POS;
111                 src |= 1 << D40_SREG_CFG_LOG_GIM_POS;
112         }
113
114         if (cfg->channel_type & STEDMA40_HIGH_PRIORITY_CHANNEL) {
115                 src |= 1 << D40_SREG_CFG_PRI_POS;
116                 dst |= 1 << D40_SREG_CFG_PRI_POS;
117         }
118
119         src |= cfg->src_info.endianess << D40_SREG_CFG_LBE_POS;
120         dst |= cfg->dst_info.endianess << D40_SREG_CFG_LBE_POS;
121
122         *src_cfg = src;
123         *dst_cfg = dst;
124 }
125
126 int d40_phy_fill_lli(struct d40_phy_lli *lli,
127                      dma_addr_t data,
128                      u32 data_size,
129                      int psize,
130                      dma_addr_t next_lli,
131                      u32 reg_cfg,
132                      bool term_int,
133                      u32 data_width,
134                      bool is_device)
135 {
136         int num_elems;
137
138         if (psize == STEDMA40_PSIZE_PHY_1)
139                 num_elems = 1;
140         else
141                 num_elems = 2 << psize;
142
143         /*
144          * Size is 16bit. data_width is 8, 16, 32 or 64 bit
145          * Block large than 64 KiB must be split.
146          */
147         if (data_size > (0xffff << data_width))
148                 return -EINVAL;
149
150         /* Must be aligned */
151         if (!IS_ALIGNED(data, 0x1 << data_width))
152                 return -EINVAL;
153
154         /* Transfer size can't be smaller than (num_elms * elem_size) */
155         if (data_size < num_elems * (0x1 << data_width))
156                 return -EINVAL;
157
158         /* The number of elements. IE now many chunks */
159         lli->reg_elt = (data_size >> data_width) << D40_SREG_ELEM_PHY_ECNT_POS;
160
161         /*
162          * Distance to next element sized entry.
163          * Usually the size of the element unless you want gaps.
164          */
165         if (!is_device)
166                 lli->reg_elt |= (0x1 << data_width) <<
167                         D40_SREG_ELEM_PHY_EIDX_POS;
168
169         /* Where the data is */
170         lli->reg_ptr = data;
171         lli->reg_cfg = reg_cfg;
172
173         /* If this scatter list entry is the last one, no next link */
174         if (next_lli == 0)
175                 lli->reg_lnk = 0x1 << D40_SREG_LNK_PHY_TCP_POS;
176         else
177                 lli->reg_lnk = next_lli;
178
179         /* Set/clear interrupt generation on this link item.*/
180         if (term_int)
181                 lli->reg_cfg |= 0x1 << D40_SREG_CFG_TIM_POS;
182         else
183                 lli->reg_cfg &= ~(0x1 << D40_SREG_CFG_TIM_POS);
184
185         /* Post link */
186         lli->reg_lnk |= 0 << D40_SREG_LNK_PHY_PRE_POS;
187
188         return 0;
189 }
190
191 int d40_phy_sg_to_lli(struct scatterlist *sg,
192                       int sg_len,
193                       dma_addr_t target,
194                       struct d40_phy_lli *lli,
195                       dma_addr_t lli_phys,
196                       u32 reg_cfg,
197                       u32 data_width,
198                       int psize)
199 {
200         int total_size = 0;
201         int i;
202         struct scatterlist *current_sg = sg;
203         dma_addr_t next_lli_phys;
204         dma_addr_t dst;
205         int err = 0;
206
207         for_each_sg(sg, current_sg, sg_len, i) {
208
209                 total_size += sg_dma_len(current_sg);
210
211                 /* If this scatter list entry is the last one, no next link */
212                 if (sg_len - 1 == i)
213                         next_lli_phys = 0;
214                 else
215                         next_lli_phys = ALIGN(lli_phys + (i + 1) *
216                                               sizeof(struct d40_phy_lli),
217                                               D40_LLI_ALIGN);
218
219                 if (target)
220                         dst = target;
221                 else
222                         dst = sg_phys(current_sg);
223
224                 err = d40_phy_fill_lli(&lli[i],
225                                        dst,
226                                        sg_dma_len(current_sg),
227                                        psize,
228                                        next_lli_phys,
229                                        reg_cfg,
230                                        !next_lli_phys,
231                                        data_width,
232                                        target == dst);
233                 if (err)
234                         goto err;
235         }
236
237         return total_size;
238  err:
239         return err;
240 }
241
242
243 void d40_phy_lli_write(void __iomem *virtbase,
244                        u32 phy_chan_num,
245                        struct d40_phy_lli *lli_dst,
246                        struct d40_phy_lli *lli_src)
247 {
248
249         writel(lli_src->reg_cfg, virtbase + D40_DREG_PCBASE +
250                phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSCFG);
251         writel(lli_src->reg_elt, virtbase + D40_DREG_PCBASE +
252                phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT);
253         writel(lli_src->reg_ptr, virtbase + D40_DREG_PCBASE +
254                phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSPTR);
255         writel(lli_src->reg_lnk, virtbase + D40_DREG_PCBASE +
256                phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSLNK);
257
258         writel(lli_dst->reg_cfg, virtbase + D40_DREG_PCBASE +
259                phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDCFG);
260         writel(lli_dst->reg_elt, virtbase + D40_DREG_PCBASE +
261                phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT);
262         writel(lli_dst->reg_ptr, virtbase + D40_DREG_PCBASE +
263                phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDPTR);
264         writel(lli_dst->reg_lnk, virtbase + D40_DREG_PCBASE +
265                phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDLNK);
266
267 }
268
269 /* DMA logical lli operations */
270
271 void d40_log_fill_lli(struct d40_log_lli *lli,
272                       dma_addr_t data, u32 data_size,
273                       u32 lli_next_off, u32 reg_cfg,
274                       u32 data_width,
275                       bool term_int, bool addr_inc)
276 {
277         lli->lcsp13 = reg_cfg;
278
279         /* The number of elements to transfer */
280         lli->lcsp02 = ((data_size >> data_width) <<
281                        D40_MEM_LCSP0_ECNT_POS) & D40_MEM_LCSP0_ECNT_MASK;
282         /* 16 LSBs address of the current element */
283         lli->lcsp02 |= data & D40_MEM_LCSP0_SPTR_MASK;
284         /* 16 MSBs address of the current element */
285         lli->lcsp13 |= data & D40_MEM_LCSP1_SPTR_MASK;
286
287         if (addr_inc)
288                 lli->lcsp13 |= D40_MEM_LCSP1_SCFG_INCR_MASK;
289
290         lli->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK;
291         /* If this scatter list entry is the last one, no next link */
292         lli->lcsp13 |= (lli_next_off << D40_MEM_LCSP1_SLOS_POS) &
293                 D40_MEM_LCSP1_SLOS_MASK;
294
295         if (term_int)
296                 lli->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK;
297         else
298                 lli->lcsp13 &= ~D40_MEM_LCSP1_SCFG_TIM_MASK;
299 }
300
301 int d40_log_sg_to_dev(struct d40_lcla_elem *lcla,
302                       struct scatterlist *sg,
303                       int sg_len,
304                       struct d40_log_lli_bidir *lli,
305                       struct d40_def_lcsp *lcsp,
306                       u32 src_data_width,
307                       u32 dst_data_width,
308                       enum dma_data_direction direction,
309                       dma_addr_t dev_addr, int max_len,
310                       int llis_per_log)
311 {
312         int total_size = 0;
313         struct scatterlist *current_sg = sg;
314         int i;
315         u32 next_lli_off_dst = 0;
316         u32 next_lli_off_src = 0;
317
318         for_each_sg(sg, current_sg, sg_len, i) {
319                 total_size += sg_dma_len(current_sg);
320
321                 /*
322                  * If this scatter list entry is the last one or
323                  * max length, terminate link.
324                  */
325                 if (sg_len - 1 == i || ((i+1) % max_len == 0)) {
326                         next_lli_off_src = 0;
327                         next_lli_off_dst = 0;
328                 } else {
329                         if (next_lli_off_dst == 0 &&
330                             next_lli_off_src == 0) {
331                                 /* The first lli will be at next_lli_off */
332                                 next_lli_off_dst = (lcla->dst_id *
333                                                     llis_per_log + 1);
334                                 next_lli_off_src = (lcla->src_id *
335                                                     llis_per_log + 1);
336                         } else {
337                                 next_lli_off_dst++;
338                                 next_lli_off_src++;
339                         }
340                 }
341
342                 if (direction == DMA_TO_DEVICE) {
343                         d40_log_fill_lli(&lli->src[i],
344                                          sg_phys(current_sg),
345                                          sg_dma_len(current_sg),
346                                          next_lli_off_src,
347                                          lcsp->lcsp1, src_data_width,
348                                          false,
349                                          true);
350                         d40_log_fill_lli(&lli->dst[i],
351                                          dev_addr,
352                                          sg_dma_len(current_sg),
353                                          next_lli_off_dst,
354                                          lcsp->lcsp3, dst_data_width,
355                                          /* No next == terminal interrupt */
356                                          !next_lli_off_dst,
357                                          false);
358                 } else {
359                         d40_log_fill_lli(&lli->dst[i],
360                                          sg_phys(current_sg),
361                                          sg_dma_len(current_sg),
362                                          next_lli_off_dst,
363                                          lcsp->lcsp3, dst_data_width,
364                                          /* No next == terminal interrupt */
365                                          !next_lli_off_dst,
366                                          true);
367                         d40_log_fill_lli(&lli->src[i],
368                                          dev_addr,
369                                          sg_dma_len(current_sg),
370                                          next_lli_off_src,
371                                          lcsp->lcsp1, src_data_width,
372                                          false,
373                                          false);
374                 }
375         }
376         return total_size;
377 }
378
379 int d40_log_sg_to_lli(int lcla_id,
380                       struct scatterlist *sg,
381                       int sg_len,
382                       struct d40_log_lli *lli_sg,
383                       u32 lcsp13, /* src or dst*/
384                       u32 data_width,
385                       int max_len, int llis_per_log)
386 {
387         int total_size = 0;
388         struct scatterlist *current_sg = sg;
389         int i;
390         u32 next_lli_off = 0;
391
392         for_each_sg(sg, current_sg, sg_len, i) {
393                 total_size += sg_dma_len(current_sg);
394
395                 /*
396                  * If this scatter list entry is the last one or
397                  * max length, terminate link.
398                  */
399                 if (sg_len - 1 == i || ((i+1) % max_len == 0))
400                         next_lli_off = 0;
401                 else {
402                         if (next_lli_off == 0)
403                                 /* The first lli will be at next_lli_off */
404                                 next_lli_off = lcla_id * llis_per_log + 1;
405                         else
406                                 next_lli_off++;
407                 }
408
409                 d40_log_fill_lli(&lli_sg[i],
410                                  sg_phys(current_sg),
411                                  sg_dma_len(current_sg),
412                                  next_lli_off,
413                                  lcsp13, data_width,
414                                  !next_lli_off,
415                                  true);
416         }
417         return total_size;
418 }
419
420 int d40_log_lli_write(struct d40_log_lli_full *lcpa,
421                        struct d40_log_lli *lcla_src,
422                        struct d40_log_lli *lcla_dst,
423                        struct d40_log_lli *lli_dst,
424                        struct d40_log_lli *lli_src,
425                        int llis_per_log)
426 {
427         u32 slos;
428         u32 dlos;
429         int i;
430
431         writel(lli_src->lcsp02, &lcpa->lcsp0);
432         writel(lli_src->lcsp13, &lcpa->lcsp1);
433         writel(lli_dst->lcsp02, &lcpa->lcsp2);
434         writel(lli_dst->lcsp13, &lcpa->lcsp3);
435
436         slos = lli_src->lcsp13 & D40_MEM_LCSP1_SLOS_MASK;
437         dlos = lli_dst->lcsp13 & D40_MEM_LCSP3_DLOS_MASK;
438
439         for (i = 0; (i < llis_per_log) && slos && dlos; i++) {
440                 writel(lli_src[i + 1].lcsp02, &lcla_src[i].lcsp02);
441                 writel(lli_src[i + 1].lcsp13, &lcla_src[i].lcsp13);
442                 writel(lli_dst[i + 1].lcsp02, &lcla_dst[i].lcsp02);
443                 writel(lli_dst[i + 1].lcsp13, &lcla_dst[i].lcsp13);
444
445                 slos = lli_src[i + 1].lcsp13 & D40_MEM_LCSP1_SLOS_MASK;
446                 dlos = lli_dst[i + 1].lcsp13 & D40_MEM_LCSP3_DLOS_MASK;
447         }
448
449         return i;
450
451 }