1 /* 2 * Copyright (C) ST-Ericsson SA 2007-2010 3 * Author: Per Forlin <per.forlin@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 <linux/platform_data/dma-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 == DMA_MEM_TO_DEV || 22 cfg->dir == DMA_MEM_TO_MEM) 23 l1 |= BIT(D40_MEM_LCSP1_SCFG_INCR_POS); 24 25 /* dst is mem? -> increase address pos */ 26 if (cfg->dir == DMA_DEV_TO_MEM || 27 cfg->dir == DMA_MEM_TO_MEM) 28 l3 |= BIT(D40_MEM_LCSP3_DCFG_INCR_POS); 29 30 /* src is hw? -> master port 1 */ 31 if (cfg->dir == DMA_DEV_TO_MEM || 32 cfg->dir == DMA_DEV_TO_DEV) 33 l1 |= BIT(D40_MEM_LCSP1_SCFG_MST_POS); 34 35 /* dst is hw? -> master port 1 */ 36 if (cfg->dir == DMA_MEM_TO_DEV || 37 cfg->dir == DMA_DEV_TO_DEV) 38 l3 |= BIT(D40_MEM_LCSP3_DCFG_MST_POS); 39 40 l3 |= BIT(D40_MEM_LCSP3_DCFG_EIM_POS); 41 l3 |= cfg->dst_info.psize << D40_MEM_LCSP3_DCFG_PSIZE_POS; 42 l3 |= cfg->dst_info.data_width << D40_MEM_LCSP3_DCFG_ESIZE_POS; 43 44 l1 |= BIT(D40_MEM_LCSP1_SCFG_EIM_POS); 45 l1 |= cfg->src_info.psize << D40_MEM_LCSP1_SCFG_PSIZE_POS; 46 l1 |= cfg->src_info.data_width << D40_MEM_LCSP1_SCFG_ESIZE_POS; 47 48 *lcsp1 = l1; 49 *lcsp3 = l3; 50 51 } 52 53 void d40_phy_cfg(struct stedma40_chan_cfg *cfg, u32 *src_cfg, u32 *dst_cfg) 54 { 55 u32 src = 0; 56 u32 dst = 0; 57 58 if ((cfg->dir == DMA_DEV_TO_MEM) || 59 (cfg->dir == DMA_DEV_TO_DEV)) { 60 /* Set master port to 1 */ 61 src |= BIT(D40_SREG_CFG_MST_POS); 62 src |= D40_TYPE_TO_EVENT(cfg->dev_type); 63 64 if (cfg->src_info.flow_ctrl == STEDMA40_NO_FLOW_CTRL) 65 src |= BIT(D40_SREG_CFG_PHY_TM_POS); 66 else 67 src |= 3 << D40_SREG_CFG_PHY_TM_POS; 68 } 69 if ((cfg->dir == DMA_MEM_TO_DEV) || 70 (cfg->dir == DMA_DEV_TO_DEV)) { 71 /* Set master port to 1 */ 72 dst |= BIT(D40_SREG_CFG_MST_POS); 73 dst |= D40_TYPE_TO_EVENT(cfg->dev_type); 74 75 if (cfg->dst_info.flow_ctrl == STEDMA40_NO_FLOW_CTRL) 76 dst |= BIT(D40_SREG_CFG_PHY_TM_POS); 77 else 78 dst |= 3 << D40_SREG_CFG_PHY_TM_POS; 79 } 80 /* Interrupt on end of transfer for destination */ 81 dst |= BIT(D40_SREG_CFG_TIM_POS); 82 83 /* Generate interrupt on error */ 84 src |= BIT(D40_SREG_CFG_EIM_POS); 85 dst |= BIT(D40_SREG_CFG_EIM_POS); 86 87 /* PSIZE */ 88 if (cfg->src_info.psize != STEDMA40_PSIZE_PHY_1) { 89 src |= BIT(D40_SREG_CFG_PHY_PEN_POS); 90 src |= cfg->src_info.psize << D40_SREG_CFG_PSIZE_POS; 91 } 92 if (cfg->dst_info.psize != STEDMA40_PSIZE_PHY_1) { 93 dst |= BIT(D40_SREG_CFG_PHY_PEN_POS); 94 dst |= cfg->dst_info.psize << D40_SREG_CFG_PSIZE_POS; 95 } 96 97 /* Element size */ 98 src |= cfg->src_info.data_width << D40_SREG_CFG_ESIZE_POS; 99 dst |= cfg->dst_info.data_width << D40_SREG_CFG_ESIZE_POS; 100 101 /* Set the priority bit to high for the physical channel */ 102 if (cfg->high_priority) { 103 src |= BIT(D40_SREG_CFG_PRI_POS); 104 dst |= BIT(D40_SREG_CFG_PRI_POS); 105 } 106 107 if (cfg->src_info.big_endian) 108 src |= BIT(D40_SREG_CFG_LBE_POS); 109 if (cfg->dst_info.big_endian) 110 dst |= BIT(D40_SREG_CFG_LBE_POS); 111 112 *src_cfg = src; 113 *dst_cfg = dst; 114 } 115 116 static int d40_phy_fill_lli(struct d40_phy_lli *lli, 117 dma_addr_t data, 118 u32 data_size, 119 dma_addr_t next_lli, 120 u32 reg_cfg, 121 struct stedma40_half_channel_info *info, 122 unsigned int flags) 123 { 124 bool addr_inc = flags & LLI_ADDR_INC; 125 bool term_int = flags & LLI_TERM_INT; 126 unsigned int data_width = info->data_width; 127 int psize = info->psize; 128 int num_elems; 129 130 if (psize == STEDMA40_PSIZE_PHY_1) 131 num_elems = 1; 132 else 133 num_elems = 2 << psize; 134 135 /* Must be aligned */ 136 if (!IS_ALIGNED(data, 0x1 << data_width)) 137 return -EINVAL; 138 139 /* Transfer size can't be smaller than (num_elms * elem_size) */ 140 if (data_size < num_elems * (0x1 << data_width)) 141 return -EINVAL; 142 143 /* The number of elements. IE now many chunks */ 144 lli->reg_elt = (data_size >> data_width) << D40_SREG_ELEM_PHY_ECNT_POS; 145 146 /* 147 * Distance to next element sized entry. 148 * Usually the size of the element unless you want gaps. 149 */ 150 if (addr_inc) 151 lli->reg_elt |= (0x1 << data_width) << 152 D40_SREG_ELEM_PHY_EIDX_POS; 153 154 /* Where the data is */ 155 lli->reg_ptr = data; 156 lli->reg_cfg = reg_cfg; 157 158 /* If this scatter list entry is the last one, no next link */ 159 if (next_lli == 0) 160 lli->reg_lnk = BIT(D40_SREG_LNK_PHY_TCP_POS); 161 else 162 lli->reg_lnk = next_lli; 163 164 /* Set/clear interrupt generation on this link item.*/ 165 if (term_int) 166 lli->reg_cfg |= BIT(D40_SREG_CFG_TIM_POS); 167 else 168 lli->reg_cfg &= ~BIT(D40_SREG_CFG_TIM_POS); 169 170 /* Post link */ 171 lli->reg_lnk |= 0 << D40_SREG_LNK_PHY_PRE_POS; 172 173 return 0; 174 } 175 176 static int d40_seg_size(int size, int data_width1, int data_width2) 177 { 178 u32 max_w = max(data_width1, data_width2); 179 u32 min_w = min(data_width1, data_width2); 180 u32 seg_max = ALIGN(STEDMA40_MAX_SEG_SIZE << min_w, 1 << max_w); 181 182 if (seg_max > STEDMA40_MAX_SEG_SIZE) 183 seg_max -= (1 << max_w); 184 185 if (size <= seg_max) 186 return size; 187 188 if (size <= 2 * seg_max) 189 return ALIGN(size / 2, 1 << max_w); 190 191 return seg_max; 192 } 193 194 static struct d40_phy_lli * 195 d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, 196 dma_addr_t lli_phys, dma_addr_t first_phys, u32 reg_cfg, 197 struct stedma40_half_channel_info *info, 198 struct stedma40_half_channel_info *otherinfo, 199 unsigned long flags) 200 { 201 bool lastlink = flags & LLI_LAST_LINK; 202 bool addr_inc = flags & LLI_ADDR_INC; 203 bool term_int = flags & LLI_TERM_INT; 204 bool cyclic = flags & LLI_CYCLIC; 205 int err; 206 dma_addr_t next = lli_phys; 207 int size_rest = size; 208 int size_seg = 0; 209 210 /* 211 * This piece may be split up based on d40_seg_size(); we only want the 212 * term int on the last part. 213 */ 214 if (term_int) 215 flags &= ~LLI_TERM_INT; 216 217 do { 218 size_seg = d40_seg_size(size_rest, info->data_width, 219 otherinfo->data_width); 220 size_rest -= size_seg; 221 222 if (size_rest == 0 && term_int) 223 flags |= LLI_TERM_INT; 224 225 if (size_rest == 0 && lastlink) 226 next = cyclic ? first_phys : 0; 227 else 228 next = ALIGN(next + sizeof(struct d40_phy_lli), 229 D40_LLI_ALIGN); 230 231 err = d40_phy_fill_lli(lli, addr, size_seg, next, 232 reg_cfg, info, flags); 233 234 if (err) 235 goto err; 236 237 lli++; 238 if (addr_inc) 239 addr += size_seg; 240 } while (size_rest); 241 242 return lli; 243 244 err: 245 return NULL; 246 } 247 248 int d40_phy_sg_to_lli(struct scatterlist *sg, 249 int sg_len, 250 dma_addr_t target, 251 struct d40_phy_lli *lli_sg, 252 dma_addr_t lli_phys, 253 u32 reg_cfg, 254 struct stedma40_half_channel_info *info, 255 struct stedma40_half_channel_info *otherinfo, 256 unsigned long flags) 257 { 258 int total_size = 0; 259 int i; 260 struct scatterlist *current_sg = sg; 261 struct d40_phy_lli *lli = lli_sg; 262 dma_addr_t l_phys = lli_phys; 263 264 if (!target) 265 flags |= LLI_ADDR_INC; 266 267 for_each_sg(sg, current_sg, sg_len, i) { 268 dma_addr_t sg_addr = sg_dma_address(current_sg); 269 unsigned int len = sg_dma_len(current_sg); 270 dma_addr_t dst = target ?: sg_addr; 271 272 total_size += sg_dma_len(current_sg); 273 274 if (i == sg_len - 1) 275 flags |= LLI_TERM_INT | LLI_LAST_LINK; 276 277 l_phys = ALIGN(lli_phys + (lli - lli_sg) * 278 sizeof(struct d40_phy_lli), D40_LLI_ALIGN); 279 280 lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, lli_phys, 281 reg_cfg, info, otherinfo, flags); 282 283 if (lli == NULL) 284 return -EINVAL; 285 } 286 287 return total_size; 288 } 289 290 291 /* DMA logical lli operations */ 292 293 static void d40_log_lli_link(struct d40_log_lli *lli_dst, 294 struct d40_log_lli *lli_src, 295 int next, unsigned int flags) 296 { 297 bool interrupt = flags & LLI_TERM_INT; 298 u32 slos = 0; 299 u32 dlos = 0; 300 301 if (next != -EINVAL) { 302 slos = next * 2; 303 dlos = next * 2 + 1; 304 } 305 306 if (interrupt) { 307 lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; 308 lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; 309 } 310 311 lli_src->lcsp13 = (lli_src->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) | 312 (slos << D40_MEM_LCSP1_SLOS_POS); 313 314 lli_dst->lcsp13 = (lli_dst->lcsp13 & ~D40_MEM_LCSP1_SLOS_MASK) | 315 (dlos << D40_MEM_LCSP1_SLOS_POS); 316 } 317 318 void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, 319 struct d40_log_lli *lli_dst, 320 struct d40_log_lli *lli_src, 321 int next, unsigned int flags) 322 { 323 d40_log_lli_link(lli_dst, lli_src, next, flags); 324 325 writel_relaxed(lli_src->lcsp02, &lcpa[0].lcsp0); 326 writel_relaxed(lli_src->lcsp13, &lcpa[0].lcsp1); 327 writel_relaxed(lli_dst->lcsp02, &lcpa[0].lcsp2); 328 writel_relaxed(lli_dst->lcsp13, &lcpa[0].lcsp3); 329 } 330 331 void d40_log_lli_lcla_write(struct d40_log_lli *lcla, 332 struct d40_log_lli *lli_dst, 333 struct d40_log_lli *lli_src, 334 int next, unsigned int flags) 335 { 336 d40_log_lli_link(lli_dst, lli_src, next, flags); 337 338 writel_relaxed(lli_src->lcsp02, &lcla[0].lcsp02); 339 writel_relaxed(lli_src->lcsp13, &lcla[0].lcsp13); 340 writel_relaxed(lli_dst->lcsp02, &lcla[1].lcsp02); 341 writel_relaxed(lli_dst->lcsp13, &lcla[1].lcsp13); 342 } 343 344 static void d40_log_fill_lli(struct d40_log_lli *lli, 345 dma_addr_t data, u32 data_size, 346 u32 reg_cfg, 347 u32 data_width, 348 unsigned int flags) 349 { 350 bool addr_inc = flags & LLI_ADDR_INC; 351 352 lli->lcsp13 = reg_cfg; 353 354 /* The number of elements to transfer */ 355 lli->lcsp02 = ((data_size >> data_width) << 356 D40_MEM_LCSP0_ECNT_POS) & D40_MEM_LCSP0_ECNT_MASK; 357 358 BUG_ON((data_size >> data_width) > STEDMA40_MAX_SEG_SIZE); 359 360 /* 16 LSBs address of the current element */ 361 lli->lcsp02 |= data & D40_MEM_LCSP0_SPTR_MASK; 362 /* 16 MSBs address of the current element */ 363 lli->lcsp13 |= data & D40_MEM_LCSP1_SPTR_MASK; 364 365 if (addr_inc) 366 lli->lcsp13 |= D40_MEM_LCSP1_SCFG_INCR_MASK; 367 368 } 369 370 static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, 371 dma_addr_t addr, 372 int size, 373 u32 lcsp13, /* src or dst*/ 374 u32 data_width1, 375 u32 data_width2, 376 unsigned int flags) 377 { 378 bool addr_inc = flags & LLI_ADDR_INC; 379 struct d40_log_lli *lli = lli_sg; 380 int size_rest = size; 381 int size_seg = 0; 382 383 do { 384 size_seg = d40_seg_size(size_rest, data_width1, data_width2); 385 size_rest -= size_seg; 386 387 d40_log_fill_lli(lli, 388 addr, 389 size_seg, 390 lcsp13, data_width1, 391 flags); 392 if (addr_inc) 393 addr += size_seg; 394 lli++; 395 } while (size_rest); 396 397 return lli; 398 } 399 400 int d40_log_sg_to_lli(struct scatterlist *sg, 401 int sg_len, 402 dma_addr_t dev_addr, 403 struct d40_log_lli *lli_sg, 404 u32 lcsp13, /* src or dst*/ 405 u32 data_width1, u32 data_width2) 406 { 407 int total_size = 0; 408 struct scatterlist *current_sg = sg; 409 int i; 410 struct d40_log_lli *lli = lli_sg; 411 unsigned long flags = 0; 412 413 if (!dev_addr) 414 flags |= LLI_ADDR_INC; 415 416 for_each_sg(sg, current_sg, sg_len, i) { 417 dma_addr_t sg_addr = sg_dma_address(current_sg); 418 unsigned int len = sg_dma_len(current_sg); 419 dma_addr_t addr = dev_addr ?: sg_addr; 420 421 total_size += sg_dma_len(current_sg); 422 423 lli = d40_log_buf_to_lli(lli, addr, len, 424 lcsp13, 425 data_width1, 426 data_width2, 427 flags); 428 } 429 430 return total_size; 431 } 432