29
29
#include <media/v4l2-event.h>
30
30
#include <media/v4l2-fwnode.h>
31
31
#include <media/v4l2-mediabus.h>
32
+ #include <media/v4l2-rect.h>
32
33
33
34
/* Chip ID */
34
35
#define IMX219_REG_CHIP_ID CCI_REG16(0x0000)
73
74
/* V_TIMING internal */
74
75
#define IMX219_REG_VTS CCI_REG16(0x0160)
75
76
#define IMX219_VTS_MAX 0xffff
77
+ #define IMX219_VTS_DEF 1763
76
78
77
79
#define IMX219_VBLANK_MIN 32
78
80
146
148
#define IMX219_PIXEL_ARRAY_TOP 8U
147
149
#define IMX219_PIXEL_ARRAY_WIDTH 3280U
148
150
#define IMX219_PIXEL_ARRAY_HEIGHT 2464U
151
+ #define IMX219_MIN_COMPOSE_SIZE 8U
149
152
150
153
/* Mode : resolution and related config&values */
151
154
struct imx219_mode {
@@ -284,6 +287,8 @@ static const u32 imx219_mbus_formats[] = {
284
287
#define IMX219_XCLR_MIN_DELAY_US 6200
285
288
#define IMX219_XCLR_DELAY_RANGE_US 1000
286
289
290
+ static const u32 binning_ratios [] = { 1 , 2 };
291
+
287
292
/* Mode configs */
288
293
static const struct imx219_mode supported_modes [] = {
289
294
{
@@ -296,19 +301,19 @@ static const struct imx219_mode supported_modes[] = {
296
301
/* 1080P 30fps cropped */
297
302
.width = 1920 ,
298
303
.height = 1080 ,
299
- .vts_def = 1763 ,
304
+ .vts_def = IMX219_VTS_DEF ,
300
305
},
301
306
{
302
307
/* 2x2 binned 30fps mode */
303
308
.width = 1640 ,
304
309
.height = 1232 ,
305
- .vts_def = 1763 ,
310
+ .vts_def = IMX219_VTS_DEF ,
306
311
},
307
312
{
308
313
/* 640x480 30fps mode */
309
314
.width = 640 ,
310
315
.height = 480 ,
311
- .vts_def = 1763 ,
316
+ .vts_def = IMX219_VTS_DEF ,
312
317
},
313
318
};
314
319
@@ -809,14 +814,47 @@ static int imx219_enum_frame_size(struct v4l2_subdev *sd,
809
814
return 0 ;
810
815
}
811
816
817
+ static void imx219_refresh_ctrls (struct v4l2_subdev * sd ,
818
+ struct v4l2_subdev_state * state ,
819
+ unsigned int vts_def )
820
+ {
821
+ int exposure_max ;
822
+ int exposure_def ;
823
+ int hblank ;
824
+ struct imx219 * imx219 = to_imx219 (sd );
825
+ struct v4l2_mbus_framefmt * fmt =
826
+ v4l2_subdev_get_pad_format (sd , state , 0 );
827
+
828
+ /* Update limits and set FPS to default */
829
+ __v4l2_ctrl_modify_range (imx219 -> vblank , IMX219_VBLANK_MIN ,
830
+ IMX219_VTS_MAX - fmt -> height , 1 ,
831
+ vts_def - fmt -> height );
832
+ __v4l2_ctrl_s_ctrl (imx219 -> vblank , vts_def - fmt -> height );
833
+ /* Update max exposure while meeting expected vblanking */
834
+ exposure_max = vts_def - 4 ;
835
+ exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT ) ?
836
+ exposure_max :
837
+ IMX219_EXPOSURE_DEFAULT ;
838
+ __v4l2_ctrl_modify_range (imx219 -> exposure , imx219 -> exposure -> minimum ,
839
+ exposure_max , imx219 -> exposure -> step ,
840
+ exposure_def );
841
+ /*
842
+ * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
843
+ * depends on mode->width only, and is not changeble in any
844
+ * way other than changing the mode.
845
+ */
846
+ hblank = IMX219_PPL_DEFAULT - fmt -> width ;
847
+ __v4l2_ctrl_modify_range (imx219 -> hblank , hblank , hblank , 1 , hblank );
848
+ }
849
+
812
850
static int imx219_set_pad_format (struct v4l2_subdev * sd ,
813
851
struct v4l2_subdev_state * state ,
814
852
struct v4l2_subdev_format * fmt )
815
853
{
816
854
struct imx219 * imx219 = to_imx219 (sd );
817
855
const struct imx219_mode * mode ;
818
856
struct v4l2_mbus_framefmt * format ;
819
- struct v4l2_rect * crop ;
857
+ struct v4l2_rect * crop , * compose ;
820
858
unsigned int bin_h , bin_v ;
821
859
822
860
mode = v4l2_find_nearest_size (supported_modes ,
@@ -842,34 +880,14 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
842
880
crop -> left = (IMX219_NATIVE_WIDTH - crop -> width ) / 2 ;
843
881
crop -> top = (IMX219_NATIVE_HEIGHT - crop -> height ) / 2 ;
844
882
845
- if (fmt -> which == V4L2_SUBDEV_FORMAT_ACTIVE ) {
846
- int exposure_max ;
847
- int exposure_def ;
848
- int hblank ;
849
-
850
- /* Update limits and set FPS to default */
851
- __v4l2_ctrl_modify_range (imx219 -> vblank , IMX219_VBLANK_MIN ,
852
- IMX219_VTS_MAX - mode -> height , 1 ,
853
- mode -> vts_def - mode -> height );
854
- __v4l2_ctrl_s_ctrl (imx219 -> vblank ,
855
- mode -> vts_def - mode -> height );
856
- /* Update max exposure while meeting expected vblanking */
857
- exposure_max = mode -> vts_def - 4 ;
858
- exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT ) ?
859
- exposure_max : IMX219_EXPOSURE_DEFAULT ;
860
- __v4l2_ctrl_modify_range (imx219 -> exposure ,
861
- imx219 -> exposure -> minimum ,
862
- exposure_max , imx219 -> exposure -> step ,
863
- exposure_def );
864
- /*
865
- * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
866
- * depends on mode->width only, and is not changeble in any
867
- * way other than changing the mode.
868
- */
869
- hblank = IMX219_PPL_DEFAULT - mode -> width ;
870
- __v4l2_ctrl_modify_range (imx219 -> hblank , hblank , hblank , 1 ,
871
- hblank );
872
- }
883
+ compose = v4l2_subdev_get_pad_compose (sd , state , 0 );
884
+ compose -> width = format -> width ;
885
+ compose -> height = format -> height ;
886
+ compose -> left = 0 ;
887
+ compose -> top = 0 ;
888
+
889
+ if (fmt -> which == V4L2_SUBDEV_FORMAT_ACTIVE )
890
+ imx219_refresh_ctrls (sd , state , mode -> vts_def );
873
891
874
892
return 0 ;
875
893
}
@@ -884,6 +902,11 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
884
902
return 0 ;
885
903
}
886
904
905
+ case V4L2_SEL_TGT_COMPOSE : {
906
+ sel -> r = * v4l2_subdev_get_pad_compose (sd , state , 0 );
907
+ return 0 ;
908
+ }
909
+
887
910
case V4L2_SEL_TGT_NATIVE_SIZE :
888
911
sel -> r .top = 0 ;
889
912
sel -> r .left = 0 ;
@@ -900,11 +923,145 @@ static int imx219_get_selection(struct v4l2_subdev *sd,
900
923
sel -> r .height = IMX219_PIXEL_ARRAY_HEIGHT ;
901
924
902
925
return 0 ;
926
+
927
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT :
928
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS :
929
+ case V4L2_SEL_TGT_COMPOSE_PADDED :
930
+ sel -> r .top = 0 ;
931
+ sel -> r .left = 0 ;
932
+ sel -> r .width = IMX219_PIXEL_ARRAY_WIDTH ;
933
+ sel -> r .height = IMX219_PIXEL_ARRAY_HEIGHT ;
934
+ return 0 ;
903
935
}
904
936
905
937
return - EINVAL ;
906
938
}
907
939
940
+ #define IMX219_ROUND (dim , step , flags ) \
941
+ ((flags) & V4L2_SEL_FLAG_GE ? \
942
+ round_up((dim), (step)) : \
943
+ ((flags) & V4L2_SEL_FLAG_LE ? \
944
+ round_down((dim), (step)) : \
945
+ round_down((dim) + (step) / 2, (step))))
946
+
947
+ static int imx219_set_selection_crop (struct v4l2_subdev * sd ,
948
+ struct v4l2_subdev_state * sd_state ,
949
+ struct v4l2_subdev_selection * sel )
950
+ {
951
+ u32 max_binning ;
952
+ struct v4l2_rect * compose , * crop ;
953
+ struct v4l2_mbus_framefmt * fmt ;
954
+
955
+ crop = v4l2_subdev_get_pad_crop (sd , sd_state , 0 );
956
+ if (v4l2_rect_equal (& sel -> r , crop ))
957
+ return false;
958
+ max_binning = binning_ratios [ARRAY_SIZE (binning_ratios ) - 1 ];
959
+ sel -> r .width =
960
+ clamp (IMX219_ROUND (sel -> r .width , max_binning , sel -> flags ),
961
+ max_binning * IMX219_MIN_COMPOSE_SIZE ,
962
+ IMX219_PIXEL_ARRAY_WIDTH );
963
+ sel -> r .height =
964
+ clamp (IMX219_ROUND (sel -> r .width , max_binning , sel -> flags ),
965
+ max_binning * IMX219_MIN_COMPOSE_SIZE ,
966
+ IMX219_PIXEL_ARRAY_WIDTH );
967
+ sel -> r .left =
968
+ min_t (u32 , sel -> r .left , IMX219_PIXEL_ARRAY_LEFT - sel -> r .width );
969
+ sel -> r .top =
970
+ min_t (u32 , sel -> r .top , IMX219_PIXEL_ARRAY_TOP - sel -> r .top );
971
+
972
+ compose = v4l2_subdev_get_pad_compose (sd , sd_state , 0 );
973
+ fmt = v4l2_subdev_get_pad_format (sd , sd_state , 0 );
974
+ * crop = sel -> r ;
975
+ compose -> height = crop -> height ;
976
+ compose -> width = crop -> width ;
977
+ return true;
978
+ }
979
+
980
+ static int imx219_binning_goodness (u32 act , u32 ask , u32 flags )
981
+ {
982
+ const int goodness = 100000 ;
983
+ int val = 0 ;
984
+
985
+ if (flags & V4L2_SEL_FLAG_GE )
986
+ if (act < ask )
987
+ val -= goodness ;
988
+
989
+ if (flags & V4L2_SEL_FLAG_LE )
990
+ if (act > ask )
991
+ val -= goodness ;
992
+
993
+ val -= abs (act - ask );
994
+
995
+ return val ;
996
+ }
997
+
998
+ static bool imx219_set_selection_compose (struct v4l2_subdev * sd ,
999
+ struct v4l2_subdev_state * state ,
1000
+ struct v4l2_subdev_selection * sel )
1001
+ {
1002
+ int best_goodness ;
1003
+ struct v4l2_rect * compose , * crop ;
1004
+
1005
+ compose = v4l2_subdev_get_pad_compose (sd , state , 0 );
1006
+ if (v4l2_rect_equal (compose , & sel -> r ))
1007
+ return false;
1008
+
1009
+ crop = v4l2_subdev_get_pad_crop (sd , state , 0 );
1010
+
1011
+ best_goodness = INT_MIN ;
1012
+ for (int i = 0 ; i < ARRAY_SIZE (binning_ratios ); ++ i ) {
1013
+ u32 width = crop -> width / binning_ratios [i ];
1014
+ int goodness = imx219_binning_goodness (width , sel -> r .width ,
1015
+ sel -> flags );
1016
+ if (goodness > best_goodness ) {
1017
+ best_goodness = goodness ;
1018
+ compose -> width = width ;
1019
+ }
1020
+ }
1021
+ best_goodness = INT_MIN ;
1022
+ for (int i = 0 ; i < ARRAY_SIZE (binning_ratios ); ++ i ) {
1023
+ u32 height = crop -> height / binning_ratios [i ];
1024
+ int goodness = imx219_binning_goodness (height , sel -> r .height ,
1025
+ sel -> flags );
1026
+ if (goodness > best_goodness ) {
1027
+ best_goodness = goodness ;
1028
+ compose -> height = height ;
1029
+ }
1030
+ }
1031
+ return true;
1032
+ }
1033
+
1034
+ static int imx219_set_selection (struct v4l2_subdev * sd ,
1035
+ struct v4l2_subdev_state * sd_state ,
1036
+ struct v4l2_subdev_selection * sel )
1037
+ {
1038
+ bool compose_updated = false;
1039
+
1040
+ switch (sel -> target ) {
1041
+ case V4L2_SEL_TGT_CROP :
1042
+ compose_updated = imx219_set_selection_crop (sd , sd_state , sel );
1043
+ break ;
1044
+ case V4L2_SEL_TGT_COMPOSE :
1045
+ compose_updated =
1046
+ imx219_set_selection_compose (sd , sd_state , sel );
1047
+ break ;
1048
+ default :
1049
+ return - EINVAL ;
1050
+ }
1051
+ if (compose_updated ) {
1052
+ struct v4l2_rect * compose =
1053
+ v4l2_subdev_get_pad_compose (sd , sd_state , 0 );
1054
+ struct v4l2_mbus_framefmt * fmt =
1055
+ v4l2_subdev_get_pad_format (sd , sd_state , 0 );
1056
+ fmt -> height = compose -> height ;
1057
+ fmt -> width = compose -> width ;
1058
+ }
1059
+ if (compose_updated && sel -> which == V4L2_SUBDEV_FORMAT_ACTIVE )
1060
+ imx219_refresh_ctrls (sd , sd_state , IMX219_VTS_DEF );
1061
+
1062
+ return 0 ;
1063
+ }
1064
+
908
1065
static int imx219_init_cfg (struct v4l2_subdev * sd ,
909
1066
struct v4l2_subdev_state * state )
910
1067
{
@@ -938,6 +1095,7 @@ static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
938
1095
.get_fmt = v4l2_subdev_get_fmt ,
939
1096
.set_fmt = imx219_set_pad_format ,
940
1097
.get_selection = imx219_get_selection ,
1098
+ .set_selection = imx219_set_selection ,
941
1099
.enum_frame_size = imx219_enum_frame_size ,
942
1100
};
943
1101
0 commit comments