s5pv210 HDMI 1920x1080P@60Hz 显示 高清图片
s5pv210 可以设置成1920x1080P@60Hz显示,虽然datasheet并没有提供这种配置,因为1080P@60hz,需要 148500000的Pixel Clock,但是datasheet给出最高的是74250000。
在hdmiphy_drv.c 添加148500000的clock配置(linux3.9.7)
这个数据最终会通过调用 hdmiphy_s_dv_preset函数,hdmi的专用i2c,写入的hdmi模块中
static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd, struct v4l2_dv_preset *preset) { const u8 *data; u8 buffer[32]; int ret; struct hdmiphy_ctx *ctx = sd_to_ctx(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); struct device *dev = &client->dev; dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset); data = hdmiphy_find_conf(preset->preset, ctx->conf_tab); if (!data) { dev_err(dev, "format not supported\n"); return -EINVAL; } /* storing configuration to the device */ memcpy(buffer, data, 32); ret = i2c_master_send(client, buffer, 32); if (ret != 32) { dev_err(dev, "failed to configure HDMIPHY via I2C\n"); return -EIO; } return 0; }
#include <errno.h> #include <fcntl.h> #include <linux/videodev2.h> #include <math.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #define ERRSTR strerror(errno) #define debug #define BYE_ON(cond, ...) \ do { \ if (cond) { \ int errsv = errno; \ fprintf(stderr, "ERROR(%s:%d) : ", \ __FILE__, __LINE__); \ errno = errsv; \ fprintf(stderr, __VA_ARGS__); \ abort(); \ } \ } while(0) #define ReqButNum 3 //#define HDMI480P //#define HDMI720P #define HDMI1080P #ifdef HDMI480P #define hdmi_width 720 #define hdmi_height 480 #endif #ifdef HDMI720P #define hdmi_width 1280 #define hdmi_height 720 #endif #ifdef HDMI1080P #define hdmi_width 1920 #define hdmi_height 1080 #endif #define CLEAR(x) memset(&(x), 0, sizeof(x)) #define BYE_ON(cond, ...) \ do { \ if (cond) { \ int errsv = errno; \ fprintf(stderr, "ERROR(%s:%d) : ", \ __FILE__, __LINE__); \ errno = errsv; \ fprintf(stderr, __VA_ARGS__); \ abort(); \ } \ } while(0) struct hdmibuffer { int index; void *data; size_t size; size_t width; size_t height; /* buffer state */ double t; }; struct hdmibuffer hdmi_buffer[ReqButNum]; struct buffer { int index; void *data; size_t size; size_t width; size_t height; /* buffer state */ double t; }; struct context { int fd; struct hdmibuffer *buffer; size_t buffer_cnt; }; char hdmi_path[] = "/dev/video10"; static int hdmi_fd; int open_hdmi_device() { int fd; if((fd = open(hdmi_path,O_RDWR)) < 0) { perror("Fail to open"); exit(EXIT_FAILURE); } hdmi_fd = fd; printf("open hdmi success %d\n",fd); return fd; } int hdmi_setfmt() { int ret; /* configure desired image size */ struct v4l2_format fmt; struct v4l2_fmtdesc fmtdesc; memset(&fmtdesc,0,sizeof(fmtdesc)); fmtdesc.index = 0; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; while((ret = ioctl(hdmi_fd,VIDIOC_ENUM_FMT,&fmtdesc)) == 0) { fmtdesc.index ++ ; printf("{pixelformat = %c%c%c%c},description = '%s'\n", fmtdesc.pixelformat & 0xff,(fmtdesc.pixelformat >> 8)&0xff, (fmtdesc.pixelformat >> 16) & 0xff,(fmtdesc.pixelformat >> 24)&0xff, fmtdesc.description); } memset(&fmt,0,sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; fmt.fmt.pix.width = hdmi_width; fmt.fmt.pix.height = hdmi_height; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; //V4L2_FIELD_NONE; //V4L2_FIELD_INTERLACED; printf("%s: +\n", __func__); /* format is hardcoded: draw procedures work only in 32-bit mode */ fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR32; ret = ioctl(hdmi_fd, VIDIOC_S_FMT, &fmt); BYE_ON(ret < 0, "VIDIOC_S_FMT failed: %s\n", ERRSTR); /* update format struct to values adjusted by a driver */ ret = ioctl(hdmi_fd, VIDIOC_G_FMT, &fmt); BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR); printf("getfmt:%d,%d\n", fmt.fmt.pix.width, fmt.fmt.pix.height); BYE_ON((fmt.fmt.pix.width < hdmi_width) | (fmt.fmt.pix.height < hdmi_height), "VIDIOC_G_FMT failed: %s\n", ERRSTR); /* crop output area on display */ struct v4l2_crop crop; crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; crop.c.left = 0; crop.c.top = 0; crop.c.width = hdmi_width; crop.c.height = hdmi_height; ret = ioctl(hdmi_fd, VIDIOC_S_CROP, &crop); BYE_ON(ret < 0, "VIDIOC_S_CROP failed: %s\n", ERRSTR); printf("%s: -\n", __func__); return 0; } int hdmi_reqbufs() { int ret; int i,j; struct v4l2_requestbuffers rqbufs; struct v4l2_plane plane; struct v4l2_buffer buf; struct v4l2_format fmt; rqbufs.count = ReqButNum; rqbufs.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; rqbufs.memory = V4L2_MEMORY_MMAP; printf("%s +\n", __func__); ret = ioctl(hdmi_fd, VIDIOC_REQBUFS, &rqbufs); printf("reqbuf:%d\n", rqbufs.count); BYE_ON(ret < 0, "VIDIOC_REQBUFS failed: %s\n", ERRSTR); BYE_ON(rqbufs.count < ReqButNum, "failed to get %d buffers\n", ReqButNum); // ret = ioctl(hdmi_fd, VIDIOC_G_FMT, &fmt); // BYE_ON(ret < 0, "VIDIOC_G_FMT failed: %s\n", ERRSTR); /* buffers initalization */ for (i = 0; i < ReqButNum; ++i) { buf.index = i; buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; buf.memory = V4L2_MEMORY_MMAP; buf.m.planes = &plane; buf.length = 1; /* get buffer properties from a driver */ ret = ioctl(hdmi_fd, VIDIOC_QUERYBUF, &buf); BYE_ON(ret < 0, "VIDIOC_QUERYBUF for buffer %d failed: %s\n", buf.index, ERRSTR); hdmi_buffer[i].index = i; /* mmap buffer to user space */ hdmi_buffer[i].data = mmap(NULL, plane.length, PROT_READ | PROT_WRITE, MAP_SHARED, hdmi_fd, plane.m.mem_offset); BYE_ON(hdmi_buffer[i].data == MAP_FAILED, "mmap failed: %s\n", ERRSTR); hdmi_buffer[i].size = plane.length; hdmi_buffer[i].width = hdmi_width; hdmi_buffer[i].height = hdmi_height; /* fill buffer with black */ for (j = 0; 4 * j < hdmi_buffer[i].size; ++j) ((unsigned int *)hdmi_buffer[i].data)[j] = 0xff000000; } printf("%s -\n", __func__); return 0; } int init_device() { hdmi_setfmt(); hdmi_reqbufs(); printf("%s -\n", __func__); } int hdmi_streamon() { enum v4l2_buf_type type; int ret; // hdmi_qbuf(2); struct timeval tv; gettimeofday(&tv, NULL); type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; ret = ioctl(hdmi_fd, VIDIOC_STREAMON, &type); BYE_ON(ret, "VIDIOC_STREAMON failed: %s\n", ERRSTR); return 0; } int hdmi_qbuf(int index) { struct v4l2_buffer buf; struct v4l2_plane plane; debug("queue +\n"); memset(&buf, 0, sizeof(buf)); memset(&plane, 0, sizeof(plane)); buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; buf.index = index; buf.memory = V4L2_MEMORY_MMAP; buf.m.planes = &plane; buf.length = 1; int ret; ret = ioctl(hdmi_fd, VIDIOC_QBUF, &buf); BYE_ON(ret, "VIDIOC_QBUF(index = %d) failed: %s\n", index, ERRSTR); //sem_post(&lcd_sem); return 0; } int hdmi_dbuf(int *index) { int ret; struct v4l2_buffer buf; struct v4l2_plane plane; debug("dequeue +\n"); memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; buf.memory = V4L2_MEMORY_MMAP; buf.m.planes = &plane; buf.length = 1; ret = ioctl(hdmi_fd, VIDIOC_DQBUF, &buf); BYE_ON(ret, "VIDIOC_DQBUF failed: %s\n", ERRSTR); *index = buf.index; return 0; } unsigned int *display_bmp_image() { unsigned int *img_buf; FILE *fp; int count = 0, i = 0, j=0, r, g, b; char ch; char *pch; int buf_size = hdmi_width * hdmi_height; img_buf = (unsigned int *)malloc(buf_size * sizeof(int)); memset(img_buf, 0, sizeof(img_buf)); if(NULL == (fp = fopen("./test.bmp", "r"))) { printf("open the image file %s failed!\n", "test.bmp"); return; } for(i = 0 ; i < 54 ; i++) ch=fgetc(fp); for(i = 0; i < hdmi_height; i++) { for(j = 0; j < hdmi_width; j++) { r = fgetc(fp); g = fgetc(fp); b = fgetc(fp); img_buf[(hdmi_height - i - 1) * hdmi_width + j] = (unsigned int)(0xff000000 | (b << 16) | (g << 8) | r); } } fclose(fp); return (void *)img_buf; } int main() { int static i = 0; int j = 0; int k = 0; int r, g, b; unsigned int *bmp_buf; bmp_buf = display_bmp_image(); open_hdmi_device(); hdmi_setfmt(); hdmi_reqbufs(); hdmi_qbuf(0); hdmi_qbuf(1); hdmi_qbuf(2); hdmi_streamon(); while(1) { hdmi_dbuf(&i); k = (k + 8)%24; printf("i=%d, %lx\n",i, 0xff000000 | (0xff << k)); memcpy((void *)hdmi_buffer[i].data, (void *)bmp_buf, hdmi_width * hdmi_height * 4); hdmi_qbuf(i); getchar(); for(j = 0; j < hdmi_width * hdmi_height; j ++) ((unsigned int *)hdmi_buffer[i].data)[j] = 0xff000000 | (0xff << k); } }
只能运行逐行扫描模式,即1080P,720P,480P,不能运行隔行扫描,即1080i,
提示错误:
[ 31.609709] s5p-mixer s5p-mixer: no vsync detected - timeout [ 31.609758] ------------[ cut here ]------------ [ 31.609817] WARNING: at drivers/media/platform/s5p-tv/mixer_drv.c:83 mxr_streamer_get+0x148/0x1c4() [ 31.609887] failed to get vsync (-62) from output [ 31.611366] Modules linked in: [ 31.614429] [<c0018d30>] (unwind_backtrace+0x0/0xf0) from [<c0023158>] (warn_slowpath_common+0x4c/0x68) [ 31.623787] [<c0023158>] (warn_slowpath_common+0x4c/0x68) from [<c0023208>] (warn_slowpath_fmt+0x30/0x40) [ 31.633314] [<c0023208>] (warn_slowpath_fmt+0x30/0x40) from [<c0318a44>] (mxr_streamer_get+0x148/0x1c4) [ 31.642672] [<c0318a44>] (mxr_streamer_get+0x148/0x1c4) from [<c03191d4>] (start_streaming+0x80/0xb0) [ 31.651858] [<c03191d4>] (start_streaming+0x80/0xb0) from [<c02f5d44>] (vb2_streamon+0x74/0x160) [ 31.660616] [<c02f5d44>] (vb2_streamon+0x74/0x160) from [<c02e3ff8>] (v4l_streamon+0x18/0x1c) [ 31.669103] [<c02e3ff8>] (v4l_streamon+0x18/0x1c) from [<c02e671c>] (__video_do_ioctl+0x25c/0x33c) [ 31.678027] [<c02e671c>] (__video_do_ioctl+0x25c/0x33c) from [<c02e7938>] (video_usercopy+0xac/0x3f4) [ 31.687212] [<c02e7938>] (video_usercopy+0xac/0x3f4) from [<c02e2774>] (v4l2_ioctl+0xe0/0x144) [ 31.695802] [<c02e2774>] (v4l2_ioctl+0xe0/0x144) from [<c00bae44>] (do_vfs_ioctl+0x80/0x618) [ 31.704199] [<c00bae44>] (do_vfs_ioctl+0x80/0x618) from [<c00bb418>] (sys_ioctl+0x3c/0x60) [ 31.712437] [<c00bb418>] (sys_ioctl+0x3c/0x60) from [<c0013940>] (ret_fast_syscall+0x0/0x30) [ 31.720829] ---[ end trace f6f0c2e97ef6ff7e ]---
DELL S2340L显示器只能配置到1080P@60HZ, 不能显示50HZ和30HZ,所以只能配置到60Hz,在运行动画时,刷屏有点闪烁,以后在分析