diff options
author | Rabin Vincent <rabin.vincent@stericsson.com> | 2011-01-25 05:18:35 -0500 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-01-31 01:27:21 -0500 |
commit | 0c842b551063c5f7382ac9b457992f3b34972801 (patch) | |
tree | da606f382493e6cf3540b4245b86a784a78e46b4 /drivers/dma/ste_dma40_ll.c | |
parent | 86eb5fb61125e4646c9447a1f2ce130817dab34e (diff) |
dma40: cyclic xfer support
Support cyclic transfers, which are useful for ALSA drivers.
Acked-by: Per Forlin <per.forlin@stericsson.com>
Acked-by: Jonas Aaberg <jonas.aberg@stericsson.com>
Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/dma/ste_dma40_ll.c')
-rw-r--r-- | drivers/dma/ste_dma40_ll.c | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/drivers/dma/ste_dma40_ll.c b/drivers/dma/ste_dma40_ll.c index 88b9e371be2f..cad9e1daedff 100644 --- a/drivers/dma/ste_dma40_ll.c +++ b/drivers/dma/ste_dma40_ll.c | |||
@@ -202,13 +202,15 @@ static int d40_seg_size(int size, int data_width1, int data_width2) | |||
202 | 202 | ||
203 | static struct d40_phy_lli * | 203 | static struct d40_phy_lli * |
204 | d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, | 204 | d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, |
205 | dma_addr_t lli_phys, u32 reg_cfg, | 205 | dma_addr_t lli_phys, dma_addr_t first_phys, u32 reg_cfg, |
206 | struct stedma40_half_channel_info *info, | 206 | struct stedma40_half_channel_info *info, |
207 | struct stedma40_half_channel_info *otherinfo, | 207 | struct stedma40_half_channel_info *otherinfo, |
208 | unsigned long flags) | 208 | unsigned long flags) |
209 | { | 209 | { |
210 | bool lastlink = flags & LLI_LAST_LINK; | ||
210 | bool addr_inc = flags & LLI_ADDR_INC; | 211 | bool addr_inc = flags & LLI_ADDR_INC; |
211 | bool term_int = flags & LLI_TERM_INT; | 212 | bool term_int = flags & LLI_TERM_INT; |
213 | bool cyclic = flags & LLI_CYCLIC; | ||
212 | int err; | 214 | int err; |
213 | dma_addr_t next = lli_phys; | 215 | dma_addr_t next = lli_phys; |
214 | int size_rest = size; | 216 | int size_rest = size; |
@@ -226,10 +228,12 @@ d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, | |||
226 | otherinfo->data_width); | 228 | otherinfo->data_width); |
227 | size_rest -= size_seg; | 229 | size_rest -= size_seg; |
228 | 230 | ||
229 | if (term_int && size_rest == 0) { | 231 | if (size_rest == 0 && term_int) |
230 | next = 0; | ||
231 | flags |= LLI_TERM_INT; | 232 | flags |= LLI_TERM_INT; |
232 | } else | 233 | |
234 | if (size_rest == 0 && lastlink) | ||
235 | next = cyclic ? first_phys : 0; | ||
236 | else | ||
233 | next = ALIGN(next + sizeof(struct d40_phy_lli), | 237 | next = ALIGN(next + sizeof(struct d40_phy_lli), |
234 | D40_LLI_ALIGN); | 238 | D40_LLI_ALIGN); |
235 | 239 | ||
@@ -257,14 +261,14 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, | |||
257 | dma_addr_t lli_phys, | 261 | dma_addr_t lli_phys, |
258 | u32 reg_cfg, | 262 | u32 reg_cfg, |
259 | struct stedma40_half_channel_info *info, | 263 | struct stedma40_half_channel_info *info, |
260 | struct stedma40_half_channel_info *otherinfo) | 264 | struct stedma40_half_channel_info *otherinfo, |
265 | unsigned long flags) | ||
261 | { | 266 | { |
262 | int total_size = 0; | 267 | int total_size = 0; |
263 | int i; | 268 | int i; |
264 | struct scatterlist *current_sg = sg; | 269 | struct scatterlist *current_sg = sg; |
265 | struct d40_phy_lli *lli = lli_sg; | 270 | struct d40_phy_lli *lli = lli_sg; |
266 | dma_addr_t l_phys = lli_phys; | 271 | dma_addr_t l_phys = lli_phys; |
267 | unsigned long flags = 0; | ||
268 | 272 | ||
269 | if (!target) | 273 | if (!target) |
270 | flags |= LLI_ADDR_INC; | 274 | flags |= LLI_ADDR_INC; |
@@ -277,12 +281,12 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, | |||
277 | total_size += sg_dma_len(current_sg); | 281 | total_size += sg_dma_len(current_sg); |
278 | 282 | ||
279 | if (i == sg_len - 1) | 283 | if (i == sg_len - 1) |
280 | flags |= LLI_TERM_INT; | 284 | flags |= LLI_TERM_INT | LLI_LAST_LINK; |
281 | 285 | ||
282 | l_phys = ALIGN(lli_phys + (lli - lli_sg) * | 286 | l_phys = ALIGN(lli_phys + (lli - lli_sg) * |
283 | sizeof(struct d40_phy_lli), D40_LLI_ALIGN); | 287 | sizeof(struct d40_phy_lli), D40_LLI_ALIGN); |
284 | 288 | ||
285 | lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, | 289 | lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, lli_phys, |
286 | reg_cfg, info, otherinfo, flags); | 290 | reg_cfg, info, otherinfo, flags); |
287 | 291 | ||
288 | if (lli == NULL) | 292 | if (lli == NULL) |
@@ -297,15 +301,18 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, | |||
297 | 301 | ||
298 | static void d40_log_lli_link(struct d40_log_lli *lli_dst, | 302 | static void d40_log_lli_link(struct d40_log_lli *lli_dst, |
299 | struct d40_log_lli *lli_src, | 303 | struct d40_log_lli *lli_src, |
300 | int next) | 304 | int next, unsigned int flags) |
301 | { | 305 | { |
306 | bool interrupt = flags & LLI_TERM_INT; | ||
302 | u32 slos = 0; | 307 | u32 slos = 0; |
303 | u32 dlos = 0; | 308 | u32 dlos = 0; |
304 | 309 | ||
305 | if (next != -EINVAL) { | 310 | if (next != -EINVAL) { |
306 | slos = next * 2; | 311 | slos = next * 2; |
307 | dlos = next * 2 + 1; | 312 | dlos = next * 2 + 1; |
308 | } else { | 313 | } |
314 | |||
315 | if (interrupt) { | ||
309 | lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; | 316 | lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; |
310 | lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; | 317 | lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; |
311 | } | 318 | } |
@@ -320,9 +327,9 @@ static void d40_log_lli_link(struct d40_log_lli *lli_dst, | |||
320 | void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, | 327 | void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, |
321 | struct d40_log_lli *lli_dst, | 328 | struct d40_log_lli *lli_dst, |
322 | struct d40_log_lli *lli_src, | 329 | struct d40_log_lli *lli_src, |
323 | int next) | 330 | int next, unsigned int flags) |
324 | { | 331 | { |
325 | d40_log_lli_link(lli_dst, lli_src, next); | 332 | d40_log_lli_link(lli_dst, lli_src, next, flags); |
326 | 333 | ||
327 | writel(lli_src->lcsp02, &lcpa[0].lcsp0); | 334 | writel(lli_src->lcsp02, &lcpa[0].lcsp0); |
328 | writel(lli_src->lcsp13, &lcpa[0].lcsp1); | 335 | writel(lli_src->lcsp13, &lcpa[0].lcsp1); |
@@ -333,9 +340,9 @@ void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, | |||
333 | void d40_log_lli_lcla_write(struct d40_log_lli *lcla, | 340 | void d40_log_lli_lcla_write(struct d40_log_lli *lcla, |
334 | struct d40_log_lli *lli_dst, | 341 | struct d40_log_lli *lli_dst, |
335 | struct d40_log_lli *lli_src, | 342 | struct d40_log_lli *lli_src, |
336 | int next) | 343 | int next, unsigned int flags) |
337 | { | 344 | { |
338 | d40_log_lli_link(lli_dst, lli_src, next); | 345 | d40_log_lli_link(lli_dst, lli_src, next, flags); |
339 | 346 | ||
340 | writel(lli_src->lcsp02, &lcla[0].lcsp02); | 347 | writel(lli_src->lcsp02, &lcla[0].lcsp02); |
341 | writel(lli_src->lcsp13, &lcla[0].lcsp13); | 348 | writel(lli_src->lcsp13, &lcla[0].lcsp13); |