diff options
Diffstat (limited to 'exynos4/hal/libhdmi/SecHdmi/SecHdmiV4L2Utils.cpp')
-rw-r--r-- | exynos4/hal/libhdmi/SecHdmi/SecHdmiV4L2Utils.cpp | 2434 |
1 files changed, 2434 insertions, 0 deletions
diff --git a/exynos4/hal/libhdmi/SecHdmi/SecHdmiV4L2Utils.cpp b/exynos4/hal/libhdmi/SecHdmi/SecHdmiV4L2Utils.cpp new file mode 100644 index 0000000..217ce51 --- /dev/null +++ b/exynos4/hal/libhdmi/SecHdmi/SecHdmiV4L2Utils.cpp @@ -0,0 +1,2434 @@ +/* + * 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" +#include <cutils/log.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <ctype.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <signal.h> + +#if defined(BOARD_USE_V4L2) +#include "sec_utils_v4l2.h" +#include "s5p_tvout_v4l2.h" +#include "videodev2.h" +#else +#include "sec_utils.h" +#include "s5p_tvout.h" +#endif +#include "SecFimc.h" +#if defined(BOARD_USES_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 "SecHdmiCommon.h" +#include "SecHdmiV4L2Utils.h" + +namespace android { + +unsigned int output_type = V4L2_OUTPUT_TYPE_DIGITAL; +#if defined(BOARD_USE_V4L2) +unsigned int g_preset_id = V4L2_DV_1080P30; +#endif +v4l2_std_id t_std_id = V4L2_STD_1080P_30; +int g_hpd_state = HPD_CABLE_OUT; +unsigned int g_hdcp_en = 0; + +int fp_tvout = -1; +int fp_tvout_v = -1; +int fp_tvout_g0 = -1; +int fp_tvout_g1 = -1; + +struct vid_overlay_param vo_param; + +#if defined(BOARD_USES_FIMGAPI) +unsigned int g2d_reserved_memory[HDMI_G2D_OUTPUT_BUF_NUM]; +unsigned int g2d_reserved_memory_size = 0; +unsigned int cur_g2d_address = 0; +unsigned int g2d_buf_index = 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_open(const char *fp_name) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int fp; + + fp = open(fp_name, O_RDWR); + if (fp < 0) + LOGE("drv (%s) open failed!!\n", fp_name); + + return fp; +} +#if defined(BOARD_USE_V4L2) +int tvout_std_v4l2_init(int fd, unsigned int 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 (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_std_v4l2_enum_output(fd, &output); + LOGD("tvout_v4l2_enum_output():: output_type=%d output.index=%d output.name=%s", 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=%d]", __func__, output_type); +// return -1; + } + + // set output +// tvout_std_v4l2_s_output(fp_tvout, output.index); +// output_index = 0; +// tvout_std_v4l2_g_output(fp_tvout, &output_index); + +// if (output.capabilities & V4L2_OUT_CAP_PRESETS) { + tvout_std_v4l2_enum_dv_presets(fd); + preset.preset = preset_id; + if (tvout_std_v4l2_s_dv_preset(fd, &preset) < 0 ) { + LOGE("%s::tvout_std_v4l2_s_dv_preset failed", __func__); + return -1; + } +// } + + 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_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; + } +#ifdef DEBUG_HDMI_HW_LEVEL + 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); +#endif + } + + 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", __func__); + return -1; + } + + return 0; +} + +/* + ioctl VIDIOC_ENUMOUTPUT + To query the attributes of a video outputs applications initialize the index field of struct v4l2_output + and call the VIDIOC_ENUMOUTPUT ioctl with a pointer to this structure. Drivers fill the rest of the + structure or return an EINVAL error code when the index is out of bounds + */ +int tvout_std_v4l2_enum_output(int fd, struct v4l2_output *output) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + + ret = ioctl(fd, VIDIOC_ENUMOUTPUT, output); + + if (ret >=0) + LOGV("tvout_v4l2_enum_output" "enum. output [index = %d] :: type : 0x%08x , name = %s\n", + output->index,output->type,output->name); + + return ret; +} + +/* + ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT + To query the current video output applications call the VIDIOC_G_OUTPUT ioctl with a pointer to an + integer where the driver stores the number of the output, as in the struct v4l2_output index field. + This ioctl will fail only when there are no video outputs, returning the EINVAL error code + */ +int tvout_std_v4l2_s_output(int fd, int index) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s:: index = 0x%x", __func__, index); +#endif + + int ret; + + ret = ioctl(fd, VIDIOC_S_OUTPUT, &index); + if (ret < 0) { + LOGE("tvout_v4l2_s_output" "VIDIOC_S_OUTPUT failed %d\n", errno); + return ret; + } + + return ret; +} + +int tvout_std_v4l2_g_output(int fd, int *index) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + + ret = ioctl(fd, VIDIOC_G_OUTPUT, index); + if (ret < 0) { + LOGE("tvout_v4l2_g_output" "VIDIOC_G_OUTPUT failed %d\n", errno); + return ret; + } else { + LOGV("tvout_v4l2_g_output" "Current output index %d\n", *index); + } + + return ret; +} + +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_LIB_FIMC + LOGD("%s::vaddr[bufidx=%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]; + } + + 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_MIXER; 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; + + 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; +} +#else +int tvout_init(v4l2_std_id std_id) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s:: std_id = 0x%x", __func__, std_id); +#endif + + int ret; + struct v4l2_output output; + struct v4l2_standard std; + v4l2_std_id std_g_id; + struct tvout_param tv_g_param; + + unsigned int matched = 0, i = 0; + int output_index; + + // It was initialized already + if (fp_tvout <= 0) { + fp_tvout = tvout_open(TVOUT_DEV); + if (fp_tvout < 0) { + LOGE("tvout video drv open failed\n"); + return -1; + } + } + + if (output_type >= V4L2_OUTPUT_TYPE_DIGITAL && + output_type <= V4L2_OUTPUT_TYPE_DVI) + if (ioctl(fp_tvout, VIDIOC_HDCP_ENABLE, g_hdcp_en) < 0) + LOGE("tvout_init" "VIDIOC_HDCP_ENABLE failed %d\n", errno); + + /* ============== query capability============== */ + tvout_v4l2_querycap(fp_tvout); + + tvout_v4l2_enum_std(fp_tvout, &std, std_id); + + // set std + tvout_v4l2_s_std(fp_tvout, std_id); + tvout_v4l2_g_std(fp_tvout, &std_g_id); + + i = 0; + + do { + output.index = i; + ret = tvout_v4l2_enum_output(fp_tvout, &output); + if (output.type == output_type) { + matched = 1; + break; + } + i++; + } while (ret >=0); + + if (!matched) { + LOGE("no matched output type [type : 0x%08x]\n", output_type); + return -1; + } + + // set output + tvout_v4l2_s_output(fp_tvout, output.index); + output_index = 0; + tvout_v4l2_g_output(fp_tvout, &output_index); + + //set fmt param + vo_param.src.base_y = (void *)0x0; + vo_param.src.base_c = (void *)0x0; + vo_param.src.pix_fmt.width = 0; + vo_param.src.pix_fmt.height = 0; + vo_param.src.pix_fmt.field = V4L2_FIELD_NONE; + vo_param.src.pix_fmt.pixelformat = V4L2_PIX_FMT_NV12T; + + vo_param.src_crop.left = 0; + vo_param.src_crop.top = 0; + vo_param.src_crop.width = 0; + vo_param.src_crop.height = 0; + + return fp_tvout; +} + +int tvout_deinit() +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + if (0 < fp_tvout) { + close(fp_tvout); + fp_tvout = -1; + } + return 0; +} + +int tvout_v4l2_querycap(int fp) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s:: fp = 0x%x", __func__, fp); +#endif + + struct v4l2_capability cap; + int ret; + + ret = ioctl(fp, VIDIOC_QUERYCAP, &cap); + + if (ret < 0) { + LOGE("tvout_v4l2_querycap" "VIDIOC_QUERYCAP failed %d\n", errno); + return ret; + } + +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("tvout_v4l2_querycap" "DRIVER : %s, CARD : %s, CAP.: 0x%08x\n", + cap.driver, cap.card, cap.capabilities); +#endif + + return ret; +} + +/* + ioctl VIDIOC_G_STD, VIDIOC_S_STD + To query and select the current video standard applications use the VIDIOC_G_STD and + VIDIOC_S_STD ioctls which take a pointer to a v4l2_std_id type as argument. VIDIOC_G_STD can + return a single flag or a set of flags as in struct v4l2_standard field id + */ + +int tvout_v4l2_g_std(int fp, v4l2_std_id *std_id) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + + ret = ioctl(fp, VIDIOC_G_STD, std_id); + if (ret < 0) { + LOGE("tvout_v4l2_g_std" "VIDIOC_G_STD failed %d\n", errno); + return ret; + } + + return ret; +} + +int tvout_v4l2_s_std(int fp, v4l2_std_id std_id) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s:: std_id = 0x%x", __func__, std_id); +#endif + + int ret; + + ret = ioctl(fp, VIDIOC_S_STD, &std_id); + if (ret < 0) { + LOGE("tvout_v4l2_s_std" "VIDIOC_S_STD failed %d\n", errno); + return ret; + } + + return ret; +} + +/* + ioctl VIDIOC_ENUMSTD + To query the attributes of a video standard, especially a custom (driver defined) one, applications + initialize the index field of struct v4l2_standard and call the VIDIOC_ENUMSTD ioctl with a pointer + to this structure. Drivers fill the rest of the structure or return an EINVAL error code when the index + is out of bounds. + */ +int tvout_v4l2_enum_std(int fp, struct v4l2_standard *std, v4l2_std_id std_id) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + std->index = 0; + while (0 == ioctl (fp, VIDIOC_ENUMSTD, std)) { + if (std->id & std_id) + LOGV("tvout_v4l2_enum_std" "Current video standard: %s\n", std->name); + + std->index++; + } + + return 0; +} + +/* + ioctl VIDIOC_ENUMOUTPUT + To query the attributes of a video outputs applications initialize the index field of struct v4l2_output + and call the VIDIOC_ENUMOUTPUT ioctl with a pointer to this structure. Drivers fill the rest of the + structure or return an EINVAL error code when the index is out of bounds + */ +int tvout_v4l2_enum_output(int fp, struct v4l2_output *output) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + + ret = ioctl(fp, VIDIOC_ENUMOUTPUT, output); + + if (ret >=0) + LOGV("tvout_v4l2_enum_output" "enum. output [index = %d] :: type : 0x%08x , name = %s\n", + output->index,output->type,output->name); + + return ret; +} + +/* + ioctl VIDIOC_G_OUTPUT, VIDIOC_S_OUTPUT + To query the current video output applications call the VIDIOC_G_OUTPUT ioctl with a pointer to an + integer where the driver stores the number of the output, as in the struct v4l2_output index field. + This ioctl will fail only when there are no video outputs, returning the EINVAL error code + */ +int tvout_v4l2_s_output(int fp, int index) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s:: index = 0x%x", __func__, index); +#endif + + int ret; + + ret = ioctl(fp, VIDIOC_S_OUTPUT, &index); + if (ret < 0) { + LOGE("tvout_v4l2_s_output" "VIDIOC_S_OUTPUT failed %d\n", errno); + return ret; + } + + return ret; +} + +int tvout_v4l2_g_output(int fp, int *index) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + + ret = ioctl(fp, VIDIOC_G_OUTPUT, index); + if (ret < 0) { + LOGE("tvout_v4l2_g_output" "VIDIOC_G_OUTPUT failed %d\n", errno); + return ret; + } else { + LOGV("tvout_v4l2_g_output" "Current output index %d\n", *index); + } + + return ret; +} + +/* + ioctl VIDIOC_ENUM_FMT + To enumerate image formats applications initialize the type and index field of struct v4l2_fmtdesc + and call the VIDIOC_ENUM_FMT ioctl with a pointer to this structure. Drivers fill the rest of the + structure or return an EINVAL error code. All formats are enumerable by beginning at index zero + and incrementing by one until EINVAL is returned. + */ +int tvout_v4l2_enum_fmt(int fp, struct v4l2_fmtdesc *desc) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + desc->index = 0; + while (0 == ioctl(fp, VIDIOC_ENUM_FMT, desc)) { + LOGV("tvout_v4l2_enum_fmt" "enum. fmt [id : 0x%08x] :: type = 0x%08x, name = %s, pxlfmt = 0x%08x\n", + desc->index, + desc->type, + desc->description, + desc->pixelformat); + desc->index++; + } + + return 0; +} + +int tvout_v4l2_g_fmt(int fp, int buf_type, void* ptr) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + struct v4l2_format format; + struct v4l2_pix_format_s5p_tvout *fmt_param = (struct v4l2_pix_format_s5p_tvout*)ptr; + + format.type = (enum v4l2_buf_type)buf_type; + + ret = ioctl(fp, VIDIOC_G_FMT, &format); + if (ret < 0) { + LOGE("tvout_v4l2_g_fmt" "type : %d, VIDIOC_G_FMT failed %d\n", buf_type, errno); + return ret; + } else { + memcpy(fmt_param, format.fmt.raw_data, sizeof(struct v4l2_pix_format_s5p_tvout)); + LOGV("tvout_v4l2_g_fmt" "get. fmt [base_c : 0x%08x], [base_y : 0x%08x] type = 0x%08x, width = %d, height = %d\n", + fmt_param->base_c, + fmt_param->base_y, + fmt_param->pix_fmt.pixelformat, + fmt_param->pix_fmt.width, + fmt_param->pix_fmt.height); + } + + return 0; +} + +int tvout_v4l2_s_fmt(int fp, int buf_type, void *ptr) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + struct v4l2_format format; + int ret; + + format.type = (enum v4l2_buf_type)buf_type; + switch (buf_type) { + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + format.fmt.win = *((struct v4l2_window *) ptr); + break; + + case V4L2_BUF_TYPE_PRIVATE: { + struct v4l2_vid_overlay_src *fmt_param = + (struct v4l2_vid_overlay_src *) ptr; + + memcpy(format.fmt.raw_data, fmt_param, + sizeof(struct v4l2_vid_overlay_src)); + break; + } + case V4L2_BUF_TYPE_VIDEO_OUTPUT: { + struct v4l2_pix_format_s5p_tvout *fmt_param = + (struct v4l2_pix_format_s5p_tvout *)ptr; + memcpy(format.fmt.raw_data, fmt_param, + sizeof(struct v4l2_pix_format_s5p_tvout)); + break; + } + default: + break; + } + + ret = ioctl(fp, VIDIOC_S_FMT, &format); + if (ret < 0) { + LOGE("tvout_v4l2_s_fmt [tvout_v4l2_s_fmt] : type : %d, VIDIOC_S_FMT failed %d\n", + buf_type, errno); + return ret; + } + return 0; + +} + +int tvout_v4l2_g_fbuf(int fp, struct v4l2_framebuffer *frame) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + + ret = ioctl(fp, VIDIOC_G_FBUF, frame); + if (ret < 0) { + LOGE("tvout_v4l2_g_fbuf" "VIDIOC_STREAMON failed %d\n", errno); + return ret; + } + + LOGV("tvout_v4l2_g_fbuf" "get. fbuf: base = 0x%08X, pixel format = %d\n", + frame->base, + frame->fmt.pixelformat); + return 0; +} + +int tvout_v4l2_s_fbuf(int fp, struct v4l2_framebuffer *frame) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + + ret = ioctl(fp, VIDIOC_S_FBUF, frame); + if (ret < 0) { + LOGE("tvout_v4l2_s_fbuf" "VIDIOC_STREAMON failed %d\n", errno); + return ret; + } + return 0; +} + +int tvout_v4l2_s_baseaddr(int fp, void *base_addr) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + + ret = ioctl(fp, S5PTVFB_WIN_SET_ADDR, base_addr); + if (ret < 0) { + LOGE("tvout_v4l2_baseaddr" "VIDIOC_S_BASEADDR failed %d\n", errno); + return ret; + } + return 0; +} + +int tvout_v4l2_g_crop(int fp, unsigned int type, struct v4l2_rect *rect) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret; + struct v4l2_crop crop; + crop.type = (enum v4l2_buf_type)type; + ret = ioctl(fp, VIDIOC_G_CROP, &crop); + if (ret < 0) { + LOGE("tvout_v4l2_g_crop" "VIDIOC_G_CROP failed %d\n", errno); + return ret; + } + + rect->left = crop.c.left; + rect->top = crop.c.top; + rect->width = crop.c.width; + rect->height = crop.c.height; + + LOGV("tvout_v4l2_g_crop" "get. crop : left = %d, top = %d, width = %d, height = %d\n", + rect->left, + rect->top, + rect->width, + rect->height); + return 0; +} + +int tvout_v4l2_s_crop(int fp, unsigned int type, struct v4l2_rect *rect) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + struct v4l2_crop crop; + int ret; + + crop.type = (enum v4l2_buf_type)type; + + crop.c.left = rect->left; + crop.c.top = rect->top; + crop.c.width = rect->width; + crop.c.height = rect->height; + + ret = ioctl(fp, VIDIOC_S_CROP, &crop); + if (ret < 0) { + LOGE("tvout_v4l2_s_crop" "VIDIOC_S_CROP failed %d\n", errno); + return ret; + } + + return 0; +} + +int tvout_v4l2_start_overlay(int fp) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret, start = 1; + + ret = ioctl(fp, VIDIOC_OVERLAY, &start); + if (ret < 0) { + LOGE("tvout_v4l2_start_overlay" "VIDIOC_OVERLAY failed\n"); + return ret; + } + + return ret; +} + +int tvout_v4l2_stop_overlay(int fp) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int ret, stop =0; + + ret = ioctl(fp, VIDIOC_OVERLAY, &stop); + if (ret < 0) { + LOGE("tvout_v4l2_stop_overlay" "VIDIOC_OVERLAY failed\n"); + return ret; + } + + return ret; +} +#endif + +int hdmi_init_layer(int layer) +{ + int fd = -1; +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("### %s (layer = %d) called", __func__, layer); +#endif + + switch (layer) { + case HDMI_LAYER_VIDEO : + if (fp_tvout_v <= 0) { + fp_tvout_v = tvout_open(TVOUT_DEV_V); + if (fp_tvout_v < 0) { + LOGE("tvout video layer open failed\n"); + return -1; + } + fd = fp_tvout_v; + } + break; + case HDMI_LAYER_GRAPHIC_0 : + if (fp_tvout_g0 <= 0) { +#if defined(BOARD_USE_V4L2) + fp_tvout_g0 = tvout_open(TVOUT_DEV_G0); +#else + fp_tvout_g0 = fb_open(TVOUT_FB_G0); +#endif + if (fp_tvout_g0 < 0) { + LOGE("tvout graphic layer 0 open failed\n"); + return -1; + } + fd = fp_tvout_g0; + } + break; + case HDMI_LAYER_GRAPHIC_1 : + if (fp_tvout_g1 <= 0) { +#if defined(BOARD_USE_V4L2) + fp_tvout_g1 = tvout_open(TVOUT_DEV_G1); +#else + fp_tvout_g1 = fb_open(TVOUT_FB_G1); +#endif + if (fp_tvout_g1 < 0) { + LOGE("tvout graphic layer 1 open failed\n"); + return -1; + } + fd = fp_tvout_g1; + } + break; + default : + LOGE("%s::unmathced layer(%d) fail", __func__, layer); + fd = -1; + break; + } + + return fd; +} + +int hdmi_deinit_layer(int layer) +{ + int ret = 0; +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("### %s(layer = %d) called", __func__, layer); +#endif + switch (layer) { + case HDMI_LAYER_VIDEO : + if (0 < fp_tvout_v) { + close(fp_tvout_v); + fp_tvout_v = -1; + } + break; + case HDMI_LAYER_GRAPHIC_0 : + if (0 < fp_tvout_g0) { + close(fp_tvout_g0); + fp_tvout_g0 = -1; + } + break; + case HDMI_LAYER_GRAPHIC_1 : + if (0 < fp_tvout_g1) { + close(fp_tvout_g1); + fp_tvout_g1 = -1; + } + break; + default : + LOGE("%s::unmathced layer(%d) fail", __func__, layer); + ret = -1; + break; + } + + return ret; +} + +#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; + } +} + +#if defined(BOARD_USE_V4L2) +int hdmi_get_src_plane(int srcColorFormat, unsigned int *num_of_plane) +{ + int v4l2ColorFormat = HAL_PIXEL_FORMAT_2_V4L2_PIX(srcColorFormat); + + switch (v4l2ColorFormat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_RGB565X: + *num_of_plane = 1; + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV12MT: + case V4L2_PIX_FMT_NV21M: + *num_of_plane = 2; + break; + default: + LOGE("%s::invalid color type", __func__); + return -1; + } + + return 0; +} +#endif + +#if defined(BOARD_USE_V4L2) +int hdmi_set_v_param(int fd, int layer, + int srcColorFormat, + int src_w, int src_h, + SecBuffer * dstBuffer, + int dst_x, int dst_y, int dst_w, int dst_h) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int v4l2ColorFormat = HAL_PIXEL_FORMAT_2_V4L2_PIX(srcColorFormat); + int round_up_src_w; + int round_up_src_h; + unsigned int num_of_plane; + struct v4l2_rect rect; + + /* src_w, src_h round up to DWORD because of VP restriction */ +#if defined(SAMSUNG_EXYNOS4x12) + round_up_src_w = ROUND_UP(src_w, 16); +#else defined(SAMSUNG_EXYNOS4210) + round_up_src_w = ROUND_UP(src_w, 8); +#endif + round_up_src_h = ROUND_UP(src_h, 8); + + switch (v4l2ColorFormat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + dstBuffer->size.s = (round_up_src_w * round_up_src_h * 3) >> 1; + num_of_plane = 1; + break; + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV12MT: + case V4L2_PIX_FMT_NV21M: + dstBuffer->size.extS[0] = (round_up_src_w * round_up_src_h * 3) >> 1; + dstBuffer->size.extS[1] = (round_up_src_w * round_up_src_h * 3) >> 2; + num_of_plane = 2; + break; + default: + LOGE("%s::invalid color type", __func__); + return false; + break; + } + + hdmi_cal_rect(src_w, src_h, dst_w, dst_h, &rect); + rect.left = ALIGN(rect.left, 16); + + /* set format for VP input */ + if (tvout_std_v4l2_s_fmt(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_FIELD_ANY, round_up_src_w, round_up_src_h, v4l2ColorFormat, num_of_plane) < 0) { + LOGE("%s::tvout_std_v4l2_s_fmt()[video layer] failed", __func__); + return -1; + } + + /* set crop for VP input */ + if (tvout_std_v4l2_s_crop(fd, V4L2_BUF_TYPE_VIDEO_OVERLAY, V4L2_FIELD_ANY, 0, 0, src_w, src_h) < 0) { + LOGE("%s::tvout_std_v4l2_s_crop()[video layer] failed", __func__); + return -1; + } + + /* set crop for VP output */ + if (tvout_std_v4l2_s_crop(fd, 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()[video layer] failed", __func__); + return -1; + } + + /* request buffer for VP input */ + if (tvout_std_v4l2_reqbuf(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_MEMORY_USERPTR, HDMI_NUM_MIXER_BUF) < 0) { + LOGE("%s::tvout_std_v4l2_reqbuf(buf_num=%d)[video layer] failed", __func__, HDMI_NUM_MIXER_BUF); + return -1; + } + + return 0; +} + +int hdmi_set_g_param(int fd, int layer, + int srcColorFormat, + int src_w, int src_h, + SecBuffer * dstBuffer, + 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 v4l2ColorFormat = HAL_PIXEL_FORMAT_2_V4L2_PIX(srcColorFormat); + + rect.left = dst_x; + rect.top = dst_y; + +#if defined(BOARD_USES_FIMGAPI) + rect.width = dst_w; + rect.height = dst_h; +#else + rect.width = src_w; + rect.height = src_h; +#endif + + switch (v4l2ColorFormat) { + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB32: + dstBuffer->size.s = rect.width * rect.height << 2; + break; + case V4L2_PIX_FMT_RGB565X: + dstBuffer->size.s = rect.width * rect.height << 1; + break; + default: + LOGE("%s::invalid color type", __func__); + return false; + break; + } + + /* set format for mixer graphic layer input device*/ + if (tvout_std_v4l2_s_fmt(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_FIELD_ANY, rect.width, rect.height, v4l2ColorFormat, 1) < 0) { + LOGE("%s::tvout_std_v4l2_s_fmt() [layer=%d] failed", __func__, layer); + return -1; + } + + /* set crop for mixer graphic layer input device*/ + if (tvout_std_v4l2_s_crop(fd, 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() [layer=%d] failed", __func__, layer); + return -1; + } + + /* request buffer for mixer graphic layer input device */ + if (tvout_std_v4l2_reqbuf(fd, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, V4L2_MEMORY_USERPTR, HDMI_NUM_MIXER_BUF) < 0) { + LOGE("%s::tvout_std_v4l2_reqbuf(buf_num=%d) [layer=%d] failed", __func__, HDMI_NUM_MIXER_BUF, layer); + return -1; + } + + /* enable alpha blending for mixer graphic layer */ + if (tvout_std_v4l2_s_ctrl(fd, V4L2_CID_TV_LAYER_BLEND_ENABLE, 1) < 0) { + LOGE("%s::tvout_std_v4l2_s_ctrl() [layer=%d] failed", __func__, layer); + return -1; + } + + /* enable per-pixel blending for mixer graphic layer */ + if (tvout_std_v4l2_s_ctrl(fd, V4L2_CID_TV_PIXEL_BLEND_ENABLE, 1) < 0) { + LOGE("%s::tvout_std_v4l2_s_ctrl [layer=%d] failed", __func__, layer); + return false; + } + + /* set global alpha value for mixer graphic layer */ + if (tvout_std_v4l2_s_ctrl(fd, V4L2_CID_TV_LAYER_BLEND_ALPHA, 255) < 0) { + LOGE("%s::tvout_std_v4l2_s_ctrl() [layer=%d] failed", __func__, layer); + return -1; + } + + return 0; +} + +int hdmi_set_g_scaling(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, unsigned int hwc_layer) +{ +#if defined(BOARD_USES_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 (g_preset_id) { + case V4L2_DV_1080P60: + case V4L2_DV_1080P30: + case V4L2_DV_1080I60: + case V4L2_DV_720P60_SB_HALF: + case V4L2_DV_720P59_94_SB_HALF: + case V4L2_DV_1080P24_TB: + case V4L2_DV_1080P23_98_TB: + dst_color_format = CF_ARGB_8888; + dst_bpp = 4; + break; + case V4L2_DV_480P60: + case V4L2_DV_576P50: + case V4L2_DV_720P60: + case V4L2_DV_720P50_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)) { + dst_addr = (unsigned char *)g2d_reserved_memory[g2d_buf_index]; + + g2d_buf_index++; + if (g2d_buf_index >= HDMI_G2D_OUTPUT_BUF_NUM) + g2d_buf_index = 0; + + 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) fail", __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() fail", __func__); + return -1; + } + +#ifdef DEBUG_MSG_ENABLE + LOGD("hdmi_set_g_scaling:: \n \\ + layer=%d,\n \\ + srcColorFormat=%d,\n \\ + src_w=%d, src_h=%d,\n\\ + src_address=0x%x, dst_addr=0x%x,\n\\ + dst_x=%d, dst_y=%d, dst_w=%d, dst_h=%d ", + layer, + srcColorFormat, + src_w, src_h, + src_address, dst_addr, + dst_x, dst_y, dst_w, dst_h); +#endif + dstBuffer->virt.p = (char *)dst_addr; + } +#else + dstBuffer->virt.p = (char *)src_address; +#endif + + return 0; +} +#else +int hdmi_set_v_param(int layer, + int src_w, int src_h, int colorFormat, + unsigned int src_y_address, unsigned int src_c_address, + int dst_w, int dst_h) +{ +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int round_up_src_w; + int round_up_src_h; + if (fp_tvout_v <= 0) { + LOGE("fp_tvout is < 0 fail\n"); + return -1; + } + + /* src_w, src_h round up to DWORD because of VP restriction */ +#if defined(SAMSUNG_EXYNOS4x12) + round_up_src_w = ROUND_UP(src_w, 16); +#else defined(SAMSUNG_EXYNOS4210) + round_up_src_w = ROUND_UP(src_w, 8); +#endif + round_up_src_h = ROUND_UP(src_h, 8); + + vo_param.src.base_y = (void *)src_y_address; + vo_param.src.base_c = (void *)src_c_address; + vo_param.src.pix_fmt.width = round_up_src_w; + vo_param.src.pix_fmt.height = round_up_src_h; + vo_param.src.pix_fmt.field = V4L2_FIELD_NONE; + vo_param.src.pix_fmt.pixelformat = colorFormat; + + tvout_v4l2_s_fmt(fp_tvout_v, V4L2_BUF_TYPE_PRIVATE, &vo_param.src); + + vo_param.src_crop.width = src_w; + vo_param.src_crop.height = src_h; + + tvout_v4l2_s_crop(fp_tvout_v, V4L2_BUF_TYPE_PRIVATE, &vo_param.src_crop); + + if (dst_w * src_h <= dst_h * src_w) { + vo_param.dst_win.w.left = 0; + vo_param.dst_win.w.top = (dst_h - ((dst_w * src_h) / src_w)) >> 1; + vo_param.dst_win.w.width = dst_w; + vo_param.dst_win.w.height = ((dst_w * src_h) / src_w); + } else { + vo_param.dst_win.w.left = (dst_w - ((dst_h * src_w) / src_h)) >> 1; + vo_param.dst_win.w.top = 0; + vo_param.dst_win.w.width = ((dst_h * src_w) / src_h); + vo_param.dst_win.w.height = dst_h; + } + + vo_param.dst.fmt.priv = 10; + vo_param.dst_win.global_alpha = 255; + tvout_v4l2_s_fbuf(fp_tvout_v, &vo_param.dst); + tvout_v4l2_s_fmt(fp_tvout_v, V4L2_BUF_TYPE_VIDEO_OVERLAY, &vo_param.dst_win); + + return 0; +} + +int hdmi_gl_set_param(int layer, + int srcColorFormat, + int src_w, int src_h, + unsigned int src_y_address, unsigned int src_c_address, + int dst_x, int dst_y, int dst_w, int dst_h, + int rotVal) +{ +#if defined(BOARD_USES_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; + + struct fb_var_screeninfo var; + struct s5ptvfb_user_window window; + + int fp_tvout_g; + + if(layer == HDMI_LAYER_GRAPHIC_0) + fp_tvout_g = fp_tvout_g0; + else + fp_tvout_g = fp_tvout_g1; + + 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; + var.bits_per_pixel = 32; + var.transp.length = 8; + 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; + var.bits_per_pixel = 16; + var.transp.length = 4; + break; + } + + static unsigned int prev_src_addr = 0; + + if ((cur_g2d_address == 0) || (src_y_address != prev_src_addr)) { + dst_addr = (unsigned char *)g2d_reserved_memory[g2d_buf_index]; + + g2d_buf_index++; + if (g2d_buf_index >= HDMI_G2D_OUTPUT_BUF_NUM) + g2d_buf_index = 0; + + cur_g2d_address = (unsigned int)dst_addr; + prev_src_addr = src_y_address; + + srcAddr = {(addr_space)ADDR_PHYS, (unsigned long)src_y_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_PHYS, (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) fail", __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() fail", __func__); + return -1; + } + + var.xres = dst_w; + var.yres = dst_h; + + var.xres_virtual = var.xres; + var.yres_virtual = var.yres; + var.xoffset = 0; + var.yoffset = 0; + var.width = 0; + var.height = 0; + var.activate = FB_ACTIVATE_FORCE; + + window.x = dst_x; + window.y = dst_y; + + tvout_v4l2_s_baseaddr(fp_tvout_g, (void *)dst_addr); + put_vscreeninfo(fp_tvout_g, &var); + + if (ioctl(fp_tvout_g, S5PTVFB_WIN_POSITION, &window) < 0) { + LOGE("%s::S5PTVFB_WIN_POSITION ioctl failed.", __func__); + return -1; + } + } + + return 0; +#else + struct fb_var_screeninfo var; + struct s5ptvfb_user_window window; + + struct overlay_param ov_param; + + // set base address for grp layer0 of mixer + int fp_tvout_g; + +#ifdef DEBUG_MSG_ENABLE + LOGD("hdmi_gl_set_param:: \n \\ + layer=%d,\n \\ + srcColorFormat=%d,\n \\ + src_w=%d, src_h=%d,\n\\ + src_y_address=0x%x, src_c_address=0x%x,\n\\ + dst_x=%d, dst_y=%d, dst_w=%d, dst_h=%d ", + layer, + srcColorFormat, + src_w, src_h, + src_y_address, src_c_address, + dst_x, dst_y, dst_w, dst_h); +#endif + + if (layer == HDMI_LAYER_GRAPHIC_0) + fp_tvout_g = fp_tvout_g0; + else + fp_tvout_g = fp_tvout_g1; + + var.xres = src_w; + var.yres = src_h; + var.xres_virtual = var.xres; + var.yres_virtual = var.yres; + var.xoffset = 0; + var.yoffset = 0; + var.width = src_w; + var.height = src_h; + var.activate = FB_ACTIVATE_FORCE; + if (srcColorFormat == HAL_PIXEL_FORMAT_RGB_565) { + var.bits_per_pixel = 16; + var.transp.length = 0; + } + else { + var.bits_per_pixel = 32; + var.transp.length = 8; + } + + window.x = dst_x; + window.y = dst_y; + + tvout_v4l2_s_baseaddr(fp_tvout_g, (void *)src_y_address); + put_vscreeninfo(fp_tvout_g, &var); + if (ioctl(fp_tvout_g, S5PTVFB_WIN_POSITION, &window) < 0) { + LOGE("%s:: S5PTVFB_WIN_POSITION ioctl failed.", __func__); + return -1; + } + + return 0; +#endif +} +#endif + +int hdmi_cable_status() +{ +#if defined(BOARD_USE_V4L2) +#ifdef DEBUG_HDMI_HW_LEVEL + LOGD("%s", __func__); +#endif + + int cable_status = 0; + int fd = 0; + struct v4l2_control ctrl; + + fd = open(TVOUT_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; +#else + int cable_status = 0; + int fp_hpd = 0; + + fp_hpd = open(HPD_DEV, O_RDWR); + if (fp_hpd <= 0) { + LOGE("hpd drv open failed\n"); + return -1; + } + + //Delay about 0.3s + usleep(500000); + if (ioctl(fp_hpd, HPD_GET_STATE, &cable_status) < 0) { + LOGE("hpd drv HPD_GET_STATE ioctl failed\n"); + cable_status = -1; + } + + close(fp_hpd); + + return cable_status; +#endif +} + +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; +} + +#if defined(BOARD_USE_V4L2) +int hdmi_check_resolution(unsigned int preset_id) +{ + struct HDMIVideoParameter video; + struct HDMIAudioParameter audio; + + switch (preset_id) { + case V4L2_DV_480P60: + video.resolution = v720x480p_60Hz; + video.pixelAspectRatio = HDMI_PIXEL_RATIO_16_9; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_576P50: + video.resolution = v720x576p_50Hz; + video.pixelAspectRatio = HDMI_PIXEL_RATIO_16_9; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_720P60: + video.resolution = v1280x720p_60Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_720P50: + video.resolution = v1280x720p_50Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_1080P60: + video.resolution = v1920x1080p_60Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_1080P50: + video.resolution = v1920x1080p_50Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_1080I60: + video.resolution = v1920x1080i_60Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_1080I50: + video.resolution = v1920x1080i_50Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_480P59_94: + video.resolution = v720x480p_60Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_720P59_94: + video.resolution = v1280x720p_60Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_1080I59_94: + video.resolution = v1920x1080i_60Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_1080P59_94: + video.resolution = v1920x1080p_60Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_1080P30: + video.resolution = v1920x1080p_30Hz; + video.hdmi_3d_format = HDMI_2D_VIDEO_FORMAT; + break; + case V4L2_DV_720P60_SB_HALF: + video.resolution = v1280x720p_60Hz; + video.hdmi_3d_format = HDMI_3D_SSH_FORMAT; + break; + case V4L2_DV_720P59_94_SB_HALF: + video.resolution = v1280x720p_60Hz; + video.hdmi_3d_format = HDMI_3D_SSH_FORMAT; + break; + case V4L2_DV_720P50_TB: + video.resolution = v1280x720p_50Hz; + video.hdmi_3d_format = HDMI_3D_TB_FORMAT; + break; + case V4L2_DV_1080P24_TB: + video.resolution = v1920x1080p_24Hz; + video.hdmi_3d_format = HDMI_3D_TB_FORMAT; + break; + case V4L2_DV_1080P23_98_TB: + video.resolution = v1920x1080p_24Hz; + video.hdmi_3d_format = HDMI_3D_TB_FORMAT; + break; + default: + LOGE("%s::unmathced preset_id(%d)", __func__, preset_id); + return -1; + break; + } + + if (!EDIDVideoResolutionSupport(&video)) { +#ifdef DEBUG_MSG_ENABLE + LOGD("%s::EDIDVideoResolutionSupport(%d) fail (not suppoted preset_id) \n", __func__, preset_id); +#endif + return -1; + } + + return 0; +} + +int hdmi_resolution_2_preset_id(unsigned int resolution, int * w, int * h, unsigned int *preset_id) +{ + int ret = 0; + + switch (resolution) { + case 1080960: + *w = 1920; + *h = 1080; + *preset_id = V4L2_DV_1080P60; + break; + case 1080950: + *w = 1920; + *h = 1080; + *preset_id = V4L2_DV_1080P50; + break; + case 1080930: + *w = 1920; + *h = 1080; + *preset_id = V4L2_DV_1080P30; + break; + case 1080924: + *w = 1920; + *h = 1080; + *preset_id = V4L2_DV_1080P24_TB; + break; + case 1080160: + *w = 1920; + *h = 1080; + *preset_id = V4L2_DV_1080I60; + break; + case 1080150: + *w = 1920; + *h = 1080; + *preset_id = V4L2_DV_1080I50; + break; + case 720960: + *w = 1280; + *h = 720; + *preset_id = V4L2_DV_720P60; + break; + case 7209601: + *w = 1280; + *h = 720; + *preset_id = V4L2_DV_720P60_SB_HALF; + break; + case 720950: + *w = 1280; + *h = 720; + *preset_id = V4L2_DV_720P50; + break; + case 7209501: + *w = 1280; + *h = 720; + *preset_id = V4L2_DV_720P50_TB; + break; + case 5769501: + *w = 720; + *h = 576; + *preset_id = V4L2_DV_576P50; + break; + case 5769502: + *w = 720; + *h = 576; + *preset_id = V4L2_DV_576P50; + break; + case 4809601: + *w = 720; + *h = 480; + *preset_id = V4L2_DV_480P60; + break; + case 4809602: + *w = 720; + *h = 480; + *preset_id = V4L2_DV_480P60; + break; + default: + LOGE("%s::unmathced resolution(%d)", __func__, resolution); + ret = -1; + break; + } + + return ret; +} +#else +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) +{ + int ret = 0; + + switch (resolution) { + case 1080960: + *std_id = V4L2_STD_1080P_60; + *w = 1920; + *h = 1080; + break; + case 1080950: + *std_id = V4L2_STD_1080P_50; + *w = 1920; + *h = 1080; + break; + case 1080930: + *std_id = V4L2_STD_1080P_30; + *w = 1920; + *h = 1080; + break; + case 1080924: + *std_id = V4L2_STD_TVOUT_1080P_24_TB; + *w = 1920; + *h = 1080; + break; + case 1080160: + *std_id = V4L2_STD_1080I_60; + *w = 1920; + *h = 1080; + break; + case 1080150: + *std_id = V4L2_STD_1080I_50; + *w = 1920; + *h = 1080; + break; + case 720960: + *std_id = V4L2_STD_720P_60; + *w = 1280; + *h = 720; + break; + case 7209601: + *std_id = V4L2_STD_TVOUT_720P_60_SBS_HALF; + *w = 1280; + *h = 720; + break; + case 720950: + *std_id = V4L2_STD_720P_50; + *w = 1280; + *h = 720; + break; + case 7209501: + *std_id = V4L2_STD_TVOUT_720P_50_TB; + *w = 1280; + *h = 720; + break; + case 5769501: + *std_id = V4L2_STD_576P_50_16_9; + *w = 720; + *h = 576; + break; + case 5769502: + *std_id = V4L2_STD_576P_50_4_3; + *w = 720; + *h = 576; + break; + case 4809601: + *std_id = V4L2_STD_480P_60_16_9; + *w = 720; + *h = 480; + break; + case 4809602: + *std_id = V4L2_STD_480P_60_4_3; + *w = 720; + *h = 480; + break; + default: + LOGE("%s::unmathced resolution(%d)", __func__, resolution); + ret = -1; + break; + } + + return ret; +} +#endif + +int hdmi_enable_hdcp(unsigned int hdcp_en) +{ + if (ioctl(fp_tvout, 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(void) +{ + 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(fp_tvout, VIDIOC_INIT_AUDIO, 1) < 0) { + LOGE("%s::VIDIOC_INIT_AUDIO(1) fail", __func__); + ret = -1; + } + } else { + if (ioctl(fp_tvout, VIDIOC_INIT_AUDIO, 0) < 0) { + LOGE("%s::VIDIOC_INIT_AUDIO(0) fail", __func__); + ret = -1; + } + } + + return ret; +} + +} |