diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2014-11-27 08:07:38 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-12-02 08:18:10 -0500 |
commit | 1fb69bfd29e4b2e5e93922105326dd6cbd5ef6eb (patch) | |
tree | 6dba331c7ae6a7dd37c41ada06c56ced2eec345b | |
parent | 3e8a78d13997bc559aad626dfa0fb26e50a99676 (diff) |
[media] adv7511: improve colorspace handling
Add support for YCbCr output and support setting colorspace,
YCbCr encoding and quantization for the AVI InfoFrame.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r-- | drivers/media/i2c/adv7511.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 8acc8c5d67d7..81736aaf0f31 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/videodev2.h> | 26 | #include <linux/videodev2.h> |
27 | #include <linux/gpio.h> | 27 | #include <linux/gpio.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/hdmi.h> | ||
29 | #include <linux/v4l2-dv-timings.h> | 30 | #include <linux/v4l2-dv-timings.h> |
30 | #include <media/v4l2-device.h> | 31 | #include <media/v4l2-device.h> |
31 | #include <media/v4l2-common.h> | 32 | #include <media/v4l2-common.h> |
@@ -96,6 +97,10 @@ struct adv7511_state { | |||
96 | bool have_monitor; | 97 | bool have_monitor; |
97 | /* timings from s_dv_timings */ | 98 | /* timings from s_dv_timings */ |
98 | struct v4l2_dv_timings dv_timings; | 99 | struct v4l2_dv_timings dv_timings; |
100 | u32 fmt_code; | ||
101 | u32 colorspace; | ||
102 | u32 ycbcr_enc; | ||
103 | u32 quantization; | ||
99 | /* controls */ | 104 | /* controls */ |
100 | struct v4l2_ctrl *hdmi_mode_ctrl; | 105 | struct v4l2_ctrl *hdmi_mode_ctrl; |
101 | struct v4l2_ctrl *hotplug_ctrl; | 106 | struct v4l2_ctrl *hotplug_ctrl; |
@@ -804,8 +809,209 @@ static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) | |||
804 | return 0; | 809 | return 0; |
805 | } | 810 | } |
806 | 811 | ||
812 | static int adv7511_enum_mbus_code(struct v4l2_subdev *sd, | ||
813 | struct v4l2_subdev_fh *fh, | ||
814 | struct v4l2_subdev_mbus_code_enum *code) | ||
815 | { | ||
816 | if (code->pad != 0) | ||
817 | return -EINVAL; | ||
818 | |||
819 | switch (code->index) { | ||
820 | case 0: | ||
821 | code->code = MEDIA_BUS_FMT_RGB888_1X24; | ||
822 | break; | ||
823 | case 1: | ||
824 | code->code = MEDIA_BUS_FMT_YUYV8_1X16; | ||
825 | break; | ||
826 | case 2: | ||
827 | code->code = MEDIA_BUS_FMT_UYVY8_1X16; | ||
828 | break; | ||
829 | default: | ||
830 | return -EINVAL; | ||
831 | } | ||
832 | return 0; | ||
833 | } | ||
834 | |||
835 | static void adv7511_fill_format(struct adv7511_state *state, | ||
836 | struct v4l2_mbus_framefmt *format) | ||
837 | { | ||
838 | memset(format, 0, sizeof(*format)); | ||
839 | |||
840 | format->width = state->dv_timings.bt.width; | ||
841 | format->height = state->dv_timings.bt.height; | ||
842 | format->field = V4L2_FIELD_NONE; | ||
843 | } | ||
844 | |||
845 | static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
846 | struct v4l2_subdev_format *format) | ||
847 | { | ||
848 | struct adv7511_state *state = get_adv7511_state(sd); | ||
849 | |||
850 | if (format->pad != 0) | ||
851 | return -EINVAL; | ||
852 | |||
853 | adv7511_fill_format(state, &format->format); | ||
854 | |||
855 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
856 | struct v4l2_mbus_framefmt *fmt; | ||
857 | |||
858 | fmt = v4l2_subdev_get_try_format(fh, format->pad); | ||
859 | format->format.code = fmt->code; | ||
860 | format->format.colorspace = fmt->colorspace; | ||
861 | format->format.ycbcr_enc = fmt->ycbcr_enc; | ||
862 | format->format.quantization = fmt->quantization; | ||
863 | } else { | ||
864 | format->format.code = state->fmt_code; | ||
865 | format->format.colorspace = state->colorspace; | ||
866 | format->format.ycbcr_enc = state->ycbcr_enc; | ||
867 | format->format.quantization = state->quantization; | ||
868 | } | ||
869 | |||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | static int adv7511_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
874 | struct v4l2_subdev_format *format) | ||
875 | { | ||
876 | struct adv7511_state *state = get_adv7511_state(sd); | ||
877 | /* | ||
878 | * Bitfield namings come the CEA-861-F standard, table 8 "Auxiliary | ||
879 | * Video Information (AVI) InfoFrame Format" | ||
880 | * | ||
881 | * c = Colorimetry | ||
882 | * ec = Extended Colorimetry | ||
883 | * y = RGB or YCbCr | ||
884 | * q = RGB Quantization Range | ||
885 | * yq = YCC Quantization Range | ||
886 | */ | ||
887 | u8 c = HDMI_COLORIMETRY_NONE; | ||
888 | u8 ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; | ||
889 | u8 y = HDMI_COLORSPACE_RGB; | ||
890 | u8 q = HDMI_QUANTIZATION_RANGE_DEFAULT; | ||
891 | u8 yq = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; | ||
892 | |||
893 | if (format->pad != 0) | ||
894 | return -EINVAL; | ||
895 | switch (format->format.code) { | ||
896 | case MEDIA_BUS_FMT_UYVY8_1X16: | ||
897 | case MEDIA_BUS_FMT_YUYV8_1X16: | ||
898 | case MEDIA_BUS_FMT_RGB888_1X24: | ||
899 | break; | ||
900 | default: | ||
901 | return -EINVAL; | ||
902 | } | ||
903 | |||
904 | adv7511_fill_format(state, &format->format); | ||
905 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
906 | struct v4l2_mbus_framefmt *fmt; | ||
907 | |||
908 | fmt = v4l2_subdev_get_try_format(fh, format->pad); | ||
909 | fmt->code = format->format.code; | ||
910 | fmt->colorspace = format->format.colorspace; | ||
911 | fmt->ycbcr_enc = format->format.ycbcr_enc; | ||
912 | fmt->quantization = format->format.quantization; | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | switch (format->format.code) { | ||
917 | case MEDIA_BUS_FMT_UYVY8_1X16: | ||
918 | adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01); | ||
919 | adv7511_wr_and_or(sd, 0x16, 0x03, 0xb8); | ||
920 | y = HDMI_COLORSPACE_YUV422; | ||
921 | break; | ||
922 | case MEDIA_BUS_FMT_YUYV8_1X16: | ||
923 | adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01); | ||
924 | adv7511_wr_and_or(sd, 0x16, 0x03, 0xbc); | ||
925 | y = HDMI_COLORSPACE_YUV422; | ||
926 | break; | ||
927 | case MEDIA_BUS_FMT_RGB888_1X24: | ||
928 | default: | ||
929 | adv7511_wr_and_or(sd, 0x15, 0xf0, 0x00); | ||
930 | adv7511_wr_and_or(sd, 0x16, 0x03, 0x00); | ||
931 | break; | ||
932 | } | ||
933 | state->fmt_code = format->format.code; | ||
934 | state->colorspace = format->format.colorspace; | ||
935 | state->ycbcr_enc = format->format.ycbcr_enc; | ||
936 | state->quantization = format->format.quantization; | ||
937 | |||
938 | switch (format->format.colorspace) { | ||
939 | case V4L2_COLORSPACE_ADOBERGB: | ||
940 | c = HDMI_COLORIMETRY_EXTENDED; | ||
941 | ec = y ? HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601 : | ||
942 | HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB; | ||
943 | break; | ||
944 | case V4L2_COLORSPACE_SMPTE170M: | ||
945 | c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE; | ||
946 | if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV601) { | ||
947 | c = HDMI_COLORIMETRY_EXTENDED; | ||
948 | ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; | ||
949 | } | ||
950 | break; | ||
951 | case V4L2_COLORSPACE_REC709: | ||
952 | c = y ? HDMI_COLORIMETRY_ITU_709 : HDMI_COLORIMETRY_NONE; | ||
953 | if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV709) { | ||
954 | c = HDMI_COLORIMETRY_EXTENDED; | ||
955 | ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; | ||
956 | } | ||
957 | break; | ||
958 | case V4L2_COLORSPACE_SRGB: | ||
959 | c = y ? HDMI_COLORIMETRY_EXTENDED : HDMI_COLORIMETRY_NONE; | ||
960 | ec = y ? HDMI_EXTENDED_COLORIMETRY_S_YCC_601 : | ||
961 | HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; | ||
962 | break; | ||
963 | case V4L2_COLORSPACE_BT2020: | ||
964 | c = HDMI_COLORIMETRY_EXTENDED; | ||
965 | if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM) | ||
966 | ec = 5; /* Not yet available in hdmi.h */ | ||
967 | else | ||
968 | ec = 6; /* Not yet available in hdmi.h */ | ||
969 | break; | ||
970 | default: | ||
971 | break; | ||
972 | } | ||
973 | |||
974 | /* | ||
975 | * CEA-861-F says that for RGB formats the YCC range must match the | ||
976 | * RGB range, although sources should ignore the YCC range. | ||
977 | * | ||
978 | * The RGB quantization range shouldn't be non-zero if the EDID doesn't | ||
979 | * have the Q bit set in the Video Capabilities Data Block, however this | ||
980 | * isn't checked at the moment. The assumption is that the application | ||
981 | * knows the EDID and can detect this. | ||
982 | * | ||
983 | * The same is true for the YCC quantization range: non-standard YCC | ||
984 | * quantization ranges should only be sent if the EDID has the YQ bit | ||
985 | * set in the Video Capabilities Data Block. | ||
986 | */ | ||
987 | switch (format->format.quantization) { | ||
988 | case V4L2_QUANTIZATION_FULL_RANGE: | ||
989 | q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT : | ||
990 | HDMI_QUANTIZATION_RANGE_FULL; | ||
991 | yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_FULL; | ||
992 | break; | ||
993 | case V4L2_QUANTIZATION_LIM_RANGE: | ||
994 | q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT : | ||
995 | HDMI_QUANTIZATION_RANGE_LIMITED; | ||
996 | yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_LIMITED; | ||
997 | break; | ||
998 | } | ||
999 | |||
1000 | adv7511_wr_and_or(sd, 0x4a, 0xbf, 0); | ||
1001 | adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5); | ||
1002 | adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6); | ||
1003 | adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2)); | ||
1004 | adv7511_wr_and_or(sd, 0x59, 0x0f, yq << 4); | ||
1005 | adv7511_wr_and_or(sd, 0x4a, 0xff, 1); | ||
1006 | |||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
807 | static const struct v4l2_subdev_pad_ops adv7511_pad_ops = { | 1010 | static const struct v4l2_subdev_pad_ops adv7511_pad_ops = { |
808 | .get_edid = adv7511_get_edid, | 1011 | .get_edid = adv7511_get_edid, |
1012 | .enum_mbus_code = adv7511_enum_mbus_code, | ||
1013 | .get_fmt = adv7511_get_fmt, | ||
1014 | .set_fmt = adv7511_set_fmt, | ||
809 | .enum_dv_timings = adv7511_enum_dv_timings, | 1015 | .enum_dv_timings = adv7511_enum_dv_timings, |
810 | .dv_timings_cap = adv7511_dv_timings_cap, | 1016 | .dv_timings_cap = adv7511_dv_timings_cap, |
811 | }; | 1017 | }; |
@@ -1123,6 +1329,8 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * | |||
1123 | return -ENODEV; | 1329 | return -ENODEV; |
1124 | } | 1330 | } |
1125 | memcpy(&state->pdata, pdata, sizeof(state->pdata)); | 1331 | memcpy(&state->pdata, pdata, sizeof(state->pdata)); |
1332 | state->fmt_code = MEDIA_BUS_FMT_RGB888_1X24; | ||
1333 | state->colorspace = V4L2_COLORSPACE_SRGB; | ||
1126 | 1334 | ||
1127 | sd = &state->sd; | 1335 | sd = &state->sd; |
1128 | 1336 | ||