| |
| /* |
| * Copyright (c) 2011 Samsung Electronics Co., Ltd. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| * Authors: |
| * Shirish S <s.shirish@samsung.com> |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <sys/ioctl.h> |
| #include <sys/mman.h> |
| #include <sys/time.h> |
| #include <linux/vt.h> |
| #include <linux/videodev2.h> |
| #include <linux/fb.h> |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <poll.h> |
| #include <signal.h> |
| #include <asm/types.h> |
| #include <sys/socket.h> |
| #include <linux/rtnetlink.h> |
| #include <linux/netlink.h> |
| #include <linux/i2c.h> |
| #include <linux/i2c-dev.h> |
| #include <linux/videodev2.h> |
| #include <X11/Xatom.h> |
| #include <X11/extensions/Xv.h> |
| /* all driver need this */ |
| #include "xf86.h" |
| #include "xf86_OSproc.h" |
| |
| #include "mipointer.h" |
| #include "mibstore.h" |
| #include "micmap.h" |
| #include "colormapst.h" |
| #include "xf86cmap.h" |
| #include "xorg-server.h" |
| /* for visuals */ |
| #include "fb.h" |
| |
| #if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 6 |
| #include "xf86Resources.h" |
| #include "xf86RAC.h" |
| #endif |
| |
| #include "xf86Crtc.h" |
| #include "xf86xv.h" |
| |
| |
| #include "fourcc.h" |
| |
| #include "exynos5_hdmi.h" |
| #include "video.h" |
| |
| #include "omap_driver.h" |
| |
| /* Private data for TV output */ |
| typedef struct _EXYNOS5HDMIOutputPrivateRec { |
| I2CBusPtr pI2CBus; |
| Bool hdtv_connected; |
| Bool hdtv_720x576_supported; |
| Bool hdtv_720x480_supported; |
| int hdtv_connector_type; /* HDMI/DVI */ |
| v4l2_std_id mode_720x576; |
| v4l2_std_id mode_720x480; |
| int modeHDisplay; |
| int modeVDisplay; |
| } EXYNOS5HDMIOutputPrivateRec, *EXYNOS5HDMIOutputPrivatePtr; |
| |
| /* Accepted resolutions for TV */ |
| typedef struct _tv_input_res { |
| int HDisplay; |
| int VDisplay; |
| float VRefresh; |
| int Flags; |
| int res; |
| v4l2_std_id std; |
| int priority; |
| } tv_input_res; |
| static tv_input_res tv_input_res_table[] = { |
| {1920, 1080, 30.0, 0, v1920x1080p_30Hz, V4L2_STD_1080P_30, 0}, |
| {1920, 1080, 60.0, 0, v1920x1080p_60Hz, V4L2_STD_1080P_60, 1}, |
| {1920, 1080, 50.0, 0, v1920x1080p_50Hz, V4L2_STD_1080P_50, 2}, |
| {1280, 720, 60.0, 0, v1280x720p_60Hz, V4L2_STD_720P_60, 3}, |
| {1280, 720, 50.0, 0, v1280x720p_50Hz, V4L2_STD_720P_50, 4}, |
| {720, 576, 50.0, 0, v720x576p_50Hz, V4L2_STD_576P_50_4_3, 5}, |
| {720, 480, 60.0, 0, v720x480p_60Hz, V4L2_STD_480P_60_4_3, 6}, |
| /*{1920, 1080, 60.0, V_INTERLACE, v1920x1080i_60Hz, V4L2_STD_1080I_60, 7}, |
| {1920, 1080, 50.0, V_INTERLACE, v1920x1080i_50Hz, V4L2_STD_1080I_50, 8},*/ |
| }; |
| typedef unsigned short u16; |
| typedef struct _dv_presets { |
| u16 width; |
| u16 height; |
| const char *name; |
| } dv_presets; |
| #ifdef EXYNOS_EDID /* FUTURE REQUIREMENT FOR EDID */ |
| static dv_presets dv_presets_table [] = { |
| { 0, 0, "Invalid" }, /* V4L2_DV_INVALID */ |
| { 720, 480, "480p@59.94" }, /* V4L2_DV_480P59_94 */ |
| { 720, 576, "576p@50" }, /* V4L2_DV_576P50 */ |
| { 1280, 720, "720p@24" }, /* V4L2_DV_720P24 */ |
| { 1280, 720, "720p@25" }, /* V4L2_DV_720P25 */ |
| { 1280, 720, "720p@30" }, /* V4L2_DV_720P30 */ |
| { 1280, 720, "720p@50" }, /* V4L2_DV_720P50 */ |
| { 1280, 720, "720p@59.94" }, /* V4L2_DV_720P59_94 */ |
| { 1280, 720, "720p@60" }, /* V4L2_DV_720P60 */ |
| { 1920, 1080, "1080i@29.97" }, /* V4L2_DV_1080I29_97 */ |
| { 1920, 1080, "1080i@30" }, /* V4L2_DV_1080I30 */ |
| { 1920, 1080, "1080i@25" }, /* V4L2_DV_1080I25 */ |
| { 1920, 1080, "1080i@50" }, /* V4L2_DV_1080I50 */ |
| { 1920, 1080, "1080i@60" }, /* V4L2_DV_1080I60 */ |
| { 1920, 1080, "1080p@24" }, /* V4L2_DV_1080P24 */ |
| { 1920, 1080, "1080p@25" }, /* V4L2_DV_1080P25 */ |
| { 1920, 1080, "1080p@30" }, /* V4L2_DV_1080P30 */ |
| { 1920, 1080, "1080p@50" }, /* V4L2_DV_1080P50 */ |
| { 1920, 1080, "1080p@60" }, /* V4L2_DV_1080P60 */ |
| }; |
| #endif |
| #define TV_INPUT_RES_TABLE_SIZE (sizeof(tv_input_res_table)/sizeof(tv_input_res_table[0])) |
| |
| /* Output property resources */ |
| |
| /* PAL modes */ |
| #define PAL_MODE_NAME "pal_mode" |
| #define NUM_PAL_MODES 6 |
| const char *pal_mode_names[] = { |
| "PAL-M", |
| "PAL-N", |
| "PAL-Nc", |
| "PAL-60", |
| "PAL-BDGHI", |
| "DIGITAL", |
| }; |
| static Atom pal_mode_atom; |
| static Atom pal_mode_name_atoms[NUM_PAL_MODES]; |
| static Bool isstreaming; |
| /* NTSC modes */ |
| #define NTSC_MODE_NAME "ntsc_mode" |
| #define NUM_NTSC_MODES 3 |
| const char *ntsc_mode_names[] = { |
| "NTSC-M", |
| "NTSC-443", |
| "DIGITAL", |
| }; |
| static Atom ntsc_mode_atom; |
| static Atom ntsc_mode_name_atoms[NUM_NTSC_MODES]; |
| #define BUFFER_CNT 2 |
| struct buffer { |
| int index; |
| void *data; |
| size_t size; |
| size_t width; |
| size_t height; |
| |
| /* buffer state */ |
| double t; |
| }; |
| struct setup { |
| char *path; |
| int width; |
| int height; |
| int x; |
| int y; |
| }; |
| struct crop_info { |
| int full_width; |
| int full_height; |
| int width; |
| int height; |
| int xoffset; |
| int yoffset; |
| }; |
| struct context { |
| int fd; |
| struct buffer *buffer; |
| struct v4l2_plane planes; |
| size_t buffer_cnt; |
| }; |
| |
| int exynos5_init_hdmi(int fp_tvout, v4l2_std_id std_id, int output_type, int bufFD) |
| { |
| int ret; |
| struct v4l2_buffer buf; |
| struct v4l2_plane plane; |
| struct v4l2_format fmt; |
| /* allocate buffers */ |
| struct v4l2_requestbuffers rqbufs; |
| int type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; |
| |
| if(isstreaming) |
| return 0; |
| |
| /* configure desired image size */ |
| fmt.type = type; |
| fmt.fmt.pix_mp.width = TV_WIDTH; |
| fmt.fmt.pix_mp.height = TV_HEIGHT; |
| fmt.fmt.pix_mp.num_planes = 1; |
| /* format is hardcoded: draw procedures work only in 32-bit mode */ |
| fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_BGR32; |
| |
| ret = ioctl(fp_tvout, VIDIOC_S_FMT, &fmt); |
| if(ret < 0) { |
| xf86Msg(X_ERROR," %s: VIDIOC_S_FMT failed\n", __func__); |
| return ret; |
| } |
| |
| /* update format struct to values adjusted by a driver */ |
| ret = ioctl(fp_tvout, VIDIOC_G_FMT, &fmt); |
| if(ret < 0) { |
| xf86Msg(X_ERROR," %s: VIDIOC_G_FMT failed\n", __func__); |
| return ret; |
| } |
| |
| rqbufs.count = BUFFER_CNT; |
| rqbufs.type = type; |
| rqbufs.memory = V4L2_MEMORY_DMABUF; |
| |
| ret = ioctl(fp_tvout, VIDIOC_REQBUFS, &rqbufs); |
| if((ret < 0) || (rqbufs.count != BUFFER_CNT)){ |
| xf86Msg(X_ERROR," %s: VIDIOC_REQBUFS failed becase %s\n", __func__,strerror(-ret)); |
| return ret; |
| } |
| |
| memset(&buf, 0, sizeof(buf)); |
| memset(&plane, 0, sizeof(plane)); |
| buf.type = type; |
| buf.index = 0; |
| buf.memory = V4L2_MEMORY_DMABUF; |
| buf.m.planes = &plane; |
| buf.m.planes[0].m.fd = bufFD; |
| buf.length = 1; |
| ret = ioctl(fp_tvout, VIDIOC_QBUF, &buf); |
| if(ret < 0) { |
| xf86Msg(X_ERROR," %s: VIDIOC_QBUF failed ret=%s \n", __func__,strerror(-ret)); |
| return ret; |
| } |
| |
| /* start streaming */ |
| ret = ioctl(fp_tvout, VIDIOC_STREAMON, &type); |
| if(ret < 0) { |
| xf86Msg(X_ERROR," %s: VIDIOC_STREAMON failed ret=%s\n", __func__,strerror(ret)); |
| return ret; |
| } |
| |
| isstreaming=1; |
| return 0; |
| } |
| |
| #ifdef EXYNOS_EDID |
| |
| /* I2C bus routines for DDC */ |
| static void EXYNOS5I2CUDelay(I2CBusPtr b, int usec) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void EXYNOS5I2CPutBits(I2CBusPtr b, int scl, int sda) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void EXYNOS5I2CGetBits(I2CBusPtr b, int *scl, int *sda) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static Bool EXYNOS5I2CStart(I2CBusPtr b, int timeout) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return FALSE; |
| } |
| |
| static Bool EXYNOS5I2CAddress(I2CDevPtr d, I2CSlaveAddr addr) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return FALSE; |
| } |
| |
| static void EXYNOS5I2CStop(I2CDevPtr d) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static Bool EXYNOS5I2CPutByte(I2CDevPtr d, I2CByte data) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return FALSE; |
| } |
| |
| static Bool EXYNOS5I2CGetByte(I2CDevPtr d, I2CByte *data, Bool last) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return FALSE; |
| } |
| |
| static int EXYNOS5I2CWriteRead(I2CDevPtr d, I2CByte *WriteBuffer, int nWrite, I2CByte *ReadBuffer, int nRead) |
| { |
| int i2c_fd = (int)d->pI2CBus->DriverPrivate.uval; |
| struct i2c_rdwr_ioctl_data msgset; |
| struct i2c_msg msgs[2]; |
| int ret; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| msgs[0].addr = d->SlaveAddr>>1; |
| msgs[0].flags = 0; |
| msgs[0].len = nWrite; |
| msgs[0].buf = WriteBuffer; |
| |
| msgs[1].addr = d->SlaveAddr>>1; |
| msgs[1].flags = I2C_M_RD; |
| msgs[1].len = nRead; |
| msgs[1].buf = ReadBuffer; |
| |
| msgset.nmsgs = 2; |
| msgset.msgs = msgs; |
| |
| ret = ioctl(i2c_fd, I2C_RDWR, &msgset); |
| if(ret < 0) { |
| xf86Msg(X_ERROR,"%s: I2C_RDWR failed because %s\n", __func__,strerror(-ret)); |
| return ret; |
| } |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| |
| return 0; |
| } |
| |
| /* I2C bus initialization for DDC */ |
| static Bool EXYNOS5I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_fd, char *name) |
| { |
| I2CBusPtr pI2CBus; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| pI2CBus = xf86CreateI2CBusRec(); |
| |
| if (!pI2CBus) |
| return FALSE; |
| |
| pI2CBus->BusName = name; |
| pI2CBus->scrnIndex = pScrn->scrnIndex; |
| |
| pI2CBus->DriverPrivate.uval = (unsigned long)i2c_fd; |
| |
| pI2CBus->I2CWriteRead = EXYNOS5I2CWriteRead; |
| |
| if (!xf86I2CBusInit(pI2CBus)) |
| return FALSE; |
| |
| *bus_ptr = pI2CBus; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| |
| return TRUE; |
| } |
| |
| #endif |
| /* NTSC/PAL SetProperty helper routines */ |
| |
| /* The mode to index and index to mode is required in different contexts: |
| * in exynos5_hdmi_output_create_resources and |
| * exynos5_hdmi_output_set_property. |
| */ |
| |
| static int pal_mode_to_index(v4l2_std_id mode) |
| { |
| int index; |
| |
| switch(mode) { |
| case V4L2_STD_PAL_M: |
| index = 0; |
| break; |
| case V4L2_STD_PAL_N: |
| index = 1; |
| break; |
| case V4L2_STD_PAL_Nc: |
| index = 2; |
| break; |
| case V4L2_STD_PAL_60: |
| index = 3; |
| break; |
| case V4L2_STD_PAL_BDGHI: |
| index = 4; |
| break; |
| case V4L2_STD_576P_50_4_3: |
| index = 5; |
| break; |
| default: |
| index = 0; |
| break; |
| } |
| |
| return index; |
| } |
| |
| static v4l2_std_id pal_index_to_mode(int index) |
| { |
| v4l2_std_id mode; |
| |
| switch(index) { |
| case 0: |
| mode = V4L2_STD_PAL_M; |
| break; |
| case 1: |
| mode = V4L2_STD_PAL_N; |
| break; |
| case 2: |
| mode = V4L2_STD_PAL_Nc; |
| break; |
| case 3: |
| mode = V4L2_STD_PAL_60; |
| break; |
| case 4: |
| mode = V4L2_STD_PAL_BDGHI; |
| break; |
| case 5: |
| mode = V4L2_STD_576P_50_4_3; |
| break; |
| default: |
| mode = V4L2_STD_PAL_M; |
| break; |
| } |
| |
| return mode; |
| } |
| /* The mode to index and index to mode is required in different contexts: |
| * in exynos5_hdmi_output_create_resources and |
| * exynos5_hdmi_output_set_property. |
| */ |
| static int ntsc_mode_to_index(v4l2_std_id mode) |
| { |
| int index; |
| |
| switch(mode) { |
| case V4L2_STD_NTSC_M: |
| index = 0; |
| break; |
| case V4L2_STD_NTSC_443: |
| index = 1; |
| break; |
| case V4L2_STD_480P_60_4_3: |
| index = 2; |
| break; |
| default: |
| index = 0; |
| break; |
| } |
| |
| return index; |
| } |
| |
| static v4l2_std_id ntsc_index_to_mode(int index) |
| { |
| v4l2_std_id mode; |
| |
| switch(index) { |
| case 0: |
| mode = V4L2_STD_NTSC_M; |
| break; |
| case 1: |
| mode = V4L2_STD_NTSC_443; |
| break; |
| case 2: |
| mode = V4L2_STD_480P_60_4_3; |
| break; |
| default: |
| mode = V4L2_STD_NTSC_M; |
| break; |
| } |
| |
| return mode; |
| } |
| |
| static int pal_mode_lookup(const char *name) |
| { |
| int i; |
| |
| for (i = 0; i < NUM_PAL_MODES; i++) |
| if (!strcmp(name, pal_mode_names[i])) |
| return i; |
| |
| return -1; |
| } |
| |
| static int ntsc_mode_lookup(const char *name) |
| { |
| int i; |
| |
| for (i = 0; i < NUM_NTSC_MODES; i++) |
| if (!strcmp(name, ntsc_mode_names[i])) |
| return i; |
| |
| return -1; |
| } |
| |
| |
| /* CRTC routines for RandR support of TV */ |
| static void |
| exynos5_hdmi_crtc_dpms(xf86CrtcPtr crtc, int mode) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| #ifdef EXYNOS_EDID |
| static void |
| exynos5_hdmi_crtc_save(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_restore(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| #endif |
| static Bool |
| exynos5_hdmi_crtc_lock(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return TRUE; |
| } |
| |
| static void |
| exynos5_hdmi_crtc_unlock(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static Bool |
| exynos5_hdmi_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, |
| DisplayModePtr adjusted_mode) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return TRUE; |
| } |
| |
| static void |
| exynos5_hdmi_crtc_prepare(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| /* Sets the viewport coordinates(x,y) for TV in the virtual framebuffer */ |
| static void |
| exynos5_hdmi_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, |
| DisplayModePtr adjusted_mode, int x, int y) |
| { |
| OMAPPtr fPtr = OMAPPTR(crtc->scrn); |
| int ret; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| fPtr->fb_tv_var.xoffset=x; |
| fPtr->fb_tv_var.yoffset=y; |
| |
| ret = exynos5_init_hdmi(fPtr->tvout_std_fd, 0, 0,fPtr->dma_fd); |
| if(ret) { |
| xf86Msg(X_ERROR, "%s: TV Init failed because %s\n",__func__,strerror(-ret)); |
| return; |
| } |
| |
| ret = ioctl(fPtr->fb_tv_fd, FBIOPUT_VSCREENINFO, &fPtr->fb_tv_var); |
| if(ret < 0) { |
| xf86Msg(X_ERROR, "%s: FBIOPUT_VSCREENINFO failed %s\n", __func__,strerror(-ret)); |
| return; |
| } |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_commit(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, |
| CARD16 *blue, int size) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| #ifdef EXYNOS_EDID |
| static void * |
| exynos5_hdmi_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return NULL; |
| } |
| |
| static PixmapPtr |
| exynos5_hdmi_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return NULL; |
| } |
| |
| static void |
| exynos5_hdmi_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr pPixmap, void *data) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_show_cursor(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_hide_cursor(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_load_cursor_image(xf86CrtcPtr crtc, CARD8 *image) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_crtc_destroy(xf86CrtcPtr crtc) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static Bool |
| exynos5_hdmi_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, |
| Rotation rotation, int x, int y) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return TRUE; |
| } |
| |
| #endif |
| static void |
| exynos5_hdmi_crtc_set_origin(xf86CrtcPtr crtc, int x, int y) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static const xf86CrtcFuncsRec exynos5_hdmi_crtc_funcs = { |
| .dpms = exynos5_hdmi_crtc_dpms, |
| .lock = exynos5_hdmi_crtc_lock, |
| .unlock = exynos5_hdmi_crtc_unlock, |
| .mode_fixup = exynos5_hdmi_crtc_mode_fixup, |
| .prepare = exynos5_hdmi_crtc_prepare, |
| .mode_set = exynos5_hdmi_crtc_mode_set, |
| .commit = exynos5_hdmi_crtc_commit, |
| .gamma_set = exynos5_hdmi_crtc_gamma_set, |
| .set_origin = exynos5_hdmi_crtc_set_origin, |
| }; |
| |
| |
| /* TV output functions for RandR */ |
| |
| /* Creates resouces for NTSC/PAL SetProperty function */ |
| static void |
| exynos5_hdmi_output_create_resources(xf86OutputPtr output) |
| { |
| int err, i; |
| EXYNOS5HDMIOutputPrivatePtr tv_priv = output->driver_private; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| /* Set up analog TV's PAL mode */ |
| pal_mode_atom = MakeAtom(PAL_MODE_NAME, sizeof(PAL_MODE_NAME) - 1, TRUE); |
| if(pal_mode_atom == 0) { |
| xf86Msg(X_ERROR,"%s: MakeAtom failed, %d\n", __func__, (int)pal_mode_atom ); |
| return; |
| } |
| |
| for(i = 0; i < NUM_PAL_MODES; i++) { |
| pal_mode_name_atoms[i] = MakeAtom(pal_mode_names[i], strlen(pal_mode_names[i]), TRUE); |
| if(pal_mode_name_atoms[i] == 0) { |
| xf86Msg(X_ERROR,"%s: MakeAtom failed for pal_mode_name_atoms[%d] iteration\n", __func__, i ); |
| return; |
| } |
| |
| } |
| |
| err = RRConfigureOutputProperty(output->randr_output, pal_mode_atom, FALSE, FALSE, FALSE, NUM_PAL_MODES, (INT32 *)pal_mode_name_atoms); |
| if (err != 0) { |
| xf86Msg(X_ERROR,"%s: RRConfigureOutputProperty error, %d\n", __func__, err); |
| return; |
| } |
| |
| err = RRChangeOutputProperty(output->randr_output, pal_mode_atom, XA_ATOM, 32, PropModeReplace, 1, &pal_mode_name_atoms[pal_mode_to_index(tv_priv->mode_720x576)], FALSE, TRUE); |
| if (err != 0) { |
| xf86Msg(X_ERROR,"%s: RRChangeOutputProperty error, %d\n", __func__, err); |
| return; |
| } |
| |
| /* Set up analog TV's NTSC mode */ |
| ntsc_mode_atom = MakeAtom(NTSC_MODE_NAME, sizeof(NTSC_MODE_NAME) - 1, TRUE); |
| |
| for(i = 0; i < NUM_NTSC_MODES; i++) { |
| ntsc_mode_name_atoms[i] = MakeAtom(ntsc_mode_names[i], strlen(ntsc_mode_names[i]), TRUE); |
| if(ntsc_mode_name_atoms[i] == 0) { |
| xf86Msg(X_ERROR,"%s: MakeAtom failed for ntsc_mode_name_atoms[%d] iteration\n", __func__,i ); |
| return; |
| } |
| } |
| |
| err = RRConfigureOutputProperty(output->randr_output, ntsc_mode_atom, FALSE, FALSE, FALSE, NUM_NTSC_MODES, (INT32 *)ntsc_mode_name_atoms); |
| if (err != 0) { |
| xf86Msg(X_ERROR,"%s: RRConfigureOutputProperty error, %d\n", __func__, err); |
| return; |
| } |
| |
| err = RRChangeOutputProperty(output->randr_output, ntsc_mode_atom, XA_ATOM, 32, PropModeReplace, 1, &ntsc_mode_name_atoms[ntsc_mode_to_index(tv_priv->mode_720x480)], FALSE, TRUE); |
| if (err != 0) |
| xf86Msg(X_ERROR,"%s: RRChangeOutputProperty error, %d\n", __func__, err); |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| /* Power management function */ |
| static void |
| exynos5_hdmi_output_dpms(xf86OutputPtr output, int mode) |
| { |
| OMAPPtr fPtr = OMAPPTR(output->scrn); |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++, mode=%d\n", __func__, mode); |
| /* TODO: The below functionalities need to be properly implemented |
| * in the device driver, currently they are dummy*/ |
| if(mode == DPMSModeOn) { |
| if (ioctl(fPtr->fb_tv_fd, FBIOBLANK, FB_BLANK_UNBLANK)) { |
| xf86Msg(X_ERROR, "%s: failed ioctl FBIOBLANK\n", __func__); |
| return; |
| } |
| } |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_output_save(xf86OutputPtr output) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_output_restore(xf86OutputPtr output) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static int |
| exynos5_hdmi_output_mode_valid(xf86OutputPtr output, DisplayModePtr pMode) |
| { |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| pMode->HDisplay=TV_WIDTH; |
| pMode->VDisplay =TV_HEIGHT; |
| pMode->VRefresh = xf86ModeVRefresh(pMode); |
| |
| |
| /* If HDTV is not connected, we support 720x576 and 720x480 always so that analog |
| * TV can be enabled anytime */ |
| if(pMode->HDisplay == TV_WIDTH && (pMode->VDisplay == 576 || pMode->VDisplay == TV_HEIGHT)) { |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return MODE_OK; |
| }else |
| { |
| xf86Msg(X_ERROR, "%s: Mode (%d x %d @ %f) not supported\n", __func__,pMode->HDisplay,pMode->VDisplay,pMode->VRefresh); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return MODE_ERROR; |
| } |
| |
| } |
| |
| static Bool |
| exynos5_hdmi_output_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, |
| DisplayModePtr adjusted_mode) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return TRUE; |
| } |
| |
| static void |
| exynos5_hdmi_output_prepare(xf86OutputPtr output) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_output_commit(xf86OutputPtr output) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| output->funcs->dpms(output, DPMSModeOn); |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static void |
| exynos5_hdmi_output_mode_set(xf86OutputPtr output, DisplayModePtr mode, |
| DisplayModePtr adjusted_mode) |
| { |
| OMAPPtr fPtr = OMAPPTR(output->scrn); |
| EXYNOS5HDMIOutputPrivatePtr tv_priv = output->driver_private; |
| int ret; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| mode->VRefresh = xf86ModeVRefresh(mode); |
| |
| /* Other than 720x576 and 720x480, rest of the resolutions are for HDTV */ |
| ret = exynos5_init_hdmi(fPtr->tvout_std_fd, tv_input_res_table[6].std, tv_priv->hdtv_connector_type, fPtr->dma_fd); |
| if(ret) { |
| xf86Msg(X_ERROR, "%s: TV Init failed %s \n", __func__,strerror(-ret)); |
| return; |
| } |
| |
| |
| /* In case of dynamic stride */ |
| if(!fPtr->bFixedStride) { |
| EXYNOS5DBGMSG(X_INFO, "%s: dynamic stride\n", __func__); |
| |
| /* Change the framebuffer dimensions */ |
| fPtr->fb_tv_var.xres = fPtr->fb_tv_var.xres_virtual = mode->HDisplay; |
| fPtr->fb_tv_var.yres = fPtr->fb_tv_var.yres_virtual = mode->VDisplay; |
| |
| ret = ioctl(fPtr->fb_tv_fd, FBIOPUT_VSCREENINFO, &fPtr->fb_tv_var); |
| if( ret < 0) { |
| xf86Msg(X_ERROR, "%s: FBIOPUT_VSCREENINFO failed %s\n", __func__,strerror(-ret)); |
| return ; |
| } |
| } |
| |
| /* We need to remember the resolution that is set here */ |
| tv_priv->modeHDisplay = mode->HDisplay; |
| tv_priv->modeVDisplay = mode->VDisplay; |
| |
| xf86DrvMsg(0, X_INFO, "Changing mode to %i %i %i %i\n", mode->HDisplay, mode->VDisplay, mode->HDisplay, mode->HDisplay*2); |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static xf86OutputStatus |
| exynos5_hdmi_output_detect(xf86OutputPtr output) |
| { |
| unsigned int hpd_status = 0; |
| #ifdef EXYNOS_HPD |
| int ret; |
| #endif |
| EXYNOS5HDMIOutputPrivatePtr tv_priv = output->driver_private; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| #ifdef EXYNOS_HPD |
| /* Open HPD driver for hot-plug detection of HDTV */ |
| if((fPtr->hpd_fd = open(fPtr->hpd_dev_name, O_RDWR)) < 0) { |
| xf86Msg(X_ERROR, "%s: HPD device open failed\n", __func__); |
| tv_priv->hdtv_connected = FALSE; |
| return XF86OutputStatusDisconnected; |
| } |
| |
| ret = read(fPtr->hpd_fd, &hpd_status, sizeof(unsigned int)); |
| if(ret < 0) { |
| xf86Msg(X_ERROR, "%s: read failed %s\n", __func__,strerror(-ret)); |
| return; |
| } |
| |
| xf86Msg(X_INFO, "%s: HPD status = %u\n", __func__, hpd_status); |
| |
| close(fPtr->hpd_fd); |
| #else |
| hpd_status = 1; |
| #endif |
| |
| if(hpd_status == 1) |
| tv_priv->hdtv_connected = TRUE; |
| else |
| tv_priv->hdtv_connected = FALSE; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| |
| return (hpd_status == 1) ? XF86OutputStatusConnected : XF86OutputStatusDisconnected ; |
| } |
| |
| |
| DisplayModePtr tv_make_mode( int xres, int yres, DisplayModePtr prev ) |
| { |
| DisplayModePtr mode_ptr; |
| unsigned int hactive_s = xres; |
| unsigned int vactive_s = yres; |
| |
| mode_ptr = xnfcalloc(1, sizeof(DisplayModeRec)); |
| |
| mode_ptr->HDisplay = hactive_s; |
| mode_ptr->HSyncStart = hactive_s + 20; |
| mode_ptr->HSyncEnd = hactive_s + 40; |
| mode_ptr->HTotal = hactive_s + 80; |
| |
| mode_ptr->VDisplay = vactive_s; |
| mode_ptr->VSyncStart = vactive_s + 20; |
| mode_ptr->VSyncEnd = vactive_s + 40; |
| mode_ptr->VTotal = vactive_s + 80; |
| |
| mode_ptr->VRefresh = 60.0; |
| |
| mode_ptr->Clock = (int) (mode_ptr->VRefresh * mode_ptr->VTotal * mode_ptr->HTotal / 1000.0); |
| |
| mode_ptr->type = M_T_DRIVER; |
| |
| xf86SetModeDefaultName(mode_ptr); |
| |
| mode_ptr->next = NULL; |
| mode_ptr->prev = prev; |
| |
| return mode_ptr; |
| } |
| |
| static DisplayModePtr |
| exynos5_hdmi_output_get_modes(xf86OutputPtr output) |
| { |
| OMAPPtr fPtr = OMAPPTR(output->scrn); |
| ScrnInfoPtr pScrn = output->scrn; |
| DisplayModePtr mode_ptr; |
| EXYNOS5HDMIOutputPrivatePtr tv_priv = output->driver_private; |
| struct v4l2_dv_preset preset_dv; |
| struct v4l2_dv_enum_preset preset; |
| int hactive_s = TV_WIDTH; |
| int vactive_s = TV_HEIGHT; |
| unsigned long preset_code[256]; |
| int index=0; |
| int ret; |
| |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| /*HACK*/ |
| /* Will be fixed with EDID*/ |
| index=0; |
| ret = ioctl(fPtr->tvout_std_fd, VIDIOC_S_OUTPUT, &index); |
| if (ret<0) { |
| xf86Msg(X_INFO, "%s: VIDIOC_S_OUTPUT failed %s\n\n", __func__,strerror(-ret)); |
| return 0; |
| } |
| |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: Presets List: ", __func__); |
| /* setting presets */ |
| for (index = 0;1; ++index) { |
| preset.index = index; |
| |
| ret = ioctl(fPtr->tvout_std_fd, VIDIOC_ENUM_DV_PRESETS, &preset); |
| if (ret<0) |
| EXYNOS5DBGMSG(X_INFO, "%s: VIDIOC_ENUM_DV_PRESETS last index=%d\n\n", __func__,index); |
| |
| if (ret && errno == EINVAL) |
| break; |
| |
| preset_code[index] = preset.preset; |
| } |
| /*HACK*/ |
| /* Will be fixed with EDID, hard coding to 720p*/ |
| index=5; |
| preset_dv.preset = preset_code[index]; |
| ret = ioctl(fPtr->tvout_std_fd, VIDIOC_S_DV_PRESET, &preset_dv); |
| if (ret < 0) |
| xf86DrvMsg(0, X_ERROR,"VIDIOC_S_DV_PRESET failed because : %s\n", strerror(-ret)); |
| |
| if ( pScrn->modes != NULL ) |
| { |
| /* Use the modes supplied by the implementation if available */ |
| DisplayModePtr mode, first = mode = pScrn->modes; |
| DisplayModePtr modeptr = NULL, modeptr_prev = NULL, modeptr_first = NULL; |
| do { |
| int xres = mode->HDisplay = hactive_s; |
| int yres = mode->VDisplay = vactive_s; |
| |
| xf86DrvMsg(0, X_INFO, "Adding mode: %i x %i\n", xres, yres); |
| |
| if ( modeptr_first == NULL ) |
| { |
| modeptr_first = tv_make_mode( xres, yres, NULL ); |
| modeptr = modeptr_first; |
| } |
| else |
| { |
| modeptr->next = tv_make_mode( xres, yres, modeptr_prev); |
| modeptr = modeptr->next; |
| } |
| modeptr_prev = modeptr; |
| |
| mode = mode->next; |
| } while (mode != NULL && mode != first); |
| |
| return modeptr_first; |
| } |
| |
| mode_ptr = xnfcalloc(1, sizeof(DisplayModeRec)); |
| |
| mode_ptr->HDisplay = hactive_s; |
| mode_ptr->HSyncStart = hactive_s + 20; |
| mode_ptr->HSyncEnd = hactive_s + 40; |
| mode_ptr->HTotal = hactive_s + 80; |
| |
| mode_ptr->VDisplay = vactive_s; |
| mode_ptr->VSyncStart = vactive_s + 20; |
| mode_ptr->VSyncEnd = vactive_s + 40; |
| mode_ptr->VTotal = vactive_s + 80; |
| |
| mode_ptr->VRefresh = 60.0; |
| |
| mode_ptr->Clock = (int) (mode_ptr->VRefresh * mode_ptr->VTotal * mode_ptr->HTotal / 1000.0); |
| |
| mode_ptr->type = M_T_DRIVER; |
| |
| xf86SetModeDefaultName(mode_ptr); |
| |
| mode_ptr->next = NULL; |
| mode_ptr->prev = NULL; |
| tv_priv->hdtv_connector_type = V4L2_OUTPUT_TYPE_HDMI_RGB; |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return mode_ptr; |
| } |
| |
| static Bool |
| exynos5_hdmi_output_set_property(xf86OutputPtr output, Atom property, |
| RRPropertyValuePtr value) |
| { |
| OMAPPtr fPtr = OMAPPTR(output->scrn); |
| EXYNOS5HDMIOutputPrivatePtr tv_priv = output->driver_private; |
| v4l2_std_id userMode; |
| Atom atom; |
| const char *name; |
| int index,ret; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| if(value->type != XA_ATOM || value->format != 32 || value->size != 1) { |
| xf86Msg(X_ERROR, "%s: Invalid property value\n", __func__); |
| return FALSE; |
| } |
| |
| memcpy(&atom, value->data, 4); |
| name = NameForAtom(atom); |
| |
| /* This function is not complete and all the variables like atom and name shall be |
| * used once EDID functionality is implemented */ |
| if(property == pal_mode_atom) { |
| |
| index = pal_mode_lookup(name); |
| if(index < 0) { |
| xf86Msg(X_ERROR, "%s: Invalid mode index\n", __func__); |
| return FALSE; |
| } |
| |
| userMode = pal_index_to_mode(index); |
| |
| /* Check if the mode is already set */ |
| if(tv_priv->mode_720x576 != userMode) { |
| /* Check if user has set 720x576 mode for HDTV, but either the HDTV is not |
| * connected or the HDTV does not support 720x576 mode */ |
| if(userMode == V4L2_STD_576P_50_4_3 && (!tv_priv->hdtv_connected || !tv_priv->hdtv_720x576_supported)) { |
| xf86Msg(X_ERROR, "%s: Mode can not be set\n", __func__); |
| return FALSE; |
| } |
| |
| tv_priv->mode_720x576 = userMode; |
| |
| if(tv_priv->modeHDisplay == 720 && tv_priv->modeVDisplay == 576) { |
| if(tv_priv->hdtv_connected && tv_priv->hdtv_720x576_supported && tv_priv->mode_720x576 == V4L2_STD_576P_50_4_3) { |
| ret = exynos5_init_hdmi(fPtr->tvout_std_fd, tv_priv->mode_720x576, tv_priv->hdtv_connector_type, 0); |
| if(ret){ |
| xf86Msg(X_ERROR, "%s: TV Init Failed %s line %d\n", __func__,strerror(-ret),__LINE__); |
| return FALSE; |
| } |
| } |
| else { |
| ret = exynos5_init_hdmi(fPtr->tvout_std_fd, tv_priv->mode_720x576, V4L2_OUTPUT_TYPE_COMPOSITE, 0); |
| if(ret){ |
| xf86Msg(X_ERROR, "%s: TV Init Failed %s line %d\n", __func__,strerror(-ret),__LINE__); |
| return FALSE; |
| } |
| } |
| } |
| } |
| } |
| else if(property == ntsc_mode_atom) { |
| |
| index = ntsc_mode_lookup(name); |
| if(index < 0) { |
| xf86Msg(X_ERROR, "%s: Invalid mode index\n", __func__); |
| return FALSE; |
| } |
| |
| userMode = ntsc_index_to_mode(index); |
| |
| /* Check if the mode is already set */ |
| if(tv_priv->mode_720x480 != userMode) { |
| /* Check if user has set 720x480 mode for HDTV, but either the HDTV is not |
| * connected or the HDTV does not support 720x480 mode */ |
| if(userMode == V4L2_STD_480P_60_4_3 && (!tv_priv->hdtv_connected || !tv_priv->hdtv_720x480_supported)) { |
| xf86Msg(X_ERROR, "%s: Mode can not be set\n", __func__); |
| return FALSE; |
| } |
| |
| tv_priv->mode_720x480 = userMode; |
| |
| if(tv_priv->modeHDisplay == 720 && tv_priv->modeVDisplay == 480) { |
| if(tv_priv->hdtv_connected && tv_priv->hdtv_720x480_supported && tv_priv->mode_720x480 == V4L2_STD_480P_60_4_3) { |
| ret = exynos5_init_hdmi(fPtr->tvout_std_fd, tv_priv->mode_720x480, tv_priv->hdtv_connector_type, 0); |
| if(ret){ |
| xf86Msg(X_ERROR, "%s: TV Init Failed %s line %d\n", __func__,strerror(-ret),__LINE__); |
| return FALSE; |
| } |
| } |
| else { |
| ret = exynos5_init_hdmi(fPtr->tvout_std_fd, tv_priv->mode_720x480, V4L2_OUTPUT_TYPE_COMPOSITE, 0); |
| if(ret){ |
| xf86Msg(X_ERROR, "%s: TV Init Failed %s line %d\n", __func__,strerror(-ret),__LINE__); |
| return FALSE; |
| } |
| } |
| } |
| } |
| } |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| |
| return TRUE; |
| } |
| |
| static Bool |
| exynos5_hdmi_output_get_property(xf86OutputPtr output, Atom property) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return TRUE; |
| } |
| |
| static xf86CrtcPtr |
| exynos5_hdmi_output_get_crtc(xf86OutputPtr output) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| return output->crtc; |
| } |
| |
| static void |
| exynos5_hdmi_output_destroy(xf86OutputPtr output) |
| { |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| } |
| |
| static const xf86OutputFuncsRec exynos5_hdmi_output_funcs = { |
| .create_resources = exynos5_hdmi_output_create_resources, |
| .dpms = exynos5_hdmi_output_dpms, |
| .save = exynos5_hdmi_output_save, |
| .restore = exynos5_hdmi_output_restore, |
| .mode_valid = exynos5_hdmi_output_mode_valid, |
| .mode_fixup = exynos5_hdmi_output_mode_fixup, |
| .prepare = exynos5_hdmi_output_prepare, |
| .commit = exynos5_hdmi_output_commit, |
| .mode_set = exynos5_hdmi_output_mode_set, |
| .detect = exynos5_hdmi_output_detect, |
| .get_modes = exynos5_hdmi_output_get_modes, |
| #ifdef RANDR_12_INTERFACE |
| .set_property = exynos5_hdmi_output_set_property, |
| #endif |
| #ifdef RANDR_13_INTERFACE |
| .get_property = exynos5_hdmi_output_get_property, |
| #endif |
| #ifdef RANDR_GET_CRTC_INTERFACE |
| .get_crtc = exynos5_hdmi_output_get_crtc, |
| #endif |
| .destroy = exynos5_hdmi_output_destroy, |
| }; |
| |
| /* Init function called from driver's PreInit function */ |
| Bool exynos5_hdmi_init(ScrnInfoPtr pScrn) |
| { |
| xf86CrtcPtr crtc; |
| xf86OutputPtr output; |
| EXYNOS5HDMIOutputPrivatePtr tv_priv; |
| OMAPPtr fPtr; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ++++\n", __func__); |
| |
| /* Create CRTC */ |
| crtc = xf86CrtcCreate(pScrn, &exynos5_hdmi_crtc_funcs); |
| if(crtc == NULL) { |
| xf86Msg(X_ERROR, "%s: xf86CrtcCreate failed\n", __func__); |
| return FALSE; |
| } |
| |
| /* Create output for TV */ |
| |
| output = xf86OutputCreate(pScrn, &exynos5_hdmi_output_funcs, "TV"); |
| if(output == NULL) { |
| xf86Msg(X_ERROR, "%s: xf86OutputCreate failed\n", __func__); |
| return FALSE; |
| } |
| |
| fPtr = OMAPPTR(output->scrn); |
| /*HACK*/ |
| output->possible_crtcs = 8;/* First 7 crtcs are assigned to kms possible crtcs */ |
| |
| fPtr->tvout_std_fd = open(/*fPtr->tvout_std_dev_name*/"/dev/video16", O_RDWR); |
| if (fPtr->tvout_std_fd < 0) { |
| xf86Msg(X_ERROR, "%s: %s open failed\n", __func__, fPtr->tvout_std_dev_name); |
| return FALSE; |
| } |
| xf86Msg(X_ERROR, "%s: %s openedi fd =%d\n", __func__, fPtr->tvout_std_dev_name,fPtr->tvout_std_fd); |
| |
| tv_priv = xnfcalloc(sizeof(EXYNOS5HDMIOutputPrivateRec), 1); |
| /* xnfcalloc exits server when allocation failes hence no check is put*/ |
| #if EXYNOS_EDID |
| /* Open I2C1 for getting (EDID+E-EDID) data through DDC bus */ |
| if((i2c_fd = open(fPtr->ddc_dev_name, O_RDWR)) < 0) { |
| xf86Msg(X_ERROR, "%s: I2C-1 device open failed\n", __func__); |
| return FALSE; |
| } |
| /* Initialize DDC(I2C) bus */ |
| if(!EXYNOS5I2CInit(pScrn, &tv_priv->pI2CBus, i2c_fd, "I2C-DDC")) { |
| xf86Msg(X_ERROR,"%s: EXYNOS5I2CInit failed\n", __func__); |
| return FALSE; |
| } |
| #endif |
| /* Default initialization of private data for TV output */ |
| tv_priv->hdtv_connected = FALSE; |
| tv_priv->hdtv_720x576_supported = FALSE; |
| tv_priv->hdtv_720x480_supported = FALSE; |
| tv_priv->hdtv_connector_type = V4L2_OUTPUT_TYPE_HDMI; |
| tv_priv->mode_720x576 = V4L2_STD_PAL_M; |
| tv_priv->mode_720x480 = V4L2_STD_NTSC_M; |
| |
| output->driver_private = tv_priv; |
| |
| EXYNOS5DBGMSG(X_INFO, "%s: ----\n", __func__); |
| |
| return TRUE; |
| } |