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>
19 #include "vsp1_rwpf.h"
20 #include "vsp1_video.h"
22 #define RPF_MAX_WIDTH 8190
23 #define RPF_MAX_HEIGHT 8190
25 /* -----------------------------------------------------------------------------
29 static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
31 vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET,
35 /* -----------------------------------------------------------------------------
36 * V4L2 Subdevice Operations
39 static struct v4l2_subdev_pad_ops rpf_pad_ops = {
40 .init_cfg = vsp1_entity_init_cfg,
41 .enum_mbus_code = vsp1_rwpf_enum_mbus_code,
42 .enum_frame_size = vsp1_rwpf_enum_frame_size,
43 .get_fmt = vsp1_rwpf_get_format,
44 .set_fmt = vsp1_rwpf_set_format,
45 .get_selection = vsp1_rwpf_get_selection,
46 .set_selection = vsp1_rwpf_set_selection,
49 static struct v4l2_subdev_ops rpf_ops = {
53 /* -----------------------------------------------------------------------------
54 * VSP1 Entity Operations
57 static void rpf_set_memory(struct vsp1_entity *entity)
59 struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
61 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
62 rpf->mem.addr[0] + rpf->offsets[0]);
63 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
64 rpf->mem.addr[1] + rpf->offsets[1]);
65 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
66 rpf->mem.addr[2] + rpf->offsets[1]);
69 static void rpf_configure(struct vsp1_entity *entity)
71 struct vsp1_pipeline *pipe = to_vsp1_pipeline(&entity->subdev.entity);
72 struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
73 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
74 const struct v4l2_pix_format_mplane *format = &rpf->format;
75 const struct v4l2_mbus_framefmt *source_format;
76 const struct v4l2_mbus_framefmt *sink_format;
77 const struct v4l2_rect *crop;
78 unsigned int left = 0;
83 /* Source size, stride and crop offsets.
85 * The crop offsets correspond to the location of the crop rectangle top
86 * left corner in the plane buffer. Only two offsets are needed, as
87 * planes 2 and 3 always have identical strides.
89 crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
91 vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
92 (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
93 (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
94 vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
95 (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
96 (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
98 rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
99 + crop->left * fmtinfo->bpp[0] / 8;
100 pstride = format->plane_fmt[0].bytesperline
101 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
103 if (format->num_planes > 1) {
104 rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
105 + crop->left * fmtinfo->bpp[1] / 8;
106 pstride |= format->plane_fmt[1].bytesperline
107 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
112 vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
115 sink_format = vsp1_entity_get_pad_format(&rpf->entity,
118 source_format = vsp1_entity_get_pad_format(&rpf->entity,
122 infmt = VI6_RPF_INFMT_CIPM
123 | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
125 if (fmtinfo->swap_yc)
126 infmt |= VI6_RPF_INFMT_SPYCS;
127 if (fmtinfo->swap_uv)
128 infmt |= VI6_RPF_INFMT_SPUVS;
130 if (sink_format->code != source_format->code)
131 infmt |= VI6_RPF_INFMT_CSC;
133 vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
134 vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
136 /* Output location */
138 const struct v4l2_rect *compose;
140 compose = vsp1_entity_get_pad_compose(pipe->bru,
143 left = compose->left;
147 vsp1_rpf_write(rpf, VI6_RPF_LOC,
148 (left << VI6_RPF_LOC_HCOORD_SHIFT) |
149 (top << VI6_RPF_LOC_VCOORD_SHIFT));
151 /* Use the alpha channel (extended to 8 bits) when available or an
152 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
153 * otherwise. Disable color keying.
155 vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
156 (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
157 : VI6_RPF_ALPH_SEL_ASEL_FIXED));
159 vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
160 rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
162 vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha);
164 vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
165 vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
168 static const struct vsp1_entity_operations rpf_entity_ops = {
169 .set_memory = rpf_set_memory,
170 .configure = rpf_configure,
173 /* -----------------------------------------------------------------------------
174 * Initialization and Cleanup
177 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
179 struct vsp1_rwpf *rpf;
183 rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
185 return ERR_PTR(-ENOMEM);
187 rpf->max_width = RPF_MAX_WIDTH;
188 rpf->max_height = RPF_MAX_HEIGHT;
190 rpf->entity.ops = &rpf_entity_ops;
191 rpf->entity.type = VSP1_ENTITY_RPF;
192 rpf->entity.index = index;
194 sprintf(name, "rpf.%u", index);
195 ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
199 /* Initialize the control handler. */
200 ret = vsp1_rwpf_init_ctrls(rpf);
202 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
210 vsp1_entity_destroy(&rpf->entity);