blob: a68f26db9b3f3580e5509300e0fc82b74b24e69d [file] [log] [blame]
Laurent Pinchart26e0ca22013-06-04 11:22:30 -03001/*
2 * vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter
3 *
Laurent Pinchart8a1edc52014-02-06 14:42:31 -03004 * Copyright (C) 2013-2014 Renesas Electronics Corporation
Laurent Pinchart26e0ca22013-06-04 11:22:30 -03005 *
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
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030029static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
30{
Takashi Saito1517b032015-09-07 01:40:25 -030031 vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET,
32 data);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030033}
34
35/* -----------------------------------------------------------------------------
36 * V4L2 Subdevice Core Operations
37 */
38
39static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
40{
Laurent Pinchart3dbb6102015-08-05 16:57:35 -030041 struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030042 struct vsp1_rwpf *rpf = to_rwpf(subdev);
Laurent Pinchart86960ee2015-07-28 14:00:43 -030043 const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
44 const struct v4l2_pix_format_mplane *format = &rpf->format;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -030045 const struct v4l2_rect *crop = &rpf->crop;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030046 u32 pstride;
47 u32 infmt;
Laurent Pinchart7578c202014-05-21 19:00:05 -030048
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030049 if (!enable)
50 return 0;
51
Laurent Pincharte5ad37b2013-08-24 20:49:58 -030052 /* Source size, stride and crop offsets.
53 *
54 * The crop offsets correspond to the location of the crop rectangle top
55 * left corner in the plane buffer. Only two offsets are needed, as
56 * planes 2 and 3 always have identical strides.
57 */
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030058 vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
Laurent Pincharte5ad37b2013-08-24 20:49:58 -030059 (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
60 (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030061 vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
Laurent Pincharte5ad37b2013-08-24 20:49:58 -030062 (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
63 (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030064
Laurent Pincharte5ad37b2013-08-24 20:49:58 -030065 rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
66 + crop->left * fmtinfo->bpp[0] / 8;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030067 pstride = format->plane_fmt[0].bytesperline
68 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
Takanari Hayama857161f2014-11-26 22:25:01 -030069
Laurent Pincharte5ad37b2013-08-24 20:49:58 -030070 if (format->num_planes > 1) {
71 rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
72 + crop->left * fmtinfo->bpp[1] / 8;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030073 pstride |= format->plane_fmt[1].bytesperline
74 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
Laurent Pinchart4d346be52015-11-01 13:48:11 -020075 } else {
76 rpf->offsets[1] = 0;
Laurent Pincharte5ad37b2013-08-24 20:49:58 -030077 }
Laurent Pinchart26e0ca22013-06-04 11:22:30 -030078
79 vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
80
81 /* Format */
82 infmt = VI6_RPF_INFMT_CIPM
83 | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
84
85 if (fmtinfo->swap_yc)
86 infmt |= VI6_RPF_INFMT_SPYCS;
87 if (fmtinfo->swap_uv)
88 infmt |= VI6_RPF_INFMT_SPUVS;
89
90 if (rpf->entity.formats[RWPF_PAD_SINK].code !=
91 rpf->entity.formats[RWPF_PAD_SOURCE].code)
92 infmt |= VI6_RPF_INFMT_CSC;
93
94 vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
95 vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
96
Laurent Pinchart629bb6d2013-07-10 18:03:46 -030097 /* Output location */
98 vsp1_rpf_write(rpf, VI6_RPF_LOC,
99 (rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) |
100 (rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT));
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300101
Laurent Pinchart7578c202014-05-21 19:00:05 -0300102 /* Use the alpha channel (extended to 8 bits) when available or an
103 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
104 * otherwise. Disable color keying.
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300105 */
Laurent Pinchart7a52b6d2014-05-26 20:12:53 -0300106 vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
107 (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
108 : VI6_RPF_ALPH_SEL_ASEL_FIXED));
Laurent Pinchart3dbb6102015-08-05 16:57:35 -0300109
Laurent Pinchart3dbb6102015-08-05 16:57:35 -0300110 vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
Laurent Pinchartbd2fdd52015-11-01 12:19:42 -0200111 rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
112
113 vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha);
Laurent Pinchart3dbb6102015-08-05 16:57:35 -0300114
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300115 vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
116 vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
117
118 return 0;
119}
120
121/* -----------------------------------------------------------------------------
122 * V4L2 Subdevice Operations
123 */
124
125static struct v4l2_subdev_video_ops rpf_video_ops = {
126 .s_stream = rpf_s_stream,
127};
128
129static struct v4l2_subdev_pad_ops rpf_pad_ops = {
130 .enum_mbus_code = vsp1_rwpf_enum_mbus_code,
131 .enum_frame_size = vsp1_rwpf_enum_frame_size,
132 .get_fmt = vsp1_rwpf_get_format,
133 .set_fmt = vsp1_rwpf_set_format,
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300134 .get_selection = vsp1_rwpf_get_selection,
135 .set_selection = vsp1_rwpf_set_selection,
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300136};
137
138static struct v4l2_subdev_ops rpf_ops = {
139 .video = &rpf_video_ops,
140 .pad = &rpf_pad_ops,
141};
142
143/* -----------------------------------------------------------------------------
Laurent Pinchart52434532015-11-17 12:23:23 -0200144 * VSP1 Entity Operations
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300145 */
146
Laurent Pinchart52434532015-11-17 12:23:23 -0200147static void rpf_set_memory(struct vsp1_entity *entity)
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300148{
Laurent Pinchart52434532015-11-17 12:23:23 -0200149 struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
150
Laurent Pincharte5ad37b2013-08-24 20:49:58 -0300151 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
Laurent Pinchart351bbf92015-11-01 15:18:56 -0200152 rpf->mem.addr[0] + rpf->offsets[0]);
Laurent Pinchart4d346be52015-11-01 13:48:11 -0200153 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
Laurent Pinchart351bbf92015-11-01 15:18:56 -0200154 rpf->mem.addr[1] + rpf->offsets[1]);
Laurent Pinchart4d346be52015-11-01 13:48:11 -0200155 vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
Laurent Pinchart351bbf92015-11-01 15:18:56 -0200156 rpf->mem.addr[2] + rpf->offsets[1]);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300157}
158
Laurent Pinchart52434532015-11-17 12:23:23 -0200159static const struct vsp1_entity_operations rpf_entity_ops = {
Laurent Pinchartb58faa92015-07-28 16:04:47 -0300160 .set_memory = rpf_set_memory,
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300161};
162
163/* -----------------------------------------------------------------------------
164 * Initialization and Cleanup
165 */
166
167struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
168{
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300169 struct vsp1_rwpf *rpf;
Laurent Pinchart823329d2015-11-15 19:42:01 -0200170 char name[6];
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300171 int ret;
172
173 rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
174 if (rpf == NULL)
175 return ERR_PTR(-ENOMEM);
176
177 rpf->max_width = RPF_MAX_WIDTH;
178 rpf->max_height = RPF_MAX_HEIGHT;
179
Laurent Pinchart52434532015-11-17 12:23:23 -0200180 rpf->entity.ops = &rpf_entity_ops;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300181 rpf->entity.type = VSP1_ENTITY_RPF;
182 rpf->entity.index = index;
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300183
Laurent Pinchart823329d2015-11-15 19:42:01 -0200184 sprintf(name, "rpf.%u", index);
185 ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300186 if (ret < 0)
187 return ERR_PTR(ret);
188
Laurent Pinchart7578c202014-05-21 19:00:05 -0300189 /* Initialize the control handler. */
Laurent Pinchartbd2fdd52015-11-01 12:19:42 -0200190 ret = vsp1_rwpf_init_ctrls(rpf);
191 if (ret < 0) {
Laurent Pinchart7578c202014-05-21 19:00:05 -0300192 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
193 index);
Laurent Pinchart7578c202014-05-21 19:00:05 -0300194 goto error;
195 }
196
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300197 return rpf;
198
Laurent Pinchart1499be62014-05-28 12:49:13 -0300199error:
200 vsp1_entity_destroy(&rpf->entity);
Laurent Pinchart26e0ca22013-06-04 11:22:30 -0300201 return ERR_PTR(ret);
202}