2 * vsp1_rpf.c -- R-Car VSP1 Read 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>
20 #include "vsp1_pipe.h"
21 #include "vsp1_rwpf.h"
22 #include "vsp1_video.h"
24 #define RPF_MAX_WIDTH 8190
25 #define RPF_MAX_HEIGHT 8190
27 /* -----------------------------------------------------------------------------
31 static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
32 struct vsp1_dl_list *dl, u32 reg, u32 data)
34 vsp1_dl_list_write(dl, reg + rpf->entity.index * VI6_RPF_OFFSET, data);
37 /* -----------------------------------------------------------------------------
38 * V4L2 Subdevice Operations
41 static struct v4l2_subdev_ops rpf_ops = {
42 .pad = &vsp1_rwpf_pad_ops,
45 /* -----------------------------------------------------------------------------
46 * VSP1 Entity Operations
49 static void rpf_set_memory(struct vsp1_entity *entity, struct vsp1_dl_list *dl)
51 struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
53 vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_Y,
54 rpf->mem.addr[0] + rpf->offsets[0]);
55 vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C0,
56 rpf->mem.addr[1] + rpf->offsets[1]);
57 vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_ADDR_C1,
58 rpf->mem.addr[2] + rpf->offsets[1]);
61 static void rpf_configure(struct vsp1_entity *entity,
62 struct vsp1_pipeline *pipe,
63 struct vsp1_dl_list *dl)
65 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
66 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
67 const struct v4l2_pix_format_mplane *format = &rpf->format;
68 const struct v4l2_mbus_framefmt *source_format;
69 const struct v4l2_mbus_framefmt *sink_format;
70 const struct v4l2_rect *crop;
71 unsigned int left = 0;
76 /* Source size, stride and crop offsets.
78 * The crop offsets correspond to the location of the crop rectangle top
79 * left corner in the plane buffer. Only two offsets are needed, as
80 * planes 2 and 3 always have identical strides.
82 crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
84 vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_BSIZE,
85 (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
86 (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
87 vsp1_rpf_write(rpf, dl, VI6_RPF_SRC_ESIZE,
88 (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
89 (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
91 rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
92 + crop->left * fmtinfo->bpp[0] / 8;
93 pstride = format->plane_fmt[0].bytesperline
94 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
96 if (format->num_planes > 1) {
97 rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
98 + crop->left * fmtinfo->bpp[1] / 8;
99 pstride |= format->plane_fmt[1].bytesperline
100 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
105 vsp1_rpf_write(rpf, dl, VI6_RPF_SRCM_PSTRIDE, pstride);
108 sink_format = vsp1_entity_get_pad_format(&rpf->entity,
111 source_format = vsp1_entity_get_pad_format(&rpf->entity,
115 infmt = VI6_RPF_INFMT_CIPM
116 | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
118 if (fmtinfo->swap_yc)
119 infmt |= VI6_RPF_INFMT_SPYCS;
120 if (fmtinfo->swap_uv)
121 infmt |= VI6_RPF_INFMT_SPUVS;
123 if (sink_format->code != source_format->code)
124 infmt |= VI6_RPF_INFMT_CSC;
126 vsp1_rpf_write(rpf, dl, VI6_RPF_INFMT, infmt);
127 vsp1_rpf_write(rpf, dl, VI6_RPF_DSWAP, fmtinfo->swap);
129 /* Output location */
131 const struct v4l2_rect *compose;
133 compose = vsp1_entity_get_pad_compose(pipe->bru,
136 left = compose->left;
140 vsp1_rpf_write(rpf, dl, VI6_RPF_LOC,
141 (left << VI6_RPF_LOC_HCOORD_SHIFT) |
142 (top << VI6_RPF_LOC_VCOORD_SHIFT));
144 /* On Gen2 use the alpha channel (extended to 8 bits) when available or
145 * a fixed alpha value set through the V4L2_CID_ALPHA_COMPONENT control
148 * The Gen3 RPF has extended alpha capability and can both multiply the
149 * alpha channel by a fixed global alpha value, and multiply the pixel
150 * components to convert the input to premultiplied alpha.
152 * As alpha premultiplication is available in the BRU for both Gen2 and
153 * Gen3 we handle it there and use the Gen3 alpha multiplier for global
154 * alpha multiplication only. This however prevents conversion to
155 * premultiplied alpha if no BRU is present in the pipeline. If that use
156 * case turns out to be useful we will revisit the implementation (for
159 * We enable alpha multiplication on Gen3 using the fixed alpha value
160 * set through the V4L2_CID_ALPHA_COMPONENT control when the input
161 * contains an alpha channel. On Gen2 the global alpha is ignored in
164 * In all cases, disable color keying.
166 vsp1_rpf_write(rpf, dl, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
167 (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
168 : VI6_RPF_ALPH_SEL_ASEL_FIXED));
170 vsp1_rpf_write(rpf, dl, VI6_RPF_VRTCOL_SET,
171 rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
173 if (entity->vsp1->info->gen == 3) {
176 if (fmtinfo->alpha) {
177 /* When the input contains an alpha channel enable the
178 * alpha multiplier. If the input is premultiplied we
179 * need to multiply both the alpha channel and the pixel
180 * components by the global alpha value to keep them
181 * premultiplied. Otherwise multiply the alpha channel
184 bool premultiplied = format->flags
185 & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
187 mult = VI6_RPF_MULT_ALPHA_A_MMD_RATIO
189 VI6_RPF_MULT_ALPHA_P_MMD_RATIO :
190 VI6_RPF_MULT_ALPHA_P_MMD_NONE)
191 | (rpf->alpha << VI6_RPF_MULT_ALPHA_RATIO_SHIFT);
193 /* When the input doesn't contain an alpha channel the
194 * global alpha value is applied in the unpacking unit,
195 * the alpha multiplier isn't needed and must be
198 mult = VI6_RPF_MULT_ALPHA_A_MMD_NONE
199 | VI6_RPF_MULT_ALPHA_P_MMD_NONE;
202 vsp1_rpf_write(rpf, dl, VI6_RPF_MULT_ALPHA, mult);
205 vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, dl, rpf->alpha);
207 vsp1_rpf_write(rpf, dl, VI6_RPF_MSK_CTRL, 0);
208 vsp1_rpf_write(rpf, dl, VI6_RPF_CKEY_CTRL, 0);
212 static const struct vsp1_entity_operations rpf_entity_ops = {
213 .set_memory = rpf_set_memory,
214 .configure = rpf_configure,
217 /* -----------------------------------------------------------------------------
218 * Initialization and Cleanup
221 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
223 struct vsp1_rwpf *rpf;
227 rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
229 return ERR_PTR(-ENOMEM);
231 rpf->max_width = RPF_MAX_WIDTH;
232 rpf->max_height = RPF_MAX_HEIGHT;
234 rpf->entity.ops = &rpf_entity_ops;
235 rpf->entity.type = VSP1_ENTITY_RPF;
236 rpf->entity.index = index;
238 sprintf(name, "rpf.%u", index);
239 ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
243 /* Initialize the control handler. */
244 ret = vsp1_rwpf_init_ctrls(rpf);
246 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
254 vsp1_entity_destroy(&rpf->entity);