s5pv210 HDMI 1080P 高清显示

s5pv210 HDMI 1920x1080P@60Hz 显示 高清图片

s5pv210 HDMI 1080P 高清显示_第1张图片


s5pv210 可以设置成1920x1080P@60Hz显示,虽然datasheet并没有提供这种配置,因为1080P@60hz,需要 148500000的Pixel Clock,但是datasheet给出最高的是74250000。

s5pv210 HDMI 1080P 高清显示_第2张图片

在hdmiphy_drv.c 添加148500000的clock配置(linux3.9.7)

s5pv210 HDMI 1080P 高清显示_第3张图片

这个数据最终会通过调用 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;
}

测试源码(自己可以制作1080P的bmp图片)

#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,在运行动画时,刷屏有点闪烁,以后在分析

你可能感兴趣的:(s5pv210 HDMI 1080P 高清显示)