2 * vsp1_wpf.c -- R-Car VSP1 Write Pixel Formatter
4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
14 #include <linux/device.h>
16 #include <media/v4l2-subdev.h>
19 #include "vsp1_rwpf.h"
20 #include "vsp1_video.h"
22 #define WPF_MAX_WIDTH 2048
23 #define WPF_MAX_HEIGHT 2048
25 /* -----------------------------------------------------------------------------
29 static inline u32
vsp1_wpf_read(struct vsp1_rwpf
*wpf
, u32 reg
)
31 return vsp1_read(wpf
->entity
.vsp1
,
32 reg
+ wpf
->entity
.index
* VI6_WPF_OFFSET
);
35 static inline void vsp1_wpf_write(struct vsp1_rwpf
*wpf
, u32 reg
, u32 data
)
37 vsp1_write(wpf
->entity
.vsp1
,
38 reg
+ wpf
->entity
.index
* VI6_WPF_OFFSET
, data
);
41 /* -----------------------------------------------------------------------------
45 static int wpf_s_ctrl(struct v4l2_ctrl
*ctrl
)
47 struct vsp1_rwpf
*wpf
=
48 container_of(ctrl
->handler
, struct vsp1_rwpf
, ctrls
);
51 if (!vsp1_entity_is_streaming(&wpf
->entity
))
55 case V4L2_CID_ALPHA_COMPONENT
:
56 value
= vsp1_wpf_read(wpf
, VI6_WPF_OUTFMT
);
57 value
&= ~VI6_WPF_OUTFMT_PDV_MASK
;
58 value
|= ctrl
->val
<< VI6_WPF_OUTFMT_PDV_SHIFT
;
59 vsp1_wpf_write(wpf
, VI6_WPF_OUTFMT
, value
);
66 static const struct v4l2_ctrl_ops wpf_ctrl_ops
= {
70 /* -----------------------------------------------------------------------------
71 * V4L2 Subdevice Core Operations
74 static int wpf_s_stream(struct v4l2_subdev
*subdev
, int enable
)
76 struct vsp1_pipeline
*pipe
= to_vsp1_pipeline(&subdev
->entity
);
77 struct vsp1_rwpf
*wpf
= to_rwpf(subdev
);
78 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
79 const struct v4l2_rect
*crop
= &wpf
->crop
;
85 ret
= vsp1_entity_set_streaming(&wpf
->entity
, enable
);
90 vsp1_write(vsp1
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
), 0);
91 vsp1_wpf_write(wpf
, VI6_WPF_SRCRPF
, 0);
95 /* Sources. If the pipeline has a single input and BRU is not used,
96 * configure it as the master layer. Otherwise configure all
97 * inputs as sub-layers and select the virtual RPF as the master
100 for (i
= 0; i
< pipe
->num_inputs
; ++i
) {
101 struct vsp1_rwpf
*input
= pipe
->inputs
[i
];
103 srcrpf
|= (!pipe
->bru
&& pipe
->num_inputs
== 1)
104 ? VI6_WPF_SRCRPF_RPF_ACT_MST(input
->entity
.index
)
105 : VI6_WPF_SRCRPF_RPF_ACT_SUB(input
->entity
.index
);
108 if (pipe
->bru
|| pipe
->num_inputs
> 1)
109 srcrpf
|= VI6_WPF_SRCRPF_VIRACT_MST
;
111 vsp1_wpf_write(wpf
, VI6_WPF_SRCRPF
, srcrpf
);
113 /* Destination stride. */
115 struct v4l2_pix_format_mplane
*format
= &wpf
->format
;
117 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_STRIDE_Y
,
118 format
->plane_fmt
[0].bytesperline
);
119 if (format
->num_planes
> 1)
120 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_STRIDE_C
,
121 format
->plane_fmt
[1].bytesperline
);
124 vsp1_wpf_write(wpf
, VI6_WPF_HSZCLIP
, VI6_WPF_SZCLIP_EN
|
125 (crop
->left
<< VI6_WPF_SZCLIP_OFST_SHIFT
) |
126 (crop
->width
<< VI6_WPF_SZCLIP_SIZE_SHIFT
));
127 vsp1_wpf_write(wpf
, VI6_WPF_VSZCLIP
, VI6_WPF_SZCLIP_EN
|
128 (crop
->top
<< VI6_WPF_SZCLIP_OFST_SHIFT
) |
129 (crop
->height
<< VI6_WPF_SZCLIP_SIZE_SHIFT
));
133 const struct vsp1_format_info
*fmtinfo
= wpf
->fmtinfo
;
135 outfmt
= fmtinfo
->hwfmt
<< VI6_WPF_OUTFMT_WRFMT_SHIFT
;
138 outfmt
|= VI6_WPF_OUTFMT_PXA
;
139 if (fmtinfo
->swap_yc
)
140 outfmt
|= VI6_WPF_OUTFMT_SPYCS
;
141 if (fmtinfo
->swap_uv
)
142 outfmt
|= VI6_WPF_OUTFMT_SPUVS
;
144 vsp1_wpf_write(wpf
, VI6_WPF_DSWAP
, fmtinfo
->swap
);
147 if (wpf
->entity
.formats
[RWPF_PAD_SINK
].code
!=
148 wpf
->entity
.formats
[RWPF_PAD_SOURCE
].code
)
149 outfmt
|= VI6_WPF_OUTFMT_CSC
;
151 /* Take the control handler lock to ensure that the PDV value won't be
152 * changed behind our back by a set control operation.
154 mutex_lock(wpf
->ctrls
.lock
);
155 outfmt
|= vsp1_wpf_read(wpf
, VI6_WPF_OUTFMT
) & VI6_WPF_OUTFMT_PDV_MASK
;
156 vsp1_wpf_write(wpf
, VI6_WPF_OUTFMT
, outfmt
);
157 mutex_unlock(wpf
->ctrls
.lock
);
159 vsp1_write(vsp1
, VI6_DPR_WPF_FPORCH(wpf
->entity
.index
),
160 VI6_DPR_WPF_FPORCH_FP_WPFN
);
162 vsp1_write(vsp1
, VI6_WPF_WRBCK_CTRL
, 0);
164 /* Enable interrupts */
165 vsp1_write(vsp1
, VI6_WPF_IRQ_STA(wpf
->entity
.index
), 0);
166 vsp1_write(vsp1
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
),
167 VI6_WFP_IRQ_ENB_FREE
);
172 /* -----------------------------------------------------------------------------
173 * V4L2 Subdevice Operations
176 static struct v4l2_subdev_video_ops wpf_video_ops
= {
177 .s_stream
= wpf_s_stream
,
180 static struct v4l2_subdev_pad_ops wpf_pad_ops
= {
181 .enum_mbus_code
= vsp1_rwpf_enum_mbus_code
,
182 .enum_frame_size
= vsp1_rwpf_enum_frame_size
,
183 .get_fmt
= vsp1_rwpf_get_format
,
184 .set_fmt
= vsp1_rwpf_set_format
,
185 .get_selection
= vsp1_rwpf_get_selection
,
186 .set_selection
= vsp1_rwpf_set_selection
,
189 static struct v4l2_subdev_ops wpf_ops
= {
190 .video
= &wpf_video_ops
,
194 /* -----------------------------------------------------------------------------
195 * Video Device Operations
198 static void wpf_buf_queue(struct vsp1_rwpf
*wpf
, struct vsp1_video_buffer
*buf
)
200 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_Y
, buf
->addr
[0]);
201 if (buf
->buf
.vb2_buf
.num_planes
> 1)
202 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_C0
, buf
->addr
[1]);
203 if (buf
->buf
.vb2_buf
.num_planes
> 2)
204 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_C1
, buf
->addr
[2]);
207 static const struct vsp1_rwpf_operations wpf_vdev_ops
= {
208 .queue
= wpf_buf_queue
,
211 /* -----------------------------------------------------------------------------
212 * Initialization and Cleanup
215 struct vsp1_rwpf
*vsp1_wpf_create(struct vsp1_device
*vsp1
, unsigned int index
)
217 struct v4l2_subdev
*subdev
;
218 struct vsp1_video
*video
;
219 struct vsp1_rwpf
*wpf
;
222 wpf
= devm_kzalloc(vsp1
->dev
, sizeof(*wpf
), GFP_KERNEL
);
224 return ERR_PTR(-ENOMEM
);
226 wpf
->ops
= &wpf_vdev_ops
;
228 wpf
->max_width
= WPF_MAX_WIDTH
;
229 wpf
->max_height
= WPF_MAX_HEIGHT
;
231 wpf
->entity
.type
= VSP1_ENTITY_WPF
;
232 wpf
->entity
.index
= index
;
234 ret
= vsp1_entity_init(vsp1
, &wpf
->entity
, 2);
238 /* Initialize the V4L2 subdev. */
239 subdev
= &wpf
->entity
.subdev
;
240 v4l2_subdev_init(subdev
, &wpf_ops
);
242 subdev
->entity
.ops
= &vsp1_media_ops
;
243 subdev
->internal_ops
= &vsp1_subdev_internal_ops
;
244 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s wpf.%u",
245 dev_name(vsp1
->dev
), index
);
246 v4l2_set_subdevdata(subdev
, wpf
);
247 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
249 vsp1_entity_init_formats(subdev
, NULL
);
251 /* Initialize the control handler. */
252 v4l2_ctrl_handler_init(&wpf
->ctrls
, 1);
253 v4l2_ctrl_new_std(&wpf
->ctrls
, &wpf_ctrl_ops
, V4L2_CID_ALPHA_COMPONENT
,
256 wpf
->entity
.subdev
.ctrl_handler
= &wpf
->ctrls
;
258 if (wpf
->ctrls
.error
) {
259 dev_err(vsp1
->dev
, "wpf%u: failed to initialize controls\n",
261 ret
= wpf
->ctrls
.error
;
265 /* Initialize the video device. */
268 video
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
271 ret
= vsp1_video_init(video
, wpf
);
275 wpf
->entity
.video
= video
;
276 wpf
->entity
.sink
= &wpf
->video
.video
.entity
;
281 vsp1_entity_destroy(&wpf
->entity
);