ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 806-dma-0012-MLK-17094-dma-fsl-edma-v3-add-suspend-resume-to-rest.patch
1 From 411a2f6ad13bd58646de34a340553232044f0951 Mon Sep 17 00:00:00 2001
2 From: Robin Gong <yibin.gong@nxp.com>
3 Date: Mon, 4 Dec 2017 15:35:09 +0800
4 Subject: [PATCH] MLK-17094 dma: fsl-edma-v3: add suspend/resume to restore
5  back channel registers
6
7 Add suspend to save channel registers and resume to restore them back since
8 edmav3 may powered off in suspend.
9
10 Signed-off-by: Robin Gong <yibin.gong@nxp.com>
11 (cherry picked from commit 7eda1ae538ec7e7c0f993b3ea91805459f3dedd3)
12 ---
13  drivers/dma/fsl-edma-v3.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
14  1 file changed, 86 insertions(+)
15
16 --- a/drivers/dma/fsl-edma-v3.c
17 +++ b/drivers/dma/fsl-edma-v3.c
18 @@ -111,6 +111,11 @@
19  #define CHAN_PREFIX                    "edma0-chan"
20  #define CHAN_POSFIX                    "-tx"
21  
22 +enum fsl_edma3_pm_state {
23 +       RUNNING = 0,
24 +       SUSPENDED,
25 +};
26 +
27  struct fsl_edma3_hw_tcd {
28         __le32  saddr;
29         __le16  soff;
30 @@ -142,6 +147,8 @@ struct fsl_edma3_slave_config {
31  struct fsl_edma3_chan {
32         struct virt_dma_chan            vchan;
33         enum dma_status                 status;
34 +       enum fsl_edma3_pm_state         pm_state;
35 +       bool                            idle;
36         struct fsl_edma3_engine         *edma3;
37         struct fsl_edma3_desc           *edesc;
38         struct fsl_edma3_slave_config   fsc;
39 @@ -165,11 +172,18 @@ struct fsl_edma3_desc {
40         struct fsl_edma3_sw_tcd         tcd[];
41  };
42  
43 +struct fsl_edma3_reg_save {
44 +       u32 csr;
45 +       u32 sbr;
46 +};
47 +
48  struct fsl_edma3_engine {
49         struct dma_device       dma_dev;
50         struct mutex            fsl_edma3_mutex;
51         u32                     n_chans;
52         int                     errirq;
53 +       #define MAX_CHAN_NUM    32
54 +       struct fsl_edma3_reg_save edma_regs[MAX_CHAN_NUM];
55         bool                    swap;   /* remote/local swapped on Audio edma */
56         struct fsl_edma3_chan   chans[];
57  };
58 @@ -266,6 +280,7 @@ static int fsl_edma3_terminate_all(struc
59         spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
60         fsl_edma3_disable_request(fsl_chan);
61         fsl_chan->edesc = NULL;
62 +       fsl_chan->idle = true;
63         vchan_get_all_descriptors(&fsl_chan->vchan, &head);
64         spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
65         vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
66 @@ -281,6 +296,7 @@ static int fsl_edma3_pause(struct dma_ch
67         if (fsl_chan->edesc) {
68                 fsl_edma3_disable_request(fsl_chan);
69                 fsl_chan->status = DMA_PAUSED;
70 +               fsl_chan->idle = true;
71         }
72         spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
73         return 0;
74 @@ -295,6 +311,7 @@ static int fsl_edma3_resume(struct dma_c
75         if (fsl_chan->edesc) {
76                 fsl_edma3_enable_request(fsl_chan);
77                 fsl_chan->status = DMA_IN_PROGRESS;
78 +               fsl_chan->idle = false;
79         }
80         spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
81         return 0;
82 @@ -664,6 +681,7 @@ static void fsl_edma3_xfer_desc(struct f
83         fsl_edma3_set_tcd_regs(fsl_chan, fsl_chan->edesc->tcd[0].vtcd);
84         fsl_edma3_enable_request(fsl_chan);
85         fsl_chan->status = DMA_IN_PROGRESS;
86 +       fsl_chan->idle = false;
87  }
88  
89  static size_t fsl_edma3_desc_residue(struct fsl_edma3_chan *fsl_chan,
90 @@ -700,6 +718,7 @@ static irqreturn_t fsl_edma3_tx_handler(
91                 vchan_cookie_complete(&fsl_chan->edesc->vdesc);
92                 fsl_chan->edesc = NULL;
93                 fsl_chan->status = DMA_COMPLETE;
94 +               fsl_chan->idle = true;
95         } else {
96                 vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
97         }
98 @@ -719,6 +738,12 @@ static void fsl_edma3_issue_pending(stru
99  
100         spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
101  
102 +       if (unlikely(fsl_chan->pm_state != RUNNING)) {
103 +               spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
104 +               /* cannot submit due to suspend */
105 +               return;
106 +       }
107 +
108         if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
109                 fsl_edma3_xfer_desc(fsl_chan);
110  
111 @@ -821,6 +846,8 @@ static int fsl_edma3_probe(struct platfo
112                 unsigned long val;
113  
114                 fsl_chan->edma3 = fsl_edma3;
115 +               fsl_chan->pm_state = RUNNING;
116 +               fsl_chan->idle = true;
117                 /* Get per channel membase */
118                 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
119                 fsl_chan->membase = devm_ioremap_resource(&pdev->dev, res);
120 @@ -932,6 +959,64 @@ static int fsl_edma3_remove(struct platf
121         return 0;
122  }
123  
124 +static int fsl_edma3_suspend_late(struct device *dev)
125 +{
126 +       struct fsl_edma3_engine *fsl_edma = dev_get_drvdata(dev);
127 +       struct fsl_edma3_chan *fsl_chan;
128 +       unsigned long flags;
129 +       void __iomem *addr;
130 +       int i;
131 +
132 +       for (i = 0; i < fsl_edma->n_chans; i++) {
133 +               fsl_chan = &fsl_edma->chans[i];
134 +               addr = fsl_chan->membase;
135 +
136 +               spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
137 +               fsl_edma->edma_regs[i].csr = readl(addr + EDMA_CH_CSR);
138 +               fsl_edma->edma_regs[i].sbr = readl(addr + EDMA_CH_SBR);
139 +               /* Make sure chan is idle or will force disable. */
140 +               if (unlikely(!fsl_chan->idle)) {
141 +                       dev_warn(dev, "WARN: There is non-idle channel.");
142 +                       fsl_edma3_disable_request(fsl_chan);
143 +               }
144 +               fsl_chan->pm_state = SUSPENDED;
145 +               spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
146 +       }
147 +
148 +       return 0;
149 +}
150 +
151 +static int fsl_edma3_resume_early(struct device *dev)
152 +{
153 +       struct fsl_edma3_engine *fsl_edma = dev_get_drvdata(dev);
154 +       struct fsl_edma3_chan *fsl_chan;
155 +       void __iomem *addr;
156 +       unsigned long flags;
157 +       int i;
158 +
159 +       for (i = 0; i < fsl_edma->n_chans; i++) {
160 +               fsl_chan = &fsl_edma->chans[i];
161 +               addr = fsl_chan->membase;
162 +
163 +               spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
164 +               writel(fsl_edma->edma_regs[i].csr, addr + EDMA_CH_CSR);
165 +               writel(fsl_edma->edma_regs[i].sbr, addr + EDMA_CH_SBR);
166 +               /* restore tcd if this channel not terminated before suspend */
167 +               if (fsl_chan->edesc)
168 +                       fsl_edma3_set_tcd_regs(fsl_chan,
169 +                                               fsl_chan->edesc->tcd[0].vtcd);
170 +               fsl_chan->pm_state = RUNNING;
171 +               spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
172 +       }
173 +
174 +       return 0;
175 +}
176 +
177 +static const struct dev_pm_ops fsl_edma3_pm_ops = {
178 +       .suspend_late   = fsl_edma3_suspend_late,
179 +       .resume_early   = fsl_edma3_resume_early,
180 +};
181 +
182  static const struct of_device_id fsl_edma3_dt_ids[] = {
183         { .compatible = "fsl,imx8qm-edma", },
184         { .compatible = "fsl,imx8qm-adma", },
185 @@ -943,6 +1028,7 @@ static struct platform_driver fsl_edma3_
186         .driver         = {
187                 .name   = "fsl-edma-v3",
188                 .of_match_table = fsl_edma3_dt_ids,
189 +               .pm     = &fsl_edma3_pm_ops,
190         },
191         .probe          = fsl_edma3_probe,
192         .remove         = fsl_edma3_remove,