bcm27xx: add kernel 5.10 support
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-5.10 / 950-0617-media-rpivid-Improve-stream_on-off-conformance-clock.patch
1 From 6a269149abd400ff09bb61b254d7d7891b2b01b1 Mon Sep 17 00:00:00 2001
2 From: John Cox <jc@kynesim.co.uk>
3 Date: Sat, 3 Apr 2021 16:27:03 +0100
4 Subject: [PATCH] media: rpivid: Improve stream_on/off conformance &
5 clock setup
6
7 Fix stream on & off such that failures leave the driver in the correct
8 state. Ensure that the clock is on when we are streaming and off when
9 all contexts attached to this device have stopped streaming.
10
11 Signed-off-by: John Cox <jc@kynesim.co.uk>
12 ---
13 drivers/staging/media/rpivid/rpivid.c | 8 +-
14 drivers/staging/media/rpivid/rpivid.h | 15 ++-
15 drivers/staging/media/rpivid/rpivid_hw.c | 1 +
16 drivers/staging/media/rpivid/rpivid_video.c | 103 +++++++++++++++-----
17 4 files changed, 101 insertions(+), 26 deletions(-)
18
19 --- a/drivers/staging/media/rpivid/rpivid.c
20 +++ b/drivers/staging/media/rpivid/rpivid.c
21 @@ -212,9 +212,12 @@ static int rpivid_open(struct file *file
22 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
23 if (!ctx) {
24 mutex_unlock(&dev->dev_mutex);
25 - return -ENOMEM;
26 + ret = -ENOMEM;
27 + goto err_unlock;
28 }
29
30 + mutex_init(&ctx->ctx_mutex);
31 +
32 v4l2_fh_init(&ctx->fh, video_devdata(file));
33 file->private_data = &ctx->fh;
34 ctx->dev = dev;
35 @@ -245,7 +248,9 @@ static int rpivid_open(struct file *file
36 err_ctrls:
37 v4l2_ctrl_handler_free(&ctx->hdl);
38 err_free:
39 + mutex_destroy(&ctx->ctx_mutex);
40 kfree(ctx);
41 +err_unlock:
42 mutex_unlock(&dev->dev_mutex);
43
44 return ret;
45 @@ -266,6 +271,7 @@ static int rpivid_release(struct file *f
46 kfree(ctx->ctrls);
47
48 v4l2_fh_exit(&ctx->fh);
49 + mutex_destroy(&ctx->ctx_mutex);
50
51 kfree(ctx);
52
53 --- a/drivers/staging/media/rpivid/rpivid.h
54 +++ b/drivers/staging/media/rpivid/rpivid.h
55 @@ -84,6 +84,11 @@ struct rpivid_q_aux;
56 #define RPIVID_AUX_ENT_COUNT VB2_MAX_FRAME
57
58
59 +#define RPIVID_CTX_STATE_STOPPED 0 /* stream_off */
60 +#define RPIVID_CTX_STATE_STREAM_ON 1 /* decoding */
61 +#define RPIVID_CTX_STATE_STREAM_STOP 2 /* in stream_off */
62 +#define RPIVID_CTX_STATE_STREAM_ERR 3 /* stream_on but broken */
63 +
64 struct rpivid_ctx {
65 struct v4l2_fh fh;
66 struct rpivid_dev *dev;
67 @@ -91,10 +96,19 @@ struct rpivid_ctx {
68 struct v4l2_pix_format_mplane src_fmt;
69 struct v4l2_pix_format_mplane dst_fmt;
70 int dst_fmt_set;
71 +
72 + atomic_t stream_state;
73 + struct clk_request *clk_req;
74 + int src_stream_on;
75 + int dst_stream_on;
76 +
77 // fatal_err is set if an error has occurred s.t. decode cannot
78 // continue (such as running out of CMA)
79 int fatal_err;
80
81 + /* Lock for queue operations */
82 + struct mutex ctx_mutex;
83 +
84 struct v4l2_ctrl_handler hdl;
85 struct v4l2_ctrl **ctrls;
86
87 @@ -180,7 +194,6 @@ struct rpivid_dev {
88 void __iomem *base_h265;
89
90 struct clk *clock;
91 - struct clk_request *hevc_req;
92
93 int cache_align;
94
95 --- a/drivers/staging/media/rpivid/rpivid_hw.c
96 +++ b/drivers/staging/media/rpivid/rpivid_hw.c
97 @@ -359,6 +359,7 @@ int rpivid_hw_probe(struct rpivid_dev *d
98 void rpivid_hw_remove(struct rpivid_dev *dev)
99 {
100 // IRQ auto freed on unload so no need to do it here
101 + // ioremap auto freed on unload
102 ictl_uninit(&dev->ic_active1);
103 ictl_uninit(&dev->ic_active2);
104 }
105 --- a/drivers/staging/media/rpivid/rpivid_video.c
106 +++ b/drivers/staging/media/rpivid/rpivid_video.c
107 @@ -18,6 +18,7 @@
108 #include <media/v4l2-mem2mem.h>
109
110 #include "rpivid.h"
111 +#include "rpivid_hw.h"
112 #include "rpivid_video.h"
113 #include "rpivid_dec.h"
114
115 @@ -533,33 +534,85 @@ static int rpivid_buf_prepare(struct vb2
116 return 0;
117 }
118
119 +/* Only stops the clock if streaom off on both output & capture */
120 +static void stop_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx)
121 +{
122 + if (ctx->src_stream_on ||
123 + ctx->dst_stream_on ||
124 + !ctx->clk_req)
125 + return;
126 +
127 + clk_request_done(ctx->clk_req);
128 + ctx->clk_req = NULL;
129 +
130 + clk_disable_unprepare(dev->clock);
131 +}
132 +
133 +/* Always starts the clock if it isn't already on this ctx */
134 +static int start_clock(struct rpivid_dev *dev, struct rpivid_ctx *ctx)
135 +{
136 + long max_hevc_clock;
137 + int rv;
138 +
139 + if (ctx->clk_req)
140 + return 0;
141 +
142 + max_hevc_clock = clk_round_rate(dev->clock, ULONG_MAX);
143 +
144 + ctx->clk_req = clk_request_start(dev->clock, max_hevc_clock);
145 + if (!ctx->clk_req) {
146 + dev_err(dev->dev, "Failed to set clock rate\n");
147 + return -EIO;
148 + }
149 +
150 + rv = clk_prepare_enable(dev->clock);
151 + if (rv) {
152 + dev_err(dev->dev, "Failed to enable clock\n");
153 + clk_request_done(ctx->clk_req);
154 + ctx->clk_req = NULL;
155 + return rv;
156 + }
157 +
158 + return 0;
159 +}
160 +
161 static int rpivid_start_streaming(struct vb2_queue *vq, unsigned int count)
162 {
163 struct rpivid_ctx *ctx = vb2_get_drv_priv(vq);
164 struct rpivid_dev *dev = ctx->dev;
165 - long max_hevc_clock = clk_round_rate(dev->clock, ULONG_MAX);
166 int ret = 0;
167
168 - if (ctx->src_fmt.pixelformat != V4L2_PIX_FMT_HEVC_SLICE)
169 - return -EINVAL;
170 -
171 - if (V4L2_TYPE_IS_OUTPUT(vq->type) && dev->dec_ops->start)
172 - ret = dev->dec_ops->start(ctx);
173 + if (!V4L2_TYPE_IS_OUTPUT(vq->type)) {
174 + ctx->dst_stream_on = 1;
175 + goto ok;
176 + }
177
178 - dev->hevc_req = clk_request_start(dev->clock, max_hevc_clock);
179 - if (!dev->hevc_req) {
180 - dev_err(dev->dev, "Failed to set clock rate\n");
181 - goto out;
182 + if (ctx->src_fmt.pixelformat != V4L2_PIX_FMT_HEVC_SLICE) {
183 + ret = -EINVAL;
184 + goto fail_cleanup;
185 }
186
187 - ret = clk_prepare_enable(dev->clock);
188 + if (ctx->src_stream_on)
189 + goto ok;
190 +
191 + ret = start_clock(dev, ctx);
192 if (ret)
193 - dev_err(dev->dev, "Failed to enable clock\n");
194 + goto fail_cleanup;
195
196 -out:
197 + if (dev->dec_ops->start)
198 + ret = dev->dec_ops->start(ctx);
199 if (ret)
200 - rpivid_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
201 + goto fail_stop_clock;
202 +
203 + ctx->src_stream_on = 1;
204 +ok:
205 + return 0;
206
207 +fail_stop_clock:
208 + stop_clock(dev, ctx);
209 +fail_cleanup:
210 + v4l2_err(&dev->v4l2_dev, "%s: qtype=%d: FAIL\n", __func__, vq->type);
211 + rpivid_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
212 return ret;
213 }
214
215 @@ -568,17 +621,19 @@ static void rpivid_stop_streaming(struct
216 struct rpivid_ctx *ctx = vb2_get_drv_priv(vq);
217 struct rpivid_dev *dev = ctx->dev;
218
219 - if (V4L2_TYPE_IS_OUTPUT(vq->type) && dev->dec_ops->stop)
220 - dev->dec_ops->stop(ctx);
221 + if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
222 + ctx->src_stream_on = 0;
223 + if (dev->dec_ops->stop)
224 + dev->dec_ops->stop(ctx);
225 + } else {
226 + ctx->dst_stream_on = 0;
227 + }
228
229 rpivid_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
230
231 - if (dev->hevc_req)
232 - {
233 - clk_request_done(dev->hevc_req);
234 - dev->hevc_req = NULL;
235 - }
236 - clk_disable_unprepare(dev->clock);
237 + vb2_wait_for_all_buffers(vq);
238 +
239 + stop_clock(dev, ctx);
240 }
241
242 static void rpivid_buf_queue(struct vb2_buffer *vb)
243 @@ -622,7 +677,7 @@ int rpivid_queue_init(void *priv, struct
244 src_vq->ops = &rpivid_qops;
245 src_vq->mem_ops = &vb2_dma_contig_memops;
246 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
247 - src_vq->lock = &ctx->dev->dev_mutex;
248 + src_vq->lock = &ctx->ctx_mutex;
249 src_vq->dev = ctx->dev->dev;
250 src_vq->supports_requests = true;
251 src_vq->requires_requests = true;
252 @@ -639,7 +694,7 @@ int rpivid_queue_init(void *priv, struct
253 dst_vq->ops = &rpivid_qops;
254 dst_vq->mem_ops = &vb2_dma_contig_memops;
255 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
256 - dst_vq->lock = &ctx->dev->dev_mutex;
257 + dst_vq->lock = &ctx->ctx_mutex;
258 dst_vq->dev = ctx->dev->dev;
259
260 return vb2_queue_init(dst_vq);