[media] v4l: vsp1: Create a new configure operation to setup modules
[cascardo/linux.git] / drivers / media / platform / vsp1 / vsp1_rpf.c
1 /*
2  * vsp1_rpf.c  --  R-Car VSP1 Read Pixel Formatter
3  *
4  * Copyright (C) 2013-2014 Renesas Electronics Corporation
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
29 static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
30 {
31         vsp1_mod_write(&rpf->entity, reg + rpf->entity.index * VI6_RPF_OFFSET,
32                        data);
33 }
34
35 /* -----------------------------------------------------------------------------
36  * V4L2 Subdevice Operations
37  */
38
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,
47 };
48
49 static struct v4l2_subdev_ops rpf_ops = {
50         .pad    = &rpf_pad_ops,
51 };
52
53 /* -----------------------------------------------------------------------------
54  * VSP1 Entity Operations
55  */
56
57 static void rpf_set_memory(struct vsp1_entity *entity)
58 {
59         struct vsp1_rwpf *rpf = entity_to_rwpf(entity);
60
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]);
67 }
68
69 static void rpf_configure(struct vsp1_entity *entity)
70 {
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;
79         unsigned int top = 0;
80         u32 pstride;
81         u32 infmt;
82
83         /* Source size, stride and crop offsets.
84          *
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.
88          */
89         crop = vsp1_rwpf_get_crop(rpf, rpf->entity.config);
90
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));
97
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;
102
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;
108         } else {
109                 rpf->offsets[1] = 0;
110         }
111
112         vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
113
114         /* Format */
115         sink_format = vsp1_entity_get_pad_format(&rpf->entity,
116                                                  rpf->entity.config,
117                                                  RWPF_PAD_SINK);
118         source_format = vsp1_entity_get_pad_format(&rpf->entity,
119                                                    rpf->entity.config,
120                                                    RWPF_PAD_SOURCE);
121
122         infmt = VI6_RPF_INFMT_CIPM
123               | (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
124
125         if (fmtinfo->swap_yc)
126                 infmt |= VI6_RPF_INFMT_SPYCS;
127         if (fmtinfo->swap_uv)
128                 infmt |= VI6_RPF_INFMT_SPUVS;
129
130         if (sink_format->code != source_format->code)
131                 infmt |= VI6_RPF_INFMT_CSC;
132
133         vsp1_rpf_write(rpf, VI6_RPF_INFMT, infmt);
134         vsp1_rpf_write(rpf, VI6_RPF_DSWAP, fmtinfo->swap);
135
136         /* Output location */
137         if (pipe->bru) {
138                 const struct v4l2_rect *compose;
139
140                 compose = vsp1_entity_get_pad_compose(pipe->bru,
141                                                       pipe->bru->config,
142                                                       rpf->bru_input);
143                 left = compose->left;
144                 top = compose->top;
145         }
146
147         vsp1_rpf_write(rpf, VI6_RPF_LOC,
148                        (left << VI6_RPF_LOC_HCOORD_SHIFT) |
149                        (top << VI6_RPF_LOC_VCOORD_SHIFT));
150
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.
154          */
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));
158
159         vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
160                        rpf->alpha << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
161
162         vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, rpf->alpha);
163
164         vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
165         vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
166 }
167
168 static const struct vsp1_entity_operations rpf_entity_ops = {
169         .set_memory = rpf_set_memory,
170         .configure = rpf_configure,
171 };
172
173 /* -----------------------------------------------------------------------------
174  * Initialization and Cleanup
175  */
176
177 struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
178 {
179         struct vsp1_rwpf *rpf;
180         char name[6];
181         int ret;
182
183         rpf = devm_kzalloc(vsp1->dev, sizeof(*rpf), GFP_KERNEL);
184         if (rpf == NULL)
185                 return ERR_PTR(-ENOMEM);
186
187         rpf->max_width = RPF_MAX_WIDTH;
188         rpf->max_height = RPF_MAX_HEIGHT;
189
190         rpf->entity.ops = &rpf_entity_ops;
191         rpf->entity.type = VSP1_ENTITY_RPF;
192         rpf->entity.index = index;
193
194         sprintf(name, "rpf.%u", index);
195         ret = vsp1_entity_init(vsp1, &rpf->entity, name, 2, &rpf_ops);
196         if (ret < 0)
197                 return ERR_PTR(ret);
198
199         /* Initialize the control handler. */
200         ret = vsp1_rwpf_init_ctrls(rpf);
201         if (ret < 0) {
202                 dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
203                         index);
204                 goto error;
205         }
206
207         return rpf;
208
209 error:
210         vsp1_entity_destroy(&rpf->entity);
211         return ERR_PTR(ret);
212 }