Linux-libre 4.14.14-gnu
[librecmc/linux-libre.git] / drivers / media / platform / vsp1 / vsp1_hgo.c
1 /*
2  * vsp1_hgo.c  --  R-Car VSP1 Histogram Generator 1D
3  *
4  * Copyright (C) 2016 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 #include <linux/gfp.h>
16
17 #include <media/v4l2-subdev.h>
18 #include <media/videobuf2-vmalloc.h>
19
20 #include "vsp1.h"
21 #include "vsp1_dl.h"
22 #include "vsp1_hgo.h"
23
24 #define HGO_DATA_SIZE                           ((2 + 256) * 4)
25
26 /* -----------------------------------------------------------------------------
27  * Device Access
28  */
29
30 static inline u32 vsp1_hgo_read(struct vsp1_hgo *hgo, u32 reg)
31 {
32         return vsp1_read(hgo->histo.entity.vsp1, reg);
33 }
34
35 static inline void vsp1_hgo_write(struct vsp1_hgo *hgo, struct vsp1_dl_list *dl,
36                                   u32 reg, u32 data)
37 {
38         vsp1_dl_list_write(dl, reg, data);
39 }
40
41 /* -----------------------------------------------------------------------------
42  * Frame End Handler
43  */
44
45 void vsp1_hgo_frame_end(struct vsp1_entity *entity)
46 {
47         struct vsp1_hgo *hgo = to_hgo(&entity->subdev);
48         struct vsp1_histogram_buffer *buf;
49         unsigned int i;
50         size_t size;
51         u32 *data;
52
53         buf = vsp1_histogram_buffer_get(&hgo->histo);
54         if (!buf)
55                 return;
56
57         data = buf->addr;
58
59         if (hgo->num_bins == 256) {
60                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
61                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
62
63                 for (i = 0; i < 256; ++i) {
64                         vsp1_write(hgo->histo.entity.vsp1,
65                                    VI6_HGO_EXT_HIST_ADDR, i);
66                         *data++ = vsp1_hgo_read(hgo, VI6_HGO_EXT_HIST_DATA);
67                 }
68
69                 size = (2 + 256) * sizeof(u32);
70         } else if (hgo->max_rgb) {
71                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
72                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
73
74                 for (i = 0; i < 64; ++i)
75                         *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i));
76
77                 size = (2 + 64) * sizeof(u32);
78         } else {
79                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_R_MAXMIN);
80                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN);
81                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_MAXMIN);
82
83                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_R_SUM);
84                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM);
85                 *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_SUM);
86
87                 for (i = 0; i < 64; ++i) {
88                         data[i] = vsp1_hgo_read(hgo, VI6_HGO_R_HISTO(i));
89                         data[i+64] = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i));
90                         data[i+128] = vsp1_hgo_read(hgo, VI6_HGO_B_HISTO(i));
91                 }
92
93                 size = (6 + 64 * 3) * sizeof(u32);
94         }
95
96         vsp1_histogram_buffer_complete(&hgo->histo, buf, size);
97 }
98
99 /* -----------------------------------------------------------------------------
100  * Controls
101  */
102
103 #define V4L2_CID_VSP1_HGO_MAX_RGB               (V4L2_CID_USER_BASE | 0x1001)
104 #define V4L2_CID_VSP1_HGO_NUM_BINS              (V4L2_CID_USER_BASE | 0x1002)
105
106 static const struct v4l2_ctrl_config hgo_max_rgb_control = {
107         .id = V4L2_CID_VSP1_HGO_MAX_RGB,
108         .name = "Maximum RGB Mode",
109         .type = V4L2_CTRL_TYPE_BOOLEAN,
110         .min = 0,
111         .max = 1,
112         .def = 0,
113         .step = 1,
114         .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
115 };
116
117 static const s64 hgo_num_bins[] = {
118         64, 256,
119 };
120
121 static const struct v4l2_ctrl_config hgo_num_bins_control = {
122         .id = V4L2_CID_VSP1_HGO_NUM_BINS,
123         .name = "Number of Bins",
124         .type = V4L2_CTRL_TYPE_INTEGER_MENU,
125         .min = 0,
126         .max = 1,
127         .def = 0,
128         .qmenu_int = hgo_num_bins,
129         .flags = V4L2_CTRL_FLAG_MODIFY_LAYOUT,
130 };
131
132 /* -----------------------------------------------------------------------------
133  * VSP1 Entity Operations
134  */
135
136 static void hgo_configure(struct vsp1_entity *entity,
137                           struct vsp1_pipeline *pipe,
138                           struct vsp1_dl_list *dl,
139                           enum vsp1_entity_params params)
140 {
141         struct vsp1_hgo *hgo = to_hgo(&entity->subdev);
142         struct v4l2_rect *compose;
143         struct v4l2_rect *crop;
144         unsigned int hratio;
145         unsigned int vratio;
146
147         if (params != VSP1_ENTITY_PARAMS_INIT)
148                 return;
149
150         crop = vsp1_entity_get_pad_selection(entity, entity->config,
151                                              HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
152         compose = vsp1_entity_get_pad_selection(entity, entity->config,
153                                                 HISTO_PAD_SINK,
154                                                 V4L2_SEL_TGT_COMPOSE);
155
156         vsp1_hgo_write(hgo, dl, VI6_HGO_REGRST, VI6_HGO_REGRST_RCLEA);
157
158         vsp1_hgo_write(hgo, dl, VI6_HGO_OFFSET,
159                        (crop->left << VI6_HGO_OFFSET_HOFFSET_SHIFT) |
160                        (crop->top << VI6_HGO_OFFSET_VOFFSET_SHIFT));
161         vsp1_hgo_write(hgo, dl, VI6_HGO_SIZE,
162                        (crop->width << VI6_HGO_SIZE_HSIZE_SHIFT) |
163                        (crop->height << VI6_HGO_SIZE_VSIZE_SHIFT));
164
165         mutex_lock(hgo->ctrls.handler.lock);
166         hgo->max_rgb = hgo->ctrls.max_rgb->cur.val;
167         if (hgo->ctrls.num_bins)
168                 hgo->num_bins = hgo_num_bins[hgo->ctrls.num_bins->cur.val];
169         mutex_unlock(hgo->ctrls.handler.lock);
170
171         hratio = crop->width * 2 / compose->width / 3;
172         vratio = crop->height * 2 / compose->height / 3;
173         vsp1_hgo_write(hgo, dl, VI6_HGO_MODE,
174                        (hgo->num_bins == 256 ? VI6_HGO_MODE_STEP : 0) |
175                        (hgo->max_rgb ? VI6_HGO_MODE_MAXRGB : 0) |
176                        (hratio << VI6_HGO_MODE_HRATIO_SHIFT) |
177                        (vratio << VI6_HGO_MODE_VRATIO_SHIFT));
178 }
179
180 static const struct vsp1_entity_operations hgo_entity_ops = {
181         .configure = hgo_configure,
182         .destroy = vsp1_histogram_destroy,
183 };
184
185 /* -----------------------------------------------------------------------------
186  * Initialization and Cleanup
187  */
188
189 static const unsigned int hgo_mbus_formats[] = {
190         MEDIA_BUS_FMT_AYUV8_1X32,
191         MEDIA_BUS_FMT_ARGB8888_1X32,
192         MEDIA_BUS_FMT_AHSV8888_1X32,
193 };
194
195 struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
196 {
197         struct vsp1_hgo *hgo;
198         int ret;
199
200         hgo = devm_kzalloc(vsp1->dev, sizeof(*hgo), GFP_KERNEL);
201         if (hgo == NULL)
202                 return ERR_PTR(-ENOMEM);
203
204         /* Initialize the control handler. */
205         v4l2_ctrl_handler_init(&hgo->ctrls.handler,
206                                vsp1->info->gen == 3 ? 2 : 1);
207         hgo->ctrls.max_rgb = v4l2_ctrl_new_custom(&hgo->ctrls.handler,
208                                                   &hgo_max_rgb_control, NULL);
209         if (vsp1->info->gen == 3)
210                 hgo->ctrls.num_bins =
211                         v4l2_ctrl_new_custom(&hgo->ctrls.handler,
212                                              &hgo_num_bins_control, NULL);
213
214         hgo->max_rgb = false;
215         hgo->num_bins = 64;
216
217         hgo->histo.entity.subdev.ctrl_handler = &hgo->ctrls.handler;
218
219         /* Initialize the video device and queue for statistics data. */
220         ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
221                                   &hgo_entity_ops, hgo_mbus_formats,
222                                   ARRAY_SIZE(hgo_mbus_formats),
223                                   HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
224         if (ret < 0) {
225                 vsp1_entity_destroy(&hgo->histo.entity);
226                 return ERR_PTR(ret);
227         }
228
229         return hgo;
230 }