Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
1fb69bfd 3e8a78d1

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