1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd. */
3*4882a593Smuzhiyun
4*4882a593Smuzhiyun #include <linux/compat.h>
5*4882a593Smuzhiyun #include <linux/delay.h>
6*4882a593Smuzhiyun #include <linux/interrupt.h>
7*4882a593Smuzhiyun #include <linux/iommu.h>
8*4882a593Smuzhiyun #include <linux/pm_runtime.h>
9*4882a593Smuzhiyun #include <linux/videodev2.h>
10*4882a593Smuzhiyun #include <media/media-entity.h>
11*4882a593Smuzhiyun #include <media/videobuf2-dma-contig.h>
12*4882a593Smuzhiyun #include <media/v4l2-event.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include "dev.h"
15*4882a593Smuzhiyun #include "regs.h"
16*4882a593Smuzhiyun
cal_fec_mesh(u32 width,u32 height,u32 mode)17*4882a593Smuzhiyun u32 cal_fec_mesh(u32 width, u32 height, u32 mode)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun u32 mesh_size, mesh_left_height;
20*4882a593Smuzhiyun u32 w = ALIGN(width, 32);
21*4882a593Smuzhiyun u32 h = ALIGN(height, 32);
22*4882a593Smuzhiyun u32 spb_num = (h + 127) >> 7;
23*4882a593Smuzhiyun u32 left_height = h & 127;
24*4882a593Smuzhiyun u32 mesh_width = mode ? (w / 32 + 1) : (w / 16 + 1);
25*4882a593Smuzhiyun u32 mesh_height = mode ? 9 : 17;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun if (!left_height)
28*4882a593Smuzhiyun left_height = 128;
29*4882a593Smuzhiyun mesh_left_height = mode ? (left_height / 16 + 1) :
30*4882a593Smuzhiyun (left_height / 8 + 1);
31*4882a593Smuzhiyun mesh_size = (spb_num - 1) * mesh_width * mesh_height +
32*4882a593Smuzhiyun mesh_width * mesh_left_height;
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun return mesh_size;
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static const struct isppsd_fmt rkispp_formats[] = {
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
40*4882a593Smuzhiyun .fourcc = V4L2_PIX_FMT_NV16,
41*4882a593Smuzhiyun .wr_fmt = FMT_YUV422,
42*4882a593Smuzhiyun },
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun
find_fmt(u32 mbus_code)45*4882a593Smuzhiyun static const struct isppsd_fmt *find_fmt(u32 mbus_code)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun const struct isppsd_fmt *fmt;
48*4882a593Smuzhiyun int i, array_size = ARRAY_SIZE(rkispp_formats);
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun for (i = 0; i < array_size; i++) {
51*4882a593Smuzhiyun fmt = &rkispp_formats[i];
52*4882a593Smuzhiyun if (fmt->mbus_code == mbus_code)
53*4882a593Smuzhiyun return fmt;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun return NULL;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
rkispp_subdev_link_setup(struct media_entity * entity,const struct media_pad * local,const struct media_pad * remote,u32 flags)59*4882a593Smuzhiyun static int rkispp_subdev_link_setup(struct media_entity *entity,
60*4882a593Smuzhiyun const struct media_pad *local,
61*4882a593Smuzhiyun const struct media_pad *remote,
62*4882a593Smuzhiyun u32 flags)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
65*4882a593Smuzhiyun struct rkispp_subdev *ispp_sdev;
66*4882a593Smuzhiyun struct rkispp_device *dev;
67*4882a593Smuzhiyun struct rkispp_stream_vdev *vdev;
68*4882a593Smuzhiyun struct rkispp_stream *stream = NULL;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun if (local->index != RKISPP_PAD_SINK &&
71*4882a593Smuzhiyun local->index != RKISPP_PAD_SOURCE)
72*4882a593Smuzhiyun return 0;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun if (!sd)
75*4882a593Smuzhiyun return -ENODEV;
76*4882a593Smuzhiyun ispp_sdev = v4l2_get_subdevdata(sd);
77*4882a593Smuzhiyun dev = ispp_sdev->dev;
78*4882a593Smuzhiyun vdev = &dev->stream_vdev;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if (!strcmp(remote->entity->name, II_VDEV_NAME)) {
81*4882a593Smuzhiyun stream = &vdev->stream[STREAM_II];
82*4882a593Smuzhiyun if (ispp_sdev->state & ISPP_START)
83*4882a593Smuzhiyun return -EBUSY;
84*4882a593Smuzhiyun if (flags & MEDIA_LNK_FL_ENABLED)
85*4882a593Smuzhiyun dev->inp = INP_DDR;
86*4882a593Smuzhiyun else if (ispp_sdev->remote_sd)
87*4882a593Smuzhiyun dev->inp = INP_ISP;
88*4882a593Smuzhiyun else
89*4882a593Smuzhiyun dev->inp = INP_INVAL;
90*4882a593Smuzhiyun stream->linked = flags & MEDIA_LNK_FL_ENABLED;
91*4882a593Smuzhiyun v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
92*4882a593Smuzhiyun "input:%d\n", dev->inp);
93*4882a593Smuzhiyun } else if (!strcmp(remote->entity->name, MB_VDEV_NAME)) {
94*4882a593Smuzhiyun stream = &vdev->stream[STREAM_MB];
95*4882a593Smuzhiyun } else if (!strcmp(remote->entity->name, S0_VDEV_NAME)) {
96*4882a593Smuzhiyun stream = &vdev->stream[STREAM_S0];
97*4882a593Smuzhiyun } else if (!strcmp(remote->entity->name, S1_VDEV_NAME)) {
98*4882a593Smuzhiyun stream = &vdev->stream[STREAM_S1];
99*4882a593Smuzhiyun } else if (!strcmp(remote->entity->name, S2_VDEV_NAME)) {
100*4882a593Smuzhiyun stream = &vdev->stream[STREAM_S2];
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun if (stream && dev->stream_sync) {
103*4882a593Smuzhiyun stream->linked = flags & MEDIA_LNK_FL_ENABLED;
104*4882a593Smuzhiyun v4l2_dbg(1, rkispp_debug, &dev->v4l2_dev,
105*4882a593Smuzhiyun "stream:%d linked:%d\n",
106*4882a593Smuzhiyun stream->id, stream->linked);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
rkispp_sd_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)111*4882a593Smuzhiyun static int rkispp_sd_get_fmt(struct v4l2_subdev *sd,
112*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
113*4882a593Smuzhiyun struct v4l2_subdev_format *fmt)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
116*4882a593Smuzhiyun struct v4l2_mbus_framefmt *mf;
117*4882a593Smuzhiyun const struct isppsd_fmt *ispp_fmt;
118*4882a593Smuzhiyun int ret = 0;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (!fmt)
121*4882a593Smuzhiyun goto err;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (fmt->pad != RKISPP_PAD_SINK &&
124*4882a593Smuzhiyun fmt->pad != RKISPP_PAD_SOURCE)
125*4882a593Smuzhiyun goto err;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun mf = &fmt->format;
128*4882a593Smuzhiyun if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
129*4882a593Smuzhiyun if (!cfg)
130*4882a593Smuzhiyun goto err;
131*4882a593Smuzhiyun mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun *mf = ispp_sdev->in_fmt;
135*4882a593Smuzhiyun if (fmt->pad == RKISPP_PAD_SINK && ispp_sdev->dev->inp == INP_ISP) {
136*4882a593Smuzhiyun ret = v4l2_subdev_call(ispp_sdev->remote_sd,
137*4882a593Smuzhiyun pad, get_fmt, cfg, fmt);
138*4882a593Smuzhiyun if (!ret) {
139*4882a593Smuzhiyun ispp_fmt = find_fmt(fmt->format.code);
140*4882a593Smuzhiyun if (!ispp_fmt)
141*4882a593Smuzhiyun goto err;
142*4882a593Smuzhiyun if (ispp_sdev->in_fmt.width != mf->width ||
143*4882a593Smuzhiyun ispp_sdev->in_fmt.height != mf->height) {
144*4882a593Smuzhiyun ispp_sdev->out_fmt = *ispp_fmt;
145*4882a593Smuzhiyun ispp_sdev->out_fmt.width = mf->width;
146*4882a593Smuzhiyun ispp_sdev->out_fmt.height = mf->height;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun ispp_sdev->in_fmt = *mf;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun } else {
151*4882a593Smuzhiyun *mf = ispp_sdev->in_fmt;
152*4882a593Smuzhiyun mf->width = ispp_sdev->out_fmt.width;
153*4882a593Smuzhiyun mf->height = ispp_sdev->out_fmt.height;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun return ret;
156*4882a593Smuzhiyun err:
157*4882a593Smuzhiyun return -EINVAL;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
rkispp_sd_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)160*4882a593Smuzhiyun static int rkispp_sd_set_fmt(struct v4l2_subdev *sd,
161*4882a593Smuzhiyun struct v4l2_subdev_pad_config *cfg,
162*4882a593Smuzhiyun struct v4l2_subdev_format *fmt)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
165*4882a593Smuzhiyun struct v4l2_mbus_framefmt *mf;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (!fmt)
168*4882a593Smuzhiyun return -EINVAL;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun /* format from isp output */
171*4882a593Smuzhiyun if (fmt->pad == RKISPP_PAD_SINK && ispp_sdev->dev->inp == INP_ISP)
172*4882a593Smuzhiyun return 0;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun mf = &fmt->format;
175*4882a593Smuzhiyun if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
176*4882a593Smuzhiyun if (!cfg)
177*4882a593Smuzhiyun return -EINVAL;
178*4882a593Smuzhiyun mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (fmt->pad == RKISPP_PAD_SINK) {
182*4882a593Smuzhiyun ispp_sdev->in_fmt = *mf;
183*4882a593Smuzhiyun } else {
184*4882a593Smuzhiyun ispp_sdev->out_fmt.width = mf->width;
185*4882a593Smuzhiyun ispp_sdev->out_fmt.height = mf->height;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun return 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
rkispp_sd_s_stream(struct v4l2_subdev * sd,int on)191*4882a593Smuzhiyun static int rkispp_sd_s_stream(struct v4l2_subdev *sd, int on)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
194*4882a593Smuzhiyun struct rkispp_device *dev = ispp_sdev->dev;
195*4882a593Smuzhiyun int ret = 0;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun v4l2_dbg(1, rkispp_debug, &ispp_sdev->dev->v4l2_dev,
198*4882a593Smuzhiyun "s_stream on:%d\n", on);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun if (on) {
201*4882a593Smuzhiyun ispp_sdev->state = ISPP_START;
202*4882a593Smuzhiyun ispp_sdev->frm_sync_seq = -1;
203*4882a593Smuzhiyun ispp_sdev->frame_timestamp = 0;
204*4882a593Smuzhiyun rkispp_event_handle(dev, CMD_STREAM, &ispp_sdev->state);
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (dev->inp == INP_ISP)
208*4882a593Smuzhiyun ret = v4l2_subdev_call(ispp_sdev->remote_sd, video, s_stream, on);
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if ((on && ret) || (!on && !ret)) {
211*4882a593Smuzhiyun ispp_sdev->state = ISPP_STOP;
212*4882a593Smuzhiyun if (dev->stream_vdev.monitor.is_en) {
213*4882a593Smuzhiyun dev->stream_vdev.monitor.is_en = false;
214*4882a593Smuzhiyun if (!completion_done(&dev->stream_vdev.monitor.cmpl))
215*4882a593Smuzhiyun complete(&dev->stream_vdev.monitor.cmpl);
216*4882a593Smuzhiyun if (!completion_done(&dev->stream_vdev.monitor.tnr.cmpl))
217*4882a593Smuzhiyun complete(&dev->stream_vdev.monitor.tnr.cmpl);
218*4882a593Smuzhiyun if (!completion_done(&dev->stream_vdev.monitor.nr.cmpl))
219*4882a593Smuzhiyun complete(&dev->stream_vdev.monitor.nr.cmpl);
220*4882a593Smuzhiyun if (!completion_done(&dev->stream_vdev.monitor.fec.cmpl))
221*4882a593Smuzhiyun complete(&dev->stream_vdev.monitor.fec.cmpl);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun rkispp_event_handle(dev, CMD_STREAM, &ispp_sdev->state);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun return ret;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
rkispp_sd_s_rx_buffer(struct v4l2_subdev * sd,void * buf,unsigned int * size)228*4882a593Smuzhiyun static int rkispp_sd_s_rx_buffer(struct v4l2_subdev *sd,
229*4882a593Smuzhiyun void *buf, unsigned int *size)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
232*4882a593Smuzhiyun struct rkispp_device *dev = ispp_sdev->dev;
233*4882a593Smuzhiyun u32 cmd = CMD_INIT_POOL;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /* size isn't using now */
236*4882a593Smuzhiyun if (!buf)
237*4882a593Smuzhiyun return -EINVAL;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun if (ispp_sdev->state == ISPP_START) {
240*4882a593Smuzhiyun struct rkisp_ispp_buf *dbufs = buf;
241*4882a593Smuzhiyun struct rkispp_stream_vdev *vdev = &dev->stream_vdev;
242*4882a593Smuzhiyun u64 ns = ktime_get_ns();
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun vdev->dbg.interval = ns - vdev->dbg.timestamp;
245*4882a593Smuzhiyun vdev->dbg.timestamp = ns;
246*4882a593Smuzhiyun vdev->dbg.delay = ns - dbufs->frame_timestamp;
247*4882a593Smuzhiyun vdev->dbg.id = dbufs->frame_id;
248*4882a593Smuzhiyun cmd = CMD_QUEUE_DMABUF;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return rkispp_event_handle(dev, cmd, buf);
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
rkispp_sd_s_power(struct v4l2_subdev * sd,int on)254*4882a593Smuzhiyun static int rkispp_sd_s_power(struct v4l2_subdev *sd, int on)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
257*4882a593Smuzhiyun struct rkispp_device *ispp_dev = ispp_sdev->dev;
258*4882a593Smuzhiyun int ret;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun v4l2_dbg(1, rkispp_debug, &ispp_dev->v4l2_dev,
261*4882a593Smuzhiyun "s_power on:%d\n", on);
262*4882a593Smuzhiyun if (on) {
263*4882a593Smuzhiyun if (ispp_dev->inp == INP_ISP) {
264*4882a593Smuzhiyun struct v4l2_subdev_format fmt;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /* update format, if ispp input change */
267*4882a593Smuzhiyun fmt.pad = RKISPP_PAD_SINK;
268*4882a593Smuzhiyun fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
269*4882a593Smuzhiyun ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt);
270*4882a593Smuzhiyun if (ret) {
271*4882a593Smuzhiyun v4l2_err(&ispp_dev->v4l2_dev,
272*4882a593Smuzhiyun "%s get format fail:%d\n",
273*4882a593Smuzhiyun __func__, ret);
274*4882a593Smuzhiyun return ret;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun ret = v4l2_subdev_call(ispp_sdev->remote_sd,
278*4882a593Smuzhiyun core, s_power, 1);
279*4882a593Smuzhiyun if (ret < 0) {
280*4882a593Smuzhiyun v4l2_err(&ispp_dev->v4l2_dev,
281*4882a593Smuzhiyun "%s set isp power on fail:%d\n",
282*4882a593Smuzhiyun __func__, ret);
283*4882a593Smuzhiyun return ret;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun ret = pm_runtime_get_sync(ispp_dev->dev);
287*4882a593Smuzhiyun if (ret < 0) {
288*4882a593Smuzhiyun v4l2_err(&ispp_dev->v4l2_dev,
289*4882a593Smuzhiyun "%s runtime get failed:%d\n",
290*4882a593Smuzhiyun __func__, ret);
291*4882a593Smuzhiyun if (ispp_dev->inp == INP_ISP)
292*4882a593Smuzhiyun v4l2_subdev_call(ispp_sdev->remote_sd,
293*4882a593Smuzhiyun core, s_power, 0);
294*4882a593Smuzhiyun return ret;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun } else {
297*4882a593Smuzhiyun if (ispp_dev->inp == INP_ISP)
298*4882a593Smuzhiyun v4l2_subdev_call(ispp_sdev->remote_sd, core, s_power, 0);
299*4882a593Smuzhiyun ret = pm_runtime_put_sync(ispp_dev->dev);
300*4882a593Smuzhiyun if (ret < 0)
301*4882a593Smuzhiyun v4l2_err(&ispp_dev->v4l2_dev,
302*4882a593Smuzhiyun "%s runtime put failed:%d\n",
303*4882a593Smuzhiyun __func__, ret);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun return ret;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
rkispp_ioctl(struct v4l2_subdev * sd,unsigned int cmd,void * arg)309*4882a593Smuzhiyun static long rkispp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun struct rkispp_subdev *ispp_sdev = v4l2_get_subdevdata(sd);
312*4882a593Smuzhiyun struct rkispp_device *ispp_dev = ispp_sdev->dev;
313*4882a593Smuzhiyun struct rkispp_fecbuf_info *fecbuf;
314*4882a593Smuzhiyun struct rkispp_fecbuf_size *fecsize;
315*4882a593Smuzhiyun struct rkisp_ispp_reg **reg_buf;
316*4882a593Smuzhiyun bool *rkispp_reg_withstream;
317*4882a593Smuzhiyun long ret = 0;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (!arg)
320*4882a593Smuzhiyun return -EINVAL;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun switch (cmd) {
323*4882a593Smuzhiyun case RKISPP_CMD_SET_INIT_MODULE:
324*4882a593Smuzhiyun ispp_dev->stream_vdev.module_ens = *((int *)arg);
325*4882a593Smuzhiyun if (ispp_dev->hw_dev->is_fec_ext)
326*4882a593Smuzhiyun ispp_dev->stream_vdev.module_ens &= ~ISPP_MODULE_FEC_ST;
327*4882a593Smuzhiyun break;
328*4882a593Smuzhiyun case RKISPP_CMD_GET_FECBUF_INFO:
329*4882a593Smuzhiyun fecbuf = (struct rkispp_fecbuf_info *)arg;
330*4882a593Smuzhiyun rkispp_params_get_fecbuf_inf(&ispp_dev->params_vdev[PARAM_VDEV_FEC], fecbuf);
331*4882a593Smuzhiyun break;
332*4882a593Smuzhiyun case RKISPP_CMD_SET_FECBUF_SIZE:
333*4882a593Smuzhiyun fecsize = (struct rkispp_fecbuf_size *)arg;
334*4882a593Smuzhiyun rkispp_params_set_fecbuf_size(&ispp_dev->params_vdev[PARAM_VDEV_FEC], fecsize);
335*4882a593Smuzhiyun break;
336*4882a593Smuzhiyun case RKISP_ISPP_CMD_REQUEST_REGBUF:
337*4882a593Smuzhiyun reg_buf = (struct rkisp_ispp_reg **)arg;
338*4882a593Smuzhiyun rkispp_request_regbuf(ispp_dev, reg_buf);
339*4882a593Smuzhiyun break;
340*4882a593Smuzhiyun case RKISP_ISPP_CMD_GET_REG_WITHSTREAM:
341*4882a593Smuzhiyun rkispp_reg_withstream = arg;
342*4882a593Smuzhiyun *rkispp_reg_withstream = rkispp_is_reg_withstream_global();
343*4882a593Smuzhiyun break;
344*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_ISPP_VERSION_V10)
345*4882a593Smuzhiyun case RKISPP_CMD_GET_TNRBUF_FD:
346*4882a593Smuzhiyun ret = rkispp_get_tnrbuf_fd(ispp_dev, (struct rkispp_buf_idxfd *)arg);
347*4882a593Smuzhiyun break;
348*4882a593Smuzhiyun case RKISPP_CMD_GET_NRBUF_FD:
349*4882a593Smuzhiyun ret = rkispp_get_nrbuf_fd(ispp_dev, (struct rkispp_buf_idxfd *)arg);
350*4882a593Smuzhiyun break;
351*4882a593Smuzhiyun case RKISPP_CMD_TRIGGER_MODE:
352*4882a593Smuzhiyun rkispp_set_trigger_mode(ispp_dev, (struct rkispp_trigger_mode *)arg);
353*4882a593Smuzhiyun break;
354*4882a593Smuzhiyun #endif
355*4882a593Smuzhiyun default:
356*4882a593Smuzhiyun ret = -ENOIOCTLCMD;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun return ret;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
rkispp_compat_ioctl32(struct v4l2_subdev * sd,unsigned int cmd,unsigned long arg)363*4882a593Smuzhiyun static long rkispp_compat_ioctl32(struct v4l2_subdev *sd,
364*4882a593Smuzhiyun unsigned int cmd, unsigned long arg)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun void __user *up = compat_ptr(arg);
367*4882a593Smuzhiyun struct rkispp_fecbuf_info fecbuf;
368*4882a593Smuzhiyun struct rkispp_fecbuf_size fecsize;
369*4882a593Smuzhiyun struct rkispp_buf_idxfd idxfd;
370*4882a593Smuzhiyun struct rkispp_trigger_mode t_mode;
371*4882a593Smuzhiyun long ret = 0;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (!up)
374*4882a593Smuzhiyun return -EINVAL;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun switch (cmd) {
377*4882a593Smuzhiyun case RKISPP_CMD_GET_FECBUF_INFO:
378*4882a593Smuzhiyun ret = rkispp_ioctl(sd, cmd, &fecbuf);
379*4882a593Smuzhiyun if (!ret && copy_to_user(up, &fecbuf, sizeof(fecbuf)))
380*4882a593Smuzhiyun ret = -EFAULT;
381*4882a593Smuzhiyun break;
382*4882a593Smuzhiyun case RKISPP_CMD_SET_FECBUF_SIZE:
383*4882a593Smuzhiyun if (copy_from_user(&fecsize, up, sizeof(fecsize)))
384*4882a593Smuzhiyun return -EFAULT;
385*4882a593Smuzhiyun ret = rkispp_ioctl(sd, cmd, &fecsize);
386*4882a593Smuzhiyun break;
387*4882a593Smuzhiyun case RKISPP_CMD_GET_TNRBUF_FD:
388*4882a593Smuzhiyun case RKISPP_CMD_GET_NRBUF_FD:
389*4882a593Smuzhiyun ret = rkispp_ioctl(sd, cmd, &idxfd);
390*4882a593Smuzhiyun if (!ret && copy_to_user(up, &idxfd, sizeof(idxfd)))
391*4882a593Smuzhiyun ret = -EFAULT;
392*4882a593Smuzhiyun break;
393*4882a593Smuzhiyun case RKISPP_CMD_TRIGGER_MODE:
394*4882a593Smuzhiyun if (copy_from_user(&t_mode, up, sizeof(t_mode)))
395*4882a593Smuzhiyun return -EFAULT;
396*4882a593Smuzhiyun ret = rkispp_ioctl(sd, cmd, &t_mode);
397*4882a593Smuzhiyun break;
398*4882a593Smuzhiyun default:
399*4882a593Smuzhiyun ret = -ENOIOCTLCMD;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun return ret;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun #endif
405*4882a593Smuzhiyun
rkispp_subscribe_event(struct v4l2_subdev * sd,struct v4l2_fh * fh,struct v4l2_event_subscription * sub)406*4882a593Smuzhiyun static int rkispp_subscribe_event(struct v4l2_subdev *sd,
407*4882a593Smuzhiyun struct v4l2_fh *fh,
408*4882a593Smuzhiyun struct v4l2_event_subscription *sub)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun switch (sub->type) {
411*4882a593Smuzhiyun case RKISPP_V4L2_EVENT_TNR_COMPLETE:
412*4882a593Smuzhiyun return v4l2_event_subscribe(fh, sub, RKISPP_BUF_MAX, NULL);
413*4882a593Smuzhiyun default:
414*4882a593Smuzhiyun return -EINVAL;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun static const struct media_entity_operations rkispp_sd_media_ops = {
419*4882a593Smuzhiyun .link_setup = rkispp_subdev_link_setup,
420*4882a593Smuzhiyun .link_validate = v4l2_subdev_link_validate,
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun static const struct v4l2_subdev_pad_ops rkispp_sd_pad_ops = {
424*4882a593Smuzhiyun .get_fmt = rkispp_sd_get_fmt,
425*4882a593Smuzhiyun .set_fmt = rkispp_sd_set_fmt,
426*4882a593Smuzhiyun };
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun static const struct v4l2_subdev_video_ops rkispp_sd_video_ops = {
429*4882a593Smuzhiyun .s_stream = rkispp_sd_s_stream,
430*4882a593Smuzhiyun .s_rx_buffer = rkispp_sd_s_rx_buffer,
431*4882a593Smuzhiyun };
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun static const struct v4l2_subdev_core_ops rkispp_sd_core_ops = {
434*4882a593Smuzhiyun .s_power = rkispp_sd_s_power,
435*4882a593Smuzhiyun .ioctl = rkispp_ioctl,
436*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
437*4882a593Smuzhiyun .compat_ioctl32 = rkispp_compat_ioctl32,
438*4882a593Smuzhiyun #endif
439*4882a593Smuzhiyun .subscribe_event = rkispp_subscribe_event,
440*4882a593Smuzhiyun .unsubscribe_event = v4l2_event_subdev_unsubscribe,
441*4882a593Smuzhiyun };
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun static struct v4l2_subdev_ops rkispp_sd_ops = {
444*4882a593Smuzhiyun .core = &rkispp_sd_core_ops,
445*4882a593Smuzhiyun .video = &rkispp_sd_video_ops,
446*4882a593Smuzhiyun .pad = &rkispp_sd_pad_ops,
447*4882a593Smuzhiyun };
448*4882a593Smuzhiyun
rkispp_register_subdev(struct rkispp_device * dev,struct v4l2_device * v4l2_dev)449*4882a593Smuzhiyun int rkispp_register_subdev(struct rkispp_device *dev,
450*4882a593Smuzhiyun struct v4l2_device *v4l2_dev)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun struct rkispp_subdev *ispp_sdev = &dev->ispp_sdev;
453*4882a593Smuzhiyun struct v4l2_subdev *sd;
454*4882a593Smuzhiyun int ret;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun memset(ispp_sdev, 0, sizeof(*ispp_sdev));
457*4882a593Smuzhiyun ispp_sdev->dev = dev;
458*4882a593Smuzhiyun sd = &ispp_sdev->sd;
459*4882a593Smuzhiyun ispp_sdev->state = ISPP_STOP;
460*4882a593Smuzhiyun v4l2_subdev_init(sd, &rkispp_sd_ops);
461*4882a593Smuzhiyun sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
462*4882a593Smuzhiyun sd->entity.ops = &rkispp_sd_media_ops;
463*4882a593Smuzhiyun snprintf(sd->name, sizeof(sd->name), "rkispp-subdev");
464*4882a593Smuzhiyun sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_COMPOSER;
465*4882a593Smuzhiyun ispp_sdev->pads[RKISPP_PAD_SINK].flags =
466*4882a593Smuzhiyun MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
467*4882a593Smuzhiyun ispp_sdev->pads[RKISPP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK;
468*4882a593Smuzhiyun ispp_sdev->pads[RKISPP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
469*4882a593Smuzhiyun ispp_sdev->pads[RKISPP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun ret = media_entity_pads_init(&sd->entity, RKISPP_PAD_MAX,
472*4882a593Smuzhiyun ispp_sdev->pads);
473*4882a593Smuzhiyun if (ret < 0)
474*4882a593Smuzhiyun return ret;
475*4882a593Smuzhiyun sd->owner = THIS_MODULE;
476*4882a593Smuzhiyun v4l2_set_subdevdata(sd, ispp_sdev);
477*4882a593Smuzhiyun sd->grp_id = GRP_ID_ISPP;
478*4882a593Smuzhiyun ret = v4l2_device_register_subdev(v4l2_dev, sd);
479*4882a593Smuzhiyun if (ret < 0)
480*4882a593Smuzhiyun goto free_media;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun ret = v4l2_device_register_subdev_nodes(v4l2_dev);
483*4882a593Smuzhiyun if (ret < 0)
484*4882a593Smuzhiyun goto free_subdev;
485*4882a593Smuzhiyun return ret;
486*4882a593Smuzhiyun free_subdev:
487*4882a593Smuzhiyun v4l2_device_unregister_subdev(sd);
488*4882a593Smuzhiyun free_media:
489*4882a593Smuzhiyun media_entity_cleanup(&sd->entity);
490*4882a593Smuzhiyun v4l2_err(sd, "Failed to register subdev, ret:%d\n", ret);
491*4882a593Smuzhiyun return ret;
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun
rkispp_unregister_subdev(struct rkispp_device * dev)494*4882a593Smuzhiyun void rkispp_unregister_subdev(struct rkispp_device *dev)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun struct v4l2_subdev *sd = &dev->ispp_sdev.sd;
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun v4l2_device_unregister_subdev(sd);
499*4882a593Smuzhiyun media_entity_cleanup(&sd->entity);
500*4882a593Smuzhiyun }
501