From: Zheng Yang Date: Thu, 10 May 2012 03:05:35 +0000 (+0800) Subject: rk30 hdmi: X-Git-Tag: firefly_0821_release~9210 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=92618408f502cce5a3da7c3c050a76d2156b0c22;p=firefly-linux-kernel-4.4.55.git rk30 hdmi: 1. Support video pixel data color space convertion. 2. Output video color mode accrording EDID: When sink declares support YCbCr, hdmi should send YCbCr pixel data. Otherwise, hdmi should send RGB pixel data. --- diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c b/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c index 0c3bf081272a..9c75c3031c41 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c +++ b/drivers/video/rockchip/hdmi/rk30_hdmi_hw.c @@ -197,39 +197,158 @@ static void rk30_hdmi_config_phy(unsigned char vic) static void rk30_hdmi_config_avi(unsigned char vic, unsigned char output_color) { - int i; + int i, clolorimetry, aspect_ratio; char info[SIZE_AVI_INFOFRAME]; - HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); - HDMIWrReg(CONTROL_PACKET_HB0, 0x82); - HDMIWrReg(CONTROL_PACKET_HB1, 0x2); - HDMIWrReg(CONTROL_PACKET_HB2, 0x0D); memset(info, 0, SIZE_AVI_INFOFRAME); + HDMIWrReg(CONTROL_PACKET_BUF_INDEX, INFOFRAME_AVI); + info[0] = 0x82; + info[1] = 0x02; + info[2] = 0x0D; + info[3] = info[0] + info[1] + info[2]; + + if(output_color == VIDEO_OUTPUT_YCBCR444) + info[4] = (AVI_COLOR_MODE_YCBCR444 << 5); + else if(output_color == VIDEO_OUTPUT_YCBCR422) + info[4] = (AVI_COLOR_MODE_YCBCR422 << 5); + else + info[4] = (AVI_COLOR_MODE_RGB << 5); + info[4] |= (1 << 4); //Enable active format data bits is present in info[2] + + switch(vic) + { + case HDMI_720x480i_60Hz_4_3: + case HDMI_720x576i_50Hz_4_3: + case HDMI_720x480p_60Hz_4_3: + case HDMI_720x576p_50Hz_4_3: + aspect_ratio = AVI_CODED_FRAME_ASPECT_4_3; + clolorimetry = AVI_COLORIMETRY_SMPTE_170M; + break; + case HDMI_720x480i_60Hz_16_9: + case HDMI_720x576i_50Hz_16_9: + case HDMI_720x480p_60Hz_16_9: + case HDMI_720x576p_50Hz_16_9: + aspect_ratio = AVI_CODED_FRAME_ASPECT_16_9; + clolorimetry = AVI_COLORIMETRY_SMPTE_170M; + break; + default: + aspect_ratio = AVI_CODED_FRAME_ASPECT_16_9; + clolorimetry = AVI_COLORIMETRY_ITU709; + } + + if(output_color == VIDEO_OUTPUT_RGB444) + clolorimetry = AVI_COLORIMETRY_NO_DATA; - info[1] = (AVI_COLOR_MODE_RGB << 5); - info[2] = (AVI_COLORIMETRY_NO_DATA << 6) | (AVI_CODED_FRAME_ASPECT_NO_DATA << 4) | ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME; - info[3] = 0; - info[4] = vic; - info[5] = 0; + info[5] = (clolorimetry << 6) | (aspect_ratio << 4) | ACTIVE_ASPECT_RATE_SAME_AS_CODED_FRAME; + info[6] = 0; + info[7] = vic; + info[8] = 0; // Calculate AVI InfoFrame ChecKsum - info[0] = 0x82 + 0x02 +0x0D; - for (i = 1; i < SIZE_AVI_INFOFRAME; i++) + for (i = 4; i < SIZE_AVI_INFOFRAME; i++) { - info[0] += info[i]; + info[3] += info[i]; } - info[0] = 0x100 - info[0]; + info[3] = 0x100 - info[3]; for(i = 0; i < SIZE_AVI_INFOFRAME; i++) - HDMIWrReg(CONTROL_PACKET_PB_ADDR + i*4, info[i]); + HDMIWrReg(CONTROL_PACKET_HB0 + i*4, info[i]); } + +static char coeff_csc[][24] = { + //G B R Bias + { //CSC_RGB_0_255_TO_ITU601_16_235 + 0x11, 0xb6, 0x02, 0x0b, 0x10, 0x55, 0x00, 0x80, //Cr + 0x02, 0x59, 0x01, 0x32, 0x00, 0x75, 0x00, 0x10, //Y + 0x11, 0x5b, 0x10, 0xb0, 0x02, 0x0b, 0x00, 0x80, //Cb + }, + { //CSC_RGB_0_255_TO_ITU709_16_235 + 0x11, 0xdb, 0x02, 0x0b, 0x10, 0x30, 0x00, 0x80, //Cr + 0x02, 0xdc, 0x00, 0xda, 0x00, 0x4a, 0x00, 0x10, //Y + 0x11, 0x93, 0x10, 0x78, 0x02, 0x0b, 0x00, 0x80, //Cb + }, + //Y Cr Cb Bias + { //CSC_ITU601_16_235_TO_RGB_16_235 + 0x04, 0x00, 0x05, 0x7c, 0x00, 0x00, 0x02, 0xaf, //R + 0x04, 0x00, 0x12, 0xcb, 0x11, 0x58, 0x00, 0x84, //G + 0x04, 0x00, 0x00, 0x00, 0x06, 0xee, 0x02, 0xde, //B + }, + { //CSC_ITU709_16_235_TO_RGB_16_235 + 0x04, 0x00, 0x06, 0x29, 0x00, 0x00, 0x02, 0xc5, //R + 0x04, 0x00, 0x11, 0xd6, 0x10, 0xbb, 0x00, 0x52, //G + 0x04, 0x00, 0x00, 0x00, 0x07, 0x44, 0x02, 0xe8, //B + }, + { //CSC_ITU601_16_235_TO_RGB_0_255 + 0x04, 0xa8, 0x05, 0x7c, 0x00, 0x00, 0x02, 0xc2, //R + 0x04, 0xa8, 0x12, 0xcb, 0x11, 0x58, 0x00, 0x72, //G + 0x04, 0xa8, 0x00, 0x00, 0x06, 0xee, 0x02, 0xf0, //B + }, + { //CSC_ITU709_16_235_TO_RGB_0_255 + 0x04, 0xa8, 0x06, 0x29, 0x00, 0x00, 0x02, 0xd8, //R + 0x04, 0xa8, 0x11, 0xd6, 0x10, 0xbb, 0x00, 0x40, //G + 0x04, 0xa8, 0x00, 0x00, 0x07, 0x44, 0x02, 0xfb, //B + }, + +}; -int rk30_hdmi_config_video(int vic, int output_color, int output_mode) +static void rk30_hdmi_config_csc(struct rk30_hdmi_video_para *vpara) +{ + int i, temp, mode; + char *coeff = NULL; + + if( ((vpara->input_color == VIDEO_INPUT_COLOR_RGB) && (vpara->output_color == VIDEO_OUTPUT_RGB444)) || + ((vpara->input_color == VIDEO_INPUT_COLOR_YCBCR) && (vpara->output_color != VIDEO_OUTPUT_RGB444) )) + { + HDMIWrReg(CSC_CONFIG1, v_CSC_MODE(CSC_MODE_AUTO) | v_CSC_BRSWAP_DIABLE(1)); + return; + } + + switch(vpara->vic) + { + case HDMI_720x480i_60Hz_4_3: + case HDMI_720x576i_50Hz_4_3: + case HDMI_720x480p_60Hz_4_3: + case HDMI_720x576p_50Hz_4_3: + case HDMI_720x480i_60Hz_16_9: + case HDMI_720x576i_50Hz_16_9: + case HDMI_720x480p_60Hz_16_9: + case HDMI_720x576p_50Hz_16_9: + if(vpara->input_color == VIDEO_INPUT_COLOR_RGB) + mode = CSC_RGB_0_255_TO_ITU601_16_235; + else if(vpara->output_mode == OUTPUT_HDMI) + mode = CSC_ITU601_16_235_TO_RGB_16_235; + else + mode = CSC_ITU601_16_235_TO_RGB_0_255; + break; + default: + if(vpara->input_color == VIDEO_INPUT_COLOR_RGB) + mode = CSC_RGB_0_255_TO_ITU709_16_235; + else if(vpara->output_mode == OUTPUT_HDMI) + mode = CSC_ITU709_16_235_TO_RGB_16_235; + else + mode = CSC_ITU709_16_235_TO_RGB_0_255; + break; + } + + coeff = coeff_csc[mode]; + + HDMIMskReg(temp, CSC_CONFIG1, m_CSC_MODE, v_CSC_MODE(CSC_MODE_MANUAL)); + + for(i = 0; i < 24; i++) + HDMIWrReg(CSC_PARA_C0_H + i*4, coeff[i]); + + HDMIWrReg(AV_CTRL2, v_CSC_ENABLE(1)); +} + +//int rk30_hdmi_config_video(int vic, int output_color, int output_mode) +int rk30_hdmi_config_video(struct rk30_hdmi_video_para *vpara) { int value; struct fb_videomode *mode; hdmi_dbg(hdmi->dev, "[%s]\n", __FUNCTION__); + if(vpara == NULL) + return -1; if(hdmi->pwr_mode == PWR_SAVE_MODE_E) rk30_hdmi_set_pwr_mode(PWR_SAVE_MODE_D); @@ -238,18 +357,20 @@ int rk30_hdmi_config_video(int vic, int output_color, int output_mode) // Input video mode is RGB24bit, Data enable signal from external HDMIMskReg(value, AV_CTRL1, m_INPUT_VIDEO_MODE | m_DE_SIGNAL_SELECT, \ - v_INPUT_VIDEO_MODE(VIDEO_INPUT_RGB_YCBCR_444) | EXTERNAL_DE) + v_INPUT_VIDEO_MODE(vpara->input_mode) | EXTERNAL_DE) HDMIMskReg(value, VIDEO_CTRL1, m_VIDEO_OUTPUT_MODE | m_VIDEO_INPUT_DEPTH | m_VIDEO_INPUT_COLOR_MODE, \ - v_VIDEO_OUTPUT_MODE(output_color) | v_VIDEO_INPUT_DEPTH(VIDEO_INPUT_DEPTH_8BIT) | VIDEO_INPUT_COLOR_RGB) - + v_VIDEO_OUTPUT_MODE(vpara->output_color) | v_VIDEO_INPUT_DEPTH(VIDEO_INPUT_DEPTH_8BIT) | vpara->input_color) + HDMIWrReg(DEEP_COLOR_MODE, 0x20); + // color space convert + rk30_hdmi_config_csc(vpara); // Set HDMI Mode - HDMIWrReg(HDCP_CTRL, v_HDMI_DVI(output_mode)); + HDMIWrReg(HDCP_CTRL, v_HDMI_DVI(vpara->output_mode)); // Set ext video - mode = (struct fb_videomode *)hdmi_vic_to_videomode(vic); + mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic); if(mode == NULL) { - hdmi_dbg(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vic); + hdmi_dbg(hdmi->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic); return -ENOENT; } value = v_EXT_VIDEO_ENABLE(1) | v_INTERLACE(mode->vmode); @@ -287,14 +408,15 @@ int rk30_hdmi_config_video(int vic, int output_color, int output_mode) value = mode->vsync_len; HDMIWrReg(EXT_VIDEO_PARA_VSYNCWIDTH, value & 0xFF); - if(output_mode == OUTPUT_HDMI) { - rk30_hdmi_config_avi(vic, output_mode); + if(vpara->output_mode == OUTPUT_HDMI) { + rk30_hdmi_config_avi(vpara->vic, vpara->output_color); hdmi_dbg(hdmi->dev, "[%s] sucess output HDMI.\n", __FUNCTION__); } else { hdmi_dbg(hdmi->dev, "[%s] sucess output DVI.\n", __FUNCTION__); } - rk30_hdmi_config_phy(vic); + + rk30_hdmi_config_phy(vpara->vic); rk30_hdmi_control_output(0); return 0; } diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.h b/drivers/video/rockchip/hdmi/rk30_hdmi_hw.h index df2c258f0106..968614f9b9b0 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_hw.h +++ b/drivers/video/rockchip/hdmi/rk30_hdmi_hw.h @@ -78,6 +78,11 @@ enum { #define m_DE_SIGNAL_SELECT (1 << 0) /* HDMI_AV_CTRL2 */ +#define AV_CTRL2 0xec +#define m_CSC_ENABLE (1 << 0) +#define v_CSC_ENABLE(n) (n) + +/* HDMI_VIDEO_CTRL1 */ #define VIDEO_CTRL1 0x58 enum { VIDEO_OUTPUT_RGB444 = 0, @@ -116,6 +121,56 @@ enum{ #define TMDS_CLOCK_MODE_MASK 0x3 << 6 #define TMDS_CLOCK_MODE(n) (n) << 6 +#define CSC_PARA_C0_H 0x60 +#define CSC_PARA_C0_L 0x64 +#define CSC_PARA_C1_H 0x68 +#define CSC_PARA_C1_L 0x6c +#define CSC_PARA_C2_H 0x70 +#define CSC_PARA_C2_L 0x74 +#define CSC_PARA_C3_H 0x78 +#define CSC_PARA_C3_L 0x7c +#define CSC_PARA_C4_H 0x80 +#define CSC_PARA_C4_L 0x84 +#define CSC_PARA_C5_H 0x88 +#define CSC_PARA_C5_L 0x8c +#define CSC_PARA_C6_H 0x90 +#define CSC_PARA_C6_L 0x94 +#define CSC_PARA_C7_H 0x98 +#define CSC_PARA_C7_L 0x9c +#define CSC_PARA_C8_H 0xa0 +#define CSC_PARA_C8_L 0xa4 +#define CSC_PARA_C9_H 0xa8 +#define CSC_PARA_C10_H 0xac +#define CSC_PARA_C10_L 0xb4 +#define CSC_PARA_C11_H 0xb8 +#define CSC_PARA_C11_L 0xbc + +#define CSC_CONFIG1 0x34c +#define m_CSC_MODE (1 << 7) +#define m_CSC_COEF_MODE (0xF << 3) //Only used in auto csc mode +#define m_CSC_STATUS (1 << 2) +#define m_CSC_VID_SELECT (1 << 1) +#define m_CSC_BRSWAP_DIABLE (1) + +enum { + CSC_MODE_MANUAL = 0, + CSC_MODE_AUTO +}; +#define v_CSC_MODE(n) (n << 7) +enum { + COE_SDTV_LIMITED_RANGE = 0x08, + COE_SDTV_FULL_RANGE = 0x04, + COE_HDTV_60Hz = 0x2, + COE_HDTV_50Hz = 0x1 +}; +#define v_CSC_COE_MODE(n) (n << 3) +enum { + CSC_INPUT_VID_5_19 = 0, + CSC_INPUT_VID_28_29 +}; +#define v_CSC_VID_SELECT(n) (n << 1) +#define v_CSC_BRSWAP_DIABLE(n) (n) + /* VIDEO_SETTING2 */ #define VIDEO_SETTING2 0x114 #define m_UNMUTE (1 << 7) @@ -139,7 +194,7 @@ enum { #define CONTROL_PACKET_HB1 0x184 #define CONTROL_PACKET_HB2 0x188 #define CONTROL_PACKET_PB_ADDR 0x18c -#define SIZE_AVI_INFOFRAME 0xe // 14 bytes +#define SIZE_AVI_INFOFRAME 0x11 // 17 bytes #define SIZE_AUDIO_INFOFRAME 0x0F // 15 bytes enum { AVI_COLOR_MODE_RGB = 0, @@ -288,10 +343,29 @@ enum { temp = __raw_readl(hdmi->regbase + addr) & (0xFF - (msk)) ; \ __raw_writel(temp | ( (val) & (msk) ), hdmi->regbase + addr); +/* RK30 HDMI Video Configure Parameters */ +struct rk30_hdmi_video_para { + int vic; + int input_mode; //input video data interface + int input_color; //input video color mode + int output_mode; //output hdmi or dvi + int output_color; //output video color mode +}; + +/* Color Space Convertion Mode */ +enum { + CSC_RGB_0_255_TO_ITU601_16_235 = 0, //RGB 0-255 input to YCbCr 16-235 output according BT601 + CSC_RGB_0_255_TO_ITU709_16_235, //RGB 0-255 input to YCbCr 16-235 output accroding BT709 + CSC_ITU601_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT601 + CSC_ITU709_16_235_TO_RGB_16_235, //YCbCr 16-235 input to RGB 16-235 output according BT709 + CSC_ITU601_16_235_TO_RGB_0_255, //YCbCr 16-235 input to RGB 0-255 output according BT601 + CSC_ITU709_16_235_TO_RGB_0_255 //YCbCr 16-235 input to RGB 0-255 output according BT709 +}; + extern int rk30_hdmi_detect_hotplug(void); extern int rk30_hdmi_read_edid(int block, unsigned char *buff); extern int rk30_hdmi_removed(void); -extern int rk30_hdmi_config_video(int vic, int output_color, int output_mode); +extern int rk30_hdmi_config_video(struct rk30_hdmi_video_para *vpara); extern int rk30_hdmi_config_audio(struct hdmi_audio *audio); extern void rk30_hdmi_control_output(int enable); #endif \ No newline at end of file diff --git a/drivers/video/rockchip/hdmi/rk30_hdmi_task.c b/drivers/video/rockchip/hdmi/rk30_hdmi_task.c index 03a9b63a80f0..b4c9c2c37e77 100755 --- a/drivers/video/rockchip/hdmi/rk30_hdmi_task.c +++ b/drivers/video/rockchip/hdmi/rk30_hdmi_task.c @@ -162,6 +162,7 @@ void hdmi_work(struct work_struct *work) { int hotplug, state_last; int rc = HDMI_ERROR_SUCESS, trytimes = 0; + struct rk30_hdmi_video_para video; mutex_lock(&work_mutex); /* Process hdmi command */ @@ -230,7 +231,17 @@ void hdmi_work(struct work_struct *work) break; case CONFIG_VIDEO: hdmi->display = HDMI_DISABLE; - rc = rk30_hdmi_config_video(hdmi->vic, VIDEO_OUTPUT_RGB444, hdmi->edid.sink_hdmi); + video.vic = hdmi->vic; + video.input_mode = VIDEO_INPUT_RGB_YCBCR_444; + video.input_color = VIDEO_INPUT_COLOR_RGB;//VIDEO_INPUT_COLOR_YCBCR + video.output_mode = hdmi->edid.sink_hdmi; + if(hdmi->edid.ycbcr444) + video.output_color = VIDEO_OUTPUT_YCBCR444; + else if(hdmi->edid.ycbcr422) + video.output_color = VIDEO_OUTPUT_YCBCR422; + else + video.output_color = VIDEO_OUTPUT_RGB444; + rc = rk30_hdmi_config_video(&video); if(rc == HDMI_ERROR_SUCESS) { if(hdmi->edid.sink_hdmi)