Loading arch/arm/plat-nomadik/include/plat/ste_dma40.h +3 −19 Original line number Diff line number Diff line Loading @@ -104,6 +104,8 @@ struct stedma40_half_channel_info { * * @dir: MEM 2 MEM, PERIPH 2 MEM , MEM 2 PERIPH, PERIPH 2 PERIPH * @high_priority: true if high-priority * @realtime: true if realtime mode is to be enabled. Only available on DMA40 * version 3+, i.e DB8500v2+ * @mode: channel mode: physical, logical, or operation * @mode_opt: options for the chosen channel mode * @src_dev_type: Src device type Loading @@ -119,6 +121,7 @@ struct stedma40_half_channel_info { struct stedma40_chan_cfg { enum stedma40_xfer_dir dir; bool high_priority; bool realtime; enum stedma40_mode mode; enum stedma40_mode_opt mode_opt; int src_dev_type; Loading Loading @@ -168,25 +171,6 @@ struct stedma40_platform_data { bool stedma40_filter(struct dma_chan *chan, void *data); /** * stedma40_memcpy_sg() - extension of the dma framework, memcpy to/from * scattergatter lists. * * @chan: dmaengine handle * @sgl_dst: Destination scatter list * @sgl_src: Source scatter list * @sgl_len: The length of each scatterlist. Both lists must be of equal length * and each element must match the corresponding element in the other scatter * list. * @flags: is actually enum dma_ctrl_flags. See dmaengine.h */ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, struct scatterlist *sgl_dst, struct scatterlist *sgl_src, unsigned int sgl_len, unsigned long flags); /** * stedma40_slave_mem() - Transfers a raw data buffer to or from a slave * (=device) Loading drivers/dma/ste_dma40.c +650 −752 File changed.Preview size limit exceeded, changes collapsed. Show changes drivers/dma/ste_dma40_ll.c +79 −139 Original line number Diff line number Diff line Loading @@ -125,13 +125,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg, static int d40_phy_fill_lli(struct d40_phy_lli *lli, dma_addr_t data, u32 data_size, int psize, dma_addr_t next_lli, u32 reg_cfg, bool term_int, u32 data_width, bool is_device) struct stedma40_half_channel_info *info, unsigned int flags) { bool addr_inc = flags & LLI_ADDR_INC; bool term_int = flags & LLI_TERM_INT; unsigned int data_width = info->data_width; int psize = info->psize; int num_elems; if (psize == STEDMA40_PSIZE_PHY_1) Loading @@ -154,7 +156,7 @@ static int d40_phy_fill_lli(struct d40_phy_lli *lli, * Distance to next element sized entry. * Usually the size of the element unless you want gaps. */ if (!is_device) if (addr_inc) lli->reg_elt |= (0x1 << data_width) << D40_SREG_ELEM_PHY_EIDX_POS; Loading Loading @@ -198,47 +200,51 @@ static int d40_seg_size(int size, int data_width1, int data_width2) return seg_max; } struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, int psize, dma_addr_t lli_phys, u32 reg_cfg, bool term_int, u32 data_width1, u32 data_width2, bool is_device) static struct d40_phy_lli * d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, dma_addr_t lli_phys, dma_addr_t first_phys, u32 reg_cfg, struct stedma40_half_channel_info *info, struct stedma40_half_channel_info *otherinfo, unsigned long flags) { bool lastlink = flags & LLI_LAST_LINK; bool addr_inc = flags & LLI_ADDR_INC; bool term_int = flags & LLI_TERM_INT; bool cyclic = flags & LLI_CYCLIC; int err; dma_addr_t next = lli_phys; int size_rest = size; int size_seg = 0; /* * This piece may be split up based on d40_seg_size(); we only want the * term int on the last part. */ if (term_int) flags &= ~LLI_TERM_INT; do { size_seg = d40_seg_size(size_rest, data_width1, data_width2); size_seg = d40_seg_size(size_rest, info->data_width, otherinfo->data_width); size_rest -= size_seg; if (term_int && size_rest == 0) next = 0; if (size_rest == 0 && term_int) flags |= LLI_TERM_INT; if (size_rest == 0 && lastlink) next = cyclic ? first_phys : 0; else next = ALIGN(next + sizeof(struct d40_phy_lli), D40_LLI_ALIGN); err = d40_phy_fill_lli(lli, addr, size_seg, psize, next, reg_cfg, !next, data_width1, is_device); err = d40_phy_fill_lli(lli, addr, size_seg, next, reg_cfg, info, flags); if (err) goto err; lli++; if (!is_device) if (addr_inc) addr += size_seg; } while (size_rest); Loading @@ -254,39 +260,35 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, struct d40_phy_lli *lli_sg, dma_addr_t lli_phys, u32 reg_cfg, u32 data_width1, u32 data_width2, int psize) struct stedma40_half_channel_info *info, struct stedma40_half_channel_info *otherinfo, unsigned long flags) { int total_size = 0; int i; struct scatterlist *current_sg = sg; dma_addr_t dst; struct d40_phy_lli *lli = lli_sg; dma_addr_t l_phys = lli_phys; if (!target) flags |= LLI_ADDR_INC; for_each_sg(sg, current_sg, sg_len, i) { dma_addr_t sg_addr = sg_dma_address(current_sg); unsigned int len = sg_dma_len(current_sg); dma_addr_t dst = target ?: sg_addr; total_size += sg_dma_len(current_sg); if (target) dst = target; else dst = sg_phys(current_sg); if (i == sg_len - 1) flags |= LLI_TERM_INT | LLI_LAST_LINK; l_phys = ALIGN(lli_phys + (lli - lli_sg) * sizeof(struct d40_phy_lli), D40_LLI_ALIGN); lli = d40_phy_buf_to_lli(lli, dst, sg_dma_len(current_sg), psize, l_phys, reg_cfg, sg_len - 1 == i, data_width1, data_width2, target == dst); lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, lli_phys, reg_cfg, info, otherinfo, flags); if (lli == NULL) return -EINVAL; } Loading @@ -295,45 +297,22 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, } void d40_phy_lli_write(void __iomem *virtbase, u32 phy_chan_num, struct d40_phy_lli *lli_dst, struct d40_phy_lli *lli_src) { writel(lli_src->reg_cfg, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSCFG); writel(lli_src->reg_elt, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT); writel(lli_src->reg_ptr, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSPTR); writel(lli_src->reg_lnk, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSLNK); writel(lli_dst->reg_cfg, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDCFG); writel(lli_dst->reg_elt, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT); writel(lli_dst->reg_ptr, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDPTR); writel(lli_dst->reg_lnk, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDLNK); } /* DMA logical lli operations */ static void d40_log_lli_link(struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next) int next, unsigned int flags) { bool interrupt = flags & LLI_TERM_INT; u32 slos = 0; u32 dlos = 0; if (next != -EINVAL) { slos = next * 2; dlos = next * 2 + 1; } else { } if (interrupt) { lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; } Loading @@ -348,9 +327,9 @@ static void d40_log_lli_link(struct d40_log_lli *lli_dst, void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next) int next, unsigned int flags) { d40_log_lli_link(lli_dst, lli_src, next); d40_log_lli_link(lli_dst, lli_src, next, flags); writel(lli_src->lcsp02, &lcpa[0].lcsp0); writel(lli_src->lcsp13, &lcpa[0].lcsp1); Loading @@ -361,9 +340,9 @@ void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, void d40_log_lli_lcla_write(struct d40_log_lli *lcla, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next) int next, unsigned int flags) { d40_log_lli_link(lli_dst, lli_src, next); d40_log_lli_link(lli_dst, lli_src, next, flags); writel(lli_src->lcsp02, &lcla[0].lcsp02); writel(lli_src->lcsp13, &lcla[0].lcsp13); Loading @@ -375,8 +354,10 @@ static void d40_log_fill_lli(struct d40_log_lli *lli, dma_addr_t data, u32 data_size, u32 reg_cfg, u32 data_width, bool addr_inc) unsigned int flags) { bool addr_inc = flags & LLI_ADDR_INC; lli->lcsp13 = reg_cfg; /* The number of elements to transfer */ Loading @@ -395,67 +376,15 @@ static void d40_log_fill_lli(struct d40_log_lli *lli, } int d40_log_sg_to_dev(struct scatterlist *sg, int sg_len, struct d40_log_lli_bidir *lli, struct d40_def_lcsp *lcsp, u32 src_data_width, u32 dst_data_width, enum dma_data_direction direction, dma_addr_t dev_addr) { int total_size = 0; struct scatterlist *current_sg = sg; int i; struct d40_log_lli *lli_src = lli->src; struct d40_log_lli *lli_dst = lli->dst; for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); if (direction == DMA_TO_DEVICE) { lli_src = d40_log_buf_to_lli(lli_src, sg_phys(current_sg), sg_dma_len(current_sg), lcsp->lcsp1, src_data_width, dst_data_width, true); lli_dst = d40_log_buf_to_lli(lli_dst, dev_addr, sg_dma_len(current_sg), lcsp->lcsp3, dst_data_width, src_data_width, false); } else { lli_dst = d40_log_buf_to_lli(lli_dst, sg_phys(current_sg), sg_dma_len(current_sg), lcsp->lcsp3, dst_data_width, src_data_width, true); lli_src = d40_log_buf_to_lli(lli_src, dev_addr, sg_dma_len(current_sg), lcsp->lcsp1, src_data_width, dst_data_width, false); } } return total_size; } struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, dma_addr_t addr, int size, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2, bool addr_inc) unsigned int flags) { bool addr_inc = flags & LLI_ADDR_INC; struct d40_log_lli *lli = lli_sg; int size_rest = size; int size_seg = 0; Loading @@ -468,7 +397,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, addr, size_seg, lcsp13, data_width1, addr_inc); flags); if (addr_inc) addr += size_seg; lli++; Loading @@ -479,6 +408,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, dma_addr_t dev_addr, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2) Loading @@ -487,14 +417,24 @@ int d40_log_sg_to_lli(struct scatterlist *sg, struct scatterlist *current_sg = sg; int i; struct d40_log_lli *lli = lli_sg; unsigned long flags = 0; if (!dev_addr) flags |= LLI_ADDR_INC; for_each_sg(sg, current_sg, sg_len, i) { dma_addr_t sg_addr = sg_dma_address(current_sg); unsigned int len = sg_dma_len(current_sg); dma_addr_t addr = dev_addr ?: sg_addr; total_size += sg_dma_len(current_sg); lli = d40_log_buf_to_lli(lli, sg_phys(current_sg), sg_dma_len(current_sg), lli = d40_log_buf_to_lli(lli, addr, len, lcsp13, data_width1, data_width2, true); data_width1, data_width2, flags); } return total_size; } drivers/dma/ste_dma40_ll.h +29 −37 Original line number Diff line number Diff line Loading @@ -163,6 +163,22 @@ #define D40_DREG_LCEIS1 0x0B4 #define D40_DREG_LCEIS2 0x0B8 #define D40_DREG_LCEIS3 0x0BC #define D40_DREG_PSEG1 0x110 #define D40_DREG_PSEG2 0x114 #define D40_DREG_PSEG3 0x118 #define D40_DREG_PSEG4 0x11C #define D40_DREG_PCEG1 0x120 #define D40_DREG_PCEG2 0x124 #define D40_DREG_PCEG3 0x128 #define D40_DREG_PCEG4 0x12C #define D40_DREG_RSEG1 0x130 #define D40_DREG_RSEG2 0x134 #define D40_DREG_RSEG3 0x138 #define D40_DREG_RSEG4 0x13C #define D40_DREG_RCEG1 0x140 #define D40_DREG_RCEG2 0x144 #define D40_DREG_RCEG3 0x148 #define D40_DREG_RCEG4 0x14C #define D40_DREG_STFU 0xFC8 #define D40_DREG_ICFG 0xFCC #define D40_DREG_PERIPHID0 0xFE0 Loading Loading @@ -277,6 +293,13 @@ struct d40_def_lcsp { /* Physical channels */ enum d40_lli_flags { LLI_ADDR_INC = 1 << 0, LLI_TERM_INT = 1 << 1, LLI_CYCLIC = 1 << 2, LLI_LAST_LINK = 1 << 3, }; void d40_phy_cfg(struct stedma40_chan_cfg *cfg, u32 *src_cfg, u32 *dst_cfg, Loading @@ -292,46 +315,15 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, struct d40_phy_lli *lli, dma_addr_t lli_phys, u32 reg_cfg, u32 data_width1, u32 data_width2, int psize); struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t data, u32 data_size, int psize, dma_addr_t next_lli, u32 reg_cfg, bool term_int, u32 data_width1, u32 data_width2, bool is_device); void d40_phy_lli_write(void __iomem *virtbase, u32 phy_chan_num, struct d40_phy_lli *lli_dst, struct d40_phy_lli *lli_src); struct stedma40_half_channel_info *info, struct stedma40_half_channel_info *otherinfo, unsigned long flags); /* Logical channels */ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, dma_addr_t addr, int size, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2, bool addr_inc); int d40_log_sg_to_dev(struct scatterlist *sg, int sg_len, struct d40_log_lli_bidir *lli, struct d40_def_lcsp *lcsp, u32 src_data_width, u32 dst_data_width, enum dma_data_direction direction, dma_addr_t dev_addr); int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, dma_addr_t dev_addr, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2); Loading @@ -339,11 +331,11 @@ int d40_log_sg_to_lli(struct scatterlist *sg, void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next); int next, unsigned int flags); void d40_log_lli_lcla_write(struct d40_log_lli *lcla, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next); int next, unsigned int flags); #endif /* STE_DMA40_LLI_H */ Loading
arch/arm/plat-nomadik/include/plat/ste_dma40.h +3 −19 Original line number Diff line number Diff line Loading @@ -104,6 +104,8 @@ struct stedma40_half_channel_info { * * @dir: MEM 2 MEM, PERIPH 2 MEM , MEM 2 PERIPH, PERIPH 2 PERIPH * @high_priority: true if high-priority * @realtime: true if realtime mode is to be enabled. Only available on DMA40 * version 3+, i.e DB8500v2+ * @mode: channel mode: physical, logical, or operation * @mode_opt: options for the chosen channel mode * @src_dev_type: Src device type Loading @@ -119,6 +121,7 @@ struct stedma40_half_channel_info { struct stedma40_chan_cfg { enum stedma40_xfer_dir dir; bool high_priority; bool realtime; enum stedma40_mode mode; enum stedma40_mode_opt mode_opt; int src_dev_type; Loading Loading @@ -168,25 +171,6 @@ struct stedma40_platform_data { bool stedma40_filter(struct dma_chan *chan, void *data); /** * stedma40_memcpy_sg() - extension of the dma framework, memcpy to/from * scattergatter lists. * * @chan: dmaengine handle * @sgl_dst: Destination scatter list * @sgl_src: Source scatter list * @sgl_len: The length of each scatterlist. Both lists must be of equal length * and each element must match the corresponding element in the other scatter * list. * @flags: is actually enum dma_ctrl_flags. See dmaengine.h */ struct dma_async_tx_descriptor *stedma40_memcpy_sg(struct dma_chan *chan, struct scatterlist *sgl_dst, struct scatterlist *sgl_src, unsigned int sgl_len, unsigned long flags); /** * stedma40_slave_mem() - Transfers a raw data buffer to or from a slave * (=device) Loading
drivers/dma/ste_dma40.c +650 −752 File changed.Preview size limit exceeded, changes collapsed. Show changes
drivers/dma/ste_dma40_ll.c +79 −139 Original line number Diff line number Diff line Loading @@ -125,13 +125,15 @@ void d40_phy_cfg(struct stedma40_chan_cfg *cfg, static int d40_phy_fill_lli(struct d40_phy_lli *lli, dma_addr_t data, u32 data_size, int psize, dma_addr_t next_lli, u32 reg_cfg, bool term_int, u32 data_width, bool is_device) struct stedma40_half_channel_info *info, unsigned int flags) { bool addr_inc = flags & LLI_ADDR_INC; bool term_int = flags & LLI_TERM_INT; unsigned int data_width = info->data_width; int psize = info->psize; int num_elems; if (psize == STEDMA40_PSIZE_PHY_1) Loading @@ -154,7 +156,7 @@ static int d40_phy_fill_lli(struct d40_phy_lli *lli, * Distance to next element sized entry. * Usually the size of the element unless you want gaps. */ if (!is_device) if (addr_inc) lli->reg_elt |= (0x1 << data_width) << D40_SREG_ELEM_PHY_EIDX_POS; Loading Loading @@ -198,47 +200,51 @@ static int d40_seg_size(int size, int data_width1, int data_width2) return seg_max; } struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, int psize, dma_addr_t lli_phys, u32 reg_cfg, bool term_int, u32 data_width1, u32 data_width2, bool is_device) static struct d40_phy_lli * d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t addr, u32 size, dma_addr_t lli_phys, dma_addr_t first_phys, u32 reg_cfg, struct stedma40_half_channel_info *info, struct stedma40_half_channel_info *otherinfo, unsigned long flags) { bool lastlink = flags & LLI_LAST_LINK; bool addr_inc = flags & LLI_ADDR_INC; bool term_int = flags & LLI_TERM_INT; bool cyclic = flags & LLI_CYCLIC; int err; dma_addr_t next = lli_phys; int size_rest = size; int size_seg = 0; /* * This piece may be split up based on d40_seg_size(); we only want the * term int on the last part. */ if (term_int) flags &= ~LLI_TERM_INT; do { size_seg = d40_seg_size(size_rest, data_width1, data_width2); size_seg = d40_seg_size(size_rest, info->data_width, otherinfo->data_width); size_rest -= size_seg; if (term_int && size_rest == 0) next = 0; if (size_rest == 0 && term_int) flags |= LLI_TERM_INT; if (size_rest == 0 && lastlink) next = cyclic ? first_phys : 0; else next = ALIGN(next + sizeof(struct d40_phy_lli), D40_LLI_ALIGN); err = d40_phy_fill_lli(lli, addr, size_seg, psize, next, reg_cfg, !next, data_width1, is_device); err = d40_phy_fill_lli(lli, addr, size_seg, next, reg_cfg, info, flags); if (err) goto err; lli++; if (!is_device) if (addr_inc) addr += size_seg; } while (size_rest); Loading @@ -254,39 +260,35 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, struct d40_phy_lli *lli_sg, dma_addr_t lli_phys, u32 reg_cfg, u32 data_width1, u32 data_width2, int psize) struct stedma40_half_channel_info *info, struct stedma40_half_channel_info *otherinfo, unsigned long flags) { int total_size = 0; int i; struct scatterlist *current_sg = sg; dma_addr_t dst; struct d40_phy_lli *lli = lli_sg; dma_addr_t l_phys = lli_phys; if (!target) flags |= LLI_ADDR_INC; for_each_sg(sg, current_sg, sg_len, i) { dma_addr_t sg_addr = sg_dma_address(current_sg); unsigned int len = sg_dma_len(current_sg); dma_addr_t dst = target ?: sg_addr; total_size += sg_dma_len(current_sg); if (target) dst = target; else dst = sg_phys(current_sg); if (i == sg_len - 1) flags |= LLI_TERM_INT | LLI_LAST_LINK; l_phys = ALIGN(lli_phys + (lli - lli_sg) * sizeof(struct d40_phy_lli), D40_LLI_ALIGN); lli = d40_phy_buf_to_lli(lli, dst, sg_dma_len(current_sg), psize, l_phys, reg_cfg, sg_len - 1 == i, data_width1, data_width2, target == dst); lli = d40_phy_buf_to_lli(lli, dst, len, l_phys, lli_phys, reg_cfg, info, otherinfo, flags); if (lli == NULL) return -EINVAL; } Loading @@ -295,45 +297,22 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, } void d40_phy_lli_write(void __iomem *virtbase, u32 phy_chan_num, struct d40_phy_lli *lli_dst, struct d40_phy_lli *lli_src) { writel(lli_src->reg_cfg, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSCFG); writel(lli_src->reg_elt, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSELT); writel(lli_src->reg_ptr, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSPTR); writel(lli_src->reg_lnk, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SSLNK); writel(lli_dst->reg_cfg, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDCFG); writel(lli_dst->reg_elt, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDELT); writel(lli_dst->reg_ptr, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDPTR); writel(lli_dst->reg_lnk, virtbase + D40_DREG_PCBASE + phy_chan_num * D40_DREG_PCDELTA + D40_CHAN_REG_SDLNK); } /* DMA logical lli operations */ static void d40_log_lli_link(struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next) int next, unsigned int flags) { bool interrupt = flags & LLI_TERM_INT; u32 slos = 0; u32 dlos = 0; if (next != -EINVAL) { slos = next * 2; dlos = next * 2 + 1; } else { } if (interrupt) { lli_dst->lcsp13 |= D40_MEM_LCSP1_SCFG_TIM_MASK; lli_dst->lcsp13 |= D40_MEM_LCSP3_DTCP_MASK; } Loading @@ -348,9 +327,9 @@ static void d40_log_lli_link(struct d40_log_lli *lli_dst, void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next) int next, unsigned int flags) { d40_log_lli_link(lli_dst, lli_src, next); d40_log_lli_link(lli_dst, lli_src, next, flags); writel(lli_src->lcsp02, &lcpa[0].lcsp0); writel(lli_src->lcsp13, &lcpa[0].lcsp1); Loading @@ -361,9 +340,9 @@ void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, void d40_log_lli_lcla_write(struct d40_log_lli *lcla, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next) int next, unsigned int flags) { d40_log_lli_link(lli_dst, lli_src, next); d40_log_lli_link(lli_dst, lli_src, next, flags); writel(lli_src->lcsp02, &lcla[0].lcsp02); writel(lli_src->lcsp13, &lcla[0].lcsp13); Loading @@ -375,8 +354,10 @@ static void d40_log_fill_lli(struct d40_log_lli *lli, dma_addr_t data, u32 data_size, u32 reg_cfg, u32 data_width, bool addr_inc) unsigned int flags) { bool addr_inc = flags & LLI_ADDR_INC; lli->lcsp13 = reg_cfg; /* The number of elements to transfer */ Loading @@ -395,67 +376,15 @@ static void d40_log_fill_lli(struct d40_log_lli *lli, } int d40_log_sg_to_dev(struct scatterlist *sg, int sg_len, struct d40_log_lli_bidir *lli, struct d40_def_lcsp *lcsp, u32 src_data_width, u32 dst_data_width, enum dma_data_direction direction, dma_addr_t dev_addr) { int total_size = 0; struct scatterlist *current_sg = sg; int i; struct d40_log_lli *lli_src = lli->src; struct d40_log_lli *lli_dst = lli->dst; for_each_sg(sg, current_sg, sg_len, i) { total_size += sg_dma_len(current_sg); if (direction == DMA_TO_DEVICE) { lli_src = d40_log_buf_to_lli(lli_src, sg_phys(current_sg), sg_dma_len(current_sg), lcsp->lcsp1, src_data_width, dst_data_width, true); lli_dst = d40_log_buf_to_lli(lli_dst, dev_addr, sg_dma_len(current_sg), lcsp->lcsp3, dst_data_width, src_data_width, false); } else { lli_dst = d40_log_buf_to_lli(lli_dst, sg_phys(current_sg), sg_dma_len(current_sg), lcsp->lcsp3, dst_data_width, src_data_width, true); lli_src = d40_log_buf_to_lli(lli_src, dev_addr, sg_dma_len(current_sg), lcsp->lcsp1, src_data_width, dst_data_width, false); } } return total_size; } struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, static struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, dma_addr_t addr, int size, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2, bool addr_inc) unsigned int flags) { bool addr_inc = flags & LLI_ADDR_INC; struct d40_log_lli *lli = lli_sg; int size_rest = size; int size_seg = 0; Loading @@ -468,7 +397,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, addr, size_seg, lcsp13, data_width1, addr_inc); flags); if (addr_inc) addr += size_seg; lli++; Loading @@ -479,6 +408,7 @@ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, dma_addr_t dev_addr, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2) Loading @@ -487,14 +417,24 @@ int d40_log_sg_to_lli(struct scatterlist *sg, struct scatterlist *current_sg = sg; int i; struct d40_log_lli *lli = lli_sg; unsigned long flags = 0; if (!dev_addr) flags |= LLI_ADDR_INC; for_each_sg(sg, current_sg, sg_len, i) { dma_addr_t sg_addr = sg_dma_address(current_sg); unsigned int len = sg_dma_len(current_sg); dma_addr_t addr = dev_addr ?: sg_addr; total_size += sg_dma_len(current_sg); lli = d40_log_buf_to_lli(lli, sg_phys(current_sg), sg_dma_len(current_sg), lli = d40_log_buf_to_lli(lli, addr, len, lcsp13, data_width1, data_width2, true); data_width1, data_width2, flags); } return total_size; }
drivers/dma/ste_dma40_ll.h +29 −37 Original line number Diff line number Diff line Loading @@ -163,6 +163,22 @@ #define D40_DREG_LCEIS1 0x0B4 #define D40_DREG_LCEIS2 0x0B8 #define D40_DREG_LCEIS3 0x0BC #define D40_DREG_PSEG1 0x110 #define D40_DREG_PSEG2 0x114 #define D40_DREG_PSEG3 0x118 #define D40_DREG_PSEG4 0x11C #define D40_DREG_PCEG1 0x120 #define D40_DREG_PCEG2 0x124 #define D40_DREG_PCEG3 0x128 #define D40_DREG_PCEG4 0x12C #define D40_DREG_RSEG1 0x130 #define D40_DREG_RSEG2 0x134 #define D40_DREG_RSEG3 0x138 #define D40_DREG_RSEG4 0x13C #define D40_DREG_RCEG1 0x140 #define D40_DREG_RCEG2 0x144 #define D40_DREG_RCEG3 0x148 #define D40_DREG_RCEG4 0x14C #define D40_DREG_STFU 0xFC8 #define D40_DREG_ICFG 0xFCC #define D40_DREG_PERIPHID0 0xFE0 Loading Loading @@ -277,6 +293,13 @@ struct d40_def_lcsp { /* Physical channels */ enum d40_lli_flags { LLI_ADDR_INC = 1 << 0, LLI_TERM_INT = 1 << 1, LLI_CYCLIC = 1 << 2, LLI_LAST_LINK = 1 << 3, }; void d40_phy_cfg(struct stedma40_chan_cfg *cfg, u32 *src_cfg, u32 *dst_cfg, Loading @@ -292,46 +315,15 @@ int d40_phy_sg_to_lli(struct scatterlist *sg, struct d40_phy_lli *lli, dma_addr_t lli_phys, u32 reg_cfg, u32 data_width1, u32 data_width2, int psize); struct d40_phy_lli *d40_phy_buf_to_lli(struct d40_phy_lli *lli, dma_addr_t data, u32 data_size, int psize, dma_addr_t next_lli, u32 reg_cfg, bool term_int, u32 data_width1, u32 data_width2, bool is_device); void d40_phy_lli_write(void __iomem *virtbase, u32 phy_chan_num, struct d40_phy_lli *lli_dst, struct d40_phy_lli *lli_src); struct stedma40_half_channel_info *info, struct stedma40_half_channel_info *otherinfo, unsigned long flags); /* Logical channels */ struct d40_log_lli *d40_log_buf_to_lli(struct d40_log_lli *lli_sg, dma_addr_t addr, int size, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2, bool addr_inc); int d40_log_sg_to_dev(struct scatterlist *sg, int sg_len, struct d40_log_lli_bidir *lli, struct d40_def_lcsp *lcsp, u32 src_data_width, u32 dst_data_width, enum dma_data_direction direction, dma_addr_t dev_addr); int d40_log_sg_to_lli(struct scatterlist *sg, int sg_len, dma_addr_t dev_addr, struct d40_log_lli *lli_sg, u32 lcsp13, /* src or dst*/ u32 data_width1, u32 data_width2); Loading @@ -339,11 +331,11 @@ int d40_log_sg_to_lli(struct scatterlist *sg, void d40_log_lli_lcpa_write(struct d40_log_lli_full *lcpa, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next); int next, unsigned int flags); void d40_log_lli_lcla_write(struct d40_log_lli *lcla, struct d40_log_lli *lli_dst, struct d40_log_lli *lli_src, int next); int next, unsigned int flags); #endif /* STE_DMA40_LLI_H */