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_list
*dl
,
135 struct vsp1_dl_body
*dlb
)
137 struct vsp1_hgo
*hgo
= to_hgo(&entity
->subdev
);
138 struct v4l2_rect
*compose
;
139 struct v4l2_rect
*crop
;
143 crop
= vsp1_entity_get_pad_selection(entity
, entity
->config
,
144 HISTO_PAD_SINK
, V4L2_SEL_TGT_CROP
);
145 compose
= vsp1_entity_get_pad_selection(entity
, entity
->config
,
147 V4L2_SEL_TGT_COMPOSE
);
149 vsp1_hgo_write(hgo
, dlb
, VI6_HGO_REGRST
, VI6_HGO_REGRST_RCLEA
);
151 vsp1_hgo_write(hgo
, dlb
, VI6_HGO_OFFSET
,
152 (crop
->left
<< VI6_HGO_OFFSET_HOFFSET_SHIFT
) |
153 (crop
->top
<< VI6_HGO_OFFSET_VOFFSET_SHIFT
));
154 vsp1_hgo_write(hgo
, dlb
, VI6_HGO_SIZE
,
155 (crop
->width
<< VI6_HGO_SIZE_HSIZE_SHIFT
) |
156 (crop
->height
<< VI6_HGO_SIZE_VSIZE_SHIFT
));
158 mutex_lock(hgo
->ctrls
.handler
.lock
);
159 hgo
->max_rgb
= hgo
->ctrls
.max_rgb
->cur
.val
;
160 if (hgo
->ctrls
.num_bins
)
161 hgo
->num_bins
= hgo_num_bins
[hgo
->ctrls
.num_bins
->cur
.val
];
162 mutex_unlock(hgo
->ctrls
.handler
.lock
);
164 hratio
= crop
->width
* 2 / compose
->width
/ 3;
165 vratio
= crop
->height
* 2 / compose
->height
/ 3;
166 vsp1_hgo_write(hgo
, dlb
, VI6_HGO_MODE
,
167 (hgo
->num_bins
== 256 ? VI6_HGO_MODE_STEP
: 0) |
168 (hgo
->max_rgb
? VI6_HGO_MODE_MAXRGB
: 0) |
169 (hratio
<< VI6_HGO_MODE_HRATIO_SHIFT
) |
170 (vratio
<< VI6_HGO_MODE_VRATIO_SHIFT
));
173 static const struct vsp1_entity_operations hgo_entity_ops
= {
174 .configure_stream
= hgo_configure_stream
,
175 .destroy
= vsp1_histogram_destroy
,
178 /* -----------------------------------------------------------------------------
179 * Initialization and Cleanup
182 static const unsigned int hgo_mbus_formats
[] = {
183 MEDIA_BUS_FMT_AYUV8_1X32
,
184 MEDIA_BUS_FMT_ARGB8888_1X32
,
185 MEDIA_BUS_FMT_AHSV8888_1X32
,
188 struct vsp1_hgo
*vsp1_hgo_create(struct vsp1_device
*vsp1
)
190 struct vsp1_hgo
*hgo
;
193 hgo
= devm_kzalloc(vsp1
->dev
, sizeof(*hgo
), GFP_KERNEL
);
195 return ERR_PTR(-ENOMEM
);
197 /* Initialize the control handler. */
198 v4l2_ctrl_handler_init(&hgo
->ctrls
.handler
,
199 vsp1
->info
->gen
== 3 ? 2 : 1);
200 hgo
->ctrls
.max_rgb
= v4l2_ctrl_new_custom(&hgo
->ctrls
.handler
,
201 &hgo_max_rgb_control
, NULL
);
202 if (vsp1
->info
->gen
== 3)
203 hgo
->ctrls
.num_bins
=
204 v4l2_ctrl_new_custom(&hgo
->ctrls
.handler
,
205 &hgo_num_bins_control
, NULL
);
207 hgo
->max_rgb
= false;
210 hgo
->histo
.entity
.subdev
.ctrl_handler
= &hgo
->ctrls
.handler
;
212 /* Initialize the video device and queue for statistics data. */
213 ret
= vsp1_histogram_init(vsp1
, &hgo
->histo
, VSP1_ENTITY_HGO
, "hgo",
214 &hgo_entity_ops
, hgo_mbus_formats
,
215 ARRAY_SIZE(hgo_mbus_formats
),
216 HGO_DATA_SIZE
, V4L2_META_FMT_VSP1_HGO
);
218 vsp1_entity_destroy(&hgo
->histo
.entity
);