1af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d8b46839SM'boumba Cedric Madianga /* 3d8b46839SM'boumba Cedric Madianga * Driver for STM32 DMA controller 4d8b46839SM'boumba Cedric Madianga * 5d8b46839SM'boumba Cedric Madianga * Inspired by dma-jz4740.c and tegra20-apb-dma.c 6d8b46839SM'boumba Cedric Madianga * 7d8b46839SM'boumba Cedric Madianga * Copyright (C) M'boumba Cedric Madianga 2015 8d8b46839SM'boumba Cedric Madianga * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com> 9a2b6103bSPierre Yves MORDRET * Pierre-Yves Mordret <pierre-yves.mordret@st.com> 10d8b46839SM'boumba Cedric Madianga */ 11d8b46839SM'boumba Cedric Madianga 12d8b46839SM'boumba Cedric Madianga #include <linux/clk.h> 13d8b46839SM'boumba Cedric Madianga #include <linux/delay.h> 14d8b46839SM'boumba Cedric Madianga #include <linux/dmaengine.h> 15d8b46839SM'boumba Cedric Madianga #include <linux/dma-mapping.h> 16d8b46839SM'boumba Cedric Madianga #include <linux/err.h> 17d8b46839SM'boumba Cedric Madianga #include <linux/init.h> 18d8b46839SM'boumba Cedric Madianga #include <linux/jiffies.h> 19d8b46839SM'boumba Cedric Madianga #include <linux/list.h> 20d8b46839SM'boumba Cedric Madianga #include <linux/module.h> 21d8b46839SM'boumba Cedric Madianga #include <linux/of.h> 22d8b46839SM'boumba Cedric Madianga #include <linux/of_device.h> 23d8b46839SM'boumba Cedric Madianga #include <linux/of_dma.h> 24d8b46839SM'boumba Cedric Madianga #include <linux/platform_device.h> 2548bc73baSPierre-Yves MORDRET #include <linux/pm_runtime.h> 26d8b46839SM'boumba Cedric Madianga #include <linux/reset.h> 27d8b46839SM'boumba Cedric Madianga #include <linux/sched.h> 28d8b46839SM'boumba Cedric Madianga #include <linux/slab.h> 29d8b46839SM'boumba Cedric Madianga 30d8b46839SM'boumba Cedric Madianga #include "virt-dma.h" 31d8b46839SM'boumba Cedric Madianga 32d8b46839SM'boumba Cedric Madianga #define STM32_DMA_LISR 0x0000 /* DMA Low Int Status Reg */ 33d8b46839SM'boumba Cedric Madianga #define STM32_DMA_HISR 0x0004 /* DMA High Int Status Reg */ 34d8b46839SM'boumba Cedric Madianga #define STM32_DMA_LIFCR 0x0008 /* DMA Low Int Flag Clear Reg */ 35d8b46839SM'boumba Cedric Madianga #define STM32_DMA_HIFCR 0x000c /* DMA High Int Flag Clear Reg */ 36d8b46839SM'boumba Cedric Madianga #define STM32_DMA_TCI BIT(5) /* Transfer Complete Interrupt */ 37c2d86b1cSPierre Yves MORDRET #define STM32_DMA_HTI BIT(4) /* Half Transfer Interrupt */ 38d8b46839SM'boumba Cedric Madianga #define STM32_DMA_TEI BIT(3) /* Transfer Error Interrupt */ 39d8b46839SM'boumba Cedric Madianga #define STM32_DMA_DMEI BIT(2) /* Direct Mode Error Interrupt */ 40d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FEI BIT(0) /* FIFO Error Interrupt */ 419df3bd55SPierre Yves MORDRET #define STM32_DMA_MASKI (STM32_DMA_TCI \ 429df3bd55SPierre Yves MORDRET | STM32_DMA_TEI \ 439df3bd55SPierre Yves MORDRET | STM32_DMA_DMEI \ 449df3bd55SPierre Yves MORDRET | STM32_DMA_FEI) 45d8b46839SM'boumba Cedric Madianga 46d8b46839SM'boumba Cedric Madianga /* DMA Stream x Configuration Register */ 47d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR(x) (0x0010 + 0x18 * (x)) /* x = 0..7 */ 48d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_REQ(n) ((n & 0x7) << 25) 49d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_MBURST_MASK GENMASK(24, 23) 50d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_MBURST(n) ((n & 0x3) << 23) 51d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PBURST_MASK GENMASK(22, 21) 52d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PBURST(n) ((n & 0x3) << 21) 53d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PL_MASK GENMASK(17, 16) 54d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PL(n) ((n & 0x3) << 16) 55d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_MSIZE_MASK GENMASK(14, 13) 56d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_MSIZE(n) ((n & 0x3) << 13) 57d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PSIZE_MASK GENMASK(12, 11) 58d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PSIZE(n) ((n & 0x3) << 11) 59d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PSIZE_GET(n) ((n & STM32_DMA_SCR_PSIZE_MASK) >> 11) 60d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_DIR_MASK GENMASK(7, 6) 61d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_DIR(n) ((n & 0x3) << 6) 62d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_CT BIT(19) /* Target in double buffer */ 63d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_DBM BIT(18) /* Double Buffer Mode */ 64d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PINCOS BIT(15) /* Peripheral inc offset size */ 65d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_MINC BIT(10) /* Memory increment mode */ 66d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PINC BIT(9) /* Peripheral increment mode */ 67d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_CIRC BIT(8) /* Circular mode */ 68d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PFCTRL BIT(5) /* Peripheral Flow Controller */ 69249d5531SPierre Yves MORDRET #define STM32_DMA_SCR_TCIE BIT(4) /* Transfer Complete Int Enable 70249d5531SPierre Yves MORDRET */ 71d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_TEIE BIT(2) /* Transfer Error Int Enable */ 72d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_DMEIE BIT(1) /* Direct Mode Err Int Enable */ 73d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_EN BIT(0) /* Stream Enable */ 74d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_CFG_MASK (STM32_DMA_SCR_PINC \ 75d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_MINC \ 76d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_PINCOS \ 77d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_PL_MASK) 78d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_IRQ_MASK (STM32_DMA_SCR_TCIE \ 79d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_TEIE \ 80d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_DMEIE) 81d8b46839SM'boumba Cedric Madianga 82d8b46839SM'boumba Cedric Madianga /* DMA Stream x number of data register */ 83d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SNDTR(x) (0x0014 + 0x18 * (x)) 84d8b46839SM'boumba Cedric Madianga 85d8b46839SM'boumba Cedric Madianga /* DMA stream peripheral address register */ 86d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SPAR(x) (0x0018 + 0x18 * (x)) 87d8b46839SM'boumba Cedric Madianga 88d8b46839SM'boumba Cedric Madianga /* DMA stream x memory 0 address register */ 89d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SM0AR(x) (0x001c + 0x18 * (x)) 90d8b46839SM'boumba Cedric Madianga 91d8b46839SM'boumba Cedric Madianga /* DMA stream x memory 1 address register */ 92d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SM1AR(x) (0x0020 + 0x18 * (x)) 93d8b46839SM'boumba Cedric Madianga 94d8b46839SM'boumba Cedric Madianga /* DMA stream x FIFO control register */ 95d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR(x) (0x0024 + 0x18 * (x)) 96d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_FTH_MASK GENMASK(1, 0) 97d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_FTH(n) (n & STM32_DMA_SFCR_FTH_MASK) 98d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_FEIE BIT(7) /* FIFO error interrupt enable */ 99d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_DMDIS BIT(2) /* Direct mode disable */ 100d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_MASK (STM32_DMA_SFCR_FEIE \ 101d8b46839SM'boumba Cedric Madianga | STM32_DMA_SFCR_DMDIS) 102d8b46839SM'boumba Cedric Madianga 103d8b46839SM'boumba Cedric Madianga /* DMA direction */ 104d8b46839SM'boumba Cedric Madianga #define STM32_DMA_DEV_TO_MEM 0x00 105d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MEM_TO_DEV 0x01 106d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MEM_TO_MEM 0x02 107d8b46839SM'boumba Cedric Madianga 108d8b46839SM'boumba Cedric Madianga /* DMA priority level */ 109d8b46839SM'boumba Cedric Madianga #define STM32_DMA_PRIORITY_LOW 0x00 110d8b46839SM'boumba Cedric Madianga #define STM32_DMA_PRIORITY_MEDIUM 0x01 111d8b46839SM'boumba Cedric Madianga #define STM32_DMA_PRIORITY_HIGH 0x02 112d8b46839SM'boumba Cedric Madianga #define STM32_DMA_PRIORITY_VERY_HIGH 0x03 113d8b46839SM'boumba Cedric Madianga 114d8b46839SM'boumba Cedric Madianga /* DMA FIFO threshold selection */ 115d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FIFO_THRESHOLD_1QUARTERFULL 0x00 116d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FIFO_THRESHOLD_HALFFULL 0x01 117d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL 0x02 118d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FIFO_THRESHOLD_FULL 0x03 119d8b46839SM'boumba Cedric Madianga 120d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MAX_DATA_ITEMS 0xffff 12180a76952SPierre Yves MORDRET /* 12280a76952SPierre Yves MORDRET * Valid transfer starts from @0 to @0xFFFE leading to unaligned scatter 12380a76952SPierre Yves MORDRET * gather at boundary. Thus it's safer to round down this value on FIFO 12480a76952SPierre Yves MORDRET * size (16 Bytes) 12580a76952SPierre Yves MORDRET */ 12680a76952SPierre Yves MORDRET #define STM32_DMA_ALIGNED_MAX_DATA_ITEMS \ 12780a76952SPierre Yves MORDRET ALIGN_DOWN(STM32_DMA_MAX_DATA_ITEMS, 16) 128d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MAX_CHANNELS 0x08 129d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MAX_REQUEST_ID 0x08 130d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MAX_DATA_PARAM 0x03 131a2b6103bSPierre Yves MORDRET #define STM32_DMA_FIFO_SIZE 16 /* FIFO is 16 bytes */ 132a2b6103bSPierre Yves MORDRET #define STM32_DMA_MIN_BURST 4 133276b0046SM'boumba Cedric Madianga #define STM32_DMA_MAX_BURST 16 134d8b46839SM'boumba Cedric Madianga 135951f44cbSPierre Yves MORDRET /* DMA Features */ 136951f44cbSPierre Yves MORDRET #define STM32_DMA_THRESHOLD_FTR_MASK GENMASK(1, 0) 137951f44cbSPierre Yves MORDRET #define STM32_DMA_THRESHOLD_FTR_GET(n) ((n) & STM32_DMA_THRESHOLD_FTR_MASK) 138951f44cbSPierre Yves MORDRET 139d8b46839SM'boumba Cedric Madianga enum stm32_dma_width { 140d8b46839SM'boumba Cedric Madianga STM32_DMA_BYTE, 141d8b46839SM'boumba Cedric Madianga STM32_DMA_HALF_WORD, 142d8b46839SM'boumba Cedric Madianga STM32_DMA_WORD, 143d8b46839SM'boumba Cedric Madianga }; 144d8b46839SM'boumba Cedric Madianga 145d8b46839SM'boumba Cedric Madianga enum stm32_dma_burst_size { 146d8b46839SM'boumba Cedric Madianga STM32_DMA_BURST_SINGLE, 147d8b46839SM'boumba Cedric Madianga STM32_DMA_BURST_INCR4, 148d8b46839SM'boumba Cedric Madianga STM32_DMA_BURST_INCR8, 149d8b46839SM'boumba Cedric Madianga STM32_DMA_BURST_INCR16, 150d8b46839SM'boumba Cedric Madianga }; 151d8b46839SM'boumba Cedric Madianga 152951f44cbSPierre Yves MORDRET /** 153951f44cbSPierre Yves MORDRET * struct stm32_dma_cfg - STM32 DMA custom configuration 154951f44cbSPierre Yves MORDRET * @channel_id: channel ID 155951f44cbSPierre Yves MORDRET * @request_line: DMA request 156951f44cbSPierre Yves MORDRET * @stream_config: 32bit mask specifying the DMA channel configuration 157951f44cbSPierre Yves MORDRET * @features: 32bit mask specifying the DMA Feature list 158951f44cbSPierre Yves MORDRET */ 159d8b46839SM'boumba Cedric Madianga struct stm32_dma_cfg { 160d8b46839SM'boumba Cedric Madianga u32 channel_id; 161d8b46839SM'boumba Cedric Madianga u32 request_line; 162d8b46839SM'boumba Cedric Madianga u32 stream_config; 163951f44cbSPierre Yves MORDRET u32 features; 164d8b46839SM'boumba Cedric Madianga }; 165d8b46839SM'boumba Cedric Madianga 166d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan_reg { 167d8b46839SM'boumba Cedric Madianga u32 dma_lisr; 168d8b46839SM'boumba Cedric Madianga u32 dma_hisr; 169d8b46839SM'boumba Cedric Madianga u32 dma_lifcr; 170d8b46839SM'boumba Cedric Madianga u32 dma_hifcr; 171d8b46839SM'boumba Cedric Madianga u32 dma_scr; 172d8b46839SM'boumba Cedric Madianga u32 dma_sndtr; 173d8b46839SM'boumba Cedric Madianga u32 dma_spar; 174d8b46839SM'boumba Cedric Madianga u32 dma_sm0ar; 175d8b46839SM'boumba Cedric Madianga u32 dma_sm1ar; 176d8b46839SM'boumba Cedric Madianga u32 dma_sfcr; 177d8b46839SM'boumba Cedric Madianga }; 178d8b46839SM'boumba Cedric Madianga 179d8b46839SM'boumba Cedric Madianga struct stm32_dma_sg_req { 180d8b46839SM'boumba Cedric Madianga u32 len; 181d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan_reg chan_reg; 182d8b46839SM'boumba Cedric Madianga }; 183d8b46839SM'boumba Cedric Madianga 184d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc { 185d8b46839SM'boumba Cedric Madianga struct virt_dma_desc vdesc; 186d8b46839SM'boumba Cedric Madianga bool cyclic; 187d8b46839SM'boumba Cedric Madianga u32 num_sgs; 188d8b46839SM'boumba Cedric Madianga struct stm32_dma_sg_req sg_req[]; 189d8b46839SM'boumba Cedric Madianga }; 190d8b46839SM'boumba Cedric Madianga 191d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan { 192d8b46839SM'boumba Cedric Madianga struct virt_dma_chan vchan; 193d8b46839SM'boumba Cedric Madianga bool config_init; 194d8b46839SM'boumba Cedric Madianga bool busy; 195d8b46839SM'boumba Cedric Madianga u32 id; 196d8b46839SM'boumba Cedric Madianga u32 irq; 197d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc; 198d8b46839SM'boumba Cedric Madianga u32 next_sg; 199d8b46839SM'boumba Cedric Madianga struct dma_slave_config dma_sconfig; 200d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan_reg chan_reg; 201951f44cbSPierre Yves MORDRET u32 threshold; 202a2b6103bSPierre Yves MORDRET u32 mem_burst; 203a2b6103bSPierre Yves MORDRET u32 mem_width; 204d8b46839SM'boumba Cedric Madianga }; 205d8b46839SM'boumba Cedric Madianga 206d8b46839SM'boumba Cedric Madianga struct stm32_dma_device { 207d8b46839SM'boumba Cedric Madianga struct dma_device ddev; 208d8b46839SM'boumba Cedric Madianga void __iomem *base; 209d8b46839SM'boumba Cedric Madianga struct clk *clk; 210d8b46839SM'boumba Cedric Madianga bool mem2mem; 211d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS]; 212d8b46839SM'boumba Cedric Madianga }; 213d8b46839SM'boumba Cedric Madianga 214d8b46839SM'boumba Cedric Madianga static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan) 215d8b46839SM'boumba Cedric Madianga { 216d8b46839SM'boumba Cedric Madianga return container_of(chan->vchan.chan.device, struct stm32_dma_device, 217d8b46839SM'boumba Cedric Madianga ddev); 218d8b46839SM'boumba Cedric Madianga } 219d8b46839SM'boumba Cedric Madianga 220d8b46839SM'boumba Cedric Madianga static struct stm32_dma_chan *to_stm32_dma_chan(struct dma_chan *c) 221d8b46839SM'boumba Cedric Madianga { 222d8b46839SM'boumba Cedric Madianga return container_of(c, struct stm32_dma_chan, vchan.chan); 223d8b46839SM'boumba Cedric Madianga } 224d8b46839SM'boumba Cedric Madianga 225d8b46839SM'boumba Cedric Madianga static struct stm32_dma_desc *to_stm32_dma_desc(struct virt_dma_desc *vdesc) 226d8b46839SM'boumba Cedric Madianga { 227d8b46839SM'boumba Cedric Madianga return container_of(vdesc, struct stm32_dma_desc, vdesc); 228d8b46839SM'boumba Cedric Madianga } 229d8b46839SM'boumba Cedric Madianga 230d8b46839SM'boumba Cedric Madianga static struct device *chan2dev(struct stm32_dma_chan *chan) 231d8b46839SM'boumba Cedric Madianga { 232d8b46839SM'boumba Cedric Madianga return &chan->vchan.chan.dev->device; 233d8b46839SM'boumba Cedric Madianga } 234d8b46839SM'boumba Cedric Madianga 235d8b46839SM'boumba Cedric Madianga static u32 stm32_dma_read(struct stm32_dma_device *dmadev, u32 reg) 236d8b46839SM'boumba Cedric Madianga { 237d8b46839SM'boumba Cedric Madianga return readl_relaxed(dmadev->base + reg); 238d8b46839SM'boumba Cedric Madianga } 239d8b46839SM'boumba Cedric Madianga 240d8b46839SM'boumba Cedric Madianga static void stm32_dma_write(struct stm32_dma_device *dmadev, u32 reg, u32 val) 241d8b46839SM'boumba Cedric Madianga { 242d8b46839SM'boumba Cedric Madianga writel_relaxed(val, dmadev->base + reg); 243d8b46839SM'boumba Cedric Madianga } 244d8b46839SM'boumba Cedric Madianga 245d8b46839SM'boumba Cedric Madianga static int stm32_dma_get_width(struct stm32_dma_chan *chan, 246d8b46839SM'boumba Cedric Madianga enum dma_slave_buswidth width) 247d8b46839SM'boumba Cedric Madianga { 248d8b46839SM'boumba Cedric Madianga switch (width) { 249d8b46839SM'boumba Cedric Madianga case DMA_SLAVE_BUSWIDTH_1_BYTE: 250d8b46839SM'boumba Cedric Madianga return STM32_DMA_BYTE; 251d8b46839SM'boumba Cedric Madianga case DMA_SLAVE_BUSWIDTH_2_BYTES: 252d8b46839SM'boumba Cedric Madianga return STM32_DMA_HALF_WORD; 253d8b46839SM'boumba Cedric Madianga case DMA_SLAVE_BUSWIDTH_4_BYTES: 254d8b46839SM'boumba Cedric Madianga return STM32_DMA_WORD; 255d8b46839SM'boumba Cedric Madianga default: 256d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Dma bus width not supported\n"); 257d8b46839SM'boumba Cedric Madianga return -EINVAL; 258d8b46839SM'boumba Cedric Madianga } 259d8b46839SM'boumba Cedric Madianga } 260d8b46839SM'boumba Cedric Madianga 261a2b6103bSPierre Yves MORDRET static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, 262a2b6103bSPierre Yves MORDRET u32 threshold) 263a2b6103bSPierre Yves MORDRET { 264a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth max_width; 265a2b6103bSPierre Yves MORDRET 266a2b6103bSPierre Yves MORDRET if (threshold == STM32_DMA_FIFO_THRESHOLD_FULL) 267a2b6103bSPierre Yves MORDRET max_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 268a2b6103bSPierre Yves MORDRET else 269a2b6103bSPierre Yves MORDRET max_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 270a2b6103bSPierre Yves MORDRET 271a2b6103bSPierre Yves MORDRET while ((buf_len < max_width || buf_len % max_width) && 272a2b6103bSPierre Yves MORDRET max_width > DMA_SLAVE_BUSWIDTH_1_BYTE) 273a2b6103bSPierre Yves MORDRET max_width = max_width >> 1; 274a2b6103bSPierre Yves MORDRET 275a2b6103bSPierre Yves MORDRET return max_width; 276a2b6103bSPierre Yves MORDRET } 277a2b6103bSPierre Yves MORDRET 278a2b6103bSPierre Yves MORDRET static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, 279a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth width) 280a2b6103bSPierre Yves MORDRET { 281a2b6103bSPierre Yves MORDRET u32 remaining; 282a2b6103bSPierre Yves MORDRET 283a2b6103bSPierre Yves MORDRET if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) { 284a2b6103bSPierre Yves MORDRET if (burst != 0) { 285a2b6103bSPierre Yves MORDRET /* 286a2b6103bSPierre Yves MORDRET * If number of beats fit in several whole bursts 287a2b6103bSPierre Yves MORDRET * this configuration is allowed. 288a2b6103bSPierre Yves MORDRET */ 289a2b6103bSPierre Yves MORDRET remaining = ((STM32_DMA_FIFO_SIZE / width) * 290a2b6103bSPierre Yves MORDRET (threshold + 1) / 4) % burst; 291a2b6103bSPierre Yves MORDRET 292a2b6103bSPierre Yves MORDRET if (remaining == 0) 293a2b6103bSPierre Yves MORDRET return true; 294a2b6103bSPierre Yves MORDRET } else { 295a2b6103bSPierre Yves MORDRET return true; 296a2b6103bSPierre Yves MORDRET } 297a2b6103bSPierre Yves MORDRET } 298a2b6103bSPierre Yves MORDRET 299a2b6103bSPierre Yves MORDRET return false; 300a2b6103bSPierre Yves MORDRET } 301a2b6103bSPierre Yves MORDRET 302a2b6103bSPierre Yves MORDRET static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold) 303a2b6103bSPierre Yves MORDRET { 304cc832dc8SPierre-Yves MORDRET /* 305cc832dc8SPierre-Yves MORDRET * Buffer or period length has to be aligned on FIFO depth. 306cc832dc8SPierre-Yves MORDRET * Otherwise bytes may be stuck within FIFO at buffer or period 307cc832dc8SPierre-Yves MORDRET * length. 308cc832dc8SPierre-Yves MORDRET */ 309cc832dc8SPierre-Yves MORDRET return ((buf_len % ((threshold + 1) * 4)) == 0); 310a2b6103bSPierre Yves MORDRET } 311a2b6103bSPierre Yves MORDRET 312a2b6103bSPierre Yves MORDRET static u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold, 313a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth width) 314a2b6103bSPierre Yves MORDRET { 315a2b6103bSPierre Yves MORDRET u32 best_burst = max_burst; 316a2b6103bSPierre Yves MORDRET 317a2b6103bSPierre Yves MORDRET if (best_burst == 1 || !stm32_dma_is_burst_possible(buf_len, threshold)) 318a2b6103bSPierre Yves MORDRET return 0; 319a2b6103bSPierre Yves MORDRET 320a2b6103bSPierre Yves MORDRET while ((buf_len < best_burst * width && best_burst > 1) || 321a2b6103bSPierre Yves MORDRET !stm32_dma_fifo_threshold_is_allowed(best_burst, threshold, 322a2b6103bSPierre Yves MORDRET width)) { 323a2b6103bSPierre Yves MORDRET if (best_burst > STM32_DMA_MIN_BURST) 324a2b6103bSPierre Yves MORDRET best_burst = best_burst >> 1; 325a2b6103bSPierre Yves MORDRET else 326a2b6103bSPierre Yves MORDRET best_burst = 0; 327a2b6103bSPierre Yves MORDRET } 328a2b6103bSPierre Yves MORDRET 329a2b6103bSPierre Yves MORDRET return best_burst; 330a2b6103bSPierre Yves MORDRET } 331a2b6103bSPierre Yves MORDRET 332d8b46839SM'boumba Cedric Madianga static int stm32_dma_get_burst(struct stm32_dma_chan *chan, u32 maxburst) 333d8b46839SM'boumba Cedric Madianga { 334d8b46839SM'boumba Cedric Madianga switch (maxburst) { 335d8b46839SM'boumba Cedric Madianga case 0: 336d8b46839SM'boumba Cedric Madianga case 1: 337d8b46839SM'boumba Cedric Madianga return STM32_DMA_BURST_SINGLE; 338d8b46839SM'boumba Cedric Madianga case 4: 339d8b46839SM'boumba Cedric Madianga return STM32_DMA_BURST_INCR4; 340d8b46839SM'boumba Cedric Madianga case 8: 341d8b46839SM'boumba Cedric Madianga return STM32_DMA_BURST_INCR8; 342d8b46839SM'boumba Cedric Madianga case 16: 343d8b46839SM'boumba Cedric Madianga return STM32_DMA_BURST_INCR16; 344d8b46839SM'boumba Cedric Madianga default: 345d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Dma burst size not supported\n"); 346d8b46839SM'boumba Cedric Madianga return -EINVAL; 347d8b46839SM'boumba Cedric Madianga } 348d8b46839SM'boumba Cedric Madianga } 349d8b46839SM'boumba Cedric Madianga 350d8b46839SM'boumba Cedric Madianga static void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan, 351a2b6103bSPierre Yves MORDRET u32 src_burst, u32 dst_burst) 352d8b46839SM'boumba Cedric Madianga { 353d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_MASK; 354d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_DMEIE; 355d8b46839SM'boumba Cedric Madianga 356a2b6103bSPierre Yves MORDRET if (!src_burst && !dst_burst) { 357d8b46839SM'boumba Cedric Madianga /* Using direct mode */ 358d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_DMEIE; 359d8b46839SM'boumba Cedric Madianga } else { 360d8b46839SM'boumba Cedric Madianga /* Using FIFO mode */ 361d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_MASK; 362d8b46839SM'boumba Cedric Madianga } 363d8b46839SM'boumba Cedric Madianga } 364d8b46839SM'boumba Cedric Madianga 365d8b46839SM'boumba Cedric Madianga static int stm32_dma_slave_config(struct dma_chan *c, 366d8b46839SM'boumba Cedric Madianga struct dma_slave_config *config) 367d8b46839SM'boumba Cedric Madianga { 368d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 369d8b46839SM'boumba Cedric Madianga 370d8b46839SM'boumba Cedric Madianga memcpy(&chan->dma_sconfig, config, sizeof(*config)); 371d8b46839SM'boumba Cedric Madianga 372d8b46839SM'boumba Cedric Madianga chan->config_init = true; 373d8b46839SM'boumba Cedric Madianga 374d8b46839SM'boumba Cedric Madianga return 0; 375d8b46839SM'boumba Cedric Madianga } 376d8b46839SM'boumba Cedric Madianga 377d8b46839SM'boumba Cedric Madianga static u32 stm32_dma_irq_status(struct stm32_dma_chan *chan) 378d8b46839SM'boumba Cedric Madianga { 379d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 380d8b46839SM'boumba Cedric Madianga u32 flags, dma_isr; 381d8b46839SM'boumba Cedric Madianga 382d8b46839SM'boumba Cedric Madianga /* 383d8b46839SM'boumba Cedric Madianga * Read "flags" from DMA_xISR register corresponding to the selected 384d8b46839SM'boumba Cedric Madianga * DMA channel at the correct bit offset inside that register. 385d8b46839SM'boumba Cedric Madianga * 386d8b46839SM'boumba Cedric Madianga * If (ch % 4) is 2 or 3, left shift the mask by 16 bits. 387d8b46839SM'boumba Cedric Madianga * If (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits. 388d8b46839SM'boumba Cedric Madianga */ 389d8b46839SM'boumba Cedric Madianga 390d8b46839SM'boumba Cedric Madianga if (chan->id & 4) 391d8b46839SM'boumba Cedric Madianga dma_isr = stm32_dma_read(dmadev, STM32_DMA_HISR); 392d8b46839SM'boumba Cedric Madianga else 393d8b46839SM'boumba Cedric Madianga dma_isr = stm32_dma_read(dmadev, STM32_DMA_LISR); 394d8b46839SM'boumba Cedric Madianga 395d8b46839SM'boumba Cedric Madianga flags = dma_isr >> (((chan->id & 2) << 3) | ((chan->id & 1) * 6)); 396d8b46839SM'boumba Cedric Madianga 3979df3bd55SPierre Yves MORDRET return flags & STM32_DMA_MASKI; 398d8b46839SM'boumba Cedric Madianga } 399d8b46839SM'boumba Cedric Madianga 400d8b46839SM'boumba Cedric Madianga static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) 401d8b46839SM'boumba Cedric Madianga { 402d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 403d8b46839SM'boumba Cedric Madianga u32 dma_ifcr; 404d8b46839SM'boumba Cedric Madianga 405d8b46839SM'boumba Cedric Madianga /* 406d8b46839SM'boumba Cedric Madianga * Write "flags" to the DMA_xIFCR register corresponding to the selected 407d8b46839SM'boumba Cedric Madianga * DMA channel at the correct bit offset inside that register. 408d8b46839SM'boumba Cedric Madianga * 409d8b46839SM'boumba Cedric Madianga * If (ch % 4) is 2 or 3, left shift the mask by 16 bits. 410d8b46839SM'boumba Cedric Madianga * If (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits. 411d8b46839SM'boumba Cedric Madianga */ 4129df3bd55SPierre Yves MORDRET flags &= STM32_DMA_MASKI; 413d8b46839SM'boumba Cedric Madianga dma_ifcr = flags << (((chan->id & 2) << 3) | ((chan->id & 1) * 6)); 414d8b46839SM'boumba Cedric Madianga 415d8b46839SM'boumba Cedric Madianga if (chan->id & 4) 416d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_HIFCR, dma_ifcr); 417d8b46839SM'boumba Cedric Madianga else 418d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_LIFCR, dma_ifcr); 419d8b46839SM'boumba Cedric Madianga } 420d8b46839SM'boumba Cedric Madianga 421d8b46839SM'boumba Cedric Madianga static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) 422d8b46839SM'boumba Cedric Madianga { 423d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 424d8b46839SM'boumba Cedric Madianga unsigned long timeout = jiffies + msecs_to_jiffies(5000); 425d8b46839SM'boumba Cedric Madianga u32 dma_scr, id; 426d8b46839SM'boumba Cedric Madianga 427d8b46839SM'boumba Cedric Madianga id = chan->id; 428d8b46839SM'boumba Cedric Madianga dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 429d8b46839SM'boumba Cedric Madianga 430d8b46839SM'boumba Cedric Madianga if (dma_scr & STM32_DMA_SCR_EN) { 431d8b46839SM'boumba Cedric Madianga dma_scr &= ~STM32_DMA_SCR_EN; 432d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SCR(id), dma_scr); 433d8b46839SM'boumba Cedric Madianga 434d8b46839SM'boumba Cedric Madianga do { 435d8b46839SM'boumba Cedric Madianga dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 436d8b46839SM'boumba Cedric Madianga dma_scr &= STM32_DMA_SCR_EN; 437d8b46839SM'boumba Cedric Madianga if (!dma_scr) 438d8b46839SM'boumba Cedric Madianga break; 439d8b46839SM'boumba Cedric Madianga 440d8b46839SM'boumba Cedric Madianga if (time_after_eq(jiffies, timeout)) { 441d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "%s: timeout!\n", 442d8b46839SM'boumba Cedric Madianga __func__); 443d8b46839SM'boumba Cedric Madianga return -EBUSY; 444d8b46839SM'boumba Cedric Madianga } 445d8b46839SM'boumba Cedric Madianga cond_resched(); 446d8b46839SM'boumba Cedric Madianga } while (1); 447d8b46839SM'boumba Cedric Madianga } 448d8b46839SM'boumba Cedric Madianga 449d8b46839SM'boumba Cedric Madianga return 0; 450d8b46839SM'boumba Cedric Madianga } 451d8b46839SM'boumba Cedric Madianga 452d8b46839SM'boumba Cedric Madianga static void stm32_dma_stop(struct stm32_dma_chan *chan) 453d8b46839SM'boumba Cedric Madianga { 454d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 455d8b46839SM'boumba Cedric Madianga u32 dma_scr, dma_sfcr, status; 456d8b46839SM'boumba Cedric Madianga int ret; 457d8b46839SM'boumba Cedric Madianga 458d8b46839SM'boumba Cedric Madianga /* Disable interrupts */ 459d8b46839SM'boumba Cedric Madianga dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 460d8b46839SM'boumba Cedric Madianga dma_scr &= ~STM32_DMA_SCR_IRQ_MASK; 461d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); 462d8b46839SM'boumba Cedric Madianga dma_sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); 463d8b46839SM'boumba Cedric Madianga dma_sfcr &= ~STM32_DMA_SFCR_FEIE; 464d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), dma_sfcr); 465d8b46839SM'boumba Cedric Madianga 466d8b46839SM'boumba Cedric Madianga /* Disable DMA */ 467d8b46839SM'boumba Cedric Madianga ret = stm32_dma_disable_chan(chan); 468d8b46839SM'boumba Cedric Madianga if (ret < 0) 469d8b46839SM'boumba Cedric Madianga return; 470d8b46839SM'boumba Cedric Madianga 471d8b46839SM'boumba Cedric Madianga /* Clear interrupt status if it is there */ 472d8b46839SM'boumba Cedric Madianga status = stm32_dma_irq_status(chan); 473d8b46839SM'boumba Cedric Madianga if (status) { 474d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "%s(): clearing interrupt: 0x%08x\n", 475d8b46839SM'boumba Cedric Madianga __func__, status); 476d8b46839SM'boumba Cedric Madianga stm32_dma_irq_clear(chan, status); 477d8b46839SM'boumba Cedric Madianga } 478d8b46839SM'boumba Cedric Madianga 479d8b46839SM'boumba Cedric Madianga chan->busy = false; 480d8b46839SM'boumba Cedric Madianga } 481d8b46839SM'boumba Cedric Madianga 482d8b46839SM'boumba Cedric Madianga static int stm32_dma_terminate_all(struct dma_chan *c) 483d8b46839SM'boumba Cedric Madianga { 484d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 485d8b46839SM'boumba Cedric Madianga unsigned long flags; 486d8b46839SM'boumba Cedric Madianga LIST_HEAD(head); 487d8b46839SM'boumba Cedric Madianga 488d8b46839SM'boumba Cedric Madianga spin_lock_irqsave(&chan->vchan.lock, flags); 489d8b46839SM'boumba Cedric Madianga 490d8b46839SM'boumba Cedric Madianga if (chan->busy) { 491d8b46839SM'boumba Cedric Madianga stm32_dma_stop(chan); 492d8b46839SM'boumba Cedric Madianga chan->desc = NULL; 493d8b46839SM'boumba Cedric Madianga } 494d8b46839SM'boumba Cedric Madianga 495d8b46839SM'boumba Cedric Madianga vchan_get_all_descriptors(&chan->vchan, &head); 496d8b46839SM'boumba Cedric Madianga spin_unlock_irqrestore(&chan->vchan.lock, flags); 497d8b46839SM'boumba Cedric Madianga vchan_dma_desc_free_list(&chan->vchan, &head); 498d8b46839SM'boumba Cedric Madianga 499d8b46839SM'boumba Cedric Madianga return 0; 500d8b46839SM'boumba Cedric Madianga } 501d8b46839SM'boumba Cedric Madianga 502dc808675SM'boumba Cedric Madianga static void stm32_dma_synchronize(struct dma_chan *c) 503dc808675SM'boumba Cedric Madianga { 504dc808675SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 505dc808675SM'boumba Cedric Madianga 506dc808675SM'boumba Cedric Madianga vchan_synchronize(&chan->vchan); 507dc808675SM'boumba Cedric Madianga } 508dc808675SM'boumba Cedric Madianga 509d8b46839SM'boumba Cedric Madianga static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) 510d8b46839SM'boumba Cedric Madianga { 511d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 512d8b46839SM'boumba Cedric Madianga u32 scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 513d8b46839SM'boumba Cedric Madianga u32 ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); 514d8b46839SM'boumba Cedric Madianga u32 spar = stm32_dma_read(dmadev, STM32_DMA_SPAR(chan->id)); 515d8b46839SM'boumba Cedric Madianga u32 sm0ar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(chan->id)); 516d8b46839SM'boumba Cedric Madianga u32 sm1ar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(chan->id)); 517d8b46839SM'boumba Cedric Madianga u32 sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); 518d8b46839SM'boumba Cedric Madianga 519d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SCR: 0x%08x\n", scr); 520d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "NDTR: 0x%08x\n", ndtr); 521d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SPAR: 0x%08x\n", spar); 522d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SM0AR: 0x%08x\n", sm0ar); 523d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SM1AR: 0x%08x\n", sm1ar); 524d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); 525d8b46839SM'boumba Cedric Madianga } 526d8b46839SM'boumba Cedric Madianga 527e57cb3b3SPierre Yves MORDRET static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan); 528e57cb3b3SPierre Yves MORDRET 5298d1b76f0SM'boumba Cedric Madianga static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) 530d8b46839SM'boumba Cedric Madianga { 531d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 532d8b46839SM'boumba Cedric Madianga struct virt_dma_desc *vdesc; 533d8b46839SM'boumba Cedric Madianga struct stm32_dma_sg_req *sg_req; 534d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan_reg *reg; 535d8b46839SM'boumba Cedric Madianga u32 status; 536d8b46839SM'boumba Cedric Madianga int ret; 537d8b46839SM'boumba Cedric Madianga 538d8b46839SM'boumba Cedric Madianga ret = stm32_dma_disable_chan(chan); 539d8b46839SM'boumba Cedric Madianga if (ret < 0) 5408d1b76f0SM'boumba Cedric Madianga return; 541d8b46839SM'boumba Cedric Madianga 542d8b46839SM'boumba Cedric Madianga if (!chan->desc) { 543d8b46839SM'boumba Cedric Madianga vdesc = vchan_next_desc(&chan->vchan); 544d8b46839SM'boumba Cedric Madianga if (!vdesc) 5458d1b76f0SM'boumba Cedric Madianga return; 546d8b46839SM'boumba Cedric Madianga 547d8b46839SM'boumba Cedric Madianga chan->desc = to_stm32_dma_desc(vdesc); 548d8b46839SM'boumba Cedric Madianga chan->next_sg = 0; 549d8b46839SM'boumba Cedric Madianga } 550d8b46839SM'boumba Cedric Madianga 551d8b46839SM'boumba Cedric Madianga if (chan->next_sg == chan->desc->num_sgs) 552d8b46839SM'boumba Cedric Madianga chan->next_sg = 0; 553d8b46839SM'boumba Cedric Madianga 554d8b46839SM'boumba Cedric Madianga sg_req = &chan->desc->sg_req[chan->next_sg]; 555d8b46839SM'boumba Cedric Madianga reg = &sg_req->chan_reg; 556d8b46839SM'boumba Cedric Madianga 557d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); 558d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar); 559d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SM0AR(chan->id), reg->dma_sm0ar); 560d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), reg->dma_sfcr); 561d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SM1AR(chan->id), reg->dma_sm1ar); 562d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), reg->dma_sndtr); 563d8b46839SM'boumba Cedric Madianga 564d8b46839SM'boumba Cedric Madianga chan->next_sg++; 565d8b46839SM'boumba Cedric Madianga 566d8b46839SM'boumba Cedric Madianga /* Clear interrupt status if it is there */ 567d8b46839SM'boumba Cedric Madianga status = stm32_dma_irq_status(chan); 568d8b46839SM'boumba Cedric Madianga if (status) 569d8b46839SM'boumba Cedric Madianga stm32_dma_irq_clear(chan, status); 570d8b46839SM'boumba Cedric Madianga 571e57cb3b3SPierre Yves MORDRET if (chan->desc->cyclic) 572e57cb3b3SPierre Yves MORDRET stm32_dma_configure_next_sg(chan); 573e57cb3b3SPierre Yves MORDRET 574d8b46839SM'boumba Cedric Madianga stm32_dma_dump_reg(chan); 575d8b46839SM'boumba Cedric Madianga 576d8b46839SM'boumba Cedric Madianga /* Start DMA */ 577d8b46839SM'boumba Cedric Madianga reg->dma_scr |= STM32_DMA_SCR_EN; 578d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); 579d8b46839SM'boumba Cedric Madianga 580d8b46839SM'boumba Cedric Madianga chan->busy = true; 581d8b46839SM'boumba Cedric Madianga 58290ec93cbSBenjamin Gaignard dev_dbg(chan2dev(chan), "vchan %pK: started\n", &chan->vchan); 583d8b46839SM'boumba Cedric Madianga } 584d8b46839SM'boumba Cedric Madianga 585d8b46839SM'boumba Cedric Madianga static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) 586d8b46839SM'boumba Cedric Madianga { 587d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 588d8b46839SM'boumba Cedric Madianga struct stm32_dma_sg_req *sg_req; 589d8b46839SM'boumba Cedric Madianga u32 dma_scr, dma_sm0ar, dma_sm1ar, id; 590d8b46839SM'boumba Cedric Madianga 591d8b46839SM'boumba Cedric Madianga id = chan->id; 592d8b46839SM'boumba Cedric Madianga dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 593d8b46839SM'boumba Cedric Madianga 594d8b46839SM'boumba Cedric Madianga if (dma_scr & STM32_DMA_SCR_DBM) { 595d8b46839SM'boumba Cedric Madianga if (chan->next_sg == chan->desc->num_sgs) 596d8b46839SM'boumba Cedric Madianga chan->next_sg = 0; 597d8b46839SM'boumba Cedric Madianga 598d8b46839SM'boumba Cedric Madianga sg_req = &chan->desc->sg_req[chan->next_sg]; 599d8b46839SM'boumba Cedric Madianga 600d8b46839SM'boumba Cedric Madianga if (dma_scr & STM32_DMA_SCR_CT) { 601d8b46839SM'boumba Cedric Madianga dma_sm0ar = sg_req->chan_reg.dma_sm0ar; 602d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar); 603d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n", 604d8b46839SM'boumba Cedric Madianga stm32_dma_read(dmadev, STM32_DMA_SM0AR(id))); 605d8b46839SM'boumba Cedric Madianga } else { 606d8b46839SM'boumba Cedric Madianga dma_sm1ar = sg_req->chan_reg.dma_sm1ar; 607d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar); 608d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n", 609d8b46839SM'boumba Cedric Madianga stm32_dma_read(dmadev, STM32_DMA_SM1AR(id))); 610d8b46839SM'boumba Cedric Madianga } 611d8b46839SM'boumba Cedric Madianga } 612d8b46839SM'boumba Cedric Madianga } 613d8b46839SM'boumba Cedric Madianga 614d8b46839SM'boumba Cedric Madianga static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan) 615d8b46839SM'boumba Cedric Madianga { 616d8b46839SM'boumba Cedric Madianga if (chan->desc) { 617d8b46839SM'boumba Cedric Madianga if (chan->desc->cyclic) { 618d8b46839SM'boumba Cedric Madianga vchan_cyclic_callback(&chan->desc->vdesc); 6192b12c558SM'boumba Cedric Madianga chan->next_sg++; 620d8b46839SM'boumba Cedric Madianga stm32_dma_configure_next_sg(chan); 621d8b46839SM'boumba Cedric Madianga } else { 622d8b46839SM'boumba Cedric Madianga chan->busy = false; 623d8b46839SM'boumba Cedric Madianga if (chan->next_sg == chan->desc->num_sgs) { 624d8b46839SM'boumba Cedric Madianga list_del(&chan->desc->vdesc.node); 625d8b46839SM'boumba Cedric Madianga vchan_cookie_complete(&chan->desc->vdesc); 626d8b46839SM'boumba Cedric Madianga chan->desc = NULL; 627d8b46839SM'boumba Cedric Madianga } 628d8b46839SM'boumba Cedric Madianga stm32_dma_start_transfer(chan); 629d8b46839SM'boumba Cedric Madianga } 630d8b46839SM'boumba Cedric Madianga } 631d8b46839SM'boumba Cedric Madianga } 632d8b46839SM'boumba Cedric Madianga 633d8b46839SM'boumba Cedric Madianga static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) 634d8b46839SM'boumba Cedric Madianga { 635d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = devid; 636d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 637ca4c72c0SPierre-Yves MORDRET u32 status, scr, sfcr; 638d8b46839SM'boumba Cedric Madianga 639d8b46839SM'boumba Cedric Madianga spin_lock(&chan->vchan.lock); 640d8b46839SM'boumba Cedric Madianga 641d8b46839SM'boumba Cedric Madianga status = stm32_dma_irq_status(chan); 642d8b46839SM'boumba Cedric Madianga scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 643ca4c72c0SPierre-Yves MORDRET sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); 644d8b46839SM'boumba Cedric Madianga 645c2d86b1cSPierre Yves MORDRET if (status & STM32_DMA_TCI) { 646d8b46839SM'boumba Cedric Madianga stm32_dma_irq_clear(chan, STM32_DMA_TCI); 647c2d86b1cSPierre Yves MORDRET if (scr & STM32_DMA_SCR_TCIE) 648d8b46839SM'boumba Cedric Madianga stm32_dma_handle_chan_done(chan); 649c2d86b1cSPierre Yves MORDRET status &= ~STM32_DMA_TCI; 650c2d86b1cSPierre Yves MORDRET } 651c2d86b1cSPierre Yves MORDRET if (status & STM32_DMA_HTI) { 652c2d86b1cSPierre Yves MORDRET stm32_dma_irq_clear(chan, STM32_DMA_HTI); 653c2d86b1cSPierre Yves MORDRET status &= ~STM32_DMA_HTI; 654c2d86b1cSPierre Yves MORDRET } 655c2d86b1cSPierre Yves MORDRET if (status & STM32_DMA_FEI) { 656c2d86b1cSPierre Yves MORDRET stm32_dma_irq_clear(chan, STM32_DMA_FEI); 657c2d86b1cSPierre Yves MORDRET status &= ~STM32_DMA_FEI; 658ca4c72c0SPierre-Yves MORDRET if (sfcr & STM32_DMA_SFCR_FEIE) { 659c2d86b1cSPierre Yves MORDRET if (!(scr & STM32_DMA_SCR_EN)) 660c2d86b1cSPierre Yves MORDRET dev_err(chan2dev(chan), "FIFO Error\n"); 661c2d86b1cSPierre Yves MORDRET else 662c2d86b1cSPierre Yves MORDRET dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); 663c2d86b1cSPierre Yves MORDRET } 664ca4c72c0SPierre-Yves MORDRET } 665c2d86b1cSPierre Yves MORDRET if (status) { 666d8b46839SM'boumba Cedric Madianga stm32_dma_irq_clear(chan, status); 667d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); 668c2d86b1cSPierre Yves MORDRET if (!(scr & STM32_DMA_SCR_EN)) 669c2d86b1cSPierre Yves MORDRET dev_err(chan2dev(chan), "chan disabled by HW\n"); 670d8b46839SM'boumba Cedric Madianga } 671d8b46839SM'boumba Cedric Madianga 672d8b46839SM'boumba Cedric Madianga spin_unlock(&chan->vchan.lock); 673d8b46839SM'boumba Cedric Madianga 674d8b46839SM'boumba Cedric Madianga return IRQ_HANDLED; 675d8b46839SM'boumba Cedric Madianga } 676d8b46839SM'boumba Cedric Madianga 677d8b46839SM'boumba Cedric Madianga static void stm32_dma_issue_pending(struct dma_chan *c) 678d8b46839SM'boumba Cedric Madianga { 679d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 680d8b46839SM'boumba Cedric Madianga unsigned long flags; 681d8b46839SM'boumba Cedric Madianga 682d8b46839SM'boumba Cedric Madianga spin_lock_irqsave(&chan->vchan.lock, flags); 6838d1b76f0SM'boumba Cedric Madianga if (vchan_issue_pending(&chan->vchan) && !chan->desc && !chan->busy) { 68490ec93cbSBenjamin Gaignard dev_dbg(chan2dev(chan), "vchan %pK: issued\n", &chan->vchan); 6858d1b76f0SM'boumba Cedric Madianga stm32_dma_start_transfer(chan); 686e57cb3b3SPierre Yves MORDRET 687d8b46839SM'boumba Cedric Madianga } 688d8b46839SM'boumba Cedric Madianga spin_unlock_irqrestore(&chan->vchan.lock, flags); 689d8b46839SM'boumba Cedric Madianga } 690d8b46839SM'boumba Cedric Madianga 691d8b46839SM'boumba Cedric Madianga static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, 692d8b46839SM'boumba Cedric Madianga enum dma_transfer_direction direction, 693a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth *buswidth, 694a2b6103bSPierre Yves MORDRET u32 buf_len) 695d8b46839SM'boumba Cedric Madianga { 696d8b46839SM'boumba Cedric Madianga enum dma_slave_buswidth src_addr_width, dst_addr_width; 697d8b46839SM'boumba Cedric Madianga int src_bus_width, dst_bus_width; 698d8b46839SM'boumba Cedric Madianga int src_burst_size, dst_burst_size; 699a2b6103bSPierre Yves MORDRET u32 src_maxburst, dst_maxburst, src_best_burst, dst_best_burst; 700a2b6103bSPierre Yves MORDRET u32 dma_scr, threshold; 701d8b46839SM'boumba Cedric Madianga 702d8b46839SM'boumba Cedric Madianga src_addr_width = chan->dma_sconfig.src_addr_width; 703d8b46839SM'boumba Cedric Madianga dst_addr_width = chan->dma_sconfig.dst_addr_width; 704d8b46839SM'boumba Cedric Madianga src_maxburst = chan->dma_sconfig.src_maxburst; 705d8b46839SM'boumba Cedric Madianga dst_maxburst = chan->dma_sconfig.dst_maxburst; 706a2b6103bSPierre Yves MORDRET threshold = chan->threshold; 707d8b46839SM'boumba Cedric Madianga 708d8b46839SM'boumba Cedric Madianga switch (direction) { 709d8b46839SM'boumba Cedric Madianga case DMA_MEM_TO_DEV: 710a2b6103bSPierre Yves MORDRET /* Set device data size */ 711d8b46839SM'boumba Cedric Madianga dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); 712d8b46839SM'boumba Cedric Madianga if (dst_bus_width < 0) 713d8b46839SM'boumba Cedric Madianga return dst_bus_width; 714d8b46839SM'boumba Cedric Madianga 715a2b6103bSPierre Yves MORDRET /* Set device burst size */ 716a2b6103bSPierre Yves MORDRET dst_best_burst = stm32_dma_get_best_burst(buf_len, 717a2b6103bSPierre Yves MORDRET dst_maxburst, 718a2b6103bSPierre Yves MORDRET threshold, 719a2b6103bSPierre Yves MORDRET dst_addr_width); 720a2b6103bSPierre Yves MORDRET 721a2b6103bSPierre Yves MORDRET dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); 722d8b46839SM'boumba Cedric Madianga if (dst_burst_size < 0) 723d8b46839SM'boumba Cedric Madianga return dst_burst_size; 724d8b46839SM'boumba Cedric Madianga 725a2b6103bSPierre Yves MORDRET /* Set memory data size */ 726a2b6103bSPierre Yves MORDRET src_addr_width = stm32_dma_get_max_width(buf_len, threshold); 727a2b6103bSPierre Yves MORDRET chan->mem_width = src_addr_width; 728d8b46839SM'boumba Cedric Madianga src_bus_width = stm32_dma_get_width(chan, src_addr_width); 729d8b46839SM'boumba Cedric Madianga if (src_bus_width < 0) 730d8b46839SM'boumba Cedric Madianga return src_bus_width; 731d8b46839SM'boumba Cedric Madianga 732a2b6103bSPierre Yves MORDRET /* Set memory burst size */ 733a2b6103bSPierre Yves MORDRET src_maxburst = STM32_DMA_MAX_BURST; 734a2b6103bSPierre Yves MORDRET src_best_burst = stm32_dma_get_best_burst(buf_len, 735a2b6103bSPierre Yves MORDRET src_maxburst, 736a2b6103bSPierre Yves MORDRET threshold, 737a2b6103bSPierre Yves MORDRET src_addr_width); 738a2b6103bSPierre Yves MORDRET src_burst_size = stm32_dma_get_burst(chan, src_best_burst); 739d8b46839SM'boumba Cedric Madianga if (src_burst_size < 0) 740d8b46839SM'boumba Cedric Madianga return src_burst_size; 741d8b46839SM'boumba Cedric Madianga 742d8b46839SM'boumba Cedric Madianga dma_scr = STM32_DMA_SCR_DIR(STM32_DMA_MEM_TO_DEV) | 743d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PSIZE(dst_bus_width) | 744d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_MSIZE(src_bus_width) | 745d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PBURST(dst_burst_size) | 746d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_MBURST(src_burst_size); 747d8b46839SM'boumba Cedric Madianga 748a2b6103bSPierre Yves MORDRET /* Set FIFO threshold */ 749a2b6103bSPierre Yves MORDRET chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; 750a2b6103bSPierre Yves MORDRET chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(threshold); 751a2b6103bSPierre Yves MORDRET 752a2b6103bSPierre Yves MORDRET /* Set peripheral address */ 753d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr; 754d8b46839SM'boumba Cedric Madianga *buswidth = dst_addr_width; 755d8b46839SM'boumba Cedric Madianga break; 756d8b46839SM'boumba Cedric Madianga 757d8b46839SM'boumba Cedric Madianga case DMA_DEV_TO_MEM: 758a2b6103bSPierre Yves MORDRET /* Set device data size */ 759d8b46839SM'boumba Cedric Madianga src_bus_width = stm32_dma_get_width(chan, src_addr_width); 760d8b46839SM'boumba Cedric Madianga if (src_bus_width < 0) 761d8b46839SM'boumba Cedric Madianga return src_bus_width; 762d8b46839SM'boumba Cedric Madianga 763a2b6103bSPierre Yves MORDRET /* Set device burst size */ 764a2b6103bSPierre Yves MORDRET src_best_burst = stm32_dma_get_best_burst(buf_len, 765a2b6103bSPierre Yves MORDRET src_maxburst, 766a2b6103bSPierre Yves MORDRET threshold, 767a2b6103bSPierre Yves MORDRET src_addr_width); 768a2b6103bSPierre Yves MORDRET chan->mem_burst = src_best_burst; 769a2b6103bSPierre Yves MORDRET src_burst_size = stm32_dma_get_burst(chan, src_best_burst); 770d8b46839SM'boumba Cedric Madianga if (src_burst_size < 0) 771d8b46839SM'boumba Cedric Madianga return src_burst_size; 772d8b46839SM'boumba Cedric Madianga 773a2b6103bSPierre Yves MORDRET /* Set memory data size */ 774a2b6103bSPierre Yves MORDRET dst_addr_width = stm32_dma_get_max_width(buf_len, threshold); 775a2b6103bSPierre Yves MORDRET chan->mem_width = dst_addr_width; 776d8b46839SM'boumba Cedric Madianga dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); 777d8b46839SM'boumba Cedric Madianga if (dst_bus_width < 0) 778d8b46839SM'boumba Cedric Madianga return dst_bus_width; 779d8b46839SM'boumba Cedric Madianga 780a2b6103bSPierre Yves MORDRET /* Set memory burst size */ 781a2b6103bSPierre Yves MORDRET dst_maxburst = STM32_DMA_MAX_BURST; 782a2b6103bSPierre Yves MORDRET dst_best_burst = stm32_dma_get_best_burst(buf_len, 783a2b6103bSPierre Yves MORDRET dst_maxburst, 784a2b6103bSPierre Yves MORDRET threshold, 785a2b6103bSPierre Yves MORDRET dst_addr_width); 786a2b6103bSPierre Yves MORDRET chan->mem_burst = dst_best_burst; 787a2b6103bSPierre Yves MORDRET dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); 788d8b46839SM'boumba Cedric Madianga if (dst_burst_size < 0) 789d8b46839SM'boumba Cedric Madianga return dst_burst_size; 790d8b46839SM'boumba Cedric Madianga 791d8b46839SM'boumba Cedric Madianga dma_scr = STM32_DMA_SCR_DIR(STM32_DMA_DEV_TO_MEM) | 792d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PSIZE(src_bus_width) | 793d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_MSIZE(dst_bus_width) | 794d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PBURST(src_burst_size) | 795d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_MBURST(dst_burst_size); 796d8b46839SM'boumba Cedric Madianga 797a2b6103bSPierre Yves MORDRET /* Set FIFO threshold */ 798a2b6103bSPierre Yves MORDRET chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; 799a2b6103bSPierre Yves MORDRET chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(threshold); 800a2b6103bSPierre Yves MORDRET 801a2b6103bSPierre Yves MORDRET /* Set peripheral address */ 802d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr; 803d8b46839SM'boumba Cedric Madianga *buswidth = chan->dma_sconfig.src_addr_width; 804d8b46839SM'boumba Cedric Madianga break; 805d8b46839SM'boumba Cedric Madianga 806d8b46839SM'boumba Cedric Madianga default: 807d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Dma direction is not supported\n"); 808d8b46839SM'boumba Cedric Madianga return -EINVAL; 809d8b46839SM'boumba Cedric Madianga } 810d8b46839SM'boumba Cedric Madianga 811a2b6103bSPierre Yves MORDRET stm32_dma_set_fifo_config(chan, src_best_burst, dst_best_burst); 812d8b46839SM'boumba Cedric Madianga 813a2b6103bSPierre Yves MORDRET /* Set DMA control register */ 814d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr &= ~(STM32_DMA_SCR_DIR_MASK | 815d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PSIZE_MASK | STM32_DMA_SCR_MSIZE_MASK | 816d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PBURST_MASK | STM32_DMA_SCR_MBURST_MASK); 817d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= dma_scr; 818d8b46839SM'boumba Cedric Madianga 819d8b46839SM'boumba Cedric Madianga return 0; 820d8b46839SM'boumba Cedric Madianga } 821d8b46839SM'boumba Cedric Madianga 822d8b46839SM'boumba Cedric Madianga static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) 823d8b46839SM'boumba Cedric Madianga { 824d8b46839SM'boumba Cedric Madianga memset(regs, 0, sizeof(struct stm32_dma_chan_reg)); 825d8b46839SM'boumba Cedric Madianga } 826d8b46839SM'boumba Cedric Madianga 827d8b46839SM'boumba Cedric Madianga static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( 828d8b46839SM'boumba Cedric Madianga struct dma_chan *c, struct scatterlist *sgl, 829d8b46839SM'boumba Cedric Madianga u32 sg_len, enum dma_transfer_direction direction, 830d8b46839SM'boumba Cedric Madianga unsigned long flags, void *context) 831d8b46839SM'boumba Cedric Madianga { 832d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 833d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc; 834d8b46839SM'boumba Cedric Madianga struct scatterlist *sg; 835d8b46839SM'boumba Cedric Madianga enum dma_slave_buswidth buswidth; 836d8b46839SM'boumba Cedric Madianga u32 nb_data_items; 837d8b46839SM'boumba Cedric Madianga int i, ret; 838d8b46839SM'boumba Cedric Madianga 839d8b46839SM'boumba Cedric Madianga if (!chan->config_init) { 840d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "dma channel is not configured\n"); 841d8b46839SM'boumba Cedric Madianga return NULL; 842d8b46839SM'boumba Cedric Madianga } 843d8b46839SM'boumba Cedric Madianga 844d8b46839SM'boumba Cedric Madianga if (sg_len < 1) { 845d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Invalid segment length %d\n", sg_len); 846d8b46839SM'boumba Cedric Madianga return NULL; 847d8b46839SM'boumba Cedric Madianga } 848d8b46839SM'boumba Cedric Madianga 849402096cbSGustavo A. R. Silva desc = kzalloc(struct_size(desc, sg_req, sg_len), GFP_NOWAIT); 850d8b46839SM'boumba Cedric Madianga if (!desc) 851d8b46839SM'boumba Cedric Madianga return NULL; 852d8b46839SM'boumba Cedric Madianga 853d8b46839SM'boumba Cedric Madianga /* Set peripheral flow controller */ 854d8b46839SM'boumba Cedric Madianga if (chan->dma_sconfig.device_fc) 855d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_PFCTRL; 856d8b46839SM'boumba Cedric Madianga else 857d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; 858d8b46839SM'boumba Cedric Madianga 859d8b46839SM'boumba Cedric Madianga for_each_sg(sgl, sg, sg_len, i) { 860a2b6103bSPierre Yves MORDRET ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, 861a2b6103bSPierre Yves MORDRET sg_dma_len(sg)); 862a2b6103bSPierre Yves MORDRET if (ret < 0) 863a2b6103bSPierre Yves MORDRET goto err; 864a2b6103bSPierre Yves MORDRET 865d8b46839SM'boumba Cedric Madianga desc->sg_req[i].len = sg_dma_len(sg); 866d8b46839SM'boumba Cedric Madianga 867d8b46839SM'boumba Cedric Madianga nb_data_items = desc->sg_req[i].len / buswidth; 86880a76952SPierre Yves MORDRET if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) { 869d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "nb items not supported\n"); 870d8b46839SM'boumba Cedric Madianga goto err; 871d8b46839SM'boumba Cedric Madianga } 872d8b46839SM'boumba Cedric Madianga 873d8b46839SM'boumba Cedric Madianga stm32_dma_clear_reg(&desc->sg_req[i].chan_reg); 874d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_scr = chan->chan_reg.dma_scr; 875d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sfcr = chan->chan_reg.dma_sfcr; 876d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar; 877d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm0ar = sg_dma_address(sg); 878d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm1ar = sg_dma_address(sg); 879d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items; 880d8b46839SM'boumba Cedric Madianga } 881d8b46839SM'boumba Cedric Madianga 882d8b46839SM'boumba Cedric Madianga desc->num_sgs = sg_len; 883d8b46839SM'boumba Cedric Madianga desc->cyclic = false; 884d8b46839SM'boumba Cedric Madianga 885d8b46839SM'boumba Cedric Madianga return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); 886d8b46839SM'boumba Cedric Madianga 887d8b46839SM'boumba Cedric Madianga err: 888d8b46839SM'boumba Cedric Madianga kfree(desc); 889d8b46839SM'boumba Cedric Madianga return NULL; 890d8b46839SM'boumba Cedric Madianga } 891d8b46839SM'boumba Cedric Madianga 892d8b46839SM'boumba Cedric Madianga static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( 893d8b46839SM'boumba Cedric Madianga struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, 894d8b46839SM'boumba Cedric Madianga size_t period_len, enum dma_transfer_direction direction, 895d8b46839SM'boumba Cedric Madianga unsigned long flags) 896d8b46839SM'boumba Cedric Madianga { 897d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 898d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc; 899d8b46839SM'boumba Cedric Madianga enum dma_slave_buswidth buswidth; 900d8b46839SM'boumba Cedric Madianga u32 num_periods, nb_data_items; 901d8b46839SM'boumba Cedric Madianga int i, ret; 902d8b46839SM'boumba Cedric Madianga 903d8b46839SM'boumba Cedric Madianga if (!buf_len || !period_len) { 904d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Invalid buffer/period len\n"); 905d8b46839SM'boumba Cedric Madianga return NULL; 906d8b46839SM'boumba Cedric Madianga } 907d8b46839SM'boumba Cedric Madianga 908d8b46839SM'boumba Cedric Madianga if (!chan->config_init) { 909d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "dma channel is not configured\n"); 910d8b46839SM'boumba Cedric Madianga return NULL; 911d8b46839SM'boumba Cedric Madianga } 912d8b46839SM'boumba Cedric Madianga 913d8b46839SM'boumba Cedric Madianga if (buf_len % period_len) { 914d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "buf_len not multiple of period_len\n"); 915d8b46839SM'boumba Cedric Madianga return NULL; 916d8b46839SM'boumba Cedric Madianga } 917d8b46839SM'boumba Cedric Madianga 918d8b46839SM'boumba Cedric Madianga /* 919d8b46839SM'boumba Cedric Madianga * We allow to take more number of requests till DMA is 920d8b46839SM'boumba Cedric Madianga * not started. The driver will loop over all requests. 921d8b46839SM'boumba Cedric Madianga * Once DMA is started then new requests can be queued only after 922d8b46839SM'boumba Cedric Madianga * terminating the DMA. 923d8b46839SM'boumba Cedric Madianga */ 924d8b46839SM'boumba Cedric Madianga if (chan->busy) { 925d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Request not allowed when dma busy\n"); 926d8b46839SM'boumba Cedric Madianga return NULL; 927d8b46839SM'boumba Cedric Madianga } 928d8b46839SM'boumba Cedric Madianga 929a2b6103bSPierre Yves MORDRET ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, period_len); 930d8b46839SM'boumba Cedric Madianga if (ret < 0) 931d8b46839SM'boumba Cedric Madianga return NULL; 932d8b46839SM'boumba Cedric Madianga 933d8b46839SM'boumba Cedric Madianga nb_data_items = period_len / buswidth; 93480a76952SPierre Yves MORDRET if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) { 935d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "number of items not supported\n"); 936d8b46839SM'boumba Cedric Madianga return NULL; 937d8b46839SM'boumba Cedric Madianga } 938d8b46839SM'boumba Cedric Madianga 939d8b46839SM'boumba Cedric Madianga /* Enable Circular mode or double buffer mode */ 940d8b46839SM'boumba Cedric Madianga if (buf_len == period_len) 941d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_CIRC; 942d8b46839SM'boumba Cedric Madianga else 943d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM; 944d8b46839SM'boumba Cedric Madianga 945d8b46839SM'boumba Cedric Madianga /* Clear periph ctrl if client set it */ 946d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; 947d8b46839SM'boumba Cedric Madianga 948d8b46839SM'boumba Cedric Madianga num_periods = buf_len / period_len; 949d8b46839SM'boumba Cedric Madianga 950402096cbSGustavo A. R. Silva desc = kzalloc(struct_size(desc, sg_req, num_periods), GFP_NOWAIT); 951d8b46839SM'boumba Cedric Madianga if (!desc) 952d8b46839SM'boumba Cedric Madianga return NULL; 953d8b46839SM'boumba Cedric Madianga 954d8b46839SM'boumba Cedric Madianga for (i = 0; i < num_periods; i++) { 955d8b46839SM'boumba Cedric Madianga desc->sg_req[i].len = period_len; 956d8b46839SM'boumba Cedric Madianga 957d8b46839SM'boumba Cedric Madianga stm32_dma_clear_reg(&desc->sg_req[i].chan_reg); 958d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_scr = chan->chan_reg.dma_scr; 959d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sfcr = chan->chan_reg.dma_sfcr; 960d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar; 961d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm0ar = buf_addr; 962d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm1ar = buf_addr; 963d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items; 964d8b46839SM'boumba Cedric Madianga buf_addr += period_len; 965d8b46839SM'boumba Cedric Madianga } 966d8b46839SM'boumba Cedric Madianga 967d8b46839SM'boumba Cedric Madianga desc->num_sgs = num_periods; 968d8b46839SM'boumba Cedric Madianga desc->cyclic = true; 969d8b46839SM'boumba Cedric Madianga 970d8b46839SM'boumba Cedric Madianga return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); 971d8b46839SM'boumba Cedric Madianga } 972d8b46839SM'boumba Cedric Madianga 973d8b46839SM'boumba Cedric Madianga static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( 974d8b46839SM'boumba Cedric Madianga struct dma_chan *c, dma_addr_t dest, 975d8b46839SM'boumba Cedric Madianga dma_addr_t src, size_t len, unsigned long flags) 976d8b46839SM'boumba Cedric Madianga { 977d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 978a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth max_width; 979d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc; 980d8b46839SM'boumba Cedric Madianga size_t xfer_count, offset; 981a2b6103bSPierre Yves MORDRET u32 num_sgs, best_burst, dma_burst, threshold; 982d8b46839SM'boumba Cedric Madianga int i; 983d8b46839SM'boumba Cedric Madianga 98480a76952SPierre Yves MORDRET num_sgs = DIV_ROUND_UP(len, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); 985402096cbSGustavo A. R. Silva desc = kzalloc(struct_size(desc, sg_req, num_sgs), GFP_NOWAIT); 986d8b46839SM'boumba Cedric Madianga if (!desc) 987d8b46839SM'boumba Cedric Madianga return NULL; 988d8b46839SM'boumba Cedric Madianga 989a2b6103bSPierre Yves MORDRET threshold = chan->threshold; 990a2b6103bSPierre Yves MORDRET 991d8b46839SM'boumba Cedric Madianga for (offset = 0, i = 0; offset < len; offset += xfer_count, i++) { 992d8b46839SM'boumba Cedric Madianga xfer_count = min_t(size_t, len - offset, 99380a76952SPierre Yves MORDRET STM32_DMA_ALIGNED_MAX_DATA_ITEMS); 994d8b46839SM'boumba Cedric Madianga 995a2b6103bSPierre Yves MORDRET /* Compute best burst size */ 996a2b6103bSPierre Yves MORDRET max_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 997a2b6103bSPierre Yves MORDRET best_burst = stm32_dma_get_best_burst(len, STM32_DMA_MAX_BURST, 998a2b6103bSPierre Yves MORDRET threshold, max_width); 999a2b6103bSPierre Yves MORDRET dma_burst = stm32_dma_get_burst(chan, best_burst); 1000d8b46839SM'boumba Cedric Madianga 1001d8b46839SM'boumba Cedric Madianga stm32_dma_clear_reg(&desc->sg_req[i].chan_reg); 1002d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_scr = 1003d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_DIR(STM32_DMA_MEM_TO_MEM) | 1004a2b6103bSPierre Yves MORDRET STM32_DMA_SCR_PBURST(dma_burst) | 1005a2b6103bSPierre Yves MORDRET STM32_DMA_SCR_MBURST(dma_burst) | 1006d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_MINC | 1007d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PINC | 1008d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_TCIE | 1009d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_TEIE; 1010a2b6103bSPierre Yves MORDRET desc->sg_req[i].chan_reg.dma_sfcr |= STM32_DMA_SFCR_MASK; 1011a2b6103bSPierre Yves MORDRET desc->sg_req[i].chan_reg.dma_sfcr |= 1012a2b6103bSPierre Yves MORDRET STM32_DMA_SFCR_FTH(threshold); 1013d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_spar = src + offset; 1014d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm0ar = dest + offset; 1015d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sndtr = xfer_count; 1016a2b6103bSPierre Yves MORDRET desc->sg_req[i].len = xfer_count; 1017d8b46839SM'boumba Cedric Madianga } 1018d8b46839SM'boumba Cedric Madianga 1019d8b46839SM'boumba Cedric Madianga desc->num_sgs = num_sgs; 1020d8b46839SM'boumba Cedric Madianga desc->cyclic = false; 1021d8b46839SM'boumba Cedric Madianga 1022d8b46839SM'boumba Cedric Madianga return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); 1023d8b46839SM'boumba Cedric Madianga } 1024d8b46839SM'boumba Cedric Madianga 10252b12c558SM'boumba Cedric Madianga static u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan) 10262b12c558SM'boumba Cedric Madianga { 10272b12c558SM'boumba Cedric Madianga u32 dma_scr, width, ndtr; 10282b12c558SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 10292b12c558SM'boumba Cedric Madianga 10302b12c558SM'boumba Cedric Madianga dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 10312b12c558SM'boumba Cedric Madianga width = STM32_DMA_SCR_PSIZE_GET(dma_scr); 10322b12c558SM'boumba Cedric Madianga ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); 10332b12c558SM'boumba Cedric Madianga 10342b12c558SM'boumba Cedric Madianga return ndtr << width; 10352b12c558SM'boumba Cedric Madianga } 10362b12c558SM'boumba Cedric Madianga 10372a4885abSArnaud Pouliquen /** 10382a4885abSArnaud Pouliquen * stm32_dma_is_current_sg - check that expected sg_req is currently transferred 10392a4885abSArnaud Pouliquen * @chan: dma channel 10402a4885abSArnaud Pouliquen * 10412a4885abSArnaud Pouliquen * This function called when IRQ are disable, checks that the hardware has not 10422a4885abSArnaud Pouliquen * switched on the next transfer in double buffer mode. The test is done by 10432a4885abSArnaud Pouliquen * comparing the next_sg memory address with the hardware related register 10442a4885abSArnaud Pouliquen * (based on CT bit value). 10452a4885abSArnaud Pouliquen * 10462a4885abSArnaud Pouliquen * Returns true if expected current transfer is still running or double 10472a4885abSArnaud Pouliquen * buffer mode is not activated. 10482a4885abSArnaud Pouliquen */ 10492a4885abSArnaud Pouliquen static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan) 10502a4885abSArnaud Pouliquen { 10512a4885abSArnaud Pouliquen struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 10522a4885abSArnaud Pouliquen struct stm32_dma_sg_req *sg_req; 10532a4885abSArnaud Pouliquen u32 dma_scr, dma_smar, id; 10542a4885abSArnaud Pouliquen 10552a4885abSArnaud Pouliquen id = chan->id; 10562a4885abSArnaud Pouliquen dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 10572a4885abSArnaud Pouliquen 10582a4885abSArnaud Pouliquen if (!(dma_scr & STM32_DMA_SCR_DBM)) 10592a4885abSArnaud Pouliquen return true; 10602a4885abSArnaud Pouliquen 10612a4885abSArnaud Pouliquen sg_req = &chan->desc->sg_req[chan->next_sg]; 10622a4885abSArnaud Pouliquen 10632a4885abSArnaud Pouliquen if (dma_scr & STM32_DMA_SCR_CT) { 10642a4885abSArnaud Pouliquen dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id)); 10652a4885abSArnaud Pouliquen return (dma_smar == sg_req->chan_reg.dma_sm0ar); 10662a4885abSArnaud Pouliquen } 10672a4885abSArnaud Pouliquen 10682a4885abSArnaud Pouliquen dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)); 10692a4885abSArnaud Pouliquen 10702a4885abSArnaud Pouliquen return (dma_smar == sg_req->chan_reg.dma_sm1ar); 10712a4885abSArnaud Pouliquen } 10722a4885abSArnaud Pouliquen 1073d8b46839SM'boumba Cedric Madianga static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, 1074d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc, 1075d8b46839SM'boumba Cedric Madianga u32 next_sg) 1076d8b46839SM'boumba Cedric Madianga { 1077a2b6103bSPierre Yves MORDRET u32 modulo, burst_size; 10782a4885abSArnaud Pouliquen u32 residue; 10792a4885abSArnaud Pouliquen u32 n_sg = next_sg; 10802a4885abSArnaud Pouliquen struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg]; 1081d8b46839SM'boumba Cedric Madianga int i; 1082d8b46839SM'boumba Cedric Madianga 10832b12c558SM'boumba Cedric Madianga /* 10842a4885abSArnaud Pouliquen * Calculate the residue means compute the descriptors 10852a4885abSArnaud Pouliquen * information: 10862a4885abSArnaud Pouliquen * - the sg_req currently transferred 10872a4885abSArnaud Pouliquen * - the Hardware remaining position in this sg (NDTR bits field). 10882a4885abSArnaud Pouliquen * 10892a4885abSArnaud Pouliquen * A race condition may occur if DMA is running in cyclic or double 10902a4885abSArnaud Pouliquen * buffer mode, since the DMA register are automatically reloaded at end 10912a4885abSArnaud Pouliquen * of period transfer. The hardware may have switched to the next 10922a4885abSArnaud Pouliquen * transfer (CT bit updated) just before the position (SxNDTR reg) is 10932a4885abSArnaud Pouliquen * read. 10942a4885abSArnaud Pouliquen * In this case the SxNDTR reg could (or not) correspond to the new 10952a4885abSArnaud Pouliquen * transfer position, and not the expected one. 10962a4885abSArnaud Pouliquen * The strategy implemented in the stm32 driver is to: 10972a4885abSArnaud Pouliquen * - read the SxNDTR register 10982a4885abSArnaud Pouliquen * - crosscheck that hardware is still in current transfer. 10992a4885abSArnaud Pouliquen * In case of switch, we can assume that the DMA is at the beginning of 11002a4885abSArnaud Pouliquen * the next transfer. So we approximate the residue in consequence, by 11012a4885abSArnaud Pouliquen * pointing on the beginning of next transfer. 11022a4885abSArnaud Pouliquen * 11032a4885abSArnaud Pouliquen * This race condition doesn't apply for none cyclic mode, as double 11042a4885abSArnaud Pouliquen * buffer is not used. In such situation registers are updated by the 11052a4885abSArnaud Pouliquen * software. 11062b12c558SM'boumba Cedric Madianga */ 11072a4885abSArnaud Pouliquen 1108a2b6103bSPierre Yves MORDRET residue = stm32_dma_get_remaining_bytes(chan); 11092a4885abSArnaud Pouliquen 11102a4885abSArnaud Pouliquen if (!stm32_dma_is_current_sg(chan)) { 11112a4885abSArnaud Pouliquen n_sg++; 11122a4885abSArnaud Pouliquen if (n_sg == chan->desc->num_sgs) 11132a4885abSArnaud Pouliquen n_sg = 0; 11142a4885abSArnaud Pouliquen residue = sg_req->len; 1115a2b6103bSPierre Yves MORDRET } 1116d8b46839SM'boumba Cedric Madianga 11172b12c558SM'boumba Cedric Madianga /* 11182a4885abSArnaud Pouliquen * In cyclic mode, for the last period, residue = remaining bytes 11192a4885abSArnaud Pouliquen * from NDTR, 11202a4885abSArnaud Pouliquen * else for all other periods in cyclic mode, and in sg mode, 11212a4885abSArnaud Pouliquen * residue = remaining bytes from NDTR + remaining 11222a4885abSArnaud Pouliquen * periods/sg to be transferred 11232b12c558SM'boumba Cedric Madianga */ 11242a4885abSArnaud Pouliquen if (!chan->desc->cyclic || n_sg != 0) 11252a4885abSArnaud Pouliquen for (i = n_sg; i < desc->num_sgs; i++) 1126d8b46839SM'boumba Cedric Madianga residue += desc->sg_req[i].len; 1127d8b46839SM'boumba Cedric Madianga 1128a2b6103bSPierre Yves MORDRET if (!chan->mem_burst) 1129a2b6103bSPierre Yves MORDRET return residue; 1130a2b6103bSPierre Yves MORDRET 1131a2b6103bSPierre Yves MORDRET burst_size = chan->mem_burst * chan->mem_width; 1132a2b6103bSPierre Yves MORDRET modulo = residue % burst_size; 1133a2b6103bSPierre Yves MORDRET if (modulo) 1134a2b6103bSPierre Yves MORDRET residue = residue - modulo + burst_size; 1135a2b6103bSPierre Yves MORDRET 1136d8b46839SM'boumba Cedric Madianga return residue; 1137d8b46839SM'boumba Cedric Madianga } 1138d8b46839SM'boumba Cedric Madianga 1139d8b46839SM'boumba Cedric Madianga static enum dma_status stm32_dma_tx_status(struct dma_chan *c, 1140d8b46839SM'boumba Cedric Madianga dma_cookie_t cookie, 1141d8b46839SM'boumba Cedric Madianga struct dma_tx_state *state) 1142d8b46839SM'boumba Cedric Madianga { 1143d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1144d8b46839SM'boumba Cedric Madianga struct virt_dma_desc *vdesc; 1145d8b46839SM'boumba Cedric Madianga enum dma_status status; 1146d8b46839SM'boumba Cedric Madianga unsigned long flags; 114757b5a321SM'boumba Cedric Madianga u32 residue = 0; 1148d8b46839SM'boumba Cedric Madianga 1149d8b46839SM'boumba Cedric Madianga status = dma_cookie_status(c, cookie, state); 1150249d5531SPierre Yves MORDRET if (status == DMA_COMPLETE || !state) 1151d8b46839SM'boumba Cedric Madianga return status; 1152d8b46839SM'boumba Cedric Madianga 1153d8b46839SM'boumba Cedric Madianga spin_lock_irqsave(&chan->vchan.lock, flags); 1154d8b46839SM'boumba Cedric Madianga vdesc = vchan_find_desc(&chan->vchan, cookie); 115557b5a321SM'boumba Cedric Madianga if (chan->desc && cookie == chan->desc->vdesc.tx.cookie) 1156d8b46839SM'boumba Cedric Madianga residue = stm32_dma_desc_residue(chan, chan->desc, 1157d8b46839SM'boumba Cedric Madianga chan->next_sg); 115857b5a321SM'boumba Cedric Madianga else if (vdesc) 1159d8b46839SM'boumba Cedric Madianga residue = stm32_dma_desc_residue(chan, 1160d8b46839SM'boumba Cedric Madianga to_stm32_dma_desc(vdesc), 0); 1161d8b46839SM'boumba Cedric Madianga dma_set_residue(state, residue); 1162d8b46839SM'boumba Cedric Madianga 1163d8b46839SM'boumba Cedric Madianga spin_unlock_irqrestore(&chan->vchan.lock, flags); 1164d8b46839SM'boumba Cedric Madianga 1165d8b46839SM'boumba Cedric Madianga return status; 1166d8b46839SM'boumba Cedric Madianga } 1167d8b46839SM'boumba Cedric Madianga 1168d8b46839SM'boumba Cedric Madianga static int stm32_dma_alloc_chan_resources(struct dma_chan *c) 1169d8b46839SM'boumba Cedric Madianga { 1170d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1171d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 1172d8b46839SM'boumba Cedric Madianga int ret; 1173d8b46839SM'boumba Cedric Madianga 1174d8b46839SM'boumba Cedric Madianga chan->config_init = false; 117548bc73baSPierre-Yves MORDRET 117648bc73baSPierre-Yves MORDRET ret = pm_runtime_get_sync(dmadev->ddev.dev); 117748bc73baSPierre-Yves MORDRET if (ret < 0) 1178d8b46839SM'boumba Cedric Madianga return ret; 1179d8b46839SM'boumba Cedric Madianga 1180d8b46839SM'boumba Cedric Madianga ret = stm32_dma_disable_chan(chan); 1181d8b46839SM'boumba Cedric Madianga if (ret < 0) 118248bc73baSPierre-Yves MORDRET pm_runtime_put(dmadev->ddev.dev); 1183d8b46839SM'boumba Cedric Madianga 1184d8b46839SM'boumba Cedric Madianga return ret; 1185d8b46839SM'boumba Cedric Madianga } 1186d8b46839SM'boumba Cedric Madianga 1187d8b46839SM'boumba Cedric Madianga static void stm32_dma_free_chan_resources(struct dma_chan *c) 1188d8b46839SM'boumba Cedric Madianga { 1189d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1190d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 1191d8b46839SM'boumba Cedric Madianga unsigned long flags; 1192d8b46839SM'boumba Cedric Madianga 1193d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "Freeing channel %d\n", chan->id); 1194d8b46839SM'boumba Cedric Madianga 1195d8b46839SM'boumba Cedric Madianga if (chan->busy) { 1196d8b46839SM'boumba Cedric Madianga spin_lock_irqsave(&chan->vchan.lock, flags); 1197d8b46839SM'boumba Cedric Madianga stm32_dma_stop(chan); 1198d8b46839SM'boumba Cedric Madianga chan->desc = NULL; 1199d8b46839SM'boumba Cedric Madianga spin_unlock_irqrestore(&chan->vchan.lock, flags); 1200d8b46839SM'boumba Cedric Madianga } 1201d8b46839SM'boumba Cedric Madianga 120248bc73baSPierre-Yves MORDRET pm_runtime_put(dmadev->ddev.dev); 1203d8b46839SM'boumba Cedric Madianga 1204d8b46839SM'boumba Cedric Madianga vchan_free_chan_resources(to_virt_chan(c)); 1205d8b46839SM'boumba Cedric Madianga } 1206d8b46839SM'boumba Cedric Madianga 1207d8b46839SM'boumba Cedric Madianga static void stm32_dma_desc_free(struct virt_dma_desc *vdesc) 1208d8b46839SM'boumba Cedric Madianga { 1209d8b46839SM'boumba Cedric Madianga kfree(container_of(vdesc, struct stm32_dma_desc, vdesc)); 1210d8b46839SM'boumba Cedric Madianga } 1211d8b46839SM'boumba Cedric Madianga 1212e97adb49SVinod Koul static void stm32_dma_set_config(struct stm32_dma_chan *chan, 1213d8b46839SM'boumba Cedric Madianga struct stm32_dma_cfg *cfg) 1214d8b46839SM'boumba Cedric Madianga { 1215d8b46839SM'boumba Cedric Madianga stm32_dma_clear_reg(&chan->chan_reg); 1216d8b46839SM'boumba Cedric Madianga 1217d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr = cfg->stream_config & STM32_DMA_SCR_CFG_MASK; 1218d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_REQ(cfg->request_line); 1219d8b46839SM'boumba Cedric Madianga 1220d8b46839SM'boumba Cedric Madianga /* Enable Interrupts */ 1221d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_TEIE | STM32_DMA_SCR_TCIE; 1222d8b46839SM'boumba Cedric Madianga 1223951f44cbSPierre Yves MORDRET chan->threshold = STM32_DMA_THRESHOLD_FTR_GET(cfg->features); 1224d8b46839SM'boumba Cedric Madianga } 1225d8b46839SM'boumba Cedric Madianga 1226d8b46839SM'boumba Cedric Madianga static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, 1227d8b46839SM'boumba Cedric Madianga struct of_dma *ofdma) 1228d8b46839SM'boumba Cedric Madianga { 1229d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = ofdma->of_dma_data; 12305df4eb45SM'boumba Cedric Madianga struct device *dev = dmadev->ddev.dev; 1231d8b46839SM'boumba Cedric Madianga struct stm32_dma_cfg cfg; 1232d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan; 1233d8b46839SM'boumba Cedric Madianga struct dma_chan *c; 1234d8b46839SM'boumba Cedric Madianga 12355df4eb45SM'boumba Cedric Madianga if (dma_spec->args_count < 4) { 12365df4eb45SM'boumba Cedric Madianga dev_err(dev, "Bad number of cells\n"); 1237d8b46839SM'boumba Cedric Madianga return NULL; 12385df4eb45SM'boumba Cedric Madianga } 1239d8b46839SM'boumba Cedric Madianga 1240d8b46839SM'boumba Cedric Madianga cfg.channel_id = dma_spec->args[0]; 1241d8b46839SM'boumba Cedric Madianga cfg.request_line = dma_spec->args[1]; 1242d8b46839SM'boumba Cedric Madianga cfg.stream_config = dma_spec->args[2]; 1243951f44cbSPierre Yves MORDRET cfg.features = dma_spec->args[3]; 1244d8b46839SM'boumba Cedric Madianga 1245249d5531SPierre Yves MORDRET if (cfg.channel_id >= STM32_DMA_MAX_CHANNELS || 1246249d5531SPierre Yves MORDRET cfg.request_line >= STM32_DMA_MAX_REQUEST_ID) { 12475df4eb45SM'boumba Cedric Madianga dev_err(dev, "Bad channel and/or request id\n"); 1248d8b46839SM'boumba Cedric Madianga return NULL; 12495df4eb45SM'boumba Cedric Madianga } 1250d8b46839SM'boumba Cedric Madianga 1251d8b46839SM'boumba Cedric Madianga chan = &dmadev->chan[cfg.channel_id]; 1252d8b46839SM'boumba Cedric Madianga 1253d8b46839SM'boumba Cedric Madianga c = dma_get_slave_channel(&chan->vchan.chan); 12545df4eb45SM'boumba Cedric Madianga if (!c) { 1255041cf7e0SColin Ian King dev_err(dev, "No more channels available\n"); 12565df4eb45SM'boumba Cedric Madianga return NULL; 12575df4eb45SM'boumba Cedric Madianga } 12585df4eb45SM'boumba Cedric Madianga 1259d8b46839SM'boumba Cedric Madianga stm32_dma_set_config(chan, &cfg); 1260d8b46839SM'boumba Cedric Madianga 1261d8b46839SM'boumba Cedric Madianga return c; 1262d8b46839SM'boumba Cedric Madianga } 1263d8b46839SM'boumba Cedric Madianga 1264d8b46839SM'boumba Cedric Madianga static const struct of_device_id stm32_dma_of_match[] = { 1265d8b46839SM'boumba Cedric Madianga { .compatible = "st,stm32-dma", }, 1266d8b46839SM'boumba Cedric Madianga { /* sentinel */ }, 1267d8b46839SM'boumba Cedric Madianga }; 1268d8b46839SM'boumba Cedric Madianga MODULE_DEVICE_TABLE(of, stm32_dma_of_match); 1269d8b46839SM'boumba Cedric Madianga 1270d8b46839SM'boumba Cedric Madianga static int stm32_dma_probe(struct platform_device *pdev) 1271d8b46839SM'boumba Cedric Madianga { 1272d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan; 1273d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev; 1274d8b46839SM'boumba Cedric Madianga struct dma_device *dd; 1275d8b46839SM'boumba Cedric Madianga const struct of_device_id *match; 1276d8b46839SM'boumba Cedric Madianga struct resource *res; 12778cf1e0fcSEtienne Carriere struct reset_control *rst; 1278d8b46839SM'boumba Cedric Madianga int i, ret; 1279d8b46839SM'boumba Cedric Madianga 1280d8b46839SM'boumba Cedric Madianga match = of_match_device(stm32_dma_of_match, &pdev->dev); 1281d8b46839SM'boumba Cedric Madianga if (!match) { 1282d8b46839SM'boumba Cedric Madianga dev_err(&pdev->dev, "Error: No device match found\n"); 1283d8b46839SM'boumba Cedric Madianga return -ENODEV; 1284d8b46839SM'boumba Cedric Madianga } 1285d8b46839SM'boumba Cedric Madianga 1286d8b46839SM'boumba Cedric Madianga dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL); 1287d8b46839SM'boumba Cedric Madianga if (!dmadev) 1288d8b46839SM'boumba Cedric Madianga return -ENOMEM; 1289d8b46839SM'boumba Cedric Madianga 1290d8b46839SM'boumba Cedric Madianga dd = &dmadev->ddev; 1291d8b46839SM'boumba Cedric Madianga 1292d8b46839SM'boumba Cedric Madianga res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1293d8b46839SM'boumba Cedric Madianga dmadev->base = devm_ioremap_resource(&pdev->dev, res); 1294d8b46839SM'boumba Cedric Madianga if (IS_ERR(dmadev->base)) 1295d8b46839SM'boumba Cedric Madianga return PTR_ERR(dmadev->base); 1296d8b46839SM'boumba Cedric Madianga 1297d8b46839SM'boumba Cedric Madianga dmadev->clk = devm_clk_get(&pdev->dev, NULL); 1298d8b46839SM'boumba Cedric Madianga if (IS_ERR(dmadev->clk)) { 1299d8b46839SM'boumba Cedric Madianga dev_err(&pdev->dev, "Error: Missing controller clock\n"); 1300d8b46839SM'boumba Cedric Madianga return PTR_ERR(dmadev->clk); 1301d8b46839SM'boumba Cedric Madianga } 1302d8b46839SM'boumba Cedric Madianga 130348bc73baSPierre-Yves MORDRET ret = clk_prepare_enable(dmadev->clk); 130448bc73baSPierre-Yves MORDRET if (ret < 0) { 130548bc73baSPierre-Yves MORDRET dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret); 130648bc73baSPierre-Yves MORDRET return ret; 130748bc73baSPierre-Yves MORDRET } 130848bc73baSPierre-Yves MORDRET 1309d8b46839SM'boumba Cedric Madianga dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node, 1310d8b46839SM'boumba Cedric Madianga "st,mem2mem"); 1311d8b46839SM'boumba Cedric Madianga 13128cf1e0fcSEtienne Carriere rst = devm_reset_control_get(&pdev->dev, NULL); 13138cf1e0fcSEtienne Carriere if (!IS_ERR(rst)) { 13148cf1e0fcSEtienne Carriere reset_control_assert(rst); 1315d8b46839SM'boumba Cedric Madianga udelay(2); 13168cf1e0fcSEtienne Carriere reset_control_deassert(rst); 1317d8b46839SM'boumba Cedric Madianga } 1318d8b46839SM'boumba Cedric Madianga 1319d8b46839SM'boumba Cedric Madianga dma_cap_set(DMA_SLAVE, dd->cap_mask); 1320d8b46839SM'boumba Cedric Madianga dma_cap_set(DMA_PRIVATE, dd->cap_mask); 1321d8b46839SM'boumba Cedric Madianga dma_cap_set(DMA_CYCLIC, dd->cap_mask); 1322d8b46839SM'boumba Cedric Madianga dd->device_alloc_chan_resources = stm32_dma_alloc_chan_resources; 1323d8b46839SM'boumba Cedric Madianga dd->device_free_chan_resources = stm32_dma_free_chan_resources; 1324d8b46839SM'boumba Cedric Madianga dd->device_tx_status = stm32_dma_tx_status; 1325d8b46839SM'boumba Cedric Madianga dd->device_issue_pending = stm32_dma_issue_pending; 1326d8b46839SM'boumba Cedric Madianga dd->device_prep_slave_sg = stm32_dma_prep_slave_sg; 1327d8b46839SM'boumba Cedric Madianga dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic; 1328d8b46839SM'boumba Cedric Madianga dd->device_config = stm32_dma_slave_config; 1329d8b46839SM'boumba Cedric Madianga dd->device_terminate_all = stm32_dma_terminate_all; 1330dc808675SM'boumba Cedric Madianga dd->device_synchronize = stm32_dma_synchronize; 1331d8b46839SM'boumba Cedric Madianga dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 1332d8b46839SM'boumba Cedric Madianga BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 1333d8b46839SM'boumba Cedric Madianga BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); 1334d8b46839SM'boumba Cedric Madianga dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 1335d8b46839SM'boumba Cedric Madianga BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 1336d8b46839SM'boumba Cedric Madianga BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); 1337d8b46839SM'boumba Cedric Madianga dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); 1338d8b46839SM'boumba Cedric Madianga dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 1339276b0046SM'boumba Cedric Madianga dd->max_burst = STM32_DMA_MAX_BURST; 1340d8b46839SM'boumba Cedric Madianga dd->dev = &pdev->dev; 1341d8b46839SM'boumba Cedric Madianga INIT_LIST_HEAD(&dd->channels); 1342d8b46839SM'boumba Cedric Madianga 1343d8b46839SM'boumba Cedric Madianga if (dmadev->mem2mem) { 1344d8b46839SM'boumba Cedric Madianga dma_cap_set(DMA_MEMCPY, dd->cap_mask); 1345d8b46839SM'boumba Cedric Madianga dd->device_prep_dma_memcpy = stm32_dma_prep_dma_memcpy; 1346d8b46839SM'boumba Cedric Madianga dd->directions |= BIT(DMA_MEM_TO_MEM); 1347d8b46839SM'boumba Cedric Madianga } 1348d8b46839SM'boumba Cedric Madianga 1349d8b46839SM'boumba Cedric Madianga for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { 1350d8b46839SM'boumba Cedric Madianga chan = &dmadev->chan[i]; 1351d8b46839SM'boumba Cedric Madianga chan->id = i; 1352d8b46839SM'boumba Cedric Madianga chan->vchan.desc_free = stm32_dma_desc_free; 1353d8b46839SM'boumba Cedric Madianga vchan_init(&chan->vchan, dd); 1354d8b46839SM'boumba Cedric Madianga } 1355d8b46839SM'boumba Cedric Madianga 1356d8b46839SM'boumba Cedric Madianga ret = dma_async_device_register(dd); 1357d8b46839SM'boumba Cedric Madianga if (ret) 135848bc73baSPierre-Yves MORDRET goto clk_free; 1359d8b46839SM'boumba Cedric Madianga 1360d8b46839SM'boumba Cedric Madianga for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { 1361d8b46839SM'boumba Cedric Madianga chan = &dmadev->chan[i]; 1362c6504be5SVinod Koul ret = platform_get_irq(pdev, i); 1363e17be6e1SStephen Boyd if (ret < 0) 1364d8b46839SM'boumba Cedric Madianga goto err_unregister; 1365c6504be5SVinod Koul chan->irq = ret; 1366c6504be5SVinod Koul 1367d8b46839SM'boumba Cedric Madianga ret = devm_request_irq(&pdev->dev, chan->irq, 1368d8b46839SM'boumba Cedric Madianga stm32_dma_chan_irq, 0, 1369d8b46839SM'boumba Cedric Madianga dev_name(chan2dev(chan)), chan); 1370d8b46839SM'boumba Cedric Madianga if (ret) { 1371d8b46839SM'boumba Cedric Madianga dev_err(&pdev->dev, 1372d8b46839SM'boumba Cedric Madianga "request_irq failed with err %d channel %d\n", 1373d8b46839SM'boumba Cedric Madianga ret, i); 1374d8b46839SM'boumba Cedric Madianga goto err_unregister; 1375d8b46839SM'boumba Cedric Madianga } 1376d8b46839SM'boumba Cedric Madianga } 1377d8b46839SM'boumba Cedric Madianga 1378d8b46839SM'boumba Cedric Madianga ret = of_dma_controller_register(pdev->dev.of_node, 1379d8b46839SM'boumba Cedric Madianga stm32_dma_of_xlate, dmadev); 1380d8b46839SM'boumba Cedric Madianga if (ret < 0) { 1381d8b46839SM'boumba Cedric Madianga dev_err(&pdev->dev, 1382d8b46839SM'boumba Cedric Madianga "STM32 DMA DMA OF registration failed %d\n", ret); 1383d8b46839SM'boumba Cedric Madianga goto err_unregister; 1384d8b46839SM'boumba Cedric Madianga } 1385d8b46839SM'boumba Cedric Madianga 1386d8b46839SM'boumba Cedric Madianga platform_set_drvdata(pdev, dmadev); 1387d8b46839SM'boumba Cedric Madianga 138848bc73baSPierre-Yves MORDRET pm_runtime_set_active(&pdev->dev); 138948bc73baSPierre-Yves MORDRET pm_runtime_enable(&pdev->dev); 139048bc73baSPierre-Yves MORDRET pm_runtime_get_noresume(&pdev->dev); 139148bc73baSPierre-Yves MORDRET pm_runtime_put(&pdev->dev); 139248bc73baSPierre-Yves MORDRET 1393d8b46839SM'boumba Cedric Madianga dev_info(&pdev->dev, "STM32 DMA driver registered\n"); 1394d8b46839SM'boumba Cedric Madianga 1395d8b46839SM'boumba Cedric Madianga return 0; 1396d8b46839SM'boumba Cedric Madianga 1397d8b46839SM'boumba Cedric Madianga err_unregister: 1398d8b46839SM'boumba Cedric Madianga dma_async_device_unregister(dd); 139948bc73baSPierre-Yves MORDRET clk_free: 140048bc73baSPierre-Yves MORDRET clk_disable_unprepare(dmadev->clk); 1401d8b46839SM'boumba Cedric Madianga 1402d8b46839SM'boumba Cedric Madianga return ret; 1403d8b46839SM'boumba Cedric Madianga } 1404d8b46839SM'boumba Cedric Madianga 140548bc73baSPierre-Yves MORDRET #ifdef CONFIG_PM 140648bc73baSPierre-Yves MORDRET static int stm32_dma_runtime_suspend(struct device *dev) 140748bc73baSPierre-Yves MORDRET { 140848bc73baSPierre-Yves MORDRET struct stm32_dma_device *dmadev = dev_get_drvdata(dev); 140948bc73baSPierre-Yves MORDRET 141048bc73baSPierre-Yves MORDRET clk_disable_unprepare(dmadev->clk); 141148bc73baSPierre-Yves MORDRET 141248bc73baSPierre-Yves MORDRET return 0; 141348bc73baSPierre-Yves MORDRET } 141448bc73baSPierre-Yves MORDRET 141548bc73baSPierre-Yves MORDRET static int stm32_dma_runtime_resume(struct device *dev) 141648bc73baSPierre-Yves MORDRET { 141748bc73baSPierre-Yves MORDRET struct stm32_dma_device *dmadev = dev_get_drvdata(dev); 141848bc73baSPierre-Yves MORDRET int ret; 141948bc73baSPierre-Yves MORDRET 142048bc73baSPierre-Yves MORDRET ret = clk_prepare_enable(dmadev->clk); 142148bc73baSPierre-Yves MORDRET if (ret) { 142248bc73baSPierre-Yves MORDRET dev_err(dev, "failed to prepare_enable clock\n"); 142348bc73baSPierre-Yves MORDRET return ret; 142448bc73baSPierre-Yves MORDRET } 142548bc73baSPierre-Yves MORDRET 142648bc73baSPierre-Yves MORDRET return 0; 142748bc73baSPierre-Yves MORDRET } 142848bc73baSPierre-Yves MORDRET #endif 142948bc73baSPierre-Yves MORDRET 143005f8740aSPierre-Yves MORDRET #ifdef CONFIG_PM_SLEEP 143105f8740aSPierre-Yves MORDRET static int stm32_dma_suspend(struct device *dev) 143205f8740aSPierre-Yves MORDRET { 143305f8740aSPierre-Yves MORDRET struct stm32_dma_device *dmadev = dev_get_drvdata(dev); 143405f8740aSPierre-Yves MORDRET int id, ret, scr; 143505f8740aSPierre-Yves MORDRET 143605f8740aSPierre-Yves MORDRET ret = pm_runtime_get_sync(dev); 143705f8740aSPierre-Yves MORDRET if (ret < 0) 143805f8740aSPierre-Yves MORDRET return ret; 143905f8740aSPierre-Yves MORDRET 144005f8740aSPierre-Yves MORDRET for (id = 0; id < STM32_DMA_MAX_CHANNELS; id++) { 144105f8740aSPierre-Yves MORDRET scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 144205f8740aSPierre-Yves MORDRET if (scr & STM32_DMA_SCR_EN) { 144305f8740aSPierre-Yves MORDRET dev_warn(dev, "Suspend is prevented by Chan %i\n", id); 144405f8740aSPierre-Yves MORDRET return -EBUSY; 144505f8740aSPierre-Yves MORDRET } 144605f8740aSPierre-Yves MORDRET } 144705f8740aSPierre-Yves MORDRET 144805f8740aSPierre-Yves MORDRET pm_runtime_put_sync(dev); 144905f8740aSPierre-Yves MORDRET 145005f8740aSPierre-Yves MORDRET pm_runtime_force_suspend(dev); 145105f8740aSPierre-Yves MORDRET 145205f8740aSPierre-Yves MORDRET return 0; 145305f8740aSPierre-Yves MORDRET } 145405f8740aSPierre-Yves MORDRET 145505f8740aSPierre-Yves MORDRET static int stm32_dma_resume(struct device *dev) 145605f8740aSPierre-Yves MORDRET { 145705f8740aSPierre-Yves MORDRET return pm_runtime_force_resume(dev); 145805f8740aSPierre-Yves MORDRET } 145905f8740aSPierre-Yves MORDRET #endif 146005f8740aSPierre-Yves MORDRET 146148bc73baSPierre-Yves MORDRET static const struct dev_pm_ops stm32_dma_pm_ops = { 146205f8740aSPierre-Yves MORDRET SET_SYSTEM_SLEEP_PM_OPS(stm32_dma_suspend, stm32_dma_resume) 146348bc73baSPierre-Yves MORDRET SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend, 146448bc73baSPierre-Yves MORDRET stm32_dma_runtime_resume, NULL) 146548bc73baSPierre-Yves MORDRET }; 146648bc73baSPierre-Yves MORDRET 1467d8b46839SM'boumba Cedric Madianga static struct platform_driver stm32_dma_driver = { 1468d8b46839SM'boumba Cedric Madianga .driver = { 1469d8b46839SM'boumba Cedric Madianga .name = "stm32-dma", 1470d8b46839SM'boumba Cedric Madianga .of_match_table = stm32_dma_of_match, 147148bc73baSPierre-Yves MORDRET .pm = &stm32_dma_pm_ops, 1472d8b46839SM'boumba Cedric Madianga }, 1473d8b46839SM'boumba Cedric Madianga }; 1474d8b46839SM'boumba Cedric Madianga 1475d8b46839SM'boumba Cedric Madianga static int __init stm32_dma_init(void) 1476d8b46839SM'boumba Cedric Madianga { 1477d8b46839SM'boumba Cedric Madianga return platform_driver_probe(&stm32_dma_driver, stm32_dma_probe); 1478d8b46839SM'boumba Cedric Madianga } 1479d8b46839SM'boumba Cedric Madianga subsys_initcall(stm32_dma_init); 1480