[media] v4l: vsp1: Store active selection rectangles in a pad config structure
[deliverable/linux.git] / drivers / media / platform / vsp1 / vsp1_rpf.c
CommitLineData
26e0ca22
LP
1/*
2 * vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter
3 *
8a1edc55 4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
26e0ca22
LP
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
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.
12 */
13
14#include <linux/device.h>
15
16#include <media/v4l2-subdev.h>
17
18#include "vsp1.h"
19#include "vsp1_rwpf.h"
20#include "vsp1_video.h"
21
22#define RPF_MAX_WIDTH 8190
23#define RPF_MAX_HEIGHT 8190
24
25/* -----------------------------------------------------------------------------
26 * Device Access
27 */
28
26e0ca22
LP
29static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
30{
1517b039
TS
31 vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET,
32 data);
26e0ca22
LP
33}
34
35/* -----------------------------------------------------------------------------
36 * V4L2 Subdevice Core Operations
37 */
38
39static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
40{
3dbb6100 41 struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
26e0ca22 42 struct vsp1_rwpf *rpf = to_rwpf(subdev);
86960eec
LP
43 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
44 const struct v4l2_pix_format_mplane *format = &rpf->format;
e790c3cb
LP
45 const struct v4l2_mbus_framefmt *source_format;
46 const struct v4l2_mbus_framefmt *sink_format;
b7e5107e
LP
47 const struct v4l2_rect *crop;
48 unsigned int left = 0;
49 unsigned int top = 0;
26e0ca22
LP
50 u32 pstride;
51 u32 infmt;
7578c204 52
26e0ca22
LP
53 if (!enable)
54 return 0;
55
e5ad37b6
LP
56 /* Source size, stride and crop offsets.
57 *
58 * The crop offsets correspond to the location of the crop rectangle top
59 * left corner in the plane buffer. Only two offsets are needed, as
60 * planes 2 and 3 always have identical strides.
61 */
b7e5107e
LP
62 crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
63
26e0ca22 64 vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
e5ad37b6
LP
65 (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
66 (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
26e0ca22 67 vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
e5ad37b6
LP
68 (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
69 (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
26e0ca22 70
e5ad37b6
LP
71 rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
72 + crop->left * fmtinfo->bpp[0] / 8;
26e0ca22
LP
73 pstride = format->plane_fmt[0].bytesperline
74 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
857161fc 75
e5ad37b6
LP
76 if (format->num_planes > 1) {
77 rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
78 + crop->left * fmtinfo->bpp[1] / 8;
26e0ca22
LP
79 pstride |= format->plane_fmt[1].bytesperline
80 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
4d346be5
LP
81 } else {
82 rpf->offsets[1] = 0;
e5ad37b6 83 }
26e0ca22
LP
84
85 vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
86
87 /* Format */
e790c3cb
LP
88 sink_format = vsp1_entity_get_pad_format(&rpf->entity,
89 rpf->entity.config,
90 RWPF_PAD_SINK);
91 source_format = vsp1_entity_get_pad_format(&rpf->entity,
92 rpf->entity.config,
93 RWPF_PAD_SOURCE);
94
26e0ca22
LP
95 infmt = VI6_RPF_INFMT_CIPM
96 | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
97
98 if (fmtinfo->swap_yc)
99 infmt |= VI6_RPF_INFMT_SPYCS;
100 if (fmtinfo->swap_uv)
101 infmt |= VI6_RPF_INFMT_SPUVS;
102
e790c3cb 103 if (sink_format->code != source_format->code)
26e0ca22
LP
104 infmt |= VI6_RPF_INFMT_CSC;
105
106 vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
107 vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
108
629bb6d4 109 /* Output location */
b7e5107e
LP
110 if (pipe->bru) {
111 const struct v4l2_rect *compose;
112
113 compose = vsp1_entity_get_pad_compose(pipe->bru,
114 pipe->bru->config,
115 rpf->bru_input);
116 left = compose->left;
117 top = compose->top;
118 }
119
629bb6d4 120 vsp1_rpf_write(rpf, VI6_RPF_LOC,
b7e5107e
LP
121 (left << VI6_RPF_LOC_HCOORD_SHIFT) |
122 (top << VI6_RPF_LOC_VCOORD_SHIFT));
26e0ca22 123
7578c204
LP
124 /* Use the alpha channel (extended to 8 bits) when available or an
125 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
126 * otherwise. Disable color keying.
26e0ca22 127 */
7a52b6de
LP
128 vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
129 (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
130 : VI6_RPF_ALPH_SEL_ASEL_FIXED));
3dbb6100 131
3dbb6100 132 vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
bd2fdd5a
LP
133 rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
134
135 vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha);
3dbb6100 136
26e0ca22
LP
137 vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
138 vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
139
140 return 0;
141}
142
143/* -----------------------------------------------------------------------------
144 * V4L2 Subdevice Operations
145 */
146
147static struct v4l2_subdev_video_ops rpf_video_ops = {
148 .s_stream = rpf_s_stream,
149};
150
151static struct v4l2_subdev_pad_ops rpf_pad_ops = {
0efdf0f5 152 .init_cfg = vsp1_entity_init_cfg,
26e0ca22
LP
153 .enum_mbus_code = vsp1_rwpf_enum_mbus_code,
154 .enum_frame_size = vsp1_rwpf_enum_frame_size,
155 .get_fmt = vsp1_rwpf_get_format,
156 .set_fmt = vsp1_rwpf_set_format,
e5ad37b6
LP
157 .get_selection = vsp1_rwpf_get_selection,
158 .set_selection = vsp1_rwpf_set_selection,
26e0ca22
LP
159};
160
161static struct v4l2_subdev_ops rpf_ops = {
162 .video = &rpf_video_ops,
163 .pad = &rpf_pad_ops,
164};
165
166/* -----------------------------------------------------------------------------
52434534 167 * VSP1 Entity Operations
26e0ca22
LP
168 */
169
52434534 170static void rpf_set_memory(struct vsp1_entity *entity)
26e0ca22 171{
52434534
LP
172 struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
173
e5ad37b6 174 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
351bbf99 175 rpf->mem.addr[0] + rpf->offsets[0]);
4d346be5 176 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
351bbf99 177 rpf->mem.addr[1] + rpf->offsets[1]);
4d346be5 178 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
351bbf99 179 rpf->mem.addr[2] + rpf->offsets[1]);
26e0ca22
LP
180}
181
52434534 182static const struct vsp1_entity_operations rpf_entity_ops = {
b58faa95 183 .set_memory = rpf_set_memory,
26e0ca22
LP
184};
185
186/* -----------------------------------------------------------------------------
187 * Initialization and Cleanup
188 */
189
190struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
191{
26e0ca22 192 struct vsp1_rwpf *rpf;
823329df 193 char name[6];
26e0ca22
LP
194 int ret;
195
196 rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
197 if (rpf == NULL)
198 return ERR_PTR(-ENOMEM);
199
200 rpf->max_width = RPF_MAX_WIDTH;
201 rpf->max_height = RPF_MAX_HEIGHT;
202
52434534 203 rpf->entity.ops = &rpf_entity_ops;
26e0ca22
LP
204 rpf->entity.type = VSP1_ENTITY_RPF;
205 rpf->entity.index = index;
26e0ca22 206
823329df
LP
207 sprintf(name, "rpf.%u", index);
208 ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
26e0ca22
LP
209 if (ret < 0)
210 return ERR_PTR(ret);
211
7578c204 212 /* Initialize the control handler. */
bd2fdd5a
LP
213 ret = vsp1_rwpf_init_ctrls(rpf);
214 if (ret < 0) {
7578c204
LP
215 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
216 index);
7578c204
LP
217 goto error;
218 }
219
26e0ca22
LP
220 return rpf;
221
1499be67
LP
222error:
223 vsp1_entity_destroy(&rpf->entity);
26e0ca22
LP
224 return ERR_PTR(ret);
225}
This page took 0.150733 seconds and 5 git commands to generate.