2 * vsp1_hgo.c -- R-Car VSP1 Histogram Generator 1D
4 * Copyright (C) 2016 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
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.
14 #include <linux/device.h>
15 #include <linux/gfp.h>
17 #include <media/v4l2-subdev.h>
18 #include <media/videobuf2-vmalloc.h>
24 #define HGO_DATA_SIZE ((2 + 256) * 4)
26 /* -----------------------------------------------------------------------------
30 static inline u32
vsp1_hgo_read(struct vsp1_hgo
*hgo
, u32 reg
)
32 return vsp1_read(hgo
->histo
.entity
.vsp1
, reg
);
35 static inline void vsp1_hgo_write(struct vsp1_hgo
*hgo
, struct vsp1_dl_list
*dl
,
38 vsp1_dl_list_write(dl
, reg
, data
);
41 /* -----------------------------------------------------------------------------
45 void vsp1_hgo_frame_end(struct vsp1_entity
*entity
)
47 struct vsp1_hgo
*hgo
= to_hgo(&entity
->subdev
);
48 struct vsp1_histogram_buffer
*buf
;
53 buf
= vsp1_histogram_buffer_get(&hgo
->histo
);
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
);
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
);
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
);
74 for (i
= 0; i
< 64; ++i
)
75 *data
++ = vsp1_hgo_read(hgo
, VI6_HGO_G_HISTO(i
));
77 size
= (2 + 64) * sizeof(u32
);
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
);
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
);
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
));
93 size
= (6 + 64 * 3) * sizeof(u32
);
96 vsp1_histogram_buffer_complete(&hgo
->histo
, buf
, size
);
99 /* -----------------------------------------------------------------------------
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)
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
,
114 .flags
= V4L2_CTRL_FLAG_MODIFY_LAYOUT
,
117 static const s64 hgo_num_bins
[] = {
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
,
128 .qmenu_int
= hgo_num_bins
,
129 .flags
= V4L2_CTRL_FLAG_MODIFY_LAYOUT
,
132 /* -----------------------------------------------------------------------------
133 * VSP1 Entity Operations
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
)
141 struct vsp1_hgo
*hgo
= to_hgo(&entity
->subdev
);
142 struct v4l2_rect
*compose
;
143 struct v4l2_rect
*crop
;
147 if (params
!= VSP1_ENTITY_PARAMS_INIT
)
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
,
154 V4L2_SEL_TGT_COMPOSE
);
156 vsp1_hgo_write(hgo
, dl
, VI6_HGO_REGRST
, VI6_HGO_REGRST_RCLEA
);
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
));
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
);
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
));
180 static const struct vsp1_entity_operations hgo_entity_ops
= {
181 .configure
= hgo_configure
,
182 .destroy
= vsp1_histogram_destroy
,
185 /* -----------------------------------------------------------------------------
186 * Initialization and Cleanup
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
,
195 struct vsp1_hgo
*vsp1_hgo_create(struct vsp1_device
*vsp1
)
197 struct vsp1_hgo
*hgo
;
200 hgo
= devm_kzalloc(vsp1
->dev
, sizeof(*hgo
), GFP_KERNEL
);
202 return ERR_PTR(-ENOMEM
);
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
);
214 hgo
->max_rgb
= false;
217 hgo
->histo
.entity
.subdev
.ctrl_handler
= &hgo
->ctrls
.handler
;
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
);
225 vsp1_entity_destroy(&hgo
->histo
.entity
);