/* * Copyright@ Samsung Electronics Co. LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 //#define LOG_TAG "libhdmi" //#define DEBUG_HDMI_HW_LEVEL #include #include #include #include #include #include #include #include #include #include #include #include "sec_utils_v4l2.h" #include "s5p_tvout_v4l2.h" #include "videodev2.h" #if defined(BOARD_USES_HDMI_FIMGAPI) #include "sec_g2d_4x.h" #include "FimgApi.h" #endif #include "audio.h" #include "video.h" #include "../libhdmi/libsForhdmi/libedid/libedid.h" #include "../libhdmi/libsForhdmi/libcec/libcec.h" #include "SecGscaler.h" #include "SecHdmiCommon.h" #include "SecHdmiV4L2Utils.h" namespace android { unsigned int output_type = V4L2_OUTPUT_TYPE_DIGITAL; v4l2_std_id t_std_id = V4L2_STD_1080P_30; int g_hpd_state = HPD_CABLE_OUT; unsigned int g_hdcp_en = 0; #if defined(BOARD_USES_HDMI_FIMGAPI) unsigned int g2d_reserved_memory0 = 0; unsigned int g2d_reserved_memory1 = 0; unsigned int g2d_reserved_memory_size = 0; unsigned int cur_g2d_address = 0; #endif void display_menu(void) { struct HDMIVideoParameter video; struct HDMIAudioParameter audio; #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif audio.formatCode = LPCM_FORMAT; audio.outPacket = HDMI_ASP; audio.channelNum = CH_2; audio.sampleFreq = SF_44KHZ; LOGI("=============== HDMI Audio =============\n"); if (EDIDAudioModeSupport(&audio)) LOGI("= 2CH_PCM 44100Hz audio supported =\n"); LOGI("========= HDMI Mode & Color Space =======\n"); video.mode = HDMI; if (EDIDHDMIModeSupport(&video)) { video.colorSpace = HDMI_CS_YCBCR444; if (EDIDColorSpaceSupport(&video)) LOGI("= 1. HDMI(YCbCr) =\n"); video.colorSpace = HDMI_CS_RGB; if (EDIDColorSpaceSupport(&video)) LOGI("= 2. HDMI(RGB) =\n"); } else { video.mode = DVI; if (EDIDHDMIModeSupport(&video)) LOGI("= 3. DVI =\n"); } LOGI("=========== HDMI Rseolution ========\n"); /* 480P */ video.resolution = v720x480p_60Hz; video.pixelAspectRatio = HDMI_PIXEL_RATIO_16_9; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 4. 480P_60_16_9 (0x04000000) =\n"); video.resolution = v640x480p_60Hz; video.pixelAspectRatio = HDMI_PIXEL_RATIO_4_3; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 5. 480P_60_4_3 (0x05000000) =\n"); /* 576P */ video.resolution = v720x576p_50Hz; video.pixelAspectRatio = HDMI_PIXEL_RATIO_16_9; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 6. 576P_50_16_9 (0x06000000) =\n"); video.pixelAspectRatio = HDMI_PIXEL_RATIO_4_3; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 7. 576P_50_4_3 (0x07000000) =\n"); /* 720P 60 */ video.resolution = v1280x720p_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 8. 720P_60 (0x08000000) =\n"); /* 720P_50 */ video.resolution = v1280x720p_50Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 9. 720P_50 (0x09000000) =\n"); /* 1080P_60 */ video.resolution = v1920x1080p_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= a. 1080P_60 (0x0a000000) =\n"); /* 1080P_50 */ video.resolution = v1920x1080p_50Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= b. 1080P_50 (0x0b000000) =\n"); /* 1080I_60 */ video.resolution = v1920x1080i_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= c. 1080I_60 (0x0c000000) =\n"); /* 1080I_50 */ video.resolution = v1920x1080i_50Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= d. 1080I_50 (0x0d000000) =\n"); /* 1080P_30 */ video.resolution = v1920x1080p_30Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= e. 1080P_30 (0x12000000) =\n"); LOGI("=========== HDMI 3D Format ========\n"); /* 720P_60_SBS_HALF */ video.resolution = v1280x720p_60Hz; video.hdmi_3d_format = HDMI_3D_SSH_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= f. 720P_60_SBS_HALF (0x13000000) =\n"); /* 720P_59_SBS_HALF */ video.resolution = v1280x720p_60Hz; video.hdmi_3d_format = HDMI_3D_SSH_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 10. 720P_59_SBS_HALF (0x14000000) =\n"); /* 720P_50_TB */ video.resolution = v1280x720p_50Hz; video.hdmi_3d_format = HDMI_3D_TB_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 11. 720P_50_TB (0x15000000) =\n"); /* 1080P_24_TB */ video.resolution = v1920x1080p_24Hz; video.hdmi_3d_format = HDMI_3D_TB_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 12. 1080P_24_TB (0x16000000) =\n"); /* 1080P_23_TB */ video.resolution = v1920x1080p_24Hz; video.hdmi_3d_format = HDMI_3D_TB_FORMAT; if (EDIDVideoResolutionSupport(&video)) LOGI("= 13. 1080P_24_TB (0x17000000) =\n"); LOGI("=========================================\n"); } int tvout_init(int fd_tvout, __u32 preset_id) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::preset_id = 0x%x", __func__, preset_id); #endif int ret; struct v4l2_output output; struct v4l2_dv_preset preset; unsigned int matched = 0, i = 0; int output_index; if (fd_tvout <= 0) { fd_tvout = open(TVOUT0_DEV_G0, O_RDWR); if (fd_tvout < 0) { LOGE("%s::fd_tvout open failed", __func__); return -1; } } /* if (output_type >= V4L2_OUTPUT_TYPE_DIGITAL && output_type <= V4L2_OUTPUT_TYPE_DVI) if (ioctl(fd_tvout, VIDIOC_HDCP_ENABLE, g_hdcp_en) < 0) LOGE("%s::VIDIOC_HDCP_ENABLE failed %d", __func__, errno); */ i = 0; do { output.index = i; ret = tvout_v4l2_enum_output(fd_tvout, &output); LOGV("%s::output_type=%d output.index=%d .name=%s", __func__, output_type, output.index, output.name); if (output.type == output_type) { matched = 1; break; } i++; } while (ret >=0); /* if (!matched) { LOGE("%s::no matched output type [type=0x%08x]", __func__, output_type); return -1; } tvout_v4l2_s_output(fd_tvout, output.index); output_index = 0; tvout_v4l2_g_output(fd_tvout, &output_index); */ #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::input preset_id=0x%08x", __func__, preset_id); #endif if (output.capabilities & V4L2_OUT_CAP_PRESETS) { tvout_std_v4l2_enum_dv_presets(fd_tvout); preset.preset = preset_id; if (tvout_std_v4l2_s_dv_preset(fd_tvout, &preset) < 0 ) { LOGE("%s::tvout_std_v4l2_s_dv_preset failed", __func__); return -1; } } return fd_tvout; } int tvout_deinit() { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif return 0; } int tvout_std_v4l2_querycap(int fd, char *node) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_capability v4l2cap; if (ioctl(fd, VIDIOC_QUERYCAP, &v4l2cap) < 0) { LOGE("%s::VIDIOC_QUERYCAP failed", __func__); return -1; } if (!(v4l2cap.capabilities & V4L2_CAP_STREAMING)) { LOGE("%s::%s is not support streaming", __func__, node); return -1; } if (!(v4l2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)) { LOGE("%s::%s is not support video output mplane", __func__, node); return -1; } return 0; } int tvout_std_v4l2_s_fmt(int fd, enum v4l2_buf_type type, enum v4l2_field field, int w, int h, int colorformat, int num_planes) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_format fmt; fmt.type = type; if (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0) { LOGE("%s::VIDIOC_G_FMT failed", __func__); return -1; } switch (fmt.type) { case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_CAPTURE: fmt.fmt.pix.width = w; fmt.fmt.pix.height = h; fmt.fmt.pix.pixelformat = colorformat; fmt.fmt.pix.field = field; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: fmt.fmt.pix_mp.width = w; fmt.fmt.pix_mp.height = h; fmt.fmt.pix_mp.pixelformat = colorformat; fmt.fmt.pix_mp.field = field; fmt.fmt.pix_mp.num_planes = num_planes; break; default: LOGE("%s::invalid buffer type", __func__); return -1; break; } if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) { LOGE("%s::VIDIOC_S_FMT failed", __func__); return -1; } return 0; } int tvout_std_v4l2_s_crop(int fd, enum v4l2_buf_type type, enum v4l2_field, int x, int y, int w, int h) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_crop crop; crop.type = type; crop.c.left = x; crop.c.top = y; crop.c.width = w; crop.c.height = h; if (ioctl(fd, VIDIOC_S_CROP, &crop) < 0) { LOGE("%s::VIDIOC_S_CROP (x=%d, y=%d, w=%d, h=%d) failed", __func__, x, y, w, h); return -1; } return 0; } int tvout_std_v4l2_s_ctrl(int fd, int id, int value) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_control vc; vc.id = id; vc.value = value; if (ioctl(fd, VIDIOC_S_CTRL, &vc) < 0) { LOGE("%s::VIDIOC_S_CTRL (id=%d,value=%d) failed", __func__, id, value); return -1; } return 0; } int tvout_std_v4l2_reqbuf(int fd, enum v4l2_buf_type type, enum v4l2_memory memory, unsigned int num_bufs) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_requestbuffers reqbuf; reqbuf.type = type; reqbuf.memory = memory; reqbuf.count = num_bufs; if (ioctl(fd, VIDIOC_REQBUFS, &reqbuf) < 0) { LOGE("%s::VIDIOC_REQBUFS failed", __func__); return -1; } if (reqbuf.count < num_bufs) { LOGE("%s::VIDIOC_REQBUFS failed ((reqbuf.count(%d) < num_bufs(%d))", __func__, reqbuf.count, num_bufs); return -1; } return 0; } int tvout_std_v4l2_querybuf(int fd, enum v4l2_buf_type type, enum v4l2_memory memory, unsigned int buf_index, unsigned int num_planes, SecBuffer *secBuf) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_buffer buf; struct v4l2_plane planes[MAX_PLANES_MIXER]; memset(&buf, 0, sizeof(struct v4l2_buffer)); for (int i = 0; i < MAX_PLANES_MIXER; i++) memset(&planes[i], 0, sizeof(struct v4l2_plane)); if (MAX_BUFFERS_MIXER <= buf_index || MAX_PLANES_MIXER <= num_planes) { LOGE("%s::exceed MAX! : buf_index=%d, num_plane=%d", __func__, buf_index, num_planes); return -1; } buf.type = type; buf.memory = V4L2_MEMORY_MMAP; buf.index = buf_index; buf.length = num_planes; buf.m.planes = planes; if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) { LOGE("%s::VIDIOC_QUERYBUF failed, plane_cnt=%d", __func__, buf.length); return -1; } for (unsigned int i = 0; i < num_planes; i++) { if ((secBuf->virt.extP[i] = (char *)mmap(0, buf.m.planes[i].length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.planes[i].m.mem_offset)) < 0) { LOGE("%s::mmap failed", __func__); LOGE("%s::Offset = 0x%x", __func__, buf.m.planes[i].m.mem_offset); LOGE("%s::Legnth = %d" , __func__, buf.m.planes[i].length); LOGE("%s::vaddr[%d][%d] = 0x%x", __func__, buf_index, i, (unsigned int)secBuf->virt.extP[i]); return -1; } secBuf->size.extS[i] = buf.m.planes[i].length; #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::vaddr[bufindex=%d][planeidx=%d] = 0x%x", __func__, buf_index, i, (unsigned int)secBuf->virt.extP[i]); LOGD("%s::Legnth = %d" , __func__, buf.m.planes[i].length); #endif } return 0; } int tvout_std_v4l2_qbuf(int fd, enum v4l2_buf_type type, enum v4l2_memory memory, int buf_index, int num_planes, SecBuffer *secBuf) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_buffer buf; struct v4l2_plane planes[MAX_PLANES_MIXER]; memset(&buf, 0, sizeof(struct v4l2_buffer)); for (int i = 0; i < MAX_PLANES_MIXER; i++) memset(&planes[i], 0, sizeof(struct v4l2_plane)); buf.type = type; buf.memory = memory; buf.length = num_planes; buf.index = buf_index; buf.m.planes = planes; for (unsigned int i = 0; i < buf.length; i++) { buf.m.planes[i].m.userptr = (unsigned long)secBuf->virt.extP[i]; buf.m.planes[i].length = secBuf->size.extS[i]; buf.m.planes[i].bytesused = buf.m.planes[i].length; #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::buf.index=%d", __func__, buf.index); LOGD("%s::buf.m.planes[%d].m.userptr=0x%08x", __func__, i, (unsigned int)buf.m.planes[i].m.userptr); LOGD("%s::buf.m.planes[%d].length =0x%08x", __func__, i, buf.m.planes[i].length); LOGD("%s::buf.m.planes[%d].bytesused=0x%08x", __func__, i, buf.m.planes[i].bytesused); #endif } if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) { LOGE("%s::VIDIOC_QBUF failed", __func__); return -1; } return 0; } int tvout_std_v4l2_dqbuf(int fd, enum v4l2_buf_type type, enum v4l2_memory memory, int *buf_index, int num_planes) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_buffer buf; struct v4l2_plane planes[MAX_PLANES_MIXER]; memset(&buf, 0, sizeof(struct v4l2_buffer)); for (int i = 0; i < MAX_PLANES_GSCALER; i++) memset(&planes[i], 0, sizeof(struct v4l2_plane)); buf.type = type; buf.memory = memory; buf.length = num_planes; buf.m.planes = planes; if (ioctl(fd, VIDIOC_DQBUF, &buf) < 0) { LOGE("%s::VIDIOC_DQBUF failed", __func__); return -1; } *buf_index = buf.index; #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::buf.index=%d", __func__, buf.index); #endif return 0; } int tvout_std_v4l2_streamon(int fd, enum v4l2_buf_type type) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) { LOGE("%s::VIDIOC_STREAMON failed", __func__); return -1; } return 0; } int tvout_std_v4l2_streamoff(int fd, enum v4l2_buf_type type) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0) { LOGE("%s::VIDIOC_STREAMOFF failed", __func__); return -1; } return 0; } int tvout_v4l2_enum_output(int fd, struct v4l2_output *output) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif int ret = -1 ; ret = ioctl(fd, VIDIOC_ENUMOUTPUT, output); if (ret < 0) { if (errno == EINVAL) return -1; LOGE("%s::VIDIOC_ENUMOUTPUT", __func__); return -1; } LOGD("%s::index=%d, type=0x%08x, name=%s", __func__, output->index, output->type, output->name); return ret; } int tvout_v4l2_s_output(int fd, int index) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif if (ioctl(fd, VIDIOC_S_OUTPUT, &index) < 0) { LOGE("%s::VIDIOC_S_OUTPUT failed", __func__); return -1; } return 0; } int tvout_v4l2_g_output(int fd, int *index) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif if (ioctl(fd, VIDIOC_G_OUTPUT, index) < 0) { LOGE("%s::VIDIOC_G_OUTPUT failed", __func__); return -1; } return 0; } int tvout_std_v4l2_enum_dv_presets(int fd) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_dv_enum_preset enum_preset; int ret = -1; for (int index = 0; ; index++) { enum_preset.index = index; ret = ioctl(fd, VIDIOC_ENUM_DV_PRESETS, &enum_preset); if (ret < 0) { if (errno == EINVAL) break; LOGE("%s::VIDIOC_ENUM_DV_PRESETS", __func__); return -1; } LOGD("%s::index=%d, preset=0x%08x, name=%s, w=%d, h=%d", __func__, enum_preset.index, enum_preset.preset, enum_preset.name, enum_preset.width, enum_preset.height); } return 0; } int tvout_std_v4l2_s_dv_preset(int fd, struct v4l2_dv_preset *preset) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif if (ioctl(fd, VIDIOC_S_DV_PRESET, preset) < 0) { LOGE("%s::VIDIOC_S_DV_PRESET failed preset_id=%d", __func__, preset->preset); return -1; } #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::preset_id=%d", __func__, preset->preset); #endif return 0; } int tvout_std_subdev_s_fmt(int fd, unsigned int pad, int w, int h, enum v4l2_mbus_pixelcode code) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_subdev_format fmt; fmt.pad = pad; fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; fmt.format.width = w; fmt.format.height = h; fmt.format.code = code; if (ioctl(fd, VIDIOC_SUBDEV_S_FMT, &fmt) < 0) { LOGE("%s::VIDIOC_SUBDEV_S_FMT", __func__); return -1; } #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::format w=%d, h=%d", __func__, fmt.format.width, fmt.format.height); #endif return 0; } int tvout_std_subdev_s_crop(int fd, unsigned int pad, int x, int y, int w, int h) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::pad=%d, crop x=%d, y=%d, w=%d, h=%d", __func__, pad, x, y, w, h); #endif struct v4l2_subdev_crop crop; crop.pad = pad; crop.which = V4L2_SUBDEV_FORMAT_ACTIVE; crop.rect.left = x; crop.rect.top = y; crop.rect.width = w; crop.rect.height = h; if (ioctl(fd, VIDIOC_SUBDEV_S_CROP, &crop) < 0) { LOGE("%s::VIDIOC_SUBDEV_S_CROP", __func__); return -1; } #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s::pad=%d, crop x=%d, y=%d, w=%d, h=%d", __func__, pad, crop.rect.left, crop.rect.top, crop.rect.width, crop.rect.height); #endif return 0; } #define ROUND_UP(value, boundary) ((((uint32_t)(value)) + \ (((uint32_t) boundary)-1)) & \ (~(((uint32_t) boundary)-1))) void hdmi_cal_rect(int src_w, int src_h, int dst_w, int dst_h, struct v4l2_rect *dst_rect) { if (dst_w * src_h <= dst_h * src_w) { dst_rect->left = 0; dst_rect->top = (dst_h - ((dst_w * src_h) / src_w)) >> 1; dst_rect->width = dst_w; dst_rect->height = ((dst_w * src_h) / src_w); } else { dst_rect->left = (dst_w - ((dst_h * src_w) / src_h)) >> 1; dst_rect->top = 0; dst_rect->width = ((dst_h * src_w) / src_h); dst_rect->height = dst_h; } } int hdmi_set_videolayer(int fd, int hdmiW, int hdmiH, struct v4l2_rect * rect) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif if (tvout_std_subdev_s_fmt(fd, MIXER_V_SUBDEV_PAD_SINK, hdmiW, hdmiH, V4L2_MBUS_FMT_YUV8_1X24) < 0) { LOGE("%s::tvout_std_subdev_s_fmt(PAD=%d)[videolayer] failed", __func__, MIXER_V_SUBDEV_PAD_SINK); return -1; } if (tvout_std_subdev_s_crop(fd, MIXER_V_SUBDEV_PAD_SINK, 0, 0, rect->width, rect->height) < 0) { LOGE("%s::tvout_std_subdev_s_crop(PAD=%d)[videolayer] failed", __func__, MIXER_V_SUBDEV_PAD_SINK); return -1; } if (tvout_std_subdev_s_crop(fd, MIXER_V_SUBDEV_PAD_SOURCE, rect->left, rect->top, rect->width, rect->height) < 0) { LOGE("%s::tvout_std_subdev_s_crop(PAD=%d)[videolayer] failed", __func__, MIXER_V_SUBDEV_PAD_SOURCE); return -1; } return 0; } int hdmi_set_graphiclayer(int fd_subdev, int fd_videodev,int layer, int srcColorFormat, int src_w, int src_h, unsigned int src_address, SecBuffer * dstBuffer, int dst_x, int dst_y, int dst_w, int dst_h, int rotVal) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif #if defined(BOARD_USES_HDMI_FIMGAPI) int dst_color_format; int dst_bpp; unsigned char *dst_addr; fimg2d_blit BlitParam; rotation g2d_rotation; fimg2d_addr srcAddr; fimg2d_image srcImage; fimg2d_rect srcRect; fimg2d_addr dstAddr; fimg2d_image dstImage; fimg2d_rect dstRect; fimg2d_clip dstClip; fimg2d_scale Scaling; switch (t_std_id) { case V4L2_STD_1080P_60: case V4L2_STD_1080P_30: case V4L2_STD_1080I_60: case V4L2_STD_TVOUT_720P_60_SBS_HALF: case V4L2_STD_TVOUT_720P_59_SBS_HALF: case V4L2_STD_TVOUT_1080P_24_TB: case V4L2_STD_TVOUT_1080P_23_TB: dst_color_format = CF_ARGB_8888; dst_bpp = 4; break; case V4L2_STD_480P_60_16_9: case V4L2_STD_576P_50_16_9: case V4L2_STD_720P_60: case V4L2_STD_TVOUT_720P_50_TB: default: dst_color_format = CF_ARGB_4444; dst_bpp = 2; break; } static unsigned int prev_src_addr = 0; if ((cur_g2d_address == 0) || (src_address != prev_src_addr)) { if ((cur_g2d_address == 0) || (cur_g2d_address == g2d_reserved_memory1)) dst_addr = (unsigned char *)g2d_reserved_memory0; else dst_addr = (unsigned char *)g2d_reserved_memory1; cur_g2d_address = (unsigned int)dst_addr; prev_src_addr = src_address; srcAddr = {(addr_space)ADDR_USER, (unsigned long)src_address, src_w*src_h*4, 1, 0}; srcImage = {srcAddr, srcAddr, src_w, src_h, src_w*4, AX_RGB, CF_ARGB_8888}; srcRect = {0, 0, src_w, src_h}; dstAddr = {(addr_space)ADDR_USER, (unsigned long)dst_addr, dst_w*dst_h*dst_bpp, 1, 0}; dstImage = {dstAddr, dstAddr, dst_w, dst_h, dst_w*dst_bpp, AX_RGB, (color_format)dst_color_format}; dstRect = {0, 0, dst_w, dst_h}; dstClip = {0, 0, 0, dst_w, dst_h}; if (rotVal == 0 || rotVal == 180) Scaling = {SCALING_BILINEAR, SCALING_PIXELS, 0, 0, src_w, src_h, dst_w, dst_h}; else Scaling = {SCALING_BILINEAR, SCALING_PIXELS, 0, 0, src_w, src_h, dst_h, dst_w}; switch (rotVal) { case 0: g2d_rotation = ORIGIN; break; case 90: g2d_rotation = ROT_90; break; case 180: g2d_rotation = ROT_180; break; case 270: g2d_rotation = ROT_270; break; default: LOGE("%s::invalid rotVal(%d) : failed", __func__, rotVal); return -1; break; } BlitParam = {BLIT_OP_SRC, NON_PREMULTIPLIED, 0xff, 0, g2d_rotation, &Scaling, 0, 0, &dstClip, 0, &srcImage, &dstImage, NULL, &srcRect, &dstRect, NULL, 0}; if (stretchFimgApi(&BlitParam) < 0) { LOGE("%s::stretchFimgApi() failed", __func__); return -1; } dstBuffer->virt.p = (char *)dst_addr; } #else dstBuffer->virt.p = (char *)src_address; #endif return 0; } int hdmi_set_g_Params(int fd_subdev, int fd_videodev, int layer, int srcColorFormat, int src_w, int src_h, int dst_x, int dst_y, int dst_w, int dst_h) { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif struct v4l2_rect rect; int src_pad = 0; int sink_pad = 0; int v4l2ColorFormat = HAL_PIXEL_FORMAT_2_V4L2_PIX(srcColorFormat); switch (layer) { case HDMI_LAYER_GRAPHIC_0: sink_pad = MIXER_G0_SUBDEV_PAD_SINK; src_pad = MIXER_G0_SUBDEV_PAD_SOURCE; break; case HDMI_LAYER_GRAPHIC_1: sink_pad = MIXER_G1_SUBDEV_PAD_SINK; src_pad = MIXER_G1_SUBDEV_PAD_SOURCE; break; default: LOGE("%s::invalid layer(%d)", __func__, layer); break; }; rect.left = dst_x; rect.top = dst_y; #if defined(BOARD_USES_HDMI_FIMGAPI) rect.width = dst_w; rect.height = dst_h; #else rect.width = src_w; rect.height = src_h; #endif /* set sub device for mixer graphic layer input */ if (tvout_std_subdev_s_fmt(fd_subdev, sink_pad, rect.width, rect.height, V4L2_MBUS_FMT_XRGB8888_4X8_LE) < 0) { LOGE("%s::tvout_std_subdev_s_fmt(PAD=%d)[graphic layer] failed", __func__, sink_pad); return -1; } if (tvout_std_subdev_s_crop(fd_subdev, sink_pad, 0, 0, rect.width, rect.height) < 0) { LOGE("%s::tvout_std_subdev_s_crop(PAD=%d)[graphic layer] failed", __func__, sink_pad); return -1; } if (tvout_std_subdev_s_crop(fd_subdev, src_pad, rect.left, rect.top, rect.width, rect.height) < 0) { LOGE("%s::tvout_std_subdev_s_crop(PAD=%d)[graphic layer] failed", __func__, src_pad); return -1; } /* set format for mixer graphic layer input device*/ if (tvout_std_v4l2_s_fmt(fd_videodev, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_FIELD_ANY, rect.width, rect.height, v4l2ColorFormat, 1) < 0) { LOGE("%s::tvout_std_v4l2_s_fmt()[graphic layer] failed", __func__); return -1; } if (tvout_std_v4l2_s_crop(fd_videodev, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_FIELD_ANY, rect.left, rect.top, rect.width, rect.height) < 0) { LOGE("%s::tvout_std_v4l2_s_crop()[graphic layer] failed", __func__); return -1; } /* request buffer for mixer graphic layer input device */ if (tvout_std_v4l2_reqbuf(fd_videodev, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_MEMORY_USERPTR, 2) < 0) { LOGE("%s::tvout_std_v4l2_reqbuf(buf_num=%d)[graphic layer] failed", __func__, 2); return -1; } return 0; } int hdmi_cable_status() { #ifdef DEBUG_HDMI_HW_LEVEL LOGD("%s", __func__); #endif int cable_status = 0; int fd = 0; struct v4l2_control ctrl; fd = open(TVOUT0_DEV_G0, O_RDWR); if (fd <= 0) { LOGE("%s: graphic layer 0 drv open failed", __func__); return -1; } ctrl.id = V4L2_CID_TV_HPD_STATUS; if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) { LOGE("Get HPD_STATUS fail"); cable_status = -1; } else { cable_status = ctrl.value; } #ifdef DEBUG_HDMI_HW_LEVEL LOGD("HPD_STATUS = %d", cable_status); #endif close(fd); return cable_status; } int hdmi_outputmode_2_v4l2_output_type(int output_mode) { int v4l2_output_type = -1; switch (output_mode) { case HDMI_OUTPUT_MODE_YCBCR: v4l2_output_type = V4L2_OUTPUT_TYPE_DIGITAL; break; case HDMI_OUTPUT_MODE_RGB: v4l2_output_type = V4L2_OUTPUT_TYPE_HDMI_RGB; break; case HDMI_OUTPUT_MODE_DVI: v4l2_output_type = V4L2_OUTPUT_TYPE_DVI; break; case COMPOSITE_OUTPUT_MODE: v4l2_output_type = V4L2_OUTPUT_TYPE_COMPOSITE; break; default: LOGE("%s::unmathced HDMI_mode(%d)", __func__, output_mode); v4l2_output_type = -1; break; } return v4l2_output_type; } int hdmi_v4l2_output_type_2_outputmode(int v4l2_output_type) { int outputMode = -1; switch (v4l2_output_type) { case V4L2_OUTPUT_TYPE_DIGITAL: outputMode = HDMI_OUTPUT_MODE_YCBCR; break; case V4L2_OUTPUT_TYPE_HDMI_RGB: outputMode = HDMI_OUTPUT_MODE_RGB; break; case V4L2_OUTPUT_TYPE_DVI: outputMode = HDMI_OUTPUT_MODE_DVI; break; case V4L2_OUTPUT_TYPE_COMPOSITE: outputMode = COMPOSITE_OUTPUT_MODE; break; default: LOGE("%s::unmathced v4l2_output_type(%d)", __func__, v4l2_output_type); outputMode = -1; break; } return outputMode; } int composite_std_2_v4l2_std_id(int std) { int std_id = -1; switch (std) { case COMPOSITE_STD_NTSC_M: std_id = V4L2_STD_NTSC_M; break; case COMPOSITE_STD_NTSC_443: std_id = V4L2_STD_NTSC_443; break; case COMPOSITE_STD_PAL_BDGHI: std_id = V4L2_STD_PAL_BDGHI; break; case COMPOSITE_STD_PAL_M: std_id = V4L2_STD_PAL_M; break; case COMPOSITE_STD_PAL_N: std_id = V4L2_STD_PAL_N; break; case COMPOSITE_STD_PAL_Nc: std_id = V4L2_STD_PAL_Nc; break; case COMPOSITE_STD_PAL_60: std_id = V4L2_STD_PAL_60; break; default: LOGE("%s::unmathced composite_std(%d)", __func__, std); break; } return std_id; } int hdmi_check_output_mode(int v4l2_output_type) { struct HDMIVideoParameter video; struct HDMIAudioParameter audio; int calbirate_v4l2_mode = v4l2_output_type; audio.formatCode = LPCM_FORMAT; audio.outPacket = HDMI_ASP; audio.channelNum = CH_2; audio.sampleFreq = SF_44KHZ; switch (v4l2_output_type) { case V4L2_OUTPUT_TYPE_DIGITAL : video.mode = HDMI; if (!EDIDHDMIModeSupport(&video)) { calbirate_v4l2_mode = V4L2_OUTPUT_TYPE_DVI; LOGI("Change mode into DVI\n"); break; } video.colorSpace = HDMI_CS_YCBCR444; if (!EDIDColorSpaceSupport(&video)) { calbirate_v4l2_mode = V4L2_OUTPUT_TYPE_HDMI_RGB; LOGI("Change mode into HDMI_RGB\n"); } break; case V4L2_OUTPUT_TYPE_HDMI_RGB: video.mode = HDMI; if (!EDIDHDMIModeSupport(&video)) { calbirate_v4l2_mode = V4L2_OUTPUT_TYPE_DVI; LOGI("Change mode into DVI\n"); break; } video.colorSpace = HDMI_CS_RGB; if (!EDIDColorSpaceSupport(&video)) { calbirate_v4l2_mode = V4L2_OUTPUT_TYPE_DIGITAL; LOGI("Change mode into HDMI_YCBCR\n"); } break; case V4L2_OUTPUT_TYPE_DVI: video.mode = DVI; if (!EDIDHDMIModeSupport(&video)) { video.colorSpace = HDMI_CS_YCBCR444; if (!EDIDColorSpaceSupport(&video)) { calbirate_v4l2_mode = V4L2_OUTPUT_TYPE_HDMI_RGB; LOGI("Change mode into HDMI_RGB\n"); } else { calbirate_v4l2_mode = V4L2_OUTPUT_TYPE_DIGITAL; LOGI("Change mode into HDMI_YCBCR\n"); } break; } break; default: break; } return calbirate_v4l2_mode; } int hdmi_check_resolution(v4l2_std_id std_id) { struct HDMIVideoParameter video; struct HDMIAudioParameter audio; switch (std_id) { case V4L2_STD_480P_60_16_9: video.resolution = v720x480p_60Hz; video.pixelAspectRatio = HDMI_PIXEL_RATIO_16_9; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_480P_60_4_3: video.resolution = v640x480p_60Hz; video.pixelAspectRatio = HDMI_PIXEL_RATIO_4_3; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_576P_50_16_9: video.resolution = v720x576p_50Hz; video.pixelAspectRatio = HDMI_PIXEL_RATIO_16_9; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_576P_50_4_3: video.resolution = v720x576p_50Hz; video.pixelAspectRatio = HDMI_PIXEL_RATIO_4_3; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_720P_60: video.resolution = v1280x720p_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_720P_50: video.resolution = v1280x720p_50Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_1080P_60: video.resolution = v1920x1080p_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_1080P_50: video.resolution = v1920x1080p_50Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_1080I_60: video.resolution = v1920x1080i_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_1080I_50: video.resolution = v1920x1080i_50Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_480P_59: video.resolution = v720x480p_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_720P_59: video.resolution = v1280x720p_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_1080I_59: video.resolution = v1920x1080i_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_1080P_59: video.resolution = v1920x1080p_60Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_1080P_30: video.resolution = v1920x1080p_30Hz; video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; break; case V4L2_STD_TVOUT_720P_60_SBS_HALF: video.resolution = v1280x720p_60Hz; video.hdmi_3d_format = HDMI_3D_SSH_FORMAT; break; case V4L2_STD_TVOUT_720P_59_SBS_HALF: video.resolution = v1280x720p_60Hz; video.hdmi_3d_format = HDMI_3D_SSH_FORMAT; break; case V4L2_STD_TVOUT_720P_50_TB: video.resolution = v1280x720p_50Hz; video.hdmi_3d_format = HDMI_3D_TB_FORMAT; break; case V4L2_STD_TVOUT_1080P_24_TB: video.resolution = v1920x1080p_24Hz; video.hdmi_3d_format = HDMI_3D_TB_FORMAT; break; case V4L2_STD_TVOUT_1080P_23_TB: video.resolution = v1920x1080p_24Hz; video.hdmi_3d_format = HDMI_3D_TB_FORMAT; break; default: LOGE("%s::unmathced std_id(%lld)", __func__, std_id); return -1; break; } if (!EDIDVideoResolutionSupport(&video)) { #ifdef DEBUG_MSG_ENABLE LOGD("%s::EDIDVideoResolutionSupport(%llx) fail (not suppoted std_id) \n", __func__, std_id); #endif return -1; } return 0; } int hdmi_resolution_2_std_id(unsigned int resolution, int * w, int * h, v4l2_std_id * std_id, __u32 *preset_id) { int ret = 0; switch (resolution) { case 1080960: *std_id = V4L2_STD_1080P_60; *w = 1920; *h = 1080; *preset_id = V4L2_DV_1080P60; break; case 1080950: *std_id = V4L2_STD_1080P_50; *w = 1920; *h = 1080; *preset_id = V4L2_DV_1080P50; break; case 1080930: *std_id = V4L2_STD_1080P_30; *w = 1920; *h = 1080; *preset_id = V4L2_DV_1080P30; break; case 1080924: *std_id = V4L2_STD_TVOUT_1080P_24_TB; *w = 1920; *h = 1080; *preset_id = V4L2_DV_1080P24_TB; break; case 1080160: *std_id = V4L2_STD_1080I_60; *w = 1920; *h = 1080; *preset_id = V4L2_DV_1080I60; break; case 1080150: *std_id = V4L2_STD_1080I_50; *w = 1920; *h = 1080; *preset_id = V4L2_DV_1080I50; break; case 720960: *std_id = V4L2_STD_720P_60; *w = 1280; *h = 720; *preset_id = V4L2_DV_720P60; break; case 7209601: *std_id = V4L2_STD_TVOUT_720P_60_SBS_HALF; *w = 1280; *h = 720; *preset_id = V4L2_DV_720P60_SB_HALF; break; case 720950: *std_id = V4L2_STD_720P_50; *w = 1280; *h = 720; *preset_id = V4L2_DV_720P50; break; case 7209501: *std_id = V4L2_STD_TVOUT_720P_50_TB; *w = 1280; *h = 720; *preset_id = V4L2_DV_720P50_TB; break; case 5769501: *std_id = V4L2_STD_576P_50_16_9; *w = 720; *h = 576; *preset_id = V4L2_DV_576P50; break; case 5769502: *std_id = V4L2_STD_576P_50_4_3; *w = 720; *h = 576; *preset_id = V4L2_DV_576P50; break; case 4809601: *std_id = V4L2_STD_480P_60_16_9; *w = 720; *h = 480; *preset_id = V4L2_DV_480P60; break; case 4809602: *std_id = V4L2_STD_480P_60_4_3; *w = 720; *h = 480; *preset_id = V4L2_DV_480P60; break; default: LOGE("%s::unmathced resolution(%d)", __func__, resolution); ret = -1; break; } return ret; } int hdmi_enable_hdcp(int fd, unsigned int hdcp_en) { if (ioctl(fd, VIDIOC_HDCP_ENABLE, hdcp_en) < 0) { LOGD("%s::VIDIOC_HDCP_ENABLE(%d) fail \n", __func__, hdcp_en); return -1; } return 0; } int hdmi_check_audio(int fd) { struct HDMIAudioParameter audio; enum state audio_state = ON; int ret = 0; audio.formatCode = LPCM_FORMAT; audio.outPacket = HDMI_ASP; audio.channelNum = CH_2; audio.sampleFreq = SF_44KHZ; #if defined(BOARD_USES_EDID) if (!EDIDAudioModeSupport(&audio)) audio_state = NOT_SUPPORT; else audio_state = ON; #endif if (audio_state == ON) { if (ioctl(fd, VIDIOC_INIT_AUDIO, 1) < 0) { LOGE("%s::VIDIOC_INIT_AUDIO(1) failed", __func__); ret = -1; } } else { if (ioctl(fd, VIDIOC_INIT_AUDIO, 0) < 0) { LOGE("%s::VIDIOC_INIT_AUDIO(0) failed", __func__); ret = -1; } } return ret; } }