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 121c32d6c3SAmelie Delaunay #include <linux/bitfield.h> 13d8b46839SM'boumba Cedric Madianga #include <linux/clk.h> 14d8b46839SM'boumba Cedric Madianga #include <linux/delay.h> 15d8b46839SM'boumba Cedric Madianga #include <linux/dmaengine.h> 16d8b46839SM'boumba Cedric Madianga #include <linux/dma-mapping.h> 17d8b46839SM'boumba Cedric Madianga #include <linux/err.h> 18d8b46839SM'boumba Cedric Madianga #include <linux/init.h> 19409ffc4dSAmelie Delaunay #include <linux/iopoll.h> 20d8b46839SM'boumba Cedric Madianga #include <linux/jiffies.h> 21d8b46839SM'boumba Cedric Madianga #include <linux/list.h> 22d8b46839SM'boumba Cedric Madianga #include <linux/module.h> 23d8b46839SM'boumba Cedric Madianga #include <linux/of.h> 24d8b46839SM'boumba Cedric Madianga #include <linux/of_device.h> 25d8b46839SM'boumba Cedric Madianga #include <linux/of_dma.h> 26d8b46839SM'boumba Cedric Madianga #include <linux/platform_device.h> 2748bc73baSPierre-Yves MORDRET #include <linux/pm_runtime.h> 28d8b46839SM'boumba Cedric Madianga #include <linux/reset.h> 29d8b46839SM'boumba Cedric Madianga #include <linux/sched.h> 30d8b46839SM'boumba Cedric Madianga #include <linux/slab.h> 31d8b46839SM'boumba Cedric Madianga 32d8b46839SM'boumba Cedric Madianga #include "virt-dma.h" 33d8b46839SM'boumba Cedric Madianga 34d8b46839SM'boumba Cedric Madianga #define STM32_DMA_LISR 0x0000 /* DMA Low Int Status Reg */ 35d8b46839SM'boumba Cedric Madianga #define STM32_DMA_HISR 0x0004 /* DMA High Int Status Reg */ 364dc36a53SAmelie Delaunay #define STM32_DMA_ISR(n) (((n) & 4) ? STM32_DMA_HISR : STM32_DMA_LISR) 37d8b46839SM'boumba Cedric Madianga #define STM32_DMA_LIFCR 0x0008 /* DMA Low Int Flag Clear Reg */ 38d8b46839SM'boumba Cedric Madianga #define STM32_DMA_HIFCR 0x000c /* DMA High Int Flag Clear Reg */ 394dc36a53SAmelie Delaunay #define STM32_DMA_IFCR(n) (((n) & 4) ? STM32_DMA_HIFCR : STM32_DMA_LIFCR) 40d8b46839SM'boumba Cedric Madianga #define STM32_DMA_TCI BIT(5) /* Transfer Complete Interrupt */ 41c2d86b1cSPierre Yves MORDRET #define STM32_DMA_HTI BIT(4) /* Half Transfer Interrupt */ 42d8b46839SM'boumba Cedric Madianga #define STM32_DMA_TEI BIT(3) /* Transfer Error Interrupt */ 43d8b46839SM'boumba Cedric Madianga #define STM32_DMA_DMEI BIT(2) /* Direct Mode Error Interrupt */ 44d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FEI BIT(0) /* FIFO Error Interrupt */ 459df3bd55SPierre Yves MORDRET #define STM32_DMA_MASKI (STM32_DMA_TCI \ 469df3bd55SPierre Yves MORDRET | STM32_DMA_TEI \ 479df3bd55SPierre Yves MORDRET | STM32_DMA_DMEI \ 489df3bd55SPierre Yves MORDRET | STM32_DMA_FEI) 494dc36a53SAmelie Delaunay /* 504dc36a53SAmelie Delaunay * If (chan->id % 4) is 2 or 3, left shift the mask by 16 bits; 514dc36a53SAmelie Delaunay * if (ch % 4) is 1 or 3, additionally left shift the mask by 6 bits. 524dc36a53SAmelie Delaunay */ 534dc36a53SAmelie Delaunay #define STM32_DMA_FLAGS_SHIFT(n) ({ typeof(n) (_n) = (n); \ 544dc36a53SAmelie Delaunay (((_n) & 2) << 3) | (((_n) & 1) * 6); }) 55d8b46839SM'boumba Cedric Madianga 56d8b46839SM'boumba Cedric Madianga /* DMA Stream x Configuration Register */ 57d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR(x) (0x0010 + 0x18 * (x)) /* x = 0..7 */ 581c32d6c3SAmelie Delaunay #define STM32_DMA_SCR_REQ_MASK GENMASK(27, 25) 59d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_MBURST_MASK GENMASK(24, 23) 60d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PBURST_MASK GENMASK(22, 21) 61d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PL_MASK GENMASK(17, 16) 62d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_MSIZE_MASK GENMASK(14, 13) 63d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PSIZE_MASK GENMASK(12, 11) 64d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_DIR_MASK GENMASK(7, 6) 652b5b7405SAmelie Delaunay #define STM32_DMA_SCR_TRBUFF BIT(20) /* Bufferable transfer for USART/UART */ 66d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_CT BIT(19) /* Target in double buffer */ 67d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_DBM BIT(18) /* Double Buffer Mode */ 68d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PINCOS BIT(15) /* Peripheral inc offset size */ 69d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_MINC BIT(10) /* Memory increment mode */ 70d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PINC BIT(9) /* Peripheral increment mode */ 71d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_CIRC BIT(8) /* Circular mode */ 72d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_PFCTRL BIT(5) /* Peripheral Flow Controller */ 73249d5531SPierre Yves MORDRET #define STM32_DMA_SCR_TCIE BIT(4) /* Transfer Complete Int Enable 74249d5531SPierre Yves MORDRET */ 75d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_TEIE BIT(2) /* Transfer Error Int Enable */ 76d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_DMEIE BIT(1) /* Direct Mode Err Int Enable */ 77d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_EN BIT(0) /* Stream Enable */ 78d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_CFG_MASK (STM32_DMA_SCR_PINC \ 79d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_MINC \ 80d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_PINCOS \ 81d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_PL_MASK) 82d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SCR_IRQ_MASK (STM32_DMA_SCR_TCIE \ 83d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_TEIE \ 84d8b46839SM'boumba Cedric Madianga | STM32_DMA_SCR_DMEIE) 85d8b46839SM'boumba Cedric Madianga 86d8b46839SM'boumba Cedric Madianga /* DMA Stream x number of data register */ 87d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SNDTR(x) (0x0014 + 0x18 * (x)) 88d8b46839SM'boumba Cedric Madianga 89d8b46839SM'boumba Cedric Madianga /* DMA stream peripheral address register */ 90d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SPAR(x) (0x0018 + 0x18 * (x)) 91d8b46839SM'boumba Cedric Madianga 92d8b46839SM'boumba Cedric Madianga /* DMA stream x memory 0 address register */ 93d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SM0AR(x) (0x001c + 0x18 * (x)) 94d8b46839SM'boumba Cedric Madianga 95d8b46839SM'boumba Cedric Madianga /* DMA stream x memory 1 address register */ 96d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SM1AR(x) (0x0020 + 0x18 * (x)) 97d8b46839SM'boumba Cedric Madianga 98d8b46839SM'boumba Cedric Madianga /* DMA stream x FIFO control register */ 99d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR(x) (0x0024 + 0x18 * (x)) 100d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_FTH_MASK GENMASK(1, 0) 101d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_FEIE BIT(7) /* FIFO error interrupt enable */ 102d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_DMDIS BIT(2) /* Direct mode disable */ 103d8b46839SM'boumba Cedric Madianga #define STM32_DMA_SFCR_MASK (STM32_DMA_SFCR_FEIE \ 104d8b46839SM'boumba Cedric Madianga | STM32_DMA_SFCR_DMDIS) 105d8b46839SM'boumba Cedric Madianga 106d8b46839SM'boumba Cedric Madianga /* DMA direction */ 107d8b46839SM'boumba Cedric Madianga #define STM32_DMA_DEV_TO_MEM 0x00 108d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MEM_TO_DEV 0x01 109d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MEM_TO_MEM 0x02 110d8b46839SM'boumba Cedric Madianga 111d8b46839SM'boumba Cedric Madianga /* DMA priority level */ 112d8b46839SM'boumba Cedric Madianga #define STM32_DMA_PRIORITY_LOW 0x00 113d8b46839SM'boumba Cedric Madianga #define STM32_DMA_PRIORITY_MEDIUM 0x01 114d8b46839SM'boumba Cedric Madianga #define STM32_DMA_PRIORITY_HIGH 0x02 115d8b46839SM'boumba Cedric Madianga #define STM32_DMA_PRIORITY_VERY_HIGH 0x03 116d8b46839SM'boumba Cedric Madianga 117d8b46839SM'boumba Cedric Madianga /* DMA FIFO threshold selection */ 118d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FIFO_THRESHOLD_1QUARTERFULL 0x00 119d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FIFO_THRESHOLD_HALFFULL 0x01 120d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL 0x02 121d8b46839SM'boumba Cedric Madianga #define STM32_DMA_FIFO_THRESHOLD_FULL 0x03 122955b1766SAmelie Delaunay #define STM32_DMA_FIFO_THRESHOLD_NONE 0x04 123d8b46839SM'boumba Cedric Madianga 124d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MAX_DATA_ITEMS 0xffff 12580a76952SPierre Yves MORDRET /* 12680a76952SPierre Yves MORDRET * Valid transfer starts from @0 to @0xFFFE leading to unaligned scatter 12780a76952SPierre Yves MORDRET * gather at boundary. Thus it's safer to round down this value on FIFO 12880a76952SPierre Yves MORDRET * size (16 Bytes) 12980a76952SPierre Yves MORDRET */ 13080a76952SPierre Yves MORDRET #define STM32_DMA_ALIGNED_MAX_DATA_ITEMS \ 13180a76952SPierre Yves MORDRET ALIGN_DOWN(STM32_DMA_MAX_DATA_ITEMS, 16) 132d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MAX_CHANNELS 0x08 133d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MAX_REQUEST_ID 0x08 134d8b46839SM'boumba Cedric Madianga #define STM32_DMA_MAX_DATA_PARAM 0x03 135a2b6103bSPierre Yves MORDRET #define STM32_DMA_FIFO_SIZE 16 /* FIFO is 16 bytes */ 136a2b6103bSPierre Yves MORDRET #define STM32_DMA_MIN_BURST 4 137276b0046SM'boumba Cedric Madianga #define STM32_DMA_MAX_BURST 16 138d8b46839SM'boumba Cedric Madianga 139951f44cbSPierre Yves MORDRET /* DMA Features */ 140951f44cbSPierre Yves MORDRET #define STM32_DMA_THRESHOLD_FTR_MASK GENMASK(1, 0) 141955b1766SAmelie Delaunay #define STM32_DMA_DIRECT_MODE_MASK BIT(2) 1422b5b7405SAmelie Delaunay #define STM32_DMA_ALT_ACK_MODE_MASK BIT(4) 14372379517SAmelie Delaunay #define STM32_DMA_MDMA_STREAM_ID_MASK GENMASK(19, 16) 144951f44cbSPierre Yves MORDRET 145d8b46839SM'boumba Cedric Madianga enum stm32_dma_width { 146d8b46839SM'boumba Cedric Madianga STM32_DMA_BYTE, 147d8b46839SM'boumba Cedric Madianga STM32_DMA_HALF_WORD, 148d8b46839SM'boumba Cedric Madianga STM32_DMA_WORD, 149d8b46839SM'boumba Cedric Madianga }; 150d8b46839SM'boumba Cedric Madianga 151d8b46839SM'boumba Cedric Madianga enum stm32_dma_burst_size { 152d8b46839SM'boumba Cedric Madianga STM32_DMA_BURST_SINGLE, 153d8b46839SM'boumba Cedric Madianga STM32_DMA_BURST_INCR4, 154d8b46839SM'boumba Cedric Madianga STM32_DMA_BURST_INCR8, 155d8b46839SM'boumba Cedric Madianga STM32_DMA_BURST_INCR16, 156d8b46839SM'boumba Cedric Madianga }; 157d8b46839SM'boumba Cedric Madianga 158951f44cbSPierre Yves MORDRET /** 159951f44cbSPierre Yves MORDRET * struct stm32_dma_cfg - STM32 DMA custom configuration 160951f44cbSPierre Yves MORDRET * @channel_id: channel ID 161951f44cbSPierre Yves MORDRET * @request_line: DMA request 162951f44cbSPierre Yves MORDRET * @stream_config: 32bit mask specifying the DMA channel configuration 163951f44cbSPierre Yves MORDRET * @features: 32bit mask specifying the DMA Feature list 164951f44cbSPierre Yves MORDRET */ 165d8b46839SM'boumba Cedric Madianga struct stm32_dma_cfg { 166d8b46839SM'boumba Cedric Madianga u32 channel_id; 167d8b46839SM'boumba Cedric Madianga u32 request_line; 168d8b46839SM'boumba Cedric Madianga u32 stream_config; 169951f44cbSPierre Yves MORDRET u32 features; 170d8b46839SM'boumba Cedric Madianga }; 171d8b46839SM'boumba Cedric Madianga 172d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan_reg { 173d8b46839SM'boumba Cedric Madianga u32 dma_lisr; 174d8b46839SM'boumba Cedric Madianga u32 dma_hisr; 175d8b46839SM'boumba Cedric Madianga u32 dma_lifcr; 176d8b46839SM'boumba Cedric Madianga u32 dma_hifcr; 177d8b46839SM'boumba Cedric Madianga u32 dma_scr; 178d8b46839SM'boumba Cedric Madianga u32 dma_sndtr; 179d8b46839SM'boumba Cedric Madianga u32 dma_spar; 180d8b46839SM'boumba Cedric Madianga u32 dma_sm0ar; 181d8b46839SM'boumba Cedric Madianga u32 dma_sm1ar; 182d8b46839SM'boumba Cedric Madianga u32 dma_sfcr; 183d8b46839SM'boumba Cedric Madianga }; 184d8b46839SM'boumba Cedric Madianga 185d8b46839SM'boumba Cedric Madianga struct stm32_dma_sg_req { 186d8b46839SM'boumba Cedric Madianga u32 len; 187d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan_reg chan_reg; 188d8b46839SM'boumba Cedric Madianga }; 189d8b46839SM'boumba Cedric Madianga 190d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc { 191d8b46839SM'boumba Cedric Madianga struct virt_dma_desc vdesc; 192d8b46839SM'boumba Cedric Madianga bool cyclic; 193d8b46839SM'boumba Cedric Madianga u32 num_sgs; 194d8b46839SM'boumba Cedric Madianga struct stm32_dma_sg_req sg_req[]; 195d8b46839SM'boumba Cedric Madianga }; 196d8b46839SM'boumba Cedric Madianga 19772379517SAmelie Delaunay /** 19872379517SAmelie Delaunay * struct stm32_dma_mdma_config - STM32 DMA MDMA configuration 19972379517SAmelie Delaunay * @stream_id: DMA request to trigger STM32 MDMA transfer 20072379517SAmelie Delaunay * @ifcr: DMA interrupt flag clear register address, 20172379517SAmelie Delaunay * used by STM32 MDMA to clear DMA Transfer Complete flag 20272379517SAmelie Delaunay * @tcf: DMA Transfer Complete flag 20372379517SAmelie Delaunay */ 20472379517SAmelie Delaunay struct stm32_dma_mdma_config { 20572379517SAmelie Delaunay u32 stream_id; 20672379517SAmelie Delaunay u32 ifcr; 20772379517SAmelie Delaunay u32 tcf; 20872379517SAmelie Delaunay }; 20972379517SAmelie Delaunay 210d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan { 211d8b46839SM'boumba Cedric Madianga struct virt_dma_chan vchan; 212d8b46839SM'boumba Cedric Madianga bool config_init; 213d8b46839SM'boumba Cedric Madianga bool busy; 214d8b46839SM'boumba Cedric Madianga u32 id; 215d8b46839SM'boumba Cedric Madianga u32 irq; 216d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc; 217d8b46839SM'boumba Cedric Madianga u32 next_sg; 218d8b46839SM'boumba Cedric Madianga struct dma_slave_config dma_sconfig; 219d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan_reg chan_reg; 220951f44cbSPierre Yves MORDRET u32 threshold; 221a2b6103bSPierre Yves MORDRET u32 mem_burst; 222a2b6103bSPierre Yves MORDRET u32 mem_width; 223099a9a94SAmelie Delaunay enum dma_status status; 22472379517SAmelie Delaunay bool trig_mdma; 22572379517SAmelie Delaunay struct stm32_dma_mdma_config mdma_config; 226d8b46839SM'boumba Cedric Madianga }; 227d8b46839SM'boumba Cedric Madianga 228d8b46839SM'boumba Cedric Madianga struct stm32_dma_device { 229d8b46839SM'boumba Cedric Madianga struct dma_device ddev; 230d8b46839SM'boumba Cedric Madianga void __iomem *base; 231d8b46839SM'boumba Cedric Madianga struct clk *clk; 232d8b46839SM'boumba Cedric Madianga bool mem2mem; 233d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS]; 234d8b46839SM'boumba Cedric Madianga }; 235d8b46839SM'boumba Cedric Madianga 236d8b46839SM'boumba Cedric Madianga static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan) 237d8b46839SM'boumba Cedric Madianga { 238d8b46839SM'boumba Cedric Madianga return container_of(chan->vchan.chan.device, struct stm32_dma_device, 239d8b46839SM'boumba Cedric Madianga ddev); 240d8b46839SM'boumba Cedric Madianga } 241d8b46839SM'boumba Cedric Madianga 242d8b46839SM'boumba Cedric Madianga static struct stm32_dma_chan *to_stm32_dma_chan(struct dma_chan *c) 243d8b46839SM'boumba Cedric Madianga { 244d8b46839SM'boumba Cedric Madianga return container_of(c, struct stm32_dma_chan, vchan.chan); 245d8b46839SM'boumba Cedric Madianga } 246d8b46839SM'boumba Cedric Madianga 247d8b46839SM'boumba Cedric Madianga static struct stm32_dma_desc *to_stm32_dma_desc(struct virt_dma_desc *vdesc) 248d8b46839SM'boumba Cedric Madianga { 249d8b46839SM'boumba Cedric Madianga return container_of(vdesc, struct stm32_dma_desc, vdesc); 250d8b46839SM'boumba Cedric Madianga } 251d8b46839SM'boumba Cedric Madianga 252d8b46839SM'boumba Cedric Madianga static struct device *chan2dev(struct stm32_dma_chan *chan) 253d8b46839SM'boumba Cedric Madianga { 254d8b46839SM'boumba Cedric Madianga return &chan->vchan.chan.dev->device; 255d8b46839SM'boumba Cedric Madianga } 256d8b46839SM'boumba Cedric Madianga 257d8b46839SM'boumba Cedric Madianga static u32 stm32_dma_read(struct stm32_dma_device *dmadev, u32 reg) 258d8b46839SM'boumba Cedric Madianga { 259d8b46839SM'boumba Cedric Madianga return readl_relaxed(dmadev->base + reg); 260d8b46839SM'boumba Cedric Madianga } 261d8b46839SM'boumba Cedric Madianga 262d8b46839SM'boumba Cedric Madianga static void stm32_dma_write(struct stm32_dma_device *dmadev, u32 reg, u32 val) 263d8b46839SM'boumba Cedric Madianga { 264d8b46839SM'boumba Cedric Madianga writel_relaxed(val, dmadev->base + reg); 265d8b46839SM'boumba Cedric Madianga } 266d8b46839SM'boumba Cedric Madianga 267d8b46839SM'boumba Cedric Madianga static int stm32_dma_get_width(struct stm32_dma_chan *chan, 268d8b46839SM'boumba Cedric Madianga enum dma_slave_buswidth width) 269d8b46839SM'boumba Cedric Madianga { 270d8b46839SM'boumba Cedric Madianga switch (width) { 271d8b46839SM'boumba Cedric Madianga case DMA_SLAVE_BUSWIDTH_1_BYTE: 272d8b46839SM'boumba Cedric Madianga return STM32_DMA_BYTE; 273d8b46839SM'boumba Cedric Madianga case DMA_SLAVE_BUSWIDTH_2_BYTES: 274d8b46839SM'boumba Cedric Madianga return STM32_DMA_HALF_WORD; 275d8b46839SM'boumba Cedric Madianga case DMA_SLAVE_BUSWIDTH_4_BYTES: 276d8b46839SM'boumba Cedric Madianga return STM32_DMA_WORD; 277d8b46839SM'boumba Cedric Madianga default: 278d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Dma bus width not supported\n"); 279d8b46839SM'boumba Cedric Madianga return -EINVAL; 280d8b46839SM'boumba Cedric Madianga } 281d8b46839SM'boumba Cedric Madianga } 282d8b46839SM'boumba Cedric Madianga 283a2b6103bSPierre Yves MORDRET static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, 284e0ebdbdcSAmelie Delaunay dma_addr_t buf_addr, 285a2b6103bSPierre Yves MORDRET u32 threshold) 286a2b6103bSPierre Yves MORDRET { 287a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth max_width; 288a2b6103bSPierre Yves MORDRET 289a2b6103bSPierre Yves MORDRET if (threshold == STM32_DMA_FIFO_THRESHOLD_FULL) 290a2b6103bSPierre Yves MORDRET max_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 291a2b6103bSPierre Yves MORDRET else 292a2b6103bSPierre Yves MORDRET max_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 293a2b6103bSPierre Yves MORDRET 294a2b6103bSPierre Yves MORDRET while ((buf_len < max_width || buf_len % max_width) && 295a2b6103bSPierre Yves MORDRET max_width > DMA_SLAVE_BUSWIDTH_1_BYTE) 296a2b6103bSPierre Yves MORDRET max_width = max_width >> 1; 297a2b6103bSPierre Yves MORDRET 29824983633SArnd Bergmann if (buf_addr & (max_width - 1)) 299e0ebdbdcSAmelie Delaunay max_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 300e0ebdbdcSAmelie Delaunay 301a2b6103bSPierre Yves MORDRET return max_width; 302a2b6103bSPierre Yves MORDRET } 303a2b6103bSPierre Yves MORDRET 304a2b6103bSPierre Yves MORDRET static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, 305a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth width) 306a2b6103bSPierre Yves MORDRET { 307a2b6103bSPierre Yves MORDRET u32 remaining; 308a2b6103bSPierre Yves MORDRET 309955b1766SAmelie Delaunay if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE) 310955b1766SAmelie Delaunay return false; 311955b1766SAmelie Delaunay 312a2b6103bSPierre Yves MORDRET if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) { 313a2b6103bSPierre Yves MORDRET if (burst != 0) { 314a2b6103bSPierre Yves MORDRET /* 315a2b6103bSPierre Yves MORDRET * If number of beats fit in several whole bursts 316a2b6103bSPierre Yves MORDRET * this configuration is allowed. 317a2b6103bSPierre Yves MORDRET */ 318a2b6103bSPierre Yves MORDRET remaining = ((STM32_DMA_FIFO_SIZE / width) * 319a2b6103bSPierre Yves MORDRET (threshold + 1) / 4) % burst; 320a2b6103bSPierre Yves MORDRET 321a2b6103bSPierre Yves MORDRET if (remaining == 0) 322a2b6103bSPierre Yves MORDRET return true; 323a2b6103bSPierre Yves MORDRET } else { 324a2b6103bSPierre Yves MORDRET return true; 325a2b6103bSPierre Yves MORDRET } 326a2b6103bSPierre Yves MORDRET } 327a2b6103bSPierre Yves MORDRET 328a2b6103bSPierre Yves MORDRET return false; 329a2b6103bSPierre Yves MORDRET } 330a2b6103bSPierre Yves MORDRET 331a2b6103bSPierre Yves MORDRET static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold) 332a2b6103bSPierre Yves MORDRET { 333955b1766SAmelie Delaunay /* If FIFO direct mode, burst is not possible */ 334955b1766SAmelie Delaunay if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE) 335955b1766SAmelie Delaunay return false; 336955b1766SAmelie Delaunay 337cc832dc8SPierre-Yves MORDRET /* 338cc832dc8SPierre-Yves MORDRET * Buffer or period length has to be aligned on FIFO depth. 339cc832dc8SPierre-Yves MORDRET * Otherwise bytes may be stuck within FIFO at buffer or period 340cc832dc8SPierre-Yves MORDRET * length. 341cc832dc8SPierre-Yves MORDRET */ 342cc832dc8SPierre-Yves MORDRET return ((buf_len % ((threshold + 1) * 4)) == 0); 343a2b6103bSPierre Yves MORDRET } 344a2b6103bSPierre Yves MORDRET 345a2b6103bSPierre Yves MORDRET static u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold, 346a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth width) 347a2b6103bSPierre Yves MORDRET { 348a2b6103bSPierre Yves MORDRET u32 best_burst = max_burst; 349a2b6103bSPierre Yves MORDRET 350a2b6103bSPierre Yves MORDRET if (best_burst == 1 || !stm32_dma_is_burst_possible(buf_len, threshold)) 351a2b6103bSPierre Yves MORDRET return 0; 352a2b6103bSPierre Yves MORDRET 353a2b6103bSPierre Yves MORDRET while ((buf_len < best_burst * width && best_burst > 1) || 354a2b6103bSPierre Yves MORDRET !stm32_dma_fifo_threshold_is_allowed(best_burst, threshold, 355a2b6103bSPierre Yves MORDRET width)) { 356a2b6103bSPierre Yves MORDRET if (best_burst > STM32_DMA_MIN_BURST) 357a2b6103bSPierre Yves MORDRET best_burst = best_burst >> 1; 358a2b6103bSPierre Yves MORDRET else 359a2b6103bSPierre Yves MORDRET best_burst = 0; 360a2b6103bSPierre Yves MORDRET } 361a2b6103bSPierre Yves MORDRET 362a2b6103bSPierre Yves MORDRET return best_burst; 363a2b6103bSPierre Yves MORDRET } 364a2b6103bSPierre Yves MORDRET 365d8b46839SM'boumba Cedric Madianga static int stm32_dma_get_burst(struct stm32_dma_chan *chan, u32 maxburst) 366d8b46839SM'boumba Cedric Madianga { 367d8b46839SM'boumba Cedric Madianga switch (maxburst) { 368d8b46839SM'boumba Cedric Madianga case 0: 369d8b46839SM'boumba Cedric Madianga case 1: 370d8b46839SM'boumba Cedric Madianga return STM32_DMA_BURST_SINGLE; 371d8b46839SM'boumba Cedric Madianga case 4: 372d8b46839SM'boumba Cedric Madianga return STM32_DMA_BURST_INCR4; 373d8b46839SM'boumba Cedric Madianga case 8: 374d8b46839SM'boumba Cedric Madianga return STM32_DMA_BURST_INCR8; 375d8b46839SM'boumba Cedric Madianga case 16: 376d8b46839SM'boumba Cedric Madianga return STM32_DMA_BURST_INCR16; 377d8b46839SM'boumba Cedric Madianga default: 378d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Dma burst size not supported\n"); 379d8b46839SM'boumba Cedric Madianga return -EINVAL; 380d8b46839SM'boumba Cedric Madianga } 381d8b46839SM'boumba Cedric Madianga } 382d8b46839SM'boumba Cedric Madianga 383d8b46839SM'boumba Cedric Madianga static void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan, 384a2b6103bSPierre Yves MORDRET u32 src_burst, u32 dst_burst) 385d8b46839SM'boumba Cedric Madianga { 386d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_MASK; 387d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_DMEIE; 388d8b46839SM'boumba Cedric Madianga 389a2b6103bSPierre Yves MORDRET if (!src_burst && !dst_burst) { 390d8b46839SM'boumba Cedric Madianga /* Using direct mode */ 391d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_DMEIE; 392d8b46839SM'boumba Cedric Madianga } else { 393d8b46839SM'boumba Cedric Madianga /* Using FIFO mode */ 394d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_MASK; 395d8b46839SM'boumba Cedric Madianga } 396d8b46839SM'boumba Cedric Madianga } 397d8b46839SM'boumba Cedric Madianga 398d8b46839SM'boumba Cedric Madianga static int stm32_dma_slave_config(struct dma_chan *c, 399d8b46839SM'boumba Cedric Madianga struct dma_slave_config *config) 400d8b46839SM'boumba Cedric Madianga { 401d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 402d8b46839SM'boumba Cedric Madianga 403d8b46839SM'boumba Cedric Madianga memcpy(&chan->dma_sconfig, config, sizeof(*config)); 404d8b46839SM'boumba Cedric Madianga 40572379517SAmelie Delaunay /* Check if user is requesting DMA to trigger STM32 MDMA */ 40672379517SAmelie Delaunay if (config->peripheral_size) { 40772379517SAmelie Delaunay config->peripheral_config = &chan->mdma_config; 40872379517SAmelie Delaunay config->peripheral_size = sizeof(chan->mdma_config); 40972379517SAmelie Delaunay chan->trig_mdma = true; 41072379517SAmelie Delaunay } 41172379517SAmelie Delaunay 412d8b46839SM'boumba Cedric Madianga chan->config_init = true; 413d8b46839SM'boumba Cedric Madianga 414d8b46839SM'boumba Cedric Madianga return 0; 415d8b46839SM'boumba Cedric Madianga } 416d8b46839SM'boumba Cedric Madianga 417d8b46839SM'boumba Cedric Madianga static u32 stm32_dma_irq_status(struct stm32_dma_chan *chan) 418d8b46839SM'boumba Cedric Madianga { 419d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 420d8b46839SM'boumba Cedric Madianga u32 flags, dma_isr; 421d8b46839SM'boumba Cedric Madianga 422d8b46839SM'boumba Cedric Madianga /* 423d8b46839SM'boumba Cedric Madianga * Read "flags" from DMA_xISR register corresponding to the selected 424d8b46839SM'boumba Cedric Madianga * DMA channel at the correct bit offset inside that register. 425d8b46839SM'boumba Cedric Madianga */ 426d8b46839SM'boumba Cedric Madianga 4274dc36a53SAmelie Delaunay dma_isr = stm32_dma_read(dmadev, STM32_DMA_ISR(chan->id)); 4284dc36a53SAmelie Delaunay flags = dma_isr >> STM32_DMA_FLAGS_SHIFT(chan->id); 429d8b46839SM'boumba Cedric Madianga 4309df3bd55SPierre Yves MORDRET return flags & STM32_DMA_MASKI; 431d8b46839SM'boumba Cedric Madianga } 432d8b46839SM'boumba Cedric Madianga 433d8b46839SM'boumba Cedric Madianga static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) 434d8b46839SM'boumba Cedric Madianga { 435d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 436d8b46839SM'boumba Cedric Madianga u32 dma_ifcr; 437d8b46839SM'boumba Cedric Madianga 438d8b46839SM'boumba Cedric Madianga /* 439d8b46839SM'boumba Cedric Madianga * Write "flags" to the DMA_xIFCR register corresponding to the selected 440d8b46839SM'boumba Cedric Madianga * DMA channel at the correct bit offset inside that register. 441d8b46839SM'boumba Cedric Madianga */ 4429df3bd55SPierre Yves MORDRET flags &= STM32_DMA_MASKI; 4434dc36a53SAmelie Delaunay dma_ifcr = flags << STM32_DMA_FLAGS_SHIFT(chan->id); 444d8b46839SM'boumba Cedric Madianga 4454dc36a53SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_IFCR(chan->id), dma_ifcr); 446d8b46839SM'boumba Cedric Madianga } 447d8b46839SM'boumba Cedric Madianga 448d8b46839SM'boumba Cedric Madianga static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) 449d8b46839SM'boumba Cedric Madianga { 450d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 451409ffc4dSAmelie Delaunay u32 dma_scr, id, reg; 452d8b46839SM'boumba Cedric Madianga 453d8b46839SM'boumba Cedric Madianga id = chan->id; 454409ffc4dSAmelie Delaunay reg = STM32_DMA_SCR(id); 455409ffc4dSAmelie Delaunay dma_scr = stm32_dma_read(dmadev, reg); 456d8b46839SM'boumba Cedric Madianga 457d8b46839SM'boumba Cedric Madianga if (dma_scr & STM32_DMA_SCR_EN) { 458d8b46839SM'boumba Cedric Madianga dma_scr &= ~STM32_DMA_SCR_EN; 459409ffc4dSAmelie Delaunay stm32_dma_write(dmadev, reg, dma_scr); 460d8b46839SM'boumba Cedric Madianga 461409ffc4dSAmelie Delaunay return readl_relaxed_poll_timeout_atomic(dmadev->base + reg, 462409ffc4dSAmelie Delaunay dma_scr, !(dma_scr & STM32_DMA_SCR_EN), 463409ffc4dSAmelie Delaunay 10, 1000000); 464d8b46839SM'boumba Cedric Madianga } 465d8b46839SM'boumba Cedric Madianga 466d8b46839SM'boumba Cedric Madianga return 0; 467d8b46839SM'boumba Cedric Madianga } 468d8b46839SM'boumba Cedric Madianga 469d8b46839SM'boumba Cedric Madianga static void stm32_dma_stop(struct stm32_dma_chan *chan) 470d8b46839SM'boumba Cedric Madianga { 471d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 472d8b46839SM'boumba Cedric Madianga u32 dma_scr, dma_sfcr, status; 473d8b46839SM'boumba Cedric Madianga int ret; 474d8b46839SM'boumba Cedric Madianga 475d8b46839SM'boumba Cedric Madianga /* Disable interrupts */ 476d8b46839SM'boumba Cedric Madianga dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 477d8b46839SM'boumba Cedric Madianga dma_scr &= ~STM32_DMA_SCR_IRQ_MASK; 478d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); 479d8b46839SM'boumba Cedric Madianga dma_sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); 480d8b46839SM'boumba Cedric Madianga dma_sfcr &= ~STM32_DMA_SFCR_FEIE; 481d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), dma_sfcr); 482d8b46839SM'boumba Cedric Madianga 483d8b46839SM'boumba Cedric Madianga /* Disable DMA */ 484d8b46839SM'boumba Cedric Madianga ret = stm32_dma_disable_chan(chan); 485d8b46839SM'boumba Cedric Madianga if (ret < 0) 486d8b46839SM'boumba Cedric Madianga return; 487d8b46839SM'boumba Cedric Madianga 488d8b46839SM'boumba Cedric Madianga /* Clear interrupt status if it is there */ 489d8b46839SM'boumba Cedric Madianga status = stm32_dma_irq_status(chan); 490d8b46839SM'boumba Cedric Madianga if (status) { 491d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "%s(): clearing interrupt: 0x%08x\n", 492d8b46839SM'boumba Cedric Madianga __func__, status); 493d8b46839SM'boumba Cedric Madianga stm32_dma_irq_clear(chan, status); 494d8b46839SM'boumba Cedric Madianga } 495d8b46839SM'boumba Cedric Madianga 496d8b46839SM'boumba Cedric Madianga chan->busy = false; 497099a9a94SAmelie Delaunay chan->status = DMA_COMPLETE; 498d8b46839SM'boumba Cedric Madianga } 499d8b46839SM'boumba Cedric Madianga 500d8b46839SM'boumba Cedric Madianga static int stm32_dma_terminate_all(struct dma_chan *c) 501d8b46839SM'boumba Cedric Madianga { 502d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 503d8b46839SM'boumba Cedric Madianga unsigned long flags; 504d8b46839SM'boumba Cedric Madianga LIST_HEAD(head); 505d8b46839SM'boumba Cedric Madianga 506d8b46839SM'boumba Cedric Madianga spin_lock_irqsave(&chan->vchan.lock, flags); 507d8b46839SM'boumba Cedric Madianga 508d80cbef3SAmelie Delaunay if (chan->desc) { 50979e40b06SAmelie Delaunay dma_cookie_complete(&chan->desc->vdesc.tx); 510d80cbef3SAmelie Delaunay vchan_terminate_vdesc(&chan->desc->vdesc); 511d80cbef3SAmelie Delaunay if (chan->busy) 512d8b46839SM'boumba Cedric Madianga stm32_dma_stop(chan); 513d8b46839SM'boumba Cedric Madianga chan->desc = NULL; 514d8b46839SM'boumba Cedric Madianga } 515d8b46839SM'boumba Cedric Madianga 516d8b46839SM'boumba Cedric Madianga vchan_get_all_descriptors(&chan->vchan, &head); 517d8b46839SM'boumba Cedric Madianga spin_unlock_irqrestore(&chan->vchan.lock, flags); 518d8b46839SM'boumba Cedric Madianga vchan_dma_desc_free_list(&chan->vchan, &head); 519d8b46839SM'boumba Cedric Madianga 520d8b46839SM'boumba Cedric Madianga return 0; 521d8b46839SM'boumba Cedric Madianga } 522d8b46839SM'boumba Cedric Madianga 523dc808675SM'boumba Cedric Madianga static void stm32_dma_synchronize(struct dma_chan *c) 524dc808675SM'boumba Cedric Madianga { 525dc808675SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 526dc808675SM'boumba Cedric Madianga 527dc808675SM'boumba Cedric Madianga vchan_synchronize(&chan->vchan); 528dc808675SM'boumba Cedric Madianga } 529dc808675SM'boumba Cedric Madianga 530d8b46839SM'boumba Cedric Madianga static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) 531d8b46839SM'boumba Cedric Madianga { 532d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 533d8b46839SM'boumba Cedric Madianga u32 scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 534d8b46839SM'boumba Cedric Madianga u32 ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); 535d8b46839SM'boumba Cedric Madianga u32 spar = stm32_dma_read(dmadev, STM32_DMA_SPAR(chan->id)); 536d8b46839SM'boumba Cedric Madianga u32 sm0ar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(chan->id)); 537d8b46839SM'boumba Cedric Madianga u32 sm1ar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(chan->id)); 538d8b46839SM'boumba Cedric Madianga u32 sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); 539d8b46839SM'boumba Cedric Madianga 540d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SCR: 0x%08x\n", scr); 541d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "NDTR: 0x%08x\n", ndtr); 542d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SPAR: 0x%08x\n", spar); 543d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SM0AR: 0x%08x\n", sm0ar); 544d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SM1AR: 0x%08x\n", sm1ar); 545d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); 546d8b46839SM'boumba Cedric Madianga } 547d8b46839SM'boumba Cedric Madianga 548db60a63eSAmelie Delaunay static void stm32_dma_sg_inc(struct stm32_dma_chan *chan) 549db60a63eSAmelie Delaunay { 550db60a63eSAmelie Delaunay chan->next_sg++; 551db60a63eSAmelie Delaunay if (chan->desc->cyclic && (chan->next_sg == chan->desc->num_sgs)) 552db60a63eSAmelie Delaunay chan->next_sg = 0; 553db60a63eSAmelie Delaunay } 554db60a63eSAmelie Delaunay 555e57cb3b3SPierre Yves MORDRET static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan); 556e57cb3b3SPierre Yves MORDRET 5578d1b76f0SM'boumba Cedric Madianga static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) 558d8b46839SM'boumba Cedric Madianga { 559d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 560d8b46839SM'boumba Cedric Madianga struct virt_dma_desc *vdesc; 561d8b46839SM'boumba Cedric Madianga struct stm32_dma_sg_req *sg_req; 562d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan_reg *reg; 563d8b46839SM'boumba Cedric Madianga u32 status; 564d8b46839SM'boumba Cedric Madianga int ret; 565d8b46839SM'boumba Cedric Madianga 566d8b46839SM'boumba Cedric Madianga ret = stm32_dma_disable_chan(chan); 567d8b46839SM'boumba Cedric Madianga if (ret < 0) 5688d1b76f0SM'boumba Cedric Madianga return; 569d8b46839SM'boumba Cedric Madianga 570d8b46839SM'boumba Cedric Madianga if (!chan->desc) { 571d8b46839SM'boumba Cedric Madianga vdesc = vchan_next_desc(&chan->vchan); 572d8b46839SM'boumba Cedric Madianga if (!vdesc) 5738d1b76f0SM'boumba Cedric Madianga return; 574d8b46839SM'boumba Cedric Madianga 575d80cbef3SAmelie Delaunay list_del(&vdesc->node); 576d80cbef3SAmelie Delaunay 577d8b46839SM'boumba Cedric Madianga chan->desc = to_stm32_dma_desc(vdesc); 578d8b46839SM'boumba Cedric Madianga chan->next_sg = 0; 579d8b46839SM'boumba Cedric Madianga } 580d8b46839SM'boumba Cedric Madianga 581d8b46839SM'boumba Cedric Madianga if (chan->next_sg == chan->desc->num_sgs) 582d8b46839SM'boumba Cedric Madianga chan->next_sg = 0; 583d8b46839SM'boumba Cedric Madianga 584d8b46839SM'boumba Cedric Madianga sg_req = &chan->desc->sg_req[chan->next_sg]; 585d8b46839SM'boumba Cedric Madianga reg = &sg_req->chan_reg; 586d8b46839SM'boumba Cedric Madianga 58772379517SAmelie Delaunay /* When DMA triggers STM32 MDMA, DMA Transfer Complete is managed by STM32 MDMA */ 58872379517SAmelie Delaunay if (chan->trig_mdma && chan->dma_sconfig.direction != DMA_MEM_TO_DEV) 58972379517SAmelie Delaunay reg->dma_scr &= ~STM32_DMA_SCR_TCIE; 59072379517SAmelie Delaunay 59122a0bb29SPierre-Yves MORDRET reg->dma_scr &= ~STM32_DMA_SCR_EN; 592d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); 593d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar); 594d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SM0AR(chan->id), reg->dma_sm0ar); 595d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), reg->dma_sfcr); 596d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SM1AR(chan->id), reg->dma_sm1ar); 597d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), reg->dma_sndtr); 598d8b46839SM'boumba Cedric Madianga 599db60a63eSAmelie Delaunay stm32_dma_sg_inc(chan); 600d8b46839SM'boumba Cedric Madianga 601d8b46839SM'boumba Cedric Madianga /* Clear interrupt status if it is there */ 602d8b46839SM'boumba Cedric Madianga status = stm32_dma_irq_status(chan); 603d8b46839SM'boumba Cedric Madianga if (status) 604d8b46839SM'boumba Cedric Madianga stm32_dma_irq_clear(chan, status); 605d8b46839SM'boumba Cedric Madianga 606e57cb3b3SPierre Yves MORDRET if (chan->desc->cyclic) 607e57cb3b3SPierre Yves MORDRET stm32_dma_configure_next_sg(chan); 608e57cb3b3SPierre Yves MORDRET 609d8b46839SM'boumba Cedric Madianga stm32_dma_dump_reg(chan); 610d8b46839SM'boumba Cedric Madianga 611d8b46839SM'boumba Cedric Madianga /* Start DMA */ 612099a9a94SAmelie Delaunay chan->busy = true; 613099a9a94SAmelie Delaunay chan->status = DMA_IN_PROGRESS; 614d8b46839SM'boumba Cedric Madianga reg->dma_scr |= STM32_DMA_SCR_EN; 615d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); 616d8b46839SM'boumba Cedric Madianga 61790ec93cbSBenjamin Gaignard dev_dbg(chan2dev(chan), "vchan %pK: started\n", &chan->vchan); 618d8b46839SM'boumba Cedric Madianga } 619d8b46839SM'boumba Cedric Madianga 620d8b46839SM'boumba Cedric Madianga static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) 621d8b46839SM'boumba Cedric Madianga { 622d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 623d8b46839SM'boumba Cedric Madianga struct stm32_dma_sg_req *sg_req; 624d8b46839SM'boumba Cedric Madianga u32 dma_scr, dma_sm0ar, dma_sm1ar, id; 625d8b46839SM'boumba Cedric Madianga 626d8b46839SM'boumba Cedric Madianga id = chan->id; 627d8b46839SM'boumba Cedric Madianga dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 628d8b46839SM'boumba Cedric Madianga 629d8b46839SM'boumba Cedric Madianga sg_req = &chan->desc->sg_req[chan->next_sg]; 630d8b46839SM'boumba Cedric Madianga 631d8b46839SM'boumba Cedric Madianga if (dma_scr & STM32_DMA_SCR_CT) { 632d8b46839SM'boumba Cedric Madianga dma_sm0ar = sg_req->chan_reg.dma_sm0ar; 633d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar); 634d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n", 635d8b46839SM'boumba Cedric Madianga stm32_dma_read(dmadev, STM32_DMA_SM0AR(id))); 636d8b46839SM'boumba Cedric Madianga } else { 637d8b46839SM'boumba Cedric Madianga dma_sm1ar = sg_req->chan_reg.dma_sm1ar; 638d8b46839SM'boumba Cedric Madianga stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar); 639d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n", 640d8b46839SM'boumba Cedric Madianga stm32_dma_read(dmadev, STM32_DMA_SM1AR(id))); 641d8b46839SM'boumba Cedric Madianga } 642d8b46839SM'boumba Cedric Madianga } 643d8b46839SM'boumba Cedric Madianga 644099a9a94SAmelie Delaunay static void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan) 645099a9a94SAmelie Delaunay { 646099a9a94SAmelie Delaunay struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 647099a9a94SAmelie Delaunay u32 dma_scr; 648099a9a94SAmelie Delaunay 649099a9a94SAmelie Delaunay /* 650099a9a94SAmelie Delaunay * Read and store current remaining data items and peripheral/memory addresses to be 651099a9a94SAmelie Delaunay * updated on resume 652099a9a94SAmelie Delaunay */ 653099a9a94SAmelie Delaunay dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 654099a9a94SAmelie Delaunay /* 655099a9a94SAmelie Delaunay * Transfer can be paused while between a previous resume and reconfiguration on transfer 656099a9a94SAmelie Delaunay * complete. If transfer is cyclic and CIRC and DBM have been deactivated for resume, need 657099a9a94SAmelie Delaunay * to set it here in SCR backup to ensure a good reconfiguration on transfer complete. 658099a9a94SAmelie Delaunay */ 659099a9a94SAmelie Delaunay if (chan->desc && chan->desc->cyclic) { 660099a9a94SAmelie Delaunay if (chan->desc->num_sgs == 1) 661099a9a94SAmelie Delaunay dma_scr |= STM32_DMA_SCR_CIRC; 662099a9a94SAmelie Delaunay else 663099a9a94SAmelie Delaunay dma_scr |= STM32_DMA_SCR_DBM; 664099a9a94SAmelie Delaunay } 665099a9a94SAmelie Delaunay chan->chan_reg.dma_scr = dma_scr; 666099a9a94SAmelie Delaunay 667099a9a94SAmelie Delaunay /* 668099a9a94SAmelie Delaunay * Need to temporarily deactivate CIRC/DBM until next Transfer Complete interrupt, otherwise 669099a9a94SAmelie Delaunay * on resume NDTR autoreload value will be wrong (lower than the initial period length) 670099a9a94SAmelie Delaunay */ 671099a9a94SAmelie Delaunay if (chan->desc && chan->desc->cyclic) { 672099a9a94SAmelie Delaunay dma_scr &= ~(STM32_DMA_SCR_DBM | STM32_DMA_SCR_CIRC); 673099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); 674099a9a94SAmelie Delaunay } 675099a9a94SAmelie Delaunay 676099a9a94SAmelie Delaunay chan->chan_reg.dma_sndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); 677099a9a94SAmelie Delaunay 678140fd5e7SAmelie Delaunay chan->status = DMA_PAUSED; 679140fd5e7SAmelie Delaunay 680099a9a94SAmelie Delaunay dev_dbg(chan2dev(chan), "vchan %pK: paused\n", &chan->vchan); 681099a9a94SAmelie Delaunay } 682099a9a94SAmelie Delaunay 683099a9a94SAmelie Delaunay static void stm32_dma_post_resume_reconfigure(struct stm32_dma_chan *chan) 684099a9a94SAmelie Delaunay { 685099a9a94SAmelie Delaunay struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 686099a9a94SAmelie Delaunay struct stm32_dma_sg_req *sg_req; 687099a9a94SAmelie Delaunay u32 dma_scr, status, id; 688099a9a94SAmelie Delaunay 689099a9a94SAmelie Delaunay id = chan->id; 690099a9a94SAmelie Delaunay dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 691099a9a94SAmelie Delaunay 692099a9a94SAmelie Delaunay /* Clear interrupt status if it is there */ 693099a9a94SAmelie Delaunay status = stm32_dma_irq_status(chan); 694099a9a94SAmelie Delaunay if (status) 695099a9a94SAmelie Delaunay stm32_dma_irq_clear(chan, status); 696099a9a94SAmelie Delaunay 697099a9a94SAmelie Delaunay if (!chan->next_sg) 698099a9a94SAmelie Delaunay sg_req = &chan->desc->sg_req[chan->desc->num_sgs - 1]; 699099a9a94SAmelie Delaunay else 700099a9a94SAmelie Delaunay sg_req = &chan->desc->sg_req[chan->next_sg - 1]; 701099a9a94SAmelie Delaunay 702099a9a94SAmelie Delaunay /* Reconfigure NDTR with the initial value */ 703099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), sg_req->chan_reg.dma_sndtr); 704099a9a94SAmelie Delaunay 705099a9a94SAmelie Delaunay /* Restore SPAR */ 706099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SPAR(id), sg_req->chan_reg.dma_spar); 707099a9a94SAmelie Delaunay 708099a9a94SAmelie Delaunay /* Restore SM0AR/SM1AR whatever DBM/CT as they may have been modified */ 709099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), sg_req->chan_reg.dma_sm0ar); 710099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), sg_req->chan_reg.dma_sm1ar); 711099a9a94SAmelie Delaunay 712099a9a94SAmelie Delaunay /* Reactivate CIRC/DBM if needed */ 713099a9a94SAmelie Delaunay if (chan->chan_reg.dma_scr & STM32_DMA_SCR_DBM) { 714099a9a94SAmelie Delaunay dma_scr |= STM32_DMA_SCR_DBM; 715099a9a94SAmelie Delaunay /* Restore CT */ 716099a9a94SAmelie Delaunay if (chan->chan_reg.dma_scr & STM32_DMA_SCR_CT) 717099a9a94SAmelie Delaunay dma_scr &= ~STM32_DMA_SCR_CT; 718099a9a94SAmelie Delaunay else 719099a9a94SAmelie Delaunay dma_scr |= STM32_DMA_SCR_CT; 720099a9a94SAmelie Delaunay } else if (chan->chan_reg.dma_scr & STM32_DMA_SCR_CIRC) { 721099a9a94SAmelie Delaunay dma_scr |= STM32_DMA_SCR_CIRC; 722099a9a94SAmelie Delaunay } 723099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); 724099a9a94SAmelie Delaunay 725099a9a94SAmelie Delaunay stm32_dma_configure_next_sg(chan); 726099a9a94SAmelie Delaunay 727099a9a94SAmelie Delaunay stm32_dma_dump_reg(chan); 728099a9a94SAmelie Delaunay 729099a9a94SAmelie Delaunay dma_scr |= STM32_DMA_SCR_EN; 730099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); 731099a9a94SAmelie Delaunay 732099a9a94SAmelie Delaunay dev_dbg(chan2dev(chan), "vchan %pK: reconfigured after pause/resume\n", &chan->vchan); 733099a9a94SAmelie Delaunay } 734099a9a94SAmelie Delaunay 735ded62306SAmelie Delaunay static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan, u32 scr) 736d8b46839SM'boumba Cedric Madianga { 737ded62306SAmelie Delaunay if (!chan->desc) 738ded62306SAmelie Delaunay return; 739ded62306SAmelie Delaunay 740d8b46839SM'boumba Cedric Madianga if (chan->desc->cyclic) { 741d8b46839SM'boumba Cedric Madianga vchan_cyclic_callback(&chan->desc->vdesc); 74272379517SAmelie Delaunay if (chan->trig_mdma) 74372379517SAmelie Delaunay return; 744db60a63eSAmelie Delaunay stm32_dma_sg_inc(chan); 745099a9a94SAmelie Delaunay /* cyclic while CIRC/DBM disable => post resume reconfiguration needed */ 746099a9a94SAmelie Delaunay if (!(scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM))) 747099a9a94SAmelie Delaunay stm32_dma_post_resume_reconfigure(chan); 748099a9a94SAmelie Delaunay else if (scr & STM32_DMA_SCR_DBM) 749d8b46839SM'boumba Cedric Madianga stm32_dma_configure_next_sg(chan); 750d8b46839SM'boumba Cedric Madianga } else { 751d8b46839SM'boumba Cedric Madianga chan->busy = false; 752099a9a94SAmelie Delaunay chan->status = DMA_COMPLETE; 753d8b46839SM'boumba Cedric Madianga if (chan->next_sg == chan->desc->num_sgs) { 754d8b46839SM'boumba Cedric Madianga vchan_cookie_complete(&chan->desc->vdesc); 755d8b46839SM'boumba Cedric Madianga chan->desc = NULL; 756d8b46839SM'boumba Cedric Madianga } 757d8b46839SM'boumba Cedric Madianga stm32_dma_start_transfer(chan); 758d8b46839SM'boumba Cedric Madianga } 759d8b46839SM'boumba Cedric Madianga } 760d8b46839SM'boumba Cedric Madianga 761d8b46839SM'boumba Cedric Madianga static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) 762d8b46839SM'boumba Cedric Madianga { 763d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = devid; 764d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 765ca4c72c0SPierre-Yves MORDRET u32 status, scr, sfcr; 766d8b46839SM'boumba Cedric Madianga 767d8b46839SM'boumba Cedric Madianga spin_lock(&chan->vchan.lock); 768d8b46839SM'boumba Cedric Madianga 769d8b46839SM'boumba Cedric Madianga status = stm32_dma_irq_status(chan); 770d8b46839SM'boumba Cedric Madianga scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 771ca4c72c0SPierre-Yves MORDRET sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); 772d8b46839SM'boumba Cedric Madianga 773c2d86b1cSPierre Yves MORDRET if (status & STM32_DMA_FEI) { 774c2d86b1cSPierre Yves MORDRET stm32_dma_irq_clear(chan, STM32_DMA_FEI); 775c2d86b1cSPierre Yves MORDRET status &= ~STM32_DMA_FEI; 776ca4c72c0SPierre-Yves MORDRET if (sfcr & STM32_DMA_SFCR_FEIE) { 777a44d9d72SAmelie Delaunay if (!(scr & STM32_DMA_SCR_EN) && 778a44d9d72SAmelie Delaunay !(status & STM32_DMA_TCI)) 779c2d86b1cSPierre Yves MORDRET dev_err(chan2dev(chan), "FIFO Error\n"); 780c2d86b1cSPierre Yves MORDRET else 781c2d86b1cSPierre Yves MORDRET dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); 782c2d86b1cSPierre Yves MORDRET } 783ca4c72c0SPierre-Yves MORDRET } 784955b1766SAmelie Delaunay if (status & STM32_DMA_DMEI) { 785955b1766SAmelie Delaunay stm32_dma_irq_clear(chan, STM32_DMA_DMEI); 786955b1766SAmelie Delaunay status &= ~STM32_DMA_DMEI; 787955b1766SAmelie Delaunay if (sfcr & STM32_DMA_SCR_DMEIE) 788955b1766SAmelie Delaunay dev_dbg(chan2dev(chan), "Direct mode overrun\n"); 789955b1766SAmelie Delaunay } 790a44d9d72SAmelie Delaunay 791a44d9d72SAmelie Delaunay if (status & STM32_DMA_TCI) { 792a44d9d72SAmelie Delaunay stm32_dma_irq_clear(chan, STM32_DMA_TCI); 793099a9a94SAmelie Delaunay if (scr & STM32_DMA_SCR_TCIE) { 794140fd5e7SAmelie Delaunay if (chan->status != DMA_PAUSED) 795ded62306SAmelie Delaunay stm32_dma_handle_chan_done(chan, scr); 796099a9a94SAmelie Delaunay } 797a44d9d72SAmelie Delaunay status &= ~STM32_DMA_TCI; 798a44d9d72SAmelie Delaunay } 799a44d9d72SAmelie Delaunay 800a44d9d72SAmelie Delaunay if (status & STM32_DMA_HTI) { 801a44d9d72SAmelie Delaunay stm32_dma_irq_clear(chan, STM32_DMA_HTI); 802a44d9d72SAmelie Delaunay status &= ~STM32_DMA_HTI; 803a44d9d72SAmelie Delaunay } 804a44d9d72SAmelie Delaunay 805c2d86b1cSPierre Yves MORDRET if (status) { 806d8b46839SM'boumba Cedric Madianga stm32_dma_irq_clear(chan, status); 807d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); 808c2d86b1cSPierre Yves MORDRET if (!(scr & STM32_DMA_SCR_EN)) 809c2d86b1cSPierre Yves MORDRET dev_err(chan2dev(chan), "chan disabled by HW\n"); 810d8b46839SM'boumba Cedric Madianga } 811d8b46839SM'boumba Cedric Madianga 812d8b46839SM'boumba Cedric Madianga spin_unlock(&chan->vchan.lock); 813d8b46839SM'boumba Cedric Madianga 814d8b46839SM'boumba Cedric Madianga return IRQ_HANDLED; 815d8b46839SM'boumba Cedric Madianga } 816d8b46839SM'boumba Cedric Madianga 817d8b46839SM'boumba Cedric Madianga static void stm32_dma_issue_pending(struct dma_chan *c) 818d8b46839SM'boumba Cedric Madianga { 819d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 820d8b46839SM'boumba Cedric Madianga unsigned long flags; 821d8b46839SM'boumba Cedric Madianga 822d8b46839SM'boumba Cedric Madianga spin_lock_irqsave(&chan->vchan.lock, flags); 8238d1b76f0SM'boumba Cedric Madianga if (vchan_issue_pending(&chan->vchan) && !chan->desc && !chan->busy) { 82490ec93cbSBenjamin Gaignard dev_dbg(chan2dev(chan), "vchan %pK: issued\n", &chan->vchan); 8258d1b76f0SM'boumba Cedric Madianga stm32_dma_start_transfer(chan); 826e57cb3b3SPierre Yves MORDRET 827d8b46839SM'boumba Cedric Madianga } 828d8b46839SM'boumba Cedric Madianga spin_unlock_irqrestore(&chan->vchan.lock, flags); 829d8b46839SM'boumba Cedric Madianga } 830d8b46839SM'boumba Cedric Madianga 831099a9a94SAmelie Delaunay static int stm32_dma_pause(struct dma_chan *c) 832099a9a94SAmelie Delaunay { 833099a9a94SAmelie Delaunay struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 834099a9a94SAmelie Delaunay unsigned long flags; 835099a9a94SAmelie Delaunay int ret; 836099a9a94SAmelie Delaunay 837099a9a94SAmelie Delaunay if (chan->status != DMA_IN_PROGRESS) 838099a9a94SAmelie Delaunay return -EPERM; 839099a9a94SAmelie Delaunay 840099a9a94SAmelie Delaunay spin_lock_irqsave(&chan->vchan.lock, flags); 841140fd5e7SAmelie Delaunay 842099a9a94SAmelie Delaunay ret = stm32_dma_disable_chan(chan); 843099a9a94SAmelie Delaunay if (!ret) 844140fd5e7SAmelie Delaunay stm32_dma_handle_chan_paused(chan); 845140fd5e7SAmelie Delaunay 846099a9a94SAmelie Delaunay spin_unlock_irqrestore(&chan->vchan.lock, flags); 847099a9a94SAmelie Delaunay 848099a9a94SAmelie Delaunay return ret; 849099a9a94SAmelie Delaunay } 850099a9a94SAmelie Delaunay 851099a9a94SAmelie Delaunay static int stm32_dma_resume(struct dma_chan *c) 852099a9a94SAmelie Delaunay { 853099a9a94SAmelie Delaunay struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 854099a9a94SAmelie Delaunay struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 855099a9a94SAmelie Delaunay struct stm32_dma_chan_reg chan_reg = chan->chan_reg; 856099a9a94SAmelie Delaunay u32 id = chan->id, scr, ndtr, offset, spar, sm0ar, sm1ar; 857099a9a94SAmelie Delaunay struct stm32_dma_sg_req *sg_req; 858099a9a94SAmelie Delaunay unsigned long flags; 859099a9a94SAmelie Delaunay 860099a9a94SAmelie Delaunay if (chan->status != DMA_PAUSED) 861099a9a94SAmelie Delaunay return -EPERM; 862099a9a94SAmelie Delaunay 863099a9a94SAmelie Delaunay scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 864099a9a94SAmelie Delaunay if (WARN_ON(scr & STM32_DMA_SCR_EN)) 865099a9a94SAmelie Delaunay return -EPERM; 866099a9a94SAmelie Delaunay 867099a9a94SAmelie Delaunay spin_lock_irqsave(&chan->vchan.lock, flags); 868099a9a94SAmelie Delaunay 869099a9a94SAmelie Delaunay /* sg_reg[prev_sg] contains original ndtr, sm0ar and sm1ar before pausing the transfer */ 870099a9a94SAmelie Delaunay if (!chan->next_sg) 871099a9a94SAmelie Delaunay sg_req = &chan->desc->sg_req[chan->desc->num_sgs - 1]; 872099a9a94SAmelie Delaunay else 873099a9a94SAmelie Delaunay sg_req = &chan->desc->sg_req[chan->next_sg - 1]; 874099a9a94SAmelie Delaunay 875099a9a94SAmelie Delaunay ndtr = sg_req->chan_reg.dma_sndtr; 8761c32d6c3SAmelie Delaunay offset = (ndtr - chan_reg.dma_sndtr); 8771c32d6c3SAmelie Delaunay offset <<= FIELD_GET(STM32_DMA_SCR_PSIZE_MASK, chan_reg.dma_scr); 878099a9a94SAmelie Delaunay spar = sg_req->chan_reg.dma_spar; 879099a9a94SAmelie Delaunay sm0ar = sg_req->chan_reg.dma_sm0ar; 880099a9a94SAmelie Delaunay sm1ar = sg_req->chan_reg.dma_sm1ar; 881099a9a94SAmelie Delaunay 882099a9a94SAmelie Delaunay /* 883099a9a94SAmelie Delaunay * The peripheral and/or memory addresses have to be updated in order to adjust the 884099a9a94SAmelie Delaunay * address pointers. Need to check increment. 885099a9a94SAmelie Delaunay */ 886099a9a94SAmelie Delaunay if (chan_reg.dma_scr & STM32_DMA_SCR_PINC) 887099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SPAR(id), spar + offset); 888099a9a94SAmelie Delaunay else 889099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SPAR(id), spar); 890099a9a94SAmelie Delaunay 891099a9a94SAmelie Delaunay if (!(chan_reg.dma_scr & STM32_DMA_SCR_MINC)) 892099a9a94SAmelie Delaunay offset = 0; 893099a9a94SAmelie Delaunay 894099a9a94SAmelie Delaunay /* 895099a9a94SAmelie Delaunay * In case of DBM, the current target could be SM1AR. 896099a9a94SAmelie Delaunay * Need to temporarily deactivate CIRC/DBM to finish the current transfer, so 897099a9a94SAmelie Delaunay * SM0AR becomes the current target and must be updated with SM1AR + offset if CT=1. 898099a9a94SAmelie Delaunay */ 899099a9a94SAmelie Delaunay if ((chan_reg.dma_scr & STM32_DMA_SCR_DBM) && (chan_reg.dma_scr & STM32_DMA_SCR_CT)) 900099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), sm1ar + offset); 901099a9a94SAmelie Delaunay else 902099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), sm0ar + offset); 903099a9a94SAmelie Delaunay 904099a9a94SAmelie Delaunay /* NDTR must be restored otherwise internal HW counter won't be correctly reset */ 905099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SNDTR(id), chan_reg.dma_sndtr); 906099a9a94SAmelie Delaunay 907099a9a94SAmelie Delaunay /* 908099a9a94SAmelie Delaunay * Need to temporarily deactivate CIRC/DBM until next Transfer Complete interrupt, 909099a9a94SAmelie Delaunay * otherwise NDTR autoreload value will be wrong (lower than the initial period length) 910099a9a94SAmelie Delaunay */ 911099a9a94SAmelie Delaunay if (chan_reg.dma_scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM)) 912099a9a94SAmelie Delaunay chan_reg.dma_scr &= ~(STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM); 913099a9a94SAmelie Delaunay 914099a9a94SAmelie Delaunay if (chan_reg.dma_scr & STM32_DMA_SCR_DBM) 915099a9a94SAmelie Delaunay stm32_dma_configure_next_sg(chan); 916099a9a94SAmelie Delaunay 917099a9a94SAmelie Delaunay stm32_dma_dump_reg(chan); 918099a9a94SAmelie Delaunay 919099a9a94SAmelie Delaunay /* The stream may then be re-enabled to restart transfer from the point it was stopped */ 920099a9a94SAmelie Delaunay chan->status = DMA_IN_PROGRESS; 921099a9a94SAmelie Delaunay chan_reg.dma_scr |= STM32_DMA_SCR_EN; 922099a9a94SAmelie Delaunay stm32_dma_write(dmadev, STM32_DMA_SCR(id), chan_reg.dma_scr); 923099a9a94SAmelie Delaunay 924099a9a94SAmelie Delaunay spin_unlock_irqrestore(&chan->vchan.lock, flags); 925099a9a94SAmelie Delaunay 926099a9a94SAmelie Delaunay dev_dbg(chan2dev(chan), "vchan %pK: resumed\n", &chan->vchan); 927099a9a94SAmelie Delaunay 928099a9a94SAmelie Delaunay return 0; 929099a9a94SAmelie Delaunay } 930099a9a94SAmelie Delaunay 931d8b46839SM'boumba Cedric Madianga static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, 932d8b46839SM'boumba Cedric Madianga enum dma_transfer_direction direction, 933a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth *buswidth, 934e0ebdbdcSAmelie Delaunay u32 buf_len, dma_addr_t buf_addr) 935d8b46839SM'boumba Cedric Madianga { 936d8b46839SM'boumba Cedric Madianga enum dma_slave_buswidth src_addr_width, dst_addr_width; 937d8b46839SM'boumba Cedric Madianga int src_bus_width, dst_bus_width; 938d8b46839SM'boumba Cedric Madianga int src_burst_size, dst_burst_size; 939a2b6103bSPierre Yves MORDRET u32 src_maxburst, dst_maxburst, src_best_burst, dst_best_burst; 940955b1766SAmelie Delaunay u32 dma_scr, fifoth; 941d8b46839SM'boumba Cedric Madianga 942d8b46839SM'boumba Cedric Madianga src_addr_width = chan->dma_sconfig.src_addr_width; 943d8b46839SM'boumba Cedric Madianga dst_addr_width = chan->dma_sconfig.dst_addr_width; 944d8b46839SM'boumba Cedric Madianga src_maxburst = chan->dma_sconfig.src_maxburst; 945d8b46839SM'boumba Cedric Madianga dst_maxburst = chan->dma_sconfig.dst_maxburst; 946955b1766SAmelie Delaunay fifoth = chan->threshold; 947d8b46839SM'boumba Cedric Madianga 948d8b46839SM'boumba Cedric Madianga switch (direction) { 949d8b46839SM'boumba Cedric Madianga case DMA_MEM_TO_DEV: 950a2b6103bSPierre Yves MORDRET /* Set device data size */ 951d8b46839SM'boumba Cedric Madianga dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); 952d8b46839SM'boumba Cedric Madianga if (dst_bus_width < 0) 953d8b46839SM'boumba Cedric Madianga return dst_bus_width; 954d8b46839SM'boumba Cedric Madianga 955a2b6103bSPierre Yves MORDRET /* Set device burst size */ 956a2b6103bSPierre Yves MORDRET dst_best_burst = stm32_dma_get_best_burst(buf_len, 957a2b6103bSPierre Yves MORDRET dst_maxburst, 958955b1766SAmelie Delaunay fifoth, 959a2b6103bSPierre Yves MORDRET dst_addr_width); 960a2b6103bSPierre Yves MORDRET 961a2b6103bSPierre Yves MORDRET dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); 962d8b46839SM'boumba Cedric Madianga if (dst_burst_size < 0) 963d8b46839SM'boumba Cedric Madianga return dst_burst_size; 964d8b46839SM'boumba Cedric Madianga 965a2b6103bSPierre Yves MORDRET /* Set memory data size */ 966e0ebdbdcSAmelie Delaunay src_addr_width = stm32_dma_get_max_width(buf_len, buf_addr, 967e0ebdbdcSAmelie Delaunay fifoth); 968a2b6103bSPierre Yves MORDRET chan->mem_width = src_addr_width; 969d8b46839SM'boumba Cedric Madianga src_bus_width = stm32_dma_get_width(chan, src_addr_width); 970d8b46839SM'boumba Cedric Madianga if (src_bus_width < 0) 971d8b46839SM'boumba Cedric Madianga return src_bus_width; 972d8b46839SM'boumba Cedric Madianga 973af229d2cSAmelie Delaunay /* 974af229d2cSAmelie Delaunay * Set memory burst size - burst not possible if address is not aligned on 975af229d2cSAmelie Delaunay * the address boundary equal to the size of the transfer 976af229d2cSAmelie Delaunay */ 97724983633SArnd Bergmann if (buf_addr & (buf_len - 1)) 978af229d2cSAmelie Delaunay src_maxburst = 1; 979af229d2cSAmelie Delaunay else 980a2b6103bSPierre Yves MORDRET src_maxburst = STM32_DMA_MAX_BURST; 981a2b6103bSPierre Yves MORDRET src_best_burst = stm32_dma_get_best_burst(buf_len, 982a2b6103bSPierre Yves MORDRET src_maxburst, 983955b1766SAmelie Delaunay fifoth, 984a2b6103bSPierre Yves MORDRET src_addr_width); 985a2b6103bSPierre Yves MORDRET src_burst_size = stm32_dma_get_burst(chan, src_best_burst); 986d8b46839SM'boumba Cedric Madianga if (src_burst_size < 0) 987d8b46839SM'boumba Cedric Madianga return src_burst_size; 988d8b46839SM'boumba Cedric Madianga 9891c32d6c3SAmelie Delaunay dma_scr = FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_MEM_TO_DEV) | 9901c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_PSIZE_MASK, dst_bus_width) | 9911c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_MSIZE_MASK, src_bus_width) | 9921c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, dst_burst_size) | 9931c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, src_burst_size); 994d8b46839SM'boumba Cedric Madianga 995a2b6103bSPierre Yves MORDRET /* Set FIFO threshold */ 996a2b6103bSPierre Yves MORDRET chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; 997955b1766SAmelie Delaunay if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE) 9981c32d6c3SAmelie Delaunay chan->chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, fifoth); 999a2b6103bSPierre Yves MORDRET 1000a2b6103bSPierre Yves MORDRET /* Set peripheral address */ 1001d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr; 1002d8b46839SM'boumba Cedric Madianga *buswidth = dst_addr_width; 1003d8b46839SM'boumba Cedric Madianga break; 1004d8b46839SM'boumba Cedric Madianga 1005d8b46839SM'boumba Cedric Madianga case DMA_DEV_TO_MEM: 1006a2b6103bSPierre Yves MORDRET /* Set device data size */ 1007d8b46839SM'boumba Cedric Madianga src_bus_width = stm32_dma_get_width(chan, src_addr_width); 1008d8b46839SM'boumba Cedric Madianga if (src_bus_width < 0) 1009d8b46839SM'boumba Cedric Madianga return src_bus_width; 1010d8b46839SM'boumba Cedric Madianga 1011a2b6103bSPierre Yves MORDRET /* Set device burst size */ 1012a2b6103bSPierre Yves MORDRET src_best_burst = stm32_dma_get_best_burst(buf_len, 1013a2b6103bSPierre Yves MORDRET src_maxburst, 1014955b1766SAmelie Delaunay fifoth, 1015a2b6103bSPierre Yves MORDRET src_addr_width); 1016a2b6103bSPierre Yves MORDRET chan->mem_burst = src_best_burst; 1017a2b6103bSPierre Yves MORDRET src_burst_size = stm32_dma_get_burst(chan, src_best_burst); 1018d8b46839SM'boumba Cedric Madianga if (src_burst_size < 0) 1019d8b46839SM'boumba Cedric Madianga return src_burst_size; 1020d8b46839SM'boumba Cedric Madianga 1021a2b6103bSPierre Yves MORDRET /* Set memory data size */ 1022e0ebdbdcSAmelie Delaunay dst_addr_width = stm32_dma_get_max_width(buf_len, buf_addr, 1023e0ebdbdcSAmelie Delaunay fifoth); 1024a2b6103bSPierre Yves MORDRET chan->mem_width = dst_addr_width; 1025d8b46839SM'boumba Cedric Madianga dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); 1026d8b46839SM'boumba Cedric Madianga if (dst_bus_width < 0) 1027d8b46839SM'boumba Cedric Madianga return dst_bus_width; 1028d8b46839SM'boumba Cedric Madianga 1029af229d2cSAmelie Delaunay /* 1030af229d2cSAmelie Delaunay * Set memory burst size - burst not possible if address is not aligned on 1031af229d2cSAmelie Delaunay * the address boundary equal to the size of the transfer 1032af229d2cSAmelie Delaunay */ 103324983633SArnd Bergmann if (buf_addr & (buf_len - 1)) 1034af229d2cSAmelie Delaunay dst_maxburst = 1; 1035af229d2cSAmelie Delaunay else 1036a2b6103bSPierre Yves MORDRET dst_maxburst = STM32_DMA_MAX_BURST; 1037a2b6103bSPierre Yves MORDRET dst_best_burst = stm32_dma_get_best_burst(buf_len, 1038a2b6103bSPierre Yves MORDRET dst_maxburst, 1039955b1766SAmelie Delaunay fifoth, 1040a2b6103bSPierre Yves MORDRET dst_addr_width); 1041a2b6103bSPierre Yves MORDRET chan->mem_burst = dst_best_burst; 1042a2b6103bSPierre Yves MORDRET dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); 1043d8b46839SM'boumba Cedric Madianga if (dst_burst_size < 0) 1044d8b46839SM'boumba Cedric Madianga return dst_burst_size; 1045d8b46839SM'boumba Cedric Madianga 10461c32d6c3SAmelie Delaunay dma_scr = FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_DEV_TO_MEM) | 10471c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_PSIZE_MASK, src_bus_width) | 10481c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_MSIZE_MASK, dst_bus_width) | 10491c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, src_burst_size) | 10501c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, dst_burst_size); 1051d8b46839SM'boumba Cedric Madianga 1052a2b6103bSPierre Yves MORDRET /* Set FIFO threshold */ 1053a2b6103bSPierre Yves MORDRET chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; 1054955b1766SAmelie Delaunay if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE) 10551c32d6c3SAmelie Delaunay chan->chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, fifoth); 1056a2b6103bSPierre Yves MORDRET 1057a2b6103bSPierre Yves MORDRET /* Set peripheral address */ 1058d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr; 1059d8b46839SM'boumba Cedric Madianga *buswidth = chan->dma_sconfig.src_addr_width; 1060d8b46839SM'boumba Cedric Madianga break; 1061d8b46839SM'boumba Cedric Madianga 1062d8b46839SM'boumba Cedric Madianga default: 1063d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Dma direction is not supported\n"); 1064d8b46839SM'boumba Cedric Madianga return -EINVAL; 1065d8b46839SM'boumba Cedric Madianga } 1066d8b46839SM'boumba Cedric Madianga 1067a2b6103bSPierre Yves MORDRET stm32_dma_set_fifo_config(chan, src_best_burst, dst_best_burst); 1068d8b46839SM'boumba Cedric Madianga 1069a2b6103bSPierre Yves MORDRET /* Set DMA control register */ 1070d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr &= ~(STM32_DMA_SCR_DIR_MASK | 1071d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PSIZE_MASK | STM32_DMA_SCR_MSIZE_MASK | 1072d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PBURST_MASK | STM32_DMA_SCR_MBURST_MASK); 1073d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= dma_scr; 1074d8b46839SM'boumba Cedric Madianga 1075d8b46839SM'boumba Cedric Madianga return 0; 1076d8b46839SM'boumba Cedric Madianga } 1077d8b46839SM'boumba Cedric Madianga 1078d8b46839SM'boumba Cedric Madianga static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) 1079d8b46839SM'boumba Cedric Madianga { 1080d8b46839SM'boumba Cedric Madianga memset(regs, 0, sizeof(struct stm32_dma_chan_reg)); 1081d8b46839SM'boumba Cedric Madianga } 1082d8b46839SM'boumba Cedric Madianga 1083d8b46839SM'boumba Cedric Madianga static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( 1084d8b46839SM'boumba Cedric Madianga struct dma_chan *c, struct scatterlist *sgl, 1085d8b46839SM'boumba Cedric Madianga u32 sg_len, enum dma_transfer_direction direction, 1086d8b46839SM'boumba Cedric Madianga unsigned long flags, void *context) 1087d8b46839SM'boumba Cedric Madianga { 1088d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1089d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc; 1090d8b46839SM'boumba Cedric Madianga struct scatterlist *sg; 1091d8b46839SM'boumba Cedric Madianga enum dma_slave_buswidth buswidth; 1092d8b46839SM'boumba Cedric Madianga u32 nb_data_items; 1093d8b46839SM'boumba Cedric Madianga int i, ret; 1094d8b46839SM'boumba Cedric Madianga 1095d8b46839SM'boumba Cedric Madianga if (!chan->config_init) { 1096d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "dma channel is not configured\n"); 1097d8b46839SM'boumba Cedric Madianga return NULL; 1098d8b46839SM'boumba Cedric Madianga } 1099d8b46839SM'boumba Cedric Madianga 1100d8b46839SM'boumba Cedric Madianga if (sg_len < 1) { 1101d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Invalid segment length %d\n", sg_len); 1102d8b46839SM'boumba Cedric Madianga return NULL; 1103d8b46839SM'boumba Cedric Madianga } 1104d8b46839SM'boumba Cedric Madianga 1105402096cbSGustavo A. R. Silva desc = kzalloc(struct_size(desc, sg_req, sg_len), GFP_NOWAIT); 1106d8b46839SM'boumba Cedric Madianga if (!desc) 1107d8b46839SM'boumba Cedric Madianga return NULL; 1108d8b46839SM'boumba Cedric Madianga 1109d8b46839SM'boumba Cedric Madianga /* Set peripheral flow controller */ 1110d8b46839SM'boumba Cedric Madianga if (chan->dma_sconfig.device_fc) 1111d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_PFCTRL; 1112d8b46839SM'boumba Cedric Madianga else 1113d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; 1114d8b46839SM'boumba Cedric Madianga 111572379517SAmelie Delaunay /* Activate Double Buffer Mode if DMA triggers STM32 MDMA and more than 1 sg */ 111672379517SAmelie Delaunay if (chan->trig_mdma && sg_len > 1) 111772379517SAmelie Delaunay chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM; 111872379517SAmelie Delaunay 1119d8b46839SM'boumba Cedric Madianga for_each_sg(sgl, sg, sg_len, i) { 1120a2b6103bSPierre Yves MORDRET ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, 1121e0ebdbdcSAmelie Delaunay sg_dma_len(sg), 1122e0ebdbdcSAmelie Delaunay sg_dma_address(sg)); 1123a2b6103bSPierre Yves MORDRET if (ret < 0) 1124a2b6103bSPierre Yves MORDRET goto err; 1125a2b6103bSPierre Yves MORDRET 1126d8b46839SM'boumba Cedric Madianga desc->sg_req[i].len = sg_dma_len(sg); 1127d8b46839SM'boumba Cedric Madianga 1128d8b46839SM'boumba Cedric Madianga nb_data_items = desc->sg_req[i].len / buswidth; 112980a76952SPierre Yves MORDRET if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) { 1130d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "nb items not supported\n"); 1131d8b46839SM'boumba Cedric Madianga goto err; 1132d8b46839SM'boumba Cedric Madianga } 1133d8b46839SM'boumba Cedric Madianga 1134d8b46839SM'boumba Cedric Madianga stm32_dma_clear_reg(&desc->sg_req[i].chan_reg); 1135d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_scr = chan->chan_reg.dma_scr; 1136d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sfcr = chan->chan_reg.dma_sfcr; 1137d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar; 1138d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm0ar = sg_dma_address(sg); 1139d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm1ar = sg_dma_address(sg); 114072379517SAmelie Delaunay if (chan->trig_mdma) 114172379517SAmelie Delaunay desc->sg_req[i].chan_reg.dma_sm1ar += sg_dma_len(sg); 1142d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items; 1143d8b46839SM'boumba Cedric Madianga } 1144d8b46839SM'boumba Cedric Madianga 1145d8b46839SM'boumba Cedric Madianga desc->num_sgs = sg_len; 1146d8b46839SM'boumba Cedric Madianga desc->cyclic = false; 1147d8b46839SM'boumba Cedric Madianga 1148d8b46839SM'boumba Cedric Madianga return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); 1149d8b46839SM'boumba Cedric Madianga 1150d8b46839SM'boumba Cedric Madianga err: 1151d8b46839SM'boumba Cedric Madianga kfree(desc); 1152d8b46839SM'boumba Cedric Madianga return NULL; 1153d8b46839SM'boumba Cedric Madianga } 1154d8b46839SM'boumba Cedric Madianga 1155d8b46839SM'boumba Cedric Madianga static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( 1156d8b46839SM'boumba Cedric Madianga struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, 1157d8b46839SM'boumba Cedric Madianga size_t period_len, enum dma_transfer_direction direction, 1158d8b46839SM'boumba Cedric Madianga unsigned long flags) 1159d8b46839SM'boumba Cedric Madianga { 1160d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1161d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc; 1162d8b46839SM'boumba Cedric Madianga enum dma_slave_buswidth buswidth; 1163d8b46839SM'boumba Cedric Madianga u32 num_periods, nb_data_items; 1164d8b46839SM'boumba Cedric Madianga int i, ret; 1165d8b46839SM'boumba Cedric Madianga 1166d8b46839SM'boumba Cedric Madianga if (!buf_len || !period_len) { 1167d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Invalid buffer/period len\n"); 1168d8b46839SM'boumba Cedric Madianga return NULL; 1169d8b46839SM'boumba Cedric Madianga } 1170d8b46839SM'boumba Cedric Madianga 1171d8b46839SM'boumba Cedric Madianga if (!chan->config_init) { 1172d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "dma channel is not configured\n"); 1173d8b46839SM'boumba Cedric Madianga return NULL; 1174d8b46839SM'boumba Cedric Madianga } 1175d8b46839SM'boumba Cedric Madianga 1176d8b46839SM'boumba Cedric Madianga if (buf_len % period_len) { 1177d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "buf_len not multiple of period_len\n"); 1178d8b46839SM'boumba Cedric Madianga return NULL; 1179d8b46839SM'boumba Cedric Madianga } 1180d8b46839SM'boumba Cedric Madianga 1181d8b46839SM'boumba Cedric Madianga /* 1182d8b46839SM'boumba Cedric Madianga * We allow to take more number of requests till DMA is 1183d8b46839SM'boumba Cedric Madianga * not started. The driver will loop over all requests. 1184d8b46839SM'boumba Cedric Madianga * Once DMA is started then new requests can be queued only after 1185d8b46839SM'boumba Cedric Madianga * terminating the DMA. 1186d8b46839SM'boumba Cedric Madianga */ 1187d8b46839SM'boumba Cedric Madianga if (chan->busy) { 1188d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "Request not allowed when dma busy\n"); 1189d8b46839SM'boumba Cedric Madianga return NULL; 1190d8b46839SM'boumba Cedric Madianga } 1191d8b46839SM'boumba Cedric Madianga 1192e0ebdbdcSAmelie Delaunay ret = stm32_dma_set_xfer_param(chan, direction, &buswidth, period_len, 1193e0ebdbdcSAmelie Delaunay buf_addr); 1194d8b46839SM'boumba Cedric Madianga if (ret < 0) 1195d8b46839SM'boumba Cedric Madianga return NULL; 1196d8b46839SM'boumba Cedric Madianga 1197d8b46839SM'boumba Cedric Madianga nb_data_items = period_len / buswidth; 119880a76952SPierre Yves MORDRET if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) { 1199d8b46839SM'boumba Cedric Madianga dev_err(chan2dev(chan), "number of items not supported\n"); 1200d8b46839SM'boumba Cedric Madianga return NULL; 1201d8b46839SM'boumba Cedric Madianga } 1202d8b46839SM'boumba Cedric Madianga 1203d8b46839SM'boumba Cedric Madianga /* Enable Circular mode or double buffer mode */ 1204099a9a94SAmelie Delaunay if (buf_len == period_len) { 1205d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_CIRC; 1206099a9a94SAmelie Delaunay } else { 1207d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM; 1208099a9a94SAmelie Delaunay chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_CT; 1209099a9a94SAmelie Delaunay } 1210d8b46839SM'boumba Cedric Madianga 1211d8b46839SM'boumba Cedric Madianga /* Clear periph ctrl if client set it */ 1212d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; 1213d8b46839SM'boumba Cedric Madianga 1214d8b46839SM'boumba Cedric Madianga num_periods = buf_len / period_len; 1215d8b46839SM'boumba Cedric Madianga 1216402096cbSGustavo A. R. Silva desc = kzalloc(struct_size(desc, sg_req, num_periods), GFP_NOWAIT); 1217d8b46839SM'boumba Cedric Madianga if (!desc) 1218d8b46839SM'boumba Cedric Madianga return NULL; 1219d8b46839SM'boumba Cedric Madianga 1220d8b46839SM'boumba Cedric Madianga for (i = 0; i < num_periods; i++) { 1221d8b46839SM'boumba Cedric Madianga desc->sg_req[i].len = period_len; 1222d8b46839SM'boumba Cedric Madianga 1223d8b46839SM'boumba Cedric Madianga stm32_dma_clear_reg(&desc->sg_req[i].chan_reg); 1224d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_scr = chan->chan_reg.dma_scr; 1225d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sfcr = chan->chan_reg.dma_sfcr; 1226d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_spar = chan->chan_reg.dma_spar; 1227d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm0ar = buf_addr; 1228d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm1ar = buf_addr; 122972379517SAmelie Delaunay if (chan->trig_mdma) 123072379517SAmelie Delaunay desc->sg_req[i].chan_reg.dma_sm1ar += period_len; 1231d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sndtr = nb_data_items; 123272379517SAmelie Delaunay if (!chan->trig_mdma) 1233d8b46839SM'boumba Cedric Madianga buf_addr += period_len; 1234d8b46839SM'boumba Cedric Madianga } 1235d8b46839SM'boumba Cedric Madianga 1236d8b46839SM'boumba Cedric Madianga desc->num_sgs = num_periods; 1237d8b46839SM'boumba Cedric Madianga desc->cyclic = true; 1238d8b46839SM'boumba Cedric Madianga 1239d8b46839SM'boumba Cedric Madianga return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); 1240d8b46839SM'boumba Cedric Madianga } 1241d8b46839SM'boumba Cedric Madianga 1242d8b46839SM'boumba Cedric Madianga static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( 1243d8b46839SM'boumba Cedric Madianga struct dma_chan *c, dma_addr_t dest, 1244d8b46839SM'boumba Cedric Madianga dma_addr_t src, size_t len, unsigned long flags) 1245d8b46839SM'boumba Cedric Madianga { 1246d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1247a2b6103bSPierre Yves MORDRET enum dma_slave_buswidth max_width; 1248d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc; 1249d8b46839SM'boumba Cedric Madianga size_t xfer_count, offset; 1250a2b6103bSPierre Yves MORDRET u32 num_sgs, best_burst, dma_burst, threshold; 1251d8b46839SM'boumba Cedric Madianga int i; 1252d8b46839SM'boumba Cedric Madianga 125380a76952SPierre Yves MORDRET num_sgs = DIV_ROUND_UP(len, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); 1254402096cbSGustavo A. R. Silva desc = kzalloc(struct_size(desc, sg_req, num_sgs), GFP_NOWAIT); 1255d8b46839SM'boumba Cedric Madianga if (!desc) 1256d8b46839SM'boumba Cedric Madianga return NULL; 1257d8b46839SM'boumba Cedric Madianga 1258a2b6103bSPierre Yves MORDRET threshold = chan->threshold; 1259a2b6103bSPierre Yves MORDRET 1260d8b46839SM'boumba Cedric Madianga for (offset = 0, i = 0; offset < len; offset += xfer_count, i++) { 1261d8b46839SM'boumba Cedric Madianga xfer_count = min_t(size_t, len - offset, 126280a76952SPierre Yves MORDRET STM32_DMA_ALIGNED_MAX_DATA_ITEMS); 1263d8b46839SM'boumba Cedric Madianga 1264a2b6103bSPierre Yves MORDRET /* Compute best burst size */ 1265a2b6103bSPierre Yves MORDRET max_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 1266a2b6103bSPierre Yves MORDRET best_burst = stm32_dma_get_best_burst(len, STM32_DMA_MAX_BURST, 1267a2b6103bSPierre Yves MORDRET threshold, max_width); 1268a2b6103bSPierre Yves MORDRET dma_burst = stm32_dma_get_burst(chan, best_burst); 1269d8b46839SM'boumba Cedric Madianga 1270d8b46839SM'boumba Cedric Madianga stm32_dma_clear_reg(&desc->sg_req[i].chan_reg); 1271d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_scr = 12721c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_DIR_MASK, STM32_DMA_MEM_TO_MEM) | 12731c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_PBURST_MASK, dma_burst) | 12741c32d6c3SAmelie Delaunay FIELD_PREP(STM32_DMA_SCR_MBURST_MASK, dma_burst) | 1275d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_MINC | 1276d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_PINC | 1277d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_TCIE | 1278d8b46839SM'boumba Cedric Madianga STM32_DMA_SCR_TEIE; 1279a2b6103bSPierre Yves MORDRET desc->sg_req[i].chan_reg.dma_sfcr |= STM32_DMA_SFCR_MASK; 12801c32d6c3SAmelie Delaunay desc->sg_req[i].chan_reg.dma_sfcr |= FIELD_PREP(STM32_DMA_SFCR_FTH_MASK, threshold); 1281d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_spar = src + offset; 1282d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sm0ar = dest + offset; 1283d8b46839SM'boumba Cedric Madianga desc->sg_req[i].chan_reg.dma_sndtr = xfer_count; 1284a2b6103bSPierre Yves MORDRET desc->sg_req[i].len = xfer_count; 1285d8b46839SM'boumba Cedric Madianga } 1286d8b46839SM'boumba Cedric Madianga 1287d8b46839SM'boumba Cedric Madianga desc->num_sgs = num_sgs; 1288d8b46839SM'boumba Cedric Madianga desc->cyclic = false; 1289d8b46839SM'boumba Cedric Madianga 1290d8b46839SM'boumba Cedric Madianga return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); 1291d8b46839SM'boumba Cedric Madianga } 1292d8b46839SM'boumba Cedric Madianga 12932b12c558SM'boumba Cedric Madianga static u32 stm32_dma_get_remaining_bytes(struct stm32_dma_chan *chan) 12942b12c558SM'boumba Cedric Madianga { 12952b12c558SM'boumba Cedric Madianga u32 dma_scr, width, ndtr; 12962b12c558SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 12972b12c558SM'boumba Cedric Madianga 12982b12c558SM'boumba Cedric Madianga dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); 12991c32d6c3SAmelie Delaunay width = FIELD_GET(STM32_DMA_SCR_PSIZE_MASK, dma_scr); 13002b12c558SM'boumba Cedric Madianga ndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); 13012b12c558SM'boumba Cedric Madianga 13022b12c558SM'boumba Cedric Madianga return ndtr << width; 13032b12c558SM'boumba Cedric Madianga } 13042b12c558SM'boumba Cedric Madianga 13052a4885abSArnaud Pouliquen /** 13062a4885abSArnaud Pouliquen * stm32_dma_is_current_sg - check that expected sg_req is currently transferred 13072a4885abSArnaud Pouliquen * @chan: dma channel 13082a4885abSArnaud Pouliquen * 13092a4885abSArnaud Pouliquen * This function called when IRQ are disable, checks that the hardware has not 13102a4885abSArnaud Pouliquen * switched on the next transfer in double buffer mode. The test is done by 13112a4885abSArnaud Pouliquen * comparing the next_sg memory address with the hardware related register 13122a4885abSArnaud Pouliquen * (based on CT bit value). 13132a4885abSArnaud Pouliquen * 13142a4885abSArnaud Pouliquen * Returns true if expected current transfer is still running or double 13152a4885abSArnaud Pouliquen * buffer mode is not activated. 13162a4885abSArnaud Pouliquen */ 13172a4885abSArnaud Pouliquen static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan) 13182a4885abSArnaud Pouliquen { 13192a4885abSArnaud Pouliquen struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 13202a4885abSArnaud Pouliquen struct stm32_dma_sg_req *sg_req; 1321099a9a94SAmelie Delaunay u32 dma_scr, dma_smar, id, period_len; 13222a4885abSArnaud Pouliquen 13232a4885abSArnaud Pouliquen id = chan->id; 13242a4885abSArnaud Pouliquen dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 13252a4885abSArnaud Pouliquen 1326099a9a94SAmelie Delaunay /* In cyclic CIRC but not DBM, CT is not used */ 13272a4885abSArnaud Pouliquen if (!(dma_scr & STM32_DMA_SCR_DBM)) 13282a4885abSArnaud Pouliquen return true; 13292a4885abSArnaud Pouliquen 13302a4885abSArnaud Pouliquen sg_req = &chan->desc->sg_req[chan->next_sg]; 1331099a9a94SAmelie Delaunay period_len = sg_req->len; 13322a4885abSArnaud Pouliquen 1333099a9a94SAmelie Delaunay /* DBM - take care of a previous pause/resume not yet post reconfigured */ 13342a4885abSArnaud Pouliquen if (dma_scr & STM32_DMA_SCR_CT) { 13352a4885abSArnaud Pouliquen dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM0AR(id)); 1336099a9a94SAmelie Delaunay /* 1337099a9a94SAmelie Delaunay * If transfer has been pause/resumed, 1338099a9a94SAmelie Delaunay * SM0AR is in the range of [SM0AR:SM0AR+period_len] 1339099a9a94SAmelie Delaunay */ 1340099a9a94SAmelie Delaunay return (dma_smar >= sg_req->chan_reg.dma_sm0ar && 1341099a9a94SAmelie Delaunay dma_smar < sg_req->chan_reg.dma_sm0ar + period_len); 13422a4885abSArnaud Pouliquen } 13432a4885abSArnaud Pouliquen 13442a4885abSArnaud Pouliquen dma_smar = stm32_dma_read(dmadev, STM32_DMA_SM1AR(id)); 1345099a9a94SAmelie Delaunay /* 1346099a9a94SAmelie Delaunay * If transfer has been pause/resumed, 1347099a9a94SAmelie Delaunay * SM1AR is in the range of [SM1AR:SM1AR+period_len] 1348099a9a94SAmelie Delaunay */ 1349099a9a94SAmelie Delaunay return (dma_smar >= sg_req->chan_reg.dma_sm1ar && 1350099a9a94SAmelie Delaunay dma_smar < sg_req->chan_reg.dma_sm1ar + period_len); 13512a4885abSArnaud Pouliquen } 13522a4885abSArnaud Pouliquen 1353d8b46839SM'boumba Cedric Madianga static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, 1354d8b46839SM'boumba Cedric Madianga struct stm32_dma_desc *desc, 1355d8b46839SM'boumba Cedric Madianga u32 next_sg) 1356d8b46839SM'boumba Cedric Madianga { 1357a2b6103bSPierre Yves MORDRET u32 modulo, burst_size; 13582a4885abSArnaud Pouliquen u32 residue; 13592a4885abSArnaud Pouliquen u32 n_sg = next_sg; 13602a4885abSArnaud Pouliquen struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg]; 1361d8b46839SM'boumba Cedric Madianga int i; 1362d8b46839SM'boumba Cedric Madianga 13632b12c558SM'boumba Cedric Madianga /* 13642a4885abSArnaud Pouliquen * Calculate the residue means compute the descriptors 13652a4885abSArnaud Pouliquen * information: 13662a4885abSArnaud Pouliquen * - the sg_req currently transferred 13672a4885abSArnaud Pouliquen * - the Hardware remaining position in this sg (NDTR bits field). 13682a4885abSArnaud Pouliquen * 13692a4885abSArnaud Pouliquen * A race condition may occur if DMA is running in cyclic or double 13702a4885abSArnaud Pouliquen * buffer mode, since the DMA register are automatically reloaded at end 13712a4885abSArnaud Pouliquen * of period transfer. The hardware may have switched to the next 13722a4885abSArnaud Pouliquen * transfer (CT bit updated) just before the position (SxNDTR reg) is 13732a4885abSArnaud Pouliquen * read. 13742a4885abSArnaud Pouliquen * In this case the SxNDTR reg could (or not) correspond to the new 13752a4885abSArnaud Pouliquen * transfer position, and not the expected one. 13762a4885abSArnaud Pouliquen * The strategy implemented in the stm32 driver is to: 13772a4885abSArnaud Pouliquen * - read the SxNDTR register 13782a4885abSArnaud Pouliquen * - crosscheck that hardware is still in current transfer. 13792a4885abSArnaud Pouliquen * In case of switch, we can assume that the DMA is at the beginning of 13802a4885abSArnaud Pouliquen * the next transfer. So we approximate the residue in consequence, by 13812a4885abSArnaud Pouliquen * pointing on the beginning of next transfer. 13822a4885abSArnaud Pouliquen * 13832a4885abSArnaud Pouliquen * This race condition doesn't apply for none cyclic mode, as double 13842a4885abSArnaud Pouliquen * buffer is not used. In such situation registers are updated by the 13852a4885abSArnaud Pouliquen * software. 13862b12c558SM'boumba Cedric Madianga */ 13872a4885abSArnaud Pouliquen 1388a2b6103bSPierre Yves MORDRET residue = stm32_dma_get_remaining_bytes(chan); 13892a4885abSArnaud Pouliquen 1390099a9a94SAmelie Delaunay if (chan->desc->cyclic && !stm32_dma_is_current_sg(chan)) { 13912a4885abSArnaud Pouliquen n_sg++; 13922a4885abSArnaud Pouliquen if (n_sg == chan->desc->num_sgs) 13932a4885abSArnaud Pouliquen n_sg = 0; 13942a4885abSArnaud Pouliquen residue = sg_req->len; 1395a2b6103bSPierre Yves MORDRET } 1396d8b46839SM'boumba Cedric Madianga 13972b12c558SM'boumba Cedric Madianga /* 13982a4885abSArnaud Pouliquen * In cyclic mode, for the last period, residue = remaining bytes 13992a4885abSArnaud Pouliquen * from NDTR, 14002a4885abSArnaud Pouliquen * else for all other periods in cyclic mode, and in sg mode, 14012a4885abSArnaud Pouliquen * residue = remaining bytes from NDTR + remaining 14022a4885abSArnaud Pouliquen * periods/sg to be transferred 14032b12c558SM'boumba Cedric Madianga */ 14042a4885abSArnaud Pouliquen if (!chan->desc->cyclic || n_sg != 0) 14052a4885abSArnaud Pouliquen for (i = n_sg; i < desc->num_sgs; i++) 1406d8b46839SM'boumba Cedric Madianga residue += desc->sg_req[i].len; 1407d8b46839SM'boumba Cedric Madianga 1408a2b6103bSPierre Yves MORDRET if (!chan->mem_burst) 1409a2b6103bSPierre Yves MORDRET return residue; 1410a2b6103bSPierre Yves MORDRET 1411a2b6103bSPierre Yves MORDRET burst_size = chan->mem_burst * chan->mem_width; 1412a2b6103bSPierre Yves MORDRET modulo = residue % burst_size; 1413a2b6103bSPierre Yves MORDRET if (modulo) 1414a2b6103bSPierre Yves MORDRET residue = residue - modulo + burst_size; 1415a2b6103bSPierre Yves MORDRET 1416d8b46839SM'boumba Cedric Madianga return residue; 1417d8b46839SM'boumba Cedric Madianga } 1418d8b46839SM'boumba Cedric Madianga 1419d8b46839SM'boumba Cedric Madianga static enum dma_status stm32_dma_tx_status(struct dma_chan *c, 1420d8b46839SM'boumba Cedric Madianga dma_cookie_t cookie, 1421d8b46839SM'boumba Cedric Madianga struct dma_tx_state *state) 1422d8b46839SM'boumba Cedric Madianga { 1423d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1424d8b46839SM'boumba Cedric Madianga struct virt_dma_desc *vdesc; 1425d8b46839SM'boumba Cedric Madianga enum dma_status status; 1426d8b46839SM'boumba Cedric Madianga unsigned long flags; 142757b5a321SM'boumba Cedric Madianga u32 residue = 0; 1428d8b46839SM'boumba Cedric Madianga 1429d8b46839SM'boumba Cedric Madianga status = dma_cookie_status(c, cookie, state); 1430099a9a94SAmelie Delaunay if (status == DMA_COMPLETE) 1431099a9a94SAmelie Delaunay return status; 1432099a9a94SAmelie Delaunay 1433099a9a94SAmelie Delaunay status = chan->status; 1434099a9a94SAmelie Delaunay 1435099a9a94SAmelie Delaunay if (!state) 1436d8b46839SM'boumba Cedric Madianga return status; 1437d8b46839SM'boumba Cedric Madianga 1438d8b46839SM'boumba Cedric Madianga spin_lock_irqsave(&chan->vchan.lock, flags); 1439d8b46839SM'boumba Cedric Madianga vdesc = vchan_find_desc(&chan->vchan, cookie); 144057b5a321SM'boumba Cedric Madianga if (chan->desc && cookie == chan->desc->vdesc.tx.cookie) 1441d8b46839SM'boumba Cedric Madianga residue = stm32_dma_desc_residue(chan, chan->desc, 1442d8b46839SM'boumba Cedric Madianga chan->next_sg); 144357b5a321SM'boumba Cedric Madianga else if (vdesc) 1444d8b46839SM'boumba Cedric Madianga residue = stm32_dma_desc_residue(chan, 1445d8b46839SM'boumba Cedric Madianga to_stm32_dma_desc(vdesc), 0); 1446d8b46839SM'boumba Cedric Madianga dma_set_residue(state, residue); 1447d8b46839SM'boumba Cedric Madianga 1448d8b46839SM'boumba Cedric Madianga spin_unlock_irqrestore(&chan->vchan.lock, flags); 1449d8b46839SM'boumba Cedric Madianga 1450d8b46839SM'boumba Cedric Madianga return status; 1451d8b46839SM'boumba Cedric Madianga } 1452d8b46839SM'boumba Cedric Madianga 1453d8b46839SM'boumba Cedric Madianga static int stm32_dma_alloc_chan_resources(struct dma_chan *c) 1454d8b46839SM'boumba Cedric Madianga { 1455d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1456d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 1457d8b46839SM'boumba Cedric Madianga int ret; 1458d8b46839SM'boumba Cedric Madianga 1459d8b46839SM'boumba Cedric Madianga chan->config_init = false; 146048bc73baSPierre-Yves MORDRET 1461d54db74aSZhang Qilong ret = pm_runtime_resume_and_get(dmadev->ddev.dev); 146248bc73baSPierre-Yves MORDRET if (ret < 0) 1463d8b46839SM'boumba Cedric Madianga return ret; 1464d8b46839SM'boumba Cedric Madianga 1465d8b46839SM'boumba Cedric Madianga ret = stm32_dma_disable_chan(chan); 1466d8b46839SM'boumba Cedric Madianga if (ret < 0) 146748bc73baSPierre-Yves MORDRET pm_runtime_put(dmadev->ddev.dev); 1468d8b46839SM'boumba Cedric Madianga 1469d8b46839SM'boumba Cedric Madianga return ret; 1470d8b46839SM'boumba Cedric Madianga } 1471d8b46839SM'boumba Cedric Madianga 1472d8b46839SM'boumba Cedric Madianga static void stm32_dma_free_chan_resources(struct dma_chan *c) 1473d8b46839SM'boumba Cedric Madianga { 1474d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan = to_stm32_dma_chan(c); 1475d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); 1476d8b46839SM'boumba Cedric Madianga unsigned long flags; 1477d8b46839SM'boumba Cedric Madianga 1478d8b46839SM'boumba Cedric Madianga dev_dbg(chan2dev(chan), "Freeing channel %d\n", chan->id); 1479d8b46839SM'boumba Cedric Madianga 1480d8b46839SM'boumba Cedric Madianga if (chan->busy) { 1481d8b46839SM'boumba Cedric Madianga spin_lock_irqsave(&chan->vchan.lock, flags); 1482d8b46839SM'boumba Cedric Madianga stm32_dma_stop(chan); 1483d8b46839SM'boumba Cedric Madianga chan->desc = NULL; 1484d8b46839SM'boumba Cedric Madianga spin_unlock_irqrestore(&chan->vchan.lock, flags); 1485d8b46839SM'boumba Cedric Madianga } 1486d8b46839SM'boumba Cedric Madianga 148748bc73baSPierre-Yves MORDRET pm_runtime_put(dmadev->ddev.dev); 1488d8b46839SM'boumba Cedric Madianga 1489d8b46839SM'boumba Cedric Madianga vchan_free_chan_resources(to_virt_chan(c)); 14905d4d4dfbSAmelie Delaunay stm32_dma_clear_reg(&chan->chan_reg); 14915d4d4dfbSAmelie Delaunay chan->threshold = 0; 1492d8b46839SM'boumba Cedric Madianga } 1493d8b46839SM'boumba Cedric Madianga 1494d8b46839SM'boumba Cedric Madianga static void stm32_dma_desc_free(struct virt_dma_desc *vdesc) 1495d8b46839SM'boumba Cedric Madianga { 1496d8b46839SM'boumba Cedric Madianga kfree(container_of(vdesc, struct stm32_dma_desc, vdesc)); 1497d8b46839SM'boumba Cedric Madianga } 1498d8b46839SM'boumba Cedric Madianga 1499e97adb49SVinod Koul static void stm32_dma_set_config(struct stm32_dma_chan *chan, 1500d8b46839SM'boumba Cedric Madianga struct stm32_dma_cfg *cfg) 1501d8b46839SM'boumba Cedric Madianga { 1502d8b46839SM'boumba Cedric Madianga stm32_dma_clear_reg(&chan->chan_reg); 1503d8b46839SM'boumba Cedric Madianga 1504d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr = cfg->stream_config & STM32_DMA_SCR_CFG_MASK; 15051c32d6c3SAmelie Delaunay chan->chan_reg.dma_scr |= FIELD_PREP(STM32_DMA_SCR_REQ_MASK, cfg->request_line); 1506d8b46839SM'boumba Cedric Madianga 1507d8b46839SM'boumba Cedric Madianga /* Enable Interrupts */ 1508d8b46839SM'boumba Cedric Madianga chan->chan_reg.dma_scr |= STM32_DMA_SCR_TEIE | STM32_DMA_SCR_TCIE; 1509d8b46839SM'boumba Cedric Madianga 15101c32d6c3SAmelie Delaunay chan->threshold = FIELD_GET(STM32_DMA_THRESHOLD_FTR_MASK, cfg->features); 15111c32d6c3SAmelie Delaunay if (FIELD_GET(STM32_DMA_DIRECT_MODE_MASK, cfg->features)) 1512955b1766SAmelie Delaunay chan->threshold = STM32_DMA_FIFO_THRESHOLD_NONE; 15131c32d6c3SAmelie Delaunay if (FIELD_GET(STM32_DMA_ALT_ACK_MODE_MASK, cfg->features)) 15142b5b7405SAmelie Delaunay chan->chan_reg.dma_scr |= STM32_DMA_SCR_TRBUFF; 151572379517SAmelie Delaunay chan->mdma_config.stream_id = FIELD_GET(STM32_DMA_MDMA_STREAM_ID_MASK, cfg->features); 1516d8b46839SM'boumba Cedric Madianga } 1517d8b46839SM'boumba Cedric Madianga 1518d8b46839SM'boumba Cedric Madianga static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, 1519d8b46839SM'boumba Cedric Madianga struct of_dma *ofdma) 1520d8b46839SM'boumba Cedric Madianga { 1521d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev = ofdma->of_dma_data; 15225df4eb45SM'boumba Cedric Madianga struct device *dev = dmadev->ddev.dev; 1523d8b46839SM'boumba Cedric Madianga struct stm32_dma_cfg cfg; 1524d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan; 1525d8b46839SM'boumba Cedric Madianga struct dma_chan *c; 1526d8b46839SM'boumba Cedric Madianga 15275df4eb45SM'boumba Cedric Madianga if (dma_spec->args_count < 4) { 15285df4eb45SM'boumba Cedric Madianga dev_err(dev, "Bad number of cells\n"); 1529d8b46839SM'boumba Cedric Madianga return NULL; 15305df4eb45SM'boumba Cedric Madianga } 1531d8b46839SM'boumba Cedric Madianga 1532d8b46839SM'boumba Cedric Madianga cfg.channel_id = dma_spec->args[0]; 1533d8b46839SM'boumba Cedric Madianga cfg.request_line = dma_spec->args[1]; 1534d8b46839SM'boumba Cedric Madianga cfg.stream_config = dma_spec->args[2]; 1535951f44cbSPierre Yves MORDRET cfg.features = dma_spec->args[3]; 1536d8b46839SM'boumba Cedric Madianga 1537249d5531SPierre Yves MORDRET if (cfg.channel_id >= STM32_DMA_MAX_CHANNELS || 1538249d5531SPierre Yves MORDRET cfg.request_line >= STM32_DMA_MAX_REQUEST_ID) { 15395df4eb45SM'boumba Cedric Madianga dev_err(dev, "Bad channel and/or request id\n"); 1540d8b46839SM'boumba Cedric Madianga return NULL; 15415df4eb45SM'boumba Cedric Madianga } 1542d8b46839SM'boumba Cedric Madianga 1543d8b46839SM'boumba Cedric Madianga chan = &dmadev->chan[cfg.channel_id]; 1544d8b46839SM'boumba Cedric Madianga 1545d8b46839SM'boumba Cedric Madianga c = dma_get_slave_channel(&chan->vchan.chan); 15465df4eb45SM'boumba Cedric Madianga if (!c) { 1547041cf7e0SColin Ian King dev_err(dev, "No more channels available\n"); 15485df4eb45SM'boumba Cedric Madianga return NULL; 15495df4eb45SM'boumba Cedric Madianga } 15505df4eb45SM'boumba Cedric Madianga 1551d8b46839SM'boumba Cedric Madianga stm32_dma_set_config(chan, &cfg); 1552d8b46839SM'boumba Cedric Madianga 1553d8b46839SM'boumba Cedric Madianga return c; 1554d8b46839SM'boumba Cedric Madianga } 1555d8b46839SM'boumba Cedric Madianga 1556d8b46839SM'boumba Cedric Madianga static const struct of_device_id stm32_dma_of_match[] = { 1557d8b46839SM'boumba Cedric Madianga { .compatible = "st,stm32-dma", }, 1558d8b46839SM'boumba Cedric Madianga { /* sentinel */ }, 1559d8b46839SM'boumba Cedric Madianga }; 1560d8b46839SM'boumba Cedric Madianga MODULE_DEVICE_TABLE(of, stm32_dma_of_match); 1561d8b46839SM'boumba Cedric Madianga 1562d8b46839SM'boumba Cedric Madianga static int stm32_dma_probe(struct platform_device *pdev) 1563d8b46839SM'boumba Cedric Madianga { 1564d8b46839SM'boumba Cedric Madianga struct stm32_dma_chan *chan; 1565d8b46839SM'boumba Cedric Madianga struct stm32_dma_device *dmadev; 1566d8b46839SM'boumba Cedric Madianga struct dma_device *dd; 1567d8b46839SM'boumba Cedric Madianga const struct of_device_id *match; 1568d8b46839SM'boumba Cedric Madianga struct resource *res; 15698cf1e0fcSEtienne Carriere struct reset_control *rst; 1570d8b46839SM'boumba Cedric Madianga int i, ret; 1571d8b46839SM'boumba Cedric Madianga 1572d8b46839SM'boumba Cedric Madianga match = of_match_device(stm32_dma_of_match, &pdev->dev); 1573d8b46839SM'boumba Cedric Madianga if (!match) { 1574d8b46839SM'boumba Cedric Madianga dev_err(&pdev->dev, "Error: No device match found\n"); 1575d8b46839SM'boumba Cedric Madianga return -ENODEV; 1576d8b46839SM'boumba Cedric Madianga } 1577d8b46839SM'boumba Cedric Madianga 1578d8b46839SM'boumba Cedric Madianga dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL); 1579d8b46839SM'boumba Cedric Madianga if (!dmadev) 1580d8b46839SM'boumba Cedric Madianga return -ENOMEM; 1581d8b46839SM'boumba Cedric Madianga 1582d8b46839SM'boumba Cedric Madianga dd = &dmadev->ddev; 1583d8b46839SM'boumba Cedric Madianga 1584*42c3cdaaSYangtao Li dmadev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 1585d8b46839SM'boumba Cedric Madianga if (IS_ERR(dmadev->base)) 1586d8b46839SM'boumba Cedric Madianga return PTR_ERR(dmadev->base); 1587d8b46839SM'boumba Cedric Madianga 1588d8b46839SM'boumba Cedric Madianga dmadev->clk = devm_clk_get(&pdev->dev, NULL); 15891c966e1dSKrzysztof Kozlowski if (IS_ERR(dmadev->clk)) 15901c966e1dSKrzysztof Kozlowski return dev_err_probe(&pdev->dev, PTR_ERR(dmadev->clk), "Can't get clock\n"); 1591d8b46839SM'boumba Cedric Madianga 159248bc73baSPierre-Yves MORDRET ret = clk_prepare_enable(dmadev->clk); 159348bc73baSPierre-Yves MORDRET if (ret < 0) { 159448bc73baSPierre-Yves MORDRET dev_err(&pdev->dev, "clk_prep_enable error: %d\n", ret); 159548bc73baSPierre-Yves MORDRET return ret; 159648bc73baSPierre-Yves MORDRET } 159748bc73baSPierre-Yves MORDRET 1598d8b46839SM'boumba Cedric Madianga dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node, 1599d8b46839SM'boumba Cedric Madianga "st,mem2mem"); 1600d8b46839SM'boumba Cedric Madianga 16018cf1e0fcSEtienne Carriere rst = devm_reset_control_get(&pdev->dev, NULL); 1602615eee2cSEtienne Carriere if (IS_ERR(rst)) { 1603615eee2cSEtienne Carriere ret = PTR_ERR(rst); 1604615eee2cSEtienne Carriere if (ret == -EPROBE_DEFER) 1605615eee2cSEtienne Carriere goto clk_free; 1606615eee2cSEtienne Carriere } else { 16078cf1e0fcSEtienne Carriere reset_control_assert(rst); 1608d8b46839SM'boumba Cedric Madianga udelay(2); 16098cf1e0fcSEtienne Carriere reset_control_deassert(rst); 1610d8b46839SM'boumba Cedric Madianga } 1611d8b46839SM'boumba Cedric Madianga 1612d7a9e426SAmelie Delaunay dma_set_max_seg_size(&pdev->dev, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); 1613d7a9e426SAmelie Delaunay 1614d8b46839SM'boumba Cedric Madianga dma_cap_set(DMA_SLAVE, dd->cap_mask); 1615d8b46839SM'boumba Cedric Madianga dma_cap_set(DMA_PRIVATE, dd->cap_mask); 1616d8b46839SM'boumba Cedric Madianga dma_cap_set(DMA_CYCLIC, dd->cap_mask); 1617d8b46839SM'boumba Cedric Madianga dd->device_alloc_chan_resources = stm32_dma_alloc_chan_resources; 1618d8b46839SM'boumba Cedric Madianga dd->device_free_chan_resources = stm32_dma_free_chan_resources; 1619d8b46839SM'boumba Cedric Madianga dd->device_tx_status = stm32_dma_tx_status; 1620d8b46839SM'boumba Cedric Madianga dd->device_issue_pending = stm32_dma_issue_pending; 1621d8b46839SM'boumba Cedric Madianga dd->device_prep_slave_sg = stm32_dma_prep_slave_sg; 1622d8b46839SM'boumba Cedric Madianga dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic; 1623d8b46839SM'boumba Cedric Madianga dd->device_config = stm32_dma_slave_config; 1624099a9a94SAmelie Delaunay dd->device_pause = stm32_dma_pause; 1625099a9a94SAmelie Delaunay dd->device_resume = stm32_dma_resume; 1626d8b46839SM'boumba Cedric Madianga dd->device_terminate_all = stm32_dma_terminate_all; 1627dc808675SM'boumba Cedric Madianga dd->device_synchronize = stm32_dma_synchronize; 1628d8b46839SM'boumba Cedric Madianga dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 1629d8b46839SM'boumba Cedric Madianga BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 1630d8b46839SM'boumba Cedric Madianga BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); 1631d8b46839SM'boumba Cedric Madianga dd->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 1632d8b46839SM'boumba Cedric Madianga BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 1633d8b46839SM'boumba Cedric Madianga BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); 1634d8b46839SM'boumba Cedric Madianga dd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); 1635d8b46839SM'boumba Cedric Madianga dd->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 163632ce1088SAmelie Delaunay dd->copy_align = DMAENGINE_ALIGN_32_BYTES; 1637276b0046SM'boumba Cedric Madianga dd->max_burst = STM32_DMA_MAX_BURST; 1638728f6c78SAmelie Delaunay dd->max_sg_burst = STM32_DMA_ALIGNED_MAX_DATA_ITEMS; 163922a0bb29SPierre-Yves MORDRET dd->descriptor_reuse = true; 1640d8b46839SM'boumba Cedric Madianga dd->dev = &pdev->dev; 1641d8b46839SM'boumba Cedric Madianga INIT_LIST_HEAD(&dd->channels); 1642d8b46839SM'boumba Cedric Madianga 1643d8b46839SM'boumba Cedric Madianga if (dmadev->mem2mem) { 1644d8b46839SM'boumba Cedric Madianga dma_cap_set(DMA_MEMCPY, dd->cap_mask); 1645d8b46839SM'boumba Cedric Madianga dd->device_prep_dma_memcpy = stm32_dma_prep_dma_memcpy; 1646d8b46839SM'boumba Cedric Madianga dd->directions |= BIT(DMA_MEM_TO_MEM); 1647d8b46839SM'boumba Cedric Madianga } 1648d8b46839SM'boumba Cedric Madianga 1649d8b46839SM'boumba Cedric Madianga for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { 1650d8b46839SM'boumba Cedric Madianga chan = &dmadev->chan[i]; 1651d8b46839SM'boumba Cedric Madianga chan->id = i; 1652d8b46839SM'boumba Cedric Madianga chan->vchan.desc_free = stm32_dma_desc_free; 1653d8b46839SM'boumba Cedric Madianga vchan_init(&chan->vchan, dd); 165472379517SAmelie Delaunay 165572379517SAmelie Delaunay chan->mdma_config.ifcr = res->start; 165672379517SAmelie Delaunay chan->mdma_config.ifcr += STM32_DMA_IFCR(chan->id); 165772379517SAmelie Delaunay 165872379517SAmelie Delaunay chan->mdma_config.tcf = STM32_DMA_TCI; 165972379517SAmelie Delaunay chan->mdma_config.tcf <<= STM32_DMA_FLAGS_SHIFT(chan->id); 1660d8b46839SM'boumba Cedric Madianga } 1661d8b46839SM'boumba Cedric Madianga 1662d8b46839SM'boumba Cedric Madianga ret = dma_async_device_register(dd); 1663d8b46839SM'boumba Cedric Madianga if (ret) 166448bc73baSPierre-Yves MORDRET goto clk_free; 1665d8b46839SM'boumba Cedric Madianga 1666d8b46839SM'boumba Cedric Madianga for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { 1667d8b46839SM'boumba Cedric Madianga chan = &dmadev->chan[i]; 1668c6504be5SVinod Koul ret = platform_get_irq(pdev, i); 1669e17be6e1SStephen Boyd if (ret < 0) 1670d8b46839SM'boumba Cedric Madianga goto err_unregister; 1671c6504be5SVinod Koul chan->irq = ret; 1672c6504be5SVinod Koul 1673d8b46839SM'boumba Cedric Madianga ret = devm_request_irq(&pdev->dev, chan->irq, 1674d8b46839SM'boumba Cedric Madianga stm32_dma_chan_irq, 0, 1675d8b46839SM'boumba Cedric Madianga dev_name(chan2dev(chan)), chan); 1676d8b46839SM'boumba Cedric Madianga if (ret) { 1677d8b46839SM'boumba Cedric Madianga dev_err(&pdev->dev, 1678d8b46839SM'boumba Cedric Madianga "request_irq failed with err %d channel %d\n", 1679d8b46839SM'boumba Cedric Madianga ret, i); 1680d8b46839SM'boumba Cedric Madianga goto err_unregister; 1681d8b46839SM'boumba Cedric Madianga } 1682d8b46839SM'boumba Cedric Madianga } 1683d8b46839SM'boumba Cedric Madianga 1684d8b46839SM'boumba Cedric Madianga ret = of_dma_controller_register(pdev->dev.of_node, 1685d8b46839SM'boumba Cedric Madianga stm32_dma_of_xlate, dmadev); 1686d8b46839SM'boumba Cedric Madianga if (ret < 0) { 1687d8b46839SM'boumba Cedric Madianga dev_err(&pdev->dev, 1688d8b46839SM'boumba Cedric Madianga "STM32 DMA DMA OF registration failed %d\n", ret); 1689d8b46839SM'boumba Cedric Madianga goto err_unregister; 1690d8b46839SM'boumba Cedric Madianga } 1691d8b46839SM'boumba Cedric Madianga 1692d8b46839SM'boumba Cedric Madianga platform_set_drvdata(pdev, dmadev); 1693d8b46839SM'boumba Cedric Madianga 169448bc73baSPierre-Yves MORDRET pm_runtime_set_active(&pdev->dev); 169548bc73baSPierre-Yves MORDRET pm_runtime_enable(&pdev->dev); 169648bc73baSPierre-Yves MORDRET pm_runtime_get_noresume(&pdev->dev); 169748bc73baSPierre-Yves MORDRET pm_runtime_put(&pdev->dev); 169848bc73baSPierre-Yves MORDRET 1699d8b46839SM'boumba Cedric Madianga dev_info(&pdev->dev, "STM32 DMA driver registered\n"); 1700d8b46839SM'boumba Cedric Madianga 1701d8b46839SM'boumba Cedric Madianga return 0; 1702d8b46839SM'boumba Cedric Madianga 1703d8b46839SM'boumba Cedric Madianga err_unregister: 1704d8b46839SM'boumba Cedric Madianga dma_async_device_unregister(dd); 170548bc73baSPierre-Yves MORDRET clk_free: 170648bc73baSPierre-Yves MORDRET clk_disable_unprepare(dmadev->clk); 1707d8b46839SM'boumba Cedric Madianga 1708d8b46839SM'boumba Cedric Madianga return ret; 1709d8b46839SM'boumba Cedric Madianga } 1710d8b46839SM'boumba Cedric Madianga 171148bc73baSPierre-Yves MORDRET #ifdef CONFIG_PM 171248bc73baSPierre-Yves MORDRET static int stm32_dma_runtime_suspend(struct device *dev) 171348bc73baSPierre-Yves MORDRET { 171448bc73baSPierre-Yves MORDRET struct stm32_dma_device *dmadev = dev_get_drvdata(dev); 171548bc73baSPierre-Yves MORDRET 171648bc73baSPierre-Yves MORDRET clk_disable_unprepare(dmadev->clk); 171748bc73baSPierre-Yves MORDRET 171848bc73baSPierre-Yves MORDRET return 0; 171948bc73baSPierre-Yves MORDRET } 172048bc73baSPierre-Yves MORDRET 172148bc73baSPierre-Yves MORDRET static int stm32_dma_runtime_resume(struct device *dev) 172248bc73baSPierre-Yves MORDRET { 172348bc73baSPierre-Yves MORDRET struct stm32_dma_device *dmadev = dev_get_drvdata(dev); 172448bc73baSPierre-Yves MORDRET int ret; 172548bc73baSPierre-Yves MORDRET 172648bc73baSPierre-Yves MORDRET ret = clk_prepare_enable(dmadev->clk); 172748bc73baSPierre-Yves MORDRET if (ret) { 172848bc73baSPierre-Yves MORDRET dev_err(dev, "failed to prepare_enable clock\n"); 172948bc73baSPierre-Yves MORDRET return ret; 173048bc73baSPierre-Yves MORDRET } 173148bc73baSPierre-Yves MORDRET 173248bc73baSPierre-Yves MORDRET return 0; 173348bc73baSPierre-Yves MORDRET } 173448bc73baSPierre-Yves MORDRET #endif 173548bc73baSPierre-Yves MORDRET 173605f8740aSPierre-Yves MORDRET #ifdef CONFIG_PM_SLEEP 1737baa14243SAmelie Delaunay static int stm32_dma_pm_suspend(struct device *dev) 173805f8740aSPierre-Yves MORDRET { 173905f8740aSPierre-Yves MORDRET struct stm32_dma_device *dmadev = dev_get_drvdata(dev); 174005f8740aSPierre-Yves MORDRET int id, ret, scr; 174105f8740aSPierre-Yves MORDRET 1742d54db74aSZhang Qilong ret = pm_runtime_resume_and_get(dev); 174305f8740aSPierre-Yves MORDRET if (ret < 0) 174405f8740aSPierre-Yves MORDRET return ret; 174505f8740aSPierre-Yves MORDRET 174605f8740aSPierre-Yves MORDRET for (id = 0; id < STM32_DMA_MAX_CHANNELS; id++) { 174705f8740aSPierre-Yves MORDRET scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); 174805f8740aSPierre-Yves MORDRET if (scr & STM32_DMA_SCR_EN) { 174905f8740aSPierre-Yves MORDRET dev_warn(dev, "Suspend is prevented by Chan %i\n", id); 175005f8740aSPierre-Yves MORDRET return -EBUSY; 175105f8740aSPierre-Yves MORDRET } 175205f8740aSPierre-Yves MORDRET } 175305f8740aSPierre-Yves MORDRET 175405f8740aSPierre-Yves MORDRET pm_runtime_put_sync(dev); 175505f8740aSPierre-Yves MORDRET 175605f8740aSPierre-Yves MORDRET pm_runtime_force_suspend(dev); 175705f8740aSPierre-Yves MORDRET 175805f8740aSPierre-Yves MORDRET return 0; 175905f8740aSPierre-Yves MORDRET } 176005f8740aSPierre-Yves MORDRET 1761baa14243SAmelie Delaunay static int stm32_dma_pm_resume(struct device *dev) 176205f8740aSPierre-Yves MORDRET { 176305f8740aSPierre-Yves MORDRET return pm_runtime_force_resume(dev); 176405f8740aSPierre-Yves MORDRET } 176505f8740aSPierre-Yves MORDRET #endif 176605f8740aSPierre-Yves MORDRET 176748bc73baSPierre-Yves MORDRET static const struct dev_pm_ops stm32_dma_pm_ops = { 1768baa14243SAmelie Delaunay SET_SYSTEM_SLEEP_PM_OPS(stm32_dma_pm_suspend, stm32_dma_pm_resume) 176948bc73baSPierre-Yves MORDRET SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend, 177048bc73baSPierre-Yves MORDRET stm32_dma_runtime_resume, NULL) 177148bc73baSPierre-Yves MORDRET }; 177248bc73baSPierre-Yves MORDRET 1773d8b46839SM'boumba Cedric Madianga static struct platform_driver stm32_dma_driver = { 1774d8b46839SM'boumba Cedric Madianga .driver = { 1775d8b46839SM'boumba Cedric Madianga .name = "stm32-dma", 1776d8b46839SM'boumba Cedric Madianga .of_match_table = stm32_dma_of_match, 177748bc73baSPierre-Yves MORDRET .pm = &stm32_dma_pm_ops, 1778d8b46839SM'boumba Cedric Madianga }, 1779615eee2cSEtienne Carriere .probe = stm32_dma_probe, 1780d8b46839SM'boumba Cedric Madianga }; 1781d8b46839SM'boumba Cedric Madianga 1782d8b46839SM'boumba Cedric Madianga static int __init stm32_dma_init(void) 1783d8b46839SM'boumba Cedric Madianga { 1784615eee2cSEtienne Carriere return platform_driver_register(&stm32_dma_driver); 1785d8b46839SM'boumba Cedric Madianga } 1786d8b46839SM'boumba Cedric Madianga subsys_initcall(stm32_dma_init); 1787