1 // SPDX-License-Identifier: GPL-2.0+
3 * vsp1_hgt.c -- R-Car VSP1 Histogram Generator 2D
5 * Copyright (C) 2016 Renesas Electronics Corporation
7 * Contact: Niklas Söderlund (niklas.soderlund@ragnatech.se)
10 #include <linux/device.h>
11 #include <linux/gfp.h>
13 #include <media/v4l2-subdev.h>
14 #include <media/videobuf2-vmalloc.h>
20 #define HGT_DATA_SIZE ((2 + 6 * 32) * 4)
22 /* -----------------------------------------------------------------------------
26 static inline u32
vsp1_hgt_read(struct vsp1_hgt
*hgt
, u32 reg
)
28 return vsp1_read(hgt
->histo
.entity
.vsp1
, reg
);
31 static inline void vsp1_hgt_write(struct vsp1_hgt
*hgt
,
32 struct vsp1_dl_body
*dlb
, u32 reg
, u32 data
)
34 vsp1_dl_body_write(dlb
, reg
, data
);
37 /* -----------------------------------------------------------------------------
41 void vsp1_hgt_frame_end(struct vsp1_entity
*entity
)
43 struct vsp1_hgt
*hgt
= to_hgt(&entity
->subdev
);
44 struct vsp1_histogram_buffer
*buf
;
49 buf
= vsp1_histogram_buffer_get(&hgt
->histo
);
55 *data
++ = vsp1_hgt_read(hgt
, VI6_HGT_MAXMIN
);
56 *data
++ = vsp1_hgt_read(hgt
, VI6_HGT_SUM
);
58 for (m
= 0; m
< 6; ++m
)
59 for (n
= 0; n
< 32; ++n
)
60 *data
++ = vsp1_hgt_read(hgt
, VI6_HGT_HISTO(m
, n
));
62 vsp1_histogram_buffer_complete(&hgt
->histo
, buf
, HGT_DATA_SIZE
);
65 /* -----------------------------------------------------------------------------
69 #define V4L2_CID_VSP1_HGT_HUE_AREAS (V4L2_CID_USER_BASE | 0x1001)
71 static int hgt_hue_areas_try_ctrl(struct v4l2_ctrl
*ctrl
)
73 const u8
*values
= ctrl
->p_new
.p_u8
;
77 * The hardware has constraints on the hue area boundaries beyond the
78 * control min, max and step. The values must match one of the following
81 * 0L <= 0U <= 1L <= 1U <= 2L <= 2U <= 3L <= 3U <= 4L <= 4U <= 5L <= 5U
82 * 0U <= 1L <= 1U <= 2L <= 2U <= 3L <= 3U <= 4L <= 4U <= 5L <= 5U <= 0L
84 * Start by verifying the common part...
86 for (i
= 1; i
< (HGT_NUM_HUE_AREAS
* 2) - 1; ++i
) {
87 if (values
[i
] > values
[i
+1])
91 /* ... and handle 0L separately. */
92 if (values
[0] > values
[1] && values
[11] > values
[0])
98 static int hgt_hue_areas_s_ctrl(struct v4l2_ctrl
*ctrl
)
100 struct vsp1_hgt
*hgt
= container_of(ctrl
->handler
, struct vsp1_hgt
,
103 memcpy(hgt
->hue_areas
, ctrl
->p_new
.p_u8
, sizeof(hgt
->hue_areas
));
107 static const struct v4l2_ctrl_ops hgt_hue_areas_ctrl_ops
= {
108 .try_ctrl
= hgt_hue_areas_try_ctrl
,
109 .s_ctrl
= hgt_hue_areas_s_ctrl
,
112 static const struct v4l2_ctrl_config hgt_hue_areas
= {
113 .ops
= &hgt_hue_areas_ctrl_ops
,
114 .id
= V4L2_CID_VSP1_HGT_HUE_AREAS
,
115 .name
= "Boundary Values for Hue Area",
116 .type
= V4L2_CTRL_TYPE_U8
,
124 /* -----------------------------------------------------------------------------
125 * VSP1 Entity Operations
128 static void hgt_configure_stream(struct vsp1_entity
*entity
,
129 struct vsp1_pipeline
*pipe
,
130 struct vsp1_dl_list
*dl
,
131 struct vsp1_dl_body
*dlb
)
133 struct vsp1_hgt
*hgt
= to_hgt(&entity
->subdev
);
134 struct v4l2_rect
*compose
;
135 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_hgt_write(hgt
, dlb
, VI6_HGT_REGRST
, VI6_HGT_REGRST_RCLEA
);
150 vsp1_hgt_write(hgt
, dlb
, VI6_HGT_OFFSET
,
151 (crop
->left
<< VI6_HGT_OFFSET_HOFFSET_SHIFT
) |
152 (crop
->top
<< VI6_HGT_OFFSET_VOFFSET_SHIFT
));
153 vsp1_hgt_write(hgt
, dlb
, VI6_HGT_SIZE
,
154 (crop
->width
<< VI6_HGT_SIZE_HSIZE_SHIFT
) |
155 (crop
->height
<< VI6_HGT_SIZE_VSIZE_SHIFT
));
157 mutex_lock(hgt
->ctrls
.lock
);
158 for (i
= 0; i
< HGT_NUM_HUE_AREAS
; ++i
) {
159 lower
= hgt
->hue_areas
[i
*2 + 0];
160 upper
= hgt
->hue_areas
[i
*2 + 1];
161 vsp1_hgt_write(hgt
, dlb
, VI6_HGT_HUE_AREA(i
),
162 (lower
<< VI6_HGT_HUE_AREA_LOWER_SHIFT
) |
163 (upper
<< VI6_HGT_HUE_AREA_UPPER_SHIFT
));
165 mutex_unlock(hgt
->ctrls
.lock
);
167 hratio
= crop
->width
* 2 / compose
->width
/ 3;
168 vratio
= crop
->height
* 2 / compose
->height
/ 3;
169 vsp1_hgt_write(hgt
, dlb
, VI6_HGT_MODE
,
170 (hratio
<< VI6_HGT_MODE_HRATIO_SHIFT
) |
171 (vratio
<< VI6_HGT_MODE_VRATIO_SHIFT
));
174 static const struct vsp1_entity_operations hgt_entity_ops
= {
175 .configure_stream
= hgt_configure_stream
,
176 .destroy
= vsp1_histogram_destroy
,
179 /* -----------------------------------------------------------------------------
180 * Initialization and Cleanup
183 static const unsigned int hgt_mbus_formats
[] = {
184 MEDIA_BUS_FMT_AHSV8888_1X32
,
187 struct vsp1_hgt
*vsp1_hgt_create(struct vsp1_device
*vsp1
)
189 struct vsp1_hgt
*hgt
;
192 hgt
= devm_kzalloc(vsp1
->dev
, sizeof(*hgt
), GFP_KERNEL
);
194 return ERR_PTR(-ENOMEM
);
196 /* Initialize the control handler. */
197 v4l2_ctrl_handler_init(&hgt
->ctrls
, 1);
198 v4l2_ctrl_new_custom(&hgt
->ctrls
, &hgt_hue_areas
, NULL
);
200 hgt
->histo
.entity
.subdev
.ctrl_handler
= &hgt
->ctrls
;
202 /* Initialize the video device and queue for statistics data. */
203 ret
= vsp1_histogram_init(vsp1
, &hgt
->histo
, VSP1_ENTITY_HGT
, "hgt",
204 &hgt_entity_ops
, hgt_mbus_formats
,
205 ARRAY_SIZE(hgt_mbus_formats
),
206 HGT_DATA_SIZE
, V4L2_META_FMT_VSP1_HGT
);
208 vsp1_entity_destroy(&hgt
->histo
.entity
);
212 v4l2_ctrl_handler_setup(&hgt
->ctrls
);