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