1 // SPDX-License-Identifier: GPL-2.0+
3 * vsp1_hgo.c -- R-Car VSP1 Histogram Generator 1D
5 * Copyright (C) 2016 Renesas Electronics Corporation
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
10 #include <linux/device.h>
11 #include <linux/gfp.h>
13 #include <media/v4l2-subdev.h>
14 #include <media/videobuf2-vmalloc.h>
20 #define HGO_DATA_SIZE ((2 + 256) * 4)
22 /* -----------------------------------------------------------------------------
26 static inline u32
vsp1_hgo_read(struct vsp1_hgo
*hgo
, u32 reg
)
28 return vsp1_read(hgo
->histo
.entity
.vsp1
, reg
);
31 static inline void vsp1_hgo_write(struct vsp1_hgo
*hgo
,
32 struct vsp1_dl_body
*dlb
, u32 reg
, u32 data
)
34 vsp1_dl_body_write(dlb
, reg
, data
);
37 /* -----------------------------------------------------------------------------
41 void vsp1_hgo_frame_end(struct vsp1_entity
*entity
)
43 struct vsp1_hgo
*hgo
= to_hgo(&entity
->subdev
);
44 struct vsp1_histogram_buffer
*buf
;
49 buf
= vsp1_histogram_buffer_get(&hgo
->histo
);
55 if (hgo
->num_bins
== 256) {
56 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_G_MAXMIN
);
57 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_G_SUM
);
59 for (i
= 0; i
< 256; ++i
) {
60 vsp1_write(hgo
->histo
.entity
.vsp1
,
61 VI6_HGO_EXT_HIST_ADDR
, i
);
62 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_EXT_HIST_DATA
);
65 size
= (2 + 256) * sizeof(u32
);
66 } else if (hgo
->max_rgb
) {
67 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_G_MAXMIN
);
68 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_G_SUM
);
70 for (i
= 0; i
< 64; ++i
)
71 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_G_HISTO(i
));
73 size
= (2 + 64) * sizeof(u32
);
75 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_R_MAXMIN
);
76 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_G_MAXMIN
);
77 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_B_MAXMIN
);
79 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_R_SUM
);
80 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_G_SUM
);
81 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_B_SUM
);
83 for (i
= 0; i
< 64; ++i
) {
84 data
[i
] = vsp1_hgo_read(hgo
, VI6_HGO_R_HISTO(i
));
85 data
[i
+64] = vsp1_hgo_read(hgo
, VI6_HGO_G_HISTO(i
));
86 data
[i
+128] = vsp1_hgo_read(hgo
, VI6_HGO_B_HISTO(i
));
89 size
= (6 + 64 * 3) * sizeof(u32
);
92 vsp1_histogram_buffer_complete(&hgo
->histo
, buf
, size
);
95 /* -----------------------------------------------------------------------------
99 #define V4L2_CID_VSP1_HGO_MAX_RGB (V4L2_CID_USER_BASE | 0x1001)
100 #define V4L2_CID_VSP1_HGO_NUM_BINS (V4L2_CID_USER_BASE | 0x1002)
102 static const struct v4l2_ctrl_config hgo_max_rgb_control
= {
103 .id
= V4L2_CID_VSP1_HGO_MAX_RGB
,
104 .name
= "Maximum RGB Mode",
105 .type
= V4L2_CTRL_TYPE_BOOLEAN
,
110 .flags
= V4L2_CTRL_FLAG_MODIFY_LAYOUT
,
113 static const s64 hgo_num_bins
[] = {
117 static const struct v4l2_ctrl_config hgo_num_bins_control
= {
118 .id
= V4L2_CID_VSP1_HGO_NUM_BINS
,
119 .name
= "Number of Bins",
120 .type
= V4L2_CTRL_TYPE_INTEGER_MENU
,
124 .qmenu_int
= hgo_num_bins
,
125 .flags
= V4L2_CTRL_FLAG_MODIFY_LAYOUT
,
128 /* -----------------------------------------------------------------------------
129 * VSP1 Entity Operations
132 static void hgo_configure_stream(struct vsp1_entity
*entity
,
133 struct vsp1_pipeline
*pipe
,
134 struct vsp1_dl_body
*dlb
)
136 struct vsp1_hgo
*hgo
= to_hgo(&entity
->subdev
);
137 struct v4l2_rect
*compose
;
138 struct v4l2_rect
*crop
;
142 crop
= vsp1_entity_get_pad_selection(entity
, entity
->config
,
143 HISTO_PAD_SINK
, V4L2_SEL_TGT_CROP
);
144 compose
= vsp1_entity_get_pad_selection(entity
, entity
->config
,
146 V4L2_SEL_TGT_COMPOSE
);
148 vsp1_hgo_write(hgo
, dlb
, VI6_HGO_REGRST
, VI6_HGO_REGRST_RCLEA
);
150 vsp1_hgo_write(hgo
, dlb
, VI6_HGO_OFFSET
,
151 (crop
->left
<< VI6_HGO_OFFSET_HOFFSET_SHIFT
) |
152 (crop
->top
<< VI6_HGO_OFFSET_VOFFSET_SHIFT
));
153 vsp1_hgo_write(hgo
, dlb
, VI6_HGO_SIZE
,
154 (crop
->width
<< VI6_HGO_SIZE_HSIZE_SHIFT
) |
155 (crop
->height
<< VI6_HGO_SIZE_VSIZE_SHIFT
));
157 mutex_lock(hgo
->ctrls
.handler
.lock
);
158 hgo
->max_rgb
= hgo
->ctrls
.max_rgb
->cur
.val
;
159 if (hgo
->ctrls
.num_bins
)
160 hgo
->num_bins
= hgo_num_bins
[hgo
->ctrls
.num_bins
->cur
.val
];
161 mutex_unlock(hgo
->ctrls
.handler
.lock
);
163 hratio
= crop
->width
* 2 / compose
->width
/ 3;
164 vratio
= crop
->height
* 2 / compose
->height
/ 3;
165 vsp1_hgo_write(hgo
, dlb
, VI6_HGO_MODE
,
166 (hgo
->num_bins
== 256 ? VI6_HGO_MODE_STEP
: 0) |
167 (hgo
->max_rgb
? VI6_HGO_MODE_MAXRGB
: 0) |
168 (hratio
<< VI6_HGO_MODE_HRATIO_SHIFT
) |
169 (vratio
<< VI6_HGO_MODE_VRATIO_SHIFT
));
172 static const struct vsp1_entity_operations hgo_entity_ops
= {
173 .configure_stream
= hgo_configure_stream
,
174 .destroy
= vsp1_histogram_destroy
,
177 /* -----------------------------------------------------------------------------
178 * Initialization and Cleanup
181 static const unsigned int hgo_mbus_formats
[] = {
182 MEDIA_BUS_FMT_AYUV8_1X32
,
183 MEDIA_BUS_FMT_ARGB8888_1X32
,
184 MEDIA_BUS_FMT_AHSV8888_1X32
,
187 struct vsp1_hgo
*vsp1_hgo_create(struct vsp1_device
*vsp1
)
189 struct vsp1_hgo
*hgo
;
192 hgo
= devm_kzalloc(vsp1
->dev
, sizeof(*hgo
), GFP_KERNEL
);
194 return ERR_PTR(-ENOMEM
);
196 /* Initialize the control handler. */
197 v4l2_ctrl_handler_init(&hgo
->ctrls
.handler
,
198 vsp1
->info
->gen
== 3 ? 2 : 1);
199 hgo
->ctrls
.max_rgb
= v4l2_ctrl_new_custom(&hgo
->ctrls
.handler
,
200 &hgo_max_rgb_control
, NULL
);
201 if (vsp1
->info
->gen
== 3)
202 hgo
->ctrls
.num_bins
=
203 v4l2_ctrl_new_custom(&hgo
->ctrls
.handler
,
204 &hgo_num_bins_control
, NULL
);
206 hgo
->max_rgb
= false;
209 hgo
->histo
.entity
.subdev
.ctrl_handler
= &hgo
->ctrls
.handler
;
211 /* Initialize the video device and queue for statistics data. */
212 ret
= vsp1_histogram_init(vsp1
, &hgo
->histo
, VSP1_ENTITY_HGO
, "hgo",
213 &hgo_entity_ops
, hgo_mbus_formats
,
214 ARRAY_SIZE(hgo_mbus_formats
),
215 HGO_DATA_SIZE
, V4L2_META_FMT_VSP1_HGO
);
217 vsp1_entity_destroy(&hgo
->histo
.entity
);