RK3368 Edp屏调试,利用EDID做兼容
Platform: RK3368
OS: Android 6.0
Kernel: 3.10.0
文章目录
最近采购经常换显示面板,而RK的Edp屏相关的配置都是在dts里面写死的,一个屏幕需要写一个dts配置,所以就想做个Edp屏兼容.原理就是将Edp屏里面的EDID读取出来,提取时序相关信息,然后覆盖掉原来从dts中获取的屏幕配置.
1. kernel部分修改
1.1 Edp EDID信息打印:
在调试阶段,可以在drivers/video/fbmon.c里面将DEBUG打开,这样内核会将EDID信息直接打印出来.
1.2 修改lcdc驱动
修改rk3368_lcdc,如果屏幕是Edp类型的就将Edp屏的最佳时序从EDID中提取出来,然后覆盖rk_screen从dts中获取的屏幕时序配置.
diff --git a/drivers/video/rockchip/lcdc/rk3368_lcdc.c b/drivers/video/rockchip/lcdc/rk3368_lcdc.c
index 17cdd3a..84eb89e 100755
--- a/drivers/video/rockchip/lcdc/rk3368_lcdc.c
+++ b/drivers/video/rockchip/lcdc/rk3368_lcdc.c
@@ -2288,6 +2288,22 @@ static int rk3368_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
rk3368_lcdc_reg_restore(lcdc_dev);
/*if (dev_drv->iommu_enabled)
rk3368_lcdc_mmu_en(dev_drv); */
+
+ //if current screen type is eDP, then overlay videomode by EDID.
+ if(dev_drv->cur_screen->type==SCREEN_EDP &&
+ dev_drv->trsm_ops && dev_drv->trsm_ops->enable &&
+ strstr(saved_command_line,"edp.edid=1")!= NULL){
+ if(!support_uboot_display()){
+ dev_drv->trsm_ops->enable();
+ }
+ if(rk32_edp_get_screen_info_from_edid(dev_drv->cur_screen)==0){
+ rk_fb_set_prmry_screen_specs(dev_drv->cur_screen);
+ }
+ if(!support_uboot_display()){
+ dev_drv->trsm_ops->disable();
+ }
+ }
+
if ((support_uboot_display() && (lcdc_dev->prop == PRMRY))) {
rk3368_lcdc_set_dclk(dev_drv, 0);
/*rk3368_lcdc_enable_irq(dev_drv);*/
1.3 修改rk_screen
添加一个函数rk_fb_set_prmry_screen_specs,用来覆盖原来从dts中读取的显示配置.
diff --git a/drivers/video/rockchip/screen/rk_screen.c b/drivers/video/rockchip/screen/rk_screen.c
index d5e3b15..f5d27a0 100755
--- a/drivers/video/rockchip/screen/rk_screen.c
+++ b/drivers/video/rockchip/screen/rk_screen.c
@@ -44,6 +44,27 @@ int rk_fb_set_prmry_screen(struct rk_screen *screen)
return 0;
}
+int rk_fb_set_prmry_screen_specs(struct rk_screen *screen)
+{
+ if (unlikely(!rk_screen) || unlikely(!screen))
+ return -1;
+
+ rk_screen->mode.xres = screen->mode.xres;
+ rk_screen->mode.yres = screen->mode.yres;
+ rk_screen->mode.pixclock = screen->mode.pixclock;
+ rk_screen->mode.left_margin = screen->mode.left_margin;
+ rk_screen->mode.right_margin = screen->mode.right_margin;
+ rk_screen->mode.upper_margin = screen->mode.upper_margin;
+ rk_screen->mode.lower_margin = screen->mode.lower_margin;
+ rk_screen->mode.hsync_len = screen->mode.hsync_len;
+ rk_screen->mode.vsync_len = screen->mode.vsync_len;
+ rk_screen->pin_hsync = screen->mode.sync & FB_SYNC_HOR_HIGH_ACT ? 1 : 0;
+ rk_screen->pin_vsync = screen->mode.sync & FB_SYNC_VERT_HIGH_ACT ? 1 : 0;
+ rk_screen->width = screen->width;
+ rk_screen->height= screen->height;
+ return 0;
+}
+
size_t get_fb_size(u8 reserved_fb)
{
size_t size = 0;
1.4 修改dts
从EDID中提取显示时序,以及dts中的自定义配置解析:
dts文件配置:
&edp{
status = "okay";
enhanced-mode;
//bist-mode;
scramble-enable;
};
1.5 修改rk32_dp驱动
diff --git a/drivers/video/rockchip/transmitter/rk32_dp.c b/drivers/video/rockchip/transmitter/rk32_dp.c
index 2b3457c..021188d 100755
--- a/drivers/video/rockchip/transmitter/rk32_dp.c
+++ b/drivers/video/rockchip/transmitter/rk32_dp.c
@@ -39,9 +39,10 @@
#include "rk32_dp.h"
-/*#define EDP_BIST_MODE*/
/*#define SW_LT*/
+static int rk32_edp_enable_scramble(struct rk32_edp *edp, bool enable);
+
#define RK3368_GRF_SOC_CON4 0x410
static struct rk32_edp *rk32_edp;
@@ -293,8 +294,7 @@ static int rk32_edp_read_edid(struct rk32_edp *edp)
dev_err(edp->dev, "EDID Read success!\n");
return 0;
}
-#define open_t 0
-#if open_t
+
static int rk32_edp_handle_edid(struct rk32_edp *edp)
{
u8 buf[12];
@@ -306,8 +306,8 @@ static int rk32_edp_handle_edid(struct rk32_edp *edp)
if (retval < 0)
return retval;
- for (i = 0; i < 12; i++)
- dev_info(edp->dev, "%d:>>0x%02x\n", i, buf[i]);
+ //for (i = 0; i < 12; i++)
+ // dev_info(edp->dev, "%d:>>0x%02x\n", i, buf[i]);
/* Read EDID */
for (i = 0; i < 3; i++) {
retval = rk32_edp_read_edid(edp);
@@ -407,7 +407,6 @@ static int rk32_edp_set_enhanced_mode(struct rk32_edp *edp)
return 0;
}
-#endif
#if defined(SW_LT)
@@ -1097,9 +1096,9 @@ static int rk32_edp_config_video(struct rk32_edp *edp,
rk32_edp_set_video_cr_mn(edp, CALCULATED_M, 0, 0);
/* For video bist, Video timing must be generated by register */
-#ifndef EDP_BIST_MODE
- rk32_edp_set_video_timing_mode(edp, VIDEO_TIMING_FROM_CAPTURE);
-#endif
+ if(edp->bist_mode){
+ rk32_edp_set_video_timing_mode(edp, VIDEO_TIMING_FROM_CAPTURE);
+ }
/* Disable video mute */
rk32_edp_enable_video_mute(edp, 0);
@@ -1165,6 +1164,59 @@ static irqreturn_t rk32_edp_isr(int irq, void *arg)
return IRQ_HANDLED;
}
+static struct fb_videomode *rk32_edp_get_preferred_mode(struct fb_monspecs *spec)
+{
+ int i;
+
+ if (!spec || !spec->modedb || !(spec->misc & FB_MISC_1ST_DETAIL))
+ return NULL;
+
+ for (i = 0; i < spec->modedb_len; i++) {
+ if (spec->modedb[i].flag & FB_MODE_IS_FIRST &&
+ spec->modedb[i].flag & FB_MODE_IS_DETAILED)
+ return &spec->modedb[i];
+ }
+
+ return NULL;
+}
+
+int rk32_edp_get_screen_info_from_edid(struct rk_screen *screen)
+{
+ struct rk32_edp *edp = rk32_edp;
+
+ int ret = rk32_edp_handle_edid(edp);
+ if (ret) {
+ dev_err(edp->dev, "unable to handle edid\n");
+ return -1;
+ }
+ dev_info(edp->dev, "EDID Version %d.%d\n", (int) edp->specs.version, (int) edp->specs.revision);
+ dev_info(edp->dev, " Manufacturer: %s, Model: %x\n", edp->specs.manufacturer, edp->specs.model);
+ dev_info(edp->dev, " Year: %u Week %u\n", edp->specs.year, edp->specs.week);
+
+ struct fb_videomode *preferred_mode = rk32_edp_get_preferred_mode(&edp->specs);
+
+ if(preferred_mode!=NULL){
+ dev_info(edp->dev, " Preferred Timing: %ld MHz\n", PICOS2KHZ(preferred_mode->pixclock)/1000);
+
+ screen->mode.xres = preferred_mode->xres;
+ screen->mode.yres = preferred_mode->yres;
+ screen->mode.pixclock = PICOS2KHZ(preferred_mode->pixclock)*1000;
+ screen->mode.left_margin = preferred_mode->left_margin;
+ screen->mode.right_margin = preferred_mode->right_margin;
+ screen->mode.upper_margin = preferred_mode->upper_margin;
+ screen->mode.lower_margin = preferred_mode->lower_margin;
+ screen->mode.hsync_len = preferred_mode->hsync_len;
+ screen->mode.vsync_len = preferred_mode->vsync_len;
+ screen->mode.sync = preferred_mode->sync;
+
+ screen->width = edp->specs.max_x*10;
+ screen->height= edp->specs.max_y*10;
+ return 0;
+ }
+ pr_info("EDID preferred mode not found!\n");
+ return -1;
+}
+
static int rk32_edp_enable(void)
{
int ret = 0;
@@ -1175,24 +1227,23 @@ static int rk32_edp_enable(void)
rk32_edp_pre_init(edp);
rk32_edp_init_edp(edp);
enable_irq(edp->irq);
- /*ret = rk32_edp_handle_edid(edp);
+/*
+ ret = rk32_edp_handle_edid(edp);
if (ret) {
dev_err(edp->dev, "unable to handle edid\n");
- //goto out;
}
-
- ret = rk32_edp_enable_scramble(edp, 0);
+*/
+ ret = rk32_edp_enable_scramble(edp, edp->scramble_enable);
if (ret) {
dev_err(edp->dev, "unable to set scramble\n");
- //goto out;
}
- ret = rk32_edp_enable_rx_to_enhanced_mode(edp, 0);
+ ret = rk32_edp_enable_rx_to_enhanced_mode(edp, edp->enhanced_mode);
if (ret) {
dev_err(edp->dev, "unable to set enhanced mode\n");
- //goto out;
}
- rk32_edp_enable_enhanced_mode(edp, 1);*/
+ rk32_edp_enable_enhanced_mode(edp, edp->enhanced_mode);
+
ret = rk32_edp_set_link_train(edp);
if (ret)
@@ -1204,9 +1255,10 @@ static int rk32_edp_enable(void)
rk32_edp_set_link_bandwidth(edp, edp->link_train.link_rate);
rk32_edp_init_video(edp);
-#ifdef EDP_BIST_MODE
- rk32_edp_bist_cfg(edp);
-#endif
+ if(edp->bist_mode){
+ rk32_edp_bist_cfg(edp);
+ }
+
ret = rk32_edp_config_video(edp, &edp->video_info);
if (ret)
dev_err(edp->dev, "unable to config video\n");
@@ -1237,7 +1289,6 @@ static struct rk_fb_trsm_ops trsm_edp_ops = {
.disable = rk32_edp_disable,
};
-/*#if 0
static int rk32_edp_enable_scramble(struct rk32_edp *edp, bool enable)
{
u8 data;
@@ -1279,7 +1330,7 @@ static int rk32_edp_enable_scramble(struct rk32_edp *edp, bool enable)
return 0;
}
-#endif*/
+
static int rk32_edp_psr_enable(struct rk32_edp *edp)
{
u8 buf;
@@ -1749,6 +1800,21 @@ static int rk32_edp_probe(struct platform_device *pdev)
return PTR_ERR(edp->regs);
}
+ if (of_property_read_bool(np, "bist-mode")){
+ edp->bist_mode = true;
+ dev_info(&pdev->dev, "bist mode\n");
+ }
+
+ if (of_property_read_bool(np, "enhanced-mode")){
+ edp->enhanced_mode= true;
+ dev_info(&pdev->dev, "enhanced mode\n");
+ }
+
+ if (of_property_read_bool(np, "scramble-enable")){
+ edp->scramble_enable= true;
+ dev_info(&pdev->dev, "scramble enable\n");
+ }
+
edp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
if (IS_ERR(edp->grf) && !cpu_is_rk3288()) {
dev_err(&pdev->dev, "can't find rockchip,grf property\n");
diff --git a/drivers/video/rockchip/transmitter/rk32_dp.h b/drivers/video/rockchip/transmitter/rk32_dp.h
index 08347b5..ce7a58d 100755
--- a/drivers/video/rockchip/transmitter/rk32_dp.h
+++ b/drivers/video/rockchip/transmitter/rk32_dp.h
@@ -565,6 +565,9 @@ struct rk32_edp {
struct fb_monspecs specs;
bool clk_on;
bool edp_en;
+ bool bist_mode;
+ bool enhanced_mode;
+ bool scramble_enable;
struct dentry *debugfs_dir;
};
2. uboot部分修改
2.1 修改代码,添加edp的EDID相关代码
diff --git a/common/cmd_bootrk.c b/common/cmd_bootrk.c
index 87b1a85..f156977 100755
--- a/common/cmd_bootrk.c
+++ b/common/cmd_bootrk.c
@@ -465,6 +465,11 @@ static void rk_commandline_setenv(const char *boot_name, rk_boot_img_hdr *hdr, b
}
#endif /* CONFIG_RK_FB_DDREND */
+#if defined(CONFIG_RK_EDP_EDID)
+ snprintf(command_line, sizeof(command_line),
+ "%s edp.edid=%d", command_line, 1);
+#endif
+
snprintf(command_line, sizeof(command_line),
"%s loader.timestamp=%s", command_line, U_BOOT_TIMESTAMP);
diff --git a/drivers/video/rk32_dp.c b/drivers/video/rk32_dp.c
index 49c0df6..d9b241c 100755
--- a/drivers/video/rk32_dp.c
+++ b/drivers/video/rk32_dp.c
@@ -9,6 +9,8 @@
#include <common.h>
#include <lcd.h>
#include <asm/arch/rkplat.h>
+#include <linux/rk_screen.h>
+#include "edid.h"
#include "rk32_dp.h"
#if defined(CONFIG_OF)
@@ -21,6 +23,8 @@
#include <linux/seq_file.h>
#endif
+DECLARE_GLOBAL_DATA_PTR;
+
//#define EDP_BIST_MODE
#define RUN_IN_UBOOT
@@ -137,10 +141,610 @@ static int rk32_edp_detect_hpd(struct rk32_edp *edp)
return 0;
}
+#endif
+
+const struct fb_videomode vesa_modes[] = {
+ /* 0 640x350-85 VESA */
+ { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA},
+ /* 1 640x400-85 VESA */
+ { NULL, 85, 640, 400, 31746, 96, 32, 41, 01, 64, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 2 720x400-85 VESA */
+ { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 3 640x480-60 VESA */
+ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2,
+ 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 4 640x480-72 VESA */
+ { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2,
+ 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 5 640x480-75 VESA */
+ { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
+ 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 6 640x480-85 VESA */
+ { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
+ 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 7 800x600-56 VESA */
+ { NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 8 800x600-60 VESA */
+ { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 9 800x600-72 VESA */
+ { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 10 800x600-75 VESA */
+ { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 11 800x600-85 VESA */
+ { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 12 1024x768i-43 VESA */
+ { NULL, 43, 1024, 768, 22271, 56, 8, 41, 0, 176, 8,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_INTERLACED, FB_MODE_IS_VESA },
+ /* 13 1024x768-60 VESA */
+ { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 14 1024x768-70 VESA */
+ { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 15 1024x768-75 VESA */
+ { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 16 1024x768-85 VESA */
+ { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 17 1152x864-75 VESA */
+ { NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 18 1280x960-60 VESA */
+ { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 19 1280x960-85 VESA */
+ { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 20 1280x1024-60 VESA */
+ { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 21 1280x1024-75 VESA */
+ { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 22 1280x1024-85 VESA */
+ { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 23 1600x1200-60 VESA */
+ { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 24 1600x1200-65 VESA */
+ { NULL, 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 25 1600x1200-70 VESA */
+ { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 26 1600x1200-75 VESA */
+ { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 27 1600x1200-85 VESA */
+ { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
+ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 28 1792x1344-60 VESA */
+ { NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 29 1792x1344-75 VESA */
+ { NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 30 1856x1392-60 VESA */
+ { NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 31 1856x1392-75 VESA */
+ { NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 32 1920x1440-60 VESA */
+ { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 33 1920x1440-75 VESA */
+ { NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+};
+
+#define EDP_EDID_LENGTH 128
+static int edid_checksum(unsigned char *edid)
+{
+ unsigned char csum = 0, all_null = 0;
+ int i, err = 0;
+
+ for (i = 0; i < EDP_EDID_LENGTH; i++) {
+ csum += edid[i];
+ all_null |= edid[i];
+ }
+
+ if (csum == 0x00 && all_null) {
+ /* checksum passed, everything's good */
+ err = 1;
+ }
+
+ return err;
+}
+
+static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs)
+{
+ specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@';
+ specs->manufacturer[1] = ((block[0] & 0x03) << 3) +
+ ((block[1] & 0xe0) >> 5) + '@';
+ specs->manufacturer[2] = (block[1] & 0x1f) + '@';
+ specs->manufacturer[3] = 0;
+ specs->model = block[2] + (block[3] << 8);
+ specs->serial = block[4] + (block[5] << 8) +
+ (block[6] << 16) + (block[7] << 24);
+ specs->year = block[9] + 1990;
+ specs->week = block[8];
+ debug(" Manufacturer: %s\n", specs->manufacturer);
+ debug(" Model: %x\n", specs->model);
+ debug(" Serial#: %u\n", specs->serial);
+ debug(" Year: %u Week %u\n", specs->year, specs->week);
+}
+
+static void calc_mode_timings(int xres, int yres, int refresh,
+ struct fb_videomode *mode)
+{
+ struct fb_var_screeninfo *var;
+
+ var = malloc(sizeof(struct fb_var_screeninfo));
+
+ if (var) {
+ var->xres = xres;
+ var->yres = yres;
+ //fb_get_mode(FB_VSYNCTIMINGS | FB_IGNOREMON,
+ // refresh, var, NULL);
+ mode->xres = xres;
+ mode->yres = yres;
+ mode->pixclock = var->pixclock;
+ mode->refresh = refresh;
+ mode->left_margin = var->left_margin;
+ mode->right_margin = var->right_margin;
+ mode->upper_margin = var->upper_margin;
+ mode->lower_margin = var->lower_margin;
+ mode->hsync_len = var->hsync_len;
+ mode->vsync_len = var->vsync_len;
+ mode->vmode = 0;
+ mode->sync = 0;
+ free(var);
+ }
+}
+
+static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
+{
+ int num = 0;
+ unsigned char c;
+
+ c = block[0];
+ if (c&0x80) {
+ calc_mode_timings(720, 400, 70, &mode[num]);
+ mode[num++].flag = FB_MODE_IS_CALCULATED;
+ debug(" 720x400@70Hz\n");
+ }
+ if (c&0x40) {
+ calc_mode_timings(720, 400, 88, &mode[num]);
+ mode[num++].flag = FB_MODE_IS_CALCULATED;
+ debug(" 720x400@88Hz\n");
+ }
+ if (c&0x20) {
+ mode[num++] = vesa_modes[3];
+ debug(" 640x480@60Hz\n");
+ }
+ if (c&0x10) {
+ calc_mode_timings(640, 480, 67, &mode[num]);
+ mode[num++].flag = FB_MODE_IS_CALCULATED;
+ debug(" 640x480@67Hz\n");
+ }
+ if (c&0x08) {
+ mode[num++] = vesa_modes[4];
+ debug(" 640x480@72Hz\n");
+ }
+ if (c&0x04) {
+ mode[num++] = vesa_modes[5];
+ debug(" 640x480@75Hz\n");
+ }
+ if (c&0x02) {
+ mode[num++] = vesa_modes[7];
+ debug(" 800x600@56Hz\n");
+ }
+ if (c&0x01) {
+ mode[num++] = vesa_modes[8];
+ debug(" 800x600@60Hz\n");
+ }
+
+ c = block[1];
+ if (c&0x80) {
+ mode[num++] = vesa_modes[9];
+ debug(" 800x600@72Hz\n");
+ }
+ if (c&0x40) {
+ mode[num++] = vesa_modes[10];
+ debug(" 800x600@75Hz\n");
+ }
+ if (c&0x20) {
+ calc_mode_timings(832, 624, 75, &mode[num]);
+ mode[num++].flag = FB_MODE_IS_CALCULATED;
+ debug(" 832x624@75Hz\n");
+ }
+ if (c&0x10) {
+ mode[num++] = vesa_modes[12];
+ debug(" 1024x768@87Hz Interlaced\n");
+ }
+ if (c&0x08) {
+ mode[num++] = vesa_modes[13];
+ debug(" 1024x768@60Hz\n");
+ }
+ if (c&0x04) {
+ mode[num++] = vesa_modes[14];
+ debug(" 1024x768@70Hz\n");
+ }
+ if (c&0x02) {
+ mode[num++] = vesa_modes[15];
+ debug(" 1024x768@75Hz\n");
+ }
+ if (c&0x01) {
+ mode[num++] = vesa_modes[21];
+ debug(" 1280x1024@75Hz\n");
+ }
+ c = block[2];
+ if (c&0x80) {
+ mode[num++] = vesa_modes[17];
+ debug(" 1152x870@75Hz\n");
+ }
+ debug(" Manufacturer's mask: %x\n",c&0x7F);
+ return num;
+}
+
+#define VESA_MODEDB_SIZE 34
+
+static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
+ int ver, int rev)
+{
+ int xres, yres = 0, refresh, ratio, i;
+
+ xres = (block[0] + 31) * 8;
+ if (xres <= 256)
+ return 0;
+
+ ratio = (block[1] & 0xc0) >> 6;
+ switch (ratio) {
+ case 0:
+ /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
+ if (ver < 1 || (ver == 1 && rev < 3))
+ yres = xres;
+ else
+ yres = (xres * 10)/16;
+ break;
+ case 1:
+ yres = (xres * 3)/4;
+ break;
+ case 2:
+ yres = (xres * 4)/5;
+ break;
+ case 3:
+ yres = (xres * 9)/16;
+ break;
+ }
+ refresh = (block[1] & 0x3f) + 60;
+
+ printf(" %dx%d@%dHz\n", xres, yres, refresh);
+ for (i = 0; i < VESA_MODEDB_SIZE; i++) {
+ if (vesa_modes[i].xres == xres &&
+ vesa_modes[i].yres == yres &&
+ vesa_modes[i].refresh == refresh) {
+ *mode = vesa_modes[i];
+ mode->flag |= FB_MODE_IS_STANDARD;
+ return 1;
+ }
+ }
+ calc_mode_timings(xres, yres, refresh, mode);
+ return 1;
+}
+
+static int get_dst_timing(unsigned char *block,
+ struct fb_videomode *mode, int ver, int rev)
+{
+ int j, num = 0;
+
+ for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
+ num += get_std_timing(block, &mode[num], ver, rev);
+
+ return num;
+}
+
+static void get_detailed_timing(unsigned char *block,
+ struct fb_videomode *mode)
+{
+ mode->xres = H_ACTIVE;
+ mode->yres = V_ACTIVE;
+ mode->pixclock = PIXEL_CLOCK;
+ mode->pixclock /= 1000;
+ mode->pixclock = KHZ2PICOS(mode->pixclock);
+ mode->right_margin = H_SYNC_OFFSET;
+ mode->left_margin = (H_ACTIVE + H_BLANKING) -
+ (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH);
+ mode->upper_margin = V_BLANKING - V_SYNC_OFFSET -
+ V_SYNC_WIDTH;
+ mode->lower_margin = V_SYNC_OFFSET;
+ mode->hsync_len = H_SYNC_WIDTH;
+ mode->vsync_len = V_SYNC_WIDTH;
+ if (HSYNC_POSITIVE)
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ if (VSYNC_POSITIVE)
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+ mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
+ (V_ACTIVE + V_BLANKING));
+ if (INTERLACED) {
+ mode->yres *= 2;
+ mode->upper_margin *= 2;
+ mode->lower_margin *= 2;
+ mode->vsync_len *= 2;
+ mode->vmode |= FB_VMODE_INTERLACED;
+ }
+ mode->flag = FB_MODE_IS_DETAILED;
+
+ debug(" %d MHz ", PIXEL_CLOCK/1000000);
+ debug("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET,
+ H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING);
+ debug("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET,
+ V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING);
+ debug("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-",
+ (VSYNC_POSITIVE) ? "+" : "-");
+}
+
+static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
+{
+ struct fb_videomode *mode, *m;
+ unsigned char *block;
+ int num = 0, i, first = 1;
+ int ver, rev;
+
+ ver = edid[EDID_STRUCT_VERSION];
+ rev = edid[EDID_STRUCT_REVISION];
+
+ mode = malloc(50 * sizeof(struct fb_videomode));
+ if (mode == NULL)
+ return NULL;
+
+ if (edid == NULL || !edid_checksum(edid)) {
+ free(mode);
+ return NULL;
+ }
+
+ *dbsize = 0;
+
+ debug(" Detailed Timings\n");
+ block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+ for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
+ if (!(block[0] == 0x00 && block[1] == 0x00)) {
+ get_detailed_timing(block, &mode[num]);
+ if (first) {
+ mode[num].flag |= FB_MODE_IS_FIRST;
+ first = 0;
+ }
+ num++;
+ }
+ }
+
+ debug(" Supported VESA Modes\n");
+ block = edid + ESTABLISHED_TIMING_1;
+ num += get_est_timing(block, &mode[num]);
+
+ debug(" Standard Timings\n");
+ block = edid + STD_TIMING_DESCRIPTIONS_START;
+ for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
+ num += get_std_timing(block, &mode[num], ver, rev);
+
+ block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+ for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
+ if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
+ num += get_dst_timing(block + 5, &mode[num], ver, rev);
+ }
+
+ /* Yikes, EDID data is totally useless */
+ if (!num) {
+ free(mode);
+ return NULL;
+ }
+
+ *dbsize = num;
+ m = malloc(num * sizeof(struct fb_videomode));
+ if (!m)
+ return mode;
+ memmove(m, mode, num * sizeof(struct fb_videomode));
+ free(mode);
+ return m;
+}
+
+static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+ unsigned char c, *block;
+
+ block = edid + EDID_STRUCT_DISPLAY;
+
+ c = block[0] & 0x80;
+ specs->input = 0;
+ if (c) {
+ specs->input |= FB_DISP_DDI;
+ debug(" Digital Display Input");
+ } else {
+ debug(" Analog Display Input: Input Voltage - ");
+ switch ((block[0] & 0x60) >> 5) {
+ case 0:
+ debug("0.700V/0.300V");
+ specs->input |= FB_DISP_ANA_700_300;
+ break;
+ case 1:
+ debug("0.714V/0.286V");
+ specs->input |= FB_DISP_ANA_714_286;
+ break;
+ case 2:
+ debug("1.000V/0.400V");
+ specs->input |= FB_DISP_ANA_1000_400;
+ break;
+ case 3:
+ debug("0.700V/0.000V");
+ specs->input |= FB_DISP_ANA_700_000;
+ break;
+ }
+ }
+ debug("\n Sync: ");
+ c = block[0] & 0x10;
+ if (c)
+ debug(" Configurable signal level\n");
+ c = block[0] & 0x0f;
+ specs->signal = 0;
+ if (c & 0x10) {
+ debug("Blank to Blank ");
+ specs->signal |= FB_SIGNAL_BLANK_BLANK;
+ }
+ if (c & 0x08) {
+ debug("Separate ");
+ specs->signal |= FB_SIGNAL_SEPARATE;
+ }
+ if (c & 0x04) {
+ debug("Composite ");
+ specs->signal |= FB_SIGNAL_COMPOSITE;
+ }
+ if (c & 0x02) {
+ debug("Sync on Green ");
+ specs->signal |= FB_SIGNAL_SYNC_ON_GREEN;
+ }
+ if (c & 0x01) {
+ debug("Serration on ");
+ specs->signal |= FB_SIGNAL_SERRATION_ON;
+ }
+ debug("\n");
+ specs->max_x = block[1];
+ specs->max_y = block[2];
+ debug(" Max H-size in cm: ");
+ if (specs->max_x)
+ debug("%d\n", specs->max_x);
+ else
+ debug("variable\n");
+ debug(" Max V-size in cm: ");
+ if (specs->max_y)
+ debug("%d\n", specs->max_y);
+ else
+ debug("variable\n");
+
+ c = block[3];
+ specs->gamma = c+100;
+ debug(" Gamma: ");
+ debug("%d.%d\n", specs->gamma/100, specs->gamma % 100);
+
+ switch ((block[4] & 0x18) >> 3) {
+ case 0:
+ debug(" Monochrome/Grayscale\n");
+ specs->input |= FB_DISP_MONO;
+ break;
+ case 1:
+ debug(" RGB Color Display\n");
+ specs->input |= FB_DISP_RGB;
+ break;
+ case 2:
+ debug(" Non-RGB Multicolor Display\n");
+ specs->input |= FB_DISP_MULTI;
+ break;
+ default:
+ debug(" Unknown\n");
+ specs->input |= FB_DISP_UNKNOWN;
+ break;
+ }
+
+ specs->misc = 0;
+ c = block[4] & 0x7;
+ if (c & 0x04) {
+ debug(" Default color format is primary\n");
+ specs->misc |= FB_MISC_PRIM_COLOR;
+ }
+ if (c & 0x02) {
+ debug(" First DETAILED Timing is preferred\n");
+ specs->misc |= FB_MISC_1ST_DETAIL;
+ }
+ if (c & 0x01) {
+ debug(" Display is GTF capable\n");
+ specs->gtf = 1;
+ }
+}
+
+void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
+{
+ int i, found = 0;
+
+ if (edid == NULL)
+ return;
+
+ if (!(edid_checksum(edid)))
+ return;
+
+ memset(specs, 0, sizeof(struct fb_monspecs));
+
+ specs->version = edid[EDID_STRUCT_VERSION];
+ specs->revision = edid[EDID_STRUCT_REVISION];
+
+ debug("EDID Version %d.%d\n", (int) specs->version,
+ (int) specs->revision);
+
+ parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs);
+
+ get_monspecs(edid, specs);
+
+ specs->modedb = fb_create_modedb(edid, (int *)&specs->modedb_len);
+
+ /*
+ * Workaround for buggy EDIDs that sets that the first
+ * detailed timing is preferred but has not detailed
+ * timing specified
+ */
+ for (i = 0; i < specs->modedb_len; i++) {
+ if (specs->modedb[i].flag & FB_MODE_IS_DETAILED) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ specs->misc &= ~FB_MISC_1ST_DETAIL;
+
+}
+
+static unsigned char inline rk32_edp_calc_edid_check_sum(unsigned char *edid_data)
+{
+ int i;
+ unsigned char sum = 0;
+
+ for (i = 0; i < EDP_EDID_LENGTH; i++)
+ sum = sum + edid_data[i];
+
+ return sum;
+}
static int rk32_edp_read_edid(struct rk32_edp *edp)
{
- unsigned char edid[EDID_LENGTH * 2];
+ unsigned char edid[EDP_EDID_LENGTH * 2];
unsigned int extend_block = 0;
unsigned char sum;
unsigned char test_vector;
@@ -165,25 +769,25 @@ static int rk32_edp_read_edid(struct rk32_edp *edp)
/* Read EDID data */
retval = rk32_edp_read_bytes_from_i2c(edp, EDID_ADDR, EDID_HEADER,
- EDID_LENGTH, &edid[EDID_HEADER]);
+ EDP_EDID_LENGTH, &edid[EDID_HEADER]);
if (retval != 0) {
debug( "EDID Read failed!\n");
return -EIO;
}
- sum = edp_calc_edid_check_sum(edid);
+ sum = rk32_edp_calc_edid_check_sum(edid);
if (sum != 0) {
debug( "EDID bad checksum!\n");
return 0;
}
/* Read additional EDID data */
- retval = rk32_edp_read_bytes_from_i2c(edp, EDID_ADDR, EDID_LENGTH,
- EDID_LENGTH, &edid[EDID_LENGTH]);
+ retval = rk32_edp_read_bytes_from_i2c(edp, EDID_ADDR, EDP_EDID_LENGTH,
+ EDP_EDID_LENGTH, &edid[EDP_EDID_LENGTH]);
if (retval != 0) {
debug( "EDID Read failed!\n");
return -EIO;
}
- sum = edp_calc_edid_check_sum(&edid[EDID_LENGTH]);
+ sum = rk32_edp_calc_edid_check_sum(&edid[EDP_EDID_LENGTH]);
if (sum != 0) {
debug( "EDID bad checksum!\n");
return 0;
@@ -199,7 +803,7 @@ static int rk32_edp_read_edid(struct rk32_edp *edp)
if (test_vector & DPCD_TEST_EDID_READ) {
retval = rk32_edp_write_byte_to_dpcd(edp,
DPCD_TEST_EDID_CHECKSUM,
- edid[EDID_LENGTH + EDID_CHECKSUM]);
+ edid[EDP_EDID_LENGTH + EDID_CHECKSUM]);
if (retval < 0) {
debug( "DPCD EDID Write failed!\n");
return retval;
@@ -217,12 +821,12 @@ static int rk32_edp_read_edid(struct rk32_edp *edp)
/* Read EDID data */
retval = rk32_edp_read_bytes_from_i2c(edp, EDID_ADDR, EDID_HEADER,
- EDID_LENGTH, &edid[EDID_HEADER]);
+ EDP_EDID_LENGTH, &edid[EDID_HEADER]);
if (retval != 0) {
debug( "EDID Read failed!\n");
return -EIO;
}
- sum = edp_calc_edid_check_sum(edid);
+ sum = rk32_edp_calc_edid_check_sum(edid);
if (sum != 0) {
debug( "EDID bad checksum!\n");
return 0;
@@ -253,7 +857,7 @@ static int rk32_edp_read_edid(struct rk32_edp *edp)
}
}
fb_edid_to_monspecs(edid, &edp->specs);
- printf( "EDID Read success!\n");
+ debug( "EDID Read success!\n");
return 0;
}
@@ -269,7 +873,7 @@ static int rk32_edp_handle_edid(struct rk32_edp *edp)
return retval;
for (i=0 ;i < 12; i++)
- printf( "%d:>>0x%02x\n", i, buf[i]);
+ debug( "%d:>>0x%02x\n", i, buf[i]);
/* Read EDID */
for (i = 0; i < 3; i++) {
retval = rk32_edp_read_edid(edp);
@@ -308,6 +912,7 @@ static int rk32_edp_enable_rx_to_enhanced_mode(struct rk32_edp *edp,
return retval;
}
+#ifndef RUN_IN_UBOOT
void rk32_edp_rx_control(struct rk32_edp *edp, bool enable)
{
/*rk32_edp_write_byte_to_dpcd(edp, DPCD_ADDR_USER_DEFINED1,0);
@@ -1065,7 +1670,6 @@ static int rk32_edp_config_video(struct rk32_edp *edp,
return retval;
}
-#ifndef RUN_IN_UBOOT
static int rk32_edp_enable_scramble(struct rk32_edp *edp, bool enable)
{
u8 data;
@@ -1103,7 +1707,60 @@ static int rk32_edp_enable_scramble(struct rk32_edp *edp, bool enable)
return 0;
}
-#endif /* #ifndef RUN_IN_UBOOT */
+
+static struct fb_videomode *rk32_edp_get_preferred_mode(struct fb_monspecs *spec)
+{
+ int i;
+
+ if (!spec || !spec->modedb || !(spec->misc & FB_MISC_1ST_DETAIL))
+ return NULL;
+
+ for (i = 0; i < spec->modedb_len; i++) {
+ if (spec->modedb[i].flag & FB_MODE_IS_FIRST &&
+ spec->modedb[i].flag & FB_MODE_IS_DETAILED)
+ return &spec->modedb[i];
+ }
+
+ return NULL;
+}
+
+int rk32_edp_get_screen_info_from_edid(struct rk_screen *screen)
+{
+ struct rk32_edp *edp = &rk32_edp;
+
+ int ret = rk32_edp_handle_edid(edp);
+ if (ret) {
+ printf("unable to handle edid\n");
+ return -1;
+ }
+
+ printf("EDID Version %d.%d\n", (int) edp->specs.version, (int) edp->specs.revision);
+ printf(" Manufacturer: %s, Model: %x\n", edp->specs.manufacturer, edp->specs.model);
+ printf(" Year: %u Week %u\n", edp->specs.year, edp->specs.week);
+
+ struct fb_videomode *preferred_mode = rk32_edp_get_preferred_mode(&edp->specs);
+
+ if(preferred_mode!=NULL){
+ printf(" Preferred Timing: %ld MHz\n", PICOS2KHZ(preferred_mode->pixclock)/1000);
+
+ screen->mode.xres = preferred_mode->xres;
+ screen->mode.yres = preferred_mode->yres;
+ screen->mode.pixclock = PICOS2KHZ(preferred_mode->pixclock)*1000;
+ screen->mode.left_margin = preferred_mode->left_margin;
+ screen->mode.right_margin = preferred_mode->right_margin;
+ screen->mode.upper_margin = preferred_mode->upper_margin;
+ screen->mode.lower_margin = preferred_mode->lower_margin;
+ screen->mode.hsync_len = preferred_mode->hsync_len;
+ screen->mode.vsync_len = preferred_mode->vsync_len;
+ screen->mode.sync = preferred_mode->sync;
+
+ screen->width = edp->specs.max_x*10;
+ screen->height= edp->specs.max_y*10;
+ return 0;
+ }
+ printf("EDID preferred mode not found!\n");
+ return -1;
+}
int rk32_edp_enable(vidinfo_t *vid)
{
@@ -1124,7 +1781,28 @@ int rk32_edp_enable(vidinfo_t *vid)
rk32_edp_clk_enable(edp);
rk32_edp_pre_init();
rk32_edp_init_edp(edp);
-
+
+ if (gd->fdt_blob) {
+ int node = fdt_path_offset(gd->fdt_blob, "/edp");
+ if(fdtdec_get_bool(gd->fdt_blob, node, "scramble-enable")){
+ debug("edp scramble enable.\n");
+ ret = rk32_edp_enable_scramble(edp, true);
+ if (ret) {
+ printf("unable to set scramble\n");
+ }
+ }
+
+ if(fdtdec_get_bool(gd->fdt_blob, node, "enhanced-mode")){
+ debug("edp enhanced mode.\n");
+
+ ret = rk32_edp_enable_rx_to_enhanced_mode(edp, true);
+ if (ret) {
+ printf("unable to set rx enhanced mode\n");
+ }
+ rk32_edp_enable_enhanced_mode(edp, true);
+ }
+ }
+
ret = rk32_edp_set_link_train(edp);
if (ret)
printf( "link train failed!\n");
diff --git a/drivers/video/rk32_dp.h b/drivers/video/rk32_dp.h
index 0ff0137..ea0de91 100755
--- a/drivers/video/rk32_dp.h
+++ b/drivers/video/rk32_dp.h
@@ -13,6 +13,7 @@
#include <asm/io.h>
#include <errno.h>
#include <lcd.h>
+#include <linux/fb.h>
#include "dpcd_edid.h"
#define DP_VERSION 0x10
@@ -527,6 +528,7 @@ struct rk32_edp {
vidinfo_t * vid;
struct link_train link_train;
struct video_info video_info;
+ struct fb_monspecs specs;
};
diff --git a/drivers/video/rk3368_lcdc.c b/drivers/video/rk3368_lcdc.c
index 9bf6752..e105c96 100755
--- a/drivers/video/rk3368_lcdc.c
+++ b/drivers/video/rk3368_lcdc.c
@@ -5,6 +5,7 @@
*/
#include "rk3368_lcdc.h"
+
/*******************register definition**********************/
struct lcdc_device rk33_lcdc;
extern struct rockchip_fb rockchip_fb;
@@ -13,6 +14,7 @@ int lcdEnstatus=-1;
#define EARLY_TIME 500 /*us*/
extern int rk31xx_lvds_enable(vidinfo_t * vid);
extern int rk32_edp_enable(vidinfo_t * vid);
+extern int rk32_edp_get_screen_info_from_edid(struct rk_screen *screen);
extern int rk32_mipi_enable(vidinfo_t * vid);
extern int rk32_dsi_enable(void);
extern int rk32_dsi_disable(void);
@@ -998,6 +1000,36 @@ static void rk3368_lcdc_bcsh_path_sel(struct lcdc_device *lcdc_dev)
}
}
+void rk3368_lcdc_get_vidinfo_from_edid(vidinfo_t *vid)
+{
+ rk32_edp_enable(vid);
+
+ struct rk_screen screen;
+
+ if(rk32_edp_get_screen_info_from_edid(&screen)!=0){
+ return;
+ }
+
+ vid->vl_freq = screen.mode.pixclock;
+
+ vid->vl_hspw = screen.mode.hsync_len;
+ vid->vl_hbpd = screen.mode.left_margin;
+ vid->vl_col = screen.mode.xres;
+ vid->vl_hfpd = screen.mode.right_margin;
+
+ vid->vl_vspw = screen.mode.vsync_len;
+ vid->vl_vbpd = screen.mode.upper_margin;
+ vid->vl_row = screen.mode.yres;
+ vid->vl_vfpd = screen.mode.lower_margin;
+
+ vid->vl_hsp = screen.mode.sync & FB_SYNC_HOR_HIGH_ACT ? 1 : 0;
+ vid->vl_vsp = screen.mode.sync & FB_SYNC_VERT_HIGH_ACT ? 1 : 0;
+
+ vid->vl_width = screen.width;
+ vid->vl_height= screen.height;
+}
+
+
int rk_lcdc_load_screen(vidinfo_t *vid)
{
struct lcdc_device *lcdc_dev = &rk33_lcdc;
diff --git a/drivers/video/rockchip_fb.c b/drivers/video/rockchip_fb.c
index 6e35e10..e846d42 100755
--- a/drivers/video/rockchip_fb.c
+++ b/drivers/video/rockchip_fb.c
@@ -487,6 +487,18 @@ void lcd_ctrl_init(void *lcdbase)
panel_info.logo_rgb_mode = RGB565;
rk_fb_pwr_enable(fb);
+
+#if defined(CONFIG_RK_EDP_EDID)
+ //get EDID for eDP panel.
+ if(panel_info.screen_type == SCREEN_EDP){
+ rk3368_lcdc_get_vidinfo_from_edid(&panel_info);
+ if(panel_info.vl_freq >= 1000*1000){
+ panel_info.vl_freq = panel_info.vl_freq/(1000*1000);
+ panel_info.vl_freq *= 1000*1000;
+ }
+ }
+#endif
+
panel_info.real_freq = rkclk_lcdc_clk_set(panel_info.lcdc_id,
panel_info.vl_freq);
rk_lcdc_init(panel_info.lcdc_id);
2.2 在config中添加Edp配置
diff --git a/include/configs/rk_default_config.h b/include/configs/rk_default_config.h
index 5583559..1bd3767 100755
--- a/include/configs/rk_default_config.h
+++ b/include/configs/rk_default_config.h
@@ -438,5 +438,6 @@
#endif /* CONFIG_LCD */
+#define CONFIG_RK_EDP_EDID
#endif /* __RK_DEFAULT_CONFIG_H */

本文档详细介绍了如何针对RK3368平台进行EDP屏的调试,通过分析和利用EDID信息来实现屏幕的兼容性。在kernel部分,主要涉及了Edid信息打印、lcdc驱动、rk_screen、dts和rk32_dp驱动的修改。而在uboot部分,着重阐述了代码的调整和配置文件中Edp设置的添加。
608

被折叠的 条评论
为什么被折叠?



