layerscape: add patches-5.4
[openwrt/staging/mkresin.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,