2 * vsp1_hgt.c -- R-Car VSP1 Histogram Generator 2D
4 * Copyright (C) 2016 Renesas Electronics Corporation
6 * Contact: Niklas Söderlund (niklas.soderlund@ragnatech.se)
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 HGT_DATA_SIZE ((2 + 6 * 32) * 4)
26 /* -----------------------------------------------------------------------------
30 static inline u32
vsp1_hgt_read(struct vsp1_hgt
*hgt
, u32 reg
)
32 return vsp1_read(hgt
->histo
.entity
.vsp1
, reg
);
35 static inline void vsp1_hgt_write(struct vsp1_hgt
*hgt
, struct vsp1_dl_list
*dl
,
38 vsp1_dl_list_write(dl
, reg
, data
);
41 /* -----------------------------------------------------------------------------
45 void vsp1_hgt_frame_end(struct vsp1_entity
*entity
)
47 struct vsp1_hgt
*hgt
= to_hgt(&entity
->subdev
);
48 struct vsp1_histogram_buffer
*buf
;
53 buf
= vsp1_histogram_buffer_get(&hgt
->histo
);
59 *data
++ = vsp1_hgt_read(hgt
, VI6_HGT_MAXMIN
);
60 *data
++ = vsp1_hgt_read(hgt
, VI6_HGT_SUM
);
62 for (m
= 0; m
< 6; ++m
)
63 for (n
= 0; n
< 32; ++n
)
64 *data
++ = vsp1_hgt_read(hgt
, VI6_HGT_HISTO(m
, n
));
66 vsp1_histogram_buffer_complete(&hgt
->histo
, buf
, HGT_DATA_SIZE
);
69 /* -----------------------------------------------------------------------------
73 #define V4L2_CID_VSP1_HGT_HUE_AREAS (V4L2_CID_USER_BASE | 0x1001)
75 static int hgt_hue_areas_try_ctrl(struct v4l2_ctrl
*ctrl
)
77 const u8
*values
= ctrl
->p_new
.p_u8
;
81 * The hardware has constraints on the hue area boundaries beyond the
82 * control min, max and step. The values must match one of the following
85 * 0L <= 0U <= 1L <= 1U <= 2L <= 2U <= 3L <= 3U <= 4L <= 4U <= 5L <= 5U
86 * 0U <= 1L <= 1U <= 2L <= 2U <= 3L <= 3U <= 4L <= 4U <= 5L <= 5U <= 0L
88 * Start by verifying the common part...
90 for (i
= 1; i
< (HGT_NUM_HUE_AREAS
* 2) - 1; ++i
) {
91 if (values
[i
] > values
[i
+1])
95 /* ... and handle 0L separately. */
96 if (values
[0] > values
[1] && values
[11] > values
[0])
102 static int hgt_hue_areas_s_ctrl(struct v4l2_ctrl
*ctrl
)
104 struct vsp1_hgt
*hgt
= container_of(ctrl
->handler
, struct vsp1_hgt
,
107 memcpy(hgt
->hue_areas
, ctrl
->p_new
.p_u8
, sizeof(hgt
->hue_areas
));
111 static const struct v4l2_ctrl_ops hgt_hue_areas_ctrl_ops
= {
112 .try_ctrl
= hgt_hue_areas_try_ctrl
,
113 .s_ctrl
= hgt_hue_areas_s_ctrl
,
116 static const struct v4l2_ctrl_config hgt_hue_areas
= {
117 .ops
= &hgt_hue_areas_ctrl_ops
,
118 .id
= V4L2_CID_VSP1_HGT_HUE_AREAS
,
119 .name
= "Boundary Values for Hue Area",
120 .type
= V4L2_CTRL_TYPE_U8
,
128 /* -----------------------------------------------------------------------------
129 * VSP1 Entity Operations
132 static void hgt_configure(struct vsp1_entity
*entity
,
133 struct vsp1_pipeline
*pipe
,
134 struct vsp1_dl_list
*dl
,
135 enum vsp1_entity_params params
)
137 struct vsp1_hgt
*hgt
= to_hgt(&entity
->subdev
);
138 struct v4l2_rect
*compose
;
139 struct v4l2_rect
*crop
;
146 if (params
!= VSP1_ENTITY_PARAMS_INIT
)
149 crop
= vsp1_entity_get_pad_selection(entity
, entity
->config
,
150 HISTO_PAD_SINK
, V4L2_SEL_TGT_CROP
);
151 compose
= vsp1_entity_get_pad_selection(entity
, entity
->config
,
153 V4L2_SEL_TGT_COMPOSE
);
155 vsp1_hgt_write(hgt
, dl
, VI6_HGT_REGRST
, VI6_HGT_REGRST_RCLEA
);
157 vsp1_hgt_write(hgt
, dl
, VI6_HGT_OFFSET
,
158 (crop
->left
<< VI6_HGT_OFFSET_HOFFSET_SHIFT
) |
159 (crop
->top
<< VI6_HGT_OFFSET_VOFFSET_SHIFT
));
160 vsp1_hgt_write(hgt
, dl
, VI6_HGT_SIZE
,
161 (crop
->width
<< VI6_HGT_SIZE_HSIZE_SHIFT
) |
162 (crop
->height
<< VI6_HGT_SIZE_VSIZE_SHIFT
));
164 mutex_lock(hgt
->ctrls
.lock
);
165 for (i
= 0; i
< HGT_NUM_HUE_AREAS
; ++i
) {
166 lower
= hgt
->hue_areas
[i
*2 + 0];
167 upper
= hgt
->hue_areas
[i
*2 + 1];
168 vsp1_hgt_write(hgt
, dl
, VI6_HGT_HUE_AREA(i
),
169 (lower
<< VI6_HGT_HUE_AREA_LOWER_SHIFT
) |
170 (upper
<< VI6_HGT_HUE_AREA_UPPER_SHIFT
));
172 mutex_unlock(hgt
->ctrls
.lock
);
174 hratio
= crop
->width
* 2 / compose
->width
/ 3;
175 vratio
= crop
->height
* 2 / compose
->height
/ 3;
176 vsp1_hgt_write(hgt
, dl
, VI6_HGT_MODE
,
177 (hratio
<< VI6_HGT_MODE_HRATIO_SHIFT
) |
178 (vratio
<< VI6_HGT_MODE_VRATIO_SHIFT
));
181 static const struct vsp1_entity_operations hgt_entity_ops
= {
182 .configure
= hgt_configure
,
183 .destroy
= vsp1_histogram_destroy
,
186 /* -----------------------------------------------------------------------------
187 * Initialization and Cleanup
190 static const unsigned int hgt_mbus_formats
[] = {
191 MEDIA_BUS_FMT_AHSV8888_1X32
,
194 struct vsp1_hgt
*vsp1_hgt_create(struct vsp1_device
*vsp1
)
196 struct vsp1_hgt
*hgt
;
199 hgt
= devm_kzalloc(vsp1
->dev
, sizeof(*hgt
), GFP_KERNEL
);
201 return ERR_PTR(-ENOMEM
);
203 /* Initialize the control handler. */
204 v4l2_ctrl_handler_init(&hgt
->ctrls
, 1);
205 v4l2_ctrl_new_custom(&hgt
->ctrls
, &hgt_hue_areas
, NULL
);
207 hgt
->histo
.entity
.subdev
.ctrl_handler
= &hgt
->ctrls
;
209 /* Initialize the video device and queue for statistics data. */
210 ret
= vsp1_histogram_init(vsp1
, &hgt
->histo
, VSP1_ENTITY_HGT
, "hgt",
211 &hgt_entity_ops
, hgt_mbus_formats
,
212 ARRAY_SIZE(hgt_mbus_formats
),
213 HGT_DATA_SIZE
, V4L2_META_FMT_VSP1_HGT
);
215 vsp1_entity_destroy(&hgt
->histo
.entity
);
219 v4l2_ctrl_handler_setup(&hgt
->ctrls
);