1
2
3
4
5
6
7
8
9
10
11
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
28
29
30static inline u32 vsp1_hgo_read(struct vsp1_hgo *hgo, u32 reg)
31{
32 return vsp1_read(hgo->histo.entity.vsp1, reg);
33}
34
35static 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
43
44
45void 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
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
106static 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
117static const s64 hgo_num_bins[] = {
118 64, 256,
119};
120
121static 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
134
135
136static 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
180static const struct vsp1_entity_operations hgo_entity_ops = {
181 .configure = hgo_configure,
182 .destroy = vsp1_histogram_destroy,
183};
184
185
186
187
188
189static 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
195struct 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
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
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}
231