video: rockchip: add auto dp support for vr product

Change-Id: Ic4e4a3c0214c23bd55d883df6d2106646ef33614
Signed-off-by: Luo wei <lw@rock-chips.com>
This commit is contained in:
Luo wei
2017-01-18 17:49:34 +08:00
committed by Huang, Tao
parent 7ba1220f6b
commit ec6d8f10b9
11 changed files with 364 additions and 8 deletions

View File

@@ -448,6 +448,22 @@ static ssize_t debug_store(struct device *dev,
static DEVICE_ATTR_RW(debug);
static ssize_t prop_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct rk_display_device *dsp = dev_get_drvdata(dev);
int ret = -EINVAL;
mutex_lock(&dsp->lock);
if (dsp->ops && dsp->ops->getvrinfo)
ret = dsp->ops->getvrinfo(dsp, buf);
mutex_unlock(&dsp->lock);
return ret;
}
static DEVICE_ATTR_RO(prop);
static struct attribute *display_device_attrs[] = {
&dev_attr_name.attr,
&dev_attr_type.attr,
@@ -462,6 +478,7 @@ static struct attribute *display_device_attrs[] = {
&dev_attr_audioinfo.attr,
&dev_attr_monspecs.attr,
&dev_attr_debug.attr,
&dev_attr_prop.attr,
NULL,
};

View File

@@ -1,5 +1,6 @@
#include "rockchip_dp.h"
#include <linux/delay.h>
#include <linux/of_gpio.h>
static int rockchip_dp_removed(struct hdmi *hdmi_drv)
{
@@ -201,6 +202,62 @@ static int rockchip_dp_fb_event_notify(struct notifier_block *self,
return NOTIFY_OK;
}
static int cdn_dp_get_prop_dts(struct hdmi *hdmi, struct device_node *np)
{
const struct property *prop;
int i = 0, nstates = 0;
const __be32 *val;
int value;
struct edid_prop_value *pval = NULL;
if (!hdmi || !np)
return -EINVAL;
if (!of_property_read_u32(np, "dp_edid_auto_support", &value))
hdmi->edid_auto_support = value;
prop = of_find_property(np, "dp_edid_prop_value", NULL);
if (!prop || !prop->value) {
pr_info("%s:No edid-prop-value, %d\n", __func__, !prop);
return -EINVAL;
}
nstates = (prop->length / sizeof(struct edid_prop_value));
pval = kcalloc(nstates, sizeof(struct edid_prop_value), GFP_NOWAIT);
if (!pval)
return -ENOMEM;
for (i = 0, val = prop->value; i < nstates; i++) {
pval[i].vid = be32_to_cpup(val++);
pval[i].pid = be32_to_cpup(val++);
pval[i].sn = be32_to_cpup(val++);
pval[i].xres = be32_to_cpup(val++);
pval[i].yres = be32_to_cpup(val++);
pval[i].vic = be32_to_cpup(val++);
pval[i].width = be32_to_cpup(val++);
pval[i].height = be32_to_cpup(val++);
pval[i].x_w = be32_to_cpup(val++);
pval[i].x_h = be32_to_cpup(val++);
pval[i].hwrotation = be32_to_cpup(val++);
pval[i].einit = be32_to_cpup(val++);
pval[i].vsync = be32_to_cpup(val++);
pval[i].panel = be32_to_cpup(val++);
pval[i].scan = be32_to_cpup(val++);
pr_info("%s: 0x%x 0x%x 0x%x %d %d %d %d %d %d %d %d %d %d %d %d\n",
__func__, pval[i].vid, pval[i].pid, pval[i].sn,
pval[i].width, pval[i].height, pval[i].xres,
pval[i].yres, pval[i].vic, pval[i].x_w,
pval[i].x_h, pval[i].hwrotation, pval[i].einit,
pval[i].vsync, pval[i].panel, pval[i].scan);
}
hdmi->pvalue = pval;
hdmi->nstates = nstates;
return 0;
}
int cdn_dp_fb_register(struct platform_device *pdev, void *dp)
{
struct hdmi_ops *rk_dp_ops;
@@ -260,6 +317,7 @@ int cdn_dp_fb_register(struct platform_device *pdev, void *dp)
dp_dev->hdmi->colormode = HDMI_COLOR_RGB_0_255;
dp_dev->dp = dp;
cdn_dp_get_prop_dts(dp_dev->hdmi, np);
dp_dev->fb_notif.notifier_call = rockchip_dp_fb_event_notify;
fb_register_client(&dp_dev->fb_notif);
dev_set_drvdata(dev, dp_dev);

View File

@@ -132,7 +132,14 @@ static void hdmi_wq_set_video(struct hdmi *hdmi)
video->color_input = HDMI_COLOR_RGB_0_255;
if ((hdmi->vic & HDMI_VIDEO_DMT) || (hdmi->vic & HDMI_VIDEO_DISCRETE_VR)) {
video->vic = hdmi->vic;
if (hdmi->edid_auto_support) {
if (hdmi->prop.value.vic)
video->vic = hdmi->prop.value.vic;
else
video->vic = hdmi->vic;
} else {
video->vic = hdmi->vic;
}
video->color_output_depth = 8;
} else {
video->vic = hdmi->vic & HDMI_VIC_MASK;
@@ -181,7 +188,8 @@ static void hdmi_wq_parse_edid(struct hdmi *hdmi)
continue;
}
rc = hdmi_edid_parse_base(pedid->raw[0], &extendblock, pedid);
rc = hdmi_edid_parse_base(hdmi,
pedid->raw[0], &extendblock, pedid);
if (rc) {
dev_err(hdmi->dev,
"[HDMI] parse edid base block error\n");

View File

@@ -78,7 +78,30 @@ static int hdmi_edid_parse_dtd(unsigned char *block, struct fb_videomode *mode)
return E_HDMI_EDID_SUCCESS;
}
int hdmi_edid_parse_base(unsigned char *buf,
static int edid_parse_prop_value(unsigned char *buf,
struct hdmi_edid *pedid)
{
unsigned char *block = &buf[0x36];
pedid->value.vid = ((buf[ID_MANUFACTURER_NAME_END] << 8) |
(buf[ID_MANUFACTURER_NAME]));
pedid->value.pid = ((buf[ID_MODEL + 1] << 8) |
(buf[ID_MODEL]));
pedid->value.sn = ((buf[ID_SERIAL_NUMBER + 3] << 24) |
(buf[ID_SERIAL_NUMBER + 2] << 16) |
(buf[ID_SERIAL_NUMBER + 1] << 8) |
buf[ID_SERIAL_NUMBER]);
pedid->value.xres = H_ACTIVE;
pedid->value.yres = V_ACTIVE;
pr_info("%s:read:vid=0x%x,pid=0x%x,sn=0x%x,xres=%d,yres=%d\n",
__func__, pedid->value.vid, pedid->value.pid,
pedid->value.sn, pedid->value.xres, pedid->value.yres);
return 0;
}
int hdmi_edid_parse_base(struct hdmi *hdmi, unsigned char *buf,
int *extend_num, struct hdmi_edid *pedid)
{
int rc = E_HDMI_EDID_SUCCESS;
@@ -119,6 +142,9 @@ int hdmi_edid_parse_base(unsigned char *buf,
fb_edid_to_monspecs(buf, pedid->specs);
if (hdmi->edid_auto_support)
edid_parse_prop_value(buf, pedid);
out:
/* For some sink, edid checksum is failed because several
* byte is wrong. To fix this case, we think it is a good

View File

@@ -862,6 +862,29 @@ static const struct hdmi_video_timing hdmi_mode[] = {
.pixelrepeat = 1,
.interface = OUT_P888,
},
{
/* samsung */
.mode = {
.name = "1440x2560@70Hz",
.refresh = 70,
.xres = 1440,
.yres = 2560,
.pixclock = 285000000,
.left_margin = 40,
.right_margin = 80,
.upper_margin = 2,
.lower_margin = 6,
.hsync_len = 20,
.vsync_len = 8,
.sync = 0,
.vmode = 0,
.flag = 0,
},
.vic = HDMI_VIDEO_DISCRETE_VR | 6,
.vic_2nd = 0,
.pixelrepeat = 1,
.interface = OUT_P888,
},
};
static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
@@ -875,10 +898,24 @@ static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
if (hdmi->vic == 0)
hdmi->vic = hdmi->property->defaultmode;
if ((hdmi->vic & HDMI_VIDEO_DMT) || (hdmi->vic & HDMI_VIDEO_DISCRETE_VR))
vic = hdmi->vic;
else
vic = hdmi->vic & HDMI_VIC_MASK;
if (hdmi->edid_auto_support) {
if ((hdmi->vic & HDMI_VIDEO_DMT) ||
(hdmi->vic & HDMI_VIDEO_DISCRETE_VR)) {
if (hdmi->prop.value.vic)
vic = hdmi->prop.value.vic;
else
vic = hdmi->vic;
} else {
vic = hdmi->vic & HDMI_VIC_MASK;
}
} else {
if ((hdmi->vic & HDMI_VIDEO_DMT) ||
(hdmi->vic & HDMI_VIDEO_DISCRETE_VR))
vic = hdmi->vic;
else
vic = hdmi->vic & HDMI_VIC_MASK;
}
for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
if (hdmi_mode[i].vic == vic ||
hdmi_mode[i].vic_2nd == vic)
@@ -959,6 +996,15 @@ static int hdmi_set_info(struct rk_screen *screen, struct hdmi *hdmi)
screen->overscan.top = hdmi->yscale;
screen->overscan.right = hdmi->xscale;
screen->overscan.bottom = hdmi->yscale;
screen->width = hdmi->prop.value.width;
screen->height = hdmi->prop.value.height;
pr_info("%s:line=%d %d %d %d %d %d %d %d %d\n",
__func__, __LINE__, screen->mode.xres, screen->mode.yres,
screen->mode.left_margin, screen->mode.right_margin,
screen->mode.upper_margin, screen->mode.lower_margin,
screen->mode.hsync_len, screen->mode.vsync_len);
return 0;
}
@@ -1240,6 +1286,66 @@ static void hdmi_sort_modelist(struct hdmi_edid *edid, int feature)
}
}
static int edid_select_prop_value(struct hdmi *hdmi)
{
struct edid_prop_value *prop_value = NULL;
int nstates = 0;
int i, vid, pid, sn, xres, yres, reboot = 0;
prop_value = hdmi->pvalue;
nstates = hdmi->nstates;
if (!prop_value) {
pr_info("%s:pvalue is NULL\n", __func__);
return -1;
}
vid = hdmi->edid.value.vid;
pid = hdmi->edid.value.pid;
sn = hdmi->edid.value.sn;
xres = hdmi->edid.value.xres;
yres = hdmi->edid.value.yres;
for (i = 0; i < nstates; i++) {
if ((prop_value[i].vid == vid) &&
(prop_value[i].pid == pid) &&
(prop_value[i].sn == sn) &&
(prop_value[i].xres == xres) &&
(prop_value[i].yres == yres)) {
hdmi->edid.value = prop_value[i];
hdmi->prop.value = prop_value[i];
if ((hdmi->prop.valid) &&
((hdmi->prop.last_vid != vid) ||
(hdmi->prop.last_pid != pid) ||
(hdmi->prop.last_sn != sn) ||
(hdmi->prop.last_xres != xres) ||
(hdmi->prop.last_yres != yres))) {
reboot = 1;
} else {
reboot = 0;
}
hdmi->prop.last_vid = vid;
hdmi->prop.last_pid = pid;
hdmi->prop.last_sn = sn;
hdmi->prop.last_xres = xres;
hdmi->prop.last_yres = yres;
hdmi->prop.valid = 1;
pr_info("%s:i=%d reboot=%d,valid=%d\n",
__func__, i, reboot, hdmi->prop.valid);
break;
}
}
if (reboot) {
dev_info(hdmi->dev, "%s:kernel_restart\n", __func__);
kernel_restart(NULL);
}
return 0;
}
/**
* hdmi_ouputmode_select - select hdmi transmitter output mode: hdmi or dvi?
* @hdmi: handle of hdmi
@@ -1261,6 +1367,9 @@ int hdmi_ouputmode_select(struct hdmi *hdmi, int edid_ok)
hdmi->edid.ycbcr422 = 0;
}
if (hdmi->edid_auto_support)
edid_select_prop_value(hdmi);
if (head->next == head) {
dev_info(hdmi->dev,
"warning: no CEA video mode parsed from EDID !!!!\n");

View File

@@ -541,6 +541,30 @@ static int hdmi_get_debug(struct rk_display_device *device, char *buf)
return len;
}
static int vr_get_info(struct rk_display_device *device, char *buf)
{
struct hdmi *hdmi = device->priv_data;
int valid, width, height, x_w, x_h, hwr, einit, vsync, panel, scan;
int len = 0;
valid = hdmi->prop.valid;
width = hdmi->prop.value.width;
height = hdmi->prop.value.height;
x_w = hdmi->prop.value.x_w;
x_h = hdmi->prop.value.x_h;
hwr = hdmi->prop.value.hwrotation;
einit = hdmi->prop.value.einit;
vsync = hdmi->prop.value.vsync;
panel = hdmi->prop.value.panel;
scan = hdmi->prop.value.scan;
len = snprintf(buf, PAGE_SIZE,
"valid=%d,width=%d,height=%d,xres=%d,yres=%d,hwrotation=%d,orientation=%d,vsync=%d,panel=%d,scan=%d\n",
valid, width, height, x_w, x_h, hwr, einit, vsync, panel, scan);
return len;
}
static struct rk_display_ops hdmi_display_ops = {
.setenable = hdmi_set_enable,
.getenable = hdmi_get_enable,
@@ -557,6 +581,7 @@ static struct rk_display_ops hdmi_display_ops = {
.setscale = hdmi_set_scale,
.getscale = hdmi_get_scale,
.getdebug = hdmi_get_debug,
.getvrinfo = vr_get_info,
};
static int hdmi_display_probe(struct rk_display_device *device, void *devdata)
@@ -565,6 +590,11 @@ static int hdmi_display_probe(struct rk_display_device *device, void *devdata)
device->owner = THIS_MODULE;
strcpy(device->type, "HDMI");
if (strstr(hdmi->property->name, "dp"))
strcpy(device->type, "DP");
else
strcpy(device->type, "HDMI");
device->priority = DISPLAY_PRIORITY_HDMI;
device->name = hdmi->property->name;
device->property = hdmi->property->display;

View File

@@ -8,6 +8,7 @@
#include <linux/switch.h>
#endif
#include <sound/pcm_params.h>
#include <linux/reboot.h>
#define HDMI_VIDEO_NORMAL 0
#define HDMI_VIDEO_DMT BIT(9)
@@ -284,6 +285,36 @@ struct hdmi_audio {
};
#define HDMI_MAX_EDID_BLOCK 8
struct edid_prop_value {
int vid;
int pid;
int sn;
int xres;
int yres;
int vic;
int width;
int height;
int x_w;
int x_h;
int hwrotation;
int einit;
int vsync;
int panel;
int scan;
};
struct edid_prop_data {
struct edid_prop_value value;
int valid;
int last_vid;
int last_pid;
int last_sn;
int last_xres;
int last_yres;
};
/* HDMI EDID Information */
struct hdmi_edid {
unsigned char sink_hdmi; /* HDMI display device flag */
@@ -313,6 +344,8 @@ struct hdmi_edid {
unsigned char dual_view;
unsigned char osd_disparity_3d;
struct edid_prop_value value;
unsigned int colorimetry;
struct fb_monspecs *specs; /*Device spec*/
struct list_head modelist; /*Device supported display mode list*/
@@ -414,6 +447,11 @@ struct hdmi {
int colormode; /* Output color mode*/
int colorimetry; /* Output colorimetry */
struct hdmi_edid edid; /* EDID information*/
struct edid_prop_data prop; /* Property for dp */
struct edid_prop_value *pvalue;
int nstates;
int edid_auto_support; /* Auto dp enable flag */
int enable; /* Enable flag*/
int sleep; /* Sleep flag*/
int vic; /* HDMI output video information code*/
@@ -515,7 +553,7 @@ struct rk_display_device *hdmi_register_display_sysfs(struct hdmi *hdmi,
struct device *parent);
void hdmi_unregister_display_sysfs(struct hdmi *hdmi);
int hdmi_edid_parse_base(unsigned char *buf,
int hdmi_edid_parse_base(struct hdmi *hdmi, unsigned char *buf,
int *extend_num, struct hdmi_edid *pedid);
int hdmi_edid_parse_extensions(unsigned char *buf,
struct hdmi_edid *pedid);

View File

@@ -424,6 +424,62 @@ static const struct of_device_id rk_hdmi_dt_ids[] = {
{}
};
static int hdmi_get_prop_dts(struct hdmi *hdmi, struct device_node *np)
{
const struct property *prop;
int i = 0, nstates = 0;
const __be32 *val;
int value;
struct edid_prop_value *pval = NULL;
if (!hdmi || !np) {
pr_info("%s:line=%d hdmi or np is null\n", __func__, __LINE__);
return -1;
}
if (!of_property_read_u32(np, "hdmi_edid_auto_support", &value))
hdmi->edid_auto_support = value;
prop = of_find_property(np, "hdmi_edid_prop_value", NULL);
if (!prop || !prop->value) {
pr_info("%s:No edid-prop-value, %d\n", __func__, !prop);
return -1;
}
nstates = (prop->length / sizeof(struct edid_prop_value));
pval = kcalloc(nstates, sizeof(struct edid_prop_value), GFP_NOWAIT);
for (i = 0, val = prop->value; i < nstates; i++) {
pval[i].vid = be32_to_cpup(val++);
pval[i].pid = be32_to_cpup(val++);
pval[i].sn = be32_to_cpup(val++);
pval[i].xres = be32_to_cpup(val++);
pval[i].yres = be32_to_cpup(val++);
pval[i].vic = be32_to_cpup(val++);
pval[i].width = be32_to_cpup(val++);
pval[i].height = be32_to_cpup(val++);
pval[i].x_w = be32_to_cpup(val++);
pval[i].x_h = be32_to_cpup(val++);
pval[i].hwrotation = be32_to_cpup(val++);
pval[i].einit = be32_to_cpup(val++);
pval[i].vsync = be32_to_cpup(val++);
pval[i].panel = be32_to_cpup(val++);
pval[i].scan = be32_to_cpup(val++);
pr_info("%s: 0x%x 0x%x 0x%x %d %d %d %d %d %d %d %d %d %d %d %d\n",
__func__, pval[i].vid, pval[i].pid, pval[i].sn,
pval[i].width, pval[i].height, pval[i].xres,
pval[i].yres, pval[i].vic, pval[i].x_w,
pval[i].x_h, pval[i].hwrotation, pval[i].einit,
pval[i].vsync, pval[i].panel, pval[i].scan);
}
hdmi->pvalue = pval;
hdmi->nstates = nstates;
return 0;
}
static int rockchip_hdmiv2_parse_dt(struct hdmi_dev *hdmi_dev)
{
int val = 0;
@@ -636,6 +692,8 @@ static int rockchip_hdmiv2_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto failed1;
}
hdmi_get_prop_dts(hdmi_dev->hdmi, hdmi_dev->dev->of_node);
mutex_init(&hdmi_dev->ddc_lock);
hdmi_dev->hdmi->dev = &pdev->dev;
hdmi_dev->hdmi->soctype = hdmi_dev->soctype;

View File

@@ -75,6 +75,8 @@ static const struct phy_mpll_config_tab PHY_MPLL_TABLE[] = {
1, 3, 0, 0, 0, 0, 3},
{269390000, 269390000, 0, 8, 0, 0, 0,
1, 0, 0, 0, 0, 0, 3},
{285000000, 285000000, 0, 8, 0, 0, 0,
1, 0, 0, 0, 0, 0, 3},
{297000000, 148500000, 0, 8, 0, 0, 0,
1, 0, 1, 0, 0, 0, 3},
{297000000, 297000000, 0, 8, 0, 0, 0,

View File

@@ -3777,6 +3777,15 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
}
kobject_uevent_env(&dev_drv->dev->kobj, KOBJ_CHANGE, envp);
if (dev_drv->cur_screen->width && dev_drv->cur_screen->height) {
/* for vr auto dp support */
info = rk_fb->fb[dev_drv->fb_index_base];
info->var.width = dev_drv->cur_screen->width;
info->var.height = dev_drv->cur_screen->height;
pr_info("%s:info->var.width=%d, info->var.height=%d\n",
__func__, info->var.width, info->var.height);
}
hdmi_switch_state = 1;
load_screen = true;
dev_drv->hdmi_switch = 0;

1
include/linux/display-sys.h Executable file → Normal file
View File

@@ -66,6 +66,7 @@ struct rk_display_ops {
char *audioinfo, int len);
int (*getmonspecs)(struct rk_display_device *,
struct fb_monspecs *monspecs);
int (*getvrinfo)(struct rk_display_device *, char *);
};
struct rk_display_device {